Changes and additions migrated from cvs.devel.redhat.com:/cvs/devel/glibc to fedora...
[glibc.git] / nscd / connections.c
blobfe65b661d7edabde76a7342630a4f296f3416d33
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"
44 #include "selinux.h"
47 /* Number of bytes of data we initially reserve for each hash table bucket. */
48 #define DEFAULT_DATASIZE_PER_BUCKET 1024
51 /* Wrapper functions with error checking for standard functions. */
52 extern void *xmalloc (size_t n);
53 extern void *xcalloc (size_t n, size_t s);
54 extern void *xrealloc (void *o, size_t n);
56 /* Support to run nscd as an unprivileged user */
57 const char *server_user;
58 static uid_t server_uid;
59 static gid_t server_gid;
60 const char *stat_user;
61 uid_t stat_uid;
62 static gid_t *server_groups;
63 #ifndef NGROUPS
64 # define NGROUPS 32
65 #endif
66 static int server_ngroups;
68 static void begin_drop_privileges (void);
69 static void finish_drop_privileges (void);
71 /* Map request type to a string. */
72 const char *serv2str[LASTREQ] =
74 [GETPWBYNAME] = "GETPWBYNAME",
75 [GETPWBYUID] = "GETPWBYUID",
76 [GETGRBYNAME] = "GETGRBYNAME",
77 [GETGRBYGID] = "GETGRBYGID",
78 [GETHOSTBYNAME] = "GETHOSTBYNAME",
79 [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6",
80 [GETHOSTBYADDR] = "GETHOSTBYADDR",
81 [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
82 [SHUTDOWN] = "SHUTDOWN",
83 [GETSTAT] = "GETSTAT",
84 [INVALIDATE] = "INVALIDATE",
85 [GETFDPW] = "GETFDPW",
86 [GETFDGR] = "GETFDGR",
87 [GETFDHST] = "GETFDHST",
88 [GETAI] = "GETAI"
91 /* The control data structures for the services. */
92 struct database_dyn dbs[lastdb] =
94 [pwddb] = {
95 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
96 .enabled = 0,
97 .check_file = 1,
98 .persistent = 0,
99 .shared = 0,
100 .filename = "/etc/passwd",
101 .db_filename = _PATH_NSCD_PASSWD_DB,
102 .disabled_iov = &pwd_iov_disabled,
103 .postimeout = 3600,
104 .negtimeout = 20,
105 .wr_fd = -1,
106 .ro_fd = -1,
107 .mmap_used = false
109 [grpdb] = {
110 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
111 .enabled = 0,
112 .check_file = 1,
113 .persistent = 0,
114 .shared = 0,
115 .filename = "/etc/group",
116 .db_filename = _PATH_NSCD_GROUP_DB,
117 .disabled_iov = &grp_iov_disabled,
118 .postimeout = 3600,
119 .negtimeout = 60,
120 .wr_fd = -1,
121 .ro_fd = -1,
122 .mmap_used = false
124 [hstdb] = {
125 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
126 .enabled = 0,
127 .check_file = 1,
128 .persistent = 0,
129 .shared = 0,
130 .filename = "/etc/hosts",
131 .db_filename = _PATH_NSCD_HOSTS_DB,
132 .disabled_iov = &hst_iov_disabled,
133 .postimeout = 3600,
134 .negtimeout = 20,
135 .wr_fd = -1,
136 .ro_fd = -1,
137 .mmap_used = false
142 /* Mapping of request type to database. */
143 static struct database_dyn *const serv2db[LASTREQ] =
145 [GETPWBYNAME] = &dbs[pwddb],
146 [GETPWBYUID] = &dbs[pwddb],
147 [GETGRBYNAME] = &dbs[grpdb],
148 [GETGRBYGID] = &dbs[grpdb],
149 [GETHOSTBYNAME] = &dbs[hstdb],
150 [GETHOSTBYNAMEv6] = &dbs[hstdb],
151 [GETHOSTBYADDR] = &dbs[hstdb],
152 [GETHOSTBYADDRv6] = &dbs[hstdb],
153 [GETFDPW] = &dbs[pwddb],
154 [GETFDGR] = &dbs[grpdb],
155 [GETFDHST] = &dbs[hstdb],
156 [GETAI] = &dbs[hstdb],
160 /* Number of seconds between two cache pruning runs. */
161 #define CACHE_PRUNE_INTERVAL 15
164 /* Number of threads to use. */
165 int nthreads = -1;
167 /* Socket for incoming connections. */
168 static int sock;
170 /* Number of times clients had to wait. */
171 unsigned long int client_queued;
174 /* Initialize database information structures. */
175 void
176 nscd_init (void)
178 struct sockaddr_un sock_addr;
179 size_t cnt;
181 /* Secure mode and unprivileged mode are incompatible */
182 if (server_user != NULL && secure_in_use)
184 dbg_log (_("Cannot run nscd in secure mode as unprivileged user"));
185 exit (1);
188 /* Look up unprivileged uid/gid/groups before we start listening on the
189 socket */
190 if (server_user != NULL)
191 begin_drop_privileges ();
193 if (nthreads == -1)
194 /* No configuration for this value, assume a default. */
195 nthreads = 2 * lastdb;
197 for (cnt = 0; cnt < lastdb; ++cnt)
198 if (dbs[cnt].enabled)
200 pthread_rwlock_init (&dbs[cnt].lock, NULL);
201 pthread_mutex_init (&dbs[cnt].memlock, NULL);
203 if (dbs[cnt].persistent)
205 /* Try to open the appropriate file on disk. */
206 int fd = open (dbs[cnt].db_filename, O_RDWR);
207 if (fd != -1)
209 struct stat64 st;
210 void *mem;
211 size_t total;
212 struct database_pers_head head;
213 ssize_t n = TEMP_FAILURE_RETRY (read (fd, &head,
214 sizeof (head)));
215 if (n != sizeof (head) || fstat64 (fd, &st) != 0)
217 fail_db:
218 dbg_log (_("invalid persistent database file \"%s\": %s"),
219 dbs[cnt].db_filename, strerror (errno));
220 dbs[cnt].persistent = 0;
222 else if (head.module == 0 && head.data_size == 0)
224 /* The file has been created, but the head has not been
225 initialized yet. Remove the old file. */
226 unlink (dbs[cnt].db_filename);
228 else if (head.header_size != (int) sizeof (head))
230 dbg_log (_("invalid persistent database file \"%s\": %s"),
231 dbs[cnt].db_filename,
232 _("header size does not match"));
233 dbs[cnt].persistent = 0;
235 else if ((total = (sizeof (head)
236 + roundup (head.module * sizeof (ref_t),
237 ALIGN)
238 + head.data_size))
239 > st.st_size)
241 dbg_log (_("invalid persistent database file \"%s\": %s"),
242 dbs[cnt].db_filename,
243 _("file size does not match"));
244 dbs[cnt].persistent = 0;
246 else if ((mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
247 MAP_SHARED, fd, 0)) == MAP_FAILED)
248 goto fail_db;
249 else
251 /* Success. We have the database. */
252 dbs[cnt].head = mem;
253 dbs[cnt].memsize = total;
254 dbs[cnt].data = (char *)
255 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
256 ALIGN / sizeof (ref_t))];
257 dbs[cnt].mmap_used = true;
259 if (dbs[cnt].suggested_module > head.module)
260 dbg_log (_("suggested size of table for database %s larger than the persistent database's table"),
261 dbnames[cnt]);
263 dbs[cnt].wr_fd = fd;
264 fd = -1;
265 /* We also need a read-only descriptor. */
266 if (dbs[cnt].shared)
268 dbs[cnt].ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
269 if (dbs[cnt].ro_fd == -1)
270 dbg_log (_("\
271 cannot create read-only descriptor for \"%s\"; no mmap"),
272 dbs[cnt].db_filename);
275 // XXX Shall we test whether the descriptors actually
276 // XXX point to the same file?
279 /* Close the file descriptors in case something went
280 wrong in which case the variable have not been
281 assigned -1. */
282 if (fd != -1)
283 close (fd);
287 if (dbs[cnt].head == NULL)
289 /* No database loaded. Allocate the data structure,
290 possibly on disk. */
291 struct database_pers_head head;
292 size_t total = (sizeof (head)
293 + roundup (dbs[cnt].suggested_module
294 * sizeof (ref_t), ALIGN)
295 + (dbs[cnt].suggested_module
296 * DEFAULT_DATASIZE_PER_BUCKET));
298 /* Try to create the database. If we do not need a
299 persistent database create a temporary file. */
300 int fd;
301 int ro_fd = -1;
302 if (dbs[cnt].persistent)
304 fd = open (dbs[cnt].db_filename,
305 O_RDWR | O_CREAT | O_EXCL | O_TRUNC,
306 S_IRUSR | S_IWUSR);
307 if (fd != -1 && dbs[cnt].shared)
308 ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
310 else
312 size_t slen = strlen (dbs[cnt].db_filename);
313 char fname[slen + 8];
314 strcpy (mempcpy (fname, dbs[cnt].db_filename, slen),
315 ".XXXXXX");
316 fd = mkstemp (fname);
318 /* We do not need the file name anymore after we
319 opened another file descriptor in read-only mode. */
320 if (fd != -1 && dbs[cnt].shared)
322 ro_fd = open (fname, O_RDONLY);
324 unlink (fname);
328 if (fd == -1)
330 if (errno == EEXIST)
332 dbg_log (_("database for %s corrupted or simultaneously used; remove %s manually if necessary and restart"),
333 dbnames[cnt], dbs[cnt].db_filename);
334 // XXX Correct way to terminate?
335 exit (1);
338 if (dbs[cnt].persistent)
339 dbg_log (_("cannot create %s; no persistent database used"),
340 dbs[cnt].db_filename);
341 else
342 dbg_log (_("cannot create %s; no sharing possible"),
343 dbs[cnt].db_filename);
345 dbs[cnt].persistent = 0;
346 // XXX remember: no mmap
348 else
350 /* Tell the user if we could not create the read-only
351 descriptor. */
352 if (ro_fd == -1 && dbs[cnt].shared)
353 dbg_log (_("\
354 cannot create read-only descriptor for \"%s\"; no mmap"),
355 dbs[cnt].db_filename);
357 /* Before we create the header, initialiye the hash
358 table. So that if we get interrupted if writing
359 the header we can recognize a partially initialized
360 database. */
361 size_t ps = sysconf (_SC_PAGESIZE);
362 char tmpbuf[ps];
363 assert (~ENDREF == 0);
364 memset (tmpbuf, '\xff', ps);
366 size_t remaining = dbs[cnt].suggested_module * sizeof (ref_t);
367 off_t offset = sizeof (head);
369 size_t towrite;
370 if (offset % ps != 0)
372 towrite = MIN (remaining, ps - (offset % ps));
373 pwrite (fd, tmpbuf, towrite, offset);
374 offset += towrite;
375 remaining -= towrite;
378 while (remaining > ps)
380 pwrite (fd, tmpbuf, ps, offset);
381 offset += ps;
382 remaining -= ps;
385 if (remaining > 0)
386 pwrite (fd, tmpbuf, remaining, offset);
388 /* Create the header of the file. */
389 struct database_pers_head head =
391 .version = DB_VERSION,
392 .header_size = sizeof (head),
393 .module = dbs[cnt].suggested_module,
394 .data_size = (dbs[cnt].suggested_module
395 * DEFAULT_DATASIZE_PER_BUCKET),
396 .first_free = 0
398 void *mem;
400 if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head)))
401 != sizeof (head))
402 || ftruncate (fd, total) != 0
403 || (mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
404 MAP_SHARED, fd, 0)) == MAP_FAILED)
406 unlink (dbs[cnt].db_filename);
407 dbg_log (_("cannot write to database file %s: %s"),
408 dbs[cnt].db_filename, strerror (errno));
409 dbs[cnt].persistent = 0;
411 else
413 /* Success. */
414 dbs[cnt].head = mem;
415 dbs[cnt].data = (char *)
416 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
417 ALIGN / sizeof (ref_t))];
418 dbs[cnt].memsize = total;
419 dbs[cnt].mmap_used = true;
421 /* Remember the descriptors. */
422 dbs[cnt].wr_fd = fd;
423 dbs[cnt].ro_fd = ro_fd;
424 fd = -1;
425 ro_fd = -1;
428 if (fd != -1)
429 close (fd);
430 if (ro_fd != -1)
431 close (ro_fd);
435 if (dbs[cnt].head == NULL)
437 /* We do not use the persistent database. Just
438 create an in-memory data structure. */
439 assert (! dbs[cnt].persistent);
441 dbs[cnt].head = xmalloc (sizeof (struct database_pers_head)
442 + (dbs[cnt].suggested_module
443 * sizeof (ref_t)));
444 memset (dbs[cnt].head, '\0', sizeof (dbs[cnt].head));
445 assert (~ENDREF == 0);
446 memset (dbs[cnt].head->array, '\xff',
447 dbs[cnt].suggested_module * sizeof (ref_t));
448 dbs[cnt].head->module = dbs[cnt].suggested_module;
449 dbs[cnt].head->data_size = (DEFAULT_DATASIZE_PER_BUCKET
450 * dbs[cnt].head->module);
451 dbs[cnt].data = xmalloc (dbs[cnt].head->data_size);
452 dbs[cnt].head->first_free = 0;
454 dbs[cnt].shared = 0;
455 assert (dbs[cnt].ro_fd == -1);
458 if (dbs[cnt].check_file)
460 /* We need the modification date of the file. */
461 struct stat st;
463 if (stat (dbs[cnt].filename, &st) < 0)
465 /* We cannot stat() the file, disable file checking. */
466 dbg_log (_("cannot stat() file `%s': %s"),
467 dbs[cnt].filename, strerror (errno));
468 dbs[cnt].check_file = 0;
470 else
471 dbs[cnt].file_mtime = st.st_mtime;
475 /* Create the socket. */
476 sock = socket (AF_UNIX, SOCK_STREAM, 0);
477 if (sock < 0)
479 dbg_log (_("cannot open socket: %s"), strerror (errno));
480 exit (1);
482 /* Bind a name to the socket. */
483 sock_addr.sun_family = AF_UNIX;
484 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
485 if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
487 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
488 exit (1);
491 /* We don't wait for data otherwise races between threads can get
492 them stuck on accept. */
493 int fl = fcntl (sock, F_GETFL);
494 if (fl != -1)
495 fcntl (sock, F_SETFL, fl | O_NONBLOCK);
497 /* Set permissions for the socket. */
498 chmod (_PATH_NSCDSOCKET, DEFFILEMODE);
500 /* Set the socket up to accept connections. */
501 if (listen (sock, SOMAXCONN) < 0)
503 dbg_log (_("cannot enable socket to accept connections: %s"),
504 strerror (errno));
505 exit (1);
508 /* Change to unprivileged uid/gid/groups if specifed in config file */
509 if (server_user != NULL)
510 finish_drop_privileges ();
514 /* Close the connections. */
515 void
516 close_sockets (void)
518 close (sock);
522 static void
523 invalidate_cache (char *key)
525 dbtype number;
527 if (strcmp (key, "passwd") == 0)
528 number = pwddb;
529 else if (strcmp (key, "group") == 0)
530 number = grpdb;
531 else if (__builtin_expect (strcmp (key, "hosts"), 0) == 0)
533 number = hstdb;
535 /* Re-initialize the resolver. resolv.conf might have changed. */
536 res_init ();
538 else
539 return;
541 if (dbs[number].enabled)
542 prune_cache (&dbs[number], LONG_MAX);
546 #ifdef SCM_RIGHTS
547 static void
548 send_ro_fd (struct database_dyn *db, char *key, int fd)
550 /* If we do not have an read-only file descriptor do nothing. */
551 if (db->ro_fd == -1)
552 return;
554 /* We need to send some data along with the descriptor. */
555 struct iovec iov[1];
556 iov[0].iov_base = key;
557 iov[0].iov_len = strlen (key) + 1;
559 /* Prepare the control message to transfer the descriptor. */
560 char buf[CMSG_SPACE (sizeof (int))];
561 struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
562 .msg_control = buf, .msg_controllen = sizeof (buf) };
563 struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
565 cmsg->cmsg_level = SOL_SOCKET;
566 cmsg->cmsg_type = SCM_RIGHTS;
567 cmsg->cmsg_len = CMSG_LEN (sizeof (int));
569 *(int *) CMSG_DATA (cmsg) = db->ro_fd;
571 msg.msg_controllen = cmsg->cmsg_len;
573 /* Send the control message. We repeat when we are interrupted but
574 everything else is ignored. */
575 (void) TEMP_FAILURE_RETRY (sendmsg (fd, &msg, 0));
577 if (__builtin_expect (debug_level > 0, 0))
578 dbg_log (_("provide access to FD %d, for %s"), db->ro_fd, key);
580 #endif /* SCM_RIGHTS */
583 /* Handle new request. */
584 static void
585 handle_request (int fd, request_header *req, void *key, uid_t uid)
587 if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
589 if (debug_level > 0)
590 dbg_log (_("\
591 cannot handle old request version %d; current version is %d"),
592 req->version, NSCD_VERSION);
593 return;
596 /* Make the SELinux check before we go on to the standard checks. We
597 need to verify that the request type is valid, since it has not
598 yet been checked at this point. */
599 if (selinux_enabled
600 && __builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
601 && __builtin_expect (req->type, LASTREQ) < LASTREQ
602 && nscd_request_avc_has_perm (fd, req->type) != 0)
603 return;
605 struct database_dyn *db = serv2db[req->type];
607 if ((__builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
608 && __builtin_expect (req->type, LASTDBREQ) <= LASTDBREQ)
609 || req->type == GETAI)
611 if (__builtin_expect (debug_level, 0) > 0)
613 if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
615 char buf[INET6_ADDRSTRLEN];
617 dbg_log ("\t%s (%s)", serv2str[req->type],
618 inet_ntop (req->type == GETHOSTBYADDR
619 ? AF_INET : AF_INET6,
620 key, buf, sizeof (buf)));
622 else
623 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
626 /* Is this service enabled? */
627 if (!db->enabled)
629 /* No, sent the prepared record. */
630 if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
631 db->disabled_iov->iov_len))
632 != (ssize_t) db->disabled_iov->iov_len
633 && __builtin_expect (debug_level, 0) > 0)
635 /* We have problems sending the result. */
636 char buf[256];
637 dbg_log (_("cannot write result: %s"),
638 strerror_r (errno, buf, sizeof (buf)));
641 return;
644 /* Be sure we can read the data. */
645 if (__builtin_expect (pthread_rwlock_tryrdlock (&db->lock) != 0, 0))
647 ++db->head->rdlockdelayed;
648 pthread_rwlock_rdlock (&db->lock);
651 /* See whether we can handle it from the cache. */
652 struct datahead *cached;
653 cached = (struct datahead *) cache_search (req->type, key, req->key_len,
654 db, uid);
655 if (cached != NULL)
657 /* Hurray it's in the cache. */
658 if (TEMP_FAILURE_RETRY (write (fd, cached->data, cached->recsize))
659 != cached->recsize
660 && __builtin_expect (debug_level, 0) > 0)
662 /* We have problems sending the result. */
663 char buf[256];
664 dbg_log (_("cannot write result: %s"),
665 strerror_r (errno, buf, sizeof (buf)));
668 pthread_rwlock_unlock (&db->lock);
670 return;
673 pthread_rwlock_unlock (&db->lock);
675 else if (__builtin_expect (debug_level, 0) > 0)
677 if (req->type == INVALIDATE)
678 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
679 else
680 dbg_log ("\t%s", serv2str[req->type]);
683 /* Handle the request. */
684 switch (req->type)
686 case GETPWBYNAME:
687 addpwbyname (db, fd, req, key, uid);
688 break;
690 case GETPWBYUID:
691 addpwbyuid (db, fd, req, key, uid);
692 break;
694 case GETGRBYNAME:
695 addgrbyname (db, fd, req, key, uid);
696 break;
698 case GETGRBYGID:
699 addgrbygid (db, fd, req, key, uid);
700 break;
702 case GETHOSTBYNAME:
703 addhstbyname (db, fd, req, key, uid);
704 break;
706 case GETHOSTBYNAMEv6:
707 addhstbynamev6 (db, fd, req, key, uid);
708 break;
710 case GETHOSTBYADDR:
711 addhstbyaddr (db, fd, req, key, uid);
712 break;
714 case GETHOSTBYADDRv6:
715 addhstbyaddrv6 (db, fd, req, key, uid);
716 break;
718 case GETAI:
719 addhstai (db, fd, req, key, uid);
720 break;
722 case GETSTAT:
723 case SHUTDOWN:
724 case INVALIDATE:
725 if (! secure_in_use)
727 /* Get the callers credentials. */
728 #ifdef SO_PEERCRED
729 struct ucred caller;
730 socklen_t optlen = sizeof (caller);
732 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
734 char buf[256];
736 dbg_log (_("error getting callers id: %s"),
737 strerror_r (errno, buf, sizeof (buf)));
738 break;
741 uid = caller.uid;
742 #else
743 /* Some systems have no SO_PEERCRED implementation. They don't
744 care about security so we don't as well. */
745 uid = 0;
746 #endif
749 /* Accept shutdown, getstat and invalidate only from root. For
750 the stat call also allow the user specified in the config file. */
751 if (req->type == GETSTAT)
753 if (uid == 0 || uid == stat_uid)
754 send_stats (fd, dbs);
756 else if (uid == 0)
758 if (req->type == INVALIDATE)
759 invalidate_cache (key);
760 else
761 termination_handler (0);
763 break;
765 case GETFDPW:
766 case GETFDGR:
767 case GETFDHST:
768 #ifdef SCM_RIGHTS
769 send_ro_fd (serv2db[req->type], key, fd);
770 #endif
771 break;
773 default:
774 /* Ignore the command, it's nothing we know. */
775 break;
780 /* This is the main loop. It is replicated in different threads but the
781 `poll' call makes sure only one thread handles an incoming connection. */
782 static void *
783 __attribute__ ((__noreturn__))
784 nscd_run (void *p)
786 long int my_number = (long int) p;
787 struct pollfd conn;
788 int run_prune = my_number < lastdb && dbs[my_number].enabled;
789 time_t next_prune = run_prune ? time (NULL) + CACHE_PRUNE_INTERVAL : 0;
790 static unsigned long int nready;
792 if (run_prune)
793 setup_thread (&dbs[my_number]);
795 conn.fd = sock;
796 conn.events = POLLRDNORM;
798 while (1)
800 int nr;
801 time_t now = 0;
803 /* One more thread available. */
804 atomic_increment (&nready);
806 no_conn:
809 int timeout = -1;
810 if (run_prune)
812 /* NB: we do not flush the timestamp update using msync since
813 this value doesnot matter on disk. */
814 dbs[my_number].head->timestamp = now = time (NULL);
815 timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
818 nr = poll (&conn, 1, timeout);
820 if (nr == 0)
822 /* The `poll' call timed out. It's time to clean up the
823 cache. */
824 atomic_decrement (&nready);
825 assert (my_number < lastdb);
826 prune_cache (&dbs[my_number], time(NULL));
827 now = time (NULL);
828 next_prune = now + CACHE_PRUNE_INTERVAL;
830 goto try_get;
833 while ((conn.revents & POLLRDNORM) == 0);
835 got_data:;
836 /* We have a new incoming connection. Accept the connection. */
837 int fd = TEMP_FAILURE_RETRY (accept (conn.fd, NULL, NULL));
838 request_header req;
839 char buf[256];
840 uid_t uid = -1;
841 #ifdef SO_PEERCRED
842 pid_t pid = 0;
843 #endif
845 if (__builtin_expect (fd, 0) < 0)
847 if (errno != EAGAIN && errno != EWOULDBLOCK)
848 dbg_log (_("while accepting connection: %s"),
849 strerror_r (errno, buf, sizeof (buf)));
850 goto no_conn;
853 /* This thread is busy. */
854 atomic_decrement (&nready);
856 /* Now read the request. */
857 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
858 != sizeof (req), 0))
860 if (debug_level > 0)
861 dbg_log (_("short read while reading request: %s"),
862 strerror_r (errno, buf, sizeof (buf)));
863 close (fd);
864 continue;
867 /* Check whether this is a valid request type. */
868 if (req.type < GETPWBYNAME || req.type >= LASTREQ)
869 goto close_and_out;
871 /* Some systems have no SO_PEERCRED implementation. They don't
872 care about security so we don't as well. */
873 #ifdef SO_PEERCRED
874 if (secure_in_use)
876 struct ucred caller;
877 socklen_t optlen = sizeof (caller);
879 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
881 dbg_log (_("error getting callers id: %s"),
882 strerror_r (errno, buf, sizeof (buf)));
883 goto close_and_out;
886 if (req.type < GETPWBYNAME || req.type > LASTDBREQ
887 || serv2db[req.type]->secure)
888 uid = caller.uid;
890 pid = caller.pid;
892 else if (__builtin_expect (debug_level > 0, 0))
894 struct ucred caller;
895 socklen_t optlen = sizeof (caller);
897 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) == 0)
898 pid = caller.pid;
900 #endif
902 /* It should not be possible to crash the nscd with a silly
903 request (i.e., a terribly large key). We limit the size to 1kb. */
904 if (__builtin_expect (req.key_len, 1) < 0
905 || __builtin_expect (req.key_len, 1) > 1024)
907 if (debug_level > 0)
908 dbg_log (_("key length in request too long: %d"), req.key_len);
910 else
912 /* Get the key. */
913 char keybuf[req.key_len];
915 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
916 req.key_len))
917 != req.key_len, 0))
919 if (debug_level > 0)
920 dbg_log (_("short read while reading request key: %s"),
921 strerror_r (errno, buf, sizeof (buf)));
922 close (fd);
923 continue;
926 if (__builtin_expect (debug_level, 0) > 0)
928 #ifdef SO_PEERCRED
929 if (pid != 0)
930 dbg_log (_("\
931 handle_request: request received (Version = %d) from PID %ld"),
932 req.version, (long int) pid);
933 else
934 #endif
935 dbg_log (_("\
936 handle_request: request received (Version = %d)"), req.version);
939 /* Phew, we got all the data, now process it. */
940 handle_request (fd, &req, keybuf, uid);
943 close_and_out:
944 /* We are done. */
945 close (fd);
947 /* Just determine whether any data is present. We do this to
948 measure whether clients are queued up. */
949 try_get:
950 nr = poll (&conn, 1, 0);
951 if (nr != 0)
953 if (nready == 0)
954 ++client_queued;
956 atomic_increment (&nready);
958 goto got_data;
964 /* Start all the threads we want. The initial process is thread no. 1. */
965 void
966 start_threads (void)
968 long int i;
969 pthread_attr_t attr;
970 pthread_t th;
972 pthread_attr_init (&attr);
973 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
975 /* We allow less than LASTDB threads only for debugging. */
976 if (debug_level == 0)
977 nthreads = MAX (nthreads, lastdb);
979 for (i = 1; i < nthreads; ++i)
980 pthread_create (&th, &attr, nscd_run, (void *) i);
982 pthread_attr_destroy (&attr);
984 nscd_run ((void *) 0);
987 /* Look up the uid, gid, and supplementary groups to run nscd as. When
988 this function is called, we are not listening on the nscd socket yet so
989 we can just use the ordinary lookup functions without causing a lockup */
990 static void
991 begin_drop_privileges (void)
993 struct passwd *pwd = getpwnam (server_user);
995 if (pwd == NULL)
997 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
998 error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"),
999 server_user);
1002 server_uid = pwd->pw_uid;
1003 server_gid = pwd->pw_gid;
1005 if (getgrouplist (server_user, server_gid, NULL, &server_ngroups) == 0)
1007 /* This really must never happen. */
1008 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1009 error (EXIT_FAILURE, errno, _("initial getgrouplist failed"));
1012 server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
1014 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
1015 == -1)
1017 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1018 error (EXIT_FAILURE, errno, _("getgrouplist failed"));
1023 /* Call setgroups(), setgid(), and setuid() to drop root privileges and
1024 run nscd as the user specified in the configuration file. */
1025 static void
1026 finish_drop_privileges (void)
1028 if (setgroups (server_ngroups, server_groups) == -1)
1030 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1031 error (EXIT_FAILURE, errno, _("setgroups failed"));
1034 if (setgid (server_gid) == -1)
1036 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1037 perror ("setgid");
1038 exit (1);
1041 if (setuid (server_uid) == -1)
1043 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1044 perror ("setuid");
1045 exit (1);
1049 /* Handle the HUP signal which will force a dump of the cache */
1050 void
1051 sighup_handler (int signum)
1053 /* Prune the password database */
1054 prune_cache (&dbs[pwddb], LONG_MAX);
1056 /* Prune the group database */
1057 prune_cache (&dbs[grpdb], LONG_MAX);
1059 /* Prune the host database */
1060 prune_cache (&dbs[hstdb], LONG_MAX);