Add pam support (work in progress)

This commit is contained in:
Howard Chu 2009-04-17 12:11:33 +00:00
parent 016500f41d
commit 8b5489e681
7 changed files with 890 additions and 3 deletions

View File

@ -32,7 +32,7 @@ all: nssov.la
XOBJS = tio.lo
OBJS = alias.lo ether.lo group.lo host.lo netgroup.lo network.lo \
nssov.lo passwd.lo protocol.lo rpc.lo service.lo shadow.lo
nssov.lo passwd.lo protocol.lo rpc.lo service.lo shadow.lo pam.lo
.SUFFIXES: .c .o .lo

View File

@ -197,6 +197,12 @@
#define NSLCD_ACTION_SHADOW_BYNAME 2001
#define NSLCD_ACTION_SHADOW_ALL 2005
#define NSLCD_ACTION_PAM_AUTHC 20001
#define NSLCD_ACTION_PAM_AUTHZ 20002
#define NSLCD_ACTION_PAM_SESS_O 20003
#define NSLCD_ACTION_PAM_SESS_C 20004
#define NSLCD_ACTION_PAM_PWMOD 20005
/* Request result codes. */
#define NSLCD_RESULT_END 3 /* key was not found */
#define NSLCD_RESULT_SUCCESS 0 /* everything ok */

View File

