2010-06-24 08:33:58 +04:00
#!/usr/bin/env python
2007-12-17 10:20:20 +03:00
# Unix SMB/CIFS implementation.
2010-06-20 03:28:39 +04:00
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2010
2009-09-19 23:57:41 +04:00
# Copyright (C) Matthias Dieter Wallnoefer 2009
2007-12-17 10:20:20 +03:00
#
# Based on the original in EJS:
2008-01-25 03:02:13 +03:00
# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
2011-10-21 20:05:07 +04:00
# Copyright (C) Giampaolo Lauria <lauria2@yahoo.com> 2011
2010-11-28 05:34:47 +03:00
#
2007-12-17 10:20:20 +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.
2010-11-28 05:34:47 +03:00
#
2007-12-17 10:20:20 +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.
2010-11-28 05:34:47 +03:00
#
2007-12-17 10:20:20 +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/>.
#
2007-12-30 03:14:15 +03:00
""" Convenience functions for using the SAM. """
2007-12-17 10:20:20 +03:00
import samba
2007-12-18 04:21:14 +03:00
import ldb
2008-08-30 01:32:44 +04:00
import time
2009-03-12 07:20:25 +03:00
import base64
2011-08-05 07:09:35 +04:00
import os
2010-09-29 02:55:22 +04:00
from samba import dsdb
2010-06-22 20:03:15 +04:00
from samba . ndr import ndr_unpack , ndr_pack
2010-11-28 05:34:47 +03:00
from samba . dcerpc import drsblobs , misc
2011-08-05 05:17:06 +04:00
from samba . common import normalise_int32
2007-12-17 10:20:20 +03:00
2008-05-22 19:42:18 +04:00
__docformat__ = " restructuredText "
2010-11-28 05:34:47 +03:00
2007-12-17 10:20:20 +03:00
class SamDB ( samba . Ldb ) :
2007-12-30 03:14:15 +03:00
""" The SAM database. """
2008-04-14 13:51:02 +04:00
2010-06-22 20:03:15 +04:00
hash_oid_name = { }
2009-08-15 17:20:09 +04:00
def __init__ ( self , url = None , lp = None , modules_dir = None , session_info = None ,
2010-06-20 13:59:49 +04:00
credentials = None , flags = 0 , options = None , global_schema = True ,
2010-09-19 06:28:05 +04:00
auto_connect = True , am_rodc = None ) :
2008-04-14 13:51:02 +04:00
self . lp = lp
2010-04-20 05:48:51 +04:00
if not auto_connect :
url = None
elif url is None and lp is not None :
2011-06-02 09:43:40 +04:00
url = lp . samdb_url ( )
2009-08-15 17:20:09 +04:00
2011-08-03 05:31:45 +04:00
self . url = url
2009-08-15 17:20:09 +04:00
super ( SamDB , self ) . __init__ ( url = url , lp = lp , modules_dir = modules_dir ,
2010-11-28 05:34:47 +03:00
session_info = session_info , credentials = credentials , flags = flags ,
options = options )
2009-08-15 17:20:09 +04:00
2010-04-07 14:11:12 +04:00
if global_schema :
2010-06-20 17:22:49 +04:00
dsdb . _dsdb_set_global_schema ( self )
2008-04-14 13:51:02 +04:00
2010-09-19 06:28:05 +04:00
if am_rodc is not None :
dsdb . _dsdb_set_am_rodc ( self , am_rodc )
2010-05-17 13:49:37 +04:00
2009-08-15 17:20:09 +04:00
def connect ( self , url = None , flags = 0 , options = None ) :
2011-09-02 08:42:50 +04:00
''' connect to the database '''
2011-08-05 07:09:35 +04:00
if self . lp is not None and not os . path . exists ( url ) :
2010-04-20 05:48:51 +04:00
url = self . lp . private_path ( url )
2011-08-03 05:31:45 +04:00
self . url = url
2010-04-20 05:48:51 +04:00
super ( SamDB , self ) . connect ( url = url , flags = flags ,
2009-08-15 17:20:09 +04:00
options = options )
2007-12-18 04:21:14 +03:00
2010-09-19 07:22:23 +04:00
def am_rodc ( self ) :
2011-09-02 08:42:50 +04:00
''' return True if we are an RODC '''
2010-09-19 07:22:23 +04:00
return dsdb . _am_rodc ( self )
2011-12-07 02:56:31 +04:00
def am_pdc ( self ) :
''' return True if we are an PDC emulator '''
return dsdb . _am_pdc ( self )
2009-09-18 22:16:05 +04:00
def domain_dn ( self ) :
2011-09-02 08:42:50 +04:00
''' return the domain DN '''
2010-11-15 08:41:59 +03:00
return str ( self . get_default_basedn ( ) )
2009-09-18 22:16:05 +04:00
2011-11-08 23:59:19 +04:00
def disable_account ( self , search_filter ) :
""" Disables an account
: param search_filter : LDAP filter to find the user ( eg
samccountname = name )
"""
2011-11-15 02:54:29 +04:00
flags = samba . dsdb . UF_ACCOUNTDISABLE
2011-11-08 23:59:19 +04:00
self . toggle_userAccountFlags ( search_filter , flags , on = True )
2010-09-29 02:55:22 +04:00
def enable_account ( self , search_filter ) :
2009-09-18 22:16:05 +04:00
""" Enables an account
2010-11-28 05:34:47 +03:00
: param search_filter : LDAP filter to find the user ( eg
samccountname = name )
2007-12-17 10:20:20 +03:00
"""
2011-06-24 18:37:26 +04:00
flags = samba . dsdb . UF_ACCOUNTDISABLE | samba . dsdb . UF_PASSWD_NOTREQD
self . toggle_userAccountFlags ( search_filter , flags , on = False )
2011-10-21 20:05:07 +04:00
def toggle_userAccountFlags ( self , search_filter , flags , flags_str = None ,
on = True , strict = False ) :
2011-06-24 18:37:26 +04:00
""" toggle_userAccountFlags
: param search_filter : LDAP filter to find the user ( eg
samccountname = name )
: flags : samba . dsdb . UF_ * flags
: on : on = True ( default ) = > set , on = False = > unset
: strict : strict = False ( default ) ignore if no action is needed
strict = True raises an Exception if . . .
"""
2009-09-18 22:16:05 +04:00
res = self . search ( base = self . domain_dn ( ) , scope = ldb . SCOPE_SUBTREE ,
2010-09-29 02:55:22 +04:00
expression = search_filter , attrs = [ " userAccountControl " ] )
2011-06-01 08:41:51 +04:00
if len ( res ) == 0 :
2011-10-21 20:05:07 +04:00
raise Exception ( " Unable to find account where ' %s ' " % search_filter )
2009-09-18 22:16:05 +04:00
assert ( len ( res ) == 1 )
2011-06-24 18:37:26 +04:00
account_dn = res [ 0 ] . dn
old_uac = int ( res [ 0 ] [ " userAccountControl " ] [ 0 ] )
if on :
if strict and ( old_uac & flags ) :
2011-10-21 20:05:07 +04:00
error = " Account flag(s) ' %s ' already set " % flags_str
2011-06-24 18:37:26 +04:00
raise Exception ( error )
new_uac = old_uac | flags
else :
if strict and not ( old_uac & flags ) :
2011-10-21 20:05:07 +04:00
error = " Account flag(s) ' %s ' already unset " % flags_str
2011-06-24 18:37:26 +04:00
raise Exception ( error )
2009-09-18 22:16:05 +04:00
2011-06-24 18:37:26 +04:00
new_uac = old_uac & ~ flags
if old_uac == new_uac :
return
2008-03-28 04:08:54 +03:00
2007-12-17 10:20:20 +03:00
mod = """
dn : % s
changetype : modify
2011-06-24 18:37:26 +04:00
delete : userAccountControl
userAccountControl : % u
add : userAccountControl
2007-12-17 10:20:20 +03:00
userAccountControl : % u
2011-06-24 18:37:26 +04:00
""" % (account_dn, old_uac, new_uac)
2007-12-30 03:14:15 +03:00
self . modify_ldif ( mod )
2010-11-28 05:34:47 +03:00
2010-09-29 02:55:22 +04:00
def force_password_change_at_next_login ( self , search_filter ) :
2009-09-18 22:16:05 +04:00
""" Forces a password change at next login
2010-11-28 05:34:47 +03:00
: param search_filter : LDAP filter to find the user ( eg
samccountname = name )
2009-06-18 06:38:04 +04:00
"""
2009-09-18 22:16:05 +04:00
res = self . search ( base = self . domain_dn ( ) , scope = ldb . SCOPE_SUBTREE ,
2010-09-29 02:55:22 +04:00
expression = search_filter , attrs = [ ] )
2011-06-01 08:46:04 +04:00
if len ( res ) == 0 :
raise Exception ( ' Unable to find user " %s " ' % search_filter )
2009-09-18 22:16:05 +04:00
assert ( len ( res ) == 1 )
user_dn = res [ 0 ] . dn
2009-06-18 06:38:04 +04:00
mod = """
dn : % s
changetype : modify
replace : pwdLastSet
pwdLastSet : 0
""" % (user_dn)
self . modify_ldif ( mod )
2010-06-07 20:10:28 +04:00
def newgroup ( self , groupname , groupou = None , grouptype = None ,
2010-11-24 18:17:15 +03:00
description = None , mailaddress = None , notes = None , sd = None ) :
2010-06-07 20:10:28 +04:00
""" Adds a new group with additional parameters
: param groupname : Name of the new group
: param grouptype : Type of the new group
: param description : Description of the new group
: param mailaddress : Email address of the new group
: param notes : Notes of the new group
2010-11-24 18:17:15 +03:00
: param sd : security descriptor of the object
2010-06-07 20:10:28 +04:00
"""
2010-06-08 23:33:56 +04:00
group_dn = " CN= %s , %s , %s " % ( groupname , ( groupou or " CN=Users " ) , self . domain_dn ( ) )
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
# The new user record. Note the reliance on the SAMLDB module which
# fills in the default informations
2010-06-20 03:28:39 +04:00
ldbmessage = { " dn " : group_dn ,
2010-06-08 23:33:56 +04:00
" sAMAccountName " : groupname ,
" objectClass " : " group " }
2010-06-07 20:10:28 +04:00
2010-06-20 03:28:39 +04:00
if grouptype is not None :
2011-08-05 05:17:06 +04:00
ldbmessage [ " groupType " ] = normalise_int32 ( grouptype )
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if description is not None :
ldbmessage [ " description " ] = description
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if mailaddress is not None :
ldbmessage [ " mail " ] = mailaddress
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if notes is not None :
ldbmessage [ " info " ] = notes
2010-06-07 20:10:28 +04:00
2010-11-24 18:17:15 +03:00
if sd is not None :
ldbmessage [ " nTSecurityDescriptor " ] = ndr_pack ( sd )
2010-06-20 13:59:49 +04:00
self . add ( ldbmessage )
2010-06-07 20:10:28 +04:00
2010-06-20 04:32:23 +04:00
def deletegroup ( self , groupname ) :
2010-06-07 20:10:28 +04:00
""" Deletes a group
: param groupname : Name of the target group
"""
2011-07-28 11:14:28 +04:00
groupfilter = " (&(sAMAccountName= %s )(objectCategory= %s , %s )) " % ( ldb . binary_encode ( groupname ) , " CN=Group,CN=Schema,CN=Configuration " , self . domain_dn ( ) )
2010-06-07 20:10:28 +04:00
self . transaction_start ( )
try :
targetgroup = self . search ( base = self . domain_dn ( ) , scope = ldb . SCOPE_SUBTREE ,
expression = groupfilter , attrs = [ ] )
if len ( targetgroup ) == 0 :
2010-06-20 04:32:23 +04:00
raise Exception ( ' Unable to find group " %s " ' % groupname )
2010-06-07 20:10:28 +04:00
assert ( len ( targetgroup ) == 1 )
2010-09-29 02:35:51 +04:00
self . delete ( targetgroup [ 0 ] . dn )
2012-02-25 18:56:25 +04:00
except :
2010-06-07 20:10:28 +04:00
self . transaction_cancel ( )
raise
else :
self . transaction_commit ( )
2010-06-20 04:32:23 +04:00
def add_remove_group_members ( self , groupname , listofmembers ,
2010-06-07 20:10:28 +04:00
add_members_operation = True ) :
""" Adds or removes group members
: param groupname : Name of the target group
: param listofmembers : Comma - separated list of group members
2010-11-28 16:09:30 +03:00
: param add_members_operation : Defines if its an add or remove
operation
2010-06-07 20:10:28 +04:00
"""
2011-07-28 11:14:28 +04:00
groupfilter = " (&(sAMAccountName= %s )(objectCategory= %s , %s )) " % (
ldb . binary_encode ( groupname ) , " CN=Group,CN=Schema,CN=Configuration " , self . domain_dn ( ) )
2010-06-07 20:10:28 +04:00
groupmembers = listofmembers . split ( ' , ' )
self . transaction_start ( )
try :
targetgroup = self . search ( base = self . domain_dn ( ) , scope = ldb . SCOPE_SUBTREE ,
expression = groupfilter , attrs = [ ' member ' ] )
if len ( targetgroup ) == 0 :
2010-06-20 04:32:23 +04:00
raise Exception ( ' Unable to find group " %s " ' % groupname )
2010-06-07 20:10:28 +04:00
assert ( len ( targetgroup ) == 1 )
modified = False
addtargettogroup = """
dn : % s
changetype : modify
""" % (str(targetgroup[0].dn))
for member in groupmembers :
targetmember = self . search ( base = self . domain_dn ( ) , scope = ldb . SCOPE_SUBTREE ,
2011-07-28 11:14:28 +04:00
expression = " (|(sAMAccountName= %s )(CN= %s )) " % (
ldb . binary_encode ( member ) , ldb . binary_encode ( member ) ) , attrs = [ ] )
2010-06-07 20:10:28 +04:00
if len ( targetmember ) != 1 :
2010-09-29 02:35:51 +04:00
continue
2010-06-07 20:10:28 +04:00
if add_members_operation is True and ( targetgroup [ 0 ] . get ( ' member ' ) is None or str ( targetmember [ 0 ] . dn ) not in targetgroup [ 0 ] [ ' member ' ] ) :
2010-09-29 02:35:51 +04:00
modified = True
addtargettogroup + = """ add: member
2010-06-07 20:10:28 +04:00
member : % s
""" % (str(targetmember[0].dn))
elif add_members_operation is False and ( targetgroup [ 0 ] . get ( ' member ' ) is not None and str ( targetmember [ 0 ] . dn ) in targetgroup [ 0 ] [ ' member ' ] ) :
2010-09-29 02:35:51 +04:00
modified = True
addtargettogroup + = """ delete: member
2010-06-07 20:10:28 +04:00
member : % s
""" % (str(targetmember[0].dn))
if modified is True :
2010-09-29 02:35:51 +04:00
self . modify_ldif ( addtargettogroup )
2010-06-07 20:10:28 +04:00
2012-02-25 18:56:25 +04:00
except :
2010-06-07 20:10:28 +04:00
self . transaction_cancel ( )
raise
else :
self . transaction_commit ( )
2010-05-09 12:54:19 +04:00
def newuser ( self , username , password ,
2010-11-28 05:34:47 +03:00
force_password_change_at_next_login_req = False ,
useusernameascn = False , userou = None , surname = None , givenname = None ,
initials = None , profilepath = None , scriptpath = None , homedrive = None ,
homedirectory = None , jobtitle = None , department = None , company = None ,
description = None , mailaddress = None , internetaddress = None ,
telephonenumber = None , physicaldeliveryoffice = None , sd = None ,
setpassword = True ) :
2010-06-07 20:10:28 +04:00
""" Adds a new user with additional parameters
2009-09-18 22:16:05 +04:00
2009-09-21 01:49:05 +04:00
: param username : Name of the new user
2007-12-30 03:14:15 +03:00
: param password : Password for the new user
2009-09-21 01:49:05 +04:00
: param force_password_change_at_next_login_req : Force password change
2010-11-28 05:34:47 +03:00
: param useusernameascn : Use username as cn rather that firstname +
initials + lastname
2010-06-07 20:10:28 +04:00
: param userou : Object container ( without domainDN postfix ) for new user
: param surname : Surname of the new user
: param givenname : First name of the new user
: param initials : Initials of the new user
: param profilepath : Profile path of the new user
: param scriptpath : Logon script path of the new user
: param homedrive : Home drive of the new user
: param homedirectory : Home directory of the new user
: param jobtitle : Job title of the new user
: param department : Department of the new user
: param company : Company of the new user
: param description : of the new user
: param mailaddress : Email address of the new user
: param internetaddress : Home page of the new user
: param telephonenumber : Phone number of the new user
: param physicaldeliveryoffice : Office location of the new user
2010-11-23 18:48:53 +03:00
: param sd : security descriptor of the object
: param setpassword : optionally disable password reset
2010-06-20 03:28:39 +04:00
"""
2010-06-07 20:10:28 +04:00
2010-09-29 02:35:51 +04:00
displayname = " "
2010-06-07 20:10:28 +04:00
if givenname is not None :
displayname + = givenname
if initials is not None :
displayname + = ' %s . ' % initials
if surname is not None :
displayname + = ' %s ' % surname
2010-06-20 03:28:39 +04:00
cn = username
2010-06-07 20:10:28 +04:00
if useusernameascn is None and displayname is not " " :
cn = displayname
2010-06-08 23:33:56 +04:00
user_dn = " CN= %s , %s , %s " % ( cn , ( userou or " CN=Users " ) , self . domain_dn ( ) )
2009-02-11 19:54:58 +03:00
2010-10-19 12:56:07 +04:00
dnsdomain = ldb . Dn ( self , self . domain_dn ( ) ) . canonical_str ( ) . replace ( " / " , " " )
user_principal_name = " %s @ %s " % ( username , dnsdomain )
2010-06-08 23:33:56 +04:00
# The new user record. Note the reliance on the SAMLDB module which
# fills in the default informations
2010-06-20 03:28:39 +04:00
ldbmessage = { " dn " : user_dn ,
2010-09-29 02:35:51 +04:00
" sAMAccountName " : username ,
2010-10-16 22:51:09 +04:00
" userPrincipalName " : user_principal_name ,
2010-09-29 02:35:51 +04:00
" objectClass " : " user " }
2010-06-07 20:10:28 +04:00
2010-06-20 03:28:39 +04:00
if surname is not None :
2010-06-08 23:33:56 +04:00
ldbmessage [ " sn " ] = surname
2010-06-07 20:10:28 +04:00
2010-06-20 03:28:39 +04:00
if givenname is not None :
2010-06-08 23:33:56 +04:00
ldbmessage [ " givenName " ] = givenname
2010-06-07 20:10:28 +04:00
2010-06-20 03:28:39 +04:00
if displayname is not " " :
2010-06-08 23:33:56 +04:00
ldbmessage [ " displayName " ] = displayname
ldbmessage [ " name " ] = displayname
2010-06-07 20:10:28 +04:00
2010-06-20 03:28:39 +04:00
if initials is not None :
2010-06-08 23:33:56 +04:00
ldbmessage [ " initials " ] = ' %s . ' % initials
2010-06-07 20:10:28 +04:00
2010-06-20 03:28:39 +04:00
if profilepath is not None :
2010-06-08 23:33:56 +04:00
ldbmessage [ " profilePath " ] = profilepath
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if scriptpath is not None :
ldbmessage [ " scriptPath " ] = scriptpath
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if homedrive is not None :
ldbmessage [ " homeDrive " ] = homedrive
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if homedirectory is not None :
ldbmessage [ " homeDirectory " ] = homedirectory
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if jobtitle is not None :
ldbmessage [ " title " ] = jobtitle
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if department is not None :
ldbmessage [ " department " ] = department
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if company is not None :
ldbmessage [ " company " ] = company
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if description is not None :
ldbmessage [ " description " ] = description
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if mailaddress is not None :
ldbmessage [ " mail " ] = mailaddress
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if internetaddress is not None :
ldbmessage [ " wWWHomePage " ] = internetaddress
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if telephonenumber is not None :
ldbmessage [ " telephoneNumber " ] = telephonenumber
2010-06-07 20:10:28 +04:00
2010-06-08 23:33:56 +04:00
if physicaldeliveryoffice is not None :
ldbmessage [ " physicalDeliveryOfficeName " ] = physicaldeliveryoffice
2010-06-07 20:10:28 +04:00
2010-11-23 18:48:53 +03:00
if sd is not None :
ldbmessage [ " nTSecurityDescriptor " ] = ndr_pack ( sd )
2010-06-08 23:33:56 +04:00
self . transaction_start ( )
try :
2010-06-07 20:10:28 +04:00
self . add ( ldbmessage )
2009-02-11 19:54:58 +03:00
2009-09-19 23:57:41 +04:00
# Sets the password for it
2010-11-23 18:48:53 +03:00
if setpassword :
2011-07-28 11:14:28 +04:00
self . setpassword ( " (samAccountName= %s ) " % ldb . binary_encode ( username ) , password ,
2010-11-23 18:48:53 +03:00
force_password_change_at_next_login_req )
2012-02-25 18:56:25 +04:00
except :
2009-02-11 19:54:58 +03:00
self . transaction_cancel ( )
raise
2010-04-08 23:01:17 +04:00
else :
self . transaction_commit ( )
2008-03-28 04:08:54 +03:00
2011-08-15 06:06:59 +04:00
def deleteuser ( self , username ) :
""" Deletes a user
: param username : Name of the target user
"""
filter = " (&(sAMAccountName= %s )(objectCategory= %s , %s )) " % ( ldb . binary_encode ( username ) , " CN=Person,CN=Schema,CN=Configuration " , self . domain_dn ( ) )
self . transaction_start ( )
try :
target = self . search ( base = self . domain_dn ( ) , scope = ldb . SCOPE_SUBTREE ,
expression = filter , attrs = [ ] )
if len ( target ) == 0 :
raise Exception ( ' Unable to find user " %s " ' % username )
assert ( len ( target ) == 1 )
self . delete ( target [ 0 ] . dn )
2012-02-25 18:56:25 +04:00
except :
2011-08-15 06:06:59 +04:00
self . transaction_cancel ( )
raise
else :
self . transaction_commit ( )
2010-09-29 02:55:22 +04:00
def setpassword ( self , search_filter , password ,
2010-11-28 05:34:47 +03:00
force_change_at_next_login = False , username = None ) :
2009-09-18 22:16:05 +04:00
""" Sets the password for a user
2010-11-28 05:34:47 +03:00
: param search_filter : LDAP filter to find the user ( eg
samccountname = name )
2008-03-28 04:08:54 +03:00
: param password : Password for the user
2010-04-04 05:30:03 +04:00
: param force_change_at_next_login : Force password change
2008-03-28 04:08:54 +03:00
"""
self . transaction_start ( )
2009-02-11 19:54:58 +03:00
try :
2009-08-15 17:20:09 +04:00
res = self . search ( base = self . domain_dn ( ) , scope = ldb . SCOPE_SUBTREE ,
2010-09-29 02:55:22 +04:00
expression = search_filter , attrs = [ ] )
2010-04-15 11:15:25 +04:00
if len ( res ) == 0 :
2010-09-29 02:55:22 +04:00
raise Exception ( ' Unable to find user " %s " ' % ( username or search_filter ) )
2010-11-29 08:57:25 +03:00
if len ( res ) > 1 :
raise Exception ( ' Matched %u multiple users with filter " %s " ' % ( len ( res ) , search_filter ) )
2009-02-11 19:54:58 +03:00
user_dn = res [ 0 ] . dn
2009-09-10 02:46:51 +04:00
setpw = """
dn : % s
changetype : modify
2010-07-08 11:36:30 +04:00
replace : unicodePwd
unicodePwd : : % s
""" % (user_dn, base64.b64encode(( " \" " + password + " \" " ).encode( ' utf-16-le ' )))
2009-02-11 19:54:58 +03:00
2009-09-10 02:46:51 +04:00
self . modify_ldif ( setpw )
2009-02-11 19:54:58 +03:00
2010-04-04 05:30:03 +04:00
if force_change_at_next_login :
2009-09-21 01:49:05 +04:00
self . force_password_change_at_next_login (
" (dn= " + str ( user_dn ) + " ) " )
2009-06-17 03:14:17 +04:00
2009-02-11 19:54:58 +03:00
# modify the userAccountControl to remove the disabled bit
2010-09-29 02:55:22 +04:00
self . enable_account ( search_filter )
2012-02-25 18:56:25 +04:00
except :
2009-02-11 19:54:58 +03:00
self . transaction_cancel ( )
raise
2010-04-08 23:01:17 +04:00
else :
self . transaction_commit ( )
2007-12-17 10:20:20 +03:00
2010-09-29 02:55:22 +04:00
def setexpiry ( self , search_filter , expiry_seconds , no_expiry_req = False ) :
2009-09-18 22:16:05 +04:00
""" Sets the account expiry for a user
2010-11-28 05:34:47 +03:00
: param search_filter : LDAP filter to find the user ( eg
samaccountname = name )
2008-08-30 01:32:44 +04:00
: param expiry_seconds : expiry time from now in seconds
2009-09-21 01:49:05 +04:00
: param no_expiry_req : if set , then don ' t expire password
2008-08-30 01:32:44 +04:00
"""
2009-02-11 19:54:58 +03:00
self . transaction_start ( )
try :
res = self . search ( base = self . domain_dn ( ) , scope = ldb . SCOPE_SUBTREE ,
2010-09-29 02:55:22 +04:00
expression = search_filter ,
2009-09-21 15:53:47 +04:00
attrs = [ " userAccountControl " , " accountExpires " ] )
2011-06-01 08:46:04 +04:00
if len ( res ) == 0 :
raise Exception ( ' Unable to find user " %s " ' % search_filter )
2009-09-21 01:49:05 +04:00
assert ( len ( res ) == 1 )
2009-09-18 22:16:05 +04:00
user_dn = res [ 0 ] . dn
2009-02-11 19:54:58 +03:00
userAccountControl = int ( res [ 0 ] [ " userAccountControl " ] [ 0 ] )
accountExpires = int ( res [ 0 ] [ " accountExpires " ] [ 0 ] )
2009-09-21 01:49:05 +04:00
if no_expiry_req :
2009-02-11 19:54:58 +03:00
userAccountControl = userAccountControl | 0x10000
accountExpires = 0
else :
userAccountControl = userAccountControl & ~ 0x10000
2010-04-04 02:30:34 +04:00
accountExpires = samba . unix2nttime ( expiry_seconds + int ( time . time ( ) ) )
2009-02-11 19:54:58 +03:00
2009-09-18 22:16:05 +04:00
setexp = """
2009-03-12 05:13:14 +03:00
dn : % s
changetype : modify
replace : userAccountControl
userAccountControl : % u
replace : accountExpires
accountExpires : % u
2009-09-18 22:16:05 +04:00
""" % (user_dn, userAccountControl, accountExpires)
self . modify_ldif ( setexp )
2012-02-25 18:56:25 +04:00
except :
2009-02-11 19:54:58 +03:00
self . transaction_cancel ( )
raise
2010-04-08 23:01:17 +04:00
else :
self . transaction_commit ( )
2010-04-04 05:30:03 +04:00
def set_domain_sid ( self , sid ) :
""" Change the domain SID used by this LDB.
: param sid : The new domain sid to use .
"""
2010-06-20 17:22:49 +04:00
dsdb . _samdb_set_domain_sid ( self , sid )
2010-04-04 05:30:03 +04:00
def get_domain_sid ( self ) :
2010-11-28 05:34:47 +03:00
""" Read the domain SID used by this LDB. """
2010-08-20 01:26:53 +04:00
return dsdb . _samdb_get_domain_sid ( self )
2010-04-04 05:30:03 +04:00
2010-11-28 16:09:30 +03:00
domain_sid = property ( get_domain_sid , set_domain_sid ,
" SID for the domain " )
2010-04-04 05:30:03 +04:00
def set_invocation_id ( self , invocation_id ) :
""" Set the invocation id for this SamDB handle.
: param invocation_id : GUID of the invocation id .
"""
2010-06-20 17:22:49 +04:00
dsdb . _dsdb_set_ntds_invocation_id ( self , invocation_id )
2010-04-04 05:30:03 +04:00
2010-11-28 16:09:30 +03:00
def get_invocation_id ( self ) :
""" Get the invocation_id id """
return dsdb . _samdb_ntds_invocation_id ( self )
invocation_id = property ( get_invocation_id , set_invocation_id ,
" Invocation ID GUID " )
2010-06-20 03:28:39 +04:00
def get_oid_from_attid ( self , attid ) :
2010-06-20 17:22:49 +04:00
return dsdb . _dsdb_get_oid_from_attid ( self , attid )
2010-06-20 03:28:39 +04:00
2010-11-28 05:34:47 +03:00
def get_attid_from_lDAPDisplayName ( self , ldap_display_name ,
is_schema_nc = False ) :
2011-06-22 08:41:50 +04:00
''' return the attribute ID for a LDAP attribute as an integer as found in DRSUAPI '''
2010-11-28 05:34:47 +03:00
return dsdb . _dsdb_get_attid_from_lDAPDisplayName ( self ,
ldap_display_name , is_schema_nc )
2010-08-24 16:08:27 +04:00
2011-06-22 08:41:50 +04:00
def get_syntax_oid_from_lDAPDisplayName ( self , ldap_display_name ) :
''' return the syntax OID for a LDAP attribute as a string '''
return dsdb . _dsdb_get_syntax_oid_from_lDAPDisplayName ( self , ldap_display_name )
2011-07-07 00:29:58 +04:00
def get_systemFlags_from_lDAPDisplayName ( self , ldap_display_name ) :
''' return the systemFlags for a LDAP attribute as a integer '''
return dsdb . _dsdb_get_systemFlags_from_lDAPDisplayName ( self , ldap_display_name )
def get_linkId_from_lDAPDisplayName ( self , ldap_display_name ) :
''' return the linkID for a LDAP attribute as a integer '''
return dsdb . _dsdb_get_linkId_from_lDAPDisplayName ( self , ldap_display_name )
2011-07-11 08:27:21 +04:00
def get_lDAPDisplayName_by_attid ( self , attid ) :
''' return the lDAPDisplayName from an integer DRS attribute ID '''
return dsdb . _dsdb_get_lDAPDisplayName_by_attid ( self , attid )
2011-07-11 10:55:11 +04:00
def get_backlink_from_lDAPDisplayName ( self , ldap_display_name ) :
''' return the attribute name of the corresponding backlink from the name
of a forward link attribute . If there is no backlink return None '''
return dsdb . _dsdb_get_backlink_from_lDAPDisplayName ( self , ldap_display_name )
2010-04-20 05:48:51 +04:00
def set_ntds_settings_dn ( self , ntds_settings_dn ) :
2010-11-28 05:34:47 +03:00
""" Set the NTDS Settings DN, as would be returned on the dsServiceName
rootDSE attribute .
2010-04-20 05:48:51 +04:00
This allows the DN to be set before the database fully exists
: param ntds_settings_dn : The new DN to use
"""
2010-06-20 17:22:49 +04:00
dsdb . _samdb_set_ntds_settings_dn ( self , ntds_settings_dn )
2010-04-20 05:48:51 +04:00
2010-04-04 05:30:03 +04:00
def get_ntds_GUID ( self ) :
2010-11-28 05:34:47 +03:00
""" Get the NTDS objectGUID """
2010-06-20 17:22:49 +04:00
return dsdb . _samdb_ntds_objectGUID ( self )
2010-04-04 05:30:03 +04:00
def server_site_name ( self ) :
2010-11-28 05:34:47 +03:00
""" Get the server site name """
2010-06-20 17:22:49 +04:00
return dsdb . _samdb_server_site_name ( self )
2010-04-09 00:07:42 +04:00
2011-08-22 11:40:45 +04:00
def host_dns_name ( self ) :
""" return the DNS name of this host """
res = self . search ( base = ' ' , scope = ldb . SCOPE_BASE , attrs = [ ' dNSHostName ' ] )
return res [ 0 ] [ ' dNSHostName ' ] [ 0 ]
def domain_dns_name ( self ) :
""" return the DNS name of the domain root """
domain_dn = self . get_default_basedn ( )
return domain_dn . canonical_str ( ) . split ( ' / ' ) [ 0 ]
def forest_dns_name ( self ) :
""" return the DNS name of the forest root """
forest_dn = self . get_root_basedn ( )
return forest_dn . canonical_str ( ) . split ( ' / ' ) [ 0 ]
2010-04-09 00:07:42 +04:00
def load_partition_usn ( self , base_dn ) :
2010-06-20 17:22:49 +04:00
return dsdb . _dsdb_load_partition_usn ( self , base_dn )
2010-06-20 04:32:23 +04:00
def set_schema ( self , schema ) :
self . set_schema_from_ldb ( schema . ldb )
2010-09-29 02:55:22 +04:00
def set_schema_from_ldb ( self , ldb_conn ) :
dsdb . _dsdb_set_schema_from_ldb ( self , ldb_conn )
2010-06-20 04:32:23 +04:00
2010-11-05 06:06:10 +03:00
def dsdb_DsReplicaAttribute ( self , ldb , ldap_display_name , ldif_elements ) :
2011-06-17 05:29:44 +04:00
''' convert a list of attribute values to a DRSUAPI DsReplicaAttribute '''
2010-11-05 06:06:10 +03:00
return dsdb . _dsdb_DsReplicaAttribute ( ldb , ldap_display_name , ldif_elements )
2011-06-17 05:29:44 +04:00
def dsdb_normalise_attributes ( self , ldb , ldap_display_name , ldif_elements ) :
''' normalise a list of attribute values '''
return dsdb . _dsdb_normalise_attributes ( ldb , ldap_display_name , ldif_elements )
2010-06-22 20:03:15 +04:00
def get_attribute_from_attid ( self , attid ) :
""" Get from an attid the associated attribute
2010-11-28 05:34:47 +03:00
: param attid : The attribute id for searched attribute
: return : The name of the attribute associated with this id
2010-06-22 20:03:15 +04:00
"""
if len ( self . hash_oid_name . keys ( ) ) == 0 :
self . _populate_oid_attid ( )
if self . hash_oid_name . has_key ( self . get_oid_from_attid ( attid ) ) :
return self . hash_oid_name [ self . get_oid_from_attid ( attid ) ]
else :
return None
def _populate_oid_attid ( self ) :
2010-11-28 05:34:47 +03:00
""" Populate the hash hash_oid_name.
2010-06-22 20:03:15 +04:00
2010-11-28 05:34:47 +03:00
This hash contains the oid of the attribute as a key and
its display name as a value
2010-06-22 20:03:15 +04:00
"""
self . hash_oid_name = { }
res = self . search ( expression = " objectClass=attributeSchema " ,
controls = [ " search_options:1:2 " ] ,
attrs = [ " attributeID " ,
" lDAPDisplayName " ] )
if len ( res ) > 0 :
for e in res :
strDisplay = str ( e . get ( " lDAPDisplayName " ) )
self . hash_oid_name [ str ( e . get ( " attributeID " ) ) ] = strDisplay
def get_attribute_replmetadata_version ( self , dn , att ) :
2010-11-28 05:34:47 +03:00
""" Get the version field trom the replPropertyMetaData for
the given field
2010-06-22 20:03:15 +04:00
2010-11-28 05:34:47 +03:00
: param dn : The on which we want to get the version
: param att : The name of the attribute
: return : The value of the version field in the replPropertyMetaData
for the given attribute . None if the attribute is not replicated
2010-06-22 20:03:15 +04:00
"""
res = self . search ( expression = " dn= %s " % dn ,
scope = ldb . SCOPE_SUBTREE ,
controls = [ " search_options:1:2 " ] ,
attrs = [ " replPropertyMetaData " ] )
if len ( res ) == 0 :
return None
repl = ndr_unpack ( drsblobs . replPropertyMetaDataBlob ,
str ( res [ 0 ] [ " replPropertyMetaData " ] ) )
ctr = repl . ctr
if len ( self . hash_oid_name . keys ( ) ) == 0 :
self . _populate_oid_attid ( )
for o in ctr . array :
# Search for Description
att_oid = self . get_oid_from_attid ( o . attid )
if self . hash_oid_name . has_key ( att_oid ) and \
att . lower ( ) == self . hash_oid_name [ att_oid ] . lower ( ) :
return o . version
return None
2010-11-28 05:34:47 +03:00
def set_attribute_replmetadata_version ( self , dn , att , value ,
addifnotexist = False ) :
2010-06-22 20:03:15 +04:00
res = self . search ( expression = " dn= %s " % dn ,
scope = ldb . SCOPE_SUBTREE ,
controls = [ " search_options:1:2 " ] ,
attrs = [ " replPropertyMetaData " ] )
if len ( res ) == 0 :
return None
repl = ndr_unpack ( drsblobs . replPropertyMetaDataBlob ,
str ( res [ 0 ] [ " replPropertyMetaData " ] ) )
ctr = repl . ctr
now = samba . unix2nttime ( int ( time . time ( ) ) )
found = False
if len ( self . hash_oid_name . keys ( ) ) == 0 :
self . _populate_oid_attid ( )
for o in ctr . array :
# Search for Description
att_oid = self . get_oid_from_attid ( o . attid )
if self . hash_oid_name . has_key ( att_oid ) and \
att . lower ( ) == self . hash_oid_name [ att_oid ] . lower ( ) :
found = True
seq = self . sequence_number ( ldb . SEQ_NEXT )
o . version = value
o . originating_change_time = now
o . originating_invocation_id = misc . GUID ( self . get_invocation_id ( ) )
o . originating_usn = seq
o . local_usn = seq
2010-08-10 18:19:40 +04:00
if not found and addifnotexist and len ( ctr . array ) > 0 :
o2 = drsblobs . replPropertyMetaData1 ( )
o2 . attid = 589914
att_oid = self . get_oid_from_attid ( o2 . attid )
seq = self . sequence_number ( ldb . SEQ_NEXT )
o2 . version = value
o2 . originating_change_time = now
o2 . originating_invocation_id = misc . GUID ( self . get_invocation_id ( ) )
o2 . originating_usn = seq
o2 . local_usn = seq
found = True
tab = ctr . array
tab . append ( o2 )
ctr . count = ctr . count + 1
ctr . array = tab
2010-06-22 20:03:15 +04:00
if found :
replBlob = ndr_pack ( repl )
msg = ldb . Message ( )
msg . dn = res [ 0 ] . dn
msg [ " replPropertyMetaData " ] = ldb . MessageElement ( replBlob ,
ldb . FLAG_MOD_REPLACE ,
" replPropertyMetaData " )
self . modify ( msg , [ " local_oid:1.3.6.1.4.1.7165.4.3.14:0 " ] )
2010-06-20 04:32:23 +04:00
def write_prefixes_from_schema ( self ) :
2010-06-20 17:22:49 +04:00
dsdb . _dsdb_write_prefixes_from_schema_to_ldb ( self )
2010-09-09 11:34:55 +04:00
def get_partitions_dn ( self ) :
return dsdb . _dsdb_get_partitions_dn ( self )
2010-11-22 19:34:18 +03:00
def set_minPwdAge ( self , value ) :
m = ldb . Message ( )
m . dn = ldb . Dn ( self , self . domain_dn ( ) )
m [ " minPwdAge " ] = ldb . MessageElement ( value , ldb . FLAG_MOD_REPLACE , " minPwdAge " )
self . modify ( m )
def get_minPwdAge ( self ) :
res = self . search ( self . domain_dn ( ) , scope = ldb . SCOPE_BASE , attrs = [ " minPwdAge " ] )
if len ( res ) == 0 :
return None
elif not " minPwdAge " in res [ 0 ] :
return None
else :
return res [ 0 ] [ " minPwdAge " ] [ 0 ]
2010-11-23 12:20:12 +03:00
2010-12-02 11:55:56 +03:00
def set_minPwdLength ( self , value ) :
m = ldb . Message ( )
m . dn = ldb . Dn ( self , self . domain_dn ( ) )
m [ " minPwdLength " ] = ldb . MessageElement ( value , ldb . FLAG_MOD_REPLACE , " minPwdLength " )
self . modify ( m )
def get_minPwdLength ( self ) :
res = self . search ( self . domain_dn ( ) , scope = ldb . SCOPE_BASE , attrs = [ " minPwdLength " ] )
if len ( res ) == 0 :
return None
elif not " minPwdLength " in res [ 0 ] :
return None
else :
return res [ 0 ] [ " minPwdLength " ] [ 0 ]
def set_pwdProperties ( self , value ) :
m = ldb . Message ( )
m . dn = ldb . Dn ( self , self . domain_dn ( ) )
m [ " pwdProperties " ] = ldb . MessageElement ( value , ldb . FLAG_MOD_REPLACE , " pwdProperties " )
self . modify ( m )
def get_pwdProperties ( self ) :
res = self . search ( self . domain_dn ( ) , scope = ldb . SCOPE_BASE , attrs = [ " pwdProperties " ] )
if len ( res ) == 0 :
return None
elif not " pwdProperties " in res [ 0 ] :
return None
else :
return res [ 0 ] [ " pwdProperties " ] [ 0 ]
2010-11-23 12:20:12 +03:00
def set_dsheuristics ( self , dsheuristics ) :
m = ldb . Message ( )
m . dn = ldb . Dn ( self , " CN=Directory Service,CN=Windows NT,CN=Services, %s "
% self . get_config_basedn ( ) . get_linearized ( ) )
if dsheuristics is not None :
2010-11-28 05:34:47 +03:00
m [ " dSHeuristics " ] = ldb . MessageElement ( dsheuristics ,
ldb . FLAG_MOD_REPLACE , " dSHeuristics " )
2010-11-23 12:20:12 +03:00
else :
2010-11-28 05:34:47 +03:00
m [ " dSHeuristics " ] = ldb . MessageElement ( [ ] , ldb . FLAG_MOD_DELETE ,
" dSHeuristics " )
2010-11-23 12:20:12 +03:00
self . modify ( m )
def get_dsheuristics ( self ) :
res = self . search ( " CN=Directory Service,CN=Windows NT,CN=Services, %s "
% self . get_config_basedn ( ) . get_linearized ( ) ,
scope = ldb . SCOPE_BASE , attrs = [ " dSHeuristics " ] )
if len ( res ) == 0 :
dsheuristics = None
elif " dSHeuristics " in res [ 0 ] :
dsheuristics = res [ 0 ] [ " dSHeuristics " ] [ 0 ]
else :
dsheuristics = None
return dsheuristics
2010-11-23 15:31:34 +03:00
def create_ou ( self , ou_dn , description = None , name = None , sd = None ) :
""" Creates an organizationalUnit object
: param ou_dn : dn of the new object
: param description : description attribute
: param name : name atttribute
: param sd : security descriptor of the object , can be
an SDDL string or security . descriptor type
"""
2010-11-25 15:25:28 +03:00
m = { " dn " : ou_dn ,
" objectClass " : " organizationalUnit " }
2010-11-23 15:31:34 +03:00
if description :
2010-11-25 20:57:51 +03:00
m [ " description " ] = description
2010-11-23 15:31:34 +03:00
if name :
2010-11-25 20:57:51 +03:00
m [ " name " ] = name
2010-11-23 15:31:34 +03:00
if sd :
2010-11-25 20:57:51 +03:00
m [ " nTSecurityDescriptor " ] = ndr_pack ( sd )
2010-11-23 15:31:34 +03:00
self . add ( m )
2011-11-28 10:19:50 +04:00
def sequence_number ( self , seq_type ) :
""" Returns the value of the sequence number according to the requested type
: param seq_type : type of sequence number
"""
self . transaction_start ( )
try :
seq = super ( SamDB , self ) . sequence_number ( seq_type )
2012-02-25 18:56:25 +04:00
except :
2011-11-28 10:19:50 +04:00
self . transaction_cancel ( )
raise
else :
self . transaction_commit ( )
return seq
2011-12-04 17:23:34 +04:00
def get_dsServiceName ( self ) :
''' get the NTDS DN from the rootDSE '''
res = self . search ( base = " " , scope = ldb . SCOPE_BASE , attrs = [ " dsServiceName " ] )
return res [ 0 ] [ " dsServiceName " ] [ 0 ]
def get_serverName ( self ) :
''' get the server DN from the rootDSE '''
res = self . search ( base = " " , scope = ldb . SCOPE_BASE , attrs = [ " serverName " ] )
return res [ 0 ] [ " serverName " ] [ 0 ]