]> git.sur5r.net Git - openldap/blobdiff - contrib/slapd-modules/nssov/pam.c
Merge remote-tracking branch 'origin/mdb.master' into OPENLDAP_REL_ENG_2_4
[openldap] / contrib / slapd-modules / nssov / pam.c
index b603e679dc4f2778b741377dba227c3db21a442e..e1d5edaa3b181ca492a7e221f6137eaaf100e36d 100644 (file)
@@ -2,8 +2,9 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
  *
- * Copyright 2008-2010 The OpenLDAP Foundation.
+ * Copyright 2008-2014 The OpenLDAP Foundation.
  * Portions Copyright 2008 by Howard Chu, Symas Corp.
+ * Portions Copyright 2013 by Ted C. Cheng, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -28,6 +29,7 @@ struct paminfo {
        struct berval pwd;
        int authz;
        struct berval msg;
+       int ispwdmgr;
 };
 
 static int pam_bindcb(
@@ -109,7 +111,7 @@ static int pam_uid2dn(nssov_info *ni, Operation *op,
 
        if (!isvalidusername(&pi->uid)) {
                Debug(LDAP_DEBUG_ANY,"nssov_pam_uid2dn(%s): invalid user name\n",
-                       pi->uid.bv_val,0,0);
+                       pi->uid.bv_val ? pi->uid.bv_val : "NULL",0,0);
                return NSLCD_PAM_USER_UNKNOWN;
        }
 
@@ -150,27 +152,31 @@ int pam_do_bind(nssov_info *ni,TFILE *fp,Operation *op,
        pi->msg.bv_val = pi->pwd.bv_val;
        pi->msg.bv_len = 0;
        pi->authz = NSLCD_PAM_SUCCESS;
-       BER_BVZERO(&pi->dn);
 
-       rc = pam_uid2dn(ni, op, pi);
-       if (rc) goto finish;
+       if (!pi->ispwdmgr) {
 
-       if (BER_BVISEMPTY(&pi->pwd)) {
-               rc = NSLCD_PAM_IGNORE;
-               goto finish;
-       }
+               BER_BVZERO(&pi->dn);
+               rc = pam_uid2dn(ni, op, pi);
+               if (rc) goto finish;
 
-       /* Should only need to do this once at open time, but there's always
-        * the possibility that ppolicy will get loaded later.
-        */
-       if (!ppolicy_cid) {
-               rc = slap_find_control_id(LDAP_CONTROL_PASSWORDPOLICYREQUEST,
-                       &ppolicy_cid);
-       }
-       /* of course, 0 is a valid cid, but it won't be ppolicy... */
-       if (ppolicy_cid) {
-               op->o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_NONCRITICAL;
+               if (BER_BVISEMPTY(&pi->pwd)) {
+                       rc = NSLCD_PAM_PERM_DENIED;
+                       goto finish;
+               }
+
+               /* Should only need to do this once at open time, but there's always
+                * the possibility that ppolicy will get loaded later.
+                */
+               if (!ppolicy_cid) {
+                       rc = slap_find_control_id(LDAP_CONTROL_PASSWORDPOLICYREQUEST,
+                               &ppolicy_cid);
+               }
+               /* of course, 0 is a valid cid, but it won't be ppolicy... */
+               if (ppolicy_cid) {
+                       op->o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_NONCRITICAL;
+               }
        }
+
        cb.sc_response = pam_bindcb;
        cb.sc_private = pi;
        op->o_callback = &cb;
@@ -198,6 +204,8 @@ int pam_do_bind(nssov_info *ni,TFILE *fp,Operation *op,
        default: rc = NSLCD_PAM_AUTH_ERR; break;
        }
 finish:
+       Debug(LDAP_DEBUG_ANY,"pam_do_bind (%s): rc (%d)\n",
+               pi->dn.bv_val ? pi->dn.bv_val : "NULL", rc, 0);
        return rc;
 }
 
@@ -206,7 +214,6 @@ 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];
@@ -215,27 +222,80 @@ int pam_authc(nssov_info *ni,TFILE *fp,Operation *op)
        struct paminfo pi;
 
 
-       READ_STRING_BUF2(fp,uidc,sizeof(uidc));
+       READ_STRING(fp,uidc);
        pi.uid.bv_val = uidc;
        pi.uid.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,dnc,sizeof(dnc));