@ -78,6 +78,14 @@ EXPORTED {
_nss_ldap_getspent_r;
_nss_ldap_endspent;
# pam - pluggable auth
pam_sm_acct_mgmt;
pam_sm_authenticate;
pam_sm_chauthtok;
pam_sm_close_session;
pam_sm_open_session;
pam_sm_setcred;
# everything else should not be exported
local:
*;

View File

@ -0,0 +1,657 @@
/*
pam.c - pam module functions
Copyright (C) 2009 Howard Chu
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include "prototypes.h"
#include "common.h"
#include "compat/attrs.h"
#ifndef HAVE_PAM_PAM_MODULES_H
#include <security/pam_modules.h>
#else
#include <pam/pam_modules.h>
#endif
#define CONST_ARG const
#define IGNORE_UNKNOWN 1
#define IGNORE_UNAVAIL 2
#define PLD_CTX "PAM_LDAPD_CTX"
#define NSS2PAM_RC(rc,ignore,ok) \
switch(rc) { \
case NSS_STATUS_SUCCESS: \
rc = ok; break; \
case NSS_STATUS_UNAVAIL: \
rc = (ignore & IGNORE_UNAVAIL) ? PAM_IGNORE : PAM_AUTHINFO_UNAVAIL; \
break; \
case NSS_STATUS_NOTFOUND: \
rc = (ignore & IGNORE_UNKNOWN) ? PAM_IGNORE: PAM_USER_UNKNOWN; \
break; \
default: \
rc = PAM_SYSTEM_ERR; break; \
}
typedef struct pld_ctx {
char *user;
char *dn;
char *tmpluser;
char *authzmsg;
int authok;
int authz;
char buf[1024];
} pld_ctx;
static void pam_clr_ctx(
pld_ctx *ctx)
{
if (ctx->user) {
free(ctx->user);
ctx->user = NULL;
}
ctx->dn = NULL;
ctx->tmpluser = NULL;
ctx->authzmsg = NULL;
ctx->authok = 0;
ctx->authz = 0;
}
static void pam_del_ctx(
pam_handle_t *pamh, void *data, int err)
{
pld_ctx *ctx = data;
pam_clr_ctx(ctx);
free(ctx);
}
static int pam_get_ctx(
pam_handle_t *pamh, const char *user, pld_ctx **pctx)
{
pld_ctx *ctx = NULL;
int rc;
if (pam_get_data(pamh, PLD_CTX, (CONST_ARG void **)&ctx) == PAM_SUCCESS) {
if (ctx->user && strcmp(ctx->user, user)) {
pam_clr_ctx(ctx);
}
rc = PAM_SUCCESS;
}
if (!ctx) {
ctx = calloc(1, sizeof(*ctx));
if (!ctx)
return PAM_BUF_ERR;
rc = pam_set_data(pamh, PLD_CTX, ctx, pam_del_ctx);
if (rc != PAM_SUCCESS)
pam_del_ctx(pamh, ctx, 0);
}
if (rc == PAM_SUCCESS)
*pctx = ctx;
return rc;
}
static int pam_get_authtok(
pam_handle_t *pamh, int flags, char *prompt1, char *prompt2, char **pwd)
{
int rc;
char *p;
struct pam_message msg[1], *pmsg[1];
struct pam_response *resp;
struct pam_conv *conv;
*pwd = NULL;
rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &conv);
if (rc == PAM_SUCCESS) {
pmsg[0] = &msg[0];
msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
msg[0].msg = prompt1;
resp = NULL;
rc = conv->conv (1,
(CONST_ARG struct pam_message **) pmsg,
&resp, conv->appdata_ptr);
} else {
return rc;
}
if (resp != NULL) {
if ((flags & PAM_DISALLOW_NULL_AUTHTOK) && resp[0].resp == NULL)
{
free (resp);
return PAM_AUTH_ERR;
}
p = resp[0].resp;
resp[0].resp = NULL;
free (resp);
} else {
return PAM_CONV_ERR;
}
if (prompt2) {
msg[0].msg = prompt2;
resp = NULL;
rc = conv->conv (1,
(CONST_ARG struct pam_message **) pmsg,
&resp, conv->appdata_ptr);
if (resp && resp[0].resp && !strcmp(resp[0].resp, p))
rc = PAM_SUCCESS;
else
rc = PAM_AUTHTOK_RECOVERY_ERR;
if (resp) {
if (resp[0].resp) {
(void) memset(resp[0].resp, 0, strlen(resp[0].resp));
free(resp[0].resp);
}
free(resp);
}
}
if (rc == PAM_SUCCESS)
*pwd = p;
else if (p) {
memset(p, 0, strlen(p));
free(p);
}
return rc;
}
static enum nss_status pam_read_authc(
TFILE *fp,pld_ctx *ctx,int *errnop)
{
char *buffer = ctx->buf;
size_t buflen = sizeof(ctx->buf);
size_t bufptr = 0;
int32_t tmpint32;
READ_INT32(fp,ctx->authok);
READ_INT32(fp,ctx->authz);
READ_STRING_BUF(fp,ctx->dn);
READ_STRING_BUF(fp,ctx->authzmsg);
READ_STRING_BUF(fp,ctx->tmpluser);
return NSS_STATUS_SUCCESS;
}
static enum nss_status pam_do_authc(
pld_ctx *ctx, const char *name, const char *svc,const char *pwd,int *errnop)
{
NSS_BYGEN(NSLCD_ACTION_PAM_AUTHC,
WRITE_STRING(fp,name);
WRITE_STRING(fp,svc);
WRITE_STRING(fp,pwd),
pam_read_authc(fp,ctx,errnop));
}
#define USE_FIRST 1
#define TRY_FIRST 2
#define USE_TOKEN 4
int pam_sm_authenticate(
pam_handle_t *pamh, int flags, int argc, const char **argv)
{
int err, rc;
const char *username, *svc;
char *p = NULL;
int first_pass = 0, ignore_flags = 0;
int i;
pld_ctx *ctx;
for (i = 0; i < argc; i++) {
if (!strcmp (argv[i], "use_first_pass"))
first_pass |= USE_FIRST;
else if (!strcmp (argv[i], "try_first_pass"))
first_pass |= TRY_FIRST;
else if (!strcmp (argv[i], "ignore_unknown_user"))
ignore_flags |= IGNORE_UNKNOWN;
else if (!strcmp (argv[i], "ignore_authinfo_unavail"))
ignore_flags |= IGNORE_UNAVAIL;
else if (!strcmp (argv[i], "no_warn"))
;
else if (!strcmp (argv[i], "debug"))
;
else
syslog (LOG_ERR, "illegal option %s", argv[i]);
}
rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL);
if (rc != PAM_SUCCESS)
return rc;
rc = pam_get_ctx(pamh, username, &ctx);
if (rc != PAM_SUCCESS)
return rc;
rc = pam_get_item (pamh, PAM_SERVICE, (CONST_ARG void **) &svc);
if (rc != PAM_SUCCESS)
return rc;
for (i=0;i<2;i++) {
if (!first_pass) {
rc = pam_get_authtok(pamh, flags, i ? "LDAP Password: " :
"Password: ", NULL, &p);
i = 2;
if (rc == PAM_SUCCESS) {
pam_set_item(pamh, PAM_AUTHTOK, p);
memset(p, 0, strlen(p));
free(p);
} else {
break;
}
}
rc = pam_get_item (pamh, PAM_AUTHTOK, (CONST_ARG void **) &p);
if (rc == PAM_SUCCESS) {
rc = pam_do_authc(ctx, username, svc, p, &err);
NSS2PAM_RC(rc, ignore_flags, ctx->authok);
}
if (rc == PAM_SUCCESS || (first_pass & USE_FIRST)) {
break;
}
first_pass = 0;
}
if (rc == PAM_SUCCESS)
ctx->user = strdup(username);
return rc;
}
int pam_sm_setcred(
pam_handle_t *pamh, int flags, int argc, const char **argv)
{
return PAM_SUCCESS;
}
static int
pam_warn(
struct pam_conv *aconv, const char *message, int style, int no_warn)
{
struct pam_message msg, *pmsg;
struct pam_response *resp;
if (no_warn)
return PAM_SUCCESS;
pmsg = &msg;
msg.msg_style = style;
msg.msg = (char *) message;
resp = NULL;
return aconv->conv (1,
(CONST_ARG struct pam_message **) &pmsg,
&resp, aconv->appdata_ptr);
}
static enum nss_status pam_read_authz(
TFILE *fp,pld_ctx *ctx,int *errnop)
{
char *buffer = ctx->buf;
size_t buflen = sizeof(ctx->buf);
size_t bufptr = 0;
int32_t tmpint32;
READ_INT32(fp,ctx->authz);
READ_STRING_BUF(fp,ctx->authzmsg);
return NSS_STATUS_SUCCESS;
}
static enum nss_status pam_do_authz(
pld_ctx *ctx, const char *svc,int *errnop)
{
NSS_BYGEN(NSLCD_ACTION_PAM_AUTHZ,
WRITE_STRING(fp,ctx->dn);
WRITE_STRING(fp,svc),
pam_read_authz(fp,ctx,errnop));
}
int pam_sm_acct_mgmt(
pam_handle_t *pamh, int flags, int argc, const char **argv)
{
int rc, err;
const char *username, *svc;
int no_warn = 0, ignore_flags = 0;
int i;
struct pam_conv *appconv;
pld_ctx *ctx = NULL, ctx2;
for (i = 0; i < argc; i++)
{
if (!strcmp (argv[i], "use_first_pass"))
;
else if (!strcmp (argv[i], "try_first_pass"))
;
else if (!strcmp (argv[i], "no_warn"))
no_warn = 1;
else if (!strcmp (argv[i], "ignore_unknown_user"))
ignore_flags |= IGNORE_UNKNOWN;
else if (!strcmp (argv[i], "ignore_authinfo_unavail"))
ignore_flags |= IGNORE_UNAVAIL;
else if (!strcmp (argv[i], "debug"))
;
else
syslog (LOG_ERR, "illegal option %s", argv[i]);
}
if (flags & PAM_SILENT)
no_warn = 1;
rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &appconv);
if (rc != PAM_SUCCESS)
return rc;
rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL);
if (rc != PAM_SUCCESS)
return rc;
if (username == NULL)
return PAM_USER_UNKNOWN;
rc = pam_get_ctx(pamh, username, &ctx);
if (rc != PAM_SUCCESS)
return rc;
rc = pam_get_item (pamh, PAM_SERVICE, (CONST_ARG void **) &svc);
if (rc != PAM_SUCCESS)
return rc;
ctx2.dn = ctx->dn;
rc = pam_do_authz(&ctx2, svc, &err);
NSS2PAM_RC(rc, ignore_flags, PAM_SUCCESS);
if (rc != PAM_SUCCESS) {
if (rc != PAM_IGNORE)
pam_warn(appconv, "LDAP authorization failed", PAM_ERROR_MSG, no_warn);
} else {
if (ctx2.authz != PAM_SUCCESS)
pam_warn(appconv, ctx2.authzmsg, PAM_ERROR_MSG, no_warn);
else if ( ctx->authz != PAM_SUCCESS ) {
rc = ctx->authz;
pam_warn(appconv, ctx->authzmsg, PAM_ERROR_MSG, no_warn);
}
}
if ( rc == PAM_SUCCESS && ctx->tmpluser && ctx->tmpluser[0] ) {
rc = pam_set_item(pamh, PAM_USER, ctx->tmpluser);
}
return rc;
}
static enum nss_status pam_do_sess_o(
pld_ctx *ctx, const char *svc,int *errnop)
{
NSS_BYGEN(NSLCD_ACTION_PAM_SESS_O,
WRITE_STRING(fp,ctx->dn);
WRITE_STRING(fp,svc),
NSS_STATUS_SUCCESS);
}
int pam_sm_open_session(
pam_handle_t *pamh, int flags, int argc, const char **argv)
{
int rc, err;
const char *username, *svc;
int no_warn = 0, ignore_flags = 0;
int i, success = PAM_SUCCESS;
struct pam_conv *appconv;
pld_ctx *ctx = NULL;
for (i = 0; i < argc; i++)
{
if (!strcmp (argv[i], "use_first_pass"))
;
else if (!strcmp (argv[i], "try_first_pass"))
;
else if (!strcmp (argv[i], "no_warn"))
no_warn = 1;
else if (!strcmp (argv[i], "ignore_unknown_user"))
ignore_flags |= IGNORE_UNKNOWN;
else if (!strcmp (argv[i], "ignore_authinfo_unavail"))
ignore_flags |= IGNORE_UNAVAIL;
else if (!strcmp (argv[i], "debug"))
;
else
syslog (LOG_ERR, "illegal option %s", argv[i]);
}
if (flags & PAM_SILENT)
no_warn = 1;
rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &appconv);
if (rc != PAM_SUCCESS)
return rc;
rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL);
if (rc != PAM_SUCCESS)
return rc;
if (username == NULL)
return PAM_USER_UNKNOWN;
rc = pam_get_ctx(pamh, username, &ctx);
if (rc != PAM_SUCCESS)
return rc;
rc = pam_get_item (pamh, PAM_SERVICE, (CONST_ARG void **) &svc);
if (rc != PAM_SUCCESS)
return rc;
rc = pam_do_sess_o(ctx, svc, &err);
NSS2PAM_RC(rc, ignore_flags, PAM_SUCCESS);
if (rc != PAM_SUCCESS && rc != PAM_IGNORE)
pam_warn(appconv, "LDAP open_session failed", PAM_ERROR_MSG, no_warn);
return rc;
}
static enum nss_status pam_do_sess_c(
pld_ctx *ctx, const char *svc,int *errnop)
{
NSS_BYGEN(NSLCD_ACTION_PAM_SESS_C,
WRITE_STRING(fp,ctx->dn);
WRITE_STRING(fp,svc),
NSS_STATUS_SUCCESS);
}
int pam_sm_close_session(
pam_handle_t *pamh, int flags, int argc, const char **argv)
{
int rc, err;
const char *username, *svc;
int no_warn = 0, ignore_flags = 0;
int i, success = PAM_SUCCESS;
struct pam_conv *appconv;
pld_ctx *ctx = NULL;
for (i = 0; i < argc; i++)
{
if (!strcmp (argv[i], "use_first_pass"))
;
else if (!strcmp (argv[i], "try_first_pass"))
;
else if (!strcmp (argv[i], "no_warn"))
no_warn = 1;
else if (!strcmp (argv[i], "ignore_unknown_user"))
ignore_flags |= IGNORE_UNKNOWN;
else if (!strcmp (argv[i], "ignore_authinfo_unavail"))
ignore_flags |= IGNORE_UNAVAIL;
else if (!strcmp (argv[i], "debug"))
;
else
syslog (LOG_ERR, "illegal option %s", argv[i]);
}
if (flags & PAM_SILENT)
no_warn = 1;
rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &appconv);
if (rc != PAM_SUCCESS)
return rc;
rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL);
if (rc != PAM_SUCCESS)
return rc;
if (username == NULL)
return PAM_USER_UNKNOWN;
rc = pam_get_ctx(pamh, username, &ctx);
if (rc != PAM_SUCCESS)
return rc;
rc = pam_get_item (pamh, PAM_SERVICE, (CONST_ARG void **) &svc);
if (rc != PAM_SUCCESS)
return rc;
rc = pam_do_sess_c(ctx, svc, &err);
NSS2PAM_RC(rc, ignore_flags, PAM_SUCCESS);
if (rc != PAM_SUCCESS && rc != PAM_IGNORE)
pam_warn(appconv, "LDAP close_session failed", PAM_ERROR_MSG, no_warn);
return rc;
}
static enum nss_status pam_do_pwmod(
pld_ctx *ctx, const char *oldpw, const char *newpw, int *errnop)
{
NSS_BYGEN(NSLCD_ACTION_PAM_SESS_C,
WRITE_STRING(fp,ctx->dn);
WRITE_STRING(fp,ctx->user);
WRITE_STRING(fp,oldpw);
WRITE_STRING(fp,newpw),
pam_read_authz(fp,ctx,errnop));
}
int pam_sm_chauthtok(
pam_handle_t *pamh, int flags, int argc, const char **argv)
{
int rc, err;
const char *username, *p = NULL, *q = NULL;
int first_pass = 0, no_warn = 0, ignore_flags = 0;
int i, success = PAM_SUCCESS;
struct pam_conv *appconv;
pld_ctx *ctx = NULL;
for (i = 0; i < argc; i++)
{
if (!strcmp (argv[i], "use_first_pass"))
first_pass |= USE_FIRST;
else if (!strcmp (argv[i], "try_first_pass"))
first_pass |= TRY_FIRST;
else if (!strcmp (argv[i], "use_authtok"))
first_pass |= USE_TOKEN;
else if (!strcmp (argv[i], "no_warn"))
no_warn = 1;
else if (!strcmp (argv[i], "ignore_unknown_user"))
ignore_flags |= IGNORE_UNKNOWN;
else if (!strcmp (argv[i], "ignore_authinfo_unavail"))
ignore_flags |= IGNORE_UNAVAIL;
else if (!strcmp (argv[i], "debug"))
;
else
syslog (LOG_ERR, "illegal option %s", argv[i]);
}
if (flags & PAM_SILENT)
no_warn = 1;
rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &appconv);
if (rc != PAM_SUCCESS)
return rc;
rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL);
if (rc != PAM_SUCCESS)
return rc;
if (username == NULL)
return PAM_USER_UNKNOWN;
rc = pam_get_ctx(pamh, username, &ctx);
if (rc != PAM_SUCCESS)
return rc;
if (flags & PAM_PRELIM_CHECK) {
if (getuid()) {
if (!first_pass) {
rc = pam_get_authtok(pamh, flags, "(current) LDAP Password: ",
NULL, &p);
if (rc == PAM_SUCCESS) {
pam_set_item(pamh, PAM_OLDAUTHTOK, p);
memset(p, 0, strlen(p));
free(p);
}
}
} else {
rc = PAM_SUCCESS;
}
return rc;
}
if (getuid()) {
rc = pam_get_item(pamh, PAM_OLDAUTHTOK, &p);
if (rc) return rc;
}
if (first_pass) {
rc = pam_get_item(pamh, PAM_AUTHTOK, &q);
if ((rc != PAM_SUCCESS || !q) && (first_pass & (USE_FIRST|USE_TOKEN))) {
if (rc == PAM_SUCCESS)
rc = PAM_AUTHTOK_RECOVERY_ERR;
return rc;
}
}
if (!q) {
rc = pam_get_authtok(pamh, flags, "Enter new LDAP Password: ",
"Retype new LDAP Password: ", &q);
if (rc == PAM_SUCCESS) {
pam_set_item(pamh, PAM_AUTHTOK, q);
memset(q, 0, strlen(q));
free(q);
rc = pam_get_item(pamh, PAM_AUTHTOK, &q);
}
if (rc != PAM_SUCCESS)
return rc;
}
rc = pam_do_pwmod(ctx, p, q, &err);
p = NULL; q = NULL;
NSS2PAM_RC(rc, ignore_flags, PAM_SUCCESS);
if (rc == PAM_SUCCESS) {
rc = ctx->authz;
if (rc != PAM_SUCCESS)
pam_warn(appconv, ctx->authzmsg, PAM_ERROR_MSG, no_warn);
} else if (rc != PAM_IGNORE)
pam_warn(appconv, "LDAP pwmod failed", PAM_ERROR_MSG, no_warn);
return rc;
}
#ifdef PAM_STATIC
struct pam_module _modstruct = {
"pam_ldapd",
pam_sm_authenticate,
pam_sm_setcred,
pam_sm_acct_mgmt,
pam_sm_open_session,
pam_sm_close_session,
pam_sm_chauthtok
};
#endif /* PAM_STATIC */

View File

@ -322,13 +322,11 @@ static void handleconnection(nssov_info *ni,int sock,Operation *op)
case NSLCD_ACTION_SERVICE_ALL: (void)nssov_service_all(ni,fp,op); break;
case NSLCD_ACTION_SHADOW_BYNAME: if (uid==0) (void)nssov_shadow_byname(ni,fp,op); break;
case NSLCD_ACTION_SHADOW_ALL: if (uid==0) (void)nssov_shadow_all(ni,fp,op); break;
#ifdef notyet
case NSLCD_ACTION_PAM_AUTHC: (void)pam_authc(ni,fp,op); break;
case NSLCD_ACTION_PAM_AUTHZ: (void)pam_authz(ni,fp,op); break;
case NSLCD_ACTION_PAM_SESS_O: (void)pam_sess_o(ni,fp,op); break;
case NSLCD_ACTION_PAM_SESS_C: (void)pam_sess_c(ni,fp,op); break;
case NSLCD_ACTION_PAM_PWMOD: (void)pam_pwmod(ni,fp,op); break;
#endif
default:
Debug( LDAP_DEBUG_ANY,"nssov: invalid request id: %d",(int)action,0,0);
break;

View File

@ -195,6 +195,11 @@ int nssov_service_bynumber(nssov_info *ni,TFILE *fp,Operation *op);
int nssov_service_all(nssov_info *ni,TFILE *fp,Operation *op);
int nssov_shadow_byname(nssov_info *ni,TFILE *fp,Operation *op);
int nssov_shadow_all(nssov_info *ni,TFILE *fp,Operation *op);
int pam_authc(nssov_info *ni,TFILE *fp,Operation *op);
int pam_authz(nssov_info *ni,TFILE *fp,Operation *op);
int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op);
int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op);
int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op);
/* config initialization */
#define NSSOV_INIT(db) \

