version 1.1.1.1, 2012/02/21 16:23:02
|
version 1.1.1.2, 2013/07/22 10:46:11
|
Line 1
|
Line 1
|
/* |
/* |
* Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com> | * Copyright (c) 2010, 2011, 2013 Todd C. Miller <Todd.Miller@courtesan.com> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
Line 16
|
Line 16
|
|
|
#include <config.h> |
#include <config.h> |
|
|
|
#ifndef HAVE_GETGROUPLIST |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <stdio.h> |
#include <stdio.h> |
#ifdef STDC_HEADERS |
#ifdef STDC_HEADERS |
Line 33
|
Line 35
|
# include <strings.h> |
# include <strings.h> |
#endif /* HAVE_STRINGS_H */ |
#endif /* HAVE_STRINGS_H */ |
#include <grp.h> |
#include <grp.h> |
|
#ifdef HAVE_NSS_SEARCH |
|
# include <limits.h> |
|
# include <nsswitch.h> |
|
# ifdef HAVE_NSS_DBDEFS_H |
|
# include <nss_dbdefs.h> |
|
# else |
|
# include "compat/nss_dbdefs.h" |
|
# endif |
|
#endif |
|
|
#include "missing.h" |
#include "missing.h" |
|
|
#ifdef HAVE_GETGRSET | #if defined(HAVE_GETGRSET) |
/* |
/* |
* BSD-compatible getgrouplist(3) using getgrset(3) |
* BSD-compatible getgrouplist(3) using getgrset(3) |
*/ |
*/ |
Line 70 getgrouplist(const char *name, gid_t basegid, gid_t *g
|
Line 81 getgrouplist(const char *name, gid_t basegid, gid_t *g
|
rval = 0; |
rval = 0; |
|
|
done: |
done: |
efree(grset); | free(grset); |
#ifdef HAVE_SETAUTHDB |
#ifdef HAVE_SETAUTHDB |
aix_restoreauthdb(); |
aix_restoreauthdb(); |
#endif |
#endif |
Line 79 done:
|
Line 90 done:
|
return rval; |
return rval; |
} |
} |
|
|
#else /* HAVE_GETGRSET */ | #elif defined(HAVE_NSS_SEARCH) |
|
|
|
#ifndef GID_MAX |
|
# define GID_MAX UID_MAX |
|
#endif |
|
|
|
#ifndef ALIGNBYTES |
|
# define ALIGNBYTES (sizeof(long) - 1L) |
|
#endif |
|
#ifndef ALIGN |
|
# define ALIGN(p) (((unsigned long)(p) + ALIGNBYTES) & ~ALIGNBYTES) |
|
#endif |
|
|
|
extern void _nss_initf_group(nss_db_params_t *); |
|
|
/* |
/* |
|
* Convert a groups file string (instr) to a struct group (ent) using |
|
* buf for storage. |
|
*/ |
|
static int |
|
str2grp(const char *instr, int inlen, void *ent, char *buf, int buflen) |
|
{ |
|
struct group *grp = ent; |
|
char *cp, *ep, *fieldsep = buf; |
|
char **gr_mem, **gr_end; |
|
int yp = 0; |
|
unsigned long gid; |
|
|
|
/* Must at least have space to copy instr -> buf. */ |
|
if (inlen >= buflen) |
|
return NSS_STR_PARSE_ERANGE; |
|
|
|
/* Paranoia: buf and instr should be distinct. */ |
|
if (buf != instr) { |
|
memmove(buf, instr, inlen); |
|
buf[inlen] = '\0'; |
|
} |
|
|
|
if ((fieldsep = strchr(cp = fieldsep, ':')) == NULL) |
|
return NSS_STR_PARSE_PARSE; |
|
*fieldsep++ = '\0'; |
|
grp->gr_name = cp; |
|
|
|
/* Check for YP inclusion/exclusion entries. */ |
|
if (*cp == '+' || *cp == '-') { |
|
/* Only the name is required for YP inclusion/exclusion entries. */ |
|
grp->gr_passwd = ""; |
|
grp->gr_gid = 0; |
|
grp->gr_mem = NULL; |
|
yp = 1; |
|
} |
|
|
|
if ((fieldsep = strchr(cp = fieldsep, ':')) == NULL) |
|
return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE; |
|
*fieldsep++ = '\0'; |
|
grp->gr_passwd = cp; |
|
|
|
if ((fieldsep = strchr(cp = fieldsep, ':')) == NULL) |
|
return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE; |
|
*fieldsep++ = '\0'; |
|
gid = strtoul(cp, &ep, 10); |
|
if (*cp == '\0' || *ep != '\0') |
|
return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE; |
|
#ifdef GID_NOBODY |
|
if (*cp == '-' && gid != 0) { |
|
/* Negative gids get mapped to nobody on Solaris. */ |
|
grp->gr_gid = GID_NOBODY; |
|
} else |
|
#endif |
|
if ((errno == ERANGE && gid == ULONG_MAX) || |
|
gid > GID_MAX || gid != (gid_t)gid) { |
|
return NSS_STR_PARSE_ERANGE; |
|
} else { |
|
grp->gr_gid = (gid_t)gid; |
|
} |
|
|
|
/* Store group members, taking care to use proper alignment. */ |
|
grp->gr_mem = NULL; |
|
if (*fieldsep != '\0') { |
|
grp->gr_mem = gr_mem = (char **)ALIGN(buf + inlen + 1); |
|
gr_end = (char **)((unsigned long)(buf + buflen) & ~ALIGNBYTES); |
|
for (;;) { |
|
if (gr_mem == gr_end) |
|
return NSS_STR_PARSE_ERANGE; /* out of space! */ |
|
*gr_mem++ = cp; |
|
if (fieldsep == NULL) |
|
break; |
|
if ((fieldsep = strchr(cp = fieldsep, ',')) != NULL) |
|
*fieldsep++ = '\0'; |
|
} |
|
*gr_mem = NULL; |
|
} |
|
return NSS_STR_PARSE_SUCCESS; |
|
} |
|
|
|
static nss_status_t |
|
process_cstr(const char *instr, int inlen, struct nss_groupsbymem *gbm) |
|
{ |
|
const char *user = gbm->username; |
|
nss_status_t rval = NSS_NOTFOUND; |
|
nss_XbyY_buf_t *buf; |
|
struct group *grp; |
|
char **gr_mem; |
|
int error, i; |
|
|
|
buf = _nss_XbyY_buf_alloc(sizeof(struct group), NSS_BUFLEN_GROUP); |
|
if (buf == NULL) |
|
return NSS_UNAVAIL; |
|
|
|
/* Parse groups file string -> struct group. */ |
|
grp = buf->result; |
|
error = (*gbm->str2ent)(instr, inlen, grp, buf->buffer, buf->buflen); |
|
if (error || grp->gr_mem == NULL) |
|
goto done; |
|
|
|
for (gr_mem = grp->gr_mem; *gr_mem != NULL; gr_mem++) { |
|
if (strcmp(*gr_mem, user) == 0) { |
|
/* Append to gid_array unless gr_gid is a dupe. */ |
|
for (i = 0; i < gbm->numgids; i++) { |
|
if (gbm->gid_array[i] == grp->gr_gid) |
|
goto done; /* already present */ |
|
} |
|
/* Store gid if there is space. */ |
|
if (i < gbm->maxgids) |
|
gbm->gid_array[i] = grp->gr_gid; |
|
/* Always increment numgids so we can detect when out of space. */ |
|
gbm->numgids++; |
|
goto done; |
|
} |
|
} |
|
done: |
|
_nss_XbyY_buf_free(buf); |
|
return rval; |
|
} |
|
|
|
/* |
|
* BSD-compatible getgrouplist(3) using nss_search(3) |
|
*/ |
|
int |
|
getgrouplist(const char *name, gid_t basegid, gid_t *groups, int *ngroupsp) |
|
{ |
|
struct nss_groupsbymem gbm; |
|
static DEFINE_NSS_DB_ROOT(db_root); |
|
|
|
/* We support BSD semantics where the first element is the base gid */ |
|
if (*ngroupsp <= 0) |
|
return -1; |
|
groups[0] = basegid; |
|
|
|
memset(&gbm, 0, sizeof(gbm)); |
|
gbm.username = name; |
|
gbm.gid_array = groups; |
|
gbm.maxgids = *ngroupsp; |
|
gbm.numgids = 1; /* for basegid */ |
|
gbm.force_slow_way = 1; |
|
gbm.str2ent = str2grp; |
|
gbm.process_cstr = process_cstr; |
|
|
|
/* |
|
* Can't use nss_search return value since it may return NSS_UNAVAIL |
|
* when no nsswitch.conf entry (e.g. compat mode). |
|
*/ |
|
(void)nss_search(&db_root, _nss_initf_group, NSS_DBOP_GROUP_BYMEMBER, &gbm); |
|
|
|
if (gbm.numgids <= gbm.maxgids) { |
|
*ngroupsp = gbm.numgids; |
|
return 0; |
|
} |
|
*ngroupsp = gbm.maxgids; |
|
return -1; |
|
} |
|
|
|
#else /* !HAVE_GETGRSET && !HAVE__GETGROUPSBYMEMBER */ |
|
|
|
/* |
* BSD-compatible getgrouplist(3) using getgrent(3) |
* BSD-compatible getgrouplist(3) using getgrent(3) |
*/ |
*/ |
int |
int |
Line 128 done:
|
Line 311 done:
|
|
|
return rval; |
return rval; |
} |
} |
#endif /* HAVE_GETGRSET */ | #endif /* !HAVE_GETGRSET && !HAVE__GETGROUPSBYMEMBER */ |
| #endif /* HAVE_GETGROUPLIST */ |