home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume20 / rc / part03 / which.c < prev   
Encoding:
C/C++ Source or Header  |  1991-05-22  |  2.9 KB  |  136 lines

  1. /* which.c: check to see if a file is executable.
  2.  
  3.    This function is isolated from the rest because of #include trouble with
  4.    ANSI compilers.
  5.  
  6.    This function was originally written with Maarten Litmaath's which.c as
  7.    a template, but was changed in order to accomodate the possibility of
  8.    rc's running setuid or the possibility of executing files not in the
  9.    primary group. Much of this file has been re-vamped by Paul Haahr.
  10.    I re-re-vamped the functions that Paul supplied to correct minor bugs
  11.    and to strip out unneeded functionality.
  12. */
  13.  
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <sys/param.h>
  17. #include "builtins.h"
  18.  
  19. #define M_USR 0700
  20. #define M_GRP 0070
  21. #define M_OTH 0007
  22. #define X_ALL 0111
  23.  
  24. #ifndef NULL
  25. #define NULL 0
  26. #endif
  27.  
  28. typedef struct List {
  29.     char *w;
  30.     char *m;
  31.     struct List *n;
  32. } List;
  33.  
  34. extern int stat(const char *, struct stat *);
  35. extern int geteuid(void);
  36. extern int getegid(void);
  37. extern int getgroups(int, int *);
  38. extern char *strcpy(char *, char *);
  39. extern char *strcat(char *, char *);
  40. extern int strlen(char *);
  41.  
  42. extern List *varlookup(char *);
  43. extern void *ealloc(int);
  44. extern void efree(void *);
  45. extern int isabsolute(char *);
  46.  
  47. static int initialized = 0;
  48. static int uid, gid;
  49.  
  50. #ifdef NGROUPS
  51. static int ngroups, gidset[NGROUPS];
  52.  
  53. /* determine whether gid lies in gidset */
  54.  
  55. static int ingidset(int gid) {
  56.     int i;
  57.     for (i = 0; i < ngroups; i++)
  58.         if (gid == gidset[i])
  59.             return 1;
  60.     return 0;
  61. }
  62. #endif
  63.  
  64. /*
  65.    A home-grown access/stat. Does the right thing for group-executable files.
  66.    Returns a boolean result instead of this -1 nonsense.
  67. */
  68.  
  69. static int rc_access(char *path) {
  70.     struct stat st;
  71.     int mask;
  72.  
  73.     if (stat(path, &st) != 0)
  74.         return 0;
  75.  
  76.     mask = X_ALL;
  77.  
  78.     if (uid != 0) {
  79.         if (uid == st.st_uid)
  80.             mask &= M_USR;
  81. #ifdef NGROUPS
  82.         else if (gid == st.st_gid || ingidset(st.st_gid))
  83. #else
  84.         else if (gid == st.st_gid)
  85. #endif
  86.             mask &= M_GRP;
  87.         else
  88.             mask &= M_OTH;
  89.     }
  90.     
  91.     return (st.st_mode & S_IFMT) == S_IFREG && (st.st_mode & mask) == mask;
  92. }
  93.  
  94. /* return a full pathname by searching $path, and by checking the status of the file */
  95.  
  96. char *which(char *name) {
  97.     static char *test = NULL;
  98.     static int testlen = 0;
  99.     List *path;
  100.     int len;
  101.  
  102.     if (name == NULL)    /* no filename? can happen with "> foo" as a command */
  103.         return NULL;
  104.  
  105.     if (!initialized) {
  106.         initialized = 1;
  107.         uid = geteuid();
  108.         gid = getegid();
  109. #ifdef NGROUPS
  110.         ngroups = getgroups(NGROUPS, gidset);
  111. #endif
  112.     }
  113.  
  114.     if (isabsolute(name)) /* absolute pathname? */
  115.         return rc_access(name) ? name : NULL;
  116.  
  117.     len = strlen(name);
  118.     for (path = varlookup("path"); path != NULL; path = path->n) {
  119.         int need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */
  120.         if (testlen < need) {
  121.             efree(test);
  122.             test = ealloc(testlen = need);
  123.         }
  124.         if (*path->w == '\0') {
  125.             strcpy(test, name);
  126.         } else {
  127.             strcpy(test, path->w);
  128.             strcat(test, "/");
  129.             strcat(test, name);
  130.         }
  131.         if (rc_access(test))
  132.             return test;
  133.     }
  134.     return NULL;
  135. }
  136.