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