Update.
[glibc.git] / nscd / connections.c
blob11be7c3d0cf9e73c80ecaefd927ef5204d370243
1 /* Inner loops of cache daemon.
2 Copyright (C) 1998-2003, 2004 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include <assert.h>
22 #include <atomic.h>
23 #include <error.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <grp.h>
27 #include <libintl.h>
28 #include <pthread.h>
29 #include <pwd.h>
30 #include <resolv.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <arpa/inet.h>
35 #include <sys/mman.h>
36 #include <sys/param.h>
37 #include <sys/poll.h>
38 #include <sys/socket.h>
39 #include <sys/stat.h>
40 #include <sys/un.h>
42 #include "nscd.h"
43 #include "dbg_log.h"
46 /* Number of bytes of data we initially reserve for each hash table bucket. */
47 #define DEFAULT_DATASIZE_PER_BUCKET 1024
50 /* Wrapper functions with error checking for standard functions. */
51 extern void *xmalloc (size_t n);
52 extern void *xcalloc (size_t n, size_t s);
53 extern void *xrealloc (void *o, size_t n);
55 /* Support to run nscd as an unprivileged user */
56 const char *server_user;
57 static uid_t server_uid;
58 static gid_t server_gid;
59 const char *stat_user;
60 uid_t stat_uid;
61 static gid_t *server_groups;
62 #ifndef NGROUPS
63 # define NGROUPS 32
64 #endif
65 static int server_ngroups;
67 static void begin_drop_privileges (void);
68 static void finish_drop_privileges (void);
70 /* Map request type to a string. */
71 const char *serv2str[LASTREQ] =
73 [GETPWBYNAME] = "GETPWBYNAME",
74 [GETPWBYUID] = "GETPWBYUID",
75 [GETGRBYNAME] = "GETGRBYNAME",
76 [GETGRBYGID] = "GETGRBYGID",
77 [GETHOSTBYNAME] = "GETHOSTBYNAME",
78 [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6",
79 [GETHOSTBYADDR] = "GETHOSTBYADDR",
80 [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
81 [SHUTDOWN] = "SHUTDOWN",
82 [GETSTAT] = "GETSTAT",
83 [INVALIDATE] = "INVALIDATE",
84 [GETFDPW] = "GETFDPW",
85 [GETFDGR] = "GETFDGR",
86 [GETFDHST] = "GETFDHST"
89 /* The control data structures for the services. */
90 struct database_dyn dbs[lastdb] =
92 [pwddb] = {
93 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
94 .enabled = 0,
95 .check_file = 1,
96 .persistent = 0,
97 .shared = 0,
98 .filename = "/etc/passwd",
99 .db_filename = _PATH_NSCD_PASSWD_DB,
100 .disabled_iov = &pwd_iov_disabled,
101 .postimeout = 3600,
102 .negtimeout = 20,
103 .wr_fd = -1,
104 .ro_fd = -1,
105 .mmap_used = false
107 [grpdb] = {
108 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
109 .enabled = 0,
110 .check_file = 1,
111 .persistent = 0,
112 .shared = 0,
113 .filename = "/etc/group",
114 .db_filename = _PATH_NSCD_GROUP_DB,
115 .disabled_iov = &grp_iov_disabled,
116 .postimeout = 3600,
117 .negtimeout = 60,
118 .wr_fd = -1,
119 .ro_fd = -1,
120 .mmap_used = false
122 [hstdb] = {
123 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
124 .enabled = 0,
125 .check_file = 1,
126 .persistent = 0,
127 .shared = 0,
128 .filename = "/etc/hosts",
129 .db_filename = _PATH_NSCD_HOSTS_DB,
130 .disabled_iov = &hst_iov_disabled,
131 .postimeout = 3600,
132 .negtimeout = 20,
133 .wr_fd = -1,
134 .ro_fd = -1,
135 .mmap_used = false
140 /* Mapping of request type to database. */
141 static struct database_dyn *const serv2db[LASTREQ] =
143 [GETPWBYNAME] = &dbs[pwddb],
144 [GETPWBYUID] = &dbs[pwddb],
145 [GETGRBYNAME] = &dbs[grpdb],
146 [GETGRBYGID] = &dbs[grpdb],
147 [GETHOSTBYNAME] = &dbs[hstdb],
148 [GETHOSTBYNAMEv6] = &dbs[hstdb],
149 [GETHOSTBYADDR] = &dbs[hstdb],
150 [GETHOSTBYADDRv6] = &dbs[hstdb],
151 [GETFDPW] = &dbs[pwddb],
152 [GETFDGR] = &dbs[grpdb],
153 [GETFDHST] = &dbs[hstdb],
157 /* Number of seconds between two cache pruning runs. */
158 #define CACHE_PRUNE_INTERVAL 15
161 /* Number of threads to use. */
162 int nthreads = -1;
164 /* Socket for incoming connections. */
165 static int sock;
167 /* Number of times clients had to wait. */
168 unsigned long int client_queued;
171 /* Initialize database information structures. */
172 void
173 nscd_init (void)
175 struct sockaddr_un sock_addr;
176 size_t cnt;
178 /* Secure mode and unprivileged mode are incompatible */
179 if (server_user != NULL && secure_in_use)
181 dbg_log (_("Cannot run nscd in secure mode as unprivileged user"));
182 exit (1);
185 /* Look up unprivileged uid/gid/groups before we start listening on the
186 socket */
187 if (server_user != NULL)
188 begin_drop_privileges ();
190 if (nthreads == -1)
191 /* No configuration for this value, assume a default. */
192 nthreads = 2 * lastdb;
194 for (cnt = 0; cnt < lastdb; ++cnt)
195 if (dbs[cnt].enabled)
197 pthread_rwlock_init (&dbs[cnt].lock, NULL);
198 pthread_mutex_init (&dbs[cnt].memlock, NULL);
200 if (dbs[cnt].persistent)
202 /* Try to open the appropriate file on disk. */
203 int fd = open (dbs[cnt].db_filename, O_RDWR);
204 if (fd != -1)
206 struct stat64 st;
207 void *mem;
208 size_t total;
209 struct database_pers_head head;
210 ssize_t n = TEMP_FAILURE_RETRY (read (fd, &head,
211 sizeof (head)));
212 if (n != sizeof (head) || fstat64 (fd, &st) != 0)
214 fail_db:
215 dbg_log (_("invalid persistent database file \"%s\": %s"),
216 dbs[cnt].db_filename, strerror (errno));
217 dbs[cnt].persistent = 0;
219 else if (head.module == 0 && head.data_size == 0)
221 /* The file has been created, but the head has not been
222 initialized yet. Remove the old file. */
223 unlink (dbs[cnt].db_filename);
225 else if (head.header_size != (int) sizeof (head))
227 dbg_log (_("invalid persistent database file \"%s\": %s"),
228 dbs[cnt].db_filename,
229 _("header size does not match"));
230 dbs[cnt].persistent = 0;
232 else if ((total = (sizeof (head)
233 + roundup (head.module * sizeof (ref_t),
234 ALIGN)
235 + head.data_size))
236 > st.st_size)
238 dbg_log (_("invalid persistent database file \"%s\": %s"),
239 dbs[cnt].db_filename,
240 _("file size does not match"));
241 dbs[cnt].persistent = 0;
243 else if ((mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
244 MAP_SHARED, fd, 0)) == MAP_FAILED)
245 goto fail_db;
246 else
248 /* Success. We have the database. */
249 dbs[cnt].head = mem;
250 dbs[cnt].memsize = total;
251 dbs[cnt].data = (char *)
252 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
253 ALIGN / sizeof (ref_t))];
254 dbs[cnt].mmap_used = true;
256 if (dbs[cnt].suggested_module > head.module)
257 dbg_log (_("suggested size of table for database %s larger than the persistent database's table"),
258 dbnames[cnt]);
260 dbs[cnt].wr_fd = fd;
261 fd = -1;
262 /* We also need a read-only descriptor. */
263 if (dbs[cnt].shared)
265 dbs[cnt].ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
266 if (dbs[cnt].ro_fd == -1)
267 dbg_log (_("\
268 cannot create read-only descriptor for \"%s\"; no mmap"),
269 dbs[cnt].db_filename);
272 // XXX Shall we test whether the descriptors actually
273 // XXX point to the same file?
276 /* Close the file descriptors in case something went
277 wrong in which case the variable have not been
278 assigned -1. */
279 if (fd != -1)
280 close (fd);
284 if (dbs[cnt].head == NULL)
286 /* No database loaded. Allocate the data structure,
287 possibly on disk. */
288 struct database_pers_head head;
289 size_t total = (sizeof (head)
290 + roundup (dbs[cnt].suggested_module
291 * sizeof (ref_t), ALIGN)
292 + (dbs[cnt].suggested_module
293 * DEFAULT_DATASIZE_PER_BUCKET));
295 /* Try to create the database. If we do not need a
296 persistent database create a temporary file. */
297 int fd;
298 int ro_fd = -1;
299 if (dbs[cnt].persistent)
301 fd = open (dbs[cnt].db_filename,
302 O_RDWR | O_CREAT | O_EXCL | O_TRUNC,
303 S_IRUSR | S_IWUSR);
304 if (fd != -1 && dbs[cnt].shared)
305 ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
307 else
309 size_t slen = strlen (dbs[cnt].db_filename);
310 char fname[slen + 8];
311 strcpy (mempcpy (fname, dbs[cnt].db_filename, slen),
312 ".XXXXXX");
313 fd = mkstemp (fname);
315 /* We do not need the file name anymore after we
316 opened another file descriptor in read-only mode. */
317 if (fd != -1 && dbs[cnt].shared)
319 ro_fd = open (fname, O_RDONLY);
321 unlink (fname);
325 if (fd == -1)
327 if (errno == EEXIST)
329 dbg_log (_("database for %s corrupted or simultaneously used; remove %s manually if necessary and restart"),
330 dbnames[cnt], dbs[cnt].db_filename);
331 // XXX Correct way to terminate?
332 exit (1);
335 if (dbs[cnt].persistent)
336 dbg_log (_("cannot create %s; no persistent database used"),
337 dbs[cnt].db_filename);
338 else
339 dbg_log (_("cannot create %s; no sharing possible"),
340 dbs[cnt].db_filename);
342 dbs[cnt].persistent = 0;
343 // XXX remember: no mmap
345 else
347 /* Tell the user if we could not create the read-only
348 descriptor. */
349 if (ro_fd == -1 && dbs[cnt].shared)
350 dbg_log (_("\
351 cannot create read-only descriptor for \"%s\"; no mmap"),
352 dbs[cnt].db_filename);
354 /* Before we create the header, initialiye the hash
355 table. So that if we get interrupted if writing
356 the header we can recognize a partially initialized
357 database. */
358 size_t ps = sysconf (_SC_PAGESIZE);
359 char tmpbuf[ps];
360 assert (~ENDREF == 0);
361 memset (tmpbuf, '\xff', ps);
363 size_t remaining = dbs[cnt].suggested_module * sizeof (ref_t);
364 off_t offset = sizeof (head);
366 size_t towrite;
367 if (offset % ps != 0)
369 towrite = MIN (remaining, ps - (offset % ps));
370 pwrite (fd, tmpbuf, towrite, offset);
371 offset += towrite;
372 remaining -= towrite;
375 while (remaining > ps)
377 pwrite (fd, tmpbuf, ps, offset);
378 offset += ps;
379 remaining -= ps;
382 if (remaining > 0)
383 pwrite (fd, tmpbuf, remaining, offset);
385 /* Create the header of the file. */
386 struct database_pers_head head =
388 .version = DB_VERSION,
389 .header_size = sizeof (head),
390 .module = dbs[cnt].suggested_module,
391 .data_size = (dbs[cnt].suggested_module
392 * DEFAULT_DATASIZE_PER_BUCKET),
393 .first_free = 0
395 void *mem;
397 if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head)))
398 != sizeof (head))
399 || ftruncate (fd, total) != 0
400 || (mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
401 MAP_SHARED, fd, 0)) == MAP_FAILED)
403 unlink (dbs[cnt].db_filename);
404 dbg_log (_("cannot write to database file %s: %s"),
405 dbs[cnt].db_filename, strerror (errno));
406 dbs[cnt].persistent = 0;
408 else
410 /* Success. */
411 dbs[cnt].head = mem;
412 dbs[cnt].data = (char *)
413 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
414 ALIGN / sizeof (ref_t))];
415 dbs[cnt].memsize = total;
416 dbs[cnt].mmap_used = true;
418 /* Remember the descriptors. */
419 dbs[cnt].wr_fd = fd;
420 dbs[cnt].ro_fd = ro_fd;
421 fd = -1;
422 ro_fd = -1;
425 if (fd != -1)
426 close (fd);
427 if (ro_fd != -1)
428 close (ro_fd);
432 if (dbs[cnt].head == NULL)
434 /* We do not use the persistent database. Just
435 create an in-memory data structure. */
436 assert (! dbs[cnt].persistent);
438 dbs[cnt].head = xmalloc (sizeof (struct database_pers_head)
439 + (dbs[cnt].suggested_module
440 * sizeof (ref_t)));
441 memset (dbs[cnt].head, '\0', sizeof (dbs[cnt].head));
442 assert (~ENDREF == 0);
443 memset (dbs[cnt].head->array, '\xff',
444 dbs[cnt].suggested_module * sizeof (ref_t));
445 dbs[cnt].head->module = dbs[cnt].suggested_module;
446 dbs[cnt].head->data_size = (DEFAULT_DATASIZE_PER_BUCKET
447 * dbs[cnt].head->module);
448 dbs[cnt].data = xmalloc (dbs[cnt].head->data_size);
449 dbs[cnt].head->first_free = 0;
451 dbs[cnt].shared = 0;
452 assert (dbs[cnt].ro_fd == -1);
455 if (dbs[cnt].check_file)
457 /* We need the modification date of the file. */
458 struct stat st;
460 if (stat (dbs[cnt].filename, &st) < 0)
462 /* We cannot stat() the file, disable file checking. */
463 dbg_log (_("cannot stat() file `%s': %s"),
464 dbs[cnt].filename, strerror (errno));
465 dbs[cnt].check_file = 0;
467 else
468 dbs[cnt].file_mtime = st.st_mtime;
472 /* Create the socket. */
473 sock = socket (AF_UNIX, SOCK_STREAM, 0);
474 if (sock < 0)
476 dbg_log (_("cannot open socket: %s"), strerror (errno));
477 exit (1);
479 /* Bind a name to the socket. */
480 sock_addr.sun_family = AF_UNIX;
481 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
482 if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
484 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
485 exit (1);
488 /* We don't wait for data otherwise races between threads can get
489 them stuck on accept. */
490 int fl = fcntl (sock, F_GETFL);
491 if (fl != -1)
492 fcntl (sock, F_SETFL, fl | O_NONBLOCK);
494 /* Set permissions for the socket. */
495 chmod (_PATH_NSCDSOCKET, DEFFILEMODE);
497 /* Set the socket up to accept connections. */
498 if (listen (sock, SOMAXCONN) < 0)
500 dbg_log (_("cannot enable socket to accept connections: %s"),
501 strerror (errno));
502 exit (1);
505 /* Change to unprivileged uid/gid/groups if specifed in config file */
506 if (server_user != NULL)
507 finish_drop_privileges ();
511 /* Close the connections. */
512 void
513 close_sockets (void)
515 close (sock);
519 static void
520 invalidate_cache (char *key)
522 dbtype number;
524 if (strcmp (key, "passwd") == 0)
525 number = pwddb;
526 else if (strcmp (key, "group") == 0)
527 number = grpdb;
528 else if (__builtin_expect (strcmp (key, "hosts"), 0) == 0)
530 number = hstdb;
532 /* Re-initialize the resolver. resolv.conf might have changed. */
533 res_init ();
535 else
536 return;
538 if (dbs[number].enabled)
539 prune_cache (&dbs[number], LONG_MAX);
543 #ifdef SCM_RIGHTS
544 static void
545 send_ro_fd (struct database_dyn *db, char *key, int fd)
547 /* If we do not have an read-only file descriptor do nothing. */
548 if (db->ro_fd == -1)
549 return;
551 /* We need to send some data along with the descriptor. */
552 struct iovec iov[1];
553 iov[0].iov_base = key;
554 iov[0].iov_len = strlen (key) + 1;
556 /* Prepare the control message to transfer the descriptor. */
557 char buf[CMSG_SPACE (sizeof (int))];
558 struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
559 .msg_control = buf, .msg_controllen = sizeof (buf) };
560 struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
562 cmsg->cmsg_level = SOL_SOCKET;
563 cmsg->cmsg_type = SCM_RIGHTS;
564 cmsg->cmsg_len = CMSG_LEN (sizeof (int));
566 *(int *) CMSG_DATA (cmsg) = db->ro_fd;
568 msg.msg_controllen = cmsg->cmsg_len;
570 /* Send the control message. We repeat when we are interrupted but
571 everything else is ignored. */
572 (void) TEMP_FAILURE_RETRY (sendmsg (fd, &msg, 0));
574 if (__builtin_expect (debug_level > 0, 0))
575 dbg_log (_("provide access to FD %d, for %s"), db->ro_fd, key);
577 #endif /* SCM_RIGHTS */
580 /* Handle new request. */
581 static void
582 handle_request (int fd, request_header *req, void *key, uid_t uid)
584 if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
586 if (debug_level > 0)
587 dbg_log (_("\
588 cannot handle old request version %d; current version is %d"),
589 req->version, NSCD_VERSION);
590 return;
593 struct database_dyn *db = serv2db[req->type];
595 if (__builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
596 && __builtin_expect (req->type, LASTDBREQ) <= LASTDBREQ)
598 if (__builtin_expect (debug_level, 0) > 0)
600 if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
602 char buf[INET6_ADDRSTRLEN];
604 dbg_log ("\t%s (%s)", serv2str[req->type],
605 inet_ntop (req->type == GETHOSTBYADDR
606 ? AF_INET : AF_INET6,
607 key, buf, sizeof (buf)));
609 else
610 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
613 /* Is this service enabled? */
614 if (!db->enabled)
616 /* No, sent the prepared record. */
617 if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
618 db->disabled_iov->iov_len))
619 != (ssize_t) db->disabled_iov->iov_len
620 && __builtin_expect (debug_level, 0) > 0)
622 /* We have problems sending the result. */
623 char buf[256];
624 dbg_log (_("cannot write result: %s"),
625 strerror_r (errno, buf, sizeof (buf)));
628 return;
631 /* Be sure we can read the data. */
632 if (__builtin_expect (pthread_rwlock_tryrdlock (&db->lock) != 0, 0))
634 ++db->head->rdlockdelayed;
635 pthread_rwlock_rdlock (&db->lock);
638 /* See whether we can handle it from the cache. */
639 struct datahead *cached;
640 cached = (struct datahead *) cache_search (req->type, key, req->key_len,
641 db, uid);
642 if (cached != NULL)
644 /* Hurray it's in the cache. */
645 if (TEMP_FAILURE_RETRY (write (fd, cached->data, cached->recsize))
646 != cached->recsize
647 && __builtin_expect (debug_level, 0) > 0)
649 /* We have problems sending the result. */
650 char buf[256];
651 dbg_log (_("cannot write result: %s"),
652 strerror_r (errno, buf, sizeof (buf)));
655 pthread_rwlock_unlock (&db->lock);
657 return;
660 pthread_rwlock_unlock (&db->lock);
662 else if (__builtin_expect (debug_level, 0) > 0)
664 if (req->type == INVALIDATE)
665 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
666 else
667 dbg_log ("\t%s", serv2str[req->type]);
670 /* Handle the request. */
671 switch (req->type)
673 case GETPWBYNAME:
674 addpwbyname (db, fd, req, key, uid);
675 break;
677 case GETPWBYUID:
678 addpwbyuid (db, fd, req, key, uid);
679 break;
681 case GETGRBYNAME:
682 addgrbyname (db, fd, req, key, uid);
683 break;
685 case GETGRBYGID:
686 addgrbygid (db, fd, req, key, uid);
687 break;
689 case GETHOSTBYNAME:
690 addhstbyname (db, fd, req, key, uid);
691 break;
693 case GETHOSTBYNAMEv6:
694 addhstbynamev6 (db, fd, req, key, uid);
695 break;
697 case GETHOSTBYADDR:
698 addhstbyaddr (db, fd, req, key, uid);
699 break;
701 case GETHOSTBYADDRv6:
702 addhstbyaddrv6 (db, fd, req, key, uid);
703 break;
705 case GETSTAT:
706 case SHUTDOWN:
707 case INVALIDATE:
708 if (! secure_in_use)
710 /* Get the callers credentials. */
711 #ifdef SO_PEERCRED
712 struct ucred caller;
713 socklen_t optlen = sizeof (caller);
715 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
717 char buf[256];
719 dbg_log (_("error getting callers id: %s"),
720 strerror_r (errno, buf, sizeof (buf)));
721 break;
724 uid = caller.uid;
725 #else
726 /* Some systems have no SO_PEERCRED implementation. They don't
727 care about security so we don't as well. */
728 uid = 0;
729 #endif
732 /* Accept shutdown, getstat and invalidate only from root. For
733 the stat call also allow the user specified in the config file. */
734 if (req->type == GETSTAT)
736 if (uid == 0 || uid == stat_uid)
737 send_stats (fd, dbs);
739 else if (uid == 0)
741 if (req->type == INVALIDATE)
742 invalidate_cache (key);
743 else
744 termination_handler (0);
746 break;
748 case GETFDPW:
749 case GETFDGR:
750 case GETFDHST:
751 #ifdef SCM_RIGHTS
752 send_ro_fd (serv2db[req->type], key, fd);
753 #endif
754 break;
756 default:
757 /* Ignore the command, it's nothing we know. */
758 break;
763 /* This is the main loop. It is replicated in different threads but the
764 `poll' call makes sure only one thread handles an incoming connection. */
765 static void *
766 __attribute__ ((__noreturn__))
767 nscd_run (void *p)
769 long int my_number = (long int) p;
770 struct pollfd conn;
771 int run_prune = my_number < lastdb && dbs[my_number].enabled;
772 time_t next_prune = run_prune ? time (NULL) + CACHE_PRUNE_INTERVAL : 0;
773 static unsigned long int nready;
775 if (my_number < lastdb)
776 setup_thread (&dbs[my_number]);
778 conn.fd = sock;
779 conn.events = POLLRDNORM;
781 while (1)
783 int nr;
784 time_t now = 0;
786 /* One more thread available. */
787 atomic_increment (&nready);
789 no_conn:
792 int timeout = -1;
793 if (run_prune)
795 /* NB: we do not flush the timestamp update using msync since
796 this value doesnot matter on disk. */
797 dbs[my_number].head->timestamp = now = time (NULL);
798 timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
801 nr = poll (&conn, 1, timeout);
803 if (nr == 0)
805 /* The `poll' call timed out. It's time to clean up the
806 cache. */
807 atomic_decrement (&nready);
808 assert (my_number < lastdb);
809 prune_cache (&dbs[my_number], time(NULL));
810 now = time (NULL);
811 next_prune = now + CACHE_PRUNE_INTERVAL;
813 goto try_get;
816 while ((conn.revents & POLLRDNORM) == 0);
818 got_data:;
819 /* We have a new incoming connection. Accept the connection. */
820 int fd = TEMP_FAILURE_RETRY (accept (conn.fd, NULL, NULL));
821 request_header req;
822 char buf[256];
823 uid_t uid = -1;
824 #ifdef SO_PEERCRED
825 pid_t pid = 0;
826 #endif
828 if (__builtin_expect (fd, 0) < 0)
830 if (errno != EAGAIN && errno != EWOULDBLOCK)
831 dbg_log (_("while accepting connection: %s"),
832 strerror_r (errno, buf, sizeof (buf)));
833 goto no_conn;
836 /* This thread is busy. */
837 atomic_decrement (&nready);
839 /* Now read the request. */
840 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
841 != sizeof (req), 0))
843 if (debug_level > 0)
844 dbg_log (_("short read while reading request: %s"),
845 strerror_r (errno, buf, sizeof (buf)));
846 close (fd);
847 continue;
850 /* Check whether this is a valid request type. */
851 if (req.type < GETPWBYNAME || req.type >= LASTREQ)
852 goto close_and_out;
854 /* Some systems have no SO_PEERCRED implementation. They don't
855 care about security so we don't as well. */
856 #ifdef SO_PEERCRED
857 if (secure_in_use)
859 struct ucred caller;
860 socklen_t optlen = sizeof (caller);
862 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
864 dbg_log (_("error getting callers id: %s"),
865 strerror_r (errno, buf, sizeof (buf)));
866 goto close_and_out;
869 if (req.type < GETPWBYNAME || req.type > LASTDBREQ
870 || serv2db[req.type]->secure)
871 uid = caller.uid;
873 pid = caller.pid;
875 else if (__builtin_expect (debug_level > 0, 0))
877 struct ucred caller;
878 socklen_t optlen = sizeof (caller);
880 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) == 0)
881 pid = caller.pid;
883 #endif
885 /* It should not be possible to crash the nscd with a silly
886 request (i.e., a terribly large key). We limit the size to 1kb. */
887 if (__builtin_expect (req.key_len, 1) < 0
888 || __builtin_expect (req.key_len, 1) > 1024)
890 if (debug_level > 0)
891 dbg_log (_("key length in request too long: %d"), req.key_len);
893 else
895 /* Get the key. */
896 char keybuf[req.key_len];
898 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
899 req.key_len))
900 != req.key_len, 0))
902 if (debug_level > 0)
903 dbg_log (_("short read while reading request key: %s"),
904 strerror_r (errno, buf, sizeof (buf)));
905 close (fd);
906 continue;
909 if (__builtin_expect (debug_level, 0) > 0)
911 #ifdef SO_PEERCRED
912 if (pid != 0)
913 dbg_log (_("\
914 handle_request: request received (Version = %d) from PID %ld"),
915 req.version, (long int) pid);
916 else
917 #endif
918 dbg_log (_("\
919 handle_request: request received (Version = %d)"), req.version);
922 /* Phew, we got all the data, now process it. */
923 handle_request (fd, &req, keybuf, uid);
926 close_and_out:
927 /* We are done. */
928 close (fd);
930 /* Just determine whether any data is present. We do this to
931 measure whether clients are queued up. */
932 try_get:
933 nr = poll (&conn, 1, 0);
934 if (nr != 0)
936 if (nready == 0)
937 ++client_queued;
939 atomic_increment (&nready);
941 goto got_data;
947 /* Start all the threads we want. The initial process is thread no. 1. */
948 void
949 start_threads (void)
951 long int i;
952 pthread_attr_t attr;
953 pthread_t th;
955 pthread_attr_init (&attr);
956 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
958 /* We allow less than LASTDB threads only for debugging. */
959 if (debug_level == 0)
960 nthreads = MAX (nthreads, lastdb);
962 for (i = 1; i < nthreads; ++i)
963 pthread_create (&th, &attr, nscd_run, (void *) i);
965 pthread_attr_destroy (&attr);
967 nscd_run ((void *) 0);
971 /* Look up the uid, gid, and supplementary groups to run nscd as. When
972 this function is called, we are not listening on the nscd socket yet so
973 we can just use the ordinary lookup functions without causing a lockup */
974 static void
975 begin_drop_privileges (void)
977 struct passwd *pwd = getpwnam (server_user);
979 if (pwd == NULL)
981 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
982 error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"),
983 server_user);
986 server_uid = pwd->pw_uid;
987 server_gid = pwd->pw_gid;
989 if (getgrouplist (server_user, server_gid, NULL, &server_ngroups) == 0)
991 /* This really must never happen. */
992 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
993 error (EXIT_FAILURE, errno, _("initial getgrouplist failed"));
996 server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
998 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
999 == -1)
1001 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1002 error (EXIT_FAILURE, errno, _("getgrouplist failed"));
1007 /* Call setgroups(), setgid(), and setuid() to drop root privileges and
1008 run nscd as the user specified in the configuration file. */
1009 static void
1010 finish_drop_privileges (void)
1012 if (setgroups (server_ngroups, server_groups) == -1)
1014 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1015 error (EXIT_FAILURE, errno, _("setgroups failed"));
1018 if (setgid (server_gid) == -1)
1020 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1021 perror ("setgid");
1022 exit (1);
1025 if (setuid (server_uid) == -1)
1027 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1028 perror ("setuid");
1029 exit (1);