[2924] in Kerberos-V5-bugs

home help back first fref pref prev next nref lref last post

pending/592: PATCH: appl/bsd/kcmd.c

daemon@ATHENA.MIT.EDU (Larry Schwimmer)
Wed May 20 21:01:56 1998

Resent-From: gnats@rt-11.MIT.EDU (GNATS Management)
Resent-To: gnats-admin@rt-11.MIT.EDU
Resent-Reply-To: krb5-bugs@MIT.EDU,
        Larry Schwimmer <schwim@whatmore.Stanford.EDU>
Date: Wed, 20 May 1998 17:51:51 -0700 (PDT)
From: Larry Schwimmer <schwim@whatmore.Stanford.EDU>
To: krb5-bugs@MIT.EDU


>Number:         592
>Category:       pending
>Synopsis:       PATCH: appl/bsd/kcmd.c
>Confidential:   yes
>Severity:       serious
>Priority:       medium
>Responsible:    gnats-admin
>State:          open
>Class:          sw-bug
>Submitter-Id:   unknown
>Arrival-Date:   Wed May 20 20:52:00 EDT 1998
>Last-Modified:
>Originator:
>Organization:
>Release:
>Environment:
>Description:
>How-To-Repeat:
>Fix:
>Audit-Trail:
>Unformatted:
Submitter-Id:	net
Originator:	Larry Schwimmer
Organization:	Stanford University
Confidential:	no
Synopsis:	kcmd connection optimization, krb4 support
Severity:	non-critical
Priority:	medium
Category:	krb5-appl
Class:		sw-bug,  change-request
Release:	krb5-1.0.5
Environment:	ALL
Description:

1) connection optimization

	The appl/bsd clients which use kcmd are non-optimal in
failure.  They first make a connection and then perform a sendauth
call.  For cases when there is no ticket, it is a waste to initiate a
connection since the sendauth call will never succeed.  The first part
of this patch moves the credential cache check before the connection
is created so that unnecessary connections are not made.

2) krb4 support

	The second part of the patch adds k4cmd, which is based on the
krb4 kcmd with updates from the krb5 kcmd source.  The purpose of this
code is to add krb4 fallback support to rsh and rlogin.  We are in the
process of migrating to krb5 and having support for both krb4 and krb5
is a prerequisite for the transition.
	Portions of the patches for krlogin.c and krsh.c that I will
be sending depend on this patch.

Fix:

	Patch below.

			yours,
				Larry Schwimmer
				schwim@leland.stanford.edu
				Leland Systems Group

	
--- appl/bsd/kcmd.c.orig	Fri Feb  6 19:41:16 1998
+++ appl/bsd/kcmd.c	Tue Apr 21 15:38:59 1998
@@ -156,6 +156,18 @@
 	krb5_princ_set_realm_length(bsd_context,get_cred->server,strlen(realm));
 	krb5_princ_set_realm_data(bsd_context,get_cred->server,strdup(realm));
    }
+
+    if (status = krb5_cc_default(bsd_context, &cc)) {
+	krb5_free_creds(bsd_context, get_cred);
+    	return status;
+    }
+
+    if (status = krb5_cc_get_principal(bsd_context, cc, &get_cred->client)) {
+    	(void) krb5_cc_close(bsd_context, cc);
+	krb5_free_creds(bsd_context, get_cred);
+	return status;
+    }
+
 #ifdef POSIX_SIGNALS
     sigemptyset(&urgmask);
     sigaddset(&urgmask, SIGURG);
@@ -267,14 +279,6 @@
         goto bad2;
     }
 
-    if (status = krb5_cc_default(bsd_context, &cc))
-    	goto bad2;
-
-    if (status = krb5_cc_get_principal(bsd_context, cc, &get_cred->client)) {
-    	(void) krb5_cc_close(bsd_context, cc);
-    	goto bad2;
-    }
-
     /* Get ticket from credentials cache or kdc */
     status = krb5_get_credentials(bsd_context, 0, cc, get_cred, &ret_cred);
     krb5_free_creds(bsd_context, get_cred);
