s3-VFS: Fix building out-of-tree modules.
[samba.git] / source4 / setup / domainlevel
1 #!/usr/bin/python
2 #
3 # Raises domain and forest function levels
4 #
5 # Copyright Matthias Dieter Wallnoefer 2009
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 sys
22
23 # Find right directory when running from source tree
24 sys.path.insert(0, "bin/python")
25
26 import samba.getopt as options
27 import optparse
28 import ldb
29
30 from samba.auth import system_session
31 from samba.samdb import SamDB
32 from samba import DS_DOMAIN_FUNCTION_2000, DS_DOMAIN_FUNCTION_2003
33 from samba import DS_DOMAIN_FUNCTION_2003_MIXED, DS_DOMAIN_FUNCTION_2008
34 from samba import DS_DOMAIN_FUNCTION_2008_R2
35
36 parser = optparse.OptionParser("domainlevel (show | raise <options>)")
37 sambaopts = options.SambaOptions(parser)
38 parser.add_option_group(sambaopts)
39 parser.add_option_group(options.VersionOptions(parser))
40 credopts = options.CredentialsOptions(parser)
41 parser.add_option_group(credopts)
42 parser.add_option("-H", help="LDB URL for database or target server", type=str)
43 parser.add_option("--quiet", help="Be quiet", action="store_true")
44 parser.add_option("--forest",
45   help="The forest function level (2000 | 2003 | 2008 | 2008_R2). We don't support the 2003 with mixed domains (NT4 DC support) level.", type=str)
46 parser.add_option("--domain",
47   help="The domain function level (2000 | 2003 | 2008 | 2008_R2). We don't support mixed/interim (NT4 DC support) levels.", type=str)
48 opts, args = parser.parse_args()
49
50 #
51 #  print a message if quiet is not set
52 #
53 def message(text):
54         if not opts.quiet:
55                 print text
56
57 if len(args) == 0:
58         parser.print_usage()
59         sys.exit(1)
60
61 lp = sambaopts.get_loadparm()
62 creds = credopts.get_credentials(lp)
63
64 if opts.H is not None:
65         url = opts.H
66 else:
67         url = lp.get("sam database")
68
69 samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp)
70
71 domain_dn = SamDB.domain_dn(samdb)
72
73 res_forest = samdb.search("CN=Partitions,CN=Configuration," + domain_dn,
74   scope=ldb.SCOPE_BASE, attrs=["msDS-Behavior-Version"])
75 assert(len(res_forest) == 1)
76
77 res_domain = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
78   attrs=["msDS-Behavior-Version", "nTMixedDomain"])
79 assert(len(res_domain) == 1)
80
81 try:
82         level_forest = int(res_forest[0]["msDS-Behavior-Version"][0])
83         level_domain = int(res_domain[0]["msDS-Behavior-Version"][0])
84         level_domain_mixed = int(res_domain[0]["nTMixedDomain"][0])
85
86         if level_forest < 0 or level_domain < 0:
87                 print "ERROR: Domain and/or forest functional level(s) is/are invalid. Correct them or reprovision!"
88                 sys.exit(1)
89         if level_forest > level_domain:
90                 print "ERROR: Forest function level is higher than the domain level(s). That can't be. Correct this or reprovision!"
91                 sys.exit(1)
92 except:
93         print "ERROR: Could not retrieve the actual domain and/or forest level!"
94         if args[0] == "show":
95                 print "So the levels can't be displayed!"
96         sys.exit(1)
97
98 if args[0] == "show":
99         message("Domain and forest function level for domain '" + domain_dn + "'")
100         if level_forest == DS_DOMAIN_FUNCTION_2003_MIXED:
101                 message("\nATTENTION: You run SAMBA 4 on the 2003 with mixed domains (NT4 DC support) forest level. This isn't supported! Please raise!")
102         if (level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0) or level_domain == DS_DOMAIN_FUNCTION_2003_MIXED:
103                 message("\nATTENTION: You run SAMBA 4 on a mixed/interim (NT4 DC support) domain level. This isn't supported! Please raise!")
104
105         message("")
106
107         if level_forest == DS_DOMAIN_FUNCTION_2000:
108                 outstr = "2000"
109         elif level_forest == DS_DOMAIN_FUNCTION_2003_MIXED:
110                 outstr = "2003 with mixed domains/interim (NT4 DC support)"
111         elif level_forest == DS_DOMAIN_FUNCTION_2003:
112                 outstr = "2003"
113         elif level_forest == DS_DOMAIN_FUNCTION_2008:
114                 outstr = "2008"
115         elif level_forest == DS_DOMAIN_FUNCTION_2008_R2:
116                 outstr = "2008 R2"
117         else:
118                 outstr = "higher than 2008 R2"
119         message("Forest function level: (Windows) " + outstr)
120
121         if level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0:
122                 outstr = "2000 mixed (NT4 DC support)"
123         elif level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed == 0:
124                 outstr = "2000"
125         elif level_domain == DS_DOMAIN_FUNCTION_2003_MIXED:
126                 outstr = "2003 with mixed domains/interim (NT4 DC support)"
127         elif level_domain == DS_DOMAIN_FUNCTION_2003:
128                 outstr = "2003"
129         elif level_domain == DS_DOMAIN_FUNCTION_2008:
130                 outstr = "2008"
131         elif level_domain == DS_DOMAIN_FUNCTION_2008_R2:
132                 outstr = "2008 R2"
133         else:
134                 outstr = "higher than 2008 R2"
135         message("Domain function level: (Windows) " + outstr)
136
137 elif args[0] == "raise":
138         msgs = []
139
140         if opts.domain is not None:
141                 arg = opts.domain
142
143                 if arg == "2000":
144                         new_level_domain = DS_DOMAIN_FUNCTION_2000      
145                 elif arg == "2003":
146                         new_level_domain = DS_DOMAIN_FUNCTION_2003
147                 elif arg == "2008":
148                         new_level_domain = DS_DOMAIN_FUNCTION_2008
149                 elif arg == "2008_R2":
150                         new_level_domain = DS_DOMAIN_FUNCTION_2008_R2
151                 else:
152                         print "ERROR: Wrong argument '" + arg + "'!"
153                         sys.exit(1)
154
155                 if new_level_domain <= level_domain and level_domain_mixed == 0:
156                         print "ERROR: Domain function level can't be smaller equal to the actual one!"
157                         sys.exit(1)
158
159                 # Deactivate mixed/interim domain support
160                 if level_domain_mixed != 0:
161                         m = ldb.Message()
162                         m.dn = ldb.Dn(samdb, domain_dn)
163                         m["nTMixedDomain"] = ldb.MessageElement("0",
164                           ldb.FLAG_MOD_REPLACE, "nTMixedDomain")
165                         samdb.modify(m)
166
167                 m = ldb.Message()
168                 m.dn = ldb.Dn(samdb, domain_dn)
169                 m["msDS-Behavior-Version"]= ldb.MessageElement(
170                   str(new_level_domain), ldb.FLAG_MOD_REPLACE,
171                   "msDS-Behavior-Version")
172                 samdb.modify(m)
173
174                 level_domain = new_level_domain
175
176                 msgs.append("Domain function level changed!")
177
178         if opts.forest is not None:
179                 arg = opts.forest
180
181                 if arg == "2000":
182                         new_level_forest = DS_DOMAIN_FUNCTION_2000      
183                 elif arg == "2003":
184                         new_level_forest = DS_DOMAIN_FUNCTION_2003
185                 elif arg == "2008":
186                         new_level_forest = DS_DOMAIN_FUNCTION_2008
187                 elif arg == "2008_R2":
188                         new_level_forest = DS_DOMAIN_FUNCTION_2008_R2
189                 else:
190                         print "ERROR: Wrong argument '" + arg + "'!"
191                         sys.exit(1)
192
193                 if new_level_forest <= level_forest:
194                         print "ERROR: Forest function level can't be smaller equal to the actual one!"
195                         sys.exit(1)
196
197                 if new_level_forest > level_domain:
198                         print "ERROR: Forest function level can't be higher than the domain function level(s). Please raise it/them first!"
199                         sys.exit(1)
200
201                 m = ldb.Message()
202                 m.dn = ldb.Dn(samdb, "CN=Partitions,CN=Configuration,"
203                   + domain_dn)
204                 m["msDS-Behavior-Version"]= ldb.MessageElement(
205                   str(new_level_forest), ldb.FLAG_MOD_REPLACE,
206                   "msDS-Behavior-Version")
207                 samdb.modify(m)
208
209                 msgs.append("Forest function level changed!")
210
211         msgs.append("All changes applied successfully!")
212
213         message("\n".join(msgs))
214 else:
215         print "ERROR: Wrong argument '" + args[0] + "'!"
216         sys.exit(1)