allow the samr commands to work back and the help too ;-)
[sfrench/samba-autobuild/.git] / source3 / rpcclient / rpcclient.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.2
4    RPC pipe client
5
6    Copyright (C) Tim Potter 2000-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 #include "rpcclient.h"
25
26 extern pstring debugf;
27
28 DOM_SID domain_sid;
29
30 /* List to hold groups of commands */
31
32 static struct cmd_list {
33         struct cmd_list *prev, *next;
34         struct cmd_set *cmd_set;
35 } *cmd_list;
36
37 /****************************************************************************
38 handle completion of commands for readline
39 ****************************************************************************/
40 static char **completion_fn(char *text, int start, int end)
41 {
42 #define MAX_COMPLETIONS 100
43         char **matches;
44         int i, count=0;
45         struct cmd_list *commands = cmd_list;
46
47 #if 0   /* JERRY */
48         /* FIXME!!!  -- what to do when completing argument? */
49         /* for words not at the start of the line fallback 
50            to filename completion */
51         if (start) 
52                 return NULL;
53 #endif
54
55         /* make sure we have a list of valid commands */
56         if (!commands) 
57                 return NULL;
58
59         matches = (char **)malloc(sizeof(matches[0])*MAX_COMPLETIONS);
60         if (!matches) return NULL;
61
62         matches[count++] = strdup(text);
63         if (!matches[0]) return NULL;
64
65         while (commands && count < MAX_COMPLETIONS-1) 
66         {
67                 if (!commands->cmd_set)
68                         break;
69                 
70                 for (i=0; commands->cmd_set[i].name; i++)
71                 {
72                         if ((strncmp(text, commands->cmd_set[i].name, strlen(text)) == 0) &&
73                                 commands->cmd_set[i].fn) 
74                         {
75                                 matches[count] = strdup(commands->cmd_set[i].name);
76                                 if (!matches[count]) 
77                                         return NULL;
78                                 count++;
79                         }
80                 }
81                 
82                 commands = commands->next;
83                 
84         }
85
86         if (count == 2) {
87                 SAFE_FREE(matches[0]);
88                 matches[0] = strdup(matches[1]);
89         }
90         matches[count] = NULL;
91         return matches;
92 }
93
94 /***********************************************************************
95  * read in username/password credentials from a file
96  */
97 static void read_authfile (
98         char *filename, 
99         char* username, 
100         char* password, 
101         char* domain
102 )
103 {
104         FILE *auth;
105         fstring buf;
106         uint16 len = 0;
107         char *ptr, *val, *param;
108                                
109         if ((auth=sys_fopen(filename, "r")) == NULL)
110         {
111                 printf ("ERROR: Unable to open credentials file!\n");
112                 return;
113         }
114                                 
115         while (!feof(auth))
116         {  
117                 /* get a line from the file */
118                 if (!fgets (buf, sizeof(buf), auth))
119                         continue;
120                 
121                 len = strlen(buf);
122                 
123                 /* skip empty lines */                  
124                 if ((len) && (buf[len-1]=='\n'))
125                 {
126                         buf[len-1] = '\0';
127                         len--;
128                 }       
129                 if (len == 0)
130                         continue;
131                                         
132                 /* break up the line into parameter & value.
133                    will need to eat a little whitespace possibly */
134                 param = buf;
135                 if (!(ptr = strchr_m(buf, '=')))
136                         continue;
137                 val = ptr+1;
138                 *ptr = '\0';
139                                         
140                 /* eat leading white space */
141                 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
142                         val++;
143                                         
144                 if (strwicmp("password", param) == 0)
145                         fstrcpy (password, val);
146                 else if (strwicmp("username", param) == 0)
147                         fstrcpy (username, val);
148                 else if (strwicmp("domain", param) == 0)
149                         fstrcpy (domain, val);
150                                                 
151                 memset(buf, 0, sizeof(buf));
152         }
153         fclose(auth);
154         
155         return;
156 }
157
158 static char* next_command (char** cmdstr)
159 {
160         static pstring          command;
161         char                    *p;
162         
163         if (!cmdstr || !(*cmdstr))
164                 return NULL;
165         
166         p = strchr_m(*cmdstr, ';');
167         if (p)
168                 *p = '\0';
169         pstrcpy(command, *cmdstr);
170         *cmdstr = p;
171         
172         return command;
173 }
174
175 static void get_username (char *username)
176 {
177         if (getenv("USER"))
178                 pstrcpy(username,getenv("USER"));
179  
180         if (*username == 0 && getenv("LOGNAME"))
181                 pstrcpy(username,getenv("LOGNAME"));
182  
183         if (*username == 0) {
184                 pstrcpy(username,"GUEST");
185         }
186
187         return;
188 }
189
190 /* Fetch the SID for this computer */
191
192 void fetch_machine_sid(struct cli_state *cli)
193 {
194         POLICY_HND pol;
195         NTSTATUS result = NT_STATUS_OK;
196         uint32 info_class = 5;
197         fstring domain_name;
198         static BOOL got_domain_sid;
199         TALLOC_CTX *mem_ctx;
200
201         if (got_domain_sid) return;
202
203         if (!(mem_ctx=talloc_init()))
204         {
205                 DEBUG(0,("fetch_domain_sid: talloc_init returned NULL!\n"));
206                 goto error;
207         }
208
209
210         if (!cli_nt_session_open (cli, PIPE_LSARPC)) {
211                 fprintf(stderr, "could not initialise lsa pipe\n");
212                 goto error;
213         }
214         
215         result = cli_lsa_open_policy(cli, mem_ctx, True, 
216                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
217                                      &pol);
218         if (!NT_STATUS_IS_OK(result)) {
219                 goto error;
220         }
221
222         result = cli_lsa_query_info_policy(cli, mem_ctx, &pol, info_class, 
223                                            domain_name, &domain_sid);
224         if (!NT_STATUS_IS_OK(result)) {
225                 goto error;
226         }
227
228         got_domain_sid = True;
229
230         cli_lsa_close(cli, mem_ctx, &pol);
231         cli_nt_session_close(cli);
232         talloc_destroy(mem_ctx);
233
234         return;
235
236  error:
237         fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain);
238
239         if (!NT_STATUS_IS_OK(result)) {
240                 fprintf(stderr, "error: %s\n", get_nt_error_msg(result));
241         }
242
243         exit(1);
244 }
245
246 /* Initialise client credentials for authenticated pipe access */
247
248 void init_rpcclient_creds(struct ntuser_creds *creds, char* username,
249                           char* domain, char* password)
250 {
251         ZERO_STRUCTP(creds);
252
253         if (lp_encrypted_passwords()) {
254                 pwd_make_lm_nt_16(&creds->pwd, password);
255         } else {
256                 pwd_set_cleartext(&creds->pwd, password);
257         }
258
259         fstrcpy(creds->user_name, username);
260         fstrcpy(creds->domain, domain);
261
262         if (! *username) {
263                 creds->pwd.null_pwd = True;
264         }
265 }
266
267
268 /* Display help on commands */
269
270 static NTSTATUS cmd_help(struct cli_state *cli, TALLOC_CTX *mem_ctx,
271                          int argc, char **argv)
272 {
273         struct cmd_list *tmp;
274         struct cmd_set *tmp_set;
275
276         /* Usage */
277
278         if (argc > 2) {
279                 printf("Usage: %s [command]\n", argv[0]);
280                 return NT_STATUS_OK;
281         }
282
283         /* Help on one command */
284
285         if (argc == 2) {
286                 for (tmp = cmd_list; tmp; tmp = tmp->next) {
287                         
288                         tmp_set = tmp->cmd_set;
289
290                         while(tmp_set->name) {
291                                 if (strequal(argv[1], tmp_set->name)) {
292                                         if (tmp_set->usage &&
293                                             tmp_set->usage[0])
294                                                 printf("%s\n", tmp_set->usage);
295                                         else
296                                                 printf("No help for %s\n", tmp_set->name);
297
298                                         return NT_STATUS_OK;
299                                 }
300
301                                 tmp_set++;
302                         }
303                 }
304
305                 printf("No such command: %s\n", argv[1]);
306                 return NT_STATUS_OK;
307         }
308
309         /* List all commands */
310
311         for (tmp = cmd_list; tmp; tmp = tmp->next) {
312
313                 tmp_set = tmp->cmd_set;
314
315                 while(tmp_set->name) {
316
317                         printf("%15s\t\t%s\n", tmp_set->name,
318                                tmp_set->description);
319
320                         tmp_set++;
321                 }
322         }
323
324         return NT_STATUS_OK;
325 }
326
327 /* Change the debug level */
328
329 static NTSTATUS cmd_debuglevel(struct cli_state *cli, TALLOC_CTX *mem_ctx,
330                                int argc, char **argv)
331 {
332         if (argc > 2) {
333                 printf("Usage: %s [debuglevel]\n", argv[0]);
334                 return NT_STATUS_OK;
335         }
336
337         if (argc == 2) {
338                 DEBUGLEVEL = atoi(argv[1]);
339         }
340
341         printf("debuglevel is %d\n", DEBUGLEVEL);
342
343         return NT_STATUS_OK;
344 }
345
346 static NTSTATUS cmd_quit(struct cli_state *cli, TALLOC_CTX *mem_ctx,
347                          int argc, char **argv)
348 {
349         exit(0);
350         return NT_STATUS_OK; /* NOTREACHED */
351 }
352
353 /* Build in rpcclient commands */
354
355 static struct cmd_set rpcclient_commands[] = {
356
357         { "GENERAL OPTIONS" },
358
359         { "help",       cmd_help,       NULL,   "Get help on commands", "[command]" },
360         { "?",          cmd_help,       NULL,   "Get help on commands", "[command]" },
361         { "debuglevel", cmd_debuglevel, NULL,   "Set debug level", "level" },
362         { "exit",       cmd_quit,       NULL,   "Exit program", "" },
363         { "quit",       cmd_quit,       NULL,   "Exit program", "" },
364
365         { NULL }
366 };
367
368 static struct cmd_set separator_command[] = {
369         { "---------------", NULL,      NULL,   "----------------------" },
370         { NULL }
371 };
372
373
374 /* Various pipe commands */
375
376 extern struct cmd_set lsarpc_commands[];
377 extern struct cmd_set samr_commands[];
378 extern struct cmd_set spoolss_commands[];
379 extern struct cmd_set netlogon_commands[];
380 extern struct cmd_set srvsvc_commands[];
381 extern struct cmd_set dfs_commands[];
382 extern struct cmd_set reg_commands[];
383
384 static struct cmd_set *rpcclient_command_list[] = {
385         rpcclient_commands,
386         lsarpc_commands,
387         samr_commands,
388         spoolss_commands,
389         netlogon_commands,
390         srvsvc_commands,
391         dfs_commands,
392         reg_commands,
393         NULL
394 };
395
396 static void add_command_set(struct cmd_set *cmd_set)
397 {
398         struct cmd_list *entry;
399
400         if (!(entry = (struct cmd_list *)malloc(sizeof(struct cmd_list)))) {
401                 DEBUG(0, ("out of memory\n"));
402                 return;
403         }
404
405         ZERO_STRUCTP(entry);
406
407         entry->cmd_set = cmd_set;
408         DLIST_ADD(cmd_list, entry);
409 }
410
411 static NTSTATUS do_cmd(struct cli_state *cli, struct cmd_set *cmd_entry, 
412                        char *cmd)
413 {
414         char *p = cmd, **argv = NULL;
415         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
416         pstring buf;
417         int argc = 0, i;
418
419         /* Count number of arguments first time through the loop then
420            allocate memory and strdup them. */
421
422  again:
423         while(next_token(&p, buf, " ", sizeof(buf))) {
424                 if (argv) {
425                         argv[argc] = strdup(buf);
426                 }
427                 
428                 argc++;
429         }
430                                 
431         if (!argv) {
432
433                 /* Create argument list */
434
435                 argv = (char **)malloc(sizeof(char *) * argc);
436                 memset(argv, 0, sizeof(char *) * argc);
437
438                 if (!argv) {
439                         fprintf(stderr, "out of memory\n");
440                         result = NT_STATUS_NO_MEMORY;
441                         goto done;
442                 }
443                                         
444                 p = cmd;
445                 argc = 0;
446                                         
447                 goto again;
448         }
449
450         /* Call the function */
451
452         if (cmd_entry->fn) {
453                 TALLOC_CTX *mem_ctx;
454
455                 /* Create mem_ctx */
456
457                 if (!(mem_ctx = talloc_init())) {
458                         DEBUG(0, ("talloc_init() failed\n"));
459                         goto done;
460                 }
461
462                 /* Open pipe */
463
464                 if (cmd_entry->pipe)
465                         if (!cli_nt_session_open(cli, cmd_entry->pipe)) {
466                                 DEBUG(0, ("Could not initialise %s\n",
467                                           cmd_entry->pipe));
468                                 goto done;
469                         }
470
471                 /* Run command */
472
473                 result = cmd_entry->fn(cli, mem_ctx, argc, argv);
474
475                 /* Cleanup */
476
477                 if (cmd_entry->pipe)
478                         cli_nt_session_close(cli);
479
480                 talloc_destroy(mem_ctx);
481
482         } else {
483                 fprintf (stderr, "Invalid command\n");
484                 goto done;
485         }
486
487  done:
488                                                 
489         /* Cleanup */
490
491         if (argv) {
492                 for (i = 0; i < argc; i++)
493                         SAFE_FREE(argv[i]);
494         
495                 SAFE_FREE(argv);
496         }
497         
498         return result;
499 }
500
501 /* Process a command entered at the prompt or as part of -c */
502
503 static NTSTATUS process_cmd(struct cli_state *cli, char *cmd)
504 {
505         struct cmd_list *temp_list;
506         BOOL found = False;
507         pstring buf;
508         char *p = cmd;
509         NTSTATUS result = NT_STATUS_OK;
510         int len = 0;
511
512         if (cmd[strlen(cmd) - 1] == '\n')
513                 cmd[strlen(cmd) - 1] = '\0';
514
515         if (!next_token(&p, buf, " ", sizeof(buf))) {
516                 return NT_STATUS_OK;
517         }
518
519         /* strip the trainly \n if it exsists */
520         len = strlen(buf);
521         if (buf[len-1] == '\n')
522                 buf[len-1] = '\0';
523
524         /* Search for matching commands */
525
526         for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) {
527                 struct cmd_set *temp_set = temp_list->cmd_set;
528
529                 while(temp_set->name) {
530                         if (strequal(buf, temp_set->name)) {
531                                 found = True;
532                                 result = do_cmd(cli, temp_set, cmd);
533
534                                 goto done;
535                         }
536                         temp_set++;
537                 }
538         }
539
540  done:
541         if (!found && buf[0]) {
542                 printf("command not found: %s\n", buf);
543                 return NT_STATUS_OK;
544         }
545
546         if (!NT_STATUS_IS_OK(result)) {
547                 printf("result was %s\n", get_nt_error_msg(result));
548         }
549
550         return result;
551 }
552
553 /************************************************************************/
554 struct cli_state *setup_connection(struct cli_state *cli, char *system_name,
555                                    struct ntuser_creds *creds)
556 {
557         struct in_addr dest_ip;
558         struct nmb_name calling, called;
559         fstring dest_host;
560         extern pstring global_myname;
561         struct ntuser_creds anon;
562
563         /* Initialise cli_state information */
564         if (!cli_initialise(cli)) {
565                 return NULL;
566         }
567
568         if (!creds) {
569                 ZERO_STRUCT(anon);
570                 anon.pwd.null_pwd = 1;
571                 creds = &anon;
572         }
573
574         cli_init_creds(cli, creds);
575
576         /* Establish a SMB connection */
577         if (!resolve_srv_name(system_name, dest_host, &dest_ip)) {
578                 return NULL;
579         }
580
581         make_nmb_name(&called, dns_to_netbios_name(dest_host), 0x20);
582         make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
583
584         if (!cli_establish_connection(cli, dest_host, &dest_ip, &calling, 
585                                       &called, "IPC$", "IPC", False, True)) {
586                 return NULL;
587         }
588         
589         return cli;
590 }
591
592
593 /* Print usage information */
594 static void usage(void)
595 {
596         printf("Usage: rpcclient server [options]\n");
597
598         printf("\t-A authfile           file containing user credentials\n");
599         printf("\t-c \"command string\"   execute semicolon separated cmds\n");
600         printf("\t-d debuglevel         set the debuglevel\n");
601         printf("\t-l logfile            name of logfile to use as opposed to stdout\n");
602         printf("\t-h                    Print this help message.\n");
603         printf("\t-N                    don't ask for a password\n");
604         printf("\t-s configfile         specify an alternative config file\n");
605         printf("\t-U username           set the network username\n");
606         printf("\t-W domain             set the domain name for user account\n");
607         printf("\n");
608 }
609
610 /* Main function */
611
612  int main(int argc, char *argv[])
613 {
614         extern char             *optarg;
615         extern int              optind;
616         extern pstring          global_myname;
617         BOOL                    got_pass = False;
618         BOOL                    interactive = True;
619         int                     opt;
620         int                     olddebug;
621         pstring                 cmdstr = "", 
622                                 servicesf = CONFIGFILE;
623         struct ntuser_creds     creds;
624         struct cli_state        cli;
625         fstring                 password,
626                                 username,
627                                 domain,
628                                 server;
629         struct cmd_set **cmd_set;
630
631         setlinebuf(stdout);
632
633         DEBUGLEVEL = 1;
634
635         while ((opt = getopt(argc, argv, "A:s:Nd:U:W:c:l:h")) != EOF) {
636                 switch (opt) {
637                 case 'A':
638                         /* only get the username, password, and domain from the file */
639                         read_authfile (optarg, username, password, domain);
640                         if (strlen (password))
641                                 got_pass = True;
642                         break;
643
644                 case 'c':
645                         pstrcpy(cmdstr, optarg);
646                         break;
647
648                 case 'd':
649                         DEBUGLEVEL = atoi(optarg);
650                         break;
651
652                 case 'l':
653                         slprintf(debugf, sizeof(debugf) - 1, "%s.client", optarg);
654                         interactive = False;
655                         break;
656
657                 case 'N':
658                         got_pass = True;
659                         break;
660                         
661                 case 's':
662                         pstrcpy(servicesf, optarg);
663                         break;
664
665                 case 'U': {
666                         char *lp;
667                         pstrcpy(username,optarg);
668                         if ((lp=strchr_m(username,'%'))) {
669                                 *lp = 0;
670                                 pstrcpy(password,lp+1);
671                                 got_pass = True;
672                                 memset(strchr_m(optarg,'%')+1,'X',strlen(password));
673                         }
674                         break;
675                 }
676                 
677                 case 'W':
678                         pstrcpy(domain, optarg);
679                         break;
680                         
681                 case 'h':
682                 default:
683                         usage();
684                         exit(1);
685                 }
686         }
687
688         argv += optind;
689         argc -= optind;
690
691         /* Parse options */
692         if (argc == 0) {
693                 usage();
694                 return 0;
695         }
696         
697         if (strncmp("//", argv[0], 2) == 0 || strncmp("\\\\", argv[0], 2) == 0)
698                 argv[0] += 2;
699
700         pstrcpy(server, argv[0]);
701
702         /* the following functions are part of the Samba debugging
703            facilities.  See lib/debug.c */
704         setup_logging("rpcclient", interactive);
705         if (!interactive) 
706                 reopen_logs();
707         
708         /* Load smb.conf file */
709         /* FIXME!  How to get this DEBUGLEVEL to last over lp_load()? */
710         olddebug = DEBUGLEVEL;
711         if (!lp_load(servicesf,True,False,False)) {
712                 fprintf(stderr, "Can't load %s\n", servicesf);
713         }
714         DEBUGLEVEL = olddebug;
715
716         load_interfaces();
717
718         TimeInit();
719
720         get_myname((*global_myname)?NULL:global_myname);
721         strupper(global_myname);
722         
723         /*
724          * initialize the credentials struct.  Get password
725          * from stdin if necessary
726          */
727         if (!strlen(username) && !got_pass)
728                 get_username(username);
729                 
730         if (!got_pass) {
731                 init_rpcclient_creds (&creds, username, domain, "");
732                 pwd_read(&creds.pwd, "Enter Password: ", lp_encrypted_passwords());
733         }
734         else {
735                 init_rpcclient_creds (&creds, username, domain, password);
736         }
737         memset(password,'X',sizeof(password));
738
739         /* open a connection to the specified server */
740         ZERO_STRUCTP (&cli);
741         if (!setup_connection (&cli, server, &creds)) {
742                 return 1;
743         }
744         
745         /* There are no pointers in ntuser_creds struct so zero it out */
746
747         ZERO_STRUCTP (&creds);
748         
749         /* Load command lists */
750
751         cmd_set = rpcclient_command_list;
752
753         while(*cmd_set) {
754                 add_command_set(*cmd_set);
755                 add_command_set(separator_command);
756                 cmd_set++;
757         }
758
759         fetch_machine_sid(&cli);
760  
761        /* Do anything specified with -c */
762         if (cmdstr[0]) {
763                 char    *cmd;
764                 char    *p = cmdstr;
765  
766                 while((cmd=next_command(&p)) != NULL) {
767                         process_cmd(&cli, cmd);
768                 }
769  
770                 return 0;
771         }
772
773         /* Loop around accepting commands */
774
775         while(1) {
776                 pstring prompt;
777                 char *line;
778
779                 slprintf(prompt, sizeof(prompt) - 1, "rpcclient $> ");
780
781                 line = smb_readline(prompt, NULL, completion_fn);
782
783                 if (line == NULL)
784                         break;
785
786                 if (line[0] != '\n')
787                         process_cmd(&cli, line);
788         }
789
790         return 0;
791 }