]> git.sur5r.net Git - openldap/commitdiff
Reformat requests, rough pwmod support
authorHoward Chu <hyc@openldap.org>
Mon, 20 Apr 2009 10:25:24 +0000 (10:25 +0000)
committerHoward Chu <hyc@openldap.org>
Mon, 20 Apr 2009 10:25:24 +0000 (10:25 +0000)
contrib/slapd-modules/nssov/nss-ldapd/nss/pam.c
contrib/slapd-modules/nssov/pam.c

index 281f66ff2a17ea93164afd3d0d27ccc2b1251ace..40b1e4cd6eda9e6037b0b0ecf358040d89d724f4 100644 (file)
@@ -62,6 +62,7 @@ typedef struct pld_ctx {
        char *dn;
        char *tmpluser;
        char *authzmsg;
+       char *oldpw;
        int authok;
        int authz;
        char buf[1024];
@@ -74,6 +75,11 @@ static void pam_clr_ctx(
                free(ctx->user);
                ctx->user = NULL;
        }
+       if (ctx->oldpw) {
+               memset(ctx->oldpw,0,strlen(ctx->oldpw));
+               free(ctx->oldpw);
+               ctx->oldpw = NULL;
+       }
        ctx->dn = NULL;
        ctx->tmpluser = NULL;
        ctx->authzmsg = NULL;
@@ -184,23 +190,25 @@ static int pam_get_authtok(
 static enum nss_status pam_read_authc(
        TFILE *fp,pld_ctx *ctx,int *errnop)
 {
-       char *buffer = ctx->buf;
+       char *buffer = ctx->buf, *user;
        size_t buflen = sizeof(ctx->buf);
        size_t bufptr = 0;
        int32_t tmpint32;
 
+       READ_STRING_BUF(fp,user);
+       READ_STRING_BUF(fp,ctx->dn);
        READ_INT32(fp,ctx->authok);
        READ_INT32(fp,ctx->authz);
-       READ_STRING_BUF(fp,ctx->dn);
        READ_STRING_BUF(fp,ctx->authzmsg);
        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)
+       pld_ctx *ctx, const char *user, const char *svc,const char *pwd,int *errnop)
 {
        NSS_BYGEN(NSLCD_ACTION_PAM_AUTHC,
-               WRITE_STRING(fp,name);
+               WRITE_STRING(fp,user);
+               WRITE_STRING(fp,"" /* DN */);
                WRITE_STRING(fp,svc);
                WRITE_STRING(fp,pwd),
                pam_read_authc(fp,ctx,errnop));
@@ -273,8 +281,11 @@ int pam_sm_authenticate(
                first_pass = 0;
        }
 
-       if (rc == PAM_SUCCESS)
+       if (rc == PAM_SUCCESS) {
                ctx->user = strdup(username);
+               if (ctx->authz == PAM_NEW_AUTHTOK_REQD)
+                       ctx->oldpw = strdup(p);
+       }
 
        return rc;
 }
@@ -314,9 +325,10 @@ static enum nss_status pam_read_authz(
        size_t bufptr = 0;
        int32_t tmpint32;
 
+       READ_STRING_BUF(fp,ctx->tmpluser);
+       READ_STRING_BUF(fp,ctx->dn);
        READ_INT32(fp,ctx->authz);
        READ_STRING_BUF(fp,ctx->authzmsg);
-       READ_STRING_BUF(fp,ctx->tmpluser);
        return NSS_STATUS_SUCCESS;
 }
 
@@ -324,6 +336,7 @@ 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->user);
                WRITE_STRING(fp,ctx->dn);
                WRITE_STRING(fp,svc),
                pam_read_authz(fp,ctx,errnop));
@@ -380,6 +393,7 @@ int pam_sm_acct_mgmt(
                return rc;
 
        ctx2.dn = ctx->dn;
+       ctx2.user = ctx->user;
        rc = pam_do_authz(&ctx2, svc, &err);
        NSS2PAM_RC(rc, ignore_flags, PAM_SUCCESS);
        if (rc != PAM_SUCCESS) {
@@ -404,6 +418,7 @@ 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->user);
                WRITE_STRING(fp,ctx->dn);
                WRITE_STRING(fp,svc),
                NSS_STATUS_SUCCESS);
@@ -470,6 +485,7 @@ 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->user);
                WRITE_STRING(fp,ctx->dn);
                WRITE_STRING(fp,svc),
                NSS_STATUS_SUCCESS);
