--- pam_ldap.c.SSL Fri Dec 1 18:30:51 2000 +++ pam_ldap.c Fri Dec 1 18:32:24 2000 @@ -422,6 +422,7 @@ result->min_uid = 0; result->max_uid = 0; result->nds_passwd = 0; + result->ad_passwd = 0; result->tmplattr = NULL; result->tmpluser = NULL; @@ -702,6 +703,10 @@ { result->nds_passwd = !strcasecmp (v, "yes"); } + else if (!strcasecmp (k, "pam_ad_passwd")) + { + result->ad_passwd = !strcasecmp (v, "yes"); + } } if (result->host == NULL) @@ -1665,6 +1670,82 @@ rc = PAM_SUCCESS; } } + else if (session->conf->ad_passwd) + { + /* To be able to change a password in AD via LDAP, an SSL connection + * with a cipher strength of at least 128 bit must be established. + * http://support.microsoft.com/support/kb/articles/q264/4/80.ASP + * http://support.microsoft.com/support/kb/articles/Q247/0/78.ASP + * + * The password attribute used by AD is unicodePwd. Its syntax is octect + * string. The actual value is the password surrounded by quotes in + * Unicode (LSBFirst). + * + * NT passwords can have max. 14 characters. + * + * FIXME: + * The conversion to Unicode only works if the locale is + * ISO-8859-1 (aka Latin-1) [of which ASCII is a subset]. + */ + + struct berval bvalold; + struct berval bvalnew; + struct berval *bvalsold[2]; + struct berval *bvalsnew[2]; + char old_password_with_quotes[17], new_password_with_quotes[17]; + char old_unicode_password[34], new_unicode_password[34]; + int i; + + snprintf( new_password_with_quotes, sizeof(new_password_with_quotes), "\"%s\"", new_password); + memset( new_unicode_password, 0, sizeof(new_unicode_password) ); + for ( i = 0; i < strlen(new_password_with_quotes); i++ ) + new_unicode_password[i*2] = new_password_with_quotes[i]; + bvalnew.bv_val = new_unicode_password; + bvalnew.bv_len = strlen(new_password_with_quotes) * 2; + + bvalsnew[0] = &bvalnew; + bvalsnew[1] = NULL; + mod.mod_vals.modv_bvals = bvalsnew; + mod.mod_type = (char *) "unicodePwd"; + mod.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES; + + if ( !session->conf->rootbinddn || geteuid () != 0 ) + { + /* user must supply old password */ + snprintf( old_password_with_quotes, sizeof(old_password_with_quotes), "\"%s\"", old_password); + memset( old_unicode_password, 0, sizeof(old_unicode_password) ); + for ( i = 0; i < strlen(old_password_with_quotes); i++ ) + old_unicode_password[i*2] = old_password_with_quotes[i]; + bvalold.bv_val = old_unicode_password; + bvalold.bv_len = strlen(old_password_with_quotes) * 2; + + bvalsold[0] = &bvalold; + bvalsold[1] = NULL; + mod2.mod_vals.modv_bvals = bvalsold; + mod2.mod_type = (char *) "unicodePwd"; + mod2.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES; + + mods[0] = &mod; + mods[1] = &mod2; + mods[2] = NULL; + } + else + { + mods[0] = &mod; + mods[1] = NULL; + } + + rc = ldap_modify_s (session->ld, session->info->userdn, mods); + if (rc != LDAP_SUCCESS) + { + syslog (LOG_ERR, "pam_ldap: ldap_modify_s %s", ldap_err2string (rc)); + rc = PAM_PERM_DENIED; + } + else + { + rc = PAM_SUCCESS; + } + } else { /* Netscape generates hashed automatically, but UMich doesn't. */ --- pam_ldap.h.orig Fri Dec 1 18:27:28 2000 +++ pam_ldap.h Fri Dec 1 18:30:28 2000 @@ -75,6 +75,8 @@ uid_t max_uid; /* password change for NDS */ int nds_passwd; + /* password change for Microsoft Active Directory */ + int ad_passwd; } pam_ldap_config_t;