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
34 #include <arpa/inet.h>
36 #include <sys/param.h>
38 #include <sys/socket.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
;
61 static gid_t
*server_groups
;
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",
84 [GETFDPW
] = "GETFDPW",
85 [GETFDGR
] = "GETFDGR",
86 [GETFDHST
] = "GETFDHST",
90 /* The control data structures for the services. */
91 struct database_dyn dbs
[lastdb
] =
94 .lock
= PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
,
99 .filename
= "/etc/passwd",
100 .db_filename
= _PATH_NSCD_PASSWD_DB
,
101 .disabled_iov
= &pwd_iov_disabled
,
109 .lock
= PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
,
114 .filename
= "/etc/group",
115 .db_filename
= _PATH_NSCD_GROUP_DB
,
116 .disabled_iov
= &grp_iov_disabled
,
124 .lock
= PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
,
129 .filename
= "/etc/hosts",
130 .db_filename
= _PATH_NSCD_HOSTS_DB
,
131 .disabled_iov
= &hst_iov_disabled
,
141 /* Mapping of request type to database. */
142 static struct database_dyn
*const serv2db
[LASTREQ
] =
144 [GETPWBYNAME
] = &dbs
[pwddb
],
145 [GETPWBYUID
] = &dbs
[pwddb
],
146 [GETGRBYNAME
] = &dbs
[grpdb
],
147 [GETGRBYGID
] = &dbs
[grpdb
],
148 [GETHOSTBYNAME
] = &dbs
[hstdb
],
149 [GETHOSTBYNAMEv6
] = &dbs
[hstdb
],
150 [GETHOSTBYADDR
] = &dbs
[hstdb
],
151 [GETHOSTBYADDRv6
] = &dbs
[hstdb
],
152 [GETFDPW
] = &dbs
[pwddb
],
153 [GETFDGR
] = &dbs
[grpdb
],
154 [GETFDHST
] = &dbs
[hstdb
],
155 [GETAI
] = &dbs
[hstdb
],
159 /* Number of seconds between two cache pruning runs. */
160 #define CACHE_PRUNE_INTERVAL 15
163 /* Number of threads to use. */
166 /* Socket for incoming connections. */
169 /* Number of times clients had to wait. */
170 unsigned long int client_queued
;
173 /* Initialize database information structures. */
177 struct sockaddr_un sock_addr
;
180 /* Secure mode and unprivileged mode are incompatible */
181 if (server_user
!= NULL
&& secure_in_use
)
183 dbg_log (_("Cannot run nscd in secure mode as unprivileged user"));
187 /* Look up unprivileged uid/gid/groups before we start listening on the
189 if (server_user
!= NULL
)
190 begin_drop_privileges ();
193 /* No configuration for this value, assume a default. */
194 nthreads
= 2 * lastdb
;
196 for (cnt
= 0; cnt
< lastdb
; ++cnt
)
197 if (dbs
[cnt
].enabled
)
199 pthread_rwlock_init (&dbs
[cnt
].lock
, NULL
);
200 pthread_mutex_init (&dbs
[cnt
].memlock
, NULL
);
202 if (dbs
[cnt
].persistent
)
204 /* Try to open the appropriate file on disk. */
205 int fd
= open (dbs
[cnt
].db_filename
, O_RDWR
);
211 struct database_pers_head head
;
212 ssize_t n
= TEMP_FAILURE_RETRY (read (fd
, &head
,
214 if (n
!= sizeof (head
) || fstat64 (fd
, &st
) != 0)
217 dbg_log (_("invalid persistent database file \"%s\": %s"),
218 dbs
[cnt
].db_filename
, strerror (errno
));
219 dbs
[cnt
].persistent
= 0;
221 else if (head
.module
== 0 && head
.data_size
== 0)
223 /* The file has been created, but the head has not been
224 initialized yet. Remove the old file. */
225 unlink (dbs
[cnt
].db_filename
);
227 else if (head
.header_size
!= (int) sizeof (head
))
229 dbg_log (_("invalid persistent database file \"%s\": %s"),
230 dbs
[cnt
].db_filename
,
231 _("header size does not match"));
232 dbs
[cnt
].persistent
= 0;
234 else if ((total
= (sizeof (head
)
235 + roundup (head
.module
* sizeof (ref_t
),
240 dbg_log (_("invalid persistent database file \"%s\": %s"),
241 dbs
[cnt
].db_filename
,
242 _("file size does not match"));
243 dbs
[cnt
].persistent
= 0;
245 else if ((mem
= mmap (NULL
, total
, PROT_READ
| PROT_WRITE
,
246 MAP_SHARED
, fd
, 0)) == MAP_FAILED
)
250 /* Success. We have the database. */
252 dbs
[cnt
].memsize
= total
;
253 dbs
[cnt
].data
= (char *)
254 &dbs
[cnt
].head
->array
[roundup (dbs
[cnt
].head
->module
,
255 ALIGN
/ sizeof (ref_t
))];
256 dbs
[cnt
].mmap_used
= true;
258 if (dbs
[cnt
].suggested_module
> head
.module
)
259 dbg_log (_("suggested size of table for database %s larger than the persistent database's table"),
264 /* We also need a read-only descriptor. */
267 dbs
[cnt
].ro_fd
= open (dbs
[cnt
].db_filename
, O_RDONLY
);
268 if (dbs
[cnt
].ro_fd
== -1)
270 cannot create read-only descriptor for \"%s\"; no mmap"),
271 dbs
[cnt
].db_filename
);
274 // XXX Shall we test whether the descriptors actually
275 // XXX point to the same file?
278 /* Close the file descriptors in case something went
279 wrong in which case the variable have not been
286 if (dbs
[cnt
].head
== NULL
)
288 /* No database loaded. Allocate the data structure,
290 struct database_pers_head head
;
291 size_t total
= (sizeof (head
)
292 + roundup (dbs
[cnt
].suggested_module
293 * sizeof (ref_t
), ALIGN
)
294 + (dbs
[cnt
].suggested_module
295 * DEFAULT_DATASIZE_PER_BUCKET
));
297 /* Try to create the database. If we do not need a
298 persistent database create a temporary file. */
301 if (dbs
[cnt
].persistent
)
303 fd
= open (dbs
[cnt
].db_filename
,
304 O_RDWR
| O_CREAT
| O_EXCL
| O_TRUNC
,
306 if (fd
!= -1 && dbs
[cnt
].shared
)
307 ro_fd
= open (dbs
[cnt
].db_filename
, O_RDONLY
);
311 size_t slen
= strlen (dbs
[cnt
].db_filename
);
312 char fname
[slen
+ 8];
313 strcpy (mempcpy (fname
, dbs
[cnt
].db_filename
, slen
),
315 fd
= mkstemp (fname
);
317 /* We do not need the file name anymore after we
318 opened another file descriptor in read-only mode. */
319 if (fd
!= -1 && dbs
[cnt
].shared
)
321 ro_fd
= open (fname
, O_RDONLY
);
331 dbg_log (_("database for %s corrupted or simultaneously used; remove %s manually if necessary and restart"),
332 dbnames
[cnt
], dbs
[cnt
].db_filename
);
333 // XXX Correct way to terminate?
337 if (dbs
[cnt
].persistent
)
338 dbg_log (_("cannot create %s; no persistent database used"),
339 dbs
[cnt
].db_filename
);
341 dbg_log (_("cannot create %s; no sharing possible"),
342 dbs
[cnt
].db_filename
);
344 dbs
[cnt
].persistent
= 0;
345 // XXX remember: no mmap
349 /* Tell the user if we could not create the read-only
351 if (ro_fd
== -1 && dbs
[cnt
].shared
)
353 cannot create read-only descriptor for \"%s\"; no mmap"),
354 dbs
[cnt
].db_filename
);
356 /* Before we create the header, initialiye the hash
357 table. So that if we get interrupted if writing
358 the header we can recognize a partially initialized
360 size_t ps
= sysconf (_SC_PAGESIZE
);
362 assert (~ENDREF
== 0);
363 memset (tmpbuf
, '\xff', ps
);
365 size_t remaining
= dbs
[cnt
].suggested_module
* sizeof (ref_t
);
366 off_t offset
= sizeof (head
);
369 if (offset
% ps
!= 0)
371 towrite
= MIN (remaining
, ps
- (offset
% ps
));
372 pwrite (fd
, tmpbuf
, towrite
, offset
);
374 remaining
-= towrite
;
377 while (remaining
> ps
)
379 pwrite (fd
, tmpbuf
, ps
, offset
);
385 pwrite (fd
, tmpbuf
, remaining
, offset
);
387 /* Create the header of the file. */
388 struct database_pers_head head
=
390 .version
= DB_VERSION
,
391 .header_size
= sizeof (head
),
392 .module
= dbs
[cnt
].suggested_module
,
393 .data_size
= (dbs
[cnt
].suggested_module
394 * DEFAULT_DATASIZE_PER_BUCKET
),
399 if ((TEMP_FAILURE_RETRY (write (fd
, &head
, sizeof (head
)))
401 || ftruncate (fd
, total
) != 0
402 || (mem
= mmap (NULL
, total
, PROT_READ
| PROT_WRITE
,
403 MAP_SHARED
, fd
, 0)) == MAP_FAILED
)
405 unlink (dbs
[cnt
].db_filename
);
406 dbg_log (_("cannot write to database file %s: %s"),
407 dbs
[cnt
].db_filename
, strerror (errno
));
408 dbs
[cnt
].persistent
= 0;
414 dbs
[cnt
].data
= (char *)
415 &dbs
[cnt
].head
->array
[roundup (dbs
[cnt
].head
->module
,
416 ALIGN
/ sizeof (ref_t
))];
417 dbs
[cnt
].memsize
= total
;
418 dbs
[cnt
].mmap_used
= true;
420 /* Remember the descriptors. */
422 dbs
[cnt
].ro_fd
= ro_fd
;
434 if (dbs
[cnt
].head
== NULL
)
436 /* We do not use the persistent database. Just
437 create an in-memory data structure. */
438 assert (! dbs
[cnt
].persistent
);
440 dbs
[cnt
].head
= xmalloc (sizeof (struct database_pers_head
)
441 + (dbs
[cnt
].suggested_module
443 memset (dbs
[cnt
].head
, '\0', sizeof (dbs
[cnt
].head
));
444 assert (~ENDREF
== 0);
445 memset (dbs
[cnt
].head
->array
, '\xff',
446 dbs
[cnt
].suggested_module
* sizeof (ref_t
));
447 dbs
[cnt
].head
->module
= dbs
[cnt
].suggested_module
;
448 dbs
[cnt
].head
->data_size
= (DEFAULT_DATASIZE_PER_BUCKET
449 * dbs
[cnt
].head
->module
);
450 dbs
[cnt
].data
= xmalloc (dbs
[cnt
].head
->data_size
);
451 dbs
[cnt
].head
->first_free
= 0;
454 assert (dbs
[cnt
].ro_fd
== -1);
457 if (dbs
[cnt
].check_file
)
459 /* We need the modification date of the file. */
462 if (stat (dbs
[cnt
].filename
, &st
) < 0)
464 /* We cannot stat() the file, disable file checking. */
465 dbg_log (_("cannot stat() file `%s': %s"),
466 dbs
[cnt
].filename
, strerror (errno
));
467 dbs
[cnt
].check_file
= 0;
470 dbs
[cnt
].file_mtime
= st
.st_mtime
;
474 /* Create the socket. */
475 sock
= socket (AF_UNIX
, SOCK_STREAM
, 0);
478 dbg_log (_("cannot open socket: %s"), strerror (errno
));
481 /* Bind a name to the socket. */
482 sock_addr
.sun_family
= AF_UNIX
;
483 strcpy (sock_addr
.sun_path
, _PATH_NSCDSOCKET
);
484 if (bind (sock
, (struct sockaddr
*) &sock_addr
, sizeof (sock_addr
)) < 0)
486 dbg_log ("%s: %s", _PATH_NSCDSOCKET
, strerror (errno
));
490 /* We don't wait for data otherwise races between threads can get
491 them stuck on accept. */
492 int fl
= fcntl (sock
, F_GETFL
);
494 fcntl (sock
, F_SETFL
, fl
| O_NONBLOCK
);
496 /* Set permissions for the socket. */
497 chmod (_PATH_NSCDSOCKET
, DEFFILEMODE
);
499 /* Set the socket up to accept connections. */
500 if (listen (sock
, SOMAXCONN
) < 0)
502 dbg_log (_("cannot enable socket to accept connections: %s"),
507 /* Change to unprivileged uid/gid/groups if specifed in config file */
508 if (server_user
!= NULL
)
509 finish_drop_privileges ();
513 /* Close the connections. */
522 invalidate_cache (char *key
)
526 if (strcmp (key
, "passwd") == 0)
528 else if (strcmp (key
, "group") == 0)
530 else if (__builtin_expect (strcmp (key
, "hosts"), 0) == 0)
534 /* Re-initialize the resolver. resolv.conf might have changed. */
540 if (dbs
[number
].enabled
)
541 prune_cache (&dbs
[number
], LONG_MAX
);
547 send_ro_fd (struct database_dyn
*db
, char *key
, int fd
)
549 /* If we do not have an read-only file descriptor do nothing. */
553 /* We need to send some data along with the descriptor. */
555 iov
[0].iov_base
= key
;
556 iov
[0].iov_len
= strlen (key
) + 1;
558 /* Prepare the control message to transfer the descriptor. */
559 char buf
[CMSG_SPACE (sizeof (int))];
560 struct msghdr msg
= { .msg_iov
= iov
, .msg_iovlen
= 1,
561 .msg_control
= buf
, .msg_controllen
= sizeof (buf
) };
562 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR (&msg
);
564 cmsg
->cmsg_level
= SOL_SOCKET
;
565 cmsg
->cmsg_type
= SCM_RIGHTS
;
566 cmsg
->cmsg_len
= CMSG_LEN (sizeof (int));
568 *(int *) CMSG_DATA (cmsg
) = db
->ro_fd
;
570 msg
.msg_controllen
= cmsg
->cmsg_len
;
572 /* Send the control message. We repeat when we are interrupted but
573 everything else is ignored. */
574 (void) TEMP_FAILURE_RETRY (sendmsg (fd
, &msg
, 0));
576 if (__builtin_expect (debug_level
> 0, 0))
577 dbg_log (_("provide access to FD %d, for %s"), db
->ro_fd
, key
);
579 #endif /* SCM_RIGHTS */
582 /* Handle new request. */
584 handle_request (int fd
, request_header
*req
, void *key
, uid_t uid
)
586 if (__builtin_expect (req
->version
, NSCD_VERSION
) != NSCD_VERSION
)
590 cannot handle old request version %d; current version is %d"),
591 req
->version
, NSCD_VERSION
);
595 struct database_dyn
*db
= serv2db
[req
->type
];
597 if ((__builtin_expect (req
->type
, GETPWBYNAME
) >= GETPWBYNAME
598 && __builtin_expect (req
->type
, LASTDBREQ
) <= LASTDBREQ
)
599 || req
->type
== GETAI
)
601 if (__builtin_expect (debug_level
, 0) > 0)
603 if (req
->type
== GETHOSTBYADDR
|| req
->type
== GETHOSTBYADDRv6
)
605 char buf
[INET6_ADDRSTRLEN
];
607 dbg_log ("\t%s (%s)", serv2str
[req
->type
],
608 inet_ntop (req
->type
== GETHOSTBYADDR
609 ? AF_INET
: AF_INET6
,
610 key
, buf
, sizeof (buf
)));
613 dbg_log ("\t%s (%s)", serv2str
[req
->type
], (char *) key
);
616 /* Is this service enabled? */
619 /* No, sent the prepared record. */
620 if (TEMP_FAILURE_RETRY (write (fd
, db
->disabled_iov
->iov_base
,
621 db
->disabled_iov
->iov_len
))
622 != (ssize_t
) db
->disabled_iov
->iov_len
623 && __builtin_expect (debug_level
, 0) > 0)
625 /* We have problems sending the result. */
627 dbg_log (_("cannot write result: %s"),
628 strerror_r (errno
, buf
, sizeof (buf
)));
634 /* Be sure we can read the data. */
635 if (__builtin_expect (pthread_rwlock_tryrdlock (&db
->lock
) != 0, 0))
637 ++db
->head
->rdlockdelayed
;
638 pthread_rwlock_rdlock (&db
->lock
);
641 /* See whether we can handle it from the cache. */
642 struct datahead
*cached
;
643 cached
= (struct datahead
*) cache_search (req
->type
, key
, req
->key_len
,
647 /* Hurray it's in the cache. */
648 if (TEMP_FAILURE_RETRY (write (fd
, cached
->data
, cached
->recsize
))
650 && __builtin_expect (debug_level
, 0) > 0)
652 /* We have problems sending the result. */
654 dbg_log (_("cannot write result: %s"),
655 strerror_r (errno
, buf
, sizeof (buf
)));
658 pthread_rwlock_unlock (&db
->lock
);
663 pthread_rwlock_unlock (&db
->lock
);
665 else if (__builtin_expect (debug_level
, 0) > 0)
667 if (req
->type
== INVALIDATE
)
668 dbg_log ("\t%s (%s)", serv2str
[req
->type
], (char *) key
);
670 dbg_log ("\t%s", serv2str
[req
->type
]);
673 /* Handle the request. */
677 addpwbyname (db
, fd
, req
, key
, uid
);
681 addpwbyuid (db
, fd
, req
, key
, uid
);
685 addgrbyname (db
, fd
, req
, key
, uid
);
689 addgrbygid (db
, fd
, req
, key
, uid
);
693 addhstbyname (db
, fd
, req
, key
, uid
);
696 case GETHOSTBYNAMEv6
:
697 addhstbynamev6 (db
, fd
, req
, key
, uid
);
701 addhstbyaddr (db
, fd
, req
, key
, uid
);
704 case GETHOSTBYADDRv6
:
705 addhstbyaddrv6 (db
, fd
, req
, key
, uid
);
709 addhstai (db
, fd
, req
, key
, uid
);
717 /* Get the callers credentials. */
720 socklen_t optlen
= sizeof (caller
);
722 if (getsockopt (fd
, SOL_SOCKET
, SO_PEERCRED
, &caller
, &optlen
) < 0)
726 dbg_log (_("error getting callers id: %s"),
727 strerror_r (errno
, buf
, sizeof (buf
)));
733 /* Some systems have no SO_PEERCRED implementation. They don't
734 care about security so we don't as well. */
739 /* Accept shutdown, getstat and invalidate only from root. For
740 the stat call also allow the user specified in the config file. */
741 if (req
->type
== GETSTAT
)
743 if (uid
== 0 || uid
== stat_uid
)
744 send_stats (fd
, dbs
);
748 if (req
->type
== INVALIDATE
)
749 invalidate_cache (key
);
751 termination_handler (0);
759 send_ro_fd (serv2db
[req
->type
], key
, fd
);
764 /* Ignore the command, it's nothing we know. */
770 /* This is the main loop. It is replicated in different threads but the
771 `poll' call makes sure only one thread handles an incoming connection. */
773 __attribute__ ((__noreturn__
))
776 long int my_number
= (long int) p
;
778 int run_prune
= my_number
< lastdb
&& dbs
[my_number
].enabled
;
779 time_t next_prune
= run_prune
? time (NULL
) + CACHE_PRUNE_INTERVAL
: 0;
780 static unsigned long int nready
;
783 setup_thread (&dbs
[my_number
]);
786 conn
.events
= POLLRDNORM
;
793 /* One more thread available. */
794 atomic_increment (&nready
);
802 /* NB: we do not flush the timestamp update using msync since
803 this value doesnot matter on disk. */
804 dbs
[my_number
].head
->timestamp
= now
= time (NULL
);
805 timeout
= now
< next_prune
? 1000 * (next_prune
- now
) : 0;
808 nr
= poll (&conn
, 1, timeout
);
812 /* The `poll' call timed out. It's time to clean up the
814 atomic_decrement (&nready
);
815 assert (my_number
< lastdb
);
816 prune_cache (&dbs
[my_number
], time(NULL
));
818 next_prune
= now
+ CACHE_PRUNE_INTERVAL
;
823 while ((conn
.revents
& POLLRDNORM
) == 0);
826 /* We have a new incoming connection. Accept the connection. */
827 int fd
= TEMP_FAILURE_RETRY (accept (conn
.fd
, NULL
, NULL
));
835 if (__builtin_expect (fd
, 0) < 0)
837 if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
)
838 dbg_log (_("while accepting connection: %s"),
839 strerror_r (errno
, buf
, sizeof (buf
)));
843 /* This thread is busy. */
844 atomic_decrement (&nready
);
846 /* Now read the request. */
847 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd
, &req
, sizeof (req
)))
851 dbg_log (_("short read while reading request: %s"),
852 strerror_r (errno
, buf
, sizeof (buf
)));
857 /* Check whether this is a valid request type. */
858 if (req
.type
< GETPWBYNAME
|| req
.type
>= LASTREQ
)
861 /* Some systems have no SO_PEERCRED implementation. They don't
862 care about security so we don't as well. */
867 socklen_t optlen
= sizeof (caller
);
869 if (getsockopt (fd
, SOL_SOCKET
, SO_PEERCRED
, &caller
, &optlen
) < 0)
871 dbg_log (_("error getting callers id: %s"),
872 strerror_r (errno
, buf
, sizeof (buf
)));
876 if (req
.type
< GETPWBYNAME
|| req
.type
> LASTDBREQ
877 || serv2db
[req
.type
]->secure
)
882 else if (__builtin_expect (debug_level
> 0, 0))
885 socklen_t optlen
= sizeof (caller
);
887 if (getsockopt (fd
, SOL_SOCKET
, SO_PEERCRED
, &caller
, &optlen
) == 0)
892 /* It should not be possible to crash the nscd with a silly
893 request (i.e., a terribly large key). We limit the size to 1kb. */
894 if (__builtin_expect (req
.key_len
, 1) < 0
895 || __builtin_expect (req
.key_len
, 1) > 1024)
898 dbg_log (_("key length in request too long: %d"), req
.key_len
);
903 char keybuf
[req
.key_len
];
905 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd
, keybuf
,
910 dbg_log (_("short read while reading request key: %s"),
911 strerror_r (errno
, buf
, sizeof (buf
)));
916 if (__builtin_expect (debug_level
, 0) > 0)
921 handle_request: request received (Version = %d) from PID %ld"),
922 req
.version
, (long int) pid
);
926 handle_request: request received (Version = %d)"), req
.version
);
929 /* Phew, we got all the data, now process it. */
930 handle_request (fd
, &req
, keybuf
, uid
);
937 /* Just determine whether any data is present. We do this to
938 measure whether clients are queued up. */
940 nr
= poll (&conn
, 1, 0);
946 atomic_increment (&nready
);
954 /* Start all the threads we want. The initial process is thread no. 1. */
962 pthread_attr_init (&attr
);
963 pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
);
965 /* We allow less than LASTDB threads only for debugging. */
966 if (debug_level
== 0)
967 nthreads
= MAX (nthreads
, lastdb
);
969 for (i
= 1; i
< nthreads
; ++i
)
970 pthread_create (&th
, &attr
, nscd_run
, (void *) i
);
972 pthread_attr_destroy (&attr
);
974 nscd_run ((void *) 0);
978 /* Look up the uid, gid, and supplementary groups to run nscd as. When
979 this function is called, we are not listening on the nscd socket yet so
980 we can just use the ordinary lookup functions without causing a lockup */
982 begin_drop_privileges (void)
984 struct passwd
*pwd
= getpwnam (server_user
);
988 dbg_log (_("Failed to run nscd as user '%s'"), server_user
);
989 error (EXIT_FAILURE
, 0, _("Failed to run nscd as user '%s'"),
993 server_uid
= pwd
->pw_uid
;
994 server_gid
= pwd
->pw_gid
;
996 if (getgrouplist (server_user
, server_gid
, NULL
, &server_ngroups
) == 0)
998 /* This really must never happen. */
999 dbg_log (_("Failed to run nscd as user '%s'"), server_user
);
1000 error (EXIT_FAILURE
, errno
, _("initial getgrouplist failed"));
1003 server_groups
= (gid_t
*) xmalloc (server_ngroups
* sizeof (gid_t
));
1005 if (getgrouplist (server_user
, server_gid
, server_groups
, &server_ngroups
)
1008 dbg_log (_("Failed to run nscd as user '%s'"), server_user
);
1009 error (EXIT_FAILURE
, errno
, _("getgrouplist failed"));
1014 /* Call setgroups(), setgid(), and setuid() to drop root privileges and
1015 run nscd as the user specified in the configuration file. */
1017 finish_drop_privileges (void)
1019 if (setgroups (server_ngroups
, server_groups
) == -1)
1021 dbg_log (_("Failed to run nscd as user '%s'"), server_user
);
1022 error (EXIT_FAILURE
, errno
, _("setgroups failed"));
1025 if (setgid (server_gid
) == -1)
1027 dbg_log (_("Failed to run nscd as user '%s'"), server_user
);
1032 if (setuid (server_uid
) == -1)
1034 dbg_log (_("Failed to run nscd as user '%s'"), server_user
);