CVE-2013-4408:s3:Ensure LookupNames replies arrays are range checked.
[Samba.git] / lib / nss_wrapper / nss_wrapper.c
blob8767fbfd8921feadb358bf81695225f69fdf5a86
1 /*
2 * Copyright (C) Stefan Metzmacher 2007 <metze@samba.org>
3 * Copyright (C) Guenther Deschner 2009 <gd@samba.org>
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the author nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #ifdef _SAMBA_BUILD_
37 /* defining this gives us the posix getpwnam_r() calls on solaris
38 Thanks to heimdal for this */
39 #ifndef _POSIX_PTHREAD_SEMANTICS
40 #define _POSIX_PTHREAD_SEMANTICS
41 #endif
43 #define NSS_WRAPPER_NOT_REPLACE
44 #include "../replace/replace.h"
45 #include "system/passwd.h"
46 #include "system/filesys.h"
47 #include "../nsswitch/nsstest.h"
49 #else /* _SAMBA_BUILD_ */
51 #error nss_wrapper_only_supported_in_samba_yet
53 #endif
55 #ifndef _PUBLIC_
56 #define _PUBLIC_
57 #endif
59 /* not all systems have _r functions... */
60 #ifndef HAVE_GETPWNAM_R
61 #define getpwnam_r(name, pwdst, buf, buflen, pwdstp) ENOSYS
62 #endif
63 #ifndef HAVE_GETPWUID_R
64 #define getpwuid_r(uid, pwdst, buf, buflen, pwdstp) ENOSYS
65 #endif
66 #ifndef HAVE_GETPWENT_R
67 #define getpwent_r(pwdst, buf, buflen, pwdstp) ENOSYS
68 #endif
69 #ifndef HAVE_GETGRNAM_R
70 #define getgrnam_r(name, grdst, buf, buflen, grdstp) ENOSYS
71 #endif
72 #ifndef HAVE_GETGRGID_R
73 #define getgrgid_r(gid, grdst, buf, buflen, grdstp) ENOSYS
74 #endif
75 #ifndef HAVE_GETGRENT_R
76 #define getgrent_r(grdst, buf, buflen, grdstp) ENOSYS
77 #endif
79 /* not all systems have getgrouplist */
80 #ifndef HAVE_GETGROUPLIST
81 #define getgrouplist(user, group, groups, ngroups) 0
82 #endif
84 /* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
85 * for now */
86 #define REWRITE_CALLS
88 #ifdef REWRITE_CALLS
90 #define real_getpwnam getpwnam
91 #define real_getpwnam_r getpwnam_r
92 #define real_getpwuid getpwuid
93 #define real_getpwuid_r getpwuid_r
95 #define real_setpwent setpwent
96 #define real_getpwent getpwent
97 #define real_getpwent_r getpwent_r
98 #define real_endpwent endpwent
101 #define real_getgrlst getgrlst
102 #define real_getgrlst_r getgrlst_r
103 #define real_initgroups_dyn initgroups_dyn
105 #define real_initgroups initgroups
106 #define real_getgrouplist getgrouplist
108 #define real_getgrnam getgrnam
109 #define real_getgrnam_r getgrnam_r
110 #define real_getgrgid getgrgid
111 #define real_getgrgid_r getgrgid_r
113 #define real_setgrent setgrent
114 #define real_getgrent getgrent
115 #define real_getgrent_r getgrent_r
116 #define real_endgrent endgrent
118 #endif
120 #if 0
121 # ifdef DEBUG
122 # define NWRAP_ERROR(args) DEBUG(0, args)
123 # else
124 # define NWRAP_ERROR(args) printf args
125 # endif
126 #else
127 #define NWRAP_ERROR(args)
128 #endif
130 #if 0
131 # ifdef DEBUG
132 # define NWRAP_DEBUG(args) DEBUG(0, args)
133 # else
134 # define NWRAP_DEBUG(args) printf args
135 # endif
136 #else
137 #define NWRAP_DEBUG(args)
138 #endif
140 #if 0
141 # ifdef DEBUG
142 # define NWRAP_VERBOSE(args) DEBUG(0, args)
143 # else
144 # define NWRAP_VERBOSE(args) printf args
145 # endif
146 #else
147 #define NWRAP_VERBOSE(args)
148 #endif
150 struct nwrap_module_nss_fns {
151 NSS_STATUS (*_nss_getpwnam_r)(const char *name, struct passwd *result, char *buffer,
152 size_t buflen, int *errnop);
153 NSS_STATUS (*_nss_getpwuid_r)(uid_t uid, struct passwd *result, char *buffer,
154 size_t buflen, int *errnop);
155 NSS_STATUS (*_nss_setpwent)(void);
156 NSS_STATUS (*_nss_getpwent_r)(struct passwd *result, char *buffer,
157 size_t buflen, int *errnop);
158 NSS_STATUS (*_nss_endpwent)(void);
159 NSS_STATUS (*_nss_initgroups)(const char *user, gid_t group, long int *start,
160 long int *size, gid_t **groups, long int limit, int *errnop);
161 NSS_STATUS (*_nss_getgrnam_r)(const char *name, struct group *result, char *buffer,
162 size_t buflen, int *errnop);
163 NSS_STATUS (*_nss_getgrgid_r)(gid_t gid, struct group *result, char *buffer,
164 size_t buflen, int *errnop);
165 NSS_STATUS (*_nss_setgrent)(void);
166 NSS_STATUS (*_nss_getgrent_r)(struct group *result, char *buffer,
167 size_t buflen, int *errnop);
168 NSS_STATUS (*_nss_endgrent)(void);
171 struct nwrap_backend {
172 const char *name;
173 const char *so_path;
174 void *so_handle;
175 struct nwrap_ops *ops;
176 struct nwrap_module_nss_fns *fns;
179 struct nwrap_ops {
180 struct passwd * (*nw_getpwnam)(struct nwrap_backend *b,
181 const char *name);
182 int (*nw_getpwnam_r)(struct nwrap_backend *b,
183 const char *name, struct passwd *pwdst,
184 char *buf, size_t buflen, struct passwd **pwdstp);
185 struct passwd * (*nw_getpwuid)(struct nwrap_backend *b,
186 uid_t uid);
187 int (*nw_getpwuid_r)(struct nwrap_backend *b,
188 uid_t uid, struct passwd *pwdst,
189 char *buf, size_t buflen, struct passwd **pwdstp);
190 void (*nw_setpwent)(struct nwrap_backend *b);
191 struct passwd * (*nw_getpwent)(struct nwrap_backend *b);
192 int (*nw_getpwent_r)(struct nwrap_backend *b,
193 struct passwd *pwdst, char *buf,
194 size_t buflen, struct passwd **pwdstp);
195 void (*nw_endpwent)(struct nwrap_backend *b);
196 int (*nw_initgroups)(struct nwrap_backend *b,
197 const char *user, gid_t group);
198 struct group * (*nw_getgrnam)(struct nwrap_backend *b,
199 const char *name);
200 int (*nw_getgrnam_r)(struct nwrap_backend *b,
201 const char *name, struct group *grdst,
202 char *buf, size_t buflen, struct group **grdstp);
203 struct group * (*nw_getgrgid)(struct nwrap_backend *b,
204 gid_t gid);
205 int (*nw_getgrgid_r)(struct nwrap_backend *b,
206 gid_t gid, struct group *grdst,
207 char *buf, size_t buflen, struct group **grdstp);
208 void (*nw_setgrent)(struct nwrap_backend *b);
209 struct group * (*nw_getgrent)(struct nwrap_backend *b);
210 int (*nw_getgrent_r)(struct nwrap_backend *b,
211 struct group *grdst, char *buf,
212 size_t buflen, struct group **grdstp);
213 void (*nw_endgrent)(struct nwrap_backend *b);
216 /* prototypes for files backend */
219 static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
220 const char *name);
221 static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
222 const char *name, struct passwd *pwdst,
223 char *buf, size_t buflen, struct passwd **pwdstp);
224 static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
225 uid_t uid);
226 static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
227 uid_t uid, struct passwd *pwdst,
228 char *buf, size_t buflen, struct passwd **pwdstp);
229 static void nwrap_files_setpwent(struct nwrap_backend *b);
230 static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b);
231 static int nwrap_files_getpwent_r(struct nwrap_backend *b,
232 struct passwd *pwdst, char *buf,
233 size_t buflen, struct passwd **pwdstp);
234 static void nwrap_files_endpwent(struct nwrap_backend *b);
235 static int nwrap_files_initgroups(struct nwrap_backend *b,
236 const char *user, gid_t group);
237 static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
238 const char *name);
239 static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
240 const char *name, struct group *grdst,
241 char *buf, size_t buflen, struct group **grdstp);
242 static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
243 gid_t gid);
244 static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
245 gid_t gid, struct group *grdst,
246 char *buf, size_t buflen, struct group **grdstp);
247 static void nwrap_files_setgrent(struct nwrap_backend *b);
248 static struct group *nwrap_files_getgrent(struct nwrap_backend *b);
249 static int nwrap_files_getgrent_r(struct nwrap_backend *b,
250 struct group *grdst, char *buf,
251 size_t buflen, struct group **grdstp);
252 static void nwrap_files_endgrent(struct nwrap_backend *b);
254 /* prototypes for module backend */
256 static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b);
257 static int nwrap_module_getpwent_r(struct nwrap_backend *b,
258 struct passwd *pwdst, char *buf,
259 size_t buflen, struct passwd **pwdstp);
260 static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
261 const char *name);
262 static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
263 const char *name, struct passwd *pwdst,
264 char *buf, size_t buflen, struct passwd **pwdstp);
265 static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
266 uid_t uid);
267 static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
268 uid_t uid, struct passwd *pwdst,
269 char *buf, size_t buflen, struct passwd **pwdstp);
270 static void nwrap_module_setpwent(struct nwrap_backend *b);
271 static void nwrap_module_endpwent(struct nwrap_backend *b);
272 static struct group *nwrap_module_getgrent(struct nwrap_backend *b);
273 static int nwrap_module_getgrent_r(struct nwrap_backend *b,
274 struct group *grdst, char *buf,
275 size_t buflen, struct group **grdstp);
276 static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
277 const char *name);
278 static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
279 const char *name, struct group *grdst,
280 char *buf, size_t buflen, struct group **grdstp);
281 static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
282 gid_t gid);
283 static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
284 gid_t gid, struct group *grdst,
285 char *buf, size_t buflen, struct group **grdstp);
286 static void nwrap_module_setgrent(struct nwrap_backend *b);
287 static void nwrap_module_endgrent(struct nwrap_backend *b);
288 static int nwrap_module_initgroups(struct nwrap_backend *b,
289 const char *user, gid_t group);
291 struct nwrap_ops nwrap_files_ops = {
292 .nw_getpwnam = nwrap_files_getpwnam,
293 .nw_getpwnam_r = nwrap_files_getpwnam_r,
294 .nw_getpwuid = nwrap_files_getpwuid,
295 .nw_getpwuid_r = nwrap_files_getpwuid_r,
296 .nw_setpwent = nwrap_files_setpwent,
297 .nw_getpwent = nwrap_files_getpwent,
298 .nw_getpwent_r = nwrap_files_getpwent_r,
299 .nw_endpwent = nwrap_files_endpwent,
300 .nw_initgroups = nwrap_files_initgroups,
301 .nw_getgrnam = nwrap_files_getgrnam,
302 .nw_getgrnam_r = nwrap_files_getgrnam_r,
303 .nw_getgrgid = nwrap_files_getgrgid,
304 .nw_getgrgid_r = nwrap_files_getgrgid_r,
305 .nw_setgrent = nwrap_files_setgrent,
306 .nw_getgrent = nwrap_files_getgrent,
307 .nw_getgrent_r = nwrap_files_getgrent_r,
308 .nw_endgrent = nwrap_files_endgrent,
311 struct nwrap_ops nwrap_module_ops = {
312 .nw_getpwnam = nwrap_module_getpwnam,
313 .nw_getpwnam_r = nwrap_module_getpwnam_r,
314 .nw_getpwuid = nwrap_module_getpwuid,
315 .nw_getpwuid_r = nwrap_module_getpwuid_r,
316 .nw_setpwent = nwrap_module_setpwent,
317 .nw_getpwent = nwrap_module_getpwent,
318 .nw_getpwent_r = nwrap_module_getpwent_r,
319 .nw_endpwent = nwrap_module_endpwent,
320 .nw_initgroups = nwrap_module_initgroups,
321 .nw_getgrnam = nwrap_module_getgrnam,
322 .nw_getgrnam_r = nwrap_module_getgrnam_r,
323 .nw_getgrgid = nwrap_module_getgrgid,
324 .nw_getgrgid_r = nwrap_module_getgrgid_r,
325 .nw_setgrent = nwrap_module_setgrent,
326 .nw_getgrent = nwrap_module_getgrent,
327 .nw_getgrent_r = nwrap_module_getgrent_r,
328 .nw_endgrent = nwrap_module_endgrent,
331 struct nwrap_main {
332 const char *nwrap_switch;
333 int num_backends;
334 struct nwrap_backend *backends;
337 struct nwrap_main *nwrap_main_global;
338 struct nwrap_main __nwrap_main_global;
340 struct nwrap_cache {
341 const char *path;
342 int fd;
343 struct stat st;
344 uint8_t *buf;
345 void *private_data;
346 bool (*parse_line)(struct nwrap_cache *, char *line);
347 void (*unload)(struct nwrap_cache *);
350 struct nwrap_pw {
351 struct nwrap_cache *cache;
353 struct passwd *list;
354 int num;
355 int idx;
358 struct nwrap_cache __nwrap_cache_pw;
359 struct nwrap_pw nwrap_pw_global;
361 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line);
362 static void nwrap_pw_unload(struct nwrap_cache *nwrap);
364 struct nwrap_gr {
365 struct nwrap_cache *cache;
367 struct group *list;
368 int num;
369 int idx;
372 struct nwrap_cache __nwrap_cache_gr;
373 struct nwrap_gr nwrap_gr_global;
375 static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line);
376 static void nwrap_gr_unload(struct nwrap_cache *nwrap);
378 static void *nwrap_load_module_fn(struct nwrap_backend *b,
379 const char *fn_name)
381 void *res;
382 char *s;
384 if (!b->so_handle) {
385 NWRAP_ERROR(("%s: no handle\n",
386 __location__));
387 return NULL;
390 if (asprintf(&s, "_nss_%s_%s", b->name, fn_name) == -1) {
391 NWRAP_ERROR(("%s: out of memory\n",
392 __location__));
393 return NULL;
396 res = dlsym(b->so_handle, s);
397 if (!res) {
398 NWRAP_ERROR(("%s: cannot find function %s in %s\n",
399 __location__, s, b->so_path));
401 free(s);
402 s = NULL;
403 return res;
406 static struct nwrap_module_nss_fns *nwrap_load_module_fns(struct nwrap_backend *b)
408 struct nwrap_module_nss_fns *fns;
410 if (!b->so_handle) {
411 return NULL;
414 fns = (struct nwrap_module_nss_fns *)malloc(sizeof(struct nwrap_module_nss_fns));
415 if (!fns) {
416 return NULL;
419 fns->_nss_getpwnam_r = (NSS_STATUS (*)(const char *, struct passwd *, char *, size_t, int *))
420 nwrap_load_module_fn(b, "getpwnam_r");
421 fns->_nss_getpwuid_r = (NSS_STATUS (*)(uid_t, struct passwd *, char *, size_t, int *))
422 nwrap_load_module_fn(b, "getpwuid_r");
423 fns->_nss_setpwent = (NSS_STATUS(*)(void))
424 nwrap_load_module_fn(b, "setpwent");
425 fns->_nss_getpwent_r = (NSS_STATUS (*)(struct passwd *, char *, size_t, int *))
426 nwrap_load_module_fn(b, "getpwent_r");
427 fns->_nss_endpwent = (NSS_STATUS(*)(void))
428 nwrap_load_module_fn(b, "endpwent");
429 fns->_nss_initgroups = (NSS_STATUS (*)(const char *, gid_t, long int *, long int *, gid_t **, long int, int *))
430 nwrap_load_module_fn(b, "initgroups_dyn");
431 fns->_nss_getgrnam_r = (NSS_STATUS (*)(const char *, struct group *, char *, size_t, int *))
432 nwrap_load_module_fn(b, "getgrnam_r");
433 fns->_nss_getgrgid_r = (NSS_STATUS (*)(gid_t, struct group *, char *, size_t, int *))
434 nwrap_load_module_fn(b, "getgrgid_r");
435 fns->_nss_setgrent = (NSS_STATUS(*)(void))
436 nwrap_load_module_fn(b, "setgrent");
437 fns->_nss_getgrent_r = (NSS_STATUS (*)(struct group *, char *, size_t, int *))
438 nwrap_load_module_fn(b, "getgrent_r");
439 fns->_nss_endgrent = (NSS_STATUS(*)(void))
440 nwrap_load_module_fn(b, "endgrent");
442 return fns;
445 static void *nwrap_load_module(const char *so_path)
447 void *h;
449 if (!so_path || !strlen(so_path)) {
450 return NULL;
453 h = dlopen(so_path, RTLD_LAZY);
454 if (!h) {
455 NWRAP_ERROR(("%s: cannot open shared library %s\n",
456 __location__, so_path));
457 return NULL;
460 return h;
463 static bool nwrap_module_init(const char *name,
464 struct nwrap_ops *ops,
465 const char *so_path,
466 int *num_backends,
467 struct nwrap_backend **backends)
469 struct nwrap_backend *b;
471 *backends = (struct nwrap_backend *)realloc(*backends,
472 sizeof(struct nwrap_backend) * ((*num_backends) + 1));
473 if (!*backends) {
474 NWRAP_ERROR(("%s: out of memory\n",
475 __location__));
476 return false;
479 b = &((*backends)[*num_backends]);
481 b->name = name;
482 b->ops = ops;
483 b->so_path = so_path;
485 if (so_path != NULL) {
486 b->so_handle = nwrap_load_module(so_path);
487 b->fns = nwrap_load_module_fns(b);
488 if (b->fns == NULL) {
489 return false;
491 } else {
492 b->so_handle = NULL;
493 b->fns = NULL;
496 (*num_backends)++;
498 return true;
501 static void nwrap_backend_init(struct nwrap_main *r)
503 const char *winbind_so_path = getenv("NSS_WRAPPER_WINBIND_SO_PATH");
505 r->num_backends = 0;
506 r->backends = NULL;
508 if (!nwrap_module_init("files", &nwrap_files_ops, NULL,
509 &r->num_backends,
510 &r->backends)) {
511 NWRAP_ERROR(("%s: failed to initialize 'files' backend\n",
512 __location__));
513 return;
516 if (winbind_so_path && strlen(winbind_so_path)) {
517 if (!nwrap_module_init("winbind", &nwrap_module_ops, winbind_so_path,
518 &r->num_backends,
519 &r->backends)) {
520 NWRAP_ERROR(("%s: failed to initialize 'winbind' backend\n",
521 __location__));
522 return;
527 static void nwrap_init(void)
529 static bool initialized;
531 if (initialized) return;
532 initialized = true;
534 nwrap_main_global = &__nwrap_main_global;
536 nwrap_backend_init(nwrap_main_global);
538 nwrap_pw_global.cache = &__nwrap_cache_pw;
540 nwrap_pw_global.cache->path = getenv("NSS_WRAPPER_PASSWD");
541 nwrap_pw_global.cache->fd = -1;
542 nwrap_pw_global.cache->private_data = &nwrap_pw_global;
543 nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
544 nwrap_pw_global.cache->unload = nwrap_pw_unload;
546 nwrap_gr_global.cache = &__nwrap_cache_gr;
548 nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
549 nwrap_gr_global.cache->fd = -1;
550 nwrap_gr_global.cache->private_data = &nwrap_gr_global;
551 nwrap_gr_global.cache->parse_line = nwrap_gr_parse_line;
552 nwrap_gr_global.cache->unload = nwrap_gr_unload;
555 static bool nwrap_enabled(void)
557 nwrap_init();
559 if (!nwrap_pw_global.cache->path) {
560 return false;
562 if (nwrap_pw_global.cache->path[0] == '\0') {
563 return false;
565 if (!nwrap_gr_global.cache->path) {
566 return false;
568 if (nwrap_gr_global.cache->path[0] == '\0') {
569 return false;
572 return true;
575 static bool nwrap_parse_file(struct nwrap_cache *nwrap)
577 int ret;
578 uint8_t *buf = NULL;
579 char *nline;
581 if (nwrap->st.st_size == 0) {
582 NWRAP_DEBUG(("%s: size == 0\n",
583 __location__));
584 goto done;
587 if (nwrap->st.st_size > INT32_MAX) {
588 NWRAP_ERROR(("%s: size[%u] larger than INT32_MAX\n",
589 __location__, (unsigned)nwrap->st.st_size));
590 goto failed;
593 ret = lseek(nwrap->fd, 0, SEEK_SET);
594 if (ret != 0) {
595 NWRAP_ERROR(("%s: lseek - %d\n",__location__,ret));
596 goto failed;
599 buf = (uint8_t *)malloc(nwrap->st.st_size + 1);
600 if (!buf) {
601 NWRAP_ERROR(("%s: malloc failed\n",__location__));
602 goto failed;
605 ret = read(nwrap->fd, buf, nwrap->st.st_size);
606 if (ret != nwrap->st.st_size) {
607 NWRAP_ERROR(("%s: read(%u) gave %d\n",
608 __location__, (unsigned)nwrap->st.st_size, ret));
609 goto failed;
612 buf[nwrap->st.st_size] = '\0';
614 nline = (char *)buf;
615 while (nline && nline[0]) {
616 char *line;
617 char *e;
618 bool ok;
620 line = nline;
621 nline = NULL;
623 e = strchr(line, '\n');
624 if (e) {
625 e[0] = '\0';
626 e++;
627 if (e[0] == '\r') {
628 e[0] = '\0';
629 e++;
631 nline = e;
634 NWRAP_VERBOSE(("%s:'%s'\n",__location__, line));
636 if (strlen(line) == 0) {
637 continue;
640 ok = nwrap->parse_line(nwrap, line);
641 if (!ok) {
642 goto failed;
646 done:
647 nwrap->buf = buf;
648 return true;
650 failed:
651 if (buf) free(buf);
652 return false;
655 static void nwrap_files_cache_unload(struct nwrap_cache *nwrap)
657 nwrap->unload(nwrap);
659 if (nwrap->buf) free(nwrap->buf);
661 nwrap->buf = NULL;
664 static void nwrap_files_cache_reload(struct nwrap_cache *nwrap)
666 struct stat st;
667 int ret;
668 bool ok;
669 bool retried = false;
671 reopen:
672 if (nwrap->fd < 0) {
673 nwrap->fd = open(nwrap->path, O_RDONLY);
674 if (nwrap->fd < 0) {
675 NWRAP_ERROR(("%s: unable to open '%s' readonly %d:%s\n",
676 __location__,
677 nwrap->path, nwrap->fd,
678 strerror(errno)));
679 return;
681 NWRAP_VERBOSE(("%s: open '%s'\n", __location__, nwrap->path));
684 ret = fstat(nwrap->fd, &st);
685 if (ret != 0) {
686 NWRAP_ERROR(("%s: fstat(%s) - %d:%s\n",
687 __location__,
688 nwrap->path,
689 ret, strerror(errno)));
690 return;
693 if (retried == false && st.st_nlink == 0) {
694 /* maybe someone has replaced the file... */
695 NWRAP_DEBUG(("%s: st_nlink == 0, reopen %s\n",
696 __location__, nwrap->path));
697 retried = true;
698 memset(&nwrap->st, 0, sizeof(nwrap->st));
699 close(nwrap->fd);
700 nwrap->fd = -1;
701 goto reopen;
704 if (st.st_mtime == nwrap->st.st_mtime) {
705 NWRAP_VERBOSE(("%s: st_mtime[%u] hasn't changed, skip reload\n",
706 __location__, (unsigned)st.st_mtime));
707 return;
709 NWRAP_DEBUG(("%s: st_mtime has changed [%u] => [%u], start reload\n",
710 __location__, (unsigned)st.st_mtime,
711 (unsigned)nwrap->st.st_mtime));
713 nwrap->st = st;
715 nwrap_files_cache_unload(nwrap);
717 ok = nwrap_parse_file(nwrap);
718 if (!ok) {
719 NWRAP_ERROR(("%s: failed to reload %s\n",
720 __location__, nwrap->path));
721 nwrap_files_cache_unload(nwrap);
723 NWRAP_DEBUG(("%s: reloaded %s\n",
724 __location__, nwrap->path));
728 * the caller has to call nwrap_unload() on failure
730 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
732 struct nwrap_pw *nwrap_pw;
733 char *c;
734 char *p;
735 char *e;
736 struct passwd *pw;
737 size_t list_size;
739 nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
741 list_size = sizeof(*nwrap_pw->list) * (nwrap_pw->num+1);
742 pw = (struct passwd *)realloc(nwrap_pw->list, list_size);
743 if (!pw) {
744 NWRAP_ERROR(("%s:realloc(%u) failed\n",
745 __location__, list_size));
746 return false;
748 nwrap_pw->list = pw;
750 pw = &nwrap_pw->list[nwrap_pw->num];
752 c = line;
754 /* name */
755 p = strchr(c, ':');
756 if (!p) {
757 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
758 __location__, line, c));
759 return false;
761 *p = '\0';
762 p++;
763 pw->pw_name = c;
764 c = p;
766 NWRAP_VERBOSE(("name[%s]\n", pw->pw_name));
768 /* password */
769 p = strchr(c, ':');
770 if (!p) {
771 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
772 __location__, line, c));
773 return false;
775 *p = '\0';
776 p++;
777 pw->pw_passwd = c;
778 c = p;
780 NWRAP_VERBOSE(("password[%s]\n", pw->pw_passwd));
782 /* uid */
783 p = strchr(c, ':');
784 if (!p) {
785 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
786 __location__, line, c));
787 return false;
789 *p = '\0';
790 p++;
791 e = NULL;
792 pw->pw_uid = (uid_t)strtoul(c, &e, 10);
793 if (c == e) {
794 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
795 __location__, line, c, strerror(errno)));
796 return false;
798 if (e == NULL) {
799 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
800 __location__, line, c, strerror(errno)));
801 return false;
803 if (e[0] != '\0') {
804 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
805 __location__, line, c, strerror(errno)));
806 return false;
808 c = p;
810 NWRAP_VERBOSE(("uid[%u]\n", pw->pw_uid));
812 /* gid */
813 p = strchr(c, ':');
814 if (!p) {
815 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
816 __location__, line, c));
817 return false;
819 *p = '\0';
820 p++;
821 e = NULL;
822 pw->pw_gid = (gid_t)strtoul(c, &e, 10);
823 if (c == e) {
824 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
825 __location__, line, c, strerror(errno)));
826 return false;
828 if (e == NULL) {
829 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
830 __location__, line, c, strerror(errno)));
831 return false;
833 if (e[0] != '\0') {
834 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
835 __location__, line, c, strerror(errno)));
836 return false;
838 c = p;
840 NWRAP_VERBOSE(("gid[%u]\n", pw->pw_gid));
842 /* gecos */
843 p = strchr(c, ':');
844 if (!p) {
845 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
846 __location__, line, c));
847 return false;
849 *p = '\0';
850 p++;
851 pw->pw_gecos = c;
852 c = p;
854 NWRAP_VERBOSE(("gecos[%s]\n", pw->pw_gecos));
856 /* dir */
857 p = strchr(c, ':');
858 if (!p) {
859 NWRAP_ERROR(("%s:'%s'\n",__location__,c));
860 return false;
862 *p = '\0';
863 p++;
864 pw->pw_dir = c;
865 c = p;
867 NWRAP_VERBOSE(("dir[%s]\n", pw->pw_dir));
869 /* shell */
870 pw->pw_shell = c;
871 NWRAP_VERBOSE(("shell[%s]\n", pw->pw_shell));
873 NWRAP_DEBUG(("add user[%s:%s:%u:%u:%s:%s:%s]\n",
874 pw->pw_name, pw->pw_passwd,
875 pw->pw_uid, pw->pw_gid,
876 pw->pw_gecos, pw->pw_dir, pw->pw_shell));
878 nwrap_pw->num++;
879 return true;
882 static void nwrap_pw_unload(struct nwrap_cache *nwrap)
884 struct nwrap_pw *nwrap_pw;
885 nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
887 if (nwrap_pw->list) free(nwrap_pw->list);
889 nwrap_pw->list = NULL;
890 nwrap_pw->num = 0;
891 nwrap_pw->idx = 0;
894 static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
895 char *buf, size_t buflen, struct passwd **dstp)
897 char *first;
898 char *last;
899 off_t ofs;
901 first = src->pw_name;
903 last = src->pw_shell;
904 while (*last) last++;
906 ofs = PTR_DIFF(last + 1, first);
908 if (ofs > buflen) {
909 return ERANGE;
912 memcpy(buf, first, ofs);
914 ofs = PTR_DIFF(src->pw_name, first);
915 dst->pw_name = buf + ofs;
916 ofs = PTR_DIFF(src->pw_passwd, first);
917 dst->pw_passwd = buf + ofs;
918 dst->pw_uid = src->pw_uid;
919 dst->pw_gid = src->pw_gid;
920 ofs = PTR_DIFF(src->pw_gecos, first);
921 dst->pw_gecos = buf + ofs;
922 ofs = PTR_DIFF(src->pw_dir, first);
923 dst->pw_dir = buf + ofs;
924 ofs = PTR_DIFF(src->pw_shell, first);
925 dst->pw_shell = buf + ofs;
927 if (dstp) {
928 *dstp = dst;
931 return 0;
935 * the caller has to call nwrap_unload() on failure
937 static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
939 struct nwrap_gr *nwrap_gr;
940 char *c;
941 char *p;
942 char *e;
943 struct group *gr;
944 size_t list_size;
945 unsigned nummem;
947 nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
949 list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
950 gr = (struct group *)realloc(nwrap_gr->list, list_size);
951 if (!gr) {
952 NWRAP_ERROR(("%s:realloc failed\n",__location__));
953 return false;
955 nwrap_gr->list = gr;
957 gr = &nwrap_gr->list[nwrap_gr->num];
959 c = line;
961 /* name */
962 p = strchr(c, ':');
963 if (!p) {
964 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
965 __location__, line, c));
966 return false;
968 *p = '\0';
969 p++;
970 gr->gr_name = c;
971 c = p;
973 NWRAP_VERBOSE(("name[%s]\n", gr->gr_name));
975 /* password */
976 p = strchr(c, ':');
977 if (!p) {
978 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
979 __location__, line, c));
980 return false;
982 *p = '\0';
983 p++;
984 gr->gr_passwd = c;
985 c = p;
987 NWRAP_VERBOSE(("password[%s]\n", gr->gr_passwd));
989 /* gid */
990 p = strchr(c, ':');
991 if (!p) {
992 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
993 __location__, line, c));
994 return false;
996 *p = '\0';
997 p++;
998 e = NULL;
999 gr->gr_gid = (gid_t)strtoul(c, &e, 10);
1000 if (c == e) {
1001 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
1002 __location__, line, c, strerror(errno)));
1003 return false;
1005 if (e == NULL) {
1006 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
1007 __location__, line, c, strerror(errno)));
1008 return false;
1010 if (e[0] != '\0') {
1011 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
1012 __location__, line, c, strerror(errno)));
1013 return false;
1015 c = p;
1017 NWRAP_VERBOSE(("gid[%u]\n", gr->gr_gid));
1019 /* members */
1020 gr->gr_mem = (char **)malloc(sizeof(char *));
1021 if (!gr->gr_mem) {
1022 NWRAP_ERROR(("%s:calloc failed\n",__location__));
1023 return false;
1025 gr->gr_mem[0] = NULL;
1027 for(nummem=0; p; nummem++) {
1028 char **m;
1029 size_t m_size;
1030 c = p;
1031 p = strchr(c, ',');
1032 if (p) {
1033 *p = '\0';
1034 p++;
1037 if (strlen(c) == 0) {
1038 break;
1041 m_size = sizeof(char *) * (nummem+2);
1042 m = (char **)realloc(gr->gr_mem, m_size);
1043 if (!m) {
1044 NWRAP_ERROR(("%s:realloc(%u) failed\n",
1045 __location__, m_size));
1046 return false;
1048 gr->gr_mem = m;
1049 gr->gr_mem[nummem] = c;
1050 gr->gr_mem[nummem+1] = NULL;
1052 NWRAP_VERBOSE(("member[%u]: '%s'\n", nummem, gr->gr_mem[nummem]));
1055 NWRAP_DEBUG(("add group[%s:%s:%u:] with %u members\n",
1056 gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem));
1058 nwrap_gr->num++;
1059 return true;
1062 static void nwrap_gr_unload(struct nwrap_cache *nwrap)
1064 int i;
1065 struct nwrap_gr *nwrap_gr;
1066 nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
1068 if (nwrap_gr->list) {
1069 for (i=0; i < nwrap_gr->num; i++) {
1070 if (nwrap_gr->list[i].gr_mem) {
1071 free(nwrap_gr->list[i].gr_mem);
1074 free(nwrap_gr->list);
1077 nwrap_gr->list = NULL;
1078 nwrap_gr->num = 0;
1079 nwrap_gr->idx = 0;
1082 static int nwrap_gr_copy_r(const struct group *src, struct group *dst,
1083 char *buf, size_t buflen, struct group **dstp)
1085 char *first;
1086 char **lastm;
1087 char *last = NULL;
1088 off_t ofsb;
1089 off_t ofsm;
1090 off_t ofs;
1091 unsigned i;
1093 first = src->gr_name;
1095 lastm = src->gr_mem;
1096 while (*lastm) {
1097 last = *lastm;
1098 lastm++;
1101 if (last == NULL) {
1102 last = src->gr_passwd;
1104 while (*last) last++;
1106 ofsb = PTR_DIFF(last + 1, first);
1107 ofsm = PTR_DIFF(lastm + 1, src->gr_mem);
1109 if ((ofsb + ofsm) > buflen) {
1110 return ERANGE;
1113 memcpy(buf, first, ofsb);
1114 memcpy(buf + ofsb, src->gr_mem, ofsm);
1116 ofs = PTR_DIFF(src->gr_name, first);
1117 dst->gr_name = buf + ofs;
1118 ofs = PTR_DIFF(src->gr_passwd, first);
1119 dst->gr_passwd = buf + ofs;
1120 dst->gr_gid = src->gr_gid;
1122 dst->gr_mem = (char **)(buf + ofsb);
1123 for (i=0; src->gr_mem[i]; i++) {
1124 ofs = PTR_DIFF(src->gr_mem[i], first);
1125 dst->gr_mem[i] = buf + ofs;
1128 if (dstp) {
1129 *dstp = dst;
1132 return 0;
1135 /* user functions */
1136 static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
1137 const char *name)
1139 int i;
1141 nwrap_files_cache_reload(nwrap_pw_global.cache);
1143 for (i=0; i<nwrap_pw_global.num; i++) {
1144 if (strcmp(nwrap_pw_global.list[i].pw_name, name) == 0) {
1145 NWRAP_DEBUG(("%s: user[%s] found\n",
1146 __location__, name));
1147 return &nwrap_pw_global.list[i];
1149 NWRAP_VERBOSE(("%s: user[%s] does not match [%s]\n",
1150 __location__, name,
1151 nwrap_pw_global.list[i].pw_name));
1154 NWRAP_DEBUG(("%s: user[%s] not found\n", __location__, name));
1156 errno = ENOENT;
1157 return NULL;
1160 static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
1161 const char *name, struct passwd *pwdst,
1162 char *buf, size_t buflen, struct passwd **pwdstp)
1164 struct passwd *pw;
1166 pw = nwrap_files_getpwnam(b, name);
1167 if (!pw) {
1168 if (errno == 0) {
1169 return ENOENT;
1171 return errno;
1174 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
1177 static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
1178 uid_t uid)
1180 int i;
1182 nwrap_files_cache_reload(nwrap_pw_global.cache);
1184 for (i=0; i<nwrap_pw_global.num; i++) {
1185 if (nwrap_pw_global.list[i].pw_uid == uid) {
1186 NWRAP_DEBUG(("%s: uid[%u] found\n",
1187 __location__, uid));
1188 return &nwrap_pw_global.list[i];
1190 NWRAP_VERBOSE(("%s: uid[%u] does not match [%u]\n",
1191 __location__, uid,
1192 nwrap_pw_global.list[i].pw_uid));
1195 NWRAP_DEBUG(("%s: uid[%u] not found\n", __location__, uid));
1197 errno = ENOENT;
1198 return NULL;
1201 static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
1202 uid_t uid, struct passwd *pwdst,
1203 char *buf, size_t buflen, struct passwd **pwdstp)
1205 struct passwd *pw;
1207 pw = nwrap_files_getpwuid(b, uid);
1208 if (!pw) {
1209 if (errno == 0) {
1210 return ENOENT;
1212 return errno;
1215 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
1218 /* user enum functions */
1219 static void nwrap_files_setpwent(struct nwrap_backend *b)
1221 nwrap_pw_global.idx = 0;
1224 static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b)
1226 struct passwd *pw;
1228 if (nwrap_pw_global.idx == 0) {
1229 nwrap_files_cache_reload(nwrap_pw_global.cache);
1232 if (nwrap_pw_global.idx >= nwrap_pw_global.num) {
1233 errno = ENOENT;
1234 return NULL;
1237 pw = &nwrap_pw_global.list[nwrap_pw_global.idx++];
1239 NWRAP_VERBOSE(("%s: return user[%s] uid[%u]\n",
1240 __location__, pw->pw_name, pw->pw_uid));
1242 return pw;
1245 static int nwrap_files_getpwent_r(struct nwrap_backend *b,
1246 struct passwd *pwdst, char *buf,
1247 size_t buflen, struct passwd **pwdstp)
1249 struct passwd *pw;
1251 pw = nwrap_files_getpwent(b);
1252 if (!pw) {
1253 if (errno == 0) {
1254 return ENOENT;
1256 return errno;
1259 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
1262 static void nwrap_files_endpwent(struct nwrap_backend *b)
1264 nwrap_pw_global.idx = 0;
1267 /* misc functions */
1268 static int nwrap_files_initgroups(struct nwrap_backend *b,
1269 const char *user, gid_t group)
1271 /* TODO: maybe we should also fake this... */
1272 return EPERM;
1275 /* group functions */
1276 static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
1277 const char *name)
1279 int i;
1281 nwrap_files_cache_reload(nwrap_gr_global.cache);
1283 for (i=0; i<nwrap_gr_global.num; i++) {
1284 if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) {
1285 NWRAP_DEBUG(("%s: group[%s] found\n",
1286 __location__, name));
1287 return &nwrap_gr_global.list[i];
1289 NWRAP_VERBOSE(("%s: group[%s] does not match [%s]\n",
1290 __location__, name,
1291 nwrap_gr_global.list[i].gr_name));
1294 NWRAP_DEBUG(("%s: group[%s] not found\n", __location__, name));
1296 errno = ENOENT;
1297 return NULL;
1300 static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
1301 const char *name, struct group *grdst,
1302 char *buf, size_t buflen, struct group **grdstp)
1304 struct group *gr;
1306 gr = nwrap_files_getgrnam(b, name);
1307 if (!gr) {
1308 if (errno == 0) {
1309 return ENOENT;
1311 return errno;
1314 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
1317 static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
1318 gid_t gid)
1320 int i;
1322 nwrap_files_cache_reload(nwrap_gr_global.cache);
1324 for (i=0; i<nwrap_gr_global.num; i++) {
1325 if (nwrap_gr_global.list[i].gr_gid == gid) {
1326 NWRAP_DEBUG(("%s: gid[%u] found\n",
1327 __location__, gid));
1328 return &nwrap_gr_global.list[i];
1330 NWRAP_VERBOSE(("%s: gid[%u] does not match [%u]\n",
1331 __location__, gid,
1332 nwrap_gr_global.list[i].gr_gid));
1335 NWRAP_DEBUG(("%s: gid[%u] not found\n", __location__, gid));
1337 errno = ENOENT;
1338 return NULL;
1341 static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
1342 gid_t gid, struct group *grdst,
1343 char *buf, size_t buflen, struct group **grdstp)
1345 struct group *gr;
1347 gr = nwrap_files_getgrgid(b, gid);
1348 if (!gr) {
1349 if (errno == 0) {
1350 return ENOENT;
1352 return errno;
1355 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
1358 /* group enum functions */
1359 static void nwrap_files_setgrent(struct nwrap_backend *b)
1361 nwrap_gr_global.idx = 0;
1364 static struct group *nwrap_files_getgrent(struct nwrap_backend *b)
1366 struct group *gr;
1368 if (nwrap_gr_global.idx == 0) {
1369 nwrap_files_cache_reload(nwrap_gr_global.cache);
1372 if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
1373 errno = ENOENT;
1374 return NULL;
1377 gr = &nwrap_gr_global.list[nwrap_gr_global.idx++];
1379 NWRAP_VERBOSE(("%s: return group[%s] gid[%u]\n",
1380 __location__, gr->gr_name, gr->gr_gid));
1382 return gr;
1385 static int nwrap_files_getgrent_r(struct nwrap_backend *b,
1386 struct group *grdst, char *buf,
1387 size_t buflen, struct group **grdstp)
1389 struct group *gr;
1391 gr = nwrap_files_getgrent(b);
1392 if (!gr) {
1393 if (errno == 0) {
1394 return ENOENT;
1396 return errno;
1399 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
1402 static void nwrap_files_endgrent(struct nwrap_backend *b)
1404 nwrap_gr_global.idx = 0;
1408 * module backend
1411 #ifndef SAFE_FREE
1412 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
1413 #endif
1415 static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
1416 const char *name)
1418 static struct passwd pwd;
1419 static char buf[1000];
1420 NSS_STATUS status;
1422 if (!b->fns->_nss_getpwnam_r) {
1423 return NULL;
1426 status = b->fns->_nss_getpwnam_r(name, &pwd, buf, sizeof(buf), &errno);
1427 if (status == NSS_STATUS_NOTFOUND) {
1428 return NULL;
1430 if (status != NSS_STATUS_SUCCESS) {
1431 return NULL;
1433 return &pwd;
1436 static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
1437 const char *name, struct passwd *pwdst,
1438 char *buf, size_t buflen, struct passwd **pwdstp)
1440 int ret;
1442 if (!b->fns->_nss_getpwnam_r) {
1443 return NSS_STATUS_NOTFOUND;
1446 ret = b->fns->_nss_getpwnam_r(name, pwdst, buf, buflen, &errno);
1447 switch (ret) {
1448 case NSS_STATUS_SUCCESS:
1449 return 0;
1450 case NSS_STATUS_NOTFOUND:
1451 if (errno != 0) {
1452 return errno;
1454 return ENOENT;
1455 case NSS_STATUS_TRYAGAIN:
1456 if (errno != 0) {
1457 return errno;
1459 return ERANGE;
1460 default:
1461 if (errno != 0) {
1462 return errno;
1464 return ret;
1468 static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
1469 uid_t uid)
1471 static struct passwd pwd;
1472 static char buf[1000];
1473 NSS_STATUS status;
1475 if (!b->fns->_nss_getpwuid_r) {
1476 return NULL;
1479 status = b->fns->_nss_getpwuid_r(uid, &pwd, buf, sizeof(buf), &errno);
1480 if (status == NSS_STATUS_NOTFOUND) {
1481 return NULL;
1483 if (status != NSS_STATUS_SUCCESS) {
1484 return NULL;
1486 return &pwd;
1489 static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
1490 uid_t uid, struct passwd *pwdst,
1491 char *buf, size_t buflen, struct passwd **pwdstp)
1493 int ret;
1495 if (!b->fns->_nss_getpwuid_r) {
1496 return ENOENT;
1499 ret = b->fns->_nss_getpwuid_r(uid, pwdst, buf, buflen, &errno);
1500 switch (ret) {
1501 case NSS_STATUS_SUCCESS:
1502 return 0;
1503 case NSS_STATUS_NOTFOUND:
1504 if (errno != 0) {
1505 return errno;
1507 return ENOENT;
1508 case NSS_STATUS_TRYAGAIN:
1509 if (errno != 0) {
1510 return errno;
1512 return ERANGE;
1513 default:
1514 if (errno != 0) {
1515 return errno;
1517 return ret;
1521 static void nwrap_module_setpwent(struct nwrap_backend *b)
1523 if (!b->fns->_nss_setpwent) {
1524 return;
1527 b->fns->_nss_setpwent();
1530 static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b)
1532 static struct passwd pwd;
1533 static char buf[1000];
1534 NSS_STATUS status;
1536 if (!b->fns->_nss_getpwent_r) {
1537 return NULL;
1540 status = b->fns->_nss_getpwent_r(&pwd, buf, sizeof(buf), &errno);
1541 if (status == NSS_STATUS_NOTFOUND) {
1542 return NULL;
1544 if (status != NSS_STATUS_SUCCESS) {
1545 return NULL;
1547 return &pwd;
1550 static int nwrap_module_getpwent_r(struct nwrap_backend *b,
1551 struct passwd *pwdst, char *buf,
1552 size_t buflen, struct passwd **pwdstp)
1554 int ret;
1556 if (!b->fns->_nss_getpwent_r) {
1557 return ENOENT;
1560 ret = b->fns->_nss_getpwent_r(pwdst, buf, buflen, &errno);
1561 switch (ret) {
1562 case NSS_STATUS_SUCCESS:
1563 return 0;
1564 case NSS_STATUS_NOTFOUND:
1565 if (errno != 0) {
1566 return errno;
1568 return ENOENT;
1569 case NSS_STATUS_TRYAGAIN:
1570 if (errno != 0) {
1571 return errno;
1573 return ERANGE;
1574 default:
1575 if (errno != 0) {
1576 return errno;
1578 return ret;
1582 static void nwrap_module_endpwent(struct nwrap_backend *b)
1584 if (!b->fns->_nss_endpwent) {
1585 return;
1588 b->fns->_nss_endpwent();
1591 static int nwrap_module_initgroups(struct nwrap_backend *b,
1592 const char *user, gid_t group)
1594 gid_t *groups;
1595 long int start;
1596 long int size;
1598 if (!b->fns->_nss_initgroups) {
1599 return NSS_STATUS_UNAVAIL;
1602 return b->fns->_nss_initgroups(user, group, &start, &size, &groups, 0, &errno);
1605 static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
1606 const char *name)
1608 static struct group grp;
1609 static char *buf;
1610 static int buflen = 1000;
1611 NSS_STATUS status;
1613 if (!b->fns->_nss_getgrnam_r) {
1614 return NULL;
1617 if (!buf) {
1618 buf = (char *)malloc(buflen);
1620 again:
1621 status = b->fns->_nss_getgrnam_r(name, &grp, buf, buflen, &errno);
1622 if (status == NSS_STATUS_TRYAGAIN) {
1623 buflen *= 2;
1624 buf = (char *)realloc(buf, buflen);
1625 if (!buf) {
1626 return NULL;
1628 goto again;
1630 if (status == NSS_STATUS_NOTFOUND) {
1631 SAFE_FREE(buf);
1632 return NULL;
1634 if (status != NSS_STATUS_SUCCESS) {
1635 SAFE_FREE(buf);
1636 return NULL;
1638 return &grp;
1641 static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
1642 const char *name, struct group *grdst,
1643 char *buf, size_t buflen, struct group **grdstp)
1645 int ret;
1647 if (!b->fns->_nss_getgrnam_r) {
1648 return ENOENT;
1651 ret = b->fns->_nss_getgrnam_r(name, grdst, buf, buflen, &errno);
1652 switch (ret) {
1653 case NSS_STATUS_SUCCESS:
1654 return 0;
1655 case NSS_STATUS_NOTFOUND:
1656 if (errno != 0) {
1657 return errno;
1659 return ENOENT;
1660 case NSS_STATUS_TRYAGAIN:
1661 if (errno != 0) {
1662 return errno;
1664 return ERANGE;
1665 default:
1666 if (errno != 0) {
1667 return errno;
1669 return ret;
1673 static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
1674 gid_t gid)
1676 static struct group grp;
1677 static char *buf;
1678 static int buflen = 1000;
1679 NSS_STATUS status;
1681 if (!b->fns->_nss_getgrgid_r) {
1682 return NULL;
1685 if (!buf) {
1686 buf = (char *)malloc(buflen);
1689 again:
1690 status = b->fns->_nss_getgrgid_r(gid, &grp, buf, buflen, &errno);
1691 if (status == NSS_STATUS_TRYAGAIN) {
1692 buflen *= 2;
1693 buf = (char *)realloc(buf, buflen);
1694 if (!buf) {
1695 return NULL;
1697 goto again;
1699 if (status == NSS_STATUS_NOTFOUND) {
1700 SAFE_FREE(buf);
1701 return NULL;
1703 if (status != NSS_STATUS_SUCCESS) {
1704 SAFE_FREE(buf);
1705 return NULL;
1707 return &grp;
1710 static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
1711 gid_t gid, struct group *grdst,
1712 char *buf, size_t buflen, struct group **grdstp)
1714 int ret;
1716 if (!b->fns->_nss_getgrgid_r) {
1717 return ENOENT;
1720 ret = b->fns->_nss_getgrgid_r(gid, grdst, buf, buflen, &errno);
1721 switch (ret) {
1722 case NSS_STATUS_SUCCESS:
1723 return 0;
1724 case NSS_STATUS_NOTFOUND:
1725 if (errno != 0) {
1726 return errno;
1728 return ENOENT;
1729 case NSS_STATUS_TRYAGAIN:
1730 if (errno != 0) {
1731 return errno;
1733 return ERANGE;
1734 default:
1735 if (errno != 0) {
1736 return errno;
1738 return ret;
1742 static void nwrap_module_setgrent(struct nwrap_backend *b)
1744 if (!b->fns->_nss_setgrent) {
1745 return;
1748 b->fns->_nss_setgrent();
1751 static struct group *nwrap_module_getgrent(struct nwrap_backend *b)
1753 static struct group grp;
1754 static char *buf;
1755 static int buflen = 1024;
1756 NSS_STATUS status;
1758 if (!b->fns->_nss_getgrent_r) {
1759 return NULL;
1762 if (!buf) {
1763 buf = (char *)malloc(buflen);
1766 again:
1767 status = b->fns->_nss_getgrent_r(&grp, buf, buflen, &errno);
1768 if (status == NSS_STATUS_TRYAGAIN) {
1769 buflen *= 2;
1770 buf = (char *)realloc(buf, buflen);
1771 if (!buf) {
1772 return NULL;
1774 goto again;
1776 if (status == NSS_STATUS_NOTFOUND) {
1777 SAFE_FREE(buf);
1778 return NULL;
1780 if (status != NSS_STATUS_SUCCESS) {
1781 SAFE_FREE(buf);
1782 return NULL;
1784 return &grp;
1787 static int nwrap_module_getgrent_r(struct nwrap_backend *b,
1788 struct group *grdst, char *buf,
1789 size_t buflen, struct group **grdstp)
1791 int ret;
1793 if (!b->fns->_nss_getgrent_r) {
1794 return ENOENT;
1797 ret = b->fns->_nss_getgrent_r(grdst, buf, buflen, &errno);
1798 switch (ret) {
1799 case NSS_STATUS_SUCCESS:
1800 return 0;
1801 case NSS_STATUS_NOTFOUND:
1802 if (errno != 0) {
1803 return errno;
1805 return ENOENT;
1806 case NSS_STATUS_TRYAGAIN:
1807 if (errno != 0) {
1808 return errno;
1810 return ERANGE;
1811 default:
1812 if (errno != 0) {
1813 return errno;
1815 return ret;
1819 static void nwrap_module_endgrent(struct nwrap_backend *b)
1821 if (!b->fns->_nss_endgrent) {
1822 return;
1825 b->fns->_nss_endgrent();
1829 * PUBLIC interface
1832 _PUBLIC_ struct passwd *nwrap_getpwnam(const char *name)
1834 int i;
1835 struct passwd *pwd;
1837 if (!nwrap_enabled()) {
1838 return real_getpwnam(name);
1841 for (i=0; i < nwrap_main_global->num_backends; i++) {
1842 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1843 pwd = b->ops->nw_getpwnam(b, name);
1844 if (pwd) {
1845 return pwd;
1849 return NULL;
1852 _PUBLIC_ int nwrap_getpwnam_r(const char *name, struct passwd *pwdst,
1853 char *buf, size_t buflen, struct passwd **pwdstp)
1855 int i,ret;
1857 if (!nwrap_enabled()) {
1858 return real_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
1861 for (i=0; i < nwrap_main_global->num_backends; i++) {
1862 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1863 ret = b->ops->nw_getpwnam_r(b, name, pwdst, buf, buflen, pwdstp);
1864 if (ret == ENOENT) {
1865 continue;
1867 return ret;
1870 return ENOENT;
1873 _PUBLIC_ struct passwd *nwrap_getpwuid(uid_t uid)
1875 int i;
1876 struct passwd *pwd;
1878 if (!nwrap_enabled()) {
1879 return real_getpwuid(uid);
1882 for (i=0; i < nwrap_main_global->num_backends; i++) {
1883 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1884 pwd = b->ops->nw_getpwuid(b, uid);
1885 if (pwd) {
1886 return pwd;
1890 return NULL;
1893 _PUBLIC_ int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst,
1894 char *buf, size_t buflen, struct passwd **pwdstp)
1896 int i,ret;
1898 if (!nwrap_enabled()) {
1899 return real_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
1902 for (i=0; i < nwrap_main_global->num_backends; i++) {
1903 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1904 ret = b->ops->nw_getpwuid_r(b, uid, pwdst, buf, buflen, pwdstp);
1905 if (ret == ENOENT) {
1906 continue;
1908 return ret;
1911 return ENOENT;
1914 _PUBLIC_ void nwrap_setpwent(void)
1916 int i;
1918 if (!nwrap_enabled()) {
1919 real_setpwent();
1920 return;
1923 for (i=0; i < nwrap_main_global->num_backends; i++) {
1924 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1925 b->ops->nw_setpwent(b);
1929 _PUBLIC_ struct passwd *nwrap_getpwent(void)
1931 int i;
1932 struct passwd *pwd;
1934 if (!nwrap_enabled()) {
1935 return real_getpwent();
1938 for (i=0; i < nwrap_main_global->num_backends; i++) {
1939 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1940 pwd = b->ops->nw_getpwent(b);
1941 if (pwd) {
1942 return pwd;
1946 return NULL;
1949 _PUBLIC_ int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
1950 size_t buflen, struct passwd **pwdstp)
1952 int i,ret;
1954 if (!nwrap_enabled()) {
1955 #ifdef SOLARIS_GETPWENT_R
1956 struct passwd *pw;
1957 pw = real_getpwent_r(pwdst, buf, buflen);
1958 if (!pw) {
1959 if (errno == 0) {
1960 return ENOENT;
1962 return errno;
1964 if (pwdstp) {
1965 *pwdstp = pw;
1967 return 0;
1968 #else
1969 return real_getpwent_r(pwdst, buf, buflen, pwdstp);
1970 #endif
1973 for (i=0; i < nwrap_main_global->num_backends; i++) {
1974 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1975 ret = b->ops->nw_getpwent_r(b, pwdst, buf, buflen, pwdstp);
1976 if (ret == ENOENT) {
1977 continue;
1979 return ret;
1982 return ENOENT;
1985 _PUBLIC_ void nwrap_endpwent(void)
1987 int i;
1989 if (!nwrap_enabled()) {
1990 real_endpwent();
1991 return;
1994 for (i=0; i < nwrap_main_global->num_backends; i++) {
1995 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1996 b->ops->nw_endpwent(b);
2000 _PUBLIC_ int nwrap_initgroups(const char *user, gid_t group)
2002 int i;
2004 if (!nwrap_enabled()) {
2005 return real_initgroups(user, group);
2008 for (i=0; i < nwrap_main_global->num_backends; i++) {
2009 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2010 return b->ops->nw_initgroups(b, user, group);
2013 errno = ENOENT;
2014 return -1;
2017 _PUBLIC_ struct group *nwrap_getgrnam(const char *name)
2019 int i;
2020 struct group *grp;
2022 if (!nwrap_enabled()) {
2023 return real_getgrnam(name);
2026 for (i=0; i < nwrap_main_global->num_backends; i++) {
2027 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2028 grp = b->ops->nw_getgrnam(b, name);
2029 if (grp) {
2030 return grp;
2034 return NULL;
2037 _PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *grdst,
2038 char *buf, size_t buflen, struct group **grdstp)
2040 int i,ret;
2042 if (!nwrap_enabled()) {
2043 return real_getgrnam_r(name, grdst, buf, buflen, grdstp);
2046 for (i=0; i < nwrap_main_global->num_backends; i++) {
2047 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2048 ret = b->ops->nw_getgrnam_r(b, name, grdst, buf, buflen, grdstp);
2049 if (ret == ENOENT) {
2050 continue;
2052 return ret;
2055 return ENOENT;
2058 _PUBLIC_ struct group *nwrap_getgrgid(gid_t gid)
2060 int i;
2061 struct group *grp;
2063 if (!nwrap_enabled()) {
2064 return real_getgrgid(gid);
2067 for (i=0; i < nwrap_main_global->num_backends; i++) {
2068 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2069 grp = b->ops->nw_getgrgid(b, gid);
2070 if (grp) {
2071 return grp;
2075 return NULL;
2078 _PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *grdst,
2079 char *buf, size_t buflen, struct group **grdstp)
2081 int i,ret;
2083 if (!nwrap_enabled()) {
2084 return real_getgrgid_r(gid, grdst, buf, buflen, grdstp);
2087 for (i=0; i < nwrap_main_global->num_backends; i++) {
2088 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2089 ret = b->ops->nw_getgrgid_r(b, gid, grdst, buf, buflen, grdstp);
2090 if (ret == ENOENT) {
2091 continue;
2093 return ret;
2096 return ENOENT;
2099 _PUBLIC_ void nwrap_setgrent(void)
2101 int i;
2103 if (!nwrap_enabled()) {
2104 real_setgrent();
2105 return;
2108 for (i=0; i < nwrap_main_global->num_backends; i++) {
2109 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2110 b->ops->nw_setgrent(b);
2114 _PUBLIC_ struct group *nwrap_getgrent(void)
2116 int i;
2117 struct group *grp;
2119 if (!nwrap_enabled()) {
2120 return real_getgrent();
2123 for (i=0; i < nwrap_main_global->num_backends; i++) {
2124 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2125 grp = b->ops->nw_getgrent(b);
2126 if (grp) {
2127 return grp;
2131 return NULL;
2134 _PUBLIC_ int nwrap_getgrent_r(struct group *grdst, char *buf,
2135 size_t buflen, struct group **grdstp)
2137 int i,ret;
2139 if (!nwrap_enabled()) {
2140 #ifdef SOLARIS_GETGRENT_R
2141 struct group *gr;
2142 gr = real_getgrent_r(grdst, buf, buflen);
2143 if (!gr) {
2144 if (errno == 0) {
2145 return ENOENT;
2147 return errno;
2149 if (grdstp) {
2150 *grdstp = gr;
2152 return 0;
2153 #else
2154 return real_getgrent_r(grdst, buf, buflen, grdstp);
2155 #endif
2158 for (i=0; i < nwrap_main_global->num_backends; i++) {
2159 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2160 ret = b->ops->nw_getgrent_r(b, grdst, buf, buflen, grdstp);
2161 if (ret == ENOENT) {
2162 continue;
2164 return ret;
2167 return ENOENT;
2170 _PUBLIC_ void nwrap_endgrent(void)
2172 int i;
2174 if (!nwrap_enabled()) {
2175 real_endgrent();
2176 return;
2179 for (i=0; i < nwrap_main_global->num_backends; i++) {
2180 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2181 b->ops->nw_endgrent(b);
2185 _PUBLIC_ int nwrap_getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
2187 struct group *grp;
2188 gid_t *groups_tmp;
2189 int count = 1;
2190 const char *name_of_group = "";
2192 if (!nwrap_enabled()) {
2193 return real_getgrouplist(user, group, groups, ngroups);
2196 NWRAP_DEBUG(("%s: getgrouplist called for %s\n", __location__, user));
2198 groups_tmp = (gid_t *)malloc(count * sizeof(gid_t));
2199 if (!groups_tmp) {
2200 NWRAP_ERROR(("%s:calloc failed\n",__location__));
2201 errno = ENOMEM;
2202 return -1;
2205 memcpy(groups_tmp, &group, sizeof(gid_t));
2207 grp = nwrap_getgrgid(group);
2208 if (grp) {
2209 name_of_group = grp->gr_name;
2212 nwrap_setgrent();
2213 while ((grp = nwrap_getgrent()) != NULL) {
2214 int i = 0;
2216 NWRAP_VERBOSE(("%s: inspecting %s for group membership\n",
2217 __location__, grp->gr_name));
2219 for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
2221 if ((strcmp(user, grp->gr_mem[i]) == 0) &&
2222 (strcmp(name_of_group, grp->gr_name) != 0)) {
2224 NWRAP_DEBUG(("%s: %s is member of %s\n",
2225 __location__, user, grp->gr_name));
2227 groups_tmp = (gid_t *)realloc(groups_tmp, (count + 1) * sizeof(gid_t));
2228 if (!groups_tmp) {
2229 NWRAP_ERROR(("%s:calloc failed\n",__location__));
2230 errno = ENOMEM;
2231 return -1;
2234 memcpy(&groups_tmp[count], &grp->gr_gid, sizeof(gid_t));
2235 count++;
2240 nwrap_endgrent();
2242 NWRAP_VERBOSE(("%s: %s is member of %d groups: %d\n",
2243 __location__, user, *ngroups));
2245 if (*ngroups < count) {
2246 *ngroups = count;
2247 free(groups_tmp);
2248 return -1;
2251 *ngroups = count;
2252 memcpy(groups, groups_tmp, count * sizeof(gid_t));
2253 free(groups_tmp);
2255 return count;