]> git.sur5r.net Git - openldap/blobdiff - contrib/slapd-modules/nssov/pam.c
Merge remote-tracking branch 'origin/mdb.RE/0.9'
[openldap] / contrib / slapd-modules / nssov / pam.c
index 31f5e37f7a9c4a75de8409d2568f25a8fa57d05e..e1d5edaa3b181ca492a7e221f6137eaaf100e36d 100644 (file)
@@ -2,8 +2,9 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
  *
- * Copyright 2008-2013 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;
 }
 
@@ -227,11 +235,64 @@ int pam_authc(nssov_info *ni,TFILE *fp,Operation *op)
        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_BEGIN);
@@ -294,7 +355,8 @@ int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
        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)) {
@@ -477,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;
 }
 
@@ -496,6 +571,8 @@ 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(fp,uidc);
        uid.bv_val = uidc;
@@ -520,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;
@@ -532,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 );
@@ -547,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;
@@ -568,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_BEGIN);
-       WRITE_INT32(fp,op->o_time);
+       WRITE_INT32(fp,sessionID);
        return 0;
 }
 
@@ -620,49 +736,96 @@ int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op)
        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_BEGIN);