s4:samba-tool - fix Gémes Géza patch regarding parameter handling
[bbaumbach/samba-autobuild/.git] / source4 / scripting / python / samba / netcmd / user.py
1 #!/usr/bin/env python
2 #
3 # user management
4 #
5 # Copyright Jelmer Vernooij 2010 <jelmer@samba.org>
6 # Copyright Theresa Halloran 2011 <theresahalloran@gmail.com>
7 # Copyright Giampaolo Lauria 2011 <lauria2@yahoo.com>
8 #
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 #
22
23 import samba.getopt as options
24 import sys, ldb
25 from getpass import getpass
26 from samba.auth import system_session
27 from samba.samdb import SamDB
28 from samba import gensec, generate_random_password
29 from samba.net import Net
30
31 from samba.netcmd import (
32     Command,
33     CommandError,
34     SuperCommand,
35     Option,
36     )
37
38
39 class cmd_user_create(Command):
40     """Creates a new user
41
42 This command creates a new user account in the Active Directory domain.  The username specified on the command is the sAMaccountName.
43
44 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).
45
46 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.
47
48 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.
49
50 Example1:
51 samba-tool user add User1 passw0rd --given-name=John --surname=Smith --must-change-at-next-login -H ldap://samba.samdom.example.com -Uadministrator%passw1rd
52
53 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.
54
55 Example2:
56 sudo samba-tool user add User2 passw2rd --given-name=Jane --surname=Doe --must-change-at-next-login
57
58 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.
59
60 Example3:
61 samba-tool user add User3 passw3rd --userou=OrgUnit
62
63 Example3 shows how to create a new user in the OrgUnit organizational unit.
64
65 """
66     synopsis = "%prog <username> [<password>] [options]"
67
68     takes_options = [
69         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
70                 metavar="URL", dest="H"),
71         Option("--must-change-at-next-login",
72                 help="Force password to be changed on next login",
73                 action="store_true"),
74         Option("--random-password",
75                 help="Generate random password",
76                 action="store_true"),
77         Option("--use-username-as-cn",
78                 help="Force use of username as user's CN",
79                 action="store_true"),
80         Option("--userou",
81                 help="Alternative location (without domainDN counterpart) to default CN=Users in which new user object will be created",
82                 type=str),
83         Option("--surname", help="User's surname", type=str),
84         Option("--given-name", help="User's given name", type=str),
85         Option("--initials", help="User's initials", type=str),
86         Option("--profile-path", help="User's profile path", type=str),
87         Option("--script-path", help="User's logon script path", type=str),
88         Option("--home-drive", help="User's home drive letter", type=str),
89         Option("--home-directory", help="User's home directory path", type=str),
90         Option("--job-title", help="User's job title", type=str),
91         Option("--department", help="User's department", type=str),
92         Option("--company", help="User's company", type=str),
93         Option("--description", help="User's description", type=str),
94         Option("--mail-address", help="User's email address", type=str),
95         Option("--internet-address", help="User's home page", type=str),
96         Option("--telephone-number", help="User's phone number", type=str),
97         Option("--physical-delivery-office", help="User's office location", type=str),
98     ]
99
100     takes_args = ["username", "password?"]
101
102     def run(self, username, password=None, credopts=None, sambaopts=None,
103             versionopts=None, H=None, must_change_at_next_login=None, random_password=None,
104             use_username_as_cn=None, userou=None, surname=None, given_name=None, initials=None,
105             profile_path=None, script_path=None, home_drive=None, home_directory=None,
106             job_title=None, department=None, company=None, description=None,
107             mail_address=None, internet_address=None, telephone_number=None, physical_delivery_office=None):
108
109         if random_password is True:
110             password = generate_random_password(128, 255)
111
112         while 1:
113             if password is not None and password is not '':
114                 break
115             password = getpass("New Password: ")
116
117         lp = sambaopts.get_loadparm()
118         creds = credopts.get_credentials(lp)
119
120         try:
121             samdb = SamDB(url=H, session_info=system_session(),
122                           credentials=creds, lp=lp)
123             samdb.newuser(username, password,
124                           force_password_change_at_next_login_req=must_change_at_next_login,
125                           useusernameascn=use_username_as_cn, userou=userou, surname=surname, givenname=given_name, initials=initials,
126                           profilepath=profile_path, homedrive=home_drive, scriptpath=script_path, homedirectory=home_directory,
127                           jobtitle=job_title, department=department, company=company, description=description,
128                           mailaddress=mail_address, internetaddress=internet_address,
129                           telephonenumber=telephone_number, physicaldeliveryoffice=physical_delivery_office)
130         except Exception, e:
131             raise CommandError("Failed to add user '%s': " % username, e)
132
133         self.outf.write("User '%s' created successfully\n" % username)
134
135
136 class cmd_user_add(cmd_user_create):
137     __doc__ = cmd_user_create.__doc__
138     # take this print out after the add subcommand is removed.
139     # the add subcommand is deprecated but left in for now to allow people to migrate to create
140
141     def run(self, *args, **kwargs):
142         self.err.write("\nNote: samba-tool user add is deprecated.  Please use samba-tool user create for the same function.\n")
143         return super(self, cmd_user_add).run(*args, **kwargs)
144
145
146 class cmd_user_delete(Command):
147     """Deletes a user
148
149 This command deletes a user account from the Active Directory domain.  The username specified on the command is the sAMAccountName.
150
151 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.
152
153 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.
154
155 Example1:
156 samba-tool user delete User1 -H ldap://samba.samdom.example.com --username=administrator --password=passw1rd
157
158 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.
159
160 Example2:
161 sudo samba-tool user delete User2
162
163 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.
164
165 """
166     synopsis = "%prog <username> [options]"
167
168     takes_options = [
169         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
170                metavar="URL", dest="H"),
171     ]
172
173     takes_args = ["username"]
174
175     def run(self, username, credopts=None, sambaopts=None, versionopts=None, H=None):
176
177         lp = sambaopts.get_loadparm()
178         creds = credopts.get_credentials(lp, fallback_machine=True)
179
180         try:
181             samdb = SamDB(url=H, session_info=system_session(),
182                           credentials=creds, lp=lp)
183             samdb.deleteuser(username)
184         except Exception, e:
185             raise CommandError('Failed to remove user "%s"' % username, e)
186         self.outf.write("Deleted user %s\n" % username)
187
188
189 class cmd_user_enable(Command):
190     """Enables a user
191
192 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.
193
194 There are many reasons why an account may become disabled.  These include:
195 - If a user exceeds the account policy for logon attempts
196 - If an administrator disables the account
197 - If the account expires
198
199 The samba-tool user enable command allows an administrator to enable an account which has become disabled.
200
201 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.
202
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.
204
205 Example1:
206 samba-tool user enable Testuser1 --URL=ldap://samba.samdom.example.com --username=administrator --password=passw1rd
207
208 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.
209
210 Exampl2:
211 su samba-tool user enable Testuser2
212
213 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.
214
215 Example3:
216 samba-tool user enable --filter=samaccountname=Testuser3
217
218 Example3 shows how to enable a user in the domain against a local LDAP server.  It uses the --filter=samaccountname to specify the username.
219
220 """
221     synopsis = "%prog (<username>|--filter <filter>) [options]"
222
223     takes_options = [
224         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
225                metavar="URL", dest="H"),
226         Option("--filter", help="LDAP Filter to set password on", type=str),
227         ]
228
229     takes_args = ["username?"]
230
231     def run(self, username=None, sambaopts=None, credopts=None,
232             versionopts=None, filter=None, H=None):
233         if username is None and filter is None:
234             raise CommandError("Either the username or '--filter' must be specified!")
235
236         if filter is None:
237             filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
238
239         lp = sambaopts.get_loadparm()
240         creds = credopts.get_credentials(lp, fallback_machine=True)
241
242         samdb = SamDB(url=H, session_info=system_session(),
243             credentials=creds, lp=lp)
244         try:
245             samdb.enable_account(filter)
246         except Exception, msg:
247             raise CommandError("Failed to enable user '%s': %s" % (username or filter, msg))
248         self.outf.write("Enabled user '%s'\n" % (username or filter))
249
250
251 class cmd_user_setexpiry(Command):
252     """Sets the expiration of a user account
253
254 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.
255
256 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.
257
258 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.
259
260 Example1:
261 samba-tool user setexpiry User1 --days=20 --URL=ldap://samba.samdom.example.com --username=administrator --password=passw1rd
262
263 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.
264
265 Exampl2:
266 su samba-tool user setexpiry User2
267
268 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.
269
270 Example3:
271 samba-tool user setexpiry --days=20 --filter=samaccountname=User3
272
273 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.
274
275 Example4:
276 samba-tool user setexpiry --noexpiry User4
277 Example4 shows how to set the account expiration so that it will never expire.  The username and sAMAccountName in this example is User4.
278
279 """
280     synopsis = "%prog (<username>|--filter <filter>) [options]"
281
282     takes_options = [
283         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
284                metavar="URL", dest="H"),
285         Option("--filter", help="LDAP Filter to set password on", type=str),
286         Option("--days", help="Days to expiry", type=int, default=0),
287         Option("--noexpiry", help="Password does never expire", action="store_true", default=False),
288     ]
289
290     takes_args = ["username?"]
291
292     def run(self, username=None, sambaopts=None, credopts=None,
293             versionopts=None, H=None, filter=None, days=None, noexpiry=None):
294         if username is None and filter is None:
295             raise CommandError("Either the username or '--filter' must be specified!")
296
297         if filter is None:
298             filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
299
300         lp = sambaopts.get_loadparm()
301         creds = credopts.get_credentials(lp)
302
303         samdb = SamDB(url=H, session_info=system_session(),
304             credentials=creds, lp=lp)
305
306         try:
307             samdb.setexpiry(filter, days*24*3600, no_expiry_req=noexpiry)
308         except Exception, msg:
309             # FIXME: Catch more specific exception
310             raise CommandError("Failed to set expiry for user '%s': %s" % (
311                 username or filter, msg))
312         self.outf.write("Set expiry for user '%s' to %u days\n" % (
313             username or filter, days))
314
315
316 class cmd_user_password(Command):
317     """Change password for a user account (the one provided in authentication)
318
319
320
321 """
322
323     synopsis = "%prog [options]"
324
325     takes_options = [
326         Option("--newpassword", help="New password", type=str),
327         ]
328
329     def run(self, credopts=None, sambaopts=None, versionopts=None,
330                 newpassword=None):
331
332         lp = sambaopts.get_loadparm()
333         creds = credopts.get_credentials(lp)
334
335         # get old password now, to get the password prompts in the right order
336         old_password = creds.get_password()
337
338         net = Net(creds, lp, server=credopts.ipaddress)
339
340         password = newpassword
341         while 1:
342             if password is not None and password is not '':
343                 break
344             password = getpass("New Password: ")
345
346         try:
347             net.change_password(password)
348         except Exception, msg:
349             # FIXME: catch more specific exception
350             raise CommandError("Failed to change password : %s" % msg)
351         self.outf.write("Changed password OK\n")
352
353
354 class cmd_user_setpassword(Command):
355     """Sets or resets the password of a user account
356
357 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.
358
359 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.
360
361 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.
362
363 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.
364
365 Example1:
366 samba-tool user setpassword TestUser1 passw0rd --URL=ldap://samba.samdom.example.com -Uadministrator%passw1rd
367
368 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.
369
370 Example2:
371 sudo samba-tool user setpassword TestUser2 passw0rd --must-change-at-next-login
372
373 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.
374
375 Example3:
376 samba-tool user setpassword --filter=samaccountname=TestUser3 --password=passw0rd
377
378 Example3 shows how an administrator would reset TestUser3 user's password to passw0rd using the --filter= option to specify the username.
379
380 """
381     synopsis = "%prog (<username>|--filter <filter>) [options]"
382
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("--newpassword", help="Set password", type=str),
388         Option("--must-change-at-next-login",
389                help="Force password to be changed on next login",
390                action="store_true"),
391         Option("--random-password",
392                 help="Generate random password",
393                 action="store_true"),
394         ]
395
396     takes_args = ["username?"]
397
398     def run(self, username=None, filter=None, credopts=None, sambaopts=None,
399             versionopts=None, H=None, newpassword=None,
400             must_change_at_next_login=None, random_password=None):
401         if filter is None and username is None:
402             raise CommandError("Either the username or '--filter' must be specified!")
403
404         if random_password is True:
405             password = generate_random_password(128, 255)
406         else:
407             password = newpassword
408
409         while 1:
410             if password is not None and password is not '':
411                 break
412             password = getpass("New Password: ")
413
414         if filter is None:
415             filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
416
417         lp = sambaopts.get_loadparm()
418         creds = credopts.get_credentials(lp)
419
420         creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
421
422         samdb = SamDB(url=H, session_info=system_session(),
423                       credentials=creds, lp=lp)
424
425         try:
426             samdb.setpassword(filter, password,
427                               force_change_at_next_login=must_change_at_next_login,
428                               username=username)
429         except Exception, msg:
430             # FIXME: catch more specific exception
431             raise CommandError("Failed to set password for user '%s': %s" % (username or filter, msg))
432         self.outf.write("Changed password OK\n")
433
434
435 class cmd_user(SuperCommand):
436     """User management"""
437
438     subcommands = {}
439     subcommands["add"] = cmd_user_create()
440     subcommands["create"] = cmd_user_create()
441     subcommands["delete"] = cmd_user_delete()
442     subcommands["enable"] = cmd_user_enable()
443     subcommands["setexpiry"] = cmd_user_setexpiry()
444     subcommands["password"] = cmd_user_password()
445     subcommands["setpassword"] = cmd_user_setpassword()