Fix parameter name.
[glibc/pb-stable.git] / nscd / connections.c
blob5cb73eb2527d844125a8704ca43bddd8257e6b52
1 /* Inner loops of cache daemon.
2 Copyright (C) 1998,1999,2000,2001,2002,2003 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 <grp.h>
26 #include <pthread.h>
27 #include <pwd.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <libintl.h>
32 #include <arpa/inet.h>
33 #include <sys/param.h>
34 #include <sys/poll.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <sys/un.h>
39 #include "nscd.h"
40 #include "dbg_log.h"
42 /* Wrapper functions with error checking for standard functions. */
43 extern void *xmalloc (size_t n);
44 extern void *xcalloc (size_t n, size_t s);
45 extern void *xrealloc (void *o, size_t n);
47 /* Support to run nscd as an unprivileged user */
48 const char *server_user;
49 static uid_t server_uid;
50 static gid_t server_gid;
51 const char *stat_user;
52 uid_t stat_uid;
53 static gid_t *server_groups;
54 #ifndef NGROUPS
55 # define NGROUPS 32
56 #endif
57 static int server_ngroups = NGROUPS;
59 static void begin_drop_privileges (void);
60 static void finish_drop_privileges (void);
63 /* Mapping of request type to database. */
64 static const dbtype serv2db[LASTDBREQ + 1] =
66 [GETPWBYNAME] = pwddb,
67 [GETPWBYUID] = pwddb,
68 [GETGRBYNAME] = grpdb,
69 [GETGRBYGID] = grpdb,
70 [GETHOSTBYNAME] = hstdb,
71 [GETHOSTBYNAMEv6] = hstdb,
72 [GETHOSTBYADDR] = hstdb,
73 [GETHOSTBYADDRv6] = hstdb,
76 /* Map request type to a string. */
77 const char *serv2str[LASTREQ] =
79 [GETPWBYNAME] = "GETPWBYNAME",
80 [GETPWBYUID] = "GETPWBYUID",
81 [GETGRBYNAME] = "GETGRBYNAME",
82 [GETGRBYGID] = "GETGRBYGID",
83 [GETHOSTBYNAME] = "GETHOSTBYNAME",
84 [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6",
85 [GETHOSTBYADDR] = "GETHOSTBYADDR",
86 [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
87 [SHUTDOWN] = "SHUTDOWN",
88 [GETSTAT] = "GETSTAT",
89 [INVALIDATE] = "INVALIDATE"
92 /* The control data structures for the services. */
93 struct database dbs[lastdb] =
95 [pwddb] = {
96 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
97 .enabled = 0,
98 .check_file = 1,
99 .filename = "/etc/passwd",
100 .module = 211,
101 .disabled_iov = &pwd_iov_disabled,
102 .postimeout = 3600,
103 .negtimeout = 20
105 [grpdb] = {
106 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
107 .enabled = 0,
108 .check_file = 1,
109 .filename = "/etc/group",
110 .module = 211,
111 .disabled_iov = &grp_iov_disabled,
112 .postimeout = 3600,
113 .negtimeout = 60
115 [hstdb] = {
116 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
117 .enabled = 0,
118 .check_file = 1,
119 .filename = "/etc/hosts",
120 .module = 211,
121 .disabled_iov = &hst_iov_disabled,
122 .postimeout = 3600,
123 .negtimeout = 20
127 /* Number of seconds between two cache pruning runs. */
128 #define CACHE_PRUNE_INTERVAL 15
130 /* Number of threads to use. */
131 int nthreads = -1;
133 /* Socket for incoming connections. */
134 static int sock;
136 /* Number of times clients had to wait. */
137 unsigned long int client_queued;
140 /* Initialize database information structures. */
141 void
142 nscd_init (void)
144 struct sockaddr_un sock_addr;
145 size_t cnt;
147 /* Secure mode and unprivileged mode are incompatible */
148 if (server_user != NULL && secure_in_use)
150 dbg_log (_("Cannot run nscd in secure mode as unprivileged user"));
151 exit (1);
154 /* Look up unprivileged uid/gid/groups before we start listening on the
155 socket */
156 if (server_user != NULL)
157 begin_drop_privileges ();
159 if (nthreads == -1)
160 /* No configuration for this value, assume a default. */
161 nthreads = 2 * lastdb;
163 for (cnt = 0; cnt < lastdb; ++cnt)
164 if (dbs[cnt].enabled)
166 pthread_rwlock_init (&dbs[cnt].lock, NULL);
168 dbs[cnt].array = (struct hashentry **)
169 calloc (dbs[cnt].module, sizeof (struct hashentry *));
170 if (dbs[cnt].array == NULL)
172 dbg_log (_("while allocating cache: %s"), strerror (errno));
173 exit (1);
176 if (dbs[cnt].check_file)
178 /* We need the modification date of the file. */
179 struct stat st;
181 if (stat (dbs[cnt].filename, &st) < 0)
183 /* We cannot stat() the file, disable file checking. */
184 dbg_log (_("cannot stat() file `%s': %s"),
185 dbs[cnt].filename, strerror (errno));
186 dbs[cnt].check_file = 0;
188 else
189 dbs[cnt].file_mtime = st.st_mtime;
193 /* Create the socket. */
194 sock = socket (AF_UNIX, SOCK_STREAM, 0);
195 if (sock < 0)
197 dbg_log (_("cannot open socket: %s"), strerror (errno));
198 exit (1);
200 /* Bind a name to the socket. */
201 sock_addr.sun_family = AF_UNIX;
202 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
203 if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
205 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
206 exit (1);
209 /* Set permissions for the socket. */
210 chmod (_PATH_NSCDSOCKET, 0666);
212 /* Set the socket up to accept connections. */
213 if (listen (sock, SOMAXCONN) < 0)
215 dbg_log (_("cannot enable socket to accept connections: %s"),
216 strerror (errno));
217 exit (1);
220 /* Change to unprivileged uid/gid/groups if specifed in config file */
221 if (server_user != NULL)
222 finish_drop_privileges ();
226 /* Close the connections. */
227 void
228 close_sockets (void)
230 close (sock);
234 static void
235 invalidate_cache (char *key)
237 dbtype number;
239 if (strcmp (key, "passwd") == 0)
240 number = pwddb;
241 else if (strcmp (key, "group") == 0)
242 number = grpdb;
243 else if (__builtin_expect (strcmp (key, "hosts"), 0) == 0)
244 number = hstdb;
245 else
246 return;
248 if (dbs[number].enabled)
249 prune_cache (&dbs[number], LONG_MAX);
253 /* Handle new request. */
254 static void
255 handle_request (int fd, request_header *req, void *key, uid_t uid)
257 if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
259 if (debug_level > 0)
260 dbg_log (_("\
261 cannot handle old request version %d; current version is %d"),
262 req->version, NSCD_VERSION);
263 return;
266 if (__builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
267 && __builtin_expect (req->type, LASTDBREQ) <= LASTDBREQ)
269 struct hashentry *cached;
270 struct database *db = &dbs[serv2db[req->type]];
272 if (__builtin_expect (debug_level, 0) > 0)
274 if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
276 char buf[INET6_ADDRSTRLEN];
278 dbg_log ("\t%s (%s)", serv2str[req->type],
279 inet_ntop (req->type == GETHOSTBYADDR
280 ? AF_INET : AF_INET6,
281 key, buf, sizeof (buf)));
283 else
284 dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
287 /* Is this service enabled? */
288 if (!db->enabled)
290 /* No, sent the prepared record. */
291 if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
292 db->disabled_iov->iov_len))
293 != (ssize_t) db->disabled_iov->iov_len
294 && __builtin_expect (debug_level, 0) > 0)
296 /* We have problems sending the result. */
297 char buf[256];
298 dbg_log (_("cannot write result: %s"),
299 strerror_r (errno, buf, sizeof (buf)));
302 return;
305 /* Be sure we can read the data. */
306 if (__builtin_expect (pthread_rwlock_tryrdlock (&db->lock) != 0, 0))
308 ++db->rdlockdelayed;
309 pthread_rwlock_rdlock (&db->lock);
312 /* See whether we can handle it from the cache. */
313 cached = (struct hashentry *) cache_search (req->type, key, req->key_len,
314 db, uid);
315 if (cached != NULL)
317 /* Hurray it's in the cache. */
318 if (TEMP_FAILURE_RETRY (write (fd, cached->packet, cached->total))
319 != cached->total
320 && __builtin_expect (debug_level, 0) > 0)
322 /* We have problems sending the result. */
323 char buf[256];
324 dbg_log (_("cannot write result: %s"),
325 strerror_r (errno, buf, sizeof (buf)));
328 pthread_rwlock_unlock (&db->lock);
330 return;
333 pthread_rwlock_unlock (&db->lock);
335 else if (__builtin_expect (debug_level, 0) > 0)
337 if (req->type == INVALIDATE)
338 dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
339 else
340 dbg_log ("\t%s", serv2str[req->type]);
343 /* Handle the request. */
344 switch (req->type)
346 case GETPWBYNAME:
347 addpwbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
348 break;
350 case GETPWBYUID:
351 addpwbyuid (&dbs[serv2db[req->type]], fd, req, key, uid);
352 break;
354 case GETGRBYNAME:
355 addgrbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
356 break;
358 case GETGRBYGID:
359 addgrbygid (&dbs[serv2db[req->type]], fd, req, key, uid);
360 break;
362 case GETHOSTBYNAME:
363 addhstbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
364 break;
366 case GETHOSTBYNAMEv6:
367 addhstbynamev6 (&dbs[serv2db[req->type]], fd, req, key, uid);
368 break;
370 case GETHOSTBYADDR:
371 addhstbyaddr (&dbs[serv2db[req->type]], fd, req, key, uid);
372 break;
374 case GETHOSTBYADDRv6:
375 addhstbyaddrv6 (&dbs[serv2db[req->type]], fd, req, key, uid);
376 break;
378 case GETSTAT:
379 case SHUTDOWN:
380 case INVALIDATE:
381 if (! secure_in_use)
383 /* Get the callers credentials. */
384 #ifdef SO_PEERCRED
385 struct ucred caller;
386 socklen_t optlen = sizeof (caller);
388 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
390 char buf[256];
392 dbg_log (_("error getting callers id: %s"),
393 strerror_r (errno, buf, sizeof (buf)));
394 break;
397 uid = caller.uid;
398 #else
399 /* Some systems have no SO_PEERCRED implementation. They don't
400 care about security so we don't as well. */
401 uid = 0;
402 #endif
405 /* Accept shutdown, getstat and invalidate only from root. For
406 the stat call also allow the user specified in the config file. */
407 if (req->type == GETSTAT)
409 if (uid == 0 || uid == stat_uid)
410 send_stats (fd, dbs);
412 else if (uid == 0)
414 if (req->type == INVALIDATE)
415 invalidate_cache (key);
416 else
417 termination_handler (0);
419 break;
421 default:
422 /* Ignore the command, it's nothing we know. */
423 break;
428 /* This is the main loop. It is replicated in different threads but the
429 `poll' call makes sure only one thread handles an incoming connection. */
430 static void *
431 __attribute__ ((__noreturn__))
432 nscd_run (void *p)
434 long int my_number = (long int) p;
435 struct pollfd conn;
436 int run_prune = my_number < lastdb && dbs[my_number].enabled;
437 time_t next_prune = run_prune ? time (NULL) + CACHE_PRUNE_INTERVAL : 0;
438 static unsigned long int nready;
440 conn.fd = sock;
441 conn.events = POLLRDNORM;
443 while (1)
445 int nr;
447 /* One more thread available. */
448 atomic_increment (&nready);
450 no_conn:
451 if (run_prune)
454 time_t now = time (NULL);
455 int timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
457 nr = poll (&conn, 1, timeout);
459 if (nr == 0)
461 /* The `poll' call timed out. It's time to clean up the
462 cache. */
463 atomic_decrement (&nready);
464 assert (my_number < lastdb);
465 prune_cache (&dbs[my_number], time(NULL));
466 now = time (NULL);
467 next_prune = now + CACHE_PRUNE_INTERVAL;
468 goto try_get;
471 while ((conn.revents & POLLRDNORM) == 0);
473 got_data:;
474 /* We have a new incoming connection. Accept the connection. */
475 int fd = TEMP_FAILURE_RETRY (accept (conn.fd, NULL, NULL));
476 request_header req;
477 char buf[256];
478 uid_t uid = -1;
479 #ifdef SO_PEERCRED
480 pid_t pid = 0;
481 #endif
483 if (__builtin_expect (fd, 0) < 0)
485 dbg_log (_("while accepting connection: %s"),
486 strerror_r (errno, buf, sizeof (buf)));
487 goto no_conn;
490 /* This thread is busy. */
491 atomic_decrement (&nready);
493 /* Now read the request. */
494 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
495 != sizeof (req), 0))
497 if (debug_level > 0)
498 dbg_log (_("short read while reading request: %s"),
499 strerror_r (errno, buf, sizeof (buf)));
500 close (fd);
501 continue;
504 /* Some systems have no SO_PEERCRED implementation. They don't
505 care about security so we don't as well. */
506 #ifdef SO_PEERCRED
507 if (secure_in_use)
509 struct ucred caller;
510 socklen_t optlen = sizeof (caller);
512 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
514 dbg_log (_("error getting callers id: %s"),
515 strerror_r (errno, buf, sizeof (buf)));
516 close (fd);
517 continue;
520 if (req.type < GETPWBYNAME || req.type > LASTDBREQ
521 || secure[serv2db[req.type]])
522 uid = caller.uid;
524 pid = caller.pid;
526 else if (__builtin_expect (debug_level > 0, 0))
528 struct ucred caller;
529 socklen_t optlen = sizeof (caller);
531 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) == 0)
532 pid = caller.pid;
534 #endif
536 /* It should not be possible to crash the nscd with a silly
537 request (i.e., a terribly large key). We limit the size to 1kb. */
538 if (__builtin_expect (req.key_len, 1) < 0
539 || __builtin_expect (req.key_len, 1) > 1024)
541 if (debug_level > 0)
542 dbg_log (_("key length in request too long: %d"), req.key_len);
543 close (fd);
544 continue;
546 else
548 /* Get the key. */
549 char keybuf[req.key_len];
551 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
552 req.key_len))
553 != req.key_len, 0))
555 if (debug_level > 0)
556 dbg_log (_("short read while reading request key: %s"),
557 strerror_r (errno, buf, sizeof (buf)));
558 close (fd);
559 continue;
562 if (__builtin_expect (debug_level, 0) > 0)
564 #ifdef SO_PEERCRED
565 if (pid != 0)
566 dbg_log (_("\
567 handle_request: request received (Version = %d) from PID %ld"),
568 req.version, (long int) pid);
569 else
570 #endif
571 dbg_log (_("\
572 handle_request: request received (Version = %d)"), req.version);
575 /* Phew, we got all the data, now process it. */
576 handle_request (fd, &req, keybuf, uid);
578 /* We are done. */
579 close (fd);
582 /* Just determine whether any data is present. We do this to
583 measure whether clients are queued up. */
584 try_get:
585 nr = poll (&conn, 1, 0);
586 if (nr != 0)
588 if (nready == 0)
589 ++client_queued;
591 atomic_increment (&nready);
593 goto got_data;
599 /* Start all the threads we want. The initial process is thread no. 1. */
600 void
601 start_threads (void)
603 long int i;
604 pthread_attr_t attr;
605 pthread_t th;
607 pthread_attr_init (&attr);
608 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
610 /* We allow less than LASTDB threads only for debugging. */
611 if (debug_level == 0)
612 nthreads = MAX (nthreads, lastdb);
614 for (i = 1; i < nthreads; ++i)
615 pthread_create (&th, &attr, nscd_run, (void *) i);
617 pthread_attr_destroy (&attr);
619 nscd_run ((void *) 0);
623 /* Look up the uid, gid, and supplementary groups to run nscd as. When
624 this function is called, we are not listening on the nscd socket yet so
625 we can just use the ordinary lookup functions without causing a lockup */
626 static void
627 begin_drop_privileges (void)
629 struct passwd *pwd;
631 pwd = getpwnam (server_user);
633 if (pwd == NULL)
635 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
636 error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"),
637 server_user);
640 server_uid = pwd->pw_uid;
641 server_gid = pwd->pw_gid;
643 server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
645 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
646 == 0)
647 return;
649 server_groups = (gid_t *) xrealloc (server_groups,
650 server_ngroups * sizeof (gid_t));
652 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
653 == -1)
655 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
656 error (EXIT_FAILURE, errno, _("getgrouplist failed"));
661 /* Call setgroups(), setgid(), and setuid() to drop root privileges and
662 run nscd as the user specified in the configuration file. */
663 static void
664 finish_drop_privileges (void)
666 if (setgroups (server_ngroups, server_groups) == -1)
668 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
669 error (EXIT_FAILURE, errno, _("setgroups failed"));
672 if (setgid (server_gid) == -1)
674 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
675 perror ("setgid");
676 exit (1);
679 if (setuid (server_uid) == -1)
681 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
682 perror ("setuid");
683 exit (1);