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