@@ -448,3 +452,256 @@
 
 #endif
 
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#include <kerberosIV/kparse.h>
+
+k4cmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm,
+      cred, schedule, msg_data, laddr, faddr, authopts)
+int *sock;
+char **ahost;
+u_short rport;
+char *locuser, *remuser, *cmd;
+int *fd2p;
+KTEXT ticket;
+char *service;
+char *realm;
+CREDENTIALS *cred;
+Key_schedule schedule;
+MSG_DAT *msg_data;
+struct sockaddr_in *laddr, *faddr;
+KRB4_32 authopts;
+{
+	int s, timo = 1, pid;
+#ifdef POSIX_SIGNALS
+	sigset_t oldmask, urgmask;
+#else
+	long oldmask;
+#endif /* POSIX_SIGNALS */
+	struct sockaddr_in sin, from, local_laddr;
+	char c;
+	int lport = START_PORT;
+	struct hostent *hp;
+	int rc;
+	char *host_save;
+	int status;
+
+	pid = getpid();
+	hp = gethostbyname(*ahost);
+	if (hp == 0) {
+		fprintf(stderr, "%s: unknown host\n", *ahost);
+		return (-1);
+	}
+	if ((host_save = malloc(strlen(hp->h_name) + 1)) == NULL) {
+	  fprintf(stderr,"k4cmd: no memory\n");
+	  return -1;
+	}
+	strcpy(host_save, hp->h_name);
+
+	/* If realm is null, look up from table */
+	if ((realm == NULL) || (realm[0] == '\0')) {
+		realm = (char *)krb_realmofhost(host_save);
+	}
+
+	/* Avoid making a useless connection by first ensuring that
+	 * a tgt exists.  Unless it does, the sendauth will fail.
+	 */
+	if (cred != (CREDENTIALS *)0) {
+	    char lrealm[REALM_SZ];
+
+	    if ((status = krb_get_tf_realm(TKT_FILE, lrealm)) != KSUCCESS)
+		return(status);
+
+	    status = krb_get_cred("krbtgt",realm,lrealm,cred);
+
+	    if (status != KSUCCESS &&
+		(strncmp(realm, lrealm, REALM_SZ)) == 0)
+		return status;
+	}
+#ifdef POSIX_SIGNALS
+	sigemptyset(&urgmask);
+	sigaddset(&urgmask,SIGURG);
+	sigprocmask(SIG_BLOCK,&urgmask,&oldmask);
+#else
+	oldmask = sigblock(sigmask(SIGURG));
+#endif /* POSIX_SIGNALS */
+	for (;;) {
+		s = getport(&lport);
+		if (s < 0) {
+			if (errno == EAGAIN)
+				fprintf(stderr, "socket: All ports in use\n");
+			else
+				perror("rcmd: socket");
+#ifdef POSIX_SIGNALS
+			sigprocmask(SIG_SETMASK,&oldmask,NULL);
+#else
+			sigsetmask(oldmask);
+#endif /* POSIX_SIGNALS */
+			return (-1);
+		}
+		sin.sin_family = hp->h_addrtype;
+		memcpy((caddr_t)&sin.sin_addr,hp->h_addr,sizeof(sin.sin_addr));
+		sin.sin_port = rport;
+		if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
+			break;
+		(void) close(s);
+		if (errno == EADDRINUSE) {
+			lport--;
+			continue;
+		}
+#if !(defined(tek) || defined(ultrix) || defined(sun) || defined(SYSV))
+		if (hp->h_addr_list[1] != NULL) {
+			int oerrno = errno;
+
+			fprintf(stderr,
+				"connect to address %s: ", inet_ntoa(sin.sin_addr));
+			errno = oerrno;
+			perror(0);
+			hp->h_addr_list++;
+			memcpy((caddr_t)&sin.sin_addr, hp->h_addr_list[0],
+			       sizeof(sin.sin_addr));
+			fprintf(stderr, "Trying %s...\n",
+				inet_ntoa(sin.sin_addr));
+			continue;
+		}
+#endif /* !(defined(ultrix) || defined(sun)) */
+		perror(hp->h_name);
+#ifdef POSIX_SIGNALS
+		sigprocmask(SIG_SETMASK,&oldmask,NULL);
+#else
+		sigsetmask(oldmask);
+#endif /* POSIX_SIGNALS */
+		return (-1);
+	}
+	lport--;
+	if (fd2p == 0) {
+		write(s, "", 1);
+		lport = 0;
+	} else {
+		char num[8];
+		int s2 = getport(&lport), s3;
+		int len = sizeof (from);
+
+		if (s2 < 0) {
+			status = -1;
+			goto bad;
+		}
+		listen(s2, 1);
+		(void) sprintf(num, "%d", lport);
+		if (write(s, num, strlen(num)+1) != strlen(num)+1) {
+			perror("write: setting up stderr");
+			(void) close(s2);
+			status = -1;
+			goto bad;
+		}
+		s3 = accept(s2, (struct sockaddr *)&from, &len);
+		(void) close(s2);
+		if (s3 < 0) {
+			perror("accept");
+			lport = 0;
+			status = -1;
+			goto bad;
+		}
+		*fd2p = s3;
+		from.sin_port = ntohs((u_short)from.sin_port);
+		if (from.sin_family != AF_INET ||
+		    from.sin_port >= IPPORT_RESERVED) {
+			fprintf(stderr,
+				"socket: protocol failure in circuit setup.\n");
+			goto bad2;
+		}
+	}
+	/*
+	 * Kerberos-authenticated service.  Don't have to send locuser,
+	 * since its already in the ticket, and we'll extract it on
+	 * the other side.
+	 */
+	/* (void) write(s, locuser, strlen(locuser)+1); */
+
+	if (!laddr) laddr = &local_laddr;
+	if (!faddr) faddr = &sin;
+	else 
+	    memcpy(faddr,&sin,sizeof(sin));
+
+	/* set up the needed stuff for mutual auth, but only if necessary */
+	if (authopts & KOPT_DO_MUTUAL) {
+		int sin_len;
+		*faddr = sin;
+
+		sin_len = sizeof (struct sockaddr_in);
+		if (getsockname(s, (struct sockaddr *)laddr, &sin_len) < 0) {
+			perror("getsockname");
+			status = -1;
+			goto bad2;
+		}
+	}
+	if ((status = krb_sendauth(authopts, s, ticket, service, host_save,
+				   realm, (unsigned KRB4_32) pid,
+				   msg_data,
+				   cred, schedule,
+				   laddr,
+				   faddr,
+				   "KCMDV0.1")) != KSUCCESS) {
+	  /* this part involves some very intimate knowledge of a 
+	     particular sendauth implementation to pry out the old bits.
+	     This only catches the case of total failure -- but that's 
+	     the one where we get useful data from the remote end. If
+	     we even get an authenticator back, then the problem gets 
+	     diagnosed locally anyhow. */	     
+	  extern KRB4_32 __krb_sendauth_hidden_tkt_len;
+	  char *old_data = (char*)&__krb_sendauth_hidden_tkt_len;
+	  if ((status == KFAILURE) && (*old_data == 1)) {
+	    write(2, old_data+1, 3);
+	    *old_data = (-1);
+	  }
+	  if ((status == KFAILURE) && (*old_data == -1)) {
+	    while (read(s, &c, 1) == 1) {
+	      (void) write(2, &c, 1);
+	      if (c == '\n')
+		break;
+	    }
+	    status = -1;
+	  }
+	  goto bad2;
+	}
+	(void) write(s, remuser, strlen(remuser)+1);
+	(void) write(s, cmd, strlen(cmd)+1);
+
+	if ((rc=read(s, &c, 1)) != 1) {
+		if (rc==-1) {
+			perror(host_save);
+		} else {
+			fprintf(stderr,"rcmd: bad connection with remote host\n");
+		}
+		status = -1;
+		goto bad2;
+	}
+	if (c != 0) {
+		while (read(s, &c, 1) == 1) {
+			(void) write(2, &c, 1);
+			if (c == '\n')
+				break;
+		}
+		status = -1;
+		goto bad2;
+	}
+#ifdef POSIX_SIGNALS
+	sigprocmask(SIG_SETMASK,&oldmask,NULL);
+#else
+	sigsetmask(oldmask);
+#endif /* POSIX_SIGNALS */
+	*sock = s;
+	return (KSUCCESS);
+ bad2:
+	if (lport)
+		(void) close(*fd2p);
+ bad:
+	(void) close(s);
+#ifdef POSIX_SIGNALS
+	sigprocmask(SIG_SETMASK,&oldmask,NULL);
+#else
+	sigsetmask(oldmask);
+#endif /* POSIX_SIGNALS */
+	return (status);
+}
+#endif /* KRB5_KRB4_COMPAT */

home help back first fref pref prev next nref lref last post