semtimedop implementation for Linux/m68k.
[glibc.git] / nscd / connections.c
blob3628877dab87033f81e71a0ce1597883817f661f
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 <error.h>
23 #include <errno.h>
24 #include <grp.h>
25 #include <pthread.h>
26 #include <pwd.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <libintl.h>
31 #include <arpa/inet.h>
32 #include <sys/param.h>
33 #include <sys/poll.h>
34 #include <sys/socket.h>
35 #include <sys/stat.h>
36 #include <sys/un.h>
38 #include "nscd.h"
39 #include "dbg_log.h"
41 /* Wrapper functions with error checking for standard functions. */
42 extern void *xmalloc (size_t n);
43 extern void *xcalloc (size_t n, size_t s);
44 extern void *xrealloc (void *o, size_t n);
46 /* Support to run nscd as an unprivileged user */
47 const char *server_user;
48 static uid_t server_uid;
49 static gid_t server_gid;
50 static gid_t *server_groups;
51 #ifndef NGROUPS
52 # define NGROUPS 32
53 #endif
54 static int server_ngroups = NGROUPS;
56 static void begin_drop_privileges (void);
57 static void finish_drop_privileges (void);
60 /* Mapping of request type to database. */
61 static const dbtype serv2db[LASTDBREQ + 1] =
63 [GETPWBYNAME] = pwddb,
64 [GETPWBYUID] = pwddb,
65 [GETGRBYNAME] = grpdb,
66 [GETGRBYGID] = grpdb,
67 [GETHOSTBYNAME] = hstdb,
68 [GETHOSTBYNAMEv6] = hstdb,
69 [GETHOSTBYADDR] = hstdb,
70 [GETHOSTBYADDRv6] = hstdb,
73 /* Map request type to a string. */
74 const char *serv2str[LASTREQ] =
76 [GETPWBYNAME] = "GETPWBYNAME",
77 [GETPWBYUID] = "GETPWBYUID",
78 [GETGRBYNAME] = "GETGRBYNAME",
79 [GETGRBYGID] = "GETGRBYGID",
80 [GETHOSTBYNAME] = "GETHOSTBYNAME",
81 [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6",
82 [GETHOSTBYADDR] = "GETHOSTBYADDR",
83 [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
84 [SHUTDOWN] = "SHUTDOWN",
85 [GETSTAT] = "GETSTAT",
86 [INVALIDATE] = "INVALIDATE"
89 /* The control data structures for the services. */
90 static struct database dbs[lastdb] =
92 [pwddb] = {
93 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
94 .enabled = 0,
95 .check_file = 1,
96 .filename = "/etc/passwd",
97 .module = 211,
98 .disabled_iov = &pwd_iov_disabled,
99 .postimeout = 3600,
100 .negtimeout = 20
102 [grpdb] = {
103 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
104 .enabled = 0,
105 .check_file = 1,
106 .filename = "/etc/group",
107 .module = 211,
108 .disabled_iov = &grp_iov_disabled,
109 .postimeout = 3600,
110 .negtimeout = 60
112 [hstdb] = {
113 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
114 .enabled = 0,
115 .check_file = 1,
116 .filename = "/etc/hosts",
117 .module = 211,
118 .disabled_iov = &hst_iov_disabled,
119 .postimeout = 3600,
120 .negtimeout = 20
124 /* Number of seconds between two cache pruning runs. */
125 #define CACHE_PRUNE_INTERVAL 15
127 /* Number of threads to use. */
128 int nthreads = -1;
130 /* Socket for incoming connections. */
131 static int sock;
134 /* Initialize database information structures. */
135 void
136 nscd_init (const char *conffile)
138 struct sockaddr_un sock_addr;
139 size_t cnt;
141 /* Read the configuration file. */
142 if (nscd_parse_file (conffile, dbs) != 0)
144 /* We couldn't read the configuration file. Disable all services
145 by shutting down the srever. */
146 dbg_log (_("cannot read configuration file; this is fatal"));
147 exit (1);
150 /* Secure mode and unprivileged mode are incompatible */
151 if (server_user != NULL && secure_in_use)
153 dbg_log (_("Cannot run nscd in secure mode as unprivileged user"));
154 exit (1);
157 /* Look up unprivileged uid/gid/groups before we start listening on the
158 socket */
159 if (server_user != NULL)
160 begin_drop_privileges ();
162 if (nthreads == -1)
163 /* No configuration for this value, assume a default. */
164 nthreads = 2 * lastdb;
166 for (cnt = 0; cnt < lastdb; ++cnt)
167 if (dbs[cnt].enabled)
169 pthread_rwlock_init (&dbs[cnt].lock, NULL);
171 dbs[cnt].array = (struct hashentry **)
172 calloc (dbs[cnt].module, sizeof (struct hashentry *));
173 if (dbs[cnt].array == NULL)
175 dbg_log (_("while allocating cache: %s"), strerror (errno));
176 exit (1);
179 if (dbs[cnt].check_file)
181 /* We need the modification date of the file. */
182 struct stat st;
184 if (stat (dbs[cnt].filename, &st) < 0)
186 /* We cannot stat() the file, disable file checking. */
187 dbg_log (_("cannot stat() file `%s': %s"),
188 dbs[cnt].filename, strerror (errno));
189 dbs[cnt].check_file = 0;
191 else
192 dbs[cnt].file_mtime = st.st_mtime;
196 /* Create the socket. */
197 sock = socket (AF_UNIX, SOCK_STREAM, 0);
198 if (sock < 0)
200 dbg_log (_("cannot open socket: %s"), strerror (errno));
201 exit (1);
203 /* Bind a name to the socket. */
204 sock_addr.sun_family = AF_UNIX;
205 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
206 if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
208 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
209 exit (1);
212 /* Set permissions for the socket. */
213 chmod (_PATH_NSCDSOCKET, 0666);
215 /* Set the socket up to accept connections. */
216 if (listen (sock, SOMAXCONN) < 0)
218 dbg_log (_("cannot enable socket to accept connections: %s"),
219 strerror (errno));
220 exit (1);
223 /* Change to unprivileged uid/gid/groups if specifed in config file */
224 if (server_user != NULL)
225 finish_drop_privileges ();
229 /* Close the connections. */
230 void
231 close_sockets (void)
233 close (sock);
236 static void
237 invalidate_cache (char *key)
239 dbtype number;
241 if (strcmp (key, "passwd") == 0)
242 number = pwddb;
243 else if (strcmp (key, "group") == 0)
244 number = grpdb;
245 else if (__builtin_expect (strcmp (key, "hosts"), 0) == 0)
246 number = hstdb;
247 else
248 return;
250 if (dbs[number].enabled)
251 prune_cache (&dbs[number], LONG_MAX);
255 /* Handle new request. */
256 static void
257 handle_request (int fd, request_header *req, void *key, uid_t uid)
259 if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
261 if (debug_level > 0)
262 dbg_log (_("\
263 cannot handle old request version %d; current version is %d"),
264 req->version, NSCD_VERSION);
265 return;
268 if (__builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
269 && __builtin_expect (req->type, LASTDBREQ) <= LASTDBREQ)
271 struct hashentry *cached;
272 struct database *db = &dbs[serv2db[req->type]];
274 if (__builtin_expect (debug_level, 0) > 0)
276 if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
278 char buf[INET6_ADDRSTRLEN];
280 dbg_log ("\t%s (%s)", serv2str[req->type],
281 inet_ntop (req->type == GETHOSTBYADDR
282 ? AF_INET : AF_INET6,
283 key, buf, sizeof (buf)));
285 else
286 dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
289 /* Is this service enabled? */
290 if (!db->enabled)
292 /* No, sent the prepared record. */
293 if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
294 db->disabled_iov->iov_len))
295 != (ssize_t) db->disabled_iov->iov_len
296 && __builtin_expect (debug_level, 0) > 0)
298 /* We have problems sending the result. */
299 char buf[256];
300 dbg_log (_("cannot write result: %s"),
301 strerror_r (errno, buf, sizeof (buf)));
304 return;
307 /* Be sure we can read the data. */
308 if (__builtin_expect (pthread_rwlock_tryrdlock (&db->lock) != 0, 0))
310 ++db->rdlockdelayed;
311 pthread_rwlock_rdlock (&db->lock);
314 /* See whether we can handle it from the cache. */
315 cached = (struct hashentry *) cache_search (req->type, key, req->key_len,
316 db, uid);
317 if (cached != NULL)
319 /* Hurray it's in the cache. */
320 if (TEMP_FAILURE_RETRY (write (fd, cached->packet, cached->total))
321 != cached->total
322 && __builtin_expect (debug_level, 0) > 0)
324 /* We have problems sending the result. */
325 char buf[256];
326 dbg_log (_("cannot write result: %s"),
327 strerror_r (errno, buf, sizeof (buf)));
330 pthread_rwlock_unlock (&db->lock);
332 return;
335 pthread_rwlock_unlock (&db->lock);
337 else if (__builtin_expect (debug_level, 0) > 0)
339 if (req->type == INVALIDATE)
340 dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
341 else
342 dbg_log ("\t%s", serv2str[req->type]);
345 /* Handle the request. */
346 switch (req->type)
348 case GETPWBYNAME:
349 addpwbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
350 break;
352 case GETPWBYUID:
353 addpwbyuid (&dbs[serv2db[req->type]], fd, req, key, uid);
354 break;
356 case GETGRBYNAME:
357 addgrbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
358 break;
360 case GETGRBYGID:
361 addgrbygid (&dbs[serv2db[req->type]], fd, req, key, uid);
362 break;
364 case GETHOSTBYNAME:
365 addhstbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
366 break;
368 case GETHOSTBYNAMEv6:
369 addhstbynamev6 (&dbs[serv2db[req->type]], fd, req, key, uid);
370 break;
372 case GETHOSTBYADDR:
373 addhstbyaddr (&dbs[serv2db[req->type]], fd, req, key, uid);
374 break;
376 case GETHOSTBYADDRv6:
377 addhstbyaddrv6 (&dbs[serv2db[req->type]], fd, req, key, uid);
378 break;
380 case GETSTAT:
381 case SHUTDOWN:
382 case INVALIDATE:
383 /* Accept shutdown, getstat and invalidate only from root */
384 if (secure_in_use && uid == 0)
386 if (req->type == GETSTAT)
387 send_stats (fd, dbs);
388 else if (req->type == INVALIDATE)
389 invalidate_cache (key);
390 else
391 termination_handler (0);
393 else
395 /* Some systems have no SO_PEERCRED implementation. They don't
396 care about security so we don't as well. */
397 #ifdef SO_PEERCRED
398 struct ucred caller;
399 socklen_t optlen = sizeof (caller);
401 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
403 char buf[256];
405 dbg_log (_("error getting callers id: %s"),
406 strerror_r (errno, buf, sizeof (buf)));
408 else
409 if (caller.uid == 0)
410 #endif
412 if (req->type == GETSTAT)
413 send_stats (fd, dbs);
414 else if (req->type == INVALIDATE)
415 invalidate_cache (key);
416 else
417 termination_handler (0);
420 break;
422 default:
423 /* Ignore the command, it's nothing we know. */
424 break;
429 /* This is the main loop. It is replicated in different threads but the
430 `poll' call makes sure only one thread handles an incoming connection. */
431 static void *
432 __attribute__ ((__noreturn__))
433 nscd_run (void *p)
435 long int my_number = (long int) p;
436 struct pollfd conn;
437 int run_prune = my_number < lastdb && dbs[my_number].enabled;
438 time_t now = time (NULL);
439 time_t next_prune = now + CACHE_PRUNE_INTERVAL;
440 int timeout = run_prune ? 1000 * (next_prune - now) : -1;
442 conn.fd = sock;
443 conn.events = POLLRDNORM;
445 while (1)
447 int nr = poll (&conn, 1, timeout);
449 if (nr == 0)
451 /* The `poll' call timed out. It's time to clean up the cache. */
452 assert (my_number < lastdb);
453 now = time (NULL);
454 prune_cache (&dbs[my_number], now);
455 next_prune = now + CACHE_PRUNE_INTERVAL;
456 timeout = 1000 * (next_prune - now);
457 continue;
460 /* We have a new incoming connection. */
461 if (conn.revents & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))
463 /* Accept the connection. */
464 int fd = TEMP_FAILURE_RETRY (accept (conn.fd, NULL, NULL));
465 request_header req;
466 char buf[256];
467 uid_t uid = 0;
468 #ifdef SO_PEERCRED
469 pid_t pid = 0;
470 #endif
472 if (__builtin_expect (fd, 0) < 0)
474 dbg_log (_("while accepting connection: %s"),
475 strerror_r (errno, buf, sizeof (buf)));
476 continue;
479 /* Now read the request. */
480 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req,
481 sizeof (req)))
482 != sizeof (req), 0))
484 if (debug_level > 0)
485 dbg_log (_("short read while reading request: %s"),
486 strerror_r (errno, buf, sizeof (buf)));
487 close (fd);
488 continue;
491 /* Some systems have no SO_PEERCRED implementation. They don't
492 care about security so we don't as well. */
493 #ifdef SO_PEERCRED
494 if (secure_in_use)
496 struct ucred caller;
497 socklen_t optlen = sizeof (caller);
499 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED,
500 &caller, &optlen) < 0)
502 dbg_log (_("error getting callers id: %s"),
503 strerror_r (errno, buf, sizeof (buf)));
504 close (fd);
505 continue;
508 if (req.type < GETPWBYNAME || req.type > LASTDBREQ
509 || secure[serv2db[req.type]])
510 uid = caller.uid;
512 pid = caller.pid;
514 else if (__builtin_expect (debug_level > 0, 0))
516 struct ucred caller;
517 socklen_t optlen = sizeof (caller);
519 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED,
520 &caller, &optlen) == 0)
521 pid = caller.pid;
523 #endif
525 /* It should not be possible to crash the nscd with a silly
526 request (i.e., a terribly large key). We limit the size
527 to 1kb. */
528 if (__builtin_expect (req.key_len, 1) < 0
529 || __builtin_expect (req.key_len, 1) > 1024)
531 if (debug_level > 0)
532 dbg_log (_("key length in request too long: %d"), req.key_len);
533 close (fd);
534 continue;
536 else
538 /* Get the key. */
539 char keybuf[req.key_len];
541 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
542 req.key_len))
543 != req.key_len, 0))
545 if (debug_level > 0)
546 dbg_log (_("short read while reading request key: %s"),
547 strerror_r (errno, buf, sizeof (buf)));
548 close (fd);
549 continue;
552 if (__builtin_expect (debug_level, 0) > 0)
554 #ifdef SO_PEERCRED
555 if (pid != 0)
556 dbg_log (_("\
557 handle_request: request received (Version = %d) from PID %ld"),
558 req.version, (long int) pid);
559 else
560 #endif
561 dbg_log (_("\
562 handle_request: request received (Version = %d)"), req.version);
565 /* Phew, we got all the data, now process it. */
566 handle_request (fd, &req, keybuf, uid);
568 /* We are done. */
569 close (fd);
573 if (run_prune)
575 now = time (NULL);
576 timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
582 /* Start all the threads we want. The initial process is thread no. 1. */
583 void
584 start_threads (void)
586 long int i;
587 pthread_attr_t attr;
588 pthread_t th;
590 pthread_attr_init (&attr);
591 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
593 /* We allow less than LASTDB threads only for debugging. */
594 if (debug_level == 0)
595 nthreads = MAX (nthreads, lastdb);
597 for (i = 1; i < nthreads; ++i)
598 pthread_create (&th, &attr, nscd_run, (void *) i);
600 pthread_attr_destroy (&attr);
602 nscd_run ((void *) 0);
606 /* Look up the uid, gid, and supplementary groups to run nscd as. When
607 this function is called, we are not listening on the nscd socket yet so
608 we can just use the ordinary lookup functions without causing a lockup */
609 static void
610 begin_drop_privileges (void)
612 struct passwd *pwd;
614 pwd = getpwnam (server_user);
616 if (pwd == NULL)
618 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
619 error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"),
620 server_user);
623 server_uid = pwd->pw_uid;
624 server_gid = pwd->pw_gid;
626 server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
628 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
629 == 0)
630 return;
632 server_groups = (gid_t *) xrealloc (server_groups,
633 server_ngroups * sizeof (gid_t));
635 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
636 == -1)
638 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
639 error (EXIT_FAILURE, errno, _("getgrouplist failed"));
644 /* Call setgroups(), setgid(), and setuid() to drop root privileges and
645 run nscd as the user specified in the configuration file. */
646 static void
647 finish_drop_privileges (void)
649 if (setgroups (server_ngroups, server_groups) == -1)
651 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
652 error (EXIT_FAILURE, errno, _("setgroups failed"));
655 if (setgid (server_gid) == -1)
657 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
658 perror ("setgid");
659 exit (1);
662 if (setuid (server_uid) == -1)
664 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
665 perror ("setuid");
666 exit (1);