2017-12-07 23:38:28 +03:00
# machine account (computer) management
#
# Copyright Bjoern Baumbch <bb@sernet.de> 2018
#
# based on user management
# Copyright Jelmer Vernooij 2010 <jelmer@samba.org>
# Copyright Theresa Halloran 2011 <theresahalloran@gmail.com>
#
# 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.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import samba . getopt as options
import ldb
2018-03-13 06:47:58 +03:00
import socket
import samba
2018-04-06 07:21:15 +03:00
import re
2019-03-13 23:40:25 +03:00
import os
import tempfile
2018-03-13 06:47:58 +03:00
from samba import sd_utils
from samba . dcerpc import dnsserver , dnsp , security
from samba . dnsserver import ARecord , AAAARecord
from samba . ndr import ndr_unpack , ndr_pack , ndr_print
from samba . remove_dc import remove_dns_references
2017-12-07 23:38:28 +03:00
from samba . auth import system_session
from samba . samdb import SamDB
2020-09-11 23:29:46 +03:00
from samba . common import get_bytes
2019-03-13 23:40:25 +03:00
from subprocess import check_call , CalledProcessError
2019-11-25 16:13:37 +03:00
from . import common
2018-03-13 06:47:58 +03:00
2017-12-07 23:38:28 +03:00
from samba import (
credentials ,
dsdb ,
Ldb ,
2018-03-13 06:47:58 +03:00
werror ,
WERRORError
2018-07-30 09:14:37 +03:00
)
2017-12-07 23:38:28 +03:00
from samba . netcmd import (
Command ,
CommandError ,
SuperCommand ,
Option ,
2018-07-30 09:14:37 +03:00
)
2017-12-07 23:38:28 +03:00
2018-03-13 06:47:58 +03:00
def _is_valid_ip ( ip_string , address_families = None ) :
""" Check ip string is valid address """
# by default, check both ipv4 and ipv6
if not address_families :
address_families = [ socket . AF_INET , socket . AF_INET6 ]
for address_family in address_families :
try :
socket . inet_pton ( address_family , ip_string )
return True # if no error, return directly
except socket . error :
continue # Otherwise, check next family
return False
def _is_valid_ipv4 ( ip_string ) :
""" Check ip string is valid ipv4 address """
return _is_valid_ip ( ip_string , address_families = [ socket . AF_INET ] )
def _is_valid_ipv6 ( ip_string ) :
""" Check ip string is valid ipv6 address """
return _is_valid_ip ( ip_string , address_families = [ socket . AF_INET6 ] )
def add_dns_records (
samdb , name , dns_conn , change_owner_sd ,
server , ip_address_list , logger ) :
""" Add DNS A or AAAA records while creating computer. """
name = name . rstrip ( ' $ ' )
client_version = dnsserver . DNS_CLIENT_VERSION_LONGHORN
select_flags = dnsserver . DNS_RPC_VIEW_AUTHORITY_DATA | dnsserver . DNS_RPC_VIEW_NO_CHILDREN
zone = samdb . domain_dns_name ( )
name_found = True
sd_helper = sd_utils . SDUtils ( samdb )
try :
buflen , res = dns_conn . DnssrvEnumRecords2 (
client_version ,
0 ,
server ,
zone ,
name ,
None ,
dnsp . DNS_TYPE_ALL ,
select_flags ,
None ,
None ,
)
except WERRORError as e :
if e . args [ 0 ] == werror . WERR_DNS_ERROR_NAME_DOES_NOT_EXIST :
name_found = False
pass
if name_found :
for rec in res . rec :
for record in rec . records :
if record . wType == dnsp . DNS_TYPE_A or record . wType == dnsp . DNS_TYPE_AAAA :
# delete record
del_rec_buf = dnsserver . DNS_RPC_RECORD_BUF ( )
del_rec_buf . rec = record
try :
dns_conn . DnssrvUpdateRecord2 (
client_version ,
0 ,
server ,
zone ,
name ,
None ,
del_rec_buf ,
)
except WERRORError as e :
if e . args [ 0 ] != werror . WERR_DNS_ERROR_NAME_DOES_NOT_EXIST :
raise
for ip_address in ip_address_list :
if _is_valid_ipv6 ( ip_address ) :
logger . info ( " Adding DNS AAAA record %s . %s for IPv6 IP: %s " % (
name , zone , ip_address ) )
rec = AAAARecord ( ip_address )
elif _is_valid_ipv4 ( ip_address ) :
logger . info ( " Adding DNS A record %s . %s for IPv4 IP: %s " % (
name , zone , ip_address ) )
rec = ARecord ( ip_address )
else :
raise ValueError ( ' Invalid IP: {} ' . format ( ip_address ) )
# Add record
add_rec_buf = dnsserver . DNS_RPC_RECORD_BUF ( )
add_rec_buf . rec = rec
dns_conn . DnssrvUpdateRecord2 (
client_version ,
0 ,
server ,
zone ,
name ,
add_rec_buf ,
None ,
)
if ( len ( ip_address_list ) > 0 ) :
domaindns_zone_dn = ldb . Dn (
samdb ,
' DC=DomainDnsZones, %s ' % samdb . get_default_basedn ( ) ,
)
dns_a_dn , ldap_record = samdb . dns_lookup (
" %s . %s " % ( name , zone ) ,
dns_partition = domaindns_zone_dn ,
)
# Make the DC own the DNS record, not the administrator
sd_helper . modify_sd_on_dn (
dns_a_dn ,
change_owner_sd ,
controls = [ " sd_flags:1: %d " % ( security . SECINFO_OWNER | security . SECINFO_GROUP ) ] ,
)
2020-08-26 16:06:47 +03:00
class cmd_computer_add ( Command ) :
""" Add a new computer.
2017-12-07 23:38:28 +03:00
2020-08-26 16:06:47 +03:00
This command adds a new computer account to the Active Directory domain .
2017-12-07 23:38:28 +03:00
The computername specified on the command is the sAMaccountName without the
trailing $ ( dollar sign ) .
2020-08-26 16:06:47 +03:00
Computer accounts may represent physical entities , such as workstations . Computer
2017-12-07 23:38:28 +03:00
accounts are also referred to as security principals and are assigned a
security identifier ( SID ) .
Example1 :
2020-08-26 16:06:47 +03:00
samba - tool computer add Computer1 - H ldap : / / samba . samdom . example . com \\
2017-12-07 23:38:28 +03:00
- Uadministrator % passw1rd
2020-08-26 16:06:47 +03:00
Example1 shows how to add a new computer to the domain against a remote LDAP
2017-12-07 23:38:28 +03:00
server . The - H parameter is used to specify the remote target server . The - U
option is used to pass the userid and password authorized to issue the command
remotely .
Example2 :
2020-08-26 16:06:47 +03:00
sudo samba - tool computer add Computer2
2017-12-07 23:38:28 +03:00
2020-08-26 16:06:47 +03:00
Example2 shows how to add a new computer to the domain against the local
2017-12-07 23:38:28 +03:00
server . sudo is used so a user may run the command as root .
Example3 :
2020-08-26 16:06:47 +03:00
samba - tool computer add Computer3 - - computerou = ' OU=OrgUnit '
2017-12-07 23:38:28 +03:00
2020-08-26 16:06:47 +03:00
Example3 shows how to add a new computer in the OrgUnit organizational unit .
2017-12-07 23:38:28 +03:00
"""
synopsis = " % prog <computername> [options] "
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " ,
type = str , metavar = " URL " , dest = " H " ) ,
Option ( " --computerou " ,
2018-07-30 09:15:34 +03:00
help = ( " DN of alternative location (with or without domainDN "
" counterpart) to default CN=Computers in which new "
" computer object will be created. E.g. ' OU=<OU name> ' " ) ,
type = str ) ,
2017-12-07 23:38:28 +03:00
Option ( " --description " , help = " Computers ' s description " , type = str ) ,
Option ( " --prepare-oldjoin " ,
help = " Prepare enabled machine account for oldjoin mechanism " ,
action = " store_true " ) ,
2018-03-13 06:47:58 +03:00
Option ( " --ip-address " ,
dest = ' ip_address_list ' ,
help = ( " IPv4 address for the computer ' s A record, or IPv6 "
" address for AAAA record, can be provided multiple "
" times " ) ,
action = ' append ' ) ,
Option ( " --service-principal-name " ,
dest = ' service_principal_name_list ' ,
help = ( " Computer ' s Service Principal Name, can be provided "
" multiple times " ) ,
action = ' append ' )
2017-12-07 23:38:28 +03:00
]
takes_args = [ " computername " ]
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
2018-07-30 09:14:37 +03:00
}
2017-12-07 23:38:28 +03:00
def run ( self , computername , credopts = None , sambaopts = None , versionopts = None ,
2018-03-13 06:47:58 +03:00
H = None , computerou = None , description = None , prepare_oldjoin = False ,
ip_address_list = None , service_principal_name_list = None ) :
if ip_address_list is None :
ip_address_list = [ ]
if service_principal_name_list is None :
service_principal_name_list = [ ]
# check each IP address if provided
for ip_address in ip_address_list :
if not _is_valid_ip ( ip_address ) :
raise CommandError ( ' Invalid IP address {} ' . format ( ip_address ) )
2017-12-07 23:38:28 +03:00
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
try :
samdb = SamDB ( url = H , session_info = system_session ( ) ,
credentials = creds , lp = lp )
samdb . newcomputer ( computername , computerou = computerou ,
description = description ,
2018-03-13 06:47:58 +03:00
prepare_oldjoin = prepare_oldjoin ,
ip_address_list = ip_address_list ,
service_principal_name_list = service_principal_name_list ,
)
if ip_address_list :
# if ip_address_list provided, then we need to create DNS
# records for this computer.
2018-04-06 07:21:15 +03:00
hostname = re . sub ( r " \ $$ " , " " , computername )
if hostname . count ( ' $ ' ) :
raise CommandError ( ' Illegal computername " %s " ' % computername )
2018-03-13 06:47:58 +03:00
filters = ' (&(sAMAccountName= {} $)(objectclass=computer)) ' . format (
2018-04-06 07:21:15 +03:00
ldb . binary_encode ( hostname ) )
2018-03-13 06:47:58 +03:00
recs = samdb . search (
base = samdb . domain_dn ( ) ,
scope = ldb . SCOPE_SUBTREE ,
expression = filters ,
attrs = [ ' primaryGroupID ' , ' objectSid ' ] )
group = recs [ 0 ] [ ' primaryGroupID ' ] [ 0 ]
owner = ndr_unpack ( security . dom_sid , recs [ 0 ] [ " objectSid " ] [ 0 ] )
dns_conn = dnsserver . dnsserver (
" ncacn_ip_tcp: {} [sign] " . format ( samdb . host_dns_name ( ) ) ,
lp , creds )
change_owner_sd = security . descriptor ( )
change_owner_sd . owner_sid = owner
change_owner_sd . group_sid = security . dom_sid (
" {} - {} " . format ( samdb . get_domain_sid ( ) , group ) ,
)
add_dns_records (
2018-04-06 07:21:15 +03:00
samdb , hostname , dns_conn ,
2018-03-13 06:47:58 +03:00
change_owner_sd , samdb . host_dns_name ( ) ,
ip_address_list , self . get_logger ( ) )
2018-05-04 13:31:33 +03:00
except Exception as e :
2020-08-26 16:06:47 +03:00
raise CommandError ( " Failed to add computer ' %s ' : " %
2017-12-07 23:38:28 +03:00
computername , e )
2020-08-26 16:06:47 +03:00
self . outf . write ( " Computer ' %s ' added successfully \n " % computername )
2017-12-07 23:38:28 +03:00
2018-03-13 06:47:58 +03:00
2017-12-07 23:38:28 +03:00
class cmd_computer_delete ( Command ) :
""" Delete a computer.
This command deletes a computer account from the Active Directory domain . The
computername specified on the command is the sAMAccountName without the
trailing $ ( dollar sign ) .
Once the account is deleted , all permissions and memberships associated with
that account are deleted . If a new computer account is added with the same name
as a previously deleted account name , the new computer does not have the
previous permissions . The new account computer will be assigned a new security
identifier ( SID ) and permissions and memberships will have to be added .
The command may be run from the root userid or another authorized
userid . The - H or - - URL = option can be used to execute the command against
a remote server .
Example1 :
2019-03-21 16:15:22 +03:00
samba - tool computer delete Computer1 - H ldap : / / samba . samdom . example . com \\
2017-12-07 23:38:28 +03:00
- Uadministrator % passw1rd
Example1 shows how to delete a computer in the domain against a remote LDAP
server . The - H parameter is used to specify the remote target server . The
- - computername = and - - password = options are used to pass the computername and
password of a computer that exists on the remote server and is authorized to
issue the command on that server .
Example2 :
sudo samba - tool computer delete Computer2
Example2 shows how to delete a computer in the domain against the local server .
sudo is used so a computer may run the command as root .
"""
synopsis = " % prog <computername> [options] "
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " ,
type = str , metavar = " URL " , dest = " H " ) ,
]
takes_args = [ " computername " ]
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
2018-07-30 09:14:37 +03:00
}
2017-12-07 23:38:28 +03:00
def run ( self , computername , credopts = None , sambaopts = None ,
versionopts = None , H = None ) :
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp , fallback_machine = True )
samdb = SamDB ( url = H , session_info = system_session ( ) ,
credentials = creds , lp = lp )
samaccountname = computername
if not computername . endswith ( ' $ ' ) :
samaccountname = " %s $ " % computername
filter = ( " (&(sAMAccountName= %s )(sAMAccountType= %u )) " %
2018-04-06 07:20:22 +03:00
( ldb . binary_encode ( samaccountname ) ,
dsdb . ATYPE_WORKSTATION_TRUST ) )
2017-12-07 23:38:28 +03:00
try :
res = samdb . search ( base = samdb . domain_dn ( ) ,
scope = ldb . SCOPE_SUBTREE ,
expression = filter ,
2018-03-13 06:47:58 +03:00
attrs = [ " userAccountControl " , " dNSHostName " ] )
2017-12-07 23:38:28 +03:00
computer_dn = res [ 0 ] . dn
computer_ac = int ( res [ 0 ] [ " userAccountControl " ] [ 0 ] )
2018-03-13 06:47:58 +03:00
if " dNSHostName " in res [ 0 ] :
2018-04-26 20:22:21 +03:00
computer_dns_host_name = str ( res [ 0 ] [ " dNSHostName " ] [ 0 ] )
2018-03-13 06:47:58 +03:00
else :
computer_dns_host_name = None
2017-12-07 23:38:28 +03:00
except IndexError :
raise CommandError ( ' Unable to find computer " %s " ' % computername )
computer_is_workstation = (
computer_ac & dsdb . UF_WORKSTATION_TRUST_ACCOUNT )
2018-07-30 09:22:19 +03:00
if not computer_is_workstation :
2017-12-07 23:38:28 +03:00
raise CommandError ( ' Failed to remove computer " %s " : '
' Computer is not a workstation - removal denied '
% computername )
try :
samdb . delete ( computer_dn )
2018-03-13 06:47:58 +03:00
if computer_dns_host_name :
remove_dns_references (
samdb , self . get_logger ( ) , computer_dns_host_name ,
ignore_no_name = True )
2018-05-04 13:31:33 +03:00
except Exception as e :
2017-12-07 23:38:28 +03:00
raise CommandError ( ' Failed to remove computer " %s " ' %
samaccountname , e )
self . outf . write ( " Deleted computer %s \n " % computername )
2019-03-13 23:40:25 +03:00
class cmd_computer_edit ( Command ) :
""" Modify Computer AD object.
This command will allow editing of a computer account in the Active
Directory domain . You will then be able to add or change attributes and
their values .
The computername specified on the command is the sAMaccountName with or
without the trailing $ ( dollar sign ) .
The command may be run from the root userid or another authorized userid .
The - H or - - URL = option can be used to execute the command against a remote
server .
Example1 :
samba - tool computer edit Computer1 - H ldap : / / samba . samdom . example . com \\
- U administrator - - password = passw1rd
Example1 shows how to edit a computers attributes in the domain against a
remote LDAP server .
The - H parameter is used to specify the remote target server .
Example2 :
samba - tool computer edit Computer2
Example2 shows how to edit a computers attributes in the domain against a
local LDAP server .
Example3 :
samba - tool computer edit Computer3 - - editor = nano
Example3 shows how to edit a computers attributes in the domain against a
local LDAP server using the ' nano ' editor .
"""
synopsis = " % prog <computername> [options] "
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " ,
type = str , metavar = " URL " , dest = " H " ) ,
Option ( " --editor " , help = " Editor to use instead of the system default, "
" or ' vi ' if no system default is set. " , type = str ) ,
]
takes_args = [ " computername " ]
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
}
def run ( self , computername , credopts = None , sambaopts = None , versionopts = None ,
H = None , editor = None ) :
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp , fallback_machine = True )
samdb = SamDB ( url = H , session_info = system_session ( ) ,
credentials = creds , lp = lp )
samaccountname = computername
if not computername . endswith ( ' $ ' ) :
samaccountname = " %s $ " % computername
filter = ( " (&(sAMAccountType= %d )(sAMAccountName= %s )) " %
( dsdb . ATYPE_WORKSTATION_TRUST ,
ldb . binary_encode ( samaccountname ) ) )
domaindn = samdb . domain_dn ( )
try :
res = samdb . search ( base = domaindn ,
expression = filter ,
scope = ldb . SCOPE_SUBTREE )
computer_dn = res [ 0 ] . dn
except IndexError :
raise CommandError ( ' Unable to find computer " %s " ' % ( computername ) )
if len ( res ) != 1 :
raise CommandError ( ' Invalid number of results: for " %s " : %d ' %
( ( computername ) , len ( res ) ) )
msg = res [ 0 ]
result_ldif = common . get_ldif_for_editor ( samdb , msg )
if editor is None :
editor = os . environ . get ( ' EDITOR ' )
if editor is None :
editor = ' vi '
with tempfile . NamedTemporaryFile ( suffix = " .tmp " ) as t_file :
t_file . write ( get_bytes ( result_ldif ) )
t_file . flush ( )
try :
check_call ( [ editor , t_file . name ] )
except CalledProcessError as e :
raise CalledProcessError ( " ERROR: " , e )
with open ( t_file . name ) as edited_file :
edited_message = edited_file . read ( )
msgs_edited = samdb . parse_ldif ( edited_message )
msg_edited = next ( msgs_edited ) [ 1 ]
res_msg_diff = samdb . msg_diff ( msg , msg_edited )
if len ( res_msg_diff ) == 0 :
self . outf . write ( " Nothing to do \n " )
return
try :
samdb . modify ( res_msg_diff )
except Exception as e :
raise CommandError ( " Failed to modify computer ' %s ' : " %
( computername , e ) )
self . outf . write ( " Modified computer ' %s ' successfully \n " % computername )
2017-12-07 23:38:28 +03:00
class cmd_computer_list ( Command ) :
""" List all computers. """
synopsis = " % prog [options] "
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " ,
type = str , metavar = " URL " , dest = " H " ) ,
2019-08-26 09:46:24 +03:00
Option ( " -b " , " --base-dn " ,
help = " Specify base DN to use " ,
type = str ) ,
2019-08-22 10:12:31 +03:00
Option ( " --full-dn " , dest = " full_dn " ,
default = False ,
action = " store_true " ,
help = " Display DN instead of the sAMAccountName. " )
2018-07-30 09:14:37 +03:00
]
2017-12-07 23:38:28 +03:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
2018-07-30 09:14:37 +03:00
}
2017-12-07 23:38:28 +03:00
2019-08-22 10:12:31 +03:00
def run ( self ,
sambaopts = None ,
credopts = None ,
versionopts = None ,
H = None ,
2019-08-26 09:46:24 +03:00
base_dn = None ,
2019-08-22 10:12:31 +03:00
full_dn = False ) :
2017-12-07 23:38:28 +03:00
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp , fallback_machine = True )
samdb = SamDB ( url = H , session_info = system_session ( ) ,
2018-07-30 09:16:12 +03:00
credentials = creds , lp = lp )
2017-12-07 23:38:28 +03:00
filter = " (sAMAccountType= %u ) " % ( dsdb . ATYPE_WORKSTATION_TRUST )
2019-08-26 09:46:24 +03:00
search_dn = samdb . domain_dn ( )
if base_dn :
search_dn = samdb . normalize_dn_in_domain ( base_dn )
res = samdb . search ( search_dn ,
scope = ldb . SCOPE_SUBTREE ,
2017-12-07 23:38:28 +03:00
expression = filter ,
attrs = [ " samaccountname " ] )
if ( len ( res ) == 0 ) :
return
for msg in res :
2019-08-22 10:12:31 +03:00
if full_dn :
self . outf . write ( " %s \n " % msg . get ( " dn " ) )
continue
2017-12-07 23:38:28 +03:00
self . outf . write ( " %s \n " % msg . get ( " samaccountname " , idx = 0 ) )
2018-07-30 09:20:39 +03:00
2017-12-07 23:38:28 +03:00
class cmd_computer_show ( Command ) :
""" Display a computer AD object.
This command displays a computer account and it ' s attributes in the Active
Directory domain .
The computername specified on the command is the sAMAccountName .
The command may be run from the root userid or another authorized
userid .
The - H or - - URL = option can be used to execute the command against a remote
server .
Example1 :
2019-03-21 16:15:22 +03:00
samba - tool computer show Computer1 - H ldap : / / samba . samdom . example . com \\
2017-12-07 23:38:28 +03:00
- U administrator
Example1 shows how display a computers attributes in the domain against a
remote LDAP server .
The - H parameter is used to specify the remote target server .
Example2 :
samba - tool computer show Computer2
Example2 shows how to display a computers attributes in the domain against a
local LDAP server .
Example3 :
samba - tool computer show Computer2 - - attributes = objectSid , operatingSystem
Example3 shows how to display a computers objectSid and operatingSystem
attribute .
"""
synopsis = " % prog <computername> [options] "
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " ,
type = str , metavar = " URL " , dest = " H " ) ,
Option ( " --attributes " ,
help = ( " Comma separated list of attributes, "
" which will be printed. " ) ,
type = str , dest = " computer_attrs " ) ,
]
takes_args = [ " computername " ]
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
2018-07-30 09:14:37 +03:00
}
2017-12-07 23:38:28 +03:00
def run ( self , computername , credopts = None , sambaopts = None , versionopts = None ,
H = None , computer_attrs = None ) :
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp , fallback_machine = True )
samdb = SamDB ( url = H , session_info = system_session ( ) ,
credentials = creds , lp = lp )
attrs = None
if computer_attrs :
attrs = computer_attrs . split ( " , " )
samaccountname = computername
if not computername . endswith ( ' $ ' ) :
samaccountname = " %s $ " % computername
filter = ( " (&(sAMAccountType= %d )(sAMAccountName= %s )) " %
( dsdb . ATYPE_WORKSTATION_TRUST ,
ldb . binary_encode ( samaccountname ) ) )
domaindn = samdb . domain_dn ( )
try :
res = samdb . search ( base = domaindn , expression = filter ,
scope = ldb . SCOPE_SUBTREE , attrs = attrs )
computer_dn = res [ 0 ] . dn
except IndexError :
raise CommandError ( ' Unable to find computer " %s " ' %
samaccountname )
for msg in res :
2019-11-25 16:13:37 +03:00
computer_ldif = common . get_ldif_for_editor ( samdb , msg )
2017-12-07 23:38:28 +03:00
self . outf . write ( computer_ldif )
2018-07-30 09:20:39 +03:00
2017-12-07 23:38:28 +03:00
class cmd_computer_move ( Command ) :
""" Move a computer to an organizational unit/container. """
2020-09-01 12:54:39 +03:00
synopsis = " % prog <computername> <new_ou_dn> [options] "
2017-12-07 23:38:28 +03:00
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " ,
type = str , metavar = " URL " , dest = " H " ) ,
]
2018-07-30 09:17:02 +03:00
takes_args = [ " computername " , " new_ou_dn " ]
2017-12-07 23:38:28 +03:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
2018-07-30 09:14:37 +03:00
}
2017-12-07 23:38:28 +03:00
def run ( self , computername , new_ou_dn , credopts = None , sambaopts = None ,
versionopts = None , H = None ) :
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp , fallback_machine = True )
samdb = SamDB ( url = H , session_info = system_session ( ) ,
credentials = creds , lp = lp )
domain_dn = ldb . Dn ( samdb , samdb . domain_dn ( ) )
samaccountname = computername
if not computername . endswith ( ' $ ' ) :
samaccountname = " %s $ " % computername
filter = ( " (&(sAMAccountName= %s )(sAMAccountType= %u )) " %
2018-04-06 07:20:22 +03:00
( ldb . binary_encode ( samaccountname ) ,
dsdb . ATYPE_WORKSTATION_TRUST ) )
2017-12-07 23:38:28 +03:00
try :
res = samdb . search ( base = domain_dn ,
expression = filter ,
scope = ldb . SCOPE_SUBTREE )
computer_dn = res [ 0 ] . dn
except IndexError :
raise CommandError ( ' Unable to find computer " %s " ' % ( computername ) )
full_new_ou_dn = ldb . Dn ( samdb , new_ou_dn )
if not full_new_ou_dn . is_child_of ( domain_dn ) :
full_new_ou_dn . add_base ( domain_dn )
new_computer_dn = ldb . Dn ( samdb , str ( computer_dn ) )
2018-07-30 09:18:25 +03:00
new_computer_dn . remove_base_components ( len ( computer_dn ) - 1 )
2017-12-07 23:38:28 +03:00
new_computer_dn . add_base ( full_new_ou_dn )
try :
samdb . rename ( computer_dn , new_computer_dn )
2018-05-04 13:31:33 +03:00
except Exception as e :
2017-12-07 23:38:28 +03:00
raise CommandError ( ' Failed to move computer " %s " ' % computername , e )
self . outf . write ( ' Moved computer " %s " to " %s " \n ' %
( computername , new_ou_dn ) )
class cmd_computer ( SuperCommand ) :
""" Computer management. """
subcommands = { }
2020-08-26 16:06:47 +03:00
subcommands [ " add " ] = cmd_computer_add ( )
subcommands [ " create " ] = cmd_computer_add ( )
2017-12-07 23:38:28 +03:00
subcommands [ " delete " ] = cmd_computer_delete ( )
2019-03-13 23:40:25 +03:00
subcommands [ " edit " ] = cmd_computer_edit ( )
2017-12-07 23:38:28 +03:00
subcommands [ " list " ] = cmd_computer_list ( )
subcommands [ " show " ] = cmd_computer_show ( )
subcommands [ " move " ] = cmd_computer_move ( )