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