smbd: Remove "st" from struct open_symlink_err
[Samba.git] / third_party / nss_wrapper / nss_wrapper.c
blob3399f06412a2e03b2e1c70f40d6ed2b588cf6e8e
1 /*
2 * BSD 3-Clause License
4 * Copyright (c) 2007, Stefan Metzmacher <metze@samba.org>
5 * Copyright (c) 2009, Guenther Deschner <gd@samba.org>
6 * Copyright (c) 2014-2015, Michael Adam <obnox@samba.org>
7 * Copyright (c) 2015, Robin Hack <hack.robin@gmail.com>
8 * Copyright (c) 2013-2018, Andreas Schneider <asn@samba.org>
9 * All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the author nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #include "config.h"
41 #include <pthread.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/socket.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <stdarg.h>
49 #include <stdbool.h>
50 #include <stddef.h>
51 #include <stdio.h>
52 #include <stdint.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <ctype.h>
57 #include <limits.h>
59 #include <netinet/in.h>
61 #include <search.h>
62 #include <assert.h>
64 #include "nss_utils.h"
66 * Defining _POSIX_PTHREAD_SEMANTICS before including pwd.h and grp.h gives us
67 * the posix getpwnam_r(), getpwuid_r(), getgrnam_r and getgrgid_r calls on
68 * Solaris
70 #ifndef _POSIX_PTHREAD_SEMANTICS
71 #define _POSIX_PTHREAD_SEMANTICS
72 #endif
74 #include <pwd.h>
75 #include <grp.h>
76 #ifdef HAVE_SHADOW_H
77 #include <shadow.h>
78 #endif /* HAVE_SHADOW_H */
80 #include <netdb.h>
81 #include <arpa/inet.h>
82 #include <netinet/in.h>
84 #include <dlfcn.h>
86 #if defined(HAVE_NSS_H)
87 /* Linux and BSD */
88 #include <nss.h>
90 typedef enum nss_status NSS_STATUS;
91 #elif defined(HAVE_NSS_COMMON_H)
92 /* Solaris */
93 #include <nss_common.h>
94 #include <nss_dbdefs.h>
95 #include <nsswitch.h>
97 typedef nss_status_t NSS_STATUS;
99 # define NSS_STATUS_SUCCESS NSS_SUCCESS
100 # define NSS_STATUS_NOTFOUND NSS_NOTFOUND
101 # define NSS_STATUS_UNAVAIL NSS_UNAVAIL
102 # define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN
103 #else
104 # error "No nsswitch support detected"
105 #endif
107 #ifndef PTR_DIFF
108 #define PTR_DIFF(p1, p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2)))
109 #endif
111 #ifndef _PUBLIC_
112 #define _PUBLIC_
113 #endif
115 #ifndef EAI_NODATA
116 #define EAI_NODATA EAI_NONAME
117 #endif
119 #ifndef EAI_ADDRFAMILY
120 #define EAI_ADDRFAMILY EAI_FAMILY
121 #endif
123 #ifndef __STRING
124 #define __STRING(x) #x
125 #endif
127 #ifndef __STRINGSTRING
128 #define __STRINGSTRING(x) __STRING(x)
129 #endif
131 #ifndef __LINESTR__
132 #define __LINESTR__ __STRINGSTRING(__LINE__)
133 #endif
135 #ifndef __location__
136 #define __location__ __FILE__ ":" __LINESTR__
137 #endif
139 #ifndef DNS_NAME_MAX
140 #define DNS_NAME_MAX 255
141 #endif
143 /* GCC have printf type attribute check. */
144 #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT
145 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
146 #else
147 #define PRINTF_ATTRIBUTE(a,b)
148 #endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */
150 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
151 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
152 #else
153 #define CONSTRUCTOR_ATTRIBUTE
154 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
156 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
157 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
158 #else
159 #define DESTRUCTOR_ATTRIBUTE
160 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
162 #define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
164 #ifndef SAFE_FREE
165 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
166 #endif
168 #ifndef discard_const
169 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
170 #endif
172 #ifndef discard_const_p
173 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
174 #endif
176 #ifdef HAVE_IPV6
177 #define NWRAP_INET_ADDRSTRLEN INET6_ADDRSTRLEN
178 #else
179 #define NWRAP_INET_ADDRSTRLEN INET_ADDRSTRLEN
180 #endif
182 #define MAX(a,b) ((a) < (b) ? (b) : (a))
183 #define MIN(a,b) ((a) > (b) ? (b) : (a))
185 static bool nwrap_initialized = false;
186 static pthread_mutex_t nwrap_initialized_mutex = PTHREAD_MUTEX_INITIALIZER;
188 /* The mutex or accessing the id */
189 static pthread_mutex_t nwrap_global_mutex = PTHREAD_MUTEX_INITIALIZER;
190 static pthread_mutex_t nwrap_gr_global_mutex = PTHREAD_MUTEX_INITIALIZER;
191 static pthread_mutex_t nwrap_he_global_mutex = PTHREAD_MUTEX_INITIALIZER;
192 static pthread_mutex_t nwrap_pw_global_mutex = PTHREAD_MUTEX_INITIALIZER;
193 static pthread_mutex_t nwrap_sp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
195 #define nss_wrapper_init_mutex(m) \
196 _nss_wrapper_init_mutex(m, #m)
198 /* Add new global locks here please */
199 /* Also don't forget to add locks to
200 * nwrap_init() function.
202 # define NWRAP_REINIT_ALL do { \
203 int ret; \
204 ret = nss_wrapper_init_mutex(&nwrap_initialized_mutex); \
205 if (ret != 0) exit(-1); \
206 ret = nss_wrapper_init_mutex(&nwrap_global_mutex); \
207 if (ret != 0) exit(-1); \
208 ret = nss_wrapper_init_mutex(&nwrap_gr_global_mutex); \
209 if (ret != 0) exit(-1); \
210 ret = nss_wrapper_init_mutex(&nwrap_he_global_mutex); \
211 if (ret != 0) exit(-1); \
212 ret = nss_wrapper_init_mutex(&nwrap_pw_global_mutex); \
213 if (ret != 0) exit(-1); \
214 ret = nss_wrapper_init_mutex(&nwrap_sp_global_mutex); \
215 if (ret != 0) exit(-1); \
216 } while(0)
218 # define NWRAP_LOCK_ALL do { \
219 nwrap_mutex_lock(&nwrap_initialized_mutex); \
220 nwrap_mutex_lock(&nwrap_global_mutex); \
221 nwrap_mutex_lock(&nwrap_gr_global_mutex); \
222 nwrap_mutex_lock(&nwrap_he_global_mutex); \
223 nwrap_mutex_lock(&nwrap_pw_global_mutex); \
224 nwrap_mutex_lock(&nwrap_sp_global_mutex); \
225 } while (0);
227 # define NWRAP_UNLOCK_ALL do {\
228 nwrap_mutex_unlock(&nwrap_sp_global_mutex); \
229 nwrap_mutex_unlock(&nwrap_pw_global_mutex); \
230 nwrap_mutex_unlock(&nwrap_he_global_mutex); \
231 nwrap_mutex_unlock(&nwrap_gr_global_mutex); \
232 nwrap_mutex_unlock(&nwrap_global_mutex); \
233 nwrap_mutex_unlock(&nwrap_initialized_mutex); \
234 } while (0);
236 static void nwrap_init(void);
238 enum nwrap_dbglvl_e {
239 NWRAP_LOG_ERROR = 0,
240 NWRAP_LOG_WARN,
241 NWRAP_LOG_DEBUG,
242 NWRAP_LOG_TRACE
245 #ifndef HAVE_GETPROGNAME
246 static const char *getprogname(void)
248 #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
249 return program_invocation_short_name;
250 #elif defined(HAVE_GETEXECNAME)
251 return getexecname();
252 #else
253 return NULL;
254 #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
256 #endif /* HAVE_GETPROGNAME */
258 static void nwrap_log(enum nwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
259 # define NWRAP_LOG(dbglvl, ...) nwrap_log((dbglvl), __func__, __VA_ARGS__)
261 static void nwrap_log(enum nwrap_dbglvl_e dbglvl,
262 const char *func,
263 const char *format, ...)
265 char buffer[1024];
266 va_list va;
267 const char *d;
268 unsigned int lvl = 0;
269 const char *prefix = "NWRAP";
270 const char *progname = getprogname();
272 d = getenv("NSS_WRAPPER_DEBUGLEVEL");
273 if (d != NULL) {
274 lvl = atoi(d);
277 if (lvl < dbglvl) {
278 return;
281 va_start(va, format);
282 vsnprintf(buffer, sizeof(buffer), format, va);
283 va_end(va);
285 switch (dbglvl) {
286 case NWRAP_LOG_ERROR:
287 prefix = "NWRAP_ERROR";
288 break;
289 case NWRAP_LOG_WARN:
290 prefix = "NWRAP_WARN";
291 break;
292 case NWRAP_LOG_DEBUG:
293 prefix = "NWRAP_DEBUG";
294 break;
295 case NWRAP_LOG_TRACE:
296 prefix = "NWRAP_TRACE";
297 break;
300 if (progname == NULL) {
301 progname = "<unknown>";
304 fprintf(stderr,
305 "%s[%s (%u)] - %s: %s\n",
306 prefix,
307 progname,
308 (unsigned int)getpid(),
309 func,
310 buffer);
313 /*****************
314 * LIBC
315 *****************/
317 #define LIBC_NAME "libc.so"
319 typedef struct passwd *(*__libc_getpwnam)(const char *name);
321 typedef int (*__libc_getpwnam_r)(const char *name,
322 struct passwd *pwd,
323 char *buf,
324 size_t buflen,
325 struct passwd **result);
327 typedef struct passwd *(*__libc_getpwuid)(uid_t uid);
329 typedef int (*__libc_getpwuid_r)(uid_t uid,
330 struct passwd *pwd,
331 char *buf,
332 size_t buflen,
333 struct passwd **result);
335 typedef void (*__libc_setpwent)(void);
337 typedef struct passwd *(*__libc_getpwent)(void);
339 #ifdef HAVE_GETPWENT_R
340 # ifdef HAVE_SOLARIS_GETPWENT_R
341 typedef struct passwd *(*__libc_getpwent_r)(struct passwd *pwbuf,
342 char *buf,
343 size_t buflen);
344 # else /* HAVE_SOLARIS_GETPWENT_R */
345 typedef int (*__libc_getpwent_r)(struct passwd *pwbuf,
346 char *buf,
347 size_t buflen,
348 struct passwd **pwbufp);
349 # endif /* HAVE_SOLARIS_GETPWENT_R */
350 #endif /* HAVE_GETPWENT_R */
352 typedef void (*__libc_endpwent)(void);
354 typedef int (*__libc_initgroups)(const char *user, gid_t gid);
356 typedef struct group *(*__libc_getgrnam)(const char *name);
358 typedef int (*__libc_getgrnam_r)(const char *name,
359 struct group *grp,
360 char *buf,
361 size_t buflen,
362 struct group **result);
364 typedef struct group *(*__libc_getgrgid)(gid_t gid);
366 typedef int (*__libc_getgrgid_r)(gid_t gid,
367 struct group *grp,
368 char *buf,
369 size_t buflen,
370 struct group **result);
372 typedef void (*__libc_setgrent)(void);
374 typedef struct group *(*__libc_getgrent)(void);
376 #ifdef HAVE_GETGRENT_R
377 # ifdef HAVE_SOLARIS_GETGRENT_R
378 typedef struct group *(*__libc_getgrent_r)(struct group *group,
379 char *buf,
380 size_t buflen);
381 # else /* HAVE_SOLARIS_GETGRENT_R */
382 typedef int (*__libc_getgrent_r)(struct group *group,
383 char *buf,
384 size_t buflen,
385 struct group **result);
386 # endif /* HAVE_SOLARIS_GETGRENT_R */
387 #endif /* HAVE_GETGRENT_R */
389 typedef void (*__libc_endgrent)(void);
391 typedef int (*__libc_getgrouplist)(const char *user,
392 gid_t group,
393 gid_t *groups,
394 int *ngroups);
396 typedef void (*__libc_sethostent)(int stayopen);
398 typedef struct hostent *(*__libc_gethostent)(void);
400 typedef void (*__libc_endhostent)(void);
402 typedef struct hostent *(*__libc_gethostbyname)(const char *name);
404 #ifdef HAVE_GETHOSTBYNAME2 /* GNU extension */
405 typedef struct hostent *(*__libc_gethostbyname2)(const char *name, int af);
406 #endif
408 #ifdef HAVE_GETHOSTBYNAME2_R /* GNU extension */
409 typedef int (*__libc_gethostbyname2_r)(const char *name,
410 int af,
411 struct hostent *ret,
412 char *buf,
413 size_t buflen,
414 struct hostent **result,
415 int *h_errnop);
416 #endif
418 typedef struct hostent *(*__libc_gethostbyaddr)(const void *addr,
419 socklen_t len,
420 int type);
422 typedef int (*__libc_getaddrinfo)(const char *node,
423 const char *service,
424 const struct addrinfo *hints,
425 struct addrinfo **res);
426 typedef int (*__libc_getnameinfo)(const struct sockaddr *sa,
427 socklen_t salen,
428 char *host,
429 size_t hostlen,
430 char *serv,
431 size_t servlen,
432 int flags);
434 typedef int (*__libc_gethostname)(char *name, size_t len);
436 #ifdef HAVE_GETHOSTBYNAME_R
437 typedef int (*__libc_gethostbyname_r)(const char *name,
438 struct hostent *ret,
439 char *buf, size_t buflen,
440 struct hostent **result, int *h_errnop);
441 #endif
443 #ifdef HAVE_GETHOSTBYADDR_R
444 typedef int (*__libc_gethostbyaddr_r)(const void *addr,
445 socklen_t len,
446 int type,
447 struct hostent *ret,
448 char *buf,
449 size_t buflen,
450 struct hostent **result,
451 int *h_errnop);
452 #endif
454 #define NWRAP_SYMBOL_ENTRY(i) \
455 union { \
456 __libc_##i f; \
457 void *obj; \
458 } _libc_##i
460 struct nwrap_libc_symbols {
461 NWRAP_SYMBOL_ENTRY(getpwnam);
462 NWRAP_SYMBOL_ENTRY(getpwnam_r);
463 NWRAP_SYMBOL_ENTRY(getpwuid);
464 NWRAP_SYMBOL_ENTRY(getpwuid_r);
465 NWRAP_SYMBOL_ENTRY(setpwent);
466 NWRAP_SYMBOL_ENTRY(getpwent);
467 #ifdef HAVE_GETPWENT_R
468 NWRAP_SYMBOL_ENTRY(getpwent_r);
469 #endif
470 NWRAP_SYMBOL_ENTRY(endpwent);
472 NWRAP_SYMBOL_ENTRY(initgroups);
473 NWRAP_SYMBOL_ENTRY(getgrnam);
474 NWRAP_SYMBOL_ENTRY(getgrnam_r);
475 NWRAP_SYMBOL_ENTRY(getgrgid);
476 NWRAP_SYMBOL_ENTRY(getgrgid_r);
477 NWRAP_SYMBOL_ENTRY(setgrent);
478 NWRAP_SYMBOL_ENTRY(getgrent);
479 #ifdef HAVE_GETGRENT_R
480 NWRAP_SYMBOL_ENTRY(getgrent_r);
481 #endif
482 NWRAP_SYMBOL_ENTRY(endgrent);
483 NWRAP_SYMBOL_ENTRY(getgrouplist);
485 NWRAP_SYMBOL_ENTRY(sethostent);
486 NWRAP_SYMBOL_ENTRY(gethostent);
487 NWRAP_SYMBOL_ENTRY(endhostent);
488 NWRAP_SYMBOL_ENTRY(gethostbyname);
489 #ifdef HAVE_GETHOSTBYNAME_R
490 NWRAP_SYMBOL_ENTRY(gethostbyname_r);
491 #endif
492 #ifdef HAVE_GETHOSTBYNAME2
493 NWRAP_SYMBOL_ENTRY(gethostbyname2);
494 #endif
495 #ifdef HAVE_GETHOSTBYNAME2_R
496 NWRAP_SYMBOL_ENTRY(gethostbyname2_r);
497 #endif
498 NWRAP_SYMBOL_ENTRY(gethostbyaddr);
499 #ifdef HAVE_GETHOSTBYADDR_R
500 NWRAP_SYMBOL_ENTRY(gethostbyaddr_r);
501 #endif
502 NWRAP_SYMBOL_ENTRY(getaddrinfo);
503 NWRAP_SYMBOL_ENTRY(getnameinfo);
504 NWRAP_SYMBOL_ENTRY(gethostname);
506 #undef NWRAP_SYMBOL_ENTRY
508 typedef NSS_STATUS (*__nss_getpwnam_r)(const char *name,
509 struct passwd *result,
510 char *buffer,
511 size_t buflen,
512 int *errnop);
513 typedef NSS_STATUS (*__nss_getpwuid_r)(uid_t uid,
514 struct passwd *result,
515 char *buffer,
516 size_t buflen,
517 int *errnop);
518 typedef NSS_STATUS (*__nss_setpwent)(void);
519 typedef NSS_STATUS (*__nss_getpwent_r)(struct passwd *result,
520 char *buffer,
521 size_t buflen,
522 int *errnop);
523 typedef NSS_STATUS (*__nss_endpwent)(void);
524 typedef NSS_STATUS (*__nss_initgroups_dyn)(const char *user,
525 gid_t group,
526 long int *start,
527 long int *size,
528 gid_t **groups,
529 long int limit,
530 int *errnop);
531 typedef NSS_STATUS (*__nss_getgrnam_r)(const char *name,
532 struct group *result,
533 char *buffer,
534 size_t buflen,
535 int *errnop);
536 typedef NSS_STATUS (*__nss_getgrgid_r)(gid_t gid,
537 struct group *result,
538 char *buffer,
539 size_t buflen,
540 int *errnop);
541 typedef NSS_STATUS (*__nss_setgrent)(void);
542 typedef NSS_STATUS (*__nss_getgrent_r)(struct group *result,
543 char *buffer,
544 size_t buflen,
545 int *errnop);
546 typedef NSS_STATUS (*__nss_endgrent)(void);
547 typedef NSS_STATUS (*__nss_gethostbyaddr_r)(const void *addr,
548 socklen_t addrlen,
549 int af,
550 struct hostent *result,
551 char *buffer,
552 size_t buflen,
553 int *errnop,
554 int *h_errnop);
555 typedef NSS_STATUS (*__nss_gethostbyname2_r)(const char *name,
556 int af,
557 struct hostent *result,
558 char *buffer,
559 size_t buflen,
560 int *errnop,
561 int *h_errnop);
563 #define NWRAP_NSS_MODULE_SYMBOL_ENTRY(i) \
564 union { \
565 __nss_##i f; \
566 void *obj; \
567 } _nss_##i
569 struct nwrap_nss_module_symbols {
570 NWRAP_NSS_MODULE_SYMBOL_ENTRY(getpwnam_r);
571 NWRAP_NSS_MODULE_SYMBOL_ENTRY(getpwuid_r);
572 NWRAP_NSS_MODULE_SYMBOL_ENTRY(setpwent);
573 NWRAP_NSS_MODULE_SYMBOL_ENTRY(getpwent_r);
574 NWRAP_NSS_MODULE_SYMBOL_ENTRY(endpwent);
576 NWRAP_NSS_MODULE_SYMBOL_ENTRY(initgroups_dyn);
577 NWRAP_NSS_MODULE_SYMBOL_ENTRY(getgrnam_r);
578 NWRAP_NSS_MODULE_SYMBOL_ENTRY(getgrgid_r);
579 NWRAP_NSS_MODULE_SYMBOL_ENTRY(setgrent);
580 NWRAP_NSS_MODULE_SYMBOL_ENTRY(getgrent_r);
581 NWRAP_NSS_MODULE_SYMBOL_ENTRY(endgrent);
583 NWRAP_NSS_MODULE_SYMBOL_ENTRY(gethostbyaddr_r);
584 NWRAP_NSS_MODULE_SYMBOL_ENTRY(gethostbyname2_r);
587 struct nwrap_backend {
588 const char *name;
589 const char *so_path;
590 void *so_handle;
591 struct nwrap_ops *ops;
592 struct nwrap_nss_module_symbols *symbols;
595 struct nwrap_vector;
597 struct nwrap_ops {
598 struct passwd * (*nw_getpwnam)(struct nwrap_backend *b,
599 const char *name);
600 int (*nw_getpwnam_r)(struct nwrap_backend *b,
601 const char *name, struct passwd *pwdst,
602 char *buf, size_t buflen, struct passwd **pwdstp);
603 struct passwd * (*nw_getpwuid)(struct nwrap_backend *b,
604 uid_t uid);
605 int (*nw_getpwuid_r)(struct nwrap_backend *b,
606 uid_t uid, struct passwd *pwdst,
607 char *buf, size_t buflen, struct passwd **pwdstp);
608 void (*nw_setpwent)(struct nwrap_backend *b);
609 struct passwd * (*nw_getpwent)(struct nwrap_backend *b);
610 int (*nw_getpwent_r)(struct nwrap_backend *b,
611 struct passwd *pwdst, char *buf,
612 size_t buflen, struct passwd **pwdstp);
613 void (*nw_endpwent)(struct nwrap_backend *b);
614 int (*nw_initgroups_dyn)(struct nwrap_backend *b,
615 const char *user,
616 gid_t group,
617 long int *start,
618 long int *size,
619 gid_t **groups,
620 long int limit,
621 int *errnop);
622 struct group * (*nw_getgrnam)(struct nwrap_backend *b,
623 const char *name);
624 int (*nw_getgrnam_r)(struct nwrap_backend *b,
625 const char *name, struct group *grdst,
626 char *buf, size_t buflen, struct group **grdstp);
627 struct group * (*nw_getgrgid)(struct nwrap_backend *b,
628 gid_t gid);
629 int (*nw_getgrgid_r)(struct nwrap_backend *b,
630 gid_t gid, struct group *grdst,
631 char *buf, size_t buflen, struct group **grdstp);
632 void (*nw_setgrent)(struct nwrap_backend *b);
633 struct group * (*nw_getgrent)(struct nwrap_backend *b);
634 int (*nw_getgrent_r)(struct nwrap_backend *b,
635 struct group *grdst, char *buf,
636 size_t buflen, struct group **grdstp);
637 void (*nw_endgrent)(struct nwrap_backend *b);
638 struct hostent *(*nw_gethostbyaddr)(struct nwrap_backend *b,
639 const void *addr,
640 socklen_t len, int type);
641 struct hostent *(*nw_gethostbyname)(struct nwrap_backend *b,
642 const char *name);
643 struct hostent *(*nw_gethostbyname2)(struct nwrap_backend *b,
644 const char *name, int af);
645 int (*nw_gethostbyname2_r)(struct nwrap_backend *b,
646 const char *name, int af,
647 struct hostent *hedst,
648 char *buf, size_t buflen,
649 struct hostent **hedstp);
652 /* Public prototypes */
654 bool nss_wrapper_enabled(void);
655 bool nss_wrapper_shadow_enabled(void);
656 bool nss_wrapper_hosts_enabled(void);
658 /* prototypes for files backend */
661 static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
662 const char *name);
663 static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
664 const char *name, struct passwd *pwdst,
665 char *buf, size_t buflen, struct passwd **pwdstp);
666 static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
667 uid_t uid);
668 static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
669 uid_t uid, struct passwd *pwdst,
670 char *buf, size_t buflen, struct passwd **pwdstp);
671 static void nwrap_files_setpwent(struct nwrap_backend *b);
672 static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b);
673 static int nwrap_files_getpwent_r(struct nwrap_backend *b,
674 struct passwd *pwdst, char *buf,
675 size_t buflen, struct passwd **pwdstp);
676 static void nwrap_files_endpwent(struct nwrap_backend *b);
677 static int nwrap_files_initgroups_dyn(struct nwrap_backend *b,
678 const char *user,
679 gid_t group,
680 long int *start,
681 long int *size,
682 gid_t **groups,
683 long int limit,
684 int *errnop);
685 static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
686 const char *name);
687 static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
688 const char *name, struct group *grdst,
689 char *buf, size_t buflen, struct group **grdstp);
690 static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
691 gid_t gid);
692 static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
693 gid_t gid, struct group *grdst,
694 char *buf, size_t buflen, struct group **grdstp);
695 static void nwrap_files_setgrent(struct nwrap_backend *b);
696 static struct group *nwrap_files_getgrent(struct nwrap_backend *b);
697 static int nwrap_files_getgrent_r(struct nwrap_backend *b,
698 struct group *grdst, char *buf,
699 size_t buflen, struct group **grdstp);
700 static void nwrap_files_endgrent(struct nwrap_backend *b);
701 static struct hostent *nwrap_files_gethostbyaddr(struct nwrap_backend *b,
702 const void *addr,
703 socklen_t len, int type);
704 static struct hostent *nwrap_files_gethostbyname(struct nwrap_backend *b,
705 const char *name);
706 #ifdef HAVE_GETHOSTBYNAME2
707 static struct hostent *nwrap_files_gethostbyname2(struct nwrap_backend *b,
708 const char *name, int af);
709 #endif /* HAVE_GETHOSTBYNAME2 */
710 static int nwrap_files_gethostbyname2_r(struct nwrap_backend *b,
711 const char *name, int af,
712 struct hostent *hedst,
713 char *buf, size_t buflen,
714 struct hostent **hedstp);
716 /* prototypes for module backend */
718 static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b);
719 static int nwrap_module_getpwent_r(struct nwrap_backend *b,
720 struct passwd *pwdst, char *buf,
721 size_t buflen, struct passwd **pwdstp);
722 static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
723 const char *name);
724 static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
725 const char *name, struct passwd *pwdst,
726 char *buf, size_t buflen, struct passwd **pwdstp);
727 static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
728 uid_t uid);
729 static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
730 uid_t uid, struct passwd *pwdst,
731 char *buf, size_t buflen, struct passwd **pwdstp);
732 static void nwrap_module_setpwent(struct nwrap_backend *b);
733 static void nwrap_module_endpwent(struct nwrap_backend *b);
734 static struct group *nwrap_module_getgrent(struct nwrap_backend *b);
735 static int nwrap_module_getgrent_r(struct nwrap_backend *b,
736 struct group *grdst, char *buf,
737 size_t buflen, struct group **grdstp);
738 static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
739 const char *name);
740 static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
741 const char *name, struct group *grdst,
742 char *buf, size_t buflen, struct group **grdstp);
743 static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
744 gid_t gid);
745 static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
746 gid_t gid, struct group *grdst,
747 char *buf, size_t buflen, struct group **grdstp);
748 static void nwrap_module_setgrent(struct nwrap_backend *b);
749 static void nwrap_module_endgrent(struct nwrap_backend *b);
750 static int nwrap_module_initgroups_dyn(struct nwrap_backend *b,
751 const char *user,
752 gid_t group,
753 long int *start,
754 long int *size,
755 gid_t **groups,
756 long int limit,
757 int *errnop);
758 static struct hostent *nwrap_module_gethostbyaddr(struct nwrap_backend *b,
759 const void *addr,
760 socklen_t len, int type);
761 static struct hostent *nwrap_module_gethostbyname(struct nwrap_backend *b,
762 const char *name);
763 static struct hostent *nwrap_module_gethostbyname2(struct nwrap_backend *b,
764 const char *name, int af);
765 static int nwrap_module_gethostbyname2_r(struct nwrap_backend *b,
766 const char *name, int af,
767 struct hostent *hedst,
768 char *buf, size_t buflen,
769 struct hostent **hedstp);
771 struct nwrap_ops nwrap_files_ops = {
772 .nw_getpwnam = nwrap_files_getpwnam,
773 .nw_getpwnam_r = nwrap_files_getpwnam_r,
774 .nw_getpwuid = nwrap_files_getpwuid,
775 .nw_getpwuid_r = nwrap_files_getpwuid_r,
776 .nw_setpwent = nwrap_files_setpwent,
777 .nw_getpwent = nwrap_files_getpwent,
778 .nw_getpwent_r = nwrap_files_getpwent_r,
779 .nw_endpwent = nwrap_files_endpwent,
780 .nw_initgroups_dyn = nwrap_files_initgroups_dyn,
781 .nw_getgrnam = nwrap_files_getgrnam,
782 .nw_getgrnam_r = nwrap_files_getgrnam_r,
783 .nw_getgrgid = nwrap_files_getgrgid,
784 .nw_getgrgid_r = nwrap_files_getgrgid_r,
785 .nw_setgrent = nwrap_files_setgrent,
786 .nw_getgrent = nwrap_files_getgrent,
787 .nw_getgrent_r = nwrap_files_getgrent_r,
788 .nw_endgrent = nwrap_files_endgrent,
789 .nw_gethostbyaddr = nwrap_files_gethostbyaddr,
790 .nw_gethostbyname = nwrap_files_gethostbyname,
791 #ifdef HAVE_GETHOSTBYNAME2
792 .nw_gethostbyname2 = nwrap_files_gethostbyname2,
793 #endif /* HAVE_GETHOSTBYNAME2 */
794 .nw_gethostbyname2_r = nwrap_files_gethostbyname2_r,
797 struct nwrap_ops nwrap_module_ops = {
798 .nw_getpwnam = nwrap_module_getpwnam,
799 .nw_getpwnam_r = nwrap_module_getpwnam_r,
800 .nw_getpwuid = nwrap_module_getpwuid,
801 .nw_getpwuid_r = nwrap_module_getpwuid_r,
802 .nw_setpwent = nwrap_module_setpwent,
803 .nw_getpwent = nwrap_module_getpwent,
804 .nw_getpwent_r = nwrap_module_getpwent_r,
805 .nw_endpwent = nwrap_module_endpwent,
806 .nw_initgroups_dyn = nwrap_module_initgroups_dyn,
807 .nw_getgrnam = nwrap_module_getgrnam,
808 .nw_getgrnam_r = nwrap_module_getgrnam_r,
809 .nw_getgrgid = nwrap_module_getgrgid,
810 .nw_getgrgid_r = nwrap_module_getgrgid_r,
811 .nw_setgrent = nwrap_module_setgrent,
812 .nw_getgrent = nwrap_module_getgrent,
813 .nw_getgrent_r = nwrap_module_getgrent_r,
814 .nw_endgrent = nwrap_module_endgrent,
815 .nw_gethostbyaddr = nwrap_module_gethostbyaddr,
816 .nw_gethostbyname = nwrap_module_gethostbyname,
817 .nw_gethostbyname2 = nwrap_module_gethostbyname2,
818 .nw_gethostbyname2_r = nwrap_module_gethostbyname2_r,
821 struct nwrap_libc {
822 void *handle;
823 void *nsl_handle;
824 void *sock_handle;
825 struct nwrap_libc_symbols symbols;
828 struct nwrap_main {
829 size_t num_backends;
830 struct nwrap_backend *backends;
831 struct nwrap_libc *libc;
834 static struct nwrap_main *nwrap_main_global;
835 static struct nwrap_main __nwrap_main_global;
838 * PROTOTYPES
840 static int nwrap_convert_he_ai(const struct hostent *he,
841 unsigned short port,
842 const struct addrinfo *hints,
843 struct addrinfo **pai,
844 bool skip_canonname);
846 #ifdef HAVE_GETGROUPLIST
847 static int nwrap_getgrouplist(const char *user,
848 gid_t group,
849 long int *size,
850 gid_t **groupsp,
851 long int limit);
852 #endif
855 * VECTORS
858 #define DEFAULT_VECTOR_CAPACITY 16
860 struct nwrap_vector {
861 void **items;
862 size_t count;
863 size_t capacity;
866 /* Macro returns pointer to first element of vector->items array.
868 * nwrap_vector is used as a memory backend which take care of
869 * memory allocations and other stuff like memory growing.
870 * nwrap_vectors should not be considered as some abstract structures.
871 * On this level, vectors are more handy than direct realloc/malloc
872 * calls.
874 * nwrap_vector->items is array inside nwrap_vector which can be
875 * directly pointed by libc structure assembled by cwrap itself.
877 * EXAMPLE:
879 * 1) struct hostent contains char **h_addr_list element.
880 * 2) nwrap_vector holds array of pointers to addresses.
881 * It's easier to use vector to store results of
882 * file parsing etc.
884 * Now, pretend that cwrap assembled struct hostent and
885 * we need to set h_addr_list to point to nwrap_vector.
886 * Idea behind is to shield users from internal nwrap_vector
887 * implementation.
888 * (Yes, not fully - array terminated by NULL is needed because
889 * it's result expected by libc function caller.)
892 * CODE EXAMPLE:
894 * struct hostent he;
895 * struct nwrap_vector *vector = malloc(sizeof(struct nwrap_vector));
896 * ... don't care about failed allocation now ...
898 * ... fill nwrap vector ...
900 * struct hostent he;
901 * he.h_addr_list = nwrap_vector_head(vector);
904 #define nwrap_vector_head(vect) ((void *)((vect)->items))
906 #define nwrap_vector_foreach(item, vect, iter) \
907 for (iter = 0, (item) = (vect).items == NULL ? NULL : (vect).items[0]; \
908 item != NULL; \
909 (item) = (vect).items[++iter])
911 #define nwrap_vector_is_initialized(vector) ((vector)->items != NULL)
913 static inline bool nwrap_vector_init(struct nwrap_vector *const vector)
915 if (vector == NULL) {
916 return false;
919 /* count is initialized by ZERO_STRUCTP */
920 ZERO_STRUCTP(vector);
921 vector->items = malloc(sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1));
922 if (vector->items == NULL) {
923 return false;
925 vector->capacity = DEFAULT_VECTOR_CAPACITY;
926 memset(vector->items, '\0', sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1));
928 return true;
931 static bool nwrap_vector_add_item(struct nwrap_vector *vector, void *const item)
933 assert (vector != NULL);
935 if (vector->items == NULL) {
936 nwrap_vector_init(vector);
939 if (vector->count == vector->capacity) {
940 /* Items array _MUST_ be NULL terminated because it's passed
941 * as result to caller which expect NULL terminated array from libc.
943 void **items = realloc(vector->items, sizeof(void *) * ((vector->capacity * 2) + 1));
944 if (items == NULL) {
945 return false;
947 vector->items = items;
949 /* Don't count ending NULL to capacity */
950 vector->capacity *= 2;
953 vector->items[vector->count] = item;
955 vector->count += 1;
956 vector->items[vector->count] = NULL;
958 return true;
961 static bool nwrap_vector_merge(struct nwrap_vector *dst,
962 struct nwrap_vector *src)
964 void **dst_items = NULL;
965 size_t count;
967 if (src->count == 0) {
968 return true;
971 count = dst->count + src->count;
973 /* We don't need reallocation if we have enough capacity. */
974 if (src->count > (dst->capacity - dst->count)) {
975 dst_items = (void **)realloc(dst->items, (count + 1) * sizeof(void *));
976 if (dst_items == NULL) {
977 return false;
979 dst->items = dst_items;
980 dst->capacity = count;
983 memcpy((void *)(((long *)dst->items) + dst->count),
984 src->items,
985 src->count * sizeof(void *));
986 dst->count = count;
988 return true;
991 struct nwrap_cache {
992 const char *path;
993 int fd;
994 FILE *fp;
995 struct stat st;
996 void *private_data;
998 struct nwrap_vector lines;
1000 bool (*parse_line)(struct nwrap_cache *, char *line);
1001 void (*unload)(struct nwrap_cache *);
1004 /* passwd */
1005 struct nwrap_pw {
1006 struct nwrap_cache *cache;
1008 struct passwd *list;
1009 int num;
1010 int idx;
1013 struct nwrap_cache __nwrap_cache_pw;
1014 struct nwrap_pw nwrap_pw_global;
1016 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line);
1017 static void nwrap_pw_unload(struct nwrap_cache *nwrap);
1019 /* shadow */
1020 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
1021 struct nwrap_sp {
1022 struct nwrap_cache *cache;
1024 struct spwd *list;
1025 int num;
1026 int idx;
1029 struct nwrap_cache __nwrap_cache_sp;
1030 struct nwrap_sp nwrap_sp_global;
1032 static bool nwrap_sp_parse_line(struct nwrap_cache *nwrap, char *line);
1033 static void nwrap_sp_unload(struct nwrap_cache *nwrap);
1034 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
1036 /* group */
1037 struct nwrap_gr {
1038 struct nwrap_cache *cache;
1040 struct group *list;
1041 int num;
1042 int idx;
1045 struct nwrap_cache __nwrap_cache_gr;
1046 struct nwrap_gr nwrap_gr_global;
1048 /* hosts */
1049 static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line);
1050 static void nwrap_he_unload(struct nwrap_cache *nwrap);
1052 struct nwrap_addrdata {
1053 unsigned char host_addr[16]; /* IPv4 or IPv6 address */
1056 static size_t max_hostents = 100;
1058 struct nwrap_entdata {
1059 struct nwrap_addrdata addr;
1060 struct hostent ht;
1062 struct nwrap_vector nwrap_addrdata;
1064 ssize_t aliases_count;
1067 struct nwrap_entlist {
1068 struct nwrap_entlist *next;
1069 struct nwrap_entdata *ed;
1072 struct nwrap_he {
1073 struct nwrap_cache *cache;
1075 struct nwrap_vector entries;
1076 struct nwrap_vector lists;
1078 int num;
1079 int idx;
1082 static struct nwrap_cache __nwrap_cache_he;
1083 static struct nwrap_he nwrap_he_global;
1086 /*********************************************************
1087 * NWRAP PROTOTYPES
1088 *********************************************************/
1090 static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line);
1091 static void nwrap_gr_unload(struct nwrap_cache *nwrap);
1092 #if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT)
1093 /* xlC and other oldschool compilers support (only) this */
1094 #pragma init (nwrap_constructor)
1095 #endif
1096 void nwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
1097 #if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
1098 #pragma fini (nwrap_destructor)
1099 #endif
1100 void nwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
1102 /*********************************************************
1103 * NWRAP LIBC LOADER FUNCTIONS
1104 *********************************************************/
1106 enum nwrap_lib {
1107 NWRAP_LIBC,
1108 NWRAP_LIBNSL,
1109 NWRAP_LIBSOCKET,
1112 static const char *nwrap_str_lib(enum nwrap_lib lib)
1114 switch (lib) {
1115 case NWRAP_LIBC:
1116 return "libc";
1117 case NWRAP_LIBNSL:
1118 return "libnsl";
1119 case NWRAP_LIBSOCKET:
1120 return "libsocket";
1123 /* Compiler would warn us about unhandled enum value if we get here */
1124 return "unknown";
1127 static void *nwrap_load_lib_handle(enum nwrap_lib lib)
1129 int flags = RTLD_LAZY;
1130 void *handle = NULL;
1131 int i;
1133 #ifdef RTLD_DEEPBIND
1134 const char *env_preload = getenv("LD_PRELOAD");
1135 const char *env_deepbind = getenv("NSS_WRAPPER_DISABLE_DEEPBIND");
1136 bool enable_deepbind = true;
1138 /* Don't do a deepbind if we run with libasan */
1139 if (env_preload != NULL && strlen(env_preload) < 1024) {
1140 const char *p = strstr(env_preload, "libasan.so");
1141 if (p != NULL) {
1142 enable_deepbind = false;
1146 if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
1147 enable_deepbind = false;
1150 if (enable_deepbind) {
1151 flags |= RTLD_DEEPBIND;
1153 #endif
1155 switch (lib) {
1156 case NWRAP_LIBNSL:
1157 #ifdef HAVE_LIBNSL
1158 handle = nwrap_main_global->libc->nsl_handle;
1159 if (handle == NULL) {
1160 for (i = 10; i >= 0; i--) {
1161 char soname[256] = {0};
1163 snprintf(soname, sizeof(soname), "libnsl.so.%d", i);
1164 handle = dlopen(soname, flags);
1165 if (handle != NULL) {
1166 break;
1170 nwrap_main_global->libc->nsl_handle = handle;
1172 break;
1173 #endif
1174 /* FALL TROUGH */
1175 case NWRAP_LIBSOCKET:
1176 #ifdef HAVE_LIBSOCKET
1177 handle = nwrap_main_global->libc->sock_handle;
1178 if (handle == NULL) {
1179 for (i = 10; i >= 0; i--) {
1180 char soname[256] = {0};
1182 snprintf(soname, sizeof(soname), "libsocket.so.%d", i);
1183 handle = dlopen(soname, flags);
1184 if (handle != NULL) {
1185 break;
1189 nwrap_main_global->libc->sock_handle = handle;
1191 break;
1192 #endif
1193 /* FALL TROUGH */
1194 case NWRAP_LIBC:
1195 handle = nwrap_main_global->libc->handle;
1196 if (handle == NULL) {
1197 for (i = 10; i >= 0; i--) {
1198 char soname[256] = {0};
1200 snprintf(soname, sizeof(soname), "libc.so.%d", i);
1201 handle = dlopen(soname, flags);
1202 if (handle != NULL) {
1203 break;
1207 nwrap_main_global->libc->handle = handle;
1209 break;
1212 if (handle == NULL) {
1213 #ifdef RTLD_NEXT
1214 handle = nwrap_main_global->libc->handle
1215 = nwrap_main_global->libc->sock_handle
1216 = nwrap_main_global->libc->nsl_handle
1217 = RTLD_NEXT;
1218 #else
1219 NWRAP_LOG(NWRAP_LOG_ERROR,
1220 "Failed to dlopen library: %s\n",
1221 dlerror());
1222 exit(-1);
1223 #endif
1226 return handle;
1229 static void *_nwrap_bind_symbol(enum nwrap_lib lib, const char *fn_name)
1231 void *handle;
1232 void *func;
1234 nwrap_init();
1236 handle = nwrap_load_lib_handle(lib);
1238 func = dlsym(handle, fn_name);
1239 if (func == NULL) {
1240 NWRAP_LOG(NWRAP_LOG_ERROR,
1241 "Failed to find %s: %s\n",
1242 fn_name, dlerror());
1243 exit(-1);
1246 NWRAP_LOG(NWRAP_LOG_TRACE,
1247 "Loaded %s from %s",
1248 fn_name, nwrap_str_lib(lib));
1249 return func;
1252 #define nwrap_mutex_lock(m) _nwrap_mutex_lock(m, #m, __func__, __LINE__)
1253 static void _nwrap_mutex_lock(pthread_mutex_t *mutex, const char *name, const char *caller, unsigned line)
1255 int ret;
1257 ret = pthread_mutex_lock(mutex);
1258 if (ret != 0) {
1259 NWRAP_LOG(NWRAP_LOG_ERROR, "PID(%d):PPID(%d): %s(%u): Couldn't lock pthread mutex(%s) - %s",
1260 getpid(), getppid(), caller, line, name, strerror(ret));
1261 abort();
1265 #define nwrap_mutex_unlock(m) _nwrap_mutex_unlock(m, #m, __func__, __LINE__)
1266 static void _nwrap_mutex_unlock(pthread_mutex_t *mutex, const char *name, const char *caller, unsigned line)
1268 int ret;
1270 ret = pthread_mutex_unlock(mutex);
1271 if (ret != 0) {
1272 NWRAP_LOG(NWRAP_LOG_ERROR, "PID(%d):PPID(%d): %s(%u): Couldn't unlock pthread mutex(%s) - %s",
1273 getpid(), getppid(), caller, line, name, strerror(ret));
1274 abort();
1278 #define nwrap_bind_symbol_libc(sym_name) \
1279 if (nwrap_main_global->libc->symbols._libc_##sym_name.obj == NULL) { \
1280 nwrap_main_global->libc->symbols._libc_##sym_name.obj = \
1281 _nwrap_bind_symbol(NWRAP_LIBC, #sym_name); \
1284 #define nwrap_bind_symbol_libc_posix(sym_name) \
1285 if (nwrap_main_global->libc->symbols._libc_##sym_name.obj == NULL) { \
1286 nwrap_main_global->libc->symbols._libc_##sym_name.obj = \
1287 _nwrap_bind_symbol(NWRAP_LIBC, "__posix_" #sym_name); \
1290 #define nwrap_bind_symbol_libnsl(sym_name) \
1291 if (nwrap_main_global->libc->symbols._libc_##sym_name.obj == NULL) { \
1292 nwrap_main_global->libc->symbols._libc_##sym_name.obj = \
1293 _nwrap_bind_symbol(NWRAP_LIBNSL, #sym_name); \
1296 #define nwrap_bind_symbol_libsocket(sym_name) \
1297 if (nwrap_main_global->libc->symbols._libc_##sym_name.obj == NULL) { \
1298 nwrap_main_global->libc->symbols._libc_##sym_name.obj = \
1299 _nwrap_bind_symbol(NWRAP_LIBSOCKET, #sym_name); \
1302 static void nwrap_bind_symbol_all(void);
1304 /* INTERNAL HELPER FUNCTIONS */
1305 static void nwrap_lines_unload(struct nwrap_cache *const nwrap)
1307 size_t p;
1308 void *item;
1309 nwrap_vector_foreach(item, nwrap->lines, p) {
1310 /* Maybe some vectors were merged ... */
1311 SAFE_FREE(item);
1313 SAFE_FREE(nwrap->lines.items);
1314 ZERO_STRUCTP(&nwrap->lines);
1318 * IMPORTANT
1320 * Functions expeciall from libc need to be loaded individually, you can't load
1321 * all at once or gdb will segfault at startup. The same applies to valgrind and
1322 * has probably something todo with with the linker.
1323 * So we need load each function at the point it is called the first time.
1325 static struct passwd *libc_getpwnam(const char *name)
1327 nwrap_bind_symbol_all();
1329 return nwrap_main_global->libc->symbols._libc_getpwnam.f(name);
1332 #ifdef HAVE_GETPWNAM_R
1333 static int libc_getpwnam_r(const char *name,
1334 struct passwd *pwd,
1335 char *buf,
1336 size_t buflen,
1337 struct passwd **result)
1339 nwrap_bind_symbol_all();
1341 return nwrap_main_global->libc->symbols._libc_getpwnam_r.f(name,
1342 pwd,
1343 buf,
1344 buflen,
1345 result);
1347 #endif
1349 static struct passwd *libc_getpwuid(uid_t uid)
1351 nwrap_bind_symbol_all();
1353 return nwrap_main_global->libc->symbols._libc_getpwuid.f(uid);
1356 #ifdef HAVE_GETPWUID_R
1357 static int libc_getpwuid_r(uid_t uid,
1358 struct passwd *pwd,
1359 char *buf,
1360 size_t buflen,
1361 struct passwd **result)
1363 nwrap_bind_symbol_all();
1365 return nwrap_main_global->libc->symbols._libc_getpwuid_r.f(uid,
1366 pwd,
1367 buf,
1368 buflen,
1369 result);
1371 #endif
1373 static inline void str_tolower(char *dst, char *src)
1375 register char *src_tmp = src;
1376 register char *dst_tmp = dst;
1378 while (*src_tmp != '\0') {
1379 *dst_tmp = tolower(*src_tmp);
1380 ++src_tmp;
1381 ++dst_tmp;
1385 static bool str_tolower_copy(char **dst_name, const char *const src_name)
1387 char *h_name_lower;
1389 if ((dst_name == NULL) || (src_name == NULL)) {
1390 return false;
1393 h_name_lower = strdup(src_name);
1394 if (h_name_lower == NULL) {
1395 NWRAP_LOG(NWRAP_LOG_DEBUG, "Out of memory while strdup");
1396 return false;
1399 str_tolower(h_name_lower, h_name_lower);
1400 *dst_name = h_name_lower;
1401 return true;
1404 static void libc_setpwent(void)
1406 nwrap_bind_symbol_all();
1408 nwrap_main_global->libc->symbols._libc_setpwent.f();
1411 static struct passwd *libc_getpwent(void)
1413 nwrap_bind_symbol_all();
1415 return nwrap_main_global->libc->symbols._libc_getpwent.f();
1418 #ifdef HAVE_GETPWENT_R
1419 # ifdef HAVE_SOLARIS_GETPWENT_R
1420 static struct passwd *libc_getpwent_r(struct passwd *pwdst,
1421 char *buf,
1422 int buflen)
1424 nwrap_bind_symbol_all();
1426 return nwrap_main_global->libc->symbols._libc_getpwent_r.f(pwdst,
1427 buf,
1428 buflen);
1430 # else /* HAVE_SOLARIS_GETPWENT_R */
1431 static int libc_getpwent_r(struct passwd *pwdst,
1432 char *buf,
1433 size_t buflen,
1434 struct passwd **pwdstp)
1436 nwrap_bind_symbol_all();
1438 return nwrap_main_global->libc->symbols._libc_getpwent_r.f(pwdst,
1439 buf,
1440 buflen,
1441 pwdstp);
1443 # endif /* HAVE_SOLARIS_GETPWENT_R */
1444 #endif /* HAVE_GETPWENT_R */
1446 static void libc_endpwent(void)
1448 nwrap_bind_symbol_all();
1450 nwrap_main_global->libc->symbols._libc_endpwent.f();
1453 static int libc_initgroups(const char *user, gid_t gid)
1455 nwrap_bind_symbol_all();
1457 return nwrap_main_global->libc->symbols._libc_initgroups.f(user, gid);
1460 static struct group *libc_getgrnam(const char *name)
1462 nwrap_bind_symbol_all();
1464 return nwrap_main_global->libc->symbols._libc_getgrnam.f(name);
1467 #ifdef HAVE_GETGRNAM_R
1468 static int libc_getgrnam_r(const char *name,
1469 struct group *grp,
1470 char *buf,
1471 size_t buflen,
1472 struct group **result)
1474 nwrap_bind_symbol_all();
1476 return nwrap_main_global->libc->symbols._libc_getgrnam_r.f(name,
1477 grp,
1478 buf,
1479 buflen,
1480 result);
1482 #endif
1484 static struct group *libc_getgrgid(gid_t gid)
1486 nwrap_bind_symbol_all();
1488 return nwrap_main_global->libc->symbols._libc_getgrgid.f(gid);
1491 #ifdef HAVE_GETGRGID_R
1492 static int libc_getgrgid_r(gid_t gid,
1493 struct group *grp,
1494 char *buf,
1495 size_t buflen,
1496 struct group **result)
1498 nwrap_bind_symbol_all();
1500 return nwrap_main_global->libc->symbols._libc_getgrgid_r.f(gid,
1501 grp,
1502 buf,
1503 buflen,
1504 result);
1506 #endif
1508 static void libc_setgrent(void)
1510 nwrap_bind_symbol_all();
1512 nwrap_main_global->libc->symbols._libc_setgrent.f();
1515 static struct group *libc_getgrent(void)
1517 nwrap_bind_symbol_all();
1519 return nwrap_main_global->libc->symbols._libc_getgrent.f();
1522 #ifdef HAVE_GETGRENT_R
1523 # ifdef HAVE_SOLARIS_GETGRENT_R
1524 static struct group *libc_getgrent_r(struct group *group,
1525 char *buf,
1526 size_t buflen)
1528 nwrap_bind_symbol_all();
1530 return nwrap_main_global->libc->symbols._libc_getgrent_r.f(group,
1531 buf,
1532 buflen);
1534 # else /* HAVE_SOLARIS_GETGRENT_R */
1535 static int libc_getgrent_r(struct group *group,
1536 char *buf,
1537 size_t buflen,
1538 struct group **result)
1540 nwrap_bind_symbol_all();
1542 return nwrap_main_global->libc->symbols._libc_getgrent_r.f(group,
1543 buf,
1544 buflen,
1545 result);
1547 # endif /* HAVE_SOLARIS_GETGRENT_R */
1548 #endif /* HAVE_GETGRENT_R */
1550 static void libc_endgrent(void)
1552 nwrap_bind_symbol_all();
1554 nwrap_main_global->libc->symbols._libc_endgrent.f();
1557 #ifdef HAVE_GETGROUPLIST
1558 static int libc_getgrouplist(const char *user,
1559 gid_t group,
1560 gid_t *groups,
1561 int *ngroups)
1563 nwrap_bind_symbol_all();
1565 return nwrap_main_global->libc->symbols._libc_getgrouplist.f(user,
1566 group,
1567 groups,
1568 ngroups);
1570 #endif
1572 static void libc_sethostent(int stayopen)
1574 nwrap_bind_symbol_all();
1576 nwrap_main_global->libc->symbols._libc_sethostent.f(stayopen);
1579 static struct hostent *libc_gethostent(void)
1581 nwrap_bind_symbol_all();
1583 return nwrap_main_global->libc->symbols._libc_gethostent.f();
1586 static void libc_endhostent(void)
1588 nwrap_bind_symbol_all();
1590 nwrap_main_global->libc->symbols._libc_endhostent.f();
1593 static struct hostent *libc_gethostbyname(const char *name)
1595 nwrap_bind_symbol_all();
1597 return nwrap_main_global->libc->symbols._libc_gethostbyname.f(name);
1600 #ifdef HAVE_GETHOSTBYNAME2 /* GNU extension */
1601 static struct hostent *libc_gethostbyname2(const char *name, int af)
1603 nwrap_bind_symbol_all();
1605 return nwrap_main_global->libc->symbols._libc_gethostbyname2.f(name, af);
1607 #endif
1609 #ifdef HAVE_GETHOSTBYNAME2_R /* GNU extension */
1610 static int libc_gethostbyname2_r(const char *name,
1611 int af,
1612 struct hostent *ret,
1613 char *buf,
1614 size_t buflen,
1615 struct hostent **result,
1616 int *h_errnop)
1618 nwrap_bind_symbol_all();
1620 return nwrap_main_global->libc->symbols._libc_gethostbyname2_r.f(name,
1622 ret,
1623 buf,
1624 buflen,
1625 result,
1626 h_errnop);
1628 #endif
1630 static struct hostent *libc_gethostbyaddr(const void *addr,
1631 socklen_t len,
1632 int type)
1634 nwrap_bind_symbol_all();
1636 return nwrap_main_global->libc->symbols._libc_gethostbyaddr.f(addr,
1637 len,
1638 type);
1641 static int libc_gethostname(char *name, size_t len)
1643 nwrap_bind_symbol_all();
1645 return nwrap_main_global->libc->symbols._libc_gethostname.f(name, len);
1648 #ifdef HAVE_GETHOSTBYNAME_R
1649 static int libc_gethostbyname_r(const char *name,
1650 struct hostent *ret,
1651 char *buf,
1652 size_t buflen,
1653 struct hostent **result,
1654 int *h_errnop)
1656 nwrap_bind_symbol_all();
1658 return nwrap_main_global->libc->symbols._libc_gethostbyname_r.f(name,
1659 ret,
1660 buf,
1661 buflen,
1662 result,
1663 h_errnop);
1665 #endif
1667 #ifdef HAVE_GETHOSTBYADDR_R
1668 static int libc_gethostbyaddr_r(const void *addr,
1669 socklen_t len,
1670 int type,
1671 struct hostent *ret,
1672 char *buf,
1673 size_t buflen,
1674 struct hostent **result,
1675 int *h_errnop)
1677 nwrap_bind_symbol_all();
1679 return nwrap_main_global->libc->symbols._libc_gethostbyaddr_r.f(addr,
1680 len,
1681 type,
1682 ret,
1683 buf,
1684 buflen,
1685 result,
1686 h_errnop);
1688 #endif
1690 static int libc_getaddrinfo(const char *node,
1691 const char *service,
1692 const struct addrinfo *hints,
1693 struct addrinfo **res)
1695 nwrap_bind_symbol_all();
1697 return nwrap_main_global->libc->symbols._libc_getaddrinfo.f(node,
1698 service,
1699 hints,
1700 res);
1703 static int libc_getnameinfo(const struct sockaddr *sa,
1704 socklen_t salen,
1705 char *host,
1706 size_t hostlen,
1707 char *serv,
1708 size_t servlen,
1709 int flags)
1711 nwrap_bind_symbol_all();
1713 return nwrap_main_global->libc->symbols._libc_getnameinfo.f(sa,
1714 salen,
1715 host,
1716 hostlen,
1717 serv,
1718 servlen,
1719 flags);
1722 static void __nwrap_bind_symbol_all_once(void)
1724 nwrap_bind_symbol_libc(getpwnam);
1725 #ifdef HAVE_GETPWNAM_R
1726 # ifdef HAVE___POSIX_GETPWNAM_R
1727 nwrap_bind_symbol_libc_posix(getpwnam_r);
1728 # else
1729 nwrap_bind_symbol_libc(getpwnam_r);
1730 # endif
1731 #endif
1732 nwrap_bind_symbol_libc(getpwuid);
1733 #ifdef HAVE_GETPWUID_R
1734 # ifdef HAVE___POSIX_GETPWUID_R
1735 nwrap_bind_symbol_libc_posix(getpwuid_r);
1736 # else
1737 nwrap_bind_symbol_libc(getpwuid_r);
1738 # endif
1739 #endif
1740 nwrap_bind_symbol_libc(setpwent);
1741 nwrap_bind_symbol_libc(getpwent);
1742 #ifdef HAVE_GETPWENT_R
1743 nwrap_bind_symbol_libc(getpwent_r);
1744 #endif
1745 nwrap_bind_symbol_libc(endpwent);
1746 nwrap_bind_symbol_libc(initgroups);
1747 nwrap_bind_symbol_libc(getgrnam);
1748 #ifdef HAVE_GETGRNAM_R
1749 # ifdef HAVE___POSIX_GETGRNAM_R
1750 nwrap_bind_symbol_libc_posix(getgrnam_r);
1751 # else
1752 nwrap_bind_symbol_libc(getgrnam_r);
1753 # endif
1754 #endif
1755 nwrap_bind_symbol_libc(getgrgid);
1756 #ifdef HAVE_GETGRGID_R
1757 # ifdef HAVE___POSIX_GETGRGID_R
1758 nwrap_bind_symbol_libc_posix(getgrgid_r);
1759 # else
1760 nwrap_bind_symbol_libc(getgrgid_r);
1761 # endif
1762 #endif
1763 nwrap_bind_symbol_libc(setgrent);
1764 nwrap_bind_symbol_libc(getgrent);
1765 nwrap_bind_symbol_libc(getgrent_r);
1766 nwrap_bind_symbol_libc(endgrent);
1767 nwrap_bind_symbol_libc(getgrouplist);
1768 nwrap_bind_symbol_libnsl(sethostent);
1769 nwrap_bind_symbol_libnsl(gethostent);
1770 nwrap_bind_symbol_libnsl(endhostent);
1771 nwrap_bind_symbol_libnsl(gethostbyname);
1772 #ifdef HAVE_GETHOSTBYNAME2 /* GNU extension */
1773 nwrap_bind_symbol_libnsl(gethostbyname2);
1774 #endif
1775 #ifdef HAVE_GETHOSTBYNAME2_R /* GNU extension */
1776 nwrap_bind_symbol_libnsl(gethostbyname2_r);
1777 #endif
1778 nwrap_bind_symbol_libnsl(gethostbyaddr);
1779 nwrap_bind_symbol_libnsl(gethostname);
1780 #ifdef HAVE_GETHOSTBYNAME_R
1781 nwrap_bind_symbol_libnsl(gethostbyname_r);
1782 #endif
1783 #ifdef HAVE_GETHOSTBYADDR_R
1784 nwrap_bind_symbol_libnsl(gethostbyaddr_r);
1785 #endif
1786 nwrap_bind_symbol_libsocket(getaddrinfo);
1787 nwrap_bind_symbol_libsocket(getnameinfo);
1790 static void nwrap_bind_symbol_all(void)
1792 static pthread_once_t all_symbol_binding_once = PTHREAD_ONCE_INIT;
1794 pthread_once(&all_symbol_binding_once, __nwrap_bind_symbol_all_once);
1797 /*********************************************************
1798 * NWRAP NSS MODULE LOADER FUNCTIONS
1799 *********************************************************/
1801 static void *_nwrap_bind_nss_module_symbol(struct nwrap_backend *b,
1802 const char *fn_name)
1804 void *res = NULL;
1805 char *s = NULL;
1806 int rc;
1808 if (b->so_handle == NULL) {
1809 NWRAP_LOG(NWRAP_LOG_ERROR, "No handle");
1810 return NULL;
1813 rc = asprintf(&s, "_nss_%s_%s", b->name, fn_name);
1814 if (rc == -1) {
1815 NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
1816 return NULL;
1819 res = dlsym(b->so_handle, s);
1820 if (res == NULL) {
1821 NWRAP_LOG(NWRAP_LOG_WARN,
1822 "Cannot find function %s in %s",
1823 s, b->so_path);
1825 SAFE_FREE(s);
1826 return res;
1829 #define nwrap_nss_module_bind_symbol(sym_name) \
1830 if (symbols->_nss_##sym_name.obj == NULL) { \
1831 symbols->_nss_##sym_name.obj = \
1832 _nwrap_bind_nss_module_symbol(b, #sym_name); \
1835 #define nwrap_nss_module_bind_symbol2(sym_name, alt_name) \
1836 if (symbols->_nss_##sym_name.obj == NULL) { \
1837 symbols->_nss_##sym_name.obj = \
1838 _nwrap_bind_nss_module_symbol(b, #alt_name); \
1841 static struct nwrap_nss_module_symbols *
1842 nwrap_bind_nss_module_symbols(struct nwrap_backend *b)
1844 struct nwrap_nss_module_symbols *symbols;
1846 if (!b->so_handle) {
1847 return NULL;
1850 symbols = calloc(1, sizeof(struct nwrap_nss_module_symbols));
1851 if (symbols == NULL) {
1852 return NULL;
1855 nwrap_nss_module_bind_symbol(getpwnam_r);
1856 nwrap_nss_module_bind_symbol(getpwuid_r);
1857 nwrap_nss_module_bind_symbol(setpwent);
1858 nwrap_nss_module_bind_symbol(getpwent_r);
1859 nwrap_nss_module_bind_symbol(endpwent);
1860 nwrap_nss_module_bind_symbol(initgroups_dyn);
1861 nwrap_nss_module_bind_symbol(getgrnam_r);
1862 nwrap_nss_module_bind_symbol(getgrgid_r);
1863 nwrap_nss_module_bind_symbol(setgrent);
1864 nwrap_nss_module_bind_symbol(getgrent_r);
1865 nwrap_nss_module_bind_symbol(endgrent);
1866 nwrap_nss_module_bind_symbol(gethostbyaddr_r);
1867 nwrap_nss_module_bind_symbol(gethostbyname2_r);
1869 return symbols;
1872 static void *nwrap_load_module(const char *so_path)
1874 void *h;
1876 if (!so_path || !strlen(so_path)) {
1877 return NULL;
1880 h = dlopen(so_path, RTLD_LAZY);
1881 if (!h) {
1882 NWRAP_LOG(NWRAP_LOG_ERROR,
1883 "Cannot open shared library %s",
1884 so_path);
1885 return NULL;
1888 return h;
1891 static bool nwrap_module_init(const char *name,
1892 struct nwrap_ops *ops,
1893 const char *so_path,
1894 size_t *num_backends,
1895 struct nwrap_backend **backends)
1897 struct nwrap_backend *b = NULL;
1898 size_t n = *num_backends + 1;
1900 b = realloc(*backends, sizeof(struct nwrap_backend) * n);
1901 if (b == NULL) {
1902 NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
1903 return false;
1905 *backends = b;
1907 b = &((*backends)[*num_backends]);
1909 *b = (struct nwrap_backend) {
1910 .name = name,
1911 .ops = ops,
1912 .so_path = so_path,
1915 if (so_path != NULL) {
1916 b->so_handle = nwrap_load_module(so_path);
1917 b->symbols = nwrap_bind_nss_module_symbols(b);
1918 if (b->symbols == NULL) {
1919 return false;
1923 *num_backends = n;
1925 return true;
1928 static void nwrap_libc_init(struct nwrap_main *r)
1930 r->libc = calloc(1, sizeof(struct nwrap_libc));
1931 if (r->libc == NULL) {
1932 printf("Failed to allocate memory for libc");
1933 exit(-1);
1937 static void nwrap_backend_init(struct nwrap_main *r)
1939 const char *module_so_path = getenv("NSS_WRAPPER_MODULE_SO_PATH");
1940 const char *module_fn_name = getenv("NSS_WRAPPER_MODULE_FN_PREFIX");
1942 r->num_backends = 0;
1943 r->backends = NULL;
1945 if (!nwrap_module_init("files", &nwrap_files_ops, NULL,
1946 &r->num_backends,
1947 &r->backends)) {
1948 NWRAP_LOG(NWRAP_LOG_ERROR,
1949 "Failed to initialize 'files' backend");
1950 return;
1953 if (module_so_path != NULL &&
1954 module_so_path[0] != '\0' &&
1955 module_fn_name != NULL &&
1956 module_fn_name[0] != '\0') {
1957 if (!nwrap_module_init(module_fn_name,
1958 &nwrap_module_ops,
1959 module_so_path,
1960 &r->num_backends,
1961 &r->backends)) {
1962 NWRAP_LOG(NWRAP_LOG_ERROR,
1963 "Failed to initialize '%s' backend",
1964 module_fn_name);
1965 return;
1970 static int _nss_wrapper_init_mutex(pthread_mutex_t *m, const char *name)
1972 pthread_mutexattr_t ma;
1973 bool need_destroy = false;
1974 int ret = 0;
1976 #define __CHECK(cmd) do { \
1977 ret = cmd; \
1978 if (ret != 0) { \
1979 NWRAP_LOG(NWRAP_LOG_ERROR, \
1980 "%s: %s - failed %d", \
1981 name, #cmd, ret); \
1982 goto done; \
1984 } while(0)
1986 *m = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
1987 __CHECK(pthread_mutexattr_init(&ma));
1988 need_destroy = true;
1989 __CHECK(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK));
1990 __CHECK(pthread_mutex_init(m, &ma));
1991 done:
1992 if (need_destroy) {
1993 pthread_mutexattr_destroy(&ma);
1995 return ret;
1998 static void nwrap_init(void)
2000 const char *env;
2001 char *endptr;
2002 size_t max_hostents_tmp;
2003 int ok;
2005 nwrap_mutex_lock(&nwrap_initialized_mutex);
2006 if (nwrap_initialized) {
2007 nwrap_mutex_unlock(&nwrap_initialized_mutex);
2008 return;
2012 * Still holding nwrap_initialized lock here.
2013 * We don't use NWRAP_(UN)LOCK_ALL macros here because we
2014 * want to avoid overhead when other threads do their job.
2016 nwrap_mutex_lock(&nwrap_global_mutex);
2017 nwrap_mutex_lock(&nwrap_gr_global_mutex);
2018 nwrap_mutex_lock(&nwrap_he_global_mutex);
2019 nwrap_mutex_lock(&nwrap_pw_global_mutex);
2020 nwrap_mutex_lock(&nwrap_sp_global_mutex);
2022 nwrap_initialized = true;
2024 env = getenv("NSS_WRAPPER_MAX_HOSTENTS");
2025 if (env != NULL) {
2026 max_hostents_tmp = (size_t)strtoul(env, &endptr, 10);
2027 if ((*env == '\0') ||
2028 (*endptr != '\0') ||
2029 (max_hostents_tmp == 0)) {
2030 NWRAP_LOG(NWRAP_LOG_DEBUG,
2031 "Error parsing NSS_WRAPPER_MAX_HOSTENTS "
2032 "value or value is too small. "
2033 "Using default value: %lu.",
2034 (unsigned long)max_hostents);
2035 } else {
2036 max_hostents = max_hostents_tmp;
2039 /* Initialize hash table */
2040 NWRAP_LOG(NWRAP_LOG_DEBUG,
2041 "Initializing hash table of size %lu items.",
2042 (unsigned long)max_hostents);
2043 ok = hcreate(max_hostents);
2044 if (!ok) {
2045 NWRAP_LOG(NWRAP_LOG_ERROR,
2046 "Failed to initialize hash table");
2047 exit(-1);
2050 nwrap_main_global = &__nwrap_main_global;
2052 nwrap_libc_init(nwrap_main_global);
2054 nwrap_backend_init(nwrap_main_global);
2056 /* passwd */
2057 nwrap_pw_global.cache = &__nwrap_cache_pw;
2059 nwrap_pw_global.cache->path = getenv("NSS_WRAPPER_PASSWD");
2060 nwrap_pw_global.cache->fp = NULL;
2061 nwrap_pw_global.cache->fd = -1;
2062 nwrap_pw_global.cache->private_data = &nwrap_pw_global;
2063 nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
2064 nwrap_pw_global.cache->unload = nwrap_pw_unload;
2066 /* shadow */
2067 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
2068 nwrap_sp_global.cache = &__nwrap_cache_sp;
2070 nwrap_sp_global.cache->path = getenv("NSS_WRAPPER_SHADOW");
2071 nwrap_sp_global.cache->fp = NULL;
2072 nwrap_sp_global.cache->fd = -1;
2073 nwrap_sp_global.cache->private_data = &nwrap_sp_global;
2074 nwrap_sp_global.cache->parse_line = nwrap_sp_parse_line;
2075 nwrap_sp_global.cache->unload = nwrap_sp_unload;
2076 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
2078 /* group */
2079 nwrap_gr_global.cache = &__nwrap_cache_gr;
2081 nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
2082 nwrap_gr_global.cache->fp = NULL;
2083 nwrap_gr_global.cache->fd = -1;
2084 nwrap_gr_global.cache->private_data = &nwrap_gr_global;
2085 nwrap_gr_global.cache->parse_line = nwrap_gr_parse_line;
2086 nwrap_gr_global.cache->unload = nwrap_gr_unload;
2088 /* hosts */
2089 nwrap_he_global.cache = &__nwrap_cache_he;
2091 nwrap_he_global.cache->path = getenv("NSS_WRAPPER_HOSTS");
2092 nwrap_he_global.cache->fp = NULL;
2093 nwrap_he_global.cache->fd = -1;
2094 nwrap_he_global.cache->private_data = &nwrap_he_global;
2095 nwrap_he_global.cache->parse_line = nwrap_he_parse_line;
2096 nwrap_he_global.cache->unload = nwrap_he_unload;
2098 /* We hold all locks here so we can use NWRAP_UNLOCK_ALL. */
2099 nwrap_mutex_unlock(&nwrap_sp_global_mutex);
2100 nwrap_mutex_unlock(&nwrap_pw_global_mutex);
2101 nwrap_mutex_unlock(&nwrap_he_global_mutex);
2102 nwrap_mutex_unlock(&nwrap_gr_global_mutex);
2103 nwrap_mutex_unlock(&nwrap_global_mutex);
2104 nwrap_mutex_unlock(&nwrap_initialized_mutex);
2107 bool nss_wrapper_enabled(void)
2109 nwrap_init();
2111 if (nwrap_pw_global.cache->path == NULL ||
2112 nwrap_pw_global.cache->path[0] == '\0') {
2113 return false;
2115 if (nwrap_gr_global.cache->path == NULL ||
2116 nwrap_gr_global.cache->path[0] == '\0') {
2117 return false;
2120 return true;
2123 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
2124 bool nss_wrapper_shadow_enabled(void)
2126 nwrap_init();
2128 if (nwrap_sp_global.cache->path == NULL ||
2129 nwrap_sp_global.cache->path[0] == '\0') {
2130 return false;
2133 return true;
2135 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
2137 bool nss_wrapper_hosts_enabled(void)
2139 nwrap_init();
2141 if (nwrap_he_global.cache->path == NULL ||
2142 nwrap_he_global.cache->path[0] == '\0') {
2143 return false;
2146 return true;
2149 static bool nwrap_hostname_enabled(void)
2151 nwrap_init();
2153 if (getenv("NSS_WRAPPER_HOSTNAME") == NULL) {
2154 return false;
2157 return true;
2160 static bool nwrap_parse_file(struct nwrap_cache *nwrap)
2162 char *line = NULL;
2163 ssize_t n;
2164 /* Unused but getline needs it */
2165 size_t len;
2166 bool ok;
2168 if (nwrap->st.st_size == 0) {
2169 NWRAP_LOG(NWRAP_LOG_DEBUG, "size == 0");
2170 return true;
2173 /* Support for 32-bit system I guess */
2174 if (nwrap->st.st_size > INT32_MAX) {
2175 NWRAP_LOG(NWRAP_LOG_ERROR,
2176 "Size[%u] larger than INT32_MAX",
2177 (unsigned)nwrap->st.st_size);
2178 return false;
2181 rewind(nwrap->fp);
2183 do {
2184 n = getline(&line, &len, nwrap->fp);
2185 if (n < 0) {
2186 SAFE_FREE(line);
2187 if (feof(nwrap->fp)) {
2188 break;
2191 NWRAP_LOG(NWRAP_LOG_ERROR,
2192 "Unable to read line from file: %s",
2193 nwrap->path);
2194 return false;
2197 if (line[n - 1] == '\n') {
2198 line[n - 1] = '\0';
2201 if (line[0] == '\0') {
2202 SAFE_FREE(line);
2203 continue;
2206 ok = nwrap->parse_line(nwrap, line);
2207 if (!ok) {
2208 NWRAP_LOG(NWRAP_LOG_ERROR,
2209 "Unable to parse line file: %s",
2210 line);
2211 SAFE_FREE(line);
2212 return false;
2215 /* Line is parsed without issues so add it to list */
2216 ok = nwrap_vector_add_item(&(nwrap->lines), (void *const) line);
2217 if (!ok) {
2218 NWRAP_LOG(NWRAP_LOG_ERROR,
2219 "Unable to add line to vector");
2220 return false;
2223 /* This forces getline to allocate new memory for line. */
2224 line = NULL;
2225 } while (!feof(nwrap->fp));
2227 return true;
2230 static void nwrap_files_cache_unload(struct nwrap_cache *nwrap)
2232 nwrap->unload(nwrap);
2234 nwrap_lines_unload(nwrap);
2237 static bool nwrap_files_cache_reload(struct nwrap_cache *nwrap)
2239 struct stat st;
2240 int ret;
2241 bool ok;
2242 bool retried = false;
2244 assert(nwrap != NULL);
2246 reopen:
2247 if (nwrap->fd < 0) {
2248 nwrap->fp = fopen(nwrap->path, "re");
2249 if (nwrap->fp == NULL) {
2250 nwrap->fd = -1;
2251 NWRAP_LOG(NWRAP_LOG_ERROR,
2252 "Unable to open '%s' readonly %d:%s",
2253 nwrap->path, nwrap->fd,
2254 strerror(errno));
2255 return false;
2258 nwrap->fd = fileno(nwrap->fp);
2259 NWRAP_LOG(NWRAP_LOG_DEBUG, "Open '%s'", nwrap->path);
2262 ret = fstat(nwrap->fd, &st);
2263 if (ret != 0 && errno == EBADF && retried == false) {
2264 /* maybe something closed the fd on our behalf */
2265 NWRAP_LOG(NWRAP_LOG_TRACE,
2266 "fstat(%s) - %d:%s - reopen",
2267 nwrap->path,
2268 ret,
2269 strerror(errno));
2270 retried = true;
2271 memset(&nwrap->st, 0, sizeof(nwrap->st));
2272 fclose(nwrap->fp);
2273 nwrap->fp = NULL;
2274 nwrap->fd = -1;
2275 goto reopen;
2277 else if (ret != 0) {
2278 NWRAP_LOG(NWRAP_LOG_ERROR,
2279 "fstat(%s) - %d:%s",
2280 nwrap->path,
2281 ret,
2282 strerror(errno));
2283 fclose(nwrap->fp);
2284 nwrap->fp = NULL;
2285 nwrap->fd = -1;
2286 return false;
2289 if (retried == false && st.st_nlink == 0) {
2290 /* maybe someone has replaced the file... */
2291 NWRAP_LOG(NWRAP_LOG_TRACE,
2292 "st_nlink == 0, reopen %s",
2293 nwrap->path);
2294 retried = true;
2295 memset(&nwrap->st, 0, sizeof(nwrap->st));
2296 fclose(nwrap->fp);
2297 nwrap->fp = NULL;
2298 nwrap->fd = -1;
2299 goto reopen;
2302 if (st.st_mtime == nwrap->st.st_mtime) {
2303 NWRAP_LOG(NWRAP_LOG_TRACE,
2304 "st_mtime[%u] hasn't changed, skip reload",
2305 (unsigned)st.st_mtime);
2306 return true;
2309 NWRAP_LOG(NWRAP_LOG_TRACE,
2310 "st_mtime has changed [%u] => [%u], start reload",
2311 (unsigned)st.st_mtime,
2312 (unsigned)nwrap->st.st_mtime);
2314 nwrap->st = st;
2316 nwrap_files_cache_unload(nwrap);
2318 ok = nwrap_parse_file(nwrap);
2319 if (!ok) {
2320 NWRAP_LOG(NWRAP_LOG_ERROR, "Failed to reload %s", nwrap->path);
2321 nwrap_files_cache_unload(nwrap);
2322 return false;
2325 NWRAP_LOG(NWRAP_LOG_TRACE, "Reloaded %s", nwrap->path);
2326 return true;
2330 * the caller has to call nwrap_unload() on failure
2332 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
2334 struct nwrap_pw *nwrap_pw;
2335 char *c;
2336 char *p;
2337 char *e;
2338 struct passwd *pw;
2339 size_t list_size;
2341 nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
2343 list_size = sizeof(*nwrap_pw->list) * (nwrap_pw->num+1);
2344 pw = (struct passwd *)realloc(nwrap_pw->list, list_size);
2345 if (!pw) {
2346 NWRAP_LOG(NWRAP_LOG_ERROR,
2347 "realloc(%u) failed",
2348 (unsigned)list_size);
2349 return false;
2351 nwrap_pw->list = pw;
2353 pw = &nwrap_pw->list[nwrap_pw->num];
2355 c = line;
2357 /* name */
2358 p = strchr(c, ':');
2359 if (!p) {
2360 NWRAP_LOG(NWRAP_LOG_ERROR,
2361 "Invalid line[%s]: '%s'",
2362 line,
2364 return false;
2366 *p = '\0';
2367 p++;
2368 pw->pw_name = c;
2369 c = p;
2371 NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]\n", pw->pw_name);
2373 /* password */
2374 p = strchr(c, ':');
2375 if (!p) {
2376 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
2377 return false;
2379 *p = '\0';
2380 p++;
2381 pw->pw_passwd = c;
2382 c = p;
2384 NWRAP_LOG(NWRAP_LOG_TRACE, "password[%s]\n", pw->pw_passwd);
2386 /* uid */
2387 p = strchr(c, ':');
2388 if (!p) {
2389 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
2390 return false;
2392 *p = '\0';
2393 p++;
2394 e = NULL;
2395 pw->pw_uid = (uid_t)strtoul(c, &e, 10);
2396 if (c == e) {
2397 NWRAP_LOG(NWRAP_LOG_ERROR,
2398 "Invalid line[%s]: '%s' - %s",
2399 line, c, strerror(errno));
2400 return false;
2402 if (e == NULL) {
2403 NWRAP_LOG(NWRAP_LOG_ERROR,
2404 "Invalid line[%s]: '%s' - %s",
2405 line, c, strerror(errno));
2406 return false;
2408 if (e[0] != '\0') {
2409 NWRAP_LOG(NWRAP_LOG_ERROR,
2410 "Invalid line[%s]: '%s' - %s",
2411 line, c, strerror(errno));
2412 return false;
2414 c = p;
2416 NWRAP_LOG(NWRAP_LOG_TRACE, "uid[%u]", pw->pw_uid);
2418 /* gid */
2419 p = strchr(c, ':');
2420 if (!p) {
2421 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
2422 return false;
2424 *p = '\0';
2425 p++;
2426 e = NULL;
2427 pw->pw_gid = (gid_t)strtoul(c, &e, 10);
2428 if (c == e) {
2429 NWRAP_LOG(NWRAP_LOG_ERROR,
2430 "Invalid line[%s]: '%s' - %s",
2431 line, c, strerror(errno));
2432 return false;
2434 if (e == NULL) {
2435 NWRAP_LOG(NWRAP_LOG_ERROR,
2436 "Invalid line[%s]: '%s' - %s",
2437 line, c, strerror(errno));
2438 return false;
2440 if (e[0] != '\0') {
2441 NWRAP_LOG(NWRAP_LOG_ERROR,
2442 "Invalid line[%s]: '%s' - %s",
2443 line, c, strerror(errno));
2444 return false;
2446 c = p;
2448 NWRAP_LOG(NWRAP_LOG_TRACE, "gid[%u]\n", pw->pw_gid);
2450 #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
2451 pw->pw_class = discard_const_p(char, "");
2453 NWRAP_LOG(NWRAP_LOG_TRACE, "class[%s]", pw->pw_class);
2454 #endif /* HAVE_STRUCT_PASSWD_PW_CLASS */
2456 #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
2457 pw->pw_change = 0;
2459 NWRAP_LOG(NWRAP_LOG_TRACE,
2460 "change[%lu]",
2461 (unsigned long)pw->pw_change);
2462 #endif /* HAVE_STRUCT_PASSWD_PW_CHANGE */
2464 #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
2465 pw->pw_expire = 0;
2467 NWRAP_LOG(NWRAP_LOG_TRACE,
2468 "expire[%lu]",
2469 (unsigned long)pw->pw_expire);
2470 #endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE */
2472 /* gecos */
2473 p = strchr(c, ':');
2474 if (!p) {
2475 NWRAP_LOG(NWRAP_LOG_ERROR, "invalid line[%s]: '%s'", line, c);
2476 return false;
2478 *p = '\0';
2479 p++;
2480 pw->pw_gecos = c;
2481 c = p;
2483 NWRAP_LOG(NWRAP_LOG_TRACE, "gecos[%s]", pw->pw_gecos);
2485 /* dir */
2486 p = strchr(c, ':');
2487 if (!p) {
2488 NWRAP_LOG(NWRAP_LOG_ERROR, "'%s'", c);
2489 return false;
2491 *p = '\0';
2492 p++;
2493 pw->pw_dir = c;
2494 c = p;
2496 NWRAP_LOG(NWRAP_LOG_TRACE, "dir[%s]", pw->pw_dir);
2498 /* shell */
2499 pw->pw_shell = c;
2500 NWRAP_LOG(NWRAP_LOG_TRACE, "shell[%s]", pw->pw_shell);
2502 NWRAP_LOG(NWRAP_LOG_DEBUG,
2503 "Added user[%s:%s:%u:%u:%s:%s:%s]",
2504 pw->pw_name, pw->pw_passwd,
2505 pw->pw_uid, pw->pw_gid,
2506 pw->pw_gecos, pw->pw_dir, pw->pw_shell);
2508 nwrap_pw->num++;
2509 return true;
2512 static void nwrap_pw_unload(struct nwrap_cache *nwrap)
2514 struct nwrap_pw *nwrap_pw;
2515 nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
2517 SAFE_FREE(nwrap_pw->list);
2518 nwrap_pw->num = 0;
2519 nwrap_pw->idx = 0;
2522 static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
2523 char *buf, size_t buflen, struct passwd **dstp)
2525 char *first;
2526 char *last;
2527 off_t ofs;
2529 first = src->pw_name;
2531 last = src->pw_shell;
2532 while (*last) last++;
2534 ofs = PTR_DIFF(last + 1, first);
2536 if (ofs > (off_t) buflen) {
2537 return ERANGE;
2540 memcpy(buf, first, ofs);
2542 ofs = PTR_DIFF(src->pw_name, first);
2543 dst->pw_name = buf + ofs;
2544 ofs = PTR_DIFF(src->pw_passwd, first);
2545 dst->pw_passwd = buf + ofs;
2546 dst->pw_uid = src->pw_uid;
2547 dst->pw_gid = src->pw_gid;
2548 #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
2549 ofs = PTR_DIFF(src->pw_class, first);
2550 dst->pw_class = buf + ofs;
2551 #endif /* HAVE_STRUCT_PASSWD_PW_CLASS */
2553 #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
2554 dst->pw_change = 0;
2555 #endif /* HAVE_STRUCT_PASSWD_PW_CHANGE */
2557 #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
2558 dst->pw_expire = 0;
2559 #endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE */
2561 ofs = PTR_DIFF(src->pw_gecos, first);
2562 dst->pw_gecos = buf + ofs;
2563 ofs = PTR_DIFF(src->pw_dir, first);
2564 dst->pw_dir = buf + ofs;
2565 ofs = PTR_DIFF(src->pw_shell, first);
2566 dst->pw_shell = buf + ofs;
2568 if (dstp) {
2569 *dstp = dst;
2572 return 0;
2575 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
2576 static bool nwrap_sp_parse_line(struct nwrap_cache *nwrap, char *line)
2578 struct nwrap_sp *nwrap_sp;
2579 struct spwd *sp;
2580 size_t list_size;
2581 char *c;
2582 char *e;
2583 char *p;
2585 nwrap_sp = (struct nwrap_sp *)nwrap->private_data;
2587 list_size = sizeof(*nwrap_sp->list) * (nwrap_sp->num+1);
2588 sp = (struct spwd *)realloc(nwrap_sp->list, list_size);
2589 if (sp == NULL) {
2590 NWRAP_LOG(NWRAP_LOG_ERROR,
2591 "realloc(%u) failed",
2592 (unsigned)list_size);
2593 return false;
2595 nwrap_sp->list = sp;
2597 sp = &nwrap_sp->list[nwrap_sp->num];
2599 c = line;
2601 /* name */
2602 p = strchr(c, ':');
2603 if (p == NULL) {
2604 NWRAP_LOG(NWRAP_LOG_ERROR,
2605 "name -- Invalid line[%s]: '%s'",
2606 line,
2608 return false;
2610 *p = '\0';
2611 p++;
2612 sp->sp_namp = c;
2613 c = p;
2615 NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]\n", sp->sp_namp);
2617 /* pwd */
2618 p = strchr(c, ':');
2619 if (p == NULL) {
2620 NWRAP_LOG(NWRAP_LOG_ERROR,
2621 "pwd -- Invalid line[%s]: '%s'",
2622 line,
2624 return false;
2626 *p = '\0';
2627 p++;
2628 sp->sp_pwdp = c;
2629 c = p;
2631 /* lstchg (long) */
2632 if (c[0] == ':') {
2633 sp->sp_lstchg = -1;
2634 p++;
2635 } else {
2636 p = strchr(c, ':');
2637 if (p == NULL) {
2638 NWRAP_LOG(NWRAP_LOG_ERROR,
2639 "lstchg -- Invalid line[%s]: '%s'",
2640 line,
2642 return false;
2644 *p = '\0';
2645 p++;
2646 sp->sp_lstchg = strtol(c, &e, 10);
2647 if (c == e) {
2648 NWRAP_LOG(NWRAP_LOG_ERROR,
2649 "lstchg -- Invalid line[%s]: '%s' - %s",
2650 line, c, strerror(errno));
2651 return false;
2653 if (e == NULL) {
2654 NWRAP_LOG(NWRAP_LOG_ERROR,
2655 "lstchg -- Invalid line[%s]: '%s' - %s",
2656 line, c, strerror(errno));
2657 return false;
2659 if (e[0] != '\0') {
2660 NWRAP_LOG(NWRAP_LOG_ERROR,
2661 "lstchg -- Invalid line[%s]: '%s' - %s",
2662 line, c, strerror(errno));
2663 return false;
2666 c = p;
2668 /* min (long) */
2669 if (c[0] == ':') {
2670 sp->sp_min = -1;
2671 p++;
2672 } else {
2673 p = strchr(c, ':');
2674 if (p == NULL) {
2675 NWRAP_LOG(NWRAP_LOG_ERROR,
2676 "min -- Invalid line[%s]: '%s'",
2677 line,
2679 return false;
2681 *p = '\0';
2682 p++;
2683 sp->sp_min = strtol(c, &e, 10);
2684 if (c == e) {
2685 NWRAP_LOG(NWRAP_LOG_ERROR,
2686 "min -- Invalid line[%s]: '%s' - %s",
2687 line, c, strerror(errno));
2688 return false;
2690 if (e == NULL) {
2691 NWRAP_LOG(NWRAP_LOG_ERROR,
2692 "min -- Invalid line[%s]: '%s' - %s",
2693 line, c, strerror(errno));
2694 return false;
2696 if (e[0] != '\0') {
2697 NWRAP_LOG(NWRAP_LOG_ERROR,
2698 "min -- Invalid line[%s]: '%s' - %s",
2699 line, c, strerror(errno));
2700 return false;
2703 c = p;
2705 /* max (long) */
2706 if (c[0] == ':') {
2707 sp->sp_max = -1;
2708 p++;
2709 } else {
2710 p = strchr(c, ':');
2711 if (p == NULL) {
2712 NWRAP_LOG(NWRAP_LOG_ERROR,
2713 "max -- Invalid line[%s]: '%s'",
2714 line,
2716 return false;
2718 *p = '\0';
2719 p++;
2720 sp->sp_max = strtol(c, &e, 10);
2721 if (c == e) {
2722 NWRAP_LOG(NWRAP_LOG_ERROR,
2723 "max -- Invalid line[%s]: '%s' - %s",
2724 line, c, strerror(errno));
2725 return false;
2727 if (e == NULL) {
2728 NWRAP_LOG(NWRAP_LOG_ERROR,
2729 "max -- Invalid line[%s]: '%s' - %s",
2730 line, c, strerror(errno));
2731 return false;
2733 if (e[0] != '\0') {
2734 NWRAP_LOG(NWRAP_LOG_ERROR,
2735 "max -- Invalid line[%s]: '%s' - %s",
2736 line, c, strerror(errno));
2737 return false;
2740 c = p;
2742 /* warn (long) */
2743 if (c[0] == ':') {
2744 sp->sp_warn = -1;
2745 p++;
2746 } else {
2747 p = strchr(c, ':');
2748 if (p == NULL) {
2749 NWRAP_LOG(NWRAP_LOG_ERROR,
2750 "warn -- Invalid line[%s]: '%s'",
2751 line,
2753 return false;
2755 *p = '\0';
2756 p++;
2757 sp->sp_warn = strtol(c, &e, 10);
2758 if (c == e) {
2759 NWRAP_LOG(NWRAP_LOG_ERROR,
2760 "warn -- Invalid line[%s]: '%s' - %s",
2761 line, c, strerror(errno));
2762 return false;
2764 if (e == NULL) {
2765 NWRAP_LOG(NWRAP_LOG_ERROR,
2766 "warn -- Invalid line[%s]: '%s' - %s",
2767 line, c, strerror(errno));
2768 return false;
2770 if (e[0] != '\0') {
2771 NWRAP_LOG(NWRAP_LOG_ERROR,
2772 "warn -- Invalid line[%s]: '%s' - %s",
2773 line, c, strerror(errno));
2774 return false;
2777 c = p;
2779 /* inact (long) */
2780 if (c[0] == ':') {
2781 sp->sp_inact = -1;
2782 p++;
2783 } else {
2784 p = strchr(c, ':');
2785 if (p == NULL) {
2786 NWRAP_LOG(NWRAP_LOG_ERROR,
2787 "inact -- Invalid line[%s]: '%s'",
2788 line,
2790 return false;
2792 *p = '\0';
2793 p++;
2794 sp->sp_inact = strtol(c, &e, 10);
2795 if (c == e) {
2796 NWRAP_LOG(NWRAP_LOG_ERROR,
2797 "inact -- Invalid line[%s]: '%s' - %s",
2798 line, c, strerror(errno));
2799 return false;
2801 if (e == NULL) {
2802 NWRAP_LOG(NWRAP_LOG_ERROR,
2803 "inact -- Invalid line[%s]: '%s' - %s",
2804 line, c, strerror(errno));
2805 return false;
2807 if (e[0] != '\0') {
2808 NWRAP_LOG(NWRAP_LOG_ERROR,
2809 "inact -- Invalid line[%s]: '%s' - %s",
2810 line, c, strerror(errno));
2811 return false;
2814 c = p;
2816 /* expire (long) */
2817 if (c[0] == ':') {
2818 sp->sp_expire = -1;
2819 p++;
2820 } else {
2821 p = strchr(c, ':');
2822 if (p == NULL) {
2823 NWRAP_LOG(NWRAP_LOG_ERROR,
2824 "expire -- Invalid line[%s]: '%s'",
2825 line,
2827 return false;
2829 *p = '\0';
2830 p++;
2831 sp->sp_expire = strtol(c, &e, 10);
2832 if (c == e) {
2833 NWRAP_LOG(NWRAP_LOG_ERROR,
2834 "expire -- Invalid line[%s]: '%s' - %s",
2835 line, c, strerror(errno));
2836 return false;
2838 if (e == NULL) {
2839 NWRAP_LOG(NWRAP_LOG_ERROR,
2840 "expire -- Invalid line[%s]: '%s' - %s",
2841 line, c, strerror(errno));
2842 return false;
2844 if (e[0] != '\0') {
2845 NWRAP_LOG(NWRAP_LOG_ERROR,
2846 "expire -- Invalid line[%s]: '%s' - %s",
2847 line, c, strerror(errno));
2848 return false;
2851 c = p;
2853 nwrap_sp->num++;
2854 return true;
2857 static void nwrap_sp_unload(struct nwrap_cache *nwrap)
2859 struct nwrap_sp *nwrap_sp;
2860 nwrap_sp = (struct nwrap_sp *)nwrap->private_data;
2862 SAFE_FREE(nwrap_sp->list);
2863 nwrap_sp->num = 0;
2864 nwrap_sp->idx = 0;
2866 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
2869 * the caller has to call nwrap_unload() on failure
2871 static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
2873 struct nwrap_gr *nwrap_gr;
2874 char *c;
2875 char *p;
2876 char *e;
2877 struct group *gr;
2878 size_t list_size;
2879 unsigned nummem;
2881 nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
2883 list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
2884 gr = (struct group *)realloc(nwrap_gr->list, list_size);
2885 if (!gr) {
2886 NWRAP_LOG(NWRAP_LOG_ERROR, "realloc failed");
2887 return false;
2889 nwrap_gr->list = gr;
2891 gr = &nwrap_gr->list[nwrap_gr->num];
2893 c = line;
2895 /* name */
2896 p = strchr(c, ':');
2897 if (!p) {
2898 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
2899 return false;
2901 *p = '\0';
2902 p++;
2903 gr->gr_name = c;
2904 c = p;
2906 NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]", gr->gr_name);
2908 /* password */
2909 p = strchr(c, ':');
2910 if (!p) {
2911 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
2912 return false;
2914 *p = '\0';
2915 p++;
2916 gr->gr_passwd = c;
2917 c = p;
2919 NWRAP_LOG(NWRAP_LOG_TRACE, "password[%s]", gr->gr_passwd);
2921 /* gid */
2922 p = strchr(c, ':');
2923 if (!p) {
2924 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
2925 return false;
2927 *p = '\0';
2928 p++;
2929 e = NULL;
2930 gr->gr_gid = (gid_t)strtoul(c, &e, 10);
2931 if (c == e) {
2932 NWRAP_LOG(NWRAP_LOG_ERROR,
2933 "Invalid line[%s]: '%s' - %s",
2934 line, c, strerror(errno));
2935 return false;
2937 if (e == NULL) {
2938 NWRAP_LOG(NWRAP_LOG_ERROR,
2939 "Invalid line[%s]: '%s' - %s",
2940 line, c, strerror(errno));
2941 return false;
2943 if (e[0] != '\0') {
2944 NWRAP_LOG(NWRAP_LOG_ERROR,
2945 "Invalid line[%s]: '%s' - %s",
2946 line, c, strerror(errno));
2947 return false;
2949 c = p;
2951 NWRAP_LOG(NWRAP_LOG_TRACE, "gid[%u]", gr->gr_gid);
2953 /* members */
2954 gr->gr_mem = (char **)malloc(sizeof(char *));
2955 if (!gr->gr_mem) {
2956 NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
2957 return false;
2959 gr->gr_mem[0] = NULL;
2961 for(nummem = 0; p != NULL && p[0] != '\0'; nummem++) {
2962 char **m;
2963 size_t m_size;
2964 c = p;
2965 p = strchr(c, ',');
2966 if (p) {
2967 *p = '\0';
2968 p++;
2971 if (strlen(c) == 0) {
2972 break;
2975 m_size = sizeof(char *) * (nummem+2);
2976 m = (char **)realloc(gr->gr_mem, m_size);
2977 if (!m) {
2978 NWRAP_LOG(NWRAP_LOG_ERROR,
2979 "realloc(%zd) failed",
2980 m_size);
2981 return false;
2983 gr->gr_mem = m;
2984 gr->gr_mem[nummem] = c;
2985 gr->gr_mem[nummem+1] = NULL;
2987 NWRAP_LOG(NWRAP_LOG_TRACE,
2988 "member[%u]: '%s'",
2989 nummem, gr->gr_mem[nummem]);
2992 NWRAP_LOG(NWRAP_LOG_DEBUG,
2993 "Added group[%s:%s:%u:] with %u members",
2994 gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem);
2996 nwrap_gr->num++;
2997 return true;
3000 static void nwrap_gr_unload(struct nwrap_cache *nwrap)
3002 int i;
3003 struct nwrap_gr *nwrap_gr;
3004 nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
3006 if (nwrap_gr->list) {
3007 for (i=0; i < nwrap_gr->num; i++) {
3008 SAFE_FREE(nwrap_gr->list[i].gr_mem);
3010 SAFE_FREE(nwrap_gr->list);
3013 nwrap_gr->num = 0;
3014 nwrap_gr->idx = 0;
3017 static struct nwrap_entlist *nwrap_entlist_init(struct nwrap_entdata *ed)
3019 struct nwrap_entlist *el;
3021 if (ed == NULL) {
3022 NWRAP_LOG(NWRAP_LOG_ERROR,
3023 "entry is NULL, can't create list item");
3024 return NULL;
3027 el = (struct nwrap_entlist *)malloc(sizeof(struct nwrap_entlist));
3028 if (el == NULL) {
3029 NWRAP_LOG(NWRAP_LOG_ERROR, "malloc failed");
3030 return NULL;
3033 el->next = NULL;
3034 el->ed = ed;
3036 return el;
3039 static bool nwrap_ed_inventarize_add_new(char *const h_name,
3040 struct nwrap_entdata *const ed)
3042 ENTRY e;
3043 ENTRY *p;
3044 struct nwrap_entlist *el;
3045 bool ok;
3047 if (h_name == NULL) {
3048 NWRAP_LOG(NWRAP_LOG_ERROR, "h_name NULL - can't add");
3049 return false;
3052 el = nwrap_entlist_init(ed);
3053 if (el == NULL) {
3054 return false;
3057 e.key = h_name;
3058 e.data = (void *)el;
3060 p = hsearch(e, ENTER);
3061 if (p == NULL) {
3062 NWRAP_LOG(NWRAP_LOG_ERROR,
3063 "Hash table is full (%s)!",
3064 strerror(errno));
3065 return false;
3068 ok = nwrap_vector_add_item(&(nwrap_he_global.lists), (void *)el);
3069 if (!ok) {
3070 NWRAP_LOG(NWRAP_LOG_ERROR,
3071 "Failed to add list entry to vector.");
3072 return false;
3075 return true;
3078 static bool nwrap_ed_inventarize_add_to_existing(struct nwrap_entdata *const ed,
3079 struct nwrap_entlist *const el)
3081 struct nwrap_entlist *cursor;
3082 struct nwrap_entlist *el_new;
3084 if (el == NULL) {
3085 NWRAP_LOG(NWRAP_LOG_ERROR, "list is NULL, can not add");
3086 return false;
3090 for (cursor = el; cursor->next != NULL; cursor = cursor->next)
3092 if (cursor->ed == ed) {
3093 /* The entry already exists in this list. */
3094 return true;
3098 if (cursor->ed == ed) {
3099 /* The entry already exists in this list. */
3100 return true;
3103 el_new = nwrap_entlist_init(ed);
3104 if (el_new == NULL) {
3105 return false;
3108 cursor->next = el_new;
3109 return true;
3112 static bool nwrap_ed_inventarize(char *const name,
3113 struct nwrap_entdata *const ed)
3115 ENTRY e;
3116 ENTRY *p;
3117 bool ok;
3119 e.key = name;
3120 e.data = NULL;
3122 NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching name: %s", e.key);
3124 p = hsearch(e, FIND);
3125 if (p == NULL) {
3126 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found. Adding...", name);
3127 ok = nwrap_ed_inventarize_add_new(name, ed);
3128 } else {
3129 struct nwrap_entlist *el = (struct nwrap_entlist *)p->data;
3131 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s found. Add record to list.", name);
3132 ok = nwrap_ed_inventarize_add_to_existing(ed, el);
3135 return ok;
3138 static bool nwrap_add_hname(struct nwrap_entdata *const ed)
3140 char *const h_name = (char *const)(ed->ht.h_name);
3141 unsigned i;
3142 bool ok;
3144 ok = nwrap_ed_inventarize(h_name, ed);
3145 if (!ok) {
3146 return false;
3149 if (ed->ht.h_aliases == NULL) {
3150 return true;
3153 /* Itemize aliases */
3154 for (i = 0; ed->ht.h_aliases[i] != NULL; ++i) {
3155 char *h_name_alias;
3157 h_name_alias = ed->ht.h_aliases[i];
3159 NWRAP_LOG(NWRAP_LOG_DEBUG, "Add alias: %s", h_name_alias);
3161 if (!nwrap_ed_inventarize(h_name_alias, ed)) {
3162 NWRAP_LOG(NWRAP_LOG_ERROR,
3163 "Unable to add alias: %s", h_name_alias);
3164 return false;
3168 return true;
3171 static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
3173 struct nwrap_he *nwrap_he = (struct nwrap_he *)nwrap->private_data;
3174 bool do_aliases = true;
3175 ssize_t aliases_count = 0;
3176 char *p;
3177 char *i;
3178 char *n;
3180 char *ip;
3181 bool ok;
3183 struct nwrap_entdata *ed = (struct nwrap_entdata *)
3184 malloc(sizeof(struct nwrap_entdata));
3185 if (ed == NULL) {
3186 NWRAP_LOG(NWRAP_LOG_ERROR,
3187 "Unable to allocate memory for nwrap_entdata");
3188 return false;
3190 ZERO_STRUCTP(ed);
3192 i = line;
3195 * IP
3198 /* Walk to first char */
3199 for (p = i; *p != '.' && *p != ':' && !isxdigit((int) *p); p++) {
3200 if (*p == '\0') {
3201 NWRAP_LOG(NWRAP_LOG_ERROR,
3202 "Invalid line[%s]: '%s'",
3203 line, i);
3204 free(ed);
3205 return false;
3209 for (i = p; !isspace((int)*p); p++) {
3210 if (*p == '\0') {
3211 NWRAP_LOG(NWRAP_LOG_ERROR,
3212 "Invalid line[%s]: '%s'",
3213 line, i);
3214 free(ed);
3215 return false;
3219 *p = '\0';
3221 if (inet_pton(AF_INET, i, ed->addr.host_addr)) {
3222 ed->ht.h_addrtype = AF_INET;
3223 ed->ht.h_length = 4;
3224 #ifdef HAVE_IPV6
3225 } else if (inet_pton(AF_INET6, i, ed->addr.host_addr)) {
3226 ed->ht.h_addrtype = AF_INET6;
3227 ed->ht.h_length = 16;
3228 #endif
3229 } else {
3230 NWRAP_LOG(NWRAP_LOG_ERROR,
3231 "Invalid line[%s]: '%s'",
3232 line, i);
3234 free(ed);
3235 return false;
3237 ip = i;
3239 ok = nwrap_vector_add_item(&(ed->nwrap_addrdata),
3240 (void *const)ed->addr.host_addr);
3241 if (!ok) {
3242 NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add addrdata to vector");
3243 free(ed);
3244 return false;
3246 ed->ht.h_addr_list = nwrap_vector_head(&ed->nwrap_addrdata);
3248 p++;
3251 * FQDN
3254 /* Walk to first char */
3255 for (n = p; *p != '_' && !isalnum((int) *p); p++) {
3256 if (*p == '\0') {
3257 NWRAP_LOG(NWRAP_LOG_ERROR,
3258 "Invalid line[%s]: '%s'",
3259 line, n);
3261 free(ed);
3262 return false;
3266 for (n = p; !isspace((int)*p); p++) {
3267 if (*p == '\0') {
3268 do_aliases = false;
3269 break;
3273 *p = '\0';
3275 /* Convert to lowercase. This operate on same memory region */
3276 str_tolower(n, n);
3277 ed->ht.h_name = n;
3279 /* glib's getent always dereferences he->h_aliases */
3280 ed->ht.h_aliases = malloc(sizeof(char *));
3281 if (ed->ht.h_aliases == NULL) {
3282 free(ed);
3283 return false;
3285 ed->ht.h_aliases[0] = NULL;
3288 * Aliases
3290 while (do_aliases) {
3291 char **aliases;
3292 char *a;
3294 p++;
3296 /* Walk to first char */
3297 for (a = p; *p != '_' && !isalnum((int) *p); p++) {
3298 if (*p == '\0') {
3299 do_aliases = false;
3300 break;
3303 /* Only trailing spaces are left */
3304 if (!do_aliases) {
3305 break;
3308 for (a = p; !isspace((int)*p); p++) {
3309 if (*p == '\0') {
3310 do_aliases = false;
3311 break;
3315 *p = '\0';
3317 aliases = realloc(ed->ht.h_aliases, sizeof(char *) * (aliases_count + 2));
3318 if (aliases == NULL) {
3319 free(ed);
3320 return false;
3322 ed->ht.h_aliases = aliases;
3324 str_tolower(a, a);
3325 aliases[aliases_count] = a;
3326 aliases[aliases_count + 1] = NULL;
3328 aliases_count += 1;
3331 ok = nwrap_vector_add_item(&(nwrap_he->entries), (void *const)ed);
3332 if (!ok) {
3333 NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add entry to vector");
3334 free(ed);
3335 return false;
3338 ed->aliases_count = aliases_count;
3339 /* Inventarize item */
3340 ok = nwrap_add_hname(ed);
3341 if (!ok) {
3342 return false;
3345 ok = nwrap_ed_inventarize(ip, ed);
3346 if (!ok) {
3347 return false;
3350 nwrap_he->num++;
3351 return true;
3354 static void nwrap_he_unload(struct nwrap_cache *nwrap)
3356 struct nwrap_he *nwrap_he =
3357 (struct nwrap_he *)nwrap->private_data;
3358 struct nwrap_entdata *ed;
3359 struct nwrap_entlist *el;
3360 size_t i;
3361 int rc;
3363 nwrap_vector_foreach (ed, nwrap_he->entries, i)
3365 SAFE_FREE(ed->nwrap_addrdata.items);
3366 SAFE_FREE(ed->ht.h_aliases);
3367 SAFE_FREE(ed);
3369 SAFE_FREE(nwrap_he->entries.items);
3370 nwrap_he->entries.count = nwrap_he->entries.capacity = 0;
3372 nwrap_vector_foreach(el, nwrap_he->lists, i)
3374 while (el != NULL) {
3375 struct nwrap_entlist *el_next;
3377 el_next = el->next;
3378 SAFE_FREE(el);
3379 el = el_next;
3382 SAFE_FREE(nwrap_he->lists.items);
3383 nwrap_he->lists.count = nwrap_he->lists.capacity = 0;
3385 nwrap_he->num = 0;
3386 nwrap_he->idx = 0;
3389 * If we unload the file, the pointers in the hash table point to
3390 * invalid memory. So we need to destroy the hash table and recreate
3391 * it.
3393 hdestroy();
3394 rc = hcreate(max_hostents);
3395 if (rc == 0) {
3396 NWRAP_LOG(NWRAP_LOG_ERROR, "Failed to initialize hash table");
3397 exit(-1);
3402 /* user functions */
3403 static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
3404 const char *name)
3406 int i;
3407 bool ok;
3409 (void) b; /* unused */
3411 NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name);
3413 ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
3414 if (!ok) {
3415 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
3416 return NULL;
3419 for (i=0; i<nwrap_pw_global.num; i++) {
3420 if (strcmp(nwrap_pw_global.list[i].pw_name, name) == 0) {
3421 NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] found", name);
3422 return &nwrap_pw_global.list[i];
3424 NWRAP_LOG(NWRAP_LOG_DEBUG,
3425 "user[%s] does not match [%s]",
3426 name,
3427 nwrap_pw_global.list[i].pw_name);
3430 NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] not found\n", name);
3432 errno = ENOENT;
3433 return NULL;
3436 static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
3437 const char *name, struct passwd *pwdst,
3438 char *buf, size_t buflen, struct passwd **pwdstp)
3440 struct passwd *pw;
3442 pw = nwrap_files_getpwnam(b, name);
3443 if (!pw) {
3444 if (errno == 0) {
3445 return ENOENT;
3447 return errno;
3450 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
3453 static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
3454 uid_t uid)
3456 int i;
3457 bool ok;
3459 (void) b; /* unused */
3461 ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
3462 if (!ok) {
3463 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
3464 return NULL;
3467 for (i=0; i<nwrap_pw_global.num; i++) {
3468 if (nwrap_pw_global.list[i].pw_uid == uid) {
3469 NWRAP_LOG(NWRAP_LOG_DEBUG, "uid[%u] found", uid);
3470 return &nwrap_pw_global.list[i];
3472 NWRAP_LOG(NWRAP_LOG_DEBUG,
3473 "uid[%u] does not match [%u]",
3474 uid,
3475 nwrap_pw_global.list[i].pw_uid);
3478 NWRAP_LOG(NWRAP_LOG_DEBUG, "uid[%u] not found\n", uid);
3480 errno = ENOENT;
3481 return NULL;
3484 static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
3485 uid_t uid, struct passwd *pwdst,
3486 char *buf, size_t buflen, struct passwd **pwdstp)
3488 struct passwd *pw;
3490 pw = nwrap_files_getpwuid(b, uid);
3491 if (!pw) {
3492 if (errno == 0) {
3493 return ENOENT;
3495 return errno;
3498 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
3501 /* user enum functions */
3502 static void nwrap_files_setpwent(struct nwrap_backend *b)
3504 (void) b; /* unused */
3506 nwrap_pw_global.idx = 0;
3509 static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b)
3511 struct passwd *pw;
3513 (void) b; /* unused */
3515 if (nwrap_pw_global.idx == 0) {
3516 bool ok;
3517 ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
3518 if (!ok) {
3519 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
3520 return NULL;
3524 if (nwrap_pw_global.idx >= nwrap_pw_global.num) {
3525 errno = ENOENT;
3526 return NULL;
3529 pw = &nwrap_pw_global.list[nwrap_pw_global.idx++];
3531 NWRAP_LOG(NWRAP_LOG_DEBUG,
3532 "return user[%s] uid[%u]",
3533 pw->pw_name, pw->pw_uid);
3535 return pw;
3538 static int nwrap_files_getpwent_r(struct nwrap_backend *b,
3539 struct passwd *pwdst, char *buf,
3540 size_t buflen, struct passwd **pwdstp)
3542 struct passwd *pw;
3544 pw = nwrap_files_getpwent(b);
3545 if (!pw) {
3546 if (errno == 0) {
3547 return ENOENT;
3549 return errno;
3552 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
3555 static void nwrap_files_endpwent(struct nwrap_backend *b)
3557 (void) b; /* unused */
3559 nwrap_pw_global.idx = 0;
3562 /* shadow */
3564 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
3566 #ifdef HAVE_SETSPENT
3567 static void nwrap_files_setspent(void)
3569 nwrap_sp_global.idx = 0;
3572 static struct spwd *nwrap_files_getspent(void)
3574 struct spwd *sp;
3576 if (nwrap_sp_global.idx == 0) {
3577 bool ok;
3579 ok = nwrap_files_cache_reload(nwrap_sp_global.cache);
3580 if (!ok) {
3581 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading shadow file");
3582 return NULL;
3586 if (nwrap_sp_global.idx >= nwrap_sp_global.num) {
3587 errno = ENOENT;
3588 return NULL;
3591 sp = &nwrap_sp_global.list[nwrap_sp_global.idx++];
3593 NWRAP_LOG(NWRAP_LOG_DEBUG,
3594 "return user[%s]",
3595 sp->sp_namp);
3597 return sp;
3600 static void nwrap_files_endspent(void)
3602 nwrap_sp_global.idx = 0;
3604 #endif /* HAVE_SETSPENT */
3606 static struct spwd *nwrap_files_getspnam(const char *name)
3608 int i;
3609 bool ok;
3611 NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name);
3613 ok = nwrap_files_cache_reload(nwrap_sp_global.cache);
3614 if (!ok) {
3615 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading shadow file");
3616 return NULL;
3619 for (i=0; i<nwrap_sp_global.num; i++) {
3620 if (strcmp(nwrap_sp_global.list[i].sp_namp, name) == 0) {
3621 NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] found", name);
3622 return &nwrap_sp_global.list[i];
3624 NWRAP_LOG(NWRAP_LOG_DEBUG,
3625 "user[%s] does not match [%s]",
3626 name,
3627 nwrap_sp_global.list[i].sp_namp);
3630 NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] not found\n", name);
3632 errno = ENOENT;
3633 return NULL;
3635 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
3637 /* misc functions */
3638 static int nwrap_files_initgroups_dyn(struct nwrap_backend *b,
3639 const char *user,
3640 gid_t group,
3641 long int *start,
3642 long int *size,
3643 gid_t **groups,
3644 long int limit,
3645 int *errnop)
3647 struct group *grp;
3648 int i = 0;
3650 (void)errnop; /* unused */
3651 nwrap_files_setgrent(b);
3652 while ((grp = nwrap_files_getgrent(b)) != NULL) {
3653 NWRAP_LOG(NWRAP_LOG_DEBUG,
3654 "Inspecting %s for group membership",
3655 grp->gr_name);
3657 for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
3658 if (group != grp->gr_gid &&
3659 (strcmp(user, grp->gr_mem[i]) == 0)) {
3660 NWRAP_LOG(NWRAP_LOG_DEBUG,
3661 "%s is member of %s",
3662 user,
3663 grp->gr_name);
3665 if (*start == *size) {
3666 long int newsize;
3667 gid_t *newgroups;
3669 newsize = 2 * (*size);
3670 if (limit > 0 && newsize > limit) {
3671 newsize = MAX(limit, *size);
3673 newgroups = (gid_t *) realloc((*groups),
3674 newsize * sizeof(**groups));
3675 if (!newgroups) {
3676 errno = ENOMEM;
3677 return -1;
3679 *groups = newgroups;
3680 *size = newsize;
3682 (*groups)[*start] = grp->gr_gid;
3683 (*start)++;
3688 nwrap_files_endgrent(b);
3689 return *start;
3692 /* group functions */
3693 static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
3694 const char *name)
3696 int i;
3697 bool ok;
3699 (void) b; /* unused */
3701 ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
3702 if (!ok) {
3703 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
3704 return NULL;
3707 for (i=0; i<nwrap_gr_global.num; i++) {
3708 if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) {
3709 NWRAP_LOG(NWRAP_LOG_DEBUG, "group[%s] found", name);
3710 return &nwrap_gr_global.list[i];
3712 NWRAP_LOG(NWRAP_LOG_DEBUG,
3713 "group[%s] does not match [%s]",
3714 name,
3715 nwrap_gr_global.list[i].gr_name);
3718 NWRAP_LOG(NWRAP_LOG_DEBUG, "group[%s] not found", name);
3720 errno = ENOENT;
3721 return NULL;
3724 static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
3725 const char *name, struct group *grdst,
3726 char *buf, size_t buflen, struct group **grdstp)
3728 struct group *gr;
3730 gr = nwrap_files_getgrnam(b, name);
3731 if (!gr) {
3732 if (errno == 0) {
3733 return ENOENT;
3735 return errno;
3738 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
3741 static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
3742 gid_t gid)
3744 int i;
3745 bool ok;
3747 (void) b; /* unused */
3749 ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
3750 if (!ok) {
3751 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
3752 return NULL;
3755 for (i=0; i<nwrap_gr_global.num; i++) {
3756 if (nwrap_gr_global.list[i].gr_gid == gid) {
3757 NWRAP_LOG(NWRAP_LOG_DEBUG, "gid[%u] found", gid);
3758 return &nwrap_gr_global.list[i];
3760 NWRAP_LOG(NWRAP_LOG_DEBUG,
3761 "gid[%u] does not match [%u]",
3762 gid,
3763 nwrap_gr_global.list[i].gr_gid);
3766 NWRAP_LOG(NWRAP_LOG_DEBUG, "gid[%u] not found", gid);
3768 errno = ENOENT;
3769 return NULL;
3772 static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
3773 gid_t gid, struct group *grdst,
3774 char *buf, size_t buflen, struct group **grdstp)
3776 struct group *gr;
3778 gr = nwrap_files_getgrgid(b, gid);
3779 if (!gr) {
3780 if (errno == 0) {
3781 return ENOENT;
3783 return errno;
3786 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
3789 /* group enum functions */
3790 static void nwrap_files_setgrent(struct nwrap_backend *b)
3792 (void) b; /* unused */
3794 nwrap_gr_global.idx = 0;
3797 static struct group *nwrap_files_getgrent(struct nwrap_backend *b)
3799 struct group *gr;
3801 (void) b; /* unused */
3803 if (nwrap_gr_global.idx == 0) {
3804 bool ok;
3806 ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
3807 if (!ok) {
3808 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
3809 return NULL;
3813 if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
3814 errno = ENOENT;
3815 return NULL;
3818 gr = &nwrap_gr_global.list[nwrap_gr_global.idx++];
3820 NWRAP_LOG(NWRAP_LOG_DEBUG,
3821 "return group[%s] gid[%u]",
3822 gr->gr_name, gr->gr_gid);
3824 return gr;
3827 static int nwrap_files_getgrent_r(struct nwrap_backend *b,
3828 struct group *grdst, char *buf,
3829 size_t buflen, struct group **grdstp)
3831 struct group *gr;
3833 gr = nwrap_files_getgrent(b);
3834 if (!gr) {
3835 if (errno == 0) {
3836 return ENOENT;
3838 return errno;
3841 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
3844 static void nwrap_files_endgrent(struct nwrap_backend *b)
3846 (void) b; /* unused */
3848 nwrap_gr_global.idx = 0;
3851 /* hosts functions */
3852 static int nwrap_files_internal_gethostbyname(const char *name, int af,
3853 struct hostent *result,
3854 struct nwrap_vector *addr_list)
3856 struct nwrap_entlist *el;
3857 struct hostent *he;
3858 char *h_name_lower;
3859 ENTRY e;
3860 ENTRY *e_p;
3861 char canon_name[DNS_NAME_MAX] = { 0 };
3862 size_t name_len;
3863 bool he_found = false;
3864 bool ok;
3867 * We need to make sure we have zeroed return pointer for consumers
3868 * which don't check return values, e.g. OpenLDAP.
3870 ZERO_STRUCTP(result);
3872 ok = nwrap_files_cache_reload(nwrap_he_global.cache);
3873 if (!ok) {
3874 NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
3875 goto no_ent;
3878 name_len = strlen(name);
3879 if (name_len < sizeof(canon_name) && name[name_len - 1] == '.') {
3880 memcpy(canon_name, name, name_len - 1);
3881 canon_name[name_len] = '\0';
3882 name = canon_name;
3885 if (!str_tolower_copy(&h_name_lower, name)) {
3886 NWRAP_LOG(NWRAP_LOG_DEBUG,
3887 "Out of memory while converting to lower case");
3888 goto no_ent;
3891 /* Look at hash table for element */
3892 NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching for name: %s", h_name_lower);
3893 e.key = h_name_lower;
3894 e.data = NULL;
3895 e_p = hsearch(e, FIND);
3896 if (e_p == NULL) {
3897 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found.", h_name_lower);
3898 SAFE_FREE(h_name_lower);
3899 goto no_ent;
3901 SAFE_FREE(h_name_lower);
3903 /* Always cleanup vector and results */
3904 if (!nwrap_vector_is_initialized(addr_list)) {
3905 if (!nwrap_vector_init(addr_list)) {
3906 NWRAP_LOG(NWRAP_LOG_DEBUG,
3907 "Unable to initialize memory for addr_list vector");
3908 goto no_ent;
3910 } else {
3911 /* When vector is initialized data are valid no more.
3912 * Quick way how to free vector is: */
3913 addr_list->count = 0;
3916 /* Iterate through results */
3917 for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next)
3919 he = &(el->ed->ht);
3921 /* Filter by address familiy if provided */
3922 if (af != AF_UNSPEC && he->h_addrtype != af) {
3923 continue;
3927 * GLIBC HACK?
3928 * glibc doesn't return ipv6 addresses when AF_UNSPEC is used
3930 if (af == AF_UNSPEC && he->h_addrtype != AF_INET) {
3931 continue;
3934 if (!he_found) {
3935 memcpy(result, he, sizeof(struct hostent));
3936 NWRAP_LOG(NWRAP_LOG_DEBUG,
3937 "Name found. Returning record for %s",
3938 he->h_name);
3939 he_found = true;
3941 nwrap_vector_merge(addr_list, &el->ed->nwrap_addrdata);
3942 result->h_addr_list = nwrap_vector_head(addr_list);
3945 if (he_found) {
3946 return 0;
3948 NWRAP_LOG(NWRAP_LOG_DEBUG,
3949 "Name found in database. No records matches type.");
3951 no_ent:
3952 errno = ENOENT;
3953 return -1;
3956 static int nwrap_files_gethostbyname2_r(struct nwrap_backend *b,
3957 const char *name, int af,
3958 struct hostent *hedst,
3959 char *buf, size_t buflen,
3960 struct hostent **hedstp)
3962 struct nwrap_vector *addr_list = NULL;
3963 union {
3964 char *ptr;
3965 char **list;
3966 } g;
3967 int rc;
3969 (void) b; /* unused */
3970 (void) af; /* unused */
3972 if (name == NULL || hedst == NULL || buf == NULL || buflen == 0) {
3973 errno = EINVAL;
3974 return -1;
3976 *hedstp = NULL;
3977 buf[0] = '\0';
3979 addr_list = calloc(1, sizeof(struct nwrap_vector));
3980 if (addr_list == NULL) {
3981 NWRAP_LOG(NWRAP_LOG_ERROR,
3982 "Unable to allocate memory for address list");
3983 errno = ENOENT;
3984 return -1;
3987 rc = nwrap_files_internal_gethostbyname(name, af, hedst,
3988 addr_list);
3989 if (rc == -1) {
3990 SAFE_FREE(addr_list->items);
3991 SAFE_FREE(addr_list);
3992 errno = ENOENT;
3993 return -1;
3996 /* +1 i for ending NULL pointer */
3997 if (buflen < ((addr_list->count + 1) * sizeof(void *))) {
3998 SAFE_FREE(addr_list->items);
3999 SAFE_FREE(addr_list);
4000 return ERANGE;
4003 /* Copy all to user provided buffer and change
4004 * pointers in returned structure.
4005 * +1 is for ending NULL pointer. */
4006 memcpy(buf, addr_list->items, (addr_list->count + 1) * sizeof(void *));
4008 SAFE_FREE(addr_list->items);
4009 SAFE_FREE(addr_list);
4011 g.ptr = buf;
4012 hedst->h_addr_list = g.list;
4013 *hedstp = hedst;
4014 return 0;
4017 #ifdef HAVE_GETHOSTBYNAME_R
4018 static int nwrap_gethostbyname_r(const char *name,
4019 struct hostent *ret,
4020 char *buf, size_t buflen,
4021 struct hostent **result, int *h_errnop)
4023 int rc;
4024 size_t i;
4026 for (i=0; i < nwrap_main_global->num_backends; i++) {
4027 struct nwrap_backend *b = &nwrap_main_global->backends[i];
4028 rc = b->ops->nw_gethostbyname2_r(b, name, AF_UNSPEC, ret,
4029 buf, buflen, result);
4030 if (rc == 0) {
4031 return 0;
4032 } else if (rc == ERANGE) {
4033 return ERANGE;
4036 *h_errnop = h_errno;
4037 return ENOENT;
4040 int gethostbyname_r(const char *name,
4041 struct hostent *ret,
4042 char *buf, size_t buflen,
4043 struct hostent **result, int *h_errnop)
4045 if (!nss_wrapper_hosts_enabled()) {
4046 return libc_gethostbyname_r(name,
4047 ret,
4048 buf,
4049 buflen,
4050 result,
4051 h_errnop);
4054 return nwrap_gethostbyname_r(name, ret, buf, buflen, result, h_errnop);
4056 #endif
4058 #ifdef HAVE_GETHOSTBYNAME2_R
4059 static int nwrap_gethostbyname2_r(const char *name, int af,
4060 struct hostent *ret,
4061 char *buf, size_t buflen,
4062 struct hostent **result, int *h_errnop)
4064 int rc;
4065 size_t i;
4067 for (i=0; i < nwrap_main_global->num_backends; i++) {
4068 struct nwrap_backend *b = &nwrap_main_global->backends[i];
4069 rc = b->ops->nw_gethostbyname2_r(b, name, af, ret,
4070 buf, buflen, result);
4071 if (rc == 0) {
4072 return 0;
4073 } else if (rc == ERANGE) {
4074 return ERANGE;
4077 *h_errnop = h_errno;
4078 return ENOENT;
4081 int gethostbyname2_r(const char *name, int af,
4082 struct hostent *ret,
4083 char *buf, size_t buflen,
4084 struct hostent **result, int *h_errnop)
4086 if (!nss_wrapper_hosts_enabled()) {
4087 return libc_gethostbyname2_r(name, af, ret, buf, buflen,
4088 result, h_errnop);
4091 return nwrap_gethostbyname2_r(name, af, ret, buf, buflen, result,
4092 h_errnop);
4094 #endif
4096 static int nwrap_files_getaddrinfo(const char *name,
4097 unsigned short port,
4098 const struct addrinfo *hints,
4099 struct addrinfo **ai)
4101 struct nwrap_entlist *el;
4102 struct hostent *he;
4103 struct addrinfo *ai_head = NULL;
4104 struct addrinfo *ai_cur = NULL;
4105 char *h_name_lower;
4106 size_t name_len;
4107 char canon_name[DNS_NAME_MAX] = { 0 };
4108 bool skip_canonname = false;
4109 ENTRY e = {
4110 .key = NULL,
4112 ENTRY *e_p = NULL;
4113 int rc;
4114 bool ok;
4116 ok = nwrap_files_cache_reload(nwrap_he_global.cache);
4117 if (!ok) {
4118 NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
4119 return EAI_SYSTEM;
4122 name_len = strlen(name);
4123 if (name_len == 0) {
4124 return EAI_NONAME;
4127 if (name_len < sizeof(canon_name) && name[name_len - 1] == '.') {
4128 memcpy(canon_name, name, name_len - 1);
4129 canon_name[name_len] = '\0';
4130 name = canon_name;
4133 if (!str_tolower_copy(&h_name_lower, name)) {
4134 NWRAP_LOG(NWRAP_LOG_DEBUG,
4135 "Out of memory while converting to lower case");
4136 return EAI_MEMORY;
4139 NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching for name: %s", h_name_lower);
4140 e.key = h_name_lower;
4141 e.data = NULL;
4142 e_p = hsearch(e, FIND);
4143 if (e_p == NULL) {
4144 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found.", h_name_lower);
4145 SAFE_FREE(h_name_lower);
4146 errno = ENOENT;
4147 return EAI_NONAME;
4149 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name: %s found.", h_name_lower);
4150 SAFE_FREE(h_name_lower);
4152 rc = EAI_NONAME;
4153 for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next)
4155 int rc2;
4156 struct addrinfo *ai_new = NULL;
4158 he = &(el->ed->ht);
4160 if (hints->ai_family != AF_UNSPEC &&
4161 he->h_addrtype != hints->ai_family)
4163 NWRAP_LOG(NWRAP_LOG_DEBUG,
4164 "Entry found but with wrong AF - "
4165 "remembering EAI_ADDRINFO.");
4166 rc = EAI_ADDRFAMILY;
4167 continue;
4170 /* Function allocates memory and returns it in ai. */
4171 rc2 = nwrap_convert_he_ai(he,
4172 port,
4173 hints,
4174 &ai_new,
4175 skip_canonname);
4176 if (rc2 != 0) {
4177 NWRAP_LOG(NWRAP_LOG_ERROR, "Error converting he to ai");
4178 if (ai_head != NULL) {
4179 freeaddrinfo(ai_head);
4181 return rc2;
4183 skip_canonname = true;
4185 if (ai_head == NULL) {
4186 ai_head = ai_new;
4188 if (ai_cur != NULL) {
4189 ai_cur->ai_next = ai_new;
4191 ai_cur = ai_new;
4194 if (ai_head != NULL) {
4195 rc = 0;
4198 *ai = ai_head;
4200 return rc;
4203 static struct hostent *nwrap_files_gethostbyaddr(struct nwrap_backend *b,
4204 const void *addr,
4205 socklen_t len, int type)
4207 struct hostent *he;
4208 char ip[NWRAP_INET_ADDRSTRLEN] = {0};
4209 struct nwrap_entdata *ed;
4210 const char *a;
4211 size_t i;
4212 bool ok;
4214 (void) b; /* unused */
4215 (void) len; /* unused */
4217 ok = nwrap_files_cache_reload(nwrap_he_global.cache);
4218 if (!ok) {
4219 NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
4220 return NULL;
4223 a = inet_ntop(type, addr, ip, sizeof(ip));
4224 if (a == NULL) {
4225 errno = EINVAL;
4226 return NULL;
4229 nwrap_vector_foreach(ed, nwrap_he_global.entries, i)
4231 he = &(ed->ht);
4232 if (he->h_addrtype != type) {
4233 continue;
4236 if (memcmp(addr, he->h_addr_list[0], he->h_length) == 0) {
4237 return he;
4241 errno = ENOENT;
4242 return NULL;
4245 #ifdef HAVE_GETHOSTBYADDR_R
4246 static int nwrap_gethostbyaddr_r(const void *addr, socklen_t len, int type,
4247 struct hostent *ret,
4248 char *buf, size_t buflen,
4249 struct hostent **result, int *h_errnop)
4251 size_t i;
4252 for (i=0; i < nwrap_main_global->num_backends; i++) {
4253 struct nwrap_backend *b = &nwrap_main_global->backends[i];
4254 *result = b->ops->nw_gethostbyaddr(b, addr, len, type);
4255 if (*result != NULL) {
4256 break;
4260 if (*result != NULL) {
4261 memset(buf, '\0', buflen);
4262 *ret = **result;
4263 return 0;
4266 *h_errnop = h_errno;
4267 return -1;
4270 int gethostbyaddr_r(const void *addr, socklen_t len, int type,
4271 struct hostent *ret,
4272 char *buf, size_t buflen,
4273 struct hostent **result, int *h_errnop)
4275 if (!nss_wrapper_hosts_enabled()) {
4276 return libc_gethostbyaddr_r(addr,
4277 len,
4278 type,
4279 ret,
4280 buf,
4281 buflen,
4282 result,
4283 h_errnop);
4286 return nwrap_gethostbyaddr_r(addr, len, type, ret, buf, buflen, result, h_errnop);
4288 #endif
4290 /* hosts enum functions */
4291 static void nwrap_files_sethostent(void)
4293 nwrap_he_global.idx = 0;
4296 static struct hostent *nwrap_files_gethostent(void)
4298 struct hostent *he;
4300 if (nwrap_he_global.idx == 0) {
4301 bool ok;
4303 ok = nwrap_files_cache_reload(nwrap_he_global.cache);
4304 if (!ok) {
4305 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading hosts file");
4306 return NULL;
4310 if (nwrap_he_global.idx >= nwrap_he_global.num) {
4311 errno = ENOENT;
4312 return NULL;
4315 he = &((struct nwrap_entdata *)nwrap_he_global.entries.items[nwrap_he_global.idx++])->ht;
4317 NWRAP_LOG(NWRAP_LOG_DEBUG, "return hosts[%s]", he->h_name);
4319 return he;
4322 static void nwrap_files_endhostent(void)
4324 nwrap_he_global.idx = 0;
4328 * module backend
4332 static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
4333 const char *name)
4335 static struct passwd pwd;
4336 static char buf[1000];
4337 NSS_STATUS status;
4339 if (b->symbols->_nss_getpwnam_r.f == NULL) {
4340 return NULL;
4343 status = b->symbols->_nss_getpwnam_r.f(name,
4344 &pwd,
4345 buf,
4346 sizeof(buf),
4347 &errno);
4348 if (status == NSS_STATUS_NOTFOUND) {
4349 return NULL;
4351 if (status != NSS_STATUS_SUCCESS) {
4352 return NULL;
4355 return &pwd;
4358 static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
4359 const char *name, struct passwd *pwdst,
4360 char *buf, size_t buflen, struct passwd **pwdstp)
4362 int ret;
4364 *pwdstp = NULL;
4366 if (b->symbols->_nss_getpwnam_r.f == NULL) {
4367 return NSS_STATUS_NOTFOUND;
4370 ret = b->symbols->_nss_getpwnam_r.f(name, pwdst, buf, buflen, &errno);
4371 switch (ret) {
4372 case NSS_STATUS_SUCCESS:
4373 *pwdstp = pwdst;
4374 return 0;
4375 case NSS_STATUS_NOTFOUND:
4376 if (errno != 0) {
4377 return errno;
4379 return ENOENT;
4380 case NSS_STATUS_TRYAGAIN:
4381 if (errno != 0) {
4382 return errno;
4384 return ERANGE;
4385 default:
4386 if (errno != 0) {
4387 return errno;
4389 return ret;
4393 static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
4394 uid_t uid)
4396 static struct passwd pwd;
4397 static char buf[1000];
4398 NSS_STATUS status;
4400 if (b->symbols->_nss_getpwuid_r.f == NULL) {
4401 return NULL;
4404 status = b->symbols->_nss_getpwuid_r.f(uid,
4405 &pwd,
4406 buf,
4407 sizeof(buf),
4408 &errno);
4409 if (status == NSS_STATUS_NOTFOUND) {
4410 return NULL;
4412 if (status != NSS_STATUS_SUCCESS) {
4413 return NULL;
4415 return &pwd;
4418 static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
4419 uid_t uid, struct passwd *pwdst,
4420 char *buf, size_t buflen, struct passwd **pwdstp)
4422 int ret;
4424 *pwdstp = NULL;
4426 if (b->symbols->_nss_getpwuid_r.f == NULL) {
4427 return ENOENT;
4430 ret = b->symbols->_nss_getpwuid_r.f(uid, pwdst, buf, buflen, &errno);
4431 switch (ret) {
4432 case NSS_STATUS_SUCCESS:
4433 *pwdstp = pwdst;
4434 return 0;
4435 case NSS_STATUS_NOTFOUND:
4436 if (errno != 0) {
4437 return errno;
4439 return ENOENT;
4440 case NSS_STATUS_TRYAGAIN:
4441 if (errno != 0) {
4442 return errno;
4444 return ERANGE;
4445 default:
4446 if (errno != 0) {
4447 return errno;
4449 return ret;
4453 static void nwrap_module_setpwent(struct nwrap_backend *b)
4455 if (b->symbols->_nss_setpwent.f == NULL) {
4456 return;
4459 b->symbols->_nss_setpwent.f();
4462 static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b)
4464 static struct passwd pwd;
4465 static char buf[1000];
4466 NSS_STATUS status;
4468 if (b->symbols->_nss_getpwent_r.f == NULL) {
4469 return NULL;
4472 status = b->symbols->_nss_getpwent_r.f(&pwd, buf, sizeof(buf), &errno);
4473 if (status == NSS_STATUS_NOTFOUND) {
4474 return NULL;
4476 if (status != NSS_STATUS_SUCCESS) {
4477 return NULL;
4479 return &pwd;
4482 static int nwrap_module_getpwent_r(struct nwrap_backend *b,
4483 struct passwd *pwdst, char *buf,
4484 size_t buflen, struct passwd **pwdstp)
4486 int ret;
4488 *pwdstp = NULL;
4490 if (b->symbols->_nss_getpwent_r.f == NULL) {
4491 return ENOENT;
4494 ret = b->symbols->_nss_getpwent_r.f(pwdst, buf, buflen, &errno);
4495 switch (ret) {
4496 case NSS_STATUS_SUCCESS:
4497 *pwdstp = pwdst;
4498 return 0;
4499 case NSS_STATUS_NOTFOUND:
4500 if (errno != 0) {
4501 return errno;
4503 return ENOENT;
4504 case NSS_STATUS_TRYAGAIN:
4505 if (errno != 0) {
4506 return errno;
4508 return ERANGE;
4509 default:
4510 if (errno != 0) {
4511 return errno;
4513 return ret;
4517 static void nwrap_module_endpwent(struct nwrap_backend *b)
4519 if (b->symbols->_nss_endpwent.f == NULL) {
4520 return;
4523 b->symbols->_nss_endpwent.f();
4526 static int nwrap_module_initgroups_dyn(struct nwrap_backend *b,
4527 const char *user,
4528 gid_t group,
4529 long int *start,
4530 long int *size,
4531 gid_t **groups,
4532 long int limit,
4533 int *errnop)
4535 if (b->symbols->_nss_initgroups_dyn.f == NULL) {
4536 return NSS_STATUS_UNAVAIL;
4539 return b->symbols->_nss_initgroups_dyn.f(user,
4540 group,
4541 start,
4542 size,
4543 groups,
4544 limit,
4545 errnop);
4548 static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
4549 const char *name)
4551 static struct group grp;
4552 static char *buf;
4553 static int buflen = 1000;
4554 NSS_STATUS status;
4556 if (b->symbols->_nss_getgrnam_r.f == NULL) {
4557 return NULL;
4560 if (!buf) {
4561 buf = (char *)malloc(buflen);
4563 again:
4564 status = b->symbols->_nss_getgrnam_r.f(name, &grp, buf, buflen, &errno);
4565 if (status == NSS_STATUS_TRYAGAIN) {
4566 buflen *= 2;
4567 buf = (char *)realloc(buf, buflen);
4568 if (!buf) {
4569 return NULL;
4571 goto again;
4573 if (status == NSS_STATUS_NOTFOUND) {
4574 SAFE_FREE(buf);
4575 return NULL;
4577 if (status != NSS_STATUS_SUCCESS) {
4578 SAFE_FREE(buf);
4579 return NULL;
4581 return &grp;
4584 static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
4585 const char *name, struct group *grdst,
4586 char *buf, size_t buflen, struct group **grdstp)
4588 int ret;
4590 *grdstp = NULL;
4592 if (b->symbols->_nss_getgrnam_r.f == NULL) {
4593 return ENOENT;
4596 ret = b->symbols->_nss_getgrnam_r.f(name, grdst, buf, buflen, &errno);
4597 switch (ret) {
4598 case NSS_STATUS_SUCCESS:
4599 *grdstp = grdst;
4600 return 0;
4601 case NSS_STATUS_NOTFOUND:
4602 if (errno != 0) {
4603 return errno;
4605 return ENOENT;
4606 case NSS_STATUS_TRYAGAIN:
4607 if (errno != 0) {
4608 return errno;
4610 return ERANGE;
4611 default:
4612 if (errno != 0) {
4613 return errno;
4615 return ret;
4619 static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
4620 gid_t gid)
4622 static struct group grp;
4623 static char *buf;
4624 static int buflen = 1000;
4625 NSS_STATUS status;
4627 if (b->symbols->_nss_getgrgid_r.f == NULL) {
4628 return NULL;
4631 if (!buf) {
4632 buf = (char *)malloc(buflen);
4635 again:
4636 status = b->symbols->_nss_getgrgid_r.f(gid, &grp, buf, buflen, &errno);
4637 if (status == NSS_STATUS_TRYAGAIN) {
4638 buflen *= 2;
4639 buf = (char *)realloc(buf, buflen);
4640 if (!buf) {
4641 return NULL;
4643 goto again;
4645 if (status == NSS_STATUS_NOTFOUND) {
4646 SAFE_FREE(buf);
4647 return NULL;
4649 if (status != NSS_STATUS_SUCCESS) {
4650 SAFE_FREE(buf);
4651 return NULL;
4653 return &grp;
4656 static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
4657 gid_t gid, struct group *grdst,
4658 char *buf, size_t buflen, struct group **grdstp)
4660 int ret;
4662 *grdstp = NULL;
4664 if (b->symbols->_nss_getgrgid_r.f == NULL) {
4665 return ENOENT;
4668 ret = b->symbols->_nss_getgrgid_r.f(gid, grdst, buf, buflen, &errno);
4669 switch (ret) {
4670 case NSS_STATUS_SUCCESS:
4671 *grdstp = grdst;
4672 return 0;
4673 case NSS_STATUS_NOTFOUND:
4674 if (errno != 0) {
4675 return errno;
4677 return ENOENT;
4678 case NSS_STATUS_TRYAGAIN:
4679 if (errno != 0) {
4680 return errno;
4682 return ERANGE;
4683 default:
4684 if (errno != 0) {
4685 return errno;
4687 return ret;
4691 static void nwrap_module_setgrent(struct nwrap_backend *b)
4693 if (b->symbols->_nss_setgrent.f == NULL) {
4694 return;
4697 b->symbols->_nss_setgrent.f();
4700 static struct group *nwrap_module_getgrent(struct nwrap_backend *b)
4702 static struct group grp;
4703 static char *buf;
4704 static int buflen = 1024;
4705 NSS_STATUS status;
4707 if (b->symbols->_nss_getgrent_r.f == NULL) {
4708 return NULL;
4711 if (!buf) {
4712 buf = (char *)malloc(buflen);
4715 again:
4716 status = b->symbols->_nss_getgrent_r.f(&grp, buf, buflen, &errno);
4717 if (status == NSS_STATUS_TRYAGAIN) {
4718 buflen *= 2;
4719 buf = (char *)realloc(buf, buflen);
4720 if (!buf) {
4721 return NULL;
4723 goto again;
4725 if (status == NSS_STATUS_NOTFOUND) {
4726 SAFE_FREE(buf);
4727 return NULL;
4729 if (status != NSS_STATUS_SUCCESS) {
4730 SAFE_FREE(buf);
4731 return NULL;
4733 return &grp;
4736 static int nwrap_module_getgrent_r(struct nwrap_backend *b,
4737 struct group *grdst, char *buf,
4738 size_t buflen, struct group **grdstp)
4740 int ret;
4742 *grdstp = NULL;
4744 if (b->symbols->_nss_getgrent_r.f == NULL) {
4745 return ENOENT;
4748 ret = b->symbols->_nss_getgrent_r.f(grdst, buf, buflen, &errno);
4749 switch (ret) {
4750 case NSS_STATUS_SUCCESS:
4751 *grdstp = grdst;
4752 return 0;
4753 case NSS_STATUS_NOTFOUND:
4754 if (errno != 0) {
4755 return errno;
4757 return ENOENT;
4758 case NSS_STATUS_TRYAGAIN:
4759 if (errno != 0) {
4760 return errno;
4762 return ERANGE;
4763 default:
4764 if (errno != 0) {
4765 return errno;
4767 return ret;
4771 static void nwrap_module_endgrent(struct nwrap_backend *b)
4773 if (b->symbols->_nss_endgrent.f == NULL) {
4774 return;
4777 b->symbols->_nss_endgrent.f();
4780 static struct hostent *nwrap_module_gethostbyaddr(struct nwrap_backend *b,
4781 const void *addr,
4782 socklen_t len, int type)
4784 static struct hostent he;
4785 static char *buf = NULL;
4786 static size_t buflen = 1000;
4787 NSS_STATUS status;
4789 if (b->symbols->_nss_gethostbyaddr_r.f == NULL) {
4790 return NULL;
4793 if (buf == NULL) {
4794 buf = (char *)malloc(buflen);
4795 if (buf == NULL) {
4796 return NULL;
4799 again:
4800 status = b->symbols->_nss_gethostbyaddr_r.f(addr,
4801 len,
4802 type,
4803 &he,
4804 buf,
4805 buflen,
4806 &errno,
4807 &h_errno);
4808 if (status == NSS_STATUS_TRYAGAIN) {
4809 char *p = NULL;
4811 buflen *= 2;
4812 p = (char *)realloc(buf, buflen);
4813 if (p == NULL) {
4814 SAFE_FREE(buf);
4815 return NULL;
4817 buf = p;
4818 goto again;
4820 if (status == NSS_STATUS_NOTFOUND) {
4821 SAFE_FREE(buf);
4822 return NULL;
4824 if (status != NSS_STATUS_SUCCESS) {
4825 SAFE_FREE(buf);
4826 return NULL;
4829 return &he;
4832 static int nwrap_module_gethostbyname2_r(struct nwrap_backend *b,
4833 const char *name, int af,
4834 struct hostent *hedst,
4835 char *buf, size_t buflen,
4836 struct hostent **hedstp)
4838 NSS_STATUS status;
4840 *hedstp = NULL;
4842 if (b->symbols->_nss_gethostbyname2_r.f == NULL) {
4843 return ENOENT;
4846 status = b->symbols->_nss_gethostbyname2_r.f(name,
4848 hedst,
4849 buf,
4850 buflen,
4851 &errno,
4852 &h_errno);
4853 switch (status) {
4854 case NSS_STATUS_SUCCESS:
4855 *hedstp = hedst;
4856 return 0;
4857 case NSS_STATUS_NOTFOUND:
4858 if (errno != 0) {
4859 return errno;
4861 return ENOENT;
4862 case NSS_STATUS_TRYAGAIN:
4863 if (errno != 0) {
4864 return errno;
4866 return ERANGE;
4867 default:
4868 if (errno != 0) {
4869 return errno;
4871 return status;
4875 static struct hostent *nwrap_module_gethostbyname(struct nwrap_backend *b,
4876 const char *name)
4878 static struct hostent he;
4879 static char *buf = NULL;
4880 static size_t buflen = 1000;
4881 NSS_STATUS status;
4883 if (b->symbols->_nss_gethostbyname2_r.f == NULL) {
4884 return NULL;
4887 if (buf == NULL) {
4888 buf = (char *)malloc(buflen);
4889 if (buf == NULL) {
4890 return NULL;
4894 again:
4895 status = b->symbols->_nss_gethostbyname2_r.f(name,
4896 AF_UNSPEC,
4897 &he,
4898 buf,
4899 buflen,
4900 &errno,
4901 &h_errno);
4902 if (status == NSS_STATUS_TRYAGAIN) {
4903 char *p = NULL;
4905 buflen *= 2;
4906 p = (char *)realloc(buf, buflen);
4907 if (p == NULL) {
4908 SAFE_FREE(buf);
4909 return NULL;
4911 buf = p;
4912 goto again;
4914 if (status == NSS_STATUS_NOTFOUND) {
4915 SAFE_FREE(buf);
4916 return NULL;
4918 if (status != NSS_STATUS_SUCCESS) {
4919 SAFE_FREE(buf);
4920 return NULL;
4923 return &he;
4926 static struct hostent *nwrap_module_gethostbyname2(struct nwrap_backend *b,
4927 const char *name, int af)
4929 static struct hostent he;
4930 static char *buf = NULL;
4931 static size_t buflen = 1000;
4932 NSS_STATUS status;
4934 if (b->symbols->_nss_gethostbyname2_r.f == NULL) {
4935 return NULL;
4938 if (buf == NULL) {
4939 buf = (char *)malloc(buflen);
4940 if (buf == NULL) {
4941 return NULL;
4945 again:
4946 status = b->symbols->_nss_gethostbyname2_r.f(name,
4948 &he,
4949 buf,
4950 buflen,
4951 &errno,
4952 &h_errno);
4953 if (status == NSS_STATUS_TRYAGAIN) {
4954 char *p = NULL;
4956 buflen *= 2;
4957 p = (char *)realloc(buf, buflen);
4958 if (p == NULL) {
4959 SAFE_FREE(buf);
4960 return NULL;
4962 buf = p;
4963 goto again;
4965 if (status == NSS_STATUS_NOTFOUND) {
4966 SAFE_FREE(buf);
4967 return NULL;
4969 if (status != NSS_STATUS_SUCCESS) {
4970 SAFE_FREE(buf);
4971 return NULL;
4974 return &he;
4977 /****************************************************************************
4978 * GETPWNAM
4979 ***************************************************************************/
4981 static struct passwd *nwrap_getpwnam(const char *name)
4983 size_t i;
4984 struct passwd *pwd;
4986 for (i=0; i < nwrap_main_global->num_backends; i++) {
4987 struct nwrap_backend *b = &nwrap_main_global->backends[i];
4988 pwd = b->ops->nw_getpwnam(b, name);
4989 if (pwd) {
4990 return pwd;
4994 return NULL;
4997 struct passwd *getpwnam(const char *name)
4999 if (!nss_wrapper_enabled()) {
5000 return libc_getpwnam(name);
5003 return nwrap_getpwnam(name);
5006 /****************************************************************************
5007 * GETPWNAM_R
5008 ***************************************************************************/
5010 static int nwrap_getpwnam_r(const char *name, struct passwd *pwdst,
5011 char *buf, size_t buflen, struct passwd **pwdstp)
5013 size_t i;
5014 int ret;
5016 for (i=0; i < nwrap_main_global->num_backends; i++) {
5017 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5018 ret = b->ops->nw_getpwnam_r(b, name, pwdst, buf, buflen, pwdstp);
5019 if (ret == ENOENT) {
5020 continue;
5022 return ret;
5025 return ENOENT;
5028 #ifdef HAVE_GETPWNAM_R
5029 # ifdef HAVE_SOLARIS_GETPWNAM_R
5030 int getpwnam_r(const char *name, struct passwd *pwdst,
5031 char *buf, int buflen, struct passwd **pwdstp)
5032 # else /* HAVE_SOLARIS_GETPWNAM_R */
5033 int getpwnam_r(const char *name, struct passwd *pwdst,
5034 char *buf, size_t buflen, struct passwd **pwdstp)
5035 # endif /* HAVE_SOLARIS_GETPWNAM_R */
5037 if (!nss_wrapper_enabled()) {
5038 return libc_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
5041 return nwrap_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
5043 #endif
5045 /****************************************************************************
5046 * GETPWUID
5047 ***************************************************************************/
5049 static struct passwd *nwrap_getpwuid(uid_t uid)
5051 size_t i;
5052 struct passwd *pwd;
5054 for (i=0; i < nwrap_main_global->num_backends; i++) {
5055 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5056 pwd = b->ops->nw_getpwuid(b, uid);
5057 if (pwd) {
5058 return pwd;
5062 return NULL;
5065 struct passwd *getpwuid(uid_t uid)
5067 if (!nss_wrapper_enabled()) {
5068 return libc_getpwuid(uid);
5071 return nwrap_getpwuid(uid);
5074 /****************************************************************************
5075 * GETPWUID_R
5076 ***************************************************************************/
5078 static int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst,
5079 char *buf, size_t buflen, struct passwd **pwdstp)
5081 size_t i;
5082 int ret;
5084 for (i=0; i < nwrap_main_global->num_backends; i++) {
5085 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5086 ret = b->ops->nw_getpwuid_r(b, uid, pwdst, buf, buflen, pwdstp);
5087 if (ret == ENOENT) {
5088 continue;
5090 return ret;
5093 return ENOENT;
5096 #ifdef HAVE_SOLARIS_GETPWUID_R
5097 int getpwuid_r(uid_t uid, struct passwd *pwdst,
5098 char *buf, int buflen, struct passwd **pwdstp)
5099 #else
5100 int getpwuid_r(uid_t uid, struct passwd *pwdst,
5101 char *buf, size_t buflen, struct passwd **pwdstp)
5102 #endif
5104 if (!nss_wrapper_enabled()) {
5105 return libc_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
5108 return nwrap_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
5111 /****************************************************************************
5112 * SETPWENT
5113 ***************************************************************************/
5115 static void nwrap_setpwent(void)
5117 size_t i;
5119 for (i=0; i < nwrap_main_global->num_backends; i++) {
5120 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5121 b->ops->nw_setpwent(b);
5125 void setpwent(void)
5127 if (!nss_wrapper_enabled()) {
5128 libc_setpwent();
5129 return;
5132 nwrap_setpwent();
5135 /****************************************************************************
5136 * GETPWENT
5137 ***************************************************************************/
5139 static struct passwd *nwrap_getpwent(void)
5141 size_t i;
5142 struct passwd *pwd;
5144 for (i=0; i < nwrap_main_global->num_backends; i++) {
5145 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5146 pwd = b->ops->nw_getpwent(b);
5147 if (pwd) {
5148 return pwd;
5152 return NULL;
5155 struct passwd *getpwent(void)
5157 if (!nss_wrapper_enabled()) {
5158 return libc_getpwent();
5161 return nwrap_getpwent();
5164 /****************************************************************************
5165 * GETPWENT_R
5166 ***************************************************************************/
5168 #ifdef HAVE_GETPWENT_R
5169 static int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
5170 size_t buflen, struct passwd **pwdstp)
5172 size_t i;
5173 int ret;
5175 for (i=0; i < nwrap_main_global->num_backends; i++) {
5176 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5177 ret = b->ops->nw_getpwent_r(b, pwdst, buf, buflen, pwdstp);
5178 if (ret == ENOENT) {
5179 continue;
5181 return ret;
5184 return ENOENT;
5187 # ifdef HAVE_SOLARIS_GETPWENT_R
5188 struct passwd *getpwent_r(struct passwd *pwdst, char *buf, int buflen)
5190 struct passwd *pwdstp = NULL;
5191 int rc;
5193 if (!nss_wrapper_enabled()) {
5194 return libc_getpwent_r(pwdst, buf, buflen);
5196 rc = nwrap_getpwent_r(pwdst, buf, buflen, &pwdstp);
5197 if (rc < 0) {
5198 return NULL;
5201 return pwdstp;
5203 # else /* HAVE_SOLARIS_GETPWENT_R */
5204 int getpwent_r(struct passwd *pwdst, char *buf,
5205 size_t buflen, struct passwd **pwdstp)
5207 if (!nss_wrapper_enabled()) {
5208 return libc_getpwent_r(pwdst, buf, buflen, pwdstp);
5211 return nwrap_getpwent_r(pwdst, buf, buflen, pwdstp);
5213 # endif /* HAVE_SOLARIS_GETPWENT_R */
5214 #endif /* HAVE_GETPWENT_R */
5216 /****************************************************************************
5217 * ENDPWENT
5218 ***************************************************************************/
5220 static void nwrap_endpwent(void)
5222 size_t i;
5224 for (i=0; i < nwrap_main_global->num_backends; i++) {
5225 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5226 b->ops->nw_endpwent(b);
5230 void endpwent(void)
5232 if (!nss_wrapper_enabled()) {
5233 libc_endpwent();
5234 return;
5237 nwrap_endpwent();
5240 /****************************************************************************
5241 * INITGROUPS
5242 ***************************************************************************/
5244 static int nwrap_initgroups(const char *user, gid_t group)
5246 #if defined(NGROUPS_MAX) && NGROUPS_MAX == 0
5247 /* No extra groups allowed. */
5248 return 0;
5249 #elif !defined(HAVE_GETGROUPLIST)
5250 return 0;
5251 #else
5252 long int size;
5253 long int limit;
5254 gid_t *groups;
5255 int ngroups;
5256 int result;
5257 const char *env = getenv("UID_WRAPPER");
5259 if (env == NULL || env[0] != '1') {
5260 NWRAP_LOG(NWRAP_LOG_WARN,
5261 "initgroups() requires uid_wrapper to work!");
5262 return 0;
5265 limit = sysconf(_SC_NGROUPS_MAX);
5266 if (limit > 0) {
5267 size = MIN(limit, 64);
5268 } else {
5269 size = 16;
5272 groups = (gid_t *)malloc(size * sizeof(gid_t));
5273 if (groups == NULL) {
5274 /* No more memory. */
5275 return -1;
5278 ngroups = nwrap_getgrouplist(user, group, &size, &groups, limit);
5280 /* Try to set the maximum number of groups the kernel can handle. */
5281 do {
5282 result = setgroups(ngroups, groups);
5283 } while (result == -1 && errno == EINVAL && --ngroups > 0);
5285 free(groups);
5287 return result;
5288 #endif
5291 int initgroups(const char *user, gid_t group)
5293 if (!nss_wrapper_enabled()) {
5294 return libc_initgroups(user, group);
5297 return nwrap_initgroups(user, group);
5300 /****************************************************************************
5301 * GETGRNAM
5302 ***************************************************************************/
5304 static struct group *nwrap_getgrnam(const char *name)
5306 size_t i;
5307 struct group *grp;
5309 for (i=0; i < nwrap_main_global->num_backends; i++) {
5310 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5311 grp = b->ops->nw_getgrnam(b, name);
5312 if (grp) {
5313 return grp;
5317 return NULL;
5320 struct group *getgrnam(const char *name)
5322 if (!nss_wrapper_enabled()) {
5323 return libc_getgrnam(name);
5326 return nwrap_getgrnam(name);
5329 /****************************************************************************
5330 * GETGRNAM_R
5331 ***************************************************************************/
5333 static int nwrap_getgrnam_r(const char *name, struct group *grdst,
5334 char *buf, size_t buflen, struct group **grdstp)
5336 size_t i;
5337 int ret;
5339 for (i=0; i < nwrap_main_global->num_backends; i++) {
5340 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5341 ret = b->ops->nw_getgrnam_r(b, name, grdst, buf, buflen, grdstp);
5342 if (ret == ENOENT) {
5343 continue;
5345 return ret;
5348 return ENOENT;
5351 #ifdef HAVE_GETGRNAM_R
5352 # ifdef HAVE_SOLARIS_GETGRNAM_R
5353 int getgrnam_r(const char *name, struct group *grp,
5354 char *buf, int buflen, struct group **pgrp)
5355 # else /* HAVE_SOLARIS_GETGRNAM_R */
5356 int getgrnam_r(const char *name, struct group *grp,
5357 char *buf, size_t buflen, struct group **pgrp)
5358 # endif /* HAVE_SOLARIS_GETGRNAM_R */
5360 if (!nss_wrapper_enabled()) {
5361 return libc_getgrnam_r(name,
5362 grp,
5363 buf,
5364 buflen,
5365 pgrp);
5368 return nwrap_getgrnam_r(name, grp, buf, buflen, pgrp);
5370 #endif /* HAVE_GETGRNAM_R */
5372 /****************************************************************************
5373 * GETGRGID
5374 ***************************************************************************/
5376 static struct group *nwrap_getgrgid(gid_t gid)
5378 size_t i;
5379 struct group *grp;
5381 for (i=0; i < nwrap_main_global->num_backends; i++) {
5382 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5383 grp = b->ops->nw_getgrgid(b, gid);
5384 if (grp) {
5385 return grp;
5389 return NULL;
5392 struct group *getgrgid(gid_t gid)
5394 if (!nss_wrapper_enabled()) {
5395 return libc_getgrgid(gid);
5398 return nwrap_getgrgid(gid);
5401 /****************************************************************************
5402 * GETGRGID_R
5403 ***************************************************************************/
5405 static int nwrap_getgrgid_r(gid_t gid, struct group *grdst,
5406 char *buf, size_t buflen, struct group **grdstp)
5408 size_t i;
5409 int ret;
5411 for (i=0; i < nwrap_main_global->num_backends; i++) {
5412 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5413 ret = b->ops->nw_getgrgid_r(b, gid, grdst, buf, buflen, grdstp);
5414 if (ret == ENOENT) {
5415 continue;
5417 return ret;
5420 return ENOENT;
5423 #ifdef HAVE_GETGRGID_R
5424 # ifdef HAVE_SOLARIS_GETGRGID_R
5425 int getgrgid_r(gid_t gid, struct group *grdst,
5426 char *buf, int buflen, struct group **grdstp)
5427 # else /* HAVE_SOLARIS_GETGRGID_R */
5428 int getgrgid_r(gid_t gid, struct group *grdst,
5429 char *buf, size_t buflen, struct group **grdstp)
5430 # endif /* HAVE_SOLARIS_GETGRGID_R */
5432 if (!nss_wrapper_enabled()) {
5433 return libc_getgrgid_r(gid, grdst, buf, buflen, grdstp);
5436 return nwrap_getgrgid_r(gid, grdst, buf, buflen, grdstp);
5438 #endif
5440 /****************************************************************************
5441 * SETGRENT
5442 ***************************************************************************/
5444 static void nwrap_setgrent(void)
5446 size_t i;
5448 for (i=0; i < nwrap_main_global->num_backends; i++) {
5449 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5450 b->ops->nw_setgrent(b);
5454 #ifdef HAVE_BSD_SETGRENT
5455 int setgrent(void)
5456 #else
5457 void setgrent(void)
5458 #endif
5460 if (!nss_wrapper_enabled()) {
5461 libc_setgrent();
5462 goto out;
5465 nwrap_setgrent();
5467 out:
5468 #ifdef HAVE_BSD_SETGRENT
5469 return 0;
5470 #else
5471 return;
5472 #endif
5475 /****************************************************************************
5476 * GETGRENT
5477 ***************************************************************************/
5479 static struct group *nwrap_getgrent(void)
5481 size_t i;
5482 struct group *grp;
5484 for (i=0; i < nwrap_main_global->num_backends; i++) {
5485 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5486 grp = b->ops->nw_getgrent(b);
5487 if (grp) {
5488 return grp;
5492 return NULL;
5495 struct group *getgrent(void)
5497 if (!nss_wrapper_enabled()) {
5498 return libc_getgrent();
5501 return nwrap_getgrent();
5504 /****************************************************************************
5505 * GETGRENT_R
5506 ***************************************************************************/
5508 #ifdef HAVE_GETGRENT_R
5509 static int nwrap_getgrent_r(struct group *grdst, char *buf,
5510 size_t buflen, struct group **grdstp)
5512 size_t i;
5513 int ret;
5515 for (i=0; i < nwrap_main_global->num_backends; i++) {
5516 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5517 ret = b->ops->nw_getgrent_r(b, grdst, buf, buflen, grdstp);
5518 if (ret == ENOENT) {
5519 continue;
5521 return ret;
5524 return ENOENT;
5527 # ifdef HAVE_SOLARIS_GETGRENT_R
5528 struct group *getgrent_r(struct group *src, char *buf, int buflen)
5530 struct group *grdstp = NULL;
5531 int rc;
5533 if (!nss_wrapper_enabled()) {
5534 return libc_getgrent_r(src, buf, buflen);
5537 rc = nwrap_getgrent_r(src, buf, buflen, &grdstp);
5538 if (rc < 0) {
5539 return NULL;
5542 return grdstp;
5544 # else /* HAVE_SOLARIS_GETGRENT_R */
5545 int getgrent_r(struct group *src, char *buf,
5546 size_t buflen, struct group **grdstp)
5548 if (!nss_wrapper_enabled()) {
5549 return libc_getgrent_r(src, buf, buflen, grdstp);
5552 return nwrap_getgrent_r(src, buf, buflen, grdstp);
5554 # endif /* HAVE_SOLARIS_GETGRENT_R */
5555 #endif /* HAVE_GETGRENT_R */
5557 /****************************************************************************
5558 * ENDGRENT
5559 ***************************************************************************/
5561 static void nwrap_endgrent(void)
5563 size_t i;
5565 for (i=0; i < nwrap_main_global->num_backends; i++) {
5566 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5567 b->ops->nw_endgrent(b);
5571 void endgrent(void)
5573 if (!nss_wrapper_enabled()) {
5574 libc_endgrent();
5575 return;
5578 nwrap_endgrent();
5581 /****************************************************************************
5582 * GETGROUPLIST
5583 ***************************************************************************/
5585 #ifdef HAVE_GETGROUPLIST
5586 static int nwrap_getgrouplist(const char *user,
5587 gid_t group,
5588 long int *size,
5589 gid_t **groupsp,
5590 long int limit)
5592 enum nss_status status = NSS_STATUS_UNAVAIL;
5593 /* Start is one, because we have the first group as parameter. */
5594 long int start = 1;
5595 size_t i;
5597 /* Never store more than the starting *SIZE number of elements. */
5598 assert(*size > 0);
5599 (*groupsp)[0] = group;
5601 for (i = 0; i < nwrap_main_global->num_backends; i++) {
5602 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5603 long int prev_start = start;
5604 long int cnt = prev_start;
5606 status = b->ops->nw_initgroups_dyn(b,
5607 user,
5608 group,
5609 &start,
5610 size,
5611 groupsp,
5612 limit,
5613 &errno);
5615 /* Remove duplicates. */
5616 while (cnt < start) {
5617 long int inner;
5618 for (inner = 0; inner < prev_start; ++inner)
5619 if ((*groupsp)[inner] == (*groupsp)[cnt])
5620 break;
5622 if (inner < prev_start)
5623 (*groupsp)[cnt] = (*groupsp)[--start];
5624 else
5625 ++cnt;
5627 NWRAP_LOG(NWRAP_LOG_DEBUG,
5628 "Resource '%s' returned status=%d and increased "
5629 "count of groups to %ld",
5630 b->name,
5631 status,
5632 start);
5634 return start;
5637 int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
5639 long int size;
5640 int total, retval;
5641 gid_t *newgroups;
5643 if (!nss_wrapper_enabled()) {
5644 return libc_getgrouplist(user, group, groups, ngroups);
5647 size = MAX(1, *ngroups);
5648 newgroups = (gid_t *)malloc(size * sizeof(gid_t));
5649 if (newgroups == NULL) {
5650 return -1;
5653 total = nwrap_getgrouplist(user, group, &size, &newgroups, -1);
5655 if (groups != NULL) {
5656 memcpy(groups, newgroups, MIN(*ngroups, total) * sizeof(gid_t));
5659 free(newgroups);
5661 retval = total > *ngroups ? -1 : total;
5662 *ngroups = total;
5664 return retval;
5666 #endif
5668 /**********************************************************
5669 * SHADOW
5670 **********************************************************/
5672 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
5674 #ifdef HAVE_SETSPENT
5675 static void nwrap_setspent(void)
5677 nwrap_files_setspent();
5680 void setspent(void)
5682 if (!nss_wrapper_shadow_enabled()) {
5683 return;
5686 nwrap_setspent();
5689 static struct spwd *nwrap_getspent(void)
5691 return nwrap_files_getspent();
5694 struct spwd *getspent(void)
5696 if (!nss_wrapper_shadow_enabled()) {
5697 return NULL;
5700 return nwrap_getspent();
5703 static void nwrap_endspent(void)
5705 nwrap_files_endspent();
5708 void endspent(void)
5710 if (!nss_wrapper_shadow_enabled()) {
5711 return;
5714 nwrap_endspent();
5716 #endif /* HAVE_SETSPENT */
5718 static struct spwd *nwrap_getspnam(const char *name)
5720 return nwrap_files_getspnam(name);
5723 struct spwd *getspnam(const char *name)
5725 if (!nss_wrapper_shadow_enabled()) {
5726 return NULL;
5729 return nwrap_getspnam(name);
5732 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
5734 /**********************************************************
5735 * NETDB
5736 **********************************************************/
5738 static void nwrap_sethostent(int stayopen) {
5739 (void) stayopen; /* ignored */
5741 nwrap_files_sethostent();
5744 #ifdef HAVE_SOLARIS_SETHOSTENT
5745 int sethostent(int stayopen)
5747 if (!nss_wrapper_hosts_enabled()) {
5748 libc_sethostent(stayopen);
5749 return 0;
5752 nwrap_sethostent(stayopen);
5754 return 0;
5756 #else /* HAVE_SOLARIS_SETHOSTENT */
5757 void sethostent(int stayopen)
5759 if (!nss_wrapper_hosts_enabled()) {
5760 libc_sethostent(stayopen);
5761 return;
5764 nwrap_sethostent(stayopen);
5766 #endif /* HAVE_SOLARIS_SETHOSTENT */
5768 static struct hostent *nwrap_gethostent(void)
5770 return nwrap_files_gethostent();
5773 struct hostent *gethostent(void) {
5774 if (!nss_wrapper_hosts_enabled()) {
5775 return libc_gethostent();
5778 return nwrap_gethostent();
5781 static void nwrap_endhostent(void) {
5782 nwrap_files_endhostent();
5785 #ifdef HAVE_SOLARIS_ENDHOSTENT
5786 int endhostent(void)
5788 if (!nss_wrapper_hosts_enabled()) {
5789 libc_endhostent();
5790 return 0;
5793 nwrap_endhostent();
5795 return 0;
5797 #else /* HAVE_SOLARIS_ENDHOSTENT */
5798 void endhostent(void)
5800 if (!nss_wrapper_hosts_enabled()) {
5801 libc_endhostent();
5802 return;
5805 nwrap_endhostent();
5807 #endif /* HAVE_SOLARIS_ENDHOSTENT */
5810 #ifdef BSD
5811 /* BSD implementation stores data in thread local storage but GLIBC does not */
5812 static __thread struct hostent user_he;
5813 static __thread struct nwrap_vector user_addrlist;
5814 #else
5815 static struct hostent user_he;
5816 static struct nwrap_vector user_addrlist;
5817 #endif /* BSD */
5819 static struct hostent *nwrap_files_gethostbyname(struct nwrap_backend *b,
5820 const char *name)
5822 int ret;
5824 (void) b; /* unused */
5826 ret = nwrap_files_internal_gethostbyname(name, AF_UNSPEC, &user_he,
5827 &user_addrlist);
5828 if (ret == 0) {
5829 return &user_he;
5832 return NULL;
5835 static struct hostent *nwrap_gethostbyname(const char *name)
5837 size_t i;
5838 struct hostent *he = NULL;
5840 for (i=0; i < nwrap_main_global->num_backends; i++) {
5841 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5842 he = b->ops->nw_gethostbyname(b, name);
5843 if (he != NULL) {
5844 return he;
5848 return NULL;
5851 struct hostent *gethostbyname(const char *name)
5853 if (!nss_wrapper_hosts_enabled()) {
5854 return libc_gethostbyname(name);
5857 return nwrap_gethostbyname(name);
5860 /* This is a GNU extension - Also can be found on BSD systems */
5861 #ifdef HAVE_GETHOSTBYNAME2
5862 #ifdef BSD
5863 /* BSD implementation stores data in thread local storage but GLIBC not */
5864 static __thread struct hostent user_he2;
5865 static __thread struct nwrap_vector user_addrlist2;
5866 #else
5867 static struct hostent user_he2;
5868 static struct nwrap_vector user_addrlist2;
5869 #endif /* BSD */
5871 static struct hostent *nwrap_files_gethostbyname2(struct nwrap_backend *b,
5872 const char *name, int af)
5874 int ret;
5876 (void) b; /* unused */
5878 ret = nwrap_files_internal_gethostbyname(name, af, &user_he2,
5879 &user_addrlist2);
5880 if (ret == 0) {
5881 return &user_he2;
5884 return NULL;
5887 static struct hostent *nwrap_gethostbyname2(const char *name, int af)
5889 size_t i;
5890 struct hostent *he = NULL;
5892 for (i=0; i < nwrap_main_global->num_backends; i++) {
5893 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5894 he = b->ops->nw_gethostbyname2(b, name, af);
5895 if (he != NULL) {
5896 return he;
5900 return NULL;
5903 struct hostent *gethostbyname2(const char *name, int af)
5905 if (!nss_wrapper_hosts_enabled()) {
5906 return libc_gethostbyname2(name, af);
5909 return nwrap_gethostbyname2(name, af);
5911 #endif
5913 static struct hostent *nwrap_gethostbyaddr(const void *addr,
5914 socklen_t len, int type)
5916 size_t i;
5917 struct hostent *he = NULL;
5919 for (i=0; i < nwrap_main_global->num_backends; i++) {
5920 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5921 he = b->ops->nw_gethostbyaddr(b, addr, len, type);
5922 if (he != NULL) {
5923 return he;
5927 return NULL;
5930 struct hostent *gethostbyaddr(const void *addr,
5931 socklen_t len, int type)
5933 if (!nss_wrapper_hosts_enabled()) {
5934 return libc_gethostbyaddr(addr, len, type);
5937 return nwrap_gethostbyaddr(addr, len, type);
5940 static const struct addrinfo default_hints =
5942 .ai_flags = AI_ADDRCONFIG|AI_V4MAPPED,
5943 .ai_family = AF_UNSPEC,
5944 .ai_socktype = 0,
5945 .ai_protocol = 0,
5946 .ai_addrlen = 0,
5947 .ai_addr = NULL,
5948 .ai_canonname = NULL,
5949 .ai_next = NULL
5952 static int nwrap_convert_he_ai(const struct hostent *he,
5953 unsigned short port,
5954 const struct addrinfo *hints,
5955 struct addrinfo **pai,
5956 bool skip_canonname)
5958 struct addrinfo *ai;
5959 socklen_t socklen;
5961 if (he == NULL) {
5962 return EAI_MEMORY;
5965 switch (he->h_addrtype) {
5966 case AF_INET:
5967 socklen = sizeof(struct sockaddr_in);
5968 break;
5969 #ifdef HAVE_IPV6
5970 case AF_INET6:
5971 socklen = sizeof(struct sockaddr_in6);
5972 break;
5973 #endif
5974 default:
5975 return EAI_FAMILY;
5978 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + socklen);
5979 if (ai == NULL) {
5980 return EAI_MEMORY;
5983 ai->ai_flags = hints->ai_flags;
5984 ai->ai_family = he->h_addrtype;
5985 ai->ai_socktype = hints->ai_socktype;
5986 ai->ai_protocol = hints->ai_protocol;
5987 ai->ai_canonname = NULL;
5989 if (ai->ai_socktype == 0) {
5990 ai->ai_socktype = SOCK_DGRAM;
5992 if (ai->ai_protocol == 0) {
5993 if (ai->ai_socktype == SOCK_DGRAM) {
5994 ai->ai_protocol = IPPROTO_UDP;
5995 } else if (ai->ai_socktype == SOCK_STREAM) {
5996 ai->ai_protocol = IPPROTO_TCP;
6000 ai->ai_addrlen = socklen;
6001 ai->ai_addr = (void *)(ai + 1);
6003 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
6004 ai->ai_addr->sa_len = socklen;
6005 #endif
6006 ai->ai_addr->sa_family = he->h_addrtype;
6008 switch (he->h_addrtype) {
6009 case AF_INET:
6011 union {
6012 struct sockaddr *sa;
6013 struct sockaddr_in *in;
6014 } addr;
6016 addr.sa = ai->ai_addr;
6018 memset(addr.in, 0, sizeof(struct sockaddr_in));
6020 addr.in->sin_port = htons(port);
6021 addr.in->sin_family = AF_INET;
6023 memset(addr.in->sin_zero,
6024 '\0',
6025 sizeof (addr.in->sin_zero));
6026 memcpy(&(addr.in->sin_addr),
6027 he->h_addr_list[0],
6028 he->h_length);
6031 break;
6032 #ifdef HAVE_IPV6
6033 case AF_INET6:
6035 union {
6036 struct sockaddr *sa;
6037 struct sockaddr_in6 *in6;
6038 } addr;
6040 addr.sa = ai->ai_addr;
6042 memset(addr.in6, 0, sizeof(struct sockaddr_in6));
6044 addr.in6->sin6_port = htons(port);
6045 addr.in6->sin6_family = AF_INET6;
6047 memcpy(&addr.in6->sin6_addr,
6048 he->h_addr_list[0],
6049 he->h_length);
6051 break;
6052 #endif
6055 ai->ai_next = NULL;
6057 if (he->h_name && !skip_canonname) {
6058 ai->ai_canonname = strdup(he->h_name);
6059 if (ai->ai_canonname == NULL) {
6060 freeaddrinfo(ai);
6061 return EAI_MEMORY;
6065 *pai = ai;
6066 return 0;
6069 static int nwrap_getaddrinfo(const char *node,
6070 const char *service,
6071 const struct addrinfo *hints,
6072 struct addrinfo **res)
6074 struct addrinfo *ai = NULL;
6075 unsigned short port = 0;
6076 struct {
6077 int family;
6078 union {
6079 struct in_addr v4;
6080 #ifdef HAVE_IPV6
6081 struct in6_addr v6;
6082 } in;
6083 #endif
6084 } addr = {
6085 .family = AF_UNSPEC,
6087 int rc;
6089 if (node == NULL && service == NULL) {
6090 return EAI_NONAME;
6093 if (hints == NULL) {
6094 hints = &default_hints;
6097 /* EAI_BADFLAGS
6098 hints.ai_flags contains invalid flags; or, hints.ai_flags
6099 included AI_CANONNAME and name was NULL.
6101 if ((hints->ai_flags & AI_CANONNAME) && (node == NULL)) {
6102 return EAI_BADFLAGS;
6105 /* If no node has been specified, let glibc deal with it */
6106 if (node == NULL) {
6107 int ret;
6108 struct addrinfo *p = NULL;
6110 ret = libc_getaddrinfo(node, service, hints, &p);
6112 if (ret == 0) {
6113 *res = p;
6115 return ret;
6118 if (service != NULL && service[0] != '\0') {
6119 const char *proto = NULL;
6120 struct servent *s;
6121 char *end_ptr;
6122 long sl;
6124 errno = 0;
6125 sl = strtol(service, &end_ptr, 10);
6127 if (*end_ptr == '\0') {
6128 port = sl;
6129 goto valid_port;
6130 } else if (hints->ai_flags & AI_NUMERICSERV) {
6131 return EAI_NONAME;
6134 if (hints->ai_protocol != 0) {
6135 struct protoent *pent;
6137 pent = getprotobynumber(hints->ai_protocol);
6138 if (pent != NULL) {
6139 proto = pent->p_name;
6143 s = getservbyname(service, proto);
6144 if (s == NULL) {
6145 return EAI_NONAME;
6147 port = ntohs(s->s_port);
6150 valid_port:
6152 rc = inet_pton(AF_INET, node, &addr.in.v4);
6153 if (rc == 1) {
6154 addr.family = AF_INET;
6156 #ifdef HAVE_IPV6
6157 if (addr.family == AF_UNSPEC) {
6158 rc = inet_pton(AF_INET6, node, &addr.in.v6);
6159 if (rc == 1) {
6160 addr.family = AF_INET6;
6163 #endif
6165 if (addr.family == AF_UNSPEC) {
6166 if (hints->ai_flags & AI_NUMERICHOST) {
6167 return EAI_NONAME;
6169 } else if ((hints->ai_family != AF_UNSPEC) &&
6170 (hints->ai_family != addr.family))
6172 return EAI_ADDRFAMILY;
6175 rc = nwrap_files_getaddrinfo(node, port, hints, &ai);
6176 if (rc != 0) {
6177 int ret;
6178 struct addrinfo *p = NULL;
6180 ret = libc_getaddrinfo(node, service, hints, &p);
6182 if (ret == 0) {
6184 * nwrap_files_getaddrinfo failed, but libc was
6185 * successful -- use the result from libc.
6187 *res = p;
6188 return 0;
6191 return rc;
6195 * If the socktype was not specified, duplicate
6196 * each ai returned, so that we have variants for
6197 * both UDP and TCP.
6199 if (hints->ai_socktype == 0) {
6200 struct addrinfo *ai_cur;
6202 /* freeaddrinfo() frees ai_canonname and ai so allocate them */
6203 for (ai_cur = ai; ai_cur != NULL; ai_cur = ai_cur->ai_next) {
6204 struct addrinfo *ai_new;
6206 /* duplicate the current entry */
6208 ai_new = malloc(sizeof(struct addrinfo));
6209 if (ai_new == NULL) {
6210 freeaddrinfo(ai);
6211 return EAI_MEMORY;
6214 memcpy(ai_new, ai_cur, sizeof(struct addrinfo));
6215 ai_new->ai_next = NULL;
6217 /* We need a deep copy or freeaddrinfo() will blow up */
6218 if (ai_cur->ai_canonname != NULL) {
6219 ai_new->ai_canonname =
6220 strdup(ai_cur->ai_canonname);
6223 if (ai_cur->ai_socktype == SOCK_DGRAM) {
6224 ai_new->ai_socktype = SOCK_STREAM;
6225 } else if (ai_cur->ai_socktype == SOCK_STREAM) {
6226 ai_new->ai_socktype = SOCK_DGRAM;
6228 if (ai_cur->ai_protocol == IPPROTO_TCP) {
6229 ai_new->ai_protocol = IPPROTO_UDP;
6230 } else if (ai_cur->ai_protocol == IPPROTO_UDP) {
6231 ai_new->ai_protocol = IPPROTO_TCP;
6234 /* now insert the new entry */
6236 ai_new->ai_next = ai_cur->ai_next;
6237 ai_cur->ai_next = ai_new;
6239 /* and move on (don't duplicate the new entry) */
6241 ai_cur = ai_new;
6245 *res = ai;
6247 return 0;
6250 int getaddrinfo(const char *node, const char *service,
6251 const struct addrinfo *hints,
6252 struct addrinfo **res)
6254 if (!nss_wrapper_hosts_enabled()) {
6255 return libc_getaddrinfo(node, service, hints, res);
6258 return nwrap_getaddrinfo(node, service, hints, res);
6261 static int nwrap_getnameinfo(const struct sockaddr *sa, socklen_t salen,
6262 char *host, size_t hostlen,
6263 char *serv, size_t servlen,
6264 int flags)
6266 struct hostent *he;
6267 struct servent *service;
6268 const char *proto;
6269 const void *addr;
6270 socklen_t addrlen;
6271 uint16_t port;
6272 sa_family_t type;
6273 size_t i;
6275 if (sa == NULL || salen < sizeof(sa_family_t)) {
6276 return EAI_FAMILY;
6279 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL) {
6280 return EAI_NONAME;
6283 type = sa->sa_family;
6284 switch (type) {
6285 case AF_INET: {
6286 union {
6287 const struct sockaddr *sa;
6288 const struct sockaddr_in *in;
6289 } a;
6291 if (salen < sizeof(struct sockaddr_in)) {
6292 return EAI_FAMILY;
6295 a.sa = sa;
6297 addr = &(a.in->sin_addr);
6298 addrlen = sizeof(a.in->sin_addr);
6299 port = ntohs(a.in->sin_port);
6300 break;
6302 #ifdef HAVE_IPV6
6303 case AF_INET6: {
6304 union {
6305 const struct sockaddr *sa;
6306 const struct sockaddr_in6 *in6;
6307 } a;
6309 if (salen < sizeof(struct sockaddr_in6)) {
6310 return EAI_FAMILY;
6313 a.sa = sa;
6315 addr = &(a.in6->sin6_addr);
6316 addrlen = sizeof(a.in6->sin6_addr);
6317 port = ntohs(a.in6->sin6_port);
6318 break;
6320 #endif
6321 default:
6322 return EAI_FAMILY;
6325 if (host != NULL) {
6326 he = NULL;
6327 if ((flags & NI_NUMERICHOST) == 0) {
6328 for (i=0; i < nwrap_main_global->num_backends; i++) {
6329 struct nwrap_backend *b = &nwrap_main_global->backends[i];
6330 he = b->ops->nw_gethostbyaddr(b, addr, addrlen, type);
6331 if (he != NULL) {
6332 break;
6335 if ((flags & NI_NAMEREQD) && (he == NULL || he->h_name == NULL))
6336 return EAI_NONAME;
6338 if (he != NULL && he->h_name != NULL) {
6339 if (strlen(he->h_name) >= hostlen)
6340 return EAI_OVERFLOW;
6341 snprintf(host, hostlen, "%s", he->h_name);
6342 if (flags & NI_NOFQDN)
6343 host[strcspn(host, ".")] = '\0';
6344 } else {
6345 if (inet_ntop(type, addr, host, hostlen) == NULL)
6346 return (errno == ENOSPC) ? EAI_OVERFLOW : EAI_FAIL;
6350 if (serv != NULL) {
6351 service = NULL;
6352 if ((flags & NI_NUMERICSERV) == 0) {
6353 proto = (flags & NI_DGRAM) ? "udp" : "tcp";
6354 service = getservbyport(htons(port), proto);
6356 if (service != NULL) {
6357 if (strlen(service->s_name) >= servlen)
6358 return EAI_OVERFLOW;
6359 snprintf(serv, servlen, "%s", service->s_name);
6360 } else {
6361 if (snprintf(serv, servlen, "%u", port) >= (int) servlen)
6362 return EAI_OVERFLOW;
6366 return 0;
6369 #ifdef HAVE_LINUX_GETNAMEINFO
6370 int getnameinfo(const struct sockaddr *sa, socklen_t salen,
6371 char *host, socklen_t hostlen,
6372 char *serv, socklen_t servlen,
6373 int flags)
6374 #elif defined(HAVE_LINUX_GETNAMEINFO_UNSIGNED)
6375 int getnameinfo(const struct sockaddr *sa, socklen_t salen,
6376 char *host, socklen_t hostlen,
6377 char *serv, socklen_t servlen,
6378 unsigned int flags)
6379 #else
6380 int getnameinfo(const struct sockaddr *sa, socklen_t salen,
6381 char *host, size_t hostlen,
6382 char *serv, size_t servlen,
6383 int flags)
6384 #endif
6386 if (!nss_wrapper_hosts_enabled()) {
6387 return libc_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
6390 return nwrap_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
6393 static int nwrap_gethostname(char *name, size_t len)
6395 const char *hostname = getenv("NSS_WRAPPER_HOSTNAME");
6397 if (strlen(hostname) >= len) {
6398 errno = ENAMETOOLONG;
6399 return -1;
6401 snprintf(name, len, "%s", hostname);
6403 return 0;
6406 #ifdef HAVE_SOLARIS_GETHOSTNAME
6407 int gethostname(char *name, int len)
6408 #else /* HAVE_SOLARIS_GETHOSTNAME */
6409 int gethostname(char *name, size_t len)
6410 #endif /* HAVE_SOLARIS_GETHOSTNAME */
6412 if (!nwrap_hostname_enabled()) {
6413 return libc_gethostname(name, len);
6416 return nwrap_gethostname(name, len);
6419 static void nwrap_thread_prepare(void)
6421 nwrap_init();
6422 NWRAP_LOCK_ALL;
6425 static void nwrap_thread_parent(void)
6427 NWRAP_UNLOCK_ALL;
6430 static void nwrap_thread_child(void)
6432 NWRAP_REINIT_ALL;
6435 /****************************
6436 * CONSTRUCTOR
6437 ***************************/
6438 void nwrap_constructor(void)
6440 NWRAP_REINIT_ALL;
6443 * If we hold a lock and the application forks, then the child
6444 * is not able to unlock the mutex and we are in a deadlock.
6446 * Setting these handlers should prevent such deadlocks.
6448 pthread_atfork(&nwrap_thread_prepare,
6449 &nwrap_thread_parent,
6450 &nwrap_thread_child);
6452 /* Do not call nwrap_init() here. */
6455 /****************************
6456 * DESTRUCTOR
6457 ***************************/
6460 * This function is called when the library is unloaded and makes sure that
6461 * sockets get closed and the unix file for the socket are unlinked.
6463 void nwrap_destructor(void)
6465 size_t i;
6467 NWRAP_LOCK_ALL;
6468 if (nwrap_main_global != NULL) {
6469 struct nwrap_main *m = nwrap_main_global;
6471 /* libc */
6472 if (m->libc != NULL) {
6473 if (m->libc->handle != NULL
6474 #ifdef RTLD_NEXT
6475 && m->libc->handle != RTLD_NEXT
6476 #endif
6478 dlclose(m->libc->handle);
6480 if (m->libc->nsl_handle != NULL
6481 #ifdef RTLD_NEXT
6482 && m->libc->nsl_handle != RTLD_NEXT
6483 #endif
6485 dlclose(m->libc->nsl_handle);
6487 if (m->libc->sock_handle != NULL
6488 #ifdef RTLD_NEXT
6489 && m->libc->sock_handle != RTLD_NEXT
6490 #endif
6492 dlclose(m->libc->sock_handle);
6494 SAFE_FREE(m->libc);
6497 /* backends */
6498 if (m->backends != NULL) {
6499 for (i = 0; i < m->num_backends; i++) {
6500 struct nwrap_backend *b = &(m->backends[i]);
6502 if (b->so_handle != NULL) {
6503 dlclose(b->so_handle);
6505 SAFE_FREE(b->symbols);
6507 SAFE_FREE(m->backends);
6511 if (nwrap_pw_global.cache != NULL) {
6512 struct nwrap_cache *c = nwrap_pw_global.cache;
6514 nwrap_files_cache_unload(c);
6515 if (c->fd >= 0) {
6516 fclose(c->fp);
6517 c->fd = -1;
6520 SAFE_FREE(nwrap_pw_global.list);
6521 nwrap_pw_global.num = 0;
6524 if (nwrap_gr_global.cache != NULL) {
6525 struct nwrap_cache *c = nwrap_gr_global.cache;
6527 nwrap_files_cache_unload(c);
6528 if (c->fd >= 0) {
6529 fclose(c->fp);
6530 c->fd = -1;
6533 SAFE_FREE(nwrap_gr_global.list);
6534 nwrap_pw_global.num = 0;
6537 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
6538 if (nwrap_sp_global.cache != NULL) {
6539 struct nwrap_cache *c = nwrap_sp_global.cache;
6541 nwrap_files_cache_unload(c);
6542 if (c->fd >= 0) {
6543 fclose(c->fp);
6544 c->fd = -1;
6547 nwrap_sp_global.num = 0;
6549 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
6551 if (nwrap_he_global.cache != NULL) {
6552 struct nwrap_cache *c = nwrap_he_global.cache;
6554 nwrap_files_cache_unload(c);
6555 if (c->fd >= 0) {
6556 fclose(c->fp);
6557 c->fd = -1;
6560 nwrap_he_global.num = 0;
6563 free(user_addrlist.items);
6564 #ifdef HAVE_GETHOSTBYNAME2
6565 free(user_addrlist2.items);
6566 #endif
6568 hdestroy();
6569 NWRAP_UNLOCK_ALL;