2010-06-24 08:33:58 +04:00
#!/usr/bin/env python
2007-11-21 15:07:16 +03:00
# Unix SMB/CIFS implementation.
2008-01-25 03:02:13 +03:00
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
2009-12-30 23:48:42 +03:00
#
2008-01-25 03:02:13 +03:00
# Based on the original in EJS:
2007-11-21 15:07:16 +03:00
# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
2009-12-30 23:48:42 +03:00
#
2007-11-21 15:07:16 +03: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.
2009-12-30 23:48:42 +03:00
#
2007-11-21 15:07:16 +03: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.
2009-12-30 23:48:42 +03:00
#
2007-11-21 15:07:16 +03: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/>.
#
2008-05-24 06:01:57 +04:00
""" Samba 4. """
2008-05-22 19:42:18 +04:00
__docformat__ = " restructuredText "
2007-11-21 15:07:16 +03:00
import os
2010-03-31 00:06:45 +04:00
import sys
2007-11-21 15:07:16 +03:00
2010-11-03 21:12:17 +03:00
def in_source_tree ( ) :
2007-12-16 19:17:37 +03:00
""" Check whether the script is being run from the source dir. """
2009-04-23 03:21:47 +04:00
return os . path . exists ( " %s /../../../selftest/skip " % os . path . dirname ( __file__ ) )
2007-12-16 17:33:58 +03:00
2007-12-16 19:17:37 +03:00
2007-12-16 17:33:58 +03:00
# When running, in-tree, make sure bin/python is in the PYTHONPATH
2010-11-03 21:12:17 +03:00
if in_source_tree ( ) :
2007-12-16 19:17:37 +03:00
srcdir = " %s /../../.. " % os . path . dirname ( __file__ )
sys . path . append ( " %s /bin/python " % srcdir )
default_ldb_modules_dir = " %s /bin/modules/ldb " % srcdir
2008-05-22 03:50:38 +04:00
else :
default_ldb_modules_dir = None
2007-12-16 19:17:37 +03:00
2007-12-16 17:33:58 +03:00
2007-12-16 17:50:02 +03:00
import ldb
2010-04-04 04:01:47 +04:00
from samba . _ldb import Ldb as _Ldb
2007-12-17 10:20:20 +03:00
2010-04-04 04:01:47 +04:00
class Ldb ( _Ldb ) :
2009-12-30 23:48:42 +03:00
""" Simple Samba-specific LDB subclass that takes care
2007-12-17 10:20:20 +03:00
of setting up the modules dir , credentials pointers , etc .
2009-12-30 23:48:42 +03:00
Please note that this is intended to be for all Samba LDB files ,
not necessarily the Sam database . For Sam - specific helper
2007-12-17 10:20:20 +03:00
functions see samdb . py .
2007-11-21 15:07:16 +03:00
"""
2010-09-22 08:33:30 +04:00
2009-08-15 17:20:09 +04:00
def __init__ ( self , url = None , lp = None , modules_dir = None , session_info = None ,
credentials = None , flags = 0 , options = None ) :
""" Opens a Samba Ldb file.
2007-12-17 10:20:20 +03:00
2007-12-17 13:12:36 +03:00
: param url : Optional LDB URL to open
2009-08-15 17:20:09 +04:00
: param lp : Optional loadparm object
: param modules_dir : Optional modules directory
2007-12-17 10:20:20 +03:00
: param session_info : Optional session information
: param credentials : Optional credentials , defaults to anonymous .
2009-08-15 17:20:09 +04:00
: param flags : Optional LDB flags
: param options : Additional options ( optional )
2007-12-17 10:20:20 +03:00
This is different from a regular Ldb file in that the Samba - specific
2009-12-30 23:48:42 +03:00
modules - dir is used by default and that credentials and session_info
2007-12-17 10:20:20 +03:00
can be passed through ( required by some modules ) .
"""
2007-12-17 13:12:36 +03:00
2007-12-17 10:20:20 +03:00
if modules_dir is not None :
2007-12-17 13:12:36 +03:00
self . set_modules_dir ( modules_dir )
elif default_ldb_modules_dir is not None :
self . set_modules_dir ( default_ldb_modules_dir )
2009-07-18 20:39:20 +04:00
elif lp is not None :
self . set_modules_dir ( os . path . join ( lp . get ( " modules dir " ) , " ldb " ) )
2007-12-17 13:12:36 +03:00
2007-12-17 10:20:20 +03:00
if session_info is not None :
2008-05-23 05:20:37 +04:00
self . set_session_info ( session_info )
2007-12-17 13:12:36 +03:00
2009-08-15 17:20:09 +04:00
if credentials is not None :
self . set_credentials ( credentials )
2007-12-20 17:53:56 +03:00
2007-12-17 10:20:20 +03:00
if lp is not None :
2008-05-23 05:20:37 +04:00
self . set_loadparm ( lp )
2007-12-17 13:12:36 +03:00
2009-08-15 17:20:09 +04:00
# This must be done before we load the schema, as these handlers for
# objectSid and objectGUID etc must take precedence over the 'binary
# attribute' declaration in the schema
2010-04-04 04:07:46 +04:00
self . register_samba_handlers ( )
2009-08-15 17:20:09 +04:00
# TODO set debug
2010-09-29 02:09:09 +04:00
def msg ( l , text ) :
2007-12-18 04:21:14 +03:00
print text
2007-12-18 19:21:13 +03:00
#self.set_debug(msg)
2007-12-18 04:21:14 +03:00
2010-04-04 04:01:47 +04:00
self . set_utf8_casefold ( )
2009-08-15 17:20:09 +04:00
# Allow admins to force non-sync ldb for all databases
2009-08-17 15:40:19 +04:00
if lp is not None :
nosync_p = lp . get ( " nosync " , " ldb " )
2010-03-01 06:46:40 +03:00
if nosync_p is not None and nosync_p == True :
2010-04-08 22:28:11 +04:00
flags | = ldb . FLG_NOSYNC
2009-08-15 17:20:09 +04:00
2010-06-20 03:37:06 +04:00
self . set_create_perms ( 0600 )
2009-10-27 21:52:21 +03:00
2009-08-17 15:40:19 +04:00
if url is not None :
self . connect ( url , flags , options )
2007-12-18 04:21:28 +03:00
2009-12-30 23:48:42 +03:00
def searchone ( self , attribute , basedn = None , expression = None ,
2007-12-20 01:27:38 +03:00
scope = ldb . SCOPE_BASE ) :
2007-12-24 04:19:41 +03:00
""" Search for one attribute as a string.
2009-12-30 23:48:42 +03:00
2007-12-24 04:19:41 +03:00
: param basedn : BaseDN for the search .
: param attribute : Name of the attribute
: param expression : Optional search expression .
: param scope : Search scope ( defaults to base ) .
: return : Value of attribute as a string or None if it wasn ' t found.
"""
2007-12-18 19:21:13 +03:00
res = self . search ( basedn , scope , expression , [ attribute ] )
2007-12-17 10:20:20 +03:00
if len ( res ) != 1 or res [ 0 ] [ attribute ] is None :
return None
2007-12-20 01:27:31 +03:00
values = set ( res [ 0 ] [ attribute ] )
assert len ( values ) == 1
2008-01-25 05:54:33 +03:00
return self . schema_format_value ( attribute , values . pop ( ) )
2007-12-17 10:20:20 +03:00
2009-09-06 23:08:08 +04:00
def erase_users_computers ( self , dn ) :
2010-06-20 04:32:23 +04:00
""" Erases user and computer objects from our AD.
2010-11-28 16:09:30 +03:00
2010-06-20 04:32:23 +04:00
This is needed since the ' samldb ' module denies the deletion of primary
groups . Therefore all groups shouldn ' t be primary somewhere anymore.
"""
2009-09-06 23:08:08 +04:00
try :
res = self . search ( base = dn , scope = ldb . SCOPE_SUBTREE , attrs = [ ] ,
expression = " (|(objectclass=user)(objectclass=computer)) " )
2010-03-01 07:04:23 +03:00
except ldb . LdbError , ( errno , _ ) :
if errno == ldb . ERR_NO_SUCH_OBJECT :
# Ignore no such object errors
return
else :
raise
2009-09-06 23:08:08 +04:00
try :
for msg in res :
2010-06-19 00:20:22 +04:00
self . delete ( msg . dn , [ " relax:0 " ] )
2010-03-01 07:04:23 +03:00
except ldb . LdbError , ( errno , _ ) :
if errno != ldb . ERR_NO_SUCH_OBJECT :
# Ignore no such object errors
raise
2009-09-06 23:08:08 +04:00
2009-08-17 05:33:25 +04:00
def erase_except_schema_controlled ( self ) :
2010-06-11 01:12:53 +04:00
""" Erase this ldb.
2010-11-28 16:09:30 +03:00
2010-06-11 01:12:53 +04:00
: note : Removes all records , except those that are controlled by
Samba4 ' s schema.
"""
2009-09-06 23:08:08 +04:00
2008-01-11 18:13:46 +03:00
basedn = " "
2009-09-06 23:08:08 +04:00
# Try to delete user/computer accounts to allow deletion of groups
self . erase_users_computers ( basedn )
2009-08-25 10:27:20 +04:00
# Delete the 'visible' records, and the invisble 'deleted' records (if this DB supports it)
2009-12-30 23:48:42 +03:00
for msg in self . search ( basedn , ldb . SCOPE_SUBTREE ,
2010-06-20 04:32:23 +04:00
" (&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO))) " ,
2010-09-20 00:36:12 +04:00
[ ] , controls = [ " show_deleted:0 " , " show_recycled:0 " ] ) :
2007-12-20 01:27:38 +03:00
try :
2010-06-19 00:20:22 +04:00
self . delete ( msg . dn , [ " relax:0 " ] )
2010-03-01 07:04:23 +03:00
except ldb . LdbError , ( errno , _ ) :
if errno != ldb . ERR_NO_SUCH_OBJECT :
# Ignore no such object errors
raise
2009-12-30 23:48:42 +03:00
res = self . search ( basedn , ldb . SCOPE_SUBTREE ,
2010-09-20 00:36:12 +04:00
" (&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO))) " , [ ] , controls = [ " show_deleted:0 " , " show_recycled:0 " ] )
2007-12-17 10:20:20 +03:00
assert len ( res ) == 0
2007-11-21 15:07:16 +03:00
2009-08-13 08:37:06 +04:00
# delete the specials
2009-12-30 23:48:42 +03:00
for attr in [ " @SUBCLASSES " , " @MODULES " ,
2009-08-13 08:37:06 +04:00
" @OPTIONS " , " @PARTITION " , " @KLUDGEACL " ] :
try :
2010-06-19 00:20:22 +04:00
self . delete ( attr , [ " relax:0 " ] )
2010-03-01 07:04:23 +03:00
except ldb . LdbError , ( errno , _ ) :
if errno != ldb . ERR_NO_SUCH_OBJECT :
# Ignore missing dn errors
raise
2009-08-13 08:37:06 +04:00
2009-08-17 05:33:25 +04:00
def erase ( self ) :
""" Erase this ldb, removing all records. """
self . erase_except_schema_controlled ( )
# delete the specials
for attr in [ " @INDEXLIST " , " @ATTRIBUTES " ] :
try :
2010-06-19 00:20:22 +04:00
self . delete ( attr , [ " relax:0 " ] )
2010-03-01 07:04:23 +03:00
except ldb . LdbError , ( errno , _ ) :
2010-03-01 18:24:29 +03:00
if errno != ldb . ERR_NO_SUCH_OBJECT :
2010-03-01 07:04:23 +03:00
# Ignore missing dn errors
raise
2009-08-17 05:33:25 +04:00
2007-12-20 01:27:38 +03:00
def load_ldif_file_add ( self , ldif_path ) :
""" Load a LDIF file.
: param ldif_path : Path to LDIF file .
"""
2007-12-24 04:19:41 +03:00
self . add_ldif ( open ( ldif_path , ' r ' ) . read ( ) )
2007-12-20 01:27:38 +03:00
2009-11-20 14:22:38 +03:00
def add_ldif ( self , ldif , controls = None ) :
2007-12-30 03:14:15 +03:00
""" Add data based on a LDIF string.
: param ldif : LDIF text .
"""
2007-12-20 01:27:38 +03:00
for changetype , msg in self . parse_ldif ( ldif ) :
assert changetype == ldb . CHANGETYPE_NONE
2010-09-29 02:09:09 +04:00
self . add ( msg , controls )
2007-12-20 01:27:38 +03:00
2009-11-20 14:22:38 +03:00
def modify_ldif ( self , ldif , controls = None ) :
2007-12-30 03:14:15 +03:00
""" Modify database based on a LDIF string.
: param ldif : LDIF text .
"""
2008-01-02 10:52:31 +03:00
for changetype , msg in self . parse_ldif ( ldif ) :
2010-06-20 04:32:23 +04:00
if changetype == ldb . CHANGETYPE_ADD :
2010-01-06 01:15:35 +03:00
self . add ( msg , controls )
else :
self . modify ( msg , controls )
2007-12-24 04:19:41 +03:00
2007-11-21 15:07:16 +03:00
def substitute_var ( text , values ) :
2010-06-11 01:12:53 +04:00
""" Substitute strings of the form $ {NAME} in str, replacing
2010-06-20 17:22:49 +04:00
with substitutions from values .
2009-12-30 23:48:42 +03:00
2007-11-21 15:07:16 +03:00
: param text : Text in which to subsitute .
: param values : Dictionary with keys and values .
"""
for ( name , value ) in values . items ( ) :
2007-12-18 19:21:13 +03:00
assert isinstance ( name , str ) , " %r is not a string " % name
assert isinstance ( value , str ) , " Value %r for %s is not a string " % ( value , name )
2007-11-21 15:07:16 +03:00
text = text . replace ( " $ { %s } " % name , value )
return text
2007-12-10 12:29:45 +03:00
2008-01-25 00:18:27 +03:00
def check_all_substituted ( text ) :
2010-11-28 16:09:30 +03:00
""" Check that all substitution variables in a string have been replaced.
2008-01-25 00:18:27 +03:00
If not , raise an exception .
2009-12-30 23:48:42 +03:00
2008-01-25 00:18:27 +03:00
: param text : The text to search for substitution variables
"""
if not " $ { " in text :
2009-02-24 03:02:26 +03:00
return
2009-12-30 23:48:42 +03:00
2008-01-25 00:18:27 +03:00
var_start = text . find ( " $ { " )
var_end = text . find ( " } " , var_start )
2009-12-30 23:48:42 +03:00
2010-11-28 16:09:30 +03:00
raise Exception ( " Not all variables substituted: %s " %
text [ var_start : var_end + 1 ] )
2008-01-25 00:18:27 +03:00
2010-09-29 02:53:22 +04:00
def read_and_sub_file ( file_name , subst_vars ) :
2009-10-30 06:31:25 +03:00
""" Read a file and sub in variables found in it
2009-12-30 23:48:42 +03:00
2010-09-29 02:53:22 +04:00
: param file_name : File to be read ( typically from setup directory )
2009-10-30 06:31:25 +03:00
param subst_vars : Optional variables to subsitute in the file .
"""
2010-09-29 02:53:22 +04:00
data = open ( file_name , ' r ' ) . read ( )
2009-10-30 06:31:25 +03:00
if subst_vars is not None :
data = substitute_var ( data , subst_vars )
2010-02-26 06:24:38 +03:00
check_all_substituted ( data )
2009-10-30 06:31:25 +03:00
return data
2009-10-30 07:18:42 +03:00
def setup_file ( template , fname , subst_vars = None ) :
""" Setup a file in the private dir.
: param template : Path of the template file .
: param fname : Path of the file to create .
: param subst_vars : Substitution variables .
"""
2010-06-11 01:12:53 +04:00
if os . path . exists ( fname ) :
os . unlink ( fname )
2009-10-30 07:18:42 +03:00
data = read_and_sub_file ( template , subst_vars )
2010-06-11 01:12:53 +04:00
f = open ( fname , ' w ' )
try :
f . write ( data )
finally :
f . close ( )
2009-10-30 07:18:42 +03:00
2007-12-10 12:29:45 +03:00
def valid_netbios_name ( name ) :
""" Check whether a name is valid as a NetBIOS name. """
2009-04-06 01:17:43 +04:00
# See crh's book (1.4.1.1)
2008-03-28 00:30:18 +03:00
if len ( name ) > 15 :
2007-12-10 12:29:45 +03:00
return False
2009-04-06 01:17:43 +04:00
for x in name :
if not x . isalnum ( ) and not x in " !#$ % & ' ()-.@^_ {} ~ " :
return False
2007-12-10 12:29:45 +03:00
return True
2009-08-13 13:37:38 +04:00
2010-12-09 21:45:37 +03:00
def import_bundled_package ( modulename , location ) :
""" Import the bundled version of a package.
: note : This should only be called if the system version of the package
is not adequate .
: param modulename : Module name to import
: param location : Location to add to sys . path ( can be relative to
$ { srcdir } / lib )
"""
if in_source_tree ( ) :
sys . path . insert ( 0 ,
os . path . join ( os . path . dirname ( __file__ ) ,
" ../../../../lib " , location ) )
__import__ ( modulename )
else :
sys . modules [ modulename ] = __import__ (
" samba.external. %s " % modulename , fromlist = [ " samba.external " ] )
2010-12-10 02:47:33 +03:00
def force_bundled_package ( packagename , location ) :
""" Forcibly use the bundled package.
This will first unload the system module and then load the bundled one .
: param packagename : The package name
: param location : Location to add to sys . path ( can be relative to
$ { srcdir } / lib )
"""
for m in sys . modules . keys ( ) :
if m . startswith ( " %s . " % packagename ) :
del sys . modules [ m ]
import_bundled_package ( packagename , location )
2010-03-29 18:21:26 +04:00
def ensure_external_module ( modulename , location ) :
""" Add a location to sys.path if an external dependency can ' t be found.
: param modulename : Module name to import
2010-11-28 16:09:30 +03:00
: param location : Location to add to sys . path ( can be relative to
$ { srcdir } / lib )
2010-03-29 18:21:26 +04:00
"""
try :
__import__ ( modulename )
except ImportError :
2010-12-09 23:38:48 +03:00
import_bundled_package ( modulename , location )
2010-12-09 21:45:37 +03:00
2010-03-29 18:21:26 +04:00
2010-09-29 02:09:09 +04:00
from samba import _glue
2010-04-08 22:34:40 +04:00
version = _glue . version
interface_ips = _glue . interface_ips
set_debug_level = _glue . set_debug_level
2010-11-29 05:26:48 +03:00
get_debug_level = _glue . get_debug_level
2010-04-08 22:34:40 +04:00
unix2nttime = _glue . unix2nttime
2010-11-27 15:47:30 +03:00
nttime2string = _glue . nttime2string
nttime2unix = _glue . nttime2unix
unix2nttime = _glue . unix2nttime
2010-04-08 22:34:40 +04:00
generate_random_password = _glue . generate_random_password