Redescribe --userou usage
[Samba.git] / python / samba / netcmd / user.py
blob24dd77df568c76510de537935625ffa2179b7060
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 import pwd
23 from getpass import getpass
24 from samba.auth import system_session
25 from samba.samdb import SamDB
26 from samba import (
27 dsdb,
28 gensec,
29 generate_random_password,
31 from samba.net import Net
33 from samba.netcmd import (
34 Command,
35 CommandError,
36 SuperCommand,
37 Option,
41 class cmd_user_create(Command):
42 """Create a new user.
44 This command creates a new user account in the Active Directory domain. The username specified on the command is the sAMaccountName.
46 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).
48 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.
50 Unix (RFC2307) attributes may be added to the user account. Attributes taken from NSS are obtained on the local machine. Explicitly given values override values obtained from NSS. Configure 'idmap_ldb:use rfc2307 = Yes' to use these attributes for UID/GID mapping.
52 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.
54 Example1:
55 samba-tool user add User1 passw0rd --given-name=John --surname=Smith --must-change-at-next-login -H ldap://samba.samdom.example.com -Uadministrator%passw1rd
57 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.
59 Example2:
60 sudo samba-tool user add User2 passw2rd --given-name=Jane --surname=Doe --must-change-at-next-login
62 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.
64 Example3:
65 samba-tool user add User3 passw3rd --userou='OU=OrgUnit'
67 Example3 shows how to create a new user in the OrgUnit organizational unit.
69 Example4:
70 samba-tool user create User4 passw4rd --rfc2307-from-nss --gecos 'some text'
72 Example4 shows how to create a new user with Unix UID, GID and login-shell set from the local NSS and GECOS set to 'some text'.
74 """
75 synopsis = "%prog <username> [<password>] [options]"
77 takes_options = [
78 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
79 metavar="URL", dest="H"),
80 Option("--must-change-at-next-login",
81 help="Force password to be changed on next login",
82 action="store_true"),
83 Option("--random-password",
84 help="Generate random password",
85 action="store_true"),
86 Option("--use-username-as-cn",
87 help="Force use of username as user's CN",
88 action="store_true"),
89 Option("--userou",
90 help="DN of alternative location (without domainDN counterpart) to default CN=Users in which new user object will be created. E. g. 'OU=<OU name>'",
91 type=str),
92 Option("--surname", help="User's surname", type=str),
93 Option("--given-name", help="User's given name", type=str),
94 Option("--initials", help="User's initials", type=str),
95 Option("--profile-path", help="User's profile path", type=str),
96 Option("--script-path", help="User's logon script path", type=str),
97 Option("--home-drive", help="User's home drive letter", type=str),
98 Option("--home-directory", help="User's home directory path", type=str),
99 Option("--job-title", help="User's job title", type=str),
100 Option("--department", help="User's department", type=str),
101 Option("--company", help="User's company", type=str),
102 Option("--description", help="User's description", type=str),
103 Option("--mail-address", help="User's email address", type=str),
104 Option("--internet-address", help="User's home page", type=str),
105 Option("--telephone-number", help="User's phone number", type=str),
106 Option("--physical-delivery-office", help="User's office location", type=str),
107 Option("--rfc2307-from-nss",
108 help="Copy Unix user attributes from NSS (will be overridden by explicit UID/GID/GECOS/shell)",
109 action="store_true"),
110 Option("--uid", help="User's Unix/RFC2307 username", type=str),
111 Option("--uid-number", help="User's Unix/RFC2307 numeric UID", type=int),
112 Option("--gid-number", help="User's Unix/RFC2307 primary GID number", type=int),
113 Option("--gecos", help="User's Unix/RFC2307 GECOS field", type=str),
114 Option("--login-shell", help="User's Unix/RFC2307 login shell", type=str),
117 takes_args = ["username", "password?"]
119 takes_optiongroups = {
120 "sambaopts": options.SambaOptions,
121 "credopts": options.CredentialsOptions,
122 "versionopts": options.VersionOptions,
125 def run(self, username, password=None, credopts=None, sambaopts=None,
126 versionopts=None, H=None, must_change_at_next_login=False,
127 random_password=False, use_username_as_cn=False, userou=None,
128 surname=None, given_name=None, initials=None, profile_path=None,
129 script_path=None, home_drive=None, home_directory=None,
130 job_title=None, department=None, company=None, description=None,
131 mail_address=None, internet_address=None, telephone_number=None,
132 physical_delivery_office=None, rfc2307_from_nss=False,
133 uid=None, uid_number=None, gid_number=None, gecos=None, login_shell=None):
135 if random_password:
136 password = generate_random_password(128, 255)
138 while True:
139 if password is not None and password is not '':
140 break
141 password = getpass("New Password: ")
142 passwordverify = getpass("Retype Password: ")
143 if not password == passwordverify:
144 password = None
145 self.outf.write("Sorry, passwords do not match.\n")
147 if rfc2307_from_nss:
148 pwent = pwd.getpwnam(username)
149 if uid is None:
150 uid = username
151 if uid_number is None:
152 uid_number = pwent[2]
153 if gid_number is None:
154 gid_number = pwent[3]
155 if gecos is None:
156 gecos = pwent[4]
157 if login_shell is None:
158 login_shell = pwent[6]
160 lp = sambaopts.get_loadparm()
161 creds = credopts.get_credentials(lp)
163 if uid_number or gid_number:
164 if not lp.get("idmap_ldb:use rfc2307"):
165 self.outf.write("You are setting a Unix/RFC2307 UID or GID. You may want to set 'idmap_ldb:use rfc2307 = Yes' to use those attributes for XID/SID-mapping.\n")
167 try:
168 samdb = SamDB(url=H, session_info=system_session(),
169 credentials=creds, lp=lp)
170 samdb.newuser(username, password, force_password_change_at_next_login_req=must_change_at_next_login,
171 useusernameascn=use_username_as_cn, userou=userou, surname=surname, givenname=given_name, initials=initials,
172 profilepath=profile_path, homedrive=home_drive, scriptpath=script_path, homedirectory=home_directory,
173 jobtitle=job_title, department=department, company=company, description=description,
174 mailaddress=mail_address, internetaddress=internet_address,
175 telephonenumber=telephone_number, physicaldeliveryoffice=physical_delivery_office,
176 uid=uid, uidnumber=uid_number, gidnumber=gid_number, gecos=gecos, loginshell=login_shell)
177 except Exception, e:
178 raise CommandError("Failed to add user '%s': " % username, e)
180 self.outf.write("User '%s' created successfully\n" % username)
183 class cmd_user_add(cmd_user_create):
184 __doc__ = cmd_user_create.__doc__
185 # take this print out after the add subcommand is removed.
186 # the add subcommand is deprecated but left in for now to allow people to
187 # migrate to create
189 def run(self, *args, **kwargs):
190 self.err.write(
191 "Note: samba-tool user add is deprecated. "
192 "Please use samba-tool user create for the same function.\n")
193 return super(self, cmd_user_add).run(*args, **kwargs)
196 class cmd_user_delete(Command):
197 """Delete a user.
199 This command deletes a user account from the Active Directory domain. The username specified on the command is the sAMAccountName.
201 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.
203 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.
205 Example1:
206 samba-tool user delete User1 -H ldap://samba.samdom.example.com --username=administrator --password=passw1rd
208 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.
210 Example2:
211 sudo samba-tool user delete User2
213 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.
216 synopsis = "%prog <username> [options]"
218 takes_options = [
219 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
220 metavar="URL", dest="H"),
223 takes_args = ["username"]
224 takes_optiongroups = {
225 "sambaopts": options.SambaOptions,
226 "credopts": options.CredentialsOptions,
227 "versionopts": options.VersionOptions,
230 def run(self, username, credopts=None, sambaopts=None, versionopts=None,
231 H=None):
232 lp = sambaopts.get_loadparm()
233 creds = credopts.get_credentials(lp, fallback_machine=True)
235 try:
236 samdb = SamDB(url=H, session_info=system_session(),
237 credentials=creds, lp=lp)
238 samdb.deleteuser(username)
239 except Exception, e:
240 raise CommandError('Failed to remove user "%s"' % username, e)
241 self.outf.write("Deleted user %s\n" % username)
244 class cmd_user_list(Command):
245 """List all users."""
247 synopsis = "%prog [options]"
249 takes_options = [
250 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
251 metavar="URL", dest="H"),
254 takes_optiongroups = {
255 "sambaopts": options.SambaOptions,
256 "credopts": options.CredentialsOptions,
257 "versionopts": options.VersionOptions,
260 def run(self, sambaopts=None, credopts=None, versionopts=None, H=None):
261 lp = sambaopts.get_loadparm()
262 creds = credopts.get_credentials(lp, fallback_machine=True)
264 samdb = SamDB(url=H, session_info=system_session(),
265 credentials=creds, lp=lp)
267 domain_dn = samdb.domain_dn()
268 res = samdb.search(domain_dn, scope=ldb.SCOPE_SUBTREE,
269 expression=("(&(objectClass=user)(userAccountControl:%s:=%u))"
270 % (ldb.OID_COMPARATOR_AND, dsdb.UF_NORMAL_ACCOUNT)),
271 attrs=["samaccountname"])
272 if (len(res) == 0):
273 return
275 for msg in res:
276 self.outf.write("%s\n" % msg.get("samaccountname", idx=0))
279 class cmd_user_enable(Command):
280 """Enable an user.
282 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.
284 There are many reasons why an account may become disabled. These include:
285 - If a user exceeds the account policy for logon attempts
286 - If an administrator disables the account
287 - If the account expires
289 The samba-tool user enable command allows an administrator to enable an account which has become disabled.
291 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.
293 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.
295 Example1:
296 samba-tool user enable Testuser1 --URL=ldap://samba.samdom.example.com --username=administrator --password=passw1rd
298 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.
300 Example2:
301 su samba-tool user enable Testuser2
303 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.
305 Example3:
306 samba-tool user enable --filter=samaccountname=Testuser3
308 Example3 shows how to enable a user in the domain against a local LDAP server. It uses the --filter=samaccountname to specify the username.
311 synopsis = "%prog (<username>|--filter <filter>) [options]"
314 takes_optiongroups = {
315 "sambaopts": options.SambaOptions,
316 "versionopts": options.VersionOptions,
317 "credopts": options.CredentialsOptions,
320 takes_options = [
321 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
322 metavar="URL", dest="H"),
323 Option("--filter", help="LDAP Filter to set password on", type=str),
326 takes_args = ["username?"]
328 def run(self, username=None, sambaopts=None, credopts=None,
329 versionopts=None, filter=None, H=None):
330 if username is None and filter is None:
331 raise CommandError("Either the username or '--filter' must be specified!")
333 if filter is None:
334 filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
336 lp = sambaopts.get_loadparm()
337 creds = credopts.get_credentials(lp, fallback_machine=True)
339 samdb = SamDB(url=H, session_info=system_session(),
340 credentials=creds, lp=lp)
341 try:
342 samdb.enable_account(filter)
343 except Exception, msg:
344 raise CommandError("Failed to enable user '%s': %s" % (username or filter, msg))
345 self.outf.write("Enabled user '%s'\n" % (username or filter))
348 class cmd_user_disable(Command):
349 """Disable an user."""
351 synopsis = "%prog (<username>|--filter <filter>) [options]"
353 takes_options = [
354 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
355 metavar="URL", dest="H"),
356 Option("--filter", help="LDAP Filter to set password on", type=str),
359 takes_args = ["username?"]
361 takes_optiongroups = {
362 "sambaopts": options.SambaOptions,
363 "credopts": options.CredentialsOptions,
364 "versionopts": options.VersionOptions,
367 def run(self, username=None, sambaopts=None, credopts=None,
368 versionopts=None, filter=None, H=None):
369 if username is None and filter is None:
370 raise CommandError("Either the username or '--filter' must be specified!")
372 if filter is None:
373 filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
375 lp = sambaopts.get_loadparm()
376 creds = credopts.get_credentials(lp, fallback_machine=True)
378 samdb = SamDB(url=H, session_info=system_session(),
379 credentials=creds, lp=lp)
380 try:
381 samdb.disable_account(filter)
382 except Exception, msg:
383 raise CommandError("Failed to disable user '%s': %s" % (username or filter, msg))
386 class cmd_user_setexpiry(Command):
387 """Set the expiration of a user account.
389 The user can either be specified by their sAMAccountName or using the --filter option.
391 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.
393 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.
395 Example1:
396 samba-tool user setexpiry User1 --days=20 --URL=ldap://samba.samdom.example.com --username=administrator --password=passw1rd
398 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.
400 Example2:
401 su samba-tool user setexpiry User2
403 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.
405 Example3:
406 samba-tool user setexpiry --days=20 --filter=samaccountname=User3
408 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.
410 Example4:
411 samba-tool user setexpiry --noexpiry User4
412 Example4 shows how to set the account expiration so that it will never expire. The username and sAMAccountName in this example is User4.
415 synopsis = "%prog (<username>|--filter <filter>) [options]"
417 takes_optiongroups = {
418 "sambaopts": options.SambaOptions,
419 "versionopts": options.VersionOptions,
420 "credopts": options.CredentialsOptions,
423 takes_options = [
424 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
425 metavar="URL", dest="H"),
426 Option("--filter", help="LDAP Filter to set password on", type=str),
427 Option("--days", help="Days to expiry", type=int, default=0),
428 Option("--noexpiry", help="Password does never expire", action="store_true", default=False),
431 takes_args = ["username?"]
433 def run(self, username=None, sambaopts=None, credopts=None,
434 versionopts=None, H=None, filter=None, days=None, noexpiry=None):
435 if username is None and filter is None:
436 raise CommandError("Either the username or '--filter' must be specified!")
438 if filter is None:
439 filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
441 lp = sambaopts.get_loadparm()
442 creds = credopts.get_credentials(lp)
444 samdb = SamDB(url=H, session_info=system_session(),
445 credentials=creds, lp=lp)
447 try:
448 samdb.setexpiry(filter, days*24*3600, no_expiry_req=noexpiry)
449 except Exception, msg:
450 # FIXME: Catch more specific exception
451 raise CommandError("Failed to set expiry for user '%s': %s" % (
452 username or filter, msg))
453 if days:
454 self.outf.write("Expiry for user '%s' set to %u days.\n" % (
455 username or filter, days))
456 else:
457 self.outf.write("Expiry for user '%s' disabled.\n" % (
458 username or filter))
461 class cmd_user_password(Command):
462 """Change password for a user account (the one provided in authentication).
465 synopsis = "%prog [options]"
467 takes_options = [
468 Option("--newpassword", help="New password", type=str),
471 takes_optiongroups = {
472 "sambaopts": options.SambaOptions,
473 "credopts": options.CredentialsOptions,
474 "versionopts": options.VersionOptions,
477 def run(self, credopts=None, sambaopts=None, versionopts=None,
478 newpassword=None):
480 lp = sambaopts.get_loadparm()
481 creds = credopts.get_credentials(lp)
483 # get old password now, to get the password prompts in the right order
484 old_password = creds.get_password()
486 net = Net(creds, lp, server=credopts.ipaddress)
488 password = newpassword
489 while True:
490 if password is not None and password is not '':
491 break
492 password = getpass("New Password: ")
493 passwordverify = getpass("Retype Password: ")
494 if not password == passwordverify:
495 password = None
496 self.outf.write("Sorry, passwords do not match.\n")
498 try:
499 net.change_password(password)
500 except Exception, msg:
501 # FIXME: catch more specific exception
502 raise CommandError("Failed to change password : %s" % msg)
503 self.outf.write("Changed password OK\n")
506 class cmd_user_setpassword(Command):
507 """Set or reset the password of a user account.
509 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.
511 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.
513 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.
515 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.
517 Example1:
518 samba-tool user setpassword TestUser1 --newpassword=passw0rd --URL=ldap://samba.samdom.example.com -Uadministrator%passw1rd
520 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.
522 Example2:
523 sudo samba-tool user setpassword TestUser2 --newpassword=passw0rd --must-change-at-next-login
525 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.
527 Example3:
528 samba-tool user setpassword --filter=samaccountname=TestUser3 --newpassword=passw0rd
530 Example3 shows how an administrator would reset TestUser3 user's password to passw0rd using the --filter= option to specify the username.
533 synopsis = "%prog (<username>|--filter <filter>) [options]"
535 takes_optiongroups = {
536 "sambaopts": options.SambaOptions,
537 "versionopts": options.VersionOptions,
538 "credopts": options.CredentialsOptions,
541 takes_options = [
542 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
543 metavar="URL", dest="H"),
544 Option("--filter", help="LDAP Filter to set password on", type=str),
545 Option("--newpassword", help="Set password", type=str),
546 Option("--must-change-at-next-login",
547 help="Force password to be changed on next login",
548 action="store_true"),
549 Option("--random-password",
550 help="Generate random password",
551 action="store_true"),
554 takes_args = ["username?"]
556 def run(self, username=None, filter=None, credopts=None, sambaopts=None,
557 versionopts=None, H=None, newpassword=None,
558 must_change_at_next_login=False, random_password=False):
559 if filter is None and username is None:
560 raise CommandError("Either the username or '--filter' must be specified!")
562 if random_password:
563 password = generate_random_password(128, 255)
564 else:
565 password = newpassword
567 while 1:
568 if password is not None and password is not '':
569 break
570 password = getpass("New Password: ")
572 if filter is None:
573 filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
575 lp = sambaopts.get_loadparm()
576 creds = credopts.get_credentials(lp)
578 creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
580 samdb = SamDB(url=H, session_info=system_session(),
581 credentials=creds, lp=lp)
583 try:
584 samdb.setpassword(filter, password,
585 force_change_at_next_login=must_change_at_next_login,
586 username=username)
587 except Exception, msg:
588 # FIXME: catch more specific exception
589 raise CommandError("Failed to set password for user '%s': %s" % (username or filter, msg))
590 self.outf.write("Changed password OK\n")
593 class cmd_user(SuperCommand):
594 """User management."""
596 subcommands = {}
597 subcommands["add"] = cmd_user_create()
598 subcommands["create"] = cmd_user_create()
599 subcommands["delete"] = cmd_user_delete()
600 subcommands["disable"] = cmd_user_disable()
601 subcommands["enable"] = cmd_user_enable()
602 subcommands["list"] = cmd_user_list()
603 subcommands["setexpiry"] = cmd_user_setexpiry()
604 subcommands["password"] = cmd_user_password()
605 subcommands["setpassword"] = cmd_user_setpassword()