@@ -535,22 +551,26 @@ int pam_sm_close_session(
 static enum nss_status pam_read_pwmod(
        TFILE *fp,pld_ctx *ctx,int *errnop)
 {
-       char *buffer = ctx->buf;
+       char *buffer = ctx->buf, *user;
        size_t buflen = sizeof(ctx->buf);
        size_t bufptr = 0;
        int32_t tmpint32;
 
+       READ_STRING_BUF(fp,user);
+       READ_STRING_BUF(fp,ctx->dn);
        READ_INT32(fp,ctx->authz);
        READ_STRING_BUF(fp,ctx->authzmsg);
        return NSS_STATUS_SUCCESS;
 }
 
 static enum nss_status pam_do_pwmod(
-       pld_ctx *ctx, const char *user, const char *oldpw, const char *newpw, int *errnop)
+       pld_ctx *ctx, const char *user, const char *svc,
+       const char *oldpw, const char *newpw, int *errnop)
 {
        NSS_BYGEN(NSLCD_ACTION_PAM_PWMOD,
-               WRITE_STRING(fp,ctx->dn);
                WRITE_STRING(fp,user);
+               WRITE_STRING(fp,ctx->dn);
+               WRITE_STRING(fp,svc);
                WRITE_STRING(fp,oldpw);
                WRITE_STRING(fp,newpw),
                pam_read_pwmod(fp,ctx,errnop));
@@ -560,7 +580,7 @@ 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;
+       const char *username, *p = NULL, *q = NULL, *svc;
        int first_pass = 0, no_warn = 0, ignore_flags = 0;
        int i, success = PAM_SUCCESS;
        struct pam_conv *appconv;
@@ -604,6 +624,10 @@ int pam_sm_chauthtok(
        if (rc != PAM_SUCCESS)
                return rc;
 
+       rc = pam_get_item (pamh, PAM_SERVICE, (CONST_ARG void **) &svc);
+       if (rc != PAM_SUCCESS)
+               return rc;
+
        if (flags & PAM_PRELIM_CHECK) {
                if (getuid()) {
                        if (!first_pass) {
@@ -615,16 +639,23 @@ int pam_sm_chauthtok(
                                        free(p);
                                }
                        }
+                       rc = pam_get_item(pamh, PAM_OLDAUTHTOK, &p);
+                       if (rc) return rc;
                } else {
                        rc = PAM_SUCCESS;
                }
+               if (!ctx->dn) {
+                       rc = pam_do_pwmod(ctx, username, svc, p, NULL, &err);
+                       NSS2PAM_RC(rc, ignore_flags, PAM_SUCCESS);
+               }
                return rc;
        }
 
-       if (getuid()) {
-               rc = pam_get_item(pamh, PAM_OLDAUTHTOK, &p);
-               if (rc) return rc;
-       }
+       rc = pam_get_item(pamh, PAM_OLDAUTHTOK, &p);
+       if (rc) return rc;
+
+       if (!p)
+               p = ctx->oldpw;
 
        if (first_pass) {
                rc = pam_get_item(pamh, PAM_AUTHTOK, &q);
@@ -646,7 +677,7 @@ int pam_sm_chauthtok(
                if (rc != PAM_SUCCESS)
                        return rc;
        }
-       rc = pam_do_pwmod(ctx, username, p, q, &err);
+       rc = pam_do_pwmod(ctx, username, svc, p, q, &err);
        p = NULL; q = NULL;
        NSS2PAM_RC(rc, ignore_flags, PAM_SUCCESS);
        if (rc == PAM_SUCCESS) {
index b735465e7c4cd8509e2d6e24a10c32eec0b94e63..a960547fe08212776f1eb11ebed8fd48cf80b375 100644 (file)
 
 static int ppolicy_cid;
 
-struct bindinfo {
+struct paminfo {
+       struct berval uid;
+       struct berval dn;
+       struct berval svc;
+       struct berval pwd;
        int authz;
        struct berval msg;
 };
@@ -27,7 +31,7 @@ struct bindinfo {
 static int pam_bindcb(
        Operation *op, SlapReply *rs)
 {
-       struct bindinfo *bi = op->o_callback->sc_private;
+       struct paminfo *pi = op->o_callback->sc_private;
        LDAPControl *ctrl = ldap_control_find(LDAP_CONTROL_PASSWORDPOLICYRESPONSE,
                rs->sr_ctrls, NULL);
        if (ctrl) {
@@ -68,23 +72,23 @@ static int pam_bindcb(
                                                unit = "years";
                                        }
 #endif
-                                       bi->msg.bv_len = sprintf(bi->msg.bv_val,
+                                       pi->msg.bv_len = sprintf(pi->msg.bv_val,
                                                "\nWARNING: Password expires in %d %s\n", expire, unit);
                                } else if (grace > 0) {
-                                       bi->msg.bv_len = sprintf(bi->msg.bv_val,
+                                       pi->msg.bv_len = sprintf(pi->msg.bv_val,
                                                "Password expired; %d grace logins remaining",
                                                grace);
-                                       bi->authz = PAM_NEW_AUTHTOK_REQD;
+                                       pi->authz = PAM_NEW_AUTHTOK_REQD;
                                } else if (error != PP_noError) {
                                        ber_str2bv(ldap_passwordpolicy_err2txt(error), 0, 0,
-                                               &bi->msg);
+                                               &pi->msg);
                                        switch (error) {
                                        case PP_passwordExpired:
                                                /* report this during authz */
                                                rs->sr_err = LDAP_SUCCESS;
                                                /* fallthru */
                                        case PP_changeAfterReset:
-                                               bi->authz = PAM_NEW_AUTHTOK_REQD;
+                                               pi->authz = PAM_NEW_AUTHTOK_REQD;
                                        }
                                }
                        }
@@ -94,69 +98,58 @@ static int pam_bindcb(
        return LDAP_SUCCESS;
 }
 
-int pam_authc(nssov_info *ni,TFILE *fp,Operation *op)
+int pam_do_bind(nssov_info *ni,TFILE *fp,Operation *op,
+       struct paminfo *pi)
 {
-       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;
-       struct bindinfo bi;
-
-       bi.authz = PAM_SUCCESS;
-       bi.msg.bv_val = pwdc;
-       bi.msg.bv_len = 0;
-
-       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;
+       struct berval sdn;
 
-       Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n",uid.bv_val,0,0);
+       pi->msg.bv_val = pi->pwd.bv_val;
+       pi->msg.bv_len = 0;
+       pi->authz = PAM_SUCCESS;
+       BER_BVZERO(&pi->dn);
 
-       if (!isvalidusername(&uid)) {
-               Debug(LDAP_DEBUG_ANY,"nssov_pam_authc(%s): invalid user name\n",uid.bv_val,0,0);
+       if (!isvalidusername(&pi->uid)) {
+               Debug(LDAP_DEBUG_ANY,"nssov_pam_do_bind(%s): invalid user name\n",
+                       pi->uid.bv_val,0,0);
                rc = PAM_USER_UNKNOWN;
                goto finish;
        }
 
-       BER_BVZERO(&dn);
-
        if (ni->ni_pam_opts & NI_PAM_SASL2DN) {
                int hlen = global_host_bv.bv_len;
 
                /* cn=<service>+uid=<user>,cn=<host>,cn=pam,cn=auth */
-               sdn.bv_len = uid.bv_len + svc.bv_len + hlen +
+               sdn.bv_len = pi->uid.bv_len + pi->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_bv.bv_val);
-               slap_sasl2dn(op, &sdn, &dn, 0);
+                       pi->svc.bv_val, pi->uid.bv_val, global_host_bv.bv_val);
+               slap_sasl2dn(op, &sdn, &pi->dn, 0);
                op->o_tmpfree( sdn.bv_val, op->o_tmpmemctx );
        }
 
        /* If no luck, do a basic uid search */
-       if (BER_BVISEMPTY(&dn) && (ni->ni_pam_opts & NI_PAM_UID2DN)) {
-               nssov_uid2dn(op, ni, &uid, &dn);
-               if (!BER_BVISEMPTY(&dn)) {
-                       sdn = dn;
-                       dnNormalize( 0, NULL, NULL, &sdn, &dn, op->o_tmpmemctx );
+       if (BER_BVISEMPTY(&pi->dn) && (ni->ni_pam_opts & NI_PAM_UID2DN)) {
+               nssov_uid2dn(op, ni, &pi->uid, &pi->dn);
+               if (!BER_BVISEMPTY(&pi->dn)) {
+                       sdn = pi->dn;
+                       dnNormalize( 0, NULL, NULL, &sdn, &pi->dn, op->o_tmpmemctx );
                }
        }
        BER_BVZERO(&sdn);
-       if (BER_BVISEMPTY(&dn)) {
+       if (BER_BVISEMPTY(&pi->dn)) {
                rc = PAM_USER_UNKNOWN;
                goto finish;
        }
 
+       if (BER_BVISEMPTY(&pi->pwd)) {
+               rc = PAM_IGNORE;
+               goto finish;
+       }
+
        /* Should only need to do this once at open time, but there's always
         * the possibility that ppolicy will get loaded later.
         */
@@ -169,7 +162,7 @@ int pam_authc(nssov_info *ni,TFILE *fp,Operation *op)
                op->o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_NONCRITICAL;
        }
        cb.sc_response = pam_bindcb;
-       cb.sc_private = &bi;
+       cb.sc_private = pi;
        op->o_callback = &cb;
        op->o_dn.bv_val[0] = 0;
        op->o_dn.bv_len = 0;
@@ -178,12 +171,12 @@ int pam_authc(nssov_info *ni,TFILE *fp,Operation *op)
        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;
+       op->orb_cred = pi->pwd;
+       op->o_req_dn = pi->dn;
+       op->o_req_ndn = pi->dn;
        slap_op_time( &op->o_time, &op->o_tincr );
        rc = op->o_bd->be_bind( op, &rs );
-       memset(pwd.bv_val,0,pwd.bv_len);
+       memset(pi->pwd.bv_val,0,pi->pwd.bv_len);
        /* quirk: on successful bind, caller has to send result. we need
         * to make sure callbacks run.
         */
@@ -194,15 +187,50 @@ int pam_authc(nssov_info *ni,TFILE *fp,Operation *op)
        case LDAP_INVALID_CREDENTIALS: rc = PAM_AUTH_ERR; break;
        default: rc = PAM_AUTH_ERR; break;
        }
+finish:
+       return rc;
+}
+
+int pam_authc(nssov_info *ni,TFILE *fp,Operation *op)
+{
+       int32_t tmpint32;
+       int rc;
+       slap_callback cb = {0};
+       SlapReply rs = {REP_RESULT};
+       char dnc[1024];
+       char uidc[32];
+       char svcc[256];
+       char pwdc[256];
+       struct berval sdn, dn;
+       struct paminfo pi;
+
+
+       READ_STRING_BUF2(fp,uidc,sizeof(uidc));
+       pi.uid.bv_val = uidc;
+       pi.uid.bv_len = tmpint32;
+       READ_STRING_BUF2(fp,dnc,sizeof(dnc));
+       pi.dn.bv_val = dnc;
+       pi.dn.bv_len = tmpint32;
+       READ_STRING_BUF2(fp,svcc,sizeof(svcc));
+       pi.svc.bv_val = svcc;
+       pi.svc.bv_len = tmpint32;
+       READ_STRING_BUF2(fp,pwdc,sizeof(pwdc));
+       pi.pwd.bv_val = pwdc;
+       pi.pwd.bv_len = tmpint32;
+
+       Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n",pi.uid.bv_val,0,0);
+
+       rc = pam_do_bind(ni, fp, op, &pi);
 
 finish:
        WRITE_INT32(fp,NSLCD_VERSION);
        WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC);
        WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
+       WRITE_BERVAL(fp,&pi.uid);
+       WRITE_BERVAL(fp,&pi.dn);
        WRITE_INT32(fp,rc);
-       WRITE_INT32(fp,bi.authz);       /* authz */
-       WRITE_BERVAL(fp,&dn);
-       WRITE_BERVAL(fp,&bi.msg);       /* authzmsg */
+       WRITE_INT32(fp,pi.authz);       /* authz */
+       WRITE_BERVAL(fp,&pi.msg);       /* authzmsg */
        return 0;
 }
 
@@ -222,11 +250,11 @@ static struct berval uidmsg =
 
 int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
 {
-       struct berval dn, svc;
+       struct berval dn, uid, svc;
        struct berval authzmsg = BER_BVNULL;
-       struct berval tmpluser = BER_BVNULL;
        int32_t tmpint32;
        char dnc[1024];
+       char uidc[32];
        char svcc[256];
        int rc = PAM_SUCCESS;
        Entry *e = NULL;
@@ -234,6 +262,9 @@ int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
        SlapReply rs = {REP_RESULT};
        slap_callback cb = {0};
 
+       READ_STRING_BUF2(fp,uidc,sizeof(uidc));
+       uid.bv_val = uidc;
+       uid.bv_len = tmpint32;
        READ_STRING_BUF2(fp,dnc,sizeof(dnc));
        dn.bv_val = dnc;
        dn.bv_len = tmpint32;
@@ -399,18 +430,19 @@ int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
        if (ni->ni_pam_template_ad) {
                a = attr_find(e->e_attrs, ni->ni_pam_template_ad);
                if (a)
-                       tmpluser = a->a_vals[0];
+                       uid = a->a_vals[0];
                else if (!BER_BVISEMPTY(&ni->ni_pam_template))
-                       tmpluser = ni->ni_pam_template;
+                       uid = ni->ni_pam_template;
        }
 
 finish:
        WRITE_INT32(fp,NSLCD_VERSION);
        WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ);
        WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
+       WRITE_BERVAL(fp,&uid);
+       WRITE_BERVAL(fp,&dn);
        WRITE_INT32(fp,rc);
        WRITE_BERVAL(fp,&authzmsg);
-       WRITE_BERVAL(fp,&tmpluser);
        if (e) {
                be_entry_release_r(op, e);
        }
@@ -419,11 +451,15 @@ finish:
 
 int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op)
 {
-       struct berval dn, svc;
+       struct berval dn, uid, svc;
        int32_t tmpint32;
        char dnc[1024];
        char svcc[256];
+       char uidc[32];
 
+       READ_STRING_BUF2(fp,uidc,sizeof(uidc));
+       uid.bv_val = uidc;
+       uid.bv_len = tmpint32;
        READ_STRING_BUF2(fp,dnc,sizeof(dnc));
        dn.bv_val = dnc;
        dn.bv_len = tmpint32;
@@ -441,11 +477,15 @@ int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op)
 
 int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op)
 {
-       struct berval dn, svc;
+       struct berval dn, uid, svc;
        int32_t tmpint32;
        char dnc[1024];
        char svcc[256];
+       char uidc[32];
 
+       READ_STRING_BUF2(fp,uidc,sizeof(uidc));
+       uid.bv_val = uidc;
+       uid.bv_len = tmpint32;
        READ_STRING_BUF2(fp,dnc,sizeof(dnc));
        dn.bv_val = dnc;
        dn.bv_len = tmpint32;
@@ -463,33 +503,82 @@ int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op)
 
 int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op)
 {
-       struct berval dn, uid, opw, npw;
+       struct berval npw;
        int32_t tmpint32;
        char dnc[1024];
-       char uidc[256];
+       char uidc[32];
        char opwc[256];
        char npwc[256];
+       char svcc[256];
+       struct paminfo pi;
+       int rc;
 
-       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;
+       pi.uid.bv_val = uidc;
+       pi.uid.bv_len = tmpint32;
+       READ_STRING_BUF2(fp,dnc,sizeof(dnc));
+       pi.dn.bv_val = dnc;
+       pi.dn.bv_len = tmpint32;
+       READ_STRING_BUF2(fp,svcc,sizeof(svcc));
+       pi.svc.bv_val = svcc;
+       pi.svc.bv_len = tmpint32;
        READ_STRING_BUF2(fp,opwc,sizeof(opwc));
-       opw.bv_val = opwc;
-       opw.bv_len = tmpint32;
+       pi.pwd.bv_val = opwc;
+       pi.pwd.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);
+       Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(%s), %s\n",
+               pi.dn.bv_val,pi.uid.bv_val,0);
+
+       BER_BVZERO(&pi.msg);
+
+       /* This is a prelim check */
+       if (BER_BVISEMPTY(&pi.dn)) {
+               rc = pam_do_bind(ni,fp,op,&pi);
+               if (rc == PAM_IGNORE)
+                       rc = PAM_SUCCESS;
+       } else {
+               BerElementBuffer berbuf;
+               BerElement *ber = (BerElement *)&berbuf;
+               struct berval bv;
+               SlapReply rs = {REP_RESULT};
+               slap_callback cb = {0};
+
+               ber_init_w_nullc(ber, LBER_USE_DER);
+               ber_printf(ber, "{");
+               if (!BER_BVISEMPTY(&pi.pwd))
+                       ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD,
+                               &pi.pwd);
+               if (!BER_BVISEMPTY(&npw))
+                       ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW,
+                               &npw);
+               ber_printf(ber, "N}");
+               ber_flatten2(ber, &bv, 0);
+               op->o_tag = LDAP_REQ_EXTENDED;
+               op->ore_reqoid = slap_EXOP_MODIFY_PASSWD;
+               op->ore_reqdata = &bv;
+               op->o_dn = pi.dn;
+               op->o_ndn = pi.dn;
+               op->o_callback = &cb;
+               op->o_conn->c_authz_backend = op->o_bd;
+               cb.sc_response = pam_nullcb;
+               op->o_bd = frontendDB;
+               rc = op->o_bd->be_extended(op, &rs);
+               if (rs.sr_text)
+                       ber_str2bv(rs.sr_text, 0, 0, &pi.msg);
+               if (rc == LDAP_SUCCESS)
+                       rc = PAM_SUCCESS;
+               else
+                       rc = PAM_PERM_DENIED;
+       }
        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);
+       WRITE_BERVAL(fp,&pi.uid);
+       WRITE_BERVAL(fp,&pi.dn);
+       WRITE_INT32(fp,rc);
+       WRITE_BERVAL(fp,&pi.msg);
        return 0;
 }