Blame nslcd/passwd.c

Packit 6bd9ab
/*
Packit 6bd9ab
   passwd.c - password entry lookup routines
Packit 6bd9ab
   Parts of this file were part of the nss_ldap library (as ldap-pwd.c)
Packit 6bd9ab
   which has been forked into the nss-pam-ldapd library.
Packit 6bd9ab
Packit 6bd9ab
   Copyright (C) 1997-2005 Luke Howard
Packit 6bd9ab
   Copyright (C) 2006 West Consulting
Packit 6bd9ab
   Copyright (C) 2006-2017 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 <stdlib.h>
Packit 6bd9ab
#include <sys/types.h>
Packit 6bd9ab
#include <unistd.h>
Packit 6bd9ab
#include <string.h>
Packit 6bd9ab
#include <pthread.h>
Packit 6bd9ab
Packit 6bd9ab
#include "common.h"
Packit 6bd9ab
#include "log.h"
Packit 6bd9ab
#include "myldap.h"
Packit 6bd9ab
#include "cfg.h"
Packit 6bd9ab
#include "attmap.h"
Packit 6bd9ab
#include "common/dict.h"
Packit 6bd9ab
#include "compat/strndup.h"
Packit 6bd9ab
Packit 6bd9ab
/* ( nisSchema.2.0 NAME 'posixAccount' SUP top AUXILIARY
Packit 6bd9ab
 *   DESC 'Abstraction of an account with POSIX attributes'
Packit 6bd9ab
 *   MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
Packit 6bd9ab
 *   MAY ( userPassword $ loginShell $ gecos $ description ) )
Packit 6bd9ab
 */
Packit 6bd9ab
Packit 6bd9ab
/* the search base for searches */
Packit 6bd9ab
const char *passwd_bases[NSS_LDAP_CONFIG_MAX_BASES] = { NULL };
Packit 6bd9ab
Packit 6bd9ab
/* the search scope for searches */
Packit 6bd9ab
int passwd_scope = LDAP_SCOPE_DEFAULT;
Packit 6bd9ab
Packit 6bd9ab
/* the basic search filter for searches */
Packit 6bd9ab
const char *passwd_filter = "(objectClass=posixAccount)";
Packit 6bd9ab
Packit 6bd9ab
/* the attributes used in searches */
Packit 6bd9ab
const char *attmap_passwd_uid           = "uid";
Packit 6bd9ab
const char *attmap_passwd_userPassword  = "\"*\"";
Packit 6bd9ab
const char *attmap_passwd_uidNumber     = "uidNumber";
Packit 6bd9ab
const char *attmap_passwd_gidNumber     = "gidNumber";
Packit 6bd9ab
const char *attmap_passwd_gecos         = "\"${gecos:-$cn}\"";
Packit 6bd9ab
const char *attmap_passwd_homeDirectory = "homeDirectory";
Packit 6bd9ab
const char *attmap_passwd_loginShell    = "loginShell";
Packit 6bd9ab
Packit 6bd9ab
/* special properties for objectSid-based searches
Packit 6bd9ab
   (these are already LDAP-escaped strings) */
Packit 6bd9ab
static char *uidSid = NULL;
Packit 6bd9ab
static char *gidSid = NULL;
Packit 6bd9ab
Packit 6bd9ab
/* default values for attributes */
Packit 6bd9ab
static const char *default_passwd_userPassword = "*"; /* unmatchable */
Packit 6bd9ab
Packit 6bd9ab
/* Note that the resulting password value should be one of:
Packit 6bd9ab
   <empty> - no password set, allow login without password
Packit 6bd9ab
   *       - often used to prevent logins
Packit 6bd9ab
   x       - "valid" encrypted password that does not match any valid password
Packit 6bd9ab
             often used to indicate that the password is defined elsewhere
Packit 6bd9ab
   other   - encrypted password, usually in crypt(3) format */
Packit 6bd9ab
Packit 6bd9ab
/* the attribute list to request with searches */
Packit 6bd9ab
static const char **passwd_attrs = NULL;
Packit 6bd9ab
Packit 6bd9ab
/* create a search filter for searching a passwd entry
Packit 6bd9ab
   by name, return -1 on errors */
Packit 6bd9ab
static int mkfilter_passwd_byname(const char *name,
Packit 6bd9ab
                                  char *buffer, size_t buflen)
