Hi Andrew, here's the patch... It adds a new parameter to smb.conf 'ldap passwd sync = Yes | No | Only':
Yes -> try to update the password on the LDAP-Server via extended operations. No -> didn't try to update the passwd Only -> This only the Passchange via extended operations is done. and lmPassword, ntPassword, pwdLastSet are not updated/added this is only availible if the ldap libs support LDAP_EXOP_X_MODIFY_PASSWD. metze ----------------------------------------------------------------------------- Stefan "metze" Metzmacher <[EMAIL PROTECTED]>
diff -Npur --exclude=CVS HEAD/source/include/smb.h HEAD-pdb/source/include/smb.h --- HEAD/source/include/smb.h Thu Aug 1 07:25:08 2002 +++ HEAD-pdb/source/include/smb.h Thu Aug 1 10:11:05 2002 @@ -1375,6 +1375,9 @@ enum schema_types {SCHEMA_COMPAT, SCHEMA /* LDAP SSL options */ enum ldap_ssl_types {LDAP_SSL_ON, LDAP_SSL_OFF, LDAP_SSL_START_TLS}; +/* LDAP PASSWD SYNC methods */ +enum ldap_passwd_sync_types {LDAP_PASSWD_SYNC_ON, LDAP_PASSWD_SYNC_OFF, +LDAP_PASSWD_SYNC_ONLY}; + /* Remote architectures we know about. */ enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT, RA_WIN2K, RA_SAMBA}; diff -Npur --exclude=CVS HEAD/source/param/loadparm.c HEAD-pdb/source/param/loadparm.c --- HEAD/source/param/loadparm.c Thu Aug 1 07:25:09 2002 +++ HEAD-pdb/source/param/loadparm.c Thu Aug 1 10:57:08 2002 @@ -205,11 +205,13 @@ typedef struct int iLockSpinTime; char *szLdapMachineSuffix; char *szLdapUserSuffix; - int ldap_port; int ldap_ssl; char *szLdapSuffix; char *szLdapFilter; char *szLdapAdminDn; +#ifdef LDAP_EXOP_X_MODIFY_PASSWD + int ldap_passwd_sync; +#endif /* LDAP_EXOP_X_MODIFY_PASSWD */ BOOL bMsAddPrinterWizard; BOOL bDNSproxy; BOOL bWINSsupport; @@ -590,6 +592,20 @@ static struct enum_list enum_ldap_ssl[] {-1, NULL} }; +static struct enum_list enum_ldap_passwd_sync[] = { + {LDAP_PASSWD_SYNC_ON, "Yes"}, + {LDAP_PASSWD_SYNC_ON, "yes"}, + {LDAP_PASSWD_SYNC_ON, "on"}, + {LDAP_PASSWD_SYNC_ON, "On"}, + {LDAP_PASSWD_SYNC_OFF, "no"}, + {LDAP_PASSWD_SYNC_OFF, "No"}, + {LDAP_PASSWD_SYNC_OFF, "off"}, + {LDAP_PASSWD_SYNC_OFF, "Off"}, + {LDAP_PASSWD_SYNC_ONLY, "Only"}, + {LDAP_PASSWD_SYNC_ONLY, "only"}, + {-1, NULL} +}; + /* Types of machine we can announce as. */ #define ANNOUNCE_AS_NT_SERVER 1 #define ANNOUNCE_AS_WIN95 2 @@ -968,6 +984,9 @@ static struct parm_struct parm_table[] = {"ldap filter", P_STRING, P_GLOBAL, &Globals.szLdapFilter, NULL, NULL, 0}, {"ldap admin dn", P_STRING, P_GLOBAL, &Globals.szLdapAdminDn, NULL, NULL, 0}, {"ldap ssl", P_ENUM, P_GLOBAL, &Globals.ldap_ssl, NULL, enum_ldap_ssl, 0}, +#ifdef LDAP_EXOP_X_MODIFY_PASSWD + {"ldap passwd sync", P_ENUM, P_GLOBAL, &Globals.ldap_passwd_sync, NULL, +enum_ldap_passwd_sync, 0}, +#endif /* LDAP_EXOP_X_MODIFY_PASSWD */ {"Miscellaneous Options", P_SEP, P_SEPARATOR}, {"add share command", P_STRING, P_GLOBAL, &Globals.szAddShareCommand, NULL, NULL, 0}, @@ -1334,6 +1353,9 @@ static void init_globals(void) string_set(&Globals.szLdapFilter, "(&(uid=%u)(objectclass=sambaAccount))"); string_set(&Globals.szLdapAdminDn, ""); Globals.ldap_ssl = LDAP_SSL_ON; +#ifdef LDAP_EXOP_X_MODIFY_PASSWD + Globals.ldap_passwd_sync = LDAP_PASSWD_SYNC_OFF; +#endif /* LDAP_EXOP_X_MODIFY_PASSWD */ /* these parameters are set to defaults that are more appropriate for the increasing samba install base: @@ -1543,6 +1565,9 @@ FN_GLOBAL_STRING(lp_ldap_user_suffix, &G FN_GLOBAL_STRING(lp_ldap_filter, &Globals.szLdapFilter) FN_GLOBAL_STRING(lp_ldap_admin_dn, &Globals.szLdapAdminDn) FN_GLOBAL_INTEGER(lp_ldap_ssl, &Globals.ldap_ssl) +#ifdef LDAP_EXOP_X_MODIFY_PASSWD +FN_GLOBAL_INTEGER(lp_ldap_passwd_sync, &Globals.ldap_passwd_sync) +#endif /* LDAP_EXOP_X_MODIFY_PASSWD */ FN_GLOBAL_STRING(lp_add_share_cmd, &Globals.szAddShareCommand) FN_GLOBAL_STRING(lp_change_share_cmd, &Globals.szChangeShareCommand) FN_GLOBAL_STRING(lp_delete_share_cmd, &Globals.szDeleteShareCommand) diff -Npur --exclude=CVS HEAD/source/include/smb.h HEAD-pdb/source/include/smb.h --- HEAD/source/include/smb.h Thu Aug 1 07:25:08 2002 +++ HEAD-pdb/source/include/smb.h Fri Aug 2 09:28:01 2002 @@ -652,7 +652,7 @@ typedef struct sam_passwd DATA_BLOB lm_pw; /* .data is Null if no password */ DATA_BLOB nt_pw; /* .data is Null if no password */ - DATA_BLOB plaintext_pw; /* .data is Null if not available */ + char* plaintext_pw; /* is Null if not available */ uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */ uint32 unknown_3; /* 0x00ff ffff */ @@ -1374,6 +1374,9 @@ enum schema_types {SCHEMA_COMPAT, SCHEMA /* LDAP SSL options */ enum ldap_ssl_types {LDAP_SSL_ON, LDAP_SSL_OFF, LDAP_SSL_START_TLS}; + +/* LDAP PASSWD SYNC methods */ +enum ldap_passwd_sync_types {LDAP_PASSWD_SYNC_ON, LDAP_PASSWD_SYNC_OFF, +LDAP_PASSWD_SYNC_ONLY}; /* Remote architectures we know about. */ enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT, RA_WIN2K, RA_SAMBA}; diff -Npur --exclude=CVS HEAD/source/passdb/passdb.c HEAD-pdb/source/passdb/passdb.c --- HEAD/source/passdb/passdb.c Thu Aug 1 07:25:09 2002 +++ HEAD-pdb/source/passdb/passdb.c Fri Aug 2 11:30:47 2002 @@ -75,11 +75,19 @@ static void pdb_fill_default_sam(SAM_ACC user->private.workstations = ""; user->private.unknown_str = ""; user->private.munged_dial = ""; + + user->private.plaintext_pw = NULL; + } static void destroy_pdb_talloc(SAM_ACCOUNT **user) { if (*user) { + data_blob_clear_free(&((*user)->private.lm_pw)); + data_blob_clear_free(&((*user)->private.nt_pw)); + + if((*user)->private.plaintext_pw!=NULL) + +memset((*user)->private.plaintext_pw,'\0',strlen((*user)->private.plaintext_pw)); talloc_destroy((*user)->mem_ctx); *user = NULL; } @@ -283,7 +291,8 @@ static void pdb_free_sam_contents(SAM_AC data_blob_clear_free(&(user->private.lm_pw)); data_blob_clear_free(&(user->private.nt_pw)); - data_blob_clear_free(&(user->private.plaintext_pw)); + if (user->private.plaintext_pw!=NULL) + +memset(user->private.plaintext_pw,'\0',strlen(user->private.plaintext_pw)); } diff -Npur --exclude=CVS HEAD/source/passdb/pdb_get_set.c HEAD-pdb/source/passdb/pdb_get_set.c --- HEAD/source/passdb/pdb_get_set.c Wed Jul 24 07:57:11 2002 +++ HEAD-pdb/source/passdb/pdb_get_set.c Fri Aug 2 10:31:40 2002 @@ -151,7 +151,7 @@ const uint8* pdb_get_lanman_passwd (cons const char* pdb_get_plaintext_passwd (const SAM_ACCOUNT *sampass) { if (sampass) { - return ((char*)sampass->private.plaintext_pw.data); + return (sampass->private.plaintext_pw); } else return (NULL); @@ -956,14 +956,24 @@ BOOL pdb_set_lanman_passwd (SAM_ACCOUNT below) ********************************************************************/ -BOOL pdb_set_plaintext_pw_only (SAM_ACCOUNT *sampass, const uint8 *password, size_t len) +BOOL pdb_set_plaintext_pw_only (SAM_ACCOUNT *sampass, const char *password) { if (!sampass) return False; - data_blob_clear_free(&sampass->private.plaintext_pw); - - sampass->private.plaintext_pw = data_blob(password, len); + if (password) { + if (sampass->private.plaintext_pw!=NULL) + +memset(sampass->private.plaintext_pw,'\0',strlen(sampass->private.plaintext_pw)+1); + sampass->private.plaintext_pw = talloc_strdup(sampass->mem_ctx, +password); + + if (!sampass->private.plaintext_pw) { + DEBUG(0, ("pdb_set_unknown_str: talloc_strdup() failed!\n")); + return False; + } + + } else { + sampass->private.plaintext_pw = NULL; + } return True; } @@ -1062,7 +1072,10 @@ BOOL pdb_set_plaintext_passwd (SAM_ACCOU if (!pdb_set_lanman_passwd (sampass, new_lanman_p16)) return False; - + + if (!pdb_set_plaintext_pw_only (sampass, plaintext)) + return False; + if (!pdb_set_pass_changed_now (sampass)) return False; diff -Npur --exclude=CVS HEAD/source/passdb/pdb_ldap.c HEAD-pdb/source/passdb/pdb_ldap.c --- HEAD/source/passdb/pdb_ldap.c Tue Jul 30 10:39:13 2002 +++ HEAD-pdb/source/passdb/pdb_ldap.c Fri Aug 2 11:02:05 2002 @@ -1,11 +1,12 @@ /* Unix SMB/CIFS implementation. LDAP protocol helper functions for SAMBA - Copyright (C) Gerald Carter 2001 - Copyright (C) Shahms King 2001 - Copyright (C) Jean François Micouleau 1998 - Copyright (C) Andrew Bartlett 2002 - + Copyright (C) Jean François Micouleau 1998 + Copyright (C) Gerald Carter 2001 + Copyright (C) Shahms King 2001 + Copyright (C) Andrew Bartlett 2002 + Copyright (C) Stefan (metze) Metzmacher 2002 + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -158,7 +159,8 @@ static const char *attr[] = {"uid", "pwd ******************************************************************/ static BOOL ldapsam_open_connection (struct ldapsam_privates *ldap_state, LDAP ** ldap_struct) { - + int version; + if (geteuid() != 0) { DEBUG(0, ("ldap_open_connection: cannot access LDAP when not root..\n")); return False; @@ -171,6 +173,16 @@ static BOOL ldapsam_open_connection (str DEBUG(0, ("ldap_initialize: %s\n", strerror(errno))); return (False); } + + if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == +LDAP_OPT_SUCCESS) + { + if (version != LDAP_VERSION3) + { + version = LDAP_VERSION3; + ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, +&version); + } + } + #else /* Parse the string manually */ @@ -179,7 +191,6 @@ static BOOL ldapsam_open_connection (str int rc; int tls = LDAP_OPT_X_TLS_HARD; int port = 0; - int version; fstring protocol; fstring host; const char *p = ldap_state->uri; @@ -409,7 +420,7 @@ static int ldapsam_search_one_user (stru DEBUG(2, ("ldapsam_search_one_user: searching for:[%s]\n", filter)); - rc = ldap_search_s(ldap_struct, lp_ldap_suffix (), scope, filter, attr, 0, result); + rc = ldap_search_s(ldap_struct, lp_ldap_suffix (), scope, filter, (char +**)attr, 0, result); if (rc != LDAP_SUCCESS) { DEBUG(0,("ldapsam_search_one_user: Problem during the LDAP search: %s\n", @@ -932,9 +943,6 @@ static BOOL init_ldap_from_sam (struct l slprintf(temp, sizeof(temp) - 1, "%i", rid); make_a_mod(mods, ldap_op, "primaryGroupID", temp); - slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_last_set_time(sampass)); - make_a_mod(mods, ldap_op, "pwdLastSet", temp); - /* displayName, cn, and gecos should all be the same * most easily accomplished by giving them the same OID * gecos isn't set here b/c it should be handled by the @@ -977,6 +985,7 @@ static BOOL init_ldap_from_sam (struct l make_a_mod(mods, ldap_op, "kickoffTime", temp); } + if (IS_SAM_SET(sampass, FLAG_SAM_CANCHANGETIME)) { slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_can_change_time(sampass)); make_a_mod(mods, ldap_op, "pwdCanChange", temp); @@ -987,13 +996,26 @@ static BOOL init_ldap_from_sam (struct l make_a_mod(mods, ldap_op, "pwdMustChange", temp); } - /* FIXME: Hours stuff goes in LDAP */ - pdb_sethexpwd (temp, pdb_get_lanman_passwd(sampass), pdb_get_acct_ctrl(sampass)); - make_a_mod (mods, ldap_op, "lmPassword", temp); +#ifdef LDAP_EXOP_X_MODIFY_PASSWD + if (lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_ONLY) + { +#endif /* LDAP_EXOP_X_MODIFY_PASSWD */ + + pdb_sethexpwd (temp, pdb_get_lanman_passwd(sampass), +pdb_get_acct_ctrl(sampass)); + make_a_mod (mods, ldap_op, "lmPassword", temp); - pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass), pdb_get_acct_ctrl(sampass)); - make_a_mod (mods, ldap_op, "ntPassword", temp); + pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass), +pdb_get_acct_ctrl(sampass)); + make_a_mod (mods, ldap_op, "ntPassword", temp); + slprintf (temp, sizeof (temp) - 1, "%li", +pdb_get_pass_last_set_time(sampass)); + make_a_mod(mods, ldap_op, "pwdLastSet", temp); + +#ifdef LDAP_EXOP_X_MODIFY_PASSWD + } +#endif /* LDAP_EXOP_X_MODIFY_PASSWD */ + + /* FIXME: Hours stuff goes in LDAP */ + make_a_mod (mods, ldap_op, "acctFlags", pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass), NEW_PW_FORMAT_SPACE_PADDED_LEN)); @@ -1018,18 +1040,19 @@ static uint32 check_nua_rid_is_avail(str if (ldapsam_search_one_user_by_rid(ldap_state, ldap_struct, final_rid, &result) != LDAP_SUCCESS) { DEBUG(0, ("Cannot allocate NUA RID %d (0x%x), as the confirmation search failed!\n", final_rid, final_rid)); - final_rid = 0; ldap_msgfree(result); + return 0; } if (ldap_count_entries(ldap_struct, result) != 0) { DEBUG(0, ("Cannot allocate NUA RID %d (0x%x), as the RID is already in use!!\n", final_rid, final_rid)); - final_rid = 0; ldap_msgfree(result); + return 0; } DEBUG(5, ("NUA RID %d (0x%x), declared valid\n", final_rid, final_rid)); + ldap_msgfree(result); return final_rid; } @@ -1081,7 +1104,7 @@ static uint32 search_top_nua_rid(struct DEBUG(2, ("ldapsam_get_next_available_nua_rid: searching for:[%s]\n", final_filter)); rc = ldap_search_s(ldap_struct, lp_ldap_suffix(), - LDAP_SCOPE_SUBTREE, final_filter, attr, 0, + LDAP_SCOPE_SUBTREE, final_filter, (char **)attr, 0, &result); if (rc != LDAP_SUCCESS) @@ -1179,7 +1202,7 @@ static BOOL ldapsam_setsampwent(struct p all_string_sub(filter, "%u", "*", sizeof(pstring)); rc = ldap_search_s(ldap_state->ldap_struct, lp_ldap_suffix(), - LDAP_SCOPE_SUBTREE, filter, attr, 0, + LDAP_SCOPE_SUBTREE, filter, (char **)attr, 0, &ldap_state->result); if (rc != LDAP_SUCCESS) @@ -1361,6 +1384,100 @@ static BOOL ldapsam_getsampwsid(struct p return ldapsam_getsampwrid(my_methods, user, rid); } +static BOOL ldapsam_modify_entry(LDAP *ldap_struct,SAM_ACCOUNT *newpwd,char +*dn,LDAPMod **mods,int ldap_op) +{ + int version; + int rc; + + switch(ldap_op) + { + case LDAP_MOD_ADD: + if((rc = +ldap_add_s(ldap_struct,dn,mods))!=LDAP_SUCCESS) + { + char *ld_error; + ldap_get_option(ldap_struct, +LDAP_OPT_ERROR_STRING, + &ld_error); + DEBUG(0, + ("failed to add user with uid = %s +with: %s\n\t%s\n", + pdb_get_username(newpwd), +ldap_err2string(rc), + ld_error)); + free(ld_error); + return False; + } + break; + case LDAP_MOD_REPLACE: + if((rc = +ldap_modify_s(ldap_struct,dn,mods))!=LDAP_SUCCESS) + { + char *ld_error; + ldap_get_option(ldap_struct, +LDAP_OPT_ERROR_STRING, + &ld_error); + DEBUG(0, + ("failed to modify user with uid = %s +with: %s\n\t%s\n", + pdb_get_username(newpwd), +ldap_err2string(rc), + ld_error)); + free(ld_error); + return False; + } + break; + default: + DEBUG(0,("Wrong LDAP operation type: %d!\n",ldap_op)); + return False; + } + +#ifdef LDAP_EXOP_X_MODIFY_PASSWD + if (ldap_get_option(ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == +LDAP_OPT_SUCCESS) + { + if (version != LDAP_VERSION3) + { + version = LDAP_VERSION3; + ldap_set_option (ldap_struct, LDAP_OPT_PROTOCOL_VERSION, +&version); + } + } + + if +((lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_OFF)&&(pdb_get_plaintext_passwd(newpwd)!=NULL)) + { + BerElement *ber; + struct berval *bv; + char *retoid; + struct berval *retdata; + + if ((ber = ber_alloc_t(LBER_USE_DER))==NULL) + { + DEBUG(0,("ber_alloc_t returns NULL\n")); + return False; + } + ber_printf (ber, "{"); + ber_printf (ber, "ts", LDAP_TAG_EXOP_X_MODIFY_PASSWD_ID,dn); + ber_printf (ber, "ts", LDAP_TAG_EXOP_X_MODIFY_PASSWD_NEW, +pdb_get_plaintext_passwd(newpwd)); + ber_printf (ber, "N}"); + + if ((rc = ber_flatten (ber, &bv))<0) + { + DEBUG(0,("ber_flatten returns a value <0\n")); + return False; + } + + ber_free(ber,1); + + if ((rc = ldap_extended_operation_s(ldap_struct, +LDAP_EXOP_X_MODIFY_PASSWD, + bv, NULL, NULL, &retoid, +&retdata))!=LDAP_SUCCESS) + { + DEBUG(0,("LDAP Password could not be changed for user %s: +%s\n", + pdb_get_username(newpwd),ldap_err2string(rc))); + } else { + DEBUG(3,("LDAP Password changed for user +%s\n",pdb_get_username(newpwd))); + + ber_bvfree(retdata); + ber_memfree(retoid); + } + ber_bvfree(bv); + } +#else + DEBUG(10,("LDAP PASSWORD SYNC is not supported!\n")); +#endif /* LDAP_EXOP_X_MODIFY_PASSWD */ + return True; +} + /********************************************************************** Delete entry from LDAP for username *********************************************************************/ @@ -1402,7 +1519,8 @@ static BOOL ldapsam_delete_sam_account(s entry = ldap_first_entry (ldap_struct, result); dn = ldap_get_dn (ldap_struct, entry); - + ldap_msgfree(result); + rc = ldap_delete_s (ldap_struct, dn); ldap_memfree (dn); @@ -1463,23 +1581,18 @@ static BOOL ldapsam_update_sam_account(s entry = ldap_first_entry(ldap_struct, result); dn = ldap_get_dn(ldap_struct, entry); - - rc = ldap_modify_s(ldap_struct, dn, mods); - - if (rc != LDAP_SUCCESS) + ldap_msgfree(result); + + if (!ldapsam_modify_entry(ldap_struct,newpwd,dn,mods,LDAP_MOD_REPLACE)) { - char *ld_error; - ldap_get_option(ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(0, - ("failed to modify user with uid = %s with: %s\n\t%s\n", - pdb_get_username(newpwd), ldap_err2string(rc), - ld_error)); - free(ld_error); + DEBUG(0,("failed to modify user with uid = %s\n", + pdb_get_username(newpwd))); + ldap_mods_free(mods,1); ldap_unbind(ldap_struct); return False; } + DEBUG(2, ("successfully modified uid = %s in the LDAP database\n", pdb_get_username(newpwd))); @@ -1502,7 +1615,7 @@ static BOOL ldapsam_add_sam_account(stru LDAPMod **mods = NULL; int ldap_op; uint32 num_result; - + const char *username = pdb_get_username(newpwd); if (!username || !*username) { DEBUG(0, ("Cannot add user without a username!\n")); @@ -1574,26 +1687,15 @@ static BOOL ldapsam_add_sam_account(stru } make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", "sambaAccount"); - if (ldap_op == LDAP_MOD_REPLACE) { - rc = ldap_modify_s(ldap_struct, dn, mods); - } - else { - rc = ldap_add_s(ldap_struct, dn, mods); - } - - if (rc != LDAP_SUCCESS) + if (!ldapsam_modify_entry(ldap_struct,newpwd,dn,mods,ldap_op)) { - char *ld_error; - - ldap_get_option (ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(0,("failed to modify/add user with uid = %s (dn = %s) with: %s\n\t%s\n", - pdb_get_username(newpwd), dn, ldap_err2string (rc), ld_error)); - free(ld_error); - ldap_mods_free(mods, 1); + DEBUG(0,("failed to modify/add user with uid = %s (dn = %s)\n", + pdb_get_username(newpwd),dn)); + ldap_mods_free(mods,1); ldap_unbind(ldap_struct); return False; } - + DEBUG(2,("added: uid = %s in the LDAP database\n", pdb_get_username(newpwd))); ldap_mods_free(mods, 1); ldap_unbind(ldap_struct);