summaryrefslogtreecommitdiffstats
path: root/source4/scripting/bin/get-descriptors
blob: 6e6922282f6d467c6cb730383495899576a3a9ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/env python3
#
# Unix SMB/CIFS implementation.
# A script to compare differences of security descriotors between
# a remote host and the local Ldb
# Needs the local domain, the remote domain, IP of the remote host
# Username and password for the remote domain, must be at least
# Domain Administrator
#
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
# Copyright (C) Nadezhda Ivanova <nadezhda.ivanova@postpath.com> 2009
#
# Based on the original in EJS:
# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
#
# 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 optparse
import sys
import base64

sys.path.insert(0, "bin/python")

import samba
from samba.auth import system_session
import samba.getopt as options
from samba.ndr import ndr_pack, ndr_unpack
from samba.dcerpc import security
from samba import Ldb
from samba.samdb import SamDB
from ldb import SCOPE_SUBTREE, SCOPE_BASE

parser = optparse.OptionParser("get-descriptors [options]")
sambaopts = options.SambaOptions(parser)
credopts = options.CredentialsOptions(parser)
parser.add_option_group(credopts)

parser.add_option("--local-domain", type="string", metavar="LOCALDOMAIN",
                  help="set local domain")
parser.add_option("--remote-domain", type="string", metavar="REMOTEDOMAIN",
                  help="set remote domain")
parser.add_option("--host", type="string", metavar="HOST",
                  help="Ip of the remote host used for comparison")
parser.add_option("--as-ldif", help="Output in LDIF format", action="store_true")

lp = sambaopts.get_loadparm()
creds = credopts.get_credentials(lp)

opts = parser.parse_args()[0]

if not opts.host or not opts.localdomain or not opts.remote_domain:
    parser.print_usage()
    sys.exit(1)

class DescrGetter:

    def __init__(self, localdomain, remotedomain):
        self.samdb = SamDB(session_info=system_session(), lp=lp, options=["modules:paged_searches"])
        self.remote_ldb= Ldb("ldap://" + opts.host + ":389", credentials=creds, lp=lp,
                             options=["modules:paged_searches"])
        self.local_domain = localdomain.replace(".", ",DC=")
        self.local_domain = "DC=" + self.local_domain
        self.remote_domain = remotedomain.replace(".", ",DC=")
        self.remote_domain = "DC=" + self.remote_domain
        self.local_map = {}
        self.remote_map = {}

    def get_domain_local_sid(self):
        res = self.samdb.search(base=self.local_domain,expression="(objectClass=*)", scope=SCOPE_BASE)
        self.local_sid = ndr_unpack( security.dom_sid,res[0]["objectSid"][0])

    def get_domain_remote_sid(self):
        res = self.remote_ldb.search(base=self.remote_domain, expression="(objectClass=*)", scope=SCOPE_BASE)
        self.remote_sid = ndr_unpack( security.dom_sid,res[0]["objectSid"][0])

    def add_to_ldif(self, dn, descr):
        ldif_entry = ["dn: " + dn,
                      "changetype: modify",
                      "replace: nTSecurityDescriptor",
                      "nTSecurityDescriptor::  " + base64.b64encode(ndr_pack(descr)).decode('utf8')]

        for line in ldif_entry:
            length = 79
            if len(line) <= length + 1:
                print(line)
            else:
                for i in range(len(line) / length + 1):
                    if i == 0:
                        l = line[i * length:((i + 1) * length)]
                    else:
                        l = " " + line[(i * length):((i + 1) * length)]
                    print(l)
        print("\n")

    def write_as_sddl(self, dn, descr):
        print(dn)
        print(descr + "\n")

    def read_descr_by_base(self, search_base):
        res = self.samdb.search(base=search_base + self.local_domain, expression="(objectClass=*)", scope=SCOPE_SUBTREE, attrs=["nTSecurityDescriptor"])
        for entry in res:
            dn = entry["dn"].__str__().replace(self.local_domain, "")

            if "nTSecurityDescriptor" in entry:
                desc_obj = ndr_unpack(security.descriptor, entry["nTSecurityDescriptor"][0])
                self.local_map[dn] = desc_obj

        res = self.remote_ldb.search(base=search_base + self.remote_domain, expression="(objectClass=*)", scope=SCOPE_SUBTREE, attrs=["nTSecurityDescriptor"])
        for entry in res:
            dn = entry["dn"].__str__().replace(self.remote_domain, "")

            if "nTSecurityDescriptor" in entry:
                desc_obj = ndr_unpack(security.descriptor, entry["nTSecurityDescriptor"][0])
                self.remote_map[dn] = desc_obj

    def read_desc(self):
        self.read_descr_by_base("CN=Schema,CN=Configuration,")
        self.read_descr_by_base("CN=Configuration,")
        self.read_descr_by_base("")

    def write_desc_to_ldif(self):
        key_list_local = self.local_map.keys()
        key_list_remote = self.remote_map.keys()
        for key in key_list_remote:
            if key in key_list_local:
                sddl = self.remote_map[key].as_sddl(self.remote_sid)
                sddl_local = self.local_map[key].as_sddl(self.local_sid)
                if sddl != sddl_local:
                    descr = security.descriptor.from_sddl(sddl, self.local_sid)
                if opts.as_ldif:
                    self.add_to_ldif(key + self.local_domain, descr)
                else:
                    self.write_as_sddl(key, descr.as_sddl(self.local_sid))

    def run(self):
        self.get_domain_local_sid()
        self.get_domain_remote_sid()
        self.read_desc()
        self.write_desc_to_ldif()

desc = DescrGetter(opts.local_domain, opts.remote_domain)
desc.run()