home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume4 / give / give.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-03  |  7.8 KB  |  428 lines

  1. /*
  2.  * give -- a paranoid's cat program
  3.  */
  4. #include <stdio.h>
  5. #include <pwd.h>
  6. #include <fcntl.h>
  7. #include <sys/param.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10.  
  11. #ifdef DEBUG
  12. #define INSTANTIATE"
  13. #endif
  14. #include "debug.h"
  15.  
  16. #define PR (void) fprintf(stderr,
  17. #define EQ(a,b) strcmp(a,b) == 0
  18. #define ERR (-1)
  19. #define EOS '\0'
  20. #define YES 1    /* Function returns. */
  21. #define NO 0
  22. #define OK 0    /* Program exit codes */
  23. #define BAD 1
  24. #define AWFULL 3
  25.  
  26. typedef struct {
  27.     char    *dptr;
  28.     int    dsize;
  29. } DATUM;
  30.  
  31. char *ProgName = NULL;
  32. usage() {
  33.     PR "Usage: %s [person] file...\n",ProgName);
  34. }
  35.  
  36.  
  37. main(argc,argv) int argc; char *argv[]; {
  38.     void give(), take(), remove(), exit();
  39.  
  40.     begin("main");
  41.     ProgName = argv[0];
  42.     if (argc < 2) {
  43.         if (exists(".give.dir")) {
  44.             /* Say what we've got. */
  45.             printDB();
  46.         }
  47.         else {
  48.             /* Tell the user the usage. */
  49.             usage();
  50.             exit(BAD);
  51.         }
  52.     }
  53.     else if (argv[1][0] == '-') {
  54.         switch (toupper(argv[1][1])) {
  55.         case 'D': /* Its the owner doing cleanup. */
  56.             remove(argc-2,(char **)&argv[2]);
  57.             break;
  58.         case 'T': /* Force it to "take". */
  59.             take(argc-2,(char **)&argv[2]);
  60.             break;
  61.         default: /* Error in usage. */
  62.             usage();
  63.             exit(BAD);    
  64.         }
  65.     }
  66.     else if (ownerIsRunningMe()) {
  67.         /* Its a give-to-someone (nonsetuid) request. */
  68.         give(argc-1,(char **)&argv[1]);
  69.     }
  70.     else {
  71.         /* Its a setuid-owner cat request. */
  72.         take(argc-1,(char **)&argv[1]);
  73.  
  74.     }
  75.     end();
  76.     exit(OK);
  77. }
  78.  
  79. /*
  80.  * take -- cat the file, if both it and the user match up
  81.  */
  82.  void
  83. take(count, arg) int count; char *arg[]; {
  84.     int    i;
  85.     char    *userName, *getUserId();
  86.     char    *path, *absPath();
  87.  
  88.     begin("take");
  89.     /* Find the caller's userid. */
  90.     userName = getUserId();
  91.     pr1("I am %s\n",userName);
  92.     pr1("count is %d\n",count);
  93.  
  94.     for (i=0; i < count; i++) {
  95.         /* Read the database, and see if we get a match. */
  96.         if ((path= absPath(arg[i])) == NULL) {
  97.             PR "%s: could not get the absolute path of \"%s\",",
  98.                 ProgName,arg[i]);
  99.             PR " is it elsewhere or does it contains a ..?\n");
  100.             continue;
  101.         }
  102.         if (searchDB(userName,path)) {
  103.             cat(path);
  104.         }
  105.     }
  106.     end();
  107. }
  108.  
  109.  
  110. /*
  111.  * give -- put the person and file in the .give database
  112.  */
  113.  void
  114. give(count, arg) int count; char *arg[]; {
  115.     int    i;
  116.     char    *absPath();
  117.     char     *userName;
  118.     char    *path;
  119.  
  120.     begin("give");
  121.     /* Break the user name out of the args vector. */
  122.     userName = arg[0];
  123.     count--; 
  124.     arg = (char **)&arg[1];
  125.  
  126.     /* Find if the named person has a userid. */
  127.     if (validateUserId(userName) == 0) {
  128.         PR "%s: %s is not a known user-id on this system\n",
  129.             ProgName, userName);
  130.         exit(BAD);
  131.     }
  132.  
  133.     /* And process each of the files in order. */
  134.     for (i=0; i < count; i++) {
  135.         /* Find the absolute pathname of the file. */
  136.         if ((path= absPath(arg[i])) == NULL) {
  137.             PR "%s: file \"%s\" not found, ignored.\n",
  138.                 ProgName, arg[i]);
  139.         }
  140.         else {
  141.             /* Put them in the database. */
  142.             addDB(userName,path);
  143.         }
  144.     }
  145.     end();
  146. }
  147.  
  148. /*
  149.  * remove -- remove a person-filename pair from the database
  150.  */
  151.  void
  152. remove(count, arg) int count; char **arg; {
  153.     int    i;
  154.     char    *absPath();
  155.     char     *userName;
  156.     char    *path;
  157.  
  158.     begin("give");
  159.     /* Break the user name out of the args vector. */
  160.     userName = arg[0];
  161.     count--; 
  162.     arg = (char **)&arg[1];
  163.  
  164.     /* And remove each of the files in order. */
  165.     for (i=0; i < count; i++) {
  166.         /* Find the absolute pathname of the file. */
  167.         if ((path= absPath(arg[i])) == NULL) {
  168.             PR "%s: file \"%s\" not found, ignored.\n",
  169.                 ProgName, arg[i]);
  170.         }
  171.         else {
  172.             /* Take them out of the database. */
  173.             removeDB(userName,path);
  174.         }
  175.     }
  176.     end();
  177. }
  178.  
  179.  
  180. /*
  181. ** Filesystem functions
  182. **
  183. */
  184.  
  185. /* 
  186.  * absPath -- find the absolute pathname of a file, return NULL
  187.  *    if it doesn't have (a canonical and unique) one.
  188.  */
  189.  char *
  190. absPath(name) char *name; {
  191.     static char path[MAXPATHLEN*2];
  192.     char    *getcwd(), *strcat(), *strcpy();
  193.  
  194.     begin("abspath");
  195.     if (*name == '/') {
  196.         /* Its an absolute path. */
  197.         (void) strcpy(path,name);
  198.     }
  199.     else {
  200.         /* Its a relative path: prefix the working directory. */
  201.         if (getcwd(path,MAXPATHLEN) == NULL) {
  202.             PR "%s: can't find working directory, halting\n",
  203.                 ProgName);
  204.             exit(AWFULL);
  205.         }
  206.         (void) strcat(strcat(path,"/"),name);
  207.     }
  208.     if (!canonical(path)) {
  209.         ret(NULL);
  210.     }
  211.     else if (exists(path) == NO) {
  212.         ret(NULL);
  213.     }
  214.     else {
  215.         ret(path);
  216.     }
  217. }
  218.  
  219. /* 
  220.  * canonical -- test a pathname for a ".." sequence.
  221.  */
  222.  int 
  223. canonical(name) char *name; {
  224.     char *p, *strchr();
  225.  
  226.     begin("canonical");
  227.     p = name;
  228.     while ((p=strchr(p+1,'.')) != NULL) {
  229.         if (p[1] == '.') {
  230.             ret(NO);
  231.         }
  232.     }
  233.     ret(YES);
  234. }
  235.  
  236. /*
  237.  * exists -- stat a file for presence/absence
  238.  */
  239.  int
  240. exists(path) char *path; {
  241.         struct stat buf;
  242.  
  243.     return (stat(path, &buf) != ERR);
  244. }
  245.  
  246.  
  247. /*
  248. ** userid functions
  249. **
  250. */
  251.  
  252. /*
  253.  * getUserId -- Find the user's userid.
  254.  */
  255.  char *
  256. getUserId() {
  257.         struct passwd *p, *getpwuid();
  258.     unsigned short getuid();
  259.  
  260.     begin("getUserId");
  261.     if ((p=getpwuid((int)getuid())) == NULL) {
  262.         ret(NULL);
  263.     }
  264.     else {
  265.         ret(p->pw_name);
  266.     }
  267. }
  268.  
  269. /*
  270.  * validateUserId -- Find if the named person has a userid. 
  271.  */
  272.  int
  273. validateUserId(name) char *name; {
  274.     struct passwd *getpwnam();
  275.  
  276.     return (getpwnam(name) != NULL);
  277. }
  278.  
  279. /*
  280.  * ownerIsRunningMe -- return YES if the owner of the program is running it
  281.  */
  282.  int
  283. ownerIsRunningMe() {
  284.     unsigned short getuid(), geteuid();
  285.  
  286.     return (getuid() == geteuid());
  287. }
  288.  
  289.     
  290.  
  291. /*
  292. ** database functions -- these happen to use dbm(3x), but anything is
  293. **    acceptable that can provide the primitives.  Ingres would be 
  294. **    somewhat nicer...
  295. */
  296. #define MAXNAME 100
  297.  
  298. /*
  299.  * addDB -- add a person-filename pair.
  300.  */
  301. addDB(person,file) char *person, *file; {
  302.     DATUM    key,
  303.         content;
  304.     char    record[MAXNAME+MAXPATHLEN],
  305.         *strcat(), *strcpy();
  306.  
  307.     begin("addDB");
  308.     initDB();
  309.     key.dptr = strcat(strcat(strcpy(record,person)," "),file);
  310.     key.dsize = strlen(record)+1;
  311.     content.dptr = " ";
  312.     content.dsize = 2;
  313.     pr1("key is '%s'\n",record);
  314.     if (store(key,content) < 0) {
  315.         PR "%s: database failed on a store, halting\n",
  316.             ProgName);
  317.         exit(AWFULL);
  318.     }
  319.     end();
  320. }
  321.  
  322. /*
  323.  * searchDB -- see if a person-filename pair is present.
  324.  */
  325.  int
  326. searchDB(person,file) char *person, *file; {
  327.     DATUM    key, content, fetch();
  328.     char    record[MAXNAME+MAXPATHLEN],
  329.         *strcat(), *strcpy();
  330.  
  331.     begin("searchDB");
  332.     initDB();
  333.     key.dptr = strcat(strcat(strcpy(record,person)," "),file);
  334.     key.dsize = strlen(record)+1;
  335.     pr1("key is '%s'\n",record);
  336.     content = fetch(key);
  337.     pr2("content = '%s' (0x%X)\n",content.dptr,content.dptr);
  338.     ret(content.dptr != NULL);
  339. }
  340.  
  341. /* 
  342.  * removeDB -- remove a person-filename pair
  343.  */
  344. removeDB(person,file) char *person, *file; {
  345.     DATUM    key;
  346.     char    record[MAXNAME+MAXPATHLEN],
  347.         *strcat(), *strcpy();
  348.     int    rc;
  349.  
  350.     begin("removeDB");
  351.     initDB();
  352.     key.dptr = strcat(strcat(strcpy(record,person)," "),file);
  353.     key.dsize = strlen(record)+1;
  354.     pr1("key is '%s'\n",record);
  355.     rc = delete(key);
  356.     pr1("rc = %d\n",rc);
  357.     if (rc < 0) {
  358.         PR "%s: could not remove \"%s\" from database\n",
  359.             ProgName,record);
  360.         exit(AWFULL);
  361.     }
  362.     end();
  363. }
  364.  
  365. /* 
  366.  * printDB -- print all person-filename pairs in the database
  367.  */
  368. printDB() {
  369.     DATUM    key, firstkey(), nextkey();
  370.  
  371.     begin("printDB");
  372.     initDB();
  373.     key = firstkey();
  374.     if (key.dptr == NULL) {
  375.         usage();
  376.     }
  377.     else {
  378.         for (; key.dptr != NULL; key=nextkey(key))
  379.             (void) printf("%s\n",key.dptr);
  380.     }
  381.     end();
  382. }
  383.  
  384. /*
  385.  * initDB -- open the db file
  386.  */
  387.  static
  388. initDB() {
  389.     static openRqd = YES;
  390.  
  391.     begin("initDB");
  392.     if (openRqd) {
  393.         if (exists(".give.pag") == NO) {
  394.             (void) creat(".give.dir",0755);
  395.             (void) creat(".give.pag",0755);
  396.             /* Success test is the dbminit... */
  397.         }
  398.         if (dbminit(".give") < 0) {
  399.             PR "%s: cannot open .give.[dir|pag] file, halting\n",
  400.                 ProgName);
  401.             exit(AWFULL);
  402.         }
  403.     }
  404.     openRqd = NO;
  405.     end();
  406. }
  407.  
  408. /*
  409.  * cat -- send a file to stdout.
  410.  */
  411. #define BLOCKSIZE    1024
  412. cat(p) char *p; {
  413.     char    block[BLOCKSIZE];
  414.     int    fd, 
  415.         i;
  416.  
  417.     begin("cat");
  418.     pr1("p is '%s'\n",p);
  419.     if ((fd=open(p,O_RDONLY)) == ERR) {
  420.         PR "%s: can't open %s (inpossible!)\n",
  421.             ProgName, p);
  422.         exit(AWFULL);
  423.     }
  424.     while ((i=read(fd,block,(unsigned)BLOCKSIZE)) != 0)
  425.         (void) write(1,block,(unsigned)i);
  426.     (void) close(fd);
  427. }
  428.