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>
47 /* Number of bytes of data we initially reserve for each hash table bucket. */
48 #define DEFAULT_DATASIZE_PER_BUCKET 1024
51 /* Wrapper functions with error checking for standard functions. */
52 extern void *xmalloc (size_t n
);
53 extern void *xcalloc (size_t n
, size_t s
);
54 extern void *xrealloc (void *o
, size_t n
);
56 /* Support to run nscd as an unprivileged user */
57 const char *server_user
;
58 static uid_t server_uid
;
59 static gid_t server_gid
;
60 const char *stat_user
;
62 static gid_t
*server_groups
;
66 static int server_ngroups
;
68 static void begin_drop_privileges (void);
69 static void finish_drop_privileges (void);
71 /* Map request type to a string. */
72 const char *serv2str
[LASTREQ
] =
74 [GETPWBYNAME
] = "GETPWBYNAME",
75 [GETPWBYUID
] = "GETPWBYUID",
76 [GETGRBYNAME
] = "GETGRBYNAME",
77 [GETGRBYGID
] = "GETGRBYGID",
78 [GETHOSTBYNAME
] = "GETHOSTBYNAME",
79 [GETHOSTBYNAMEv6
] = "GETHOSTBYNAMEv6",
80 [GETHOSTBYADDR
] = "GETHOSTBYADDR",
81 [GETHOSTBYADDRv6
] = "GETHOSTBYADDRv6",
82 [SHUTDOWN
] = "SHUTDOWN",
83 [GETSTAT
] = "GETSTAT",
84 [INVALIDATE
] = "INVALIDATE",
85 [GETFDPW
] = "GETFDPW",
86 [GETFDGR
] = "GETFDGR",
87 [GETFDHST
] = "GETFDHST",
89 [INITGROUPS
] = "INITGROUPS"
92 /* The control data structures for the services. */
93 struct database_dyn dbs
[lastdb
] =
96 .lock
= PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
,
101 .filename
= "/etc/passwd",
102 .db_filename
= _PATH_NSCD_PASSWD_DB
,
103 .disabled_iov
= &pwd_iov_disabled
,
111 .lock
= PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
,
116 .filename
= "/etc/group",
117 .db_filename
= _PATH_NSCD_GROUP_DB
,
118 .disabled_iov
= &grp_iov_disabled
,
126 .lock
= PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
,
131 .filename
= "/etc/hosts",
132 .db_filename
= _PATH_NSCD_HOSTS_DB
,
133 .disabled_iov
= &hst_iov_disabled
,
143 /* Mapping of request type to database. */
144 static struct database_dyn
*const serv2db
[LASTREQ
] =
146 [GETPWBYNAME
] = &dbs
[pwddb
],
147 [GETPWBYUID
] = &dbs
[pwddb
],
148 [GETGRBYNAME
] = &dbs
[grpdb
],
149 [GETGRBYGID
] = &dbs
[grpdb
],
150 [GETHOSTBYNAME
] = &dbs
[hstdb
],
151 [GETHOSTBYNAMEv6
] = &dbs
[hstdb
],
152 [GETHOSTBYADDR
] = &dbs
[hstdb
],
153 [GETHOSTBYADDRv6
] = &dbs
[hstdb
],
154 [GETFDPW
] = &dbs
[pwddb
],
155 [GETFDGR
] = &dbs
[grpdb
],
156 [GETFDHST
] = &dbs
[hstdb
],
157 [GETAI
] = &dbs
[hstdb
],
158 [INITGROUPS
] = &dbs
[grpdb
]
162 /* Number of seconds between two cache pruning runs. */
163 #define CACHE_PRUNE_INTERVAL 15
166 /* Number of threads to use. */
169 /* Socket for incoming connections. */
172 /* Number of times clients had to wait. */
173 unsigned long int client_queued
;
176 /* Initialize database information structures. */
180 struct sockaddr_un sock_addr
;
183 /* Secure mode and unprivileged mode are incompatible */
184 if (server_user
!= NULL
&& secure_in_use
)
186 dbg_log (_("Cannot run nscd in secure mode as unprivileged user"));
190 /* Look up unprivileged uid/gid/groups before we start listening on the
192 if (server_user
!= NULL
)
193 begin_drop_privileges ();
196 /* No configuration for this value, assume a default. */
197 nthreads
= 2 * lastdb
;
199 for (cnt
= 0; cnt
< lastdb
; ++cnt
)
200 if (dbs
[cnt
].enabled
)
202 pthread_rwlock_init (&dbs
[cnt
].lock
, NULL
);
203 pthread_mutex_init (&dbs
[cnt
].memlock
, NULL
);
205 if (dbs
[cnt
].persistent
)
207 /* Try to open the appropriate file on disk. */
208 int fd
= open (dbs
[cnt
].db_filename
, O_RDWR
);
214 struct database_pers_head head
;
215 ssize_t n
= TEMP_FAILURE_RETRY (read (fd
, &head
,
217 if (n
!= sizeof (head
) || fstat64 (fd
, &st
) != 0)
220 dbg_log (_("invalid persistent database file \"%s\": %s"),
221 dbs
[cnt
].db_filename
, strerror (errno
));
222 dbs
[cnt
].persistent
= 0;
224 else if (head
.module
== 0 && head
.data_size
== 0)
226 /* The file has been created, but the head has not been
227 initialized yet. Remove the old file. */
228 unlink (dbs
[cnt
].db_filename
);
230 else if (head
.header_size
!= (int) sizeof (head
))
232 dbg_log (_("invalid persistent database file \"%s\": %s"),
233 dbs
[cnt
].db_filename
,
234 _("header size does not match"));
235 dbs
[cnt
].persistent
= 0;
237 else if ((total
= (sizeof (head
)
238 + roundup (head
.module
* sizeof (ref_t
),
243 dbg_log (_("invalid persistent database file \"%s\": %s"),
244 dbs
[cnt
].db_filename
,
245 _("file size does not match"));
246 dbs
[cnt
].persistent
= 0;
248 else if ((mem
= mmap (NULL
, total
, PROT_READ
| PROT_WRITE
,
249 MAP_SHARED
, fd
, 0)) == MAP_FAILED
)
253 /* Success. We have the database. */
255 dbs
[cnt
].memsize
= total
;
256 dbs
[cnt
].data
= (char *)
257 &dbs
[cnt
].head
->array
[roundup (dbs
[cnt
].head
->module
,
258 ALIGN
/ sizeof (ref_t
))];
259 dbs
[cnt
].mmap_used
= true;
261 if (dbs
[cnt
].suggested_module
> head
.module
)
262 dbg_log (_("suggested size of table for database %s larger than the persistent database's table"),
267 /* We also need a read-only descriptor. */
270 dbs
[cnt
].ro_fd
= open (dbs
[cnt
].db_filename
, O_RDONLY
);
271 if (dbs
[cnt
].ro_fd
== -1)
273 cannot create read-only descriptor for \"%s\"; no mmap"),
274 dbs
[cnt
].db_filename
);
277 // XXX Shall we test whether the descriptors actually
278 // XXX point to the same file?
281 /* Close the file descriptors in case something went
282 wrong in which case the variable have not been
289 if (dbs
[cnt
].head
== NULL
)
291 /* No database loaded. Allocate the data structure,
293 struct database_pers_head head
;
294 size_t total
= (sizeof (head
)
295 + roundup (dbs
[cnt
].suggested_module
296 * sizeof (ref_t
), ALIGN
)
297 + (dbs
[cnt
].suggested_module
298 * DEFAULT_DATASIZE_PER_BUCKET
));
300 /* Try to create the database. If we do not need a
301 persistent database create a temporary file. */
304 if (dbs
[cnt
].persistent
)
306 fd
= open (dbs
[cnt
].db_filename
,
307 O_RDWR
| O_CREAT
| O_EXCL
| O_TRUNC
,
309 if (fd
!= -1 && dbs
[cnt
].shared
)
310 ro_fd
= open (dbs
[cnt
].db_filename
, O_RDONLY
);
314 size_t slen
= strlen (dbs
[cnt
].db_filename
);
315 char fname
[slen
+ 8];
316 strcpy (mempcpy (fname
, dbs
[cnt
].db_filename
, slen
),
318 fd
= mkstemp (fname
);
320 /* We do not need the file name anymore after we
321 opened another file descriptor in read-only mode. */
322 if (fd
!= -1 && dbs
[cnt
].shared
)
324 ro_fd
= open (fname
, O_RDONLY
);
334 dbg_log (_("database for %s corrupted or simultaneously used; remove %s manually if necessary and restart"),
335 dbnames
[cnt
], dbs
[cnt
].db_filename
);
336 // XXX Correct way to terminate?
340 if (dbs
[cnt
].persistent
)
341 dbg_log (_("cannot create %s; no persistent database used"),
342 dbs
[cnt
].db_filename
);
344 dbg_log (_("cannot create %s; no sharing possible"),
345 dbs
[cnt
].db_filename
);
347 dbs
[cnt
].persistent
= 0;
348 // XXX remember: no mmap
352 /* Tell the user if we could not create the read-only
354 if (ro_fd
== -1 && dbs
[cnt
].shared
)
356 cannot create read-only descriptor for \"%s\"; no mmap"),
357 dbs
[cnt
].db_filename
);
359 /* Before we create the header, initialiye the hash
360 table. So that if we get interrupted if writing
361 the header we can recognize a partially initialized
363 size_t ps
= sysconf (_SC_PAGESIZE
);
365 assert (~ENDREF
== 0);
366 memset (tmpbuf
, '\xff', ps
);
368 size_t remaining
= dbs
[cnt
].suggested_module
* sizeof (ref_t
);
369 off_t offset
= sizeof (head
);
372 if (offset
% ps
!= 0)
374 towrite
= MIN (remaining
, ps
- (offset
% ps
));
375 pwrite (fd
, tmpbuf
, towrite
, offset
);
377 remaining
-= towrite
;
380 while (remaining
> ps
)
382 pwrite (fd
, tmpbuf
, ps
, offset
);
388 pwrite (fd
, tmpbuf
, remaining
, offset
);
390 /* Create the header of the file. */
391 struct database_pers_head head
=
393 .version
= DB_VERSION
,
394 .header_size
= sizeof (head
),
395 .module
= dbs
[cnt
].suggested_module
,
396 .data_size
= (dbs
[cnt
].suggested_module
397 * DEFAULT_DATASIZE_PER_BUCKET
),
402 if ((TEMP_FAILURE_RETRY (write (fd
, &head
, sizeof (head
)))
404 || ftruncate (fd
, total
) != 0
405 || (mem
= mmap (NULL
, total
, PROT_READ
| PROT_WRITE
,
406 MAP_SHARED
, fd
, 0)) == MAP_FAILED
)
408 unlink (dbs
[cnt
].db_filename
);
409 dbg_log (_("cannot write to database file %s: %s"),
410 dbs
[cnt
].db_filename
, strerror (errno
));
411 dbs
[cnt
].persistent
= 0;
417 dbs
[cnt
].data
= (char *)
418 &dbs
[cnt
].head
->array
[roundup (dbs
[cnt
].head
->module
,
419 ALIGN
/ sizeof (ref_t
))];
420 dbs
[cnt
].memsize
= total
;
421 dbs
[cnt
].mmap_used
= true;
423 /* Remember the descriptors. */
425 dbs
[cnt
].ro_fd
= ro_fd
;
437 if (dbs
[cnt
].head
== NULL
)
439 /* We do not use the persistent database. Just
440 create an in-memory data structure. */
441 assert (! dbs
[cnt
].persistent
);
443 dbs
[cnt
].head
= xmalloc (sizeof (struct database_pers_head
)
444 + (dbs
[cnt
].suggested_module
446 memset (dbs
[cnt
].head
, '\0', sizeof (dbs
[cnt
].head
));
447 assert (~ENDREF
== 0);
448 memset (dbs
[cnt
].head
->array
, '\xff',
449 dbs
[cnt
].suggested_module
* sizeof (ref_t
));
450 dbs
[cnt
].head
->module
= dbs
[cnt
].suggested_module
;
451 dbs
[cnt
].head
->data_size
= (DEFAULT_DATASIZE_PER_BUCKET
452 * dbs
[cnt
].head
->module
);
453 dbs
[cnt
].data
= xmalloc (dbs
[cnt
].head
->data_size
);
454 dbs
[cnt
].head
->first_free
= 0;
457 assert (dbs
[cnt
].ro_fd
== -1);
460 if (dbs
[cnt
].check_file
)
462 /* We need the modification date of the file. */
465 if (stat (dbs
[cnt
].filename
, &st
) < 0)
467 /* We cannot stat() the file, disable file checking. */
468 dbg_log (_("cannot stat() file `%s': %s"),
469 dbs
[cnt
].filename
, strerror (errno
));
470 dbs
[cnt
].check_file
= 0;
473 dbs
[cnt
].file_mtime
= st
.st_mtime
;
477 /* Create the socket. */
478 sock
= socket (AF_UNIX
, SOCK_STREAM
, 0);
481 dbg_log (_("cannot open socket: %s"), strerror (errno
));
484 /* Bind a name to the socket. */
485 sock_addr
.sun_family
= AF_UNIX
;
486 strcpy (sock_addr
.sun_path
, _PATH_NSCDSOCKET
);
487 if (bind (sock
, (struct sockaddr
*) &sock_addr
, sizeof (sock_addr
)) < 0)
489 dbg_log ("%s: %s", _PATH_NSCDSOCKET
, strerror (errno
));
493 /* We don't wait for data otherwise races between threads can get
494 them stuck on accept. */
495 int fl
= fcntl (sock
, F_GETFL
);
497 fcntl (sock
, F_SETFL
, fl
| O_NONBLOCK
);
499 /* Set permissions for the socket. */
500 chmod (_PATH_NSCDSOCKET
, DEFFILEMODE
);
502 /* Set the socket up to accept connections. */
503 if (listen (sock
, SOMAXCONN
) < 0)
505 dbg_log (_("cannot enable socket to accept connections: %s"),
510 /* Change to unprivileged uid/gid/groups if specifed in config file */
511 if (server_user
!= NULL
)
512 finish_drop_privileges ();
516 /* Close the connections. */
525 invalidate_cache (char *key
)
529 if (strcmp (key
, "passwd") == 0)
531 else if (strcmp (key
, "group") == 0)
533 else if (__builtin_expect (strcmp (key
, "hosts"), 0) == 0)
537 /* Re-initialize the resolver. resolv.conf might have changed. */
543 if (dbs
[number
].enabled
)
544 prune_cache (&dbs
[number
], LONG_MAX
);
550 send_ro_fd (struct database_dyn
*db
, char *key
, int fd
)
552 /* If we do not have an read-only file descriptor do nothing. */
556 /* We need to send some data along with the descriptor. */
558 iov
[0].iov_base
= key
;
559 iov
[0].iov_len
= strlen (key
) + 1;
561 /* Prepare the control message to transfer the descriptor. */
562 char buf
[CMSG_SPACE (sizeof (int))];
563 struct msghdr msg
= { .msg_iov
= iov
, .msg_iovlen
= 1,
564 .msg_control
= buf
, .msg_controllen
= sizeof (buf
) };
565 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR (&msg
);
567 cmsg
->cmsg_level
= SOL_SOCKET
;
568 cmsg
->cmsg_type
= SCM_RIGHTS
;
569 cmsg
->cmsg_len
= CMSG_LEN (sizeof (int));
571 *(int *) CMSG_DATA (cmsg
) = db
->ro_fd
;
573 msg
.msg_controllen
= cmsg
->cmsg_len
;
575 /* Send the control message. We repeat when we are interrupted but
576 everything else is ignored. */
577 (void) TEMP_FAILURE_RETRY (sendmsg (fd
, &msg
, 0));
579 if (__builtin_expect (debug_level
> 0, 0))
580 dbg_log (_("provide access to FD %d, for %s"), db
->ro_fd
, key
);
582 #endif /* SCM_RIGHTS */
585 /* Handle new request. */
587 handle_request (int fd
, request_header
*req
, void *key
, uid_t uid
)
589 if (__builtin_expect (req
->version
, NSCD_VERSION
) != NSCD_VERSION
)
593 cannot handle old request version %d; current version is %d"),
594 req
->version
, NSCD_VERSION
);
598 /* Make the SELinux check before we go on to the standard checks. We
599 need to verify that the request type is valid, since it has not
600 yet been checked at this point. */
602 && __builtin_expect (req
->type
, GETPWBYNAME
) >= GETPWBYNAME
603 && __builtin_expect (req
->type
, LASTREQ
) < LASTREQ
604 && nscd_request_avc_has_perm (fd
, req
->type
) != 0)
607 struct database_dyn
*db
= serv2db
[req
->type
];
609 // XXX Clean up so that each new command need not introduce a
610 // XXX new conditional.
611 if ((__builtin_expect (req
->type
, GETPWBYNAME
) >= GETPWBYNAME
612 && __builtin_expect (req
->type
, LASTDBREQ
) <= LASTDBREQ
)
613 || req
->type
== GETAI
|| req
->type
== INITGROUPS
)
615 if (__builtin_expect (debug_level
, 0) > 0)
617 if (req
->type
== GETHOSTBYADDR
|| req
->type
== GETHOSTBYADDRv6
)
619 char buf
[INET6_ADDRSTRLEN
];
621 dbg_log ("\t%s (%s)", serv2str
[req
->type
],
622 inet_ntop (req
->type
== GETHOSTBYADDR
623 ? AF_INET
: AF_INET6
,
624 key
, buf
, sizeof (buf
)));
627 dbg_log ("\t%s (%s)", serv2str
[req
->type
], (char *) key
);
630 /* Is this service enabled? */
633 /* No, sent the prepared record. */
634 if (TEMP_FAILURE_RETRY (write (fd
, db
->disabled_iov
->iov_base
,
635 db
->disabled_iov
->iov_len
))
636 != (ssize_t
) db
->disabled_iov
->iov_len
637 && __builtin_expect (debug_level
, 0) > 0)
639 /* We have problems sending the result. */
641 dbg_log (_("cannot write result: %s"),
642 strerror_r (errno
, buf
, sizeof (buf
)));
648 /* Be sure we can read the data. */
649 if (__builtin_expect (pthread_rwlock_tryrdlock (&db
->lock
) != 0, 0))
651 ++db
->head
->rdlockdelayed
;
652 pthread_rwlock_rdlock (&db
->lock
);
655 /* See whether we can handle it from the cache. */
656 struct datahead
*cached
;
657 cached
= (struct datahead
*) cache_search (req
->type
, key
, req
->key_len
,
661 /* Hurray it's in the cache. */
662 if (TEMP_FAILURE_RETRY (write (fd
, cached
->data
, cached
->recsize
))
664 && __builtin_expect (debug_level
, 0) > 0)
666 /* We have problems sending the result. */
668 dbg_log (_("cannot write result: %s"),
669 strerror_r (errno
, buf
, sizeof (buf
)));
672 pthread_rwlock_unlock (&db
->lock
);
677 pthread_rwlock_unlock (&db
->lock
);
679 else if (__builtin_expect (debug_level
, 0) > 0)
681 if (req
->type
== INVALIDATE
)
682 dbg_log ("\t%s (%s)", serv2str
[req
->type
], (char *) key
);
684 dbg_log ("\t%s", serv2str
[req
->type
]);
687 /* Handle the request. */
691 addpwbyname (db
, fd
, req
, key
, uid
);
695 addpwbyuid (db
, fd
, req
, key
, uid
);
699 addgrbyname (db
, fd
, req
, key
, uid
);
703 addgrbygid (db
, fd
, req
, key
, uid
);
707 addhstbyname (db
, fd
, req
, key
, uid
);
710 case GETHOSTBYNAMEv6
:
711 addhstbynamev6 (db
, fd
, req
, key
, uid
);
715 addhstbyaddr (db
, fd
, req
, key
, uid
);
718 case GETHOSTBYADDRv6
:
719 addhstbyaddrv6 (db
, fd
, req
, key
, uid
);
723 addhstai (db
, fd
, req
, key
, uid
);
727 addinitgroups (db
, fd
, req
, key
, uid
);
735 /* Get the callers credentials. */
738 socklen_t optlen
= sizeof (caller
);
740 if (getsockopt (fd
, SOL_SOCKET
, SO_PEERCRED
, &caller
, &optlen
) < 0)
744 dbg_log (_("error getting callers id: %s"),
745 strerror_r (errno
, buf
, sizeof (buf
)));
751 /* Some systems have no SO_PEERCRED implementation. They don't
752 care about security so we don't as well. */
757 /* Accept shutdown, getstat and invalidate only from root. For
758 the stat call also allow the user specified in the config file. */
759 if (req
->type
== GETSTAT
)
761 if (uid
== 0 || uid
== stat_uid
)
762 send_stats (fd
, dbs
);
766 if (req
->type
== INVALIDATE
)
767 invalidate_cache (key
);
769 termination_handler (0);
777 send_ro_fd (serv2db
[req
->type
], key
, fd
);
782 /* Ignore the command, it's nothing we know. */
788 /* This is the main loop. It is replicated in different threads but the
789 `poll' call makes sure only one thread handles an incoming connection. */
791 __attribute__ ((__noreturn__
))
794 long int my_number
= (long int) p
;
796 int run_prune
= my_number
< lastdb
&& dbs
[my_number
].enabled
;
797 time_t next_prune
= run_prune
? time (NULL
) + CACHE_PRUNE_INTERVAL
: 0;
798 static unsigned long int nready
;
801 setup_thread (&dbs
[my_number
]);
804 conn
.events
= POLLRDNORM
;
811 /* One more thread available. */
812 atomic_increment (&nready
);
820 /* NB: we do not flush the timestamp update using msync since
821 this value doesnot matter on disk. */
822 dbs
[my_number
].head
->timestamp
= now
= time (NULL
);
823 timeout
= now
< next_prune
? 1000 * (next_prune
- now
) : 0;
826 nr
= poll (&conn
, 1, timeout
);
830 /* The `poll' call timed out. It's time to clean up the
832 atomic_decrement (&nready
);
833 assert (my_number
< lastdb
);
834 prune_cache (&dbs
[my_number
], time(NULL
));
836 next_prune
= now
+ CACHE_PRUNE_INTERVAL
;
841 while ((conn
.revents
& POLLRDNORM
) == 0);
844 /* We have a new incoming connection. Accept the connection. */
845 int fd
= TEMP_FAILURE_RETRY (accept (conn
.fd
, NULL
, NULL
));
853 if (__builtin_expect (fd
, 0) < 0)
855 if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
)
856 dbg_log (_("while accepting connection: %s"),
857 strerror_r (errno
, buf
, sizeof (buf
)));
861 /* This thread is busy. */
862 atomic_decrement (&nready
);
864 /* Now read the request. */
865 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd
, &req
, sizeof (req
)))
869 dbg_log (_("short read while reading request: %s"),
870 strerror_r (errno
, buf
, sizeof (buf
)));
875 /* Check whether this is a valid request type. */
876 if (req
.type
< GETPWBYNAME
|| req
.type
>= LASTREQ
)
879 /* Some systems have no SO_PEERCRED implementation. They don't
880 care about security so we don't as well. */
885 socklen_t optlen
= sizeof (caller
);
887 if (getsockopt (fd
, SOL_SOCKET
, SO_PEERCRED
, &caller
, &optlen
) < 0)
889 dbg_log (_("error getting callers id: %s"),
890 strerror_r (errno
, buf
, sizeof (buf
)));
894 if (req
.type
< GETPWBYNAME
|| req
.type
> LASTDBREQ
895 || serv2db
[req
.type
]->secure
)
900 else if (__builtin_expect (debug_level
> 0, 0))
903 socklen_t optlen
= sizeof (caller
);
905 if (getsockopt (fd
, SOL_SOCKET
, SO_PEERCRED
, &caller
, &optlen
) == 0)
910 /* It should not be possible to crash the nscd with a silly
911 request (i.e., a terribly large key). We limit the size to 1kb. */
912 if (__builtin_expect (req
.key_len
, 1) < 0
913 || __builtin_expect (req
.key_len
, 1) > 1024)
916 dbg_log (_("key length in request too long: %d"), req
.key_len
);
921 char keybuf
[req
.key_len
];
923 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd
, keybuf
,
928 dbg_log (_("short read while reading request key: %s"),
929 strerror_r (errno
, buf
, sizeof (buf
)));
934 if (__builtin_expect (debug_level
, 0) > 0)
939 handle_request: request received (Version = %d) from PID %ld"),
940 req
.version
, (long int) pid
);
944 handle_request: request received (Version = %d)"), req
.version
);
947 /* Phew, we got all the data, now process it. */
948 handle_request (fd
, &req
, keybuf
, uid
);
955 /* Just determine whether any data is present. We do this to
956 measure whether clients are queued up. */
958 nr
= poll (&conn
, 1, 0);
964 atomic_increment (&nready
);
972 /* Start all the threads we want. The initial process is thread no. 1. */
980 pthread_attr_init (&attr
);
981 pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
);
983 /* We allow less than LASTDB threads only for debugging. */
984 if (debug_level
== 0)
985 nthreads
= MAX (nthreads
, lastdb
);
987 for (i
= 1; i
< nthreads
; ++i
)
988 pthread_create (&th
, &attr
, nscd_run
, (void *) i
);
990 pthread_attr_destroy (&attr
);
992 nscd_run ((void *) 0);
995 /* Look up the uid, gid, and supplementary groups to run nscd as. When
996 this function is called, we are not listening on the nscd socket yet so
997 we can just use the ordinary lookup functions without causing a lockup */
999 begin_drop_privileges (void)
1001 struct passwd
*pwd
= getpwnam (server_user
);
1005 dbg_log (_("Failed to run nscd as user '%s'"), server_user
);
1006 error (EXIT_FAILURE
, 0, _("Failed to run nscd as user '%s'"),
1010 server_uid
= pwd
->pw_uid
;
1011 server_gid
= pwd
->pw_gid
;
1013 if (getgrouplist (server_user
, server_gid
, NULL
, &server_ngroups
) == 0)
1015 /* This really must never happen. */
1016 dbg_log (_("Failed to run nscd as user '%s'"), server_user
);
1017 error (EXIT_FAILURE
, errno
, _("initial getgrouplist failed"));
1020 server_groups
= (gid_t
*) xmalloc (server_ngroups
* sizeof (gid_t
));
1022 if (getgrouplist (server_user
, server_gid
, server_groups
, &server_ngroups
)
1025 dbg_log (_("Failed to run nscd as user '%s'"), server_user
);
1026 error (EXIT_FAILURE
, errno
, _("getgrouplist failed"));
1031 /* Call setgroups(), setgid(), and setuid() to drop root privileges and
1032 run nscd as the user specified in the configuration file. */
1034 finish_drop_privileges (void)
1036 if (setgroups (server_ngroups
, server_groups
) == -1)
1038 dbg_log (_("Failed to run nscd as user '%s'"), server_user
);
1039 error (EXIT_FAILURE
, errno
, _("setgroups failed"));
1042 if (setgid (server_gid
) == -1)
1044 dbg_log (_("Failed to run nscd as user '%s'"), server_user
);
1049 if (setuid (server_uid
) == -1)
1051 dbg_log (_("Failed to run nscd as user '%s'"), server_user
);
1057 /* Handle the HUP signal which will force a dump of the cache */
1059 sighup_handler (int signum
)
1061 /* Prune the password database */
1062 prune_cache (&dbs
[pwddb
], LONG_MAX
);
1064 /* Prune the group database */
1065 prune_cache (&dbs
[grpdb
], LONG_MAX
);
1067 /* Prune the host database */
1068 prune_cache (&dbs
[hstdb
], LONG_MAX
);