dcc26a29c94d66830c6747f5deee083232fffa59
[ira/wip.git] / source4 / setup / domainlevel
1 #!/usr/bin/python
2 #
3 #       Raises domain and forest function levels
4 #
5 #       Copyright Matthias Dieter Wallnoefer 2009
6 #       Released under the GNU GPL version 3 or later
7 #
8 import os, sys
9
10 sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "../bin/python"))
11
12 import samba.getopt as options
13 import optparse
14 import ldb
15
16 from samba.auth import system_session
17 from samba.samdb import SamDB
18 from samba import DS_DOMAIN_FUNCTION_2000, DS_DOMAIN_FUNCTION_2003
19 from samba import DS_DOMAIN_FUNCTION_2008, DS_DOMAIN_FUNCTION_2008_R2
20
21 parser = optparse.OptionParser("domainlevel (show | raise <options>)")
22 sambaopts = options.SambaOptions(parser)
23 parser.add_option_group(sambaopts)
24 parser.add_option_group(options.VersionOptions(parser))
25 credopts = options.CredentialsOptions(parser)
26 parser.add_option_group(credopts)
27 parser.add_option("--quiet", help="Be quiet", action="store_true")
28 parser.add_option("-H", help="LDB URL for database or target server", type=str)
29 parser.add_option("--forest",
30   help="The forest function level (2000 | 2003 | 2008 | 2008_R2). We don't support mixed/interim (NT4 DC support) levels.", type=str)
31 parser.add_option("--domain",
32   help="The domain function level (2000 | 2003 | 2008 | 2008_R2). We don't support mixed/interim (NT4 DC support) levels.", type=str)
33 opts, args = parser.parse_args()
34
35 #
36 #  print a message if quiet is not set
37 #
38 def message(text):
39         if not opts.quiet:
40                 print text
41
42 if len(args) == 0:
43         parser.print_usage()
44         sys.exit(1)
45
46 lp = sambaopts.get_loadparm()
47
48 creds = credopts.get_credentials(lp)
49
50 if opts.H is not None:
51         url = opts.H
52 else:
53         url = lp.get("sam database")
54
55 samdb = SamDB(url=url, session_info=system_session(),
56               credentials=creds, lp=lp)
57
58 domain_dn = SamDB.domain_dn(samdb)
59
60 res_forest = samdb.search("CN=Partitions,CN=Configuration," + domain_dn,
61   scope=ldb.SCOPE_BASE, attrs=["msDS-Behavior-Version"])
62 assert(len(res_forest) == 1)
63
64 res_domain = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
65   attrs=["msDS-Behavior-Version"])
66 assert(len(res_domain) == 1)
67
68 try:
69         level_forest = int(res_forest[0]["msDS-Behavior-Version"][0])
70         level_domain = int(res_domain[0]["msDS-Behavior-Version"][0])
71
72         if level_forest < 0 or level_forest == 1 or level_forest > 4 or level_domain < 0 or level_domain == 1 or level_domain > 4:
73                 print "ERROR: Domain and/or forest functional level(s) is/are invalid. Correct them or reprovision!"
74                 sys.exit(1)
75         if level_forest > level_domain:
76                 print "ERROR: Forest function level is higher than the domain level(s). That can't be. Correct this or reprovision!"
77                 sys.exit(1)
78 except:
79         print "ERROR: Could not retrieve the actual domain and forest level!"
80         if args[0] == "show":
81                 print "So the levels can't be displayed!"
82         sys.exit(1)
83
84 if args[0] == "show":
85         message("Domain and forest function level for domain '" + domain_dn + "'")
86         message("")
87
88         if level_forest == DS_DOMAIN_FUNCTION_2000:
89                 outstr = "2000"
90         elif level_forest == DS_DOMAIN_FUNCTION_2003:
91                 outstr = "2003"
92         elif level_forest == DS_DOMAIN_FUNCTION_2008:
93                 outstr = "2008"
94         elif level_forest == DS_DOMAIN_FUNCTION_2008_R2:
95                 outstr = "2008 R2"
96         message("Forest function level: (Windows) " + outstr)
97
98         if level_domain == DS_DOMAIN_FUNCTION_2000:
99                 outstr = "2000"
100         elif level_domain == DS_DOMAIN_FUNCTION_2003:
101                 outstr = "2003"
102         elif level_domain == DS_DOMAIN_FUNCTION_2008:
103                 outstr = "2008"
104         elif level_domain == DS_DOMAIN_FUNCTION_2008_R2:
105                 outstr = "2008 R2"
106         message("Domain function level: (Windows) " + outstr)
107
108 elif args[0] == "raise":
109         msgs = []
110
111         if opts.domain is not None:
112                 arg = opts.domain
113
114                 if arg == "2000":
115                         new_level_domain = DS_DOMAIN_FUNCTION_2000      
116                 elif arg == "2003":
117                         new_level_domain = DS_DOMAIN_FUNCTION_2003
118                 elif arg == "2008":
119                         new_level_domain = DS_DOMAIN_FUNCTION_2008
120                 elif arg == "2008_R2":
121                         new_level_domain = DS_DOMAIN_FUNCTION_2008_R2
122                 else:
123                         print "ERROR: Wrong argument '" + arg + "'!"
124                         sys.exit(1)
125
126                 if new_level_domain <= level_domain:
127                         print "ERROR: Domain function level can't be smaller equal to the actual one!"
128                         sys.exit(1)
129
130                 m = ldb.Message()
131                 m.dn = ldb.Dn(samdb, domain_dn)
132                 m["msDS-Behavior-Version"]= ldb.MessageElement(
133                   str(new_level_domain), ldb.FLAG_MOD_REPLACE,
134                   "msDS-Behavior-Version")
135                 samdb.modify(m)
136
137                 level_domain = new_level_domain
138
139                 msgs.append("Domain function level changed!")
140
141         if opts.forest is not None:
142                 arg = opts.forest
143
144                 if arg == "2000":
145                         new_level_forest = DS_DOMAIN_FUNCTION_2000      
146                 elif arg == "2003":
147                         new_level_forest = DS_DOMAIN_FUNCTION_2003
148                 elif arg == "2008":
149                         new_level_forest = DS_DOMAIN_FUNCTION_2008
150                 elif arg == "2008_R2":
151                         new_level_forest = DS_DOMAIN_FUNCTION_2008_R2
152                 else:
153                         print "ERROR: Wrong argument '" + arg + "'!"
154                         sys.exit(1)
155
156                 if new_level_forest <= level_forest:
157                         print "ERROR: Forest function level can't be smaller equal to the actual one!"
158                         sys.exit(1)
159
160                 if new_level_forest > level_domain:
161                         print "ERROR: Forest function level can't be higher than the domain function level(s). Please raise it/them first!"
162                         sys.exit(1)
163
164                 m = ldb.Message()
165
166                 m.dn = ldb.Dn(samdb, "CN=Partitions,CN=Configuration,"
167                   + domain_dn)
168                 m["msDS-Behavior-Version"]= ldb.MessageElement(
169                   str(new_level_forest), ldb.FLAG_MOD_REPLACE,
170                   "msDS-Behavior-Version")
171                 samdb.modify(m)
172
173                 msgs.append("Forest function level changed!")
174
175         msgs.append("All changes applied successfully!")
176
177         message("\n".join(msgs))
178 else:
179         print "ERROR: Wrong argument '" + args[0] + "'!"
180         sys.exit(1)