Line data Source code
1 : /*
2 : * System Security Services Daemon. NSS client interface
3 : *
4 : * Authors:
5 : * Lukas Slebodnik <lslebodn@redhat.com>
6 : *
7 : * Copyright (C) 2015 Red Hat
8 : *
9 : * This program is free software; you can redistribute it and/or modify
10 : * it under the terms of the GNU Lesser General Public License as
11 : * published by the Free Software Foundation; either version 2.1 of the
12 : * License, or (at your option) any later version.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU Lesser General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU Lesser General Public License
20 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : /* INITGROUPs database NSS interface using mmap cache */
24 :
25 : #include <errno.h>
26 : #include <stdio.h>
27 : #include <string.h>
28 : #include <stdlib.h>
29 : #include <stddef.h>
30 : #include <sys/mman.h>
31 : #include <time.h>
32 : #include "nss_mc.h"
33 : #include "util/util_safealign.h"
34 :
35 : struct sss_cli_mc_ctx initgr_mc_ctx = { UNINITIALIZED, -1, 0, NULL, 0, NULL, 0,
36 : NULL, 0, 0 };
37 :
38 0 : static errno_t sss_nss_mc_parse_result(struct sss_mc_rec *rec,
39 : long int *start, long int *size,
40 : gid_t **groups, long int limit)
41 : {
42 : struct sss_mc_initgr_data *data;
43 : time_t expire;
44 : long int i;
45 : uint32_t num_groups;
46 : long int max_ret;
47 :
48 : /* additional checks before filling result*/
49 0 : expire = rec->expire;
50 0 : if (expire < time(NULL)) {
51 : /* entry is now invalid */
52 0 : return EINVAL;
53 : }
54 :
55 0 : data = (struct sss_mc_initgr_data *)rec->data;
56 0 : num_groups = data->num_groups;
57 0 : max_ret = num_groups;
58 :
59 : /* check we have enough space in the buffer */
60 0 : if ((*size - *start) < num_groups) {
61 : long int newsize;
62 : gid_t *newgroups;
63 :
64 0 : newsize = *size + num_groups;
65 0 : if ((limit > 0) && (newsize > limit)) {
66 0 : newsize = limit;
67 0 : max_ret = newsize - *start;
68 : }
69 :
70 0 : newgroups = (gid_t *)realloc((*groups), newsize * sizeof(**groups));
71 0 : if (!newgroups) {
72 0 : return ENOMEM;
73 : }
74 0 : *groups = newgroups;
75 0 : *size = newsize;
76 : }
77 :
78 0 : for (i = 0; i < max_ret; i++) {
79 0 : SAFEALIGN_COPY_UINT32(&(*groups)[*start], data->gids + i, NULL);
80 0 : *start += 1;
81 : }
82 :
83 0 : return 0;
84 : }
85 :
86 0 : errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len,
87 : gid_t group, long int *start, long int *size,
88 : gid_t **groups, long int limit)
89 : {
90 0 : struct sss_mc_rec *rec = NULL;
91 : struct sss_mc_initgr_data *data;
92 : char *rec_name;
93 : uint32_t hash;
94 : uint32_t slot;
95 : int ret;
96 0 : const size_t data_offset = offsetof(struct sss_mc_initgr_data, gids);
97 : size_t data_size;
98 :
99 0 : ret = sss_nss_mc_get_ctx("initgroups", &initgr_mc_ctx);
100 0 : if (ret) {
101 0 : return ret;
102 : }
103 :
104 : /* Get max size of data table. */
105 0 : data_size = initgr_mc_ctx.dt_size;
106 :
107 : /* hashes are calculated including the NULL terminator */
108 0 : hash = sss_nss_mc_hash(&initgr_mc_ctx, name, name_len + 1);
109 0 : slot = initgr_mc_ctx.hash_table[hash];
110 :
111 : /* If slot is not within the bounds of mmaped region and
112 : * it's value is not MC_INVALID_VAL, then the cache is
113 : * probbably corrupted. */
114 0 : while (MC_SLOT_WITHIN_BOUNDS(slot, data_size)) {
115 : /* free record from previous iteration */
116 0 : free(rec);
117 0 : rec = NULL;
118 :
119 0 : ret = sss_nss_mc_get_record(&initgr_mc_ctx, slot, &rec);
120 0 : if (ret) {
121 0 : goto done;
122 : }
123 :
124 : /* check record matches what we are searching for */
125 0 : if (hash != rec->hash1) {
126 : /* if name hash does not match we can skip this immediately */
127 0 : slot = sss_nss_mc_next_slot_with_hash(rec, hash);
128 0 : continue;
129 : }
130 :
131 0 : data = (struct sss_mc_initgr_data *)rec->data;
132 0 : rec_name = (char *)data + data->name;
133 : /* Integrity check
134 : * - name_len cannot be longer than all strings or data
135 : * - all data must be within copy of record
136 : * - size of record must be lower that data table size
137 : * - data->strs cannot point outside strings */
138 0 : if (name_len > data->strs_len
139 0 : || data->strs_len > data->data_len
140 0 : || data->data_len > rec->len
141 0 : || rec->len > data_size
142 0 : || (data->strs + name_len) > (data_offset + data->data_len)) {
143 0 : ret = ENOENT;
144 0 : goto done;
145 : }
146 :
147 0 : if (strcmp(name, rec_name) == 0) {
148 0 : break;
149 : }
150 :
151 0 : slot = sss_nss_mc_next_slot_with_hash(rec, hash);
152 : }
153 :
154 0 : if (!MC_SLOT_WITHIN_BOUNDS(slot, data_size)) {
155 0 : ret = ENOENT;
156 0 : goto done;
157 : }
158 :
159 0 : ret = sss_nss_mc_parse_result(rec, start, size, groups, limit);
160 :
161 : done:
162 0 : free(rec);
163 0 : __sync_sub_and_fetch(&initgr_mc_ctx.active_threads, 1);
164 0 : return ret;
165 : }
|