Serious (and I *mean* serious) attempt to fix little/bigendian RPC issues.
[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 extern pstring global_myname;
34 extern fstring global_myworkgroup;
35
36 /****************************************************************************
37 Generate the next creds to use.
38 ****************************************************************************/
39
40 static void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred)
41 {
42   /*
43    * Create the new client credentials.
44    */
45
46   cli->clnt_cred.timestamp.time = time(NULL);
47
48   memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred));
49
50   /* Calculate the new credentials. */
51   cred_create(cli->sess_key, &(cli->clnt_cred.challenge),
52               new_clnt_cred->timestamp, &(new_clnt_cred->challenge));
53
54 }
55
56 #if UNUSED_CODE
57 /****************************************************************************
58 do a LSA Logon Control2
59 ****************************************************************************/
60 BOOL cli_net_logon_ctrl2(struct cli_state *cli, uint32 status_level)
61 {
62   prs_struct rbuf;
63   prs_struct buf; 
64   NET_Q_LOGON_CTRL2 q_l;
65   BOOL ok = False;
66
67   prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
68   prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
69
70   /* create and send a MSRPC command with api NET_LOGON_CTRL2 */
71
72   DEBUG(4,("do_net_logon_ctrl2 from %s status level:%x\n",
73            global_myname, status_level));
74
75   /* store the parameters */
76   init_q_logon_ctrl2(&q_l, unix_to_dos(cli->srv_name_slash,False), 
77                      status_level);
78
79   /* turn parameters into data stream */
80   if(!net_io_q_logon_ctrl2("", &q_l,  &buf, 0)) {
81     DEBUG(0,("cli_net_logon_ctrl2: Error : failed to marshall NET_Q_LOGON_CTRL2 struct.\n"));
82     prs_mem_free(&buf);
83     prs_mem_free(&rbuf);
84     return False;
85   }
86
87   /* send the data on \PIPE\ */
88   if (rpc_api_pipe_req(cli, NET_LOGON_CTRL2, &buf, &rbuf))
89   {
90     NET_R_LOGON_CTRL2 r_l;
91
92     /*
93      * Unmarshall the return buffer.
94      */
95     ok = net_io_r_logon_ctrl2("", &r_l, &rbuf, 0);
96                 
97     if (ok && r_l.status != 0)
98     {
99       /* report error code */
100       DEBUG(0,("do_net_logon_ctrl2: Error %s\n", get_nt_error_msg(r_l.status)));
101       cli->nt_error = r_l.status;
102       ok = False;
103     }
104   }
105
106   prs_mem_free(&buf);
107   prs_mem_free(&rbuf);
108
109   return ok;
110 }
111 #endif
112
113 /****************************************************************************
114 LSA Authenticate 2
115
116 Send the client credential, receive back a server credential.
117 Ensure that the server credential returned matches the session key 
118 encrypt of the server challenge originally received. JRA.
119 ****************************************************************************/
120
121 BOOL cli_net_auth2(struct cli_state *cli, uint16 sec_chan, 
122                    uint32 neg_flags, DOM_CHAL *srv_chal)
123 {
124   prs_struct rbuf;
125   prs_struct buf; 
126   NET_Q_AUTH_2 q_a;
127   BOOL ok = False;
128
129   prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
130   prs_init(&rbuf, 0,    cli->mem_ctx, UNMARSHALL);
131
132   /* create and send a MSRPC command with api NET_AUTH2 */
133
134   DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
135            cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname,
136            credstr(cli->clnt_cred.challenge.data), neg_flags));
137
138   /* store the parameters */
139   init_q_auth_2(&q_a, unix_to_dos(cli->srv_name_slash,False), cli->mach_acct, 
140                 sec_chan, global_myname, &cli->clnt_cred.challenge, neg_flags);
141
142   /* turn parameters into data stream */
143   if(!net_io_q_auth_2("", &q_a,  &buf, 0)) {
144     DEBUG(0,("cli_net_auth2: Error : failed to marshall NET_Q_AUTH_2 struct.\n"));
145     prs_mem_free(&buf);
146     prs_mem_free(&rbuf);
147     return False;
148   }
149
150   /* send the data on \PIPE\ */
151   if (rpc_api_pipe_req(cli, NET_AUTH2, &buf, &rbuf))
152   {
153     NET_R_AUTH_2 r_a;
154
155     ok = net_io_r_auth_2("", &r_a, &rbuf, 0);
156                 
157     if (ok && r_a.status != 0)
158     {
159       /* report error code */
160       DEBUG(0,("cli_net_auth2: Error %s\n", get_nt_error_msg(r_a.status)));
161       cli->nt_error = r_a.status;
162       ok = False;
163     }
164
165     if (ok)
166     {
167       /* 
168        * Check the returned value using the initial
169        * server received challenge.
170        */
171       UTIME zerotime;
172
173       zerotime.time = 0;
174       if(cred_assert( &r_a.srv_chal, cli->sess_key, srv_chal, zerotime) == 0) {
175         /*
176          * Server replied with bad credential. Fail.
177          */
178         DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
179 password ?).\n", cli->desthost ));
180         ok = False;
181       }
182     }
183
184 #if 0
185     /*
186      * Try commenting this out to see if this makes the connect
187      * work for a NT 3.51 PDC. JRA.
188      */
189
190     if (ok && r_a.srv_flgs.neg_flags != q_a.clnt_flgs.neg_flags)
191     {
192       /* report different neg_flags */
193       DEBUG(0,("cli_net_auth2: error neg_flags (q,r) differ - (%x,%x)\n",
194           q_a.clnt_flgs.neg_flags, r_a.srv_flgs.neg_flags));
195       ok = False;
196     }
197 #endif
198
199   }
200
201   prs_mem_free(&buf);
202   prs_mem_free(&rbuf);
203
204   return ok;
205 }
206
207 /****************************************************************************
208 LSA Request Challenge. Sends our challenge to server, then gets
209 server response. These are used to generate the credentials.
210 ****************************************************************************/
211
212 BOOL cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal)
213 {
214   prs_struct rbuf;
215   prs_struct buf; 
216   NET_Q_REQ_CHAL q_c;
217   BOOL valid_chal = False;
218
219   prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
220   prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
221
222   /* create and send a MSRPC command with api NET_REQCHAL */
223
224   DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s: %s\n",
225          cli->desthost, global_myname, credstr(clnt_chal->data)));
226
227   /* store the parameters */
228   init_q_req_chal(&q_c, unix_to_dos(cli->srv_name_slash,False), 
229                   global_myname, clnt_chal);
230
231   /* turn parameters into data stream */
232   if(!net_io_q_req_chal("", &q_c,  &buf, 0)) {
233     DEBUG(0,("cli_net_req_chal: Error : failed to marshall NET_Q_REQ_CHAL struct.\n"));
234     prs_mem_free(&buf);
235     prs_mem_free(&rbuf);
236     return False;
237   }
238
239   /* send the data on \PIPE\ */
240   if (rpc_api_pipe_req(cli, NET_REQCHAL, &buf, &rbuf))
241   {
242     NET_R_REQ_CHAL r_c;
243     BOOL ok;
244
245     ok = net_io_r_req_chal("", &r_c, &rbuf, 0);
246                 
247     if (ok && r_c.status != 0)
248     {
249       /* report error code */
250       DEBUG(0,("cli_net_req_chal: Error %s\n", get_nt_error_msg(r_c.status)));
251       cli->nt_error = r_c.status;
252       ok = False;
253     }
254
255     if (ok)
256     {
257       /* ok, at last: we're happy. return the challenge */
258       memcpy(srv_chal, r_c.srv_chal.data, sizeof(srv_chal->data));
259       valid_chal = True;
260     }
261   }
262
263   prs_mem_free(&buf);
264   prs_mem_free(&rbuf);
265
266   return valid_chal;
267 }
268
269 /***************************************************************************
270 LSA Server Password Set.
271 ****************************************************************************/
272
273 BOOL cli_net_srv_pwset(struct cli_state *cli, uint8 hashed_mach_pwd[16])
274 {
275   prs_struct rbuf;
276   prs_struct buf; 
277   DOM_CRED new_clnt_cred;
278   NET_Q_SRV_PWSET q_s;
279   BOOL ok = False;
280   uint16 sec_chan_type = 2;
281
282   gen_next_creds( cli, &new_clnt_cred);
283
284   prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
285   prs_init(&rbuf, 0,    cli->mem_ctx, UNMARSHALL);
286
287   /* create and send a MSRPC command with api NET_SRV_PWSET */
288
289   DEBUG(4,("cli_net_srv_pwset: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
290            cli->srv_name_slash, cli->mach_acct, sec_chan_type, global_myname,
291            credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
292
293   /* store the parameters */
294   init_q_srv_pwset(&q_s, unix_to_dos(cli->srv_name_slash,False), 
295                    cli->mach_acct, sec_chan_type, global_myname, 
296                    &new_clnt_cred, (char *)hashed_mach_pwd);
297
298   /* turn parameters into data stream */
299   if(!net_io_q_srv_pwset("", &q_s,  &buf, 0)) {
300     DEBUG(0,("cli_net_srv_pwset: Error : failed to marshall NET_Q_SRV_PWSET struct.\n"));
301     prs_mem_free(&buf);
302     prs_mem_free(&rbuf);
303     return False;
304   }
305
306   /* send the data on \PIPE\ */
307   if (rpc_api_pipe_req(cli, NET_SRVPWSET, &buf, &rbuf))
308   {
309     NET_R_SRV_PWSET r_s;
310
311     ok = net_io_r_srv_pwset("", &r_s, &rbuf, 0);
312                 
313     if (ok && r_s.status != 0)
314     {
315       /* report error code */
316       DEBUG(0,("cli_net_srv_pwset: %s\n", get_nt_error_msg(r_s.status)));
317       cli->nt_error = r_s.status;
318       ok = False;
319     }
320
321     /* Update the credentials. */
322     if (ok && !clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_cred)))
323     {
324       /*
325        * Server replied with bad credential. Fail.
326        */
327       DEBUG(0,("cli_net_srv_pwset: server %s replied with bad credential (bad machine \
328 password ?).\n", cli->desthost ));
329       ok = False;
330     }
331   }
332
333   prs_mem_free(&buf);
334   prs_mem_free(&rbuf);
335
336   return ok;
337 }
338
339 /***************************************************************************
340  LSA SAM Logon internal - interactive or network. Does level 2 or 3 but always
341  returns level 3.
342 ****************************************************************************/
343
344 static uint32 cli_net_sam_logon_internal(struct cli_state *cli, NET_ID_INFO_CTR *ctr, 
345                        NET_USER_INFO_3 *user_info3, uint16 validation_level)
346 {
347         DOM_CRED new_clnt_cred;
348         DOM_CRED dummy_rtn_creds;
349         prs_struct rbuf;
350         prs_struct buf; 
351         NET_Q_SAM_LOGON q_s;
352         NET_R_SAM_LOGON r_s;
353         uint32 retval;
354
355         gen_next_creds( cli, &new_clnt_cred);
356
357         prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
358         prs_init(&rbuf, 0,    cli->mem_ctx, UNMARSHALL);
359
360         /* create and send a MSRPC command with api NET_SAMLOGON */
361
362         DEBUG(4,("cli_net_sam_logon_internal: srv:%s mc:%s clnt %s %x ll: %d\n",
363              cli->srv_name_slash, global_myname, 
364              credstr(new_clnt_cred.challenge.data), cli->clnt_cred.timestamp.time,
365              ctr->switch_value));
366
367         memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
368         dummy_rtn_creds.timestamp.time = time(NULL);
369
370         /* store the parameters */
371         q_s.validation_level = validation_level;
372         init_sam_info(&q_s.sam_id, unix_to_dos(cli->srv_name_slash,False), 
373                 global_myname, &new_clnt_cred, &dummy_rtn_creds, 
374                 ctr->switch_value, ctr);
375
376         /* turn parameters into data stream */
377         if(!net_io_q_sam_logon("", &q_s,  &buf, 0)) {
378                 DEBUG(0,("cli_net_sam_logon_internal: Error : failed to marshall NET_Q_SAM_LOGON struct.\n"));
379                 retval = NT_STATUS_NO_MEMORY;
380                 goto out;
381         }
382
383         /* send the data on \PIPE\ */
384         if (!rpc_api_pipe_req(cli, NET_SAMLOGON, &buf, &rbuf)) {
385                 DEBUG(0,("cli_net_sam_logon_internal: Erro rpc_api_pipe_req failed.\n"));
386                 retval = cli->nt_error;
387                 goto out;
388         }
389
390         r_s.user = user_info3;
391
392         if(!net_io_r_sam_logon("", &r_s, &rbuf, 0)) {
393                 DEBUG(0,("cli_net_sam_logon_internal: Error : failed to unmarshal NET_R_SAM_LOGON struct.\n"));
394                 retval = NT_STATUS_NO_MEMORY;
395                 goto out;
396         }
397                 
398         retval = r_s.status;
399
400         /*
401          * Don't treat NT_STATUS_INVALID_INFO_CLASS as an error - we will re-issue
402          * the call.
403          */
404         
405         if (retval == NT_STATUS_INVALID_INFO_CLASS) {
406                 goto out;
407         }
408
409         if (retval != 0) {
410                 /* report error code */
411                 DEBUG(0,("cli_net_sam_logon_internal: %s\n", get_nt_error_msg(r_s.status)));
412                 cli->nt_error = r_s.status;
413                 goto out;
414     }
415
416     /* Update the credentials. */
417     if (!clnt_deal_with_creds(cli->sess_key, &cli->clnt_cred, &r_s.srv_creds)) {
418                 /*
419                  * Server replied with bad credential. Fail.
420                  */
421                 DEBUG(0,("cli_net_sam_logon_internal: server %s replied with bad credential (bad machine \
422 password ?).\n", cli->desthost ));
423                 retval = NT_STATUS_WRONG_PASSWORD;
424     }
425
426     if (r_s.switch_value != validation_level) {
427                 /* report different switch_value */
428                 DEBUG(0,("cli_net_sam_logon: switch_value of %x expected %x\n", (unsigned int)validation_level,
429                                         (unsigned int)r_s.switch_value));
430                 retval = NT_STATUS_INVALID_PARAMETER;
431     }
432
433   out:
434
435         prs_mem_free(&buf);
436         prs_mem_free(&rbuf);
437
438         return retval;
439 }
440
441 /***************************************************************************
442 LSA SAM Logon - interactive or network.
443 ****************************************************************************/
444
445 BOOL cli_net_sam_logon(struct cli_state *cli, NET_ID_INFO_CTR *ctr, NET_USER_INFO_3 *user_info3)
446 {
447         BOOL ok = True;
448 #if 0 /* JRATEST */
449         uint16 validation_level=2;
450 #else
451         uint16 validation_level=3;
452 #endif
453         uint32 ret_err_code;
454
455         ret_err_code = cli_net_sam_logon_internal(cli, ctr, user_info3, validation_level);
456
457         if(ret_err_code == NT_STATUS_NOPROBLEMO) {
458                 DEBUG(10,("cli_net_sam_logon: Success \n"));
459                 ok = True;
460         } else if (ret_err_code == NT_STATUS_INVALID_INFO_CLASS) {
461                 DEBUG(10,("cli_net_sam_logon: STATUS INVALID INFO CLASS \n"));
462
463                 validation_level=2;
464
465                 /*
466                  * Since this is the second time we call this function, don't care
467                  * for the error. If its error, return False. 
468                  */
469
470                 if(cli_net_sam_logon_internal(cli, ctr, user_info3, validation_level) != 0)
471                         ok = False;
472
473         } else {
474                 DEBUG(10,("cli_net_sam_logon: Error\n"));
475                 ok = False;
476         }
477
478         return ok;
479 }
480
481 /***************************************************************************
482 LSA SAM Logoff.
483
484 This currently doesnt work correctly as the domain controller 
485 returns NT_STATUS_INVALID_INFO_CLASS - we obviously need to
486 send a different info level. Right now though, I'm not sure
487 what that needs to be (I need to see one on the wire before
488 I can be sure). JRA.
489 ****************************************************************************/
490 BOOL cli_net_sam_logoff(struct cli_state *cli, NET_ID_INFO_CTR *ctr)
491 {
492   DOM_CRED new_clnt_cred;
493   DOM_CRED dummy_rtn_creds;
494   prs_struct rbuf;
495   prs_struct buf; 
496   NET_Q_SAM_LOGOFF q_s;
497   BOOL ok = False;
498
499   gen_next_creds( cli, &new_clnt_cred);
500
501   prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
502   prs_init(&rbuf, 0,    cli->mem_ctx, UNMARSHALL);
503
504   /* create and send a MSRPC command with api NET_SAMLOGOFF */
505
506   DEBUG(4,("cli_net_sam_logoff: srv:%s mc:%s clnt %s %x ll: %d\n",
507             cli->srv_name_slash, global_myname,
508             credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time,
509             ctr->switch_value));
510
511   memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
512
513   init_sam_info(&q_s.sam_id, unix_to_dos(cli->srv_name_slash,False), 
514                 global_myname, &new_clnt_cred, &dummy_rtn_creds, 
515                 ctr->switch_value, ctr);
516
517   /* turn parameters into data stream */
518   if(!net_io_q_sam_logoff("", &q_s,  &buf, 0)) {
519     DEBUG(0,("cli_net_sam_logoff: Error : failed to marshall NET_Q_SAM_LOGOFF struct.\n"));
520     prs_mem_free(&buf);
521     prs_mem_free(&rbuf);
522     return False;
523   }
524
525   /* send the data on \PIPE\ */
526   if (rpc_api_pipe_req(cli, NET_SAMLOGOFF, &buf, &rbuf))
527   {
528     NET_R_SAM_LOGOFF r_s;
529
530     ok = net_io_r_sam_logoff("", &r_s, &rbuf, 0);
531                 
532     if (ok && r_s.status != 0)
533     {
534       /* report error code */
535       DEBUG(0,("cli_net_sam_logoff: %s\n", get_nt_error_msg(r_s.status)));
536       cli->nt_error = r_s.status;
537       ok = False;
538     }
539
540     /* Update the credentials. */
541     if (ok && !clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_creds)))
542     {
543       /*
544        * Server replied with bad credential. Fail.
545        */
546       DEBUG(0,("cli_net_sam_logoff: server %s replied with bad credential (bad machine \
547 password ?).\n", cli->desthost ));
548       ok = False;
549     }
550   }
551
552   prs_mem_free(&buf);
553   prs_mem_free(&rbuf);
554
555   return ok;
556 }
557
558 /*********************************************************
559  Change the domain password on the PDC.
560 **********************************************************/
561
562 static BOOL modify_trust_password( char *domain, char *remote_machine, 
563                           unsigned char orig_trust_passwd_hash[16],
564                           unsigned char new_trust_passwd_hash[16])
565 {
566   struct cli_state cli;
567
568   ZERO_STRUCT(cli);
569   if(cli_initialise(&cli) == False) {
570     DEBUG(0,("modify_trust_password: unable to initialize client connection.\n"));
571     return False;
572   }
573
574   if(!resolve_name( remote_machine, &cli.dest_ip, 0x20)) {
575     DEBUG(0,("modify_trust_password: Can't resolve address for %s\n", remote_machine));
576     cli_shutdown(&cli);
577     return False;
578   }
579
580   if (ismyip(cli.dest_ip)) {
581     DEBUG(0,("modify_trust_password: Machine %s is one of our addresses. Cannot add \
582 to ourselves.\n", remote_machine));
583     cli_shutdown(&cli);
584     return False;
585   }
586
587   if (!cli_connect(&cli, remote_machine, &cli.dest_ip)) {
588     DEBUG(0,("modify_trust_password: unable to connect to SMB server on \
589 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
590     cli_shutdown(&cli);
591     return False;
592   }
593   
594   if (!attempt_netbios_session_request(&cli, global_myname, remote_machine, &cli.dest_ip)) {
595     DEBUG(0,("modify_trust_password: machine %s rejected the NetBIOS \
596 session request. Error was %s\n", remote_machine, cli_errstr(&cli) ));
597     cli_shutdown(&cli);
598     return False;
599   }
600
601   cli.protocol = PROTOCOL_NT1;
602     
603   if (!cli_negprot(&cli)) {
604     DEBUG(0,("modify_trust_password: machine %s rejected the negotiate protocol. \
605 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
606     cli_shutdown(&cli);
607     return False;
608   }
609
610   if (cli.protocol != PROTOCOL_NT1) {
611     DEBUG(0,("modify_trust_password: machine %s didn't negotiate NT protocol.\n", 
612             remote_machine));
613     cli_shutdown(&cli);
614     return False;
615   }
616     
617   /*
618    * Do an anonymous session setup.
619    */
620     
621   if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
622     DEBUG(0,("modify_trust_password: machine %s rejected the session setup. \
623 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
624     cli_shutdown(&cli);
625     return False;
626   }
627     
628   if (!(cli.sec_mode & 1)) {
629     DEBUG(0,("modify_trust_password: machine %s isn't in user level security mode\n",
630           remote_machine));
631     cli_shutdown(&cli);
632     return False;
633   }
634     
635   if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
636     DEBUG(0,("modify_trust_password: machine %s rejected the tconX on the IPC$ share. \
637 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
638     cli_shutdown(&cli);
639     return False;
640   }
641
642   /*
643    * Ok - we have an anonymous connection to the IPC$ share.
644    * Now start the NT Domain stuff :-).
645    */
646
647   if(cli_lsa_get_domain_sid(&cli, remote_machine) == False) {
648     DEBUG(0,("modify_trust_password: unable to obtain domain sid from %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
649     cli_ulogoff(&cli);
650     cli_shutdown(&cli);
651     return False;
652   }
653
654   if(cli_nt_session_open(&cli, PIPE_NETLOGON) == False) {
655     DEBUG(0,("modify_trust_password: unable to open the domain client session to \
656 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
657     cli_nt_session_close(&cli);
658     cli_ulogoff(&cli);
659     cli_shutdown(&cli);
660     return False;
661   } 
662   
663   if(cli_nt_setup_creds(&cli, orig_trust_passwd_hash) == False) {
664     DEBUG(0,("modify_trust_password: unable to setup the PDC credentials to machine \
665 %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
666     cli_nt_session_close(&cli);
667     cli_ulogoff(&cli);
668     cli_shutdown(&cli);
669     return False;
670   } 
671
672   if( cli_nt_srv_pwset( &cli,new_trust_passwd_hash ) == False) {
673     DEBUG(0,("modify_trust_password: unable to change password for machine %s in domain \
674 %s to Domain controller %s. Error was %s.\n", global_myname, domain, remote_machine, 
675                             cli_errstr(&cli)));
676     cli_close(&cli, cli.nt_pipe_fnum);
677     cli_ulogoff(&cli);
678     cli_shutdown(&cli);
679     return False;
680   }
681
682   cli_nt_session_close(&cli);
683   cli_ulogoff(&cli);
684   cli_shutdown(&cli);
685
686   return True;
687 }
688
689 /************************************************************************
690  Change the trust account password for a domain.
691  The user of this function must have locked the trust password file for
692  update.
693 ************************************************************************/
694
695 BOOL change_trust_account_password( char *domain, char *remote_machine_list)
696 {
697   fstring remote_machine;
698   unsigned char old_trust_passwd_hash[16];
699   unsigned char new_trust_passwd_hash[16];
700   time_t lct;
701   BOOL res = False;
702
703   if(!secrets_fetch_trust_account_password(domain, old_trust_passwd_hash, &lct)) {
704     DEBUG(0,("change_trust_account_password: unable to read the machine \
705 account password for domain %s.\n", domain));
706     return False;
707   }
708
709   /*
710    * Create the new (random) password.
711    */
712   generate_random_buffer( new_trust_passwd_hash, 16, True);
713
714   while(remote_machine_list && 
715         next_token(&remote_machine_list, remote_machine, 
716                    LIST_SEP, sizeof(remote_machine))) {
717     strupper(remote_machine);
718     if(strequal(remote_machine, "*")) {
719
720       /*
721        * We have been asked to dynamcially determine the IP addresses of the PDC.
722        */
723
724       struct in_addr *ip_list = NULL;
725       int count = 0;
726       int i;
727
728       /* Use the PDC *only* for this. */
729       if(!get_dc_list(True, domain, &ip_list, &count))
730         continue;
731
732       /*
733        * Try and connect to the PDC/BDC list in turn as an IP
734        * address used as a string.
735        */
736
737       for(i = 0; i < count; i++) {
738         fstring dc_name;
739         if(!lookup_pdc_name(global_myname, domain, &ip_list[i], dc_name))
740           continue;
741         if((res = modify_trust_password( domain, dc_name,
742                                          old_trust_passwd_hash, new_trust_passwd_hash)))
743           break;
744       }
745
746       if(ip_list != NULL)
747         free((char *)ip_list);
748
749     } else {
750       res = modify_trust_password( domain, remote_machine,
751                                    old_trust_passwd_hash, new_trust_passwd_hash);
752     }
753
754     if(res) {
755       DEBUG(0,("%s : change_trust_account_password: Changed password for \
756 domain %s.\n", timestring(False), domain));
757       /*
758        * Return the result of trying to write the new password
759        * back into the trust account file.
760        */
761       res = secrets_store_trust_account_password(domain, new_trust_passwd_hash);
762       memset(new_trust_passwd_hash, 0, 16);
763       memset(old_trust_passwd_hash, 0, 16);
764       return res;
765     }
766   }
767
768   memset(new_trust_passwd_hash, 0, 16);
769   memset(old_trust_passwd_hash, 0, 16);
770
771   DEBUG(0,("%s : change_trust_account_password: Failed to change password for \
772 domain %s.\n", timestring(False), domain));
773   return False;
774 }