Update.
[glibc.git] / nscd / connections.c
blobc3100816dff64da5656ed9ed82ed0637c5886a1c
1 /* Inner loops of cache daemon.
2 Copyright (C) 1998-2003, 2004 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include <assert.h>
22 #include <atomic.h>
23 #include <error.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <grp.h>
27 #include <libintl.h>
28 #include <pthread.h>
29 #include <pwd.h>
30 #include <resolv.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <arpa/inet.h>
35 #include <sys/mman.h>
36 #include <sys/param.h>
37 #include <sys/poll.h>
38 #include <sys/socket.h>
39 #include <sys/stat.h>
40 #include <sys/un.h>
42 #include "nscd.h"
43 #include "dbg_log.h"
46 /* Number of bytes of data we initially reserve for each hash table bucket. */
47 #define DEFAULT_DATASIZE_PER_BUCKET 1024
50 /* Wrapper functions with error checking for standard functions. */
51 extern void *xmalloc (size_t n);
52 extern void *xcalloc (size_t n, size_t s);
53 extern void *xrealloc (void *o, size_t n);
55 /* Support to run nscd as an unprivileged user */
56 const char *server_user;
57 static uid_t server_uid;
58 static gid_t server_gid;
59 const char *stat_user;
60 uid_t stat_uid;
61 static gid_t *server_groups;
62 #ifndef NGROUPS
63 # define NGROUPS 32
64 #endif
65 static int server_ngroups;
67 static void begin_drop_privileges (void);
68 static void finish_drop_privileges (void);
70 /* Map request type to a string. */
71 const char *serv2str[LASTREQ] =
73 [GETPWBYNAME] = "GETPWBYNAME",
74 [GETPWBYUID] = "GETPWBYUID",
75 [GETGRBYNAME] = "GETGRBYNAME",
76 [GETGRBYGID] = "GETGRBYGID",
77 [GETHOSTBYNAME] = "GETHOSTBYNAME",
78 [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6",
79 [GETHOSTBYADDR] = "GETHOSTBYADDR",
80 [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
81 [SHUTDOWN] = "SHUTDOWN",
82 [GETSTAT] = "GETSTAT",
83 [INVALIDATE] = "INVALIDATE"
86 /* The control data structures for the services. */
87 struct database_dyn dbs[lastdb] =
89 [pwddb] = {
90 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
91 .enabled = 0,
92 .check_file = 1,
93 .persistent = 0,
94 .filename = "/etc/passwd",
95 .db_filename = _PATH_NSCD_PASSWD_DB,
96 .disabled_iov = &pwd_iov_disabled,
97 .postimeout = 3600,
98 .negtimeout = 20,
99 .wr_fd = -1,
100 .ro_fd = -1,
101 .mmap_used = false
103 [grpdb] = {
104 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
105 .enabled = 0,
106 .check_file = 1,
107 .persistent = 0,
108 .filename = "/etc/group",
109 .db_filename = _PATH_NSCD_GROUP_DB,
110 .disabled_iov = &grp_iov_disabled,
111 .postimeout = 3600,
112 .negtimeout = 60,
113 .wr_fd = -1,
114 .ro_fd = -1,
115 .mmap_used = false
117 [hstdb] = {
118 .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
119 .enabled = 0,
120 .check_file = 1,
121 .persistent = 0,
122 .filename = "/etc/hosts",
123 .db_filename = _PATH_NSCD_HOSTS_DB,
124 .disabled_iov = &hst_iov_disabled,
125 .postimeout = 3600,
126 .negtimeout = 20,
127 .wr_fd = -1,
128 .ro_fd = -1,
129 .mmap_used = false
134 /* Mapping of request type to database. */
135 static struct database_dyn *const serv2db[LASTDBREQ + 1] =
137 [GETPWBYNAME] = &dbs[pwddb],
138 [GETPWBYUID] = &dbs[pwddb],
139 [GETGRBYNAME] = &dbs[grpdb],
140 [GETGRBYGID] = &dbs[grpdb],
141 [GETHOSTBYNAME] = &dbs[hstdb],
142 [GETHOSTBYNAMEv6] = &dbs[hstdb],
143 [GETHOSTBYADDR] = &dbs[hstdb],
144 [GETHOSTBYADDRv6] = &dbs[hstdb]
148 /* Number of seconds between two cache pruning runs. */
149 #define CACHE_PRUNE_INTERVAL 15
152 /* Number of threads to use. */
153 int nthreads = -1;
155 /* Socket for incoming connections. */
156 static int sock;
158 /* Number of times clients had to wait. */
159 unsigned long int client_queued;
161 /* Alignment requirement of the beginning of the data region. */
162 #define ALIGN 16
165 /* Initialize database information structures. */
166 void
167 nscd_init (void)
169 struct sockaddr_un sock_addr;
170 size_t cnt;
172 /* Secure mode and unprivileged mode are incompatible */
173 if (server_user != NULL && secure_in_use)
175 dbg_log (_("Cannot run nscd in secure mode as unprivileged user"));
176 exit (1);
179 /* Look up unprivileged uid/gid/groups before we start listening on the
180 socket */
181 if (server_user != NULL)
182 begin_drop_privileges ();
184 if (nthreads == -1)
185 /* No configuration for this value, assume a default. */
186 nthreads = 2 * lastdb;
188 for (cnt = 0; cnt < lastdb; ++cnt)
189 if (dbs[cnt].enabled)
191 pthread_rwlock_init (&dbs[cnt].lock, NULL);
192 pthread_mutex_init (&dbs[cnt].memlock, NULL);
194 if (dbs[cnt].persistent)
196 /* Try to open the appropriate file on disk. */
197 int fd = open (dbs[cnt].db_filename, O_RDWR);
198 if (fd != -1)
200 struct stat64 st;
201 void *mem;
202 size_t total;
203 struct database_pers_head head;
204 ssize_t n = TEMP_FAILURE_RETRY (read (fd, &head,
205 sizeof (head)));
206 if (n != sizeof (head) || fstat64 (fd, &st) != 0)
208 fail_db:
209 dbg_log (_("invalid persistent database file \"%s\": %s"),
210 dbs[cnt].db_filename, strerror (errno));
211 dbs[cnt].persistent = 0;
213 else if (head.module == 0 && head.data_size == 0)
215 /* The file has been created, but the head has not been
216 initialized yet. Remove the old file. */
217 unlink (dbs[cnt].db_filename);
219 else if (head.header_size != (int) sizeof (head))
221 dbg_log (_("invalid persistent database file \"%s\": %s"),
222 dbs[cnt].db_filename,
223 _("header size does not match"));
224 dbs[cnt].persistent = 0;
226 else if ((total = (sizeof (head)
227 + roundup (head.module
228 * sizeof (struct hashentry),
229 ALIGN)
230 + head.data_size))
231 < st.st_size)
233 dbg_log (_("invalid persistent database file \"%s\": %s"),
234 dbs[cnt].db_filename,
235 _("file size does not match"));
236 dbs[cnt].persistent = 0;
238 else if ((mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
239 MAP_SHARED, fd, 0)) == MAP_FAILED)
240 goto fail_db;
241 else
243 /* Success. We have the database. */
244 dbs[cnt].head = mem;
245 dbs[cnt].memsize = total;
246 dbs[cnt].data = (char *)
247 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
248 ALIGN / sizeof (ref_t))];
249 dbs[cnt].mmap_used = true;
251 if (dbs[cnt].suggested_module > head.module)
252 dbg_log (_("suggested size of table for database %s larger than the persistent database's table"),
253 dbnames[cnt]);
255 dbs[cnt].wr_fd = fd;
256 fd = -1;
257 /* We also need a read-only descriptor. */
258 dbs[cnt].ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
259 if (dbs[cnt].ro_fd == -1)
260 dbg_log (_("\
261 cannot create read-only descriptor for \"%s\"; no mmap"),
262 dbs[cnt].db_filename);
264 // XXX Shall we test whether the descriptors actually
265 // XXX point to the same file?
268 /* Close the file descriptors in case something went
269 wrong in which case the variable have not been
270 assigned -1. */
271 if (fd != -1)
272 close (fd);
276 if (dbs[cnt].head == NULL)
278 /* No database loaded. Allocate the data structure,
279 possibly on disk. */
280 struct database_pers_head head;
281 size_t total = (sizeof (head)
282 + roundup (dbs[cnt].suggested_module
283 * sizeof (ref_t), ALIGN)
284 + (dbs[cnt].suggested_module
285 * DEFAULT_DATASIZE_PER_BUCKET));
287 /* Try to create the database. If we do not need a
288 persistent database create a temporary file. */
289 int fd;
290 int ro_fd = -1;
291 if (dbs[cnt].persistent)
293 fd = open (dbs[cnt].db_filename,
294 O_RDWR | O_CREAT | O_EXCL | O_TRUNC,
295 S_IRUSR | S_IWUSR);
296 if (fd != -1)
297 ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
299 else
301 size_t slen = strlen (dbs[cnt].db_filename);
302 char fname[slen + 8];
303 strcpy (mempcpy (fname, dbs[cnt].db_filename, slen),
304 ".XXXXXX");
305 fd = mkstemp (fname);
307 /* We do not need the file name anymore after we
308 opened another file descriptor in read-only mode. */
309 if (fd != -1)
311 ro_fd = open (fname, O_RDONLY);
313 unlink (fname);
317 if (fd == -1)
319 if (errno == EEXIST)
321 dbg_log (_("database for %s corrupted or simultaneously used; remove %s manually if necessary and restart"),
322 dbnames[cnt], dbs[cnt].db_filename);
323 // XXX Correct way to terminate?
324 exit (1);
327 if (dbs[cnt].persistent)
328 dbg_log (_("cannot create %s; no persistent database used"),
329 dbs[cnt].db_filename);
330 else
331 dbg_log (_("cannot create %s; no sharing possible"),
332 dbs[cnt].db_filename);
334 dbs[cnt].persistent = 0;
335 // XXX remember: no mmap
337 else
339 /* Tell the user if we could not create the read-only
340 descriptor. */
341 if (ro_fd == -1)
342 dbg_log (_("\
343 cannot create read-only descriptor for \"%s\"; no mmap"),
344 dbs[cnt].db_filename);
346 /* Before we create the header, initialiye the hash
347 table. So that if we get interrupted if writing
348 the header we can recognize a partially initialized
349 database. */
350 size_t ps = sysconf (_SC_PAGESIZE);
351 char tmpbuf[ps];
352 assert (~ENDREF == 0);
353 memset (tmpbuf, '\xff', ps);
355 size_t remaining = dbs[cnt].suggested_module * sizeof (ref_t);
356 off_t offset = sizeof (head);
358 size_t towrite;
359 if (offset % ps != 0)
361 towrite = MIN (remaining, ps - (offset % ps));
362 pwrite (fd, tmpbuf, towrite, offset);
363 offset += towrite;
364 remaining -= towrite;
367 while (remaining > ps)
369 pwrite (fd, tmpbuf, ps, offset);
370 offset += ps;
371 remaining -= ps;
374 if (remaining > 0)
375 pwrite (fd, tmpbuf, remaining, offset);
377 /* Create the header of the file. */
378 struct database_pers_head head =
380 .version = DB_VERSION,
381 .header_size = sizeof (head),
382 .module = dbs[cnt].suggested_module,
383 .data_size = (dbs[cnt].suggested_module
384 * DEFAULT_DATASIZE_PER_BUCKET),
385 .first_free = 0
387 void *mem;
389 if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head)))
390 != sizeof (head))
391 || ftruncate (fd, total) != 0
392 || (mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
393 MAP_SHARED, fd, 0)) == MAP_FAILED)
395 unlink (dbs[cnt].db_filename);
396 dbg_log (_("cannot write to database file %s: %s"),
397 dbs[cnt].db_filename, strerror (errno));
398 dbs[cnt].persistent = 0;
400 else
402 /* Success. */
403 dbs[cnt].head = mem;
404 dbs[cnt].data = (char *)
405 &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
406 ALIGN / sizeof (ref_t))];
407 dbs[cnt].memsize = total;
408 dbs[cnt].mmap_used = true;
410 /* Remember the descriptors. */
411 dbs[cnt].wr_fd = fd;
412 dbs[cnt].ro_fd = ro_fd;
413 fd = -1;
414 ro_fd = -1;
417 if (fd != -1)
418 close (fd);
419 if (ro_fd != -1)
420 close (ro_fd);
424 if (dbs[cnt].head == NULL)
426 /* We do not use the persistent database. Just
427 create an in-memory data structure. */
428 assert (! dbs[cnt].persistent);
430 dbs[cnt].head = xmalloc (sizeof (struct database_pers_head)
431 + (dbs[cnt].suggested_module
432 * sizeof (ref_t)));
433 memset (dbs[cnt].head, '\0', sizeof (dbs[cnt].head));
434 assert (~ENDREF == 0);
435 memset (dbs[cnt].head->array, '\xff',
436 dbs[cnt].suggested_module * sizeof (ref_t));
437 dbs[cnt].head->module = dbs[cnt].suggested_module;
438 dbs[cnt].head->data_size = (DEFAULT_DATASIZE_PER_BUCKET
439 * dbs[cnt].head->module);
440 dbs[cnt].data = xmalloc (dbs[cnt].head->data_size);
441 dbs[cnt].head->first_free = 0;
444 if (dbs[cnt].check_file)
446 /* We need the modification date of the file. */
447 struct stat st;
449 if (stat (dbs[cnt].filename, &st) < 0)
451 /* We cannot stat() the file, disable file checking. */
452 dbg_log (_("cannot stat() file `%s': %s"),
453 dbs[cnt].filename, strerror (errno));
454 dbs[cnt].check_file = 0;
456 else
457 dbs[cnt].file_mtime = st.st_mtime;
461 /* Create the socket. */
462 sock = socket (AF_UNIX, SOCK_STREAM, 0);
463 if (sock < 0)
465 dbg_log (_("cannot open socket: %s"), strerror (errno));
466 exit (1);
468 /* Bind a name to the socket. */
469 sock_addr.sun_family = AF_UNIX;
470 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
471 if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
473 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
474 exit (1);
477 /* We don't wait for data otherwise races between threads can get
478 them stuck on accept. */
479 int fl = fcntl (sock, F_GETFL);
480 if (fl != -1)
481 fcntl (sock, F_SETFL, fl | O_NONBLOCK);
483 /* Set permissions for the socket. */
484 chmod (_PATH_NSCDSOCKET, DEFFILEMODE);
486 /* Set the socket up to accept connections. */
487 if (listen (sock, SOMAXCONN) < 0)
489 dbg_log (_("cannot enable socket to accept connections: %s"),
490 strerror (errno));
491 exit (1);
494 /* Change to unprivileged uid/gid/groups if specifed in config file */
495 if (server_user != NULL)
496 finish_drop_privileges ();
500 /* Close the connections. */
501 void
502 close_sockets (void)
504 close (sock);
508 static void
509 invalidate_cache (char *key)
511 dbtype number;
513 if (strcmp (key, "passwd") == 0)
514 number = pwddb;
515 else if (strcmp (key, "group") == 0)
516 number = grpdb;
517 else if (__builtin_expect (strcmp (key, "hosts"), 0) == 0)
519 number = hstdb;
521 /* Re-initialize the resolver. resolv.conf might have changed. */
522 res_init ();
524 else
525 return;
527 if (dbs[number].enabled)
528 prune_cache (&dbs[number], LONG_MAX);
532 /* Handle new request. */
533 static void
534 handle_request (int fd, request_header *req, void *key, uid_t uid)
536 if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
538 if (debug_level > 0)
539 dbg_log (_("\
540 cannot handle old request version %d; current version is %d"),
541 req->version, NSCD_VERSION);
542 return;
545 struct database_dyn *db = serv2db[req->type];
547 if (__builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
548 && __builtin_expect (req->type, LASTDBREQ) <= LASTDBREQ)
550 if (__builtin_expect (debug_level, 0) > 0)
552 if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
554 char buf[INET6_ADDRSTRLEN];
556 dbg_log ("\t%s (%s)", serv2str[req->type],
557 inet_ntop (req->type == GETHOSTBYADDR
558 ? AF_INET : AF_INET6,
559 key, buf, sizeof (buf)));
561 else
562 dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
565 /* Is this service enabled? */
566 if (!db->enabled)
568 /* No, sent the prepared record. */
569 if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
570 db->disabled_iov->iov_len))
571 != (ssize_t) db->disabled_iov->iov_len
572 && __builtin_expect (debug_level, 0) > 0)
574 /* We have problems sending the result. */
575 char buf[256];
576 dbg_log (_("cannot write result: %s"),
577 strerror_r (errno, buf, sizeof (buf)));
580 return;
583 /* Be sure we can read the data. */
584 if (__builtin_expect (pthread_rwlock_tryrdlock (&db->lock) != 0, 0))
586 ++db->head->rdlockdelayed;
587 pthread_rwlock_rdlock (&db->lock);
590 /* See whether we can handle it from the cache. */
591 struct datahead *cached;
592 cached = (struct datahead *) cache_search (req->type, key, req->key_len,
593 db, uid);
594 if (cached != NULL)
596 /* Hurray it's in the cache. */
597 if (TEMP_FAILURE_RETRY (write (fd, cached->data, cached->recsize))
598 != cached->recsize
599 && __builtin_expect (debug_level, 0) > 0)
601 /* We have problems sending the result. */
602 char buf[256];
603 dbg_log (_("cannot write result: %s"),
604 strerror_r (errno, buf, sizeof (buf)));
607 pthread_rwlock_unlock (&db->lock);
609 return;
612 pthread_rwlock_unlock (&db->lock);
614 else if (__builtin_expect (debug_level, 0) > 0)
616 if (req->type == INVALIDATE)
617 dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
618 else
619 dbg_log ("\t%s", serv2str[req->type]);
622 /* Handle the request. */
623 switch (req->type)
625 case GETPWBYNAME:
626 addpwbyname (db, fd, req, key, uid);
627 break;
629 case GETPWBYUID:
630 addpwbyuid (db, fd, req, key, uid);
631 break;
633 case GETGRBYNAME:
634 addgrbyname (db, fd, req, key, uid);
635 break;
637 case GETGRBYGID:
638 addgrbygid (db, fd, req, key, uid);
639 break;
641 case GETHOSTBYNAME:
642 addhstbyname (db, fd, req, key, uid);
643 break;
645 case GETHOSTBYNAMEv6:
646 addhstbynamev6 (db, fd, req, key, uid);
647 break;
649 case GETHOSTBYADDR:
650 addhstbyaddr (db, fd, req, key, uid);
651 break;
653 case GETHOSTBYADDRv6:
654 addhstbyaddrv6 (db, fd, req, key, uid);
655 break;
657 case GETSTAT:
658 case SHUTDOWN:
659 case INVALIDATE:
660 if (! secure_in_use)
662 /* Get the callers credentials. */
663 #ifdef SO_PEERCRED
664 struct ucred caller;
665 socklen_t optlen = sizeof (caller);
667 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
669 char buf[256];
671 dbg_log (_("error getting callers id: %s"),
672 strerror_r (errno, buf, sizeof (buf)));
673 break;
676 uid = caller.uid;
677 #else
678 /* Some systems have no SO_PEERCRED implementation. They don't
679 care about security so we don't as well. */
680 uid = 0;
681 #endif
684 /* Accept shutdown, getstat and invalidate only from root. For
685 the stat call also allow the user specified in the config file. */
686 if (req->type == GETSTAT)
688 if (uid == 0 || uid == stat_uid)
689 send_stats (fd, dbs);
691 else if (uid == 0)
693 if (req->type == INVALIDATE)
694 invalidate_cache (key);
695 else
696 termination_handler (0);
698 break;
700 default:
701 /* Ignore the command, it's nothing we know. */
702 break;
707 /* This is the main loop. It is replicated in different threads but the
708 `poll' call makes sure only one thread handles an incoming connection. */
709 static void *
710 __attribute__ ((__noreturn__))
711 nscd_run (void *p)
713 long int my_number = (long int) p;
714 struct pollfd conn;
715 int run_prune = my_number < lastdb && dbs[my_number].enabled;
716 time_t next_prune = run_prune ? time (NULL) + CACHE_PRUNE_INTERVAL : 0;
717 static unsigned long int nready;
719 conn.fd = sock;
720 conn.events = POLLRDNORM;
722 while (1)
724 int nr;
725 time_t now = 0;
727 /* One more thread available. */
728 atomic_increment (&nready);
730 no_conn:
733 int timeout = -1;
734 if (run_prune)
736 now = time (NULL);
737 timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
740 nr = poll (&conn, 1, timeout);
742 if (nr == 0)
744 /* The `poll' call timed out. It's time to clean up the
745 cache. */
746 atomic_decrement (&nready);
747 assert (my_number < lastdb);
748 prune_cache (&dbs[my_number], time(NULL));
749 now = time (NULL);
750 next_prune = now + CACHE_PRUNE_INTERVAL;
752 goto try_get;
755 while ((conn.revents & POLLRDNORM) == 0);
757 got_data:;
758 /* We have a new incoming connection. Accept the connection. */
759 int fd = TEMP_FAILURE_RETRY (accept (conn.fd, NULL, NULL));
760 request_header req;
761 char buf[256];
762 uid_t uid = -1;
763 #ifdef SO_PEERCRED
764 pid_t pid = 0;
765 #endif
767 if (__builtin_expect (fd, 0) < 0)
769 if (errno != EAGAIN && errno != EWOULDBLOCK)
770 dbg_log (_("while accepting connection: %s"),
771 strerror_r (errno, buf, sizeof (buf)));
772 goto no_conn;
775 /* This thread is busy. */
776 atomic_decrement (&nready);
778 /* Now read the request. */
779 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
780 != sizeof (req), 0))
782 if (debug_level > 0)
783 dbg_log (_("short read while reading request: %s"),
784 strerror_r (errno, buf, sizeof (buf)));
785 close (fd);
786 continue;
789 /* Some systems have no SO_PEERCRED implementation. They don't
790 care about security so we don't as well. */
791 #ifdef SO_PEERCRED
792 if (secure_in_use)
794 struct ucred caller;
795 socklen_t optlen = sizeof (caller);
797 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
799 dbg_log (_("error getting callers id: %s"),
800 strerror_r (errno, buf, sizeof (buf)));
801 close (fd);
802 continue;
805 if (req.type < GETPWBYNAME || req.type > LASTDBREQ
806 || serv2db[req.type]->secure)
807 uid = caller.uid;
809 pid = caller.pid;
811 else if (__builtin_expect (debug_level > 0, 0))
813 struct ucred caller;
814 socklen_t optlen = sizeof (caller);
816 if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) == 0)
817 pid = caller.pid;
819 #endif
821 /* It should not be possible to crash the nscd with a silly
822 request (i.e., a terribly large key). We limit the size to 1kb. */
823 if (__builtin_expect (req.key_len, 1) < 0
824 || __builtin_expect (req.key_len, 1) > 1024)
826 if (debug_level > 0)
827 dbg_log (_("key length in request too long: %d"), req.key_len);
828 close (fd);
829 continue;
831 else
833 /* Get the key. */
834 char keybuf[req.key_len];
836 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
837 req.key_len))
838 != req.key_len, 0))
840 if (debug_level > 0)
841 dbg_log (_("short read while reading request key: %s"),
842 strerror_r (errno, buf, sizeof (buf)));
843 close (fd);
844 continue;
847 if (__builtin_expect (debug_level, 0) > 0)
849 #ifdef SO_PEERCRED
850 if (pid != 0)
851 dbg_log (_("\
852 handle_request: request received (Version = %d) from PID %ld"),
853 req.version, (long int) pid);
854 else
855 #endif
856 dbg_log (_("\
857 handle_request: request received (Version = %d)"), req.version);
860 /* Phew, we got all the data, now process it. */
861 handle_request (fd, &req, keybuf, uid);
863 /* We are done. */
864 close (fd);
867 /* Just determine whether any data is present. We do this to
868 measure whether clients are queued up. */
869 try_get:
870 nr = poll (&conn, 1, 0);
871 if (nr != 0)
873 if (nready == 0)
874 ++client_queued;
876 atomic_increment (&nready);
878 goto got_data;
884 /* Start all the threads we want. The initial process is thread no. 1. */
885 void
886 start_threads (void)
888 long int i;
889 pthread_attr_t attr;
890 pthread_t th;
892 pthread_attr_init (&attr);
893 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
895 /* We allow less than LASTDB threads only for debugging. */
896 if (debug_level == 0)
897 nthreads = MAX (nthreads, lastdb);
899 for (i = 1; i < nthreads; ++i)
900 pthread_create (&th, &attr, nscd_run, (void *) i);
902 pthread_attr_destroy (&attr);
904 nscd_run ((void *) 0);
908 /* Look up the uid, gid, and supplementary groups to run nscd as. When
909 this function is called, we are not listening on the nscd socket yet so
910 we can just use the ordinary lookup functions without causing a lockup */
911 static void
912 begin_drop_privileges (void)
914 struct passwd *pwd = getpwnam (server_user);
916 if (pwd == NULL)
918 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
919 error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"),
920 server_user);
923 server_uid = pwd->pw_uid;
924 server_gid = pwd->pw_gid;
926 if (getgrouplist (server_user, server_gid, NULL, &server_ngroups) == 0)
928 /* This really must never happen. */
929 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
930 error (EXIT_FAILURE, errno, _("initial getgrouplist failed"));
933 server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
935 if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
936 == -1)
938 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
939 error (EXIT_FAILURE, errno, _("getgrouplist failed"));
944 /* Call setgroups(), setgid(), and setuid() to drop root privileges and
945 run nscd as the user specified in the configuration file. */
946 static void
947 finish_drop_privileges (void)
949 if (setgroups (server_ngroups, server_groups) == -1)
951 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
952 error (EXIT_FAILURE, errno, _("setgroups failed"));
955 if (setgid (server_gid) == -1)
957 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
958 perror ("setgid");
959 exit (1);
962 if (setuid (server_uid) == -1)
964 dbg_log (_("Failed to run nscd as user '%s'"), server_user);
965 perror ("setuid");
966 exit (1);