]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/connections.c
Test for stack alignment.
[thirdparty/glibc.git] / nscd / connections.c
CommitLineData
67479a70 1/* Inner loops of cache daemon.
482bbeb9 2 Copyright (C) 1998-2003, 2004 Free Software Foundation, Inc.
d67281a7 3 This file is part of the GNU C Library.
67479a70 4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
d67281a7
UD
5
6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
d67281a7
UD
10
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
41bdb6e2 14 Lesser General Public License for more details.
d67281a7 15
41bdb6e2
AJ
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. */
d67281a7 20
4401d759 21#include <alloca.h>
67479a70 22#include <assert.h>
0fdb4f42 23#include <atomic.h>
d67281a7 24#include <error.h>
67479a70 25#include <errno.h>
d6db0975 26#include <fcntl.h>
057685e4 27#include <grp.h>
a95a08b4 28#include <libintl.h>
d67281a7 29#include <pthread.h>
057685e4 30#include <pwd.h>
482bbeb9 31#include <resolv.h>
057685e4 32#include <stdio.h>
d67281a7
UD
33#include <stdlib.h>
34#include <unistd.h>
8d8c6efa 35#include <arpa/inet.h>
fc03df7a
UD
36#ifdef HAVE_EPOLL
37# include <sys/epoll.h>
38#endif
a95a08b4 39#include <sys/mman.h>
67479a70 40#include <sys/param.h>
a53bad16 41#include <sys/poll.h>
d67281a7
UD
42#include <sys/socket.h>
43#include <sys/stat.h>
d67281a7
UD
44#include <sys/un.h>
45
46#include "nscd.h"
47#include "dbg_log.h"
74a30a58 48#include "selinux.h"
d67281a7 49
a95a08b4
UD
50
51/* Number of bytes of data we initially reserve for each hash table bucket. */
52#define DEFAULT_DATASIZE_PER_BUCKET 1024
53
54
057685e4
UD
55/* Wrapper functions with error checking for standard functions. */
56extern void *xmalloc (size_t n);
57extern void *xcalloc (size_t n, size_t s);
58extern void *xrealloc (void *o, size_t n);
59
60/* Support to run nscd as an unprivileged user */
61const char *server_user;
62static uid_t server_uid;
63static gid_t server_gid;
a12ce44f
UD
64const char *stat_user;
65uid_t stat_uid;
057685e4
UD
66static gid_t *server_groups;
67#ifndef NGROUPS
68# define NGROUPS 32
69#endif
a95a08b4 70static int server_ngroups;
057685e4 71
27e82856
UD
72static pthread_attr_t attr;
73
057685e4
UD
74static void begin_drop_privileges (void);
75static void finish_drop_privileges (void);
76
67479a70
UD
77/* Map request type to a string. */
78const char *serv2str[LASTREQ] =
d67281a7 79{
67479a70
UD
80 [GETPWBYNAME] = "GETPWBYNAME",
81 [GETPWBYUID] = "GETPWBYUID",
82 [GETGRBYNAME] = "GETGRBYNAME",
83 [GETGRBYGID] = "GETGRBYGID",
84 [GETHOSTBYNAME] = "GETHOSTBYNAME",
85 [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6",
86 [GETHOSTBYADDR] = "GETHOSTBYADDR",
87 [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
88 [SHUTDOWN] = "SHUTDOWN",
756409c4 89 [GETSTAT] = "GETSTAT",
c207f23b
UD
90 [INVALIDATE] = "INVALIDATE",
91 [GETFDPW] = "GETFDPW",
92 [GETFDGR] = "GETFDGR",
d19687d6 93 [GETFDHST] = "GETFDHST",
f7e7a396
UD
94 [GETAI] = "GETAI",
95 [INITGROUPS] = "INITGROUPS"
67479a70
UD
96};
97
98/* The control data structures for the services. */
a95a08b4 99struct database_dyn dbs[lastdb] =
67479a70
UD
100{
101 [pwddb] = {
c2e13112
RM
102 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
103 .enabled = 0,
104 .check_file = 1,
a95a08b4 105 .persistent = 0,
c207f23b 106 .shared = 0,
c2e13112 107 .filename = "/etc/passwd",
a95a08b4 108 .db_filename = _PATH_NSCD_PASSWD_DB,
c2e13112
RM
109 .disabled_iov = &pwd_iov_disabled,
110 .postimeout = 3600,
a95a08b4
UD
111 .negtimeout = 20,
112 .wr_fd = -1,
113 .ro_fd = -1,
114 .mmap_used = false
67479a70
UD
115 },
116 [grpdb] = {
c2e13112
RM
117 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
118 .enabled = 0,
119 .check_file = 1,
a95a08b4 120 .persistent = 0,
c207f23b 121 .shared = 0,
c2e13112 122 .filename = "/etc/group",
a95a08b4 123 .db_filename = _PATH_NSCD_GROUP_DB,
c2e13112
RM
124 .disabled_iov = &grp_iov_disabled,
125 .postimeout = 3600,
a95a08b4
UD
126 .negtimeout = 60,
127 .wr_fd = -1,
128 .ro_fd = -1,
129 .mmap_used = false
67479a70
UD
130 },
131 [hstdb] = {
c2e13112
RM
132 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
133 .enabled = 0,
134 .check_file = 1,
a95a08b4 135 .persistent = 0,
c207f23b 136 .shared = 0,
c2e13112 137 .filename = "/etc/hosts",
a95a08b4 138 .db_filename = _PATH_NSCD_HOSTS_DB,
c2e13112
RM
139 .disabled_iov = &hst_iov_disabled,
140 .postimeout = 3600,
a95a08b4
UD
141 .negtimeout = 20,
142 .wr_fd = -1,
143 .ro_fd = -1,
144 .mmap_used = false
67479a70
UD
145 }
146};
d67281a7 147
a95a08b4
UD
148
149/* Mapping of request type to database. */
c207f23b 150static struct database_dyn *const serv2db[LASTREQ] =
a95a08b4
UD
151{
152 [GETPWBYNAME] = &dbs[pwddb],
153 [GETPWBYUID] = &dbs[pwddb],
154 [GETGRBYNAME] = &dbs[grpdb],
155 [GETGRBYGID] = &dbs[grpdb],
156 [GETHOSTBYNAME] = &dbs[hstdb],
157 [GETHOSTBYNAMEv6] = &dbs[hstdb],
158 [GETHOSTBYADDR] = &dbs[hstdb],
c207f23b
UD
159 [GETHOSTBYADDRv6] = &dbs[hstdb],
160 [GETFDPW] = &dbs[pwddb],
161 [GETFDGR] = &dbs[grpdb],
162 [GETFDHST] = &dbs[hstdb],
d19687d6 163 [GETAI] = &dbs[hstdb],
f7e7a396 164 [INITGROUPS] = &dbs[grpdb]
a95a08b4
UD
165};
166
167
34489d95
UD
168/* Number of seconds between two cache pruning runs. */
169#define CACHE_PRUNE_INTERVAL 15
170
a95a08b4 171
27e82856 172/* Initial number of threads to use. */
67479a70 173int nthreads = -1;
27e82856
UD
174/* Maximum number of threads to use. */
175int max_nthreads = 32;
d67281a7 176
67479a70
UD
177/* Socket for incoming connections. */
178static int sock;
d67281a7 179
0fdb4f42
UD
180/* Number of times clients had to wait. */
181unsigned long int client_queued;
182
d67281a7 183
67479a70
UD
184/* Initialize database information structures. */
185void
a12ce44f 186nscd_init (void)
d67281a7 187{
67479a70
UD
188 struct sockaddr_un sock_addr;
189 size_t cnt;
d67281a7 190
057685e4
UD
191 /* Secure mode and unprivileged mode are incompatible */
192 if (server_user != NULL && secure_in_use)
193 {
194 dbg_log (_("Cannot run nscd in secure mode as unprivileged user"));
195 exit (1);
196 }
197
198 /* Look up unprivileged uid/gid/groups before we start listening on the
199 socket */
200 if (server_user != NULL)
201 begin_drop_privileges ();
202
67479a70
UD
203 if (nthreads == -1)
204 /* No configuration for this value, assume a default. */
205 nthreads = 2 * lastdb;
d67281a7 206
67479a70
UD
207 for (cnt = 0; cnt < lastdb; ++cnt)
208 if (dbs[cnt].enabled)
9db29cde 209 {
67479a70 210 pthread_rwlock_init (&dbs[cnt].lock, NULL);
a95a08b4 211 pthread_mutex_init (&dbs[cnt].memlock, NULL);
264d5b94 212
a95a08b4 213 if (dbs[cnt].persistent)
e09edf23 214 {
a95a08b4
UD
215 /* Try to open the appropriate file on disk. */
216 int fd = open (dbs[cnt].db_filename, O_RDWR);
217 if (fd != -1)
218 {
219 struct stat64 st;
220 void *mem;
221 size_t total;
222 struct database_pers_head head;
223 ssize_t n = TEMP_FAILURE_RETRY (read (fd, &head,
224 sizeof (head)));
225 if (n != sizeof (head) || fstat64 (fd, &st) != 0)
226 {
227 fail_db:
228 dbg_log (_("invalid persistent database file \"%s\": %s"),
229 dbs[cnt].db_filename, strerror (errno));
230 dbs[cnt].persistent = 0;
231 }
232 else if (head.module == 0 && head.data_size == 0)
233 {
234 /* The file has been created, but the head has not been
235 initialized yet. Remove the old file. */
236 unlink (dbs[cnt].db_filename);
237 }
238 else if (head.header_size != (int) sizeof (head))
239 {
240 dbg_log (_("invalid persistent database file \"%s\": %s"),
241 dbs[cnt].db_filename,
242 _("header size does not match"));
243 dbs[cnt].persistent = 0;
244 }
245 else if ((total = (sizeof (head)
c207f23b 246 + roundup (head.module * sizeof (ref_t),
a95a08b4
UD
247 ALIGN)
248 + head.data_size))
c207f23b 249 > st.st_size)
a95a08b4
UD
250 {
251 dbg_log (_("invalid persistent database file \"%s\": %s"),
252 dbs[cnt].db_filename,
253 _("file size does not match"));
254 dbs[cnt].persistent = 0;
255 }
256 else if ((mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
257 MAP_SHARED, fd, 0)) == MAP_FAILED)
258 goto fail_db;
259 else
260 {
261 /* Success. We have the database. */
262 dbs[cnt].head = mem;
263 dbs[cnt].memsize = total;
264 dbs[cnt].data = (char *)
265 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
266 ALIGN / sizeof (ref_t))];
267 dbs[cnt].mmap_used = true;
268
269 if (dbs[cnt].suggested_module > head.module)
270 dbg_log (_("suggested size of table for database %s larger than the persistent database's table"),
271 dbnames[cnt]);
272
273 dbs[cnt].wr_fd = fd;
274 fd = -1;
275 /* We also need a read-only descriptor. */
d13a3c57
UD
276 if (dbs[cnt].shared)
277 {
278 dbs[cnt].ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
279 if (dbs[cnt].ro_fd == -1)
280 dbg_log (_("\
a95a08b4 281cannot create read-only descriptor for \"%s\"; no mmap"),
d13a3c57
UD
282 dbs[cnt].db_filename);
283 }
a95a08b4
UD
284
285 // XXX Shall we test whether the descriptors actually
286 // XXX point to the same file?
287 }
288
289 /* Close the file descriptors in case something went
290 wrong in which case the variable have not been
291 assigned -1. */
292 if (fd != -1)
293 close (fd);
294 }
295 }
296
297 if (dbs[cnt].head == NULL)
298 {
299 /* No database loaded. Allocate the data structure,
300 possibly on disk. */
301 struct database_pers_head head;
302 size_t total = (sizeof (head)
303 + roundup (dbs[cnt].suggested_module
304 * sizeof (ref_t), ALIGN)
305 + (dbs[cnt].suggested_module
306 * DEFAULT_DATASIZE_PER_BUCKET));
307
308 /* Try to create the database. If we do not need a
309 persistent database create a temporary file. */
310 int fd;
311 int ro_fd = -1;
312 if (dbs[cnt].persistent)
313 {
314 fd = open (dbs[cnt].db_filename,
315 O_RDWR | O_CREAT | O_EXCL | O_TRUNC,
316 S_IRUSR | S_IWUSR);
d13a3c57 317 if (fd != -1 && dbs[cnt].shared)
a95a08b4
UD
318 ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
319 }
320 else
321 {
a8a58967 322 char fname[] = _PATH_NSCD_XYZ_DB_TMP;
a95a08b4
UD
323 fd = mkstemp (fname);
324
325 /* We do not need the file name anymore after we
326 opened another file descriptor in read-only mode. */
5ca3d19c 327 if (fd != -1)
a95a08b4 328 {
5ca3d19c
UD
329 if (dbs[cnt].shared)
330 ro_fd = open (fname, O_RDONLY);
a95a08b4
UD
331
332 unlink (fname);
333 }
334 }
335
336 if (fd == -1)
337 {
338 if (errno == EEXIST)
339 {
340 dbg_log (_("database for %s corrupted or simultaneously used; remove %s manually if necessary and restart"),
341 dbnames[cnt], dbs[cnt].db_filename);
342 // XXX Correct way to terminate?
343 exit (1);
344 }
345
346 if (dbs[cnt].persistent)
347 dbg_log (_("cannot create %s; no persistent database used"),
348 dbs[cnt].db_filename);
349 else
350 dbg_log (_("cannot create %s; no sharing possible"),
351 dbs[cnt].db_filename);
352
353 dbs[cnt].persistent = 0;
354 // XXX remember: no mmap
355 }
356 else
357 {
358 /* Tell the user if we could not create the read-only
359 descriptor. */
d13a3c57 360 if (ro_fd == -1 && dbs[cnt].shared)
a95a08b4
UD
361 dbg_log (_("\
362cannot create read-only descriptor for \"%s\"; no mmap"),
363 dbs[cnt].db_filename);
364
365 /* Before we create the header, initialiye the hash
366 table. So that if we get interrupted if writing
367 the header we can recognize a partially initialized
368 database. */
369 size_t ps = sysconf (_SC_PAGESIZE);
370 char tmpbuf[ps];
371 assert (~ENDREF == 0);
372 memset (tmpbuf, '\xff', ps);
373
374 size_t remaining = dbs[cnt].suggested_module * sizeof (ref_t);
375 off_t offset = sizeof (head);
376
377 size_t towrite;
378 if (offset % ps != 0)
379 {
380 towrite = MIN (remaining, ps - (offset % ps));
381 pwrite (fd, tmpbuf, towrite, offset);
382 offset += towrite;
383 remaining -= towrite;
384 }
385
386 while (remaining > ps)
387 {
388 pwrite (fd, tmpbuf, ps, offset);
389 offset += ps;
390 remaining -= ps;
391 }
392
393 if (remaining > 0)
394 pwrite (fd, tmpbuf, remaining, offset);
395
396 /* Create the header of the file. */
397 struct database_pers_head head =
398 {
399 .version = DB_VERSION,
400 .header_size = sizeof (head),
401 .module = dbs[cnt].suggested_module,
402 .data_size = (dbs[cnt].suggested_module
403 * DEFAULT_DATASIZE_PER_BUCKET),
404 .first_free = 0
405 };
406 void *mem;
407
408 if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head)))
409 != sizeof (head))
410 || ftruncate (fd, total) != 0
411 || (mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
412 MAP_SHARED, fd, 0)) == MAP_FAILED)
413 {
414 unlink (dbs[cnt].db_filename);
415 dbg_log (_("cannot write to database file %s: %s"),
416 dbs[cnt].db_filename, strerror (errno));
417 dbs[cnt].persistent = 0;
418 }
419 else
420 {
421 /* Success. */
422 dbs[cnt].head = mem;
423 dbs[cnt].data = (char *)
424 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
425 ALIGN / sizeof (ref_t))];
426 dbs[cnt].memsize = total;
427 dbs[cnt].mmap_used = true;
428
429 /* Remember the descriptors. */
430 dbs[cnt].wr_fd = fd;
431 dbs[cnt].ro_fd = ro_fd;
432 fd = -1;
433 ro_fd = -1;
434 }
435
436 if (fd != -1)
437 close (fd);
438 if (ro_fd != -1)
439 close (ro_fd);
440 }
441 }
442
4401d759
UD
443 if (paranoia
444 && ((dbs[cnt].wr_fd != -1
445 && fcntl (dbs[cnt].wr_fd, F_SETFD, FD_CLOEXEC) == -1)
446 || (dbs[cnt].ro_fd != -1
447 && fcntl (dbs[cnt].ro_fd, F_SETFD, FD_CLOEXEC) == -1)))
448 {
449 dbg_log (_("\
450cannot set socket to close on exec: %s; disabling paranoia mode"),
451 strerror (errno));
452 paranoia = 0;
453 }
454
a95a08b4
UD
455 if (dbs[cnt].head == NULL)
456 {
457 /* We do not use the persistent database. Just
458 create an in-memory data structure. */
459 assert (! dbs[cnt].persistent);
460
461 dbs[cnt].head = xmalloc (sizeof (struct database_pers_head)
462 + (dbs[cnt].suggested_module
463 * sizeof (ref_t)));
464 memset (dbs[cnt].head, '\0', sizeof (dbs[cnt].head));
465 assert (~ENDREF == 0);
466 memset (dbs[cnt].head->array, '\xff',
467 dbs[cnt].suggested_module * sizeof (ref_t));
468 dbs[cnt].head->module = dbs[cnt].suggested_module;
469 dbs[cnt].head->data_size = (DEFAULT_DATASIZE_PER_BUCKET
470 * dbs[cnt].head->module);
471 dbs[cnt].data = xmalloc (dbs[cnt].head->data_size);
472 dbs[cnt].head->first_free = 0;
c207f23b
UD
473
474 dbs[cnt].shared = 0;
475 assert (dbs[cnt].ro_fd == -1);
e09edf23 476 }
d67281a7 477
67479a70 478 if (dbs[cnt].check_file)
d67281a7 479 {
67479a70
UD
480 /* We need the modification date of the file. */
481 struct stat st;
d67281a7 482
67479a70 483 if (stat (dbs[cnt].filename, &st) < 0)
d67281a7 484 {
67479a70
UD
485 /* We cannot stat() the file, disable file checking. */
486 dbg_log (_("cannot stat() file `%s': %s"),
e09edf23 487 dbs[cnt].filename, strerror (errno));
67479a70 488 dbs[cnt].check_file = 0;
d67281a7
UD
489 }
490 else
67479a70
UD
491 dbs[cnt].file_mtime = st.st_mtime;
492 }
493 }
d67281a7
UD
494
495 /* Create the socket. */
67479a70
UD
496 sock = socket (AF_UNIX, SOCK_STREAM, 0);
497 if (sock < 0)
d67281a7 498 {
67479a70 499 dbg_log (_("cannot open socket: %s"), strerror (errno));
d67281a7
UD
500 exit (1);
501 }
502 /* Bind a name to the socket. */
503 sock_addr.sun_family = AF_UNIX;
504 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
67479a70 505 if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
d67281a7
UD
506 {
507 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
508 exit (1);
509 }
67479a70 510
4401d759 511 /* We don't want to get stuck on accept. */
d6db0975 512 int fl = fcntl (sock, F_GETFL);
4401d759
UD
513 if (fl == -1 || fcntl (sock, F_SETFL, fl | O_NONBLOCK) == -1)
514 {
515 dbg_log (_("cannot change socket to nonblocking mode: %s"),
516 strerror (errno));
517 exit (1);
518 }
519
520 /* The descriptor needs to be closed on exec. */
521 if (paranoia && fcntl (sock, F_SETFD, FD_CLOEXEC) == -1)
522 {
523 dbg_log (_("cannot set socket to close on exec: %s"),
524 strerror (errno));
525 exit (1);
526 }
d6db0975 527
d67281a7 528 /* Set permissions for the socket. */
a95a08b4 529 chmod (_PATH_NSCDSOCKET, DEFFILEMODE);
d67281a7
UD
530
531 /* Set the socket up to accept connections. */
67479a70 532 if (listen (sock, SOMAXCONN) < 0)
d67281a7 533 {
67479a70
UD
534 dbg_log (_("cannot enable socket to accept connections: %s"),
535 strerror (errno));
d67281a7
UD
536 exit (1);
537 }
057685e4
UD
538
539 /* Change to unprivileged uid/gid/groups if specifed in config file */
540 if (server_user != NULL)
541 finish_drop_privileges ();
d67281a7
UD
542}
543
67479a70
UD
544
545/* Close the connections. */
d67281a7 546void
67479a70 547close_sockets (void)
d67281a7 548{
67479a70
UD
549 close (sock);
550}
d67281a7 551
a12ce44f 552
756409c4 553static void
549b3c3a 554invalidate_cache (char *key)
756409c4
UD
555{
556 dbtype number;
557
558 if (strcmp (key, "passwd") == 0)
559 number = pwddb;
560 else if (strcmp (key, "group") == 0)
561 number = grpdb;
23700036 562 else if (__builtin_expect (strcmp (key, "hosts"), 0) == 0)
482bbeb9
UD
563 {
564 number = hstdb;
565
566 /* Re-initialize the resolver. resolv.conf might have changed. */
567 res_init ();
568 }
23700036
UD
569 else
570 return;
756409c4 571
fd665070
UD
572 if (dbs[number].enabled)
573 prune_cache (&dbs[number], LONG_MAX);
756409c4
UD
574}
575
67479a70 576
c207f23b
UD
577#ifdef SCM_RIGHTS
578static void
579send_ro_fd (struct database_dyn *db, char *key, int fd)
580{
581 /* If we do not have an read-only file descriptor do nothing. */
582 if (db->ro_fd == -1)
583 return;
584
585 /* We need to send some data along with the descriptor. */
586 struct iovec iov[1];
587 iov[0].iov_base = key;
588 iov[0].iov_len = strlen (key) + 1;
589
590 /* Prepare the control message to transfer the descriptor. */
591 char buf[CMSG_SPACE (sizeof (int))];
592 struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
593 .msg_control = buf, .msg_controllen = sizeof (buf) };
594 struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
595
596 cmsg->cmsg_level = SOL_SOCKET;
597 cmsg->cmsg_type = SCM_RIGHTS;
598 cmsg->cmsg_len = CMSG_LEN (sizeof (int));
599
600 *(int *) CMSG_DATA (cmsg) = db->ro_fd;
601
602 msg.msg_controllen = cmsg->cmsg_len;
603
604 /* Send the control message. We repeat when we are interrupted but
605 everything else is ignored. */
606 (void) TEMP_FAILURE_RETRY (sendmsg (fd, &msg, 0));
607
608 if (__builtin_expect (debug_level > 0, 0))
609 dbg_log (_("provide access to FD %d, for %s"), db->ro_fd, key);
610}
611#endif /* SCM_RIGHTS */
612
613
67479a70
UD
614/* Handle new request. */
615static void
a1c542bf 616handle_request (int fd, request_header *req, void *key, uid_t uid)
67479a70 617{
23700036 618 if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
d67281a7 619 {
98e75a1c
UD
620 if (debug_level > 0)
621 dbg_log (_("\
67479a70 622cannot handle old request version %d; current version is %d"),
98e75a1c 623 req->version, NSCD_VERSION);
d67281a7
UD
624 return;
625 }
626
74a30a58
UD
627 /* Make the SELinux check before we go on to the standard checks. We
628 need to verify that the request type is valid, since it has not
629 yet been checked at this point. */
630 if (selinux_enabled
631 && __builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
632 && __builtin_expect (req->type, LASTREQ) < LASTREQ
633 && nscd_request_avc_has_perm (fd, req->type) != 0)
634 return;
635
a95a08b4
UD
636 struct database_dyn *db = serv2db[req->type];
637
f7e7a396
UD
638 // XXX Clean up so that each new command need not introduce a
639 // XXX new conditional.
d19687d6
UD
640 if ((__builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
641 && __builtin_expect (req->type, LASTDBREQ) <= LASTDBREQ)
f7e7a396 642 || req->type == GETAI || req->type == INITGROUPS)
d67281a7 643 {
23700036 644 if (__builtin_expect (debug_level, 0) > 0)
8d8c6efa
UD
645 {
646 if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
647 {
648 char buf[INET6_ADDRSTRLEN];
649
650 dbg_log ("\t%s (%s)", serv2str[req->type],
651 inet_ntop (req->type == GETHOSTBYADDR
652 ? AF_INET : AF_INET6,
653 key, buf, sizeof (buf)));
654 }
655 else
a95a08b4 656 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
8d8c6efa 657 }
d67281a7 658
67479a70
UD
659 /* Is this service enabled? */
660 if (!db->enabled)
661 {
ce85d65b 662 /* No, sent the prepared record. */
67479a70
UD
663 if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
664 db->disabled_iov->iov_len))
4c5dd2a2 665 != (ssize_t) db->disabled_iov->iov_len
23700036 666 && __builtin_expect (debug_level, 0) > 0)
67479a70
UD
667 {
668 /* We have problems sending the result. */
669 char buf[256];
670 dbg_log (_("cannot write result: %s"),
671 strerror_r (errno, buf, sizeof (buf)));
672 }
d67281a7 673
67479a70
UD
674 return;
675 }
d67281a7 676
67479a70 677 /* Be sure we can read the data. */
c86e6aec
UD
678 if (__builtin_expect (pthread_rwlock_tryrdlock (&db->lock) != 0, 0))
679 {
a95a08b4 680 ++db->head->rdlockdelayed;
c86e6aec
UD
681 pthread_rwlock_rdlock (&db->lock);
682 }
67479a70
UD
683
684 /* See whether we can handle it from the cache. */
a95a08b4
UD
685 struct datahead *cached;
686 cached = (struct datahead *) cache_search (req->type, key, req->key_len,
687 db, uid);
67479a70
UD
688 if (cached != NULL)
689 {
690 /* Hurray it's in the cache. */
a95a08b4
UD
691 if (TEMP_FAILURE_RETRY (write (fd, cached->data, cached->recsize))
692 != cached->recsize
23700036 693 && __builtin_expect (debug_level, 0) > 0)
67479a70
UD
694 {
695 /* We have problems sending the result. */
696 char buf[256];
697 dbg_log (_("cannot write result: %s"),
698 strerror_r (errno, buf, sizeof (buf)));
699 }
700
701 pthread_rwlock_unlock (&db->lock);
702
703 return;
704 }
705
706 pthread_rwlock_unlock (&db->lock);
d67281a7 707 }
23700036 708 else if (__builtin_expect (debug_level, 0) > 0)
756409c4
UD
709 {
710 if (req->type == INVALIDATE)
c207f23b 711 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
0532e21b 712 else
a95a08b4 713 dbg_log ("\t%s", serv2str[req->type]);
756409c4 714 }
67479a70
UD
715
716 /* Handle the request. */
717 switch (req->type)
d67281a7 718 {
67479a70 719 case GETPWBYNAME:
a95a08b4 720 addpwbyname (db, fd, req, key, uid);
67479a70
UD
721 break;
722
723 case GETPWBYUID:
a95a08b4 724 addpwbyuid (db, fd, req, key, uid);
67479a70
UD
725 break;
726
727 case GETGRBYNAME:
a95a08b4 728 addgrbyname (db, fd, req, key, uid);
67479a70
UD
729 break;
730
731 case GETGRBYGID:
a95a08b4 732 addgrbygid (db, fd, req, key, uid);
67479a70
UD
733 break;
734
735 case GETHOSTBYNAME:
a95a08b4 736 addhstbyname (db, fd, req, key, uid);
67479a70
UD
737 break;
738
739 case GETHOSTBYNAMEv6:
a95a08b4 740 addhstbynamev6 (db, fd, req, key, uid);
67479a70
UD
741 break;
742
743 case GETHOSTBYADDR:
a95a08b4 744 addhstbyaddr (db, fd, req, key, uid);
67479a70
UD
745 break;
746
747 case GETHOSTBYADDRv6:
a95a08b4 748 addhstbyaddrv6 (db, fd, req, key, uid);
67479a70
UD
749 break;
750
d19687d6
UD
751 case GETAI:
752 addhstai (db, fd, req, key, uid);
753 break;
754
f7e7a396
UD
755 case INITGROUPS:
756 addinitgroups (db, fd, req, key, uid);
757 break;
758
67479a70 759 case GETSTAT:
67479a70 760 case SHUTDOWN:
756409c4 761 case INVALIDATE:
a12ce44f 762 if (! secure_in_use)
54000924 763 {
a12ce44f 764 /* Get the callers credentials. */
cedc8559 765#ifdef SO_PEERCRED
be3c40b6
RM
766 struct ucred caller;
767 socklen_t optlen = sizeof (caller);
768
a1c542bf
UD
769 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
770 {
771 char buf[256];
772
773 dbg_log (_("error getting callers id: %s"),
774 strerror_r (errno, buf, sizeof (buf)));
a12ce44f 775 break;
a1c542bf 776 }
a12ce44f
UD
777
778 uid = caller.uid;
779#else
780 /* Some systems have no SO_PEERCRED implementation. They don't
781 care about security so we don't as well. */
782 uid = 0;
cedc8559 783#endif
a12ce44f
UD
784 }
785
786 /* Accept shutdown, getstat and invalidate only from root. For
787 the stat call also allow the user specified in the config file. */
788 if (req->type == GETSTAT)
789 {
790 if (uid == 0 || uid == stat_uid)
791 send_stats (fd, dbs);
792 }
793 else if (uid == 0)
794 {
795 if (req->type == INVALIDATE)
796 invalidate_cache (key);
797 else
798 termination_handler (0);
a1c542bf 799 }
67479a70
UD
800 break;
801
c207f23b
UD
802 case GETFDPW:
803 case GETFDGR:
804 case GETFDHST:
805#ifdef SCM_RIGHTS
806 send_ro_fd (serv2db[req->type], key, fd);
807#endif
808 break;
809
67479a70 810 default:
64acf8ed
UD
811 /* Ignore the command, it's nothing we know. */
812 break;
d67281a7 813 }
67479a70
UD
814}
815
d67281a7 816
4401d759
UD
817/* Restart the process. */
818static void
819restart (void)
820{
821 /* First determine the parameters. We do not use the parameters
822 passed to main() since in case nscd is started by running the
823 dynamic linker this will not work. Yes, this is not the usual
824 case but nscd is part of glibc and we occasionally do this. */
825 size_t buflen = 1024;
826 char *buf = alloca (buflen);
827 size_t readlen = 0;
828 int fd = open ("/proc/self/cmdline", O_RDONLY);
829 if (fd == -1)
830 {
831 dbg_log (_("\
832cannot open /proc/self/cmdline: %s; disabling paranoia mode"),
833 strerror (errno));
834
835 paranoia = 0;
836 return;
837 }
838
839 while (1)
840 {
841 ssize_t n = TEMP_FAILURE_RETRY (read (fd, buf + readlen,
842 buflen - readlen));
843 if (n == -1)
844 {
845 dbg_log (_("\
846cannot open /proc/self/cmdline: %s; disabling paranoia mode"),
847 strerror (errno));
848
849 close (fd);
850 paranoia = 0;
851 return;
852 }
853
854 readlen += n;
855
856 if (readlen < buflen)
857 break;
858
859 /* We might have to extend the buffer. */
860 size_t old_buflen = buflen;
861 char *newp = extend_alloca (buf, buflen, 2 * buflen);
862 buf = memmove (newp, buf, old_buflen);
863 }
864
865 close (fd);
866
867 /* Parse the command line. Worst case scenario: every two
868 characters form one parameter (one character plus NUL). */
869 char **argv = alloca ((readlen / 2 + 1) * sizeof (argv[0]));
870 int argc = 0;
871
872 char *cp = buf;
873 while (cp < buf + readlen)
874 {
875 argv[argc++] = cp;
876 cp = (char *) rawmemchr (cp, '\0') + 1;
877 }
878 argv[argc] = NULL;
879
880 /* Second, change back to the old user if we changed it. */
881 if (server_user != NULL)
882 {
883 if (setuid (old_uid) != 0)
884 {
885 dbg_log (_("\
886cannot change to old UID: %s; disabling paranoia mode"),
887 strerror (errno));
888
889 paranoia = 0;
890 return;
891 }
892
893 if (setgid (old_gid) != 0)
894 {
895 dbg_log (_("\
896cannot change to old GID: %s; disabling paranoia mode"),
897 strerror (errno));
898
899 setuid (server_uid);
900 paranoia = 0;
901 return;
902 }
903 }
904
905 /* Next change back to the old working directory. */
906 if (chdir (oldcwd) == -1)
907 {
908 dbg_log (_("\
909cannot change to old working directory: %s; disabling paranoia mode"),
910 strerror (errno));
911
912 if (server_user != NULL)
913 {
914 setuid (server_uid);
915 setgid (server_gid);
916 }
917 paranoia = 0;
918 return;
919 }
920
921 /* Synchronize memory. */
922 for (int cnt = 0; cnt < lastdb; ++cnt)
923 {
924 /* Make sure nobody keeps using the database. */
925 dbs[cnt].head->timestamp = 0;
926
927 if (dbs[cnt].persistent)
928 // XXX async OK?
929 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
930 }
931
932 /* The preparations are done. */
933 execv ("/proc/self/exe", argv);
934
935 /* If we come here, we will never be able to re-exec. */
936 dbg_log (_("re-exec failed: %s; disabling paranoia mode"),
937 strerror (errno));
938
939 if (server_user != NULL)
940 {
941 setuid (server_uid);
942 setgid (server_gid);
943 }
944 chdir ("/");
945 paranoia = 0;
946}
947
948
1945c96f
UD
949/* List of file descriptors. */
950struct fdlist
951{
952 int fd;
953 struct fdlist *next;
954};
955/* Memory allocated for the list. */
956static struct fdlist *fdlist;
957/* List of currently ready-to-read file descriptors. */
958static struct fdlist *readylist;
959
960/* Conditional variable and mutex to signal availability of entries in
961 READYLIST. The condvar is initialized dynamically since we might
962 use a different clock depending on availability. */
963static pthread_cond_t readylist_cond;
964static pthread_mutex_t readylist_lock = PTHREAD_MUTEX_INITIALIZER;
965
966/* The clock to use with the condvar. */
967static clockid_t timeout_clock = CLOCK_REALTIME;
968
969/* Number of threads ready to handle the READYLIST. */
970static unsigned long int nready;
971
972
67479a70
UD
973/* This is the main loop. It is replicated in different threads but the
974 `poll' call makes sure only one thread handles an incoming connection. */
975static void *
976__attribute__ ((__noreturn__))
977nscd_run (void *p)
978{
1945c96f
UD
979 const long int my_number = (long int) p;
980 const int run_prune = my_number < lastdb && dbs[my_number].enabled;
981 struct timespec prune_ts;
982 int to = 0;
983 char buf[256];
264d5b94 984
72ae1e97 985 if (run_prune)
1945c96f
UD
986 {
987 setup_thread (&dbs[my_number]);
081fc592 988
1945c96f
UD
989 /* We are running. */
990 dbs[my_number].head->timestamp = time (NULL);
d67281a7 991
1945c96f
UD
992 if (clock_gettime (timeout_clock, &prune_ts) == -1)
993 /* Should never happen. */
994 abort ();
0fdb4f42 995
1945c96f
UD
996 /* Compute timeout time. */
997 prune_ts.tv_sec += CACHE_PRUNE_INTERVAL;
998 }
999
1000 /* Initial locking. */
1001 pthread_mutex_lock (&readylist_lock);
1002
1003 /* One more thread available. */
1004 ++nready;
0fdb4f42 1005
1945c96f
UD
1006 while (1)
1007 {
1008 while (readylist == NULL)
d6db0975 1009 {
d6db0975
UD
1010 if (run_prune)
1011 {
1945c96f
UD
1012 /* Wait, but not forever. */
1013 to = pthread_cond_timedwait (&readylist_cond, &readylist_lock,
1014 &prune_ts);
1015
1016 /* If we were woken and there is no work to be done,
1017 just start pruning. */
1018 if (readylist == NULL && to == ETIMEDOUT)
1019 {
4401d759 1020 --nready;
1945c96f
UD
1021 pthread_mutex_unlock (&readylist_lock);
1022 goto only_prune;
1023 }
d6db0975 1024 }
1945c96f
UD
1025 else
1026 /* No need to timeout. */
1027 pthread_cond_wait (&readylist_cond, &readylist_lock);
1028 }
0fdb4f42 1029
1945c96f
UD
1030 struct fdlist *it = readylist->next;
1031 if (readylist->next == readylist)
1032 /* Just one entry on the list. */
1033 readylist = NULL;
1034 else
1035 readylist->next = it->next;
0fdb4f42 1036
1945c96f
UD
1037 /* Extract the information and mark the record ready to be used
1038 again. */
1039 int fd = it->fd;
1040 it->next = NULL;
0fdb4f42 1041
1945c96f
UD
1042 /* One more thread available. */
1043 --nready;
67479a70 1044
1945c96f
UD
1045 /* We are done with the list. */
1046 pthread_mutex_unlock (&readylist_lock);
67479a70 1047
1945c96f
UD
1048 /* We do not want to block on a short read or so. */
1049 int fl = fcntl (fd, F_GETFL);
1050 if (fl == -1 || fcntl (fd, F_SETFL, fl | O_NONBLOCK) == -1)
1051 goto close_and_out;
0fdb4f42
UD
1052
1053 /* Now read the request. */
1945c96f 1054 request_header req;
0fdb4f42
UD
1055 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
1056 != sizeof (req), 0))
d67281a7 1057 {
1945c96f
UD
1058 /* We failed to read data. Note that this also might mean we
1059 failed because we would have blocked. */
0fdb4f42
UD
1060 if (debug_level > 0)
1061 dbg_log (_("short read while reading request: %s"),
1062 strerror_r (errno, buf, sizeof (buf)));
1945c96f 1063 goto close_and_out;
0fdb4f42
UD
1064 }
1065
3c82c131
UD
1066 /* Check whether this is a valid request type. */
1067 if (req.type < GETPWBYNAME || req.type >= LASTREQ)
1068 goto close_and_out;
1069
0fdb4f42
UD
1070 /* Some systems have no SO_PEERCRED implementation. They don't
1071 care about security so we don't as well. */
1945c96f 1072 uid_t uid = -1;
c86e6aec 1073#ifdef SO_PEERCRED
1945c96f
UD
1074 pid_t pid = 0;
1075
0fdb4f42
UD
1076 if (secure_in_use)
1077 {
1078 struct ucred caller;
1079 socklen_t optlen = sizeof (caller);
d67281a7 1080
0fdb4f42 1081 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
d67281a7 1082 {
0fdb4f42 1083 dbg_log (_("error getting callers id: %s"),
67479a70 1084 strerror_r (errno, buf, sizeof (buf)));
3c82c131 1085 goto close_and_out;
67479a70 1086 }
264d5b94 1087
0fdb4f42 1088 if (req.type < GETPWBYNAME || req.type > LASTDBREQ
a95a08b4 1089 || serv2db[req.type]->secure)
0fdb4f42 1090 uid = caller.uid;
c86e6aec 1091
a12ce44f 1092 pid = caller.pid;
0fdb4f42
UD
1093 }
1094 else if (__builtin_expect (debug_level > 0, 0))
1095 {
1096 struct ucred caller;
1097 socklen_t optlen = sizeof (caller);
c86e6aec 1098
0fdb4f42
UD
1099 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) == 0)
1100 pid = caller.pid;
1101 }
cedc8559 1102#endif
a1c542bf 1103
0fdb4f42
UD
1104 /* It should not be possible to crash the nscd with a silly
1105 request (i.e., a terribly large key). We limit the size to 1kb. */
1945c96f 1106#define MAXKEYLEN 1024
0fdb4f42 1107 if (__builtin_expect (req.key_len, 1) < 0
1945c96f 1108 || __builtin_expect (req.key_len, 1) > MAXKEYLEN)
0fdb4f42
UD
1109 {
1110 if (debug_level > 0)
1111 dbg_log (_("key length in request too long: %d"), req.key_len);
0fdb4f42
UD
1112 }
1113 else
1114 {
1115 /* Get the key. */
1945c96f 1116 char keybuf[MAXKEYLEN];
0fdb4f42
UD
1117
1118 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
1119 req.key_len))
1120 != req.key_len, 0))
67479a70 1121 {
1945c96f 1122 /* Again, this can also mean we would have blocked. */
98e75a1c 1123 if (debug_level > 0)
0fdb4f42
UD
1124 dbg_log (_("short read while reading request key: %s"),
1125 strerror_r (errno, buf, sizeof (buf)));
1945c96f 1126 goto close_and_out;
67479a70 1127 }
0fdb4f42
UD
1128
1129 if (__builtin_expect (debug_level, 0) > 0)
67479a70 1130 {
c86e6aec 1131#ifdef SO_PEERCRED
0fdb4f42
UD
1132 if (pid != 0)
1133 dbg_log (_("\
c86e6aec 1134handle_request: request received (Version = %d) from PID %ld"),
0fdb4f42
UD
1135 req.version, (long int) pid);
1136 else
c86e6aec 1137#endif
0fdb4f42 1138 dbg_log (_("\
c86e6aec 1139handle_request: request received (Version = %d)"), req.version);
0fdb4f42 1140 }
c86e6aec 1141
0fdb4f42
UD
1142 /* Phew, we got all the data, now process it. */
1143 handle_request (fd, &req, keybuf, uid);
d67281a7 1144 }
264d5b94 1145
3c82c131
UD
1146 close_and_out:
1147 /* We are done. */
1148 close (fd);
1149
1945c96f
UD
1150 /* Check whether we should be pruning the cache. */
1151 assert (run_prune || to == 0);
1152 if (to == ETIMEDOUT)
1153 {
1154 only_prune:
1155 /* The pthread_cond_timedwait() call timed out. It is time
1156 to clean up the cache. */
1157 assert (my_number < lastdb);
1158 prune_cache (&dbs[my_number],
1159 prune_ts.tv_sec + (prune_ts.tv_nsec >= 500000000));
1160
1161 if (clock_gettime (timeout_clock, &prune_ts) == -1)
1162 /* Should never happen. */
1163 abort ();
1164
1165 /* Compute next timeout time. */
1166 prune_ts.tv_sec += CACHE_PRUNE_INTERVAL;
1167
1168 /* In case the list is emtpy we do not want to run the prune
1169 code right away again. */
1170 to = 0;
1171 }
1172
1173 /* Re-locking. */
1174 pthread_mutex_lock (&readylist_lock);
1175
1176 /* One more thread available. */
1177 ++nready;
1178 }
1179}
1180
1181
fc03df7a
UD
1182static unsigned int nconns;
1183
1945c96f 1184static void
fc03df7a 1185fd_ready (int fd)
1945c96f 1186{
fc03df7a
UD
1187 pthread_mutex_lock (&readylist_lock);
1188
1189 /* Find an empty entry in FDLIST. */
1190 size_t inner;
1191 for (inner = 0; inner < nconns; ++inner)
1192 if (fdlist[inner].next == NULL)
1193 break;
1194 assert (inner < nconns);
1195
1196 fdlist[inner].fd = fd;
1197
1198 if (readylist == NULL)
1199 readylist = fdlist[inner].next = &fdlist[inner];
1945c96f 1200 else
fc03df7a
UD
1201 {
1202 fdlist[inner].next = readylist->next;
1203 readylist = readylist->next = &fdlist[inner];
1204 }
1205
1206 bool do_signal = true;
1207 if (__builtin_expect (nready == 0, 0))
1208 {
1209 ++client_queued;
1210 do_signal = false;
27e82856
UD
1211
1212 /* Try to start another thread to help out. */
1213 pthread_t th;
1214 if (nthreads < max_nthreads
1215 && pthread_create (&th, &attr, nscd_run,
1216 (void *) (long int) nthreads) == 0)
1217 {
1218 /* We got another thread. */
1219 ++nthreads;
1220 /* The new thread might new a kick. */
1221 do_signal = true;
1222 }
1223
fc03df7a
UD
1224 }
1225
1226 pthread_mutex_unlock (&readylist_lock);
1227
1228 /* Tell one of the worker threads there is work to do. */
1229 if (do_signal)
1230 pthread_cond_signal (&readylist_cond);
1231}
1945c96f 1232
fc03df7a 1233
4401d759
UD
1234/* Check whether restarting should happen. */
1235static inline int
1236restart_p (time_t now)
1237{
1238 return (paranoia && readylist == NULL && nready == nthreads
1239 && now >= restart_time);
1240}
1241
1242
1243/* Array for times a connection was accepted. */
fc03df7a
UD
1244static time_t *starttime;
1245
1246
1247static void
1248__attribute__ ((__noreturn__))
1249main_loop_poll (void)
1250{
1945c96f
UD
1251 struct pollfd *conns = (struct pollfd *) xmalloc (nconns
1252 * sizeof (conns[0]));
1253
1945c96f
UD
1254 conns[0].fd = sock;
1255 conns[0].events = POLLRDNORM;
1256 size_t nused = 1;
1257 size_t firstfree = 1;
1258
1259 while (1)
1260 {
1261 /* Wait for any event. We wait at most a couple of seconds so
1262 that we can check whether we should close any of the accepted
1263 connections since we have not received a request. */
1264#define MAX_ACCEPT_TIMEOUT 30
1265#define MIN_ACCEPT_TIMEOUT 5
1266#define MAIN_THREAD_TIMEOUT \
1267 (MAX_ACCEPT_TIMEOUT * 1000 \
1268 - ((MAX_ACCEPT_TIMEOUT - MIN_ACCEPT_TIMEOUT) * 1000 * nused) / (2 * nconns))
1269
1270 int n = poll (conns, nused, MAIN_THREAD_TIMEOUT);
1271
1272 time_t now = time (NULL);
1273
1274 /* If there is a descriptor ready for reading or there is a new
1275 connection, process this now. */
1276 if (n > 0)
67479a70 1277 {
1945c96f
UD
1278 if (conns[0].revents != 0)
1279 {
1280 /* We have a new incoming connection. Accept the connection. */
1281 int fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL));
1282
fc03df7a
UD
1283 /* use the descriptor if we have not reached the limit. */
1284 if (fd >= 0 && firstfree < nconns)
1945c96f 1285 {
1945c96f
UD
1286 conns[firstfree].fd = fd;
1287 conns[firstfree].events = POLLRDNORM;
1288 starttime[firstfree] = now;
1289 if (firstfree >= nused)
1290 nused = firstfree + 1;
1291
1292 do
1293 ++firstfree;
1294 while (firstfree < nused && conns[firstfree].fd != -1);
1295 }
1296
1945c96f
UD
1297 --n;
1298 }
1299
1300 for (size_t cnt = 1; cnt < nused && n > 0; ++cnt)
1301 if (conns[cnt].revents != 0)
1302 {
fc03df7a 1303 fd_ready (conns[cnt].fd);
1945c96f
UD
1304
1305 /* Clean up the CONNS array. */
1306 conns[cnt].fd = -1;
1307 if (cnt < firstfree)
1308 firstfree = cnt;
1309 if (cnt == nused - 1)
1310 do
1311 --nused;
1312 while (conns[nused - 1].fd == -1);
1313
1314 --n;
1315 }
1316 }
1317
1318 /* Now find entries which have timed out. */
1319 assert (nused > 0);
fc03df7a
UD
1320
1321 /* We make the timeout length depend on the number of file
1322 descriptors currently used. */
1945c96f
UD
1323#define ACCEPT_TIMEOUT \
1324 (MAX_ACCEPT_TIMEOUT \
1325 - ((MAX_ACCEPT_TIMEOUT - MIN_ACCEPT_TIMEOUT) * nused) / nconns)
fc03df7a 1326 time_t laststart = now - ACCEPT_TIMEOUT;
1945c96f 1327
fc03df7a
UD
1328 for (size_t cnt = nused - 1; cnt > 0; --cnt)
1329 {
1945c96f
UD
1330 if (conns[cnt].fd != -1 && starttime[cnt] < laststart)
1331 {
1332 /* Remove the entry, it timed out. */
1333 (void) close (conns[cnt].fd);
1334 conns[cnt].fd = -1;
1335
1336 if (cnt < firstfree)
1337 firstfree = cnt;
1338 if (cnt == nused - 1)
1339 do
1340 --nused;
1341 while (conns[nused - 1].fd == -1);
1342 }
67479a70 1343 }
4401d759
UD
1344
1345 if (restart_p (now))
1346 restart ();
67308730 1347 }
d67281a7
UD
1348}
1349
67479a70 1350
fc03df7a
UD
1351#ifdef HAVE_EPOLL
1352static void
1353main_loop_epoll (int efd)
1354{
1355 struct epoll_event ev = { 0, };
1356 int nused = 1;
1357 size_t highest = 0;
1358
1359 /* Add the socket. */
1360 ev.events = EPOLLRDNORM;
1361 ev.data.fd = sock;
1362 if (epoll_ctl (efd, EPOLL_CTL_ADD, sock, &ev) == -1)
1363 /* We cannot use epoll. */
1364 return;
1365
1366 while (1)
1367 {
1368 struct epoll_event revs[100];
1369# define nrevs (sizeof (revs) / sizeof (revs[0]))
1370
1371 int n = epoll_wait (efd, revs, nrevs, MAIN_THREAD_TIMEOUT);
1372
1373 time_t now = time (NULL);
1374
1375 for (int cnt = 0; cnt < n; ++cnt)
1376 if (revs[cnt].data.fd == sock)
1377 {
1378 /* A new connection. */
1379 int fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL));
1380
1381 if (fd >= 0)
1382 {
1383 /* Try to add the new descriptor. */
1384 ev.data.fd = fd;
1385 if (fd >= nconns
1386 || epoll_ctl (efd, EPOLL_CTL_ADD, fd, &ev) == -1)
1387 /* The descriptor is too large or something went
1388 wrong. Close the descriptor. */
1389 close (fd);
1390 else
1391 {
1392 /* Remember when we accepted the connection. */
1393 starttime[fd] = now;
1394
1395 if (fd > highest)
1396 highest = fd;
1397
1398 ++nused;
1399 }
1400 }
1401 }
1402 else
1403 {
1404 /* Remove the descriptor from the epoll descriptor. */
1405 struct epoll_event ev = { 0, };
1406 (void) epoll_ctl (efd, EPOLL_CTL_DEL, revs[cnt].data.fd, &ev);
1407
1408 /* Get a worked to handle the request. */
1409 fd_ready (revs[cnt].data.fd);
1410
1411 /* Reset the time. */
1412 starttime[revs[cnt].data.fd] = 0;
1413 if (revs[cnt].data.fd == highest)
1414 do
1415 --highest;
1416 while (highest > 0 && starttime[highest] == 0);
1417
1418 --nused;
1419 }
1420
1421 /* Now look for descriptors for accepted connections which have
1422 no reply in too long of a time. */
1423 time_t laststart = now - ACCEPT_TIMEOUT;
1424 for (int cnt = highest; cnt > STDERR_FILENO; --cnt)
1425 if (cnt != sock && starttime[cnt] != 0 && starttime[cnt] < laststart)
1426 {
1427 /* We are waiting for this one for too long. Close it. */
1428 struct epoll_event ev = {0, };
1429 (void) epoll_ctl (efd, EPOLL_CTL_DEL, cnt, &ev);
1430
1431 (void) close (cnt);
1432
1433 starttime[cnt] = 0;
1434 if (cnt == highest)
1435 --highest;
1436 }
1437 else if (cnt != sock && starttime[cnt] == 0 && cnt == highest)
1438 --highest;
4401d759
UD
1439
1440 if (restart_p (now))
1441 restart ();
fc03df7a
UD
1442 }
1443}
1444#endif
1445
1446
67479a70 1447/* Start all the threads we want. The initial process is thread no. 1. */
d67281a7 1448void
67479a70 1449start_threads (void)
d67281a7 1450{
1945c96f
UD
1451 /* Initialize the conditional variable we will use. The only
1452 non-standard attribute we might use is the clock selection. */
1453 pthread_condattr_t condattr;
1454 pthread_condattr_init (&condattr);
1455
3078cba2
UD
1456#if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0 \
1457 && defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
1945c96f
UD
1458 /* Determine whether the monotonous clock is available. */
1459 struct timespec dummy;
3078cba2 1460# if _POSIX_MONOTONIC_CLOCK == 0
94d824f9 1461 if (sysconf (_SC_MONOTONIC_CLOCK) > 0)
3078cba2
UD
1462# endif
1463# if _POSIX_CLOCK_SELECTION == 0
94d824f9 1464 if (sysconf (_SC_CLOCK_SELECTION) > 0)
3078cba2 1465# endif
94d824f9
UD
1466 if (clock_getres (CLOCK_MONOTONIC, &dummy) == 0
1467 && pthread_condattr_setclock (&condattr, CLOCK_MONOTONIC) == 0)
1468 timeout_clock = CLOCK_MONOTONIC;
1945c96f 1469#endif
d67281a7 1470
1945c96f
UD
1471 pthread_cond_init (&readylist_cond, &condattr);
1472 pthread_condattr_destroy (&condattr);
1473
1474
1475 /* Create the attribute for the threads. They are all created
1476 detached. */
67479a70
UD
1477 pthread_attr_init (&attr);
1478 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
27e82856
UD
1479 /* Use 1MB stacks, twice as much for 64-bit architectures. */
1480 pthread_attr_setstacksize (&attr, 1024 * 1024 * (sizeof (void *) / 4));
d67281a7 1481
67479a70
UD
1482 /* We allow less than LASTDB threads only for debugging. */
1483 if (debug_level == 0)
1484 nthreads = MAX (nthreads, lastdb);
d67281a7 1485
27e82856 1486 int nfailed = 0;
1945c96f
UD
1487 for (long int i = 0; i < nthreads; ++i)
1488 {
1489 pthread_t th;
27e82856
UD
1490 if (pthread_create (&th, &attr, nscd_run, (void *) (i - nfailed)) != 0)
1491 ++nfailed;
1492 }
1493 if (nthreads - nfailed < lastdb)
1494 {
1495 /* We could not start enough threads. */
1496 dbg_log (_("could only start %d threads; terminating"),
1497 nthreads - nfailed);
1498 exit (1);
1945c96f 1499 }
d67281a7 1500
fc03df7a
UD
1501 /* Determine how much room for descriptors we should initially
1502 allocate. This might need to change later if we cap the number
1503 with MAXCONN. */
1504 const long int nfds = sysconf (_SC_OPEN_MAX);
1505#define MINCONN 32
1506#define MAXCONN 16384
1507 if (nfds == -1 || nfds > MAXCONN)
1508 nconns = MAXCONN;
1509 else if (nfds < MINCONN)
1510 nconns = MINCONN;
1511 else
1512 nconns = nfds;
1513
1514 /* We need memory to pass descriptors on to the worker threads. */
1515 fdlist = (struct fdlist *) xcalloc (nconns, sizeof (fdlist[0]));
1516 /* Array to keep track when connection was accepted. */
1517 starttime = (time_t *) xcalloc (nconns, sizeof (starttime[0]));
1518
1945c96f
UD
1519 /* In the main thread we execute the loop which handles incoming
1520 connections. */
fc03df7a
UD
1521#ifdef HAVE_EPOLL
1522 int efd = epoll_create (100);
1523 if (efd != -1)
1524 {
1525 main_loop_epoll (efd);
1526 close (efd);
1527 }
1528#endif
1529
1530 main_loop_poll ();
d67281a7 1531}
057685e4
UD
1532
1533
1534/* Look up the uid, gid, and supplementary groups to run nscd as. When
1535 this function is called, we are not listening on the nscd socket yet so
1536 we can just use the ordinary lookup functions without causing a lockup */
1537static void
1538begin_drop_privileges (void)
1539{
a95a08b4 1540 struct passwd *pwd = getpwnam (server_user);
057685e4
UD
1541
1542 if (pwd == NULL)
1543 {
1544 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1545 error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"),
1546 server_user);
1547 }
1548
1549 server_uid = pwd->pw_uid;
1550 server_gid = pwd->pw_gid;
1551
4401d759
UD
1552 /* Save the old UID/GID if we have to change back. */
1553 if (paranoia)
1554 {
1555 old_uid = getuid ();
1556 old_gid = getgid ();
1557 }
1558
a95a08b4
UD
1559 if (getgrouplist (server_user, server_gid, NULL, &server_ngroups) == 0)
1560 {
1561 /* This really must never happen. */
1562 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1563 error (EXIT_FAILURE, errno, _("initial getgrouplist failed"));
1564 }
057685e4 1565
a95a08b4 1566 server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
057685e4
UD
1567
1568 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
1569 == -1)
1570 {
1571 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1572 error (EXIT_FAILURE, errno, _("getgrouplist failed"));
1573 }
1574}
1575
1576
1577/* Call setgroups(), setgid(), and setuid() to drop root privileges and
1578 run nscd as the user specified in the configuration file. */
1579static void
1580finish_drop_privileges (void)
1581{
1582 if (setgroups (server_ngroups, server_groups) == -1)
1583 {
1584 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1585 error (EXIT_FAILURE, errno, _("setgroups failed"));
1586 }
1587
1588 if (setgid (server_gid) == -1)
1589 {
1590 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1591 perror ("setgid");
1592 exit (1);
1593 }
1594
1595 if (setuid (server_uid) == -1)
1596 {
1597 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
1598 perror ("setuid");
1599 exit (1);
1600 }
1601}