View File

@ -0,0 +1,213 @@
/* pam.c - pam processing routines */
/* $OpenLDAP$ */
/*
* Copyright 2009 by Howard Chu, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "nssov.h"
#include <security/pam_modules.h>
static int pam_nullcb(
Operation *op, SlapReply *rs)
{
return LDAP_SUCCESS;
}
int pam_authc(nssov_info *ni,TFILE *fp,Operation *op)
{
int32_t tmpint32;
int rc;
slap_callback cb = {0};
SlapReply rs = {REP_RESULT};
char uidc[32];
char svcc[256];
char pwdc[256];
struct berval uid, svc, pwd, sdn, dn;
int hlen;
READ_STRING_BUF2(fp,uidc,sizeof(uidc));
uid.bv_val = uidc;
uid.bv_len = tmpint32;
READ_STRING_BUF2(fp,svcc,sizeof(svcc));
svc.bv_val = svcc;
svc.bv_len = tmpint32;
READ_STRING_BUF2(fp,pwdc,sizeof(pwdc));
pwd.bv_val = pwdc;
pwd.bv_len = tmpint32;
Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n",uid.bv_val,0,0);
if (!isvalidusername(&uid)) {
Debug(LDAP_DEBUG_ANY,"nssov_pam_authc(%s): invalid user name\n",uid.bv_val,0,0);
rc = PAM_USER_UNKNOWN;
goto finish;
}
/* Why didn't we make this a berval? */
hlen = strlen(global_host);
/* First try this form, to allow service-dependent mappings */
/* cn=<service>+uid=<user>,cn=<host>,cn=pam,cn=auth */
sdn.bv_len = uid.bv_len + svc.bv_len + hlen + STRLENOF( "cn=+uid=,cn=,cn=pam,cn=auth" );
sdn.bv_val = op->o_tmpalloc( sdn.bv_len + 1, op->o_tmpmemctx );
sprintf(sdn.bv_val, "cn=%s+uid=%s,cn=%s,cn=pam,cn=auth", svcc, uidc, global_host);
BER_BVZERO(&dn);
slap_sasl2dn(op, &sdn, &dn, 0);
op->o_tmpfree( sdn.bv_val, op->o_tmpmemctx );
/* If no luck, do a basic uid search */
if (BER_BVISEMPTY(&dn)) {
if (!nssov_uid2dn(op, ni, &uid, &dn)) {
rc = PAM_USER_UNKNOWN;
goto finish;
}
sdn = dn;
dnNormalize( 0, NULL, NULL, &sdn, &dn, op->o_tmpmemctx );
}
BER_BVZERO(&sdn);
/* TODO: add ppolicy control */
cb.sc_response = pam_nullcb;
op->o_callback = &cb;
op->o_dn.bv_val[0] = 0;
op->o_dn.bv_len = 0;
op->o_ndn.bv_val[0] = 0;
op->o_ndn.bv_len = 0;
op->o_tag = LDAP_REQ_BIND;
op->o_protocol = LDAP_VERSION3;
op->orb_method = LDAP_AUTH_SIMPLE;
op->orb_cred = pwd;
op->o_req_dn = dn;
op->o_req_ndn = dn;
slap_op_time( &op->o_time, &op->o_tincr );
op->o_bd->be_bind( op, &rs );
memset(pwd.bv_val,0,pwd.bv_len);
switch(rs.sr_err) {
case LDAP_SUCCESS: rc = PAM_SUCCESS; break;
case LDAP_INVALID_CREDENTIALS: rc = PAM_AUTH_ERR; break;
default: rc = PAM_AUTH_ERR; break;
}
finish:
WRITE_INT32(fp,NSLCD_VERSION);
WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC);
WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
WRITE_INT32(fp,rc);
WRITE_INT32(fp,PAM_SUCCESS); /* authz */
WRITE_BERVAL(fp,&dn);
WRITE_BERVAL(fp,&sdn); /* authzmsg */
WRITE_BERVAL(fp,&sdn); /* tmpluser */
return 0;
}
int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
{
struct berval dn, svc;
struct berval authzmsg = BER_BVNULL;
int32_t tmpint32;
char dnc[1024];
char svcc[256];
READ_STRING_BUF2(fp,dnc,sizeof(dnc));
dn.bv_val = dnc;
dn.bv_len = tmpint32;
READ_STRING_BUF2(fp,svcc,sizeof(svcc));
svc.bv_val = svcc;
svc.bv_len = tmpint32;
Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n",dn.bv_val,0,0);
WRITE_INT32(fp,NSLCD_VERSION);
WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ);
WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
WRITE_INT32(fp,PAM_SUCCESS);
WRITE_BERVAL(fp,&authzmsg);
return 0;
}
int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op)
{
struct berval dn, svc;
int32_t tmpint32;
char dnc[1024];
char svcc[256];
READ_STRING_BUF2(fp,dnc,sizeof(dnc));
dn.bv_val = dnc;
dn.bv_len = tmpint32;
READ_STRING_BUF2(fp,svcc,sizeof(svcc));
svc.bv_val = svcc;
svc.bv_len = tmpint32;
Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_o(%s)\n",dn.bv_val,0,0);
WRITE_INT32(fp,NSLCD_VERSION);
WRITE_INT32(fp,NSLCD_ACTION_PAM_SESS_O);
WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
return 0;
}
int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op)
{
struct berval dn, svc;
int32_t tmpint32;
char dnc[1024];
char svcc[256];
READ_STRING_BUF2(fp,dnc,sizeof(dnc));
dn.bv_val = dnc;
dn.bv_len = tmpint32;
READ_STRING_BUF2(fp,svcc,sizeof(svcc));
svc.bv_val = svcc;
svc.bv_len = tmpint32;
Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_c(%s)\n",dn.bv_val,0,0);
WRITE_INT32(fp,NSLCD_VERSION);
WRITE_INT32(fp,NSLCD_ACTION_PAM_SESS_C);
WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
return 0;
}
int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op)
{
struct berval dn, uid, opw, npw;
int32_t tmpint32;
char dnc[1024];
char uidc[256];
char opwc[256];
char npwc[256];
READ_STRING_BUF2(fp,dnc,sizeof(dnc));
dn.bv_val = dnc;
dn.bv_len = tmpint32;
READ_STRING_BUF2(fp,uidc,sizeof(uidc));
uid.bv_val = uidc;
uid.bv_len = tmpint32;
READ_STRING_BUF2(fp,opwc,sizeof(opwc));
opw.bv_val = opwc;
opw.bv_len = tmpint32;
READ_STRING_BUF2(fp,npwc,sizeof(npwc));
npw.bv_val = npwc;
npw.bv_len = tmpint32;
Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(%s), %s\n",dn.bv_val,uid.bv_val,0);
BER_BVZERO(&npw);
WRITE_INT32(fp,NSLCD_VERSION);
WRITE_INT32(fp,NSLCD_ACTION_PAM_PWMOD);
WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
WRITE_INT32(fp,PAM_SUCCESS);
WRITE_BERVAL(fp,&npw);
return 0;
}