1379485f1d8d16bd5b260281c90730b8565f9753
[kai/samba.git] / source / 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         /* Initialise */
268
269         if (!(mem_ctx = talloc_init())) {
270                 DEBUG(0,("talloc_init failed\n"));
271                 return result;
272         }
273
274         if (!cli_nt_session_open (cli, PIPE_NETLOGON)) {
275                 DEBUG(0, ("Could not initialize netlogon pipe!\n"));
276                 goto done;
277         }
278
279         /* Request a challenge */
280
281         if (!NT_STATUS_IS_OK(new_cli_nt_setup_creds(cli, trust_passwd))) {
282                 DEBUG(0, ("Error initialising session creds\n"));
283                 goto done;
284         }
285
286         /* Do sam synchronisation on the SAM database*/
287
288         result = cli_netlogon_sam_sync(cli, mem_ctx, 0, &num_deltas_0, &hdr_deltas_0, &deltas_0);
289         
290         if (!NT_STATUS_IS_OK(result))
291                 goto done;
292
293         /* verbose mode */
294         if (verbose)
295                 decode_sam_deltas(num_deltas_0, hdr_deltas_0, deltas_0);
296
297
298         /* 
299          * we can't yet do several sam_sync in a raw, it's a credential problem 
300          * we must chain the credentials
301          */
302
303
304 #if 0
305         /* Do sam synchronisation on the LSA database */
306
307         result = cli_netlogon_sam_sync(cli, mem_ctx, 2, &num_deltas_2, &hdr_deltas_2, &deltas_2);
308         
309         if (!NT_STATUS_IS_OK(result))
310                 goto done;
311
312         /* verbose mode */
313         if (verbose)
314                 decode_sam_deltas(num_deltas_2, hdr_deltas_2, deltas_2);
315 #endif
316
317         /* Produce smbpasswd output - good for migrating from NT! */
318
319         if (do_smbpasswd_output) {
320                 int i;
321
322                 for (i = 0; i < num_deltas_0; i++) {
323                         SAM_ACCOUNT_INFO *a;
324                         fstring acct_name, hex_nt_passwd, hex_lm_passwd;
325                         uchar lm_passwd[16], nt_passwd[16];
326
327                         /* Skip non-user accounts */
328
329                         if (hdr_deltas_0[i].type != SAM_DELTA_ACCOUNT_INFO)
330                                 continue;
331
332                         a = &deltas_0[i].account_info;
333
334                         unistr2_to_ascii(acct_name, &a->uni_acct_name,
335                                          sizeof(acct_name) - 1);
336
337                         /* Decode hashes from password hash */
338
339                         sam_pwd_hash(a->user_rid, a->pass.buf_lm_pwd, 
340                                      lm_passwd, 0);
341                         sam_pwd_hash(a->user_rid, a->pass.buf_nt_pwd, 
342                                      nt_passwd, 0);
343
344                         /* Encode as strings */
345
346                         smbpasswd_sethexpwd(hex_lm_passwd, lm_passwd,
347                                             a->acb_info);
348                         smbpasswd_sethexpwd(hex_nt_passwd, nt_passwd,
349                                             a->acb_info);
350
351                         /* Display user info */
352
353                         printf("%s:%d:%s:%s:%s:LCT-0\n", acct_name,
354                                a->user_rid, hex_lm_passwd, hex_nt_passwd,
355                                smbpasswd_encode_acb_info(a->acb_info));
356                 }
357                                
358                 goto done;
359         }
360
361         /* Update sam tdb */
362
363  done:
364         cli_nt_session_close(cli);
365         talloc_destroy(mem_ctx);
366         
367         return result;
368 }
369
370 /* Replicate sam deltas */
371
372 static NTSTATUS sam_repl(struct cli_state *cli, unsigned char trust_passwde[16],
373                          uint32 low_serial)
374 {
375         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
376
377         return result;
378 }
379
380 /* Print usage information */
381
382 static void usage(void)
383 {
384         printf("Usage: samsync [options]\n");
385
386         printf("\t-d debuglevel         set the debuglevel\n");
387         printf("\t-h                    Print this help message.\n");
388         printf("\t-s configfile         specify an alternative config file\n");
389         printf("\t-S                    synchronise sam database\n");
390         printf("\t-R                    replicate sam deltas\n");
391         printf("\t-U username           username and password\n");
392         printf("\t-p                    produce smbpasswd output\n");
393         printf("\t-V                    verbose output\n");
394         printf("\n");
395 }
396
397 /* Initialise client credentials for authenticated pipe access */
398
399 void init_rpcclient_creds(struct ntuser_creds *creds, char* username,
400                           char* domain, char* password)
401 {
402         ZERO_STRUCTP(creds);
403
404         if (lp_encrypted_passwords()) {
405                 pwd_make_lm_nt_16(&creds->pwd, password);
406         } else {
407                 pwd_set_cleartext(&creds->pwd, password);
408         }
409
410         fstrcpy(creds->user_name, username);
411         fstrcpy(creds->domain, domain);
412
413         if (! *username) {
414                 creds->pwd.null_pwd = True;
415         }
416 }
417
418 /* Connect to primary domain controller */
419
420 static struct cli_state *init_connection(struct cli_state *cli,
421                                          char *username, char *domain,
422                                          char *password)
423 {
424         struct ntuser_creds creds;
425         extern pstring global_myname;
426         struct in_addr *dest_ip;
427         struct nmb_name calling, called;
428         int count;
429         fstring dest_host;
430
431         /* Initialise cli_state information */
432
433         ZERO_STRUCTP(cli);
434
435         if (!cli_initialise(cli)) {
436                 return NULL;
437         }
438
439         init_rpcclient_creds(&creds, username, domain, password);
440         cli_init_creds(cli, &creds);
441
442         /* Look up name of PDC controller */
443
444         if (!get_dc_list(True, lp_workgroup(), &dest_ip, &count)) {
445                 DEBUG(0, ("Cannot find domain controller for domain %s\n",
446                           lp_workgroup()));
447                 return NULL;
448         }
449
450         if (!lookup_dc_name(global_myname, lp_workgroup(), dest_ip, 
451                             dest_host)) {
452                 DEBUG(0, ("Could not lookup up PDC name for domain %s\n",
453                           lp_workgroup()));
454                 return NULL;
455         }
456
457         get_myname((*global_myname)?NULL:global_myname);
458         strupper(global_myname);
459
460         make_nmb_name(&called, dns_to_netbios_name(dest_host), 0x20);
461         make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
462
463         /* Establish a SMB connection */
464
465         if (!cli_establish_connection(cli, dest_host, dest_ip, &calling, 
466                                       &called, "IPC$", "IPC", False, True)) {
467                 return NULL;
468         }
469         
470         return cli;
471 }
472
473 /* Main function */
474
475  int main(int argc, char **argv)
476 {
477         BOOL do_sam_sync = False, do_sam_repl = False;
478         struct cli_state cli;
479         NTSTATUS result;
480         int opt;
481         extern pstring debugf;
482         BOOL interactive = False, do_smbpasswd_output = False;
483         BOOL verbose = False;
484         uint32 low_serial = 0;
485         unsigned char trust_passwd[16];
486         fstring username, domain, password;
487
488         if (argc == 1) {
489                 usage();
490                 return 1;
491         }
492
493         ZERO_STRUCT(username);
494         ZERO_STRUCT(domain);
495         ZERO_STRUCT(password);
496
497         /* Parse command line options */
498
499         while((opt = getopt(argc, argv, "s:d:SR:hiU:W:pV")) != EOF) {
500                 switch (opt) {
501                 case 's':
502                         pstrcpy(dyn_CONFIGFILE, optarg);
503                         break;
504                 case 'd':
505                         DEBUGLEVEL = atoi(optarg);
506                         break;
507                 case 'S':
508                         do_sam_sync = 1;
509                         break;
510                 case 'R':
511                         do_sam_repl = 1;
512                         low_serial = atoi(optarg);
513                         break;
514                 case 'i':
515                         interactive = True;
516                         break;
517                 case 'U': {
518                         char *lp;
519
520                         fstrcpy(username,optarg);
521                         if ((lp=strchr_m(username,'%'))) {
522                                 *lp = 0;
523                                 fstrcpy(password,lp+1);
524                                 memset(strchr_m(optarg, '%') + 1, 'X',
525                                        strlen(password));
526                         }
527                         break;
528                 }
529                 case 'W':
530                         pstrcpy(domain, optarg);
531                         break;
532                 case 'p':
533                         do_smbpasswd_output = True;
534                         break;
535                 case 'V':
536                         verbose = True;
537                         break;
538                case 'h':
539                 default:
540                         usage();
541                         exit(1);
542                 }
543         }
544
545         argc -= optind;
546
547         if (argc > 0) {
548                 usage();
549                 return 1;
550         }
551
552         /* Initialise samba */
553
554         slprintf(debugf, sizeof(debugf) - 1, "%s/log.%s", dyn_LOGFILEBASE, 
555                  "samsync");
556
557         setup_logging("samsync", interactive);
558
559         if (!interactive)
560                 reopen_logs();
561
562         if (!lp_load(dyn_CONFIGFILE, True, False, False)) {
563                 fprintf(stderr, "Can't load %s\n", dyn_CONFIGFILE);
564         }
565
566         load_interfaces();
567
568         /* Check arguments make sense */
569
570         if (do_sam_sync && do_sam_repl) {
571                 fprintf(stderr, "cannot specify both -S and -R\n");
572                 return 1;
573
574         }
575
576         if (!do_sam_sync && !do_sam_repl) {
577                 fprintf(stderr, "must specify either -S or -R\n");
578                 return 1;
579         }
580
581         if (do_sam_repl && low_serial == 0) {
582                 fprintf(stderr, "serial number must be positive\n");
583                 return 1;
584         }
585
586         /* BDC operations require the machine account password */
587
588         if (!secrets_init()) {
589                 DEBUG(0, ("Unable to initialise secrets database\n"));
590                 return 1;
591         }
592
593         if (!secrets_fetch_trust_account_password(lp_workgroup(), 
594                                                   trust_passwd, NULL)) {
595                 DEBUG(0, ("could not fetch trust account password\n"));
596                 return 1;
597         }        
598
599         /* Perform sync or replication */
600
601         if (!init_connection(&cli, username, domain, password))
602                 return 1;
603
604         if (do_sam_sync)
605                 result = sam_sync(&cli, trust_passwd, do_smbpasswd_output, verbose);
606
607         if (do_sam_repl)
608                 result = sam_repl(&cli, trust_passwd, low_serial);
609
610         if (!NT_STATUS_IS_OK(result)) {
611                 DEBUG(0, ("%s\n", get_nt_error_msg(result)));
612                 return 1;
613         }
614
615         return 0;
616 }