1 /*
2 * System Security Services Daemon. NSS client interface
3 *
4 * Copyright (C) Simo Sorce 2007
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /* PASSWD database NSS interface */
22
23 #include <nss.h>
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <string.h>
30 #include "sss_cli.h"
31
32 static struct sss_nss_getpwent_data {
33 size_t len;
34 size_t ptr;
35 uint8_t *data;
36 } sss_nss_getpwent_data;
37
38 static void sss_nss_getpwent_data_clean(void) {
39
40 if (sss_nss_getpwent_data.data != NULL) {
41 free(sss_nss_getpwent_data.data);
42 sss_nss_getpwent_data.data = NULL;
43 }
44 sss_nss_getpwent_data.len = 0;
45 sss_nss_getpwent_data.ptr = 0;
46 }
47
48 /* GETPWNAM Request:
49 *
50 * 0-X: string with name
51 *
52 * GERTPWUID Request:
53 *
54 * 0-3: 32bit number with uid
55 *
56 * Replies:
57 *
58 * 0-3: 32bit unsigned number of results
59 * 4-7: 32bit unsigned (reserved/padding)
60 * For each result:
61 * 0-3: 32bit number uid
62 * 4-7: 32bit number gid
63 * 8-X: sequence of 5, 0 terminated, strings (name, passwd, gecos, dir, shell)
64 */
65
66 struct sss_nss_pw_rep {
67 struct passwd *result;
68 char *buffer;
69 size_t buflen;
70 };
71
72 static int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr,
73 uint8_t *buf, size_t *len)
74 {
75 size_t i, slen, dlen;
76 char *sbuf;
77 uint32_t c;
78
79 if (*len < 13) { /* not enough space for data, bad packet */
80 return EBADMSG;
81 }
82
83 SAFEALIGN_COPY_UINT32(&c, buf, NULL);
84 pr->result->pw_uid = c;
85 SAFEALIGN_COPY_UINT32(&c, buf+sizeof(uint32_t), NULL);
86 pr->result->pw_gid = c;
87
88 sbuf = (char *)&buf[8];
89 slen = *len - 8;
90 dlen = pr->buflen;
91
92 i = 0;
93 pr->result->pw_name = &(pr->buffer[i]);
94 while (slen > i && dlen > 0) {
95 pr->buffer[i] = sbuf[i];
96 if (pr->buffer[i] == '\0') break;
97 i++;
98 dlen--;
99 }
100 if (slen <= i) { /* premature end of buf */
101 return EBADMSG;
102 }
103 if (dlen <= 0) { /* not enough memory */
104 return ERANGE; /* not ENOMEM, ERANGE is what glibc looks for */
105 }
106 i++;
107 dlen--;
108
109 pr->result->pw_passwd = &(pr->buffer[i]);
110 while (slen > i && dlen > 0) {
111 pr->buffer[i] = sbuf[i];
112 if (pr->buffer[i] == '\0') break;
113 i++;
114 dlen--;
115 }
116 if (slen <= i) { /* premature end of buf */
117 return EBADMSG;
118 }
119 if (dlen <= 0) { /* not enough memory */
120 return ERANGE; /* not ENOMEM, ERANGE is what glibc looks for */
121 }
122 i++;
123 dlen--;
124
125 pr->result->pw_gecos = &(pr->buffer[i]);
126 while (slen > i && dlen > 0) {
127 pr->buffer[i] = sbuf[i];
128 if (pr->buffer[i] == '\0') break;
129 i++;
130 dlen--;
131 }
132 if (slen <= i) { /* premature end of buf */
133 return EBADMSG;
134 }
135 if (dlen <= 0) { /* not enough memory */
136 return ERANGE; /* not ENOMEM, ERANGE is what glibc looks for */
137 }
138 i++;
139 dlen--;
140
141 pr->result->pw_dir = &(pr->buffer[i]);
142 while (slen > i && dlen > 0) {
143 pr->buffer[i] = sbuf[i];
144 if (pr->buffer[i] == '\0') break;
145 i++;
146 dlen--;
147 }
148 if (slen <= i) { /* premature end of buf */
149 return EBADMSG;
150 }
151 if (dlen <= 0) { /* not enough memory */
152 return ERANGE; /* not ENOMEM, ERANGE is what glibc looks for */
153 }
154 i++;
155 dlen--;
156
157 pr->result->pw_shell = &(pr->buffer[i]);
158 while (slen > i && dlen > 0) {
159 pr->buffer[i] = sbuf[i];
160 if (pr->buffer[i] == '\0') break;
161 i++;
162 dlen--;
163 }
164 if (slen <= i) { /* premature end of buf */
165 return EBADMSG;
166 }
167 if (dlen <= 0) { /* not enough memory */
168 return ERANGE; /* not ENOMEM, ERANGE is what glibc looks for */
169 }
170
171 *len = slen -i -1;
172
173 return 0;
174 }
175
176 enum nss_status _nss_sss_getpwnam_r(const char *name, struct passwd *result,
177 char *buffer, size_t buflen, int *errnop)
178 {
179 struct sss_cli_req_data rd;
180 struct sss_nss_pw_rep pwrep;
181 uint8_t *repbuf;
182 size_t replen, len;
183 enum nss_status nret;
184 int ret;
185
186 /* Caught once glibc passing in buffer == 0x0 */
187 if (!buffer || !buflen) return ERANGE;
188
189 rd.len = strlen(name) + 1;
190 rd.data = name;
191
192 nret = sss_nss_make_request(SSS_NSS_GETPWNAM, &rd,
193 &repbuf, &replen, errnop);
194 if (nret != NSS_STATUS_SUCCESS) {
195 return nret;
196 }
197
198 pwrep.result = result;
199 pwrep.buffer = buffer;
200 pwrep.buflen = buflen;
201
202 /* no results if not found */
203 if (((uint32_t *)repbuf)[0] == 0) {
204 free(repbuf);
205 return NSS_STATUS_NOTFOUND;
206 }
207
208 /* only 1 result is accepted for this function */
209 if (((uint32_t *)repbuf)[0] != 1) {
210 *errnop = EBADMSG;
211 return NSS_STATUS_TRYAGAIN;
212 }
213
214 len = replen - 8;
215 ret = sss_nss_getpw_readrep(&pwrep, repbuf+8, &len);
216 free(repbuf);
217 if (ret) {
218 *errnop = ret;
219 return NSS_STATUS_TRYAGAIN;
220 }
221
222 return NSS_STATUS_SUCCESS;
223 }
224
225 enum nss_status _nss_sss_getpwuid_r(uid_t uid, struct passwd *result,
226 char *buffer, size_t buflen, int *errnop)
227 {
228 struct sss_cli_req_data rd;
229 struct sss_nss_pw_rep pwrep;
230 uint8_t *repbuf;
231 size_t replen, len;
232 enum nss_status nret;
233 uint32_t user_uid;
234 int ret;
235
236 /* Caught once glibc passing in buffer == 0x0 */
237 if (!buffer || !buflen) return ERANGE;
238
239 user_uid = uid;
240 rd.len = sizeof(uint32_t);
241 rd.data = &user_uid;
242
Event alloc_arg: Calling allocation function "sss_nss_make_request" on "repbuf". [model]
Also see events: [leaked_storage] | |
243 nret = sss_nss_make_request(SSS_NSS_GETPWUID, &rd,
244 &repbuf, &replen, errnop);
At conditional (1): "nret != 1": Taking false branch.
|
245 if (nret != NSS_STATUS_SUCCESS) {
246 return nret;
247 }
248
249 pwrep.result = result;
250 pwrep.buffer = buffer;
251 pwrep.buflen = buflen;
252
253 /* no results if not found */
At conditional (2): "(uint32_t*)repbuf[0] == 0U": Taking false branch.
|
254 if (((uint32_t *)repbuf)[0] == 0) {
255 free(repbuf);
256 return NSS_STATUS_NOTFOUND;
257 }
258
259 /* only 1 result is accepted for this function */
At conditional (3): "(uint32_t*)repbuf[0] != 1U": Taking true branch.
|
260 if (((uint32_t *)repbuf)[0] != 1) {
261 *errnop = EBADMSG;
Event leaked_storage: Variable "repbuf" going out of scope leaks the storage it points to.
Also see events: [alloc_arg] | |
262 return NSS_STATUS_TRYAGAIN;
263 }
264
265 len = replen - 8;
266 ret = sss_nss_getpw_readrep(&pwrep, repbuf+8, &len);
267 free(repbuf);
268 if (ret) {
269 *errnop = ret;
270 return NSS_STATUS_TRYAGAIN;
271 }
272
273 return NSS_STATUS_SUCCESS;
274 }
275
276 enum nss_status _nss_sss_setpwent(void)
277 {
278 enum nss_status nret;
279 int errnop;
280
281 /* make sure we do not have leftovers, and release memory */
282 sss_nss_getpwent_data_clean();
283
284 nret = sss_nss_make_request(SSS_NSS_SETPWENT,
285 NULL, NULL, NULL, &errnop);
286 if (nret != NSS_STATUS_SUCCESS) {
287 errno = errnop;
288 return nret;
289 }
290
291 return NSS_STATUS_SUCCESS;
292 }
293
294 enum nss_status _nss_sss_getpwent_r(struct passwd *result,
295 char *buffer, size_t buflen,
296 int *errnop)
297 {
298 struct sss_cli_req_data rd;
299 struct sss_nss_pw_rep pwrep;
300 uint8_t *repbuf;
301 size_t replen;
302 enum nss_status nret;
303 uint32_t num_entries;
304 int ret;
305
306 /* Caught once glibc passing in buffer == 0x0 */
307 if (!buffer || !buflen) return ERANGE;
308
309 /* if there are leftovers return the next one */
310 if (sss_nss_getpwent_data.data != NULL &&
311 sss_nss_getpwent_data.ptr < sss_nss_getpwent_data.len) {
312
313 repbuf = sss_nss_getpwent_data.data + sss_nss_getpwent_data.ptr;
314 replen = sss_nss_getpwent_data.len - sss_nss_getpwent_data.ptr;
315
316 pwrep.result = result;
317 pwrep.buffer = buffer;
318 pwrep.buflen = buflen;
319
320 ret = sss_nss_getpw_readrep(&pwrep, repbuf, &replen);
321 if (ret) {
322 *errnop = ret;
323 return NSS_STATUS_TRYAGAIN;
324 }
325
326 /* advance buffer pointer */
327 sss_nss_getpwent_data.ptr = sss_nss_getpwent_data.len - replen;
328
329 return NSS_STATUS_SUCCESS;
330 }
331
332 /* release memory if any */
333 sss_nss_getpwent_data_clean();
334
335 /* retrieve no more than SSS_NSS_MAX_ENTRIES at a time */
336 num_entries = SSS_NSS_MAX_ENTRIES;
337 rd.len = sizeof(uint32_t);
338 rd.data = &num_entries;
339
340 nret = sss_nss_make_request(SSS_NSS_GETPWENT, &rd,
341 &repbuf, &replen, errnop);
342 if (nret != NSS_STATUS_SUCCESS) {
343 return nret;
344 }
345
346 /* no results if not found */
347 if ((((uint32_t *)repbuf)[0] == 0) || (replen - 8 == 0)) {
348 free(repbuf);
349 return NSS_STATUS_NOTFOUND;
350 }
351
352 sss_nss_getpwent_data.data = repbuf;
353 sss_nss_getpwent_data.len = replen;
354 sss_nss_getpwent_data.ptr = 8; /* skip metadata fields */
355
356 /* call again ourselves, this will return the first result */
357 return _nss_sss_getpwent_r(result, buffer, buflen, errnop);
358 }
359
360 enum nss_status _nss_sss_endpwent(void)
361 {
362 enum nss_status nret;
363 int errnop;
364
365 /* make sure we do not have leftovers, and release memory */
366 sss_nss_getpwent_data_clean();
367
368 nret = sss_nss_make_request(SSS_NSS_ENDPWENT,
369 NULL, NULL, NULL, &errnop);
370 if (nret != NSS_STATUS_SUCCESS) {
371 errno = errnop;
372 return nret;
373 }
374
375 return NSS_STATUS_SUCCESS;
376 }