30f6a9b
We can get stuck if a write is going to block because both ends are writing and
30f6a9b
neither end is reading.  This is a port of a patch which aims to solve that
30f6a9b
problem, but for now it's incomplete because we don't handle partial writes.  A
30f6a9b
proper non-blocking implementation would require a bit more work.
30f6a9b
30f6a9b
diff -ur krb5-1.5/src/appl/bsd/defines.h krb5-1.5/src/appl/bsd/defines.h
30f6a9b
--- krb5-1.5/src/appl/bsd/defines.h	2003-01-01 05:13:20.000000000 -0500
30f6a9b
+++ krb5-1.5/src/appl/bsd/defines.h	2006-07-21 15:11:44.000000000 -0400
30f6a9b
@@ -34,6 +34,7 @@
30f6a9b
 		 enum kcmd_proto *protonum /* input and output */
30f6a9b
 		 );
30f6a9b
 
30f6a9b
+extern int rcmd_stream_has_unsent_data (void);
30f6a9b
 extern int rcmd_stream_read (int fd, char *buf, size_t len, int secondary);
30f6a9b
 extern int rcmd_stream_write (int fd, char *buf, size_t len, int secondary);
30f6a9b
 extern int getport (int * /* portnum */, int * /* addrfamily */);
30f6a9b
diff -ur krb5-1.5/src/appl/bsd/kcmd.c krb5-1.5/src/appl/bsd/kcmd.c
30f6a9b
--- krb5-1.5/src/appl/bsd/kcmd.c	2004-10-01 18:08:14.000000000 -0400
30f6a9b
+++ krb5-1.5/src/appl/bsd/kcmd.c	2006-07-21 15:11:44.000000000 -0400
30f6a9b
@@ -839,6 +839,11 @@
30f6a9b
     output = twrite;
30f6a9b
 }
30f6a9b
 
30f6a9b
+int rcmd_stream_has_unsent_data (void)
30f6a9b
+{
30f6a9b
+    return (nstored > 0);
30f6a9b
+}
30f6a9b
+
30f6a9b
 void rcmd_stream_init_krb5(in_keyblock, encrypt_flag, lencheck, am_client,
30f6a9b
 			   protonum)
30f6a9b
      krb5_keyblock *in_keyblock;
30f6a9b
@@ -1019,7 +1024,8 @@
30f6a9b
 	cc = krb5_net_read(bsd_context, fd, &c, 1);
30f6a9b
 	/* we should check for non-blocking here, but we'd have
30f6a9b
 	   to make it save partial reads as well. */
30f6a9b
-	if (cc <= 0) return cc; /* read error */
30f6a9b
+	if (cc == 0) return nreturned; /* EOF */
30f6a9b
+	if (cc < 0) return cc; /* read error */
30f6a9b
 	if (cc == 1) {
30f6a9b
 	    if (c == 0 || !do_lencheck) break;
30f6a9b
 	}
30f6a9b
diff -ur krb5-1.5/src/appl/bsd/krsh.c krb5-1.5/src/appl/bsd/krsh.c
30f6a9b
--- krb5-1.5/src/appl/bsd/krsh.c	2006-07-21 16:05:57.000000000 -0400
30f6a9b
+++ krb5-1.5/src/appl/bsd/krsh.c	2006-07-21 15:19:05.000000000 -0400
30f6a9b
@@ -128,10 +128,11 @@
30f6a9b
      char **argv0;
