[PATCH] Upgrade for TDBSAM formatM

Aurélien Degrémont adegremont at idealx.com
Mon Nov 3 16:19:26 GMT 2003


Jeremy Allison wrote:

>On Mon, Oct 20, 2003 at 06:23:50PM +0200, Aur?lien Degr?mont wrote:
>  
>
>Your version of the old tdb format is not current with what
>is in SAMBA_3_0 CVS. In CVS the one of the DWORDs has been
>replaced with 2 WORDs (bad_password_count and logon_count).
>
>This means the init_buffer_from_sam_v0 in this patch is a
>regression to what we have.
>
>The patch looks good, it's just going to need some work to
>apply with what we currently have in SAMBA_3_0 CVS.
>
>That is what is taking me the time to apply it.
>  
>
Here is the new version of the patch, updated for SAMBA_3_0 
(samba-3.0.1-pre1).
This patch only implements the versionning system of TDBSAM. I had a new 
field (lockout_time) to the new TDBSAM datas only to test it.
The new fields of TDBSAM v1 must be discuss. It's useless to apply this 
patch if we must add others fields in few days/weeks that will compel to 
create a other tdbformat (v2) just after this one (v1). I have already 
talked about them here (lockout_time, nt_password, munged_dial).
Except this, the patch is ok.

Aurélien Degrémont


-------------- next part --------------
diff -ruN samba-3.0.1pre1/source/passdb/passdb.c samba-tdbsam-3.0.1pre1/source/passdb/passdb.c
--- samba-3.0.1pre1/source/passdb/passdb.c	2003-10-10 20:08:36.000000000 +0200
+++ samba-tdbsam-3.0.1pre1/source/passdb/passdb.c	2003-11-03 15:49:44.000000000 +0100
@@ -1288,7 +1288,8 @@
  Marshall/unmarshall SAM_ACCOUNT structs.
  *********************************************************************/
 
-#define TDB_FORMAT_STRING       "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
+#define TDB_FORMAT_STRING_v0       "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
+#define TDB_FORMAT_STRING_V1       "dddddddBBBBBBBBBBBBddBBwdwdBwwd"
 
 /**********************************************************************
  Intialize a SAM_ACCOUNT struct from a BYTE buffer of size len
@@ -1296,6 +1297,21 @@
 
 BOOL init_sam_from_buffer(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen)
 {
+	return(init_sam_from_buffer_v1(sampass, buf, buflen));
+}
+
+/**********************************************************************
+ Intialize a BYTE buffer from a SAM_ACCOUNT struct
+ *********************************************************************/
+
+uint32 init_buffer_from_sam (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_only)
+{
+	return(init_buffer_from_sam_v1(buf, sampass, size_only));
+}
+
+
+BOOL init_sam_from_buffer_v0(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen)
+{
 
 	/* times are stored as 32bit integer
 	   take care on system with 64bit wide time_t
@@ -1338,7 +1354,7 @@
 	}
 									
 	/* unpack the buffer into variables */
-	len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING,
+	len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_v0,
 		&logon_time,
 		&logoff_time,
 		&kickoff_time,
@@ -1468,11 +1484,425 @@
 	return ret;
 }
 
-/**********************************************************************
- Intialize a BYTE buffer from a SAM_ACCOUNT struct
- *********************************************************************/
 
