]> sourceware.org Git - glibc.git/blame - nscd/nscd.c
Update.
[glibc.git] / nscd / nscd.c
CommitLineData
8e597a18 1/* Copyright (c) 1998-2003, 2004 Free Software Foundation, Inc.
d67281a7 2 This file is part of the GNU C Library.
a1c542bf 3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
d67281a7
UD
4
5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
d67281a7
UD
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 13 Lesser General Public License for more details.
d67281a7 14
41bdb6e2
AJ
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
d67281a7 19
67479a70 20/* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
d67281a7 21
4d06461a 22#include <argp.h>
67479a70 23#include <assert.h>
d4397629 24#include <dirent.h>
d67281a7 25#include <errno.h>
4d06461a 26#include <error.h>
d4397629 27#include <fcntl.h>
d67281a7
UD
28#include <libintl.h>
29#include <locale.h>
d4397629 30#include <paths.h>
d67281a7 31#include <pthread.h>
d67281a7 32#include <signal.h>
a12ce44f 33#include <stdbool.h>
d67281a7
UD
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <syslog.h>
4c223a7c 38#include <unistd.h>
a95a08b4 39#include <sys/mman.h>
d67281a7 40#include <sys/socket.h>
d4397629 41#include <sys/stat.h>
ead07d01 42#include <sys/uio.h>
d67281a7
UD
43#include <sys/un.h>
44
45#include "dbg_log.h"
46#include "nscd.h"
74a30a58 47#include "selinux.h"
ef4d5b32 48#include "../nss/nsswitch.h"
d4397629 49#include <device-nrs.h>
d67281a7
UD
50
51/* Get libc version number. */
52#include <version.h>
53
54#define PACKAGE _libc_intl_domainname
55
56/* Structure used by main() thread to keep track of the number of
57 active threads. Used to limit how many threads it will create
58 and under a shutdown condition to wait till all in-progress
59 requests have finished before "turning off the lights". */
60
61typedef struct
62{
63 int num_active;
64 pthread_cond_t thread_exit_cv;
65 pthread_mutex_t mutex;
66} thread_info_t;
67
68thread_info_t thread_info;
69
a1c542bf
UD
70int do_shutdown;
71int disabled_passwd;
72int disabled_group;
4d06461a 73int go_background = 1;
a1c542bf 74
a1c542bf 75int secure_in_use;
67479a70 76static const char *conffile = _PATH_NSCDCONF;
d67281a7 77
c86e6aec
UD
78time_t start_time;
79
3418007e
UD
80uintptr_t pagesize_m1;
81
d67281a7
UD
82static int check_pid (const char *file);
83static int write_pid (const char *file);
d67281a7 84
4d06461a
UD
85/* Name and version of program. */
86static void print_version (FILE *stream, struct argp_state *state);
87void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
88
89/* Definitions of arguments for argp functions. */
90static const struct argp_option options[] =
91{
92 { "config-file", 'f', N_("NAME"), 0,
93 N_("Read configuration data from NAME") },
94 { "debug", 'd', NULL, 0,
95 N_("Do not fork and display messages on the current tty") },
67479a70 96 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
4d06461a 97 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
3dd90163 98 { "statistic", 'g', NULL, 0, N_("Print current configuration statistic") },
756409c4
UD
99 { "invalidate", 'i', N_("TABLE"), 0,
100 N_("Invalidate the specified cache") },
3c12b91a
UD
101 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
102 N_("Use separate cache for each user")},
4d06461a
UD
103 { NULL, 0, NULL, 0, NULL }
104};
105
106/* Short description of program. */
67a96999 107static const char doc[] = N_("Name Service Cache Daemon.");
4d06461a
UD
108
109/* Prototype for option handler. */
d8cf93f4 110static error_t parse_opt (int key, char *arg, struct argp_state *state);
4d06461a
UD
111
112/* Data structure to communicate with argp functions. */
113static struct argp argp =
114{
115 options, parse_opt, NULL, doc,
116};
117
a12ce44f
UD
118/* True if only statistics are requested. */
119static bool get_stats;
120
d67281a7
UD
121int
122main (int argc, char **argv)
123{
4d06461a 124 int remaining;
d67281a7
UD
125
126 /* Set locale via LC_ALL. */
127 setlocale (LC_ALL, "");
128 /* Set the text message domain. */
129 textdomain (PACKAGE);
130
74a30a58
UD
131 /* Determine if the kernel has SELinux support. */
132 nscd_selinux_enabled (&selinux_enabled);
133
4d06461a
UD
134 /* Parse and process arguments. */
135 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
136
14e9dd67 137 if (remaining != argc)
d67281a7 138 {
4d06461a
UD
139 error (0, 0, gettext ("wrong number of arguments"));
140 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
141 exit (EXIT_FAILURE);
d67281a7
UD
142 }
143
a12ce44f
UD
144 /* Read the configuration file. */
145 if (nscd_parse_file (conffile, dbs) != 0)
146 {
147 /* We couldn't read the configuration file. We don't start the
148 server. */
149 dbg_log (_("cannot read configuration file; this is fatal"));
150 exit (1);
151 }
152
153 /* Do we only get statistics? */
154 if (get_stats)
155 /* Does not return. */
156 receive_print_stats ();
157
d67281a7
UD
158 /* Check if we are already running. */
159 if (check_pid (_PATH_NSCDPID))
67479a70 160 error (EXIT_FAILURE, 0, _("already running"));
d67281a7 161
c86e6aec
UD
162 /* Remember when we started. */
163 start_time = time (NULL);
164
3418007e
UD
165 /* Determine page size. */
166 pagesize_m1 = getpagesize () - 1;
167
d67281a7
UD
168 /* Behave like a daemon. */
169 if (go_background)
170 {
6c202c68
UD
171 int i;
172
230c3e1e
UD
173 pid_t pid = fork ();
174 if (pid == -1)
175 error (EXIT_FAILURE, errno, _("cannot fork"));
176 if (pid != 0)
6c202c68
UD
177 exit (0);
178
d4397629
UD
179 int nullfd = open (_PATH_DEVNULL, O_RDWR);
180 if (nullfd != -1)
181 {
182 struct stat64 st;
183
184 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
185#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
186 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
187#endif
188 )
189 {
190 /* It is the /dev/null special device alright. */
191 (void) dup2 (nullfd, STDIN_FILENO);
192 (void) dup2 (nullfd, STDOUT_FILENO);
193 (void) dup2 (nullfd, STDERR_FILENO);
194
195 if (nullfd > 2)
196 close (nullfd);
197 }
198 else
199 {
200 /* Ugh, somebody is trying to play a trick on us. */
201 close (nullfd);
202 nullfd = -1;
203 }
204 }
205 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
206
207 DIR *d = opendir ("/proc/self/fd");
208 if (d != NULL)
209 {
210 struct dirent64 *dirent;
211 int dfdn = dirfd (d);
212
213 while ((dirent = readdir64 (d)) != NULL)
214 {
215 char *endp;
4c5dd2a2 216 long int fdn = strtol (dirent->d_name, &endp, 10);
d4397629
UD
217
218 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
219 close ((int) fdn);
220 }
221
222 closedir (d);
223 }
224 else
225 for (i = min_close_fd; i < getdtablesize (); i++)
226 close (i);
6c202c68 227
230c3e1e
UD
228 pid = fork ();
229 if (pid == -1)
230 error (EXIT_FAILURE, errno, _("cannot fork"));
231 if (pid != 0)
6c202c68
UD
232 exit (0);
233
adcf0e4a
UD
234 setsid ();
235
6c202c68
UD
236 chdir ("/");
237
d67281a7
UD
238 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
239
d67281a7
UD
240 if (write_pid (_PATH_NSCDPID) < 0)
241 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
242
f4047366
UD
243 if (!init_logfile ())
244 dbg_log (_("Could not create log file"));
245
67479a70 246 /* Ignore job control signals. */
d67281a7
UD
247 signal (SIGTTOU, SIG_IGN);
248 signal (SIGTTIN, SIG_IGN);
249 signal (SIGTSTP, SIG_IGN);
250 }
6c202c68 251
74a30a58
UD
252 /* Start the SELinux AVC. */
253 if (selinux_enabled)
254 nscd_avc_init ();
255
6c202c68
UD
256 signal (SIGINT, termination_handler);
257 signal (SIGQUIT, termination_handler);
258 signal (SIGTERM, termination_handler);
259 signal (SIGPIPE, SIG_IGN);
260
230c3e1e 261 /* Cleanup files created by a previous 'bind'. */
d67281a7
UD
262 unlink (_PATH_NSCDSOCKET);
263
ef4d5b32
UD
264 /* Make sure we do not get recursive calls. */
265 __nss_disable_nscd ();
266
67479a70 267 /* Init databases. */
a12ce44f 268 nscd_init ();
d67281a7 269
d67281a7 270 /* Handle incoming requests */
67479a70 271 start_threads ();
d67281a7
UD
272
273 return 0;
274}
275
4d06461a
UD
276
277/* Handle program arguments. */
278static error_t
279parse_opt (int key, char *arg, struct argp_state *state)
280{
281 switch (key)
282 {
283 case 'd':
67479a70 284 ++debug_level;
4d06461a
UD
285 go_background = 0;
286 break;
67479a70 287
4d06461a
UD
288 case 'f':
289 conffile = arg;
290 break;
67479a70 291
4d06461a
UD
292 case 'K':
293 if (getuid () != 0)
67479a70 294 error (EXIT_FAILURE, 0, _("Only root is allowed to use this option!"));
4d06461a 295 {
67479a70 296 int sock = nscd_open_socket ();
4d06461a
UD
297 request_header req;
298 ssize_t nbytes;
299
300 if (sock == -1)
301 exit (EXIT_FAILURE);
302
303 req.version = NSCD_VERSION;
304 req.type = SHUTDOWN;
305 req.key_len = 0;
67479a70
UD
306 nbytes = TEMP_FAILURE_RETRY (write (sock, &req,
307 sizeof (request_header)));
4d06461a 308 close (sock);
67479a70 309 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
4d06461a 310 }
67479a70 311
4d06461a 312 case 'g':
a12ce44f
UD
313 get_stats = true;
314 break;
67479a70 315
756409c4
UD
316 case 'i':
317 if (getuid () != 0)
318 error (EXIT_FAILURE, 0, _("Only root is allowed to use this option!"));
319 else
320 {
321 int sock = nscd_open_socket ();
756409c4
UD
322
323 if (sock == -1)
324 exit (EXIT_FAILURE);
325
ead07d01
UD
326 request_header req;
327 ssize_t nbytes;
328 struct iovec iov[2];
329
756409c4
UD
330 if (strcmp (arg, "passwd") == 0)
331 req.key_len = sizeof "passwd";
332 else if (strcmp (arg, "group") == 0)
333 req.key_len = sizeof "group";
334 else if (strcmp (arg, "hosts") == 0)
335 req.key_len = sizeof "hosts";
336 else
337 return ARGP_ERR_UNKNOWN;
338
339 req.version = NSCD_VERSION;
340 req.type = INVALIDATE;
756409c4 341
ead07d01
UD
342 iov[0].iov_base = &req;
343 iov[0].iov_len = sizeof (req);
f731666f 344 iov[1].iov_base = arg;
ead07d01
UD
345 iov[1].iov_len = req.key_len;
346
347 nbytes = TEMP_FAILURE_RETRY (writev (sock, iov, 2));
756409c4
UD
348
349 close (sock);
350
ead07d01
UD
351 exit (nbytes != iov[0].iov_len + iov[1].iov_len
352 ? EXIT_FAILURE : EXIT_SUCCESS);
756409c4
UD
353 }
354
67479a70
UD
355 case 't':
356 nthreads = atol (arg);
357 break;
358
a1c542bf 359 case 'S':
3c12b91a 360#if 0
a1c542bf 361 if (strcmp (arg, "passwd,yes") == 0)
a95a08b4 362 secure_in_use = dbs[pwddb].secure = 1;
a1c542bf 363 else if (strcmp (arg, "group,yes") == 0)
a95a08b4 364 secure_in_use = dbs[grpdb].secure = 1;
a1c542bf 365 else if (strcmp (arg, "hosts,yes") == 0)
a95a08b4 366 secure_in_use = dbs[hstdb].secure = 1;
3c12b91a
UD
367#else
368 error (0, 0, _("secure services not implemented anymore"));
369#endif
a1c542bf
UD
370 break;
371
4d06461a
UD
372 default:
373 return ARGP_ERR_UNKNOWN;
374 }
67479a70 375
4d06461a
UD
376 return 0;
377}
378
379/* Print the version information. */
380static void
381print_version (FILE *stream, struct argp_state *state)
382{
383 fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
384 fprintf (stream, gettext ("\
385Copyright (C) %s Free Software Foundation, Inc.\n\
386This is free software; see the source for copying conditions. There is NO\n\
387warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
8e597a18 388"), "2004");
67479a70
UD
389 fprintf (stream, gettext ("Written by %s.\n"),
390 "Thorsten Kukuk and Ulrich Drepper");
4d06461a
UD
391}
392
393
67479a70 394/* Create a socket connected to a name. */
d67281a7 395int
67479a70 396nscd_open_socket (void)
d67281a7
UD
397{
398 struct sockaddr_un addr;
399 int sock;
400
401 sock = socket (PF_UNIX, SOCK_STREAM, 0);
402 if (sock < 0)
403 return -1;
404
405 addr.sun_family = AF_UNIX;
67479a70 406 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
d67281a7
UD
407 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
408 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
409 {
410 close (sock);
411 return -1;
412 }
413
414 return sock;
415}
416
417/* Cleanup. */
67479a70 418void
d67281a7
UD
419termination_handler (int signum)
420{
421 close_sockets ();
422
230c3e1e 423 /* Clean up the file created by 'bind'. */
d67281a7
UD
424 unlink (_PATH_NSCDSOCKET);
425
426 /* Clean up pid file. */
427 unlink (_PATH_NSCDPID);
428
a95a08b4
UD
429 // XXX Terminate threads.
430
431 /* Synchronize memory. */
432 for (int cnt = 0; cnt < lastdb; ++cnt)
433 if (dbs[cnt].persistent)
434 // XXX async OK?
435 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
436
74a30a58
UD
437 /* Shutdown the SELinux AVC. */
438 if (selinux_enabled)
439 nscd_avc_destroy ();
440
230c3e1e 441 _exit (EXIT_SUCCESS);
d67281a7
UD
442}
443
d67281a7
UD
444/* Returns 1 if the process in pid file FILE is running, 0 if not. */
445static int
446check_pid (const char *file)
447{
448 FILE *fp;
449
450 fp = fopen (file, "r");
451 if (fp)
452 {
453 pid_t pid;
67479a70 454 int n;
d67281a7 455
67479a70 456 n = fscanf (fp, "%d", &pid);
d67281a7
UD
457 fclose (fp);
458
67479a70 459 if (n != 1 || kill (pid, 0) == 0)
d67281a7
UD
460 return 1;
461 }
462
463 return 0;
464}
465
466/* Write the current process id to the file FILE.
467 Returns 0 if successful, -1 if not. */
468static int
469write_pid (const char *file)
470{
471 FILE *fp;
472
473 fp = fopen (file, "w");
474 if (fp == NULL)
475 return -1;
476
477 fprintf (fp, "%d\n", getpid ());
67479a70 478 if (fflush (fp) || ferror (fp))
d67281a7
UD
479 return -1;
480
481 fclose (fp);
482
483 return 0;
484}
d19687d6
UD
485
486
487/* This is an ugly hack which prevents getaddrinfo from being dragged
488 into nscd. There currently is no special getaddrinfo version for
489 use in nscd. In case it should be necessary such a version must be
490 created and this dummy version should be removed. */
04c785b2
UD
491extern void getaddrinfo (void) __attribute ((visibility ("hidden")));
492
d19687d6
UD
493void
494getaddrinfo (void)
495{
496 abort ();
497}
This page took 0.291448 seconds and 5 git commands to generate.