Hi, As I said yesterday, I worked on a solution for tdb format in order to manage easily new fields for this format. So I add small changes to init_sam_from_buffer and init_buffer_from_sam in this purpose. The data TDB_FORMAT_STRING became an array which contains the list of the different fields format which exist. When the tdb file is read, for each records, Samba will try the most recent format defined into the sources and, if the data length doesn't fit, he fallbacks to a previous format, and so on...until there is no others formats availables. With this method, we could add new fields at the end of the records and preserve compatibility ! Each record will be read in its original format and be write into the newest format. So, the tranformation is transparent. The conversion, between different tdb versions, works in both directions. The patch is not functionnal. It is just a proposition and I will finish it if you agree. It is designed for passdb.c RC4 and add 2 fields (bad pwd count, lock out time) which are not implemented (into other files), are just here as examples. I'm waiting for your comments :) TIA Aur?lien Degr?mont -------------- next part -------------- --- ../samba-clean/source/passdb/passdb.c Mon Sep 15 01:57:54 2003 +++ source/passdb/passdb.c Tue Sep 23 16:55:46 2003 @@ -78,6 +78,7 @@ user->private.pass_can_change_time = (time_t)0; user->private.logoff_time = user->private.kickoff_time = + user->private.lockout_time = (time_t)0; user->private.pass_must_change_time = get_time_t_max(); user->private.unknown_3 = 0x00ffffff; /* don't know */ user->private.logon_divs = 168; /* hours per week */ @@ -85,6 +86,7 @@ memset(user->private.hours, 0xff, user->private.hours_len); /* available at all hours */ user->private.unknown_5 = 0x00000000; /* don't know */ user->private.unknown_6 = 0x000004ec; /* don't know */ + user->private.bad_pwd_count = 0; /* Some parts of samba strlen their pdb_get...() returns, so this keeps the interface unchanged for now. */ @@ -1269,7 +1271,21 @@ Marshall/unmarshall SAM_ACCOUNT structs. *********************************************************************/ -#define TDB_FORMAT_STRING "ddddddBBBBBBBBBBBBddBBwdwdBdd" + + +/** List of different formats ** + They must be ordered by size. + The eldest is the first (index 0). + The newest is the last. + */ +const char * TDB_FORMAT_STRING[] = { + "ddddddBBBBBBBBBBBBddBBwdwdBdd" , // Version 0 + "ddddddBBBBBBBBBBBBddBBwdwdBdddd" // Version 1 (include bad password count et logon time) + }; + +// Index of the most recent version +#define TDB_FORMAT_NEWEST_VERSION 1 + /********************************************************************** Intialize a SAM_ACCOUNT struct from a BYTE buffer of size len @@ -1284,6 +1300,7 @@ uint32 logon_time, logoff_time, kickoff_time, + lockout_time, pass_last_set_time, pass_can_change_time, pass_must_change_time; @@ -1304,12 +1321,13 @@ fullname_len, homedir_len, logon_script_len, profile_path_len, acct_desc_len, workstations_len; - uint32 user_rid, group_rid, unknown_3, hours_len, unknown_5, unknown_6; + uint32 user_rid, group_rid, unknown_3, hours_len, unknown_5, unknown_6, bad_pwd_count; uint16 acct_ctrl, logon_divs; uint8 *hours; static uint8 *lm_pw_ptr, *nt_pw_ptr; - uint32 len = 0; + uint32 len = -1; uint32 lm_pw_len, nt_pw_len, hourslen; + short int format_version = TDB_FORMAT_NEWEST_VERSION; BOOL ret = True; if(sampass == NULL || buf == NULL) { @@ -1317,38 +1335,58 @@ return False; } - /* unpack the buffer into variables */ - len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING, - &logon_time, - &logoff_time, - &kickoff_time, - &pass_last_set_time, - &pass_can_change_time, - &pass_must_change_time, - &username_len, &username, - &domain_len, &domain, - &nt_username_len, &nt_username, - &fullname_len, &fullname, - &homedir_len, &homedir, - &dir_drive_len, &dir_drive, - &logon_script_len, &logon_script, - &profile_path_len, &profile_path, - &acct_desc_len, &acct_desc, - &workstations_len, &workstations, - &unknown_str_len, &unknown_str, - &munged_dial_len, &munged_dial, - &user_rid, - &group_rid, - &lm_pw_len, &lm_pw_ptr, - &nt_pw_len, &nt_pw_ptr, - &acct_ctrl, - &unknown_3, - &logon_divs, - &hours_len, - &hourslen, &hours, - &unknown_5, - &unknown_6); - + /* Initialize the fields which could be non-initialized by the tdb_unpack() due to different tdb format */ + bad_pwd_count = 0; + lockout_time = (time_t) 0; + + + /* try successively the tdb format */ + while (len == -1 && format_version >= 0) { + + DEBUG(20, ("init_sam_from_buffer: try to use the version %d of tdb format for the record\n", format_version)); + + /* unpack the buffer into variables */ + len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING[format_version], + &logon_time, + &logoff_time, + &kickoff_time, + &pass_last_set_time, + &pass_can_change_time, + &pass_must_change_time, + &username_len, &username, + &domain_len, &domain, + &nt_username_len, &nt_username, + &fullname_len, &fullname, + &homedir_len, &homedir, + &dir_drive_len, &dir_drive, + &logon_script_len, &logon_script, + &profile_path_len, &profile_path, + &acct_desc_len, &acct_desc, + &workstations_len, &workstations, + &unknown_str_len, &unknown_str, + &munged_dial_len, &munged_dial, + &user_rid, + &group_rid, + &lm_pw_len, &lm_pw_ptr, + &nt_pw_len, &nt_pw_ptr, + &acct_ctrl, + &unknown_3, + &logon_divs, + &hours_len, + &hourslen, &hours, + &unknown_5, + &unknown_6, + &lockout_time, + &bad_pwd_count); + + /* If a error has occured, try the next format */ + if (len == -1) { + format_version--; + DEBUG(20, ("init_sam_from_buffer: cannot use the tdb format version %d for the record\n",format_version)); + } + } + + if (len == -1) { ret = False; goto done; @@ -1427,6 +1465,9 @@ pdb_set_logon_divs(sampass, logon_divs, PDB_SET); pdb_set_hours(sampass, hours, PDB_SET); + pdb_set_lockout_time(sampass, lockout_time, PDB_SET); + pdb_set_bad_pwd_count(sampass, bad_pwd_count, PDB_SET); + done: SAFE_FREE(username); @@ -1460,11 +1501,12 @@ uint32 logon_time, logoff_time, kickoff_time, + lockout_time, pass_last_set_time, pass_can_change_time, pass_must_change_time; - uint32 user_rid, group_rid; + uint32 user_rid, group_rid, bad_pwd_count; const char *username; const char *domain; @@ -1500,6 +1542,7 @@ logon_time = (uint32)pdb_get_logon_time(sampass); logoff_time = (uint32)pdb_get_logoff_time(sampass); kickoff_time = (uint32)pdb_get_kickoff_time(sampass); + lockout_time = (uint32)pdb_get_lockout_time(sampass); pass_can_change_time = (uint32)pdb_get_pass_can_change_time(sampass); pass_must_change_time = (uint32)pdb_get_pass_must_change_time(sampass); pass_last_set_time = (uint32)pdb_get_pass_last_set_time(sampass); @@ -1598,10 +1641,11 @@ if (munged_dial) munged_dial_len = strlen(munged_dial) +1; else - munged_dial_len = 0; - + munged_dial_len = 0; + + /* one time to get the size needed */ - len = tdb_pack(NULL, 0, TDB_FORMAT_STRING, + len = tdb_pack(NULL, 0, TDB_FORMAT_STRING[TDB_FORMAT_NEWEST_VERSION], logon_time, logoff_time, kickoff_time, @@ -1630,7 +1674,9 @@ pdb_get_hours_len(sampass), MAX_HOURS_LEN, pdb_get_hours(sampass), pdb_get_unknown_5(sampass), - pdb_get_unknown_6(sampass)); + pdb_get_unknown_6(sampass), + lockout_time, + pdb_get_bad_pwd_count(sampass)); if (size_only) @@ -1643,7 +1689,7 @@ } /* now for the real call to tdb_pack() */ - buflen = tdb_pack((char *)*buf, len, TDB_FORMAT_STRING, + buflen = tdb_pack((char *)*buf, len, TDB_FORMAT_STRING[TDB_FORMAT_NEWEST_VERSION], logon_time, logoff_time, kickoff_time, @@ -1672,7 +1718,9 @@ pdb_get_hours_len(sampass), MAX_HOURS_LEN, pdb_get_hours(sampass), pdb_get_unknown_5(sampass), - pdb_get_unknown_6(sampass)); + pdb_get_unknown_6(sampass), + lockout_time, + pdb_get_bad_pwd_count(sampass)); /* check to make sure we got it correct */ @@ -1732,5 +1780,3 @@ return True; } - -