+       READ_STRING(fp,dnc);
        pi.dn.bv_val = dnc;
        pi.dn.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,svcc,sizeof(svcc));
+       READ_STRING(fp,svcc);
        pi.svc.bv_val = svcc;
        pi.svc.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,pwdc,sizeof(pwdc));
+       READ_STRING(fp,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);
+       Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n",
+                       pi.uid.bv_val ? pi.uid.bv_val : "NULL",0,0);
+
+       pi.ispwdmgr = 0;
+
+       /* if service is "passwd" and "nssov-pam-password-prohibit-message */
+       /* is set, deny the auth request */
+       if (!strcmp(svcc, "passwd") &&
+               !BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) {
+               Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(): %s (%s)\n",
+                       "password_prohibit_message for passwd",
+                       ni->ni_pam_password_prohibit_message.bv_val,0);
+               ber_str2bv(ni->ni_pam_password_prohibit_message.bv_val, 0, 0, &pi.msg);
+               pi.authz = NSLCD_PAM_PERM_DENIED;
+               rc = NSLCD_PAM_PERM_DENIED;
+               goto finish;
+       }
+
+       /* if username is null, pwdmgr password preliminary check */
+       if (BER_BVISEMPTY(&pi.uid)) {
+               if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_dn)) {
+                       /* pwdmgr dn not configured */
+                       Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n",
+                               "pwdmgr dn not configured", 0, 0);
+                       ber_str2bv("pwdmgr dn not configured", 0, 0, &pi.msg);
+                       pi.authz = NSLCD_PAM_PERM_DENIED;
+                       rc = NSLCD_PAM_PERM_DENIED;
+                       goto finish;
+               } else {
+                       /* use pwdmgr dn */
+                       ber_str2bv(ni->ni_pam_pwdmgr_dn.bv_val, 0, 0, &pi.dn);
+               }
+
+               /* use pwdmgr pwd if configured */
+               if (BER_BVISEMPTY(&pi.pwd)) {
+                       if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_pwd)) {
+                               Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n",
+                                       "no pwdmgr pwd", 0, 0);
+                               ber_str2bv("pwdmgr pwd not configured", 0, 0, &pi.msg);
+                               pi.authz = NSLCD_PAM_PERM_DENIED;
+                               rc = NSLCD_PAM_PERM_DENIED;
+                               goto finish;
+                       }
+                       /* use configured pwdmgr pwd */
+                       memset((void *) pwdc, 0, 256);
+                       strncpy(pi.pwd.bv_val, ni->ni_pam_pwdmgr_pwd.bv_val,
+                                       ni->ni_pam_pwdmgr_pwd.bv_len);
+                       pi.pwd.bv_len = ni->ni_pam_pwdmgr_pwd.bv_len;
+               }
+               pi.ispwdmgr = 1;
+       }
+
 
        rc = pam_do_bind(ni, fp, op, &pi);
 
 finish:
+       Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s): rc (%d)\n",
+               pi.dn.bv_val ? pi.dn.bv_val : "NULL",rc,0);
        WRITE_INT32(fp,NSLCD_VERSION);
        WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC);
-       WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
+       WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
        WRITE_BERVAL(fp,&pi.uid);
        WRITE_BERVAL(fp,&pi.dn);
        WRITE_INT32(fp,rc);
@@ -274,29 +334,29 @@ int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
        int rc;
        Entry *e = NULL;
        Attribute *a;
-       SlapReply rs = {REP_RESULT};
        slap_callback cb = {0};
 
-       READ_STRING_BUF2(fp,uidc,sizeof(uidc));
+       READ_STRING(fp,uidc);
        uid.bv_val = uidc;
        uid.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,dnc,sizeof(dnc));
