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