* sysdeps/m68k/fpu/bits/mathinline.h (isgreater, isgreaterequal)
[glibc.git] / nscd / connections.c
blob58e05018d34382efb4b6efbb9a7366ec1f13e779
1 /* Inner loops of cache daemon.
2 Copyright (C) 1998, 1999, 2000, 2001, 2002 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)
174 error (EXIT_FAILURE, errno, "while allocating cache");
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 char buf[128];
184 /* We cannot stat() the file, disable file checking. */
185 dbg_log (_("cannot stat() file `%s': %s"),
186 dbs[cnt].filename,
187 strerror_r (errno, buf, sizeof (buf)));
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 /* Set permissions for the socket. */
212 chmod (_PATH_NSCDSOCKET, 0666);
214 /* Set the socket up to accept connections. */
215 if (listen (sock, SOMAXCONN) < 0)
217 dbg_log (_("cannot enable socket to accept connections: %s"),
218 strerror (errno));
219 exit (1);
222 /* Change to unprivileged uid/gid/groups if specifed in config file */
223 if (server_user != NULL)
224 finish_drop_privileges ();
228 /* Close the connections. */
229 void
230 close_sockets (void)
232 close (sock);
235 static void
236 invalidate_cache (char *key)
238 dbtype number;
240 if (strcmp (key, "passwd") == 0)
241 number = pwddb;
242 else if (strcmp (key, "group") == 0)
243 number = grpdb;
244 else if (__builtin_expect (strcmp (key, "hosts"), 0) == 0)
245 number = hstdb;
246 else
247 return;
249 if (dbs[number].enabled)
250 prune_cache (&dbs[number], LONG_MAX);
254 /* Handle new request. */
255 static void
256 handle_request (int fd, request_header *req, void *key, uid_t uid)
258 if (__builtin_expect (debug_level, 0) > 0)
259 dbg_log (_("handle_request: request received (Version = %d)"),
260 req->version);
262 if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
264 if (debug_level > 0)
265 dbg_log (_("\
266 cannot handle old request version %d; current version is %d"),
267 req->version, NSCD_VERSION);
268 return;
271 if (__builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
272 && __builtin_expect (req->type, LASTDBREQ) <= LASTDBREQ)
274 struct hashentry *cached;
275 struct database *db = &dbs[serv2db[req->type]];
277 if (__builtin_expect (debug_level, 0) > 0)
279 if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
281 char buf[INET6_ADDRSTRLEN];
283 dbg_log ("\t%s (%s)", serv2str[req->type],
284 inet_ntop (req->type == GETHOSTBYADDR
285 ? AF_INET : AF_INET6,
286 key, buf, sizeof (buf)));
288 else
289 dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
292 /* Is this service enabled? */
293 if (!db->enabled)
295 /* No, sent the prepared record. */
296 if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
297 db->disabled_iov->iov_len))
298 != db->disabled_iov->iov_len
299 && __builtin_expect (debug_level, 0) > 0)
301 /* We have problems sending the result. */
302 char buf[256];
303 dbg_log (_("cannot write result: %s"),
304 strerror_r (errno, buf, sizeof (buf)));
307 return;
310 /* Be sure we can read the data. */
311 pthread_rwlock_rdlock (&db->lock);
313 /* See whether we can handle it from the cache. */
314 cached = (struct hashentry *) cache_search (req->type, key, req->key_len,
315 db, uid);
316 if (cached != NULL)
318 /* Hurray it's in the cache. */
319 if (TEMP_FAILURE_RETRY (write (fd, cached->packet, cached->total))
320 != cached->total
321 && __builtin_expect (debug_level, 0) > 0)
323 /* We have problems sending the result. */
324 char buf[256];
325 dbg_log (_("cannot write result: %s"),
326 strerror_r (errno, buf, sizeof (buf)));
329 pthread_rwlock_unlock (&db->lock);
331 return;
334 pthread_rwlock_unlock (&db->lock);
336 else if (__builtin_expect (debug_level, 0) > 0)
338 if (req->type == INVALIDATE)
339 dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
340 else
341 dbg_log ("\t%s", serv2str[req->type]);
344 /* Handle the request. */
345 switch (req->type)
347 case GETPWBYNAME:
348 addpwbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
349 break;
351 case GETPWBYUID:
352 addpwbyuid (&dbs[serv2db[req->type]], fd, req, key, uid);
353 break;
355 case GETGRBYNAME:
356 addgrbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
357 break;
359 case GETGRBYGID:
360 addgrbygid (&dbs[serv2db[req->type]], fd, req, key, uid);
361 break;
363 case GETHOSTBYNAME:
364 addhstbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
365 break;
367 case GETHOSTBYNAMEv6:
368 addhstbynamev6 (&dbs[serv2db[req->type]], fd, req, key, uid);
369 break;
371 case GETHOSTBYADDR:
372 addhstbyaddr (&dbs[serv2db[req->type]], fd, req, key, uid);
373 break;
375 case GETHOSTBYADDRv6:
376 addhstbyaddrv6 (&dbs[serv2db[req->type]], fd, req, key, uid);
377 break;
379 case GETSTAT:
380 case SHUTDOWN:
381 case INVALIDATE:
382 /* Accept shutdown, getstat and invalidate only from root */
383 if (secure_in_use && uid == 0)
385 if (req->type == GETSTAT)
386 send_stats (fd, dbs);
387 else if (req->type == INVALIDATE)
388 invalidate_cache (key);
389 else
390 termination_handler (0);
392 else
394 /* Some systems have no SO_PEERCRED implementation. They don't
395 care about security so we don't as well. */
396 #ifdef SO_PEERCRED
397 struct ucred caller;
398 socklen_t optlen = sizeof (caller);
400 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
402 char buf[256];
404 dbg_log (_("error getting callers id: %s"),
405 strerror_r (errno, buf, sizeof (buf)));
407 else
408 if (caller.uid == 0)
409 #endif
411 if (req->type == GETSTAT)
412 send_stats (fd, dbs);
413 else if (req->type == INVALIDATE)
414 invalidate_cache (key);
415 else
416 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 now = time (NULL);
438 time_t next_prune = now + CACHE_PRUNE_INTERVAL;
439 int timeout = run_prune ? 1000 * (next_prune - now) : -1;
441 conn.fd = sock;
442 conn.events = POLLRDNORM;
444 while (1)
446 int nr = poll (&conn, 1, timeout);
448 if (nr == 0)
450 /* The `poll' call timed out. It's time to clean up the cache. */
451 assert (my_number < lastdb);
452 now = time (NULL);
453 prune_cache (&dbs[my_number], now);
454 next_prune = now + CACHE_PRUNE_INTERVAL;
455 timeout = 1000 * (next_prune - now);
456 continue;
459 /* We have a new incoming connection. */
460 if (conn.revents & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))
462 /* Accept the connection. */
463 int fd = accept (conn.fd, NULL, NULL);
464 request_header req;
465 char buf[256];
466 uid_t uid = 0;
468 if (__builtin_expect (fd, 0) < 0)
470 dbg_log (_("while accepting connection: %s"),
471 strerror_r (errno, buf, sizeof (buf)));
472 continue;
475 /* Now read the request. */
476 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req,
477 sizeof (req)))
478 != sizeof (req), 0))
480 if (debug_level > 0)
481 dbg_log (_("short read while reading request: %s"),
482 strerror_r (errno, buf, sizeof (buf)));
483 close (fd);
484 continue;
487 /* Some systems have no SO_PEERCRED implementation. They don't
488 care about security so we don't as well. */
489 #ifdef SO_PEERCRED
490 if (secure_in_use)
492 struct ucred caller;
493 socklen_t optlen = sizeof (caller);
495 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED,
496 &caller, &optlen) < 0)
498 dbg_log (_("error getting callers id: %s"),
499 strerror_r (errno, buf, sizeof (buf)));
500 close (fd);
501 continue;
504 if (req.type < GETPWBYNAME || req.type > LASTDBREQ
505 || secure[serv2db[req.type]])
506 uid = caller.uid;
508 #endif
510 /* It should not be possible to crash the nscd with a silly
511 request (i.e., a terribly large key). We limit the size
512 to 1kb. */
513 if (__builtin_expect (req.key_len, 1) < 0
514 || __builtin_expect (req.key_len, 1) > 1024)
516 if (debug_level > 0)
517 dbg_log (_("key length in request too long: %d"), req.key_len);
518 close (fd);
519 continue;
521 else
523 /* Get the key. */
524 char keybuf[req.key_len];
526 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
527 req.key_len))
528 != req.key_len, 0))
530 if (debug_level > 0)
531 dbg_log (_("short read while reading request key: %s"),
532 strerror_r (errno, buf, sizeof (buf)));
533 close (fd);
534 continue;
537 /* Phew, we got all the data, now process it. */
538 handle_request (fd, &req, keybuf, uid);
540 /* We are done. */
541 close (fd);
545 if (run_prune)
547 now = time (NULL);
548 timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
554 /* Start all the threads we want. The initial process is thread no. 1. */
555 void
556 start_threads (void)
558 long int i;
559 pthread_attr_t attr;
560 pthread_t th;
562 pthread_attr_init (&attr);
563 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
565 /* We allow less than LASTDB threads only for debugging. */
566 if (debug_level == 0)
567 nthreads = MAX (nthreads, lastdb);
569 for (i = 1; i < nthreads; ++i)
570 pthread_create (&th, &attr, nscd_run, (void *) i);
572 pthread_attr_destroy (&attr);
574 nscd_run ((void *) 0);
578 /* Look up the uid, gid, and supplementary groups to run nscd as. When
579 this function is called, we are not listening on the nscd socket yet so
580 we can just use the ordinary lookup functions without causing a lockup */
581 static void
582 begin_drop_privileges (void)
584 struct passwd *pwd;
586 pwd = getpwnam (server_user);
588 if (pwd == NULL)
590 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
591 error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"),
592 server_user);
595 server_uid = pwd->pw_uid;
596 server_gid = pwd->pw_gid;
598 server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
600 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
601 == 0)
602 return;
604 server_groups = (gid_t *) xrealloc (server_groups,
605 server_ngroups * sizeof (gid_t));
607 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
608 == -1)
610 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
611 error (EXIT_FAILURE, errno, _("getgrouplist failed"));
616 /* Call setgroups(), setgid(), and setuid() to drop root privileges and
617 run nscd as the user specified in the configuration file. */
618 static void
619 finish_drop_privileges (void)
621 if (setgroups (server_ngroups, server_groups) == -1)
623 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
624 error (EXIT_FAILURE, errno, _("setgroups failed"));
627 if (setgid (server_gid) == -1)
629 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
630 perror ("setgid");
631 exit (1);
634 if (setuid (server_uid) == -1)
636 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
637 perror ("setuid");
638 exit (1);