nfs4acls: Use talloc_realloc()
[Samba.git] / python / samba / netcmd / user.py
blob2bc5522e26bd825ee9d483e739e1b3d165726700
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 Example5:
75 samba-tool user add User5 passw5rd --nis-domain=samdom --unix-home=/home/User5 \
76 --uid-number=10005 --login-shell=/bin/false --gid-number=10000
78 Example5 shows how to create an RFC2307/NIS domain enabled user account. If
79 --nis-domain is set, then the other four parameters are mandatory.
81 """
82 synopsis = "%prog <username> [<password>] [options]"
84 takes_options = [
85 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
86 metavar="URL", dest="H"),
87 Option("--must-change-at-next-login",
88 help="Force password to be changed on next login",
89 action="store_true"),
90 Option("--random-password",
91 help="Generate random password",
92 action="store_true"),
93 Option("--use-username-as-cn",
94 help="Force use of username as user's CN",
95 action="store_true"),
96 Option("--userou",
97 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>'",
98 type=str),
99 Option("--surname", help="User's surname", type=str),
100 Option("--given-name", help="User's given name", type=str),
101 Option("--initials", help="User's initials", type=str),
102 Option("--profile-path", help="User's profile path", type=str),
103 Option("--script-path", help="User's logon script path", type=str),
104 Option("--home-drive", help="User's home drive letter", type=str),
105 Option("--home-directory", help="User's home directory path", type=str),
106 Option("--job-title", help="User's job title", type=str),
107 Option("--department", help="User's department", type=str),
108 Option("--company", help="User's company", type=str),
109 Option("--description", help="User's description", type=str),
110 Option("--mail-address", help="User's email address", type=str),
111 Option("--internet-address", help="User's home page", type=str),
112 Option("--telephone-number", help="User's phone number", type=str),
113 Option("--physical-delivery-office", help="User's office location", type=str),
114 Option("--rfc2307-from-nss",
115 help="Copy Unix user attributes from NSS (will be overridden by explicit UID/GID/GECOS/shell)",
116 action="store_true"),
117 Option("--nis-domain", help="User's Unix/RFC2307 NIS domain", type=str),
118 Option("--unix-home", help="User's Unix/RFC2307 home directory",
119 type=str),
120 Option("--uid", help="User's Unix/RFC2307 username", type=str),
121 Option("--uid-number", help="User's Unix/RFC2307 numeric UID", type=int),
122 Option("--gid-number", help="User's Unix/RFC2307 primary GID number", type=int),
123 Option("--gecos", help="User's Unix/RFC2307 GECOS field", type=str),
124 Option("--login-shell", help="User's Unix/RFC2307 login shell", type=str),
127 takes_args = ["username", "password?"]
129 takes_optiongroups = {
130 "sambaopts": options.SambaOptions,
131 "credopts": options.CredentialsOptions,
132 "versionopts": options.VersionOptions,
135 def run(self, username, password=None, credopts=None, sambaopts=None,
136 versionopts=None, H=None, must_change_at_next_login=False,
137 random_password=False, use_username_as_cn=False, userou=None,
138 surname=None, given_name=None, initials=None, profile_path=None,
139 script_path=None, home_drive=None, home_directory=None,
140 job_title=None, department=None, company=None, description=None,
141 mail_address=None, internet_address=None, telephone_number=None,
142 physical_delivery_office=None, rfc2307_from_nss=False,
143 nis_domain=None, unix_home=None, uid=None, uid_number=None,
144 gid_number=None, gecos=None, login_shell=None):
146 if random_password:
147 password = generate_random_password(128, 255)
149 while True:
150 if password is not None and password is not '':
151 break
152 password = getpass("New Password: ")
153 passwordverify = getpass("Retype Password: ")
154 if not password == passwordverify:
155 password = None
156 self.outf.write("Sorry, passwords do not match.\n")
158 if rfc2307_from_nss:
159 pwent = pwd.getpwnam(username)
160 if uid is None:
161 uid = username
162 if uid_number is None:
163 uid_number = pwent[2]
164 if gid_number is None:
165 gid_number = pwent[3]
166 if gecos is None:
167 gecos = pwent[4]
168 if login_shell is None:
169 login_shell = pwent[6]
171 lp = sambaopts.get_loadparm()
172 creds = credopts.get_credentials(lp)
174 if uid_number or gid_number:
175 if not lp.get("idmap_ldb:use rfc2307"):
176 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")
178 if nis_domain is not None:
179 if None in (uid_number, login_shell, unix_home, gid_number):
180 raise CommandError('Missing parameters. To enable NIS features, '
181 'the following options have to be given: '
182 '--nis-domain=, --uidNumber=, --login-shell='
183 ', --unix-home=, --gid-number= Operation '
184 'cancelled.')
186 try:
187 samdb = SamDB(url=H, session_info=system_session(),
188 credentials=creds, lp=lp)
189 samdb.newuser(username, password, force_password_change_at_next_login_req=must_change_at_next_login,
190 useusernameascn=use_username_as_cn, userou=userou, surname=surname, givenname=given_name, initials=initials,
191 profilepath=profile_path, homedrive=home_drive, scriptpath=script_path, homedirectory=home_directory,
192 jobtitle=job_title, department=department, company=company, description=description,
193 mailaddress=mail_address, internetaddress=internet_address,
194 telephonenumber=telephone_number, physicaldeliveryoffice=physical_delivery_office,
195 nisdomain=nis_domain, unixhome=unix_home, uid=uid,
196 uidnumber=uid_number, gidnumber=gid_number,
197 gecos=gecos, loginshell=login_shell)
198 except Exception, e:
199 raise CommandError("Failed to add user '%s': " % username, e)
201 self.outf.write("User '%s' created successfully\n" % username)
204 class cmd_user_add(cmd_user_create):
205 __doc__ = cmd_user_create.__doc__
206 # take this print out after the add subcommand is removed.
207 # the add subcommand is deprecated but left in for now to allow people to
208 # migrate to create
210 def run(self, *args, **kwargs):
211 self.err.write(
212 "Note: samba-tool user add is deprecated. "
213 "Please use samba-tool user create for the same function.\n")
214 return super(self, cmd_user_add).run(*args, **kwargs)
217 class cmd_user_delete(Command):
218 """Delete a user.
220 This command deletes a user account from the Active Directory domain. The username specified on the command is the sAMAccountName.
222 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.
224 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.
226 Example1:
227 samba-tool user delete User1 -H ldap://samba.samdom.example.com --username=administrator --password=passw1rd
229 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.
231 Example2:
232 sudo samba-tool user delete User2
234 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.
237 synopsis = "%prog <username> [options]"
239 takes_options = [
240 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
241 metavar="URL", dest="H"),
244 takes_args = ["username"]
245 takes_optiongroups = {
246 "sambaopts": options.SambaOptions,
247 "credopts": options.CredentialsOptions,
248 "versionopts": options.VersionOptions,
251 def run(self, username, credopts=None, sambaopts=None, versionopts=None,
252 H=None):
253 lp = sambaopts.get_loadparm()
254 creds = credopts.get_credentials(lp, fallback_machine=True)
256 try:
257 samdb = SamDB(url=H, session_info=system_session(),
258 credentials=creds, lp=lp)
259 samdb.deleteuser(username)
260 except Exception, e:
261 raise CommandError('Failed to remove user "%s"' % username, e)
262 self.outf.write("Deleted user %s\n" % username)
265 class cmd_user_list(Command):
266 """List all users."""
268 synopsis = "%prog [options]"
270 takes_options = [
271 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
272 metavar="URL", dest="H"),
275 takes_optiongroups = {
276 "sambaopts": options.SambaOptions,
277 "credopts": options.CredentialsOptions,
278 "versionopts": options.VersionOptions,
281 def run(self, sambaopts=None, credopts=None, versionopts=None, H=None):
282 lp = sambaopts.get_loadparm()
283 creds = credopts.get_credentials(lp, fallback_machine=True)
285 samdb = SamDB(url=H, session_info=system_session(),
286 credentials=creds, lp=lp)
288 domain_dn = samdb.domain_dn()
289 res = samdb.search(domain_dn, scope=ldb.SCOPE_SUBTREE,
290 expression=("(&(objectClass=user)(userAccountControl:%s:=%u))"
291 % (ldb.OID_COMPARATOR_AND, dsdb.UF_NORMAL_ACCOUNT)),
292 attrs=["samaccountname"])
293 if (len(res) == 0):
294 return
296 for msg in res:
297 self.outf.write("%s\n" % msg.get("samaccountname", idx=0))
300 class cmd_user_enable(Command):
301 """Enable an user.
303 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.
305 There are many reasons why an account may become disabled. These include:
306 - If a user exceeds the account policy for logon attempts
307 - If an administrator disables the account
308 - If the account expires
310 The samba-tool user enable command allows an administrator to enable an account which has become disabled.
312 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.
314 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.
316 Example1:
317 samba-tool user enable Testuser1 --URL=ldap://samba.samdom.example.com --username=administrator --password=passw1rd
319 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.
321 Example2:
322 su samba-tool user enable Testuser2
324 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.
326 Example3:
327 samba-tool user enable --filter=samaccountname=Testuser3
329 Example3 shows how to enable a user in the domain against a local LDAP server. It uses the --filter=samaccountname to specify the username.
332 synopsis = "%prog (<username>|--filter <filter>) [options]"
335 takes_optiongroups = {
336 "sambaopts": options.SambaOptions,
337 "versionopts": options.VersionOptions,
338 "credopts": options.CredentialsOptions,
341 takes_options = [
342 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
343 metavar="URL", dest="H"),
344 Option("--filter", help="LDAP Filter to set password on", type=str),
347 takes_args = ["username?"]
349 def run(self, username=None, sambaopts=None, credopts=None,
350 versionopts=None, filter=None, H=None):
351 if username is None and filter is None:
352 raise CommandError("Either the username or '--filter' must be specified!")
354 if filter is None:
355 filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
357 lp = sambaopts.get_loadparm()
358 creds = credopts.get_credentials(lp, fallback_machine=True)
360 samdb = SamDB(url=H, session_info=system_session(),
361 credentials=creds, lp=lp)
362 try:
363 samdb.enable_account(filter)
364 except Exception, msg:
365 raise CommandError("Failed to enable user '%s': %s" % (username or filter, msg))
366 self.outf.write("Enabled user '%s'\n" % (username or filter))
369 class cmd_user_disable(Command):
370 """Disable an user."""
372 synopsis = "%prog (<username>|--filter <filter>) [options]"
374 takes_options = [
375 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
376 metavar="URL", dest="H"),
377 Option("--filter", help="LDAP Filter to set password on", type=str),
380 takes_args = ["username?"]
382 takes_optiongroups = {
383 "sambaopts": options.SambaOptions,
384 "credopts": options.CredentialsOptions,
385 "versionopts": options.VersionOptions,
388 def run(self, username=None, sambaopts=None, credopts=None,
389 versionopts=None, filter=None, H=None):
390 if username is None and filter is None:
391 raise CommandError("Either the username or '--filter' must be specified!")
393 if filter is None:
394 filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
396 lp = sambaopts.get_loadparm()
397 creds = credopts.get_credentials(lp, fallback_machine=True)
399 samdb = SamDB(url=H, session_info=system_session(),
400 credentials=creds, lp=lp)
401 try:
402 samdb.disable_account(filter)
403 except Exception, msg:
404 raise CommandError("Failed to disable user '%s': %s" % (username or filter, msg))
407 class cmd_user_setexpiry(Command):
408 """Set the expiration of a user account.
410 The user can either be specified by their sAMAccountName or using the --filter option.
412 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.
414 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.
416 Example1:
417 samba-tool user setexpiry User1 --days=20 --URL=ldap://samba.samdom.example.com --username=administrator --password=passw1rd
419 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.
421 Example2:
422 su samba-tool user setexpiry User2
424 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.
426 Example3:
427 samba-tool user setexpiry --days=20 --filter=samaccountname=User3
429 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.
431 Example4:
432 samba-tool user setexpiry --noexpiry User4
433 Example4 shows how to set the account expiration so that it will never expire. The username and sAMAccountName in this example is User4.
436 synopsis = "%prog (<username>|--filter <filter>) [options]"
438 takes_optiongroups = {
439 "sambaopts": options.SambaOptions,
440 "versionopts": options.VersionOptions,
441 "credopts": options.CredentialsOptions,
444 takes_options = [
445 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
446 metavar="URL", dest="H"),
447 Option("--filter", help="LDAP Filter to set password on", type=str),
448 Option("--days", help="Days to expiry", type=int, default=0),
449 Option("--noexpiry", help="Password does never expire", action="store_true", default=False),
452 takes_args = ["username?"]
454 def run(self, username=None, sambaopts=None, credopts=None,
455 versionopts=None, H=None, filter=None, days=None, noexpiry=None):
456 if username is None and filter is None:
457 raise CommandError("Either the username or '--filter' must be specified!")
459 if filter is None:
460 filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
462 lp = sambaopts.get_loadparm()
463 creds = credopts.get_credentials(lp)
465 samdb = SamDB(url=H, session_info=system_session(),
466 credentials=creds, lp=lp)
468 try:
469 samdb.setexpiry(filter, days*24*3600, no_expiry_req=noexpiry)
470 except Exception, msg:
471 # FIXME: Catch more specific exception
472 raise CommandError("Failed to set expiry for user '%s': %s" % (
473 username or filter, msg))
474 if noexpiry:
475 self.outf.write("Expiry for user '%s' disabled.\n" % (
476 username or filter))
477 else:
478 self.outf.write("Expiry for user '%s' set to %u days.\n" % (
479 username or filter, days))
482 class cmd_user_password(Command):
483 """Change password for a user account (the one provided in authentication).
486 synopsis = "%prog [options]"
488 takes_options = [
489 Option("--newpassword", help="New password", type=str),
492 takes_optiongroups = {
493 "sambaopts": options.SambaOptions,
494 "credopts": options.CredentialsOptions,
495 "versionopts": options.VersionOptions,
498 def run(self, credopts=None, sambaopts=None, versionopts=None,
499 newpassword=None):
501 lp = sambaopts.get_loadparm()
502 creds = credopts.get_credentials(lp)
504 # get old password now, to get the password prompts in the right order
505 old_password = creds.get_password()
507 net = Net(creds, lp, server=credopts.ipaddress)
509 password = newpassword
510 while True:
511 if password is not None and password is not '':
512 break
513 password = getpass("New Password: ")
514 passwordverify = getpass("Retype Password: ")
515 if not password == passwordverify:
516 password = None
517 self.outf.write("Sorry, passwords do not match.\n")
519 try:
520 net.change_password(password)
521 except Exception, msg:
522 # FIXME: catch more specific exception
523 raise CommandError("Failed to change password : %s" % msg)
524 self.outf.write("Changed password OK\n")
527 class cmd_user_setpassword(Command):
528 """Set or reset the password of a user account.
530 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.
532 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.
534 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.
536 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.
538 Example1:
539 samba-tool user setpassword TestUser1 --newpassword=passw0rd --URL=ldap://samba.samdom.example.com -Uadministrator%passw1rd
541 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.
543 Example2:
544 sudo samba-tool user setpassword TestUser2 --newpassword=passw0rd --must-change-at-next-login
546 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.
548 Example3:
549 samba-tool user setpassword --filter=samaccountname=TestUser3 --newpassword=passw0rd
551 Example3 shows how an administrator would reset TestUser3 user's password to passw0rd using the --filter= option to specify the username.
554 synopsis = "%prog (<username>|--filter <filter>) [options]"
556 takes_optiongroups = {
557 "sambaopts": options.SambaOptions,
558 "versionopts": options.VersionOptions,
559 "credopts": options.CredentialsOptions,
562 takes_options = [
563 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
564 metavar="URL", dest="H"),
565 Option("--filter", help="LDAP Filter to set password on", type=str),
566 Option("--newpassword", help="Set password", type=str),
567 Option("--must-change-at-next-login",
568 help="Force password to be changed on next login",
569 action="store_true"),
570 Option("--random-password",
571 help="Generate random password",
572 action="store_true"),
575 takes_args = ["username?"]
577 def run(self, username=None, filter=None, credopts=None, sambaopts=None,
578 versionopts=None, H=None, newpassword=None,
579 must_change_at_next_login=False, random_password=False):
580 if filter is None and username is None:
581 raise CommandError("Either the username or '--filter' must be specified!")
583 if random_password:
584 password = generate_random_password(128, 255)
585 else:
586 password = newpassword
588 while 1:
589 if password is not None and password is not '':
590 break
591 password = getpass("New Password: ")
593 if filter is None:
594 filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
596 lp = sambaopts.get_loadparm()
597 creds = credopts.get_credentials(lp)
599 creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
601 samdb = SamDB(url=H, session_info=system_session(),
602 credentials=creds, lp=lp)
604 try:
605 samdb.setpassword(filter, password,
606 force_change_at_next_login=must_change_at_next_login,
607 username=username)
608 except Exception, msg:
609 # FIXME: catch more specific exception
610 raise CommandError("Failed to set password for user '%s': %s" % (username or filter, msg))
611 self.outf.write("Changed password OK\n")
614 class cmd_user(SuperCommand):
615 """User management."""
617 subcommands = {}
618 subcommands["add"] = cmd_user_create()
619 subcommands["create"] = cmd_user_create()
620 subcommands["delete"] = cmd_user_delete()
621 subcommands["disable"] = cmd_user_disable()
622 subcommands["enable"] = cmd_user_enable()
623 subcommands["list"] = cmd_user_list()
624 subcommands["setexpiry"] = cmd_user_setexpiry()
625 subcommands["password"] = cmd_user_password()
626 subcommands["setpassword"] = cmd_user_setpassword()