Removed 'extern int DEBUGLEVEL' as it is now in the smb.h header.
[samba.git] / source3 / lib / cmd_interp.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB client
5    Copyright (C) Andrew Tridgell                1994-1998
6    Copyright (C) Luke Kenneth Casson Leighton   1998-2000
7    Copyright (C) Gerald Carter                       2000
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #ifdef SYSLOG
25 #undef SYSLOG
26 #endif
27
28 #include "includes.h"
29 #include "rpc_parse.h"
30
31 #ifndef REGISTER
32 #define REGISTER 0
33 #endif
34
35 extern pstring debugf;
36 extern pstring global_myname;
37
38 extern pstring user_socket_options;
39
40 /* found in rpc_client/cli_connect.c */
41 extern struct user_creds *usr_creds;
42
43
44 #define CNV_LANG(s) dos2unix_format(s,False)
45 #define CNV_INPUT(s) unix2dos_format(s,True)
46
47 static int process_tok(fstring tok);
48 static uint32 cmd_help(struct client_info *info, int argc, char *argv[]);
49 static uint32 cmd_quit(struct client_info *info, int argc, char *argv[]);
50 static uint32 cmd_set(struct client_info *info, int argc, char *argv[]);
51 static uint32 cmd_use(struct client_info *info, int argc, char *argv[]);
52
53 static struct user_creds usr;
54
55 struct client_info cli_info;
56
57 char **cmd_argv = NULL;
58 uint32 cmd_argc = 0;
59
60 FILE *out_hnd;
61
62
63 static void cmd_set_free(struct command_set *item)
64 {
65         if (item != NULL)
66                 SAFE_FREE(item->name);
67
68         SAFE_FREE(item);
69 }
70
71 static struct command_set *cmd_set_dup(const struct command_set *from)
72 {
73         if (from != NULL)
74         {
75                 struct command_set *copy;
76                 
77                 copy = (struct command_set*)malloc(sizeof(struct command_set));
78                 if (copy != NULL)
79                 {
80                         memcpy(copy, from, sizeof(struct command_set));
81                         if (from->name != NULL)
82                                 copy->name = strdup(from->name);
83                 }
84                 return copy;
85         }
86         return NULL;
87 }
88
89 void free_cmd_set_array(uint32 num_entries, struct command_set **entries)
90 {
91         void (*fn) (void *) = (void (*)(void *))&cmd_set_free;
92         free_void_array(num_entries, (void **)entries, *fn);
93 }
94
95 struct command_set *add_cmd_set_to_array(uint32 *len, struct command_set ***array,
96                                          const struct command_set *cmd)
97 {
98         void *(*fn) (const void *) = (void *(*)(const void *))&cmd_set_dup;
99         return (struct command_set *)add_copy_to_array(len, (void ***)array,
100                                                        (const void *)cmd, *fn,
101                                                        False);
102
103 }
104
105 static struct command_set **commands = NULL;
106 static uint32 num_commands = 0;
107
108 /****************************************************************************
109  add in individual command-sets.
110  ****************************************************************************/
111 void add_command_set(const struct command_set *cmds)
112 {
113         while (! ((cmds->fn==NULL) && (strlen(cmds->name)==0)))
114         {
115                 add_cmd_set_to_array(&num_commands, &commands, cmds);
116                 cmds++;
117         }
118 }
119
120 /****************************************************************************
121  This defines the commands supported by this client
122  ****************************************************************************/
123 static struct command_set general_commands[] = {
124         /*
125          * maintenance
126          */
127
128         {"General", NULL, NULL, {NULL, NULL}},
129
130         { "set", cmd_set,
131          "run rpcclient inside rpcclient (change options etc.)",
132          {NULL, NULL}
133         },
134
135         { "use", cmd_use,
136          "net use and net view",
137          {NULL, NULL}
138         },
139
140         /*
141          * bye bye
142          */
143
144         { "quit", cmd_quit,
145          "logoff the server",
146          {NULL, NULL}
147         },
148         { "q", cmd_quit,
149          "logoff the server",
150          {NULL, NULL}
151         },
152         { "exit", cmd_quit,
153          "logoff the server",
154          {NULL, NULL}
155         },
156         { "bye", cmd_quit,
157          "logoff the server",
158          {NULL, NULL}
159         },
160
161         /*
162          * eek!
163          */
164
165         { "help", cmd_help,
166          "[command] give help on a command",
167          {NULL, NULL}
168         },
169         { "?", cmd_help,
170          "[command] give help on a command",
171          {NULL, NULL}
172         },
173
174         /*
175          * shell
176          */
177
178         { "!", NULL,
179          "run a shell command on the local system",
180          {NULL, NULL}
181         },
182
183         /*
184          * oop!
185          */
186
187         { "", NULL, NULL,
188          {NULL, NULL}
189         }
190 };
191
192
193 /****************************************************************************
194 do a (presumably graceful) quit...
195 ****************************************************************************/
196 static uint32 cmd_quit(struct client_info *info, int argc, char *argv[])
197 {
198         free_connections();
199         exit(0);
200         
201         /* NOTREACHED */
202         return 0;
203 }
204
205 /****************************************************************************
206 help
207 ****************************************************************************/
208 static uint32 cmd_help(struct client_info *info, int argc, char *argv[])
209 {
210         int i = 0;
211
212         /* get help on a specific command */
213         if (argc > 1)
214         {
215                 if ((i = process_tok(argv[0])) >= 0)
216                 {
217                         fprintf(out_hnd, "HELP %s:\n\t%s\n\n", commands[i]->name, 
218                                 commands[i]->description);
219                 }
220
221                 return 0;
222         }
223
224         /* Print out the list of available commands */
225         for (i = 0; i < num_commands; i++)
226         {
227                 if (commands[i]->fn == NULL)
228                         fprintf (out_hnd, "\n");
229                 else
230                         fprintf (out_hnd, "\t");
231
232                 fprintf(out_hnd, "%s\n", commands[i]->name);
233         }
234
235         return 0;
236 }
237
238 /*******************************************************************
239   lookup a command string in the list of commands, including 
240   abbreviations
241   ******************************************************************/
242 static int process_tok(char *tok)
243 {
244         int i = 0, matches = 0;
245         int cmd = 0;
246         int tok_len = strlen(tok);
247
248         for (i = 0; i < num_commands; i++)
249         {
250                 if (strequal(commands[i]->name, tok))
251                 {
252                         matches = 1;
253                         cmd = i;
254                         break;
255                 }
256                 else if (strnequal(commands[i]->name, tok, tok_len))
257                 {
258                         matches++;
259                         cmd = i;
260                 }
261         }
262
263         if (matches == 0)
264                 return (-1);
265         else if (matches == 1)
266                 return (cmd);
267         else
268                 return (-2);
269 }
270
271 /****************************************************************************
272   turn command line into command argument array
273 ****************************************************************************/
274 static BOOL get_cmd_args(char *line)
275 {
276         char *ptr = line;
277         pstring tok;
278         cmd_argc = 0;
279         cmd_argv = NULL;
280
281         /* get the first part of the command */
282         if (!next_token_nr(&ptr, tok, NULL, sizeof(tok)))
283                 return False;
284
285         do
286         {
287                 add_chars_to_array(&cmd_argc, &cmd_argv, tok);
288         }
289         while (next_token_nr(NULL, tok, NULL, sizeof(tok)));
290
291         add_chars_to_array(&cmd_argc, &cmd_argv, NULL);
292
293         return True;
294 }
295
296 /* command options mask */
297 static uint32 cmd_set_options = 0xffffffff;
298
299 /****************************************************************************
300   process commands from the client
301 ****************************************************************************/
302 static uint32 do_command(struct client_info *info, char *line)
303 {
304         NTSTATUS status = 0x0;
305         int i;
306
307         if (!get_cmd_args(line))
308                 return False;
309
310         if (cmd_argc == 0)
311                 return False;
312         
313         i = process_tok(cmd_argv[0]);
314         if (i >= 0)
315         {
316                 int argc = ((int)cmd_argc);
317                 char **argv = cmd_argv;
318                 optind = 0;
319
320                 status = commands[i]->fn(info, argc, argv);
321         }
322         else if (i == -2)
323         {
324                 fprintf(out_hnd, "%s: command abbreviation ambiguous\n",
325                         CNV_LANG(cmd_argv[0]));
326         }
327         else
328         {
329                 fprintf(out_hnd, "%s: command not found\n",
330                         CNV_LANG(cmd_argv[0]));
331         }
332
333         free_char_array(cmd_argc, cmd_argv);
334         parse_talloc_free(); /* Free up init_XXX memory. */
335
336         return status;
337 }
338
339
340 /****************************************************************************
341   process commands from the client
342 ****************************************************************************/
343 static uint32 process(struct client_info *info, char *cmd_str)
344 {
345         NTSTATUS status = 0;
346         pstring line;
347         char *cmd = cmd_str;
348
349         if (cmd != NULL)
350         {
351                 while (cmd[0] != '\0')
352                 {
353                         char *p;
354
355                         if ((p = strchr_m(cmd, ';')) == 0)
356                         {
357                                 strncpy(line, cmd, 999);
358                                 line[1000] = '\0';
359                                 cmd += strlen(cmd);
360                         }
361                         else
362                         {
363                                 if (p - cmd > 999)
364                                         p = cmd + 999;
365                                 strncpy(line, cmd, p - cmd);
366                                 line[p - cmd] = '\0';
367                                 cmd = p + 1;
368                         }
369
370                         /* input language code to internal one */
371                         CNV_INPUT(line);
372
373                         status = do_command(info, line);
374                         if (status == 0x0)
375                         {
376                                 continue;
377                         }
378                 }
379         }
380         else
381         {
382                 while (!feof(stdin))
383                 {
384 #ifdef HAVE_LIBREADLINE
385                         char *ret_line;
386 #endif
387                         pstring pline;
388                         BOOL at_sym = False;
389                         
390                         pline[0] = 0;
391                         if (info->show_prompt)
392                         {
393                                 safe_strcat(pline, "[", sizeof(pline) - 1);
394                                 if (usr.ntc.domain[0] != 0)
395                                 {
396                                         safe_strcat(pline, usr.ntc.domain,
397                                                     sizeof(pline) - 1);
398                                         safe_strcat(pline, "\\", sizeof(pline) - 1);
399                                         at_sym = True;
400                                 }
401                                 if (usr.ntc.user_name[0] != 0)
402                                 {
403                                         safe_strcat(pline, usr.ntc.user_name,
404                                                     sizeof(pline) - 1);
405                                         at_sym = True;
406                                 }
407                                 if (at_sym)
408                                         safe_strcat(pline, "@", sizeof(pline) - 1);
409                                                 
410                                 safe_strcat(pline, cli_info.dest_host,
411                                             sizeof(pline) - 1);
412                                 safe_strcat(pline, "]$ ", sizeof(pline) - 1);
413                         }
414 #ifndef HAVE_LIBREADLINE
415
416                         /* display a prompt */
417                         fprintf(out_hnd, "%s", CNV_LANG(pline));
418                         fflush(out_hnd);
419
420                         cli_use_wait_keyboard();
421
422                         /* and get a response */
423                         if (!fgets(line, 1000, stdin))
424                         {
425                                 break;
426                         }
427
428 #else /* HAVE_LIBREADLINE */
429
430                         if (!(ret_line = readline(pline)))
431                                 break;
432                         SAFE_FREE(ret_line);
433
434                         /* Copy read line to samba buffer */
435
436                         pstrcpy(line, rl_line_buffer);
437
438                         /* Add to history */
439
440                         if (strlen(line) > 0)
441                                 add_history(line);
442 #endif
443                         /* input language code to internal one */
444                         CNV_INPUT(line);
445
446                         /* special case - first char is ! */
447                         if (*line == '!')
448                         {
449                                 system(line + 1);
450                                 continue;
451                         }
452
453                         fprintf(out_hnd, "%s\n", line);
454
455                         status = do_command(info, line);
456                         if (status == 0x0)
457                         {
458                                 continue;
459                         }
460                 }
461         }
462         return status;
463 }
464
465 /****************************************************************************
466 usage on the program
467 ****************************************************************************/
468 static void usage(char *pname)
469 {
470         fprintf(out_hnd,
471                 "Usage: %s [\\server] [password] [-U user] -[W domain] [-l log] ",
472                 pname);
473
474         fprintf(out_hnd, "\nVersion %s\n", VERSION);
475         fprintf(out_hnd, "\t-d debuglevel         set the debuglevel\n");
476         fprintf(out_hnd,
477                 "\t-S <\\>server         Server to connect to\n");
478         fprintf(out_hnd,
479                 "\t-l log basename.      Basename for log/debug files\n");
480         fprintf(out_hnd,
481                 "\t-n netbios name.      Use this name as my netbios name\n");
482         fprintf(out_hnd,
483                 "\t-N                    don't ask for a password\n");
484         fprintf(out_hnd,
485                 "\t-m max protocol       set the max protocol level\n");
486         fprintf(out_hnd,
487                 "\t-I dest IP            use this IP to connect to\n");
488         fprintf(out_hnd,
489                 "\t-E                    write messages to stderr instead of stdout\n");
490         fprintf(out_hnd,
491                 "\t-A filename           file from which to read the authentication credentials\n");
492         fprintf(out_hnd,
493                 "\t-P                    hide prompt (used for shell scripts)\n");
494         fprintf(out_hnd,
495                 "\t-U username           set the network username\n");
496         fprintf(out_hnd,
497                 "\t-U username%%pass      set the network username and password\n");
498         fprintf(out_hnd, "\t-W domain             set the domain name\n");
499         fprintf(out_hnd,
500                 "\t-c 'command string'   execute semicolon separated commands\n");
501         fprintf(out_hnd,
502                 "\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n");
503         fprintf(out_hnd, "\n");
504 }
505
506 #ifdef HAVE_LIBREADLINE
507
508 /****************************************************************************
509 GNU readline completion functions
510 ****************************************************************************/
511
512 /* Complete an rpcclient command */
513
514 static char *complete_cmd(char *text, int state)
515 {
516         static int cmd_index;
517         char *name;
518
519         /* Initialise */
520
521         if (state == 0)
522                 cmd_index = 0;
523
524         /* Return the next name which partially matches the list of commands */
525
526         while ((cmd_index < num_commands)
527                && (strlen(name = commands[cmd_index++]->name) > 0))
528         {
529                 if (strncmp(name, text, strlen(text)) == 0)
530                         return strdup(name);
531         }
532
533         return NULL;
534 }
535
536 /* Main completion function */
537
538 static char **completion_fn(char *text, int start, int end)
539 {
540         pstring cmd_partial;
541         int cmd_index;
542         int num_words;
543
544         int i;
545         char lastch = ' ';
546
547         (void)get_cmd_args(rl_line_buffer);
548
549         safe_strcpy(cmd_partial, rl_line_buffer,
550                     MAX(sizeof(cmd_partial), end) - 1);
551
552         /* Complete rpcclient command */
553
554         if (start == 0)
555                 return completion_matches(text, complete_cmd);
556
557         /* Count # of words in command */
558
559         num_words = 0;
560         for (i = 0; i <= end; i++)
561         {
562                 if ((rl_line_buffer[i] != ' ') && (lastch == ' '))
563                         num_words++;
564                 lastch = rl_line_buffer[i];
565         }
566
567         if (rl_line_buffer[end] == ' ')
568                 num_words++;
569
570         /* Work out which command we are completing for */
571
572         for (cmd_index = 0; cmd_index < num_commands; cmd_index++)
573         {
574
575                 /* Check each command in array */
576
577                 if (strncmp(rl_line_buffer, commands[cmd_index]->name,
578                             strlen(commands[cmd_index]->name)) == 0)
579                 {
580                         /* Call appropriate completion function */
581
582                         if (num_words == 2 || num_words == 3)
583                         {
584                                 char *(*fn) (char *, int);
585                                 fn = commands[cmd_index]->compl_args[num_words - 2];
586                                 if (fn != NULL)
587                                         return completion_matches(text, fn);
588                         }
589                 }
590         }
591
592         /* Eeek! */
593         return NULL;
594 }
595
596 /* To avoid filename completion being activated when no valid
597    completions are found, we assign this stub completion function
598    to the rl_completion_entry_function variable. */
599
600 static char *complete_cmd_null(char *text, int state)
601 {
602         return NULL;
603 }
604
605 #endif /* HAVE_LIBREADLINE */
606
607 static void set_user_password(struct ntuser_creds *u,
608                               BOOL got_pass, char *password)
609 {
610         /* set the password cache info */
611         if (got_pass)
612         {
613                 if (password == NULL)
614                 {
615                         DEBUG(10, ("set_user_password: NULL pwd\n"));
616                         pwd_set_nullpwd(&u->pwd);
617                 }
618                 else
619                 {
620                         /* generate 16 byte hashes */
621                         DEBUG(10, ("set_user_password: generate\n"));
622                         if (lp_encrypted_passwords())
623                                 pwd_make_lm_nt_16(&u->pwd, password);
624                         else
625                                 pwd_set_cleartext(&u->pwd, password);
626                 }
627         }
628         else
629         {
630                 DEBUG(10, ("set_user_password: read\n"));
631                 pwd_read(&u->pwd, "Enter Password:", True);
632         }
633 }
634
635 static uint32 cmd_use(struct client_info *info, int argc, char *argv[])
636 {
637         int opt;
638         BOOL net_use = False;
639         BOOL net_use_add = True;
640         BOOL force_close = False;
641         fstring dest_host;
642         fstring srv_name;
643         BOOL null_pwd = False;
644         BOOL got_pwd = False;
645         pstring password;
646
647
648         if (usr_creds != NULL)
649                 copy_nt_creds(&usr.ntc, &usr_creds->ntc);
650         else
651                 copy_nt_creds(&usr.ntc, NULL);
652
653         pstrcpy(dest_host, cli_info.dest_host);
654         pstrcpy(usr.ntc.user_name, optarg);
655         info->reuse = False;
656
657         if (argc <= 1)
658         {
659                 report(out_hnd,
660                        "net [\\\\Server] [-U user%%pass] [-W domain] [-d] [-f]\n");
661                 report(out_hnd, "    -d     Deletes a connection\n");
662                 report(out_hnd, "    -f     Forcibly deletes a connection\n");
663                 report(out_hnd, "net -u     Shows all connections\n");
664                 return 0;
665         }
666
667         if (argc > 1 && (*argv[1] != '-'))
668         {
669                 if (strnequal("\\\\", argv[1], 2) ||
670                     strnequal("//", argv[1], 2))
671                 {
672                         pstrcpy(dest_host, argv[1] + 2);
673                 }
674                 argc--;
675                 argv++;
676         }
677
678         while ((opt = getopt(argc, argv, "udU:W:")) != EOF)
679         {
680                 switch (opt)
681                 {
682                         case 'u':
683                         {
684                                 net_use = True;
685                                 break;
686                         }
687
688                         case 'U':
689                         {
690                                 char *lp;
691                                 pstrcpy(usr.ntc.user_name, optarg);
692                                 if ((lp = strchr_m(usr.ntc.user_name, '%')))
693                                 {
694                                         *lp = 0;
695                                         pstrcpy(password, lp + 1);
696                                         memset(strchr_m(optarg, '%') + 1, 'X',
697                                                strlen(password));
698                                         got_pwd = True;
699                                 }
700                                 if (usr.ntc.user_name[0] == 0
701                                     && password[0] == 0)
702                                 {
703                                         null_pwd = True;
704                                 }
705                                 break;
706                         }
707
708                         case 'N':
709                         {
710                                 null_pwd = True;
711                         }
712                         case 'W':
713                         {
714                                 pstrcpy(usr.ntc.domain, optarg);
715                                 break;
716                         }
717
718                         case 'd':
719                         {
720                                 net_use_add = False;
721                                 break;
722                         }
723
724                         case 'f':
725                         {
726                                 force_close = True;
727                                 break;
728                         }
729
730                         default:
731                         {
732                                 report(out_hnd,
733                                        "net -S \\server [-U user%%pass] [-W domain] [-d] [-f]\n");
734                                 report(out_hnd, "net -u\n");
735                                 break;
736                         }
737                 }
738         }
739
740         if (strnequal("\\\\", dest_host, 2))
741         {
742                 fstrcpy(srv_name, dest_host);
743         }
744         else
745         {
746                 fstrcpy(srv_name, "\\\\");
747                 fstrcat(srv_name, dest_host);
748         }
749         strupper(srv_name);
750
751         if (net_use)
752         {
753                 int i;
754                 uint32 num_uses;
755                 struct use_info **use;
756                 cli_net_use_enum(&num_uses, &use);
757
758                 if (num_uses == 0)
759                 {
760                         report(out_hnd, "No connections\n");
761                 }
762                 else
763                 {
764                         report(out_hnd, "Connections:\n");
765
766                         for (i = 0; i < num_uses; i++)
767                         {
768                                 if (use[i] != NULL && use[i]->connected)
769                                 {
770                                         report(out_hnd, "Server:\t%s\t",use[i]->srv_name);
771                                         report(out_hnd, "Key:\t[%d,%x]\t",use[i]->key.pid, use[i]->key.vuid);
772                                         report(out_hnd, "User:\t%s\t", use[i]->user_name);
773                                         report(out_hnd, "Domain:\t%s\n", use[i]->domain);
774                                 }
775                         }
776                 }
777         }
778         else if (net_use_add)
779         {
780                 BOOL isnew;
781                 if (null_pwd)
782                         set_user_password(&usr.ntc, True, NULL);
783                 else
784                         set_user_password(&usr.ntc, got_pwd, password);
785
786                 /* paranoia: destroy the local copy of the password */
787                 ZERO_STRUCT(password);
788
789                 report(out_hnd, "Server:\t%s:\tUser:\t%s\tDomain:\t%s\n",
790                        srv_name, usr.ntc.user_name, usr.ntc.domain);
791                 report(out_hnd, "Connection:\t");
792
793                 if (cli_net_use_add(srv_name, &usr.ntc, info->reuse, &isnew) != NULL)
794                         report(out_hnd, "OK\n");
795                 else
796                         report(out_hnd, "FAILED\n");
797         }
798         else
799         {
800                 BOOL closed;
801                 report(out_hnd, "Server:\t%s:\tUser:\t%s\tDomain:\t%s\n",
802                        srv_name, usr.ntc.user_name, usr.ntc.domain);
803                 report(out_hnd, "Connection:\t");
804
805                 if (!cli_net_use_del(srv_name, &usr.ntc, force_close, &closed))
806                         report(out_hnd, ": Does not exist\n");
807                 else if (force_close && closed)
808                         report(out_hnd, ": Forcibly terminated\n");
809                 else if (closed)
810                         report(out_hnd, ": Terminated\n");
811                 else
812                         report(out_hnd, ": Unlinked\n");
813         }
814
815         /* paranoia: destroy the local copy of the password */
816         ZERO_STRUCT(password);
817
818         return 0;
819 }
820
821 /******************************************************************
822    allow or disallow automatic connections.  rpctorture, because it
823    does not reestablish connections after sys_fork(), fails unless the
824    connection is established AFTER the sys_fork()
825  ******************************************************************/
826 static BOOL auto_connect = True;
827 void cmd_set_no_autoconnect(void)
828 {
829         auto_connect = False;
830 }
831
832 #define CMD_STR 0x1
833 #define CMD_DBF 0x2
834 #define CMD_SVC 0x4
835 #define CMD_TERM 0x8
836 #define CMD_PASS 0x10
837 #define CMD_USER 0x20
838 #define CMD_NOPW 0x40
839 #define CMD_DBLV 0x80
840 #define CMD_HELP 0x100
841 #define CMD_SOCK 0x200
842 #define CMD_IFACE 0x400
843 #define CMD_DOM 0x800
844 #define CMD_IP 0x1000
845 #define CMD_HOST 0x2000
846 #define CMD_NAME 0x4000
847 #define CMD_DBG 0x8000
848 #define CMD_SCOPE 0x10000
849 #define CMD_INTER 0x20000
850
851 static void read_authfile (char *filename, char* username, char* password)
852 {
853         FILE *auth;
854         fstring buf;
855         uint16 len = 0;
856         char *ptr, *val, *param;
857                                
858         if ((auth=sys_fopen(filename, "r")) == NULL)
859         {
860                 /* fail if we can't open the credentials file */
861                 DEBUG(0,("ERROR: Unable to open credentials file!\n"));
862                 return;
863         }
864                                 
865         while (!feof(auth))
866         {  
867                 /* get a line from the file */
868                 if (!fgets (buf, sizeof(buf), auth))
869                         continue;
870                 
871                 len = strlen(buf);
872                 
873                 /* skip empty lines */                  
874                 if ((len) && (buf[len-1]=='\n'))
875                 {
876                         buf[len-1] = '\0';
877                         len--;
878                 }       
879                 if (len == 0)
880                         continue;
881                                         
882                 /* break up the line into parameter & value.
883                    will need to eat a little whitespace possibly */
884                 param = buf;
885                 if (!(ptr = strchr_m(buf, '=')))
886                         continue;
887                 val = ptr+1;
888                 *ptr = '\0';
889                                         
890                 /* eat leading white space */
891                 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
892                         val++;
893                                         
894                 if (strwicmp("password", param) == 0)
895                 {
896                         pstrcpy(password, val);
897                         cmd_set_options |= CMD_PASS;
898                 }
899                 else if (strwicmp("username", param) == 0)
900                 {
901                         pstrcpy(username, val);
902                         cmd_set_options |= CMD_USER;
903                 }
904                                                 
905                 memset(buf, 0, sizeof(buf));
906         }
907         fclose(auth);
908         
909         return;
910 }
911
912 static uint32 cmd_set(CLIENT_INFO *info, int argc, char *argv[])
913 {
914         BOOL interactive = True;
915         char *cmd_str = NULL;
916         int opt;
917         extern char *optarg;
918         static pstring servicesf = CONFIGFILE;
919         pstring term_code;
920         pstring password;       /* local copy only, if one is entered */
921         fstring srv_name;
922         int new_debuglevel = -1;
923
924         password[0] = 0;
925         usr_creds = &usr;
926         info->reuse = False;
927 #ifdef KANJI
928         pstrcpy(term_code, KANJI);
929 #else /* KANJI */
930         *term_code = 0;
931 #endif /* KANJI */
932
933         if (argc > 1 && (*argv[1] != '-'))
934         {
935                 if (strnequal("\\\\", argv[1], 2) ||
936                     strnequal("//", argv[1], 2))
937                 {
938                         cmd_set_options |= CMD_HOST;
939                         pstrcpy(cli_info.dest_host, argv[1] + 2);
940                         strupper(cli_info.dest_host);
941                 }
942                 argc--;
943                 argv++;
944         }
945         
946         if (argc > 1 && (*argv[1] != '-'))
947         {
948                 cmd_set_options |= CMD_PASS;
949                 pstrcpy(password, argv[1]);
950                 memset(argv[1], 'X', strlen(argv[1]));
951                 argc--;
952                 argv++;
953         }
954
955         while ((opt = getopt(argc, argv,"PRs:O:M:S:i:Nn:d:l:hI:EB:U:L:t:m:W:T:D:c:A:")) != EOF)
956         {
957                 switch (opt)
958                 {
959                         /* reuse connections in the case of a previous authentication */
960                         case 'R':
961                         {
962                                 info->reuse = True;
963                                 break;
964                         }
965
966                         /* max protocol */
967                         case 'm':
968                         {
969                                 /* FIXME ... max_protocol seems to be funny here */
970
971                                 int max_protocol = 0;
972                                 max_protocol = interpret_protocol(optarg, max_protocol);
973                                 fprintf(stderr, "max protocol not currently supported\n");
974                                 break;
975                         }
976
977                         /* socket options */
978                         case 'O':
979                         {
980                                 cmd_set_options |= CMD_SOCK;
981                                 pstrcpy(user_socket_options, optarg);
982                                 break;
983                         }
984
985                         /* define the server to connect to */
986                         case 'S':
987                         {
988                                 cmd_set_options |= CMD_HOST;
989                                 pstrcpy(cli_info.dest_host, optarg);
990                                 strupper(cli_info.dest_host);
991                                 break;
992                         }
993
994                         /* username for the connection -- support the 
995                            username%password format as well */
996                         case 'U':
997                         {
998                                 char *lp;
999                                 cmd_set_options |= CMD_USER;
1000                                 pstrcpy(usr.ntc.user_name, optarg);
1001                                 if ((lp = strchr_m(usr.ntc.user_name, '%')))
1002                                 {
1003                                         *lp = 0;
1004                                         pstrcpy(password, lp + 1);
1005                                         cmd_set_options |= CMD_PASS;
1006                                         memset(lp+1, 'X', strlen(password));
1007                                 }
1008                                 break;
1009                         }
1010                         
1011                         /* authfile -- only get the username and password from the file */
1012                         case 'A':
1013                         {
1014                                 read_authfile (optarg, usr.ntc.user_name, password);
1015                                 break;
1016                         }
1017
1018                         /* define the workgroup/domain name */
1019                         case 'W':
1020                         {
1021                                 cmd_set_options |= CMD_DOM;
1022                                 pstrcpy(usr.ntc.domain, optarg);
1023                                 break;
1024                         }
1025                         
1026                         /* should we display a command prompt at all */
1027                         case 'P':
1028                         { /* optarg == prompt string ? */
1029                                 info->show_prompt = False;
1030                                 break;
1031                         }
1032
1033                         /* send to stderr instaed of stdout */
1034                         case 'E':
1035                         {
1036                                 cmd_set_options |= CMD_DBG;
1037                                 dbf = x_stderr;
1038                                 break;
1039                         }
1040
1041                         /* IP address of destination host */
1042                         case 'I':
1043                         {
1044                                 cmd_set_options |= CMD_IP;
1045                                 cli_info.dest_ip = *interpret_addr2(optarg);
1046                                 if (zero_ip(cli_info.dest_ip))
1047                                 {
1048                                         free_connections();
1049                                         exit(1);
1050                                 }
1051                                 break;
1052                         }
1053
1054                         /* define netbios name of client machine we are on */
1055                         case 'n':
1056                         {
1057                                 cmd_set_options |= CMD_NAME;
1058                                 fstrcpy(global_myname, optarg);
1059                                 break;
1060                         }
1061
1062                         /* do not prompt for a password.  Implies anonymous connection
1063                            unless the password was passed in username%password form */
1064                         case 'N':
1065                         {
1066                                 cmd_set_options |= CMD_NOPW | CMD_PASS;
1067                                 break;
1068                         }
1069
1070                         /* debug level */
1071                         case 'd':
1072                         {
1073                                 cmd_set_options |= CMD_DBLV;
1074                                 if (*optarg == 'A')
1075                                         new_debuglevel = 10000;
1076                                 else
1077                                         new_debuglevel = atoi(optarg);
1078                                 break;
1079                         }
1080
1081                         /* log file name */
1082                         case 'l':
1083                         {
1084                                 cmd_set_options |= CMD_INTER;
1085                                 slprintf(debugf, sizeof(debugf) - 1, "%s.client", optarg);
1086                                 interactive = False;
1087                                 break;
1088                         }
1089
1090                         /* command string to be executed */
1091                         case 'c':
1092                         {
1093                                 cmd_set_options |= CMD_STR;
1094                                 cmd_str = optarg;
1095                                 break;
1096                         }
1097
1098                         /* program usage/help screen */
1099                         case 'h':
1100                         {
1101                                 cmd_set_options |= CMD_HELP;
1102                                 usage(argv[0]);
1103                                 break;
1104                         }
1105
1106                         /* config file to use */
1107                         case 's':
1108                         {
1109                                 cmd_set_options |= CMD_SVC;
1110                                 pstrcpy(servicesf, optarg);
1111                                 break;
1112                         }
1113
1114                         /* terminal code */
1115                         case 't':
1116                         {
1117                                 cmd_set_options |= CMD_TERM;
1118                                 pstrcpy(term_code, optarg);
1119                                 break;
1120                         }
1121
1122                         default:
1123                         {
1124                                 cmd_set_options |= CMD_HELP;
1125                                 usage(argv[0]);
1126                                 break;
1127                         }
1128                 }
1129         }
1130
1131         
1132         if (cmd_set_options & CMD_INTER)
1133         {
1134                 setup_logging(debugf, interactive);
1135                 if (!interactive)
1136                         reopen_logs();
1137         }
1138
1139         strupper(global_myname);
1140         fstrcpy(cli_info.myhostname, global_myname);
1141
1142         if (cmd_set_options & CMD_SVC) 
1143         {
1144                 if (!lp_load(servicesf, True, False, False))
1145                 {
1146                         fprintf(stderr, "Can't load %s - run testparm to debug it\n",
1147                                 servicesf);
1148                 }
1149
1150         }
1151
1152         if (new_debuglevel != -1) {
1153                 DEBUGLEVEL = new_debuglevel;
1154         }
1155
1156         if (cmd_set_options & CMD_INTER) 
1157         {
1158                 load_interfaces();
1159         }
1160
1161         DEBUG(10, ("cmd_set: options: %x\n", cmd_set_options));
1162
1163         if (cmd_set_options & CMD_HELP) {
1164                 return 0;
1165         }
1166
1167         /* NULL password if specified or is username is empty */
1168         if ((cmd_set_options & CMD_NOPW) || (strlen(usr.ntc.user_name) == 0)) 
1169                 set_user_password(&usr.ntc, True, NULL);
1170         else
1171                 set_user_password(&usr.ntc, ((cmd_set_options & CMD_PASS) != 0), password);
1172
1173         /* paranoia: destroy the local copy of the password */
1174         ZERO_STRUCT(password);
1175
1176         if (strcmp(cli_info.dest_host, "*") == 0) 
1177         {
1178                 /* special case - we want the PDC */
1179                 struct in_addr ip;
1180                 if (!resolve_srv_name(cli_info.dest_host, cli_info.dest_host, &ip)) {
1181                         report(out_hnd, "ERROR: Failed to find the PDC\n");
1182                         return 1;
1183                 }
1184         }
1185
1186         fstrcpy(srv_name, "\\\\");
1187         fstrcat(srv_name, cli_info.dest_host);
1188         strupper(srv_name);
1189
1190
1191         if (auto_connect)
1192         {
1193                 BOOL isnew;
1194                 report(out_hnd, "Server:\t%s:\tUser:\t%s\tDomain:\t%s\n",
1195                        srv_name, usr.ntc.user_name, usr.ntc.domain);
1196                 report(out_hnd, "Connection:\t");
1197
1198                 if (cli_net_use_add(srv_name, &usr.ntc, info->reuse, &isnew) != NULL)
1199                 {
1200                         report(out_hnd, "OK\n");
1201                 }
1202                 else
1203                 {
1204                         report(out_hnd, "FAILED\n");
1205                 }
1206                 /* ???? --jerry
1207                 usr_creds = NULL; */
1208         }
1209         
1210         if (cmd_str != NULL)
1211                 return process(&cli_info, cmd_str);
1212
1213         return 0;
1214 }
1215
1216 static void read_user_env(struct ntuser_creds *u)
1217 {
1218         pstring password;
1219
1220         password[0] = 0;
1221
1222         if (getenv("USER"))
1223         {
1224                 char *p;
1225                 pstrcpy(u->user_name, getenv("USER"));
1226
1227                 /* modification to support userid%passwd syntax in the USER var
1228                    25.Aug.97, jdblair@uab.edu */
1229
1230                 if ((p = strchr_m(u->user_name, '%')))
1231                 {
1232                         *p = 0;
1233                         pstrcpy(password, p + 1);
1234                         memset(strchr_m(getenv("USER"), '%') + 1, 'X',
1235                                strlen(password));
1236                 }
1237         }
1238
1239         /* modification to support PASSWD environmental var
1240            25.Aug.97, jdblair@uab.edu */
1241         if (getenv("PASSWD"))
1242                 pstrcpy(password, getenv("PASSWD"));
1243
1244         if (*u->user_name == 0 && getenv("LOGNAME"))
1245                 pstrcpy(u->user_name, getenv("LOGNAME"));
1246
1247         set_user_password(u, True, password);
1248
1249         /* paranoia: destroy the local copy of the password */
1250         ZERO_STRUCT(password);
1251 }
1252
1253 static void readline_init(void)
1254 {
1255 #ifdef HAVE_LIBREADLINE
1256         /* Initialise GNU Readline */ rl_readline_name = "rpcclient";
1257         rl_attempted_completion_function = completion_fn;
1258         rl_completion_entry_function = (Function *) complete_cmd_null;
1259
1260         /* Initialise history list */
1261
1262         using_history();
1263
1264 #else
1265         int x;
1266         x = 0;                  /* stop compiler warnings */
1267 #endif /* HAVE_LIBREADLINE */
1268 }
1269
1270 /****************************************************************************
1271   main program
1272 ****************************************************************************/
1273 int command_main(int argc, char *argv[])
1274 {
1275         NTSTATUS status;
1276         mode_t myumask = 0755;
1277         char progname[255], path[255], *s;
1278         pstring msg;
1279
1280         DEBUGLEVEL = 2;
1281
1282         /* add in the internal command set and the various
1283            client RPC groups--spoolss, lsa, etc... */
1284         add_command_set(general_commands);
1285
1286         /* usr_creds is a global most recently used set of user credentials
1287            retrieved from the connection list. */
1288         copy_user_creds(&usr, NULL);
1289         usr_creds = &usr;
1290         usr.ptr_ntc = 1;
1291         
1292         out_hnd = stdout;
1293
1294         /* retrieve the binary name used when invoking the program
1295            for instances like samedit, etc... */
1296         strncpy(path, argv[0], 255);
1297         for (s = strtok(path, "/"); s; s = strtok(NULL, "/"))
1298                 fstrcpy(progname, s);
1299
1300         slprintf(debugf, sizeof(debugf) - 1,
1301                  "%s/log.%s", LOGFILEBASE, progname);
1302
1303         /* initialize usr */
1304         pstrcpy(usr.ntc.domain, "");
1305         pstrcpy(usr.ntc.user_name, "");
1306         pstrcpy(cli_info.myhostname, "");
1307         pstrcpy(cli_info.dest_host, "");
1308         
1309         /* init client_info struct */
1310         cli_info.dest_ip.s_addr = 0;
1311         cli_info.show_prompt = True;
1312         ZERO_STRUCT(cli_info.dom.level3_sid);
1313         ZERO_STRUCT(cli_info.dom.level5_sid);
1314         fstrcpy(cli_info.dom.level3_dom, "");
1315         fstrcpy(cli_info.dom.level5_dom, "");
1316
1317         readline_init();
1318         TimeInit();
1319         init_connections();
1320
1321         myumask = umask(0);
1322         umask(myumask);
1323
1324         if (!get_myname(global_myname))
1325         {
1326                 fprintf(stderr, "Failed to get my hostname.\n");
1327         }
1328
1329         if (argc < 2)
1330         {
1331                 usage(argv[0]);
1332                 free_connections();
1333                 exit(1);
1334         }
1335
1336         read_user_env(&usr.ntc);
1337
1338         cmd_set_options &= ~CMD_HELP;
1339         cmd_set_options &= ~CMD_STR;
1340         cmd_set_options &= ~CMD_NOPW;
1341         cmd_set_options &= ~CMD_USER;
1342         cmd_set_options &= ~CMD_PASS;
1343
1344         /*  parse the command line args
1345             init the first connection if possible
1346             process a command if passed in on the command line */
1347         status = cmd_set(&cli_info, argc, argv);
1348
1349         /* Should we exit?  Are we done? */
1350         if (cmd_set_options & (CMD_HELP|CMD_STR)) {
1351                 free_connections();
1352                 get_nt_error_msg(status, msg, sizeof(msg));
1353
1354                 report(out_hnd, "Exit Status: %s\n", msg);
1355                 /* unix only has 8 bit error codes - blergh */
1356                 exit(status & 0xFF);
1357         }
1358
1359         DEBUG(3, ("%s client started (version %s)\n",
1360                   timestring(False), VERSION));
1361
1362         /* enter shell mode */
1363         status = process(&cli_info, NULL);
1364
1365         /* cleanup */
1366         free_connections();
1367         free_cmd_set_array(num_commands, commands);
1368         num_commands = 0;
1369         commands = NULL;
1370         
1371         /* report and exit */
1372         get_nt_error_msg(status, msg, sizeof(msg));
1373         report(out_hnd, "Exit Status: %s\n", msg);
1374         return status;
1375 }