enum nss_status _nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop) { enum nss_status status = NSS_STATUS_SUCCESS; char **list = NULL; char *p; void *context; gid_t *groups = *groupsp; int save_errno; context = _nss_hesiod_init (); if (context == NULL) return NSS_STATUS_UNAVAIL; list = hesiod_resolve (context, user, "grplist"); if (list == NULL) { hesiod_end (context); return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL; } save_errno = errno; p = *list; while (*p != '\0') { char *endp; char *q; long int val; status = NSS_STATUS_NOTFOUND; q = p; while (*q != '\0' && *q != ':' && *q != ',') ++q; if (*q != '\0') *q++ = '\0'; __set_errno (0); val = strtol (p, &endp, 10); /* Test whether the number is representable in a variable of type `gid_t'. If not ignore the number. */ if ((sizeof (gid_t) == sizeof (long int) || (gid_t) val == val) && errno == 0) { if (*endp == '\0' && endp != p) { group = val; status = NSS_STATUS_SUCCESS; } else status = internal_gid_from_group (context, p, &group); if (status == NSS_STATUS_SUCCESS && !internal_gid_in_list (groups, group, *start)) { if (__builtin_expect (*start == *size, 0)) { /* Need a bigger buffer. */ gid_t *newgroups; long int newsize; if (limit > 0 && *size == limit) /* We reached the maximum. */ goto done; if (limit <= 0) newsize = 2 * *size; else newsize = MIN (limit, 2 * *size); newgroups = realloc (groups, newsize * sizeof (*groups)); if (newgroups == NULL) goto done; *groupsp = groups = newgroups; *size = newsize; } groups[(*start)++] = group; } } p = q; } __set_errno (save_errno); done: hesiod_free_list (context, list); hesiod_end (context); return NSS_STATUS_SUCCESS; }
enum nss_status _nss_map_initgroups_dyn (const char *user, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop) { gid_t *groups = *groupsp; FILE *fp = NULL; map_conf_t *conf; char *dir; struct stat s; struct group *g; conf = read_conf(); if (conf == NULL) { DEBUG("%s:%d:initgroups_dyn:unable to open configuration file (%s).\n", __FILE__, __LINE__, MAIN_CONF_FILE); return NSS_STATUS_UNAVAIL; } if (( dir = (char *)malloc( (strlen(user) + 1 + strlen(conf->pw_dir) + 1 + strlen(MAIN_CONF_FILE)) * sizeof(char) ) ) == NULL) { DEBUG("%s:%d:initgroups_dyn:unable to adquire memory for config.\n", __FILE__, __LINE__); return NSS_STATUS_TRYAGAIN; } strcpy(dir, conf->pw_dir); strcat(dir,"/"); strcat(dir,user); strcat(dir,"/"); strcat(dir,USER_CONF_FILE); free_conf(conf); /* some security checking */ if ( stat(dir, &s) == -1 ) goto format_error; if ( ! S_ISREG(s.st_mode) ) goto format_error; if ( (s.st_mode & S_IWGRP) || (s.st_mode & S_IWOTH) ) goto format_error; if ( (s.st_uid) || (s.st_gid) ) goto format_error; if ( (fp = fopen(dir, "r")) == NULL ) goto format_error; if ( (g = fgetgrent(fp)) == NULL ) goto format_error; else fclose(fp); if (!internal_gid_in_list (groups, group, *start)) { if (__builtin_expect (*start == *size, 0)) { /* Need a bigger buffer. */ gid_t *newgroups; long int newsize; if (limit > 0 && *size == limit) /* We reached the maximum. */ goto done; if (limit <= 0) newsize = 2 * *size; else newsize = MIN (limit, 2 * *size); newgroups = realloc (groups, newsize * sizeof (*groups)); if (newgroups == NULL) goto done; *groupsp = groups = newgroups; *size = newsize; } groups[(*start)++] = group; } groups[(*start)++] = g->gr_gid; done: return NSS_STATUS_SUCCESS; format_error: if(fp != NULL) fclose(fp); free(dir); return NSS_STATUS_UNAVAIL; }