s4 upgradeprovision: Add a function for schema reloading
[mat/samba.git] / source4 / scripting / bin / samba_spnupdate
1 #!/usr/bin/env python
2 #
3 # update our servicePrincipalName names from spn_update_list
4 #
5 # Copyright (C) Andrew Tridgell 2010
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20
21 import os, sys
22
23 # ensure we get messages out immediately, so they get in the samba logs,
24 # and don't get swallowed by a timeout
25 os.putenv('PYTHONUNBUFFERED', '1')
26
27 # Find right directory when running from source tree
28 sys.path.insert(0, "bin/python")
29
30 import samba, ldb
31 import optparse
32 from samba import Ldb
33 from samba import getopt as options
34 from samba.auth import system_session
35 from samba.samdb import SamDB
36 from samba.credentials import Credentials, DONT_USE_KERBEROS
37
38 parser = optparse.OptionParser("samba_spnupdate")
39 sambaopts = options.SambaOptions(parser)
40 parser.add_option_group(sambaopts)
41 parser.add_option_group(options.VersionOptions(parser))
42 parser.add_option("--verbose", action="store_true")
43
44 credopts = options.CredentialsOptions(parser)
45 parser.add_option_group(credopts)
46
47 ccachename = None
48
49 opts, args = parser.parse_args()
50
51 if len(args) != 0:
52     parser.print_usage()
53     sys.exit(1)
54
55 lp = sambaopts.get_loadparm()
56 creds = credopts.get_credentials(lp)
57
58 domain = lp.get("realm")
59 host = lp.get("netbios name")
60
61
62 # get the list of substitution vars
63 def get_subst_vars(samdb):
64     global lp
65     vars = {}
66
67     vars['DNSDOMAIN'] = lp.get('realm').lower()
68     vars['HOSTNAME']  = lp.get('netbios name').lower() + "." + vars['DNSDOMAIN']
69     vars['NETBIOSNAME'] = lp.get('netbios name').upper()
70     vars['WORKGROUP'] = lp.get('workgroup')
71     vars['NTDSGUID']  = samdb.get_ntds_GUID()
72     res = samdb.search(base=None, scope=ldb.SCOPE_BASE, attrs=["objectGUID"])
73     guid = samdb.schema_format_value("objectGUID", res[0]['objectGUID'][0])
74     vars['DOMAINGUID'] = guid
75     return vars
76
77 try:
78     private_dir = lp.get("private dir")
79     secrets_path = os.path.join(private_dir, lp.get("secrets database"))
80
81     secrets_db = Ldb(url=secrets_path, session_info=system_session(),
82                      credentials=creds, lp=lp)
83     res = secrets_db.search(base=None,
84                             expression="(&(objectclass=ldapSecret)(cn=SAMDB Credentials))",
85                             attrs=["samAccountName", "secret"])
86
87     if len(res) == 1:
88         credentials = Credentials()
89         credentials.set_kerberos_state(DONT_USE_KERBEROS)
90
91         if "samAccountName" in res[0]:
92             credentials.set_username(res[0]["samAccountName"][0])
93
94         if "secret" in res[0]:
95             credentials.set_password(res[0]["secret"][0])
96
97     else:
98         credentials = None
99
100     samdb = SamDB(url=lp.get("sam database"), session_info=system_session(), credentials=credentials, lp=lp)
101 except ldb.LdbError, (num, msg):
102     print("Unable to open sam database %s : %s" % (lp.get("sam database"), msg))
103     sys.exit(1)
104
105 # get the substitution dictionary
106 sub_vars = get_subst_vars(samdb)
107
108 # get the list of SPN entries we should have
109 spn_update_list = lp.private_path('spn_update_list')
110
111 file = open(spn_update_list, "r")
112
113 spn_list = []
114
115 # build the spn list
116 for line in file:
117     line = line.strip()
118     if line == '' or line[0] == "#":
119         continue
120     line = samba.substitute_var(line, sub_vars)
121     spn_list.append(line)
122
123 # get the current list of SPNs in our sam
124 res = samdb.search(base="",
125                    expression='(&(objectClass=computer)(samaccountname=%s$))' % sub_vars['NETBIOSNAME'],
126                    attrs=["servicePrincipalName"])
127 if not res or len(res) != 1:
128     print("Failed to find computer object for %s$" % sub_vars['NETBIOSNAME'])
129     sys.exit(1)
130
131 old_spns = []
132 for s in res[0]['servicePrincipalName']:
133     old_spns.append(s)
134
135 if opts.verbose:
136     print("Existing SPNs: %s" % old_spns)
137
138 add_list = []
139
140 # work out what needs to be added
141 for s in spn_list:
142     in_list = False
143     for s2 in old_spns:
144         if s2.upper() == s.upper():
145             in_list = True
146             break
147     if not in_list:
148         add_list.append(s)
149
150 if opts.verbose:
151     print("New SPNs: %s" % add_list)
152
153 if add_list == []:
154     if opts.verbose:
155         print("Nothing to add")
156     sys.exit(0)
157
158 # build the modify request
159 msg = ldb.Message()
160 msg.dn = res[0]['dn']
161 msg[""] = ldb.MessageElement(add_list,
162                              ldb.FLAG_MOD_ADD, "servicePrincipalName")
163 res = samdb.modify(msg)
164 sys.exit(0)