samba-tool: add --smartcard-required option to 'samba-tool user create'
[samba.git] / python / samba / netcmd / user.py
1 # user management
2 #
3 # Copyright Jelmer Vernooij 2010 <jelmer@samba.org>
4 # Copyright Theresa Halloran 2011 <theresahalloran@gmail.com>
5 #
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.
10 #
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.
15 #
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/>.
18 #
19
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,
30     )
31 from samba.net import Net
32
33 from samba.netcmd import (
34     Command,
35     CommandError,
36     SuperCommand,
37     Option,
38     )
39
40
41 class cmd_user_create(Command):
42     """Create a new user.
43
44 This command creates a new user account in the Active Directory domain.  The username specified on the command is the sAMaccountName.
45
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).
47
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.
49
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.
51
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.
53
54 Example1:
55 samba-tool user create User1 passw0rd --given-name=John --surname=Smith --must-change-at-next-login -H ldap://samba.samdom.example.com -Uadministrator%passw1rd
56
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.
58
59 Example2:
60 sudo samba-tool user create User2 passw2rd --given-name=Jane --surname=Doe --must-change-at-next-login
61
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.
63
64 Example3:
65 samba-tool user create User3 passw3rd --userou='OU=OrgUnit'
66
67 Example3 shows how to create a new user in the OrgUnit organizational unit.
68
69 Example4:
70 samba-tool user create User4 passw4rd --rfc2307-from-nss --gecos 'some text'
71
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'.
73
74 Example5:
75 samba-tool user create User5 passw5rd --nis-domain=samdom --unix-home=/home/User5 \
76            --uid-number=10005 --login-shell=/bin/false --gid-number=10000
77
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.
80
81 """
82     synopsis = "%prog <username> [<password>] [options]"
83
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("--smartcard-required",
94                 help="Require a smartcard for interactive logons",
95                 action="store_true"),
96         Option("--use-username-as-cn",
97                 help="Force use of username as user's CN",
98                 action="store_true"),
99         Option("--userou",
100                 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>'",
101                 type=str),
102         Option("--surname", help="User's surname", type=str),
103         Option("--given-name", help="User's given name", type=str),
104         Option("--initials", help="User's initials", type=str),
105         Option("--profile-path", help="User's profile path", type=str),
106         Option("--script-path", help="User's logon script path", type=str),
107         Option("--home-drive", help="User's home drive letter", type=str),
108         Option("--home-directory", help="User's home directory path", type=str),
109         Option("--job-title", help="User's job title", type=str),
110         Option("--department", help="User's department", type=str),
111         Option("--company", help="User's company", type=str),
112         Option("--description", help="User's description", type=str),
113         Option("--mail-address", help="User's email address", type=str),
114         Option("--internet-address", help="User's home page", type=str),
115         Option("--telephone-number", help="User's phone number", type=str),
116         Option("--physical-delivery-office", help="User's office location", type=str),
117         Option("--rfc2307-from-nss",
118                 help="Copy Unix user attributes from NSS (will be overridden by explicit UID/GID/GECOS/shell)",
119                 action="store_true"),
120         Option("--nis-domain", help="User's Unix/RFC2307 NIS domain", type=str),
121         Option("--unix-home", help="User's Unix/RFC2307 home directory",
122                 type=str),
123         Option("--uid", help="User's Unix/RFC2307 username", type=str),
124         Option("--uid-number", help="User's Unix/RFC2307 numeric UID", type=int),
125         Option("--gid-number", help="User's Unix/RFC2307 primary GID number", type=int),
126         Option("--gecos", help="User's Unix/RFC2307 GECOS field", type=str),
127         Option("--login-shell", help="User's Unix/RFC2307 login shell", type=str),
128     ]
129
130     takes_args = ["username", "password?"]
131
132     takes_optiongroups = {
133         "sambaopts": options.SambaOptions,
134         "credopts": options.CredentialsOptions,
135         "versionopts": options.VersionOptions,
136         }
137
138     def run(self, username, password=None, credopts=None, sambaopts=None,
139             versionopts=None, H=None, must_change_at_next_login=False,
140             random_password=False, use_username_as_cn=False, userou=None,
141             surname=None, given_name=None, initials=None, profile_path=None,
142             script_path=None, home_drive=None, home_directory=None,
143             job_title=None, department=None, company=None, description=None,
144             mail_address=None, internet_address=None, telephone_number=None,
145             physical_delivery_office=None, rfc2307_from_nss=False,
146             nis_domain=None, unix_home=None, uid=None, uid_number=None,
147             gid_number=None, gecos=None, login_shell=None,
148             smartcard_required=False):
149
150         if smartcard_required:
151             if password is not None and password is not '':
152                 raise CommandError('It is not allowed to specifiy '
153                                    '--newpassword '
154                                    'together with --smartcard-required.')
155             if must_change_at_next_login:
156                 raise CommandError('It is not allowed to specifiy '
157                                    '--must-change-at-next-login '
158                                    'together with --smartcard-required.')
159
160         if random_password and not smartcard_required:
161             password = generate_random_password(128, 255)
162
163         while True:
164             if smartcard_required:
165                 break
166             if password is not None and password is not '':
167                 break
168             password = getpass("New Password: ")
169             passwordverify = getpass("Retype Password: ")
170             if not password == passwordverify:
171                 password = None
172                 self.outf.write("Sorry, passwords do not match.\n")
173
174         if rfc2307_from_nss:
175                 pwent = pwd.getpwnam(username)
176                 if uid is None:
177                     uid = username
178                 if uid_number is None:
179                     uid_number = pwent[2]
180                 if gid_number is None:
181                     gid_number = pwent[3]
182                 if gecos is None:
183                     gecos = pwent[4]
184                 if login_shell is None:
185                     login_shell = pwent[6]
186
187         lp = sambaopts.get_loadparm()
188         creds = credopts.get_credentials(lp)
189
190         if uid_number or gid_number:
191             if not lp.get("idmap_ldb:use rfc2307"):
192                 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")
193
194         if nis_domain is not None:
195             if None in (uid_number, login_shell, unix_home, gid_number):
196                 raise CommandError('Missing parameters. To enable NIS features, '
197                                    'the following options have to be given: '
198                                    '--nis-domain=, --uidNumber=, --login-shell='
199                                    ', --unix-home=, --gid-number= Operation '
200                                    'cancelled.')
201
202         try:
203             samdb = SamDB(url=H, session_info=system_session(),
204                           credentials=creds, lp=lp)
205             samdb.newuser(username, password, force_password_change_at_next_login_req=must_change_at_next_login,
206                           useusernameascn=use_username_as_cn, userou=userou, surname=surname, givenname=given_name, initials=initials,
207                           profilepath=profile_path, homedrive=home_drive, scriptpath=script_path, homedirectory=home_directory,
208                           jobtitle=job_title, department=department, company=company, description=description,
209                           mailaddress=mail_address, internetaddress=internet_address,
210                           telephonenumber=telephone_number, physicaldeliveryoffice=physical_delivery_office,
211                           nisdomain=nis_domain, unixhome=unix_home, uid=uid,
212                           uidnumber=uid_number, gidnumber=gid_number,
213                           gecos=gecos, loginshell=login_shell,
214                           smartcard_required=smartcard_required)
215         except Exception, e:
216             raise CommandError("Failed to add user '%s': " % username, e)
217
218         self.outf.write("User '%s' created successfully\n" % username)
219
220
221 class cmd_user_add(cmd_user_create):
222     __doc__ = cmd_user_create.__doc__
223     # take this print out after the add subcommand is removed.
224     # the add subcommand is deprecated but left in for now to allow people to
225     # migrate to create
226
227     def run(self, *args, **kwargs):
228         self.outf.write(
229             "Note: samba-tool user add is deprecated.  "
230             "Please use samba-tool user create for the same function.\n")
231         return super(cmd_user_add, self).run(*args, **kwargs)
232
233
234 class cmd_user_delete(Command):
235     """Delete a user.
236
237 This command deletes a user account from the Active Directory domain.  The username specified on the command is the sAMAccountName.
238
239 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.
240
241 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.
242
243 Example1:
244 samba-tool user delete User1 -H ldap://samba.samdom.example.com --username=administrator --password=passw1rd
245
246 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.
247
248 Example2:
249 sudo samba-tool user delete User2
250
251 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.
252
253 """
254     synopsis = "%prog <username> [options]"
255
256     takes_options = [
257         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
258                metavar="URL", dest="H"),
259     ]
260
261     takes_args = ["username"]
262     takes_optiongroups = {
263         "sambaopts": options.SambaOptions,
264         "credopts": options.CredentialsOptions,
265         "versionopts": options.VersionOptions,
266         }
267
268     def run(self, username, credopts=None, sambaopts=None, versionopts=None,
269             H=None):
270         lp = sambaopts.get_loadparm()
271         creds = credopts.get_credentials(lp, fallback_machine=True)
272
273         try:
274             samdb = SamDB(url=H, session_info=system_session(),
275                           credentials=creds, lp=lp)
276             samdb.deleteuser(username)
277         except Exception, e:
278             raise CommandError('Failed to remove user "%s"' % username, e)
279         self.outf.write("Deleted user %s\n" % username)
280
281
282 class cmd_user_list(Command):
283     """List all users."""
284
285     synopsis = "%prog [options]"
286
287     takes_options = [
288         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
289                metavar="URL", dest="H"),
290         ]
291
292     takes_optiongroups = {
293         "sambaopts": options.SambaOptions,
294         "credopts": options.CredentialsOptions,
295         "versionopts": options.VersionOptions,
296         }
297
298     def run(self, sambaopts=None, credopts=None, versionopts=None, H=None):
299         lp = sambaopts.get_loadparm()
300         creds = credopts.get_credentials(lp, fallback_machine=True)
301
302         samdb = SamDB(url=H, session_info=system_session(),
303             credentials=creds, lp=lp)
304
305         domain_dn = samdb.domain_dn()
306         res = samdb.search(domain_dn, scope=ldb.SCOPE_SUBTREE,
307                     expression=("(&(objectClass=user)(userAccountControl:%s:=%u))"
308                     % (ldb.OID_COMPARATOR_AND, dsdb.UF_NORMAL_ACCOUNT)),
309                     attrs=["samaccountname"])
310         if (len(res) == 0):
311             return
312
313         for msg in res:
314             self.outf.write("%s\n" % msg.get("samaccountname", idx=0))
315
316
317 class cmd_user_enable(Command):
318     """Enable an user.
319
320 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.
321
322 There are many reasons why an account may become disabled.  These include:
323 - If a user exceeds the account policy for logon attempts
324 - If an administrator disables the account
325 - If the account expires
326
327 The samba-tool user enable command allows an administrator to enable an account which has become disabled.
328
329 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.
330
331 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.
332
333 Example1:
334 samba-tool user enable Testuser1 --URL=ldap://samba.samdom.example.com --username=administrator --password=passw1rd
335
336 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.
337
338 Example2:
339 su samba-tool user enable Testuser2
340
341 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.
342
343 Example3:
344 samba-tool user enable --filter=samaccountname=Testuser3
345
346 Example3 shows how to enable a user in the domain against a local LDAP server.  It uses the --filter=samaccountname to specify the username.
347
348 """
349     synopsis = "%prog (<username>|--filter <filter>) [options]"
350
351
352     takes_optiongroups = {
353         "sambaopts": options.SambaOptions,
354         "versionopts": options.VersionOptions,
355         "credopts": options.CredentialsOptions,
356     }
357
358     takes_options = [
359         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
360                metavar="URL", dest="H"),
361         Option("--filter", help="LDAP Filter to set password on", type=str),
362         ]
363
364     takes_args = ["username?"]
365
366     def run(self, username=None, sambaopts=None, credopts=None,
367             versionopts=None, filter=None, H=None):
368         if username is None and filter is None:
369             raise CommandError("Either the username or '--filter' must be specified!")
370
371         if filter is None:
372             filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
373
374         lp = sambaopts.get_loadparm()
375         creds = credopts.get_credentials(lp, fallback_machine=True)
376
377         samdb = SamDB(url=H, session_info=system_session(),
378             credentials=creds, lp=lp)
379         try:
380             samdb.enable_account(filter)
381         except Exception, msg:
382             raise CommandError("Failed to enable user '%s': %s" % (username or filter, msg))
383         self.outf.write("Enabled user '%s'\n" % (username or filter))
384
385
386 class cmd_user_disable(Command):
387     """Disable an user."""
388
389     synopsis = "%prog (<username>|--filter <filter>) [options]"
390
391     takes_options = [
392         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
393                metavar="URL", dest="H"),
394         Option("--filter", help="LDAP Filter to set password on", type=str),
395         ]
396
397     takes_args = ["username?"]
398
399     takes_optiongroups = {
400         "sambaopts": options.SambaOptions,
401         "credopts": options.CredentialsOptions,
402         "versionopts": options.VersionOptions,
403         }
404
405     def run(self, username=None, sambaopts=None, credopts=None,
406             versionopts=None, filter=None, H=None):
407         if username is None and filter is None:
408             raise CommandError("Either the username or '--filter' must be specified!")
409
410         if filter is None:
411             filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
412
413         lp = sambaopts.get_loadparm()
414         creds = credopts.get_credentials(lp, fallback_machine=True)
415
416         samdb = SamDB(url=H, session_info=system_session(),
417             credentials=creds, lp=lp)
418         try:
419             samdb.disable_account(filter)
420         except Exception, msg:
421             raise CommandError("Failed to disable user '%s': %s" % (username or filter, msg))
422
423
424 class cmd_user_setexpiry(Command):
425     """Set the expiration of a user account.
426
427 The user can either be specified by their sAMAccountName or using the --filter option.
428
429 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.
430
431 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.
432
433 Example1:
434 samba-tool user setexpiry User1 --days=20 --URL=ldap://samba.samdom.example.com --username=administrator --password=passw1rd
435
436 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.
437
438 Example2:
439 su samba-tool user setexpiry User2
440
441 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.
442
443 Example3:
444 samba-tool user setexpiry --days=20 --filter=samaccountname=User3
445
446 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= parameter and the username in this example is User3.
447
448 Example4:
449 samba-tool user setexpiry --noexpiry User4
450 Example4 shows how to set the account expiration so that it will never expire.  The username and sAMAccountName in this example is User4.
451
452 """
453     synopsis = "%prog (<username>|--filter <filter>) [options]"
454
455     takes_optiongroups = {
456         "sambaopts": options.SambaOptions,
457         "versionopts": options.VersionOptions,
458         "credopts": options.CredentialsOptions,
459     }
460
461     takes_options = [
462         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
463                metavar="URL", dest="H"),
464         Option("--filter", help="LDAP Filter to set password on", type=str),
465         Option("--days", help="Days to expiry", type=int, default=0),
466         Option("--noexpiry", help="Password does never expire", action="store_true", default=False),
467     ]
468
469     takes_args = ["username?"]
470
471     def run(self, username=None, sambaopts=None, credopts=None,
472             versionopts=None, H=None, filter=None, days=None, noexpiry=None):
473         if username is None and filter is None:
474             raise CommandError("Either the username or '--filter' must be specified!")
475
476         if filter is None:
477             filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
478
479         lp = sambaopts.get_loadparm()
480         creds = credopts.get_credentials(lp)
481
482         samdb = SamDB(url=H, session_info=system_session(),
483             credentials=creds, lp=lp)
484
485         try:
486             samdb.setexpiry(filter, days*24*3600, no_expiry_req=noexpiry)
487         except Exception, msg:
488             # FIXME: Catch more specific exception
489             raise CommandError("Failed to set expiry for user '%s': %s" % (
490                 username or filter, msg))
491         if noexpiry:
492             self.outf.write("Expiry for user '%s' disabled.\n" % (
493                 username or filter))
494         else:
495             self.outf.write("Expiry for user '%s' set to %u days.\n" % (
496                 username or filter, days))
497
498
499 class cmd_user_password(Command):
500     """Change password for a user account (the one provided in authentication).
501 """
502
503     synopsis = "%prog [options]"
504
505     takes_options = [
506         Option("--newpassword", help="New password", type=str),
507         ]
508
509     takes_optiongroups = {
510         "sambaopts": options.SambaOptions,
511         "credopts": options.CredentialsOptions,
512         "versionopts": options.VersionOptions,
513         }
514
515     def run(self, credopts=None, sambaopts=None, versionopts=None,
516                 newpassword=None):
517
518         lp = sambaopts.get_loadparm()
519         creds = credopts.get_credentials(lp)
520
521         # get old password now, to get the password prompts in the right order
522         old_password = creds.get_password()
523
524         net = Net(creds, lp, server=credopts.ipaddress)
525
526         password = newpassword
527         while True:
528             if password is not None and password is not '':
529                 break
530             password = getpass("New Password: ")
531             passwordverify = getpass("Retype Password: ")
532             if not password == passwordverify:
533                 password = None
534                 self.outf.write("Sorry, passwords do not match.\n")
535
536         try:
537             net.change_password(password)
538         except Exception, msg:
539             # FIXME: catch more specific exception
540             raise CommandError("Failed to change password : %s" % msg)
541         self.outf.write("Changed password OK\n")
542
543
544 class cmd_user_setpassword(Command):
545     """Set or reset the password of a user account.
546
547 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.
548
549 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.
550
551 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.
552
553 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.
554
555 Example1:
556 samba-tool user setpassword TestUser1 --newpassword=passw0rd --URL=ldap://samba.samdom.example.com -Uadministrator%passw1rd
557
558 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.
559
560 Example2:
561 sudo samba-tool user setpassword TestUser2 --newpassword=passw0rd --must-change-at-next-login
562
563 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.
564
565 Example3:
566 samba-tool user setpassword --filter=samaccountname=TestUser3 --newpassword=passw0rd
567
568 Example3 shows how an administrator would reset TestUser3 user's password to passw0rd using the --filter= option to specify the username.
569
570 """
571     synopsis = "%prog (<username>|--filter <filter>) [options]"
572
573     takes_optiongroups = {
574         "sambaopts": options.SambaOptions,
575         "versionopts": options.VersionOptions,
576         "credopts": options.CredentialsOptions,
577     }
578
579     takes_options = [
580         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
581                metavar="URL", dest="H"),
582         Option("--filter", help="LDAP Filter to set password on", type=str),
583         Option("--newpassword", help="Set password", type=str),
584         Option("--must-change-at-next-login",
585                help="Force password to be changed on next login",
586                action="store_true"),
587         Option("--random-password",
588                 help="Generate random password",
589                 action="store_true"),
590         ]
591
592     takes_args = ["username?"]
593
594     def run(self, username=None, filter=None, credopts=None, sambaopts=None,
595             versionopts=None, H=None, newpassword=None,
596             must_change_at_next_login=False, random_password=False):
597         if filter is None and username is None:
598             raise CommandError("Either the username or '--filter' must be specified!")
599
600         if random_password:
601             password = generate_random_password(128, 255)
602         else:
603             password = newpassword
604
605         while 1:
606             if password is not None and password is not '':
607                 break
608             password = getpass("New Password: ")
609
610         if filter is None:
611             filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
612
613         lp = sambaopts.get_loadparm()
614         creds = credopts.get_credentials(lp)
615
616         creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
617
618         samdb = SamDB(url=H, session_info=system_session(),
619                       credentials=creds, lp=lp)
620
621         try:
622             samdb.setpassword(filter, password,
623                               force_change_at_next_login=must_change_at_next_login,
624                               username=username)
625         except Exception, msg:
626             # FIXME: catch more specific exception
627             raise CommandError("Failed to set password for user '%s': %s" % (username or filter, msg))
628         self.outf.write("Changed password OK\n")
629
630
631 class cmd_user(SuperCommand):
632     """User management."""
633
634     subcommands = {}
635     subcommands["add"] = cmd_user_add()
636     subcommands["create"] = cmd_user_create()
637     subcommands["delete"] = cmd_user_delete()
638     subcommands["disable"] = cmd_user_disable()
639     subcommands["enable"] = cmd_user_enable()
640     subcommands["list"] = cmd_user_list()
641     subcommands["setexpiry"] = cmd_user_setexpiry()
642     subcommands["password"] = cmd_user_password()
643     subcommands["setpassword"] = cmd_user_setpassword()