mirror of
https://github.com/samba-team/samba.git
synced 2025-11-25 00:23:52 +03:00
r26616: Support parsing of user data in SAmba 3 tdbsam.
This commit is contained in:
committed by
Stefan Metzmacher
parent
cc15136c1e
commit
2f33e0451d
@@ -23,7 +23,7 @@ from credentials import Credentials
|
|||||||
class SambaOptions(optparse.OptionGroup):
|
class SambaOptions(optparse.OptionGroup):
|
||||||
def __init__(self, parser):
|
def __init__(self, parser):
|
||||||
optparse.OptionGroup.__init__(self, parser, "Samba Common Options")
|
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")
|
help="Configuration file")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -324,7 +324,8 @@ class SAMUser:
|
|||||||
domain=None, dir_drive=None, munged_dial=None, homedir=None, logon_script=None,
|
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,
|
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,
|
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.username = name
|
||||||
self.uid = uid
|
self.uid = uid
|
||||||
self.lm_password = lm_password
|
self.lm_password = lm_password
|
||||||
@@ -351,37 +352,16 @@ class SAMUser:
|
|||||||
self.pass_can_change_time = pass_can_change_time
|
self.pass_can_change_time = pass_can_change_time
|
||||||
self.pass_must_change_time = pass_must_change_time
|
self.pass_must_change_time = pass_must_change_time
|
||||||
self.user_rid = user_rid
|
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):
|
def __eq__(self, other):
|
||||||
if not isinstance(other, SAMUser):
|
if not isinstance(other, SAMUser):
|
||||||
return False
|
return False
|
||||||
return (self.username == other.username and
|
return self.__dict__ == other.__dict__
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class SmbpasswdFile:
|
class SmbpasswdFile:
|
||||||
def __init__(self, file):
|
def __init__(self, file):
|
||||||
@@ -451,7 +431,7 @@ class LdapSam:
|
|||||||
class TdbSam:
|
class TdbSam:
|
||||||
def __init__(self, file):
|
def __init__(self, file):
|
||||||
self.tdb = tdb.Tdb(file, flags=os.O_RDONLY)
|
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)
|
assert self.version in (0, 1, 2)
|
||||||
|
|
||||||
def usernames(self):
|
def usernames(self):
|
||||||
@@ -463,41 +443,82 @@ class TdbSam:
|
|||||||
|
|
||||||
def __getitem__(self, name):
|
def __getitem__(self, name):
|
||||||
data = self.tdb["%s%s\0" % (TDBSAM_USER_PREFIX, 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 = 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.logoff_time = logoff_time
|
||||||
user.kickoff_time = kickoff_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
|
user.pass_can_change_time = pass_can_change_time
|
||||||
|
|
||||||
# &username_len, &sampass->username, /* B */
|
(user.username, data) = unpack_string(data)
|
||||||
# &domain_len, &sampass->domain, /* B */
|
(user.domain, data) = unpack_string(data)
|
||||||
# &nt_username_len, &sampass->nt_username, /* B */
|
(user.nt_username, data) = unpack_string(data)
|
||||||
# &fullname_len, &sampass->fullname, /* B */
|
(user.fullname, data) = unpack_string(data)
|
||||||
# &homedir_len, &sampass->homedir, /* B */
|
(user.homedir, data) = unpack_string(data)
|
||||||
# &dir_drive_len, &sampass->dir_drive, /* B */
|
(user.dir_drive, data) = unpack_string(data)
|
||||||
# &logon_script_len, &sampass->logon_script, /* B */
|
(user.logon_script, data) = unpack_string(data)
|
||||||
# &profile_path_len, &sampass->profile_path, /* B */
|
(user.profile_path, data) = unpack_string(data)
|
||||||
# &acct_desc_len, &sampass->acct_desc, /* B */
|
(user.acct_desc, data) = unpack_string(data)
|
||||||
# &workstations_len, &sampass->workstations, /* B */
|
(user.workstations, data) = unpack_string(data)
|
||||||
# &unknown_str_len, &sampass->unknown_str, /* B */
|
(user.unknown_str, data) = unpack_string(data)
|
||||||
# &munged_dial_len, &sampass->munged_dial, /* B */
|
(user.munged_dial, data) = unpack_string(data)
|
||||||
# &sampass->user_rid, /* d */
|
|
||||||
# &sampass->group_rid, /* d */
|
(user.user_rid, data) = unpack_int32(data)
|
||||||
# &lm_pw_len, sampass->lm_pw.hash, /* B */
|
(user.group_rid, data) = unpack_int32(data)
|
||||||
# &nt_pw_len, sampass->nt_pw.hash, /* B */
|
|
||||||
# &sampass->acct_ctrl, /* w */
|
(user.lm_password, data) = unpack_string(data)
|
||||||
# &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */
|
(user.nt_password, data) = unpack_string(data)
|
||||||
# &sampass->logon_divs, /* w */
|
|
||||||
# &sampass->hours_len, /* d */
|
if self.version > 1:
|
||||||
# &hourslen, &sampass->hours, /* B */
|
(user.nt_password_history, data) = unpack_string(data)
|
||||||
# &sampass->bad_password_count, /* w */
|
|
||||||
# &sampass->logon_count, /* w */
|
(user.acct_ctrl, data) = unpack_uint16(data)
|
||||||
# &sampass->unknown_6); /* d */
|
(_, 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
|
return user
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
|||||||
@@ -107,9 +107,37 @@ class TdbSamTestCase(unittest.TestCase):
|
|||||||
self.assertEquals(3, len(list(self.samdb.usernames())))
|
self.assertEquals(3, len(list(self.samdb.usernames())))
|
||||||
|
|
||||||
def test_getuser(self):
|
def test_getuser(self):
|
||||||
return
|
|
||||||
user = SAMUser("root")
|
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):
|
class WinsDatabaseTestCase(unittest.TestCase):
|
||||||
|
|||||||
@@ -435,56 +435,3 @@ def import_registry(samba4_registry, samba3_regdb):
|
|||||||
key_handle.set_value(value_name, value_type, value_data)
|
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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user