(root)/
glibc-2.38/
nscd/
nscd_conf.c
       1  /* Copyright (c) 1998-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     This program is free software; you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published
       6     by the Free Software Foundation; version 2 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program; if not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <ctype.h>
      18  #include <errno.h>
      19  #include <error.h>
      20  #include <libintl.h>
      21  #include <malloc.h>
      22  #include <pwd.h>
      23  #include <stdio.h>
      24  #include <stdio_ext.h>
      25  #include <stdlib.h>
      26  #include <string.h>
      27  #include <unistd.h>
      28  #include <sys/param.h>
      29  #include <sys/types.h>
      30  
      31  #include "dbg_log.h"
      32  #include "nscd.h"
      33  
      34  
      35  /* Names of the databases.  */
      36  const char *const dbnames[lastdb] =
      37  {
      38    [pwddb] = "passwd",
      39    [grpdb] = "group",
      40    [hstdb] = "hosts",
      41    [servdb] = "services",
      42    [netgrdb] = "netgroup"
      43  };
      44  
      45  
      46  static int
      47  find_db (const char *name)
      48  {
      49    for (int cnt = 0; cnt < lastdb; ++cnt)
      50      if (strcmp (name, dbnames[cnt]) == 0)
      51        return cnt;
      52  
      53    error (0, 0, _("database %s is not supported"), name);
      54    return -1;
      55  }
      56  
      57  int
      58  nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
      59  {
      60    FILE *fp;
      61    char *line, *cp, *entry, *arg1, *arg2;
      62    size_t len;
      63    int cnt;
      64    const unsigned int initial_error_message_count = error_message_count;
      65  
      66    /* Open the configuration file.  */
      67    fp = fopen (fname, "r");
      68    if (fp == NULL)
      69      return -1;
      70  
      71    /* The stream is not used by more than one thread.  */
      72    (void) __fsetlocking (fp, FSETLOCKING_BYCALLER);
      73  
      74    line = NULL;
      75    len = 0;
      76  
      77    do
      78      {
      79        ssize_t n = getline (&line, &len, fp);
      80        if (n < 0)
      81  	break;
      82        if (line[n - 1] == '\n')
      83  	line[n - 1] = '\0';
      84  
      85        /* Because the file format does not know any form of quoting we
      86  	 can search forward for the next '#' character and if found
      87  	 make it terminating the line.  */
      88        *strchrnul (line, '#') = '\0';
      89  
      90        /* If the line is blank it is ignored.  */
      91        if (line[0] == '\0')
      92  	continue;
      93  
      94        entry = line;
      95        while (isspace (*entry) && *entry != '\0')
      96  	++entry;
      97        cp = entry;
      98        while (!isspace (*cp) && *cp != '\0')
      99  	++cp;
     100        arg1 = cp;
     101        ++arg1;
     102        *cp = '\0';
     103        if (strlen (entry) == 0)
     104  	error (0, 0, _("Parse error: %s"), line);
     105        while (isspace (*arg1) && *arg1 != '\0')
     106  	++arg1;
     107        cp = arg1;
     108        while (!isspace (*cp) && *cp != '\0')
     109  	++cp;
     110        arg2 = cp;
     111        ++arg2;
     112        *cp = '\0';
     113        if (strlen (arg2) > 0)
     114  	{
     115  	  while (isspace (*arg2) && *arg2 != '\0')
     116  	    ++arg2;
     117  	  cp = arg2;
     118  	  while (!isspace (*cp) && *cp != '\0')
     119  	    ++cp;
     120  	  *cp = '\0';
     121  	}
     122  
     123        if (strcmp (entry, "positive-time-to-live") == 0)
     124  	{
     125  	  int idx = find_db (arg1);
     126  	  if (idx >= 0)
     127  	    dbs[idx].postimeout = atol (arg2);
     128  	}
     129        else if (strcmp (entry, "negative-time-to-live") == 0)
     130  	{
     131  	  int idx = find_db (arg1);
     132  	  if (idx >= 0)
     133  	    dbs[idx].negtimeout = atol (arg2);
     134  	}
     135        else if (strcmp (entry, "suggested-size") == 0)
     136  	{
     137  	  int idx = find_db (arg1);
     138  	  if (idx >= 0)
     139  	    dbs[idx].suggested_module
     140  	      = atol (arg2) ?: DEFAULT_SUGGESTED_MODULE;
     141  	}
     142        else if (strcmp (entry, "enable-cache") == 0)
     143  	{
     144  	  int idx = find_db (arg1);
     145  	  if (idx >= 0)
     146  	    {
     147  	      if (strcmp (arg2, "no") == 0)
     148  		dbs[idx].enabled = 0;
     149  	      else if (strcmp (arg2, "yes") == 0)
     150  		dbs[idx].enabled = 1;
     151  	    }
     152  	}
     153        else if (strcmp (entry, "check-files") == 0)
     154  	{
     155  	  int idx = find_db (arg1);
     156  	  if (idx >= 0)
     157  	    {
     158  	      if (strcmp (arg2, "no") == 0)
     159  		dbs[idx].check_file = 0;
     160  	      else if (strcmp (arg2, "yes") == 0)
     161  		dbs[idx].check_file = 1;
     162  	    }
     163  	}
     164        else if (strcmp (entry, "max-db-size") == 0)
     165  	{
     166  	  int idx = find_db (arg1);
     167  	  if (idx >= 0)
     168  	    dbs[idx].max_db_size = atol (arg2) ?: DEFAULT_MAX_DB_SIZE;
     169  	}
     170        else if (strcmp (entry, "logfile") == 0)
     171  	set_logfile (arg1);
     172        else if (strcmp (entry, "debug-level") == 0)
     173  	{
     174  	  int level = atoi (arg1);
     175  	  if (level > 0)
     176  	    debug_level = level;
     177  	}
     178        else if (strcmp (entry, "threads") == 0)
     179  	{
     180  	  if (nthreads == -1)
     181  	    nthreads = MAX (atol (arg1), lastdb);
     182  	}
     183        else if (strcmp (entry, "max-threads") == 0)
     184  	{
     185  	  max_nthreads = MAX (atol (arg1), lastdb);
     186  	}
     187        else if (strcmp (entry, "server-user") == 0)
     188  	{
     189  	  if (!arg1)
     190  	    error (0, 0, _("Must specify user name for server-user option"));
     191  	  else
     192  	    {
     193  	      free ((char *) server_user);
     194  	      server_user = xstrdup (arg1);
     195  	    }
     196  	}
     197        else if (strcmp (entry, "stat-user") == 0)
     198  	{
     199  	  if (arg1 == NULL)
     200  	    error (0, 0, _("Must specify user name for stat-user option"));
     201  	  else
     202  	    {
     203  	      free ((char *) stat_user);
     204  	      stat_user = xstrdup (arg1);
     205  
     206  	      struct passwd *pw = getpwnam (stat_user);
     207  	      if (pw != NULL)
     208  		stat_uid = pw->pw_uid;
     209  	    }
     210  	}
     211        else if (strcmp (entry, "persistent") == 0)
     212  	{
     213  	  int idx = find_db (arg1);
     214  	  if (idx >= 0)
     215  	    {
     216  	      if (strcmp (arg2, "no") == 0)
     217  		dbs[idx].persistent = 0;
     218  	      else if (strcmp (arg2, "yes") == 0)
     219  		dbs[idx].persistent = 1;
     220  	    }
     221  	}
     222        else if (strcmp (entry, "shared") == 0)
     223  	{
     224  	  int idx = find_db (arg1);
     225  	  if (idx >= 0)
     226  	    {
     227  	      if (strcmp (arg2, "no") == 0)
     228  		dbs[idx].shared = 0;
     229  	      else if (strcmp (arg2, "yes") == 0)
     230  		dbs[idx].shared = 1;
     231  	    }
     232  	}
     233        else if (strcmp (entry, "reload-count") == 0)
     234  	{
     235  	  if (strcasecmp (arg1, "unlimited") == 0)
     236  	    reload_count = UINT_MAX;
     237  	  else
     238  	    {
     239  	      unsigned long int count = strtoul (arg1, NULL, 0);
     240  	      if (count > UINT8_MAX - 1)
     241  		reload_count = UINT_MAX;
     242  	      else
     243  		reload_count = count;
     244  	    }
     245  	}
     246        else if (strcmp (entry, "paranoia") == 0)
     247  	{
     248  	  if (strcmp (arg1, "no") == 0)
     249  	    paranoia = 0;
     250  	  else if (strcmp (arg1, "yes") == 0)
     251  	    paranoia = 1;
     252  	}
     253        else if (strcmp (entry, "restart-interval") == 0)
     254  	{
     255  	  if (arg1 != NULL)
     256  	    restart_interval = atol (arg1);
     257  	  else
     258  	    error (0, 0, _("Must specify value for restart-interval option"));
     259  	}
     260        else if (strcmp (entry, "auto-propagate") == 0)
     261  	{
     262  	  int idx = find_db (arg1);
     263  	  if (idx >= 0)
     264  	    {
     265  	      if (strcmp (arg2, "no") == 0)
     266  		dbs[idx].propagate = 0;
     267  	      else if (strcmp (arg2, "yes") == 0)
     268  		dbs[idx].propagate = 1;
     269  	    }
     270  	}
     271        else
     272  	error (0, 0, _("Unknown option: %s %s %s"), entry, arg1, arg2);
     273      }
     274    while (!feof_unlocked (fp));
     275  
     276    if (paranoia)
     277      {
     278        restart_time = time (NULL) + restart_interval;
     279  
     280        /* Save the old current workding directory if we are in paranoia
     281  	 mode.  We have to change back to it.  */
     282        oldcwd = get_current_dir_name ();
     283        if (oldcwd == NULL)
     284  	{
     285  	  error (0, 0, _("\
     286  cannot get current working directory: %s; disabling paranoia mode"),
     287  		   strerror (errno));
     288  	  paranoia = 0;
     289  	}
     290      }
     291  
     292    /* Enforce sanity.  */
     293    if (max_nthreads < nthreads)
     294      max_nthreads = nthreads;
     295  
     296    for (cnt = 0; cnt < lastdb; ++cnt)
     297      {
     298        size_t datasize = (sizeof (struct database_pers_head)
     299  			 + roundup (dbs[cnt].suggested_module
     300  				    * sizeof (ref_t), ALIGN)
     301  			 + (dbs[cnt].suggested_module
     302  			    * DEFAULT_DATASIZE_PER_BUCKET));
     303        if (datasize > dbs[cnt].max_db_size)
     304  	{
     305  	  error (0, 0, _("maximum file size for %s database too small"),
     306  		   dbnames[cnt]);
     307  	  dbs[cnt].max_db_size = datasize;
     308  	}
     309  
     310      }
     311  
     312    /* Free the buffer.  */
     313    free (line);
     314    /* Close configuration file.  */
     315    fclose (fp);
     316  
     317    return error_message_count != initial_error_message_count;
     318  }