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