Attempt to fix bug 5616
[samba.git] / source / 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, cli->mem_ctx,
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, cli->mem_ctx,
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
428         *info3 = NULL;
429
430         ZERO_STRUCT(zeros);
431         ZERO_STRUCT(ret_creds);
432
433         ZERO_STRUCT(lm);
434         ZERO_STRUCT(nt);
435
436         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
437         if (!logon) {
438                 return NT_STATUS_NO_MEMORY;
439         }
440
441         network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
442         if (!network_info) {
443                 return NT_STATUS_NO_MEMORY;
444         }
445
446         netlogon_creds_client_step(cli->dc, &clnt_creds);
447
448         if (server[0] != '\\' && server[1] != '\\') {
449                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
450         } else {
451                 server_name_slash = server;
452         }
453
454         if (workstation[0] != '\\' && workstation[1] != '\\') {
455                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
456         } else {
457                 workstation_name_slash = workstation;
458         }
459
460         if (!workstation_name_slash || !server_name_slash) {
461                 DEBUG(0, ("talloc_asprintf failed!\n"));
462                 return NT_STATUS_NO_MEMORY;
463         }
464
465         /* Initialise input parameters */
466
467         lm.data = lm_response.data;
468         lm.length = lm_response.length;
469         nt.data = nt_response.data;
470         nt.length = nt_response.length;
471
472         init_netr_NetworkInfo(network_info,
473                               domain,
474                               logon_parameters,
475                               0xdead,
476                               0xbeef,
477                               username,
478                               workstation_name_slash,
479                               (uint8_t *) chal,
480                               nt,
481                               lm);
482
483         logon->network = network_info;
484
485         /* Marshall data and send request */
486
487         result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
488                                            server_name_slash,
489                                            global_myname(),
490                                            &clnt_creds,
491                                            &ret_creds,
492                                            NET_LOGON_TYPE,
493                                            logon,
494                                            validation_level,
495                                            &validation,
496                                            &authoritative);
497         if (!NT_STATUS_IS_OK(result)) {
498                 return result;
499         }
500
501         if (memcmp(zeros, validation.sam3->base.key.key, 16) != 0) {
502                 SamOEMhash(validation.sam3->base.key.key,
503                            cli->dc->sess_key, 16);
504         }
505
506         if (memcmp(zeros, validation.sam3->base.LMSessKey.key, 8) != 0) {
507                 SamOEMhash(validation.sam3->base.LMSessKey.key,
508                            cli->dc->sess_key, 8);
509         }
510
511         if (memcmp(zeros, ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
512                 /* Check returned credentials if present. */
513                 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
514                         DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
515                         return NT_STATUS_ACCESS_DENIED;
516                 }
517         }
518
519         *info3 = validation.sam3;
520
521         return result;
522 }
523
524 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
525                                               TALLOC_CTX *mem_ctx,
526                                               uint32 logon_parameters,
527                                               const char *server,
528                                               const char *username,
529                                               const char *domain,
530                                               const char *workstation,
531                                               const uint8 chal[8],
532                                               DATA_BLOB lm_response,
533                                               DATA_BLOB nt_response,
534                                               struct netr_SamInfo3 **info3)
535 {
536         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
537         int validation_level = 3;
538         const char *workstation_name_slash;
539         const char *server_name_slash;
540         uint8 zeros[16];
541         union netr_LogonInfo *logon = NULL;
542         struct netr_NetworkInfo *network_info;
543         uint8_t authoritative;
544         union netr_Validation validation;
545         struct netr_ChallengeResponse lm;
546         struct netr_ChallengeResponse nt;
547         struct netr_UserSessionKey user_session_key;
548         struct netr_LMSessionKey lmsesskey;
549         uint32_t flags = 0;
550
551         *info3 = NULL;
552
553         ZERO_STRUCT(zeros);
554
555         ZERO_STRUCT(lm);
556         ZERO_STRUCT(nt);
557
558         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
559         if (!logon) {
560                 return NT_STATUS_NO_MEMORY;
561         }
562
563         network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
564         if (!network_info) {
565                 return NT_STATUS_NO_MEMORY;
566         }
567
568         if (server[0] != '\\' && server[1] != '\\') {
569                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
570         } else {
571                 server_name_slash = server;
572         }
573
574         if (workstation[0] != '\\' && workstation[1] != '\\') {
575                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
576         } else {
577                 workstation_name_slash = workstation;
578         }
579
580         if (!workstation_name_slash || !server_name_slash) {
581                 DEBUG(0, ("talloc_asprintf failed!\n"));
582                 return NT_STATUS_NO_MEMORY;
583         }
584
585         /* Initialise input parameters */
586
587         lm.data = lm_response.data;
588         lm.length = lm_response.length;
589         nt.data = nt_response.data;
590         nt.length = nt_response.length;
591
592         init_netr_NetworkInfo(network_info,
593                               domain,
594                               logon_parameters,
595                               0xdead,
596                               0xbeef,
597                               username,
598                               workstation_name_slash,
599                               (uint8_t *) chal,
600                               nt,
601                               lm);
602
603         logon->network = network_info;
604
605         /* Marshall data and send request */
606
607         result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
608                                              server_name_slash,
609                                              global_myname(),
610                                              NET_LOGON_TYPE,
611                                              logon,
612                                              validation_level,
613                                              &validation,
614                                              &authoritative,
615                                              &flags);
616         if (!NT_STATUS_IS_OK(result)) {
617                 return result;
618         }
619
620         user_session_key = validation.sam3->base.key;
621         lmsesskey = validation.sam3->base.LMSessKey;
622
623         if (memcmp(zeros, user_session_key.key, 16) != 0) {
624                 SamOEMhash(user_session_key.key, cli->dc->sess_key, 16);
625         }
626
627         if (memcmp(zeros, lmsesskey.key, 8) != 0) {
628                 SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8);
629         }
630
631         *info3 = validation.sam3;
632
633         return result;
634 }