-uint32 init_buffer_from_sam (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_only)
+uint32 init_buffer_from_sam_v0 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_only)
+{
+	size_t len, buflen;
+
+	/* times are stored as 32bit integer
+	   take care on system with 64bit wide time_t
+	   --SSS */
+	uint32	logon_time,
+		logoff_time,
+		kickoff_time,
+		pass_last_set_time,
+		pass_can_change_time,
+		pass_must_change_time;
+
+	uint32  user_rid, group_rid;
+
+	const char *username;
+	const char *domain;
+	const char *nt_username;
+	const char *dir_drive;
+	const char *unknown_str;
+	const char *munged_dial;
+	const char *fullname;
+	const char *homedir;
+	const char *logon_script;
+	const char *profile_path;
+	const char *acct_desc;
+	const char *workstations;
+	uint32	username_len, domain_len, nt_username_len,
+		dir_drive_len, unknown_str_len, munged_dial_len,
+		fullname_len, homedir_len, logon_script_len,
+		profile_path_len, acct_desc_len, workstations_len;
+
+	const uint8 *lm_pw;
+	const uint8 *nt_pw;
+	uint32	lm_pw_len = 16;
+	uint32	nt_pw_len = 16;
+
+	/* do we have a valid SAM_ACCOUNT pointer? */
+	if (sampass == NULL) {
+		DEBUG(0, ("init_buffer_from_sam: SAM_ACCOUNT is NULL!\n"));
+		return -1;
+	}
+	
+	*buf = NULL;
+	buflen = 0;
+
+	logon_time = (uint32)pdb_get_logon_time(sampass);
+	logoff_time = (uint32)pdb_get_logoff_time(sampass);
+	kickoff_time = (uint32)pdb_get_kickoff_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);
+
+	user_rid = pdb_get_user_rid(sampass);
+	group_rid = pdb_get_group_rid(sampass);
+
+	username = pdb_get_username(sampass);
+	if (username)
+		username_len = strlen(username) +1;
+	else
+		username_len = 0;
+
+	domain = pdb_get_domain(sampass);
+	if (domain)
+		domain_len = strlen(domain) +1;
+	else
+		domain_len = 0;
+
+	nt_username = pdb_get_nt_username(sampass);
+	if (nt_username)
+		nt_username_len = strlen(nt_username) +1;
+	else
+		nt_username_len = 0;
+
+	fullname = pdb_get_fullname(sampass);
+	if (fullname)
+		fullname_len = strlen(fullname) +1;
+	else
+		fullname_len = 0;
+
+	/*
+	 * Only updates fields which have been set (not defaults from smb.conf)
+	 */
+
+	if (!IS_SAM_DEFAULT(sampass, PDB_DRIVE)) 
+		dir_drive = pdb_get_dir_drive(sampass);
+	else
+		dir_drive = NULL;
+	if (dir_drive)
+		dir_drive_len = strlen(dir_drive) +1;
+	else
+		dir_drive_len = 0;
+
+	if (!IS_SAM_DEFAULT(sampass, PDB_SMBHOME))
+		homedir = pdb_get_homedir(sampass);
+	else
+		homedir = NULL;
+	if (homedir)
+		homedir_len = strlen(homedir) +1;
+	else
+		homedir_len = 0;
+
+	if (!IS_SAM_DEFAULT(sampass, PDB_LOGONSCRIPT))
+		logon_script = pdb_get_logon_script(sampass);
+	else
+		logon_script = NULL;
+	if (logon_script)
+		logon_script_len = strlen(logon_script) +1;
+	else
+		logon_script_len = 0;
+
+	if (!IS_SAM_DEFAULT(sampass, PDB_PROFILE))
+		profile_path = pdb_get_profile_path(sampass);
+	else
+		profile_path = NULL;
+	if (profile_path)
+		profile_path_len = strlen(profile_path) +1;
+	else
+		profile_path_len = 0;
+	
+	lm_pw = pdb_get_lanman_passwd(sampass);
+	if (!lm_pw)
+		lm_pw_len = 0;
+	
+	nt_pw = pdb_get_nt_passwd(sampass);
+	if (!nt_pw)
+		nt_pw_len = 0;
+		
+	acct_desc = pdb_get_acct_desc(sampass);
+	if (acct_desc)
+		acct_desc_len = strlen(acct_desc) +1;
+	else
+		acct_desc_len = 0;
+
+	workstations = pdb_get_workstations(sampass);
+	if (workstations)
+		workstations_len = strlen(workstations) +1;
+	else
+		workstations_len = 0;
+
+	unknown_str = NULL;
+	unknown_str_len = 0;
+
+	munged_dial = pdb_get_munged_dial(sampass);
+	if (munged_dial)
+		munged_dial_len = strlen(munged_dial) +1;
+	else
+		munged_dial_len = 0;	
+		
+	/* one time to get the size needed */
+	len = tdb_pack(NULL, 0,  TDB_FORMAT_STRING_v0,
+		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,
+		nt_pw_len, nt_pw,
+		pdb_get_acct_ctrl(sampass),
+		pdb_get_unknown_3(sampass),
+		pdb_get_logon_divs(sampass),
+		pdb_get_hours_len(sampass),
+		MAX_HOURS_LEN, pdb_get_hours(sampass),
+		pdb_get_bad_password_count(sampass),
+		pdb_get_logon_count(sampass),
+		pdb_get_unknown_6(sampass));
+
+
+	if (size_only)
+		return buflen;
+
+	/* malloc the space needed */
+	if ( (*buf=(uint8*)malloc(len)) == NULL) {
+		DEBUG(0,("init_buffer_from_sam: Unable to malloc() memory for buffer!\n"));
+		return (-1);
+	}
+	
+	/* now for the real call to tdb_pack() */
+	buflen = tdb_pack((char *)*buf, len,  TDB_FORMAT_STRING_v0,
+		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,
+		nt_pw_len, nt_pw,
+		pdb_get_acct_ctrl(sampass),
+		pdb_get_unknown_3(sampass),
+		pdb_get_logon_divs(sampass),
+		pdb_get_hours_len(sampass),
+		MAX_HOURS_LEN, pdb_get_hours(sampass),
+		pdb_get_bad_password_count(sampass),
+		pdb_get_logon_count(sampass),
+		pdb_get_unknown_6(sampass));
+	
+	
+	/* check to make sure we got it correct */
+	if (buflen != len) {
+		DEBUG(0, ("init_buffer_from_sam: somthing odd is going on here: bufflen (%lu) != len (%lu) in tdb_pack operations!\n", 
+			  (unsigned long)buflen, (unsigned long)len));  
+		/* error */
+		SAFE_FREE (*buf);
+		return (-1);
+	}
+
+	return (buflen);
+}
+
+
+BOOL init_sam_from_buffer_v1(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen)
+{
+
+	/* times are stored as 32bit integer
+	   take care on system with 64bit wide time_t
+	   --SSS */
+	uint32	logon_time,
+		logoff_time,
+		kickoff_time,
+		lockout_time,
+		pass_last_set_time,
+		pass_can_change_time,
+		pass_must_change_time;
+	char *username;
+	char *domain;
+	char *nt_username;
+	char *dir_drive;
+	char *unknown_str;
+	char *munged_dial;
+	char *fullname;
+	char *homedir;
+	char *logon_script;
+	char *profile_path;
+	char *acct_desc;
+	char *workstations;
+	uint32	username_len, domain_len, nt_username_len,
+		dir_drive_len, unknown_str_len, munged_dial_len,
+		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_6;
+	uint16	acct_ctrl, logon_divs;
+	uint16	bad_password_count, logon_count;
+	uint8	*hours;
+	static uint8	*lm_pw_ptr, *nt_pw_ptr;
+	uint32		len = 0;
+	uint32		lm_pw_len, nt_pw_len, hourslen;
+	BOOL ret = True;
+	
+	if(sampass == NULL || buf == NULL) {
+		DEBUG(0, ("init_sam_from_buffer: NULL parameters found!\n"));
+		return False;
+	}
+									
+	/* unpack the buffer into variables */
+	len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_v1,
+		&logon_time,
+		&logoff_time,
+		&kickoff_time,
+		&lockout_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,
+		&bad_password_count,
+		&logon_count,
+		&unknown_6);
+		
+	if (len == -1)  {
+		ret = False;
+		goto done;
+	}
+
+	pdb_set_logon_time(sampass, logon_time, PDB_SET);
+	pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
+	pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
+	pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
+	pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
+	pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
+
+	pdb_set_username(sampass, username, PDB_SET); 
+	pdb_set_domain(sampass, domain, PDB_SET);
+	pdb_set_nt_username(sampass, nt_username, PDB_SET);
+	pdb_set_fullname(sampass, fullname, PDB_SET);
+
+	if (homedir) {
+		pdb_set_homedir(sampass, homedir, PDB_SET);
+	}
+	else {
+		pdb_set_homedir(sampass, 
+			talloc_sub_basic(sampass->mem_ctx, username, lp_logon_home()),
+			PDB_DEFAULT);
+	}
+
+	if (dir_drive) 	
+		pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
+	else {
+		pdb_set_dir_drive(sampass, 
+			talloc_sub_basic(sampass->mem_ctx,  username, lp_logon_drive()),
+			PDB_DEFAULT);
+	}
+
+	if (logon_script) 
+		pdb_set_logon_script(sampass, logon_script, PDB_SET);
+	else {
+		pdb_set_logon_script(sampass, 
+			talloc_sub_basic(sampass->mem_ctx, username, lp_logon_script()),
+			PDB_DEFAULT);
+	}
+	
+	if (profile_path) {	
+		pdb_set_profile_path(sampass, profile_path, PDB_SET);
+	} else {
+		pdb_set_profile_path(sampass, 
+			talloc_sub_basic(sampass->mem_ctx, username, lp_logon_path()),
+			PDB_DEFAULT);
+	}
+
+	pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
+	pdb_set_workstations(sampass, workstations, PDB_SET);
+	pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
+
+	if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
+		if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
+			ret = False;
+			goto done;
+		}
+	}
+
+	if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
+		if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
+			ret = False;
+			goto done;
+		}
+	}
+
+	pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
+	pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
+	pdb_set_unknown_3(sampass, unknown_3, PDB_SET);
+	pdb_set_hours_len(sampass, hours_len, PDB_SET);
+	pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
+	pdb_set_logon_count(sampass, logon_count, PDB_SET);
+	pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
+	pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
+	pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
+	pdb_set_hours(sampass, hours, PDB_SET);
+
+done:
+
+	SAFE_FREE(username);
+	SAFE_FREE(domain);
+	SAFE_FREE(nt_username);
+	SAFE_FREE(fullname);
+	SAFE_FREE(homedir);
+	SAFE_FREE(dir_drive);
+	SAFE_FREE(logon_script);
+	SAFE_FREE(profile_path);
+	SAFE_FREE(acct_desc);
+	SAFE_FREE(workstations);
+	SAFE_FREE(munged_dial);
+	SAFE_FREE(unknown_str);
+	SAFE_FREE(hours);
+
+	return ret;
+}
+
+
+uint32 init_buffer_from_sam_v1 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_only)
 {
 	size_t len, buflen;
 
@@ -1482,6 +1912,7 @@
 	uint32	logon_time,
 		logoff_time,
 		kickoff_time,
+		lockout_time,
 		pass_last_set_time,
 		pass_can_change_time,
 		pass_must_change_time;
@@ -1522,6 +1953,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)0;
 	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);