+       READ_STRING(fp,dnc);
        dn.bv_val = dnc;
        dn.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,svcc,sizeof(svcc));
+       READ_STRING(fp,svcc);
        svc.bv_val = svcc;
        svc.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,ruserc,sizeof(ruserc));
+       READ_STRING(fp,ruserc);
        ruser.bv_val = ruserc;
        ruser.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,rhostc,sizeof(rhostc));
+       READ_STRING(fp,rhostc);
        rhost.bv_val = rhostc;
        rhost.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,ttyc,sizeof(ttyc));
+       READ_STRING(fp,ttyc);
        tty.bv_val = ttyc;
        tty.bv_len = tmpint32;
 
-       Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n",dn.bv_val,0,0);
+       Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n",
+                       dn.bv_val ? dn.bv_val : "NULL",0,0);
 
        /* If we didn't do authc, we don't have a DN yet */
        if (BER_BVISEMPTY(&dn)) {
@@ -314,6 +374,7 @@ int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
                AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
                struct berval hostdn = BER_BVNULL;
                struct berval odn = op->o_ndn;
+               SlapReply rs = {REP_RESULT};
                op->o_dn = dn;
                op->o_ndn = dn;
                {
@@ -342,8 +403,7 @@ int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
                                !BER_BVISEMPTY(&ni->ni_pam_defhost)) {
                                filter.bv_len = sizeof(fbuf);
                                filter.bv_val = fbuf;
-                               memset(&rs2, 0, sizeof(rs2));
-                               rs2.sr_type = REP_RESULT;
+                               rs_reinit(&rs2, REP_RESULT);
                                nssov_filter_byname(mi,0,&ni->ni_pam_defhost,&filter);
                                op->ors_filterstr = filter;
                                op->ors_filter = str2filter_x(op, filter.bv_val);
@@ -382,6 +442,7 @@ int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
                !BER_BVISEMPTY(&ni->ni_pam_group_dn) &&
                ni->ni_pam_group_ad) {
                AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
+               SlapReply rs = {REP_RESULT};
                op->o_callback = &cb;
                cb.sc_response = slap_null_cb;
                op->o_tag = LDAP_REQ_COMPARE;
@@ -470,7 +531,7 @@ int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
 finish:
        WRITE_INT32(fp,NSLCD_VERSION);
        WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ);
-       WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
+       WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
        WRITE_BERVAL(fp,&uid);
        WRITE_BERVAL(fp,&dn);
        WRITE_INT32(fp,rc);
@@ -478,6 +539,19 @@ finish:
        if (e) {
                be_entry_release_r(op, e);
        }
+       switch (rc) {
+       case NSLCD_PAM_SUCCESS:
+               Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(): success\n", 0,0,0);
+               break;
+       case NSLCD_PAM_PERM_DENIED:
+               Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(): %s\n",
+                       authzmsg.bv_val ? authzmsg.bv_val : "NULL",0,0);
+               break;
+       default:
+               Debug(LDAP_DEBUG_TRACE,
+                       "nssov_pam_authz(): permission denied, rc (%d)\n",
+                       rc, 0, 0);
+       }
        return 0;
 }
 
@@ -497,23 +571,25 @@ static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action)
        struct berval timestamp, bv[2], *nbv;
        time_t stamp;
        Modifications mod;
+       int rc = 0;
+       int sessionID = -1;
 
-       READ_STRING_BUF2(fp,uidc,sizeof(uidc));
+       READ_STRING(fp,uidc);
        uid.bv_val = uidc;
        uid.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,dnc,sizeof(dnc));
+       READ_STRING(fp,dnc);
        dn.bv_val = dnc;
        dn.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,svcc,sizeof(svcc));
+       READ_STRING(fp,svcc);
        svc.bv_val = svcc;
        svc.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,ttyc,sizeof(ttyc));
+       READ_STRING(fp,ttyc);
        tty.bv_val = ttyc;
        tty.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,rhostc,sizeof(rhostc));
