summary refs log tree commit diff
path: root/nscd/nscd.c
diff options
context:
space:
mode:
Diffstat (limited to 'nscd/nscd.c')
-rw-r--r--nscd/nscd.c423
1 files changed, 423 insertions, 0 deletions
diff --git a/nscd/nscd.c b/nscd/nscd.c
new file mode 100644
index 0000000000..59d4a60e02
--- /dev/null
+++ b/nscd/nscd.c
@@ -0,0 +1,423 @@
+/* Copyright (c) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+/* nscd - Name Service Cache Daemon. Caches passwd and group.  */
+
+#include <errno.h>
+#include <getopt.h>
+#include <libintl.h>
+#include <locale.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "dbg_log.h"
+#include "nscd.h"
+
+/* Get libc version number.  */
+#include <version.h>
+
+#define PACKAGE _libc_intl_domainname
+
+/* Structure used by main() thread to keep track of the number of
+   active threads.  Used to limit how many threads it will create
+   and under a shutdown condition to wait till all in-progress
+   requests have finished before "turning off the lights".  */
+
+typedef struct
+{
+  int             num_active;
+  pthread_cond_t  thread_exit_cv;
+  pthread_mutex_t mutex;
+} thread_info_t;
+
+thread_info_t thread_info;
+
+int do_shutdown = 0;
+int disabled_passwd = 0;
+int disabled_group = 0;
+
+static void termination_handler (int signum);
+static int check_pid (const char *file);
+static int write_pid (const char *file);
+static void usage (int status) __attribute__ ((noreturn));
+static void handle_requests (void);
+
+int
+main (int argc, char **argv)
+{
+  int go_background = 1;
+  const char *conffile = _PATH_NSCDCONF;
+
+  /* Set locale via LC_ALL.  */
+  setlocale (LC_ALL, "");
+  /* Set the text message domain.  */
+  textdomain (PACKAGE);
+
+  while (1)
+    {
+      int c;
+      int option_index = 0;
+      static struct option long_options[] = {
+	{ "debug", no_argument, NULL, 'd' },
+	{ "help", no_argument, NULL, 'h' },
+	{ "version", no_argument, NULL, 'V' },
+	{ "shutdown", no_argument, NULL, 'K' },
+        {NULL, 0, NULL, '\0'}
+      };
+
+      c = getopt_long (argc, argv, "df:ghKV", long_options, &option_index);
+      if (c == (-1))
+        break;
+      switch (c)
+	{
+	case 'd':
+	  debug_flag = 1;
+	  go_background = 0;
+	  break;
+	case 'f':
+	  conffile = optarg;
+	  break;
+	case 'h':
+	  usage (EXIT_SUCCESS);
+	  break;
+	case 'K':
+	  if (getuid () != 0)
+	    {
+	      printf (_("Only root is allowed to use this option!\n\n"));
+	      usage (EXIT_FAILURE);
+	    }
+	  {
+	    int sock = __nscd_open_socket ();
+	    request_header req;
+	    ssize_t nbytes;
+
+	    if (sock == -1)
+	      exit (EXIT_FAILURE);
+
+	    req.version = NSCD_VERSION;
+	    req.type = SHUTDOWN;
+	    req.key_len = 0;
+	    nbytes = write (sock, &req, sizeof (request_header));
+	    close (sock);
+	    if (nbytes != req.key_len)
+	      exit (EXIT_FAILURE);
+	    else
+	      exit (EXIT_SUCCESS);
+	  }
+	case 'g':
+	  print_stat ();
+	  exit (EXIT_SUCCESS);
+	case 'V':
+	  printf ("nscd (GNU %s) %s\n", PACKAGE, VERSION);
+	  printf (_("\
+Copyright (C) %s Free Software Foundation, Inc.\n\
+This is free software; see the source for copying conditions.  There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+"), "1998");
+	  printf (_("Written by %s.\n"), "Thorsten Kukuk");
+	  exit (EXIT_SUCCESS);
+	default:
+	  usage (EXIT_FAILURE);
+	}
+    }
+
+  signal (SIGINT, termination_handler);
+  signal (SIGQUIT, termination_handler);
+  signal (SIGTERM, termination_handler);
+
+  /* Check if we are already running. */
+  if (check_pid (_PATH_NSCDPID))
+    {
+      fputs (_("already running"), stderr);
+      exit (EXIT_FAILURE);
+    }
+
+  /* Behave like a daemon.  */
+  if (go_background)
+    {
+      openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
+
+      if (daemon (0, 0) < 0)
+	{
+	  fprintf (stderr, _("connot auto-background: %s\n"),
+		   strerror (errno));
+	  exit (EXIT_FAILURE);
+	}
+      if (write_pid (_PATH_NSCDPID) < 0)
+        dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
+
+      /* Ignore job control signals */
+      signal (SIGTTOU, SIG_IGN);
+      signal (SIGTTIN, SIG_IGN);
+      signal (SIGTSTP, SIG_IGN);
+    }
+  /* Cleanup files created by a previous `bind' */
+  unlink (_PATH_NSCDSOCKET);
+
+  nscd_parse_file (conffile);
+
+  /* Create first sockets */
+  init_sockets ();
+  /* Init databases */
+  cache_pwdinit ();
+  cache_grpinit ();
+  /* Handle incoming requests */
+  handle_requests ();
+
+  return 0;
+}
+
+/* Create a socket connected to a name. */
+int
+__nscd_open_socket (void)
+{
+  struct sockaddr_un addr;
+  int sock;
+
+  sock = socket (PF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    return -1;
+
+  addr.sun_family = AF_UNIX;
+  strcpy (addr.sun_path, _PATH_NSCDSOCKET);
+  if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
+    {
+      close (sock);
+      return -1;
+    }
+
+  return sock;
+}
+
+/* Cleanup.  */
+static void
+termination_handler (int signum)
+{
+  close_sockets ();
+
+  /* Clean up the files created by `bind'.  */
+  unlink (_PATH_NSCDSOCKET);
+
+  /* Clean up pid file.  */
+  unlink (_PATH_NSCDPID);
+
+  exit (EXIT_SUCCESS);
+}
+
+/* Display usage information and exit.  */
+static void
+usage (int status)
+{
+  if (status != EXIT_SUCCESS)
+    fprintf (stderr, _("Try `%s --help' for more information.\n"),
+             program_invocation_name);
+  else
+    {
+      printf (_("\
+Usage: %s [OPTION]...\n\
+  -d, --debug           do not fork and display messages on the current tty\n\
+  -h, --help            display this help and exit\n\
+  -V, --version         output version information and exit\n\
+  -f configuration-file read configuration data from the specified file.\n\
+  -K, --shutdown        shut the server down.\n\
+  -g                    Prints configuration and statistics to stdout.\n"),
+              program_invocation_name);
+      fputs (_("\
+Report bugs using the `glibcbug' script to <bugs@gnu.org>.\n"),
+             stdout);
+    }
+  exit (status);
+}
+
+/* Returns 1 if the process in pid file FILE is running, 0 if not.  */
+static int
+check_pid (const char *file)
+{
+  FILE *fp;
+
+  fp = fopen (file, "r");
+  if (fp)
+    {
+      pid_t pid;
+
+      fscanf (fp, "%d", &pid);
+      fclose (fp);
+
+      if (kill (pid, 0) == 0)
+        return 1;
+    }
+
+  return 0;
+}
+
+/* Write the current process id to the file FILE.
+   Returns 0 if successful, -1 if not.  */
+static int
+write_pid (const char *file)
+{
+  FILE *fp;
+
+  fp = fopen (file, "w");
+  if (fp == NULL)
+    return -1;
+
+  fprintf (fp, "%d\n", getpid ());
+  if (ferror (fp))
+    return -1;
+
+  fclose (fp);
+
+  return 0;
+}
+
+/* Type of the lookup function for netname2user.  */
+typedef int (*pwbyname_function) (const char *name, struct passwd *pw,
+				   char *buffer, size_t buflen);
+
+/* Hanlde incoming requests.  */
+static
+void handle_requests (void)
+{
+  request_header req;
+  int conn; /* Handle on which connection (client) the request came from.  */
+  int done = 0;
+  char *key;
+
+  while (!done)
+    {
+      key = NULL;
+      get_request (&conn, &req, &key);
+      if (debug_flag)
+	dbg_log (_("handle_requests: request received (Version = %d)"),
+		 req.version);
+      switch (req.type)
+	{
+	case GETPWBYNAME:
+	  {
+	    param_t *param = malloc (sizeof (param_t));
+	    pthread_t thread;
+
+	    if (debug_flag)
+	      dbg_log ("\tGETPWBYNAME (%s)", key);
+	    param->key = key;
+	    param->conn = conn;
+	    if (disabled_passwd)
+	      pthread_create (&thread, NULL, cache_pw_disabled, (void *)param);
+	    else
+	      pthread_create (&thread, NULL, cache_getpwnam, (void *)param);
+	    pthread_detach (thread);
+	  }
+	  break;
+	case GETPWBYUID:
+	  {
+	    param_t *param = malloc (sizeof (param_t));
+	    pthread_t thread;
+
+	    if (debug_flag)
+	      dbg_log ("\tGETPWBYUID (%s)", key);
+	    param->key = key;
+	    param->conn = conn;
+	    if (disabled_passwd)
+	      pthread_create (&thread, NULL, cache_pw_disabled, (void *)param);
+	    else
+	      pthread_create (&thread, NULL, cache_getpwuid, (void *)param);
+	    pthread_detach (thread);
+	  }
+	  break;
+	case GETGRBYNAME:
+	  {
+	    param_t *param = malloc (sizeof (param_t));
+	    pthread_t thread;
+
+	    if (debug_flag)
+	      dbg_log ("\tGETGRBYNAME (%s)", key);
+	    param->key = key;
+	    param->conn = conn;
+	    if (disabled_group)
+	      pthread_create (&thread, NULL, cache_gr_disabled, (void *)param);
+	    else
+	      pthread_create (&thread, NULL, cache_getgrnam, (void *)param);
+	    pthread_detach (thread);
+	  }
+	  break;
+	case GETGRBYGID:
+	  {
+	    param_t *param = malloc (sizeof (param_t));
+	    pthread_t thread;
+
+	    if (debug_flag)
+	      dbg_log ("\tGETGRBYGID (%s)", key);
+	    param->key = key;
+	    param->conn = conn;
+	    if (disabled_group)
+	      pthread_create (&thread, NULL, cache_gr_disabled, (void *)param);
+	    else
+	      pthread_create (&thread, NULL, cache_getgrgid, (void *)param);
+	    pthread_detach (thread);
+	  }
+	  break;
+	case GETHOSTBYNAME:
+	  /* Not yetimplemented.  */
+	  close_socket (conn);
+	  break;
+	case GETHOSTBYADDR:
+	  /* Not yet implemented. */
+	  close_socket (conn);
+	  break;
+	case SHUTDOWN:
+	  do_shutdown = 1;
+	  close_socket (0);
+	  close_socket (conn);
+	  /* Clean up the files created by `bind'.  */
+	  unlink (_PATH_NSCDSOCKET);
+	  /* Clean up pid file.  */
+	  unlink (_PATH_NSCDPID);
+	  done = 1;
+	  break;
+	case GETSTAT:
+	  {
+	    stat_response_header resp;
+
+	    if (debug_flag)
+	      dbg_log ("\tGETSTAT");
+
+	    get_pw_stat (&resp);
+	    get_gr_stat (&resp);
+	    resp.debug_level = debug_flag;
+	    resp.pw_enabled = !disabled_passwd;
+	    resp.gr_enabled = !disabled_group;
+
+	    stat_send (conn, &resp);
+
+	    close_socket (conn);
+	  }
+	  break;
+	default:
+	  dbg_log (_("Unknown request (%d)"), req.type);
+	  break;
+	}
+    }
+}