Started adding some help/usage info for rpcclient commands.
[samba.git] / source / rpcclient / rpcclient.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.2
4    RPC pipe client
5
6    Copyright (C) Tim Potter 2000
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 extern int DEBUGLEVEL;
26 extern fstring 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                 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 domain */
191
192 void fetch_domain_sid(struct cli_state *cli)
193 {
194         POLICY_HND pol;
195         uint32 result = 0, info_class = 5;
196         fstring domain_name;
197         static BOOL got_domain_sid;
198         TALLOC_CTX *mem_ctx;
199
200         if (got_domain_sid) return;
201
202         if (!(mem_ctx=talloc_init()))
203         {
204                 DEBUG(0,("fetch_domain_sid: talloc_init returned NULL!\n"));
205                 goto error;
206         }
207
208
209         if (!cli_nt_session_open (cli, PIPE_LSARPC)) {
210                 fprintf(stderr, "could not initialise lsa pipe\n");
211                 goto error;
212         }
213         
214         if ((result = cli_lsa_open_policy(cli, mem_ctx, True, 
215                                           SEC_RIGHTS_MAXIMUM_ALLOWED,
216                                           &pol) != NT_STATUS_NOPROBLEMO)) {
217                 goto error;
218         }
219
220         if ((result = cli_lsa_query_info_policy(cli, mem_ctx, &pol, info_class, 
221                                                 domain_name, &domain_sid))
222             != NT_STATUS_NOPROBLEMO) {
223                 goto error;
224         }
225
226         got_domain_sid = True;
227
228         cli_lsa_close(cli, mem_ctx, &pol);
229         cli_nt_session_close(cli);
230         talloc_destroy(mem_ctx);
231
232         return;
233
234  error:
235         fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain);
236
237         if (result != NT_STATUS_NOPROBLEMO) {
238                 fprintf(stderr, "error: %s\n", get_nt_error_msg(result));
239         }
240
241         exit(1);
242 }
243
244 /* Initialise client credentials for authenticated pipe access */
245
246 void init_rpcclient_creds(struct ntuser_creds *creds, char* username,
247                           char* domain, char* password)
248 {
249         ZERO_STRUCTP(creds);
250
251         if (lp_encrypted_passwords()) {
252                 pwd_make_lm_nt_16(&creds->pwd, password);
253         } else {
254                 pwd_set_cleartext(&creds->pwd, password);
255         }
256
257         fstrcpy(creds->user_name, username);
258         fstrcpy(creds->domain, domain);
259
260         if (! *username) {
261                 creds->pwd.null_pwd = True;
262         }
263 }
264
265
266 /* Display help on commands */
267
268 static uint32 cmd_help(struct cli_state *cli, int argc, char **argv)
269 {
270         struct cmd_list *tmp;
271         struct cmd_set *tmp_set;
272
273         /* Usage */
274
275         if (argc > 2) {
276                 printf("Usage: %s [command]\n", argv[0]);
277                 return 0;
278         }
279
280         /* Help on one command */
281
282         if (argc == 2) {
283                 for (tmp = cmd_list; tmp; tmp = tmp->next) {
284                         
285                         tmp_set = tmp->cmd_set;
286
287                         while(tmp_set->name) {
288                                 if (strequal(argv[1], tmp_set->name)) {
289                                         if (tmp_set->usage &&
290                                             tmp_set->usage[0])
291                                                 printf("%s\n", tmp_set->usage);
292                                         else
293                                                 printf("No help for %s\n", tmp_set->name);
294
295                                         return 0;
296                                 }
297
298                                 tmp_set++;
299                         }
300                 }
301
302                 printf("No such command: %s\n", argv[1]);
303                 return 0;
304         }
305
306         /* List all commands */
307
308         for (tmp = cmd_list; tmp; tmp = tmp->next) {
309
310                 tmp_set = tmp->cmd_set;
311
312                 while(tmp_set->name) {
313
314                         printf("%15s\t\t%s\n", tmp_set->name,
315                                tmp_set->description);
316
317                         tmp_set++;
318                 }
319         }
320
321         return 0;
322 }
323
324 /* Change the debug level */
325
326 static uint32 cmd_debuglevel(struct cli_state *cli, int argc, char **argv)
327 {
328         if (argc > 2) {
329                 printf("Usage: %s [debuglevel]\n", argv[0]);
330                 return NT_STATUS_NOPROBLEMO;
331         }
332
333         if (argc == 2) {
334                 DEBUGLEVEL = atoi(argv[1]);
335         }
336
337         printf("debuglevel is %d\n", DEBUGLEVEL);
338
339         return NT_STATUS_NOPROBLEMO;
340 }
341
342 static uint32 cmd_quit(struct cli_state *cli, int argc, char **argv)
343 {
344         exit(0);
345         return NT_STATUS_NOPROBLEMO; /* NOTREACHED */
346 }
347
348 /* Build in rpcclient commands */
349
350 static struct cmd_set rpcclient_commands[] = {
351
352         { "GENERAL OPTIONS" },
353
354         { "help",       cmd_help,       "Get help on commands", "[command]" },
355         { "?",          cmd_help,       "Get help on commands", "[command]" },
356         { "debuglevel", cmd_debuglevel, "Set debug level", "level" },
357         { "exit",       cmd_quit,       "Exit program", "" },
358         { "quit",       cmd_quit,       "Exit program", "" },
359
360         { NULL }
361 };
362
363 static struct cmd_set separator_command[] = {
364         { "---------------", NULL,      "----------------------" },
365         { NULL }
366 };
367
368
369 /* Various pipe commands */
370
371 extern struct cmd_set lsarpc_commands[];
372 extern struct cmd_set samr_commands[];
373 extern struct cmd_set spoolss_commands[];
374 extern struct cmd_set netlogon_commands[];
375 extern struct cmd_set srvsvc_commands[];
376 extern struct cmd_set dfs_commands[];
377
378 static struct cmd_set *rpcclient_command_list[] = {
379         rpcclient_commands,
380         lsarpc_commands,
381         samr_commands,
382         spoolss_commands,
383         netlogon_commands,
384         srvsvc_commands,
385         dfs_commands,
386         NULL
387 };
388
389 void add_command_set(struct cmd_set *cmd_set)
390 {
391         struct cmd_list *entry;
392
393         if (!(entry = (struct cmd_list *)malloc(sizeof(struct cmd_list)))) {
394                 DEBUG(0, ("out of memory\n"));
395                 return;
396         }
397
398         ZERO_STRUCTP(entry);
399
400         entry->cmd_set = cmd_set;
401         DLIST_ADD(cmd_list, entry);
402 }
403
404 static uint32 do_cmd(struct cli_state *cli, struct cmd_set *cmd_entry, char *cmd)
405 {
406         char *p = cmd, **argv = NULL;
407         uint32 result;
408         pstring buf;
409         int argc = 1, i;
410
411         next_token_nr(&p, buf, " ", sizeof(buf));
412
413         /* Count number of arguments first time through the loop then
414            allocate memory and strdup them. */
415
416  again:
417         while(next_token_nr(NULL, buf, " ", sizeof(buf))) {
418                 if (argv) {
419                         argv[argc] = strdup(buf);
420                 }
421                 
422                 argc++;
423         }
424                                 
425         if (!argv) {
426
427                 /* Create argument list */
428
429                 argv = (char **)malloc(sizeof(char *) * argc);
430
431                 if (!argv) {
432                         fprintf(stderr, "out of memoryx\n");
433                         return 0;
434                 }
435                                         
436                 p = cmd;
437                 next_token_nr(&p, buf, " ", sizeof(buf));
438                 argv[0] = strdup(buf);
439                 argc = 1;
440                                         
441                 goto again;
442         }
443
444         /* Call the function */
445         if (cmd_entry->fn) {
446                 result = cmd_entry->fn(cli, argc, argv);
447         }
448         else {
449                 fprintf (stderr, "Invalid command\n");
450                 result = NT_STATUS_INVALID_PARAMETER;
451         }
452
453                                                 
454         /* Cleanup */
455         for (i = 0; i < argc; i++) {
456                 free(argv[i]);
457         }
458         
459         free(argv);
460         
461         return result;
462 }
463
464 /* Process a command entered at the prompt or as part of -c */
465
466 static uint32 process_cmd(struct cli_state *cli, char *cmd)
467 {
468         struct cmd_list *temp_list;
469         BOOL found = False;
470         pstring buf;
471         char *p = cmd;
472         uint32 result=0;
473         int len = 0;
474
475         if (cmd[strlen(cmd) - 1] == '\n')
476                 cmd[strlen(cmd) - 1] = '\0';
477
478         if (!next_token_nr(&p, buf, " ", sizeof(buf))) {
479                 return 0;
480         }
481
482         /* strip the trainly \n if it exsists */
483         len = strlen(buf);
484         if (buf[len-1] == '\n')
485                 buf[len-1] = '\0';
486
487         /* Search for matching commands */
488
489         for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) {
490                 struct cmd_set *temp_set = temp_list->cmd_set;
491
492                 while(temp_set->name) {
493                         if (strequal(buf, temp_set->name)) {
494                                 found = True;
495                                 result = do_cmd(cli, temp_set, cmd);
496                                 goto done;
497                         }
498                         temp_set++;
499                 }
500         }
501
502  done:
503         if (!found && buf[0]) {
504                 printf("command not found: %s\n", buf);
505                 return 0;
506         }
507
508         if (result != 0) {
509                 printf("result was %s\n", get_nt_error_msg(result));
510         }
511
512         return result;
513 }
514
515 /************************************************************************/
516 struct cli_state *setup_connection(struct cli_state *cli, char *system_name,
517                                    struct ntuser_creds *creds)
518 {
519         struct in_addr dest_ip;
520         struct nmb_name calling, called;
521         fstring dest_host;
522         extern pstring global_myname;
523         struct ntuser_creds anon;
524
525         /* Initialise cli_state information */
526         if (!cli_initialise(cli)) {
527                 return NULL;
528         }
529
530         if (!creds) {
531                 ZERO_STRUCT(anon);
532                 anon.pwd.null_pwd = 1;
533                 creds = &anon;
534         }
535
536         cli_init_creds(cli, creds);
537
538         /* Establish a SMB connection */
539         if (!resolve_srv_name(system_name, dest_host, &dest_ip)) {
540                 return NULL;
541         }
542
543         make_nmb_name(&called, dns_to_netbios_name(dest_host), 0x20);
544         make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
545
546         if (!cli_establish_connection(cli, dest_host, &dest_ip, &calling, 
547                                       &called, "IPC$", "IPC", False, True)) {
548                 return NULL;
549         }
550         
551         return cli;
552 }
553
554
555 /* Print usage information */
556 static void usage(void)
557 {
558         printf("Usage: rpcclient [options] server\n");
559
560         printf("\t-A authfile           file containing user credentials\n");
561         printf("\t-c \"command string\"   execute semicolon separated cmds\n");
562         printf("\t-d debuglevel         set the debuglevel\n");
563         printf("\t-l logfile            name of logfile to use as opposed to stdout\n");
564         printf("\t-h                    Print this help message.\n");
565         printf("\t-N                    don't ask for a password\n");
566         printf("\t-s configfile         specify an alternative config file\n");
567         printf("\t-U username           set the network username\n");
568         printf("\t-W domain             set the domain name for user account\n");
569         printf("\n");
570 }
571
572 /* Main function */
573
574  int main(int argc, char *argv[])
575 {
576         extern char             *optarg;
577         extern int              optind;
578         extern pstring          global_myname;
579         BOOL                    got_pass = False;
580         BOOL                    interactive = True;
581         int                     opt;
582         int                     olddebug;
583         pstring                 cmdstr = "", 
584                                 servicesf = CONFIGFILE;
585         struct ntuser_creds     creds;
586         struct cli_state        cli;
587         fstring                 password,
588                                 username,
589                                 domain,
590                                 server;
591         struct cmd_set **cmd_set;
592
593         setlinebuf(stdout);
594
595         DEBUGLEVEL = 1;
596
597         while ((opt = getopt(argc, argv, "A:s:Nd:U:W:c:l:h")) != EOF) {
598                 switch (opt) {
599                 case 'A':
600                         /* only get the username, password, and domain from the file */
601                         read_authfile (optarg, username, password, domain);
602                         if (strlen (password))
603                                 got_pass = True;
604                         break;
605
606                 case 'c':
607                         pstrcpy(cmdstr, optarg);
608                         break;
609
610                 case 'd':
611                         DEBUGLEVEL = atoi(optarg);
612                         break;
613
614                 case 'l':
615                         slprintf(debugf, sizeof(debugf) - 1, "%s.client", optarg);
616                         interactive = False;
617                         break;
618
619                 case 'N':
620                         got_pass = True;
621                         break;
622                         
623                 case 's':
624                         pstrcpy(servicesf, optarg);
625                         break;
626
627                 case 'U': {
628                         char *lp;
629                         pstrcpy(username,optarg);
630                         if ((lp=strchr_m(username,'%'))) {
631                                 *lp = 0;
632                                 pstrcpy(password,lp+1);
633                                 got_pass = True;
634                                 memset(strchr_m(optarg,'%')+1,'X',strlen(password));
635                         }
636                         break;
637                 }
638                 
639                 case 'W':
640                         pstrcpy(domain, optarg);
641                         break;
642                         
643                 case 'h':
644                 default:
645                         usage();
646                         exit(1);
647                 }
648         }
649
650         argv += optind;
651         argc -= optind;
652
653         /* Parse options */
654         if (argc < 1) {
655                 usage();
656                 return 0;
657         }
658         
659         pstrcpy(server, argv[0]);
660
661         /* the following functions are part of the Samba debugging
662            facilities.  See lib/debug.c */
663         setup_logging("rpcclient", interactive);
664         if (!interactive) 
665                 reopen_logs();
666         
667         /* Load smb.conf file */
668         /* FIXME!  How to get this DEBUGLEVEL to last over lp_load()? */
669         olddebug = DEBUGLEVEL;
670         if (!lp_load(servicesf,True,False,False)) {
671                 fprintf(stderr, "Can't load %s\n", servicesf);
672         }
673         DEBUGLEVEL = olddebug;
674
675         load_interfaces();
676
677         TimeInit();
678
679         get_myname((*global_myname)?NULL:global_myname);
680         strupper(global_myname);
681         
682         /*
683          * initialize the credentials struct.  Get password
684          * from stdin if necessary
685          */
686         if (!strlen(username) && !got_pass)
687                 get_username(username);
688                 
689         if (!got_pass) {
690                 init_rpcclient_creds (&creds, username, domain, "");
691                 pwd_read(&creds.pwd, "Enter Password: ", lp_encrypted_passwords());
692         }
693         else {
694                 init_rpcclient_creds (&creds, username, domain, password);
695         }
696         memset(password,'X',strlen(password));
697
698         /* open a connection to the specified server */
699         ZERO_STRUCTP (&cli);
700         if (!setup_connection (&cli, server, &creds)) {
701                 return 0;
702         }
703         
704         /* There are no pointers in ntuser_creds struct so zero it out */
705
706         ZERO_STRUCTP (&creds);
707         
708         /* Load command lists */
709
710         cmd_set = rpcclient_command_list;
711
712         while(*cmd_set) {
713                 add_command_set(*cmd_set);
714                 add_command_set(separator_command);
715                 cmd_set++;
716         }
717
718         /* Do anything specified with -c */
719         if (cmdstr[0]) {
720                 char    *cmd;
721                 char    *p = cmdstr;
722  
723                 while((cmd=next_command(&p)) != NULL) {
724                         process_cmd(&cli, cmd);
725                 }
726  
727                 return 0;
728         }
729
730         /* Loop around accepting commands */
731
732         while(1) {
733                 pstring prompt;
734                 char *line;
735
736                 slprintf(prompt, sizeof(prompt) - 1, "rpcclient $> ");
737
738                 line = smb_readline(prompt, NULL, completion_fn);
739
740                 if (line == NULL)
741                         break;
742
743                 if (line[0] != '\n')
744                         process_cmd(&cli, line);
745         }
746
747         return 0;
748 }