* posix/execl.c: Fix last argument of memcpy. Reported by Brian
[glibc.git] / nscd / connections.c
blob7f7514f8f6e5f6462f95f51de6cc30cc28cf4b2a
1 /* Inner loops of cache daemon.
2 Copyright (C) 1998, 1999, 2000, 2001 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 <pthread.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <libintl.h>
28 #include <arpa/inet.h>
29 #include <sys/param.h>
30 #include <sys/poll.h>
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33 #include <sys/un.h>
35 #include "nscd.h"
36 #include "dbg_log.h"
39 /* Mapping of request type to database. */
40 static const dbtype serv2db[LASTDBREQ + 1] =
42 [GETPWBYNAME] = pwddb,
43 [GETPWBYUID] = pwddb,
44 [GETGRBYNAME] = grpdb,
45 [GETGRBYGID] = grpdb,
46 [GETHOSTBYNAME] = hstdb,
47 [GETHOSTBYNAMEv6] = hstdb,
48 [GETHOSTBYADDR] = hstdb,
49 [GETHOSTBYADDRv6] = hstdb,
52 /* Map request type to a string. */
53 const char *serv2str[LASTREQ] =
55 [GETPWBYNAME] = "GETPWBYNAME",
56 [GETPWBYUID] = "GETPWBYUID",
57 [GETGRBYNAME] = "GETGRBYNAME",
58 [GETGRBYGID] = "GETGRBYGID",
59 [GETHOSTBYNAME] = "GETHOSTBYNAME",
60 [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6",
61 [GETHOSTBYADDR] = "GETHOSTBYADDR",
62 [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
63 [SHUTDOWN] = "SHUTDOWN",
64 [GETSTAT] = "GETSTAT",
65 [INVALIDATE] = "INVALIDATE"
68 /* The control data structures for the services. */
69 static struct database dbs[lastdb] =
71 [pwddb] = {
72 lock: PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
73 enabled: 0,
74 check_file: 1,
75 filename: "/etc/passwd",
76 module: 211,
77 disabled_iov: &pwd_iov_disabled,
78 postimeout: 3600,
79 negtimeout: 20
81 [grpdb] = {
82 lock: PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
83 enabled: 0,
84 check_file: 1,
85 filename: "/etc/group",
86 module: 211,
87 disabled_iov: &grp_iov_disabled,
88 postimeout: 3600,
89 negtimeout: 60
91 [hstdb] = {
92 lock: PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
93 enabled: 0,
94 check_file: 1,
95 filename: "/etc/hosts",
96 module: 211,
97 disabled_iov: &hst_iov_disabled,
98 postimeout: 3600,
99 negtimeout: 20
103 /* Number of seconds between two cache pruning runs. */
104 #define CACHE_PRUNE_INTERVAL 15
106 /* Number of threads to use. */
107 int nthreads = -1;
109 /* Socket for incoming connections. */
110 static int sock;
113 /* Initialize database information structures. */
114 void
115 nscd_init (const char *conffile)
117 struct sockaddr_un sock_addr;
118 size_t cnt;
120 /* Read the configuration file. */
121 if (nscd_parse_file (conffile, dbs) != 0)
123 /* We couldn't read the configuration file. Disable all services
124 by shutting down the srever. */
125 dbg_log (_("cannot read configuration file; this is fatal"));
126 exit (1);
128 if (nthreads == -1)
129 /* No configuration for this value, assume a default. */
130 nthreads = 2 * lastdb;
132 for (cnt = 0; cnt < lastdb; ++cnt)
133 if (dbs[cnt].enabled)
135 pthread_rwlock_init (&dbs[cnt].lock, NULL);
137 dbs[cnt].array = (struct hashentry **)
138 calloc (dbs[cnt].module, sizeof (struct hashentry *));
139 if (dbs[cnt].array == NULL)
140 error (EXIT_FAILURE, errno, "while allocating cache");
142 if (dbs[cnt].check_file)
144 /* We need the modification date of the file. */
145 struct stat st;
147 if (stat (dbs[cnt].filename, &st) < 0)
149 char buf[128];
150 /* We cannot stat() the file, disable file checking. */
151 dbg_log (_("cannot stat() file `%s': %s"),
152 dbs[cnt].filename,
153 strerror_r (errno, buf, sizeof (buf)));
154 dbs[cnt].check_file = 0;
156 else
157 dbs[cnt].file_mtime = st.st_mtime;
161 /* Create the socket. */
162 sock = socket (AF_UNIX, SOCK_STREAM, 0);
163 if (sock < 0)
165 dbg_log (_("cannot open socket: %s"), strerror (errno));
166 exit (1);
168 /* Bind a name to the socket. */
169 sock_addr.sun_family = AF_UNIX;
170 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
171 if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
173 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
174 exit (1);
177 /* Set permissions for the socket. */
178 chmod (_PATH_NSCDSOCKET, 0666);
180 /* Set the socket up to accept connections. */
181 if (listen (sock, SOMAXCONN) < 0)
183 dbg_log (_("cannot enable socket to accept connections: %s"),
184 strerror (errno));
185 exit (1);
190 /* Close the connections. */
191 void
192 close_sockets (void)
194 close (sock);
197 static void
198 invalidate_cache (char *key)
200 dbtype number;
202 if (strcmp (key, "passwd") == 0)
203 number = pwddb;
204 else if (strcmp (key, "group") == 0)
205 number = grpdb;
206 else if (__builtin_expect (strcmp (key, "hosts"), 0) == 0)
207 number = hstdb;
208 else
209 return;
211 if (dbs[number].enabled)
212 prune_cache (&dbs[number], LONG_MAX);
216 /* Handle new request. */
217 static void
218 handle_request (int fd, request_header *req, void *key, uid_t uid)
220 if (__builtin_expect (debug_level, 0) > 0)
221 dbg_log (_("handle_request: request received (Version = %d)"),
222 req->version);
224 if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
226 if (debug_level > 0)
227 dbg_log (_("\
228 cannot handle old request version %d; current version is %d"),
229 req->version, NSCD_VERSION);
230 return;
233 if (__builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
234 && __builtin_expect (req->type, LASTDBREQ) <= LASTDBREQ)
236 struct hashentry *cached;
237 struct database *db = &dbs[serv2db[req->type]];
239 if (__builtin_expect (debug_level, 0) > 0)
241 if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
243 char buf[INET6_ADDRSTRLEN];
245 dbg_log ("\t%s (%s)", serv2str[req->type],
246 inet_ntop (req->type == GETHOSTBYADDR
247 ? AF_INET : AF_INET6,
248 key, buf, sizeof (buf)));
250 else
251 dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
254 /* Is this service enabled? */
255 if (!db->enabled)
257 /* No, sent the prepared record. */
258 if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
259 db->disabled_iov->iov_len))
260 != db->disabled_iov->iov_len
261 && __builtin_expect (debug_level, 0) > 0)
263 /* We have problems sending the result. */
264 char buf[256];
265 dbg_log (_("cannot write result: %s"),
266 strerror_r (errno, buf, sizeof (buf)));
269 return;
272 /* Be sure we can read the data. */
273 pthread_rwlock_rdlock (&db->lock);
275 /* See whether we can handle it from the cache. */
276 cached = (struct hashentry *) cache_search (req->type, key, req->key_len,
277 db, uid);
278 if (cached != NULL)
280 /* Hurray it's in the cache. */
281 if (TEMP_FAILURE_RETRY (write (fd, cached->packet, cached->total))
282 != cached->total
283 && __builtin_expect (debug_level, 0) > 0)
285 /* We have problems sending the result. */
286 char buf[256];
287 dbg_log (_("cannot write result: %s"),
288 strerror_r (errno, buf, sizeof (buf)));
291 pthread_rwlock_unlock (&db->lock);
293 return;
296 pthread_rwlock_unlock (&db->lock);
298 else if (__builtin_expect (debug_level, 0) > 0)
300 if (req->type == INVALIDATE)
301 dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
302 else
303 dbg_log ("\t%s", serv2str[req->type]);
306 /* Handle the request. */
307 switch (req->type)
309 case GETPWBYNAME:
310 addpwbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
311 break;
313 case GETPWBYUID:
314 addpwbyuid (&dbs[serv2db[req->type]], fd, req, key, uid);
315 break;
317 case GETGRBYNAME:
318 addgrbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
319 break;
321 case GETGRBYGID:
322 addgrbygid (&dbs[serv2db[req->type]], fd, req, key, uid);
323 break;
325 case GETHOSTBYNAME:
326 addhstbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
327 break;
329 case GETHOSTBYNAMEv6:
330 addhstbynamev6 (&dbs[serv2db[req->type]], fd, req, key, uid);
331 break;
333 case GETHOSTBYADDR:
334 addhstbyaddr (&dbs[serv2db[req->type]], fd, req, key, uid);
335 break;
337 case GETHOSTBYADDRv6:
338 addhstbyaddrv6 (&dbs[serv2db[req->type]], fd, req, key, uid);
339 break;
341 case GETSTAT:
342 case SHUTDOWN:
343 case INVALIDATE:
344 /* Accept shutdown, getstat and invalidate only from root */
345 if (secure_in_use && uid == 0)
347 if (req->type == GETSTAT)
348 send_stats (fd, dbs);
349 else if (req->type == INVALIDATE)
350 invalidate_cache (key);
351 else
352 termination_handler (0);
354 else
356 struct ucred caller;
357 socklen_t optlen = sizeof (caller);
359 /* Some systems have no SO_PEERCRED implementation. They don't
360 care about security so we don't as well. */
361 #ifdef SO_PEERCRED
362 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
364 char buf[256];
366 dbg_log (_("error getting callers id: %s"),
367 strerror_r (errno, buf, sizeof (buf)));
369 else
370 if (caller.uid == 0)
371 #endif
373 if (req->type == GETSTAT)
374 send_stats (fd, dbs);
375 else if (req->type == INVALIDATE)
376 invalidate_cache (key);
377 else
378 termination_handler (0);
381 break;
383 default:
384 /* Ignore the command, it's nothing we know. */
385 break;
390 /* This is the main loop. It is replicated in different threads but the
391 `poll' call makes sure only one thread handles an incoming connection. */
392 static void *
393 __attribute__ ((__noreturn__))
394 nscd_run (void *p)
396 long int my_number = (long int) p;
397 struct pollfd conn;
398 int run_prune = my_number < lastdb && dbs[my_number].enabled;
399 time_t now = time (NULL);
400 time_t next_prune = now + CACHE_PRUNE_INTERVAL;
401 int timeout = run_prune ? 1000 * (next_prune - now) : -1;
403 conn.fd = sock;
404 conn.events = POLLRDNORM;
406 while (1)
408 int nr = poll (&conn, 1, timeout);
410 if (nr == 0)
412 /* The `poll' call timed out. It's time to clean up the cache. */
413 assert (my_number < lastdb);
414 now = time (NULL);
415 prune_cache (&dbs[my_number], now);
416 next_prune = now + CACHE_PRUNE_INTERVAL;
417 timeout = 1000 * (next_prune - now);
418 continue;
421 /* We have a new incoming connection. */
422 if (conn.revents & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))
424 /* Accept the connection. */
425 int fd = accept (conn.fd, NULL, NULL);
426 request_header req;
427 char buf[256];
428 uid_t uid = 0;
430 if (__builtin_expect (fd, 0) < 0)
432 dbg_log (_("while accepting connection: %s"),
433 strerror_r (errno, buf, sizeof (buf)));
434 continue;
437 /* Now read the request. */
438 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req,
439 sizeof (req)))
440 != sizeof (req), 0))
442 if (debug_level > 0)
443 dbg_log (_("short read while reading request: %s"),
444 strerror_r (errno, buf, sizeof (buf)));
445 close (fd);
446 continue;
449 /* Some systems have no SO_PEERCRED implementation. They don't
450 care about security so we don't as well. */
451 #ifdef SO_PEERCRED
452 if (secure_in_use)
454 struct ucred caller;
455 socklen_t optlen = sizeof (caller);
457 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED,
458 &caller, &optlen) < 0)
460 dbg_log (_("error getting callers id: %s"),
461 strerror_r (errno, buf, sizeof (buf)));
462 close (fd);
463 continue;
466 if (req.type < GETPWBYNAME || req.type > LASTDBREQ
467 || secure[serv2db[req.type]])
468 uid = caller.uid;
470 #endif
472 /* It should not be possible to crash the nscd with a silly
473 request (i.e., a terribly large key). We limit the size
474 to 1kb. */
475 if (__builtin_expect (req.key_len, 1) < 0
476 || __builtin_expect (req.key_len, 1) > 1024)
478 if (debug_level > 0)
479 dbg_log (_("key length in request too long: %d"), req.key_len);
480 close (fd);
481 continue;
483 else
485 /* Get the key. */
486 char keybuf[req.key_len];
488 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
489 req.key_len))
490 != req.key_len, 0))
492 if (debug_level > 0)
493 dbg_log (_("short read while reading request key: %s"),
494 strerror_r (errno, buf, sizeof (buf)));
495 close (fd);
496 continue;
499 /* Phew, we got all the data, now process it. */
500 handle_request (fd, &req, keybuf, uid);
502 /* We are done. */
503 close (fd);
507 if (run_prune)
509 now = time (NULL);
510 timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
516 /* Start all the threads we want. The initial process is thread no. 1. */
517 void
518 start_threads (void)
520 long int i;
521 pthread_attr_t attr;
522 pthread_t th;
524 pthread_attr_init (&attr);
525 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
527 /* We allow less than LASTDB threads only for debugging. */
528 if (debug_level == 0)
529 nthreads = MAX (nthreads, lastdb);
531 for (i = 1; i < nthreads; ++i)
532 pthread_create (&th, &attr, nscd_run, (void *) i);
534 pthread_attr_destroy (&attr);
536 nscd_run ((void *) 0);