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