+       READ_STRING(fp,rhostc);
        rhost.bv_val = rhostc;
        rhost.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,ruserc,sizeof(ruserc));
+       READ_STRING(fp,ruserc);
        ruser.bv_val = ruserc;
        ruser.bv_len = tmpint32;
        READ_INT32(fp,stamp);
@@ -521,7 +597,20 @@ static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action)
        Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(%s)\n",
                action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', dn.bv_val,0);
 
-       if (!dn.bv_len || !ni->ni_pam_sessions) return 0;
+       if (!dn.bv_len) {
+               Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(): %s\n",
+                       action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', "null DN",0);
+               rc = -1;
+               goto done;
+       }
+
+       if (!ni->ni_pam_sessions) {
+               Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(): %s\n",
+                       action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
+                       "pam session(s) not configured, ignored",0);
+               rc = -1;
+               goto done;
+       }
 
        {
                int i, found=0;
@@ -533,7 +622,14 @@ static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action)
                                break;
                        }
                }
-               if (!found) return 0;
+               if (!found) {
+                       Debug(LDAP_DEBUG_TRACE,
+                               "nssov_pam_sess_%c(): service(%s) not configured, ignored\n",
+                               action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
+                               svc.bv_val,0);
+                       rc = -1;
+                       goto done;
+               }
        }
 
        slap_op_time( &op->o_time, &op->o_tincr );
@@ -548,6 +644,9 @@ static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action)
        sprintf(bv[0].bv_val, "%s %s %s %s (%s@%s)",
                timestamp.bv_val, global_host_bv.bv_val, svc.bv_val, tty.bv_val,
                ruser.bv_val, rhost.bv_val);
+
+       Debug(LDAP_DEBUG_TRACE, "nssov_pam_sess_%c(): loginStatus (%s) \n",
+                       action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', bv[0].bv_val,0);
        
        mod.sml_numvals = 1;
        mod.sml_values = bv;
@@ -569,16 +668,32 @@ static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action)
        op->orm_no_opattrs = 1;
        op->o_req_dn = dn;
        op->o_req_ndn = dn;
-       op->o_bd->be_modify( op, &rs );
+       if (op->o_bd->be_modify( op, &rs ) != LDAP_SUCCESS) {
+               Debug(LDAP_DEBUG_TRACE,
+                       "nssov_pam_sess_%c(): modify op failed\n",
+                       action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
+                       0,0);
+               rc = -1;
+       }
+
        if ( mod.sml_next ) {
                slap_mods_free( mod.sml_next, 1 );
        }
        ber_bvarray_free_x( nbv, op->o_tmpmemctx );
 
+done:;
+
+       if (rc == 0) {
+               Debug(LDAP_DEBUG_TRACE,
+                       "nssov_pam_sess_%c(): success\n",
+                       action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
+                       0,0);
+               sessionID = op->o_time;
+       }
        WRITE_INT32(fp,NSLCD_VERSION);
        WRITE_INT32(fp,action);
-       WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
-       WRITE_INT32(fp,op->o_time);
+       WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
+       WRITE_INT32(fp,sessionID);
        return 0;
 }
 
@@ -604,69 +719,116 @@ int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op)
        struct paminfo pi;
        int rc;
 
-       READ_STRING_BUF2(fp,uidc,sizeof(uidc));
+       READ_STRING(fp,uidc);
        pi.uid.bv_val = uidc;
        pi.uid.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,dnc,sizeof(dnc));
+       READ_STRING(fp,dnc);
        pi.dn.bv_val = dnc;
        pi.dn.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,svcc,sizeof(svcc));
+       READ_STRING(fp,svcc);
        pi.svc.bv_val = svcc;
        pi.svc.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,opwc,sizeof(opwc));
+       READ_STRING(fp,opwc);
        pi.pwd.bv_val = opwc;
        pi.pwd.bv_len = tmpint32;
