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