This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[sfrench/samba-autobuild/.git] / source3 / rpcclient / samsync.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SAM synchronisation and replication
4
5    Copyright (C) Tim Potter 2001,2002
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 DOM_SID domain_sid;
25
26 static void decode_domain_info(SAM_DOMAIN_INFO *a)
27 {
28         fstring temp;
29         printf("Domain Information\n");
30         printf("------------------\n");
31
32         unistr2_to_ascii(temp, &a->uni_dom_name, sizeof(temp)-1);
33         printf("\tDomain              :%s\n", temp);
34         printf("\tMin password len    :%d\n", a->min_pwd_len);
35         printf("\tpassword history len:%d\n", a->pwd_history_len);
36         printf("\tcreation time       :%s\n", http_timestring(nt_time_to_unix(&a->creation_time)));
37 }
38
39 static void decode_sam_group_info(SAM_GROUP_INFO *a)
40 {
41         fstring temp;
42         printf("\nDomain Group Information\n");
43         printf("------------------------\n");
44
45         unistr2_to_ascii(temp, &a->uni_grp_name, sizeof(temp)-1);
46         printf("\tGroup name          :%s\n", temp);
47         unistr2_to_ascii(temp, &a->uni_grp_desc, sizeof(temp)-1);
48         printf("\tGroup description   :%s\n", temp);
49         printf("\trid                 :%d\n", a->gid.g_rid);
50         printf("\tattribute           :%d\n", a->gid.attr);
51 }
52
53 static void decode_sam_account_info(SAM_ACCOUNT_INFO *a)
54 {
55         fstring temp;
56         printf("\nUser Information\n");
57         printf("----------------\n");
58
59         unistr2_to_ascii(temp, &a->uni_acct_name, sizeof(temp)-1);
60         printf("\tUser name          :%s\n", temp);
61         printf("\tuser's rid         :%d\n", a->user_rid);
62         printf("\tuser's primary gid :%d\n", a->group_rid);
63         unistr2_to_ascii(temp, &a->uni_full_name, sizeof(temp)-1);
64         printf("\tfull name          :%s\n", temp);
65         unistr2_to_ascii(temp, &a->uni_home_dir, sizeof(temp)-1);
66         printf("\thome directory     :%s\n", temp);
67         unistr2_to_ascii(temp, &a->uni_dir_drive, sizeof(temp)-1);
68         printf("\tdrive              :%s\n", temp);
69         unistr2_to_ascii(temp, &a->uni_logon_script, sizeof(temp)-1);
70         printf("\tlogon script       :%s\n", temp);
71         unistr2_to_ascii(temp, &a->uni_acct_desc, sizeof(temp)-1);
72         printf("\tdescription        :%s\n", temp);
73         unistr2_to_ascii(temp, &a->uni_workstations, sizeof(temp)-1);
74         printf("\tworkstations       :%s\n", temp);
75 }
76
77 static void decode_sam_grp_mem_info(SAM_GROUP_MEM_INFO *a)
78 {
79         int i;
80         printf("\nGroup members information\n");
81         printf("-------------------------\n");
82         printf("\tnum members        :%d\n", a->num_members);
83
84         for (i=0; i<a->num_members; i++) {
85                 printf("\trid, attr:%d, %d\n", a->rids[i], a->attribs[i]);
86         }
87 }
88
89 static void decode_sam_alias_info(SAM_ALIAS_INFO *a)
90 {
91         fstring temp;
92         printf("\nAlias Information\n");
93         printf("-----------------\n");
94
95         unistr2_to_ascii(temp, &a->uni_als_name, sizeof(temp)-1);
96         printf("\tname               :%s\n", temp);
97         unistr2_to_ascii(temp, &a->uni_als_desc, sizeof(temp)-1);
98         printf("\tdescription        :%s\n", temp);
99         printf("\trid                :%d\n", a->als_rid);
100 }
101
102 static void decode_sam_als_mem_info(SAM_ALIAS_MEM_INFO *a)
103 {
104         int i;
105         fstring temp;
106         printf("\nAlias members Information\n");
107         printf("-------------------------\n");
108         printf("\tnum members        :%d\n", a->num_members);
109         printf("\tnum sids           :%d\n", a->num_sids);
110         for (i=0; i<a->num_sids; i++) {
111                 printf("\tsid                :%s\n", sid_to_string(temp, &a->sids[i].sid));
112         }
113
114
115 }
116
117 static void decode_sam_dom_info(SAM_DELTA_DOM *a)
118 {
119         fstring temp;
120         printf("\nDomain information\n");
121         printf("------------------\n");
122
123         unistr2_to_ascii(temp, &a->domain_name, sizeof(temp)-1);
124         printf("\tdomain name        :%s\n", temp);
125         printf("\tsid                :%s\n", sid_to_string(temp, &a->domain_sid.sid));
126 }
127
128 static void decode_sam_unk0e_info(SAM_DELTA_UNK0E *a)
129 {
130         fstring temp;
131         printf("\nTrust information\n");
132         printf("-----------------\n");
133
134         unistr2_to_ascii(temp, &a->domain, sizeof(temp)-1);
135         printf("\tdomain name        :%s\n", temp);
136         printf("\tsid                :%s\n", sid_to_string(temp, &a->sid.sid));
137         display_sec_desc(a->sec_desc);
138 }
139
140 static void decode_sam_privs_info(SAM_DELTA_PRIVS *a)
141 {
142         int i;
143         fstring temp;
144         printf("\nSID and privileges information\n");
145         printf("------------------------------\n");
146         printf("\tsid                :%s\n", sid_to_string(temp, &a->sid.sid));
147         display_sec_desc(a->sec_desc);
148         printf("\tprivileges count   :%d\n", a->privlist_count);
149         for (i=0; i<a->privlist_count; i++) {
150                 unistr2_to_ascii(temp, &a->uni_privslist[i], sizeof(temp)-1);
151                 printf("\tprivilege name     :%s\n", temp);
152                 printf("\tattribute          :%d\n", a->attributes[i]);
153         }
154 }
155
156 static void decode_sam_unk12_info(SAM_DELTA_UNK12 *a)
157 {
158         fstring temp;
159         printf("\nTrusted information\n");
160         printf("-------------------\n");
161
162         unistr2_to_ascii(temp, &a->secret, sizeof(temp)-1);
163         printf("\tsecret name        :%s\n", temp);
164         display_sec_desc(a->sec_desc);
165         
166         printf("\ttime 1             :%s\n", http_timestring(nt_time_to_unix(&a->time1)));
167         printf("\ttime 2             :%s\n", http_timestring(nt_time_to_unix(&a->time2)));
168
169         display_sec_desc(a->sec_desc2);
170 }
171
172 static void decode_sam_stamp(SAM_DELTA_STAMP *a)
173 {
174         printf("\nStamp information\n");
175         printf("-----------------\n");
176         printf("\tsequence number    :%d\n", a->seqnum);
177 }
178
179 static void decode_sam_deltas(uint32 num_deltas, SAM_DELTA_HDR *hdr_deltas, SAM_DELTA_CTR *deltas)
180 {
181         int i;
182         for (i = 0; i < num_deltas; i++) {
183                 switch (hdr_deltas[i].type) {
184                         case SAM_DELTA_DOMAIN_INFO: {
185                                 SAM_DOMAIN_INFO *a;
186                                 a = &deltas[i].domain_info;
187                                 decode_domain_info(a);
188                                 break;
189                         }
190                         case SAM_DELTA_GROUP_INFO:  {
191                                 SAM_GROUP_INFO *a;
192                                 a = &deltas[i].group_info;
193                                 decode_sam_group_info(a);
194                                 break;
195                         }
196                         case SAM_DELTA_ACCOUNT_INFO: {
197                                 SAM_ACCOUNT_INFO *a;
198                                 a = &deltas[i].account_info;
199                                 decode_sam_account_info(a);
200                                 break;
201                         }
202                         case SAM_DELTA_GROUP_MEM: {
203                                 SAM_GROUP_MEM_INFO *a;
204                                 a = &deltas[i].grp_mem_info;
205                                 decode_sam_grp_mem_info(a);
206                                 break;
207                         }
208                         case SAM_DELTA_ALIAS_INFO: {
209                                 SAM_ALIAS_INFO *a;
210                                 a = &deltas[i].alias_info;
211                                 decode_sam_alias_info(a);
212                                 break;
213                         }
214                         case SAM_DELTA_ALIAS_MEM: {
215                                 SAM_ALIAS_MEM_INFO *a;
216                                 a = &deltas[i].als_mem_info;
217                                 decode_sam_als_mem_info(a);
218                                 break;
219                         }
220                         case SAM_DELTA_DOM_INFO: {
221                                 SAM_DELTA_DOM *a;
222                                 a = &deltas[i].dom_info;
223                                 decode_sam_dom_info(a);
224                                 break;
225                         }
226                         case SAM_DELTA_UNK0E_INFO: {
227                                 SAM_DELTA_UNK0E *a;
228                                 a = &deltas[i].unk0e_info;
229                                 decode_sam_unk0e_info(a);
230                                 break;
231                         }
232                         case SAM_DELTA_PRIVS_INFO: {
233                                 SAM_DELTA_PRIVS *a;
234                                 a = &deltas[i].privs_info;
235                                 decode_sam_privs_info(a);
236                                 break;
237                         }
238                         case SAM_DELTA_UNK12_INFO: {
239                                 SAM_DELTA_UNK12 *a;
240                                 a = &deltas[i].unk12_info;
241                                 decode_sam_unk12_info(a);
242                                 break;
243                         }
244                         case SAM_DELTA_SAM_STAMP: {
245                                 SAM_DELTA_STAMP *a;
246                                 a = &deltas[i].stamp;
247                                 decode_sam_stamp(a);
248                                 break;
249                         }
250                         default:
251                                 DEBUG(0,("unknown delta type: %d\n", hdr_deltas[i].type));
252                                 break;  
253                 }
254         }
255 }
256
257 /* Convert a SAM_ACCOUNT_DELTA to a SAM_ACCOUNT. */
258
259 static void sam_account_from_delta(SAM_ACCOUNT *account,
260                                    SAM_ACCOUNT_INFO *delta)
261 {
262         DOM_SID sid;
263         fstring s;
264
265         /* Username, fullname, home dir, dir drive, logon script, acct
266            desc, workstations, profile. */
267
268         unistr2_to_ascii(s, &delta->uni_acct_name, sizeof(s) - 1);
269         pdb_set_nt_username(account, s);
270
271         /* Unix username is the same - for sainity */
272         pdb_set_username(account, s);
273
274         unistr2_to_ascii(s, &delta->uni_full_name, sizeof(s) - 1);
275         pdb_set_fullname(account, s);
276
277         unistr2_to_ascii(s, &delta->uni_home_dir, sizeof(s) - 1);
278         pdb_set_homedir(account, s, True);
279
280         unistr2_to_ascii(s, &delta->uni_dir_drive, sizeof(s) - 1);
281         pdb_set_dir_drive(account, s, True);
282
283         unistr2_to_ascii(s, &delta->uni_logon_script, sizeof(s) - 1);
284         pdb_set_logon_script(account, s, True);
285
286         unistr2_to_ascii(s, &delta->uni_acct_desc, sizeof(s) - 1);
287         pdb_set_acct_desc(account, s);
288
289         unistr2_to_ascii(s, &delta->uni_workstations, sizeof(s) - 1);
290         pdb_set_workstations(account, s);
291
292         unistr2_to_ascii(s, &delta->uni_profile, sizeof(s) - 1);
293         pdb_set_profile_path(account, s, True);
294
295         /* User and group sid */
296
297         sid_copy(&sid, &domain_sid);
298         sid_append_rid(&sid, delta->user_rid);
299         pdb_set_user_sid(account, &sid);
300
301         sid_copy(&sid, &domain_sid);
302         sid_append_rid(&sid, delta->group_rid);
303         pdb_set_group_sid(account, &sid);
304
305         /* Logon and password information */
306
307         pdb_set_logon_time(account, nt_time_to_unix(&delta->logon_time), True);
308         pdb_set_logoff_time(account, nt_time_to_unix(&delta->logoff_time), 
309                             True);
310
311         pdb_set_logon_divs(account, delta->logon_divs);
312
313         /* TODO: logon hours */
314         /* TODO: bad password count */
315         /* TODO: logon count */
316
317         pdb_set_pass_last_set_time(
318                 account, nt_time_to_unix(&delta->pwd_last_set_time));
319
320         /* TODO: account expiry time */
321
322         pdb_set_acct_ctrl(account, delta->acb_info);
323 }
324
325 static void apply_account_info(SAM_ACCOUNT_INFO *sam_acct_delta)
326 {
327         SAM_ACCOUNT sam_acct;
328         BOOL result;
329
330         ZERO_STRUCT(sam_acct);
331
332         pdb_init_sam(&sam_acct);
333
334         sam_account_from_delta(&sam_acct, sam_acct_delta);
335         result = pdb_add_sam_account(&sam_acct);
336 }
337
338 /* Apply an array of deltas to the SAM database */
339
340 static void apply_deltas(uint32 num_deltas, SAM_DELTA_HDR *hdr_deltas,
341                          SAM_DELTA_CTR *deltas)
342 {
343         uint32 i;
344
345         for (i = 0; i < num_deltas; i++) {
346                 switch(hdr_deltas[i].type) {
347                 case SAM_DELTA_ACCOUNT_INFO:
348                         apply_account_info(&deltas[i].account_info);
349                         break;
350                 }
351         }
352 }
353
354 /* Synchronise sam database */
355
356 static NTSTATUS sam_sync(struct cli_state *cli, unsigned char trust_passwd[16],
357                          BOOL do_smbpasswd_output, BOOL verbose)
358 {
359         TALLOC_CTX *mem_ctx;
360         SAM_DELTA_HDR *hdr_deltas_0, *hdr_deltas_2;
361         SAM_DELTA_CTR *deltas_0, *deltas_2;
362         uint32 num_deltas_0, num_deltas_2;
363         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
364         struct pdb_context *in;
365
366         DOM_CRED ret_creds;
367
368         /* Initialise */
369
370         if (!NT_STATUS_IS_OK(make_pdb_context_list(&in, lp_passdb_backend()))){
371                 DEBUG(0, ("Can't initialize passdb backend.\n"));
372                       return result;
373         }
374
375         if (!(mem_ctx = talloc_init())) {
376                 DEBUG(0,("talloc_init failed\n"));
377                 return result;
378         }
379
380         if (!cli_nt_session_open (cli, PIPE_NETLOGON)) {
381                 DEBUG(0, ("Could not initialize netlogon pipe!\n"));
382                 goto done;
383         }
384
385         /* Request a challenge */
386
387         if (!NT_STATUS_IS_OK(cli_nt_setup_creds(cli, SEC_CHAN_BDC, trust_passwd))) {
388                 DEBUG(0, ("Error initialising session creds\n"));
389                 goto done;
390         }
391
392         /* on first call the returnAuthenticator is empty */
393         memset(&ret_creds, 0, sizeof(ret_creds));
394
395         /* Do sam synchronisation on the SAM database*/
396
397         result = cli_netlogon_sam_sync(cli, mem_ctx, &ret_creds, 0, 
398                                        &num_deltas_0, &hdr_deltas_0, 
399                                        &deltas_0);
400         
401         if (!NT_STATUS_IS_OK(result))
402                 goto done;
403
404         apply_deltas(num_deltas_0, hdr_deltas_0, deltas_0);
405
406
407         /* 
408          * we can't yet do several sam_sync in a raw, it's a credential problem 
409          * we must chain the credentials
410          */
411
412 #if 1
413         /* Do sam synchronisation on the LSA database */
414
415         result = cli_netlogon_sam_sync(cli, mem_ctx, &ret_creds, 2, &num_deltas_2, &hdr_deltas_2, &deltas_2);
416         
417         if (!NT_STATUS_IS_OK(result))
418                 goto done;
419
420         /* verbose mode */
421         if (verbose)
422                 decode_sam_deltas(num_deltas_2, hdr_deltas_2, deltas_2);
423 #endif
424
425         /* Produce smbpasswd output - good for migrating from NT! */
426
427         if (do_smbpasswd_output) {
428                 int i;
429
430                 for (i = 0; i < num_deltas_0; i++) {
431                         SAM_ACCOUNT_INFO *a;
432                         fstring acct_name, hex_nt_passwd, hex_lm_passwd;
433                         uchar lm_passwd[16], nt_passwd[16];
434
435                         /* Skip non-user accounts */
436
437                         if (hdr_deltas_0[i].type != SAM_DELTA_ACCOUNT_INFO)
438                                 continue;
439
440                         a = &deltas_0[i].account_info;
441
442                         unistr2_to_ascii(acct_name, &a->uni_acct_name,
443                                          sizeof(acct_name) - 1);
444
445                         /* Decode hashes from password hash */
446
447                         sam_pwd_hash(a->user_rid, a->pass.buf_lm_pwd, 
448                                      lm_passwd, 0);
449                         sam_pwd_hash(a->user_rid, a->pass.buf_nt_pwd, 
450                                      nt_passwd, 0);
451
452                         /* Encode as strings */
453
454                         smbpasswd_sethexpwd(hex_lm_passwd, lm_passwd,
455                                             a->acb_info);
456                         smbpasswd_sethexpwd(hex_nt_passwd, nt_passwd,
457                                             a->acb_info);
458
459                         /* Display user info */
460
461                         printf("%s:%d:%s:%s:%s:LCT-0\n", acct_name,
462                                a->user_rid, hex_lm_passwd, hex_nt_passwd,
463                                smbpasswd_encode_acb_info(a->acb_info));
464                 }
465                                
466                 goto done;
467         }
468
469         /* Update sam tdb */
470
471  done:
472         cli_nt_session_close(cli);
473         talloc_destroy(mem_ctx);
474         
475         return result;
476 }
477
478 /* Replicate sam deltas */
479
480 static NTSTATUS sam_repl(struct cli_state *cli, unsigned char trust_passwde[16],
481                          uint32 low_serial)
482 {
483         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
484
485         return result;
486 }
487
488 /* Connect to primary domain controller */
489
490 static struct cli_state *init_connection(struct cli_state **cli,
491                                          char *username, char *domain,
492                                          char *password)
493 {
494         extern pstring global_myname;
495         struct in_addr *dest_ip;
496         int count;
497         fstring dest_host;
498
499         /* Initialise myname */
500
501         if (!global_myname[0]) {
502                 char *p;
503
504                 fstrcpy(global_myname, myhostname());
505                 p = strchr(global_myname, '.');
506                 if (p)
507                         *p = 0;
508         }
509
510         /* Look up name of PDC controller */
511
512         if (!get_dc_list(True, lp_workgroup(), &dest_ip, &count)) {
513                 DEBUG(0, ("Cannot find domain controller for domain %s\n",
514                           lp_workgroup()));
515                 return NULL;
516         }
517
518         if (!lookup_dc_name(global_myname, lp_workgroup(), dest_ip, 
519                             dest_host)) {
520                 DEBUG(0, ("Could not lookup up PDC name for domain %s\n",
521                           lp_workgroup()));
522                 return NULL;
523         }
524
525         if (NT_STATUS_IS_OK(cli_full_connection(cli, global_myname, dest_host,
526                                                 dest_ip, 0,
527                                                 "IPC$", "IPC",  
528                                                 username, domain,
529                                                 password, 0))) {
530                 return *cli;
531         }
532
533         return NULL;
534 }
535
536 /* Main function */
537
538 static fstring popt_username, popt_domain, popt_password;
539 static BOOL popt_got_pass;
540
541 static void user_callback(poptContext con, 
542                           enum poptCallbackReason reason,
543                           const struct poptOption *opt,
544                           const char *arg, const void *data)
545 {
546         char *p, *ch;
547
548         if (!arg)
549                 return;
550
551         switch(opt->val) {
552
553                 /* Check for [DOMAIN\\]username[%password]*/
554
555         case 'U':
556
557                 p = arg;
558
559                 if ((ch = strchr(p, '\\'))) {
560                         fstrcpy(popt_domain, p); 
561                         popt_domain[ch - p] = 0;
562                 }
563
564                 fstrcpy(popt_username, p);
565
566                 if ((ch = strchr(p, '%'))) {
567                         popt_username[ch - p] = 0;
568                         fstrcpy(popt_password, ch + 1);
569                         popt_got_pass = True;
570                 }
571
572                 break;
573                 
574         case 'W':
575                 fstrcpy(popt_domain, arg);
576                 break;
577         }
578 }
579
580 /* Return domain, username and password passed in from cmd line */
581
582 void popt_common_get_auth_info(char **domain, char **username, char **password,
583                                BOOL *got_pass)
584 {
585         *domain = popt_domain;
586         *username = popt_username;
587         *password = popt_password;
588         *got_pass = popt_got_pass;
589 }
590
591 struct poptOption popt_common_auth_info[] = {
592         { NULL, 0, POPT_ARG_CALLBACK, user_callback },
593         { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set username",
594           "[DOMAIN\\]username[%password]" },
595         { "domain", 'W', POPT_ARG_STRING, NULL, 'W', "Set domain name", 
596           "DOMAIN"},
597         { 0 }
598 };
599
600 static BOOL popt_interactive;
601
602 BOOL popt_common_is_interactive(void)
603 {
604         return popt_interactive;
605 }
606
607 struct poptOption popt_common_interactive[] = {
608         { "interactive", 'i', POPT_ARG_NONE, &popt_interactive, 'i',
609           "Log to stdout" },
610         { 0 }
611 };
612
613  int main(int argc, char **argv)
614 {
615         BOOL do_sam_sync = False, do_sam_repl = False;
616         struct cli_state *cli;
617         NTSTATUS result;
618         pstring logfile;
619         BOOL do_smbpasswd_output = False;
620         BOOL verbose = True, got_pass = False;
621         uint32 serial = 0;
622         unsigned char trust_passwd[16];
623         char *username, *domain, *password;
624         poptContext pc;
625         char c;
626
627         struct poptOption popt_samsync_opts[] = {
628                 { "synchronise", 'S', POPT_ARG_NONE, &do_sam_sync, 'S', 
629                   "Perform full SAM synchronisation" },
630                 { "replicate", 'R', POPT_ARG_NONE, &do_sam_repl, 'R',
631                   "Replicate SAM changes" },
632                 { "serial", 0, POPT_ARG_INT, &serial, 0, "SAM serial number" },
633                 { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug },
634                 { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_auth_info },
635                 { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_interactive },
636                 POPT_AUTOHELP
637                 { 0 }
638         };
639
640         /* Read command line options */
641
642         pc = poptGetContext("samsync", argc, (const char **)argv,
643                             popt_samsync_opts, 0);
644
645         if (argc == 1) {
646                 poptPrintUsage(pc, stdout, 0);
647                 return 1;
648         }
649
650         while ((c = poptGetNextOpt(pc)) != -1) {
651
652                 /* Argument processing error */
653
654                 if (c < -1) {
655                         fprintf(stderr, "samsync: %s: %s\n",
656                                 poptBadOption(pc, POPT_BADOPTION_NOALIAS),
657                                 poptStrerror(c));
658                         return 1;
659                 }
660
661                 /* Handle arguments */
662
663                 switch (c) {
664                 case 'h':
665                         poptPrintHelp(pc, stdout, 0);
666                         return 1;
667                 case 'u':
668                         poptPrintUsage(pc, stdout, 0);
669                         return 1;
670                 }
671         }
672
673         /* Bail out if any extra args were passed */
674
675         if (poptPeekArg(pc)) {
676                 fprintf(stderr, "samsync: invalid argument %s\n",
677                         poptPeekArg(pc));
678                 poptPrintUsage(pc, stdout, 0);
679                 return 1;
680         }
681
682         poptFreeContext(pc);
683
684         /* Setup logging */
685
686         dbf = x_stdout;
687
688         if (!lp_load(dyn_CONFIGFILE, True, False, False)) {
689                 d_fprintf(stderr, "samsync: error opening config file %s. "
690                           "Error was %s\n", dyn_CONFIGFILE, strerror(errno));
691                 return 1;
692         }
693
694         slprintf(logfile, sizeof(logfile) - 1, "%s/log.%s", dyn_LOGFILEBASE, 
695                  "samsync");
696
697         lp_set_logfile(logfile);
698
699         setup_logging("samsync", popt_common_is_interactive());
700
701         if (!popt_common_is_interactive())
702                 reopen_logs();
703
704         load_interfaces();
705
706         /* Check arguments make sense */
707
708         if (do_sam_sync && do_sam_repl) {
709                 DEBUG(0, ("cannot specify both -S and -R\n"));
710                 return 1;
711
712         }
713
714         if (!do_sam_sync && !do_sam_repl) {
715                 DEBUG(0, ("samsync: you must either --synchronise or "
716                           "--replicate the SAM database\n"));
717                 return 1;
718         }
719
720         if (do_sam_repl && serial == 0) {
721                 DEBUG(0, ("samsync: must specify serial number\n"));
722                 return 1;
723         }
724
725         if (do_sam_sync && serial != 0) {
726                 DEBUG(0, ("samsync: you can't specify a serial number when "
727                           "synchonising the SAM database\n"));
728                 return 1;
729         }
730
731         /* BDC operations require the machine account password */
732
733         if (!secrets_init()) {
734                 DEBUG(0, ("samsync: unable to initialise secrets database\n"));
735                 return 1;
736         }
737
738         if (!secrets_fetch_trust_account_password(lp_workgroup(), 
739                                                   trust_passwd, NULL)) {
740                 DEBUG(0, ("samsync: could not fetch trust account password\n"));
741                 return 1;
742         }        
743
744         /* I wish the domain sid wasn't stored in secrets.tdb */
745
746         if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
747                 DEBUG(0, ("samsync: could not retrieve domain sid\n"));
748                 return 1;
749         }
750
751         /* Perform sync or replication */
752
753         popt_common_get_auth_info(&domain, &username, &password, &got_pass);
754
755         if (!init_connection(&cli, username, domain, password))
756                 return 1;
757
758         if (do_sam_sync)
759                 result = sam_sync(cli, trust_passwd, do_smbpasswd_output, 
760                                   verbose);
761
762         if (do_sam_repl)
763                 result = sam_repl(cli, trust_passwd, serial);
764
765         if (!NT_STATUS_IS_OK(result)) {
766                 DEBUG(0, ("%s\n", nt_errstr(result)));
767                 return 1;
768         }
769
770         return 0;
771 }