30f6a9b
 {
30f6a9b
     int rem, pid = 0;
30f6a9b
-    char *host=0, *cp, **ap, buf[RCMD_BUFSIZ], *args, **argv = argv0, *user = 0;
30f6a9b
+    char *host=0, *cp, **ap, buf[PIPE_BUF], *args, **argv = argv0, *user = 0;
30f6a9b
     register int cc;
30f6a9b
     struct passwd *pwd;
30f6a9b
     fd_set readfrom, ready;
30f6a9b
+    fd_set writeto, ready_wr;
30f6a9b
     int one = 1;
30f6a9b
     struct servent *sp;
30f6a9b
     struct servent defaultservent;
30f6a9b
@@ -548,9 +549,14 @@
30f6a9b
     FD_ZERO(&readfrom);
30f6a9b
     FD_SET(rfd2, &readfrom);
30f6a9b
     FD_SET(rem, &readfrom);
30f6a9b
+    FD_ZERO(&writeto);
30f6a9b
     do {
30f6a9b
+	int max_fd;
30f6a9b
+	max_fd = (rfd2 > rem) ? rfd2 : rem;
30f6a9b
+	max_fd = (max_fd > 2) ? max_fd : 2;
30f6a9b
 	ready = readfrom;
30f6a9b
-	if (select(((rfd2 > rem) ? rfd2 : rem) + 1, &ready, 0, 0, 0) < 0) {
30f6a9b
+	ready_wr = writeto;
30f6a9b
+	if (select(max_fd + 1, &ready, &ready_wr, 0, 0) < 0) {
30f6a9b
 	    if (errno != EINTR) {
30f6a9b
 		perror("select");
30f6a9b
 		exit(1);
30f6a9b
@@ -558,22 +564,38 @@
30f6a9b
 	    continue;
30f6a9b
 	}
30f6a9b
 	if (FD_ISSET(rfd2, &ready)) {
30f6a9b
-	    errno = 0;
30f6a9b
-	    cc = rcmd_stream_read(rfd2, buf, sizeof buf, 1);
30f6a9b
-	    if (cc <= 0) {
30f6a9b
-		if ((errno != EWOULDBLOCK) && (errno != EAGAIN))
30f6a9b
-		    FD_CLR(rfd2, &readfrom);
30f6a9b
-	    } else
30f6a9b
-	      (void) write(2, buf, (unsigned) cc);
30f6a9b
+            FD_SET(2, &writeto);
30f6a9b
+	}
30f6a9b
+	if (FD_ISSET(2, &ready_wr)) {
30f6a9b
+	    do {
30f6a9b
+		errno = 0;
30f6a9b
+		cc = rcmd_stream_read(rfd2, buf, sizeof buf, 1);
30f6a9b
+		if (cc <= 0) {
30f6a9b
+		    if ((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
30f6a9b
+			FD_CLR(rfd2, &readfrom);
30f6a9b
+			break;
30f6a9b
+		    }
30f6a9b
+		} else
30f6a9b
+		  (void) write(2, buf, (unsigned) cc);
30f6a9b
+	    } while (rcmd_stream_has_unsent_data());
30f6a9b
+	    FD_CLR(2, &writeto);
30f6a9b
 	}
30f6a9b
 	if (FD_ISSET(rem, &ready)) {
30f6a9b
-	    errno = 0;
30f6a9b
-	    cc = rcmd_stream_read(rem, buf, sizeof buf, 0);
30f6a9b
-	    if (cc <= 0) {
30f6a9b
-		if ((errno != EWOULDBLOCK) && (errno != EAGAIN))
30f6a9b
-		    FD_CLR(rem, &readfrom);
30f6a9b
-	    } else
30f6a9b
-	      (void) write(1, buf, (unsigned) cc);
30f6a9b
+	    FD_SET(1, &writeto);
30f6a9b
+	}
30f6a9b
+	if (FD_ISSET(1, &ready_wr)) {
30f6a9b
+	    do {
30f6a9b
+		errno = 0;
30f6a9b
+		cc = rcmd_stream_read(rem, buf, sizeof buf, 0);
30f6a9b
+		if (cc <= 0) {
30f6a9b
+		    if ((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
30f6a9b
+			FD_CLR(rem, &readfrom);
30f6a9b
+			break;
30f6a9b
+		    }
30f6a9b
+		} else
30f6a9b
+		  (void) write(1, buf, (unsigned) cc);
30f6a9b
+	    } while (rcmd_stream_has_unsent_data());
30f6a9b
+	    FD_CLR(1, &writeto);
30f6a9b
 	}
30f6a9b
     } while (FD_ISSET(rem, &readfrom) || FD_ISSET(rfd2, &readfrom));
30f6a9b
     if (nflag == 0)
30f6a9b
diff -ur krb5-1.5/src/appl/bsd/krshd.c krb5-1.5/src/appl/bsd/krshd.c
30f6a9b
--- krb5-1.5/src/appl/bsd/krshd.c	2006-06-20 00:06:52.000000000 -0400
30f6a9b
+++ krb5-1.5/src/appl/bsd/krshd.c	2006-07-21 16:02:12.000000000 -0400
30f6a9b
@@ -633,7 +633,8 @@
30f6a9b
     short port;
30f6a9b
     int pv[2], pw[2], px[2], cc;
30f6a9b
     fd_set ready, readfrom;
30f6a9b
-    char buf[RCMD_BUFSIZ], sig;
30f6a9b
+    fd_set ready_wr, writeto;
30f6a9b
+    char buf[PIPE_BUF], sig;
30f6a9b
     struct sockaddr_storage localaddr;
30f6a9b
 #ifdef POSIX_SIGNALS
30f6a9b
     struct sigaction sa;
30f6a9b
@@ -1261,6 +1262,10 @@
30f6a9b
 	    if (pw[0] > maxfd)
30f6a9b
 		maxfd = pw[0];
30f6a9b
 	    
30f6a9b
+	    if (px[1] > maxfd)
30f6a9b
+		maxfd = px[1];
30f6a9b
+	    FD_ZERO(&writeto);
30f6a9b
+
30f6a9b
 	    /* read from f, write to px[1] -- child stdin */
30f6a9b
 	    /* read from s, signal child */
30f6a9b
 	    /* read from pv[0], write to s -- child stderr */
30f6a9b
@@ -1268,36 +1273,47 @@
30f6a9b
 
30f6a9b
 	    do {
30f6a9b
 		ready = readfrom;
30f6a9b
-		if (select(maxfd + 1, &ready, (fd_set *)0,
30f6a9b
+		ready_wr = writeto;
30f6a9b
+		if (select(maxfd + 1, &ready, &ready_wr,
30f6a9b
 			   (fd_set *)0, (struct timeval *)0) < 0) {
30f6a9b
 		    if (errno == EINTR) {
30f6a9b
 			continue;
30f6a9b
 		    } else {
30f6a9b
 			break;
30f6a9b
-		}
30f6a9b
+		    }
30f6a9b
 		}
30f6a9b
 
30f6a9b
 		if (port&&FD_ISSET(pv[0], &ready)) {
30f6a9b
+		    FD_SET(s, &writeto);
30f6a9b
+		    FD_CLR(pv[0], &readfrom);
30f6a9b
+		}
30f6a9b
+		if (port&&FD_ISSET(s, &ready_wr)) {
30f6a9b
 		    /* read from the child stderr, write to the net */
30f6a9b
 		    errno = 0;
30f6a9b
 		    cc = read(pv[0], buf, sizeof (buf));
30f6a9b
-		    if (cc <= 0) {
30f6a9b
+		    if ((cc <= 0) ||
30f6a9b
+			(rcmd_stream_write(s, buf, (unsigned) cc, 1) != cc)) {
30f6a9b
 			shutdown(s, 1+1);
30f6a9b
-			FD_CLR(pv[0], &readfrom);
30f6a9b
 		    } else {
30f6a9b
-			(void) rcmd_stream_write(s, buf, (unsigned) cc, 1);
30f6a9b
+			FD_SET(pv[0], &readfrom);
30f6a9b
 		    }
30f6a9b
+		    FD_CLR(s, &writeto);
30f6a9b
 		}
30f6a9b
 		if (FD_ISSET(pw[0], &ready)) {
30f6a9b
+		    FD_SET(f, &writeto);
30f6a9b
+		    FD_CLR(pw[0], &readfrom);
30f6a9b
+		}
30f6a9b
+		if (FD_ISSET(f, &ready_wr)) {
30f6a9b
 		    /* read from the child stdout, write to the net */
30f6a9b
 		    errno = 0;
30f6a9b
 		    cc = read(pw[0], buf, sizeof (buf));
30f6a9b
-		    if (cc <= 0) {
30f6a9b
+		    if ((cc <= 0) ||
30f6a9b
+			(rcmd_stream_write(f, buf, (unsigned) cc, 0) != cc)) {
30f6a9b
 			shutdown(f, 1+1);
30f6a9b
-			FD_CLR(pw[0], &readfrom);
30f6a9b
 		    } else {
30f6a9b
-			(void) rcmd_stream_write(f, buf, (unsigned) cc, 0);
30f6a9b
+			FD_SET(pw[0], &readfrom);
30f6a9b
 		    }
30f6a9b
+		    FD_CLR(f, &writeto);
30f6a9b
 		}
30f6a9b
 		if (port&&FD_ISSET(s, &ready)) {
30f6a9b
 		    /* read from the alternate channel, signal the child */
30f6a9b
@@ -1315,12 +1331,15 @@
30f6a9b
 		    }
30f6a9b
 		}
30f6a9b
 		if (FD_ISSET(f, &ready)) {
30f6a9b
+		    FD_SET(px[1], &writeto);
30f6a9b
+		    FD_CLR(f, &readfrom);
30f6a9b
+		}
30f6a9b
+		if (FD_ISSET(px[1], &ready_wr)) {
30f6a9b
 		    /* read from the net, write to child stdin */
30f6a9b
 		    errno = 0;
30f6a9b
 		    cc = rcmd_stream_read(f, buf, sizeof(buf), 0);
30f6a9b
 		    if (cc <= 0) {
30f6a9b
 			(void) close(px[1]);
30f6a9b
-			FD_CLR(f, &readfrom);
30f6a9b
 		    } else {
30f6a9b
 		        int wcc;
30f6a9b
 		        wcc = write(px[1], buf, (unsigned) cc);
30f6a9b
@@ -1328,17 +1347,22 @@
30f6a9b
 			  /* pipe closed, don't read any more */
30f6a9b
 			  /* might check for EPIPE */
30f6a9b
 			  (void) close(px[1]);
30f6a9b
-			  FD_CLR(f, &readfrom);
30f6a9b
-			} else if (wcc != cc) {
30f6a9b
-			  syslog(LOG_INFO, "only wrote %d/%d to child", 
30f6a9b
-				 wcc, cc);
30f6a9b
+			} else {
30f6a9b
+			    if (wcc != cc)
30f6a9b
+				syslog(LOG_INFO, "only wrote %d/%d to child", 
30f6a9b
+				       wcc, cc);
30f6a9b
+			    FD_SET(f, &readfrom);
30f6a9b
 			}
30f6a9b
 		    }
30f6a9b
+		    FD_CLR(px[1], &writeto);
30f6a9b
 		}
30f6a9b
 	    } while ((port&&FD_ISSET(s, &readfrom)) ||
30f6a9b
 		     FD_ISSET(f, &readfrom) ||
30f6a9b
 		     (port&&FD_ISSET(pv[0], &readfrom) )||
30f6a9b
-		     FD_ISSET(pw[0], &readfrom));
30f6a9b
+		     FD_ISSET(pw[0], &readfrom) ||
30f6a9b
+		     (port&&FD_ISSET(s, &writeto)) ||
30f6a9b
+		     FD_ISSET(f, &writeto) ||
30f6a9b
+		     FD_ISSET(px[1], &writeto));
30f6a9b
 	    ignore_signals();
30f6a9b
 #ifdef KERBEROS
30f6a9b
 	    syslog(LOG_INFO ,