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