s4-samba-tool: add password verification in change user pass
[Samba/gebeck_regimport.git] / source4 / scripting / python / samba / netcmd / user.py
blob6ba6150004306b87bbedf0efc1d8bd0b64587c70
1 # user management
3 # Copyright Jelmer Vernooij 2010 <jelmer@samba.org>
4 # Copyright Theresa Halloran 2011 <theresahalloran@gmail.com>
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 import samba.getopt as options
21 import ldb
22 from getpass import getpass
23 from samba.auth import system_session
24 from samba.samdb import SamDB
25 from samba import (
26 dsdb,
27 gensec,
28 generate_random_password,
30 from samba.net import Net
32 from samba.netcmd import (
33 Command,
34 CommandError,
35 SuperCommand,
36 Option,
40 class cmd_user_create(Command):
41 """Creates a new user
43 This command creates a new user account in the Active Directory domain. The username specified on the command is the sAMaccountName.
45 User accounts may represent physical entities, such as people or may be used as service accounts for applications. User accounts are also referred to as security principals and are assigned a security identifier (SID).
47 A user account enables a user to logon to a computer and domain with an identity that can be authenticated. To maximize security, each user should have their own unique user account and password. A user's access to domain resources is based on permissions assigned to the user account.
49 The command may be run from the root userid or another authorized userid. The -H or --URL= option can be used to execute the command against a remote server.
51 Example1:
52 samba-tool user add User1 passw0rd --given-name=John --surname=Smith --must-change-at-next-login -H ldap://samba.samdom.example.com -Uadministrator%passw1rd
54 Example1 shows how to create a new user in the domain against a remote LDAP server. The -H parameter is used to specify the remote target server. The -U option is used to pass the userid and password authorized to issue the command remotely.
56 Example2:
57 sudo samba-tool user add User2 passw2rd --given-name=Jane --surname=Doe --must-change-at-next-login
59 Example2 shows how to create a new user in the domain against the local server. sudo is used so a user may run the command as root. In this example, after User2 is created, he/she will be forced to change their password when they logon.
61 Example3:
62 samba-tool user add User3 passw3rd --userou=OrgUnit
64 Example3 shows how to create a new user in the OrgUnit organizational unit.
66 """
67 synopsis = "%prog <username> [<password>] [options]"
69 takes_options = [
70 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
71 metavar="URL", dest="H"),
72 Option("--must-change-at-next-login",
73 help="Force password to be changed on next login",
74 action="store_true"),
75 Option("--random-password",
76 help="Generate random password",
77 action="store_true"),
78 Option("--use-username-as-cn",
79 help="Force use of username as user's CN",
80 action="store_true"),
81 Option("--userou",
82 help="Alternative location (without domainDN counterpart) to default CN=Users in which new user object will be created",
83 type=str),
84 Option("--surname", help="User's surname", type=str),
85 Option("--given-name", help="User's given name", type=str),
86 Option("--initials", help="User's initials", type=str),
87 Option("--profile-path", help="User's profile path", type=str),
88 Option("--script-path", help="User's logon script path", type=str),
89 Option("--home-drive", help="User's home drive letter", type=str),
90 Option("--home-directory", help="User's home directory path", type=str),
91 Option("--job-title", help="User's job title", type=str),
92 Option("--department", help="User's department", type=str),
93 Option("--company", help="User's company", type=str),
94 Option("--description", help="User's description", type=str),
95 Option("--mail-address", help="User's email address", type=str),
96 Option("--internet-address", help="User's home page", type=str),
97 Option("--telephone-number", help="User's phone number", type=str),
98 Option("--physical-delivery-office", help="User's office location", type=str),
101 takes_args = ["username", "password?"]
103 takes_optiongroups = {
104 "sambaopts": options.SambaOptions,
105 "credopts": options.CredentialsOptions,
106 "versionopts": options.VersionOptions,
109 def run(self, username, password=None, credopts=None, sambaopts=None,
110 versionopts=None, H=None, must_change_at_next_login=False, random_password=False,
111 use_username_as_cn=False, userou=None, surname=None, given_name=None, initials=None,
112 profile_path=None, script_path=None, home_drive=None, home_directory=None,
113 job_title=None, department=None, company=None, description=None,
114 mail_address=None, internet_address=None, telephone_number=None, physical_delivery_office=None):
116 if random_password:
117 password = generate_random_password(128, 255)
119 while True:
120 if password is not None and password is not '':
121 break
122 password = getpass("New Password: ")
123 passwordverify = getpass("Retype Password: ")
124 if not password == passwordverify:
125 password = None
126 self.outf.write("Sorry, passwords do not match.\n")
128 lp = sambaopts.get_loadparm()
129 creds = credopts.get_credentials(lp)
131 try:
132 samdb = SamDB(url=H, session_info=system_session(),
133 credentials=creds, lp=lp)
134 samdb.newuser(username, password,
135 force_password_change_at_next_login_req=must_change_at_next_login,
136 useusernameascn=use_username_as_cn, userou=userou, surname=surname, givenname=given_name, initials=initials,
137 profilepath=profile_path, homedrive=home_drive, scriptpath=script_path, homedirectory=home_directory,
138 jobtitle=job_title, department=department, company=company, description=description,
139 mailaddress=mail_address, internetaddress=internet_address,
140 telephonenumber=telephone_number, physicaldeliveryoffice=physical_delivery_office)
141 except Exception, e:
142 raise CommandError("Failed to add user '%s': " % username, e)
144 self.outf.write("User '%s' created successfully\n" % username)
147 class cmd_user_add(cmd_user_create):
148 __doc__ = cmd_user_create.__doc__
149 # take this print out after the add subcommand is removed.
150 # the add subcommand is deprecated but left in for now to allow people to migrate to create
152 def run(self, *args, **kwargs):
153 self.err.write("\nNote: samba-tool user add is deprecated. Please use samba-tool user create for the same function.\n")
154 return super(self, cmd_user_add).run(*args, **kwargs)
157 class cmd_user_delete(Command):
158 """Deletes a user
160 This command deletes a user account from the Active Directory domain. The username specified on the command is the sAMAccountName.
162 Once the account is deleted, all permissions and memberships associated with that account are deleted. If a new user account is added with the same name as a previously deleted account name, the new user does not have the previous permissions. The new account user will be assigned a new security identifier (SID) and permissions and memberships will have to be added.
164 The command may be run from the root userid or another authorized userid. The -H or --URL= option can be used to execute the command against a remote server.
166 Example1:
167 samba-tool user delete User1 -H ldap://samba.samdom.example.com --username=administrator --password=passw1rd
169 Example1 shows how to delete a user in the domain against a remote LDAP server. The -H parameter is used to specify the remote target server. The --username= and --password= options are used to pass the username and password of a user that exists on the remote server and is authorized to issue the command on that server.
171 Example2:
172 sudo samba-tool user delete User2
174 Example2 shows how to delete a user in the domain against the local server. sudo is used so a user may run the command as root.
177 synopsis = "%prog <username> [options]"
179 takes_options = [
180 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
181 metavar="URL", dest="H"),
184 takes_args = ["username"]
185 takes_optiongroups = {
186 "sambaopts": options.SambaOptions,
187 "credopts": options.CredentialsOptions,
188 "versionopts": options.VersionOptions,
191 def run(self, username, credopts=None, sambaopts=None, versionopts=None, H=None):
192 lp = sambaopts.get_loadparm()
193 creds = credopts.get_credentials(lp, fallback_machine=True)
195 try:
196 samdb = SamDB(url=H, session_info=system_session(),
197 credentials=creds, lp=lp)
198 samdb.deleteuser(username)
199 except Exception, e:
200 raise CommandError('Failed to remove user "%s"' % username, e)
201 self.outf.write("Deleted user %s\n" % username)
204 class cmd_user_list(Command):
205 """List all users"""
207 synopsis = "%prog [options]"
209 takes_options = [
210 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
211 metavar="URL", dest="H"),
214 takes_optiongroups = {
215 "sambaopts": options.SambaOptions,
216 "credopts": options.CredentialsOptions,
217 "versionopts": options.VersionOptions,
220 def run(self, sambaopts=None, credopts=None, versionopts=None, H=None):
221 lp = sambaopts.get_loadparm()
222 creds = credopts.get_credentials(lp, fallback_machine=True)
224 samdb = SamDB(url=H, session_info=system_session(),
225 credentials=creds, lp=lp)
227 domain_dn = samdb.domain_dn()
228 res = samdb.search(domain_dn, scope=ldb.SCOPE_SUBTREE,
229 expression=("(&(objectClass=user)(userAccountControl:%s:=%u))"
230 % (ldb.OID_COMPARATOR_AND, dsdb.UF_NORMAL_ACCOUNT)),
231 attrs=["samaccountname"])
232 if (len(res) == 0):
233 return
235 for msg in res:
236 self.outf.write("%s\n" % msg.get("samaccountname", idx=0))
239 class cmd_user_enable(Command):
240 """Enables a user
242 This command enables a user account for logon to an Active Directory domain. The username specified on the command is the sAMAccountName. The username may also be specified using the --filter option.
244 There are many reasons why an account may become disabled. These include:
245 - If a user exceeds the account policy for logon attempts
246 - If an administrator disables the account
247 - If the account expires
249 The samba-tool user enable command allows an administrator to enable an account which has become disabled.
251 Additionally, the enable function allows an administrator to have a set of created user accounts defined and setup with default permissions that can be easily enabled for use.
253 The command may be run from the root userid or another authorized userid. The -H or --URL= option can be used to execute the command against a remote server.
255 Example1:
256 samba-tool user enable Testuser1 --URL=ldap://samba.samdom.example.com --username=administrator --password=passw1rd
258 Example1 shows how to enable a user in the domain against a remote LDAP server. The --URL parameter is used to specify the remote target server. The --username= and --password= options are used to pass the username and password of a user that exists on the remote server and is authorized to update that server.
260 Exampl2:
261 su samba-tool user enable Testuser2
263 Example2 shows how to enable user Testuser2 for use in the domain on the local server. sudo is used so a user may run the command as root.
265 Example3:
266 samba-tool user enable --filter=samaccountname=Testuser3
268 Example3 shows how to enable a user in the domain against a local LDAP server. It uses the --filter=samaccountname to specify the username.
271 synopsis = "%prog (<username>|--filter <filter>) [options]"
274 takes_optiongroups = {
275 "sambaopts": options.SambaOptions,
276 "versionopts": options.VersionOptions,
277 "credopts": options.CredentialsOptions,
280 takes_options = [
281 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
282 metavar="URL", dest="H"),
283 Option("--filter", help="LDAP Filter to set password on", type=str),
286 takes_args = ["username?"]
288 def run(self, username=None, sambaopts=None, credopts=None,
289 versionopts=None, filter=None, H=None):
290 if username is None and filter is None:
291 raise CommandError("Either the username or '--filter' must be specified!")
293 if filter is None:
294 filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
296 lp = sambaopts.get_loadparm()
297 creds = credopts.get_credentials(lp, fallback_machine=True)
299 samdb = SamDB(url=H, session_info=system_session(),
300 credentials=creds, lp=lp)
301 try:
302 samdb.enable_account(filter)
303 except Exception, msg:
304 raise CommandError("Failed to enable user '%s': %s" % (username or filter, msg))
305 self.outf.write("Enabled user '%s'\n" % (username or filter))
308 class cmd_user_disable(Command):
309 """Disable a user"""
311 synopsis = "%prog (<username>|--filter <filter>) [options]"
313 takes_options = [
314 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
315 metavar="URL", dest="H"),
316 Option("--filter", help="LDAP Filter to set password on", type=str),
319 takes_args = ["username?"]
321 takes_optiongroups = {
322 "sambaopts": options.SambaOptions,
323 "credopts": options.CredentialsOptions,
324 "versionopts": options.VersionOptions,
327 def run(self, username=None, sambaopts=None, credopts=None,
328 versionopts=None, filter=None, H=None):
329 if username is None and filter is None:
330 raise CommandError("Either the username or '--filter' must be specified!")
332 if filter is None:
333 filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
335 lp = sambaopts.get_loadparm()
336 creds = credopts.get_credentials(lp, fallback_machine=True)
338 samdb = SamDB(url=H, session_info=system_session(),
339 credentials=creds, lp=lp)
340 try:
341 samdb.disable_account(filter)
342 except Exception, msg:
343 raise CommandError("Failed to disable user '%s': %s" % (username or filter, msg))
346 class cmd_user_setexpiry(Command):
347 """Sets the expiration of a user account
349 This command sets the expiration of a user account. The username specified on the command is the sAMAccountName. The username may also be specified using the --filter option.
351 When a user account expires, it becomes disabled and the user is unable to logon. The administrator may issue the samba-tool user enable command to enable the account for logon. The permissions and memberships associated with the account are retained when the account is enabled.
353 The command may be run from the root userid or another authorized userid. The -H or --URL= option can be used to execute the command on a remote server.
355 Example1:
356 samba-tool user setexpiry User1 --days=20 --URL=ldap://samba.samdom.example.com --username=administrator --password=passw1rd
358 Example1 shows how to set the expiration of an account in a remote LDAP server. The --URL parameter is used to specify the remote target server. The --username= and --password= options are used to pass the username and password of a user that exists on the remote server and is authorized to update that server.
360 Exampl2:
361 su samba-tool user setexpiry User2
363 Example2 shows how to set the account expiration of user User2 so it will never expire. The user in this example resides on the local server. sudo is used so a user may run the command as root.
365 Example3:
366 samba-tool user setexpiry --days=20 --filter=samaccountname=User3
368 Example3 shows how to set the account expiration date to end of day 20 days from the current day. The username or sAMAccountName is specified using the --filter= paramter and the username in this example is User3.
370 Example4:
371 samba-tool user setexpiry --noexpiry User4
372 Example4 shows how to set the account expiration so that it will never expire. The username and sAMAccountName in this example is User4.
375 synopsis = "%prog (<username>|--filter <filter>) [options]"
377 takes_optiongroups = {
378 "sambaopts": options.SambaOptions,
379 "versionopts": options.VersionOptions,
380 "credopts": options.CredentialsOptions,
383 takes_options = [
384 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
385 metavar="URL", dest="H"),
386 Option("--filter", help="LDAP Filter to set password on", type=str),
387 Option("--days", help="Days to expiry", type=int, default=0),
388 Option("--noexpiry", help="Password does never expire", action="store_true", default=False),
391 takes_args = ["username?"]
393 def run(self, username=None, sambaopts=None, credopts=None,
394 versionopts=None, H=None, filter=None, days=None, noexpiry=None):
395 if username is None and filter is None:
396 raise CommandError("Either the username or '--filter' must be specified!")
398 if filter is None:
399 filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
401 lp = sambaopts.get_loadparm()
402 creds = credopts.get_credentials(lp)
404 samdb = SamDB(url=H, session_info=system_session(),
405 credentials=creds, lp=lp)
407 try:
408 samdb.setexpiry(filter, days*24*3600, no_expiry_req=noexpiry)
409 except Exception, msg:
410 # FIXME: Catch more specific exception
411 raise CommandError("Failed to set expiry for user '%s': %s" % (
412 username or filter, msg))
413 self.outf.write("Set expiry for user '%s' to %u days\n" % (
414 username or filter, days))
417 class cmd_user_password(Command):
418 """Change password for a user account (the one provided in authentication)
421 synopsis = "%prog [options]"
423 takes_options = [
424 Option("--newpassword", help="New password", type=str),
427 takes_optiongroups = {
428 "sambaopts": options.SambaOptions,
429 "credopts": options.CredentialsOptions,
430 "versionopts": options.VersionOptions,
433 def run(self, credopts=None, sambaopts=None, versionopts=None,
434 newpassword=None):
436 lp = sambaopts.get_loadparm()
437 creds = credopts.get_credentials(lp)
439 # get old password now, to get the password prompts in the right order
440 old_password = creds.get_password()
442 net = Net(creds, lp, server=credopts.ipaddress)
444 password = newpassword
445 while True:
446 if password is not None and password is not '':
447 break
448 password = getpass("New Password: ")
449 passwordverify = getpass("Retype Password: ")
450 if not password == passwordverify:
451 password = None
452 self.outf.write("Sorry, passwords do not match.\n")
454 try:
455 net.change_password(password)
456 except Exception, msg:
457 # FIXME: catch more specific exception
458 raise CommandError("Failed to change password : %s" % msg)
459 self.outf.write("Changed password OK\n")
462 class cmd_user_setpassword(Command):
463 """Sets or resets the password of a user account
465 This command sets or resets the logon password for a user account. The username specified on the command is the sAMAccountName. The username may also be specified using the --filter option.
467 If the password is not specified on the command through the --newpassword parameter, the user is prompted for the password to be entered through the command line.
469 It is good security practice for the administrator to use the --must-change-at-next-login option which requires that when the user logs on to the account for the first time following the password change, he/she must change the password.
471 The command may be run from the root userid or another authorized userid. The -H or --URL= option can be used to execute the command against a remote server.
473 Example1:
474 samba-tool user setpassword TestUser1 passw0rd --URL=ldap://samba.samdom.example.com -Uadministrator%passw1rd
476 Example1 shows how to set the password of user TestUser1 on a remote LDAP server. The --URL parameter is used to specify the remote target server. The -U option is used to pass the username and password of a user that exists on the remote server and is authorized to update the server.
478 Example2:
479 sudo samba-tool user setpassword TestUser2 passw0rd --must-change-at-next-login
481 Example2 shows how an administrator would reset the TestUser2 user's password to passw0rd. The user is running under the root userid using the sudo command. In this example the user TestUser2 must change their password the next time they logon to the account.
483 Example3:
484 samba-tool user setpassword --filter=samaccountname=TestUser3 --password=passw0rd
486 Example3 shows how an administrator would reset TestUser3 user's password to passw0rd using the --filter= option to specify the username.
489 synopsis = "%prog (<username>|--filter <filter>) [options]"
491 takes_optiongroups = {
492 "sambaopts": options.SambaOptions,
493 "versionopts": options.VersionOptions,
494 "credopts": options.CredentialsOptions,
497 takes_options = [
498 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
499 metavar="URL", dest="H"),
500 Option("--filter", help="LDAP Filter to set password on", type=str),
501 Option("--newpassword", help="Set password", type=str),
502 Option("--must-change-at-next-login",
503 help="Force password to be changed on next login",
504 action="store_true"),
505 Option("--random-password",
506 help="Generate random password",
507 action="store_true"),
510 takes_args = ["username?"]
512 def run(self, username=None, filter=None, credopts=None, sambaopts=None,
513 versionopts=None, H=None, newpassword=None,
514 must_change_at_next_login=False, random_password=False):
515 if filter is None and username is None:
516 raise CommandError("Either the username or '--filter' must be specified!")
518 if random_password:
519 password = generate_random_password(128, 255)
520 else:
521 password = newpassword
523 while 1:
524 if password is not None and password is not '':
525 break
526 password = getpass("New Password: ")
528 if filter is None:
529 filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
531 lp = sambaopts.get_loadparm()
532 creds = credopts.get_credentials(lp)
534 creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
536 samdb = SamDB(url=H, session_info=system_session(),
537 credentials=creds, lp=lp)
539 try:
540 samdb.setpassword(filter, password,
541 force_change_at_next_login=must_change_at_next_login,
542 username=username)
543 except Exception, msg:
544 # FIXME: catch more specific exception
545 raise CommandError("Failed to set password for user '%s': %s" % (username or filter, msg))
546 self.outf.write("Changed password OK\n")
549 class cmd_user(SuperCommand):
550 """User management"""
552 subcommands = {}
553 subcommands["add"] = cmd_user_create()
554 subcommands["create"] = cmd_user_create()
555 subcommands["delete"] = cmd_user_delete()
556 subcommands["disable"] = cmd_user_disable()
557 subcommands["enable"] = cmd_user_enable()
558 subcommands["list"] = cmd_user_list()
559 subcommands["setexpiry"] = cmd_user_setexpiry()
560 subcommands["password"] = cmd_user_password()
561 subcommands["setpassword"] = cmd_user_setpassword()