s3: don't build krb5 locator plugin if we don't build winbind
[Samba/gebeck_regimport.git] / lib / nss_wrapper / nss_wrapper.c
blob42fc4cfb0267a6910dbd314b03646a536fe4a486
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 #define _POSIX_PTHREAD_SEMANTICS
41 #define NSS_WRAPPER_NOT_REPLACE
42 #include "../replace/replace.h"
43 #include "system/passwd.h"
44 #include "system/filesys.h"
45 #include "../nsswitch/nsstest.h"
47 #else /* _SAMBA_BUILD_ */
49 #error nss_wrapper_only_supported_in_samba_yet
51 #endif
53 #ifndef _PUBLIC_
54 #define _PUBLIC_
55 #endif
57 /* not all systems have _r functions... */
58 #ifndef HAVE_GETPWNAM_R
59 #define getpwnam_r(name, pwdst, buf, buflen, pwdstp) ENOSYS
60 #endif
61 #ifndef HAVE_GETPWUID_R
62 #define getpwuid_r(uid, pwdst, buf, buflen, pwdstp) ENOSYS
63 #endif
64 #ifndef HAVE_GETPWENT_R
65 #define getpwent_r(pwdst, buf, buflen, pwdstp) ENOSYS
66 #endif
67 #ifndef HAVE_GETGRNAM_R
68 #define getgrnam_r(name, grdst, buf, buflen, grdstp) ENOSYS
69 #endif
70 #ifndef HAVE_GETGRGID_R
71 #define getgrgid_r(gid, grdst, buf, buflen, grdstp) ENOSYS
72 #endif
73 #ifndef HAVE_GETGRENT_R
74 #define getgrent_r(grdst, buf, buflen, grdstp) ENOSYS
75 #endif
77 /* not all systems have getgrouplist */
78 #ifndef HAVE_GETGROUPLIST
79 #define getgrouplist(user, group, groups, ngroups) 0
80 #endif
82 /* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
83 * for now */
84 #define REWRITE_CALLS
86 #ifdef REWRITE_CALLS
88 #define real_getpwnam getpwnam
89 #define real_getpwnam_r getpwnam_r
90 #define real_getpwuid getpwuid
91 #define real_getpwuid_r getpwuid_r
93 #define real_setpwent setpwent
94 #define real_getpwent getpwent
95 #define real_getpwent_r getpwent_r
96 #define real_endpwent endpwent
99 #define real_getgrlst getgrlst
100 #define real_getgrlst_r getgrlst_r
101 #define real_initgroups_dyn initgroups_dyn
103 #define real_initgroups initgroups
104 #define real_getgrouplist getgrouplist
106 #define real_getgrnam getgrnam
107 #define real_getgrnam_r getgrnam_r
108 #define real_getgrgid getgrgid
109 #define real_getgrgid_r getgrgid_r
111 #define real_setgrent setgrent
112 #define real_getgrent getgrent
113 #define real_getgrent_r getgrent_r
114 #define real_endgrent endgrent
116 #endif
118 #if 0
119 # ifdef DEBUG
120 # define NWRAP_ERROR(args) DEBUG(0, args)
121 # else
122 # define NWRAP_ERROR(args) printf args
123 # endif
124 #else
125 #define NWRAP_ERROR(args)
126 #endif
128 #if 0
129 # ifdef DEBUG
130 # define NWRAP_DEBUG(args) DEBUG(0, args)
131 # else
132 # define NWRAP_DEBUG(args) printf args
133 # endif
134 #else
135 #define NWRAP_DEBUG(args)
136 #endif
138 #if 0
139 # ifdef DEBUG
140 # define NWRAP_VERBOSE(args) DEBUG(0, args)
141 # else
142 # define NWRAP_VERBOSE(args) printf args
143 # endif
144 #else
145 #define NWRAP_VERBOSE(args)
146 #endif
148 struct nwrap_module_nss_fns {
149 NSS_STATUS (*_nss_getpwnam_r)(const char *name, struct passwd *result, char *buffer,
150 size_t buflen, int *errnop);
151 NSS_STATUS (*_nss_getpwuid_r)(uid_t uid, struct passwd *result, char *buffer,
152 size_t buflen, int *errnop);
153 NSS_STATUS (*_nss_setpwent)(void);
154 NSS_STATUS (*_nss_getpwent_r)(struct passwd *result, char *buffer,
155 size_t buflen, int *errnop);
156 NSS_STATUS (*_nss_endpwent)(void);
157 NSS_STATUS (*_nss_initgroups)(const char *user, gid_t group, long int *start,
158 long int *size, gid_t **groups, long int limit, int *errnop);
159 NSS_STATUS (*_nss_getgrnam_r)(const char *name, struct group *result, char *buffer,
160 size_t buflen, int *errnop);
161 NSS_STATUS (*_nss_getgrgid_r)(gid_t gid, struct group *result, char *buffer,
162 size_t buflen, int *errnop);
163 NSS_STATUS (*_nss_setgrent)(void);
164 NSS_STATUS (*_nss_getgrent_r)(struct group *result, char *buffer,
165 size_t buflen, int *errnop);
166 NSS_STATUS (*_nss_endgrent)(void);
169 struct nwrap_backend {
170 const char *name;
171 const char *so_path;
172 void *so_handle;
173 struct nwrap_ops *ops;
174 struct nwrap_module_nss_fns *fns;
177 struct nwrap_ops {
178 struct passwd * (*nw_getpwnam)(struct nwrap_backend *b,
179 const char *name);
180 int (*nw_getpwnam_r)(struct nwrap_backend *b,
181 const char *name, struct passwd *pwdst,
182 char *buf, size_t buflen, struct passwd **pwdstp);
183 struct passwd * (*nw_getpwuid)(struct nwrap_backend *b,
184 uid_t uid);
185 int (*nw_getpwuid_r)(struct nwrap_backend *b,
186 uid_t uid, struct passwd *pwdst,
187 char *buf, size_t buflen, struct passwd **pwdstp);
188 void (*nw_setpwent)(struct nwrap_backend *b);
189 struct passwd * (*nw_getpwent)(struct nwrap_backend *b);
190 int (*nw_getpwent_r)(struct nwrap_backend *b,
191 struct passwd *pwdst, char *buf,
192 size_t buflen, struct passwd **pwdstp);
193 void (*nw_endpwent)(struct nwrap_backend *b);
194 int (*nw_initgroups)(struct nwrap_backend *b,
195 const char *user, gid_t group);
196 struct group * (*nw_getgrnam)(struct nwrap_backend *b,
197 const char *name);
198 int (*nw_getgrnam_r)(struct nwrap_backend *b,
199 const char *name, struct group *grdst,
200 char *buf, size_t buflen, struct group **grdstp);
201 struct group * (*nw_getgrgid)(struct nwrap_backend *b,
202 gid_t gid);
203 int (*nw_getgrgid_r)(struct nwrap_backend *b,
204 gid_t gid, struct group *grdst,
205 char *buf, size_t buflen, struct group **grdstp);
206 void (*nw_setgrent)(struct nwrap_backend *b);
207 struct group * (*nw_getgrent)(struct nwrap_backend *b);
208 int (*nw_getgrent_r)(struct nwrap_backend *b,
209 struct group *grdst, char *buf,
210 size_t buflen, struct group **grdstp);
211 void (*nw_endgrent)(struct nwrap_backend *b);
214 /* prototypes for files backend */
217 static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
218 const char *name);
219 static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
220 const char *name, struct passwd *pwdst,
221 char *buf, size_t buflen, struct passwd **pwdstp);
222 static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
223 uid_t uid);
224 static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
225 uid_t uid, struct passwd *pwdst,
226 char *buf, size_t buflen, struct passwd **pwdstp);
227 static void nwrap_files_setpwent(struct nwrap_backend *b);
228 static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b);
229 static int nwrap_files_getpwent_r(struct nwrap_backend *b,
230 struct passwd *pwdst, char *buf,
231 size_t buflen, struct passwd **pwdstp);
232 static void nwrap_files_endpwent(struct nwrap_backend *b);
233 static int nwrap_files_initgroups(struct nwrap_backend *b,
234 const char *user, gid_t group);
235 static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
236 const char *name);
237 static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
238 const char *name, struct group *grdst,
239 char *buf, size_t buflen, struct group **grdstp);
240 static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
241 gid_t gid);
242 static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
243 gid_t gid, struct group *grdst,
244 char *buf, size_t buflen, struct group **grdstp);
245 static void nwrap_files_setgrent(struct nwrap_backend *b);
246 static struct group *nwrap_files_getgrent(struct nwrap_backend *b);
247 static int nwrap_files_getgrent_r(struct nwrap_backend *b,
248 struct group *grdst, char *buf,
249 size_t buflen, struct group **grdstp);
250 static void nwrap_files_endgrent(struct nwrap_backend *b);
252 /* prototypes for module backend */
254 static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b);
255 static int nwrap_module_getpwent_r(struct nwrap_backend *b,
256 struct passwd *pwdst, char *buf,
257 size_t buflen, struct passwd **pwdstp);
258 static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
259 const char *name);
260 static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
261 const char *name, struct passwd *pwdst,
262 char *buf, size_t buflen, struct passwd **pwdstp);
263 static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
264 uid_t uid);
265 static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
266 uid_t uid, struct passwd *pwdst,
267 char *buf, size_t buflen, struct passwd **pwdstp);
268 static void nwrap_module_setpwent(struct nwrap_backend *b);
269 static void nwrap_module_endpwent(struct nwrap_backend *b);
270 static struct group *nwrap_module_getgrent(struct nwrap_backend *b);
271 static int nwrap_module_getgrent_r(struct nwrap_backend *b,
272 struct group *grdst, char *buf,
273 size_t buflen, struct group **grdstp);
274 static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
275 const char *name);
276 static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
277 const char *name, struct group *grdst,
278 char *buf, size_t buflen, struct group **grdstp);
279 static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
280 gid_t gid);
281 static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
282 gid_t gid, struct group *grdst,
283 char *buf, size_t buflen, struct group **grdstp);
284 static void nwrap_module_setgrent(struct nwrap_backend *b);
285 static void nwrap_module_endgrent(struct nwrap_backend *b);
286 static int nwrap_module_initgroups(struct nwrap_backend *b,
287 const char *user, gid_t group);
289 struct nwrap_ops nwrap_files_ops = {
290 .nw_getpwnam = nwrap_files_getpwnam,
291 .nw_getpwnam_r = nwrap_files_getpwnam_r,
292 .nw_getpwuid = nwrap_files_getpwuid,
293 .nw_getpwuid_r = nwrap_files_getpwuid_r,
294 .nw_setpwent = nwrap_files_setpwent,
295 .nw_getpwent = nwrap_files_getpwent,
296 .nw_getpwent_r = nwrap_files_getpwent_r,
297 .nw_endpwent = nwrap_files_endpwent,
298 .nw_initgroups = nwrap_files_initgroups,
299 .nw_getgrnam = nwrap_files_getgrnam,
300 .nw_getgrnam_r = nwrap_files_getgrnam_r,
301 .nw_getgrgid = nwrap_files_getgrgid,
302 .nw_getgrgid_r = nwrap_files_getgrgid_r,
303 .nw_setgrent = nwrap_files_setgrent,
304 .nw_getgrent = nwrap_files_getgrent,
305 .nw_getgrent_r = nwrap_files_getgrent_r,
306 .nw_endgrent = nwrap_files_endgrent,
309 struct nwrap_ops nwrap_module_ops = {
310 .nw_getpwnam = nwrap_module_getpwnam,
311 .nw_getpwnam_r = nwrap_module_getpwnam_r,
312 .nw_getpwuid = nwrap_module_getpwuid,
313 .nw_getpwuid_r = nwrap_module_getpwuid_r,
314 .nw_setpwent = nwrap_module_setpwent,
315 .nw_getpwent = nwrap_module_getpwent,
316 .nw_getpwent_r = nwrap_module_getpwent_r,
317 .nw_endpwent = nwrap_module_endpwent,
318 .nw_initgroups = nwrap_module_initgroups,
319 .nw_getgrnam = nwrap_module_getgrnam,
320 .nw_getgrnam_r = nwrap_module_getgrnam_r,
321 .nw_getgrgid = nwrap_module_getgrgid,
322 .nw_getgrgid_r = nwrap_module_getgrgid_r,
323 .nw_setgrent = nwrap_module_setgrent,
324 .nw_getgrent = nwrap_module_getgrent,
325 .nw_getgrent_r = nwrap_module_getgrent_r,
326 .nw_endgrent = nwrap_module_endgrent,
329 struct nwrap_main {
330 const char *nwrap_switch;
331 int num_backends;
332 struct nwrap_backend *backends;
335 struct nwrap_main *nwrap_main_global;
336 struct nwrap_main __nwrap_main_global;
338 struct nwrap_cache {
339 const char *path;
340 int fd;
341 struct stat st;
342 uint8_t *buf;
343 void *private_data;
344 bool (*parse_line)(struct nwrap_cache *, char *line);
345 void (*unload)(struct nwrap_cache *);
348 struct nwrap_pw {
349 struct nwrap_cache *cache;
351 struct passwd *list;
352 int num;
353 int idx;
356 struct nwrap_cache __nwrap_cache_pw;
357 struct nwrap_pw nwrap_pw_global;
359 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line);
360 static void nwrap_pw_unload(struct nwrap_cache *nwrap);
362 struct nwrap_gr {
363 struct nwrap_cache *cache;
365 struct group *list;
366 int num;
367 int idx;
370 struct nwrap_cache __nwrap_cache_gr;
371 struct nwrap_gr nwrap_gr_global;
373 static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line);
374 static void nwrap_gr_unload(struct nwrap_cache *nwrap);
376 static void *nwrap_load_module_fn(struct nwrap_backend *b,
377 const char *fn_name)
379 void *res;
380 char *s;
382 if (!b->so_handle) {
383 NWRAP_ERROR(("%s: no handle\n",
384 __location__));
385 return NULL;
388 if (asprintf(&s, "_nss_%s_%s", b->name, fn_name) == -1) {
389 NWRAP_ERROR(("%s: out of memory\n",
390 __location__));
391 return NULL;
394 res = dlsym(b->so_handle, s);
395 if (!res) {
396 NWRAP_ERROR(("%s: cannot find function %s in %s\n",
397 __location__, s, b->so_path));
399 free(s);
400 s = NULL;
401 return res;
404 static struct nwrap_module_nss_fns *nwrap_load_module_fns(struct nwrap_backend *b)
406 struct nwrap_module_nss_fns *fns;
408 if (!b->so_handle) {
409 return NULL;
412 fns = (struct nwrap_module_nss_fns *)malloc(sizeof(struct nwrap_module_nss_fns));
413 if (!fns) {
414 return NULL;
417 fns->_nss_getpwnam_r = (NSS_STATUS (*)(const char *, struct passwd *, char *, size_t, int *))
418 nwrap_load_module_fn(b, "getpwnam_r");
419 fns->_nss_getpwuid_r = (NSS_STATUS (*)(uid_t, struct passwd *, char *, size_t, int *))
420 nwrap_load_module_fn(b, "getpwuid_r");
421 fns->_nss_setpwent = (NSS_STATUS(*)(void))
422 nwrap_load_module_fn(b, "setpwent");
423 fns->_nss_getpwent_r = (NSS_STATUS (*)(struct passwd *, char *, size_t, int *))
424 nwrap_load_module_fn(b, "getpwent_r");
425 fns->_nss_endpwent = (NSS_STATUS(*)(void))
426 nwrap_load_module_fn(b, "endpwent");
427 fns->_nss_initgroups = (NSS_STATUS (*)(const char *, gid_t, long int *, long int *, gid_t **, long int, int *))
428 nwrap_load_module_fn(b, "initgroups_dyn");
429 fns->_nss_getgrnam_r = (NSS_STATUS (*)(const char *, struct group *, char *, size_t, int *))
430 nwrap_load_module_fn(b, "getgrnam_r");
431 fns->_nss_getgrgid_r = (NSS_STATUS (*)(gid_t, struct group *, char *, size_t, int *))
432 nwrap_load_module_fn(b, "getgrgid_r");
433 fns->_nss_setgrent = (NSS_STATUS(*)(void))
434 nwrap_load_module_fn(b, "setgrent");
435 fns->_nss_getgrent_r = (NSS_STATUS (*)(struct group *, char *, size_t, int *))
436 nwrap_load_module_fn(b, "getgrent_r");
437 fns->_nss_endgrent = (NSS_STATUS(*)(void))
438 nwrap_load_module_fn(b, "endgrent");
440 return fns;
443 static void *nwrap_load_module(const char *so_path)
445 void *h;
447 if (!so_path || !strlen(so_path)) {
448 return NULL;
451 h = dlopen(so_path, RTLD_LAZY);
452 if (!h) {
453 NWRAP_ERROR(("%s: cannot open shared library %s\n",
454 __location__, so_path));
455 return NULL;
458 return h;
461 static bool nwrap_module_init(const char *name,
462 struct nwrap_ops *ops,
463 const char *so_path,
464 int *num_backends,
465 struct nwrap_backend **backends)
467 *backends = (struct nwrap_backend *)realloc(*backends,
468 sizeof(struct nwrap_backend) * ((*num_backends) + 1));
469 if (!*backends) {
470 NWRAP_ERROR(("%s: out of memory\n",
471 __location__));
472 return false;
475 (*backends)[*num_backends].name = name;
476 (*backends)[*num_backends].ops = ops;
477 (*backends)[*num_backends].so_path = so_path;
478 (*backends)[*num_backends].so_handle = nwrap_load_module(so_path);
479 (*backends)[*num_backends].fns = nwrap_load_module_fns(&((*backends)[*num_backends]));
481 (*num_backends)++;
483 return true;
486 static void nwrap_backend_init(struct nwrap_main *r)
488 const char *winbind_so_path = getenv("NSS_WRAPPER_WINBIND_SO_PATH");
490 r->num_backends = 0;
491 r->backends = NULL;
493 if (!nwrap_module_init("files", &nwrap_files_ops, NULL,
494 &r->num_backends,
495 &r->backends)) {
496 NWRAP_ERROR(("%s: failed to initialize 'files' backend\n",
497 __location__));
498 return;
501 if (winbind_so_path && strlen(winbind_so_path)) {
502 if (!nwrap_module_init("winbind", &nwrap_module_ops, winbind_so_path,
503 &r->num_backends,
504 &r->backends)) {
505 NWRAP_ERROR(("%s: failed to initialize 'winbind' backend\n",
506 __location__));
507 return;
512 static void nwrap_init(void)
514 static bool initialized;
516 if (initialized) return;
517 initialized = true;
519 nwrap_main_global = &__nwrap_main_global;
521 nwrap_backend_init(nwrap_main_global);
523 nwrap_pw_global.cache = &__nwrap_cache_pw;
525 nwrap_pw_global.cache->path = getenv("NSS_WRAPPER_PASSWD");
526 nwrap_pw_global.cache->fd = -1;
527 nwrap_pw_global.cache->private_data = &nwrap_pw_global;
528 nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
529 nwrap_pw_global.cache->unload = nwrap_pw_unload;
531 nwrap_gr_global.cache = &__nwrap_cache_gr;
533 nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
534 nwrap_gr_global.cache->fd = -1;
535 nwrap_gr_global.cache->private_data = &nwrap_gr_global;
536 nwrap_gr_global.cache->parse_line = nwrap_gr_parse_line;
537 nwrap_gr_global.cache->unload = nwrap_gr_unload;
540 static bool nwrap_enabled(void)
542 nwrap_init();
544 if (!nwrap_pw_global.cache->path) {
545 return false;
547 if (nwrap_pw_global.cache->path[0] == '\0') {
548 return false;
550 if (!nwrap_gr_global.cache->path) {
551 return false;
553 if (nwrap_gr_global.cache->path[0] == '\0') {
554 return false;
557 return true;
560 static bool nwrap_parse_file(struct nwrap_cache *nwrap)
562 int ret;
563 uint8_t *buf = NULL;
564 char *nline;
566 if (nwrap->st.st_size == 0) {
567 NWRAP_DEBUG(("%s: size == 0\n",
568 __location__));
569 goto done;
572 if (nwrap->st.st_size > INT32_MAX) {
573 NWRAP_ERROR(("%s: size[%u] larger than INT32_MAX\n",
574 __location__, (unsigned)nwrap->st.st_size));
575 goto failed;
578 ret = lseek(nwrap->fd, 0, SEEK_SET);
579 if (ret != 0) {
580 NWRAP_ERROR(("%s: lseek - %d\n",__location__,ret));
581 goto failed;
584 buf = (uint8_t *)malloc(nwrap->st.st_size + 1);
585 if (!buf) {
586 NWRAP_ERROR(("%s: malloc failed\n",__location__));
587 goto failed;
590 ret = read(nwrap->fd, buf, nwrap->st.st_size);
591 if (ret != nwrap->st.st_size) {
592 NWRAP_ERROR(("%s: read(%u) gave %d\n",
593 __location__, (unsigned)nwrap->st.st_size, ret));
594 goto failed;
597 buf[nwrap->st.st_size] = '\0';
599 nline = (char *)buf;
600 while (nline && nline[0]) {
601 char *line;
602 char *e;
603 bool ok;
605 line = nline;
606 nline = NULL;
608 e = strchr(line, '\n');
609 if (e) {
610 e[0] = '\0';
611 e++;
612 if (e[0] == '\r') {
613 e[0] = '\0';
614 e++;
616 nline = e;
619 NWRAP_VERBOSE(("%s:'%s'\n",__location__, line));
621 if (strlen(line) == 0) {
622 continue;
625 ok = nwrap->parse_line(nwrap, line);
626 if (!ok) {
627 goto failed;
631 done:
632 nwrap->buf = buf;
633 return true;
635 failed:
636 if (buf) free(buf);
637 return false;
640 static void nwrap_files_cache_unload(struct nwrap_cache *nwrap)
642 nwrap->unload(nwrap);
644 if (nwrap->buf) free(nwrap->buf);
646 nwrap->buf = NULL;
649 static void nwrap_files_cache_reload(struct nwrap_cache *nwrap)
651 struct stat st;
652 int ret;
653 bool ok;
654 bool retried = false;
656 reopen:
657 if (nwrap->fd < 0) {
658 nwrap->fd = open(nwrap->path, O_RDONLY);
659 if (nwrap->fd < 0) {
660 NWRAP_ERROR(("%s: unable to open '%s' readonly %d:%s\n",
661 __location__,
662 nwrap->path, nwrap->fd,
663 strerror(errno)));
664 return;
666 NWRAP_VERBOSE(("%s: open '%s'\n", __location__, nwrap->path));
669 ret = fstat(nwrap->fd, &st);
670 if (ret != 0) {
671 NWRAP_ERROR(("%s: fstat(%s) - %d:%s\n",
672 __location__,
673 nwrap->path,
674 ret, strerror(errno)));
675 return;
678 if (retried == false && st.st_nlink == 0) {
679 /* maybe someone has replaced the file... */
680 NWRAP_DEBUG(("%s: st_nlink == 0, reopen %s\n",
681 __location__, nwrap->path));
682 retried = true;
683 memset(&nwrap->st, 0, sizeof(nwrap->st));
684 close(nwrap->fd);
685 nwrap->fd = -1;
686 goto reopen;
689 if (st.st_mtime == nwrap->st.st_mtime) {
690 NWRAP_VERBOSE(("%s: st_mtime[%u] hasn't changed, skip reload\n",
691 __location__, (unsigned)st.st_mtime));
692 return;
694 NWRAP_DEBUG(("%s: st_mtime has changed [%u] => [%u], start reload\n",
695 __location__, (unsigned)st.st_mtime,
696 (unsigned)nwrap->st.st_mtime));
698 nwrap->st = st;
700 nwrap_files_cache_unload(nwrap);
702 ok = nwrap_parse_file(nwrap);
703 if (!ok) {
704 NWRAP_ERROR(("%s: failed to reload %s\n",
705 __location__, nwrap->path));
706 nwrap_files_cache_unload(nwrap);
708 NWRAP_DEBUG(("%s: reloaded %s\n",
709 __location__, nwrap->path));
713 * the caller has to call nwrap_unload() on failure
715 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
717 struct nwrap_pw *nwrap_pw;
718 char *c;
719 char *p;
720 char *e;
721 struct passwd *pw;
722 size_t list_size;
724 nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
726 list_size = sizeof(*nwrap_pw->list) * (nwrap_pw->num+1);
727 pw = (struct passwd *)realloc(nwrap_pw->list, list_size);
728 if (!pw) {
729 NWRAP_ERROR(("%s:realloc(%u) failed\n",
730 __location__, list_size));
731 return false;
733 nwrap_pw->list = pw;
735 pw = &nwrap_pw->list[nwrap_pw->num];
737 c = line;
739 /* name */
740 p = strchr(c, ':');
741 if (!p) {
742 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
743 __location__, line, c));
744 return false;
746 *p = '\0';
747 p++;
748 pw->pw_name = c;
749 c = p;
751 NWRAP_VERBOSE(("name[%s]\n", pw->pw_name));
753 /* password */
754 p = strchr(c, ':');
755 if (!p) {
756 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
757 __location__, line, c));
758 return false;
760 *p = '\0';
761 p++;
762 pw->pw_passwd = c;
763 c = p;
765 NWRAP_VERBOSE(("password[%s]\n", pw->pw_passwd));
767 /* uid */
768 p = strchr(c, ':');
769 if (!p) {
770 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
771 __location__, line, c));
772 return false;
774 *p = '\0';
775 p++;
776 e = NULL;
777 pw->pw_uid = (uid_t)strtoul(c, &e, 10);
778 if (c == e) {
779 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
780 __location__, line, c, strerror(errno)));
781 return false;
783 if (e == NULL) {
784 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
785 __location__, line, c, strerror(errno)));
786 return false;
788 if (e[0] != '\0') {
789 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
790 __location__, line, c, strerror(errno)));
791 return false;
793 c = p;
795 NWRAP_VERBOSE(("uid[%u]\n", pw->pw_uid));
797 /* gid */
798 p = strchr(c, ':');
799 if (!p) {
800 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
801 __location__, line, c));
802 return false;
804 *p = '\0';
805 p++;
806 e = NULL;
807 pw->pw_gid = (gid_t)strtoul(c, &e, 10);
808 if (c == e) {
809 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
810 __location__, line, c, strerror(errno)));
811 return false;
813 if (e == NULL) {
814 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
815 __location__, line, c, strerror(errno)));
816 return false;
818 if (e[0] != '\0') {
819 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
820 __location__, line, c, strerror(errno)));
821 return false;
823 c = p;
825 NWRAP_VERBOSE(("gid[%u]\n", pw->pw_gid));
827 /* gecos */
828 p = strchr(c, ':');
829 if (!p) {
830 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
831 __location__, line, c));
832 return false;
834 *p = '\0';
835 p++;
836 pw->pw_gecos = c;
837 c = p;
839 NWRAP_VERBOSE(("gecos[%s]\n", pw->pw_gecos));
841 /* dir */
842 p = strchr(c, ':');
843 if (!p) {
844 NWRAP_ERROR(("%s:'%s'\n",__location__,c));
845 return false;
847 *p = '\0';
848 p++;
849 pw->pw_dir = c;
850 c = p;
852 NWRAP_VERBOSE(("dir[%s]\n", pw->pw_dir));
854 /* shell */
855 pw->pw_shell = c;
856 NWRAP_VERBOSE(("shell[%s]\n", pw->pw_shell));
858 NWRAP_DEBUG(("add user[%s:%s:%u:%u:%s:%s:%s]\n",
859 pw->pw_name, pw->pw_passwd,
860 pw->pw_uid, pw->pw_gid,
861 pw->pw_gecos, pw->pw_dir, pw->pw_shell));
863 nwrap_pw->num++;
864 return true;
867 static void nwrap_pw_unload(struct nwrap_cache *nwrap)
869 struct nwrap_pw *nwrap_pw;
870 nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
872 if (nwrap_pw->list) free(nwrap_pw->list);
874 nwrap_pw->list = NULL;
875 nwrap_pw->num = 0;
876 nwrap_pw->idx = 0;
879 static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
880 char *buf, size_t buflen, struct passwd **dstp)
882 char *first;
883 char *last;
884 off_t ofs;
886 first = src->pw_name;
888 last = src->pw_shell;
889 while (*last) last++;
891 ofs = PTR_DIFF(last + 1, first);
893 if (ofs > buflen) {
894 return ERANGE;
897 memcpy(buf, first, ofs);
899 ofs = PTR_DIFF(src->pw_name, first);
900 dst->pw_name = buf + ofs;
901 ofs = PTR_DIFF(src->pw_passwd, first);
902 dst->pw_passwd = buf + ofs;
903 dst->pw_uid = src->pw_uid;
904 dst->pw_gid = src->pw_gid;
905 ofs = PTR_DIFF(src->pw_gecos, first);
906 dst->pw_gecos = buf + ofs;
907 ofs = PTR_DIFF(src->pw_dir, first);
908 dst->pw_dir = buf + ofs;
909 ofs = PTR_DIFF(src->pw_shell, first);
910 dst->pw_shell = buf + ofs;
912 if (dstp) {
913 *dstp = dst;
916 return 0;
920 * the caller has to call nwrap_unload() on failure
922 static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
924 struct nwrap_gr *nwrap_gr;
925 char *c;
926 char *p;
927 char *e;
928 struct group *gr;
929 size_t list_size;
930 unsigned nummem;
932 nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
934 list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
935 gr = (struct group *)realloc(nwrap_gr->list, list_size);
936 if (!gr) {
937 NWRAP_ERROR(("%s:realloc failed\n",__location__));
938 return false;
940 nwrap_gr->list = gr;
942 gr = &nwrap_gr->list[nwrap_gr->num];
944 c = line;
946 /* name */
947 p = strchr(c, ':');
948 if (!p) {
949 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
950 __location__, line, c));
951 return false;
953 *p = '\0';
954 p++;
955 gr->gr_name = c;
956 c = p;
958 NWRAP_VERBOSE(("name[%s]\n", gr->gr_name));
960 /* password */
961 p = strchr(c, ':');
962 if (!p) {
963 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
964 __location__, line, c));
965 return false;
967 *p = '\0';
968 p++;
969 gr->gr_passwd = c;
970 c = p;
972 NWRAP_VERBOSE(("password[%s]\n", gr->gr_passwd));
974 /* gid */
975 p = strchr(c, ':');
976 if (!p) {
977 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
978 __location__, line, c));
979 return false;
981 *p = '\0';
982 p++;
983 e = NULL;
984 gr->gr_gid = (gid_t)strtoul(c, &e, 10);
985 if (c == e) {
986 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
987 __location__, line, c, strerror(errno)));
988 return false;
990 if (e == NULL) {
991 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
992 __location__, line, c, strerror(errno)));
993 return false;
995 if (e[0] != '\0') {
996 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
997 __location__, line, c, strerror(errno)));
998 return false;
1000 c = p;
1002 NWRAP_VERBOSE(("gid[%u]\n", gr->gr_gid));
1004 /* members */
1005 gr->gr_mem = (char **)malloc(sizeof(char *));
1006 if (!gr->gr_mem) {
1007 NWRAP_ERROR(("%s:calloc failed\n",__location__));
1008 return false;
1010 gr->gr_mem[0] = NULL;
1012 for(nummem=0; p; nummem++) {
1013 char **m;
1014 size_t m_size;
1015 c = p;
1016 p = strchr(c, ',');
1017 if (p) {
1018 *p = '\0';
1019 p++;
1022 if (strlen(c) == 0) {
1023 break;
1026 m_size = sizeof(char *) * (nummem+2);
1027 m = (char **)realloc(gr->gr_mem, m_size);
1028 if (!m) {
1029 NWRAP_ERROR(("%s:realloc(%u) failed\n",
1030 __location__, m_size));
1031 return false;
1033 gr->gr_mem = m;
1034 gr->gr_mem[nummem] = c;
1035 gr->gr_mem[nummem+1] = NULL;
1037 NWRAP_VERBOSE(("member[%u]: '%s'\n", nummem, gr->gr_mem[nummem]));
1040 NWRAP_DEBUG(("add group[%s:%s:%u:] with %u members\n",
1041 gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem));
1043 nwrap_gr->num++;
1044 return true;
1047 static void nwrap_gr_unload(struct nwrap_cache *nwrap)
1049 int i;
1050 struct nwrap_gr *nwrap_gr;
1051 nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
1053 if (nwrap_gr->list) {
1054 for (i=0; i < nwrap_gr->num; i++) {
1055 if (nwrap_gr->list[i].gr_mem) {
1056 free(nwrap_gr->list[i].gr_mem);
1059 free(nwrap_gr->list);
1062 nwrap_gr->list = NULL;
1063 nwrap_gr->num = 0;
1064 nwrap_gr->idx = 0;
1067 static int nwrap_gr_copy_r(const struct group *src, struct group *dst,
1068 char *buf, size_t buflen, struct group **dstp)
1070 char *first;
1071 char **lastm;
1072 char *last = NULL;
1073 off_t ofsb;
1074 off_t ofsm;
1075 off_t ofs;
1076 unsigned i;
1078 first = src->gr_name;
1080 lastm = src->gr_mem;
1081 while (*lastm) {
1082 last = *lastm;
1083 lastm++;
1086 if (last == NULL) {
1087 last = src->gr_passwd;
1089 while (*last) last++;
1091 ofsb = PTR_DIFF(last + 1, first);
1092 ofsm = PTR_DIFF(lastm + 1, src->gr_mem);
1094 if ((ofsb + ofsm) > buflen) {
1095 return ERANGE;
1098 memcpy(buf, first, ofsb);
1099 memcpy(buf + ofsb, src->gr_mem, ofsm);
1101 ofs = PTR_DIFF(src->gr_name, first);
1102 dst->gr_name = buf + ofs;
1103 ofs = PTR_DIFF(src->gr_passwd, first);
1104 dst->gr_passwd = buf + ofs;
1105 dst->gr_gid = src->gr_gid;
1107 dst->gr_mem = (char **)(buf + ofsb);
1108 for (i=0; src->gr_mem[i]; i++) {
1109 ofs = PTR_DIFF(src->gr_mem[i], first);
1110 dst->gr_mem[i] = buf + ofs;
1113 if (dstp) {
1114 *dstp = dst;
1117 return 0;
1120 /* user functions */
1121 static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
1122 const char *name)
1124 int i;
1126 nwrap_files_cache_reload(nwrap_pw_global.cache);
1128 for (i=0; i<nwrap_pw_global.num; i++) {
1129 if (strcmp(nwrap_pw_global.list[i].pw_name, name) == 0) {
1130 NWRAP_DEBUG(("%s: user[%s] found\n",
1131 __location__, name));
1132 return &nwrap_pw_global.list[i];
1134 NWRAP_VERBOSE(("%s: user[%s] does not match [%s]\n",
1135 __location__, name,
1136 nwrap_pw_global.list[i].pw_name));
1139 NWRAP_DEBUG(("%s: user[%s] not found\n", __location__, name));
1141 errno = ENOENT;
1142 return NULL;
1145 static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
1146 const char *name, struct passwd *pwdst,
1147 char *buf, size_t buflen, struct passwd **pwdstp)
1149 struct passwd *pw;
1151 pw = nwrap_files_getpwnam(b, name);
1152 if (!pw) {
1153 if (errno == 0) {
1154 return ENOENT;
1156 return errno;
1159 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
1162 static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
1163 uid_t uid)
1165 int i;
1167 nwrap_files_cache_reload(nwrap_pw_global.cache);
1169 for (i=0; i<nwrap_pw_global.num; i++) {
1170 if (nwrap_pw_global.list[i].pw_uid == uid) {
1171 NWRAP_DEBUG(("%s: uid[%u] found\n",
1172 __location__, uid));
1173 return &nwrap_pw_global.list[i];
1175 NWRAP_VERBOSE(("%s: uid[%u] does not match [%u]\n",
1176 __location__, uid,
1177 nwrap_pw_global.list[i].pw_uid));
1180 NWRAP_DEBUG(("%s: uid[%u] not found\n", __location__, uid));
1182 errno = ENOENT;
1183 return NULL;
1186 static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
1187 uid_t uid, struct passwd *pwdst,
1188 char *buf, size_t buflen, struct passwd **pwdstp)
1190 struct passwd *pw;
1192 pw = nwrap_files_getpwuid(b, uid);
1193 if (!pw) {
1194 if (errno == 0) {
1195 return ENOENT;
1197 return errno;
1200 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
1203 /* user enum functions */
1204 static void nwrap_files_setpwent(struct nwrap_backend *b)
1206 nwrap_pw_global.idx = 0;
1209 static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b)
1211 struct passwd *pw;
1213 if (nwrap_pw_global.idx == 0) {
1214 nwrap_files_cache_reload(nwrap_pw_global.cache);
1217 if (nwrap_pw_global.idx >= nwrap_pw_global.num) {
1218 errno = ENOENT;
1219 return NULL;
1222 pw = &nwrap_pw_global.list[nwrap_pw_global.idx++];
1224 NWRAP_VERBOSE(("%s: return user[%s] uid[%u]\n",
1225 __location__, pw->pw_name, pw->pw_uid));
1227 return pw;
1230 static int nwrap_files_getpwent_r(struct nwrap_backend *b,
1231 struct passwd *pwdst, char *buf,
1232 size_t buflen, struct passwd **pwdstp)
1234 struct passwd *pw;
1236 pw = nwrap_files_getpwent(b);
1237 if (!pw) {
1238 if (errno == 0) {
1239 return ENOENT;
1241 return errno;
1244 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
1247 static void nwrap_files_endpwent(struct nwrap_backend *b)
1249 nwrap_pw_global.idx = 0;
1252 /* misc functions */
1253 static int nwrap_files_initgroups(struct nwrap_backend *b,
1254 const char *user, gid_t group)
1256 /* TODO: maybe we should also fake this... */
1257 return EPERM;
1260 /* group functions */
1261 static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
1262 const char *name)
1264 int i;
1266 nwrap_files_cache_reload(nwrap_gr_global.cache);
1268 for (i=0; i<nwrap_gr_global.num; i++) {
1269 if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) {
1270 NWRAP_DEBUG(("%s: group[%s] found\n",
1271 __location__, name));
1272 return &nwrap_gr_global.list[i];
1274 NWRAP_VERBOSE(("%s: group[%s] does not match [%s]\n",
1275 __location__, name,
1276 nwrap_gr_global.list[i].gr_name));
1279 NWRAP_DEBUG(("%s: group[%s] not found\n", __location__, name));
1281 errno = ENOENT;
1282 return NULL;
1285 static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
1286 const char *name, struct group *grdst,
1287 char *buf, size_t buflen, struct group **grdstp)
1289 struct group *gr;
1291 gr = nwrap_files_getgrnam(b, name);
1292 if (!gr) {
1293 if (errno == 0) {
1294 return ENOENT;
1296 return errno;
1299 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
1302 static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
1303 gid_t gid)
1305 int i;
1307 nwrap_files_cache_reload(nwrap_gr_global.cache);
1309 for (i=0; i<nwrap_gr_global.num; i++) {
1310 if (nwrap_gr_global.list[i].gr_gid == gid) {
1311 NWRAP_DEBUG(("%s: gid[%u] found\n",
1312 __location__, gid));
1313 return &nwrap_gr_global.list[i];
1315 NWRAP_VERBOSE(("%s: gid[%u] does not match [%u]\n",
1316 __location__, gid,
1317 nwrap_gr_global.list[i].gr_gid));
1320 NWRAP_DEBUG(("%s: gid[%u] not found\n", __location__, gid));
1322 errno = ENOENT;
1323 return NULL;
1326 static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
1327 gid_t gid, struct group *grdst,
1328 char *buf, size_t buflen, struct group **grdstp)
1330 struct group *gr;
1332 gr = nwrap_files_getgrgid(b, gid);
1333 if (!gr) {
1334 if (errno == 0) {
1335 return ENOENT;
1337 return errno;
1340 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
1343 /* group enum functions */
1344 static void nwrap_files_setgrent(struct nwrap_backend *b)
1346 nwrap_gr_global.idx = 0;
1349 static struct group *nwrap_files_getgrent(struct nwrap_backend *b)
1351 struct group *gr;
1353 if (nwrap_gr_global.idx == 0) {
1354 nwrap_files_cache_reload(nwrap_gr_global.cache);
1357 if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
1358 errno = ENOENT;
1359 return NULL;
1362 gr = &nwrap_gr_global.list[nwrap_gr_global.idx++];
1364 NWRAP_VERBOSE(("%s: return group[%s] gid[%u]\n",
1365 __location__, gr->gr_name, gr->gr_gid));
1367 return gr;
1370 static int nwrap_files_getgrent_r(struct nwrap_backend *b,
1371 struct group *grdst, char *buf,
1372 size_t buflen, struct group **grdstp)
1374 struct group *gr;
1376 gr = nwrap_files_getgrent(b);
1377 if (!gr) {
1378 if (errno == 0) {
1379 return ENOENT;
1381 return errno;
1384 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
1387 static void nwrap_files_endgrent(struct nwrap_backend *b)
1389 nwrap_gr_global.idx = 0;
1393 * module backend
1396 #ifndef SAFE_FREE
1397 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
1398 #endif
1400 static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
1401 const char *name)
1403 static struct passwd pwd;
1404 static char buf[1000];
1405 NSS_STATUS status;
1407 if (!b->fns->_nss_getpwnam_r) {
1408 return NULL;
1411 status = b->fns->_nss_getpwnam_r(name, &pwd, buf, sizeof(buf), &errno);
1412 if (status == NSS_STATUS_NOTFOUND) {
1413 return NULL;
1415 if (status != NSS_STATUS_SUCCESS) {
1416 return NULL;
1418 return &pwd;
1421 static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
1422 const char *name, struct passwd *pwdst,
1423 char *buf, size_t buflen, struct passwd **pwdstp)
1425 int ret;
1427 if (!b->fns->_nss_getpwnam_r) {
1428 return NSS_STATUS_NOTFOUND;
1431 ret = b->fns->_nss_getpwnam_r(name, pwdst, buf, buflen, &errno);
1432 switch (ret) {
1433 case NSS_STATUS_SUCCESS:
1434 return 0;
1435 case NSS_STATUS_NOTFOUND:
1436 if (errno != 0) {
1437 return errno;
1439 return ENOENT;
1440 case NSS_STATUS_TRYAGAIN:
1441 if (errno != 0) {
1442 return errno;
1444 return ERANGE;
1445 default:
1446 if (errno != 0) {
1447 return errno;
1449 return ret;
1453 static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
1454 uid_t uid)
1456 static struct passwd pwd;
1457 static char buf[1000];
1458 NSS_STATUS status;
1460 if (!b->fns->_nss_getpwuid_r) {
1461 return NULL;
1464 status = b->fns->_nss_getpwuid_r(uid, &pwd, buf, sizeof(buf), &errno);
1465 if (status == NSS_STATUS_NOTFOUND) {
1466 return NULL;
1468 if (status != NSS_STATUS_SUCCESS) {
1469 return NULL;
1471 return &pwd;
1474 static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
1475 uid_t uid, struct passwd *pwdst,
1476 char *buf, size_t buflen, struct passwd **pwdstp)
1478 int ret;
1480 if (!b->fns->_nss_getpwuid_r) {
1481 return ENOENT;
1484 ret = b->fns->_nss_getpwuid_r(uid, pwdst, buf, buflen, &errno);
1485 switch (ret) {
1486 case NSS_STATUS_SUCCESS:
1487 return 0;
1488 case NSS_STATUS_NOTFOUND:
1489 if (errno != 0) {
1490 return errno;
1492 return ENOENT;
1493 case NSS_STATUS_TRYAGAIN:
1494 if (errno != 0) {
1495 return errno;
1497 return ERANGE;
1498 default:
1499 if (errno != 0) {
1500 return errno;
1502 return ret;
1506 static void nwrap_module_setpwent(struct nwrap_backend *b)
1508 if (!b->fns->_nss_setpwent) {
1509 return;
1512 b->fns->_nss_setpwent();
1515 static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b)
1517 static struct passwd pwd;
1518 static char buf[1000];
1519 NSS_STATUS status;
1521 if (!b->fns->_nss_getpwent_r) {
1522 return NULL;
1525 status = b->fns->_nss_getpwent_r(&pwd, buf, sizeof(buf), &errno);
1526 if (status == NSS_STATUS_NOTFOUND) {
1527 return NULL;
1529 if (status != NSS_STATUS_SUCCESS) {
1530 return NULL;
1532 return &pwd;
1535 static int nwrap_module_getpwent_r(struct nwrap_backend *b,
1536 struct passwd *pwdst, char *buf,
1537 size_t buflen, struct passwd **pwdstp)
1539 int ret;
1541 if (!b->fns->_nss_getpwent_r) {
1542 return ENOENT;
1545 ret = b->fns->_nss_getpwent_r(pwdst, buf, buflen, &errno);
1546 switch (ret) {
1547 case NSS_STATUS_SUCCESS:
1548 return 0;
1549 case NSS_STATUS_NOTFOUND:
1550 if (errno != 0) {
1551 return errno;
1553 return ENOENT;
1554 case NSS_STATUS_TRYAGAIN:
1555 if (errno != 0) {
1556 return errno;
1558 return ERANGE;
1559 default:
1560 if (errno != 0) {
1561 return errno;
1563 return ret;
1567 static void nwrap_module_endpwent(struct nwrap_backend *b)
1569 if (!b->fns->_nss_endpwent) {
1570 return;
1573 b->fns->_nss_endpwent();
1576 static int nwrap_module_initgroups(struct nwrap_backend *b,
1577 const char *user, gid_t group)
1579 gid_t *groups;
1580 long int start;
1581 long int size;
1583 if (!b->fns->_nss_initgroups) {
1584 return NSS_STATUS_UNAVAIL;
1587 return b->fns->_nss_initgroups(user, group, &start, &size, &groups, 0, &errno);
1590 static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
1591 const char *name)
1593 static struct group grp;
1594 static char *buf;
1595 static int buflen = 1000;
1596 NSS_STATUS status;
1598 if (!b->fns->_nss_getgrnam_r) {
1599 return NULL;
1602 if (!buf) {
1603 buf = (char *)malloc(buflen);
1605 again:
1606 status = b->fns->_nss_getgrnam_r(name, &grp, buf, buflen, &errno);
1607 if (status == NSS_STATUS_TRYAGAIN) {
1608 buflen *= 2;
1609 buf = (char *)realloc(buf, buflen);
1610 if (!buf) {
1611 return NULL;
1613 goto again;
1615 if (status == NSS_STATUS_NOTFOUND) {
1616 SAFE_FREE(buf);
1617 return NULL;
1619 if (status != NSS_STATUS_SUCCESS) {
1620 SAFE_FREE(buf);
1621 return NULL;
1623 return &grp;
1626 static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
1627 const char *name, struct group *grdst,
1628 char *buf, size_t buflen, struct group **grdstp)
1630 int ret;
1632 if (!b->fns->_nss_getgrnam_r) {
1633 return ENOENT;
1636 ret = b->fns->_nss_getgrnam_r(name, grdst, buf, buflen, &errno);
1637 switch (ret) {
1638 case NSS_STATUS_SUCCESS:
1639 return 0;
1640 case NSS_STATUS_NOTFOUND:
1641 if (errno != 0) {
1642 return errno;
1644 return ENOENT;
1645 case NSS_STATUS_TRYAGAIN:
1646 if (errno != 0) {
1647 return errno;
1649 return ERANGE;
1650 default:
1651 if (errno != 0) {
1652 return errno;
1654 return ret;
1658 static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
1659 gid_t gid)
1661 static struct group grp;
1662 static char *buf;
1663 static int buflen = 1000;
1664 NSS_STATUS status;
1666 if (!b->fns->_nss_getgrgid_r) {
1667 return NULL;
1670 if (!buf) {
1671 buf = (char *)malloc(buflen);
1674 again:
1675 status = b->fns->_nss_getgrgid_r(gid, &grp, buf, buflen, &errno);
1676 if (status == NSS_STATUS_TRYAGAIN) {
1677 buflen *= 2;
1678 buf = (char *)realloc(buf, buflen);
1679 if (!buf) {
1680 return NULL;
1682 goto again;
1684 if (status == NSS_STATUS_NOTFOUND) {
1685 SAFE_FREE(buf);
1686 return NULL;
1688 if (status != NSS_STATUS_SUCCESS) {
1689 SAFE_FREE(buf);
1690 return NULL;
1692 return &grp;
1695 static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
1696 gid_t gid, struct group *grdst,
1697 char *buf, size_t buflen, struct group **grdstp)
1699 int ret;
1701 if (!b->fns->_nss_getgrgid_r) {
1702 return ENOENT;
1705 ret = b->fns->_nss_getgrgid_r(gid, grdst, buf, buflen, &errno);
1706 switch (ret) {
1707 case NSS_STATUS_SUCCESS:
1708 return 0;
1709 case NSS_STATUS_NOTFOUND:
1710 if (errno != 0) {
1711 return errno;
1713 return ENOENT;
1714 case NSS_STATUS_TRYAGAIN:
1715 if (errno != 0) {
1716 return errno;
1718 return ERANGE;
1719 default:
1720 if (errno != 0) {
1721 return errno;
1723 return ret;
1727 static void nwrap_module_setgrent(struct nwrap_backend *b)
1729 if (!b->fns->_nss_setgrent) {
1730 return;
1733 b->fns->_nss_setgrent();
1736 static struct group *nwrap_module_getgrent(struct nwrap_backend *b)
1738 static struct group grp;
1739 static char *buf;
1740 static int buflen = 1024;
1741 NSS_STATUS status;
1743 if (!b->fns->_nss_getgrent_r) {
1744 return NULL;
1747 if (!buf) {
1748 buf = (char *)malloc(buflen);
1751 again:
1752 status = b->fns->_nss_getgrent_r(&grp, buf, buflen, &errno);
1753 if (status == NSS_STATUS_TRYAGAIN) {
1754 buflen *= 2;
1755 buf = (char *)realloc(buf, buflen);
1756 if (!buf) {
1757 return NULL;
1759 goto again;
1761 if (status == NSS_STATUS_NOTFOUND) {
1762 SAFE_FREE(buf);
1763 return NULL;
1765 if (status != NSS_STATUS_SUCCESS) {
1766 SAFE_FREE(buf);
1767 return NULL;
1769 return &grp;
1772 static int nwrap_module_getgrent_r(struct nwrap_backend *b,
1773 struct group *grdst, char *buf,
1774 size_t buflen, struct group **grdstp)
1776 int ret;
1778 if (!b->fns->_nss_getgrent_r) {
1779 return ENOENT;
1782 ret = b->fns->_nss_getgrent_r(grdst, buf, buflen, &errno);
1783 switch (ret) {
1784 case NSS_STATUS_SUCCESS:
1785 return 0;
1786 case NSS_STATUS_NOTFOUND:
1787 if (errno != 0) {
1788 return errno;
1790 return ENOENT;
1791 case NSS_STATUS_TRYAGAIN:
1792 if (errno != 0) {
1793 return errno;
1795 return ERANGE;
1796 default:
1797 if (errno != 0) {
1798 return errno;
1800 return ret;
1804 static void nwrap_module_endgrent(struct nwrap_backend *b)
1806 if (!b->fns->_nss_endgrent) {
1807 return;
1810 b->fns->_nss_endgrent();
1814 * PUBLIC interface
1817 _PUBLIC_ struct passwd *nwrap_getpwnam(const char *name)
1819 int i;
1820 struct passwd *pwd;
1822 if (!nwrap_enabled()) {
1823 return real_getpwnam(name);
1826 for (i=0; i < nwrap_main_global->num_backends; i++) {
1827 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1828 pwd = b->ops->nw_getpwnam(b, name);
1829 if (pwd) {
1830 return pwd;
1834 return NULL;
1837 _PUBLIC_ int nwrap_getpwnam_r(const char *name, struct passwd *pwdst,
1838 char *buf, size_t buflen, struct passwd **pwdstp)
1840 int i,ret;
1842 if (!nwrap_enabled()) {
1843 return real_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
1846 for (i=0; i < nwrap_main_global->num_backends; i++) {
1847 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1848 ret = b->ops->nw_getpwnam_r(b, name, pwdst, buf, buflen, pwdstp);
1849 if (ret == ENOENT) {
1850 continue;
1852 return ret;
1855 return ENOENT;
1858 _PUBLIC_ struct passwd *nwrap_getpwuid(uid_t uid)
1860 int i;
1861 struct passwd *pwd;
1863 if (!nwrap_enabled()) {
1864 return real_getpwuid(uid);
1867 for (i=0; i < nwrap_main_global->num_backends; i++) {
1868 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1869 pwd = b->ops->nw_getpwuid(b, uid);
1870 if (pwd) {
1871 return pwd;
1875 return NULL;
1878 _PUBLIC_ int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst,
1879 char *buf, size_t buflen, struct passwd **pwdstp)
1881 int i,ret;
1883 if (!nwrap_enabled()) {
1884 return real_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
1887 for (i=0; i < nwrap_main_global->num_backends; i++) {
1888 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1889 ret = b->ops->nw_getpwuid_r(b, uid, pwdst, buf, buflen, pwdstp);
1890 if (ret == ENOENT) {
1891 continue;
1893 return ret;
1896 return ENOENT;
1899 _PUBLIC_ void nwrap_setpwent(void)
1901 int i;
1903 if (!nwrap_enabled()) {
1904 real_setpwent();
1905 return;
1908 for (i=0; i < nwrap_main_global->num_backends; i++) {
1909 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1910 b->ops->nw_setpwent(b);
1914 _PUBLIC_ struct passwd *nwrap_getpwent(void)
1916 int i;
1917 struct passwd *pwd;
1919 if (!nwrap_enabled()) {
1920 return real_getpwent();
1923 for (i=0; i < nwrap_main_global->num_backends; i++) {
1924 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1925 pwd = b->ops->nw_getpwent(b);
1926 if (pwd) {
1927 return pwd;
1931 return NULL;
1934 _PUBLIC_ int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
1935 size_t buflen, struct passwd **pwdstp)
1937 int i,ret;
1939 if (!nwrap_enabled()) {
1940 #ifdef SOLARIS_GETPWENT_R
1941 struct passwd *pw;
1942 pw = real_getpwent_r(pwdst, buf, buflen);
1943 if (!pw) {
1944 if (errno == 0) {
1945 return ENOENT;
1947 return errno;
1949 if (pwdstp) {
1950 *pwdstp = pw;
1952 return 0;
1953 #else
1954 return real_getpwent_r(pwdst, buf, buflen, pwdstp);
1955 #endif
1958 for (i=0; i < nwrap_main_global->num_backends; i++) {
1959 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1960 ret = b->ops->nw_getpwent_r(b, pwdst, buf, buflen, pwdstp);
1961 if (ret == ENOENT) {
1962 continue;
1964 return ret;
1967 return ENOENT;
1970 _PUBLIC_ void nwrap_endpwent(void)
1972 int i;
1974 if (!nwrap_enabled()) {
1975 real_endpwent();
1976 return;
1979 for (i=0; i < nwrap_main_global->num_backends; i++) {
1980 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1981 b->ops->nw_endpwent(b);
1985 _PUBLIC_ int nwrap_initgroups(const char *user, gid_t group)
1987 int i;
1989 if (!nwrap_enabled()) {
1990 return real_initgroups(user, group);
1993 for (i=0; i < nwrap_main_global->num_backends; i++) {
1994 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1995 return b->ops->nw_initgroups(b, user, group);
1998 errno = ENOENT;
1999 return -1;
2002 _PUBLIC_ struct group *nwrap_getgrnam(const char *name)
2004 int i;
2005 struct group *grp;
2007 if (!nwrap_enabled()) {
2008 return real_getgrnam(name);
2011 for (i=0; i < nwrap_main_global->num_backends; i++) {
2012 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2013 grp = b->ops->nw_getgrnam(b, name);
2014 if (grp) {
2015 return grp;
2019 return NULL;
2022 _PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *grdst,
2023 char *buf, size_t buflen, struct group **grdstp)
2025 int i,ret;
2027 if (!nwrap_enabled()) {
2028 return real_getgrnam_r(name, grdst, buf, buflen, grdstp);
2031 for (i=0; i < nwrap_main_global->num_backends; i++) {
2032 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2033 ret = b->ops->nw_getgrnam_r(b, name, grdst, buf, buflen, grdstp);
2034 if (ret == ENOENT) {
2035 continue;
2037 return ret;
2040 return ENOENT;
2043 _PUBLIC_ struct group *nwrap_getgrgid(gid_t gid)
2045 int i;
2046 struct group *grp;
2048 if (!nwrap_enabled()) {
2049 return real_getgrgid(gid);
2052 for (i=0; i < nwrap_main_global->num_backends; i++) {
2053 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2054 grp = b->ops->nw_getgrgid(b, gid);
2055 if (grp) {
2056 return grp;
2060 return NULL;
2063 _PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *grdst,
2064 char *buf, size_t buflen, struct group **grdstp)
2066 int i,ret;
2068 if (!nwrap_enabled()) {
2069 return real_getgrgid_r(gid, grdst, buf, buflen, grdstp);
2072 for (i=0; i < nwrap_main_global->num_backends; i++) {
2073 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2074 ret = b->ops->nw_getgrgid_r(b, gid, grdst, buf, buflen, grdstp);
2075 if (ret == ENOENT) {
2076 continue;
2078 return ret;
2081 return ENOENT;
2084 _PUBLIC_ void nwrap_setgrent(void)
2086 int i;
2088 if (!nwrap_enabled()) {
2089 real_setgrent();
2090 return;
2093 for (i=0; i < nwrap_main_global->num_backends; i++) {
2094 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2095 b->ops->nw_setgrent(b);
2099 _PUBLIC_ struct group *nwrap_getgrent(void)
2101 int i;
2102 struct group *grp;
2104 if (!nwrap_enabled()) {
2105 return real_getgrent();
2108 for (i=0; i < nwrap_main_global->num_backends; i++) {
2109 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2110 grp = b->ops->nw_getgrent(b);
2111 if (grp) {
2112 return grp;
2116 return NULL;
2119 _PUBLIC_ int nwrap_getgrent_r(struct group *grdst, char *buf,
2120 size_t buflen, struct group **grdstp)
2122 int i,ret;
2124 if (!nwrap_enabled()) {
2125 #ifdef SOLARIS_GETGRENT_R
2126 struct group *gr;
2127 gr = real_getgrent_r(grdst, buf, buflen);
2128 if (!gr) {
2129 if (errno == 0) {
2130 return ENOENT;
2132 return errno;
2134 if (grdstp) {
2135 *grdstp = gr;
2137 return 0;
2138 #else
2139 return real_getgrent_r(grdst, buf, buflen, grdstp);
2140 #endif
2143 for (i=0; i < nwrap_main_global->num_backends; i++) {
2144 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2145 ret = b->ops->nw_getgrent_r(b, grdst, buf, buflen, grdstp);
2146 if (ret == ENOENT) {
2147 continue;
2149 return ret;
2152 return ENOENT;
2155 _PUBLIC_ void nwrap_endgrent(void)
2157 int i;
2159 if (!nwrap_enabled()) {
2160 real_endgrent();
2161 return;
2164 for (i=0; i < nwrap_main_global->num_backends; i++) {
2165 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2166 b->ops->nw_endgrent(b);
2170 _PUBLIC_ int nwrap_getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
2172 struct group *grp;
2173 gid_t *groups_tmp;
2174 int count = 1;
2175 const char *name_of_group = "";
2177 if (!nwrap_enabled()) {
2178 return real_getgrouplist(user, group, groups, ngroups);
2181 NWRAP_DEBUG(("%s: getgrouplist called for %s\n", __location__, user));
2183 groups_tmp = (gid_t *)malloc(count * sizeof(gid_t));
2184 if (!groups_tmp) {
2185 NWRAP_ERROR(("%s:calloc failed\n",__location__));
2186 errno = ENOMEM;
2187 return -1;
2190 memcpy(groups_tmp, &group, sizeof(gid_t));
2192 grp = nwrap_getgrgid(group);
2193 if (grp) {
2194 name_of_group = grp->gr_name;
2197 nwrap_setgrent();
2198 while ((grp = nwrap_getgrent()) != NULL) {
2199 int i = 0;
2201 NWRAP_VERBOSE(("%s: inspecting %s for group membership\n",
2202 __location__, grp->gr_name));
2204 for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
2206 if ((strcmp(user, grp->gr_mem[i]) == 0) &&
2207 (strcmp(name_of_group, grp->gr_name) != 0)) {
2209 NWRAP_DEBUG(("%s: %s is member of %s\n",
2210 __location__, user, grp->gr_name));
2212 groups_tmp = (gid_t *)realloc(groups_tmp, (count + 1) * sizeof(gid_t));
2213 if (!groups_tmp) {
2214 NWRAP_ERROR(("%s:calloc failed\n",__location__));
2215 errno = ENOMEM;
2216 return -1;
2219 memcpy(&groups_tmp[count], &grp->gr_gid, sizeof(gid_t));
2220 count++;
2225 nwrap_endgrent();
2227 NWRAP_VERBOSE(("%s: %s is member of %d groups: %d\n",
2228 __location__, user, *ngroups));
2230 if (*ngroups < count) {
2231 *ngroups = count;
2232 free(groups_tmp);
2233 return -1;
2236 *ngroups = count;
2237 memcpy(groups, groups_tmp, count * sizeof(gid_t));
2238 free(groups_tmp);
2240 return count;