532517f2efa7d30b6809a29f7375837f37a70c75
[kai/samba.git] / source3 / rpcclient / samsync.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.2
4    RPC pipe client
5
6    Copyright (C) Tim Potter 2001
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 static void decode_domain_info(SAM_DOMAIN_INFO *a)
26 {
27         fstring temp;
28         printf("Domain Information\n");
29         printf("------------------\n");
30
31         unistr2_to_ascii(temp, &a->uni_dom_name, sizeof(temp)-1);
32         printf("\tDomain              :%s\n", temp);
33         printf("\tMin password len    :%d\n", a->min_pwd_len);
34         printf("\tpassword history len:%d\n", a->pwd_history_len);
35         printf("\tcreation time       :%s\n", http_timestring(nt_time_to_unix(&a->creation_time)));
36 }
37
38 static void decode_sam_group_info(SAM_GROUP_INFO *a)
39 {
40         fstring temp;
41         printf("\nDomain Group Information\n");
42         printf("------------------------\n");
43
44         unistr2_to_ascii(temp, &a->uni_grp_name, sizeof(temp)-1);
45         printf("\tGroup name          :%s\n", temp);
46         unistr2_to_ascii(temp, &a->uni_grp_desc, sizeof(temp)-1);
47         printf("\tGroup description   :%s\n", temp);
48         printf("\trid                 :%d\n", a->gid.g_rid);
49         printf("\tattribute           :%d\n", a->gid.attr);
50 }
51
52 static void decode_sam_account_info(SAM_ACCOUNT_INFO *a)
53 {
54         fstring temp;
55         printf("\nUser Information\n");
56         printf("----------------\n");
57
58         unistr2_to_ascii(temp, &a->uni_acct_name, sizeof(temp)-1);
59         printf("\tUser name          :%s\n", temp);
60         printf("\tuser's rid         :%d\n", a->user_rid);
61         printf("\tuser's primary gid :%d\n", a->group_rid);
62         unistr2_to_ascii(temp, &a->uni_full_name, sizeof(temp)-1);
63         printf("\tfull name          :%s\n", temp);
64         unistr2_to_ascii(temp, &a->uni_home_dir, sizeof(temp)-1);
65         printf("\thome directory     :%s\n", temp);
66         unistr2_to_ascii(temp, &a->uni_dir_drive, sizeof(temp)-1);
67         printf("\tdrive              :%s\n", temp);
68         unistr2_to_ascii(temp, &a->uni_logon_script, sizeof(temp)-1);
69         printf("\tlogon script       :%s\n", temp);
70         unistr2_to_ascii(temp, &a->uni_acct_desc, sizeof(temp)-1);
71         printf("\tdescription        :%s\n", temp);
72         unistr2_to_ascii(temp, &a->uni_workstations, sizeof(temp)-1);
73         printf("\tworkstations       :%s\n", temp);
74 }
75
76 static void decode_sam_grp_mem_info(SAM_GROUP_MEM_INFO *a)
77 {
78         int i;
79         printf("\nGroup members information\n");
80         printf("-------------------------\n");
81         printf("\tnum members        :%d\n", a->num_members);
82
83         for (i=0; i<a->num_members; i++) {
84                 printf("\trid, attr:%d, %d\n", a->rids[i], a->attribs[i]);
85         }
86 }
87
88 static void decode_sam_alias_info(SAM_ALIAS_INFO *a)
89 {
90         fstring temp;
91         printf("\nAlias Information\n");
92         printf("-----------------\n");
93
94         unistr2_to_ascii(temp, &a->uni_als_name, sizeof(temp)-1);
95         printf("\tname               :%s\n", temp);
96         unistr2_to_ascii(temp, &a->uni_als_desc, sizeof(temp)-1);
97         printf("\tdescription        :%s\n", temp);
98         printf("\trid                :%d\n", a->als_rid);
99 }
100
101 static void decode_sam_als_mem_info(SAM_ALIAS_MEM_INFO *a)
102 {
103         int i;
104         fstring temp;
105         printf("\nAlias members Information\n");
106         printf("-------------------------\n");
107         printf("\tnum members        :%d\n", a->num_members);
108         printf("\tnum sids           :%d\n", a->num_sids);
109         for (i=0; i<a->num_sids; i++) {
110                 printf("\tsid                :%s\n", sid_to_string(temp, &a->sids[i].sid));
111         }
112
113
114 }
115
116 static void decode_sam_dom_info(SAM_DELTA_DOM *a)
117 {
118         fstring temp;
119         printf("\nDomain information\n");
120         printf("------------------\n");
121
122         unistr2_to_ascii(temp, &a->domain_name, sizeof(temp)-1);
123         printf("\tdomain name        :%s\n", temp);
124         printf("\tsid                :%s\n", sid_to_string(temp, &a->domain_sid.sid));
125 }
126
127 static void decode_sam_unk0e_info(SAM_DELTA_UNK0E *a)
128 {
129         fstring temp;
130         printf("\nTrust information\n");
131         printf("-----------------\n");
132
133         unistr2_to_ascii(temp, &a->domain, sizeof(temp)-1);
134         printf("\tdomain name        :%s\n", temp);
135         printf("\tsid                :%s\n", sid_to_string(temp, &a->sid.sid));
136         display_sec_desc(a->sec_desc);
137 }
138
139 static void decode_sam_privs_info(SAM_DELTA_PRIVS *a)
140 {
141         int i;
142         fstring temp;
143         printf("\nSID and privileges information\n");
144         printf("------------------------------\n");
145         printf("\tsid                :%s\n", sid_to_string(temp, &a->sid.sid));
146         display_sec_desc(a->sec_desc);
147         printf("\tprivileges count   :%d\n", a->privlist_count);
148         for (i=0; i<a->privlist_count; i++) {
149                 unistr2_to_ascii(temp, &a->uni_privslist[i], sizeof(temp)-1);
150                 printf("\tprivilege name     :%s\n", temp);
151                 printf("\tattribute          :%d\n", a->attributes[i]);
152         }
153 }
154
155 static void decode_sam_unk12_info(SAM_DELTA_UNK12 *a)
156 {
157         fstring temp;
158         printf("\nTrusted information\n");
159         printf("-------------------\n");
160
161         unistr2_to_ascii(temp, &a->secret, sizeof(temp)-1);
162         printf("\tsecret name        :%s\n", temp);
163         display_sec_desc(a->sec_desc);
164         
165         printf("\ttime 1             :%s\n", http_timestring(nt_time_to_unix(&a->time1)));
166         printf("\ttime 2             :%s\n", http_timestring(nt_time_to_unix(&a->time2)));
167
168         display_sec_desc(a->sec_desc2);
169 }
170
171 static void decode_sam_stamp(SAM_DELTA_STAMP *a)
172 {
173         printf("\nStamp information\n");
174         printf("-----------------\n");
175         printf("\tsequence number    :%d\n", a->seqnum);
176 }
177
178 static void decode_sam_deltas(uint32 num_deltas, SAM_DELTA_HDR *hdr_deltas, SAM_DELTA_CTR *deltas)
179 {
180         int i;
181         for (i = 0; i < num_deltas; i++) {
182                 switch (hdr_deltas[i].type) {
183                         case SAM_DELTA_DOMAIN_INFO: {
184                                 SAM_DOMAIN_INFO *a;
185                                 a = &deltas[i].domain_info;
186                                 decode_domain_info(a);
187                                 break;
188                         }
189                         case SAM_DELTA_GROUP_INFO:  {
190                                 SAM_GROUP_INFO *a;
191                                 a = &deltas[i].group_info;
192                                 decode_sam_group_info(a);
193                                 break;
194                         }
195                         case SAM_DELTA_ACCOUNT_INFO: {
196                                 SAM_ACCOUNT_INFO *a;
197                                 a = &deltas[i].account_info;
198                                 decode_sam_account_info(a);
199                                 break;
200                         }
201                         case SAM_DELTA_GROUP_MEM: {
202                                 SAM_GROUP_MEM_INFO *a;
203                                 a = &deltas[i].grp_mem_info;
204                                 decode_sam_grp_mem_info(a);
205                                 break;
206                         }
207                         case SAM_DELTA_ALIAS_INFO: {
208                                 SAM_ALIAS_INFO *a;
209                                 a = &deltas[i].alias_info;
210                                 decode_sam_alias_info(a);
211                                 break;
212                         }
213                         case SAM_DELTA_ALIAS_MEM: {
214                                 SAM_ALIAS_MEM_INFO *a;
215                                 a = &deltas[i].als_mem_info;
216                                 decode_sam_als_mem_info(a);
217                                 break;
218                         }
219                         case SAM_DELTA_DOM_INFO: {
220                                 SAM_DELTA_DOM *a;
221                                 a = &deltas[i].dom_info;
222                                 decode_sam_dom_info(a);
223                                 break;
224                         }
225                         case SAM_DELTA_UNK0E_INFO: {
226                                 SAM_DELTA_UNK0E *a;
227                                 a = &deltas[i].unk0e_info;
228                                 decode_sam_unk0e_info(a);
229                                 break;
230                         }
231                         case SAM_DELTA_PRIVS_INFO: {
232                                 SAM_DELTA_PRIVS *a;
233                                 a = &deltas[i].privs_info;
234                                 decode_sam_privs_info(a);
235                                 break;
236                         }
237                         case SAM_DELTA_UNK12_INFO: {
238                                 SAM_DELTA_UNK12 *a;
239                                 a = &deltas[i].unk12_info;
240                                 decode_sam_unk12_info(a);
241                                 break;
242                         }
243                         case SAM_DELTA_SAM_STAMP: {
244                                 SAM_DELTA_STAMP *a;
245                                 a = &deltas[i].stamp;
246                                 decode_sam_stamp(a);
247                                 break;
248                         }
249                         default:
250                                 DEBUG(0,("unknown delta type: %d\n", hdr_deltas[i].type));
251                                 break;  
252                 }
253         }
254 }
255
256 /* Synchronise sam database */
257
258 static NTSTATUS sam_sync(struct cli_state *cli, unsigned char trust_passwd[16],
259                          BOOL do_smbpasswd_output, BOOL verbose)
260 {
261         TALLOC_CTX *mem_ctx;
262         SAM_DELTA_HDR *hdr_deltas_0, *hdr_deltas_1, *hdr_deltas_2;
263         SAM_DELTA_CTR *deltas_0, *deltas_1, *deltas_2;
264         uint32 num_deltas_0, num_deltas_1, num_deltas_2;
265         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
266
267         DOM_CRED ret_creds;
268         /* Initialise */
269
270         if (!(mem_ctx = talloc_init())) {
271                 DEBUG(0,("talloc_init failed\n"));
272                 return result;
273         }
274
275         if (!cli_nt_session_open (cli, PIPE_NETLOGON)) {
276                 DEBUG(0, ("Could not initialize netlogon pipe!\n"));
277                 goto done;
278         }
279
280         /* Request a challenge */
281
282         if (!NT_STATUS_IS_OK(new_cli_nt_setup_creds(cli, trust_passwd))) {
283                 DEBUG(0, ("Error initialising session creds\n"));
284                 goto done;
285         }
286
287         /* on first call the returnAuthenticator is empty */
288         memset(&ret_creds, 0, sizeof(ret_creds));
289
290         /* Do sam synchronisation on the SAM database*/
291
292         result = cli_netlogon_sam_sync(cli, mem_ctx, &ret_creds, 0, &num_deltas_0, &hdr_deltas_0, &deltas_0);
293         
294         if (!NT_STATUS_IS_OK(result))
295                 goto done;
296
297         /* verbose mode */
298         if (verbose)
299                 decode_sam_deltas(num_deltas_0, hdr_deltas_0, deltas_0);
300
301
302         /* 
303          * we can't yet do several sam_sync in a raw, it's a credential problem 
304          * we must chain the credentials
305          */
306
307 #if 1
308         /* Do sam synchronisation on the LSA database */
309
310         result = cli_netlogon_sam_sync(cli, mem_ctx, &ret_creds, 2, &num_deltas_2, &hdr_deltas_2, &deltas_2);
311         
312         if (!NT_STATUS_IS_OK(result))
313                 goto done;
314
315         /* verbose mode */
316         if (verbose)
317                 decode_sam_deltas(num_deltas_2, hdr_deltas_2, deltas_2);
318 #endif
319
320         /* Produce smbpasswd output - good for migrating from NT! */
321
322         if (do_smbpasswd_output) {
323                 int i;
324
325                 for (i = 0; i < num_deltas_0; i++) {
326                         SAM_ACCOUNT_INFO *a;
327                         fstring acct_name, hex_nt_passwd, hex_lm_passwd;
328                         uchar lm_passwd[16], nt_passwd[16];
329
330                         /* Skip non-user accounts */
331
332                         if (hdr_deltas_0[i].type != SAM_DELTA_ACCOUNT_INFO)
333                                 continue;
334
335                         a = &deltas_0[i].account_info;
336
337                         unistr2_to_ascii(acct_name, &a->uni_acct_name,
338                                          sizeof(acct_name) - 1);
339
340                         /* Decode hashes from password hash */
341
342                         sam_pwd_hash(a->user_rid, a->pass.buf_lm_pwd, 
343                                      lm_passwd, 0);
344                         sam_pwd_hash(a->user_rid, a->pass.buf_nt_pwd, 
345                                      nt_passwd, 0);
346
347                         /* Encode as strings */
348
349                         smbpasswd_sethexpwd(hex_lm_passwd, lm_passwd,
350                                             a->acb_info);
351                         smbpasswd_sethexpwd(hex_nt_passwd, nt_passwd,
352                                             a->acb_info);
353
354                         /* Display user info */
355
356                         printf("%s:%d:%s:%s:%s:LCT-0\n", acct_name,
357                                a->user_rid, hex_lm_passwd, hex_nt_passwd,
358                                smbpasswd_encode_acb_info(a->acb_info));
359                 }
360                                
361                 goto done;
362         }
363
364         /* Update sam tdb */
365
366  done:
367         cli_nt_session_close(cli);
368         talloc_destroy(mem_ctx);
369         
370         return result;
371 }
372
373 /* Replicate sam deltas */
374
375 static NTSTATUS sam_repl(struct cli_state *cli, unsigned char trust_passwde[16],
376                          uint32 low_serial)
377 {
378         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
379
380         return result;
381 }
382
383 /* Print usage information */
384
385 static void usage(void)
386 {
387         printf("Usage: samsync [options]\n");
388
389         printf("\t-d debuglevel         set the debuglevel\n");
390         printf("\t-h                    Print this help message.\n");
391         printf("\t-s configfile         specify an alternative config file\n");
392         printf("\t-S                    synchronise sam database\n");
393         printf("\t-R                    replicate sam deltas\n");
394         printf("\t-U username           username and password\n");
395         printf("\t-p                    produce smbpasswd output\n");
396         printf("\t-V                    verbose output\n");
397         printf("\n");
398 }
399
400 /* Initialise client credentials for authenticated pipe access */
401
402 void init_rpcclient_creds(struct ntuser_creds *creds, char* username,
403                           char* domain, char* password)
404 {
405         ZERO_STRUCTP(creds);
406
407         if (lp_encrypted_passwords()) {
408                 pwd_make_lm_nt_16(&creds->pwd, password);
409         } else {
410                 pwd_set_cleartext(&creds->pwd, password);
411         }
412
413         fstrcpy(creds->user_name, username);
414         fstrcpy(creds->domain, domain);
415
416         if (! *username) {
417                 creds->pwd.null_pwd = True;
418         }
419 }
420
421 /* Connect to primary domain controller */
422
423 static struct cli_state *init_connection(struct cli_state *cli,
424                                          char *username, char *domain,
425                                          char *password)
426 {
427         struct ntuser_creds creds;
428         extern pstring global_myname;
429         struct in_addr *dest_ip;
430         struct nmb_name calling, called;
431         int count;
432         fstring dest_host;
433
434         /* Initialise cli_state information */
435
436         ZERO_STRUCTP(cli);
437
438         if (!cli_initialise(cli)) {
439                 return NULL;
440         }
441
442         init_rpcclient_creds(&creds, username, domain, password);
443         cli_init_creds(cli, &creds);
444
445         /* Look up name of PDC controller */
446
447         if (!get_dc_list(True, lp_workgroup(), &dest_ip, &count)) {
448                 DEBUG(0, ("Cannot find domain controller for domain %s\n",
449                           lp_workgroup()));
450                 return NULL;
451         }
452
453         if (!lookup_dc_name(global_myname, lp_workgroup(), dest_ip, 
454                             dest_host)) {
455                 DEBUG(0, ("Could not lookup up PDC name for domain %s\n",
456                           lp_workgroup()));
457                 return NULL;
458         }
459
460         get_myname((*global_myname)?NULL:global_myname);
461         strupper(global_myname);
462
463         make_nmb_name(&called, dns_to_netbios_name(dest_host), 0x20);
464         make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
465
466         /* Establish a SMB connection */
467
468         if (!cli_establish_connection(cli, dest_host, dest_ip, &calling, 
469                                       &called, "IPC$", "IPC", False, True)) {
470                 return NULL;
471         }
472         
473         return cli;
474 }
475
476 /* Main function */
477
478  int main(int argc, char **argv)
479 {
480         BOOL do_sam_sync = False, do_sam_repl = False;
481         struct cli_state cli;
482         NTSTATUS result;
483         int opt;
484         pstring logfile;
485         BOOL interactive = False, do_smbpasswd_output = False;
486         BOOL verbose = False;
487         uint32 low_serial = 0;
488         unsigned char trust_passwd[16];
489         fstring username, domain, password;
490
491         if (argc == 1) {
492                 usage();
493                 return 1;
494         }
495
496         ZERO_STRUCT(username);
497         ZERO_STRUCT(domain);
498         ZERO_STRUCT(password);
499
500         /* Parse command line options */
501
502         while((opt = getopt(argc, argv, "s:d:SR:hiU:W:pV")) != EOF) {
503                 switch (opt) {
504                 case 's':
505                         pstrcpy(dyn_CONFIGFILE, optarg);
506                         break;
507                 case 'd':
508                         DEBUGLEVEL = atoi(optarg);
509                         break;
510                 case 'S':
511                         do_sam_sync = 1;
512                         break;
513                 case 'R':
514                         do_sam_repl = 1;
515                         low_serial = atoi(optarg);
516                         break;
517                 case 'i':
518                         interactive = True;
519                         break;
520                 case 'U': {
521                         char *lp;
522
523                         fstrcpy(username,optarg);
524                         if ((lp=strchr_m(username,'%'))) {
525                                 *lp = 0;
526                                 fstrcpy(password,lp+1);
527                                 memset(strchr_m(optarg, '%') + 1, 'X',
528                                        strlen(password));
529                         }
530                         break;
531                 }
532                 case 'W':
533                         pstrcpy(domain, optarg);
534                         break;
535                 case 'p':
536                         do_smbpasswd_output = True;
537                         break;
538                 case 'V':
539                         verbose = True;
540                         break;
541                case 'h':
542                 default:
543                         usage();
544                         exit(1);
545                 }
546         }
547
548         argc -= optind;
549
550         if (argc > 0) {
551                 usage();
552                 return 1;
553         }
554
555         /* Initialise samba */
556
557         slprintf(logfile, sizeof(logfile) - 1, "%s/log.%s", dyn_LOGFILEBASE, 
558                  "samsync");
559         lp_set_logfile(logfile);
560
561         setup_logging("samsync", interactive);
562
563         if (!interactive)
564                 reopen_logs();
565
566         if (!lp_load(dyn_CONFIGFILE, True, False, False)) {
567                 fprintf(stderr, "Can't load %s\n", dyn_CONFIGFILE);
568         }
569
570         load_interfaces();
571
572         /* Check arguments make sense */
573
574         if (do_sam_sync && do_sam_repl) {
575                 fprintf(stderr, "cannot specify both -S and -R\n");
576                 return 1;
577
578         }
579
580         if (!do_sam_sync && !do_sam_repl) {
581                 fprintf(stderr, "must specify either -S or -R\n");
582                 return 1;
583         }
584
585         if (do_sam_repl && low_serial == 0) {
586                 fprintf(stderr, "serial number must be positive\n");
587                 return 1;
588         }
589
590         /* BDC operations require the machine account password */
591
592         if (!secrets_init()) {
593                 DEBUG(0, ("Unable to initialise secrets database\n"));
594                 return 1;
595         }
596
597         if (!secrets_fetch_trust_account_password(lp_workgroup(), 
598                                                   trust_passwd, NULL)) {
599                 DEBUG(0, ("could not fetch trust account password\n"));
600                 return 1;
601         }        
602
603         /* Perform sync or replication */
604
605         if (!init_connection(&cli, username, domain, password))
606                 return 1;
607
608         if (do_sam_sync)
609                 result = sam_sync(&cli, trust_passwd, do_smbpasswd_output, verbose);
610
611         if (do_sam_repl)
612                 result = sam_repl(&cli, trust_passwd, low_serial);
613
614         if (!NT_STATUS_IS_OK(result)) {
615                 DEBUG(0, ("%s\n", get_nt_error_msg(result)));
616                 return 1;
617         }
618
619         return 0;
620 }