diff options
Diffstat (limited to 'src/tet3/dtet2lib/eaccess.c')
-rw-r--r-- | src/tet3/dtet2lib/eaccess.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/src/tet3/dtet2lib/eaccess.c b/src/tet3/dtet2lib/eaccess.c new file mode 100644 index 00000000..ee2ff604 --- /dev/null +++ b/src/tet3/dtet2lib/eaccess.c @@ -0,0 +1,217 @@ +/* + * SCCS: @(#)eaccess.c 1.12 (99/04/21) + * + * UniSoft Ltd., London, England + * + * (C) Copyright 1992 X/Open Company Limited + * + * All rights reserved. No part of this source code may be reproduced, + * stored in a retrieval system, or transmitted, in any form or by any + * means, electronic, mechanical, photocopying, recording or otherwise, + * except as stated in the end-user licence agreement, without the prior + * permission of the copyright owners. + * + * X/Open and the 'X' symbol are trademarks of X/Open Company Limited in + * the UK and other countries. + */ + +#ifndef lint +static char sccsid[] = "@(#)eaccess.c 1.12 (99/04/21) TET3 release 3.3"; +#endif + +/************************************************************************ + +SCCS: @(#)eaccess.c 1.12 99/04/21 TETware release 3.3 +NAME: eaccess.c +PRODUCT: TETware +AUTHOR: Andrew Dingwall, UniSoft Ltd. +DATE CREATED: June 1992 + +DESCRIPTION: + function to check access permissions wrt effective user and group IDs + +MODIFICATIONS: + Andrew Dingwall, UniSoft Ltd., January 1994 + use S_ISDIR instead of S_IFMT for strict posix conformance + + Geoff Clare, UniSoft Ltd., August 1996 + Missing <unistd.h>. + + Andrew Dingwall, UniSoft Ltd., March 1999 + On UNIX systems, check group permissions w.r.t. supplementary + group IDs as well as against the egid. + +************************************************************************/ + +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +# include <limits.h> +# include <unistd.h> +#include "dtmac.h" +#include "error.h" +#include "ltoa.h" +#include "dtetlib.h" + + +#ifdef NEEDsrcFile +static char srcFile[] = __FILE__; /* file name for error reporting */ +#endif + + +/* static function declarations */ +static int check_grouplist PROTOLIST((struct STAT_ST *, int)); + + +/* +** tet_eaccess() - like access() but checks permissions wrt +** effective user and group IDs +** +** Note: this routine assumes that access and file modes are +** encoded in the traditional way; ie: 4 = read, 2 = write, 1 = exec +** user perms = 0700, group perms = 070, other perms = 07. +** +** Since this routine provides support for the tccd OP_ACCESS +** request (among other things) and thus needs to be able to +** receive a mode argument from another system, it will be necessary +** to implement a machine-independent mode transfer mechanism if +** the above assumption is incorrect for a particular system. +*/ + +int tet_eaccess(path, mode) +char *path; +register int mode; +{ + struct STAT_ST stbuf; + + + uid_t euid; + int rc, rc2; + + /* + ** first check for things like non-existent file, + ** read-only file system etc. + */ + if (ACCESS(path, mode) < 0) { + if (errno != EACCES) + return(-1); + } + else + if ((mode &= 07) == 0) + return(0); + + /* + ** here if access() succeeded, or failed because of wrong permissions; + ** first get the file permissions + */ + if (STAT(path, &stbuf) < 0) + return(-1); + + /* + ** check the permissions wrt the euid, the egid and the + ** supplementary groups list; + ** treating root specially (like the kernel does) + */ + rc = 0; + if ((euid = geteuid()) == 0) { + if (!S_ISDIR(stbuf.st_mode) && + (stbuf.st_mode & 0111) == 0 && (mode & 01)) + rc = -1; + } + else if (stbuf.st_uid == euid) { + if (((stbuf.st_mode >> 6) & mode) != mode) + rc = -1; + } + else if (stbuf.st_gid == getegid()) { + if (((stbuf.st_mode >> 3) & mode) != mode) + rc = -1; + } + else { + rc2 = check_grouplist(&stbuf, mode); + switch (rc2) { + case 2: + break; + case 1: + rc = -1; + break; + case 0: + if ((stbuf.st_mode & mode) != mode) + rc = -1; + break; + case -1: + return(-1); + default: + /* "can't happen" */ + fatal(0, "check_grouplist() returned unexpected value", + tet_i2a(rc2)); + /* NOTREACHED */ + return(-1); + } + } + + if (rc < 0) + errno = EACCES; + return(rc); + + +} + + + +/* +** check_grouplist() - check the requested access mode against +** the process's supplementary grouplist +** +** return 2 if a supplementary group matched and group access is allowed +** 1 if a supplementary group matched but group access is +** not allowed +** 0 if no supplementary groups matched +** -1 on error (with errno set) +*/ + +static int check_grouplist(stp, mode) +struct STAT_ST *stp; +int mode; +{ + int errsave, ngids, ngmax; + gid_t *gidp; + static gid_t *gids = (gid_t *) 0; + static int lgids = 0; + + /* + ** allocate a buffer to hold the supplementary group list; + ** we only evaluate NGROUPS_MAX once because on some systems it + ** can be a call to sysconf() + */ + ngmax = (int) NGROUPS_MAX; + if (BUFCHK((char **) &gids, &lgids, ngmax * (int) sizeof *gidp) < 0) { + errno = ENOMEM; + return(-1); + } + + /* + ** get the supplementary group list from the kernel; + ** it probably won't change from one invocation of tet_eaccess() to + ** the next, but we get it on each call just to be on the safe side + **/ + if ((ngids = getgroups(ngmax, gids)) < 0) { + errsave = errno; + error(errno, "can't get supplementary group list", (char *) 0); + errno = errsave; + return(-1); + } + + /* + ** check the file's group id against each supplementary group; + ** if the groups match, see if the requested access permission(s) + ** will be granted + */ + for (gidp = gids; gidp < gids + ngids; gidp++) + if (stp->st_gid == *gidp) + return(((stp->st_mode >> 3) & mode) == mode ? 2 : 1); + + return(0); +} + + |