-       READ_STRING_BUF2(fp,npwc,sizeof(npwc));
+       READ_STRING(fp,npwc);
        npw.bv_val = npwc;
        npw.bv_len = tmpint32;
 
        Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(%s), %s\n",
-               pi.dn.bv_val,pi.uid.bv_val,0);
+               pi.dn.bv_val ? pi.dn.bv_val : "NULL",
+               pi.uid.bv_val ? pi.uid.bv_val : "NULL" ,0);
 
        BER_BVZERO(&pi.msg);
+       pi.ispwdmgr = 0;
+
+       /* nssov_pam prohibits password mod */
+       if (!BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) {
+               Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(): %s (%s)\n",
+                       "password_prohibit_message",
+                       ni->ni_pam_password_prohibit_message.bv_val,0);
+               ber_str2bv(ni->ni_pam_password_prohibit_message.bv_val, 0, 0, &pi.msg);
+               rc = NSLCD_PAM_PERM_DENIED;
+               goto done;
+       }
 
-       /* This is a prelim check */
        if (BER_BVISEMPTY(&pi.dn)) {
-               rc = pam_do_bind(ni,fp,op,&pi);
-               if (rc == NSLCD_PAM_IGNORE)
-                       rc = NSLCD_PAM_SUCCESS;
+               /* should not be here at all, pam_authc() should have returned */
+               /* error */
+               Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), %s\n",
+                       "prelim checking failed", 0, 0);
+               ber_str2bv("no pwmod requesting dn", 0, 0, &pi.msg);
+               rc = NSLCD_PAM_PERM_DENIED;
+               goto done;
+       }
+
+       if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_dn)) {
+               Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), %s\n",
+                       "pwdmgr not configured", 0, 0);
+               ber_str2bv("pwdmgr not configured", 0, 0, &pi.msg);
+               rc = NSLCD_PAM_PERM_DENIED;
+               goto done;
+       } else if (!ber_bvcmp(&pi.dn, &ni->ni_pam_pwdmgr_dn)) {
+               /* root user requesting pwmod, convert uid to dn */
+               pi.ispwdmgr = 1;
+               rc = pam_uid2dn(ni, op, &pi);
+               if (rc) {
+                       ber_str2bv("unable to convert uid to dn", 0, 0, &pi.msg);
+                       rc = NSLCD_PAM_PERM_DENIED;
+                       goto done;
+               }
+       }
+
+       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.dn))
+               ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
+                       &pi.dn);
+       /* supply old pwd only when end-user changing pwd */
+       if (!BER_BVISEMPTY(&pi.pwd) && pi.ispwdmgr == 0)
+               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;
+
+       if (pi.ispwdmgr) {
+               /* root user changing end-user passwords */
+               op->o_dn = ni->ni_pam_pwdmgr_dn;
+               op->o_ndn = ni->ni_pam_pwdmgr_dn;
        } 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;
+               /* end-user self-pwd-mod */
                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 = slap_null_cb;
-               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 = NSLCD_PAM_SUCCESS;
-               else
-                       rc = NSLCD_PAM_PERM_DENIED;
        }
+       op->o_callback = &cb;
+       op->o_conn->c_authz_backend = op->o_bd;
+       cb.sc_response = slap_null_cb;
+       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 = NSLCD_PAM_SUCCESS;
+       else
+               rc = NSLCD_PAM_PERM_DENIED;
+
+done:;
+       Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), rc (%d)\n", rc, 0, 0);
        WRITE_INT32(fp,NSLCD_VERSION);
        WRITE_INT32(fp,NSLCD_ACTION_PAM_PWMOD);
-       WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
+       WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
        WRITE_BERVAL(fp,&pi.uid);
        WRITE_BERVAL(fp,&pi.dn);
        WRITE_INT32(fp,rc);
@@ -679,7 +841,7 @@ int nssov_pam_init()
        int code = 0;
        const char *text;
        if (!ad_loginStatus)
-               code = slap_str2ad( "loginStatus", &ad_loginStatus, &text );
+               code = slap_str2ad("loginStatus", &ad_loginStatus, &text);
 
        return code;
 }