1 /* This file is part of unscd, a complete nscd replacement.
2 * Copyright (C) 2007 Denys Vlasenko. Licensed under the GPL version 2. */
4 /* unscd is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * unscd is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You can download the GNU General Public License from the GNU website
14 * at http://www.gnu.org/ or write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
20 gcc -Wall -Wunused-parameter -Os -o nscd nscd.c
22 gcc -fomit-frame-pointer -Wl,--sort-section -Wl,alignment -Wl,--sort-common
27 nscd problems are not exactly unheard of. Over the years, there were
28 quite a bit of bugs in it. This leads people to invent babysitters
29 which restart crashed/hung nscd. This is ugly.
31 After looking at nscd source in glibc I arrived to the conclusion
32 that its design is contributing to this significantly. Even if nscd's
33 code is 100.00% perfect and bug-free, it can still suffer from bugs
34 in libraries it calls.
36 As designed, it's a multithreaded program which calls NSS libraries.
37 These libraries are not part of libc, they may be provided
38 by third-party projects (samba, ldap, you name it).
40 Thus nscd cannot be sure that libraries it calls do not have memory
41 or file descriptor leaks and other bugs.
43 Since nscd is multithreaded program with single shared cache,
44 any resource leak in any NSS library has cumulative effect.
45 Even if a NSS library leaks a file descriptor 0.01% of the time,
46 this will make nscd crash or hang after some time.
48 Of course bugs in NSS .so modules should be fixed, but meanwhile
49 I do want nscd which does not crash or lock up.
51 So I went ahead and wrote a replacement.
53 It is a single-threaded server process which offloads all NSS
54 lookups to worker children (not threads, but fully independent
55 processes). Cache hits are handled by parent. Only cache misses
56 start worker children. This design is immune against
57 resource leaks and hangs in NSS libraries.
59 It is also many times smaller.
61 Currently (v0.36) it emulates glibc nscd pretty closely
62 (handles same command line flags and config file), and is moderately tested.
64 Please note that as of 2008-08 it is not in wide use (yet?).
65 If you have trouble compiling it, see an incompatibility with
66 "standard" one or experience hangs/crashes, please report it to
67 vda.linux@googlemail.com
69 ***********************************************************************/
71 /* Make struct ucred appear in sys/socket.h */
73 /* For all good things */
90 #include <sys/socket.h>
92 #include <sys/types.h>
98 /* For inet_ntoa (for debug build only) */
99 #include <arpa/inet.h>
102 * 0.21 add SEGV reporting to worker
103 * 0.22 don't do freeaddrinfo() in GETAI worker, it's crashy
104 * 0.23 add parameter parsing
105 * 0.24 add conf file parsing, not using results yet
106 * 0.25 used some of conf file settings (not tested)
107 * 0.26 almost all conf file settings are wired up
108 * 0.27 a bit more of almost all conf file settings are wired up
109 * 0.28 optimized cache aging
110 * 0.29 implemented invalidate and shutdown options
111 * 0.30 fixed buglet (sizeof(ptr) != sizeof(array))
112 * 0.31 reduced client_info by one member
113 * 0.32 fix nttl/size defaults; simpler check for worker child in main()
114 * 0.33 tweak includes so that it builds on my new machine (64-bit userspace);
115 * do not die on unknown service name, just warn
116 * ("services" is a new service we don't support)
117 * 0.34 create /var/run/nscd/nscd.pid pidfile like glibc nscd 2.8 does;
118 * delay setuid'ing itself to server-user after log and pidfile are open
119 * 0.35 readlink /proc/self/exe and use result if execing /proc/self/exe fails
120 * 0.36 excercise extreme paranoia handling server-user option;
121 * a little bit more verbose logging:
122 * L_DEBUG2 log level added, use debug-level 7 to get it
123 * 0.37 users reported over-zealous "detected change in /etc/passwd",
124 * apparently stat() returns random garbage in unused padding
125 * on some systems. Made the check less paranoid.
126 * 0.38 log POLLHUP better
127 * 0.39 log answers to client better, log getpwnam in the worker,
128 * pass debug level value down to worker.
129 * 0.40 fix handling of shutdown and invalidate requests;
130 * fix bug with answer written in several pieces
131 * 0.40.1 set hints.ai_socktype = SOCK_STREAM in GETAI request
132 * 0.41 eliminate double caching of two near-simultaneous identical requests -
134 * 0.42 execute /proc/self/exe by link name first (better comm field)
135 * 0.43 fix off-by-one error in setgroups
136 * 0.44 make -d[ddd] bump up debug - easier to explain to users
137 * how to produce detailed log (no nscd.conf tweaking)
138 * 0.45 Fix out-of-bounds array access and log/pid file permissions -
139 * thanks to Sebastian Krahmer (krahmer AT suse.de)
140 * 0.46 fix a case when we forgot to remove a future entry on worker failure
141 * 0.47 fix nscd without -d to not bump debug level
142 * 0.48 fix for changes in __nss_disable_nscd API in glibc-2.15
144 #define PROGRAM_VERSION "0.48"
146 #define DEBUG_BUILD 1
153 #define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0])))
155 #define NORETURN __attribute__ ((__noreturn__))
158 #ifdef MY_CPU_HATES_CHARS
159 typedef int smallint;
161 typedef signed char smallint;
167 L_DEBUG = ((1 << 1) * DEBUG_BUILD),
168 L_DEBUG2 = ((1 << 2) * DEBUG_BUILD),
169 L_DUMP = ((1 << 3) * DEBUG_BUILD),
175 static smallint debug = D_DAEMON;
177 static void verror(const char *s, va_list p, const char *strerr)
180 int sz, rem, strerr_len;
184 if (debug & D_STAMP) {
185 gettimeofday(&tv, NULL);
186 sz = sprintf(msgbuf, "%02u:%02u:%02u.%05u ",
187 (unsigned)((tv.tv_sec / (60*60)) % 24),
188 (unsigned)((tv.tv_sec / 60) % 60),
189 (unsigned)(tv.tv_sec % 60),
190 (unsigned)(tv.tv_usec / 10));
192 rem = sizeof(msgbuf) - sz;
193 sz += vsnprintf(msgbuf + sz, rem, s, p);
194 rem = sizeof(msgbuf) - sz; /* can be negative after this! */
197 strerr_len = strlen(strerr);
198 if (rem >= strerr_len + 4) { /* ": STRERR\n\0" */
201 strcpy(msgbuf + sz, strerr);
210 fputs(msgbuf, stderr);
213 static void error(const char *msg, ...)
217 verror(msg, p, NULL);
221 static void error_and_die(const char *msg, ...) NORETURN;
222 static void error_and_die(const char *msg, ...)
226 verror(msg, p, NULL);
231 static void perror_and_die(const char *msg, ...) NORETURN;
232 static void perror_and_die(const char *msg, ...)
236 /* Guard against "<error message>: Success" */
237 verror(msg, p, errno ? strerror(errno) : NULL);
242 static void nscd_log(int mask, const char *msg, ...)
247 verror(msg, p, NULL);
252 #define log(lvl, ...) do { if (lvl) nscd_log(lvl, __VA_ARGS__); } while (0)
255 static void dump(const void *ptr, int len)
258 const unsigned char *buf;
261 if (!(debug & L_DUMP))
266 int chunk = ((len >= 16) ? 16 : len);
268 "%02x %02x %02x %02x %02x %02x %02x %02x "
269 "%02x %02x %02x %02x %02x %02x %02x %02x " + (16-chunk) * 5,
270 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
271 buf[8], buf[9],buf[10],buf[11],buf[12],buf[13],buf[14],buf[15]
273 fprintf(stderr, "%*s", (16-chunk) * 3, "");
277 unsigned char c = *buf++;
278 *p++ = (c >= 32 && c < 127 ? c : '.');
286 void dump(const void *ptr, int len);
289 #define hex_dump(p,n) do { if (L_DUMP) dump(p,n); } while (0)
291 static int xopen3(const char *pathname, int flags, int mode)
293 int fd = open(pathname, flags, mode);
295 perror_and_die("open");
299 static void xpipe(int *fds)
302 perror_and_die("pipe");
305 static void xexecve(const char *filename, char **argv, char **envp) NORETURN;
306 static void xexecve(const char *filename, char **argv, char **envp)
308 execve(filename, argv, envp);
309 perror_and_die("cannot re-exec %s", filename);
312 static void ndelay_on(int fd)
314 int fl = fcntl(fd, F_GETFL);
316 perror_and_die("F_GETFL");
317 if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) < 0)
318 perror_and_die("setting O_NONBLOCK");
321 static void close_on_exec(int fd)
323 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
324 perror_and_die("setting FD_CLOEXEC");
327 static unsigned monotonic_ms(void)
330 if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts))
331 perror_and_die("clock_gettime(MONOTONIC)");
332 return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
335 static unsigned strsize(const char *str)
337 return strlen(str) + 1;
340 static unsigned strsize_aligned4(const char *str)
342 return (strlen(str) + 1 + 3) & (~3);
345 static ssize_t safe_read(int fd, void *buf, size_t count)
349 n = read(fd, buf, count);
350 } while (n < 0 && errno == EINTR);
354 static ssize_t full_read(int fd, void *buf, size_t len)
360 cc = safe_read(fd, buf, len);
362 return cc; /* read() returns -1 on failure. */
365 buf = ((char *)buf) + cc;
373 static void xsafe_read(int fd, void *buf, size_t len)
375 if (len != safe_read(fd, buf, len))
376 perror_and_die("short read");
378 static void xfull_read(int fd, void *buf, size_t len)
380 if (len != full_read(fd, buf, len))
381 perror_and_die("short read");
385 static ssize_t safe_write(int fd, const void *buf, size_t count)
389 n = write(fd, buf, count);
390 } while (n < 0 && errno == EINTR);
394 static ssize_t full_write(int fd, const void *buf, size_t len)
401 cc = safe_write(fd, buf, len);
403 return cc; /* write() returns -1 on failure. */
405 buf = ((const char *)buf) + cc;
411 static void xsafe_write(int fd, const void *buf, size_t count)
413 if (count != safe_write(fd, buf, count))
414 perror_and_die("short write of %ld bytes", (long)count);
416 static void xfull_write(int fd, const void *buf, size_t count)
418 if (count != full_write(fd, buf, count))
419 perror_and_die("short write of %ld bytes", (long)count);
422 static void xmovefd(int from_fd, int to_fd)
424 if (from_fd != to_fd) {
425 if (dup2(from_fd, to_fd) < 0)
426 perror_and_die("dup2");
431 static unsigned getnum(const char *str)
433 if (str[0] >= '0' && str[0] <= '9') {
435 unsigned long l = strtoul(str, &p, 10);
436 /* must not overflow int even after x1000 */
437 if (!*p && l <= INT_MAX / 1000)
440 error_and_die("malformed or too big number '%s'", str);
443 static char *skip_whitespace(const char *s)
445 /* NB: isspace('\0') returns 0 */
446 while (isspace(*s)) ++s;
450 static char *skip_non_whitespace(const char *s)
452 while (*s && !isspace(*s)) ++s;
456 static void *xmalloc(unsigned sz)
458 void *p = malloc(sz);
460 error_and_die("out of memory");
464 static void *xzalloc(unsigned sz)
466 void *p = xmalloc(sz);
471 static void *xrealloc(void *p, unsigned size)
473 p = realloc(p, size);
475 error_and_die("out of memory");
479 static const char *xstrdup(const char *str)
481 const char *p = strdup(str);
483 error_and_die("out of memory");
498 static const char srv_name[3][7] = {
507 smallint srv_enable[3];
508 smallint check_files[3];
513 /* We try to closely mimic glibc nscd */
514 .logfile = NULL, /* default is to not have a log file */
516 .srv_enable = { 0, 0, 0 },
517 .check_files = { 1, 1, 1 },
518 .pttl = { 3600, 3600, 3600 },
519 .nttl = { 20, 60, 20 },
520 /* huh, what is the default cache size in glibc nscd? */
521 .size = { 256 * 8 / 3, 256 * 8 / 3, 256 * 8 / 3 },
524 static const char default_conffile[] = "/etc/nscd.conf";
525 static const char *self_exe_points_to = "/proc/self/exe";
529 ** Clients, workers machinery
532 /* Header common to all requests */
533 #define USER_REQ_STRUCT \
534 uint32_t version; /* Version number of the daemon interface */ \
535 uint32_t type; /* Service requested */ \
536 uint32_t key_len; /* Key length */
538 typedef struct user_req_header {
544 MAX_USER_REQ_SIZE = 1024,
545 USER_HDR_SIZE = sizeof(user_req_header),
546 /* DNS queries time out after 20 seconds,
547 * we will allow for a bit more */
548 WORKER_TIMEOUT_SEC = 30,
549 CLIENT_TIMEOUT_MS = 100,
550 SMALL_POLL_TIMEOUT_MS = 200,
553 typedef struct user_req {
555 struct { /* as came from client */
558 struct { /* when stored in cache, overlaps .version */
560 /* (timestamp24 * 256) == timestamp in ms */
561 unsigned timestamp24:24;
564 char reqbuf[MAX_USER_REQ_SIZE - USER_HDR_SIZE];
567 /* Compile-time check for correct size */
568 struct BUG_wrong_user_req_size {
569 char BUG_wrong_user_req_size[sizeof(user_req) == MAX_USER_REQ_SIZE ? 1 : -1];
581 SHUTDOWN, /* Shut the server down */
582 GETSTAT, /* Get the server statistic */
583 INVALIDATE, /* Invalidate one special cache */
595 static const char *const typestr[] = {
596 "GETPWBYNAME", /* done */
597 "GETPWBYUID", /* done */
598 "GETGRBYNAME", /* done */
599 "GETGRBYGID", /* done */
600 "GETHOSTBYNAME", /* done */
601 "GETHOSTBYNAMEv6", /* done */
602 "GETHOSTBYADDR", /* done */
603 "GETHOSTBYADDRv6", /* done */
604 "SHUTDOWN", /* done */
605 "GETSTAT", /* info? */
606 "INVALIDATE", /* done */
607 /* won't do: nscd passes a name of shmem segment
608 * which client can map and "see" the db */
610 "GETFDGR", /* won't do */
611 "GETFDHST", /* won't do */
613 "INITGROUPS", /* done */
614 "GETSERVBYNAME", /* prio 3 (no caching?) */
615 "GETSERVBYPORT", /* prio 3 (no caching?) */
616 "GETFDSERV" /* won't do */
619 extern const char *const typestr[];
621 static const smallint type_to_srv[] = {
622 [GETPWBYNAME ] = SRV_PASSWD,
623 [GETPWBYUID ] = SRV_PASSWD,
624 [GETGRBYNAME ] = SRV_GROUP,
625 [GETGRBYGID ] = SRV_GROUP,
626 [GETHOSTBYNAME ] = SRV_HOSTS,
627 [GETHOSTBYNAMEv6 ] = SRV_HOSTS,
628 [GETHOSTBYADDR ] = SRV_HOSTS,
629 [GETHOSTBYADDRv6 ] = SRV_HOSTS,
630 [GETAI ] = SRV_HOSTS,
631 [INITGROUPS ] = SRV_GROUP,
634 static int unsupported_ureq_type(unsigned type)
636 if (type == GETAI) return 0;
637 if (type == INITGROUPS) return 0;
638 if (type == GETSTAT) return 1;
639 if (type > INVALIDATE) return 1;
644 typedef struct client_info {
645 /* if client_fd != 0, we are waiting for the reply from worker
646 * on pfd[i].fd, and client_fd is saved client's fd
647 * (we need to put it back into pfd[i].fd later) */
649 unsigned bytecnt; /* bytes read from client */
650 unsigned bufidx; /* buffer# in global client_buf[] */
652 unsigned respos; /* response */
653 user_req *resptr; /* response */
654 user_req **cache_pp; /* cache entry address */
655 user_req *ureq; /* request (points to client_buf[x]) */
658 static unsigned g_now_ms;
659 static int min_closed = INT_MAX;
660 static int cnt_closed = 0;
661 static int num_clients = 2; /* two listening sockets are "clients" too */
663 /* We read up to max_reqnum requests in parallel */
664 static unsigned max_reqnum = 14;
666 static char (*client_buf)[MAX_USER_REQ_SIZE];
667 static char *busy_cbuf;
668 static struct pollfd *pfd;
669 static client_info *cinfo;
671 /* Request, response and cache data structures:
673 * cache[] (defined later):
674 * cacheline_t cache[cache_size] array, or in other words,
675 * user_req* cache[cache_size][8] array.
676 * Every client request is hashed, hash value determines which cache[x]
677 * will have the response stored in one of its 8 elements.
678 * Cache entries have this format: request, then padding to 32 bits,
680 * Addresses in cache[x][y] may be NULL or:
681 * (&client_buf[z]) & 1: the cache miss is in progress ("future entry"):
682 * "the data is not in the cache (yet), wait for it to appear"
683 * (&client_buf[z]) & 3: the cache miss is in progress and other clients
684 * also want the same data ("shared future entry")
685 * else (non-NULL but low two bits are 0): cached data in malloc'ed block
687 * Each of these is a [max_reqnum] sized array:
688 * pfd[i] - given to poll() to wait for requests and replies.
689 * .fd: first two pfd[i]: listening Unix domain sockets, else
690 * .fd: open fd to a client, for reading client's request, or
691 * .fd: open fd to a worker, to send request and get response back
692 * cinfo[i] - auxiliary client data for pfd[i]
693 * .client_fd: open fd to a client, in case we already had read its
694 * request and got a cache miss, and created a worker or
695 * wait for another client's worker.
696 * Otherwise, it's 0 and client's fd is in pfd[i].fd
697 * .bufidx: index in client_buf[] we store client's request in
698 * .bytecnt: size of the request
699 * .started_ms: used to time out unresponsive clients
702 * .cache_pp: &cache[x][y] where the response is, or will be stored.
704 * When a client has received its reply (or otherwise closed (timeout etc)),
705 * corresponding pfd[i] and cinfo[i] are removed by shifting [i+1], [i+2] etc
706 * elements down, so that both arrays never have free holes.
707 * [num_clients] is always the first free element.
709 * Each of these also is a [max_reqnum] sized array, but indexes
710 * do not correspond directly to pfd[i] and cinfo[i]:
711 * client_buf[n][MAX_USER_REQ_SIZE] - buffers we read client requests into
712 * busy_cbuf[n] - bool flags marking busy client_buf[]
714 /* Possible reductions:
715 * fd, bufidx - uint8_t
716 * started_ms -> uint16_t started_s
717 * ureq - eliminate (derivable from bufidx?)
720 /* Are special bits 0? is it a true cached entry? */
721 #define CACHED_ENTRY(p) ( ((long)(p) & 3) == 0 )
722 /* Are special bits 11? is it a shared future cache entry? */
723 #define CACHE_SHARED(p) ( ((long)(p) & 3) == 3 )
724 /* Return a ptr with special bits cleared (used for accessing data) */
725 #define CACHE_PTR(p) ( (void*) ((long)(p) & ~(long)3) )
726 /* Return a ptr with special bits set to x1: make future cache entry ptr */
727 #define MAKE_FUTURE_PTR(p) ( (void*) ((long)(p) | 1) )
728 /* Modify ptr, set special bits to 11: shared future cache entry */
729 #define MARK_PTR_SHARED(pp) ( *(long*)(pp) |= 3 )
731 static inline unsigned ureq_size(const user_req *ureq)
733 return sizeof(user_req_header) + ureq->key_len;
736 static unsigned cache_age(const user_req *ureq)
738 if (!CACHED_ENTRY(ureq))
740 return (uint32_t) (g_now_ms - (ureq->timestamp24 << 8));
743 static void set_cache_timestamp(user_req *ureq)
745 ureq->timestamp24 = g_now_ms >> 8;
748 static int alloc_buf_no(void)
753 next_buf = (next_buf + 1) % max_reqnum;
754 if (!busy_cbuf[cur]) {
758 } while (next_buf != n);
759 error_and_die("no free bufs?!");
762 static inline void *bufno2buf(int i)
764 return client_buf[i];
767 static void close_client(unsigned i)
769 log(L_DEBUG, "closing client %u (fd %u,%u)", i, pfd[i].fd, cinfo[i].client_fd);
770 /* Paranoia. We had nasty bugs where client was closed twice. */
771 if (pfd[i].fd == 0) ////
774 if (cinfo[i].client_fd && cinfo[i].client_fd != pfd[i].fd)
775 close(cinfo[i].client_fd);
776 pfd[i].fd = 0; /* flag as unused (coalescing needs this) */
777 busy_cbuf[cinfo[i].bufidx] = 0;
785 ** nscd API <-> C API conversion
788 typedef struct response_header {
789 uint32_t version_or_size;
794 typedef struct initgr_response_header {
795 uint32_t version_or_size;
798 /* code assumes gid_t == int32, let's check that */
799 int32_t gid[sizeof(gid_t) == sizeof(int32_t) ? 0 : -1];
800 /* char user_str[as_needed]; */
801 } initgr_response_header;
803 static initgr_response_header *obtain_initgroups(const char *username)
805 struct initgr_response_header *resp;
807 enum { MAGIC_OFFSET = sizeof(*resp) / sizeof(int32_t) };
811 pw = getpwnam(username);
814 resp->version_or_size = sizeof(*resp);
820 /* getgrouplist may be very expensive, it's much better to allocate
821 * a bit more than to run getgrouplist twice */
825 sz = sizeof(*resp) + sizeof(resp->gid[0]) * ngroups;
826 resp = xrealloc(resp, sz);
827 } while (getgrouplist(username, pw->pw_gid, (gid_t*) &resp->gid, &ngroups) == -1);
828 log(L_DEBUG, "ngroups=%d", ngroups);
830 sz = sizeof(*resp) + sizeof(resp->gid[0]) * ngroups;
831 /* resp = xrealloc(resp, sz); - why bother */
832 resp->version_or_size = sz;
834 resp->ngrps = ngroups;
839 typedef struct pw_response_header {
840 uint32_t version_or_size;
843 int32_t pw_passwd_len;
846 int32_t pw_gecos_len;
848 int32_t pw_shell_len;
849 /* char pw_name[pw_name_len]; */
850 /* char pw_passwd[pw_passwd_len]; */
851 /* char pw_gecos[pw_gecos_len]; */
852 /* char pw_dir[pw_dir_len]; */
853 /* char pw_shell[pw_shell_len]; */
854 } pw_response_header;
856 static pw_response_header *marshal_passwd(struct passwd *pw)
859 pw_response_header *resp;
860 unsigned pw_name_len;
861 unsigned pw_passwd_len;
862 unsigned pw_gecos_len;
864 unsigned pw_shell_len;
865 unsigned sz = sizeof(*resp);
867 sz += (pw_name_len = strsize(pw->pw_name));
868 sz += (pw_passwd_len = strsize(pw->pw_passwd));
869 sz += (pw_gecos_len = strsize(pw->pw_gecos));
870 sz += (pw_dir_len = strsize(pw->pw_dir));
871 sz += (pw_shell_len = strsize(pw->pw_shell));
874 resp->version_or_size = sz;
880 resp->pw_name_len = pw_name_len;
881 resp->pw_passwd_len = pw_passwd_len;
882 resp->pw_uid = pw->pw_uid;
883 resp->pw_gid = pw->pw_gid;
884 resp->pw_gecos_len = pw_gecos_len;
885 resp->pw_dir_len = pw_dir_len;
886 resp->pw_shell_len = pw_shell_len;
887 p = (char*)(resp + 1);
888 strcpy(p, pw->pw_name); p += pw_name_len;
889 strcpy(p, pw->pw_passwd); p += pw_passwd_len;
890 strcpy(p, pw->pw_gecos); p += pw_gecos_len;
891 strcpy(p, pw->pw_dir); p += pw_dir_len;
892 strcpy(p, pw->pw_shell); p += pw_shell_len;
893 log(L_DEBUG, "sz:%u realsz:%u", sz, p - (char*)resp);
898 typedef struct gr_response_header {
899 uint32_t version_or_size;
901 int32_t gr_name_len; /* strlen(gr->gr_name) + 1; */
902 int32_t gr_passwd_len; /* strlen(gr->gr_passwd) + 1; */
903 int32_t gr_gid; /* gr->gr_gid */
904 int32_t gr_mem_cnt; /* while (gr->gr_mem[gr_mem_cnt]) ++gr_mem_cnt; */
905 /* int32_t gr_mem_len[gr_mem_cnt]; */
906 /* char gr_name[gr_name_len]; */
907 /* char gr_passwd[gr_passwd_len]; */
908 /* char gr_mem[gr_mem_cnt][gr_mem_len[i]]; */
909 /* char gr_gid_str[as_needed]; - huh? */
910 /* char orig_key[as_needed]; - needed?? I don't do this ATM... */
912 glibc adds gr_gid_str, but client doesn't get/use it:
913 writev(3, [{"\2\0\0\0\2\0\0\0\5\0\0\0", 12}, {"root\0", 5}], 2) = 17
914 poll([{fd=3, events=POLLIN|POLLERR|POLLHUP, revents=POLLIN}], 1, 5000) = 1
915 read(3, "\2\0\0\0\1\0\0\0\10\0\0\0\4\0\0\0\0\0\0\0\0\0\0\0", 24) = 24
916 readv(3, [{"", 0}, {"root\0\0\0\0\0\0\0\0", 12}], 2) = 12
919 } gr_response_header;
921 static gr_response_header *marshal_group(struct group *gr)
924 gr_response_header *resp;
926 unsigned sz = sizeof(*resp);
928 sz += strsize(gr->gr_name);
929 sz += strsize(gr->gr_passwd);
931 while (gr->gr_mem[gr_mem_cnt]) {
932 sz += strsize(gr->gr_mem[gr_mem_cnt]);
935 /* for int32_t gr_mem_len[gr_mem_cnt]; */
936 sz += gr_mem_cnt * sizeof(int32_t);
939 resp->version_or_size = sz;
945 resp->gr_name_len = strsize(gr->gr_name);
946 resp->gr_passwd_len = strsize(gr->gr_passwd);
947 resp->gr_gid = gr->gr_gid;
948 resp->gr_mem_cnt = gr_mem_cnt;
949 p = (char*)(resp + 1);
950 /* int32_t gr_mem_len[gr_mem_cnt]; */
952 while (gr->gr_mem[gr_mem_cnt]) {
953 *(uint32_t*)p = strsize(gr->gr_mem[gr_mem_cnt]);
957 /* char gr_name[gr_name_len]; */
958 strcpy(p, gr->gr_name);
959 p += strsize(gr->gr_name);
960 /* char gr_passwd[gr_passwd_len]; */
961 strcpy(p, gr->gr_passwd);
962 p += strsize(gr->gr_passwd);
963 /* char gr_mem[gr_mem_cnt][gr_mem_len[i]]; */
965 while (gr->gr_mem[gr_mem_cnt]) {
966 strcpy(p, gr->gr_mem[gr_mem_cnt]);
967 p += strsize(gr->gr_mem[gr_mem_cnt]);
970 log(L_DEBUG, "sz:%u realsz:%u", sz, p - (char*)resp);
975 typedef struct hst_response_header {
976 uint32_t version_or_size;
979 int32_t h_aliases_cnt;
980 int32_t h_addrtype; /* AF_INET or AF_INET6 */
981 int32_t h_length; /* 4 or 16 */
982 int32_t h_addr_list_cnt;
984 /* char h_name[h_name_len]; - we pad it to 4 bytes */
985 /* uint32_t h_aliases_len[h_aliases_cnt]; */
986 /* char h_addr_list[h_addr_list_cnt][h_length]; - every one is the same size [h_length] (4 or 16) */
987 /* char h_aliases[h_aliases_cnt][h_aliases_len[i]]; */
988 } hst_response_header;
990 static hst_response_header *marshal_hostent(struct hostent *h)
993 hst_response_header *resp;
995 unsigned h_aliases_cnt;
996 unsigned h_addr_list_cnt;
997 unsigned sz = sizeof(*resp);
999 /* char h_name[h_name_len] */
1000 sz += h_name_len = strsize_aligned4(h->h_name);
1001 h_addr_list_cnt = 0;
1002 while (h->h_addr_list[h_addr_list_cnt]) {
1005 /* char h_addr_list[h_addr_list_cnt][h_length] */
1006 sz += h_addr_list_cnt * h->h_length;
1008 while (h->h_aliases[h_aliases_cnt]) {
1009 /* char h_aliases[h_aliases_cnt][h_aliases_len[i]] */
1010 sz += strsize(h->h_aliases[h_aliases_cnt]);
1013 /* uint32_t h_aliases_len[h_aliases_cnt] */
1014 sz += h_aliases_cnt * 4;
1017 resp->version_or_size = sz;
1019 /*resp->found = 0;*/
1020 resp->error = HOST_NOT_FOUND;
1024 resp->h_name_len = h_name_len;
1025 resp->h_aliases_cnt = h_aliases_cnt;
1026 resp->h_addrtype = h->h_addrtype;
1027 resp->h_length = h->h_length;
1028 resp->h_addr_list_cnt = h_addr_list_cnt;
1029 /*resp->error = 0;*/
1030 p = (char*)(resp + 1);
1031 /* char h_name[h_name_len]; */
1032 strcpy(p, h->h_name);
1034 /* uint32_t h_aliases_len[h_aliases_cnt]; */
1036 while (h->h_aliases[h_aliases_cnt]) {
1037 *(uint32_t*)p = strsize(h->h_aliases[h_aliases_cnt]);
1041 /* char h_addr_list[h_addr_list_cnt][h_length]; */
1042 h_addr_list_cnt = 0;
1043 while (h->h_addr_list[h_addr_list_cnt]) {
1044 memcpy(p, h->h_addr_list[h_addr_list_cnt], h->h_length);
1048 /* char h_aliases[h_aliases_cnt][h_aliases_len[i]]; */
1050 while (h->h_aliases[h_aliases_cnt]) {
1051 strcpy(p, h->h_aliases[h_aliases_cnt]);
1052 p += strsize(h->h_aliases[h_aliases_cnt]);
1055 log(L_DEBUG, "sz:%u realsz:%u", sz, p - (char*)resp);
1060 /* Reply to addrinfo query */
1061 typedef struct ai_response_header {
1062 uint32_t version_or_size;
1068 /* char ai_addr[naddrs][4 or 16]; - addrslen bytes in total */
1069 /* char ai_family[naddrs]; - AF_INET[6] each (determines ai_addr[i] length) */
1070 /* char ai_canonname[canonlen]; */
1071 } ai_response_header;
1073 static ai_response_header *obtain_addrinfo(const char *hostname)
1075 struct addrinfo hints;
1076 struct addrinfo *ai;
1077 struct addrinfo *ap;
1078 ai_response_header *resp;
1082 unsigned naddrs = 0;
1083 unsigned addrslen = 0;
1084 unsigned canonlen = 0;
1086 memset(&hints, 0, sizeof(hints));
1087 hints.ai_flags = AI_CANONNAME;
1088 /* kills dups (one for each possible SOCK_xxx) */
1089 /* this matches glibc behavior */
1090 hints.ai_socktype = SOCK_STREAM;
1091 ai = NULL; /* on failure getaddrinfo may leave it as-is */
1092 err = getaddrinfo(hostname, NULL, &hints, &ai);
1096 if (ai->ai_canonname)
1097 sz += canonlen = strsize(ai->ai_canonname);
1101 addrslen += (ap->ai_family == AF_INET ? 4 : 16);
1104 sz += naddrs + addrslen;
1107 resp->version_or_size = sz;
1110 /*resp->found = 0;*/
1114 resp->naddrs = naddrs;
1115 resp->addrslen = addrslen;
1116 resp->canonlen = canonlen;
1117 p = (char*)(resp + 1);
1118 family = p + addrslen;
1121 /* char ai_family[naddrs]; */
1122 *family++ = ap->ai_family;
1123 /* char ai_addr[naddrs][4 or 16]; */
1124 if (ap->ai_family == AF_INET) {
1125 memcpy(p, &(((struct sockaddr_in*)(ap->ai_addr))->sin_addr), 4);
1128 memcpy(p, &(((struct sockaddr_in6*)(ap->ai_addr))->sin6_addr), 16);
1133 /* char ai_canonname[canonlen]; */
1134 if (ai->ai_canonname)
1135 strcpy(family, ai->ai_canonname);
1136 log(L_DEBUG, "sz:%u realsz:%u", sz, family + strsize(ai->ai_canonname) - (char*)resp);
1138 /* glibc 2.3.6 segfaults here sometimes
1139 * (maybe my mistake, fixed by "ai = NULL;" above).
1140 * Since we are in worker and are going to exit anyway, why bother? */
1141 /*freeaddrinfo(ai);*/
1150 /* one 8-element "cacheline" */
1151 typedef user_req *cacheline_t[8];
1152 static unsigned cache_size;
1153 /* Points to cacheline_t cache[cache_size] array, or in other words,
1154 * points to user_req* cache[cache_size][8] array */
1155 static cacheline_t *cache;
1156 static unsigned cached_cnt;
1157 static unsigned cache_access_cnt = 1; /* prevent division by zero */
1158 static unsigned cache_hit_cnt = 1;
1159 static unsigned last_age_time;
1160 static unsigned aging_interval_ms;
1161 static unsigned min_aging_interval_ms;
1163 static response_header *ureq_response(user_req *ureq)
1165 /* Skip query part, find answer part
1166 * (answer is 32-bit aligned) */
1167 return (void*) ((char*)ureq + ((ureq_size(ureq) + 3) & ~3));
1170 /* This hash is supposed to be good for short textual data */
1171 static uint32_t bernstein_hash(void *p, unsigned sz, uint32_t hash)
1175 hash = (32 * hash + hash) ^ *key++;
1180 static void free_refcounted_ureq(user_req **ureqp)
1182 user_req *ureq = *ureqp;
1184 if (!CACHED_ENTRY(ureq))
1187 if (ureq->refcount) {
1190 log(L_DEBUG2, "refcount == 0, free(%p)", ureq);
1196 static user_req **lookup_in_cache(user_req *ureq)
1198 user_req **cacheline;
1202 unsigned ureq_sz = ureq_size(ureq);
1204 /* prevent overflow and division by zero */
1206 if ((int)cache_access_cnt < 0) {
1207 cache_access_cnt = (cache_access_cnt >> 1) + 1;
1208 cache_hit_cnt = (cache_hit_cnt >> 1) + 1;
1211 hash = bernstein_hash(&ureq->key_len, ureq_sz - offsetof(user_req, key_len), ureq->type);
1212 log(L_DEBUG2, "hash:%08x", hash);
1213 hash = hash % cache_size;
1214 cacheline = cache[hash];
1217 for (i = 0; i < 8; i++) {
1218 user_req *cached = CACHE_PTR(cacheline[i]);
1220 if (free_cache == -1)
1224 /* ureq->version is always 2 and is reused in cache
1225 * for other purposes, we need to skip it here */
1226 if (memcmp(&ureq->type, &cached->type, ureq_sz - offsetof(user_req, type)) == 0) {
1227 log(L_DEBUG, "found in cache[%u][%u]", hash, i);
1229 return &cacheline[i];
1233 if (free_cache >= 0) {
1236 log(L_DEBUG, "not found, using free cache[%u][%u]", hash, i);
1240 unsigned oldest_idx = 0;
1241 unsigned oldest_age = 0;
1242 for (i = 0; i < 8; i++) {
1243 unsigned age = cache_age(cacheline[i]);
1244 if (age > oldest_age) {
1249 if (oldest_age == 0) {
1250 /* All entries in cacheline are "future" entries!
1251 * This is very unlikely, but we must still work correctly.
1252 * We call this "fake cache entry".
1253 * The data will be "cached" only for the duration
1254 * of this client's request lifetime.
1256 log(L_DEBUG, "not found, and cache[%u] is full: using fake cache entry", hash);
1260 log(L_DEBUG, "not found, freeing and reusing cache[%u][%u] (age %u)", hash, i, oldest_age);
1261 free_refcounted_ureq(&cacheline[i]);
1264 cacheline[i] = MAKE_FUTURE_PTR(ureq);
1265 return &cacheline[i];
1268 static void age_cache(unsigned free_all, int srv)
1270 user_req **cp = *cache;
1272 unsigned sv = cached_cnt;
1274 log(L_DEBUG, "aging cache, srv:%d, free_all:%u", srv, free_all);
1275 if (srv == -1 || free_all)
1276 aging_interval_ms = INT_MAX;
1279 user_req *cached = *cp;
1280 if (CACHED_ENTRY(cached) && cached != NULL) {
1281 int csrv = type_to_srv[cached->type];
1282 if (srv == -1 || srv == csrv) {
1285 free_refcounted_ureq(cp);
1287 unsigned age = cache_age(cached);
1288 response_header *resp = ureq_response(cached);
1289 unsigned ttl = (resp->found ? config.pttl : config.nttl)[csrv];
1291 log(L_DEBUG2, "freeing: age %u positive %d ttl %u", age, resp->found, ttl);
1293 free_refcounted_ureq(cp);
1294 } else if (srv == -1) {
1296 if (aging_interval_ms > ttl)
1297 aging_interval_ms = ttl;
1304 log(L_INFO, "aged cache, freed:%u, remain:%u", sv - cached_cnt, cached_cnt);
1305 log(L_DEBUG2, "aging interval now %u ms", aging_interval_ms);
1313 /* Spawns a worker and feeds it with user query on stdin */
1314 /* Returns stdout fd of the worker, in blocking mode */
1315 static int create_and_feed_worker(user_req *ureq)
1321 } to_child, to_parent;
1323 /* NB: these pipe fds are in blocking mode and non-CLOEXECed */
1324 xpipe(&to_child.rd);
1325 xpipe(&to_parent.rd);
1328 if (pid < 0) /* error */
1329 perror_and_die("vfork");
1330 if (!pid) { /* child */
1331 char param[sizeof(int)*3 + 2];
1335 close(to_parent.rd);
1336 xmovefd(to_child.rd, 0);
1337 xmovefd(to_parent.wr, 1);
1338 sprintf(param, "%u", debug);
1339 argv[0] = (char*) "worker_nscd";
1342 /* Re-exec ourself, cleaning up all allocated memory.
1343 * fds in parent are marked CLOEXEC and will be closed too
1345 /* Try link name first: it's better to have comm field
1346 * of "nscd" than "exe" (pgrep reported to fail to find us
1347 * by name when comm field contains "exe") */
1348 execve(self_exe_points_to, argv, argv+2);
1349 xexecve("/proc/self/exe", argv, argv+2);
1354 close(to_parent.wr);
1355 /* We do not expect child to block for any noticeably long time,
1356 * and also we expect write to be one-piece one:
1357 * ureq size is <= 1k and pipes are guaranteed to accept
1358 * at least PIPE_BUF at once */
1359 xsafe_write(to_child.wr, ureq, ureq_size(ureq));
1362 close_on_exec(to_parent.rd);
1363 return to_parent.rd;
1366 static user_req *worker_ureq;
1369 static const char *req_str(unsigned type, const char *buf)
1371 if (type == GETHOSTBYADDR) {
1373 in.s_addr = *((uint32_t*)buf);
1374 return inet_ntoa(in);
1376 if (type == GETHOSTBYADDRv6) {
1382 const char *req_str(unsigned type, const char *buf);
1385 static void worker_signal_handler(int sig)
1388 log(L_INFO, "worker:%d got sig:%d while handling req "
1389 "type:%d(%s) key_len:%d '%s'",
1391 worker_ureq->type, typestr[worker_ureq->type],
1392 worker_ureq->key_len,
1393 req_str(worker_ureq->type, worker_ureq->reqbuf)
1396 log(L_INFO, "worker:%d got sig:%d while handling req "
1397 "type:%d key_len:%d",
1399 worker_ureq->type, worker_ureq->key_len);
1404 static void worker(const char *param) NORETURN;
1405 static void worker(const char *param)
1410 debug = atoi(param);
1412 worker_ureq = &ureq; /* for signal handler */
1414 /* Make sure we won't hang, but rather die */
1415 if (WORKER_TIMEOUT_SEC)
1416 alarm(WORKER_TIMEOUT_SEC);
1418 /* NB: fds 0, 1 are in blocking mode */
1420 /* We block here (for a short time) */
1421 /* Due to ureq size < PIPE_BUF read is atomic */
1422 /* No error or size checking: we trust the parent */
1423 safe_read(0, &ureq, sizeof(ureq));
1425 signal(SIGSEGV, worker_signal_handler);
1426 signal(SIGBUS, worker_signal_handler);
1427 signal(SIGILL, worker_signal_handler);
1428 signal(SIGFPE, worker_signal_handler);
1429 signal(SIGABRT, worker_signal_handler);
1431 signal(SIGSTKFLT, worker_signal_handler);
1434 if (ureq.type == GETHOSTBYNAME
1435 || ureq.type == GETHOSTBYNAMEv6
1437 resp = marshal_hostent(
1438 ureq.type == GETHOSTBYNAME
1439 ? gethostbyname(ureq.reqbuf)
1440 : gethostbyname2(ureq.reqbuf, AF_INET6)
1442 } else if (ureq.type == GETHOSTBYADDR
1443 || ureq.type == GETHOSTBYADDRv6
1445 resp = marshal_hostent(gethostbyaddr(ureq.reqbuf, ureq.key_len,
1446 (ureq.type == GETHOSTBYADDR ? AF_INET : AF_INET6)
1448 } else if (ureq.type == GETPWBYNAME) {
1450 log(L_DEBUG2, "getpwnam('%s')", ureq.reqbuf);
1451 pw = getpwnam(ureq.reqbuf);
1452 log(L_DEBUG2, "getpwnam result:%p", pw);
1453 resp = marshal_passwd(pw);
1454 } else if (ureq.type == GETPWBYUID) {
1455 resp = marshal_passwd(getpwuid(atoi(ureq.reqbuf)));
1456 } else if (ureq.type == GETGRBYNAME) {
1457 struct group *gr = getgrnam(ureq.reqbuf);
1458 resp = marshal_group(gr);
1459 } else if (ureq.type == GETGRBYGID) {
1460 struct group *gr = getgrgid(atoi(ureq.reqbuf));
1461 resp = marshal_group(gr);
1462 } else if (ureq.type == GETAI) {
1463 resp = obtain_addrinfo(ureq.reqbuf);
1464 } else /*if (ureq.type == INITGROUPS)*/ {
1465 resp = obtain_initgroups(ureq.reqbuf);
1468 if (!((response_header*)resp)->found) {
1469 /* Parent knows about this special case */
1470 xfull_write(1, resp, 8);
1472 /* Responses can be big (getgrnam("guest") on a big user db),
1473 * we cannot rely on them being atomic. full_write loops
1475 xfull_write(1, resp, ((response_header*)resp)->version_or_size);
1485 static const char checked_filenames[][sizeof("/etc/passwd")] = {
1486 [SRV_PASSWD] = "/etc/passwd", /* "/etc/shadow"? */
1487 [SRV_GROUP] = "/etc/group",
1488 [SRV_HOSTS] = "/etc/hosts", /* "/etc/resolv.conf" "/etc/nsswitch.conf"? */
1491 static long checked_status[ARRAY_SIZE(checked_filenames)];
1493 static void check_files(int srv)
1496 const char *file = checked_filenames[srv];
1499 memset(&tsb, 0, sizeof(tsb));
1500 stat(file, &tsb); /* ignore errors */
1501 /* Comparing struct stat's was giving false positives.
1502 * Extracting only those fields which are interesting: */
1503 v = (long)tsb.st_mtime ^ (long)tsb.st_size ^ (long)tsb.st_ino; /* ^ (long)tsb.st_dev ? */
1505 if (v != checked_status[srv]) {
1506 checked_status[srv] = v;
1507 log(L_INFO, "detected change in %s", file);
1508 age_cache(/*free_all:*/ 1, srv);
1512 /* Returns 1 if we immediately have the answer */
1513 static int handle_client(int i)
1516 user_req *ureq = cinfo[i].ureq;
1517 user_req **cache_pp;
1518 user_req *ureq_and_resp;
1521 log(L_DEBUG, "version:%d type:%d(%s) key_len:%d '%s'",
1522 ureq->version, ureq->type,
1523 ureq->type < ARRAY_SIZE(typestr) ? typestr[ureq->type] : "BAD",
1524 ureq->key_len, req_str(ureq->type, ureq->reqbuf));
1527 if (ureq->version != NSCD_VERSION) {
1528 log(L_INFO, "wrong version");
1532 if (ureq->key_len > sizeof(ureq->reqbuf)) {
1533 log(L_INFO, "bogus key_len %u - ignoring", ureq->key_len);
1537 if (cinfo[i].bytecnt < USER_HDR_SIZE + ureq->key_len) {
1538 log(L_INFO, "read %d, need to read %d",
1539 cinfo[i].bytecnt, USER_HDR_SIZE + ureq->key_len);
1540 return 0; /* more to read */
1542 if (cinfo[i].bytecnt > USER_HDR_SIZE + ureq->key_len) {
1543 log(L_INFO, "read overflow");
1547 if (unsupported_ureq_type(ureq->type)) {
1548 /* We don't know this request. Just close the connection.
1549 * (glibc client interprets this like "not supported by this nscd")
1550 * Happens very often, thus DEBUG, not INFO */
1551 log(L_DEBUG, "unsupported query, dropping");
1555 srv = type_to_srv[ureq->type];
1556 if (!config.srv_enable[srv]) {
1557 log(L_INFO, "service %d is disabled, dropping", srv);
1562 hex_dump(cinfo[i].ureq, cinfo[i].bytecnt);
1564 if (ureq->type == SHUTDOWN
1565 || ureq->type == INVALIDATE
1568 struct ucred caller;
1569 socklen_t optlen = sizeof(caller);
1570 if (getsockopt(pfd[i].fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0) {
1571 log(L_INFO, "ignoring special request - cannot get caller's id: %s", strerror(errno));
1575 if (caller.uid != 0) {
1576 log(L_INFO, "special request from non-root - ignoring");
1581 if (ureq->type == SHUTDOWN) {
1582 log(L_INFO, "got shutdown request, exiting");
1585 if (!ureq->key_len || ureq->reqbuf[ureq->key_len - 1]) {
1586 log(L_INFO, "malformed invalidate request - ignoring");
1590 log(L_INFO, "got invalidate request, flushing cache");
1591 /* Frees entire cache. TODO: replace -1 with service (in ureq->reqbuf) */
1592 age_cache(/*free_all:*/ 1, -1);
1597 if (ureq->type != GETHOSTBYADDR
1598 && ureq->type != GETHOSTBYADDRv6
1600 if (ureq->key_len && ureq->reqbuf[ureq->key_len - 1] != '\0') {
1601 log(L_INFO, "badly terminated buffer");
1607 if (config.check_files[srv]) {
1611 cache_pp = lookup_in_cache(ureq);
1612 ureq_and_resp = cache_pp ? *cache_pp : NULL;
1614 if (ureq_and_resp) {
1615 if (CACHED_ENTRY(ureq_and_resp)) {
1616 /* Found. Save ptr to response into cinfo and return */
1617 response_header *resp = ureq_response(ureq_and_resp);
1618 unsigned sz = resp->version_or_size;
1620 log(L_DEBUG, "sz:%u", sz);
1622 ureq_and_resp->refcount++; /* cache shouldn't free it under us! */
1623 pfd[i].events = POLLOUT; /* we want to write out */
1624 cinfo[i].resptr = ureq_and_resp;
1625 /*cinfo[i].respos = 0; - already is */
1626 /* prevent future matches with anything */
1627 cinfo[i].cache_pp = (void *) 1;
1628 return 1; /* "ready to write data out to client" */
1631 /* Not found. Remember a pointer where it will appear */
1632 cinfo[i].cache_pp = cache_pp;
1634 /* If it does not point to our own ureq buffer... */
1635 if (CACHE_PTR(ureq_and_resp) != ureq) {
1636 /* We are not the first client who wants this */
1637 log(L_DEBUG, "another request is in progress (%p), waiting for its result", ureq_and_resp);
1638 MARK_PTR_SHARED(cache_pp); /* "please inform us when it's ready" */
1639 /* "we do not wait for client anymore" */
1640 cinfo[i].client_fd = pfd[i].fd;
1641 /* Don't wait on fd. Worker response will unblock us */
1645 /* else: lookup_in_cache inserted (ureq & 1) into *cache_pp:
1646 * we are the first client to miss on this ureq. */
1649 /* Start worker thread */
1650 log(L_DEBUG, "stored %p in cache, starting a worker", ureq_and_resp);
1651 /* Now we will wait on worker's fd, not client's! */
1652 cinfo[i].client_fd = pfd[i].fd;
1653 pfd[i].fd = create_and_feed_worker(ureq);
1657 static void prepare_for_writeout(unsigned i, user_req *cached)
1659 log(L_DEBUG2, "client %u: data is ready at %p", i, cached);
1661 if (cinfo[i].client_fd) {
1662 pfd[i].fd = cinfo[i].client_fd;
1663 cinfo[i].client_fd = 0; /* "we don't wait for worker reply" */
1665 pfd[i].events = POLLOUT;
1667 /* Writeout position etc */
1668 cinfo[i].resptr = cached;
1669 /*cinfo[i].respos = 0; - already is */
1670 /* if worker took some time to get info (e.g. DNS query),
1671 * prevent client timeout from triggering at once */
1672 cinfo[i].started_ms = g_now_ms;
1675 /* Worker seems to be ready to write the response.
1676 * When we return, response is fully read and stored in cache,
1677 * worker's fd is closed, pfd[i] and cinfo[i] are updated. */
1678 static void handle_worker_response(int i)
1680 struct { /* struct response_header + small body */
1681 uint32_t version_or_size;
1687 response_header *resp;
1688 unsigned sz, resp_sz;
1689 unsigned ureq_sz_aligned;
1692 ureq = cinfo[i].ureq;
1693 ureq_sz_aligned = (char*)ureq_response(ureq) - (char*)ureq;
1695 sz = full_read(pfd[i].fd, &sz_and_found, sizeof(sz_and_found));
1697 /* worker was killed? */
1698 log(L_DEBUG, "worker gave short reply:%u < 8", sz);
1702 resp_sz = sz_and_found.version_or_size;
1703 if (resp_sz < sz || resp_sz > 0xfffffff) { /* 256 mb */
1704 error("BUG: bad size from worker:%u", resp_sz);
1708 /* Create new block of cached info */
1709 cached = xzalloc(ureq_sz_aligned + resp_sz);
1710 log(L_DEBUG2, "xzalloc(%u):%p", ureq_sz_aligned + resp_sz, cached);
1711 resp = (void*) (((char*) cached) + ureq_sz_aligned);
1712 memcpy(cached, ureq, ureq_size(ureq));
1713 memcpy(resp, &sz_and_found, sz);
1714 if (sz_and_found.found && resp_sz > sz) {
1715 /* We need to read data only if it's found
1716 * (otherwise worker sends only 8 bytes).
1718 * Replies can be big (getgrnam("guest") on a big user db),
1719 * we cannot rely on them being atomic. However, we know
1720 * that worker _always_ gives reply in one full_write(),
1721 * so we loop and read it all
1722 * (looping is implemented inside full_read())
1724 if (full_read(pfd[i].fd, ((char*) resp) + sz, resp_sz - sz) != resp_sz - sz) {
1725 /* worker was killed? */
1726 log(L_DEBUG, "worker gave short reply, free(%p)", cached);
1733 set_cache_timestamp(cached);
1734 hex_dump(resp, resp_sz);
1741 user_req **cache_pp = cinfo[i].cache_pp;
1742 if (cache_pp != NULL) { /* if not a fake entry */
1745 if (CACHE_SHARED(ureq)) {
1746 /* Other clients wait for this response too,
1747 * wake them (and us) up and set refcount = no_of_clients */
1750 for (j = 2; j < num_clients; j++) {
1751 if (cinfo[j].cache_pp == cache_pp) {
1752 /* This client uses the same cache entry */
1754 /* prevent future matches with anything */
1755 cinfo[j].cache_pp = (void *) 1;
1756 prepare_for_writeout(j, cached);
1761 /* prevent future matches with anything */
1762 cinfo[i].cache_pp = (void *) 1;
1766 prepare_for_writeout(i, cached);
1768 /* cache shouldn't free it under us! */
1770 cached->refcount = ref;
1771 aging_interval_ms = min_aging_interval_ms;
1774 static void main_loop(void)
1776 /* 1/2 of smallest negative TTL */
1777 min_aging_interval_ms = config.nttl[0];
1778 if (min_aging_interval_ms > config.nttl[1]) min_aging_interval_ms = config.nttl[1];
1779 if (min_aging_interval_ms > config.nttl[2]) min_aging_interval_ms = config.nttl[2];
1780 min_aging_interval_ms = (min_aging_interval_ms / 2) | 1;
1781 aging_interval_ms = min_aging_interval_ms;
1787 r = SMALL_POLL_TIMEOUT_MS;
1788 if (num_clients <= 2 && !cached_cnt)
1789 r = -1; /* infinite */
1790 else if (num_clients < max_reqnum)
1791 r = aging_interval_ms;
1792 #if 0 /* Debug: leak detector */
1794 static unsigned long long cnt;
1795 static unsigned long low_malloc = -1L;
1796 static unsigned long low_sbrk = -1L;
1797 void *p = malloc(540); /* should not be too small */
1800 if ((unsigned long)p < low_malloc)
1801 low_malloc = (unsigned long)p;
1802 if ((unsigned long)s < low_sbrk)
1803 low_sbrk = (unsigned long)s;
1804 log(L_INFO, "poll %llu (%d ms). clients:%u cached:%u %u/%u malloc:%p (%lu), sbrk:%p (%lu)",
1805 cnt, r, num_clients, cached_cnt, cache_hit_cnt, cache_access_cnt,
1806 p, (unsigned long)p - low_malloc,
1807 s, (unsigned long)s - low_sbrk);
1811 log(L_DEBUG, "poll %d ms. clients:%u cached:%u hit ratio:%u/%u",
1812 r, num_clients, cached_cnt, cache_hit_cnt, cache_access_cnt);
1815 r = poll(pfd, num_clients, r);
1816 log(L_DEBUG2, "poll returns %d", r);
1819 perror_and_die("poll");
1823 /* Everything between polls never sleeps.
1824 * There is no blocking I/O (except when we talk to worker thread
1825 * which is guaranteed to not block us for long) */
1827 g_now_ms = monotonic_ms();
1829 goto skip_fd_checks;
1831 for (i = 0; i < 2; i++) {
1833 if (!pfd[i].revents)
1835 /* pfd[i].revents = 0; - not needed */
1836 cfd = accept(pfd[i].fd, NULL, NULL);
1838 /* odd... poll() says we can accept but accept failed? */
1839 log(L_DEBUG2, "accept failed with %s", strerror(errno));
1844 /* x[num_clients] is next free element, taking it */
1845 log(L_DEBUG2, "new client %d, fd %d", num_clients, cfd);
1846 pfd[num_clients].fd = cfd;
1847 pfd[num_clients].events = POLLIN;
1848 /* this will make us do read() in next for() loop: */
1849 pfd[num_clients].revents = POLLIN;
1850 memset(&cinfo[num_clients], 0, sizeof(cinfo[num_clients]));
1851 /* cinfo[num_clients].bytecnt = 0; - done */
1852 cinfo[num_clients].started_ms = g_now_ms;
1853 cinfo[num_clients].bufidx = alloc_buf_no();
1854 cinfo[num_clients].ureq = bufno2buf(cinfo[num_clients].bufidx);
1856 if (num_clients >= max_reqnum) {
1857 /* stop accepting new connects for now */
1858 pfd[0].events = pfd[0].revents = 0;
1859 pfd[1].events = pfd[1].revents = 0;
1862 for (; i < num_clients; i++) {
1863 if (!pfd[i].revents)
1865 log(L_DEBUG2, "pfd[%d].revents:0x%x", i, pfd[i].revents);
1866 /* pfd[i].revents = 0; - not needed */
1868 /* "Write out result" case */
1869 if (pfd[i].revents == POLLOUT) {
1870 response_header *resp;
1872 if (!cinfo[i].resptr) {
1873 /* corner case: worker gave bad response earlier */
1878 resp = ureq_response(cinfo[i].resptr);
1879 resp_sz = resp->version_or_size;
1880 resp->version_or_size = NSCD_VERSION;
1881 r = safe_write(pfd[i].fd, ((char*) resp) + cinfo[i].respos, resp_sz - cinfo[i].respos);
1882 resp->version_or_size = resp_sz;
1884 if (r < 0 && errno == EAGAIN)
1886 if (r <= 0) { /* client isn't there anymore */
1887 log(L_DEBUG, "client %d is gone (write returned %d)", i, r);
1889 if (cinfo[i].cache_pp == NULL) {
1890 log(L_DEBUG, "client %d: freeing fake cache entry %p", i, cinfo[i].resptr);
1891 free(cinfo[i].resptr);
1893 /* Most of the time, it is not freed here,
1894 * only refcounted--. Freeing happens
1895 * if it was deleted from cache[] but retained
1897 free_refcounted_ureq(&cinfo[i].resptr);
1902 cinfo[i].respos += r;
1903 if (cinfo[i].respos >= resp_sz) {
1904 /* We wrote everything */
1905 /* No point in trying to get next request, it won't come.
1906 * glibc 2.4 client closes its end after each request,
1907 * without testing for EOF from server. strace:
1909 * read(3, "www.google.com\0\0", 16) = 16
1912 log(L_DEBUG, "client %u: sent answer %u bytes", i, cinfo[i].respos);
1913 goto write_out_is_done;
1917 /* "Read reply from worker" case. Worker may be
1918 * already dead, revents may contain other bits too */
1919 if ((pfd[i].revents & POLLIN) && cinfo[i].client_fd) {
1920 log(L_DEBUG, "reading response for client %u", i);
1921 handle_worker_response(i);
1922 /* We can immediately try to write a response
1927 /* POLLHUP means pfd[i].fd is closed by peer.
1928 * POLLHUP+POLLOUT is seen when we switch for writeout
1929 * and see that pfd[i].fd is closed by peer. */
1930 if ((pfd[i].revents & ~POLLOUT) == POLLHUP) {
1931 int is_client = (cinfo[i].client_fd == 0 || cinfo[i].client_fd == pfd[i].fd);
1932 log(L_INFO, "%s %u disappeared (got POLLHUP on fd %d)",
1933 is_client ? "client" : "worker",
1940 /* Read worker output anyway, error handling
1941 * in that function deals with short read.
1942 * Simply closing client is wrong: it leaks
1943 * shared future entries. */
1944 handle_worker_response(i);
1949 /* All strange and unexpected cases */
1950 if (pfd[i].revents != POLLIN) {
1951 /* Not just "can read", but some other bits are there */
1952 log(L_INFO, "client %u revents is strange:%x", i, pfd[i].revents);
1957 /* "Read request from client" case */
1958 r = safe_read(pfd[i].fd, (char*)(cinfo[i].ureq) + cinfo[i].bytecnt, MAX_USER_REQ_SIZE - cinfo[i].bytecnt);
1960 log(L_DEBUG2, "error reading from client: %s", strerror(errno));
1961 if (errno == EAGAIN)
1967 log(L_INFO, "premature EOF from client, dropping");
1971 cinfo[i].bytecnt += r;
1972 if (cinfo[i].bytecnt >= sizeof(user_req_header)) {
1973 if (handle_client(i)) {
1974 /* Response is found in cache! */
1978 } /* for each client[2..num_clients-1] */
1982 if ((g_now_ms - last_age_time) >= aging_interval_ms) {
1983 last_age_time = g_now_ms;
1984 age_cache(/*free_all:*/ 0, -1);
1987 /* Close timed out client connections */
1988 for (i = 2; i < num_clients; i++) {
1989 if (pfd[i].fd != 0 /* not closed yet? */ ////
1990 && cinfo[i].client_fd == 0 /* do we still wait for client, not worker? */
1991 && (g_now_ms - cinfo[i].started_ms) > CLIENT_TIMEOUT_MS
1993 log(L_INFO, "timed out waiting for client %u (%u ms), dropping",
1994 i, (unsigned)(g_now_ms - cinfo[i].started_ms));
2002 /* We closed at least one client, coalesce pfd[], cinfo[] */
2003 if (min_closed + cnt_closed >= num_clients) {
2004 /* clients [min_closed..num_clients-1] are all closed */
2005 /* log(L_DEBUG, "taking shortcut"); - almost always happens */
2010 while (i < num_clients) {
2014 if (++i >= num_clients)
2018 cinfo[j++] = cinfo[i++];
2022 num_clients -= cnt_closed;
2023 log(L_DEBUG, "removing %d closed clients. clients:%d", cnt_closed, num_clients);
2024 min_closed = INT_MAX;
2026 /* start accepting new connects */
2027 pfd[0].events = POLLIN;
2028 pfd[1].events = POLLIN;
2037 #define NSCD_PIDFILE "/var/run/nscd/nscd.pid"
2038 #define NSCD_DIR "/var/run/nscd"
2039 #define NSCD_SOCKET "/var/run/nscd/socket"
2040 #define NSCD_SOCKET_OLD "/var/run/.nscd_socket"
2042 static smallint wrote_pidfile;
2044 static void cleanup_on_signal(int sig)
2047 unlink(NSCD_PIDFILE);
2048 unlink(NSCD_SOCKET_OLD);
2049 unlink(NSCD_SOCKET);
2053 static void write_pid(void)
2055 FILE *pid = fopen(NSCD_PIDFILE, "w");
2058 fprintf(pid, "%d\n", getpid());
2063 /* Open a listening nscd server socket */
2064 static int open_socket(const char *name)
2066 struct sockaddr_un sun;
2067 int sock = socket(AF_UNIX, SOCK_STREAM, 0);
2069 perror_and_die("cannot create unix domain socket");
2071 close_on_exec(sock);
2072 sun.sun_family = AF_UNIX;
2073 strcpy(sun.sun_path, name);
2075 if (bind(sock, (struct sockaddr *) &sun, sizeof(sun)) < 0)
2076 perror_and_die("bind(%s)", name);
2077 if (chmod(name, 0666) < 0)
2078 perror_and_die("chmod(%s)", name);
2079 if (listen(sock, (max_reqnum/8) | 1) < 0)
2080 perror_and_die("listen");
2084 static const struct option longopt[] = {
2085 /* name, has_arg, int *flag, int val */
2086 { "debug" , no_argument , NULL, 'd' },
2087 { "config-file", required_argument, NULL, 'f' },
2088 { "invalidate" , required_argument, NULL, 'i' },
2089 { "shutdown" , no_argument , NULL, 'K' },
2090 { "nthreads" , required_argument, NULL, 't' },
2091 { "version" , no_argument , NULL, 'V' },
2092 { "help" , no_argument , NULL, '?' },
2093 { "usage" , no_argument , NULL, '?' },
2094 /* just exit(0). TODO: "test" connect? */
2095 { "statistic" , no_argument , NULL, 'g' },
2096 { "secure" , no_argument , NULL, 'S' }, /* ? */
2100 static const char *const help[] = {
2101 "Do not daemonize; log to stderr (-dd: more verbosity)",
2102 "File to read configuration from",
2104 "Shut the server down",
2105 "Serve N requests in parallel",
2109 static void print_help_and_die(void)
2111 const struct option *opt = longopt;
2112 const char *const *h = help;
2114 puts("Usage: nscd [OPTION...]\n"
2115 "Name Service Cache Daemon\n");
2117 printf("\t" "-%c,--%-11s %s\n", opt->val, opt->name, *h);
2120 } while (opt->val != '?');
2124 static char *skip_service(int *srv, const char *s)
2126 if (strcmp("passwd", s) == 0) {
2129 } else if (strcmp("group", s) == 0) {
2131 } else if (strcmp("hosts", s) == 0) {
2136 return skip_whitespace(s + 6);
2139 static void handle_null(const char *str, int srv) {}
2141 static void handle_logfile(const char *str, int srv)
2143 config.logfile = xstrdup(str);
2146 static void handle_debuglvl(const char *str, int srv)
2148 debug |= (uint8_t) getnum(str);
2151 static void handle_threads(const char *str, int srv)
2153 unsigned n = getnum(str);
2158 static void handle_user(const char *str, int srv)
2160 config.user = xstrdup(str);
2163 static void handle_enable(const char *str, int srv)
2165 config.srv_enable[srv] = ((str[0] | 0x20) == 'y');
2168 static void handle_pttl(const char *str, int srv)
2170 config.pttl[srv] = getnum(str);
2173 static void handle_nttl(const char *str, int srv)
2175 config.nttl[srv] = getnum(str);
2178 static void handle_size(const char *str, int srv)
2180 config.size[srv] = getnum(str);
2183 static void handle_chfiles(const char *str, int srv)
2185 config.check_files[srv] = ((str[0] | 0x20) == 'y');
2188 static void parse_conffile(const char *conffile, int warn)
2190 static const struct confword {
2192 void (*handler)(const char *, int);
2194 { "_" "logfile" , handle_logfile },
2195 { "_" "debug-level" , handle_debuglvl },
2196 { "_" "threads" , handle_threads },
2197 { "_" "max-threads" , handle_threads },
2198 { "_" "server-user" , handle_user },
2199 /* ignore: any user can stat */
2200 { "_" "stat-user" , handle_null },
2201 { "_" "paranoia" , handle_null }, /* ? */
2202 /* ignore: design goal is to never crash/hang */
2203 { "_" "reload-count" , handle_null },
2204 { "_" "restart-interval" , handle_null },
2205 { "S" "enable-cache" , handle_enable },
2206 { "S" "positive-time-to-live" , handle_pttl },
2207 { "S" "negative-time-to-live" , handle_nttl },
2208 { "S" "suggested-size" , handle_size },
2209 { "S" "check-files" , handle_chfiles },
2210 { "S" "persistent" , handle_null }, /* ? */
2211 { "S" "shared" , handle_null }, /* ? */
2212 { "S" "auto-propagate" , handle_null }, /* ? */
2217 FILE *file = fopen(conffile, "r");
2221 if (conffile != default_conffile)
2222 perror_and_die("cannot open %s", conffile);
2226 while (fgets(buf, sizeof(buf), file) != NULL) {
2227 const struct confword *word;
2229 int len = strlen(buf);
2233 if (buf[len-1] != '\n') {
2234 if (len >= sizeof(buf) - 1)
2235 error_and_die("%s:%d: line is too long", conffile, lineno);
2236 len++; /* last line, not terminated by '\n' */
2240 p = strchr(buf, '#');
2244 p = skip_whitespace(buf);
2247 *skip_non_whitespace(p) = '\0';
2250 if (strcmp(word->str + 1, p) == 0) {
2252 p = skip_whitespace(p + strlen(p) + 1);
2253 *skip_non_whitespace(p) = '\0';
2254 if (word->str[0] == 'S') {
2255 char *p2 = skip_service(&srv, p);
2258 error("%s:%d: ignoring unknown service name '%s'", conffile, lineno, p);
2262 *skip_non_whitespace(p) = '\0';
2264 word->handler(p, srv);
2270 error("%s:%d: ignoring unknown directive '%s'", conffile, lineno, p);
2279 /* "XX,XX[,XX]..." -> gid_t[] */
2280 static gid_t* env_U_to_uid_and_gids(const char *str, int *sizep)
2291 ug = xmalloc(ng * sizeof(ug[0]));
2299 *gp++ = strtoul(sp, (char**)&sp, 16);
2300 if (errno || (*sp != ',' && *sp != '\0'))
2301 error_and_die("internal error");
2312 static char* user_to_env_U(const char *user)
2319 pw = getpwnam(user);
2321 perror_and_die("user '%s' is not known", user);
2324 /* 0th cell will be used for uid */
2325 ug = xmalloc((1 + ng) * sizeof(ug[0]));
2326 if (getgrouplist(user, pw->pw_gid, &ug[1], &ng) < 0) {
2327 ug = xrealloc(ug, (1 + ng) * sizeof(ug[0]));
2328 if (getgrouplist(user, pw->pw_gid, &ug[1], &ng) < 0)
2329 perror_and_die("can't get groups of user '%s'", user);
2334 /* How much do we need for "-Uxx,xx[,xx]..." string? */
2335 ug_str = xmalloc((sizeof(unsigned long)+1)*2 * ng + 3);
2341 sp += sprintf(sp, "%lx,", (unsigned long)(*gp++));
2350 /* not static - don't inline me, compiler! */
2351 void readlink_self_exe(void);
2352 void readlink_self_exe(void)
2354 char buf[PATH_MAX + 1];
2355 ssize_t sz = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
2357 perror_and_die("readlink %s failed", "/proc/self/exe");
2359 self_exe_points_to = xstrdup(buf);
2363 static void special_op(const char *arg) NORETURN;
2364 static void special_op(const char *arg)
2366 static const user_req_header ureq = { NSCD_VERSION, SHUTDOWN, 0 };
2368 struct sockaddr_un addr;
2371 sock = socket(PF_UNIX, SOCK_STREAM, 0);
2373 error_and_die("cannot create AF_UNIX socket");
2375 addr.sun_family = AF_UNIX;
2376 strcpy(addr.sun_path, NSCD_SOCKET);
2377 if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
2378 error_and_die("cannot connect to %s", NSCD_SOCKET);
2380 if (!arg) { /* shutdown */
2381 xfull_write(sock, &ureq, sizeof(ureq));
2382 printf("sent shutdown request, exiting\n");
2383 } else { /* invalidate */
2384 size_t arg_len = strlen(arg) + 1;
2386 user_req_header req;
2389 reqdata.req.version = NSCD_VERSION;
2390 reqdata.req.type = INVALIDATE;
2391 reqdata.req.key_len = arg_len;
2392 memcpy(reqdata.arg, arg, arg_len);
2393 xfull_write(sock, &reqdata, arg_len + sizeof(ureq));
2395 printf("sent invalidate(%s) request, exiting\n", arg);
2402 /* Callback for glibc-2.15 */
2404 static void do_nothing(size_t dbidx, struct traced_file *finfo)
2406 /* nscd from glibc-2.15 does something like this:
2407 if (!dbs[dbidx].enabled || !dbs[dbidx].check_file)
2409 add_file_to_watch_list(finfo->fname);
2413 /* This internal glibc function is called to disable trying to contact nscd.
2414 * We _are_ nscd, so we need to do the lookups, and not recurse.
2415 * Until 2.14, this function was taking no parameters.
2416 * In 2.15, it takes a function pointer from hell.
2418 void __nss_disable_nscd(void (*hell)(size_t, struct traced_file*));
2421 int main(int argc, char **argv)
2426 const char *conffile;
2428 /* make sure we don't get recursive calls */
2429 __nss_disable_nscd(do_nothing);
2431 if (argv[0][0] == 'w') /* "worker_nscd" */
2437 /* Make sure stdio is not closed */
2438 n = xopen3("/dev/null", O_RDWR, 0);
2441 /* Close unexpected open file descriptors */
2442 n |= 0xff; /* start from at least fd# 255 */
2447 /* For idiotic kernels which disallow "exec /proc/self/exe" */
2448 readlink_self_exe();
2450 conffile = default_conffile;
2452 while ((n = getopt_long(argc, argv, "df:i:KVgt:", longopt, NULL)) != -1) {
2463 special_op(optarg); /* exits */
2465 /* shutdown server */
2466 special_op(NULL); /* exits */
2468 puts("unscd - nscd which does not hang, v."PROGRAM_VERSION);
2474 max_reqnum = getnum(optarg);
2480 print_help_and_die();
2483 /* Multiple -d can bump debug regardless of nscd.conf:
2484 * no -d or -d: 0, -dd: 1,
2485 * -ddd: 3, -dddd: 7, -ddddd: 15
2488 debug |= (((1U << opt_d_cnt) >> 1) - 1) & L_ALL;
2490 env_U = getenv("U");
2491 /* Avoid duplicate warnings if $U exists */
2492 parse_conffile(conffile, /* warn? */ (env_U == NULL));
2494 /* I have a user report of (broken?) ldap nss library
2495 * opening and never closing a socket to a ldap server,
2496 * even across fork() and exec(). This messes up
2497 * worker child's operations for the reporter.
2499 * This strenghtens my belief that nscd _must not_ trust
2500 * nss libs to be written correctly.
2502 * Here, we need to jump through the hoops to guard against
2503 * such problems. If config file has server-user setting, we need
2504 * to setgroups + setuid. For that, we need to get uid and gid vector.
2505 * And that means possibly using buggy nss libs.
2506 * We will do it here, but then we will re-exec, passing uid+gids
2507 * in an environment variable.
2509 if (!env_U && config.user) {
2510 /* user_to_env_U() does getpwnam and getgrouplist */
2511 if (putenv(user_to_env_U(config.user)))
2512 error_and_die("out of memory");
2513 /* fds leaked by nss will be closed by execed copy */
2514 execv(self_exe_points_to, argv);
2515 xexecve("/proc/self/exe", argv, environ);
2518 /* Allocate dynamically sized stuff */
2519 max_reqnum += 2; /* account for 2 first "fake" clients */
2520 if (max_reqnum < 8) max_reqnum = 8; /* sanitize */
2521 /* Since refcount is a byte, can't serve more than 255-2 clients
2522 * at once. The rest will block in connect() */
2523 if (max_reqnum > 0xff) max_reqnum = 0xff;
2524 client_buf = xzalloc(max_reqnum * sizeof(client_buf[0]));
2525 busy_cbuf = xzalloc(max_reqnum * sizeof(busy_cbuf[0]));
2526 pfd = xzalloc(max_reqnum * sizeof(pfd[0]));
2527 cinfo = xzalloc(max_reqnum * sizeof(cinfo[0]));
2529 cache_size = (config.size[0] + config.size[1] + config.size[2]) / 8;
2530 if (cache_size < 8) cache_size = 8; /* 8*8 = 64 entries min */
2531 if (cache_size > 0xffff) cache_size = 0xffff; /* 8*64k entries max */
2532 cache_size |= 1; /* force it to be odd */
2533 cache = xzalloc(cache_size * sizeof(cache[0]));
2535 /* Register cleanup hooks */
2536 signal(SIGINT, cleanup_on_signal);
2537 signal(SIGTERM, cleanup_on_signal);
2538 /* Don't die if a client closes a socket on us */
2539 signal(SIGPIPE, SIG_IGN);
2540 /* Avoid creating zombies */
2541 signal(SIGCHLD, SIG_IGN);
2543 /* Ensure workers don't have SIGALRM ignored */
2544 signal(SIGALRM, SIG_DFL);
2547 if (mkdir(NSCD_DIR, 0755) == 0) {
2548 /* prevent bad mode of NSCD_DIR if umask is e.g. 077 */
2549 chmod(NSCD_DIR, 0755);
2551 pfd[0].fd = open_socket(NSCD_SOCKET);
2552 pfd[1].fd = open_socket(NSCD_SOCKET_OLD);
2553 pfd[0].events = POLLIN;
2554 pfd[1].events = POLLIN;
2556 if (debug & D_DAEMON) {
2557 daemon(/*nochdir*/ 1, /*noclose*/ 0);
2558 if (config.logfile) {
2559 /* nochdir=1: relative paths still work as expected */
2560 xmovefd(xopen3(config.logfile, O_WRONLY|O_CREAT|O_TRUNC, 0666), 2);
2563 debug = 0; /* why bother? it's /dev/null'ed anyway */
2565 chdir("/"); /* compat */
2568 /* ignore job control signals */
2569 signal(SIGTTOU, SIG_IGN);
2570 signal(SIGTTIN, SIG_IGN);
2571 signal(SIGTSTP, SIG_IGN);
2574 log(L_ALL, "nscd v" PROGRAM_VERSION ", debug level 0x%x", debug & L_ALL);
2575 log(L_DEBUG, "max %u requests in parallel", max_reqnum - 2);
2576 log(L_DEBUG, "cache size %u x 8 entries", cache_size);
2580 gid_t *ug = env_U_to_uid_and_gids(env_U, &size);
2582 if (setgroups(size - 1, &ug[1]) || setgid(ug[1]))
2583 perror_and_die("cannot set groups for user '%s'", config.user);
2586 perror_and_die("cannot set uid to %u", (unsigned)(ug[0]));
2590 for (n = 0; n < 3; n++) {
2591 log(L_DEBUG, "%s cache enabled:%u pttl:%u nttl:%u",
2593 config.srv_enable[n],
2596 config.pttl[n] *= 1000;
2597 config.nttl[n] *= 1000;