home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / c / cops_104.zip / cops_104 / src / is_able.c < prev    next >
C/C++ Source or Header  |  1992-03-10  |  6KB  |  222 lines

  1. /*
  2.     Usage:
  3.  
  4.  is_able filename {w|g|s|S}       {r|w|B|b|s}
  5.          (world/group/SUID/SGID   read/write/{read&write}/{suid&write}/s[ug]id)
  6.  
  7.     The second arg of {r|w} determines whether a file is (group or world
  8.   depending on the first arg of {w|g}) writable/readable, or if it is
  9.   SUID/SGID (first arg, either s or S, respectively), and prints out a
  10.   short message to that effect.
  11.  
  12.  So:
  13.     is_able w w        # checks if world writable
  14.     is_able g r        # checks if group readable
  15.     is_able s s        # checks if SUID
  16.     is_able S b        # checks if world writable and SGID
  17.  
  18.       Permissions bits:          vvv--- Permission bits
  19.                1 = execute        00000
  20.                2 = writable         ^
  21.                4 = readable         + Setuid bits
  22.  
  23.       Setuid bits:
  24.                1 = sticky
  25.                2 = set group id
  26.                4 = set user od
  27.  
  28.     Pete Shipley (shipley@mica.berkeley.edu) gutted my original code,
  29.   made in cleaner and smarter, and combined everything into one compact
  30.   file.  What a deal, huh?  Then I came along and beat up his code and
  31.   made it look ugly again (I changed the is_writeable option to return
  32.   true if _any_ parent directories are writable, not just the target.  So
  33.   you can blame me if you want.  Better yet, just send me a patch if I
  34.   blew it.)
  35.  
  36. */
  37.  
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40. #include <ctype.h>
  41. #include <stdio.h>
  42.  
  43. #define G_READ_TEST 00044    /* group (or world) readable */
  44. #define W_READ_TEST 00004    /* world readable */
  45. #define G_READ_STRING    "Warning!  %s is group readable!\n"
  46. #define W_READ_STRING    "Warning!  %s is _World_ readable!\n"
  47.  
  48. #define G_WRITE_TEST 00022    /* group (or world) writable */
  49. #define W_WRITE_TEST 00002    /* world writable */
  50. #define G_WRITE_STRING    "Warning!  %s is group writable!\n"
  51. #define G_WRITE_TREE    "Warning!  %s is group writable! (*)\n"
  52. #define W_WRITE_STRING    "Warning!  %s is _World_ writable!\n"
  53. #define W_WRITE_TREE    "Warning!  %s is _World_ writable! (*)\n"
  54.  
  55. #define SGID_TEST 02000        /* set group id */
  56. #define SUID_TEST 04000        /* set user id */
  57. #define SUID_STRING    "Warning!  %s is SUID!\n"
  58. #define SGID_STRING    "Warning!  %s is SGID!\n"
  59.  
  60. char usage[]="Usage: is_able file {w|g|S|s} {r|w|B|b|}\n";
  61.  
  62. main(argc,argv)
  63. int argc;
  64. char **argv;
  65. {
  66. char file[256],wg,rwb,gstring[35],wstring[35],wstring_tree[50],
  67.     gstring_tree[50], suidstring[35];
  68. register int group, read, write, both, suid, sgid, verbose, xmode;
  69. static struct stat statb;
  70.  
  71. group=read=write=suid=sgid=both=verbose=xmode=0;
  72.  
  73. /* check out arguments */
  74. if (argc != 4) {
  75.     fprintf(stderr, usage);
  76.     exit(1);
  77.     }
  78.  
  79. /* parse arguments */
  80. strcpy(file, argv[1]);
  81.  
  82. /* get stats on file in question -- if doesn't exist, exit */
  83. if (stat(file,&statb) < 0) {
  84.     fprintf(stderr, file);
  85.     exit(2);
  86.     }
  87.  
  88. wg   = argv[2][0];        /* world or group */
  89. rwb  = argv[3][0];        /* read/write/both */
  90.  
  91. /* set the report string and some flags */
  92. if (wg == 'g') group = 1;
  93. else if (wg == 's') suid = 1;
  94. else if (wg == 'S') sgid = 1;
  95.  
  96. if (rwb == 'r') {
  97.     if (group) strcpy(gstring, G_READ_STRING);
  98.     else strcpy(wstring, W_READ_STRING);
  99.     read = 1;
  100.     }
  101. else if (rwb == 's')
  102.     (suid?strcpy(suidstring,SUID_STRING):strcpy(suidstring,SGID_STRING));
  103.  
  104. else if (rwb == 'w') {
  105.     if (group) {
  106.         strcpy(gstring, G_WRITE_STRING);
  107.         strcpy(gstring_tree, G_WRITE_TREE);
  108.         }
  109.     else {
  110.         strcpy(wstring, W_WRITE_STRING);
  111.         strcpy(wstring_tree, W_WRITE_TREE);
  112.         }
  113.     write = 1;
  114.     }
  115. else if (rwb == 'b') {
  116.     /* do the write first, then read check */
  117.     if (group) strcpy(gstring, G_WRITE_STRING);
  118.     else strcpy(wstring, W_WRITE_STRING);
  119.     if (suid) strcpy(suidstring,SUID_STRING);
  120.     both = read = write = 1;
  121.     }
  122. else if (rwb == 'B') {
  123.     /* do the write first, then s[ug]id check */
  124.     if (suid) strcpy(suidstring, SUID_STRING);
  125.     else if (sgid) strcpy(suidstring, SGID_STRING);
  126.     else {
  127.         fprintf(stderr, usage);
  128.         exit(1);
  129.         }
  130.     both = write = 1;
  131.     }
  132. else {
  133.     fprintf(stderr, usage);
  134.     exit(1);
  135.     }
  136.  
  137. /*
  138.  *         the write stuff, so to speak...
  139.  *   What I'm doing in this mess is to parse the file in question, check out
  140.  * whole path; 'cause if anything is world writable, you can compromise.
  141.  * For instance, if /usr is world writable, then /usr/spool/mail is
  142.  * compromisable, no matter what its permissions are.
  143.  *
  144. */
  145. if (write) {
  146.     /* 256 levels of dirs, max len each 256 chars */
  147.     char foo_dirs[256][256];
  148.     char *foo_file;
  149.     int i = 0, j;
  150.  
  151.     foo_file = file;
  152.     strcpy(foo_dirs[i++], foo_file);
  153.  
  154.     j=strlen(foo_file) - 1;
  155.     do {
  156.         if (foo_file[j] == '/')
  157.             strncpy(foo_dirs[i++], foo_file, j);
  158.     } while (--j > 0);
  159.  
  160.     for (j = 0; j < i; j++) {
  161.         if (stat(foo_dirs[j],&statb) < 0)
  162.             continue;
  163.         xmode=statb.st_mode;
  164.         if (!group) {
  165.             if (xmode & W_WRITE_TEST) {
  166.                 /* want to distinguish between file being
  167.                    writable and directory tree being
  168.                    writable; j==0 means actual file */
  169.                 if (!j) printf( wstring, file);
  170.                 else printf( wstring_tree, file);
  171.                 if (both) goto bboth;
  172.                 exit(!xmode);
  173.                 }
  174.             }
  175.         else if (xmode & G_WRITE_TEST) {
  176.             if (!j) printf( gstring, file);
  177.             else printf( gstring_tree, file);
  178.             if (both) goto bboth;
  179.             exit(!xmode);
  180.             }
  181.         }
  182.  
  183. if (!both) exit(!xmode);
  184. }
  185.  
  186. bboth:
  187. if (both) if (stat(file,&statb) < 0) {
  188.         fprintf(stderr, file);
  189.         exit(2);
  190.         }
  191.  
  192. /* find premissions on file in question */
  193. if (group)
  194.     xmode = statb.st_mode & G_READ_TEST;
  195. else
  196.     xmode = statb.st_mode & W_READ_TEST;
  197.  
  198. if (wg == 's') {
  199.     /* check SUID */
  200.     xmode = statb.st_mode & SUID_TEST;
  201.     if (xmode) printf( suidstring, file);
  202.     exit (!xmode);
  203.     }
  204. if (wg == 'S') {
  205.     /* check SGID */
  206.     xmode = statb.st_mode & SGID_TEST;
  207.     if (xmode) printf( suidstring, file);
  208.     exit (!xmode);
  209.     }
  210.  
  211. if (rwb == 'b') {
  212.     /* do the read now */
  213.     if (group) strcpy(gstring, G_READ_STRING);
  214.     else strcpy(wstring, W_READ_STRING);
  215.     }
  216.  
  217. /* report finding */
  218. if (xmode) printf( (group ? gstring : wstring), file);
  219.  
  220. exit(!xmode);
  221. }
  222.