r14570: Move some functions also they are also used from kpasswd
[samba.git] / source4 / rpc_server / samr / samr_password.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    samr server password set/change handling
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "rpc_server/dcerpc_server.h"
26 #include "rpc_server/common/common.h"
27 #include "rpc_server/samr/dcesrv_samr.h"
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "system/time.h"
30 #include "lib/crypto/crypto.h"
31 #include "ads.h"
32 #include "libcli/ldap/ldap.h"
33 #include "dsdb/samdb/samdb.h"
34 #include "auth/auth.h"
35 #include "rpc_server/samr/proto.h"
36 #include "libcli/auth/libcli_auth.h"
37 #include "db_wrap.h"
38
39 /* 
40   samr_ChangePasswordUser 
41 */
42 NTSTATUS samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
43                                  struct samr_ChangePasswordUser *r)
44 {
45         struct dcesrv_handle *h;
46         struct samr_account_state *a_state;
47         struct ldb_context *sam_ctx;
48         struct ldb_message **res, *msg;
49         int ret;
50         struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
51         struct samr_Password *lm_pwd, *nt_pwd;
52         NTSTATUS status = NT_STATUS_OK;
53         const char * const attrs[] = { "lmPwdHash", "ntPwdHash" , NULL };
54
55         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
56
57         a_state = h->data;
58
59         /* basic sanity checking on parameters.  Do this before any database ops */
60         if (!r->in.lm_present || !r->in.nt_present ||
61             !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
62             !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
63                 /* we should really handle a change with lm not
64                    present */
65                 return NT_STATUS_INVALID_PARAMETER_MIX;
66         }
67         if (!r->in.cross1_present || !r->in.nt_cross) {
68                 return NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED;
69         }
70         if (!r->in.cross2_present || !r->in.lm_cross) {
71                 return NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED;
72         }
73
74         /* To change a password we need to open as system */
75         sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
76         if (sam_ctx == NULL) {
77                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
78         }
79
80         ret = ldb_transaction_start(sam_ctx);
81         if (ret) {
82                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
83                 return NT_STATUS_TRANSACTION_ABORTED;
84         }
85
86         /* fetch the old hashes */
87         ret = gendb_search_dn(sam_ctx, mem_ctx,
88                               a_state->account_dn, &res, attrs);
89         if (ret != 1) {
90                 ldb_transaction_cancel(sam_ctx);
91                 return NT_STATUS_WRONG_PASSWORD;
92         }
93         msg = res[0];
94
95         status = samdb_result_passwords(mem_ctx, msg, &lm_pwd, &nt_pwd);
96         if (!NT_STATUS_IS_OK(status) || !lm_pwd || !nt_pwd) {
97                 ldb_transaction_cancel(sam_ctx);
98                 return NT_STATUS_WRONG_PASSWORD;
99         }
100
101         /* decrypt and check the new lm hash */
102         D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
103         D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
104         if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
105                 ldb_transaction_cancel(sam_ctx);
106                 return NT_STATUS_WRONG_PASSWORD;
107         }
108
109         /* decrypt and check the new nt hash */
110         D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
111         D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
112         if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
113                 ldb_transaction_cancel(sam_ctx);
114                 return NT_STATUS_WRONG_PASSWORD;
115         }
116         
117         /* check the nt cross hash */
118         D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
119         if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
120                 ldb_transaction_cancel(sam_ctx);
121                 return NT_STATUS_WRONG_PASSWORD;
122         }
123
124         /* check the lm cross hash */
125         D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
126         if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
127                 ldb_transaction_cancel(sam_ctx);
128                 return NT_STATUS_WRONG_PASSWORD;
129         }
130
131         msg = ldb_msg_new(mem_ctx);
132         if (msg == NULL) {
133                 ldb_transaction_cancel(sam_ctx);
134                 return NT_STATUS_NO_MEMORY;
135         }
136
137         msg->dn = ldb_dn_copy(msg, a_state->account_dn);
138         if (!msg->dn) {
139                 ldb_transaction_cancel(sam_ctx);
140                 return NT_STATUS_NO_MEMORY;
141         }
142
143         /* set the password on the user DN specified.  This may fail
144          * due to password policies */
145         status = samdb_set_password(sam_ctx, mem_ctx,
146                                     a_state->account_dn, a_state->domain_state->domain_dn,
147                                     msg, NULL, &new_lmPwdHash, &new_ntPwdHash, 
148                                     True, /* this is a user password change */
149                                     True, /* run restriction tests */
150                                     NULL,
151                                     NULL);
152         if (!NT_STATUS_IS_OK(status)) {
153                 ldb_transaction_cancel(sam_ctx);
154                 return status;
155         }
156
157         /* The above call only setup the modifications, this actually
158          * makes the write to the database. */
159         ret = samdb_replace(sam_ctx, mem_ctx, msg);
160         if (ret != 0) {
161                 DEBUG(2,("Failed to modify record to change password on %s: %s\n",
162                          ldb_dn_linearize(mem_ctx, a_state->account_dn),
163                          ldb_errstring(sam_ctx)));
164                 ldb_transaction_cancel(sam_ctx);
165                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
166         }
167
168         /* And this confirms it in a transaction commit */
169         ret = ldb_transaction_commit(sam_ctx);
170         if (ret != 0) {
171                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
172                          ldb_dn_linearize(mem_ctx, a_state->account_dn),
173                          ldb_errstring(sam_ctx)));
174                 return NT_STATUS_TRANSACTION_ABORTED;
175         }
176
177         return NT_STATUS_OK;
178 }
179
180 /* 
181   samr_OemChangePasswordUser2 
182 */
183 NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
184                                      struct samr_OemChangePasswordUser2 *r)
185 {
186         NTSTATUS status;
187         char new_pass[512];
188         uint32_t new_pass_len;
189         struct samr_CryptPassword *pwbuf = r->in.password;
190         struct ldb_context *sam_ctx;
191         const struct ldb_dn *user_dn;
192         int ret;
193         struct ldb_message **res, *mod;
194         const char * const attrs[] = { "objectSid", "lmPwdHash", NULL };
195         struct samr_Password *lm_pwd;
196         DATA_BLOB lm_pwd_blob;
197         uint8_t new_lm_hash[16];
198         struct samr_Password lm_verifier;
199
200         if (pwbuf == NULL) {
201                 return NT_STATUS_WRONG_PASSWORD;
202         }
203
204         /* To change a password we need to open as system */
205         sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
206         if (sam_ctx == NULL) {
207                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
208         }
209
210         ret = ldb_transaction_start(sam_ctx);
211         if (ret) {
212                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
213                 return NT_STATUS_TRANSACTION_ABORTED;
214         }
215
216         /* we need the users dn and the domain dn (derived from the
217            user SID). We also need the current lm password hash in
218            order to decrypt the incoming password */
219         ret = gendb_search(sam_ctx, 
220                            mem_ctx, NULL, &res, attrs,
221                            "(&(sAMAccountName=%s)(objectclass=user))",
222                            r->in.account->string);
223         if (ret != 1) {
224                 ldb_transaction_cancel(sam_ctx);
225                 /* Don't give the game away:  (don't allow anonymous users to prove the existance of usernames) */
226                 return NT_STATUS_WRONG_PASSWORD;
227         }
228
229         user_dn = res[0]->dn;
230
231         status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, NULL);
232         if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
233                 ldb_transaction_cancel(sam_ctx);
234                 return NT_STATUS_WRONG_PASSWORD;
235         }
236
237         /* decrypt the password we have been given */
238         lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash)); 
239         arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
240         data_blob_free(&lm_pwd_blob);
241         
242         if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
243                               &new_pass_len, STR_ASCII)) {
244                 ldb_transaction_cancel(sam_ctx);
245                 DEBUG(3,("samr: failed to decode password buffer\n"));
246                 return NT_STATUS_WRONG_PASSWORD;
247         }
248
249         /* check LM verifier */
250         if (lm_pwd == NULL || r->in.hash == NULL) {
251                 ldb_transaction_cancel(sam_ctx);
252                 return NT_STATUS_WRONG_PASSWORD;
253         }
254
255         E_deshash(new_pass, new_lm_hash);
256         E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
257         if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
258                 ldb_transaction_cancel(sam_ctx);
259                 return NT_STATUS_WRONG_PASSWORD;
260         }
261
262         mod = ldb_msg_new(mem_ctx);
263         if (mod == NULL) {
264                 ldb_transaction_cancel(sam_ctx);
265                 return NT_STATUS_NO_MEMORY;
266         }
267
268         mod->dn = ldb_dn_copy(mod, user_dn);
269         if (!mod->dn) {
270                 ldb_transaction_cancel(sam_ctx);
271                 return NT_STATUS_NO_MEMORY;
272         }
273
274         /* set the password on the user DN specified.  This may fail
275          * due to password policies */
276         status = samdb_set_password(sam_ctx, mem_ctx,
277                                     user_dn, NULL, 
278                                     mod, new_pass, 
279                                     NULL, NULL,
280                                     True, /* this is a user password change */
281                                     True, /* run restriction tests */
282                                     NULL, 
283                                     NULL);
284         if (!NT_STATUS_IS_OK(status)) {
285                 ldb_transaction_cancel(sam_ctx);
286                 return status;
287         }
288
289         /* The above call only setup the modifications, this actually
290          * makes the write to the database. */
291         ret = samdb_replace(sam_ctx, mem_ctx, mod);
292         if (ret != 0) {
293                 DEBUG(2,("Failed to modify record to change password on %s: %s\n",
294                          ldb_dn_linearize(mem_ctx, user_dn),
295                          ldb_errstring(sam_ctx)));
296                 ldb_transaction_cancel(sam_ctx);
297                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
298         }
299
300         /* And this confirms it in a transaction commit */
301         ret = ldb_transaction_commit(sam_ctx);
302         if (ret != 0) {
303                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
304                          ldb_dn_linearize(mem_ctx, user_dn),
305                          ldb_errstring(sam_ctx)));
306                 return NT_STATUS_TRANSACTION_ABORTED;
307         }
308
309         return NT_STATUS_OK;
310 }
311
312
313 /* 
314   samr_ChangePasswordUser3 
315 */
316 NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, 
317                                   TALLOC_CTX *mem_ctx,
318                                   struct samr_ChangePasswordUser3 *r)
319 {       
320         NTSTATUS status;
321         char new_pass[512];
322         uint32_t new_pass_len;
323         struct ldb_context *sam_ctx = NULL;
324         const struct ldb_dn *user_dn;
325         int ret;
326         struct ldb_message **res, *mod;
327         const char * const attrs[] = { "ntPwdHash", "lmPwdHash", NULL };
328         struct samr_Password *nt_pwd, *lm_pwd;
329         DATA_BLOB nt_pwd_blob;
330         struct samr_DomInfo1 *dominfo = NULL;
331         struct samr_ChangeReject *reject = NULL;
332         enum samr_RejectReason reason = SAMR_REJECT_OTHER;
333         uint8_t new_nt_hash[16], new_lm_hash[16];
334         struct samr_Password nt_verifier, lm_verifier;
335
336         ZERO_STRUCT(r->out);
337
338         if (r->in.nt_password == NULL ||
339             r->in.nt_verifier == NULL) {
340                 return NT_STATUS_INVALID_PARAMETER;
341         }
342
343         /* To change a password we need to open as system */
344         sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
345         if (sam_ctx == NULL) {
346                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
347         }
348
349         ret = ldb_transaction_start(sam_ctx);
350         if (ret) {
351                 talloc_free(sam_ctx);
352                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
353                 return NT_STATUS_TRANSACTION_ABORTED;
354         }
355
356         /* we need the users dn and the domain dn (derived from the
357            user SID). We also need the current lm and nt password hashes
358            in order to decrypt the incoming passwords */
359         ret = gendb_search(sam_ctx, 
360                            mem_ctx, NULL, &res, attrs,
361                            "(&(sAMAccountName=%s)(objectclass=user))",
362                            r->in.account->string);
363         if (ret != 1) {
364                 /* Don't give the game away:  (don't allow anonymous users to prove the existance of usernames) */
365                 status = NT_STATUS_WRONG_PASSWORD;
366                 goto failed;
367         }
368
369         user_dn = res[0]->dn;
370
371         status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, &nt_pwd);
372         if (!NT_STATUS_IS_OK(status) ) {
373                 goto failed;
374         }
375
376         if (!nt_pwd) {
377                 status = NT_STATUS_WRONG_PASSWORD;
378                 goto failed;
379         }
380
381         /* decrypt the password we have been given */
382         nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
383         arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
384         data_blob_free(&nt_pwd_blob);
385
386         if (!decode_pw_buffer(r->in.nt_password->data, new_pass, sizeof(new_pass),
387                               &new_pass_len, STR_UNICODE)) {
388                 DEBUG(3,("samr: failed to decode password buffer\n"));
389                 status = NT_STATUS_WRONG_PASSWORD;
390                 goto failed;
391         }
392
393         if (r->in.nt_verifier == NULL) {
394                 status = NT_STATUS_WRONG_PASSWORD;
395                 goto failed;
396         }
397
398         /* check NT verifier */
399         E_md4hash(new_pass, new_nt_hash);
400         E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
401         if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
402                 status = NT_STATUS_WRONG_PASSWORD;
403                 goto failed;
404         }
405
406         /* check LM verifier */
407         if (lm_pwd && r->in.lm_verifier != NULL) {
408                 E_deshash(new_pass, new_lm_hash);
409                 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
410                 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
411                         status = NT_STATUS_WRONG_PASSWORD;
412                         goto failed;
413                 }
414         }
415
416
417         mod = ldb_msg_new(mem_ctx);
418         if (mod == NULL) {
419                 return NT_STATUS_NO_MEMORY;
420         }
421
422         mod->dn = ldb_dn_copy(mod, user_dn);
423         if (!mod->dn) {
424                 status = NT_STATUS_NO_MEMORY;
425                 goto failed;
426         }
427
428         /* set the password on the user DN specified.  This may fail
429          * due to password policies */
430         status = samdb_set_password(sam_ctx, mem_ctx,
431                                     user_dn, NULL, 
432                                     mod, new_pass, 
433                                     NULL, NULL,
434                                     True, /* this is a user password change */
435                                     True, /* run restriction tests */
436                                     &reason, 
437                                     &dominfo);
438         if (!NT_STATUS_IS_OK(status)) {
439                 goto failed;
440         }
441
442         /* The above call only setup the modifications, this actually
443          * makes the write to the database. */
444         ret = samdb_replace(sam_ctx, mem_ctx, mod);
445         if (ret != 0) {
446                 DEBUG(2,("samdb_replace failed to change password for %s: %s\n",
447                          ldb_dn_linearize(mem_ctx, user_dn),
448                          ldb_errstring(sam_ctx)));
449                 status = NT_STATUS_UNSUCCESSFUL;
450                 goto failed;
451         }
452
453         /* And this confirms it in a transaction commit */
454         ret = ldb_transaction_commit(sam_ctx);
455         if (ret != 0) {
456                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
457                          ldb_dn_linearize(mem_ctx, user_dn),
458                          ldb_errstring(sam_ctx)));
459                 status = NT_STATUS_TRANSACTION_ABORTED;
460                 goto failed;
461         }
462
463         return NT_STATUS_OK;
464
465 failed:
466         ldb_transaction_cancel(sam_ctx);
467         talloc_free(sam_ctx);
468
469         reject = talloc(mem_ctx, struct samr_ChangeReject);
470         r->out.dominfo = dominfo;
471         r->out.reject = reject;
472
473         if (reject == NULL) {
474                 return status;
475         }
476         ZERO_STRUCTP(reject);
477
478         reject->reason = reason;
479
480         return status;
481 }
482
483
484 /* 
485   samr_ChangePasswordUser2 
486
487   easy - just a subset of samr_ChangePasswordUser3
488 */
489 NTSTATUS samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
490                                   struct samr_ChangePasswordUser2 *r)
491 {
492         struct samr_ChangePasswordUser3 r2;
493
494         r2.in.server = r->in.server;
495         r2.in.account = r->in.account;
496         r2.in.nt_password = r->in.nt_password;
497         r2.in.nt_verifier = r->in.nt_verifier;
498         r2.in.lm_change = r->in.lm_change;
499         r2.in.lm_password = r->in.lm_password;
500         r2.in.lm_verifier = r->in.lm_verifier;
501         r2.in.password3 = NULL;
502
503         return samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
504 }
505
506
507 /*
508   set password via a samr_CryptPassword buffer
509   this will in the 'msg' with modify operations that will update the user
510   password when applied
511 */
512 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
513                            void *sam_ctx,
514                            const struct ldb_dn *account_dn, const struct ldb_dn *domain_dn,
515                            TALLOC_CTX *mem_ctx,
516                            struct ldb_message *msg, 
517                            struct samr_CryptPassword *pwbuf)
518 {
519         NTSTATUS nt_status;
520         char new_pass[512];
521         uint32_t new_pass_len;
522         DATA_BLOB session_key = data_blob(NULL, 0);
523
524         nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
525         if (!NT_STATUS_IS_OK(nt_status)) {
526                 return nt_status;
527         }
528
529         arcfour_crypt_blob(pwbuf->data, 516, &session_key);
530
531         if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
532                               &new_pass_len, STR_UNICODE)) {
533                 DEBUG(3,("samr: failed to decode password buffer\n"));
534                 return NT_STATUS_WRONG_PASSWORD;
535         }
536
537         /* set the password - samdb needs to know both the domain and user DNs,
538            so the domain password policy can be used */
539         return samdb_set_password(sam_ctx, mem_ctx,
540                                   account_dn, domain_dn, 
541                                   msg, new_pass, 
542                                   NULL, NULL,
543                                   False, /* This is a password set, not change */
544                                   True, /* run restriction tests */
545                                   NULL, NULL);
546 }
547
548
549 /*
550   set password via a samr_CryptPasswordEx buffer
551   this will in the 'msg' with modify operations that will update the user
552   password when applied
553 */
554 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
555                               struct ldb_context *sam_ctx,
556                               const struct ldb_dn *account_dn, const struct ldb_dn *domain_dn,
557                               TALLOC_CTX *mem_ctx,
558                               struct ldb_message *msg, 
559                               struct samr_CryptPasswordEx *pwbuf)
560 {
561         NTSTATUS nt_status;
562         char new_pass[512];
563         uint32_t new_pass_len;
564         DATA_BLOB co_session_key;
565         DATA_BLOB session_key = data_blob(NULL, 0);
566         struct MD5Context ctx;
567
568         nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
569         if (!NT_STATUS_IS_OK(nt_status)) {
570                 return nt_status;
571         }
572
573         co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
574         if (!co_session_key.data) {
575                 return NT_STATUS_NO_MEMORY;
576         }
577
578         MD5Init(&ctx);
579         MD5Update(&ctx, &pwbuf->data[516], 16);
580         MD5Update(&ctx, session_key.data, session_key.length);
581         MD5Final(co_session_key.data, &ctx);
582         
583         arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
584
585         if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
586                               &new_pass_len, STR_UNICODE)) {
587                 DEBUG(3,("samr: failed to decode password buffer\n"));
588                 return NT_STATUS_WRONG_PASSWORD;
589         }
590
591         /* set the password - samdb needs to know both the domain and user DNs,
592            so the domain password policy can be used */
593         return samdb_set_password(sam_ctx, mem_ctx,
594                                   account_dn, domain_dn, 
595                                   msg, new_pass, 
596                                   NULL, NULL,
597                                   False, /* This is a password set, not change */
598                                   True, /* run restriction tests */
599                                   NULL, NULL);
600 }
601
602