Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

1517 lines
34 KiB
C

static char sccsid[] = "@(#)10 1.31 src/bos/usr/ccs/lib/libc/getgrent.c, libcs, bos41J, 9511A_all 3/6/95 14:18:30";
/*
* COMPONENT_NAME: LIBCS
*
* FUNCTIONS: REPORT
* addtogrset
* addtominuslist
* bind_to_yp
* check_dce
* check_yellow
* endgrent
* fgetgrent
* freeminuslist
* getfirstfromyellow
* getgidfromyellow
* getgrent
* getgrgid
* getgrgid_compat
* getgrnam
* getgrnam_compat
* getgroupsbyuser
* getgrset
* getgrset_compat
* getnamefromyellow
* getnextfromyellow
* gidof
* grskip
* interpret
* interpretwithsave
* matchgid
* matchname
* onminuslist
* reset_grjunk_authstate
* save
* set_getgrent_remote
* setgrent
* setgrjunk
*
* ORIGINS: 24,26,27
*
* This module contains IBM CONFIDENTIAL code. -- (IBM
* Confidential Restricted when combined with the aggregated
* modules for this product)
* SOURCE MATERIALS
*
* (C) COPYRIGHT International Business Machines Corp. 1989, 1995
* All Rights Reserved
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
#include <stdio.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <usersec.h>
#include <rpcsvc/ypclnt.h>
/*
* Prototypes for externally used routines.
*/
extern unsigned long strtoul();
extern int strlen();
extern int strcmp();
extern char *strcpy();
extern char *calloc();
extern char *malloc();
/*
* Prototypes for all routines defined within this file
*/
void set_getgrent_remote(int);
void reset_grjunk_authstate();
struct group * getgrgid(gid_t);
struct group * getgrnam(const char *);
char * getgrset(const char *);
int getgroupsbyuser(uid_t, struct setlist *, int *);
int addtogrset(char *,struct setlist *,int *,struct group *);
struct group * getgrent(void);
void setgrent();
void endgrent();
struct group * fgetgrent(FILE *);
static struct _grjunk * setgrjunk();
static struct group * getgrgid_compat(gid_t);
static struct group * getgrnam_compat(const char *);
static char * getgrset_compat(const char *);
static char * grskip(char *, int);
static struct group * interpret(char *, int);
static int freeminuslist();
static struct group * interpretwithsave(char *, int, struct group *);
static int onminuslist(struct group *);
static int getnextfromyellow();
static int getfirstfromyellow();
static struct group * getnamefromyellow(char *, struct group *);
static int addtominuslist(char *);
static struct group * save(struct group *);
static int matchname(char *, struct group **, char *);
static int matchgid(char *, struct group **, gid_t);
static gid_t gidof(char *);
static struct group * getgidfromyellow(int, struct group *);
static int check_dce();
static int check_yellow();
static int bind_to_yp();
#define MAXINT 0x7fffffff;
#define MAXGRP 2000
/*
* In GRPLINLEN the 14 represents the ":!:GID LENGTH:" in the group file.
*/
#define GRPLINLEN (L_cuserid) + ((L_cuserid + 1) * MAXGRP) + 14
static struct _grjunk
{
char *_domain;
struct group _NULLGP;
FILE * _grf;
char *_yp;
int _yplen;
char *_oldyp;
int _oldyplen;
char *_agr_mem[MAXGRP];
enum {FILES, COMPAT, DCE}
_authstate; /* first name resolution mechanism */
struct secmethod_table /* Function pointer table for */
_dcemethod; /* loadable module interface (DCE) */
struct list {
char *name;
struct list *nxt;
} *_minuslist;
struct group _interpgp;
char _interpline[GRPLINLEN+1];
int _usingyellow;
} *__grjunk;
#define domain (_gr->_domain)
#define NULLGP (_gr->_NULLGP)
#define grf (_gr->_grf)
#define yp (_gr->_yp)
#define yplen (_gr->_yplen)
#define oldyp (_gr->_oldyp)
#define oldyplen (_gr->_oldyplen)
#define agr_mem (_gr->_agr_mem)
#define minuslist (_gr->_minuslist)
#define interpgp (_gr->_interpgp)
#define interpline (_gr->_interpline)
#define usingyellow (_gr->_usingyellow)
#define authstate (_gr->_authstate)
#define dcemethod (_gr->_dcemethod)
#define getgrgid_dce (_gr->_dcemethod.method_getgrgid)
#define getgrnam_dce (_gr->_dcemethod.method_getgrnam)
#define getgrset_dce (_gr->_dcemethod.method_getgrset)
static char GROUP[] = "/etc/group";
static int firsttime = 0;
/*
* The following macros, defines, and static variable define and retrieve
* what paths, name resolution should take. This variable is set in the
* set_getgrent_remote() routine and checked in the getgrnam() routine
* and whenever an NIS lookup is about to take place. Before a lookup
* in another domain (such as NIS) the programmer should use
* REPORT(NIS_MASK) to determine if lookups are meant to flow into the NIS
* domain. (see comments in the set_getgrent_remote() for instructions on
* valid settings.
*/
#define SET_LOCAL 0x1 /* Local only resolution */
#define SET_ALL 0x2 /* Resolve through all possible methods */
#define SET_LOCAL_NIS 0x4 /* Resolve through local and NIS only */
#define SET_DCE 0x8 /* Resolve through DCE onlt */
static int _report_remote_entries = SET_ALL;
#define LOCAL_MASK 0x7
#define NIS_MASK 0x6
#define DCE_MASK 0xA
#define REPORT(a) (_report_remote_entries & a)
struct setlist {
char *name;
gid_t gid;
struct setlist *next;
};
/*
* NAME: setgrjunk
*
* FUNCTION: Initialization routine for static and malloc'd variables.
* All routines that attempt to update or query the state
* of the internal routines should call this first.
*
* RETURNS: 0 - failure in initialzation
* _grjunk structure - correct initialization
*/
static struct _grjunk *
setgrjunk()
{
register struct _grjunk *_gr = __grjunk;
if (_gr == 0)
{
char *env;
_gr = (struct _grjunk *)calloc(1, sizeof(*__grjunk));
if (_gr == 0)
return(0);
/*
* Check the AUTHSTATE environment variable for the primary
* authentication mechanism that was used by this user
* during login. This mechanism will be attempted first.
* The default resolution is (local files plus NIS) if the
* environment variable is not set.
*/
authstate = COMPAT;
env = getenv(AUTH_ENV);
if (!(env == NULL || env[0] == '\0'))
if (!strcmp(env, AUTH_DCE))
authstate = DCE;
__grjunk = _gr;
}
return(__grjunk);
}
/*
* NAME: getgrgid
*
* FUNCTION: Given a group id, this routine will attempt to resolve
* it to a group structure. The routine has several possible
* callout routines. If the user authenticated via DCE, this
* will be the primary callout. Otherwise we will use
* the normal name resolution routines, herein named
* getgrnam_compat()
*
* See design 7673. AIX/DCE Security Enablement for a rationale
* on this approach.
*
* RETURNS: Null - Name resolution failed.
* struct group * - group structure.
*/
struct group *
getgrgid(register gid_t gid)
{
register struct _grjunk *_gr = setgrjunk();
struct group *gr = (struct group *)NULL;
if (_gr == 0)
return (0);
/*
* If my primary authentication was something other than DCE
* (meaning local or NIS) then I will check the local files (and NIS)
* first. If this resolution does not return a valid entry then I
* will attempt to load dce and call the getgrgid_dce() routine.
*
* Otherwise my authstate environment variable was DCE so I
* should check DCE and if that fails check the local files.
*/
if (authstate != DCE)
{
if ((gr = getgrgid_compat(gid)) == (struct group *)NULL)
{
if (check_dce())
gr = getgrgid_dce(gid);
}
}
else
{
if (check_dce())
{
gr = getgrgid_dce(gid);
}
if (!gr)
gr = getgrgid_compat(gid);
}
return gr;
}
/*
* NAME: getgrgid_compat
*
* FUNCTION: Normal name resolution routine which implements the lookup
* in the local security database files and NIS if the local
* database is configured with the YP plus and minus semantics.
*
* Returns: Null - Name resolution failed.
* struct group * - group structure
*/
static struct group *
getgrgid_compat(register gid_t gid)
{
register struct _grjunk *_gr = setgrjunk();
struct group *p;
char line[GRPLINLEN+1];
char *s, *t;
if (_gr == 0)
return (0);
setgrent();
if (!check_yellow()) {
while ( (p = getgrent()) && p->gr_gid != gid )
;
endgrent();
return(p);
}
if (!grf)
return NULL;
while ( (s = t = fgets(line, GRPLINLEN + 1, grf)) != NULL) {
/*
* A15852 fix - Read until Newline for lines longer than BUFSIZ.
*/
while (*s != (char) NULL) {
if ((!(isspace((int)(*s)))) || (*s == '\n')) {
*t++ = *s;
}
*s++;
}
if (line[0] == '\n')
continue;
/* A15852 fix end. */
if ((p = interpret(line, strlen(line))) == NULL)
continue;
if (matchgid(line, &p, gid)) {
endgrent();
return p;
}
}
endgrent();
return NULL;
}
/*
* NAME: getgrnam
*
* FUNCTION: Given a group name, this routine will attempt to resolve
* it to a group structure. The routine has several possible
* callout routines. If the user authenticated via DCE, this
* will be the primary callout. Otherwise we will use
* the normal name resolution routines, herein named
* getgrnam_compat()
*
* See design 7673. AIX/DCE Security Enablement for a rationale
* on this approach.
*
* RETURNS: Null - Name resolution failed.
* struct group * - group structure.
*/
struct group *
getgrnam(const register char *nam)
{
register struct _grjunk *_gr = setgrjunk();
struct group *gr = (struct group *)NULL;
if (_gr == 0)
return (0);
/*
* If my primary authentication was something other than DCE
* (meaning local or NIS) then I will check the local files (and NIS)
* first. If this resolution does not return a valid entry then I
* will attempt to load dce and call the getgrnam_dce() routine.
*
* Otherwise my authstate environment variable was DCE so I
* should check DCE and if that fails check the local files.
*/
if (authstate != DCE)
{
if ((gr = getgrnam_compat(nam)) == (struct group *)NULL)
{
if (check_dce())
gr = getgrnam_dce(nam);
}
}
else
{
if (check_dce())
{
gr = getgrnam_dce(nam);
}
if (!gr)
gr = getgrnam_compat(nam);
}
return gr;
}
/*
* NAME: getgrnam_compat
*
* FUNCTION: Normal name resolution routine which implements the lookup
* in the local security database files and NIS if the local
* database is configured with the YP plus and minus semantics.
*
* Returns: Null - Name resolution failed.
* struct group * - group structure
*/
static struct group *
getgrnam_compat(const register char *name)
{
register struct _grjunk *_gr = setgrjunk();
struct group *p;
char line[GRPLINLEN+1];
char *s, *t;
if (_gr == 0)
return NULL;
setgrent();
if (!check_yellow()) {
while ( (p = getgrent()) && strcmp(p->gr_name, name) )
;
endgrent();
return(p);
}
if (!grf)
return NULL;
while ((s = t = fgets(line, GRPLINLEN + 1, grf)) != NULL) {
/*
* A15852 fix - Read until Newline for lines longer than BUFSIZ.
*/
while (*s != (char) NULL) {
if ((!(isspace((int)(*s)))) || (*s == '\n')) {
*t++ = *s;
}
*s++;
}
if (line[0] == '\n')
continue;
/* A15852 fix end. */
if ((p = interpret(line, strlen(line))) == NULL)
continue;
if (matchname(line, &p, name)) {
endgrent();
return p;
}
}
endgrent();
return NULL;
}
/*
* NAME: getgrset
*
* FUNCTION: Given a user name, this routine will attempt to resolve
* it to a list of primary and supplementary group ids for this
* user. The routine has several possible callout routines. If
* the user authenticated via DCE, this will be the primary callout.
* Otherwise we will use the normal name resolution routines, herein
* named getgrset_compat()
*
* See design 7673. AIX/DCE Security Enablement for a rationale
* on this approach.
*
* RETURNS: Null - Name resolution failed.
* struct group * - group structure.
*/
char *
getgrset(const char *nam)
{
register struct _grjunk *_gr = setgrjunk();
char *gr = (char *)NULL;
char *env;
if (_gr == 0)
return (0);
/*
* This is somewhat unusual that I am rereading my AUTHSTATE
* variable here, but this is the only routine where it might
* make an explicit difference. This particular routine is
* relying on getgrent() for it's compat behaviour. However
* DCE does not implement getgrent() therefore we need to be
* very explicit and use the getgrset() routine, which DCE
* does implement.
*/
authstate = COMPAT;
env = getenv(AUTH_ENV);
if (!(env == NULL || env[0] == '\0'))
if (!strcmp(env, AUTH_DCE))
authstate = DCE;
/*
* If my primary authentication was something other than DCE
* (meaning local or NIS) then I will check the local files (and NIS)
* first. If this resolution does not return a valid entry then I
* will attempt to load dce and call the getgrset_dce() routine.
*
* Otherwise my authstate environment variable was DCE so I
* should check DCE and if that fails check the local files.
*/
if (authstate != DCE)
{
if ((gr = getgrset_compat(nam)) == (char *)NULL)
{
if (check_dce())
gr = getgrset_dce(nam);
}
}
else
{
if (check_dce())
{
gr = getgrset_dce(nam);
}
if (!gr)
gr = getgrset_compat(nam);
}
return gr;
}
/*
* NAME: getgrset_compat
*
* FUNCTION: Normal name resolution routine which implements the lookup
* in the local security database files and NIS if the local
* database is configured with the YP plus and minus semantics.
*
* Returns: Null - Name resolution failed.
* struct group * - group structure
*/
static char *
getgrset_compat(register char *user)
{
register struct _grjunk *_gr = setgrjunk();
struct group *gp, *savegp;
struct passwd *pwp;
struct setlist *slp, *tslp;
char *buf, **p;
int count, endoffile;
int i, j;
gid_t gid;
if (_gr == 0)
return NULL;
count = 0;
/* get the users primary group that is specified in the passwd entry
* get the group name and put it as the first entry in the buffer.
*/
if ((pwp = getpwnam(user)) == NULL)
return(NULL);
gid = pwp->pw_gid;
if ((gp = getgrgid(gid)) == NULL)
return(NULL);
if ((slp = (struct setlist *)malloc(sizeof(struct setlist))) == NULL)
return(NULL);
slp->next = NULL;
count = 1;
if ((slp->name = malloc(strlen(gp->gr_name) + 1)) == NULL)
return(NULL);
strcpy(slp->name, gp->gr_name);
slp->gid = gid;
/* let's start our search */
setgrent();
if (!check_yellow()) {
while (gp = getgrent()) {
addtogrset(user, slp, &count, gp);
}
} else {
if (!grf)
return(NULL);
endoffile = 0;
while (!endoffile) {
int linefnd;
char *s, *p;
char line[GRPLINLEN+1];
if (yp) {
gp = interpretwithsave(yp, yplen, savegp);
free(yp);
getnextfromyellow();
if (gp == NULL)
continue;
if (onminuslist(gp))
continue;
else {
addtogrset(user, slp, &count, gp);
continue;
}
} else {
if (!(s = p = fgets(line,GRPLINLEN + 1,grf))) {
endoffile = 1;
continue;
}
while (*s != (char) NULL) {
if ((!(isspace((int)(*s)))) ||
(*s == '\n')) {
*p++ = *s;
}
*s++;
}
*p = *s;
if (line[0] == '\n')
continue;
}
if ((gp = interpret(line, strlen(line))) == NULL)
continue;
switch (line[0]) {
case '+':
if (!bind_to_yp())
continue;
if (strcmp(gp->gr_name, "+") == 0) {
if (!getgroupsbyuser
(pwp->pw_uid, slp, &count)) {
getfirstfromyellow();
savegp = save(gp);
}
continue;
}
/*
* else look up this entry in yellow pages
*/
savegp = save(gp);
gp = getnamefromyellow(gp->gr_name + 1, savegp);
if (gp == NULL)
continue;
else if (onminuslist(gp))
continue;
else
addtogrset(user, slp, &count, gp);
break;
case '-':
addtominuslist(gp->gr_name + 1);
break;
default:
if (onminuslist(gp))
continue;
addtogrset(user, slp, &count, gp);
break;
}
}
}
endgrent();
buf = interpline;
buf[0] = '\0';
for (tslp = slp; tslp; tslp = tslp->next) {
int len;
sprintf(buf, "%lu", tslp->gid);
len = strlen(buf);
if (tslp->next) {
buf[len] = ',';
len++;
}
buf += len;
/* Storage no longer needed */
if (tslp->name) free(tslp->name);
free(tslp);
}
return(interpline);
}
int
getgroupsbyuser(uid_t uid, struct setlist *slp, int *count)
{
register struct _grjunk *_gr = setgrjunk();
int reason;
char *val, *tval, *tgid;
int vallen;
#define MAXGROUPNAM 256
char groupid[MAXGROUPNAM];
char usernetname[MAXGROUPNAM]; /* for lack of a better define */
static int nomap_netid = FALSE;
struct setlist *tslp;
gid_t gid;
/*
* If there is a minus list then the system has been configured to
* delete groups from the NIS groups map. Since the standard search
* is trying to be subverted by this function and the list is going
* to be based on group ids and not the group names this short cut
* can not be used.
*/
if (nomap_netid == TRUE || minuslist != NULL)
return(0);
/* Get the users netname so that we can search netid.byname */
if (user2netname(usernetname, uid, domain) == 0)
return(0);
/* Check the NIS map to see if the user's mapping exists */
if (reason = yp_match(domain, "netid.byname",
usernetname, strlen(usernetname),
&val, &vallen)) {
if (reason == YPERR_MAP)
nomap_netid = TRUE;
return(0);
} else {
/*
* Walk through the list of groups and add them to the
* set that is already started. First skip to the beginning
* of the list.
*/
for (tval = val; *tval && *tval != ':'; tval++)
;
if (*tval != ':')
return(0);
for (tval++; (int)tval <= ((int)val + (int)vallen); ) {
tgid = groupid;
while (*tval != ',' && *tval != '\0' && *tval != '\n')
*tgid++ = *tval++;
tval++;
*tgid = '\0';
gid = atol(groupid);
/* check to see if the gid is already on the list */
for (tslp = slp; tslp; slp = tslp, tslp = tslp->next) {
if (gid == tslp->gid)
break;
}
if (tslp)
continue;
if ((tslp = (struct setlist *)malloc
(sizeof(struct setlist))) == NULL) {
free(val);
return(-1);
}
slp->next = tslp;
tslp->next = NULL;
tslp->name = NULL;
tslp->gid = gid;
(*count)++;
}
free(val);
}
return(1);
}
int
addtogrset (char *user, struct setlist *slp, int *count, struct group *gp)
{
char *group;
struct setlist *tslp;
int i, j, sz, match, offset;
group = gp->gr_name;
/* check to see if the group had already been added to the list */
for (tslp = slp; tslp; tslp = tslp->next) {
if (!strcmp(tslp->name, group)) {
return(0);
}
}
/* check group membership to see if the user is part of the group */
for (i = 0; gp->gr_mem[i]; i++) {
if (!strcmp(user, gp->gr_mem[i])) {
for (; slp->next; slp = slp->next)
;
if ((tslp = (struct setlist *)malloc
(sizeof(struct setlist))) == NULL)
return(-1);
if ((tslp->name = malloc(strlen(group) + 1)) == NULL)
return(-1);
slp->next = tslp;
tslp->next = NULL;
strcpy(tslp->name, group);
tslp->gid = gp->gr_gid;
(*count)++;
return(1);
}
}
return(2);
}
void
setgrent()
{
register struct _grjunk *_gr = setgrjunk();
register int flags;
if (_gr == 0)
return;
if (!grf) {
/* open /etc/group for close on exec */
if ((grf = fopen(GROUP, "r")) == NULL)
return;
flags = fcntl (grf->_file, F_GETFD, 0);
flags |= FD_CLOEXEC;
fcntl (grf->_file, F_SETFD, flags);
} else
rewind(grf);
if (yp)
free(yp);
yp = NULL;
freeminuslist();
}
void
endgrent()
{
register struct _grjunk *_gr = setgrjunk();
if (_gr == 0)
return;
if (grf) {
(void) fclose(grf);
grf = NULL;
}
if (yp)
free(yp);
yp = NULL;
freeminuslist();
}
struct group *
fgetgrent(FILE *f)
{
char line1[GRPLINLEN+1];
char *p, *s;
int linefnd;
struct group *gr;
/*
* A15852 fix - Read until Newline for lines longer than BUFSIZ.
* Be sure to loop thru invalid lines.
*/
do {
linefnd = 0;
while (linefnd == 0) {
if ( !(s = p = fgets(line1, GRPLINLEN + 1, f)))
return(NULL);
while (*s != (char) NULL) {
if ((!(isspace((int)(*s)))) || (*s == '\n')) {
*p++ = *s;
}
*s++;
}
if (line1[0] != '\n')
linefnd = 1;
}
/* A15852 fix end. */
} while ((gr = interpret(line1, strlen(line1))) == NULL);
return (gr);
}
static char *
grskip(register char *p, register int c)
{
while (*p && *p != c && *p != '\n')
++p;
if (*p == '\n')
*p = '\0';
else if (*p != '\0')
*p++ = '\0';
return(p);
}
struct group *
getgrent(void)
{
register struct _grjunk *_gr = setgrjunk();
char line1[GRPLINLEN+1];
static struct group *savegp;
struct group *gp;
register int flags;
char *p, *s;
int linefnd;
if (_gr == 0)
return(0);
if (!grf) {
/* open /etc/group for close on exec */
if ((grf = fopen(GROUP, "r")) == NULL)
return ((struct group *)NULL);
flags = fcntl (grf->_file, F_GETFD, 0);
flags |= FD_CLOEXEC;
if (fcntl (grf->_file, F_SETFD, flags) < 0)
return ((struct group *)NULL);
}
again:
if (yp) {
gp = interpretwithsave(yp, yplen, savegp);
free(yp);
getnextfromyellow();
if (gp == NULL)
goto again;
if (onminuslist(gp))
goto again;
else
return gp;
} else
{
linefnd = 0;
while ( linefnd == 0 ) {
if ( !(s = p = fgets(line1, GRPLINLEN + 1, grf)))
return(NULL);
while (*s != (char) NULL) {
if ((!(isspace((int)(*s)))) || (*s == '\n')) {
*p++ = *s;
}
*s++;
}
if (line1[0] != '\n')
linefnd = 1;
}
}
if ((gp = interpret(line1, strlen(line1))) == NULL)
goto again;
switch (line1[0]) {
case '+':
if (!check_yellow())
goto again;
if (!bind_to_yp())
goto again;
if (strcmp(gp->gr_name, "+") == 0) {
getfirstfromyellow();
savegp = save(gp);
goto again;
}
/*
* else look up this entry in yellow pages
*/
savegp = save(gp);
gp = getnamefromyellow(gp->gr_name + 1, savegp);
if (gp == NULL)
goto again;
else if (onminuslist(gp))
goto again;
else
return gp;
case '-':
if (!check_yellow())
goto again;
if (!bind_to_yp())
goto again;
addtominuslist(gp->gr_name + 1);
goto again;
default:
if (onminuslist(gp))
goto again;
return gp;
}
}
static struct group *
interpret(char *val, int len)
{
register struct _grjunk *_gr = setgrjunk();
register char *p, **q;
char *end;
unsigned long x;
register int ypentry;
if (_gr == 0)
return (0);
strncpy(interpline, val, len);
p = interpline;
interpline[len] = '\n';
interpline[len+1] = 0;
/*
* Set "ypentry" if this entry references the Yellow Pages;
* if so, null GIDs are allowed (because they will be filled in
* from the matching Yellow Pages entry).
*/
ypentry = (*p == '+' || *p == '-');
interpgp.gr_name = p;
p = grskip(p, ':');
interpgp.gr_passwd = p;
p = grskip(p, ':');
/* check for non-null gid */
if (*p == ':' && !ypentry)
return (NULL);
x = strtoul(p, &end, 10);
p = end;
/* check for numeric value - must have stopped on the colon */
if (*p++ != ':' && !ypentry)
return (NULL);
interpgp.gr_gid = x;
interpgp.gr_mem = agr_mem;
(void) grskip(p, '\n');
q = agr_mem;
while (*p) {
if (q < &agr_mem[MAXGRP-1])
*q++ = p;
p = grskip(p, ',');
}
*q = NULL;
return(&interpgp);
}
static int
freeminuslist()
{
register struct _grjunk *_gr = setgrjunk();
struct list *ls;
if (_gr == 0)
return;
for (ls = minuslist; ls != NULL; ls = ls->nxt) {
free(ls->name);
free(ls);
}
minuslist = NULL;
}
static struct group *
interpretwithsave(char *val, int len, struct group *savegp)
{
register struct _grjunk *_gr = setgrjunk();
struct group *gp;
if (_gr == 0)
return NULL;
if ((gp = interpret(val, len)) == NULL)
return NULL;
if (savegp->gr_passwd && *savegp->gr_passwd)
gp->gr_passwd = savegp->gr_passwd;
if (savegp->gr_mem && *savegp->gr_mem)
gp->gr_mem = savegp->gr_mem;
return gp;
}
static int
onminuslist(struct group *gp)
{
register struct _grjunk *_gr = setgrjunk();
struct list *ls;
register char *nm;
if (_gr == 0)
return 0;
nm = gp->gr_name;
for (ls = minuslist; ls != NULL; ls = ls->nxt)
if (strcmp(ls->name, nm) == 0)
return 1;
return 0;
}
static int
getnextfromyellow()
{
register struct _grjunk *_gr = setgrjunk();
int reason;
char *key = NULL;
int keylen;
if (_gr == 0)
return;
/* Return if we should not report NIS */
if (!REPORT(NIS_MASK))
{
yp = NULL;
return 0;
}
if (reason = yp_next(domain, "group.byname", oldyp, oldyplen, &key,
&keylen,
&yp, &yplen)) {
yp = NULL;
}
if (oldyp)
free(oldyp);
oldyp = key;
oldyplen = keylen;
}
static int
getfirstfromyellow()
{
register struct _grjunk *_gr = setgrjunk();
int reason;
char *key = NULL;
int keylen;
if (_gr == 0)
return;
/* Return if we should not report NIS */
if (!REPORT(NIS_MASK))
{
yp = NULL;
return 0;
}
if (reason = yp_first(domain, "group.byname", &key, &keylen, &yp,
&yplen))
yp = NULL;
if (oldyp)
free(oldyp);
oldyp = key;
oldyplen = keylen;
}
static struct group *
getnamefromyellow(char *name, struct group *savegp)
{
register struct _grjunk *_gr = setgrjunk();
struct group *gp;
int reason;
char *val;
int vallen;
if (_gr == 0)
return NULL;
/* Return if we should not report NIS users */
if (!REPORT(NIS_MASK))
return((struct group *)NULL);
if (reason = yp_match(domain, "group.byname", name, strlen(name),
&val, &vallen))
return NULL;
else
{
gp = interpret(val, vallen);
free(val);
if (gp == NULL)
return NULL;
if (savegp->gr_passwd && *savegp->gr_passwd)
gp->gr_passwd = savegp->gr_passwd;
if (savegp->gr_mem && *savegp->gr_mem)
gp->gr_mem = savegp->gr_mem;
return gp;
}
}
static int
addtominuslist(char *name)
{
register struct _grjunk *_gr = setgrjunk();
struct list *ls;
char *buf;
if (_gr == 0)
return;
ls = (struct list *)malloc(sizeof(struct list ));
buf = (char *)malloc(strlen(name) + 1);
(void) strcpy(buf, name);
ls->name = buf;
ls->nxt = minuslist;
minuslist = ls;
}
/*
* save away psswd, gr_mem fields, which are the only
* ones which can be specified in a local + entry to override the
* value in the yellow pages
*/
static struct group *
save(struct group *gp)
{
register struct _grjunk *_gr = setgrjunk();
static struct group *sv;
char *gr_mem[MAXGRP];
char **av, **q = 0;
int lnth;
if (_gr == 0)
return 0;
/*
* free up stuff from last time around
*/
if (sv) {
for (av = sv->gr_mem; *av != NULL; av++) {
if (q >= &gr_mem[MAXGRP-1])
break;
free(*q);
q++;
}
free(sv->gr_passwd);
free(sv->gr_mem);
free(sv);
}
sv = (struct group *)malloc(sizeof(struct group ));
sv->gr_passwd = (char *)malloc(strlen(gp->gr_passwd) + 1);
(void) strcpy(sv->gr_passwd, gp->gr_passwd);
q = gr_mem;
for (av = gp->gr_mem; *av != NULL; av++) {
if (q >= &gr_mem[MAXGRP-1])
break;
*q = (char *)malloc(strlen(*av) + 1);
(void) strcpy(*q, *av);
q++;
}
*q = 0;
lnth = (sizeof (char *)) * (q - gr_mem + 1);
sv->gr_mem = (char **)malloc(lnth);
bcopy((char *)gr_mem, (char *)sv->gr_mem, lnth);
return sv;
}
static int
matchname(char *line1, struct group **gpp, char *name)
{
register struct _grjunk *_gr = setgrjunk();
struct group *savegp;
struct group *gp = *gpp;
if (_gr == 0)
return 0;
switch (line1[0]) {
case '+':
if (!bind_to_yp())
break;
if (strcmp(gp->gr_name, "+") == 0) {
savegp = save(gp);
gp = getnamefromyellow(name, savegp);
if (gp) {
*gpp = gp;
return 1;
} else
return 0;
}
if (strcmp(gp->gr_name + 1, name) == 0) {
savegp = save(gp);
gp = getnamefromyellow(gp->gr_name + 1, savegp);
if (gp) {
*gpp = gp;
return 1;
} else
return 0;
}
break;
case '-':
if (strcmp(gp->gr_name + 1, name) == 0) {
*gpp = NULL;
return 1;
}
break;
default:
if (strcmp(gp->gr_name, name) == 0)
return 1;
}
return 0;
}
static int
matchgid(char *line1, struct group **gpp, gid_t gid)
{
register struct _grjunk *_gr = setgrjunk();
struct group *savegp;
struct group *gp = *gpp;
if (_gr == 0)
return 0;
switch (line1[0]) {
case '+':
if (strcmp(gp->gr_name, "+") == 0) {
savegp = save(gp);
gp = getgidfromyellow(gid, savegp);
if (gp) {
*gpp = gp;
return 1;
} else
return 0;
}
savegp = save(gp);
gp = getnamefromyellow(gp->gr_name + 1, savegp);
if (gp && gp->gr_gid == gid) {
*gpp = gp;
return 1;
} else
return 0;
case '-':
if (!bind_to_yp())
break;
if (gid == gidof(gp->gr_name + 1)) {
*gpp = NULL;
return 1;
}
break;
default:
if (gp->gr_gid == gid)
return 1;
}
return 0;
}
static gid_t
gidof(char *name)
{
register struct _grjunk *_gr = setgrjunk();
struct group *gp;
if (_gr == 0)
return 0;
gp = getnamefromyellow(name, &NULLGP);
if (gp)
return gp->gr_gid;
else
return MAXINT;
}
static struct group *
getgidfromyellow(int gid, struct group *savegp)
{
register struct _grjunk *_gr = setgrjunk();
struct group *gp;
int reason;
char *val;
int vallen;
char gidstr[20];
if (_gr == 0)
return 0;
/* Return if we should not report NIS users */
if (!REPORT(NIS_MASK))
return((struct group *)NULL);
sprintf(gidstr, "%d", gid);
if (reason = yp_match(domain, "group.bygid", gidstr,
strlen(gidstr), &val, &vallen)) {
return NULL;
} else
{
gp = interpret(val, vallen);
free(val);
if (gp == NULL)
return NULL;
if (savegp->gr_passwd && *savegp->gr_passwd)
gp->gr_passwd = savegp->gr_passwd;
if (savegp->gr_mem && *savegp->gr_mem)
gp->gr_mem = savegp->gr_mem;
return gp;
}
}
/*
* NAME: check_dce
*
* FUNCTION: If the name resolution is to report DCE user names, and
* if the DCE module is loaded, or can be loaded then this
* module reports true.
*
* Returns: 0 - Do not check DCE name resolution.
* 1 - Check DCE name resolution
*/
static int
check_dce()
{
static int loaded;
register struct _grjunk *_gr = setgrjunk();
if (!REPORT(DCE_MASK))
return(0);
if (loaded)
return(loaded);
/*
* Load the security method using the libs.a routine _load_secmethod().
* This should either fail or produce a function pointer table
* with name resolution routines.
*/
if (!_load_secmethod(AUTH_DCE, &dcemethod))
loaded = TRUE;
return(loaded);
}
/*
* NAME: check_yellow
*
* FUNCTION: This is not quite the same as the old usingyellow variable.
* This function returns true if we want to use yellow pages.
* It does everything except the bind. The bind is left until
* we hit something which forces us to bind.
*
* RETURNS: 1 - NIS should be queried.
* 0 - NIS should not be queried.
*/
static int
check_yellow()
{
register struct _grjunk *_gr = setgrjunk();
if (!REPORT(NIS_MASK))
return(0);
if (domain == NULL)
(void) usingypmap(&domain, NULL);
return domain != NULL;
}
static int
bind_to_yp()
{
register struct _grjunk *_gr = setgrjunk();
if (check_yellow() && firsttime == 0) {
firsttime = 1;
usingyellow = !yp_bind(domain);
}
return usingyellow;
}
/*
* NAME: set_getgrent_remote
*
* FUNCTION: Turns on and off remote lookup routines. This interface
* supports the following lookup paths depending on the "value"
* parameter.
*
* value Path
* ----- ---------------
* 0 : Local
* 1 : Local, NIS, DCE
* 2 : Local, NIS ---> "COMPAT"
* 3 : DCE
*
* The routine is useful in AIX 4.1 since DCE wants to support the
* policy that user names and ids are uniquely defined within
* all domains (ie. no conflicts).
*/
void
set_getgrent_remote(int value)
{
switch(value)
{
case 0 : _report_remote_entries = SET_LOCAL;
break;
case 1 : _report_remote_entries = SET_ALL;
break;
case 2 : _report_remote_entries = SET_LOCAL_NIS;
break;
case 3 : _report_remote_entries = SET_DCE;
break;
default : _report_remote_entries = SET_ALL;
}
}
/*
* NAME: reset_grjunk_authstate
*
* FUNCTION: reset the value of authstate in the _grjunk static area,
* based on the AUTHSTATE env variable. This is only necessary
* after a call to authenticate (which sets AUTHSTATE) to ensure
* the getpw* / getgr* routines bind properly.
*
*/
void
reset_grjunk_authstate()
{
register struct _grjunk *_gr = setgrjunk();
if (_gr != NULL) {
char *env;
authstate = COMPAT;
env = getenv(AUTH_ENV);
if (!(env == NULL || env[0] == '\0'))
if (!strcmp(env, AUTH_DCE))
authstate = DCE;
}
return;
}