@@ -1623,10 +2055,11 @@
 		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_v1,
 		logon_time,
 		logoff_time,
 		kickoff_time,
+		lockout_time,
 		pass_last_set_time,
 		pass_can_change_time,
 		pass_must_change_time,
@@ -1666,10 +2099,11 @@
 	}
 	
 	/* 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_v1,
 		logon_time,
 		logoff_time,
 		kickoff_time,
+		lockout_time,
 		pass_last_set_time,
 		pass_can_change_time,
 		pass_must_change_time,
@@ -1756,5 +2190,3 @@
 
 	return True;
 }
-
-
diff -ruN samba-3.0.1pre1/source/passdb/pdb_tdb.c samba-tdbsam-3.0.1pre1/source/passdb/pdb_tdb.c
--- samba-3.0.1pre1/source/passdb/pdb_tdb.c	2003-08-15 22:39:57.000000000 +0200
+++ samba-tdbsam-3.0.1pre1/source/passdb/pdb_tdb.c	2003-11-03 15:35:52.000000000 +0100
@@ -37,10 +37,12 @@
 
 #endif
 
+#define TDBSAM_VERSION	1			/* Most recent TDBSAM version */
 #define PDB_VERSION		"20010830"
 #define PASSDB_FILE_NAME	"passdb.tdb"
 #define USERPREFIX		"USER_"
 #define RIDPREFIX		"RID_"
