Blame nslcd/pam.c

Packit 6bd9ab
/*
Packit 6bd9ab
   pam.c - pam processing routines
Packit 6bd9ab
Packit 6bd9ab
   Copyright (C) 2009 Howard Chu
Packit 6bd9ab
   Copyright (C) 2009-2017 Arthur de Jong
Packit 6bd9ab
   Copyright (C) 2015 Nokia Solutions and Networks
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 <string.h>
Packit 6bd9ab
#ifdef HAVE_STDINT_H
Packit 6bd9ab
#include <stdint.h>
Packit 6bd9ab
#endif /* HAVE_STDINT_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
#include "myldap.h"
Packit 6bd9ab
#include "cfg.h"
Packit 6bd9ab
#include "attmap.h"
Packit 6bd9ab
#include "common/dict.h"
Packit 6bd9ab
#include "common/expr.h"
Packit 6bd9ab
Packit 6bd9ab
static void search_var_add(DICT *dict, const char *name, const char *value)
Packit 6bd9ab
{
Packit 6bd9ab
  size_t sz;
Packit 6bd9ab
  char *escaped_value;
Packit 6bd9ab
  /* allocate memory for escaped string */
Packit 6bd9ab
  sz = ((strlen(value) + 8) * 120) / 100;
Packit 6bd9ab
  escaped_value = (char *)malloc(sz);
Packit 6bd9ab
  if (escaped_value == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_CRIT, "search_var_add(): malloc() failed to allocate memory");
Packit 6bd9ab
    return;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* perform escaping of the value */
Packit 6bd9ab
  if (myldap_escape(value, escaped_value, sz))
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "search_var_add(): escaped_value buffer too small");
Packit 6bd9ab
    free(escaped_value);
Packit 6bd9ab
    return;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* add to dict */
Packit 6bd9ab
  dict_put(dict, name, escaped_value);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* build a dictionary with variables that can be used in searches */
Packit 6bd9ab
static DICT *search_vars_new(const char *dn, const char *username,
Packit 6bd9ab
                             const char *service, const char *ruser,
Packit 6bd9ab
                             const char *rhost, const char *tty)
