Blame pam/pam.c

Packit 6bd9ab
/*
Packit 6bd9ab
   pam.c - pam module functions
Packit 6bd9ab
Packit 6bd9ab
   Copyright (C) 2009 Howard Chu
Packit 6bd9ab
   Copyright (C) 2009-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 <stdlib.h>
Packit 6bd9ab
#include <string.h>
Packit 6bd9ab
#include <errno.h>
Packit 6bd9ab
#include <syslog.h>
Packit 6bd9ab
#include <unistd.h>
Packit 6bd9ab
#include <sys/types.h>
Packit 6bd9ab
#include <pwd.h>
Packit 6bd9ab
Packit 6bd9ab
/* these are defined (before including pam_modules.h) for staticly linking */
Packit 6bd9ab
#define PAM_SM_AUTH
Packit 6bd9ab
#define PAM_SM_ACCOUNT
Packit 6bd9ab
#define PAM_SM_SESSION
Packit 6bd9ab
#define PAM_SM_PASSWORD
Packit 6bd9ab
Packit 6bd9ab
#include "common.h"
Packit 6bd9ab
#include "compat/attrs.h"
Packit 6bd9ab
#include "compat/pam_compat.h"
Packit 6bd9ab
Packit 6bd9ab
#ifdef HAVE_SECURITY_PAM_APPL_H
Packit 6bd9ab
#include <security/pam_appl.h>
Packit 6bd9ab
#endif /* HAVE_SECURITY_PAM_APPL_H */
Packit 6bd9ab
#ifndef HAVE_PAM_PAM_MODULES_H
Packit 6bd9ab
#include <security/pam_modules.h>
Packit 6bd9ab
#ifdef HAVE_SECURITY_PAM_EXT_H
Packit 6bd9ab
#include <security/pam_ext.h>
Packit 6bd9ab
#endif /* HAVE_SECURITY_PAM_EXT_H */
Packit 6bd9ab
#else /* not HAVE_PAM_PAM_MODULES_H */
Packit 6bd9ab
#include <pam/pam_modules.h>
Packit 6bd9ab
#endif /* not HAVE_PAM_PAM_MODULES_H */
Packit 6bd9ab
Packit 6bd9ab
/* the name we store our context under */
Packit 6bd9ab
#define PLD_CTX "PAM_LDAPD_CTX"
Packit 6bd9ab
Packit 6bd9ab
/* structure that stores the results for an nslcd call */
Packit 6bd9ab
struct nslcd_resp {
Packit 6bd9ab
  int res;
Packit 6bd9ab
  char msg[1024];
Packit 6bd9ab
};
Packit 6bd9ab
Packit 6bd9ab
/* this struct represents the context that the PAM module keeps
Packit 6bd9ab
   between calls */
