ftp.c revision 72445
155682Smarkm/* 255682Smarkm * Copyright (c) 1985, 1989, 1993, 1994 355682Smarkm * The Regents of the University of California. All rights reserved. 455682Smarkm * 555682Smarkm * Redistribution and use in source and binary forms, with or without 655682Smarkm * modification, are permitted provided that the following conditions 755682Smarkm * are met: 855682Smarkm * 1. Redistributions of source code must retain the above copyright 955682Smarkm * notice, this list of conditions and the following disclaimer. 1055682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer in the 1255682Smarkm * documentation and/or other materials provided with the distribution. 1355682Smarkm * 3. All advertising materials mentioning features or use of this software 1455682Smarkm * must display the following acknowledgement: 1555682Smarkm * This product includes software developed by the University of 1655682Smarkm * California, Berkeley and its contributors. 1755682Smarkm * 4. Neither the name of the University nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "ftp_locl.h" 3572445SassarRCSID ("$Id: ftp.c,v 1.69 2000/10/08 13:15:33 assar Exp $"); 3655682Smarkm 3755682Smarkmstruct sockaddr_storage hisctladdr_ss; 3855682Smarkmstruct sockaddr *hisctladdr = (struct sockaddr *)&hisctladdr_ss; 3955682Smarkmstruct sockaddr_storage data_addr_ss; 4055682Smarkmstruct sockaddr *data_addr = (struct sockaddr *)&data_addr_ss; 4155682Smarkmstruct sockaddr_storage myctladdr_ss; 4255682Smarkmstruct sockaddr *myctladdr = (struct sockaddr *)&myctladdr_ss; 4355682Smarkmint data = -1; 4455682Smarkmint abrtflag = 0; 4555682Smarkmjmp_buf ptabort; 4655682Smarkmint ptabflg; 4755682Smarkmint ptflag = 0; 4855682Smarkmoff_t restart_point = 0; 4955682Smarkm 5055682Smarkm 5155682SmarkmFILE *cin, *cout; 5255682Smarkm 5355682Smarkmtypedef void (*sighand) (int); 5455682Smarkm 5555682Smarkmchar * 5655682Smarkmhookup (const char *host, int port) 5755682Smarkm{ 5855682Smarkm static char hostnamebuf[MaxHostNameLen]; 5955682Smarkm struct addrinfo *ai, *a; 6055682Smarkm struct addrinfo hints; 6155682Smarkm int error; 6255682Smarkm char portstr[NI_MAXSERV]; 6372445Sassar socklen_t len; 6455682Smarkm int s; 6555682Smarkm 6655682Smarkm memset (&hints, 0, sizeof(hints)); 6755682Smarkm hints.ai_socktype = SOCK_STREAM; 6855682Smarkm hints.ai_protocol = IPPROTO_TCP; 6955682Smarkm hints.ai_flags = AI_CANONNAME; 7055682Smarkm 7155682Smarkm snprintf (portstr, sizeof(portstr), "%u", ntohs(port)); 7255682Smarkm 7355682Smarkm error = getaddrinfo (host, portstr, &hints, &ai); 7455682Smarkm if (error) { 7555682Smarkm warnx ("%s: %s", host, gai_strerror(error)); 7655682Smarkm code = -1; 7755682Smarkm return NULL; 7855682Smarkm } 7955682Smarkm strlcpy (hostnamebuf, host, sizeof(hostnamebuf)); 8055682Smarkm hostname = hostnamebuf; 8155682Smarkm 8255682Smarkm for (a = ai; a != NULL; a = a->ai_next) { 8355682Smarkm s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 8455682Smarkm if (s < 0) 8555682Smarkm continue; 8655682Smarkm 8755682Smarkm if (a->ai_canonname != NULL) 8855682Smarkm strlcpy (hostnamebuf, a->ai_canonname, sizeof(hostnamebuf)); 8955682Smarkm 9055682Smarkm memcpy (hisctladdr, a->ai_addr, a->ai_addrlen); 9155682Smarkm 9255682Smarkm error = connect (s, a->ai_addr, a->ai_addrlen); 9355682Smarkm if (error < 0) { 9455682Smarkm char addrstr[256]; 9555682Smarkm 9655682Smarkm if (getnameinfo (a->ai_addr, a->ai_addrlen, 9755682Smarkm addrstr, sizeof(addrstr), 9855682Smarkm NULL, 0, NI_NUMERICHOST) != 0) 9955682Smarkm strlcpy (addrstr, "unknown address", sizeof(addrstr)); 10055682Smarkm 10155682Smarkm warn ("connect %s", addrstr); 10255682Smarkm close (s); 10355682Smarkm continue; 10455682Smarkm } 10555682Smarkm break; 10655682Smarkm } 10755682Smarkm freeaddrinfo (ai); 10855682Smarkm if (error < 0) { 10955682Smarkm warnx ("failed to contact %s", host); 11055682Smarkm code = -1; 11155682Smarkm return NULL; 11255682Smarkm } 11355682Smarkm 11455682Smarkm len = sizeof(myctladdr_ss); 11555682Smarkm if (getsockname (s, myctladdr, &len) < 0) { 11655682Smarkm warn ("getsockname"); 11755682Smarkm code = -1; 11855682Smarkm close (s); 11955682Smarkm return NULL; 12055682Smarkm } 12155682Smarkm#ifdef IPTOS_LOWDELAY 12255682Smarkm socket_set_tos (s, IPTOS_LOWDELAY); 12355682Smarkm#endif 12455682Smarkm cin = fdopen (s, "r"); 12555682Smarkm cout = fdopen (s, "w"); 12655682Smarkm if (cin == NULL || cout == NULL) { 12755682Smarkm warnx ("fdopen failed."); 12855682Smarkm if (cin) 12955682Smarkm fclose (cin); 13055682Smarkm if (cout) 13155682Smarkm fclose (cout); 13255682Smarkm code = -1; 13355682Smarkm goto bad; 13455682Smarkm } 13555682Smarkm if (verbose) 13655682Smarkm printf ("Connected to %s.\n", hostname); 13755682Smarkm if (getreply (0) > 2) { /* read startup message from server */ 13855682Smarkm if (cin) 13955682Smarkm fclose (cin); 14055682Smarkm if (cout) 14155682Smarkm fclose (cout); 14255682Smarkm code = -1; 14355682Smarkm goto bad; 14455682Smarkm } 14555682Smarkm#if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT) 14655682Smarkm { 14755682Smarkm int on = 1; 14855682Smarkm 14955682Smarkm if (setsockopt (s, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof (on)) 15055682Smarkm < 0 && debug) { 15155682Smarkm warn ("setsockopt"); 15255682Smarkm } 15355682Smarkm } 15455682Smarkm#endif /* SO_OOBINLINE */ 15555682Smarkm 15655682Smarkm return (hostname); 15755682Smarkmbad: 15855682Smarkm close (s); 15955682Smarkm return NULL; 16055682Smarkm} 16155682Smarkm 16255682Smarkmint 16355682Smarkmlogin (char *host) 16455682Smarkm{ 16555682Smarkm char tmp[80]; 16655682Smarkm char defaultpass[128]; 16755682Smarkm char *user, *pass, *acct; 16855682Smarkm int n, aflag = 0; 16955682Smarkm 17055682Smarkm char *myname = NULL; 17155682Smarkm struct passwd *pw = k_getpwuid(getuid()); 17255682Smarkm 17355682Smarkm if (pw != NULL) 17455682Smarkm myname = pw->pw_name; 17555682Smarkm 17655682Smarkm user = pass = acct = 0; 17755682Smarkm 17855682Smarkm if(sec_login(host)) 17955682Smarkm printf("\n*** Using plaintext user and password ***\n\n"); 18055682Smarkm else{ 18155682Smarkm printf("Authentication successful.\n\n"); 18255682Smarkm } 18355682Smarkm 18455682Smarkm if (ruserpass (host, &user, &pass, &acct) < 0) { 18555682Smarkm code = -1; 18655682Smarkm return (0); 18755682Smarkm } 18855682Smarkm while (user == NULL) { 18955682Smarkm if (myname) 19055682Smarkm printf ("Name (%s:%s): ", host, myname); 19155682Smarkm else 19255682Smarkm printf ("Name (%s): ", host); 19372445Sassar *tmp = '\0'; 19472445Sassar if (fgets (tmp, sizeof (tmp) - 1, stdin) != NULL) 19572445Sassar tmp[strlen (tmp) - 1] = '\0'; 19655682Smarkm if (*tmp == '\0') 19755682Smarkm user = myname; 19855682Smarkm else 19955682Smarkm user = tmp; 20055682Smarkm } 20155682Smarkm strlcpy(username, user, sizeof(username)); 20255682Smarkm n = command("USER %s", user); 20372445Sassar if (n == COMPLETE) 20472445Sassar n = command("PASS dummy"); /* DK: Compatibility with gssftp daemon */ 20572445Sassar else if(n == CONTINUE) { 20672445Sassar if (pass == NULL) { 20755682Smarkm char prompt[128]; 20855682Smarkm if(myname && 20972445Sassar (!strcmp(user, "ftp") || !strcmp(user, "anonymous"))) { 21055682Smarkm snprintf(defaultpass, sizeof(defaultpass), 21155682Smarkm "%s@%s", myname, mydomain); 21255682Smarkm snprintf(prompt, sizeof(prompt), 21355682Smarkm "Password (%s): ", defaultpass); 21472445Sassar } else if (sec_complete) { 21572445Sassar pass = myname; 21672445Sassar } else { 21755682Smarkm *defaultpass = '\0'; 21855682Smarkm snprintf(prompt, sizeof(prompt), "Password: "); 21955682Smarkm } 22072445Sassar if (pass == NULL) { 22172445Sassar pass = defaultpass; 22272445Sassar des_read_pw_string (tmp, sizeof (tmp), prompt, 0); 22372445Sassar if (tmp[0]) 22472445Sassar pass = tmp; 22572445Sassar } 22655682Smarkm } 22755682Smarkm n = command ("PASS %s", pass); 22855682Smarkm } 22955682Smarkm if (n == CONTINUE) { 23055682Smarkm aflag++; 23155682Smarkm acct = tmp; 23255682Smarkm des_read_pw_string (acct, 128, "Account:", 0); 23355682Smarkm n = command ("ACCT %s", acct); 23455682Smarkm } 23555682Smarkm if (n != COMPLETE) { 23655682Smarkm warnx ("Login failed."); 23755682Smarkm return (0); 23855682Smarkm } 23955682Smarkm if (!aflag && acct != NULL) 24055682Smarkm command ("ACCT %s", acct); 24155682Smarkm if (proxy) 24255682Smarkm return (1); 24355682Smarkm for (n = 0; n < macnum; ++n) { 24455682Smarkm if (!strcmp("init", macros[n].mac_name)) { 24555682Smarkm strlcpy (line, "$init", sizeof (line)); 24655682Smarkm makeargv(); 24755682Smarkm domacro(margc, margv); 24855682Smarkm break; 24955682Smarkm } 25055682Smarkm } 25155682Smarkm sec_set_protection_level (); 25255682Smarkm return (1); 25355682Smarkm} 25455682Smarkm 25555682Smarkmvoid 25655682Smarkmcmdabort (int sig) 25755682Smarkm{ 25855682Smarkm 25955682Smarkm printf ("\n"); 26055682Smarkm fflush (stdout); 26155682Smarkm abrtflag++; 26255682Smarkm if (ptflag) 26355682Smarkm longjmp (ptabort, 1); 26455682Smarkm} 26555682Smarkm 26655682Smarkmint 26755682Smarkmcommand (char *fmt,...) 26855682Smarkm{ 26955682Smarkm va_list ap; 27055682Smarkm int r; 27155682Smarkm sighand oldintr; 27255682Smarkm 27355682Smarkm abrtflag = 0; 27455682Smarkm if (cout == NULL) { 27555682Smarkm warn ("No control connection for command"); 27655682Smarkm code = -1; 27755682Smarkm return (0); 27855682Smarkm } 27955682Smarkm oldintr = signal(SIGINT, cmdabort); 28055682Smarkm va_start(ap, fmt); 28155682Smarkm if(debug){ 28255682Smarkm printf("---> "); 28355682Smarkm if (strncmp("PASS ", fmt, 5) == 0) 28455682Smarkm printf("PASS XXXX"); 28555682Smarkm else 28655682Smarkm vfprintf(stdout, fmt, ap); 28755682Smarkm va_start(ap, fmt); 28855682Smarkm } 28955682Smarkm sec_vfprintf(cout, fmt, ap); 29055682Smarkm va_end(ap); 29155682Smarkm if(debug){ 29255682Smarkm printf("\n"); 29355682Smarkm fflush(stdout); 29455682Smarkm } 29555682Smarkm fprintf (cout, "\r\n"); 29655682Smarkm fflush (cout); 29755682Smarkm cpend = 1; 29855682Smarkm r = getreply (!strcmp (fmt, "QUIT")); 29955682Smarkm if (abrtflag && oldintr != SIG_IGN) 30055682Smarkm (*oldintr) (SIGINT); 30155682Smarkm signal (SIGINT, oldintr); 30255682Smarkm return (r); 30355682Smarkm} 30455682Smarkm 30555682Smarkmchar reply_string[BUFSIZ]; /* last line of previous reply */ 30655682Smarkm 30755682Smarkmint 30855682Smarkmgetreply (int expecteof) 30955682Smarkm{ 31055682Smarkm char *p; 31155682Smarkm char *lead_string; 31255682Smarkm int c; 31355682Smarkm struct sigaction sa, osa; 31455682Smarkm char buf[1024]; 31555682Smarkm 31655682Smarkm sigemptyset (&sa.sa_mask); 31755682Smarkm sa.sa_flags = 0; 31855682Smarkm sa.sa_handler = cmdabort; 31955682Smarkm sigaction (SIGINT, &sa, &osa); 32055682Smarkm 32155682Smarkm p = buf; 32255682Smarkm 32355682Smarkm while (1) { 32455682Smarkm c = getc (cin); 32555682Smarkm switch (c) { 32655682Smarkm case EOF: 32755682Smarkm if (expecteof) { 32855682Smarkm sigaction (SIGINT, &osa, NULL); 32955682Smarkm code = 221; 33055682Smarkm return 0; 33155682Smarkm } 33255682Smarkm lostpeer (0); 33355682Smarkm if (verbose) { 33455682Smarkm printf ("421 Service not available, " 33555682Smarkm "remote server has closed connection\n"); 33655682Smarkm fflush (stdout); 33755682Smarkm } 33855682Smarkm code = 421; 33955682Smarkm return (4); 34055682Smarkm case IAC: 34155682Smarkm c = getc (cin); 34255682Smarkm if (c == WILL || c == WONT) 34355682Smarkm fprintf (cout, "%c%c%c", IAC, DONT, getc (cin)); 34455682Smarkm if (c == DO || c == DONT) 34555682Smarkm fprintf (cout, "%c%c%c", IAC, WONT, getc (cin)); 34655682Smarkm continue; 34755682Smarkm case '\n': 34855682Smarkm *p++ = '\0'; 34955682Smarkm if(isdigit(buf[0])){ 35055682Smarkm sscanf(buf, "%d", &code); 35155682Smarkm if(code == 631){ 35255682Smarkm sec_read_msg(buf, prot_safe); 35355682Smarkm sscanf(buf, "%d", &code); 35455682Smarkm lead_string = "S:"; 35555682Smarkm } else if(code == 632){ 35655682Smarkm sec_read_msg(buf, prot_private); 35755682Smarkm sscanf(buf, "%d", &code); 35855682Smarkm lead_string = "P:"; 35955682Smarkm }else if(code == 633){ 36055682Smarkm sec_read_msg(buf, prot_confidential); 36155682Smarkm sscanf(buf, "%d", &code); 36255682Smarkm lead_string = "C:"; 36355682Smarkm }else if(sec_complete) 36455682Smarkm lead_string = "!!"; 36555682Smarkm else 36655682Smarkm lead_string = ""; 36755682Smarkm if (verbose > 0 || (verbose > -1 && code > 499)) 36855682Smarkm fprintf (stdout, "%s%s\n", lead_string, buf); 36955682Smarkm if (buf[3] == ' ') { 37055682Smarkm strcpy (reply_string, buf); 37155682Smarkm if (code >= 200) 37255682Smarkm cpend = 0; 37355682Smarkm sigaction (SIGINT, &osa, NULL); 37455682Smarkm if (code == 421) 37555682Smarkm lostpeer (0); 37655682Smarkm#if 1 37755682Smarkm if (abrtflag && 37855682Smarkm osa.sa_handler != cmdabort && 37955682Smarkm osa.sa_handler != SIG_IGN) 38055682Smarkm osa.sa_handler (SIGINT); 38155682Smarkm#endif 38255682Smarkm if (code == 227 || code == 229) { 38355682Smarkm char *p, *q; 38455682Smarkm 38555682Smarkm pasv[0] = 0; 38655682Smarkm p = strchr (reply_string, '('); 38755682Smarkm if (p) { 38855682Smarkm p++; 38955682Smarkm q = strchr(p, ')'); 39055682Smarkm if(q){ 39155682Smarkm memcpy (pasv, p, q - p); 39255682Smarkm pasv[q - p] = 0; 39355682Smarkm } 39455682Smarkm } 39555682Smarkm } 39655682Smarkm return code / 100; 39755682Smarkm } 39855682Smarkm }else{ 39955682Smarkm if(verbose > 0 || (verbose > -1 && code > 499)){ 40055682Smarkm if(sec_complete) 40155682Smarkm fprintf(stdout, "!!"); 40255682Smarkm fprintf(stdout, "%s\n", buf); 40355682Smarkm } 40455682Smarkm } 40555682Smarkm p = buf; 40655682Smarkm continue; 40755682Smarkm default: 40855682Smarkm *p++ = c; 40955682Smarkm } 41055682Smarkm } 41155682Smarkm 41255682Smarkm} 41355682Smarkm 41455682Smarkm 41555682Smarkm#if 0 41655682Smarkmint 41755682Smarkmgetreply (int expecteof) 41855682Smarkm{ 41955682Smarkm int c, n; 42055682Smarkm int dig; 42155682Smarkm int originalcode = 0, continuation = 0; 42255682Smarkm sighand oldintr; 42355682Smarkm int pflag = 0; 42455682Smarkm char *cp, *pt = pasv; 42555682Smarkm 42655682Smarkm oldintr = signal (SIGINT, cmdabort); 42755682Smarkm for (;;) { 42855682Smarkm dig = n = code = 0; 42955682Smarkm cp = reply_string; 43055682Smarkm while ((c = getc (cin)) != '\n') { 43155682Smarkm if (c == IAC) { /* handle telnet commands */ 43255682Smarkm switch (c = getc (cin)) { 43355682Smarkm case WILL: 43455682Smarkm case WONT: 43555682Smarkm c = getc (cin); 43655682Smarkm fprintf (cout, "%c%c%c", IAC, DONT, c); 43755682Smarkm fflush (cout); 43855682Smarkm break; 43955682Smarkm case DO: 44055682Smarkm case DONT: 44155682Smarkm c = getc (cin); 44255682Smarkm fprintf (cout, "%c%c%c", IAC, WONT, c); 44355682Smarkm fflush (cout); 44455682Smarkm break; 44555682Smarkm default: 44655682Smarkm break; 44755682Smarkm } 44855682Smarkm continue; 44955682Smarkm } 45055682Smarkm dig++; 45155682Smarkm if (c == EOF) { 45255682Smarkm if (expecteof) { 45355682Smarkm signal (SIGINT, oldintr); 45455682Smarkm code = 221; 45555682Smarkm return (0); 45655682Smarkm } 45755682Smarkm lostpeer (0); 45855682Smarkm if (verbose) { 45955682Smarkm printf ("421 Service not available, remote server has closed connection\n"); 46055682Smarkm fflush (stdout); 46155682Smarkm } 46255682Smarkm code = 421; 46355682Smarkm return (4); 46455682Smarkm } 46555682Smarkm if (c != '\r' && (verbose > 0 || 46655682Smarkm (verbose > -1 && n == '5' && dig > 4))) { 46755682Smarkm if (proxflag && 46855682Smarkm (dig == 1 || dig == 5 && verbose == 0)) 46955682Smarkm printf ("%s:", hostname); 47055682Smarkm putchar (c); 47155682Smarkm } 47255682Smarkm if (dig < 4 && isdigit (c)) 47355682Smarkm code = code * 10 + (c - '0'); 47455682Smarkm if (!pflag && code == 227) 47555682Smarkm pflag = 1; 47655682Smarkm if (dig > 4 && pflag == 1 && isdigit (c)) 47755682Smarkm pflag = 2; 47855682Smarkm if (pflag == 2) { 47955682Smarkm if (c != '\r' && c != ')') 48055682Smarkm *pt++ = c; 48155682Smarkm else { 48255682Smarkm *pt = '\0'; 48355682Smarkm pflag = 3; 48455682Smarkm } 48555682Smarkm } 48655682Smarkm if (dig == 4 && c == '-') { 48755682Smarkm if (continuation) 48855682Smarkm code = 0; 48955682Smarkm continuation++; 49055682Smarkm } 49155682Smarkm if (n == 0) 49255682Smarkm n = c; 49355682Smarkm if (cp < &reply_string[sizeof (reply_string) - 1]) 49455682Smarkm *cp++ = c; 49555682Smarkm } 49655682Smarkm if (verbose > 0 || verbose > -1 && n == '5') { 49755682Smarkm putchar (c); 49855682Smarkm fflush (stdout); 49955682Smarkm } 50055682Smarkm if (continuation && code != originalcode) { 50155682Smarkm if (originalcode == 0) 50255682Smarkm originalcode = code; 50355682Smarkm continue; 50455682Smarkm } 50555682Smarkm *cp = '\0'; 50655682Smarkm if(sec_complete){ 50755682Smarkm if(code == 631) 50855682Smarkm sec_read_msg(reply_string, prot_safe); 50955682Smarkm else if(code == 632) 51055682Smarkm sec_read_msg(reply_string, prot_private); 51155682Smarkm else if(code == 633) 51255682Smarkm sec_read_msg(reply_string, prot_confidential); 51355682Smarkm n = code / 100 + '0'; 51455682Smarkm } 51555682Smarkm if (n != '1') 51655682Smarkm cpend = 0; 51755682Smarkm signal (SIGINT, oldintr); 51855682Smarkm if (code == 421 || originalcode == 421) 51955682Smarkm lostpeer (0); 52055682Smarkm if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) 52155682Smarkm (*oldintr) (SIGINT); 52255682Smarkm return (n - '0'); 52355682Smarkm } 52455682Smarkm} 52555682Smarkm 52655682Smarkm#endif 52755682Smarkm 52855682Smarkmint 52955682Smarkmempty (fd_set * mask, int sec) 53055682Smarkm{ 53155682Smarkm struct timeval t; 53255682Smarkm 53372445Sassar t.tv_sec = sec; 53455682Smarkm t.tv_usec = 0; 53572445Sassar return (select (FD_SETSIZE, mask, NULL, NULL, &t)); 53655682Smarkm} 53755682Smarkm 53855682Smarkmjmp_buf sendabort; 53955682Smarkm 54055682Smarkmstatic RETSIGTYPE 54155682Smarkmabortsend (int sig) 54255682Smarkm{ 54355682Smarkm 54455682Smarkm mflag = 0; 54555682Smarkm abrtflag = 0; 54655682Smarkm printf ("\nsend aborted\nwaiting for remote to finish abort\n"); 54755682Smarkm fflush (stdout); 54855682Smarkm longjmp (sendabort, 1); 54955682Smarkm} 55055682Smarkm 55155682Smarkm#define HASHBYTES 1024 55255682Smarkm 55355682Smarkmstatic int 55455682Smarkmcopy_stream (FILE * from, FILE * to) 55555682Smarkm{ 55655682Smarkm static size_t bufsize; 55755682Smarkm static char *buf; 55855682Smarkm int n; 55955682Smarkm int bytes = 0; 56055682Smarkm int werr = 0; 56155682Smarkm int hashbytes = HASHBYTES; 56255682Smarkm struct stat st; 56355682Smarkm 56455682Smarkm#if defined(HAVE_MMAP) && !defined(NO_MMAP) 56555682Smarkm void *chunk; 56655682Smarkm 56755682Smarkm#ifndef MAP_FAILED 56855682Smarkm#define MAP_FAILED (-1) 56955682Smarkm#endif 57055682Smarkm 57155682Smarkm if (fstat (fileno (from), &st) == 0 && S_ISREG (st.st_mode)) { 57255682Smarkm /* 57355682Smarkm * mmap zero bytes has potential of loosing, don't do it. 57455682Smarkm */ 57555682Smarkm if (st.st_size == 0) 57655682Smarkm return 0; 57755682Smarkm chunk = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fileno (from), 0); 57855682Smarkm if (chunk != (void *) MAP_FAILED) { 57955682Smarkm int res; 58055682Smarkm 58155682Smarkm res = sec_write (fileno (to), chunk, st.st_size); 58255682Smarkm if (munmap (chunk, st.st_size) < 0) 58355682Smarkm warn ("munmap"); 58455682Smarkm sec_fflush (to); 58555682Smarkm return res; 58655682Smarkm } 58755682Smarkm } 58855682Smarkm#endif 58955682Smarkm 59055682Smarkm buf = alloc_buffer (buf, &bufsize, 59155682Smarkm fstat (fileno (from), &st) >= 0 ? &st : NULL); 59255682Smarkm if (buf == NULL) 59355682Smarkm return -1; 59455682Smarkm 59555682Smarkm while ((n = read (fileno (from), buf, bufsize)) > 0) { 59655682Smarkm werr = sec_write (fileno (to), buf, n); 59755682Smarkm if (werr < 0) 59855682Smarkm break; 59955682Smarkm bytes += werr; 60055682Smarkm while (hash && bytes > hashbytes) { 60155682Smarkm putchar ('#'); 60255682Smarkm hashbytes += HASHBYTES; 60355682Smarkm } 60455682Smarkm } 60555682Smarkm sec_fflush (to); 60655682Smarkm if (n < 0) 60755682Smarkm warn ("local"); 60855682Smarkm 60955682Smarkm if (werr < 0) { 61055682Smarkm if (errno != EPIPE) 61155682Smarkm warn ("netout"); 61255682Smarkm bytes = -1; 61355682Smarkm } 61455682Smarkm return bytes; 61555682Smarkm} 61655682Smarkm 61755682Smarkmvoid 61855682Smarkmsendrequest (char *cmd, char *local, char *remote, char *lmode, int printnames) 61955682Smarkm{ 62055682Smarkm struct stat st; 62155682Smarkm struct timeval start, stop; 62255682Smarkm int c, d; 62355682Smarkm FILE *fin, *dout = 0; 62455682Smarkm int (*closefunc) (FILE *); 62572445Sassar RETSIGTYPE (*oldintr)(int), (*oldintp)(int); 62655682Smarkm long bytes = 0, hashbytes = HASHBYTES; 62755682Smarkm char *rmode = "w"; 62855682Smarkm 62955682Smarkm if (verbose && printnames) { 63055682Smarkm if (local && strcmp (local, "-") != 0) 63155682Smarkm printf ("local: %s ", local); 63255682Smarkm if (remote) 63355682Smarkm printf ("remote: %s\n", remote); 63455682Smarkm } 63555682Smarkm if (proxy) { 63655682Smarkm proxtrans (cmd, local, remote); 63755682Smarkm return; 63855682Smarkm } 63955682Smarkm if (curtype != type) 64055682Smarkm changetype (type, 0); 64155682Smarkm closefunc = NULL; 64255682Smarkm oldintr = NULL; 64355682Smarkm oldintp = NULL; 64455682Smarkm 64555682Smarkm if (setjmp (sendabort)) { 64655682Smarkm while (cpend) { 64755682Smarkm getreply (0); 64855682Smarkm } 64955682Smarkm if (data >= 0) { 65055682Smarkm close (data); 65155682Smarkm data = -1; 65255682Smarkm } 65355682Smarkm if (oldintr) 65455682Smarkm signal (SIGINT, oldintr); 65555682Smarkm if (oldintp) 65655682Smarkm signal (SIGPIPE, oldintp); 65755682Smarkm code = -1; 65855682Smarkm return; 65955682Smarkm } 66055682Smarkm oldintr = signal (SIGINT, abortsend); 66155682Smarkm if (strcmp (local, "-") == 0) 66255682Smarkm fin = stdin; 66355682Smarkm else if (*local == '|') { 66455682Smarkm oldintp = signal (SIGPIPE, SIG_IGN); 66555682Smarkm fin = popen (local + 1, lmode); 66655682Smarkm if (fin == NULL) { 66755682Smarkm warn ("%s", local + 1); 66855682Smarkm signal (SIGINT, oldintr); 66955682Smarkm signal (SIGPIPE, oldintp); 67055682Smarkm code = -1; 67155682Smarkm return; 67255682Smarkm } 67355682Smarkm closefunc = pclose; 67455682Smarkm } else { 67555682Smarkm fin = fopen (local, lmode); 67655682Smarkm if (fin == NULL) { 67755682Smarkm warn ("local: %s", local); 67855682Smarkm signal (SIGINT, oldintr); 67955682Smarkm code = -1; 68055682Smarkm return; 68155682Smarkm } 68255682Smarkm closefunc = fclose; 68355682Smarkm if (fstat (fileno (fin), &st) < 0 || 68455682Smarkm (st.st_mode & S_IFMT) != S_IFREG) { 68555682Smarkm fprintf (stdout, "%s: not a plain file.\n", local); 68655682Smarkm signal (SIGINT, oldintr); 68755682Smarkm fclose (fin); 68855682Smarkm code = -1; 68955682Smarkm return; 69055682Smarkm } 69155682Smarkm } 69255682Smarkm if (initconn ()) { 69355682Smarkm signal (SIGINT, oldintr); 69455682Smarkm if (oldintp) 69555682Smarkm signal (SIGPIPE, oldintp); 69655682Smarkm code = -1; 69755682Smarkm if (closefunc != NULL) 69855682Smarkm (*closefunc) (fin); 69955682Smarkm return; 70055682Smarkm } 70155682Smarkm if (setjmp (sendabort)) 70255682Smarkm goto abort; 70355682Smarkm 70455682Smarkm if (restart_point && 70555682Smarkm (strcmp (cmd, "STOR") == 0 || strcmp (cmd, "APPE") == 0)) { 70655682Smarkm int rc; 70755682Smarkm 70855682Smarkm switch (curtype) { 70955682Smarkm case TYPE_A: 71055682Smarkm rc = fseek (fin, (long) restart_point, SEEK_SET); 71155682Smarkm break; 71255682Smarkm case TYPE_I: 71355682Smarkm case TYPE_L: 71455682Smarkm rc = lseek (fileno (fin), restart_point, SEEK_SET); 71555682Smarkm break; 71655682Smarkm } 71755682Smarkm if (rc < 0) { 71855682Smarkm warn ("local: %s", local); 71955682Smarkm restart_point = 0; 72055682Smarkm if (closefunc != NULL) 72155682Smarkm (*closefunc) (fin); 72255682Smarkm return; 72355682Smarkm } 72455682Smarkm if (command ("REST %ld", (long) restart_point) 72555682Smarkm != CONTINUE) { 72655682Smarkm restart_point = 0; 72755682Smarkm if (closefunc != NULL) 72855682Smarkm (*closefunc) (fin); 72955682Smarkm return; 73055682Smarkm } 73155682Smarkm restart_point = 0; 73255682Smarkm rmode = "r+w"; 73355682Smarkm } 73455682Smarkm if (remote) { 73555682Smarkm if (command ("%s %s", cmd, remote) != PRELIM) { 73655682Smarkm signal (SIGINT, oldintr); 73755682Smarkm if (oldintp) 73855682Smarkm signal (SIGPIPE, oldintp); 73955682Smarkm if (closefunc != NULL) 74055682Smarkm (*closefunc) (fin); 74155682Smarkm return; 74255682Smarkm } 74355682Smarkm } else if (command ("%s", cmd) != PRELIM) { 74455682Smarkm signal(SIGINT, oldintr); 74555682Smarkm if (oldintp) 74655682Smarkm signal(SIGPIPE, oldintp); 74755682Smarkm if (closefunc != NULL) 74855682Smarkm (*closefunc)(fin); 74955682Smarkm return; 75055682Smarkm } 75155682Smarkm dout = dataconn(rmode); 75255682Smarkm if (dout == NULL) 75355682Smarkm goto abort; 75455682Smarkm set_buffer_size (fileno (dout), 0); 75555682Smarkm gettimeofday (&start, (struct timezone *) 0); 75655682Smarkm oldintp = signal (SIGPIPE, SIG_IGN); 75755682Smarkm switch (curtype) { 75855682Smarkm 75955682Smarkm case TYPE_I: 76055682Smarkm case TYPE_L: 76155682Smarkm errno = d = c = 0; 76255682Smarkm bytes = copy_stream (fin, dout); 76355682Smarkm break; 76455682Smarkm 76555682Smarkm case TYPE_A: 76655682Smarkm while ((c = getc (fin)) != EOF) { 76755682Smarkm if (c == '\n') { 76855682Smarkm while (hash && (bytes >= hashbytes)) { 76955682Smarkm putchar ('#'); 77055682Smarkm fflush (stdout); 77155682Smarkm hashbytes += HASHBYTES; 77255682Smarkm } 77355682Smarkm if (ferror (dout)) 77455682Smarkm break; 77555682Smarkm sec_putc ('\r', dout); 77655682Smarkm bytes++; 77755682Smarkm } 77855682Smarkm sec_putc (c, dout); 77955682Smarkm bytes++; 78055682Smarkm } 78155682Smarkm sec_fflush (dout); 78255682Smarkm if (hash) { 78355682Smarkm if (bytes < hashbytes) 78455682Smarkm putchar ('#'); 78555682Smarkm putchar ('\n'); 78655682Smarkm fflush (stdout); 78755682Smarkm } 78855682Smarkm if (ferror (fin)) 78955682Smarkm warn ("local: %s", local); 79055682Smarkm if (ferror (dout)) { 79155682Smarkm if (errno != EPIPE) 79255682Smarkm warn ("netout"); 79355682Smarkm bytes = -1; 79455682Smarkm } 79555682Smarkm break; 79655682Smarkm } 79755682Smarkm if (closefunc != NULL) 79855682Smarkm (*closefunc) (fin); 79955682Smarkm fclose (dout); 80055682Smarkm gettimeofday (&stop, (struct timezone *) 0); 80155682Smarkm getreply (0); 80255682Smarkm signal (SIGINT, oldintr); 80355682Smarkm if (oldintp) 80455682Smarkm signal (SIGPIPE, oldintp); 80555682Smarkm if (bytes > 0) 80655682Smarkm ptransfer ("sent", bytes, &start, &stop); 80755682Smarkm return; 80855682Smarkmabort: 80955682Smarkm signal (SIGINT, oldintr); 81055682Smarkm if (oldintp) 81155682Smarkm signal (SIGPIPE, oldintp); 81255682Smarkm if (!cpend) { 81355682Smarkm code = -1; 81455682Smarkm return; 81555682Smarkm } 81655682Smarkm if (data >= 0) { 81755682Smarkm close (data); 81855682Smarkm data = -1; 81955682Smarkm } 82055682Smarkm if (dout) 82155682Smarkm fclose (dout); 82255682Smarkm getreply (0); 82355682Smarkm code = -1; 82455682Smarkm if (closefunc != NULL && fin != NULL) 82555682Smarkm (*closefunc) (fin); 82655682Smarkm gettimeofday (&stop, (struct timezone *) 0); 82755682Smarkm if (bytes > 0) 82855682Smarkm ptransfer ("sent", bytes, &start, &stop); 82955682Smarkm} 83055682Smarkm 83155682Smarkmjmp_buf recvabort; 83255682Smarkm 83355682Smarkmvoid 83455682Smarkmabortrecv (int sig) 83555682Smarkm{ 83655682Smarkm 83755682Smarkm mflag = 0; 83855682Smarkm abrtflag = 0; 83955682Smarkm printf ("\nreceive aborted\nwaiting for remote to finish abort\n"); 84055682Smarkm fflush (stdout); 84155682Smarkm longjmp (recvabort, 1); 84255682Smarkm} 84355682Smarkm 84455682Smarkmvoid 84555682Smarkmrecvrequest (char *cmd, char *local, char *remote, 84655682Smarkm char *lmode, int printnames, int local_given) 84755682Smarkm{ 84855682Smarkm FILE *fout, *din = 0; 84955682Smarkm int (*closefunc) (FILE *); 85055682Smarkm sighand oldintr, oldintp; 85155682Smarkm int c, d, is_retr, tcrflag, bare_lfs = 0; 85255682Smarkm static size_t bufsize; 85355682Smarkm static char *buf; 85455682Smarkm long bytes = 0, hashbytes = HASHBYTES; 85555682Smarkm struct timeval start, stop; 85655682Smarkm struct stat st; 85755682Smarkm 85855682Smarkm is_retr = strcmp (cmd, "RETR") == 0; 85955682Smarkm if (is_retr && verbose && printnames) { 86055682Smarkm if (local && strcmp (local, "-") != 0) 86155682Smarkm printf ("local: %s ", local); 86255682Smarkm if (remote) 86355682Smarkm printf ("remote: %s\n", remote); 86455682Smarkm } 86555682Smarkm if (proxy && is_retr) { 86655682Smarkm proxtrans (cmd, local, remote); 86755682Smarkm return; 86855682Smarkm } 86955682Smarkm closefunc = NULL; 87055682Smarkm oldintr = NULL; 87155682Smarkm oldintp = NULL; 87255682Smarkm tcrflag = !crflag && is_retr; 87355682Smarkm if (setjmp (recvabort)) { 87455682Smarkm while (cpend) { 87555682Smarkm getreply (0); 87655682Smarkm } 87755682Smarkm if (data >= 0) { 87855682Smarkm close (data); 87955682Smarkm data = -1; 88055682Smarkm } 88155682Smarkm if (oldintr) 88255682Smarkm signal (SIGINT, oldintr); 88355682Smarkm code = -1; 88455682Smarkm return; 88555682Smarkm } 88655682Smarkm oldintr = signal (SIGINT, abortrecv); 88755682Smarkm if (!local_given || (strcmp (local, "-") && *local != '|')) { 88855682Smarkm if (access (local, 2) < 0) { 88955682Smarkm char *dir = strrchr (local, '/'); 89055682Smarkm 89155682Smarkm if (errno != ENOENT && errno != EACCES) { 89255682Smarkm warn ("local: %s", local); 89355682Smarkm signal (SIGINT, oldintr); 89455682Smarkm code = -1; 89555682Smarkm return; 89655682Smarkm } 89755682Smarkm if (dir != NULL) 89855682Smarkm *dir = 0; 89955682Smarkm d = access (dir ? local : ".", 2); 90055682Smarkm if (dir != NULL) 90155682Smarkm *dir = '/'; 90255682Smarkm if (d < 0) { 90355682Smarkm warn ("local: %s", local); 90455682Smarkm signal (SIGINT, oldintr); 90555682Smarkm code = -1; 90655682Smarkm return; 90755682Smarkm } 90855682Smarkm if (!runique && errno == EACCES && 90955682Smarkm chmod (local, 0600) < 0) { 91055682Smarkm warn ("local: %s", local); 91155682Smarkm signal (SIGINT, oldintr); 91255682Smarkm signal (SIGINT, oldintr); 91355682Smarkm code = -1; 91455682Smarkm return; 91555682Smarkm } 91655682Smarkm if (runique && errno == EACCES && 91755682Smarkm (local = gunique (local)) == NULL) { 91855682Smarkm signal (SIGINT, oldintr); 91955682Smarkm code = -1; 92055682Smarkm return; 92155682Smarkm } 92255682Smarkm } else if (runique && (local = gunique (local)) == NULL) { 92355682Smarkm signal(SIGINT, oldintr); 92455682Smarkm code = -1; 92555682Smarkm return; 92655682Smarkm } 92755682Smarkm } 92855682Smarkm if (!is_retr) { 92955682Smarkm if (curtype != TYPE_A) 93055682Smarkm changetype (TYPE_A, 0); 93155682Smarkm } else if (curtype != type) 93255682Smarkm changetype (type, 0); 93355682Smarkm if (initconn ()) { 93455682Smarkm signal (SIGINT, oldintr); 93555682Smarkm code = -1; 93655682Smarkm return; 93755682Smarkm } 93855682Smarkm if (setjmp (recvabort)) 93955682Smarkm goto abort; 94055682Smarkm if (is_retr && restart_point && 94155682Smarkm command ("REST %ld", (long) restart_point) != CONTINUE) 94255682Smarkm return; 94355682Smarkm if (remote) { 94455682Smarkm if (command ("%s %s", cmd, remote) != PRELIM) { 94555682Smarkm signal (SIGINT, oldintr); 94655682Smarkm return; 94755682Smarkm } 94855682Smarkm } else { 94955682Smarkm if (command ("%s", cmd) != PRELIM) { 95055682Smarkm signal (SIGINT, oldintr); 95155682Smarkm return; 95255682Smarkm } 95355682Smarkm } 95455682Smarkm din = dataconn ("r"); 95555682Smarkm if (din == NULL) 95655682Smarkm goto abort; 95755682Smarkm set_buffer_size (fileno (din), 1); 95855682Smarkm if (local_given && strcmp (local, "-") == 0) 95955682Smarkm fout = stdout; 96055682Smarkm else if (local_given && *local == '|') { 96155682Smarkm oldintp = signal (SIGPIPE, SIG_IGN); 96255682Smarkm fout = popen (local + 1, "w"); 96355682Smarkm if (fout == NULL) { 96455682Smarkm warn ("%s", local + 1); 96555682Smarkm goto abort; 96655682Smarkm } 96755682Smarkm closefunc = pclose; 96855682Smarkm } else { 96955682Smarkm fout = fopen (local, lmode); 97055682Smarkm if (fout == NULL) { 97155682Smarkm warn ("local: %s", local); 97255682Smarkm goto abort; 97355682Smarkm } 97455682Smarkm closefunc = fclose; 97555682Smarkm } 97655682Smarkm buf = alloc_buffer (buf, &bufsize, 97755682Smarkm fstat (fileno (fout), &st) >= 0 ? &st : NULL); 97855682Smarkm if (buf == NULL) 97955682Smarkm goto abort; 98055682Smarkm 98155682Smarkm gettimeofday (&start, (struct timezone *) 0); 98255682Smarkm switch (curtype) { 98355682Smarkm 98455682Smarkm case TYPE_I: 98555682Smarkm case TYPE_L: 98655682Smarkm if (restart_point && 98755682Smarkm lseek (fileno (fout), restart_point, SEEK_SET) < 0) { 98855682Smarkm warn ("local: %s", local); 98955682Smarkm if (closefunc != NULL) 99055682Smarkm (*closefunc) (fout); 99155682Smarkm return; 99255682Smarkm } 99355682Smarkm errno = d = 0; 99455682Smarkm while ((c = sec_read (fileno (din), buf, bufsize)) > 0) { 99555682Smarkm if ((d = write (fileno (fout), buf, c)) != c) 99655682Smarkm break; 99755682Smarkm bytes += c; 99855682Smarkm if (hash) { 99955682Smarkm while (bytes >= hashbytes) { 100055682Smarkm putchar ('#'); 100155682Smarkm hashbytes += HASHBYTES; 100255682Smarkm } 100355682Smarkm fflush (stdout); 100455682Smarkm } 100555682Smarkm } 100655682Smarkm if (hash && bytes > 0) { 100755682Smarkm if (bytes < HASHBYTES) 100855682Smarkm putchar ('#'); 100955682Smarkm putchar ('\n'); 101055682Smarkm fflush (stdout); 101155682Smarkm } 101255682Smarkm if (c < 0) { 101355682Smarkm if (errno != EPIPE) 101455682Smarkm warn ("netin"); 101555682Smarkm bytes = -1; 101655682Smarkm } 101755682Smarkm if (d < c) { 101855682Smarkm if (d < 0) 101955682Smarkm warn ("local: %s", local); 102055682Smarkm else 102155682Smarkm warnx ("%s: short write", local); 102255682Smarkm } 102355682Smarkm break; 102455682Smarkm 102555682Smarkm case TYPE_A: 102655682Smarkm if (restart_point) { 102755682Smarkm int i, n, ch; 102855682Smarkm 102955682Smarkm if (fseek (fout, 0L, SEEK_SET) < 0) 103055682Smarkm goto done; 103155682Smarkm n = restart_point; 103255682Smarkm for (i = 0; i++ < n;) { 103355682Smarkm if ((ch = sec_getc (fout)) == EOF) 103455682Smarkm goto done; 103555682Smarkm if (ch == '\n') 103655682Smarkm i++; 103755682Smarkm } 103855682Smarkm if (fseek (fout, 0L, SEEK_CUR) < 0) { 103955682Smarkm done: 104055682Smarkm warn ("local: %s", local); 104155682Smarkm if (closefunc != NULL) 104255682Smarkm (*closefunc) (fout); 104355682Smarkm return; 104455682Smarkm } 104555682Smarkm } 104655682Smarkm while ((c = sec_getc(din)) != EOF) { 104755682Smarkm if (c == '\n') 104855682Smarkm bare_lfs++; 104955682Smarkm while (c == '\r') { 105055682Smarkm while (hash && (bytes >= hashbytes)) { 105155682Smarkm putchar ('#'); 105255682Smarkm fflush (stdout); 105355682Smarkm hashbytes += HASHBYTES; 105455682Smarkm } 105555682Smarkm bytes++; 105655682Smarkm if ((c = sec_getc (din)) != '\n' || tcrflag) { 105755682Smarkm if (ferror (fout)) 105855682Smarkm goto break2; 105955682Smarkm putc ('\r', fout); 106055682Smarkm if (c == '\0') { 106155682Smarkm bytes++; 106255682Smarkm goto contin2; 106355682Smarkm } 106455682Smarkm if (c == EOF) 106555682Smarkm goto contin2; 106655682Smarkm } 106755682Smarkm } 106855682Smarkm putc (c, fout); 106955682Smarkm bytes++; 107055682Smarkm contin2:; 107155682Smarkm } 107255682Smarkmbreak2: 107355682Smarkm if (bare_lfs) { 107455682Smarkm printf ("WARNING! %d bare linefeeds received in ASCII mode\n", 107555682Smarkm bare_lfs); 107655682Smarkm printf ("File may not have transferred correctly.\n"); 107755682Smarkm } 107855682Smarkm if (hash) { 107955682Smarkm if (bytes < hashbytes) 108055682Smarkm putchar ('#'); 108155682Smarkm putchar ('\n'); 108255682Smarkm fflush (stdout); 108355682Smarkm } 108455682Smarkm if (ferror (din)) { 108555682Smarkm if (errno != EPIPE) 108655682Smarkm warn ("netin"); 108755682Smarkm bytes = -1; 108855682Smarkm } 108955682Smarkm if (ferror (fout)) 109055682Smarkm warn ("local: %s", local); 109155682Smarkm break; 109255682Smarkm } 109355682Smarkm if (closefunc != NULL) 109455682Smarkm (*closefunc) (fout); 109555682Smarkm signal (SIGINT, oldintr); 109655682Smarkm if (oldintp) 109755682Smarkm signal (SIGPIPE, oldintp); 109855682Smarkm fclose (din); 109955682Smarkm gettimeofday (&stop, (struct timezone *) 0); 110055682Smarkm getreply (0); 110155682Smarkm if (bytes > 0 && is_retr) 110255682Smarkm ptransfer ("received", bytes, &start, &stop); 110355682Smarkm return; 110455682Smarkmabort: 110555682Smarkm 110655682Smarkm /* abort using RFC959 recommended IP,SYNC sequence */ 110755682Smarkm 110855682Smarkm if (oldintp) 110955682Smarkm signal (SIGPIPE, oldintr); 111055682Smarkm signal (SIGINT, SIG_IGN); 111155682Smarkm if (!cpend) { 111255682Smarkm code = -1; 111355682Smarkm signal (SIGINT, oldintr); 111455682Smarkm return; 111555682Smarkm } 111655682Smarkm abort_remote(din); 111755682Smarkm code = -1; 111855682Smarkm if (data >= 0) { 111955682Smarkm close (data); 112055682Smarkm data = -1; 112155682Smarkm } 112255682Smarkm if (closefunc != NULL && fout != NULL) 112355682Smarkm (*closefunc) (fout); 112455682Smarkm if (din) 112555682Smarkm fclose (din); 112655682Smarkm gettimeofday (&stop, (struct timezone *) 0); 112755682Smarkm if (bytes > 0) 112855682Smarkm ptransfer ("received", bytes, &start, &stop); 112955682Smarkm signal (SIGINT, oldintr); 113055682Smarkm} 113155682Smarkm 113255682Smarkmstatic int 113355682Smarkmparse_epsv (const char *str) 113455682Smarkm{ 113555682Smarkm char sep; 113655682Smarkm char *end; 113755682Smarkm int port; 113855682Smarkm 113955682Smarkm if (*str == '\0') 114055682Smarkm return -1; 114155682Smarkm sep = *str++; 114255682Smarkm if (sep != *str++) 114355682Smarkm return -1; 114455682Smarkm if (sep != *str++) 114555682Smarkm return -1; 114655682Smarkm port = strtol (str, &end, 0); 114755682Smarkm if (str == end) 114855682Smarkm return -1; 114955682Smarkm if (end[0] != sep || end[1] != '\0') 115055682Smarkm return -1; 115155682Smarkm return htons(port); 115255682Smarkm} 115355682Smarkm 115455682Smarkmstatic int 115555682Smarkmparse_pasv (struct sockaddr_in *sin, const char *str) 115655682Smarkm{ 115755682Smarkm int a0, a1, a2, a3, p0, p1; 115855682Smarkm 115955682Smarkm /* 116055682Smarkm * What we've got at this point is a string of comma separated 116155682Smarkm * one-byte unsigned integer values. The first four are the an IP 116255682Smarkm * address. The fifth is the MSB of the port number, the sixth is the 116355682Smarkm * LSB. From that we'll prepare a sockaddr_in. 116455682Smarkm */ 116555682Smarkm 116655682Smarkm if (sscanf (str, "%d,%d,%d,%d,%d,%d", 116755682Smarkm &a0, &a1, &a2, &a3, &p0, &p1) != 6) { 116855682Smarkm printf ("Passive mode address scan failure. " 116955682Smarkm "Shouldn't happen!\n"); 117055682Smarkm return -1; 117155682Smarkm } 117255682Smarkm if (a0 < 0 || a0 > 255 || 117355682Smarkm a1 < 0 || a1 > 255 || 117455682Smarkm a2 < 0 || a2 > 255 || 117555682Smarkm a3 < 0 || a3 > 255 || 117655682Smarkm p0 < 0 || p0 > 255 || 117755682Smarkm p1 < 0 || p1 > 255) { 117855682Smarkm printf ("Can't parse passive mode string.\n"); 117955682Smarkm return -1; 118055682Smarkm } 118155682Smarkm memset (sin, 0, sizeof(*sin)); 118255682Smarkm sin->sin_family = AF_INET; 118355682Smarkm sin->sin_addr.s_addr = htonl ((a0 << 24) | (a1 << 16) | 118455682Smarkm (a2 << 8) | a3); 118555682Smarkm sin->sin_port = htons ((p0 << 8) | p1); 118655682Smarkm return 0; 118755682Smarkm} 118855682Smarkm 118955682Smarkmstatic int 119055682Smarkmpassive_mode (void) 119155682Smarkm{ 119255682Smarkm int port; 119355682Smarkm 119455682Smarkm data = socket (myctladdr->sa_family, SOCK_STREAM, 0); 119555682Smarkm if (data < 0) { 119655682Smarkm warn ("socket"); 119755682Smarkm return (1); 119855682Smarkm } 119955682Smarkm if (options & SO_DEBUG) 120055682Smarkm socket_set_debug (data); 120155682Smarkm if (command ("EPSV") != COMPLETE) { 120255682Smarkm if (command ("PASV") != COMPLETE) { 120355682Smarkm printf ("Passive mode refused.\n"); 120455682Smarkm goto bad; 120555682Smarkm } 120655682Smarkm } 120755682Smarkm 120855682Smarkm /* 120955682Smarkm * Parse the reply to EPSV or PASV 121055682Smarkm */ 121155682Smarkm 121255682Smarkm port = parse_epsv (pasv); 121355682Smarkm if (port > 0) { 121455682Smarkm data_addr->sa_family = myctladdr->sa_family; 121555682Smarkm socket_set_address_and_port (data_addr, 121655682Smarkm socket_get_address (hisctladdr), 121755682Smarkm port); 121855682Smarkm } else { 121955682Smarkm if (parse_pasv ((struct sockaddr_in *)data_addr, pasv) < 0) 122055682Smarkm goto bad; 122155682Smarkm } 122255682Smarkm 122355682Smarkm if (connect (data, data_addr, socket_sockaddr_size (data_addr)) < 0) { 122455682Smarkm warn ("connect"); 122555682Smarkm goto bad; 122655682Smarkm } 122755682Smarkm#ifdef IPTOS_THROUGHPUT 122855682Smarkm socket_set_tos (data, IPTOS_THROUGHPUT); 122955682Smarkm#endif 123055682Smarkm return (0); 123155682Smarkmbad: 123255682Smarkm close (data); 123355682Smarkm data = -1; 123455682Smarkm sendport = 1; 123555682Smarkm return (1); 123655682Smarkm} 123755682Smarkm 123855682Smarkm 123955682Smarkmstatic int 124055682Smarkmactive_mode (void) 124155682Smarkm{ 124255682Smarkm int tmpno = 0; 124372445Sassar socklen_t len; 124455682Smarkm int result; 124555682Smarkm 124655682Smarkmnoport: 124755682Smarkm data_addr->sa_family = myctladdr->sa_family; 124855682Smarkm socket_set_address_and_port (data_addr, socket_get_address (myctladdr), 124955682Smarkm sendport ? 0 : socket_get_port (myctladdr)); 125055682Smarkm 125155682Smarkm if (data != -1) 125255682Smarkm close (data); 125355682Smarkm data = socket (data_addr->sa_family, SOCK_STREAM, 0); 125455682Smarkm if (data < 0) { 125555682Smarkm warn ("socket"); 125655682Smarkm if (tmpno) 125755682Smarkm sendport = 1; 125855682Smarkm return (1); 125955682Smarkm } 126055682Smarkm if (!sendport) 126155682Smarkm socket_set_reuseaddr (data, 1); 126255682Smarkm if (bind (data, data_addr, socket_sockaddr_size (data_addr)) < 0) { 126355682Smarkm warn ("bind"); 126455682Smarkm goto bad; 126555682Smarkm } 126655682Smarkm if (options & SO_DEBUG) 126755682Smarkm socket_set_debug (data); 126855682Smarkm len = sizeof (data_addr_ss); 126955682Smarkm if (getsockname (data, data_addr, &len) < 0) { 127055682Smarkm warn ("getsockname"); 127155682Smarkm goto bad; 127255682Smarkm } 127355682Smarkm if (listen (data, 1) < 0) 127455682Smarkm warn ("listen"); 127555682Smarkm if (sendport) { 127655682Smarkm char *cmd; 127755682Smarkm char addr_str[256]; 127855682Smarkm int inet_af; 127955682Smarkm int overbose; 128055682Smarkm 128155682Smarkm if (inet_ntop (data_addr->sa_family, socket_get_address (data_addr), 128255682Smarkm addr_str, sizeof(addr_str)) == NULL) 128355682Smarkm errx (1, "inet_ntop failed"); 128455682Smarkm switch (data_addr->sa_family) { 128555682Smarkm case AF_INET : 128655682Smarkm inet_af = 1; 128755682Smarkm break; 128855682Smarkm#ifdef HAVE_IPV6 128955682Smarkm case AF_INET6 : 129055682Smarkm inet_af = 2; 129155682Smarkm break; 129255682Smarkm#endif 129355682Smarkm default : 129455682Smarkm errx (1, "bad address family %d", data_addr->sa_family); 129555682Smarkm } 129655682Smarkm 129755682Smarkm asprintf (&cmd, "EPRT |%d|%s|%d|", 129855682Smarkm inet_af, addr_str, ntohs(socket_get_port (data_addr))); 129955682Smarkm 130055682Smarkm overbose = verbose; 130155682Smarkm if (debug == 0) 130255682Smarkm verbose = -1; 130355682Smarkm 130455682Smarkm result = command (cmd); 130555682Smarkm 130655682Smarkm verbose = overbose; 130755682Smarkm 130855682Smarkm if (result == ERROR) { 130955682Smarkm struct sockaddr_in *sin = (struct sockaddr_in *)data_addr; 131055682Smarkm 131155682Smarkm unsigned int a = ntohl(sin->sin_addr.s_addr); 131255682Smarkm unsigned int p = ntohs(sin->sin_port); 131355682Smarkm 131455682Smarkm if (data_addr->sa_family != AF_INET) { 131555682Smarkm warnx ("remote server doesn't support EPRT"); 131655682Smarkm goto bad; 131755682Smarkm } 131855682Smarkm 131955682Smarkm result = command("PORT %d,%d,%d,%d,%d,%d", 132055682Smarkm (a >> 24) & 0xff, 132155682Smarkm (a >> 16) & 0xff, 132255682Smarkm (a >> 8) & 0xff, 132355682Smarkm a & 0xff, 132455682Smarkm (p >> 8) & 0xff, 132555682Smarkm p & 0xff); 132655682Smarkm if (result == ERROR && sendport == -1) { 132755682Smarkm sendport = 0; 132855682Smarkm tmpno = 1; 132955682Smarkm goto noport; 133055682Smarkm } 133155682Smarkm return (result != COMPLETE); 133255682Smarkm } 133355682Smarkm return result != COMPLETE; 133455682Smarkm } 133555682Smarkm if (tmpno) 133655682Smarkm sendport = 1; 133755682Smarkm 133855682Smarkm 133955682Smarkm#ifdef IPTOS_THROUGHPUT 134055682Smarkm socket_set_tos (data, IPTOS_THROUGHPUT); 134155682Smarkm#endif 134255682Smarkm return (0); 134355682Smarkmbad: 134455682Smarkm close (data); 134555682Smarkm data = -1; 134655682Smarkm if (tmpno) 134755682Smarkm sendport = 1; 134855682Smarkm return (1); 134955682Smarkm} 135055682Smarkm 135155682Smarkm/* 135255682Smarkm * Need to start a listen on the data channel before we send the command, 135355682Smarkm * otherwise the server's connect may fail. 135455682Smarkm */ 135555682Smarkmint 135655682Smarkminitconn (void) 135755682Smarkm{ 135855682Smarkm if (passivemode) 135955682Smarkm return passive_mode (); 136055682Smarkm else 136155682Smarkm return active_mode (); 136255682Smarkm} 136355682Smarkm 136455682SmarkmFILE * 136555682Smarkmdataconn (const char *lmode) 136655682Smarkm{ 136755682Smarkm struct sockaddr_storage from_ss; 136855682Smarkm struct sockaddr *from = (struct sockaddr *)&from_ss; 136972445Sassar socklen_t fromlen = sizeof(from_ss); 137072445Sassar int s; 137155682Smarkm 137255682Smarkm if (passivemode) 137355682Smarkm return (fdopen (data, lmode)); 137455682Smarkm 137555682Smarkm s = accept (data, from, &fromlen); 137655682Smarkm if (s < 0) { 137755682Smarkm warn ("accept"); 137855682Smarkm close (data), data = -1; 137955682Smarkm return (NULL); 138055682Smarkm } 138155682Smarkm close (data); 138255682Smarkm data = s; 138355682Smarkm#ifdef IPTOS_THROUGHPUT 138455682Smarkm socket_set_tos (s, IPTOS_THROUGHPUT); 138555682Smarkm#endif 138655682Smarkm return (fdopen (data, lmode)); 138755682Smarkm} 138855682Smarkm 138955682Smarkmvoid 139055682Smarkmptransfer (char *direction, long int bytes, 139155682Smarkm struct timeval * t0, struct timeval * t1) 139255682Smarkm{ 139355682Smarkm struct timeval td; 139455682Smarkm float s; 139555682Smarkm float bs; 139655682Smarkm int prec; 139755682Smarkm char *unit; 139855682Smarkm 139955682Smarkm if (verbose) { 140055682Smarkm td.tv_sec = t1->tv_sec - t0->tv_sec; 140155682Smarkm td.tv_usec = t1->tv_usec - t0->tv_usec; 140255682Smarkm if (td.tv_usec < 0) { 140355682Smarkm td.tv_sec--; 140455682Smarkm td.tv_usec += 1000000; 140555682Smarkm } 140655682Smarkm s = td.tv_sec + (td.tv_usec / 1000000.); 140755682Smarkm bs = bytes / (s ? s : 1); 140855682Smarkm if (bs >= 1048576) { 140955682Smarkm bs /= 1048576; 141055682Smarkm unit = "M"; 141155682Smarkm prec = 2; 141255682Smarkm } else if (bs >= 1024) { 141355682Smarkm bs /= 1024; 141455682Smarkm unit = "k"; 141555682Smarkm prec = 1; 141655682Smarkm } else { 141755682Smarkm unit = ""; 141855682Smarkm prec = 0; 141955682Smarkm } 142055682Smarkm 142155682Smarkm printf ("%ld bytes %s in %.3g seconds (%.*f %sbyte/s)\n", 142255682Smarkm bytes, direction, s, prec, bs, unit); 142355682Smarkm } 142455682Smarkm} 142555682Smarkm 142655682Smarkmvoid 142755682Smarkmpsabort (int sig) 142855682Smarkm{ 142955682Smarkm 143055682Smarkm abrtflag++; 143155682Smarkm} 143255682Smarkm 143355682Smarkmvoid 143455682Smarkmpswitch (int flag) 143555682Smarkm{ 143655682Smarkm sighand oldintr; 143755682Smarkm static struct comvars { 143855682Smarkm int connect; 143955682Smarkm char name[MaxHostNameLen]; 144055682Smarkm struct sockaddr_storage mctl; 144155682Smarkm struct sockaddr_storage hctl; 144255682Smarkm FILE *in; 144355682Smarkm FILE *out; 144455682Smarkm int tpe; 144555682Smarkm int curtpe; 144655682Smarkm int cpnd; 144755682Smarkm int sunqe; 144855682Smarkm int runqe; 144955682Smarkm int mcse; 145055682Smarkm int ntflg; 145155682Smarkm char nti[17]; 145255682Smarkm char nto[17]; 145355682Smarkm int mapflg; 145455682Smarkm char mi[MaxPathLen]; 145555682Smarkm char mo[MaxPathLen]; 145655682Smarkm } proxstruct, tmpstruct; 145755682Smarkm struct comvars *ip, *op; 145855682Smarkm 145955682Smarkm abrtflag = 0; 146055682Smarkm oldintr = signal (SIGINT, psabort); 146155682Smarkm if (flag) { 146255682Smarkm if (proxy) 146355682Smarkm return; 146455682Smarkm ip = &tmpstruct; 146555682Smarkm op = &proxstruct; 146655682Smarkm proxy++; 146755682Smarkm } else { 146855682Smarkm if (!proxy) 146955682Smarkm return; 147055682Smarkm ip = &proxstruct; 147155682Smarkm op = &tmpstruct; 147255682Smarkm proxy = 0; 147355682Smarkm } 147455682Smarkm ip->connect = connected; 147555682Smarkm connected = op->connect; 147655682Smarkm if (hostname) { 147755682Smarkm strlcpy (ip->name, hostname, sizeof (ip->name)); 147855682Smarkm } else 147955682Smarkm ip->name[0] = 0; 148055682Smarkm hostname = op->name; 148155682Smarkm ip->hctl = hisctladdr_ss; 148255682Smarkm hisctladdr_ss = op->hctl; 148355682Smarkm ip->mctl = myctladdr_ss; 148455682Smarkm myctladdr_ss = op->mctl; 148555682Smarkm ip->in = cin; 148655682Smarkm cin = op->in; 148755682Smarkm ip->out = cout; 148855682Smarkm cout = op->out; 148955682Smarkm ip->tpe = type; 149055682Smarkm type = op->tpe; 149155682Smarkm ip->curtpe = curtype; 149255682Smarkm curtype = op->curtpe; 149355682Smarkm ip->cpnd = cpend; 149455682Smarkm cpend = op->cpnd; 149555682Smarkm ip->sunqe = sunique; 149655682Smarkm sunique = op->sunqe; 149755682Smarkm ip->runqe = runique; 149855682Smarkm runique = op->runqe; 149955682Smarkm ip->mcse = mcase; 150055682Smarkm mcase = op->mcse; 150155682Smarkm ip->ntflg = ntflag; 150255682Smarkm ntflag = op->ntflg; 150355682Smarkm strlcpy (ip->nti, ntin, sizeof (ip->nti)); 150455682Smarkm strlcpy (ntin, op->nti, 17); 150555682Smarkm strlcpy (ip->nto, ntout, sizeof (ip->nto)); 150655682Smarkm strlcpy (ntout, op->nto, 17); 150755682Smarkm ip->mapflg = mapflag; 150855682Smarkm mapflag = op->mapflg; 150955682Smarkm strlcpy (ip->mi, mapin, MaxPathLen); 151055682Smarkm strlcpy (mapin, op->mi, MaxPathLen); 151155682Smarkm strlcpy (ip->mo, mapout, MaxPathLen); 151255682Smarkm strlcpy (mapout, op->mo, MaxPathLen); 151355682Smarkm signal(SIGINT, oldintr); 151455682Smarkm if (abrtflag) { 151555682Smarkm abrtflag = 0; 151655682Smarkm (*oldintr) (SIGINT); 151755682Smarkm } 151855682Smarkm} 151955682Smarkm 152055682Smarkmvoid 152155682Smarkmabortpt (int sig) 152255682Smarkm{ 152355682Smarkm 152455682Smarkm printf ("\n"); 152555682Smarkm fflush (stdout); 152655682Smarkm ptabflg++; 152755682Smarkm mflag = 0; 152855682Smarkm abrtflag = 0; 152955682Smarkm longjmp (ptabort, 1); 153055682Smarkm} 153155682Smarkm 153255682Smarkmvoid 153355682Smarkmproxtrans (char *cmd, char *local, char *remote) 153455682Smarkm{ 153555682Smarkm sighand oldintr; 153655682Smarkm int secndflag = 0, prox_type, nfnd; 153755682Smarkm char *cmd2; 153855682Smarkm fd_set mask; 153955682Smarkm 154055682Smarkm if (strcmp (cmd, "RETR")) 154155682Smarkm cmd2 = "RETR"; 154255682Smarkm else 154355682Smarkm cmd2 = runique ? "STOU" : "STOR"; 154455682Smarkm if ((prox_type = type) == 0) { 154555682Smarkm if (unix_server && unix_proxy) 154655682Smarkm prox_type = TYPE_I; 154755682Smarkm else 154855682Smarkm prox_type = TYPE_A; 154955682Smarkm } 155055682Smarkm if (curtype != prox_type) 155155682Smarkm changetype (prox_type, 1); 155255682Smarkm if (command ("PASV") != COMPLETE) { 155355682Smarkm printf ("proxy server does not support third party transfers.\n"); 155455682Smarkm return; 155555682Smarkm } 155655682Smarkm pswitch (0); 155755682Smarkm if (!connected) { 155855682Smarkm printf ("No primary connection\n"); 155955682Smarkm pswitch (1); 156055682Smarkm code = -1; 156155682Smarkm return; 156255682Smarkm } 156355682Smarkm if (curtype != prox_type) 156455682Smarkm changetype (prox_type, 1); 156555682Smarkm if (command ("PORT %s", pasv) != COMPLETE) { 156655682Smarkm pswitch (1); 156755682Smarkm return; 156855682Smarkm } 156955682Smarkm if (setjmp (ptabort)) 157055682Smarkm goto abort; 157155682Smarkm oldintr = signal (SIGINT, abortpt); 157255682Smarkm if (command ("%s %s", cmd, remote) != PRELIM) { 157355682Smarkm signal (SIGINT, oldintr); 157455682Smarkm pswitch (1); 157555682Smarkm return; 157655682Smarkm } 157755682Smarkm sleep (2); 157855682Smarkm pswitch (1); 157955682Smarkm secndflag++; 158055682Smarkm if (command ("%s %s", cmd2, local) != PRELIM) 158155682Smarkm goto abort; 158255682Smarkm ptflag++; 158355682Smarkm getreply (0); 158455682Smarkm pswitch (0); 158555682Smarkm getreply (0); 158655682Smarkm signal (SIGINT, oldintr); 158755682Smarkm pswitch (1); 158855682Smarkm ptflag = 0; 158955682Smarkm printf ("local: %s remote: %s\n", local, remote); 159055682Smarkm return; 159155682Smarkmabort: 159255682Smarkm signal (SIGINT, SIG_IGN); 159355682Smarkm ptflag = 0; 159455682Smarkm if (strcmp (cmd, "RETR") && !proxy) 159555682Smarkm pswitch (1); 159655682Smarkm else if (!strcmp (cmd, "RETR") && proxy) 159755682Smarkm pswitch (0); 159855682Smarkm if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ 159955682Smarkm if (command ("%s %s", cmd2, local) != PRELIM) { 160055682Smarkm pswitch (0); 160155682Smarkm if (cpend) 160255682Smarkm abort_remote ((FILE *) NULL); 160355682Smarkm } 160455682Smarkm pswitch (1); 160555682Smarkm if (ptabflg) 160655682Smarkm code = -1; 160755682Smarkm signal (SIGINT, oldintr); 160855682Smarkm return; 160955682Smarkm } 161055682Smarkm if (cpend) 161155682Smarkm abort_remote ((FILE *) NULL); 161255682Smarkm pswitch (!proxy); 161355682Smarkm if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ 161455682Smarkm if (command ("%s %s", cmd2, local) != PRELIM) { 161555682Smarkm pswitch (0); 161655682Smarkm if (cpend) 161755682Smarkm abort_remote ((FILE *) NULL); 161855682Smarkm pswitch (1); 161955682Smarkm if (ptabflg) 162055682Smarkm code = -1; 162155682Smarkm signal (SIGINT, oldintr); 162255682Smarkm return; 162355682Smarkm } 162455682Smarkm } 162555682Smarkm if (cpend) 162655682Smarkm abort_remote ((FILE *) NULL); 162755682Smarkm pswitch (!proxy); 162855682Smarkm if (cpend) { 162955682Smarkm FD_ZERO (&mask); 163072445Sassar if (fileno(cin) >= FD_SETSIZE) 163172445Sassar errx (1, "fd too large"); 163255682Smarkm FD_SET (fileno (cin), &mask); 163355682Smarkm if ((nfnd = empty (&mask, 10)) <= 0) { 163455682Smarkm if (nfnd < 0) { 163555682Smarkm warn ("abort"); 163655682Smarkm } 163755682Smarkm if (ptabflg) 163855682Smarkm code = -1; 163955682Smarkm lostpeer (0); 164055682Smarkm } 164155682Smarkm getreply (0); 164255682Smarkm getreply (0); 164355682Smarkm } 164455682Smarkm if (proxy) 164555682Smarkm pswitch (0); 164655682Smarkm pswitch (1); 164755682Smarkm if (ptabflg) 164855682Smarkm code = -1; 164955682Smarkm signal (SIGINT, oldintr); 165055682Smarkm} 165155682Smarkm 165255682Smarkmvoid 165355682Smarkmreset (int argc, char **argv) 165455682Smarkm{ 165555682Smarkm fd_set mask; 165655682Smarkm int nfnd = 1; 165755682Smarkm 165855682Smarkm FD_ZERO (&mask); 165955682Smarkm while (nfnd > 0) { 166072445Sassar if (fileno (cin) >= FD_SETSIZE) 166172445Sassar errx (1, "fd too large"); 166255682Smarkm FD_SET (fileno (cin), &mask); 166355682Smarkm if ((nfnd = empty (&mask, 0)) < 0) { 166455682Smarkm warn ("reset"); 166555682Smarkm code = -1; 166655682Smarkm lostpeer(0); 166755682Smarkm } else if (nfnd) { 166855682Smarkm getreply(0); 166955682Smarkm } 167055682Smarkm } 167155682Smarkm} 167255682Smarkm 167355682Smarkmchar * 167455682Smarkmgunique (char *local) 167555682Smarkm{ 167655682Smarkm static char new[MaxPathLen]; 167755682Smarkm char *cp = strrchr (local, '/'); 167855682Smarkm int d, count = 0; 167955682Smarkm char ext = '1'; 168055682Smarkm 168155682Smarkm if (cp) 168255682Smarkm *cp = '\0'; 168355682Smarkm d = access (cp ? local : ".", 2); 168455682Smarkm if (cp) 168555682Smarkm *cp = '/'; 168655682Smarkm if (d < 0) { 168755682Smarkm warn ("local: %s", local); 168855682Smarkm return NULL; 168955682Smarkm } 169055682Smarkm strlcpy (new, local, sizeof(new)); 169155682Smarkm cp = new + strlen(new); 169255682Smarkm *cp++ = '.'; 169355682Smarkm while (!d) { 169455682Smarkm if (++count == 100) { 169555682Smarkm printf ("runique: can't find unique file name.\n"); 169655682Smarkm return NULL; 169755682Smarkm } 169855682Smarkm *cp++ = ext; 169955682Smarkm *cp = '\0'; 170055682Smarkm if (ext == '9') 170155682Smarkm ext = '0'; 170255682Smarkm else 170355682Smarkm ext++; 170455682Smarkm if ((d = access (new, 0)) < 0) 170555682Smarkm break; 170655682Smarkm if (ext != '0') 170755682Smarkm cp--; 170855682Smarkm else if (*(cp - 2) == '.') 170955682Smarkm *(cp - 1) = '1'; 171055682Smarkm else { 171155682Smarkm *(cp - 2) = *(cp - 2) + 1; 171255682Smarkm cp--; 171355682Smarkm } 171455682Smarkm } 171555682Smarkm return (new); 171655682Smarkm} 171755682Smarkm 171855682Smarkmvoid 171955682Smarkmabort_remote (FILE * din) 172055682Smarkm{ 172155682Smarkm char buf[BUFSIZ]; 172255682Smarkm int nfnd; 172355682Smarkm fd_set mask; 172455682Smarkm 172555682Smarkm /* 172655682Smarkm * send IAC in urgent mode instead of DM because 4.3BSD places oob mark 172755682Smarkm * after urgent byte rather than before as is protocol now 172855682Smarkm */ 172955682Smarkm snprintf (buf, sizeof (buf), "%c%c%c", IAC, IP, IAC); 173055682Smarkm if (send (fileno (cout), buf, 3, MSG_OOB) != 3) 173155682Smarkm warn ("abort"); 173255682Smarkm fprintf (cout, "%cABOR\r\n", DM); 173355682Smarkm fflush (cout); 173455682Smarkm FD_ZERO (&mask); 173572445Sassar if (fileno (cin) >= FD_SETSIZE) 173672445Sassar errx (1, "fd too large"); 173755682Smarkm FD_SET (fileno (cin), &mask); 173855682Smarkm if (din) { 173972445Sassar if (fileno (din) >= FD_SETSIZE) 174072445Sassar errx (1, "fd too large"); 174155682Smarkm FD_SET (fileno (din), &mask); 174255682Smarkm } 174355682Smarkm if ((nfnd = empty (&mask, 10)) <= 0) { 174455682Smarkm if (nfnd < 0) { 174555682Smarkm warn ("abort"); 174655682Smarkm } 174755682Smarkm if (ptabflg) 174855682Smarkm code = -1; 174955682Smarkm lostpeer (0); 175055682Smarkm } 175155682Smarkm if (din && FD_ISSET (fileno (din), &mask)) { 175255682Smarkm while (read (fileno (din), buf, BUFSIZ) > 0) 175355682Smarkm /* LOOP */ ; 175455682Smarkm } 175555682Smarkm if (getreply (0) == ERROR && code == 552) { 175655682Smarkm /* 552 needed for nic style abort */ 175755682Smarkm getreply (0); 175855682Smarkm } 175955682Smarkm getreply (0); 176055682Smarkm} 1761