Line data Source code
1 : /*
2 : SSSD
3 :
4 : NSS Responder Interface for ID-SID mappings
5 :
6 : Authors:
7 : Sumit Bose <sbose@redhat.com>
8 :
9 : Copyright (C) 2013 Red Hat
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include <stdlib.h>
26 : #include <errno.h>
27 : #include <nss.h>
28 :
29 : #include "sss_client/sss_cli.h"
30 : #include "sss_client/idmap/sss_nss_idmap.h"
31 : #include "util/strtonum.h"
32 :
33 : #define DATA_START (3 * sizeof(uint32_t))
34 : union input {
35 : const char *str;
36 : uint32_t id;
37 : };
38 :
39 : struct output {
40 : enum sss_id_type type;
41 : union {
42 : char *str;
43 : uint32_t id;
44 : struct sss_nss_kv *kv_list;
45 : } d;
46 : };
47 :
48 0 : int nss_status_to_errno(enum nss_status nret) {
49 0 : switch (nret) {
50 : case NSS_STATUS_TRYAGAIN:
51 0 : return EAGAIN;
52 : case NSS_STATUS_SUCCESS:
53 0 : return EOK;
54 : case NSS_STATUS_UNAVAIL:
55 : default:
56 0 : return ENOENT;
57 : }
58 :
59 : return EINVAL;
60 : }
61 :
62 1 : void sss_nss_free_kv(struct sss_nss_kv *kv_list)
63 : {
64 : size_t c;
65 :
66 1 : if (kv_list != NULL) {
67 2 : for (c = 0; kv_list[c].key != NULL; c++) {
68 1 : free(kv_list[c].key);
69 1 : free(kv_list[c].value);
70 : }
71 1 : free(kv_list);
72 : }
73 1 : }
74 :
75 1 : static int buf_to_kv_list(uint8_t *buf, size_t buf_len,
76 : struct sss_nss_kv **kv_list)
77 : {
78 : size_t c;
79 1 : size_t count = 0;
80 : struct sss_nss_kv *list;
81 : uint8_t *p;
82 : int ret;
83 :
84 11 : for (c = 0; c < buf_len; c++) {
85 10 : if (buf[c] == '\0') {
86 2 : count++;
87 : }
88 : }
89 :
90 1 : if ((count % 2) != 0) {
91 0 : return EINVAL;
92 : }
93 1 : count /= 2;
94 :
95 1 : list = calloc((count + 1), sizeof(struct sss_nss_kv));
96 1 : if (list == NULL) {
97 0 : return ENOMEM;
98 : }
99 :
100 1 : p = buf;
101 2 : for (c = 0; c < count; c++) {
102 1 : list[c].key = strdup((char *) p);
103 1 : if (list[c].key == NULL) {
104 0 : ret = ENOMEM;
105 0 : goto done;
106 : }
107 :
108 1 : p = memchr(p, '\0', buf_len - (p - buf));
109 1 : if (p == NULL) {
110 0 : ret = EINVAL;
111 0 : goto done;
112 : }
113 1 : p++;
114 :
115 1 : list[c].value = strdup((char *) p);
116 1 : if (list[c].value == NULL) {
117 0 : ret = ENOMEM;
118 0 : goto done;
119 : }
120 :
121 1 : p = memchr(p, '\0', buf_len - (p - buf));
122 1 : if (p == NULL) {
123 0 : ret = EINVAL;
124 0 : goto done;
125 : }
126 1 : p++;
127 : }
128 :
129 1 : *kv_list = list;
130 :
131 1 : ret = EOK;
132 :
133 : done:
134 1 : if (ret != EOK) {
135 0 : sss_nss_free_kv(list);
136 : }
137 :
138 1 : return ret;
139 : }
140 :
141 5 : static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd ,
142 : struct output *out)
143 : {
144 : int ret;
145 : size_t inp_len;
146 : struct sss_cli_req_data rd;
147 5 : uint8_t *repbuf = NULL;
148 : size_t replen;
149 : int errnop;
150 : enum nss_status nret;
151 : uint32_t num_results;
152 5 : char *str = NULL;
153 : size_t data_len;
154 : uint32_t c;
155 : struct sss_nss_kv *kv_list;
156 :
157 5 : switch (cmd) {
158 : case SSS_NSS_GETSIDBYNAME:
159 : case SSS_NSS_GETNAMEBYSID:
160 : case SSS_NSS_GETIDBYSID:
161 : case SSS_NSS_GETORIGBYNAME:
162 5 : ret = sss_strnlen(inp.str, SSS_NAME_MAX, &inp_len);
163 5 : if (ret != EOK) {
164 0 : return EINVAL;
165 : }
166 :
167 5 : rd.len = inp_len + 1;
168 5 : rd.data = inp.str;
169 :
170 5 : break;
171 : case SSS_NSS_GETSIDBYID:
172 0 : rd.len = sizeof(uint32_t);
173 0 : rd.data = &inp.id;
174 :
175 0 : break;
176 : default:
177 0 : return EINVAL;
178 : }
179 :
180 5 : sss_nss_lock();
181 :
182 5 : nret = sss_nss_make_request(cmd, &rd, &repbuf, &replen, &errnop);
183 5 : if (nret != NSS_STATUS_SUCCESS) {
184 0 : ret = nss_status_to_errno(nret);
185 0 : goto done;
186 : }
187 :
188 5 : if (replen < 8) {
189 0 : ret = EBADMSG;
190 0 : goto done;
191 : }
192 :
193 5 : SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL);
194 5 : if (num_results == 0) {
195 0 : ret = ENOENT;
196 0 : goto done;
197 5 : } else if (num_results > 1) {
198 0 : ret = EBADMSG;
199 0 : goto done;
200 : }
201 :
202 : /* Skip first two 32 bit values (number of results and
203 : * reserved padding) */
204 5 : SAFEALIGN_COPY_UINT32(&out->type, repbuf + 2 * sizeof(uint32_t), NULL);
205 :
206 5 : data_len = replen - DATA_START;
207 :
208 5 : switch(cmd) {
209 : case SSS_NSS_GETSIDBYID:
210 : case SSS_NSS_GETSIDBYNAME:
211 : case SSS_NSS_GETNAMEBYSID:
212 4 : if (data_len <= 1 || repbuf[replen - 1] != '\0') {
213 0 : ret = EBADMSG;
214 0 : goto done;
215 : }
216 :
217 4 : str = malloc(sizeof(char) * data_len);
218 4 : if (str == NULL) {
219 0 : ret = ENOMEM;
220 0 : goto done;
221 : }
222 :
223 4 : strncpy(str, (char *) repbuf + DATA_START, data_len);
224 :
225 4 : out->d.str = str;
226 :
227 4 : break;
228 : case SSS_NSS_GETIDBYSID:
229 0 : if (data_len != sizeof(uint32_t)) {
230 0 : ret = EBADMSG;
231 0 : goto done;
232 : }
233 :
234 0 : SAFEALIGN_COPY_UINT32(&c, repbuf + DATA_START, NULL);
235 0 : out->d.id = c;
236 :
237 0 : break;
238 : case SSS_NSS_GETORIGBYNAME:
239 1 : ret = buf_to_kv_list(repbuf + DATA_START, data_len, &kv_list);
240 1 : if (ret != EOK) {
241 0 : goto done;
242 : }
243 :
244 1 : out->d.kv_list = kv_list;
245 :
246 1 : break;
247 : default:
248 0 : ret = EINVAL;
249 0 : goto done;
250 : }
251 :
252 5 : ret = EOK;
253 :
254 : done:
255 5 : sss_nss_unlock();
256 5 : free(repbuf);
257 5 : if (ret != EOK) {
258 0 : free(str);
259 : }
260 :
261 5 : return ret;
262 : }
263 :
264 7 : int sss_nss_getsidbyname(const char *fq_name, char **sid,
265 : enum sss_id_type *type)
266 : {
267 : int ret;
268 : union input inp;
269 : struct output out;
270 :
271 7 : if (sid == NULL || fq_name == NULL || *fq_name == '\0') {
272 3 : return EINVAL;
273 : }
274 :
275 4 : inp.str = fq_name;
276 :
277 4 : ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYNAME, &out);
278 4 : if (ret == EOK) {
279 4 : *sid = out.d.str;
280 4 : *type = out.type;
281 : }
282 :
283 4 : return ret;
284 : }
285 :
286 0 : int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type)
287 : {
288 : int ret;
289 : union input inp;
290 : struct output out;
291 :
292 0 : if (sid == NULL) {
293 0 : return EINVAL;
294 : }
295 :
296 0 : inp.id = id;
297 :
298 0 : ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYID, &out);
299 0 : if (ret == EOK) {
300 0 : *sid = out.d.str;
301 0 : *type = out.type;
302 : }
303 :
304 0 : return ret;
305 : }
306 :
307 0 : int sss_nss_getnamebysid(const char *sid, char **fq_name,
308 : enum sss_id_type *type)
309 : {
310 : int ret;
311 : union input inp;
312 : struct output out;
313 :
314 0 : if (fq_name == NULL || sid == NULL || *sid == '\0') {
315 0 : return EINVAL;
316 : }
317 :
318 0 : inp.str = sid;
319 :
320 0 : ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYSID, &out);
321 0 : if (ret == EOK) {
322 0 : *fq_name = out.d.str;
323 0 : *type = out.type;
324 : }
325 :
326 0 : return ret;
327 : }
328 :
329 0 : int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type)
330 : {
331 : int ret;
332 : union input inp;
333 : struct output out;
334 :
335 0 : if (id == NULL || id_type == NULL || sid == NULL || *sid == '\0') {
336 0 : return EINVAL;
337 : }
338 :
339 0 : inp.str = sid;
340 :
341 0 : ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETIDBYSID, &out);
342 0 : if (ret == EOK) {
343 0 : *id = out.d.id;
344 0 : *id_type = out.type;
345 : }
346 :
347 0 : return ret;
348 : }
349 :
350 1 : int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list,
351 : enum sss_id_type *type)
352 : {
353 : int ret;
354 : union input inp;
355 : struct output out;
356 :
357 1 : if (kv_list == NULL || fq_name == NULL || *fq_name == '\0') {
358 0 : return EINVAL;
359 : }
360 :
361 1 : inp.str = fq_name;
362 :
363 1 : ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETORIGBYNAME, &out);
364 1 : if (ret == EOK) {
365 1 : *kv_list = out.d.kv_list;
366 1 : *type = out.type;
367 : }
368 :
369 1 : return ret;
370 : }
|