static enum nss_status internal_getgrent(struct group *gr, char *buffer, size_t buflen, int *errnop, void *cmpdata, int (*cmpFunc)(void *, void *)) { struct group *grpp; int r = 0; enum nss_status result = NSS_STATUS_SUCCESS; if ( (fgrent.stream == NULL) || (cmpdata != NULL) ) result = internal_setent(&fgrent); if (result != NSS_STATUS_SUCCESS) return result; while (!r) { r = fgetgrent_r(fgrent.stream, gr, buffer, buflen, &grpp); if ( (cmpFunc == NULL) || (cmpFunc(gr, cmpdata))) break; } if (r == ERANGE) { *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } if (r) return NSS_STATUS_NOTFOUND; return result; }
/* Maintenance of the shared handle open on the database. */ enum nss_status _nss_db_setnetgrent (const char *group, struct __netgrent *result) { struct nss_db_map state; enum nss_status status = internal_setent (DBFILE, &state); if (status == NSS_STATUS_SUCCESS) { const struct nss_db_header *header = state.header; const stridx_t *hashtable = (const stridx_t *) ((const char *) header + header->dbs[0].hashoffset); const char *valstrtab = (const char *) header + header->valstroffset; uint32_t hashval = __hash_string (group); size_t grouplen = strlen (group); size_t hidx = hashval % header->dbs[0].hashsize; size_t hval2 = 1 + hashval % (header->dbs[0].hashsize - 2); status = NSS_STATUS_NOTFOUND; while (hashtable[hidx] != ~((stridx_t) 0)) { const char *valstr = valstrtab + hashtable[hidx]; if (strncmp (valstr, group, grouplen) == 0 && isblank (valstr[grouplen])) { const char *cp = &valstr[grouplen + 1]; while (isblank (*cp)) ++cp; if (*cp != '\0') { result->data = strdup (cp); if (result->data == NULL) status = NSS_STATUS_TRYAGAIN; else { status = NSS_STATUS_SUCCESS; result->cursor = result->data; } break; } } if ((hidx += hval2) >= header->dbs[0].hashsize) hidx -= header->dbs[0].hashsize; } internal_endent (&state); } return status; }
/* Open the database. */ enum nss_status CONCAT(_nss_db_set,ENTNAME) (int stayopen) { enum nss_status status; __libc_lock_lock (lock); status = internal_setent (DBFILE, &db); /* Remember STAYOPEN flag. */ if (db != NULL) keep_db |= stayopen; /* Reset the sequential index. */ entidx = 0; __libc_lock_unlock (lock); return status; }
/* Thread-safe, exported version of that. */ enum nss_status CONCAT(CONCAT(CONCAT(_nss_, ALTFILES_MODULE_NAME), _set), ENTNAME) (int stayopen) { enum nss_status status; __libc_lock_lock (lock); status = internal_setent (stayopen); if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0) { fclose (stream); stream = NULL; status = NSS_STATUS_UNAVAIL; } last_use = getent; __libc_lock_unlock (lock); return status; }
enum nss_status _nss_db_initgroups_dyn (const char *user, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop) { struct nss_db_map state = { NULL, 0 }; enum nss_status status = internal_setent (_PATH_VARDB "group.db", &state); if (status != NSS_STATUS_SUCCESS) { *errnop = errno; return status; } const struct nss_db_header *header = state.header; int i; for (i = 0; i < header->ndbs; ++i) if (header->dbs[i].id == ':') break; if (i == header->ndbs) { status = NSS_STATUS_UNAVAIL; goto out; } const stridx_t *hashtable = (const stridx_t *) ((const char *) header + header->dbs[i].hashoffset); const char *valstrtab = (const char *) header + header->valstroffset; size_t userlen = strlen (user); uint32_t hashval = __hash_string (user); size_t hidx = hashval % header->dbs[i].hashsize; size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2); gid_t *groups = *groupsp; status = NSS_STATUS_NOTFOUND; while (hashtable[hidx] != ~((stridx_t) 0)) { const char *valstr = valstrtab + hashtable[hidx]; while (isblank (*valstr)) ++valstr; if (strncmp (valstr, user, userlen) == 0 && isblank (valstr[userlen])) { valstr += userlen + 1; while (isblank (*valstr)) ++valstr; while (*valstr != '\0') { errno = 0; char *endp; unsigned long int n = strtoul (valstr, &endp, 10); if (*endp != ',' && *endp != '\0') break; valstr = *endp == '\0' ? endp : endp + 1; if (n != ULONG_MAX || errno != ERANGE) { /* Insert the group. */ if (*start == *size) { /* Need a bigger buffer. */ if (limit > 0 && *size == limit) { /* We reached the maximum. */ status = NSS_STATUS_SUCCESS; goto out; } long int newsize; if (limit <= 0) newsize = 2 * *size; else newsize = MIN (limit, 2 * *size); gid_t *newgroups = realloc (groups, newsize * sizeof (*groups)); if (newgroups == NULL) { *errnop = ENOMEM; status = NSS_STATUS_TRYAGAIN; goto out; } *groupsp = groups = newgroups; *size = newsize; } groups[*start] = n; *start += 1; } } status = NSS_STATUS_SUCCESS; break; } if ((hidx += hval2) >= header->dbs[i].hashsize) hidx -= header->dbs[i].hashsize; } out: internal_endent (&state); return status; }
enum nss_status _nss_filesplus_setgrent(void) { NSS_DEBUG("filesplus: %s\n",__func__); return internal_setent(&fgrent); }
enum nss_status _nss_filesplus_initgroups_dyn(const char *user, gid_t gid, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop) { enum nss_status result = NSS_STATUS_SUCCESS; struct group gr; char *buffer; size_t buffer_size; int found_one = 0; int i; gid_t *groups = *groupsp; NSS_DEBUG("filesplus: %s\n",__func__); result = internal_setent(&fgrent); if (result != NSS_STATUS_SUCCESS) return result; buffer_size = MAX_LINE_SIZE; buffer = (char *) malloc(buffer_size); while (result == NSS_STATUS_SUCCESS) { result = internal_getgrent(&gr, buffer, buffer_size, errnop, NULL, NULL); if ((result == NSS_STATUS_TRYAGAIN) && ( *errnop == ERANGE)) { char *new_buf; buffer_size = 2 * buffer_size; new_buf = (char *) realloc(buffer, buffer_size); if (new_buf == NULL) { *errnop = errno; result = NSS_STATUS_UNAVAIL; break; } buffer = new_buf; *errnop = 0; result = NSS_STATUS_SUCCESS; continue; } if (result != NSS_STATUS_SUCCESS) continue; if (gr.gr_gid == gid) continue; for (i = 0; ; i++) { if (gr.gr_mem[i] == NULL) break; if (strcmp(gr.gr_mem[i], user) == 0) { /* Matches user. Insert this group. */ if (*start == *size) { /* Need a bigger buffer. */ if (limit > 0 && *size == limit) /* We reached the maximum. */ goto out; long int newsize; if (limit <= 0) newsize = 2 * *size; else newsize = MIN (limit, 2 * *size); gid_t *newgroups = realloc (groups, newsize * sizeof (*groups)); if (newgroups == NULL) { *errnop = ENOMEM; result = NSS_STATUS_TRYAGAIN; goto out; } *groupsp = groups = newgroups; *size = newsize; } groups[*start] = gr.gr_gid; *start += 1; found_one = 1; break; } } } out: free(buffer); internal_endent(&fgrent); if (NSS_STATUS_NOTFOUND && found_one) result = NSS_STATUS_SUCCESS; return result; }