1 /* This file is part of unscd, a complete nscd replacement.
2 * Copyright (C) 2007-2012 Denys Vlasenko. Licensed under the GPL version 2.
5 /* unscd is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * unscd is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You can download the GNU General Public License from the GNU website
15 * at http://www.gnu.org/ or write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
21 gcc -Wall -Wunused-parameter -Os -o nscd nscd.c
23 gcc -fomit-frame-pointer -Wl,--sort-section -Wl,alignment -Wl,--sort-common
28 nscd problems are not exactly unheard of. Over the years, there were
29 quite a bit of bugs in it. This leads people to invent babysitters
30 which restart crashed/hung nscd. This is ugly.
32 After looking at nscd source in glibc I arrived to the conclusion
33 that its design is contributing to this significantly. Even if nscd's
34 code is 100.00% perfect and bug-free, it can still suffer from bugs
35 in libraries it calls.
37 As designed, it's a multithreaded program which calls NSS libraries.
38 These libraries are not part of libc, they may be provided
39 by third-party projects (samba, ldap, you name it).
41 Thus nscd cannot be sure that libraries it calls do not have memory
42 or file descriptor leaks and other bugs.
44 Since nscd is multithreaded program with single shared cache,
45 any resource leak in any NSS library has cumulative effect.
46 Even if a NSS library leaks a file descriptor 0.01% of the time,
47 this will make nscd crash or hang after some time.
49 Of course bugs in NSS .so modules should be fixed, but meanwhile
50 I do want nscd which does not crash or lock up.
52 So I went ahead and wrote a replacement.
54 It is a single-threaded server process which offloads all NSS
55 lookups to worker children (not threads, but fully independent
56 processes). Cache hits are handled by parent. Only cache misses
57 start worker children. This design is immune against
58 resource leaks and hangs in NSS libraries.
60 It is also many times smaller.
62 Currently (v0.36) it emulates glibc nscd pretty closely
63 (handles same command line flags and config file), and is moderately tested.
65 Please note that as of 2008-08 it is not in wide use (yet?).
66 If you have trouble compiling it, see an incompatibility with
67 "standard" one or experience hangs/crashes, please report it to
68 vda.linux@googlemail.com
70 ***********************************************************************/
72 /* Make struct ucred appear in sys/socket.h */
74 /* For all good things */
91 #include <sys/socket.h>
93 #include <sys/types.h>
99 /* For inet_ntoa (for debug build only) */
100 #include <arpa/inet.h>
103 * 0.21 add SEGV reporting to worker
104 * 0.22 don't do freeaddrinfo() in GETAI worker, it's crashy
105 * 0.23 add parameter parsing
106 * 0.24 add conf file parsing, not using results yet
107 * 0.25 used some of conf file settings (not tested)
108 * 0.26 almost all conf file settings are wired up
109 * 0.27 a bit more of almost all conf file settings are wired up
110 * 0.28 optimized cache aging
111 * 0.29 implemented invalidate and shutdown options
112 * 0.30 fixed buglet (sizeof(ptr) != sizeof(array))
113 * 0.31 reduced client_info by one member
114 * 0.32 fix nttl/size defaults; simpler check for worker child in main()
115 * 0.33 tweak includes so that it builds on my new machine (64-bit userspace);
116 * do not die on unknown service name, just warn
117 * ("services" is a new service we don't support)
118 * 0.34 create /var/run/nscd/nscd.pid pidfile like glibc nscd 2.8 does;
119 * delay setuid'ing itself to server-user after log and pidfile are open
120 * 0.35 readlink /proc/self/exe and use result if execing /proc/self/exe fails
121 * 0.36 excercise extreme paranoia handling server-user option;
122 * a little bit more verbose logging:
123 * L_DEBUG2 log level added, use debug-level 7 to get it
124 * 0.37 users reported over-zealous "detected change in /etc/passwd",
125 * apparently stat() returns random garbage in unused padding
126 * on some systems. Made the check less paranoid.
127 * 0.38 log POLLHUP better
128 * 0.39 log answers to client better, log getpwnam in the worker,
129 * pass debug level value down to worker.
130 * 0.40 fix handling of shutdown and invalidate requests;
131 * fix bug with answer written in several pieces
132 * 0.40.1 set hints.ai_socktype = SOCK_STREAM in GETAI request
133 * 0.41 eliminate double caching of two near-simultaneous identical requests -
135 * 0.42 execute /proc/self/exe by link name first (better comm field)
136 * 0.43 fix off-by-one error in setgroups
137 * 0.44 make -d[ddd] bump up debug - easier to explain to users
138 * how to produce detailed log (no nscd.conf tweaking)
139 * 0.45 Fix out-of-bounds array access and log/pid file permissions -
140 * thanks to Sebastian Krahmer (krahmer AT suse.de)
141 * 0.46 fix a case when we forgot to remove a future entry on worker failure
142 * 0.47 fix nscd without -d to not bump debug level
143 * 0.48 fix for changes in __nss_disable_nscd API in glibc-2.15
144 * 0.49 minor tweaks to messages
146 #define PROGRAM_VERSION "0.49"
148 #define DEBUG_BUILD 1
155 #define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0])))
157 #define NORETURN __attribute__ ((__noreturn__))
160 #ifdef MY_CPU_HATES_CHARS
161 typedef int smallint;
163 typedef signed char smallint;
169 L_DEBUG = ((1 << 1) * DEBUG_BUILD),
170 L_DEBUG2 = ((1 << 2) * DEBUG_BUILD),
171 L_DUMP = ((1 << 3) * DEBUG_BUILD),
177 static smallint debug = D_DAEMON;
179 static void verror(const char *s, va_list p, const char *strerr)
182 int sz, rem, strerr_len;
186 if (debug & D_STAMP) {
187 gettimeofday(&tv, NULL);
188 sz = sprintf(msgbuf, "%02u:%02u:%02u.%05u ",
189 (unsigned)((tv.tv_sec / (60*60)) % 24),
190 (unsigned)((tv.tv_sec / 60) % 60),
191 (unsigned)(tv.tv_sec % 60),
192 (unsigned)(tv.tv_usec / 10));
194 rem = sizeof(msgbuf) - sz;
195 sz += vsnprintf(msgbuf + sz, rem, s, p);
196 rem = sizeof(msgbuf) - sz; /* can be negative after this! */
199 strerr_len = strlen(strerr);
200 if (rem >= strerr_len + 4) { /* ": STRERR\n\0" */
203 strcpy(msgbuf + sz, strerr);
212 fputs(msgbuf, stderr);
215 static void error(const char *msg, ...)
219 verror(msg, p, NULL);
223 static void error_and_die(const char *msg, ...) NORETURN;
224 static void error_and_die(const char *msg, ...)
228 verror(msg, p, NULL);
233 static void perror_and_die(const char *msg, ...) NORETURN;
234 static void perror_and_die(const char *msg, ...)
238 /* Guard against "<error message>: Success" */
239 verror(msg, p, errno ? strerror(errno) : NULL);
244 static void nscd_log(int mask, const char *msg, ...)
249 verror(msg, p, NULL);
254 #define log(lvl, ...) do { if (lvl) nscd_log(lvl, __VA_ARGS__); } while (0)
257 static void dump(const void *ptr, int len)
260 const unsigned char *buf;
263 if (!(debug & L_DUMP))
268 int chunk = ((len >= 16) ? 16 : len);
270 "%02x %02x %02x %02x %02x %02x %02x %02x "
271 "%02x %02x %02x %02x %02x %02x %02x %02x " + (16-chunk) * 5,
272 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
273 buf[8], buf[9],buf[10],buf[11],buf[12],buf[13],buf[14],buf[15]
275 fprintf(stderr, "%*s", (16-chunk) * 3, "");
279 unsigned char c = *buf++;
280 *p++ = (c >= 32 && c < 127 ? c : '.');
288 void dump(const void *ptr, int len);
291 #define hex_dump(p,n) do { if (L_DUMP) dump(p,n); } while (0)
293 static int xopen3(const char *pathname, int flags, int mode)
295 int fd = open(pathname, flags, mode);
297 perror_and_die("open");
301 static void xpipe(int *fds)
304 perror_and_die("pipe");
307 static void xexecve(const char *filename, char **argv, char **envp) NORETURN;
308 static void xexecve(const char *filename, char **argv, char **envp)
310 execve(filename, argv, envp);
311 perror_and_die("cannot re-exec %s", filename);
314 static void ndelay_on(int fd)
316 int fl = fcntl(fd, F_GETFL);
318 perror_and_die("F_GETFL");
319 if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) < 0)
320 perror_and_die("setting O_NONBLOCK");
323 static void close_on_exec(int fd)
325 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
326 perror_and_die("setting FD_CLOEXEC");
329 static unsigned monotonic_ms(void)
332 if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts))
333 perror_and_die("clock_gettime(MONOTONIC)");
334 return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
337 static unsigned strsize(const char *str)
339 return strlen(str) + 1;
342 static unsigned strsize_aligned4(const char *str)
344 return (strlen(str) + 1 + 3) & (~3);
347 static ssize_t safe_read(int fd, void *buf, size_t count)
351 n = read(fd, buf, count);
352 } while (n < 0 && errno == EINTR);
356 static ssize_t full_read(int fd, void *buf, size_t len)
362 cc = safe_read(fd, buf, len);
364 return cc; /* read() returns -1 on failure. */
367 buf = ((char *)buf) + cc;
375 static void xsafe_read(int fd, void *buf, size_t len)
377 if (len != safe_read(fd, buf, len))
378 perror_and_die("short read");
380 static void xfull_read(int fd, void *buf, size_t len)
382 if (len != full_read(fd, buf, len))
383 perror_and_die("short read");
387 static ssize_t safe_write(int fd, const void *buf, size_t count)
391 n = write(fd, buf, count);
392 } while (n < 0 && errno == EINTR);
396 static ssize_t full_write(int fd, const void *buf, size_t len)
403 cc = safe_write(fd, buf, len);
405 return cc; /* write() returns -1 on failure. */
407 buf = ((const char *)buf) + cc;
413 static void xsafe_write(int fd, const void *buf, size_t count)
415 if (count != safe_write(fd, buf, count))
416 perror_and_die("short write of %ld bytes", (long)count);
418 static void xfull_write(int fd, const void *buf, size_t count)
420 if (count != full_write(fd, buf, count))
421 perror_and_die("short write of %ld bytes", (long)count);
424 static void xmovefd(int from_fd, int to_fd)
426 if (from_fd != to_fd) {
427 if (dup2(from_fd, to_fd) < 0)
428 perror_and_die("dup2");
433 static unsigned getnum(const char *str)
435 if (str[0] >= '0' && str[0] <= '9') {
437 unsigned long l = strtoul(str, &p, 10);
438 /* must not overflow int even after x1000 */
439 if (!*p && l <= INT_MAX / 1000)
442 error_and_die("malformed or too big number '%s'", str);
445 static char *skip_whitespace(const char *s)
447 /* NB: isspace('\0') returns 0 */
448 while (isspace(*s)) ++s;
452 static char *skip_non_whitespace(const char *s)
454 while (*s && !isspace(*s)) ++s;
458 static void *xmalloc(unsigned sz)
460 void *p = malloc(sz);
462 error_and_die("out of memory");
466 static void *xzalloc(unsigned sz)
468 void *p = xmalloc(sz);
473 static void *xrealloc(void *p, unsigned size)
475 p = realloc(p, size);
477 error_and_die("out of memory");
481 static const char *xstrdup(const char *str)
483 const char *p = strdup(str);
485 error_and_die("out of memory");
500 static const char srv_name[3][7] = {
509 smallint srv_enable[3];
510 smallint check_files[3];
515 /* We try to closely mimic glibc nscd */
516 .logfile = NULL, /* default is to not have a log file */
518 .srv_enable = { 0, 0, 0 },
519 .check_files = { 1, 1, 1 },
520 .pttl = { 3600, 3600, 3600 },
521 .nttl = { 20, 60, 20 },
522 /* huh, what is the default cache size in glibc nscd? */
523 .size = { 256 * 8 / 3, 256 * 8 / 3, 256 * 8 / 3 },
526 static const char default_conffile[] = "/etc/nscd.conf";
527 static const char *self_exe_points_to = "/proc/self/exe";
531 ** Clients, workers machinery
534 /* Header common to all requests */
535 #define USER_REQ_STRUCT \
536 uint32_t version; /* Version number of the daemon interface */ \
537 uint32_t type; /* Service requested */ \
538 uint32_t key_len; /* Key length */
540 typedef struct user_req_header {
546 MAX_USER_REQ_SIZE = 1024,
547 USER_HDR_SIZE = sizeof(user_req_header),
548 /* DNS queries time out after 20 seconds,
549 * we will allow for a bit more */
550 WORKER_TIMEOUT_SEC = 30,
551 CLIENT_TIMEOUT_MS = 100,
552 SMALL_POLL_TIMEOUT_MS = 200,
555 typedef struct user_req {
557 struct { /* as came from client */
560 struct { /* when stored in cache, overlaps .version */
562 /* (timestamp24 * 256) == timestamp in ms */
563 unsigned timestamp24:24;
566 char reqbuf[MAX_USER_REQ_SIZE - USER_HDR_SIZE];
569 /* Compile-time check for correct size */
570 struct BUG_wrong_user_req_size {
571 char BUG_wrong_user_req_size[sizeof(user_req) == MAX_USER_REQ_SIZE ? 1 : -1];
583 SHUTDOWN, /* Shut the server down */
584 GETSTAT, /* Get the server statistic */
585 INVALIDATE, /* Invalidate one special cache */
597 static const char *const typestr[] = {
598 "GETPWBYNAME", /* done */
599 "GETPWBYUID", /* done */
600 "GETGRBYNAME", /* done */
601 "GETGRBYGID", /* done */
602 "GETHOSTBYNAME", /* done */
603 "GETHOSTBYNAMEv6", /* done */
604 "GETHOSTBYADDR", /* done */
605 "GETHOSTBYADDRv6", /* done */
606 "SHUTDOWN", /* done */
607 "GETSTAT", /* info? */
608 "INVALIDATE", /* done */
609 /* won't do: nscd passes a name of shmem segment
610 * which client can map and "see" the db */
612 "GETFDGR", /* won't do */
613 "GETFDHST", /* won't do */
615 "INITGROUPS", /* done */
616 "GETSERVBYNAME", /* prio 3 (no caching?) */
617 "GETSERVBYPORT", /* prio 3 (no caching?) */
618 "GETFDSERV" /* won't do */
621 extern const char *const typestr[];
623 static const smallint type_to_srv[] = {
624 [GETPWBYNAME ] = SRV_PASSWD,
625 [GETPWBYUID ] = SRV_PASSWD,
626 [GETGRBYNAME ] = SRV_GROUP,
627 [GETGRBYGID ] = SRV_GROUP,
628 [GETHOSTBYNAME ] = SRV_HOSTS,
629 [GETHOSTBYNAMEv6 ] = SRV_HOSTS,
630 [GETHOSTBYADDR ] = SRV_HOSTS,
631 [GETHOSTBYADDRv6 ] = SRV_HOSTS,
632 [GETAI ] = SRV_HOSTS,
633 [INITGROUPS ] = SRV_GROUP,
636 static int unsupported_ureq_type(unsigned type)
638 if (type == GETAI) return 0;
639 if (type == INITGROUPS) return 0;
640 if (type == GETSTAT) return 1;
641 if (type > INVALIDATE) return 1;
646 typedef struct client_info {
647 /* if client_fd != 0, we are waiting for the reply from worker
648 * on pfd[i].fd, and client_fd is saved client's fd
649 * (we need to put it back into pfd[i].fd later) */
651 unsigned bytecnt; /* bytes read from client */
652 unsigned bufidx; /* buffer# in global client_buf[] */
654 unsigned respos; /* response */
655 user_req *resptr; /* response */
656 user_req **cache_pp; /* cache entry address */
657 user_req *ureq; /* request (points to client_buf[x]) */
660 static unsigned g_now_ms;
661 static int min_closed = INT_MAX;
662 static int cnt_closed = 0;
663 static int num_clients = 2; /* two listening sockets are "clients" too */
665 /* We read up to max_reqnum requests in parallel */
666 static unsigned max_reqnum = 14;
668 static char (*client_buf)[MAX_USER_REQ_SIZE];
669 static char *busy_cbuf;
670 static struct pollfd *pfd;
671 static client_info *cinfo;
673 /* Request, response and cache data structures:
675 * cache[] (defined later):
676 * cacheline_t cache[cache_size] array, or in other words,
677 * user_req* cache[cache_size][8] array.
678 * Every client request is hashed, hash value determines which cache[x]
679 * will have the response stored in one of its 8 elements.
680 * Cache entries have this format: request, then padding to 32 bits,
682 * Addresses in cache[x][y] may be NULL or:
683 * (&client_buf[z]) & 1: the cache miss is in progress ("future entry"):
684 * "the data is not in the cache (yet), wait for it to appear"
685 * (&client_buf[z]) & 3: the cache miss is in progress and other clients
686 * also want the same data ("shared future entry")
687 * else (non-NULL but low two bits are 0): cached data in malloc'ed block
689 * Each of these is a [max_reqnum] sized array:
690 * pfd[i] - given to poll() to wait for requests and replies.
691 * .fd: first two pfd[i]: listening Unix domain sockets, else
692 * .fd: open fd to a client, for reading client's request, or
693 * .fd: open fd to a worker, to send request and get response back
694 * cinfo[i] - auxiliary client data for pfd[i]
695 * .client_fd: open fd to a client, in case we already had read its
696 * request and got a cache miss, and created a worker or
697 * wait for another client's worker.
698 * Otherwise, it's 0 and client's fd is in pfd[i].fd
699 * .bufidx: index in client_buf[] we store client's request in
700 * .bytecnt: size of the request
701 * .started_ms: used to time out unresponsive clients
704 * .cache_pp: &cache[x][y] where the response is, or will be stored.
706 * When a client has received its reply (or otherwise closed (timeout etc)),
707 * corresponding pfd[i] and cinfo[i] are removed by shifting [i+1], [i+2] etc
708 * elements down, so that both arrays never have free holes.
709 * [num_clients] is always the first free element.
711 * Each of these also is a [max_reqnum] sized array, but indexes
712 * do not correspond directly to pfd[i] and cinfo[i]:
713 * client_buf[n][MAX_USER_REQ_SIZE] - buffers we read client requests into
714 * busy_cbuf[n] - bool flags marking busy client_buf[]
716 /* Possible reductions:
717 * fd, bufidx - uint8_t
718 * started_ms -> uint16_t started_s
719 * ureq - eliminate (derivable from bufidx?)
722 /* Are special bits 0? is it a true cached entry? */
723 #define CACHED_ENTRY(p) ( ((long)(p) & 3) == 0 )
724 /* Are special bits 11? is it a shared future cache entry? */
725 #define CACHE_SHARED(p) ( ((long)(p) & 3) == 3 )
726 /* Return a ptr with special bits cleared (used for accessing data) */
727 #define CACHE_PTR(p) ( (void*) ((long)(p) & ~(long)3) )
728 /* Return a ptr with special bits set to x1: make future cache entry ptr */
729 #define MAKE_FUTURE_PTR(p) ( (void*) ((long)(p) | 1) )
730 /* Modify ptr, set special bits to 11: shared future cache entry */
731 #define MARK_PTR_SHARED(pp) ( *(long*)(pp) |= 3 )
733 static inline unsigned ureq_size(const user_req *ureq)
735 return sizeof(user_req_header) + ureq->key_len;
738 static unsigned cache_age(const user_req *ureq)
740 if (!CACHED_ENTRY(ureq))
742 return (uint32_t) (g_now_ms - (ureq->timestamp24 << 8));
745 static void set_cache_timestamp(user_req *ureq)
747 ureq->timestamp24 = g_now_ms >> 8;
750 static int alloc_buf_no(void)
755 next_buf = (next_buf + 1) % max_reqnum;
756 if (!busy_cbuf[cur]) {
760 } while (next_buf != n);
761 error_and_die("no free bufs?!");
764 static inline void *bufno2buf(int i)
766 return client_buf[i];
769 static void close_client(unsigned i)
771 log(L_DEBUG, "closing client %u (fd %u,%u)", i, pfd[i].fd, cinfo[i].client_fd);
772 /* Paranoia. We had nasty bugs where client was closed twice. */
773 if (pfd[i].fd == 0) ////
776 if (cinfo[i].client_fd && cinfo[i].client_fd != pfd[i].fd)
777 close(cinfo[i].client_fd);
778 pfd[i].fd = 0; /* flag as unused (coalescing needs this) */
779 busy_cbuf[cinfo[i].bufidx] = 0;
787 ** nscd API <-> C API conversion
790 typedef struct response_header {
791 uint32_t version_or_size;
796 typedef struct initgr_response_header {
797 uint32_t version_or_size;
800 /* code assumes gid_t == int32, let's check that */
801 int32_t gid[sizeof(gid_t) == sizeof(int32_t) ? 0 : -1];
802 /* char user_str[as_needed]; */
803 } initgr_response_header;
805 static initgr_response_header *obtain_initgroups(const char *username)
807 struct initgr_response_header *resp;
809 enum { MAGIC_OFFSET = sizeof(*resp) / sizeof(int32_t) };
813 pw = getpwnam(username);
816 resp->version_or_size = sizeof(*resp);
822 /* getgrouplist may be very expensive, it's much better to allocate
823 * a bit more than to run getgrouplist twice */
827 sz = sizeof(*resp) + sizeof(resp->gid[0]) * ngroups;
828 resp = xrealloc(resp, sz);
829 } while (getgrouplist(username, pw->pw_gid, (gid_t*) &resp->gid, &ngroups) == -1);
830 log(L_DEBUG, "ngroups=%d", ngroups);
832 sz = sizeof(*resp) + sizeof(resp->gid[0]) * ngroups;
833 /* resp = xrealloc(resp, sz); - why bother */
834 resp->version_or_size = sz;
836 resp->ngrps = ngroups;
841 typedef struct pw_response_header {
842 uint32_t version_or_size;
845 int32_t pw_passwd_len;
848 int32_t pw_gecos_len;
850 int32_t pw_shell_len;
851 /* char pw_name[pw_name_len]; */
852 /* char pw_passwd[pw_passwd_len]; */
853 /* char pw_gecos[pw_gecos_len]; */
854 /* char pw_dir[pw_dir_len]; */
855 /* char pw_shell[pw_shell_len]; */
856 } pw_response_header;
858 static pw_response_header *marshal_passwd(struct passwd *pw)
861 pw_response_header *resp;
862 unsigned pw_name_len;
863 unsigned pw_passwd_len;
864 unsigned pw_gecos_len;
866 unsigned pw_shell_len;
867 unsigned sz = sizeof(*resp);
869 sz += (pw_name_len = strsize(pw->pw_name));
870 sz += (pw_passwd_len = strsize(pw->pw_passwd));
871 sz += (pw_gecos_len = strsize(pw->pw_gecos));
872 sz += (pw_dir_len = strsize(pw->pw_dir));
873 sz += (pw_shell_len = strsize(pw->pw_shell));
876 resp->version_or_size = sz;
882 resp->pw_name_len = pw_name_len;
883 resp->pw_passwd_len = pw_passwd_len;
884 resp->pw_uid = pw->pw_uid;
885 resp->pw_gid = pw->pw_gid;
886 resp->pw_gecos_len = pw_gecos_len;
887 resp->pw_dir_len = pw_dir_len;
888 resp->pw_shell_len = pw_shell_len;
889 p = (char*)(resp + 1);
890 strcpy(p, pw->pw_name); p += pw_name_len;
891 strcpy(p, pw->pw_passwd); p += pw_passwd_len;
892 strcpy(p, pw->pw_gecos); p += pw_gecos_len;
893 strcpy(p, pw->pw_dir); p += pw_dir_len;
894 strcpy(p, pw->pw_shell); p += pw_shell_len;
895 log(L_DEBUG, "sz:%u realsz:%u", sz, p - (char*)resp);
900 typedef struct gr_response_header {
901 uint32_t version_or_size;
903 int32_t gr_name_len; /* strlen(gr->gr_name) + 1; */
904 int32_t gr_passwd_len; /* strlen(gr->gr_passwd) + 1; */
905 int32_t gr_gid; /* gr->gr_gid */
906 int32_t gr_mem_cnt; /* while (gr->gr_mem[gr_mem_cnt]) ++gr_mem_cnt; */
907 /* int32_t gr_mem_len[gr_mem_cnt]; */
908 /* char gr_name[gr_name_len]; */
909 /* char gr_passwd[gr_passwd_len]; */
910 /* char gr_mem[gr_mem_cnt][gr_mem_len[i]]; */
911 /* char gr_gid_str[as_needed]; - huh? */
912 /* char orig_key[as_needed]; - needed?? I don't do this ATM... */
914 glibc adds gr_gid_str, but client doesn't get/use it:
915 writev(3, [{"\2\0\0\0\2\0\0\0\5\0\0\0", 12}, {"root\0", 5}], 2) = 17
916 poll([{fd=3, events=POLLIN|POLLERR|POLLHUP, revents=POLLIN}], 1, 5000) = 1
917 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
918 readv(3, [{"", 0}, {"root\0\0\0\0\0\0\0\0", 12}], 2) = 12
921 } gr_response_header;
923 static gr_response_header *marshal_group(struct group *gr)
926 gr_response_header *resp;
928 unsigned sz = sizeof(*resp);
930 sz += strsize(gr->gr_name);
931 sz += strsize(gr->gr_passwd);
933 while (gr->gr_mem[gr_mem_cnt]) {
934 sz += strsize(gr->gr_mem[gr_mem_cnt]);
937 /* for int32_t gr_mem_len[gr_mem_cnt]; */
938 sz += gr_mem_cnt * sizeof(int32_t);
941 resp->version_or_size = sz;
947 resp->gr_name_len = strsize(gr->gr_name);
948 resp->gr_passwd_len = strsize(gr->gr_passwd);
949 resp->gr_gid = gr->gr_gid;
950 resp->gr_mem_cnt = gr_mem_cnt;
951 p = (char*)(resp + 1);
952 /* int32_t gr_mem_len[gr_mem_cnt]; */
954 while (gr->gr_mem[gr_mem_cnt]) {
955 *(uint32_t*)p = strsize(gr->gr_mem[gr_mem_cnt]);
959 /* char gr_name[gr_name_len]; */
960 strcpy(p, gr->gr_name);
961 p += strsize(gr->gr_name);
962 /* char gr_passwd[gr_passwd_len]; */
963 strcpy(p, gr->gr_passwd);
964 p += strsize(gr->gr_passwd);
965 /* char gr_mem[gr_mem_cnt][gr_mem_len[i]]; */
967 while (gr->gr_mem[gr_mem_cnt]) {
968 strcpy(p, gr->gr_mem[gr_mem_cnt]);
969 p += strsize(gr->gr_mem[gr_mem_cnt]);
972 log(L_DEBUG, "sz:%u realsz:%u", sz, p - (char*)resp);
977 typedef struct hst_response_header {
978 uint32_t version_or_size;
981 int32_t h_aliases_cnt;
982 int32_t h_addrtype; /* AF_INET or AF_INET6 */
983 int32_t h_length; /* 4 or 16 */
984 int32_t h_addr_list_cnt;
986 /* char h_name[h_name_len]; - we pad it to 4 bytes */
987 /* uint32_t h_aliases_len[h_aliases_cnt]; */
988 /* char h_addr_list[h_addr_list_cnt][h_length]; - every one is the same size [h_length] (4 or 16) */
989 /* char h_aliases[h_aliases_cnt][h_aliases_len[i]]; */
990 } hst_response_header;
992 static hst_response_header *marshal_hostent(struct hostent *h)
995 hst_response_header *resp;
997 unsigned h_aliases_cnt;
998 unsigned h_addr_list_cnt;
999 unsigned sz = sizeof(*resp);
1001 /* char h_name[h_name_len] */
1002 sz += h_name_len = strsize_aligned4(h->h_name);
1003 h_addr_list_cnt = 0;
1004 while (h->h_addr_list[h_addr_list_cnt]) {
1007 /* char h_addr_list[h_addr_list_cnt][h_length] */
1008 sz += h_addr_list_cnt * h->h_length;
1010 while (h->h_aliases[h_aliases_cnt]) {
1011 /* char h_aliases[h_aliases_cnt][h_aliases_len[i]] */
1012 sz += strsize(h->h_aliases[h_aliases_cnt]);
1015 /* uint32_t h_aliases_len[h_aliases_cnt] */
1016 sz += h_aliases_cnt * 4;
1019 resp->version_or_size = sz;
1021 /*resp->found = 0;*/
1022 resp->error = HOST_NOT_FOUND;
1026 resp->h_name_len = h_name_len;
1027 resp->h_aliases_cnt = h_aliases_cnt;
1028 resp->h_addrtype = h->h_addrtype;
1029 resp->h_length = h->h_length;
1030 resp->h_addr_list_cnt = h_addr_list_cnt;
1031 /*resp->error = 0;*/
1032 p = (char*)(resp + 1);
1033 /* char h_name[h_name_len]; */
1034 strcpy(p, h->h_name);
1036 /* uint32_t h_aliases_len[h_aliases_cnt]; */
1038 while (h->h_aliases[h_aliases_cnt]) {
1039 *(uint32_t*)p = strsize(h->h_aliases[h_aliases_cnt]);
1043 /* char h_addr_list[h_addr_list_cnt][h_length]; */
1044 h_addr_list_cnt = 0;
1045 while (h->h_addr_list[h_addr_list_cnt]) {
1046 memcpy(p, h->h_addr_list[h_addr_list_cnt], h->h_length);
1050 /* char h_aliases[h_aliases_cnt][h_aliases_len[i]]; */
1052 while (h->h_aliases[h_aliases_cnt]) {
1053 strcpy(p, h->h_aliases[h_aliases_cnt]);
1054 p += strsize(h->h_aliases[h_aliases_cnt]);
1057 log(L_DEBUG, "sz:%u realsz:%u", sz, p - (char*)resp);
1062 /* Reply to addrinfo query */
1063 typedef struct ai_response_header {
1064 uint32_t version_or_size;
1070 /* char ai_addr[naddrs][4 or 16]; - addrslen bytes in total */
1071 /* char ai_family[naddrs]; - AF_INET[6] each (determines ai_addr[i] length) */
1072 /* char ai_canonname[canonlen]; */
1073 } ai_response_header;
1075 static ai_response_header *obtain_addrinfo(const char *hostname)
1077 struct addrinfo hints;
1078 struct addrinfo *ai;
1079 struct addrinfo *ap;
1080 ai_response_header *resp;
1084 unsigned naddrs = 0;
1085 unsigned addrslen = 0;
1086 unsigned canonlen = 0;
1088 memset(&hints, 0, sizeof(hints));
1089 hints.ai_flags = AI_CANONNAME;
1090 /* kills dups (one for each possible SOCK_xxx) */
1091 /* this matches glibc behavior */
1092 hints.ai_socktype = SOCK_STREAM;
1093 ai = NULL; /* on failure getaddrinfo may leave it as-is */
1094 err = getaddrinfo(hostname, NULL, &hints, &ai);
1098 if (ai->ai_canonname)
1099 sz += canonlen = strsize(ai->ai_canonname);
1103 addrslen += (ap->ai_family == AF_INET ? 4 : 16);
1106 sz += naddrs + addrslen;
1109 resp->version_or_size = sz;
1112 /*resp->found = 0;*/
1116 resp->naddrs = naddrs;
1117 resp->addrslen = addrslen;
1118 resp->canonlen = canonlen;
1119 p = (char*)(resp + 1);
1120 family = p + addrslen;
1123 /* char ai_family[naddrs]; */
1124 *family++ = ap->ai_family;
1125 /* char ai_addr[naddrs][4 or 16]; */
1126 if (ap->ai_family == AF_INET) {
1127 memcpy(p, &(((struct sockaddr_in*)(ap->ai_addr))->sin_addr), 4);
1130 memcpy(p, &(((struct sockaddr_in6*)(ap->ai_addr))->sin6_addr), 16);
1135 /* char ai_canonname[canonlen]; */
1136 if (ai->ai_canonname)
1137 strcpy(family, ai->ai_canonname);
1138 log(L_DEBUG, "sz:%u realsz:%u", sz, family + strsize(ai->ai_canonname) - (char*)resp);
1140 /* glibc 2.3.6 segfaults here sometimes
1141 * (maybe my mistake, fixed by "ai = NULL;" above).
1142 * Since we are in worker and are going to exit anyway, why bother? */
1143 /*freeaddrinfo(ai);*/
1152 /* one 8-element "cacheline" */
1153 typedef user_req *cacheline_t[8];
1154 static unsigned cache_size;
1155 /* Points to cacheline_t cache[cache_size] array, or in other words,
1156 * points to user_req* cache[cache_size][8] array */
1157 static cacheline_t *cache;
1158 static unsigned cached_cnt;
1159 static unsigned cache_access_cnt = 1; /* prevent division by zero */
1160 static unsigned cache_hit_cnt = 1;
1161 static unsigned last_age_time;
1162 static unsigned aging_interval_ms;
1163 static unsigned min_aging_interval_ms;
1165 static response_header *ureq_response(user_req *ureq)
1167 /* Skip query part, find answer part
1168 * (answer is 32-bit aligned) */
1169 return (void*) ((char*)ureq + ((ureq_size(ureq) + 3) & ~3));
1172 /* This hash is supposed to be good for short textual data */
1173 static uint32_t bernstein_hash(void *p, unsigned sz, uint32_t hash)
1177 hash = (32 * hash + hash) ^ *key++;
1182 static void free_refcounted_ureq(user_req **ureqp)
1184 user_req *ureq = *ureqp;
1186 if (!CACHED_ENTRY(ureq))
1189 if (ureq->refcount) {
1192 log(L_DEBUG2, "refcount == 0, free(%p)", ureq);
1198 static user_req **lookup_in_cache(user_req *ureq)
1200 user_req **cacheline;
1204 unsigned ureq_sz = ureq_size(ureq);
1206 /* prevent overflow and division by zero */
1208 if ((int)cache_access_cnt < 0) {
1209 cache_access_cnt = (cache_access_cnt >> 1) + 1;
1210 cache_hit_cnt = (cache_hit_cnt >> 1) + 1;
1213 hash = bernstein_hash(&ureq->key_len, ureq_sz - offsetof(user_req, key_len), ureq->type);
1214 log(L_DEBUG2, "hash:%08x", hash);
1215 hash = hash % cache_size;
1216 cacheline = cache[hash];
1219 for (i = 0; i < 8; i++) {
1220 user_req *cached = CACHE_PTR(cacheline[i]);
1222 if (free_cache == -1)
1226 /* ureq->version is always 2 and is reused in cache
1227 * for other purposes, we need to skip it here */
1228 if (memcmp(&ureq->type, &cached->type, ureq_sz - offsetof(user_req, type)) == 0) {
1229 log(L_DEBUG, "found in cache[%u][%u]", hash, i);
1231 return &cacheline[i];
1235 if (free_cache >= 0) {
1238 log(L_DEBUG, "not found, using free cache[%u][%u]", hash, i);
1242 unsigned oldest_idx = 0;
1243 unsigned oldest_age = 0;
1244 for (i = 0; i < 8; i++) {
1245 unsigned age = cache_age(cacheline[i]);
1246 if (age > oldest_age) {
1251 if (oldest_age == 0) {
1252 /* All entries in cacheline are "future" entries!
1253 * This is very unlikely, but we must still work correctly.
1254 * We call this "fake cache entry".
1255 * The data will be "cached" only for the duration
1256 * of this client's request lifetime.
1258 log(L_DEBUG, "not found, and cache[%u] is full: using fake cache entry", hash);
1262 log(L_DEBUG, "not found, freeing and reusing cache[%u][%u] (age %u)", hash, i, oldest_age);
1263 free_refcounted_ureq(&cacheline[i]);
1266 cacheline[i] = MAKE_FUTURE_PTR(ureq);
1267 return &cacheline[i];
1270 static void age_cache(unsigned free_all, int srv)
1272 user_req **cp = *cache;
1274 unsigned sv = cached_cnt;
1276 log(L_DEBUG, "aging cache, srv:%d, free_all:%u", srv, free_all);
1277 if (srv == -1 || free_all)
1278 aging_interval_ms = INT_MAX;
1281 user_req *cached = *cp;
1282 if (CACHED_ENTRY(cached) && cached != NULL) {
1283 int csrv = type_to_srv[cached->type];
1284 if (srv == -1 || srv == csrv) {
1287 free_refcounted_ureq(cp);
1289 unsigned age = cache_age(cached);
1290 response_header *resp = ureq_response(cached);
1291 unsigned ttl = (resp->found ? config.pttl : config.nttl)[csrv];
1293 log(L_DEBUG2, "freeing: age %u positive %d ttl %u", age, resp->found, ttl);
1295 free_refcounted_ureq(cp);
1296 } else if (srv == -1) {
1298 if (aging_interval_ms > ttl)
1299 aging_interval_ms = ttl;
1306 log(L_INFO, "aged cache, freed:%u, remain:%u", sv - cached_cnt, cached_cnt);
1307 log(L_DEBUG2, "aging interval now %u ms", aging_interval_ms);
1315 /* Spawns a worker and feeds it with user query on stdin */
1316 /* Returns stdout fd of the worker, in blocking mode */
1317 static int create_and_feed_worker(user_req *ureq)
1323 } to_child, to_parent;
1325 /* NB: these pipe fds are in blocking mode and non-CLOEXECed */
1326 xpipe(&to_child.rd);
1327 xpipe(&to_parent.rd);
1330 if (pid < 0) /* error */
1331 perror_and_die("vfork");
1332 if (!pid) { /* child */
1333 char param[sizeof(int)*3 + 2];
1337 close(to_parent.rd);
1338 xmovefd(to_child.rd, 0);
1339 xmovefd(to_parent.wr, 1);
1340 sprintf(param, "%u", debug);
1341 argv[0] = (char*) "worker_nscd";
1344 /* Re-exec ourself, cleaning up all allocated memory.
1345 * fds in parent are marked CLOEXEC and will be closed too
1347 /* Try link name first: it's better to have comm field
1348 * of "nscd" than "exe" (pgrep reported to fail to find us
1349 * by name when comm field contains "exe") */
1350 execve(self_exe_points_to, argv, argv+2);
1351 xexecve("/proc/self/exe", argv, argv+2);
1356 close(to_parent.wr);
1357 /* We do not expect child to block for any noticeably long time,
1358 * and also we expect write to be one-piece one:
1359 * ureq size is <= 1k and pipes are guaranteed to accept
1360 * at least PIPE_BUF at once */
1361 xsafe_write(to_child.wr, ureq, ureq_size(ureq));
1364 close_on_exec(to_parent.rd);
1365 return to_parent.rd;
1368 static user_req *worker_ureq;
1371 static const char *req_str(unsigned type, const char *buf)
1373 if (type == GETHOSTBYADDR) {
1375 in.s_addr = *((uint32_t*)buf);
1376 return inet_ntoa(in);
1378 if (type == GETHOSTBYADDRv6) {
1384 const char *req_str(unsigned type, const char *buf);
1387 static void worker_signal_handler(int sig)
1390 log(L_INFO, "worker:%d got sig:%d while handling req "
1391 "type:%d(%s) key_len:%d '%s'",
1393 worker_ureq->type, typestr[worker_ureq->type],
1394 worker_ureq->key_len,
1395 req_str(worker_ureq->type, worker_ureq->reqbuf)
1398 log(L_INFO, "worker:%d got sig:%d while handling req "
1399 "type:%d key_len:%d",
1401 worker_ureq->type, worker_ureq->key_len);
1406 static void worker(const char *param) NORETURN;
1407 static void worker(const char *param)
1412 debug = atoi(param);
1414 worker_ureq = &ureq; /* for signal handler */
1416 /* Make sure we won't hang, but rather die */
1417 if (WORKER_TIMEOUT_SEC)
1418 alarm(WORKER_TIMEOUT_SEC);
1420 /* NB: fds 0, 1 are in blocking mode */
1422 /* We block here (for a short time) */
1423 /* Due to ureq size < PIPE_BUF read is atomic */
1424 /* No error or size checking: we trust the parent */
1425 safe_read(0, &ureq, sizeof(ureq));
1427 signal(SIGSEGV, worker_signal_handler);
1428 signal(SIGBUS, worker_signal_handler);
1429 signal(SIGILL, worker_signal_handler);
1430 signal(SIGFPE, worker_signal_handler);
1431 signal(SIGABRT, worker_signal_handler);
1433 signal(SIGSTKFLT, worker_signal_handler);
1436 if (ureq.type == GETHOSTBYNAME
1437 || ureq.type == GETHOSTBYNAMEv6
1439 resp = marshal_hostent(
1440 ureq.type == GETHOSTBYNAME
1441 ? gethostbyname(ureq.reqbuf)
1442 : gethostbyname2(ureq.reqbuf, AF_INET6)
1444 } else if (ureq.type == GETHOSTBYADDR
1445 || ureq.type == GETHOSTBYADDRv6
1447 resp = marshal_hostent(gethostbyaddr(ureq.reqbuf, ureq.key_len,
1448 (ureq.type == GETHOSTBYADDR ? AF_INET : AF_INET6)
1450 } else if (ureq.type == GETPWBYNAME) {
1452 log(L_DEBUG2, "getpwnam('%s')", ureq.reqbuf);
1453 pw = getpwnam(ureq.reqbuf);
1454 log(L_DEBUG2, "getpwnam result:%p", pw);
1455 resp = marshal_passwd(pw);
1456 } else if (ureq.type == GETPWBYUID) {
1457 resp = marshal_passwd(getpwuid(atoi(ureq.reqbuf)));
1458 } else if (ureq.type == GETGRBYNAME) {
1459 struct group *gr = getgrnam(ureq.reqbuf);
1460 resp = marshal_group(gr);
1461 } else if (ureq.type == GETGRBYGID) {
1462 struct group *gr = getgrgid(atoi(ureq.reqbuf));
1463 resp = marshal_group(gr);
1464 } else if (ureq.type == GETAI) {
1465 resp = obtain_addrinfo(ureq.reqbuf);
1466 } else /*if (ureq.type == INITGROUPS)*/ {
1467 resp = obtain_initgroups(ureq.reqbuf);
1470 if (!((response_header*)resp)->found) {
1471 /* Parent knows about this special case */
1472 xfull_write(1, resp, 8);
1474 /* Responses can be big (getgrnam("guest") on a big user db),
1475 * we cannot rely on them being atomic. full_write loops
1477 xfull_write(1, resp, ((response_header*)resp)->version_or_size);
1487 static const char checked_filenames[][sizeof("/etc/passwd")] = {
1488 [SRV_PASSWD] = "/etc/passwd", /* "/etc/shadow"? */
1489 [SRV_GROUP] = "/etc/group",
1490 [SRV_HOSTS] = "/etc/hosts", /* "/etc/resolv.conf" "/etc/nsswitch.conf"? */
1493 static long checked_status[ARRAY_SIZE(checked_filenames)];
1495 static void check_files(int srv)
1498 const char *file = checked_filenames[srv];
1501 memset(&tsb, 0, sizeof(tsb));
1502 stat(file, &tsb); /* ignore errors */
1503 /* Comparing struct stat's was giving false positives.
1504 * Extracting only those fields which are interesting: */
1505 v = (long)tsb.st_mtime ^ (long)tsb.st_size ^ (long)tsb.st_ino; /* ^ (long)tsb.st_dev ? */
1507 if (v != checked_status[srv]) {
1508 checked_status[srv] = v;
1509 log(L_INFO, "detected change in %s", file);
1510 age_cache(/*free_all:*/ 1, srv);
1514 /* Returns 1 if we immediately have the answer */
1515 static int handle_client(int i)
1518 user_req *ureq = cinfo[i].ureq;
1519 user_req **cache_pp;
1520 user_req *ureq_and_resp;
1523 log(L_DEBUG, "version:%d type:%d(%s) key_len:%d '%s'",
1524 ureq->version, ureq->type,
1525 ureq->type < ARRAY_SIZE(typestr) ? typestr[ureq->type] : "?",
1526 ureq->key_len, req_str(ureq->type, ureq->reqbuf));
1529 if (ureq->version != NSCD_VERSION) {
1530 log(L_INFO, "wrong version");
1534 if (ureq->key_len > sizeof(ureq->reqbuf)) {
1535 log(L_INFO, "bogus key_len %u - ignoring", ureq->key_len);
1539 if (cinfo[i].bytecnt < USER_HDR_SIZE + ureq->key_len) {
1540 log(L_INFO, "read %d, need to read %d",
1541 cinfo[i].bytecnt, USER_HDR_SIZE + ureq->key_len);
1542 return 0; /* more to read */
1544 if (cinfo[i].bytecnt > USER_HDR_SIZE + ureq->key_len) {
1545 log(L_INFO, "read overflow: %u > %u",
1546 (int)cinfo[i].bytecnt, (int)(USER_HDR_SIZE + ureq->key_len));
1550 if (unsupported_ureq_type(ureq->type)) {
1551 /* We don't know this request. Just close the connection.
1552 * (glibc client interprets this like "not supported by this nscd")
1553 * Happens very often, thus DEBUG, not INFO */
1554 log(L_DEBUG, "unsupported query, dropping");
1558 srv = type_to_srv[ureq->type];
1559 if (!config.srv_enable[srv]) {
1560 log(L_INFO, "service %d is disabled, dropping", srv);
1565 hex_dump(cinfo[i].ureq, cinfo[i].bytecnt);
1567 if (ureq->type == SHUTDOWN
1568 || ureq->type == INVALIDATE
1571 struct ucred caller;
1572 socklen_t optlen = sizeof(caller);
1573 if (getsockopt(pfd[i].fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0) {
1574 log(L_INFO, "ignoring special request - cannot get caller's id: %s", strerror(errno));
1578 if (caller.uid != 0) {
1579 log(L_INFO, "special request from non-root - ignoring");
1584 if (ureq->type == SHUTDOWN) {
1585 log(L_INFO, "got shutdown request, exiting");
1588 if (!ureq->key_len || ureq->reqbuf[ureq->key_len - 1]) {
1589 log(L_INFO, "malformed invalidate request - ignoring");
1593 log(L_INFO, "got invalidate request, flushing cache");
1594 /* Frees entire cache. TODO: replace -1 with service (in ureq->reqbuf) */
1595 age_cache(/*free_all:*/ 1, -1);
1600 if (ureq->type != GETHOSTBYADDR
1601 && ureq->type != GETHOSTBYADDRv6
1603 if (ureq->key_len && ureq->reqbuf[ureq->key_len - 1] != '\0') {
1604 log(L_INFO, "badly terminated buffer");
1610 if (config.check_files[srv]) {
1614 cache_pp = lookup_in_cache(ureq);
1615 ureq_and_resp = cache_pp ? *cache_pp : NULL;
1617 if (ureq_and_resp) {
1618 if (CACHED_ENTRY(ureq_and_resp)) {
1619 /* Found. Save ptr to response into cinfo and return */
1620 response_header *resp = ureq_response(ureq_and_resp);
1621 unsigned sz = resp->version_or_size;
1623 log(L_DEBUG, "sz:%u", sz);
1625 ureq_and_resp->refcount++; /* cache shouldn't free it under us! */
1626 pfd[i].events = POLLOUT; /* we want to write out */
1627 cinfo[i].resptr = ureq_and_resp;
1628 /*cinfo[i].respos = 0; - already is */
1629 /* prevent future matches with anything */
1630 cinfo[i].cache_pp = (void *) 1;
1631 return 1; /* "ready to write data out to client" */
1634 /* Not found. Remember a pointer where it will appear */
1635 cinfo[i].cache_pp = cache_pp;
1637 /* If it does not point to our own ureq buffer... */
1638 if (CACHE_PTR(ureq_and_resp) != ureq) {
1639 /* We are not the first client who wants this */
1640 log(L_DEBUG, "another request is in progress (%p), waiting for its result", ureq_and_resp);
1641 MARK_PTR_SHARED(cache_pp); /* "please inform us when it's ready" */
1642 /* "we do not wait for client anymore" */
1643 cinfo[i].client_fd = pfd[i].fd;
1644 /* Don't wait on fd. Worker response will unblock us */
1648 /* else: lookup_in_cache inserted (ureq & 1) into *cache_pp:
1649 * we are the first client to miss on this ureq. */
1652 /* Start worker thread */
1653 log(L_DEBUG, "stored %p in cache, starting a worker", ureq_and_resp);
1654 /* Now we will wait on worker's fd, not client's! */
1655 cinfo[i].client_fd = pfd[i].fd;
1656 pfd[i].fd = create_and_feed_worker(ureq);
1660 static void prepare_for_writeout(unsigned i, user_req *cached)
1662 log(L_DEBUG2, "client %u: data is ready at %p", i, cached);
1664 if (cinfo[i].client_fd) {
1665 pfd[i].fd = cinfo[i].client_fd;
1666 cinfo[i].client_fd = 0; /* "we don't wait for worker reply" */
1668 pfd[i].events = POLLOUT;
1670 /* Writeout position etc */
1671 cinfo[i].resptr = cached;
1672 /*cinfo[i].respos = 0; - already is */
1673 /* if worker took some time to get info (e.g. DNS query),
1674 * prevent client timeout from triggering at once */
1675 cinfo[i].started_ms = g_now_ms;
1678 /* Worker seems to be ready to write the response.
1679 * When we return, response is fully read and stored in cache,
1680 * worker's fd is closed, pfd[i] and cinfo[i] are updated. */
1681 static void handle_worker_response(int i)
1683 struct { /* struct response_header + small body */
1684 uint32_t version_or_size;
1690 response_header *resp;
1691 unsigned sz, resp_sz;
1692 unsigned ureq_sz_aligned;
1695 ureq = cinfo[i].ureq;
1696 ureq_sz_aligned = (char*)ureq_response(ureq) - (char*)ureq;
1698 sz = full_read(pfd[i].fd, &sz_and_found, sizeof(sz_and_found));
1700 /* worker was killed? */
1701 log(L_DEBUG, "worker gave short reply:%u < 8", sz);
1705 resp_sz = sz_and_found.version_or_size;
1706 if (resp_sz < sz || resp_sz > 0x0fffffff) { /* 256 mb */
1707 error("BUG: bad size from worker:%u", resp_sz);
1711 /* Create new block of cached info */
1712 cached = xzalloc(ureq_sz_aligned + resp_sz);
1713 log(L_DEBUG2, "xzalloc(%u):%p sz:%u resp_sz:%u found:%u",
1714 ureq_sz_aligned + resp_sz, cached,
1716 (int)sz_and_found.found
1718 resp = (void*) (((char*) cached) + ureq_sz_aligned);
1719 memcpy(cached, ureq, ureq_size(ureq));
1720 memcpy(resp, &sz_and_found, sz);
1721 if (sz_and_found.found && resp_sz > sz) {
1722 /* We need to read data only if it's found
1723 * (otherwise worker sends only 8 bytes).
1725 * Replies can be big (getgrnam("guest") on a big user db),
1726 * we cannot rely on them being atomic. However, we know
1727 * that worker _always_ gives reply in one full_write(),
1728 * so we loop and read it all
1729 * (looping is implemented inside full_read())
1731 if (full_read(pfd[i].fd, ((char*) resp) + sz, resp_sz - sz) != resp_sz - sz) {
1732 /* worker was killed? */
1733 log(L_DEBUG, "worker gave short reply, free(%p)", cached);
1740 set_cache_timestamp(cached);
1741 hex_dump(resp, resp_sz);
1748 user_req **cache_pp = cinfo[i].cache_pp;
1749 if (cache_pp != NULL) { /* if not a fake entry */
1752 if (CACHE_SHARED(ureq)) {
1753 /* Other clients wait for this response too,
1754 * wake them (and us) up and set refcount = no_of_clients */
1757 for (j = 2; j < num_clients; j++) {
1758 if (cinfo[j].cache_pp == cache_pp) {
1759 /* This client uses the same cache entry */
1761 /* prevent future matches with anything */
1762 cinfo[j].cache_pp = (void *) 1;
1763 prepare_for_writeout(j, cached);
1768 /* prevent future matches with anything */
1769 cinfo[i].cache_pp = (void *) 1;
1773 prepare_for_writeout(i, cached);
1775 /* cache shouldn't free it under us! */
1777 cached->refcount = ref;
1778 aging_interval_ms = min_aging_interval_ms;
1781 static void main_loop(void)
1783 /* 1/2 of smallest negative TTL */
1784 min_aging_interval_ms = config.nttl[0];
1785 if (min_aging_interval_ms > config.nttl[1]) min_aging_interval_ms = config.nttl[1];
1786 if (min_aging_interval_ms > config.nttl[2]) min_aging_interval_ms = config.nttl[2];
1787 min_aging_interval_ms = (min_aging_interval_ms / 2) | 1;
1788 aging_interval_ms = min_aging_interval_ms;
1794 r = SMALL_POLL_TIMEOUT_MS;
1795 if (num_clients <= 2 && !cached_cnt)
1796 r = -1; /* infinite */
1797 else if (num_clients < max_reqnum)
1798 r = aging_interval_ms;
1799 #if 0 /* Debug: leak detector */
1801 static unsigned long long cnt;
1802 static unsigned long low_malloc = -1L;
1803 static unsigned long low_sbrk = -1L;
1804 void *p = malloc(540); /* should not be too small */
1807 if ((unsigned long)p < low_malloc)
1808 low_malloc = (unsigned long)p;
1809 if ((unsigned long)s < low_sbrk)
1810 low_sbrk = (unsigned long)s;
1811 log(L_INFO, "poll %llu (%d ms). clients:%u cached:%u %u/%u malloc:%p (%lu), sbrk:%p (%lu)",
1812 cnt, r, num_clients, cached_cnt, cache_hit_cnt, cache_access_cnt,
1813 p, (unsigned long)p - low_malloc,
1814 s, (unsigned long)s - low_sbrk);
1818 log(L_DEBUG, "poll %d ms. clients:%u cached:%u hit ratio:%u/%u",
1819 r, num_clients, cached_cnt, cache_hit_cnt, cache_access_cnt);
1822 r = poll(pfd, num_clients, r);
1823 log(L_DEBUG2, "poll returns %d", r);
1826 perror_and_die("poll");
1830 /* Everything between polls never sleeps.
1831 * There is no blocking I/O (except when we talk to worker thread
1832 * which is guaranteed to not block us for long) */
1834 g_now_ms = monotonic_ms();
1836 goto skip_fd_checks;
1838 for (i = 0; i < 2; i++) {
1840 if (!pfd[i].revents)
1842 /* pfd[i].revents = 0; - not needed */
1843 cfd = accept(pfd[i].fd, NULL, NULL);
1845 /* odd... poll() says we can accept but accept failed? */
1846 log(L_DEBUG2, "accept failed with %s", strerror(errno));
1851 /* x[num_clients] is next free element, taking it */
1852 log(L_DEBUG2, "new client %d, fd %d", num_clients, cfd);
1853 pfd[num_clients].fd = cfd;
1854 pfd[num_clients].events = POLLIN;
1855 /* this will make us do read() in next for() loop: */
1856 pfd[num_clients].revents = POLLIN;
1857 memset(&cinfo[num_clients], 0, sizeof(cinfo[num_clients]));
1858 /* cinfo[num_clients].bytecnt = 0; - done */
1859 cinfo[num_clients].started_ms = g_now_ms;
1860 cinfo[num_clients].bufidx = alloc_buf_no();
1861 cinfo[num_clients].ureq = bufno2buf(cinfo[num_clients].bufidx);
1863 if (num_clients >= max_reqnum) {
1864 /* stop accepting new connects for now */
1865 pfd[0].events = pfd[0].revents = 0;
1866 pfd[1].events = pfd[1].revents = 0;
1869 for (; i < num_clients; i++) {
1870 if (!pfd[i].revents)
1872 log(L_DEBUG2, "pfd[%d].revents:0x%x", i, pfd[i].revents);
1873 /* pfd[i].revents = 0; - not needed */
1875 /* "Write out result" case */
1876 if (pfd[i].revents == POLLOUT) {
1877 response_header *resp;
1879 if (!cinfo[i].resptr) {
1880 /* corner case: worker gave bad response earlier */
1885 resp = ureq_response(cinfo[i].resptr);
1886 resp_sz = resp->version_or_size;
1887 resp->version_or_size = NSCD_VERSION;
1889 r = safe_write(pfd[i].fd, ((char*) resp) + cinfo[i].respos, resp_sz - cinfo[i].respos);
1890 resp->version_or_size = resp_sz;
1892 if (r < 0 && errno == EAGAIN)
1894 if (r <= 0) { /* client isn't there anymore */
1895 log(L_DEBUG, "client %d is gone (write returned:%d err:%s)",
1896 i, r, errno ? strerror(errno) : "-");
1898 if (cinfo[i].cache_pp == NULL) {
1899 log(L_DEBUG, "client %d: freeing fake cache entry %p", i, cinfo[i].resptr);
1900 free(cinfo[i].resptr);
1902 /* Most of the time, it is not freed here,
1903 * only refcounted--. Freeing happens
1904 * if it was deleted from cache[] but retained
1906 free_refcounted_ureq(&cinfo[i].resptr);
1911 cinfo[i].respos += r;
1912 if (cinfo[i].respos >= resp_sz) {
1913 /* We wrote everything */
1914 /* No point in trying to get next request, it won't come.
1915 * glibc 2.4 client closes its end after each request,
1916 * without testing for EOF from server. strace:
1918 * read(3, "www.google.com\0\0", 16) = 16
1921 log(L_DEBUG, "client %u: sent answer %u bytes", i, cinfo[i].respos);
1922 goto write_out_is_done;
1926 /* "Read reply from worker" case. Worker may be
1927 * already dead, revents may contain other bits too */
1928 if ((pfd[i].revents & POLLIN) && cinfo[i].client_fd) {
1929 log(L_DEBUG, "reading response for client %u", i);
1930 handle_worker_response(i);
1931 /* We can immediately try to write a response
1936 /* POLLHUP means pfd[i].fd is closed by peer.
1937 * POLLHUP+POLLOUT is seen when we switch for writeout
1938 * and see that pfd[i].fd is closed by peer. */
1939 if ((pfd[i].revents & ~POLLOUT) == POLLHUP) {
1940 int is_client = (cinfo[i].client_fd == 0 || cinfo[i].client_fd == pfd[i].fd);
1941 log(L_INFO, "%s %u disappeared (got POLLHUP on fd %d)",
1942 is_client ? "client" : "worker",
1949 /* Read worker output anyway, error handling
1950 * in that function deals with short read.
1951 * Simply closing client is wrong: it leaks
1952 * shared future entries. */
1953 handle_worker_response(i);
1958 /* All strange and unexpected cases */
1959 if (pfd[i].revents != POLLIN) {
1960 /* Not just "can read", but some other bits are there */
1961 log(L_INFO, "client %u revents is strange:%x", i, pfd[i].revents);
1966 /* "Read request from client" case */
1967 r = safe_read(pfd[i].fd, (char*)(cinfo[i].ureq) + cinfo[i].bytecnt, MAX_USER_REQ_SIZE - cinfo[i].bytecnt);
1969 log(L_DEBUG2, "error reading from client: %s", strerror(errno));
1970 if (errno == EAGAIN)
1976 log(L_INFO, "premature EOF from client, dropping");
1980 cinfo[i].bytecnt += r;
1981 if (cinfo[i].bytecnt >= sizeof(user_req_header)) {
1982 if (handle_client(i)) {
1983 /* Response is found in cache! */
1987 } /* for each client[2..num_clients-1] */
1991 if ((g_now_ms - last_age_time) >= aging_interval_ms) {
1992 last_age_time = g_now_ms;
1993 age_cache(/*free_all:*/ 0, -1);
1996 /* Close timed out client connections */
1997 for (i = 2; i < num_clients; i++) {
1998 if (pfd[i].fd != 0 /* not closed yet? */ ////
1999 && cinfo[i].client_fd == 0 /* do we still wait for client, not worker? */
2000 && (g_now_ms - cinfo[i].started_ms) > CLIENT_TIMEOUT_MS
2002 log(L_INFO, "timed out waiting for client %u (%u ms), dropping",
2003 i, (unsigned)(g_now_ms - cinfo[i].started_ms));
2011 /* We closed at least one client, coalesce pfd[], cinfo[] */
2012 if (min_closed + cnt_closed >= num_clients) {
2013 /* clients [min_closed..num_clients-1] are all closed */
2014 /* log(L_DEBUG, "taking shortcut"); - almost always happens */
2019 while (i < num_clients) {
2023 if (++i >= num_clients)
2027 cinfo[j++] = cinfo[i++];
2031 num_clients -= cnt_closed;
2032 log(L_DEBUG, "removing %d closed clients. clients:%d", cnt_closed, num_clients);
2033 min_closed = INT_MAX;
2035 /* start accepting new connects */
2036 pfd[0].events = POLLIN;
2037 pfd[1].events = POLLIN;
2046 #define NSCD_PIDFILE "/var/run/nscd/nscd.pid"
2047 #define NSCD_DIR "/var/run/nscd"
2048 #define NSCD_SOCKET "/var/run/nscd/socket"
2049 #define NSCD_SOCKET_OLD "/var/run/.nscd_socket"
2051 static smallint wrote_pidfile;
2053 static void cleanup_on_signal(int sig)
2056 unlink(NSCD_PIDFILE);
2057 unlink(NSCD_SOCKET_OLD);
2058 unlink(NSCD_SOCKET);
2062 static void write_pid(void)
2064 FILE *pid = fopen(NSCD_PIDFILE, "w");
2067 fprintf(pid, "%d\n", getpid());
2072 /* Open a listening nscd server socket */
2073 static int open_socket(const char *name)
2075 struct sockaddr_un sun;
2076 int sock = socket(AF_UNIX, SOCK_STREAM, 0);
2078 perror_and_die("cannot create unix domain socket");
2080 close_on_exec(sock);
2081 sun.sun_family = AF_UNIX;
2082 strcpy(sun.sun_path, name);
2084 if (bind(sock, (struct sockaddr *) &sun, sizeof(sun)) < 0)
2085 perror_and_die("bind(%s)", name);
2086 if (chmod(name, 0666) < 0)
2087 perror_and_die("chmod(%s)", name);
2088 if (listen(sock, (max_reqnum/8) | 1) < 0)
2089 perror_and_die("listen");
2093 static const struct option longopt[] = {
2094 /* name, has_arg, int *flag, int val */
2095 { "debug" , no_argument , NULL, 'd' },
2096 { "config-file", required_argument, NULL, 'f' },
2097 { "invalidate" , required_argument, NULL, 'i' },
2098 { "shutdown" , no_argument , NULL, 'K' },
2099 { "nthreads" , required_argument, NULL, 't' },
2100 { "version" , no_argument , NULL, 'V' },
2101 { "help" , no_argument , NULL, '?' },
2102 { "usage" , no_argument , NULL, '?' },
2103 /* just exit(0). TODO: "test" connect? */
2104 { "statistic" , no_argument , NULL, 'g' },
2105 { "secure" , no_argument , NULL, 'S' }, /* ? */
2109 static const char *const help[] = {
2110 "Do not daemonize; log to stderr (-dd: more verbosity)",
2111 "File to read configuration from",
2113 "Shut the server down",
2114 "Serve N requests in parallel",
2118 static void print_help_and_die(void)
2120 const struct option *opt = longopt;
2121 const char *const *h = help;
2123 puts("Usage: nscd [OPTION...]\n"
2124 "Name Service Cache Daemon\n");
2126 printf("\t" "-%c,--%-11s %s\n", opt->val, opt->name, *h);
2129 } while (opt->val != '?');
2133 static char *skip_service(int *srv, const char *s)
2135 if (strcmp("passwd", s) == 0) {
2138 } else if (strcmp("group", s) == 0) {
2140 } else if (strcmp("hosts", s) == 0) {
2145 return skip_whitespace(s + 6);
2148 static void handle_null(const char *str, int srv) {}
2150 static void handle_logfile(const char *str, int srv)
2152 config.logfile = xstrdup(str);
2155 static void handle_debuglvl(const char *str, int srv)
2157 debug |= (uint8_t) getnum(str);
2160 static void handle_threads(const char *str, int srv)
2162 unsigned n = getnum(str);
2167 static void handle_user(const char *str, int srv)
2169 config.user = xstrdup(str);
2172 static void handle_enable(const char *str, int srv)
2174 config.srv_enable[srv] = ((str[0] | 0x20) == 'y');
2177 static void handle_pttl(const char *str, int srv)
2179 config.pttl[srv] = getnum(str);
2182 static void handle_nttl(const char *str, int srv)
2184 config.nttl[srv] = getnum(str);
2187 static void handle_size(const char *str, int srv)
2189 config.size[srv] = getnum(str);
2192 static void handle_chfiles(const char *str, int srv)
2194 config.check_files[srv] = ((str[0] | 0x20) == 'y');
2197 static void parse_conffile(const char *conffile, int warn)
2199 static const struct confword {
2201 void (*handler)(const char *, int);
2203 { "_" "logfile" , handle_logfile },
2204 { "_" "debug-level" , handle_debuglvl },
2205 { "_" "threads" , handle_threads },
2206 { "_" "max-threads" , handle_threads },
2207 { "_" "server-user" , handle_user },
2208 /* ignore: any user can stat */
2209 { "_" "stat-user" , handle_null },
2210 { "_" "paranoia" , handle_null }, /* ? */
2211 /* ignore: design goal is to never crash/hang */
2212 { "_" "reload-count" , handle_null },
2213 { "_" "restart-interval" , handle_null },
2214 { "S" "enable-cache" , handle_enable },
2215 { "S" "positive-time-to-live" , handle_pttl },
2216 { "S" "negative-time-to-live" , handle_nttl },
2217 { "S" "suggested-size" , handle_size },
2218 { "S" "check-files" , handle_chfiles },
2219 { "S" "persistent" , handle_null }, /* ? */
2220 { "S" "shared" , handle_null }, /* ? */
2221 { "S" "auto-propagate" , handle_null }, /* ? */
2226 FILE *file = fopen(conffile, "r");
2230 if (conffile != default_conffile)
2231 perror_and_die("cannot open %s", conffile);
2235 while (fgets(buf, sizeof(buf), file) != NULL) {
2236 const struct confword *word;
2238 int len = strlen(buf);
2242 if (buf[len-1] != '\n') {
2243 if (len >= sizeof(buf) - 1)
2244 error_and_die("%s:%d: line is too long", conffile, lineno);
2245 len++; /* last line, not terminated by '\n' */
2249 p = strchr(buf, '#');
2253 p = skip_whitespace(buf);
2256 *skip_non_whitespace(p) = '\0';
2259 if (strcmp(word->str + 1, p) == 0) {
2261 p = skip_whitespace(p + strlen(p) + 1);
2262 *skip_non_whitespace(p) = '\0';
2263 if (word->str[0] == 'S') {
2264 char *p2 = skip_service(&srv, p);
2267 error("%s:%d: ignoring unknown service name '%s'", conffile, lineno, p);
2271 *skip_non_whitespace(p) = '\0';
2273 word->handler(p, srv);
2279 error("%s:%d: ignoring unknown directive '%s'", conffile, lineno, p);
2288 /* "XX,XX[,XX]..." -> gid_t[] */
2289 static gid_t* env_U_to_uid_and_gids(const char *str, int *sizep)
2300 ug = xmalloc(ng * sizeof(ug[0]));
2308 *gp++ = strtoul(sp, (char**)&sp, 16);
2309 if (errno || (*sp != ',' && *sp != '\0'))
2310 error_and_die("internal error");
2321 static char* user_to_env_U(const char *user)
2328 pw = getpwnam(user);
2330 perror_and_die("user '%s' is not known", user);
2333 /* 0th cell will be used for uid */
2334 ug = xmalloc((1 + ng) * sizeof(ug[0]));
2335 if (getgrouplist(user, pw->pw_gid, &ug[1], &ng) < 0) {
2336 ug = xrealloc(ug, (1 + ng) * sizeof(ug[0]));
2337 if (getgrouplist(user, pw->pw_gid, &ug[1], &ng) < 0)
2338 perror_and_die("can't get groups of user '%s'", user);
2343 /* How much do we need for "-Uxx,xx[,xx]..." string? */
2344 ug_str = xmalloc((sizeof(unsigned long)+1)*2 * ng + 3);
2350 sp += sprintf(sp, "%lx,", (unsigned long)(*gp++));
2359 /* not static - don't inline me, compiler! */
2360 void readlink_self_exe(void);
2361 void readlink_self_exe(void)
2363 char buf[PATH_MAX + 1];
2364 ssize_t sz = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
2366 perror_and_die("readlink %s failed", "/proc/self/exe");
2368 self_exe_points_to = xstrdup(buf);
2372 static void special_op(const char *arg) NORETURN;
2373 static void special_op(const char *arg)
2375 static const user_req_header ureq = { NSCD_VERSION, SHUTDOWN, 0 };
2377 struct sockaddr_un addr;
2380 sock = socket(PF_UNIX, SOCK_STREAM, 0);
2382 error_and_die("cannot create AF_UNIX socket");
2384 addr.sun_family = AF_UNIX;
2385 strcpy(addr.sun_path, NSCD_SOCKET);
2386 if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
2387 error_and_die("cannot connect to %s", NSCD_SOCKET);
2389 if (!arg) { /* shutdown */
2390 xfull_write(sock, &ureq, sizeof(ureq));
2391 printf("sent shutdown request, exiting\n");
2392 } else { /* invalidate */
2393 size_t arg_len = strlen(arg) + 1;
2395 user_req_header req;
2398 reqdata.req.version = NSCD_VERSION;
2399 reqdata.req.type = INVALIDATE;
2400 reqdata.req.key_len = arg_len;
2401 memcpy(reqdata.arg, arg, arg_len);
2402 xfull_write(sock, &reqdata, arg_len + sizeof(ureq));
2403 printf("sent invalidate(%s) request, exiting\n", arg);
2409 /* Callback for glibc-2.15 */
2411 static void do_nothing(size_t dbidx, struct traced_file *finfo)
2413 /* nscd from glibc-2.15 does something like this:
2414 if (!dbs[dbidx].enabled || !dbs[dbidx].check_file)
2416 add_file_to_watch_list(finfo->fname);
2420 /* This internal glibc function is called to disable trying to contact nscd.
2421 * We _are_ nscd, so we need to do the lookups, and not recurse.
2422 * Until 2.14, this function was taking no parameters.
2423 * In 2.15, it takes a function pointer from hell.
2425 void __nss_disable_nscd(void (*hell)(size_t, struct traced_file*));
2428 int main(int argc, char **argv)
2433 const char *conffile;
2435 /* make sure we don't get recursive calls */
2436 __nss_disable_nscd(do_nothing);
2438 if (argv[0][0] == 'w') /* "worker_nscd" */
2444 /* Make sure stdio is not closed */
2445 n = xopen3("/dev/null", O_RDWR, 0);
2448 /* Close unexpected open file descriptors */
2449 n |= 0xff; /* start from at least fd# 255 */
2454 /* For idiotic kernels which disallow "exec /proc/self/exe" */
2455 readlink_self_exe();
2457 conffile = default_conffile;
2459 while ((n = getopt_long(argc, argv, "df:i:KVgt:", longopt, NULL)) != -1) {
2470 special_op(optarg); /* exits */
2472 /* shutdown server */
2473 special_op(NULL); /* exits */
2475 puts("unscd - nscd which does not hang, v."PROGRAM_VERSION);
2481 max_reqnum = getnum(optarg);
2487 print_help_and_die();
2490 /* Multiple -d can bump debug regardless of nscd.conf:
2491 * no -d or -d: 0, -dd: 1,
2492 * -ddd: 3, -dddd: 7, -ddddd: 15
2495 debug |= (((1U << opt_d_cnt) >> 1) - 1) & L_ALL;
2497 env_U = getenv("U");
2498 /* Avoid duplicate warnings if $U exists */
2499 parse_conffile(conffile, /* warn? */ (env_U == NULL));
2501 /* I have a user report of (broken?) ldap nss library
2502 * opening and never closing a socket to a ldap server,
2503 * even across fork() and exec(). This messes up
2504 * worker child's operations for the reporter.
2506 * This strenghtens my belief that nscd _must not_ trust
2507 * nss libs to be written correctly.
2509 * Here, we need to jump through the hoops to guard against
2510 * such problems. If config file has server-user setting, we need
2511 * to setgroups + setuid. For that, we need to get uid and gid vector.
2512 * And that means possibly using buggy nss libs.
2513 * We will do it here, but then we will re-exec, passing uid+gids
2514 * in an environment variable.
2516 if (!env_U && config.user) {
2517 /* user_to_env_U() does getpwnam and getgrouplist */
2518 if (putenv(user_to_env_U(config.user)))
2519 error_and_die("out of memory");
2520 /* fds leaked by nss will be closed by execed copy */
2521 execv(self_exe_points_to, argv);
2522 xexecve("/proc/self/exe", argv, environ);
2525 /* Allocate dynamically sized stuff */
2526 max_reqnum += 2; /* account for 2 first "fake" clients */
2527 if (max_reqnum < 8) max_reqnum = 8; /* sanitize */
2528 /* Since refcount is a byte, can't serve more than 255-2 clients
2529 * at once. The rest will block in connect() */
2530 if (max_reqnum > 0xff) max_reqnum = 0xff;
2531 client_buf = xzalloc(max_reqnum * sizeof(client_buf[0]));
2532 busy_cbuf = xzalloc(max_reqnum * sizeof(busy_cbuf[0]));
2533 pfd = xzalloc(max_reqnum * sizeof(pfd[0]));
2534 cinfo = xzalloc(max_reqnum * sizeof(cinfo[0]));
2536 cache_size = (config.size[0] + config.size[1] + config.size[2]) / 8;
2537 if (cache_size < 8) cache_size = 8; /* 8*8 = 64 entries min */
2538 if (cache_size > 0xffff) cache_size = 0xffff; /* 8*64k entries max */
2539 cache_size |= 1; /* force it to be odd */
2540 cache = xzalloc(cache_size * sizeof(cache[0]));
2542 /* Register cleanup hooks */
2543 signal(SIGINT, cleanup_on_signal);
2544 signal(SIGTERM, cleanup_on_signal);
2545 /* Don't die if a client closes a socket on us */
2546 signal(SIGPIPE, SIG_IGN);
2547 /* Avoid creating zombies */
2548 signal(SIGCHLD, SIG_IGN);
2550 /* Ensure workers don't have SIGALRM ignored */
2551 signal(SIGALRM, SIG_DFL);
2554 if (mkdir(NSCD_DIR, 0755) == 0) {
2555 /* prevent bad mode of NSCD_DIR if umask is e.g. 077 */
2556 chmod(NSCD_DIR, 0755);
2558 pfd[0].fd = open_socket(NSCD_SOCKET);
2559 pfd[1].fd = open_socket(NSCD_SOCKET_OLD);
2560 pfd[0].events = POLLIN;
2561 pfd[1].events = POLLIN;
2563 if (debug & D_DAEMON) {
2564 daemon(/*nochdir*/ 1, /*noclose*/ 0);
2565 if (config.logfile) {
2566 /* nochdir=1: relative paths still work as expected */
2567 xmovefd(xopen3(config.logfile, O_WRONLY|O_CREAT|O_TRUNC, 0666), 2);
2570 debug = 0; /* why bother? it's /dev/null'ed anyway */
2572 chdir("/"); /* compat */
2575 /* ignore job control signals */
2576 signal(SIGTTOU, SIG_IGN);
2577 signal(SIGTTIN, SIG_IGN);
2578 signal(SIGTSTP, SIG_IGN);
2581 log(L_ALL, "unscd v" PROGRAM_VERSION ", debug level 0x%x", debug & L_ALL);
2582 log(L_DEBUG, "max %u requests in parallel", max_reqnum - 2);
2583 log(L_DEBUG, "cache size %u x 8 entries", cache_size);
2587 gid_t *ug = env_U_to_uid_and_gids(env_U, &size);
2589 if (setgroups(size - 1, &ug[1]) || setgid(ug[1]))
2590 perror_and_die("cannot set groups for user '%s'", config.user);
2593 perror_and_die("cannot set uid to %u", (unsigned)(ug[0]));
2597 for (n = 0; n < 3; n++) {
2598 log(L_DEBUG, "%s cache enabled:%u pttl:%u nttl:%u",
2600 config.srv_enable[n],
2603 config.pttl[n] *= 1000;
2604 config.nttl[n] *= 1000;