From 8b5489e681b95460de78a7ab2046eaa804d75996 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Fri, 17 Apr 2009 12:11:33 +0000 Subject: [PATCH] Add pam support (work in progress) --- contrib/slapd-modules/nssov/Makefile | 2 +- contrib/slapd-modules/nssov/nss-ldapd/nslcd.h | 6 + .../nssov/nss-ldapd/nss/exports.linux | 8 + .../slapd-modules/nssov/nss-ldapd/nss/pam.c | 657 ++++++++++++++++++ contrib/slapd-modules/nssov/nssov.c | 2 - contrib/slapd-modules/nssov/nssov.h | 5 + contrib/slapd-modules/nssov/pam.c | 213 ++++++ 7 files changed, 890 insertions(+), 3 deletions(-) create mode 100644 contrib/slapd-modules/nssov/nss-ldapd/nss/pam.c create mode 100644 contrib/slapd-modules/nssov/pam.c diff --git a/contrib/slapd-modules/nssov/Makefile b/contrib/slapd-modules/nssov/Makefile index 1d231ef57d..dd21999262 100644 --- a/contrib/slapd-modules/nssov/Makefile +++ b/contrib/slapd-modules/nssov/Makefile @@ -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 diff --git a/contrib/slapd-modules/nssov/nss-ldapd/nslcd.h b/contrib/slapd-modules/nssov/nss-ldapd/nslcd.h index 38b0962ffa..8a2a999d27 100644 --- a/contrib/slapd-modules/nssov/nss-ldapd/nslcd.h +++ b/contrib/slapd-modules/nssov/nss-ldapd/nslcd.h @@ -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 */ diff --git a/contrib/slapd-modules/nssov/nss-ldapd/nss/exports.linux b/contrib/slapd-modules/nssov/nss-ldapd/nss/exports.linux index 62c031399f..c7f9b1e6e3 100644 --- a/contrib/slapd-modules/nssov/nss-ldapd/nss/exports.linux +++ b/contrib/slapd-modules/nssov/nss-ldapd/nss/exports.linux @@ -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: *; diff --git a/contrib/slapd-modules/nssov/nss-ldapd/nss/pam.c b/contrib/slapd-modules/nssov/nss-ldapd/nss/pam.c new file mode 100644 index 0000000000..23de682a47 --- /dev/null +++ b/contrib/slapd-modules/nssov/nss-ldapd/nss/pam.c @@ -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 +#include +#include +#include + +#include "prototypes.h" +#include "common.h" +#include "compat/attrs.h" + +#ifndef HAVE_PAM_PAM_MODULES_H +#include +#else +#include +#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 */ diff --git a/contrib/slapd-modules/nssov/nssov.c b/contrib/slapd-modules/nssov/nssov.c index ceb3621d50..10f6178e83 100644 --- a/contrib/slapd-modules/nssov/nssov.c +++ b/contrib/slapd-modules/nssov/nssov.c @@ -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; diff --git a/contrib/slapd-modules/nssov/nssov.h b/contrib/slapd-modules/nssov/nssov.h index 01303ac57d..d8c6f6832d 100644 --- a/contrib/slapd-modules/nssov/nssov.h +++ b/contrib/slapd-modules/nssov/nssov.h @@ -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) \ diff --git a/contrib/slapd-modules/nssov/pam.c b/contrib/slapd-modules/nssov/pam.c new file mode 100644 index 0000000000..2f69d94902 --- /dev/null +++ b/contrib/slapd-modules/nssov/pam.c @@ -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 + * . + */ + +#include "nssov.h" + +#include + +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=+uid=,cn=,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; +} -- 2.39.5