r26616: Support parsing of user data in SAmba 3 tdbsam.
authorJelmer Vernooij <jelmer@samba.org>
Fri, 28 Dec 2007 05:31:59 +0000 (23:31 -0600)
committerStefan Metzmacher <metze@samba.org>
Thu, 27 Dec 2007 23:36:06 +0000 (17:36 -0600)
(This used to be commit 2f33e0451d6699fed8bc9abfa2f331317502b358)

source4/scripting/python/samba/getopt.py
source4/scripting/python/samba/samba3.py
source4/scripting/python/samba/tests/samba3.py
source4/scripting/python/samba/upgrade.py

index 3335c55bc68337bafb0382335785a5c10f2ef32e..014dd336d848e96a934c26fa1702bb245f3c84c6 100644 (file)
@@ -23,7 +23,7 @@ from credentials import Credentials
 class SambaOptions(optparse.OptionGroup):
     def __init__(self, parser):
         optparse.OptionGroup.__init__(self, parser, "Samba Common Options")
-        self.add_option("--configfile", type="string", metavar="FILE",
+        self.add_option("-s", "--configfile", type="string", metavar="FILE",
                         help="Configuration file")
 
 
index c9153d85cf451810dcf2255a9464fe805f3ace09..27656900adc41972f70eebb3c1c5052647a9ea1f 100644 (file)
@@ -324,7 +324,8 @@ class SAMUser:
                  domain=None, dir_drive=None, munged_dial=None, homedir=None, logon_script=None,
                  profile_path=None, workstations=None, kickoff_time=None, bad_password_time=None,
                  pass_last_set_time=None, pass_can_change_time=None, pass_must_change_time=None,
-                 user_rid=None):
+                 user_rid=None, unknown_6=None, nt_password_history=None,
+                 unknown_str=None, hours=None, logon_divs=None):
         self.username = name
         self.uid = uid
         self.lm_password = lm_password
@@ -351,37 +352,16 @@ class SAMUser:
         self.pass_can_change_time = pass_can_change_time
         self.pass_must_change_time = pass_must_change_time
         self.user_rid = user_rid
+        self.unknown_6 = unknown_6
+        self.nt_password_history = nt_password_history
+        self.unknown_str = unknown_str
+        self.hours = hours
+        self.logon_divs = logon_divs
 
     def __eq__(self, other): 
         if not isinstance(other, SAMUser):
             return False
-        return (self.username == other.username and 
-                self.uid == other.uid and 
-                self.lm_password == other.lm_password and 
-                self.nt_password == other.nt_password and 
-                self.acct_ctrl == other.acct_ctrl and 
-                self.pass_last_set_time == other.pass_last_set_time and 
-                self.nt_username == other.nt_username and 
-                self.fullname == other.fullname and 
-                self.logon_time == other.logon_time and 
-                self.logoff_time == other.logoff_time and 
-                self.acct_desc == other.acct_desc and 
-                self.group_rid == other.group_rid and 
-                self.bad_password_count == other.bad_password_count and 
-                self.logon_count == other.logon_count and 
-                self.domain == other.domain and 
-                self.dir_drive == other.dir_drive and 
-                self.munged_dial == other.munged_dial and 
-                self.homedir == other.homedir and 
-                self.logon_script == other.logon_script and 
-                self.profile_path == other.profile_path and 
-                self.workstations == other.workstations and 
-                self.kickoff_time == other.kickoff_time and 
-                self.bad_password_time == other.bad_password_time and 
-                self.pass_can_change_time == other.pass_can_change_time and 
-                self.pass_must_change_time == other.pass_must_change_time and 
-                self.user_rid == other.user_rid)
-
+        return self.__dict__ == other.__dict__
 
 class SmbpasswdFile:
     def __init__(self, file):
@@ -451,7 +431,7 @@ class LdapSam:
 class TdbSam:
     def __init__(self, file):
         self.tdb = tdb.Tdb(file, flags=os.O_RDONLY)
-        self.version = self.tdb.fetch_uint32("INFO/version") or 0
+        self.version = self.tdb.fetch_uint32("INFO/version\0") or 0
         assert self.version in (0, 1, 2)
 
     def usernames(self):
@@ -463,41 +443,82 @@ class TdbSam:
     
     def __getitem__(self, name):
         data = self.tdb["%s%s\0" % (TDBSAM_USER_PREFIX, name)]
