17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28*92163adaSToomas Soome /* All Rights Reserved */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
327c478bd9Sstevel@tonic-gate * The Regents of the University of California
337c478bd9Sstevel@tonic-gate * All Rights Reserved
347c478bd9Sstevel@tonic-gate *
357c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
367c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
377c478bd9Sstevel@tonic-gate * contributors.
387c478bd9Sstevel@tonic-gate */
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate #include "ftp_var.h"
417c478bd9Sstevel@tonic-gate #include <arpa/nameser.h>
427c478bd9Sstevel@tonic-gate #include <sys/types.h>
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate /*
457c478bd9Sstevel@tonic-gate * WRITE() returns:
46*92163adaSToomas Soome * >0 no error
477c478bd9Sstevel@tonic-gate * -1 error, errorno is set
487c478bd9Sstevel@tonic-gate * -2 security error (secure_write() only)
497c478bd9Sstevel@tonic-gate */
507c478bd9Sstevel@tonic-gate #define PUTC(x, y) secure_putc(x, y)
517c478bd9Sstevel@tonic-gate #define READ(x, y, z) secure_read(x, y, z)
527c478bd9Sstevel@tonic-gate #define WRITE(x, y, z) secure_write(x, y, z)
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate static struct sockaddr_in6 data_addr;
557c478bd9Sstevel@tonic-gate int data = -1;
567c478bd9Sstevel@tonic-gate static int abrtflag = 0;
577c478bd9Sstevel@tonic-gate static int ptflag = 0;
587c478bd9Sstevel@tonic-gate static jmp_buf sendabort;
597c478bd9Sstevel@tonic-gate static jmp_buf recvabort;
60*92163adaSToomas Soome static jmp_buf ptabort;
617c478bd9Sstevel@tonic-gate static int ptabflg;
627c478bd9Sstevel@tonic-gate static boolean_t pasv_refused;
637c478bd9Sstevel@tonic-gate boolean_t eport_supported = B_TRUE;
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate * For IPv6 addresses, EPSV will be the default (rather than EPRT/LPRT).
667c478bd9Sstevel@tonic-gate * The EPSV/ERPT ftp protocols are specified in RFC 2428.
677c478bd9Sstevel@tonic-gate *
687c478bd9Sstevel@tonic-gate * Perform EPSV if passivemode is set and ipv6rem is TRUE.
697c478bd9Sstevel@tonic-gate */
707c478bd9Sstevel@tonic-gate static boolean_t ipv6rem;
717c478bd9Sstevel@tonic-gate int use_eprt = 0; /* Testing option that specifies EPRT by default */
727c478bd9Sstevel@tonic-gate FILE *ctrl_in, *ctrl_out;
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate static void abortsend(int sig);
757c478bd9Sstevel@tonic-gate static void abortpt(int sig);
767c478bd9Sstevel@tonic-gate static void proxtrans(char *cmd, char *local, char *remote);
777c478bd9Sstevel@tonic-gate static void cmdabort(int sig);
787c478bd9Sstevel@tonic-gate static int empty(struct fd_set *mask, int sec, int nfds);
797c478bd9Sstevel@tonic-gate static void abortrecv(int sig);
807c478bd9Sstevel@tonic-gate static int initconn(void);
817c478bd9Sstevel@tonic-gate static FILE *dataconn(char *mode);
827c478bd9Sstevel@tonic-gate static void ptransfer(char *direction, off_t bytes, hrtime_t t0,
837c478bd9Sstevel@tonic-gate hrtime_t t1, char *local, char *remote);
847c478bd9Sstevel@tonic-gate static void psabort(int sig);
857c478bd9Sstevel@tonic-gate static char *gunique(char *local);
867c478bd9Sstevel@tonic-gate static const char *inet_ntop_native(int af, const void *src, char *dst,
877c478bd9Sstevel@tonic-gate size_t size);
887c478bd9Sstevel@tonic-gate static ssize_t timedread(int fd, void *buf, size_t maxlen, int timeout);
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gate static int secure_command(char *);
917c478bd9Sstevel@tonic-gate static int decode_reply(uchar_t *, int, uchar_t *, int, boolean_t *);
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate static ssize_t bufcnt; /* number of bytes in buf[] */
947c478bd9Sstevel@tonic-gate static char *bufp; /* next character in buf */
957c478bd9Sstevel@tonic-gate static int buferr; /* last errno */
967c478bd9Sstevel@tonic-gate static size_t bufsize;
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate static void fdio_setbuf(char *buffer, size_t bufsize);
997c478bd9Sstevel@tonic-gate static int fdio_fillbuf(int fd);
1007c478bd9Sstevel@tonic-gate static int fdio_error(int fd);
1017c478bd9Sstevel@tonic-gate #define fdio_getc(fd) (--bufcnt < 0 ? fdio_fillbuf((fd)) : \
1027c478bd9Sstevel@tonic-gate ((unsigned char)*bufp++))
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate #define MAX(a, b) ((a) > (b) ? (a) : (b))
1057c478bd9Sstevel@tonic-gate #define NONZERO(x) ((x) == 0 ? 1 : (x))
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate static void
fdio_setbuf(char * buffer,size_t maxsize)1087c478bd9Sstevel@tonic-gate fdio_setbuf(char *buffer, size_t maxsize)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate buf = buffer;
1117c478bd9Sstevel@tonic-gate bufp = buf;
1127c478bd9Sstevel@tonic-gate bufcnt = 0;
1137c478bd9Sstevel@tonic-gate buferr = 0;
1147c478bd9Sstevel@tonic-gate bufsize = maxsize;
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate static int
fdio_fillbuf(int fd)1187c478bd9Sstevel@tonic-gate fdio_fillbuf(int fd)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate bufcnt = timedread(fd, buf, bufsize, timeout);
1217c478bd9Sstevel@tonic-gate if (bufcnt < 0)
1227c478bd9Sstevel@tonic-gate buferr = errno;
1237c478bd9Sstevel@tonic-gate if (bufcnt <= 0)
1247c478bd9Sstevel@tonic-gate return (EOF);
1257c478bd9Sstevel@tonic-gate bufp = buf;
1267c478bd9Sstevel@tonic-gate bufcnt--;
1277c478bd9Sstevel@tonic-gate return ((unsigned char)*bufp++);
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate * fdio_error - used on a file descriptor instead of ferror()
1327c478bd9Sstevel@tonic-gate */
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1357c478bd9Sstevel@tonic-gate static int
fdio_error(int fd)1367c478bd9Sstevel@tonic-gate fdio_error(int fd)
1377c478bd9Sstevel@tonic-gate {
1387c478bd9Sstevel@tonic-gate return (buferr);
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate * timedread - read buffer (like "read"), but with timeout (in seconds)
1437c478bd9Sstevel@tonic-gate */
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate static ssize_t
timedread(int fd,void * buf,size_t size,int timeout)1467c478bd9Sstevel@tonic-gate timedread(int fd, void *buf, size_t size, int timeout)
1477c478bd9Sstevel@tonic-gate {
1487c478bd9Sstevel@tonic-gate struct fd_set mask;
1497c478bd9Sstevel@tonic-gate struct timeval tv;
1507c478bd9Sstevel@tonic-gate int err;
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate if (!timeout)
1537c478bd9Sstevel@tonic-gate return (READ(fd, buf, size));
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate tv.tv_sec = (time_t)timeout;
1567c478bd9Sstevel@tonic-gate tv.tv_usec = 0;
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate FD_ZERO(&mask);
1597c478bd9Sstevel@tonic-gate FD_SET(fd, &mask);
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate err = select(fd + 1, &mask, NULL, NULL, &tv);
1627c478bd9Sstevel@tonic-gate if (err == 0)
1637c478bd9Sstevel@tonic-gate errno = ETIMEDOUT;
1647c478bd9Sstevel@tonic-gate if (err <= 0)
1657c478bd9Sstevel@tonic-gate return (-1);
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate return (READ(fd, buf, size));
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate
1717c478bd9Sstevel@tonic-gate char *
hookup(char * host,char * service)1727c478bd9Sstevel@tonic-gate hookup(char *host, char *service)
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate struct addrinfo hints, *ai = NULL, *ai_head;
1757c478bd9Sstevel@tonic-gate int s;
1767c478bd9Sstevel@tonic-gate socklen_t len;
1777c478bd9Sstevel@tonic-gate static char hostnamebuf[80];
1787c478bd9Sstevel@tonic-gate struct in6_addr ipv6addr;
1797c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN];
1807c478bd9Sstevel@tonic-gate int error_num;
1817c478bd9Sstevel@tonic-gate int on = 1;
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate * There appears to be a bug in getaddrinfo() where, if the
1857c478bd9Sstevel@tonic-gate * ai_family is set to AF_INET6, and the host is a v4-only
1867c478bd9Sstevel@tonic-gate * host, getaddrinfo() returns an error instead of returning
1877c478bd9Sstevel@tonic-gate * an v4-mapped ipv6 address. Therefore the ai_family is
1887c478bd9Sstevel@tonic-gate * set to AF_UNSPEC and any returned v4 addresses are
1897c478bd9Sstevel@tonic-gate * explicitly mapped within ftp.
1907c478bd9Sstevel@tonic-gate */
1917c478bd9Sstevel@tonic-gate bzero((char *)&remctladdr, sizeof (remctladdr));
1927c478bd9Sstevel@tonic-gate bzero((char *)&hints, sizeof (hints));
1937c478bd9Sstevel@tonic-gate hints.ai_flags = AI_CANONNAME;
1947c478bd9Sstevel@tonic-gate hints.ai_family = AF_UNSPEC;
1957c478bd9Sstevel@tonic-gate hints.ai_socktype = SOCK_STREAM;
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate error_num = getaddrinfo(host, service, &hints, &ai);
1987c478bd9Sstevel@tonic-gate if (error_num != 0) {
1997c478bd9Sstevel@tonic-gate if (error_num == EAI_AGAIN) {
2007c478bd9Sstevel@tonic-gate (void) printf(
2017c478bd9Sstevel@tonic-gate "%s: unknown host or invalid literal address "
2027c478bd9Sstevel@tonic-gate "(try again later)\n", host);
2037c478bd9Sstevel@tonic-gate } else {
2047c478bd9Sstevel@tonic-gate (void) printf(
2057c478bd9Sstevel@tonic-gate "%s: unknown host or invalid literal address\n",
2067c478bd9Sstevel@tonic-gate host);
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate code = -1;
2097c478bd9Sstevel@tonic-gate return ((char *)0);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate ai_head = ai;
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate /*
2157c478bd9Sstevel@tonic-gate * If ai_canonname is a IPv4-mapped IPv6 literal, we'll convert it to
2167c478bd9Sstevel@tonic-gate * IPv4 literal address.
2177c478bd9Sstevel@tonic-gate */
2187c478bd9Sstevel@tonic-gate if (ai->ai_canonname != NULL &&
2197c478bd9Sstevel@tonic-gate (inet_pton(AF_INET6, ai->ai_canonname, &ipv6addr) > 0) &&
2207c478bd9Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&ipv6addr)) {
2217c478bd9Sstevel@tonic-gate struct in_addr src4;
2227c478bd9Sstevel@tonic-gate hostnamebuf[0] = '\0';
2237c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&ipv6addr, &src4);
2247c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET, &src4, hostnamebuf,
2257c478bd9Sstevel@tonic-gate sizeof (hostnamebuf));
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate /*
2287c478bd9Sstevel@tonic-gate * It can even be the case that the "host" supplied by the user
2297c478bd9Sstevel@tonic-gate * can be a IPv4-mapped IPv6 literal. So, let's fix that too.
2307c478bd9Sstevel@tonic-gate */
2317c478bd9Sstevel@tonic-gate if ((inet_pton(AF_INET6, host, &ipv6addr) > 0) &&
2327c478bd9Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&ipv6addr) &&
2337c478bd9Sstevel@tonic-gate strlen(hostnamebuf) <= strlen(host)) {
2347c478bd9Sstevel@tonic-gate (void) strlcpy(host, hostnamebuf, strlen(host) + 1);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate } else {
2377c478bd9Sstevel@tonic-gate reset_timer();
2387c478bd9Sstevel@tonic-gate (void) strlcpy(hostnamebuf,
2397c478bd9Sstevel@tonic-gate (ai->ai_canonname ? ai->ai_canonname : host),
2407c478bd9Sstevel@tonic-gate sizeof (hostnamebuf));
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate hostname = hostnamebuf;
2447c478bd9Sstevel@tonic-gate for (;;) {
2457c478bd9Sstevel@tonic-gate int oerrno;
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate bcopy(ai->ai_addr, &remctladdr, ai->ai_addrlen);
2487c478bd9Sstevel@tonic-gate if (ai->ai_addr->sa_family == AF_INET) {
2497c478bd9Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(
2507c478bd9Sstevel@tonic-gate &(((struct sockaddr_in *)ai->ai_addr)->sin_addr),
2517c478bd9Sstevel@tonic-gate &remctladdr.sin6_addr);
2527c478bd9Sstevel@tonic-gate remctladdr.sin6_family = AF_INET6;
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate s = socket(AF_INET6, SOCK_STREAM, 0);
2567c478bd9Sstevel@tonic-gate if (s < 0) {
2577c478bd9Sstevel@tonic-gate perror("ftp: socket");
2587c478bd9Sstevel@tonic-gate code = -1;
2597c478bd9Sstevel@tonic-gate freeaddrinfo(ai_head);
2607c478bd9Sstevel@tonic-gate return (0);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate if (timeout && setsockopt(s, IPPROTO_TCP, TCP_ABORT_THRESHOLD,
2637c478bd9Sstevel@tonic-gate (char *)&timeoutms, sizeof (timeoutms)) < 0 && debug)
2647c478bd9Sstevel@tonic-gate perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)");
2657c478bd9Sstevel@tonic-gate reset_timer();
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate error_num = connect(s, (struct sockaddr *)&remctladdr,
2687c478bd9Sstevel@tonic-gate sizeof (remctladdr));
2697c478bd9Sstevel@tonic-gate oerrno = errno;
2707c478bd9Sstevel@tonic-gate if (error_num >= 0)
2717c478bd9Sstevel@tonic-gate break;
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate /*
2747c478bd9Sstevel@tonic-gate * Maintain message behavior: only include the address in
2757c478bd9Sstevel@tonic-gate * our error message if we have another one to try; if this
2767c478bd9Sstevel@tonic-gate * is the last address on our list, just print the error.
2777c478bd9Sstevel@tonic-gate */
2787c478bd9Sstevel@tonic-gate if (ai->ai_next != NULL) {
2797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ftp: connect to address %s: ",
2807c478bd9Sstevel@tonic-gate inet_ntop_native(ai->ai_addr->sa_family,
2817c478bd9Sstevel@tonic-gate (void *)ai->ai_addr, abuf, sizeof (abuf)));
2827c478bd9Sstevel@tonic-gate errno = oerrno;
2837c478bd9Sstevel@tonic-gate perror((char *)0);
2847c478bd9Sstevel@tonic-gate } else {
2857c478bd9Sstevel@tonic-gate perror("ftp: connect");
2867c478bd9Sstevel@tonic-gate code = -1;
2877c478bd9Sstevel@tonic-gate freeaddrinfo(ai_head);
2887c478bd9Sstevel@tonic-gate goto bad;
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate ai = ai->ai_next;
2917c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "Trying %s...\n",
2927c478bd9Sstevel@tonic-gate inet_ntop_native(ai->ai_addr->sa_family,
2937c478bd9Sstevel@tonic-gate (void *)ai->ai_addr, abuf, sizeof (abuf)));
2947c478bd9Sstevel@tonic-gate (void) close(s);
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate /* Set ipv6rem to TRUE if control connection is a native IPv6 address */
2997c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&remctladdr.sin6_addr))
3007c478bd9Sstevel@tonic-gate ipv6rem = B_FALSE;
3017c478bd9Sstevel@tonic-gate else
3027c478bd9Sstevel@tonic-gate ipv6rem = B_TRUE;
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate freeaddrinfo(ai_head);
3067c478bd9Sstevel@tonic-gate ai = NULL;
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate /*
3097c478bd9Sstevel@tonic-gate * Set passive mode flag on by default only if a native IPv6 address
3107c478bd9Sstevel@tonic-gate * is being used -and- the use_eprt is not set.
3117c478bd9Sstevel@tonic-gate */
3127c478bd9Sstevel@tonic-gate if (ipv6rem == B_TRUE && use_eprt == 0)
3137c478bd9Sstevel@tonic-gate passivemode = 1;
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate len = sizeof (myctladdr);
3167c478bd9Sstevel@tonic-gate if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
3177c478bd9Sstevel@tonic-gate perror("ftp: getsockname");
3187c478bd9Sstevel@tonic-gate code = -1;
3197c478bd9Sstevel@tonic-gate goto bad;
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate ctrl_in = fdopen(s, "r");
3227c478bd9Sstevel@tonic-gate ctrl_out = fdopen(s, "w");
3237c478bd9Sstevel@tonic-gate if (ctrl_in == NULL || ctrl_out == NULL) {
3247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ftp: fdopen failed.\n");
3257c478bd9Sstevel@tonic-gate if (ctrl_in)
3267c478bd9Sstevel@tonic-gate (void) fclose(ctrl_in);
3277c478bd9Sstevel@tonic-gate if (ctrl_out)
3287c478bd9Sstevel@tonic-gate (void) fclose(ctrl_out);
3297c478bd9Sstevel@tonic-gate code = -1;
3307c478bd9Sstevel@tonic-gate goto bad;
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate if (verbose)
3337c478bd9Sstevel@tonic-gate (void) printf("Connected to %s.\n", hostname);
3347c478bd9Sstevel@tonic-gate if (getreply(0) > 2) { /* read startup message from server */
3357c478bd9Sstevel@tonic-gate if (ctrl_in)
3367c478bd9Sstevel@tonic-gate (void) fclose(ctrl_in);
3377c478bd9Sstevel@tonic-gate if (ctrl_out)
3387c478bd9Sstevel@tonic-gate (void) fclose(ctrl_out);
3397c478bd9Sstevel@tonic-gate ctrl_in = ctrl_out = NULL;
3407c478bd9Sstevel@tonic-gate ctrl_in = ctrl_out = NULL;
3417c478bd9Sstevel@tonic-gate code = -1;
3427c478bd9Sstevel@tonic-gate goto bad;
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
3457c478bd9Sstevel@tonic-gate sizeof (on)) < 0 && debug)
3467c478bd9Sstevel@tonic-gate perror("ftp: setsockopt (SO_OOBINLINE)");
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate return (hostname);
3497c478bd9Sstevel@tonic-gate bad:
3507c478bd9Sstevel@tonic-gate (void) close(s);
3517c478bd9Sstevel@tonic-gate return ((char *)0);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate int
login(char * host)3557c478bd9Sstevel@tonic-gate login(char *host)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate char tmp[80];
3587c478bd9Sstevel@tonic-gate char *user, *pass, *acct;
3597c478bd9Sstevel@tonic-gate int n, aflag = 0;
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate user = pass = acct = 0;
3627c478bd9Sstevel@tonic-gate if (ruserpass(host, &user, &pass, &acct) < 0) {
3637c478bd9Sstevel@tonic-gate disconnect(0, NULL);
3647c478bd9Sstevel@tonic-gate code = -1;
3657c478bd9Sstevel@tonic-gate return (0);
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate if (user == NULL) {
3687c478bd9Sstevel@tonic-gate char *myname = getlogin();
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate if (myname == NULL) {
3717c478bd9Sstevel@tonic-gate struct passwd *pp = getpwuid(getuid());
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate if (pp != NULL)
3747c478bd9Sstevel@tonic-gate myname = pp->pw_name;
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate stop_timer();
3777c478bd9Sstevel@tonic-gate (void) printf("Name (%s:%s): ", host,
378*92163adaSToomas Soome (myname == NULL) ? "" : myname);
3797c478bd9Sstevel@tonic-gate *tmp = '\0';
3807c478bd9Sstevel@tonic-gate if (fgets(tmp, sizeof (tmp) - 1, stdin) != NULL)
3817c478bd9Sstevel@tonic-gate tmp[strlen(tmp) - 1] = '\0';
3827c478bd9Sstevel@tonic-gate if (*tmp != '\0')
3837c478bd9Sstevel@tonic-gate user = tmp;
3847c478bd9Sstevel@tonic-gate else if (myname != NULL)
3857c478bd9Sstevel@tonic-gate user = myname;
3867c478bd9Sstevel@tonic-gate else
3877c478bd9Sstevel@tonic-gate return (0);
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate n = command("USER %s", user);
3907c478bd9Sstevel@tonic-gate if (n == CONTINUE) {
3917c478bd9Sstevel@tonic-gate int oldclevel;
3927c478bd9Sstevel@tonic-gate if (pass == NULL)
3937c478bd9Sstevel@tonic-gate pass = mygetpass("Password:");
3947c478bd9Sstevel@tonic-gate oldclevel = clevel;
3957c478bd9Sstevel@tonic-gate clevel = PROT_P;
3967c478bd9Sstevel@tonic-gate n = command("PASS %s", pass);
3977c478bd9Sstevel@tonic-gate /* level may have changed */
3987c478bd9Sstevel@tonic-gate if (clevel == PROT_P)
3997c478bd9Sstevel@tonic-gate clevel = oldclevel;
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate if (n == CONTINUE) {
4027c478bd9Sstevel@tonic-gate aflag++;
4037c478bd9Sstevel@tonic-gate if (acct == NULL)
4047c478bd9Sstevel@tonic-gate acct = mygetpass("Account:");
4057c478bd9Sstevel@tonic-gate n = command("ACCT %s", acct);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate if (n != COMPLETE) {
4087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Login failed.\n");
4097c478bd9Sstevel@tonic-gate return (0);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate if (!aflag && acct != NULL)
4127c478bd9Sstevel@tonic-gate (void) command("ACCT %s", acct);
4137c478bd9Sstevel@tonic-gate if (proxy)
4147c478bd9Sstevel@tonic-gate return (1);
4157c478bd9Sstevel@tonic-gate for (n = 0; n < macnum; ++n) {
4167c478bd9Sstevel@tonic-gate if (strcmp("init", macros[n].mac_name) == 0) {
4177c478bd9Sstevel@tonic-gate (void) strlcpy(line, "$init", sizeof (line));
4187c478bd9Sstevel@tonic-gate makeargv();
4197c478bd9Sstevel@tonic-gate domacro(margc, margv);
4207c478bd9Sstevel@tonic-gate break;
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate return (1);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4277c478bd9Sstevel@tonic-gate static void
cmdabort(int sig)4287c478bd9Sstevel@tonic-gate cmdabort(int sig)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate (void) printf("\n");
4317c478bd9Sstevel@tonic-gate (void) fflush(stdout);
4327c478bd9Sstevel@tonic-gate abrtflag++;
4337c478bd9Sstevel@tonic-gate if (ptflag)
4347c478bd9Sstevel@tonic-gate longjmp(ptabort, 1);
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate int
command(char * fmt,...)4387c478bd9Sstevel@tonic-gate command(char *fmt, ...)
4397c478bd9Sstevel@tonic-gate {
4407c478bd9Sstevel@tonic-gate int r;
4417c478bd9Sstevel@tonic-gate void (*oldintr)();
4427c478bd9Sstevel@tonic-gate va_list ap;
4437c478bd9Sstevel@tonic-gate char command_buf[FTPBUFSIZ];
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate va_start(ap, fmt);
4467c478bd9Sstevel@tonic-gate abrtflag = 0;
4477c478bd9Sstevel@tonic-gate if (debug) {
4487c478bd9Sstevel@tonic-gate (void) printf("---> ");
4497c478bd9Sstevel@tonic-gate if (strncmp("PASS ", fmt, 5) == 0)
4507c478bd9Sstevel@tonic-gate (void) printf("PASS XXXX");
4517c478bd9Sstevel@tonic-gate else if (strncmp("ACCT ", fmt, 5) == 0)
4527c478bd9Sstevel@tonic-gate (void) printf("ACCT XXXX");
4537c478bd9Sstevel@tonic-gate else
4547c478bd9Sstevel@tonic-gate (void) vfprintf(stdout, fmt, ap);
4557c478bd9Sstevel@tonic-gate (void) printf("\n");
4567c478bd9Sstevel@tonic-gate (void) fflush(stdout);
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate if (ctrl_out == NULL) {
4597c478bd9Sstevel@tonic-gate perror("No control connection for command");
4607c478bd9Sstevel@tonic-gate code = -1;
4617c478bd9Sstevel@tonic-gate return (0);
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate oldintr = signal(SIGINT, cmdabort);
4647c478bd9Sstevel@tonic-gate (void) vsnprintf(command_buf, FTPBUFSIZ, fmt, ap);
4657c478bd9Sstevel@tonic-gate va_end(ap);
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate again: if (secure_command(command_buf) == 0)
4687c478bd9Sstevel@tonic-gate return (0);
4697c478bd9Sstevel@tonic-gate
4707c478bd9Sstevel@tonic-gate cpend = 1;
4717c478bd9Sstevel@tonic-gate r = getreply(strcmp(fmt, "QUIT") == 0);
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate if (r == 533 && clevel == PROT_P) {
4747c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ENC command not supported at server; "
475*92163adaSToomas Soome "retrying under MIC...\n");
4767c478bd9Sstevel@tonic-gate clevel = PROT_S;
4777c478bd9Sstevel@tonic-gate goto again;
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate if (abrtflag && oldintr != SIG_IGN)
4817c478bd9Sstevel@tonic-gate (*oldintr)();
4827c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
4837c478bd9Sstevel@tonic-gate return (r);
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate /* Need to save reply reponse from server for use in EPSV mode */
4877c478bd9Sstevel@tonic-gate char reply_string[BUFSIZ];
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate int
getreply(int expecteof)4907c478bd9Sstevel@tonic-gate getreply(int expecteof)
4917c478bd9Sstevel@tonic-gate {
4927c478bd9Sstevel@tonic-gate /*
4937c478bd9Sstevel@tonic-gate * 'code' is the 3 digit reply code, form xyz
4947c478bd9Sstevel@tonic-gate * 'dig' counts the number of digits we are along in the code
4957c478bd9Sstevel@tonic-gate * 'n' is the first digit of 'code'
4967c478bd9Sstevel@tonic-gate * 4yz: resource unavailable
4977c478bd9Sstevel@tonic-gate * 5yz: an error occurred, failure
4987c478bd9Sstevel@tonic-gate * 6yz: protected reply (is_base64 == TRUE)
4997c478bd9Sstevel@tonic-gate * 631 - base 64 encoded safe message
500*92163adaSToomas Soome * 632 - base 64 encoded private message
501*92163adaSToomas Soome * 633 - base 64 encoded confidential message
5027c478bd9Sstevel@tonic-gate * 'c' is a wide char type, for international char sets
5037c478bd9Sstevel@tonic-gate */
5047c478bd9Sstevel@tonic-gate wint_t c;
5057c478bd9Sstevel@tonic-gate int i, n;
5067c478bd9Sstevel@tonic-gate int dig;
5077c478bd9Sstevel@tonic-gate int originalcode = 0, continuation = 0;
5087c478bd9Sstevel@tonic-gate void (*oldintr)();
5097c478bd9Sstevel@tonic-gate int pflag = 0;
5107c478bd9Sstevel@tonic-gate char *pt = pasv;
5117c478bd9Sstevel@tonic-gate /*
5127c478bd9Sstevel@tonic-gate * this is the input and output buffers needed for
5137c478bd9Sstevel@tonic-gate * radix_encode()
5147c478bd9Sstevel@tonic-gate */
5157c478bd9Sstevel@tonic-gate unsigned char ibuf[FTPBUFSIZ];
5167c478bd9Sstevel@tonic-gate unsigned char obuf[FTPBUFSIZ];
5177c478bd9Sstevel@tonic-gate boolean_t is_base64;
5187c478bd9Sstevel@tonic-gate int len;
5197c478bd9Sstevel@tonic-gate char *cp;
5207c478bd9Sstevel@tonic-gate
5217c478bd9Sstevel@tonic-gate if (!ctrl_in)
5227c478bd9Sstevel@tonic-gate return (0);
5237c478bd9Sstevel@tonic-gate oldintr = signal(SIGINT, cmdabort);
5247c478bd9Sstevel@tonic-gate
5257c478bd9Sstevel@tonic-gate ibuf[0] = '\0';
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate if (reply_parse)
5287c478bd9Sstevel@tonic-gate reply_ptr = reply_buf;
5297c478bd9Sstevel@tonic-gate
5307c478bd9Sstevel@tonic-gate for (;;) {
5317c478bd9Sstevel@tonic-gate obuf[0] = '\0';
5327c478bd9Sstevel@tonic-gate dig = n = code = 0;
5337c478bd9Sstevel@tonic-gate i = is_base64 = 0;
5347c478bd9Sstevel@tonic-gate cp = reply_string;
5357c478bd9Sstevel@tonic-gate reset_timer(); /* once per line */
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate while ((c = ibuf[0] ?
5387c478bd9Sstevel@tonic-gate (wint_t)ibuf[i++] : fgetwc(ctrl_in)) != '\n') {
5397c478bd9Sstevel@tonic-gate
540*92163adaSToomas Soome if (i >= FTPBUFSIZ)
5417c478bd9Sstevel@tonic-gate break;
542*92163adaSToomas Soome
543*92163adaSToomas Soome if (c == IAC) { /* handle telnet commands */
544*92163adaSToomas Soome switch (c = fgetwc(ctrl_in)) {
545*92163adaSToomas Soome case WILL:
546*92163adaSToomas Soome case WONT:
547*92163adaSToomas Soome c = fgetwc(ctrl_in);
548*92163adaSToomas Soome (void) fprintf(ctrl_out, "%c%c%wc", IAC,
549*92163adaSToomas Soome WONT, c);
550*92163adaSToomas Soome (void) fflush(ctrl_out);
551*92163adaSToomas Soome break;
552*92163adaSToomas Soome case DO:
553*92163adaSToomas Soome case DONT:
554*92163adaSToomas Soome c = fgetwc(ctrl_in);
555*92163adaSToomas Soome (void) fprintf(ctrl_out, "%c%c%wc", IAC,
556*92163adaSToomas Soome DONT, c);
557*92163adaSToomas Soome (void) fflush(ctrl_out);
558*92163adaSToomas Soome break;
559*92163adaSToomas Soome default:
560*92163adaSToomas Soome break;
561*92163adaSToomas Soome }
562*92163adaSToomas Soome continue;
5637c478bd9Sstevel@tonic-gate }
564*92163adaSToomas Soome dig++;
565*92163adaSToomas Soome if (c == EOF) {
566*92163adaSToomas Soome if (expecteof) {
567*92163adaSToomas Soome (void) signal(SIGINT, oldintr);
568*92163adaSToomas Soome code = 221;
569*92163adaSToomas Soome return (0);
570*92163adaSToomas Soome }
571*92163adaSToomas Soome lostpeer(0);
572*92163adaSToomas Soome if (verbose) {
573*92163adaSToomas Soome (void) printf(
574*92163adaSToomas Soome "421 Service not available, remote"
575*92163adaSToomas Soome " server has closed connection\n");
576*92163adaSToomas Soome } else {
577*92163adaSToomas Soome (void) printf("Lost connection\n");
578*92163adaSToomas Soome }
579*92163adaSToomas Soome (void) fflush(stdout);
580*92163adaSToomas Soome code = 421;
581*92163adaSToomas Soome return (4);
5827c478bd9Sstevel@tonic-gate }
583*92163adaSToomas Soome if (n == 0)
584*92163adaSToomas Soome n = c;
585*92163adaSToomas Soome
586*92163adaSToomas Soome if (n == '6')
587*92163adaSToomas Soome is_base64 = 1;
588*92163adaSToomas Soome
5897c478bd9Sstevel@tonic-gate if ((auth_type != AUTHTYPE_NONE) && !ibuf[0] &&
590*92163adaSToomas Soome (is_base64 || continuation)) {
591*92163adaSToomas Soome /* start storing chars in obuf */
592*92163adaSToomas Soome if (c != '\r' && dig > 4)
593*92163adaSToomas Soome obuf[i++] = (char)c;
594*92163adaSToomas Soome } else {
595*92163adaSToomas Soome if ((auth_type != AUTHTYPE_NONE) && !ibuf[0] &&
596*92163adaSToomas Soome dig == 1 && verbose)
597*92163adaSToomas Soome (void) printf("Unauthenticated reply "
598*92163adaSToomas Soome "received from server:\n");
599*92163adaSToomas Soome if (reply_parse)
600*92163adaSToomas Soome *reply_ptr++ = (char)c;
601*92163adaSToomas Soome if (c != '\r' && (verbose > 0 ||
602*92163adaSToomas Soome (verbose > -1 && n == '5' && dig > 4))) {
603*92163adaSToomas Soome if (proxflag &&
604*92163adaSToomas Soome (dig == 1 || dig == 5 &&
605*92163adaSToomas Soome verbose == 0))
606*92163adaSToomas Soome (void) printf("%s:", hostname);
607*92163adaSToomas Soome (void) putwchar(c);
608*92163adaSToomas Soome }
609*92163adaSToomas Soome } /* endif auth_type && !ibuf[0] ... */
6107c478bd9Sstevel@tonic-gate
611*92163adaSToomas Soome if ((auth_type != AUTHTYPE_NONE) && !ibuf[0] &&
612*92163adaSToomas Soome !is_base64)
613*92163adaSToomas Soome continue;
614*92163adaSToomas Soome
615*92163adaSToomas Soome /* we are still extracting the 3 digit code */
616*92163adaSToomas Soome if (dig < 4 && isascii(c) && isdigit(c))
617*92163adaSToomas Soome code = code * 10 + (c - '0');
618*92163adaSToomas Soome
619*92163adaSToomas Soome /* starting passive mode */
620*92163adaSToomas Soome if (!pflag && code == 227)
621*92163adaSToomas Soome pflag = 1;
622*92163adaSToomas Soome
623*92163adaSToomas Soome /* start to store characters, when dig > 4 */
624*92163adaSToomas Soome if (dig > 4 && pflag == 1 && isascii(c) && isdigit(c))
625*92163adaSToomas Soome pflag = 2;
626*92163adaSToomas Soome if (pflag == 2) {
627*92163adaSToomas Soome if (c != '\r' && c != ')') {
628*92163adaSToomas Soome /*
629*92163adaSToomas Soome * the mb array is to deal with
630*92163adaSToomas Soome * the wchar_t
631*92163adaSToomas Soome */
632*92163adaSToomas Soome char mb[MB_LEN_MAX];
633*92163adaSToomas Soome int avail;
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate /*
636*92163adaSToomas Soome * space available in pasv[], accounting
637*92163adaSToomas Soome * for trailing NULL
6387c478bd9Sstevel@tonic-gate */
639*92163adaSToomas Soome avail = &pasv[sizeof (pasv)] - pt - 1;
640*92163adaSToomas Soome
641*92163adaSToomas Soome len = wctomb(mb, c);
642*92163adaSToomas Soome if (len <= 0 && avail > 0) {
643*92163adaSToomas Soome *pt++ = (unsigned char)c;
644*92163adaSToomas Soome } else if (len > 0 && avail >= len) {
645*92163adaSToomas Soome bcopy(mb, pt, (size_t)len);
646*92163adaSToomas Soome pt += len;
647*92163adaSToomas Soome } else {
648*92163adaSToomas Soome /*
649*92163adaSToomas Soome * no room in pasv[];
650*92163adaSToomas Soome * close connection
651*92163adaSToomas Soome */
652*92163adaSToomas Soome (void) printf("\nReply too long"
653*92163adaSToomas Soome " - closing connection\n");
654*92163adaSToomas Soome lostpeer(0);
655*92163adaSToomas Soome (void) fflush(stdout);
656*92163adaSToomas Soome (void) signal(SIGINT, oldintr);
657*92163adaSToomas Soome return (4);
658*92163adaSToomas Soome }
659*92163adaSToomas Soome } else {
660*92163adaSToomas Soome *pt = '\0';
661*92163adaSToomas Soome pflag = 3;
6627c478bd9Sstevel@tonic-gate }
663*92163adaSToomas Soome } /* endif pflag == 2 */
664*92163adaSToomas Soome if (dig == 4 && c == '-' && !is_base64) {
665*92163adaSToomas Soome if (continuation)
666*92163adaSToomas Soome code = 0;
667*92163adaSToomas Soome continuation++;
6687c478bd9Sstevel@tonic-gate }
669*92163adaSToomas Soome if (cp < &reply_string[sizeof (reply_string) - 1])
670*92163adaSToomas Soome *cp++ = c;
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate } /* end while */
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate if ((auth_type != AUTHTYPE_NONE) && !ibuf[0] && !is_base64)
6757c478bd9Sstevel@tonic-gate return (getreply(expecteof));
6767c478bd9Sstevel@tonic-gate
6777c478bd9Sstevel@tonic-gate ibuf[0] = obuf[i] = '\0';
6787c478bd9Sstevel@tonic-gate
6797c478bd9Sstevel@tonic-gate if (code && is_base64) {
680*92163adaSToomas Soome boolean_t again = 0;
681*92163adaSToomas Soome n = decode_reply(ibuf, sizeof (ibuf), obuf, n, &again);
682*92163adaSToomas Soome if (again)
683*92163adaSToomas Soome continue;
684*92163adaSToomas Soome } else {
685*92163adaSToomas Soome if (verbose > 0 || verbose > -1 && n == '5') {
686*92163adaSToomas Soome (void) putwchar(c);
687*92163adaSToomas Soome (void) fflush(stdout);
688*92163adaSToomas Soome }
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate if (continuation && code != originalcode) {
6927c478bd9Sstevel@tonic-gate ibuf[0] = obuf[i] = '\0';
6937c478bd9Sstevel@tonic-gate if (originalcode == 0)
6947c478bd9Sstevel@tonic-gate originalcode = code;
6957c478bd9Sstevel@tonic-gate continue;
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate *cp = '\0';
6987c478bd9Sstevel@tonic-gate if (n != '1')
6997c478bd9Sstevel@tonic-gate cpend = 0;
7007c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
7017c478bd9Sstevel@tonic-gate if (code == 421 || originalcode == 421)
7027c478bd9Sstevel@tonic-gate lostpeer(0);
7037c478bd9Sstevel@tonic-gate if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
7047c478bd9Sstevel@tonic-gate (*oldintr)();
7057c478bd9Sstevel@tonic-gate
7067c478bd9Sstevel@tonic-gate if (reply_parse) {
707*92163adaSToomas Soome *reply_ptr = '\0';
708*92163adaSToomas Soome if (reply_ptr = strstr(reply_buf, reply_parse)) {
709*92163adaSToomas Soome reply_parse = reply_ptr + strlen(reply_parse);
710*92163adaSToomas Soome if (reply_ptr = strpbrk(reply_parse, " \r"))
711*92163adaSToomas Soome *reply_ptr = '\0';
712*92163adaSToomas Soome } else {
713*92163adaSToomas Soome reply_parse = reply_ptr;
714*92163adaSToomas Soome }
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate
7177c478bd9Sstevel@tonic-gate return (n - '0');
7187c478bd9Sstevel@tonic-gate } /* end for */
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate
7217c478bd9Sstevel@tonic-gate static int
empty(struct fd_set * mask,int sec,int nfds)7227c478bd9Sstevel@tonic-gate empty(struct fd_set *mask, int sec, int nfds)
7237c478bd9Sstevel@tonic-gate {
7247c478bd9Sstevel@tonic-gate struct timeval t;
7257c478bd9Sstevel@tonic-gate
7267c478bd9Sstevel@tonic-gate reset_timer();
7277c478bd9Sstevel@tonic-gate t.tv_sec = (time_t)sec;
7287c478bd9Sstevel@tonic-gate t.tv_usec = 0;
7297c478bd9Sstevel@tonic-gate return (select(nfds, mask, NULL, NULL, &t));
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate
7327c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7337c478bd9Sstevel@tonic-gate static void
abortsend(int sig)7347c478bd9Sstevel@tonic-gate abortsend(int sig)
7357c478bd9Sstevel@tonic-gate {
7367c478bd9Sstevel@tonic-gate mflag = 0;
7377c478bd9Sstevel@tonic-gate abrtflag = 0;
7387c478bd9Sstevel@tonic-gate (void) printf("\nsend aborted\n");
7397c478bd9Sstevel@tonic-gate (void) fflush(stdout);
7407c478bd9Sstevel@tonic-gate longjmp(sendabort, 1);
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate void
sendrequest(char * cmd,char * local,char * remote,int allowpipe)7447c478bd9Sstevel@tonic-gate sendrequest(char *cmd, char *local, char *remote, int allowpipe)
7457c478bd9Sstevel@tonic-gate {
7467c478bd9Sstevel@tonic-gate FILE *fin, *dout = 0;
7477c478bd9Sstevel@tonic-gate int (*closefunc)();
7487c478bd9Sstevel@tonic-gate void (*oldintr)(), (*oldintp)();
7497c478bd9Sstevel@tonic-gate off_t bytes = 0, hashbytes = HASHSIZ;
7507c478bd9Sstevel@tonic-gate int c;
7517c478bd9Sstevel@tonic-gate /*
7527c478bd9Sstevel@tonic-gate * d >= 0 if there is no error
7537c478bd9Sstevel@tonic-gate * -1 if there was a normal file i/o error
7547c478bd9Sstevel@tonic-gate * -2 if there was a security error
7557c478bd9Sstevel@tonic-gate */
7567c478bd9Sstevel@tonic-gate int d;
7577c478bd9Sstevel@tonic-gate struct stat st;
7587c478bd9Sstevel@tonic-gate hrtime_t start, stop;
7597c478bd9Sstevel@tonic-gate char *dmode;
7607c478bd9Sstevel@tonic-gate
7617c478bd9Sstevel@tonic-gate if (proxy) {
7627c478bd9Sstevel@tonic-gate proxtrans(cmd, local, remote);
7637c478bd9Sstevel@tonic-gate return;
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate closefunc = NULL;
7667c478bd9Sstevel@tonic-gate oldintr = NULL;
7677c478bd9Sstevel@tonic-gate oldintp = NULL;
7687c478bd9Sstevel@tonic-gate dmode = "w";
7697c478bd9Sstevel@tonic-gate if (setjmp(sendabort)) {
7707c478bd9Sstevel@tonic-gate while (cpend) {
7717c478bd9Sstevel@tonic-gate (void) getreply(0);
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate if (data >= 0) {
7747c478bd9Sstevel@tonic-gate (void) close(data);
7757c478bd9Sstevel@tonic-gate data = -1;
7767c478bd9Sstevel@tonic-gate }
7777c478bd9Sstevel@tonic-gate if (oldintr)
7787c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
7797c478bd9Sstevel@tonic-gate if (oldintp)
7807c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, oldintp);
7817c478bd9Sstevel@tonic-gate code = -1;
7827c478bd9Sstevel@tonic-gate restart_point = 0;
7837c478bd9Sstevel@tonic-gate return;
7847c478bd9Sstevel@tonic-gate }
7857c478bd9Sstevel@tonic-gate oldintr = signal(SIGINT, abortsend);
7867c478bd9Sstevel@tonic-gate if (strcmp(local, "-") == 0)
7877c478bd9Sstevel@tonic-gate fin = stdin;
7887c478bd9Sstevel@tonic-gate else if (allowpipe && *local == '|') {
7897c478bd9Sstevel@tonic-gate oldintp = signal(SIGPIPE, SIG_IGN);
7907c478bd9Sstevel@tonic-gate fin = mypopen(local + 1, "r");
7917c478bd9Sstevel@tonic-gate if (fin == NULL) {
7927c478bd9Sstevel@tonic-gate perror(local + 1);
7937c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
7947c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, oldintp);
7957c478bd9Sstevel@tonic-gate code = -1;
7967c478bd9Sstevel@tonic-gate restart_point = 0;
7977c478bd9Sstevel@tonic-gate return;
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate closefunc = mypclose;
8007c478bd9Sstevel@tonic-gate } else {
8017c478bd9Sstevel@tonic-gate fin = fopen(local, "r");
8027c478bd9Sstevel@tonic-gate if (fin == NULL) {
8037c478bd9Sstevel@tonic-gate perror(local);
8047c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
8057c478bd9Sstevel@tonic-gate code = -1;
8067c478bd9Sstevel@tonic-gate restart_point = 0;
8077c478bd9Sstevel@tonic-gate return;
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate closefunc = fclose;
8107c478bd9Sstevel@tonic-gate if (fstat(fileno(fin), &st) < 0 ||
8117c478bd9Sstevel@tonic-gate (st.st_mode&S_IFMT) != S_IFREG) {
8127c478bd9Sstevel@tonic-gate (void) fprintf(stdout,
813*92163adaSToomas Soome "%s: not a plain file.\n", local);
8147c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
8157c478bd9Sstevel@tonic-gate code = -1;
8167c478bd9Sstevel@tonic-gate (void) fclose(fin);
8177c478bd9Sstevel@tonic-gate restart_point = 0;
8187c478bd9Sstevel@tonic-gate return;
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate if (initconn()) {
8227c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
8237c478bd9Sstevel@tonic-gate if (oldintp)
8247c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, oldintp);
8257c478bd9Sstevel@tonic-gate code = -1;
8267c478bd9Sstevel@tonic-gate if (closefunc != NULL)
8277c478bd9Sstevel@tonic-gate (*closefunc)(fin);
8287c478bd9Sstevel@tonic-gate restart_point = 0;
8297c478bd9Sstevel@tonic-gate return;
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate if (setjmp(sendabort))
8327c478bd9Sstevel@tonic-gate goto abort;
8337c478bd9Sstevel@tonic-gate if ((restart_point > 0) &&
8347c478bd9Sstevel@tonic-gate (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
8357c478bd9Sstevel@tonic-gate if (fseeko(fin, restart_point, SEEK_SET) < 0) {
8367c478bd9Sstevel@tonic-gate perror(local);
8377c478bd9Sstevel@tonic-gate if (closefunc != NULL)
8387c478bd9Sstevel@tonic-gate (*closefunc)(fin);
8397c478bd9Sstevel@tonic-gate restart_point = 0;
8407c478bd9Sstevel@tonic-gate return;
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate if (command("REST %lld", (longlong_t)restart_point)
843*92163adaSToomas Soome != CONTINUE) {
8447c478bd9Sstevel@tonic-gate if (closefunc != NULL)
8457c478bd9Sstevel@tonic-gate (*closefunc)(fin);
8467c478bd9Sstevel@tonic-gate restart_point = 0;
8477c478bd9Sstevel@tonic-gate return;
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate dmode = "r+w";
8507c478bd9Sstevel@tonic-gate }
8517c478bd9Sstevel@tonic-gate restart_point = 0;
8527c478bd9Sstevel@tonic-gate if (remote) {
8537c478bd9Sstevel@tonic-gate if (command("%s %s", cmd, remote) != PRELIM) {
8547c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
8557c478bd9Sstevel@tonic-gate if (oldintp)
8567c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, oldintp);
8577c478bd9Sstevel@tonic-gate if (closefunc != NULL)
8587c478bd9Sstevel@tonic-gate (*closefunc)(fin);
8597c478bd9Sstevel@tonic-gate if (data >= 0) {
8607c478bd9Sstevel@tonic-gate (void) close(data);
8617c478bd9Sstevel@tonic-gate data = -1;
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate return;
8647c478bd9Sstevel@tonic-gate }
8657c478bd9Sstevel@tonic-gate } else
8667c478bd9Sstevel@tonic-gate if (command("%s", cmd) != PRELIM) {
8677c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
8687c478bd9Sstevel@tonic-gate if (oldintp)
8697c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, oldintp);
8707c478bd9Sstevel@tonic-gate if (closefunc != NULL)
8717c478bd9Sstevel@tonic-gate (*closefunc)(fin);
8727c478bd9Sstevel@tonic-gate if (data >= 0) {
8737c478bd9Sstevel@tonic-gate (void) close(data);
8747c478bd9Sstevel@tonic-gate data = -1;
8757c478bd9Sstevel@tonic-gate }
8767c478bd9Sstevel@tonic-gate return;
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate dout = dataconn(dmode);
8797c478bd9Sstevel@tonic-gate if (dout == NULL)
8807c478bd9Sstevel@tonic-gate goto abort;
8817c478bd9Sstevel@tonic-gate stop_timer();
8827c478bd9Sstevel@tonic-gate oldintp = signal(SIGPIPE, SIG_IGN);
8837c478bd9Sstevel@tonic-gate start = gethrtime();
8847c478bd9Sstevel@tonic-gate switch (type) {
8857c478bd9Sstevel@tonic-gate
8867c478bd9Sstevel@tonic-gate case TYPE_I:
8877c478bd9Sstevel@tonic-gate case TYPE_L:
8887c478bd9Sstevel@tonic-gate errno = d = 0;
8897c478bd9Sstevel@tonic-gate while ((c = read(fileno(fin), buf, FTPBUFSIZ)) > 0) {
8907c478bd9Sstevel@tonic-gate if ((d = WRITE(fileno(dout), buf, c)) < 0)
8917c478bd9Sstevel@tonic-gate break;
8927c478bd9Sstevel@tonic-gate bytes += c;
8937c478bd9Sstevel@tonic-gate if (hash) {
8947c478bd9Sstevel@tonic-gate while (bytes >= hashbytes) {
8957c478bd9Sstevel@tonic-gate (void) putchar('#');
8967c478bd9Sstevel@tonic-gate hashbytes += HASHSIZ;
8977c478bd9Sstevel@tonic-gate }
8987c478bd9Sstevel@tonic-gate (void) fflush(stdout);
8997c478bd9Sstevel@tonic-gate }
9007c478bd9Sstevel@tonic-gate }
9017c478bd9Sstevel@tonic-gate if (hash && bytes > 0) {
9027c478bd9Sstevel@tonic-gate if (bytes < hashbytes)
9037c478bd9Sstevel@tonic-gate (void) putchar('#');
9047c478bd9Sstevel@tonic-gate (void) putchar('\n');
9057c478bd9Sstevel@tonic-gate (void) fflush(stdout);
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate if (c < 0)
9087c478bd9Sstevel@tonic-gate perror(local);
9097c478bd9Sstevel@tonic-gate
9107c478bd9Sstevel@tonic-gate if (d >= 0)
9117c478bd9Sstevel@tonic-gate d = secure_flush(fileno(dout));
9127c478bd9Sstevel@tonic-gate
9137c478bd9Sstevel@tonic-gate if (d < 0) {
9147c478bd9Sstevel@tonic-gate if ((d == -1) && (errno != EPIPE))
9157c478bd9Sstevel@tonic-gate perror("netout");
9167c478bd9Sstevel@tonic-gate bytes = -1;
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate break;
9197c478bd9Sstevel@tonic-gate
9207c478bd9Sstevel@tonic-gate case TYPE_A:
9217c478bd9Sstevel@tonic-gate while ((c = getc(fin)) != EOF) {
9227c478bd9Sstevel@tonic-gate if (c == '\n') {
9237c478bd9Sstevel@tonic-gate while (hash && (bytes >= hashbytes)) {
9247c478bd9Sstevel@tonic-gate (void) putchar('#');
9257c478bd9Sstevel@tonic-gate (void) fflush(stdout);
9267c478bd9Sstevel@tonic-gate hashbytes += HASHSIZ;
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate if (ferror(dout) || PUTC('\r', dout) < 0)
9297c478bd9Sstevel@tonic-gate break;
9307c478bd9Sstevel@tonic-gate bytes++;
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate if (PUTC(c, dout) < 0)
9347c478bd9Sstevel@tonic-gate break;
9357c478bd9Sstevel@tonic-gate bytes++;
9367c478bd9Sstevel@tonic-gate #ifdef notdef
9377c478bd9Sstevel@tonic-gate if (c == '\r') {
9387c478bd9Sstevel@tonic-gate /* this violates rfc */
9397c478bd9Sstevel@tonic-gate (void) PUTC('\0', dout);
9407c478bd9Sstevel@tonic-gate bytes++;
9417c478bd9Sstevel@tonic-gate }
9427c478bd9Sstevel@tonic-gate #endif
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate if (hash && bytes > 0) {
9457c478bd9Sstevel@tonic-gate if (bytes < hashbytes)
9467c478bd9Sstevel@tonic-gate (void) putchar('#');
9477c478bd9Sstevel@tonic-gate (void) putchar('\n');
9487c478bd9Sstevel@tonic-gate (void) fflush(stdout);
9497c478bd9Sstevel@tonic-gate }
9507c478bd9Sstevel@tonic-gate if (ferror(fin))
9517c478bd9Sstevel@tonic-gate perror(local);
9527c478bd9Sstevel@tonic-gate
9537c478bd9Sstevel@tonic-gate d = ferror(dout) ? -1 : 0;
9547c478bd9Sstevel@tonic-gate if (d == 0)
9557c478bd9Sstevel@tonic-gate d = secure_flush(fileno(dout));
9567c478bd9Sstevel@tonic-gate
9577c478bd9Sstevel@tonic-gate if (d < 0) {
9587c478bd9Sstevel@tonic-gate if ((d == -1) && (errno != EPIPE))
9597c478bd9Sstevel@tonic-gate perror("netout");
9607c478bd9Sstevel@tonic-gate bytes = -1;
9617c478bd9Sstevel@tonic-gate }
9627c478bd9Sstevel@tonic-gate break;
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate reset_timer();
9657c478bd9Sstevel@tonic-gate if (closefunc != NULL)
9667c478bd9Sstevel@tonic-gate (*closefunc)(fin);
9677c478bd9Sstevel@tonic-gate if (ctrl_in != NULL) {
9687c478bd9Sstevel@tonic-gate int dfn = fileno(dout);
9697c478bd9Sstevel@tonic-gate int nfds = fileno(ctrl_in);
9707c478bd9Sstevel@tonic-gate fd_set mask;
9717c478bd9Sstevel@tonic-gate
9727c478bd9Sstevel@tonic-gate /*
9737c478bd9Sstevel@tonic-gate * There could be data not yet written to dout,
9747c478bd9Sstevel@tonic-gate * in the stdio buffer; so, before a shutdown()
9757c478bd9Sstevel@tonic-gate * on further sends, do fflush(dout)
9767c478bd9Sstevel@tonic-gate */
9777c478bd9Sstevel@tonic-gate (void) fflush(dout);
9787c478bd9Sstevel@tonic-gate
9797c478bd9Sstevel@tonic-gate /* sending over; shutdown sending on dfn */
9807c478bd9Sstevel@tonic-gate (void) shutdown(dfn, SHUT_WR);
9817c478bd9Sstevel@tonic-gate FD_ZERO(&mask);
9827c478bd9Sstevel@tonic-gate FD_SET(dfn, &mask);
9837c478bd9Sstevel@tonic-gate FD_SET(nfds, &mask);
9847c478bd9Sstevel@tonic-gate nfds = MAX(dfn, nfds);
9857c478bd9Sstevel@tonic-gate
9867c478bd9Sstevel@tonic-gate /*
9877c478bd9Sstevel@tonic-gate * Wait for remote end to either close data socket
9887c478bd9Sstevel@tonic-gate * or ack that we've closed our end; it doesn't
9897c478bd9Sstevel@tonic-gate * matter which happens first.
9907c478bd9Sstevel@tonic-gate */
9917c478bd9Sstevel@tonic-gate (void) select(nfds + 1, &mask, NULL, NULL, NULL);
9927c478bd9Sstevel@tonic-gate }
9937c478bd9Sstevel@tonic-gate (void) fclose(dout); data = -1;
9947c478bd9Sstevel@tonic-gate stop = gethrtime();
9957c478bd9Sstevel@tonic-gate (void) getreply(0);
9967c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
9977c478bd9Sstevel@tonic-gate if (oldintp)
9987c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, oldintp);
9997c478bd9Sstevel@tonic-gate
10007c478bd9Sstevel@tonic-gate /*
10017c478bd9Sstevel@tonic-gate * Only print the transfer successful message if the code returned
10027c478bd9Sstevel@tonic-gate * from remote is 226 or 250. All other codes are error codes.
10037c478bd9Sstevel@tonic-gate */
10047c478bd9Sstevel@tonic-gate if ((bytes > 0) && verbose && ((code == 226) || (code == 250)))
10057c478bd9Sstevel@tonic-gate ptransfer("sent", bytes, start, stop, local, remote);
10067c478bd9Sstevel@tonic-gate if (!ctrl_in)
10077c478bd9Sstevel@tonic-gate (void) printf("Lost connection\n");
10087c478bd9Sstevel@tonic-gate return;
10097c478bd9Sstevel@tonic-gate abort:
10107c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
10117c478bd9Sstevel@tonic-gate if (oldintp)
10127c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, oldintp);
10137c478bd9Sstevel@tonic-gate if (!cpend) {
10147c478bd9Sstevel@tonic-gate code = -1;
10157c478bd9Sstevel@tonic-gate return;
10167c478bd9Sstevel@tonic-gate }
10177c478bd9Sstevel@tonic-gate if (data >= 0) {
10187c478bd9Sstevel@tonic-gate (void) close(data);
10197c478bd9Sstevel@tonic-gate data = -1;
10207c478bd9Sstevel@tonic-gate }
10217c478bd9Sstevel@tonic-gate if (dout) {
10227c478bd9Sstevel@tonic-gate (void) fclose(dout);
10237c478bd9Sstevel@tonic-gate data = -1;
10247c478bd9Sstevel@tonic-gate }
10257c478bd9Sstevel@tonic-gate (void) getreply(0);
10267c478bd9Sstevel@tonic-gate code = -1;
10277c478bd9Sstevel@tonic-gate if (closefunc != NULL && fin != NULL)
10287c478bd9Sstevel@tonic-gate (*closefunc)(fin);
10297c478bd9Sstevel@tonic-gate stop = gethrtime();
10307c478bd9Sstevel@tonic-gate /*
10317c478bd9Sstevel@tonic-gate * Only print the transfer successful message if the code returned
10327c478bd9Sstevel@tonic-gate * from remote is 226 or 250. All other codes are error codes.
10337c478bd9Sstevel@tonic-gate */
10347c478bd9Sstevel@tonic-gate if ((bytes > 0) && verbose && ((code == 226) || (code == 250)))
10357c478bd9Sstevel@tonic-gate ptransfer("sent", bytes, start, stop, local, remote);
10367c478bd9Sstevel@tonic-gate if (!ctrl_in)
10377c478bd9Sstevel@tonic-gate (void) printf("Lost connection\n");
10387c478bd9Sstevel@tonic-gate restart_point = 0;
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate
10417c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10427c478bd9Sstevel@tonic-gate static void
abortrecv(int sig)10437c478bd9Sstevel@tonic-gate abortrecv(int sig)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate mflag = 0;
10467c478bd9Sstevel@tonic-gate abrtflag = 0;
10477c478bd9Sstevel@tonic-gate (void) printf("\n");
10487c478bd9Sstevel@tonic-gate (void) fflush(stdout);
10497c478bd9Sstevel@tonic-gate longjmp(recvabort, 1);
10507c478bd9Sstevel@tonic-gate }
10517c478bd9Sstevel@tonic-gate
10527c478bd9Sstevel@tonic-gate void
recvrequest(char * cmd,char * local,char * remote,char * mode,int allowpipe)10537c478bd9Sstevel@tonic-gate recvrequest(char *cmd, char *local, char *remote, char *mode, int allowpipe)
10547c478bd9Sstevel@tonic-gate {
10557c478bd9Sstevel@tonic-gate FILE *fout, *din = 0;
10567c478bd9Sstevel@tonic-gate int (*closefunc)();
10577c478bd9Sstevel@tonic-gate void (*oldintr)(), (*oldintp)();
10587c478bd9Sstevel@tonic-gate int oldverbose, oldtype = 0, tcrflag, nfnd;
10597c478bd9Sstevel@tonic-gate char msg;
10607c478bd9Sstevel@tonic-gate off_t bytes = 0, hashbytes = HASHSIZ;
10617c478bd9Sstevel@tonic-gate struct fd_set mask;
10627c478bd9Sstevel@tonic-gate int c, d, n;
10637c478bd9Sstevel@tonic-gate hrtime_t start, stop;
10647c478bd9Sstevel@tonic-gate int errflg = 0;
10657c478bd9Sstevel@tonic-gate int infd;
10667c478bd9Sstevel@tonic-gate int nfds;
10677c478bd9Sstevel@tonic-gate int retrcmd;
10687c478bd9Sstevel@tonic-gate
10697c478bd9Sstevel@tonic-gate retrcmd = (strcmp(cmd, "RETR") == 0);
10707c478bd9Sstevel@tonic-gate if (proxy && retrcmd) {
10717c478bd9Sstevel@tonic-gate proxtrans(cmd, local, remote);
10727c478bd9Sstevel@tonic-gate return;
10737c478bd9Sstevel@tonic-gate }
10747c478bd9Sstevel@tonic-gate closefunc = NULL;
10757c478bd9Sstevel@tonic-gate oldintr = NULL;
10767c478bd9Sstevel@tonic-gate oldintp = NULL;
10777c478bd9Sstevel@tonic-gate tcrflag = !crflag && retrcmd;
10787c478bd9Sstevel@tonic-gate if (setjmp(recvabort)) {
10797c478bd9Sstevel@tonic-gate while (cpend) {
10807c478bd9Sstevel@tonic-gate (void) getreply(0);
10817c478bd9Sstevel@tonic-gate }
10827c478bd9Sstevel@tonic-gate if (data >= 0) {
10837c478bd9Sstevel@tonic-gate (void) close(data);
10847c478bd9Sstevel@tonic-gate data = -1;
10857c478bd9Sstevel@tonic-gate }
10867c478bd9Sstevel@tonic-gate if (oldintr)
10877c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
10887c478bd9Sstevel@tonic-gate code = -1;
10897c478bd9Sstevel@tonic-gate return;
10907c478bd9Sstevel@tonic-gate }
10917c478bd9Sstevel@tonic-gate oldintr = signal(SIGINT, abortrecv);
10927c478bd9Sstevel@tonic-gate if (local != NULL &&
10937c478bd9Sstevel@tonic-gate strcmp(local, "-") != 0 &&
10947c478bd9Sstevel@tonic-gate (*local != '|' || !allowpipe)) {
10957c478bd9Sstevel@tonic-gate if (access(local, W_OK) < 0) {
10967c478bd9Sstevel@tonic-gate char *dir = rindex(local, '/');
10977c478bd9Sstevel@tonic-gate int file_errno = errno;
10987c478bd9Sstevel@tonic-gate
10997c478bd9Sstevel@tonic-gate if (file_errno != ENOENT && file_errno != EACCES) {
11007c478bd9Sstevel@tonic-gate perror(local);
11017c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
11027c478bd9Sstevel@tonic-gate code = -1;
11037c478bd9Sstevel@tonic-gate return;
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate if ((dir != NULL) && (dir != local))
11067c478bd9Sstevel@tonic-gate *dir = 0;
11077c478bd9Sstevel@tonic-gate if (dir == local)
11087c478bd9Sstevel@tonic-gate d = access("/", W_OK);
11097c478bd9Sstevel@tonic-gate else
11107c478bd9Sstevel@tonic-gate d = access(dir ? local : ".", W_OK);
11117c478bd9Sstevel@tonic-gate if ((dir != NULL) && (dir != local))
11127c478bd9Sstevel@tonic-gate *dir = '/';
11137c478bd9Sstevel@tonic-gate if (d < 0) {
11147c478bd9Sstevel@tonic-gate perror(local);
11157c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
11167c478bd9Sstevel@tonic-gate code = -1;
11177c478bd9Sstevel@tonic-gate return;
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate if (!runique && file_errno == EACCES) {
11207c478bd9Sstevel@tonic-gate errno = file_errno;
11217c478bd9Sstevel@tonic-gate perror(local);
11227c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
11237c478bd9Sstevel@tonic-gate code = -1;
11247c478bd9Sstevel@tonic-gate return;
11257c478bd9Sstevel@tonic-gate }
11267c478bd9Sstevel@tonic-gate if (runique && file_errno == EACCES &&
11277c478bd9Sstevel@tonic-gate (local = gunique(local)) == NULL) {
11287c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
11297c478bd9Sstevel@tonic-gate code = -1;
11307c478bd9Sstevel@tonic-gate return;
11317c478bd9Sstevel@tonic-gate }
11327c478bd9Sstevel@tonic-gate } else if (runique && (local = gunique(local)) == NULL) {
11337c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
11347c478bd9Sstevel@tonic-gate code = -1;
11357c478bd9Sstevel@tonic-gate return;
11367c478bd9Sstevel@tonic-gate }
11377c478bd9Sstevel@tonic-gate }
11387c478bd9Sstevel@tonic-gate if (initconn()) {
11397c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
11407c478bd9Sstevel@tonic-gate code = -1;
11417c478bd9Sstevel@tonic-gate return;
11427c478bd9Sstevel@tonic-gate }
11437c478bd9Sstevel@tonic-gate if (setjmp(recvabort))
11447c478bd9Sstevel@tonic-gate goto abort;
11457c478bd9Sstevel@tonic-gate if (!retrcmd && type != TYPE_A) {
11467c478bd9Sstevel@tonic-gate oldtype = type;
11477c478bd9Sstevel@tonic-gate oldverbose = verbose;
11487c478bd9Sstevel@tonic-gate if (!debug)
11497c478bd9Sstevel@tonic-gate verbose = 0;
11507c478bd9Sstevel@tonic-gate setascii(0, NULL);
11517c478bd9Sstevel@tonic-gate verbose = oldverbose;
11527c478bd9Sstevel@tonic-gate }
11537c478bd9Sstevel@tonic-gate if ((restart_point > 0) && retrcmd &&
11547c478bd9Sstevel@tonic-gate command("REST %lld", (longlong_t)restart_point) != CONTINUE) {
11557c478bd9Sstevel@tonic-gate return;
11567c478bd9Sstevel@tonic-gate }
11577c478bd9Sstevel@tonic-gate if (remote) {
11587c478bd9Sstevel@tonic-gate if (command("%s %s", cmd, remote) != PRELIM) {
11597c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
11607c478bd9Sstevel@tonic-gate if (oldtype) {
11617c478bd9Sstevel@tonic-gate if (!debug)
11627c478bd9Sstevel@tonic-gate verbose = 0;
11637c478bd9Sstevel@tonic-gate switch (oldtype) {
11647c478bd9Sstevel@tonic-gate case TYPE_I:
11657c478bd9Sstevel@tonic-gate setbinary(0, NULL);
11667c478bd9Sstevel@tonic-gate break;
11677c478bd9Sstevel@tonic-gate case TYPE_E:
11687c478bd9Sstevel@tonic-gate setebcdic(0, NULL);
11697c478bd9Sstevel@tonic-gate break;
11707c478bd9Sstevel@tonic-gate case TYPE_L:
11717c478bd9Sstevel@tonic-gate settenex(0, NULL);
11727c478bd9Sstevel@tonic-gate break;
11737c478bd9Sstevel@tonic-gate }
11747c478bd9Sstevel@tonic-gate verbose = oldverbose;
11757c478bd9Sstevel@tonic-gate }
11767c478bd9Sstevel@tonic-gate return;
11777c478bd9Sstevel@tonic-gate }
11787c478bd9Sstevel@tonic-gate } else {
11797c478bd9Sstevel@tonic-gate if (command("%s", cmd) != PRELIM) {
11807c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
11817c478bd9Sstevel@tonic-gate if (oldtype) {
11827c478bd9Sstevel@tonic-gate if (!debug)
11837c478bd9Sstevel@tonic-gate verbose = 0;
11847c478bd9Sstevel@tonic-gate switch (oldtype) {
11857c478bd9Sstevel@tonic-gate case TYPE_I:
11867c478bd9Sstevel@tonic-gate setbinary(0, NULL);
11877c478bd9Sstevel@tonic-gate break;
11887c478bd9Sstevel@tonic-gate case TYPE_E:
11897c478bd9Sstevel@tonic-gate setebcdic(0, NULL);
11907c478bd9Sstevel@tonic-gate break;
11917c478bd9Sstevel@tonic-gate case TYPE_L:
11927c478bd9Sstevel@tonic-gate settenex(0, NULL);
11937c478bd9Sstevel@tonic-gate break;
11947c478bd9Sstevel@tonic-gate }
11957c478bd9Sstevel@tonic-gate verbose = oldverbose;
11967c478bd9Sstevel@tonic-gate }
11977c478bd9Sstevel@tonic-gate return;
11987c478bd9Sstevel@tonic-gate }
11997c478bd9Sstevel@tonic-gate }
12007c478bd9Sstevel@tonic-gate din = dataconn("r");
12017c478bd9Sstevel@tonic-gate if (din == NULL)
12027c478bd9Sstevel@tonic-gate goto abort;
12037c478bd9Sstevel@tonic-gate
12047c478bd9Sstevel@tonic-gate if (local == NULL) {
12057c478bd9Sstevel@tonic-gate fout = tmp_nlst;
12067c478bd9Sstevel@tonic-gate } else if (strcmp(local, "-") == 0) {
12077c478bd9Sstevel@tonic-gate fout = stdout;
12087c478bd9Sstevel@tonic-gate } else if (allowpipe && *local == '|') {
12097c478bd9Sstevel@tonic-gate oldintp = signal(SIGPIPE, SIG_IGN);
12107c478bd9Sstevel@tonic-gate fout = mypopen(local + 1, "w");
12117c478bd9Sstevel@tonic-gate if (fout == NULL) {
12127c478bd9Sstevel@tonic-gate perror(local+1);
12137c478bd9Sstevel@tonic-gate goto abort;
12147c478bd9Sstevel@tonic-gate }
12157c478bd9Sstevel@tonic-gate closefunc = mypclose;
12167c478bd9Sstevel@tonic-gate } else {
12177c478bd9Sstevel@tonic-gate fout = fopen(local, mode);
12187c478bd9Sstevel@tonic-gate if (fout == NULL) {
12197c478bd9Sstevel@tonic-gate perror(local);
12207c478bd9Sstevel@tonic-gate goto abort;
12217c478bd9Sstevel@tonic-gate }
12227c478bd9Sstevel@tonic-gate closefunc = fclose;
12237c478bd9Sstevel@tonic-gate }
12247c478bd9Sstevel@tonic-gate start = gethrtime();
12257c478bd9Sstevel@tonic-gate stop_timer();
12267c478bd9Sstevel@tonic-gate switch (type) {
12277c478bd9Sstevel@tonic-gate
12287c478bd9Sstevel@tonic-gate case TYPE_I:
12297c478bd9Sstevel@tonic-gate case TYPE_L:
12307c478bd9Sstevel@tonic-gate if ((restart_point > 0) && retrcmd &&
12317c478bd9Sstevel@tonic-gate lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
12327c478bd9Sstevel@tonic-gate perror(local);
12337c478bd9Sstevel@tonic-gate goto abort;
12347c478bd9Sstevel@tonic-gate }
12357c478bd9Sstevel@tonic-gate errno = d = 0;
12367c478bd9Sstevel@tonic-gate infd = fileno(din);
12377c478bd9Sstevel@tonic-gate while ((c = timedread(infd, buf, FTPBUFSIZ, timeout)) > 0) {
12387c478bd9Sstevel@tonic-gate for (n = 0; n < c; n += d) {
12397c478bd9Sstevel@tonic-gate d = write(fileno(fout), &buf[n], c - n);
12407c478bd9Sstevel@tonic-gate if (d == -1)
12417c478bd9Sstevel@tonic-gate goto writeerr;
12427c478bd9Sstevel@tonic-gate }
12437c478bd9Sstevel@tonic-gate bytes += c;
12447c478bd9Sstevel@tonic-gate if (hash) {
12457c478bd9Sstevel@tonic-gate while (bytes >= hashbytes) {
12467c478bd9Sstevel@tonic-gate (void) putchar('#');
12477c478bd9Sstevel@tonic-gate hashbytes += HASHSIZ;
12487c478bd9Sstevel@tonic-gate }
12497c478bd9Sstevel@tonic-gate (void) fflush(stdout);
12507c478bd9Sstevel@tonic-gate }
12517c478bd9Sstevel@tonic-gate }
12527c478bd9Sstevel@tonic-gate if (hash && bytes > 0) {
12537c478bd9Sstevel@tonic-gate if (bytes < hashbytes)
12547c478bd9Sstevel@tonic-gate (void) putchar('#');
12557c478bd9Sstevel@tonic-gate (void) putchar('\n');
12567c478bd9Sstevel@tonic-gate (void) fflush(stdout);
12577c478bd9Sstevel@tonic-gate }
12587c478bd9Sstevel@tonic-gate if (c < 0) {
12597c478bd9Sstevel@tonic-gate errflg = 1;
12607c478bd9Sstevel@tonic-gate perror("netin");
12617c478bd9Sstevel@tonic-gate }
12627c478bd9Sstevel@tonic-gate if ((d < 0) || ((c == 0) && (fsync(fileno(fout)) == -1))) {
12637c478bd9Sstevel@tonic-gate writeerr:
12647c478bd9Sstevel@tonic-gate errflg = 1;
12657c478bd9Sstevel@tonic-gate perror(local);
12667c478bd9Sstevel@tonic-gate }
12677c478bd9Sstevel@tonic-gate break;
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate case TYPE_A:
12707c478bd9Sstevel@tonic-gate if ((restart_point > 0) && retrcmd) {
12717c478bd9Sstevel@tonic-gate int c;
12727c478bd9Sstevel@tonic-gate off_t i = 0;
12737c478bd9Sstevel@tonic-gate
12747c478bd9Sstevel@tonic-gate if (fseek(fout, 0L, SEEK_SET) < 0) {
12757c478bd9Sstevel@tonic-gate perror(local);
12767c478bd9Sstevel@tonic-gate goto abort;
12777c478bd9Sstevel@tonic-gate }
12787c478bd9Sstevel@tonic-gate while (i++ < restart_point) {
12797c478bd9Sstevel@tonic-gate if ((c = getc(fout)) == EOF) {
12807c478bd9Sstevel@tonic-gate if (ferror(fout))
12817c478bd9Sstevel@tonic-gate perror(local);
12827c478bd9Sstevel@tonic-gate else
12837c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
1284*92163adaSToomas Soome "%s: Unexpected end of "
1285*92163adaSToomas Soome "file\n", local);
12867c478bd9Sstevel@tonic-gate goto abort;
12877c478bd9Sstevel@tonic-gate }
12887c478bd9Sstevel@tonic-gate if (c == '\n')
12897c478bd9Sstevel@tonic-gate i++;
12907c478bd9Sstevel@tonic-gate }
12917c478bd9Sstevel@tonic-gate if (fseeko(fout, 0L, SEEK_CUR) < 0) {
12927c478bd9Sstevel@tonic-gate perror(local);
12937c478bd9Sstevel@tonic-gate goto abort;
12947c478bd9Sstevel@tonic-gate }
12957c478bd9Sstevel@tonic-gate }
12967c478bd9Sstevel@tonic-gate fdio_setbuf(buf, FTPBUFSIZ);
12977c478bd9Sstevel@tonic-gate infd = fileno(din);
12987c478bd9Sstevel@tonic-gate while ((c = fdio_getc(infd)) != EOF) {
12997c478bd9Sstevel@tonic-gate while (c == '\r') {
13007c478bd9Sstevel@tonic-gate while (hash && (bytes >= hashbytes)) {
13017c478bd9Sstevel@tonic-gate (void) putchar('#');
13027c478bd9Sstevel@tonic-gate (void) fflush(stdout);
13037c478bd9Sstevel@tonic-gate hashbytes += HASHSIZ;
13047c478bd9Sstevel@tonic-gate }
13057c478bd9Sstevel@tonic-gate bytes++;
13067c478bd9Sstevel@tonic-gate
13077c478bd9Sstevel@tonic-gate if ((c = fdio_getc(infd)) != '\n' || tcrflag) {
13087c478bd9Sstevel@tonic-gate if (ferror(fout))
13097c478bd9Sstevel@tonic-gate break;
13107c478bd9Sstevel@tonic-gate if (putc('\r', fout) == EOF)
13117c478bd9Sstevel@tonic-gate goto writer_ascii_err;
13127c478bd9Sstevel@tonic-gate }
13137c478bd9Sstevel@tonic-gate #ifdef notdef
13147c478bd9Sstevel@tonic-gate if (c == '\0') {
13157c478bd9Sstevel@tonic-gate bytes++;
13167c478bd9Sstevel@tonic-gate continue;
13177c478bd9Sstevel@tonic-gate }
13187c478bd9Sstevel@tonic-gate #endif
13197c478bd9Sstevel@tonic-gate if (c == EOF)
13207c478bd9Sstevel@tonic-gate goto endread;
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate if (putc(c, fout) == EOF)
13237c478bd9Sstevel@tonic-gate goto writer_ascii_err;
13247c478bd9Sstevel@tonic-gate bytes++;
13257c478bd9Sstevel@tonic-gate }
13267c478bd9Sstevel@tonic-gate endread:
13277c478bd9Sstevel@tonic-gate if (hash && bytes > 0) {
13287c478bd9Sstevel@tonic-gate if (bytes < hashbytes)
13297c478bd9Sstevel@tonic-gate (void) putchar('#');
13307c478bd9Sstevel@tonic-gate (void) putchar('\n');
13317c478bd9Sstevel@tonic-gate (void) fflush(stdout);
13327c478bd9Sstevel@tonic-gate }
13337c478bd9Sstevel@tonic-gate if (fdio_error(infd)) {
13347c478bd9Sstevel@tonic-gate errflg = 1;
13357c478bd9Sstevel@tonic-gate perror("netin");
13367c478bd9Sstevel@tonic-gate }
13377c478bd9Sstevel@tonic-gate if ((fflush(fout) == EOF) || ferror(fout) ||
1338*92163adaSToomas Soome (fsync(fileno(fout)) == -1)) {
13397c478bd9Sstevel@tonic-gate writer_ascii_err:
13407c478bd9Sstevel@tonic-gate errflg = 1;
13417c478bd9Sstevel@tonic-gate perror(local);
13427c478bd9Sstevel@tonic-gate }
13437c478bd9Sstevel@tonic-gate break;
13447c478bd9Sstevel@tonic-gate }
13457c478bd9Sstevel@tonic-gate reset_timer();
13467c478bd9Sstevel@tonic-gate if (closefunc != NULL)
13477c478bd9Sstevel@tonic-gate (*closefunc)(fout);
13487c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
13497c478bd9Sstevel@tonic-gate if (oldintp)
13507c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, oldintp);
13517c478bd9Sstevel@tonic-gate (void) fclose(din); data = -1;
13527c478bd9Sstevel@tonic-gate stop = gethrtime();
13537c478bd9Sstevel@tonic-gate (void) getreply(0);
13547c478bd9Sstevel@tonic-gate if (bytes > 0 && verbose && !errflg)
13557c478bd9Sstevel@tonic-gate ptransfer("received", bytes, start, stop, local, remote);
13567c478bd9Sstevel@tonic-gate if (!ctrl_in)
13577c478bd9Sstevel@tonic-gate (void) printf("Lost connection\n");
13587c478bd9Sstevel@tonic-gate if (oldtype) {
13597c478bd9Sstevel@tonic-gate if (!debug)
13607c478bd9Sstevel@tonic-gate verbose = 0;
13617c478bd9Sstevel@tonic-gate switch (oldtype) {
13627c478bd9Sstevel@tonic-gate case TYPE_I:
13637c478bd9Sstevel@tonic-gate setbinary(0, NULL);
13647c478bd9Sstevel@tonic-gate break;
13657c478bd9Sstevel@tonic-gate case TYPE_E:
13667c478bd9Sstevel@tonic-gate setebcdic(0, NULL);
13677c478bd9Sstevel@tonic-gate break;
13687c478bd9Sstevel@tonic-gate case TYPE_L:
13697c478bd9Sstevel@tonic-gate settenex(0, NULL);
13707c478bd9Sstevel@tonic-gate break;
13717c478bd9Sstevel@tonic-gate }
13727c478bd9Sstevel@tonic-gate verbose = oldverbose;
13737c478bd9Sstevel@tonic-gate }
13747c478bd9Sstevel@tonic-gate return;
13757c478bd9Sstevel@tonic-gate abort:
13767c478bd9Sstevel@tonic-gate
13777c478bd9Sstevel@tonic-gate /* abort using RFC959 recommended IP, SYNC sequence */
13787c478bd9Sstevel@tonic-gate
13797c478bd9Sstevel@tonic-gate stop = gethrtime();
13807c478bd9Sstevel@tonic-gate if (oldintp)
13817c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, oldintp);
13827c478bd9Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN);
13837c478bd9Sstevel@tonic-gate if (!cpend) {
13847c478bd9Sstevel@tonic-gate code = -1;
13857c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
13867c478bd9Sstevel@tonic-gate return;
13877c478bd9Sstevel@tonic-gate }
13887c478bd9Sstevel@tonic-gate
13897c478bd9Sstevel@tonic-gate (void) fprintf(ctrl_out, "%c%c", IAC, IP);
13907c478bd9Sstevel@tonic-gate (void) fflush(ctrl_out);
13917c478bd9Sstevel@tonic-gate msg = (char)IAC;
13927c478bd9Sstevel@tonic-gate /*
13937c478bd9Sstevel@tonic-gate * send IAC in urgent mode instead of DM because UNIX places oob
13947c478bd9Sstevel@tonic-gate * mark after urgent byte rather than before as now is protocol
13957c478bd9Sstevel@tonic-gate */
13967c478bd9Sstevel@tonic-gate if (send(fileno(ctrl_out), &msg, 1, MSG_OOB) != 1) {
13977c478bd9Sstevel@tonic-gate perror("abort");
13987c478bd9Sstevel@tonic-gate }
13997c478bd9Sstevel@tonic-gate (void) fprintf(ctrl_out, "%cABOR\r\n", DM);
14007c478bd9Sstevel@tonic-gate (void) fflush(ctrl_out);
14017c478bd9Sstevel@tonic-gate nfds = fileno(ctrl_in) + 1;
14027c478bd9Sstevel@tonic-gate FD_ZERO(&mask);
14037c478bd9Sstevel@tonic-gate FD_SET(fileno(ctrl_in), &mask);
14047c478bd9Sstevel@tonic-gate if (din) {
14057c478bd9Sstevel@tonic-gate FD_SET(fileno(din), &mask);
14067c478bd9Sstevel@tonic-gate nfds = MAX(fileno(din) + 1, nfds);
14077c478bd9Sstevel@tonic-gate }
14087c478bd9Sstevel@tonic-gate if ((nfnd = empty(&mask, 10, nfds)) <= 0) {
14097c478bd9Sstevel@tonic-gate if (nfnd < 0) {
14107c478bd9Sstevel@tonic-gate perror("abort");
14117c478bd9Sstevel@tonic-gate }
14127c478bd9Sstevel@tonic-gate code = -1;
14137c478bd9Sstevel@tonic-gate lostpeer(0);
14147c478bd9Sstevel@tonic-gate }
14157c478bd9Sstevel@tonic-gate if (din && FD_ISSET(fileno(din), &mask)) {
14167c478bd9Sstevel@tonic-gate do {
14177c478bd9Sstevel@tonic-gate reset_timer();
14187c478bd9Sstevel@tonic-gate } while ((c = read(fileno(din), buf, FTPBUFSIZ)) > 0);
14197c478bd9Sstevel@tonic-gate }
14207c478bd9Sstevel@tonic-gate if ((c = getreply(0)) == ERROR && code == 552) {
14217c478bd9Sstevel@tonic-gate /* needed for nic style abort */
14227c478bd9Sstevel@tonic-gate if (data >= 0) {
14237c478bd9Sstevel@tonic-gate (void) close(data);
14247c478bd9Sstevel@tonic-gate data = -1;
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate (void) getreply(0);
14277c478bd9Sstevel@tonic-gate }
14287c478bd9Sstevel@tonic-gate if (oldtype) {
14297c478bd9Sstevel@tonic-gate if (!debug)
14307c478bd9Sstevel@tonic-gate verbose = 0;
14317c478bd9Sstevel@tonic-gate switch (oldtype) {
14327c478bd9Sstevel@tonic-gate case TYPE_I:
14337c478bd9Sstevel@tonic-gate setbinary(0, NULL);
14347c478bd9Sstevel@tonic-gate break;
14357c478bd9Sstevel@tonic-gate case TYPE_E:
14367c478bd9Sstevel@tonic-gate setebcdic(0, NULL);
14377c478bd9Sstevel@tonic-gate break;
14387c478bd9Sstevel@tonic-gate case TYPE_L:
14397c478bd9Sstevel@tonic-gate settenex(0, NULL);
14407c478bd9Sstevel@tonic-gate break;
14417c478bd9Sstevel@tonic-gate }
14427c478bd9Sstevel@tonic-gate verbose = oldverbose;
14437c478bd9Sstevel@tonic-gate }
14447c478bd9Sstevel@tonic-gate (void) getreply(0);
14457c478bd9Sstevel@tonic-gate code = -1;
14467c478bd9Sstevel@tonic-gate if (data >= 0) {
14477c478bd9Sstevel@tonic-gate (void) close(data);
14487c478bd9Sstevel@tonic-gate data = -1;
14497c478bd9Sstevel@tonic-gate }
14507c478bd9Sstevel@tonic-gate if (closefunc != NULL && fout != NULL)
14517c478bd9Sstevel@tonic-gate (*closefunc)(fout);
14527c478bd9Sstevel@tonic-gate if (din) {
14537c478bd9Sstevel@tonic-gate (void) fclose(din);
14547c478bd9Sstevel@tonic-gate data = -1;
14557c478bd9Sstevel@tonic-gate }
14567c478bd9Sstevel@tonic-gate if (bytes > 0 && verbose)
14577c478bd9Sstevel@tonic-gate ptransfer("received", bytes, start, stop, local, remote);
14587c478bd9Sstevel@tonic-gate if (!ctrl_in)
14597c478bd9Sstevel@tonic-gate (void) printf("Lost connection\n");
14607c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
14617c478bd9Sstevel@tonic-gate }
14627c478bd9Sstevel@tonic-gate
14637c478bd9Sstevel@tonic-gate /*
14647c478bd9Sstevel@tonic-gate * Need to start a listen on the data channel
14657c478bd9Sstevel@tonic-gate * before we send the command, otherwise the
14667c478bd9Sstevel@tonic-gate * server's connect may fail.
14677c478bd9Sstevel@tonic-gate */
14687c478bd9Sstevel@tonic-gate
14697c478bd9Sstevel@tonic-gate static int
initconn(void)14707c478bd9Sstevel@tonic-gate initconn(void)
14717c478bd9Sstevel@tonic-gate {
14727c478bd9Sstevel@tonic-gate unsigned char *p, *a;
14737c478bd9Sstevel@tonic-gate int result, tmpno = 0;
14747c478bd9Sstevel@tonic-gate int on = 1;
14757c478bd9Sstevel@tonic-gate socklen_t len;
14767c478bd9Sstevel@tonic-gate int v4_addr;
14777c478bd9Sstevel@tonic-gate char *c, *c2, delm;
14787c478bd9Sstevel@tonic-gate in_port_t ports;
14797c478bd9Sstevel@tonic-gate
14807c478bd9Sstevel@tonic-gate pasv_refused = B_FALSE;
14817c478bd9Sstevel@tonic-gate if (passivemode) {
14827c478bd9Sstevel@tonic-gate data = socket(AF_INET6, SOCK_STREAM, 0);
14837c478bd9Sstevel@tonic-gate if (data < 0) {
14847c478bd9Sstevel@tonic-gate perror("socket");
14857c478bd9Sstevel@tonic-gate return (1);
14867c478bd9Sstevel@tonic-gate }
14877c478bd9Sstevel@tonic-gate if (timeout && setsockopt(data, IPPROTO_TCP,
14887c478bd9Sstevel@tonic-gate TCP_ABORT_THRESHOLD, (char *)&timeoutms,
14897c478bd9Sstevel@tonic-gate sizeof (timeoutms)) < 0 && debug)
14907c478bd9Sstevel@tonic-gate perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)");
14917c478bd9Sstevel@tonic-gate if ((options & SO_DEBUG) &&
14927c478bd9Sstevel@tonic-gate setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1493*92163adaSToomas Soome sizeof (on)) < 0)
14947c478bd9Sstevel@tonic-gate perror("setsockopt (ignored)");
14957c478bd9Sstevel@tonic-gate /*
14967c478bd9Sstevel@tonic-gate * Use the system wide default send and receive buffer sizes
14977c478bd9Sstevel@tonic-gate * unless one has been specified.
14987c478bd9Sstevel@tonic-gate */
14997c478bd9Sstevel@tonic-gate if (tcpwindowsize) {
15007c478bd9Sstevel@tonic-gate if (setsockopt(data, SOL_SOCKET, SO_SNDBUF,
15017c478bd9Sstevel@tonic-gate (char *)&tcpwindowsize, sizeof (tcpwindowsize)) < 0)
15027c478bd9Sstevel@tonic-gate perror("ftp: setsockopt (SO_SNDBUF - ignored)");
15037c478bd9Sstevel@tonic-gate if (setsockopt(data, SOL_SOCKET, SO_RCVBUF,
15047c478bd9Sstevel@tonic-gate (char *)&tcpwindowsize, sizeof (tcpwindowsize)) < 0)
15057c478bd9Sstevel@tonic-gate perror("ftp: setsockopt (SO_RCVBUF - ignored)");
15067c478bd9Sstevel@tonic-gate }
15077c478bd9Sstevel@tonic-gate
15087c478bd9Sstevel@tonic-gate data_addr = remctladdr;
15097c478bd9Sstevel@tonic-gate
15107c478bd9Sstevel@tonic-gate if (ipv6rem == B_TRUE) {
15117c478bd9Sstevel@tonic-gate if (command("EPSV") != COMPLETE) {
15127c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
1513*92163adaSToomas Soome "Passive mode refused. Try EPRT\n");
15147c478bd9Sstevel@tonic-gate pasv_refused = B_TRUE;
15157c478bd9Sstevel@tonic-gate goto noport;
15167c478bd9Sstevel@tonic-gate }
15177c478bd9Sstevel@tonic-gate
15187c478bd9Sstevel@tonic-gate /*
15197c478bd9Sstevel@tonic-gate * Get the data port from reply string from the
15207c478bd9Sstevel@tonic-gate * server. The format of the reply string is:
15217c478bd9Sstevel@tonic-gate * 229 Entering Extended Passive Mode (|||port|)
15227c478bd9Sstevel@tonic-gate * where | is the delimiter being used.
15237c478bd9Sstevel@tonic-gate */
15247c478bd9Sstevel@tonic-gate c = strchr(reply_string, '(');
15257c478bd9Sstevel@tonic-gate c2 = strchr(reply_string, ')');
15267c478bd9Sstevel@tonic-gate if (c == NULL || c2 == NULL) {
15277c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Extended passive mode"
15287c478bd9Sstevel@tonic-gate "parsing failure.\n");
15297c478bd9Sstevel@tonic-gate goto bad;
15307c478bd9Sstevel@tonic-gate }
153195c74518SToomas Soome *(c2 - 1) = '\0';
15327c478bd9Sstevel@tonic-gate /* Delimiter is the next char in the reply string */
15337c478bd9Sstevel@tonic-gate delm = *(++c);
15347c478bd9Sstevel@tonic-gate while (*c == delm) {
15357c478bd9Sstevel@tonic-gate if (!*(c++)) {
15367c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
15377c478bd9Sstevel@tonic-gate "Extended passive mode"
15387c478bd9Sstevel@tonic-gate "parsing failure.\n");
15397c478bd9Sstevel@tonic-gate goto bad;
15407c478bd9Sstevel@tonic-gate }
15417c478bd9Sstevel@tonic-gate }
15427c478bd9Sstevel@tonic-gate /* assign the port for data connection */
15437c478bd9Sstevel@tonic-gate ports = (in_port_t)atoi(c);
15447c478bd9Sstevel@tonic-gate data_addr.sin6_port = htons(ports);
15457c478bd9Sstevel@tonic-gate } else {
15467c478bd9Sstevel@tonic-gate int a1, a2, a3, a4, p1, p2;
15477c478bd9Sstevel@tonic-gate
15487c478bd9Sstevel@tonic-gate if (command("PASV") != COMPLETE) {
15497c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
1550*92163adaSToomas Soome "Passive mode refused. Try PORT\n");
15517c478bd9Sstevel@tonic-gate pasv_refused = B_TRUE;
15527c478bd9Sstevel@tonic-gate goto noport;
15537c478bd9Sstevel@tonic-gate }
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate /*
15567c478bd9Sstevel@tonic-gate * Get the data port from reply string from the
15577c478bd9Sstevel@tonic-gate * server. The format of the reply string is:
15587c478bd9Sstevel@tonic-gate * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)
15597c478bd9Sstevel@tonic-gate */
15607c478bd9Sstevel@tonic-gate if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
1561*92163adaSToomas Soome &a1, &a2, &a3, &a4, &p1, &p2) != 6) {
15627c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
1563*92163adaSToomas Soome "Passive mode parsing failure.\n");
15647c478bd9Sstevel@tonic-gate goto bad;
15657c478bd9Sstevel@tonic-gate }
15667c478bd9Sstevel@tonic-gate /*
15677c478bd9Sstevel@tonic-gate * Set the supplied address and port in an
15687c478bd9Sstevel@tonic-gate * IPv4-mapped IPv6 address.
15697c478bd9Sstevel@tonic-gate */
15707c478bd9Sstevel@tonic-gate a = (unsigned char *)&data_addr.sin6_addr +
1571*92163adaSToomas Soome sizeof (struct in6_addr) -
1572*92163adaSToomas Soome sizeof (struct in_addr);
15737c478bd9Sstevel@tonic-gate #define UC(b) ((b)&0xff)
15747c478bd9Sstevel@tonic-gate a[0] = UC(a1);
15757c478bd9Sstevel@tonic-gate a[1] = UC(a2);
15767c478bd9Sstevel@tonic-gate a[2] = UC(a3);
15777c478bd9Sstevel@tonic-gate a[3] = UC(a4);
15787c478bd9Sstevel@tonic-gate p = (unsigned char *)&data_addr.sin6_port;
15797c478bd9Sstevel@tonic-gate p[0] = UC(p1);
15807c478bd9Sstevel@tonic-gate p[1] = UC(p2);
15817c478bd9Sstevel@tonic-gate }
15827c478bd9Sstevel@tonic-gate
15837c478bd9Sstevel@tonic-gate if (connect(data, (struct sockaddr *)&data_addr,
15847c478bd9Sstevel@tonic-gate sizeof (data_addr)) < 0) {
15857c478bd9Sstevel@tonic-gate perror("connect");
15867c478bd9Sstevel@tonic-gate goto bad;
15877c478bd9Sstevel@tonic-gate }
15887c478bd9Sstevel@tonic-gate return (0);
15897c478bd9Sstevel@tonic-gate }
15907c478bd9Sstevel@tonic-gate
15917c478bd9Sstevel@tonic-gate noport:
15927c478bd9Sstevel@tonic-gate data_addr = myctladdr;
15937c478bd9Sstevel@tonic-gate if (sendport)
15947c478bd9Sstevel@tonic-gate data_addr.sin6_port = 0; /* let system pick one */
15957c478bd9Sstevel@tonic-gate
15967c478bd9Sstevel@tonic-gate if (data != -1)
15977c478bd9Sstevel@tonic-gate (void) close(data);
15987c478bd9Sstevel@tonic-gate data = socket(AF_INET6, SOCK_STREAM, 0);
15997c478bd9Sstevel@tonic-gate if (data < 0) {
16007c478bd9Sstevel@tonic-gate perror("ftp: socket");
16017c478bd9Sstevel@tonic-gate if (tmpno)
16027c478bd9Sstevel@tonic-gate sendport = 1;
16037c478bd9Sstevel@tonic-gate return (1);
16047c478bd9Sstevel@tonic-gate }
16057c478bd9Sstevel@tonic-gate if (!sendport)
16067c478bd9Sstevel@tonic-gate if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR,
16077c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)) < 0) {
16087c478bd9Sstevel@tonic-gate perror("ftp: setsockopt (SO_REUSEADDR)");
16097c478bd9Sstevel@tonic-gate goto bad;
16107c478bd9Sstevel@tonic-gate }
16117c478bd9Sstevel@tonic-gate if (bind(data,
16127c478bd9Sstevel@tonic-gate (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
16137c478bd9Sstevel@tonic-gate perror("ftp: bind");
16147c478bd9Sstevel@tonic-gate goto bad;
16157c478bd9Sstevel@tonic-gate }
16167c478bd9Sstevel@tonic-gate if (timeout && setsockopt(data, IPPROTO_TCP, TCP_ABORT_THRESHOLD,
16177c478bd9Sstevel@tonic-gate (char *)&timeoutms, sizeof (timeoutms)) < 0 && debug)
16187c478bd9Sstevel@tonic-gate perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)");
16197c478bd9Sstevel@tonic-gate if (options & SO_DEBUG &&
16207c478bd9Sstevel@tonic-gate setsockopt(data, SOL_SOCKET, SO_DEBUG,
16217c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)) < 0)
16227c478bd9Sstevel@tonic-gate perror("ftp: setsockopt (SO_DEBUG - ignored)");
16237c478bd9Sstevel@tonic-gate /*
16247c478bd9Sstevel@tonic-gate * Use the system wide default send and receive buffer sizes unless
16257c478bd9Sstevel@tonic-gate * one has been specified.
16267c478bd9Sstevel@tonic-gate */
16277c478bd9Sstevel@tonic-gate if (tcpwindowsize) {
16287c478bd9Sstevel@tonic-gate if (setsockopt(data, SOL_SOCKET, SO_SNDBUF,
16297c478bd9Sstevel@tonic-gate (char *)&tcpwindowsize, sizeof (tcpwindowsize)) < 0)
16307c478bd9Sstevel@tonic-gate perror("ftp: setsockopt (SO_SNDBUF - ignored)");
16317c478bd9Sstevel@tonic-gate if (setsockopt(data, SOL_SOCKET, SO_RCVBUF,
16327c478bd9Sstevel@tonic-gate (char *)&tcpwindowsize, sizeof (tcpwindowsize)) < 0)
16337c478bd9Sstevel@tonic-gate perror("ftp: setsockopt (SO_RCVBUF - ignored)");
16347c478bd9Sstevel@tonic-gate }
16357c478bd9Sstevel@tonic-gate len = sizeof (data_addr);
16367c478bd9Sstevel@tonic-gate if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
16377c478bd9Sstevel@tonic-gate perror("ftp: getsockname");
16387c478bd9Sstevel@tonic-gate goto bad;
16397c478bd9Sstevel@tonic-gate }
16407c478bd9Sstevel@tonic-gate
16417c478bd9Sstevel@tonic-gate v4_addr = IN6_IS_ADDR_V4MAPPED(&data_addr.sin6_addr);
16427c478bd9Sstevel@tonic-gate if (listen(data, 1) < 0)
16437c478bd9Sstevel@tonic-gate perror("ftp: listen");
16447c478bd9Sstevel@tonic-gate
16457c478bd9Sstevel@tonic-gate if (sendport) {
16467c478bd9Sstevel@tonic-gate a = (unsigned char *)&data_addr.sin6_addr;
16477c478bd9Sstevel@tonic-gate p = (unsigned char *)&data_addr.sin6_port;
16487c478bd9Sstevel@tonic-gate if (v4_addr) {
16497c478bd9Sstevel@tonic-gate result =
16507c478bd9Sstevel@tonic-gate command("PORT %d,%d,%d,%d,%d,%d",
16517c478bd9Sstevel@tonic-gate UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
16527c478bd9Sstevel@tonic-gate UC(p[0]), UC(p[1]));
16537c478bd9Sstevel@tonic-gate } else {
16547c478bd9Sstevel@tonic-gate char hname[INET6_ADDRSTRLEN];
16557c478bd9Sstevel@tonic-gate
16567c478bd9Sstevel@tonic-gate result = COMPLETE + 1;
16577c478bd9Sstevel@tonic-gate /*
16587c478bd9Sstevel@tonic-gate * if on previous try to server, it was
16597c478bd9Sstevel@tonic-gate * determined that the server doesn't support
16607c478bd9Sstevel@tonic-gate * EPRT, don't bother trying again. Just try
16617c478bd9Sstevel@tonic-gate * LPRT.
16627c478bd9Sstevel@tonic-gate */
16637c478bd9Sstevel@tonic-gate if (eport_supported == B_TRUE) {
16647c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, &data_addr.sin6_addr,
16657c478bd9Sstevel@tonic-gate hname, sizeof (hname)) != NULL) {
16667c478bd9Sstevel@tonic-gate result = command("EPRT |%d|%s|%d|", 2,
16677c478bd9Sstevel@tonic-gate hname, htons(data_addr.sin6_port));
16687c478bd9Sstevel@tonic-gate if (result != COMPLETE)
16697c478bd9Sstevel@tonic-gate eport_supported = B_FALSE;
1670*92163adaSToomas Soome }
16717c478bd9Sstevel@tonic-gate }
16727c478bd9Sstevel@tonic-gate /* Try LPRT */
16737c478bd9Sstevel@tonic-gate if (result != COMPLETE) {
16747c478bd9Sstevel@tonic-gate result = command(
1675*92163adaSToomas Soome "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
1676*92163adaSToomas Soome "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1677*92163adaSToomas Soome 6, 16,
1678*92163adaSToomas Soome UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1679*92163adaSToomas Soome UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
1680*92163adaSToomas Soome UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
1681*92163adaSToomas Soome UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
1682*92163adaSToomas Soome 2, UC(p[0]), UC(p[1]));
16837c478bd9Sstevel@tonic-gate }
16847c478bd9Sstevel@tonic-gate }
16857c478bd9Sstevel@tonic-gate
16867c478bd9Sstevel@tonic-gate if (result == ERROR && sendport == -1) {
16877c478bd9Sstevel@tonic-gate sendport = 0;
16887c478bd9Sstevel@tonic-gate tmpno = 1;
16897c478bd9Sstevel@tonic-gate goto noport;
16907c478bd9Sstevel@tonic-gate }
16917c478bd9Sstevel@tonic-gate return (result != COMPLETE);
16927c478bd9Sstevel@tonic-gate }
16937c478bd9Sstevel@tonic-gate if (tmpno)
16947c478bd9Sstevel@tonic-gate sendport = 1;
16957c478bd9Sstevel@tonic-gate return (0);
16967c478bd9Sstevel@tonic-gate bad:
16977c478bd9Sstevel@tonic-gate (void) close(data), data = -1;
16987c478bd9Sstevel@tonic-gate if (tmpno)
16997c478bd9Sstevel@tonic-gate sendport = 1;
17007c478bd9Sstevel@tonic-gate return (1);
17017c478bd9Sstevel@tonic-gate }
17027c478bd9Sstevel@tonic-gate
17037c478bd9Sstevel@tonic-gate static FILE *
dataconn(char * mode)17047c478bd9Sstevel@tonic-gate dataconn(char *mode)
17057c478bd9Sstevel@tonic-gate {
17067c478bd9Sstevel@tonic-gate struct sockaddr_in6 from;
17077c478bd9Sstevel@tonic-gate int s;
17087c478bd9Sstevel@tonic-gate socklen_t fromlen = sizeof (from);
17097c478bd9Sstevel@tonic-gate
17107c478bd9Sstevel@tonic-gate reset_timer();
17117c478bd9Sstevel@tonic-gate if (passivemode && !pasv_refused)
17127c478bd9Sstevel@tonic-gate return (fdopen(data, mode));
17137c478bd9Sstevel@tonic-gate
17147c478bd9Sstevel@tonic-gate s = accept(data, (struct sockaddr *)&from, &fromlen);
17157c478bd9Sstevel@tonic-gate if (s < 0) {
17167c478bd9Sstevel@tonic-gate perror("ftp: accept");
17177c478bd9Sstevel@tonic-gate (void) close(data), data = -1;
17187c478bd9Sstevel@tonic-gate return (NULL);
17197c478bd9Sstevel@tonic-gate }
17207c478bd9Sstevel@tonic-gate (void) close(data);
17217c478bd9Sstevel@tonic-gate data = s;
17227c478bd9Sstevel@tonic-gate return (fdopen(data, mode));
17237c478bd9Sstevel@tonic-gate }
17247c478bd9Sstevel@tonic-gate
17257c478bd9Sstevel@tonic-gate static void
ptransfer(char * direction,off_t bytes,hrtime_t t0,hrtime_t t1,char * local,char * remote)17267c478bd9Sstevel@tonic-gate ptransfer(char *direction, off_t bytes, hrtime_t t0,
17277c478bd9Sstevel@tonic-gate hrtime_t t1, char *local, char *remote)
17287c478bd9Sstevel@tonic-gate {
17297c478bd9Sstevel@tonic-gate hrtime_t td; /* nanoseconds in a 64 bit int */
17307c478bd9Sstevel@tonic-gate double s, bs;
17317c478bd9Sstevel@tonic-gate
17327c478bd9Sstevel@tonic-gate td = t1 - t0;
17337c478bd9Sstevel@tonic-gate s = (double)td / 1000000000.0; /* seconds */
17347c478bd9Sstevel@tonic-gate bs = (double)bytes / NONZERO(s);
17357c478bd9Sstevel@tonic-gate if (local && *local != '-')
17367c478bd9Sstevel@tonic-gate (void) printf("local: %s ", local);
17377c478bd9Sstevel@tonic-gate if (remote)
17387c478bd9Sstevel@tonic-gate (void) printf("remote: %s\n", remote);
17397c478bd9Sstevel@tonic-gate (void) printf("%lld bytes %s in %.2g seconds (%.2f Kbytes/s)\n",
1740*92163adaSToomas Soome (longlong_t)bytes, direction, s, bs / 1024.0);
17417c478bd9Sstevel@tonic-gate }
17427c478bd9Sstevel@tonic-gate
17437c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17447c478bd9Sstevel@tonic-gate static void
psabort(int sig)17457c478bd9Sstevel@tonic-gate psabort(int sig)
17467c478bd9Sstevel@tonic-gate {
17477c478bd9Sstevel@tonic-gate abrtflag++;
17487c478bd9Sstevel@tonic-gate }
17497c478bd9Sstevel@tonic-gate
17507c478bd9Sstevel@tonic-gate void
pswitch(int flag)17517c478bd9Sstevel@tonic-gate pswitch(int flag)
17527c478bd9Sstevel@tonic-gate {
17537c478bd9Sstevel@tonic-gate void (*oldintr)();
17547c478bd9Sstevel@tonic-gate static struct comvars {
17557c478bd9Sstevel@tonic-gate int connect;
17567c478bd9Sstevel@tonic-gate char name[MAXHOSTNAMELEN];
17577c478bd9Sstevel@tonic-gate struct sockaddr_in6 mctl;
17587c478bd9Sstevel@tonic-gate struct sockaddr_in6 hctl;
17597c478bd9Sstevel@tonic-gate FILE *in;
17607c478bd9Sstevel@tonic-gate FILE *out;
17617c478bd9Sstevel@tonic-gate int tpe;
17627c478bd9Sstevel@tonic-gate int cpnd;
17637c478bd9Sstevel@tonic-gate int sunqe;
17647c478bd9Sstevel@tonic-gate int runqe;
17657c478bd9Sstevel@tonic-gate int mcse;
17667c478bd9Sstevel@tonic-gate int ntflg;
17677c478bd9Sstevel@tonic-gate char nti[17];
17687c478bd9Sstevel@tonic-gate char nto[17];
17697c478bd9Sstevel@tonic-gate int mapflg;
17707c478bd9Sstevel@tonic-gate char mi[MAXPATHLEN];
17717c478bd9Sstevel@tonic-gate char mo[MAXPATHLEN];
17727c478bd9Sstevel@tonic-gate int authtype;
17737c478bd9Sstevel@tonic-gate int clvl;
17747c478bd9Sstevel@tonic-gate int dlvl;
17757c478bd9Sstevel@tonic-gate } proxstruct, tmpstruct;
17767c478bd9Sstevel@tonic-gate struct comvars *ip, *op;
17777c478bd9Sstevel@tonic-gate
17787c478bd9Sstevel@tonic-gate abrtflag = 0;
17797c478bd9Sstevel@tonic-gate oldintr = signal(SIGINT, psabort);
17807c478bd9Sstevel@tonic-gate if (flag) {
17817c478bd9Sstevel@tonic-gate if (proxy)
17827c478bd9Sstevel@tonic-gate return;
17837c478bd9Sstevel@tonic-gate ip = &tmpstruct;
17847c478bd9Sstevel@tonic-gate op = &proxstruct;
17857c478bd9Sstevel@tonic-gate proxy++;
17867c478bd9Sstevel@tonic-gate } else {
17877c478bd9Sstevel@tonic-gate if (!proxy)
17887c478bd9Sstevel@tonic-gate return;
17897c478bd9Sstevel@tonic-gate ip = &proxstruct;
17907c478bd9Sstevel@tonic-gate op = &tmpstruct;
17917c478bd9Sstevel@tonic-gate proxy = 0;
17927c478bd9Sstevel@tonic-gate }
17937c478bd9Sstevel@tonic-gate ip->connect = connected;
17947c478bd9Sstevel@tonic-gate connected = op->connect;
17957c478bd9Sstevel@tonic-gate if (hostname)
17967c478bd9Sstevel@tonic-gate (void) strlcpy(ip->name, hostname, sizeof (ip->name));
17977c478bd9Sstevel@tonic-gate else
17987c478bd9Sstevel@tonic-gate ip->name[0] = 0;
17997c478bd9Sstevel@tonic-gate hostname = op->name;
18007c478bd9Sstevel@tonic-gate ip->hctl = remctladdr;
18017c478bd9Sstevel@tonic-gate remctladdr = op->hctl;
18027c478bd9Sstevel@tonic-gate ip->mctl = myctladdr;
18037c478bd9Sstevel@tonic-gate myctladdr = op->mctl;
18047c478bd9Sstevel@tonic-gate ip->in = ctrl_in;
18057c478bd9Sstevel@tonic-gate ctrl_in = op->in;
18067c478bd9Sstevel@tonic-gate ip->out = ctrl_out;
18077c478bd9Sstevel@tonic-gate ctrl_out = op->out;
18087c478bd9Sstevel@tonic-gate ip->tpe = type;
18097c478bd9Sstevel@tonic-gate type = op->tpe;
18107c478bd9Sstevel@tonic-gate if (!type)
18117c478bd9Sstevel@tonic-gate type = 1;
18127c478bd9Sstevel@tonic-gate ip->cpnd = cpend;
18137c478bd9Sstevel@tonic-gate cpend = op->cpnd;
18147c478bd9Sstevel@tonic-gate ip->sunqe = sunique;
18157c478bd9Sstevel@tonic-gate sunique = op->sunqe;
18167c478bd9Sstevel@tonic-gate ip->runqe = runique;
18177c478bd9Sstevel@tonic-gate runique = op->runqe;
18187c478bd9Sstevel@tonic-gate ip->mcse = mcase;
18197c478bd9Sstevel@tonic-gate mcase = op->mcse;
18207c478bd9Sstevel@tonic-gate ip->ntflg = ntflag;
18217c478bd9Sstevel@tonic-gate ntflag = op->ntflg;
18227c478bd9Sstevel@tonic-gate (void) strlcpy(ip->nti, ntin, sizeof (ip->nti));
18237c478bd9Sstevel@tonic-gate (void) strlcpy(ntin, op->nti, sizeof (ntin));
18247c478bd9Sstevel@tonic-gate (void) strlcpy(ip->nto, ntout, sizeof (ip->nto));
18257c478bd9Sstevel@tonic-gate (void) strlcpy(ntout, op->nto, sizeof (ntout));
18267c478bd9Sstevel@tonic-gate ip->mapflg = mapflag;
18277c478bd9Sstevel@tonic-gate mapflag = op->mapflg;
18287c478bd9Sstevel@tonic-gate (void) strlcpy(ip->mi, mapin, sizeof (ip->mi));
18297c478bd9Sstevel@tonic-gate (void) strlcpy(mapin, op->mi, sizeof (mapin));
18307c478bd9Sstevel@tonic-gate (void) strlcpy(ip->mo, mapout, sizeof (ip->mo));
18317c478bd9Sstevel@tonic-gate (void) strlcpy(mapout, op->mo, sizeof (mapout));
18327c478bd9Sstevel@tonic-gate
18337c478bd9Sstevel@tonic-gate ip->authtype = auth_type;
18347c478bd9Sstevel@tonic-gate auth_type = op->authtype;
18357c478bd9Sstevel@tonic-gate ip->clvl = clevel;
18367c478bd9Sstevel@tonic-gate clevel = op->clvl;
18377c478bd9Sstevel@tonic-gate ip->dlvl = dlevel;
18387c478bd9Sstevel@tonic-gate dlevel = op->dlvl;
18397c478bd9Sstevel@tonic-gate if (!clevel)
18407c478bd9Sstevel@tonic-gate clevel = PROT_C;
18417c478bd9Sstevel@tonic-gate if (!dlevel)
18427c478bd9Sstevel@tonic-gate dlevel = PROT_C;
18437c478bd9Sstevel@tonic-gate
18447c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
18457c478bd9Sstevel@tonic-gate if (abrtflag) {
18467c478bd9Sstevel@tonic-gate abrtflag = 0;
18477c478bd9Sstevel@tonic-gate (*oldintr)();
18487c478bd9Sstevel@tonic-gate }
18497c478bd9Sstevel@tonic-gate }
18507c478bd9Sstevel@tonic-gate
18517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
18527c478bd9Sstevel@tonic-gate static void
abortpt(int sig)18537c478bd9Sstevel@tonic-gate abortpt(int sig)
18547c478bd9Sstevel@tonic-gate {
18557c478bd9Sstevel@tonic-gate (void) printf("\n");
18567c478bd9Sstevel@tonic-gate (void) fflush(stdout);
18577c478bd9Sstevel@tonic-gate ptabflg++;
18587c478bd9Sstevel@tonic-gate mflag = 0;
18597c478bd9Sstevel@tonic-gate abrtflag = 0;
18607c478bd9Sstevel@tonic-gate longjmp(ptabort, 1);
18617c478bd9Sstevel@tonic-gate }
18627c478bd9Sstevel@tonic-gate
18637c478bd9Sstevel@tonic-gate static void
proxtrans(char * cmd,char * local,char * remote)18647c478bd9Sstevel@tonic-gate proxtrans(char *cmd, char *local, char *remote)
18657c478bd9Sstevel@tonic-gate {
18667c478bd9Sstevel@tonic-gate void (*oldintr)();
18677c478bd9Sstevel@tonic-gate int tmptype, oldtype = 0, secndflag = 0, nfnd;
18687c478bd9Sstevel@tonic-gate extern jmp_buf ptabort;
18697c478bd9Sstevel@tonic-gate char *cmd2;
18707c478bd9Sstevel@tonic-gate struct fd_set mask;
18717c478bd9Sstevel@tonic-gate int ipv4_addr = IN6_IS_ADDR_V4MAPPED(&remctladdr.sin6_addr);
18727c478bd9Sstevel@tonic-gate
18737c478bd9Sstevel@tonic-gate if (strcmp(cmd, "RETR"))
18747c478bd9Sstevel@tonic-gate cmd2 = "RETR";
18757c478bd9Sstevel@tonic-gate else
18767c478bd9Sstevel@tonic-gate cmd2 = runique ? "STOU" : "STOR";
18777c478bd9Sstevel@tonic-gate if (command(ipv4_addr ? "PASV" : "EPSV") != COMPLETE) {
18787c478bd9Sstevel@tonic-gate (void) printf(
18797c478bd9Sstevel@tonic-gate "proxy server does not support third part transfers.\n");
18807c478bd9Sstevel@tonic-gate return;
18817c478bd9Sstevel@tonic-gate }
18827c478bd9Sstevel@tonic-gate tmptype = type;
18837c478bd9Sstevel@tonic-gate pswitch(0);
18847c478bd9Sstevel@tonic-gate if (!connected) {
18857c478bd9Sstevel@tonic-gate (void) printf("No primary connection\n");
18867c478bd9Sstevel@tonic-gate pswitch(1);
18877c478bd9Sstevel@tonic-gate code = -1;
18887c478bd9Sstevel@tonic-gate return;
18897c478bd9Sstevel@tonic-gate }
18907c478bd9Sstevel@tonic-gate if (type != tmptype) {
18917c478bd9Sstevel@tonic-gate oldtype = type;
18927c478bd9Sstevel@tonic-gate switch (tmptype) {
18937c478bd9Sstevel@tonic-gate case TYPE_A:
18947c478bd9Sstevel@tonic-gate setascii(0, NULL);
18957c478bd9Sstevel@tonic-gate break;
18967c478bd9Sstevel@tonic-gate case TYPE_I:
18977c478bd9Sstevel@tonic-gate setbinary(0, NULL);
18987c478bd9Sstevel@tonic-gate break;
18997c478bd9Sstevel@tonic-gate case TYPE_E:
19007c478bd9Sstevel@tonic-gate setebcdic(0, NULL);
19017c478bd9Sstevel@tonic-gate break;
19027c478bd9Sstevel@tonic-gate case TYPE_L:
19037c478bd9Sstevel@tonic-gate settenex(0, NULL);
19047c478bd9Sstevel@tonic-gate break;
19057c478bd9Sstevel@tonic-gate }
19067c478bd9Sstevel@tonic-gate }
19077c478bd9Sstevel@tonic-gate if (command(ipv4_addr ? "PORT %s" : "EPRT %s", pasv) != COMPLETE) {
19087c478bd9Sstevel@tonic-gate switch (oldtype) {
19097c478bd9Sstevel@tonic-gate case 0:
19107c478bd9Sstevel@tonic-gate break;
19117c478bd9Sstevel@tonic-gate case TYPE_A:
19127c478bd9Sstevel@tonic-gate setascii(0, NULL);
19137c478bd9Sstevel@tonic-gate break;
19147c478bd9Sstevel@tonic-gate case TYPE_I:
19157c478bd9Sstevel@tonic-gate setbinary(0, NULL);
19167c478bd9Sstevel@tonic-gate break;
19177c478bd9Sstevel@tonic-gate case TYPE_E:
19187c478bd9Sstevel@tonic-gate setebcdic(0, NULL);
19197c478bd9Sstevel@tonic-gate break;
19207c478bd9Sstevel@tonic-gate case TYPE_L:
19217c478bd9Sstevel@tonic-gate settenex(0, NULL);
19227c478bd9Sstevel@tonic-gate break;
19237c478bd9Sstevel@tonic-gate }
19247c478bd9Sstevel@tonic-gate pswitch(1);
19257c478bd9Sstevel@tonic-gate return;
19267c478bd9Sstevel@tonic-gate }
19277c478bd9Sstevel@tonic-gate if (setjmp(ptabort))
19287c478bd9Sstevel@tonic-gate goto abort;
19297c478bd9Sstevel@tonic-gate oldintr = signal(SIGINT, (void (*)())abortpt);
19307c478bd9Sstevel@tonic-gate if (command("%s %s", cmd, remote) != PRELIM) {
19317c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
19327c478bd9Sstevel@tonic-gate switch (oldtype) {
19337c478bd9Sstevel@tonic-gate case 0:
19347c478bd9Sstevel@tonic-gate break;
19357c478bd9Sstevel@tonic-gate case TYPE_A:
19367c478bd9Sstevel@tonic-gate setascii(0, NULL);
19377c478bd9Sstevel@tonic-gate break;
19387c478bd9Sstevel@tonic-gate case TYPE_I:
19397c478bd9Sstevel@tonic-gate setbinary(0, NULL);
19407c478bd9Sstevel@tonic-gate break;
19417c478bd9Sstevel@tonic-gate case TYPE_E:
19427c478bd9Sstevel@tonic-gate setebcdic(0, NULL);
19437c478bd9Sstevel@tonic-gate break;
19447c478bd9Sstevel@tonic-gate case TYPE_L:
19457c478bd9Sstevel@tonic-gate settenex(0, NULL);
19467c478bd9Sstevel@tonic-gate break;
19477c478bd9Sstevel@tonic-gate }
19487c478bd9Sstevel@tonic-gate pswitch(1);
19497c478bd9Sstevel@tonic-gate return;
19507c478bd9Sstevel@tonic-gate }
19517c478bd9Sstevel@tonic-gate (void) sleep(2);
19527c478bd9Sstevel@tonic-gate pswitch(1);
19537c478bd9Sstevel@tonic-gate secndflag++;
19547c478bd9Sstevel@tonic-gate if (command("%s %s", cmd2, local) != PRELIM)
19557c478bd9Sstevel@tonic-gate goto abort;
19567c478bd9Sstevel@tonic-gate ptflag++;
19577c478bd9Sstevel@tonic-gate (void) getreply(0);
19587c478bd9Sstevel@tonic-gate pswitch(0);
19597c478bd9Sstevel@tonic-gate (void) getreply(0);
19607c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
19617c478bd9Sstevel@tonic-gate switch (oldtype) {
19627c478bd9Sstevel@tonic-gate case 0:
19637c478bd9Sstevel@tonic-gate break;
19647c478bd9Sstevel@tonic-gate case TYPE_A:
19657c478bd9Sstevel@tonic-gate setascii(0, NULL);
19667c478bd9Sstevel@tonic-gate break;
19677c478bd9Sstevel@tonic-gate case TYPE_I:
19687c478bd9Sstevel@tonic-gate setbinary(0, NULL);
19697c478bd9Sstevel@tonic-gate break;
19707c478bd9Sstevel@tonic-gate case TYPE_E:
19717c478bd9Sstevel@tonic-gate setebcdic(0, NULL);
19727c478bd9Sstevel@tonic-gate break;
19737c478bd9Sstevel@tonic-gate case TYPE_L:
19747c478bd9Sstevel@tonic-gate settenex(0, NULL);
19757c478bd9Sstevel@tonic-gate break;
19767c478bd9Sstevel@tonic-gate }
19777c478bd9Sstevel@tonic-gate pswitch(1);
19787c478bd9Sstevel@tonic-gate ptflag = 0;
19797c478bd9Sstevel@tonic-gate (void) printf("local: %s remote: %s\n", local, remote);
19807c478bd9Sstevel@tonic-gate return;
19817c478bd9Sstevel@tonic-gate abort:
19827c478bd9Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN);
19837c478bd9Sstevel@tonic-gate ptflag = 0;
19847c478bd9Sstevel@tonic-gate if (strcmp(cmd, "RETR") && !proxy)
19857c478bd9Sstevel@tonic-gate pswitch(1);
19867c478bd9Sstevel@tonic-gate else if ((strcmp(cmd, "RETR") == 0) && proxy)
19877c478bd9Sstevel@tonic-gate pswitch(0);
19887c478bd9Sstevel@tonic-gate if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
19897c478bd9Sstevel@tonic-gate if (command("%s %s", cmd2, local) != PRELIM) {
19907c478bd9Sstevel@tonic-gate pswitch(0);
19917c478bd9Sstevel@tonic-gate switch (oldtype) {
19927c478bd9Sstevel@tonic-gate case 0:
19937c478bd9Sstevel@tonic-gate break;
19947c478bd9Sstevel@tonic-gate case TYPE_A:
19957c478bd9Sstevel@tonic-gate setascii(0, NULL);
19967c478bd9Sstevel@tonic-gate break;
19977c478bd9Sstevel@tonic-gate case TYPE_I:
19987c478bd9Sstevel@tonic-gate setbinary(0, NULL);
19997c478bd9Sstevel@tonic-gate break;
20007c478bd9Sstevel@tonic-gate case TYPE_E:
20017c478bd9Sstevel@tonic-gate setebcdic(0, NULL);
20027c478bd9Sstevel@tonic-gate break;
20037c478bd9Sstevel@tonic-gate case TYPE_L:
20047c478bd9Sstevel@tonic-gate settenex(0, NULL);
20057c478bd9Sstevel@tonic-gate break;
20067c478bd9Sstevel@tonic-gate }
20077c478bd9Sstevel@tonic-gate if (cpend) {
20087c478bd9Sstevel@tonic-gate char msg[2];
20097c478bd9Sstevel@tonic-gate
20107c478bd9Sstevel@tonic-gate (void) fprintf(ctrl_out, "%c%c", IAC, IP);
20117c478bd9Sstevel@tonic-gate (void) fflush(ctrl_out);
20127c478bd9Sstevel@tonic-gate *msg = (char)IAC;
20137c478bd9Sstevel@tonic-gate *(msg+1) = (char)DM;
20147c478bd9Sstevel@tonic-gate if (send(fileno(ctrl_out), msg, 2, MSG_OOB)
20157c478bd9Sstevel@tonic-gate != 2)
20167c478bd9Sstevel@tonic-gate perror("abort");
20177c478bd9Sstevel@tonic-gate (void) fprintf(ctrl_out, "ABOR\r\n");
20187c478bd9Sstevel@tonic-gate (void) fflush(ctrl_out);
20197c478bd9Sstevel@tonic-gate FD_ZERO(&mask);
20207c478bd9Sstevel@tonic-gate FD_SET(fileno(ctrl_in), &mask);
20217c478bd9Sstevel@tonic-gate if ((nfnd = empty(&mask, 10,
20227c478bd9Sstevel@tonic-gate fileno(ctrl_in) + 1)) <= 0) {
20237c478bd9Sstevel@tonic-gate if (nfnd < 0) {
20247c478bd9Sstevel@tonic-gate perror("abort");
20257c478bd9Sstevel@tonic-gate }
20267c478bd9Sstevel@tonic-gate if (ptabflg)
20277c478bd9Sstevel@tonic-gate code = -1;
20287c478bd9Sstevel@tonic-gate lostpeer(0);
20297c478bd9Sstevel@tonic-gate }
20307c478bd9Sstevel@tonic-gate (void) getreply(0);
20317c478bd9Sstevel@tonic-gate (void) getreply(0);
20327c478bd9Sstevel@tonic-gate }
20337c478bd9Sstevel@tonic-gate }
20347c478bd9Sstevel@tonic-gate pswitch(1);
20357c478bd9Sstevel@tonic-gate if (ptabflg)
20367c478bd9Sstevel@tonic-gate code = -1;
20377c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
20387c478bd9Sstevel@tonic-gate return;
20397c478bd9Sstevel@tonic-gate }
20407c478bd9Sstevel@tonic-gate if (cpend) {
20417c478bd9Sstevel@tonic-gate char msg[2];
20427c478bd9Sstevel@tonic-gate
20437c478bd9Sstevel@tonic-gate (void) fprintf(ctrl_out, "%c%c", IAC, IP);
20447c478bd9Sstevel@tonic-gate (void) fflush(ctrl_out);
20457c478bd9Sstevel@tonic-gate *msg = (char)IAC;
20467c478bd9Sstevel@tonic-gate *(msg+1) = (char)DM;
20477c478bd9Sstevel@tonic-gate if (send(fileno(ctrl_out), msg, 2, MSG_OOB) != 2)
20487c478bd9Sstevel@tonic-gate perror("abort");
20497c478bd9Sstevel@tonic-gate (void) fprintf(ctrl_out, "ABOR\r\n");
20507c478bd9Sstevel@tonic-gate (void) fflush(ctrl_out);
20517c478bd9Sstevel@tonic-gate FD_ZERO(&mask);
20527c478bd9Sstevel@tonic-gate FD_SET(fileno(ctrl_in), &mask);
20537c478bd9Sstevel@tonic-gate if ((nfnd = empty(&mask, 10, fileno(ctrl_in) + 1)) <= 0) {
20547c478bd9Sstevel@tonic-gate if (nfnd < 0) {
20557c478bd9Sstevel@tonic-gate perror("abort");
20567c478bd9Sstevel@tonic-gate }
20577c478bd9Sstevel@tonic-gate if (ptabflg)
20587c478bd9Sstevel@tonic-gate code = -1;
20597c478bd9Sstevel@tonic-gate lostpeer(0);
20607c478bd9Sstevel@tonic-gate }
20617c478bd9Sstevel@tonic-gate (void) getreply(0);
20627c478bd9Sstevel@tonic-gate (void) getreply(0);
20637c478bd9Sstevel@tonic-gate }
20647c478bd9Sstevel@tonic-gate pswitch(!proxy);
20657c478bd9Sstevel@tonic-gate if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
20667c478bd9Sstevel@tonic-gate if (command("%s %s", cmd2, local) != PRELIM) {
20677c478bd9Sstevel@tonic-gate pswitch(0);
20687c478bd9Sstevel@tonic-gate switch (oldtype) {
20697c478bd9Sstevel@tonic-gate case 0:
20707c478bd9Sstevel@tonic-gate break;
20717c478bd9Sstevel@tonic-gate case TYPE_A:
20727c478bd9Sstevel@tonic-gate setascii(0, NULL);
20737c478bd9Sstevel@tonic-gate break;
20747c478bd9Sstevel@tonic-gate case TYPE_I:
20757c478bd9Sstevel@tonic-gate setbinary(0, NULL);
20767c478bd9Sstevel@tonic-gate break;
20777c478bd9Sstevel@tonic-gate case TYPE_E:
20787c478bd9Sstevel@tonic-gate setebcdic(0, NULL);
20797c478bd9Sstevel@tonic-gate break;
20807c478bd9Sstevel@tonic-gate case TYPE_L:
20817c478bd9Sstevel@tonic-gate settenex(0, NULL);
20827c478bd9Sstevel@tonic-gate break;
20837c478bd9Sstevel@tonic-gate }
20847c478bd9Sstevel@tonic-gate if (cpend) {
20857c478bd9Sstevel@tonic-gate char msg[2];
20867c478bd9Sstevel@tonic-gate
20877c478bd9Sstevel@tonic-gate (void) fprintf(ctrl_out, "%c%c", IAC, IP);
20887c478bd9Sstevel@tonic-gate (void) fflush(ctrl_out);
20897c478bd9Sstevel@tonic-gate *msg = (char)IAC;
20907c478bd9Sstevel@tonic-gate *(msg+1) = (char)DM;
20917c478bd9Sstevel@tonic-gate if (send(fileno(ctrl_out), msg, 2, MSG_OOB)
20927c478bd9Sstevel@tonic-gate != 2)
20937c478bd9Sstevel@tonic-gate perror("abort");
20947c478bd9Sstevel@tonic-gate (void) fprintf(ctrl_out, "ABOR\r\n");
20957c478bd9Sstevel@tonic-gate (void) fflush(ctrl_out);
20967c478bd9Sstevel@tonic-gate FD_ZERO(&mask);
20977c478bd9Sstevel@tonic-gate FD_SET(fileno(ctrl_in), &mask);
20987c478bd9Sstevel@tonic-gate if ((nfnd = empty(&mask, 10,
20997c478bd9Sstevel@tonic-gate fileno(ctrl_in) + 1)) <= 0) {
21007c478bd9Sstevel@tonic-gate if (nfnd < 0) {
21017c478bd9Sstevel@tonic-gate perror("abort");
21027c478bd9Sstevel@tonic-gate }
21037c478bd9Sstevel@tonic-gate if (ptabflg)
21047c478bd9Sstevel@tonic-gate code = -1;
21057c478bd9Sstevel@tonic-gate lostpeer(0);
21067c478bd9Sstevel@tonic-gate }
21077c478bd9Sstevel@tonic-gate (void) getreply(0);
21087c478bd9Sstevel@tonic-gate (void) getreply(0);
21097c478bd9Sstevel@tonic-gate }
21107c478bd9Sstevel@tonic-gate pswitch(1);
21117c478bd9Sstevel@tonic-gate if (ptabflg)
21127c478bd9Sstevel@tonic-gate code = -1;
21137c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
21147c478bd9Sstevel@tonic-gate return;
21157c478bd9Sstevel@tonic-gate }
21167c478bd9Sstevel@tonic-gate }
21177c478bd9Sstevel@tonic-gate if (cpend) {
21187c478bd9Sstevel@tonic-gate char msg[2];
21197c478bd9Sstevel@tonic-gate
21207c478bd9Sstevel@tonic-gate (void) fprintf(ctrl_out, "%c%c", IAC, IP);
21217c478bd9Sstevel@tonic-gate (void) fflush(ctrl_out);
21227c478bd9Sstevel@tonic-gate *msg = (char)IAC;
21237c478bd9Sstevel@tonic-gate *(msg+1) = (char)DM;
21247c478bd9Sstevel@tonic-gate if (send(fileno(ctrl_out), msg, 2, MSG_OOB) != 2)
21257c478bd9Sstevel@tonic-gate perror("abort");
21267c478bd9Sstevel@tonic-gate (void) fprintf(ctrl_out, "ABOR\r\n");
21277c478bd9Sstevel@tonic-gate (void) fflush(ctrl_out);
21287c478bd9Sstevel@tonic-gate FD_ZERO(&mask);
21297c478bd9Sstevel@tonic-gate FD_SET(fileno(ctrl_in), &mask);
21307c478bd9Sstevel@tonic-gate if ((nfnd = empty(&mask, 10, fileno(ctrl_in) + 1)) <= 0) {
21317c478bd9Sstevel@tonic-gate if (nfnd < 0) {
21327c478bd9Sstevel@tonic-gate perror("abort");
21337c478bd9Sstevel@tonic-gate }
21347c478bd9Sstevel@tonic-gate if (ptabflg)
21357c478bd9Sstevel@tonic-gate code = -1;
21367c478bd9Sstevel@tonic-gate lostpeer(0);
21377c478bd9Sstevel@tonic-gate }
21387c478bd9Sstevel@tonic-gate (void) getreply(0);
21397c478bd9Sstevel@tonic-gate (void) getreply(0);
21407c478bd9Sstevel@tonic-gate }
21417c478bd9Sstevel@tonic-gate pswitch(!proxy);
21427c478bd9Sstevel@tonic-gate if (cpend) {
21437c478bd9Sstevel@tonic-gate FD_ZERO(&mask);
21447c478bd9Sstevel@tonic-gate FD_SET(fileno(ctrl_in), &mask);
21457c478bd9Sstevel@tonic-gate if ((nfnd = empty(&mask, 10, fileno(ctrl_in) + 1)) <= 0) {
21467c478bd9Sstevel@tonic-gate if (nfnd < 0) {
21477c478bd9Sstevel@tonic-gate perror("abort");
21487c478bd9Sstevel@tonic-gate }
21497c478bd9Sstevel@tonic-gate if (ptabflg)
21507c478bd9Sstevel@tonic-gate code = -1;
21517c478bd9Sstevel@tonic-gate lostpeer(0);
21527c478bd9Sstevel@tonic-gate }
21537c478bd9Sstevel@tonic-gate (void) getreply(0);
21547c478bd9Sstevel@tonic-gate (void) getreply(0);
21557c478bd9Sstevel@tonic-gate }
21567c478bd9Sstevel@tonic-gate if (proxy)
21577c478bd9Sstevel@tonic-gate pswitch(0);
21587c478bd9Sstevel@tonic-gate switch (oldtype) {
21597c478bd9Sstevel@tonic-gate case 0:
21607c478bd9Sstevel@tonic-gate break;
21617c478bd9Sstevel@tonic-gate case TYPE_A:
21627c478bd9Sstevel@tonic-gate setascii(0, NULL);
21637c478bd9Sstevel@tonic-gate break;
21647c478bd9Sstevel@tonic-gate case TYPE_I:
21657c478bd9Sstevel@tonic-gate setbinary(0, NULL);
21667c478bd9Sstevel@tonic-gate break;
21677c478bd9Sstevel@tonic-gate case TYPE_E:
21687c478bd9Sstevel@tonic-gate setebcdic(0, NULL);
21697c478bd9Sstevel@tonic-gate break;
21707c478bd9Sstevel@tonic-gate case TYPE_L:
21717c478bd9Sstevel@tonic-gate settenex(0, NULL);
21727c478bd9Sstevel@tonic-gate break;
21737c478bd9Sstevel@tonic-gate }
21747c478bd9Sstevel@tonic-gate pswitch(1);
21757c478bd9Sstevel@tonic-gate if (ptabflg)
21767c478bd9Sstevel@tonic-gate code = -1;
21777c478bd9Sstevel@tonic-gate (void) signal(SIGINT, oldintr);
21787c478bd9Sstevel@tonic-gate }
21797c478bd9Sstevel@tonic-gate
21807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21817c478bd9Sstevel@tonic-gate void
reset(int argc,char * argv[])21827c478bd9Sstevel@tonic-gate reset(int argc, char *argv[])
21837c478bd9Sstevel@tonic-gate {
21847c478bd9Sstevel@tonic-gate struct fd_set mask;
21857c478bd9Sstevel@tonic-gate int nfnd = 1;
21867c478bd9Sstevel@tonic-gate
21877c478bd9Sstevel@tonic-gate FD_ZERO(&mask);
21887c478bd9Sstevel@tonic-gate while (nfnd > 0) {
21897c478bd9Sstevel@tonic-gate FD_SET(fileno(ctrl_in), &mask);
21907c478bd9Sstevel@tonic-gate if ((nfnd = empty(&mask, 0, fileno(ctrl_in) + 1)) < 0) {
21917c478bd9Sstevel@tonic-gate perror("reset");
21927c478bd9Sstevel@tonic-gate code = -1;
21937c478bd9Sstevel@tonic-gate lostpeer(0);
21947c478bd9Sstevel@tonic-gate } else if (nfnd > 0) {
21957c478bd9Sstevel@tonic-gate (void) getreply(0);
21967c478bd9Sstevel@tonic-gate }
21977c478bd9Sstevel@tonic-gate }
21987c478bd9Sstevel@tonic-gate }
21997c478bd9Sstevel@tonic-gate
22007c478bd9Sstevel@tonic-gate static char *
gunique(char * local)22017c478bd9Sstevel@tonic-gate gunique(char *local)
22027c478bd9Sstevel@tonic-gate {
22037c478bd9Sstevel@tonic-gate static char new[MAXPATHLEN];
22047c478bd9Sstevel@tonic-gate char *cp = rindex(local, '/');
22057c478bd9Sstevel@tonic-gate int d, count = 0;
22067c478bd9Sstevel@tonic-gate char ext = '1';
22077c478bd9Sstevel@tonic-gate
22087c478bd9Sstevel@tonic-gate if (cp)
22097c478bd9Sstevel@tonic-gate *cp = '\0';
22107c478bd9Sstevel@tonic-gate d = access(cp ? local : ".", 2);
22117c478bd9Sstevel@tonic-gate if (cp)
22127c478bd9Sstevel@tonic-gate *cp = '/';
22137c478bd9Sstevel@tonic-gate if (d < 0) {
22147c478bd9Sstevel@tonic-gate perror(local);
22157c478bd9Sstevel@tonic-gate return ((char *)0);
22167c478bd9Sstevel@tonic-gate }
22177c478bd9Sstevel@tonic-gate if (strlcpy(new, local, sizeof (new)) >= sizeof (new))
22187c478bd9Sstevel@tonic-gate (void) printf("gunique: too long: local %s, %d, new %d\n",
22197c478bd9Sstevel@tonic-gate local, strlen(local), sizeof (new));
22207c478bd9Sstevel@tonic-gate
22217c478bd9Sstevel@tonic-gate cp = new + strlen(new);
22227c478bd9Sstevel@tonic-gate *cp++ = '.';
22237c478bd9Sstevel@tonic-gate while (!d) {
22247c478bd9Sstevel@tonic-gate if (++count == 100) {
22257c478bd9Sstevel@tonic-gate (void) printf(
2226*92163adaSToomas Soome "gunique: can't find unique file name.\n");
2227*92163adaSToomas Soome return (NULL);
22287c478bd9Sstevel@tonic-gate }
22297c478bd9Sstevel@tonic-gate *cp++ = ext;
22307c478bd9Sstevel@tonic-gate *cp = '\0';
22317c478bd9Sstevel@tonic-gate if (ext == '9')
22327c478bd9Sstevel@tonic-gate ext = '0';
22337c478bd9Sstevel@tonic-gate else
22347c478bd9Sstevel@tonic-gate ext++;
22357c478bd9Sstevel@tonic-gate if ((d = access(new, 0)) < 0)
22367c478bd9Sstevel@tonic-gate break;
22377c478bd9Sstevel@tonic-gate if (ext != '0')
22387c478bd9Sstevel@tonic-gate cp--;
22397c478bd9Sstevel@tonic-gate else if (*(cp - 2) == '.')
22407c478bd9Sstevel@tonic-gate *(cp - 1) = '1';
22417c478bd9Sstevel@tonic-gate else {
22427c478bd9Sstevel@tonic-gate *(cp - 2) = *(cp - 2) + 1;
22437c478bd9Sstevel@tonic-gate cp--;
22447c478bd9Sstevel@tonic-gate }
22457c478bd9Sstevel@tonic-gate }
22467c478bd9Sstevel@tonic-gate return (new);
22477c478bd9Sstevel@tonic-gate }
22487c478bd9Sstevel@tonic-gate
22497c478bd9Sstevel@tonic-gate /*
22507c478bd9Sstevel@tonic-gate * This is a wrap-around function for inet_ntop(). In case the af is AF_INET6
22517c478bd9Sstevel@tonic-gate * and the address pointed by src is a IPv4-mapped IPv6 address, it
22527c478bd9Sstevel@tonic-gate * returns printable IPv4 address, not IPv4-mapped IPv6 address. In other cases
22537c478bd9Sstevel@tonic-gate * it behaves just like inet_ntop().
22547c478bd9Sstevel@tonic-gate */
22557c478bd9Sstevel@tonic-gate const char *
inet_ntop_native(int af,const void * src,char * dst,size_t size)22567c478bd9Sstevel@tonic-gate inet_ntop_native(int af, const void *src, char *dst, size_t size)
22577c478bd9Sstevel@tonic-gate {
22587c478bd9Sstevel@tonic-gate struct in_addr src4;
22597c478bd9Sstevel@tonic-gate const char *result;
22607c478bd9Sstevel@tonic-gate struct sockaddr_in *sin;
22617c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6;
22627c478bd9Sstevel@tonic-gate
22637c478bd9Sstevel@tonic-gate if (af == AF_INET6) {
22647c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)src;
22657c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
22667c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, &src4);
22677c478bd9Sstevel@tonic-gate result = inet_ntop(AF_INET, &src4, dst, size);
22687c478bd9Sstevel@tonic-gate } else {
22697c478bd9Sstevel@tonic-gate result = inet_ntop(AF_INET6, &sin6->sin6_addr,
22707c478bd9Sstevel@tonic-gate dst, size);
22717c478bd9Sstevel@tonic-gate }
22727c478bd9Sstevel@tonic-gate } else {
22737c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)src;
22747c478bd9Sstevel@tonic-gate result = inet_ntop(af, &sin->sin_addr, dst, size);
22757c478bd9Sstevel@tonic-gate }
22767c478bd9Sstevel@tonic-gate
22777c478bd9Sstevel@tonic-gate return (result);
22787c478bd9Sstevel@tonic-gate }
22797c478bd9Sstevel@tonic-gate
22807c478bd9Sstevel@tonic-gate int
secure_command(char * cmd)22817c478bd9Sstevel@tonic-gate secure_command(char *cmd)
22827c478bd9Sstevel@tonic-gate {
22837c478bd9Sstevel@tonic-gate unsigned char *in = NULL, *out = NULL;
22847c478bd9Sstevel@tonic-gate int length = 0;
22857c478bd9Sstevel@tonic-gate size_t inlen;
22867c478bd9Sstevel@tonic-gate
22877c478bd9Sstevel@tonic-gate if ((auth_type != AUTHTYPE_NONE) && clevel != PROT_C) {
22887c478bd9Sstevel@tonic-gate gss_buffer_desc in_buf, out_buf;
22897c478bd9Sstevel@tonic-gate OM_uint32 maj_stat, min_stat;
22907c478bd9Sstevel@tonic-gate
22917c478bd9Sstevel@tonic-gate /* secure_command (based on level) */
22927c478bd9Sstevel@tonic-gate if (auth_type == AUTHTYPE_GSSAPI) {
22937c478bd9Sstevel@tonic-gate OM_uint32 expire_time;
22947c478bd9Sstevel@tonic-gate int conf_state;
22957c478bd9Sstevel@tonic-gate /* clevel = PROT_P; */
22967c478bd9Sstevel@tonic-gate in_buf.value = cmd;
22977c478bd9Sstevel@tonic-gate in_buf.length = strlen(cmd) + 1;
22987c478bd9Sstevel@tonic-gate
22997c478bd9Sstevel@tonic-gate maj_stat = gss_context_time(&min_stat, gcontext,
2300*92163adaSToomas Soome &expire_time);
23017c478bd9Sstevel@tonic-gate if (GSS_ERROR(maj_stat)) {
23027c478bd9Sstevel@tonic-gate user_gss_error(maj_stat, min_stat,
2303*92163adaSToomas Soome "gss context has expired");
23047c478bd9Sstevel@tonic-gate fatal("Your gss credentials have expired. "
2305*92163adaSToomas Soome "Good-bye!");
23067c478bd9Sstevel@tonic-gate }
23077c478bd9Sstevel@tonic-gate maj_stat = gss_seal(&min_stat, gcontext,
2308*92163adaSToomas Soome (clevel == PROT_P), /* private */
2309*92163adaSToomas Soome GSS_C_QOP_DEFAULT,
2310*92163adaSToomas Soome &in_buf, &conf_state,
2311*92163adaSToomas Soome &out_buf);
23127c478bd9Sstevel@tonic-gate if (maj_stat != GSS_S_COMPLETE) {
23137c478bd9Sstevel@tonic-gate /* generally need to deal */
23147c478bd9Sstevel@tonic-gate user_gss_error(maj_stat, min_stat,
2315*92163adaSToomas Soome (clevel == PROT_P) ?
2316*92163adaSToomas Soome "gss_seal ENC didn't complete":
2317*92163adaSToomas Soome "gss_seal MIC didn't complete");
23187c478bd9Sstevel@tonic-gate } else if ((clevel == PROT_P) && !conf_state) {
23197c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
2320*92163adaSToomas Soome "GSSAPI didn't encrypt message");
23217c478bd9Sstevel@tonic-gate out = out_buf.value;
23227c478bd9Sstevel@tonic-gate } else {
23237c478bd9Sstevel@tonic-gate if (debug)
2324*92163adaSToomas Soome (void) fprintf(stderr,
2325*92163adaSToomas Soome "sealed (%s) %d bytes\n",
2326*92163adaSToomas Soome clevel == PROT_P ? "ENC" : "MIC",
2327*92163adaSToomas Soome out_buf.length);
23287c478bd9Sstevel@tonic-gate
23297c478bd9Sstevel@tonic-gate out = out_buf.value;
23307c478bd9Sstevel@tonic-gate }
23317c478bd9Sstevel@tonic-gate }
23327c478bd9Sstevel@tonic-gate /* Other auth types go here ... */
23337c478bd9Sstevel@tonic-gate inlen = ((4 * out_buf.length) / 3) + 4;
23347c478bd9Sstevel@tonic-gate in = (uchar_t *)malloc(inlen);
23357c478bd9Sstevel@tonic-gate if (in == NULL) {
23367c478bd9Sstevel@tonic-gate gss_release_buffer(&min_stat, &out_buf);
23377c478bd9Sstevel@tonic-gate fatal("Memory error allocating space for response.");
23387c478bd9Sstevel@tonic-gate }
23397c478bd9Sstevel@tonic-gate length = out_buf.length;
23407c478bd9Sstevel@tonic-gate if (auth_error = radix_encode(out, in, inlen, &length, 0)) {
23417c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
2342*92163adaSToomas Soome "Couldn't base 64 encode command (%s)\n",
2343*92163adaSToomas Soome radix_error(auth_error));
23447c478bd9Sstevel@tonic-gate free(in);
23457c478bd9Sstevel@tonic-gate gss_release_buffer(&min_stat, &out_buf);
23467c478bd9Sstevel@tonic-gate return (0);
23477c478bd9Sstevel@tonic-gate }
23487c478bd9Sstevel@tonic-gate
23497c478bd9Sstevel@tonic-gate (void) fprintf(ctrl_out, "%s %s",
2350*92163adaSToomas Soome clevel == PROT_P ? "ENC" : "MIC", in);
23517c478bd9Sstevel@tonic-gate
23527c478bd9Sstevel@tonic-gate free(in);
23537c478bd9Sstevel@tonic-gate gss_release_buffer(&min_stat, &out_buf);
23547c478bd9Sstevel@tonic-gate
23557c478bd9Sstevel@tonic-gate if (debug)
23567c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
23577c478bd9Sstevel@tonic-gate "secure_command(%s)\nencoding %d bytes %s %s\n",
23587c478bd9Sstevel@tonic-gate cmd, length,
23597c478bd9Sstevel@tonic-gate (clevel == PROT_P) ? "ENC" : "MIC", in);
23607c478bd9Sstevel@tonic-gate } else {
23617c478bd9Sstevel@tonic-gate /*
23627c478bd9Sstevel@tonic-gate * auth_type = AUTHTYPE_NONE or
23637c478bd9Sstevel@tonic-gate * command channel is not protected
23647c478bd9Sstevel@tonic-gate */
23657c478bd9Sstevel@tonic-gate fputs(cmd, ctrl_out);
23667c478bd9Sstevel@tonic-gate }
23677c478bd9Sstevel@tonic-gate
23687c478bd9Sstevel@tonic-gate (void) fprintf(ctrl_out, "\r\n");
23697c478bd9Sstevel@tonic-gate (void) fflush(ctrl_out);
23707c478bd9Sstevel@tonic-gate return (1);
23717c478bd9Sstevel@tonic-gate }
23727c478bd9Sstevel@tonic-gate
23737c478bd9Sstevel@tonic-gate unsigned int maxbuf;
23747c478bd9Sstevel@tonic-gate unsigned char *ucbuf;
23757c478bd9Sstevel@tonic-gate
23767c478bd9Sstevel@tonic-gate void
setpbsz(unsigned int size)23777c478bd9Sstevel@tonic-gate setpbsz(unsigned int size)
23787c478bd9Sstevel@tonic-gate {
23797c478bd9Sstevel@tonic-gate unsigned int actualbuf;
23807c478bd9Sstevel@tonic-gate int oldverbose;
23817c478bd9Sstevel@tonic-gate
23827c478bd9Sstevel@tonic-gate if (ucbuf)
23837c478bd9Sstevel@tonic-gate (void) free(ucbuf);
23847c478bd9Sstevel@tonic-gate actualbuf = size;
23857c478bd9Sstevel@tonic-gate while ((ucbuf = (unsigned char *)malloc(actualbuf)) == NULL) {
23867c478bd9Sstevel@tonic-gate if (actualbuf)
23877c478bd9Sstevel@tonic-gate actualbuf >>= 2;
23887c478bd9Sstevel@tonic-gate else {
23897c478bd9Sstevel@tonic-gate perror("Error while trying to malloc PROT buffer:");
23907c478bd9Sstevel@tonic-gate exit(1);
23917c478bd9Sstevel@tonic-gate }
23927c478bd9Sstevel@tonic-gate }
23937c478bd9Sstevel@tonic-gate oldverbose = verbose;
23947c478bd9Sstevel@tonic-gate verbose = 0;
23957c478bd9Sstevel@tonic-gate reply_parse = "PBSZ=";
23967c478bd9Sstevel@tonic-gate if (command("PBSZ %u", actualbuf) != COMPLETE)
23977c478bd9Sstevel@tonic-gate fatal("Cannot set PROT buffer size");
23987c478bd9Sstevel@tonic-gate if (reply_parse) {
23997c478bd9Sstevel@tonic-gate if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
24007c478bd9Sstevel@tonic-gate maxbuf = actualbuf;
24017c478bd9Sstevel@tonic-gate } else
24027c478bd9Sstevel@tonic-gate maxbuf = actualbuf;
24037c478bd9Sstevel@tonic-gate reply_parse = NULL;
24047c478bd9Sstevel@tonic-gate verbose = oldverbose;
24057c478bd9Sstevel@tonic-gate }
24067c478bd9Sstevel@tonic-gate
24077c478bd9Sstevel@tonic-gate /*
24087c478bd9Sstevel@tonic-gate * Do the base 64 decoding of the raw input buffer, b64_buf.
24097c478bd9Sstevel@tonic-gate * Also do the verification and decryption, if required.
24107c478bd9Sstevel@tonic-gate * retval contains the current error code number
24117c478bd9Sstevel@tonic-gate *
24127c478bd9Sstevel@tonic-gate * returns:
24137c478bd9Sstevel@tonic-gate * (RFC 2228: error returns are 3 digit numbers of the form 5xy)
24147c478bd9Sstevel@tonic-gate * 5 if an error occurred
24157c478bd9Sstevel@tonic-gate */
24167c478bd9Sstevel@tonic-gate static int
decode_reply(uchar_t * plain_buf,int ilen,uchar_t * b64_buf,int retval,boolean_t * again)2417*92163adaSToomas Soome decode_reply(uchar_t *plain_buf, int ilen, uchar_t *b64_buf, int retval,
2418*92163adaSToomas Soome boolean_t *again)
24197c478bd9Sstevel@tonic-gate {
24207c478bd9Sstevel@tonic-gate int len;
24217c478bd9Sstevel@tonic-gate int safe = 0;
24227c478bd9Sstevel@tonic-gate
24237c478bd9Sstevel@tonic-gate *again = 0;
24247c478bd9Sstevel@tonic-gate
24257c478bd9Sstevel@tonic-gate if (!b64_buf[0]) /* if there is no string, no problem */
2426*92163adaSToomas Soome return (retval);
24277c478bd9Sstevel@tonic-gate
24287c478bd9Sstevel@tonic-gate if ((auth_type == AUTHTYPE_NONE)) {
2429*92163adaSToomas Soome (void) printf("Cannot decode reply:\n%d %s\n", code, b64_buf);
2430*92163adaSToomas Soome return ('5');
24317c478bd9Sstevel@tonic-gate }
24327c478bd9Sstevel@tonic-gate
24337c478bd9Sstevel@tonic-gate switch (code) {
24347c478bd9Sstevel@tonic-gate
2435*92163adaSToomas Soome case 631: /* 'safe' */
24367c478bd9Sstevel@tonic-gate safe = 1;
24377c478bd9Sstevel@tonic-gate break;
24387c478bd9Sstevel@tonic-gate
2439*92163adaSToomas Soome case 632: /* 'private' */
24407c478bd9Sstevel@tonic-gate break;
24417c478bd9Sstevel@tonic-gate
2442*92163adaSToomas Soome case 633: /* 'confidential' */
24437c478bd9Sstevel@tonic-gate break;
24447c478bd9Sstevel@tonic-gate
2445*92163adaSToomas Soome default:
24467c478bd9Sstevel@tonic-gate (void) printf("Unknown reply: %d %s\n", code, b64_buf);
24477c478bd9Sstevel@tonic-gate return ('5');
24487c478bd9Sstevel@tonic-gate }
24497c478bd9Sstevel@tonic-gate
24507c478bd9Sstevel@tonic-gate /* decode the base64 encoded message */
24517c478bd9Sstevel@tonic-gate auth_error = radix_encode(b64_buf, plain_buf, ilen, &len, 1);
24527c478bd9Sstevel@tonic-gate
24537c478bd9Sstevel@tonic-gate if (auth_error) {
24547c478bd9Sstevel@tonic-gate (void) printf("Can't base 64 decode reply %d (%s)\n\"%s\"\n",
2455*92163adaSToomas Soome code, radix_error(auth_error), b64_buf);
24567c478bd9Sstevel@tonic-gate return ('5');
24577c478bd9Sstevel@tonic-gate }
24587c478bd9Sstevel@tonic-gate
24597c478bd9Sstevel@tonic-gate if (auth_type == AUTHTYPE_GSSAPI) {
24607c478bd9Sstevel@tonic-gate gss_buffer_desc xmit_buf, msg_buf;
24617c478bd9Sstevel@tonic-gate OM_uint32 maj_stat, min_stat;
24627c478bd9Sstevel@tonic-gate int conf_state = safe;
24637c478bd9Sstevel@tonic-gate xmit_buf.value = plain_buf;
24647c478bd9Sstevel@tonic-gate xmit_buf.length = len;
24657c478bd9Sstevel@tonic-gate
24667c478bd9Sstevel@tonic-gate /* decrypt/verify the message */
24677c478bd9Sstevel@tonic-gate maj_stat = gss_unseal(&min_stat, gcontext,
2468*92163adaSToomas Soome &xmit_buf, &msg_buf, &conf_state, NULL);
24697c478bd9Sstevel@tonic-gate if (maj_stat != GSS_S_COMPLETE) {
24707c478bd9Sstevel@tonic-gate user_gss_error(maj_stat, min_stat,
2471*92163adaSToomas Soome "failed unsealing reply");
24727c478bd9Sstevel@tonic-gate return ('5');
24737c478bd9Sstevel@tonic-gate }
24747c478bd9Sstevel@tonic-gate if (msg_buf.length < ilen - 2 - 1) {
24757c478bd9Sstevel@tonic-gate memcpy(plain_buf, msg_buf.value, msg_buf.length);
24767c478bd9Sstevel@tonic-gate strcpy((char *)&plain_buf[msg_buf.length], "\r\n");
24777c478bd9Sstevel@tonic-gate gss_release_buffer(&min_stat, &msg_buf);
24787c478bd9Sstevel@tonic-gate *again = 1;
24797c478bd9Sstevel@tonic-gate } else {
24807c478bd9Sstevel@tonic-gate user_gss_error(maj_stat, min_stat,
2481*92163adaSToomas Soome "reply was too long");
24827c478bd9Sstevel@tonic-gate return ('5');
24837c478bd9Sstevel@tonic-gate }
24847c478bd9Sstevel@tonic-gate } /* end if GSSAPI */
24857c478bd9Sstevel@tonic-gate
24867c478bd9Sstevel@tonic-gate /* Other auth types go here... */
24877c478bd9Sstevel@tonic-gate
24887c478bd9Sstevel@tonic-gate return (retval);
24897c478bd9Sstevel@tonic-gate }
2490