Packit 6bd9ab
{
Packit 6bd9ab
  char hostname[BUFLEN_HOSTNAME];
Packit 6bd9ab
  /* allocating this on the stack is OK because search_var_add()
Packit 6bd9ab
     will allocate new memory for the value */
Packit 6bd9ab
  const char *fqdn;
Packit 6bd9ab
  DICT *dict;
Packit 6bd9ab
  dict = dict_new();
Packit 6bd9ab
  if (dict == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_CRIT, "search_vars_new(): dict_new() failed to allocate memory");
Packit 6bd9ab
    return NULL;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* NOTE: any variables added here also need to be added to
Packit 6bd9ab
           cfg.c:check_search_variables() */
Packit 6bd9ab
  search_var_add(dict, "username", username);
Packit 6bd9ab
  search_var_add(dict, "service", service);
Packit 6bd9ab
  search_var_add(dict, "ruser", ruser);
Packit 6bd9ab
  search_var_add(dict, "rhost", rhost);
Packit 6bd9ab
  search_var_add(dict, "tty", tty);
Packit 6bd9ab
  if (gethostname(hostname, sizeof(hostname)) == 0)
Packit 6bd9ab
    search_var_add(dict, "hostname", hostname);
Packit 6bd9ab
  if ((fqdn = getfqdn()) != NULL)
Packit 6bd9ab
    search_var_add(dict, "fqdn", fqdn);
Packit 6bd9ab
  search_var_add(dict, "dn", dn);
Packit 6bd9ab
  search_var_add(dict, "uid", username);
Packit 6bd9ab
  return dict;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static void search_vars_free(DICT *dict)
Packit 6bd9ab
{
Packit 6bd9ab
  int i;
Packit 6bd9ab
  const char **keys;
Packit 6bd9ab
  void *value;
Packit 6bd9ab
  /* go over all keys and free all the values
Packit 6bd9ab
     (they were allocated in search_var_add) */
Packit 6bd9ab
  /* loop over dictionary contents */
Packit 6bd9ab
  keys = dict_keys(dict);
Packit 6bd9ab
  for (i = 0; keys[i] != NULL; i++)
Packit 6bd9ab
  {
Packit 6bd9ab
    value = dict_get(dict, keys[i]);
Packit 6bd9ab
    if (value)
Packit 6bd9ab
      free(value);
Packit 6bd9ab
  }
Packit 6bd9ab
  free(keys);
Packit 6bd9ab
  /* after this values from the dict should obviously no longer be used */
Packit 6bd9ab
  dict_free(dict);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static const char *search_var_get(const char *name, void *expander_attr)
Packit 6bd9ab
{
Packit 6bd9ab
  DICT *dict = (DICT *)expander_attr;
Packit 6bd9ab
  return (const char *)dict_get(dict, name);
Packit 6bd9ab
  /* TODO: if not set use entry to get attribute name (entry can be an
Packit 6bd9ab
           element in the dict) */
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* search all search bases using the provided filter */
Packit 6bd9ab
static int do_searches(MYLDAP_SESSION *session, const char *option,
Packit 6bd9ab
                       const char *filter)
Packit 6bd9ab
{
Packit 6bd9ab
  int i;
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  const char *base;
Packit 6bd9ab
  static const char *attrs[2];
Packit 6bd9ab
  MYLDAP_SEARCH *search;
Packit 6bd9ab
  MYLDAP_ENTRY *entry;
Packit 6bd9ab
  /* prepare the search */
Packit 6bd9ab
  attrs[0] = "dn";
Packit 6bd9ab
  attrs[1] = NULL;
Packit 6bd9ab
  /* perform a search for each search base */
Packit 6bd9ab
  log_log(LOG_DEBUG, "trying %s \"%s\"", option, filter);
Packit 6bd9ab
  for (i = 0; (base = nslcd_cfg->bases[i]) != NULL; i++)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* do the LDAP search */
Packit 6bd9ab
    search = myldap_search(session, base, LDAP_SCOPE_SUBTREE, filter, attrs, &rc);
Packit 6bd9ab
    if (search == NULL)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_ERR, "%s \"%s\" failed: %s",
Packit 6bd9ab
              option, filter, ldap_err2string(rc));
Packit 6bd9ab
      return rc;
Packit 6bd9ab
    }
Packit 6bd9ab
    /* try to get an entry */
Packit 6bd9ab
    entry = myldap_get_entry(search, &rc);
Packit 6bd9ab
    if (entry != NULL)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_DEBUG, "%s found \"%s\"", option, myldap_get_dn(entry));
Packit 6bd9ab
      return LDAP_SUCCESS;
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  log_log(LOG_ERR, "%s \"%s\" found no matches", option, filter);
Packit 6bd9ab
  if (rc == LDAP_SUCCESS)
Packit 6bd9ab
    rc = LDAP_NO_SUCH_OBJECT;
Packit 6bd9ab
  return rc;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* set up a connection and try to bind with the specified DN and password,
Packit 6bd9ab
   returns an LDAP result code */
Packit 6bd9ab
static int try_bind(const char *userdn, const char *password,
Packit 6bd9ab
                    const char *username, const char *service,
Packit 6bd9ab
                    const char *ruser, const char *rhost, const char *tty,
Packit 6bd9ab
                    int *authzrc, char *authzmsg, size_t authzmsgsz)
Packit 6bd9ab
{
Packit 6bd9ab
  MYLDAP_SESSION *session;
Packit 6bd9ab
  MYLDAP_SEARCH *search;
Packit 6bd9ab
  MYLDAP_ENTRY *entry;
Packit 6bd9ab
  static const char *attrs[2];
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  const char *msg;
Packit 6bd9ab
  DICT *dict;
Packit 6bd9ab
  char filter[BUFLEN_FILTER];
Packit 6bd9ab
  const char *res;
Packit 6bd9ab
  /* set up a new connection */
Packit 6bd9ab
  session = myldap_create_session();
Packit 6bd9ab
  if (session == NULL)
Packit 6bd9ab
    return LDAP_UNAVAILABLE;
Packit 6bd9ab
  /* perform a BIND operation with user credentials */
Packit 6bd9ab
  rc = myldap_bind(session, userdn, password, authzrc, &msg;;
Packit 6bd9ab
  if (rc == LDAP_SUCCESS)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* perform a search to trigger the BIND operation */
Packit 6bd9ab
    attrs[0] = "dn";
Packit 6bd9ab
    attrs[1] = NULL;
Packit 6bd9ab
    if (strcasecmp(nslcd_cfg->pam_authc_search, "BASE") == 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      /* do a simple search to check userdn existence */
Packit 6bd9ab
      search = myldap_search(session, userdn, LDAP_SCOPE_BASE,
Packit 6bd9ab
                             "(objectClass=*)", attrs, &rc);
Packit 6bd9ab
      if ((search == NULL) && (rc == LDAP_SUCCESS))
Packit 6bd9ab
        rc = LDAP_LOCAL_ERROR;
Packit 6bd9ab
      if (rc == LDAP_SUCCESS)
Packit 6bd9ab
      {
Packit 6bd9ab
        entry = myldap_get_entry(search, &rc);
Packit 6bd9ab
        if ((entry == NULL) && (rc == LDAP_SUCCESS))
Packit 6bd9ab
          rc = LDAP_NO_RESULTS_RETURNED;
Packit 6bd9ab
      }
Packit 6bd9ab
    }
Packit 6bd9ab
    else if (strcasecmp(nslcd_cfg->pam_authc_search, "NONE") != 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      /* build the search filter */
Packit 6bd9ab
      dict = search_vars_new(userdn, username, service, ruser, rhost, tty);
Packit 6bd9ab
      if (dict == NULL)
Packit 6bd9ab
      {
Packit 6bd9ab
        myldap_session_close(session);
Packit 6bd9ab
        return LDAP_LOCAL_ERROR;
Packit 6bd9ab
      }
Packit 6bd9ab
      res = expr_parse(nslcd_cfg->pam_authc_search, filter, sizeof(filter),
Packit 6bd9ab
                       search_var_get, (void *)dict);
Packit 6bd9ab
      if (res == NULL)
Packit 6bd9ab
      {
Packit 6bd9ab
        search_vars_free(dict);
Packit 6bd9ab
        myldap_session_close(session);
Packit 6bd9ab
        log_log(LOG_ERR, "invalid pam_authc_search \"%s\"",
Packit 6bd9ab
                nslcd_cfg->pam_authc_search);
Packit 6bd9ab
        return LDAP_LOCAL_ERROR;
Packit 6bd9ab
      }
Packit 6bd9ab
      /* perform a search for each search base */
Packit 6bd9ab
      rc = do_searches(session, "pam_authc_search", filter);
Packit 6bd9ab
      /* free search variables */
Packit 6bd9ab
      search_vars_free(dict);
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* log any authentication, search or authorsiation messages */
Packit 6bd9ab
  if (rc != LDAP_SUCCESS)
Packit 6bd9ab
    log_log(LOG_WARNING, "%s: %s", userdn, ldap_err2string(rc));
Packit 6bd9ab
  if ((msg != NULL) && (msg[0] != '\0'))
Packit 6bd9ab
  {
Packit 6bd9ab
    mysnprintf(authzmsg, authzmsgsz - 1, "%s", msg);
Packit 6bd9ab
    log_log(LOG_WARNING, "%s: %s", userdn, authzmsg);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* close the session */
Packit 6bd9ab
  myldap_session_close(session);
Packit 6bd9ab
  /* return results */
Packit 6bd9ab
  return rc;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* ensure that both userdn and username are filled in from the entry,
Packit 6bd9ab
   returns an LDAP result code */
Packit 6bd9ab
static MYLDAP_ENTRY *validate_user(MYLDAP_SESSION *session,
Packit 6bd9ab
                                   char *username, int *rcp)
Packit 6bd9ab
{
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  MYLDAP_ENTRY *entry = NULL;
Packit 6bd9ab
  /* check username for validity */
Packit 6bd9ab
  if (!isvalidname(username))
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_WARNING, "request denied by validnames option");
Packit 6bd9ab
    *rcp = LDAP_NO_SUCH_OBJECT;
Packit 6bd9ab
    return NULL;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* get the user entry based on the username */
Packit 6bd9ab
  entry = uid2entry(session, username, &rc);
Packit 6bd9ab
  if (entry == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    if (rc == LDAP_SUCCESS)
Packit 6bd9ab
      rc = LDAP_NO_SUCH_OBJECT;
Packit 6bd9ab
    log_log(LOG_DEBUG, "\"%s\": user not found: %s", username, ldap_err2string(rc));
Packit 6bd9ab
    *rcp = rc;
Packit 6bd9ab
  }
Packit 6bd9ab
  return entry;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* update the username value from the entry if needed */
Packit 6bd9ab
static void update_username(MYLDAP_ENTRY *entry, char *username,
Packit 6bd9ab
                            size_t username_len)
Packit 6bd9ab
{
Packit 6bd9ab
  const char **values;
Packit 6bd9ab
  const char *value;
Packit 6bd9ab
  /* get the "real" username */
Packit 6bd9ab
  value = myldap_get_rdn_value(entry, attmap_passwd_uid);
Packit 6bd9ab
  if (value == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* get the username from the uid attribute */
Packit 6bd9ab
    values = myldap_get_values(entry, attmap_passwd_uid);
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_uid);
Packit 6bd9ab
      return;
Packit 6bd9ab
    }
Packit 6bd9ab
    value = values[0];
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check the username */
Packit 6bd9ab
  if ((value == NULL) || !isvalidname(value) || strlen(value) >= username_len)
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
    return;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check if the username is different and update it if needed */
Packit 6bd9ab
  if (STR_CMP(username, value) != 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_INFO, "username changed from \"%s\" to \"%s\"",
Packit 6bd9ab
            username, value);
Packit 6bd9ab
    strcpy(username, value);
Packit 6bd9ab
  }
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static int check_shadow(MYLDAP_SESSION *session, const char *username,
Packit 6bd9ab
                        char *authzmsg, size_t authzmsgsz,
Packit 6bd9ab
                        int check_maxdays, int check_mindays)
Packit 6bd9ab
{
Packit 6bd9ab
  MYLDAP_ENTRY *entry = NULL;
Packit 6bd9ab
  long today, lastchangedate, mindays, maxdays, warndays, inactdays, expiredate;
Packit 6bd9ab
  unsigned long flag;
Packit 6bd9ab
  long daysleft, inactleft;
Packit 6bd9ab
  /* get the shadow entry */
Packit 6bd9ab
  entry = shadow_uid2entry(session, username, NULL);
Packit 6bd9ab
  if (entry == NULL)
Packit 6bd9ab
    return NSLCD_PAM_SUCCESS; /* no shadow entry found, nothing to check */
Packit 6bd9ab
  /* get today's date */
Packit 6bd9ab
  today = (long)(time(NULL) / (60 * 60 * 24));
Packit 6bd9ab
  /* get shadow information */
Packit 6bd9ab
  get_shadow_properties(entry, &lastchangedate, &mindays, &maxdays, &warndays,
Packit 6bd9ab
                        &inactdays, &expiredate, &flag;;
Packit 6bd9ab
  /* check account expiry date */
Packit 6bd9ab
  if ((expiredate != -1) && (today >= expiredate))
Packit 6bd9ab
  {
Packit 6bd9ab
    daysleft = today - expiredate;
Packit 6bd9ab
    mysnprintf(authzmsg, authzmsgsz - 1, "account expired %ld days ago",
Packit 6bd9ab
               daysleft);
Packit 6bd9ab
    log_log(LOG_WARNING, "%s: %s: %s",
Packit 6bd9ab
            myldap_get_dn(entry), attmap_shadow_shadowExpire, authzmsg);
Packit 6bd9ab
    return NSLCD_PAM_ACCT_EXPIRED;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* password expiration isn't interesting at this point because the user
Packit 6bd9ab
     may not have authenticated with a password and if he did that would be
Packit 6bd9ab
     checked in the authc phase */
Packit 6bd9ab
  if (check_maxdays)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* check lastchanged */
Packit 6bd9ab
    if (lastchangedate == 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      mysnprintf(authzmsg, authzmsgsz - 1, "need a new password");
Packit 6bd9ab
      log_log(LOG_WARNING, "%s: %s: %s",
Packit 6bd9ab
              myldap_get_dn(entry), attmap_shadow_shadowLastChange, authzmsg);
Packit 6bd9ab
      return NSLCD_PAM_NEW_AUTHTOK_REQD;
Packit 6bd9ab
    }
Packit 6bd9ab
    else if (today < lastchangedate)
Packit 6bd9ab
      log_log(LOG_WARNING, "%s: %s: password changed in the future",
Packit 6bd9ab
              myldap_get_dn(entry), attmap_shadow_shadowLastChange);
Packit 6bd9ab
    else if (maxdays != -1)
Packit 6bd9ab
    {
Packit 6bd9ab
      /* check maxdays */
Packit 6bd9ab
      daysleft = lastchangedate + maxdays - today;
Packit 6bd9ab
      if (daysleft == 0)
Packit 6bd9ab
        mysnprintf(authzmsg, authzmsgsz - 1, "password will expire today");
Packit 6bd9ab
      else if (daysleft < 0)
Packit 6bd9ab
        mysnprintf(authzmsg, authzmsgsz - 1, "password expired %ld days ago",
Packit 6bd9ab
                   -daysleft);
Packit 6bd9ab
      /* check inactdays */
Packit 6bd9ab
      if ((daysleft <= 0) && (inactdays != -1))
Packit 6bd9ab
      {
Packit 6bd9ab
        inactleft = lastchangedate + maxdays + inactdays - today;
Packit 6bd9ab
        if (inactleft == 0)
Packit 6bd9ab
          mysnprintf(authzmsg + strlen(authzmsg), authzmsgsz - strlen(authzmsg) - 1,
Packit 6bd9ab
                     ", account will be locked today");
Packit 6bd9ab
        else if (inactleft > 0)
Packit 6bd9ab
          mysnprintf(authzmsg + strlen(authzmsg), authzmsgsz - strlen(authzmsg) - 1,
Packit 6bd9ab
                     ", account will be locked in %ld days", inactleft);
Packit 6bd9ab
        else
Packit 6bd9ab
        {
Packit 6bd9ab
          mysnprintf(authzmsg + strlen(authzmsg), authzmsgsz - strlen(authzmsg) - 1,
Packit 6bd9ab
                     ", account locked %ld days ago", -inactleft);
Packit 6bd9ab
          log_log(LOG_WARNING, "%s: %s: %s", myldap_get_dn(entry),
Packit 6bd9ab
                  attmap_shadow_shadowInactive, authzmsg);
Packit 6bd9ab
          return NSLCD_PAM_AUTHTOK_EXPIRED;
Packit 6bd9ab
        }
Packit 6bd9ab
      }
Packit 6bd9ab
      if (daysleft <= 0)
Packit 6bd9ab
      {
Packit 6bd9ab
        /* log previously built message */
Packit 6bd9ab
        log_log(LOG_WARNING, "%s: %s: %s",
Packit 6bd9ab
                myldap_get_dn(entry), attmap_shadow_shadowMax, authzmsg);
Packit 6bd9ab
        return NSLCD_PAM_NEW_AUTHTOK_REQD;
Packit 6bd9ab
      }
Packit 6bd9ab
      /* check warndays */
Packit 6bd9ab
      if ((warndays > 0) && (daysleft <= warndays))
Packit 6bd9ab
      {
Packit 6bd9ab
        mysnprintf(authzmsg, authzmsgsz - 1,
Packit 6bd9ab
                   "password will expire in %ld days", daysleft);
Packit 6bd9ab
        log_log(LOG_WARNING, "%s: %s: %s",
Packit 6bd9ab
                myldap_get_dn(entry), attmap_shadow_shadowWarning, authzmsg);
Packit 6bd9ab
      }
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  if (check_mindays)
Packit 6bd9ab
  {
Packit 6bd9ab
    daysleft = lastchangedate + mindays - today;
Packit 6bd9ab
    if ((mindays != -1) && (daysleft > 0))
Packit 6bd9ab
    {
Packit 6bd9ab
      mysnprintf(authzmsg, authzmsgsz - 1,
Packit 6bd9ab
                 "password cannot be changed for another %ld days", daysleft);
Packit 6bd9ab
      log_log(LOG_WARNING, "%s: %s: %s",
Packit 6bd9ab
              myldap_get_dn(entry), attmap_shadow_shadowMin, authzmsg);
Packit 6bd9ab
      return NSLCD_PAM_AUTHTOK_ERR;
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  return NSLCD_PAM_SUCCESS;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* check authentication credentials of the user */
Packit 6bd9ab
int nslcd_pam_authc(TFILE *fp, MYLDAP_SESSION *session, uid_t calleruid)
Packit 6bd9ab
{
Packit 6bd9ab
  int32_t tmpint32;
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  char username[BUFLEN_NAME], service[BUFLEN_NAME], ruser[BUFLEN_NAME], rhost[BUFLEN_HOSTNAME], tty[64];
Packit 6bd9ab
  char password[BUFLEN_PASSWORD];
Packit 6bd9ab
  const char *userdn;
Packit 6bd9ab
  MYLDAP_ENTRY *entry;
Packit 6bd9ab
  int authzrc = NSLCD_PAM_SUCCESS;
Packit 6bd9ab
  char authzmsg[BUFLEN_MESSAGE];
Packit 6bd9ab
  authzmsg[0] = '\0';
Packit 6bd9ab
  /* read request parameters */
Packit 6bd9ab
  READ_STRING(fp, username);
Packit 6bd9ab
  READ_STRING(fp, service);
Packit 6bd9ab
  READ_STRING(fp, ruser);
Packit 6bd9ab
  READ_STRING(fp, rhost);
Packit 6bd9ab
  READ_STRING(fp, tty);
Packit 6bd9ab
  READ_STRING(fp, password);
Packit 6bd9ab
  /* log call */
Packit 6bd9ab
  log_setrequest("authc=\"%s\"", username);
Packit 6bd9ab
  log_log(LOG_DEBUG, "nslcd_pam_authc(\"%s\",\"%s\",\"%s\")",
Packit 6bd9ab
          username, service, *password ? "***" : "");
Packit 6bd9ab
  /* write the response header */
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_VERSION);
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_ACTION_PAM_AUTHC);
Packit 6bd9ab
  /* if the username is blank and rootpwmoddn is configured, try to
Packit 6bd9ab
     authenticate as administrator, otherwise validate request as usual */
Packit 6bd9ab
  if (*username == '\0')
Packit 6bd9ab
  {
Packit 6bd9ab
    if (nslcd_cfg->rootpwmoddn == NULL)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_NOTICE, "rootpwmoddn not configured");
Packit 6bd9ab
      /* we break the protocol */
Packit 6bd9ab
      memset(password, 0, sizeof(password));
Packit 6bd9ab
      return -1;
Packit 6bd9ab
    }
Packit 6bd9ab
    userdn = nslcd_cfg->rootpwmoddn;
Packit 6bd9ab
    /* if the caller is root we will allow the use of the rootpwmodpw option */
Packit 6bd9ab
    if ((*password == '\0') && (calleruid == 0) && (nslcd_cfg->rootpwmodpw != NULL))
Packit 6bd9ab
    {
Packit 6bd9ab
      if (strlen(nslcd_cfg->rootpwmodpw) >= sizeof(password))
Packit 6bd9ab
      {
Packit 6bd9ab
        log_log(LOG_ERR, "nslcd_pam_authc(): rootpwmodpw will not fit in password");
Packit 6bd9ab
        memset(password, 0, sizeof(password));
Packit 6bd9ab
        return -1;
Packit 6bd9ab
      }
Packit 6bd9ab
      strcpy(password, nslcd_cfg->rootpwmodpw);
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  else
Packit 6bd9ab
  {
Packit 6bd9ab
    /* try normal authentication, lookup the user entry */
Packit 6bd9ab
    entry = validate_user(session, username, &rc);
Packit 6bd9ab
    if (entry == NULL)
Packit 6bd9ab
    {
Packit 6bd9ab
      /* for user not found we just say no result */
Packit 6bd9ab
      if (rc == LDAP_NO_SUCH_OBJECT)
Packit 6bd9ab
      {
Packit 6bd9ab
        WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
      }
Packit 6bd9ab
      memset(password, 0, sizeof(password));
Packit 6bd9ab
      return -1;
Packit 6bd9ab
    }
Packit 6bd9ab
    userdn = myldap_get_dn(entry);
Packit 6bd9ab
    update_username(entry, username, sizeof(username));
Packit 6bd9ab
  }
Packit 6bd9ab
  /* try authentication */
Packit 6bd9ab
  rc = try_bind(userdn, password, username, service, ruser, rhost, tty,
Packit 6bd9ab
                &authzrc, authzmsg, sizeof(authzmsg));
Packit 6bd9ab
  if (rc == LDAP_SUCCESS)
Packit 6bd9ab
    log_log(LOG_DEBUG, "bind successful");
Packit 6bd9ab
  /* map result code */
Packit 6bd9ab
  switch (rc)
Packit 6bd9ab
  {
Packit 6bd9ab
    case LDAP_SUCCESS:             rc = NSLCD_PAM_SUCCESS;  break;
Packit 6bd9ab
    case LDAP_INVALID_CREDENTIALS: rc = NSLCD_PAM_AUTH_ERR; break;
Packit 6bd9ab
    default:                       rc = NSLCD_PAM_AUTH_ERR;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* perform shadow attribute checks */
Packit 6bd9ab
  if ((*username != '\0') && (authzrc == NSLCD_PAM_SUCCESS))
Packit 6bd9ab
    authzrc = check_shadow(session, username, authzmsg, sizeof(authzmsg), 1, 0);
Packit 6bd9ab
  /* write response */
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
Packit 6bd9ab
  WRITE_INT32(fp, rc);
Packit 6bd9ab
  WRITE_STRING(fp, username);
Packit 6bd9ab
  WRITE_INT32(fp, authzrc);
Packit 6bd9ab
  WRITE_STRING(fp, authzmsg);
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
  memset(password, 0, sizeof(password));
Packit 6bd9ab
  return 0;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* perform an authorisation search, returns an LDAP status code */
Packit 6bd9ab
static int try_authz_search(MYLDAP_SESSION *session, const char *dn,
Packit 6bd9ab
                          const char *username, const char *service,
Packit 6bd9ab
                          const char *ruser, const char *rhost,
Packit 6bd9ab
                          const char *tty)
Packit 6bd9ab
{
Packit 6bd9ab
  DICT *dict = NULL;
Packit 6bd9ab
  char filter[BUFLEN_FILTER];
Packit 6bd9ab
  int rc = LDAP_SUCCESS;
Packit 6bd9ab
  const char *res;
Packit 6bd9ab
  int i;
Packit 6bd9ab
  /* go over all pam_authz_search options */
Packit 6bd9ab
  for (i = 0; (i < NSS_LDAP_CONFIG_MAX_AUTHZ_SEARCHES) && (nslcd_cfg->pam_authz_searches[i] != NULL); i++)
Packit 6bd9ab
  {
Packit 6bd9ab
    if (dict == NULL)
Packit 6bd9ab
    {
Packit 6bd9ab
      dict = search_vars_new(dn, username, service, ruser, rhost, tty);
Packit 6bd9ab
      if (dict == NULL)
Packit 6bd9ab
        return LDAP_LOCAL_ERROR;
Packit 6bd9ab
    }
Packit 6bd9ab
    /* build the search filter */
Packit 6bd9ab
    res = expr_parse(nslcd_cfg->pam_authz_searches[i],
Packit 6bd9ab
                     filter, sizeof(filter),
Packit 6bd9ab
                     search_var_get, (void *)dict);
Packit 6bd9ab
    if (res == NULL)
Packit 6bd9ab
    {
Packit 6bd9ab
      search_vars_free(dict);
Packit 6bd9ab
      log_log(LOG_ERR, "invalid pam_authz_search \"%s\"",
Packit 6bd9ab
              nslcd_cfg->pam_authz_searches[i]);
Packit 6bd9ab
      return LDAP_LOCAL_ERROR;
Packit 6bd9ab
    }
Packit 6bd9ab
    /* perform the actual searches on all bases */
Packit 6bd9ab
    rc = do_searches(session, "pam_authz_search", filter);
Packit 6bd9ab
    if (rc != LDAP_SUCCESS)
Packit 6bd9ab
      break;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* we went over all pam_authz_search entries */
Packit 6bd9ab
  if (dict != NULL)
Packit 6bd9ab
    search_vars_free(dict);
Packit 6bd9ab
  return rc;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* check authorisation of the user */
Packit 6bd9ab
int nslcd_pam_authz(TFILE *fp, MYLDAP_SESSION *session)
Packit 6bd9ab
{
Packit 6bd9ab
  int32_t tmpint32;
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  char username[BUFLEN_NAME], service[BUFLEN_NAME], ruser[BUFLEN_NAME], rhost[BUFLEN_HOSTNAME], tty[64];
Packit 6bd9ab
  MYLDAP_ENTRY *entry;
Packit 6bd9ab
  char authzmsg[BUFLEN_MESSAGE];
Packit 6bd9ab
  authzmsg[0] = '\0';
Packit 6bd9ab
  /* read request parameters */
Packit 6bd9ab
  READ_STRING(fp, username);
Packit 6bd9ab
  READ_STRING(fp, service);
Packit 6bd9ab
  READ_STRING(fp, ruser);
Packit 6bd9ab
  READ_STRING(fp, rhost);
Packit 6bd9ab
  READ_STRING(fp, tty);
Packit 6bd9ab
  /* log call */
Packit 6bd9ab
  log_setrequest("authz=\"%s\"", username);
Packit 6bd9ab
  log_log(LOG_DEBUG, "nslcd_pam_authz(\"%s\",\"%s\",\"%s\",\"%s\",\"%s\")",
Packit 6bd9ab
          username, service, ruser, rhost, tty);
Packit 6bd9ab
  /* write the response header */
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_VERSION);
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_ACTION_PAM_AUTHZ);
Packit 6bd9ab
  /* validate request */
Packit 6bd9ab
  entry = validate_user(session, username, &rc);
Packit 6bd9ab
  if (entry == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* for user not found we just say no result */
Packit 6bd9ab
    if (rc == LDAP_NO_SUCH_OBJECT)
Packit 6bd9ab
    {
Packit 6bd9ab
      WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
    }
Packit 6bd9ab
    return -1;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check authorisation search */
Packit 6bd9ab
  rc = try_authz_search(session, myldap_get_dn(entry), username, service, ruser,
Packit 6bd9ab
                      rhost, tty);
Packit 6bd9ab
  if (rc != LDAP_SUCCESS)
Packit 6bd9ab
  {
Packit 6bd9ab
    WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
Packit 6bd9ab
    WRITE_INT32(fp, NSLCD_PAM_PERM_DENIED);
Packit 6bd9ab
    WRITE_STRING(fp, "LDAP authorisation check failed");
Packit 6bd9ab
    WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
    return 0;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* perform shadow attribute checks */
Packit 6bd9ab
  rc = check_shadow(session, username, authzmsg, sizeof(authzmsg), 0, 0);
Packit 6bd9ab
  /* write response */
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
Packit 6bd9ab
  WRITE_INT32(fp, rc);
Packit 6bd9ab
  WRITE_STRING(fp, authzmsg);
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
  return 0;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
int nslcd_pam_sess_o(TFILE *fp, MYLDAP_SESSION UNUSED(*session))
Packit 6bd9ab
{
Packit 6bd9ab
  int32_t tmpint32;
Packit 6bd9ab
  char username[BUFLEN_NAME], service[BUFLEN_NAME], ruser[BUFLEN_NAME], rhost[BUFLEN_HOSTNAME], tty[64];
Packit 6bd9ab
  char sessionid[25];
Packit 6bd9ab
  static const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Packit 6bd9ab
                                 "abcdefghijklmnopqrstuvwxyz"
Packit 6bd9ab
                                 "01234567890";
Packit 6bd9ab
  unsigned int i;
Packit 6bd9ab
  /* read request parameters */
Packit 6bd9ab
  READ_STRING(fp, username);
Packit 6bd9ab
  READ_STRING(fp, service);
Packit 6bd9ab
  READ_STRING(fp, ruser);
Packit 6bd9ab
  READ_STRING(fp, rhost);
Packit 6bd9ab
  READ_STRING(fp, tty);
Packit 6bd9ab
  /* generate pseudo-random session id */
Packit 6bd9ab
  for (i = 0; i < (sizeof(sessionid) - 1); i++)
Packit 6bd9ab
    sessionid[i] = alphabet[rand() % (sizeof(alphabet) - 1)];
Packit 6bd9ab
  sessionid[i] = '\0';
Packit 6bd9ab
  /* log call */
Packit 6bd9ab
  log_setrequest("sess_o=\"%s\"", username);
Packit 6bd9ab
  log_log(LOG_DEBUG, "nslcd_pam_sess_o(\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"): %s",
Packit 6bd9ab
          username, service, tty, rhost, ruser, sessionid);
Packit 6bd9ab
  /* write the response header */
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_VERSION);
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_ACTION_PAM_SESS_O);
Packit 6bd9ab
  /* write response */
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
Packit 6bd9ab
  WRITE_STRING(fp, sessionid);
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
  return 0;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
int nslcd_pam_sess_c(TFILE *fp, MYLDAP_SESSION UNUSED(*session))
Packit 6bd9ab
{
Packit 6bd9ab
  int32_t tmpint32;
Packit 6bd9ab
  char username[BUFLEN_NAME], service[BUFLEN_NAME], ruser[BUFLEN_NAME], rhost[BUFLEN_HOSTNAME], tty[64];
Packit 6bd9ab
  char sessionid[64];
Packit 6bd9ab
  /* read request parameters */
Packit 6bd9ab
  READ_STRING(fp, username);
Packit 6bd9ab
  READ_STRING(fp, service);
Packit 6bd9ab
  READ_STRING(fp, ruser);
Packit 6bd9ab
  READ_STRING(fp, rhost);
Packit 6bd9ab
  READ_STRING(fp, tty);
Packit 6bd9ab
  READ_STRING(fp, sessionid);
Packit 6bd9ab
  /* log call */
Packit 6bd9ab
  log_setrequest("sess_c=\"%s\"", username);
Packit 6bd9ab
  log_log(LOG_DEBUG, "nslcd_pam_sess_c(\"%s\",\"%s\",%s)",
Packit 6bd9ab
          username, service, sessionid);
Packit 6bd9ab
  /* write the response header */
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_VERSION);
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_ACTION_PAM_SESS_C);
Packit 6bd9ab
  /* write response */
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
  return 0;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
extern const char *shadow_filter;
Packit 6bd9ab
Packit 6bd9ab
/* try to update the shadowLastChange attribute of the entry if possible */
Packit 6bd9ab
static int update_lastchange(MYLDAP_SESSION *session, const char *userdn)
Packit 6bd9ab
{
Packit 6bd9ab
  MYLDAP_SEARCH *search;
Packit 6bd9ab
  MYLDAP_ENTRY *entry;
Packit 6bd9ab
  static const char *attrs[3];
Packit 6bd9ab
  const char *attr;
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  const char **values;
Packit 6bd9ab
  LDAPMod mod, *mods[2];
Packit 6bd9ab
  char buffer[64], *strvals[2];
Packit 6bd9ab
  /* find the name of the attribute to use */
Packit 6bd9ab
  if ((attmap_shadow_shadowLastChange == NULL) || (attmap_shadow_shadowLastChange[0] == '\0'))
Packit 6bd9ab
    return LDAP_LOCAL_ERROR; /* attribute not mapped at all */
Packit 6bd9ab
  else if (strcmp(attmap_shadow_shadowLastChange, "\"${shadowLastChange:--1}\"") == 0)
Packit 6bd9ab
    attr = "shadowLastChange";
Packit 6bd9ab
  else if (attmap_shadow_shadowLastChange[0] == '\"')
Packit 6bd9ab
    return LDAP_LOCAL_ERROR; /* other expressions not supported for now */
Packit 6bd9ab
  else
Packit 6bd9ab
    attr = attmap_shadow_shadowLastChange;
Packit 6bd9ab
  /* set up the attributes we need */
Packit 6bd9ab
  attrs[0] = attmap_shadow_uid;
Packit 6bd9ab
  attrs[1] = attr;
Packit 6bd9ab
  attrs[2] = NULL;
Packit 6bd9ab
  /* find the entry to see if the attribute is present */
Packit 6bd9ab
  search = myldap_search(session, userdn, LDAP_SCOPE_BASE, shadow_filter, attrs, &rc);
Packit 6bd9ab
  if (search == NULL)
Packit 6bd9ab
    return rc;
Packit 6bd9ab
  entry = myldap_get_entry(search, &rc);
Packit 6bd9ab
  if (entry == NULL)
Packit 6bd9ab
    return rc;
Packit 6bd9ab
  values = myldap_get_values(entry, attr);
Packit 6bd9ab
  if ((values == NULL) || (values[0] == NULL) || (values[0][0] == '\0'))
Packit 6bd9ab
    return LDAP_NO_SUCH_ATTRIBUTE;
Packit 6bd9ab
  /* build the value for the new attribute */
Packit 6bd9ab
  if (strcasecmp(attr, "pwdLastSet") == 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* for AD we use another timestamp */
Packit 6bd9ab
    if (mysnprintf(buffer, sizeof(buffer), "%ld000000000",
Packit 6bd9ab
                   ((long int)time(NULL) / 100L + (134774L * 864L))))
Packit 6bd9ab
      return LDAP_LOCAL_ERROR;
Packit 6bd9ab
  }
Packit 6bd9ab
  else
Packit 6bd9ab
  {
Packit 6bd9ab
    /* time in days since Jan 1, 1970 */
Packit 6bd9ab
    if (mysnprintf(buffer, sizeof(buffer), "%ld",
Packit 6bd9ab
                   ((long int)(time(NULL) / (long int)(60 * 60 * 24)))))
Packit 6bd9ab
      return LDAP_LOCAL_ERROR;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* update the shadowLastChange attribute */
Packit 6bd9ab
  strvals[0] = buffer;
Packit 6bd9ab
  strvals[1] = NULL;
Packit 6bd9ab
  mod.mod_op = LDAP_MOD_REPLACE;
Packit 6bd9ab
  mod.mod_type = (char *)attr;
Packit 6bd9ab
  mod.mod_values = strvals;
Packit 6bd9ab
  mods[0] = &mod;
Packit 6bd9ab
  mods[1] = NULL;
Packit 6bd9ab
  rc = myldap_modify(session, userdn, mods);
Packit 6bd9ab
  if (rc != LDAP_SUCCESS)
Packit 6bd9ab
    log_log(LOG_WARNING, "%s: %s: modification failed: %s",
Packit 6bd9ab
            userdn, attr, ldap_err2string(rc));
Packit 6bd9ab
  else
Packit 6bd9ab
    log_log(LOG_DEBUG, "%s: %s: modification succeeded", userdn, attr);
Packit 6bd9ab
  return rc;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* perform an LDAP password modification, returns an LDAP status code */
Packit 6bd9ab
static int try_pwmod(MYLDAP_SESSION *oldsession,
Packit 6bd9ab
                     const char *binddn, const char *userdn,
Packit 6bd9ab
                     const char *oldpassword, const char *newpassword,
Packit 6bd9ab
                     char *authzmsg, size_t authzmsg_len)
Packit 6bd9ab
{
Packit 6bd9ab
  MYLDAP_SESSION *session;
Packit 6bd9ab
  char buffer[BUFLEN_MESSAGE];
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  /* set up a new connection */
Packit 6bd9ab
  session = myldap_create_session();
Packit 6bd9ab
  if (session == NULL)
Packit 6bd9ab
    return LDAP_UNAVAILABLE;
Packit 6bd9ab
  /* perform a BIND operation */
Packit 6bd9ab
  rc = myldap_bind(session, binddn, oldpassword, NULL, NULL);
Packit 6bd9ab
  if (rc == LDAP_SUCCESS)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* if doing password modification as admin, don't pass old password along */
Packit 6bd9ab
    if ((nslcd_cfg->rootpwmoddn != NULL) &&
Packit 6bd9ab
        (strcmp(binddn, nslcd_cfg->rootpwmoddn) == 0))
Packit 6bd9ab
      oldpassword = NULL;
Packit 6bd9ab
    /* perform password modification */
Packit 6bd9ab
    rc = myldap_passwd(session, userdn, oldpassword, newpassword);
Packit 6bd9ab
    if (rc == LDAP_SUCCESS)
Packit 6bd9ab
    {
Packit 6bd9ab
      /* try to update the shadowLastChange attribute */
Packit 6bd9ab
      if (update_lastchange(session, userdn) != LDAP_SUCCESS)
Packit 6bd9ab
        /* retry with the normal session */
Packit 6bd9ab
        (void)update_lastchange(oldsession, userdn);
Packit 6bd9ab
    }
Packit 6bd9ab
    else
Packit 6bd9ab
    {
Packit 6bd9ab
      /* get a diagnostic or error message */
Packit 6bd9ab
      if ((myldap_error_message(session, rc, buffer, sizeof(buffer)) == LDAP_SUCCESS) &&
Packit 6bd9ab
          (buffer[0] != '\0'))
Packit 6bd9ab
        mysnprintf(authzmsg, authzmsg_len - 1, "password change failed: %s",
Packit 6bd9ab
                   buffer);
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* close the session */
Packit 6bd9ab
  myldap_session_close(session);
Packit 6bd9ab
  /* return */
Packit 6bd9ab
  return rc;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
int nslcd_pam_pwmod(TFILE *fp, MYLDAP_SESSION *session, uid_t calleruid)
Packit 6bd9ab
{
Packit 6bd9ab
  int32_t tmpint32;
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  char username[BUFLEN_NAME], service[BUFLEN_NAME], ruser[BUFLEN_NAME], rhost[BUFLEN_HOSTNAME], tty[64];
Packit 6bd9ab
  int asroot;
Packit 6bd9ab
  char oldpassword[BUFLEN_PASSWORD];
Packit 6bd9ab
  char newpassword[BUFLEN_PASSWORD];
Packit 6bd9ab
  const char *binddn = NULL; /* the user performing the modification */
Packit 6bd9ab
  MYLDAP_ENTRY *entry;
Packit 6bd9ab
  char authzmsg[BUFLEN_MESSAGE];
Packit 6bd9ab
  authzmsg[0] = '\0';
Packit 6bd9ab
  /* read request parameters */
Packit 6bd9ab
  READ_STRING(fp, username);
Packit 6bd9ab
  READ_STRING(fp, service);
Packit 6bd9ab
  READ_STRING(fp, ruser);
Packit 6bd9ab
  READ_STRING(fp, rhost);
Packit 6bd9ab
  READ_STRING(fp, tty);
Packit 6bd9ab
  READ_INT32(fp, asroot);
Packit 6bd9ab
  READ_STRING(fp, oldpassword);
Packit 6bd9ab
  READ_STRING(fp, newpassword);
Packit 6bd9ab
  /* log call */
Packit 6bd9ab
  log_setrequest("pwmod=\"%s\"", username);
Packit 6bd9ab
  log_log(LOG_DEBUG, "nslcd_pam_pwmod(\"%s\",%s,\"%s\",\"%s\",\"%s\")",
Packit 6bd9ab
          username, asroot ? "asroot" : "asuser", service,
Packit 6bd9ab
          *oldpassword ? "***" : "", *newpassword ? "***" : "");
Packit 6bd9ab
  /* write the response header */
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_VERSION);
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_ACTION_PAM_PWMOD);
Packit 6bd9ab
  /* validate request */
Packit 6bd9ab
  entry = validate_user(session, username, &rc);
Packit 6bd9ab
  if (entry == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* for user not found we just say no result */
Packit 6bd9ab
    if (rc == LDAP_NO_SUCH_OBJECT)
Packit 6bd9ab
    {
Packit 6bd9ab
      WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
    }
Packit 6bd9ab
    memset(oldpassword, 0, sizeof(oldpassword));
Packit 6bd9ab
    memset(newpassword, 0, sizeof(newpassword));
Packit 6bd9ab
    return -1;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check if pam_password_prohibit_message is set */
Packit 6bd9ab
  if (nslcd_cfg->pam_password_prohibit_message != NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_NOTICE, "password change prohibited");
Packit 6bd9ab
    WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
Packit 6bd9ab
    WRITE_INT32(fp, NSLCD_PAM_PERM_DENIED);
Packit 6bd9ab
    WRITE_STRING(fp, nslcd_cfg->pam_password_prohibit_message);
Packit 6bd9ab
    WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
    memset(oldpassword, 0, sizeof(oldpassword));
Packit 6bd9ab
    memset(newpassword, 0, sizeof(newpassword));
Packit 6bd9ab
    return 0;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check if the the user passed the rootpwmoddn */
Packit 6bd9ab
  if (asroot)
Packit 6bd9ab
  {
Packit 6bd9ab
    binddn = nslcd_cfg->rootpwmoddn;
Packit 6bd9ab
    /* check if rootpwmodpw should be used */
Packit 6bd9ab
    if ((*oldpassword == '\0') && (calleruid == 0) &&
Packit 6bd9ab
        (nslcd_cfg->rootpwmodpw != NULL))
Packit 6bd9ab
    {
Packit 6bd9ab
      if (strlen(nslcd_cfg->rootpwmodpw) >= sizeof(oldpassword))
Packit 6bd9ab
      {
Packit 6bd9ab
        log_log(LOG_ERR, "nslcd_pam_pwmod(): rootpwmodpw will not fit in oldpassword");
Packit 6bd9ab
        memset(oldpassword, 0, sizeof(oldpassword));
Packit 6bd9ab
        memset(newpassword, 0, sizeof(newpassword));
Packit 6bd9ab
        return -1;
Packit 6bd9ab
      }
Packit 6bd9ab
      strcpy(oldpassword, nslcd_cfg->rootpwmodpw);
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  else
Packit 6bd9ab
  {
Packit 6bd9ab
    binddn = myldap_get_dn(entry);
Packit 6bd9ab
    /* check whether shadow properties allow password change */
Packit 6bd9ab
    rc = check_shadow(session, username, authzmsg, sizeof(authzmsg), 0, 1);
Packit 6bd9ab
    if (rc != NSLCD_PAM_SUCCESS)
Packit 6bd9ab
    {
Packit 6bd9ab
      WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
Packit 6bd9ab
      WRITE_INT32(fp, rc);
Packit 6bd9ab
      WRITE_STRING(fp, authzmsg);
Packit 6bd9ab
      WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
      memset(oldpassword, 0, sizeof(oldpassword));
Packit 6bd9ab
      memset(newpassword, 0, sizeof(newpassword));
Packit 6bd9ab
      return 0;
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* perform password modification */
Packit 6bd9ab
  rc = try_pwmod(session, binddn, myldap_get_dn(entry), oldpassword, newpassword,
Packit 6bd9ab
                 authzmsg, sizeof(authzmsg));
Packit 6bd9ab
  if (rc != LDAP_SUCCESS)
Packit 6bd9ab
  {
Packit 6bd9ab
    if (authzmsg[0] == '\0')
Packit 6bd9ab
      mysnprintf(authzmsg, sizeof(authzmsg) - 1, "password change failed: %s",
Packit 6bd9ab
                 ldap_err2string(rc));
Packit 6bd9ab
    WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
Packit 6bd9ab
    WRITE_INT32(fp, NSLCD_PAM_PERM_DENIED);
Packit 6bd9ab
    WRITE_STRING(fp, authzmsg);
Packit 6bd9ab
    WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
    memset(oldpassword, 0, sizeof(oldpassword));
Packit 6bd9ab
    memset(newpassword, 0, sizeof(newpassword));
Packit 6bd9ab
    return 0;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* write response */
Packit 6bd9ab
  log_log(LOG_NOTICE, "password changed for %s", myldap_get_dn(entry));
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_PAM_SUCCESS);
Packit 6bd9ab
  WRITE_STRING(fp, "");
Packit 6bd9ab
  WRITE_INT32(fp, NSLCD_RESULT_END);
Packit 6bd9ab
  memset(oldpassword, 0, sizeof(oldpassword));
Packit 6bd9ab
  memset(newpassword, 0, sizeof(newpassword));
Packit 6bd9ab
  return 0;
Packit 6bd9ab
}