-        import struct
-        (logon_time, logoff_time, kickoff_time, pass_last_set_time, pass_can_change_time, \
-                pass_must_change_time) = struct.unpack("<llllll", data[:6*4])
         user = SAMUser(name)
-        user.logon_time = logon_time
+        import struct
+    
+        def unpack_string(data):
+            (length, ) = struct.unpack("<L", data[:4])
+            data = data[4:]
+            if length == 0:
+                return (None, data)
+            return (data[:length].rstrip("\0"), data[length:])
+
+        def unpack_int32(data):
+            (value, ) = struct.unpack("<l", data[:4])
+            return (value, data[4:])
+
+        def unpack_uint32(data):
+            (value, ) = struct.unpack("<L", data[:4])
+            return (value, data[4:])
+
+        def unpack_uint16(data):
+            (value, ) = struct.unpack("<H", data[:2])
+            return (value, data[2:])
+
+        (logon_time, data) = unpack_int32(data)
+        (logoff_time, data) = unpack_int32(data)
+        (kickoff_time, data) = unpack_int32(data)
+
+        if self.version > 0:
+            (bad_password_time, data) = unpack_int32(data)
+            if bad_password_time != 0:
+                user.bad_password_time = bad_password_time
+        (pass_last_set_time, data) = unpack_int32(data)
+        (pass_can_change_time, data) = unpack_int32(data)
+        (pass_must_change_time, data) = unpack_int32(data)
+
+        if logon_time != 0:
+            user.logon_time = logon_time
         user.logoff_time = logoff_time
         user.kickoff_time = kickoff_time
-        user.pass_last_set_time = pass_last_set_time
+        if pass_last_set_time != 0:
+            user.pass_last_set_time = pass_last_set_time
         user.pass_can_change_time = pass_can_change_time
 
-#      &username_len, &sampass->username,                      /* B */
-#              &domain_len, &sampass->domain,                          /* B */
-#              &nt_username_len, &sampass->nt_username,                /* B */
-#              &fullname_len, &sampass->fullname,                      /* B */
-#              &homedir_len, &sampass->homedir,                        /* B */
-#              &dir_drive_len, &sampass->dir_drive,                    /* B */
-#              &logon_script_len, &sampass->logon_script,              /* B */
-#              &profile_path_len, &sampass->profile_path,              /* B */
-#              &acct_desc_len, &sampass->acct_desc,                    /* B */
-#              &workstations_len, &sampass->workstations,              /* B */
-#              &unknown_str_len, &sampass->unknown_str,                /* B */
-#              &munged_dial_len, &sampass->munged_dial,                /* B */
-#              &sampass->user_rid,                                     /* d */
-#              &sampass->group_rid,                                    /* d */
-#              &lm_pw_len, sampass->lm_pw.hash,                        /* B */
-#              &nt_pw_len, sampass->nt_pw.hash,                        /* B */
-#              &sampass->acct_ctrl,                                    /* w */
-#              &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */
-#              &sampass->logon_divs,                                   /* w */
-#              &sampass->hours_len,                                    /* d */
-#              &hourslen, &sampass->hours,                             /* B */
-#              &sampass->bad_password_count,                           /* w */
-#              &sampass->logon_count,                                  /* w */
-#              &sampass->unknown_6);                                   /* d */
-#              
+        (user.username, data) = unpack_string(data)
+        (user.domain, data) = unpack_string(data)
+        (user.nt_username, data) = unpack_string(data)
+        (user.fullname, data) = unpack_string(data)
+        (user.homedir, data) = unpack_string(data)
+        (user.dir_drive, data) = unpack_string(data)
+        (user.logon_script, data) = unpack_string(data)
+        (user.profile_path, data) = unpack_string(data)
+        (user.acct_desc, data) = unpack_string(data)
+        (user.workstations, data) = unpack_string(data)
+        (user.unknown_str, data) = unpack_string(data)
+        (user.munged_dial, data) = unpack_string(data)
+
+        (user.user_rid, data) = unpack_int32(data)
+        (user.group_rid, data) = unpack_int32(data)
+
+        (user.lm_password, data) = unpack_string(data)
+        (user.nt_password, data) = unpack_string(data)
+
+        if self.version > 1:
+            (user.nt_password_history, data) = unpack_string(data)
+
+        (user.acct_ctrl, data) = unpack_uint16(data)
+        (_, data) = unpack_uint32(data) # remove_me field
+        (user.logon_divs, data) = unpack_uint16(data)
+        (hours, data) = unpack_string(data)
+        user.hours = []
+        for entry in hours:
+            for i in range(8):
+                user.hours.append(ord(entry) & (2 ** i) == (2 ** i))
+        (user.bad_password_count, data) = unpack_uint16(data)
+        (user.logon_count, data) = unpack_uint16(data)
+        (user.unknown_6, data) = unpack_uint32(data)
+        assert len(data) == 0
         return user
 
     def close(self):
