home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3543 / npipeserver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-26  |  7.2 KB  |  292 lines

  1. /* Public domain. */
  2.  
  3. #include <stdio.h>
  4. #include <signal.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <sys/file.h>
  8. #include <sys/wait.h>
  9. #include <sys/time.h>
  10. #include "dupdup.h"
  11. #include "malloc.h"
  12. #include "errno.h"
  13. #include "username.h"
  14. #include "env.h"
  15. #include "getopt.h"
  16. #include "numfiles.h"
  17.  
  18. #ifndef O_RDONLY
  19. #define O_RDONLY 0
  20. #endif
  21. #ifndef O_WRONLY
  22. #define O_WRONLY 1
  23. #endif
  24.  
  25. static int flagprintlocal = 0;
  26. static int flagverbose = 1;
  27. static char fnserv[200];
  28. static char fnlock[200];
  29. static char fnexcl[200];
  30. static int fdserv;
  31. static int fdlock;
  32. static int fdexcl;
  33. static int flagbindok = 0;
  34.  
  35. unlinkem()
  36. {
  37.  if (flagbindok)
  38.   {
  39.    unlink(fnserv);
  40.    unlink(fnlock);
  41.    unlink(fnexcl);
  42.   }
  43. }
  44.  
  45. SIGRET sigterm()
  46. {
  47.  unlinkem();
  48.  exit(0);
  49. }
  50.  
  51. SIGRET sigchld()
  52. {
  53.  wait((int *) 0); /*XXX*/
  54. }
  55.  
  56. static char errbuf[500];
  57. void die(n,s) int n; char *s;
  58. { if (flagverbose) fprintf(stderr,"npipeserver: fatal: %s\n",s); exit(n); }
  59. void dies(n,s,t) int n; char *s; char *t;
  60. { if (flagverbose) fprintf(stderr,"npipeserver: fatal: %s%s\n",s,t); exit(n); }
  61. void diep(n,s) int n; char *s;
  62. { if (flagverbose) sprintf(errbuf,"npipeserver: fatal: %s",s); perror(errbuf); exit(n); }
  63. void warnp(s) char *s;
  64. { if (flagverbose) sprintf(errbuf,"npipeserver: warning: %s",s); perror(errbuf); }
  65. void warnsp(s,t) char *s; char *t;
  66. { if (flagverbose) sprintf(errbuf,"npipeserver: warning: %s%s",s,t); perror(errbuf); }
  67.  
  68. main(argc,argv,envp)
  69. int argc;
  70. char *argv[];
  71. char *envp[];
  72. {
  73.  int *d;
  74.  int numfiles;
  75.  int uid;
  76.  int arguid;
  77.  int i;
  78.  int r;
  79.  int n;
  80.  char fns2c[200];
  81.  char fnc2s[200];
  82.  char buf[100];
  83.  int pid;
  84.  int fds2c;
  85.  int fdc2s;
  86.  char npipelocal[200]; /*XXX*/
  87.  char npiperemote[300]; /*XXX*/
  88.  int opt;
  89.  
  90.  while ((opt = getopt(argc,argv,"qQ4")) != EOF)
  91.    switch(opt)
  92.     {
  93.      case 'q':
  94.        flagverbose = 0;
  95.        break;
  96.      case 'Q':
  97.        flagverbose = 1;
  98.        break;
  99.      case '4':
  100.        flagprintlocal = 1;
  101.        break;
  102.      case '?':
  103.        break; /*XXX*/
  104.      default:
  105.        break; /*XXX*/
  106.     }
  107.  argc -= optind; argv += optind;
  108.  
  109.  if (argc < 3)
  110.    die(1,"need at least three arguments");
  111.  
  112.  uid = getuid();
  113.  if (username2uid(argv[0],&arguid) == -1)
  114.    dies(2,"cannot figure out username ",argv[0]);
  115.  if (uid && (uid != arguid))
  116.    dies(3,"permission denied for username ",argv[0]);
  117.  
  118.  for (i = 0;argv[0][i];++i)
  119.    if ((argv[0][i] == '/') || (argv[0][i] == ':') || (argv[0][i] == '.') || (argv[0][i] == '\n'))
  120.      dies(4,"illegal characters in username ",argv[0]);
  121.  
  122.  for (i = 0;argv[1][i];++i)
  123.    if ((argv[1][i] == '/') || (argv[1][i] == '.') || (argv[0][i] == '\n'))
  124.      dies(5,"illegal characters in service ",argv[1]);
  125.  
  126.  close(6);
  127.  close(7); /* XXX: these have implications that should be documented */
  128.  
  129.  numfiles = NUMFILES;
  130.  d = (int *) malloc(numfiles * sizeof(int));
  131.  if (!d)
  132.    die(6,"cannot malloc");
  133.  for (i = 0;i < numfiles;++i)
  134.    d[i] = -1;
  135.  
  136.  if (strlen(NPIPEDIR) + strlen(argv[0]) + strlen(argv[1]) + 1 > 90) /*XXX*/
  137.    die(8,"server filenames too long");
  138.  sprintf(fnserv,"%s/%ds%s",NPIPEDIR,arguid,argv[1]);
  139.  sprintf(fnlock,"%s/%dl%s",NPIPEDIR,arguid,argv[1]);
  140.  sprintf(fnexcl,"%s/%de%s",NPIPEDIR,arguid,argv[1]);
  141.    /* XXX: Even if arguid has 5 digits, this leaves 8 characters for
  142.       the service in System V filesystems. It might be worth switching
  143.       to a fixed-length or hex format... I dunno. */
  144.  
  145.  signal(SIGTERM,sigterm);
  146.  signal(SIGINT,sigterm);
  147.  signal(SIGCHLD,sigchld);
  148.  signal(SIGPIPE,SIG_IGN);
  149.  
  150.  if (env_init() == -1)
  151.    die(11,"cannot init environment");
  152.  if (env_put("PROTO=NPIPE") == -1)
  153.    die(11,"out of memory putting PROTO into environment");
  154.  sprintf(npipelocal,"NPIPELOCAL=%s:%s",argv[0],argv[1]);
  155.  if (env_put(npipelocal) == -1)
  156.    die(11,"out of memory putting NPIPELOCAL into environment");
  157.  
  158.  if (flagprintlocal)
  159.   {
  160.    FILE *fd4;
  161.    fd4 = fdopen(4,"w");
  162.    if (!fd4)
  163.      die(1,"cannot print NPIPELOCAL on fd 4");
  164.    fprintf(fd4,"%s:%s\n",argv[0],argv[1]);
  165.    fclose(fd4);
  166.    close(4); /* just in case */
  167.   }
  168.  
  169.  /* Action! */
  170.  
  171.  fdexcl = creat(fnexcl,0);
  172.  if (fdexcl == -1) /* somebody else got here before us */
  173.    die(1,"service already in use");
  174.  /* XXX: there's a race right here */
  175.  flagbindok = 1;
  176.  fdlock = creat(fnlock,0); /* refuse connections until we're ready */
  177.  if (fdlock == -1)
  178.    diep(1,"cannot create lock file");
  179.  if (write(fdlock,buf,1) < 1)
  180.    diep(1,"cannot write to lock file");
  181.  if (mknod(fnserv,010600,0) == -1)
  182.    diep(1,"cannot create server's named pipe");
  183.  if (chmod(fnlock,0600) == -1) /* gaargh. fchmod(fdlock,0600)! */
  184.    diep(1,"cannot set modes on lock file");
  185.  
  186.  /* I hate programming like this. In a real OS I'd just create the named
  187.     pipe---outside the directory hierarchy!---then try to link it in.
  188.     None of this stupid testing and locking and so on. Gaargh. */
  189.  
  190.  for (;;)
  191.   {
  192.    /* XXX: should we really die on simple I/O errors? */
  193.    for (;;)
  194.     {
  195.      fdserv = open(fnserv,O_RDONLY,0); /* this blocks */
  196.      /* XXX: don't accept too many requests at once? */
  197.      if (fdserv == -1) /* down the drain */
  198.       {
  199.        if (errno == EINTR)
  200.      continue;
  201.        unlinkem();
  202.        diep(1,"cannot open server's named pipe");
  203.       }
  204.      break;
  205.     }
  206.    n = 0;
  207.    r = 0;
  208.    while ((n < sizeof(buf)) && ((r = read(fdserv,buf + n,sizeof(buf) - n)) > 0))
  209.      n += r;
  210.    if (r > 0)
  211.      ; /* overflowed buffer---shouldn't happen, we'll just truncate it */
  212.    if (r == -1)
  213.     {
  214.      unlinkem();
  215.      diep(1,"cannot read client's pid and username");
  216.     }
  217.    /* XXX: do something for killer? */
  218.    close(fdserv);
  219.    unlink(fnserv); /*XXX: check for errors?*/
  220.    for (i = 0;i < n;++i)
  221.      if (!buf[i])
  222.        break;
  223.    if (i == n)
  224.     {
  225.      unlinkem();
  226.      die(1,"cannot read remote username");
  227.     }
  228.    /* XXX: if i is n - 1, we have a null username */
  229.    ++i; /* now buf + i is the username */
  230.    if (sscanf(buf,"%d",&pid) < 1)
  231.     {
  232.      unlinkem();
  233.      die(1,"cannot read remote pid");
  234.     }
  235.    if (!pid) /* npipekiller */
  236.      sigterm(); /*XXX*/
  237.  
  238.    switch(fork())
  239.     {
  240.      case -1:
  241.        warnp("cannot fork");
  242.        /* XXX: say anything to other side? */
  243.        break;
  244.  
  245.      case 0:
  246.  
  247.        close(fdlock);
  248.        close(fdexcl);
  249.  
  250.        sprintf(fns2c,"%s/s2c.%d",NPIPEDIR,pid);
  251.        sprintf(fnc2s,"%s/c2s.%d",NPIPEDIR,pid);
  252.  
  253.        fds2c = open(fns2c,O_WRONLY,0); /* blocks */
  254.        if (fds2c == -1)
  255.      diep(1,"cannot open server-to-client pipe");
  256.        fdc2s = open(fnc2s,O_RDONLY,0); /* blocks */
  257.        if (fdc2s == -1)
  258.      diep(1,"cannot open client-to-server pipe");
  259.  
  260.        if (write(fds2c,buf,1) < 1)
  261.      diep(1,"cannot write on server-to-client pipe");
  262.  
  263.        sprintf(npiperemote,"NPIPEREMOTE=%s",buf + i);
  264.        if (env_put(npiperemote) == -1)
  265.      die(1,"out of memory putting NPIPEREMOTE into environment");
  266.  
  267.        /* Now put fdc2s into descriptor 6 and fds2c into descriptor 7. */
  268.        /* XXX: should check that fdc2s and fds2c are small enough */
  269.        d[fdc2s] = 6;
  270.        d[fds2c] = 7;
  271.        if (dupdup(d,numfiles) == -1)
  272.      diep(1,"cannot dup connection to client");
  273.  
  274.        if (setreuid(uid,uid) == -1)
  275.      diep(1,"cannot setreuid"); /* will never happen */
  276.        signal(SIGPIPE,SIG_DFL);
  277.        execvp(argv[2],argv + 2);
  278.        warnsp("cannot exec ",argv[2]);
  279.        exit(1);
  280.  
  281.      default:
  282.        ;
  283.     }
  284.    /* the cycle begins anew */
  285.    if (mknod(fnserv,010600,0) == -1)
  286.     {
  287.      unlinkem();
  288.      diep(1,"cannot create server's named pipe");
  289.     }
  290.   }
  291. }
  292.