s4:pwsettings: Run all updates as a single modify() operation.
[ira/wip.git] / source4 / setup / pwsettings
1 #!/usr/bin/python
2 #
3 #       Sets password settings (Password complexity, history length,
4 #       minimum password length, the minimum and maximum password age) on a
5 #       Samba4 server
6 #
7 #       Copyright Jelmer Vernooij 2008
8 #       Copyright Matthias Dieter Wallnoefer 2009
9 #       Copyright Andrew Kroeger 2009
10 #       Released under the GNU GPL version 3 or later
11 #
12 import os, sys
13
14 sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "../bin/python"))
15
16 import samba.getopt as options
17 import optparse
18 import pwd
19 import ldb
20
21 from samba.auth import system_session
22 from samba.samdb import SamDB
23 from samba.dcerpc.samr import DOMAIN_PASSWORD_COMPLEX
24
25 parser = optparse.OptionParser("pwsettings (show | set <options>)")
26 sambaopts = options.SambaOptions(parser)
27 parser.add_option_group(sambaopts)
28 parser.add_option_group(options.VersionOptions(parser))
29 credopts = options.CredentialsOptions(parser)
30 parser.add_option_group(credopts)
31 parser.add_option("--quiet", help="Be quiet", action="store_true")
32 parser.add_option("-H", help="LDB URL for database or target server", type=str)
33 parser.add_option("--complexity",
34   help="The password complexity (on | off). Default is 'on'", type=str)
35 parser.add_option("--history-length",
36   help="The password history length (<integer> | default)", type=str)
37 parser.add_option("--min-pwd-length",
38   help="The minimum password length (<integer> | default)", type=str)
39 parser.add_option("--min-pwd-age",
40   help="The minimum password age (<integer in days> | default)", type=str)
41 parser.add_option("--max-pwd-age",
42   help="The maximum password age (<integer in days> | default)", type=str)
43
44 opts, args = parser.parse_args()
45
46 #
47 #  print a message if quiet is not set
48 #
49 def message(text):
50         if not opts.quiet:
51                 print text
52
53 if len(args) == 0:
54         parser.print_usage()
55         sys.exit(1)
56
57 lp = sambaopts.get_loadparm()
58
59 creds = credopts.get_credentials(lp)
60
61 if opts.H is not None:
62         url = opts.H
63 else:
64         url = lp.get("sam database")
65
66 samdb = SamDB(url=url, session_info=system_session(),
67               credentials=creds, lp=lp)
68
69 domain_dn = SamDB.domain_dn(samdb)
70 res = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
71   attrs=["pwdProperties", "pwdHistoryLength", "minPwdLength", "minPwdAge",
72   "maxPwdAge"])
73 assert(len(res) == 1)
74 try:
75         pwd_props = int(res[0]["pwdProperties"][0])
76         pwd_hist_len = int(res[0]["pwdHistoryLength"][0])
77         min_pwd_len = int(res[0]["minPwdLength"][0])
78         # ticks -> days
79         min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24))
80         max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24))
81 except:
82         if args[0] == "show":
83                 print "ERROR: Password informations missing in your AD domain object!"
84                 print "So no settings can be displayed!"
85                 sys.exit(1)
86         else:
87                 pwd_props = 0
88                 message("WARNING: Assuming previous password properties 0 (used for password complexity setting)")
89
90 if args[0] == "show":
91         message("Password informations for domain '" + domain_dn + "'")
92         message("")
93         if pwd_props & DOMAIN_PASSWORD_COMPLEX != 0:
94                 message("Password complexity: on")
95         else:
96                 message("Password complexity: off")
97         message("Password history length: " + str(pwd_hist_len))
98         message("Minimum password length: " + str(min_pwd_len))
99         message("Minimum password age (days): " + str(min_pwd_age))
100         message("Maximum password age (days): " + str(max_pwd_age))
101
102 elif args[0] == "set":
103
104         msgs = []
105         m = ldb.Message()
106         m.dn = ldb.Dn(samdb, domain_dn)
107
108         if opts.complexity is not None:
109                 if opts.complexity == "on":
110                         pwd_props = pwd_props | DOMAIN_PASSWORD_COMPLEX
111                         msgs.append("Password complexity activated!")
112                 elif opts.complexity == "off":
113                         pwd_props = pwd_props & (~DOMAIN_PASSWORD_COMPLEX)
114                         msgs.append("Password complexity deactivated!")
115                 else:
116                         print "ERROR: Wrong argument '" + opts.complexity + "'!"
117                         sys.exit(1)
118
119                 m["pwdProperties"] = ldb.MessageElement(str(pwd_props),
120                   ldb.FLAG_MOD_REPLACE, "pwdProperties")
121
122         if opts.history_length is not None:
123                 if opts.history_length == "default":
124                         pwd_hist_len = 24
125                 else:
126                         pwd_hist_len = int(opts.history_length)
127
128                 m["pwdHistoryLength"] = ldb.MessageElement(str(pwd_hist_len),
129                   ldb.FLAG_MOD_REPLACE, "pwdHistoryLength")
130                 msgs.append("Password history length changed!")
131
132         if opts.min_pwd_length is not None:
133                 if opts.min_pwd_length == "default":
134                         min_pwd_len = 7
135                 else:
136                         min_pwd_len = int(opts.min_pwd_length)
137
138                 m["minPwdLength"] = ldb.MessageElement(str(min_pwd_len),
139                   ldb.FLAG_MOD_REPLACE, "minPwdLength")
140                 msgs.append("Minimum password length changed!")
141
142         if opts.min_pwd_age is not None:
143                 if opts.min_pwd_age == "default":
144                         min_pwd_age = 0
145                 else:
146                         min_pwd_age = int(opts.min_pwd_age)
147                 # days -> ticks
148                 min_pwd_age = -int(min_pwd_age * (24 * 60 * 60 * 1e7))
149
150                 m["minPwdAge"] = ldb.MessageElement(str(min_pwd_age),
151                   ldb.FLAG_MOD_REPLACE, "minPwdAge")
152                 msgs.append("Minimum password age changed!")
153
154         if opts.max_pwd_age is not None:
155                 if opts.max_pwd_age == "default":
156                         max_pwd_age = 43
157                 else:
158                         max_pwd_age = int(opts.max_pwd_age)
159                 # days -> ticks
160                 max_pwd_age = -int(max_pwd_age * (24 * 60 * 60 * 1e7))
161
162                 m["maxPwdAge"] = ldb.MessageElement(str(max_pwd_age),
163                   ldb.FLAG_MOD_REPLACE, "maxPwdAge")
164                 msgs.append("Maximum password age changed!")
165
166         samdb.modify(m)
167
168         msgs.append("All changes applied successfully!")
169
170         message("\n".join(msgs))
171 else:
172         print "ERROR: Wrong argument '" + args[0] + "'!"
173         sys.exit(1)