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