* configure.in (--with-headers): Let argument contain a : separated
[glibc.git] / nscd / connections.c
blobfe33c76bcf31619006b108f3b9bcc20edc26e064
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",
87 [GETAI] = "GETAI"
90 /* The control data structures for the services. */
91 struct database_dyn dbs[lastdb] =
93 [pwddb] = {
94 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
95 .enabled = 0,
96 .check_file = 1,
97 .persistent = 0,
98 .shared = 0,
99 .filename = "/etc/passwd",
100 .db_filename = _PATH_NSCD_PASSWD_DB,
101 .disabled_iov = &pwd_iov_disabled,
102 .postimeout = 3600,
103 .negtimeout = 20,
104 .wr_fd = -1,
105 .ro_fd = -1,
106 .mmap_used = false
108 [grpdb] = {
109 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
110 .enabled = 0,
111 .check_file = 1,
112 .persistent = 0,
113 .shared = 0,
114 .filename = "/etc/group",
115 .db_filename = _PATH_NSCD_GROUP_DB,
116 .disabled_iov = &grp_iov_disabled,
117 .postimeout = 3600,
118 .negtimeout = 60,
119 .wr_fd = -1,
120 .ro_fd = -1,
121 .mmap_used = false
123 [hstdb] = {
124 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
125 .enabled = 0,
126 .check_file = 1,
127 .persistent = 0,
128 .shared = 0,
129 .filename = "/etc/hosts",
130 .db_filename = _PATH_NSCD_HOSTS_DB,
131 .disabled_iov = &hst_iov_disabled,
132 .postimeout = 3600,
133 .negtimeout = 20,
134 .wr_fd = -1,
135 .ro_fd = -1,
136 .mmap_used = false
141 /* Mapping of request type to database. */
142 static struct database_dyn *const serv2db[LASTREQ] =
144 [GETPWBYNAME] = &dbs[pwddb],
145 [GETPWBYUID] = &dbs[pwddb],
146 [GETGRBYNAME] = &dbs[grpdb],
147 [GETGRBYGID] = &dbs[grpdb],
148 [GETHOSTBYNAME] = &dbs[hstdb],
149 [GETHOSTBYNAMEv6] = &dbs[hstdb],
150 [GETHOSTBYADDR] = &dbs[hstdb],
151 [GETHOSTBYADDRv6] = &dbs[hstdb],
152 [GETFDPW] = &dbs[pwddb],
153 [GETFDGR] = &dbs[grpdb],
154 [GETFDHST] = &dbs[hstdb],
155 [GETAI] = &dbs[hstdb],
159 /* Number of seconds between two cache pruning runs. */
160 #define CACHE_PRUNE_INTERVAL 15
163 /* Number of threads to use. */
164 int nthreads = -1;
166 /* Socket for incoming connections. */
167 static int sock;
169 /* Number of times clients had to wait. */
170 unsigned long int client_queued;
173 /* Initialize database information structures. */
174 void
175 nscd_init (void)
177 struct sockaddr_un sock_addr;
178 size_t cnt;
180 /* Secure mode and unprivileged mode are incompatible */
181 if (server_user != NULL && secure_in_use)
183 dbg_log (_("Cannot run nscd in secure mode as unprivileged user"));
184 exit (1);
187 /* Look up unprivileged uid/gid/groups before we start listening on the
188 socket */
189 if (server_user != NULL)
190 begin_drop_privileges ();
192 if (nthreads == -1)
193 /* No configuration for this value, assume a default. */
194 nthreads = 2 * lastdb;
196 for (cnt = 0; cnt < lastdb; ++cnt)
197 if (dbs[cnt].enabled)
199 pthread_rwlock_init (&dbs[cnt].lock, NULL);
200 pthread_mutex_init (&dbs[cnt].memlock, NULL);
202 if (dbs[cnt].persistent)
204 /* Try to open the appropriate file on disk. */
205 int fd = open (dbs[cnt].db_filename, O_RDWR);
206 if (fd != -1)
208 struct stat64 st;
209 void *mem;
210 size_t total;
211 struct database_pers_head head;
212 ssize_t n = TEMP_FAILURE_RETRY (read (fd, &head,
213 sizeof (head)));
214 if (n != sizeof (head) || fstat64 (fd, &st) != 0)
216 fail_db:
217 dbg_log (_("invalid persistent database file \"%s\": %s"),
218 dbs[cnt].db_filename, strerror (errno));
219 dbs[cnt].persistent = 0;
221 else if (head.module == 0 && head.data_size == 0)
223 /* The file has been created, but the head has not been
224 initialized yet. Remove the old file. */
225 unlink (dbs[cnt].db_filename);
227 else if (head.header_size != (int) sizeof (head))
229 dbg_log (_("invalid persistent database file \"%s\": %s"),
230 dbs[cnt].db_filename,
231 _("header size does not match"));
232 dbs[cnt].persistent = 0;
234 else if ((total = (sizeof (head)
235 + roundup (head.module * sizeof (ref_t),
236 ALIGN)
237 + head.data_size))
238 > st.st_size)
240 dbg_log (_("invalid persistent database file \"%s\": %s"),
241 dbs[cnt].db_filename,
242 _("file size does not match"));
243 dbs[cnt].persistent = 0;
245 else if ((mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
246 MAP_SHARED, fd, 0)) == MAP_FAILED)
247 goto fail_db;
248 else
250 /* Success. We have the database. */
251 dbs[cnt].head = mem;
252 dbs[cnt].memsize = total;
253 dbs[cnt].data = (char *)
254 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
255 ALIGN / sizeof (ref_t))];
256 dbs[cnt].mmap_used = true;
258 if (dbs[cnt].suggested_module > head.module)
259 dbg_log (_("suggested size of table for database %s larger than the persistent database's table"),
260 dbnames[cnt]);
262 dbs[cnt].wr_fd = fd;
263 fd = -1;
264 /* We also need a read-only descriptor. */
265 if (dbs[cnt].shared)
267 dbs[cnt].ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
268 if (dbs[cnt].ro_fd == -1)
269 dbg_log (_("\
270 cannot create read-only descriptor for \"%s\"; no mmap"),
271 dbs[cnt].db_filename);
274 // XXX Shall we test whether the descriptors actually
275 // XXX point to the same file?
278 /* Close the file descriptors in case something went
279 wrong in which case the variable have not been
280 assigned -1. */
281 if (fd != -1)
282 close (fd);
286 if (dbs[cnt].head == NULL)
288 /* No database loaded. Allocate the data structure,
289 possibly on disk. */
290 struct database_pers_head head;
291 size_t total = (sizeof (head)
292 + roundup (dbs[cnt].suggested_module
293 * sizeof (ref_t), ALIGN)
294 + (dbs[cnt].suggested_module
295 * DEFAULT_DATASIZE_PER_BUCKET));
297 /* Try to create the database. If we do not need a
298 persistent database create a temporary file. */
299 int fd;
300 int ro_fd = -1;
301 if (dbs[cnt].persistent)
303 fd = open (dbs[cnt].db_filename,
304 O_RDWR | O_CREAT | O_EXCL | O_TRUNC,
305 S_IRUSR | S_IWUSR);
306 if (fd != -1 && dbs[cnt].shared)
307 ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
309 else
311 size_t slen = strlen (dbs[cnt].db_filename);
312 char fname[slen + 8];
313 strcpy (mempcpy (fname, dbs[cnt].db_filename, slen),
314 ".XXXXXX");
315 fd = mkstemp (fname);
317 /* We do not need the file name anymore after we
318 opened another file descriptor in read-only mode. */
319 if (fd != -1 && dbs[cnt].shared)
321 ro_fd = open (fname, O_RDONLY);
323 unlink (fname);
327 if (fd == -1)
329 if (errno == EEXIST)
331 dbg_log (_("database for %s corrupted or simultaneously used; remove %s manually if necessary and restart"),
332 dbnames[cnt], dbs[cnt].db_filename);
333 // XXX Correct way to terminate?
334 exit (1);
337 if (dbs[cnt].persistent)
338 dbg_log (_("cannot create %s; no persistent database used"),
339 dbs[cnt].db_filename);
340 else
341 dbg_log (_("cannot create %s; no sharing possible"),
342 dbs[cnt].db_filename);
344 dbs[cnt].persistent = 0;
345 // XXX remember: no mmap
347 else
349 /* Tell the user if we could not create the read-only
350 descriptor. */
351 if (ro_fd == -1 && dbs[cnt].shared)
352 dbg_log (_("\
353 cannot create read-only descriptor for \"%s\"; no mmap"),
354 dbs[cnt].db_filename);
356 /* Before we create the header, initialiye the hash
357 table. So that if we get interrupted if writing
358 the header we can recognize a partially initialized
359 database. */
360 size_t ps = sysconf (_SC_PAGESIZE);
361 char tmpbuf[ps];
362 assert (~ENDREF == 0);
363 memset (tmpbuf, '\xff', ps);
365 size_t remaining = dbs[cnt].suggested_module * sizeof (ref_t);
366 off_t offset = sizeof (head);
368 size_t towrite;
369 if (offset % ps != 0)
371 towrite = MIN (remaining, ps - (offset % ps));
372 pwrite (fd, tmpbuf, towrite, offset);
373 offset += towrite;
374 remaining -= towrite;
377 while (remaining > ps)
379 pwrite (fd, tmpbuf, ps, offset);
380 offset += ps;
381 remaining -= ps;
384 if (remaining > 0)
385 pwrite (fd, tmpbuf, remaining, offset);
387 /* Create the header of the file. */
388 struct database_pers_head head =
390 .version = DB_VERSION,
391 .header_size = sizeof (head),
392 .module = dbs[cnt].suggested_module,
393 .data_size = (dbs[cnt].suggested_module
394 * DEFAULT_DATASIZE_PER_BUCKET),
395 .first_free = 0
397 void *mem;
399 if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head)))
400 != sizeof (head))
401 || ftruncate (fd, total) != 0
402 || (mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
403 MAP_SHARED, fd, 0)) == MAP_FAILED)
405 unlink (dbs[cnt].db_filename);
406 dbg_log (_("cannot write to database file %s: %s"),
407 dbs[cnt].db_filename, strerror (errno));
408 dbs[cnt].persistent = 0;
410 else
412 /* Success. */
413 dbs[cnt].head = mem;
414 dbs[cnt].data = (char *)
415 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
416 ALIGN / sizeof (ref_t))];
417 dbs[cnt].memsize = total;
418 dbs[cnt].mmap_used = true;
420 /* Remember the descriptors. */
421 dbs[cnt].wr_fd = fd;
422 dbs[cnt].ro_fd = ro_fd;
423 fd = -1;
424 ro_fd = -1;
427 if (fd != -1)
428 close (fd);
429 if (ro_fd != -1)
430 close (ro_fd);
434 if (dbs[cnt].head == NULL)
436 /* We do not use the persistent database. Just
437 create an in-memory data structure. */
438 assert (! dbs[cnt].persistent);
440 dbs[cnt].head = xmalloc (sizeof (struct database_pers_head)
441 + (dbs[cnt].suggested_module
442 * sizeof (ref_t)));
443 memset (dbs[cnt].head, '\0', sizeof (dbs[cnt].head));
444 assert (~ENDREF == 0);
445 memset (dbs[cnt].head->array, '\xff',
446 dbs[cnt].suggested_module * sizeof (ref_t));
447 dbs[cnt].head->module = dbs[cnt].suggested_module;
448 dbs[cnt].head->data_size = (DEFAULT_DATASIZE_PER_BUCKET
449 * dbs[cnt].head->module);
450 dbs[cnt].data = xmalloc (dbs[cnt].head->data_size);
451 dbs[cnt].head->first_free = 0;
453 dbs[cnt].shared = 0;
454 assert (dbs[cnt].ro_fd == -1);
457 if (dbs[cnt].check_file)
459 /* We need the modification date of the file. */
460 struct stat st;
462 if (stat (dbs[cnt].filename, &st) < 0)
464 /* We cannot stat() the file, disable file checking. */
465 dbg_log (_("cannot stat() file `%s': %s"),
466 dbs[cnt].filename, strerror (errno));
467 dbs[cnt].check_file = 0;
469 else
470 dbs[cnt].file_mtime = st.st_mtime;
474 /* Create the socket. */
475 sock = socket (AF_UNIX, SOCK_STREAM, 0);
476 if (sock < 0)
478 dbg_log (_("cannot open socket: %s"), strerror (errno));
479 exit (1);
481 /* Bind a name to the socket. */
482 sock_addr.sun_family = AF_UNIX;
483 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
484 if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
486 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
487 exit (1);
490 /* We don't wait for data otherwise races between threads can get
491 them stuck on accept. */
492 int fl = fcntl (sock, F_GETFL);
493 if (fl != -1)
494 fcntl (sock, F_SETFL, fl | O_NONBLOCK);
496 /* Set permissions for the socket. */
497 chmod (_PATH_NSCDSOCKET, DEFFILEMODE);
499 /* Set the socket up to accept connections. */
500 if (listen (sock, SOMAXCONN) < 0)
502 dbg_log (_("cannot enable socket to accept connections: %s"),
503 strerror (errno));
504 exit (1);
507 /* Change to unprivileged uid/gid/groups if specifed in config file */
508 if (server_user != NULL)
509 finish_drop_privileges ();
513 /* Close the connections. */
514 void
515 close_sockets (void)
517 close (sock);
521 static void
522 invalidate_cache (char *key)
524 dbtype number;
526 if (strcmp (key, "passwd") == 0)
527 number = pwddb;
528 else if (strcmp (key, "group") == 0)
529 number = grpdb;
530 else if (__builtin_expect (strcmp (key, "hosts"), 0) == 0)
532 number = hstdb;
534 /* Re-initialize the resolver. resolv.conf might have changed. */
535 res_init ();
537 else
538 return;
540 if (dbs[number].enabled)
541 prune_cache (&dbs[number], LONG_MAX);
545 #ifdef SCM_RIGHTS
546 static void
547 send_ro_fd (struct database_dyn *db, char *key, int fd)
549 /* If we do not have an read-only file descriptor do nothing. */
550 if (db->ro_fd == -1)
551 return;
553 /* We need to send some data along with the descriptor. */
554 struct iovec iov[1];
555 iov[0].iov_base = key;
556 iov[0].iov_len = strlen (key) + 1;
558 /* Prepare the control message to transfer the descriptor. */
559 char buf[CMSG_SPACE (sizeof (int))];
560 struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
561 .msg_control = buf, .msg_controllen = sizeof (buf) };
562 struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
564 cmsg->cmsg_level = SOL_SOCKET;
565 cmsg->cmsg_type = SCM_RIGHTS;
566 cmsg->cmsg_len = CMSG_LEN (sizeof (int));
568 *(int *) CMSG_DATA (cmsg) = db->ro_fd;
570 msg.msg_controllen = cmsg->cmsg_len;
572 /* Send the control message. We repeat when we are interrupted but
573 everything else is ignored. */
574 (void) TEMP_FAILURE_RETRY (sendmsg (fd, &msg, 0));
576 if (__builtin_expect (debug_level > 0, 0))
577 dbg_log (_("provide access to FD %d, for %s"), db->ro_fd, key);
579 #endif /* SCM_RIGHTS */
582 /* Handle new request. */
583 static void
584 handle_request (int fd, request_header *req, void *key, uid_t uid)
586 if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
588 if (debug_level > 0)
589 dbg_log (_("\
590 cannot handle old request version %d; current version is %d"),
591 req->version, NSCD_VERSION);
592 return;
595 struct database_dyn *db = serv2db[req->type];
597 if ((__builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
598 && __builtin_expect (req->type, LASTDBREQ) <= LASTDBREQ)
599 || req->type == GETAI)
601 if (__builtin_expect (debug_level, 0) > 0)
603 if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
605 char buf[INET6_ADDRSTRLEN];
607 dbg_log ("\t%s (%s)", serv2str[req->type],
608 inet_ntop (req->type == GETHOSTBYADDR
609 ? AF_INET : AF_INET6,
610 key, buf, sizeof (buf)));
612 else
613 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
616 /* Is this service enabled? */
617 if (!db->enabled)
619 /* No, sent the prepared record. */
620 if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
621 db->disabled_iov->iov_len))
622 != (ssize_t) db->disabled_iov->iov_len
623 && __builtin_expect (debug_level, 0) > 0)
625 /* We have problems sending the result. */
626 char buf[256];
627 dbg_log (_("cannot write result: %s"),
628 strerror_r (errno, buf, sizeof (buf)));
631 return;
634 /* Be sure we can read the data. */
635 if (__builtin_expect (pthread_rwlock_tryrdlock (&db->lock) != 0, 0))
637 ++db->head->rdlockdelayed;
638 pthread_rwlock_rdlock (&db->lock);
641 /* See whether we can handle it from the cache. */
642 struct datahead *cached;
643 cached = (struct datahead *) cache_search (req->type, key, req->key_len,
644 db, uid);
645 if (cached != NULL)
647 /* Hurray it's in the cache. */
648 if (TEMP_FAILURE_RETRY (write (fd, cached->data, cached->recsize))
649 != cached->recsize
650 && __builtin_expect (debug_level, 0) > 0)
652 /* We have problems sending the result. */
653 char buf[256];
654 dbg_log (_("cannot write result: %s"),
655 strerror_r (errno, buf, sizeof (buf)));
658 pthread_rwlock_unlock (&db->lock);
660 return;
663 pthread_rwlock_unlock (&db->lock);
665 else if (__builtin_expect (debug_level, 0) > 0)
667 if (req->type == INVALIDATE)
668 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
669 else
670 dbg_log ("\t%s", serv2str[req->type]);
673 /* Handle the request. */
674 switch (req->type)
676 case GETPWBYNAME:
677 addpwbyname (db, fd, req, key, uid);
678 break;
680 case GETPWBYUID:
681 addpwbyuid (db, fd, req, key, uid);
682 break;
684 case GETGRBYNAME:
685 addgrbyname (db, fd, req, key, uid);
686 break;
688 case GETGRBYGID:
689 addgrbygid (db, fd, req, key, uid);
690 break;
692 case GETHOSTBYNAME:
693 addhstbyname (db, fd, req, key, uid);
694 break;
696 case GETHOSTBYNAMEv6:
697 addhstbynamev6 (db, fd, req, key, uid);
698 break;
700 case GETHOSTBYADDR:
701 addhstbyaddr (db, fd, req, key, uid);
702 break;
704 case GETHOSTBYADDRv6:
705 addhstbyaddrv6 (db, fd, req, key, uid);
706 break;
708 case GETAI:
709 addhstai (db, fd, req, key, uid);
710 break;
712 case GETSTAT:
713 case SHUTDOWN:
714 case INVALIDATE:
715 if (! secure_in_use)
717 /* Get the callers credentials. */
718 #ifdef SO_PEERCRED
719 struct ucred caller;
720 socklen_t optlen = sizeof (caller);
722 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
724 char buf[256];
726 dbg_log (_("error getting callers id: %s"),
727 strerror_r (errno, buf, sizeof (buf)));
728 break;
731 uid = caller.uid;
732 #else
733 /* Some systems have no SO_PEERCRED implementation. They don't
734 care about security so we don't as well. */
735 uid = 0;
736 #endif
739 /* Accept shutdown, getstat and invalidate only from root. For
740 the stat call also allow the user specified in the config file. */
741 if (req->type == GETSTAT)
743 if (uid == 0 || uid == stat_uid)
744 send_stats (fd, dbs);
746 else if (uid == 0)
748 if (req->type == INVALIDATE)
749 invalidate_cache (key);
750 else
751 termination_handler (0);
753 break;
755 case GETFDPW:
756 case GETFDGR:
757 case GETFDHST:
758 #ifdef SCM_RIGHTS
759 send_ro_fd (serv2db[req->type], key, fd);
760 #endif
761 break;
763 default:
764 /* Ignore the command, it's nothing we know. */
765 break;
770 /* This is the main loop. It is replicated in different threads but the
771 `poll' call makes sure only one thread handles an incoming connection. */
772 static void *
773 __attribute__ ((__noreturn__))
774 nscd_run (void *p)
776 long int my_number = (long int) p;
777 struct pollfd conn;
778 int run_prune = my_number < lastdb && dbs[my_number].enabled;
779 time_t next_prune = run_prune ? time (NULL) + CACHE_PRUNE_INTERVAL : 0;
780 static unsigned long int nready;
782 if (run_prune)
783 setup_thread (&dbs[my_number]);
785 conn.fd = sock;
786 conn.events = POLLRDNORM;
788 while (1)
790 int nr;
791 time_t now = 0;
793 /* One more thread available. */
794 atomic_increment (&nready);
796 no_conn:
799 int timeout = -1;
800 if (run_prune)
802 /* NB: we do not flush the timestamp update using msync since
803 this value doesnot matter on disk. */
804 dbs[my_number].head->timestamp = now = time (NULL);
805 timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
808 nr = poll (&conn, 1, timeout);
810 if (nr == 0)
812 /* The `poll' call timed out. It's time to clean up the
813 cache. */
814 atomic_decrement (&nready);
815 assert (my_number < lastdb);
816 prune_cache (&dbs[my_number], time(NULL));
817 now = time (NULL);
818 next_prune = now + CACHE_PRUNE_INTERVAL;
820 goto try_get;
823 while ((conn.revents & POLLRDNORM) == 0);
825 got_data:;
826 /* We have a new incoming connection. Accept the connection. */
827 int fd = TEMP_FAILURE_RETRY (accept (conn.fd, NULL, NULL));
828 request_header req;
829 char buf[256];
830 uid_t uid = -1;
831 #ifdef SO_PEERCRED
832 pid_t pid = 0;
833 #endif
835 if (__builtin_expect (fd, 0) < 0)
837 if (errno != EAGAIN && errno != EWOULDBLOCK)
838 dbg_log (_("while accepting connection: %s"),
839 strerror_r (errno, buf, sizeof (buf)));
840 goto no_conn;
843 /* This thread is busy. */
844 atomic_decrement (&nready);
846 /* Now read the request. */
847 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
848 != sizeof (req), 0))
850 if (debug_level > 0)
851 dbg_log (_("short read while reading request: %s"),
852 strerror_r (errno, buf, sizeof (buf)));
853 close (fd);
854 continue;
857 /* Check whether this is a valid request type. */
858 if (req.type < GETPWBYNAME || req.type >= LASTREQ)
859 goto close_and_out;
861 /* Some systems have no SO_PEERCRED implementation. They don't
862 care about security so we don't as well. */
863 #ifdef SO_PEERCRED
864 if (secure_in_use)
866 struct ucred caller;
867 socklen_t optlen = sizeof (caller);
869 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
871 dbg_log (_("error getting callers id: %s"),
872 strerror_r (errno, buf, sizeof (buf)));
873 goto close_and_out;
876 if (req.type < GETPWBYNAME || req.type > LASTDBREQ
877 || serv2db[req.type]->secure)
878 uid = caller.uid;
880 pid = caller.pid;
882 else if (__builtin_expect (debug_level > 0, 0))
884 struct ucred caller;
885 socklen_t optlen = sizeof (caller);
887 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) == 0)
888 pid = caller.pid;
890 #endif
892 /* It should not be possible to crash the nscd with a silly
893 request (i.e., a terribly large key). We limit the size to 1kb. */
894 if (__builtin_expect (req.key_len, 1) < 0
895 || __builtin_expect (req.key_len, 1) > 1024)
897 if (debug_level > 0)
898 dbg_log (_("key length in request too long: %d"), req.key_len);
900 else
902 /* Get the key. */
903 char keybuf[req.key_len];
905 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
906 req.key_len))
907 != req.key_len, 0))
909 if (debug_level > 0)
910 dbg_log (_("short read while reading request key: %s"),
911 strerror_r (errno, buf, sizeof (buf)));
912 close (fd);
913 continue;
916 if (__builtin_expect (debug_level, 0) > 0)
918 #ifdef SO_PEERCRED
919 if (pid != 0)
920 dbg_log (_("\
921 handle_request: request received (Version = %d) from PID %ld"),
922 req.version, (long int) pid);
923 else
924 #endif
925 dbg_log (_("\
926 handle_request: request received (Version = %d)"), req.version);
929 /* Phew, we got all the data, now process it. */
930 handle_request (fd, &req, keybuf, uid);
933 close_and_out:
934 /* We are done. */
935 close (fd);
937 /* Just determine whether any data is present. We do this to
938 measure whether clients are queued up. */
939 try_get:
940 nr = poll (&conn, 1, 0);
941 if (nr != 0)
943 if (nready == 0)
944 ++client_queued;
946 atomic_increment (&nready);
948 goto got_data;
954 /* Start all the threads we want. The initial process is thread no. 1. */
955 void
956 start_threads (void)
958 long int i;
959 pthread_attr_t attr;
960 pthread_t th;
962 pthread_attr_init (&attr);
963 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
965 /* We allow less than LASTDB threads only for debugging. */
966 if (debug_level == 0)
967 nthreads = MAX (nthreads, lastdb);
969 for (i = 1; i < nthreads; ++i)
970 pthread_create (&th, &attr, nscd_run, (void *) i);
972 pthread_attr_destroy (&attr);
974 nscd_run ((void *) 0);
978 /* Look up the uid, gid, and supplementary groups to run nscd as. When
979 this function is called, we are not listening on the nscd socket yet so
980 we can just use the ordinary lookup functions without causing a lockup */
981 static void
982 begin_drop_privileges (void)
984 struct passwd *pwd = getpwnam (server_user);
986 if (pwd == NULL)
988 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
989 error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"),
990 server_user);
993 server_uid = pwd->pw_uid;
994 server_gid = pwd->pw_gid;
996 if (getgrouplist (server_user, server_gid, NULL, &server_ngroups) == 0)
998 /* This really must never happen. */
999 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1000 error (EXIT_FAILURE, errno, _("initial getgrouplist failed"));
1003 server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
1005 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
1006 == -1)
1008 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1009 error (EXIT_FAILURE, errno, _("getgrouplist failed"));
1014 /* Call setgroups(), setgid(), and setuid() to drop root privileges and
1015 run nscd as the user specified in the configuration file. */
1016 static void
1017 finish_drop_privileges (void)
1019 if (setgroups (server_ngroups, server_groups) == -1)
1021 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1022 error (EXIT_FAILURE, errno, _("setgroups failed"));
1025 if (setgid (server_gid) == -1)
1027 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1028 perror ("setgid");
1029 exit (1);
1032 if (setuid (server_uid) == -1)
1034 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1035 perror ("setuid");
1036 exit (1);