fixing joining to domain plus something weird going down with nt logins...
[tprouty/samba.git] / source / rpc_client / cli_netlogon.c
1 /* 
2  *  Unix SMB/Netbios implementation.
3  *  Version 1.9.
4  *  RPC Pipe client / server routines
5  *  Copyright (C) Andrew Tridgell              1992-1997,
6  *  Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
7  *  Copyright (C) Paul Ashton                       1997.
8  *  Copyright (C) Jeremy Allison                    1998.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *  
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *  
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25
26 #ifdef SYSLOG
27 #undef SYSLOG
28 #endif
29
30 #include "includes.h"
31
32 extern int DEBUGLEVEL;
33
34 /****************************************************************************
35 Generate the next creds to use.
36 ****************************************************************************/
37
38 void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred)
39 {
40   /*
41    * Create the new client credentials.
42    */
43
44   cli->clnt_cred.timestamp.time = time(NULL);
45
46   memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred));
47
48   /* Calculate the new credentials. */
49   cred_create(cli->sess_key, &(cli->clnt_cred.challenge),
50               new_clnt_cred->timestamp, &(new_clnt_cred->challenge));
51
52 }
53
54 /****************************************************************************
55 do a LSA Logon Control2
56 ****************************************************************************/
57 BOOL cli_net_logon_ctrl2(const char* srv_name, uint32 status_level)
58 {
59         prs_struct rbuf;
60         prs_struct buf; 
61         NET_Q_LOGON_CTRL2 q_l;
62         BOOL ok = False;
63
64         struct cli_connection *con = NULL;
65
66         if (!cli_connection_init(srv_name, PIPE_NETLOGON, &con))
67         {
68                 return False;
69         }
70
71         prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
72         prs_init(&rbuf, 0,    4, SAFETY_MARGIN, True );
73
74         /* create and send a MSRPC command with api NET_LOGON_CTRL2 */
75
76         DEBUG(4,("net_logon_ctrl2 status level:%x\n", status_level));
77
78         /* store the parameters */
79         make_q_logon_ctrl2(&q_l, srv_name, 0, 0, status_level);
80
81         /* turn parameters into data stream */
82         net_io_q_logon_ctrl2("", &q_l,  &buf, 0);
83
84         /* send the data on \PIPE\ */
85         if (rpc_con_pipe_req(con, NET_LOGON_CTRL2, &buf, &rbuf))
86         {
87                 NET_R_LOGON_CTRL2 r_l;
88
89                 net_io_r_logon_ctrl2("", &r_l, &rbuf, 0);
90                 ok = (rbuf.offset != 0);
91
92                 if (ok && r_l.status != 0)
93                 {
94                         /* report error code */
95                         DEBUG(5,("net_logon_ctrl2: Error %s\n", get_nt_error_msg(r_l.status)));
96                         ok = False;
97                 }
98         }
99
100         prs_mem_free(&rbuf);
101         prs_mem_free(&buf );
102
103         cli_connection_unlink(con);
104         return ok;
105 }
106
107 /****************************************************************************
108 LSA Authenticate 2
109
110 Send the client credential, receive back a server credential.
111 Ensure that the server credential returned matches the session key 
112 encrypt of the server challenge originally received. JRA.
113 ****************************************************************************/
114
115 uint32 cli_net_auth2(const char *srv_name,
116                                 const char *trust_acct, 
117                                 const char *acct_name, 
118                                 uint16 sec_chan, 
119                                 uint32 neg_flags, DOM_CHAL *srv_chal)
120 {
121         prs_struct rbuf;
122         prs_struct buf; 
123         NET_Q_AUTH_2 q_a;
124         uint32 status = 0x0;
125         uint8 sess_key[16];
126         DOM_CRED clnt_cred;
127
128         struct cli_connection *con = NULL;
129
130         if (!cli_connection_getsrv(srv_name, PIPE_NETLOGON, &con))
131         {
132                 return False;
133         }
134
135         if (!cli_get_con_sesskey(con, sess_key))
136         {
137                 return False;
138         }
139
140         prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
141         prs_init(&rbuf, 0,    4, SAFETY_MARGIN, True );
142
143         /* create and send a MSRPC command with api NET_AUTH2 */
144
145         DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s neg: %x\n",
146                   srv_name, trust_acct, sec_chan, acct_name,
147                   neg_flags));
148
149         cli_con_get_cli_cred(con, &clnt_cred);
150
151         /* store the parameters */
152         make_q_auth_2(&q_a, srv_name, trust_acct, sec_chan, acct_name,
153                       &clnt_cred.challenge, neg_flags);
154
155         /* turn parameters into data stream */
156         net_io_q_auth_2("", &q_a,  &buf, 0);
157
158         /* send the data on \PIPE\ */
159         if (rpc_con_pipe_req(con, NET_AUTH2, &buf, &rbuf))
160         {
161                 NET_R_AUTH_2 r_a;
162
163                 net_io_r_auth_2("", &r_a, &rbuf, 0);
164                 status = (rbuf.offset == 0) ? 0xC0000000 | NT_STATUS_INVALID_PARAMETER : 0;
165
166                 if (status == 0x0 && r_a.status != 0)
167                 {
168                         /* report error code */
169                         DEBUG(5,("cli_net_auth2: Error %s\n",
170                                   get_nt_error_msg(r_a.status)));
171                         status = r_a.status;
172                 }
173
174                 if (status == 0x0)
175                 {
176                         /*
177                          * Check the returned value using the initial
178                          * server received challenge.
179                          */
180                         UTIME zerotime;
181
182                         zerotime.time = 0;
183                         if(cred_assert( &r_a.srv_chal, sess_key,
184                                         srv_chal, zerotime) == 0)
185                         {
186                                 /*
187                                  * Server replied with bad credential. Fail.
188                                  */
189                                 DEBUG(5,("cli_net_auth2: server %s replied \
190 with bad credential (bad trust account password ?).\n", srv_name));
191                                 status = NT_STATUS_NETWORK_CREDENTIAL_CONFLICT | 0xC0000000;
192                         }
193                 }
194
195 #if 0
196                 /*
197                  * Try commenting this out to see if this makes the connect
198                  * work for a NT 3.51 PDC. JRA.
199                  */
200
201                 if (ok && r_a.srv_flgs.neg_flags != q_a.clnt_flgs.neg_flags)
202                 {
203                         /* report different neg_flags */
204                         DEBUG(5,("cli_net_auth2: error neg_flags (q,r) differ - (%x,%x)\n",
205                         q_a.clnt_flgs.neg_flags, r_a.srv_flgs.neg_flags));
206                         ok = False;
207                 }
208 #endif
209
210         }
211         else
212         {
213                 DEBUG(5,("rpc_con_pipe_req FAILED\n"));
214                 status = 0xC0000000 | NT_STATUS_ACCESS_DENIED;
215         }
216
217         DEBUG(5,("cli_net_auth2 status: %x\n", status));
218
219         prs_mem_free(&rbuf);
220         prs_mem_free(&buf );
221
222         return status;
223 }
224
225 /****************************************************************************
226 LSA Request Challenge. Sends our challenge to server, then gets
227 server response. These are used to generate the credentials.
228 ****************************************************************************/
229
230 uint32 cli_net_req_chal( const char *srv_name, const char* myhostname,
231                                 DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal)
232 {
233   prs_struct rbuf;
234   prs_struct buf; 
235   NET_Q_REQ_CHAL q_c;
236     uint32 status = 0x0;
237
238         struct cli_connection *con = NULL;
239
240         if (!cli_connection_init(srv_name, PIPE_NETLOGON, &con))
241         {
242                 return False;
243         }
244
245   if (srv_chal == NULL || clnt_chal == NULL)
246     return 0xC0000000 | NT_STATUS_INVALID_PARAMETER;
247
248   prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
249   prs_init(&rbuf, 0,    4, SAFETY_MARGIN, True );
250
251   /* create and send a MSRPC command with api NET_REQCHAL */
252
253   DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s: %s\n",
254          srv_name, myhostname, credstr(clnt_chal->data)));
255
256   /* store the parameters */
257   make_q_req_chal(&q_c, srv_name, myhostname, clnt_chal);
258
259   /* turn parameters into data stream */
260   net_io_q_req_chal("", &q_c,  &buf, 0);
261
262   /* send the data on \PIPE\ */
263   if (rpc_con_pipe_req(con, NET_REQCHAL, &buf, &rbuf))
264   {
265     NET_R_REQ_CHAL r_c;
266
267     net_io_r_req_chal("", &r_c, &rbuf, 0);
268     status = (rbuf.offset == 0) ? 0xC0000000 | NT_STATUS_INVALID_PARAMETER : 0;
269                 
270     if (status == 0x0 && r_c.status != 0)
271     {
272       /* report error code */
273       DEBUG(5,("cli_net_req_chal: Error %s\n", get_nt_error_msg(r_c.status)));
274         status = r_c.status;
275     }
276
277     if (status == 0x0)
278     {
279       /* ok, at last: we're happy. return the challenge */
280       memcpy(srv_chal, r_c.srv_chal.data, sizeof(srv_chal->data));
281     }
282   }
283   else
284   {
285     DEBUG(5,("rpc_con_pipe_req FAILED\n"));
286     status = 0xC0000000 | NT_STATUS_ACCESS_DENIED;
287   }
288
289   prs_mem_free(&rbuf);
290   prs_mem_free(&buf );
291
292   return status;
293 }
294
295 /***************************************************************************
296 LSA Server Password Set.
297 ****************************************************************************/
298
299 BOOL cli_net_srv_pwset(const char* srv_name,
300                                 const char* myhostname,
301                                 const char* trust_acct,
302                                 uint8 hashed_trust_pwd[16],
303                                 uint16 sec_chan_type)
304 {
305   prs_struct rbuf;
306   prs_struct buf; 
307   DOM_CRED new_clnt_cred;
308   NET_Q_SRV_PWSET q_s;
309   BOOL ok = False;
310   unsigned char processed_new_pwd[16];
311   /* Process the new password. */
312
313         uint8 sess_key[16];
314         
315         struct cli_connection *con = NULL;
316
317         if (!cli_connection_getsrv(srv_name, PIPE_NETLOGON, &con))
318         {
319                 return False;
320         }
321
322         if (!cli_get_con_sesskey(con, sess_key))
323         {
324                 return False;
325         }
326
327         cred_hash3( processed_new_pwd, hashed_trust_pwd, sess_key, 1);
328
329   cli_con_gen_next_creds( con, &new_clnt_cred);
330
331   prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
332   prs_init(&rbuf, 0,    4, SAFETY_MARGIN, True );
333
334   /* create and send a MSRPC command with api NET_SRV_PWSET */
335
336   DEBUG(4,("cli_net_srv_pwset: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
337            srv_name, trust_acct, sec_chan_type, myhostname,
338            credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
339
340   /* store the parameters */
341   make_q_srv_pwset(&q_s, srv_name, trust_acct, sec_chan_type,
342                    myhostname, &new_clnt_cred, (char *)processed_new_pwd);
343
344   /* turn parameters into data stream */
345   net_io_q_srv_pwset("", &q_s,  &buf, 0);
346
347   /* send the data on \PIPE\ */
348   if (rpc_con_pipe_req(con, NET_SRVPWSET, &buf, &rbuf))
349   {
350     NET_R_SRV_PWSET r_s;
351
352     net_io_r_srv_pwset("", &r_s, &rbuf, 0);
353     ok = (rbuf.offset != 0);
354                 
355     if (ok && r_s.status != 0)
356     {
357       /* report error code */
358       DEBUG(5,("cli_net_srv_pwset: %s\n", get_nt_error_msg(r_s.status)));
359       ok = False;
360     }
361
362     /* Update the credentials. */
363     if (ok && !cli_con_deal_with_creds(con, &(r_s.srv_cred)))
364     {
365       /*
366        * Server replied with bad credential. Fail.
367        */
368       DEBUG(5,("cli_net_srv_pwset: server %s replied with bad credential \
369 (bad trust account password ?).\n", srv_name));
370       ok = False;
371     }
372   }
373
374   prs_mem_free(&rbuf);
375   prs_mem_free(&buf );
376
377   return ok;
378 }
379
380 /***************************************************************************
381 LSA SAM Logon - interactive or network.
382 ****************************************************************************/
383
384 BOOL cli_net_sam_logon(const char* srv_name, const char* myhostname,
385                                 NET_ID_INFO_CTR *ctr, 
386                                 NET_USER_INFO_3 *user_info3)
387 {
388   DOM_CRED new_clnt_cred;
389   DOM_CRED dummy_rtn_creds;
390   prs_struct rbuf;
391   prs_struct buf; 
392   uint16 validation_level = 3;
393   NET_Q_SAM_LOGON q_s;
394   BOOL ok = False;
395
396         struct cli_connection *con = NULL;
397
398         if (!cli_connection_getsrv(srv_name, PIPE_NETLOGON, &con))
399         {
400                 return False;
401         }
402
403   cli_con_gen_next_creds( con, &new_clnt_cred);
404
405   prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
406   prs_init(&rbuf, 0,    4, SAFETY_MARGIN, True );
407
408   /* create and send a MSRPC command with api NET_SAMLOGON */
409
410   DEBUG(4,("cli_net_sam_logon: srv:%s mc:%s ll: %d\n",
411              srv_name, myhostname, 
412              ctr->switch_value));
413
414   memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
415         dummy_rtn_creds.timestamp.time = time(NULL);
416
417   /* store the parameters */
418   make_sam_info(&(q_s.sam_id), srv_name, myhostname,
419          &new_clnt_cred, &dummy_rtn_creds, ctr->switch_value, ctr, validation_level);
420
421   /* turn parameters into data stream */
422   net_io_q_sam_logon("", &q_s,  &buf, 0);
423
424   /* send the data on \PIPE\ */
425   if (rpc_con_pipe_req(con, NET_SAMLOGON, &buf, &rbuf))
426   {
427     NET_R_SAM_LOGON r_s;
428
429     r_s.user = user_info3;
430
431     net_io_r_sam_logon("", &r_s, &rbuf, 0);
432     ok = (rbuf.offset != 0);
433                 
434     if (ok && r_s.status != 0)
435     {
436       /* report error code */
437       DEBUG(5,("cli_net_sam_logon: %s\n", get_nt_error_msg(r_s.status)));
438       ok = False;
439     }
440
441     /* Update the credentials. */
442     if (ok && !cli_con_deal_with_creds(con, &(r_s.srv_creds)))
443     {
444       /*
445        * Server replied with bad credential. Fail.
446        */
447       DEBUG(5,("cli_net_sam_logon: server %s replied with bad credential \
448 (bad trust account password ?).\n", srv_name));
449         ok = False;
450     }
451
452     if (ok && r_s.switch_value != 3)
453     {
454       /* report different switch_value */
455       DEBUG(5,("cli_net_sam_logon: switch_value of 3 expected %x\n",
456                    r_s.switch_value));
457       ok = False;
458     }
459   }
460
461   prs_mem_free(&rbuf);
462   prs_mem_free(&buf );
463
464   return ok;
465 }
466
467 /***************************************************************************
468 LSA SAM Logoff.
469
470 This currently doesnt work correctly as the domain controller 
471 returns NT_STATUS_INVALID_INFO_CLASS - we obviously need to
472 send a different info level. Right now though, I'm not sure
473 what that needs to be (I need to see one on the wire before
474 I can be sure). JRA.
475 ****************************************************************************/
476 BOOL cli_net_sam_logoff(const char* srv_name, const char* myhostname,
477                                 NET_ID_INFO_CTR *ctr)
478 {
479   DOM_CRED new_clnt_cred;
480   DOM_CRED dummy_rtn_creds;
481   prs_struct rbuf;
482   prs_struct buf; 
483   NET_Q_SAM_LOGOFF q_s;
484   uint16 validation_level = 3;
485   BOOL ok = False;
486
487         struct cli_connection *con = NULL;
488
489         if (!cli_connection_getsrv(srv_name, PIPE_NETLOGON, &con))
490         {
491                 return False;
492         }
493
494   cli_con_gen_next_creds( con, &new_clnt_cred);
495
496   prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
497   prs_init(&rbuf, 0,    4, SAFETY_MARGIN, True );
498
499   /* create and send a MSRPC command with api NET_SAMLOGOFF */
500
501   DEBUG(4,("cli_net_sam_logoff: srv:%s mc:%s clnt %s %x ll: %d\n",
502             srv_name, myhostname,
503             credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time,
504             ctr->switch_value));
505
506   memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
507
508   /* store the parameters */
509   make_sam_info(&(q_s.sam_id), srv_name, myhostname,
510                 &new_clnt_cred, &dummy_rtn_creds, ctr->switch_value, ctr, validation_level);
511
512   /* turn parameters into data stream */
513   net_io_q_sam_logoff("", &q_s,  &buf, 0);
514
515   /* send the data on \PIPE\ */
516   if (rpc_con_pipe_req(con, NET_SAMLOGOFF, &buf, &rbuf))
517   {
518     NET_R_SAM_LOGOFF r_s;
519
520     net_io_r_sam_logoff("", &r_s, &rbuf, 0);
521     ok = (rbuf.offset != 0);
522                 
523     if (ok && r_s.status != 0)
524     {
525       /* report error code */
526       DEBUG(5,("cli_net_sam_logoff: %s\n", get_nt_error_msg(r_s.status)));
527       ok = False;
528     }
529
530     /* Update the credentials. */
531     if (ok && !cli_con_deal_with_creds(con, &(r_s.srv_creds)))
532     {
533       /*
534        * Server replied with bad credential. Fail.
535        */
536       DEBUG(5,("cli_net_sam_logoff: server %s replied with bad credential \
537 (bad trust account password ?).\n", srv_name ));
538       ok = False;
539     }
540   }
541
542   prs_mem_free(&rbuf);
543   prs_mem_free(&buf );
544
545   return ok;
546 }
547
548 /***************************************************************************
549 Synchronise SAM Database (requires SEC_CHAN_BDC).
550 ****************************************************************************/
551 BOOL cli_net_sam_sync( const char* srv_name, const char* myhostname,
552                                 uint32 database_id,
553                                 uint32 *num_deltas,
554                                 SAM_DELTA_HDR *hdr_deltas,
555                                 SAM_DELTA_CTR *deltas)
556 {
557         NET_Q_SAM_SYNC q_s;
558         prs_struct rbuf;
559         prs_struct buf; 
560         DOM_CRED new_clnt_cred;
561         BOOL ok = False;
562         uint8 sess_key[16];
563         
564         struct cli_connection *con = NULL;
565
566         if (!cli_connection_getsrv(srv_name, PIPE_NETLOGON, &con))
567         {
568                 return False;
569         }
570
571         if (!cli_get_con_sesskey(con, sess_key))
572         {
573                 return False;
574         }
575
576         cli_con_gen_next_creds(con, &new_clnt_cred);
577         
578         prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
579         prs_init(&rbuf, 0,    4, SAFETY_MARGIN, True );
580         
581         /* create and send a MSRPC command with api NET_SAM_SYNC */
582         
583         make_q_sam_sync(&q_s, srv_name, myhostname,
584                         &new_clnt_cred, database_id);
585         
586         /* turn parameters into data stream */
587         net_io_q_sam_sync("", &q_s,  &buf, 0);
588         
589         /* send the data on \PIPE\ */
590         if (rpc_con_pipe_req(con, NET_SAM_SYNC, &buf, &rbuf))
591         {
592                 NET_R_SAM_SYNC r_s;
593
594                 r_s.hdr_deltas = hdr_deltas;
595                 r_s.deltas = deltas;
596
597                 net_io_r_sam_sync("", sess_key, &r_s, &rbuf, 0);
598                 ok = (rbuf.offset != 0);
599
600                 if (ok && r_s.status != 0 && r_s.status != STATUS_MORE_ENTRIES)
601                 {
602                         /* report error code */
603                         DEBUG(5,("cli_net_sam_sync: %s\n", get_nt_error_msg(r_s.status)));
604                         ok = False;
605                 }
606                 
607                 /* Update the credentials. */
608                 if (ok && !cli_con_deal_with_creds(con, &(r_s.srv_creds)))
609                 {
610                         DEBUG(5,("cli_net_sam_sync: server %s replied with bad \
611 credential (bad trust account password ?).\n", srv_name));
612                         ok = False;
613                 }
614
615                 if (ok)
616                 {
617                         *num_deltas = r_s.num_deltas2;
618
619                         if (r_s.status == STATUS_MORE_ENTRIES)
620                         {
621                                 DEBUG(5, ("(More entries)\n"));
622                         }
623                 }
624         }
625         
626         prs_mem_free(&rbuf);
627         prs_mem_free(&buf );
628         
629         return ok;
630 }