d833043401c5a1bc7f05d92ea44c06ecba071e50
[jra/samba/.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
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 extern struct cmd_set reg_commands[];
378
379 static struct cmd_set *rpcclient_command_list[] = {
380         rpcclient_commands,
381         lsarpc_commands,
382         samr_commands,
383         spoolss_commands,
384         netlogon_commands,
385         srvsvc_commands,
386         dfs_commands,
387         reg_commands,
388         NULL
389 };
390
391 void add_command_set(struct cmd_set *cmd_set)
392 {
393         struct cmd_list *entry;
394
395         if (!(entry = (struct cmd_list *)malloc(sizeof(struct cmd_list)))) {
396                 DEBUG(0, ("out of memory\n"));
397                 return;
398         }
399
400         ZERO_STRUCTP(entry);
401
402         entry->cmd_set = cmd_set;
403         DLIST_ADD(cmd_list, entry);
404 }
405
406 static uint32 do_cmd(struct cli_state *cli, struct cmd_set *cmd_entry, char *cmd)
407 {
408         char *p = cmd, **argv = NULL;
409         uint32 result;
410         pstring buf;
411         int argc = 0, i;
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(&p, 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 memory\n");
433                         return 0;
434                 }
435                                         
436                 p = cmd;
437                 argc = 0;
438                                         
439                 goto again;
440         }
441
442         /* Call the function */
443         if (cmd_entry->fn) {
444                 result = cmd_entry->fn(cli, argc, argv);
445         }
446         else {
447                 fprintf (stderr, "Invalid command\n");
448                 result = NT_STATUS_INVALID_PARAMETER;
449         }
450
451                                                 
452         /* Cleanup */
453         for (i = 0; i < argc; i++) {
454                 free(argv[i]);
455         }
456         
457         free(argv);
458         
459         return result;
460 }
461
462 /* Process a command entered at the prompt or as part of -c */
463
464 static uint32 process_cmd(struct cli_state *cli, char *cmd)
465 {
466         struct cmd_list *temp_list;
467         BOOL found = False;
468         pstring buf;
469         char *p = cmd;
470         uint32 result=0;
471         int len = 0;
472
473         if (cmd[strlen(cmd) - 1] == '\n')
474                 cmd[strlen(cmd) - 1] = '\0';
475
476         if (!next_token(&p, buf, " ", sizeof(buf))) {
477                 return 0;
478         }
479
480         /* strip the trainly \n if it exsists */
481         len = strlen(buf);
482         if (buf[len-1] == '\n')
483                 buf[len-1] = '\0';
484
485         /* Search for matching commands */
486
487         for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) {
488                 struct cmd_set *temp_set = temp_list->cmd_set;
489
490                 while(temp_set->name) {
491                         if (strequal(buf, temp_set->name)) {
492                                 found = True;
493                                 result = do_cmd(cli, temp_set, cmd);
494                                 goto done;
495                         }
496                         temp_set++;
497                 }
498         }
499
500  done:
501         if (!found && buf[0]) {
502                 printf("command not found: %s\n", buf);
503                 return 0;
504         }
505
506         if (result != 0) {
507                 printf("result was %s\n", get_nt_error_msg(result));
508         }
509
510         return result;
511 }
512
513 /************************************************************************/
514 struct cli_state *setup_connection(struct cli_state *cli, char *system_name,
515                                    struct ntuser_creds *creds)
516 {
517         struct in_addr dest_ip;
518         struct nmb_name calling, called;
519         fstring dest_host;
520         extern pstring global_myname;
521         struct ntuser_creds anon;
522
523         /* Initialise cli_state information */
524         if (!cli_initialise(cli)) {
525                 return NULL;
526         }
527
528         if (!creds) {
529                 ZERO_STRUCT(anon);
530                 anon.pwd.null_pwd = 1;
531                 creds = &anon;
532         }
533
534         cli_init_creds(cli, creds);
535
536         /* Establish a SMB connection */
537         if (!resolve_srv_name(system_name, dest_host, &dest_ip)) {
538                 return NULL;
539         }
540
541         make_nmb_name(&called, dns_to_netbios_name(dest_host), 0x20);
542         make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
543
544         if (!cli_establish_connection(cli, dest_host, &dest_ip, &calling, 
545                                       &called, "IPC$", "IPC", False, True)) {
546                 return NULL;
547         }
548         
549         return cli;
550 }
551
552
553 /* Print usage information */
554 static void usage(void)
555 {
556         printf("Usage: rpcclient [options] server\n");
557
558         printf("\t-A authfile           file containing user credentials\n");
559         printf("\t-c \"command string\"   execute semicolon separated cmds\n");
560         printf("\t-d debuglevel         set the debuglevel\n");
561         printf("\t-l logfile            name of logfile to use as opposed to stdout\n");
562         printf("\t-h                    Print this help message.\n");
563         printf("\t-N                    don't ask for a password\n");
564         printf("\t-s configfile         specify an alternative config file\n");
565         printf("\t-U username           set the network username\n");
566         printf("\t-W domain             set the domain name for user account\n");
567         printf("\n");
568 }
569
570 /* Main function */
571
572  int main(int argc, char *argv[])
573 {
574         extern char             *optarg;
575         extern int              optind;
576         extern pstring          global_myname;
577         BOOL                    got_pass = False;
578         BOOL                    interactive = True;
579         int                     opt;
580         int                     olddebug;
581         pstring                 cmdstr = "", 
582                                 servicesf = CONFIGFILE;
583         struct ntuser_creds     creds;
584         struct cli_state        cli;
585         fstring                 password,
586                                 username,
587                                 domain,
588                                 server;
589         struct cmd_set **cmd_set;
590
591         setlinebuf(stdout);
592
593         DEBUGLEVEL = 1;
594
595         while ((opt = getopt(argc, argv, "A:s:Nd:U:W:c:l:h")) != EOF) {
596                 switch (opt) {
597                 case 'A':
598                         /* only get the username, password, and domain from the file */
599                         read_authfile (optarg, username, password, domain);
600                         if (strlen (password))
601                                 got_pass = True;
602                         break;
603
604                 case 'c':
605                         pstrcpy(cmdstr, optarg);
606                         break;
607
608                 case 'd':
609                         DEBUGLEVEL = atoi(optarg);
610                         break;
611
612                 case 'l':
613                         slprintf(debugf, sizeof(debugf) - 1, "%s.client", optarg);
614                         interactive = False;
615                         break;
616
617                 case 'N':
618                         got_pass = True;
619                         break;
620                         
621                 case 's':
622                         pstrcpy(servicesf, optarg);
623                         break;
624
625                 case 'U': {
626                         char *lp;
627                         pstrcpy(username,optarg);
628                         if ((lp=strchr_m(username,'%'))) {
629                                 *lp = 0;
630                                 pstrcpy(password,lp+1);
631                                 got_pass = True;
632                                 memset(strchr_m(optarg,'%')+1,'X',strlen(password));
633                         }
634                         break;
635                 }
636                 
637                 case 'W':
638                         pstrcpy(domain, optarg);
639                         break;
640                         
641                 case 'h':
642                 default:
643                         usage();
644                         exit(1);
645                 }
646         }
647
648         argv += optind;
649         argc -= optind;
650
651         /* Parse options */
652         if (argc < 1) {
653                 usage();
654                 return 0;
655         }
656         
657         pstrcpy(server, argv[0]);
658
659         /* the following functions are part of the Samba debugging
660            facilities.  See lib/debug.c */
661         setup_logging("rpcclient", interactive);
662         if (!interactive) 
663                 reopen_logs();
664         
665         /* Load smb.conf file */
666         /* FIXME!  How to get this DEBUGLEVEL to last over lp_load()? */
667         olddebug = DEBUGLEVEL;
668         if (!lp_load(servicesf,True,False,False)) {
669                 fprintf(stderr, "Can't load %s\n", servicesf);
670         }
671         DEBUGLEVEL = olddebug;
672
673         load_interfaces();
674
675         TimeInit();
676
677         get_myname((*global_myname)?NULL:global_myname);
678         strupper(global_myname);
679         
680         /*
681          * initialize the credentials struct.  Get password
682          * from stdin if necessary
683          */
684         if (!strlen(username) && !got_pass)
685                 get_username(username);
686                 
687         if (!got_pass) {
688                 init_rpcclient_creds (&creds, username, domain, "");
689                 pwd_read(&creds.pwd, "Enter Password: ", lp_encrypted_passwords());
690         }
691         else {
692                 init_rpcclient_creds (&creds, username, domain, password);
693         }
694         memset(password,'X',strlen(password));
695
696         /* open a connection to the specified server */
697         ZERO_STRUCTP (&cli);
698         if (!setup_connection (&cli, server, &creds)) {
699                 return 1;
700         }
701         
702         /* There are no pointers in ntuser_creds struct so zero it out */
703
704         ZERO_STRUCTP (&creds);
705         
706         /* Load command lists */
707
708         cmd_set = rpcclient_command_list;
709
710         while(*cmd_set) {
711                 add_command_set(*cmd_set);
712                 add_command_set(separator_command);
713                 cmd_set++;
714         }
715
716         /* Do anything specified with -c */
717         if (cmdstr[0]) {
718                 char    *cmd;
719                 char    *p = cmdstr;
720  
721                 while((cmd=next_command(&p)) != NULL) {
722                         process_cmd(&cli, cmd);
723                 }
724  
725                 return 0;
726         }
727
728         /* Loop around accepting commands */
729
730         while(1) {
731                 pstring prompt;
732                 char *line;
733
734                 slprintf(prompt, sizeof(prompt) - 1, "rpcclient $> ");
735
736                 line = smb_readline(prompt, NULL, completion_fn);
737
738                 if (line == NULL)
739                         break;
740
741                 if (line[0] != '\n')
742                         process_cmd(&cli, line);
743         }
744
745         return 0;
746 }