1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 #include "ftp_var.h"
41 #include <arpa/nameser.h>
42 #include <sys/types.h>
43
44 /*
45 * WRITE() returns:
46 * >0 no error
47 * -1 error, errorno is set
48 * -2 security error (secure_write() only)
49 */
50 #define PUTC(x, y) secure_putc(x, y)
51 #define READ(x, y, z) secure_read(x, y, z)
52 #define WRITE(x, y, z) secure_write(x, y, z)
53
54 static struct sockaddr_in6 data_addr;
55 int data = -1;
56 static int abrtflag = 0;
57 static int ptflag = 0;
58 static jmp_buf sendabort;
59 static jmp_buf recvabort;
60 static jmp_buf ptabort;
61 static int ptabflg;
62 static boolean_t pasv_refused;
63 boolean_t eport_supported = B_TRUE;
64 /*
65 * For IPv6 addresses, EPSV will be the default (rather than EPRT/LPRT).
66 * The EPSV/ERPT ftp protocols are specified in RFC 2428.
67 *
68 * Perform EPSV if passivemode is set and ipv6rem is TRUE.
69 */
70 static boolean_t ipv6rem;
71 int use_eprt = 0; /* Testing option that specifies EPRT by default */
72 FILE *ctrl_in, *ctrl_out;
73
74 static void abortsend(int sig);
75 static void abortpt(int sig);
76 static void proxtrans(char *cmd, char *local, char *remote);
77 static void cmdabort(int sig);
78 static int empty(struct fd_set *mask, int sec, int nfds);
79 static void abortrecv(int sig);
80 static int initconn(void);
81 static FILE *dataconn(char *mode);
82 static void ptransfer(char *direction, off_t bytes, hrtime_t t0,
83 hrtime_t t1, char *local, char *remote);
84 static void psabort(int sig);
85 static char *gunique(char *local);
86 static const char *inet_ntop_native(int af, const void *src, char *dst,
87 size_t size);
88 static ssize_t timedread(int fd, void *buf, size_t maxlen, int timeout);
89
90 static int secure_command(char *);
91 static int decode_reply(uchar_t *, int, uchar_t *, int, boolean_t *);
92
93 static ssize_t bufcnt; /* number of bytes in buf[] */
94 static char *bufp; /* next character in buf */
95 static int buferr; /* last errno */
96 static size_t bufsize;
97
98 static void fdio_setbuf(char *buffer, size_t bufsize);
99 static int fdio_fillbuf(int fd);
100 static int fdio_error(int fd);
101 #define fdio_getc(fd) (--bufcnt < 0 ? fdio_fillbuf((fd)) : \
102 ((unsigned char)*bufp++))
103
104 #define MAX(a, b) ((a) > (b) ? (a) : (b))
105 #define NONZERO(x) ((x) == 0 ? 1 : (x))
106
107 static void
fdio_setbuf(char * buffer,size_t maxsize)108 fdio_setbuf(char *buffer, size_t maxsize)
109 {
110 buf = buffer;
111 bufp = buf;
112 bufcnt = 0;
113 buferr = 0;
114 bufsize = maxsize;
115 }
116
117 static int
fdio_fillbuf(int fd)118 fdio_fillbuf(int fd)
119 {
120 bufcnt = timedread(fd, buf, bufsize, timeout);
121 if (bufcnt < 0)
122 buferr = errno;
123 if (bufcnt <= 0)
124 return (EOF);
125 bufp = buf;
126 bufcnt--;
127 return ((unsigned char)*bufp++);
128 }
129
130 /*
131 * fdio_error - used on a file descriptor instead of ferror()
132 */
133
134 /*ARGSUSED*/
135 static int
fdio_error(int fd)136 fdio_error(int fd)
137 {
138 return (buferr);
139 }
140
141 /*
142 * timedread - read buffer (like "read"), but with timeout (in seconds)
143 */
144
145 static ssize_t
timedread(int fd,void * buf,size_t size,int timeout)146 timedread(int fd, void *buf, size_t size, int timeout)
147 {
148 struct fd_set mask;
149 struct timeval tv;
150 int err;
151
152 if (!timeout)
153 return (READ(fd, buf, size));
154
155 tv.tv_sec = (time_t)timeout;
156 tv.tv_usec = 0;
157
158 FD_ZERO(&mask);
159 FD_SET(fd, &mask);
160
161 err = select(fd + 1, &mask, NULL, NULL, &tv);
162 if (err == 0)
163 errno = ETIMEDOUT;
164 if (err <= 0)
165 return (-1);
166
167 return (READ(fd, buf, size));
168 }
169
170
171 char *
hookup(char * host,char * service)172 hookup(char *host, char *service)
173 {
174 struct addrinfo hints, *ai = NULL, *ai_head;
175 int s;
176 socklen_t len;
177 static char hostnamebuf[80];
178 struct in6_addr ipv6addr;
179 char abuf[INET6_ADDRSTRLEN];
180 int error_num;
181 int on = 1;
182
183 /*
184 * There appears to be a bug in getaddrinfo() where, if the
185 * ai_family is set to AF_INET6, and the host is a v4-only
186 * host, getaddrinfo() returns an error instead of returning
187 * an v4-mapped ipv6 address. Therefore the ai_family is
188 * set to AF_UNSPEC and any returned v4 addresses are
189 * explicitly mapped within ftp.
190 */
191 bzero((char *)&remctladdr, sizeof (remctladdr));
192 bzero((char *)&hints, sizeof (hints));
193 hints.ai_flags = AI_CANONNAME;
194 hints.ai_family = AF_UNSPEC;
195 hints.ai_socktype = SOCK_STREAM;
196
197 error_num = getaddrinfo(host, service, &hints, &ai);
198 if (error_num != 0) {
199 if (error_num == EAI_AGAIN) {
200 (void) printf(
201 "%s: unknown host or invalid literal address "
202 "(try again later)\n", host);
203 } else {
204 (void) printf(
205 "%s: unknown host or invalid literal address\n",
206 host);
207 }
208 code = -1;
209 return ((char *)0);
210 }
211 ai_head = ai;
212
213
214 /*
215 * If ai_canonname is a IPv4-mapped IPv6 literal, we'll convert it to
216 * IPv4 literal address.
217 */
218 if (ai->ai_canonname != NULL &&
219 (inet_pton(AF_INET6, ai->ai_canonname, &ipv6addr) > 0) &&
220 IN6_IS_ADDR_V4MAPPED(&ipv6addr)) {
221 struct in_addr src4;
222 hostnamebuf[0] = '\0';
223 IN6_V4MAPPED_TO_INADDR(&ipv6addr, &src4);
224 (void) inet_ntop(AF_INET, &src4, hostnamebuf,
225 sizeof (hostnamebuf));
226
227 /*
228 * It can even be the case that the "host" supplied by the user
229 * can be a IPv4-mapped IPv6 literal. So, let's fix that too.
230 */
231 if ((inet_pton(AF_INET6, host, &ipv6addr) > 0) &&
232 IN6_IS_ADDR_V4MAPPED(&ipv6addr) &&
233 strlen(hostnamebuf) <= strlen(host)) {
234 (void) strlcpy(host, hostnamebuf, strlen(host) + 1);
235 }
236 } else {
237 reset_timer();
238 (void) strlcpy(hostnamebuf,
239 (ai->ai_canonname ? ai->ai_canonname : host),
240 sizeof (hostnamebuf));
241 }
242
243 hostname = hostnamebuf;
244 for (;;) {
245 int oerrno;
246
247 bcopy(ai->ai_addr, &remctladdr, ai->ai_addrlen);
248 if (ai->ai_addr->sa_family == AF_INET) {
249 IN6_INADDR_TO_V4MAPPED(
250 &(((struct sockaddr_in *)ai->ai_addr)->sin_addr),
251 &remctladdr.sin6_addr);
252 remctladdr.sin6_family = AF_INET6;
253 }
254
255 s = socket(AF_INET6, SOCK_STREAM, 0);
256 if (s < 0) {
257 perror("ftp: socket");
258 code = -1;
259 freeaddrinfo(ai_head);
260 return (0);
261 }
262 if (timeout && setsockopt(s, IPPROTO_TCP, TCP_ABORT_THRESHOLD,
263 (char *)&timeoutms, sizeof (timeoutms)) < 0 && debug)
264 perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)");
265 reset_timer();
266
267 error_num = connect(s, (struct sockaddr *)&remctladdr,
268 sizeof (remctladdr));
269 oerrno = errno;
270 if (error_num >= 0)
271 break;
272
273 /*
274 * Maintain message behavior: only include the address in
275 * our error message if we have another one to try; if this
276 * is the last address on our list, just print the error.
277 */
278 if (ai->ai_next != NULL) {
279 (void) fprintf(stderr, "ftp: connect to address %s: ",
280 inet_ntop_native(ai->ai_addr->sa_family,
281 (void *)ai->ai_addr, abuf, sizeof (abuf)));
282 errno = oerrno;
283 perror((char *)0);
284 } else {
285 perror("ftp: connect");
286 code = -1;
287 freeaddrinfo(ai_head);
288 goto bad;
289 }
290 ai = ai->ai_next;
291 (void) fprintf(stdout, "Trying %s...\n",
292 inet_ntop_native(ai->ai_addr->sa_family,
293 (void *)ai->ai_addr, abuf, sizeof (abuf)));
294 (void) close(s);
295
296 }
297
298 /* Set ipv6rem to TRUE if control connection is a native IPv6 address */
299 if (IN6_IS_ADDR_V4MAPPED(&remctladdr.sin6_addr))
300 ipv6rem = B_FALSE;
301 else
302 ipv6rem = B_TRUE;
303
304
305 freeaddrinfo(ai_head);
306 ai = NULL;
307
308 /*
309 * Set passive mode flag on by default only if a native IPv6 address
310 * is being used -and- the use_eprt is not set.
311 */
312 if (ipv6rem == B_TRUE && use_eprt == 0)
313 passivemode = 1;
314
315 len = sizeof (myctladdr);
316 if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
317 perror("ftp: getsockname");
318 code = -1;
319 goto bad;
320 }
321 ctrl_in = fdopen(s, "r");
322 ctrl_out = fdopen(s, "w");
323 if (ctrl_in == NULL || ctrl_out == NULL) {
324 (void) fprintf(stderr, "ftp: fdopen failed.\n");
325 if (ctrl_in)
326 (void) fclose(ctrl_in);
327 if (ctrl_out)
328 (void) fclose(ctrl_out);
329 code = -1;
330 goto bad;
331 }
332 if (verbose)
333 (void) printf("Connected to %s.\n", hostname);
334 if (getreply(0) > 2) { /* read startup message from server */
335 if (ctrl_in)
336 (void) fclose(ctrl_in);
337 if (ctrl_out)
338 (void) fclose(ctrl_out);
339 ctrl_in = ctrl_out = NULL;
340 ctrl_in = ctrl_out = NULL;
341 code = -1;
342 goto bad;
343 }
344 if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
345 sizeof (on)) < 0 && debug)
346 perror("ftp: setsockopt (SO_OOBINLINE)");
347
348 return (hostname);
349 bad:
350 (void) close(s);
351 return ((char *)0);
352 }
353
354 int
login(char * host)355 login(char *host)
356 {
357 char tmp[80];
358 char *user, *pass, *acct;
359 int n, aflag = 0;
360
361 user = pass = acct = 0;
362 if (ruserpass(host, &user, &pass, &acct) < 0) {
363 disconnect(0, NULL);
364 code = -1;
365 return (0);
366 }
367 if (user == NULL) {
368 char *myname = getlogin();
369
370 if (myname == NULL) {
371 struct passwd *pp = getpwuid(getuid());
372
373 if (pp != NULL)
374 myname = pp->pw_name;
375 }
376 stop_timer();
377 (void) printf("Name (%s:%s): ", host,
378 (myname == NULL) ? "" : myname);
379 *tmp = '\0';
380 if (fgets(tmp, sizeof (tmp) - 1, stdin) != NULL)
381 tmp[strlen(tmp) - 1] = '\0';
382 if (*tmp != '\0')
383 user = tmp;
384 else if (myname != NULL)
385 user = myname;
386 else
387 return (0);
388 }
389 n = command("USER %s", user);
390 if (n == CONTINUE) {
391 int oldclevel;
392 if (pass == NULL)
393 pass = mygetpass("Password:");
394 oldclevel = clevel;
395 clevel = PROT_P;
396 n = command("PASS %s", pass);
397 /* level may have changed */
398 if (clevel == PROT_P)
399 clevel = oldclevel;
400 }
401 if (n == CONTINUE) {
402 aflag++;
403 if (acct == NULL)
404 acct = mygetpass("Account:");
405 n = command("ACCT %s", acct);
406 }
407 if (n != COMPLETE) {
408 (void) fprintf(stderr, "Login failed.\n");
409 return (0);
410 }
411 if (!aflag && acct != NULL)
412 (void) command("ACCT %s", acct);
413 if (proxy)
414 return (1);
415 for (n = 0; n < macnum; ++n) {
416 if (strcmp("init", macros[n].mac_name) == 0) {
417 (void) strlcpy(line, "$init", sizeof (line));
418 makeargv();
419 domacro(margc, margv);
420 break;
421 }
422 }
423 return (1);
424 }
425
426 /*ARGSUSED*/
427 static void
cmdabort(int sig)428 cmdabort(int sig)
429 {
430 (void) printf("\n");
431 (void) fflush(stdout);
432 abrtflag++;
433 if (ptflag)
434 longjmp(ptabort, 1);
435 }
436
437 int
command(char * fmt,...)438 command(char *fmt, ...)
439 {
440 int r;
441 void (*oldintr)();
442 va_list ap;
443 char command_buf[FTPBUFSIZ];
444
445 va_start(ap, fmt);
446 abrtflag = 0;
447 if (debug) {
448 (void) printf("---> ");
449 if (strncmp("PASS ", fmt, 5) == 0)
450 (void) printf("PASS XXXX");
451 else if (strncmp("ACCT ", fmt, 5) == 0)
452 (void) printf("ACCT XXXX");
453 else
454 (void) vfprintf(stdout, fmt, ap);
455 (void) printf("\n");
456 (void) fflush(stdout);
457 }
458 if (ctrl_out == NULL) {
459 perror("No control connection for command");
460 code = -1;
461 return (0);
462 }
463 oldintr = signal(SIGINT, cmdabort);
464 (void) vsnprintf(command_buf, FTPBUFSIZ, fmt, ap);
465 va_end(ap);
466
467 again: if (secure_command(command_buf) == 0)
468 return (0);
469
470 cpend = 1;
471 r = getreply(strcmp(fmt, "QUIT") == 0);
472
473 if (r == 533 && clevel == PROT_P) {
474 (void) fprintf(stderr, "ENC command not supported at server; "
475 "retrying under MIC...\n");
476 clevel = PROT_S;
477 goto again;
478 }
479
480 if (abrtflag && oldintr != SIG_IGN)
481 (*oldintr)();
482 (void) signal(SIGINT, oldintr);
483 return (r);
484 }
485
486 /* Need to save reply reponse from server for use in EPSV mode */
487 char reply_string[BUFSIZ];
488
489 int
getreply(int expecteof)490 getreply(int expecteof)
491 {
492 /*
493 * 'code' is the 3 digit reply code, form xyz
494 * 'dig' counts the number of digits we are along in the code
495 * 'n' is the first digit of 'code'
496 * 4yz: resource unavailable
497 * 5yz: an error occurred, failure
498 * 6yz: protected reply (is_base64 == TRUE)
499 * 631 - base 64 encoded safe message
500 * 632 - base 64 encoded private message
501 * 633 - base 64 encoded confidential message
502 * 'c' is a wide char type, for international char sets
503 */
504 wint_t c;
505 int i, n;
506 int dig;
507 int originalcode = 0, continuation = 0;
508 void (*oldintr)();
509 int pflag = 0;
510 char *pt = pasv;
511 /*
512 * this is the input and output buffers needed for
513 * radix_encode()
514 */
515 unsigned char ibuf[FTPBUFSIZ];
516 unsigned char obuf[FTPBUFSIZ];
517 boolean_t is_base64;
518 int len;
519 char *cp;
520
521 if (!ctrl_in)
522 return (0);
523 oldintr = signal(SIGINT, cmdabort);
524
525 ibuf[0] = '\0';
526
527 if (reply_parse)
528 reply_ptr = reply_buf;
529
530 for (;;) {
531 obuf[0] = '\0';
532 dig = n = code = 0;
533 i = is_base64 = 0;
534 cp = reply_string;
535 reset_timer(); /* once per line */
536
537 while ((c = ibuf[0] ?
538 (wint_t)ibuf[i++] : fgetwc(ctrl_in)) != '\n') {
539
540 if (i >= FTPBUFSIZ)
541 break;
542
543 if (c == IAC) { /* handle telnet commands */
544 switch (c = fgetwc(ctrl_in)) {
545 case WILL:
546 case WONT:
547 c = fgetwc(ctrl_in);
548 (void) fprintf(ctrl_out, "%c%c%wc", IAC,
549 WONT, c);
550 (void) fflush(ctrl_out);
551 break;
552 case DO:
553 case DONT:
554 c = fgetwc(ctrl_in);
555 (void) fprintf(ctrl_out, "%c%c%wc", IAC,
556 DONT, c);
557 (void) fflush(ctrl_out);
558 break;
559 default:
560 break;
561 }
562 continue;
563 }
564 dig++;
565 if (c == EOF) {
566 if (expecteof) {
567 (void) signal(SIGINT, oldintr);
568 code = 221;
569 return (0);
570 }
571 lostpeer(0);
572 if (verbose) {
573 (void) printf(
574 "421 Service not available, remote"
575 " server has closed connection\n");
576 } else {
577 (void) printf("Lost connection\n");
578 }
579 (void) fflush(stdout);
580 code = 421;
581 return (4);
582 }
583 if (n == 0)
584 n = c;
585
586 if (n == '6')
587 is_base64 = 1;
588
589 if ((auth_type != AUTHTYPE_NONE) && !ibuf[0] &&
590 (is_base64 || continuation)) {
591 /* start storing chars in obuf */
592 if (c != '\r' && dig > 4)
593 obuf[i++] = (char)c;
594 } else {
595 if ((auth_type != AUTHTYPE_NONE) && !ibuf[0] &&
596 dig == 1 && verbose)
597 (void) printf("Unauthenticated reply "
598 "received from server:\n");
599 if (reply_parse)
600 *reply_ptr++ = (char)c;
601 if (c != '\r' && (verbose > 0 ||
602 (verbose > -1 && n == '5' && dig > 4))) {
603 if (proxflag &&
604 (dig == 1 || dig == 5 &&
605 verbose == 0))
606 (void) printf("%s:", hostname);
607 (void) putwchar(c);
608 }
609 } /* endif auth_type && !ibuf[0] ... */
610
611 if ((auth_type != AUTHTYPE_NONE) && !ibuf[0] &&
612 !is_base64)
613 continue;
614
615 /* we are still extracting the 3 digit code */
616 if (dig < 4 && isascii(c) && isdigit(c))
617 code = code * 10 + (c - '0');
618
619 /* starting passive mode */
620 if (!pflag && code == 227)
621 pflag = 1;
622
623 /* start to store characters, when dig > 4 */
624 if (dig > 4 && pflag == 1 && isascii(c) && isdigit(c))
625 pflag = 2;
626 if (pflag == 2) {
627 if (c != '\r' && c != ')') {
628 /*
629 * the mb array is to deal with
630 * the wchar_t
631 */
632 char mb[MB_LEN_MAX];
633 int avail;
634
635 /*
636 * space available in pasv[], accounting
637 * for trailing NULL
638 */
639 avail = &pasv[sizeof (pasv)] - pt - 1;
640
641 len = wctomb(mb, c);
642 if (len <= 0 && avail > 0) {
643 *pt++ = (unsigned char)c;
644 } else if (len > 0 && avail >= len) {
645 bcopy(mb, pt, (size_t)len);
646 pt += len;
647 } else {
648 /*
649 * no room in pasv[];
650 * close connection
651 */
652 (void) printf("\nReply too long"
653 " - closing connection\n");
654 lostpeer(0);
655 (void) fflush(stdout);
656 (void) signal(SIGINT, oldintr);
657 return (4);
658 }
659 } else {
660 *pt = '\0';
661 pflag = 3;
662 }
663 } /* endif pflag == 2 */
664 if (dig == 4 && c == '-' && !is_base64) {
665 if (continuation)
666 code = 0;
667 continuation++;
668 }
669 if (cp < &reply_string[sizeof (reply_string) - 1])
670 *cp++ = c;
671
672 } /* end while */
673
674 if ((auth_type != AUTHTYPE_NONE) && !ibuf[0] && !is_base64)
675 return (getreply(expecteof));
676
677 ibuf[0] = obuf[i] = '\0';
678
679 if (code && is_base64) {
680 boolean_t again = 0;
681 n = decode_reply(ibuf, sizeof (ibuf), obuf, n, &again);
682 if (again)
683 continue;
684 } else {
685 if (verbose > 0 || verbose > -1 && n == '5') {
686 (void) putwchar(c);
687 (void) fflush(stdout);
688 }
689 }
690
691 if (continuation && code != originalcode) {
692 ibuf[0] = obuf[i] = '\0';
693 if (originalcode == 0)
694 originalcode = code;
695 continue;
696 }
697 *cp = '\0';
698 if (n != '1')
699 cpend = 0;
700 (void) signal(SIGINT, oldintr);
701 if (code == 421 || originalcode == 421)
702 lostpeer(0);
703 if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
704 (*oldintr)();
705
706 if (reply_parse) {
707 *reply_ptr = '\0';
708 if (reply_ptr = strstr(reply_buf, reply_parse)) {
709 reply_parse = reply_ptr + strlen(reply_parse);
710 if (reply_ptr = strpbrk(reply_parse, " \r"))
711 *reply_ptr = '\0';
712 } else {
713 reply_parse = reply_ptr;
714 }
715 }
716
717 return (n - '0');
718 } /* end for */
719 }
720
721 static int
empty(struct fd_set * mask,int sec,int nfds)722 empty(struct fd_set *mask, int sec, int nfds)
723 {
724 struct timeval t;
725
726 reset_timer();
727 t.tv_sec = (time_t)sec;
728 t.tv_usec = 0;
729 return (select(nfds, mask, NULL, NULL, &t));
730 }
731
732 /*ARGSUSED*/
733 static void
abortsend(int sig)734 abortsend(int sig)
735 {
736 mflag = 0;
737 abrtflag = 0;
738 (void) printf("\nsend aborted\n");
739 (void) fflush(stdout);
740 longjmp(sendabort, 1);
741 }
742
743 void
sendrequest(char * cmd,char * local,char * remote,int allowpipe)744 sendrequest(char *cmd, char *local, char *remote, int allowpipe)
745 {
746 FILE *fin, *dout = 0;
747 int (*closefunc)();
748 void (*oldintr)(), (*oldintp)();
749 off_t bytes = 0, hashbytes = HASHSIZ;
750 int c;
751 /*
752 * d >= 0 if there is no error
753 * -1 if there was a normal file i/o error
754 * -2 if there was a security error
755 */
756 int d;
757 struct stat st;
758 hrtime_t start, stop;
759 char *dmode;
760
761 if (proxy) {
762 proxtrans(cmd, local, remote);
763 return;
764 }
765 closefunc = NULL;
766 oldintr = NULL;
767 oldintp = NULL;
768 dmode = "w";
769 if (setjmp(sendabort)) {
770 while (cpend) {
771 (void) getreply(0);
772 }
773 if (data >= 0) {
774 (void) close(data);
775 data = -1;
776 }
777 if (oldintr)
778 (void) signal(SIGINT, oldintr);
779 if (oldintp)
780 (void) signal(SIGPIPE, oldintp);
781 code = -1;
782 restart_point = 0;
783 return;
784 }
785 oldintr = signal(SIGINT, abortsend);
786 if (strcmp(local, "-") == 0)
787 fin = stdin;
788 else if (allowpipe && *local == '|') {
789 oldintp = signal(SIGPIPE, SIG_IGN);
790 fin = mypopen(local + 1, "r");
791 if (fin == NULL) {
792 perror(local + 1);
793 (void) signal(SIGINT, oldintr);
794 (void) signal(SIGPIPE, oldintp);
795 code = -1;
796 restart_point = 0;
797 return;
798 }
799 closefunc = mypclose;
800 } else {
801 fin = fopen(local, "r");
802 if (fin == NULL) {
803 perror(local);
804 (void) signal(SIGINT, oldintr);
805 code = -1;
806 restart_point = 0;
807 return;
808 }
809 closefunc = fclose;
810 if (fstat(fileno(fin), &st) < 0 ||
811 (st.st_mode&S_IFMT) != S_IFREG) {
812 (void) fprintf(stdout,
813 "%s: not a plain file.\n", local);
814 (void) signal(SIGINT, oldintr);
815 code = -1;
816 (void) fclose(fin);
817 restart_point = 0;
818 return;
819 }
820 }
821 if (initconn()) {
822 (void) signal(SIGINT, oldintr);
823 if (oldintp)
824 (void) signal(SIGPIPE, oldintp);
825 code = -1;
826 if (closefunc != NULL)
827 (*closefunc)(fin);
828 restart_point = 0;
829 return;
830 }
831 if (setjmp(sendabort))
832 goto abort;
833 if ((restart_point > 0) &&
834 (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
835 if (fseeko(fin, restart_point, SEEK_SET) < 0) {
836 perror(local);
837 if (closefunc != NULL)
838 (*closefunc)(fin);
839 restart_point = 0;
840 return;
841 }
842 if (command("REST %lld", (longlong_t)restart_point)
843 != CONTINUE) {
844 if (closefunc != NULL)
845 (*closefunc)(fin);
846 restart_point = 0;
847 return;
848 }
849 dmode = "r+w";
850 }
851 restart_point = 0;
852 if (remote) {
853 if (command("%s %s", cmd, remote) != PRELIM) {
854 (void) signal(SIGINT, oldintr);
855 if (oldintp)
856 (void) signal(SIGPIPE, oldintp);
857 if (closefunc != NULL)
858 (*closefunc)(fin);
859 if (data >= 0) {
860 (void) close(data);
861 data = -1;
862 }
863 return;
864 }
865 } else
866 if (command("%s", cmd) != PRELIM) {
867 (void) signal(SIGINT, oldintr);
868 if (oldintp)
869 (void) signal(SIGPIPE, oldintp);
870 if (closefunc != NULL)
871 (*closefunc)(fin);
872 if (data >= 0) {
873 (void) close(data);
874 data = -1;
875 }
876 return;
877 }
878 dout = dataconn(dmode);
879 if (dout == NULL)
880 goto abort;
881 stop_timer();
882 oldintp = signal(SIGPIPE, SIG_IGN);
883 start = gethrtime();
884 switch (type) {
885
886 case TYPE_I:
887 case TYPE_L:
888 errno = d = 0;
889 while ((c = read(fileno(fin), buf, FTPBUFSIZ)) > 0) {
890 if ((d = WRITE(fileno(dout), buf, c)) < 0)
891 break;
892 bytes += c;
893 if (hash) {
894 while (bytes >= hashbytes) {
895 (void) putchar('#');
896 hashbytes += HASHSIZ;
897 }
898 (void) fflush(stdout);
899 }
900 }
901 if (hash && bytes > 0) {
902 if (bytes < hashbytes)
903 (void) putchar('#');
904 (void) putchar('\n');
905 (void) fflush(stdout);
906 }
907 if (c < 0)
908 perror(local);
909
910 if (d >= 0)
911 d = secure_flush(fileno(dout));
912
913 if (d < 0) {
914 if ((d == -1) && (errno != EPIPE))
915 perror("netout");
916 bytes = -1;
917 }
918 break;
919
920 case TYPE_A:
921 while ((c = getc(fin)) != EOF) {
922 if (c == '\n') {
923 while (hash && (bytes >= hashbytes)) {
924 (void) putchar('#');
925 (void) fflush(stdout);
926 hashbytes += HASHSIZ;
927 }
928 if (ferror(dout) || PUTC('\r', dout) < 0)
929 break;
930 bytes++;
931 }
932
933 if (PUTC(c, dout) < 0)
934 break;
935 bytes++;
936 #ifdef notdef
937 if (c == '\r') {
938 /* this violates rfc */
939 (void) PUTC('\0', dout);
940 bytes++;
941 }
942 #endif
943 }
944 if (hash && bytes > 0) {
945 if (bytes < hashbytes)
946 (void) putchar('#');
947 (void) putchar('\n');
948 (void) fflush(stdout);
949 }
950 if (ferror(fin))
951 perror(local);
952
953 d = ferror(dout) ? -1 : 0;
954 if (d == 0)
955 d = secure_flush(fileno(dout));
956
957 if (d < 0) {
958 if ((d == -1) && (errno != EPIPE))
959 perror("netout");
960 bytes = -1;
961 }
962 break;
963 }
964 reset_timer();
965 if (closefunc != NULL)
966 (*closefunc)(fin);
967 if (ctrl_in != NULL) {
968 int dfn = fileno(dout);
969 int nfds = fileno(ctrl_in);
970 fd_set mask;
971
972 /*
973 * There could be data not yet written to dout,
974 * in the stdio buffer; so, before a shutdown()
975 * on further sends, do fflush(dout)
976 */
977 (void) fflush(dout);
978
979 /* sending over; shutdown sending on dfn */
980 (void) shutdown(dfn, SHUT_WR);
981 FD_ZERO(&mask);
982 FD_SET(dfn, &mask);
983 FD_SET(nfds, &mask);
984 nfds = MAX(dfn, nfds);
985
986 /*
987 * Wait for remote end to either close data socket
988 * or ack that we've closed our end; it doesn't
989 * matter which happens first.
990 */
991 (void) select(nfds + 1, &mask, NULL, NULL, NULL);
992 }
993 (void) fclose(dout); data = -1;
994 stop = gethrtime();
995 (void) getreply(0);
996 (void) signal(SIGINT, oldintr);
997 if (oldintp)
998 (void) signal(SIGPIPE, oldintp);
999
1000 /*
1001 * Only print the transfer successful message if the code returned
1002 * from remote is 226 or 250. All other codes are error codes.
1003 */
1004 if ((bytes > 0) && verbose && ((code == 226) || (code == 250)))
1005 ptransfer("sent", bytes, start, stop, local, remote);
1006 if (!ctrl_in)
1007 (void) printf("Lost connection\n");
1008 return;
1009 abort:
1010 (void) signal(SIGINT, oldintr);
1011 if (oldintp)
1012 (void) signal(SIGPIPE, oldintp);
1013 if (!cpend) {
1014 code = -1;
1015 return;
1016 }
1017 if (data >= 0) {
1018 (void) close(data);
1019 data = -1;
1020 }
1021 if (dout) {
1022 (void) fclose(dout);
1023 data = -1;
1024 }
1025 (void) getreply(0);
1026 code = -1;
1027 if (closefunc != NULL && fin != NULL)
1028 (*closefunc)(fin);
1029 stop = gethrtime();
1030 /*
1031 * Only print the transfer successful message if the code returned
1032 * from remote is 226 or 250. All other codes are error codes.
1033 */
1034 if ((bytes > 0) && verbose && ((code == 226) || (code == 250)))
1035 ptransfer("sent", bytes, start, stop, local, remote);
1036 if (!ctrl_in)
1037 (void) printf("Lost connection\n");
1038 restart_point = 0;
1039 }
1040
1041 /*ARGSUSED*/
1042 static void
abortrecv(int sig)1043 abortrecv(int sig)
1044 {
1045 mflag = 0;
1046 abrtflag = 0;
1047 (void) printf("\n");
1048 (void) fflush(stdout);
1049 longjmp(recvabort, 1);
1050 }
1051
1052 void
recvrequest(char * cmd,char * local,char * remote,char * mode,int allowpipe)1053 recvrequest(char *cmd, char *local, char *remote, char *mode, int allowpipe)
1054 {
1055 FILE *fout, *din = 0;
1056 int (*closefunc)();
1057 void (*oldintr)(), (*oldintp)();
1058 int oldverbose, oldtype = 0, tcrflag, nfnd;
1059 char msg;
1060 off_t bytes = 0, hashbytes = HASHSIZ;
1061 struct fd_set mask;
1062 int c, d, n;
1063 hrtime_t start, stop;
1064 int errflg = 0;
1065 int infd;
1066 int nfds;
1067 int retrcmd;
1068
1069 retrcmd = (strcmp(cmd, "RETR") == 0);
1070 if (proxy && retrcmd) {
1071 proxtrans(cmd, local, remote);
1072 return;
1073 }
1074 closefunc = NULL;
1075 oldintr = NULL;
1076 oldintp = NULL;
1077 tcrflag = !crflag && retrcmd;
1078 if (setjmp(recvabort)) {
1079 while (cpend) {
1080 (void) getreply(0);
1081 }
1082 if (data >= 0) {
1083 (void) close(data);
1084 data = -1;
1085 }
1086 if (oldintr)
1087 (void) signal(SIGINT, oldintr);
1088 code = -1;
1089 return;
1090 }
1091 oldintr = signal(SIGINT, abortrecv);
1092 if (local != NULL &&
1093 strcmp(local, "-") != 0 &&
1094 (*local != '|' || !allowpipe)) {
1095 if (access(local, W_OK) < 0) {
1096 char *dir = rindex(local, '/');
1097 int file_errno = errno;
1098
1099 if (file_errno != ENOENT && file_errno != EACCES) {
1100 perror(local);
1101 (void) signal(SIGINT, oldintr);
1102 code = -1;
1103 return;
1104 }
1105 if ((dir != NULL) && (dir != local))
1106 *dir = 0;
1107 if (dir == local)
1108 d = access("/", W_OK);
1109 else
1110 d = access(dir ? local : ".", W_OK);
1111 if ((dir != NULL) && (dir != local))
1112 *dir = '/';
1113 if (d < 0) {
1114 perror(local);
1115 (void) signal(SIGINT, oldintr);
1116 code = -1;
1117 return;
1118 }
1119 if (!runique && file_errno == EACCES) {
1120 errno = file_errno;
1121 perror(local);
1122 (void) signal(SIGINT, oldintr);
1123 code = -1;
1124 return;
1125 }
1126 if (runique && file_errno == EACCES &&
1127 (local = gunique(local)) == NULL) {
1128 (void) signal(SIGINT, oldintr);
1129 code = -1;
1130 return;
1131 }
1132 } else if (runique && (local = gunique(local)) == NULL) {
1133 (void) signal(SIGINT, oldintr);
1134 code = -1;
1135 return;
1136 }
1137 }
1138 if (initconn()) {
1139 (void) signal(SIGINT, oldintr);
1140 code = -1;
1141 return;
1142 }
1143 if (setjmp(recvabort))
1144 goto abort;
1145 if (!retrcmd && type != TYPE_A) {
1146 oldtype = type;
1147 oldverbose = verbose;
1148 if (!debug)
1149 verbose = 0;
1150 setascii(0, NULL);
1151 verbose = oldverbose;
1152 }
1153 if ((restart_point > 0) && retrcmd &&
1154 command("REST %lld", (longlong_t)restart_point) != CONTINUE) {
1155 return;
1156 }
1157 if (remote) {
1158 if (command("%s %s", cmd, remote) != PRELIM) {
1159 (void) signal(SIGINT, oldintr);
1160 if (oldtype) {
1161 if (!debug)
1162 verbose = 0;
1163 switch (oldtype) {
1164 case TYPE_I:
1165 setbinary(0, NULL);
1166 break;
1167 case TYPE_E:
1168 setebcdic(0, NULL);
1169 break;
1170 case TYPE_L:
1171 settenex(0, NULL);
1172 break;
1173 }
1174 verbose = oldverbose;
1175 }
1176 return;
1177 }
1178 } else {
1179 if (command("%s", cmd) != PRELIM) {
1180 (void) signal(SIGINT, oldintr);
1181 if (oldtype) {
1182 if (!debug)
1183 verbose = 0;
1184 switch (oldtype) {
1185 case TYPE_I:
1186 setbinary(0, NULL);
1187 break;
1188 case TYPE_E:
1189 setebcdic(0, NULL);
1190 break;
1191 case TYPE_L:
1192 settenex(0, NULL);
1193 break;
1194 }
1195 verbose = oldverbose;
1196 }
1197 return;
1198 }
1199 }
1200 din = dataconn("r");
1201 if (din == NULL)
1202 goto abort;
1203
1204 if (local == NULL) {
1205 fout = tmp_nlst;
1206 } else if (strcmp(local, "-") == 0) {
1207 fout = stdout;
1208 } else if (allowpipe && *local == '|') {
1209 oldintp = signal(SIGPIPE, SIG_IGN);
1210 fout = mypopen(local + 1, "w");
1211 if (fout == NULL) {
1212 perror(local+1);
1213 goto abort;
1214 }
1215 closefunc = mypclose;
1216 } else {
1217 fout = fopen(local, mode);
1218 if (fout == NULL) {
1219 perror(local);
1220 goto abort;
1221 }
1222 closefunc = fclose;
1223 }
1224 start = gethrtime();
1225 stop_timer();
1226 switch (type) {
1227
1228 case TYPE_I:
1229 case TYPE_L:
1230 if ((restart_point > 0) && retrcmd &&
1231 lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1232 perror(local);
1233 goto abort;
1234 }
1235 errno = d = 0;
1236 infd = fileno(din);
1237 while ((c = timedread(infd, buf, FTPBUFSIZ, timeout)) > 0) {
1238 for (n = 0; n < c; n += d) {
1239 d = write(fileno(fout), &buf[n], c - n);
1240 if (d == -1)
1241 goto writeerr;
1242 }
1243 bytes += c;
1244 if (hash) {
1245 while (bytes >= hashbytes) {
1246 (void) putchar('#');
1247 hashbytes += HASHSIZ;
1248 }
1249 (void) fflush(stdout);
1250 }
1251 }
1252 if (hash && bytes > 0) {
1253 if (bytes < hashbytes)
1254 (void) putchar('#');
1255 (void) putchar('\n');
1256 (void) fflush(stdout);
1257 }
1258 if (c < 0) {
1259 errflg = 1;
1260 perror("netin");
1261 }
1262 if ((d < 0) || ((c == 0) && (fsync(fileno(fout)) == -1))) {
1263 writeerr:
1264 errflg = 1;
1265 perror(local);
1266 }
1267 break;
1268
1269 case TYPE_A:
1270 if ((restart_point > 0) && retrcmd) {
1271 int c;
1272 off_t i = 0;
1273
1274 if (fseek(fout, 0L, SEEK_SET) < 0) {
1275 perror(local);
1276 goto abort;
1277 }
1278 while (i++ < restart_point) {
1279 if ((c = getc(fout)) == EOF) {
1280 if (ferror(fout))
1281 perror(local);
1282 else
1283 (void) fprintf(stderr,
1284 "%s: Unexpected end of "
1285 "file\n", local);
1286 goto abort;
1287 }
1288 if (c == '\n')
1289 i++;
1290 }
1291 if (fseeko(fout, 0L, SEEK_CUR) < 0) {
1292 perror(local);
1293 goto abort;
1294 }
1295 }
1296 fdio_setbuf(buf, FTPBUFSIZ);
1297 infd = fileno(din);
1298 while ((c = fdio_getc(infd)) != EOF) {
1299 while (c == '\r') {
1300 while (hash && (bytes >= hashbytes)) {
1301 (void) putchar('#');
1302 (void) fflush(stdout);
1303 hashbytes += HASHSIZ;
1304 }
1305 bytes++;
1306
1307 if ((c = fdio_getc(infd)) != '\n' || tcrflag) {
1308 if (ferror(fout))
1309 break;
1310 if (putc('\r', fout) == EOF)
1311 goto writer_ascii_err;
1312 }
1313 #ifdef notdef
1314 if (c == '\0') {
1315 bytes++;
1316 continue;
1317 }
1318 #endif
1319 if (c == EOF)
1320 goto endread;
1321 }
1322 if (putc(c, fout) == EOF)
1323 goto writer_ascii_err;
1324 bytes++;
1325 }
1326 endread:
1327 if (hash && bytes > 0) {
1328 if (bytes < hashbytes)
1329 (void) putchar('#');
1330 (void) putchar('\n');
1331 (void) fflush(stdout);
1332 }
1333 if (fdio_error(infd)) {
1334 errflg = 1;
1335 perror("netin");
1336 }
1337 if ((fflush(fout) == EOF) || ferror(fout) ||
1338 (fsync(fileno(fout)) == -1)) {
1339 writer_ascii_err:
1340 errflg = 1;
1341 perror(local);
1342 }
1343 break;
1344 }
1345 reset_timer();
1346 if (closefunc != NULL)
1347 (*closefunc)(fout);
1348 (void) signal(SIGINT, oldintr);
1349 if (oldintp)
1350 (void) signal(SIGPIPE, oldintp);
1351 (void) fclose(din); data = -1;
1352 stop = gethrtime();
1353 (void) getreply(0);
1354 if (bytes > 0 && verbose && !errflg)
1355 ptransfer("received", bytes, start, stop, local, remote);
1356 if (!ctrl_in)
1357 (void) printf("Lost connection\n");
1358 if (oldtype) {
1359 if (!debug)
1360 verbose = 0;
1361 switch (oldtype) {
1362 case TYPE_I:
1363 setbinary(0, NULL);
1364 break;
1365 case TYPE_E:
1366 setebcdic(0, NULL);
1367 break;
1368 case TYPE_L:
1369 settenex(0, NULL);
1370 break;
1371 }
1372 verbose = oldverbose;
1373 }
1374 return;
1375 abort:
1376
1377 /* abort using RFC959 recommended IP, SYNC sequence */
1378
1379 stop = gethrtime();
1380 if (oldintp)
1381 (void) signal(SIGPIPE, oldintp);
1382 (void) signal(SIGINT, SIG_IGN);
1383 if (!cpend) {
1384 code = -1;
1385 (void) signal(SIGINT, oldintr);
1386 return;
1387 }
1388
1389 (void) fprintf(ctrl_out, "%c%c", IAC, IP);
1390 (void) fflush(ctrl_out);
1391 msg = (char)IAC;
1392 /*
1393 * send IAC in urgent mode instead of DM because UNIX places oob
1394 * mark after urgent byte rather than before as now is protocol
1395 */
1396 if (send(fileno(ctrl_out), &msg, 1, MSG_OOB) != 1) {
1397 perror("abort");
1398 }
1399 (void) fprintf(ctrl_out, "%cABOR\r\n", DM);
1400 (void) fflush(ctrl_out);
1401 nfds = fileno(ctrl_in) + 1;
1402 FD_ZERO(&mask);
1403 FD_SET(fileno(ctrl_in), &mask);
1404 if (din) {
1405 FD_SET(fileno(din), &mask);
1406 nfds = MAX(fileno(din) + 1, nfds);
1407 }
1408 if ((nfnd = empty(&mask, 10, nfds)) <= 0) {
1409 if (nfnd < 0) {
1410 perror("abort");
1411 }
1412 code = -1;
1413 lostpeer(0);
1414 }
1415 if (din && FD_ISSET(fileno(din), &mask)) {
1416 do {
1417 reset_timer();
1418 } while ((c = read(fileno(din), buf, FTPBUFSIZ)) > 0);
1419 }
1420 if ((c = getreply(0)) == ERROR && code == 552) {
1421 /* needed for nic style abort */
1422 if (data >= 0) {
1423 (void) close(data);
1424 data = -1;
1425 }
1426 (void) getreply(0);
1427 }
1428 if (oldtype) {
1429 if (!debug)
1430 verbose = 0;
1431 switch (oldtype) {
1432 case TYPE_I:
1433 setbinary(0, NULL);
1434 break;
1435 case TYPE_E:
1436 setebcdic(0, NULL);
1437 break;
1438 case TYPE_L:
1439 settenex(0, NULL);
1440 break;
1441 }
1442 verbose = oldverbose;
1443 }
1444 (void) getreply(0);
1445 code = -1;
1446 if (data >= 0) {
1447 (void) close(data);
1448 data = -1;
1449 }
1450 if (closefunc != NULL && fout != NULL)
1451 (*closefunc)(fout);
1452 if (din) {
1453 (void) fclose(din);
1454 data = -1;
1455 }
1456 if (bytes > 0 && verbose)
1457 ptransfer("received", bytes, start, stop, local, remote);
1458 if (!ctrl_in)
1459 (void) printf("Lost connection\n");
1460 (void) signal(SIGINT, oldintr);
1461 }
1462
1463 /*
1464 * Need to start a listen on the data channel
1465 * before we send the command, otherwise the
1466 * server's connect may fail.
1467 */
1468
1469 static int
initconn(void)1470 initconn(void)
1471 {
1472 unsigned char *p, *a;
1473 int result, tmpno = 0;
1474 int on = 1;
1475 socklen_t len;
1476 int v4_addr;
1477 char *c, *c2, delm;
1478 in_port_t ports;
1479
1480 pasv_refused = B_FALSE;
1481 if (passivemode) {
1482 data = socket(AF_INET6, SOCK_STREAM, 0);
1483 if (data < 0) {
1484 perror("socket");
1485 return (1);
1486 }
1487 if (timeout && setsockopt(data, IPPROTO_TCP,
1488 TCP_ABORT_THRESHOLD, (char *)&timeoutms,
1489 sizeof (timeoutms)) < 0 && debug)
1490 perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)");
1491 if ((options & SO_DEBUG) &&
1492 setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1493 sizeof (on)) < 0)
1494 perror("setsockopt (ignored)");
1495 /*
1496 * Use the system wide default send and receive buffer sizes
1497 * unless one has been specified.
1498 */
1499 if (tcpwindowsize) {
1500 if (setsockopt(data, SOL_SOCKET, SO_SNDBUF,
1501 (char *)&tcpwindowsize, sizeof (tcpwindowsize)) < 0)
1502 perror("ftp: setsockopt (SO_SNDBUF - ignored)");
1503 if (setsockopt(data, SOL_SOCKET, SO_RCVBUF,
1504 (char *)&tcpwindowsize, sizeof (tcpwindowsize)) < 0)
1505 perror("ftp: setsockopt (SO_RCVBUF - ignored)");
1506 }
1507
1508 data_addr = remctladdr;
1509
1510 if (ipv6rem == B_TRUE) {
1511 if (command("EPSV") != COMPLETE) {
1512 (void) fprintf(stderr,
1513 "Passive mode refused. Try EPRT\n");
1514 pasv_refused = B_TRUE;
1515 goto noport;
1516 }
1517
1518 /*
1519 * Get the data port from reply string from the
1520 * server. The format of the reply string is:
1521 * 229 Entering Extended Passive Mode (|||port|)
1522 * where | is the delimiter being used.
1523 */
1524 c = strchr(reply_string, '(');
1525 c2 = strchr(reply_string, ')');
1526 if (c == NULL || c2 == NULL) {
1527 (void) fprintf(stderr, "Extended passive mode"
1528 "parsing failure.\n");
1529 goto bad;
1530 }
1531 *(c2 - 1) = '\0';
1532 /* Delimiter is the next char in the reply string */
1533 delm = *(++c);
1534 while (*c == delm) {
1535 if (!*(c++)) {
1536 (void) fprintf(stderr,
1537 "Extended passive mode"
1538 "parsing failure.\n");
1539 goto bad;
1540 }
1541 }
1542 /* assign the port for data connection */
1543 ports = (in_port_t)atoi(c);
1544 data_addr.sin6_port = htons(ports);
1545 } else {
1546 int a1, a2, a3, a4, p1, p2;
1547
1548 if (command("PASV") != COMPLETE) {
1549 (void) fprintf(stderr,
1550 "Passive mode refused. Try PORT\n");
1551 pasv_refused = B_TRUE;
1552 goto noport;
1553 }
1554
1555 /*
1556 * Get the data port from reply string from the
1557 * server. The format of the reply string is:
1558 * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)
1559 */
1560 if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
1561 &a1, &a2, &a3, &a4, &p1, &p2) != 6) {
1562 (void) fprintf(stderr,
1563 "Passive mode parsing failure.\n");
1564 goto bad;
1565 }
1566 /*
1567 * Set the supplied address and port in an
1568 * IPv4-mapped IPv6 address.
1569 */
1570 a = (unsigned char *)&data_addr.sin6_addr +
1571 sizeof (struct in6_addr) -
1572 sizeof (struct in_addr);
1573 #define UC(b) ((b)&0xff)
1574 a[0] = UC(a1);
1575 a[1] = UC(a2);
1576 a[2] = UC(a3);
1577 a[3] = UC(a4);
1578 p = (unsigned char *)&data_addr.sin6_port;
1579 p[0] = UC(p1);
1580 p[1] = UC(p2);
1581 }
1582
1583 if (connect(data, (struct sockaddr *)&data_addr,
1584 sizeof (data_addr)) < 0) {
1585 perror("connect");
1586 goto bad;
1587 }
1588 return (0);
1589 }
1590
1591 noport:
1592 data_addr = myctladdr;
1593 if (sendport)
1594 data_addr.sin6_port = 0; /* let system pick one */
1595
1596 if (data != -1)
1597 (void) close(data);
1598 data = socket(AF_INET6, SOCK_STREAM, 0);
1599 if (data < 0) {
1600 perror("ftp: socket");
1601 if (tmpno)
1602 sendport = 1;
1603 return (1);
1604 }
1605 if (!sendport)
1606 if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR,
1607 (char *)&on, sizeof (on)) < 0) {
1608 perror("ftp: setsockopt (SO_REUSEADDR)");
1609 goto bad;
1610 }
1611 if (bind(data,
1612 (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
1613 perror("ftp: bind");
1614 goto bad;
1615 }
1616 if (timeout && setsockopt(data, IPPROTO_TCP, TCP_ABORT_THRESHOLD,
1617 (char *)&timeoutms, sizeof (timeoutms)) < 0 && debug)
1618 perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)");
1619 if (options & SO_DEBUG &&
1620 setsockopt(data, SOL_SOCKET, SO_DEBUG,
1621 (char *)&on, sizeof (on)) < 0)
1622 perror("ftp: setsockopt (SO_DEBUG - ignored)");
1623 /*
1624 * Use the system wide default send and receive buffer sizes unless
1625 * one has been specified.
1626 */
1627 if (tcpwindowsize) {
1628 if (setsockopt(data, SOL_SOCKET, SO_SNDBUF,
1629 (char *)&tcpwindowsize, sizeof (tcpwindowsize)) < 0)
1630 perror("ftp: setsockopt (SO_SNDBUF - ignored)");
1631 if (setsockopt(data, SOL_SOCKET, SO_RCVBUF,
1632 (char *)&tcpwindowsize, sizeof (tcpwindowsize)) < 0)
1633 perror("ftp: setsockopt (SO_RCVBUF - ignored)");
1634 }
1635 len = sizeof (data_addr);
1636 if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1637 perror("ftp: getsockname");
1638 goto bad;
1639 }
1640
1641 v4_addr = IN6_IS_ADDR_V4MAPPED(&data_addr.sin6_addr);
1642 if (listen(data, 1) < 0)
1643 perror("ftp: listen");
1644
1645 if (sendport) {
1646 a = (unsigned char *)&data_addr.sin6_addr;
1647 p = (unsigned char *)&data_addr.sin6_port;
1648 if (v4_addr) {
1649 result =
1650 command("PORT %d,%d,%d,%d,%d,%d",
1651 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
1652 UC(p[0]), UC(p[1]));
1653 } else {
1654 char hname[INET6_ADDRSTRLEN];
1655
1656 result = COMPLETE + 1;
1657 /*
1658 * if on previous try to server, it was
1659 * determined that the server doesn't support
1660 * EPRT, don't bother trying again. Just try
1661 * LPRT.
1662 */
1663 if (eport_supported == B_TRUE) {
1664 if (inet_ntop(AF_INET6, &data_addr.sin6_addr,
1665 hname, sizeof (hname)) != NULL) {
1666 result = command("EPRT |%d|%s|%d|", 2,
1667 hname, htons(data_addr.sin6_port));
1668 if (result != COMPLETE)
1669 eport_supported = B_FALSE;
1670 }
1671 }
1672 /* Try LPRT */
1673 if (result != COMPLETE) {
1674 result = command(
1675 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
1676 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1677 6, 16,
1678 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1679 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
1680 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
1681 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
1682 2, UC(p[0]), UC(p[1]));
1683 }
1684 }
1685
1686 if (result == ERROR && sendport == -1) {
1687 sendport = 0;
1688 tmpno = 1;
1689 goto noport;
1690 }
1691 return (result != COMPLETE);
1692 }
1693 if (tmpno)
1694 sendport = 1;
1695 return (0);
1696 bad:
1697 (void) close(data), data = -1;
1698 if (tmpno)
1699 sendport = 1;
1700 return (1);
1701 }
1702
1703 static FILE *
dataconn(char * mode)1704 dataconn(char *mode)
1705 {
1706 struct sockaddr_in6 from;
1707 int s;
1708 socklen_t fromlen = sizeof (from);
1709
1710 reset_timer();
1711 if (passivemode && !pasv_refused)
1712 return (fdopen(data, mode));
1713
1714 s = accept(data, (struct sockaddr *)&from, &fromlen);
1715 if (s < 0) {
1716 perror("ftp: accept");
1717 (void) close(data), data = -1;
1718 return (NULL);
1719 }
1720 (void) close(data);
1721 data = s;
1722 return (fdopen(data, mode));
1723 }
1724
1725 static void
ptransfer(char * direction,off_t bytes,hrtime_t t0,hrtime_t t1,char * local,char * remote)1726 ptransfer(char *direction, off_t bytes, hrtime_t t0,
1727 hrtime_t t1, char *local, char *remote)
1728 {
1729 hrtime_t td; /* nanoseconds in a 64 bit int */
1730 double s, bs;
1731
1732 td = t1 - t0;
1733 s = (double)td / 1000000000.0; /* seconds */
1734 bs = (double)bytes / NONZERO(s);
1735 if (local && *local != '-')
1736 (void) printf("local: %s ", local);
1737 if (remote)
1738 (void) printf("remote: %s\n", remote);
1739 (void) printf("%lld bytes %s in %.2g seconds (%.2f Kbytes/s)\n",
1740 (longlong_t)bytes, direction, s, bs / 1024.0);
1741 }
1742
1743 /*ARGSUSED*/
1744 static void
psabort(int sig)1745 psabort(int sig)
1746 {
1747 abrtflag++;
1748 }
1749
1750 void
pswitch(int flag)1751 pswitch(int flag)
1752 {
1753 void (*oldintr)();
1754 static struct comvars {
1755 int connect;
1756 char name[MAXHOSTNAMELEN];
1757 struct sockaddr_in6 mctl;
1758 struct sockaddr_in6 hctl;
1759 FILE *in;
1760 FILE *out;
1761 int tpe;
1762 int cpnd;
1763 int sunqe;
1764 int runqe;
1765 int mcse;
1766 int ntflg;
1767 char nti[17];
1768 char nto[17];
1769 int mapflg;
1770 char mi[MAXPATHLEN];
1771 char mo[MAXPATHLEN];
1772 int authtype;
1773 int clvl;
1774 int dlvl;
1775 } proxstruct, tmpstruct;
1776 struct comvars *ip, *op;
1777
1778 abrtflag = 0;
1779 oldintr = signal(SIGINT, psabort);
1780 if (flag) {
1781 if (proxy)
1782 return;
1783 ip = &tmpstruct;
1784 op = &proxstruct;
1785 proxy++;
1786 } else {
1787 if (!proxy)
1788 return;
1789 ip = &proxstruct;
1790 op = &tmpstruct;
1791 proxy = 0;
1792 }
1793 ip->connect = connected;
1794 connected = op->connect;
1795 if (hostname)
1796 (void) strlcpy(ip->name, hostname, sizeof (ip->name));
1797 else
1798 ip->name[0] = 0;
1799 hostname = op->name;
1800 ip->hctl = remctladdr;
1801 remctladdr = op->hctl;
1802 ip->mctl = myctladdr;
1803 myctladdr = op->mctl;
1804 ip->in = ctrl_in;
1805 ctrl_in = op->in;
1806 ip->out = ctrl_out;
1807 ctrl_out = op->out;
1808 ip->tpe = type;
1809 type = op->tpe;
1810 if (!type)
1811 type = 1;
1812 ip->cpnd = cpend;
1813 cpend = op->cpnd;
1814 ip->sunqe = sunique;
1815 sunique = op->sunqe;
1816 ip->runqe = runique;
1817 runique = op->runqe;
1818 ip->mcse = mcase;
1819 mcase = op->mcse;
1820 ip->ntflg = ntflag;
1821 ntflag = op->ntflg;
1822 (void) strlcpy(ip->nti, ntin, sizeof (ip->nti));
1823 (void) strlcpy(ntin, op->nti, sizeof (ntin));
1824 (void) strlcpy(ip->nto, ntout, sizeof (ip->nto));
1825 (void) strlcpy(ntout, op->nto, sizeof (ntout));
1826 ip->mapflg = mapflag;
1827 mapflag = op->mapflg;
1828 (void) strlcpy(ip->mi, mapin, sizeof (ip->mi));
1829 (void) strlcpy(mapin, op->mi, sizeof (mapin));
1830 (void) strlcpy(ip->mo, mapout, sizeof (ip->mo));
1831 (void) strlcpy(mapout, op->mo, sizeof (mapout));
1832
1833 ip->authtype = auth_type;
1834 auth_type = op->authtype;
1835 ip->clvl = clevel;
1836 clevel = op->clvl;
1837 ip->dlvl = dlevel;
1838 dlevel = op->dlvl;
1839 if (!clevel)
1840 clevel = PROT_C;
1841 if (!dlevel)
1842 dlevel = PROT_C;
1843
1844 (void) signal(SIGINT, oldintr);
1845 if (abrtflag) {
1846 abrtflag = 0;
1847 (*oldintr)();
1848 }
1849 }
1850
1851 /*ARGSUSED*/
1852 static void
abortpt(int sig)1853 abortpt(int sig)
1854 {
1855 (void) printf("\n");
1856 (void) fflush(stdout);
1857 ptabflg++;
1858 mflag = 0;
1859 abrtflag = 0;
1860 longjmp(ptabort, 1);
1861 }
1862
1863 static void
proxtrans(char * cmd,char * local,char * remote)1864 proxtrans(char *cmd, char *local, char *remote)
1865 {
1866 void (*oldintr)();
1867 int tmptype, oldtype = 0, secndflag = 0, nfnd;
1868 extern jmp_buf ptabort;
1869 char *cmd2;
1870 struct fd_set mask;
1871 int ipv4_addr = IN6_IS_ADDR_V4MAPPED(&remctladdr.sin6_addr);
1872
1873 if (strcmp(cmd, "RETR"))
1874 cmd2 = "RETR";
1875 else
1876 cmd2 = runique ? "STOU" : "STOR";
1877 if (command(ipv4_addr ? "PASV" : "EPSV") != COMPLETE) {
1878 (void) printf(
1879 "proxy server does not support third part transfers.\n");
1880 return;
1881 }
1882 tmptype = type;
1883 pswitch(0);
1884 if (!connected) {
1885 (void) printf("No primary connection\n");
1886 pswitch(1);
1887 code = -1;
1888 return;
1889 }
1890 if (type != tmptype) {
1891 oldtype = type;
1892 switch (tmptype) {
1893 case TYPE_A:
1894 setascii(0, NULL);
1895 break;
1896 case TYPE_I:
1897 setbinary(0, NULL);
1898 break;
1899 case TYPE_E:
1900 setebcdic(0, NULL);
1901 break;
1902 case TYPE_L:
1903 settenex(0, NULL);
1904 break;
1905 }
1906 }
1907 if (command(ipv4_addr ? "PORT %s" : "EPRT %s", pasv) != COMPLETE) {
1908 switch (oldtype) {
1909 case 0:
1910 break;
1911 case TYPE_A:
1912 setascii(0, NULL);
1913 break;
1914 case TYPE_I:
1915 setbinary(0, NULL);
1916 break;
1917 case TYPE_E:
1918 setebcdic(0, NULL);
1919 break;
1920 case TYPE_L:
1921 settenex(0, NULL);
1922 break;
1923 }
1924 pswitch(1);
1925 return;
1926 }
1927 if (setjmp(ptabort))
1928 goto abort;
1929 oldintr = signal(SIGINT, (void (*)())abortpt);
1930 if (command("%s %s", cmd, remote) != PRELIM) {
1931 (void) signal(SIGINT, oldintr);
1932 switch (oldtype) {
1933 case 0:
1934 break;
1935 case TYPE_A:
1936 setascii(0, NULL);
1937 break;
1938 case TYPE_I:
1939 setbinary(0, NULL);
1940 break;
1941 case TYPE_E:
1942 setebcdic(0, NULL);
1943 break;
1944 case TYPE_L:
1945 settenex(0, NULL);
1946 break;
1947 }
1948 pswitch(1);
1949 return;
1950 }
1951 (void) sleep(2);
1952 pswitch(1);
1953 secndflag++;
1954 if (command("%s %s", cmd2, local) != PRELIM)
1955 goto abort;
1956 ptflag++;
1957 (void) getreply(0);
1958 pswitch(0);
1959 (void) getreply(0);
1960 (void) signal(SIGINT, oldintr);
1961 switch (oldtype) {
1962 case 0:
1963 break;
1964 case TYPE_A:
1965 setascii(0, NULL);
1966 break;
1967 case TYPE_I:
1968 setbinary(0, NULL);
1969 break;
1970 case TYPE_E:
1971 setebcdic(0, NULL);
1972 break;
1973 case TYPE_L:
1974 settenex(0, NULL);
1975 break;
1976 }
1977 pswitch(1);
1978 ptflag = 0;
1979 (void) printf("local: %s remote: %s\n", local, remote);
1980 return;
1981 abort:
1982 (void) signal(SIGINT, SIG_IGN);
1983 ptflag = 0;
1984 if (strcmp(cmd, "RETR") && !proxy)
1985 pswitch(1);
1986 else if ((strcmp(cmd, "RETR") == 0) && proxy)
1987 pswitch(0);
1988 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
1989 if (command("%s %s", cmd2, local) != PRELIM) {
1990 pswitch(0);
1991 switch (oldtype) {
1992 case 0:
1993 break;
1994 case TYPE_A:
1995 setascii(0, NULL);
1996 break;
1997 case TYPE_I:
1998 setbinary(0, NULL);
1999 break;
2000 case TYPE_E:
2001 setebcdic(0, NULL);
2002 break;
2003 case TYPE_L:
2004 settenex(0, NULL);
2005 break;
2006 }
2007 if (cpend) {
2008 char msg[2];
2009
2010 (void) fprintf(ctrl_out, "%c%c", IAC, IP);
2011 (void) fflush(ctrl_out);
2012 *msg = (char)IAC;
2013 *(msg+1) = (char)DM;
2014 if (send(fileno(ctrl_out), msg, 2, MSG_OOB)
2015 != 2)
2016 perror("abort");
2017 (void) fprintf(ctrl_out, "ABOR\r\n");
2018 (void) fflush(ctrl_out);
2019 FD_ZERO(&mask);
2020 FD_SET(fileno(ctrl_in), &mask);
2021 if ((nfnd = empty(&mask, 10,
2022 fileno(ctrl_in) + 1)) <= 0) {
2023 if (nfnd < 0) {
2024 perror("abort");
2025 }
2026 if (ptabflg)
2027 code = -1;
2028 lostpeer(0);
2029 }
2030 (void) getreply(0);
2031 (void) getreply(0);
2032 }
2033 }
2034 pswitch(1);
2035 if (ptabflg)
2036 code = -1;
2037 (void) signal(SIGINT, oldintr);
2038 return;
2039 }
2040 if (cpend) {
2041 char msg[2];
2042
2043 (void) fprintf(ctrl_out, "%c%c", IAC, IP);
2044 (void) fflush(ctrl_out);
2045 *msg = (char)IAC;
2046 *(msg+1) = (char)DM;
2047 if (send(fileno(ctrl_out), msg, 2, MSG_OOB) != 2)
2048 perror("abort");
2049 (void) fprintf(ctrl_out, "ABOR\r\n");
2050 (void) fflush(ctrl_out);
2051 FD_ZERO(&mask);
2052 FD_SET(fileno(ctrl_in), &mask);
2053 if ((nfnd = empty(&mask, 10, fileno(ctrl_in) + 1)) <= 0) {
2054 if (nfnd < 0) {
2055 perror("abort");
2056 }
2057 if (ptabflg)
2058 code = -1;
2059 lostpeer(0);
2060 }
2061 (void) getreply(0);
2062 (void) getreply(0);
2063 }
2064 pswitch(!proxy);
2065 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
2066 if (command("%s %s", cmd2, local) != PRELIM) {
2067 pswitch(0);
2068 switch (oldtype) {
2069 case 0:
2070 break;
2071 case TYPE_A:
2072 setascii(0, NULL);
2073 break;
2074 case TYPE_I:
2075 setbinary(0, NULL);
2076 break;
2077 case TYPE_E:
2078 setebcdic(0, NULL);
2079 break;
2080 case TYPE_L:
2081 settenex(0, NULL);
2082 break;
2083 }
2084 if (cpend) {
2085 char msg[2];
2086
2087 (void) fprintf(ctrl_out, "%c%c", IAC, IP);
2088 (void) fflush(ctrl_out);
2089 *msg = (char)IAC;
2090 *(msg+1) = (char)DM;
2091 if (send(fileno(ctrl_out), msg, 2, MSG_OOB)
2092 != 2)
2093 perror("abort");
2094 (void) fprintf(ctrl_out, "ABOR\r\n");
2095 (void) fflush(ctrl_out);
2096 FD_ZERO(&mask);
2097 FD_SET(fileno(ctrl_in), &mask);
2098 if ((nfnd = empty(&mask, 10,
2099 fileno(ctrl_in) + 1)) <= 0) {
2100 if (nfnd < 0) {
2101 perror("abort");
2102 }
2103 if (ptabflg)
2104 code = -1;
2105 lostpeer(0);
2106 }
2107 (void) getreply(0);
2108 (void) getreply(0);
2109 }
2110 pswitch(1);
2111 if (ptabflg)
2112 code = -1;
2113 (void) signal(SIGINT, oldintr);
2114 return;
2115 }
2116 }
2117 if (cpend) {
2118 char msg[2];
2119
2120 (void) fprintf(ctrl_out, "%c%c", IAC, IP);
2121 (void) fflush(ctrl_out);
2122 *msg = (char)IAC;
2123 *(msg+1) = (char)DM;
2124 if (send(fileno(ctrl_out), msg, 2, MSG_OOB) != 2)
2125 perror("abort");
2126 (void) fprintf(ctrl_out, "ABOR\r\n");
2127 (void) fflush(ctrl_out);
2128 FD_ZERO(&mask);
2129 FD_SET(fileno(ctrl_in), &mask);
2130 if ((nfnd = empty(&mask, 10, fileno(ctrl_in) + 1)) <= 0) {
2131 if (nfnd < 0) {
2132 perror("abort");
2133 }
2134 if (ptabflg)
2135 code = -1;
2136 lostpeer(0);
2137 }
2138 (void) getreply(0);
2139 (void) getreply(0);
2140 }
2141 pswitch(!proxy);
2142 if (cpend) {
2143 FD_ZERO(&mask);
2144 FD_SET(fileno(ctrl_in), &mask);
2145 if ((nfnd = empty(&mask, 10, fileno(ctrl_in) + 1)) <= 0) {
2146 if (nfnd < 0) {
2147 perror("abort");
2148 }
2149 if (ptabflg)
2150 code = -1;
2151 lostpeer(0);
2152 }
2153 (void) getreply(0);
2154 (void) getreply(0);
2155 }
2156 if (proxy)
2157 pswitch(0);
2158 switch (oldtype) {
2159 case 0:
2160 break;
2161 case TYPE_A:
2162 setascii(0, NULL);
2163 break;
2164 case TYPE_I:
2165 setbinary(0, NULL);
2166 break;
2167 case TYPE_E:
2168 setebcdic(0, NULL);
2169 break;
2170 case TYPE_L:
2171 settenex(0, NULL);
2172 break;
2173 }
2174 pswitch(1);
2175 if (ptabflg)
2176 code = -1;
2177 (void) signal(SIGINT, oldintr);
2178 }
2179
2180 /*ARGSUSED*/
2181 void
reset(int argc,char * argv[])2182 reset(int argc, char *argv[])
2183 {
2184 struct fd_set mask;
2185 int nfnd = 1;
2186
2187 FD_ZERO(&mask);
2188 while (nfnd > 0) {
2189 FD_SET(fileno(ctrl_in), &mask);
2190 if ((nfnd = empty(&mask, 0, fileno(ctrl_in) + 1)) < 0) {
2191 perror("reset");
2192 code = -1;
2193 lostpeer(0);
2194 } else if (nfnd > 0) {
2195 (void) getreply(0);
2196 }
2197 }
2198 }
2199
2200 static char *
gunique(char * local)2201 gunique(char *local)
2202 {
2203 static char new[MAXPATHLEN];
2204 char *cp = rindex(local, '/');
2205 int d, count = 0;
2206 char ext = '1';
2207
2208 if (cp)
2209 *cp = '\0';
2210 d = access(cp ? local : ".", 2);
2211 if (cp)
2212 *cp = '/';
2213 if (d < 0) {
2214 perror(local);
2215 return ((char *)0);
2216 }
2217 if (strlcpy(new, local, sizeof (new)) >= sizeof (new))
2218 (void) printf("gunique: too long: local %s, %d, new %d\n",
2219 local, strlen(local), sizeof (new));
2220
2221 cp = new + strlen(new);
2222 *cp++ = '.';
2223 while (!d) {
2224 if (++count == 100) {
2225 (void) printf(
2226 "gunique: can't find unique file name.\n");
2227 return (NULL);
2228 }
2229 *cp++ = ext;
2230 *cp = '\0';
2231 if (ext == '9')
2232 ext = '0';
2233 else
2234 ext++;
2235 if ((d = access(new, 0)) < 0)
2236 break;
2237 if (ext != '0')
2238 cp--;
2239 else if (*(cp - 2) == '.')
2240 *(cp - 1) = '1';
2241 else {
2242 *(cp - 2) = *(cp - 2) + 1;
2243 cp--;
2244 }
2245 }
2246 return (new);
2247 }
2248
2249 /*
2250 * This is a wrap-around function for inet_ntop(). In case the af is AF_INET6
2251 * and the address pointed by src is a IPv4-mapped IPv6 address, it
2252 * returns printable IPv4 address, not IPv4-mapped IPv6 address. In other cases
2253 * it behaves just like inet_ntop().
2254 */
2255 const char *
inet_ntop_native(int af,const void * src,char * dst,size_t size)2256 inet_ntop_native(int af, const void *src, char *dst, size_t size)
2257 {
2258 struct in_addr src4;
2259 const char *result;
2260 struct sockaddr_in *sin;
2261 struct sockaddr_in6 *sin6;
2262
2263 if (af == AF_INET6) {
2264 sin6 = (struct sockaddr_in6 *)src;
2265 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
2266 IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, &src4);
2267 result = inet_ntop(AF_INET, &src4, dst, size);
2268 } else {
2269 result = inet_ntop(AF_INET6, &sin6->sin6_addr,
2270 dst, size);
2271 }
2272 } else {
2273 sin = (struct sockaddr_in *)src;
2274 result = inet_ntop(af, &sin->sin_addr, dst, size);
2275 }
2276
2277 return (result);
2278 }
2279
2280 int
secure_command(char * cmd)2281 secure_command(char *cmd)
2282 {
2283 unsigned char *in = NULL, *out = NULL;
2284 int length = 0;
2285 size_t inlen;
2286
2287 if ((auth_type != AUTHTYPE_NONE) && clevel != PROT_C) {
2288 gss_buffer_desc in_buf, out_buf;
2289 OM_uint32 maj_stat, min_stat;
2290
2291 /* secure_command (based on level) */
2292 if (auth_type == AUTHTYPE_GSSAPI) {
2293 OM_uint32 expire_time;
2294 int conf_state;
2295 /* clevel = PROT_P; */
2296 in_buf.value = cmd;
2297 in_buf.length = strlen(cmd) + 1;
2298
2299 maj_stat = gss_context_time(&min_stat, gcontext,
2300 &expire_time);
2301 if (GSS_ERROR(maj_stat)) {
2302 user_gss_error(maj_stat, min_stat,
2303 "gss context has expired");
2304 fatal("Your gss credentials have expired. "
2305 "Good-bye!");
2306 }
2307 maj_stat = gss_seal(&min_stat, gcontext,
2308 (clevel == PROT_P), /* private */
2309 GSS_C_QOP_DEFAULT,
2310 &in_buf, &conf_state,
2311 &out_buf);
2312 if (maj_stat != GSS_S_COMPLETE) {
2313 /* generally need to deal */
2314 user_gss_error(maj_stat, min_stat,
2315 (clevel == PROT_P) ?
2316 "gss_seal ENC didn't complete":
2317 "gss_seal MIC didn't complete");
2318 } else if ((clevel == PROT_P) && !conf_state) {
2319 (void) fprintf(stderr,
2320 "GSSAPI didn't encrypt message");
2321 out = out_buf.value;
2322 } else {
2323 if (debug)
2324 (void) fprintf(stderr,
2325 "sealed (%s) %d bytes\n",
2326 clevel == PROT_P ? "ENC" : "MIC",
2327 out_buf.length);
2328
2329 out = out_buf.value;
2330 }
2331 }
2332 /* Other auth types go here ... */
2333 inlen = ((4 * out_buf.length) / 3) + 4;
2334 in = (uchar_t *)malloc(inlen);
2335 if (in == NULL) {
2336 gss_release_buffer(&min_stat, &out_buf);
2337 fatal("Memory error allocating space for response.");
2338 }
2339 length = out_buf.length;
2340 if (auth_error = radix_encode(out, in, inlen, &length, 0)) {
2341 (void) fprintf(stderr,
2342 "Couldn't base 64 encode command (%s)\n",
2343 radix_error(auth_error));
2344 free(in);
2345 gss_release_buffer(&min_stat, &out_buf);
2346 return (0);
2347 }
2348
2349 (void) fprintf(ctrl_out, "%s %s",
2350 clevel == PROT_P ? "ENC" : "MIC", in);
2351
2352 free(in);
2353 gss_release_buffer(&min_stat, &out_buf);
2354
2355 if (debug)
2356 (void) fprintf(stderr,
2357 "secure_command(%s)\nencoding %d bytes %s %s\n",
2358 cmd, length,
2359 (clevel == PROT_P) ? "ENC" : "MIC", in);
2360 } else {
2361 /*
2362 * auth_type = AUTHTYPE_NONE or
2363 * command channel is not protected
2364 */
2365 fputs(cmd, ctrl_out);
2366 }
2367
2368 (void) fprintf(ctrl_out, "\r\n");
2369 (void) fflush(ctrl_out);
2370 return (1);
2371 }
2372
2373 unsigned int maxbuf;
2374 unsigned char *ucbuf;
2375
2376 void
setpbsz(unsigned int size)2377 setpbsz(unsigned int size)
2378 {
2379 unsigned int actualbuf;
2380 int oldverbose;
2381
2382 if (ucbuf)
2383 (void) free(ucbuf);
2384 actualbuf = size;
2385 while ((ucbuf = (unsigned char *)malloc(actualbuf)) == NULL) {
2386 if (actualbuf)
2387 actualbuf >>= 2;
2388 else {
2389 perror("Error while trying to malloc PROT buffer:");
2390 exit(1);
2391 }
2392 }
2393 oldverbose = verbose;
2394 verbose = 0;
2395 reply_parse = "PBSZ=";
2396 if (command("PBSZ %u", actualbuf) != COMPLETE)
2397 fatal("Cannot set PROT buffer size");
2398 if (reply_parse) {
2399 if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
2400 maxbuf = actualbuf;
2401 } else
2402 maxbuf = actualbuf;
2403 reply_parse = NULL;
2404 verbose = oldverbose;
2405 }
2406
2407 /*
2408 * Do the base 64 decoding of the raw input buffer, b64_buf.
2409 * Also do the verification and decryption, if required.
2410 * retval contains the current error code number
2411 *
2412 * returns:
2413 * (RFC 2228: error returns are 3 digit numbers of the form 5xy)
2414 * 5 if an error occurred
2415 */
2416 static int
decode_reply(uchar_t * plain_buf,int ilen,uchar_t * b64_buf,int retval,boolean_t * again)2417 decode_reply(uchar_t *plain_buf, int ilen, uchar_t *b64_buf, int retval,
2418 boolean_t *again)
2419 {
2420 int len;
2421 int safe = 0;
2422
2423 *again = 0;
2424
2425 if (!b64_buf[0]) /* if there is no string, no problem */
2426 return (retval);
2427
2428 if ((auth_type == AUTHTYPE_NONE)) {
2429 (void) printf("Cannot decode reply:\n%d %s\n", code, b64_buf);
2430 return ('5');
2431 }
2432
2433 switch (code) {
2434
2435 case 631: /* 'safe' */
2436 safe = 1;
2437 break;
2438
2439 case 632: /* 'private' */
2440 break;
2441
2442 case 633: /* 'confidential' */
2443 break;
2444
2445 default:
2446 (void) printf("Unknown reply: %d %s\n", code, b64_buf);
2447 return ('5');
2448 }
2449
2450 /* decode the base64 encoded message */
2451 auth_error = radix_encode(b64_buf, plain_buf, ilen, &len, 1);
2452
2453 if (auth_error) {
2454 (void) printf("Can't base 64 decode reply %d (%s)\n\"%s\"\n",
2455 code, radix_error(auth_error), b64_buf);
2456 return ('5');
2457 }
2458
2459 if (auth_type == AUTHTYPE_GSSAPI) {
2460 gss_buffer_desc xmit_buf, msg_buf;
2461 OM_uint32 maj_stat, min_stat;
2462 int conf_state = safe;
2463 xmit_buf.value = plain_buf;
2464 xmit_buf.length = len;
2465
2466 /* decrypt/verify the message */
2467 maj_stat = gss_unseal(&min_stat, gcontext,
2468 &xmit_buf, &msg_buf, &conf_state, NULL);
2469 if (maj_stat != GSS_S_COMPLETE) {
2470 user_gss_error(maj_stat, min_stat,
2471 "failed unsealing reply");
2472 return ('5');
2473 }
2474 if (msg_buf.length < ilen - 2 - 1) {
2475 memcpy(plain_buf, msg_buf.value, msg_buf.length);
2476 strcpy((char *)&plain_buf[msg_buf.length], "\r\n");
2477 gss_release_buffer(&min_stat, &msg_buf);
2478 *again = 1;
2479 } else {
2480 user_gss_error(maj_stat, min_stat,
2481 "reply was too long");
2482 return ('5');
2483 }
2484 } /* end if GSSAPI */
2485
2486 /* Other auth types go here... */
2487
2488 return (retval);
2489 }
2490