storm@texas.dk (Kim F. Storm) (06/12/90)
In article <2077@polari.UUCP> 6sigma2@polari.UUCP (Brian Matthews) writes: >In article <433@mtndew.UUCP> friedl@mtndew.UUCP (Stephen J. Friedl) writes: >|Email will get a pretty detailed note on why >|access(2) is evil. del@thrush.mlb.semi.harris.com (Don Lewis) writes: > Would using stat(2), and checking if the uids/gids match and looking > at the permission bits have been better? Should the effective or > real ids have be used? Here is the "file_exist()" function which I wrote to make all sorts of file checking easy. It is extracted from the nn distribution, so it may need a little hacking to be used out of context: /* * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved. */ #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #ifdef HAVE_MULTIGROUP #ifndef NGROUPS #include <sys/param.h> #endif #ifndef GIDSET_TYPE #define GIDSET_TYPE int #endif static int ngroups; static GIDSET_TYPE gidset[NGROUPS]; static in_grplist(gid) GIDSET_TYPE gid; { int n; for (n = 0; n < ngroups; ++n) if (gidset[n] == gid) return 1; return 0; } #define group_access(gpid) in_grplist((GIDSET_TYPE)(gpid)) #else #define group_access(gid) ((gid) == group_id) #endif /* * Test existence and access modes of a file or directory * * mode is a string composed of the following characters * f -- name is a file * d -- name is a directory * r -- name is readable * w -- name is writeable * x -- name is executeable/searchable * * 0 is returned if file does not exist or any of the requested * permissions are not present; the actual cause is returned in * errno (EACCESS, EISDIR, ENOTDIR). * Otherwise, the modification time of the file is returned. * * Examples: * file_exist("/usr", "dwr") * -- is /usr a directory, writeable AND readable? * * file_exist(file, "fx") * -- is file an executeable file? * * file_exist(file, (char *)NULL) * -- does file exist? */ time_t file_exist(name, mode) char *name; char *mode; { static unsigned short user_id, group_id; static init = 1; struct stat statb; extern int errno; if (init) { user_id = geteuid(); #ifdef HAVE_MULTIGROUP ngroups = getgroups(NGROUPS, gidset); /* Get users's group set */ group_id = gidset[0]; /* not used, but just in case... */ #else group_id = getegid(); #endif init = 0; } if (stat(name, &statb)) return 0; if (mode == NULL) return statb.st_mtime; while (*mode) { switch (*mode++) { case 'd': if ((statb.st_mode & S_IFMT) == S_IFDIR) continue; errno = ENOTDIR; return 0; case 'f': if ((statb.st_mode & S_IFMT) == S_IFREG) continue; if ((statb.st_mode & S_IFMT) == 0000000) continue; if ((statb.st_mode & S_IFMT) == S_IFDIR) { errno = EISDIR; return 0; } break; case 'r': if ((statb.st_mode & 0400) && statb.st_uid == user_id) continue; if ((statb.st_mode & 0040) && group_access(statb.st_gid)) continue; if ((statb.st_mode & 0004)) continue; break; case 'w': if ((statb.st_mode & 0200) && statb.st_uid == user_id) continue; if ((statb.st_mode & 0020) && group_access(statb.st_gid)) continue; if ((statb.st_mode & 0002)) continue; break; case 'x': if ((statb.st_mode & 0100) && statb.st_uid == user_id) continue; if ((statb.st_mode & 0010) && group_access(statb.st_gid)) continue; if ((statb.st_mode & 0001)) continue; break; } errno = EACCES; return 0; } /* all modes are ok */ return statb.st_mtime; } -- Kim F. Storm <storm@texas.dk> No news is good news, Texas Instruments A/S, Denmark but nn is better!