home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / unix / admin / 4340 < prev    next >
Encoding:
Text File  |  1992-07-27  |  4.9 KB  |  201 lines

  1. Path: sparky!uunet!decwrl!bu.edu!wang!news
  2. From: warren@itexjct.jct.ac.il (Warren Burstein)
  3. Newsgroups: comp.unix.admin
  4. Subject: Is this program secure?
  5. Message-ID: <2333@itexjct.jct.ac.il>
  6. Date: 27 Jul 92 18:36:51 GMT
  7. Sender: news@wang.com
  8. Reply-To: warren@itexjct.jct.ac.il
  9. Organization: Mail to News Gateway at Wang Labs
  10. Lines: 189
  11.  
  12. The problem: people anonymously ftp files into our upload directory -
  13. these files are owned by ftp.  Also, sometimes people who have
  14. accounts ftp stuff into our uploads dir using their own login - these
  15. files are owned by the user.
  16.  
  17. The people who maintain the ftp archives log in as 'archives' rather
  18. than ftp (to minimize the damage that they can do) and need the files
  19. to be owned by archives so that they can do things like chmod them.
  20.  
  21. So I wrote this program which makes sure the user has an euid of
  22. archives or root and that the file is underneath ~ftp, and if so
  23. chowns it to archives.  The program will be suid root, so I'd like to 
  24. be sure there are no holes (like allowing someone to make a symbolic
  25. link to /etc, chown passwd and ...).  I think the tactic of starting
  26. from the file and constantly moving up one directory until I hit
  27. either root or ~ftp will work, but if I've done something stupid, I'd
  28. rather be told about it now before a hacker finds out.
  29.  
  30. And if I've re-invented the wheel, please let me know.
  31.  
  32. /*
  33.  * If the user is USER or root, and the file is underneath ~ftp,
  34.  * chown it to USER.
  35.  */
  36.  
  37. #include <stdio.h>
  38. #include <varargs.h>
  39. #include <pwd.h>
  40. #include <sys/types.h>
  41. #include <sys/stat.h>
  42.  
  43. #ifdef BSD
  44. #define strrchr rindex
  45. #endif
  46.  
  47. char *strrchr(), *strcpy(), *strncpy(), *strcat(), *malloc();
  48. #define TRUE 1
  49. #define FALSE 0
  50.  
  51. #define USER "archives"
  52. #define FTP  "ftp"
  53.  
  54. char *argv0;
  55.  
  56. main(argc, argv)
  57. char **argv;
  58. {
  59.     struct passwd *pw;
  60.     struct stat home_st, root_st;
  61.     int arg, uid = getuid(), user_uid, user_gid;
  62.     char *home_dir;
  63.     
  64.     argv0 = argv[0];
  65.     if (argc <= 1) {
  66.     fprintf(stderr, "usage: %s files\n", argv[0]);
  67.     exit(1);
  68.     }
  69.  
  70.     /*
  71.      * Check that program is suid root.  Won't do anything if it isn't
  72.      * so might as well give up.
  73.      */
  74.     if (geteuid() != 0)
  75.     fatal("program is not suid root");
  76.  
  77.     /*
  78.      * Get USER's pw to find uid and gid that files will get changed to
  79.      */
  80.     if ( !(pw = getpwnam(USER)))
  81.     fatal("user %s unknown", USER);
  82.     user_uid = pw->pw_uid;
  83.     user_gid = pw->pw_gid;
  84.  
  85.     /*
  86.      * Get FTP's pw to find it's home dir.  Get its stat.
  87.      */
  88.     if ( !(pw = getpwnam(FTP)))
  89.     fatal("user %s unknown", FTP);
  90.     if (stat(home_dir = pw->pw_dir, &home_st))
  91.     fatal("cannot stat dir %s", home_dir);
  92.  
  93.     /*
  94.      * Also get root's stat.
  95.      */
  96.     if (stat("/", &root_st))
  97.     fatal("cannot stat /");
  98.  
  99.     /*
  100.      * Check that user is USER or root.
  101.      */
  102.     if (uid != 0 && uid != user_uid)
  103.     fatal("you are not logged in as %s or root", USER);
  104.  
  105.     /*
  106.      * Change the files if underneath ~ftp.
  107.      */
  108.     for (arg = 1; arg < argc; arg++)
  109.     if ( !underneath(&home_st, &root_st, argv[arg]))
  110.         fprintf(stderr, "%s: file %s is not underneath %s\n",
  111.             argv0, argv[arg], home_dir);
  112.     else if (chown(argv[arg], user_uid, user_gid))
  113.         perror(argv[arg]);
  114. }
  115.  
  116. /*
  117.  * Is file underneath home_dir?
  118.  *
  119.  * Get the dir that the file is in
  120.  *   if it's identical to home_dir it's underneath
  121.  *   if it's identical to / it's not.
  122.  *   if it's not identical to either, append /.. and try again
  123.  */
  124. int underneath(home_st, root_st, file)
  125. char *file;
  126. struct stat *home_st, *root_st;
  127. {
  128.     char *dir;
  129.     struct stat st;
  130.  
  131.     /*
  132.      * If file contains a slash, its dir is the file truncated at the last
  133.      * slash.  Otherwise its dir is ..
  134.      */
  135.     if (dir = strrchr(file, '/')) {
  136.     int len = dir - file;
  137.  
  138.     if ( !(dir = malloc(len + 1)))
  139.         fatal("cannot alloc for %s", file);
  140.     strncpy(dir, file, len);
  141.     dir[len] = '\0';
  142.     } else {
  143.     if ( !(dir = malloc(3)))
  144.         fatal("cannot alloc for ..", file);
  145.     strcpy(dir, "..");
  146.     }
  147.  
  148.     /*
  149.      * Keep moving to .. until we hit either the root dir or the home dir.
  150.      */
  151. #define SAME_INODE(p, q) ((p)->st_ino==(q)->st_ino && (p)->st_dev==(q)->st_dev)
  152.     for (;;) {
  153.     char *new_dir;
  154.  
  155.     if (stat(dir, &st))
  156.         fatal("cannot stat dir %s", dir);
  157.  
  158.     if (SAME_INODE(&st, root_st)) {
  159.         free(dir);
  160.         return FALSE;
  161.     }
  162.  
  163.     if (SAME_INODE(&st, home_st)) {
  164.         free(dir);
  165.         return TRUE;
  166.     }
  167.  
  168.     /*
  169.      * Append /..
  170.      */
  171.     if ( !(new_dir = malloc(strlen(dir) + 4)))
  172.         fatal("cannot alloc for %s/..", file);
  173.     strcpy(new_dir, dir);
  174.     strcat(new_dir, "/..");
  175.     free(dir);
  176.     dir = new_dir;
  177.     }
  178. }
  179.  
  180. fatal(va_alist)
  181. va_dcl
  182. {
  183.     va_list args;
  184.     char *fmt;
  185.     extern char *argv0;
  186.  
  187.     va_start(args);
  188.     fmt = va_arg(args, char *);
  189.     (void) fprintf(stderr, "%s: ", argv0);
  190.     (void) vfprintf(stderr, fmt, args);
  191.     (void) fprintf(stderr, "\n");
  192.     va_end(args);
  193.  
  194.     exit(1);
  195. }
  196. -- 
  197. /|/-\/-\       The entire kitchen        Jerusalem
  198.  |__/__/_/     is a very Czarish apple.
  199.  |warren@      But the Kibo
  200. / nysernet.org is not all that paranoid.
  201.