2 /* $NetBSD: ftp.c,v 1.29.2.1 1997/11/18 01:01:04 mellon Exp $ */
5 * Copyright (c) 1985, 1989, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/cdefs.h>
40 static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
43 __RCSID_SOURCE("$NetBSD: ftp.c,v 1.29.2.1 1997/11/18 01:01:04 mellon Exp $");
47 #include <sys/types.h>
49 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <netinet/in_systm.h>
53 #include <netinet/ip.h>
54 #include <arpa/inet.h>
56 #include <arpa/telnet.h>
74 /* wrapper for KAME-special getnameinfo() */
75 #ifndef NI_WITHSCOPEID
76 #define NI_WITHSCOPEID 0
95 struct sockaddr_in su_sin;
96 struct sockaddr_in6 su_sin6;
98 #define su_len su_si.si_len
99 #define su_family su_si.si_family
100 #define su_port su_si.si_port
102 union sockunion myctladdr, hisctladdr, data_addr;
109 int s, len, tos, error;
110 struct addrinfo hints, *res, *res0;
111 static char hostnamebuf[MAXHOSTNAMELEN];
114 if (*host0 == '[' && strrchr(host0, ']') != NULL) { /*IPv6 addr in []*/
115 strncpy(hostnamebuf, host0 + 1, strlen(host0) - 2);
116 hostnamebuf[strlen(host0) - 2] = '\0';
118 strncpy(hostnamebuf, host0, strlen(host0));
119 hostnamebuf[strlen(host0)] = '\0';
122 memset(&hints, 0, sizeof(hints));
123 hints.ai_flags = AI_CANONNAME;
124 hints.ai_family = family;
125 hints.ai_socktype = SOCK_STREAM;
126 hints.ai_protocol = 0;
127 error = getaddrinfo(host, port, &hints, &res0);
129 warnx("%s: %s", host, gai_strerror(error));
130 if (error == EAI_SYSTEM)
131 warnx("%s: %s", host, strerror(errno));
137 if (res->ai_canonname)
138 (void) strncpy(hostnamebuf, res->ai_canonname,
139 sizeof(hostnamebuf));
140 hostname = hostnamebuf;
143 * make sure that ai_addr is NOT an IPv4 mapped address.
144 * IPv4 mapped address complicates too many things in FTP
145 * protocol handling, as FTP protocol is defined differently
146 * between IPv4 and IPv6.
149 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
159 struct addrinfo *bindres;
162 for (bindres = bindres0;
164 bindres = bindres->ai_next)
165 if (bindres->ai_family == res->ai_family)
169 binderr = bind(s, bindres->ai_addr,
170 bindres->ai_addrlen);
183 if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
186 char hname[INET6_ADDRSTRLEN];
187 getnameinfo(res->ai_addr, res->ai_addrlen,
188 hname, sizeof(hname) - 1, NULL, 0,
189 NI_NUMERICHOST|NI_WITHSCOPEID);
190 warn("connect to address %s", hname);
192 getnameinfo(res->ai_addr, res->ai_addrlen,
193 hname, sizeof(hname) - 1, NULL, 0,
194 NI_NUMERICHOST|NI_WITHSCOPEID);
195 printf("Trying %s...\n", hname);
203 memcpy(&hisctladdr, res->ai_addr, res->ai_addrlen);
205 len = sizeof(myctladdr);
206 if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
212 if (myctladdr.su_family == AF_INET)
214 tos = IPTOS_LOWDELAY;
215 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
216 warn("setsockopt TOS (ignored)");
219 cin = fdopen(s, "r");
220 cout = fdopen(s, "w");
221 if (cin == NULL || cout == NULL) {
222 warnx("fdopen failed.");
231 printf("Connected to %s.\n", hostname);
232 if (getreply(0) > 2) { /* read startup message from server */
244 if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
249 #endif /* SO_OOBINLINE */
264 (void)fflush(stdout);
273 command(const char *fmt, ...)
288 fputs("---> ", stdout);
293 fmt = va_arg(ap, const char *);
295 if (strncmp("PASS ", fmt, 5) == 0)
296 fputs("PASS XXXX", stdout);
297 else if (strncmp("ACCT ", fmt, 5) == 0)
298 fputs("ACCT XXXX", stdout);
303 (void)fflush(stdout);
306 warnx("No control connection for command.");
310 oldintr = signal(SIGINT, cmdabort);
315 fmt = va_arg(ap, char *);
317 vfprintf(cout, fmt, ap);
322 r = getreply(!strcmp(fmt, "QUIT"));
323 if (abrtflag && oldintr != SIG_IGN)
325 (void)signal(SIGINT, oldintr);
329 char reply_string[BUFSIZ]; /* first line of previous reply */
335 char current_line[BUFSIZ]; /* last line of previous reply */
338 int originalcode = 0, continuation = 0;
341 char *cp, *pt = pasv;
343 oldintr = signal(SIGINT, cmdabort);
344 for (line = 0 ;; line++) {
347 while ((c = getc(cin)) != '\n') {
348 if (c == IAC) { /* handle telnet commands */
349 switch (c = getc(cin)) {
353 fprintf(cout, "%c%c%c", IAC, DONT, c);
359 fprintf(cout, "%c%c%c", IAC, WONT, c);
370 (void)signal(SIGINT, oldintr);
377 "421 Service not available, remote server has closed connection.");
378 (void)fflush(stdout);
383 if (c != '\r' && (verbose > 0 ||
384 (verbose > -1 && n == '5' && dig > 4))) {
386 (dig == 1 || (dig == 5 && verbose == 0)))
387 printf("%s:", hostname);
390 if (dig < 4 && isdigit((unsigned char)c))
391 code = code * 10 + (c - '0');
394 if (code == 227 || code == 228) {
395 /* result for PASV/LPSV */
398 } else if (code == 229) {
399 /* result for EPSV */
405 if (!(dig > 4 && isdigit((unsigned char)c)))
410 if (c != '\r' && c != ')' &&
411 pt < &pasv[sizeof(pasv)-1])
419 if (dig > 4 && c == '(')
423 if (dig == 4 && c == '-') {
430 if (cp < ¤t_line[sizeof(current_line) - 1])
433 if (verbose > 0 || (verbose > -1 && n == '5')) {
435 (void)fflush (stdout);
438 size_t len = cp - current_line;
440 if (len > sizeof(reply_string))
441 len = sizeof(reply_string);
443 (void)strncpy(reply_string, current_line, len);
444 reply_string[len] = '\0';
446 if (continuation && code != originalcode) {
447 if (originalcode == 0)
454 (void)signal(SIGINT, oldintr);
455 if (code == 421 || originalcode == 421)
457 if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
470 t.tv_sec = (long) sec;
472 return (select(32, mask, (fd_set *) 0, (fd_set *) 0, &t));
485 puts("\nsend aborted\nwaiting for remote to finish abort.");
486 (void)fflush(stdout);
487 longjmp(sendabort, 1);
491 sendrequest(cmd, local, remote, printnames)
492 const char *cmd, *local, *remote;
498 int (*closefunc) __P((FILE *));
499 sig_t oldinti, oldintr, oldintp;
500 volatile off_t hashbytes;
501 char *lmode, buf[BUFSIZ], *bufp;
504 #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
519 oprogress = progress;
520 if (verbose && printnames) {
521 if (local && *local != '-')
522 printf("local: %s ", local);
524 printf("remote: %s\n", remote);
527 proxtrans(cmd, local, remote);
537 if (setjmp(sendabort)) {
546 (void)signal(SIGINT, oldintr);
548 (void)signal(SIGPIPE, oldintp);
550 (void)signal(SIGINFO, oldinti);
554 oldintr = signal(SIGINT, abortsend);
555 oldinti = signal(SIGINFO, psummary);
556 if (strcmp(local, "-") == 0) {
559 } else if (*local == '|') {
560 oldintp = signal(SIGPIPE, SIG_IGN);
561 fin = popen(local + 1, "r");
563 warn("%s", local + 1);
564 (void)signal(SIGINT, oldintr);
565 (void)signal(SIGPIPE, oldintp);
566 (void)signal(SIGINFO, oldinti);
573 fin = fopen(local, "r");
575 warn("local: %s", local);
576 (void)signal(SIGINT, oldintr);
577 (void)signal(SIGINFO, oldinti);
582 if (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
583 printf("%s: not a plain file.\n", local);
584 (void)signal(SIGINT, oldintr);
585 (void)signal(SIGINFO, oldinti);
590 filesize = st.st_size;
593 (void)signal(SIGINT, oldintr);
594 (void)signal(SIGINFO, oldinti);
596 (void)signal(SIGPIPE, oldintp);
598 if (closefunc != NULL)
602 if (setjmp(sendabort))
606 (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
612 rc = fseek(fin, (long) restart_point, SEEK_SET);
616 rc = lseek(fileno(fin), restart_point, SEEK_SET);
620 warn("local: %s", local);
621 if (closefunc != NULL)
625 if (command("REST %qd", (long long) restart_point) !=
627 if (closefunc != NULL)
634 if (command("%s %s", cmd, remote) != PRELIM) {
635 (void)signal(SIGINT, oldintr);
636 (void)signal(SIGINFO, oldinti);
638 (void)signal(SIGPIPE, oldintp);
639 if (closefunc != NULL)
644 if (command("%s", cmd) != PRELIM) {
645 (void)signal(SIGINT, oldintr);
646 (void)signal(SIGINFO, oldinti);
648 (void)signal(SIGPIPE, oldintp);
649 if (closefunc != NULL)
653 dout = dataconn(lmode);
657 oldintp = signal(SIGPIPE, SIG_IGN);
663 while ((c = read(fileno(fin), buf, sizeof(buf))) > 0) {
665 for (bufp = buf; c > 0; c -= d, bufp += d)
666 if ((d = write(fileno(dout), bufp, c)) <= 0)
668 if (hash && (!progress || filesize < 0) ) {
669 while (bytes >= hashbytes) {
673 (void)fflush(stdout);
676 if (hash && (!progress || filesize < 0) && bytes > 0) {
680 (void)fflush(stdout);
683 warn("local: %s", local);
692 while ((c = getc(fin)) != EOF) {
694 while (hash && (!progress || filesize < 0) &&
695 (bytes >= hashbytes)) {
697 (void)fflush(stdout);
702 (void)putc('\r', dout);
707 #if 0 /* this violates RFC */
709 (void)putc('\0', dout);
714 if (hash && (!progress || filesize < 0)) {
715 if (bytes < hashbytes)
718 (void)fflush(stdout);
721 warn("local: %s", local);
730 if (closefunc != NULL)
734 (void)signal(SIGINT, oldintr);
735 (void)signal(SIGINFO, oldinti);
737 (void)signal(SIGPIPE, oldintp);
742 (void)signal(SIGINT, oldintr);
743 (void)signal(SIGINFO, oldinti);
745 (void)signal(SIGPIPE, oldintp);
758 if (closefunc != NULL && fin != NULL)
763 progress = oprogress;
777 puts("\nreceive aborted\nwaiting for remote to finish abort.");
778 (void)fflush(stdout);
779 longjmp(recvabort, 1);
783 recvrequest(cmd, local, remote, lmode, printnames, ignorespecial)
784 const char *cmd, *local, *remote, *lmode;
785 int printnames, ignorespecial;
788 int (*closefunc) __P((FILE *));
789 sig_t oldinti, oldintr, oldintp;
791 volatile int is_retr, tcrflag, bare_lfs;
792 static size_t bufsize;
794 volatile off_t hashbytes;
797 struct timeval tval[2];
801 #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
815 direction = "received";
819 oprogress = progress;
820 opreserve = preserve;
821 is_retr = (strcmp(cmd, "RETR") == 0);
822 if (is_retr && verbose && printnames) {
823 if (local && (ignorespecial || *local != '-'))
824 printf("local: %s ", local);
826 printf("remote: %s\n", remote);
828 if (proxy && is_retr) {
829 proxtrans(cmd, local, remote);
835 tcrflag = !crflag && is_retr;
836 if (setjmp(recvabort)) {
845 (void)signal(SIGINT, oldintr);
847 (void)signal(SIGINFO, oldinti);
848 progress = oprogress;
849 preserve = opreserve;
853 oldintr = signal(SIGINT, abortrecv);
854 oldinti = signal(SIGINFO, psummary);
855 if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
856 if (access(local, W_OK) < 0) {
857 char *dir = strrchr(local, '/');
859 if (errno != ENOENT && errno != EACCES) {
860 warn("local: %s", local);
861 (void)signal(SIGINT, oldintr);
862 (void)signal(SIGINFO, oldinti);
868 d = access(dir == local ? "/" : dir ? local : ".", W_OK);
872 warn("local: %s", local);
873 (void)signal(SIGINT, oldintr);
874 (void)signal(SIGINFO, oldinti);
878 if (!runique && errno == EACCES &&
879 chmod(local, 0600) < 0) {
880 warn("local: %s", local);
881 (void)signal(SIGINT, oldintr);
882 (void)signal(SIGINFO, oldinti);
886 if (runique && errno == EACCES &&
887 (local = gunique(local)) == NULL) {
888 (void)signal(SIGINT, oldintr);
889 (void)signal(SIGINFO, oldinti);
894 else if (runique && (local = gunique(local)) == NULL) {
895 (void)signal(SIGINT, oldintr);
896 (void)signal(SIGINFO, oldinti);
902 if (curtype != TYPE_A)
903 changetype(TYPE_A, 0);
907 filesize = remotesize(remote, 0);
910 (void)signal(SIGINT, oldintr);
911 (void)signal(SIGINFO, oldinti);
915 if (setjmp(recvabort))
917 if (is_retr && restart_point &&
918 command("REST %qd", (long long) restart_point) != CONTINUE)
921 if (command("%s %s", cmd, remote) != PRELIM) {
922 (void)signal(SIGINT, oldintr);
923 (void)signal(SIGINFO, oldinti);
927 if (command("%s", cmd) != PRELIM) {
928 (void)signal(SIGINT, oldintr);
929 (void)signal(SIGINFO, oldinti);
936 if (!ignorespecial && strcmp(local, "-") == 0) {
940 } else if (!ignorespecial && *local == '|') {
941 oldintp = signal(SIGPIPE, SIG_IGN);
942 fout = popen(local + 1, "w");
951 fout = fopen(local, lmode);
953 warn("local: %s", local);
958 if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
959 st.st_blksize = BUFSIZ;
960 if (st.st_blksize > bufsize) {
963 buf = malloc((unsigned)st.st_blksize);
969 bufsize = st.st_blksize;
971 if (!S_ISREG(st.st_mode)) {
980 if (is_retr && restart_point &&
981 lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
982 warn("local: %s", local);
983 progress = oprogress;
984 preserve = opreserve;
985 if (closefunc != NULL)
990 while ((c = read(fileno(din), buf, bufsize)) > 0) {
991 if ((d = write(fileno(fout), buf, c)) != c)
994 if (hash && (!progress || filesize < 0)) {
995 while (bytes >= hashbytes) {
999 (void)fflush(stdout);
1002 if (hash && (!progress || filesize < 0) && bytes > 0) {
1005 (void)putchar('\n');
1006 (void)fflush(stdout);
1015 warn("local: %s", local);
1017 warnx("%s: short write", local);
1022 if (is_retr && restart_point) {
1026 if (fseek(fout, 0L, SEEK_SET) < 0)
1028 n = (long)restart_point;
1029 for (i = 0; i++ < n;) {
1030 if ((ch = getc(fout)) == EOF)
1035 if (fseek(fout, 0L, SEEK_CUR) < 0) {
1037 warn("local: %s", local);
1038 progress = oprogress;
1039 preserve = opreserve;
1040 if (closefunc != NULL)
1045 while ((c = getc(din)) != EOF) {
1049 while (hash && (!progress || filesize < 0) &&
1050 (bytes >= hashbytes)) {
1052 (void)fflush(stdout);
1056 if ((c = getc(din)) != '\n' || tcrflag) {
1059 (void)putc('\r', fout);
1068 (void)putc(c, fout);
1075 "WARNING! %d bare linefeeds received in ASCII mode.\n", bare_lfs);
1076 puts("File may not have transferred correctly.");
1078 if (hash && (!progress || filesize < 0)) {
1079 if (bytes < hashbytes)
1081 (void)putchar('\n');
1082 (void)fflush(stdout);
1090 warn("local: %s", local);
1094 progress = oprogress;
1095 preserve = opreserve;
1096 if (closefunc != NULL)
1098 (void)signal(SIGINT, oldintr);
1099 (void)signal(SIGINFO, oldinti);
1101 (void)signal(SIGPIPE, oldintp);
1104 if (bytes >= 0 && is_retr) {
1107 if (preserve && (closefunc == fclose)) {
1108 mtime = remotemodtime(remote, 0);
1110 (void)gettimeofday(&tval[0],
1111 (struct timezone *)0);
1112 tval[1].tv_sec = mtime;
1113 tval[1].tv_usec = 0;
1114 if (utimes(local, tval) == -1) {
1116 "Can't change modification time on %s to %s",
1117 local, asctime(localtime(&mtime)));
1126 /* abort using RFC959 recommended IP,SYNC sequence */
1128 progress = oprogress;
1129 preserve = opreserve;
1131 (void)signal(SIGPIPE, oldintp);
1132 (void)signal(SIGINT, SIG_IGN);
1135 (void)signal(SIGINT, oldintr);
1136 (void)signal(SIGINFO, oldinti);
1146 if (closefunc != NULL && fout != NULL)
1152 (void)signal(SIGINT, oldintr);
1153 (void)signal(SIGINFO, oldinti);
1157 * Need to start a listen on the data channel before we send the command,
1158 * otherwise the server's connect may fail.
1164 int result, len, tmpno = 0;
1173 if (myctladdr.su_family == AF_INET6
1174 && (IN6_IS_ADDR_LINKLOCAL(&myctladdr.su_sin6.sin6_addr)
1175 || IN6_IS_ADDR_SITELOCAL(&myctladdr.su_sin6.sin6_addr))) {
1176 warnx("use of scoped address can be troublesome");
1181 data_addr = myctladdr;
1182 data = socket(data_addr.su_family, SOCK_STREAM, 0);
1188 struct addrinfo *bindres;
1191 for (bindres = bindres0;
1193 bindres = bindres->ai_next)
1194 if (bindres->ai_family == data_addr.su_family)
1196 if (bindres == NULL)
1198 binderr = bind(data, bindres->ai_addr,
1199 bindres->ai_addrlen);
1206 if ((options & SO_DEBUG) &&
1207 setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1209 warn("setsockopt (ignored)");
1210 switch (data_addr.su_family) {
1218 result = command(pasvcmd = "EPSV");
1220 if (code / 10 == 22 && code != 229) {
1221 puts("wrong server: EPSV return code must be 229");
1222 result = COMPLETE + 1;
1225 result = COMPLETE + 1;
1226 if (result != COMPLETE) {
1228 result = command(pasvcmd = "PASV");
1233 result = command(pasvcmd = "EPSV");
1234 if (code / 10 == 22 && code != 229) {
1235 puts("wrong server: EPSV return code must be 229");
1236 result = COMPLETE + 1;
1238 if (result != COMPLETE)
1239 result = command(pasvcmd = "LPSV");
1243 result = COMPLETE + 1;
1245 if (result != COMPLETE) {
1246 puts("Passive mode refused.");
1250 #define pack2(var, offset) \
1251 (((var[(offset) + 0] & 0xff) << 8) | ((var[(offset) + 1] & 0xff) << 0))
1252 #define pack4(var, offset) \
1253 (((var[(offset) + 0] & 0xff) << 24) | ((var[(offset) + 1] & 0xff) << 16) \
1254 | ((var[(offset) + 2] & 0xff) << 8) | ((var[(offset) + 3] & 0xff) << 0))
1256 * What we've got at this point is a string of comma
1257 * separated one-byte unsigned integer values.
1259 * The first four are the an IP address. The fifth is
1260 * the MSB of the port number, the sixth is the LSB.
1261 * From that we'll prepare a sockaddr_in.
1262 * In other case, the format is more complicated.
1264 if (strcmp(pasvcmd, "PASV") == 0) {
1265 if (code / 10 == 22 && code != 227) {
1266 puts("wrong server: return code must be 227");
1270 error = sscanf(pasv, "%d,%d,%d,%d,%d,%d",
1271 &h[0], &h[1], &h[2], &h[3],
1275 data_addr.su_sin.sin_addr.s_addr =
1279 } else if (strcmp(pasvcmd, "LPSV") == 0) {
1280 if (code / 10 == 22 && code != 228) {
1281 puts("wrong server: return code must be 228");
1285 switch (data_addr.su_family) {
1287 error = sscanf(pasv,
1288 "%d,%d,%d,%d,%d,%d,%d,%d,%d",
1290 &h[0], &h[1], &h[2], &h[3],
1291 &pal, &prt[0], &prt[1]);
1292 if (error == 9 && af == 4 && hal == 4 && pal == 2) {
1294 data_addr.su_sin.sin_addr.s_addr =
1301 error = sscanf(pasv,
1302 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1304 &h[0], &h[1], &h[2], &h[3],
1305 &h[4], &h[5], &h[6], &h[7],
1306 &h[8], &h[9], &h[10], &h[11],
1307 &h[12], &h[13], &h[14], &h[15],
1308 &pal, &prt[0], &prt[1]);
1309 if (error != 21 || af != 6 || hal != 16 || pal != 2) {
1317 p32 = (u_int32_t *)&data_addr.su_sin6.sin6_addr;
1318 p32[0] = htonl(pack4(h, 0));
1319 p32[1] = htonl(pack4(h, 4));
1320 p32[2] = htonl(pack4(h, 8));
1321 p32[3] = htonl(pack4(h, 12));
1328 } else if (strcmp(pasvcmd, "EPSV") == 0) {
1333 if (code / 10 == 22 && code != 229) {
1334 puts("wrong server: return code must be 229");
1338 error = sscanf(pasv, "%c%c%c%d%c",
1339 &delim[0], &delim[1], &delim[2],
1340 &prt[1], &delim[3]);
1345 if (delim[0] != delim[1] || delim[0] != delim[2]
1346 || delim[0] != delim[3]) {
1351 data_addr = hisctladdr;
1353 prt[0] = (prt[1] & 0xff00) >> 8;
1362 "Passive mode address scan failure. Shouldn't happen!");
1366 data_addr.su_port = htons(pack2(prt, 0));
1368 if (connect(data, (struct sockaddr *)&data_addr,
1369 data_addr.su_len) < 0) {
1374 if (data_addr.su_family == AF_INET)
1376 on = IPTOS_THROUGHPUT;
1377 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1379 warn("setsockopt TOS (ignored)");
1386 data_addr = myctladdr;
1388 data_addr.su_port = 0; /* let system pick one */
1391 data = socket(data_addr.su_family, SOCK_STREAM, 0);
1399 if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
1401 warn("setsockopt (reuse address)");
1405 if (data_addr.su_family == AF_INET)
1408 ports = restricted_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
1409 if (setsockopt(data, IPPROTO_IP, IP_PORTRANGE, (char *)&ports,
1411 warn("setsockopt PORTRANGE (ignored)");
1415 #ifdef IPV6_PORTRANGE
1416 if (data_addr.su_family == AF_INET6) {
1417 ports = restricted_data_ports ? IPV6_PORTRANGE_HIGH
1418 : IPV6_PORTRANGE_DEFAULT;
1419 if (setsockopt(data, IPPROTO_IPV6, IPV6_PORTRANGE,
1420 (char *)&ports, sizeof(ports)) < 0)
1421 warn("setsockopt PORTRANGE (ignored)");
1425 if (bind(data, (struct sockaddr *)&data_addr, data_addr.su_len) < 0) {
1429 if (options & SO_DEBUG &&
1430 setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1432 warn("setsockopt (ignored)");
1433 len = sizeof(data_addr);
1434 if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1435 warn("getsockname");
1438 if (listen(data, 1) < 0)
1441 char hname[INET6_ADDRSTRLEN];
1443 struct sockaddr_in data_addr4;
1444 union sockunion *daddr;
1447 if (data_addr.su_family == AF_INET6 &&
1448 IN6_IS_ADDR_V4MAPPED(&data_addr.su_sin6.sin6_addr)) {
1449 memset(&data_addr4, 0, sizeof(data_addr4));
1450 data_addr4.sin_len = sizeof(struct sockaddr_in);
1451 data_addr4.sin_family = AF_INET;
1452 data_addr4.sin_port = data_addr.su_port;
1453 memcpy((caddr_t)&data_addr4.sin_addr,
1454 (caddr_t)&data_addr.su_sin6.sin6_addr.s6_addr[12],
1455 sizeof(struct in_addr));
1456 daddr = (union sockunion *)&data_addr4;
1463 #define UC(b) (((int)b)&0xff)
1465 switch (daddr->su_family) {
1469 af = (daddr->su_family == AF_INET) ? 1 : 2;
1470 if (getnameinfo((struct sockaddr *)daddr,
1471 daddr->su_len, hname,
1472 sizeof(hname) - 1, NULL, 0,
1476 result = command("EPRT |%d|%s|%d|",
1477 af, hname, ntohs(daddr->su_port));
1481 result = COMPLETE + 1;
1484 if (result == COMPLETE)
1487 p = (char *)&daddr->su_port;
1488 switch (daddr->su_family) {
1490 a = (char *)&daddr->su_sin.sin_addr;
1491 result = command("PORT %d,%d,%d,%d,%d,%d",
1492 UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
1493 UC(p[0]), UC(p[1]));
1497 a = (char *)&daddr->su_sin6.sin6_addr;
1499 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1501 UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
1502 UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]),
1503 UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]),
1504 UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]),
1505 2, UC(p[0]), UC(p[1]));
1509 result = COMPLETE + 1; /* xxx */
1513 if (result == ERROR && sendport == -1) {
1518 return (result != COMPLETE);
1523 if (data_addr.su_family == AF_INET)
1525 on = IPTOS_THROUGHPUT;
1526 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1527 warn("setsockopt TOS (ignored)");
1532 (void)close(data), data = -1;
1542 union sockunion from;
1543 int s, fromlen, tos;
1545 fromlen = myctladdr.su_len;
1548 return (fdopen(data, lmode));
1550 s = accept(data, (struct sockaddr *) &from, &fromlen);
1553 (void)close(data), data = -1;
1559 if (data_addr.su_family == AF_INET)
1561 tos = IPTOS_THROUGHPUT;
1562 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1563 warn("setsockopt TOS (ignored)");
1566 return (fdopen(data, lmode));
1592 static struct comvars {
1594 char name[MAXHOSTNAMELEN];
1595 union sockunion mctl;
1596 union sockunion hctl;
1609 char mi[MAXPATHLEN];
1610 char mo[MAXPATHLEN];
1611 } proxstruct, tmpstruct;
1612 struct comvars *ip, *op;
1615 oldintr = signal(SIGINT, psabort);
1629 ip->connect = connected;
1630 connected = op->connect;
1632 (void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1633 ip->name[sizeof(ip->name) - 1] = '\0';
1636 hostname = op->name;
1637 ip->hctl = hisctladdr;
1638 hisctladdr = op->hctl;
1639 ip->mctl = myctladdr;
1640 myctladdr = op->mctl;
1647 ip->curtpe = curtype;
1648 curtype = op->curtpe;
1651 ip->sunqe = sunique;
1652 sunique = op->sunqe;
1653 ip->runqe = runique;
1654 runique = op->runqe;
1659 (void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
1660 (ip->nti)[sizeof(ip->nti) - 1] = '\0';
1661 (void)strcpy(ntin, op->nti);
1662 (void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
1663 (ip->nto)[sizeof(ip->nto) - 1] = '\0';
1664 (void)strcpy(ntout, op->nto);
1665 ip->mapflg = mapflag;
1666 mapflag = op->mapflg;
1667 (void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
1668 (ip->mi)[sizeof(ip->mi) - 1] = '\0';
1669 (void)strcpy(mapin, op->mi);
1670 (void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
1671 (ip->mo)[sizeof(ip->mo) - 1] = '\0';
1672 (void)strcpy(mapout, op->mo);
1673 (void)signal(SIGINT, oldintr);
1687 (void)fflush(stdout);
1691 longjmp(ptabort, 1);
1695 proxtrans(cmd, local, remote)
1696 const char *cmd, *local, *remote;
1699 int prox_type, nfnd;
1700 volatile int secndflag;
1704 #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
1711 if (strcmp(cmd, "RETR"))
1714 cmd2 = runique ? "STOU" : "STOR";
1715 if ((prox_type = type) == 0) {
1716 if (unix_server && unix_proxy)
1721 if (curtype != prox_type)
1722 changetype(prox_type, 1);
1723 if (try_epsv && command("EPSV") != COMPLETE)
1725 if (!try_epsv && command("PASV") != COMPLETE) {
1726 puts("proxy server does not support third party transfers.");
1731 puts("No primary connection.");
1736 if (curtype != prox_type)
1737 changetype(prox_type, 1);
1738 if (command("PORT %s", pasv) != COMPLETE) {
1742 if (setjmp(ptabort))
1744 oldintr = signal(SIGINT, abortpt);
1745 if (command("%s %s", cmd, remote) != PRELIM) {
1746 (void)signal(SIGINT, oldintr);
1753 if (command("%s %s", cmd2, local) != PRELIM)
1759 (void)signal(SIGINT, oldintr);
1762 printf("local: %s remote: %s\n", local, remote);
1765 (void)signal(SIGINT, SIG_IGN);
1767 if (strcmp(cmd, "RETR") && !proxy)
1769 else if (!strcmp(cmd, "RETR") && proxy)
1771 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
1772 if (command("%s %s", cmd2, local) != PRELIM) {
1775 abort_remote((FILE *) NULL);
1780 (void)signal(SIGINT, oldintr);
1784 abort_remote((FILE *) NULL);
1786 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
1787 if (command("%s %s", cmd2, local) != PRELIM) {
1790 abort_remote((FILE *) NULL);
1794 (void)signal(SIGINT, oldintr);
1799 abort_remote((FILE *) NULL);
1803 FD_SET(fileno(cin), &mask);
1804 if ((nfnd = empty(&mask, 10)) <= 0) {
1820 (void)signal(SIGINT, oldintr);
1833 FD_SET(fileno(cin), &mask);
1834 if ((nfnd = empty(&mask, 0)) < 0) {
1849 static char new[MAXPATHLEN];
1850 char *cp = strrchr(local, '/');
1856 d = access(cp == local ? "/" : cp ? local : ".", W_OK);
1860 warn("local: %s", local);
1861 return ((char *) 0);
1863 (void)strcpy(new, local);
1864 cp = new + strlen(new);
1867 if (++count == 100) {
1868 puts("runique: can't find unique file name.");
1869 return ((char *) 0);
1877 if ((d = access(new, F_OK)) < 0)
1881 else if (*(cp - 2) == '.')
1884 *(cp - 2) = *(cp - 2) + 1;
1900 warnx("Lost control connection for abort.");
1907 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1908 * after urgent byte rather than before as is protocol now
1910 sprintf(buf, "%c%c%c", IAC, IP, IAC);
1911 if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1913 fprintf(cout, "%cABOR\r\n", DM);
1916 FD_SET(fileno(cin), &mask);
1918 FD_SET(fileno(din), &mask);
1920 if ((nfnd = empty(&mask, 10)) <= 0) {
1928 if (din && FD_ISSET(fileno(din), &mask)) {
1929 while (read(fileno(din), buf, BUFSIZ) > 0)
1932 if (getreply(0) == ERROR && code == 552) {
1933 /* 552 needed for nic style abort */
1941 struct addrinfo *ai;
1943 struct sockaddr_in6 *sin6;
1944 struct sockaddr_in sin;
1946 if (ai->ai_family != AF_INET6)
1948 if (ai->ai_addrlen != sizeof(struct sockaddr_in6) ||
1949 sizeof(sin) > ai->ai_addrlen)
1951 sin6 = (struct sockaddr_in6 *)ai->ai_addr;
1952 if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
1955 memset(&sin, 0, sizeof(sin));
1956 sin.sin_family = AF_INET;
1957 sin.sin_len = sizeof(struct sockaddr_in);
1958 memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
1959 sizeof(sin.sin_addr));
1960 sin.sin_port = sin6->sin6_port;
1962 ai->ai_family = AF_INET;
1963 memcpy(ai->ai_addr, &sin, sin.sin_len);
1964 ai->ai_addrlen = sin.sin_len;