Removed version number from file header.
[samba.git] / source / libsmb / 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) Luke Kenneth Casson Leighton 1996-2000
6    Copyright (C) Tim Potter 2001
7    Copyright (C) Paul Ashton                       1997.
8    Copyright (C) Jeremy Allison                    1998.
9    Copyright (C) Andrew Bartlett                   2001.
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 #include "includes.h"
27
28 /* Opens a SMB connection to the netlogon pipe */
29
30 struct cli_state *cli_netlogon_initialise(struct cli_state *cli, 
31                                           char *system_name,
32                                           struct ntuser_creds *creds)
33 {
34         return cli_pipe_initialise(cli, system_name, PIPE_NETLOGON, creds);
35 }
36
37 /* LSA Request Challenge. Sends our challenge to server, then gets
38    server response. These are used to generate the credentials. */
39
40 NTSTATUS new_cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal, 
41                               DOM_CHAL *srv_chal)
42 {
43         prs_struct qbuf, rbuf;
44         NET_Q_REQ_CHAL q;
45         NET_R_REQ_CHAL r;
46         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
47         extern pstring global_myname;
48
49         prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
50         prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
51         
52         /* create and send a MSRPC command with api NET_REQCHAL */
53
54         DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s: %s\n",
55                  cli->desthost, global_myname, credstr(clnt_chal->data)));
56         
57         /* store the parameters */
58         init_q_req_chal(&q, cli->srv_name_slash, global_myname, clnt_chal);
59         
60         /* Marshall data and send request */
61
62         if (!net_io_q_req_chal("", &q,  &qbuf, 0) ||
63             !rpc_api_pipe_req(cli, NET_REQCHAL, &qbuf, &rbuf)) {
64                 goto done;
65         }
66
67         /* Unmarhall response */
68
69         if (!net_io_r_req_chal("", &r, &rbuf, 0)) {
70                 goto done;
71         }
72
73         result = r.status;
74
75         /* Return result */
76
77         if (NT_STATUS_IS_OK(result)) {
78                 memcpy(srv_chal, r.srv_chal.data, sizeof(srv_chal->data));
79         }
80         
81  done:
82         prs_mem_free(&qbuf);
83         prs_mem_free(&rbuf);
84         
85         return result;
86 }
87
88 /****************************************************************************
89 LSA Authenticate 2
90
91 Send the client credential, receive back a server credential.
92 Ensure that the server credential returned matches the session key 
93 encrypt of the server challenge originally received. JRA.
94 ****************************************************************************/
95
96 NTSTATUS new_cli_net_auth2(struct cli_state *cli, uint16 sec_chan, 
97                            uint32 neg_flags, DOM_CHAL *srv_chal)
98 {
99         prs_struct qbuf, rbuf;
100         NET_Q_AUTH_2 q;
101         NET_R_AUTH_2 r;
102         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
103         extern pstring global_myname;
104
105         prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
106         prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
107
108         /* create and send a MSRPC command with api NET_AUTH2 */
109
110         DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
111                  cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname,
112                  credstr(cli->clnt_cred.challenge.data), neg_flags));
113
114         /* store the parameters */
115         init_q_auth_2(&q, cli->srv_name_slash, cli->mach_acct, 
116                       sec_chan, global_myname, &cli->clnt_cred.challenge, 
117                       neg_flags);
118
119         /* turn parameters into data stream */
120
121         if (!net_io_q_auth_2("", &q,  &qbuf, 0) ||
122             !rpc_api_pipe_req(cli, NET_AUTH2, &qbuf, &rbuf)) {
123                 goto done;
124         }
125         
126         /* Unmarshall response */
127         
128         if (!net_io_r_auth_2("", &r, &rbuf, 0)) {
129                 goto done;
130         }
131
132         result = r.status;
133
134         if (NT_STATUS_IS_OK(result)) {
135                 UTIME zerotime;
136                 
137                 /*
138                  * Check the returned value using the initial
139                  * server received challenge.
140                  */
141
142                 zerotime.time = 0;
143                 if (cred_assert( &r.srv_chal, cli->sess_key, srv_chal, 
144                                  zerotime) == 0) {
145
146                         /*
147                          * Server replied with bad credential. Fail.
148                          */
149                         DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
150 password ?).\n", cli->desthost ));
151                         result = NT_STATUS_ACCESS_DENIED;
152                         goto done;
153                 }
154         }
155
156  done:
157         prs_mem_free(&qbuf);
158         prs_mem_free(&rbuf);
159         
160         return result;
161 }
162
163 /* Initialize domain session credentials */
164
165 NTSTATUS new_cli_nt_setup_creds(struct cli_state *cli, 
166                                 unsigned char mach_pwd[16])
167 {
168         DOM_CHAL clnt_chal;
169         DOM_CHAL srv_chal;
170         UTIME zerotime;
171         NTSTATUS result;
172
173         /******************* Request Challenge ********************/
174
175         generate_random_buffer(clnt_chal.data, 8, False);
176         
177         /* send a client challenge; receive a server challenge */
178         result = new_cli_net_req_chal(cli, &clnt_chal, &srv_chal);
179
180         if (!NT_STATUS_IS_OK(result)) {
181                 DEBUG(0,("cli_nt_setup_creds: request challenge failed\n"));
182                 return result;
183         }
184         
185         /**************** Long-term Session key **************/
186
187         /* calculate the session key */
188         cred_session_key(&clnt_chal, &srv_chal, (char *)mach_pwd, 
189                          cli->sess_key);
190         memset((char *)cli->sess_key+8, '\0', 8);
191
192         /******************* Authenticate 2 ********************/
193
194         /* calculate auth-2 credentials */
195         zerotime.time = 0;
196         cred_create(cli->sess_key, &clnt_chal, zerotime, 
197                     &cli->clnt_cred.challenge);
198
199         /*  
200          * Send client auth-2 challenge.
201          * Receive an auth-2 challenge response and check it.
202          */
203         
204         result = new_cli_net_auth2(cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
205                                    SEC_CHAN_WKSTA : SEC_CHAN_BDC, 0x000001ff, 
206                                    &srv_chal);
207         if (!NT_STATUS_IS_OK(result)) {
208                 DEBUG(0,("cli_nt_setup_creds: auth2 challenge failed %s\n",
209                          get_nt_error_msg(result)));
210         }
211
212         return result;
213 }
214
215 /* Logon Control 2 */
216
217 NTSTATUS cli_netlogon_logon_ctrl2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
218                                   uint32 query_level)
219 {
220         prs_struct qbuf, rbuf;
221         NET_Q_LOGON_CTRL2 q;
222         NET_R_LOGON_CTRL2 r;
223         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
224
225         ZERO_STRUCT(q);
226         ZERO_STRUCT(r);
227
228         /* Initialise parse structures */
229
230         prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
231         prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
232
233         /* Initialise input parameters */
234
235         init_net_q_logon_ctrl2(&q, cli->srv_name_slash, query_level);
236
237         /* Marshall data and send request */
238
239         if (!net_io_q_logon_ctrl2("", &q, &qbuf, 0) ||
240             !rpc_api_pipe_req(cli, NET_LOGON_CTRL2, &qbuf, &rbuf)) {
241                 result = NT_STATUS_UNSUCCESSFUL;
242                 goto done;
243         }
244
245         /* Unmarshall response */
246
247         if (!net_io_r_logon_ctrl2("", &r, &rbuf, 0)) {
248                 result = NT_STATUS_UNSUCCESSFUL;
249                 goto done;
250         }
251
252         result = r.status;
253
254  done:
255         prs_mem_free(&qbuf);
256         prs_mem_free(&rbuf);
257
258         return result;
259 }
260
261 /****************************************************************************
262 Generate the next creds to use.  Yuck - this is a cut&paste from another
263 file.  They should be combined at some stage.  )-:
264 ****************************************************************************/
265
266 static void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred)
267 {
268   /*
269    * Create the new client credentials.
270    */
271
272   cli->clnt_cred.timestamp.time = time(NULL);
273
274   memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred));
275
276   /* Calculate the new credentials. */
277   cred_create(cli->sess_key, &(cli->clnt_cred.challenge),
278               new_clnt_cred->timestamp, &(new_clnt_cred->challenge));
279
280 }
281
282 /* Sam synchronisation */
283
284 NTSTATUS cli_netlogon_sam_sync(struct cli_state *cli, TALLOC_CTX *mem_ctx, DOM_CRED *ret_creds,
285                                uint32 database_id, uint32 *num_deltas,
286                                SAM_DELTA_HDR **hdr_deltas, 
287                                SAM_DELTA_CTR **deltas)
288 {
289         prs_struct qbuf, rbuf;
290         NET_Q_SAM_SYNC q;
291         NET_R_SAM_SYNC r;
292         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
293         DOM_CRED clnt_creds;
294
295         ZERO_STRUCT(q);
296         ZERO_STRUCT(r);
297
298         /* Initialise parse structures */
299
300         prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
301         prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
302
303         /* Initialise input parameters */
304
305         gen_next_creds(cli, &clnt_creds);
306
307         init_net_q_sam_sync(&q, cli->srv_name_slash, cli->clnt_name_slash + 2,
308                             &clnt_creds, ret_creds, database_id);
309
310         /* Marshall data and send request */
311
312         if (!net_io_q_sam_sync("", &q, &qbuf, 0) ||
313             !rpc_api_pipe_req(cli, NET_SAM_SYNC, &qbuf, &rbuf)) {
314                 result = NT_STATUS_UNSUCCESSFUL;
315                 goto done;
316         }
317
318         /* Unmarshall response */
319
320         if (!net_io_r_sam_sync("", cli->sess_key, &r, &rbuf, 0)) {
321                 result = NT_STATUS_UNSUCCESSFUL;
322                 goto done;
323         }
324
325         /* Return results */
326
327         result = r.status;
328         *num_deltas = r.num_deltas2;
329         *hdr_deltas = r.hdr_deltas;
330         *deltas = r.deltas;
331
332         memcpy(ret_creds, &r.srv_creds, sizeof(*ret_creds));
333
334  done:
335         prs_mem_free(&qbuf);
336         prs_mem_free(&rbuf);
337
338         return result;
339 }
340
341 /* Sam synchronisation */
342
343 NTSTATUS cli_netlogon_sam_deltas(struct cli_state *cli, TALLOC_CTX *mem_ctx,
344                                  uint32 database_id, UINT64_S seqnum,
345                                  uint32 *num_deltas, 
346                                  SAM_DELTA_HDR **hdr_deltas, 
347                                  SAM_DELTA_CTR **deltas)
348 {
349         prs_struct qbuf, rbuf;
350         NET_Q_SAM_DELTAS q;
351         NET_R_SAM_DELTAS r;
352         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
353         DOM_CRED clnt_creds;
354
355         ZERO_STRUCT(q);
356         ZERO_STRUCT(r);
357
358         /* Initialise parse structures */
359
360         prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
361         prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
362
363         /* Initialise input parameters */
364
365         gen_next_creds(cli, &clnt_creds);
366
367         init_net_q_sam_deltas(&q, cli->srv_name_slash, 
368                               cli->clnt_name_slash + 2, &clnt_creds, 
369                               database_id, seqnum);
370
371         /* Marshall data and send request */
372
373         if (!net_io_q_sam_deltas("", &q, &qbuf, 0) ||
374             !rpc_api_pipe_req(cli, NET_SAM_DELTAS, &qbuf, &rbuf)) {
375                 result = NT_STATUS_UNSUCCESSFUL;
376                 goto done;
377         }
378
379         /* Unmarshall response */
380
381         if (!net_io_r_sam_deltas("", cli->sess_key, &r, &rbuf, 0)) {
382                 result = NT_STATUS_UNSUCCESSFUL;
383                 goto done;
384         }
385
386         /* Return results */
387
388         result = r.status;
389         *num_deltas = r.num_deltas2;
390         *hdr_deltas = r.hdr_deltas;
391         *deltas = r.deltas;
392
393  done:
394         prs_mem_free(&qbuf);
395         prs_mem_free(&rbuf);
396
397         return result;
398 }
399
400 /* Logon domain user */
401
402 NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
403                                 char *username, char *password,
404                                 int logon_type)
405 {
406         prs_struct qbuf, rbuf;
407         NET_Q_SAM_LOGON q;
408         NET_R_SAM_LOGON r;
409         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
410         DOM_CRED clnt_creds, dummy_rtn_creds;
411         extern pstring global_myname;
412         NET_ID_INFO_CTR ctr;
413         NET_USER_INFO_3 user;
414         int validation_level = 3;
415
416         ZERO_STRUCT(q);
417         ZERO_STRUCT(r);
418
419         /* Initialise parse structures */
420
421         prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
422         prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
423
424         /* Initialise input parameters */
425
426         gen_next_creds(cli, &clnt_creds);
427
428         q.validation_level = validation_level;
429
430         memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
431         dummy_rtn_creds.timestamp.time = time(NULL);
432
433         ctr.switch_value = logon_type;
434
435         switch (logon_type) {
436         case INTERACTIVE_LOGON_TYPE: {
437                 unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
438
439                 nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
440
441                 init_id_info1(&ctr.auth.id1, lp_workgroup(), 
442                               0, /* param_ctrl */
443                               0xdead, 0xbeef, /* LUID? */
444                               username, cli->clnt_name_slash,
445                               cli->sess_key, lm_owf_user_pwd,
446                               nt_owf_user_pwd);
447
448                 break;
449         }
450         case NET_LOGON_TYPE: {
451                 uint8 chal[8];
452                 unsigned char local_lm_response[24];
453                 unsigned char local_nt_response[24];
454
455                 generate_random_buffer(chal, 8, False);
456
457                 SMBencrypt(password, chal, local_lm_response);
458                 SMBNTencrypt(password, chal, local_nt_response);
459
460                 init_id_info2(&ctr.auth.id2, lp_workgroup(), 
461                               0, /* param_ctrl */
462                               0xdead, 0xbeef, /* LUID? */
463                               username, cli->clnt_name_slash, chal,
464                               local_lm_response, 24, local_nt_response, 24);
465                 break;
466         }
467         default:
468                 DEBUG(0, ("switch value %d not supported\n", 
469                           ctr.switch_value));
470                 goto done;
471         }
472
473         init_sam_info(&q.sam_id, cli->srv_name_slash, global_myname,
474                       &clnt_creds, &dummy_rtn_creds, logon_type,
475                       &ctr);
476
477         /* Marshall data and send request */
478
479         if (!net_io_q_sam_logon("", &q, &qbuf, 0) ||
480             !rpc_api_pipe_req(cli, NET_SAMLOGON, &qbuf, &rbuf)) {
481                 goto done;
482         }
483
484         /* Unmarshall response */
485
486         r.user = &user;
487
488         if (!net_io_r_sam_logon("", &r, &rbuf, 0)) {
489                 goto done;
490         }
491
492         /* Return results */
493
494         result = r.status;
495
496  done:
497         prs_mem_free(&qbuf);
498         prs_mem_free(&rbuf);
499
500         return result;
501 }
502
503
504 /** 
505  * Logon domain user with an 'network' SAM logon 
506  *
507  * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
508  **/
509
510 NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
511                                         const char *username, const char *domain, const char *workstation, 
512                                         const uint8 chal[8],
513                                         DATA_BLOB lm_response, DATA_BLOB nt_response,
514                                         NET_USER_INFO_3 *info3)
515
516 {
517         prs_struct qbuf, rbuf;
518         NET_Q_SAM_LOGON q;
519         NET_R_SAM_LOGON r;
520         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
521         DOM_CRED clnt_creds, dummy_rtn_creds;
522         NET_ID_INFO_CTR ctr;
523         extern pstring global_myname;
524         int validation_level = 3;
525         char *workstation_name_slash;
526         
527         ZERO_STRUCT(q);
528         ZERO_STRUCT(r);
529
530         workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
531         
532         if (!workstation_name_slash) {
533                 DEBUG(0, ("talloc_asprintf failed!\n"));
534                 return NT_STATUS_NO_MEMORY;
535         }
536
537         /* Initialise parse structures */
538
539         prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
540         prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
541
542         /* Initialise input parameters */
543
544         gen_next_creds(cli, &clnt_creds);
545
546         q.validation_level = validation_level;
547
548         memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
549         dummy_rtn_creds.timestamp.time = time(NULL);
550
551         ctr.switch_value = NET_LOGON_TYPE;
552
553         init_id_info2(&ctr.auth.id2, domain,
554                       0, /* param_ctrl */
555                       0xdead, 0xbeef, /* LUID? */
556                       username, workstation_name_slash, (const uchar*)chal,
557                       lm_response.data, lm_response.length, nt_response.data, nt_response.length);
558  
559         init_sam_info(&q.sam_id, cli->srv_name_slash, global_myname,
560                       &clnt_creds, &dummy_rtn_creds, NET_LOGON_TYPE,
561                       &ctr);
562
563         /* Marshall data and send request */
564
565         if (!net_io_q_sam_logon("", &q, &qbuf, 0) ||
566             !rpc_api_pipe_req(cli, NET_SAMLOGON, &qbuf, &rbuf)) {
567                 goto done;
568         }
569
570         /* Unmarshall response */
571
572         r.user = info3;
573
574         if (!net_io_r_sam_logon("", &r, &rbuf, 0)) {
575                 goto done;
576         }
577
578         /* Return results */
579
580         result = r.status;
581
582  done:
583         prs_mem_free(&qbuf);
584         prs_mem_free(&rbuf);
585
586         return result;
587 }
588
589 /***************************************************************************
590 LSA Server Password Set.
591 ****************************************************************************/
592
593 NTSTATUS cli_net_srv_pwset(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
594                            char* machine_name, uint8 hashed_mach_pwd[16])
595 {
596         prs_struct rbuf;
597         prs_struct qbuf; 
598         DOM_CRED new_clnt_cred;
599         NET_Q_SRV_PWSET q_s;
600         uint16 sec_chan_type = 2;
601         NTSTATUS nt_status;
602         char *mach_acct;
603
604         gen_next_creds( cli, &new_clnt_cred);
605         
606         prs_init(&qbuf , 1024, mem_ctx, MARSHALL);
607         prs_init(&rbuf, 0,    mem_ctx, UNMARSHALL);
608         
609         /* create and send a MSRPC command with api NET_SRV_PWSET */
610         
611         mach_acct = talloc_asprintf(mem_ctx, "%s$", machine_name);
612         
613         if (!mach_acct) {
614                 DEBUG(0,("talloc_asprintf failed!\n"));
615                 nt_status = NT_STATUS_NO_MEMORY;
616                 goto done;
617         }
618
619         DEBUG(4,("cli_net_srv_pwset: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
620                  cli->srv_name_slash, mach_acct, sec_chan_type, machine_name,
621                  credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
622         
623         /* store the parameters */
624         init_q_srv_pwset(&q_s, cli->srv_name_slash, cli->sess_key,
625                          mach_acct, sec_chan_type, machine_name, 
626                          &new_clnt_cred, (char *)hashed_mach_pwd);
627         
628         /* turn parameters into data stream */
629         if(!net_io_q_srv_pwset("", &q_s,  &qbuf, 0)) {
630                 DEBUG(0,("cli_net_srv_pwset: Error : failed to marshall NET_Q_SRV_PWSET struct.\n"));
631                 nt_status = NT_STATUS_UNSUCCESSFUL;
632                 goto done;
633         }
634         
635         /* send the data on \PIPE\ */
636         if (rpc_api_pipe_req(cli, NET_SRVPWSET, &qbuf, &rbuf))
637         {
638                 NET_R_SRV_PWSET r_s;
639                 
640                 if (!net_io_r_srv_pwset("", &r_s, &rbuf, 0)) {
641                         nt_status =  NT_STATUS_UNSUCCESSFUL;
642                         goto done;
643                 }
644                 
645                 nt_status = r_s.status;
646
647                 if (!NT_STATUS_IS_OK(r_s.status))
648                 {
649                         /* report error code */
650                         DEBUG(0,("cli_net_srv_pwset: %s\n", get_nt_error_msg(nt_status)));
651                         goto done;
652                 }
653
654                 /* Update the credentials. */
655                 if (!clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_cred)))
656                 {
657                         /*
658                          * Server replied with bad credential. Fail.
659                          */
660                         DEBUG(0,("cli_net_srv_pwset: server %s replied with bad credential (bad machine \
661 password ?).\n", cli->desthost ));
662                         nt_status = NT_STATUS_UNSUCCESSFUL;
663                 }
664         }
665
666  done:
667         prs_mem_free(&qbuf);
668         prs_mem_free(&rbuf);
669         
670         return nt_status;
671 }
672