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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
41 #include <arpa/nameser.h>
42 #include <sys/types.h>
47 * -1 error, errorno is set
48 * -2 security error (secure_write() only)
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)
54 static struct sockaddr_in6 data_addr
;
56 static int abrtflag
= 0;
57 static int ptflag
= 0;
59 static jmp_buf sendabort
;
60 static jmp_buf recvabort
;
61 static jmp_buf ptabort
;
63 static boolean_t pasv_refused
;
64 boolean_t eport_supported
= B_TRUE
;
66 * For IPv6 addresses, EPSV will be the default (rather than EPRT/LPRT).
67 * The EPSV/ERPT ftp protocols are specified in RFC 2428.
69 * Perform EPSV if passivemode is set and ipv6rem is TRUE.
71 static boolean_t ipv6rem
;
72 int use_eprt
= 0; /* Testing option that specifies EPRT by default */
73 FILE *ctrl_in
, *ctrl_out
;
75 static void abortsend(int sig
);
76 static void abortpt(int sig
);
77 static void proxtrans(char *cmd
, char *local
, char *remote
);
78 static void cmdabort(int sig
);
79 static int empty(struct fd_set
*mask
, int sec
, int nfds
);
80 static void abortrecv(int sig
);
81 static int initconn(void);
82 static FILE *dataconn(char *mode
);
83 static void ptransfer(char *direction
, off_t bytes
, hrtime_t t0
,
84 hrtime_t t1
, char *local
, char *remote
);
85 static void psabort(int sig
);
86 static char *gunique(char *local
);
87 static const char *inet_ntop_native(int af
, const void *src
, char *dst
,
89 static ssize_t
timedread(int fd
, void *buf
, size_t maxlen
, int timeout
);
91 static int secure_command(char *);
92 static int decode_reply(uchar_t
*, int, uchar_t
*, int, boolean_t
*);
94 static ssize_t bufcnt
; /* number of bytes in buf[] */
95 static char *bufp
; /* next character in buf */
96 static int buferr
; /* last errno */
97 static size_t bufsize
;
99 static void fdio_setbuf(char *buffer
, size_t bufsize
);
100 static int fdio_fillbuf(int fd
);
101 static int fdio_error(int fd
);
102 #define fdio_getc(fd) (--bufcnt < 0 ? fdio_fillbuf((fd)) : \
103 ((unsigned char)*bufp++))
105 #define MAX(a, b) ((a) > (b) ? (a) : (b))
106 #define NONZERO(x) ((x) == 0 ? 1 : (x))
109 fdio_setbuf(char *buffer
, size_t maxsize
)
121 bufcnt
= timedread(fd
, buf
, bufsize
, timeout
);
128 return ((unsigned char)*bufp
++);
132 * fdio_error - used on a file descriptor instead of ferror()
143 * timedread - read buffer (like "read"), but with timeout (in seconds)
147 timedread(int fd
, void *buf
, size_t size
, int timeout
)
154 return (READ(fd
, buf
, size
));
156 tv
.tv_sec
= (time_t)timeout
;
162 err
= select(fd
+ 1, &mask
, NULL
, NULL
, &tv
);
168 return (READ(fd
, buf
, size
));
173 hookup(char *host
, char *service
)
175 struct addrinfo hints
, *ai
= NULL
, *ai_head
;
178 static char hostnamebuf
[80];
179 struct in6_addr ipv6addr
;
180 char abuf
[INET6_ADDRSTRLEN
];
185 * There appears to be a bug in getaddrinfo() where, if the
186 * ai_family is set to AF_INET6, and the host is a v4-only
187 * host, getaddrinfo() returns an error instead of returning
188 * an v4-mapped ipv6 address. Therefore the ai_family is
189 * set to AF_UNSPEC and any returned v4 addresses are
190 * explicitly mapped within ftp.
192 bzero((char *)&remctladdr
, sizeof (remctladdr
));
193 bzero((char *)&hints
, sizeof (hints
));
194 hints
.ai_flags
= AI_CANONNAME
;
195 hints
.ai_family
= AF_UNSPEC
;
196 hints
.ai_socktype
= SOCK_STREAM
;
198 error_num
= getaddrinfo(host
, service
, &hints
, &ai
);
199 if (error_num
!= 0) {
200 if (error_num
== EAI_AGAIN
) {
202 "%s: unknown host or invalid literal address "
203 "(try again later)\n", host
);
206 "%s: unknown host or invalid literal address\n",
216 * If ai_canonname is a IPv4-mapped IPv6 literal, we'll convert it to
217 * IPv4 literal address.
219 if (ai
->ai_canonname
!= NULL
&&
220 (inet_pton(AF_INET6
, ai
->ai_canonname
, &ipv6addr
) > 0) &&
221 IN6_IS_ADDR_V4MAPPED(&ipv6addr
)) {
223 hostnamebuf
[0] = '\0';
224 IN6_V4MAPPED_TO_INADDR(&ipv6addr
, &src4
);
225 (void) inet_ntop(AF_INET
, &src4
, hostnamebuf
,
226 sizeof (hostnamebuf
));
229 * It can even be the case that the "host" supplied by the user
230 * can be a IPv4-mapped IPv6 literal. So, let's fix that too.
232 if ((inet_pton(AF_INET6
, host
, &ipv6addr
) > 0) &&
233 IN6_IS_ADDR_V4MAPPED(&ipv6addr
) &&
234 strlen(hostnamebuf
) <= strlen(host
)) {
235 (void) strlcpy(host
, hostnamebuf
, strlen(host
) + 1);
239 (void) strlcpy(hostnamebuf
,
240 (ai
->ai_canonname
? ai
->ai_canonname
: host
),
241 sizeof (hostnamebuf
));
244 hostname
= hostnamebuf
;
248 bcopy(ai
->ai_addr
, &remctladdr
, ai
->ai_addrlen
);
249 if (ai
->ai_addr
->sa_family
== AF_INET
) {
250 IN6_INADDR_TO_V4MAPPED(
251 &(((struct sockaddr_in
*)ai
->ai_addr
)->sin_addr
),
252 &remctladdr
.sin6_addr
);
253 remctladdr
.sin6_family
= AF_INET6
;
256 s
= socket(AF_INET6
, SOCK_STREAM
, 0);
258 perror("ftp: socket");
260 freeaddrinfo(ai_head
);
263 if (timeout
&& setsockopt(s
, IPPROTO_TCP
, TCP_ABORT_THRESHOLD
,
264 (char *)&timeoutms
, sizeof (timeoutms
)) < 0 && debug
)
265 perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)");
268 error_num
= connect(s
, (struct sockaddr
*)&remctladdr
,
269 sizeof (remctladdr
));
275 * Maintain message behavior: only include the address in
276 * our error message if we have another one to try; if this
277 * is the last address on our list, just print the error.
279 if (ai
->ai_next
!= NULL
) {
280 (void) fprintf(stderr
, "ftp: connect to address %s: ",
281 inet_ntop_native(ai
->ai_addr
->sa_family
,
282 (void *)ai
->ai_addr
, abuf
, sizeof (abuf
)));
286 perror("ftp: connect");
288 freeaddrinfo(ai_head
);
292 (void) fprintf(stdout
, "Trying %s...\n",
293 inet_ntop_native(ai
->ai_addr
->sa_family
,
294 (void *)ai
->ai_addr
, abuf
, sizeof (abuf
)));
299 /* Set ipv6rem to TRUE if control connection is a native IPv6 address */
300 if (IN6_IS_ADDR_V4MAPPED(&remctladdr
.sin6_addr
))
306 freeaddrinfo(ai_head
);
310 * Set passive mode flag on by default only if a native IPv6 address
311 * is being used -and- the use_eprt is not set.
313 if (ipv6rem
== B_TRUE
&& use_eprt
== 0)
316 len
= sizeof (myctladdr
);
317 if (getsockname(s
, (struct sockaddr
*)&myctladdr
, &len
) < 0) {
318 perror("ftp: getsockname");
322 ctrl_in
= fdopen(s
, "r");
323 ctrl_out
= fdopen(s
, "w");
324 if (ctrl_in
== NULL
|| ctrl_out
== NULL
) {
325 (void) fprintf(stderr
, "ftp: fdopen failed.\n");
327 (void) fclose(ctrl_in
);
329 (void) fclose(ctrl_out
);
334 (void) printf("Connected to %s.\n", hostname
);
335 if (getreply(0) > 2) { /* read startup message from server */
337 (void) fclose(ctrl_in
);
339 (void) fclose(ctrl_out
);
340 ctrl_in
= ctrl_out
= NULL
;
341 ctrl_in
= ctrl_out
= NULL
;
345 if (setsockopt(s
, SOL_SOCKET
, SO_OOBINLINE
, (char *)&on
,
346 sizeof (on
)) < 0 && debug
)
347 perror("ftp: setsockopt (SO_OOBINLINE)");
359 char *user
, *pass
, *acct
;
362 user
= pass
= acct
= 0;
363 if (ruserpass(host
, &user
, &pass
, &acct
) < 0) {
369 char *myname
= getlogin();
371 if (myname
== NULL
) {
372 struct passwd
*pp
= getpwuid(getuid());
375 myname
= pp
->pw_name
;
378 (void) printf("Name (%s:%s): ", host
,
379 (myname
== NULL
) ? "" : myname
);
381 if (fgets(tmp
, sizeof (tmp
) - 1, stdin
) != NULL
)
382 tmp
[strlen(tmp
) - 1] = '\0';
385 else if (myname
!= NULL
)
390 n
= command("USER %s", user
);
394 pass
= mygetpass("Password:");
397 n
= command("PASS %s", pass
);
398 /* level may have changed */
399 if (clevel
== PROT_P
)
405 acct
= mygetpass("Account:");
406 n
= command("ACCT %s", acct
);
409 (void) fprintf(stderr
, "Login failed.\n");
412 if (!aflag
&& acct
!= NULL
)
413 (void) command("ACCT %s", acct
);
416 for (n
= 0; n
< macnum
; ++n
) {
417 if (strcmp("init", macros
[n
].mac_name
) == 0) {
418 (void) strlcpy(line
, "$init", sizeof (line
));
420 domacro(margc
, margv
);
432 (void) fflush(stdout
);
439 command(char *fmt
, ...)
444 char command_buf
[FTPBUFSIZ
];
449 (void) printf("---> ");
450 if (strncmp("PASS ", fmt
, 5) == 0)
451 (void) printf("PASS XXXX");
452 else if (strncmp("ACCT ", fmt
, 5) == 0)
453 (void) printf("ACCT XXXX");
455 (void) vfprintf(stdout
, fmt
, ap
);
457 (void) fflush(stdout
);
459 if (ctrl_out
== NULL
) {
460 perror("No control connection for command");
464 oldintr
= signal(SIGINT
, cmdabort
);
465 (void) vsnprintf(command_buf
, FTPBUFSIZ
, fmt
, ap
);
468 again
: if (secure_command(command_buf
) == 0)
472 r
= getreply(strcmp(fmt
, "QUIT") == 0);
474 if (r
== 533 && clevel
== PROT_P
) {
475 (void) fprintf(stderr
, "ENC command not supported at server; "
476 "retrying under MIC...\n");
481 if (abrtflag
&& oldintr
!= SIG_IGN
)
483 (void) signal(SIGINT
, oldintr
);
487 /* Need to save reply reponse from server for use in EPSV mode */
488 char reply_string
[BUFSIZ
];
491 getreply(int expecteof
)
494 * 'code' is the 3 digit reply code, form xyz
495 * 'dig' counts the number of digits we are along in the code
496 * 'n' is the first digit of 'code'
497 * 4yz: resource unavailable
498 * 5yz: an error occurred, failure
499 * 6yz: protected reply (is_base64 == TRUE)
500 * 631 - base 64 encoded safe message
501 * 632 - base 64 encoded private message
502 * 633 - base 64 encoded confidential message
503 * 'c' is a wide char type, for international char sets
508 int originalcode
= 0, continuation
= 0;
513 * this is the input and output buffers needed for
516 unsigned char ibuf
[FTPBUFSIZ
];
517 unsigned char obuf
[FTPBUFSIZ
];
524 oldintr
= signal(SIGINT
, cmdabort
);
529 reply_ptr
= reply_buf
;
536 reset_timer(); /* once per line */
538 while ((c
= ibuf
[0] ?
539 (wint_t)ibuf
[i
++] : fgetwc(ctrl_in
)) != '\n') {
544 if (c
== IAC
) { /* handle telnet commands */
545 switch (c
= fgetwc(ctrl_in
)) {
549 (void) fprintf(ctrl_out
, "%c%c%wc", IAC
,
551 (void) fflush(ctrl_out
);
556 (void) fprintf(ctrl_out
, "%c%c%wc", IAC
,
558 (void) fflush(ctrl_out
);
568 (void) signal(SIGINT
, oldintr
);
575 "421 Service not available, remote"
576 " server has closed connection\n");
578 (void) printf("Lost connection\n");
579 (void) fflush(stdout
);
589 if ((auth_type
!= AUTHTYPE_NONE
) && !ibuf
[0] &&
590 (is_base64
|| continuation
)) {
591 /* start storing chars in obuf */
592 if (c
!= '\r' && dig
> 4)
595 if ((auth_type
!= AUTHTYPE_NONE
) && !ibuf
[0] &&
597 (void) printf("Unauthenticated reply received "
600 *reply_ptr
++ = (char)c
;
601 if (c
!= '\r' && (verbose
> 0 ||
602 (verbose
> -1 && n
== '5' && dig
> 4))) {
604 (dig
== 1 || dig
== 5 && verbose
== 0))
605 (void) printf("%s:", hostname
);
608 } /* endif auth_type && !ibuf[0] ... */
610 if ((auth_type
!= AUTHTYPE_NONE
) && !ibuf
[0] && !is_base64
)
613 /* we are still extracting the 3 digit code */
614 if (dig
< 4 && isascii(c
) && isdigit(c
))
615 code
= code
* 10 + (c
- '0');
617 /* starting passive mode */
618 if (!pflag
&& code
== 227)
621 /* start to store characters, when dig > 4 */
622 if (dig
> 4 && pflag
== 1 && isascii(c
) && isdigit(c
))
625 if (c
!= '\r' && c
!= ')') {
626 /* the mb array is to deal with the wchar_t */
631 * space available in pasv[], accounting
634 avail
= &pasv
[sizeof (pasv
)] - pt
- 1;
637 if (len
<= 0 && avail
> 0) {
638 *pt
++ = (unsigned char)c
;
639 } else if (len
> 0 && avail
>= len
) {
640 bcopy(mb
, pt
, (size_t)len
);
647 (void) printf("\nReply too long - "
648 "closing connection\n");
650 (void) fflush(stdout
);
651 (void) signal(SIGINT
, oldintr
);
658 } /* endif pflag == 2 */
659 if (dig
== 4 && c
== '-' && !is_base64
) {
664 if (cp
< &reply_string
[sizeof (reply_string
) - 1])
669 if ((auth_type
!= AUTHTYPE_NONE
) && !ibuf
[0] && !is_base64
)
670 return (getreply(expecteof
));
672 ibuf
[0] = obuf
[i
] = '\0';
674 if (code
&& is_base64
) {
676 n
= decode_reply(ibuf
, sizeof (ibuf
), obuf
, n
, &again
);
681 if (verbose
> 0 || verbose
> -1 && n
== '5') {
683 (void) fflush(stdout
);
686 if (continuation
&& code
!= originalcode
) {
687 ibuf
[0] = obuf
[i
] = '\0';
688 if (originalcode
== 0)
695 (void) signal(SIGINT
, oldintr
);
696 if (code
== 421 || originalcode
== 421)
698 if (abrtflag
&& oldintr
!= cmdabort
&& oldintr
!= SIG_IGN
)
703 if (reply_ptr
= strstr(reply_buf
, reply_parse
)) {
704 reply_parse
= reply_ptr
+ strlen(reply_parse
);
705 if (reply_ptr
= strpbrk(reply_parse
, " \r"))
708 reply_parse
= reply_ptr
;
716 empty(struct fd_set
*mask
, int sec
, int nfds
)
721 t
.tv_sec
= (time_t)sec
;
723 return (select(nfds
, mask
, NULL
, NULL
, &t
));
732 (void) printf("\nsend aborted\n");
733 (void) fflush(stdout
);
734 longjmp(sendabort
, 1);
738 sendrequest(char *cmd
, char *local
, char *remote
, int allowpipe
)
740 FILE *fin
, *dout
= 0;
742 void (*oldintr
)(), (*oldintp
)();
743 off_t bytes
= 0, hashbytes
= HASHSIZ
;
746 * d >= 0 if there is no error
747 * -1 if there was a normal file i/o error
748 * -2 if there was a security error
752 hrtime_t start
, stop
;
756 proxtrans(cmd
, local
, remote
);
763 if (setjmp(sendabort
)) {
772 (void) signal(SIGINT
, oldintr
);
774 (void) signal(SIGPIPE
, oldintp
);
779 oldintr
= signal(SIGINT
, abortsend
);
780 if (strcmp(local
, "-") == 0)
782 else if (allowpipe
&& *local
== '|') {
783 oldintp
= signal(SIGPIPE
, SIG_IGN
);
784 fin
= mypopen(local
+ 1, "r");
787 (void) signal(SIGINT
, oldintr
);
788 (void) signal(SIGPIPE
, oldintp
);
793 closefunc
= mypclose
;
795 fin
= fopen(local
, "r");
798 (void) signal(SIGINT
, oldintr
);
804 if (fstat(fileno(fin
), &st
) < 0 ||
805 (st
.st_mode
&S_IFMT
) != S_IFREG
) {
806 (void) fprintf(stdout
,
807 "%s: not a plain file.\n", local
);
808 (void) signal(SIGINT
, oldintr
);
816 (void) signal(SIGINT
, oldintr
);
818 (void) signal(SIGPIPE
, oldintp
);
820 if (closefunc
!= NULL
)
825 if (setjmp(sendabort
))
827 if ((restart_point
> 0) &&
828 (strcmp(cmd
, "STOR") == 0 || strcmp(cmd
, "APPE") == 0)) {
829 if (fseeko(fin
, restart_point
, SEEK_SET
) < 0) {
831 if (closefunc
!= NULL
)
836 if (command("REST %lld", (longlong_t
)restart_point
)
838 if (closefunc
!= NULL
)
847 if (command("%s %s", cmd
, remote
) != PRELIM
) {
848 (void) signal(SIGINT
, oldintr
);
850 (void) signal(SIGPIPE
, oldintp
);
851 if (closefunc
!= NULL
)
860 if (command("%s", cmd
) != PRELIM
) {
861 (void) signal(SIGINT
, oldintr
);
863 (void) signal(SIGPIPE
, oldintp
);
864 if (closefunc
!= NULL
)
872 dout
= dataconn(dmode
);
876 oldintp
= signal(SIGPIPE
, SIG_IGN
);
883 while ((c
= read(fileno(fin
), buf
, FTPBUFSIZ
)) > 0) {
884 if ((d
= WRITE(fileno(dout
), buf
, c
)) < 0)
888 while (bytes
>= hashbytes
) {
890 hashbytes
+= HASHSIZ
;
892 (void) fflush(stdout
);
895 if (hash
&& bytes
> 0) {
896 if (bytes
< hashbytes
)
898 (void) putchar('\n');
899 (void) fflush(stdout
);
905 d
= secure_flush(fileno(dout
));
908 if ((d
== -1) && (errno
!= EPIPE
))
915 while ((c
= getc(fin
)) != EOF
) {
917 while (hash
&& (bytes
>= hashbytes
)) {
919 (void) fflush(stdout
);
920 hashbytes
+= HASHSIZ
;
922 if (ferror(dout
) || PUTC('\r', dout
) < 0)
927 if (PUTC(c
, dout
) < 0)
932 /* this violates rfc */
933 (void) PUTC('\0', dout
);
938 if (hash
&& bytes
> 0) {
939 if (bytes
< hashbytes
)
941 (void) putchar('\n');
942 (void) fflush(stdout
);
947 d
= ferror(dout
) ? -1 : 0;
949 d
= secure_flush(fileno(dout
));
952 if ((d
== -1) && (errno
!= EPIPE
))
959 if (closefunc
!= NULL
)
961 if (ctrl_in
!= NULL
) {
962 int dfn
= fileno(dout
);
963 int nfds
= fileno(ctrl_in
);
967 * There could be data not yet written to dout,
968 * in the stdio buffer; so, before a shutdown()
969 * on further sends, do fflush(dout)
973 /* sending over; shutdown sending on dfn */
974 (void) shutdown(dfn
, SHUT_WR
);
978 nfds
= MAX(dfn
, nfds
);
981 * Wait for remote end to either close data socket
982 * or ack that we've closed our end; it doesn't
983 * matter which happens first.
985 (void) select(nfds
+ 1, &mask
, NULL
, NULL
, NULL
);
987 (void) fclose(dout
); data
= -1;
990 (void) signal(SIGINT
, oldintr
);
992 (void) signal(SIGPIPE
, oldintp
);
995 * Only print the transfer successful message if the code returned
996 * from remote is 226 or 250. All other codes are error codes.
998 if ((bytes
> 0) && verbose
&& ((code
== 226) || (code
== 250)))
999 ptransfer("sent", bytes
, start
, stop
, local
, remote
);
1001 (void) printf("Lost connection\n");
1004 (void) signal(SIGINT
, oldintr
);
1006 (void) signal(SIGPIPE
, oldintp
);
1016 (void) fclose(dout
);
1021 if (closefunc
!= NULL
&& fin
!= NULL
)
1025 * Only print the transfer successful message if the code returned
1026 * from remote is 226 or 250. All other codes are error codes.
1028 if ((bytes
> 0) && verbose
&& ((code
== 226) || (code
== 250)))
1029 ptransfer("sent", bytes
, start
, stop
, local
, remote
);
1031 (void) printf("Lost connection\n");
1041 (void) printf("\n");
1042 (void) fflush(stdout
);
1043 longjmp(recvabort
, 1);
1047 recvrequest(char *cmd
, char *local
, char *remote
, char *mode
, int allowpipe
)
1049 FILE *fout
, *din
= 0;
1051 void (*oldintr
)(), (*oldintp
)();
1052 int oldverbose
, oldtype
= 0, tcrflag
, nfnd
;
1054 off_t bytes
= 0, hashbytes
= HASHSIZ
;
1057 hrtime_t start
, stop
;
1063 retrcmd
= (strcmp(cmd
, "RETR") == 0);
1064 if (proxy
&& retrcmd
) {
1065 proxtrans(cmd
, local
, remote
);
1071 tcrflag
= !crflag
&& retrcmd
;
1072 if (setjmp(recvabort
)) {
1081 (void) signal(SIGINT
, oldintr
);
1085 oldintr
= signal(SIGINT
, abortrecv
);
1086 if (local
!= NULL
&&
1087 strcmp(local
, "-") != 0 &&
1088 (*local
!= '|' || !allowpipe
)) {
1089 if (access(local
, W_OK
) < 0) {
1090 char *dir
= rindex(local
, '/');
1091 int file_errno
= errno
;
1093 if (file_errno
!= ENOENT
&& file_errno
!= EACCES
) {
1095 (void) signal(SIGINT
, oldintr
);
1099 if ((dir
!= NULL
) && (dir
!= local
))
1102 d
= access("/", W_OK
);
1104 d
= access(dir
? local
: ".", W_OK
);
1105 if ((dir
!= NULL
) && (dir
!= local
))
1109 (void) signal(SIGINT
, oldintr
);
1113 if (!runique
&& file_errno
== EACCES
) {
1116 (void) signal(SIGINT
, oldintr
);
1120 if (runique
&& file_errno
== EACCES
&&
1121 (local
= gunique(local
)) == NULL
) {
1122 (void) signal(SIGINT
, oldintr
);
1126 } else if (runique
&& (local
= gunique(local
)) == NULL
) {
1127 (void) signal(SIGINT
, oldintr
);
1133 (void) signal(SIGINT
, oldintr
);
1137 if (setjmp(recvabort
))
1139 if (!retrcmd
&& type
!= TYPE_A
) {
1141 oldverbose
= verbose
;
1145 verbose
= oldverbose
;
1147 if ((restart_point
> 0) && retrcmd
&&
1148 command("REST %lld", (longlong_t
)restart_point
) != CONTINUE
) {
1152 if (command("%s %s", cmd
, remote
) != PRELIM
) {
1153 (void) signal(SIGINT
, oldintr
);
1168 verbose
= oldverbose
;
1173 if (command("%s", cmd
) != PRELIM
) {
1174 (void) signal(SIGINT
, oldintr
);
1189 verbose
= oldverbose
;
1194 din
= dataconn("r");
1198 if (local
== NULL
) {
1200 } else if (strcmp(local
, "-") == 0) {
1202 } else if (allowpipe
&& *local
== '|') {
1203 oldintp
= signal(SIGPIPE
, SIG_IGN
);
1204 fout
= mypopen(local
+ 1, "w");
1209 closefunc
= mypclose
;
1211 fout
= fopen(local
, mode
);
1218 start
= gethrtime();
1224 if ((restart_point
> 0) && retrcmd
&&
1225 lseek(fileno(fout
), restart_point
, SEEK_SET
) < 0) {
1231 while ((c
= timedread(infd
, buf
, FTPBUFSIZ
, timeout
)) > 0) {
1232 for (n
= 0; n
< c
; n
+= d
) {
1233 d
= write(fileno(fout
), &buf
[n
], c
- n
);
1239 while (bytes
>= hashbytes
) {
1240 (void) putchar('#');
1241 hashbytes
+= HASHSIZ
;
1243 (void) fflush(stdout
);
1246 if (hash
&& bytes
> 0) {
1247 if (bytes
< hashbytes
)
1248 (void) putchar('#');
1249 (void) putchar('\n');
1250 (void) fflush(stdout
);
1256 if ((d
< 0) || ((c
== 0) && (fsync(fileno(fout
)) == -1))) {
1264 if ((restart_point
> 0) && retrcmd
) {
1268 if (fseek(fout
, 0L, SEEK_SET
) < 0) {
1272 while (i
++ < restart_point
) {
1273 if ((c
= getc(fout
)) == EOF
) {
1277 (void) fprintf(stderr
,
1278 "%s: Unexpected end of file\n",
1285 if (fseeko(fout
, 0L, SEEK_CUR
) < 0) {
1290 fdio_setbuf(buf
, FTPBUFSIZ
);
1292 while ((c
= fdio_getc(infd
)) != EOF
) {
1294 while (hash
&& (bytes
>= hashbytes
)) {
1295 (void) putchar('#');
1296 (void) fflush(stdout
);
1297 hashbytes
+= HASHSIZ
;
1301 if ((c
= fdio_getc(infd
)) != '\n' || tcrflag
) {
1304 if (putc('\r', fout
) == EOF
)
1305 goto writer_ascii_err
;
1316 if (putc(c
, fout
) == EOF
)
1317 goto writer_ascii_err
;
1321 if (hash
&& bytes
> 0) {
1322 if (bytes
< hashbytes
)
1323 (void) putchar('#');
1324 (void) putchar('\n');
1325 (void) fflush(stdout
);
1327 if (fdio_error(infd
)) {
1331 if ((fflush(fout
) == EOF
) || ferror(fout
) ||
1332 (fsync(fileno(fout
)) == -1)) {
1340 if (closefunc
!= NULL
)
1342 (void) signal(SIGINT
, oldintr
);
1344 (void) signal(SIGPIPE
, oldintp
);
1345 (void) fclose(din
); data
= -1;
1348 if (bytes
> 0 && verbose
&& !errflg
)
1349 ptransfer("received", bytes
, start
, stop
, local
, remote
);
1351 (void) printf("Lost connection\n");
1366 verbose
= oldverbose
;
1371 /* abort using RFC959 recommended IP, SYNC sequence */
1375 (void) signal(SIGPIPE
, oldintp
);
1376 (void) signal(SIGINT
, SIG_IGN
);
1379 (void) signal(SIGINT
, oldintr
);
1383 (void) fprintf(ctrl_out
, "%c%c", IAC
, IP
);
1384 (void) fflush(ctrl_out
);
1387 * send IAC in urgent mode instead of DM because UNIX places oob
1388 * mark after urgent byte rather than before as now is protocol
1390 if (send(fileno(ctrl_out
), &msg
, 1, MSG_OOB
) != 1) {
1393 (void) fprintf(ctrl_out
, "%cABOR\r\n", DM
);
1394 (void) fflush(ctrl_out
);
1395 nfds
= fileno(ctrl_in
) + 1;
1397 FD_SET(fileno(ctrl_in
), &mask
);
1399 FD_SET(fileno(din
), &mask
);
1400 nfds
= MAX(fileno(din
) + 1, nfds
);
1402 if ((nfnd
= empty(&mask
, 10, nfds
)) <= 0) {
1409 if (din
&& FD_ISSET(fileno(din
), &mask
)) {
1412 } while ((c
= read(fileno(din
), buf
, FTPBUFSIZ
)) > 0);
1414 if ((c
= getreply(0)) == ERROR
&& code
== 552) {
1415 /* needed for nic style abort */
1436 verbose
= oldverbose
;
1444 if (closefunc
!= NULL
&& fout
!= NULL
)
1450 if (bytes
> 0 && verbose
)
1451 ptransfer("received", bytes
, start
, stop
, local
, remote
);
1453 (void) printf("Lost connection\n");
1454 (void) signal(SIGINT
, oldintr
);
1458 * Need to start a listen on the data channel
1459 * before we send the command, otherwise the
1460 * server's connect may fail.
1466 unsigned char *p
, *a
;
1467 int result
, tmpno
= 0;
1474 pasv_refused
= B_FALSE
;
1476 data
= socket(AF_INET6
, SOCK_STREAM
, 0);
1481 if (timeout
&& setsockopt(data
, IPPROTO_TCP
,
1482 TCP_ABORT_THRESHOLD
, (char *)&timeoutms
,
1483 sizeof (timeoutms
)) < 0 && debug
)
1484 perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)");
1485 if ((options
& SO_DEBUG
) &&
1486 setsockopt(data
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
1488 perror("setsockopt (ignored)");
1490 * Use the system wide default send and receive buffer sizes
1491 * unless one has been specified.
1493 if (tcpwindowsize
) {
1494 if (setsockopt(data
, SOL_SOCKET
, SO_SNDBUF
,
1495 (char *)&tcpwindowsize
, sizeof (tcpwindowsize
)) < 0)
1496 perror("ftp: setsockopt (SO_SNDBUF - ignored)");
1497 if (setsockopt(data
, SOL_SOCKET
, SO_RCVBUF
,
1498 (char *)&tcpwindowsize
, sizeof (tcpwindowsize
)) < 0)
1499 perror("ftp: setsockopt (SO_RCVBUF - ignored)");
1502 data_addr
= remctladdr
;
1504 if (ipv6rem
== B_TRUE
) {
1505 if (command("EPSV") != COMPLETE
) {
1506 (void) fprintf(stderr
,
1507 "Passive mode refused. Try EPRT\n");
1508 pasv_refused
= B_TRUE
;
1513 * Get the data port from reply string from the
1514 * server. The format of the reply string is:
1515 * 229 Entering Extended Passive Mode (|||port|)
1516 * where | is the delimiter being used.
1518 c
= strchr(reply_string
, '(');
1519 c2
= strchr(reply_string
, ')');
1520 if (c
== NULL
|| c2
== NULL
) {
1521 (void) fprintf(stderr
, "Extended passive mode"
1522 "parsing failure.\n");
1526 /* Delimiter is the next char in the reply string */
1528 while (*c
== delm
) {
1530 (void) fprintf(stderr
,
1531 "Extended passive mode"
1532 "parsing failure.\n");
1536 /* assign the port for data connection */
1537 ports
= (in_port_t
)atoi(c
);
1538 data_addr
.sin6_port
= htons(ports
);
1540 int a1
, a2
, a3
, a4
, p1
, p2
;
1542 if (command("PASV") != COMPLETE
) {
1543 (void) fprintf(stderr
,
1544 "Passive mode refused. Try PORT\n");
1545 pasv_refused
= B_TRUE
;
1550 * Get the data port from reply string from the
1551 * server. The format of the reply string is:
1552 * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)
1554 if (sscanf(pasv
, "%d,%d,%d,%d,%d,%d",
1555 &a1
, &a2
, &a3
, &a4
, &p1
, &p2
) != 6) {
1556 (void) fprintf(stderr
,
1557 "Passive mode parsing failure.\n");
1561 * Set the supplied address and port in an
1562 * IPv4-mapped IPv6 address.
1564 a
= (unsigned char *)&data_addr
.sin6_addr
+
1565 sizeof (struct in6_addr
) -
1566 sizeof (struct in_addr
);
1567 #define UC(b) ((b)&0xff)
1572 p
= (unsigned char *)&data_addr
.sin6_port
;
1577 if (connect(data
, (struct sockaddr
*)&data_addr
,
1578 sizeof (data_addr
)) < 0) {
1586 data_addr
= myctladdr
;
1588 data_addr
.sin6_port
= 0; /* let system pick one */
1592 data
= socket(AF_INET6
, SOCK_STREAM
, 0);
1594 perror("ftp: socket");
1600 if (setsockopt(data
, SOL_SOCKET
, SO_REUSEADDR
,
1601 (char *)&on
, sizeof (on
)) < 0) {
1602 perror("ftp: setsockopt (SO_REUSEADDR)");
1606 (struct sockaddr
*)&data_addr
, sizeof (data_addr
)) < 0) {
1607 perror("ftp: bind");
1610 if (timeout
&& setsockopt(data
, IPPROTO_TCP
, TCP_ABORT_THRESHOLD
,
1611 (char *)&timeoutms
, sizeof (timeoutms
)) < 0 && debug
)
1612 perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)");
1613 if (options
& SO_DEBUG
&&
1614 setsockopt(data
, SOL_SOCKET
, SO_DEBUG
,
1615 (char *)&on
, sizeof (on
)) < 0)
1616 perror("ftp: setsockopt (SO_DEBUG - ignored)");
1618 * Use the system wide default send and receive buffer sizes unless
1619 * one has been specified.
1621 if (tcpwindowsize
) {
1622 if (setsockopt(data
, SOL_SOCKET
, SO_SNDBUF
,
1623 (char *)&tcpwindowsize
, sizeof (tcpwindowsize
)) < 0)
1624 perror("ftp: setsockopt (SO_SNDBUF - ignored)");
1625 if (setsockopt(data
, SOL_SOCKET
, SO_RCVBUF
,
1626 (char *)&tcpwindowsize
, sizeof (tcpwindowsize
)) < 0)
1627 perror("ftp: setsockopt (SO_RCVBUF - ignored)");
1629 len
= sizeof (data_addr
);
1630 if (getsockname(data
, (struct sockaddr
*)&data_addr
, &len
) < 0) {
1631 perror("ftp: getsockname");
1635 v4_addr
= IN6_IS_ADDR_V4MAPPED(&data_addr
.sin6_addr
);
1636 if (listen(data
, 1) < 0)
1637 perror("ftp: listen");
1640 a
= (unsigned char *)&data_addr
.sin6_addr
;
1641 p
= (unsigned char *)&data_addr
.sin6_port
;
1644 command("PORT %d,%d,%d,%d,%d,%d",
1645 UC(a
[12]), UC(a
[13]), UC(a
[14]), UC(a
[15]),
1646 UC(p
[0]), UC(p
[1]));
1648 char hname
[INET6_ADDRSTRLEN
];
1650 result
= COMPLETE
+ 1;
1652 * if on previous try to server, it was
1653 * determined that the server doesn't support
1654 * EPRT, don't bother trying again. Just try
1657 if (eport_supported
== B_TRUE
) {
1658 if (inet_ntop(AF_INET6
, &data_addr
.sin6_addr
,
1659 hname
, sizeof (hname
)) != NULL
) {
1660 result
= command("EPRT |%d|%s|%d|", 2,
1661 hname
, htons(data_addr
.sin6_port
));
1662 if (result
!= COMPLETE
)
1663 eport_supported
= B_FALSE
;
1667 if (result
!= COMPLETE
) {
1669 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1671 UC(a
[0]), UC(a
[1]), UC(a
[2]), UC(a
[3]),
1672 UC(a
[4]), UC(a
[5]), UC(a
[6]), UC(a
[7]),
1673 UC(a
[8]), UC(a
[9]), UC(a
[10]), UC(a
[11]),
1674 UC(a
[12]), UC(a
[13]), UC(a
[14]), UC(a
[15]),
1675 2, UC(p
[0]), UC(p
[1]));
1679 if (result
== ERROR
&& sendport
== -1) {
1684 return (result
!= COMPLETE
);
1690 (void) close(data
), data
= -1;
1697 dataconn(char *mode
)
1699 struct sockaddr_in6 from
;
1701 socklen_t fromlen
= sizeof (from
);
1704 if (passivemode
&& !pasv_refused
)
1705 return (fdopen(data
, mode
));
1707 s
= accept(data
, (struct sockaddr
*)&from
, &fromlen
);
1709 perror("ftp: accept");
1710 (void) close(data
), data
= -1;
1715 return (fdopen(data
, mode
));
1719 ptransfer(char *direction
, off_t bytes
, hrtime_t t0
,
1720 hrtime_t t1
, char *local
, char *remote
)
1722 hrtime_t td
; /* nanoseconds in a 64 bit int */
1726 s
= (double)td
/ 1000000000.0; /* seconds */
1727 bs
= (double)bytes
/ NONZERO(s
);
1728 if (local
&& *local
!= '-')
1729 (void) printf("local: %s ", local
);
1731 (void) printf("remote: %s\n", remote
);
1732 (void) printf("%lld bytes %s in %.2g seconds (%.2f Kbytes/s)\n",
1733 (longlong_t
)bytes
, direction
, s
, bs
/ 1024.0);
1747 static struct comvars
{
1749 char name
[MAXHOSTNAMELEN
];
1750 struct sockaddr_in6 mctl
;
1751 struct sockaddr_in6 hctl
;
1763 char mi
[MAXPATHLEN
];
1764 char mo
[MAXPATHLEN
];
1768 } proxstruct
, tmpstruct
;
1769 struct comvars
*ip
, *op
;
1772 oldintr
= signal(SIGINT
, psabort
);
1786 ip
->connect
= connected
;
1787 connected
= op
->connect
;
1789 (void) strlcpy(ip
->name
, hostname
, sizeof (ip
->name
));
1792 hostname
= op
->name
;
1793 ip
->hctl
= remctladdr
;
1794 remctladdr
= op
->hctl
;
1795 ip
->mctl
= myctladdr
;
1796 myctladdr
= op
->mctl
;
1807 ip
->sunqe
= sunique
;
1808 sunique
= op
->sunqe
;
1809 ip
->runqe
= runique
;
1810 runique
= op
->runqe
;
1815 (void) strlcpy(ip
->nti
, ntin
, sizeof (ip
->nti
));
1816 (void) strlcpy(ntin
, op
->nti
, sizeof (ntin
));
1817 (void) strlcpy(ip
->nto
, ntout
, sizeof (ip
->nto
));
1818 (void) strlcpy(ntout
, op
->nto
, sizeof (ntout
));
1819 ip
->mapflg
= mapflag
;
1820 mapflag
= op
->mapflg
;
1821 (void) strlcpy(ip
->mi
, mapin
, sizeof (ip
->mi
));
1822 (void) strlcpy(mapin
, op
->mi
, sizeof (mapin
));
1823 (void) strlcpy(ip
->mo
, mapout
, sizeof (ip
->mo
));
1824 (void) strlcpy(mapout
, op
->mo
, sizeof (mapout
));
1826 ip
->authtype
= auth_type
;
1827 auth_type
= op
->authtype
;
1837 (void) signal(SIGINT
, oldintr
);
1848 (void) printf("\n");
1849 (void) fflush(stdout
);
1853 longjmp(ptabort
, 1);
1857 proxtrans(char *cmd
, char *local
, char *remote
)
1860 int tmptype
, oldtype
= 0, secndflag
= 0, nfnd
;
1861 extern jmp_buf ptabort
;
1864 int ipv4_addr
= IN6_IS_ADDR_V4MAPPED(&remctladdr
.sin6_addr
);
1866 if (strcmp(cmd
, "RETR"))
1869 cmd2
= runique
? "STOU" : "STOR";
1870 if (command(ipv4_addr
? "PASV" : "EPSV") != COMPLETE
) {
1872 "proxy server does not support third part transfers.\n");
1878 (void) printf("No primary connection\n");
1883 if (type
!= tmptype
) {
1900 if (command(ipv4_addr
? "PORT %s" : "EPRT %s", pasv
) != COMPLETE
) {
1920 if (setjmp(ptabort
))
1922 oldintr
= signal(SIGINT
, (void (*)())abortpt
);
1923 if (command("%s %s", cmd
, remote
) != PRELIM
) {
1924 (void) signal(SIGINT
, oldintr
);
1947 if (command("%s %s", cmd2
, local
) != PRELIM
)
1953 (void) signal(SIGINT
, oldintr
);
1972 (void) printf("local: %s remote: %s\n", local
, remote
);
1975 (void) signal(SIGINT
, SIG_IGN
);
1977 if (strcmp(cmd
, "RETR") && !proxy
)
1979 else if ((strcmp(cmd
, "RETR") == 0) && proxy
)
1981 if (!cpend
&& !secndflag
) { /* only here if cmd = "STOR" (proxy=1) */
1982 if (command("%s %s", cmd2
, local
) != PRELIM
) {
2003 (void) fprintf(ctrl_out
, "%c%c", IAC
, IP
);
2004 (void) fflush(ctrl_out
);
2006 *(msg
+1) = (char)DM
;
2007 if (send(fileno(ctrl_out
), msg
, 2, MSG_OOB
)
2010 (void) fprintf(ctrl_out
, "ABOR\r\n");
2011 (void) fflush(ctrl_out
);
2013 FD_SET(fileno(ctrl_in
), &mask
);
2014 if ((nfnd
= empty(&mask
, 10,
2015 fileno(ctrl_in
) + 1)) <= 0) {
2030 (void) signal(SIGINT
, oldintr
);
2036 (void) fprintf(ctrl_out
, "%c%c", IAC
, IP
);
2037 (void) fflush(ctrl_out
);
2039 *(msg
+1) = (char)DM
;
2040 if (send(fileno(ctrl_out
), msg
, 2, MSG_OOB
) != 2)
2042 (void) fprintf(ctrl_out
, "ABOR\r\n");
2043 (void) fflush(ctrl_out
);
2045 FD_SET(fileno(ctrl_in
), &mask
);
2046 if ((nfnd
= empty(&mask
, 10, fileno(ctrl_in
) + 1)) <= 0) {
2058 if (!cpend
&& !secndflag
) { /* only if cmd = "RETR" (proxy=1) */
2059 if (command("%s %s", cmd2
, local
) != PRELIM
) {
2080 (void) fprintf(ctrl_out
, "%c%c", IAC
, IP
);
2081 (void) fflush(ctrl_out
);
2083 *(msg
+1) = (char)DM
;
2084 if (send(fileno(ctrl_out
), msg
, 2, MSG_OOB
)
2087 (void) fprintf(ctrl_out
, "ABOR\r\n");
2088 (void) fflush(ctrl_out
);
2090 FD_SET(fileno(ctrl_in
), &mask
);
2091 if ((nfnd
= empty(&mask
, 10,
2092 fileno(ctrl_in
) + 1)) <= 0) {
2106 (void) signal(SIGINT
, oldintr
);
2113 (void) fprintf(ctrl_out
, "%c%c", IAC
, IP
);
2114 (void) fflush(ctrl_out
);
2116 *(msg
+1) = (char)DM
;
2117 if (send(fileno(ctrl_out
), msg
, 2, MSG_OOB
) != 2)
2119 (void) fprintf(ctrl_out
, "ABOR\r\n");
2120 (void) fflush(ctrl_out
);
2122 FD_SET(fileno(ctrl_in
), &mask
);
2123 if ((nfnd
= empty(&mask
, 10, fileno(ctrl_in
) + 1)) <= 0) {
2137 FD_SET(fileno(ctrl_in
), &mask
);
2138 if ((nfnd
= empty(&mask
, 10, fileno(ctrl_in
) + 1)) <= 0) {
2170 (void) signal(SIGINT
, oldintr
);
2175 reset(int argc
, char *argv
[])
2182 FD_SET(fileno(ctrl_in
), &mask
);
2183 if ((nfnd
= empty(&mask
, 0, fileno(ctrl_in
) + 1)) < 0) {
2187 } else if (nfnd
> 0) {
2194 gunique(char *local
)
2196 static char new[MAXPATHLEN
];
2197 char *cp
= rindex(local
, '/');
2203 d
= access(cp
? local
: ".", 2);
2210 if (strlcpy(new, local
, sizeof (new)) >= sizeof (new))
2211 (void) printf("gunique: too long: local %s, %d, new %d\n",
2212 local
, strlen(local
), sizeof (new));
2214 cp
= new + strlen(new);
2217 if (++count
== 100) {
2219 "runique: can't find unique file name.\n");
2228 if ((d
= access(new, 0)) < 0)
2232 else if (*(cp
- 2) == '.')
2235 *(cp
- 2) = *(cp
- 2) + 1;
2243 * This is a wrap-around function for inet_ntop(). In case the af is AF_INET6
2244 * and the address pointed by src is a IPv4-mapped IPv6 address, it
2245 * returns printable IPv4 address, not IPv4-mapped IPv6 address. In other cases
2246 * it behaves just like inet_ntop().
2249 inet_ntop_native(int af
, const void *src
, char *dst
, size_t size
)
2251 struct in_addr src4
;
2253 struct sockaddr_in
*sin
;
2254 struct sockaddr_in6
*sin6
;
2256 if (af
== AF_INET6
) {
2257 sin6
= (struct sockaddr_in6
*)src
;
2258 if (IN6_IS_ADDR_V4MAPPED(&sin6
->sin6_addr
)) {
2259 IN6_V4MAPPED_TO_INADDR(&sin6
->sin6_addr
, &src4
);
2260 result
= inet_ntop(AF_INET
, &src4
, dst
, size
);
2262 result
= inet_ntop(AF_INET6
, &sin6
->sin6_addr
,
2266 sin
= (struct sockaddr_in
*)src
;
2267 result
= inet_ntop(af
, &sin
->sin_addr
, dst
, size
);
2274 secure_command(char *cmd
)
2276 unsigned char *in
= NULL
, *out
= NULL
;
2280 if ((auth_type
!= AUTHTYPE_NONE
) && clevel
!= PROT_C
) {
2281 gss_buffer_desc in_buf
, out_buf
;
2282 OM_uint32 maj_stat
, min_stat
;
2284 /* secure_command (based on level) */
2285 if (auth_type
== AUTHTYPE_GSSAPI
) {
2286 OM_uint32 expire_time
;
2288 /* clevel = PROT_P; */
2290 in_buf
.length
= strlen(cmd
) + 1;
2292 maj_stat
= gss_context_time(&min_stat
, gcontext
,
2294 if (GSS_ERROR(maj_stat
)) {
2295 user_gss_error(maj_stat
, min_stat
,
2296 "gss context has expired");
2297 fatal("Your gss credentials have expired. "
2300 maj_stat
= gss_seal(&min_stat
, gcontext
,
2301 (clevel
== PROT_P
), /* private */
2303 &in_buf
, &conf_state
,
2305 if (maj_stat
!= GSS_S_COMPLETE
) {
2306 /* generally need to deal */
2307 user_gss_error(maj_stat
, min_stat
,
2308 (clevel
== PROT_P
) ?
2309 "gss_seal ENC didn't complete":
2310 "gss_seal MIC didn't complete");
2311 } else if ((clevel
== PROT_P
) && !conf_state
) {
2312 (void) fprintf(stderr
,
2313 "GSSAPI didn't encrypt message");
2314 out
= out_buf
.value
;
2317 (void) fprintf(stderr
,
2318 "sealed (%s) %d bytes\n",
2319 clevel
== PROT_P
? "ENC" : "MIC",
2322 out
= out_buf
.value
;
2325 /* Other auth types go here ... */
2326 inlen
= ((4 * out_buf
.length
) / 3) + 4;
2327 in
= (uchar_t
*)malloc(inlen
);
2329 gss_release_buffer(&min_stat
, &out_buf
);
2330 fatal("Memory error allocating space for response.");
2332 length
= out_buf
.length
;
2333 if (auth_error
= radix_encode(out
, in
, inlen
, &length
, 0)) {
2334 (void) fprintf(stderr
,
2335 "Couldn't base 64 encode command (%s)\n",
2336 radix_error(auth_error
));
2338 gss_release_buffer(&min_stat
, &out_buf
);
2342 (void) fprintf(ctrl_out
, "%s %s",
2343 clevel
== PROT_P
? "ENC" : "MIC", in
);
2346 gss_release_buffer(&min_stat
, &out_buf
);
2349 (void) fprintf(stderr
,
2350 "secure_command(%s)\nencoding %d bytes %s %s\n",
2352 (clevel
== PROT_P
) ? "ENC" : "MIC", in
);
2355 * auth_type = AUTHTYPE_NONE or
2356 * command channel is not protected
2358 fputs(cmd
, ctrl_out
);
2361 (void) fprintf(ctrl_out
, "\r\n");
2362 (void) fflush(ctrl_out
);
2366 unsigned int maxbuf
;
2367 unsigned char *ucbuf
;
2370 setpbsz(unsigned int size
)
2372 unsigned int actualbuf
;
2378 while ((ucbuf
= (unsigned char *)malloc(actualbuf
)) == NULL
) {
2382 perror("Error while trying to malloc PROT buffer:");
2386 oldverbose
= verbose
;
2388 reply_parse
= "PBSZ=";
2389 if (command("PBSZ %u", actualbuf
) != COMPLETE
)
2390 fatal("Cannot set PROT buffer size");
2392 if ((maxbuf
= (unsigned int) atol(reply_parse
)) > actualbuf
)
2397 verbose
= oldverbose
;
2401 * Do the base 64 decoding of the raw input buffer, b64_buf.
2402 * Also do the verification and decryption, if required.
2403 * retval contains the current error code number
2406 * (RFC 2228: error returns are 3 digit numbers of the form 5xy)
2407 * 5 if an error occurred
2410 decode_reply(uchar_t
*plain_buf
,
2421 if (!b64_buf
[0]) /* if there is no string, no problem */
2424 if ((auth_type
== AUTHTYPE_NONE
)) {
2425 (void) printf("Cannot decode reply:\n%d %s\n", code
, b64_buf
);
2431 case 631: /* 'safe' */
2435 case 632: /* 'private' */
2438 case 633: /* 'confidential' */
2442 (void) printf("Unknown reply: %d %s\n", code
, b64_buf
);
2446 /* decode the base64 encoded message */
2447 auth_error
= radix_encode(b64_buf
, plain_buf
, ilen
, &len
, 1);
2450 (void) printf("Can't base 64 decode reply %d (%s)\n\"%s\"\n",
2451 code
, radix_error(auth_error
), b64_buf
);
2455 if (auth_type
== AUTHTYPE_GSSAPI
) {
2456 gss_buffer_desc xmit_buf
, msg_buf
;
2457 OM_uint32 maj_stat
, min_stat
;
2458 int conf_state
= safe
;
2459 xmit_buf
.value
= plain_buf
;
2460 xmit_buf
.length
= len
;
2462 /* decrypt/verify the message */
2463 maj_stat
= gss_unseal(&min_stat
, gcontext
,
2464 &xmit_buf
, &msg_buf
, &conf_state
, NULL
);
2465 if (maj_stat
!= GSS_S_COMPLETE
) {
2466 user_gss_error(maj_stat
, min_stat
,
2467 "failed unsealing reply");
2470 if (msg_buf
.length
< ilen
- 2 - 1) {
2471 memcpy(plain_buf
, msg_buf
.value
, msg_buf
.length
);
2472 strcpy((char *)&plain_buf
[msg_buf
.length
], "\r\n");
2473 gss_release_buffer(&min_stat
, &msg_buf
);
2476 user_gss_error(maj_stat
, min_stat
,
2477 "reply was too long");
2480 } /* end if GSSAPI */
2482 /* Other auth types go here... */