1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39 #pragma ident "%Z%%M% %I% %E% SMI"
40
41
42 /*
43 * FTP User Program -- Command Routines.
44 */
45 #define FTP_NAMES
46 #include "ftp_var.h"
47
48 FILE *tmp_nlst = NULL; /* tmp file; holds NLST results for mget, etc */
49
50 static char *mname;
51 static jmp_buf jabort;
52 static jmp_buf abortprox;
53
54 static char *remglob(char *argv[], int doswitch);
55 static char *onoff(int bool);
56 static int confirm(char *cmd, char *file);
57 static int globulize(char **cpp);
58 static void proxabort(int sig);
59 static void mabort(int sig);
60 static char *dotrans(char *name);
61 static char *domap(char *name);
62 static void getit(int argc, char *argv[], int restartit, char *mode);
63
64 static char *getlevel(int);
65
66 /* Prompt for command argument, add to buffer with space separator */
67 static int
prompt_for_arg(char * buffer,int buffer_size,char * prompt)68 prompt_for_arg(char *buffer, int buffer_size, char *prompt)
69 {
70 if (strlen(buffer) > buffer_size - 2) {
71 (void) printf("Line too long\n");
72 return (-1);
73 }
74 strcat(buffer, " ");
75 stop_timer();
76 (void) printf("(%s) ", prompt);
77 if (fgets(buffer + strlen(buffer), buffer_size - strlen(buffer), stdin)
78 == NULL) {
79 reset_timer();
80 return (-1);
81 }
82
83 /* Flush what didn't fit in the buffer */
84 if (buffer[strlen(buffer)-1] != '\n') {
85 while (fgetc(stdin) != '\n' && !ferror(stdin) && !feof(stdin))
86 ;
87 (void) printf("Line too long\n");
88 reset_timer();
89 return (-1);
90 } else
91 buffer[strlen(buffer)-1] = 0;
92
93 reset_timer();
94 return (0);
95 }
96
97
98 /*
99 * Connect to peer server and
100 * auto-login, if possible.
101 */
102 void
setpeer(int argc,char * argv[])103 setpeer(int argc, char *argv[])
104 {
105 char *host;
106
107 if (connected) {
108 (void) printf("Already connected to %s, use close first.\n",
109 hostname);
110 code = -1;
111 return;
112 }
113 if (argc < 2) {
114 if (prompt_for_arg(line, sizeof (line), "to") == -1) {
115 code = -1;
116 return;
117 }
118 makeargv();
119 argc = margc;
120 argv = margv;
121 }
122 if (argc > 3 || argc < 2) {
123 (void) printf("usage: %s host-name [port]\n", argv[0]);
124 code = -1;
125 return;
126 }
127 strcpy(typename, "ascii");
128 host = hookup(argv[1], (argc > 2 ? argv[2] : "ftp"));
129 if (host) {
130 int overbose;
131 extern char reply_string[];
132
133 connected = 1;
134 /*
135 * Set up defaults for FTP.
136 */
137 clevel = dlevel = PROT_C;
138 if (autoauth) {
139 if (do_auth() && autoencrypt) {
140 clevel = PROT_P;
141 setpbsz(1<<20);
142 if (command("PROT P") == COMPLETE)
143 dlevel = PROT_P;
144 else {
145 (void) fprintf(stderr,
146 "%s: couldn't enable encryption\n",
147 argv[0]);
148 /* unable to encrypt command channel, too! */
149 dlevel = clevel = PROT_C;
150 }
151 }
152 if ((auth_type != AUTHTYPE_NONE) && (clevel == PROT_C))
153 clevel = PROT_S;
154 }
155
156 if (autologin)
157 (void) login(argv[1]);
158 /* if skipsyst is enabled, then don't send SYST command */
159 if (skipsyst)
160 return;
161
162 overbose = verbose;
163 if (debug == 0)
164 verbose = -1;
165 if (command("SYST") == COMPLETE && overbose) {
166 char *cp, c;
167
168 cp = index(reply_string+4, ' ');
169 if (cp == NULL)
170 cp = index(reply_string+4, '\r');
171 if (cp) {
172 if (cp[-1] == '.')
173 cp--;
174 c = *cp;
175 *cp = '\0';
176 }
177
178 (void) printf("Remote system type is %s.\n",
179 reply_string+4);
180 if (cp)
181 *cp = c;
182 }
183 if (strncmp(reply_string, "215 UNIX Type: L8", 17) == 0) {
184 setbinary(0, NULL);
185 if (overbose)
186 (void) printf(
187 "Using %s mode to transfer files.\n",
188 typename);
189 } else if (overbose &&
190 strncmp(reply_string, "215 TOPS20", 10) == 0) {
191 (void) printf(
192 "Remember to set tenex mode when transfering "
193 "binary files from this machine.\n");
194 }
195 verbose = overbose;
196 }
197 }
198
199 static struct types {
200 char *t_name;
201 char *t_mode;
202 int t_type;
203 char *t_arg;
204 } types[] = {
205 { "ascii", "A", TYPE_A, 0 },
206 { "binary", "I", TYPE_I, 0 },
207 { "image", "I", TYPE_I, 0 },
208 { "ebcdic", "E", TYPE_E, 0 },
209 { "tenex", "L", TYPE_L, bytename },
210 0
211 };
212
213 /*
214 * Set transfer type.
215 */
216 void
settype(int argc,char * argv[])217 settype(int argc, char *argv[])
218 {
219 struct types *p;
220 int comret;
221
222 if (argc > 2) {
223 char *sep;
224
225 (void) printf("usage: %s [", argv[0]);
226 sep = " ";
227 for (p = types; p->t_name; p++) {
228 (void) printf("%s%s", sep, p->t_name);
229 if (*sep == ' ')
230 sep = " | ";
231 }
232 (void) printf(" ]\n");
233 code = -1;
234 return;
235 }
236 if (argc < 2) {
237 (void) printf("Using %s mode to transfer files.\n", typename);
238 code = 0;
239 return;
240 }
241 for (p = types; p->t_name; p++)
242 if (strcmp(argv[1], p->t_name) == 0)
243 break;
244 if (p->t_name == 0) {
245 (void) printf("%s: unknown mode\n", argv[1]);
246 code = -1;
247 return;
248 }
249 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
250 comret = command("TYPE %s %s", p->t_mode, p->t_arg);
251 else
252 comret = command("TYPE %s", p->t_mode);
253 if (comret == COMPLETE) {
254 (void) strcpy(typename, p->t_name);
255 type = p->t_type;
256 }
257 }
258
259 /*
260 * Set binary transfer type.
261 */
262 /*ARGSUSED*/
263 void
setbinary(int argc,char * argv[])264 setbinary(int argc, char *argv[])
265 {
266 call(settype, "type", "binary", 0);
267 }
268
269 /*
270 * Set ascii transfer type.
271 */
272 /*ARGSUSED*/
273 void
setascii(int argc,char * argv[])274 setascii(int argc, char *argv[])
275 {
276 call(settype, "type", "ascii", 0);
277 }
278
279 /*
280 * Set tenex transfer type.
281 */
282 /*ARGSUSED*/
283 void
settenex(int argc,char * argv[])284 settenex(int argc, char *argv[])
285 {
286 call(settype, "type", "tenex", 0);
287 }
288
289 /*
290 * Set ebcdic transfer type.
291 */
292 /*ARGSUSED*/
293 void
setebcdic(int argc,char * argv[])294 setebcdic(int argc, char *argv[])
295 {
296 call(settype, "type", "ebcdic", 0);
297 }
298
299 /*
300 * Set file transfer mode.
301 */
302 /*ARGSUSED*/
303 void
setmode(int argc,char * argv[])304 setmode(int argc, char *argv[])
305 {
306 (void) printf("We only support %s mode, sorry.\n", modename);
307 code = -1;
308 }
309
310 /*
311 * Set file transfer format.
312 */
313 /*ARGSUSED*/
314 void
setform(int argc,char * argv[])315 setform(int argc, char *argv[])
316 {
317 (void) printf("We only support %s format, sorry.\n", formname);
318 code = -1;
319 }
320
321 /*
322 * Set file transfer structure.
323 */
324 /*ARGSUSED*/
325 void
setstruct(int argc,char * argv[])326 setstruct(int argc, char *argv[])
327 {
328
329 (void) printf("We only support %s structure, sorry.\n", structname);
330 code = -1;
331 }
332
333 /*
334 * Send a single file.
335 */
336 void
put(int argc,char * argv[])337 put(int argc, char *argv[])
338 {
339 char *cmd;
340 int loc = 0;
341 char *oldargv1;
342
343 if (argc == 2) {
344 argc++;
345 argv[2] = argv[1];
346 loc++;
347 }
348 if (argc < 2) {
349 if (prompt_for_arg(line, sizeof (line), "local-file") == -1) {
350 code = -1;
351 return;
352 }
353 makeargv();
354 argc = margc;
355 argv = margv;
356 }
357 if (argc < 2) {
358 usage:
359 (void) printf("usage: %s local-file remote-file\n", argv[0]);
360 code = -1;
361 return;
362 }
363 if (argc < 3) {
364 if (prompt_for_arg(line, sizeof (line), "remote-file") == -1) {
365 code = -1;
366 return;
367 }
368 makeargv();
369 argc = margc;
370 argv = margv;
371 }
372 if (argc < 3)
373 goto usage;
374 oldargv1 = argv[1];
375 if (!globulize(&argv[1])) {
376 code = -1;
377 return;
378 }
379 /*
380 * If "globulize" modifies argv[1], and argv[2] is a copy of
381 * the old argv[1], make it a copy of the new argv[1].
382 */
383 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
384 argv[2] = argv[1];
385 }
386 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
387 if (loc && ntflag) {
388 argv[2] = dotrans(argv[2]);
389 }
390 if (loc && mapflag) {
391 argv[2] = domap(argv[2]);
392 }
393 sendrequest(cmd, argv[1], argv[2], 1);
394 }
395
396 /*ARGSUSED*/
397 static void
mabort(int sig)398 mabort(int sig)
399 {
400 int ointer;
401
402 (void) printf("\n");
403 (void) fflush(stdout);
404 if (mflag && fromatty) {
405 ointer = interactive;
406 interactive = 1;
407 if (confirm("Continue with", mname)) {
408 interactive = ointer;
409 longjmp(jabort, 0);
410 }
411 interactive = ointer;
412 }
413 mflag = 0;
414 longjmp(jabort, 0);
415 }
416
417 /*
418 * Send multiple files.
419 */
420 void
mput(int argc,char * argv[])421 mput(int argc, char *argv[])
422 {
423 int i;
424 int ointer;
425 void (*oldintr)();
426 char *tp;
427 int len;
428
429 if (argc < 2) {
430 if (prompt_for_arg(line, sizeof (line), "local-files") == -1) {
431 code = -1;
432 return;
433 }
434 makeargv();
435 argc = margc;
436 argv = margv;
437 }
438 if (argc < 2) {
439 (void) printf("usage: %s local-files\n", argv[0]);
440 code = -1;
441 return;
442 }
443 mname = argv[0];
444 mflag = 1;
445 oldintr = signal(SIGINT, mabort);
446 (void) setjmp(jabort);
447 if (proxy) {
448 char *cp, *tp2, tmpbuf[MAXPATHLEN];
449
450 while ((cp = remglob(argv, 0)) != NULL) {
451 if (*cp == 0) {
452 mflag = 0;
453 continue;
454 }
455 if (mflag && confirm(argv[0], cp)) {
456 tp = cp;
457 if (mcase) {
458 while (*tp) {
459 if ((len =
460 mblen(tp, MB_CUR_MAX)) <= 0)
461 len = 1;
462 if (islower(*tp))
463 break;
464 tp += len;
465 }
466 if (!*tp) {
467 tp = cp;
468 tp2 = tmpbuf;
469 while (*tp) {
470 if ((len = mblen(tp,
471 MB_CUR_MAX)) <= 0)
472 len = 1;
473 memcpy(tp2, tp, len);
474 if (isupper(*tp2)) {
475 *tp2 = 'a' +
476 *tp2 - 'A';
477 }
478 tp += len;
479 tp2 += len;
480 }
481 *tp2 = 0;
482 tp = tmpbuf;
483 }
484 }
485 if (ntflag) {
486 tp = dotrans(tp);
487 }
488 if (mapflag) {
489 tp = domap(tp);
490 }
491 sendrequest((sunique) ? "STOU" : "STOR",
492 cp, tp, 0);
493 if (!mflag && fromatty) {
494 ointer = interactive;
495 interactive = 1;
496 if (confirm("Continue with", "mput")) {
497 mflag++;
498 }
499 interactive = ointer;
500 }
501 }
502 }
503 (void) signal(SIGINT, oldintr);
504 mflag = 0;
505 return;
506 }
507 for (i = 1; i < argc; i++) {
508 char **cpp, **gargs;
509
510 if (!doglob) {
511 if (mflag && confirm(argv[0], argv[i])) {
512 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
513 tp = (mapflag) ? domap(tp) : tp;
514 sendrequest((sunique) ? "STOU" : "STOR",
515 argv[i], tp, 1);
516 if (!mflag && fromatty) {
517 ointer = interactive;
518 interactive = 1;
519 if (confirm("Continue with", "mput")) {
520 mflag++;
521 }
522 interactive = ointer;
523 }
524 }
525 continue;
526 }
527 gargs = glob(argv[i]);
528 if (globerr != NULL) {
529 (void) printf("%s\n", globerr);
530 if (gargs)
531 blkfree(gargs);
532 continue;
533 }
534 for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
535 if (mflag && confirm(argv[0], *cpp)) {
536 tp = (ntflag) ? dotrans(*cpp) : *cpp;
537 tp = (mapflag) ? domap(tp) : tp;
538 sendrequest((sunique) ? "STOU" : "STOR",
539 *cpp, tp, 0);
540 if (!mflag && fromatty) {
541 ointer = interactive;
542 interactive = 1;
543 if (confirm("Continue with", "mput")) {
544 mflag++;
545 }
546 interactive = ointer;
547 }
548 }
549 }
550 if (gargs != NULL)
551 blkfree(gargs);
552 }
553 (void) signal(SIGINT, oldintr);
554 mflag = 0;
555 }
556
557 /*
558 * Restart transfer at a specific offset.
559 */
560 void
restart(int argc,char * argv[])561 restart(int argc, char *argv[])
562 {
563 off_t orestart_point = restart_point;
564
565 if (argc > 2) {
566 (void) printf("usage: %s [marker]\n", argv[0]);
567 code = -1;
568 return;
569 }
570 if (argc == 2) {
571 longlong_t rp;
572 char *endp;
573
574 errno = 0;
575 rp = strtoll(argv[1], &endp, 10);
576 if (errno || rp < 0 || *endp != '\0')
577 (void) printf("%s: Invalid offset `%s'\n",
578 argv[0], argv[1]);
579 else
580 restart_point = rp;
581 }
582 if (restart_point == 0) {
583 if (orestart_point == 0)
584 (void) printf("No restart marker defined\n");
585 else
586 (void) printf("Restart marker cleared\n");
587 } else
588 (void) printf(
589 "Restarting at %lld for next get, put or append\n",
590 (longlong_t)restart_point);
591 }
592
593 void
reget(int argc,char * argv[])594 reget(int argc, char *argv[])
595 {
596 getit(argc, argv, 1, "r+w");
597 }
598
599 void
get(int argc,char * argv[])600 get(int argc, char *argv[])
601 {
602 getit(argc, argv, 0, restart_point ? "r+w" : "w");
603 }
604
605 /*
606 * Receive one file.
607 */
608 static void
getit(int argc,char * argv[],int restartit,char * mode)609 getit(int argc, char *argv[], int restartit, char *mode)
610 {
611 int loc = 0;
612 int len;
613 int allowpipe = 1;
614
615 if (argc == 2) {
616 argc++;
617 argv[2] = argv[1];
618 /* Only permit !file if two arguments. */
619 allowpipe = 0;
620 loc++;
621 }
622 if (argc < 2) {
623 if (prompt_for_arg(line, sizeof (line), "remote-file") == -1) {
624 code = -1;
625 return;
626 }
627 makeargv();
628 argc = margc;
629 argv = margv;
630 }
631 if (argc < 2) {
632 usage:
633 (void) printf("usage: %s remote-file [ local-file ]\n",
634 argv[0]);
635 code = -1;
636 return;
637 }
638 if (argc < 3) {
639 if (prompt_for_arg(line, sizeof (line), "local-file") == -1) {
640 code = -1;
641 return;
642 }
643 makeargv();
644 argc = margc;
645 argv = margv;
646 }
647 if (argc < 3)
648 goto usage;
649 if (!globulize(&argv[2])) {
650 code = -1;
651 return;
652 }
653 if (loc && mcase) {
654 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
655
656 while (*tp) {
657 if ((len = mblen(tp, MB_CUR_MAX)) <= 0)
658 len = 1;
659 if (islower(*tp))
660 break;
661 tp += len;
662 }
663 if (!*tp) {
664 tp = argv[2];
665 tp2 = tmpbuf;
666 while (*tp) {
667 if ((len = mblen(tp, MB_CUR_MAX)) <= 0)
668 len = 1;
669 memcpy(tp2, tp, len);
670 if (isupper(*tp2))
671 *tp2 = 'a' + *tp2 - 'A';
672 tp += len;
673 tp2 += len;
674 }
675 *tp2 = 0;
676 argv[2] = tmpbuf;
677 }
678 }
679 if (loc && ntflag) {
680 argv[2] = dotrans(argv[2]);
681 }
682 if (loc && mapflag) {
683 argv[2] = domap(argv[2]);
684 }
685 if (restartit) {
686 struct stat stbuf;
687
688 if (stat(argv[2], &stbuf) < 0) {
689 perror(argv[2]);
690 code = -1;
691 return;
692 }
693 restart_point = stbuf.st_size;
694 }
695 recvrequest("RETR", argv[2], argv[1], mode, allowpipe);
696 restart_point = 0;
697 }
698
699 /*
700 * Get multiple files.
701 */
702 void
mget(int argc,char * argv[])703 mget(int argc, char *argv[])
704 {
705 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
706 int ointer;
707 void (*oldintr)();
708 int need_convert;
709 int len;
710
711 if (argc < 2) {
712 if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) {
713 code = -1;
714 return;
715 }
716 makeargv();
717 argc = margc;
718 argv = margv;
719 }
720 if (argc < 2) {
721 (void) printf("usage: %s remote-files\n", argv[0]);
722 code = -1;
723 return;
724 }
725 mname = argv[0];
726 mflag = 1;
727 oldintr = signal(SIGINT, mabort);
728 (void) setjmp(jabort);
729 while ((cp = remglob(argv, proxy)) != NULL) {
730 if (*cp == '\0') {
731 mflag = 0;
732 continue;
733 }
734 if (mflag && confirm(argv[0], cp)) {
735 strcpy(tmpbuf, cp);
736 tp = tmpbuf;
737 need_convert = 1;
738 if (mcase) {
739 tp2 = tp;
740 while (*tp2 && need_convert) {
741 /* Need any case convert? */
742 if (islower(*tp2))
743 need_convert = 0;
744 if ((len = mblen(tp2, MB_CUR_MAX)) <= 0)
745 len = 1;
746 tp2 += len;
747 }
748 tp2 = tp;
749 while (need_convert && *tp2) {
750 /* Convert to lower case */
751 if (isupper(*tp2))
752 *tp2 = tolower(*tp2);
753 if ((len = mblen(tp2, MB_CUR_MAX)) <= 0)
754 len = 1;
755 tp2 += len;
756 }
757 }
758
759 if (ntflag) {
760 tp = dotrans(tp);
761 }
762 if (mapflag) {
763 tp = domap(tp);
764 }
765 recvrequest("RETR", tp, cp, "w", 0);
766 restart_point = 0;
767 if (!mflag && fromatty) {
768 ointer = interactive;
769 interactive = 1;
770 if (confirm("Continue with", "mget")) {
771 mflag++;
772 }
773 interactive = ointer;
774 }
775 }
776 }
777 (void) signal(SIGINT, oldintr);
778 mflag = 0;
779 }
780
781 static char *
remglob(char * argv[],int doswitch)782 remglob(char *argv[], int doswitch)
783 {
784 static char buf[MAXPATHLEN];
785 static char **args;
786 int oldverbose, oldhash;
787 char *cp;
788
789 if (!mflag) {
790 if (!doglob) {
791 args = NULL;
792 } else {
793 if (tmp_nlst != NULL) {
794 (void) fclose(tmp_nlst);
795 tmp_nlst = NULL;
796 }
797 }
798 return (NULL);
799 }
800 if (!doglob) {
801 if (args == NULL)
802 args = argv;
803 if ((cp = *++args) == NULL)
804 args = NULL;
805 return (cp);
806 }
807 if (tmp_nlst == NULL) {
808 if ((tmp_nlst = tmpfile()) == NULL) {
809 (void) printf("%s\n", strerror(errno));
810 return (NULL);
811 }
812 oldverbose = verbose, verbose = 0;
813 oldhash = hash, hash = 0;
814 if (doswitch) {
815 pswitch(!proxy);
816 }
817 for (; *++argv != NULL; )
818 recvrequest("NLST", NULL, *argv, "", 0);
819 rewind(tmp_nlst);
820 if (doswitch) {
821 pswitch(!proxy);
822 }
823 verbose = oldverbose; hash = oldhash;
824 }
825 reset_timer();
826 if (fgets(buf, sizeof (buf), tmp_nlst) == NULL) {
827 (void) fclose(tmp_nlst), tmp_nlst = NULL;
828 return (NULL);
829 }
830 if ((cp = index(buf, '\n')) != NULL)
831 *cp = '\0';
832 return (buf);
833 }
834
835 static char *
onoff(int bool)836 onoff(int bool)
837 {
838 return (bool ? "on" : "off");
839 }
840
841 /*
842 * Show status.
843 */
844 /*ARGSUSED*/
845 void
status(int argc,char * argv[])846 status(int argc, char *argv[])
847 {
848 int i;
849 char *levelp;
850
851 if (connected)
852 (void) printf("Connected to %s.\n", hostname);
853 else
854 (void) printf("Not connected.\n");
855 if (!proxy) {
856 pswitch(1);
857 if (connected) {
858 (void) printf("Connected for proxy commands to %s.\n",
859 hostname);
860 } else {
861 (void) printf("No proxy connection.\n");
862 }
863 pswitch(0);
864 }
865
866 if (auth_type != AUTHTYPE_NONE)
867 (void) printf("Authentication type: %s\n",
868 GSS_AUTHTYPE_NAME(auth_type));
869 else
870 (void) printf("Not authenticated.\n");
871 (void) printf("Mechanism: %s\n", mechstr);
872 (void) printf("Autoauth: %s; Autologin: %s\n",
873 onoff(autoauth), onoff(autologin));
874 levelp = getlevel(clevel);
875 (void) printf("Control Channel Protection Level: %s\n",
876 levelp ? levelp : "<unknown>");
877 levelp = getlevel(dlevel);
878 (void) printf("Data Channel Protection Level: %s\n",
879 levelp ? levelp : "<unknown>");
880
881 (void) printf("Passive mode: %s.\n", onoff(passivemode));
882 (void) printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
883 modename, typename, formname, structname);
884 (void) printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
885 onoff(verbose), onoff(bell), onoff(interactive),
886 onoff(doglob));
887 (void) printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
888 onoff(runique));
889 (void) printf("Case: %s; CR stripping: %s\n",
890 onoff(mcase), onoff(crflag));
891 if (ntflag) {
892 (void) printf("Ntrans: (in) %s (out) %s\n", ntin, ntout);
893 } else {
894 (void) printf("Ntrans: off\n");
895 }
896 if (mapflag) {
897 (void) printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
898 } else {
899 (void) printf("Nmap: off\n");
900 }
901 (void) printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
902 onoff(hash), onoff(sendport));
903 if (macnum > 0) {
904 (void) printf("Macros:\n");
905 for (i = 0; i < macnum; i++) {
906 (void) printf("\t%s\n", macros[i].mac_name);
907 }
908 }
909 code = 0;
910 }
911
912 /*
913 * Set beep on cmd completed mode.
914 */
915 /*ARGSUSED*/
916 void
setbell(int argc,char * argv[])917 setbell(int argc, char *argv[])
918 {
919 bell = !bell;
920 (void) printf("Bell mode %s.\n", onoff(bell));
921 code = bell;
922 }
923
924 /*
925 * Turn on packet tracing.
926 */
927 /*ARGSUSED*/
928 void
settrace(int argc,char * argv[])929 settrace(int argc, char *argv[])
930 {
931 trace = !trace;
932 (void) printf("Packet tracing %s.\n", onoff(trace));
933 code = trace;
934 }
935
936 /*
937 * Toggle hash mark printing during transfers.
938 */
939 /*ARGSUSED*/
940 void
sethash(int argc,char * argv[])941 sethash(int argc, char *argv[])
942 {
943 hash = !hash;
944 (void) printf("Hash mark printing %s", onoff(hash));
945 code = hash;
946 if (hash)
947 (void) printf(" (%d bytes/hash mark)", HASHSIZ);
948 (void) printf(".\n");
949 }
950
951 /*
952 * Turn on printing of server echo's.
953 */
954 /*ARGSUSED*/
955 void
setverbose(int argc,char * argv[])956 setverbose(int argc, char *argv[])
957 {
958 verbose = !verbose;
959 (void) printf("Verbose mode %s.\n", onoff(verbose));
960 code = verbose;
961 }
962
963 /*
964 * Toggle PORT cmd use before each data connection.
965 */
966 /*ARGSUSED*/
967 void
setport(int argc,char * argv[])968 setport(int argc, char *argv[])
969 {
970 sendport = !sendport;
971 (void) printf("Use of PORT cmds %s.\n", onoff(sendport));
972 code = sendport;
973 }
974
975 /*
976 * Turn on interactive prompting
977 * during mget, mput, and mdelete.
978 */
979 /*ARGSUSED*/
980 void
setprompt(int argc,char * argv[])981 setprompt(int argc, char *argv[])
982 {
983 interactive = !interactive;
984 (void) printf("Interactive mode %s.\n", onoff(interactive));
985 code = interactive;
986 }
987
988 /*
989 * Toggle metacharacter interpretation
990 * on local file names.
991 */
992 /*ARGSUSED*/
993 void
setglob(int argc,char * argv[])994 setglob(int argc, char *argv[])
995 {
996 doglob = !doglob;
997 (void) printf("Globbing %s.\n", onoff(doglob));
998 code = doglob;
999 }
1000
1001 /*
1002 * Set debugging mode on/off and/or
1003 * set level of debugging.
1004 */
1005 void
setdebug(int argc,char * argv[])1006 setdebug(int argc, char *argv[])
1007 {
1008 int val;
1009
1010 if (argc > 1) {
1011 val = atoi(argv[1]);
1012 if (val < 0) {
1013 (void) printf("%s: bad debugging value.\n", argv[1]);
1014 code = -1;
1015 return;
1016 }
1017 } else
1018 val = !debug;
1019 debug = val;
1020 if (debug)
1021 options |= SO_DEBUG;
1022 else
1023 options &= ~SO_DEBUG;
1024 (void) printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
1025 code = debug > 0;
1026 }
1027
1028 /*
1029 * Set current working directory
1030 * on remote machine.
1031 */
1032 void
cd(int argc,char * argv[])1033 cd(int argc, char *argv[])
1034 {
1035 if (argc < 2) {
1036 if (prompt_for_arg(line, sizeof (line), "remote-directory") <
1037 0) {
1038 code = -1;
1039 return;
1040 }
1041 makeargv();
1042 argc = margc;
1043 argv = margv;
1044 }
1045 if (argc < 2) {
1046 (void) printf("usage: %s remote-directory\n", argv[0]);
1047 code = -1;
1048 return;
1049 }
1050 (void) command("CWD %s", argv[1]);
1051 }
1052
1053 /*
1054 * Set current working directory
1055 * on local machine.
1056 */
1057 void
lcd(int argc,char * argv[])1058 lcd(int argc, char *argv[])
1059 {
1060 char buf[MAXPATHLEN], *bufptr;
1061
1062 if (argc < 2)
1063 argc++, argv[1] = home;
1064 if (argc != 2) {
1065 (void) printf("usage: %s local-directory\n", argv[0]);
1066 code = -1;
1067 return;
1068 }
1069 if (!globulize(&argv[1])) {
1070 code = -1;
1071 return;
1072 }
1073 if (chdir(argv[1]) < 0) {
1074 perror(argv[1]);
1075 code = -1;
1076 return;
1077 }
1078 bufptr = getcwd(buf, MAXPATHLEN);
1079 /*
1080 * Even though chdir may succeed, getcwd may fail if a component
1081 * of the pwd is unreadable. In this case, print the argument to
1082 * chdir as the resultant directory, since we know it succeeded above.
1083 */
1084 (void) printf("Local directory now %s\n", (bufptr ? bufptr : argv[1]));
1085 code = 0;
1086 }
1087
1088 /*
1089 * Delete a single file.
1090 */
1091 void
delete(int argc,char * argv[])1092 delete(int argc, char *argv[])
1093 {
1094
1095 if (argc < 2) {
1096 if (prompt_for_arg(line, sizeof (line), "remote-file") < 0) {
1097 code = -1;
1098 return;
1099 }
1100 makeargv();
1101 argc = margc;
1102 argv = margv;
1103 }
1104 if (argc < 2) {
1105 (void) printf("usage: %s remote-file\n", argv[0]);
1106 code = -1;
1107 return;
1108 }
1109 (void) command("DELE %s", argv[1]);
1110 }
1111
1112 /*
1113 * Delete multiple files.
1114 */
1115 void
mdelete(int argc,char * argv[])1116 mdelete(int argc, char *argv[])
1117 {
1118 char *cp;
1119 int ointer;
1120 void (*oldintr)();
1121
1122 if (argc < 2) {
1123 if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) {
1124 code = -1;
1125 return;
1126 }
1127 makeargv();
1128 argc = margc;
1129 argv = margv;
1130 }
1131 if (argc < 2) {
1132 (void) printf("usage: %s remote-files\n", argv[0]);
1133 code = -1;
1134 return;
1135 }
1136 mname = argv[0];
1137 mflag = 1;
1138 oldintr = signal(SIGINT, mabort);
1139 (void) setjmp(jabort);
1140 while ((cp = remglob(argv, 0)) != NULL) {
1141 if (*cp == '\0') {
1142 mflag = 0;
1143 continue;
1144 }
1145 if (mflag && confirm(argv[0], cp)) {
1146 (void) command("DELE %s", cp);
1147 if (!mflag && fromatty) {
1148 ointer = interactive;
1149 interactive = 1;
1150 if (confirm("Continue with", "mdelete")) {
1151 mflag++;
1152 }
1153 interactive = ointer;
1154 }
1155 }
1156 }
1157 (void) signal(SIGINT, oldintr);
1158 mflag = 0;
1159 }
1160
1161 /*
1162 * Rename a remote file.
1163 */
1164 void
renamefile(int argc,char * argv[])1165 renamefile(int argc, char *argv[])
1166 {
1167
1168 if (argc < 2) {
1169 if (prompt_for_arg(line, sizeof (line), "from-name") < 0) {
1170 code = -1;
1171 return;
1172 }
1173 makeargv();
1174 argc = margc;
1175 argv = margv;
1176 }
1177 if (argc < 2) {
1178 usage:
1179 (void) printf("%s from-name to-name\n", argv[0]);
1180 code = -1;
1181 return;
1182 }
1183 if (argc < 3) {
1184 if (prompt_for_arg(line, sizeof (line), "to-name") < 0) {
1185 code = -1;
1186 return;
1187 }
1188 makeargv();
1189 argc = margc;
1190 argv = margv;
1191 }
1192 if (argc < 3)
1193 goto usage;
1194 if (command("RNFR %s", argv[1]) == CONTINUE)
1195 (void) command("RNTO %s", argv[2]);
1196 }
1197
1198 /*
1199 * Get a directory listing
1200 * of remote files.
1201 */
1202 void
ls(int argc,char * argv[])1203 ls(int argc, char *argv[])
1204 {
1205 char *cmd;
1206
1207 if (argc < 2)
1208 argc++, argv[1] = NULL;
1209 if (argc < 3)
1210 argc++, argv[2] = "-";
1211 if (argc > 3) {
1212 (void) printf("usage: %s remote-directory local-file\n",
1213 argv[0]);
1214 code = -1;
1215 return;
1216 }
1217 if (ls_invokes_NLST) {
1218 cmd = ((argv[0][0] == 'l' || argv[0][0] == 'n') ?
1219 "NLST" : "LIST");
1220 } else {
1221 cmd = ((argv[0][0] == 'n') ? "NLST" : "LIST");
1222 }
1223 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1224 code = -1;
1225 return;
1226 }
1227 recvrequest(cmd, argv[2], argv[1], "w", 1);
1228 }
1229
1230 /*
1231 * Get a directory listing
1232 * of multiple remote files.
1233 */
1234 void
mls(int argc,char * argv[])1235 mls(int argc, char *argv[])
1236 {
1237 char *cmd, mode[1], *dest;
1238 int ointer, i;
1239 void (*oldintr)();
1240
1241 if (argc < 2) {
1242 if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) {
1243 code = -1;
1244 return;
1245 }
1246 makeargv();
1247 argc = margc;
1248 argv = margv;
1249 }
1250 if (argc < 3) {
1251 if (prompt_for_arg(line, sizeof (line), "local-file") < 0) {
1252 code = -1;
1253 return;
1254 }
1255 makeargv();
1256 argc = margc;
1257 argv = margv;
1258 }
1259 if (argc < 3) {
1260 (void) printf("usage: %s remote-files local-file\n", argv[0]);
1261 code = -1;
1262 return;
1263 }
1264 dest = argv[argc - 1];
1265 argv[argc - 1] = NULL;
1266 if (strcmp(dest, "-") && *dest != '|')
1267 if (!globulize(&dest) ||
1268 !confirm("output to local-file:", dest)) {
1269 code = -1;
1270 return;
1271 }
1272 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
1273 mname = argv[0];
1274 mflag = 1;
1275 oldintr = signal(SIGINT, mabort);
1276 (void) setjmp(jabort);
1277 for (i = 1; mflag && i < argc-1; ++i) {
1278 *mode = (i == 1) ? 'w' : 'a';
1279 recvrequest(cmd, dest, argv[i], mode, 1);
1280 if (!mflag && fromatty) {
1281 ointer = interactive;
1282 interactive = 1;
1283 if (confirm("Continue with", argv[0])) {
1284 mflag ++;
1285 }
1286 interactive = ointer;
1287 }
1288 }
1289 (void) signal(SIGINT, oldintr);
1290 mflag = 0;
1291 }
1292
1293 /*
1294 * Do a shell escape
1295 */
1296 /*ARGSUSED*/
1297 void
shell(int argc,char * argv[])1298 shell(int argc, char *argv[])
1299 {
1300 pid_t pid;
1301 void (*old1)(), (*old2)();
1302 char *shellstring, *namep;
1303 int status;
1304
1305 stop_timer();
1306 old1 = signal(SIGINT, SIG_IGN);
1307 old2 = signal(SIGQUIT, SIG_IGN);
1308 if ((pid = fork()) == 0) {
1309 closefrom(STDERR_FILENO + 1);
1310 (void) signal(SIGINT, SIG_DFL);
1311 (void) signal(SIGQUIT, SIG_DFL);
1312 shellstring = getenv("SHELL");
1313 if (shellstring == NULL)
1314 shellstring = "/bin/sh";
1315 namep = rindex(shellstring, '/');
1316 if (namep == NULL)
1317 namep = shellstring;
1318 if (argc > 1) {
1319 if (debug) {
1320 (void) printf("%s -c %s\n", shellstring,
1321 altarg);
1322 (void) fflush(stdout);
1323 }
1324 execl(shellstring, namep, "-c", altarg, (char *)0);
1325 } else {
1326 if (debug) {
1327 (void) printf("%s\n", shellstring);
1328 (void) fflush(stdout);
1329 }
1330 execl(shellstring, namep, (char *)0);
1331 }
1332 perror(shellstring);
1333 code = -1;
1334 exit(1);
1335 }
1336 if (pid > 0)
1337 while (wait(&status) != pid)
1338 ;
1339 (void) signal(SIGINT, old1);
1340 (void) signal(SIGQUIT, old2);
1341 reset_timer();
1342 if (pid == (pid_t)-1) {
1343 perror("Try again later");
1344 code = -1;
1345 } else {
1346 code = 0;
1347 }
1348 }
1349
1350 /*
1351 * Send new user information (re-login)
1352 */
1353 void
user(int argc,char * argv[])1354 user(int argc, char *argv[])
1355 {
1356 char acct[80];
1357 int n, aflag = 0;
1358
1359 if (argc < 2) {
1360 if (prompt_for_arg(line, sizeof (line), "username") < 0) {
1361 code = -1;
1362 return;
1363 }
1364 makeargv();
1365 argc = margc;
1366 argv = margv;
1367 }
1368 if (argc > 4) {
1369 (void) printf("usage: %s username [password] [account]\n",
1370 argv[0]);
1371 code = -1;
1372 return;
1373 }
1374 if (argv[1] == 0) {
1375 (void) printf("access for user (nil) denied\n");
1376 code = -1;
1377 return;
1378 }
1379 n = command("USER %s", argv[1]);
1380 if (n == CONTINUE) {
1381 int oldclevel;
1382 if (argc < 3)
1383 argv[2] = mygetpass("Password: "), argc++;
1384 if ((oldclevel = clevel) == PROT_S)
1385 clevel = PROT_P;
1386 n = command("PASS %s", argv[2]);
1387 /* level may have changed */
1388 if (clevel == PROT_P)
1389 clevel = oldclevel;
1390 }
1391 if (n == CONTINUE) {
1392 if (argc < 4) {
1393 (void) printf("Account: "); (void) fflush(stdout);
1394 stop_timer();
1395 (void) fgets(acct, sizeof (acct) - 1, stdin);
1396 reset_timer();
1397 acct[strlen(acct) - 1] = '\0';
1398 argv[3] = acct; argc++;
1399 }
1400 n = command("ACCT %s", argv[3]);
1401 aflag++;
1402 }
1403 if (n != COMPLETE) {
1404 (void) fprintf(stdout, "Login failed.\n");
1405 return;
1406 }
1407 if (!aflag && argc == 4) {
1408 (void) command("ACCT %s", argv[3]);
1409 }
1410 }
1411
1412 /*
1413 * Print working directory.
1414 */
1415 /*ARGSUSED*/
1416 void
pwd(int argc,char * argv[])1417 pwd(int argc, char *argv[])
1418 {
1419 (void) command("PWD");
1420 }
1421
1422 /*
1423 * Make a directory.
1424 */
1425 void
makedir(int argc,char * argv[])1426 makedir(int argc, char *argv[])
1427 {
1428 if (argc < 2) {
1429 if (prompt_for_arg(line, sizeof (line), "directory-name") <
1430 0) {
1431 code = -1;
1432 return;
1433 }
1434 makeargv();
1435 argc = margc;
1436 argv = margv;
1437 }
1438 if (argc < 2) {
1439 (void) printf("usage: %s directory-name\n", argv[0]);
1440 code = -1;
1441 return;
1442 }
1443 (void) command("MKD %s", argv[1]);
1444 }
1445
1446 /*
1447 * Remove a directory.
1448 */
1449 void
removedir(int argc,char * argv[])1450 removedir(int argc, char *argv[])
1451 {
1452 if (argc < 2) {
1453 if (prompt_for_arg(line, sizeof (line), "directory-name") <
1454 0) {
1455 code = -1;
1456 return;
1457 }
1458 makeargv();
1459 argc = margc;
1460 argv = margv;
1461 }
1462 if (argc < 2) {
1463 (void) printf("usage: %s directory-name\n", argv[0]);
1464 code = -1;
1465 return;
1466 }
1467 (void) command("RMD %s", argv[1]);
1468 }
1469
1470 /*
1471 * Send a line, verbatim, to the remote machine.
1472 */
1473 void
quote(int argc,char * argv[])1474 quote(int argc, char *argv[])
1475 {
1476 int i, n, len;
1477 char buf[FTPBUFSIZ];
1478
1479 if (argc < 2) {
1480 if (prompt_for_arg(line, sizeof (line),
1481 "command line to send") == -1) {
1482 code = -1;
1483 return;
1484 }
1485 makeargv();
1486 argc = margc;
1487 argv = margv;
1488 }
1489 if (argc < 2) {
1490 (void) printf("usage: %s line-to-send\n", argv[0]);
1491 code = -1;
1492 return;
1493 }
1494 len = snprintf(buf, sizeof (buf), "%s", argv[1]);
1495 if (len >= 0 && len < sizeof (buf) - 1) {
1496 for (i = 2; i < argc; i++) {
1497 n = snprintf(&buf[len], sizeof (buf) - len, " %s",
1498 argv[i]);
1499 if (n < 0 || n >= sizeof (buf) - len)
1500 break;
1501 len += n;
1502 }
1503 }
1504 if (command("%s", buf) == PRELIM) {
1505 while (getreply(0) == PRELIM)
1506 ;
1507 }
1508 }
1509
1510 /*
1511 * Send a line, verbatim, to the remote machine as a SITE command.
1512 */
1513 void
site(int argc,char * argv[])1514 site(int argc, char *argv[])
1515 {
1516 int i, n, len;
1517 char buf[FTPBUFSIZ];
1518
1519 if (argc < 2) {
1520 if (prompt_for_arg(line, sizeof (line),
1521 "arguments to SITE command") == -1) {
1522 code = -1;
1523 return;
1524 }
1525 makeargv();
1526 argc = margc;
1527 argv = margv;
1528 }
1529 if (argc < 2) {
1530 (void) printf("usage: %s arg1 [arg2] ...\n", argv[0]);
1531 code = -1;
1532 return;
1533 }
1534 len = snprintf(buf, sizeof (buf), "%s", argv[1]);
1535 if (len >= 0 && len < sizeof (buf) - 1) {
1536 for (i = 2; i < argc; i++) {
1537 n = snprintf(&buf[len], sizeof (buf) - len, " %s",
1538 argv[i]);
1539 if (n < 0 || n >= sizeof (buf) - len)
1540 break;
1541 len += n;
1542 }
1543 }
1544 if (command("SITE %s", buf) == PRELIM) {
1545 while (getreply(0) == PRELIM)
1546 ;
1547 }
1548 }
1549
1550 /*
1551 * Ask the other side for help.
1552 */
1553 void
rmthelp(int argc,char * argv[])1554 rmthelp(int argc, char *argv[])
1555 {
1556 int oldverbose = verbose;
1557
1558 verbose = 1;
1559 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1560 verbose = oldverbose;
1561 }
1562
1563 /*
1564 * Terminate session and exit.
1565 */
1566 /*ARGSUSED*/
1567 void
quit(int argc,char * argv[])1568 quit(int argc, char *argv[])
1569 {
1570 if (connected)
1571 disconnect(0, NULL);
1572 pswitch(1);
1573 if (connected) {
1574 disconnect(0, NULL);
1575 }
1576 exit(0);
1577 }
1578
1579 /*
1580 * Terminate session, but don't exit.
1581 */
1582 /*ARGSUSED*/
1583 void
disconnect(int argc,char * argv[])1584 disconnect(int argc, char *argv[])
1585 {
1586 extern FILE *ctrl_in, *ctrl_out;
1587 extern int data;
1588
1589 if (!connected)
1590 return;
1591 (void) command("QUIT");
1592 if (ctrl_in) {
1593 reset_timer();
1594 (void) fclose(ctrl_in);
1595 }
1596 if (ctrl_out) {
1597 reset_timer();
1598 (void) fclose(ctrl_out);
1599 }
1600 ctrl_out = ctrl_in = NULL;
1601 connected = 0;
1602 data = -1;
1603 if (!proxy) {
1604 macnum = 0;
1605 }
1606
1607 auth_type = AUTHTYPE_NONE;
1608 clevel = dlevel = PROT_C;
1609 goteof = 0;
1610 }
1611
1612 static int
confirm(char * cmd,char * file)1613 confirm(char *cmd, char *file)
1614 {
1615 char line[FTPBUFSIZ];
1616
1617 if (!interactive)
1618 return (1);
1619 stop_timer();
1620 (void) printf("%s %s? ", cmd, file);
1621 (void) fflush(stdout);
1622 *line = '\0';
1623 (void) fgets(line, sizeof (line), stdin);
1624 reset_timer();
1625 return (*line != 'n' && *line != 'N');
1626 }
1627
1628 void
fatal(char * msg)1629 fatal(char *msg)
1630 {
1631 (void) fprintf(stderr, "ftp: %s\n", msg);
1632 exit(1);
1633 }
1634
1635 /*
1636 * Glob a local file name specification with
1637 * the expectation of a single return value.
1638 * Can't control multiple values being expanded
1639 * from the expression, we return only the first.
1640 */
1641 static int
globulize(char ** cpp)1642 globulize(char **cpp)
1643 {
1644 char **globbed;
1645
1646 if (!doglob)
1647 return (1);
1648 globbed = glob(*cpp);
1649 if (globbed != NULL && *globbed == NULL && globerr == NULL)
1650 globerr = "No match";
1651 if (globerr != NULL) {
1652 (void) printf("%s: %s\n", *cpp, globerr);
1653 if (globbed)
1654 blkfree(globbed);
1655 return (0);
1656 }
1657 if (globbed) {
1658 *cpp = strdup(*globbed);
1659 blkfree(globbed);
1660 if (!*cpp)
1661 return (0);
1662 }
1663 return (1);
1664 }
1665
1666 void
account(int argc,char * argv[])1667 account(int argc, char *argv[])
1668 {
1669 char acct[50], *ap;
1670
1671 if (argc > 1) {
1672 ++argv;
1673 --argc;
1674 (void) strncpy(acct, *argv, 49);
1675 acct[49] = '\0';
1676 while (argc > 1) {
1677 --argc;
1678 ++argv;
1679 (void) strncat(acct, *argv, 49 - strlen(acct));
1680 }
1681 ap = acct;
1682 } else {
1683 ap = mygetpass("Account:");
1684 }
1685 (void) command("ACCT %s", ap);
1686 }
1687
1688 /*ARGSUSED*/
1689 static void
proxabort(int sig)1690 proxabort(int sig)
1691 {
1692 extern int proxy;
1693
1694 if (!proxy) {
1695 pswitch(1);
1696 }
1697 if (connected) {
1698 proxflag = 1;
1699 } else {
1700 proxflag = 0;
1701 }
1702 pswitch(0);
1703 longjmp(abortprox, 1);
1704 }
1705
1706 void
doproxy(int argc,char * argv[])1707 doproxy(int argc, char *argv[])
1708 {
1709 void (*oldintr)();
1710 struct cmd *c;
1711
1712 if (argc < 2) {
1713 if (prompt_for_arg(line, sizeof (line), "command") == -1) {
1714 code = -1;
1715 return;
1716 }
1717 makeargv();
1718 argc = margc;
1719 argv = margv;
1720 }
1721 if (argc < 2) {
1722 (void) printf("usage: %s command\n", argv[0]);
1723 code = -1;
1724 return;
1725 }
1726 c = getcmd(argv[1]);
1727 if (c == (struct cmd *)-1) {
1728 (void) printf("?Ambiguous command\n");
1729 (void) fflush(stdout);
1730 code = -1;
1731 return;
1732 }
1733 if (c == 0) {
1734 (void) printf("?Invalid command\n");
1735 (void) fflush(stdout);
1736 code = -1;
1737 return;
1738 }
1739 if (!c->c_proxy) {
1740 (void) printf("?Invalid proxy command\n");
1741 (void) fflush(stdout);
1742 code = -1;
1743 return;
1744 }
1745 if (setjmp(abortprox)) {
1746 code = -1;
1747 return;
1748 }
1749 oldintr = signal(SIGINT, (void (*)())proxabort);
1750 pswitch(1);
1751 if (c->c_conn && !connected) {
1752 (void) printf("Not connected\n");
1753 (void) fflush(stdout);
1754 pswitch(0);
1755 (void) signal(SIGINT, oldintr);
1756 code = -1;
1757 return;
1758 }
1759 (*c->c_handler)(argc-1, argv+1);
1760 if (connected) {
1761 proxflag = 1;
1762 } else {
1763 proxflag = 0;
1764 }
1765 pswitch(0);
1766 (void) signal(SIGINT, oldintr);
1767 }
1768
1769 /*ARGSUSED*/
1770 void
setcase(int argc,char * argv[])1771 setcase(int argc, char *argv[])
1772 {
1773 mcase = !mcase;
1774 (void) printf("Case mapping %s.\n", onoff(mcase));
1775 code = mcase;
1776 }
1777
1778 /*ARGSUSED*/
1779 void
setcr(int argc,char * argv[])1780 setcr(int argc, char *argv[])
1781 {
1782 crflag = !crflag;
1783 (void) printf("Carriage Return stripping %s.\n", onoff(crflag));
1784 code = crflag;
1785 }
1786
1787 void
setntrans(int argc,char * argv[])1788 setntrans(int argc, char *argv[])
1789 {
1790 if (argc == 1) {
1791 ntflag = 0;
1792 (void) printf("Ntrans off.\n");
1793 code = ntflag;
1794 return;
1795 }
1796 ntflag++;
1797 code = ntflag;
1798 (void) strncpy(ntin, argv[1], 16);
1799 ntin[16] = '\0';
1800 if (argc == 2) {
1801 ntout[0] = '\0';
1802 return;
1803 }
1804 (void) strncpy(ntout, argv[2], 16);
1805 ntout[16] = '\0';
1806 }
1807
1808 static char *
dotrans(char * name)1809 dotrans(char *name)
1810 {
1811 static char new[MAXPATHLEN];
1812 char *cp1, *cp2 = new;
1813 int i, ostop, found;
1814
1815 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1816 ;
1817 for (cp1 = name; *cp1; cp1++) {
1818 found = 0;
1819 for (i = 0; *(ntin + i) && i < 16; i++) {
1820 if (*cp1 == *(ntin + i)) {
1821 found++;
1822 if (i < ostop) {
1823 *cp2++ = *(ntout + i);
1824 }
1825 break;
1826 }
1827 }
1828 if (!found) {
1829 *cp2++ = *cp1;
1830 }
1831 }
1832 *cp2 = '\0';
1833 return (new);
1834 }
1835
1836 void
setnmap(int argc,char * argv[])1837 setnmap(int argc, char *argv[])
1838 {
1839 char *cp;
1840
1841 if (argc == 1) {
1842 mapflag = 0;
1843 (void) printf("Nmap off.\n");
1844 code = mapflag;
1845 return;
1846 }
1847 if (argc < 3) {
1848 if (prompt_for_arg(line, sizeof (line), "mapout") == -1) {
1849 code = -1;
1850 return;
1851 }
1852 makeargv();
1853 argc = margc;
1854 argv = margv;
1855 }
1856 if (argc < 3) {
1857 (void) printf("Usage: %s [mapin mapout]\n", argv[0]);
1858 code = -1;
1859 return;
1860 }
1861 mapflag = 1;
1862 code = 1;
1863 cp = index(altarg, ' ');
1864 if (proxy) {
1865 while (*++cp == ' ')
1866 /* NULL */;
1867 altarg = cp;
1868 cp = index(altarg, ' ');
1869 }
1870 *cp = '\0';
1871 (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
1872 while (*++cp == ' ')
1873 /* NULL */;
1874 (void) strncpy(mapout, cp, MAXPATHLEN - 1);
1875 }
1876
1877 static char *
domap(char * name)1878 domap(char *name)
1879 {
1880 static char new[MAXPATHLEN];
1881 char *cp1 = name, *cp2 = mapin;
1882 char *tp[9], *te[9];
1883 int i, toks[9], toknum, match = 1;
1884 wchar_t wc1, wc2;
1885 int len1, len2;
1886
1887 for (i = 0; i < 9; ++i) {
1888 toks[i] = 0;
1889 }
1890 while (match && *cp1 && *cp2) {
1891 if ((len1 = mbtowc(&wc1, cp1, MB_CUR_MAX)) <= 0) {
1892 wc1 = (unsigned char)*cp1;
1893 len1 = 1;
1894 }
1895 cp1 += len1;
1896 if ((len2 = mbtowc(&wc2, cp2, MB_CUR_MAX)) <= 0) {
1897 wc2 = (unsigned char)*cp2;
1898 len2 = 1;
1899 }
1900 cp2 += len2;
1901
1902 switch (wc2) {
1903 case '\\':
1904 if ((len2 = mbtowc(&wc2, cp2, MB_CUR_MAX)) <= 0) {
1905 wc2 = (unsigned char)*cp2;
1906 len2 = 1;
1907 }
1908 cp2 += len2;
1909 if (wc2 != wc1)
1910 match = 0;
1911 break;
1912
1913 case '$':
1914 if (*cp2 >= '1' && *cp2 <= '9') {
1915 if ((len2 =
1916 mbtowc(&wc2, cp2 + 1, MB_CUR_MAX)) <= 0) {
1917 wc2 = (unsigned char)*(cp2 + 1);
1918 len2 = 1;
1919 }
1920 if (wc1 != wc2) {
1921 toks[toknum = *cp2 - '1']++;
1922 tp[toknum] = cp1 - len1;
1923 while (*cp1) {
1924 if ((len1 = mbtowc(&wc1,
1925 cp1, MB_CUR_MAX)) <= 0) {
1926 wc1 =
1927 (unsigned char)*cp1;
1928 len1 = 1;
1929 }
1930 cp1 += len1;
1931 if (wc2 == wc1)
1932 break;
1933 }
1934 if (*cp1 == 0 && wc2 != wc1)
1935 te[toknum] = cp1;
1936 else
1937 te[toknum] = cp1 - len1;
1938 }
1939 cp2++; /* Consume the digit */
1940 if (wc2)
1941 cp2 += len2; /* Consume wide char */
1942 break;
1943 }
1944 /* intentional drop through */
1945 default:
1946 if (wc2 != wc1)
1947 match = 0;
1948 break;
1949 }
1950 }
1951
1952 cp1 = new;
1953 *cp1 = '\0';
1954 cp2 = mapout;
1955 while (*cp2) {
1956 match = 0;
1957 switch (*cp2) {
1958 case '\\':
1959 cp2++;
1960 if (*cp2) {
1961 if ((len2 = mblen(cp2, MB_CUR_MAX)) <= 0)
1962 len2 = 1;
1963 memcpy(cp1, cp2, len2);
1964 cp1 += len2;
1965 cp2 += len2;
1966 }
1967 break;
1968
1969 case '[':
1970 LOOP:
1971 cp2++;
1972 if (*cp2 == '$' && isdigit(*(cp2+1))) {
1973 if (*++cp2 == '0') {
1974 char *cp3 = name;
1975
1976 while (*cp3) {
1977 *cp1++ = *cp3++;
1978 }
1979 match = 1;
1980 } else if (toks[toknum = *cp2 - '1']) {
1981 char *cp3 = tp[toknum];
1982
1983 while (cp3 != te[toknum]) {
1984 *cp1++ = *cp3++;
1985 }
1986 match = 1;
1987 }
1988 } else {
1989 while (*cp2 && *cp2 != ',' && *cp2 != ']') {
1990 if (*cp2 == '\\') {
1991 cp2++;
1992 continue;
1993 }
1994
1995 if (*cp2 == '$' && isdigit(*(cp2+1))) {
1996 if (*++cp2 == '0') {
1997 char *cp3 = name;
1998
1999 while (*cp3)
2000 *cp1++ = *cp3++;
2001 continue;
2002 }
2003 if (toks[toknum = *cp2 - '1']) {
2004 char *cp3 = tp[toknum];
2005
2006 while (cp3 !=
2007 te[toknum])
2008 *cp1++ = *cp3++;
2009 }
2010 continue;
2011 }
2012 if (*cp2) {
2013 if ((len2 =
2014 mblen(cp2, MB_CUR_MAX)) <=
2015 0) {
2016 len2 = 1;
2017 }
2018 memcpy(cp1, cp2, len2);
2019 cp1 += len2;
2020 cp2 += len2;
2021 }
2022 }
2023 if (!*cp2) {
2024 (void) printf(
2025 "nmap: unbalanced brackets\n");
2026 return (name);
2027 }
2028 match = 1;
2029 }
2030 if (match) {
2031 while (*cp2 && *cp2 != ']') {
2032 if (*cp2 == '\\' && *(cp2 + 1)) {
2033 cp2++;
2034 }
2035 if ((len2 = mblen(cp2, MB_CUR_MAX)) <=
2036 0)
2037 len2 = 1;
2038 cp2 += len2;
2039 }
2040 if (!*cp2) {
2041 (void) printf(
2042 "nmap: unbalanced brackets\n");
2043 return (name);
2044 }
2045 cp2++;
2046 break;
2047 }
2048 switch (*++cp2) {
2049 case ',':
2050 goto LOOP;
2051 case ']':
2052 break;
2053 default:
2054 cp2--;
2055 goto LOOP;
2056 }
2057 cp2++;
2058 break;
2059 case '$':
2060 if (isdigit(*(cp2 + 1))) {
2061 if (*++cp2 == '0') {
2062 char *cp3 = name;
2063
2064 while (*cp3) {
2065 *cp1++ = *cp3++;
2066 }
2067 } else if (toks[toknum = *cp2 - '1']) {
2068 char *cp3 = tp[toknum];
2069
2070 while (cp3 != te[toknum]) {
2071 *cp1++ = *cp3++;
2072 }
2073 }
2074 cp2++;
2075 break;
2076 }
2077 /* intentional drop through */
2078 default:
2079 if ((len2 = mblen(cp2, MB_CUR_MAX)) <= 0)
2080 len2 = 1;
2081 memcpy(cp1, cp2, len2);
2082 cp1 += len2;
2083 cp2 += len2;
2084 break;
2085 }
2086 }
2087 *cp1 = '\0';
2088 if (!*new) {
2089 return (name);
2090 }
2091 return (new);
2092 }
2093
2094 /*ARGSUSED*/
2095 void
setsunique(int argc,char * argv[])2096 setsunique(int argc, char *argv[])
2097 {
2098 sunique = !sunique;
2099 (void) printf("Store unique %s.\n", onoff(sunique));
2100 code = sunique;
2101 }
2102
2103 /*ARGSUSED*/
2104 void
setrunique(int argc,char * argv[])2105 setrunique(int argc, char *argv[])
2106 {
2107 runique = !runique;
2108 (void) printf("Receive unique %s.\n", onoff(runique));
2109 code = runique;
2110 }
2111
2112 /*ARGSUSED*/
2113 void
setpassive(int argc,char * argv[])2114 setpassive(int argc, char *argv[])
2115 {
2116 passivemode = !passivemode;
2117 (void) printf("Passive mode %s.\n", onoff(passivemode));
2118 code = passivemode;
2119 }
2120
2121 void
settcpwindow(int argc,char * argv[])2122 settcpwindow(int argc, char *argv[])
2123 {
2124 int owindowsize = tcpwindowsize;
2125
2126 if (argc > 2) {
2127 (void) printf("usage: %s [size]\n", argv[0]);
2128 code = -1;
2129 return;
2130 }
2131 if (argc == 2) {
2132 int window;
2133 char *endp;
2134
2135 errno = 0;
2136 window = (int)strtol(argv[1], &endp, 10);
2137 if (errno || window < 0 || *endp != '\0')
2138 (void) printf("%s: Invalid size `%s'\n",
2139 argv[0], argv[1]);
2140 else
2141 tcpwindowsize = window;
2142 }
2143 if (tcpwindowsize == 0) {
2144 if (owindowsize == 0)
2145 (void) printf("No TCP window size defined\n");
2146 else
2147 (void) printf("TCP window size cleared\n");
2148 } else
2149 (void) printf("TCP window size is set to %d\n", tcpwindowsize);
2150 }
2151
2152 /* change directory to parent directory */
2153 /*ARGSUSED*/
2154 void
cdup(int argc,char * argv[])2155 cdup(int argc, char *argv[])
2156 {
2157 (void) command("CDUP");
2158 }
2159
2160 void
macdef(int argc,char * argv[])2161 macdef(int argc, char *argv[])
2162 {
2163 char *tmp;
2164 int c;
2165
2166 if (macnum == 16) {
2167 (void) printf("Limit of 16 macros have already been defined\n");
2168 code = -1;
2169 return;
2170 }
2171 if (argc < 2) {
2172 if (prompt_for_arg(line, sizeof (line), "macro name") == -1) {
2173 code = -1;
2174 return;
2175 }
2176 makeargv();
2177 argc = margc;
2178 argv = margv;
2179 }
2180 if (argc != 2) {
2181 (void) printf("Usage: %s macro_name\n", argv[0]);
2182 code = -1;
2183 return;
2184 }
2185 if (interactive) {
2186 (void) printf("Enter macro line by line, terminating "
2187 "it with a null line\n");
2188 }
2189 (void) strncpy(macros[macnum].mac_name, argv[1], 8);
2190 if (macnum == 0) {
2191 macros[macnum].mac_start = macbuf;
2192 } else {
2193 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2194 }
2195 tmp = macros[macnum].mac_start;
2196 while (tmp != macbuf+4096) {
2197 if ((c = getchar()) == EOF) {
2198 (void) printf("macdef:end of file encountered\n");
2199 code = -1;
2200 return;
2201 }
2202 if ((*tmp = c) == '\n') {
2203 if (tmp == macros[macnum].mac_start) {
2204 macros[macnum++].mac_end = tmp;
2205 code = 0;
2206 return;
2207 }
2208 if (*(tmp-1) == '\0') {
2209 macros[macnum++].mac_end = tmp - 1;
2210 code = 0;
2211 return;
2212 }
2213 *tmp = '\0';
2214 }
2215 tmp++;
2216 }
2217 for (;;) {
2218 while ((c = getchar()) != '\n' && c != EOF)
2219 /* NULL */;
2220 if (c == EOF || getchar() == '\n') {
2221 (void) printf(
2222 "Macro not defined - 4k buffer exceeded\n");
2223 code = -1;
2224 return;
2225 }
2226 }
2227 }
2228
2229 /*
2230 * The p_name strings are for the getlevel and setlevel commands.
2231 * The name strings for printing are in the arpa/ftp.h file in the
2232 * protnames[] array of strings.
2233 */
2234 static struct levels {
2235 char *p_name;
2236 char *p_mode;
2237 int p_level;
2238 } levels[] = {
2239 { "clear", "C", PROT_C },
2240 { "safe", "S", PROT_S },
2241 { "private", "P", PROT_P },
2242 NULL
2243 };
2244
2245 /*
2246 * Return a pointer to a string which is the readable version of the
2247 * protection level, or NULL if the input level is not found.
2248 */
2249 static char *
getlevel(int level)2250 getlevel(int level)
2251 {
2252 struct levels *p;
2253
2254 for (p = levels; (p != NULL) && (p->p_level != level); p++)
2255 ;
2256 return (p ? p->p_name : NULL);
2257 }
2258
2259 static char *plevel[] = {
2260 "protect",
2261 "",
2262 NULL
2263 };
2264
2265 /*
2266 * Set control channel protection level.
2267 */
2268 void
setclevel(int argc,char * argv[])2269 setclevel(int argc, char *argv[])
2270 {
2271 struct levels *p;
2272 char *levelp;
2273 int comret;
2274
2275 if (argc > 2) {
2276 char *sep;
2277
2278 (void) printf("usage: %s [", argv[0]);
2279 sep = " ";
2280 for (p = levels; p->p_name; p++) {
2281 (void) printf("%s%s", sep, p->p_name);
2282 if (*sep == ' ')
2283 sep = " | ";
2284 }
2285 (void) printf(" ]\n");
2286 code = -1;
2287 return;
2288 }
2289 if (argc < 2) {
2290 levelp = getlevel(clevel);
2291 (void) printf("Using %s protection level for commands.\n",
2292 levelp ? levelp : "<unknown>");
2293 code = 0;
2294 return;
2295 }
2296 for (p = levels; (p != NULL) && (p->p_name); p++)
2297 if (strcmp(argv[1], p->p_name) == 0)
2298 break;
2299 if (p->p_name == 0) {
2300 (void) printf("%s: unknown protection level\n", argv[1]);
2301 code = -1;
2302 return;
2303 }
2304 if (auth_type == AUTHTYPE_NONE) {
2305 if (strcmp(p->p_name, "clear"))
2306 (void) printf("Cannot set protection level to %s\n",
2307 argv[1]);
2308 return;
2309 }
2310 if (strcmp(p->p_name, "clear") == 0) {
2311 comret = command("CCC");
2312 if (comret == COMPLETE)
2313 clevel = PROT_C;
2314 return;
2315 }
2316 clevel = p->p_level;
2317 (void) printf("Control channel protection level set to %s.\n",
2318 p->p_name);
2319 }
2320
2321 /*
2322 * Set data channel protection level.
2323 */
2324 void
setdlevel(int argc,char * argv[])2325 setdlevel(int argc, char *argv[])
2326 {
2327 struct levels *p;
2328 int comret;
2329
2330 if (argc != 2) {
2331 char *sep;
2332
2333 (void) printf("usage: %s [", argv[0]);
2334 sep = " ";
2335 for (p = levels; p->p_name; p++) {
2336 (void) printf("%s%s", sep, p->p_name);
2337 if (*sep == ' ')
2338 sep = " | ";
2339 }
2340 (void) printf(" ]\n");
2341 code = -1;
2342 return;
2343 }
2344 for (p = levels; p->p_name; p++)
2345 if (strcmp(argv[1], p->p_name) == 0)
2346 break;
2347 if (p->p_name == 0) {
2348 (void) printf("%s: unknown protection level\n", argv[1]);
2349 code = -1;
2350 return;
2351 }
2352 if (auth_type == AUTHTYPE_NONE) {
2353 if (strcmp(p->p_name, "clear"))
2354 (void) printf("Cannot set protection level to %s\n",
2355 argv[1]);
2356 return;
2357 }
2358 /* Start with a PBSZ of 1 meg */
2359 if (p->p_level != PROT_C)
2360 setpbsz(1<<20);
2361 comret = command("PROT %s", p->p_mode);
2362 if (comret == COMPLETE)
2363 dlevel = p->p_level;
2364 }
2365
2366 /*
2367 * Set clear command protection level.
2368 */
2369 /* VARARGS */
2370 void
ccc(int argc,char * argv[])2371 ccc(int argc, char *argv[])
2372 {
2373 plevel[1] = "clear";
2374 setclevel(2, plevel);
2375 }
2376
2377 /*
2378 * Set clear data protection level.
2379 */
2380 /* VARARGS */
2381 void
setclear(int argc,char * argv[])2382 setclear(int argc, char *argv[])
2383 {
2384 plevel[1] = "clear";
2385 setdlevel(2, plevel);
2386 }
2387
2388 /*
2389 * Set safe data protection level.
2390 */
2391 /* VARARGS */
2392 void
setsafe(int argc,char * argv[])2393 setsafe(int argc, char *argv[])
2394 {
2395 plevel[1] = "safe";
2396 setdlevel(2, plevel);
2397 }
2398
2399 /*
2400 * Set private data protection level.
2401 */
2402 /* VARARGS */
2403 void
setprivate(int argc,char * argv[])2404 setprivate(int argc, char *argv[])
2405 {
2406 plevel[1] = "private";
2407 setdlevel(2, plevel);
2408 }
2409
2410 /*
2411 * Set mechanism type
2412 */
2413 void
setmech(int argc,char * argv[])2414 setmech(int argc, char *argv[])
2415 {
2416 char tempmech[MECH_SZ];
2417
2418 if (argc < 2) {
2419 if (prompt_for_arg(line, sizeof (line), "mech-type") == -1) {
2420 code = -1;
2421 return;
2422 }
2423 makeargv();
2424 argc = margc;
2425 argv = margv;
2426 }
2427
2428 if (argc != 2) {
2429 (void) printf("usage: %s [ mechanism type ]\n", argv[0]);
2430 code = -1;
2431 return;
2432 }
2433
2434 if ((strlcpy(tempmech, argv[1], MECH_SZ) >= MECH_SZ) ||
2435 __gss_mech_to_oid(tempmech, (gss_OID*)&mechoid) !=
2436 GSS_S_COMPLETE) {
2437 (void) printf("%s: %s: not a valid security mechanism\n",
2438 argv[0], tempmech);
2439 code = -1;
2440 return;
2441 } else {
2442 (void) strlcpy(mechstr, tempmech, MECH_SZ);
2443 (void) printf("Using %s mechanism type\n", mechstr);
2444 code = 0;
2445 return;
2446 }
2447 }
2448