home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / pty4 / part05 / ptysecure.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-18  |  6.6 KB  |  241 lines

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <sys/file.h>
  4. #include <errno.h>
  5. extern int errno;
  6. #include "ptysecure.h"
  7. #include "ptytty.h"
  8. #include "config/ptymodes.h"
  9. #include "config/ptygroup.h"
  10.  
  11. static struct stat storig;
  12.  
  13. /* must close fdm and fds upon -1 return */
  14. int ptysecure(fdm,fds,ext,fnm,fns,flagxchown,allowinsecure)
  15. int *fdm; /* master */
  16. int *fds; /* slave */
  17. char *ext; /* char array, not string */
  18. char *fnm;
  19. char *fns;
  20. int flagxchown;
  21. int allowinsecure;
  22. {
  23. /* XXX: check that the pathnames are secure? nah */
  24. /* XXX: vhangup(): don't make me laugh */
  25. /* XXX: revoke() under 4.4 */
  26. /* XXX: ofiles... fstat... pff... */
  27. /* XXX: opencount()---but what about unprivileged users? */
  28.  
  29. /* We have the master and slave open. */
  30. /* Any number of other processes may have the slave open. */
  31. /* Any number of other processes may have our pgrp. */
  32.  
  33. /* We depend on never passing the master side to another process. */
  34. /* We depend on opens of the master side being mutually exclusive. */
  35. /* We opened the master, so no other process has the master open. */
  36. /* Through this routine we will never close the master. */
  37. /* Hence no other process will have the master open while we work. */
  38.  
  39.  char buf[20];
  40.  int fdp[2];
  41.  char psarg1[20];
  42.  int kidpid;
  43.  int numpsrets;
  44.  int pspid;
  45.  int flagchmodworked;
  46.  int parsingpid;
  47.  char *(psargs[3]);
  48.  int r;
  49.  
  50.  if (fstat(*fds,&storig) == -1)
  51.    goto death;
  52.  flagchmodworked = 1;
  53.  if (storig.st_uid != geteuid())
  54.    flagchmodworked = 0;
  55.  if (!allowinsecure && !flagchmodworked)
  56.    goto death;
  57.  if (fchmod(*fds,0600) == -1)
  58.   {
  59.    flagchmodworked = 0;
  60.    /* XXX: warning? other action? */
  61.   }
  62.  if (!allowinsecure && !flagchmodworked)
  63.    goto pdeath;
  64. /* All security guarantees are off unless the slave tty is now */
  65. /* protected from open() by normal users. In other words, we require */
  66. /* either (1) being the owner of the tty, so that the fchmod worked, */
  67. /* or (2) being privileged and having the slave ttys be protected */
  68. /* all the time anyway. (2) is a better situation. (1) is more */
  69. /* realistic for pty installations under current systems. Anyway, */
  70. /* we don't do the more powerful security tests if we can't chmod. */
  71.  
  72. /* Anyway, we depend on the slave tty now being unopenable by users. */
  73. /* This situation will persist until we change the mode again. */
  74. /* (In situation (2) it will always be true.) */
  75.  
  76. /* We depend on read() of the master side returning 0 or -1/EIO if */
  77. /* nobody has the slave side open, and something else otherwise. */
  78.  close(*fds); r = read(*fdm,buf,1);
  79.  if (r > 0) { /* XXX: warning? */ goto pmdeath; }
  80.  if ((r == -1) && (errno != EIO) && (errno != EWOULDBLOCK))
  81.   { /* XXX: warning? */ goto pmdeath; }
  82.  *fds = open(fns,O_RDWR);
  83.  if (*fds == -1) goto pmdeath;
  84.  
  85. /*
  86. Now nobody but us has the slave side open.
  87. Furthermore, as noted above, nobody but us has the master side open,
  88. and nobody will be able to open either the master or the slave.
  89.  
  90. But we're still not done! A process can access a tty even if the tty
  91. is completely protected, and even if it doesn't have a descriptor open
  92. to the tty. (Does this sound stupid? It is.) All it has to do is open
  93. /dev/tty, provided that it has the right controlling terminal. Before
  94. pronouncing the tty secure we have to take care of processes with the
  95. same ctty.
  96.  
  97. We depend on the fact that all methods of associating a process with a
  98. tty depend on (1) having the actual tty (not just /dev/tty) open; or
  99. (2) opening the tty. We know that nobody can have the actual tty open
  100. from here on.
  101. */
  102.  
  103.  if (flagchmodworked)
  104.   {
  105.    if (pipe(fdp) == -1)
  106.      goto pdeath;
  107.   
  108.    switch(kidpid = fork())
  109.     {
  110.      case -1:
  111.        close(fdp[0]);
  112.        close(fdp[1]);
  113.        goto pdeath;
  114.      case 0:
  115.        /* XXX: WARNING! We invoke /bin/ps with our privileges! */
  116.        /* If we switched back to the real uid, we couldn't trust the results. */
  117.        close(*fdm); close(*fds);
  118.        close(0); if (dup(fdp[0]) != 0) exit(1);
  119.        close(1); if (dup(fdp[1]) != 1) exit(1);
  120.        close(2); if (dup(fdp[1]) != 2) exit(1);
  121.        close(fdp[0]);
  122.        close(fdp[1]);
  123.        close(0);
  124.        psargs[0] = "/bin/ps";
  125.        psargs[1] = psarg1;
  126.        psarg1[0] = 'c'; psarg1[1] = 'g'; psarg1[2] = 'a'; psarg1[3] = 'x';
  127.        psarg1[4] = 't'; psarg1[5] = ext[0]; psarg1[6] = ext[1]; psarg1[7] = 0;
  128.        psargs[2] = (char *) 0;
  129.        setreuid(getuid(),getuid()); /* XXX: do we really want this? */
  130.        execve(psargs[0],psargs,psargs + 2);
  131.        exit(1);
  132.      default:
  133.        close(fdp[1]);
  134.     }
  135.   
  136.    numpsrets = 0;
  137.    parsingpid = 0;
  138.    while (read(fdp[0],buf,1) == 1)
  139.     {
  140.      if (parsingpid)
  141.        if ((buf[0] != ' ') && (10 > (unsigned long) (unsigned char) (buf[0] - '0')))
  142.          pspid = pspid * 10 + (buf[0] - '0');
  143.        else if (pspid)
  144.         {
  145.          parsingpid = 0;
  146.      /* XXX: tell user about pspid? */
  147.          if ((pspid == getpid()) || (pspid == kidpid))
  148.            --numpsrets; /*XXX*/
  149.         }
  150.      if (buf[0] == '\n')
  151.       {
  152.        parsingpid = 1;
  153.        pspid = 0;
  154.        ++numpsrets;
  155.       }
  156.     }
  157.    close(fdp[0]);
  158.    wait((int *) 0); /*XXX*/
  159.  
  160.    if (numpsrets != 1)
  161.     {
  162.      /* XXX: warning? */
  163.      goto pdeath;
  164.     }
  165.   }
  166.  
  167. /*
  168. We depend on /bin/ps being set up so that numpsrets == 1 implies that
  169. there were, at some point in time, no processes (except possibly us)
  170. with that tty as controlling tty.
  171.  
  172. Now lots of processes could have /dev/tty open and somehow pointing to
  173. this tty, but there are none (other than us) with the actual tty open,
  174. or with the master open, or with this controlling tty. There's an easy
  175. way to finish off: we simply repeat the first test!
  176. */
  177.  close(*fds); r = read(*fdm,buf,1);
  178.  if (r > 0) { /* XXX: warning? */ goto pmdeath; }
  179.  if ((r == -1) && (errno != EIO) && (errno != EWOULDBLOCK))
  180.   { /* XXX: warning? */ goto pmdeath; }
  181.  *fds = open(fns,O_RDWR);
  182.  if (*fds == -1) goto pmdeath;
  183.  
  184. /*
  185. Finally! The pseudo-tty is secure---or at least a hell of a lot more
  186. secure than the ttys you get from any other program.
  187. */
  188.  
  189.  if (fchmod(*fds,PTYMODE_USED) == -1)
  190.   {
  191.    /* XXX: warning? */
  192.    ;
  193.   }
  194.  if (flagxchown)
  195.   {
  196.    if (fchown(*fds,getuid(),PTYGROUP) == -1)
  197.     {
  198.      /* XXX: warning? */
  199.      ;
  200.     }
  201.   }
  202.  return 0;
  203.  
  204. pmdeath:
  205.  *fds = open(fns,O_RDWR);
  206. pdeath:
  207.  if (*fds != -1)
  208.    fchmod(*fds,PTYMODE_UNUSED);
  209. death:
  210.  close(*fds); /* *fds could be -1; that's okay */
  211. mdeath:
  212.  *fds = open("/dev/tty",O_RDWR);
  213.  if (*fds != -1)
  214.   {
  215.    if (tty_dissoc(*fds) == -1)
  216.      ;
  217.    close(*fds);
  218.   }
  219.  close(*fdm);
  220.  return -1;
  221. }
  222.  
  223. int ptyunsecure(fdm,fds,ext)
  224. int fdm;
  225. int fds;
  226. char *ext;
  227. {
  228.  if (fchmod(fds,PTYMODE_UNUSED) == -1)
  229.   {
  230.    /* XXX: warning? */
  231.    ;
  232.   }
  233.  if (getuid() != storig.st_uid)
  234.    if (fchown(fds,storig.st_uid,PTYGROUP) == -1)
  235.     {
  236.      /* XXX: warning? */
  237.      ;
  238.     }
  239.  return 0;
  240. }
  241.