ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / third_party / nss_wrapper / nss_wrapper.c
blob770d0cf5dddb3c2dff6f8424d1dca702cbf68c2a
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 #ifdef HAVE_GNU_LIB_NAMES_H
65 #include <gnu/lib-names.h>
66 #endif
68 #include "nss_utils.h"
70 * Defining _POSIX_PTHREAD_SEMANTICS before including pwd.h and grp.h gives us
71 * the posix getpwnam_r(), getpwuid_r(), getgrnam_r and getgrgid_r calls on
72 * Solaris
74 #ifndef _POSIX_PTHREAD_SEMANTICS
75 #define _POSIX_PTHREAD_SEMANTICS
76 #endif
78 #include <pwd.h>
79 #include <grp.h>
80 #ifdef HAVE_SHADOW_H
81 #include <shadow.h>
82 #endif /* HAVE_SHADOW_H */
84 #include <netdb.h>
85 #include <arpa/inet.h>
86 #include <netinet/in.h>
88 #include <dlfcn.h>
90 #if defined(HAVE_NSS_H)
91 /* Linux and BSD */
92 #include <nss.h>
94 typedef enum nss_status NSS_STATUS;
95 #elif defined(HAVE_NSS_COMMON_H)
96 /* Solaris */
97 #include <nss_common.h>
98 #include <nss_dbdefs.h>
99 #include <nsswitch.h>
101 typedef nss_status_t NSS_STATUS;
103 # define NSS_STATUS_SUCCESS NSS_SUCCESS
104 # define NSS_STATUS_NOTFOUND NSS_NOTFOUND
105 # define NSS_STATUS_UNAVAIL NSS_UNAVAIL
106 # define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN
107 #else
108 # error "No nsswitch support detected"
109 #endif
111 #ifndef PTR_DIFF
112 #define PTR_DIFF(p1, p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2)))
113 #endif
115 #ifndef _PUBLIC_
116 #define _PUBLIC_
117 #endif
119 #ifndef EAI_NODATA
120 #define EAI_NODATA EAI_NONAME
121 #endif
123 #ifndef EAI_ADDRFAMILY
124 #define EAI_ADDRFAMILY EAI_FAMILY
125 #endif
127 #ifndef __STRING
128 #define __STRING(x) #x
129 #endif
131 #ifndef __STRINGSTRING
132 #define __STRINGSTRING(x) __STRING(x)
133 #endif
135 #ifndef __LINESTR__
136 #define __LINESTR__ __STRINGSTRING(__LINE__)
137 #endif
139 #ifndef __location__
140 #define __location__ __FILE__ ":" __LINESTR__
141 #endif
143 #ifndef DNS_NAME_MAX
144 #define DNS_NAME_MAX 255
145 #endif
147 /* GCC have printf type attribute check. */
148 #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT
149 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
150 #else
151 #define PRINTF_ATTRIBUTE(a,b)
152 #endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */
154 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
155 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
156 #else
157 #define CONSTRUCTOR_ATTRIBUTE
158 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
160 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
161 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
162 #else
163 #define DESTRUCTOR_ATTRIBUTE
164 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
166 #define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
168 #ifndef SAFE_FREE
169 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
170 #endif
172 #ifndef discard_const
173 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
174 #endif
176 #ifndef discard_const_p
177 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
178 #endif
180 #ifdef HAVE_IPV6
181 #define NWRAP_INET_ADDRSTRLEN INET6_ADDRSTRLEN
182 #else
183 #define NWRAP_INET_ADDRSTRLEN INET_ADDRSTRLEN
184 #endif
186 #define MAX(a,b) ((a) < (b) ? (b) : (a))
187 #define MIN(a,b) ((a) > (b) ? (b) : (a))
189 static bool nwrap_initialized = false;
190 static pthread_mutex_t nwrap_initialized_mutex = PTHREAD_MUTEX_INITIALIZER;
192 /* The mutex or accessing the id */
193 static pthread_mutex_t nwrap_global_mutex = PTHREAD_MUTEX_INITIALIZER;
194 static pthread_mutex_t nwrap_gr_global_mutex = PTHREAD_MUTEX_INITIALIZER;
195 static pthread_mutex_t nwrap_he_global_mutex = PTHREAD_MUTEX_INITIALIZER;
196 static pthread_mutex_t nwrap_pw_global_mutex = PTHREAD_MUTEX_INITIALIZER;
197 static pthread_mutex_t nwrap_sp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
199 #define nss_wrapper_init_mutex(m) \
200 _nss_wrapper_init_mutex(m, #m)
202 /* Add new global locks here please */
203 /* Also don't forget to add locks to
204 * nwrap_init() function.
206 # define NWRAP_REINIT_ALL do { \
207 int ret; \
208 ret = nss_wrapper_init_mutex(&nwrap_initialized_mutex); \
209 if (ret != 0) exit(-1); \
210 ret = nss_wrapper_init_mutex(&nwrap_global_mutex); \
211 if (ret != 0) exit(-1); \
212 ret = nss_wrapper_init_mutex(&nwrap_gr_global_mutex); \
213 if (ret != 0) exit(-1); \
214 ret = nss_wrapper_init_mutex(&nwrap_he_global_mutex); \
215 if (ret != 0) exit(-1); \
216 ret = nss_wrapper_init_mutex(&nwrap_pw_global_mutex); \
217 if (ret != 0) exit(-1); \
218 ret = nss_wrapper_init_mutex(&nwrap_sp_global_mutex); \
219 if (ret != 0) exit(-1); \
220 } while(0)
222 # define NWRAP_LOCK_ALL do { \
223 nwrap_mutex_lock(&nwrap_initialized_mutex); \
224 nwrap_mutex_lock(&nwrap_global_mutex); \
225 nwrap_mutex_lock(&nwrap_gr_global_mutex); \
226 nwrap_mutex_lock(&nwrap_he_global_mutex); \
227 nwrap_mutex_lock(&nwrap_pw_global_mutex); \
228 nwrap_mutex_lock(&nwrap_sp_global_mutex); \
229 } while (0);
231 # define NWRAP_UNLOCK_ALL do {\
232 nwrap_mutex_unlock(&nwrap_sp_global_mutex); \
233 nwrap_mutex_unlock(&nwrap_pw_global_mutex); \
234 nwrap_mutex_unlock(&nwrap_he_global_mutex); \
235 nwrap_mutex_unlock(&nwrap_gr_global_mutex); \
236 nwrap_mutex_unlock(&nwrap_global_mutex); \
237 nwrap_mutex_unlock(&nwrap_initialized_mutex); \
238 } while (0);
240 static void nwrap_init(void);
242 enum nwrap_dbglvl_e {
243 NWRAP_LOG_ERROR = 0,
244 NWRAP_LOG_WARN,
245 NWRAP_LOG_DEBUG,
246 NWRAP_LOG_TRACE
249 #ifndef HAVE_GETPROGNAME
250 static const char *getprogname(void)
252 #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
253 return program_invocation_short_name;
254 #elif defined(HAVE_GETEXECNAME)
255 return getexecname();
256 #else
257 return NULL;
258 #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
260 #endif /* HAVE_GETPROGNAME */
262 static void nwrap_log(enum nwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
263 # define NWRAP_LOG(dbglvl, ...) nwrap_log((dbglvl), __func__, __VA_ARGS__)
265 static void nwrap_log(enum nwrap_dbglvl_e dbglvl,
266 const char *func,
267 const char *format, ...)
269 char buffer[1024];
270 va_list va;
271 const char *d;
272 unsigned int lvl = 0;
273 const char *prefix = "NWRAP";
274 const char *progname = getprogname();
276 d = getenv("NSS_WRAPPER_DEBUGLEVEL");
277 if (d != NULL) {
278 lvl = atoi(d);
281 if (lvl < dbglvl) {
282 return;
285 va_start(va, format);
286 vsnprintf(buffer, sizeof(buffer), format, va);
287 va_end(va);
289 switch (dbglvl) {
290 case NWRAP_LOG_ERROR:
291 prefix = "NWRAP_ERROR";
292 break;
293 case NWRAP_LOG_WARN:
294 prefix = "NWRAP_WARN";
295 break;
296 case NWRAP_LOG_DEBUG:
297 prefix = "NWRAP_DEBUG";
298 break;
299 case NWRAP_LOG_TRACE:
300 prefix = "NWRAP_TRACE";
301 break;
304 if (progname == NULL) {
305 progname = "<unknown>";
308 fprintf(stderr,
309 "%s[%s (%u)] - %s: %s\n",
310 prefix,
311 progname,
312 (unsigned int)getpid(),
313 func,
314 buffer);
317 /*****************
318 * LIBC
319 *****************/
321 #define LIBC_NAME "libc.so"
323 typedef struct passwd *(*__libc_getpwnam)(const char *name);
325 typedef int (*__libc_getpwnam_r)(const char *name,
326 struct passwd *pwd,
327 char *buf,
328 size_t buflen,
329 struct passwd **result);
331 typedef struct passwd *(*__libc_getpwuid)(uid_t uid);
333 typedef int (*__libc_getpwuid_r)(uid_t uid,
334 struct passwd *pwd,
335 char *buf,
336 size_t buflen,
337 struct passwd **result);
339 typedef void (*__libc_setpwent)(void);
341 typedef struct passwd *(*__libc_getpwent)(void);
343 #ifdef HAVE_GETPWENT_R
344 # ifdef HAVE_SOLARIS_GETPWENT_R
345 typedef struct passwd *(*__libc_getpwent_r)(struct passwd *pwbuf,
346 char *buf,
347 size_t buflen);
348 # else /* HAVE_SOLARIS_GETPWENT_R */
349 typedef int (*__libc_getpwent_r)(struct passwd *pwbuf,
350 char *buf,
351 size_t buflen,
352 struct passwd **pwbufp);
353 # endif /* HAVE_SOLARIS_GETPWENT_R */
354 #endif /* HAVE_GETPWENT_R */
356 typedef void (*__libc_endpwent)(void);
358 typedef int (*__libc_initgroups)(const char *user, gid_t gid);
360 typedef struct group *(*__libc_getgrnam)(const char *name);
362 typedef int (*__libc_getgrnam_r)(const char *name,
363 struct group *grp,
364 char *buf,
365 size_t buflen,
366 struct group **result);
368 typedef struct group *(*__libc_getgrgid)(gid_t gid);
370 typedef int (*__libc_getgrgid_r)(gid_t gid,
371 struct group *grp,
372 char *buf,
373 size_t buflen,
374 struct group **result);
376 typedef void (*__libc_setgrent)(void);
378 typedef struct group *(*__libc_getgrent)(void);
380 #ifdef HAVE_GETGRENT_R
381 # ifdef HAVE_SOLARIS_GETGRENT_R
382 typedef struct group *(*__libc_getgrent_r)(struct group *group,
383 char *buf,
384 size_t buflen);
385 # else /* HAVE_SOLARIS_GETGRENT_R */
386 typedef int (*__libc_getgrent_r)(struct group *group,
387 char *buf,
388 size_t buflen,
389 struct group **result);
390 # endif /* HAVE_SOLARIS_GETGRENT_R */
391 #endif /* HAVE_GETGRENT_R */
393 typedef void (*__libc_endgrent)(void);
395 typedef int (*__libc_getgrouplist)(const char *user,
396 gid_t group,
397 gid_t *groups,
398 int *ngroups);
400 typedef void (*__libc_sethostent)(int stayopen);
402 typedef struct hostent *(*__libc_gethostent)(void);
404 typedef void (*__libc_endhostent)(void);
406 typedef struct hostent *(*__libc_gethostbyname)(const char *name);
408 #ifdef HAVE_GETHOSTBYNAME2 /* GNU extension */
409 typedef struct hostent *(*__libc_gethostbyname2)(const char *name, int af);
410 #endif
412 #ifdef HAVE_GETHOSTBYNAME2_R /* GNU extension */
413 typedef int (*__libc_gethostbyname2_r)(const char *name,
414 int af,
415 struct hostent *ret,
416 char *buf,
417 size_t buflen,
418 struct hostent **result,
419 int *h_errnop);
420 #endif
422 typedef struct hostent *(*__libc_gethostbyaddr)(const void *addr,
423 socklen_t len,
424 int type);
426 typedef int (*__libc_getaddrinfo)(const char *node,
427 const char *service,
428 const struct addrinfo *hints,
429 struct addrinfo **res);
430 typedef int (*__libc_getnameinfo)(const struct sockaddr *sa,
431 socklen_t salen,
432 char *host,
433 size_t hostlen,
434 char *serv,
435 size_t servlen,
436 int flags);
438 typedef int (*__libc_gethostname)(char *name, size_t len);
440 #ifdef HAVE_GETHOSTBYNAME_R
441 typedef int (*__libc_gethostbyname_r)(const char *name,
442 struct hostent *ret,
443 char *buf, size_t buflen,
444 struct hostent **result, int *h_errnop);
445 #endif
447 #ifdef HAVE_GETHOSTBYADDR_R
448 typedef int (*__libc_gethostbyaddr_r)(const void *addr,
449 socklen_t len,
450 int type,
451 struct hostent *ret,
452 char *buf,
453 size_t buflen,
454 struct hostent **result,
455 int *h_errnop);
456 #endif
458 #define NWRAP_SYMBOL_ENTRY(i) \
459 union { \
460 __libc_##i f; \
461 void *obj; \
462 } _libc_##i
464 struct nwrap_libc_symbols {
465 NWRAP_SYMBOL_ENTRY(getpwnam);
466 NWRAP_SYMBOL_ENTRY(getpwnam_r);
467 NWRAP_SYMBOL_ENTRY(getpwuid);
468 NWRAP_SYMBOL_ENTRY(getpwuid_r);
469 NWRAP_SYMBOL_ENTRY(setpwent);
470 NWRAP_SYMBOL_ENTRY(getpwent);
471 #ifdef HAVE_GETPWENT_R
472 NWRAP_SYMBOL_ENTRY(getpwent_r);
473 #endif
474 NWRAP_SYMBOL_ENTRY(endpwent);
476 NWRAP_SYMBOL_ENTRY(initgroups);
477 NWRAP_SYMBOL_ENTRY(getgrnam);
478 NWRAP_SYMBOL_ENTRY(getgrnam_r);
479 NWRAP_SYMBOL_ENTRY(getgrgid);
480 NWRAP_SYMBOL_ENTRY(getgrgid_r);
481 NWRAP_SYMBOL_ENTRY(setgrent);
482 NWRAP_SYMBOL_ENTRY(getgrent);
483 #ifdef HAVE_GETGRENT_R
484 NWRAP_SYMBOL_ENTRY(getgrent_r);
485 #endif
486 NWRAP_SYMBOL_ENTRY(endgrent);
487 NWRAP_SYMBOL_ENTRY(getgrouplist);
489 NWRAP_SYMBOL_ENTRY(sethostent);
490 NWRAP_SYMBOL_ENTRY(gethostent);
491 NWRAP_SYMBOL_ENTRY(endhostent);
492 NWRAP_SYMBOL_ENTRY(gethostbyname);
493 #ifdef HAVE_GETHOSTBYNAME_R
494 NWRAP_SYMBOL_ENTRY(gethostbyname_r);
495 #endif
496 #ifdef HAVE_GETHOSTBYNAME2
497 NWRAP_SYMBOL_ENTRY(gethostbyname2);
498 #endif
499 #ifdef HAVE_GETHOSTBYNAME2_R
500 NWRAP_SYMBOL_ENTRY(gethostbyname2_r);
501 #endif
502 NWRAP_SYMBOL_ENTRY(gethostbyaddr);
503 #ifdef HAVE_GETHOSTBYADDR_R
504 NWRAP_SYMBOL_ENTRY(gethostbyaddr_r);
505 #endif
506 NWRAP_SYMBOL_ENTRY(getaddrinfo);
507 NWRAP_SYMBOL_ENTRY(getnameinfo);
508 NWRAP_SYMBOL_ENTRY(gethostname);
510 #undef NWRAP_SYMBOL_ENTRY
512 typedef NSS_STATUS (*__nss_getpwnam_r)(const char *name,
513 struct passwd *result,
514 char *buffer,
515 size_t buflen,
516 int *errnop);
517 typedef NSS_STATUS (*__nss_getpwuid_r)(uid_t uid,
518 struct passwd *result,
519 char *buffer,
520 size_t buflen,
521 int *errnop);
522 typedef NSS_STATUS (*__nss_setpwent)(void);
523 typedef NSS_STATUS (*__nss_getpwent_r)(struct passwd *result,
524 char *buffer,
525 size_t buflen,
526 int *errnop);
527 typedef NSS_STATUS (*__nss_endpwent)(void);
528 typedef NSS_STATUS (*__nss_initgroups_dyn)(const char *user,
529 gid_t group,
530 long int *start,
531 long int *size,
532 gid_t **groups,
533 long int limit,
534 int *errnop);
535 typedef NSS_STATUS (*__nss_getgrnam_r)(const char *name,
536 struct group *result,
537 char *buffer,
538 size_t buflen,
539 int *errnop);
540 typedef NSS_STATUS (*__nss_getgrgid_r)(gid_t gid,
541 struct group *result,
542 char *buffer,
543 size_t buflen,
544 int *errnop);
545 typedef NSS_STATUS (*__nss_setgrent)(void);
546 typedef NSS_STATUS (*__nss_getgrent_r)(struct group *result,
547 char *buffer,
548 size_t buflen,
549 int *errnop);
550 typedef NSS_STATUS (*__nss_endgrent)(void);
551 typedef NSS_STATUS (*__nss_gethostbyaddr_r)(const void *addr,
552 socklen_t addrlen,
553 int af,
554 struct hostent *result,
555 char *buffer,
556 size_t buflen,
557 int *errnop,
558 int *h_errnop);
559 typedef NSS_STATUS (*__nss_gethostbyname2_r)(const char *name,
560 int af,
561 struct hostent *result,
562 char *buffer,
563 size_t buflen,
564 int *errnop,
565 int *h_errnop);
567 #define NWRAP_NSS_MODULE_SYMBOL_ENTRY(i) \
568 union { \
569 __nss_##i f; \
570 void *obj; \
571 } _nss_##i
573 struct nwrap_nss_module_symbols {
574 NWRAP_NSS_MODULE_SYMBOL_ENTRY(getpwnam_r);
575 NWRAP_NSS_MODULE_SYMBOL_ENTRY(getpwuid_r);
576 NWRAP_NSS_MODULE_SYMBOL_ENTRY(setpwent);
577 NWRAP_NSS_MODULE_SYMBOL_ENTRY(getpwent_r);
578 NWRAP_NSS_MODULE_SYMBOL_ENTRY(endpwent);
580 NWRAP_NSS_MODULE_SYMBOL_ENTRY(initgroups_dyn);
581 NWRAP_NSS_MODULE_SYMBOL_ENTRY(getgrnam_r);
582 NWRAP_NSS_MODULE_SYMBOL_ENTRY(getgrgid_r);
583 NWRAP_NSS_MODULE_SYMBOL_ENTRY(setgrent);
584 NWRAP_NSS_MODULE_SYMBOL_ENTRY(getgrent_r);
585 NWRAP_NSS_MODULE_SYMBOL_ENTRY(endgrent);
587 NWRAP_NSS_MODULE_SYMBOL_ENTRY(gethostbyaddr_r);
588 NWRAP_NSS_MODULE_SYMBOL_ENTRY(gethostbyname2_r);
591 struct nwrap_backend {
592 const char *name;
593 const char *so_path;
594 void *so_handle;
595 struct nwrap_ops *ops;
596 struct nwrap_nss_module_symbols *symbols;
599 struct nwrap_vector;
601 struct nwrap_ops {
602 struct passwd * (*nw_getpwnam)(struct nwrap_backend *b,
603 const char *name);
604 int (*nw_getpwnam_r)(struct nwrap_backend *b,
605 const char *name, struct passwd *pwdst,
606 char *buf, size_t buflen, struct passwd **pwdstp);
607 struct passwd * (*nw_getpwuid)(struct nwrap_backend *b,
608 uid_t uid);
609 int (*nw_getpwuid_r)(struct nwrap_backend *b,
610 uid_t uid, struct passwd *pwdst,
611 char *buf, size_t buflen, struct passwd **pwdstp);
612 void (*nw_setpwent)(struct nwrap_backend *b);
613 struct passwd * (*nw_getpwent)(struct nwrap_backend *b);
614 int (*nw_getpwent_r)(struct nwrap_backend *b,
615 struct passwd *pwdst, char *buf,
616 size_t buflen, struct passwd **pwdstp);
617 void (*nw_endpwent)(struct nwrap_backend *b);
618 int (*nw_initgroups_dyn)(struct nwrap_backend *b,
619 const char *user,
620 gid_t group,
621 long int *start,
622 long int *size,
623 gid_t **groups,
624 long int limit,
625 int *errnop);
626 struct group * (*nw_getgrnam)(struct nwrap_backend *b,
627 const char *name);
628 int (*nw_getgrnam_r)(struct nwrap_backend *b,
629 const char *name, struct group *grdst,
630 char *buf, size_t buflen, struct group **grdstp);
631 struct group * (*nw_getgrgid)(struct nwrap_backend *b,
632 gid_t gid);
633 int (*nw_getgrgid_r)(struct nwrap_backend *b,
634 gid_t gid, struct group *grdst,
635 char *buf, size_t buflen, struct group **grdstp);
636 void (*nw_setgrent)(struct nwrap_backend *b);
637 struct group * (*nw_getgrent)(struct nwrap_backend *b);
638 int (*nw_getgrent_r)(struct nwrap_backend *b,
639 struct group *grdst, char *buf,
640 size_t buflen, struct group **grdstp);
641 void (*nw_endgrent)(struct nwrap_backend *b);
642 struct hostent *(*nw_gethostbyaddr)(struct nwrap_backend *b,
643 const void *addr,
644 socklen_t len, int type);
645 struct hostent *(*nw_gethostbyname)(struct nwrap_backend *b,
646 const char *name);
647 struct hostent *(*nw_gethostbyname2)(struct nwrap_backend *b,
648 const char *name, int af);
649 int (*nw_gethostbyname2_r)(struct nwrap_backend *b,
650 const char *name, int af,
651 struct hostent *hedst,
652 char *buf, size_t buflen,
653 struct hostent **hedstp);
656 /* Public prototypes */
658 bool nss_wrapper_enabled(void);
659 bool nss_wrapper_shadow_enabled(void);
660 bool nss_wrapper_hosts_enabled(void);
662 /* prototypes for files backend */
665 static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
666 const char *name);
667 static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
668 const char *name, struct passwd *pwdst,
669 char *buf, size_t buflen, struct passwd **pwdstp);
670 static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
671 uid_t uid);
672 static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
673 uid_t uid, struct passwd *pwdst,
674 char *buf, size_t buflen, struct passwd **pwdstp);
675 static void nwrap_files_setpwent(struct nwrap_backend *b);
676 static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b);
677 static int nwrap_files_getpwent_r(struct nwrap_backend *b,
678 struct passwd *pwdst, char *buf,
679 size_t buflen, struct passwd **pwdstp);
680 static void nwrap_files_endpwent(struct nwrap_backend *b);
681 static int nwrap_files_initgroups_dyn(struct nwrap_backend *b,
682 const char *user,
683 gid_t group,
684 long int *start,
685 long int *size,
686 gid_t **groups,
687 long int limit,
688 int *errnop);
689 static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
690 const char *name);
691 static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
692 const char *name, struct group *grdst,
693 char *buf, size_t buflen, struct group **grdstp);
694 static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
695 gid_t gid);
696 static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
697 gid_t gid, struct group *grdst,
698 char *buf, size_t buflen, struct group **grdstp);
699 static void nwrap_files_setgrent(struct nwrap_backend *b);
700 static struct group *nwrap_files_getgrent(struct nwrap_backend *b);
701 static int nwrap_files_getgrent_r(struct nwrap_backend *b,
702 struct group *grdst, char *buf,
703 size_t buflen, struct group **grdstp);
704 static void nwrap_files_endgrent(struct nwrap_backend *b);
705 static struct hostent *nwrap_files_gethostbyaddr(struct nwrap_backend *b,
706 const void *addr,
707 socklen_t len, int type);
708 static struct hostent *nwrap_files_gethostbyname(struct nwrap_backend *b,
709 const char *name);
710 #ifdef HAVE_GETHOSTBYNAME2
711 static struct hostent *nwrap_files_gethostbyname2(struct nwrap_backend *b,
712 const char *name, int af);
713 #endif /* HAVE_GETHOSTBYNAME2 */
714 static int nwrap_files_gethostbyname2_r(struct nwrap_backend *b,
715 const char *name, int af,
716 struct hostent *hedst,
717 char *buf, size_t buflen,
718 struct hostent **hedstp);
720 /* prototypes for module backend */
722 static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b);
723 static int nwrap_module_getpwent_r(struct nwrap_backend *b,
724 struct passwd *pwdst, char *buf,
725 size_t buflen, struct passwd **pwdstp);
726 static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
727 const char *name);
728 static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
729 const char *name, struct passwd *pwdst,
730 char *buf, size_t buflen, struct passwd **pwdstp);
731 static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
732 uid_t uid);
733 static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
734 uid_t uid, struct passwd *pwdst,
735 char *buf, size_t buflen, struct passwd **pwdstp);
736 static void nwrap_module_setpwent(struct nwrap_backend *b);
737 static void nwrap_module_endpwent(struct nwrap_backend *b);
738 static struct group *nwrap_module_getgrent(struct nwrap_backend *b);
739 static int nwrap_module_getgrent_r(struct nwrap_backend *b,
740 struct group *grdst, char *buf,
741 size_t buflen, struct group **grdstp);
742 static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
743 const char *name);
744 static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
745 const char *name, struct group *grdst,
746 char *buf, size_t buflen, struct group **grdstp);
747 static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
748 gid_t gid);
749 static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
750 gid_t gid, struct group *grdst,
751 char *buf, size_t buflen, struct group **grdstp);
752 static void nwrap_module_setgrent(struct nwrap_backend *b);
753 static void nwrap_module_endgrent(struct nwrap_backend *b);
754 static int nwrap_module_initgroups_dyn(struct nwrap_backend *b,
755 const char *user,
756 gid_t group,
757 long int *start,
758 long int *size,
759 gid_t **groups,
760 long int limit,
761 int *errnop);
762 static struct hostent *nwrap_module_gethostbyaddr(struct nwrap_backend *b,
763 const void *addr,
764 socklen_t len, int type);
765 static struct hostent *nwrap_module_gethostbyname(struct nwrap_backend *b,
766 const char *name);
767 static struct hostent *nwrap_module_gethostbyname2(struct nwrap_backend *b,
768 const char *name, int af);
769 static int nwrap_module_gethostbyname2_r(struct nwrap_backend *b,
770 const char *name, int af,
771 struct hostent *hedst,
772 char *buf, size_t buflen,
773 struct hostent **hedstp);
775 struct nwrap_ops nwrap_files_ops = {
776 .nw_getpwnam = nwrap_files_getpwnam,
777 .nw_getpwnam_r = nwrap_files_getpwnam_r,
778 .nw_getpwuid = nwrap_files_getpwuid,
779 .nw_getpwuid_r = nwrap_files_getpwuid_r,
780 .nw_setpwent = nwrap_files_setpwent,
781 .nw_getpwent = nwrap_files_getpwent,
782 .nw_getpwent_r = nwrap_files_getpwent_r,
783 .nw_endpwent = nwrap_files_endpwent,
784 .nw_initgroups_dyn = nwrap_files_initgroups_dyn,
785 .nw_getgrnam = nwrap_files_getgrnam,
786 .nw_getgrnam_r = nwrap_files_getgrnam_r,
787 .nw_getgrgid = nwrap_files_getgrgid,
788 .nw_getgrgid_r = nwrap_files_getgrgid_r,
789 .nw_setgrent = nwrap_files_setgrent,
790 .nw_getgrent = nwrap_files_getgrent,
791 .nw_getgrent_r = nwrap_files_getgrent_r,
792 .nw_endgrent = nwrap_files_endgrent,
793 .nw_gethostbyaddr = nwrap_files_gethostbyaddr,
794 .nw_gethostbyname = nwrap_files_gethostbyname,
795 #ifdef HAVE_GETHOSTBYNAME2
796 .nw_gethostbyname2 = nwrap_files_gethostbyname2,
797 #endif /* HAVE_GETHOSTBYNAME2 */
798 .nw_gethostbyname2_r = nwrap_files_gethostbyname2_r,
801 struct nwrap_ops nwrap_module_ops = {
802 .nw_getpwnam = nwrap_module_getpwnam,
803 .nw_getpwnam_r = nwrap_module_getpwnam_r,
804 .nw_getpwuid = nwrap_module_getpwuid,
805 .nw_getpwuid_r = nwrap_module_getpwuid_r,
806 .nw_setpwent = nwrap_module_setpwent,
807 .nw_getpwent = nwrap_module_getpwent,
808 .nw_getpwent_r = nwrap_module_getpwent_r,
809 .nw_endpwent = nwrap_module_endpwent,
810 .nw_initgroups_dyn = nwrap_module_initgroups_dyn,
811 .nw_getgrnam = nwrap_module_getgrnam,
812 .nw_getgrnam_r = nwrap_module_getgrnam_r,
813 .nw_getgrgid = nwrap_module_getgrgid,
814 .nw_getgrgid_r = nwrap_module_getgrgid_r,
815 .nw_setgrent = nwrap_module_setgrent,
816 .nw_getgrent = nwrap_module_getgrent,
817 .nw_getgrent_r = nwrap_module_getgrent_r,
818 .nw_endgrent = nwrap_module_endgrent,
819 .nw_gethostbyaddr = nwrap_module_gethostbyaddr,
820 .nw_gethostbyname = nwrap_module_gethostbyname,
821 .nw_gethostbyname2 = nwrap_module_gethostbyname2,
822 .nw_gethostbyname2_r = nwrap_module_gethostbyname2_r,
825 struct nwrap_libc {
826 void *handle;
827 void *nsl_handle;
828 void *sock_handle;
829 struct nwrap_libc_symbols symbols;
832 struct nwrap_main {
833 size_t num_backends;
834 struct nwrap_backend *backends;
835 struct nwrap_libc *libc;
838 static struct nwrap_main *nwrap_main_global;
839 static struct nwrap_main __nwrap_main_global;
842 * PROTOTYPES
844 static int nwrap_convert_he_ai(const struct hostent *he,
845 unsigned short port,
846 const struct addrinfo *hints,
847 struct addrinfo **pai,
848 bool skip_canonname);
850 #ifdef HAVE_GETGROUPLIST
851 static int nwrap_getgrouplist(const char *user,
852 gid_t group,
853 long int *size,
854 gid_t **groupsp,
855 long int limit);
856 #endif
859 * VECTORS
862 #define DEFAULT_VECTOR_CAPACITY 16
864 struct nwrap_vector {
865 void **items;
866 size_t count;
867 size_t capacity;
870 /* Macro returns pointer to first element of vector->items array.
872 * nwrap_vector is used as a memory backend which take care of
873 * memory allocations and other stuff like memory growing.
874 * nwrap_vectors should not be considered as some abstract structures.
875 * On this level, vectors are more handy than direct realloc/malloc
876 * calls.
878 * nwrap_vector->items is array inside nwrap_vector which can be
879 * directly pointed by libc structure assembled by cwrap itself.
881 * EXAMPLE:
883 * 1) struct hostent contains char **h_addr_list element.
884 * 2) nwrap_vector holds array of pointers to addresses.
885 * It's easier to use vector to store results of
886 * file parsing etc.
888 * Now, pretend that cwrap assembled struct hostent and
889 * we need to set h_addr_list to point to nwrap_vector.
890 * Idea behind is to shield users from internal nwrap_vector
891 * implementation.
892 * (Yes, not fully - array terminated by NULL is needed because
893 * it's result expected by libc function caller.)
896 * CODE EXAMPLE:
898 * struct hostent he;
899 * struct nwrap_vector *vector = malloc(sizeof(struct nwrap_vector));
900 * ... don't care about failed allocation now ...
902 * ... fill nwrap vector ...
904 * struct hostent he;
905 * he.h_addr_list = nwrap_vector_head(vector);
908 #define nwrap_vector_head(vect) ((void *)((vect)->items))
910 #define nwrap_vector_foreach(item, vect, iter) \
911 for (iter = 0, (item) = (vect).items == NULL ? NULL : (vect).items[0]; \
912 item != NULL; \
913 (item) = (vect).items[++iter])
915 #define nwrap_vector_is_initialized(vector) ((vector)->items != NULL)
917 static inline bool nwrap_vector_init(struct nwrap_vector *const vector)
919 if (vector == NULL) {
920 return false;
923 /* count is initialized by ZERO_STRUCTP */
924 ZERO_STRUCTP(vector);
925 vector->items = malloc(sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1));
926 if (vector->items == NULL) {
927 return false;
929 vector->capacity = DEFAULT_VECTOR_CAPACITY;
930 memset(vector->items, '\0', sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1));
932 return true;
935 static bool nwrap_vector_add_item(struct nwrap_vector *vector, void *const item)
937 assert (vector != NULL);
939 if (vector->items == NULL) {
940 nwrap_vector_init(vector);
943 if (vector->count == vector->capacity) {
944 /* Items array _MUST_ be NULL terminated because it's passed
945 * as result to caller which expect NULL terminated array from libc.
947 void **items = realloc(vector->items, sizeof(void *) * ((vector->capacity * 2) + 1));
948 if (items == NULL) {
949 return false;
951 vector->items = items;
953 /* Don't count ending NULL to capacity */
954 vector->capacity *= 2;
957 vector->items[vector->count] = item;
959 vector->count += 1;
960 vector->items[vector->count] = NULL;
962 return true;
965 static bool nwrap_vector_merge(struct nwrap_vector *dst,
966 struct nwrap_vector *src)
968 void **dst_items = NULL;
969 size_t count;
971 if (src->count == 0) {
972 return true;
975 count = dst->count + src->count;
977 /* We don't need reallocation if we have enough capacity. */
978 if (src->count > (dst->capacity - dst->count)) {
979 dst_items = (void **)realloc(dst->items, (count + 1) * sizeof(void *));
980 if (dst_items == NULL) {
981 return false;
983 dst->items = dst_items;
984 dst->capacity = count;
987 memcpy((void *)(((long *)dst->items) + dst->count),
988 src->items,
989 src->count * sizeof(void *));
990 dst->count = count;
992 return true;
995 struct nwrap_cache {
996 const char *path;
997 int fd;
998 FILE *fp;
999 struct stat st;
1000 void *private_data;
1002 struct nwrap_vector lines;
1004 bool (*parse_line)(struct nwrap_cache *, char *line);
1005 void (*unload)(struct nwrap_cache *);
1008 /* passwd */
1009 struct nwrap_pw {
1010 struct nwrap_cache *cache;
1012 struct passwd *list;
1013 int num;
1014 int idx;
1017 struct nwrap_cache __nwrap_cache_pw;
1018 struct nwrap_pw nwrap_pw_global;
1020 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line);
1021 static void nwrap_pw_unload(struct nwrap_cache *nwrap);
1023 /* shadow */
1024 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
1025 struct nwrap_sp {
1026 struct nwrap_cache *cache;
1028 struct spwd *list;
1029 int num;
1030 int idx;
1033 struct nwrap_cache __nwrap_cache_sp;
1034 struct nwrap_sp nwrap_sp_global;
1036 static bool nwrap_sp_parse_line(struct nwrap_cache *nwrap, char *line);
1037 static void nwrap_sp_unload(struct nwrap_cache *nwrap);
1038 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
1040 /* group */
1041 struct nwrap_gr {
1042 struct nwrap_cache *cache;
1044 struct group *list;
1045 int num;
1046 int idx;
1049 struct nwrap_cache __nwrap_cache_gr;
1050 struct nwrap_gr nwrap_gr_global;
1052 /* hosts */
1053 static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line);
1054 static void nwrap_he_unload(struct nwrap_cache *nwrap);
1056 struct nwrap_addrdata {
1057 unsigned char host_addr[16]; /* IPv4 or IPv6 address */
1060 static size_t max_hostents = 100;
1062 struct nwrap_entdata {
1063 struct nwrap_addrdata addr;
1064 struct hostent ht;
1066 struct nwrap_vector nwrap_addrdata;
1068 ssize_t aliases_count;
1071 struct nwrap_entlist {
1072 struct nwrap_entlist *next;
1073 struct nwrap_entdata *ed;
1076 struct nwrap_he {
1077 struct nwrap_cache *cache;
1079 struct nwrap_vector entries;
1080 struct nwrap_vector lists;
1082 int num;
1083 int idx;
1086 static struct nwrap_cache __nwrap_cache_he;
1087 static struct nwrap_he nwrap_he_global;
1090 /*********************************************************
1091 * NWRAP PROTOTYPES
1092 *********************************************************/
1094 static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line);
1095 static void nwrap_gr_unload(struct nwrap_cache *nwrap);
1096 #if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT)
1097 /* xlC and other oldschool compilers support (only) this */
1098 #pragma init (nwrap_constructor)
1099 #endif
1100 void nwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
1101 #if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
1102 #pragma fini (nwrap_destructor)
1103 #endif
1104 void nwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
1106 /*********************************************************
1107 * NWRAP LIBC LOADER FUNCTIONS
1108 *********************************************************/
1110 enum nwrap_lib {
1111 NWRAP_LIBC,
1112 NWRAP_LIBNSL,
1113 NWRAP_LIBSOCKET,
1116 static const char *nwrap_str_lib(enum nwrap_lib lib)
1118 switch (lib) {
1119 case NWRAP_LIBC:
1120 return "libc";
1121 case NWRAP_LIBNSL:
1122 return "libnsl";
1123 case NWRAP_LIBSOCKET:
1124 return "libsocket";
1127 /* Compiler would warn us about unhandled enum value if we get here */
1128 return "unknown";
1131 static void *nwrap_load_lib_handle(enum nwrap_lib lib)
1133 int flags = RTLD_LAZY;
1134 void *handle = NULL;
1135 int i;
1137 #ifdef RTLD_DEEPBIND
1138 const char *env_preload = getenv("LD_PRELOAD");
1139 const char *env_deepbind = getenv("NSS_WRAPPER_DISABLE_DEEPBIND");
1140 bool enable_deepbind = true;
1142 /* Don't do a deepbind if we run with libasan */
1143 if (env_preload != NULL && strlen(env_preload) < 1024) {
1144 const char *p = strstr(env_preload, "libasan.so");
1145 if (p != NULL) {
1146 enable_deepbind = false;
1150 if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
1151 enable_deepbind = false;
1154 if (enable_deepbind) {
1155 flags |= RTLD_DEEPBIND;
1157 #endif
1159 switch (lib) {
1160 case NWRAP_LIBNSL:
1161 #ifdef HAVE_LIBNSL
1162 handle = nwrap_main_global->libc->nsl_handle;
1163 #ifdef LIBNSL_SO
1164 if (handle == NULL) {
1165 handle = dlopen(LIBNSL_SO, flags);
1167 nwrap_main_global->libc->nsl_handle = handle;
1169 #endif
1170 if (handle == NULL) {
1171 for (i = 10; i >= 0; i--) {
1172 char soname[256] = {0};
1174 snprintf(soname, sizeof(soname), "libnsl.so.%d", i);
1175 handle = dlopen(soname, flags);
1176 if (handle != NULL) {
1177 break;
1181 nwrap_main_global->libc->nsl_handle = handle;
1183 break;
1184 #endif
1185 /* FALL TROUGH */
1186 case NWRAP_LIBSOCKET:
1187 #ifdef HAVE_LIBSOCKET
1188 handle = nwrap_main_global->libc->sock_handle;
1189 if (handle == NULL) {
1190 for (i = 10; i >= 0; i--) {
1191 char soname[256] = {0};
1193 snprintf(soname, sizeof(soname), "libsocket.so.%d", i);
1194 handle = dlopen(soname, flags);
1195 if (handle != NULL) {
1196 break;
1200 nwrap_main_global->libc->sock_handle = handle;
1202 break;
1203 #endif
1204 /* FALL TROUGH */
1205 case NWRAP_LIBC:
1206 handle = nwrap_main_global->libc->handle;
1207 #ifdef LIBC_SO
1208 if (handle == NULL) {
1209 handle = dlopen(LIBC_SO, flags);
1211 nwrap_main_global->libc->handle = handle;
1213 #endif
1214 if (handle == NULL) {
1215 for (i = 10; i >= 0; i--) {
1216 char soname[256] = {0};
1218 snprintf(soname, sizeof(soname), "libc.so.%d", i);
1219 handle = dlopen(soname, flags);
1220 if (handle != NULL) {
1221 break;
1225 nwrap_main_global->libc->handle = handle;
1227 break;
1230 if (handle == NULL) {
1231 #ifdef RTLD_NEXT
1232 handle = nwrap_main_global->libc->handle
1233 = nwrap_main_global->libc->sock_handle
1234 = nwrap_main_global->libc->nsl_handle
1235 = RTLD_NEXT;
1236 #else
1237 NWRAP_LOG(NWRAP_LOG_ERROR,
1238 "Failed to dlopen library: %s\n",
1239 dlerror());
1240 exit(-1);
1241 #endif
1244 return handle;
1247 static void *_nwrap_bind_symbol(enum nwrap_lib lib, const char *fn_name)
1249 void *handle;
1250 void *func;
1252 nwrap_init();
1254 handle = nwrap_load_lib_handle(lib);
1256 func = dlsym(handle, fn_name);
1257 if (func == NULL) {
1258 NWRAP_LOG(NWRAP_LOG_ERROR,
1259 "Failed to find %s: %s\n",
1260 fn_name, dlerror());
1261 exit(-1);
1264 NWRAP_LOG(NWRAP_LOG_TRACE,
1265 "Loaded %s from %s",
1266 fn_name, nwrap_str_lib(lib));
1267 return func;
1270 #define nwrap_mutex_lock(m) _nwrap_mutex_lock(m, #m, __func__, __LINE__)
1271 static void _nwrap_mutex_lock(pthread_mutex_t *mutex, const char *name, const char *caller, unsigned line)
1273 int ret;
1275 ret = pthread_mutex_lock(mutex);
1276 if (ret != 0) {
1277 NWRAP_LOG(NWRAP_LOG_ERROR, "PID(%d):PPID(%d): %s(%u): Couldn't lock pthread mutex(%s) - %s",
1278 getpid(), getppid(), caller, line, name, strerror(ret));
1279 abort();
1283 #define nwrap_mutex_unlock(m) _nwrap_mutex_unlock(m, #m, __func__, __LINE__)
1284 static void _nwrap_mutex_unlock(pthread_mutex_t *mutex, const char *name, const char *caller, unsigned line)
1286 int ret;
1288 ret = pthread_mutex_unlock(mutex);
1289 if (ret != 0) {
1290 NWRAP_LOG(NWRAP_LOG_ERROR, "PID(%d):PPID(%d): %s(%u): Couldn't unlock pthread mutex(%s) - %s",
1291 getpid(), getppid(), caller, line, name, strerror(ret));
1292 abort();
1296 #define nwrap_bind_symbol_libc(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_LIBC, #sym_name); \
1302 #define nwrap_bind_symbol_libc_posix(sym_name) \
1303 if (nwrap_main_global->libc->symbols._libc_##sym_name.obj == NULL) { \
1304 nwrap_main_global->libc->symbols._libc_##sym_name.obj = \
1305 _nwrap_bind_symbol(NWRAP_LIBC, "__posix_" #sym_name); \
1308 #define nwrap_bind_symbol_libnsl(sym_name) \
1309 if (nwrap_main_global->libc->symbols._libc_##sym_name.obj == NULL) { \
1310 nwrap_main_global->libc->symbols._libc_##sym_name.obj = \
1311 _nwrap_bind_symbol(NWRAP_LIBNSL, #sym_name); \
1314 #define nwrap_bind_symbol_libsocket(sym_name) \
1315 if (nwrap_main_global->libc->symbols._libc_##sym_name.obj == NULL) { \
1316 nwrap_main_global->libc->symbols._libc_##sym_name.obj = \
1317 _nwrap_bind_symbol(NWRAP_LIBSOCKET, #sym_name); \
1320 static void nwrap_bind_symbol_all(void);
1322 /* INTERNAL HELPER FUNCTIONS */
1323 static void nwrap_lines_unload(struct nwrap_cache *const nwrap)
1325 size_t p;
1326 void *item;
1327 nwrap_vector_foreach(item, nwrap->lines, p) {
1328 /* Maybe some vectors were merged ... */
1329 SAFE_FREE(item);
1331 SAFE_FREE(nwrap->lines.items);
1332 ZERO_STRUCTP(&nwrap->lines);
1336 * IMPORTANT
1338 * Functions expeciall from libc need to be loaded individually, you can't load
1339 * all at once or gdb will segfault at startup. The same applies to valgrind and
1340 * has probably something todo with with the linker.
1341 * So we need load each function at the point it is called the first time.
1343 static struct passwd *libc_getpwnam(const char *name)
1345 nwrap_bind_symbol_all();
1347 return nwrap_main_global->libc->symbols._libc_getpwnam.f(name);
1350 #ifdef HAVE_GETPWNAM_R
1351 static int libc_getpwnam_r(const char *name,
1352 struct passwd *pwd,
1353 char *buf,
1354 size_t buflen,
1355 struct passwd **result)
1357 nwrap_bind_symbol_all();
1359 return nwrap_main_global->libc->symbols._libc_getpwnam_r.f(name,
1360 pwd,
1361 buf,
1362 buflen,
1363 result);
1365 #endif
1367 static struct passwd *libc_getpwuid(uid_t uid)
1369 nwrap_bind_symbol_all();
1371 return nwrap_main_global->libc->symbols._libc_getpwuid.f(uid);
1374 #ifdef HAVE_GETPWUID_R
1375 static int libc_getpwuid_r(uid_t uid,
1376 struct passwd *pwd,
1377 char *buf,
1378 size_t buflen,
1379 struct passwd **result)
1381 nwrap_bind_symbol_all();
1383 return nwrap_main_global->libc->symbols._libc_getpwuid_r.f(uid,
1384 pwd,
1385 buf,
1386 buflen,
1387 result);
1389 #endif
1391 static inline void str_tolower(char *dst, char *src)
1393 register char *src_tmp = src;
1394 register char *dst_tmp = dst;
1396 while (*src_tmp != '\0') {
1397 *dst_tmp = tolower(*src_tmp);
1398 ++src_tmp;
1399 ++dst_tmp;
1403 static bool str_tolower_copy(char **dst_name, const char *const src_name)
1405 char *h_name_lower;
1407 if ((dst_name == NULL) || (src_name == NULL)) {
1408 return false;
1411 h_name_lower = strdup(src_name);
1412 if (h_name_lower == NULL) {
1413 NWRAP_LOG(NWRAP_LOG_DEBUG, "Out of memory while strdup");
1414 return false;
1417 str_tolower(h_name_lower, h_name_lower);
1418 *dst_name = h_name_lower;
1419 return true;
1422 static void libc_setpwent(void)
1424 nwrap_bind_symbol_all();
1426 nwrap_main_global->libc->symbols._libc_setpwent.f();
1429 static struct passwd *libc_getpwent(void)
1431 nwrap_bind_symbol_all();
1433 return nwrap_main_global->libc->symbols._libc_getpwent.f();
1436 #ifdef HAVE_GETPWENT_R
1437 # ifdef HAVE_SOLARIS_GETPWENT_R
1438 static struct passwd *libc_getpwent_r(struct passwd *pwdst,
1439 char *buf,
1440 int buflen)
1442 nwrap_bind_symbol_all();
1444 return nwrap_main_global->libc->symbols._libc_getpwent_r.f(pwdst,
1445 buf,
1446 buflen);
1448 # else /* HAVE_SOLARIS_GETPWENT_R */
1449 static int libc_getpwent_r(struct passwd *pwdst,
1450 char *buf,
1451 size_t buflen,
1452 struct passwd **pwdstp)
1454 nwrap_bind_symbol_all();
1456 return nwrap_main_global->libc->symbols._libc_getpwent_r.f(pwdst,
1457 buf,
1458 buflen,
1459 pwdstp);
1461 # endif /* HAVE_SOLARIS_GETPWENT_R */
1462 #endif /* HAVE_GETPWENT_R */
1464 static void libc_endpwent(void)
1466 nwrap_bind_symbol_all();
1468 nwrap_main_global->libc->symbols._libc_endpwent.f();
1471 static int libc_initgroups(const char *user, gid_t gid)
1473 nwrap_bind_symbol_all();
1475 return nwrap_main_global->libc->symbols._libc_initgroups.f(user, gid);
1478 static struct group *libc_getgrnam(const char *name)
1480 nwrap_bind_symbol_all();
1482 return nwrap_main_global->libc->symbols._libc_getgrnam.f(name);
1485 #ifdef HAVE_GETGRNAM_R
1486 static int libc_getgrnam_r(const char *name,
1487 struct group *grp,
1488 char *buf,
1489 size_t buflen,
1490 struct group **result)
1492 nwrap_bind_symbol_all();
1494 return nwrap_main_global->libc->symbols._libc_getgrnam_r.f(name,
1495 grp,
1496 buf,
1497 buflen,
1498 result);
1500 #endif
1502 static struct group *libc_getgrgid(gid_t gid)
1504 nwrap_bind_symbol_all();
1506 return nwrap_main_global->libc->symbols._libc_getgrgid.f(gid);
1509 #ifdef HAVE_GETGRGID_R
1510 static int libc_getgrgid_r(gid_t gid,
1511 struct group *grp,
1512 char *buf,
1513 size_t buflen,
1514 struct group **result)
1516 nwrap_bind_symbol_all();
1518 return nwrap_main_global->libc->symbols._libc_getgrgid_r.f(gid,
1519 grp,
1520 buf,
1521 buflen,
1522 result);
1524 #endif
1526 static void libc_setgrent(void)
1528 nwrap_bind_symbol_all();
1530 nwrap_main_global->libc->symbols._libc_setgrent.f();
1533 static struct group *libc_getgrent(void)
1535 nwrap_bind_symbol_all();
1537 return nwrap_main_global->libc->symbols._libc_getgrent.f();
1540 #ifdef HAVE_GETGRENT_R
1541 # ifdef HAVE_SOLARIS_GETGRENT_R
1542 static struct group *libc_getgrent_r(struct group *group,
1543 char *buf,
1544 size_t buflen)
1546 nwrap_bind_symbol_all();
1548 return nwrap_main_global->libc->symbols._libc_getgrent_r.f(group,
1549 buf,
1550 buflen);
1552 # else /* HAVE_SOLARIS_GETGRENT_R */
1553 static int libc_getgrent_r(struct group *group,
1554 char *buf,
1555 size_t buflen,
1556 struct group **result)
1558 nwrap_bind_symbol_all();
1560 return nwrap_main_global->libc->symbols._libc_getgrent_r.f(group,
1561 buf,
1562 buflen,
1563 result);
1565 # endif /* HAVE_SOLARIS_GETGRENT_R */
1566 #endif /* HAVE_GETGRENT_R */
1568 static void libc_endgrent(void)
1570 nwrap_bind_symbol_all();
1572 nwrap_main_global->libc->symbols._libc_endgrent.f();
1575 #ifdef HAVE_GETGROUPLIST
1576 static int libc_getgrouplist(const char *user,
1577 gid_t group,
1578 gid_t *groups,
1579 int *ngroups)
1581 nwrap_bind_symbol_all();
1583 return nwrap_main_global->libc->symbols._libc_getgrouplist.f(user,
1584 group,
1585 groups,
1586 ngroups);
1588 #endif
1590 static void libc_sethostent(int stayopen)
1592 nwrap_bind_symbol_all();
1594 nwrap_main_global->libc->symbols._libc_sethostent.f(stayopen);
1597 static struct hostent *libc_gethostent(void)
1599 nwrap_bind_symbol_all();
1601 return nwrap_main_global->libc->symbols._libc_gethostent.f();
1604 static void libc_endhostent(void)
1606 nwrap_bind_symbol_all();
1608 nwrap_main_global->libc->symbols._libc_endhostent.f();
1611 static struct hostent *libc_gethostbyname(const char *name)
1613 nwrap_bind_symbol_all();
1615 return nwrap_main_global->libc->symbols._libc_gethostbyname.f(name);
1618 #ifdef HAVE_GETHOSTBYNAME2 /* GNU extension */
1619 static struct hostent *libc_gethostbyname2(const char *name, int af)
1621 nwrap_bind_symbol_all();
1623 return nwrap_main_global->libc->symbols._libc_gethostbyname2.f(name, af);
1625 #endif
1627 #ifdef HAVE_GETHOSTBYNAME2_R /* GNU extension */
1628 static int libc_gethostbyname2_r(const char *name,
1629 int af,
1630 struct hostent *ret,
1631 char *buf,
1632 size_t buflen,
1633 struct hostent **result,
1634 int *h_errnop)
1636 nwrap_bind_symbol_all();
1638 return nwrap_main_global->libc->symbols._libc_gethostbyname2_r.f(name,
1640 ret,
1641 buf,
1642 buflen,
1643 result,
1644 h_errnop);
1646 #endif
1648 static struct hostent *libc_gethostbyaddr(const void *addr,
1649 socklen_t len,
1650 int type)
1652 nwrap_bind_symbol_all();
1654 return nwrap_main_global->libc->symbols._libc_gethostbyaddr.f(addr,
1655 len,
1656 type);
1659 static int libc_gethostname(char *name, size_t len)
1661 nwrap_bind_symbol_all();
1663 return nwrap_main_global->libc->symbols._libc_gethostname.f(name, len);
1666 #ifdef HAVE_GETHOSTBYNAME_R
1667 static int libc_gethostbyname_r(const char *name,
1668 struct hostent *ret,
1669 char *buf,
1670 size_t buflen,
1671 struct hostent **result,
1672 int *h_errnop)
1674 nwrap_bind_symbol_all();
1676 return nwrap_main_global->libc->symbols._libc_gethostbyname_r.f(name,
1677 ret,
1678 buf,
1679 buflen,
1680 result,
1681 h_errnop);
1683 #endif
1685 #ifdef HAVE_GETHOSTBYADDR_R
1686 static int libc_gethostbyaddr_r(const void *addr,
1687 socklen_t len,
1688 int type,
1689 struct hostent *ret,
1690 char *buf,
1691 size_t buflen,
1692 struct hostent **result,
1693 int *h_errnop)
1695 nwrap_bind_symbol_all();
1697 return nwrap_main_global->libc->symbols._libc_gethostbyaddr_r.f(addr,
1698 len,
1699 type,
1700 ret,
1701 buf,
1702 buflen,
1703 result,
1704 h_errnop);
1706 #endif
1708 static int libc_getaddrinfo(const char *node,
1709 const char *service,
1710 const struct addrinfo *hints,
1711 struct addrinfo **res)
1713 nwrap_bind_symbol_all();
1715 return nwrap_main_global->libc->symbols._libc_getaddrinfo.f(node,
1716 service,
1717 hints,
1718 res);
1721 static int libc_getnameinfo(const struct sockaddr *sa,
1722 socklen_t salen,
1723 char *host,
1724 size_t hostlen,
1725 char *serv,
1726 size_t servlen,
1727 int flags)
1729 nwrap_bind_symbol_all();
1731 return nwrap_main_global->libc->symbols._libc_getnameinfo.f(sa,
1732 salen,
1733 host,
1734 hostlen,
1735 serv,
1736 servlen,
1737 flags);
1740 static void __nwrap_bind_symbol_all_once(void)
1742 nwrap_bind_symbol_libc(getpwnam);
1743 #ifdef HAVE_GETPWNAM_R
1744 # ifdef HAVE___POSIX_GETPWNAM_R
1745 nwrap_bind_symbol_libc_posix(getpwnam_r);
1746 # else
1747 nwrap_bind_symbol_libc(getpwnam_r);
1748 # endif
1749 #endif
1750 nwrap_bind_symbol_libc(getpwuid);
1751 #ifdef HAVE_GETPWUID_R
1752 # ifdef HAVE___POSIX_GETPWUID_R
1753 nwrap_bind_symbol_libc_posix(getpwuid_r);
1754 # else
1755 nwrap_bind_symbol_libc(getpwuid_r);
1756 # endif
1757 #endif
1758 nwrap_bind_symbol_libc(setpwent);
1759 nwrap_bind_symbol_libc(getpwent);
1760 #ifdef HAVE_GETPWENT_R
1761 nwrap_bind_symbol_libc(getpwent_r);
1762 #endif
1763 nwrap_bind_symbol_libc(endpwent);
1764 nwrap_bind_symbol_libc(initgroups);
1765 nwrap_bind_symbol_libc(getgrnam);
1766 #ifdef HAVE_GETGRNAM_R
1767 # ifdef HAVE___POSIX_GETGRNAM_R
1768 nwrap_bind_symbol_libc_posix(getgrnam_r);
1769 # else
1770 nwrap_bind_symbol_libc(getgrnam_r);
1771 # endif
1772 #endif
1773 nwrap_bind_symbol_libc(getgrgid);
1774 #ifdef HAVE_GETGRGID_R
1775 # ifdef HAVE___POSIX_GETGRGID_R
1776 nwrap_bind_symbol_libc_posix(getgrgid_r);
1777 # else
1778 nwrap_bind_symbol_libc(getgrgid_r);
1779 # endif
1780 #endif
1781 nwrap_bind_symbol_libc(setgrent);
1782 nwrap_bind_symbol_libc(getgrent);
1783 nwrap_bind_symbol_libc(getgrent_r);
1784 nwrap_bind_symbol_libc(endgrent);
1785 nwrap_bind_symbol_libc(getgrouplist);
1786 nwrap_bind_symbol_libnsl(sethostent);
1787 nwrap_bind_symbol_libnsl(gethostent);
1788 nwrap_bind_symbol_libnsl(endhostent);
1789 nwrap_bind_symbol_libnsl(gethostbyname);
1790 #ifdef HAVE_GETHOSTBYNAME2 /* GNU extension */
1791 nwrap_bind_symbol_libnsl(gethostbyname2);
1792 #endif
1793 #ifdef HAVE_GETHOSTBYNAME2_R /* GNU extension */
1794 nwrap_bind_symbol_libnsl(gethostbyname2_r);
1795 #endif
1796 nwrap_bind_symbol_libnsl(gethostbyaddr);
1797 nwrap_bind_symbol_libnsl(gethostname);
1798 #ifdef HAVE_GETHOSTBYNAME_R
1799 nwrap_bind_symbol_libnsl(gethostbyname_r);
1800 #endif
1801 #ifdef HAVE_GETHOSTBYADDR_R
1802 nwrap_bind_symbol_libnsl(gethostbyaddr_r);
1803 #endif
1804 nwrap_bind_symbol_libsocket(getaddrinfo);
1805 nwrap_bind_symbol_libsocket(getnameinfo);
1808 static void nwrap_bind_symbol_all(void)
1810 static pthread_once_t all_symbol_binding_once = PTHREAD_ONCE_INIT;
1812 pthread_once(&all_symbol_binding_once, __nwrap_bind_symbol_all_once);
1815 /*********************************************************
1816 * NWRAP NSS MODULE LOADER FUNCTIONS
1817 *********************************************************/
1819 static void *_nwrap_bind_nss_module_symbol(struct nwrap_backend *b,
1820 const char *fn_name)
1822 void *res = NULL;
1823 char *s = NULL;
1824 int rc;
1826 if (b->so_handle == NULL) {
1827 NWRAP_LOG(NWRAP_LOG_ERROR, "No handle");
1828 return NULL;
1831 rc = asprintf(&s, "_nss_%s_%s", b->name, fn_name);
1832 if (rc == -1) {
1833 NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
1834 return NULL;
1837 res = dlsym(b->so_handle, s);
1838 if (res == NULL) {
1839 NWRAP_LOG(NWRAP_LOG_WARN,
1840 "Cannot find function %s in %s",
1841 s, b->so_path);
1843 SAFE_FREE(s);
1844 return res;
1847 #define nwrap_nss_module_bind_symbol(sym_name) \
1848 if (symbols->_nss_##sym_name.obj == NULL) { \
1849 symbols->_nss_##sym_name.obj = \
1850 _nwrap_bind_nss_module_symbol(b, #sym_name); \
1853 #define nwrap_nss_module_bind_symbol2(sym_name, alt_name) \
1854 if (symbols->_nss_##sym_name.obj == NULL) { \
1855 symbols->_nss_##sym_name.obj = \
1856 _nwrap_bind_nss_module_symbol(b, #alt_name); \
1859 static struct nwrap_nss_module_symbols *
1860 nwrap_bind_nss_module_symbols(struct nwrap_backend *b)
1862 struct nwrap_nss_module_symbols *symbols;
1864 if (!b->so_handle) {
1865 return NULL;
1868 symbols = calloc(1, sizeof(struct nwrap_nss_module_symbols));
1869 if (symbols == NULL) {
1870 return NULL;
1873 nwrap_nss_module_bind_symbol(getpwnam_r);
1874 nwrap_nss_module_bind_symbol(getpwuid_r);
1875 nwrap_nss_module_bind_symbol(setpwent);
1876 nwrap_nss_module_bind_symbol(getpwent_r);
1877 nwrap_nss_module_bind_symbol(endpwent);
1878 nwrap_nss_module_bind_symbol(initgroups_dyn);
1879 nwrap_nss_module_bind_symbol(getgrnam_r);
1880 nwrap_nss_module_bind_symbol(getgrgid_r);
1881 nwrap_nss_module_bind_symbol(setgrent);
1882 nwrap_nss_module_bind_symbol(getgrent_r);
1883 nwrap_nss_module_bind_symbol(endgrent);
1884 nwrap_nss_module_bind_symbol(gethostbyaddr_r);
1885 nwrap_nss_module_bind_symbol(gethostbyname2_r);
1887 return symbols;
1890 static void *nwrap_load_module(const char *so_path)
1892 void *h;
1894 if (!so_path || !strlen(so_path)) {
1895 return NULL;
1898 h = dlopen(so_path, RTLD_LAZY);
1899 if (!h) {
1900 NWRAP_LOG(NWRAP_LOG_ERROR,
1901 "Cannot open shared library %s",
1902 so_path);
1903 return NULL;
1906 return h;
1909 static bool nwrap_module_init(const char *name,
1910 struct nwrap_ops *ops,
1911 const char *so_path,
1912 size_t *num_backends,
1913 struct nwrap_backend **backends)
1915 struct nwrap_backend *b = NULL;
1916 size_t n = *num_backends + 1;
1918 b = realloc(*backends, sizeof(struct nwrap_backend) * n);
1919 if (b == NULL) {
1920 NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
1921 return false;
1923 *backends = b;
1925 b = &((*backends)[*num_backends]);
1927 *b = (struct nwrap_backend) {
1928 .name = name,
1929 .ops = ops,
1930 .so_path = so_path,
1933 if (so_path != NULL) {
1934 b->so_handle = nwrap_load_module(so_path);
1935 b->symbols = nwrap_bind_nss_module_symbols(b);
1936 if (b->symbols == NULL) {
1937 return false;
1941 *num_backends = n;
1943 return true;
1946 static void nwrap_libc_init(struct nwrap_main *r)
1948 r->libc = calloc(1, sizeof(struct nwrap_libc));
1949 if (r->libc == NULL) {
1950 printf("Failed to allocate memory for libc");
1951 exit(-1);
1955 static void nwrap_backend_init(struct nwrap_main *r)
1957 const char *module_so_path = getenv("NSS_WRAPPER_MODULE_SO_PATH");
1958 const char *module_fn_name = getenv("NSS_WRAPPER_MODULE_FN_PREFIX");
1960 r->num_backends = 0;
1961 r->backends = NULL;
1963 if (!nwrap_module_init("files", &nwrap_files_ops, NULL,
1964 &r->num_backends,
1965 &r->backends)) {
1966 NWRAP_LOG(NWRAP_LOG_ERROR,
1967 "Failed to initialize 'files' backend");
1968 return;
1971 if (module_so_path != NULL &&
1972 module_so_path[0] != '\0' &&
1973 module_fn_name != NULL &&
1974 module_fn_name[0] != '\0') {
1975 if (!nwrap_module_init(module_fn_name,
1976 &nwrap_module_ops,
1977 module_so_path,
1978 &r->num_backends,
1979 &r->backends)) {
1980 NWRAP_LOG(NWRAP_LOG_ERROR,
1981 "Failed to initialize '%s' backend",
1982 module_fn_name);
1983 return;
1988 static int _nss_wrapper_init_mutex(pthread_mutex_t *m, const char *name)
1990 pthread_mutexattr_t ma;
1991 bool need_destroy = false;
1992 int ret = 0;
1994 #define __CHECK(cmd) do { \
1995 ret = cmd; \
1996 if (ret != 0) { \
1997 NWRAP_LOG(NWRAP_LOG_ERROR, \
1998 "%s: %s - failed %d", \
1999 name, #cmd, ret); \
2000 goto done; \
2002 } while(0)
2004 *m = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
2005 __CHECK(pthread_mutexattr_init(&ma));
2006 need_destroy = true;
2007 __CHECK(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK));
2008 __CHECK(pthread_mutex_init(m, &ma));
2009 done:
2010 if (need_destroy) {
2011 pthread_mutexattr_destroy(&ma);
2013 return ret;
2016 static void nwrap_init(void)
2018 const char *env;
2019 char *endptr;
2020 size_t max_hostents_tmp;
2021 int ok;
2023 nwrap_mutex_lock(&nwrap_initialized_mutex);
2024 if (nwrap_initialized) {
2025 nwrap_mutex_unlock(&nwrap_initialized_mutex);
2026 return;
2030 * Still holding nwrap_initialized lock here.
2031 * We don't use NWRAP_(UN)LOCK_ALL macros here because we
2032 * want to avoid overhead when other threads do their job.
2034 nwrap_mutex_lock(&nwrap_global_mutex);
2035 nwrap_mutex_lock(&nwrap_gr_global_mutex);
2036 nwrap_mutex_lock(&nwrap_he_global_mutex);
2037 nwrap_mutex_lock(&nwrap_pw_global_mutex);
2038 nwrap_mutex_lock(&nwrap_sp_global_mutex);
2040 nwrap_initialized = true;
2042 env = getenv("NSS_WRAPPER_MAX_HOSTENTS");
2043 if (env != NULL) {
2044 max_hostents_tmp = (size_t)strtoul(env, &endptr, 10);
2045 if ((*env == '\0') ||
2046 (*endptr != '\0') ||
2047 (max_hostents_tmp == 0)) {
2048 NWRAP_LOG(NWRAP_LOG_DEBUG,
2049 "Error parsing NSS_WRAPPER_MAX_HOSTENTS "
2050 "value or value is too small. "
2051 "Using default value: %lu.",
2052 (unsigned long)max_hostents);
2053 } else {
2054 max_hostents = max_hostents_tmp;
2057 /* Initialize hash table */
2058 NWRAP_LOG(NWRAP_LOG_DEBUG,
2059 "Initializing hash table of size %lu items.",
2060 (unsigned long)max_hostents);
2061 ok = hcreate(max_hostents);
2062 if (!ok) {
2063 NWRAP_LOG(NWRAP_LOG_ERROR,
2064 "Failed to initialize hash table");
2065 exit(-1);
2068 nwrap_main_global = &__nwrap_main_global;
2070 nwrap_libc_init(nwrap_main_global);
2072 nwrap_backend_init(nwrap_main_global);
2074 /* passwd */
2075 nwrap_pw_global.cache = &__nwrap_cache_pw;
2077 nwrap_pw_global.cache->path = getenv("NSS_WRAPPER_PASSWD");
2078 nwrap_pw_global.cache->fp = NULL;
2079 nwrap_pw_global.cache->fd = -1;
2080 nwrap_pw_global.cache->private_data = &nwrap_pw_global;
2081 nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
2082 nwrap_pw_global.cache->unload = nwrap_pw_unload;
2084 /* shadow */
2085 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
2086 nwrap_sp_global.cache = &__nwrap_cache_sp;
2088 nwrap_sp_global.cache->path = getenv("NSS_WRAPPER_SHADOW");
2089 nwrap_sp_global.cache->fp = NULL;
2090 nwrap_sp_global.cache->fd = -1;
2091 nwrap_sp_global.cache->private_data = &nwrap_sp_global;
2092 nwrap_sp_global.cache->parse_line = nwrap_sp_parse_line;
2093 nwrap_sp_global.cache->unload = nwrap_sp_unload;
2094 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
2096 /* group */
2097 nwrap_gr_global.cache = &__nwrap_cache_gr;
2099 nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
2100 nwrap_gr_global.cache->fp = NULL;
2101 nwrap_gr_global.cache->fd = -1;
2102 nwrap_gr_global.cache->private_data = &nwrap_gr_global;
2103 nwrap_gr_global.cache->parse_line = nwrap_gr_parse_line;
2104 nwrap_gr_global.cache->unload = nwrap_gr_unload;
2106 /* hosts */
2107 nwrap_he_global.cache = &__nwrap_cache_he;
2109 nwrap_he_global.cache->path = getenv("NSS_WRAPPER_HOSTS");
2110 nwrap_he_global.cache->fp = NULL;
2111 nwrap_he_global.cache->fd = -1;
2112 nwrap_he_global.cache->private_data = &nwrap_he_global;
2113 nwrap_he_global.cache->parse_line = nwrap_he_parse_line;
2114 nwrap_he_global.cache->unload = nwrap_he_unload;
2116 /* We hold all locks here so we can use NWRAP_UNLOCK_ALL. */
2117 nwrap_mutex_unlock(&nwrap_sp_global_mutex);
2118 nwrap_mutex_unlock(&nwrap_pw_global_mutex);
2119 nwrap_mutex_unlock(&nwrap_he_global_mutex);
2120 nwrap_mutex_unlock(&nwrap_gr_global_mutex);
2121 nwrap_mutex_unlock(&nwrap_global_mutex);
2122 nwrap_mutex_unlock(&nwrap_initialized_mutex);
2125 bool nss_wrapper_enabled(void)
2127 nwrap_init();
2129 if (nwrap_pw_global.cache->path == NULL ||
2130 nwrap_pw_global.cache->path[0] == '\0') {
2131 return false;
2133 if (nwrap_gr_global.cache->path == NULL ||
2134 nwrap_gr_global.cache->path[0] == '\0') {
2135 return false;
2138 return true;
2141 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
2142 bool nss_wrapper_shadow_enabled(void)
2144 nwrap_init();
2146 if (nwrap_sp_global.cache->path == NULL ||
2147 nwrap_sp_global.cache->path[0] == '\0') {
2148 return false;
2151 return true;
2153 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
2155 bool nss_wrapper_hosts_enabled(void)
2157 nwrap_init();
2159 if (nwrap_he_global.cache->path == NULL ||
2160 nwrap_he_global.cache->path[0] == '\0') {
2161 return false;
2164 return true;
2167 static bool nwrap_hostname_enabled(void)
2169 nwrap_init();
2171 if (getenv("NSS_WRAPPER_HOSTNAME") == NULL) {
2172 return false;
2175 return true;
2178 static bool nwrap_parse_file(struct nwrap_cache *nwrap)
2180 char *line = NULL;
2181 ssize_t n;
2182 /* Unused but getline needs it */
2183 size_t len;
2184 bool ok;
2186 if (nwrap->st.st_size == 0) {
2187 NWRAP_LOG(NWRAP_LOG_DEBUG, "size == 0");
2188 return true;
2191 /* Support for 32-bit system I guess */
2192 if (nwrap->st.st_size > INT32_MAX) {
2193 NWRAP_LOG(NWRAP_LOG_ERROR,
2194 "Size[%u] larger than INT32_MAX",
2195 (unsigned)nwrap->st.st_size);
2196 return false;
2199 rewind(nwrap->fp);
2201 do {
2202 n = getline(&line, &len, nwrap->fp);
2203 if (n < 0) {
2204 SAFE_FREE(line);
2205 if (feof(nwrap->fp)) {
2206 break;
2209 NWRAP_LOG(NWRAP_LOG_ERROR,
2210 "Unable to read line from file: %s",
2211 nwrap->path);
2212 return false;
2215 if (line[n - 1] == '\n') {
2216 line[n - 1] = '\0';
2219 if (line[0] == '\0') {
2220 SAFE_FREE(line);
2221 continue;
2224 ok = nwrap->parse_line(nwrap, line);
2225 if (!ok) {
2226 NWRAP_LOG(NWRAP_LOG_ERROR,
2227 "Unable to parse line file: %s",
2228 line);
2229 SAFE_FREE(line);
2230 return false;
2233 /* Line is parsed without issues so add it to list */
2234 ok = nwrap_vector_add_item(&(nwrap->lines), (void *const) line);
2235 if (!ok) {
2236 NWRAP_LOG(NWRAP_LOG_ERROR,
2237 "Unable to add line to vector");
2238 return false;
2241 /* This forces getline to allocate new memory for line. */
2242 line = NULL;
2243 } while (!feof(nwrap->fp));
2245 return true;
2248 static void nwrap_files_cache_unload(struct nwrap_cache *nwrap)
2250 nwrap->unload(nwrap);
2252 nwrap_lines_unload(nwrap);
2255 static bool nwrap_files_cache_reload(struct nwrap_cache *nwrap)
2257 struct stat st;
2258 int ret;
2259 bool ok;
2260 bool retried = false;
2262 assert(nwrap != NULL);
2264 reopen:
2265 if (nwrap->fd < 0) {
2266 nwrap->fp = fopen(nwrap->path, "re");
2267 if (nwrap->fp == NULL) {
2268 nwrap->fd = -1;
2269 NWRAP_LOG(NWRAP_LOG_ERROR,
2270 "Unable to open '%s' readonly %d:%s",
2271 nwrap->path, nwrap->fd,
2272 strerror(errno));
2273 return false;
2276 nwrap->fd = fileno(nwrap->fp);
2277 NWRAP_LOG(NWRAP_LOG_DEBUG, "Open '%s'", nwrap->path);
2280 ret = fstat(nwrap->fd, &st);
2281 if (ret != 0 && errno == EBADF && retried == false) {
2282 /* maybe something closed the fd on our behalf */
2283 NWRAP_LOG(NWRAP_LOG_TRACE,
2284 "fstat(%s) - %d:%s - reopen",
2285 nwrap->path,
2286 ret,
2287 strerror(errno));
2288 retried = true;
2289 memset(&nwrap->st, 0, sizeof(nwrap->st));
2290 fclose(nwrap->fp);
2291 nwrap->fp = NULL;
2292 nwrap->fd = -1;
2293 goto reopen;
2295 else if (ret != 0) {
2296 NWRAP_LOG(NWRAP_LOG_ERROR,
2297 "fstat(%s) - %d:%s",
2298 nwrap->path,
2299 ret,
2300 strerror(errno));
2301 fclose(nwrap->fp);
2302 nwrap->fp = NULL;
2303 nwrap->fd = -1;
2304 return false;
2307 if (retried == false && st.st_nlink == 0) {
2308 /* maybe someone has replaced the file... */
2309 NWRAP_LOG(NWRAP_LOG_TRACE,
2310 "st_nlink == 0, reopen %s",
2311 nwrap->path);
2312 retried = true;
2313 memset(&nwrap->st, 0, sizeof(nwrap->st));
2314 fclose(nwrap->fp);
2315 nwrap->fp = NULL;
2316 nwrap->fd = -1;
2317 goto reopen;
2320 if (st.st_mtime == nwrap->st.st_mtime) {
2321 NWRAP_LOG(NWRAP_LOG_TRACE,
2322 "st_mtime[%u] hasn't changed, skip reload",
2323 (unsigned)st.st_mtime);
2324 return true;
2327 NWRAP_LOG(NWRAP_LOG_TRACE,
2328 "st_mtime has changed [%u] => [%u], start reload",
2329 (unsigned)st.st_mtime,
2330 (unsigned)nwrap->st.st_mtime);
2332 nwrap->st = st;
2334 nwrap_files_cache_unload(nwrap);
2336 ok = nwrap_parse_file(nwrap);
2337 if (!ok) {
2338 NWRAP_LOG(NWRAP_LOG_ERROR, "Failed to reload %s", nwrap->path);
2339 nwrap_files_cache_unload(nwrap);
2340 return false;
2343 NWRAP_LOG(NWRAP_LOG_TRACE, "Reloaded %s", nwrap->path);
2344 return true;
2348 * the caller has to call nwrap_unload() on failure
2350 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
2352 struct nwrap_pw *nwrap_pw;
2353 char *c;
2354 char *p;
2355 char *e;
2356 struct passwd *pw;
2357 size_t list_size;
2359 nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
2361 list_size = sizeof(*nwrap_pw->list) * (nwrap_pw->num+1);
2362 pw = (struct passwd *)realloc(nwrap_pw->list, list_size);
2363 if (!pw) {
2364 NWRAP_LOG(NWRAP_LOG_ERROR,
2365 "realloc(%u) failed",
2366 (unsigned)list_size);
2367 return false;
2369 nwrap_pw->list = pw;
2371 pw = &nwrap_pw->list[nwrap_pw->num];
2373 c = line;
2375 /* name */
2376 p = strchr(c, ':');
2377 if (!p) {
2378 NWRAP_LOG(NWRAP_LOG_ERROR,
2379 "Invalid line[%s]: '%s'",
2380 line,
2382 return false;
2384 *p = '\0';
2385 p++;
2386 pw->pw_name = c;
2387 c = p;
2389 NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]\n", pw->pw_name);
2391 /* password */
2392 p = strchr(c, ':');
2393 if (!p) {
2394 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
2395 return false;
2397 *p = '\0';
2398 p++;
2399 pw->pw_passwd = c;
2400 c = p;
2402 NWRAP_LOG(NWRAP_LOG_TRACE, "password[%s]\n", pw->pw_passwd);
2404 /* uid */
2405 p = strchr(c, ':');
2406 if (!p) {
2407 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
2408 return false;
2410 *p = '\0';
2411 p++;
2412 e = NULL;
2413 pw->pw_uid = (uid_t)strtoul(c, &e, 10);
2414 if (c == e) {
2415 NWRAP_LOG(NWRAP_LOG_ERROR,
2416 "Invalid line[%s]: '%s' - %s",
2417 line, c, strerror(errno));
2418 return false;
2420 if (e == NULL) {
2421 NWRAP_LOG(NWRAP_LOG_ERROR,
2422 "Invalid line[%s]: '%s' - %s",
2423 line, c, strerror(errno));
2424 return false;
2426 if (e[0] != '\0') {
2427 NWRAP_LOG(NWRAP_LOG_ERROR,
2428 "Invalid line[%s]: '%s' - %s",
2429 line, c, strerror(errno));
2430 return false;
2432 c = p;
2434 NWRAP_LOG(NWRAP_LOG_TRACE, "uid[%u]", pw->pw_uid);
2436 /* gid */
2437 p = strchr(c, ':');
2438 if (!p) {
2439 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
2440 return false;
2442 *p = '\0';
2443 #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
2445 * We don't support pw_class, so just let it point to
2446 * an '\0' byte (empty string).
2448 pw->pw_class = p;
2449 #endif /* HAVE_STRUCT_PASSWD_PW_CLASS */
2450 p++;
2451 e = NULL;
2452 pw->pw_gid = (gid_t)strtoul(c, &e, 10);
2453 if (c == e) {
2454 NWRAP_LOG(NWRAP_LOG_ERROR,
2455 "Invalid line[%s]: '%s' - %s",
2456 line, c, strerror(errno));
2457 return false;
2459 if (e == NULL) {
2460 NWRAP_LOG(NWRAP_LOG_ERROR,
2461 "Invalid line[%s]: '%s' - %s",
2462 line, c, strerror(errno));
2463 return false;
2465 if (e[0] != '\0') {
2466 NWRAP_LOG(NWRAP_LOG_ERROR,
2467 "Invalid line[%s]: '%s' - %s",
2468 line, c, strerror(errno));
2469 return false;
2471 c = p;
2473 NWRAP_LOG(NWRAP_LOG_TRACE, "gid[%u]\n", pw->pw_gid);
2475 #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
2476 NWRAP_LOG(NWRAP_LOG_TRACE, "class[%s]", pw->pw_class);
2477 #endif /* HAVE_STRUCT_PASSWD_PW_CLASS */
2479 #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
2480 pw->pw_change = 0;
2482 NWRAP_LOG(NWRAP_LOG_TRACE,
2483 "change[%lu]",
2484 (unsigned long)pw->pw_change);
2485 #endif /* HAVE_STRUCT_PASSWD_PW_CHANGE */
2487 #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
2488 pw->pw_expire = 0;
2490 NWRAP_LOG(NWRAP_LOG_TRACE,
2491 "expire[%lu]",
2492 (unsigned long)pw->pw_expire);
2493 #endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE */
2495 /* gecos */
2496 p = strchr(c, ':');
2497 if (!p) {
2498 NWRAP_LOG(NWRAP_LOG_ERROR, "invalid line[%s]: '%s'", line, c);
2499 return false;
2501 *p = '\0';
2502 p++;
2503 pw->pw_gecos = c;
2504 c = p;
2506 NWRAP_LOG(NWRAP_LOG_TRACE, "gecos[%s]", pw->pw_gecos);
2508 /* dir */
2509 p = strchr(c, ':');
2510 if (!p) {
2511 NWRAP_LOG(NWRAP_LOG_ERROR, "'%s'", c);
2512 return false;
2514 *p = '\0';
2515 p++;
2516 pw->pw_dir = c;
2517 c = p;
2519 NWRAP_LOG(NWRAP_LOG_TRACE, "dir[%s]", pw->pw_dir);
2521 /* shell */
2522 pw->pw_shell = c;
2523 NWRAP_LOG(NWRAP_LOG_TRACE, "shell[%s]", pw->pw_shell);
2525 NWRAP_LOG(NWRAP_LOG_DEBUG,
2526 "Added user[%s:%s:%u:%u:%s:%s:%s]",
2527 pw->pw_name, pw->pw_passwd,
2528 pw->pw_uid, pw->pw_gid,
2529 pw->pw_gecos, pw->pw_dir, pw->pw_shell);
2531 nwrap_pw->num++;
2532 return true;
2535 static void nwrap_pw_unload(struct nwrap_cache *nwrap)
2537 struct nwrap_pw *nwrap_pw;
2538 nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
2540 SAFE_FREE(nwrap_pw->list);
2541 nwrap_pw->num = 0;
2542 nwrap_pw->idx = 0;
2545 static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
2546 char *buf, size_t buflen, struct passwd **dstp)
2548 char *first;
2549 char *last;
2550 off_t ofs;
2552 first = src->pw_name;
2554 last = src->pw_shell;
2555 while (*last) last++;
2557 ofs = PTR_DIFF(last + 1, first);
2559 if (ofs > (off_t) buflen) {
2560 return ERANGE;
2563 memcpy(buf, first, ofs);
2565 ofs = PTR_DIFF(src->pw_name, first);
2566 dst->pw_name = buf + ofs;
2567 ofs = PTR_DIFF(src->pw_passwd, first);
2568 dst->pw_passwd = buf + ofs;
2569 dst->pw_uid = src->pw_uid;
2570 dst->pw_gid = src->pw_gid;
2571 #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
2572 ofs = PTR_DIFF(src->pw_class, first);
2573 dst->pw_class = buf + ofs;
2574 #endif /* HAVE_STRUCT_PASSWD_PW_CLASS */
2576 #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
2577 dst->pw_change = 0;
2578 #endif /* HAVE_STRUCT_PASSWD_PW_CHANGE */
2580 #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
2581 dst->pw_expire = 0;
2582 #endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE */
2584 ofs = PTR_DIFF(src->pw_gecos, first);
2585 dst->pw_gecos = buf + ofs;
2586 ofs = PTR_DIFF(src->pw_dir, first);
2587 dst->pw_dir = buf + ofs;
2588 ofs = PTR_DIFF(src->pw_shell, first);
2589 dst->pw_shell = buf + ofs;
2591 if (dstp) {
2592 *dstp = dst;
2595 return 0;
2598 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
2599 static bool nwrap_sp_parse_line(struct nwrap_cache *nwrap, char *line)
2601 struct nwrap_sp *nwrap_sp;
2602 struct spwd *sp;
2603 size_t list_size;
2604 char *c;
2605 char *e;
2606 char *p;
2608 nwrap_sp = (struct nwrap_sp *)nwrap->private_data;
2610 list_size = sizeof(*nwrap_sp->list) * (nwrap_sp->num+1);
2611 sp = (struct spwd *)realloc(nwrap_sp->list, list_size);
2612 if (sp == NULL) {
2613 NWRAP_LOG(NWRAP_LOG_ERROR,
2614 "realloc(%u) failed",
2615 (unsigned)list_size);
2616 return false;
2618 nwrap_sp->list = sp;
2620 sp = &nwrap_sp->list[nwrap_sp->num];
2622 c = line;
2624 /* name */
2625 p = strchr(c, ':');
2626 if (p == NULL) {
2627 NWRAP_LOG(NWRAP_LOG_ERROR,
2628 "name -- Invalid line[%s]: '%s'",
2629 line,
2631 return false;
2633 *p = '\0';
2634 p++;
2635 sp->sp_namp = c;
2636 c = p;
2638 NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]\n", sp->sp_namp);
2640 /* pwd */
2641 p = strchr(c, ':');
2642 if (p == NULL) {
2643 NWRAP_LOG(NWRAP_LOG_ERROR,
2644 "pwd -- Invalid line[%s]: '%s'",
2645 line,
2647 return false;
2649 *p = '\0';
2650 p++;
2651 sp->sp_pwdp = c;
2652 c = p;
2654 /* lstchg (long) */
2655 if (c[0] == ':') {
2656 sp->sp_lstchg = -1;
2657 p++;
2658 } else {
2659 p = strchr(c, ':');
2660 if (p == NULL) {
2661 NWRAP_LOG(NWRAP_LOG_ERROR,
2662 "lstchg -- Invalid line[%s]: '%s'",
2663 line,
2665 return false;
2667 *p = '\0';
2668 p++;
2669 sp->sp_lstchg = strtol(c, &e, 10);
2670 if (c == e) {
2671 NWRAP_LOG(NWRAP_LOG_ERROR,
2672 "lstchg -- Invalid line[%s]: '%s' - %s",
2673 line, c, strerror(errno));
2674 return false;
2676 if (e == NULL) {
2677 NWRAP_LOG(NWRAP_LOG_ERROR,
2678 "lstchg -- Invalid line[%s]: '%s' - %s",
2679 line, c, strerror(errno));
2680 return false;
2682 if (e[0] != '\0') {
2683 NWRAP_LOG(NWRAP_LOG_ERROR,
2684 "lstchg -- Invalid line[%s]: '%s' - %s",
2685 line, c, strerror(errno));
2686 return false;
2689 c = p;
2691 /* min (long) */
2692 if (c[0] == ':') {
2693 sp->sp_min = -1;
2694 p++;
2695 } else {
2696 p = strchr(c, ':');
2697 if (p == NULL) {
2698 NWRAP_LOG(NWRAP_LOG_ERROR,
2699 "min -- Invalid line[%s]: '%s'",
2700 line,
2702 return false;
2704 *p = '\0';
2705 p++;
2706 sp->sp_min = strtol(c, &e, 10);
2707 if (c == e) {
2708 NWRAP_LOG(NWRAP_LOG_ERROR,
2709 "min -- Invalid line[%s]: '%s' - %s",
2710 line, c, strerror(errno));
2711 return false;
2713 if (e == NULL) {
2714 NWRAP_LOG(NWRAP_LOG_ERROR,
2715 "min -- Invalid line[%s]: '%s' - %s",
2716 line, c, strerror(errno));
2717 return false;
2719 if (e[0] != '\0') {
2720 NWRAP_LOG(NWRAP_LOG_ERROR,
2721 "min -- Invalid line[%s]: '%s' - %s",
2722 line, c, strerror(errno));
2723 return false;
2726 c = p;
2728 /* max (long) */
2729 if (c[0] == ':') {
2730 sp->sp_max = -1;
2731 p++;
2732 } else {
2733 p = strchr(c, ':');
2734 if (p == NULL) {
2735 NWRAP_LOG(NWRAP_LOG_ERROR,
2736 "max -- Invalid line[%s]: '%s'",
2737 line,
2739 return false;
2741 *p = '\0';
2742 p++;
2743 sp->sp_max = strtol(c, &e, 10);
2744 if (c == e) {
2745 NWRAP_LOG(NWRAP_LOG_ERROR,
2746 "max -- Invalid line[%s]: '%s' - %s",
2747 line, c, strerror(errno));
2748 return false;
2750 if (e == NULL) {
2751 NWRAP_LOG(NWRAP_LOG_ERROR,
2752 "max -- Invalid line[%s]: '%s' - %s",
2753 line, c, strerror(errno));
2754 return false;
2756 if (e[0] != '\0') {
2757 NWRAP_LOG(NWRAP_LOG_ERROR,
2758 "max -- Invalid line[%s]: '%s' - %s",
2759 line, c, strerror(errno));
2760 return false;
2763 c = p;
2765 /* warn (long) */
2766 if (c[0] == ':') {
2767 sp->sp_warn = -1;
2768 p++;
2769 } else {
2770 p = strchr(c, ':');
2771 if (p == NULL) {
2772 NWRAP_LOG(NWRAP_LOG_ERROR,
2773 "warn -- Invalid line[%s]: '%s'",
2774 line,
2776 return false;
2778 *p = '\0';
2779 p++;
2780 sp->sp_warn = strtol(c, &e, 10);
2781 if (c == e) {
2782 NWRAP_LOG(NWRAP_LOG_ERROR,
2783 "warn -- Invalid line[%s]: '%s' - %s",
2784 line, c, strerror(errno));
2785 return false;
2787 if (e == NULL) {
2788 NWRAP_LOG(NWRAP_LOG_ERROR,
2789 "warn -- Invalid line[%s]: '%s' - %s",
2790 line, c, strerror(errno));
2791 return false;
2793 if (e[0] != '\0') {
2794 NWRAP_LOG(NWRAP_LOG_ERROR,
2795 "warn -- Invalid line[%s]: '%s' - %s",
2796 line, c, strerror(errno));
2797 return false;
2800 c = p;
2802 /* inact (long) */
2803 if (c[0] == ':') {
2804 sp->sp_inact = -1;
2805 p++;
2806 } else {
2807 p = strchr(c, ':');
2808 if (p == NULL) {
2809 NWRAP_LOG(NWRAP_LOG_ERROR,
2810 "inact -- Invalid line[%s]: '%s'",
2811 line,
2813 return false;
2815 *p = '\0';
2816 p++;
2817 sp->sp_inact = strtol(c, &e, 10);
2818 if (c == e) {
2819 NWRAP_LOG(NWRAP_LOG_ERROR,
2820 "inact -- Invalid line[%s]: '%s' - %s",
2821 line, c, strerror(errno));
2822 return false;
2824 if (e == NULL) {
2825 NWRAP_LOG(NWRAP_LOG_ERROR,
2826 "inact -- Invalid line[%s]: '%s' - %s",
2827 line, c, strerror(errno));
2828 return false;
2830 if (e[0] != '\0') {
2831 NWRAP_LOG(NWRAP_LOG_ERROR,
2832 "inact -- Invalid line[%s]: '%s' - %s",
2833 line, c, strerror(errno));
2834 return false;
2837 c = p;
2839 /* expire (long) */
2840 if (c[0] == ':') {
2841 sp->sp_expire = -1;
2842 p++;
2843 } else {
2844 p = strchr(c, ':');
2845 if (p == NULL) {
2846 NWRAP_LOG(NWRAP_LOG_ERROR,
2847 "expire -- Invalid line[%s]: '%s'",
2848 line,
2850 return false;
2852 *p = '\0';
2853 p++;
2854 sp->sp_expire = strtol(c, &e, 10);
2855 if (c == e) {
2856 NWRAP_LOG(NWRAP_LOG_ERROR,
2857 "expire -- Invalid line[%s]: '%s' - %s",
2858 line, c, strerror(errno));
2859 return false;
2861 if (e == NULL) {
2862 NWRAP_LOG(NWRAP_LOG_ERROR,
2863 "expire -- Invalid line[%s]: '%s' - %s",
2864 line, c, strerror(errno));
2865 return false;
2867 if (e[0] != '\0') {
2868 NWRAP_LOG(NWRAP_LOG_ERROR,
2869 "expire -- Invalid line[%s]: '%s' - %s",
2870 line, c, strerror(errno));
2871 return false;
2874 c = p;
2876 nwrap_sp->num++;
2877 return true;
2880 static void nwrap_sp_unload(struct nwrap_cache *nwrap)
2882 struct nwrap_sp *nwrap_sp;
2883 nwrap_sp = (struct nwrap_sp *)nwrap->private_data;
2885 SAFE_FREE(nwrap_sp->list);
2886 nwrap_sp->num = 0;
2887 nwrap_sp->idx = 0;
2889 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
2892 * the caller has to call nwrap_unload() on failure
2894 static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
2896 struct nwrap_gr *nwrap_gr;
2897 char *c;
2898 char *p;
2899 char *e;
2900 struct group *gr;
2901 size_t list_size;
2902 unsigned nummem;
2904 nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
2906 list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
2907 gr = (struct group *)realloc(nwrap_gr->list, list_size);
2908 if (!gr) {
2909 NWRAP_LOG(NWRAP_LOG_ERROR, "realloc failed");
2910 return false;
2912 nwrap_gr->list = gr;
2914 gr = &nwrap_gr->list[nwrap_gr->num];
2916 c = line;
2918 /* name */
2919 p = strchr(c, ':');
2920 if (!p) {
2921 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
2922 return false;
2924 *p = '\0';
2925 p++;
2926 gr->gr_name = c;
2927 c = p;
2929 NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]", gr->gr_name);
2931 /* password */
2932 p = strchr(c, ':');
2933 if (!p) {
2934 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
2935 return false;
2937 *p = '\0';
2938 p++;
2939 gr->gr_passwd = c;
2940 c = p;
2942 NWRAP_LOG(NWRAP_LOG_TRACE, "password[%s]", gr->gr_passwd);
2944 /* gid */
2945 p = strchr(c, ':');
2946 if (!p) {
2947 NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
2948 return false;
2950 *p = '\0';
2951 p++;
2952 e = NULL;
2953 gr->gr_gid = (gid_t)strtoul(c, &e, 10);
2954 if (c == e) {
2955 NWRAP_LOG(NWRAP_LOG_ERROR,
2956 "Invalid line[%s]: '%s' - %s",
2957 line, c, strerror(errno));
2958 return false;
2960 if (e == NULL) {
2961 NWRAP_LOG(NWRAP_LOG_ERROR,
2962 "Invalid line[%s]: '%s' - %s",
2963 line, c, strerror(errno));
2964 return false;
2966 if (e[0] != '\0') {
2967 NWRAP_LOG(NWRAP_LOG_ERROR,
2968 "Invalid line[%s]: '%s' - %s",
2969 line, c, strerror(errno));
2970 return false;
2972 c = p;
2974 NWRAP_LOG(NWRAP_LOG_TRACE, "gid[%u]", gr->gr_gid);
2976 /* members */
2977 gr->gr_mem = (char **)malloc(sizeof(char *));
2978 if (!gr->gr_mem) {
2979 NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
2980 return false;
2982 gr->gr_mem[0] = NULL;
2984 for(nummem = 0; p != NULL && p[0] != '\0'; nummem++) {
2985 char **m;
2986 size_t m_size;
2987 c = p;
2988 p = strchr(c, ',');
2989 if (p) {
2990 *p = '\0';
2991 p++;
2994 if (strlen(c) == 0) {
2995 break;
2998 m_size = sizeof(char *) * (nummem+2);
2999 m = (char **)realloc(gr->gr_mem, m_size);
3000 if (!m) {
3001 NWRAP_LOG(NWRAP_LOG_ERROR,
3002 "realloc(%zd) failed",
3003 m_size);
3004 return false;
3006 gr->gr_mem = m;
3007 gr->gr_mem[nummem] = c;
3008 gr->gr_mem[nummem+1] = NULL;
3010 NWRAP_LOG(NWRAP_LOG_TRACE,
3011 "member[%u]: '%s'",
3012 nummem, gr->gr_mem[nummem]);
3015 NWRAP_LOG(NWRAP_LOG_DEBUG,
3016 "Added group[%s:%s:%u:] with %u members",
3017 gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem);
3019 nwrap_gr->num++;
3020 return true;
3023 static void nwrap_gr_unload(struct nwrap_cache *nwrap)
3025 int i;
3026 struct nwrap_gr *nwrap_gr;
3027 nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
3029 if (nwrap_gr->list) {
3030 for (i=0; i < nwrap_gr->num; i++) {
3031 SAFE_FREE(nwrap_gr->list[i].gr_mem);
3033 SAFE_FREE(nwrap_gr->list);
3036 nwrap_gr->num = 0;
3037 nwrap_gr->idx = 0;
3040 static struct nwrap_entlist *nwrap_entlist_init(struct nwrap_entdata *ed)
3042 struct nwrap_entlist *el;
3044 if (ed == NULL) {
3045 NWRAP_LOG(NWRAP_LOG_ERROR,
3046 "entry is NULL, can't create list item");
3047 return NULL;
3050 el = (struct nwrap_entlist *)malloc(sizeof(struct nwrap_entlist));
3051 if (el == NULL) {
3052 NWRAP_LOG(NWRAP_LOG_ERROR, "malloc failed");
3053 return NULL;
3056 el->next = NULL;
3057 el->ed = ed;
3059 return el;
3062 static bool nwrap_ed_inventarize_add_new(char *const h_name,
3063 struct nwrap_entdata *const ed)
3065 ENTRY e;
3066 ENTRY *p;
3067 struct nwrap_entlist *el;
3068 bool ok;
3070 if (h_name == NULL) {
3071 NWRAP_LOG(NWRAP_LOG_ERROR, "h_name NULL - can't add");
3072 return false;
3075 el = nwrap_entlist_init(ed);
3076 if (el == NULL) {
3077 return false;
3080 e.key = h_name;
3081 e.data = (void *)el;
3083 p = hsearch(e, ENTER);
3084 if (p == NULL) {
3085 NWRAP_LOG(NWRAP_LOG_ERROR,
3086 "Hash table is full (%s)!",
3087 strerror(errno));
3088 return false;
3091 ok = nwrap_vector_add_item(&(nwrap_he_global.lists), (void *)el);
3092 if (!ok) {
3093 NWRAP_LOG(NWRAP_LOG_ERROR,
3094 "Failed to add list entry to vector.");
3095 return false;
3098 return true;
3101 static bool nwrap_ed_inventarize_add_to_existing(struct nwrap_entdata *const ed,
3102 struct nwrap_entlist *const el)
3104 struct nwrap_entlist *cursor;
3105 struct nwrap_entlist *el_new;
3107 if (el == NULL) {
3108 NWRAP_LOG(NWRAP_LOG_ERROR, "list is NULL, can not add");
3109 return false;
3113 for (cursor = el; cursor->next != NULL; cursor = cursor->next)
3115 if (cursor->ed == ed) {
3116 /* The entry already exists in this list. */
3117 return true;
3121 if (cursor->ed == ed) {
3122 /* The entry already exists in this list. */
3123 return true;
3126 el_new = nwrap_entlist_init(ed);
3127 if (el_new == NULL) {
3128 return false;
3131 cursor->next = el_new;
3132 return true;
3135 static bool nwrap_ed_inventarize(char *const name,
3136 struct nwrap_entdata *const ed)
3138 ENTRY e;
3139 ENTRY *p;
3140 bool ok;
3142 e.key = name;
3143 e.data = NULL;
3145 NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching name: %s", e.key);
3147 p = hsearch(e, FIND);
3148 if (p == NULL) {
3149 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found. Adding...", name);
3150 ok = nwrap_ed_inventarize_add_new(name, ed);
3151 } else {
3152 struct nwrap_entlist *el = (struct nwrap_entlist *)p->data;
3154 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s found. Add record to list.", name);
3155 ok = nwrap_ed_inventarize_add_to_existing(ed, el);
3158 return ok;
3161 static bool nwrap_add_hname(struct nwrap_entdata *const ed)
3163 char *const h_name = (char *const)(ed->ht.h_name);
3164 unsigned i;
3165 bool ok;
3167 ok = nwrap_ed_inventarize(h_name, ed);
3168 if (!ok) {
3169 return false;
3172 if (ed->ht.h_aliases == NULL) {
3173 return true;
3176 /* Itemize aliases */
3177 for (i = 0; ed->ht.h_aliases[i] != NULL; ++i) {
3178 char *h_name_alias;
3180 h_name_alias = ed->ht.h_aliases[i];
3182 NWRAP_LOG(NWRAP_LOG_DEBUG, "Add alias: %s", h_name_alias);
3184 if (!nwrap_ed_inventarize(h_name_alias, ed)) {
3185 NWRAP_LOG(NWRAP_LOG_ERROR,
3186 "Unable to add alias: %s", h_name_alias);
3187 return false;
3191 return true;
3194 static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
3196 struct nwrap_he *nwrap_he = (struct nwrap_he *)nwrap->private_data;
3197 bool do_aliases = true;
3198 ssize_t aliases_count = 0;
3199 char *p;
3200 char *i;
3201 char *n;
3203 char *ip;
3204 bool ok;
3206 struct nwrap_entdata *ed = (struct nwrap_entdata *)
3207 malloc(sizeof(struct nwrap_entdata));
3208 if (ed == NULL) {
3209 NWRAP_LOG(NWRAP_LOG_ERROR,
3210 "Unable to allocate memory for nwrap_entdata");
3211 return false;
3213 ZERO_STRUCTP(ed);
3215 i = line;
3218 * IP
3221 /* Walk to first char */
3222 for (p = i; *p != '.' && *p != ':' && !isxdigit((int) *p); p++) {
3223 if (*p == '\0') {
3224 NWRAP_LOG(NWRAP_LOG_ERROR,
3225 "Invalid line[%s]: '%s'",
3226 line, i);
3227 free(ed);
3228 return false;
3232 for (i = p; !isspace((int)*p); p++) {
3233 if (*p == '\0') {
3234 NWRAP_LOG(NWRAP_LOG_ERROR,
3235 "Invalid line[%s]: '%s'",
3236 line, i);
3237 free(ed);
3238 return false;
3242 *p = '\0';
3244 if (inet_pton(AF_INET, i, ed->addr.host_addr)) {
3245 ed->ht.h_addrtype = AF_INET;
3246 ed->ht.h_length = 4;
3247 #ifdef HAVE_IPV6
3248 } else if (inet_pton(AF_INET6, i, ed->addr.host_addr)) {
3249 ed->ht.h_addrtype = AF_INET6;
3250 ed->ht.h_length = 16;
3251 #endif
3252 } else {
3253 NWRAP_LOG(NWRAP_LOG_ERROR,
3254 "Invalid line[%s]: '%s'",
3255 line, i);
3257 free(ed);
3258 return false;
3260 ip = i;
3262 ok = nwrap_vector_add_item(&(ed->nwrap_addrdata),
3263 (void *const)ed->addr.host_addr);
3264 if (!ok) {
3265 NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add addrdata to vector");
3266 free(ed);
3267 return false;
3269 ed->ht.h_addr_list = nwrap_vector_head(&ed->nwrap_addrdata);
3271 p++;
3274 * FQDN
3277 /* Walk to first char */
3278 for (n = p; *p != '_' && !isalnum((int) *p); p++) {
3279 if (*p == '\0') {
3280 NWRAP_LOG(NWRAP_LOG_ERROR,
3281 "Invalid line[%s]: '%s'",
3282 line, n);
3284 free(ed);
3285 return false;
3289 for (n = p; !isspace((int)*p); p++) {
3290 if (*p == '\0') {
3291 do_aliases = false;
3292 break;
3296 *p = '\0';
3298 /* Convert to lowercase. This operate on same memory region */
3299 str_tolower(n, n);
3300 ed->ht.h_name = n;
3302 /* glib's getent always dereferences he->h_aliases */
3303 ed->ht.h_aliases = malloc(sizeof(char *));
3304 if (ed->ht.h_aliases == NULL) {
3305 free(ed);
3306 return false;
3308 ed->ht.h_aliases[0] = NULL;
3311 * Aliases
3313 while (do_aliases) {
3314 char **aliases;
3315 char *a;
3317 p++;
3319 /* Walk to first char */
3320 for (a = p; *p != '_' && !isalnum((int) *p); p++) {
3321 if (*p == '\0') {
3322 do_aliases = false;
3323 break;
3326 /* Only trailing spaces are left */
3327 if (!do_aliases) {
3328 break;
3331 for (a = p; !isspace((int)*p); p++) {
3332 if (*p == '\0') {
3333 do_aliases = false;
3334 break;
3338 *p = '\0';
3340 aliases = realloc(ed->ht.h_aliases, sizeof(char *) * (aliases_count + 2));
3341 if (aliases == NULL) {
3342 free(ed);
3343 return false;
3345 ed->ht.h_aliases = aliases;
3347 str_tolower(a, a);
3348 aliases[aliases_count] = a;
3349 aliases[aliases_count + 1] = NULL;
3351 aliases_count += 1;
3354 ok = nwrap_vector_add_item(&(nwrap_he->entries), (void *const)ed);
3355 if (!ok) {
3356 NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add entry to vector");
3357 free(ed);
3358 return false;
3361 ed->aliases_count = aliases_count;
3362 /* Inventarize item */
3363 ok = nwrap_add_hname(ed);
3364 if (!ok) {
3365 return false;
3368 ok = nwrap_ed_inventarize(ip, ed);
3369 if (!ok) {
3370 return false;
3373 nwrap_he->num++;
3374 return true;
3377 static void nwrap_he_unload(struct nwrap_cache *nwrap)
3379 struct nwrap_he *nwrap_he =
3380 (struct nwrap_he *)nwrap->private_data;
3381 struct nwrap_entdata *ed;
3382 struct nwrap_entlist *el;
3383 size_t i;
3384 int rc;
3386 nwrap_vector_foreach (ed, nwrap_he->entries, i)
3388 SAFE_FREE(ed->nwrap_addrdata.items);
3389 SAFE_FREE(ed->ht.h_aliases);
3390 SAFE_FREE(ed);
3392 SAFE_FREE(nwrap_he->entries.items);
3393 nwrap_he->entries.count = nwrap_he->entries.capacity = 0;
3395 nwrap_vector_foreach(el, nwrap_he->lists, i)
3397 while (el != NULL) {
3398 struct nwrap_entlist *el_next;
3400 el_next = el->next;
3401 SAFE_FREE(el);
3402 el = el_next;
3405 SAFE_FREE(nwrap_he->lists.items);
3406 nwrap_he->lists.count = nwrap_he->lists.capacity = 0;
3408 nwrap_he->num = 0;
3409 nwrap_he->idx = 0;
3412 * If we unload the file, the pointers in the hash table point to
3413 * invalid memory. So we need to destroy the hash table and recreate
3414 * it.
3416 hdestroy();
3417 rc = hcreate(max_hostents);
3418 if (rc == 0) {
3419 NWRAP_LOG(NWRAP_LOG_ERROR, "Failed to initialize hash table");
3420 exit(-1);
3425 /* user functions */
3426 static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
3427 const char *name)
3429 int i;
3430 bool ok;
3432 (void) b; /* unused */
3434 NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name);
3436 ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
3437 if (!ok) {
3438 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
3439 return NULL;
3442 for (i=0; i<nwrap_pw_global.num; i++) {
3443 if (strcmp(nwrap_pw_global.list[i].pw_name, name) == 0) {
3444 NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] found", name);
3445 return &nwrap_pw_global.list[i];
3447 NWRAP_LOG(NWRAP_LOG_DEBUG,
3448 "user[%s] does not match [%s]",
3449 name,
3450 nwrap_pw_global.list[i].pw_name);
3453 NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] not found\n", name);
3455 errno = ENOENT;
3456 return NULL;
3459 static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
3460 const char *name, struct passwd *pwdst,
3461 char *buf, size_t buflen, struct passwd **pwdstp)
3463 struct passwd *pw;
3465 pw = nwrap_files_getpwnam(b, name);
3466 if (!pw) {
3467 if (errno == 0) {
3468 return ENOENT;
3470 return errno;
3473 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
3476 static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
3477 uid_t uid)
3479 int i;
3480 bool ok;
3482 (void) b; /* unused */
3484 ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
3485 if (!ok) {
3486 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
3487 return NULL;
3490 for (i=0; i<nwrap_pw_global.num; i++) {
3491 if (nwrap_pw_global.list[i].pw_uid == uid) {
3492 NWRAP_LOG(NWRAP_LOG_DEBUG, "uid[%u] found", uid);
3493 return &nwrap_pw_global.list[i];
3495 NWRAP_LOG(NWRAP_LOG_DEBUG,
3496 "uid[%u] does not match [%u]",
3497 uid,
3498 nwrap_pw_global.list[i].pw_uid);
3501 NWRAP_LOG(NWRAP_LOG_DEBUG, "uid[%u] not found\n", uid);
3503 errno = ENOENT;
3504 return NULL;
3507 static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
3508 uid_t uid, struct passwd *pwdst,
3509 char *buf, size_t buflen, struct passwd **pwdstp)
3511 struct passwd *pw;
3513 pw = nwrap_files_getpwuid(b, uid);
3514 if (!pw) {
3515 if (errno == 0) {
3516 return ENOENT;
3518 return errno;
3521 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
3524 /* user enum functions */
3525 static void nwrap_files_setpwent(struct nwrap_backend *b)
3527 (void) b; /* unused */
3529 nwrap_pw_global.idx = 0;
3532 static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b)
3534 struct passwd *pw;
3536 (void) b; /* unused */
3538 if (nwrap_pw_global.idx == 0) {
3539 bool ok;
3540 ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
3541 if (!ok) {
3542 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
3543 return NULL;
3547 if (nwrap_pw_global.idx >= nwrap_pw_global.num) {
3548 errno = ENOENT;
3549 return NULL;
3552 pw = &nwrap_pw_global.list[nwrap_pw_global.idx++];
3554 NWRAP_LOG(NWRAP_LOG_DEBUG,
3555 "return user[%s] uid[%u]",
3556 pw->pw_name, pw->pw_uid);
3558 return pw;
3561 static int nwrap_files_getpwent_r(struct nwrap_backend *b,
3562 struct passwd *pwdst, char *buf,
3563 size_t buflen, struct passwd **pwdstp)
3565 struct passwd *pw;
3567 pw = nwrap_files_getpwent(b);
3568 if (!pw) {
3569 if (errno == 0) {
3570 return ENOENT;
3572 return errno;
3575 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
3578 static void nwrap_files_endpwent(struct nwrap_backend *b)
3580 (void) b; /* unused */
3582 nwrap_pw_global.idx = 0;
3585 /* shadow */
3587 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
3589 #ifdef HAVE_SETSPENT
3590 static void nwrap_files_setspent(void)
3592 nwrap_sp_global.idx = 0;
3595 static struct spwd *nwrap_files_getspent(void)
3597 struct spwd *sp;
3599 if (nwrap_sp_global.idx == 0) {
3600 bool ok;
3602 ok = nwrap_files_cache_reload(nwrap_sp_global.cache);
3603 if (!ok) {
3604 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading shadow file");
3605 return NULL;
3609 if (nwrap_sp_global.idx >= nwrap_sp_global.num) {
3610 errno = ENOENT;
3611 return NULL;
3614 sp = &nwrap_sp_global.list[nwrap_sp_global.idx++];
3616 NWRAP_LOG(NWRAP_LOG_DEBUG,
3617 "return user[%s]",
3618 sp->sp_namp);
3620 return sp;
3623 static void nwrap_files_endspent(void)
3625 nwrap_sp_global.idx = 0;
3627 #endif /* HAVE_SETSPENT */
3629 static struct spwd *nwrap_files_getspnam(const char *name)
3631 int i;
3632 bool ok;
3634 NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name);
3636 ok = nwrap_files_cache_reload(nwrap_sp_global.cache);
3637 if (!ok) {
3638 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading shadow file");
3639 return NULL;
3642 for (i=0; i<nwrap_sp_global.num; i++) {
3643 if (strcmp(nwrap_sp_global.list[i].sp_namp, name) == 0) {
3644 NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] found", name);
3645 return &nwrap_sp_global.list[i];
3647 NWRAP_LOG(NWRAP_LOG_DEBUG,
3648 "user[%s] does not match [%s]",
3649 name,
3650 nwrap_sp_global.list[i].sp_namp);
3653 NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] not found\n", name);
3655 errno = ENOENT;
3656 return NULL;
3658 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
3660 /* misc functions */
3661 static int nwrap_files_initgroups_dyn(struct nwrap_backend *b,
3662 const char *user,
3663 gid_t group,
3664 long int *start,
3665 long int *size,
3666 gid_t **groups,
3667 long int limit,
3668 int *errnop)
3670 struct group *grp;
3671 int i = 0;
3673 (void)errnop; /* unused */
3674 nwrap_files_setgrent(b);
3675 while ((grp = nwrap_files_getgrent(b)) != NULL) {
3676 NWRAP_LOG(NWRAP_LOG_DEBUG,
3677 "Inspecting %s for group membership",
3678 grp->gr_name);
3680 for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
3681 if (group != grp->gr_gid &&
3682 (strcmp(user, grp->gr_mem[i]) == 0)) {
3683 NWRAP_LOG(NWRAP_LOG_DEBUG,
3684 "%s is member of %s",
3685 user,
3686 grp->gr_name);
3688 if (*start == *size) {
3689 long int newsize;
3690 gid_t *newgroups;
3692 newsize = 2 * (*size);
3693 if (limit > 0 && newsize > limit) {
3694 newsize = MAX(limit, *size);
3696 newgroups = (gid_t *) realloc((*groups),
3697 newsize * sizeof(**groups));
3698 if (!newgroups) {
3699 errno = ENOMEM;
3700 return -1;
3702 *groups = newgroups;
3703 *size = newsize;
3705 (*groups)[*start] = grp->gr_gid;
3706 (*start)++;
3711 nwrap_files_endgrent(b);
3712 return *start;
3715 /* group functions */
3716 static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
3717 const char *name)
3719 int i;
3720 bool ok;
3722 (void) b; /* unused */
3724 ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
3725 if (!ok) {
3726 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
3727 return NULL;
3730 for (i=0; i<nwrap_gr_global.num; i++) {
3731 if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) {
3732 NWRAP_LOG(NWRAP_LOG_DEBUG, "group[%s] found", name);
3733 return &nwrap_gr_global.list[i];
3735 NWRAP_LOG(NWRAP_LOG_DEBUG,
3736 "group[%s] does not match [%s]",
3737 name,
3738 nwrap_gr_global.list[i].gr_name);
3741 NWRAP_LOG(NWRAP_LOG_DEBUG, "group[%s] not found", name);
3743 errno = ENOENT;
3744 return NULL;
3747 static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
3748 const char *name, struct group *grdst,
3749 char *buf, size_t buflen, struct group **grdstp)
3751 struct group *gr;
3753 gr = nwrap_files_getgrnam(b, name);
3754 if (!gr) {
3755 if (errno == 0) {
3756 return ENOENT;
3758 return errno;
3761 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
3764 static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
3765 gid_t gid)
3767 int i;
3768 bool ok;
3770 (void) b; /* unused */
3772 ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
3773 if (!ok) {
3774 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
3775 return NULL;
3778 for (i=0; i<nwrap_gr_global.num; i++) {
3779 if (nwrap_gr_global.list[i].gr_gid == gid) {
3780 NWRAP_LOG(NWRAP_LOG_DEBUG, "gid[%u] found", gid);
3781 return &nwrap_gr_global.list[i];
3783 NWRAP_LOG(NWRAP_LOG_DEBUG,
3784 "gid[%u] does not match [%u]",
3785 gid,
3786 nwrap_gr_global.list[i].gr_gid);
3789 NWRAP_LOG(NWRAP_LOG_DEBUG, "gid[%u] not found", gid);
3791 errno = ENOENT;
3792 return NULL;
3795 static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
3796 gid_t gid, struct group *grdst,
3797 char *buf, size_t buflen, struct group **grdstp)
3799 struct group *gr;
3801 gr = nwrap_files_getgrgid(b, gid);
3802 if (!gr) {
3803 if (errno == 0) {
3804 return ENOENT;
3806 return errno;
3809 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
3812 /* group enum functions */
3813 static void nwrap_files_setgrent(struct nwrap_backend *b)
3815 (void) b; /* unused */
3817 nwrap_gr_global.idx = 0;
3820 static struct group *nwrap_files_getgrent(struct nwrap_backend *b)
3822 struct group *gr;
3824 (void) b; /* unused */
3826 if (nwrap_gr_global.idx == 0) {
3827 bool ok;
3829 ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
3830 if (!ok) {
3831 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
3832 return NULL;
3836 if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
3837 errno = ENOENT;
3838 return NULL;
3841 gr = &nwrap_gr_global.list[nwrap_gr_global.idx++];
3843 NWRAP_LOG(NWRAP_LOG_DEBUG,
3844 "return group[%s] gid[%u]",
3845 gr->gr_name, gr->gr_gid);
3847 return gr;
3850 static int nwrap_files_getgrent_r(struct nwrap_backend *b,
3851 struct group *grdst, char *buf,
3852 size_t buflen, struct group **grdstp)
3854 struct group *gr;
3856 gr = nwrap_files_getgrent(b);
3857 if (!gr) {
3858 if (errno == 0) {
3859 return ENOENT;
3861 return errno;
3864 return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
3867 static void nwrap_files_endgrent(struct nwrap_backend *b)
3869 (void) b; /* unused */
3871 nwrap_gr_global.idx = 0;
3874 /* hosts functions */
3875 static int nwrap_files_internal_gethostbyname(const char *name, int af,
3876 struct hostent *result,
3877 struct nwrap_vector *addr_list)
3879 struct nwrap_entlist *el;
3880 struct hostent *he;
3881 char *h_name_lower;
3882 ENTRY e;
3883 ENTRY *e_p;
3884 char canon_name[DNS_NAME_MAX] = { 0 };
3885 size_t name_len;
3886 bool he_found = false;
3887 bool ok;
3890 * We need to make sure we have zeroed return pointer for consumers
3891 * which don't check return values, e.g. OpenLDAP.
3893 ZERO_STRUCTP(result);
3895 ok = nwrap_files_cache_reload(nwrap_he_global.cache);
3896 if (!ok) {
3897 NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
3898 goto no_ent;
3901 name_len = strlen(name);
3902 if (name_len < sizeof(canon_name) && name[name_len - 1] == '.') {
3903 memcpy(canon_name, name, name_len - 1);
3904 canon_name[name_len] = '\0';
3905 name = canon_name;
3908 if (!str_tolower_copy(&h_name_lower, name)) {
3909 NWRAP_LOG(NWRAP_LOG_DEBUG,
3910 "Out of memory while converting to lower case");
3911 goto no_ent;
3914 /* Look at hash table for element */
3915 NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching for name: %s", h_name_lower);
3916 e.key = h_name_lower;
3917 e.data = NULL;
3918 e_p = hsearch(e, FIND);
3919 if (e_p == NULL) {
3920 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found.", h_name_lower);
3921 SAFE_FREE(h_name_lower);
3922 goto no_ent;
3924 SAFE_FREE(h_name_lower);
3926 /* Always cleanup vector and results */
3927 if (!nwrap_vector_is_initialized(addr_list)) {
3928 if (!nwrap_vector_init(addr_list)) {
3929 NWRAP_LOG(NWRAP_LOG_DEBUG,
3930 "Unable to initialize memory for addr_list vector");
3931 goto no_ent;
3933 } else {
3934 /* When vector is initialized data are valid no more.
3935 * Quick way how to free vector is: */
3936 addr_list->count = 0;
3939 /* Iterate through results */
3940 for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next)
3942 he = &(el->ed->ht);
3944 /* Filter by address familiy if provided */
3945 if (af != AF_UNSPEC && he->h_addrtype != af) {
3946 continue;
3950 * GLIBC HACK?
3951 * glibc doesn't return ipv6 addresses when AF_UNSPEC is used
3953 if (af == AF_UNSPEC && he->h_addrtype != AF_INET) {
3954 continue;
3957 if (!he_found) {
3958 memcpy(result, he, sizeof(struct hostent));
3959 NWRAP_LOG(NWRAP_LOG_DEBUG,
3960 "Name found. Returning record for %s",
3961 he->h_name);
3962 he_found = true;
3964 nwrap_vector_merge(addr_list, &el->ed->nwrap_addrdata);
3965 result->h_addr_list = nwrap_vector_head(addr_list);
3968 if (he_found) {
3969 return 0;
3971 NWRAP_LOG(NWRAP_LOG_DEBUG,
3972 "Name found in database. No records matches type.");
3974 no_ent:
3975 errno = ENOENT;
3976 return -1;
3979 static int nwrap_files_gethostbyname2_r(struct nwrap_backend *b,
3980 const char *name, int af,
3981 struct hostent *hedst,
3982 char *buf, size_t buflen,
3983 struct hostent **hedstp)
3985 struct nwrap_vector *addr_list = NULL;
3986 union {
3987 char *ptr;
3988 char **list;
3989 } g;
3990 int rc;
3992 (void) b; /* unused */
3993 (void) af; /* unused */
3995 if (name == NULL || hedst == NULL || buf == NULL || buflen == 0) {
3996 errno = EINVAL;
3997 return -1;
3999 *hedstp = NULL;
4000 buf[0] = '\0';
4002 addr_list = calloc(1, sizeof(struct nwrap_vector));
4003 if (addr_list == NULL) {
4004 NWRAP_LOG(NWRAP_LOG_ERROR,
4005 "Unable to allocate memory for address list");
4006 errno = ENOENT;
4007 return -1;
4010 rc = nwrap_files_internal_gethostbyname(name, af, hedst,
4011 addr_list);
4012 if (rc == -1) {
4013 SAFE_FREE(addr_list->items);
4014 SAFE_FREE(addr_list);
4015 errno = ENOENT;
4016 return -1;
4019 /* +1 i for ending NULL pointer */
4020 if (buflen < ((addr_list->count + 1) * sizeof(void *))) {
4021 SAFE_FREE(addr_list->items);
4022 SAFE_FREE(addr_list);
4023 return ERANGE;
4026 /* Copy all to user provided buffer and change
4027 * pointers in returned structure.
4028 * +1 is for ending NULL pointer. */
4029 memcpy(buf, addr_list->items, (addr_list->count + 1) * sizeof(void *));
4031 SAFE_FREE(addr_list->items);
4032 SAFE_FREE(addr_list);
4034 g.ptr = buf;
4035 hedst->h_addr_list = g.list;
4036 *hedstp = hedst;
4037 return 0;
4040 #ifdef HAVE_GETHOSTBYNAME_R
4041 static int nwrap_gethostbyname_r(const char *name,
4042 struct hostent *ret,
4043 char *buf, size_t buflen,
4044 struct hostent **result, int *h_errnop)
4046 int rc;
4047 size_t i;
4049 for (i=0; i < nwrap_main_global->num_backends; i++) {
4050 struct nwrap_backend *b = &nwrap_main_global->backends[i];
4051 rc = b->ops->nw_gethostbyname2_r(b, name, AF_UNSPEC, ret,
4052 buf, buflen, result);
4053 if (rc == 0) {
4054 return 0;
4055 } else if (rc == ERANGE) {
4056 return ERANGE;
4059 *h_errnop = h_errno;
4060 return ENOENT;
4063 int gethostbyname_r(const char *name,
4064 struct hostent *ret,
4065 char *buf, size_t buflen,
4066 struct hostent **result, int *h_errnop)
4068 if (!nss_wrapper_hosts_enabled()) {
4069 return libc_gethostbyname_r(name,
4070 ret,
4071 buf,
4072 buflen,
4073 result,
4074 h_errnop);
4077 return nwrap_gethostbyname_r(name, ret, buf, buflen, result, h_errnop);
4079 #endif
4081 #ifdef HAVE_GETHOSTBYNAME2_R
4082 static int nwrap_gethostbyname2_r(const char *name, int af,
4083 struct hostent *ret,
4084 char *buf, size_t buflen,
4085 struct hostent **result, int *h_errnop)
4087 int rc;
4088 size_t i;
4090 for (i=0; i < nwrap_main_global->num_backends; i++) {
4091 struct nwrap_backend *b = &nwrap_main_global->backends[i];
4092 rc = b->ops->nw_gethostbyname2_r(b, name, af, ret,
4093 buf, buflen, result);
4094 if (rc == 0) {
4095 return 0;
4096 } else if (rc == ERANGE) {
4097 return ERANGE;
4100 *h_errnop = h_errno;
4101 return ENOENT;
4104 int gethostbyname2_r(const char *name, int af,
4105 struct hostent *ret,
4106 char *buf, size_t buflen,
4107 struct hostent **result, int *h_errnop)
4109 if (!nss_wrapper_hosts_enabled()) {
4110 return libc_gethostbyname2_r(name, af, ret, buf, buflen,
4111 result, h_errnop);
4114 return nwrap_gethostbyname2_r(name, af, ret, buf, buflen, result,
4115 h_errnop);
4117 #endif
4119 static int nwrap_files_getaddrinfo(const char *name,
4120 unsigned short port,
4121 const struct addrinfo *hints,
4122 struct addrinfo **ai)
4124 struct nwrap_entlist *el;
4125 struct hostent *he;
4126 struct addrinfo *ai_head = NULL;
4127 struct addrinfo *ai_cur = NULL;
4128 char *h_name_lower;
4129 size_t name_len;
4130 char canon_name[DNS_NAME_MAX] = { 0 };
4131 bool skip_canonname = false;
4132 ENTRY e = {
4133 .key = NULL,
4135 ENTRY *e_p = NULL;
4136 int rc;
4137 bool ok;
4139 ok = nwrap_files_cache_reload(nwrap_he_global.cache);
4140 if (!ok) {
4141 NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
4142 return EAI_SYSTEM;
4145 name_len = strlen(name);
4146 if (name_len == 0) {
4147 return EAI_NONAME;
4150 if (name_len < sizeof(canon_name) && name[name_len - 1] == '.') {
4151 memcpy(canon_name, name, name_len - 1);
4152 canon_name[name_len] = '\0';
4153 name = canon_name;
4156 if (!str_tolower_copy(&h_name_lower, name)) {
4157 NWRAP_LOG(NWRAP_LOG_DEBUG,
4158 "Out of memory while converting to lower case");
4159 return EAI_MEMORY;
4162 NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching for name: %s", h_name_lower);
4163 e.key = h_name_lower;
4164 e.data = NULL;
4165 e_p = hsearch(e, FIND);
4166 if (e_p == NULL) {
4167 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found.", h_name_lower);
4168 SAFE_FREE(h_name_lower);
4169 errno = ENOENT;
4170 return EAI_NONAME;
4172 NWRAP_LOG(NWRAP_LOG_DEBUG, "Name: %s found.", h_name_lower);
4173 SAFE_FREE(h_name_lower);
4175 rc = EAI_NONAME;
4176 for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next)
4178 int rc2;
4179 struct addrinfo *ai_new = NULL;
4181 he = &(el->ed->ht);
4183 if (hints->ai_family != AF_UNSPEC &&
4184 he->h_addrtype != hints->ai_family)
4186 NWRAP_LOG(NWRAP_LOG_DEBUG,
4187 "Entry found but with wrong AF - "
4188 "remembering EAI_ADDRINFO.");
4189 rc = EAI_ADDRFAMILY;
4190 continue;
4193 /* Function allocates memory and returns it in ai. */
4194 rc2 = nwrap_convert_he_ai(he,
4195 port,
4196 hints,
4197 &ai_new,
4198 skip_canonname);
4199 if (rc2 != 0) {
4200 NWRAP_LOG(NWRAP_LOG_ERROR, "Error converting he to ai");
4201 if (ai_head != NULL) {
4202 freeaddrinfo(ai_head);
4204 return rc2;
4206 skip_canonname = true;
4208 if (ai_head == NULL) {
4209 ai_head = ai_new;
4211 if (ai_cur != NULL) {
4212 ai_cur->ai_next = ai_new;
4214 ai_cur = ai_new;
4217 if (ai_head != NULL) {
4218 rc = 0;
4221 *ai = ai_head;
4223 return rc;
4226 static struct hostent *nwrap_files_gethostbyaddr(struct nwrap_backend *b,
4227 const void *addr,
4228 socklen_t len, int type)
4230 struct hostent *he;
4231 char ip[NWRAP_INET_ADDRSTRLEN] = {0};
4232 struct nwrap_entdata *ed;
4233 const char *a;
4234 size_t i;
4235 bool ok;
4237 (void) b; /* unused */
4238 (void) len; /* unused */
4240 ok = nwrap_files_cache_reload(nwrap_he_global.cache);
4241 if (!ok) {
4242 NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
4243 return NULL;
4246 a = inet_ntop(type, addr, ip, sizeof(ip));
4247 if (a == NULL) {
4248 errno = EINVAL;
4249 return NULL;
4252 nwrap_vector_foreach(ed, nwrap_he_global.entries, i)
4254 he = &(ed->ht);
4255 if (he->h_addrtype != type) {
4256 continue;
4259 if (memcmp(addr, he->h_addr_list[0], he->h_length) == 0) {
4260 return he;
4264 errno = ENOENT;
4265 return NULL;
4268 #ifdef HAVE_GETHOSTBYADDR_R
4269 static int nwrap_gethostbyaddr_r(const void *addr, socklen_t len, int type,
4270 struct hostent *ret,
4271 char *buf, size_t buflen,
4272 struct hostent **result, int *h_errnop)
4274 size_t i;
4275 for (i=0; i < nwrap_main_global->num_backends; i++) {
4276 struct nwrap_backend *b = &nwrap_main_global->backends[i];
4277 *result = b->ops->nw_gethostbyaddr(b, addr, len, type);
4278 if (*result != NULL) {
4279 break;
4283 if (*result != NULL) {
4284 memset(buf, '\0', buflen);
4285 *ret = **result;
4286 return 0;
4289 *h_errnop = h_errno;
4290 return -1;
4293 int gethostbyaddr_r(const void *addr, socklen_t len, int type,
4294 struct hostent *ret,
4295 char *buf, size_t buflen,
4296 struct hostent **result, int *h_errnop)
4298 if (!nss_wrapper_hosts_enabled()) {
4299 return libc_gethostbyaddr_r(addr,
4300 len,
4301 type,
4302 ret,
4303 buf,
4304 buflen,
4305 result,
4306 h_errnop);
4309 return nwrap_gethostbyaddr_r(addr, len, type, ret, buf, buflen, result, h_errnop);
4311 #endif
4313 /* hosts enum functions */
4314 static void nwrap_files_sethostent(void)
4316 nwrap_he_global.idx = 0;
4319 static struct hostent *nwrap_files_gethostent(void)
4321 struct hostent *he;
4323 if (nwrap_he_global.idx == 0) {
4324 bool ok;
4326 ok = nwrap_files_cache_reload(nwrap_he_global.cache);
4327 if (!ok) {
4328 NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading hosts file");
4329 return NULL;
4333 if (nwrap_he_global.idx >= nwrap_he_global.num) {
4334 errno = ENOENT;
4335 return NULL;
4338 he = &((struct nwrap_entdata *)nwrap_he_global.entries.items[nwrap_he_global.idx++])->ht;
4340 NWRAP_LOG(NWRAP_LOG_DEBUG, "return hosts[%s]", he->h_name);
4342 return he;
4345 static void nwrap_files_endhostent(void)
4347 nwrap_he_global.idx = 0;
4351 * module backend
4355 static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
4356 const char *name)
4358 static struct passwd pwd;
4359 static char buf[1000];
4360 NSS_STATUS status;
4362 if (b->symbols->_nss_getpwnam_r.f == NULL) {
4363 return NULL;
4366 status = b->symbols->_nss_getpwnam_r.f(name,
4367 &pwd,
4368 buf,
4369 sizeof(buf),
4370 &errno);
4371 if (status == NSS_STATUS_NOTFOUND) {
4372 return NULL;
4374 if (status != NSS_STATUS_SUCCESS) {
4375 return NULL;
4378 return &pwd;
4381 static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
4382 const char *name, struct passwd *pwdst,
4383 char *buf, size_t buflen, struct passwd **pwdstp)
4385 int ret;
4387 *pwdstp = NULL;
4389 if (b->symbols->_nss_getpwnam_r.f == NULL) {
4390 return NSS_STATUS_NOTFOUND;
4393 ret = b->symbols->_nss_getpwnam_r.f(name, pwdst, buf, buflen, &errno);
4394 switch (ret) {
4395 case NSS_STATUS_SUCCESS:
4396 *pwdstp = pwdst;
4397 return 0;
4398 case NSS_STATUS_NOTFOUND:
4399 if (errno != 0) {
4400 return errno;
4402 return ENOENT;
4403 case NSS_STATUS_TRYAGAIN:
4404 if (errno != 0) {
4405 return errno;
4407 return ERANGE;
4408 default:
4409 if (errno != 0) {
4410 return errno;
4412 return ret;
4416 static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
4417 uid_t uid)
4419 static struct passwd pwd;
4420 static char buf[1000];
4421 NSS_STATUS status;
4423 if (b->symbols->_nss_getpwuid_r.f == NULL) {
4424 return NULL;
4427 status = b->symbols->_nss_getpwuid_r.f(uid,
4428 &pwd,
4429 buf,
4430 sizeof(buf),
4431 &errno);
4432 if (status == NSS_STATUS_NOTFOUND) {
4433 return NULL;
4435 if (status != NSS_STATUS_SUCCESS) {
4436 return NULL;
4438 return &pwd;
4441 static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
4442 uid_t uid, struct passwd *pwdst,
4443 char *buf, size_t buflen, struct passwd **pwdstp)
4445 int ret;
4447 *pwdstp = NULL;
4449 if (b->symbols->_nss_getpwuid_r.f == NULL) {
4450 return ENOENT;
4453 ret = b->symbols->_nss_getpwuid_r.f(uid, pwdst, buf, buflen, &errno);
4454 switch (ret) {
4455 case NSS_STATUS_SUCCESS:
4456 *pwdstp = pwdst;
4457 return 0;
4458 case NSS_STATUS_NOTFOUND:
4459 if (errno != 0) {
4460 return errno;
4462 return ENOENT;
4463 case NSS_STATUS_TRYAGAIN:
4464 if (errno != 0) {
4465 return errno;
4467 return ERANGE;
4468 default:
4469 if (errno != 0) {
4470 return errno;
4472 return ret;
4476 static void nwrap_module_setpwent(struct nwrap_backend *b)
4478 if (b->symbols->_nss_setpwent.f == NULL) {
4479 return;
4482 b->symbols->_nss_setpwent.f();
4485 static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b)
4487 static struct passwd pwd;
4488 static char buf[1000];
4489 NSS_STATUS status;
4491 if (b->symbols->_nss_getpwent_r.f == NULL) {
4492 return NULL;
4495 status = b->symbols->_nss_getpwent_r.f(&pwd, buf, sizeof(buf), &errno);
4496 if (status == NSS_STATUS_NOTFOUND) {
4497 return NULL;
4499 if (status != NSS_STATUS_SUCCESS) {
4500 return NULL;
4502 return &pwd;
4505 static int nwrap_module_getpwent_r(struct nwrap_backend *b,
4506 struct passwd *pwdst, char *buf,
4507 size_t buflen, struct passwd **pwdstp)
4509 int ret;
4511 *pwdstp = NULL;
4513 if (b->symbols->_nss_getpwent_r.f == NULL) {
4514 return ENOENT;
4517 ret = b->symbols->_nss_getpwent_r.f(pwdst, buf, buflen, &errno);
4518 switch (ret) {
4519 case NSS_STATUS_SUCCESS:
4520 *pwdstp = pwdst;
4521 return 0;
4522 case NSS_STATUS_NOTFOUND:
4523 if (errno != 0) {
4524 return errno;
4526 return ENOENT;
4527 case NSS_STATUS_TRYAGAIN:
4528 if (errno != 0) {
4529 return errno;
4531 return ERANGE;
4532 default:
4533 if (errno != 0) {
4534 return errno;
4536 return ret;
4540 static void nwrap_module_endpwent(struct nwrap_backend *b)
4542 if (b->symbols->_nss_endpwent.f == NULL) {
4543 return;
4546 b->symbols->_nss_endpwent.f();
4549 static int nwrap_module_initgroups_dyn(struct nwrap_backend *b,
4550 const char *user,
4551 gid_t group,
4552 long int *start,
4553 long int *size,
4554 gid_t **groups,
4555 long int limit,
4556 int *errnop)
4558 if (b->symbols->_nss_initgroups_dyn.f == NULL) {
4559 return NSS_STATUS_UNAVAIL;
4562 return b->symbols->_nss_initgroups_dyn.f(user,
4563 group,
4564 start,
4565 size,
4566 groups,
4567 limit,
4568 errnop);
4571 static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
4572 const char *name)
4574 static struct group grp;
4575 static char *buf;
4576 static int buflen = 1000;
4577 NSS_STATUS status;
4579 if (b->symbols->_nss_getgrnam_r.f == NULL) {
4580 return NULL;
4583 if (!buf) {
4584 buf = (char *)malloc(buflen);
4586 again:
4587 status = b->symbols->_nss_getgrnam_r.f(name, &grp, buf, buflen, &errno);
4588 if (status == NSS_STATUS_TRYAGAIN) {
4589 buflen *= 2;
4590 buf = (char *)realloc(buf, buflen);
4591 if (!buf) {
4592 return NULL;
4594 goto again;
4596 if (status == NSS_STATUS_NOTFOUND) {
4597 SAFE_FREE(buf);
4598 return NULL;
4600 if (status != NSS_STATUS_SUCCESS) {
4601 SAFE_FREE(buf);
4602 return NULL;
4604 return &grp;
4607 static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
4608 const char *name, struct group *grdst,
4609 char *buf, size_t buflen, struct group **grdstp)
4611 int ret;
4613 *grdstp = NULL;
4615 if (b->symbols->_nss_getgrnam_r.f == NULL) {
4616 return ENOENT;
4619 ret = b->symbols->_nss_getgrnam_r.f(name, grdst, buf, buflen, &errno);
4620 switch (ret) {
4621 case NSS_STATUS_SUCCESS:
4622 *grdstp = grdst;
4623 return 0;
4624 case NSS_STATUS_NOTFOUND:
4625 if (errno != 0) {
4626 return errno;
4628 return ENOENT;
4629 case NSS_STATUS_TRYAGAIN:
4630 if (errno != 0) {
4631 return errno;
4633 return ERANGE;
4634 default:
4635 if (errno != 0) {
4636 return errno;
4638 return ret;
4642 static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
4643 gid_t gid)
4645 static struct group grp;
4646 static char *buf;
4647 static int buflen = 1000;
4648 NSS_STATUS status;
4650 if (b->symbols->_nss_getgrgid_r.f == NULL) {
4651 return NULL;
4654 if (!buf) {
4655 buf = (char *)malloc(buflen);
4658 again:
4659 status = b->symbols->_nss_getgrgid_r.f(gid, &grp, buf, buflen, &errno);
4660 if (status == NSS_STATUS_TRYAGAIN) {
4661 buflen *= 2;
4662 buf = (char *)realloc(buf, buflen);
4663 if (!buf) {
4664 return NULL;
4666 goto again;
4668 if (status == NSS_STATUS_NOTFOUND) {
4669 SAFE_FREE(buf);
4670 return NULL;
4672 if (status != NSS_STATUS_SUCCESS) {
4673 SAFE_FREE(buf);
4674 return NULL;
4676 return &grp;
4679 static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
4680 gid_t gid, struct group *grdst,
4681 char *buf, size_t buflen, struct group **grdstp)
4683 int ret;
4685 *grdstp = NULL;
4687 if (b->symbols->_nss_getgrgid_r.f == NULL) {
4688 return ENOENT;
4691 ret = b->symbols->_nss_getgrgid_r.f(gid, grdst, buf, buflen, &errno);
4692 switch (ret) {
4693 case NSS_STATUS_SUCCESS:
4694 *grdstp = grdst;
4695 return 0;
4696 case NSS_STATUS_NOTFOUND:
4697 if (errno != 0) {
4698 return errno;
4700 return ENOENT;
4701 case NSS_STATUS_TRYAGAIN:
4702 if (errno != 0) {
4703 return errno;
4705 return ERANGE;
4706 default:
4707 if (errno != 0) {
4708 return errno;
4710 return ret;
4714 static void nwrap_module_setgrent(struct nwrap_backend *b)
4716 if (b->symbols->_nss_setgrent.f == NULL) {
4717 return;
4720 b->symbols->_nss_setgrent.f();
4723 static struct group *nwrap_module_getgrent(struct nwrap_backend *b)
4725 static struct group grp;
4726 static char *buf;
4727 static int buflen = 1024;
4728 NSS_STATUS status;
4730 if (b->symbols->_nss_getgrent_r.f == NULL) {
4731 return NULL;
4734 if (!buf) {
4735 buf = (char *)malloc(buflen);
4738 again:
4739 status = b->symbols->_nss_getgrent_r.f(&grp, buf, buflen, &errno);
4740 if (status == NSS_STATUS_TRYAGAIN) {
4741 buflen *= 2;
4742 buf = (char *)realloc(buf, buflen);
4743 if (!buf) {
4744 return NULL;
4746 goto again;
4748 if (status == NSS_STATUS_NOTFOUND) {
4749 SAFE_FREE(buf);
4750 return NULL;
4752 if (status != NSS_STATUS_SUCCESS) {
4753 SAFE_FREE(buf);
4754 return NULL;
4756 return &grp;
4759 static int nwrap_module_getgrent_r(struct nwrap_backend *b,
4760 struct group *grdst, char *buf,
4761 size_t buflen, struct group **grdstp)
4763 int ret;
4765 *grdstp = NULL;
4767 if (b->symbols->_nss_getgrent_r.f == NULL) {
4768 return ENOENT;
4771 ret = b->symbols->_nss_getgrent_r.f(grdst, buf, buflen, &errno);
4772 switch (ret) {
4773 case NSS_STATUS_SUCCESS:
4774 *grdstp = grdst;
4775 return 0;
4776 case NSS_STATUS_NOTFOUND:
4777 if (errno != 0) {
4778 return errno;
4780 return ENOENT;
4781 case NSS_STATUS_TRYAGAIN:
4782 if (errno != 0) {
4783 return errno;
4785 return ERANGE;
4786 default:
4787 if (errno != 0) {
4788 return errno;
4790 return ret;
4794 static void nwrap_module_endgrent(struct nwrap_backend *b)
4796 if (b->symbols->_nss_endgrent.f == NULL) {
4797 return;
4800 b->symbols->_nss_endgrent.f();
4803 static struct hostent *nwrap_module_gethostbyaddr(struct nwrap_backend *b,
4804 const void *addr,
4805 socklen_t len, int type)
4807 static struct hostent he;
4808 static char *buf = NULL;
4809 static size_t buflen = 1000;
4810 NSS_STATUS status;
4812 if (b->symbols->_nss_gethostbyaddr_r.f == NULL) {
4813 return NULL;
4816 if (buf == NULL) {
4817 buf = (char *)malloc(buflen);
4818 if (buf == NULL) {
4819 return NULL;
4822 again:
4823 status = b->symbols->_nss_gethostbyaddr_r.f(addr,
4824 len,
4825 type,
4826 &he,
4827 buf,
4828 buflen,
4829 &errno,
4830 &h_errno);
4831 if (status == NSS_STATUS_TRYAGAIN) {
4832 char *p = NULL;
4834 buflen *= 2;
4835 p = (char *)realloc(buf, buflen);
4836 if (p == NULL) {
4837 SAFE_FREE(buf);
4838 return NULL;
4840 buf = p;
4841 goto again;
4843 if (status == NSS_STATUS_NOTFOUND) {
4844 SAFE_FREE(buf);
4845 return NULL;
4847 if (status != NSS_STATUS_SUCCESS) {
4848 SAFE_FREE(buf);
4849 return NULL;
4852 return &he;
4855 static int nwrap_module_gethostbyname2_r(struct nwrap_backend *b,
4856 const char *name, int af,
4857 struct hostent *hedst,
4858 char *buf, size_t buflen,
4859 struct hostent **hedstp)
4861 NSS_STATUS status;
4863 *hedstp = NULL;
4865 if (b->symbols->_nss_gethostbyname2_r.f == NULL) {
4866 return ENOENT;
4869 status = b->symbols->_nss_gethostbyname2_r.f(name,
4871 hedst,
4872 buf,
4873 buflen,
4874 &errno,
4875 &h_errno);
4876 switch (status) {
4877 case NSS_STATUS_SUCCESS:
4878 *hedstp = hedst;
4879 return 0;
4880 case NSS_STATUS_NOTFOUND:
4881 if (errno != 0) {
4882 return errno;
4884 return ENOENT;
4885 case NSS_STATUS_TRYAGAIN:
4886 if (errno != 0) {
4887 return errno;
4889 return ERANGE;
4890 default:
4891 if (errno != 0) {
4892 return errno;
4894 return status;
4898 static struct hostent *nwrap_module_gethostbyname(struct nwrap_backend *b,
4899 const char *name)
4901 static struct hostent he;
4902 static char *buf = NULL;
4903 static size_t buflen = 1000;
4904 NSS_STATUS status;
4906 if (b->symbols->_nss_gethostbyname2_r.f == NULL) {
4907 return NULL;
4910 if (buf == NULL) {
4911 buf = (char *)malloc(buflen);
4912 if (buf == NULL) {
4913 return NULL;
4917 again:
4918 status = b->symbols->_nss_gethostbyname2_r.f(name,
4919 AF_UNSPEC,
4920 &he,
4921 buf,
4922 buflen,
4923 &errno,
4924 &h_errno);
4925 if (status == NSS_STATUS_TRYAGAIN) {
4926 char *p = NULL;
4928 buflen *= 2;
4929 p = (char *)realloc(buf, buflen);
4930 if (p == NULL) {
4931 SAFE_FREE(buf);
4932 return NULL;
4934 buf = p;
4935 goto again;
4937 if (status == NSS_STATUS_NOTFOUND) {
4938 SAFE_FREE(buf);
4939 return NULL;
4941 if (status != NSS_STATUS_SUCCESS) {
4942 SAFE_FREE(buf);
4943 return NULL;
4946 return &he;
4949 static struct hostent *nwrap_module_gethostbyname2(struct nwrap_backend *b,
4950 const char *name, int af)
4952 static struct hostent he;
4953 static char *buf = NULL;
4954 static size_t buflen = 1000;
4955 NSS_STATUS status;
4957 if (b->symbols->_nss_gethostbyname2_r.f == NULL) {
4958 return NULL;
4961 if (buf == NULL) {
4962 buf = (char *)malloc(buflen);
4963 if (buf == NULL) {
4964 return NULL;
4968 again:
4969 status = b->symbols->_nss_gethostbyname2_r.f(name,
4971 &he,
4972 buf,
4973 buflen,
4974 &errno,
4975 &h_errno);
4976 if (status == NSS_STATUS_TRYAGAIN) {
4977 char *p = NULL;
4979 buflen *= 2;
4980 p = (char *)realloc(buf, buflen);
4981 if (p == NULL) {
4982 SAFE_FREE(buf);
4983 return NULL;
4985 buf = p;
4986 goto again;
4988 if (status == NSS_STATUS_NOTFOUND) {
4989 SAFE_FREE(buf);
4990 return NULL;
4992 if (status != NSS_STATUS_SUCCESS) {
4993 SAFE_FREE(buf);
4994 return NULL;
4997 return &he;
5000 /****************************************************************************
5001 * GETPWNAM
5002 ***************************************************************************/
5004 static struct passwd *nwrap_getpwnam(const char *name)
5006 size_t i;
5007 struct passwd *pwd;
5009 for (i=0; i < nwrap_main_global->num_backends; i++) {
5010 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5011 pwd = b->ops->nw_getpwnam(b, name);
5012 if (pwd) {
5013 return pwd;
5017 return NULL;
5020 struct passwd *getpwnam(const char *name)
5022 if (!nss_wrapper_enabled()) {
5023 return libc_getpwnam(name);
5026 return nwrap_getpwnam(name);
5029 /****************************************************************************
5030 * GETPWNAM_R
5031 ***************************************************************************/
5033 static int nwrap_getpwnam_r(const char *name, struct passwd *pwdst,
5034 char *buf, size_t buflen, struct passwd **pwdstp)
5036 size_t i;
5037 int ret;
5039 for (i=0; i < nwrap_main_global->num_backends; i++) {
5040 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5041 ret = b->ops->nw_getpwnam_r(b, name, pwdst, buf, buflen, pwdstp);
5042 if (ret == ENOENT) {
5043 continue;
5045 return ret;
5048 return ENOENT;
5051 #ifdef HAVE_GETPWNAM_R
5052 # ifdef HAVE_SOLARIS_GETPWNAM_R
5053 int getpwnam_r(const char *name, struct passwd *pwdst,
5054 char *buf, int buflen, struct passwd **pwdstp)
5055 # else /* HAVE_SOLARIS_GETPWNAM_R */
5056 int getpwnam_r(const char *name, struct passwd *pwdst,
5057 char *buf, size_t buflen, struct passwd **pwdstp)
5058 # endif /* HAVE_SOLARIS_GETPWNAM_R */
5060 if (!nss_wrapper_enabled()) {
5061 return libc_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
5064 return nwrap_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
5066 #endif
5068 /****************************************************************************
5069 * GETPWUID
5070 ***************************************************************************/
5072 static struct passwd *nwrap_getpwuid(uid_t uid)
5074 size_t i;
5075 struct passwd *pwd;
5077 for (i=0; i < nwrap_main_global->num_backends; i++) {
5078 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5079 pwd = b->ops->nw_getpwuid(b, uid);
5080 if (pwd) {
5081 return pwd;
5085 return NULL;
5088 struct passwd *getpwuid(uid_t uid)
5090 if (!nss_wrapper_enabled()) {
5091 return libc_getpwuid(uid);
5094 return nwrap_getpwuid(uid);
5097 /****************************************************************************
5098 * GETPWUID_R
5099 ***************************************************************************/
5101 static int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst,
5102 char *buf, size_t buflen, struct passwd **pwdstp)
5104 size_t i;
5105 int ret;
5107 for (i=0; i < nwrap_main_global->num_backends; i++) {
5108 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5109 ret = b->ops->nw_getpwuid_r(b, uid, pwdst, buf, buflen, pwdstp);
5110 if (ret == ENOENT) {
5111 continue;
5113 return ret;
5116 return ENOENT;
5119 #ifdef HAVE_SOLARIS_GETPWUID_R
5120 int getpwuid_r(uid_t uid, struct passwd *pwdst,
5121 char *buf, int buflen, struct passwd **pwdstp)
5122 #else
5123 int getpwuid_r(uid_t uid, struct passwd *pwdst,
5124 char *buf, size_t buflen, struct passwd **pwdstp)
5125 #endif
5127 if (!nss_wrapper_enabled()) {
5128 return libc_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
5131 return nwrap_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
5134 /****************************************************************************
5135 * SETPWENT
5136 ***************************************************************************/
5138 static void nwrap_setpwent(void)
5140 size_t i;
5142 for (i=0; i < nwrap_main_global->num_backends; i++) {
5143 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5144 b->ops->nw_setpwent(b);
5148 void setpwent(void)
5150 if (!nss_wrapper_enabled()) {
5151 libc_setpwent();
5152 return;
5155 nwrap_setpwent();
5158 /****************************************************************************
5159 * GETPWENT
5160 ***************************************************************************/
5162 static struct passwd *nwrap_getpwent(void)
5164 size_t i;
5165 struct passwd *pwd;
5167 for (i=0; i < nwrap_main_global->num_backends; i++) {
5168 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5169 pwd = b->ops->nw_getpwent(b);
5170 if (pwd) {
5171 return pwd;
5175 return NULL;
5178 struct passwd *getpwent(void)
5180 if (!nss_wrapper_enabled()) {
5181 return libc_getpwent();
5184 return nwrap_getpwent();
5187 /****************************************************************************
5188 * GETPWENT_R
5189 ***************************************************************************/
5191 #ifdef HAVE_GETPWENT_R
5192 static int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
5193 size_t buflen, struct passwd **pwdstp)
5195 size_t i;
5196 int ret;
5198 for (i=0; i < nwrap_main_global->num_backends; i++) {
5199 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5200 ret = b->ops->nw_getpwent_r(b, pwdst, buf, buflen, pwdstp);
5201 if (ret == ENOENT) {
5202 continue;
5204 return ret;
5207 return ENOENT;
5210 # ifdef HAVE_SOLARIS_GETPWENT_R
5211 struct passwd *getpwent_r(struct passwd *pwdst, char *buf, int buflen)
5213 struct passwd *pwdstp = NULL;
5214 int rc;
5216 if (!nss_wrapper_enabled()) {
5217 return libc_getpwent_r(pwdst, buf, buflen);
5219 rc = nwrap_getpwent_r(pwdst, buf, buflen, &pwdstp);
5220 if (rc < 0) {
5221 return NULL;
5224 return pwdstp;
5226 # else /* HAVE_SOLARIS_GETPWENT_R */
5227 int getpwent_r(struct passwd *pwdst, char *buf,
5228 size_t buflen, struct passwd **pwdstp)
5230 if (!nss_wrapper_enabled()) {
5231 return libc_getpwent_r(pwdst, buf, buflen, pwdstp);
5234 return nwrap_getpwent_r(pwdst, buf, buflen, pwdstp);
5236 # endif /* HAVE_SOLARIS_GETPWENT_R */
5237 #endif /* HAVE_GETPWENT_R */
5239 /****************************************************************************
5240 * ENDPWENT
5241 ***************************************************************************/
5243 static void nwrap_endpwent(void)
5245 size_t i;
5247 for (i=0; i < nwrap_main_global->num_backends; i++) {
5248 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5249 b->ops->nw_endpwent(b);
5253 void endpwent(void)
5255 if (!nss_wrapper_enabled()) {
5256 libc_endpwent();
5257 return;
5260 nwrap_endpwent();
5263 /****************************************************************************
5264 * INITGROUPS
5265 ***************************************************************************/
5267 static int nwrap_initgroups(const char *user, gid_t group)
5269 #if defined(NGROUPS_MAX) && NGROUPS_MAX == 0
5270 /* No extra groups allowed. */
5271 return 0;
5272 #elif !defined(HAVE_GETGROUPLIST)
5273 return 0;
5274 #else
5275 long int size;
5276 long int limit;
5277 gid_t *groups;
5278 int ngroups;
5279 int result;
5280 const char *env = getenv("UID_WRAPPER");
5282 if (env == NULL || env[0] != '1') {
5283 NWRAP_LOG(NWRAP_LOG_WARN,
5284 "initgroups() requires uid_wrapper to work!");
5285 return 0;
5288 limit = sysconf(_SC_NGROUPS_MAX);
5289 if (limit > 0) {
5290 size = MIN(limit, 64);
5291 } else {
5292 size = 16;
5295 groups = (gid_t *)malloc(size * sizeof(gid_t));
5296 if (groups == NULL) {
5297 /* No more memory. */
5298 return -1;
5301 ngroups = nwrap_getgrouplist(user, group, &size, &groups, limit);
5303 /* Try to set the maximum number of groups the kernel can handle. */
5304 do {
5305 result = setgroups(ngroups, groups);
5306 } while (result == -1 && errno == EINVAL && --ngroups > 0);
5308 free(groups);
5310 return result;
5311 #endif
5314 int initgroups(const char *user, gid_t group)
5316 if (!nss_wrapper_enabled()) {
5317 return libc_initgroups(user, group);
5320 return nwrap_initgroups(user, group);
5323 /****************************************************************************
5324 * GETGRNAM
5325 ***************************************************************************/
5327 static struct group *nwrap_getgrnam(const char *name)
5329 size_t i;
5330 struct group *grp;
5332 for (i=0; i < nwrap_main_global->num_backends; i++) {
5333 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5334 grp = b->ops->nw_getgrnam(b, name);
5335 if (grp) {
5336 return grp;
5340 return NULL;
5343 struct group *getgrnam(const char *name)
5345 if (!nss_wrapper_enabled()) {
5346 return libc_getgrnam(name);
5349 return nwrap_getgrnam(name);
5352 /****************************************************************************
5353 * GETGRNAM_R
5354 ***************************************************************************/
5356 static int nwrap_getgrnam_r(const char *name, struct group *grdst,
5357 char *buf, size_t buflen, struct group **grdstp)
5359 size_t i;
5360 int ret;
5362 for (i=0; i < nwrap_main_global->num_backends; i++) {
5363 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5364 ret = b->ops->nw_getgrnam_r(b, name, grdst, buf, buflen, grdstp);
5365 if (ret == ENOENT) {
5366 continue;
5368 return ret;
5371 return ENOENT;
5374 #ifdef HAVE_GETGRNAM_R
5375 # ifdef HAVE_SOLARIS_GETGRNAM_R
5376 int getgrnam_r(const char *name, struct group *grp,
5377 char *buf, int buflen, struct group **pgrp)
5378 # else /* HAVE_SOLARIS_GETGRNAM_R */
5379 int getgrnam_r(const char *name, struct group *grp,
5380 char *buf, size_t buflen, struct group **pgrp)
5381 # endif /* HAVE_SOLARIS_GETGRNAM_R */
5383 if (!nss_wrapper_enabled()) {
5384 return libc_getgrnam_r(name,
5385 grp,
5386 buf,
5387 buflen,
5388 pgrp);
5391 return nwrap_getgrnam_r(name, grp, buf, buflen, pgrp);
5393 #endif /* HAVE_GETGRNAM_R */
5395 /****************************************************************************
5396 * GETGRGID
5397 ***************************************************************************/
5399 static struct group *nwrap_getgrgid(gid_t gid)
5401 size_t i;
5402 struct group *grp;
5404 for (i=0; i < nwrap_main_global->num_backends; i++) {
5405 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5406 grp = b->ops->nw_getgrgid(b, gid);
5407 if (grp) {
5408 return grp;
5412 return NULL;
5415 struct group *getgrgid(gid_t gid)
5417 if (!nss_wrapper_enabled()) {
5418 return libc_getgrgid(gid);
5421 return nwrap_getgrgid(gid);
5424 /****************************************************************************
5425 * GETGRGID_R
5426 ***************************************************************************/
5428 static int nwrap_getgrgid_r(gid_t gid, struct group *grdst,
5429 char *buf, size_t buflen, struct group **grdstp)
5431 size_t i;
5432 int ret;
5434 for (i=0; i < nwrap_main_global->num_backends; i++) {
5435 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5436 ret = b->ops->nw_getgrgid_r(b, gid, grdst, buf, buflen, grdstp);
5437 if (ret == ENOENT) {
5438 continue;
5440 return ret;
5443 return ENOENT;
5446 #ifdef HAVE_GETGRGID_R
5447 # ifdef HAVE_SOLARIS_GETGRGID_R
5448 int getgrgid_r(gid_t gid, struct group *grdst,
5449 char *buf, int buflen, struct group **grdstp)
5450 # else /* HAVE_SOLARIS_GETGRGID_R */
5451 int getgrgid_r(gid_t gid, struct group *grdst,
5452 char *buf, size_t buflen, struct group **grdstp)
5453 # endif /* HAVE_SOLARIS_GETGRGID_R */
5455 if (!nss_wrapper_enabled()) {
5456 return libc_getgrgid_r(gid, grdst, buf, buflen, grdstp);
5459 return nwrap_getgrgid_r(gid, grdst, buf, buflen, grdstp);
5461 #endif
5463 /****************************************************************************
5464 * SETGRENT
5465 ***************************************************************************/
5467 static void nwrap_setgrent(void)
5469 size_t i;
5471 for (i=0; i < nwrap_main_global->num_backends; i++) {
5472 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5473 b->ops->nw_setgrent(b);
5477 #ifdef HAVE_BSD_SETGRENT
5478 int setgrent(void)
5479 #else
5480 void setgrent(void)
5481 #endif
5483 if (!nss_wrapper_enabled()) {
5484 libc_setgrent();
5485 goto out;
5488 nwrap_setgrent();
5490 out:
5491 #ifdef HAVE_BSD_SETGRENT
5492 return 0;
5493 #else
5494 return;
5495 #endif
5498 /****************************************************************************
5499 * GETGRENT
5500 ***************************************************************************/
5502 static struct group *nwrap_getgrent(void)
5504 size_t i;
5505 struct group *grp;
5507 for (i=0; i < nwrap_main_global->num_backends; i++) {
5508 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5509 grp = b->ops->nw_getgrent(b);
5510 if (grp) {
5511 return grp;
5515 return NULL;
5518 struct group *getgrent(void)
5520 if (!nss_wrapper_enabled()) {
5521 return libc_getgrent();
5524 return nwrap_getgrent();
5527 /****************************************************************************
5528 * GETGRENT_R
5529 ***************************************************************************/
5531 #ifdef HAVE_GETGRENT_R
5532 static int nwrap_getgrent_r(struct group *grdst, char *buf,
5533 size_t buflen, struct group **grdstp)
5535 size_t i;
5536 int ret;
5538 for (i=0; i < nwrap_main_global->num_backends; i++) {
5539 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5540 ret = b->ops->nw_getgrent_r(b, grdst, buf, buflen, grdstp);
5541 if (ret == ENOENT) {
5542 continue;
5544 return ret;
5547 return ENOENT;
5550 # ifdef HAVE_SOLARIS_GETGRENT_R
5551 struct group *getgrent_r(struct group *src, char *buf, int buflen)
5553 struct group *grdstp = NULL;
5554 int rc;
5556 if (!nss_wrapper_enabled()) {
5557 return libc_getgrent_r(src, buf, buflen);
5560 rc = nwrap_getgrent_r(src, buf, buflen, &grdstp);
5561 if (rc < 0) {
5562 return NULL;
5565 return grdstp;
5567 # else /* HAVE_SOLARIS_GETGRENT_R */
5568 int getgrent_r(struct group *src, char *buf,
5569 size_t buflen, struct group **grdstp)
5571 if (!nss_wrapper_enabled()) {
5572 return libc_getgrent_r(src, buf, buflen, grdstp);
5575 return nwrap_getgrent_r(src, buf, buflen, grdstp);
5577 # endif /* HAVE_SOLARIS_GETGRENT_R */
5578 #endif /* HAVE_GETGRENT_R */
5580 /****************************************************************************
5581 * ENDGRENT
5582 ***************************************************************************/
5584 static void nwrap_endgrent(void)
5586 size_t i;
5588 for (i=0; i < nwrap_main_global->num_backends; i++) {
5589 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5590 b->ops->nw_endgrent(b);
5594 void endgrent(void)
5596 if (!nss_wrapper_enabled()) {
5597 libc_endgrent();
5598 return;
5601 nwrap_endgrent();
5604 /****************************************************************************
5605 * GETGROUPLIST
5606 ***************************************************************************/
5608 #ifdef HAVE_GETGROUPLIST
5609 static int nwrap_getgrouplist(const char *user,
5610 gid_t group,
5611 long int *size,
5612 gid_t **groupsp,
5613 long int limit)
5615 enum nss_status status = NSS_STATUS_UNAVAIL;
5616 /* Start is one, because we have the first group as parameter. */
5617 long int start = 1;
5618 size_t i;
5620 /* Never store more than the starting *SIZE number of elements. */
5621 assert(*size > 0);
5622 (*groupsp)[0] = group;
5624 for (i = 0; i < nwrap_main_global->num_backends; i++) {
5625 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5626 long int prev_start = start;
5627 long int cnt = prev_start;
5629 status = b->ops->nw_initgroups_dyn(b,
5630 user,
5631 group,
5632 &start,
5633 size,
5634 groupsp,
5635 limit,
5636 &errno);
5638 /* Remove duplicates. */
5639 while (cnt < start) {
5640 long int inner;
5641 for (inner = 0; inner < prev_start; ++inner)
5642 if ((*groupsp)[inner] == (*groupsp)[cnt])
5643 break;
5645 if (inner < prev_start)
5646 (*groupsp)[cnt] = (*groupsp)[--start];
5647 else
5648 ++cnt;
5650 NWRAP_LOG(NWRAP_LOG_DEBUG,
5651 "Resource '%s' returned status=%d and increased "
5652 "count of groups to %ld",
5653 b->name,
5654 status,
5655 start);
5657 return start;
5660 int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
5662 long int size;
5663 int total, retval;
5664 gid_t *newgroups;
5666 if (!nss_wrapper_enabled()) {
5667 return libc_getgrouplist(user, group, groups, ngroups);
5670 size = MAX(1, *ngroups);
5671 newgroups = (gid_t *)malloc(size * sizeof(gid_t));
5672 if (newgroups == NULL) {
5673 return -1;
5676 total = nwrap_getgrouplist(user, group, &size, &newgroups, -1);
5678 if (groups != NULL) {
5679 memcpy(groups, newgroups, MIN(*ngroups, total) * sizeof(gid_t));
5682 free(newgroups);
5684 retval = total > *ngroups ? -1 : total;
5685 *ngroups = total;
5687 return retval;
5689 #endif
5691 /**********************************************************
5692 * SHADOW
5693 **********************************************************/
5695 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
5697 #ifdef HAVE_SETSPENT
5698 static void nwrap_setspent(void)
5700 nwrap_files_setspent();
5703 void setspent(void)
5705 if (!nss_wrapper_shadow_enabled()) {
5706 return;
5709 nwrap_setspent();
5712 static struct spwd *nwrap_getspent(void)
5714 return nwrap_files_getspent();
5717 struct spwd *getspent(void)
5719 if (!nss_wrapper_shadow_enabled()) {
5720 return NULL;
5723 return nwrap_getspent();
5726 static void nwrap_endspent(void)
5728 nwrap_files_endspent();
5731 void endspent(void)
5733 if (!nss_wrapper_shadow_enabled()) {
5734 return;
5737 nwrap_endspent();
5739 #endif /* HAVE_SETSPENT */
5741 static struct spwd *nwrap_getspnam(const char *name)
5743 return nwrap_files_getspnam(name);
5746 struct spwd *getspnam(const char *name)
5748 if (!nss_wrapper_shadow_enabled()) {
5749 return NULL;
5752 return nwrap_getspnam(name);
5755 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
5757 /**********************************************************
5758 * NETDB
5759 **********************************************************/
5761 static void nwrap_sethostent(int stayopen) {
5762 (void) stayopen; /* ignored */
5764 nwrap_files_sethostent();
5767 #ifdef HAVE_SOLARIS_SETHOSTENT
5768 int sethostent(int stayopen)
5770 if (!nss_wrapper_hosts_enabled()) {
5771 libc_sethostent(stayopen);
5772 return 0;
5775 nwrap_sethostent(stayopen);
5777 return 0;
5779 #else /* HAVE_SOLARIS_SETHOSTENT */
5780 void sethostent(int stayopen)
5782 if (!nss_wrapper_hosts_enabled()) {
5783 libc_sethostent(stayopen);
5784 return;
5787 nwrap_sethostent(stayopen);
5789 #endif /* HAVE_SOLARIS_SETHOSTENT */
5791 static struct hostent *nwrap_gethostent(void)
5793 return nwrap_files_gethostent();
5796 struct hostent *gethostent(void) {
5797 if (!nss_wrapper_hosts_enabled()) {
5798 return libc_gethostent();
5801 return nwrap_gethostent();
5804 static void nwrap_endhostent(void) {
5805 nwrap_files_endhostent();
5808 #ifdef HAVE_SOLARIS_ENDHOSTENT
5809 int endhostent(void)
5811 if (!nss_wrapper_hosts_enabled()) {
5812 libc_endhostent();
5813 return 0;
5816 nwrap_endhostent();
5818 return 0;
5820 #else /* HAVE_SOLARIS_ENDHOSTENT */
5821 void endhostent(void)
5823 if (!nss_wrapper_hosts_enabled()) {
5824 libc_endhostent();
5825 return;
5828 nwrap_endhostent();
5830 #endif /* HAVE_SOLARIS_ENDHOSTENT */
5833 #ifdef BSD
5834 /* BSD implementation stores data in thread local storage but GLIBC does not */
5835 static __thread struct hostent user_he;
5836 static __thread struct nwrap_vector user_addrlist;
5837 #else
5838 static struct hostent user_he;
5839 static struct nwrap_vector user_addrlist;
5840 #endif /* BSD */
5842 static struct hostent *nwrap_files_gethostbyname(struct nwrap_backend *b,
5843 const char *name)
5845 int ret;
5847 (void) b; /* unused */
5849 ret = nwrap_files_internal_gethostbyname(name, AF_UNSPEC, &user_he,
5850 &user_addrlist);
5851 if (ret == 0) {
5852 return &user_he;
5855 return NULL;
5858 static struct hostent *nwrap_gethostbyname(const char *name)
5860 size_t i;
5861 struct hostent *he = NULL;
5863 for (i=0; i < nwrap_main_global->num_backends; i++) {
5864 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5865 he = b->ops->nw_gethostbyname(b, name);
5866 if (he != NULL) {
5867 return he;
5871 return NULL;
5874 struct hostent *gethostbyname(const char *name)
5876 if (!nss_wrapper_hosts_enabled()) {
5877 return libc_gethostbyname(name);
5880 return nwrap_gethostbyname(name);
5883 /* This is a GNU extension - Also can be found on BSD systems */
5884 #ifdef HAVE_GETHOSTBYNAME2
5885 #ifdef BSD
5886 /* BSD implementation stores data in thread local storage but GLIBC not */
5887 static __thread struct hostent user_he2;
5888 static __thread struct nwrap_vector user_addrlist2;
5889 #else
5890 static struct hostent user_he2;
5891 static struct nwrap_vector user_addrlist2;
5892 #endif /* BSD */
5894 static struct hostent *nwrap_files_gethostbyname2(struct nwrap_backend *b,
5895 const char *name, int af)
5897 int ret;
5899 (void) b; /* unused */
5901 ret = nwrap_files_internal_gethostbyname(name, af, &user_he2,
5902 &user_addrlist2);
5903 if (ret == 0) {
5904 return &user_he2;
5907 return NULL;
5910 static struct hostent *nwrap_gethostbyname2(const char *name, int af)
5912 size_t i;
5913 struct hostent *he = NULL;
5915 for (i=0; i < nwrap_main_global->num_backends; i++) {
5916 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5917 he = b->ops->nw_gethostbyname2(b, name, af);
5918 if (he != NULL) {
5919 return he;
5923 return NULL;
5926 struct hostent *gethostbyname2(const char *name, int af)
5928 if (!nss_wrapper_hosts_enabled()) {
5929 return libc_gethostbyname2(name, af);
5932 return nwrap_gethostbyname2(name, af);
5934 #endif
5936 static struct hostent *nwrap_gethostbyaddr(const void *addr,
5937 socklen_t len, int type)
5939 size_t i;
5940 struct hostent *he = NULL;
5942 for (i=0; i < nwrap_main_global->num_backends; i++) {
5943 struct nwrap_backend *b = &nwrap_main_global->backends[i];
5944 he = b->ops->nw_gethostbyaddr(b, addr, len, type);
5945 if (he != NULL) {
5946 return he;
5950 return NULL;
5953 struct hostent *gethostbyaddr(const void *addr,
5954 socklen_t len, int type)
5956 if (!nss_wrapper_hosts_enabled()) {
5957 return libc_gethostbyaddr(addr, len, type);
5960 return nwrap_gethostbyaddr(addr, len, type);
5963 static const struct addrinfo default_hints =
5965 .ai_flags = AI_ADDRCONFIG|AI_V4MAPPED,
5966 .ai_family = AF_UNSPEC,
5967 .ai_socktype = 0,
5968 .ai_protocol = 0,
5969 .ai_addrlen = 0,
5970 .ai_addr = NULL,
5971 .ai_canonname = NULL,
5972 .ai_next = NULL
5975 static int nwrap_convert_he_ai(const struct hostent *he,
5976 unsigned short port,
5977 const struct addrinfo *hints,
5978 struct addrinfo **pai,
5979 bool skip_canonname)
5981 struct addrinfo *ai;
5982 socklen_t socklen;
5984 if (he == NULL) {
5985 return EAI_MEMORY;
5988 switch (he->h_addrtype) {
5989 case AF_INET:
5990 socklen = sizeof(struct sockaddr_in);
5991 break;
5992 #ifdef HAVE_IPV6
5993 case AF_INET6:
5994 socklen = sizeof(struct sockaddr_in6);
5995 break;
5996 #endif
5997 default:
5998 return EAI_FAMILY;
6001 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + socklen);
6002 if (ai == NULL) {
6003 return EAI_MEMORY;
6006 ai->ai_flags = hints->ai_flags;
6007 ai->ai_family = he->h_addrtype;
6008 ai->ai_socktype = hints->ai_socktype;
6009 ai->ai_protocol = hints->ai_protocol;
6010 ai->ai_canonname = NULL;
6012 if (ai->ai_socktype == 0) {
6013 ai->ai_socktype = SOCK_DGRAM;
6015 if (ai->ai_protocol == 0) {
6016 if (ai->ai_socktype == SOCK_DGRAM) {
6017 ai->ai_protocol = IPPROTO_UDP;
6018 } else if (ai->ai_socktype == SOCK_STREAM) {
6019 ai->ai_protocol = IPPROTO_TCP;
6023 ai->ai_addrlen = socklen;
6024 ai->ai_addr = (void *)(ai + 1);
6026 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
6027 ai->ai_addr->sa_len = socklen;
6028 #endif
6029 ai->ai_addr->sa_family = he->h_addrtype;
6031 switch (he->h_addrtype) {
6032 case AF_INET:
6034 union {
6035 struct sockaddr *sa;
6036 struct sockaddr_in *in;
6037 } addr;
6039 addr.sa = ai->ai_addr;
6041 memset(addr.in, 0, sizeof(struct sockaddr_in));
6043 addr.in->sin_port = htons(port);
6044 addr.in->sin_family = AF_INET;
6046 memset(addr.in->sin_zero,
6047 '\0',
6048 sizeof (addr.in->sin_zero));
6049 memcpy(&(addr.in->sin_addr),
6050 he->h_addr_list[0],
6051 he->h_length);
6054 break;
6055 #ifdef HAVE_IPV6
6056 case AF_INET6:
6058 union {
6059 struct sockaddr *sa;
6060 struct sockaddr_in6 *in6;
6061 } addr;
6063 addr.sa = ai->ai_addr;
6065 memset(addr.in6, 0, sizeof(struct sockaddr_in6));
6067 addr.in6->sin6_port = htons(port);
6068 addr.in6->sin6_family = AF_INET6;
6070 memcpy(&addr.in6->sin6_addr,
6071 he->h_addr_list[0],
6072 he->h_length);
6074 break;
6075 #endif
6078 ai->ai_next = NULL;
6080 if (he->h_name && !skip_canonname) {
6081 ai->ai_canonname = strdup(he->h_name);
6082 if (ai->ai_canonname == NULL) {
6083 freeaddrinfo(ai);
6084 return EAI_MEMORY;
6088 *pai = ai;
6089 return 0;
6092 static int nwrap_getaddrinfo(const char *node,
6093 const char *service,
6094 const struct addrinfo *hints,
6095 struct addrinfo **res)
6097 struct addrinfo *ai = NULL;
6098 unsigned short port = 0;
6099 struct {
6100 int family;
6101 union {
6102 struct in_addr v4;
6103 #ifdef HAVE_IPV6
6104 struct in6_addr v6;
6105 } in;
6106 #endif
6107 } addr = {
6108 .family = AF_UNSPEC,
6110 int rc;
6112 if (node == NULL && service == NULL) {
6113 return EAI_NONAME;
6116 if (hints == NULL) {
6117 hints = &default_hints;
6120 /* EAI_BADFLAGS
6121 hints.ai_flags contains invalid flags; or, hints.ai_flags
6122 included AI_CANONNAME and name was NULL.
6124 if ((hints->ai_flags & AI_CANONNAME) && (node == NULL)) {
6125 return EAI_BADFLAGS;
6128 /* If no node has been specified, let glibc deal with it */
6129 if (node == NULL) {
6130 int ret;
6131 struct addrinfo *p = NULL;
6133 ret = libc_getaddrinfo(node, service, hints, &p);
6135 if (ret == 0) {
6136 *res = p;
6138 return ret;
6141 if (service != NULL && service[0] != '\0') {
6142 const char *proto = NULL;
6143 struct servent *s;
6144 char *end_ptr;
6145 long sl;
6147 errno = 0;
6148 sl = strtol(service, &end_ptr, 10);
6150 if (*end_ptr == '\0') {
6151 port = sl;
6152 goto valid_port;
6153 } else if (hints->ai_flags & AI_NUMERICSERV) {
6154 return EAI_NONAME;
6157 if (hints->ai_protocol != 0) {
6158 struct protoent *pent;
6160 pent = getprotobynumber(hints->ai_protocol);
6161 if (pent != NULL) {
6162 proto = pent->p_name;
6166 s = getservbyname(service, proto);
6167 if (s == NULL) {
6168 return EAI_NONAME;
6170 port = ntohs(s->s_port);
6173 valid_port:
6175 rc = inet_pton(AF_INET, node, &addr.in.v4);
6176 if (rc == 1) {
6177 addr.family = AF_INET;
6179 #ifdef HAVE_IPV6
6180 if (addr.family == AF_UNSPEC) {
6181 rc = inet_pton(AF_INET6, node, &addr.in.v6);
6182 if (rc == 1) {
6183 addr.family = AF_INET6;
6186 #endif
6188 if (addr.family == AF_UNSPEC) {
6189 if (hints->ai_flags & AI_NUMERICHOST) {
6190 return EAI_NONAME;
6192 } else if ((hints->ai_family != AF_UNSPEC) &&
6193 (hints->ai_family != addr.family))
6195 return EAI_ADDRFAMILY;
6198 rc = nwrap_files_getaddrinfo(node, port, hints, &ai);
6199 if (rc != 0) {
6200 int ret;
6201 struct addrinfo *p = NULL;
6203 ret = libc_getaddrinfo(node, service, hints, &p);
6205 if (ret == 0) {
6207 * nwrap_files_getaddrinfo failed, but libc was
6208 * successful -- use the result from libc.
6210 *res = p;
6211 return 0;
6214 return rc;
6218 * If the socktype was not specified, duplicate
6219 * each ai returned, so that we have variants for
6220 * both UDP and TCP.
6222 if (hints->ai_socktype == 0) {
6223 struct addrinfo *ai_cur;
6225 /* freeaddrinfo() frees ai_canonname and ai so allocate them */
6226 for (ai_cur = ai; ai_cur != NULL; ai_cur = ai_cur->ai_next) {
6227 struct addrinfo *ai_new;
6229 /* duplicate the current entry */
6231 ai_new = malloc(sizeof(struct addrinfo));
6232 if (ai_new == NULL) {
6233 freeaddrinfo(ai);
6234 return EAI_MEMORY;
6237 memcpy(ai_new, ai_cur, sizeof(struct addrinfo));
6238 ai_new->ai_next = NULL;
6240 /* We need a deep copy or freeaddrinfo() will blow up */
6241 if (ai_cur->ai_canonname != NULL) {
6242 ai_new->ai_canonname =
6243 strdup(ai_cur->ai_canonname);
6246 if (ai_cur->ai_socktype == SOCK_DGRAM) {
6247 ai_new->ai_socktype = SOCK_STREAM;
6248 } else if (ai_cur->ai_socktype == SOCK_STREAM) {
6249 ai_new->ai_socktype = SOCK_DGRAM;
6251 if (ai_cur->ai_protocol == IPPROTO_TCP) {
6252 ai_new->ai_protocol = IPPROTO_UDP;
6253 } else if (ai_cur->ai_protocol == IPPROTO_UDP) {
6254 ai_new->ai_protocol = IPPROTO_TCP;
6257 /* now insert the new entry */
6259 ai_new->ai_next = ai_cur->ai_next;
6260 ai_cur->ai_next = ai_new;
6262 /* and move on (don't duplicate the new entry) */
6264 ai_cur = ai_new;
6268 *res = ai;
6270 return 0;
6273 int getaddrinfo(const char *node, const char *service,
6274 const struct addrinfo *hints,
6275 struct addrinfo **res)
6277 if (!nss_wrapper_hosts_enabled()) {
6278 return libc_getaddrinfo(node, service, hints, res);
6281 return nwrap_getaddrinfo(node, service, hints, res);
6284 static int nwrap_getnameinfo(const struct sockaddr *sa, socklen_t salen,
6285 char *host, size_t hostlen,
6286 char *serv, size_t servlen,
6287 int flags)
6289 struct hostent *he;
6290 struct servent *service;
6291 const char *proto;
6292 const void *addr;
6293 socklen_t addrlen;
6294 uint16_t port;
6295 sa_family_t type;
6296 size_t i;
6298 if (sa == NULL || salen < sizeof(sa_family_t)) {
6299 return EAI_FAMILY;
6302 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL) {
6303 return EAI_NONAME;
6306 type = sa->sa_family;
6307 switch (type) {
6308 case AF_INET: {
6309 union {
6310 const struct sockaddr *sa;
6311 const struct sockaddr_in *in;
6312 } a;
6314 if (salen < sizeof(struct sockaddr_in)) {
6315 return EAI_FAMILY;
6318 a.sa = sa;
6320 addr = &(a.in->sin_addr);
6321 addrlen = sizeof(a.in->sin_addr);
6322 port = ntohs(a.in->sin_port);
6323 break;
6325 #ifdef HAVE_IPV6
6326 case AF_INET6: {
6327 union {
6328 const struct sockaddr *sa;
6329 const struct sockaddr_in6 *in6;
6330 } a;
6332 if (salen < sizeof(struct sockaddr_in6)) {
6333 return EAI_FAMILY;
6336 a.sa = sa;
6338 addr = &(a.in6->sin6_addr);
6339 addrlen = sizeof(a.in6->sin6_addr);
6340 port = ntohs(a.in6->sin6_port);
6341 break;
6343 #endif
6344 default:
6345 return EAI_FAMILY;
6348 if (host != NULL) {
6349 he = NULL;
6350 if ((flags & NI_NUMERICHOST) == 0) {
6351 for (i=0; i < nwrap_main_global->num_backends; i++) {
6352 struct nwrap_backend *b = &nwrap_main_global->backends[i];
6353 he = b->ops->nw_gethostbyaddr(b, addr, addrlen, type);
6354 if (he != NULL) {
6355 break;
6358 if ((flags & NI_NAMEREQD) && (he == NULL || he->h_name == NULL))
6359 return EAI_NONAME;
6361 if (he != NULL && he->h_name != NULL) {
6362 if (strlen(he->h_name) >= hostlen)
6363 return EAI_OVERFLOW;
6364 snprintf(host, hostlen, "%s", he->h_name);
6365 if (flags & NI_NOFQDN)
6366 host[strcspn(host, ".")] = '\0';
6367 } else {
6368 if (inet_ntop(type, addr, host, hostlen) == NULL)
6369 return (errno == ENOSPC) ? EAI_OVERFLOW : EAI_FAIL;
6373 if (serv != NULL) {
6374 service = NULL;
6375 if ((flags & NI_NUMERICSERV) == 0) {
6376 proto = (flags & NI_DGRAM) ? "udp" : "tcp";
6377 service = getservbyport(htons(port), proto);
6379 if (service != NULL) {
6380 if (strlen(service->s_name) >= servlen)
6381 return EAI_OVERFLOW;
6382 snprintf(serv, servlen, "%s", service->s_name);
6383 } else {
6384 if (snprintf(serv, servlen, "%u", port) >= (int) servlen)
6385 return EAI_OVERFLOW;
6389 return 0;
6392 #ifdef HAVE_LINUX_GETNAMEINFO
6393 int getnameinfo(const struct sockaddr *sa, socklen_t salen,
6394 char *host, socklen_t hostlen,
6395 char *serv, socklen_t servlen,
6396 int flags)
6397 #elif defined(HAVE_LINUX_GETNAMEINFO_UNSIGNED)
6398 int getnameinfo(const struct sockaddr *sa, socklen_t salen,
6399 char *host, socklen_t hostlen,
6400 char *serv, socklen_t servlen,
6401 unsigned int flags)
6402 #else
6403 int getnameinfo(const struct sockaddr *sa, socklen_t salen,
6404 char *host, size_t hostlen,
6405 char *serv, size_t servlen,
6406 int flags)
6407 #endif
6409 if (!nss_wrapper_hosts_enabled()) {
6410 return libc_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
6413 return nwrap_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
6416 static int nwrap_gethostname(char *name, size_t len)
6418 const char *hostname = getenv("NSS_WRAPPER_HOSTNAME");
6420 if (strlen(hostname) >= len) {
6421 errno = ENAMETOOLONG;
6422 return -1;
6424 snprintf(name, len, "%s", hostname);
6426 return 0;
6429 #ifdef HAVE_SOLARIS_GETHOSTNAME
6430 int gethostname(char *name, int len)
6431 #else /* HAVE_SOLARIS_GETHOSTNAME */
6432 int gethostname(char *name, size_t len)
6433 #endif /* HAVE_SOLARIS_GETHOSTNAME */
6435 if (!nwrap_hostname_enabled()) {
6436 return libc_gethostname(name, len);
6439 return nwrap_gethostname(name, len);
6442 static void nwrap_thread_prepare(void)
6444 nwrap_init();
6445 NWRAP_LOCK_ALL;
6448 static void nwrap_thread_parent(void)
6450 NWRAP_UNLOCK_ALL;
6453 static void nwrap_thread_child(void)
6455 NWRAP_REINIT_ALL;
6458 /****************************
6459 * CONSTRUCTOR
6460 ***************************/
6461 void nwrap_constructor(void)
6463 NWRAP_REINIT_ALL;
6466 * If we hold a lock and the application forks, then the child
6467 * is not able to unlock the mutex and we are in a deadlock.
6469 * Setting these handlers should prevent such deadlocks.
6471 pthread_atfork(&nwrap_thread_prepare,
6472 &nwrap_thread_parent,
6473 &nwrap_thread_child);
6475 /* Do not call nwrap_init() here. */
6478 /****************************
6479 * DESTRUCTOR
6480 ***************************/
6483 * This function is called when the library is unloaded and makes sure that
6484 * sockets get closed and the unix file for the socket are unlinked.
6486 void nwrap_destructor(void)
6488 size_t i;
6490 NWRAP_LOCK_ALL;
6491 if (nwrap_main_global != NULL) {
6492 struct nwrap_main *m = nwrap_main_global;
6494 /* libc */
6495 if (m->libc != NULL) {
6496 if (m->libc->handle != NULL
6497 #ifdef RTLD_NEXT
6498 && m->libc->handle != RTLD_NEXT
6499 #endif
6501 dlclose(m->libc->handle);
6503 if (m->libc->nsl_handle != NULL
6504 #ifdef RTLD_NEXT
6505 && m->libc->nsl_handle != RTLD_NEXT
6506 #endif
6508 dlclose(m->libc->nsl_handle);
6510 if (m->libc->sock_handle != NULL
6511 #ifdef RTLD_NEXT
6512 && m->libc->sock_handle != RTLD_NEXT
6513 #endif
6515 dlclose(m->libc->sock_handle);
6517 SAFE_FREE(m->libc);
6520 /* backends */
6521 if (m->backends != NULL) {
6522 for (i = 0; i < m->num_backends; i++) {
6523 struct nwrap_backend *b = &(m->backends[i]);
6525 if (b->so_handle != NULL) {
6526 dlclose(b->so_handle);
6528 SAFE_FREE(b->symbols);
6530 SAFE_FREE(m->backends);
6534 if (nwrap_pw_global.cache != NULL) {
6535 struct nwrap_cache *c = nwrap_pw_global.cache;
6537 nwrap_files_cache_unload(c);
6538 if (c->fd >= 0) {
6539 fclose(c->fp);
6540 c->fd = -1;
6543 SAFE_FREE(nwrap_pw_global.list);
6544 nwrap_pw_global.num = 0;
6547 if (nwrap_gr_global.cache != NULL) {
6548 struct nwrap_cache *c = nwrap_gr_global.cache;
6550 nwrap_files_cache_unload(c);
6551 if (c->fd >= 0) {
6552 fclose(c->fp);
6553 c->fd = -1;
6556 SAFE_FREE(nwrap_gr_global.list);
6557 nwrap_gr_global.num = 0;
6560 #if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
6561 if (nwrap_sp_global.cache != NULL) {
6562 struct nwrap_cache *c = nwrap_sp_global.cache;
6564 nwrap_files_cache_unload(c);
6565 if (c->fd >= 0) {
6566 fclose(c->fp);
6567 c->fd = -1;
6570 nwrap_sp_global.num = 0;
6572 #endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
6574 if (nwrap_he_global.cache != NULL) {
6575 struct nwrap_cache *c = nwrap_he_global.cache;
6577 nwrap_files_cache_unload(c);
6578 if (c->fd >= 0) {
6579 fclose(c->fp);
6580 c->fd = -1;
6583 nwrap_he_global.num = 0;
6586 free(user_addrlist.items);
6587 #ifdef HAVE_GETHOSTBYNAME2
6588 free(user_addrlist2.items);
6589 #endif
6591 hdestroy();
6592 NWRAP_UNLOCK_ALL;