瀏覽代碼

Ticket #548 - RFE: Allow AD password sync to update shadowLastChange

Description: When passwordMinAge, passwordMaxAge, passwordWarning, etc.
are changed in a password policy, the corresponding shadow values are
also adjusted.

See this comment for more details.
https://fedorahosted.org/389/ticket/548#comment:19

This patch checks the current shadow values with the one from the
password policy, and if they don't match, it replaces the shadow value
with the one from the password policy.

Author: nhosoi

Review: wibrown
Noriko Hosoi 9 年之前
父節點
當前提交
7f63e4c167

+ 1 - 1
ldap/servers/slapd/modify.c

@@ -496,7 +496,7 @@ slapi_modify_internal_set_pb_ext(Slapi_PBlock *pb, const Slapi_DN *sdn,
 	if (pb == NULL || sdn == NULL || mods == NULL)
 	{
 		slapi_log_error(SLAPI_LOG_FATAL, NULL, 
-						"slapi_modify_internal_set_pb: NULL parameter\n");
+						"slapi_modify_internal_set_pb_ext: NULL parameter\n");
 		return;
 	}
 

+ 5 - 1
ldap/servers/slapd/opshared.c

@@ -1454,10 +1454,12 @@ iterate(Slapi_PBlock *pb, Slapi_Backend *be, int send_result,
                 continue;
             }
             /* Adding shadow password attrs. */
-            add_shadow_ext_password_attrs(pb, e);
+            add_shadow_ext_password_attrs(pb, &e);
             if (process_entry(pb, e, send_result)) 
             {
                 /* shouldn't  send this entry */
+                slapi_entry_free(pb->pb_pw_entry);
+                pb->pb_pw_entry = NULL;
                 continue;
             }
 
@@ -1483,6 +1485,8 @@ iterate(Slapi_PBlock *pb, Slapi_Backend *be, int send_result,
                     pb->pb_op->o_status = SLAPI_OP_STATUS_ABANDONED;
                     break;
             }
+            slapi_entry_free(pb->pb_pw_entry);
+            pb->pb_pw_entry = NULL;
             if (pagesize == *pnentries)
             { 
                 /* PAGED RESULTS: reached the pagesize */

+ 2 - 1
ldap/servers/slapd/proto-slap.h

@@ -937,7 +937,8 @@ void add_password_attrs( Slapi_PBlock *pb, Operation *op, Slapi_Entry *e );
 void mod_allowchange_aci(char *val);
 void pw_mod_allowchange_aci(int pw_prohibit_change);
 void pw_add_allowchange_aci(Slapi_Entry *e, int pw_prohibit_change);
-void add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry *e);
+
+int add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry **e);
 
 /*
  * pw_retry.c

+ 109 - 61
ldap/servers/slapd/pw.c

@@ -2843,108 +2843,156 @@ pw_get_ext_size(Slapi_Entry *entry, size_t *size)
     return LDAP_SUCCESS;
 }
 
-void
-add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry *e)
+int
+add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry **e)
 {
     const char *dn = NULL;
     passwdPolicy *pwpolicy = NULL;
     time_t shadowval = 0;
     time_t exptime = 0;
-    struct berval bv;
-    struct berval *bvals[2];
-
-    if (!e) {
-        return;
+    Slapi_Mods *smods = NULL;
+    LDAPMod **mods;
+    long sval;
+    int mod_num = 0;
+    char *shmin = NULL;
+    char *shmax = NULL;
+    char *shwarn = NULL;
+    char *shexp = NULL;
+    int rc = 0;
+
+    if (!e && !*e) {
+        return rc;
     }
-    dn = slapi_entry_get_ndn(e);
+    dn = slapi_entry_get_ndn(*e);
     if (!dn) {
-        return;
+        return rc;
     }
-    if (!slapi_entry_attr_hasvalue(e, SLAPI_ATTR_OBJECTCLASS, "shadowAccount")) {
+    if (!slapi_entry_attr_hasvalue(*e, SLAPI_ATTR_OBJECTCLASS, "shadowAccount")) {
         /* Not a shadowAccount; nothing to do. */
-        return;
+        return rc;
     }
     if (operation_is_flag_set(pb->pb_op, OP_FLAG_INTERNAL)) {
         /* external only */
-        return;
+        return rc;
     }
     pwpolicy = new_passwdPolicy(pb, dn);
     if (!pwpolicy) {
-        return;
+        return rc;
     }
 
     LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> add_shadow_password_attrs\n");
 
-    bvals[0] = &bv;
-    bvals[1] = NULL;
-
     /* shadowMin - the minimum number of days required between password changes. */
