Update.
[glibc.git] / nscd / connections.c
blob313ca0dc45c3d0215590b886d633e36f1a4a280b
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 <pthread.h>
28 #include <pwd.h>
29 #include <resolv.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <libintl.h>
34 #include <arpa/inet.h>
35 #include <sys/param.h>
36 #include <sys/poll.h>
37 #include <sys/socket.h>
38 #include <sys/stat.h>
39 #include <sys/un.h>
41 #include "nscd.h"
42 #include "dbg_log.h"
44 /* Wrapper functions with error checking for standard functions. */
45 extern void *xmalloc (size_t n);
46 extern void *xcalloc (size_t n, size_t s);
47 extern void *xrealloc (void *o, size_t n);
49 /* Support to run nscd as an unprivileged user */
50 const char *server_user;
51 static uid_t server_uid;
52 static gid_t server_gid;
53 const char *stat_user;
54 uid_t stat_uid;
55 static gid_t *server_groups;
56 #ifndef NGROUPS
57 # define NGROUPS 32
58 #endif
59 static int server_ngroups = NGROUPS;
61 static void begin_drop_privileges (void);
62 static void finish_drop_privileges (void);
65 /* Mapping of request type to database. */
66 static const dbtype serv2db[LASTDBREQ + 1] =
68 [GETPWBYNAME] = pwddb,
69 [GETPWBYUID] = pwddb,
70 [GETGRBYNAME] = grpdb,
71 [GETGRBYGID] = grpdb,
72 [GETHOSTBYNAME] = hstdb,
73 [GETHOSTBYNAMEv6] = hstdb,
74 [GETHOSTBYADDR] = hstdb,
75 [GETHOSTBYADDRv6] = hstdb,
78 /* Map request type to a string. */
79 const char *serv2str[LASTREQ] =
81 [GETPWBYNAME] = "GETPWBYNAME",
82 [GETPWBYUID] = "GETPWBYUID",
83 [GETGRBYNAME] = "GETGRBYNAME",
84 [GETGRBYGID] = "GETGRBYGID",
85 [GETHOSTBYNAME] = "GETHOSTBYNAME",
86 [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6",
87 [GETHOSTBYADDR] = "GETHOSTBYADDR",
88 [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
89 [SHUTDOWN] = "SHUTDOWN",
90 [GETSTAT] = "GETSTAT",
91 [INVALIDATE] = "INVALIDATE"
94 /* The control data structures for the services. */
95 struct database dbs[lastdb] =
97 [pwddb] = {
98 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
99 .enabled = 0,
100 .check_file = 1,
101 .filename = "/etc/passwd",
102 .module = 211,
103 .disabled_iov = &pwd_iov_disabled,
104 .postimeout = 3600,
105 .negtimeout = 20
107 [grpdb] = {
108 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
109 .enabled = 0,
110 .check_file = 1,
111 .filename = "/etc/group",
112 .module = 211,
113 .disabled_iov = &grp_iov_disabled,
114 .postimeout = 3600,
115 .negtimeout = 60
117 [hstdb] = {
118 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
119 .enabled = 0,
120 .check_file = 1,
121 .filename = "/etc/hosts",
122 .module = 211,
123 .disabled_iov = &hst_iov_disabled,
124 .postimeout = 3600,
125 .negtimeout = 20
129 /* Number of seconds between two cache pruning runs. */
130 #define CACHE_PRUNE_INTERVAL 15
132 /* Number of threads to use. */
133 int nthreads = -1;
135 /* Socket for incoming connections. */
136 static int sock;
138 /* Number of times clients had to wait. */
139 unsigned long int client_queued;
142 /* Initialize database information structures. */
143 void
144 nscd_init (void)
146 struct sockaddr_un sock_addr;
147 size_t cnt;
149 /* Secure mode and unprivileged mode are incompatible */
150 if (server_user != NULL && secure_in_use)
152 dbg_log (_("Cannot run nscd in secure mode as unprivileged user"));
153 exit (1);
156 /* Look up unprivileged uid/gid/groups before we start listening on the
157 socket */
158 if (server_user != NULL)
159 begin_drop_privileges ();
161 if (nthreads == -1)
162 /* No configuration for this value, assume a default. */
163 nthreads = 2 * lastdb;
165 for (cnt = 0; cnt < lastdb; ++cnt)
166 if (dbs[cnt].enabled)
168 pthread_rwlock_init (&dbs[cnt].lock, NULL);
170 dbs[cnt].array = (struct hashentry **)
171 calloc (dbs[cnt].module, sizeof (struct hashentry *));
172 if (dbs[cnt].array == NULL)
174 dbg_log (_("while allocating cache: %s"), strerror (errno));
175 exit (1);
178 if (dbs[cnt].check_file)
180 /* We need the modification date of the file. */
181 struct stat st;
183 if (stat (dbs[cnt].filename, &st) < 0)
185 /* We cannot stat() the file, disable file checking. */
186 dbg_log (_("cannot stat() file `%s': %s"),
187 dbs[cnt].filename, strerror (errno));
188 dbs[cnt].check_file = 0;
190 else
191 dbs[cnt].file_mtime = st.st_mtime;
195 /* Create the socket. */
196 sock = socket (AF_UNIX, SOCK_STREAM, 0);
197 if (sock < 0)
199 dbg_log (_("cannot open socket: %s"), strerror (errno));
200 exit (1);
202 /* Bind a name to the socket. */
203 sock_addr.sun_family = AF_UNIX;
204 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
205 if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
207 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
208 exit (1);
211 /* We don't wait for data otherwise races between threads can get
212 them stuck on accept. */
213 int fl = fcntl (sock, F_GETFL);
214 if (fl != -1)
215 fcntl (sock, F_SETFL, fl | O_NONBLOCK);
217 /* Set permissions for the socket. */
218 chmod (_PATH_NSCDSOCKET, 0666);
220 /* Set the socket up to accept connections. */
221 if (listen (sock, SOMAXCONN) < 0)
223 dbg_log (_("cannot enable socket to accept connections: %s"),
224 strerror (errno));
225 exit (1);
228 /* Change to unprivileged uid/gid/groups if specifed in config file */
229 if (server_user != NULL)
230 finish_drop_privileges ();
234 /* Close the connections. */
235 void
236 close_sockets (void)
238 close (sock);
242 static void
243 invalidate_cache (char *key)
245 dbtype number;
247 if (strcmp (key, "passwd") == 0)
248 number = pwddb;
249 else if (strcmp (key, "group") == 0)
250 number = grpdb;
251 else if (__builtin_expect (strcmp (key, "hosts"), 0) == 0)
253 number = hstdb;
255 /* Re-initialize the resolver. resolv.conf might have changed. */
256 res_init ();
258 else
259 return;
261 if (dbs[number].enabled)
262 prune_cache (&dbs[number], LONG_MAX);
266 /* Handle new request. */
267 static void
268 handle_request (int fd, request_header *req, void *key, uid_t uid)
270 if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
272 if (debug_level > 0)
273 dbg_log (_("\
274 cannot handle old request version %d; current version is %d"),
275 req->version, NSCD_VERSION);
276 return;
279 if (__builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
280 && __builtin_expect (req->type, LASTDBREQ) <= LASTDBREQ)
282 struct hashentry *cached;
283 struct database *db = &dbs[serv2db[req->type]];
285 if (__builtin_expect (debug_level, 0) > 0)
287 if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
289 char buf[INET6_ADDRSTRLEN];
291 dbg_log ("\t%s (%s)", serv2str[req->type],
292 inet_ntop (req->type == GETHOSTBYADDR
293 ? AF_INET : AF_INET6,
294 key, buf, sizeof (buf)));
296 else
297 dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
300 /* Is this service enabled? */
301 if (!db->enabled)
303 /* No, sent the prepared record. */
304 if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
305 db->disabled_iov->iov_len))
306 != (ssize_t) db->disabled_iov->iov_len
307 && __builtin_expect (debug_level, 0) > 0)
309 /* We have problems sending the result. */
310 char buf[256];
311 dbg_log (_("cannot write result: %s"),
312 strerror_r (errno, buf, sizeof (buf)));
315 return;
318 /* Be sure we can read the data. */
319 if (__builtin_expect (pthread_rwlock_tryrdlock (&db->lock) != 0, 0))
321 ++db->rdlockdelayed;
322 pthread_rwlock_rdlock (&db->lock);
325 /* See whether we can handle it from the cache. */
326 cached = (struct hashentry *) cache_search (req->type, key, req->key_len,
327 db, uid);
328 if (cached != NULL)
330 /* Hurray it's in the cache. */
331 if (TEMP_FAILURE_RETRY (write (fd, cached->packet, cached->total))
332 != cached->total
333 && __builtin_expect (debug_level, 0) > 0)
335 /* We have problems sending the result. */
336 char buf[256];
337 dbg_log (_("cannot write result: %s"),
338 strerror_r (errno, buf, sizeof (buf)));
341 pthread_rwlock_unlock (&db->lock);
343 return;
346 pthread_rwlock_unlock (&db->lock);
348 else if (__builtin_expect (debug_level, 0) > 0)
350 if (req->type == INVALIDATE)
351 dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
352 else if (req->type > LASTDBREQ && req->type < LASTREQ)
353 dbg_log ("\t%s", serv2str[req->type]);
354 else
355 dbg_log (_("\tinvalid request type %d"), req->type);
358 /* Handle the request. */
359 switch (req->type)
361 case GETPWBYNAME:
362 addpwbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
363 break;
365 case GETPWBYUID:
366 addpwbyuid (&dbs[serv2db[req->type]], fd, req, key, uid);
367 break;
369 case GETGRBYNAME:
370 addgrbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
371 break;
373 case GETGRBYGID:
374 addgrbygid (&dbs[serv2db[req->type]], fd, req, key, uid);
375 break;
377 case GETHOSTBYNAME:
378 addhstbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
379 break;
381 case GETHOSTBYNAMEv6:
382 addhstbynamev6 (&dbs[serv2db[req->type]], fd, req, key, uid);
383 break;
385 case GETHOSTBYADDR:
386 addhstbyaddr (&dbs[serv2db[req->type]], fd, req, key, uid);
387 break;
389 case GETHOSTBYADDRv6:
390 addhstbyaddrv6 (&dbs[serv2db[req->type]], fd, req, key, uid);
391 break;
393 case GETSTAT:
394 case SHUTDOWN:
395 case INVALIDATE:
396 if (! secure_in_use)
398 /* Get the callers credentials. */
399 #ifdef SO_PEERCRED
400 struct ucred caller;
401 socklen_t optlen = sizeof (caller);
403 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
405 char buf[256];
407 dbg_log (_("error getting callers id: %s"),
408 strerror_r (errno, buf, sizeof (buf)));
409 break;
412 uid = caller.uid;
413 #else
414 /* Some systems have no SO_PEERCRED implementation. They don't
415 care about security so we don't as well. */
416 uid = 0;
417 #endif
420 /* Accept shutdown, getstat and invalidate only from root. For
421 the stat call also allow the user specified in the config file. */
422 if (req->type == GETSTAT)
424 if (uid == 0 || uid == stat_uid)
425 send_stats (fd, dbs);
427 else if (uid == 0)
429 if (req->type == INVALIDATE)
430 invalidate_cache (key);
431 else
432 termination_handler (0);
434 break;
436 default:
437 /* Ignore the command, it's nothing we know. */
438 break;
443 /* This is the main loop. It is replicated in different threads but the
444 `poll' call makes sure only one thread handles an incoming connection. */
445 static void *
446 __attribute__ ((__noreturn__))
447 nscd_run (void *p)
449 long int my_number = (long int) p;
450 struct pollfd conn;
451 int run_prune = my_number < lastdb && dbs[my_number].enabled;
452 time_t next_prune = run_prune ? time (NULL) + CACHE_PRUNE_INTERVAL : 0;
453 static unsigned long int nready;
455 conn.fd = sock;
456 conn.events = POLLRDNORM;
458 while (1)
460 int nr;
461 time_t now = 0;
463 /* One more thread available. */
464 atomic_increment (&nready);
466 no_conn:
469 int timeout = -1;
470 if (run_prune)
472 now = time (NULL);
473 timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
476 nr = poll (&conn, 1, timeout);
478 if (nr == 0)
480 /* The `poll' call timed out. It's time to clean up the
481 cache. */
482 atomic_decrement (&nready);
483 assert (my_number < lastdb);
484 prune_cache (&dbs[my_number], time(NULL));
485 now = time (NULL);
486 next_prune = now + CACHE_PRUNE_INTERVAL;
487 goto try_get;
490 while ((conn.revents & POLLRDNORM) == 0);
492 got_data:;
493 /* We have a new incoming connection. Accept the connection. */
494 int fd = TEMP_FAILURE_RETRY (accept (conn.fd, NULL, NULL));
495 request_header req;
496 char buf[256];
497 uid_t uid = -1;
498 #ifdef SO_PEERCRED
499 pid_t pid = 0;
500 #endif
502 if (__builtin_expect (fd, 0) < 0)
504 if (errno != EAGAIN && errno != EWOULDBLOCK)
505 dbg_log (_("while accepting connection: %s"),
506 strerror_r (errno, buf, sizeof (buf)));
507 goto no_conn;
510 /* This thread is busy. */
511 atomic_decrement (&nready);
513 /* Now read the request. */
514 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
515 != sizeof (req), 0))
517 if (debug_level > 0)
518 dbg_log (_("short read while reading request: %s"),
519 strerror_r (errno, buf, sizeof (buf)));
520 close (fd);
521 continue;
524 /* Some systems have no SO_PEERCRED implementation. They don't
525 care about security so we don't as well. */
526 #ifdef SO_PEERCRED
527 if (secure_in_use)
529 struct ucred caller;
530 socklen_t optlen = sizeof (caller);
532 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
534 dbg_log (_("error getting callers id: %s"),
535 strerror_r (errno, buf, sizeof (buf)));
536 close (fd);
537 continue;
540 if (req.type < GETPWBYNAME || req.type > LASTDBREQ
541 || secure[serv2db[req.type]])
542 uid = caller.uid;
544 pid = caller.pid;
546 else if (__builtin_expect (debug_level > 0, 0))
548 struct ucred caller;
549 socklen_t optlen = sizeof (caller);
551 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) == 0)
552 pid = caller.pid;
554 #endif
556 /* It should not be possible to crash the nscd with a silly
557 request (i.e., a terribly large key). We limit the size to 1kb. */
558 if (__builtin_expect (req.key_len, 1) < 0
559 || __builtin_expect (req.key_len, 1) > 1024)
561 if (debug_level > 0)
562 dbg_log (_("key length in request too long: %d"), req.key_len);
563 close (fd);
564 continue;
566 else
568 /* Get the key. */
569 char keybuf[req.key_len];
571 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
572 req.key_len))
573 != req.key_len, 0))
575 if (debug_level > 0)
576 dbg_log (_("short read while reading request key: %s"),
577 strerror_r (errno, buf, sizeof (buf)));
578 close (fd);
579 continue;
582 if (__builtin_expect (debug_level, 0) > 0)
584 #ifdef SO_PEERCRED
585 if (pid != 0)
586 dbg_log (_("\
587 handle_request: request received (Version = %d) from PID %ld"),
588 req.version, (long int) pid);
589 else
590 #endif
591 dbg_log (_("\
592 handle_request: request received (Version = %d)"), req.version);
595 /* Phew, we got all the data, now process it. */
596 handle_request (fd, &req, keybuf, uid);
598 /* We are done. */
599 close (fd);
602 /* Just determine whether any data is present. We do this to
603 measure whether clients are queued up. */
604 try_get:
605 nr = poll (&conn, 1, 0);
606 if (nr != 0)
608 if (nready == 0)
609 ++client_queued;
611 atomic_increment (&nready);
613 goto got_data;
619 /* Start all the threads we want. The initial process is thread no. 1. */
620 void
621 start_threads (void)
623 long int i;
624 pthread_attr_t attr;
625 pthread_t th;
627 pthread_attr_init (&attr);
628 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
630 /* We allow less than LASTDB threads only for debugging. */
631 if (debug_level == 0)
632 nthreads = MAX (nthreads, lastdb);
634 for (i = 1; i < nthreads; ++i)
635 pthread_create (&th, &attr, nscd_run, (void *) i);
637 pthread_attr_destroy (&attr);
639 nscd_run ((void *) 0);
643 /* Look up the uid, gid, and supplementary groups to run nscd as. When
644 this function is called, we are not listening on the nscd socket yet so
645 we can just use the ordinary lookup functions without causing a lockup */
646 static void
647 begin_drop_privileges (void)
649 struct passwd *pwd;
651 pwd = getpwnam (server_user);
653 if (pwd == NULL)
655 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
656 error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"),
657 server_user);
660 server_uid = pwd->pw_uid;
661 server_gid = pwd->pw_gid;
663 server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
665 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
666 == 0)
667 return;
669 server_groups = (gid_t *) xrealloc (server_groups,
670 server_ngroups * sizeof (gid_t));
672 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
673 == -1)
675 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
676 error (EXIT_FAILURE, errno, _("getgrouplist failed"));
681 /* Call setgroups(), setgid(), and setuid() to drop root privileges and
682 run nscd as the user specified in the configuration file. */
683 static void
684 finish_drop_privileges (void)
686 if (setgroups (server_ngroups, server_groups) == -1)
688 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
689 error (EXIT_FAILURE, errno, _("setgroups failed"));
692 if (setgid (server_gid) == -1)
694 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
695 perror ("setgid");
696 exit (1);
699 if (setuid (server_uid) == -1)
701 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
702 perror ("setuid");
703 exit (1);