Blame nslcd/nsswitch.c

Packit 6bd9ab
/*
Packit 6bd9ab
   nsswitch.c - functions for parsing /etc/nsswitch.conf
Packit 6bd9ab
Packit 6bd9ab
   Copyright (C) 2011-2015 Arthur de Jong
Packit 6bd9ab
Packit 6bd9ab
   This library is free software; you can redistribute it and/or
Packit 6bd9ab
   modify it under the terms of the GNU Lesser General Public
Packit 6bd9ab
   License as published by the Free Software Foundation; either
Packit 6bd9ab
   version 2.1 of the License, or (at your option) any later version.
Packit 6bd9ab
Packit 6bd9ab
   This library is distributed in the hope that it will be useful,
Packit 6bd9ab
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6bd9ab
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6bd9ab
   Lesser General Public License for more details.
Packit 6bd9ab
Packit 6bd9ab
   You should have received a copy of the GNU Lesser General Public
Packit 6bd9ab
   License along with this library; if not, write to the Free Software
Packit 6bd9ab
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit 6bd9ab
   02110-1301 USA
Packit 6bd9ab
*/
Packit 6bd9ab
Packit 6bd9ab
#include "config.h"
Packit 6bd9ab
Packit 6bd9ab
#include <stdio.h>
Packit 6bd9ab
#include <string.h>
Packit 6bd9ab
#include <ctype.h>
Packit 6bd9ab
#include <errno.h>
Packit 6bd9ab
#include <sys/stat.h>
Packit 6bd9ab
#include <unistd.h>
Packit 6bd9ab
#include <time.h>
Packit 6bd9ab
Packit 6bd9ab
#include "common.h"
Packit 6bd9ab
#include "log.h"
Packit 6bd9ab
Packit 6bd9ab
/* the cached value of whether shadow lookups use LDAP in nsswitch.conf */
Packit 6bd9ab
#define NSSWITCH_FILE "/etc/nsswitch.conf"
Packit 6bd9ab
#define CACHED_UNKNOWN 22
Packit 6bd9ab
static int cached_shadow_uses_ldap = CACHED_UNKNOWN;
Packit 6bd9ab
static time_t cached_shadow_lastcheck = 0;
Packit 6bd9ab
#define CACHED_SHADOW_TIMEOUT (60)
Packit 6bd9ab
static time_t nsswitch_mtime = 0;
Packit 6bd9ab
Packit 6bd9ab
/* the maximum line length supported of nsswitch.conf */
Packit 6bd9ab
#define MAX_LINE_LENGTH          4096
Packit 6bd9ab
Packit 6bd9ab
/* check whether /etc/nsswitch.conf should be related to update
Packit 6bd9ab
   cached_shadow_uses_ldap */
Packit 6bd9ab
void nsswitch_check_reload(void)
Packit 6bd9ab
{
Packit 6bd9ab
  struct stat buf;
Packit 6bd9ab
  time_t t;
Packit 6bd9ab
  if ((cached_shadow_uses_ldap != CACHED_UNKNOWN) &&
Packit 6bd9ab
      ((t = time(NULL)) > (cached_shadow_lastcheck + CACHED_SHADOW_TIMEOUT)))
Packit 6bd9ab
  {
Packit 6bd9ab
    cached_shadow_lastcheck = t;
Packit 6bd9ab
    if (stat(NSSWITCH_FILE, &buf))
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_ERR, "stat(%s) failed: %s", NSSWITCH_FILE, strerror(errno));
Packit 6bd9ab
      /* trigger a recheck anyway */
Packit 6bd9ab
      cached_shadow_uses_ldap = CACHED_UNKNOWN;
Packit 6bd9ab
      return;
Packit 6bd9ab
    }
Packit 6bd9ab
    /* trigger a recheck if file changed */
Packit 6bd9ab
    if (buf.st_mtime != nsswitch_mtime)
