Refactoring: Make struct rpc_pipe_client its own talloc parent
[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
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(cli->pipe_idx == PI_NETLOGON);
138
139         dc = cli->dc;
140         if (!dc) {
141                 return NT_STATUS_INVALID_PARAMETER;
142         }
143
144         /* Ensure we don't reuse any of this state. */
145         ZERO_STRUCTP(dc);
146
147         /* Store the machine account password we're going to use. */
148         memcpy(dc->mach_pw, machine_pwd, 16);
149
150         fstrcpy(dc->remote_machine, "\\\\");
151         fstrcat(dc->remote_machine, server_name);
152
153         fstrcpy(dc->domain, domain);
154
155         fstr_sprintf( dc->mach_acct, "%s$", machine_account);
156
157  again:
158         /* Create the client challenge. */
159         generate_random_buffer(clnt_chal_send.data, 8);
160
161         /* Get the server challenge. */
162         result = rpccli_netr_ServerReqChallenge(cli, talloc_tos(),
163                                                 dc->remote_machine,
164                                                 clnt_name,
165                                                 &clnt_chal_send,
166                                                 &srv_chal_recv);
167         if (!NT_STATUS_IS_OK(result)) {
168                 return result;
169         }
170
171         /* Calculate the session key and client credentials */
172         creds_client_init(*neg_flags_inout,
173                         dc,
174                         &clnt_chal_send,
175                         &srv_chal_recv,
176                         machine_pwd,
177                         &clnt_chal_send);
178
179         /*
180          * Send client auth-2 challenge and receive server repy.
181          */
182
183         result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
184                                                  dc->remote_machine,
185                                                  dc->mach_acct,
186                                                  sec_chan_type,
187                                                  clnt_name,
188                                                  &clnt_chal_send, /* input. */
189                                                  &srv_chal_recv, /* output. */
190                                                  neg_flags_inout);
191
192         /* we might be talking to NT4, so let's downgrade in that case and retry
193          * with the returned neg_flags - gd */
194
195         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
196                 retried = true;
197                 goto again;
198         }
199
200         if (!NT_STATUS_IS_OK(result)) {
201                 return result;
202         }
203
204         /*
205          * Check the returned value using the initial
206          * server received challenge.
207          */
208
209         if (!netlogon_creds_client_check(dc, &srv_chal_recv)) {
210                 /*
211                  * Server replied with bad credential. Fail.
212                  */
213                 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
214                         "replied with bad credential\n",
215                         cli->cli->desthost ));
216                 return NT_STATUS_ACCESS_DENIED;
217         }
218
219         DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
220                 "chain established.\n",
221                 cli->cli->desthost ));
222
223         return NT_STATUS_OK;
224 }
225
226 /* Logon domain user */
227
228 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
229                                    TALLOC_CTX *mem_ctx,
230                                    uint32 logon_parameters,
231                                    const char *domain,
232                                    const char *username,
233                                    const char *password,
234                                    const char *workstation,
235                                    int logon_type)
236 {
237         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
238         struct netr_Authenticator clnt_creds;
239         struct netr_Authenticator ret_creds;
240         union netr_LogonInfo *logon;
241         union netr_Validation validation;
242         uint8_t authoritative;
243         int validation_level = 3;
244         fstring clnt_name_slash;
245         uint8 zeros[16];
246
247         ZERO_STRUCT(ret_creds);
248         ZERO_STRUCT(zeros);
249
250         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
251         if (!logon) {
252                 return NT_STATUS_NO_MEMORY;
253         }
254
255         if (workstation) {
256                 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
257         } else {
258                 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
259         }
260
261         /* Initialise input parameters */
262
263         netlogon_creds_client_step(cli->dc, &clnt_creds);
264
265         switch (logon_type) {
266         case INTERACTIVE_LOGON_TYPE: {
267
268                 struct netr_PasswordInfo *password_info;
269
270                 struct samr_Password lmpassword;
271                 struct samr_Password ntpassword;
272
273                 unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
274
275                 unsigned char lm_owf[16];
276                 unsigned char nt_owf[16];
277                 unsigned char key[16];
278
279                 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
280                 if (!password_info) {
281                         return NT_STATUS_NO_MEMORY;
282                 }
283
284                 nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
285
286 #ifdef DEBUG_PASSWORD
287                 DEBUG(100,("lm cypher:"));
288                 dump_data(100, lm_owf_user_pwd, 16);
289
290                 DEBUG(100,("nt cypher:"));
291                 dump_data(100, nt_owf_user_pwd, 16);
292 #endif
293                 memset(key, 0, 16);
294                 memcpy(key, cli->dc->sess_key, 8);
295
296                 memcpy(lm_owf, lm_owf_user_pwd, 16);
297                 SamOEMhash(lm_owf, key, 16);
298                 memcpy(nt_owf, nt_owf_user_pwd, 16);
299                 SamOEMhash(nt_owf, key, 16);
300
301 #ifdef DEBUG_PASSWORD
302                 DEBUG(100,("encrypt of lm owf password:"));
303                 dump_data(100, lm_owf, 16);
304
305                 DEBUG(100,("encrypt of nt owf password:"));
306                 dump_data(100, nt_owf, 16);
307 #endif
308                 memcpy(lmpassword.hash, lm_owf, 16);
309                 memcpy(ntpassword.hash, nt_owf, 16);
310
311                 init_netr_PasswordInfo(password_info,
312                                        domain,
313                                        logon_parameters,
314                                        0xdead,
315                                        0xbeef,
316                                        username,
317                                        clnt_name_slash,
318                                        lmpassword,
319                                        ntpassword);
320
321                 logon->password = password_info;
322
323                 break;
324         }
325         case NET_LOGON_TYPE: {
326                 struct netr_NetworkInfo *network_info;
327                 uint8 chal[8];
328                 unsigned char local_lm_response[24];
329                 unsigned char local_nt_response[24];
330                 struct netr_ChallengeResponse lm;
331                 struct netr_ChallengeResponse nt;
332
333                 ZERO_STRUCT(lm);
334                 ZERO_STRUCT(nt);
335
336                 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
337                 if (!network_info) {
338                         return NT_STATUS_NO_MEMORY;
339                 }
340
341                 generate_random_buffer(chal, 8);
342
343                 SMBencrypt(password, chal, local_lm_response);
344                 SMBNTencrypt(password, chal, local_nt_response);
345
346                 lm.length = 24;
347                 lm.data = local_lm_response;
348
349                 nt.length = 24;
350                 nt.data = local_nt_response;
351
352                 init_netr_NetworkInfo(network_info,
353                                       domain,
354                                       logon_parameters,
355                                       0xdead,
356                                       0xbeef,
357                                       username,
358                                       clnt_name_slash,
359                                       chal,
360                                       nt,
361                                       lm);
362
363                 logon->network = network_info;
364
365                 break;
366         }
367         default:
368                 DEBUG(0, ("switch value %d not supported\n",
369                         logon_type));
370                 return NT_STATUS_INVALID_INFO_CLASS;
371         }
372
373         result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
374                                            cli->dc->remote_machine,
375                                            global_myname(),
376                                            &clnt_creds,
377                                            &ret_creds,
378                                            logon_type,
379                                            logon,
380                                            validation_level,
381                                            &validation,
382                                            &authoritative);
383
384         if (memcmp(zeros, &ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
385                 /* Check returned credentials if present. */
386                 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
387                         DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
388                         return NT_STATUS_ACCESS_DENIED;
389                 }
390         }
391
392         return result;
393 }
394
395
396 /**
397  * Logon domain user with an 'network' SAM logon
398  *
399  * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
400  **/
401
402 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
403                                            TALLOC_CTX *mem_ctx,
404                                            uint32 logon_parameters,
405                                            const char *server,
406                                            const char *username,
407                                            const char *domain,
408                                            const char *workstation,
409                                            const uint8 chal[8],
410                                            DATA_BLOB lm_response,
411                                            DATA_BLOB nt_response,
412                                            struct netr_SamInfo3 **info3)
413 {
414         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
415         int validation_level = 3;
416         const char *workstation_name_slash;
417         const char *server_name_slash;
418         uint8 zeros[16];
419         struct netr_Authenticator clnt_creds;
420         struct netr_Authenticator ret_creds;
421         union netr_LogonInfo *logon = NULL;
422         struct netr_NetworkInfo *network_info;
423         uint8_t authoritative;
424         union netr_Validation validation;
425         struct netr_ChallengeResponse lm;
426         struct netr_ChallengeResponse nt;
427         struct netr_UserSessionKey user_session_key;
428         struct netr_LMSessionKey lmsesskey;
429
430         *info3 = NULL;
431
432         ZERO_STRUCT(zeros);
433         ZERO_STRUCT(ret_creds);
434
435         ZERO_STRUCT(lm);
436         ZERO_STRUCT(nt);
437
438         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
439         if (!logon) {
440                 return NT_STATUS_NO_MEMORY;
441         }
442
443         network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
444         if (!network_info) {
445                 return NT_STATUS_NO_MEMORY;
446         }
447
448         netlogon_creds_client_step(cli->dc, &clnt_creds);
449
450         if (server[0] != '\\' && server[1] != '\\') {
451                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
452         } else {
453                 server_name_slash = server;
454         }
455
456         if (workstation[0] != '\\' && workstation[1] != '\\') {
457                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
458         } else {
459                 workstation_name_slash = workstation;
460         }
461
462         if (!workstation_name_slash || !server_name_slash) {
463                 DEBUG(0, ("talloc_asprintf failed!\n"));
464                 return NT_STATUS_NO_MEMORY;
465         }
466
467         /* Initialise input parameters */
468
469         lm.data = lm_response.data;
470         lm.length = lm_response.length;
471         nt.data = nt_response.data;
472         nt.length = nt_response.length;
473
474         init_netr_NetworkInfo(network_info,
475                               domain,
476                               logon_parameters,
477                               0xdead,
478                               0xbeef,
479                               username,
480                               workstation_name_slash,
481                               (uint8_t *) chal,
482                               nt,
483                               lm);
484
485         logon->network = network_info;
486
487         /* Marshall data and send request */
488
489         result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
490                                            server_name_slash,
491                                            global_myname(),
492                                            &clnt_creds,
493                                            &ret_creds,
494                                            NET_LOGON_TYPE,
495                                            logon,
496                                            validation_level,
497                                            &validation,
498                                            &authoritative);
499         if (!NT_STATUS_IS_OK(result)) {
500                 return result;
501         }
502
503         user_session_key = validation.sam3->base.key;
504         lmsesskey = validation.sam3->base.LMSessKey;
505
506         if (memcmp(zeros, user_session_key.key, 16) != 0) {
507                 SamOEMhash(user_session_key.key, cli->dc->sess_key, 16);
508         }
509
510         if (memcmp(zeros, lmsesskey.key, 8) != 0) {
511                 SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8);
512         }
513
514         if (memcmp(zeros, ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
515                 /* Check returned credentials if present. */
516                 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
517                         DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
518                         return NT_STATUS_ACCESS_DENIED;
519                 }
520         }
521
522         *info3 = validation.sam3;
523
524         return result;
525 }
526
527 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
528                                               TALLOC_CTX *mem_ctx,
529                                               uint32 logon_parameters,
530                                               const char *server,
531                                               const char *username,
532                                               const char *domain,
533                                               const char *workstation,
534                                               const uint8 chal[8],
535                                               DATA_BLOB lm_response,
536                                               DATA_BLOB nt_response,
537                                               struct netr_SamInfo3 **info3)
538 {
539         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
540         int validation_level = 3;
541         const char *workstation_name_slash;
542         const char *server_name_slash;
543         uint8 zeros[16];
544         union netr_LogonInfo *logon = NULL;
545         struct netr_NetworkInfo *network_info;
546         uint8_t authoritative;
547         union netr_Validation validation;
548         struct netr_ChallengeResponse lm;
549         struct netr_ChallengeResponse nt;
550         struct netr_UserSessionKey user_session_key;
551         struct netr_LMSessionKey lmsesskey;
552         uint32_t flags = 0;
553
554         *info3 = NULL;
555
556         ZERO_STRUCT(zeros);
557
558         ZERO_STRUCT(lm);
559         ZERO_STRUCT(nt);
560
561         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
562         if (!logon) {
563                 return NT_STATUS_NO_MEMORY;
564         }
565
566         network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
567         if (!network_info) {
568                 return NT_STATUS_NO_MEMORY;
569         }
570
571         if (server[0] != '\\' && server[1] != '\\') {
572                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
573         } else {
574                 server_name_slash = server;
575         }
576
577         if (workstation[0] != '\\' && workstation[1] != '\\') {
578                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
579         } else {
580                 workstation_name_slash = workstation;
581         }
582
583         if (!workstation_name_slash || !server_name_slash) {
584                 DEBUG(0, ("talloc_asprintf failed!\n"));
585                 return NT_STATUS_NO_MEMORY;
586         }
587
588         /* Initialise input parameters */
589
590         lm.data = lm_response.data;
591         lm.length = lm_response.length;
592         nt.data = nt_response.data;
593         nt.length = nt_response.length;
594
595         init_netr_NetworkInfo(network_info,
596                               domain,
597                               logon_parameters,
598                               0xdead,
599                               0xbeef,
600                               username,
601                               workstation_name_slash,
602                               (uint8_t *) chal,
603                               nt,
604                               lm);
605
606         logon->network = network_info;
607
608         /* Marshall data and send request */
609
610         result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
611                                              server_name_slash,
612                                              global_myname(),
613                                              NET_LOGON_TYPE,
614                                              logon,
615                                              validation_level,
616                                              &validation,
617                                              &authoritative,
618                                              &flags);
619         if (!NT_STATUS_IS_OK(result)) {
620                 return result;
621         }
622
623         user_session_key = validation.sam3->base.key;
624         lmsesskey = validation.sam3->base.LMSessKey;
625
626         if (memcmp(zeros, user_session_key.key, 16) != 0) {
627                 SamOEMhash(user_session_key.key, cli->dc->sess_key, 16);
628         }
629
630         if (memcmp(zeros, lmsesskey.key, 8) != 0) {
631                 SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8);
632         }
633
634         *info3 = validation.sam3;
635
636         return result;
637 }