index 22b21ba1b496196d68ece2fef3682952501c5508..175aa90497c0a42343ccbfa887e687e84f3ac822 100644 (file)
@@ -107,9 +107,37 @@ class TdbSamTestCase(unittest.TestCase):
         self.assertEquals(3, len(list(self.samdb.usernames())))
 
     def test_getuser(self):
-        return
         user = SAMUser("root")
-        self.assertEquals(user, self.samdb["root"])
+        user.logoff_time = 2147483647
+        user.kickoff_time = 2147483647
+        user.pass_can_change_time = 1125418267
+        user.username = "root"
+        user.uid = None
+        user.lm_password = 'U)\x02\x03\x1b\xed\xe9\xef\xaa\xd3\xb45\xb5\x14\x04\xee'
+        user.nt_password = '\x87\x8d\x80\x14`l\xda)gzD\xef\xa15?\xc7'
+        user.acct_ctrl = 16
+        user.pass_last_set_time = 1125418267
+        user.fullname = "root"
+        user.nt_username = ""
+        user.logoff_time = 2147483647
+        user.acct_desc = ""
+        user.group_rid = 1001
+        user.logon_count = 0
+        user.bad_password_count = 0
+        user.domain = "BEDWYR"
+        user.munged_dial = ""
+        user.workstations = ""
+        user.user_rid = 1000
+        user.kickoff_time = 2147483647
+        user.logoff_time = 2147483647
+        user.unknown_6 = 1260L
+        user.logon_divs = 0
+        user.hours = [True for i in range(168)]
+        other = self.samdb["root"]
+        for name in other.__dict__:
+            if other.__dict__[name] != user.__dict__[name]:
+                print "%s: %r != %r" % (name, other.__dict__[name], user.__dict__[name])
+        self.assertEquals(user, other)
 
 
 class WinsDatabaseTestCase(unittest.TestCase):
index 3ecfe872f9ec354e11e4f5171ef6476f0afe16bc..abf1127c362a5fea463b21b68eb664d147f2cb4f 100644 (file)
@@ -435,56 +435,3 @@ def import_registry(samba4_registry, samba3_regdb):
             key_handle.set_value(value_name, value_type, value_data)
 
 
-def upgrade(subobj, samba3, message, paths, session_info, credentials):
-    ret = 0
-    samdb = Ldb(paths.samdb, session_info=session_info, credentials=credentials)
-
-    message("Writing configuration")
-    newconf = upgrade_smbconf(samba3.configuration,True)
-    newconf.save(paths.smbconf)
-
-    message("Importing account policies")
-    samdb.modify_ldif(upgrade_sam_policy(samba3,subobj.BASEDN))
-    regdb = Ldb(paths.hklm)
-
-    regdb.modify("""
-dn: value=RefusePasswordChange,key=Parameters,key=Netlogon,key=Services,key=CurrentControlSet,key=System,HIVE=NONE
-replace: type
-type: 4
-replace: data
-data: %d
-""" % policy.refuse_machine_password_change)
-
-    message("Importing users")
-    for account in samba3.samaccounts:
-        msg = "... " + account.username
-        ldif = upgrade_sam_account(samdb, accounts,subobj.BASEDN,subobj.DOMAINSID)
-        try:
-            samdb.add(ldif)
-        except LdbError, e:
-            # FIXME: Ignore 'Record exists' errors
-            msg += "... error: " + str(e)
-            ret += 1; 
-        message(msg)
-
-    message("Importing groups")
-    for mapping in samba3.groupmappings:
-        msg = "... " + mapping.nt_name
-        ldif = upgrade_sam_group(mapping, subobj.BASEDN)
-        if ldif is not None:
-            try:
-                samdb.add(ldif)
-            except LdbError, e:
-                # FIXME: Ignore 'Record exists' errors
-                msg += "... error: " + str(e)
-                ret += 1
-        message(msg)
-
-    message("Importing WINS data")
-    winsdb = Ldb(paths.winsdb)
-    ldb_erase(winsdb)
-
-    ldif = upgrade_wins(samba3)
-    winsdb.add(ldif)
-
-