463741ac05059133081c3dc96139033678a05c22
[kai/samba.git] / source3 / rpc_client / cli_netlogon.c
1 /*
2    Unix SMB/CIFS implementation.
3    NT Domain Authentication SMB / MSRPC client
4    Copyright (C) Andrew Tridgell 1992-2000
5    Copyright (C) Jeremy Allison                    1998.
6    Largely re-written by Jeremy Allison (C)        2005.
7    Copyright (C) Guenther Deschner                 2008.
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 #include "includes.h"
24 #include "rpc_client/rpc_client.h"
25 #include "../libcli/auth/libcli_auth.h"
26 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
27 #include "rpc_client/cli_netlogon.h"
28 #include "rpc_client/init_netlogon.h"
29 #include "rpc_client/util_netlogon.h"
30 #include "../libcli/security/security.h"
31
32 /****************************************************************************
33  Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
34  credentials chain. Stores the credentials in the struct dcinfo in the
35  netlogon pipe struct.
36 ****************************************************************************/
37
38 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
39                                      const char *server_name,
40                                      const char *domain,
41                                      const char *clnt_name,
42                                      const char *machine_account,
43                                      const unsigned char machine_pwd[16],
44                                      enum netr_SchannelType sec_chan_type,
45                                      uint32_t *neg_flags_inout)
46 {
47         NTSTATUS status;
48         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
49         struct netr_Credential clnt_chal_send;
50         struct netr_Credential srv_chal_recv;
51         struct samr_Password password;
52         bool retried = false;
53         fstring mach_acct;
54         uint32_t neg_flags = *neg_flags_inout;
55         struct dcerpc_binding_handle *b = cli->binding_handle;
56
57         if (!ndr_syntax_id_equal(&cli->abstract_syntax,
58                                  &ndr_table_netlogon.syntax_id)) {
59                 return NT_STATUS_INVALID_PARAMETER;
60         }
61
62         TALLOC_FREE(cli->dc);
63
64         /* Store the machine account password we're going to use. */
65         memcpy(password.hash, machine_pwd, 16);
66
67         fstr_sprintf( mach_acct, "%s$", machine_account);
68
69  again:
70         /* Create the client challenge. */
71         generate_random_buffer(clnt_chal_send.data, 8);
72
73         /* Get the server challenge. */
74         status = dcerpc_netr_ServerReqChallenge(b, talloc_tos(),
75                                                 cli->srv_name_slash,
76                                                 clnt_name,
77                                                 &clnt_chal_send,
78                                                 &srv_chal_recv,
79                                                 &result);
80         if (!NT_STATUS_IS_OK(status)) {
81                 return status;
82         }
83         if (!NT_STATUS_IS_OK(result)) {
84                 return result;
85         }
86
87         /* Calculate the session key and client credentials */
88
89         cli->dc = netlogon_creds_client_init(cli,
90                                     mach_acct,
91                                     clnt_name,
92                                     &clnt_chal_send,
93                                     &srv_chal_recv,
94                                     &password,
95                                     &clnt_chal_send,
96                                     neg_flags);
97
98         if (!cli->dc) {
99                 return NT_STATUS_NO_MEMORY;
100         }
101
102         /*
103          * Send client auth-2 challenge and receive server repy.
104          */
105
106         status = dcerpc_netr_ServerAuthenticate2(b, talloc_tos(),
107                                                  cli->srv_name_slash,
108                                                  cli->dc->account_name,
109                                                  sec_chan_type,
110                                                  cli->dc->computer_name,
111                                                  &clnt_chal_send, /* input. */
112                                                  &srv_chal_recv, /* output. */
113                                                  &neg_flags,
114                                                  &result);
115         if (!NT_STATUS_IS_OK(status)) {
116                 return status;
117         }
118         /* we might be talking to NT4, so let's downgrade in that case and retry
119          * with the returned neg_flags - gd */
120
121         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
122                 retried = true;
123                 TALLOC_FREE(cli->dc);
124                 goto again;
125         }
126
127         if (!NT_STATUS_IS_OK(result)) {
128                 return result;
129         }
130
131         /*
132          * Check the returned value using the initial
133          * server received challenge.
134          */
135
136         if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
137                 /*
138                  * Server replied with bad credential. Fail.
139                  */
140                 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
141                         "replied with bad credential\n",
142                         cli->desthost ));
143                 return NT_STATUS_ACCESS_DENIED;
144         }
145
146         DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
147                 "chain established.\n",
148                 cli->desthost ));
149
150         cli->dc->negotiate_flags = neg_flags;
151         *neg_flags_inout = neg_flags;
152
153         return NT_STATUS_OK;
154 }
155
156 /* Logon domain user */
157
158 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
159                                    TALLOC_CTX *mem_ctx,
160                                    uint32 logon_parameters,
161                                    const char *domain,
162                                    const char *username,
163                                    const char *password,
164                                    const char *workstation,
165                                    uint16_t validation_level,
166                                    int logon_type)
167 {
168         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
169         NTSTATUS status;
170         struct netr_Authenticator clnt_creds;
171         struct netr_Authenticator ret_creds;
172         union netr_LogonLevel *logon;
173         union netr_Validation validation;
174         uint8_t authoritative;
175         fstring clnt_name_slash;
176         struct dcerpc_binding_handle *b = cli->binding_handle;
177
178         ZERO_STRUCT(ret_creds);
179
180         logon = talloc_zero(mem_ctx, union netr_LogonLevel);
181         if (!logon) {
182                 return NT_STATUS_NO_MEMORY;
183         }
184
185         if (workstation) {
186                 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
187         } else {
188                 fstr_sprintf( clnt_name_slash, "\\\\%s", lp_netbios_name() );
189         }
190
191         /* Initialise input parameters */
192
193         netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
194
195         switch (logon_type) {
196         case NetlogonInteractiveInformation: {
197
198                 struct netr_PasswordInfo *password_info;
199
200                 struct samr_Password lmpassword;
201                 struct samr_Password ntpassword;
202
203                 password_info = talloc_zero(mem_ctx, struct netr_PasswordInfo);
204                 if (!password_info) {
205                         return NT_STATUS_NO_MEMORY;
206                 }
207
208                 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
209
210                 if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
211                         netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
212                         netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
213                 } else {
214                         netlogon_creds_des_encrypt(cli->dc, &lmpassword);
215                         netlogon_creds_des_encrypt(cli->dc, &ntpassword);
216                 }
217
218                 password_info->identity_info.domain_name.string         = domain;
219                 password_info->identity_info.parameter_control          = logon_parameters;
220                 password_info->identity_info.logon_id_low               = 0xdead;
221                 password_info->identity_info.logon_id_high              = 0xbeef;
222                 password_info->identity_info.account_name.string        = username;
223                 password_info->identity_info.workstation.string         = clnt_name_slash;
224
225                 password_info->lmpassword = lmpassword;
226                 password_info->ntpassword = ntpassword;
227
228                 logon->password = password_info;
229
230                 break;
231         }
232         case NetlogonNetworkInformation: {
233                 struct netr_NetworkInfo *network_info;
234                 uint8 chal[8];
235                 unsigned char local_lm_response[24];
236                 unsigned char local_nt_response[24];
237                 struct netr_ChallengeResponse lm;
238                 struct netr_ChallengeResponse nt;
239
240                 ZERO_STRUCT(lm);
241                 ZERO_STRUCT(nt);
242
243                 network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
244                 if (!network_info) {
245                         return NT_STATUS_NO_MEMORY;
246                 }
247
248                 generate_random_buffer(chal, 8);
249
250                 SMBencrypt(password, chal, local_lm_response);
251                 SMBNTencrypt(password, chal, local_nt_response);
252
253                 lm.length = 24;
254                 lm.data = local_lm_response;
255
256                 nt.length = 24;
257                 nt.data = local_nt_response;
258
259                 network_info->identity_info.domain_name.string          = domain;
260                 network_info->identity_info.parameter_control           = logon_parameters;
261                 network_info->identity_info.logon_id_low                = 0xdead;
262                 network_info->identity_info.logon_id_high               = 0xbeef;
263                 network_info->identity_info.account_name.string         = username;
264                 network_info->identity_info.workstation.string          = clnt_name_slash;
265
266                 memcpy(network_info->challenge, chal, 8);
267                 network_info->nt = nt;
268                 network_info->lm = lm;
269
270                 logon->network = network_info;
271
272                 break;
273         }
274         default:
275                 DEBUG(0, ("switch value %d not supported\n",
276                         logon_type));
277                 return NT_STATUS_INVALID_INFO_CLASS;
278         }
279
280         status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
281                                            cli->srv_name_slash,
282                                            lp_netbios_name(),
283                                            &clnt_creds,
284                                            &ret_creds,
285                                            logon_type,
286                                            logon,
287                                            validation_level,
288                                            &validation,
289                                            &authoritative,
290                                            &result);
291         if (!NT_STATUS_IS_OK(status)) {
292                 return status;
293         }
294
295         /* Always check returned credentials */
296         if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
297                 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
298                 return NT_STATUS_ACCESS_DENIED;
299         }
300
301         return result;
302 }
303
304 static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
305                                         uint16_t validation_level,
306                                         union netr_Validation *validation,
307                                         struct netr_SamInfo3 **info3_p)
308 {
309         struct netr_SamInfo3 *info3;
310         NTSTATUS status;
311
312         if (validation == NULL) {
313                 return NT_STATUS_INVALID_PARAMETER;
314         }
315
316         switch (validation_level) {
317         case 3:
318                 if (validation->sam3 == NULL) {
319                         return NT_STATUS_INVALID_PARAMETER;
320                 }
321
322                 info3 = talloc_move(mem_ctx, &validation->sam3);
323                 break;
324         case 6:
325                 if (validation->sam6 == NULL) {
326                         return NT_STATUS_INVALID_PARAMETER;
327                 }
328
329                 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
330                 if (info3 == NULL) {
331                         return NT_STATUS_NO_MEMORY;
332                 }
333                 status = copy_netr_SamBaseInfo(info3, &validation->sam6->base, &info3->base);
334                 if (!NT_STATUS_IS_OK(status)) {
335                         TALLOC_FREE(info3);
336                         return status;
337                 }
338
339                 info3->sidcount = validation->sam6->sidcount;
340                 info3->sids = talloc_move(info3, &validation->sam6->sids);
341                 break;
342         default:
343                 return NT_STATUS_BAD_VALIDATION_CLASS;
344         }
345
346         *info3_p = info3;
347
348         return NT_STATUS_OK;
349 }
350
351 /**
352  * Logon domain user with an 'network' SAM logon
353  *
354  * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
355  **/
356
357 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
358                                            TALLOC_CTX *mem_ctx,
359                                            uint32 logon_parameters,
360                                            const char *server,
361                                            const char *username,
362                                            const char *domain,
363                                            const char *workstation,
364                                            const uint8 chal[8],
365                                            uint16_t validation_level,
366                                            DATA_BLOB lm_response,
367                                            DATA_BLOB nt_response,
368                                            struct netr_SamInfo3 **info3)
369 {
370         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
371         NTSTATUS status;
372         const char *workstation_name_slash;
373         const char *server_name_slash;
374         struct netr_Authenticator clnt_creds;
375         struct netr_Authenticator ret_creds;
376         union netr_LogonLevel *logon = NULL;
377         struct netr_NetworkInfo *network_info;
378         uint8_t authoritative;
379         union netr_Validation validation;
380         struct netr_ChallengeResponse lm;
381         struct netr_ChallengeResponse nt;
382         struct dcerpc_binding_handle *b = cli->binding_handle;
383
384         *info3 = NULL;
385
386         ZERO_STRUCT(ret_creds);
387
388         ZERO_STRUCT(lm);
389         ZERO_STRUCT(nt);
390
391         logon = talloc_zero(mem_ctx, union netr_LogonLevel);
392         if (!logon) {
393                 return NT_STATUS_NO_MEMORY;
394         }
395
396         network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
397         if (!network_info) {
398                 return NT_STATUS_NO_MEMORY;
399         }
400
401         netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
402
403         if (server[0] != '\\' && server[1] != '\\') {
404                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
405         } else {
406                 server_name_slash = server;
407         }
408
409         if (workstation[0] != '\\' && workstation[1] != '\\') {
410                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
411         } else {
412                 workstation_name_slash = workstation;
413         }
414
415         if (!workstation_name_slash || !server_name_slash) {
416                 DEBUG(0, ("talloc_asprintf failed!\n"));
417                 return NT_STATUS_NO_MEMORY;
418         }
419
420         /* Initialise input parameters */
421
422         lm.data = lm_response.data;
423         lm.length = lm_response.length;
424         nt.data = nt_response.data;
425         nt.length = nt_response.length;
426
427         network_info->identity_info.domain_name.string          = domain;
428         network_info->identity_info.parameter_control           = logon_parameters;
429         network_info->identity_info.logon_id_low                = 0xdead;
430         network_info->identity_info.logon_id_high               = 0xbeef;
431         network_info->identity_info.account_name.string         = username;
432         network_info->identity_info.workstation.string          = workstation_name_slash;
433
434         memcpy(network_info->challenge, chal, 8);
435         network_info->nt = nt;
436         network_info->lm = lm;
437
438         logon->network = network_info;
439
440         /* Marshall data and send request */
441
442         status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
443                                            server_name_slash,
444                                            lp_netbios_name(),
445                                            &clnt_creds,
446                                            &ret_creds,
447                                            NetlogonNetworkInformation,
448                                            logon,
449                                            validation_level,
450                                            &validation,
451                                            &authoritative,
452                                            &result);
453         if (!NT_STATUS_IS_OK(status)) {
454                 return status;
455         }
456
457         /* Always check returned credentials. */
458         if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
459                 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
460                 return NT_STATUS_ACCESS_DENIED;
461         }
462
463         if (!NT_STATUS_IS_OK(result)) {
464                 return result;
465         }
466
467         netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
468
469         result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
470         if (!NT_STATUS_IS_OK(result)) {
471                 return result;
472         }
473
474         return result;
475 }
476
477 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
478                                               TALLOC_CTX *mem_ctx,
479                                               uint32 logon_parameters,
480                                               const char *server,
481                                               const char *username,
482                                               const char *domain,
483                                               const char *workstation,
484                                               const uint8 chal[8],
485                                               uint16_t validation_level,
486                                               DATA_BLOB lm_response,
487                                               DATA_BLOB nt_response,
488                                               struct netr_SamInfo3 **info3)
489 {
490         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
491         NTSTATUS status;
492         const char *workstation_name_slash;
493         const char *server_name_slash;
494         union netr_LogonLevel *logon = NULL;
495         struct netr_NetworkInfo *network_info;
496         uint8_t authoritative;
497         union netr_Validation validation;
498         struct netr_ChallengeResponse lm;
499         struct netr_ChallengeResponse nt;
500         uint32_t flags = 0;
501         struct dcerpc_binding_handle *b = cli->binding_handle;
502
503         *info3 = NULL;
504
505         ZERO_STRUCT(lm);
506         ZERO_STRUCT(nt);
507
508         logon = talloc_zero(mem_ctx, union netr_LogonLevel);
509         if (!logon) {
510                 return NT_STATUS_NO_MEMORY;
511         }
512
513         network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
514         if (!network_info) {
515                 return NT_STATUS_NO_MEMORY;
516         }
517
518         if (server[0] != '\\' && server[1] != '\\') {
519                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
520         } else {
521                 server_name_slash = server;
522         }
523
524         if (workstation[0] != '\\' && workstation[1] != '\\') {
525                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
526         } else {
527                 workstation_name_slash = workstation;
528         }
529
530         if (!workstation_name_slash || !server_name_slash) {
531                 DEBUG(0, ("talloc_asprintf failed!\n"));
532                 return NT_STATUS_NO_MEMORY;
533         }
534
535         /* Initialise input parameters */
536
537         lm.data = lm_response.data;
538         lm.length = lm_response.length;
539         nt.data = nt_response.data;
540         nt.length = nt_response.length;
541
542         network_info->identity_info.domain_name.string          = domain;
543         network_info->identity_info.parameter_control           = logon_parameters;
544         network_info->identity_info.logon_id_low                = 0xdead;
545         network_info->identity_info.logon_id_high               = 0xbeef;
546         network_info->identity_info.account_name.string         = username;
547         network_info->identity_info.workstation.string          = workstation_name_slash;
548
549         memcpy(network_info->challenge, chal, 8);
550         network_info->nt = nt;
551         network_info->lm = lm;
552
553         logon->network = network_info;
554
555         /* Marshall data and send request */
556
557         status = dcerpc_netr_LogonSamLogonEx(b, mem_ctx,
558                                              server_name_slash,
559                                              lp_netbios_name(),
560                                              NetlogonNetworkInformation,
561                                              logon,
562                                              validation_level,
563                                              &validation,
564                                              &authoritative,
565                                              &flags,
566                                              &result);
567         if (!NT_STATUS_IS_OK(status)) {
568                 return status;
569         }
570
571         if (!NT_STATUS_IS_OK(result)) {
572                 return result;
573         }
574
575         netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
576
577         result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
578         if (!NT_STATUS_IS_OK(result)) {
579                 return result;
580         }
581
582         return result;
583 }
584
585 /*********************************************************
586  Change the domain password on the PDC.
587
588  Just changes the password betwen the two values specified.
589
590  Caller must have the cli connected to the netlogon pipe
591  already.
592 **********************************************************/
593
594 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
595                                             TALLOC_CTX *mem_ctx,
596                                             const char *account_name,
597                                             const unsigned char orig_trust_passwd_hash[16],
598                                             const char *new_trust_pwd_cleartext,
599                                             const unsigned char new_trust_passwd_hash[16],
600                                             enum netr_SchannelType sec_channel_type)
601 {
602         NTSTATUS result, status;
603         struct netr_Authenticator clnt_creds, srv_cred;
604         struct dcerpc_binding_handle *b = cli->binding_handle;
605
606         if (!cli->dc) {
607                 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
608                 result = rpccli_netlogon_setup_creds(cli,
609                                                      cli->desthost, /* server name */
610                                                      lp_workgroup(), /* domain */
611                                                      lp_netbios_name(), /* client name */
612                                                      account_name, /* machine account name */
613                                                      orig_trust_passwd_hash,
614                                                      sec_channel_type,
615                                                      &neg_flags);
616                 if (!NT_STATUS_IS_OK(result)) {
617                         DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
618                                  nt_errstr(result)));
619                         return result;
620                 }
621         }
622
623         netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
624
625         if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
626
627                 struct netr_CryptPassword new_password;
628                 uint32_t old_timeout;
629
630                 init_netr_CryptPassword(new_trust_pwd_cleartext,
631                                         cli->dc,
632                                         &new_password);
633
634                 old_timeout = dcerpc_binding_handle_set_timeout(b, 600000);
635
636                 status = dcerpc_netr_ServerPasswordSet2(b, mem_ctx,
637                                                         cli->srv_name_slash,
638                                                         cli->dc->account_name,
639                                                         sec_channel_type,
640                                                         cli->dc->computer_name,
641                                                         &clnt_creds,
642                                                         &srv_cred,
643                                                         &new_password,
644                                                         &result);
645
646                 dcerpc_binding_handle_set_timeout(b, old_timeout);
647
648                 if (!NT_STATUS_IS_OK(status)) {
649                         DEBUG(0,("dcerpc_netr_ServerPasswordSet2 failed: %s\n",
650                                 nt_errstr(status)));
651                         return status;
652                 }
653         } else {
654
655                 struct samr_Password new_password;
656                 uint32_t old_timeout;
657
658                 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
659                 netlogon_creds_des_encrypt(cli->dc, &new_password);
660
661                 old_timeout = dcerpc_binding_handle_set_timeout(b, 600000);
662
663                 status = dcerpc_netr_ServerPasswordSet(b, mem_ctx,
664                                                        cli->srv_name_slash,
665                                                        cli->dc->account_name,
666                                                        sec_channel_type,
667                                                        cli->dc->computer_name,
668                                                        &clnt_creds,
669                                                        &srv_cred,
670                                                        &new_password,
671                                                        &result);
672
673                 dcerpc_binding_handle_set_timeout(b, old_timeout);
674
675                 if (!NT_STATUS_IS_OK(status)) {
676                         DEBUG(0,("dcerpc_netr_ServerPasswordSet failed: %s\n",
677                                 nt_errstr(status)));
678                         return status;
679                 }
680         }
681
682         /* Always check returned credentials. */
683         if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
684                 DEBUG(0,("credentials chain check failed\n"));
685                 return NT_STATUS_ACCESS_DENIED;
686         }
687
688         if (!NT_STATUS_IS_OK(result)) {
689                 DEBUG(0,("dcerpc_netr_ServerPasswordSet{2} failed: %s\n",
690                         nt_errstr(result)));
691                 return result;
692         }
693
694         return result;
695 }
696