]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - crypto/heimdal/appl/ftp/ftp/main.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.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,v 1.33.2.1 2003/08/20 16:43:14 lha Exp $");
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       "Use GSS-API bindings", NULL},
65 #endif
66     { NULL,     'v', arg_counter, &verbose,
67       "verbosity", NULL},
68     { NULL,     'K', arg_negative_flag, &use_kerberos,
69       "Disable kerberos authentication", NULL},
70     { "version", 0,  arg_flag, &version_flag },
71     { "help",   'h', arg_flag, &help_flag },
72 };
73
74 static int num_args = sizeof(getargs) / sizeof(getargs[0]);
75
76 static void
77 usage(int ecode)
78 {
79     arg_printusage(getargs, num_args, NULL, "[host [port]]");
80     exit(ecode);
81 }
82
83 int
84 main(int argc, char **argv)
85 {
86         int top;
87         struct passwd *pw = NULL;
88         char homedir[MaxPathLen];
89         struct servent *sp;
90         int optind = 0;
91
92         setprogname(argv[0]);
93
94         sp = getservbyname("ftp", "tcp");
95         if (sp == 0)
96                 errx(1, "ftp/tcp: unknown service");
97         doglob = 1;
98         interactive = 1;
99         autologin = 1;
100         lineedit = 1;
101         passivemode = 0; /* passive mode not active */
102         use_kerberos = 1;
103 #ifdef KRB5
104         ftp_do_gss_bindings = 1;
105 #endif
106
107         if(getarg(getargs, num_args, argc, argv, &optind))
108                 usage(1);
109         if(help_flag)
110                 usage(0);
111         if(version_flag) {
112                 print_version(NULL);
113                 exit(0);
114         }
115
116         if (debug_flag) {
117                 options |= SO_DEBUG;
118                 debug++;
119         }
120
121         argc -= optind;
122         argv += optind;
123
124         fromatty = isatty(fileno(stdin));
125         if (fromatty)
126                 verbose++;
127         cpend = 0;      /* no pending replies */
128         proxy = 0;      /* proxy not active */
129         crflag = 1;     /* strip c.r. on ascii gets */
130         sendport = -1;  /* not using ports */
131         /*
132          * Set up the home directory in case we're globbing.
133          */
134         pw = k_getpwuid(getuid());
135         if (pw != NULL) {
136                 strlcpy(homedir, pw->pw_dir, sizeof(homedir));
137                 home = homedir;
138         }
139         if (argc > 0) {
140             char *xargv[5];
141             
142             if (setjmp(toplevel))
143                 exit(0);
144             signal(SIGINT, intr);
145             signal(SIGPIPE, lostpeer);
146             xargv[0] = (char*)getprogname();
147             xargv[1] = argv[0];
148             xargv[2] = argv[1];
149             xargv[3] = argv[2];
150             xargv[4] = NULL;
151             setpeer(argc+1, xargv);
152         }
153         if(setjmp(toplevel) == 0)
154             top = 1;
155         else
156             top = 0;
157         if (top) {
158             signal(SIGINT, intr);
159             signal(SIGPIPE, lostpeer);
160         }
161         for (;;) {
162             cmdscanner(top);
163             top = 1;
164         }
165 }
166
167 void
168 intr(int sig)
169 {
170
171         longjmp(toplevel, 1);
172 }
173
174 #ifndef SHUT_RDWR
175 #define SHUT_RDWR 2
176 #endif
177
178 RETSIGTYPE
179 lostpeer(int sig)
180 {
181
182     if (connected) {
183         if (cout != NULL) {
184             shutdown(fileno(cout), SHUT_RDWR);
185             fclose(cout);
186             cout = NULL;
187         }
188         if (data >= 0) {
189             shutdown(data, SHUT_RDWR);
190             close(data);
191             data = -1;
192         }
193         connected = 0;
194     }
195     pswitch(1);
196     if (connected) {
197         if (cout != NULL) {
198             shutdown(fileno(cout), SHUT_RDWR);
199             fclose(cout);
200             cout = NULL;
201         }
202         connected = 0;
203     }
204     proxflag = 0;
205     pswitch(0);
206     sec_end();
207     SIGRETURN(0);
208 }
209
210 /*
211 char *
212 tail(filename)
213         char *filename;
214 {
215         char *s;
216         
217         while (*filename) {
218                 s = strrchr(filename, '/');
219                 if (s == NULL)
220                         break;
221                 if (s[1])
222                         return (s + 1);
223                 *s = '\0';
224         }
225         return (filename);
226 }
227 */
228
229 static char *
230 simple_readline(char *prompt)
231 {
232     char buf[BUFSIZ];
233     printf ("%s", prompt);
234     fflush (stdout);
235     if(fgets(buf, sizeof(buf), stdin) == NULL)
236         return NULL;
237     if (buf[strlen(buf) - 1] == '\n')
238         buf[strlen(buf) - 1] = '\0';
239     return strdup(buf);
240 }
241
242 #ifndef HAVE_READLINE
243
244 static char *
245 readline(char *prompt)
246 {
247     return simple_readline (prompt);
248 }
249
250 static void
251 add_history(char *p)
252 {
253 }
254
255 #else
256
257 /* These should not really be here */
258
259 char *readline(char *);
260 void add_history(char *);
261
262 #endif
263
264 /*
265  * Command parser.
266  */
267 void
268 cmdscanner(int top)
269 {
270     struct cmd *c;
271     int l;
272
273     if (!top)
274         putchar('\n');
275     for (;;) {
276         if (fromatty) {
277             char *p;
278             if (lineedit)
279                 p = readline("ftp> ");
280             else
281                 p = simple_readline("ftp> ");
282             if(p == NULL) {
283                 printf("\n");
284                 quit(0, 0);
285             }
286             strlcpy(line, p, sizeof(line));
287             if (lineedit)
288                 add_history(p);
289             free(p);
290         } else{
291             if (fgets(line, sizeof line, stdin) == NULL)
292                 quit(0, 0);
293         }
294         /* XXX will break on long lines */
295         l = strlen(line);
296         if (l == 0)
297             break;
298         if (line[--l] == '\n') {
299             if (l == 0)
300                 break;
301             line[l] = '\0';
302         } else if (l == sizeof(line) - 2) {
303             printf("sorry, input line too long\n");
304             while ((l = getchar()) != '\n' && l != EOF)
305                 /* void */;
306             break;
307         } /* else it was a line without a newline */
308         makeargv();
309         if (margc == 0) {
310             continue;
311         }
312         c = getcmd(margv[0]);
313         if (c == (struct cmd *)-1) {
314             printf("?Ambiguous command\n");
315             continue;
316         }
317         if (c == 0) {
318             printf("?Invalid command\n");
319             continue;
320         }
321         if (c->c_conn && !connected) {
322             printf("Not connected.\n");
323             continue;
324         }
325         (*c->c_handler)(margc, margv);
326         if (bell && c->c_bell)
327             putchar('\007');
328         if (c->c_handler != help)
329             break;
330     }
331     signal(SIGINT, intr);
332     signal(SIGPIPE, lostpeer);
333 }
334
335 struct cmd *
336 getcmd(char *name)
337 {
338         char *p, *q;
339         struct cmd *c, *found;
340         int nmatches, longest;
341
342         longest = 0;
343         nmatches = 0;
344         found = 0;
345         for (c = cmdtab; (p = c->c_name); c++) {
346                 for (q = name; *q == *p++; q++)
347                         if (*q == 0)            /* exact match? */
348                                 return (c);
349                 if (!*q) {                      /* the name was a prefix */
350                         if (q - name > longest) {
351                                 longest = q - name;
352                                 nmatches = 1;
353                                 found = c;
354                         } else if (q - name == longest)
355                                 nmatches++;
356                 }
357         }
358         if (nmatches > 1)
359                 return ((struct cmd *)-1);
360         return (found);
361 }
362
363 /*
364  * Slice a string up into argc/argv.
365  */
366
367 int slrflag;
368
369 void
370 makeargv(void)
371 {
372         char **argp;
373
374         argp = margv;
375         stringbase = line;              /* scan from first of buffer */
376         argbase = argbuf;               /* store from first of buffer */
377         slrflag = 0;
378         for (margc = 0; ; margc++) {
379                 /* Expand array if necessary */
380                 if (margc == margvlen) {
381                         int i;
382
383                         margv = (margvlen == 0)
384                                 ? (char **)malloc(20 * sizeof(char *))
385                                 : (char **)realloc(margv,
386                                         (margvlen + 20)*sizeof(char *));
387                         if (margv == NULL)
388                                 errx(1, "cannot realloc argv array");
389                         for(i = margvlen; i < margvlen + 20; ++i)
390                                 margv[i] = NULL;
391                         margvlen += 20;
392                         argp = margv + margc;
393                 }
394
395                 if ((*argp++ = slurpstring()) == NULL)
396                         break;
397         }
398
399 }
400
401 /*
402  * Parse string into argbuf;
403  * implemented with FSM to
404  * handle quoting and strings
405  */
406 char *
407 slurpstring(void)
408 {
409         int got_one = 0;
410         char *sb = stringbase;
411         char *ap = argbase;
412         char *tmp = argbase;            /* will return this if token found */
413
414         if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
415                 switch (slrflag) {      /* and $ as token for macro invoke */
416                         case 0:
417                                 slrflag++;
418                                 stringbase++;
419                                 return ((*sb == '!') ? "!" : "$");
420                                 /* NOTREACHED */
421                         case 1:
422                                 slrflag++;
423                                 altarg = stringbase;
424                                 break;
425                         default:
426                                 break;
427                 }
428         }
429
430 S0:
431         switch (*sb) {
432
433         case '\0':
434                 goto OUT;
435
436         case ' ':
437         case '\t':
438                 sb++; goto S0;
439
440         default:
441                 switch (slrflag) {
442                         case 0:
443                                 slrflag++;
444                                 break;
445                         case 1:
446                                 slrflag++;
447                                 altarg = sb;
448                                 break;
449                         default:
450                                 break;
451                 }
452                 goto S1;
453         }
454
455 S1:
456         switch (*sb) {
457
458         case ' ':
459         case '\t':
460         case '\0':
461                 goto OUT;       /* end of token */
462
463         case '\\':
464                 sb++; goto S2;  /* slurp next character */
465
466         case '"':
467                 sb++; goto S3;  /* slurp quoted string */
468
469         default:
470                 *ap++ = *sb++;  /* add character to token */
471                 got_one = 1;
472                 goto S1;
473         }
474
475 S2:
476         switch (*sb) {
477
478         case '\0':
479                 goto OUT;
480
481         default:
482                 *ap++ = *sb++;
483                 got_one = 1;
484                 goto S1;
485         }
486
487 S3:
488         switch (*sb) {
489
490         case '\0':
491                 goto OUT;
492
493         case '"':
494                 sb++; goto S1;
495
496         default:
497                 *ap++ = *sb++;
498                 got_one = 1;
499                 goto S3;
500         }
501
502 OUT:
503         if (got_one)
504                 *ap++ = '\0';
505         argbase = ap;                   /* update storage pointer */
506         stringbase = sb;                /* update scan pointer */
507         if (got_one) {
508                 return (tmp);
509         }
510         switch (slrflag) {
511                 case 0:
512                         slrflag++;
513                         break;
514                 case 1:
515                         slrflag++;
516                         altarg = (char *) 0;
517                         break;
518                 default:
519                         break;
520         }
521         return NULL;
522 }
523
524 #define HELPINDENT ((int) sizeof ("directory"))
525
526 /*
527  * Help command.
528  * Call each command handler with argc == 0 and argv[0] == name.
529  */
530 void
531 help(int argc, char **argv)
532 {
533         struct cmd *c;
534
535         if (argc == 1) {
536                 int i, j, w, k;
537                 int columns, width = 0, lines;
538
539                 printf("Commands may be abbreviated.  Commands are:\n\n");
540                 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
541                         int len = strlen(c->c_name);
542
543                         if (len > width)
544                                 width = len;
545                 }
546                 width = (width + 8) &~ 7;
547                 columns = 80 / width;
548                 if (columns == 0)
549                         columns = 1;
550                 lines = (NCMDS + columns - 1) / columns;
551                 for (i = 0; i < lines; i++) {
552                         for (j = 0; j < columns; j++) {
553                                 c = cmdtab + j * lines + i;
554                                 if (c->c_name && (!proxy || c->c_proxy)) {
555                                         printf("%s", c->c_name);
556                                 }
557                                 else if (c->c_name) {
558                                         for (k=0; k < strlen(c->c_name); k++) {
559                                                 putchar(' ');
560                                         }
561                                 }
562                                 if (c + lines >= &cmdtab[NCMDS]) {
563                                         printf("\n");
564                                         break;
565                                 }
566                                 w = strlen(c->c_name);
567                                 while (w < width) {
568                                         w = (w + 8) &~ 7;
569                                         putchar('\t');
570                                 }
571                         }
572                 }
573                 return;
574         }
575         while (--argc > 0) {
576                 char *arg;
577                 arg = *++argv;
578                 c = getcmd(arg);
579                 if (c == (struct cmd *)-1)
580                         printf("?Ambiguous help command %s\n", arg);
581                 else if (c == (struct cmd *)0)
582                         printf("?Invalid help command %s\n", arg);
583                 else
584                         printf("%-*s\t%s\n", HELPINDENT,
585                                 c->c_name, c->c_help);
586         }
587 }