[BZ #375]
[glibc.git] / nscd / connections.c
blob2ca6f69cf24a7966c8ad3fcedca4e06131c290e1
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 dbs[cnt].ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
262 fd = -1;
263 /* We also need a read-only descriptor. */
264 dbs[cnt].ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
265 if (dbs[cnt].ro_fd == -1)
266 dbg_log (_("\
267 cannot create read-only descriptor for \"%s\"; no mmap"),
268 dbs[cnt].db_filename);
270 // XXX Shall we test whether the descriptors actually
271 // XXX point to the same file?
274 /* Close the file descriptors in case something went
275 wrong in which case the variable have not been
276 assigned -1. */
277 if (fd != -1)
278 close (fd);
282 if (dbs[cnt].head == NULL)
284 /* No database loaded. Allocate the data structure,
285 possibly on disk. */
286 struct database_pers_head head;
287 size_t total = (sizeof (head)
288 + roundup (dbs[cnt].suggested_module
289 * sizeof (ref_t), ALIGN)
290 + (dbs[cnt].suggested_module
291 * DEFAULT_DATASIZE_PER_BUCKET));
293 /* Try to create the database. If we do not need a
294 persistent database create a temporary file. */
295 int fd;
296 int ro_fd = -1;
297 if (dbs[cnt].persistent)
299 fd = open (dbs[cnt].db_filename,
300 O_RDWR | O_CREAT | O_EXCL | O_TRUNC,
301 S_IRUSR | S_IWUSR);
302 if (fd != -1)
303 ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
305 else
307 size_t slen = strlen (dbs[cnt].db_filename);
308 char fname[slen + 8];
309 strcpy (mempcpy (fname, dbs[cnt].db_filename, slen),
310 ".XXXXXX");
311 fd = mkstemp (fname);
313 /* We do not need the file name anymore after we
314 opened another file descriptor in read-only mode. */
315 if (fd != -1)
317 ro_fd = open (fname, O_RDONLY);
319 unlink (fname);
323 if (fd == -1)
325 if (errno == EEXIST)
327 dbg_log (_("database for %s corrupted or simultaneously used; remove %s manually if necessary and restart"),
328 dbnames[cnt], dbs[cnt].db_filename);
329 // XXX Correct way to terminate?
330 exit (1);
333 if (dbs[cnt].persistent)
334 dbg_log (_("cannot create %s; no persistent database used"),
335 dbs[cnt].db_filename);
336 else
337 dbg_log (_("cannot create %s; no sharing possible"),
338 dbs[cnt].db_filename);
340 dbs[cnt].persistent = 0;
341 // XXX remember: no mmap
343 else
345 /* Tell the user if we could not create the read-only
346 descriptor. */
347 if (ro_fd == -1)
348 dbg_log (_("\
349 cannot create read-only descriptor for \"%s\"; no mmap"),
350 dbs[cnt].db_filename);
352 /* Before we create the header, initialiye the hash
353 table. So that if we get interrupted if writing
354 the header we can recognize a partially initialized
355 database. */
356 size_t ps = sysconf (_SC_PAGESIZE);
357 char tmpbuf[ps];
358 assert (~ENDREF == 0);
359 memset (tmpbuf, '\xff', ps);
361 size_t remaining = dbs[cnt].suggested_module * sizeof (ref_t);
362 off_t offset = sizeof (head);
364 size_t towrite;
365 if (offset % ps != 0)
367 towrite = MIN (remaining, ps - (offset % ps));
368 pwrite (fd, tmpbuf, towrite, offset);
369 offset += towrite;
370 remaining -= towrite;
373 while (remaining > ps)
375 pwrite (fd, tmpbuf, ps, offset);
376 offset += ps;
377 remaining -= ps;
380 if (remaining > 0)
381 pwrite (fd, tmpbuf, remaining, offset);
383 /* Create the header of the file. */
384 struct database_pers_head head =
386 .version = DB_VERSION,
387 .header_size = sizeof (head),
388 .module = dbs[cnt].suggested_module,
389 .data_size = (dbs[cnt].suggested_module
390 * DEFAULT_DATASIZE_PER_BUCKET),
391 .first_free = 0
393 void *mem;
395 if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head)))
396 != sizeof (head))
397 || ftruncate (fd, total) != 0
398 || (mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
399 MAP_SHARED, fd, 0)) == MAP_FAILED)
401 unlink (dbs[cnt].db_filename);
402 dbg_log (_("cannot write to database file %s: %s"),
403 dbs[cnt].db_filename, strerror (errno));
404 dbs[cnt].persistent = 0;
406 else
408 /* Success. */
409 dbs[cnt].head = mem;
410 dbs[cnt].data = (char *)
411 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
412 ALIGN / sizeof (ref_t))];
413 dbs[cnt].memsize = total;
414 dbs[cnt].mmap_used = true;
416 /* Remember the descriptors. */
417 dbs[cnt].wr_fd = fd;
418 dbs[cnt].ro_fd = ro_fd;
419 fd = -1;
420 ro_fd = -1;
423 if (fd != -1)
424 close (fd);
425 if (ro_fd != -1)
426 close (ro_fd);
430 if (dbs[cnt].head == NULL)
432 /* We do not use the persistent database. Just
433 create an in-memory data structure. */
434 assert (! dbs[cnt].persistent);
436 dbs[cnt].head = xmalloc (sizeof (struct database_pers_head)
437 + (dbs[cnt].suggested_module
438 * sizeof (ref_t)));
439 memset (dbs[cnt].head, '\0', sizeof (dbs[cnt].head));
440 assert (~ENDREF == 0);
441 memset (dbs[cnt].head->array, '\xff',
442 dbs[cnt].suggested_module * sizeof (ref_t));
443 dbs[cnt].head->module = dbs[cnt].suggested_module;
444 dbs[cnt].head->data_size = (DEFAULT_DATASIZE_PER_BUCKET
445 * dbs[cnt].head->module);
446 dbs[cnt].data = xmalloc (dbs[cnt].head->data_size);
447 dbs[cnt].head->first_free = 0;
449 dbs[cnt].shared = 0;
450 assert (dbs[cnt].ro_fd == -1);
453 if (dbs[cnt].check_file)
455 /* We need the modification date of the file. */
456 struct stat st;
458 if (stat (dbs[cnt].filename, &st) < 0)
460 /* We cannot stat() the file, disable file checking. */
461 dbg_log (_("cannot stat() file `%s': %s"),
462 dbs[cnt].filename, strerror (errno));
463 dbs[cnt].check_file = 0;
465 else
466 dbs[cnt].file_mtime = st.st_mtime;
470 /* Create the socket. */
471 sock = socket (AF_UNIX, SOCK_STREAM, 0);
472 if (sock < 0)
474 dbg_log (_("cannot open socket: %s"), strerror (errno));
475 exit (1);
477 /* Bind a name to the socket. */
478 sock_addr.sun_family = AF_UNIX;
479 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
480 if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
482 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
483 exit (1);
486 /* We don't wait for data otherwise races between threads can get
487 them stuck on accept. */
488 int fl = fcntl (sock, F_GETFL);
489 if (fl != -1)
490 fcntl (sock, F_SETFL, fl | O_NONBLOCK);
492 /* Set permissions for the socket. */
493 chmod (_PATH_NSCDSOCKET, DEFFILEMODE);
495 /* Set the socket up to accept connections. */
496 if (listen (sock, SOMAXCONN) < 0)
498 dbg_log (_("cannot enable socket to accept connections: %s"),
499 strerror (errno));
500 exit (1);
503 /* Change to unprivileged uid/gid/groups if specifed in config file */
504 if (server_user != NULL)
505 finish_drop_privileges ();
509 /* Close the connections. */
510 void
511 close_sockets (void)
513 close (sock);
517 static void
518 invalidate_cache (char *key)
520 dbtype number;
522 if (strcmp (key, "passwd") == 0)
523 number = pwddb;
524 else if (strcmp (key, "group") == 0)
525 number = grpdb;
526 else if (__builtin_expect (strcmp (key, "hosts"), 0) == 0)
528 number = hstdb;
530 /* Re-initialize the resolver. resolv.conf might have changed. */
531 res_init ();
533 else
534 return;
536 if (dbs[number].enabled)
537 prune_cache (&dbs[number], LONG_MAX);
541 #ifdef SCM_RIGHTS
542 static void
543 send_ro_fd (struct database_dyn *db, char *key, int fd)
545 /* If we do not have an read-only file descriptor do nothing. */
546 if (db->ro_fd == -1)
547 return;
549 /* We need to send some data along with the descriptor. */
550 struct iovec iov[1];
551 iov[0].iov_base = key;
552 iov[0].iov_len = strlen (key) + 1;
554 /* Prepare the control message to transfer the descriptor. */
555 char buf[CMSG_SPACE (sizeof (int))];
556 struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
557 .msg_control = buf, .msg_controllen = sizeof (buf) };
558 struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
560 cmsg->cmsg_level = SOL_SOCKET;
561 cmsg->cmsg_type = SCM_RIGHTS;
562 cmsg->cmsg_len = CMSG_LEN (sizeof (int));
564 *(int *) CMSG_DATA (cmsg) = db->ro_fd;
566 msg.msg_controllen = cmsg->cmsg_len;
568 /* Send the control message. We repeat when we are interrupted but
569 everything else is ignored. */
570 (void) TEMP_FAILURE_RETRY (sendmsg (fd, &msg, 0));
572 if (__builtin_expect (debug_level > 0, 0))
573 dbg_log (_("provide access to FD %d, for %s"), db->ro_fd, key);
575 #endif /* SCM_RIGHTS */
578 /* Handle new request. */
579 static void
580 handle_request (int fd, request_header *req, void *key, uid_t uid)
582 if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
584 if (debug_level > 0)
585 dbg_log (_("\
586 cannot handle old request version %d; current version is %d"),
587 req->version, NSCD_VERSION);
588 return;
591 struct database_dyn *db = serv2db[req->type];
593 if (__builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
594 && __builtin_expect (req->type, LASTDBREQ) <= LASTDBREQ)
596 if (__builtin_expect (debug_level, 0) > 0)
598 if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
600 char buf[INET6_ADDRSTRLEN];
602 dbg_log ("\t%s (%s)", serv2str[req->type],
603 inet_ntop (req->type == GETHOSTBYADDR
604 ? AF_INET : AF_INET6,
605 key, buf, sizeof (buf)));
607 else
608 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
611 /* Is this service enabled? */
612 if (!db->enabled)
614 /* No, sent the prepared record. */
615 if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
616 db->disabled_iov->iov_len))
617 != (ssize_t) db->disabled_iov->iov_len
618 && __builtin_expect (debug_level, 0) > 0)
620 /* We have problems sending the result. */
621 char buf[256];
622 dbg_log (_("cannot write result: %s"),
623 strerror_r (errno, buf, sizeof (buf)));
626 return;
629 /* Be sure we can read the data. */
630 if (__builtin_expect (pthread_rwlock_tryrdlock (&db->lock) != 0, 0))
632 ++db->head->rdlockdelayed;
633 pthread_rwlock_rdlock (&db->lock);
636 /* See whether we can handle it from the cache. */
637 struct datahead *cached;
638 cached = (struct datahead *) cache_search (req->type, key, req->key_len,
639 db, uid);
640 if (cached != NULL)
642 /* Hurray it's in the cache. */
643 if (TEMP_FAILURE_RETRY (write (fd, cached->data, cached->recsize))
644 != cached->recsize
645 && __builtin_expect (debug_level, 0) > 0)
647 /* We have problems sending the result. */
648 char buf[256];
649 dbg_log (_("cannot write result: %s"),
650 strerror_r (errno, buf, sizeof (buf)));
653 pthread_rwlock_unlock (&db->lock);
655 return;
658 pthread_rwlock_unlock (&db->lock);
660 else if (__builtin_expect (debug_level, 0) > 0)
662 if (req->type == INVALIDATE)
663 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
664 else
665 dbg_log ("\t%s", serv2str[req->type]);
668 /* Handle the request. */
669 switch (req->type)
671 case GETPWBYNAME:
672 addpwbyname (db, fd, req, key, uid);
673 break;
675 case GETPWBYUID:
676 addpwbyuid (db, fd, req, key, uid);
677 break;
679 case GETGRBYNAME:
680 addgrbyname (db, fd, req, key, uid);
681 break;
683 case GETGRBYGID:
684 addgrbygid (db, fd, req, key, uid);
685 break;
687 case GETHOSTBYNAME:
688 addhstbyname (db, fd, req, key, uid);
689 break;
691 case GETHOSTBYNAMEv6:
692 addhstbynamev6 (db, fd, req, key, uid);
693 break;
695 case GETHOSTBYADDR:
696 addhstbyaddr (db, fd, req, key, uid);
697 break;
699 case GETHOSTBYADDRv6:
700 addhstbyaddrv6 (db, fd, req, key, uid);
701 break;
703 case GETSTAT:
704 case SHUTDOWN:
705 case INVALIDATE:
706 if (! secure_in_use)
708 /* Get the callers credentials. */
709 #ifdef SO_PEERCRED
710 struct ucred caller;
711 socklen_t optlen = sizeof (caller);
713 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
715 char buf[256];
717 dbg_log (_("error getting callers id: %s"),
718 strerror_r (errno, buf, sizeof (buf)));
719 break;
722 uid = caller.uid;
723 #else
724 /* Some systems have no SO_PEERCRED implementation. They don't
725 care about security so we don't as well. */
726 uid = 0;
727 #endif
730 /* Accept shutdown, getstat and invalidate only from root. For
731 the stat call also allow the user specified in the config file. */
732 if (req->type == GETSTAT)
734 if (uid == 0 || uid == stat_uid)
735 send_stats (fd, dbs);
737 else if (uid == 0)
739 if (req->type == INVALIDATE)
740 invalidate_cache (key);
741 else
742 termination_handler (0);
744 break;
746 case GETFDPW:
747 case GETFDGR:
748 case GETFDHST:
749 #ifdef SCM_RIGHTS
750 send_ro_fd (serv2db[req->type], key, fd);
751 #endif
752 break;
754 default:
755 /* Ignore the command, it's nothing we know. */
756 break;
761 /* This is the main loop. It is replicated in different threads but the
762 `poll' call makes sure only one thread handles an incoming connection. */
763 static void *
764 __attribute__ ((__noreturn__))
765 nscd_run (void *p)
767 long int my_number = (long int) p;
768 struct pollfd conn;
769 int run_prune = my_number < lastdb && dbs[my_number].enabled;
770 time_t next_prune = run_prune ? time (NULL) + CACHE_PRUNE_INTERVAL : 0;
771 static unsigned long int nready;
773 if (my_number < lastdb)
774 setup_thread (&dbs[my_number]);
776 conn.fd = sock;
777 conn.events = POLLRDNORM;
779 while (1)
781 int nr;
782 time_t now = 0;
784 /* One more thread available. */
785 atomic_increment (&nready);
787 no_conn:
790 int timeout = -1;
791 if (run_prune)
793 /* NB: we do not flush the timestamp update using msync since
794 this value doesnot matter on disk. */
795 dbs[my_number].head->timestamp = now = time (NULL);
796 timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
799 nr = poll (&conn, 1, timeout);
801 if (nr == 0)
803 /* The `poll' call timed out. It's time to clean up the
804 cache. */
805 atomic_decrement (&nready);
806 assert (my_number < lastdb);
807 prune_cache (&dbs[my_number], time(NULL));
808 now = time (NULL);
809 next_prune = now + CACHE_PRUNE_INTERVAL;
811 goto try_get;
814 while ((conn.revents & POLLRDNORM) == 0);
816 got_data:;
817 /* We have a new incoming connection. Accept the connection. */
818 int fd = TEMP_FAILURE_RETRY (accept (conn.fd, NULL, NULL));
819 request_header req;
820 char buf[256];
821 uid_t uid = -1;
822 #ifdef SO_PEERCRED
823 pid_t pid = 0;
824 #endif
826 if (__builtin_expect (fd, 0) < 0)
828 if (errno != EAGAIN && errno != EWOULDBLOCK)
829 dbg_log (_("while accepting connection: %s"),
830 strerror_r (errno, buf, sizeof (buf)));
831 goto no_conn;
834 /* This thread is busy. */
835 atomic_decrement (&nready);
837 /* Now read the request. */
838 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
839 != sizeof (req), 0))
841 if (debug_level > 0)
842 dbg_log (_("short read while reading request: %s"),
843 strerror_r (errno, buf, sizeof (buf)));
844 close (fd);
845 continue;
848 /* Check whether this is a valid request type. */
849 if (req.type < GETPWBYNAME || req.type >= LASTREQ)
850 goto close_and_out;
852 /* Some systems have no SO_PEERCRED implementation. They don't
853 care about security so we don't as well. */
854 #ifdef SO_PEERCRED
855 if (secure_in_use)
857 struct ucred caller;
858 socklen_t optlen = sizeof (caller);
860 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
862 dbg_log (_("error getting callers id: %s"),
863 strerror_r (errno, buf, sizeof (buf)));
864 goto close_and_out;
867 if (req.type < GETPWBYNAME || req.type > LASTDBREQ
868 || serv2db[req.type]->secure)
869 uid = caller.uid;
871 pid = caller.pid;
873 else if (__builtin_expect (debug_level > 0, 0))
875 struct ucred caller;
876 socklen_t optlen = sizeof (caller);
878 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) == 0)
879 pid = caller.pid;
881 #endif
883 /* It should not be possible to crash the nscd with a silly
884 request (i.e., a terribly large key). We limit the size to 1kb. */
885 if (__builtin_expect (req.key_len, 1) < 0
886 || __builtin_expect (req.key_len, 1) > 1024)
888 if (debug_level > 0)
889 dbg_log (_("key length in request too long: %d"), req.key_len);
891 else
893 /* Get the key. */
894 char keybuf[req.key_len];
896 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
897 req.key_len))
898 != req.key_len, 0))
900 if (debug_level > 0)
901 dbg_log (_("short read while reading request key: %s"),
902 strerror_r (errno, buf, sizeof (buf)));
903 close (fd);
904 continue;
907 if (__builtin_expect (debug_level, 0) > 0)
909 #ifdef SO_PEERCRED
910 if (pid != 0)
911 dbg_log (_("\
912 handle_request: request received (Version = %d) from PID %ld"),
913 req.version, (long int) pid);
914 else
915 #endif
916 dbg_log (_("\
917 handle_request: request received (Version = %d)"), req.version);
920 /* Phew, we got all the data, now process it. */
921 handle_request (fd, &req, keybuf, uid);
924 close_and_out:
925 /* We are done. */
926 close (fd);
928 /* Just determine whether any data is present. We do this to
929 measure whether clients are queued up. */
930 try_get:
931 nr = poll (&conn, 1, 0);
932 if (nr != 0)
934 if (nready == 0)
935 ++client_queued;
937 atomic_increment (&nready);
939 goto got_data;
945 /* Start all the threads we want. The initial process is thread no. 1. */
946 void
947 start_threads (void)
949 long int i;
950 pthread_attr_t attr;
951 pthread_t th;
953 pthread_attr_init (&attr);
954 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
956 /* We allow less than LASTDB threads only for debugging. */
957 if (debug_level == 0)
958 nthreads = MAX (nthreads, lastdb);
960 for (i = 1; i < nthreads; ++i)
961 pthread_create (&th, &attr, nscd_run, (void *) i);
963 pthread_attr_destroy (&attr);
965 nscd_run ((void *) 0);
969 /* Look up the uid, gid, and supplementary groups to run nscd as. When
970 this function is called, we are not listening on the nscd socket yet so
971 we can just use the ordinary lookup functions without causing a lockup */
972 static void
973 begin_drop_privileges (void)
975 struct passwd *pwd = getpwnam (server_user);
977 if (pwd == NULL)
979 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
980 error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"),
981 server_user);
984 server_uid = pwd->pw_uid;
985 server_gid = pwd->pw_gid;
987 if (getgrouplist (server_user, server_gid, NULL, &server_ngroups) == 0)
989 /* This really must never happen. */
990 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
991 error (EXIT_FAILURE, errno, _("initial getgrouplist failed"));
994 server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
996 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
997 == -1)
999 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1000 error (EXIT_FAILURE, errno, _("getgrouplist failed"));
1005 /* Call setgroups(), setgid(), and setuid() to drop root privileges and
1006 run nscd as the user specified in the configuration file. */
1007 static void
1008 finish_drop_privileges (void)
1010 if (setgroups (server_ngroups, server_groups) == -1)
1012 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1013 error (EXIT_FAILURE, errno, _("setgroups failed"));
1016 if (setgid (server_gid) == -1)
1018 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1019 perror ("setgid");
1020 exit (1);
1023 if (setuid (server_uid) == -1)
1025 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1026 perror ("setuid");
1027 exit (1);