Annotation of src/usr.bin/ftp/ftp.c, Revision 1.104
1.104 ! florian 1: /* $OpenBSD: ftp.c,v 1.100 2016/08/22 16:27:00 millert Exp $ */
! 2: /* $NetBSD: ftp.c,v 1.27 1997/08/18 10:20:23 lukem Exp $ */
1.102 jasper 3:
1.34 itojun 4: /*
1.104 ! florian 5: * Copyright (C) 1997 and 1998 WIDE Project.
! 6: * All rights reserved.
1.1 deraadt 7: *
1.104 ! florian 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 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. Neither the name of the project nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
1.1 deraadt 19: *
1.104 ! florian 20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
1.1 deraadt 31: */
32:
1.104 ! florian 33: /*
! 34: * Copyright (c) 1985, 1989, 1993, 1994
! 35: * The Regents of the University of California. All rights reserved.
! 36: *
! 37: * Redistribution and use in source and binary forms, with or without
! 38: * modification, are permitted provided that the following conditions
! 39: * are met:
! 40: * 1. Redistributions of source code must retain the above copyright
! 41: * notice, this list of conditions and the following disclaimer.
! 42: * 2. Redistributions in binary form must reproduce the above copyright
! 43: * notice, this list of conditions and the following disclaimer in the
! 44: * documentation and/or other materials provided with the distribution.
! 45: * 3. Neither the name of the University nor the names of its contributors
! 46: * may be used to endorse or promote products derived from this software
! 47: * without specific prior written permission.
! 48: *
! 49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 59: * SUCH DAMAGE.
! 60: */
! 61:
! 62: #include <sys/types.h>
! 63: #include <sys/stat.h>
1.1 deraadt 64: #include <sys/socket.h>
65:
1.104 ! florian 66: #include <netinet/in.h>
! 67: #include <netinet/ip.h>
1.101 kmos 68: #include <arpa/inet.h>
1.104 ! florian 69: #include <arpa/ftp.h>
! 70: #include <arpa/telnet.h>
1.1 deraadt 71:
1.104 ! florian 72: #include <ctype.h>
1.1 deraadt 73: #include <err.h>
74: #include <errno.h>
75: #include <netdb.h>
1.104 ! florian 76: #include <poll.h>
1.54 millert 77: #include <stdarg.h>
1.1 deraadt 78: #include <stdio.h>
79: #include <stdlib.h>
80: #include <string.h>
81: #include <unistd.h>
1.104 ! florian 82: #include <utime.h>
1.1 deraadt 83:
1.104 ! florian 84: #include "ftp_var.h"
1.101 kmos 85:
1.104 ! florian 86: union sockaddr_union {
! 87: struct sockaddr sa;
! 88: struct sockaddr_in sin;
! 89: struct sockaddr_in6 sin6;
! 90: };
1.101 kmos 91:
1.104 ! florian 92: union sockaddr_union myctladdr, hisctladdr, data_addr;
1.1 deraadt 93:
1.104 ! florian 94: int data = -1;
! 95: int abrtflag = 0;
! 96: jmp_buf ptabort;
! 97: int ptabflg;
! 98: int ptflag = 0;
! 99: off_t restart_point = 0;
1.34 itojun 100:
101:
1.104 ! florian 102: FILE *cin, *cout;
1.1 deraadt 103:
1.104 ! florian 104: char *
! 105: hookup(char *host, char *port)
! 106: {
! 107: int s, tos, error;
! 108: static char hostnamebuf[HOST_NAME_MAX+1];
! 109: struct addrinfo hints, *res, *res0;
! 110: #ifndef SMALL
! 111: struct addrinfo *ares;
! 112: #endif
! 113: char hbuf[NI_MAXHOST];
! 114: char *cause = "unknown";
! 115: socklen_t namelen;
! 116:
! 117: epsv4bad = 0;
! 118:
! 119: memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
! 120: memset(&hints, 0, sizeof(hints));
! 121: hints.ai_flags = AI_CANONNAME;
! 122: hints.ai_family = family;
! 123: hints.ai_socktype = SOCK_STREAM;
! 124: hints.ai_protocol = 0;
! 125: error = getaddrinfo(host, port, &hints, &res0);
! 126: if (error == EAI_SERVICE) {
! 127: /*
! 128: * If the services file is corrupt/missing, fall back
! 129: * on our hard-coded defines.
! 130: */
! 131: char pbuf[NI_MAXSERV];
! 132:
! 133: pbuf[0] = '\0';
! 134: if (strcmp(port, "ftp") == 0)
! 135: snprintf(pbuf, sizeof(pbuf), "%d", FTP_PORT);
! 136: else if (strcmp(port, "ftpgate") == 0)
! 137: snprintf(pbuf, sizeof(pbuf), "%d", GATE_PORT);
! 138: else if (strcmp(port, "http") == 0)
! 139: snprintf(pbuf, sizeof(pbuf), "%d", HTTP_PORT);
! 140: #ifndef SMALL
! 141: else if (strcmp(port, "https") == 0)
! 142: snprintf(pbuf, sizeof(pbuf), "%d", HTTPS_PORT);
! 143: #endif /* !SMALL */
! 144: if (pbuf[0])
! 145: error = getaddrinfo(host, pbuf, &hints, &res0);
! 146: }
! 147: if (error) {
! 148: if (error == EAI_SERVICE)
! 149: warnx("%s: bad port number `%s'", host, port);
! 150: else
! 151: warnx("%s: %s", host, gai_strerror(error));
! 152: code = -1;
! 153: return (0);
1.101 kmos 154: }
1.1 deraadt 155:
1.104 ! florian 156: if (res0->ai_canonname)
! 157: strlcpy(hostnamebuf, res0->ai_canonname, sizeof(hostnamebuf));
! 158: else
! 159: strlcpy(hostnamebuf, host, sizeof(hostnamebuf));
! 160: hostname = hostnamebuf;
! 161:
! 162: #ifndef SMALL
! 163: if (srcaddr) {
! 164: struct addrinfo ahints;
! 165:
! 166: memset(&ahints, 0, sizeof(ahints));
! 167: ahints.ai_family = family;
! 168: ahints.ai_socktype = SOCK_STREAM;
! 169: ahints.ai_flags |= AI_NUMERICHOST;
! 170: ahints.ai_protocol = 0;
! 171:
! 172: error = getaddrinfo(srcaddr, NULL, &ahints, &ares);
! 173: if (error) {
! 174: warnx("%s: %s", srcaddr, gai_strerror(error));
! 175: code = -1;
! 176: return (0);
! 177: }
! 178: }
! 179: #endif /* !SMALL */
! 180:
! 181: s = -1;
! 182: for (res = res0; res; res = res->ai_next) {
! 183: if (res0->ai_next) /* if we have multiple possibilities */
! 184: {
! 185: if (getnameinfo(res->ai_addr, res->ai_addrlen,
! 186: hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
! 187: strlcpy(hbuf, "unknown", sizeof(hbuf));
! 188: if (verbose)
! 189: fprintf(ttyout, "Trying %s...\n", hbuf);
! 190: }
! 191: s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
! 192: if (s < 0) {
! 193: cause = "socket";
! 194: continue;
! 195: }
! 196: #ifndef SMALL
! 197: if (srcaddr) {
! 198: if (ares->ai_family != res->ai_family) {
! 199: close(s);
! 200: s = -1;
! 201: errno = EINVAL;
! 202: cause = "bind";
! 203: continue;
! 204: }
! 205: if (bind(s, ares->ai_addr, ares->ai_addrlen) < 0) {
! 206: cause = "bind";
! 207: error = errno;
! 208: close(s);
! 209: errno = error;
! 210: s = -1;
! 211: continue;
! 212: }
! 213: }
! 214: #endif /* !SMALL */
! 215: for (error = connect(s, res->ai_addr, res->ai_addrlen);
! 216: error != 0 && errno == EINTR; error = connect_wait(s))
! 217: continue;
! 218: if (error != 0) {
! 219: /* this "if" clause is to prevent print warning twice */
! 220: if (verbose && res->ai_next) {
! 221: if (getnameinfo(res->ai_addr, res->ai_addrlen,
! 222: hbuf, sizeof(hbuf), NULL, 0,
! 223: NI_NUMERICHOST) != 0)
! 224: strlcpy(hbuf, "(unknown)",
! 225: sizeof(hbuf));
! 226: warn("connect to address %s", hbuf);
! 227: }
! 228: cause = "connect";
! 229: error = errno;
! 230: close(s);
! 231: errno = error;
! 232: s = -1;
! 233: continue;
! 234: }
! 235:
! 236: /* finally we got one */
! 237: break;
1.101 kmos 238: }
1.104 ! florian 239: if (s < 0) {
! 240: warn("%s", cause);
! 241: code = -1;
! 242: freeaddrinfo(res0);
! 243: return 0;
! 244: }
! 245: memcpy(&hisctladdr, res->ai_addr, res->ai_addrlen);
! 246: namelen = res->ai_addrlen;
! 247: freeaddrinfo(res0);
! 248: res0 = res = NULL;
! 249: #ifndef SMALL
! 250: if (srcaddr) {
! 251: freeaddrinfo(ares);
! 252: ares = NULL;
! 253: }
! 254: #endif /* !SMALL */
! 255: if (getsockname(s, &myctladdr.sa, &namelen) < 0) {
! 256: warn("getsockname");
! 257: code = -1;
! 258: goto bad;
! 259: }
! 260: if (hisctladdr.sa.sa_family == AF_INET) {
! 261: tos = IPTOS_LOWDELAY;
! 262: if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
! 263: warn("setsockopt TOS (ignored)");
! 264: }
! 265: cin = fdopen(s, "r");
! 266: cout = fdopen(s, "w");
! 267: if (cin == NULL || cout == NULL) {
! 268: warnx("fdopen failed.");
! 269: if (cin)
! 270: (void)fclose(cin);
! 271: if (cout)
! 272: (void)fclose(cout);
! 273: code = -1;
! 274: goto bad;
! 275: }
! 276: if (verbose)
! 277: fprintf(ttyout, "Connected to %s.\n", hostname);
! 278: if (getreply(0) > 2) { /* read startup message from server */
! 279: if (cin)
! 280: (void)fclose(cin);
! 281: if (cout)
! 282: (void)fclose(cout);
! 283: code = -1;
! 284: goto bad;
! 285: }
! 286: {
! 287: int ret, on = 1;
! 288:
! 289: ret = setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on));
! 290: #ifndef SMALL
! 291: if (ret < 0 && debug)
! 292: warn("setsockopt");
! 293: #endif /* !SMALL */
! 294: }
! 295:
! 296: return (hostname);
! 297: bad:
! 298: (void)close(s);
! 299: return (NULL);
1.101 kmos 300: }
1.97 millert 301:
1.104 ! florian 302: /* ARGSUSED */
! 303: void
! 304: cmdabort(int signo)
1.1 deraadt 305: {
1.104 ! florian 306: int save_errno = errno;
1.101 kmos 307:
1.104 ! florian 308: alarmtimer(0);
! 309: (void) write(fileno(ttyout), "\n\r", 2);
! 310: abrtflag++;
! 311:
! 312: errno = save_errno;
! 313: if (ptflag)
! 314: longjmp(ptabort, 1);
! 315: }
1.101 kmos 316:
1.104 ! florian 317: int
! 318: command(const char *fmt, ...)
! 319: {
! 320: va_list ap;
! 321: int r;
! 322: sig_t oldintr;
! 323:
! 324: abrtflag = 0;
! 325: #ifndef SMALL
! 326: if (debug) {
! 327: fputs("---> ", ttyout);
! 328: va_start(ap, fmt);
! 329: if (strncmp("PASS ", fmt, 5) == 0)
! 330: fputs("PASS XXXX", ttyout);
! 331: else if (strncmp("ACCT ", fmt, 5) == 0)
! 332: fputs("ACCT XXXX", ttyout);
! 333: else
! 334: vfprintf(ttyout, fmt, ap);
! 335: va_end(ap);
! 336: putc('\n', ttyout);
! 337: (void)fflush(ttyout);
! 338: }
! 339: #endif /* !SMALL */
! 340: if (cout == NULL) {
! 341: warnx("No control connection for command.");
! 342: code = -1;
! 343: return (0);
1.1 deraadt 344: }
1.104 ! florian 345: oldintr = signal(SIGINT, cmdabort);
! 346: va_start(ap, fmt);
! 347: vfprintf(cout, fmt, ap);
! 348: va_end(ap);
! 349: fputs("\r\n", cout);
! 350: (void)fflush(cout);
! 351: cpend = 1;
! 352: r = getreply(!strcmp(fmt, "QUIT"));
! 353: if (abrtflag && oldintr != SIG_IGN)
! 354: (*oldintr)(SIGINT);
! 355: (void)signal(SIGINT, oldintr);
! 356: return (r);
! 357: }
1.101 kmos 358:
1.104 ! florian 359: int keep_alive_timeout = 60; /* 0 -> no timeout */
1.34 itojun 360:
1.104 ! florian 361: static int full_noops_sent = 0;
! 362: static time_t last_timestamp = 0; /* 0 -> no measurement yet */
! 363: static char noop[] = "NOOP\r\n";
! 364: #define NOOP_LENGTH (sizeof noop - 1)
! 365: static int current_nop_pos = 0; /* 0 -> no noop started */
! 366:
! 367: /* to achieve keep alive, we send noop one byte at a time */
! 368: static void
! 369: send_noop_char(void)
! 370: {
! 371: #ifndef SMALL
! 372: if (debug)
! 373: fprintf(ttyout, "---> %c\n", noop[current_nop_pos]);
! 374: #endif /* !SMALL */
! 375: fputc(noop[current_nop_pos++], cout);
! 376: (void)fflush(cout);
! 377: if (current_nop_pos >= NOOP_LENGTH) {
! 378: full_noops_sent++;
! 379: current_nop_pos = 0;
1.34 itojun 380: }
1.104 ! florian 381: }
1.101 kmos 382:
1.104 ! florian 383: static void
! 384: may_reset_noop_timeout(void)
! 385: {
! 386: if (keep_alive_timeout != 0)
! 387: last_timestamp = time(NULL);
1.1 deraadt 388: }
389:
1.104 ! florian 390: static void
! 391: may_receive_noop_ack(void)
1.1 deraadt 392: {
1.104 ! florian 393: int i;
1.1 deraadt 394:
1.104 ! florian 395: if (cout == NULL) {
! 396: /* Lost connection; so just pretend we're fine. */
! 397: current_nop_pos = full_noops_sent = 0;
! 398: return;
1.1 deraadt 399: }
400:
1.104 ! florian 401: /* finish sending last incomplete noop */
! 402: if (current_nop_pos != 0) {
! 403: fputs(&(noop[current_nop_pos]), cout);
! 404: #ifndef SMALL
! 405: if (debug)
! 406: fprintf(ttyout, "---> %s\n", &(noop[current_nop_pos]));
! 407: #endif /* !SMALL */
! 408: (void)fflush(cout);
! 409: current_nop_pos = 0;
! 410: full_noops_sent++;
! 411: }
! 412: /* and get the replies */
! 413: for (i = 0; i < full_noops_sent; i++)
! 414: (void)getreply(0);
1.67 espie 415:
1.104 ! florian 416: full_noops_sent = 0;
1.67 espie 417: }
418:
1.104 ! florian 419: static void
! 420: may_send_noop_char(void)
1.67 espie 421: {
1.104 ! florian 422: if (keep_alive_timeout != 0) {
! 423: if (last_timestamp != 0) {
! 424: time_t t = time(NULL);
! 425:
! 426: if (t - last_timestamp >= keep_alive_timeout) {
! 427: last_timestamp = t;
! 428: send_noop_char();
! 429: }
! 430: } else {
! 431: last_timestamp = time(NULL);
! 432: }
! 433: }
! 434: }
1.101 kmos 435:
1.104 ! florian 436: char reply_string[BUFSIZ]; /* first line of previous reply */
1.67 espie 437:
1.101 kmos 438: int
1.104 ! florian 439: getreply(int expecteof)
1.67 espie 440: {
1.104 ! florian 441: char current_line[BUFSIZ]; /* last line of previous reply */
! 442: int c, n, lineno;
! 443: int dig;
! 444: int originalcode = 0, continuation = 0;
! 445: sig_t oldintr;
! 446: int pflag = 0;
! 447: char *cp, *pt = pasv;
! 448:
! 449: memset(current_line, 0, sizeof(current_line));
! 450: oldintr = signal(SIGINT, cmdabort);
! 451: for (lineno = 0 ;; lineno++) {
! 452: dig = n = code = 0;
! 453: cp = current_line;
! 454: while ((c = fgetc(cin)) != '\n') {
! 455: if (c == IAC) { /* handle telnet commands */
! 456: switch (c = fgetc(cin)) {
! 457: case WILL:
! 458: case WONT:
! 459: c = fgetc(cin);
! 460: fprintf(cout, "%c%c%c", IAC, DONT, c);
! 461: (void)fflush(cout);
! 462: break;
! 463: case DO:
! 464: case DONT:
! 465: c = fgetc(cin);
! 466: fprintf(cout, "%c%c%c", IAC, WONT, c);
! 467: (void)fflush(cout);
! 468: break;
! 469: default:
! 470: break;
! 471: }
! 472: continue;
! 473: }
! 474: dig++;
! 475: if (c == EOF) {
! 476: if (expecteof) {
! 477: (void)signal(SIGINT, oldintr);
! 478: code = 221;
! 479: return (0);
! 480: }
! 481: lostpeer();
! 482: if (verbose) {
! 483: fputs(
! 484: "421 Service not available, remote server has closed connection.\n", ttyout);
! 485: (void)fflush(ttyout);
! 486: }
! 487: code = 421;
! 488: return (4);
! 489: }
! 490: if (c != '\r' && (verbose > 0 ||
! 491: ((verbose > -1 && n == '5' && dig > 4) &&
! 492: (((!n && c < '5') || (n && n < '5'))
! 493: || !retry_connect)))) {
! 494: if (proxflag &&
! 495: (dig == 1 || (dig == 5 && verbose == 0)))
! 496: fprintf(ttyout, "%s:", hostname);
! 497: (void)putc(c, ttyout);
! 498: }
! 499: if (dig < 4 && isdigit(c))
! 500: code = code * 10 + (c - '0');
! 501: if (!pflag && (code == 227 || code == 228))
! 502: pflag = 1;
! 503: else if (!pflag && code == 229)
! 504: pflag = 100;
! 505: if (dig > 4 && pflag == 1 && isdigit(c))
! 506: pflag = 2;
! 507: if (pflag == 2) {
! 508: if (c != '\r' && c != ')') {
! 509: if (pt < &pasv[sizeof(pasv) - 1])
! 510: *pt++ = c;
! 511: } else {
! 512: *pt = '\0';
! 513: pflag = 3;
! 514: }
! 515: }
! 516: if (pflag == 100 && c == '(')
! 517: pflag = 2;
! 518: if (dig == 4 && c == '-') {
! 519: if (continuation)
! 520: code = 0;
! 521: continuation++;
! 522: }
! 523: if (n == 0)
! 524: n = c;
! 525: if (cp < ¤t_line[sizeof(current_line) - 1])
! 526: *cp++ = c;
! 527: }
! 528: if (verbose > 0 || ((verbose > -1 && n == '5') &&
! 529: (n < '5' || !retry_connect))) {
! 530: (void)putc(c, ttyout);
! 531: (void)fflush (ttyout);
! 532: }
! 533: if (lineno == 0) {
! 534: size_t len = cp - current_line;
! 535:
! 536: if (len > sizeof(reply_string))
! 537: len = sizeof(reply_string);
! 538:
! 539: (void)strlcpy(reply_string, current_line, len);
! 540: }
! 541: if (continuation && code != originalcode) {
! 542: if (originalcode == 0)
! 543: originalcode = code;
1.101 kmos 544: continue;
1.104 ! florian 545: }
! 546: *cp = '\0';
! 547: if (n != '1')
! 548: cpend = 0;
! 549: (void)signal(SIGINT, oldintr);
! 550: if (code == 421 || originalcode == 421)
! 551: lostpeer();
! 552: if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
! 553: (*oldintr)(SIGINT);
! 554: return (n - '0');
1.74 martynas 555: }
1.104 ! florian 556: }
1.67 espie 557:
1.104 ! florian 558: #ifndef SMALL
! 559: jmp_buf sendabort;
1.67 espie 560:
1.104 ! florian 561: /* ARGSUSED */
! 562: void
! 563: abortsend(int signo)
1.67 espie 564: {
1.104 ! florian 565: int save_errno = errno;
! 566: alarmtimer(0);
! 567: mflag = 0;
! 568: abrtflag = 0;
! 569: #define MSG "\nsend aborted\nwaiting for remote to finish abort.\n"
! 570: (void) write(fileno(ttyout), MSG, strlen(MSG));
! 571: #undef MSG
1.101 kmos 572:
1.104 ! florian 573: errno = save_errno;
! 574: longjmp(sendabort, 1);
1.67 espie 575: }
576:
1.104 ! florian 577: void
! 578: sendrequest(const char *cmd, const char *local, const char *remote,
! 579: int printnames)
1.1 deraadt 580: {
1.104 ! florian 581: struct stat st;
! 582: int c, d;
! 583: FILE * volatile fin, * volatile dout;
! 584: int (* volatile closefunc)(FILE *);
! 585: volatile sig_t oldinti, oldintr, oldintp;
! 586: volatile off_t hashbytes;
! 587: char * volatile lmode;
! 588: char buf[BUFSIZ], *bufp;
! 589: int oprogress, serrno;
! 590:
! 591: hashbytes = mark;
! 592: direction = "sent";
! 593: dout = NULL;
! 594: bytes = 0;
! 595: filesize = -1;
! 596: oprogress = progress;
! 597: if (verbose && printnames) {
! 598: if (local && *local != '-')
! 599: fprintf(ttyout, "local: %s ", local);
! 600: if (remote)
! 601: fprintf(ttyout, "remote: %s\n", remote);
! 602: }
! 603: if (proxy) {
! 604: proxtrans(cmd, local, remote);
! 605: return;
! 606: }
! 607: if (curtype != type)
! 608: changetype(type, 0);
! 609: closefunc = NULL;
! 610: oldintr = NULL;
! 611: oldintp = NULL;
! 612: oldinti = NULL;
! 613: lmode = "w";
! 614: if (setjmp(sendabort)) {
! 615: while (cpend) {
! 616: (void)getreply(0);
! 617: }
! 618: if (data >= 0) {
! 619: (void)close(data);
! 620: data = -1;
! 621: }
! 622: if (oldintr)
! 623: (void)signal(SIGINT, oldintr);
! 624: if (oldintp)
! 625: (void)signal(SIGPIPE, oldintp);
! 626: if (oldinti)
! 627: (void)signal(SIGINFO, oldinti);
! 628: progress = oprogress;
! 629: code = -1;
! 630: return;
! 631: }
! 632: oldintr = signal(SIGINT, abortsend);
! 633: oldinti = signal(SIGINFO, psummary);
! 634: if (strcmp(local, "-") == 0) {
! 635: fin = stdin;
! 636: if (progress == 1)
! 637: progress = 0;
! 638: } else if (*local == '|') {
! 639: oldintp = signal(SIGPIPE, SIG_IGN);
! 640: fin = popen(local + 1, "r");
! 641: if (fin == NULL) {
! 642: warn("%s", local + 1);
! 643: (void)signal(SIGINT, oldintr);
! 644: (void)signal(SIGPIPE, oldintp);
! 645: (void)signal(SIGINFO, oldinti);
! 646: code = -1;
! 647: return;
! 648: }
! 649: if (progress == 1)
! 650: progress = 0;
! 651: closefunc = pclose;
! 652: } else {
! 653: fin = fopen(local, "r");
! 654: if (fin == NULL) {
! 655: warn("local: %s", local);
! 656: (void)signal(SIGINT, oldintr);
! 657: (void)signal(SIGINFO, oldinti);
! 658: code = -1;
! 659: return;
! 660: }
! 661: closefunc = fclose;
! 662: if (fstat(fileno(fin), &st) < 0 ||
! 663: (st.st_mode & S_IFMT) != S_IFREG) {
! 664: fprintf(ttyout, "%s: not a plain file.\n", local);
! 665: (void)signal(SIGINT, oldintr);
! 666: (void)signal(SIGINFO, oldinti);
! 667: fclose(fin);
! 668: code = -1;
! 669: return;
! 670: }
! 671: filesize = st.st_size;
! 672: }
! 673: if (initconn()) {
! 674: (void)signal(SIGINT, oldintr);
! 675: (void)signal(SIGINFO, oldinti);
! 676: if (oldintp)
! 677: (void)signal(SIGPIPE, oldintp);
! 678: code = -1;
! 679: progress = oprogress;
! 680: if (closefunc != NULL)
! 681: (*closefunc)(fin);
! 682: return;
! 683: }
! 684: if (setjmp(sendabort))
! 685: goto abort;
1.101 kmos 686:
1.104 ! florian 687: if (restart_point &&
! 688: (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
! 689: int rc = -1;
! 690:
! 691: switch (curtype) {
! 692: case TYPE_A:
! 693: rc = fseeko(fin, restart_point, SEEK_SET);
! 694: break;
! 695: case TYPE_I:
! 696: if (lseek(fileno(fin), restart_point, SEEK_SET) != -1)
! 697: rc = 0;
! 698: break;
! 699: }
! 700: if (rc == -1) {
! 701: warn("local: %s", local);
! 702: progress = oprogress;
! 703: if (closefunc != NULL)
! 704: (*closefunc)(fin);
! 705: return;
! 706: }
! 707: if (command("REST %lld", (long long) restart_point)
! 708: != CONTINUE) {
! 709: progress = oprogress;
! 710: if (closefunc != NULL)
! 711: (*closefunc)(fin);
! 712: return;
! 713: }
! 714: lmode = "r+w";
! 715: }
! 716: if (remote) {
! 717: if (command("%s %s", cmd, remote) != PRELIM) {
! 718: (void)signal(SIGINT, oldintr);
! 719: (void)signal(SIGINFO, oldinti);
! 720: progress = oprogress;
! 721: if (oldintp)
! 722: (void)signal(SIGPIPE, oldintp);
! 723: if (closefunc != NULL)
! 724: (*closefunc)(fin);
! 725: return;
! 726: }
! 727: } else
! 728: if (command("%s", cmd) != PRELIM) {
! 729: (void)signal(SIGINT, oldintr);
! 730: (void)signal(SIGINFO, oldinti);
! 731: progress = oprogress;
! 732: if (oldintp)
! 733: (void)signal(SIGPIPE, oldintp);
! 734: if (closefunc != NULL)
! 735: (*closefunc)(fin);
! 736: return;
! 737: }
! 738: dout = dataconn(lmode);
! 739: if (dout == NULL)
! 740: goto abort;
! 741: progressmeter(-1, remote);
! 742: may_reset_noop_timeout();
! 743: oldintp = signal(SIGPIPE, SIG_IGN);
! 744: serrno = 0;
! 745: switch (curtype) {
! 746:
! 747: case TYPE_I:
! 748: d = 0;
! 749: while ((c = read(fileno(fin), buf, sizeof(buf))) > 0) {
! 750: may_send_noop_char();
! 751: bytes += c;
! 752: for (bufp = buf; c > 0; c -= d, bufp += d)
! 753: if ((d = write(fileno(dout), bufp, (size_t)c))
! 754: <= 0)
! 755: break;
! 756: if (hash && (!progress || filesize < 0) ) {
! 757: while (bytes >= hashbytes) {
! 758: (void)putc('#', ttyout);
! 759: hashbytes += mark;
! 760: }
! 761: (void)fflush(ttyout);
! 762: }
! 763: }
! 764: if (c == -1 || d == -1)
! 765: serrno = errno;
! 766: if (hash && (!progress || filesize < 0) && bytes > 0) {
! 767: if (bytes < mark)
! 768: (void)putc('#', ttyout);
! 769: (void)putc('\n', ttyout);
! 770: (void)fflush(ttyout);
! 771: }
! 772: if (c < 0)
! 773: warnc(serrno, "local: %s", local);
! 774: if (d < 0) {
! 775: if (serrno != EPIPE)
! 776: warnc(serrno, "netout");
! 777: bytes = -1;
! 778: }
! 779: break;
1.1 deraadt 780:
1.104 ! florian 781: case TYPE_A:
! 782: while ((c = fgetc(fin)) != EOF) {
! 783: may_send_noop_char();
! 784: if (c == '\n') {
! 785: while (hash && (!progress || filesize < 0) &&
! 786: (bytes >= hashbytes)) {
! 787: (void)putc('#', ttyout);
! 788: (void)fflush(ttyout);
! 789: hashbytes += mark;
! 790: }
! 791: if (ferror(dout))
! 792: break;
! 793: (void)putc('\r', dout);
! 794: bytes++;
! 795: }
! 796: (void)putc(c, dout);
! 797: bytes++;
! 798: }
! 799: if (ferror(fin) || ferror(dout))
! 800: serrno = errno;
! 801: if (hash && (!progress || filesize < 0)) {
! 802: if (bytes < hashbytes)
! 803: (void)putc('#', ttyout);
! 804: (void)putc('\n', ttyout);
! 805: (void)fflush(ttyout);
! 806: }
! 807: if (ferror(fin))
! 808: warnc(serrno, "local: %s", local);
! 809: if (ferror(dout)) {
! 810: if (errno != EPIPE)
! 811: warnc(serrno, "netout");
! 812: bytes = -1;
! 813: }
! 814: break;
! 815: }
! 816: progressmeter(1, NULL);
! 817: progress = oprogress;
! 818: if (closefunc != NULL)
! 819: (*closefunc)(fin);
! 820: (void)fclose(dout);
! 821: (void)getreply(0);
! 822: may_receive_noop_ack();
! 823: (void)signal(SIGINT, oldintr);
! 824: (void)signal(SIGINFO, oldinti);
! 825: if (oldintp)
! 826: (void)signal(SIGPIPE, oldintp);
! 827: if (bytes > 0)
! 828: ptransfer(0);
! 829: return;
! 830: abort:
! 831: (void)signal(SIGINT, oldintr);
! 832: (void)signal(SIGINFO, oldinti);
! 833: progress = oprogress;
! 834: if (oldintp)
! 835: (void)signal(SIGPIPE, oldintp);
! 836: if (!cpend) {
! 837: code = -1;
! 838: return;
1.101 kmos 839: }
1.104 ! florian 840: if (data >= 0) {
! 841: (void)close(data);
! 842: data = -1;
! 843: }
! 844: if (dout)
! 845: (void)fclose(dout);
! 846: (void)getreply(0);
! 847: code = -1;
! 848: if (closefunc != NULL && fin != NULL)
! 849: (*closefunc)(fin);
! 850: if (bytes > 0)
! 851: ptransfer(0);
! 852: }
! 853: #endif /* !SMALL */
1.87 deraadt 854:
1.104 ! florian 855: jmp_buf recvabort;
1.1 deraadt 856:
1.104 ! florian 857: /* ARGSUSED */
! 858: void
! 859: abortrecv(int signo)
1.1 deraadt 860: {
1.101 kmos 861:
1.104 ! florian 862: alarmtimer(0);
! 863: mflag = 0;
! 864: abrtflag = 0;
! 865: fputs("\nreceive aborted\nwaiting for remote to finish abort.\n", ttyout);
! 866: (void)fflush(ttyout);
! 867: longjmp(recvabort, 1);
1.1 deraadt 868: }
869:
1.104 ! florian 870: void
! 871: recvrequest(const char *cmd, const char * volatile local, const char *remote,
! 872: const char *lmode, int printnames, int ignorespecial)
1.1 deraadt 873: {
1.104 ! florian 874: FILE * volatile fout, * volatile din;
! 875: int (* volatile closefunc)(FILE *);
! 876: volatile sig_t oldinti, oldintr, oldintp;
! 877: int c, d, serrno;
! 878: volatile int is_retr, tcrflag, bare_lfs;
! 879: static size_t bufsize;
! 880: static char *buf;
! 881: volatile off_t hashbytes;
! 882: struct stat st;
! 883: time_t mtime;
! 884: int oprogress;
! 885: int opreserve;
! 886:
! 887: fout = NULL;
! 888: din = NULL;
! 889: oldinti = NULL;
! 890: hashbytes = mark;
! 891: direction = "received";
! 892: bytes = 0;
! 893: bare_lfs = 0;
! 894: filesize = -1;
! 895: oprogress = progress;
! 896: opreserve = preserve;
! 897: is_retr = strcmp(cmd, "RETR") == 0;
! 898: if (is_retr && verbose && printnames) {
! 899: if (local && (ignorespecial || *local != '-'))
! 900: fprintf(ttyout, "local: %s ", local);
! 901: if (remote)
! 902: fprintf(ttyout, "remote: %s\n", remote);
! 903: }
! 904: if (proxy && is_retr) {
! 905: proxtrans(cmd, local, remote);
! 906: return;
! 907: }
! 908: closefunc = NULL;
! 909: oldintr = NULL;
! 910: oldintp = NULL;
! 911: tcrflag = !crflag && is_retr;
! 912: if (setjmp(recvabort)) {
! 913: while (cpend) {
! 914: (void)getreply(0);
! 915: }
! 916: if (data >= 0) {
! 917: (void)close(data);
! 918: data = -1;
! 919: }
! 920: if (oldintr)
! 921: (void)signal(SIGINT, oldintr);
! 922: if (oldinti)
! 923: (void)signal(SIGINFO, oldinti);
! 924: progress = oprogress;
! 925: preserve = opreserve;
! 926: code = -1;
! 927: return;
! 928: }
! 929: oldintr = signal(SIGINT, abortrecv);
! 930: oldinti = signal(SIGINFO, psummary);
! 931: if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
! 932: if (access(local, W_OK) < 0) {
! 933: char *dir;
! 934:
! 935: if (errno != ENOENT && errno != EACCES) {
! 936: warn("local: %s", local);
! 937: (void)signal(SIGINT, oldintr);
! 938: (void)signal(SIGINFO, oldinti);
! 939: code = -1;
! 940: return;
! 941: }
! 942: dir = strrchr(local, '/');
! 943: if (dir != NULL)
! 944: *dir = 0;
! 945: d = access(dir == local ? "/" : dir ? local : ".", W_OK);
! 946: if (dir != NULL)
! 947: *dir = '/';
! 948: if (d < 0) {
! 949: warn("local: %s", local);
! 950: (void)signal(SIGINT, oldintr);
! 951: (void)signal(SIGINFO, oldinti);
! 952: code = -1;
! 953: return;
! 954: }
! 955: if (!runique && errno == EACCES &&
! 956: chmod(local, (S_IRUSR|S_IWUSR)) < 0) {
! 957: warn("local: %s", local);
! 958: (void)signal(SIGINT, oldintr);
! 959: (void)signal(SIGINFO, oldinti);
! 960: code = -1;
! 961: return;
! 962: }
! 963: if (runique && errno == EACCES &&
! 964: (local = gunique(local)) == NULL) {
! 965: (void)signal(SIGINT, oldintr);
! 966: (void)signal(SIGINFO, oldinti);
! 967: code = -1;
! 968: return;
! 969: }
! 970: }
! 971: else if (runique && (local = gunique(local)) == NULL) {
! 972: (void)signal(SIGINT, oldintr);
! 973: (void)signal(SIGINFO, oldinti);
! 974: code = -1;
! 975: return;
! 976: }
! 977: }
! 978: if (!is_retr) {
! 979: if (curtype != TYPE_A)
! 980: changetype(TYPE_A, 0);
! 981: } else {
! 982: if (curtype != type)
! 983: changetype(type, 0);
! 984: filesize = remotesize(remote, 0);
! 985: }
! 986: if (initconn()) {
! 987: (void)signal(SIGINT, oldintr);
! 988: (void)signal(SIGINFO, oldinti);
! 989: code = -1;
! 990: return;
1.1 deraadt 991: }
1.104 ! florian 992: if (setjmp(recvabort))
! 993: goto abort;
! 994: if (is_retr && restart_point &&
! 995: command("REST %lld", (long long) restart_point) != CONTINUE)
! 996: return;
! 997: if (remote) {
! 998: if (command("%s %s", cmd, remote) != PRELIM) {
! 999: (void)signal(SIGINT, oldintr);
! 1000: (void)signal(SIGINFO, oldinti);
! 1001: return;
! 1002: }
! 1003: } else {
! 1004: if (command("%s", cmd) != PRELIM) {
! 1005: (void)signal(SIGINT, oldintr);
! 1006: (void)signal(SIGINFO, oldinti);
! 1007: return;
! 1008: }
! 1009: }
! 1010: din = dataconn("r");
! 1011: if (din == NULL)
! 1012: goto abort;
! 1013: if (!ignorespecial && strcmp(local, "-") == 0) {
! 1014: fout = stdout;
! 1015: preserve = 0;
! 1016: } else if (!ignorespecial && *local == '|') {
! 1017: oldintp = signal(SIGPIPE, SIG_IGN);
! 1018: fout = popen(local + 1, "w");
! 1019: if (fout == NULL) {
! 1020: warn("%s", local+1);
! 1021: goto abort;
! 1022: }
! 1023: if (progress == 1)
! 1024: progress = 0;
! 1025: preserve = 0;
! 1026: closefunc = pclose;
! 1027: } else {
! 1028: fout = fopen(local, lmode);
! 1029: if (fout == NULL) {
! 1030: warn("local: %s", local);
! 1031: goto abort;
! 1032: }
! 1033: closefunc = fclose;
! 1034: }
! 1035: if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
! 1036: st.st_blksize = BUFSIZ;
! 1037: if (st.st_blksize > bufsize) {
! 1038: (void)free(buf);
! 1039: buf = malloc((unsigned)st.st_blksize);
! 1040: if (buf == NULL) {
! 1041: warn("malloc");
! 1042: bufsize = 0;
! 1043: goto abort;
! 1044: }
! 1045: bufsize = st.st_blksize;
! 1046: }
! 1047: if ((st.st_mode & S_IFMT) != S_IFREG) {
! 1048: if (progress == 1)
! 1049: progress = 0;
! 1050: preserve = 0;
! 1051: }
! 1052: progressmeter(-1, remote);
! 1053: may_reset_noop_timeout();
! 1054: serrno = 0;
! 1055: switch (curtype) {
! 1056:
! 1057: case TYPE_I:
! 1058: if (restart_point &&
! 1059: lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
! 1060: warn("local: %s", local);
! 1061: progress = oprogress;
! 1062: preserve = opreserve;
! 1063: if (closefunc != NULL)
! 1064: (*closefunc)(fout);
! 1065: return;
! 1066: }
! 1067: errno = d = 0;
! 1068: while ((c = read(fileno(din), buf, bufsize)) > 0) {
! 1069: ssize_t wr;
! 1070: size_t rd = c;
! 1071:
! 1072: may_send_noop_char();
! 1073: d = 0;
! 1074: do {
! 1075: wr = write(fileno(fout), buf + d, rd);
! 1076: if (wr == -1) {
! 1077: d = -1;
! 1078: break;
! 1079: }
! 1080: d += wr;
! 1081: rd -= wr;
! 1082: } while (d < c);
! 1083: if (rd != 0)
! 1084: break;
! 1085: bytes += c;
! 1086: if (hash && (!progress || filesize < 0)) {
! 1087: while (bytes >= hashbytes) {
! 1088: (void)putc('#', ttyout);
! 1089: hashbytes += mark;
! 1090: }
! 1091: (void)fflush(ttyout);
! 1092: }
! 1093: }
! 1094: if (c == -1 || d < c)
! 1095: serrno = errno;
! 1096: if (hash && (!progress || filesize < 0) && bytes > 0) {
! 1097: if (bytes < mark)
! 1098: (void)putc('#', ttyout);
! 1099: (void)putc('\n', ttyout);
! 1100: (void)fflush(ttyout);
! 1101: }
! 1102: if (c < 0) {
! 1103: if (serrno != EPIPE)
! 1104: warnc(serrno, "netin");
! 1105: bytes = -1;
! 1106: }
! 1107: if (d < c) {
! 1108: if (d < 0)
! 1109: warnc(serrno, "local: %s", local);
! 1110: else
! 1111: warnx("%s: short write", local);
! 1112: }
! 1113: break;
1.101 kmos 1114:
1.104 ! florian 1115: case TYPE_A:
! 1116: if (restart_point) {
! 1117: int i, n, ch;
! 1118:
! 1119: if (fseek(fout, 0L, SEEK_SET) < 0)
! 1120: goto done;
! 1121: n = restart_point;
! 1122: for (i = 0; i++ < n;) {
! 1123: if ((ch = fgetc(fout)) == EOF) {
! 1124: if (!ferror(fout))
! 1125: errno = 0;
! 1126: goto done;
! 1127: }
! 1128: if (ch == '\n')
! 1129: i++;
! 1130: }
! 1131: if (fseek(fout, 0L, SEEK_CUR) < 0) {
! 1132: done:
! 1133: if (errno)
! 1134: warn("local: %s", local);
! 1135: else
! 1136: warnx("local: %s", local);
! 1137: progress = oprogress;
! 1138: preserve = opreserve;
! 1139: if (closefunc != NULL)
! 1140: (*closefunc)(fout);
! 1141: return;
! 1142: }
! 1143: }
! 1144: while ((c = fgetc(din)) != EOF) {
! 1145: may_send_noop_char();
! 1146: if (c == '\n')
! 1147: bare_lfs++;
! 1148: while (c == '\r') {
! 1149: while (hash && (!progress || filesize < 0) &&
! 1150: (bytes >= hashbytes)) {
! 1151: (void)putc('#', ttyout);
! 1152: (void)fflush(ttyout);
! 1153: hashbytes += mark;
! 1154: }
! 1155: bytes++;
! 1156: if ((c = fgetc(din)) != '\n' || tcrflag) {
! 1157: if (ferror(fout))
! 1158: goto break2;
! 1159: (void)putc('\r', fout);
! 1160: if (c == '\0') {
! 1161: bytes++;
! 1162: goto contin2;
! 1163: }
! 1164: if (c == EOF)
! 1165: goto contin2;
! 1166: }
! 1167: }
! 1168: (void)putc(c, fout);
! 1169: bytes++;
! 1170: contin2: ;
! 1171: }
! 1172: break2:
! 1173: if (ferror(din) || ferror(fout))
! 1174: serrno = errno;
! 1175: if (bare_lfs) {
! 1176: fprintf(ttyout,
! 1177: "WARNING! %d bare linefeeds received in ASCII mode.\n", bare_lfs);
! 1178: fputs("File may not have transferred correctly.\n",
! 1179: ttyout);
! 1180: }
! 1181: if (hash && (!progress || filesize < 0)) {
! 1182: if (bytes < hashbytes)
! 1183: (void)putc('#', ttyout);
! 1184: (void)putc('\n', ttyout);
! 1185: (void)fflush(ttyout);
! 1186: }
! 1187: if (ferror(din)) {
! 1188: if (serrno != EPIPE)
! 1189: warnc(serrno, "netin");
! 1190: bytes = -1;
! 1191: }
! 1192: if (ferror(fout))
! 1193: warnc(serrno, "local: %s", local);
1.1 deraadt 1194: break;
1.104 ! florian 1195: }
! 1196: progressmeter(1, NULL);
! 1197: progress = oprogress;
! 1198: preserve = opreserve;
! 1199: if (closefunc != NULL)
! 1200: (*closefunc)(fout);
! 1201: (void)signal(SIGINT, oldintr);
! 1202: (void)signal(SIGINFO, oldinti);
! 1203: if (oldintp)
! 1204: (void)signal(SIGPIPE, oldintp);
! 1205: (void)fclose(din);
! 1206: (void)getreply(0);
! 1207: may_receive_noop_ack();
! 1208: if (bytes >= 0 && is_retr) {
! 1209: if (bytes > 0)
! 1210: ptransfer(0);
! 1211: if (preserve && (closefunc == fclose)) {
! 1212: mtime = remotemodtime(remote, 0);
! 1213: if (mtime != -1) {
! 1214: struct utimbuf ut;
! 1215:
! 1216: ut.actime = time(NULL);
! 1217: ut.modtime = mtime;
! 1218: if (utime(local, &ut) == -1)
! 1219: fprintf(ttyout,
! 1220: "Can't change modification time on %s to %s",
! 1221: local, asctime(localtime(&mtime)));
! 1222: }
! 1223: }
! 1224: }
! 1225: return;
! 1226:
! 1227: abort:
! 1228: /* abort using RFC959 recommended IP,SYNC sequence */
! 1229: progress = oprogress;
! 1230: preserve = opreserve;
! 1231: if (oldintp)
! 1232: (void)signal(SIGPIPE, oldintp);
! 1233: (void)signal(SIGINT, SIG_IGN);
! 1234: if (!cpend) {
! 1235: code = -1;
! 1236: (void)signal(SIGINT, oldintr);
! 1237: (void)signal(SIGINFO, oldinti);
! 1238: return;
1.1 deraadt 1239: }
1.101 kmos 1240:
1.104 ! florian 1241: abort_remote(din);
! 1242: code = -1;
! 1243: if (data >= 0) {
! 1244: (void)close(data);
! 1245: data = -1;
! 1246: }
! 1247: if (closefunc != NULL && fout != NULL)
! 1248: (*closefunc)(fout);
! 1249: if (din)
! 1250: (void)fclose(din);
! 1251: if (bytes > 0)
! 1252: ptransfer(0);
! 1253: (void)signal(SIGINT, oldintr);
! 1254: (void)signal(SIGINFO, oldinti);
! 1255: }
1.1 deraadt 1256:
1.104 ! florian 1257: /*
! 1258: * Need to start a listen on the data channel before we send the command,
! 1259: * otherwise the server's connect may fail.
! 1260: */
! 1261: int
! 1262: initconn(void)
! 1263: {
! 1264: char *p, *a;
! 1265: int result = ERROR, tmpno = 0;
! 1266: int on = 1;
! 1267: int error;
! 1268: u_int addr[16], port[2];
! 1269: u_int af, hal, pal;
! 1270: char *pasvcmd = NULL;
! 1271: socklen_t namelen;
! 1272: #ifndef SMALL
! 1273: struct addrinfo *ares;
! 1274: #endif
! 1275:
! 1276: if (myctladdr.sa.sa_family == AF_INET6
! 1277: && (IN6_IS_ADDR_LINKLOCAL(&myctladdr.sin6.sin6_addr)
! 1278: || IN6_IS_ADDR_SITELOCAL(&myctladdr.sin6.sin6_addr))) {
! 1279: warnx("use of scoped address can be troublesome");
! 1280: }
! 1281: #ifndef SMALL
! 1282: if (srcaddr) {
! 1283: struct addrinfo ahints;
! 1284:
! 1285: memset(&ahints, 0, sizeof(ahints));
! 1286: ahints.ai_family = family;
! 1287: ahints.ai_socktype = SOCK_STREAM;
! 1288: ahints.ai_flags |= AI_NUMERICHOST;
! 1289: ahints.ai_protocol = 0;
! 1290:
! 1291: error = getaddrinfo(srcaddr, NULL, &ahints, &ares);
! 1292: if (error) {
! 1293: warnx("%s: %s", srcaddr, gai_strerror(error));
! 1294: code = -1;
! 1295: return (0);
! 1296: }
! 1297: }
! 1298: #endif /* !SMALL */
! 1299: reinit:
! 1300: if (passivemode) {
! 1301: data_addr = myctladdr;
! 1302: data = socket(data_addr.sa.sa_family, SOCK_STREAM, 0);
! 1303: if (data < 0) {
! 1304: warn("socket");
! 1305: return (1);
! 1306: }
! 1307: #ifndef SMALL
! 1308: if (srcaddr) {
! 1309: if (bind(data, ares->ai_addr, ares->ai_addrlen) < 0) {
! 1310: warn("bind");
! 1311: close(data);
! 1312: return (1);
! 1313: }
! 1314: }
! 1315: if ((options & SO_DEBUG) &&
! 1316: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
! 1317: sizeof(on)) < 0)
! 1318: warn("setsockopt (ignored)");
! 1319: #endif /* !SMALL */
! 1320: switch (data_addr.sa.sa_family) {
! 1321: case AF_INET:
! 1322: if (epsv4 && !epsv4bad) {
! 1323: int ov;
! 1324: /* shut this command up in case it fails */
! 1325: ov = verbose;
! 1326: verbose = -1;
! 1327: result = command(pasvcmd = "EPSV");
! 1328: /*
! 1329: * now back to whatever verbosity we had before
! 1330: * and we can try PASV
! 1331: */
! 1332: verbose = ov;
! 1333: if (code / 10 == 22 && code != 229) {
! 1334: fputs(
! 1335: "wrong server: return code must be 229\n",
! 1336: ttyout);
! 1337: result = COMPLETE + 1;
! 1338: }
! 1339: if (result != COMPLETE) {
! 1340: epsv4bad = 1;
! 1341: #ifndef SMALL
! 1342: if (debug) {
! 1343: fputs(
! 1344: "disabling epsv4 for this connection\n",
! 1345: ttyout);
! 1346: }
! 1347: #endif /* !SMALL */
! 1348: }
! 1349: }
! 1350: if (result != COMPLETE)
! 1351: result = command(pasvcmd = "PASV");
! 1352: break;
! 1353: case AF_INET6:
! 1354: result = command(pasvcmd = "EPSV");
! 1355: if (code / 10 == 22 && code != 229) {
! 1356: fputs(
! 1357: "wrong server: return code must be 229\n",
! 1358: ttyout);
! 1359: result = COMPLETE + 1;
! 1360: }
! 1361: if (result != COMPLETE)
! 1362: result = command(pasvcmd = "LPSV");
! 1363: break;
! 1364: default:
! 1365: result = COMPLETE + 1;
! 1366: break;
! 1367: }
! 1368: if (result != COMPLETE) {
! 1369: if (activefallback) {
! 1370: (void)close(data);
! 1371: data = -1;
! 1372: passivemode = 0;
! 1373: activefallback = 0;
! 1374: goto reinit;
! 1375: }
! 1376: fputs("Passive mode refused.\n", ttyout);
! 1377: goto bad;
! 1378: }
! 1379:
! 1380: #define pack2(var, off) \
! 1381: (((var[(off) + 0] & 0xff) << 8) | ((var[(off) + 1] & 0xff) << 0))
! 1382: #define pack4(var, off) \
! 1383: (((var[(off) + 0] & 0xff) << 24) | ((var[(off) + 1] & 0xff) << 16) | \
! 1384: ((var[(off) + 2] & 0xff) << 8) | ((var[(off) + 3] & 0xff) << 0))
! 1385:
! 1386: /*
! 1387: * What we've got at this point is a string of comma separated
! 1388: * one-byte unsigned integer values, separated by commas.
! 1389: */
! 1390: if (!pasvcmd)
! 1391: goto bad;
! 1392: if (strcmp(pasvcmd, "PASV") == 0) {
! 1393: if (data_addr.sa.sa_family != AF_INET) {
! 1394: fputs(
! 1395: "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
! 1396: goto bad;
! 1397: }
! 1398: if (code / 10 == 22 && code != 227) {
! 1399: fputs("wrong server: return code must be 227\n",
! 1400: ttyout);
! 1401: goto bad;
! 1402: }
! 1403: error = sscanf(pasv, "%u,%u,%u,%u,%u,%u",
! 1404: &addr[0], &addr[1], &addr[2], &addr[3],
! 1405: &port[0], &port[1]);
! 1406: if (error != 6) {
! 1407: fputs(
! 1408: "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
! 1409: goto bad;
! 1410: }
! 1411: memset(&data_addr, 0, sizeof(data_addr));
! 1412: data_addr.sin.sin_family = AF_INET;
! 1413: data_addr.sin.sin_len = sizeof(struct sockaddr_in);
! 1414: data_addr.sin.sin_addr.s_addr =
! 1415: htonl(pack4(addr, 0));
! 1416: data_addr.sin.sin_port = htons(pack2(port, 0));
! 1417: } else if (strcmp(pasvcmd, "LPSV") == 0) {
! 1418: if (code / 10 == 22 && code != 228) {
! 1419: fputs("wrong server: return code must be 228\n",
! 1420: ttyout);
! 1421: goto bad;
! 1422: }
! 1423: switch (data_addr.sa.sa_family) {
! 1424: case AF_INET:
! 1425: error = sscanf(pasv,
! 1426: "%u,%u,%u,%u,%u,%u,%u,%u,%u",
! 1427: &af, &hal,
! 1428: &addr[0], &addr[1], &addr[2], &addr[3],
! 1429: &pal, &port[0], &port[1]);
! 1430: if (error != 9) {
! 1431: fputs(
! 1432: "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
! 1433: goto bad;
! 1434: }
! 1435: if (af != 4 || hal != 4 || pal != 2) {
! 1436: fputs(
! 1437: "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
! 1438: error = 1;
! 1439: goto bad;
! 1440: }
! 1441:
! 1442: memset(&data_addr, 0, sizeof(data_addr));
! 1443: data_addr.sin.sin_family = AF_INET;
! 1444: data_addr.sin.sin_len = sizeof(struct sockaddr_in);
! 1445: data_addr.sin.sin_addr.s_addr =
! 1446: htonl(pack4(addr, 0));
! 1447: data_addr.sin.sin_port = htons(pack2(port, 0));
! 1448: break;
! 1449: case AF_INET6:
! 1450: error = sscanf(pasv,
! 1451: "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
! 1452: &af, &hal,
! 1453: &addr[0], &addr[1], &addr[2], &addr[3],
! 1454: &addr[4], &addr[5], &addr[6], &addr[7],
! 1455: &addr[8], &addr[9], &addr[10],
! 1456: &addr[11], &addr[12], &addr[13],
! 1457: &addr[14], &addr[15],
! 1458: &pal, &port[0], &port[1]);
! 1459: if (error != 21) {
! 1460: fputs(
! 1461: "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
! 1462: goto bad;
! 1463: }
! 1464: if (af != 6 || hal != 16 || pal != 2) {
! 1465: fputs(
! 1466: "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
! 1467: goto bad;
! 1468: }
! 1469:
! 1470: memset(&data_addr, 0, sizeof(data_addr));
! 1471: data_addr.sin6.sin6_family = AF_INET6;
! 1472: data_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
! 1473: {
! 1474: u_int32_t *p32;
! 1475: p32 = (u_int32_t *)&data_addr.sin6.sin6_addr;
! 1476: p32[0] = htonl(pack4(addr, 0));
! 1477: p32[1] = htonl(pack4(addr, 4));
! 1478: p32[2] = htonl(pack4(addr, 8));
! 1479: p32[3] = htonl(pack4(addr, 12));
! 1480: }
! 1481: data_addr.sin6.sin6_port = htons(pack2(port, 0));
! 1482: break;
! 1483: default:
! 1484: fputs("Bad family!\n", ttyout);
! 1485: goto bad;
! 1486: }
! 1487: } else if (strcmp(pasvcmd, "EPSV") == 0) {
! 1488: char delim[4];
! 1489:
! 1490: port[0] = 0;
! 1491: if (code / 10 == 22 && code != 229) {
! 1492: fputs("wrong server: return code must be 229\n",
! 1493: ttyout);
! 1494: goto bad;
! 1495: }
! 1496: if (sscanf(pasv, "%c%c%c%d%c", &delim[0],
! 1497: &delim[1], &delim[2], &port[1],
! 1498: &delim[3]) != 5) {
! 1499: fputs("parse error!\n", ttyout);
! 1500: goto bad;
! 1501: }
! 1502: if (delim[0] != delim[1] || delim[0] != delim[2]
! 1503: || delim[0] != delim[3]) {
! 1504: fputs("parse error!\n", ttyout);
! 1505: goto bad;
! 1506: }
! 1507: data_addr = hisctladdr;
! 1508: data_addr.sin.sin_port = htons(port[1]);
! 1509: } else
! 1510: goto bad;
! 1511:
! 1512: for (error = connect(data, &data_addr.sa, data_addr.sa.sa_len);
! 1513: error != 0 && errno == EINTR;
! 1514: error = connect_wait(data))
! 1515: continue;
! 1516: if (error != 0) {
! 1517: if (activefallback) {
! 1518: (void)close(data);
! 1519: data = -1;
! 1520: passivemode = 0;
! 1521: activefallback = 0;
! 1522: goto reinit;
! 1523: }
! 1524: warn("connect");
! 1525: goto bad;
! 1526: }
! 1527: if (data_addr.sa.sa_family == AF_INET) {
! 1528: on = IPTOS_THROUGHPUT;
! 1529: if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
! 1530: sizeof(int)) < 0)
! 1531: warn("setsockopt TOS (ignored)");
! 1532: }
! 1533: return (0);
! 1534: }
! 1535:
! 1536: noport:
! 1537: data_addr = myctladdr;
! 1538: if (sendport)
! 1539: data_addr.sin.sin_port = 0; /* let system pick one */
! 1540: if (data != -1)
! 1541: (void)close(data);
! 1542: data = socket(data_addr.sa.sa_family, SOCK_STREAM, 0);
! 1543: if (data < 0) {
! 1544: warn("socket");
! 1545: if (tmpno)
! 1546: sendport = 1;
! 1547: return (1);
! 1548: }
! 1549: if (!sendport)
! 1550: if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
! 1551: sizeof(on)) < 0) {
! 1552: warn("setsockopt (reuse address)");
! 1553: goto bad;
! 1554: }
! 1555: switch (data_addr.sa.sa_family) {
1.49 jakob 1556: case AF_INET:
1557: on = IP_PORTRANGE_HIGH;
1.104 ! florian 1558: if (setsockopt(data, IPPROTO_IP, IP_PORTRANGE,
1.49 jakob 1559: (char *)&on, sizeof(on)) < 0)
1560: warn("setsockopt IP_PORTRANGE (ignored)");
1561: break;
1562: case AF_INET6:
1563: on = IPV6_PORTRANGE_HIGH;
1.104 ! florian 1564: if (setsockopt(data, IPPROTO_IPV6, IPV6_PORTRANGE,
1.49 jakob 1565: (char *)&on, sizeof(on)) < 0)
1566: warn("setsockopt IPV6_PORTRANGE (ignored)");
1567: break;
1568: }
1.104 ! florian 1569: if (bind(data, &data_addr.sa, data_addr.sa.sa_len) < 0) {
! 1570: warn("bind");
! 1571: goto bad;
! 1572: }
! 1573: #ifndef SMALL
! 1574: if (options & SO_DEBUG &&
! 1575: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
! 1576: sizeof(on)) < 0)
! 1577: warn("setsockopt (ignored)");
! 1578: #endif /* !SMALL */
! 1579: namelen = sizeof(data_addr);
! 1580: if (getsockname(data, &data_addr.sa, &namelen) < 0) {
! 1581: warn("getsockname");
! 1582: goto bad;
! 1583: }
! 1584: if (listen(data, 1) < 0)
! 1585: warn("listen");
! 1586:
! 1587: #define UC(b) (((int)b)&0xff)
! 1588:
! 1589: if (sendport) {
! 1590: char hname[NI_MAXHOST], pbuf[NI_MAXSERV];
! 1591: int af_tmp;
! 1592: union sockaddr_union tmp;
! 1593:
! 1594: tmp = data_addr;
! 1595: switch (tmp.sa.sa_family) {
! 1596: case AF_INET:
! 1597: if (!epsv4 || epsv4bad) {
! 1598: result = COMPLETE +1;
! 1599: break;
! 1600: }
! 1601: /*FALLTHROUGH*/
! 1602: case AF_INET6:
! 1603: if (tmp.sa.sa_family == AF_INET6)
! 1604: tmp.sin6.sin6_scope_id = 0;
! 1605: af_tmp = (tmp.sa.sa_family == AF_INET) ? 1 : 2;
! 1606: if (getnameinfo(&tmp.sa, tmp.sa.sa_len, hname,
! 1607: sizeof(hname), pbuf, sizeof(pbuf),
! 1608: NI_NUMERICHOST | NI_NUMERICSERV)) {
! 1609: result = ERROR;
! 1610: } else {
! 1611: result = command("EPRT |%d|%s|%s|",
! 1612: af_tmp, hname, pbuf);
! 1613: if (result != COMPLETE) {
! 1614: epsv4bad = 1;
! 1615: #ifndef SMALL
! 1616: if (debug) {
! 1617: fputs(
! 1618: "disabling epsv4 for this connection\n",
! 1619: ttyout);
! 1620: }
! 1621: #endif /* !SMALL */
! 1622: }
! 1623: }
! 1624: break;
! 1625: default:
! 1626: result = COMPLETE + 1;
! 1627: break;
! 1628: }
! 1629: if (result == COMPLETE)
! 1630: goto skip_port;
! 1631:
! 1632: switch (data_addr.sa.sa_family) {
! 1633: case AF_INET:
! 1634: a = (char *)&data_addr.sin.sin_addr;
! 1635: p = (char *)&data_addr.sin.sin_port;
! 1636: result = command("PORT %d,%d,%d,%d,%d,%d",
! 1637: UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
! 1638: UC(p[0]), UC(p[1]));
! 1639: break;
! 1640: case AF_INET6:
! 1641: a = (char *)&data_addr.sin6.sin6_addr;
! 1642: p = (char *)&data_addr.sin6.sin6_port;
! 1643: result = command(
! 1644: "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
! 1645: 6, 16,
! 1646: UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
! 1647: UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]),
! 1648: UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]),
! 1649: UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]),
! 1650: 2, UC(p[0]), UC(p[1]));
! 1651: break;
! 1652: default:
! 1653: result = COMPLETE + 1; /* xxx */
! 1654: }
! 1655: skip_port:
! 1656:
! 1657: if (result == ERROR && sendport == -1) {
! 1658: sendport = 0;
! 1659: tmpno = 1;
! 1660: goto noport;
! 1661: }
! 1662: return (result != COMPLETE);
! 1663: }
! 1664: if (tmpno)
! 1665: sendport = 1;
! 1666: if (data_addr.sa.sa_family == AF_INET) {
! 1667: on = IPTOS_THROUGHPUT;
! 1668: if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
! 1669: sizeof(int)) < 0)
! 1670: warn("setsockopt TOS (ignored)");
! 1671: }
! 1672: return (0);
! 1673: bad:
! 1674: (void)close(data), data = -1;
! 1675: if (tmpno)
! 1676: sendport = 1;
! 1677: return (1);
! 1678: }
1.1 deraadt 1679:
1.104 ! florian 1680: FILE *
! 1681: dataconn(const char *lmode)
! 1682: {
! 1683: union sockaddr_union from;
! 1684: socklen_t fromlen = myctladdr.sa.sa_len;
! 1685: int s;
! 1686:
! 1687: if (passivemode)
! 1688: return (fdopen(data, lmode));
! 1689:
! 1690: s = accept(data, &from.sa, &fromlen);
! 1691: if (s < 0) {
! 1692: warn("accept");
! 1693: (void)close(data), data = -1;
! 1694: return (NULL);
! 1695: }
! 1696: (void)close(data);
! 1697: data = s;
! 1698: if (from.sa.sa_family == AF_INET) {
! 1699: int tos = IPTOS_THROUGHPUT;
! 1700: if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
! 1701: sizeof(int)) < 0) {
! 1702: warn("setsockopt TOS (ignored)");
! 1703: }
1.34 itojun 1704: }
1.104 ! florian 1705: return (fdopen(data, lmode));
! 1706: }
1.1 deraadt 1707:
1.104 ! florian 1708: /* ARGSUSED */
! 1709: void
! 1710: psummary(int signo)
! 1711: {
! 1712: int save_errno = errno;
1.10 millert 1713:
1.104 ! florian 1714: if (bytes > 0)
! 1715: ptransfer(1);
! 1716: errno = save_errno;
! 1717: }
1.1 deraadt 1718:
1.104 ! florian 1719: /* ARGSUSED */
! 1720: void
! 1721: psabort(int signo)
! 1722: {
1.1 deraadt 1723:
1.104 ! florian 1724: alarmtimer(0);
! 1725: abrtflag++;
! 1726: }
1.1 deraadt 1727:
1.104 ! florian 1728: void
! 1729: pswitch(int flag)
! 1730: {
! 1731: sig_t oldintr;
! 1732: static struct comvars {
! 1733: int connect;
! 1734: char name[HOST_NAME_MAX+1];
! 1735: union sockaddr_union mctl;
! 1736: union sockaddr_union hctl;
! 1737: FILE *in;
! 1738: FILE *out;
! 1739: int tpe;
! 1740: int curtpe;
! 1741: int cpnd;
! 1742: int sunqe;
! 1743: int runqe;
! 1744: int mcse;
! 1745: int ntflg;
! 1746: char nti[17];
! 1747: char nto[17];
! 1748: int mapflg;
! 1749: char mi[PATH_MAX];
! 1750: char mo[PATH_MAX];
! 1751: } proxstruct, tmpstruct;
! 1752: struct comvars *ip, *op;
! 1753:
! 1754: abrtflag = 0;
! 1755: oldintr = signal(SIGINT, psabort);
! 1756: if (flag) {
! 1757: if (proxy)
! 1758: return;
! 1759: ip = &tmpstruct;
! 1760: op = &proxstruct;
! 1761: proxy++;
! 1762: } else {
! 1763: if (!proxy)
! 1764: return;
! 1765: ip = &proxstruct;
! 1766: op = &tmpstruct;
! 1767: proxy = 0;
! 1768: }
! 1769: ip->connect = connected;
! 1770: connected = op->connect;
! 1771: if (hostname) {
! 1772: (void)strlcpy(ip->name, hostname, sizeof(ip->name));
! 1773: } else
! 1774: ip->name[0] = '\0';
! 1775: hostname = op->name;
! 1776: ip->hctl = hisctladdr;
! 1777: hisctladdr = op->hctl;
! 1778: ip->mctl = myctladdr;
! 1779: myctladdr = op->mctl;
! 1780: ip->in = cin;
! 1781: cin = op->in;
! 1782: ip->out = cout;
! 1783: cout = op->out;
! 1784: ip->tpe = type;
! 1785: type = op->tpe;
! 1786: ip->curtpe = curtype;
! 1787: curtype = op->curtpe;
! 1788: ip->cpnd = cpend;
! 1789: cpend = op->cpnd;
! 1790: ip->sunqe = sunique;
! 1791: sunique = op->sunqe;
! 1792: ip->runqe = runique;
! 1793: runique = op->runqe;
! 1794: ip->mcse = mcase;
! 1795: mcase = op->mcse;
! 1796: ip->ntflg = ntflag;
! 1797: ntflag = op->ntflg;
! 1798: (void)strlcpy(ip->nti, ntin, sizeof(ip->nti));
! 1799: (void)strlcpy(ntin, op->nti, sizeof ntin);
! 1800: (void)strlcpy(ip->nto, ntout, sizeof(ip->nto));
! 1801: (void)strlcpy(ntout, op->nto, sizeof ntout);
! 1802: ip->mapflg = mapflag;
! 1803: mapflag = op->mapflg;
! 1804: (void)strlcpy(ip->mi, mapin, sizeof(ip->mi));
! 1805: (void)strlcpy(mapin, op->mi, sizeof mapin);
! 1806: (void)strlcpy(ip->mo, mapout, sizeof(ip->mo));
! 1807: (void)strlcpy(mapout, op->mo, sizeof mapout);
! 1808: (void)signal(SIGINT, oldintr);
! 1809: if (abrtflag) {
! 1810: abrtflag = 0;
! 1811: (*oldintr)(SIGINT);
1.1 deraadt 1812: }
1.104 ! florian 1813: }
! 1814:
! 1815: /* ARGSUSED */
! 1816: void
! 1817: abortpt(int signo)
! 1818: {
1.101 kmos 1819:
1.104 ! florian 1820: alarmtimer(0);
! 1821: putc('\n', ttyout);
! 1822: (void)fflush(ttyout);
! 1823: ptabflg++;
! 1824: mflag = 0;
! 1825: abrtflag = 0;
! 1826: longjmp(ptabort, 1);
1.1 deraadt 1827: }
1828:
1.104 ! florian 1829: void
! 1830: proxtrans(const char *cmd, const char *local, const char *remote)
1.1 deraadt 1831: {
1.104 ! florian 1832: volatile sig_t oldintr;
! 1833: int prox_type, nfnd;
! 1834: volatile int secndflag;
! 1835: char * volatile cmd2;
! 1836: struct pollfd pfd[1];
! 1837:
! 1838: oldintr = NULL;
! 1839: secndflag = 0;
! 1840: if (strcmp(cmd, "RETR"))
! 1841: cmd2 = "RETR";
! 1842: else
! 1843: cmd2 = runique ? "STOU" : "STOR";
! 1844: if ((prox_type = type) == 0) {
! 1845: if (unix_server && unix_proxy)
! 1846: prox_type = TYPE_I;
! 1847: else
! 1848: prox_type = TYPE_A;
! 1849: }
! 1850: if (curtype != prox_type)
! 1851: changetype(prox_type, 1);
! 1852: if (command("PASV") != COMPLETE) {
! 1853: fputs("proxy server does not support third party transfers.\n",
! 1854: ttyout);
! 1855: return;
! 1856: }
! 1857: pswitch(0);
! 1858: if (!connected) {
! 1859: fputs("No primary connection.\n", ttyout);
! 1860: pswitch(1);
! 1861: code = -1;
! 1862: return;
! 1863: }
! 1864: if (curtype != prox_type)
! 1865: changetype(prox_type, 1);
! 1866: if (command("PORT %s", pasv) != COMPLETE) {
! 1867: pswitch(1);
! 1868: return;
! 1869: }
! 1870: if (setjmp(ptabort))
! 1871: goto abort;
! 1872: oldintr = signal(SIGINT, abortpt);
! 1873: if (command("%s %s", cmd, remote) != PRELIM) {
! 1874: (void)signal(SIGINT, oldintr);
! 1875: pswitch(1);
! 1876: return;
! 1877: }
! 1878: sleep(2);
! 1879: pswitch(1);
! 1880: secndflag++;
! 1881: if (command("%s %s", cmd2, local) != PRELIM)
! 1882: goto abort;
! 1883: ptflag++;
! 1884: (void)getreply(0);
! 1885: pswitch(0);
! 1886: (void)getreply(0);
! 1887: (void)signal(SIGINT, oldintr);
! 1888: pswitch(1);
! 1889: ptflag = 0;
! 1890: fprintf(ttyout, "local: %s remote: %s\n", local, remote);
! 1891: return;
! 1892: abort:
! 1893: (void)signal(SIGINT, SIG_IGN);
! 1894: ptflag = 0;
! 1895: if (strcmp(cmd, "RETR") && !proxy)
! 1896: pswitch(1);
! 1897: else if (!strcmp(cmd, "RETR") && proxy)
! 1898: pswitch(0);
! 1899: if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
! 1900: if (command("%s %s", cmd2, local) != PRELIM) {
! 1901: pswitch(0);
! 1902: if (cpend)
! 1903: abort_remote(NULL);
! 1904: }
! 1905: pswitch(1);
! 1906: if (ptabflg)
! 1907: code = -1;
! 1908: (void)signal(SIGINT, oldintr);
! 1909: return;
! 1910: }
! 1911: if (cpend)
! 1912: abort_remote(NULL);
! 1913: pswitch(!proxy);
! 1914: if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
! 1915: if (command("%s %s", cmd2, local) != PRELIM) {
! 1916: pswitch(0);
! 1917: if (cpend)
! 1918: abort_remote(NULL);
! 1919: pswitch(1);
! 1920: if (ptabflg)
! 1921: code = -1;
! 1922: (void)signal(SIGINT, oldintr);
! 1923: return;
! 1924: }
! 1925: }
! 1926: if (cpend)
! 1927: abort_remote(NULL);
! 1928: pswitch(!proxy);
! 1929: if (cpend) {
! 1930: pfd[0].fd = fileno(cin);
! 1931: pfd[0].events = POLLIN;
! 1932: if ((nfnd = poll(pfd, 1, 10 * 1000)) <= 0) {
! 1933: if (nfnd < 0)
! 1934: warn("abort");
! 1935: if (ptabflg)
! 1936: code = -1;
! 1937: lostpeer();
! 1938: }
! 1939: (void)getreply(0);
! 1940: (void)getreply(0);
! 1941: }
! 1942: if (proxy)
! 1943: pswitch(0);
! 1944: pswitch(1);
! 1945: if (ptabflg)
! 1946: code = -1;
! 1947: (void)signal(SIGINT, oldintr);
! 1948: }
1.1 deraadt 1949:
1.104 ! florian 1950: #ifndef SMALL
! 1951: /* ARGSUSED */
! 1952: void
! 1953: reset(int argc, char *argv[])
! 1954: {
! 1955: struct pollfd pfd[1];
! 1956: int nfnd = 1;
1.1 deraadt 1957:
1.104 ! florian 1958: pfd[0].fd = fileno(cin);
! 1959: pfd[0].events = POLLIN;
! 1960: while (nfnd > 0) {
! 1961: if ((nfnd = poll(pfd, 1, 0)) < 0) {
! 1962: warn("reset");
! 1963: code = -1;
! 1964: lostpeer();
! 1965: } else if (nfnd) {
! 1966: (void)getreply(0);
! 1967: }
1.1 deraadt 1968: }
1.104 ! florian 1969: }
! 1970: #endif
1.101 kmos 1971:
1.104 ! florian 1972: char *
! 1973: gunique(const char *local)
! 1974: {
! 1975: static char new[PATH_MAX];
! 1976: char *cp = strrchr(local, '/');
! 1977: int d, count=0;
! 1978: char ext = '1';
! 1979:
! 1980: if (cp)
! 1981: *cp = '\0';
! 1982: d = access(cp == local ? "/" : cp ? local : ".", W_OK);
! 1983: if (cp)
! 1984: *cp = '/';
! 1985: if (d < 0) {
! 1986: warn("local: %s", local);
! 1987: return ((char *) 0);
! 1988: }
! 1989: (void)strlcpy(new, local, sizeof new);
! 1990: cp = new + strlen(new);
! 1991: *cp++ = '.';
! 1992: while (!d) {
! 1993: if (++count == 100) {
! 1994: fputs("runique: can't find unique file name.\n", ttyout);
! 1995: return ((char *) 0);
! 1996: }
! 1997: *cp++ = ext;
! 1998: *cp = '\0';
! 1999: if (ext == '9')
! 2000: ext = '0';
! 2001: else
! 2002: ext++;
! 2003: if ((d = access(new, F_OK)) < 0)
! 2004: break;
! 2005: if (ext != '0')
! 2006: cp--;
! 2007: else if (*(cp - 2) == '.')
! 2008: *(cp - 1) = '1';
! 2009: else {
! 2010: *(cp - 2) = *(cp - 2) + 1;
! 2011: cp--;
! 2012: }
1.1 deraadt 2013: }
1.104 ! florian 2014: return (new);
! 2015: }
1.101 kmos 2016:
1.104 ! florian 2017: jmp_buf forceabort;
1.101 kmos 2018:
1.104 ! florian 2019: /* ARGSUSED */
! 2020: static void
! 2021: abortforce(int signo)
! 2022: {
! 2023: int save_errno = errno;
1.101 kmos 2024:
1.104 ! florian 2025: #define MSG "Forced abort. The connection will be closed.\n"
! 2026: (void) write(fileno(ttyout), MSG, strlen(MSG));
! 2027: #undef MSG
1.1 deraadt 2028:
1.104 ! florian 2029: errno = save_errno;
! 2030: longjmp(forceabort, 1);
! 2031: }
1.1 deraadt 2032:
1.104 ! florian 2033: void
! 2034: abort_remote(FILE *din)
! 2035: {
! 2036: char buf[BUFSIZ];
! 2037: nfds_t nfds;
! 2038: int nfnd;
! 2039: struct pollfd pfd[2];
! 2040: sig_t oldintr;
! 2041:
! 2042: if (cout == NULL || setjmp(forceabort)) {
! 2043: if (cout)
! 2044: fclose(cout);
! 2045: warnx("Lost control connection for abort.");
! 2046: if (ptabflg)
! 2047: code = -1;
! 2048: lostpeer();
! 2049: return;
1.1 deraadt 2050: }
2051:
1.104 ! florian 2052: oldintr = signal(SIGINT, abortforce);
1.94 krw 2053:
1.104 ! florian 2054: /*
! 2055: * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
! 2056: * after urgent byte rather than before as is protocol now
! 2057: */
! 2058: snprintf(buf, sizeof buf, "%c%c%c", IAC, IP, IAC);
! 2059: if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
! 2060: warn("abort");
! 2061: fprintf(cout, "%cABOR\r\n", DM);
! 2062: (void)fflush(cout);
! 2063: pfd[0].fd = fileno(cin);
! 2064: pfd[0].events = POLLIN;
! 2065: nfds = 1;
! 2066: if (din) {
! 2067: pfd[1].fd = fileno(din);
! 2068: pfd[1].events = POLLIN;
! 2069: nfds++;
! 2070: }
! 2071: if ((nfnd = poll(pfd, nfds, 10 * 1000)) <= 0) {
! 2072: if (nfnd < 0)
! 2073: warn("abort");
! 2074: if (ptabflg)
! 2075: code = -1;
! 2076: lostpeer();
! 2077: }
! 2078: if (din && (pfd[1].revents & POLLIN)) {
! 2079: while (read(fileno(din), buf, BUFSIZ) > 0)
! 2080: /* LOOP */;
! 2081: }
! 2082: if (getreply(0) == ERROR && code == 552) {
! 2083: /* 552 needed for nic style abort */
! 2084: (void)getreply(0);
1.13 millert 2085: }
1.104 ! florian 2086: (void)getreply(0);
! 2087: (void)signal(SIGINT, oldintr);
1.1 deraadt 2088: }