rpcclient interactive login (with trust account changing if you are root)
[samba.git] / source3 / 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 extern pstring scope;
34 extern pstring global_myname;
35 extern fstring global_myworkgroup;
36
37 /****************************************************************************
38 Generate the next creds to use.
39 ****************************************************************************/
40
41 static void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred)
42 {
43   /*
44    * Create the new client credentials.
45    */
46
47   cli->clnt_cred.timestamp.time = time(NULL);
48
49   memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred));
50
51   /* Calculate the new credentials. */
52   cred_create(cli->sess_key, &(cli->clnt_cred.challenge),
53               new_clnt_cred->timestamp, &(new_clnt_cred->challenge));
54
55 }
56
57 #if UNUSED_CODE
58 /****************************************************************************
59 do a LSA Logon Control2
60 ****************************************************************************/
61 BOOL cli_net_logon_ctrl2(struct cli_state *cli, uint32 status_level)
62 {
63   prs_struct rbuf;
64   prs_struct buf; 
65   NET_Q_LOGON_CTRL2 q_l;
66   BOOL ok = False;
67
68   prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
69   prs_init(&rbuf, 0,    4, SAFETY_MARGIN, True );
70
71   /* create and send a MSRPC command with api NET_LOGON_CTRL2 */
72
73   DEBUG(4,("do_net_logon_ctrl2 from %s status level:%x\n",
74            global_myname, status_level));
75
76   /* store the parameters */
77   make_q_logon_ctrl2(&q_l, cli->srv_name_slash, status_level);
78
79   /* turn parameters into data stream */
80   net_io_q_logon_ctrl2("", &q_l,  &buf, 0);
81
82   /* send the data on \PIPE\ */
83   if (rpc_api_pipe_req(cli, NET_LOGON_CTRL2, &buf, &rbuf))
84   {
85     NET_R_LOGON_CTRL2 r_l;
86
87     net_io_r_logon_ctrl2("", &r_l, &rbuf, 0);
88     ok = (rbuf.offset != 0);
89                 
90     if (ok && r_l.status != 0)
91     {
92       /* report error code */
93       DEBUG(0,("do_net_logon_ctrl2: Error %s\n", get_nt_error_msg(r_l.status)));
94       cli->nt_error = r_l.status;
95       ok = False;
96     }
97   }
98
99   prs_mem_free(&rbuf);
100   prs_mem_free(&buf );
101
102   return ok;
103 }
104 #endif
105
106 /****************************************************************************
107 LSA Authenticate 2
108
109 Send the client credential, receive back a server credential.
110 Ensure that the server credential returned matches the session key 
111 encrypt of the server challenge originally received. JRA.
112 ****************************************************************************/
113
114 BOOL cli_net_auth2(struct cli_state *cli, uint16 sec_chan, 
115                    uint32 neg_flags, DOM_CHAL *srv_chal)
116 {
117   prs_struct rbuf;
118   prs_struct buf; 
119   NET_Q_AUTH_2 q_a;
120   BOOL ok = False;
121
122   prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
123   prs_init(&rbuf, 0,    4, SAFETY_MARGIN, True );
124
125   /* create and send a MSRPC command with api NET_AUTH2 */
126
127   DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
128          cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname,
129          credstr(cli->clnt_cred.challenge.data), neg_flags));
130
131   /* store the parameters */
132   make_q_auth_2(&q_a, cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname,
133                 &cli->clnt_cred.challenge, neg_flags);
134
135   /* turn parameters into data stream */
136   net_io_q_auth_2("", &q_a,  &buf, 0);
137
138   /* send the data on \PIPE\ */
139   if (rpc_api_pipe_req(cli, NET_AUTH2, &buf, &rbuf))
140   {
141     NET_R_AUTH_2 r_a;
142
143     net_io_r_auth_2("", &r_a, &rbuf, 0);
144     ok = (rbuf.offset != 0);
145                 
146     if (ok && r_a.status != 0)
147     {
148       /* report error code */
149       DEBUG(0,("cli_net_auth2: Error %s\n", get_nt_error_msg(r_a.status)));
150       cli->nt_error = r_a.status;
151       ok = False;
152     }
153
154     if (ok)
155     {
156       /* 
157        * Check the returned value using the initial
158        * server received challenge.
159        */
160       UTIME zerotime;
161
162       zerotime.time = 0;
163       if(cred_assert( &r_a.srv_chal, cli->sess_key, srv_chal, zerotime) == 0) {
164         /*
165          * Server replied with bad credential. Fail.
166          */
167         DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
168 password ?).\n", cli->desthost ));
169         ok = False;
170       }
171     }
172
173     if (ok && r_a.srv_flgs.neg_flags != q_a.clnt_flgs.neg_flags)
174     {
175       /* report different neg_flags */
176       DEBUG(0,("cli_net_auth2: error neg_flags (q,r) differ - (%x,%x)\n",
177           q_a.clnt_flgs.neg_flags, r_a.srv_flgs.neg_flags));
178       ok = False;
179     }
180
181   }
182
183   prs_mem_free(&rbuf);
184   prs_mem_free(&buf );
185
186   return ok;
187 }
188
189 /****************************************************************************
190 LSA Request Challenge. Sends our challenge to server, then gets
191 server response. These are used to generate the credentials.
192 ****************************************************************************/
193
194 BOOL cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal)
195 {
196   prs_struct rbuf;
197   prs_struct buf; 
198   NET_Q_REQ_CHAL q_c;
199   BOOL valid_chal = False;
200
201   if (srv_chal == NULL || clnt_chal == NULL)
202     return False;
203
204   prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
205   prs_init(&rbuf, 0,    4, SAFETY_MARGIN, True );
206
207   /* create and send a MSRPC command with api NET_REQCHAL */
208
209   DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s: %s\n",
210          cli->desthost, global_myname, credstr(clnt_chal->data)));
211
212   /* store the parameters */
213   make_q_req_chal(&q_c, cli->srv_name_slash, global_myname, clnt_chal);
214
215   /* turn parameters into data stream */
216   net_io_q_req_chal("", &q_c,  &buf, 0);
217
218   /* send the data on \PIPE\ */
219   if (rpc_api_pipe_req(cli, NET_REQCHAL, &buf, &rbuf))
220   {
221     NET_R_REQ_CHAL r_c;
222     BOOL ok;
223
224     net_io_r_req_chal("", &r_c, &rbuf, 0);
225     ok = (rbuf.offset != 0);
226                 
227     if (ok && r_c.status != 0)
228     {
229       /* report error code */
230       DEBUG(0,("cli_net_req_chal: Error %s\n", get_nt_error_msg(r_c.status)));
231       cli->nt_error = r_c.status;
232       ok = False;
233     }
234
235     if (ok)
236     {
237       /* ok, at last: we're happy. return the challenge */
238       memcpy(srv_chal, r_c.srv_chal.data, sizeof(srv_chal->data));
239       valid_chal = True;
240     }
241   }
242
243   prs_mem_free(&rbuf);
244   prs_mem_free(&buf );
245
246   return valid_chal;
247 }
248
249 /***************************************************************************
250 LSA Server Password Set.
251 ****************************************************************************/
252
253 BOOL cli_net_srv_pwset(struct cli_state *cli, uint8 hashed_mach_pwd[16])
254 {
255   prs_struct rbuf;
256   prs_struct buf; 
257   DOM_CRED new_clnt_cred;
258   NET_Q_SRV_PWSET q_s;
259   BOOL ok = False;
260   uint16 sec_chan_type = 2;
261
262   gen_next_creds( cli, &new_clnt_cred);
263
264   prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
265   prs_init(&rbuf, 0,    4, SAFETY_MARGIN, True );
266
267   /* create and send a MSRPC command with api NET_SRV_PWSET */
268
269   DEBUG(4,("cli_net_srv_pwset: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
270            cli->srv_name_slash, cli->mach_acct, sec_chan_type, global_myname,
271            credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
272
273   /* store the parameters */
274   make_q_srv_pwset(&q_s, cli->srv_name_slash, cli->mach_acct, sec_chan_type,
275                    global_myname, &new_clnt_cred, (char *)hashed_mach_pwd);
276
277   /* turn parameters into data stream */
278   net_io_q_srv_pwset("", &q_s,  &buf, 0);
279
280   /* send the data on \PIPE\ */
281   if (rpc_api_pipe_req(cli, NET_SRVPWSET, &buf, &rbuf))
282   {
283     NET_R_SRV_PWSET r_s;
284
285     net_io_r_srv_pwset("", &r_s, &rbuf, 0);
286     ok = (rbuf.offset != 0);
287                 
288     if (ok && r_s.status != 0)
289     {
290       /* report error code */
291       DEBUG(0,("cli_net_srv_pwset: %s\n", get_nt_error_msg(r_s.status)));
292       cli->nt_error = r_s.status;
293       ok = False;
294     }
295
296     /* Update the credentials. */
297     if (ok && !clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_cred)))
298     {
299       /*
300        * Server replied with bad credential. Fail.
301        */
302       DEBUG(0,("cli_net_srv_pwset: server %s replied with bad credential (bad machine \
303 password ?).\n", cli->desthost ));
304       ok = False;
305     }
306   }
307
308   prs_mem_free(&rbuf);
309   prs_mem_free(&buf );
310
311   return ok;
312 }
313
314 /***************************************************************************
315 LSA SAM Logon - interactive or network.
316 ****************************************************************************/
317
318 BOOL cli_net_sam_logon(struct cli_state *cli, NET_ID_INFO_CTR *ctr, 
319                        NET_USER_INFO_3 *user_info3)
320 {
321   DOM_CRED new_clnt_cred;
322   DOM_CRED dummy_rtn_creds;
323   prs_struct rbuf;
324   prs_struct buf; 
325   uint16 validation_level = 3;
326   NET_Q_SAM_LOGON q_s;
327   BOOL ok = False;
328
329   gen_next_creds( cli, &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_SAMLOGON */
335
336   DEBUG(4,("cli_net_sam_logon: srv:%s mc:%s clnt %s %x ll: %d\n",
337              cli->srv_name_slash, global_myname, 
338              credstr(new_clnt_cred.challenge.data), cli->clnt_cred.timestamp.time,
339              ctr->switch_value));
340
341   memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
342
343   /* store the parameters */
344   make_sam_info(&(q_s.sam_id), cli->srv_name_slash, global_myname,
345          &new_clnt_cred, &dummy_rtn_creds, ctr->switch_value, ctr, validation_level);
346
347   /* turn parameters into data stream */
348   net_io_q_sam_logon("", &q_s,  &buf, 0);
349
350   /* send the data on \PIPE\ */
351   if (rpc_api_pipe_req(cli, NET_SAMLOGON, &buf, &rbuf))
352   {
353     NET_R_SAM_LOGON r_s;
354
355     r_s.user = user_info3;
356
357     net_io_r_sam_logon("", &r_s, &rbuf, 0);
358     ok = (rbuf.offset != 0);
359                 
360     if (ok && r_s.status != 0)
361     {
362       /* report error code */
363       DEBUG(0,("cli_net_sam_logon: %s\n", get_nt_error_msg(r_s.status)));
364       cli->nt_error = r_s.status;
365       ok = False;
366     }
367
368     /* Update the credentials. */
369     if (ok && !clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_creds)))
370     {
371       /*
372        * Server replied with bad credential. Fail.
373        */
374       DEBUG(0,("cli_net_sam_logon: server %s replied with bad credential (bad machine \
375 password ?).\n", cli->desthost ));
376         ok = False;
377     }
378
379     if (ok && r_s.switch_value != 3)
380     {
381       /* report different switch_value */
382       DEBUG(0,("cli_net_sam_logon: switch_value of 3 expected %x\n",
383                    r_s.switch_value));
384       ok = False;
385     }
386   }
387
388   prs_mem_free(&rbuf);
389   prs_mem_free(&buf );
390
391   return ok;
392 }
393
394 /***************************************************************************
395 LSA SAM Logoff.
396
397 This currently doesnt work correctly as the domain controller 
398 returns NT_STATUS_INVALID_INFO_CLASS - we obviously need to
399 send a different info level. Right now though, I'm not sure
400 what that needs to be (I need to see one on the wire before
401 I can be sure). JRA.
402 ****************************************************************************/
403 BOOL cli_net_sam_logoff(struct cli_state *cli, NET_ID_INFO_CTR *ctr)
404 {
405   DOM_CRED new_clnt_cred;
406   DOM_CRED dummy_rtn_creds;
407   prs_struct rbuf;
408   prs_struct buf; 
409   NET_Q_SAM_LOGOFF q_s;
410   uint16 validation_level = 3;
411   BOOL ok = False;
412
413   gen_next_creds( cli, &new_clnt_cred);
414
415   prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
416   prs_init(&rbuf, 0,    4, SAFETY_MARGIN, True );
417
418   /* create and send a MSRPC command with api NET_SAMLOGOFF */
419
420   DEBUG(4,("cli_net_sam_logoff: srv:%s mc:%s clnt %s %x ll: %d\n",
421             cli->srv_name_slash, global_myname,
422             credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time,
423             ctr->switch_value));
424
425   memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
426
427   /* store the parameters */
428   make_sam_info(&(q_s.sam_id), cli->srv_name_slash, global_myname,
429                 &new_clnt_cred, &dummy_rtn_creds, ctr->switch_value, ctr, validation_level);
430
431   /* turn parameters into data stream */
432   net_io_q_sam_logoff("", &q_s,  &buf, 0);
433
434   /* send the data on \PIPE\ */
435   if (rpc_api_pipe_req(cli, NET_SAMLOGOFF, &buf, &rbuf))
436   {
437     NET_R_SAM_LOGOFF r_s;
438
439     net_io_r_sam_logoff("", &r_s, &rbuf, 0);
440     ok = (rbuf.offset != 0);
441                 
442     if (ok && r_s.status != 0)
443     {
444       /* report error code */
445       DEBUG(0,("cli_net_sam_logoff: %s\n", get_nt_error_msg(r_s.status)));
446       cli->nt_error = r_s.status;
447       ok = False;
448     }
449
450     /* Update the credentials. */
451     if (ok && !clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_creds)))
452     {
453       /*
454        * Server replied with bad credential. Fail.
455        */
456       DEBUG(0,("cli_net_sam_logoff: server %s replied with bad credential (bad machine \
457 password ?).\n", cli->desthost ));
458       ok = False;
459     }
460   }
461
462   prs_mem_free(&rbuf);
463   prs_mem_free(&buf );
464
465   return ok;
466 }
467
468 /*********************************************************
469  Change the domain password on the PDC.
470 **********************************************************/
471
472 static BOOL modify_trust_password( char *domain, char *remote_machine, 
473                           unsigned char orig_trust_passwd_hash[16],
474                           unsigned char new_trust_passwd_hash[16])
475 {
476   struct cli_state cli;
477   struct nmb_name calling, called;
478
479   ZERO_STRUCT(cli);
480   if(cli_initialise(&cli) == False) {
481     DEBUG(0,("modify_trust_password: unable to initialize client connection.\n"));
482     return False;
483   }
484
485   if(!resolve_name( remote_machine, &cli.dest_ip, 0x20)) {
486     DEBUG(0,("modify_trust_password: Can't resolve address for %s\n", remote_machine));
487     return False;
488   }
489
490   if (ismyip(cli.dest_ip)) {
491     DEBUG(0,("modify_trust_password: Machine %s is one of our addresses. Cannot add \
492 to ourselves.\n", remote_machine));
493     return False;
494   }
495
496   if (!cli_connect(&cli, remote_machine, &cli.dest_ip)) {
497     DEBUG(0,("modify_trust_password: unable to connect to SMB server on \
498 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
499     return False;
500   }
501     
502   
503         make_nmb_name(&calling, global_myname , 0x0 , scope);
504         make_nmb_name(&called , remote_machine, 0x20, scope);
505
506         if (!cli_session_request(&cli, &calling, &called))
507         {
508     DEBUG(0,("modify_trust_password: machine %s rejected the session setup. \
509 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
510     cli_shutdown(&cli);
511     return False;
512   }
513
514   cli.protocol = PROTOCOL_NT1;
515     
516   if (!cli_negprot(&cli)) {
517     DEBUG(0,("modify_trust_password: machine %s rejected the negotiate protocol. \
518 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
519     cli_shutdown(&cli);
520     return False;
521   }
522   if (cli.protocol != PROTOCOL_NT1) {
523     DEBUG(0,("modify_trust_password: machine %s didn't negotiate NT protocol.\n", 
524             remote_machine));
525     cli_shutdown(&cli);
526     return False;
527   }
528     
529   /*
530    * Do an anonymous session setup.
531    */
532     
533   if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
534     DEBUG(0,("modify_trust_password: machine %s rejected the session setup. \
535 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
536     cli_shutdown(&cli);
537     return False;
538   }
539     
540   if (!(cli.sec_mode & 1)) {
541     DEBUG(0,("modify_trust_password: machine %s isn't in user level security mode\n",
542           remote_machine));
543     cli_shutdown(&cli);
544     return False;
545   }
546     
547   if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
548     DEBUG(0,("modify_trust_password: machine %s rejected the tconX on the IPC$ share. \
549 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
550     cli_shutdown(&cli);
551     return False;
552   }
553
554   /*
555    * Ok - we have an anonymous connection to the IPC$ share.
556    * Now start the NT Domain stuff :-).
557    */
558     
559   if(cli_nt_session_open(&cli, PIPE_NETLOGON, False) == False) {
560     DEBUG(0,("modify_trust_password: unable to open the domain client session to \
561 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
562     cli_nt_session_close(&cli);
563     cli_ulogoff(&cli);
564     cli_shutdown(&cli);
565     return False;
566   } 
567   
568   if(cli_nt_setup_creds(&cli, orig_trust_passwd_hash) == False) {
569     DEBUG(0,("modify_trust_password: unable to setup the PDC credentials to machine \
570 %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
571     cli_nt_session_close(&cli);
572     cli_ulogoff(&cli);
573     cli_shutdown(&cli);
574     return False;
575   } 
576
577   if( cli_nt_srv_pwset( &cli,new_trust_passwd_hash ) == False) {
578     DEBUG(0,("modify_trust_password: unable to change password for machine %s in domain \
579 %s to Domain controller %s. Error was %s.\n", global_myname, domain, remote_machine, 
580                             cli_errstr(&cli)));
581     cli_close(&cli, cli.nt_pipe_fnum);
582     cli_ulogoff(&cli);
583     cli_shutdown(&cli);
584     return False;
585   }
586
587   cli_nt_session_close(&cli);
588   cli_ulogoff(&cli);
589   cli_shutdown(&cli);
590
591   return True;
592 }
593
594 /************************************************************************
595  Change the trust account password for a domain.
596  The user of this function must have locked the trust password file for
597  update.
598 ************************************************************************/
599
600 BOOL change_trust_account_password( char *domain, char *remote_machine_list)
601 {
602   fstring remote_machine;
603   unsigned char old_trust_passwd_hash[16];
604   unsigned char new_trust_passwd_hash[16];
605   time_t lct;
606   BOOL res;
607
608   if(!get_trust_account_password( old_trust_passwd_hash, &lct)) {
609     DEBUG(0,("change_trust_account_password: unable to read the machine \
610 account password for domain %s.\n", domain));
611     return False;
612   }
613
614   /*
615    * Create the new (random) password.
616    */
617   generate_random_buffer( new_trust_passwd_hash, 16, True);
618
619   while(remote_machine_list && 
620         next_token(&remote_machine_list, remote_machine, 
621                    LIST_SEP, sizeof(remote_machine))) {
622     strupper(remote_machine);
623     if(modify_trust_password( domain, remote_machine, 
624                               old_trust_passwd_hash, new_trust_passwd_hash)) {
625       DEBUG(0,("%s : change_trust_account_password: Changed password for \
626 domain %s.\n", timestring(), domain));
627       /*
628        * Return the result of trying to write the new password
629        * back into the trust account file.
630        */
631       res = set_trust_account_password(new_trust_passwd_hash);
632       memset(new_trust_passwd_hash, 0, 16);
633       memset(old_trust_passwd_hash, 0, 16);
634       return res;
635     }
636   }
637
638   memset(new_trust_passwd_hash, 0, 16);
639   memset(old_trust_passwd_hash, 0, 16);
640
641   DEBUG(0,("%s : change_trust_account_password: Failed to change password for \
642 domain %s.\n", timestring(), domain));
643   return False;
644 }