Move tdbsam versioning/upgrade code into 3.0
authorJim McDonough <jmcd@samba.org>
Fri, 13 Feb 2004 14:48:20 +0000 (14:48 +0000)
committerJim McDonough <jmcd@samba.org>
Fri, 13 Feb 2004 14:48:20 +0000 (14:48 +0000)
(This used to be commit 730c07cac2166812f4a2da5cfba7152d168b2bdd)

source3/passdb/passdb.c
source3/passdb/pdb_tdb.c

index 1549fd0e6617fb098fb3fa69735d2ffd1e6e0983..603b4d71d2daa9b26fb9a1993dc9b5924b8516d1 100644 (file)
@@ -1297,13 +1297,29 @@ BOOL local_sid_to_gid(gid_t *pgid, const DOM_SID *psid, enum SID_NAME_USE *name_
  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
  *********************************************************************/
 
 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
@@ -1332,7 +1348,7 @@ BOOL init_sam_from_buffer(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen)
                fullname_len, homedir_len, logon_script_len,
                profile_path_len, acct_desc_len, workstations_len;
                
-       uint32  user_rid, group_rid, fields_present, hours_len, unknown_6;
+       uint32  user_rid, group_rid, remove_me, hours_len, unknown_6;
        uint16  acct_ctrl, logon_divs;
        uint16  bad_password_count, logon_count;
        uint8   *hours;
@@ -1347,7 +1363,7 @@ BOOL init_sam_from_buffer(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen)
        }
                                                                        
        /* 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,
@@ -1371,7 +1387,7 @@ BOOL init_sam_from_buffer(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen)
                &lm_pw_len, &lm_pw_ptr,
                &nt_pw_len, &nt_pw_ptr,
                &acct_ctrl,
-               &fields_present,
+               &remove_me, /* remove on the next TDB_FORMAT upgarde */
                &logon_divs,
                &hours_len,
                &hourslen, &hours,
@@ -1449,7 +1465,6 @@ BOOL init_sam_from_buffer(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen)
 
        pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
        pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
-       pdb_set_fields_present(sampass, fields_present, 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);
@@ -1477,11 +1492,8 @@ done:
        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;
 
@@ -1632,7 +1644,7 @@ uint32 init_buffer_from_sam (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_
                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_V0,
                logon_time,
                logoff_time,
                kickoff_time,
@@ -1656,7 +1668,7 @@ uint32 init_buffer_from_sam (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_
                lm_pw_len, lm_pw,
                nt_pw_len, nt_pw,
                pdb_get_acct_ctrl(sampass),
-               pdb_get_fields_present(sampass),
+               0, /* was: fileds_present, to be removed on format change */
                pdb_get_logon_divs(sampass),
                pdb_get_hours_len(sampass),
                MAX_HOURS_LEN, pdb_get_hours(sampass),
@@ -1675,7 +1687,7 @@ uint32 init_buffer_from_sam (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_
        }
        
        /* 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_V0,
                logon_time,
                logoff_time,
                kickoff_time,
@@ -1699,7 +1711,427 @@ uint32 init_buffer_from_sam (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_
                lm_pw_len, lm_pw,
                nt_pw_len, nt_pw,
                pdb_get_acct_ctrl(sampass),
-               pdb_get_fields_present(sampass),
+               0, /* was: fileds_present, to be removed on format change */
+               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,
+               bad_password_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, remove_me, 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,
+               &bad_password_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,
+               &remove_me,
+               &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_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;
+
+       /* times are stored as 32bit integer
+          take care on system with 64bit wide time_t
+          --SSS */
+       uint32  logon_time,
+               logoff_time,
+               kickoff_time,
+               bad_password_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);
+       bad_password_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);
+
+       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_V1,
+               logon_time,
+               logoff_time,
+               kickoff_time,
+               bad_password_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),
+               0,
+               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_V1,
+               logon_time,
+               logoff_time,
+               kickoff_time,
+               bad_password_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),
+               0,
                pdb_get_logon_divs(sampass),
                pdb_get_hours_len(sampass),
                MAX_HOURS_LEN, pdb_get_hours(sampass),
@@ -1765,5 +2197,3 @@ BOOL get_free_rid_range(uint32 *low, uint32 *high)
 
        return True;
 }
-
-
index 554d330ce02b3855b571718c60a931a1e770673c..9bfb10c400951d1fbff81dfb19e07cf6838b6bc5 100644 (file)
@@ -37,13 +37,15 @@ static int tdbsam_debug_level = DBGC_ALL;
 
 #endif
 
-#define PDB_VERSION            "20010830"
+#define TDBSAM_VERSION 1       /* Most recent TDBSAM version */
+#define TDBSAM_VERSION_STRING  "INFO/version"
 #define PASSDB_FILE_NAME       "passdb.tdb"
 #define USERPREFIX             "USER_"
 #define RIDPREFIX              "RID_"
+#define tdbsamver_t    int32
 
 struct tdbsam_privates {
-       TDB_CONTEXT     *passwd_tdb;
+       TDB_CONTEXT     *passwd_tdb;
 
        /* retrive-once info */
        const char *tdbsam_location;
@@ -55,24 +57,183 @@ struct pwent_list {
 };
 static struct pwent_list *tdbsam_pwent_list;
 
-/*****************************************************************************
- Utility functions to open the tdb sam database
- ****************************************************************************/
 
-static TDB_CONTEXT * tdbsam_tdbopen (const char *name, int open_flags)
+/**
+ * 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) 
 {
-       TDB_CONTEXT *tdb;
+       const char * vstring = TDBSAM_VERSION_STRING;
+       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);
+               }
                
-       if ( !(tdb = tdb_open_log(name, 0, TDB_DEFAULT, open_flags, 0600)) )    {
+       }
+
+       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;
+       tdbsamver_t     version;
+       
+       /* Try to open tdb passwd */
+       if (!(pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT, 
+                                    open_flags, 0600))) {
                DEBUG(0, ("Unable to open/create TDB passwd\n"));
                return NULL;
        }
 
-       return tdb;
+       /* Check the version */
+       version = (tdbsamver_t) tdb_fetch_int32(pdb_tdb, 
+                                               TDBSAM_VERSION_STRING);
+       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;
 }
 
 /*****************************************************************************
- Utility functions to open the tdb sam database
+ Utility functions to close the tdb sam database
  ****************************************************************************/
 
 static void tdbsam_tdbclose ( struct tdbsam_privates *state )
@@ -233,7 +394,7 @@ static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, SAM_ACCOUNT
                DEBUG(0,("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n"));
                return nt_status;
        }
-       
+
        /* Data is stored in all lower-case */
        fstrcpy(name, sname);
        strlower_m(name);
@@ -316,20 +477,21 @@ static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, SAM_ACCOUNT
        key.dsize = strlen (keystr) + 1;
 
        /* open the accounts TDB */
-       if ( !(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY)) ) {
+       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;
        }
 
        /* get the record */
        data = tdb_fetch (pwd_tdb, key);
-       if ( !data.dptr ) {
+       if (!data.dptr) {
                DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
                DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
                tdb_close (pwd_tdb);
                return nt_status;
        }
 
+
        fstrcpy(name, data.dptr);
        SAFE_FREE(data.dptr);