Packit 6bd9ab
{
Packit 6bd9ab
  char safename[BUFLEN_SAFENAME];
Packit 6bd9ab
  /* escape attribute */
Packit 6bd9ab
  if (myldap_escape(name, safename, sizeof(safename)))
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "mkfilter_passwd_byname(): safename buffer too small");
Packit 6bd9ab
    return -1;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* build filter */
Packit 6bd9ab
  return mysnprintf(buffer, buflen, "(&%s(%s=%s))",
Packit 6bd9ab
                    passwd_filter, attmap_passwd_uid, safename);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* create a search filter for searching a passwd entry
Packit 6bd9ab
   by uid, return -1 on errors */
Packit 6bd9ab
static int mkfilter_passwd_byuid(uid_t uid, char *buffer, size_t buflen)
Packit 6bd9ab
{
Packit 6bd9ab
  uid -= nslcd_cfg->nss_uid_offset;
Packit 6bd9ab
  if (uidSid != NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    return mysnprintf(buffer, buflen, "(&%s(%s=%s\\%02x\\%02x\\%02x\\%02x))",
Packit 6bd9ab
                      passwd_filter, attmap_passwd_uidNumber, uidSid,
Packit 6bd9ab
                      (int)(uid & 0xff), (int)((uid >> 8) & 0xff),
Packit 6bd9ab
                      (int)((uid >> 16) & 0xff), (int)((uid >> 24) & 0xff));
Packit 6bd9ab
  }
Packit 6bd9ab
  else
Packit 6bd9ab
  {
Packit 6bd9ab
    return mysnprintf(buffer, buflen, "(&%s(%s=%lu))",
Packit 6bd9ab
                      passwd_filter, attmap_passwd_uidNumber, (unsigned long int)uid);
Packit 6bd9ab
  }
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
void passwd_init(void)
Packit 6bd9ab
{
Packit 6bd9ab
  int i;
Packit 6bd9ab
  SET *set;
Packit 6bd9ab
  /* set up search bases */
Packit 6bd9ab
  if (passwd_bases[0] == NULL)
Packit 6bd9ab
    for (i = 0; i < NSS_LDAP_CONFIG_MAX_BASES; i++)
Packit 6bd9ab
      passwd_bases[i] = nslcd_cfg->bases[i];
Packit 6bd9ab
  /* set up scope */
Packit 6bd9ab
  if (passwd_scope == LDAP_SCOPE_DEFAULT)
Packit 6bd9ab
    passwd_scope = nslcd_cfg->scope;
Packit 6bd9ab
  /* special case when uidNumber or gidNumber reference objectSid */
Packit 6bd9ab
  if (strncasecmp(attmap_passwd_uidNumber, "objectSid:", 10) == 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    uidSid = sid2search(attmap_passwd_uidNumber + 10);
Packit 6bd9ab
    attmap_passwd_uidNumber = strndup(attmap_passwd_uidNumber, 9);
Packit 6bd9ab
  }
Packit 6bd9ab
  if (strncasecmp(attmap_passwd_gidNumber, "objectSid:", 10) == 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    gidSid = sid2search(attmap_passwd_gidNumber + 10);
Packit 6bd9ab
    attmap_passwd_gidNumber = strndup(attmap_passwd_gidNumber, 9);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* set up attribute list */
Packit 6bd9ab
  set = set_new();
Packit 6bd9ab
  attmap_add_attributes(set, "objectClass"); /* for testing shadowAccount */
Packit 6bd9ab
  attmap_add_attributes(set, attmap_passwd_uid);
Packit 6bd9ab
  attmap_add_attributes(set, attmap_passwd_userPassword);
Packit 6bd9ab
  attmap_add_attributes(set, attmap_passwd_uidNumber);
Packit 6bd9ab
  attmap_add_attributes(set, attmap_passwd_gidNumber);
Packit 6bd9ab
  attmap_add_attributes(set, attmap_passwd_gecos);
Packit 6bd9ab
  attmap_add_attributes(set, attmap_passwd_homeDirectory);
Packit 6bd9ab
  attmap_add_attributes(set, attmap_passwd_loginShell);
Packit 6bd9ab
  passwd_attrs = set_tolist(set);
Packit 6bd9ab
  if (passwd_attrs == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_CRIT, "malloc() failed to allocate memory");
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  set_free(set);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* the cache that is used in dn2uid() */
Packit 6bd9ab
static pthread_mutex_t dn2uid_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
Packit 6bd9ab
static DICT *dn2uid_cache = NULL;
Packit 6bd9ab
struct dn2uid_cache_entry {
Packit 6bd9ab
  time_t timestamp;
Packit 6bd9ab
  char *uid;
Packit 6bd9ab
};
Packit 6bd9ab
Packit 6bd9ab
/* checks whether the entry has a valid uidNumber attribute
Packit 6bd9ab
   (>= nss_min_uid) */
Packit 6bd9ab
static int entry_has_valid_uid(MYLDAP_ENTRY *entry)
Packit 6bd9ab
{
Packit 6bd9ab
  int i;
Packit 6bd9ab
  const char **values;
Packit 6bd9ab
  char *tmp;
Packit 6bd9ab
  uid_t uid;
Packit 6bd9ab
  /* if min_uid is not set any entry should do */
Packit 6bd9ab
  if (nslcd_cfg->nss_min_uid == 0)
Packit 6bd9ab
    return 1;
Packit 6bd9ab
  /* get all uidNumber attributes */
Packit 6bd9ab
  values = myldap_get_values_len(entry, attmap_passwd_uidNumber);
Packit 6bd9ab
  if ((values == NULL) || (values[0] == NULL))
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_WARNING, "%s: %s: missing",
Packit 6bd9ab
            myldap_get_dn(entry), attmap_passwd_uidNumber);
Packit 6bd9ab
    return 0;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check if there is a uidNumber attributes >= min_uid */
Packit 6bd9ab
  for (i = 0; values[i] != NULL; i++)
Packit 6bd9ab
  {
Packit 6bd9ab
    if (uidSid != NULL)
Packit 6bd9ab
      uid = (uid_t)binsid2id(values[i]);
Packit 6bd9ab
    else
Packit 6bd9ab
    {
Packit 6bd9ab
      errno = 0;
Packit 6bd9ab
      uid = strtouid(values[i], &tmp, 10);
Packit 6bd9ab
      if ((*(values[i]) == '\0') || (*tmp != '\0'))
Packit 6bd9ab
      {
Packit 6bd9ab
        log_log(LOG_WARNING, "%s: %s: non-numeric",
Packit 6bd9ab
                myldap_get_dn(entry), attmap_passwd_uidNumber);
Packit 6bd9ab
        continue;
Packit 6bd9ab
      }
Packit 6bd9ab
      else if ((errno != 0) || (strchr(values[i], '-') != NULL))
Packit 6bd9ab
      {
Packit 6bd9ab
        log_log(LOG_WARNING, "%s: %s: out of range",
Packit 6bd9ab
                myldap_get_dn(entry), attmap_passwd_uidNumber);
Packit 6bd9ab
        continue;
Packit 6bd9ab
      }
Packit 6bd9ab
    }
Packit 6bd9ab
    if (uid < nslcd_cfg->nss_min_uid)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_DEBUG, "%s: %s: less than nss_min_uid",
Packit 6bd9ab
              myldap_get_dn(entry), attmap_passwd_uidNumber);
Packit 6bd9ab
    }
Packit 6bd9ab
    else
Packit 6bd9ab
      return 1;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* nothing found */
Packit 6bd9ab
  return 0;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* Perform an LDAP lookup to translate the DN into a uid.
Packit 6bd9ab
   This function either returns NULL or a strdup()ed string. */
Packit 6bd9ab
char *lookup_dn2uid(MYLDAP_SESSION *session, const char *dn, int *rcp,
Packit 6bd9ab
                    char *buf, size_t buflen)
Packit 6bd9ab
{
Packit 6bd9ab
  MYLDAP_SEARCH *search;
Packit 6bd9ab
  MYLDAP_ENTRY *entry;
Packit 6bd9ab
  static const char *attrs[3];
Packit 6bd9ab
  int rc = LDAP_SUCCESS;
Packit 6bd9ab
  const char **values;
Packit 6bd9ab
  char *uid = NULL;
Packit 6bd9ab
  if (rcp == NULL)
Packit 6bd9ab
    rcp = &rc;
Packit 6bd9ab
  /* we have to look up the entry */
Packit 6bd9ab
  attrs[0] = attmap_passwd_uid;
Packit 6bd9ab
  attrs[1] = attmap_passwd_uidNumber;
Packit 6bd9ab
  attrs[2] = NULL;
Packit 6bd9ab
  search = myldap_search(session, dn, LDAP_SCOPE_BASE, passwd_filter, attrs, rcp);
Packit 6bd9ab
  if (search == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_WARNING, "%s: lookup error: %s", dn, ldap_err2string(*rcp));
Packit 6bd9ab
    return NULL;
Packit 6bd9ab
  }
Packit 6bd9ab
  entry = myldap_get_entry(search, rcp);
Packit 6bd9ab
  if (entry == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    if (*rcp != LDAP_SUCCESS)
Packit 6bd9ab
      log_log(LOG_WARNING, "%s: lookup error: %s", dn, ldap_err2string(*rcp));
Packit 6bd9ab
    return NULL;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check the uidNumber attribute if min_uid is set */
Packit 6bd9ab
  if (entry_has_valid_uid(entry))
Packit 6bd9ab
  {
Packit 6bd9ab
    /* get uid (just use first one) */
Packit 6bd9ab
    values = myldap_get_values(entry, attmap_passwd_uid);
Packit 6bd9ab
    /* check the result for presence and validity */
Packit 6bd9ab
    if ((values != NULL) && (values[0] != NULL) &&
Packit 6bd9ab
        isvalidname(values[0]) && (strlen(values[0]) < buflen))
Packit 6bd9ab
    {
Packit 6bd9ab
      strcpy(buf, values[0]);
Packit 6bd9ab
      uid = buf;
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* clean up and return */
Packit 6bd9ab
  myldap_search_close(search);
Packit 6bd9ab
  return uid;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* Translate the DN into a user name. This function tries several aproaches
Packit 6bd9ab
   at getting the user name, including looking in the DN for a uid attribute,
Packit 6bd9ab
   looking in the cache and falling back to looking up a uid attribute in a
Packit 6bd9ab
   LDAP query. */
Packit 6bd9ab
char *dn2uid(MYLDAP_SESSION *session, const char *dn, char *buf, size_t buflen)
Packit 6bd9ab
{
Packit 6bd9ab
  struct dn2uid_cache_entry *cacheentry = NULL;
Packit 6bd9ab
  char *uid;
Packit 6bd9ab
  /* check for empty string */
Packit 6bd9ab
  if ((dn == NULL) || (*dn == '\0'))
Packit 6bd9ab
    return NULL;
Packit 6bd9ab
  /* try to look up uid within DN string */
Packit 6bd9ab
  if (myldap_cpy_rdn_value(dn, attmap_passwd_uid, buf, buflen) != NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* check if it is valid */
Packit 6bd9ab
    if (!isvalidname(buf))
Packit 6bd9ab
      return NULL;
Packit 6bd9ab
    return buf;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* if we don't use the cache, just lookup and return */
Packit 6bd9ab
  if ((nslcd_cfg->cache_dn2uid_positive == 0) && (nslcd_cfg->cache_dn2uid_negative == 0))
Packit 6bd9ab
    return lookup_dn2uid(session, dn, NULL, buf, buflen);
Packit 6bd9ab
  /* see if we have a cached entry */
Packit 6bd9ab
  pthread_mutex_lock(&dn2uid_cache_mutex);
Packit 6bd9ab
  if (dn2uid_cache == NULL)
Packit 6bd9ab
    dn2uid_cache = dict_new();
Packit 6bd9ab
  if ((dn2uid_cache != NULL) && ((cacheentry = dict_get(dn2uid_cache, dn)) != NULL))
Packit 6bd9ab
  {
Packit 6bd9ab
    if ((cacheentry->uid != NULL) && (strlen(cacheentry->uid) < buflen))
Packit 6bd9ab
    {
Packit 6bd9ab
      /* positive hit: if the cached entry is still valid, return that */
Packit 6bd9ab
      if ((nslcd_cfg->cache_dn2uid_positive > 0) &&
Packit 6bd9ab
          (time(NULL) < (cacheentry->timestamp + nslcd_cfg->cache_dn2uid_positive)))
Packit 6bd9ab
      {
Packit 6bd9ab
        strcpy(buf, cacheentry->uid);
Packit 6bd9ab
        pthread_mutex_unlock(&dn2uid_cache_mutex);
Packit 6bd9ab
        return buf;
Packit 6bd9ab
      }
Packit 6bd9ab
    }
Packit 6bd9ab
    else
Packit 6bd9ab
    {
Packit 6bd9ab
      /* negative hit: if the cached entry is still valid, return that */
Packit 6bd9ab
      if ((nslcd_cfg->cache_dn2uid_negative > 0) &&
Packit 6bd9ab
           (time(NULL) < (cacheentry->timestamp + nslcd_cfg->cache_dn2uid_negative)))
Packit 6bd9ab
      {
Packit 6bd9ab
        pthread_mutex_unlock(&dn2uid_cache_mutex);
Packit 6bd9ab
        return NULL;
Packit 6bd9ab
      }
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  pthread_mutex_unlock(&dn2uid_cache_mutex);
Packit 6bd9ab
  /* look up the uid using an LDAP query */
Packit 6bd9ab
  uid = lookup_dn2uid(session, dn, NULL, buf, buflen);
Packit 6bd9ab
  /* store the result in the cache */
Packit 6bd9ab
  pthread_mutex_lock(&dn2uid_cache_mutex);
Packit 6bd9ab
  /* try to get the entry from the cache here again because it could have
Packit 6bd9ab
     changed in the meantime */
Packit 6bd9ab
  cacheentry = dict_get(dn2uid_cache, dn);
Packit 6bd9ab
  if (cacheentry == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* allocate a new entry in the cache */
Packit 6bd9ab
    cacheentry = (struct dn2uid_cache_entry *)malloc(sizeof(struct dn2uid_cache_entry));
Packit 6bd9ab
    if (cacheentry != NULL)
Packit 6bd9ab
    {
Packit 6bd9ab
      cacheentry->uid = NULL;
Packit 6bd9ab
      dict_put(dn2uid_cache, dn, cacheentry);
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* update the cache entry */
Packit 6bd9ab
  if (cacheentry != NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    cacheentry->timestamp = time(NULL);
Packit 6bd9ab
    /* copy the uid if needed */
Packit 6bd9ab
    if (cacheentry->uid == NULL)
Packit 6bd9ab
      cacheentry->uid = uid != NULL ? strdup(uid) : NULL;
Packit 6bd9ab
    else if ((uid == NULL) || (strcmp(cacheentry->uid, uid) != 0))
Packit 6bd9ab
    {
Packit 6bd9ab
      free(cacheentry->uid);
Packit 6bd9ab
      cacheentry->uid = uid != NULL ? strdup(uid) : NULL;
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  pthread_mutex_unlock(&dn2uid_cache_mutex);
Packit 6bd9ab
  /* copy the result into the buffer */
Packit 6bd9ab
  return uid;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
MYLDAP_ENTRY *uid2entry(MYLDAP_SESSION *session, const char *uid, int *rcp)
Packit 6bd9ab
{
Packit 6bd9ab
  MYLDAP_SEARCH *search = NULL;
Packit 6bd9ab
  MYLDAP_ENTRY *entry = NULL;
Packit 6bd9ab
  const char *base;
Packit 6bd9ab
  int i;
Packit 6bd9ab
  static const char *attrs[3];
Packit 6bd9ab
  char filter[BUFLEN_FILTER];
Packit 6bd9ab
  /* if it isn't a valid username, just bail out now */
Packit 6bd9ab
  if (!isvalidname(uid))
Packit 6bd9ab
  {
Packit 6bd9ab
    if (rcp != NULL)
Packit 6bd9ab
      *rcp = LDAP_INVALID_SYNTAX;
Packit 6bd9ab
    return NULL;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* set up attributes (we don't need much) */
Packit 6bd9ab
  attrs[0] = attmap_passwd_uid;
Packit 6bd9ab
  attrs[1] = attmap_passwd_uidNumber;
Packit 6bd9ab
  attrs[2] = NULL;
Packit 6bd9ab
  /* we have to look up the entry */
Packit 6bd9ab
  mkfilter_passwd_byname(uid, filter, sizeof(filter));
Packit 6bd9ab
  for (i = 0; (i < NSS_LDAP_CONFIG_MAX_BASES) && ((base = passwd_bases[i]) != NULL); i++)
Packit 6bd9ab
  {
Packit 6bd9ab
    search = myldap_search(session, base, passwd_scope, filter, attrs, rcp);
Packit 6bd9ab
    if (search == NULL)
Packit 6bd9ab
    {
Packit 6bd9ab
      if ((rcp != NULL) && (*rcp == LDAP_SUCCESS))
Packit 6bd9ab
        *rcp = LDAP_NO_SUCH_OBJECT;
Packit 6bd9ab
      return NULL;
Packit 6bd9ab
    }
Packit 6bd9ab
    entry = myldap_get_entry(search, rcp);
Packit 6bd9ab
    if ((entry != NULL) && (entry_has_valid_uid(entry)))
Packit 6bd9ab
      return entry;
Packit 6bd9ab
  }
Packit 6bd9ab
  if ((rcp != NULL) && (*rcp == LDAP_SUCCESS))
Packit 6bd9ab
    *rcp = LDAP_NO_SUCH_OBJECT;
Packit 6bd9ab
  return NULL;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
char *uid2dn(MYLDAP_SESSION *session, const char *uid, char *buf, size_t buflen)
Packit 6bd9ab
{
Packit 6bd9ab
  MYLDAP_ENTRY *entry;
Packit 6bd9ab
  /* look up the entry */
Packit 6bd9ab
  entry = uid2entry(session, uid, NULL);
Packit 6bd9ab
  if (entry == NULL)
Packit 6bd9ab
    return NULL;
Packit 6bd9ab
  /* get DN */
Packit 6bd9ab
  return myldap_cpy_dn(entry, buf, buflen);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
#ifndef NSS_FLAVOUR_GLIBC
Packit 6bd9ab
/* only check nsswitch.conf for glibc */
Packit 6bd9ab
#define check_nsswitch_reload()
Packit 6bd9ab
#define shadow_uses_ldap() (1)
Packit 6bd9ab
#endif /* NSS_FLAVOUR_GLIBC */
Packit 6bd9ab
Packit 6bd9ab
/* the maximum number of uidNumber attributes per entry */
Packit 6bd9ab
#define MAXUIDS_PER_ENTRY 5
Packit 6bd9ab
Packit 6bd9ab
static int write_passwd(TFILE *fp, MYLDAP_ENTRY *entry, const char *requser,
Packit 6bd9ab
                        const uid_t *requid, uid_t calleruid)
Packit 6bd9ab
{
Packit 6bd9ab
  int32_t tmpint32;
Packit 6bd9ab
  const char **tmpvalues;
Packit 6bd9ab
  char *tmp;
Packit 6bd9ab
  const char **usernames;
Packit 6bd9ab
  const char *passwd;
Packit 6bd9ab
  uid_t uids[MAXUIDS_PER_ENTRY];
Packit 6bd9ab
  int numuids;
Packit 6bd9ab
  char gidbuf[32];
Packit 6bd9ab
  gid_t gid;
Packit 6bd9ab
  char gecos[1024];
Packit 6bd9ab
  char homedir[256];
Packit 6bd9ab
  char shell[64];
Packit 6bd9ab
  char passbuffer[BUFLEN_PASSWORDHASH];
Packit 6bd9ab
  int i, j;
Packit 6bd9ab
  /* get the usernames for this entry */
Packit 6bd9ab
  usernames = myldap_get_values(entry, attmap_passwd_uid);
Packit 6bd9ab
  if ((usernames == NULL) || (usernames[0] == NULL))
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_WARNING, "%s: %s: missing",
Packit 6bd9ab
            myldap_get_dn(entry), attmap_passwd_uid);
Packit 6bd9ab
    return 0;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* if we are using shadow maps and this entry looks like it would return
Packit 6bd9ab
     shadow information, make the passwd entry indicate it */
Packit 6bd9ab
  if (myldap_has_objectclass(entry, "shadowAccount") && nsswitch_shadow_uses_ldap())
Packit 6bd9ab
  {
Packit 6bd9ab
    passwd = "x";
Packit 6bd9ab
  }
Packit 6bd9ab
  else
Packit 6bd9ab
  {
Packit 6bd9ab
    passwd = get_userpassword(entry, attmap_passwd_userPassword,
Packit 6bd9ab
                              passbuffer, sizeof(passbuffer));
Packit 6bd9ab
    if ((passwd == NULL) || (calleruid != 0))
Packit 6bd9ab
      passwd = default_passwd_userPassword;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* get the uids for this entry */
Packit 6bd9ab
  if (requid != NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    uids[0] = *requid;
Packit 6bd9ab
    numuids = 1;
Packit 6bd9ab
  }
Packit 6bd9ab
  else
Packit 6bd9ab
  {
Packit 6bd9ab
    tmpvalues = myldap_get_values_len(entry, attmap_passwd_uidNumber);
Packit 6bd9ab
    if ((tmpvalues == NULL) || (tmpvalues[0] == NULL))
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_WARNING, "%s: %s: missing",
Packit 6bd9ab
              myldap_get_dn(entry), attmap_passwd_uidNumber);
Packit 6bd9ab
      return 0;
Packit 6bd9ab
    }
Packit 6bd9ab
    for (numuids = 0; (numuids < MAXUIDS_PER_ENTRY) && (tmpvalues[numuids] != NULL); numuids++)
Packit 6bd9ab
    {
Packit 6bd9ab
      if (uidSid != NULL)
Packit 6bd9ab
        uids[numuids] = (uid_t)binsid2id(tmpvalues[numuids]);
Packit 6bd9ab
      else
Packit 6bd9ab
      {
Packit 6bd9ab
        errno = 0;
Packit 6bd9ab
        uids[numuids] = strtouid(tmpvalues[numuids], &tmp, 10);
Packit 6bd9ab
        if ((*(tmpvalues[numuids]) == '\0') || (*tmp != '\0'))
Packit 6bd9ab
        {
Packit 6bd9ab
          log_log(LOG_WARNING, "%s: %s: non-numeric",
Packit 6bd9ab
                  myldap_get_dn(entry), attmap_passwd_uidNumber);
Packit 6bd9ab
          return 0;
Packit 6bd9ab
        }
Packit 6bd9ab
        else if ((errno != 0) || (strchr(tmpvalues[numuids], '-') != NULL))
Packit 6bd9ab
        {
Packit 6bd9ab
          log_log(LOG_WARNING, "%s: %s: out of range",
Packit 6bd9ab
                  myldap_get_dn(entry), attmap_passwd_uidNumber);
Packit 6bd9ab
          return 0;
Packit 6bd9ab
        }
Packit 6bd9ab
      }
Packit 6bd9ab
      uids[numuids] += nslcd_cfg->nss_uid_offset;
Packit 6bd9ab
      if (uids[numuids] < nslcd_cfg->nss_min_uid)
Packit 6bd9ab
      {
Packit 6bd9ab
          log_log(LOG_DEBUG, "%s: %s: less than nss_min_uid",
Packit 6bd9ab
                  myldap_get_dn(entry), attmap_passwd_uidNumber);
Packit 6bd9ab
      }
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* get the gid for this entry */
Packit 6bd9ab
  if (gidSid != NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    tmpvalues = myldap_get_values_len(entry, attmap_passwd_gidNumber);
Packit 6bd9ab
    if ((tmpvalues == NULL) || (tmpvalues[0] == NULL))
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_WARNING, "%s: %s: missing",
Packit 6bd9ab
              myldap_get_dn(entry), attmap_passwd_gidNumber);
Packit 6bd9ab
      return 0;
Packit 6bd9ab
    }
Packit 6bd9ab
    gid = (gid_t)binsid2id(tmpvalues[0]);
Packit 6bd9ab
  }
Packit 6bd9ab
  else
Packit 6bd9ab
  {
Packit 6bd9ab
    attmap_get_value(entry, attmap_passwd_gidNumber, gidbuf, sizeof(gidbuf));
Packit 6bd9ab
    if (gidbuf[0] == '\0')
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_WARNING, "%s: %s: missing",
Packit 6bd9ab
              myldap_get_dn(entry), attmap_passwd_gidNumber);
Packit 6bd9ab
      return 0;
Packit 6bd9ab
    }
Packit 6bd9ab
    errno = 0;
Packit 6bd9ab
    gid = strtogid(gidbuf, &tmp, 10);
Packit 6bd9ab
    if ((gidbuf[0] == '\0') || (*tmp != '\0'))
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_WARNING, "%s: %s: non-numeric",
Packit 6bd9ab
              myldap_get_dn(entry), attmap_passwd_gidNumber);
Packit 6bd9ab
      return 0;
Packit 6bd9ab
    }
Packit 6bd9ab
    else if ((errno != 0) || (strchr(gidbuf, '-') != NULL))
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_WARNING, "%s: %s: out of range",
Packit 6bd9ab
              myldap_get_dn(entry), attmap_passwd_gidNumber);
Packit 6bd9ab
      return 0;
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  gid += nslcd_cfg->nss_gid_offset;
Packit 6bd9ab
  /* get the gecos for this entry */
Packit 6bd9ab
  attmap_get_value(entry, attmap_passwd_gecos, gecos, sizeof(gecos));
Packit 6bd9ab
  /* get the home directory for this entry */
Packit 6bd9ab
  attmap_get_value(entry, attmap_passwd_homeDirectory, homedir, sizeof(homedir));
Packit 6bd9ab
  if (homedir[0] == '\0')
Packit 6bd9ab
    log_log(LOG_WARNING, "%s: %s: missing",
Packit 6bd9ab
            myldap_get_dn(entry), attmap_passwd_homeDirectory);
Packit 6bd9ab
  /* get the shell for this entry */
Packit 6bd9ab
  attmap_get_value(entry, attmap_passwd_loginShell, shell, sizeof(shell));
Packit 6bd9ab
  /* write the entries */
Packit 6bd9ab
  for (i = 0; usernames[i] != NULL; i++)
Packit 6bd9ab
  {
Packit 6bd9ab
    if ((requser == NULL) || (STR_CMP(requser, usernames[i]) == 0))
Packit 6bd9ab
    {
Packit 6bd9ab
      if (!isvalidname(usernames[i]))
Packit 6bd9ab
      {
Packit 6bd9ab
        log_log(LOG_WARNING, "%s: %s: denied by validnames option",
Packit 6bd9ab
                myldap_get_dn(entry), attmap_passwd_uid);
Packit 6bd9ab
      }
Packit 6bd9ab
      else
Packit 6bd9ab
      {
Packit 6bd9ab
        for (j = 0; j < numuids; j++)
Packit 6bd9ab
        {
Packit 6bd9ab
          if (uids[j] >= nslcd_cfg->nss_min_uid)
Packit 6bd9ab
          {
Packit 6bd9ab
            WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
Packit 6bd9ab
            WRITE_STRING(fp, usernames[i]);
Packit 6bd9ab
            WRITE_STRING(fp, passwd);
Packit 6bd9ab
            WRITE_INT32(fp, uids[j]);
Packit 6bd9ab
            WRITE_INT32(fp, gid);
Packit 6bd9ab
            WRITE_STRING(fp, gecos);
Packit 6bd9ab
            WRITE_STRING(fp, homedir);
Packit 6bd9ab
            WRITE_STRING(fp, shell);
Packit 6bd9ab
          }
Packit 6bd9ab
        }
Packit 6bd9ab
      }
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  return 0;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
NSLCD_HANDLE_UID(
Packit 6bd9ab
  passwd, byname, NSLCD_ACTION_PASSWD_BYNAME,
Packit 6bd9ab
  char name[BUFLEN_NAME];
Packit 6bd9ab
  char filter[BUFLEN_FILTER];
Packit 6bd9ab
  READ_STRING(fp, name);
Packit 6bd9ab
  log_setrequest("passwd=\"%s\"", name);
Packit 6bd9ab
  if (!isvalidname(name))
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_WARNING, "request denied by validnames option");
Packit 6bd9ab
    return -1;
Packit 6bd9ab
  }
Packit 6bd9ab
  nsswitch_check_reload();,
Packit 6bd9ab
  mkfilter_passwd_byname(name, filter, sizeof(filter)),
Packit 6bd9ab
  write_passwd(fp, entry, name, NULL, calleruid)
Packit 6bd9ab
)
Packit 6bd9ab
Packit 6bd9ab
NSLCD_HANDLE_UID(
Packit 6bd9ab
  passwd, byuid, NSLCD_ACTION_PASSWD_BYUID,
Packit 6bd9ab
  uid_t uid;
Packit 6bd9ab
  char filter[BUFLEN_FILTER];
Packit 6bd9ab
  READ_INT32(fp, uid);
Packit 6bd9ab
  log_setrequest("passwd=%lu", (unsigned long int)uid);
Packit 6bd9ab
  if (uid < nslcd_cfg->nss_min_uid)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_DEBUG, "request ignored by nss_min_uid option");
Packit 6bd9ab
    /* return an empty result */
Packit 6bd9ab
    WRITE_INT32(fp, NSLCD_VERSION);
Packit 6bd9ab
    WRITE_INT32(fp, NSLCD_ACTION_PASSWD_BYUID);
Packit 6bd9ab
    WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
    return 0;
Packit 6bd9ab
  }
Packit 6bd9ab
  nsswitch_check_reload();,
Packit 6bd9ab
  mkfilter_passwd_byuid(uid, filter, sizeof(filter)),
Packit 6bd9ab
  write_passwd(fp, entry, NULL, &uid, calleruid)
Packit 6bd9ab
)
Packit 6bd9ab
Packit 6bd9ab
NSLCD_HANDLE_UID(
Packit 6bd9ab
  passwd, all, NSLCD_ACTION_PASSWD_ALL,
Packit 6bd9ab
  const char *filter;
Packit 6bd9ab
  log_setrequest("passwd(all)");
Packit 6bd9ab
  nsswitch_check_reload();,
Packit 6bd9ab
  (filter = passwd_filter, 0),
Packit 6bd9ab
  write_passwd(fp, entry, NULL, NULL, calleruid)
Packit 6bd9ab
)