Hi! The attached patch changes some semantics in pdb_get_set.
I had the problem that I could not join a HEAD PDC with NT4. HEAD tried to do illegal operations with the LDAP account, for example it tried to set "displayName" to "", which is not allowed. I found we have to track what attributes exist in LDAP to make the appropriate change. See the function make_ldap_mod for the core functionality. To enable that, the semantics of IS_SAM_SET changed to: Did this exist in LDAP? and IS_SAM_CHANGED means: Do we have to set it? Not really tested what this semantic change breaks, but with that patch I can now join HEAD with ldapsam again. Comments? BTW, this also does away with the 'cn' and 'displayName' co-treatment. This is simply not possible. Volker Not signed, gpg would destroy the diff ;-) Index: include/smb.h =================================================================== RCS file: /space/vl/cvstree/samba/source/include/smb.h,v retrieving revision 1.479 diff -u -r1.479 smb.h --- include/smb.h 20 Mar 2003 00:32:44 -0000 1.479 +++ include/smb.h 20 Mar 2003 22:53:35 -0000 @@ -628,8 +628,6 @@ (( pdb_get_init_flags(x, PDB_UID) != PDB_DEFAULT ) \ && ( pdb_get_init_flags(x,PDB_GID) != PDB_DEFAULT )) -#define IS_SAM_SET(x, flag) (pdb_get_init_flags(x, flag) == PDB_SET) -#define IS_SAM_CHANGED(x, flag) (pdb_get_init_flags(x, flag) == PDB_CHANGED) #define IS_SAM_DEFAULT(x, flag) (pdb_get_init_flags(x, flag) == PDB_DEFAULT) typedef struct sam_passwd Index: passdb/passdb.c =================================================================== RCS file: /space/vl/cvstree/samba/source/passdb/passdb.c,v retrieving revision 1.187 diff -u -r1.187 passdb.c --- passdb/passdb.c 22 Feb 2003 12:17:02 -0000 1.187 +++ passdb/passdb.c 20 Mar 2003 22:54:10 -0000 @@ -863,7 +863,8 @@ if (pdb_getsampwsid(sam_user, psid)) { - if (!IS_SAM_SET(sam_user,PDB_UID)&&!IS_SAM_CHANGED(sam_user,PDB_UID)) { + if (!pdb_is_sam_set(sam_user,PDB_UID)&& + !pdb_is_sam_changed(sam_user,PDB_UID)) { pdb_free_sam(&sam_user); return False; } Index: passdb/pdb_get_set.c =================================================================== RCS file: /space/vl/cvstree/samba/source/passdb/pdb_get_set.c,v retrieving revision 1.23 diff -u -r1.23 pdb_get_set.c --- passdb/pdb_get_set.c 20 Mar 2003 12:50:29 -0000 1.23 +++ passdb/pdb_get_set.c 20 Mar 2003 22:55:12 -0000 @@ -202,6 +202,22 @@ return ret; } +BOOL pdb_is_sam_set(const SAM_ACCOUNT *sampass, enum pdb_elements element) +{ + if (!sampass || !sampass->private.set_flags) + return False; + + return bitmap_query(sampass->private.set_flags, element); +} + +BOOL pdb_is_sam_changed(const SAM_ACCOUNT *sampass, enum pdb_elements element) +{ + if (!sampass || !sampass->private.change_flags) + return False; + + return bitmap_query(sampass->private.change_flags, element); +} + uid_t pdb_get_uid (const SAM_ACCOUNT *sampass) { if (sampass) @@ -475,17 +491,9 @@ DEBUG(0,("Can't set flag: %d in change_flags.\n",element)); return False; } - if (!bitmap_set(sampass->private.set_flags, element)) { - DEBUG(0,("Can't set flag: %d in set_flags.\n",element)); - return False; - } DEBUG(11, ("element %d -> now CHANGED\n", element)); break; case PDB_SET: - if (!bitmap_clear(sampass->private.change_flags, element)) { - DEBUG(0,("Can't set flag: %d in change_flags.\n",element)); - return False; - } if (!bitmap_set(sampass->private.set_flags, element)) { DEBUG(0,("Can't set flag: %d in set_flags.\n",element)); return False; Index: passdb/pdb_ldap.c =================================================================== RCS file: /space/vl/cvstree/samba/source/passdb/pdb_ldap.c,v retrieving revision 1.88 diff -u -r1.88 pdb_ldap.c --- passdb/pdb_ldap.c 20 Mar 2003 13:21:23 -0000 1.88 +++ passdb/pdb_ldap.c 20 Mar 2003 22:50:33 -0000 @@ -1158,12 +1158,8 @@ * that fits your needs; using cn then displayName rather than 'userFullName' */ - if (!get_single_attribute(ldap_state->ldap_struct, entry, "cn", fullname)) { - if (!get_single_attribute(ldap_state->ldap_struct, entry, "displayName", fullname)) { - /* leave as default */ - } else { - pdb_set_fullname(sampass, fullname, PDB_SET); - } + if (!get_single_attribute(ldap_state->ldap_struct, entry, "displayName", fullname)) { + /* leave as default */ } else { pdb_set_fullname(sampass, fullname, PDB_SET); } @@ -1275,7 +1271,27 @@ if (pdb_add) { return (!IS_SAM_DEFAULT(sampass, element)); } else { - return IS_SAM_CHANGED(sampass, element); + return pdb_is_sam_changed(sampass, element); + } +} + +static void make_ldap_mod(LDAPMod ***mods, const SAM_ACCOUNT *sampass, + enum pdb_elements element, + const char *attrib, const char *newval) +{ + if (!pdb_is_sam_changed(sampass, element)) + return; + + if (pdb_is_sam_set(sampass, element)) { + if (strlen(newval) > 0) { + make_a_mod(mods, LDAP_MOD_REPLACE, attrib, newval); + } else { + make_a_mod(mods, LDAP_MOD_DELETE, attrib, NULL); + } + } else { + if (strlen(newval) > 0) { + make_a_mod(mods, LDAP_MOD_ADD, attrib, newval); + } } } @@ -1349,66 +1365,61 @@ return False; } + make_ldap_mod(mods, sampass, + PDB_FULLNAME, "displayName", + pdb_get_fullname(sampass)); + + make_ldap_mod(mods, sampass, + PDB_ACCTDESC, "description", + pdb_get_acct_desc(sampass)); + + make_ldap_mod(mods, sampass, + PDB_WORKSTATIONS, "userWorkstations", + pdb_get_workstations(sampass)); + + make_ldap_mod(mods, sampass, + PDB_SMBHOME, "smbHome", + pdb_get_homedir(sampass)); + + make_ldap_mod(mods, sampass, + PDB_DRIVE, "homeDrive", + pdb_get_dir_drive(sampass)); + + make_ldap_mod(mods, sampass, + PDB_LOGONSCRIPT, "scriptPath", + pdb_get_logon_script(sampass)); + + make_ldap_mod(mods, sampass, + PDB_PROFILE, "profilePath", + pdb_get_profile_path(sampass)); + + slprintf(temp, sizeof(temp)-1, "%li", pdb_get_logon_time(sampass)); + make_ldap_mod(mods, sampass, + PDB_LOGONTIME, "logonTime", + temp); + + slprintf(temp, sizeof(temp)-1, "%li", pdb_get_logoff_time(sampass)); + make_ldap_mod(mods, sampass, + PDB_LOGOFFTIME, "logoffTime", + 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 - * add-user script - */ - if (need_ldap_mod(pdb_add, sampass, PDB_FULLNAME)) { - make_a_mod(mods, ldap_op, "displayName", pdb_get_fullname(sampass)); - make_a_mod(mods, ldap_op, "cn", pdb_get_fullname(sampass)); - } - if (need_ldap_mod(pdb_add, sampass, PDB_ACCTDESC)) { - make_a_mod(mods, ldap_op, "description", pdb_get_acct_desc(sampass)); - } - if (need_ldap_mod(pdb_add, sampass, PDB_WORKSTATIONS)) { - make_a_mod(mods, ldap_op, "userWorkstations", pdb_get_workstations(sampass)); - } - /* - * Only updates fields which have been set (not defaults from smb.conf) - */ - - if (need_ldap_mod(pdb_add, sampass, PDB_SMBHOME)) { - make_a_mod(mods, ldap_op, "smbHome", pdb_get_homedir(sampass)); - } - - if (need_ldap_mod(pdb_add, sampass, PDB_DRIVE)) { - make_a_mod(mods, ldap_op, "homeDrive", pdb_get_dir_drive(sampass)); - } - - if (need_ldap_mod(pdb_add, sampass, PDB_LOGONSCRIPT)) { - make_a_mod(mods, ldap_op, "scriptPath", pdb_get_logon_script(sampass)); - } - if (need_ldap_mod(pdb_add, sampass, PDB_PROFILE)) - make_a_mod(mods, ldap_op, "profilePath", pdb_get_profile_path(sampass)); - - if (need_ldap_mod(pdb_add, sampass, PDB_LOGONTIME)) { - slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logon_time(sampass)); - make_a_mod(mods, ldap_op, "logonTime", temp); - } - - if (need_ldap_mod(pdb_add, sampass, PDB_LOGOFFTIME)) { - slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logoff_time(sampass)); - make_a_mod(mods, ldap_op, "logoffTime", temp); - } - - if (need_ldap_mod(pdb_add, sampass, PDB_KICKOFFTIME)) { - slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_kickoff_time(sampass)); - make_a_mod(mods, ldap_op, "kickoffTime", temp); - } - - - if (need_ldap_mod(pdb_add, sampass, PDB_CANCHANGETIME)) { - slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_can_change_time(sampass)); - make_a_mod(mods, ldap_op, "pwdCanChange", temp); - } - - if (need_ldap_mod(pdb_add, sampass, PDB_MUSTCHANGETIME)) { - slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_must_change_time(sampass)); - make_a_mod(mods, ldap_op, "pwdMustChange", temp); - } + slprintf (temp, sizeof (temp)-1, "%li", pdb_get_kickoff_time(sampass)); + make_ldap_mod(mods, sampass, + PDB_KICKOFFTIME, "kickoffTime", + temp); + + slprintf (temp, sizeof (temp)-1, "%li", + pdb_get_pass_can_change_time(sampass)); + make_ldap_mod(mods, sampass, + PDB_CANCHANGETIME, "pwdCanChange", + temp); + + slprintf (temp, sizeof (temp)-1, "%li", + pdb_get_pass_must_change_time(sampass)); + make_ldap_mod(mods, sampass, + PDB_MUSTCHANGETIME, "pwdMustChange", + temp); if ((pdb_get_acct_ctrl(sampass)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST))|| (lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_ONLY)) {