+#define tdbsamver_t 	int32
 
 struct tdbsam_privates {
 	TDB_CONTEXT 	*passwd_tdb;
@@ -50,6 +52,177 @@
 	const char *tdbsam_location;
 };
 
+/**
+ * Convert old TDBSAM to the latest version.
+ * @param pdb_tdb A pointer to the opened TDBSAM file which must be converted. 
+ *                This file must be opened with read/write access.
+ * @param from Current version of the TDBSAM file.
+ * @return True if the conversion has been successful, false otherwise. 
+ **/
+
+static BOOL tdbsam_convert(TDB_CONTEXT *pdb_tdb, tdbsamver_t from) 
+{
+	const char * vstring = "INFO/version";
+	SAM_ACCOUNT *user = NULL;
+	const char *prefix = USERPREFIX;
+	TDB_DATA 	data, key, old_key;
+	uint8		*buf = NULL;
+	BOOL 		ret;
+
+	if (pdb_tdb == NULL) {
+		DEBUG(0,("tdbsam_convert: Bad TDB Context pointer.\n"));
+		return False;
+	}
+
+	/* handle a Samba upgrade */
+	tdb_lock_bystring(pdb_tdb, vstring, 0);
+	
+	if (!NT_STATUS_IS_OK(pdb_init_sam(&user))) {
+		DEBUG(0,("tdbsam_convert: cannot initialized a SAM_ACCOUNT.\n"));
+		return False;
+	}
+
+	/* Enumerate all records and convert them */
+	key = tdb_firstkey(pdb_tdb);
+
+	while (key.dptr) {
+	
+		/* skip all non-USER entries (eg. RIDs) */
+		while ((key.dsize != 0) && (strncmp(key.dptr, prefix, strlen (prefix)))) {
+			old_key = key;
+			/* increment to next in line */
+			key = tdb_nextkey(pdb_tdb, key);
+			SAFE_FREE(old_key.dptr);
+		}
+	
+		if (key.dptr) {
+			
+			/* read from tdbsam */
+			data = tdb_fetch(pdb_tdb, key);
+			if (!data.dptr) {
+				DEBUG(0,("tdbsam_convert: database entry not found: %s.\n",key.dptr));
+				return False;
+			}
+	
+			if (!NT_STATUS_IS_OK(pdb_reset_sam(user))) {
+				DEBUG(0,("tdbsam_convert: cannot reset SAM_ACCOUNT.\n"));
+				SAFE_FREE(data.dptr);
+				return False;
+			}
+			
+			/* unpack the buffer from the former format */
+			DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) (version:%d)\n", key.dptr, from));
+			switch (from) {
+				case 0:
+					ret = init_sam_from_buffer_v0(user, (uint8 *)data.dptr, data.dsize);
+					break;
+				case 1:
+					ret = init_sam_from_buffer_v1(user, (uint8 *)data.dptr, data.dsize);
+					break;
+				default:
+					/* unknown tdbsam version */
+					ret = False;
+			}
+			if (!ret) {
+				DEBUG(0,("tdbsam_convert: Bad SAM_ACCOUNT entry returned from TDB (key:%s) (version:%d)\n", key.dptr, from));
+				SAFE_FREE(data.dptr);
+				return False;
+			}
+	
+			/* pack from the buffer into the new format */
+			DEBUG(10,("tdbsam_convert: Try packing a record (key:%s) (version:%d)\n", key.dptr, from));
+			if ((data.dsize=init_buffer_from_sam (&buf, user, False)) == -1) {
+				DEBUG(0,("tdbsam_convert: cannot pack the SAM_ACCOUNT into the new format\n"));
+				SAFE_FREE(data.dptr);
+				return False;
+			}
+			data.dptr = (char *)buf;
+			
+			/* Store the buffer inside the TDBSAM */
+			if (tdb_store(pdb_tdb, key, data, TDB_MODIFY) != TDB_SUCCESS) {
+				DEBUG(0,("tdbsam_convert: cannot store the SAM_ACCOUNT (key:%s) in new format\n",key.dptr));
+				SAFE_FREE(data.dptr);
+				return False;
+			}
+			
+			SAFE_FREE(data.dptr);
+			
+			/* increment to next in line */
+			old_key = key;
+			key = tdb_nextkey(pdb_tdb, key);
+			SAFE_FREE(old_key.dptr);
+		}
+		
+	}
+
+	pdb_free_sam(&user);
+	
+	/* upgrade finished */
+	tdb_store_int32(pdb_tdb, vstring, TDBSAM_VERSION);
+	tdb_unlock_bystring(pdb_tdb, vstring);
+
+	return(True);	
+}
+
+/**
+ * Open the TDB passwd database, check version and convert it if needed.
+ * @param name filename of the tdbsam file.
+ * @param open_flags file access mode.
+ * @return a TDB_CONTEXT handle on the tdbsam file.
+ **/
+
+static TDB_CONTEXT * tdbsam_tdbopen (const char *name, int open_flags)
+{
+	TDB_CONTEXT 	*pdb_tdb;
+	TDB_DATA 	data, key;
+	tdbsamver_t		version;
+	
+	/* Try to open tdb passwd */
+	if (!(pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT, open_flags, 0600)))
+		return NULL;
+
+	/* Check the version */
+	version = (tdbsamver_t) tdb_fetch_int32(pdb_tdb, "INFO/version");
+	if (version == -1)
+		version = 0;	/* Version not found, assume version 0 */
+	
+	/* Compare the version */
+	if (version > TDBSAM_VERSION) {
+		/* Version more recent than the latest known */ 
+		DEBUG(0, ("TDBSAM version unknown: %d\n", version));
+		tdb_close(pdb_tdb);
+		pdb_tdb = NULL;
+	} 
+	else if (version < TDBSAM_VERSION) {
+		/* Older version, must be converted */
+		DEBUG(1, ("TDBSAM version too old (%d), trying to convert it.\n", version));
+		
+		/* Reopen the pdb file with read-write access if needed */
+		if (!(open_flags & O_RDWR)) {
+			DEBUG(10, ("tdbsam_tdbopen: TDB file opened with read only access, reopen it with read-write access.\n"));
+			tdb_close(pdb_tdb);
+			pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT, (open_flags & 07777770) | O_RDWR, 0600);
+		}
+		
+		/* Convert */
+		if (!tdbsam_convert(pdb_tdb, version)){
+			DEBUG(0, ("tdbsam_tdbopen: Error when trying to convert tdbsam: %s\n",name));
+			tdb_close(pdb_tdb);
+			pdb_tdb = NULL;
+		} else {
+			DEBUG(1, ("TDBSAM converted successfully.\n"));
+		}
+
+		/* Reopen the pdb file as it must be */
+		if (!(open_flags & O_RDWR)) {
+			tdb_close(pdb_tdb);
+			pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT, open_flags, 0600);
+		}
+	}
+	
+	return pdb_tdb;
+}
+
 /***************************************************************
  Open the TDB passwd database for SAM account enumeration.
 ****************************************************************/
