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