]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/appl/ftp/ftp/main.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / appl / ftp / ftp / main.c
1 /*
2  * Copyright (c) 1985, 1989, 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 /*
35  * FTP User Program -- Command Interface.
36  */
37
38 #include "ftp_locl.h"
39 #include <getarg.h>
40
41 RCSID("$Id: main.c 16160 2005-10-12 09:42:47Z joda $");
42
43 static int help_flag;
44 static int version_flag;
45 static int debug_flag;
46
47 struct getargs getargs[] = {
48     { NULL,     'd', arg_flag, &debug_flag,
49       "debug", NULL },
50     { NULL,     'g', arg_negative_flag, &doglob,
51       "disables globbing", NULL},
52     { NULL,     'i', arg_negative_flag, &interactive,
53       "Turn off interactive prompting", NULL},
54     { NULL,     'l', arg_negative_flag, &lineedit,
55       "Turn off line editing", NULL},
56     { NULL,   'n', arg_negative_flag, &autologin,
57       "Turn off auto-login", NULL},
58     { NULL,     'p', arg_flag, &passivemode,
59       "passive mode", NULL},
60     { NULL,     't', arg_counter, &trace,
61       "Packet tracing", NULL},
62 #ifdef KRB5
63     { "gss-bindings", 0,  arg_negative_flag, &ftp_do_gss_bindings,
64       "Don't use GSS-API bindings", NULL},
65     { "gss-delegate", 0,  arg_negative_flag, &ftp_do_gss_delegate,
66       "Disable delegation of GSS-API credentials", NULL},
67 #endif
68     { NULL,     'v', arg_counter, &verbose,
69       "verbosity", NULL},
70     { NULL,     'K', arg_negative_flag, &use_kerberos,
71       "Disable kerberos authentication", NULL},
72     { "encrypt", 'x', arg_flag, &doencrypt,
73       "Encrypt command and data channel if possible" },
74     { "version", 0,  arg_flag, &version_flag },
75     { "help",   'h', arg_flag, &help_flag },
76 };
77
78 static int num_args = sizeof(getargs) / sizeof(getargs[0]);
79
80 static void
81 usage(int ecode)
82 {
83     arg_printusage(getargs, num_args, NULL, "[host [port]]");
84     exit(ecode);
85 }
86
87 int
88 main(int argc, char **argv)
89 {
90         int top;
91         struct passwd *pw = NULL;
92         char homedir[MaxPathLen];
93         struct servent *sp;
94         int optind = 0;
95
96         setprogname(argv[0]);
97
98         sp = getservbyname("ftp", "tcp");
99         if (sp == 0)
100                 errx(1, "ftp/tcp: unknown service");
101         doglob = 1;
102         interactive = 1;
103         autologin = 1;
104         lineedit = 1;
105         passivemode = 0; /* passive mode not active */
106         use_kerberos = 1;
107 #ifdef KRB5
108         ftp_do_gss_bindings = 1;
109 #endif
110
111         if(getarg(getargs, num_args, argc, argv, &optind))
112                 usage(1);
113         if(help_flag)
114                 usage(0);
115         if(version_flag) {
116                 print_version(NULL);
117                 exit(0);
118         }
119
120         if (debug_flag) {
121                 options |= SO_DEBUG;
122                 debug++;
123         }
124
125         argc -= optind;
126         argv += optind;
127
128         fromatty = isatty(fileno(stdin));
129         if (fromatty)
130                 verbose++;
131         cpend = 0;      /* no pending replies */
132         proxy = 0;      /* proxy not active */
133         crflag = 1;     /* strip c.r. on ascii gets */
134         sendport = -1;  /* not using ports */
135         /*
136          * Set up the home directory in case we're globbing.
137          */
138         pw = k_getpwuid(getuid());
139         if (pw != NULL) {
140                 strlcpy(homedir, pw->pw_dir, sizeof(homedir));
141                 home = homedir;
142         }
143         if (argc > 0) {
144             char *xargv[5];
145             
146             if (setjmp(toplevel))
147                 exit(0);
148             signal(SIGINT, intr);
149             signal(SIGPIPE, lostpeer);
150             xargv[0] = (char*)getprogname();
151             xargv[1] = argv[0];
152             xargv[2] = argv[1];
153             xargv[3] = argv[2];
154             xargv[4] = NULL;
155             setpeer(argc+1, xargv);
156         }
157         if(setjmp(toplevel) == 0)
158             top = 1;
159         else
160             top = 0;
161         if (top) {
162             signal(SIGINT, intr);
163             signal(SIGPIPE, lostpeer);
164         }
165         for (;;) {
166             cmdscanner(top);
167             top = 1;
168         }
169 }
170
171 void
172 intr(int sig)
173 {
174
175         longjmp(toplevel, 1);
176 }
177
178 #ifndef SHUT_RDWR
179 #define SHUT_RDWR 2
180 #endif
181
182 RETSIGTYPE
183 lostpeer(int sig)
184 {
185
186     if (connected) {
187         if (cout != NULL) {
188             shutdown(fileno(cout), SHUT_RDWR);
189             fclose(cout);
190             cout = NULL;
191         }
192         if (data >= 0) {
193             shutdown(data, SHUT_RDWR);
194             close(data);
195             data = -1;
196         }
197         connected = 0;
198     }
199     pswitch(1);
200     if (connected) {
201         if (cout != NULL) {
202             shutdown(fileno(cout), SHUT_RDWR);
203             fclose(cout);
204             cout = NULL;
205         }
206         connected = 0;
207     }
208     proxflag = 0;
209     pswitch(0);
210     sec_end();
211     SIGRETURN(0);
212 }
213
214 /*
215 char *
216 tail(filename)
217         char *filename;
218 {
219         char *s;
220         
221         while (*filename) {
222                 s = strrchr(filename, '/');
223                 if (s == NULL)
224                         break;
225                 if (s[1])
226                         return (s + 1);
227                 *s = '\0';
228         }
229         return (filename);
230 }
231 */
232
233 static char *
234 simple_readline(char *prompt)
235 {
236     char buf[BUFSIZ];
237     printf ("%s", prompt);
238     fflush (stdout);
239     if(fgets(buf, sizeof(buf), stdin) == NULL)
240         return NULL;
241     if (buf[strlen(buf) - 1] == '\n')
242         buf[strlen(buf) - 1] = '\0';
243     return strdup(buf);
244 }
245
246 #ifndef HAVE_READLINE
247
248 static char *
249 readline(char *prompt)
250 {
251     return simple_readline (prompt);
252 }
253
254 static void
255 add_history(char *p)
256 {
257 }
258
259 #else
260
261 /* These should not really be here */
262
263 char *readline(char *);
264 void add_history(char *);
265
266 #endif
267
268 /*
269  * Command parser.
270  */
271 void
272 cmdscanner(int top)
273 {
274     struct cmd *c;
275     int l;
276
277     if (!top)
278         putchar('\n');
279     for (;;) {
280         if (fromatty) {
281             char *p;
282             if (lineedit)
283                 p = readline("ftp> ");
284             else
285                 p = simple_readline("ftp> ");
286             if(p == NULL) {
287                 printf("\n");
288                 quit(0, 0);
289             }
290             strlcpy(line, p, sizeof(line));
291             if (lineedit)
292                 add_history(p);
293             free(p);
294         } else{
295             if (fgets(line, sizeof line, stdin) == NULL)
296                 quit(0, 0);
297         }
298         /* XXX will break on long lines */
299         l = strlen(line);
300         if (l == 0)
301             break;
302         if (line[--l] == '\n') {
303             if (l == 0)
304                 break;
305             line[l] = '\0';
306         } else if (l == sizeof(line) - 2) {
307             printf("sorry, input line too long\n");
308             while ((l = getchar()) != '\n' && l != EOF)
309                 /* void */;
310             break;
311         } /* else it was a line without a newline */
312         makeargv();
313         if (margc == 0) {
314             continue;
315         }
316         c = getcmd(margv[0]);
317         if (c == (struct cmd *)-1) {
318             printf("?Ambiguous command\n");
319             continue;
320         }
321         if (c == 0) {
322             printf("?Invalid command\n");
323             continue;
324         }
325         if (c->c_conn && !connected) {
326             printf("Not connected.\n");
327             continue;
328         }
329         (*c->c_handler)(margc, margv);
330         if (bell && c->c_bell)
331             putchar('\007');
332         if (c->c_handler != help)
333             break;
334     }
335     signal(SIGINT, intr);
336     signal(SIGPIPE, lostpeer);
337 }
338
339 struct cmd *
340 getcmd(char *name)
341 {
342         char *p, *q;
343         struct cmd *c, *found;
344         int nmatches, longest;
345
346         longest = 0;
347         nmatches = 0;
348         found = 0;
349         for (c = cmdtab; (p = c->c_name); c++) {
350                 for (q = name; *q == *p++; q++)
351                         if (*q == 0)            /* exact match? */
352                                 return (c);
353                 if (!*q) {                      /* the name was a prefix */
354                         if (q - name > longest) {
355                                 longest = q - name;
356                                 nmatches = 1;
357                                 found = c;
358                         } else if (q - name == longest)
359                                 nmatches++;
360                 }
361         }
362         if (nmatches > 1)
363                 return ((struct cmd *)-1);
364         return (found);
365 }
366
367 /*
368  * Slice a string up into argc/argv.
369  */
370
371 int slrflag;
372
373 void
374 makeargv(void)
375 {
376         char **argp;
377
378         argp = margv;
379         stringbase = line;              /* scan from first of buffer */
380         argbase = argbuf;               /* store from first of buffer */
381         slrflag = 0;
382         for (margc = 0; ; margc++) {
383                 /* Expand array if necessary */
384                 if (margc == margvlen) {
385                         int i;
386
387                         margv = (margvlen == 0)
388                                 ? (char **)malloc(20 * sizeof(char *))
389                                 : (char **)realloc(margv,
390                                         (margvlen + 20)*sizeof(char *));
391                         if (margv == NULL)
392                                 errx(1, "cannot realloc argv array");
393                         for(i = margvlen; i < margvlen + 20; ++i)
394                                 margv[i] = NULL;
395                         margvlen += 20;
396                         argp = margv + margc;
397                 }
398
399                 if ((*argp++ = slurpstring()) == NULL)
400                         break;
401         }
402
403 }
404
405 /*
406  * Parse string into argbuf;
407  * implemented with FSM to
408  * handle quoting and strings
409  */
410 char *
411 slurpstring(void)
412 {
413         int got_one = 0;
414         char *sb = stringbase;
415         char *ap = argbase;
416         char *tmp = argbase;            /* will return this if token found */
417
418         if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
419                 switch (slrflag) {      /* and $ as token for macro invoke */
420                         case 0:
421                                 slrflag++;
422                                 stringbase++;
423                                 return ((*sb == '!') ? "!" : "$");
424                                 /* NOTREACHED */
425                         case 1:
426                                 slrflag++;
427                                 altarg = stringbase;
428                                 break;
429                         default:
430                                 break;
431                 }
432         }
433
434 S0:
435         switch (*sb) {
436
437         case '\0':
438                 goto OUT;
439
440         case ' ':
441         case '\t':
442                 sb++; goto S0;
443
444         default:
445                 switch (slrflag) {
446                         case 0:
447                                 slrflag++;
448                                 break;
449                         case 1:
450                                 slrflag++;
451                                 altarg = sb;
452                                 break;
453                         default:
454                                 break;
455                 }
456                 goto S1;
457         }
458
459 S1:
460         switch (*sb) {
461
462         case ' ':
463         case '\t':
464         case '\0':
465                 goto OUT;       /* end of token */
466
467         case '\\':
468                 sb++; goto S2;  /* slurp next character */
469
470         case '"':
471                 sb++; goto S3;  /* slurp quoted string */
472
473         default:
474                 *ap++ = *sb++;  /* add character to token */
475                 got_one = 1;
476                 goto S1;
477         }
478
479 S2:
480         switch (*sb) {
481
482         case '\0':
483                 goto OUT;
484
485         default:
486                 *ap++ = *sb++;
487                 got_one = 1;
488                 goto S1;
489         }
490
491 S3:
492         switch (*sb) {
493
494         case '\0':
495                 goto OUT;
496
497         case '"':
498                 sb++; goto S1;
499
500         default:
501                 *ap++ = *sb++;
502                 got_one = 1;
503                 goto S3;
504         }
505
506 OUT:
507         if (got_one)
508                 *ap++ = '\0';
509         argbase = ap;                   /* update storage pointer */
510         stringbase = sb;                /* update scan pointer */
511         if (got_one) {
512                 return (tmp);
513         }
514         switch (slrflag) {
515                 case 0:
516                         slrflag++;
517                         break;
518                 case 1:
519                         slrflag++;
520                         altarg = (char *) 0;
521                         break;
522                 default:
523                         break;
524         }
525         return NULL;
526 }
527
528 #define HELPINDENT ((int) sizeof ("directory"))
529
530 /*
531  * Help command.
532  * Call each command handler with argc == 0 and argv[0] == name.
533  */
534 void
535 help(int argc, char **argv)
536 {
537         struct cmd *c;
538
539         if (argc == 1) {
540                 int i, j, w, k;
541                 int columns, width = 0, lines;
542
543                 printf("Commands may be abbreviated.  Commands are:\n\n");
544                 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
545                         int len = strlen(c->c_name);
546
547                         if (len > width)
548                                 width = len;
549                 }
550                 width = (width + 8) &~ 7;
551                 columns = 80 / width;
552                 if (columns == 0)
553                         columns = 1;
554                 lines = (NCMDS + columns - 1) / columns;
555                 for (i = 0; i < lines; i++) {
556                         for (j = 0; j < columns; j++) {
557                                 c = cmdtab + j * lines + i;
558                                 if (c->c_name && (!proxy || c->c_proxy)) {
559                                         printf("%s", c->c_name);
560                                 }
561                                 else if (c->c_name) {
562                                         for (k=0; k < strlen(c->c_name); k++) {
563                                                 putchar(' ');
564                                         }
565                                 }
566                                 if (c + lines >= &cmdtab[NCMDS]) {
567                                         printf("\n");
568                                         break;
569                                 }
570                                 w = strlen(c->c_name);
571                                 while (w < width) {
572                                         w = (w + 8) &~ 7;
573                                         putchar('\t');
574                                 }
575                         }
576                 }
577                 return;
578         }
579         while (--argc > 0) {
580                 char *arg;
581                 arg = *++argv;
582                 c = getcmd(arg);
583                 if (c == (struct cmd *)-1)
584                         printf("?Ambiguous help command %s\n", arg);
585                 else if (c == (struct cmd *)0)
586                         printf("?Invalid help command %s\n", arg);
587                 else
588                         printf("%-*s\t%s\n", HELPINDENT,
589                                 c->c_name, c->c_help);
590         }
591 }