@@ -59,7 +232,7 @@
 	struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
 	
 	/* Open tdb passwd */
-	if (!(tdb_state->passwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, update?(O_RDWR|O_CREAT):O_RDONLY, 0600)))
+	if (!(tdb_state->passwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, update?(O_RDWR|O_CREAT):O_RDONLY)))
 	{
 		DEBUG(0, ("Unable to open/create TDB passwd\n"));
 		return NT_STATUS_UNSUCCESSFUL;
@@ -179,7 +352,7 @@
 	key.dsize = strlen(keystr) + 1;
 
 	/* open the accounts TDB */
-	if (!(pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
+	if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY))) {
 	
 		if (errno == ENOENT) {
 			/*
@@ -251,7 +424,7 @@
 	key.dsize = strlen (keystr) + 1;
 
 	/* open the accounts TDB */
-	if (!(pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
+	if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY))) {
 		DEBUG(0, ("pdb_getsampwrid: Unable to open TDB rid database!\n"));
 		return nt_status;
 	}
@@ -265,6 +438,7 @@
 		return nt_status;
 	}
 
+
 	fstrcpy(name, data.dptr);
 	SAFE_FREE(data.dptr);
 	
@@ -299,7 +473,7 @@
 	strlower_m(name);
 	
 	/* open the TDB */
-	if (!(pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDWR, 0600))) {
+	if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR))) {
 		DEBUG(0, ("Unable to open TDB passwd!"));
 		return nt_status;
 	}
@@ -363,7 +537,7 @@
 
  	/* open the account TDB passwd*/
 	
-	pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600);
+	pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR | O_CREAT);
 	
   	if (!pwd_tdb) {
 		DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", 
@@ -519,4 +693,3 @@
 {
 	return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
 }
-


More information about the samba-technical mailing list