|
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 */
|