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