]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/connections.c
Fix Wundef warning for SEPARATE_KEY
[thirdparty/glibc.git] / nscd / connections.c
CommitLineData
67479a70 1/* Inner loops of cache daemon.
d4697bc9 2 Copyright (C) 1998-2014 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
43bc8ac6 6 This program is free software; you can redistribute it and/or modify
2e2efe65
RM
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; version 2 of the License, or
9 (at your option) any later version.
d67281a7 10
43bc8ac6 11 This program is distributed in the hope that it will be useful,
d67281a7 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
43bc8ac6
UD
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
d67281a7 15
43bc8ac6 16 You should have received a copy of the GNU General Public License
59ba27a6 17 along with this program; if not, see <http://www.gnu.org/licenses/>. */
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>
3a2c0242 26#include <ifaddrs.h>
a95a08b4 27#include <libintl.h>
d67281a7 28#include <pthread.h>
057685e4 29#include <pwd.h>
482bbeb9 30#include <resolv.h>
057685e4 31#include <stdio.h>
d67281a7
UD
32#include <stdlib.h>
33#include <unistd.h>
e054f494 34#include <stdint.h>
8d8c6efa 35#include <arpa/inet.h>
3a2c0242 36#ifdef HAVE_NETLINK
432d41ce
UD
37# include <linux/netlink.h>
38# include <linux/rtnetlink.h>
3a2c0242 39#endif
fc03df7a
UD
40#ifdef HAVE_EPOLL
41# include <sys/epoll.h>
42#endif
5228ba2f
UD
43#ifdef HAVE_INOTIFY
44# include <sys/inotify.h>
45#endif
a95a08b4 46#include <sys/mman.h>
67479a70 47#include <sys/param.h>
a53bad16 48#include <sys/poll.h>
eac10791
UD
49#ifdef HAVE_SENDFILE
50# include <sys/sendfile.h>
51#endif
d67281a7
UD
52#include <sys/socket.h>
53#include <sys/stat.h>
d67281a7
UD
54#include <sys/un.h>
55
56#include "nscd.h"
57#include "dbg_log.h"
74a30a58 58#include "selinux.h"
a0edbb48 59#include <resolv/resolv.h>
37233df9
TS
60
61#include <kernel-features.h>
a334319f
UD
62
63
057685e4
UD
64/* Support to run nscd as an unprivileged user */
65const char *server_user;
66static uid_t server_uid;
67static gid_t server_gid;
a12ce44f
UD
68const char *stat_user;
69uid_t stat_uid;
057685e4
UD
70static gid_t *server_groups;
71#ifndef NGROUPS
72# define NGROUPS 32
73#endif
a95a08b4 74static int server_ngroups;
057685e4 75
27e82856
UD
76static pthread_attr_t attr;
77
057685e4
UD
78static void begin_drop_privileges (void);
79static void finish_drop_privileges (void);
80
67479a70 81/* Map request type to a string. */
b21fa963 82const char *const serv2str[LASTREQ] =
d67281a7 83{
67479a70
UD
84 [GETPWBYNAME] = "GETPWBYNAME",
85 [GETPWBYUID] = "GETPWBYUID",
86 [GETGRBYNAME] = "GETGRBYNAME",
87 [GETGRBYGID] = "GETGRBYGID",
88 [GETHOSTBYNAME] = "GETHOSTBYNAME",
89 [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6",
90 [GETHOSTBYADDR] = "GETHOSTBYADDR",
91 [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
92 [SHUTDOWN] = "SHUTDOWN",
756409c4 93 [GETSTAT] = "GETSTAT",
c207f23b
UD
94 [INVALIDATE] = "INVALIDATE",
95 [GETFDPW] = "GETFDPW",
96 [GETFDGR] = "GETFDGR",
d19687d6 97 [GETFDHST] = "GETFDHST",
f7e7a396 98 [GETAI] = "GETAI",
b21fa963
UD
99 [INITGROUPS] = "INITGROUPS",
100 [GETSERVBYNAME] = "GETSERVBYNAME",
101 [GETSERVBYPORT] = "GETSERVBYPORT",
684ae515
UD
102 [GETFDSERV] = "GETFDSERV",
103 [GETNETGRENT] = "GETNETGRENT",
104 [INNETGR] = "INNETGR",
105 [GETFDNETGR] = "GETFDNETGR"
67479a70
UD
106};
107
108/* The control data structures for the services. */
a95a08b4 109struct database_dyn dbs[lastdb] =
67479a70
UD
110{
111 [pwddb] = {
c2e13112 112 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
ffb1b882 113 .prune_lock = PTHREAD_MUTEX_INITIALIZER,
cd72adeb 114 .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
c2e13112
RM
115 .enabled = 0,
116 .check_file = 1,
a95a08b4 117 .persistent = 0,
797ed6f7 118 .propagate = 1,
c207f23b 119 .shared = 0,
2c210d1e 120 .max_db_size = DEFAULT_MAX_DB_SIZE,
27c377dd 121 .suggested_module = DEFAULT_SUGGESTED_MODULE,
a95a08b4 122 .db_filename = _PATH_NSCD_PASSWD_DB,
c2e13112
RM
123 .disabled_iov = &pwd_iov_disabled,
124 .postimeout = 3600,
a95a08b4
UD
125 .negtimeout = 20,
126 .wr_fd = -1,
127 .ro_fd = -1,
128 .mmap_used = false
67479a70
UD
129 },
130 [grpdb] = {
c2e13112 131 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
ffb1b882 132 .prune_lock = PTHREAD_MUTEX_INITIALIZER,
cd72adeb 133 .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
c2e13112
RM
134 .enabled = 0,
135 .check_file = 1,
a95a08b4 136 .persistent = 0,
797ed6f7 137 .propagate = 1,
c207f23b 138 .shared = 0,
2c210d1e 139 .max_db_size = DEFAULT_MAX_DB_SIZE,
27c377dd 140 .suggested_module = DEFAULT_SUGGESTED_MODULE,
a95a08b4 141 .db_filename = _PATH_NSCD_GROUP_DB,
c2e13112
RM
142 .disabled_iov = &grp_iov_disabled,
143 .postimeout = 3600,
a95a08b4
UD
144 .negtimeout = 60,
145 .wr_fd = -1,
146 .ro_fd = -1,
147 .mmap_used = false
67479a70
UD
148 },
149 [hstdb] = {
c2e13112 150 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
ffb1b882 151 .prune_lock = PTHREAD_MUTEX_INITIALIZER,
cd72adeb 152 .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
c2e13112
RM
153 .enabled = 0,
154 .check_file = 1,
a95a08b4 155 .persistent = 0,
797ed6f7 156 .propagate = 0, /* Not used. */
c207f23b 157 .shared = 0,
2c210d1e 158 .max_db_size = DEFAULT_MAX_DB_SIZE,
27c377dd 159 .suggested_module = DEFAULT_SUGGESTED_MODULE,
a95a08b4 160 .db_filename = _PATH_NSCD_HOSTS_DB,
c2e13112
RM
161 .disabled_iov = &hst_iov_disabled,
162 .postimeout = 3600,
a95a08b4
UD
163 .negtimeout = 20,
164 .wr_fd = -1,
165 .ro_fd = -1,
166 .mmap_used = false
b21fa963
UD
167 },
168 [servdb] = {
169 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
ffb1b882 170 .prune_lock = PTHREAD_MUTEX_INITIALIZER,
cd72adeb 171 .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
b21fa963
UD
172 .enabled = 0,
173 .check_file = 1,
174 .persistent = 0,
175 .propagate = 0, /* Not used. */
176 .shared = 0,
177 .max_db_size = DEFAULT_MAX_DB_SIZE,
27c377dd 178 .suggested_module = DEFAULT_SUGGESTED_MODULE,
b21fa963
UD
179 .db_filename = _PATH_NSCD_SERVICES_DB,
180 .disabled_iov = &serv_iov_disabled,
181 .postimeout = 28800,
182 .negtimeout = 20,
183 .wr_fd = -1,
184 .ro_fd = -1,
185 .mmap_used = false
684ae515
UD
186 },
187 [netgrdb] = {
188 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
189 .prune_lock = PTHREAD_MUTEX_INITIALIZER,
190 .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
191 .enabled = 0,
192 .check_file = 1,
193 .persistent = 0,
194 .propagate = 0, /* Not used. */
195 .shared = 0,
196 .max_db_size = DEFAULT_MAX_DB_SIZE,
197 .suggested_module = DEFAULT_SUGGESTED_MODULE,
198 .db_filename = _PATH_NSCD_NETGROUP_DB,
199 .disabled_iov = &netgroup_iov_disabled,
200 .postimeout = 28800,
201 .negtimeout = 20,
202 .wr_fd = -1,
203 .ro_fd = -1,
204 .mmap_used = false
67479a70
UD
205 }
206};
d67281a7 207
a95a08b4
UD
208
209/* Mapping of request type to database. */
9691d83c 210static struct
a95a08b4 211{
9691d83c
UD
212 bool data_request;
213 struct database_dyn *db;
000b027e 214} const reqinfo[LASTREQ] =
9691d83c
UD
215{
216 [GETPWBYNAME] = { true, &dbs[pwddb] },
217 [GETPWBYUID] = { true, &dbs[pwddb] },
218 [GETGRBYNAME] = { true, &dbs[grpdb] },
219 [GETGRBYGID] = { true, &dbs[grpdb] },
220 [GETHOSTBYNAME] = { true, &dbs[hstdb] },
221 [GETHOSTBYNAMEv6] = { true, &dbs[hstdb] },
222 [GETHOSTBYADDR] = { true, &dbs[hstdb] },
223 [GETHOSTBYADDRv6] = { true, &dbs[hstdb] },
224 [SHUTDOWN] = { false, NULL },
225 [GETSTAT] = { false, NULL },
226 [SHUTDOWN] = { false, NULL },
227 [GETFDPW] = { false, &dbs[pwddb] },
228 [GETFDGR] = { false, &dbs[grpdb] },
229 [GETFDHST] = { false, &dbs[hstdb] },
230 [GETAI] = { true, &dbs[hstdb] },
231 [INITGROUPS] = { true, &dbs[grpdb] },
232 [GETSERVBYNAME] = { true, &dbs[servdb] },
233 [GETSERVBYPORT] = { true, &dbs[servdb] },
684ae515
UD
234 [GETFDSERV] = { false, &dbs[servdb] },
235 [GETNETGRENT] = { true, &dbs[netgrdb] },
236 [INNETGR] = { true, &dbs[netgrdb] },
237 [GETFDNETGR] = { false, &dbs[netgrdb] }
a95a08b4
UD
238};
239
240
27e82856 241/* Initial number of threads to use. */
67479a70 242int nthreads = -1;
27e82856
UD
243/* Maximum number of threads to use. */
244int max_nthreads = 32;
d67281a7 245
67479a70
UD
246/* Socket for incoming connections. */
247static int sock;
d67281a7 248
5228ba2f
UD
249#ifdef HAVE_INOTIFY
250/* Inotify descriptor. */
319b9ad4 251int inotify_fd = -1;
5228ba2f
UD
252#endif
253
3a2c0242
UD
254#ifdef HAVE_NETLINK
255/* Descriptor for netlink status updates. */
256static int nl_status_fd = -1;
257#endif
258
3ff2c948
UD
259#ifndef __ASSUME_SOCK_CLOEXEC
260/* Negative if SOCK_CLOEXEC is not supported, positive if it is, zero
261 before be know the result. */
262static int have_sock_cloexec;
f93fc0b7
UD
263#endif
264#ifndef __ASSUME_ACCEPT4
265static int have_accept4;
3ff2c948
UD
266#endif
267
0fdb4f42
UD
268/* Number of times clients had to wait. */
269unsigned long int client_queued;
270
d67281a7 271
d2dc7d84
UD
272ssize_t
273writeall (int fd, const void *buf, size_t len)
274{
275 size_t n = len;
276 ssize_t ret;
277 do
278 {
2c210d1e 279 ret = TEMP_FAILURE_RETRY (send (fd, buf, n, MSG_NOSIGNAL));
d2dc7d84
UD
280 if (ret <= 0)
281 break;
282 buf = (const char *) buf + ret;
283 n -= ret;
284 }
285 while (n > 0);
286 return ret < 0 ? ret : len - n;
287}
288
289
bd547139
UD
290#ifdef HAVE_SENDFILE
291ssize_t
292sendfileall (int tofd, int fromfd, off_t off, size_t len)
293{
294 ssize_t n = len;
295 ssize_t ret;
296
297 do
298 {
299 ret = TEMP_FAILURE_RETRY (sendfile (tofd, fromfd, &off, n));
300 if (ret <= 0)
301 break;
302 n -= ret;
303 }
304 while (n > 0);
305 return ret < 0 ? ret : len - n;
306}
307#endif
308
309
dc4bb1c2
UD
310enum usekey
311 {
312 use_not = 0,
313 /* The following three are not really used, they are symbolic constants. */
314 use_first = 16,
315 use_begin = 32,
316 use_end = 64,
317
318 use_he = 1,
319 use_he_begin = use_he | use_begin,
320 use_he_end = use_he | use_end,
dc4bb1c2
UD
321 use_data = 3,
322 use_data_begin = use_data | use_begin,
323 use_data_end = use_data | use_end,
324 use_data_first = use_data_begin | use_first
325 };
326
327
328static int
329check_use (const char *data, nscd_ssize_t first_free, uint8_t *usemap,
330 enum usekey use, ref_t start, size_t len)
331{
332 assert (len >= 2);
333
334 if (start > first_free || start + len > first_free
335 || (start & BLOCK_ALIGN_M1))
336 return 0;
337
338 if (usemap[start] == use_not)
339 {
340 /* Add the start marker. */
341 usemap[start] = use | use_begin;
342 use &= ~use_first;
343
344 while (--len > 0)
345 if (usemap[++start] != use_not)
346 return 0;
347 else
348 usemap[start] = use;
349
350 /* Add the end marker. */
351 usemap[start] = use | use_end;
352 }
353 else if ((usemap[start] & ~use_first) == ((use | use_begin) & ~use_first))
354 {
355 /* Hash entries can't be shared. */
356 if (use == use_he)
357 return 0;
358
359 usemap[start] |= (use & use_first);
360 use &= ~use_first;
361
362 while (--len > 1)
363 if (usemap[++start] != use)
364 return 0;
365
366 if (usemap[++start] != (use | use_end))
367 return 0;
368 }
369 else
370 /* Points to a wrong object or somewhere in the middle. */
371 return 0;
372
373 return 1;
374}
375
376
377/* Verify data in persistent database. */
378static int
379verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
380{
684ae515
UD
381 assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb
382 || dbnr == netgrdb);
dc4bb1c2
UD
383
384 time_t now = time (NULL);
385
386 struct database_pers_head *head = mem;
387 struct database_pers_head head_copy = *head;
388
389 /* Check that the header that was read matches the head in the database. */
27c377dd 390 if (memcmp (head, readhead, sizeof (*head)) != 0)
dc4bb1c2
UD
391 return 0;
392
393 /* First some easy tests: make sure the database header is sane. */
394 if (head->version != DB_VERSION
395 || head->header_size != sizeof (*head)
396 /* We allow a timestamp to be one hour ahead of the current time.
397 This should cover daylight saving time changes. */
398 || head->timestamp > now + 60 * 60 + 60
399 || (head->gc_cycle & 1)
27c377dd 400 || head->module == 0
dc4bb1c2
UD
401 || (size_t) head->module > INT32_MAX / sizeof (ref_t)
402 || (size_t) head->data_size > INT32_MAX - head->module * sizeof (ref_t)
403 || head->first_free < 0
404 || head->first_free > head->data_size
405 || (head->first_free & BLOCK_ALIGN_M1) != 0
406 || head->maxnentries < 0
407 || head->maxnsearched < 0)
408 return 0;
409
410 uint8_t *usemap = calloc (head->first_free, 1);
411 if (usemap == NULL)
412 return 0;
413
414 const char *data = (char *) &head->array[roundup (head->module,
415 ALIGN / sizeof (ref_t))];
416
417 nscd_ssize_t he_cnt = 0;
418 for (nscd_ssize_t cnt = 0; cnt < head->module; ++cnt)
419 {
a6fa5328
UD
420 ref_t trail = head->array[cnt];
421 ref_t work = trail;
422 int tick = 0;
dc4bb1c2
UD
423
424 while (work != ENDREF)
425 {
426 if (! check_use (data, head->first_free, usemap, use_he, work,
427 sizeof (struct hashentry)))
428 goto fail;
429
430 /* Now we know we can dereference the record. */
431 struct hashentry *here = (struct hashentry *) (data + work);
432
433 ++he_cnt;
434
435 /* Make sure the record is for this type of service. */
436 if (here->type >= LASTREQ
000b027e 437 || reqinfo[here->type].db != &dbs[dbnr])
dc4bb1c2
UD
438 goto fail;
439
440 /* Validate boolean field value. */
441 if (here->first != false && here->first != true)
442 goto fail;
443
444 if (here->len < 0)
445 goto fail;
446
447 /* Now the data. */
448 if (here->packet < 0
449 || here->packet > head->first_free
450 || here->packet + sizeof (struct datahead) > head->first_free)
451 goto fail;
452
453 struct datahead *dh = (struct datahead *) (data + here->packet);
454
455 if (! check_use (data, head->first_free, usemap,
456 use_data | (here->first ? use_first : 0),
457 here->packet, dh->allocsize))
458 goto fail;
459
460 if (dh->allocsize < sizeof (struct datahead)
461 || dh->recsize > dh->allocsize
462 || (dh->notfound != false && dh->notfound != true)
463 || (dh->usable != false && dh->usable != true))
464 goto fail;
465
466 if (here->key < here->packet + sizeof (struct datahead)
467 || here->key > here->packet + dh->allocsize
468 || here->key + here->len > here->packet + dh->allocsize)
2aac0a86 469 goto fail;
dc4bb1c2
UD
470
471 work = here->next;
50607309 472
a6fa5328 473 if (work == trail)
50607309
UD
474 /* A circular list, this must not happen. */
475 goto fail;
a6fa5328
UD
476 if (tick)
477 trail = ((struct hashentry *) (data + trail))->next;
478 tick = 1 - tick;
dc4bb1c2
UD
479 }
480 }
481
482 if (he_cnt != head->nentries)
483 goto fail;
484
485 /* See if all data and keys had at least one reference from
486 he->first == true hashentry. */
487 for (ref_t idx = 0; idx < head->first_free; ++idx)
488 {
dc4bb1c2
UD
489 if (usemap[idx] == use_data_begin)
490 goto fail;
491 }
492
493 /* Finally, make sure the database hasn't changed since the first test. */
494 if (memcmp (mem, &head_copy, sizeof (*head)) != 0)
495 goto fail;
496
497 free (usemap);
498 return 1;
499
500fail:
501 free (usemap);
502 return 0;
503}
504
505
d7e23b02
UD
506#ifdef O_CLOEXEC
507# define EXTRA_O_FLAGS O_CLOEXEC
508#else
509# define EXTRA_O_FLAGS 0
510#endif
511
512
a334319f
UD
513/* Initialize database information structures. */
514void
515nscd_init (void)
0ecb606c 516{
057685e4
UD
517 /* Look up unprivileged uid/gid/groups before we start listening on the
518 socket */
519 if (server_user != NULL)
520 begin_drop_privileges ();
521
67479a70
UD
522 if (nthreads == -1)
523 /* No configuration for this value, assume a default. */
ffb1b882 524 nthreads = 4;
d67281a7 525
d2dc7d84 526 for (size_t cnt = 0; cnt < lastdb; ++cnt)
67479a70 527 if (dbs[cnt].enabled)
9db29cde 528 {
67479a70 529 pthread_rwlock_init (&dbs[cnt].lock, NULL);
a95a08b4 530 pthread_mutex_init (&dbs[cnt].memlock, NULL);
264d5b94 531
a95a08b4 532 if (dbs[cnt].persistent)
e09edf23 533 {
a95a08b4 534 /* Try to open the appropriate file on disk. */
d7e23b02 535 int fd = open (dbs[cnt].db_filename, O_RDWR | EXTRA_O_FLAGS);
a95a08b4
UD
536 if (fd != -1)
537 {
27c377dd 538 char *msg = NULL;
a95a08b4
UD
539 struct stat64 st;
540 void *mem;
541 size_t total;
542 struct database_pers_head head;
543 ssize_t n = TEMP_FAILURE_RETRY (read (fd, &head,
544 sizeof (head)));
545 if (n != sizeof (head) || fstat64 (fd, &st) != 0)
546 {
27c377dd
UD
547 fail_db_errno:
548 /* The code is single-threaded at this point so
549 using strerror is just fine. */
550 msg = strerror (errno);
a95a08b4
UD
551 fail_db:
552 dbg_log (_("invalid persistent database file \"%s\": %s"),
27c377dd 553 dbs[cnt].db_filename, msg);
dc4bb1c2 554 unlink (dbs[cnt].db_filename);
a95a08b4
UD
555 }
556 else if (head.module == 0 && head.data_size == 0)
557 {
27c377dd
UD
558 /* The file has been created, but the head has not
559 been initialized yet. */
560 msg = _("uninitialized header");
561 goto fail_db;
a95a08b4
UD
562 }
563 else if (head.header_size != (int) sizeof (head))
564 {
27c377dd
UD
565 msg = _("header size does not match");
566 goto fail_db;
a95a08b4
UD
567 }
568 else if ((total = (sizeof (head)
c207f23b 569 + roundup (head.module * sizeof (ref_t),
a95a08b4
UD
570 ALIGN)
571 + head.data_size))
dc4bb1c2
UD
572 > st.st_size
573 || total < sizeof (head))
a95a08b4 574 {
27c377dd
UD
575 msg = _("file size does not match");
576 goto fail_db;
a95a08b4 577 }
2c210d1e
UD
578 /* Note we map with the maximum size allowed for the
579 database. This is likely much larger than the
580 actual file size. This is OK on most OSes since
581 extensions of the underlying file will
582 automatically translate more pages available for
583 memory access. */
584 else if ((mem = mmap (NULL, dbs[cnt].max_db_size,
585 PROT_READ | PROT_WRITE,
586 MAP_SHARED, fd, 0))
587 == MAP_FAILED)
27c377dd 588 goto fail_db_errno;
dc4bb1c2
UD
589 else if (!verify_persistent_db (mem, &head, cnt))
590 {
591 munmap (mem, total);
27c377dd
UD
592 msg = _("verification failed");
593 goto fail_db;
dc4bb1c2 594 }
a95a08b4
UD
595 else
596 {
597 /* Success. We have the database. */
598 dbs[cnt].head = mem;
599 dbs[cnt].memsize = total;
600 dbs[cnt].data = (char *)
601 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
602 ALIGN / sizeof (ref_t))];
603 dbs[cnt].mmap_used = true;
604
605 if (dbs[cnt].suggested_module > head.module)
606 dbg_log (_("suggested size of table for database %s larger than the persistent database's table"),
607 dbnames[cnt]);
608
609 dbs[cnt].wr_fd = fd;
610 fd = -1;
611 /* We also need a read-only descriptor. */
d13a3c57
UD
612 if (dbs[cnt].shared)
613 {
d7e23b02
UD
614 dbs[cnt].ro_fd = open (dbs[cnt].db_filename,
615 O_RDONLY | EXTRA_O_FLAGS);
d13a3c57
UD
616 if (dbs[cnt].ro_fd == -1)
617 dbg_log (_("\
a95a08b4 618cannot create read-only descriptor for \"%s\"; no mmap"),
d13a3c57
UD
619 dbs[cnt].db_filename);
620 }
a95a08b4
UD
621
622 // XXX Shall we test whether the descriptors actually
623 // XXX point to the same file?
624 }
625
626 /* Close the file descriptors in case something went
627 wrong in which case the variable have not been
628 assigned -1. */
629 if (fd != -1)
630 close (fd);
631 }
31d322a2 632 else if (errno == EACCES)
532a6035
SP
633 do_exit (EXIT_FAILURE, 0, _("cannot access '%s'"),
634 dbs[cnt].db_filename);
a95a08b4
UD
635 }
636
637 if (dbs[cnt].head == NULL)
638 {
639 /* No database loaded. Allocate the data structure,
640 possibly on disk. */
641 struct database_pers_head head;
642 size_t total = (sizeof (head)
643 + roundup (dbs[cnt].suggested_module
644 * sizeof (ref_t), ALIGN)
645 + (dbs[cnt].suggested_module
646 * DEFAULT_DATASIZE_PER_BUCKET));
647
648 /* Try to create the database. If we do not need a
649 persistent database create a temporary file. */
650 int fd;
651 int ro_fd = -1;
652 if (dbs[cnt].persistent)
653 {
654 fd = open (dbs[cnt].db_filename,
d7e23b02 655 O_RDWR | O_CREAT | O_EXCL | O_TRUNC | EXTRA_O_FLAGS,
a95a08b4 656 S_IRUSR | S_IWUSR);
d13a3c57 657 if (fd != -1 && dbs[cnt].shared)
d7e23b02
UD
658 ro_fd = open (dbs[cnt].db_filename,
659 O_RDONLY | EXTRA_O_FLAGS);
a95a08b4
UD
660 }
661 else
662 {
a8a58967 663 char fname[] = _PATH_NSCD_XYZ_DB_TMP;
d7e23b02 664 fd = mkostemp (fname, EXTRA_O_FLAGS);
a95a08b4
UD
665
666 /* We do not need the file name anymore after we
667 opened another file descriptor in read-only mode. */
5ca3d19c 668 if (fd != -1)
a95a08b4 669 {
5ca3d19c 670 if (dbs[cnt].shared)
d7e23b02 671 ro_fd = open (fname, O_RDONLY | EXTRA_O_FLAGS);
a95a08b4
UD
672
673 unlink (fname);
674 }
675 }
676
677 if (fd == -1)
678 {
679 if (errno == EEXIST)
680 {
681 dbg_log (_("database for %s corrupted or simultaneously used; remove %s manually if necessary and restart"),
682 dbnames[cnt], dbs[cnt].db_filename);
532a6035 683 do_exit (1, 0, NULL);
a95a08b4
UD
684 }
685
686 if (dbs[cnt].persistent)
687 dbg_log (_("cannot create %s; no persistent database used"),
688 dbs[cnt].db_filename);
689 else
690 dbg_log (_("cannot create %s; no sharing possible"),
691 dbs[cnt].db_filename);
692
693 dbs[cnt].persistent = 0;
694 // XXX remember: no mmap
695 }
696 else
697 {
698 /* Tell the user if we could not create the read-only
699 descriptor. */
d13a3c57 700 if (ro_fd == -1 && dbs[cnt].shared)
a95a08b4
UD
701 dbg_log (_("\
702cannot create read-only descriptor for \"%s\"; no mmap"),
703 dbs[cnt].db_filename);
704
a31ee4b3
SP
705 /* Before we create the header, initialize the hash
706 table. That way if we get interrupted while writing
a95a08b4
UD
707 the header we can recognize a partially initialized
708 database. */
709 size_t ps = sysconf (_SC_PAGESIZE);
710 char tmpbuf[ps];
711 assert (~ENDREF == 0);
712 memset (tmpbuf, '\xff', ps);
713
714 size_t remaining = dbs[cnt].suggested_module * sizeof (ref_t);
715 off_t offset = sizeof (head);
716
717 size_t towrite;
718 if (offset % ps != 0)
719 {
720 towrite = MIN (remaining, ps - (offset % ps));
233399bc
UD
721 if (pwrite (fd, tmpbuf, towrite, offset) != towrite)
722 goto write_fail;
a95a08b4
UD
723 offset += towrite;
724 remaining -= towrite;
725 }
726
727 while (remaining > ps)
728 {
233399bc
UD
729 if (pwrite (fd, tmpbuf, ps, offset) == -1)
730 goto write_fail;
a95a08b4
UD
731 offset += ps;
732 remaining -= ps;
733 }
734
233399bc
UD
735 if (remaining > 0
736 && pwrite (fd, tmpbuf, remaining, offset) != remaining)
737 goto write_fail;
a95a08b4
UD
738
739 /* Create the header of the file. */
740 struct database_pers_head head =
741 {
742 .version = DB_VERSION,
743 .header_size = sizeof (head),
744 .module = dbs[cnt].suggested_module,
745 .data_size = (dbs[cnt].suggested_module
746 * DEFAULT_DATASIZE_PER_BUCKET),
747 .first_free = 0
748 };
749 void *mem;
750
751 if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head)))
752 != sizeof (head))
2c210d1e
UD
753 || (TEMP_FAILURE_RETRY_VAL (posix_fallocate (fd, 0, total))
754 != 0)
755 || (mem = mmap (NULL, dbs[cnt].max_db_size,
756 PROT_READ | PROT_WRITE,
a95a08b4
UD
757 MAP_SHARED, fd, 0)) == MAP_FAILED)
758 {
233399bc 759 write_fail:
a95a08b4
UD
760 unlink (dbs[cnt].db_filename);
761 dbg_log (_("cannot write to database file %s: %s"),
762 dbs[cnt].db_filename, strerror (errno));
763 dbs[cnt].persistent = 0;
764 }
765 else
766 {
767 /* Success. */
768 dbs[cnt].head = mem;
769 dbs[cnt].data = (char *)
770 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
771 ALIGN / sizeof (ref_t))];
772 dbs[cnt].memsize = total;
773 dbs[cnt].mmap_used = true;
774
775 /* Remember the descriptors. */
776 dbs[cnt].wr_fd = fd;
777 dbs[cnt].ro_fd = ro_fd;
778 fd = -1;
779 ro_fd = -1;
780 }
781
782 if (fd != -1)
783 close (fd);
784 if (ro_fd != -1)
785 close (ro_fd);
786 }
787 }
788
d7e23b02
UD
789#if !defined O_CLOEXEC || !defined __ASSUME_O_CLOEXEC
790 /* We do not check here whether the O_CLOEXEC provided to the
791 open call was successful or not. The two fcntl calls are
792 only performed once each per process start-up and therefore
793 is not noticeable at all. */
4401d759
UD
794 if (paranoia
795 && ((dbs[cnt].wr_fd != -1
796 && fcntl (dbs[cnt].wr_fd, F_SETFD, FD_CLOEXEC) == -1)
797 || (dbs[cnt].ro_fd != -1
798 && fcntl (dbs[cnt].ro_fd, F_SETFD, FD_CLOEXEC) == -1)))
799 {
800 dbg_log (_("\
801cannot set socket to close on exec: %s; disabling paranoia mode"),
802 strerror (errno));
803 paranoia = 0;
804 }
d7e23b02 805#endif
4401d759 806
a95a08b4
UD
807 if (dbs[cnt].head == NULL)
808 {
809 /* We do not use the persistent database. Just
810 create an in-memory data structure. */
811 assert (! dbs[cnt].persistent);
812
813 dbs[cnt].head = xmalloc (sizeof (struct database_pers_head)
814 + (dbs[cnt].suggested_module
815 * sizeof (ref_t)));
25059769 816 memset (dbs[cnt].head, '\0', sizeof (struct database_pers_head));
a95a08b4
UD
817 assert (~ENDREF == 0);
818 memset (dbs[cnt].head->array, '\xff',
819 dbs[cnt].suggested_module * sizeof (ref_t));
820 dbs[cnt].head->module = dbs[cnt].suggested_module;
821 dbs[cnt].head->data_size = (DEFAULT_DATASIZE_PER_BUCKET
822 * dbs[cnt].head->module);
823 dbs[cnt].data = xmalloc (dbs[cnt].head->data_size);
824 dbs[cnt].head->first_free = 0;
c207f23b
UD
825
826 dbs[cnt].shared = 0;
827 assert (dbs[cnt].ro_fd == -1);
e09edf23 828 }
67479a70 829 }
d67281a7
UD
830
831 /* Create the socket. */
3ff2c948
UD
832#ifndef __ASSUME_SOCK_CLOEXEC
833 sock = -1;
834 if (have_sock_cloexec >= 0)
835#endif
836 {
837 sock = socket (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
bd7f4857 838#ifndef __ASSUME_SOCK_CLOEXEC
3ff2c948
UD
839 if (have_sock_cloexec == 0)
840 have_sock_cloexec = sock != -1 || errno != EINVAL ? 1 : -1;
841#endif
842 }
843#ifndef __ASSUME_SOCK_CLOEXEC
844 if (have_sock_cloexec < 0)
845 sock = socket (AF_UNIX, SOCK_STREAM, 0);
846#endif
67479a70 847 if (sock < 0)
d67281a7 848 {
67479a70 849 dbg_log (_("cannot open socket: %s"), strerror (errno));
532a6035 850 do_exit (errno == EACCES ? 4 : 1, 0, NULL);
d67281a7
UD
851 }
852 /* Bind a name to the socket. */
d2dc7d84 853 struct sockaddr_un sock_addr;
d67281a7
UD
854 sock_addr.sun_family = AF_UNIX;
855 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
67479a70 856 if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
d67281a7
UD
857 {
858 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
532a6035 859 do_exit (errno == EACCES ? 4 : 1, 0, NULL);
d67281a7 860 }
67479a70 861
3ff2c948
UD
862#ifndef __ASSUME_SOCK_CLOEXEC
863 if (have_sock_cloexec < 0)
4401d759 864 {
3ff2c948
UD
865 /* We don't want to get stuck on accept. */
866 int fl = fcntl (sock, F_GETFL);
867 if (fl == -1 || fcntl (sock, F_SETFL, fl | O_NONBLOCK) == -1)
868 {
869 dbg_log (_("cannot change socket to nonblocking mode: %s"),
870 strerror (errno));
532a6035 871 do_exit (1, 0, NULL);
3ff2c948 872 }
4401d759 873
3ff2c948
UD
874 /* The descriptor needs to be closed on exec. */
875 if (paranoia && fcntl (sock, F_SETFD, FD_CLOEXEC) == -1)
876 {
877 dbg_log (_("cannot set socket to close on exec: %s"),
878 strerror (errno));
532a6035 879 do_exit (1, 0, NULL);
3ff2c948 880 }
4401d759 881 }
3ff2c948 882#endif
d6db0975 883
d67281a7 884 /* Set permissions for the socket. */
a95a08b4 885 chmod (_PATH_NSCDSOCKET, DEFFILEMODE);
d67281a7
UD
886
887 /* Set the socket up to accept connections. */
67479a70 888 if (listen (sock, SOMAXCONN) < 0)
d67281a7 889 {
67479a70
UD
890 dbg_log (_("cannot enable socket to accept connections: %s"),
891 strerror (errno));
532a6035 892 do_exit (1, 0, NULL);
d67281a7 893 }
057685e4 894
3a2c0242
UD
895#ifdef HAVE_NETLINK
896 if (dbs[hstdb].enabled)
897 {
898 /* Try to open netlink socket to monitor network setting changes. */
899 nl_status_fd = socket (AF_NETLINK,
900 SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
901 NETLINK_ROUTE);
902 if (nl_status_fd != -1)
903 {
904 struct sockaddr_nl snl;
905 memset (&snl, '\0', sizeof (snl));
906 snl.nl_family = AF_NETLINK;
907 /* XXX Is this the best set to use? */
908 snl.nl_groups = (RTMGRP_IPV4_IFADDR | RTMGRP_TC | RTMGRP_IPV4_MROUTE
909 | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_RULE
910 | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_MROUTE
911 | RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFINFO
912 | RTMGRP_IPV6_PREFIX);
913
914 if (bind (nl_status_fd, (struct sockaddr *) &snl, sizeof (snl)) != 0)
915 {
916 close (nl_status_fd);
917 nl_status_fd = -1;
918 }
919 else
920 {
921 /* Start the timestamp process. */
922 dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP]
923 = __bump_nl_timestamp ();
924
925# ifndef __ASSUME_SOCK_CLOEXEC
926 if (have_sock_cloexec < 0)
927 {
928 /* We don't want to get stuck on accept. */
929 int fl = fcntl (nl_status_fd, F_GETFL);
930 if (fl == -1
931 || fcntl (nl_status_fd, F_SETFL, fl | O_NONBLOCK) == -1)
932 {
933 dbg_log (_("\
934cannot change socket to nonblocking mode: %s"),
935 strerror (errno));
532a6035 936 do_exit (1, 0, NULL);
3a2c0242
UD
937 }
938
939 /* The descriptor needs to be closed on exec. */
940 if (paranoia
941 && fcntl (nl_status_fd, F_SETFD, FD_CLOEXEC) == -1)
942 {
943 dbg_log (_("cannot set socket to close on exec: %s"),
944 strerror (errno));
532a6035 945 do_exit (1, 0, NULL);
3a2c0242
UD
946 }
947 }
948# endif
949 }
950 }
951 }
952#endif
953
319b9ad4 954 /* Change to unprivileged uid/gid/groups if specified in config file */
057685e4
UD
955 if (server_user != NULL)
956 finish_drop_privileges ();
d67281a7
UD
957}
958
67479a70 959
471514d3
CD
960/* Register the file in FINFO as a traced file for the database DBS[DBIX].
961
962 We support registering multiple files per database. Each call to
963 register_traced_file adds to the list of registered files.
964
965 When we prune the database, either through timeout or a request to
966 invalidate, we will check to see if any of the registered files has changed.
967 When we accept new connections to handle a cache request we will also
968 check to see if any of the registered files has changed.
969
970 If we have inotify support then we install an inotify fd to notify us of
971 file deletion or modification, both of which will require we invalidate
972 the cache for the database. Without inotify support we stat the file and
973 store st_mtime to determine if the file has been modified. */
319b9ad4
UD
974void
975register_traced_file (size_t dbidx, struct traced_file *finfo)
976{
471514d3
CD
977 /* If the database is disabled or file checking is disabled
978 then ignore the registration. */
21fd49a9 979 if (! dbs[dbidx].enabled || ! dbs[dbidx].check_file)
319b9ad4
UD
980 return;
981
a1ffb40e 982 if (__glibc_unlikely (debug_level > 0))
319b9ad4
UD
983 dbg_log (_("register trace file %s for database %s"),
984 finfo->fname, dbnames[dbidx]);
985
986#ifdef HAVE_INOTIFY
987 if (inotify_fd < 0
988 || (finfo->inotify_descr = inotify_add_watch (inotify_fd, finfo->fname,
989 IN_DELETE_SELF
990 | IN_MODIFY)) < 0)
991#endif
992 {
993 /* We need the modification date of the file. */
994 struct stat64 st;
995
996 if (stat64 (finfo->fname, &st) < 0)
997 {
998 /* We cannot stat() the file, disable file checking. */
999 dbg_log (_("cannot stat() file `%s': %s"),
1000 finfo->fname, strerror (errno));
1001 return;
1002 }
1003
1004 finfo->inotify_descr = -1;
1005 finfo->mtime = st.st_mtime;
1006 }
1007
1008 /* Queue up the file name. */
1009 finfo->next = dbs[dbidx].traced_files;
1010 dbs[dbidx].traced_files = finfo;
1011}
1012
1013
67479a70 1014/* Close the connections. */
d67281a7 1015void
67479a70 1016close_sockets (void)
d67281a7 1017{
67479a70
UD
1018 close (sock);
1019}
d67281a7 1020
a12ce44f 1021
756409c4 1022static void
902c4291 1023invalidate_cache (char *key, int fd)
756409c4
UD
1024{
1025 dbtype number;
902c4291 1026 int32_t resp;
756409c4 1027
b21fa963
UD
1028 for (number = pwddb; number < lastdb; ++number)
1029 if (strcmp (key, dbnames[number]) == 0)
1030 {
319b9ad4
UD
1031 if (number == hstdb)
1032 {
1033 struct traced_file *runp = dbs[hstdb].traced_files;
1034 while (runp != NULL)
1035 if (runp->call_res_init)
1036 {
1037 res_init ();
1038 break;
1039 }
1040 else
1041 runp = runp->next;
1042 }
b21fa963 1043 break;
319b9ad4 1044 }
b21fa963
UD
1045
1046 if (number == lastdb)
902c4291
UD
1047 {
1048 resp = EINVAL;
1049 writeall (fd, &resp, sizeof (resp));
1050 return;
1051 }
756409c4 1052
fd665070 1053 if (dbs[number].enabled)
ffb1b882 1054 {
cd72adeb 1055 pthread_mutex_lock (&dbs[number].prune_run_lock);
ffb1b882 1056 prune_cache (&dbs[number], LONG_MAX, fd);
cd72adeb 1057 pthread_mutex_unlock (&dbs[number].prune_run_lock);
ffb1b882 1058 }
902c4291
UD
1059 else
1060 {
1061 resp = 0;
1062 writeall (fd, &resp, sizeof (resp));
1063 }
756409c4
UD
1064}
1065
67479a70 1066
c207f23b
UD
1067#ifdef SCM_RIGHTS
1068static void
1069send_ro_fd (struct database_dyn *db, char *key, int fd)
1070{
1071 /* If we do not have an read-only file descriptor do nothing. */
1072 if (db->ro_fd == -1)
1073 return;
1074
1075 /* We need to send some data along with the descriptor. */
f3c54060
UD
1076 uint64_t mapsize = (db->head->data_size
1077 + roundup (db->head->module * sizeof (ref_t), ALIGN)
1078 + sizeof (struct database_pers_head));
1079 struct iovec iov[2];
c207f23b
UD
1080 iov[0].iov_base = key;
1081 iov[0].iov_len = strlen (key) + 1;
f3c54060
UD
1082 iov[1].iov_base = &mapsize;
1083 iov[1].iov_len = sizeof (mapsize);
c207f23b
UD
1084
1085 /* Prepare the control message to transfer the descriptor. */
a08ab897
UD
1086 union
1087 {
1088 struct cmsghdr hdr;
1089 char bytes[CMSG_SPACE (sizeof (int))];
1090 } buf;
f3c54060 1091 struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 2,
a08ab897
UD
1092 .msg_control = buf.bytes,
1093 .msg_controllen = sizeof (buf) };
c207f23b
UD
1094 struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
1095
1096 cmsg->cmsg_level = SOL_SOCKET;
1097 cmsg->cmsg_type = SCM_RIGHTS;
1098 cmsg->cmsg_len = CMSG_LEN (sizeof (int));
1099
1ac03a1e
UD
1100 int *ip = (int *) CMSG_DATA (cmsg);
1101 *ip = db->ro_fd;
c207f23b
UD
1102
1103 msg.msg_controllen = cmsg->cmsg_len;
1104
1105 /* Send the control message. We repeat when we are interrupted but
1106 everything else is ignored. */
6925ef9a
UD
1107#ifndef MSG_NOSIGNAL
1108# define MSG_NOSIGNAL 0
1109#endif
1110 (void) TEMP_FAILURE_RETRY (sendmsg (fd, &msg, MSG_NOSIGNAL));
c207f23b 1111
a1ffb40e 1112 if (__glibc_unlikely (debug_level > 0))
c207f23b
UD
1113 dbg_log (_("provide access to FD %d, for %s"), db->ro_fd, key);
1114}
1115#endif /* SCM_RIGHTS */
1116
1117
67479a70
UD
1118/* Handle new request. */
1119static void
c52137d3 1120handle_request (int fd, request_header *req, void *key, uid_t uid, pid_t pid)
67479a70 1121{
23700036 1122 if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
d67281a7 1123 {
98e75a1c
UD
1124 if (debug_level > 0)
1125 dbg_log (_("\
67479a70 1126cannot handle old request version %d; current version is %d"),
98e75a1c 1127 req->version, NSCD_VERSION);
d67281a7
UD
1128 return;
1129 }
1130
ffb1b882 1131 /* Perform the SELinux check before we go on to the standard checks. */
000b027e 1132 if (selinux_enabled && nscd_request_avc_has_perm (fd, req->type) != 0)
ffb1b882
UD
1133 {
1134 if (debug_level > 0)
c52137d3
UD
1135 {
1136#ifdef SO_PEERCRED
1137# ifdef PATH_MAX
1138 char buf[PATH_MAX];
1139# else
1140 char buf[4096];
1141# endif
1142
1143 snprintf (buf, sizeof (buf), "/proc/%ld/exe", (long int) pid);
1144 ssize_t n = readlink (buf, buf, sizeof (buf) - 1);
1145
1146 if (n <= 0)
1147 dbg_log (_("\
1148request from %ld not handled due to missing permission"), (long int) pid);
1149 else
1150 {
1151 buf[n] = '\0';
1152 dbg_log (_("\
1153request from '%s' [%ld] not handled due to missing permission"),
1154 buf, (long int) pid);
1155 }
1156#else
1157 dbg_log (_("request not handled due to missing permission"));
1158#endif
1159 }
ffb1b882
UD
1160 return;
1161 }
74a30a58 1162
000b027e 1163 struct database_dyn *db = reqinfo[req->type].db;
a95a08b4 1164
9691d83c 1165 /* See whether we can service the request from the cache. */
000b027e 1166 if (__builtin_expect (reqinfo[req->type].data_request, true))
d67281a7 1167 {
23700036 1168 if (__builtin_expect (debug_level, 0) > 0)
8d8c6efa
UD
1169 {
1170 if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
1171 {
1172 char buf[INET6_ADDRSTRLEN];
1173
1174 dbg_log ("\t%s (%s)", serv2str[req->type],
1175 inet_ntop (req->type == GETHOSTBYADDR
1176 ? AF_INET : AF_INET6,
1177 key, buf, sizeof (buf)));
1178 }
1179 else
a95a08b4 1180 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
8d8c6efa 1181 }
d67281a7 1182
67479a70 1183 /* Is this service enabled? */
a1ffb40e 1184 if (__glibc_unlikely (!db->enabled))
67479a70 1185 {
ce85d65b 1186 /* No, sent the prepared record. */
2c210d1e
UD
1187 if (TEMP_FAILURE_RETRY (send (fd, db->disabled_iov->iov_base,
1188 db->disabled_iov->iov_len,
1189 MSG_NOSIGNAL))
4c5dd2a2 1190 != (ssize_t) db->disabled_iov->iov_len
23700036 1191 && __builtin_expect (debug_level, 0) > 0)
67479a70
UD
1192 {
1193 /* We have problems sending the result. */
1194 char buf[256];
1195 dbg_log (_("cannot write result: %s"),
1196 strerror_r (errno, buf, sizeof (buf)));
1197 }
d67281a7 1198
67479a70
UD
1199 return;
1200 }
d67281a7 1201
67479a70 1202 /* Be sure we can read the data. */
a1ffb40e 1203 if (__glibc_unlikely (pthread_rwlock_tryrdlock (&db->lock) != 0))
c86e6aec 1204 {
a95a08b4 1205 ++db->head->rdlockdelayed;
c86e6aec
UD
1206 pthread_rwlock_rdlock (&db->lock);
1207 }
67479a70
UD
1208
1209 /* See whether we can handle it from the cache. */
a95a08b4
UD
1210 struct datahead *cached;
1211 cached = (struct datahead *) cache_search (req->type, key, req->key_len,
1212 db, uid);
67479a70
UD
1213 if (cached != NULL)
1214 {
1215 /* Hurray it's in the cache. */
eac10791
UD
1216 ssize_t nwritten;
1217
1218#ifdef HAVE_SENDFILE
a1ffb40e 1219 if (__glibc_likely (db->mmap_used))
eac10791
UD
1220 {
1221 assert (db->wr_fd != -1);
1222 assert ((char *) cached->data > (char *) db->data);
1223 assert ((char *) cached->data - (char *) db->head
1224 + cached->recsize
1225 <= (sizeof (struct database_pers_head)
1226 + db->head->module * sizeof (ref_t)
1227 + db->head->data_size));
bd547139
UD
1228 nwritten = sendfileall (fd, db->wr_fd,
1229 (char *) cached->data
1230 - (char *) db->head, cached->recsize);
eac10791
UD
1231# ifndef __ASSUME_SENDFILE
1232 if (nwritten == -1 && errno == ENOSYS)
1233 goto use_write;
1234# endif
1235 }
1236 else
1237# ifndef __ASSUME_SENDFILE
1238 use_write:
1239# endif
1240#endif
1241 nwritten = writeall (fd, cached->data, cached->recsize);
1242
1243 if (nwritten != cached->recsize
23700036 1244 && __builtin_expect (debug_level, 0) > 0)
67479a70
UD
1245 {
1246 /* We have problems sending the result. */
1247 char buf[256];
1248 dbg_log (_("cannot write result: %s"),
1249 strerror_r (errno, buf, sizeof (buf)));
1250 }
1251
1252 pthread_rwlock_unlock (&db->lock);
1253
1254 return;
1255 }
1256
1257 pthread_rwlock_unlock (&db->lock);
d67281a7 1258 }
23700036 1259 else if (__builtin_expect (debug_level, 0) > 0)
756409c4
UD
1260 {
1261 if (req->type == INVALIDATE)
c207f23b 1262 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
0532e21b 1263 else
a95a08b4 1264 dbg_log ("\t%s", serv2str[req->type]);
756409c4 1265 }
67479a70
UD
1266
1267 /* Handle the request. */
1268 switch (req->type)
d67281a7 1269 {
67479a70 1270 case GETPWBYNAME:
a95a08b4 1271 addpwbyname (db, fd, req, key, uid);
67479a70
UD
1272 break;
1273
1274 case GETPWBYUID:
a95a08b4 1275 addpwbyuid (db, fd, req, key, uid);
67479a70
UD
1276 break;
1277
1278 case GETGRBYNAME:
a95a08b4 1279 addgrbyname (db, fd, req, key, uid);
67479a70
UD
1280 break;
1281
1282 case GETGRBYGID:
a95a08b4 1283 addgrbygid (db, fd, req, key, uid);
67479a70
UD
1284 break;
1285
1286 case GETHOSTBYNAME:
a95a08b4 1287 addhstbyname (db, fd, req, key, uid);
67479a70
UD
1288 break;
1289
1290 case GETHOSTBYNAMEv6:
a95a08b4 1291 addhstbynamev6 (db, fd, req, key, uid);
67479a70
UD
1292 break;
1293
1294 case GETHOSTBYADDR:
a95a08b4 1295 addhstbyaddr (db, fd, req, key, uid);
67479a70
UD
1296 break;
1297
1298 case GETHOSTBYADDRv6:
a95a08b4 1299 addhstbyaddrv6 (db, fd, req, key, uid);
67479a70
UD
1300 break;
1301
d19687d6
UD
1302 case GETAI:
1303 addhstai (db, fd, req, key, uid);
1304 break;
1305
f7e7a396
UD
1306 case INITGROUPS:
1307 addinitgroups (db, fd, req, key, uid);
1308 break;
1309
b21fa963
UD
1310 case GETSERVBYNAME:
1311 addservbyname (db, fd, req, key, uid);
1312 break;
1313
1314 case GETSERVBYPORT:
1315 addservbyport (db, fd, req, key, uid);
1316 break;
1317
684ae515
UD
1318 case GETNETGRENT:
1319 addgetnetgrent (db, fd, req, key, uid);
1320 break;
1321
1322 case INNETGR:
1323 addinnetgr (db, fd, req, key, uid);
1324 break;
1325
67479a70 1326 case GETSTAT:
67479a70 1327 case SHUTDOWN:
756409c4 1328 case INVALIDATE:
70e2ebba
UD
1329 {
1330 /* Get the callers credentials. */
cedc8559 1331#ifdef SO_PEERCRED
70e2ebba
UD
1332 struct ucred caller;
1333 socklen_t optlen = sizeof (caller);
be3c40b6 1334
70e2ebba
UD
1335 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
1336 {
1337 char buf[256];
a1c542bf 1338
c69136ae 1339 dbg_log (_("error getting caller's id: %s"),
70e2ebba
UD
1340 strerror_r (errno, buf, sizeof (buf)));
1341 break;
1342 }
a12ce44f 1343
70e2ebba 1344 uid = caller.uid;
a12ce44f 1345#else
70e2ebba
UD
1346 /* Some systems have no SO_PEERCRED implementation. They don't
1347 care about security so we don't as well. */
1348 uid = 0;
cedc8559 1349#endif
70e2ebba 1350 }
a12ce44f
UD
1351
1352 /* Accept shutdown, getstat and invalidate only from root. For
1353 the stat call also allow the user specified in the config file. */
1354 if (req->type == GETSTAT)
1355 {
1356 if (uid == 0 || uid == stat_uid)
1357 send_stats (fd, dbs);
1358 }
1359 else if (uid == 0)
1360 {
1361 if (req->type == INVALIDATE)
902c4291 1362 invalidate_cache (key, fd);
a12ce44f
UD
1363 else
1364 termination_handler (0);
a1c542bf 1365 }
67479a70
UD
1366 break;
1367
c207f23b
UD
1368 case GETFDPW:
1369 case GETFDGR:
1370 case GETFDHST:
b21fa963 1371 case GETFDSERV:
684ae515 1372 case GETFDNETGR:
c207f23b 1373#ifdef SCM_RIGHTS
000b027e 1374 send_ro_fd (reqinfo[req->type].db, key, fd);
c207f23b
UD
1375#endif
1376 break;
1377
67479a70 1378 default:
64acf8ed
UD
1379 /* Ignore the command, it's nothing we know. */
1380 break;
d67281a7 1381 }
67479a70
UD
1382}
1383
d67281a7 1384
4401d759
UD
1385/* Restart the process. */
1386static void
1387restart (void)
1388{
1389 /* First determine the parameters. We do not use the parameters
1390 passed to main() since in case nscd is started by running the
1391 dynamic linker this will not work. Yes, this is not the usual
1392 case but nscd is part of glibc and we occasionally do this. */
1393 size_t buflen = 1024;
1394 char *buf = alloca (buflen);
1395 size_t readlen = 0;
1396 int fd = open ("/proc/self/cmdline", O_RDONLY);
1397 if (fd == -1)
1398 {
1399 dbg_log (_("\
1400cannot open /proc/self/cmdline: %s; disabling paranoia mode"),
1401 strerror (errno));
1402
1403 paranoia = 0;
1404 return;
1405 }
1406
1407 while (1)
1408 {
1409 ssize_t n = TEMP_FAILURE_RETRY (read (fd, buf + readlen,
1410 buflen - readlen));
1411 if (n == -1)
1412 {
1413 dbg_log (_("\
b21fa963 1414cannot read /proc/self/cmdline: %s; disabling paranoia mode"),
4401d759
UD
1415 strerror (errno));
1416
1417 close (fd);
1418 paranoia = 0;
1419 return;
1420 }
1421
1422 readlen += n;
1423
1424 if (readlen < buflen)
1425 break;
1426
1427 /* We might have to extend the buffer. */
1428 size_t old_buflen = buflen;
1429 char *newp = extend_alloca (buf, buflen, 2 * buflen);
1430 buf = memmove (newp, buf, old_buflen);
1431 }
1432
1433 close (fd);
1434
1435 /* Parse the command line. Worst case scenario: every two
1436 characters form one parameter (one character plus NUL). */
1437 char **argv = alloca ((readlen / 2 + 1) * sizeof (argv[0]));
1438 int argc = 0;
1439
1440 char *cp = buf;
1441 while (cp < buf + readlen)
1442 {
1443 argv[argc++] = cp;
1444 cp = (char *) rawmemchr (cp, '\0') + 1;
1445 }
1446 argv[argc] = NULL;
1447
1448 /* Second, change back to the old user if we changed it. */
1449 if (server_user != NULL)
1450 {
464c9fad 1451 if (setresuid (old_uid, old_uid, old_uid) != 0)
4401d759
UD
1452 {
1453 dbg_log (_("\
1454cannot change to old UID: %s; disabling paranoia mode"),
1455 strerror (errno));
1456
1457 paranoia = 0;
1458 return;
1459 }
1460
464c9fad 1461 if (setresgid (old_gid, old_gid, old_gid) != 0)
4401d759
UD
1462 {
1463 dbg_log (_("\
1464cannot change to old GID: %s; disabling paranoia mode"),
1465 strerror (errno));
1466
1467 setuid (server_uid);
1468 paranoia = 0;
1469 return;
1470 }
1471 }
1472
1473 /* Next change back to the old working directory. */
1474 if (chdir (oldcwd) == -1)
1475 {
1476 dbg_log (_("\
1477cannot change to old working directory: %s; disabling paranoia mode"),
1478 strerror (errno));
1479
1480 if (server_user != NULL)
1481 {
1482 setuid (server_uid);
1483 setgid (server_gid);
1484 }
1485 paranoia = 0;
1486 return;
1487 }
1488
1489 /* Synchronize memory. */
528741cb 1490 int32_t certainly[lastdb];
4401d759 1491 for (int cnt = 0; cnt < lastdb; ++cnt)
0fbfe2f7 1492 if (dbs[cnt].enabled)
3e6ce4d7
UD
1493 {
1494 /* Make sure nobody keeps using the database. */
1495 dbs[cnt].head->timestamp = 0;
528741cb
UD
1496 certainly[cnt] = dbs[cnt].head->nscd_certainly_running;
1497 dbs[cnt].head->nscd_certainly_running = 0;
4401d759 1498
3e6ce4d7
UD
1499 if (dbs[cnt].persistent)
1500 // XXX async OK?
1501 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
1502 }
4401d759
UD
1503
1504 /* The preparations are done. */
d9822dbe
UD
1505#ifdef PATH_MAX
1506 char pathbuf[PATH_MAX];
1507#else
1508 char pathbuf[256];
1509#endif
1510 /* Try to exec the real nscd program so the process name (as reported
1511 in /proc/PID/status) will be 'nscd', but fall back to /proc/self/exe
351fe947 1512 if readlink or the exec with the result of the readlink call fails. */
d9822dbe 1513 ssize_t n = readlink ("/proc/self/exe", pathbuf, sizeof (pathbuf) - 1);
351fe947 1514 if (n != -1)
d9822dbe
UD
1515 {
1516 pathbuf[n] = '\0';
1517 execv (pathbuf, argv);
1518 }
351fe947 1519 execv ("/proc/self/exe", argv);
4401d759
UD
1520
1521 /* If we come here, we will never be able to re-exec. */
1522 dbg_log (_("re-exec failed: %s; disabling paranoia mode"),
1523 strerror (errno));
1524
1525 if (server_user != NULL)
1526 {
1527 setuid (server_uid);
1528 setgid (server_gid);
1529 }
233399bc
UD
1530 if (chdir ("/") != 0)
1531 dbg_log (_("cannot change current working directory to \"/\": %s"),
1532 strerror (errno));
4401d759 1533 paranoia = 0;
528741cb
UD
1534
1535 /* Reenable the databases. */
1536 time_t now = time (NULL);
1537 for (int cnt = 0; cnt < lastdb; ++cnt)
1538 if (dbs[cnt].enabled)
1539 {
1540 dbs[cnt].head->timestamp = now;
1541 dbs[cnt].head->nscd_certainly_running = certainly[cnt];
1542 }
4401d759
UD
1543}
1544
1545
1945c96f
UD
1546/* List of file descriptors. */
1547struct fdlist
1548{
1549 int fd;
1550 struct fdlist *next;
1551};
1552/* Memory allocated for the list. */
1553static struct fdlist *fdlist;
1554/* List of currently ready-to-read file descriptors. */
1555static struct fdlist *readylist;
1556
1557/* Conditional variable and mutex to signal availability of entries in
1558 READYLIST. The condvar is initialized dynamically since we might
1559 use a different clock depending on availability. */
ffb1b882 1560static pthread_cond_t readylist_cond = PTHREAD_COND_INITIALIZER;
1945c96f
UD
1561static pthread_mutex_t readylist_lock = PTHREAD_MUTEX_INITIALIZER;
1562
1563/* The clock to use with the condvar. */
1564static clockid_t timeout_clock = CLOCK_REALTIME;
1565
1566/* Number of threads ready to handle the READYLIST. */
1567static unsigned long int nready;
1568
1569
ffb1b882 1570/* Function for the clean-up threads. */
67479a70
UD
1571static void *
1572__attribute__ ((__noreturn__))
ffb1b882 1573nscd_run_prune (void *p)
67479a70 1574{
1945c96f 1575 const long int my_number = (long int) p;
ffb1b882
UD
1576 assert (dbs[my_number].enabled);
1577
1578 int dont_need_update = setup_thread (&dbs[my_number]);
1579
528741cb
UD
1580 time_t now = time (NULL);
1581
ffb1b882 1582 /* We are running. */
528741cb 1583 dbs[my_number].head->timestamp = now;
ffb1b882 1584
1945c96f 1585 struct timespec prune_ts;
a1ffb40e 1586 if (__glibc_unlikely (clock_gettime (timeout_clock, &prune_ts) == -1))
ffb1b882
UD
1587 /* Should never happen. */
1588 abort ();
1589
1590 /* Compute the initial timeout time. Prevent all the timers to go
1591 off at the same time by adding a db-based value. */
1592 prune_ts.tv_sec += CACHE_PRUNE_INTERVAL + my_number;
528741cb
UD
1593 dbs[my_number].wakeup_time = now + CACHE_PRUNE_INTERVAL + my_number;
1594
1595 pthread_mutex_t *prune_lock = &dbs[my_number].prune_lock;
cd72adeb 1596 pthread_mutex_t *prune_run_lock = &dbs[my_number].prune_run_lock;
528741cb 1597 pthread_cond_t *prune_cond = &dbs[my_number].prune_cond;
264d5b94 1598
528741cb 1599 pthread_mutex_lock (prune_lock);
ffb1b882 1600 while (1)
1945c96f 1601 {
ffb1b882 1602 /* Wait, but not forever. */
5228ba2f
UD
1603 int e = 0;
1604 if (! dbs[my_number].clear_cache)
1605 e = pthread_cond_timedwait (prune_cond, prune_lock, &prune_ts);
528741cb 1606 assert (__builtin_expect (e == 0 || e == ETIMEDOUT, 1));
081fc592 1607
ffb1b882 1608 time_t next_wait;
528741cb 1609 now = time (NULL);
5228ba2f
UD
1610 if (e == ETIMEDOUT || now >= dbs[my_number].wakeup_time
1611 || dbs[my_number].clear_cache)
ffb1b882 1612 {
528741cb
UD
1613 /* We will determine the new timout values based on the
1614 cache content. Should there be concurrent additions to
1615 the cache which are not accounted for in the cache
1616 pruning we want to know about it. Therefore set the
1617 timeout to the maximum. It will be descreased when adding
1618 new entries to the cache, if necessary. */
a4c7ea7b 1619 dbs[my_number].wakeup_time = MAX_TIMEOUT_VALUE;
528741cb 1620
5228ba2f
UD
1621 /* Unconditionally reset the flag. */
1622 time_t prune_now = dbs[my_number].clear_cache ? LONG_MAX : now;
1623 dbs[my_number].clear_cache = 0;
1624
528741cb
UD
1625 pthread_mutex_unlock (prune_lock);
1626
cd72adeb
UD
1627 /* We use a separate lock for running the prune function (instead
1628 of keeping prune_lock locked) because this enables concurrent
1629 invocations of cache_add which might modify the timeout value. */
1630 pthread_mutex_lock (prune_run_lock);
5228ba2f 1631 next_wait = prune_cache (&dbs[my_number], prune_now, -1);
cd72adeb 1632 pthread_mutex_unlock (prune_run_lock);
528741cb 1633
ffb1b882
UD
1634 next_wait = MAX (next_wait, CACHE_PRUNE_INTERVAL);
1635 /* If clients cannot determine for sure whether nscd is running
1636 we need to wake up occasionally to update the timestamp.
1637 Wait 90% of the update period. */
1638#define UPDATE_MAPPING_TIMEOUT (MAPPING_TIMEOUT * 9 / 10)
a1ffb40e 1639 if (__glibc_unlikely (! dont_need_update))
528741cb
UD
1640 {
1641 next_wait = MIN (UPDATE_MAPPING_TIMEOUT, next_wait);
1642 dbs[my_number].head->timestamp = now;
1643 }
1644
1645 pthread_mutex_lock (prune_lock);
ffb1b882
UD
1646
1647 /* Make it known when we will wake up again. */
528741cb
UD
1648 if (now + next_wait < dbs[my_number].wakeup_time)
1649 dbs[my_number].wakeup_time = now + next_wait;
1650 else
1651 next_wait = dbs[my_number].wakeup_time - now;
ffb1b882
UD
1652 }
1653 else
1654 /* The cache was just pruned. Do not do it again now. Just
1655 use the new timeout value. */
1656 next_wait = dbs[my_number].wakeup_time - now;
d67281a7 1657
1945c96f
UD
1658 if (clock_gettime (timeout_clock, &prune_ts) == -1)
1659 /* Should never happen. */
1660 abort ();
0fdb4f42 1661
ffb1b882
UD
1662 /* Compute next timeout time. */
1663 prune_ts.tv_sec += next_wait;
1945c96f 1664 }
ffb1b882
UD
1665}
1666
1667
1668/* This is the main loop. It is replicated in different threads but
ded5b9b7 1669 the use of the ready list makes sure only one thread handles an
ffb1b882
UD
1670 incoming connection. */
1671static void *
1672__attribute__ ((__noreturn__))
1673nscd_run_worker (void *p)
1674{
1675 char buf[256];
1945c96f
UD
1676
1677 /* Initial locking. */
1678 pthread_mutex_lock (&readylist_lock);
1679
1680 /* One more thread available. */
1681 ++nready;
0fdb4f42 1682
1945c96f
UD
1683 while (1)
1684 {
1685 while (readylist == NULL)
ffb1b882 1686 pthread_cond_wait (&readylist_cond, &readylist_lock);
0fdb4f42 1687
1945c96f
UD
1688 struct fdlist *it = readylist->next;
1689 if (readylist->next == readylist)
1690 /* Just one entry on the list. */
1691 readylist = NULL;
1692 else
1693 readylist->next = it->next;
0fdb4f42 1694
1945c96f
UD
1695 /* Extract the information and mark the record ready to be used
1696 again. */
1697 int fd = it->fd;
1698 it->next = NULL;
0fdb4f42 1699
1945c96f
UD
1700 /* One more thread available. */
1701 --nready;
67479a70 1702
1945c96f
UD
1703 /* We are done with the list. */
1704 pthread_mutex_unlock (&readylist_lock);
67479a70 1705
f93fc0b7
UD
1706#ifndef __ASSUME_ACCEPT4
1707 if (have_accept4 < 0)
3ff2c948
UD
1708 {
1709 /* We do not want to block on a short read or so. */
1710 int fl = fcntl (fd, F_GETFL);
1711 if (fl == -1 || fcntl (fd, F_SETFL, fl | O_NONBLOCK) == -1)
1712 goto close_and_out;
1713 }
1714#endif
0fdb4f42
UD
1715
1716 /* Now read the request. */
1945c96f 1717 request_header req;
0fdb4f42
UD
1718 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
1719 != sizeof (req), 0))
d67281a7 1720 {
1945c96f
UD
1721 /* We failed to read data. Note that this also might mean we
1722 failed because we would have blocked. */
0fdb4f42
UD
1723 if (debug_level > 0)
1724 dbg_log (_("short read while reading request: %s"),
1725 strerror_r (errno, buf, sizeof (buf)));
1945c96f 1726 goto close_and_out;
0fdb4f42
UD
1727 }
1728
3c82c131
UD
1729 /* Check whether this is a valid request type. */
1730 if (req.type < GETPWBYNAME || req.type >= LASTREQ)
1731 goto close_and_out;
1732
0fdb4f42
UD
1733 /* Some systems have no SO_PEERCRED implementation. They don't
1734 care about security so we don't as well. */
1945c96f 1735 uid_t uid = -1;
c86e6aec 1736#ifdef SO_PEERCRED
1945c96f
UD
1737 pid_t pid = 0;
1738
a1ffb40e 1739 if (__glibc_unlikely (debug_level > 0))
0fdb4f42
UD
1740 {
1741 struct ucred caller;
1742 socklen_t optlen = sizeof (caller);
c86e6aec 1743
0fdb4f42
UD
1744 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) == 0)
1745 pid = caller.pid;
1746 }
c52137d3
UD
1747#else
1748 const pid_t pid = 0;
cedc8559 1749#endif
a1c542bf 1750
0fdb4f42
UD
1751 /* It should not be possible to crash the nscd with a silly
1752 request (i.e., a terribly large key). We limit the size to 1kb. */
1753 if (__builtin_expect (req.key_len, 1) < 0
1945c96f 1754 || __builtin_expect (req.key_len, 1) > MAXKEYLEN)
0fdb4f42
UD
1755 {
1756 if (debug_level > 0)
1757 dbg_log (_("key length in request too long: %d"), req.key_len);
0fdb4f42
UD
1758 }
1759 else
1760 {
1761 /* Get the key. */
50fd745b 1762 char keybuf[MAXKEYLEN + 1];
0fdb4f42
UD
1763
1764 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
1765 req.key_len))
1766 != req.key_len, 0))
67479a70 1767 {
1945c96f 1768 /* Again, this can also mean we would have blocked. */
98e75a1c 1769 if (debug_level > 0)
0fdb4f42
UD
1770 dbg_log (_("short read while reading request key: %s"),
1771 strerror_r (errno, buf, sizeof (buf)));
1945c96f 1772 goto close_and_out;
67479a70 1773 }
50fd745b 1774 keybuf[req.key_len] = '\0';
0fdb4f42
UD
1775
1776 if (__builtin_expect (debug_level, 0) > 0)
67479a70 1777 {
c86e6aec 1778#ifdef SO_PEERCRED
0fdb4f42
UD
1779 if (pid != 0)
1780 dbg_log (_("\
c86e6aec 1781handle_request: request received (Version = %d) from PID %ld"),
0fdb4f42
UD
1782 req.version, (long int) pid);
1783 else
c86e6aec 1784#endif
0fdb4f42 1785 dbg_log (_("\
c86e6aec 1786handle_request: request received (Version = %d)"), req.version);
0fdb4f42 1787 }
c86e6aec 1788
0fdb4f42 1789 /* Phew, we got all the data, now process it. */
c52137d3 1790 handle_request (fd, &req, keybuf, uid, pid);
d67281a7 1791 }
264d5b94 1792
3c82c131
UD
1793 close_and_out:
1794 /* We are done. */
1795 close (fd);
1796
1945c96f
UD
1797 /* Re-locking. */
1798 pthread_mutex_lock (&readylist_lock);
1799
1800 /* One more thread available. */
1801 ++nready;
1802 }
1ac03a1e 1803 /* NOTREACHED */
1945c96f
UD
1804}
1805
1806
fc03df7a
UD
1807static unsigned int nconns;
1808
1945c96f 1809static void
fc03df7a 1810fd_ready (int fd)
1945c96f 1811{
fc03df7a
UD
1812 pthread_mutex_lock (&readylist_lock);
1813
1814 /* Find an empty entry in FDLIST. */
1815 size_t inner;
1816 for (inner = 0; inner < nconns; ++inner)
1817 if (fdlist[inner].next == NULL)
1818 break;
1819 assert (inner < nconns);
1820
1821 fdlist[inner].fd = fd;
1822
1823 if (readylist == NULL)
1824 readylist = fdlist[inner].next = &fdlist[inner];
1945c96f 1825 else
fc03df7a
UD
1826 {
1827 fdlist[inner].next = readylist->next;
1828 readylist = readylist->next = &fdlist[inner];
1829 }
1830
1831 bool do_signal = true;
a1ffb40e 1832 if (__glibc_unlikely (nready == 0))
fc03df7a
UD
1833 {
1834 ++client_queued;
1835 do_signal = false;
27e82856
UD
1836
1837 /* Try to start another thread to help out. */
1838 pthread_t th;
1839 if (nthreads < max_nthreads
ffb1b882 1840 && pthread_create (&th, &attr, nscd_run_worker,
27e82856
UD
1841 (void *) (long int) nthreads) == 0)
1842 {
1843 /* We got another thread. */
1844 ++nthreads;
908c9e87 1845 /* The new thread might need a kick. */
27e82856
UD
1846 do_signal = true;
1847 }
1848
fc03df7a
UD
1849 }
1850
1851 pthread_mutex_unlock (&readylist_lock);
1852
1853 /* Tell one of the worker threads there is work to do. */
1854 if (do_signal)
1855 pthread_cond_signal (&readylist_cond);
1856}
1945c96f 1857
fc03df7a 1858
4401d759 1859/* Check whether restarting should happen. */
f1d70dad 1860static bool
4401d759
UD
1861restart_p (time_t now)
1862{
1863 return (paranoia && readylist == NULL && nready == nthreads
1864 && now >= restart_time);
1865}
1866
1867
1868/* Array for times a connection was accepted. */
fc03df7a
UD
1869static time_t *starttime;
1870
471514d3
CD
1871#ifdef HAVE_INOTIFY
1872/* Inotify event for changed file. */
1873union __inev
1874{
1875 struct inotify_event i;
1876# ifndef PATH_MAX
1877# define PATH_MAX 1024
1878# endif
1879 char buf[sizeof (struct inotify_event) + PATH_MAX];
1880};
1881
1882/* Process the inotify event in INEV. If the event matches any of the files
1883 registered with a database then mark that database as requiring its cache
1884 to be cleared. We indicate the cache needs clearing by setting
1885 TO_CLEAR[DBCNT] to true for the matching database. */
1886static inline void
1887inotify_check_files (bool *to_clear, union __inev *inev)
1888{
1889 /* Check which of the files changed. */
1890 for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
1891 {
1892 struct traced_file *finfo = dbs[dbcnt].traced_files;
1893
1894 while (finfo != NULL)
1895 {
1896 /* Inotify event watch descriptor matches. */
1897 if (finfo->inotify_descr == inev->i.wd)
1898 {
1899 /* Mark cache as needing to be cleared and reinitialize. */
1900 to_clear[dbcnt] = true;
1901 if (finfo->call_res_init)
1902 res_init ();
1903 return;
1904 }
1905
1906 finfo = finfo->next;
1907 }
1908 }
1909}
1910
1911/* If an entry in the array of booleans TO_CLEAR is TRUE then clear the cache
1912 for the associated database, otherwise do nothing. The TO_CLEAR array must
1913 have LASTDB entries. */
1914static inline void
1915clear_db_cache (bool *to_clear)
1916{
1917 for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
1918 if (to_clear[dbcnt])
1919 {
1920 pthread_mutex_lock (&dbs[dbcnt].prune_lock);
1921 dbs[dbcnt].clear_cache = 1;
1922 pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
1923 pthread_cond_signal (&dbs[dbcnt].prune_cond);
1924 }
1925}
1926
1927#endif
fc03df7a
UD
1928
1929static void
1930__attribute__ ((__noreturn__))
1931main_loop_poll (void)
1932{
1945c96f
UD
1933 struct pollfd *conns = (struct pollfd *) xmalloc (nconns
1934 * sizeof (conns[0]));
1935
1945c96f
UD
1936 conns[0].fd = sock;
1937 conns[0].events = POLLRDNORM;
1938 size_t nused = 1;
1939 size_t firstfree = 1;
1940
5228ba2f
UD
1941#ifdef HAVE_INOTIFY
1942 if (inotify_fd != -1)
1943 {
1944 conns[1].fd = inotify_fd;
1945 conns[1].events = POLLRDNORM;
1946 nused = 2;
1947 firstfree = 2;
1948 }
1949#endif
1950
3a2c0242
UD
1951#ifdef HAVE_NETLINK
1952 size_t idx_nl_status_fd = 0;
1953 if (nl_status_fd != -1)
1954 {
1955 idx_nl_status_fd = nused;
1956 conns[nused].fd = nl_status_fd;
1957 conns[nused].events = POLLRDNORM;
1958 ++nused;
1959 firstfree = nused;
1960 }
1961#endif
1962
1945c96f
UD
1963 while (1)
1964 {
1965 /* Wait for any event. We wait at most a couple of seconds so
1966 that we can check whether we should close any of the accepted
1967 connections since we have not received a request. */
1968#define MAX_ACCEPT_TIMEOUT 30
1969#define MIN_ACCEPT_TIMEOUT 5
1970#define MAIN_THREAD_TIMEOUT \
1971 (MAX_ACCEPT_TIMEOUT * 1000 \
1972 - ((MAX_ACCEPT_TIMEOUT - MIN_ACCEPT_TIMEOUT) * 1000 * nused) / (2 * nconns))
1973
1974 int n = poll (conns, nused, MAIN_THREAD_TIMEOUT);
1975
1976 time_t now = time (NULL);
1977
1978 /* If there is a descriptor ready for reading or there is a new
1979 connection, process this now. */
1980 if (n > 0)
67479a70 1981 {
1945c96f
UD
1982 if (conns[0].revents != 0)
1983 {
1984 /* We have a new incoming connection. Accept the connection. */
3ff2c948
UD
1985 int fd;
1986
f93fc0b7 1987#ifndef __ASSUME_ACCEPT4
3ff2c948 1988 fd = -1;
f93fc0b7 1989 if (have_accept4 >= 0)
3ff2c948
UD
1990#endif
1991 {
f93fc0b7 1992 fd = TEMP_FAILURE_RETRY (accept4 (sock, NULL, NULL,
3ff2c948 1993 SOCK_NONBLOCK));
f93fc0b7
UD
1994#ifndef __ASSUME_ACCEPT4
1995 if (have_accept4 == 0)
1996 have_accept4 = fd != -1 || errno != ENOSYS ? 1 : -1;
3ff2c948
UD
1997#endif
1998 }
f93fc0b7
UD
1999#ifndef __ASSUME_ACCEPT4
2000 if (have_accept4 < 0)
3ff2c948
UD
2001 fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL));
2002#endif
1945c96f 2003
9388dcbb
UD
2004 /* Use the descriptor if we have not reached the limit. */
2005 if (fd >= 0)
1945c96f 2006 {
9388dcbb
UD
2007 if (firstfree < nconns)
2008 {
2009 conns[firstfree].fd = fd;
2010 conns[firstfree].events = POLLRDNORM;
2011 starttime[firstfree] = now;
2012 if (firstfree >= nused)
2013 nused = firstfree + 1;
2014
2015 do
2016 ++firstfree;
2017 while (firstfree < nused && conns[firstfree].fd != -1);
2018 }
2019 else
2020 /* We cannot use the connection so close it. */
2021 close (fd);
1945c96f
UD
2022 }
2023
1945c96f
UD
2024 --n;
2025 }
2026
5228ba2f
UD
2027 size_t first = 1;
2028#ifdef HAVE_INOTIFY
b7432416 2029 if (inotify_fd != -1 && conns[1].fd == inotify_fd)
5228ba2f
UD
2030 {
2031 if (conns[1].revents != 0)
2032 {
b7432416 2033 bool to_clear[lastdb] = { false, };
471514d3 2034 union __inev inev;
5228ba2f 2035
471514d3
CD
2036 /* Read all inotify events for files registered via
2037 register_traced_file(). */
b7432416 2038 while (1)
5228ba2f 2039 {
b7432416
UD
2040 ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
2041 sizeof (inev)));
2042 if (nb < (ssize_t) sizeof (struct inotify_event))
2043 {
39e175bb
UD
2044 if (__builtin_expect (nb == -1 && errno != EAGAIN,
2045 0))
b7432416
UD
2046 {
2047 /* Something went wrong when reading the inotify
2048 data. Better disable inotify. */
39e175bb
UD
2049 dbg_log (_("\
2050disabled inotify after read error %d"),
2051 errno);
b7432416
UD
2052 conns[1].fd = -1;
2053 firstfree = 1;
2054 if (nused == 2)
2055 nused = 1;
2056 close (inotify_fd);
2057 inotify_fd = -1;
b7432416
UD
2058 }
2059 break;
2060 }
2061
5228ba2f 2062 /* Check which of the files changed. */
471514d3 2063 inotify_check_files (to_clear, &inev);
5228ba2f
UD
2064 }
2065
b7432416 2066 /* Actually perform the cache clearing. */
471514d3 2067 clear_db_cache (to_clear);
b7432416 2068
5228ba2f
UD
2069 --n;
2070 }
2071
2072 first = 2;
2073 }
2074#endif
2075
3a2c0242
UD
2076#ifdef HAVE_NETLINK
2077 if (idx_nl_status_fd != 0 && conns[idx_nl_status_fd].revents != 0)
2078 {
2079 char buf[4096];
2080 /* Read all the data. We do not interpret it here. */
2081 while (TEMP_FAILURE_RETRY (read (nl_status_fd, buf,
2082 sizeof (buf))) != -1)
2083 ;
2084
2085 dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP]
2086 = __bump_nl_timestamp ();
2087 }
2088#endif
2089
5228ba2f 2090 for (size_t cnt = first; cnt < nused && n > 0; ++cnt)
1945c96f
UD
2091 if (conns[cnt].revents != 0)
2092 {
fc03df7a 2093 fd_ready (conns[cnt].fd);
1945c96f
UD
2094
2095 /* Clean up the CONNS array. */
2096 conns[cnt].fd = -1;
2097 if (cnt < firstfree)
2098 firstfree = cnt;
2099 if (cnt == nused - 1)
2100 do
2101 --nused;
2102 while (conns[nused - 1].fd == -1);
2103
2104 --n;
2105 }
2106 }
2107
2108 /* Now find entries which have timed out. */
2109 assert (nused > 0);
fc03df7a
UD
2110
2111 /* We make the timeout length depend on the number of file
2112 descriptors currently used. */
1945c96f
UD
2113#define ACCEPT_TIMEOUT \
2114 (MAX_ACCEPT_TIMEOUT \
2115 - ((MAX_ACCEPT_TIMEOUT - MIN_ACCEPT_TIMEOUT) * nused) / nconns)
fc03df7a 2116 time_t laststart = now - ACCEPT_TIMEOUT;
1945c96f 2117
fc03df7a
UD
2118 for (size_t cnt = nused - 1; cnt > 0; --cnt)
2119 {
1945c96f
UD
2120 if (conns[cnt].fd != -1 && starttime[cnt] < laststart)
2121 {
2122 /* Remove the entry, it timed out. */
2123 (void) close (conns[cnt].fd);
2124 conns[cnt].fd = -1;
2125
2126 if (cnt < firstfree)
2127 firstfree = cnt;
2128 if (cnt == nused - 1)
2129 do
2130 --nused;
2131 while (conns[nused - 1].fd == -1);
2132 }
67479a70 2133 }
4401d759
UD
2134
2135 if (restart_p (now))
2136 restart ();
67308730 2137 }
d67281a7
UD
2138}
2139
67479a70 2140
fc03df7a
UD
2141#ifdef HAVE_EPOLL
2142static void
2143main_loop_epoll (int efd)
2144{
2145 struct epoll_event ev = { 0, };
2146 int nused = 1;
2147 size_t highest = 0;
2148
2149 /* Add the socket. */
2150 ev.events = EPOLLRDNORM;
2151 ev.data.fd = sock;
2152 if (epoll_ctl (efd, EPOLL_CTL_ADD, sock, &ev) == -1)
2153 /* We cannot use epoll. */
2154 return;
2155
f93fc0b7 2156# ifdef HAVE_INOTIFY
5228ba2f
UD
2157 if (inotify_fd != -1)
2158 {
2159 ev.events = EPOLLRDNORM;
2160 ev.data.fd = inotify_fd;
2161 if (epoll_ctl (efd, EPOLL_CTL_ADD, inotify_fd, &ev) == -1)
2162 /* We cannot use epoll. */
2163 return;
2164 nused = 2;
2165 }
f93fc0b7 2166# endif
5228ba2f 2167
3a2c0242
UD
2168# ifdef HAVE_NETLINK
2169 if (nl_status_fd != -1)
2170 {
2171 ev.events = EPOLLRDNORM;
2172 ev.data.fd = nl_status_fd;
2173 if (epoll_ctl (efd, EPOLL_CTL_ADD, nl_status_fd, &ev) == -1)
2174 /* We cannot use epoll. */
2175 return;
2176 }
2177# endif
2178
fc03df7a
UD
2179 while (1)
2180 {
2181 struct epoll_event revs[100];
2182# define nrevs (sizeof (revs) / sizeof (revs[0]))
2183
2184 int n = epoll_wait (efd, revs, nrevs, MAIN_THREAD_TIMEOUT);
2185
2186 time_t now = time (NULL);
2187
2188 for (int cnt = 0; cnt < n; ++cnt)
2189 if (revs[cnt].data.fd == sock)
2190 {
2191 /* A new connection. */
f93fc0b7
UD
2192 int fd;
2193
2194# ifndef __ASSUME_ACCEPT4
2195 fd = -1;
2196 if (have_accept4 >= 0)
2197# endif
2198 {
2199 fd = TEMP_FAILURE_RETRY (accept4 (sock, NULL, NULL,
2200 SOCK_NONBLOCK));
2201# ifndef __ASSUME_ACCEPT4
2202 if (have_accept4 == 0)
2203 have_accept4 = fd != -1 || errno != ENOSYS ? 1 : -1;
2204# endif
2205 }
2206# ifndef __ASSUME_ACCEPT4
2207 if (have_accept4 < 0)
2208 fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL));
2209# endif
fc03df7a 2210
f93fc0b7 2211 /* Use the descriptor if we have not reached the limit. */
fc03df7a
UD
2212 if (fd >= 0)
2213 {
2214 /* Try to add the new descriptor. */
2215 ev.data.fd = fd;
2216 if (fd >= nconns
2217 || epoll_ctl (efd, EPOLL_CTL_ADD, fd, &ev) == -1)
2218 /* The descriptor is too large or something went
2219 wrong. Close the descriptor. */
2220 close (fd);
2221 else
2222 {
2223 /* Remember when we accepted the connection. */
2224 starttime[fd] = now;
2225
2226 if (fd > highest)
2227 highest = fd;
2228
2229 ++nused;
2230 }
2231 }
2232 }
f93fc0b7 2233# ifdef HAVE_INOTIFY
5228ba2f
UD
2234 else if (revs[cnt].data.fd == inotify_fd)
2235 {
b7432416 2236 bool to_clear[lastdb] = { false, };
471514d3 2237 union __inev inev;
5228ba2f 2238
471514d3
CD
2239 /* Read all inotify events for files registered via
2240 register_traced_file(). */
b7432416 2241 while (1)
5228ba2f 2242 {
b7432416 2243 ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
319b9ad4 2244 sizeof (inev)));
b7432416
UD
2245 if (nb < (ssize_t) sizeof (struct inotify_event))
2246 {
a1ffb40e 2247 if (__glibc_unlikely (nb == -1 && errno != EAGAIN))
b7432416
UD
2248 {
2249 /* Something went wrong when reading the inotify
2250 data. Better disable inotify. */
39e175bb
UD
2251 dbg_log (_("disabled inotify after read error %d"),
2252 errno);
b7432416
UD
2253 (void) epoll_ctl (efd, EPOLL_CTL_DEL, inotify_fd,
2254 NULL);
2255 close (inotify_fd);
2256 inotify_fd = -1;
b7432416
UD
2257 }
2258 break;
2259 }
2260
5228ba2f 2261 /* Check which of the files changed. */
471514d3 2262 inotify_check_files(to_clear, &inev);
5228ba2f 2263 }
b7432416
UD
2264
2265 /* Actually perform the cache clearing. */
471514d3 2266 clear_db_cache (to_clear);
5228ba2f 2267 }
3a2c0242
UD
2268# endif
2269# ifdef HAVE_NETLINK
2270 else if (revs[cnt].data.fd == nl_status_fd)
2271 {
2272 char buf[4096];
2273 /* Read all the data. We do not interpret it here. */
2274 while (TEMP_FAILURE_RETRY (read (nl_status_fd, buf,
2275 sizeof (buf))) != -1)
2276 ;
2277
2278 __bump_nl_timestamp ();
2279 }
f93fc0b7 2280# endif
fc03df7a
UD
2281 else
2282 {
2283 /* Remove the descriptor from the epoll descriptor. */
908c9e87 2284 (void) epoll_ctl (efd, EPOLL_CTL_DEL, revs[cnt].data.fd, NULL);
fc03df7a 2285
2461e3dc 2286 /* Get a worker to handle the request. */
fc03df7a
UD
2287 fd_ready (revs[cnt].data.fd);
2288
2289 /* Reset the time. */
2290 starttime[revs[cnt].data.fd] = 0;
2291 if (revs[cnt].data.fd == highest)
2292 do
2293 --highest;
2294 while (highest > 0 && starttime[highest] == 0);
2295
2296 --nused;
2297 }
2298
2299 /* Now look for descriptors for accepted connections which have
2300 no reply in too long of a time. */
2301 time_t laststart = now - ACCEPT_TIMEOUT;
b7432416
UD
2302 assert (starttime[sock] == 0);
2303 assert (inotify_fd == -1 || starttime[inotify_fd] == 0);
3a2c0242 2304 assert (nl_status_fd == -1 || starttime[nl_status_fd] == 0);
fc03df7a 2305 for (int cnt = highest; cnt > STDERR_FILENO; --cnt)
b7432416 2306 if (starttime[cnt] != 0 && starttime[cnt] < laststart)
fc03df7a
UD
2307 {
2308 /* We are waiting for this one for too long. Close it. */
908c9e87 2309 (void) epoll_ctl (efd, EPOLL_CTL_DEL, cnt, NULL);
fc03df7a
UD
2310
2311 (void) close (cnt);
2312
2313 starttime[cnt] = 0;
2314 if (cnt == highest)
2315 --highest;
2316 }
2317 else if (cnt != sock && starttime[cnt] == 0 && cnt == highest)
2318 --highest;
4401d759
UD
2319
2320 if (restart_p (now))
2321 restart ();
fc03df7a
UD
2322 }
2323}
2324#endif
2325
2326
67479a70 2327/* Start all the threads we want. The initial process is thread no. 1. */
d67281a7 2328void
67479a70 2329start_threads (void)
d67281a7 2330{
1945c96f
UD
2331 /* Initialize the conditional variable we will use. The only
2332 non-standard attribute we might use is the clock selection. */
2333 pthread_condattr_t condattr;
2334 pthread_condattr_init (&condattr);
2335
3078cba2
UD
2336#if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0 \
2337 && defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
1945c96f
UD
2338 /* Determine whether the monotonous clock is available. */
2339 struct timespec dummy;
3078cba2 2340# if _POSIX_MONOTONIC_CLOCK == 0
94d824f9 2341 if (sysconf (_SC_MONOTONIC_CLOCK) > 0)
3078cba2
UD
2342# endif
2343# if _POSIX_CLOCK_SELECTION == 0
94d824f9 2344 if (sysconf (_SC_CLOCK_SELECTION) > 0)
3078cba2 2345# endif
94d824f9
UD
2346 if (clock_getres (CLOCK_MONOTONIC, &dummy) == 0
2347 && pthread_condattr_setclock (&condattr, CLOCK_MONOTONIC) == 0)
2348 timeout_clock = CLOCK_MONOTONIC;
1945c96f 2349#endif
d67281a7 2350
1945c96f
UD
2351 /* Create the attribute for the threads. They are all created
2352 detached. */
67479a70
UD
2353 pthread_attr_init (&attr);
2354 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
27e82856 2355 /* Use 1MB stacks, twice as much for 64-bit architectures. */
7ea8eb02 2356 pthread_attr_setstacksize (&attr, NSCD_THREAD_STACKSIZE);
d67281a7 2357
67479a70
UD
2358 /* We allow less than LASTDB threads only for debugging. */
2359 if (debug_level == 0)
2360 nthreads = MAX (nthreads, lastdb);
d67281a7 2361
ffb1b882
UD
2362 /* Create the threads which prune the databases. */
2363 // XXX Ideally this work would be done by some of the worker threads.
2364 // XXX But this is problematic since we would need to be able to wake
2365 // XXX them up explicitly as well as part of the group handling the
2366 // XXX ready-list. This requires an operation where we can wait on
2367 // XXX two conditional variables at the same time. This operation
2368 // XXX does not exist (yet).
2369 for (long int i = 0; i < lastdb; ++i)
1945c96f 2370 {
ffb1b882
UD
2371 /* Initialize the conditional variable. */
2372 if (pthread_cond_init (&dbs[i].prune_cond, &condattr) != 0)
2373 {
2374 dbg_log (_("could not initialize conditional variable"));
532a6035 2375 do_exit (1, 0, NULL);
ffb1b882
UD
2376 }
2377
1945c96f 2378 pthread_t th;
ffb1b882
UD
2379 if (dbs[i].enabled
2380 && pthread_create (&th, &attr, nscd_run_prune, (void *) i) != 0)
2381 {
2382 dbg_log (_("could not start clean-up thread; terminating"));
532a6035 2383 do_exit (1, 0, NULL);
ffb1b882 2384 }
27e82856 2385 }
ffb1b882
UD
2386
2387 pthread_condattr_destroy (&condattr);
2388
2389 for (long int i = 0; i < nthreads; ++i)
27e82856 2390 {
ffb1b882
UD
2391 pthread_t th;
2392 if (pthread_create (&th, &attr, nscd_run_worker, NULL) != 0)
2393 {
2394 if (i == 0)
2395 {
2396 dbg_log (_("could not start any worker thread; terminating"));
532a6035 2397 do_exit (1, 0, NULL);
ffb1b882
UD
2398 }
2399
2400 break;
2401 }
1945c96f 2402 }
d67281a7 2403
532a6035
SP
2404 /* Now it is safe to let the parent know that we're doing fine and it can
2405 exit. */
2406 notify_parent (0);
2407
fc03df7a
UD
2408 /* Determine how much room for descriptors we should initially
2409 allocate. This might need to change later if we cap the number
2410 with MAXCONN. */
2411 const long int nfds = sysconf (_SC_OPEN_MAX);
2412#define MINCONN 32
2413#define MAXCONN 16384
2414 if (nfds == -1 || nfds > MAXCONN)
2415 nconns = MAXCONN;
2416 else if (nfds < MINCONN)
2417 nconns = MINCONN;
2418 else
2419 nconns = nfds;
2420
2421 /* We need memory to pass descriptors on to the worker threads. */
2422 fdlist = (struct fdlist *) xcalloc (nconns, sizeof (fdlist[0]));
2423 /* Array to keep track when connection was accepted. */
2424 starttime = (time_t *) xcalloc (nconns, sizeof (starttime[0]));
2425
1945c96f
UD
2426 /* In the main thread we execute the loop which handles incoming
2427 connections. */
fc03df7a
UD
2428#ifdef HAVE_EPOLL
2429 int efd = epoll_create (100);
2430 if (efd != -1)
2431 {
2432 main_loop_epoll (efd);
2433 close (efd);
2434 }
2435#endif
2436
2437 main_loop_poll ();
d67281a7 2438}
057685e4
UD
2439
2440
2441/* Look up the uid, gid, and supplementary groups to run nscd as. When
2442 this function is called, we are not listening on the nscd socket yet so
2443 we can just use the ordinary lookup functions without causing a lockup */
2444static void
2445begin_drop_privileges (void)
2446{
a95a08b4 2447 struct passwd *pwd = getpwnam (server_user);
057685e4
UD
2448
2449 if (pwd == NULL)
2450 {
2451 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
532a6035
SP
2452 do_exit (EXIT_FAILURE, 0,
2453 _("Failed to run nscd as user '%s'"), server_user);
057685e4
UD
2454 }
2455
2456 server_uid = pwd->pw_uid;
2457 server_gid = pwd->pw_gid;
2458
4401d759
UD
2459 /* Save the old UID/GID if we have to change back. */
2460 if (paranoia)
2461 {
2462 old_uid = getuid ();
2463 old_gid = getgid ();
2464 }
2465
a95a08b4
UD
2466 if (getgrouplist (server_user, server_gid, NULL, &server_ngroups) == 0)
2467 {
2468 /* This really must never happen. */
2469 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
532a6035
SP
2470 do_exit (EXIT_FAILURE, errno,
2471 _("initial getgrouplist failed"));
a95a08b4 2472 }
057685e4 2473
a95a08b4 2474 server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
057685e4
UD
2475
2476 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
2477 == -1)
2478 {
2479 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
532a6035 2480 do_exit (EXIT_FAILURE, errno, _("getgrouplist failed"));
057685e4
UD
2481 }
2482}
2483
2484
2485/* Call setgroups(), setgid(), and setuid() to drop root privileges and
2486 run nscd as the user specified in the configuration file. */
2487static void
2488finish_drop_privileges (void)
2489{
1f063dca
UD
2490#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP
2491 /* We need to preserve the capabilities to connect to the audit daemon. */
2492 cap_t new_caps = preserve_capabilities ();
2493#endif
2494
057685e4
UD
2495 if (setgroups (server_ngroups, server_groups) == -1)
2496 {
2497 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
532a6035 2498 do_exit (EXIT_FAILURE, errno, _("setgroups failed"));
057685e4
UD
2499 }
2500
91287339
UD
2501 int res;
2502 if (paranoia)
2503 res = setresgid (server_gid, server_gid, old_gid);
2504 else
2505 res = setgid (server_gid);
2506 if (res == -1)
057685e4
UD
2507 {
2508 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
532a6035 2509 do_exit (4, errno, "setgid");
057685e4
UD
2510 }
2511
91287339
UD
2512 if (paranoia)
2513 res = setresuid (server_uid, server_uid, old_uid);
2514 else
2515 res = setuid (server_uid);
2516 if (res == -1)
057685e4
UD
2517 {
2518 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
532a6035 2519 do_exit (4, errno, "setuid");
057685e4 2520 }
1f063dca
UD
2521
2522#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP
2523 /* Remove the temporary capabilities. */
2524 install_real_capabilities (new_caps);
2525#endif
057685e4 2526}