home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume22 / auth / part02 / attachport.c next >
C/C++ Source or Header  |  1990-04-29  |  21KB  |  629 lines

  1. /*
  2. attachport.c: attach a server program to a TCP port
  3. */
  4.  
  5. /* WARNING! WARNING! WARNING! */
  6. /* For the authentication to work, attachport must run setuid auth! */
  7. /* All setuid programs are dangerous! Check them carefully! */
  8.  
  9. static char attachportauthor[] =
  10. "attachport was written by Daniel J. Bernstein.\n\
  11. Internet address: brnstnd@acf10.nyu.edu.\n";
  12.  
  13. static char attachportversion[] = 
  14. "attachport version 4.1, April 18, 1990.\n\
  15. Copyright (c) 1990, Daniel J. Bernstein.\n\
  16. All rights reserved.\n";
  17.  
  18. static char attachportcopyright[] =
  19. "attachport version 4.1, April 18, 1990.\n\
  20. Copyright (c) 1990, Daniel J. Bernstein.\n\
  21. All rights reserved.\n\
  22. \n\
  23. Until January 1, 1995, you are granted the following rights: A. To make\n\
  24. copies of this work in original form, so long as (1) the copies are exact\n\
  25. and complete; (2) the copies include the copyright notice, this paragraph,\n\
  26. and the disclaimer of warranty in their entirety. B. To distribute this\n\
  27. work, or copies made under the provisions above, so long as (1) this is\n\
  28. the original work and not a derivative form; (2) you do not charge a fee\n\
  29. for copying or for distribution; (3) you ensure that the distributed form\n\
  30. includes the copyright notice, this paragraph, and the disclaimer of\n\
  31. warranty in their entirety. These rights are temporary and revocable upon\n\
  32. written, oral, or other notice by Daniel J. Bernstein. These rights are\n\
  33. automatically revoked on January 1, 1995. This copyright notice shall be\n\
  34. governed by the laws of the state of New York.\n\
  35. \n\
  36. If you have questions about attachport or about this copyright notice,\n\
  37. or if you would like additional rights beyond those granted above,\n\
  38. please feel free to contact the author at brnstnd@acf10.nyu.edu\n\
  39. on the Internet.\n";
  40.  
  41. static char attachportwarranty[] =
  42. "To the extent permitted by applicable law, Daniel J. Bernstein disclaims\n\
  43. all warranties, explicit or implied, including but not limited to the\n\
  44. implied warranties of merchantability and fitness for a particular purpose.\n\
  45. Daniel J. Bernstein is not and shall not be liable for any damages,\n\
  46. incidental or consequential, arising from the use of this program, even\n\
  47. if you inform him of the possibility of such damages. This disclaimer\n\
  48. shall be governed by the laws of the state of New York.\n\
  49. \n\
  50. In other words, use this program at your own risk.\n\
  51. \n\
  52. If you have questions about attachport or about this disclaimer of warranty,\n\
  53. please feel free to contact the author at brnstnd@acf10.nyu.edu\n\
  54. on the Internet.\n";
  55.  
  56. static char attachportusage[] =
  57. "Usage: attachport [ -01vrRxXACHUVW ] [ -pport ] program [ arg ... ]\n\
  58. Help:  attachport -H\n";
  59.  
  60. static char attachporthelp[] =
  61. "attachport attaches a server program to a TCP port.\n\
  62. \n\
  63. attachport -A: print authorship notice\n\
  64. attachport -C: print copyright notice\n\
  65. attachport -H: print this notice\n\
  66. attachport -U: print short usage summary\n\
  67. attachport -V: print version number\n\
  68. attachport -W: print disclaimer of warranty\n\
  69. \n\
  70. attachport [ -01vrRxX ] [ -pport ] program [ arg ... ]: attach program to port\n\
  71.   -v: verbose: proclaim success\n\
  72.   -1: print port number on standard output\n\
  73.   -0: check every ten seconds for fd 0 to have links; if none, wither away\n\
  74.   -x: locally authenticate connections with authd(8) (default)\n\
  75.   -X: do not locally authenticate\n\
  76.   -r: attempt to authenticate the remote side as well (default), placing\n\
  77.       user@host and TCP into environment variables REMOTE and PROTO\n\
  78.   -R: do not remotely authenticate\n\
  79.   -pport: attach server to a particular TCP port\n\
  80. \n\
  81. If you have questions about or suggestions for attachport, please feel free\n\
  82. to contact the author, Daniel J. Bernstein, at brnstnd@acf10.nyu.edu\n\
  83. on the Internet.\n";
  84.  
  85. #include <stdio.h>
  86. #include <sys/types.h>
  87. #include <sys/file.h>
  88. #ifdef BSD
  89. #include <limits.h>
  90. #endif
  91. #include <sys/ioctl.h>
  92. #include <sys/socket.h>
  93. #include <sys/time.h>
  94. #include <sys/wait.h>
  95. #include <sys/resource.h>
  96. #include <sys/stat.h>
  97. #include <netinet/in.h>
  98. #include <arpa/inet.h>
  99. #include <netdb.h>
  100. #include <signal.h>
  101. #include <sys/param.h>
  102. #include <pwd.h>
  103. extern char *malloc(); /* many systems don't have malloc.h */
  104. extern int getopt();
  105. extern char *optarg; /* these should be in getopt.h! */
  106. extern int optind;
  107. #include <ctype.h>
  108. #include "authuser.h"
  109. #include "djberr.h"
  110. #include "djbatoi.h"
  111.  
  112. #ifndef AUTHDIR
  113. #define AUTHDIR "/usr/etc/auth"
  114. #endif
  115.  
  116. #ifndef MAXHOSTNAMELEN
  117. #define MAXHOSTNAMELEN 128 /* stupid Suns don't define this in sys/param.h */
  118. #endif
  119.  
  120. int numkids = 0;
  121. int flagauth = 1;
  122.  
  123. unsigned long myinetaddr()
  124. {
  125.  char hn[MAXHOSTNAMELEN + 1];
  126.  struct hostent *he;
  127.  
  128.  if (gethostname(hn,MAXHOSTNAMELEN) == -1)
  129.    return((unsigned long) -1);
  130.  if ((he = gethostbyname(hn)) == NULL)
  131.    return((unsigned long) -1);
  132.  
  133.  return (*((unsigned long *) (he->h_addr)));
  134. }
  135.  
  136. dissociatetty()
  137. {
  138.  int fd;
  139.  
  140.  if ((fd = open("/dev/tty",O_RDWR)) == -1)
  141.   {
  142.    perrn2("%s","attachport: warning: cannot open /dev/tty");
  143.   }
  144.  else
  145.   {
  146.    if (ioctl(fd,(unsigned long) TIOCNOTTY,(char *) NULL) == -1)
  147.      perrn2("%s","attachport: warning: cannot dissociate /dev/tty");
  148.    (void) close(fd);
  149.   }
  150. }
  151.  
  152. int uid;
  153. int euid;
  154.  
  155. int flagcheckin = 0;
  156. int alrmcounter = 0;
  157.  
  158. int flagdie;
  159.  
  160. sigterm()
  161. {
  162.  flagdie = 1;
  163. }
  164.  
  165. sigalrm()
  166. {
  167.  struct stat st;
  168.  
  169.  if (flagcheckin)
  170.   {
  171.    (void) fstat(0,&st);
  172.    if (st.st_nlink == 0)
  173.      sigterm();
  174.   }
  175.  if ((++alrmcounter) % 12) /* every two minutes */
  176.   {
  177.    alrmcounter = 0;
  178.    (void) kill(getpid(),SIGCHLD);
  179.   }
  180. }
  181.  
  182. sigchld()
  183. {
  184.  int w;
  185.  char authfn[sizeof(AUTHDIR) + 30];
  186.  char authpfn[sizeof(AUTHDIR) + 30];
  187.  int authpfd;
  188.  int r;
  189.  int noweuid = geteuid();
  190.  
  191.  if (noweuid == uid) /* oopsie */
  192.    if (setreuid(uid,euid))
  193.     {
  194.      perrn2("%s","attachport: warning: cannot setreuid");
  195.      return; /* This is impossible anyway. */
  196.     }
  197.  
  198.  while ((w = wait3((union wait *) 0,WNOHANG,(struct rusage *) NULL)) > 0)
  199.   {
  200.    numkids--;
  201.    if (flagauth)
  202.     {
  203.      (void) sprintf(authpfn,"%s/tcp/ps.%d.%d",AUTHDIR,getpid(),w);
  204.      if ((authpfd = open(authpfn,O_RDONLY,0600)) == -1)
  205.       {
  206.        perrn2("attachport: warning: cannot unlink authentication entry %s",authpfn);
  207.        continue;
  208.       }
  209.      r = read(authpfd,authfn,sizeof(authfn));
  210.      (void) close(authpfd);
  211.      if ((r <= 0) || (strncmp(authfn,AUTHDIR,strlen(AUTHDIR))))
  212.       { /* Make sure the worst damage we can do is confined to AUTHDIR. */
  213.        perrn2("attachport: warning: cannot unlink authentication entry %s",authpfn);
  214.        continue;
  215.       }
  216.      authfn[r] = '\0';
  217.      if (unlink(authfn) == -1) /* had better succeed! */
  218.       {
  219.        perrn2("attachport: warning: cannot unlink authentication entry %s",authfn);
  220.        continue;
  221.       }
  222.      if (unlink(authpfn) == -1) /* had better succeed! */
  223.       {
  224.        perrn2("attachport: warning: cannot unlink authentication entry %s",authpfn);
  225.       }
  226.     }
  227.   }
  228.  
  229.  if (noweuid == uid) /* daisie */
  230.    if (setreuid(euid,uid))
  231.     {
  232.      perrn2("%s","attachport: warning: cannot setreuid");
  233.      return;
  234.     }
  235. }
  236.  
  237. extern char **environ;
  238.  
  239. main(argc,argv,envp)
  240. int argc;
  241. char *argv[];
  242. char *envp[];
  243. {
  244.  int opt;
  245.  int flagverbose = 0;
  246.  int flagminiverb = 0;
  247.  int flagremote = 2;
  248.  char *strlocalport = "0";
  249.  unsigned short localport;
  250.  char **program = NULL;
  251.  struct sockaddr_in sa;
  252.  int s;
  253.  int t;
  254.  unsigned long in;
  255.  int dummy;
  256.  struct passwd *pw;
  257.  int f;
  258.  int authfd;
  259.  int authpfd;
  260.  char authfn[sizeof(AUTHDIR) + 30];
  261.  char authpfn[sizeof(AUTHDIR) + 30];
  262.  char lockfn[sizeof(AUTHDIR) + 30];
  263.  int lockfd;
  264.  char lockbuf[32]; /* 5 pid, 1 :, 10 I, 1 ., 5 R, 1 \n, 8 U, 1\0 */
  265.            /* we use just 5 pid, 1 -, 8 U, 1\0 */
  266.  int lockbuflen;
  267.  char foobuf[32];
  268.  struct itimerval it;
  269.  fd_set ready;
  270.  struct servent *se;
  271.  struct in_addr inet; /* dummy for inet_ntoa */
  272.  int flagsigintign;
  273.  int flagsigquitign;
  274.  int flagsigtstpign;
  275.  int flagsighupign;
  276.  int flagsigxcpuign;
  277.  int flagsigxfszign;
  278.  int flagsigvtalrmign;
  279.  int flagsigprofign;
  280.  int flagsigchldign;
  281.  int flagsigalrmign;
  282.  int flagsigtermign;
  283.  
  284.  /* ALERT! ALERT! ALERT! We're probably running setuid auth! */
  285.  /* Note that accounting is by real uid, not effective uid. */
  286.  /* The system should be careful about setuid core dumps 'n' such. */
  287.  
  288.  uid = getuid();
  289.  euid = geteuid();
  290.  
  291.  /* The following are necessary to be absolutely sure of removing the
  292.     authentication entry. It's a flaw of the signal handling system that
  293.     every new extension could turn a secure program like this into an
  294.     (ever so slightly) insecure one. */
  295.  flagsigintign = (signal(SIGINT,SIG_IGN) == SIG_IGN);
  296.  flagsigquitign = (signal(SIGQUIT,SIG_IGN) == SIG_IGN);
  297.  flagsigtstpign = (signal(SIGTSTP,SIG_IGN) == SIG_IGN);
  298.  flagsighupign = (signal(SIGHUP,SIG_IGN) == SIG_IGN);
  299.  flagsigxcpuign = (signal(SIGXCPU,SIG_IGN) == SIG_IGN);
  300.  flagsigxfszign = (signal(SIGXFSZ,SIG_IGN) == SIG_IGN);
  301.  flagsigvtalrmign = (signal(SIGVTALRM,SIG_IGN) == SIG_IGN);
  302.  flagsigprofign = (signal(SIGPROF,SIG_IGN) == SIG_IGN);
  303.  flagsigchldign = (signal(SIGCHLD,SIG_IGN) == SIG_IGN);
  304.  flagsigalrmign = (signal(SIGALRM,SIG_IGN) == SIG_IGN);
  305.  flagsigtermign = (signal(SIGTERM,SIG_IGN) == SIG_IGN);
  306.  /* At least we can depend on SIG_IGN and SIG_DFL being the only
  307.     possible handlers passed through an exec. Programmers should note
  308.     the above trick to avoid having to worry about the signal() type. */
  309.  
  310.  while ((opt = getopt(argc,argv,"01vrRxXp:ACHUVW")) != EOF)
  311.    switch(opt)
  312.     {
  313.      case 'v': flagverbose = 1; break;
  314.      case '1': flagminiverb = 1; break;
  315.      case '0': flagcheckin = 1; break;
  316.      case 'r': flagremote = 1; break;
  317.      case 'R': flagremote = 0; break;
  318.      case 'x': flagauth = 1; break;
  319.      case 'X': flagauth = 0; break;
  320.      case 'p': strlocalport = optarg; break;
  321.      case 'A': (void) err(attachportauthor);(void)setreuid(uid,uid); exit(1);
  322.      case 'C': (void) err(attachportcopyright);(void)setreuid(uid,uid); exit(1);
  323.      case 'H': (void) err(attachporthelp);(void)setreuid(uid,uid); exit(1);
  324.      case 'U': (void) err(attachportusage);(void)setreuid(uid,uid); exit(1);
  325.      case 'V': (void) err(attachportversion);(void)setreuid(uid,uid); exit(1);
  326.      case 'W': (void) err(attachportwarranty);(void)setreuid(uid,uid); exit(1);
  327.      case '?': (void) err(attachportusage);(void)setreuid(uid,uid); exit(1);
  328.     }
  329.  argv += optind; argc -= optind;
  330.  program = argv;
  331.  
  332.  if ((program == NULL) || (*program == NULL))
  333.   {
  334.    (void) err(attachportusage);
  335.    (void) setreuid(uid,uid); exit(1);
  336.   }
  337.  
  338.  in = myinetaddr();
  339.  if (in == (unsigned long) -1)
  340.   {
  341.    (void) errn("attachport: fatal: can't find my own Internet number?!");
  342.    (void) setreuid(uid,uid); exit(1);
  343.   }
  344.  
  345.  t = strlen(strlocalport) - 1;
  346.  if (isascii(strlocalport[t]) && isdigit(strlocalport[t]))
  347.    localport = atoi(strlocalport); /* so who cares if it's zero? */
  348.  else
  349.    if ((se = getservbyname(strlocalport,"tcp")) == NULL)
  350.      localport = 0;
  351.    else
  352.      localport = ntohs(se->s_port); /* inconsistency alert! */
  353.                     /* se->s_port is int! */
  354.  
  355.  if (flagauth)
  356.    if ((pw = getpwuid(uid)) == NULL)
  357.     {
  358.      (void) errn("attachport: fatal: cannot authenticate: who are you?");
  359.      (void) setreuid(uid,uid); exit(1);
  360.     }
  361.  
  362.  /* We now switch to the real user id, though preserving euid for auth. */
  363.  
  364.  if (setreuid(euid,uid))
  365.   {
  366.    perrn2("%s","attachport: fatal: cannot setreuid");
  367.    (void) setreuid(uid,uid); exit(1);
  368.   }
  369.  
  370.  if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) /* no security problem */
  371.   {
  372.    perrn2("%s","attachport: fatal: cannot create socket");
  373.    (void) setreuid(uid,uid); exit(1);
  374.   }
  375.  
  376.  sa.sin_family = AF_INET;
  377.  sa.sin_port = htons(localport);
  378.  sa.sin_addr.s_addr = INADDR_ANY;
  379.  
  380.  if (bind(s,&sa,sizeof(sa)) == -1)
  381.   {
  382.    perrn2("%s","attachport: fatal: cannot bind");
  383.    (void) setreuid(uid,uid); exit(1);
  384.   }
  385.  
  386.  if (listen(s,5) == -1) /* 5 should be an option! */
  387.   {
  388.    perrn2("%s","attachport: fatal: cannot listen");
  389.    (void) setreuid(uid,uid); exit(1);
  390.   }
  391.  
  392.  dissociatetty();
  393.  
  394.  (void) signal(SIGTERM,sigterm); /* for killaport */
  395.  (void) signal(SIGALRM,sigalrm); /* used to be just if flagcheckin */
  396.  it.it_value.tv_sec = 10; it.it_value.tv_usec = 0; /* every ten seconds */
  397.  it.it_interval.tv_sec = 10; it.it_interval.tv_usec = 0;
  398.  (void) setitimer(ITIMER_REAL,&it,(struct itimerval *) 0);
  399.  
  400.  /* we still have uids switched */
  401.  if (setreuid(uid,euid))
  402.   {
  403.    perrn2("%s","attachport: fatal: cannot setreuid");
  404.    (void) setreuid(uid,uid); exit(1);
  405.   }
  406.  /* Now we're back to setuid auth... */
  407.  
  408.  dummy = sizeof(sa);
  409.  if (getsockname(s,&sa,&dummy) == -1)
  410.   {
  411.    perrn2("%s","attachport: fatal: cannot get socket name");
  412.    (void) setreuid(uid,uid); exit(1);
  413.   }
  414.  if (flagremote == 2)
  415.    flagremote = (ntohs(sa.sin_port) != 113);
  416.  if (flagverbose)
  417.    (void) errn2("attachport: attached to port %d",ntohs(sa.sin_port));
  418.  if (flagminiverb)
  419.   {
  420.    (void) printf("%d\n",ntohs(sa.sin_port));
  421.    (void) fflush(stdout);
  422.   }
  423.  if (flagauth)
  424.   {
  425.    (void) sprintf(lockfn,"%s/tcp/lock.%u",AUTHDIR,
  426.           (unsigned int) ntohs(sa.sin_port));
  427.    if (((lockfd = open(lockfn,O_WRONLY | O_CREAT | O_EXCL,0600)) == -1)
  428.      &&(((lockfd = open(lockfn,O_RDONLY)) == -1)
  429.     ||(flock(lockfd,LOCK_EX) == -1)
  430.         ||(read(lockfd,lockbuf,31) <= 0)
  431.     ||((lockbuf[0] != '!')
  432.           &&((atoi(lockbuf) <= 0)
  433.              ||(kill(atoi(lockbuf),0) == 0))) /* okay, screw the last process */
  434.     ||(close(lockfd) == -1) /* impossible */
  435.         ||((lockfd = open(lockfn,O_WRONLY | O_CREAT | O_TRUNC,0600)) == -1)))
  436.     { /* yikes, that was incomprehensible */
  437.      errn2("attachport: fatal: local port %u locked",
  438.        (unsigned int) ntohs(sa.sin_port));
  439.      (void) setreuid(uid,uid); exit(1);
  440.     }
  441.    (void) flock(lockfd,LOCK_EX);
  442.    (void) sprintf(lockbuf,"%d-%s",getpid(),pw->pw_name);
  443.    lockbuflen = strlen(lockbuf);
  444.    (void) sprintf(foobuf,"!%s%d",pw->pw_name,getpid());
  445.    (void) write(lockfd,lockbuf,lockbuflen);
  446.    (void) flock(lockfd,LOCK_UN);
  447.   }
  448.  
  449.  /* We must remain setuid auth as long as there are live authentication */
  450.  /* entries. Otherwise the user could kill us and, if lucky enough, */
  451.  /* misauthenticate future connections. It isn't so important to worry */
  452.  /* about the lock file: that can only lead to a denial of service, and */
  453.  /* it would take a huge amount of effort to guarantee that denial. */
  454.  /* Anyway, we have to fork as the real uid: one system stupidity is */
  455.  /* that fork() uses the effective uid for MAXUPRC checks. This isn't */
  456.  /* a problem if there are no live authentication entries. */
  457.  
  458.  /* The solution is simple: We screw up the lock file while forking as */
  459.  /* the real uid, then restore it afterwards. If we're killed in the */
  460.  /* middle, authd will notice. This once again reduces the problem to */
  461.  /* denial of service, which is acceptable. (In fact, the nature of the */
  462.  /* messed up lock file is that it can't even cause denial of service.) */
  463.  /* Ha! */
  464.  
  465.  (void) signal(SIGCHLD,sigchld);
  466.  for (;;)
  467.    if (flagdie)
  468.      if (numkids > 0)
  469.        sleep(60);
  470.      else
  471.       {
  472.        if (flagauth)
  473.      (void) unlink(lockfn);
  474.        (void) setreuid(uid,uid); exit(0); /* ahhh, so simple */
  475.       }
  476.    else
  477.     {
  478.      FD_ZERO(&ready); /* why, oh why doesn't this pass lint? */
  479.      FD_SET(s,&ready);
  480.      while ((select(s + 1,&ready,(fd_set *) 0,(fd_set *) 0,0) < 0)
  481.         && !flagdie)
  482.        ; /* on error, ready won't be affected, so this is safe */
  483.      if (!flagdie) /* could be set any time, so we have to check */
  484.       {
  485.        dummy = sizeof(sa);
  486.        (void) flock(lockfd,LOCK_EX);
  487.        (void) lseek(lockfd,(off_t) 0,0);
  488.        (void) write(lockfd,foobuf,lockbuflen);
  489.        if ((t = accept(s,&sa,&dummy)) > -1)
  490.          if (setreuid(euid,uid))
  491.       {
  492.        perrn2("%s","attachport: warning: cannot setreuid");
  493.        (void) setreuid(uid,euid);
  494.       }
  495.          else if ((f = fork()) == 0)
  496.           {
  497.            if (setreuid(uid,euid))
  498.             {
  499.              perrn2("%s","attachport: fatal: cannot setreuid");
  500.              (void) setreuid(uid,uid); exit(1);
  501.             }
  502.            if (flagauth)
  503.             {
  504.              (void) sprintf(authfn,"%s/tcp/%D.%d.%d",AUTHDIR,
  505.                             sa.sin_addr.s_addr,localport,ntohs(sa.sin_port));
  506.              (void) sprintf(authpfn,"%s/tcp/ps.%d.%d",AUTHDIR,getppid(),getpid());
  507.            if ((authpfd = open(authpfn,O_WRONLY | O_CREAT | O_EXCL,0600)) == -1)
  508.             {
  509.                perrn2("%s","attachport: warning: cannot authenticate");
  510.           }
  511.              if ((authfd = open(authfn,O_WRONLY | O_CREAT | O_EXCL,0600)) == -1)
  512.               {
  513.                perrn2("%s","attachport: warning: cannot authenticate");
  514.               }
  515.              (void) write(authpfd,authfn,strlen(authfn));
  516.              (void) write(authfd,pw->pw_name,strlen(pw->pw_name));
  517.              (void) close(authpfd);
  518.              (void) close(authfd); /* if it fails, tough luck. */
  519.             }
  520.  
  521.            if (flagremote)
  522.             {
  523.              unsigned long in; /* keep confirming variables separate */
  524.              unsigned short local;
  525.              unsigned short remote;
  526.              char *ruser;
  527.              char *srem;
  528.              char **temp;
  529.              char **trem;
  530.              char **tproto;
  531.              char **envbak;
  532.         
  533.              if (auth_fd(t,&in,&local,&remote) == -1)
  534.               {
  535.                perrn2("%s","attachport: fatal: cannot confirm connection");
  536.                exit(1);
  537.               }
  538.              if ((ruser = auth_tcpuser(in,local,remote)) == NULL)
  539.                ruser = ""; /* bummer */
  540.              if ((srem = malloc(strlen(ruser) + 30)) == NULL)
  541.               {
  542.                perrn2("%s","attachport: fatal: cannot allocate environment");
  543.                exit(1);
  544.               }
  545.          inet.s_addr = in;
  546.          sprintf(srem,"REMOTE=%s@%s",ruser,inet_ntoa(inet));
  547.              for (trem = envp;*trem;trem++)
  548.                if (strncmp(*trem,"REMOTE=",7) == 0)
  549.                  break;
  550.              for (tproto = envp;*tproto;tproto++)
  551.                if (strncmp(*tproto,"PROTO=",6) == 0)
  552.                  break;
  553.              if (!(*trem && *tproto))
  554.               {
  555.                envbak = envp;
  556.                if ((environ = (char **) malloc((trem - envp + 3) * sizeof(char*)))
  557.            == NULL)
  558.                 {
  559.                  perrn2("%s","attachport: fatal: cannot allocate environment");
  560.                  exit(1);
  561.                 }
  562.                for (temp = envbak;*temp;temp++)
  563.                  environ[temp - envbak] = *temp; /* not worth a bcopy */
  564.                trem = environ + ((*trem ? trem : temp++) - envbak);
  565.                tproto = environ + ((*tproto ? tproto : temp++) - envbak);
  566.                environ[temp - envbak] = NULL;
  567.               }
  568.              *trem = srem;
  569.              *tproto = "PROTO=TCP";
  570.              /* XXXXXX: Should we do confirming sanity checks here? */
  571.             }
  572.            (void) close(0); (void) dup(t);
  573.            (void) close(1); (void) dup(t);
  574.            (void) close(2); (void) dup(t);
  575.        for (t = getdtablesize();t > 2;t--)
  576.              (void) close(t);
  577.     
  578.            (void) signal(SIGINT,flagsigintign ? SIG_IGN : SIG_DFL);
  579.            (void) signal(SIGQUIT,flagsigquitign ? SIG_IGN : SIG_DFL);
  580.            (void) signal(SIGTSTP,flagsigtstpign ? SIG_IGN : SIG_DFL);
  581.            (void) signal(SIGHUP,flagsighupign ? SIG_IGN : SIG_DFL);
  582.            (void) signal(SIGXCPU,flagsigxcpuign ? SIG_IGN : SIG_DFL);
  583.            (void) signal(SIGXFSZ,flagsigxfszign ? SIG_IGN : SIG_DFL);
  584.            (void) signal(SIGVTALRM,flagsigvtalrmign ? SIG_IGN : SIG_DFL);
  585.            (void) signal(SIGPROF,flagsigprofign ? SIG_IGN : SIG_DFL);
  586.            (void) signal(SIGCHLD,flagsigchldign ? SIG_IGN : SIG_DFL);
  587.            (void) signal(SIGALRM,flagsigalrmign ? SIG_IGN : SIG_DFL);
  588.            (void) signal(SIGTERM,flagsigtermign ? SIG_IGN : SIG_DFL);
  589.  
  590.            if (setreuid(uid,uid))
  591.             {
  592.              perrn2("%s","attachport: fatal: cannot setreuid");
  593.              (void) setreuid(uid,uid); exit(1);
  594.             }
  595.  
  596.            /* Yes, Virginia, this is portable. Read execvp(3). */
  597.            /* Annoying that there isn't a better interface, though. */
  598.            (void) execvp(*program,program); /* must use environ! */
  599.        /* option to yell to remote end about failure? hmmm */
  600.            exit(1);
  601.           }
  602.          else if (f == -1)
  603.           {
  604.            /* option to yell to remote end before closing? perhaps */
  605.            (void) close(t); /* sigh */
  606.            if (setreuid(uid,euid))
  607.             {
  608.              perrn2("%s","attachport: warning: cannot setreuid");
  609.          (void) setreuid(uid,euid);
  610.             }
  611.           }
  612.          else
  613.           {
  614.            if (setreuid(uid,euid))
  615.             {
  616.              perrn2("%s","attachport: warning: cannot setreuid");
  617.          (void) setreuid(uid,euid);
  618.             }
  619.        numkids++;
  620.            (void) close(t);
  621.           }
  622.        (void) lseek(lockfd,(off_t) 0,0);
  623.        (void) write(lockfd,lockbuf,lockbuflen);
  624.        (void) flock(lockfd,LOCK_UN);
  625.       }
  626.     }
  627.  /*NOTREACHED*/
  628. }
  629.