2 * Copyright (C) Stefan Metzmacher 2007 <metze@samba.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the author nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #define NSS_WRAPPER_NOT_REPLACE
37 #include "lib/replace/replace.h"
38 #include "system/passwd.h"
39 #include "system/filesys.h"
41 #else /* _SAMBA_BUILD_ */
43 #error nss_wrapper_only_supported_in_samba_yet
51 /* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
57 #define real_getpwnam getpwnam
58 #define real_getpwnam_r getpwnam_r
59 #define real_getpwuid getpwuid
60 #define real_getpwuid_r getpwuid_r
62 #define real_setpwent setpwent
63 #define real_getpwent getpwent
64 #define real_getpwent_r getpwent_r
65 #define real_endpwent endpwent
68 #define real_getgrlst getgrlst
69 #define real_getgrlst_r getgrlst_r
70 #define real_initgroups_dyn initgroups_dyn
72 #define real_initgroups initgroups
74 #define real_getgrnam getgrnam
75 #define real_getgrnam_r getgrnam_r
76 #define real_getgrgid getgrgid
77 #define real_getgrgid_r getgrgid_r
79 #define real_setgrent setgrent
80 #define real_getgrent getgrent
81 #define real_getgrent_r getgrent_r
82 #define real_endgrent endgrent
88 # define NWRAP_ERROR(args) DEBUG(0, args)
90 # define NWRAP_ERROR(args) printf args
93 #define NWRAP_ERROR(args)
98 # define NWRAP_DEBUG(args) DEBUG(0, args)
100 # define NWRAP_DEBUG(args) printf args
103 #define NWRAP_DEBUG(args)
108 # define NWRAP_VERBOSE(args) DEBUG(0, args)
110 # define NWRAP_VERBOSE(args) printf args
113 #define NWRAP_VERBOSE(args)
122 bool (*parse_line)(struct nwrap_cache *, char *line);
123 void (*unload)(struct nwrap_cache *);
127 struct nwrap_cache *cache;
134 struct nwrap_cache __nwrap_cache_pw;
135 struct nwrap_pw nwrap_pw_global;
137 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line);
138 static void nwrap_pw_unload(struct nwrap_cache *nwrap);
140 static void nwrap_init(void)
142 static bool initialized;
144 if (initialized) return;
147 nwrap_pw_global.cache = &__nwrap_cache_pw;
149 nwrap_pw_global.cache->path = getenv("NSS_WRAPPER_PASSWD");
150 nwrap_pw_global.cache->fd = -1;
151 nwrap_pw_global.cache->private_data = &nwrap_pw_global;
152 nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
153 nwrap_pw_global.cache->unload = nwrap_pw_unload;
156 static bool nwrap_enabled(void)
160 if (!nwrap_pw_global.cache->path) {
163 if (nwrap_pw_global.cache->path[0] == '\0') {
170 static bool nwrap_parse_file(struct nwrap_cache *nwrap)
176 if (nwrap->st.st_size == 0) {
177 NWRAP_DEBUG(("%s: size == 0\n",
182 if (nwrap->st.st_size > INT32_MAX) {
183 NWRAP_ERROR(("%s: size[%u] larger than INT32_MAX\n",
184 __location__, (unsigned)nwrap->st.st_size));
188 ret = lseek(nwrap->fd, 0, SEEK_SET);
190 NWRAP_ERROR(("%s: lseek - %d\n",__location__,ret));
194 buf = malloc(nwrap->st.st_size + 1);
196 NWRAP_ERROR(("%s: malloc failed\n",__location__));
200 ret = read(nwrap->fd, buf, nwrap->st.st_size);
201 if (ret != nwrap->st.st_size) {
202 NWRAP_ERROR(("%s: read(%u) gave %d\n",
203 __location__, (unsigned)nwrap->st.st_size, ret));
207 buf[nwrap->st.st_size] = '\0';
210 while (nline && nline[0]) {
218 e = strchr(line, '\n');
229 NWRAP_VERBOSE(("%s:'%s'\n",__location__, line));
231 if (strlen(line) == 0) {
235 ok = nwrap->parse_line(nwrap, line);
250 static void nwrap_cache_unload(struct nwrap_cache *nwrap)
252 nwrap->unload(nwrap);
254 if (nwrap->buf) free(nwrap->buf);
259 static void nwrap_cache_reload(struct nwrap_cache *nwrap)
264 bool retried = false;
268 nwrap->fd = open(nwrap->path, O_RDONLY);
270 NWRAP_ERROR(("%s: unable to open '%s' readonly %d:%s\n",
272 nwrap->path, nwrap->fd,
276 NWRAP_VERBOSE(("%s: open '%s'\n", __location__, nwrap->path));
279 ret = fstat(nwrap->fd, &st);
281 NWRAP_ERROR(("%s: fstat(%s) - %d:%s\n",
284 ret, strerror(errno)));
288 if (retried == false && st.st_nlink == 0) {
289 /* maybe someone has replaced the file... */
290 NWRAP_DEBUG(("%s: st_nlink == 0, reopen %s\n",
291 __location__, nwrap->path));
293 memset(&nwrap->st, 0, sizeof(nwrap->st));
299 if (st.st_mtime == nwrap->st.st_mtime) {
300 NWRAP_VERBOSE(("%s: st_mtime[%u] hasn't changed, skip reload\n",
301 __location__, (unsigned)st.st_mtime));
304 NWRAP_DEBUG(("%s: st_mtime has changed [%u] => [%u], start reload\n",
305 __location__, (unsigned)st.st_mtime,
306 (unsigned)nwrap->st.st_mtime));
310 nwrap_cache_unload(nwrap);
312 ok = nwrap_parse_file(nwrap);
314 NWRAP_ERROR(("%s: failed to reload %s\n",
315 __location__, nwrap->path));
316 nwrap_cache_unload(nwrap);
318 NWRAP_DEBUG(("%s: reloaded %s\n",
319 __location__, nwrap->path));
323 * the caller has to call nwrap_unload() on failure
325 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
327 struct nwrap_pw *nwrap_pw;
334 nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
336 list_size = sizeof(*nwrap_pw->list) * (nwrap_pw->num+1);
337 pw = (struct passwd *)realloc(nwrap_pw->list, list_size);
339 NWRAP_ERROR(("%s:realloc(%u) failed\n",
340 __location__, list_size));
345 pw = &nwrap_pw->list[nwrap_pw->num];
352 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
353 __location__, line, c));
361 NWRAP_VERBOSE(("name[%s]\n", pw->pw_name));
366 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
367 __location__, line, c));
375 NWRAP_VERBOSE(("password[%s]\n", pw->pw_passwd));
380 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
381 __location__, line, c));
387 pw->pw_uid = (uid_t)strtoul(c, &e, 10);
389 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
390 __location__, line, c, strerror(errno)));
394 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
395 __location__, line, c, strerror(errno)));
399 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
400 __location__, line, c, strerror(errno)));
405 NWRAP_VERBOSE(("uid[%u]\n", pw->pw_uid));
410 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
411 __location__, line, c));
417 pw->pw_gid = (gid_t)strtoul(c, &e, 10);
419 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
420 __location__, line, c, strerror(errno)));
424 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
425 __location__, line, c, strerror(errno)));
429 NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
430 __location__, line, c, strerror(errno)));
435 NWRAP_VERBOSE(("gid[%u]\n", pw->pw_gid));
440 NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
441 __location__, line, c));
449 NWRAP_VERBOSE(("gecos[%s]\n", pw->pw_gecos));
454 NWRAP_ERROR(("%s:'%s'\n",__location__,c));
462 NWRAP_VERBOSE(("dir[%s]\n", pw->pw_dir));
466 NWRAP_VERBOSE(("shell[%s]\n", pw->pw_shell));
468 NWRAP_DEBUG(("add user[%s:%s:%u:%u:%s:%s:%s]\n",
469 pw->pw_name, pw->pw_passwd,
470 pw->pw_uid, pw->pw_gid,
471 pw->pw_gecos, pw->pw_dir, pw->pw_shell));
477 static void nwrap_pw_unload(struct nwrap_cache *nwrap)
479 struct nwrap_pw *nwrap_pw;
480 nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
482 if (nwrap_pw->list) free(nwrap_pw->list);
484 nwrap_pw->list = NULL;
489 static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
490 char *buf, size_t buflen, struct passwd **destp)
496 first = src->pw_name;
498 last = src->pw_shell;
499 while (*last) last++;
501 ofs = PTR_DIFF(last + 1, first);
507 memcpy(buf, first, ofs);
509 ofs = PTR_DIFF(src->pw_name, first);
510 dst->pw_name = buf + ofs;
511 ofs = PTR_DIFF(src->pw_passwd, first);
512 dst->pw_passwd = buf + ofs;
513 dst->pw_uid = src->pw_uid;
514 dst->pw_gid = src->pw_gid;
515 ofs = PTR_DIFF(src->pw_gecos, first);
516 dst->pw_gecos = buf + ofs;
517 ofs = PTR_DIFF(src->pw_dir, first);
518 dst->pw_dir = buf + ofs;
519 ofs = PTR_DIFF(src->pw_shell, first);
520 dst->pw_shell = buf + ofs;
526 _PUBLIC_ struct passwd *nwrap_getpwnam(const char *name)
530 if (!nwrap_enabled()) {
531 return real_getpwnam(name);
534 nwrap_cache_reload(nwrap_pw_global.cache);
536 for (i=0; i<nwrap_pw_global.num; i++) {
537 if (strcmp(nwrap_pw_global.list[i].pw_name, name) == 0) {
538 NWRAP_DEBUG(("%s: user[%s] found\n",
539 __location__, name));
540 return &nwrap_pw_global.list[i];
542 NWRAP_VERBOSE(("%s: user[%s] does not match [%s]\n",
544 nwrap_pw_global.list[i].pw_name));
547 NWRAP_DEBUG(("%s: user[%s] not found\n", __location__, name));
553 _PUBLIC_ int nwrap_getpwnam_r(const char *name, struct passwd *pwdst,
554 char *buf, size_t buflen, struct passwd **pwdstp)
558 if (!nwrap_enabled()) {
559 return real_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
562 pw = nwrap_getpwnam(name);
570 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
573 _PUBLIC_ struct passwd *nwrap_getpwuid(uid_t uid)
577 if (!nwrap_enabled()) {
578 return real_getpwuid(uid);
581 nwrap_cache_reload(nwrap_pw_global.cache);
583 for (i=0; i<nwrap_pw_global.num; i++) {
584 if (nwrap_pw_global.list[i].pw_uid == uid) {
585 NWRAP_DEBUG(("%s: uid[%u] found\n",
587 return &nwrap_pw_global.list[i];
589 NWRAP_VERBOSE(("%s: uid[%u] does not match [%u]\n",
591 nwrap_pw_global.list[i].pw_uid));
594 NWRAP_DEBUG(("%s: uid[%u] not found\n", __location__, uid));
600 _PUBLIC_ int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst,
601 char *buf, size_t buflen, struct passwd **pwdstp)
605 if (!nwrap_enabled()) {
606 return real_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
609 pw = nwrap_getpwuid(uid);
617 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
620 /* user enum functions */
621 _PUBLIC_ void nwrap_setpwent(void)
623 if (!nwrap_enabled()) {
627 nwrap_pw_global.idx = 0;
630 _PUBLIC_ struct passwd *nwrap_getpwent(void)
634 if (!nwrap_enabled()) {
635 return real_getpwent();
638 if (nwrap_pw_global.idx == 0) {
639 nwrap_cache_reload(nwrap_pw_global.cache);
642 if (nwrap_pw_global.idx >= nwrap_pw_global.num) {
647 pw = &nwrap_pw_global.list[nwrap_pw_global.idx++];
649 NWRAP_VERBOSE(("%s: return user[%s] uid[%u]\n",
650 __location__, pw->pw_name, pw->pw_uid));
655 _PUBLIC_ int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
656 size_t buflen, struct passwd **pwdstp)
660 if (!nwrap_enabled()) {
661 return real_getpwent_r(pwdst, buf, buflen, pwdstp);
664 pw = nwrap_getpwent();
672 return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
675 _PUBLIC_ void nwrap_endpwent(void)
677 if (!nwrap_enabled()) {
681 nwrap_pw_global.idx = 0;
685 _PUBLIC_ int nwrap_initgroups(const char *user, gid_t group)
687 return real_initgroups(user, group);
690 /* group functions */
691 _PUBLIC_ struct group *nwrap_getgrnam(const char *name)
693 return real_getgrnam(name);
696 _PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *gbuf,
697 char *buf, size_t buflen, struct group **gbufp)
699 return real_getgrnam_r(name, gbuf, buf, buflen, gbufp);
702 _PUBLIC_ struct group *nwrap_getgrgid(gid_t gid)
704 return real_getgrgid(gid);
707 _PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *gbuf,
708 char *buf, size_t buflen, struct group **gbufp)
710 return real_getgrgid_r(gid, gbuf, buf, buflen, gbufp);
713 /* group enum functions */
714 _PUBLIC_ void nwrap_setgrent(void)
719 _PUBLIC_ struct group *nwrap_getgrent(void)
721 return real_getgrent();
724 _PUBLIC_ int nwrap_getgrent_r(struct group *gbuf, char *buf,
725 size_t buflen, struct group **gbufp)
727 return real_getgrent_r(gbuf, buf, buflen, gbufp);
730 _PUBLIC_ void nwrap_endgrent(void)