]> git.sur5r.net Git - openldap/commitdiff
Add pam support (work in progress)
authorHoward Chu <hyc@openldap.org>
Fri, 17 Apr 2009 12:11:33 +0000 (12:11 +0000)
committerHoward Chu <hyc@openldap.org>
Fri, 17 Apr 2009 12:11:33 +0000 (12:11 +0000)
contrib/slapd-modules/nssov/Makefile
contrib/slapd-modules/nssov/nss-ldapd/nslcd.h
contrib/slapd-modules/nssov/nss-ldapd/nss/exports.linux
contrib/slapd-modules/nssov/nss-ldapd/nss/pam.c [new file with mode: 0644]
contrib/slapd-modules/nssov/nssov.c
contrib/slapd-modules/nssov/nssov.h
contrib/slapd-modules/nssov/pam.c [new file with mode: 0644]

index 1d231ef57d5317721a1d6477cd820906b24f8ba5..dd2199926286016533f90cb50e7e7cce0227f394 100644 (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
 
index 38b0962ffa0307dfaac3705aefd7bb5590e97c81..8a2a999d271b6f73bf1693e40724923b3e29eae4 100644 (file)
 #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 */
index 62c031399ff20bb941544b54a80af6a4f9e9ce70..c7f9b1e6e3babee5103df6fbcddcf6297f85b717 100644 (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:
     *;
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 (file)
index 0000000..23de682
--- /dev/null
@@ -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 */
index ceb3621d5096315fcd0f7b355a14ed5fdace17c8..10f6178e83a777dcd3e08e3e9a82cb93467709d3 100644 (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;
index 01303ac57dd8fac3ddfaad9fd6f879435e297a20..d8c6f6832d54f69144704d89d8d126d46c453c19 100644 (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) \
diff --git a/contrib/slapd-modules/nssov/pam.c b/contrib/slapd-modules/nssov/pam.c
new file mode 100644 (file)
index 0000000..2f69d94
--- /dev/null
@@ -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;
+}