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