-    if (!slapi_entry_attr_exists(e, "shadowMin")) {
-        if (pwpolicy->pw_minage > 0) {
-            shadowval = pwpolicy->pw_minage / _SEC_PER_DAY;
-        } else {
-            shadowval = 0;
+    if (pwpolicy->pw_minage > 0) {
+        shadowval = pwpolicy->pw_minage / _SEC_PER_DAY;
+    } else {
+        shadowval = 0;
+    }
+    shmin = slapi_entry_attr_get_charptr(*e, "shadowMin");
+    if (shmin) {
+        sval = strtol(shmin, NULL, 0);
+        if (sval != shadowval) {
+            slapi_ch_free_string(&shmin);
+            shmin = slapi_ch_smprintf("%ld", shadowval);
+            mod_num++;
         }
-        bv.bv_val = slapi_ch_smprintf("%ld", shadowval);
-        bv.bv_len = strlen(bv.bv_val);
-        slapi_entry_attr_merge(e, "shadowMin", bvals);
-        slapi_ch_free_string(&bv.bv_val);
+    } else {
+        mod_num++;
+        shmin = slapi_ch_smprintf("%ld", shadowval);
     }
 
     /* shadowMax - the maximum number of days for which the user password remains valid. */
-    if (!slapi_entry_attr_exists(e, "shadowMax")) {
-        if (pwpolicy->pw_maxage > 0) {
-            shadowval = pwpolicy->pw_maxage / _SEC_PER_DAY;
-            exptime = time_plus_sec(current_time(), pwpolicy->pw_maxage);
-        } else {
-            shadowval = 99999;
+    if (pwpolicy->pw_maxage > 0) {
+        shadowval = pwpolicy->pw_maxage / _SEC_PER_DAY;
+        exptime = time_plus_sec(current_time(), pwpolicy->pw_maxage);
+    } else {
+        shadowval = 99999;
+    }
+    shmax = slapi_entry_attr_get_charptr(*e, "shadowMax");
+    if (shmax) {
+        sval = strtol(shmax, NULL, 0);
+        if (sval != shadowval) {
+            slapi_ch_free_string(&shmax);
+            shmax = slapi_ch_smprintf("%ld", shadowval);
+            mod_num++;
         }
-        bv.bv_val = slapi_ch_smprintf("%ld", shadowval);
-        bv.bv_len = strlen(bv.bv_val);
-        slapi_entry_attr_replace(e, "shadowMax", bvals);
-        slapi_ch_free_string(&bv.bv_val);
+    } else {
+        mod_num++;
+        shmax = slapi_ch_smprintf("%ld", shadowval);
     }
 
     /* shadowWarning - the number of days of advance warning given to the user before the user password expires. */
-    if (!slapi_entry_attr_exists(e, "shadowWarning")) {
-        if (pwpolicy->pw_warning > 0) {
-            shadowval = pwpolicy->pw_warning / _SEC_PER_DAY;
-        } else {
-            shadowval = 0;
+    if (pwpolicy->pw_warning > 0) {
+        shadowval = pwpolicy->pw_warning / _SEC_PER_DAY;
+    } else {
+        shadowval = 0;
+    }
+    shwarn = slapi_entry_attr_get_charptr(*e, "shadowWarning");
+    if (shwarn) {
+        sval = strtol(shwarn, NULL, 0);
+        if (sval != shadowval) {
+            slapi_ch_free_string(&shwarn);
+            shwarn = slapi_ch_smprintf("%ld", shadowval);
+            mod_num++;
         }
-        bv.bv_val = slapi_ch_smprintf("%ld", shadowval);
-        bv.bv_len = strlen(bv.bv_val);
-        slapi_entry_attr_replace(e, "shadowWarning", bvals);
-        slapi_ch_free_string(&bv.bv_val);
+    } else {
+        mod_num++;
+        shwarn = slapi_ch_smprintf("%ld", shadowval);
     }
 
     /* shadowExpire - the date on which the user login will be disabled. */
-    if (exptime && !slapi_entry_attr_exists(e, "shadowExpire")) {
+    if (exptime) {
+        shexp = slapi_entry_attr_get_charptr(*e, "shadowExpire");
         exptime /= _SEC_PER_DAY;
-        bv.bv_val = slapi_ch_smprintf("%ld", exptime);
-        bv.bv_len = strlen(bv.bv_val);
-        slapi_entry_attr_replace(e, "shadowExpire", bvals);
-        slapi_ch_free_string(&bv.bv_val);
+        if (shexp) {
+            sval = strtol(shexp, NULL, 0);
+            if (sval != exptime) {
+                slapi_ch_free_string(&shexp);
+                shexp = slapi_ch_smprintf("%ld", shadowval);
+                mod_num++;
+            }
+        } else {
+            mod_num++;
+            shexp = slapi_ch_smprintf("%ld", exptime);
+        }
+    }
+    smods = slapi_mods_new();
+    slapi_mods_init(smods, mod_num);
+    if (shmin) {
+        slapi_mods_add(smods, LDAP_MOD_REPLACE, "shadowMin", strlen(shmin), shmin);
+        slapi_ch_free_string(&shmin);
+    }
+    if (shmax) {
+        slapi_mods_add(smods, LDAP_MOD_REPLACE, "shadowMax", strlen(shmax), shmax);
+        slapi_ch_free_string(&shmax);
+    }
+    if (shwarn) {
+        slapi_mods_add(smods, LDAP_MOD_REPLACE, "shadowWarning", strlen(shwarn), shwarn);
+        slapi_ch_free_string(&shwarn);
+    }
+    if (shexp) {
+        slapi_mods_add(smods, LDAP_MOD_REPLACE, "shadowExpire", strlen(shexp), shexp);
+        slapi_ch_free_string(&shexp);
+    }
+    /* Apply the  mods to create the resulting entry. */
+    mods = slapi_mods_get_ldapmods_byref(smods);
+    if (mods) {
+        Slapi_Entry *sentry = slapi_entry_dup(*e);
+        rc = slapi_entry_apply_mods(sentry, mods);
+        pb->pb_pw_entry = sentry;
+        *e = sentry;
     }
+    slapi_mods_free(&smods);
 
 #if 0 /* These 2 attributes are no need (or not able) to auto-fill. */
     /* 
      * shadowInactive - the number of days of inactivity allowed for the user.
      * Password Policy does not have the corresponding parameter.
+     * 
+     * shadowFlag - not currently in use.
      */
-    shadowval = 0;
-    bv.bv_val = slapi_ch_smprintf("%ld", shadowval);
-    bv.bv_len = strlen(bv.bv_val);
-    slapi_entry_attr_replace(e, "shadowInactive", bvals);
-    slapi_ch_free_string(&bv.bv_val);
-
-    /* shadowFlag - not currently in use. */
-    bv.bv_val = slapi_ch_smprintf("%d", 0);
-    bv.bv_len = strlen(bv.bv_val);
-    slapi_entry_attr_replace(e, "shadowFlag", bvals);
-    slapi_ch_free_string(&bv.bv_val);
 #endif
 
     LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- add_shadow_password_attrs\n");
-    return;
+    return rc;
 }

+ 9 - 9
ldap/servers/slapd/result.c

@@ -238,7 +238,7 @@ int send_ldap_intermediate( Slapi_PBlock *pb,  LDAPControl **ectrls,
 		rc = ber_put_seq( ber );
 	}
 	if ( rc == LBER_ERROR ) {
-		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed 0\n", 0, 0, 0 );
 		ber_free( ber, 1 /* freebuf */ );
 		goto log_and_return;
 	}
@@ -595,7 +595,7 @@ send_ldap_result_ext(
 	}
 
 	if ( rc == LBER_ERROR ) {
-		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed 1\n", 0, 0, 0 );
                 if (flush_ber_element == 1) {
                     /* we alloced the ber */
                     ber_free( ber, 1 /* freebuf */ );
@@ -857,13 +857,13 @@ send_ldapv3_referral(
 		rc = ber_printf( ber, "s", urls[i]->bv_val );
 	}
 	if ( rc == LBER_ERROR ) {
-		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed 2\n", 0, 0, 0 );
 		send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
 		    "ber_printf", 0, NULL );
 		return( -1 );
 	}
 	if ( ber_printf( ber, "}}" ) == LBER_ERROR ) {
-		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed 3\n", 0, 0, 0 );
 		send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
 		    "ber_printf", 0, NULL );
 		return( -1 );
@@ -980,7 +980,7 @@ encode_attr_2(
 #endif
 
 	if (ber_printf(ber, "{s[", returned_type?returned_type:attribute_type) == -1) {
-		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed 4\n", 0, 0, 0 );
 		ber_free( ber, 1 );
 		send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL,
 		                 "ber_printf type", 0, NULL);
@@ -994,7 +994,7 @@ encode_attr_2(
 			if ( ber_printf( ber, "o", v->bv.bv_val,v->bv.bv_len ) == -1 )
 			{
 				LDAPDebug( LDAP_DEBUG_ANY,
-				    "ber_printf failed\n", 0, 0, 0 );
+				    "ber_printf failed 5\n", 0, 0, 0 );
 				ber_free( ber, 1 );
 				send_ldap_result( pb, LDAP_OPERATIONS_ERROR,
 				    NULL, "ber_printf value", 0, NULL );
@@ -1005,7 +1005,7 @@ encode_attr_2(
 	}
 
 	if ( ber_printf( ber, "]}" ) == -1 ) {
-		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed 6\n", 0, 0, 0 );
 		ber_free( ber, 1 );
 		send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
 		    "ber_printf type end", 0, NULL );
@@ -1549,7 +1549,7 @@ send_ldap_search_entry_ext(
 	    LDAP_RES_SEARCH_ENTRY, slapi_entry_get_dn_const(e) );
 
 	if ( rc == -1 ) {
-		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed 7\n", 0, 0, 0 );
 		send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
 		    "ber_printf dn", 0, NULL );
 		goto cleanup;
@@ -1663,7 +1663,7 @@ send_ldap_search_entry_ext(
 	}
 
 	if ( rc == -1 ) {
-		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+		LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed 8\n", 0, 0, 0 );
 		send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
 		    "ber_printf entry end", 0, NULL );
 		goto cleanup;

+ 1 - 0
ldap/servers/slapd/slap.h

@@ -1735,6 +1735,7 @@ typedef struct slapi_pblock {
 	/* For ACI Target Check */
 	int pb_aci_target_check; /* this flag prevents duplicate checking of ACI's target existence */
 
+    struct slapi_entry *pb_pw_entry; /* stash dup'ed entry that shadow info is added/replaced */
 } slapi_pblock;
 
 /* index if substrlens */