Forward port of Richard Sharpe's <realrichardsharpe@gmail.com> fix for bug #8970...
[Samba.git] / lib / nss_wrapper / nss_wrapper.c
blobcfa5a6871217df2a48708669e9493408f3dc6bb4
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 struct nwrap_backend *b;
469 *backends = (struct nwrap_backend *)realloc(*backends,
470 sizeof(struct nwrap_backend) * ((*num_backends) + 1));
471 if (!*backends) {
472 NWRAP_ERROR(("%s: out of memory\n",
473 __location__));
474 return false;
477 b = &((*backends)[*num_backends]);
479 b->name = name;
480 b->ops = ops;
481 b->so_path = so_path;
483 if (so_path != NULL) {
484 b->so_handle = nwrap_load_module(so_path);
485 b->fns = nwrap_load_module_fns(b);
486 if (b->fns == NULL) {
487 return false;
489 } else {
490 b->so_handle = NULL;
491 b->fns = NULL;
494 (*num_backends)++;
496 return true;
499 static void nwrap_backend_init(struct nwrap_main *r)
501 const char *winbind_so_path = getenv("NSS_WRAPPER_WINBIND_SO_PATH");
503 r->num_backends = 0;
504 r->backends = NULL;
506 if (!nwrap_module_init("files", &nwrap_files_ops, NULL,
507 &r->num_backends,
508 &r->backends)) {
509 NWRAP_ERROR(("%s: failed to initialize 'files' backend\n",
510 __location__));
511 return;
514 if (winbind_so_path && strlen(winbind_so_path)) {
515 if (!nwrap_module_init("winbind", &nwrap_module_ops, winbind_so_path,
516 &r->num_backends,
517 &r->backends)) {
518 NWRAP_ERROR(("%s: failed to initialize 'winbind' backend\n",
519 __location__));
520 return;
525 static void nwrap_init(void)
527 static bool initialized;
529 if (initialized) return;
530 initialized = true;
532 nwrap_main_global = &__nwrap_main_global;
534 nwrap_backend_init(nwrap_main_global);
536 nwrap_pw_global.cache = &__nwrap_cache_pw;
538 nwrap_pw_global.cache->path = getenv("NSS_WRAPPER_PASSWD");
539 nwrap_pw_global.cache->fd = -1;
540 nwrap_pw_global.cache->private_data = &nwrap_pw_global;
541 nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
542 nwrap_pw_global.cache->unload = nwrap_pw_unload;
544 nwrap_gr_global.cache = &__nwrap_cache_gr;
546 nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
547 nwrap_gr_global.cache->fd = -1;
548 nwrap_gr_global.cache->private_data = &nwrap_gr_global;
549 nwrap_gr_global.cache->parse_line = nwrap_gr_parse_line;
550 nwrap_gr_global.cache->unload = nwrap_gr_unload;
553 static bool nwrap_enabled(void)
555 nwrap_init();
557 if (!nwrap_pw_global.cache->path) {
558 return false;
560 if (nwrap_pw_global.cache->path[0] == '\0') {
561 return false;
563 if (!nwrap_gr_global.cache->path) {
564 return false;
566 if (nwrap_gr_global.cache->path[0] == '\0') {
567 return false;
570 return true;
573 static bool nwrap_parse_file(struct nwrap_cache *nwrap)
575 int ret;
576 uint8_t *buf = NULL;
577 char *nline;
579 if (nwrap->st.st_size == 0) {
580 NWRAP_DEBUG(("%s: size == 0\n",
581 __location__));
582 goto done;
585 if (nwrap->st.st_size > INT32_MAX) {
586 NWRAP_ERROR(("%s: size[%u] larger than INT32_MAX\n",
587 __location__, (unsigned)nwrap->st.st_size));
588 goto failed;
591 ret = lseek(nwrap->fd, 0, SEEK_SET);
592 if (ret != 0) {
593 NWRAP_ERROR(("%s: lseek - %d\n",__location__,ret));
594 goto failed;
597 buf = (uint8_t *)malloc(nwrap->st.st_size + 1);
598 if (!buf) {
599 NWRAP_ERROR(("%s: malloc failed\n",__location__));
600 goto failed;
603 ret = read(nwrap->fd, buf, nwrap->st.st_size);
604 if (ret != nwrap->st.st_size) {
605 NWRAP_ERROR(("%s: read(%u) gave %d\n",
606 __location__, (unsigned)nwrap->st.st_size, ret));
607 goto failed;
610 buf[nwrap->st.st_size] = '\0';
612 nline = (char *)buf;
613 while (nline && nline[0]) {
614 char *line;
615 char *e;
616 bool ok;
618 line = nline;
619 nline = NULL;
621 e = strchr(line, '\n');
622 if (e) {
623 e[0] = '\0';
624 e++;
625 if (e[0] == '\r') {
626 e[0] = '\0';
627 e++;
629 nline = e;
632 NWRAP_VERBOSE(("%s:'%s'\n",__location__, line));
634 if (strlen(line) == 0) {
635 continue;
638 ok = nwrap->parse_line(nwrap, line);
639 if (!ok) {
640 goto failed;
644 done:
645 nwrap->buf = buf;
646 return true;
648 failed:
649 if (buf) free(buf);
650 return false;
653 static void nwrap_files_cache_unload(struct nwrap_cache *nwrap)
655 nwrap->unload(nwrap);
657 if (nwrap->buf) free(nwrap->buf);
659 nwrap->buf = NULL;
662 static void nwrap_files_cache_reload(struct nwrap_cache *nwrap)
664 struct stat st;
665 int ret;
666 bool ok;
667 bool retried = false;
669 reopen:
670 if (nwrap->fd < 0) {
671 nwrap->fd = open(nwrap->path, O_RDONLY);
672 if (nwrap->fd < 0) {
673 NWRAP_ERROR(("%s: unable to open '%s' readonly %d:%s\n",
674 __location__,
675 nwrap->path, nwrap->fd,
676 strerror(errno)));
677 return;
679 NWRAP_VERBOSE(("%s: open '%s'\n", __location__, nwrap->path));
682 ret = fstat(nwrap->fd, &st);
683 if (ret != 0) {
684 NWRAP_ERROR(("%s: fstat(%s) - %d:%s\n",
685 __location__,
686 nwrap->path,
687 ret, strerror(errno)));
688 return;
691 if (retried == false && st.st_nlink == 0) {
692 /* maybe someone has replaced the file... */
693 NWRAP_DEBUG(("%s: st_nlink == 0, reopen %s\n",
694 __location__, nwrap->path));
695 retried = true;
696 memset(&nwrap->st, 0, sizeof(nwrap->st));
697 close(nwrap->fd);
698 nwrap->fd = -1;
699 goto reopen;
702 if (st.st_mtime == nwrap->st.st_mtime) {
703 NWRAP_VERBOSE(("%s: st_mtime[%u] hasn't changed, skip reload\n",
704 __location__, (unsigned)st.st_mtime));
705 return;
707 NWRAP_DEBUG(("%s: st_mtime has changed [%u] => [%u], start reload\n",
708 __location__, (unsigned)st.st_mtime,
709 (unsigned)nwrap->st.st_mtime));
711 nwrap->st = st;
713 nwrap_files_cache_unload(nwrap);
715 ok = nwrap_parse_file(nwrap);
716 if (!ok) {
717 NWRAP_ERROR(("%s: failed to reload %s\n",
718 __location__, nwrap->path));
719 nwrap_files_cache_unload(nwrap);
721 NWRAP_DEBUG(("%s: reloaded %s\n",
722 __location__, nwrap->path));
726 * the caller has to call nwrap_unload() on failure
728 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
730 struct nwrap_pw *nwrap_pw;
731 char *c;
732 char *p;
733 char *e;
734 struct passwd *pw;
735 size_t list_size;
737 nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
739 list_size = sizeof(*nwrap_pw->list) * (nwrap_pw->num+1);
740 pw = (struct passwd *)realloc(nwrap_pw->list, list_size);
741 if (!pw) {
742 NWRAP_ERROR(("%s:realloc(%u) failed\n",
743 __location__, list_size));
744 return false;
746 nwrap_pw->list = pw;
748 pw = &nwrap_pw->list[nwrap_pw->num];
750 c = line;
752 /* name */
753 p = strchr(c, ':');
754 if (!p) {
755 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
756 __location__, line, c));
757 return false;
759 *p = '\0';
760 p++;
761 pw->pw_name = c;
762 c = p;
764 NWRAP_VERBOSE(("name[%s]\n", pw->pw_name));
766 /* password */
767 p = strchr(c, ':');
768 if (!p) {
769 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
770 __location__, line, c));
771 return false;
773 *p = '\0';
774 p++;
775 pw->pw_passwd = c;
776 c = p;
778 NWRAP_VERBOSE(("password[%s]\n", pw->pw_passwd));
780 /* uid */
781 p = strchr(c, ':');
782 if (!p) {
783 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
784 __location__, line, c));
785 return false;
787 *p = '\0';
788 p++;
789 e = NULL;
790 pw->pw_uid = (uid_t)strtoul(c, &e, 10);
791 if (c == e) {
792 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
793 __location__, line, c, strerror(errno)));
794 return false;
796 if (e == NULL) {
797 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
798 __location__, line, c, strerror(errno)));
799 return false;
801 if (e[0] != '\0') {
802 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
803 __location__, line, c, strerror(errno)));
804 return false;
806 c = p;
808 NWRAP_VERBOSE(("uid[%u]\n", pw->pw_uid));
810 /* gid */
811 p = strchr(c, ':');
812 if (!p) {
813 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
814 __location__, line, c));
815 return false;
817 *p = '\0';
818 p++;
819 e = NULL;
820 pw->pw_gid = (gid_t)strtoul(c, &e, 10);
821 if (c == e) {
822 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
823 __location__, line, c, strerror(errno)));
824 return false;
826 if (e == NULL) {
827 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
828 __location__, line, c, strerror(errno)));
829 return false;
831 if (e[0] != '\0') {
832 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
833 __location__, line, c, strerror(errno)));
834 return false;
836 c = p;
838 NWRAP_VERBOSE(("gid[%u]\n", pw->pw_gid));
840 /* gecos */
841 p = strchr(c, ':');
842 if (!p) {
843 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
844 __location__, line, c));
845 return false;
847 *p = '\0';
848 p++;
849 pw->pw_gecos = c;
850 c = p;
852 NWRAP_VERBOSE(("gecos[%s]\n", pw->pw_gecos));
854 /* dir */
855 p = strchr(c, ':');
856 if (!p) {
857 NWRAP_ERROR(("%s:'%s'\n",__location__,c));
858 return false;
860 *p = '\0';
861 p++;
862 pw->pw_dir = c;
863 c = p;
865 NWRAP_VERBOSE(("dir[%s]\n", pw->pw_dir));
867 /* shell */
868 pw->pw_shell = c;
869 NWRAP_VERBOSE(("shell[%s]\n", pw->pw_shell));
871 NWRAP_DEBUG(("add user[%s:%s:%u:%u:%s:%s:%s]\n",
872 pw->pw_name, pw->pw_passwd,
873 pw->pw_uid, pw->pw_gid,
874 pw->pw_gecos, pw->pw_dir, pw->pw_shell));
876 nwrap_pw->num++;
877 return true;
880 static void nwrap_pw_unload(struct nwrap_cache *nwrap)
882 struct nwrap_pw *nwrap_pw;
883 nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
885 if (nwrap_pw->list) free(nwrap_pw->list);
887 nwrap_pw->list = NULL;
888 nwrap_pw->num = 0;
889 nwrap_pw->idx = 0;
892 static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
893 char *buf, size_t buflen, struct passwd **dstp)
895 char *first;
896 char *last;
897 off_t ofs;
899 first = src->pw_name;
901 last = src->pw_shell;
902 while (*last) last++;
904 ofs = PTR_DIFF(last + 1, first);
906 if (ofs > buflen) {
907 return ERANGE;
910 memcpy(buf, first, ofs);
912 ofs = PTR_DIFF(src->pw_name, first);
913 dst->pw_name = buf + ofs;
914 ofs = PTR_DIFF(src->pw_passwd, first);
915 dst->pw_passwd = buf + ofs;
916 dst->pw_uid = src->pw_uid;
917 dst->pw_gid = src->pw_gid;
918 ofs = PTR_DIFF(src->pw_gecos, first);
919 dst->pw_gecos = buf + ofs;
920 ofs = PTR_DIFF(src->pw_dir, first);
921 dst->pw_dir = buf + ofs;
922 ofs = PTR_DIFF(src->pw_shell, first);
923 dst->pw_shell = buf + ofs;
925 if (dstp) {
926 *dstp = dst;
929 return 0;
933 * the caller has to call nwrap_unload() on failure
935 static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
937 struct nwrap_gr *nwrap_gr;
938 char *c;
939 char *p;
940 char *e;
941 struct group *gr;
942 size_t list_size;
943 unsigned nummem;
945 nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
947 list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
948 gr = (struct group *)realloc(nwrap_gr->list, list_size);
949 if (!gr) {
950 NWRAP_ERROR(("%s:realloc failed\n",__location__));
951 return false;
953 nwrap_gr->list = gr;
955 gr = &nwrap_gr->list[nwrap_gr->num];
957 c = line;
959 /* name */
960 p = strchr(c, ':');
961 if (!p) {
962 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
963 __location__, line, c));
964 return false;
966 *p = '\0';
967 p++;
968 gr->gr_name = c;
969 c = p;
971 NWRAP_VERBOSE(("name[%s]\n", gr->gr_name));
973 /* password */
974 p = strchr(c, ':');
975 if (!p) {
976 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
977 __location__, line, c));
978 return false;
980 *p = '\0';
981 p++;
982 gr->gr_passwd = c;
983 c = p;
985 NWRAP_VERBOSE(("password[%s]\n", gr->gr_passwd));
987 /* gid */
988 p = strchr(c, ':');
989 if (!p) {
990 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
991 __location__, line, c));
992 return false;
994 *p = '\0';
995 p++;
996 e = NULL;
997 gr->gr_gid = (gid_t)strtoul(c, &e, 10);
998 if (c == e) {
999 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
1000 __location__, line, c, strerror(errno)));
1001 return false;
1003 if (e == NULL) {
1004 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
1005 __location__, line, c, strerror(errno)));
1006 return false;
1008 if (e[0] != '\0') {
1009 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
1010 __location__, line, c, strerror(errno)));
1011 return false;
1013 c = p;
1015 NWRAP_VERBOSE(("gid[%u]\n", gr->gr_gid));
1017 /* members */
1018 gr->gr_mem = (char **)malloc(sizeof(char *));
1019 if (!gr->gr_mem) {
1020 NWRAP_ERROR(("%s:calloc failed\n",__location__));
1021 return false;
1023 gr->gr_mem[0] = NULL;
1025 for(nummem=0; p; nummem++) {
1026 char **m;
1027 size_t m_size;
1028 c = p;
1029 p = strchr(c, ',');
1030 if (p) {
1031 *p = '\0';
1032 p++;
1035 if (strlen(c) == 0) {
1036 break;
1039 m_size = sizeof(char *) * (nummem+2);
1040 m = (char **)realloc(gr->gr_mem, m_size);
1041 if (!m) {
1042 NWRAP_ERROR(("%s:realloc(%u) failed\n",
1043 __location__, m_size));
1044 return false;
1046 gr->gr_mem = m;
1047 gr->gr_mem[nummem] = c;
1048 gr->gr_mem[nummem+1] = NULL;
1050 NWRAP_VERBOSE(("member[%u]: '%s'\n", nummem, gr->gr_mem[nummem]));
1053 NWRAP_DEBUG(("add group[%s:%s:%u:] with %u members\n",
1054 gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem));
1056 nwrap_gr->num++;
1057 return true;
1060 static void nwrap_gr_unload(struct nwrap_cache *nwrap)
1062 int i;
1063 struct nwrap_gr *nwrap_gr;
1064 nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
1066 if (nwrap_gr->list) {
1067 for (i=0; i < nwrap_gr->num; i++) {
1068 if (nwrap_gr->list[i].gr_mem) {
1069 free(nwrap_gr->list[i].gr_mem);
1072 free(nwrap_gr->list);
1075 nwrap_gr->list = NULL;
1076 nwrap_gr->num = 0;
1077 nwrap_gr->idx = 0;
1080 static int nwrap_gr_copy_r(const struct group *src, struct group *dst,
1081 char *buf, size_t buflen, struct group **dstp)
1083 char *first;
1084 char **lastm;
1085 char *last = NULL;
1086 off_t ofsb;
1087 off_t ofsm;
1088 off_t ofs;
1089 unsigned i;
1091 first = src->gr_name;
1093 lastm = src->gr_mem;
1094 while (*lastm) {
1095 last = *lastm;
1096 lastm++;
1099 if (last == NULL) {
1100 last = src->gr_passwd;
1102 while (*last) last++;
1104 ofsb = PTR_DIFF(last + 1, first);
1105 ofsm = PTR_DIFF(lastm + 1, src->gr_mem);
1107 if ((ofsb + ofsm) > buflen) {
1108 return ERANGE;
1111 memcpy(buf, first, ofsb);
1112 memcpy(buf + ofsb, src->gr_mem, ofsm);
1114 ofs = PTR_DIFF(src->gr_name, first);
1115 dst->gr_name = buf + ofs;
1116 ofs = PTR_DIFF(src->gr_passwd, first);
1117 dst->gr_passwd = buf + ofs;
1118 dst->gr_gid = src->gr_gid;
1120 dst->gr_mem = (char **)(buf + ofsb);
1121 for (i=0; src->gr_mem[i]; i++) {
1122 ofs = PTR_DIFF(src->gr_mem[i], first);
1123 dst->gr_mem[i] = buf + ofs;
1126 if (dstp) {
1127 *dstp = dst;
1130 return 0;
1133 /* user functions */
1134 static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
1135 const char *name)
1137 int i;
1139 nwrap_files_cache_reload(nwrap_pw_global.cache);
1141 for (i=0; i<nwrap_pw_global.num; i++) {
1142 if (strcmp(nwrap_pw_global.list[i].pw_name, name) == 0) {
1143 NWRAP_DEBUG(("%s: user[%s] found\n",
1144 __location__, name));
1145 return &nwrap_pw_global.list[i];
1147 NWRAP_VERBOSE(("%s: user[%s] does not match [%s]\n",
1148 __location__, name,
1149 nwrap_pw_global.list[i].pw_name));
1152 NWRAP_DEBUG(("%s: user[%s] not found\n", __location__, name));
1154 errno = ENOENT;
1155 return NULL;
1158 static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
1159 const char *name, struct passwd *pwdst,
1160 char *buf, size_t buflen, struct passwd **pwdstp)
1162 struct passwd *pw;
1164 pw = nwrap_files_getpwnam(b, name);
1165 if (!pw) {
1166 if (errno == 0) {
1167 return ENOENT;
1169 return errno;
1172 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
1175 static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
1176 uid_t uid)
1178 int i;
1180 nwrap_files_cache_reload(nwrap_pw_global.cache);
1182 for (i=0; i<nwrap_pw_global.num; i++) {
1183 if (nwrap_pw_global.list[i].pw_uid == uid) {
1184 NWRAP_DEBUG(("%s: uid[%u] found\n",
1185 __location__, uid));
1186 return &nwrap_pw_global.list[i];
1188 NWRAP_VERBOSE(("%s: uid[%u] does not match [%u]\n",
1189 __location__, uid,
1190 nwrap_pw_global.list[i].pw_uid));
1193 NWRAP_DEBUG(("%s: uid[%u] not found\n", __location__, uid));
1195 errno = ENOENT;
1196 return NULL;
1199 static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
1200 uid_t uid, struct passwd *pwdst,
1201 char *buf, size_t buflen, struct passwd **pwdstp)
1203 struct passwd *pw;
1205 pw = nwrap_files_getpwuid(b, uid);
1206 if (!pw) {
1207 if (errno == 0) {
1208 return ENOENT;
1210 return errno;
1213 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
1216 /* user enum functions */
1217 static void nwrap_files_setpwent(struct nwrap_backend *b)
1219 nwrap_pw_global.idx = 0;
1222 static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b)
1224 struct passwd *pw;
1226 if (nwrap_pw_global.idx == 0) {
1227 nwrap_files_cache_reload(nwrap_pw_global.cache);
1230 if (nwrap_pw_global.idx >= nwrap_pw_global.num) {
1231 errno = ENOENT;
1232 return NULL;
1235 pw = &nwrap_pw_global.list[nwrap_pw_global.idx++];
1237 NWRAP_VERBOSE(("%s: return user[%s] uid[%u]\n",
1238 __location__, pw->pw_name, pw->pw_uid));
1240 return pw;
1243 static int nwrap_files_getpwent_r(struct nwrap_backend *b,
1244 struct passwd *pwdst, char *buf,
1245 size_t buflen, struct passwd **pwdstp)
1247 struct passwd *pw;
1249 pw = nwrap_files_getpwent(b);
1250 if (!pw) {
1251 if (errno == 0) {
1252 return ENOENT;
1254 return errno;
1257 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
1260 static void nwrap_files_endpwent(struct nwrap_backend *b)
1262 nwrap_pw_global.idx = 0;
1265 /* misc functions */
1266 static int nwrap_files_initgroups(struct nwrap_backend *b,
1267 const char *user, gid_t group)
1269 /* TODO: maybe we should also fake this... */
1270 return EPERM;
1273 /* group functions */
1274 static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
1275 const char *name)
1277 int i;
1279 nwrap_files_cache_reload(nwrap_gr_global.cache);
1281 for (i=0; i<nwrap_gr_global.num; i++) {
1282 if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) {
1283 NWRAP_DEBUG(("%s: group[%s] found\n",
1284 __location__, name));
1285 return &nwrap_gr_global.list[i];
1287 NWRAP_VERBOSE(("%s: group[%s] does not match [%s]\n",
1288 __location__, name,
1289 nwrap_gr_global.list[i].gr_name));
1292 NWRAP_DEBUG(("%s: group[%s] not found\n", __location__, name));
1294 errno = ENOENT;
1295 return NULL;
1298 static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
1299 const char *name, struct group *grdst,
1300 char *buf, size_t buflen, struct group **grdstp)
1302 struct group *gr;
1304 gr = nwrap_files_getgrnam(b, name);
1305 if (!gr) {
1306 if (errno == 0) {
1307 return ENOENT;
1309 return errno;
1312 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
1315 static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
1316 gid_t gid)
1318 int i;
1320 nwrap_files_cache_reload(nwrap_gr_global.cache);
1322 for (i=0; i<nwrap_gr_global.num; i++) {
1323 if (nwrap_gr_global.list[i].gr_gid == gid) {
1324 NWRAP_DEBUG(("%s: gid[%u] found\n",
1325 __location__, gid));
1326 return &nwrap_gr_global.list[i];
1328 NWRAP_VERBOSE(("%s: gid[%u] does not match [%u]\n",
1329 __location__, gid,
1330 nwrap_gr_global.list[i].gr_gid));
1333 NWRAP_DEBUG(("%s: gid[%u] not found\n", __location__, gid));
1335 errno = ENOENT;
1336 return NULL;
1339 static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
1340 gid_t gid, struct group *grdst,
1341 char *buf, size_t buflen, struct group **grdstp)
1343 struct group *gr;
1345 gr = nwrap_files_getgrgid(b, gid);
1346 if (!gr) {
1347 if (errno == 0) {
1348 return ENOENT;
1350 return errno;
1353 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
1356 /* group enum functions */
1357 static void nwrap_files_setgrent(struct nwrap_backend *b)
1359 nwrap_gr_global.idx = 0;
1362 static struct group *nwrap_files_getgrent(struct nwrap_backend *b)
1364 struct group *gr;
1366 if (nwrap_gr_global.idx == 0) {
1367 nwrap_files_cache_reload(nwrap_gr_global.cache);
1370 if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
1371 errno = ENOENT;
1372 return NULL;
1375 gr = &nwrap_gr_global.list[nwrap_gr_global.idx++];
1377 NWRAP_VERBOSE(("%s: return group[%s] gid[%u]\n",
1378 __location__, gr->gr_name, gr->gr_gid));
1380 return gr;
1383 static int nwrap_files_getgrent_r(struct nwrap_backend *b,
1384 struct group *grdst, char *buf,
1385 size_t buflen, struct group **grdstp)
1387 struct group *gr;
1389 gr = nwrap_files_getgrent(b);
1390 if (!gr) {
1391 if (errno == 0) {
1392 return ENOENT;
1394 return errno;
1397 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
1400 static void nwrap_files_endgrent(struct nwrap_backend *b)
1402 nwrap_gr_global.idx = 0;
1406 * module backend
1409 #ifndef SAFE_FREE
1410 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
1411 #endif
1413 static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
1414 const char *name)
1416 static struct passwd pwd;
1417 static char buf[1000];
1418 NSS_STATUS status;
1420 if (!b->fns->_nss_getpwnam_r) {
1421 return NULL;
1424 status = b->fns->_nss_getpwnam_r(name, &pwd, buf, sizeof(buf), &errno);
1425 if (status == NSS_STATUS_NOTFOUND) {
1426 return NULL;
1428 if (status != NSS_STATUS_SUCCESS) {
1429 return NULL;
1431 return &pwd;
1434 static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
1435 const char *name, struct passwd *pwdst,
1436 char *buf, size_t buflen, struct passwd **pwdstp)
1438 int ret;
1440 if (!b->fns->_nss_getpwnam_r) {
1441 return NSS_STATUS_NOTFOUND;
1444 ret = b->fns->_nss_getpwnam_r(name, pwdst, buf, buflen, &errno);
1445 switch (ret) {
1446 case NSS_STATUS_SUCCESS:
1447 return 0;
1448 case NSS_STATUS_NOTFOUND:
1449 if (errno != 0) {
1450 return errno;
1452 return ENOENT;
1453 case NSS_STATUS_TRYAGAIN:
1454 if (errno != 0) {
1455 return errno;
1457 return ERANGE;
1458 default:
1459 if (errno != 0) {
1460 return errno;
1462 return ret;
1466 static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
1467 uid_t uid)
1469 static struct passwd pwd;
1470 static char buf[1000];
1471 NSS_STATUS status;
1473 if (!b->fns->_nss_getpwuid_r) {
1474 return NULL;
1477 status = b->fns->_nss_getpwuid_r(uid, &pwd, buf, sizeof(buf), &errno);
1478 if (status == NSS_STATUS_NOTFOUND) {
1479 return NULL;
1481 if (status != NSS_STATUS_SUCCESS) {
1482 return NULL;
1484 return &pwd;
1487 static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
1488 uid_t uid, struct passwd *pwdst,
1489 char *buf, size_t buflen, struct passwd **pwdstp)
1491 int ret;
1493 if (!b->fns->_nss_getpwuid_r) {
1494 return ENOENT;
1497 ret = b->fns->_nss_getpwuid_r(uid, pwdst, buf, buflen, &errno);
1498 switch (ret) {
1499 case NSS_STATUS_SUCCESS:
1500 return 0;
1501 case NSS_STATUS_NOTFOUND:
1502 if (errno != 0) {
1503 return errno;
1505 return ENOENT;
1506 case NSS_STATUS_TRYAGAIN:
1507 if (errno != 0) {
1508 return errno;
1510 return ERANGE;
1511 default:
1512 if (errno != 0) {
1513 return errno;
1515 return ret;
1519 static void nwrap_module_setpwent(struct nwrap_backend *b)
1521 if (!b->fns->_nss_setpwent) {
1522 return;
1525 b->fns->_nss_setpwent();
1528 static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b)
1530 static struct passwd pwd;
1531 static char buf[1000];
1532 NSS_STATUS status;
1534 if (!b->fns->_nss_getpwent_r) {
1535 return NULL;
1538 status = b->fns->_nss_getpwent_r(&pwd, buf, sizeof(buf), &errno);
1539 if (status == NSS_STATUS_NOTFOUND) {
1540 return NULL;
1542 if (status != NSS_STATUS_SUCCESS) {
1543 return NULL;
1545 return &pwd;
1548 static int nwrap_module_getpwent_r(struct nwrap_backend *b,
1549 struct passwd *pwdst, char *buf,
1550 size_t buflen, struct passwd **pwdstp)
1552 int ret;
1554 if (!b->fns->_nss_getpwent_r) {
1555 return ENOENT;
1558 ret = b->fns->_nss_getpwent_r(pwdst, buf, buflen, &errno);
1559 switch (ret) {
1560 case NSS_STATUS_SUCCESS:
1561 return 0;
1562 case NSS_STATUS_NOTFOUND:
1563 if (errno != 0) {
1564 return errno;
1566 return ENOENT;
1567 case NSS_STATUS_TRYAGAIN:
1568 if (errno != 0) {
1569 return errno;
1571 return ERANGE;
1572 default:
1573 if (errno != 0) {
1574 return errno;
1576 return ret;
1580 static void nwrap_module_endpwent(struct nwrap_backend *b)
1582 if (!b->fns->_nss_endpwent) {
1583 return;
1586 b->fns->_nss_endpwent();
1589 static int nwrap_module_initgroups(struct nwrap_backend *b,
1590 const char *user, gid_t group)
1592 gid_t *groups;
1593 long int start;
1594 long int size;
1596 if (!b->fns->_nss_initgroups) {
1597 return NSS_STATUS_UNAVAIL;
1600 return b->fns->_nss_initgroups(user, group, &start, &size, &groups, 0, &errno);
1603 static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
1604 const char *name)
1606 static struct group grp;
1607 static char *buf;
1608 static int buflen = 1000;
1609 NSS_STATUS status;
1611 if (!b->fns->_nss_getgrnam_r) {
1612 return NULL;
1615 if (!buf) {
1616 buf = (char *)malloc(buflen);
1618 again:
1619 status = b->fns->_nss_getgrnam_r(name, &grp, buf, buflen, &errno);
1620 if (status == NSS_STATUS_TRYAGAIN) {
1621 buflen *= 2;
1622 buf = (char *)realloc(buf, buflen);
1623 if (!buf) {
1624 return NULL;
1626 goto again;
1628 if (status == NSS_STATUS_NOTFOUND) {
1629 SAFE_FREE(buf);
1630 return NULL;
1632 if (status != NSS_STATUS_SUCCESS) {
1633 SAFE_FREE(buf);
1634 return NULL;
1636 return &grp;
1639 static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
1640 const char *name, struct group *grdst,
1641 char *buf, size_t buflen, struct group **grdstp)
1643 int ret;
1645 if (!b->fns->_nss_getgrnam_r) {
1646 return ENOENT;
1649 ret = b->fns->_nss_getgrnam_r(name, grdst, buf, buflen, &errno);
1650 switch (ret) {
1651 case NSS_STATUS_SUCCESS:
1652 return 0;
1653 case NSS_STATUS_NOTFOUND:
1654 if (errno != 0) {
1655 return errno;
1657 return ENOENT;
1658 case NSS_STATUS_TRYAGAIN:
1659 if (errno != 0) {
1660 return errno;
1662 return ERANGE;
1663 default:
1664 if (errno != 0) {
1665 return errno;
1667 return ret;
1671 static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
1672 gid_t gid)
1674 static struct group grp;
1675 static char *buf;
1676 static int buflen = 1000;
1677 NSS_STATUS status;
1679 if (!b->fns->_nss_getgrgid_r) {
1680 return NULL;
1683 if (!buf) {
1684 buf = (char *)malloc(buflen);
1687 again:
1688 status = b->fns->_nss_getgrgid_r(gid, &grp, buf, buflen, &errno);
1689 if (status == NSS_STATUS_TRYAGAIN) {
1690 buflen *= 2;
1691 buf = (char *)realloc(buf, buflen);
1692 if (!buf) {
1693 return NULL;
1695 goto again;
1697 if (status == NSS_STATUS_NOTFOUND) {
1698 SAFE_FREE(buf);
1699 return NULL;
1701 if (status != NSS_STATUS_SUCCESS) {
1702 SAFE_FREE(buf);
1703 return NULL;
1705 return &grp;
1708 static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
1709 gid_t gid, struct group *grdst,
1710 char *buf, size_t buflen, struct group **grdstp)
1712 int ret;
1714 if (!b->fns->_nss_getgrgid_r) {
1715 return ENOENT;
1718 ret = b->fns->_nss_getgrgid_r(gid, grdst, buf, buflen, &errno);
1719 switch (ret) {
1720 case NSS_STATUS_SUCCESS:
1721 return 0;
1722 case NSS_STATUS_NOTFOUND:
1723 if (errno != 0) {
1724 return errno;
1726 return ENOENT;
1727 case NSS_STATUS_TRYAGAIN:
1728 if (errno != 0) {
1729 return errno;
1731 return ERANGE;
1732 default:
1733 if (errno != 0) {
1734 return errno;
1736 return ret;
1740 static void nwrap_module_setgrent(struct nwrap_backend *b)
1742 if (!b->fns->_nss_setgrent) {
1743 return;
1746 b->fns->_nss_setgrent();
1749 static struct group *nwrap_module_getgrent(struct nwrap_backend *b)
1751 static struct group grp;
1752 static char *buf;
1753 static int buflen = 1024;
1754 NSS_STATUS status;
1756 if (!b->fns->_nss_getgrent_r) {
1757 return NULL;
1760 if (!buf) {
1761 buf = (char *)malloc(buflen);
1764 again:
1765 status = b->fns->_nss_getgrent_r(&grp, buf, buflen, &errno);
1766 if (status == NSS_STATUS_TRYAGAIN) {
1767 buflen *= 2;
1768 buf = (char *)realloc(buf, buflen);
1769 if (!buf) {
1770 return NULL;
1772 goto again;
1774 if (status == NSS_STATUS_NOTFOUND) {
1775 SAFE_FREE(buf);
1776 return NULL;
1778 if (status != NSS_STATUS_SUCCESS) {
1779 SAFE_FREE(buf);
1780 return NULL;
1782 return &grp;
1785 static int nwrap_module_getgrent_r(struct nwrap_backend *b,
1786 struct group *grdst, char *buf,
1787 size_t buflen, struct group **grdstp)
1789 int ret;
1791 if (!b->fns->_nss_getgrent_r) {
1792 return ENOENT;
1795 ret = b->fns->_nss_getgrent_r(grdst, buf, buflen, &errno);
1796 switch (ret) {
1797 case NSS_STATUS_SUCCESS:
1798 return 0;
1799 case NSS_STATUS_NOTFOUND:
1800 if (errno != 0) {
1801 return errno;
1803 return ENOENT;
1804 case NSS_STATUS_TRYAGAIN:
1805 if (errno != 0) {
1806 return errno;
1808 return ERANGE;
1809 default:
1810 if (errno != 0) {
1811 return errno;
1813 return ret;
1817 static void nwrap_module_endgrent(struct nwrap_backend *b)
1819 if (!b->fns->_nss_endgrent) {
1820 return;
1823 b->fns->_nss_endgrent();
1827 * PUBLIC interface
1830 _PUBLIC_ struct passwd *nwrap_getpwnam(const char *name)
1832 int i;
1833 struct passwd *pwd;
1835 if (!nwrap_enabled()) {
1836 return real_getpwnam(name);
1839 for (i=0; i < nwrap_main_global->num_backends; i++) {
1840 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1841 pwd = b->ops->nw_getpwnam(b, name);
1842 if (pwd) {
1843 return pwd;
1847 return NULL;
1850 _PUBLIC_ int nwrap_getpwnam_r(const char *name, struct passwd *pwdst,
1851 char *buf, size_t buflen, struct passwd **pwdstp)
1853 int i,ret;
1855 if (!nwrap_enabled()) {
1856 return real_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
1859 for (i=0; i < nwrap_main_global->num_backends; i++) {
1860 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1861 ret = b->ops->nw_getpwnam_r(b, name, pwdst, buf, buflen, pwdstp);
1862 if (ret == ENOENT) {
1863 continue;
1865 return ret;
1868 return ENOENT;
1871 _PUBLIC_ struct passwd *nwrap_getpwuid(uid_t uid)
1873 int i;
1874 struct passwd *pwd;
1876 if (!nwrap_enabled()) {
1877 return real_getpwuid(uid);
1880 for (i=0; i < nwrap_main_global->num_backends; i++) {
1881 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1882 pwd = b->ops->nw_getpwuid(b, uid);
1883 if (pwd) {
1884 return pwd;
1888 return NULL;
1891 _PUBLIC_ int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst,
1892 char *buf, size_t buflen, struct passwd **pwdstp)
1894 int i,ret;
1896 if (!nwrap_enabled()) {
1897 return real_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
1900 for (i=0; i < nwrap_main_global->num_backends; i++) {
1901 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1902 ret = b->ops->nw_getpwuid_r(b, uid, pwdst, buf, buflen, pwdstp);
1903 if (ret == ENOENT) {
1904 continue;
1906 return ret;
1909 return ENOENT;
1912 _PUBLIC_ void nwrap_setpwent(void)
1914 int i;
1916 if (!nwrap_enabled()) {
1917 real_setpwent();
1918 return;
1921 for (i=0; i < nwrap_main_global->num_backends; i++) {
1922 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1923 b->ops->nw_setpwent(b);
1927 _PUBLIC_ struct passwd *nwrap_getpwent(void)
1929 int i;
1930 struct passwd *pwd;
1932 if (!nwrap_enabled()) {
1933 return real_getpwent();
1936 for (i=0; i < nwrap_main_global->num_backends; i++) {
1937 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1938 pwd = b->ops->nw_getpwent(b);
1939 if (pwd) {
1940 return pwd;
1944 return NULL;
1947 _PUBLIC_ int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
1948 size_t buflen, struct passwd **pwdstp)
1950 int i,ret;
1952 if (!nwrap_enabled()) {
1953 #ifdef SOLARIS_GETPWENT_R
1954 struct passwd *pw;
1955 pw = real_getpwent_r(pwdst, buf, buflen);
1956 if (!pw) {
1957 if (errno == 0) {
1958 return ENOENT;
1960 return errno;
1962 if (pwdstp) {
1963 *pwdstp = pw;
1965 return 0;
1966 #else
1967 return real_getpwent_r(pwdst, buf, buflen, pwdstp);
1968 #endif
1971 for (i=0; i < nwrap_main_global->num_backends; i++) {
1972 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1973 ret = b->ops->nw_getpwent_r(b, pwdst, buf, buflen, pwdstp);
1974 if (ret == ENOENT) {
1975 continue;
1977 return ret;
1980 return ENOENT;
1983 _PUBLIC_ void nwrap_endpwent(void)
1985 int i;
1987 if (!nwrap_enabled()) {
1988 real_endpwent();
1989 return;
1992 for (i=0; i < nwrap_main_global->num_backends; i++) {
1993 struct nwrap_backend *b = &nwrap_main_global->backends[i];
1994 b->ops->nw_endpwent(b);
1998 _PUBLIC_ int nwrap_initgroups(const char *user, gid_t group)
2000 int i;
2002 if (!nwrap_enabled()) {
2003 return real_initgroups(user, group);
2006 for (i=0; i < nwrap_main_global->num_backends; i++) {
2007 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2008 return b->ops->nw_initgroups(b, user, group);
2011 errno = ENOENT;
2012 return -1;
2015 _PUBLIC_ struct group *nwrap_getgrnam(const char *name)
2017 int i;
2018 struct group *grp;
2020 if (!nwrap_enabled()) {
2021 return real_getgrnam(name);
2024 for (i=0; i < nwrap_main_global->num_backends; i++) {
2025 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2026 grp = b->ops->nw_getgrnam(b, name);
2027 if (grp) {
2028 return grp;
2032 return NULL;
2035 _PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *grdst,
2036 char *buf, size_t buflen, struct group **grdstp)
2038 int i,ret;
2040 if (!nwrap_enabled()) {
2041 return real_getgrnam_r(name, grdst, buf, buflen, grdstp);
2044 for (i=0; i < nwrap_main_global->num_backends; i++) {
2045 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2046 ret = b->ops->nw_getgrnam_r(b, name, grdst, buf, buflen, grdstp);
2047 if (ret == ENOENT) {
2048 continue;
2050 return ret;
2053 return ENOENT;
2056 _PUBLIC_ struct group *nwrap_getgrgid(gid_t gid)
2058 int i;
2059 struct group *grp;
2061 if (!nwrap_enabled()) {
2062 return real_getgrgid(gid);
2065 for (i=0; i < nwrap_main_global->num_backends; i++) {
2066 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2067 grp = b->ops->nw_getgrgid(b, gid);
2068 if (grp) {
2069 return grp;
2073 return NULL;
2076 _PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *grdst,
2077 char *buf, size_t buflen, struct group **grdstp)
2079 int i,ret;
2081 if (!nwrap_enabled()) {
2082 return real_getgrgid_r(gid, grdst, buf, buflen, grdstp);
2085 for (i=0; i < nwrap_main_global->num_backends; i++) {
2086 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2087 ret = b->ops->nw_getgrgid_r(b, gid, grdst, buf, buflen, grdstp);
2088 if (ret == ENOENT) {
2089 continue;
2091 return ret;
2094 return ENOENT;
2097 _PUBLIC_ void nwrap_setgrent(void)
2099 int i;
2101 if (!nwrap_enabled()) {
2102 real_setgrent();
2103 return;
2106 for (i=0; i < nwrap_main_global->num_backends; i++) {
2107 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2108 b->ops->nw_setgrent(b);
2112 _PUBLIC_ struct group *nwrap_getgrent(void)
2114 int i;
2115 struct group *grp;
2117 if (!nwrap_enabled()) {
2118 return real_getgrent();
2121 for (i=0; i < nwrap_main_global->num_backends; i++) {
2122 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2123 grp = b->ops->nw_getgrent(b);
2124 if (grp) {
2125 return grp;
2129 return NULL;
2132 _PUBLIC_ int nwrap_getgrent_r(struct group *grdst, char *buf,
2133 size_t buflen, struct group **grdstp)
2135 int i,ret;
2137 if (!nwrap_enabled()) {
2138 #ifdef SOLARIS_GETGRENT_R
2139 struct group *gr;
2140 gr = real_getgrent_r(grdst, buf, buflen);
2141 if (!gr) {
2142 if (errno == 0) {
2143 return ENOENT;
2145 return errno;
2147 if (grdstp) {
2148 *grdstp = gr;
2150 return 0;
2151 #else
2152 return real_getgrent_r(grdst, buf, buflen, grdstp);
2153 #endif
2156 for (i=0; i < nwrap_main_global->num_backends; i++) {
2157 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2158 ret = b->ops->nw_getgrent_r(b, grdst, buf, buflen, grdstp);
2159 if (ret == ENOENT) {
2160 continue;
2162 return ret;
2165 return ENOENT;
2168 _PUBLIC_ void nwrap_endgrent(void)
2170 int i;
2172 if (!nwrap_enabled()) {
2173 real_endgrent();
2174 return;
2177 for (i=0; i < nwrap_main_global->num_backends; i++) {
2178 struct nwrap_backend *b = &nwrap_main_global->backends[i];
2179 b->ops->nw_endgrent(b);
2183 _PUBLIC_ int nwrap_getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
2185 struct group *grp;
2186 gid_t *groups_tmp;
2187 int count = 1;
2188 const char *name_of_group = "";
2190 if (!nwrap_enabled()) {
2191 return real_getgrouplist(user, group, groups, ngroups);
2194 NWRAP_DEBUG(("%s: getgrouplist called for %s\n", __location__, user));
2196 groups_tmp = (gid_t *)malloc(count * sizeof(gid_t));
2197 if (!groups_tmp) {
2198 NWRAP_ERROR(("%s:calloc failed\n",__location__));
2199 errno = ENOMEM;
2200 return -1;
2203 memcpy(groups_tmp, &group, sizeof(gid_t));
2205 grp = nwrap_getgrgid(group);
2206 if (grp) {
2207 name_of_group = grp->gr_name;
2210 nwrap_setgrent();
2211 while ((grp = nwrap_getgrent()) != NULL) {
2212 int i = 0;
2214 NWRAP_VERBOSE(("%s: inspecting %s for group membership\n",
2215 __location__, grp->gr_name));
2217 for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
2219 if ((strcmp(user, grp->gr_mem[i]) == 0) &&
2220 (strcmp(name_of_group, grp->gr_name) != 0)) {
2222 NWRAP_DEBUG(("%s: %s is member of %s\n",
2223 __location__, user, grp->gr_name));
2225 groups_tmp = (gid_t *)realloc(groups_tmp, (count + 1) * sizeof(gid_t));
2226 if (!groups_tmp) {
2227 NWRAP_ERROR(("%s:calloc failed\n",__location__));
2228 errno = ENOMEM;
2229 return -1;
2232 memcpy(&groups_tmp[count], &grp->gr_gid, sizeof(gid_t));
2233 count++;
2238 nwrap_endgrent();
2240 NWRAP_VERBOSE(("%s: %s is member of %d groups: %d\n",
2241 __location__, user, *ngroups));
2243 if (*ngroups < count) {
2244 *ngroups = count;
2245 free(groups_tmp);
2246 return -1;
2249 *ngroups = count;
2250 memcpy(groups, groups_tmp, count * sizeof(gid_t));
2251 free(groups_tmp);
2253 return count;