Packit 6bd9ab
    {
Packit 6bd9ab
      nsswitch_mtime = buf.st_mtime;
Packit 6bd9ab
      cached_shadow_uses_ldap = CACHED_UNKNOWN;
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* see if the line is a service definition for db and return a pointer to
Packit 6bd9ab
   the beginning of the services list if it is */
Packit 6bd9ab
static const char *find_db(const char *line, const char *db)
Packit 6bd9ab
{
Packit 6bd9ab
  int i;
Packit 6bd9ab
  i = strlen(db);
Packit 6bd9ab
  /* the line should begin with the db we're looking for */
Packit 6bd9ab
  if (strncmp(line, db, i) != 0)
Packit 6bd9ab
    return NULL;
Packit 6bd9ab
  /* followed by a : */
Packit 6bd9ab
  while (isspace(line[i]))
Packit 6bd9ab
    i++;
Packit 6bd9ab
  if (line[i] != ':')
Packit 6bd9ab
    return NULL;
Packit 6bd9ab
  i++;
Packit 6bd9ab
  while (isspace(line[i]))
Packit 6bd9ab
    i++;
Packit 6bd9ab
  return line + i;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* check to see if the list of services contains the specified service */
Packit 6bd9ab
static int has_service(const char *services, const char *service,
Packit 6bd9ab
                       const char *filename, int lnr)
Packit 6bd9ab
{
Packit 6bd9ab
  int i = 0, l;
Packit 6bd9ab
  if (services == NULL)
Packit 6bd9ab
    return 0;
Packit 6bd9ab
  l = strlen(service);
Packit 6bd9ab
  while (services[i] != '\0')
Packit 6bd9ab
  {
Packit 6bd9ab
    /* skip spaces */
Packit 6bd9ab
    while (isspace(services[i]))
Packit 6bd9ab
      i++;
Packit 6bd9ab
    /* check if this is the service */
Packit 6bd9ab
    if ((strncmp(services + i, service, l) == 0) && (!isalnum(services[i + l])))
Packit 6bd9ab
      return 1;
Packit 6bd9ab
    /* skip service name and spaces */
Packit 6bd9ab
    i++;
Packit 6bd9ab
    while (isalnum(services[i]))
Packit 6bd9ab
      i++;
Packit 6bd9ab
    while (isspace(services[i]))
Packit 6bd9ab
      i++;
Packit 6bd9ab
    /* skip action mappings */
Packit 6bd9ab
    if (services[i] == '[')
Packit 6bd9ab
    {
Packit 6bd9ab
      i++; /* skip [ */
Packit 6bd9ab
      while ((services[i] != ']') && (services[i] != '\0'))
Packit 6bd9ab
        i++;
Packit 6bd9ab
      if (services[i] != ']')
Packit 6bd9ab
      {
Packit 6bd9ab
        log_log(LOG_WARNING, "%s: error parsing line %d", filename, lnr);
Packit 6bd9ab
        return 0; /* parse error */
Packit 6bd9ab
      }
Packit 6bd9ab
      i++; /* skip ] */
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  return 0;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static int shadow_uses_ldap(void)
Packit 6bd9ab
{
Packit 6bd9ab
  FILE *fp;
Packit 6bd9ab
  int lnr = 0;
Packit 6bd9ab
  char linebuf[MAX_LINE_LENGTH];
Packit 6bd9ab
  const char *services;
Packit 6bd9ab
  int shadow_found = 0;
Packit 6bd9ab
  int passwd_has_ldap = 0;
Packit 6bd9ab
  /* open config file */
Packit 6bd9ab
  if ((fp = fopen(NSSWITCH_FILE, "r")) == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "cannot open %s: %s", NSSWITCH_FILE, strerror(errno));
Packit 6bd9ab
    return 0;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* read file and parse lines */
Packit 6bd9ab
  while (fgets(linebuf, sizeof(linebuf), fp) != NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    lnr++;
Packit 6bd9ab
    /* see if we have a shadow line */
Packit 6bd9ab
    services = find_db(linebuf, "shadow");
Packit 6bd9ab
    if (services != NULL)
Packit 6bd9ab
    {
Packit 6bd9ab
      shadow_found = 1;
Packit 6bd9ab
      if (has_service(services, MODULE_NAME, NSSWITCH_FILE, lnr))
Packit 6bd9ab
      {
Packit 6bd9ab
        fclose(fp);
Packit 6bd9ab
        return 1;
Packit 6bd9ab
      }
Packit 6bd9ab
    }
Packit 6bd9ab
    /* see if we have a passwd line */
Packit 6bd9ab
    services = find_db(linebuf, "passwd");
Packit 6bd9ab
    if (services != NULL)
Packit 6bd9ab
      passwd_has_ldap = has_service(services, MODULE_NAME, NSSWITCH_FILE, lnr);
Packit 6bd9ab
  }
Packit 6bd9ab
  fclose(fp);
Packit 6bd9ab
  if (shadow_found)
Packit 6bd9ab
    return 0;
Packit 6bd9ab
  return passwd_has_ldap;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* check whether shadow lookups are configured to use ldap */
Packit 6bd9ab
int nsswitch_shadow_uses_ldap(void)
Packit 6bd9ab
{
Packit 6bd9ab
  if (cached_shadow_uses_ldap == CACHED_UNKNOWN)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_INFO, "(re)loading %s", NSSWITCH_FILE);
Packit 6bd9ab
    cached_shadow_uses_ldap = shadow_uses_ldap();
Packit 6bd9ab
    cached_shadow_lastcheck = time(NULL);
Packit 6bd9ab
  }
Packit 6bd9ab
  return cached_shadow_uses_ldap;
Packit 6bd9ab
}