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