python: use '#!/usr/bin/env python' to cope with varying install locations
[mat/samba.git] / source4 / setup / provision
1 #!/usr/bin/env python
2 #
3 # Unix SMB/CIFS implementation.
4 # provision a Samba4 server
5 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
6 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
7 #
8 # Based on the original in EJS:
9 # Copyright (C) Andrew Tridgell 2005
10 #   
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 3 of the License, or
14 # (at your option) any later version.
15 #   
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 # GNU General Public License for more details.
20 #   
21 # You should have received a copy of the GNU General Public License
22 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 #
24
25 import optparse
26 import sys
27 import os
28 import tempfile
29
30 # Find right directory when running from source tree
31 sys.path.insert(0, "bin/python")
32
33 import samba
34 import samba.ntacls
35 from samba.credentials import DONT_USE_KERBEROS
36 from samba.auth import system_session
37 import samba.getopt as options
38 from samba.provision import provision, FILL_FULL, FILL_NT4SYNC, FILL_DRS, find_setup_dir
39 from samba import DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008, DS_DOMAIN_FUNCTION_2008_R2
40 from samba.provisionexceptions import ProvisioningError
41
42 # how do we make this case insensitive??
43
44 parser = optparse.OptionParser("provision [options]")
45 sambaopts = options.SambaOptions(parser)
46 parser.add_option_group(sambaopts)
47 parser.add_option_group(options.VersionOptions(parser))
48 credopts = options.CredentialsOptions(parser)
49 parser.add_option_group(credopts)
50 parser.add_option("--interactive", help="Ask for names", action="store_true")
51 parser.add_option("--setupdir", type="string", metavar="DIR", 
52                 help="directory with setup files")
53 parser.add_option("--realm", type="string", metavar="REALM", help="set realm")
54 parser.add_option("--domain", type="string", metavar="DOMAIN",
55                                   help="set domain")
56 parser.add_option("--domain-guid", type="string", metavar="GUID", 
57                 help="set domainguid (otherwise random)")
58 parser.add_option("--domain-sid", type="string", metavar="SID", 
59                 help="set domainsid (otherwise random)")
60 parser.add_option("--policy-guid", type="string", metavar="GUID",
61                                   help="set guid for domain policy")
62 parser.add_option("--policy-guid-dc", type="string", metavar="GUID",
63                                   help="set guid for domain controller policy")
64 parser.add_option("--ntds-guid", type="string", metavar="GUID", 
65                   help="set NTDS object GUID (otherwise random)")
66 parser.add_option("--invocationid", type="string", metavar="GUID", 
67                   help="set invocationid (otherwise random)")
68 parser.add_option("--host-name", type="string", metavar="HOSTNAME", 
69                 help="set hostname")
70 parser.add_option("--host-ip", type="string", metavar="IPADDRESS", 
71                 help="set IPv4 ipaddress")
72 parser.add_option("--host-ip6", type="string", metavar="IP6ADDRESS", 
73                 help="set IPv6 ipaddress")
74 parser.add_option("--adminpass", type="string", metavar="PASSWORD", 
75                 help="choose admin password (otherwise random)")
76 parser.add_option("--krbtgtpass", type="string", metavar="PASSWORD", 
77                 help="choose krbtgt password (otherwise random)")
78 parser.add_option("--machinepass", type="string", metavar="PASSWORD", 
79                 help="choose machine password (otherwise random)")
80 parser.add_option("--dnspass", type="string", metavar="PASSWORD", 
81                 help="choose dns password (otherwise random)")
82 parser.add_option("--ldapadminpass", type="string", metavar="PASSWORD", 
83                 help="choose password to set between Samba and it's LDAP backend (otherwise random)")
84 parser.add_option("--root", type="string", metavar="USERNAME", 
85                 help="choose 'root' unix username")
86 parser.add_option("--nobody", type="string", metavar="USERNAME", 
87                 help="choose 'nobody' user")
88 parser.add_option("--wheel", type="string", metavar="GROUPNAME", 
89                 help="choose 'wheel' privileged group")
90 parser.add_option("--users", type="string", metavar="GROUPNAME", 
91                 help="choose 'users' group")
92 parser.add_option("--quiet", help="Be quiet", action="store_true")
93 parser.add_option("--blank", action="store_true",
94                 help="do not add users or groups, just the structure")
95 parser.add_option("--ldap-backend-extra-port", type="int", metavar="LDAP-BACKEND-EXTRA-PORT", 
96                 help="Additional TCP port for LDAP backend server (to use for replication)")
97 parser.add_option("--ldap-backend-type", type="choice", metavar="LDAP-BACKEND-TYPE", 
98                 help="LDAP backend type (fedora-ds or openldap)",
99                 choices=["fedora-ds", "openldap"])
100 parser.add_option("--ldap-backend-nosync", help="Configure LDAP backend not to call fsync() (for performance in test environments)", action="store_true")
101 parser.add_option("--server-role", type="choice", metavar="ROLE",
102                   choices=["domain controller", "dc", "member server", "member", "standalone"],
103                 help="The server role (domain controller | dc | member server | member | standalone). Default is standalone.")
104 parser.add_option("--function-level", type="choice", metavar="FOR-FUN-LEVEL",
105                   choices=["2003", "2008", "2008_R2"],
106                 help="The domain and forest function level (2003 | 2008 | 2008_R2). Default is (Windows) 2003 (Native).")
107 parser.add_option("--partitions-only", 
108                 help="Configure Samba's partitions, but do not modify them (ie, join a BDC)", action="store_true")
109 parser.add_option("--targetdir", type="string", metavar="DIR", 
110                           help="Set target directory")
111 parser.add_option("--ol-mmr-urls", type="string", metavar="LDAPSERVER",
112                 help="List of LDAP-URLS [ ldap://<FQHN>:<PORT>/  (where <PORT> has to be different than 389!) ] separated with comma (\",\") for use with OpenLDAP-MMR (Multi-Master-Replication), e.g.: \"ldap://s4dc1:9000,ldap://s4dc2:9000\"")
113 parser.add_option("--slapd-path", type="string", metavar="SLAPD-PATH", 
114                 help="Path to slapd for LDAP backend [e.g.:'/usr/local/libexec/slapd']. Required for Setup with LDAP-Backend. OpenLDAP Version >= 2.4.17 should be used.") 
115 parser.add_option("--setup-ds-path", type="string", metavar="SETUP_DS-PATH", 
116                 help="Path to setup-ds.pl script for Fedora DS LDAP backend [e.g.:'/usr/sbin/setup-ds.pl']. Required for Setup with Fedora DS backend.") 
117 parser.add_option("--nosync", help="Configure LDAP backend not to call fsync() (for performance in test environments)", action="store_true")
118 parser.add_option("--use-xattrs", type="choice", choices=["yes","no","auto"], help="Define if we should use the native fs capabilities or a tdb file for storing attributes likes ntacl, auto tries to make an inteligent guess based on the user rights and system capabilities")
119 parser.add_option("--ldap-dryrun-mode", help="Configure LDAP backend, but do not run any binaries and exit early.  Used only for the test environment.  DO NOT USE", action="store_true")
120
121 opts = parser.parse_args()[0]
122
123 def message(text):
124         """print a message if quiet is not set."""
125         if not opts.quiet:
126                 print text
127
128 if len(sys.argv) == 1:
129         opts.interactive = True
130
131 if opts.interactive:
132         from getpass import getpass
133         import socket
134         def ask(prompt, default=None):
135                 if default is not None:
136                         print "%s [%s]: " % (prompt,default),
137                 else:
138                         print "%s: " % (prompt,),
139                 return sys.stdin.readline().rstrip("\n") or default
140         try:
141                 default = socket.getfqdn().split(".", 1)[1].upper()
142         except IndexError:
143                 default = None
144         opts.realm = ask("Realm", default)
145         if opts.realm in (None, ""):
146                 print >>sys.stderr, "No realm set!"
147                 sys.exit(1)
148
149         try:
150                 default = opts.realm.split(".")[0]
151         except IndexError:
152                 default = None
153         opts.domain = ask("Domain", default)
154         if opts.domain is None:
155                 print >> sys.stderr, "No domain set!"
156                 sys.exit(1)
157
158         opts.server_role = ask("Server Role (dc, member, standalone)", "dc")
159         for i in range(3):
160                 opts.adminpass = getpass("Administrator password: ")
161                 if not opts.adminpass:
162                         print >>sys.stderr, "Invalid administrator password."
163                 else:
164                         break
165 else:
166         if opts.realm is None or opts.domain is None:
167                 if opts.realm is None:
168                         print >>sys.stderr, "No realm set!"
169                 if opts.domain is None:
170                         print >> sys.stderr, "No domain set!"
171                 parser.print_usage()
172                 sys.exit(1)
173
174 if not opts.adminpass:
175         message("Administrator password will be set randomly!")
176
177 lp = sambaopts.get_loadparm()
178 smbconf = lp.configfile
179
180 if opts.server_role == "dc":
181         server_role = "domain controller"
182 elif opts.server_role == "member":
183         server_role = "member server"
184 else:
185         server_role = opts.server_role
186
187 if opts.function_level is None:
188         dom_for_fun_level = None
189 elif opts.function_level == "2003":
190         dom_for_fun_level = DS_DOMAIN_FUNCTION_2003
191 elif opts.function_level == "2008":
192         dom_for_fun_level = DS_DOMAIN_FUNCTION_2008
193 elif opts.function_level == "2008_R2":
194         dom_for_fun_level = DS_DOMAIN_FUNCTION_2008_R2
195
196 creds = credopts.get_credentials(lp)
197
198 creds.set_kerberos_state(DONT_USE_KERBEROS)
199
200 setup_dir = opts.setupdir
201 if setup_dir is None:
202         setup_dir = find_setup_dir()
203
204 samdb_fill = FILL_FULL
205 if opts.blank:
206     samdb_fill = FILL_NT4SYNC
207 elif opts.partitions_only:
208     samdb_fill = FILL_DRS
209
210 if not opts.use_xattrs:
211         opts.use_xattrs="auto"
212
213 eadb = True
214 if opts.use_xattrs == "yes":
215         eadb = False
216 elif opts.use_xattrs == "auto":
217         file=tempfile.NamedTemporaryFile()
218         try:
219                 samba.ntacls.setntacl(lp,file.name,"O:S-1-5-32G:S-1-5-32","S-1-5-32","native")
220                 eadb = False
221         except:
222                 if lp.get("posix:eadb") == None:
223                         message("Notice: you are not root or your system do not support xattr, tdb backend for attributes has been selected")
224                         message(" if you intend to use this provision in production you'd better rerun the script as root on a system supporting xattr")
225         file.close()
226
227
228 session = system_session()
229 try:
230         provision(setup_dir, message,
231                   session, creds, smbconf=smbconf, targetdir=opts.targetdir,
232                   samdb_fill=samdb_fill, realm=opts.realm, domain=opts.domain,
233                   domainguid=opts.domain_guid, domainsid=opts.domain_sid,
234                   policyguid=opts.policy_guid, policyguid_dc=opts.policy_guid_dc,
235                   hostname=opts.host_name,
236                   hostip=opts.host_ip, hostip6=opts.host_ip6,
237                   ntdsguid=opts.ntds_guid,
238                   invocationid=opts.invocationid, adminpass=opts.adminpass,
239                   krbtgtpass=opts.krbtgtpass, machinepass=opts.machinepass,
240                   dnspass=opts.dnspass, root=opts.root, nobody=opts.nobody,
241                   wheel=opts.wheel, users=opts.users,
242                   serverrole=server_role, dom_for_fun_level=dom_for_fun_level,
243                   ldap_backend_extra_port=opts.ldap_backend_extra_port,
244                   backend_type=opts.ldap_backend_type,
245                   ldapadminpass=opts.ldapadminpass, ol_mmr_urls=opts.ol_mmr_urls,
246                   slapd_path=opts.slapd_path, setup_ds_path=opts.setup_ds_path,
247                   nosync=opts.nosync,ldap_dryrun_mode=opts.ldap_dryrun_mode,useeadb=eadb)
248 except ProvisioningError, e:
249         print str(e)
250         exit(1)