Packit 6bd9ab
struct pld_ctx {
Packit 6bd9ab
  char *username;
Packit 6bd9ab
  struct nslcd_resp saved_authz;
Packit 6bd9ab
  struct nslcd_resp saved_session;
Packit 6bd9ab
  int asroot;
Packit 6bd9ab
  char *oldpassword;
Packit 6bd9ab
};
Packit 6bd9ab
Packit 6bd9ab
/* clear the context to all empty values */
Packit 6bd9ab
static void ctx_clear(struct pld_ctx *ctx)
Packit 6bd9ab
{
Packit 6bd9ab
  if (ctx->username)
Packit 6bd9ab
  {
Packit 6bd9ab
    free(ctx->username);
Packit 6bd9ab
    ctx->username = NULL;
Packit 6bd9ab
  }
Packit 6bd9ab
  ctx->saved_authz.res = PAM_SUCCESS;
Packit 6bd9ab
  memset(ctx->saved_authz.msg, 0, sizeof(ctx->saved_authz.msg));
Packit 6bd9ab
  ctx->saved_session.res = PAM_SUCCESS;
Packit 6bd9ab
  memset(ctx->saved_session.msg, 0, sizeof(ctx->saved_session.msg));
Packit 6bd9ab
  ctx->asroot = 0;
Packit 6bd9ab
  if (ctx->oldpassword)
Packit 6bd9ab
  {
Packit 6bd9ab
    memset(ctx->oldpassword, 0, strlen(ctx->oldpassword));
Packit 6bd9ab
    free(ctx->oldpassword);
Packit 6bd9ab
    ctx->oldpassword = NULL;
Packit 6bd9ab
  }
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* free the context (this is installed as handler into PAM) */
Packit 6bd9ab
static void ctx_free(pam_handle_t UNUSED(*pamh), void *data, int UNUSED(err))
Packit 6bd9ab
{
Packit 6bd9ab
  struct pld_ctx *ctx = data;
Packit 6bd9ab
  ctx_clear(ctx);
Packit 6bd9ab
  free(ctx);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* try to get the module's context, returns a PAM status code */
Packit 6bd9ab
static int ctx_get(pam_handle_t *pamh, const char *username, struct pld_ctx **pctx)
Packit 6bd9ab
{
Packit 6bd9ab
  struct pld_ctx *ctx = NULL;
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  /* try to get the context from PAM */
Packit 6bd9ab
  rc = pam_get_data(pamh, PLD_CTX, (const void **)&ctx;;
Packit 6bd9ab
  if ((rc == PAM_SUCCESS) && (ctx != NULL))
Packit 6bd9ab
  {
Packit 6bd9ab
    /* if the user is different clear the context */
Packit 6bd9ab
    if ((ctx->username != NULL) && (strcmp(ctx->username, username) != 0))
Packit 6bd9ab
      ctx_clear(ctx);
Packit 6bd9ab
  }
Packit 6bd9ab
  else
Packit 6bd9ab
  {
Packit 6bd9ab
    /* allocate a new context */
Packit 6bd9ab
    ctx = calloc(1, sizeof(struct pld_ctx));
Packit 6bd9ab
    if (ctx == NULL)
Packit 6bd9ab
    {
Packit 6bd9ab
      pam_syslog(pamh, LOG_CRIT, "calloc(): failed to allocate memory: %s",
Packit 6bd9ab
                 strerror(errno));
Packit 6bd9ab
      return PAM_BUF_ERR;
Packit 6bd9ab
    }
Packit 6bd9ab
    ctx_clear(ctx);
Packit 6bd9ab
    /* store the new context with the handler to free it */
Packit 6bd9ab
    rc = pam_set_data(pamh, PLD_CTX, ctx, ctx_free);
Packit 6bd9ab
    if (rc != PAM_SUCCESS)
Packit 6bd9ab
    {
Packit 6bd9ab
      ctx_free(pamh, ctx, 0);
Packit 6bd9ab
      pam_syslog(pamh, LOG_ERR, "failed to store context: %s",
Packit 6bd9ab
                 pam_strerror(pamh, rc));
Packit 6bd9ab
      return rc;
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* save the username in the context */
Packit 6bd9ab
  if (ctx->username == NULL)
Packit 6bd9ab
    ctx->username = strdup(username);
Packit 6bd9ab
  /* return the context */
Packit 6bd9ab
  *pctx = ctx;
Packit 6bd9ab
  return PAM_SUCCESS;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* our PAM module configuration */
Packit 6bd9ab
struct pld_cfg {
Packit 6bd9ab
  int nullok;
Packit 6bd9ab
  int no_warn;
Packit 6bd9ab
  int ignore_unknown_user;
Packit 6bd9ab
  int ignore_authinfo_unavail;
Packit 6bd9ab
  int debug;
Packit 6bd9ab
  uid_t minimum_uid;
Packit 6bd9ab
};
Packit 6bd9ab
Packit 6bd9ab
static void cfg_init(pam_handle_t *pamh, int flags,
Packit 6bd9ab
                     int argc, const char **argv,
Packit 6bd9ab
                     struct pld_cfg *cfg)
Packit 6bd9ab
{
Packit 6bd9ab
  int i;
Packit 6bd9ab
  /* initialise config with defaults */
Packit 6bd9ab
  cfg->nullok = 0;
Packit 6bd9ab
  cfg->no_warn = 0;
Packit 6bd9ab
  cfg->ignore_unknown_user = 0;
Packit 6bd9ab
  cfg->ignore_authinfo_unavail = 0;
Packit 6bd9ab
  cfg->debug = 0;
Packit 6bd9ab
  cfg->minimum_uid = 0;
Packit 6bd9ab
  /* go over arguments */
Packit 6bd9ab
  for (i = 0; i < argc; i++)
Packit 6bd9ab
  {
Packit 6bd9ab
    if (strcmp(argv[i], "use_first_pass") == 0)
Packit 6bd9ab
      /* ignore, this option is used by pam_get_authtok() internally */ ;
Packit 6bd9ab
    else if (strcmp(argv[i], "try_first_pass") == 0)
Packit 6bd9ab
      /* ignore, this option is used by pam_get_authtok() internally */ ;
Packit 6bd9ab
    else if (strcmp(argv[i], "nullok") == 0)
Packit 6bd9ab
      cfg->nullok = 1;
Packit 6bd9ab
    else if (strcmp(argv[i], "use_authtok") == 0)
Packit 6bd9ab
      /* ignore, this option is used by pam_get_authtok() internally */ ;
Packit 6bd9ab
    else if (strcmp(argv[i], "no_warn") == 0)
Packit 6bd9ab
      cfg->no_warn = 1;
Packit 6bd9ab
    else if (strcmp(argv[i], "ignore_unknown_user") == 0)
Packit 6bd9ab
      cfg->ignore_unknown_user = 1;
Packit 6bd9ab
    else if (strcmp(argv[i], "ignore_authinfo_unavail") == 0)
Packit 6bd9ab
      cfg->ignore_authinfo_unavail = 1;
Packit 6bd9ab
    else if (strcmp(argv[i], "debug") == 0)
Packit 6bd9ab
      cfg->debug = 1;
Packit 6bd9ab
    else if (strncmp(argv[i], "minimum_uid=", 12) == 0)
Packit 6bd9ab
      cfg->minimum_uid = (uid_t)atoi(argv[i] + 12);
Packit 6bd9ab
    else
Packit 6bd9ab
      pam_syslog(pamh, LOG_ERR, "unknown option: %s", argv[i]);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check flags */
Packit 6bd9ab
  if (flags & PAM_SILENT)
Packit 6bd9ab
    cfg->no_warn = 1;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static int init(pam_handle_t *pamh, struct pld_cfg *cfg, struct pld_ctx **ctx,
Packit 6bd9ab
                const char **username, const char **service, const char **ruser,
Packit 6bd9ab
                const char **rhost, const char **tty)
Packit 6bd9ab
{
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  struct passwd *pwent;
Packit 6bd9ab
  /* get user name */
Packit 6bd9ab
  rc = pam_get_user(pamh, username, NULL);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
  {
Packit 6bd9ab
    pam_syslog(pamh, LOG_ERR, "failed to get user name: %s", pam_strerror(pamh, rc));
Packit 6bd9ab
    return rc;
Packit 6bd9ab
  }
Packit 6bd9ab
  if ((*username == NULL) || ((*username)[0] == '\0'))
Packit 6bd9ab
  {
Packit 6bd9ab
    pam_syslog(pamh, LOG_ERR, "got empty user name");
Packit 6bd9ab
    return PAM_USER_UNKNOWN;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check uid */
Packit 6bd9ab
  if (cfg->minimum_uid > 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    pwent = pam_modutil_getpwnam(args->pamh, *username);
Packit 6bd9ab
    if ((pwent != NULL) && (pwent->pw_uid < cfg->minimum_uid))
Packit 6bd9ab
    {
Packit 6bd9ab
      if (cfg->debug)
Packit 6bd9ab
        pam_syslog(pamh, LOG_DEBUG, "uid below minimum_uid; user=%s uid=%ld",
Packit 6bd9ab
                   *username, (long)pwent->pw_uid);
Packit 6bd9ab
      return cfg->ignore_unknown_user ? PAM_IGNORE : PAM_USER_UNKNOWN;
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* get our context */
Packit 6bd9ab
  rc = ctx_get(pamh, *username, ctx);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return rc;
Packit 6bd9ab
  /* get service name */
Packit 6bd9ab
  rc = pam_get_item(pamh, PAM_SERVICE, (PAM_ITEM_CONST void **)service);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
  {
Packit 6bd9ab
    pam_syslog(pamh, LOG_ERR, "failed to get service name: %s",
Packit 6bd9ab
               pam_strerror(pamh, rc));
Packit 6bd9ab
    return rc;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* get more PAM information (ignore errors) */
Packit 6bd9ab
  pam_get_item(pamh, PAM_RUSER, (PAM_ITEM_CONST void **)ruser);
Packit 6bd9ab
  pam_get_item(pamh, PAM_RHOST, (PAM_ITEM_CONST void **)rhost);
Packit 6bd9ab
  pam_get_item(pamh, PAM_TTY, (PAM_ITEM_CONST void **)tty);
Packit 6bd9ab
  return PAM_SUCCESS;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* map a NSLCD PAM status code to a PAM status code */
Packit 6bd9ab
static int nslcd2pam_rc(pam_handle_t *pamh, int rc)
Packit 6bd9ab
{
Packit 6bd9ab
#define map(i) case NSLCD_##i: return i;
Packit 6bd9ab
  switch (rc)
Packit 6bd9ab
  {
Packit 6bd9ab
    map(PAM_SUCCESS);
Packit 6bd9ab
    map(PAM_PERM_DENIED);
Packit 6bd9ab
    map(PAM_AUTH_ERR);
Packit 6bd9ab
    map(PAM_CRED_INSUFFICIENT);
Packit 6bd9ab
    map(PAM_AUTHINFO_UNAVAIL);
Packit 6bd9ab
    map(PAM_USER_UNKNOWN);
Packit 6bd9ab
    map(PAM_MAXTRIES);
Packit 6bd9ab
    map(PAM_NEW_AUTHTOK_REQD);
Packit 6bd9ab
    map(PAM_ACCT_EXPIRED);
Packit 6bd9ab
    map(PAM_SESSION_ERR);
Packit 6bd9ab
    map(PAM_AUTHTOK_ERR);
Packit 6bd9ab
    map(PAM_AUTHTOK_DISABLE_AGING);
Packit 6bd9ab
    map(PAM_IGNORE);
Packit 6bd9ab
    map(PAM_ABORT);
Packit 6bd9ab
    map(PAM_AUTHTOK_EXPIRED);
Packit 6bd9ab
    default:
Packit 6bd9ab
      pam_syslog(pamh, LOG_ERR, "unknown NSLCD_PAM_* code returned: %d", rc);
Packit 6bd9ab
      return PAM_ABORT;
Packit 6bd9ab
  }
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* check whether the specified user is handled by nslcd */
Packit 6bd9ab
static int nslcd_request_exists(pam_handle_t *pamh, struct pld_cfg *cfg,
Packit 6bd9ab
                                const char *username)
Packit 6bd9ab
{
Packit 6bd9ab
  PAM_REQUEST(
Packit 6bd9ab
    NSLCD_ACTION_PASSWD_BYNAME,
Packit 6bd9ab
    /* log debug message */
Packit 6bd9ab
    pam_syslog(pamh, LOG_DEBUG, "nslcd account check; user=%s", username),
Packit 6bd9ab
    /* write the request parameters */
Packit 6bd9ab
    WRITE_STRING(fp, username),
Packit 6bd9ab
    /* read the result entry (skip it completely) */
Packit 6bd9ab
    SKIP_STRING(fp);            /* user name */
Packit 6bd9ab
    SKIP_STRING(fp);            /* passwd entry */
Packit 6bd9ab
    SKIP(fp, sizeof(int32_t));  /* uid */
Packit 6bd9ab
    SKIP(fp, sizeof(int32_t));  /* gid */
Packit 6bd9ab
    SKIP_STRING(fp);            /* gecos */
Packit 6bd9ab
    SKIP_STRING(fp);            /* home dir */
Packit 6bd9ab
    SKIP_STRING(fp);            /* shell */
Packit 6bd9ab
  )
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* perform an authentication call over nslcd */
Packit 6bd9ab
static int nslcd_request_authc(pam_handle_t *pamh, struct pld_cfg *cfg,
Packit 6bd9ab
                               const char *username, const char *service,
Packit 6bd9ab
                               const char *ruser, const char *rhost,
Packit 6bd9ab
                               const char *tty, const char *passwd,
Packit 6bd9ab
                               struct nslcd_resp *authc_resp,
Packit 6bd9ab
                               struct nslcd_resp *authz_resp)
Packit 6bd9ab
{
Packit 6bd9ab
  PAM_REQUEST(
Packit 6bd9ab
    NSLCD_ACTION_PAM_AUTHC,
Packit 6bd9ab
    /* log debug message */
Packit 6bd9ab
    pam_syslog(pamh, LOG_DEBUG, "nslcd authentication; user=%s", username),
Packit 6bd9ab
    /* write the request parameters */
Packit 6bd9ab
    WRITE_STRING(fp, username);
Packit 6bd9ab
    WRITE_STRING(fp, service);
Packit 6bd9ab
    WRITE_STRING(fp, ruser);
Packit 6bd9ab
    WRITE_STRING(fp, rhost);
Packit 6bd9ab
    WRITE_STRING(fp, tty);
Packit 6bd9ab
    WRITE_STRING(fp, passwd),
Packit 6bd9ab
    /* read the result entry */
Packit 6bd9ab
    READ_PAM_CODE(fp, authc_resp->res);
Packit 6bd9ab
    READ_STRING(fp, authc_resp->msg); /* user name */
Packit 6bd9ab
    /* if we want the authorisation response, save it, otherwise skip it */
Packit 6bd9ab
    if (authz_resp != NULL)
Packit 6bd9ab
    {
Packit 6bd9ab
      READ_PAM_CODE(fp, authz_resp->res);
Packit 6bd9ab
      READ_STRING(fp, authz_resp->msg);
Packit 6bd9ab
    }
Packit 6bd9ab
    else
Packit 6bd9ab
    {
Packit 6bd9ab
      SKIP(fp, sizeof(int32_t));
Packit 6bd9ab
      SKIP_STRING(fp);
Packit 6bd9ab
    }
Packit 6bd9ab
  )
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* perform an authorisation call over nslcd */
Packit 6bd9ab
static int nslcd_request_authz(pam_handle_t *pamh, struct pld_cfg *cfg,
Packit 6bd9ab
                               const char *username, const char *service,
Packit 6bd9ab
                               const char *ruser, const char *rhost,
Packit 6bd9ab
                               const char *tty, struct nslcd_resp *resp)
Packit 6bd9ab
{
Packit 6bd9ab
  PAM_REQUEST(
Packit 6bd9ab
    NSLCD_ACTION_PAM_AUTHZ,
Packit 6bd9ab
    /* log debug message */
Packit 6bd9ab
    pam_syslog(pamh, LOG_DEBUG, "nslcd authorisation; user=%s", username),
Packit 6bd9ab
    /* write the request parameters */
Packit 6bd9ab
    WRITE_STRING(fp, username);
Packit 6bd9ab
    WRITE_STRING(fp, service);
Packit 6bd9ab
    WRITE_STRING(fp, ruser);
Packit 6bd9ab
    WRITE_STRING(fp, rhost);
Packit 6bd9ab
    WRITE_STRING(fp, tty),
Packit 6bd9ab
    /* read the result entry */
Packit 6bd9ab
    READ_PAM_CODE(fp, resp->res);
Packit 6bd9ab
    READ_STRING(fp, resp->msg);
Packit 6bd9ab
  )
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* do a session open nslcd request */
Packit 6bd9ab
static int nslcd_request_sess_o(pam_handle_t *pamh, struct pld_cfg *cfg,
Packit 6bd9ab
                                const char *username, const char *service,
Packit 6bd9ab
                                const char *ruser, const char *rhost,
Packit 6bd9ab
                                const char *tty, struct nslcd_resp *resp)
Packit 6bd9ab
{
Packit 6bd9ab
  PAM_REQUEST(
Packit 6bd9ab
    NSLCD_ACTION_PAM_SESS_O,
Packit 6bd9ab
    /* log debug message */
Packit 6bd9ab
    pam_syslog(pamh, LOG_DEBUG, "nslcd session open; user=%s", username),
Packit 6bd9ab
    /* write the request parameters */
Packit 6bd9ab
    WRITE_STRING(fp, username);
Packit 6bd9ab
    WRITE_STRING(fp, service);
Packit 6bd9ab
    WRITE_STRING(fp, ruser);
Packit 6bd9ab
    WRITE_STRING(fp, rhost);
Packit 6bd9ab
    WRITE_STRING(fp, tty),
Packit 6bd9ab
    /* read the result entry */
Packit 6bd9ab
    READ_STRING(fp, resp->msg)
Packit 6bd9ab
  )
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* do a session close nslcd request */
Packit 6bd9ab
static int nslcd_request_sess_c(pam_handle_t *pamh, struct pld_cfg *cfg,
Packit 6bd9ab
                                const char *username, const char *service,
Packit 6bd9ab
                                const char *ruser, const char *rhost,
Packit 6bd9ab
                                const char *tty, const char *sessid)
Packit 6bd9ab
{
Packit 6bd9ab
  PAM_REQUEST(
Packit 6bd9ab
    NSLCD_ACTION_PAM_SESS_C,
Packit 6bd9ab
    /* log debug message */
Packit 6bd9ab
    pam_syslog(pamh, LOG_DEBUG, "nslcd session close; user=%s", username),
Packit 6bd9ab
    /* write the request parameters */
Packit 6bd9ab
    WRITE_STRING(fp, username);
Packit 6bd9ab
    WRITE_STRING(fp, service);
Packit 6bd9ab
    WRITE_STRING(fp, ruser);
Packit 6bd9ab
    WRITE_STRING(fp, rhost);
Packit 6bd9ab
    WRITE_STRING(fp, tty);
Packit 6bd9ab
    WRITE_STRING(fp, sessid),
Packit 6bd9ab
    /* no result entry to read */ ;
Packit 6bd9ab
  )
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* do a password modification nslcd call */
Packit 6bd9ab
static int nslcd_request_pwmod(pam_handle_t *pamh, struct pld_cfg *cfg,
Packit 6bd9ab
                               const char *username, const char *service,
Packit 6bd9ab
                               const char *ruser, const char *rhost,
Packit 6bd9ab
                               const char *tty, int asroot,
Packit 6bd9ab
                               const char *oldpasswd, const char *newpasswd,
Packit 6bd9ab
                               struct nslcd_resp *resp)
Packit 6bd9ab
{
Packit 6bd9ab
  PAM_REQUEST(
Packit 6bd9ab
    NSLCD_ACTION_PAM_PWMOD,
Packit 6bd9ab
    /* log debug message */
Packit 6bd9ab
    pam_syslog(pamh, LOG_DEBUG, "nslcd password modify; user=%s", username),
Packit 6bd9ab
    /* write the request parameters */
Packit 6bd9ab
    WRITE_STRING(fp, username);
Packit 6bd9ab
    WRITE_STRING(fp, service);
Packit 6bd9ab
    WRITE_STRING(fp, ruser);
Packit 6bd9ab
    WRITE_STRING(fp, rhost);
Packit 6bd9ab
    WRITE_STRING(fp, tty);
Packit 6bd9ab
    WRITE_INT32(fp, asroot);
Packit 6bd9ab
    WRITE_STRING(fp, oldpasswd);
Packit 6bd9ab
    WRITE_STRING(fp, newpasswd),
Packit 6bd9ab
    /* read the result entry */
Packit 6bd9ab
    READ_PAM_CODE(fp, resp->res);
Packit 6bd9ab
    READ_STRING(fp, resp->msg);
Packit 6bd9ab
  )
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static int nslcd_request_config_get(pam_handle_t *pamh, struct pld_cfg *cfg,
Packit 6bd9ab
                                    int cfgopt, struct nslcd_resp *resp)
Packit 6bd9ab
{
Packit 6bd9ab
  PAM_REQUEST(
Packit 6bd9ab
    NSLCD_ACTION_CONFIG_GET,
Packit 6bd9ab
    /* log debug message */
Packit 6bd9ab
    pam_syslog(pamh, LOG_DEBUG, "nslcd request config (%d)", cfgopt),
Packit 6bd9ab
    /* write the request parameter */
Packit 6bd9ab
    WRITE_INT32(fp, cfgopt),
Packit 6bd9ab
    /* read the result entry */
Packit 6bd9ab
    READ_STRING(fp, resp->msg);
Packit 6bd9ab
  )
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* remap the return code based on the configuration */
Packit 6bd9ab
static int remap_pam_rc(int rc, struct pld_cfg *cfg)
Packit 6bd9ab
{
Packit 6bd9ab
  if ((rc == PAM_AUTHINFO_UNAVAIL) && cfg->ignore_authinfo_unavail)
Packit 6bd9ab
    return PAM_IGNORE;
Packit 6bd9ab
  if ((rc == PAM_USER_UNKNOWN) && cfg->ignore_unknown_user)
Packit 6bd9ab
    return PAM_IGNORE;
Packit 6bd9ab
  return rc;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* PAM authentication check */
Packit 6bd9ab
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
Packit 6bd9ab
                        int argc, const char **argv)
Packit 6bd9ab
{
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  struct pld_cfg cfg;
Packit 6bd9ab
  struct pld_ctx *ctx;
Packit 6bd9ab
  const char *username, *service;
Packit 6bd9ab
  const char *ruser = NULL, *rhost = NULL, *tty = NULL;
Packit 6bd9ab
  char *passwd = NULL;
Packit 6bd9ab
  struct nslcd_resp resp;
Packit 6bd9ab
  /* set up configuration */
Packit 6bd9ab
  cfg_init(pamh, flags, argc, argv, &cfg;;
Packit 6bd9ab
  rc = init(pamh, &cfg, &ctx, &username, &service, &ruser, &rhost, &tty);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
  /* if service is "passwd" and pwdmod is not allowed alert user */
Packit 6bd9ab
  if (!strcmp(service, "passwd"))
Packit 6bd9ab
  {
Packit 6bd9ab
    rc = nslcd_request_config_get(pamh, &cfg, NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE,
Packit 6bd9ab
                                  &resp);
Packit 6bd9ab
    if ((rc == PAM_SUCCESS) && (resp.msg[0] != '\0'))
Packit 6bd9ab
    {
Packit 6bd9ab
      /* we silently ignore errors to get the configuration option */
Packit 6bd9ab
      pam_syslog(pamh, LOG_NOTICE, "password change prohibited: %s; user=%s",
Packit 6bd9ab
                 resp.msg, username);
Packit 6bd9ab
      if (!cfg.no_warn)
Packit 6bd9ab
        pam_error(pamh, "%s", resp.msg);
Packit 6bd9ab
      return remap_pam_rc(PAM_PERM_DENIED, &cfg;;
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* prompt the user for a password */
Packit 6bd9ab
  rc = pam_get_authtok(pamh, PAM_AUTHTOK, (const char **)&passwd, NULL);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
  {
Packit 6bd9ab
    pam_syslog(pamh, LOG_ERR, "failed to get password: %s",
Packit 6bd9ab
               pam_strerror(pamh, rc));
Packit 6bd9ab
    return rc;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check password */
Packit 6bd9ab
  if (!cfg.nullok && ((passwd == NULL) || (passwd[0] == '\0')))
Packit 6bd9ab
  {
Packit 6bd9ab
    if (cfg.debug)
Packit 6bd9ab
      pam_syslog(pamh, LOG_DEBUG, "user has empty password, access denied");
Packit 6bd9ab
    return PAM_AUTH_ERR;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* do the nslcd request */
Packit 6bd9ab
  rc = nslcd_request_authc(pamh, &cfg, username, service, ruser, rhost, tty,
Packit 6bd9ab
                           passwd, &resp, &(ctx->saved_authz));
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
  /* check the authentication result */
Packit 6bd9ab
  if (resp.res != PAM_SUCCESS)
Packit 6bd9ab
  {
Packit 6bd9ab
    pam_syslog(pamh, LOG_NOTICE, "%s; user=%s",
Packit 6bd9ab
               pam_strerror(pamh, resp.res), username);
Packit 6bd9ab
    return remap_pam_rc(resp.res, &cfg;;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* debug log */
Packit 6bd9ab
  if (cfg.debug)
Packit 6bd9ab
    pam_syslog(pamh, LOG_DEBUG, "authentication succeeded");
Packit 6bd9ab
  /* if password change is required, save old password in context */
Packit 6bd9ab
  if ((ctx->saved_authz.res == PAM_NEW_AUTHTOK_REQD) && (ctx->oldpassword == NULL))
Packit 6bd9ab
    ctx->oldpassword = strdup(passwd);
Packit 6bd9ab
  /* update caller's idea of the user name */
Packit 6bd9ab
  if ((resp.msg[0] != '\0') && (strcmp(resp.msg, username) != 0))
Packit 6bd9ab
  {
Packit 6bd9ab
    pam_syslog(pamh, LOG_INFO, "username changed from %s to %s",
Packit 6bd9ab
               username, resp.msg);
Packit 6bd9ab
    rc = pam_set_item(pamh, PAM_USER, resp.msg);
Packit 6bd9ab
    /* empty the username in the context to not loose our context */
Packit 6bd9ab
    if (ctx->username != NULL)
Packit 6bd9ab
    {
Packit 6bd9ab
      free(ctx->username);
Packit 6bd9ab
      ctx->username = NULL;
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  return rc;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* called to update the authentication credentials */
Packit 6bd9ab
int pam_sm_setcred(pam_handle_t UNUSED(*pamh), int UNUSED(flags),
Packit 6bd9ab
                   int UNUSED(argc), const char UNUSED(**argv))
Packit 6bd9ab
{
Packit 6bd9ab
  /* we don't need to do anything here */
Packit 6bd9ab
  return PAM_SUCCESS;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* PAM authorisation check */
Packit 6bd9ab
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
Packit 6bd9ab
                     int argc, const char **argv)
Packit 6bd9ab
{
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  struct pld_cfg cfg;
Packit 6bd9ab
  struct pld_ctx *ctx;
Packit 6bd9ab
  const char *username, *service;
Packit 6bd9ab
  const char *ruser = NULL, *rhost = NULL, *tty = NULL;
Packit 6bd9ab
  struct nslcd_resp authz_resp;
Packit 6bd9ab
  const char *msg = NULL;
Packit 6bd9ab
  /* set up configuration */
Packit 6bd9ab
  cfg_init(pamh, flags, argc, argv, &cfg;;
Packit 6bd9ab
  rc = init(pamh, &cfg, &ctx, &username, &service, &ruser, &rhost, &tty);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
  /* do the nslcd request */
Packit 6bd9ab
  rc = nslcd_request_authz(pamh, &cfg, username, service, ruser, rhost, tty,
Packit 6bd9ab
                           &authz_resp);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
  /* check the returned authorisation value and the value from authentication */
Packit 6bd9ab
  if (authz_resp.res != PAM_SUCCESS)
Packit 6bd9ab
  {
Packit 6bd9ab
    rc = authz_resp.res;
Packit 6bd9ab
    msg = authz_resp.msg;
Packit 6bd9ab
  }
Packit 6bd9ab
  else if (ctx->saved_authz.res != PAM_SUCCESS)
Packit 6bd9ab
  {
Packit 6bd9ab
    rc = ctx->saved_authz.res;
Packit 6bd9ab
    msg = ctx->saved_authz.msg;
Packit 6bd9ab
  }
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* turn in to generic PAM error message if message is empty */
Packit 6bd9ab
    if ((msg == NULL) || (msg[0] == '\0'))
Packit 6bd9ab
    {
Packit 6bd9ab
      msg = pam_strerror(pamh, rc);
Packit 6bd9ab
      pam_syslog(pamh, LOG_NOTICE, "%s; user=%s", msg, username);
Packit 6bd9ab
    }
Packit 6bd9ab
    else
Packit 6bd9ab
      pam_syslog(pamh, LOG_NOTICE, "%s; user=%s; err=%s",
Packit 6bd9ab
                 msg, username, pam_strerror(pamh, rc));
Packit 6bd9ab
    rc = remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
    if ((rc != PAM_IGNORE) && (!cfg.no_warn))
Packit 6bd9ab
      pam_error(pamh, "%s", msg);
Packit 6bd9ab
    return rc;
Packit 6bd9ab
  }
Packit 6bd9ab
  if (cfg.debug)
Packit 6bd9ab
    pam_syslog(pamh, LOG_DEBUG, "authorization succeeded");
Packit 6bd9ab
  /* present any informational messages to the user */
Packit 6bd9ab
  if ((authz_resp.msg[0] != '\0') && (!cfg.no_warn))
Packit 6bd9ab
  {
Packit 6bd9ab
    pam_info(pamh, "%s", authz_resp.msg);
Packit 6bd9ab
    pam_syslog(pamh, LOG_INFO, "%s; user=%s",
Packit 6bd9ab
               authz_resp.msg, username);
Packit 6bd9ab
  }
Packit 6bd9ab
  if ((ctx->saved_authz.msg[0] != '\0') && (!cfg.no_warn))
Packit 6bd9ab
  {
Packit 6bd9ab
    pam_info(pamh, "%s", ctx->saved_authz.msg);
Packit 6bd9ab
    pam_syslog(pamh, LOG_INFO, "%s; user=%s",
Packit 6bd9ab
               ctx->saved_authz.msg, username);
Packit 6bd9ab
  }
Packit 6bd9ab
  return PAM_SUCCESS;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* PAM session open call */
Packit 6bd9ab
int pam_sm_open_session(pam_handle_t *pamh, int flags,
Packit 6bd9ab
                        int argc, const char **argv)
Packit 6bd9ab
{
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  struct pld_cfg cfg;
Packit 6bd9ab
  struct pld_ctx *ctx;
Packit 6bd9ab
  const char *username, *service;
Packit 6bd9ab
  const char *ruser = NULL, *rhost = NULL, *tty = NULL;
Packit 6bd9ab
  /* set up configuration */
Packit 6bd9ab
  cfg_init(pamh, flags, argc, argv, &cfg;;
Packit 6bd9ab
  rc = init(pamh, &cfg, &ctx, &username, &service, &ruser, &rhost, &tty);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
  /* do the nslcd request */
Packit 6bd9ab
  rc = nslcd_request_sess_o(pamh, &cfg, username, service, ruser, rhost,
Packit 6bd9ab
                            tty, &(ctx->saved_session));
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
  /* debug log */
Packit 6bd9ab
  if (cfg.debug)
Packit 6bd9ab
    pam_syslog(pamh, LOG_DEBUG, "session open succeeded; session_id=%s",
Packit 6bd9ab
               ctx->saved_session.msg);
Packit 6bd9ab
  return PAM_SUCCESS;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* PAM session close call */
Packit 6bd9ab
int pam_sm_close_session(pam_handle_t *pamh, int flags,
Packit 6bd9ab
                         int argc, const char **argv)
Packit 6bd9ab
{
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  struct pld_cfg cfg;
Packit 6bd9ab
  struct pld_ctx *ctx;
Packit 6bd9ab
  const char *username, *service;
Packit 6bd9ab
  const char *ruser = NULL, *rhost = NULL, *tty = NULL;
Packit 6bd9ab
  /* set up configuration */
Packit 6bd9ab
  cfg_init(pamh, flags, argc, argv, &cfg;;
Packit 6bd9ab
  rc = init(pamh, &cfg, &ctx, &username, &service, &ruser, &rhost, &tty);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
  /* do the nslcd request */
Packit 6bd9ab
  rc = nslcd_request_sess_c(pamh, &cfg, username, service, ruser, rhost,
Packit 6bd9ab
                            tty, ctx->saved_session.msg);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
  /* debug log */
Packit 6bd9ab
  if (cfg.debug)
Packit 6bd9ab
    pam_syslog(pamh, LOG_DEBUG, "session close succeeded; session_id=%s",
Packit 6bd9ab
               ctx->saved_session.msg);
Packit 6bd9ab
  return PAM_SUCCESS;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* Change the password of the user. This function is first called with
Packit 6bd9ab
 PAM_PRELIM_CHECK set in the flags and then without the flag. In the first
Packit 6bd9ab
 pass it is determined whether we can contact the LDAP server and the
Packit 6bd9ab
 provided old password is valid. In the second pass we get the new
Packit 6bd9ab
 password and actually modify the password. */
Packit 6bd9ab
int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
Packit 6bd9ab
                     int argc, const char **argv)
Packit 6bd9ab
{
Packit 6bd9ab
  int rc;
Packit 6bd9ab
  struct pld_cfg cfg;
Packit 6bd9ab
  struct pld_ctx *ctx;
Packit 6bd9ab
  const char *username, *service;
Packit 6bd9ab
  const char *ruser = NULL, *rhost = NULL, *tty = NULL;
Packit 6bd9ab
  const char *oldpassword = NULL, *newpassword = NULL;
Packit 6bd9ab
  struct passwd *pwent;
Packit 6bd9ab
  uid_t myuid;
Packit 6bd9ab
  struct nslcd_resp resp;
Packit 6bd9ab
  const char *msg;
Packit 6bd9ab
  /* set up configuration */
Packit 6bd9ab
  cfg_init(pamh, flags, argc, argv, &cfg;;
Packit 6bd9ab
  rc = init(pamh, &cfg, &ctx, &username, &service, &ruser, &rhost, &tty);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
  /* check if password modification is allowed */
Packit 6bd9ab
  rc = nslcd_request_config_get(pamh, &cfg, NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE,
Packit 6bd9ab
                                &resp);
Packit 6bd9ab
  if ((rc == PAM_SUCCESS) && (resp.msg[0] != '\0'))
Packit 6bd9ab
  {
Packit 6bd9ab
    /* we silently ignore errors to get the configuration option */
Packit 6bd9ab
    pam_syslog(pamh, LOG_NOTICE, "password change prohibited: %s; user=%s",
Packit 6bd9ab
               resp.msg, username);
Packit 6bd9ab
    if (!cfg.no_warn)
Packit 6bd9ab
      pam_error(pamh, "%s", resp.msg);
Packit 6bd9ab
    return remap_pam_rc(PAM_PERM_DENIED, &cfg;;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* see if we are dealing with an LDAP user first */
Packit 6bd9ab
  rc = nslcd_request_exists(pamh, &cfg, username);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
  /* preliminary check, just see if we can authenticate with the current password */
Packit 6bd9ab
  if (flags & PAM_PRELIM_CHECK)
Packit 6bd9ab
  {
Packit 6bd9ab
    ctx->asroot = 0;
Packit 6bd9ab
    /* see if the user is trying to modify another user's password */
Packit 6bd9ab
    /* TODO: perhaps this can be combined with the nslcd_request_exists() call above */
Packit 6bd9ab
    pwent = pam_modutil_getpwnam(args->pamh, username);
Packit 6bd9ab
    myuid = getuid();
Packit 6bd9ab
    if ((pwent != NULL) && (pwent->pw_uid != myuid) && (!(flags & PAM_CHANGE_EXPIRED_AUTHTOK)))
Packit 6bd9ab
    {
Packit 6bd9ab
      /* we are root so we can test if nslcd will allow us to change the
Packit 6bd9ab
         user's password without the admin password */
Packit 6bd9ab
      if (myuid == 0)
Packit 6bd9ab
      {
Packit 6bd9ab
        rc = nslcd_request_authc(pamh, &cfg, "", service, ruser, rhost, tty,
Packit 6bd9ab
                                 "", &resp, NULL);
Packit 6bd9ab
        if ((rc == PAM_SUCCESS) && (resp.res == PAM_SUCCESS))
Packit 6bd9ab
        {
Packit 6bd9ab
          ctx->asroot = 1;
Packit 6bd9ab
          return pam_set_item(pamh, PAM_OLDAUTHTOK, "");
Packit 6bd9ab
        }
Packit 6bd9ab
      }
Packit 6bd9ab
      /* try to  authenticate with the LDAP administrator password by passing
Packit 6bd9ab
         an empty username to the authc request */
Packit 6bd9ab
      rc = pam_get_authtok(pamh, PAM_OLDAUTHTOK, &oldpassword,
Packit 6bd9ab
                           "LDAP administrator password: ");
Packit 6bd9ab
      if (rc != PAM_SUCCESS)
Packit 6bd9ab
        return rc;
Packit 6bd9ab
      ctx->asroot = 1;
Packit 6bd9ab
      username = "";
Packit 6bd9ab
    }
Packit 6bd9ab
    else if ((ctx->oldpassword != NULL) && (*ctx->oldpassword != '\0'))
Packit 6bd9ab
    {
Packit 6bd9ab
      /* we already have an old password stored (from a previous
Packit 6bd9ab
         authentication phase) so we'll use that and don't re-check */
Packit 6bd9ab
      rc = pam_set_item(pamh, PAM_OLDAUTHTOK, ctx->oldpassword);
Packit 6bd9ab
      return remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
    }
Packit 6bd9ab
    else
Packit 6bd9ab
    {
Packit 6bd9ab
      /* prompt the user for a password if needed */
Packit 6bd9ab
      rc = pam_get_authtok(pamh, PAM_OLDAUTHTOK, (const char **)&oldpassword,
Packit 6bd9ab
                           "(current) LDAP Password: ");
Packit 6bd9ab
      if (rc != PAM_SUCCESS)
Packit 6bd9ab
        return rc;
Packit 6bd9ab
    }
Packit 6bd9ab
    /* check for empty password */
Packit 6bd9ab
    if (!cfg.nullok && ((oldpassword == NULL) || (oldpassword[0] == '\0')))
Packit 6bd9ab
    {
Packit 6bd9ab
      if (cfg.debug)
Packit 6bd9ab
        pam_syslog(pamh, LOG_DEBUG, "user has empty password, access denied");
Packit 6bd9ab
      return PAM_AUTH_ERR;
Packit 6bd9ab
    }
Packit 6bd9ab
    /* try authenticating */
Packit 6bd9ab
    rc = nslcd_request_authc(pamh, &cfg, username, service, ruser, rhost,
Packit 6bd9ab
                             tty, oldpassword, &resp, NULL);
Packit 6bd9ab
    if (rc != PAM_SUCCESS)
Packit 6bd9ab
      return remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
    /* handle authentication result */
Packit 6bd9ab
    if (resp.res != PAM_SUCCESS)
Packit 6bd9ab
      pam_syslog(pamh, LOG_NOTICE, "%s; user=%s",
Packit 6bd9ab
                 pam_strerror(pamh, resp.res), username);
Packit 6bd9ab
    else if (cfg.debug)
Packit 6bd9ab
      pam_syslog(pamh, LOG_DEBUG, "authentication succeeded");
Packit 6bd9ab
    /* remap error code */
Packit 6bd9ab
    return remap_pam_rc(resp.res, &cfg;;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* get the old password (from the previous call) */
Packit 6bd9ab
  rc = pam_get_item(pamh, PAM_OLDAUTHTOK, (PAM_ITEM_CONST void **)&oldpassword);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return rc;
Packit 6bd9ab
  /* prompt for new password */
Packit 6bd9ab
  rc = pam_get_authtok(pamh, PAM_AUTHTOK, &newpassword, NULL);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    return rc;
Packit 6bd9ab
  /* perform the password modification */
Packit 6bd9ab
  rc = nslcd_request_pwmod(pamh, &cfg, username, service, ruser, rhost, tty,
Packit 6bd9ab
                           ctx->asroot, oldpassword, newpassword, &resp);
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
    msg = pam_strerror(pamh, rc);
Packit 6bd9ab
  else
Packit 6bd9ab
  {
Packit 6bd9ab
    rc = resp.res;
Packit 6bd9ab
    msg = resp.msg;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* remap error code */
Packit 6bd9ab
  rc = remap_pam_rc(rc, &cfg;;
Packit 6bd9ab
  /* check the returned value */
Packit 6bd9ab
  if (rc != PAM_SUCCESS)
Packit 6bd9ab
  {
Packit 6bd9ab
    pam_syslog(pamh, LOG_NOTICE, "password change failed: %s; user=%s",
Packit 6bd9ab
               msg, username);
Packit 6bd9ab
    if ((rc != PAM_IGNORE) && (!cfg.no_warn))
Packit 6bd9ab
      pam_error(pamh, "%s", msg);
Packit 6bd9ab
    return rc;
Packit 6bd9ab
  }
Packit 6bd9ab
  pam_syslog(pamh, LOG_NOTICE, "password changed for %s", username);
Packit 6bd9ab
  return PAM_SUCCESS;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
#ifdef PAM_STATIC
Packit 6bd9ab
struct pam_module PAM_NAME(modstruct) = {
Packit 6bd9ab
  "pam_" MODULE_NAME,
Packit 6bd9ab
  pam_sm_authenticate,
Packit 6bd9ab
  pam_sm_setcred,
Packit 6bd9ab
  pam_sm_acct_mgmt,
Packit 6bd9ab
  pam_sm_open_session,
Packit 6bd9ab
  pam_sm_close_session,
Packit 6bd9ab
  pam_sm_chauthtok
Packit 6bd9ab
};
Packit 6bd9ab
#endif /* PAM_STATIC */