[PATCH] Upgrade for TDBSAM format

Aurélien Degrémont adegremont at idealx.com
Mon Oct 20 16:23:50 GMT 2003


Hi,

Following the discussion i've got with Simo and Andrew B. about 
upgrading tdbsam, there is a patch for tdbsam.
This patch add :
- A version to tdbsam.
- A version management system.
- Tranparent and automatic conversion of tdbsam files to the latest 
version when they're opened.

Thanks to this, we will be able to add some new fields, and change some 
field formats of current tdbsam as explain is my other mail.

It needs tests.

Waiting for your comments...

Regards,

Aurélien Degrémont


-------------- next part --------------
diff -ruN source/passdb/passdb.c ../samba-tdbsam/source/passdb/passdb.c
--- source/passdb/passdb.c	2003-09-24 19:16:13.000000000 +0200
+++ ../samba-tdbsam/source/passdb/passdb.c	2003-10-17 17:52:54.000000000 +0200
@@ -1280,7 +1280,9 @@
  Marshall/unmarshall SAM_ACCOUNT structs.
  *********************************************************************/
 
-#define TDB_FORMAT_STRING       "ddddddBBBBBBBBBBBBddBBwdwdBdd"
+
+#define TDB_FORMAT_STRING_v0       "ddddddBBBBBBBBBBBBddBBwdwdBdd"
+#define TDB_FORMAT_STRING_v1       "dddddddBBBBBBBBBBBBddBBwdwdBdd"
 
 /**********************************************************************
  Intialize a SAM_ACCOUNT struct from a BYTE buffer of size len
@@ -1288,6 +1290,20 @@
 
 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
@@ -1329,7 +1345,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,
@@ -1457,11 +1473,420 @@
 	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_unknown_5(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_unknown_5(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,
+		pass_last_set_time,
+		pass_can_change_time,
+		pass_must_change_time,
+		lockout_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_5, unknown_6;
+	uint16	acct_ctrl, logon_divs;
+	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,
+		&pass_last_set_time,
+		&pass_can_change_time,
+		&pass_must_change_time,
+		&lockout_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);
+		
+	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_unknown_5(sampass, unknown_5, 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;
 
@@ -1473,6 +1898,7 @@
 		kickoff_time,
 		pass_last_set_time,
 		pass_can_change_time,
+		lockout_time,
 		pass_must_change_time;
 
 	uint32  user_rid, group_rid;
@@ -1514,6 +1940,7 @@
 	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);
+	lockout_time = (uint32) 0;
 
 	user_rid = pdb_get_user_rid(sampass);
 	group_rid = pdb_get_group_rid(sampass);
@@ -1612,13 +2039,14 @@
 		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,
 		pass_last_set_time,
 		pass_can_change_time,
 		pass_must_change_time,
+		lockout_time,
 		username_len, username,
 		domain_len, domain,
 		nt_username_len, nt_username,
@@ -1654,13 +2082,14 @@
 	}
 	
 	/* 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,
 		pass_last_set_time,
 		pass_can_change_time,
 		pass_must_change_time,
+		lockout_time,
 		username_len, username,
 		domain_len, domain,
 		nt_username_len, nt_username,
@@ -1699,6 +2128,7 @@
 }
 
 
+
 /**********************************************************************
 **********************************************************************/
 
@@ -1743,5 +2173,3 @@
 
 	return True;
 }
-
-
diff -ruN source/passdb/pdb_tdb.c ../samba-tdbsam/source/passdb/pdb_tdb.c
--- source/passdb/pdb_tdb.c	2003-08-15 22:39:57.000000000 +0200
+++ ../samba-tdbsam/source/passdb/pdb_tdb.c	2003-10-20 17:24:42.000000000 +0200
@@ -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