nss_mc_initgr.c revision 225dc6914cdc8920b02a129b98ece1ed97b99c03
0N/A/*
0N/A * System Security Services Daemon. NSS client interface
0N/A *
0N/A * Authors:
0N/A * Lukas Slebodnik <lslebodn@redhat.com>
180N/A *
180N/A * Copyright (C) 2015 Red Hat
51N/A *
51N/A * This program is free software; you can redistribute it and/or modify
51N/A * it under the terms of the GNU Lesser General Public License as
180N/A * published by the Free Software Foundation; either version 2.1 of the
180N/A * License, or (at your option) any later version.
180N/A *
180N/A * This program is distributed in the hope that it will be useful,
180N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
0N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
336N/A * GNU Lesser General Public License for more details.
336N/A *
336N/A * You should have received a copy of the GNU Lesser General Public License
336N/A * along with this program. If not, see <http://www.gnu.org/licenses/>.
365N/A */
408N/A
336N/A/* INITGROUPs database NSS interface using mmap cache */
361N/A
389N/A#include <errno.h>
390N/A#include <stdio.h>
370N/A#include <string.h>
378N/A#include <stdlib.h>
380N/A#include <stddef.h>
392N/A#include <sys/mman.h>
393N/A#include <time.h>
336N/A#include "nss_mc.h"
336N/A#include "util/util_safealign.h"
204N/A
204N/Astruct sss_cli_mc_ctx initgr_mc_ctx = { UNINITIALIZED, -1, 0, NULL, 0, NULL, 0,
204N/A NULL, 0, 0 };
204N/A
254N/Astatic errno_t sss_nss_mc_parse_result(struct sss_mc_rec *rec,
254N/A long int *start, long int *size,
204N/A gid_t **groups, long int limit)
217N/A{
265N/A struct sss_mc_initgr_data *data;
316N/A time_t expire;
206N/A long int i;
307N/A uint32_t num_groups;
316N/A long int max_ret;
322N/A
208N/A /* additional checks before filling result*/
209N/A expire = rec->expire;
210N/A if (expire < time(NULL)) {
216N/A /* entry is now invalid */
224N/A return EINVAL;
225N/A }
240N/A
241N/A data = (struct sss_mc_initgr_data *)rec->data;
247N/A num_groups = data->num_groups;
249N/A max_ret = num_groups;
252N/A
253N/A /* check we have enough space in the buffer */
262N/A if ((*size - *start) < num_groups) {
264N/A long int newsize;
267N/A gid_t *newgroups;
267N/A
270N/A newsize = *size + num_groups;
270N/A if ((limit > 0) && (newsize > limit)) {
272N/A newsize = limit;
275N/A max_ret = newsize - *start;
282N/A }
283N/A
328N/A newgroups = (gid_t *)realloc((*groups), newsize * sizeof(**groups));
204N/A if (!newgroups) {
204N/A return ENOMEM;
135N/A }
135N/A *groups = newgroups;
135N/A *size = newsize;
135N/A }
179N/A
143N/A for (i = 0; i < max_ret; i++) {
158N/A SAFEALIGN_COPY_UINT32(&(*groups)[*start], data->gids + i, NULL);
152N/A *start += 1;
159N/A }
179N/A
180N/A return 0;
181N/A}
180N/A
135N/Aerrno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len,
137N/A gid_t group, long int *start, long int *size,
139N/A gid_t **groups, long int limit)
144N/A{
153N/A struct sss_mc_rec *rec = NULL;
155N/A struct sss_mc_initgr_data *data;
169N/A char *rec_name;
174N/A uint32_t hash;
188N/A uint32_t slot;
189N/A int ret;
135N/A const size_t data_offset = offsetof(struct sss_mc_initgr_data, gids);
135N/A uint8_t *max_addr;
3N/A
3N/A ret = sss_nss_mc_get_ctx("initgroups", &initgr_mc_ctx);
3N/A if (ret) {
3N/A return ret;
22N/A }
22N/A
3N/A /* Get max address of data table. */
38N/A max_addr = initgr_mc_ctx.data_table + initgr_mc_ctx.dt_size;
35N/A
35N/A /* hashes are calculated including the NULL terminator */
36N/A hash = sss_nss_mc_hash(&initgr_mc_ctx, name, name_len + 1);
36N/A slot = initgr_mc_ctx.hash_table[hash];
90N/A
40N/A /* If slot is not within the bounds of mmaped region and
66N/A * it's value is not MC_INVALID_VAL, then the cache is
66N/A * probbably corrupted. */
79N/A while (MC_SLOT_WITHIN_BOUNDS(slot, initgr_mc_ctx.dt_size)) {
75N/A /* free record from previous iteration */
76N/A free(rec);
101N/A rec = NULL;
104N/A
180N/A ret = sss_nss_mc_get_record(&initgr_mc_ctx, slot, &rec);
180N/A if (ret) {
180N/A goto done;
180N/A }
22N/A
22N/A /* check record matches what we are searching for */
33N/A if (hash != rec->hash1) {
33N/A /* if name hash does not match we can skip this immediately */
45N/A slot = sss_nss_mc_next_slot_with_hash(rec, hash);
45N/A continue;
55N/A }
57N/A
58N/A data = (struct sss_mc_initgr_data *)rec->data;
60N/A rec_name = (char *)data + data->name;
62N/A /* Integrity check
73N/A * - name_len cannot be longer than all strings or data
73N/A * - data->name cannot point outside strings
93N/A * - all data must be within data_table
93N/A * - name must be within data_table */
81N/A if (name_len > data->data_len
85N/A || name_len > data->strs_len
86N/A || (data->strs + name_len) > (data_offset + data->data_len)
88N/A || (uint8_t *)data->gids + data->data_len > max_addr
91N/A || (uint8_t *)rec_name + name_len > max_addr) {
96N/A ret = ENOENT;
3N/A goto done;
3N/A }
0N/A
0N/A if (strcmp(name, rec_name) == 0) {
0N/A break;
0N/A }
0N/A
0N/A slot = sss_nss_mc_next_slot_with_hash(rec, hash);
0N/A }
0N/A
0N/A if (!MC_SLOT_WITHIN_BOUNDS(slot, initgr_mc_ctx.dt_size)) {
0N/A ret = ENOENT;
0N/A goto done;
0N/A }
0N/A
0N/A ret = sss_nss_mc_parse_result(rec, start, size, groups, limit);
0N/A
0N/Adone:
0N/A free(rec);
0N/A __sync_sub_and_fetch(&initgr_mc_ctx.active_threads, 1);
0N/A return ret;
0N/A}
0N/A