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