diff options
| author | Byron Rakitzis <byron@archone.tamu.edu> | 1992-05-27 00:00:01 +0100 |
|---|---|---|
| committer | Toby Goodwin <toby@paccrat.org> | 2015-05-16 21:22:04 +0100 |
| commit | 6bb38f6a01dbf4bbd584e038ceace0a00faa27bb (patch) | |
| tree | 589705b2492ce4681760846d9ca45600f0af298d /which.c | |
release: rc-1.4
Diffstat (limited to 'which.c')
| -rw-r--r-- | which.c | 114 |
1 files changed, 114 insertions, 0 deletions
@@ -0,0 +1,114 @@ +/* which.c: check to see if a file is executable. + + This function was originally written with Maarten Litmaath's which.c as + a template, but was changed in order to accomodate the possibility of + rc's running setuid or the possibility of executing files not in the + primary group. Much of this file has been re-vamped by Paul Haahr. + I re-re-vamped the functions that Paul supplied to correct minor bugs + and to strip out unneeded functionality. +*/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <errno.h> +#include "rc.h" + +#define X_USR 0100 +#define X_GRP 0010 +#define X_OTH 0001 +#define X_ALL (X_USR|X_GRP|X_OTH) + +extern int stat(const char *, struct stat *); + +static bool initialized = FALSE; +static int uid, gid; + +#ifdef NGROUPS +static int ngroups, gidset[NGROUPS]; + +/* determine whether gid lies in gidset */ + +static int ingidset(int g) { + int i; + for (i = 0; i < ngroups; i++) + if (g == gidset[i]) + return 1; + return 0; +} +#endif + +/* + A home-grown access/stat. Does the right thing for group-executable files. + Returns a bool instead of this -1 nonsense. +*/ + +static bool rc_access(char *path, bool verbose) { + struct stat st; + int mask; + if (stat(path, &st) != 0) { + if (verbose) /* verbose flag only set for absolute pathname */ + uerror(path); + return FALSE; + } + if (uid == 0) + mask = X_ALL; + else if (uid == st.st_uid) + mask = X_USR; +#ifdef NGROUPS + else if (gid == st.st_gid || ingidset(st.st_gid)) +#else + else if (gid == st.st_gid) +#endif + mask = X_GRP; + else + mask = X_OTH; + if (((st.st_mode & S_IFMT) == S_IFREG) && (st.st_mode & mask)) + return TRUE; + errno = EACCES; + if (verbose) + uerror(path); + return FALSE; +} + +/* return a full pathname by searching $path, and by checking the status of the file */ + +extern char *which(char *name, bool verbose) { + static char *test = NULL; + static SIZE_T testlen = 0; + List *path; + int len; + if (name == NULL) /* no filename? can happen with "> foo" as a command */ + return NULL; + if (!initialized) { + initialized = TRUE; + uid = geteuid(); + gid = getegid(); +#ifdef NGROUPS + ngroups = getgroups(NGROUPS, gidset); +#endif + } + if (isabsolute(name)) /* absolute pathname? */ + return rc_access(name, verbose) ? name : NULL; + len = strlen(name); + for (path = varlookup("path"); path != NULL; path = path->n) { + SIZE_T need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */ + if (testlen < need) { + efree(test); + test = ealloc(testlen = need); + } + if (*path->w == '\0') { + strcpy(test, name); + } else { + strcpy(test, path->w); + if (!streq(test, "/")) /* "//" is special to POSIX */ + strcat(test, "/"); + strcat(test, name); + } + if (rc_access(test, FALSE)) + return test; + } + if (verbose) + fprint(2, "%s not found\n", name); + return NULL; +} |