2007-12-23 19:19:41 -06:00
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
2010-11-28 14:09:30 +01:00
#
2007-12-23 19:19:41 -06:00
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
2010-11-28 14:09:30 +01:00
#
2007-12-23 19:19:41 -06:00
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
2010-11-28 14:09:30 +01:00
#
2007-12-23 19:19:41 -06:00
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
""" Support for reading Samba 3 data files. """
2008-05-22 17:42:18 +02:00
__docformat__ = " restructuredText "
2018-03-22 12:35:11 +00:00
REGISTRY_VALUE_PREFIX = b " SAMBA_REGVAL "
2007-12-23 19:19:41 -06:00
REGISTRY_DB_VERSION = 1
2007-12-24 11:02:52 -06:00
import os
2008-12-18 20:43:05 +00:00
import struct
2007-12-23 19:19:41 -06:00
import tdb
2018-10-11 13:40:23 +13:00
from samba . samba3 import passdb
2018-03-22 12:21:12 +00:00
from samba . samba3 import param as s3param
2020-09-11 14:29:46 -06:00
from samba . common import get_bytes
2018-07-30 18:20:39 +12:00
2013-04-11 17:12:09 +09:30
def fetch_uint32 ( db , key ) :
2008-12-18 20:43:05 +00:00
try :
2013-04-11 17:12:09 +09:30
data = db [ key ]
2008-12-18 20:43:05 +00:00
except KeyError :
return None
assert len ( data ) == 4
return struct . unpack ( " <L " , data ) [ 0 ]
2013-04-11 17:12:09 +09:30
def fetch_int32 ( db , key ) :
2008-12-18 20:43:05 +00:00
try :
2013-04-11 17:12:09 +09:30
data = db [ key ]
2008-12-18 20:43:05 +00:00
except KeyError :
return None
assert len ( data ) == 4
return struct . unpack ( " <l " , data ) [ 0 ]
2013-04-11 17:12:09 +09:30
class DbDatabase ( object ) :
2015-03-12 13:27:49 +00:00
""" Simple Samba 3 TDB database reader. """
2007-12-23 19:19:41 -06:00
def __init__ ( self , file ) :
2007-12-29 18:14:15 -06:00
""" Open a file.
2013-04-11 17:12:09 +09:30
: param file : Path of the file to open , appending . tdb or . ntdb .
2007-12-29 18:14:15 -06:00
"""
2015-03-12 13:27:49 +00:00
self . db = tdb . Tdb ( file + " .tdb " , flags = os . O_RDONLY )
2007-12-29 18:14:15 -06:00
self . _check_version ( )
def _check_version ( self ) :
pass
2007-12-24 11:02:52 -06:00
def close ( self ) :
2007-12-29 18:14:15 -06:00
""" Close resources associated with this object. """
2013-04-11 17:12:09 +09:30
self . db . close ( )
2007-12-23 19:19:41 -06:00
2007-12-29 18:14:15 -06:00
2013-04-11 17:12:09 +09:30
class Registry ( DbDatabase ) :
2007-12-29 18:14:15 -06:00
""" Simple read-only support for reading the Samba3 registry.
2010-11-28 14:09:30 +01:00
2011-08-12 16:19:06 +10:00
: note : This object uses the same syntax for registry key paths as
Samba 3. This particular format uses forward slashes for key path
separators and abbreviations for the predefined key names .
2007-12-29 18:14:15 -06:00
e . g . : HKLM / Software / Bar .
"""
2007-12-23 19:19:41 -06:00
def __len__ ( self ) :
""" Return the number of keys. """
return len ( self . keys ( ) )
def keys ( self ) :
""" Return list with all the keys. """
2018-03-22 12:35:11 +00:00
return [ k . rstrip ( b " \x00 " ) for k in self . db if not k . startswith ( REGISTRY_VALUE_PREFIX ) ]
2007-12-23 19:19:41 -06:00
def subkeys ( self , key ) :
2007-12-29 18:14:15 -06:00
""" Retrieve the subkeys for the specified key.
: param key : Key path .
: return : list with key names
"""
2018-03-28 15:08:40 +13:00
data = self . db . get ( key + b " \x00 " )
2007-12-23 19:19:41 -06:00
if data is None :
return [ ]
2007-12-26 20:55:05 -06:00
( num , ) = struct . unpack ( " <L " , data [ 0 : 4 ] )
2018-03-22 12:35:11 +00:00
keys = data [ 4 : ] . split ( b " \0 " )
assert keys [ - 1 ] == b " "
2007-12-26 20:55:05 -06:00
keys . pop ( )
assert len ( keys ) == num
return keys
2007-12-23 19:19:41 -06:00
def values ( self , key ) :
2007-12-29 18:14:15 -06:00
""" Return a dictionary with the values set for a specific key.
2011-08-12 16:19:06 +10:00
2007-12-29 18:14:15 -06:00
: param key : Key to retrieve values for .
2011-08-12 16:19:06 +10:00
: return : Dictionary with value names as key , tuple with type and
2007-12-29 18:14:15 -06:00
data as value . """
2018-03-28 15:08:40 +13:00
data = self . db . get ( REGISTRY_VALUE_PREFIX + b ' / ' + key + b ' \x00 ' )
2007-12-23 19:19:41 -06:00
if data is None :
return { }
2007-12-26 20:55:05 -06:00
ret = { }
( num , ) = struct . unpack ( " <L " , data [ 0 : 4 ] )
data = data [ 4 : ]
for i in range ( num ) :
# Value name
2018-03-22 12:35:11 +00:00
( name , data ) = data . split ( b " \0 " , 1 )
2007-12-26 20:55:05 -06:00
( type , ) = struct . unpack ( " <L " , data [ 0 : 4 ] )
data = data [ 4 : ]
( value_len , ) = struct . unpack ( " <L " , data [ 0 : 4 ] )
data = data [ 4 : ]
ret [ name ] = ( type , data [ : value_len ] )
data = data [ value_len : ]
return ret
2007-12-23 19:19:41 -06:00
# High water mark keys
2018-03-22 12:46:55 +00:00
IDMAP_HWM_GROUP = b " GROUP HWM \0 "
IDMAP_HWM_USER = b " USER HWM \0 "
2007-12-24 14:16:40 -06:00
2018-03-22 12:46:55 +00:00
IDMAP_GROUP_PREFIX = b " GID "
IDMAP_USER_PREFIX = b " UID "
2007-12-23 19:19:41 -06:00
# idmap version determines auto-conversion
2007-12-24 14:16:40 -06:00
IDMAP_VERSION_V2 = 2
2007-12-23 19:19:41 -06:00
2018-07-30 18:20:39 +12:00
2013-04-11 17:12:09 +09:30
class IdmapDatabase ( DbDatabase ) :
2007-12-29 18:14:15 -06:00
""" Samba 3 ID map database reader. """
2012-09-16 14:18:51 +02:00
2007-12-29 18:14:15 -06:00
def _check_version ( self ) :
2018-03-22 12:46:55 +00:00
assert fetch_int32 ( self . db , b " IDMAP_VERSION \0 " ) == IDMAP_VERSION_V2
2007-12-24 14:16:40 -06:00
2011-08-18 15:15:20 +10:00
def ids ( self ) :
""" Retrieve a list of all ids in this database. """
2018-04-12 16:07:24 +12:00
for k in self . db :
2011-08-18 15:15:20 +10:00
if k . startswith ( IDMAP_USER_PREFIX ) :
2018-03-22 12:46:55 +00:00
yield k . rstrip ( b " \0 " ) . split ( b " " )
2011-08-18 15:15:20 +10:00
if k . startswith ( IDMAP_GROUP_PREFIX ) :
2018-03-22 12:46:55 +00:00
yield k . rstrip ( b " \0 " ) . split ( b " " )
2011-08-18 15:15:20 +10:00
2007-12-24 14:16:40 -06:00
def uids ( self ) :
2007-12-29 18:14:15 -06:00
""" Retrieve a list of all uids in this database. """
2018-03-22 12:46:55 +00:00
for k in self . db :
2007-12-24 14:16:40 -06:00
if k . startswith ( IDMAP_USER_PREFIX ) :
2018-03-22 12:46:55 +00:00
yield int ( k [ len ( IDMAP_USER_PREFIX ) : ] . rstrip ( b " \0 " ) )
2007-12-24 14:16:40 -06:00
def gids ( self ) :
2007-12-29 18:14:15 -06:00
""" Retrieve a list of all gids in this database. """
2018-03-22 12:46:55 +00:00
for k in self . db :
2007-12-24 14:16:40 -06:00
if k . startswith ( IDMAP_GROUP_PREFIX ) :
2018-03-22 12:46:55 +00:00
yield int ( k [ len ( IDMAP_GROUP_PREFIX ) : ] . rstrip ( b " \0 " ) )
2007-12-24 14:16:40 -06:00
2011-08-18 15:15:20 +10:00
def get_sid ( self , xid , id_type ) :
2011-08-25 17:10:23 +10:00
""" Retrive SID associated with a particular id and type.
2018-05-04 22:23:39 +02:00
: param xid : UID or GID to retrieve SID for .
2011-08-25 17:10:23 +10:00
: param id_type : Type of id specified - ' UID ' or ' GID '
"""
2018-10-10 11:16:40 +01:00
data = self . db . get ( get_bytes ( " %s %s \0 " % ( id_type , str ( xid ) ) ) )
2011-08-18 15:15:20 +10:00
if data is None :
return data
return data . rstrip ( " \0 " )
2007-12-24 14:16:40 -06:00
def get_user_sid ( self , uid ) :
2007-12-29 18:14:15 -06:00
""" Retrieve the SID associated with a particular uid.
: param uid : UID to retrieve SID for .
: return : A SID or None if no mapping was found .
"""
2018-03-28 15:08:40 +13:00
data = self . db . get ( IDMAP_USER_PREFIX + str ( uid ) . encode ( ) + b ' \0 ' )
2007-12-24 14:16:40 -06:00
if data is None :
return data
2018-03-22 12:46:55 +00:00
return data . rstrip ( b " \0 " )
2007-12-24 14:16:40 -06:00
def get_group_sid ( self , gid ) :
2018-03-28 15:08:40 +13:00
data = self . db . get ( IDMAP_GROUP_PREFIX + str ( gid ) . encode ( ) + b ' \0 ' )
2007-12-24 14:16:40 -06:00
if data is None :
return data
2018-03-22 12:46:55 +00:00
return data . rstrip ( b " \0 " )
2007-12-24 14:16:40 -06:00
def get_user_hwm ( self ) :
2007-12-29 18:14:15 -06:00
""" Obtain the user high-water mark. """
2013-04-11 17:12:09 +09:30
return fetch_uint32 ( self . db , IDMAP_HWM_USER )
2007-12-24 14:16:40 -06:00
def get_group_hwm ( self ) :
2007-12-29 18:14:15 -06:00
""" Obtain the group high-water mark. """
2013-04-11 17:12:09 +09:30
return fetch_uint32 ( self . db , IDMAP_HWM_GROUP )
2007-12-23 19:19:41 -06:00
2007-12-24 13:04:33 -06:00
2013-04-11 17:12:09 +09:30
class SecretsDatabase ( DbDatabase ) :
2007-12-29 18:14:18 -06:00
""" Samba 3 Secrets database reader. """
2012-09-16 14:18:51 +02:00
2007-12-24 13:04:33 -06:00
def get_auth_password ( self ) :
2018-10-10 11:16:40 +01:00
return self . db . get ( b " SECRETS/AUTH_PASSWORD " )
2007-12-24 13:04:33 -06:00
def get_auth_domain ( self ) :
2018-10-10 11:16:40 +01:00
return self . db . get ( b " SECRETS/AUTH_DOMAIN " )
2007-12-24 13:04:33 -06:00
def get_auth_user ( self ) :
2018-10-10 11:16:40 +01:00
return self . db . get ( b " SECRETS/AUTH_USER " )
2007-12-24 13:04:33 -06:00
2007-12-25 16:36:31 -06:00
def get_domain_guid ( self , host ) :
2018-10-10 11:16:40 +01:00
return self . db . get ( b " SECRETS/DOMGUID/ %s " % host )
2007-12-24 13:04:33 -06:00
2007-12-24 14:16:59 -06:00
def ldap_dns ( self ) :
2018-04-12 16:07:24 +12:00
for k in self . db :
2007-12-24 14:16:59 -06:00
if k . startswith ( " SECRETS/LDAP_BIND_PW/ " ) :
yield k [ len ( " SECRETS/LDAP_BIND_PW/ " ) : ] . rstrip ( " \0 " )
def domains ( self ) :
2007-12-29 18:14:18 -06:00
""" Iterate over domains in this database.
: return : Iterator over the names of domains in this database .
"""
2018-04-12 16:07:24 +12:00
for k in self . db :
2007-12-24 14:16:59 -06:00
if k . startswith ( " SECRETS/SID/ " ) :
yield k [ len ( " SECRETS/SID/ " ) : ] . rstrip ( " \0 " )
2007-12-24 13:04:33 -06:00
def get_ldap_bind_pw ( self , host ) :
2018-10-10 11:16:40 +01:00
return self . db . get ( get_bytes ( " SECRETS/LDAP_BIND_PW/ %s " % host ) )
2011-08-12 16:19:06 +10:00
2007-12-24 13:04:33 -06:00
def get_afs_keyfile ( self , host ) :
2018-10-10 11:16:40 +01:00
return self . db . get ( get_bytes ( " SECRETS/AFS_KEYFILE/ %s " % host ) )
2007-12-24 13:04:33 -06:00
def get_machine_sec_channel_type ( self , host ) :
2018-10-10 11:16:40 +01:00
return fetch_uint32 ( self . db , get_bytes ( " SECRETS/MACHINE_SEC_CHANNEL_TYPE/ %s " % host ) )
2007-12-24 13:04:33 -06:00
def get_machine_last_change_time ( self , host ) :
2013-04-11 17:12:09 +09:30
return fetch_uint32 ( self . db , " SECRETS/MACHINE_LAST_CHANGE_TIME/ %s " % host )
2011-08-12 16:19:06 +10:00
2007-12-24 13:04:33 -06:00
def get_machine_password ( self , host ) :
2018-10-10 11:16:40 +01:00
return self . db . get ( get_bytes ( " SECRETS/MACHINE_PASSWORD/ %s " % host ) )
2007-12-24 13:04:33 -06:00
def get_machine_acc ( self , host ) :
2018-10-10 11:16:40 +01:00
return self . db . get ( get_bytes ( " SECRETS/$MACHINE.ACC/ %s " % host ) )
2007-12-24 13:04:33 -06:00
def get_domtrust_acc ( self , host ) :
2018-10-10 11:16:40 +01:00
return self . db . get ( get_bytes ( " SECRETS/$DOMTRUST.ACC/ %s " % host ) )
2007-12-24 13:04:33 -06:00
2007-12-24 14:16:59 -06:00
def trusted_domains ( self ) :
2018-04-12 16:07:24 +12:00
for k in self . db :
2007-12-24 14:16:59 -06:00
if k . startswith ( " SECRETS/$DOMTRUST.ACC/ " ) :
yield k [ len ( " SECRETS/$DOMTRUST.ACC/ " ) : ] . rstrip ( " \0 " )
2007-12-24 13:04:33 -06:00
def get_random_seed ( self ) :
2018-10-10 11:16:40 +01:00
return self . db . get ( b " INFO/random_seed " )
2007-12-24 13:04:33 -06:00
def get_sid ( self , host ) :
2018-10-10 11:16:40 +01:00
return self . db . get ( get_bytes ( " SECRETS/SID/ %s " % host . upper ( ) ) )
2007-12-24 13:04:33 -06:00
2007-12-23 19:19:41 -06:00
SHARE_DATABASE_VERSION_V1 = 1
SHARE_DATABASE_VERSION_V2 = 2
2012-09-16 14:18:51 +02:00
2013-04-11 17:12:09 +09:30
class ShareInfoDatabase ( DbDatabase ) :
2007-12-29 18:14:18 -06:00
""" Samba 3 Share Info database reader. """
2012-09-16 14:18:51 +02:00
2007-12-29 18:14:15 -06:00
def _check_version ( self ) :
2013-04-11 17:12:09 +09:30
assert fetch_int32 ( self . db , " INFO/version \0 " ) in ( SHARE_DATABASE_VERSION_V1 , SHARE_DATABASE_VERSION_V2 )
2007-12-23 19:19:41 -06:00
def get_secdesc ( self , name ) :
2007-12-29 18:14:18 -06:00
""" Obtain the security descriptor on a particular share.
2011-08-12 16:19:06 +10:00
2007-12-29 18:14:18 -06:00
: param name : Name of the share
"""
2018-10-10 11:16:40 +01:00
secdesc = self . db . get ( get_bytes ( " SECDESC/ %s " % name ) )
2007-12-23 19:19:41 -06:00
# FIXME: Run ndr_pull_security_descriptor
2007-12-24 14:16:40 -06:00
return secdesc
2007-12-23 19:19:41 -06:00
2007-12-25 16:36:23 -06:00
2008-08-01 21:00:09 +02:00
class Shares ( object ) :
2008-05-22 18:47:32 +02:00
""" Container for share objects. """
2007-12-25 16:36:23 -06:00
def __init__ ( self , lp , shareinfo ) :
self . lp = lp
self . shareinfo = shareinfo
def __len__ ( self ) :
2007-12-29 18:14:18 -06:00
""" Number of shares. """
2007-12-25 16:36:23 -06:00
return len ( self . lp ) - 1
def __iter__ ( self ) :
2007-12-29 18:14:18 -06:00
""" Iterate over the share names. """
2007-12-25 16:36:23 -06:00
return self . lp . __iter__ ( )
2007-12-24 13:04:33 -06:00
def shellsplit ( text ) :
""" Very simple shell-like line splitting.
2011-08-12 16:19:06 +10:00
2007-12-24 13:04:33 -06:00
: param text : Text to split .
: return : List with parts of the line as strings .
"""
ret = list ( )
inquotes = False
current = " "
for c in text :
if c == " \" " :
inquotes = not inquotes
elif c in ( " \t " , " \n " , " " ) and not inquotes :
2012-06-16 13:58:06 +10:00
if current != " " :
ret . append ( current )
2007-12-24 13:04:33 -06:00
current = " "
else :
current + = c
if current != " " :
ret . append ( current )
return ret
2007-12-23 19:19:41 -06:00
2008-08-01 21:00:09 +02:00
class WinsDatabase ( object ) :
2007-12-29 18:14:18 -06:00
""" Samba 3 WINS database reader. """
2007-12-23 19:19:41 -06:00
def __init__ ( self , file ) :
2007-12-24 13:04:33 -06:00
self . entries = { }
f = open ( file , ' r ' )
assert f . readline ( ) . rstrip ( " \n " ) == " VERSION 1 0 "
for l in f . readlines ( ) :
2018-07-30 18:19:33 +12:00
if l [ 0 ] == " # " : # skip comments
2007-12-24 13:04:33 -06:00
continue
entries = shellsplit ( l . rstrip ( " \n " ) )
name = entries [ 0 ]
ttl = int ( entries [ 1 ] )
i = 2
ips = [ ]
while " . " in entries [ i ] :
ips . append ( entries [ i ] )
2018-07-30 18:18:03 +12:00
i + = 1
2007-12-27 03:09:49 -06:00
nb_flags = int ( entries [ i ] [ : - 1 ] , 16 )
2018-07-30 18:22:34 +12:00
assert name not in self . entries , " Name %s exists twice " % name
2007-12-24 13:04:33 -06:00
self . entries [ name ] = ( ttl , ips , nb_flags )
f . close ( )
def __getitem__ ( self , name ) :
return self . entries [ name ]
2007-12-23 19:19:41 -06:00
2007-12-24 13:04:33 -06:00
def __len__ ( self ) :
return len ( self . entries )
2007-12-24 14:16:59 -06:00
def __iter__ ( self ) :
return iter ( self . entries )
2007-12-27 03:09:49 -06:00
def items ( self ) :
2008-05-22 18:47:32 +02:00
""" Return the entries in this WINS database. """
2007-12-27 03:09:49 -06:00
return self . entries . items ( )
2018-07-30 18:19:33 +12:00
def close ( self ) : # for consistency
2007-12-24 13:04:33 -06:00
pass
2007-12-23 19:19:41 -06:00
2008-08-01 21:00:09 +02:00
class Samba3 ( object ) :
2007-12-29 18:14:18 -06:00
""" Samba 3 configuration and state data reader. """
2012-09-16 14:18:51 +02:00
2011-08-25 17:10:23 +10:00
def __init__ ( self , smbconfpath , s3_lp_ctx = None ) :
2007-12-29 18:14:18 -06:00
""" Open the configuration and data for a Samba 3 installation.
: param smbconfpath : Path to the smb . conf file .
2011-08-25 17:10:23 +10:00
: param s3_lp_ctx : Samba3 Loadparm context
2007-12-29 18:14:18 -06:00
"""
2007-12-23 19:19:41 -06:00
self . smbconfpath = smbconfpath
2011-08-25 17:10:23 +10:00
if s3_lp_ctx :
self . lp = s3_lp_ctx
else :
self . lp = s3param . get_context ( )
self . lp . load ( smbconfpath )
2007-12-25 16:36:23 -06:00
2011-08-25 17:10:23 +10:00
def statedir_path ( self , path ) :
2007-12-25 16:36:23 -06:00
if path [ 0 ] == " / " or path [ 0 ] == " . " :
return path
2011-08-25 17:10:23 +10:00
return os . path . join ( self . lp . get ( " state directory " ) , path )
2007-12-25 16:36:23 -06:00
2011-08-19 12:30:19 +10:00
def privatedir_path ( self , path ) :
if path [ 0 ] == " / " or path [ 0 ] == " . " :
return path
2011-08-25 17:10:23 +10:00
return os . path . join ( self . lp . get ( " private dir " ) , path )
2011-08-19 12:30:19 +10:00
2007-12-25 16:36:23 -06:00
def get_conf ( self ) :
return self . lp
def get_sam_db ( self ) :
2011-08-25 17:10:23 +10:00
return passdb . PDB ( self . lp . get ( ' passdb backend ' ) )
2010-11-28 14:09:30 +01:00
2007-12-23 19:19:41 -06:00
def get_registry ( self ) :
2013-04-11 17:12:09 +09:30
return Registry ( self . statedir_path ( " registry " ) )
2007-12-23 19:19:41 -06:00
def get_secrets_db ( self ) :
2013-04-11 17:12:09 +09:30
return SecretsDatabase ( self . privatedir_path ( " secrets " ) )
2007-12-23 19:19:41 -06:00
2007-12-25 16:36:23 -06:00
def get_shareinfo_db ( self ) :
2013-04-11 17:12:09 +09:30
return ShareInfoDatabase ( self . statedir_path ( " share_info " ) )
2007-12-23 19:19:41 -06:00
def get_idmap_db ( self ) :
2013-04-11 17:12:09 +09:30
return IdmapDatabase ( self . statedir_path ( " winbindd_idmap " ) )
2007-12-23 19:19:41 -06:00
def get_wins_db ( self ) :
2011-08-25 17:10:23 +10:00
return WinsDatabase ( self . statedir_path ( " wins.dat " ) )
2007-12-25 16:36:23 -06:00
def get_shares ( self ) :
return Shares ( self . get_conf ( ) , self . get_shareinfo_db ( ) )