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
40 #pragma ident "%Z%%M% %I% %E% SMI"
43 #include <arpa/nameser.h>
44 #include <sys/types.h>
49 * -1 error, errorno is set
50 * -2 security error (secure_write() only)
52 #define PUTC(x, y) secure_putc(x, y)
53 #define READ(x, y, z) secure_read(x, y, z)
54 #define WRITE(x, y, z) secure_write(x, y, z)
56 static struct sockaddr_in6 data_addr
;
58 static int abrtflag
= 0;
59 static int ptflag
= 0;
61 static jmp_buf sendabort
;
62 static jmp_buf recvabort
;
63 static jmp_buf ptabort
;
65 static boolean_t pasv_refused
;
66 boolean_t eport_supported
= B_TRUE
;
68 * For IPv6 addresses, EPSV will be the default (rather than EPRT/LPRT).
69 * The EPSV/ERPT ftp protocols are specified in RFC 2428.
71 * Perform EPSV if passivemode is set and ipv6rem is TRUE.
73 static boolean_t ipv6rem
;
74 int use_eprt
= 0; /* Testing option that specifies EPRT by default */
75 FILE *ctrl_in
, *ctrl_out
;
77 static void abortsend(int sig
);
78 static void abortpt(int sig
);
79 static void proxtrans(char *cmd
, char *local
, char *remote
);
80 static void cmdabort(int sig
);
81 static int empty(struct fd_set
*mask
, int sec
, int nfds
);
82 static void abortrecv(int sig
);
83 static int initconn(void);
84 static FILE *dataconn(char *mode
);
85 static void ptransfer(char *direction
, off_t bytes
, hrtime_t t0
,
86 hrtime_t t1
, char *local
, char *remote
);
87 static void psabort(int sig
);
88 static char *gunique(char *local
);
89 static const char *inet_ntop_native(int af
, const void *src
, char *dst
,
91 static ssize_t
timedread(int fd
, void *buf
, size_t maxlen
, int timeout
);
93 static int secure_command(char *);
94 static int decode_reply(uchar_t
*, int, uchar_t
*, int, boolean_t
*);
96 static ssize_t bufcnt
; /* number of bytes in buf[] */
97 static char *bufp
; /* next character in buf */
98 static int buferr
; /* last errno */
99 static size_t bufsize
;
101 static void fdio_setbuf(char *buffer
, size_t bufsize
);
102 static int fdio_fillbuf(int fd
);
103 static int fdio_error(int fd
);
104 #define fdio_getc(fd) (--bufcnt < 0 ? fdio_fillbuf((fd)) : \
105 ((unsigned char)*bufp++))
107 #define MAX(a, b) ((a) > (b) ? (a) : (b))
108 #define NONZERO(x) ((x) == 0 ? 1 : (x))
111 fdio_setbuf(char *buffer
, size_t maxsize
)
123 bufcnt
= timedread(fd
, buf
, bufsize
, timeout
);
130 return ((unsigned char)*bufp
++);
134 * fdio_error - used on a file descriptor instead of ferror()
145 * timedread - read buffer (like "read"), but with timeout (in seconds)
149 timedread(int fd
, void *buf
, size_t size
, int timeout
)
156 return (READ(fd
, buf
, size
));
158 tv
.tv_sec
= (time_t)timeout
;
164 err
= select(fd
+ 1, &mask
, NULL
, NULL
, &tv
);
170 return (READ(fd
, buf
, size
));
175 hookup(char *host
, char *service
)
177 struct addrinfo hints
, *ai
= NULL
, *ai_head
;
180 static char hostnamebuf
[80];
181 struct in6_addr ipv6addr
;
182 char abuf
[INET6_ADDRSTRLEN
];
187 * There appears to be a bug in getaddrinfo() where, if the
188 * ai_family is set to AF_INET6, and the host is a v4-only
189 * host, getaddrinfo() returns an error instead of returning
190 * an v4-mapped ipv6 address. Therefore the ai_family is
191 * set to AF_UNSPEC and any returned v4 addresses are
192 * explicitly mapped within ftp.
194 bzero((char *)&remctladdr
, sizeof (remctladdr
));
195 bzero((char *)&hints
, sizeof (hints
));
196 hints
.ai_flags
= AI_CANONNAME
;
197 hints
.ai_family
= AF_UNSPEC
;
198 hints
.ai_socktype
= SOCK_STREAM
;
200 error_num
= getaddrinfo(host
, service
, &hints
, &ai
);
201 if (error_num
!= 0) {
202 if (error_num
== EAI_AGAIN
) {
204 "%s: unknown host or invalid literal address "
205 "(try again later)\n", host
);
208 "%s: unknown host or invalid literal address\n",
218 * If ai_canonname is a IPv4-mapped IPv6 literal, we'll convert it to
219 * IPv4 literal address.
221 if (ai
->ai_canonname
!= NULL
&&
222 (inet_pton(AF_INET6
, ai
->ai_canonname
, &ipv6addr
) > 0) &&
223 IN6_IS_ADDR_V4MAPPED(&ipv6addr
)) {
225 hostnamebuf
[0] = '\0';
226 IN6_V4MAPPED_TO_INADDR(&ipv6addr
, &src4
);
227 (void) inet_ntop(AF_INET
, &src4
, hostnamebuf
,
228 sizeof (hostnamebuf
));
231 * It can even be the case that the "host" supplied by the user
232 * can be a IPv4-mapped IPv6 literal. So, let's fix that too.
234 if ((inet_pton(AF_INET6
, host
, &ipv6addr
) > 0) &&
235 IN6_IS_ADDR_V4MAPPED(&ipv6addr
) &&
236 strlen(hostnamebuf
) <= strlen(host
)) {
237 (void) strlcpy(host
, hostnamebuf
, strlen(host
) + 1);
241 (void) strlcpy(hostnamebuf
,
242 (ai
->ai_canonname
? ai
->ai_canonname
: host
),
243 sizeof (hostnamebuf
));
246 hostname
= hostnamebuf
;
250 bcopy(ai
->ai_addr
, &remctladdr
, ai
->ai_addrlen
);
251 if (ai
->ai_addr
->sa_family
== AF_INET
) {
252 IN6_INADDR_TO_V4MAPPED(
253 &(((struct sockaddr_in
*)ai
->ai_addr
)->sin_addr
),
254 &remctladdr
.sin6_addr
);
255 remctladdr
.sin6_family
= AF_INET6
;
258 s
= socket(AF_INET6
, SOCK_STREAM
, 0);
260 perror("ftp: socket");
262 freeaddrinfo(ai_head
);
265 if (timeout
&& setsockopt(s
, IPPROTO_TCP
, TCP_ABORT_THRESHOLD
,
266 (char *)&timeoutms
, sizeof (timeoutms
)) < 0 && debug
)
267 perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)");
270 error_num
= connect(s
, (struct sockaddr
*)&remctladdr
,
271 sizeof (remctladdr
));
277 * Maintain message behavior: only include the address in
278 * our error message if we have another one to try; if this
279 * is the last address on our list, just print the error.
281 if (ai
->ai_next
!= NULL
) {
282 (void) fprintf(stderr
, "ftp: connect to address %s: ",
283 inet_ntop_native(ai
->ai_addr
->sa_family
,
284 (void *)ai
->ai_addr
, abuf
, sizeof (abuf
)));
288 perror("ftp: connect");
290 freeaddrinfo(ai_head
);
294 (void) fprintf(stdout
, "Trying %s...\n",
295 inet_ntop_native(ai
->ai_addr
->sa_family
,
296 (void *)ai
->ai_addr
, abuf
, sizeof (abuf
)));
301 /* Set ipv6rem to TRUE if control connection is a native IPv6 address */
302 if (IN6_IS_ADDR_V4MAPPED(&remctladdr
.sin6_addr
))
308 freeaddrinfo(ai_head
);
312 * Set passive mode flag on by default only if a native IPv6 address
313 * is being used -and- the use_eprt is not set.
315 if (ipv6rem
== B_TRUE
&& use_eprt
== 0)
318 len
= sizeof (myctladdr
);
319 if (getsockname(s
, (struct sockaddr
*)&myctladdr
, &len
) < 0) {
320 perror("ftp: getsockname");
324 ctrl_in
= fdopen(s
, "r");
325 ctrl_out
= fdopen(s
, "w");
326 if (ctrl_in
== NULL
|| ctrl_out
== NULL
) {
327 (void) fprintf(stderr
, "ftp: fdopen failed.\n");
329 (void) fclose(ctrl_in
);
331 (void) fclose(ctrl_out
);
336 (void) printf("Connected to %s.\n", hostname
);
337 if (getreply(0) > 2) { /* read startup message from server */
339 (void) fclose(ctrl_in
);
341 (void) fclose(ctrl_out
);
342 ctrl_in
= ctrl_out
= NULL
;
343 ctrl_in
= ctrl_out
= NULL
;
347 if (setsockopt(s
, SOL_SOCKET
, SO_OOBINLINE
, (char *)&on
,
348 sizeof (on
)) < 0 && debug
)
349 perror("ftp: setsockopt (SO_OOBINLINE)");
361 char *user
, *pass
, *acct
;
364 user
= pass
= acct
= 0;
365 if (ruserpass(host
, &user
, &pass
, &acct
) < 0) {
371 char *myname
= getlogin();
373 if (myname
== NULL
) {
374 struct passwd
*pp
= getpwuid(getuid());
377 myname
= pp
->pw_name
;
380 (void) printf("Name (%s:%s): ", host
,
381 (myname
== NULL
) ? "" : myname
);
383 if (fgets(tmp
, sizeof (tmp
) - 1, stdin
) != NULL
)
384 tmp
[strlen(tmp
) - 1] = '\0';
387 else if (myname
!= NULL
)
392 n
= command("USER %s", user
);
396 pass
= mygetpass("Password:");
399 n
= command("PASS %s", pass
);
400 /* level may have changed */
401 if (clevel
== PROT_P
)
407 acct
= mygetpass("Account:");
408 n
= command("ACCT %s", acct
);
411 (void) fprintf(stderr
, "Login failed.\n");
414 if (!aflag
&& acct
!= NULL
)
415 (void) command("ACCT %s", acct
);
418 for (n
= 0; n
< macnum
; ++n
) {
419 if (strcmp("init", macros
[n
].mac_name
) == 0) {
420 (void) strlcpy(line
, "$init", sizeof (line
));
422 domacro(margc
, margv
);
434 (void) fflush(stdout
);
441 command(char *fmt
, ...)
446 char command_buf
[FTPBUFSIZ
];
451 (void) printf("---> ");
452 if (strncmp("PASS ", fmt
, 5) == 0)
453 (void) printf("PASS XXXX");
454 else if (strncmp("ACCT ", fmt
, 5) == 0)
455 (void) printf("ACCT XXXX");
457 (void) vfprintf(stdout
, fmt
, ap
);
459 (void) fflush(stdout
);
461 if (ctrl_out
== NULL
) {
462 perror("No control connection for command");
466 oldintr
= signal(SIGINT
, cmdabort
);
467 (void) vsnprintf(command_buf
, FTPBUFSIZ
, fmt
, ap
);
470 again
: if (secure_command(command_buf
) == 0)
474 r
= getreply(strcmp(fmt
, "QUIT") == 0);
476 if (r
== 533 && clevel
== PROT_P
) {
477 (void) fprintf(stderr
, "ENC command not supported at server; "
478 "retrying under MIC...\n");
483 if (abrtflag
&& oldintr
!= SIG_IGN
)
485 (void) signal(SIGINT
, oldintr
);
489 /* Need to save reply reponse from server for use in EPSV mode */
490 char reply_string
[BUFSIZ
];
493 getreply(int expecteof
)
496 * 'code' is the 3 digit reply code, form xyz
497 * 'dig' counts the number of digits we are along in the code
498 * 'n' is the first digit of 'code'
499 * 4yz: resource unavailable
500 * 5yz: an error occurred, failure
501 * 6yz: protected reply (is_base64 == TRUE)
502 * 631 - base 64 encoded safe message
503 * 632 - base 64 encoded private message
504 * 633 - base 64 encoded confidential message
505 * 'c' is a wide char type, for international char sets
510 int originalcode
= 0, continuation
= 0;
515 * this is the input and output buffers needed for
518 unsigned char ibuf
[FTPBUFSIZ
];
519 unsigned char obuf
[FTPBUFSIZ
];
526 oldintr
= signal(SIGINT
, cmdabort
);
531 reply_ptr
= reply_buf
;
538 reset_timer(); /* once per line */
540 while ((c
= ibuf
[0] ?
541 (wint_t)ibuf
[i
++] : fgetwc(ctrl_in
)) != '\n') {
546 if (c
== IAC
) { /* handle telnet commands */
547 switch (c
= fgetwc(ctrl_in
)) {
551 (void) fprintf(ctrl_out
, "%c%c%wc", IAC
,
553 (void) fflush(ctrl_out
);
558 (void) fprintf(ctrl_out
, "%c%c%wc", IAC
,
560 (void) fflush(ctrl_out
);
570 (void) signal(SIGINT
, oldintr
);
577 "421 Service not available, remote"
578 " server has closed connection\n");
580 (void) printf("Lost connection\n");
581 (void) fflush(stdout
);
591 if ((auth_type
!= AUTHTYPE_NONE
) && !ibuf
[0] &&
592 (is_base64
|| continuation
)) {
593 /* start storing chars in obuf */
594 if (c
!= '\r' && dig
> 4)
597 if ((auth_type
!= AUTHTYPE_NONE
) && !ibuf
[0] &&
599 (void) printf("Unauthenticated reply received "
602 *reply_ptr
++ = (char)c
;
603 if (c
!= '\r' && (verbose
> 0 ||
604 (verbose
> -1 && n
== '5' && dig
> 4))) {
606 (dig
== 1 || dig
== 5 && verbose
== 0))
607 (void) printf("%s:", hostname
);
610 } /* endif auth_type && !ibuf[0] ... */
612 if ((auth_type
!= AUTHTYPE_NONE
) && !ibuf
[0] && !is_base64
)
615 /* we are still extracting the 3 digit code */
616 if (dig
< 4 && isascii(c
) && isdigit(c
))
617 code
= code
* 10 + (c
- '0');
619 /* starting passive mode */
620 if (!pflag
&& code
== 227)
623 /* start to store characters, when dig > 4 */
624 if (dig
> 4 && pflag
== 1 && isascii(c
) && isdigit(c
))
627 if (c
!= '\r' && c
!= ')') {
628 /* the mb array is to deal with the wchar_t */
633 * space available in pasv[], accounting
636 avail
= &pasv
[sizeof (pasv
)] - pt
- 1;
639 if (len
<= 0 && avail
> 0) {
640 *pt
++ = (unsigned char)c
;
641 } else if (len
> 0 && avail
>= len
) {
642 bcopy(mb
, pt
, (size_t)len
);
649 (void) printf("\nReply too long - "
650 "closing connection\n");
652 (void) fflush(stdout
);
653 (void) signal(SIGINT
, oldintr
);
660 } /* endif pflag == 2 */
661 if (dig
== 4 && c
== '-' && !is_base64
) {
666 if (cp
< &reply_string
[sizeof (reply_string
) - 1])
671 if ((auth_type
!= AUTHTYPE_NONE
) && !ibuf
[0] && !is_base64
)
672 return (getreply(expecteof
));
674 ibuf
[0] = obuf
[i
] = '\0';
676 if (code
&& is_base64
) {
678 n
= decode_reply(ibuf
, sizeof (ibuf
), obuf
, n
, &again
);
683 if (verbose
> 0 || verbose
> -1 && n
== '5') {
685 (void) fflush(stdout
);
688 if (continuation
&& code
!= originalcode
) {
689 ibuf
[0] = obuf
[i
] = '\0';
690 if (originalcode
== 0)
697 (void) signal(SIGINT
, oldintr
);
698 if (code
== 421 || originalcode
== 421)
700 if (abrtflag
&& oldintr
!= cmdabort
&& oldintr
!= SIG_IGN
)
705 if (reply_ptr
= strstr(reply_buf
, reply_parse
)) {
706 reply_parse
= reply_ptr
+ strlen(reply_parse
);
707 if (reply_ptr
= strpbrk(reply_parse
, " \r"))
710 reply_parse
= reply_ptr
;
718 empty(struct fd_set
*mask
, int sec
, int nfds
)
723 t
.tv_sec
= (time_t)sec
;
725 return (select(nfds
, mask
, NULL
, NULL
, &t
));
734 (void) printf("\nsend aborted\n");
735 (void) fflush(stdout
);
736 longjmp(sendabort
, 1);
740 sendrequest(char *cmd
, char *local
, char *remote
, int allowpipe
)
742 FILE *fin
, *dout
= 0;
744 void (*oldintr
)(), (*oldintp
)();
745 off_t bytes
= 0, hashbytes
= HASHSIZ
;
748 * d >= 0 if there is no error
749 * -1 if there was a normal file i/o error
750 * -2 if there was a security error
754 hrtime_t start
, stop
;
758 proxtrans(cmd
, local
, remote
);
765 if (setjmp(sendabort
)) {
774 (void) signal(SIGINT
, oldintr
);
776 (void) signal(SIGPIPE
, oldintp
);
781 oldintr
= signal(SIGINT
, abortsend
);
782 if (strcmp(local
, "-") == 0)
784 else if (allowpipe
&& *local
== '|') {
785 oldintp
= signal(SIGPIPE
, SIG_IGN
);
786 fin
= mypopen(local
+ 1, "r");
789 (void) signal(SIGINT
, oldintr
);
790 (void) signal(SIGPIPE
, oldintp
);
795 closefunc
= mypclose
;
797 fin
= fopen(local
, "r");
800 (void) signal(SIGINT
, oldintr
);
806 if (fstat(fileno(fin
), &st
) < 0 ||
807 (st
.st_mode
&S_IFMT
) != S_IFREG
) {
808 (void) fprintf(stdout
,
809 "%s: not a plain file.\n", local
);
810 (void) signal(SIGINT
, oldintr
);
818 (void) signal(SIGINT
, oldintr
);
820 (void) signal(SIGPIPE
, oldintp
);
822 if (closefunc
!= NULL
)
827 if (setjmp(sendabort
))
829 if ((restart_point
> 0) &&
830 (strcmp(cmd
, "STOR") == 0 || strcmp(cmd
, "APPE") == 0)) {
831 if (fseeko(fin
, restart_point
, SEEK_SET
) < 0) {
833 if (closefunc
!= NULL
)
838 if (command("REST %lld", (longlong_t
)restart_point
)
840 if (closefunc
!= NULL
)
849 if (command("%s %s", cmd
, remote
) != PRELIM
) {
850 (void) signal(SIGINT
, oldintr
);
852 (void) signal(SIGPIPE
, oldintp
);
853 if (closefunc
!= NULL
)
862 if (command("%s", cmd
) != PRELIM
) {
863 (void) signal(SIGINT
, oldintr
);
865 (void) signal(SIGPIPE
, oldintp
);
866 if (closefunc
!= NULL
)
874 dout
= dataconn(dmode
);
878 oldintp
= signal(SIGPIPE
, SIG_IGN
);
885 while ((c
= read(fileno(fin
), buf
, FTPBUFSIZ
)) > 0) {
886 if ((d
= WRITE(fileno(dout
), buf
, c
)) < 0)
890 while (bytes
>= hashbytes
) {
892 hashbytes
+= HASHSIZ
;
894 (void) fflush(stdout
);
897 if (hash
&& bytes
> 0) {
898 if (bytes
< hashbytes
)
900 (void) putchar('\n');
901 (void) fflush(stdout
);
907 d
= secure_flush(fileno(dout
));
910 if ((d
== -1) && (errno
!= EPIPE
))
917 while ((c
= getc(fin
)) != EOF
) {
919 while (hash
&& (bytes
>= hashbytes
)) {
921 (void) fflush(stdout
);
922 hashbytes
+= HASHSIZ
;
924 if (ferror(dout
) || PUTC('\r', dout
) < 0)
929 if (PUTC(c
, dout
) < 0)
934 /* this violates rfc */
935 (void) PUTC('\0', dout
);
940 if (hash
&& bytes
> 0) {
941 if (bytes
< hashbytes
)
943 (void) putchar('\n');
944 (void) fflush(stdout
);
949 d
= ferror(dout
) ? -1 : 0;
951 d
= secure_flush(fileno(dout
));
954 if ((d
== -1) && (errno
!= EPIPE
))
961 if (closefunc
!= NULL
)
963 if (ctrl_in
!= NULL
) {
964 int dfn
= fileno(dout
);
965 int nfds
= fileno(ctrl_in
);
969 * There could be data not yet written to dout,
970 * in the stdio buffer; so, before a shutdown()
971 * on further sends, do fflush(dout)
975 /* sending over; shutdown sending on dfn */
976 (void) shutdown(dfn
, SHUT_WR
);
980 nfds
= MAX(dfn
, nfds
);
983 * Wait for remote end to either close data socket
984 * or ack that we've closed our end; it doesn't
985 * matter which happens first.
987 (void) select(nfds
+ 1, &mask
, NULL
, NULL
, NULL
);
989 (void) fclose(dout
); data
= -1;
992 (void) signal(SIGINT
, oldintr
);
994 (void) signal(SIGPIPE
, oldintp
);
997 * Only print the transfer successful message if the code returned
998 * from remote is 226 or 250. All other codes are error codes.
1000 if ((bytes
> 0) && verbose
&& ((code
== 226) || (code
== 250)))
1001 ptransfer("sent", bytes
, start
, stop
, local
, remote
);
1003 (void) printf("Lost connection\n");
1006 (void) signal(SIGINT
, oldintr
);
1008 (void) signal(SIGPIPE
, oldintp
);
1018 (void) fclose(dout
);
1023 if (closefunc
!= NULL
&& fin
!= NULL
)
1027 * Only print the transfer successful message if the code returned
1028 * from remote is 226 or 250. All other codes are error codes.
1030 if ((bytes
> 0) && verbose
&& ((code
== 226) || (code
== 250)))
1031 ptransfer("sent", bytes
, start
, stop
, local
, remote
);
1033 (void) printf("Lost connection\n");
1043 (void) printf("\n");
1044 (void) fflush(stdout
);
1045 longjmp(recvabort
, 1);
1049 recvrequest(char *cmd
, char *local
, char *remote
, char *mode
, int allowpipe
)
1051 FILE *fout
, *din
= 0;
1053 void (*oldintr
)(), (*oldintp
)();
1054 int oldverbose
, oldtype
= 0, tcrflag
, nfnd
;
1056 off_t bytes
= 0, hashbytes
= HASHSIZ
;
1059 hrtime_t start
, stop
;
1065 retrcmd
= (strcmp(cmd
, "RETR") == 0);
1066 if (proxy
&& retrcmd
) {
1067 proxtrans(cmd
, local
, remote
);
1073 tcrflag
= !crflag
&& retrcmd
;
1074 if (setjmp(recvabort
)) {
1083 (void) signal(SIGINT
, oldintr
);
1087 oldintr
= signal(SIGINT
, abortrecv
);
1088 if (local
!= NULL
&&
1089 strcmp(local
, "-") != 0 &&
1090 (*local
!= '|' || !allowpipe
)) {
1091 if (access(local
, W_OK
) < 0) {
1092 char *dir
= rindex(local
, '/');
1093 int file_errno
= errno
;
1095 if (file_errno
!= ENOENT
&& file_errno
!= EACCES
) {
1097 (void) signal(SIGINT
, oldintr
);
1101 if ((dir
!= NULL
) && (dir
!= local
))
1104 d
= access("/", W_OK
);
1106 d
= access(dir
? local
: ".", W_OK
);
1107 if ((dir
!= NULL
) && (dir
!= local
))
1111 (void) signal(SIGINT
, oldintr
);
1115 if (!runique
&& file_errno
== EACCES
) {
1118 (void) signal(SIGINT
, oldintr
);
1122 if (runique
&& file_errno
== EACCES
&&
1123 (local
= gunique(local
)) == NULL
) {
1124 (void) signal(SIGINT
, oldintr
);
1128 } else if (runique
&& (local
= gunique(local
)) == NULL
) {
1129 (void) signal(SIGINT
, oldintr
);
1135 (void) signal(SIGINT
, oldintr
);
1139 if (setjmp(recvabort
))
1141 if (!retrcmd
&& type
!= TYPE_A
) {
1143 oldverbose
= verbose
;
1147 verbose
= oldverbose
;
1149 if ((restart_point
> 0) && retrcmd
&&
1150 command("REST %lld", (longlong_t
)restart_point
) != CONTINUE
) {
1154 if (command("%s %s", cmd
, remote
) != PRELIM
) {
1155 (void) signal(SIGINT
, oldintr
);
1170 verbose
= oldverbose
;
1175 if (command("%s", cmd
) != PRELIM
) {
1176 (void) signal(SIGINT
, oldintr
);
1191 verbose
= oldverbose
;
1196 din
= dataconn("r");
1200 if (local
== NULL
) {
1202 } else if (strcmp(local
, "-") == 0) {
1204 } else if (allowpipe
&& *local
== '|') {
1205 oldintp
= signal(SIGPIPE
, SIG_IGN
);
1206 fout
= mypopen(local
+ 1, "w");
1211 closefunc
= mypclose
;
1213 fout
= fopen(local
, mode
);
1220 start
= gethrtime();
1226 if ((restart_point
> 0) && retrcmd
&&
1227 lseek(fileno(fout
), restart_point
, SEEK_SET
) < 0) {
1233 while ((c
= timedread(infd
, buf
, FTPBUFSIZ
, timeout
)) > 0) {
1234 for (n
= 0; n
< c
; n
+= d
) {
1235 d
= write(fileno(fout
), &buf
[n
], c
- n
);
1241 while (bytes
>= hashbytes
) {
1242 (void) putchar('#');
1243 hashbytes
+= HASHSIZ
;
1245 (void) fflush(stdout
);
1248 if (hash
&& bytes
> 0) {
1249 if (bytes
< hashbytes
)
1250 (void) putchar('#');
1251 (void) putchar('\n');
1252 (void) fflush(stdout
);
1258 if ((d
< 0) || ((c
== 0) && (fsync(fileno(fout
)) == -1))) {
1266 if ((restart_point
> 0) && retrcmd
) {
1270 if (fseek(fout
, 0L, SEEK_SET
) < 0) {
1274 while (i
++ < restart_point
) {
1275 if ((c
= getc(fout
)) == EOF
) {
1279 (void) fprintf(stderr
,
1280 "%s: Unexpected end of file\n",
1287 if (fseeko(fout
, 0L, SEEK_CUR
) < 0) {
1292 fdio_setbuf(buf
, FTPBUFSIZ
);
1294 while ((c
= fdio_getc(infd
)) != EOF
) {
1296 while (hash
&& (bytes
>= hashbytes
)) {
1297 (void) putchar('#');
1298 (void) fflush(stdout
);
1299 hashbytes
+= HASHSIZ
;
1303 if ((c
= fdio_getc(infd
)) != '\n' || tcrflag
) {
1306 if (putc('\r', fout
) == EOF
)
1307 goto writer_ascii_err
;
1318 if (putc(c
, fout
) == EOF
)
1319 goto writer_ascii_err
;
1323 if (hash
&& bytes
> 0) {
1324 if (bytes
< hashbytes
)
1325 (void) putchar('#');
1326 (void) putchar('\n');
1327 (void) fflush(stdout
);
1329 if (fdio_error(infd
)) {
1333 if ((fflush(fout
) == EOF
) || ferror(fout
) ||
1334 (fsync(fileno(fout
)) == -1)) {
1342 if (closefunc
!= NULL
)
1344 (void) signal(SIGINT
, oldintr
);
1346 (void) signal(SIGPIPE
, oldintp
);
1347 (void) fclose(din
); data
= -1;
1350 if (bytes
> 0 && verbose
&& !errflg
)
1351 ptransfer("received", bytes
, start
, stop
, local
, remote
);
1353 (void) printf("Lost connection\n");
1368 verbose
= oldverbose
;
1373 /* abort using RFC959 recommended IP, SYNC sequence */
1377 (void) signal(SIGPIPE
, oldintp
);
1378 (void) signal(SIGINT
, SIG_IGN
);
1381 (void) signal(SIGINT
, oldintr
);
1385 (void) fprintf(ctrl_out
, "%c%c", IAC
, IP
);
1386 (void) fflush(ctrl_out
);
1389 * send IAC in urgent mode instead of DM because UNIX places oob
1390 * mark after urgent byte rather than before as now is protocol
1392 if (send(fileno(ctrl_out
), &msg
, 1, MSG_OOB
) != 1) {
1395 (void) fprintf(ctrl_out
, "%cABOR\r\n", DM
);
1396 (void) fflush(ctrl_out
);
1397 nfds
= fileno(ctrl_in
) + 1;
1399 FD_SET(fileno(ctrl_in
), &mask
);
1401 FD_SET(fileno(din
), &mask
);
1402 nfds
= MAX(fileno(din
) + 1, nfds
);
1404 if ((nfnd
= empty(&mask
, 10, nfds
)) <= 0) {
1411 if (din
&& FD_ISSET(fileno(din
), &mask
)) {
1414 } while ((c
= read(fileno(din
), buf
, FTPBUFSIZ
)) > 0);
1416 if ((c
= getreply(0)) == ERROR
&& code
== 552) {
1417 /* needed for nic style abort */
1438 verbose
= oldverbose
;
1446 if (closefunc
!= NULL
&& fout
!= NULL
)
1452 if (bytes
> 0 && verbose
)
1453 ptransfer("received", bytes
, start
, stop
, local
, remote
);
1455 (void) printf("Lost connection\n");
1456 (void) signal(SIGINT
, oldintr
);
1460 * Need to start a listen on the data channel
1461 * before we send the command, otherwise the
1462 * server's connect may fail.
1468 unsigned char *p
, *a
;
1469 int result
, tmpno
= 0;
1476 pasv_refused
= B_FALSE
;
1478 data
= socket(AF_INET6
, SOCK_STREAM
, 0);
1483 if (timeout
&& setsockopt(data
, IPPROTO_TCP
,
1484 TCP_ABORT_THRESHOLD
, (char *)&timeoutms
,
1485 sizeof (timeoutms
)) < 0 && debug
)
1486 perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)");
1487 if ((options
& SO_DEBUG
) &&
1488 setsockopt(data
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
1490 perror("setsockopt (ignored)");
1492 * Use the system wide default send and receive buffer sizes
1493 * unless one has been specified.
1495 if (tcpwindowsize
) {
1496 if (setsockopt(data
, SOL_SOCKET
, SO_SNDBUF
,
1497 (char *)&tcpwindowsize
, sizeof (tcpwindowsize
)) < 0)
1498 perror("ftp: setsockopt (SO_SNDBUF - ignored)");
1499 if (setsockopt(data
, SOL_SOCKET
, SO_RCVBUF
,
1500 (char *)&tcpwindowsize
, sizeof (tcpwindowsize
)) < 0)
1501 perror("ftp: setsockopt (SO_RCVBUF - ignored)");
1504 data_addr
= remctladdr
;
1506 if (ipv6rem
== B_TRUE
) {
1507 if (command("EPSV") != COMPLETE
) {
1508 (void) fprintf(stderr
,
1509 "Passive mode refused. Try EPRT\n");
1510 pasv_refused
= B_TRUE
;
1515 * Get the data port from reply string from the
1516 * server. The format of the reply string is:
1517 * 229 Entering Extended Passive Mode (|||port|)
1518 * where | is the delimiter being used.
1520 c
= strchr(reply_string
, '(');
1521 c2
= strchr(reply_string
, ')');
1522 if (c
== NULL
|| c2
== NULL
) {
1523 (void) fprintf(stderr
, "Extended passive mode"
1524 "parsing failure.\n");
1528 /* Delimiter is the next char in the reply string */
1530 while (*c
== delm
) {
1532 (void) fprintf(stderr
,
1533 "Extended passive mode"
1534 "parsing failure.\n");
1538 /* assign the port for data connection */
1539 ports
= (in_port_t
)atoi(c
);
1540 data_addr
.sin6_port
= htons(ports
);
1542 int a1
, a2
, a3
, a4
, p1
, p2
;
1544 if (command("PASV") != COMPLETE
) {
1545 (void) fprintf(stderr
,
1546 "Passive mode refused. Try PORT\n");
1547 pasv_refused
= B_TRUE
;
1552 * Get the data port from reply string from the
1553 * server. The format of the reply string is:
1554 * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)
1556 if (sscanf(pasv
, "%d,%d,%d,%d,%d,%d",
1557 &a1
, &a2
, &a3
, &a4
, &p1
, &p2
) != 6) {
1558 (void) fprintf(stderr
,
1559 "Passive mode parsing failure.\n");
1563 * Set the supplied address and port in an
1564 * IPv4-mapped IPv6 address.
1566 a
= (unsigned char *)&data_addr
.sin6_addr
+
1567 sizeof (struct in6_addr
) -
1568 sizeof (struct in_addr
);
1569 #define UC(b) ((b)&0xff)
1574 p
= (unsigned char *)&data_addr
.sin6_port
;
1579 if (connect(data
, (struct sockaddr
*)&data_addr
,
1580 sizeof (data_addr
)) < 0) {
1588 data_addr
= myctladdr
;
1590 data_addr
.sin6_port
= 0; /* let system pick one */
1594 data
= socket(AF_INET6
, SOCK_STREAM
, 0);
1596 perror("ftp: socket");
1602 if (setsockopt(data
, SOL_SOCKET
, SO_REUSEADDR
,
1603 (char *)&on
, sizeof (on
)) < 0) {
1604 perror("ftp: setsockopt (SO_REUSEADDR)");
1608 (struct sockaddr
*)&data_addr
, sizeof (data_addr
)) < 0) {
1609 perror("ftp: bind");
1612 if (timeout
&& setsockopt(data
, IPPROTO_TCP
, TCP_ABORT_THRESHOLD
,
1613 (char *)&timeoutms
, sizeof (timeoutms
)) < 0 && debug
)
1614 perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)");
1615 if (options
& SO_DEBUG
&&
1616 setsockopt(data
, SOL_SOCKET
, SO_DEBUG
,
1617 (char *)&on
, sizeof (on
)) < 0)
1618 perror("ftp: setsockopt (SO_DEBUG - ignored)");
1620 * Use the system wide default send and receive buffer sizes unless
1621 * one has been specified.
1623 if (tcpwindowsize
) {
1624 if (setsockopt(data
, SOL_SOCKET
, SO_SNDBUF
,
1625 (char *)&tcpwindowsize
, sizeof (tcpwindowsize
)) < 0)
1626 perror("ftp: setsockopt (SO_SNDBUF - ignored)");
1627 if (setsockopt(data
, SOL_SOCKET
, SO_RCVBUF
,
1628 (char *)&tcpwindowsize
, sizeof (tcpwindowsize
)) < 0)
1629 perror("ftp: setsockopt (SO_RCVBUF - ignored)");
1631 len
= sizeof (data_addr
);
1632 if (getsockname(data
, (struct sockaddr
*)&data_addr
, &len
) < 0) {
1633 perror("ftp: getsockname");
1637 v4_addr
= IN6_IS_ADDR_V4MAPPED(&data_addr
.sin6_addr
);
1638 if (listen(data
, 1) < 0)
1639 perror("ftp: listen");
1642 a
= (unsigned char *)&data_addr
.sin6_addr
;
1643 p
= (unsigned char *)&data_addr
.sin6_port
;
1646 command("PORT %d,%d,%d,%d,%d,%d",
1647 UC(a
[12]), UC(a
[13]), UC(a
[14]), UC(a
[15]),
1648 UC(p
[0]), UC(p
[1]));
1650 char hname
[INET6_ADDRSTRLEN
];
1652 result
= COMPLETE
+ 1;
1654 * if on previous try to server, it was
1655 * determined that the server doesn't support
1656 * EPRT, don't bother trying again. Just try
1659 if (eport_supported
== B_TRUE
) {
1660 if (inet_ntop(AF_INET6
, &data_addr
.sin6_addr
,
1661 hname
, sizeof (hname
)) != NULL
) {
1662 result
= command("EPRT |%d|%s|%d|", 2,
1663 hname
, htons(data_addr
.sin6_port
));
1664 if (result
!= COMPLETE
)
1665 eport_supported
= B_FALSE
;
1669 if (result
!= COMPLETE
) {
1671 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1673 UC(a
[0]), UC(a
[1]), UC(a
[2]), UC(a
[3]),
1674 UC(a
[4]), UC(a
[5]), UC(a
[6]), UC(a
[7]),
1675 UC(a
[8]), UC(a
[9]), UC(a
[10]), UC(a
[11]),
1676 UC(a
[12]), UC(a
[13]), UC(a
[14]), UC(a
[15]),
1677 2, UC(p
[0]), UC(p
[1]));
1681 if (result
== ERROR
&& sendport
== -1) {
1686 return (result
!= COMPLETE
);
1692 (void) close(data
), data
= -1;
1699 dataconn(char *mode
)
1701 struct sockaddr_in6 from
;
1703 socklen_t fromlen
= sizeof (from
);
1706 if (passivemode
&& !pasv_refused
)
1707 return (fdopen(data
, mode
));
1709 s
= accept(data
, (struct sockaddr
*)&from
, &fromlen
);
1711 perror("ftp: accept");
1712 (void) close(data
), data
= -1;
1717 return (fdopen(data
, mode
));
1721 ptransfer(char *direction
, off_t bytes
, hrtime_t t0
,
1722 hrtime_t t1
, char *local
, char *remote
)
1724 hrtime_t td
; /* nanoseconds in a 64 bit int */
1728 s
= (double)td
/ 1000000000.0; /* seconds */
1729 bs
= (double)bytes
/ NONZERO(s
);
1730 if (local
&& *local
!= '-')
1731 (void) printf("local: %s ", local
);
1733 (void) printf("remote: %s\n", remote
);
1734 (void) printf("%lld bytes %s in %.2g seconds (%.2f Kbytes/s)\n",
1735 (longlong_t
)bytes
, direction
, s
, bs
/ 1024.0);
1749 static struct comvars
{
1751 char name
[MAXHOSTNAMELEN
];
1752 struct sockaddr_in6 mctl
;
1753 struct sockaddr_in6 hctl
;
1765 char mi
[MAXPATHLEN
];
1766 char mo
[MAXPATHLEN
];
1770 } proxstruct
, tmpstruct
;
1771 struct comvars
*ip
, *op
;
1774 oldintr
= signal(SIGINT
, psabort
);
1788 ip
->connect
= connected
;
1789 connected
= op
->connect
;
1791 (void) strlcpy(ip
->name
, hostname
, sizeof (ip
->name
));
1794 hostname
= op
->name
;
1795 ip
->hctl
= remctladdr
;
1796 remctladdr
= op
->hctl
;
1797 ip
->mctl
= myctladdr
;
1798 myctladdr
= op
->mctl
;
1809 ip
->sunqe
= sunique
;
1810 sunique
= op
->sunqe
;
1811 ip
->runqe
= runique
;
1812 runique
= op
->runqe
;
1817 (void) strlcpy(ip
->nti
, ntin
, sizeof (ip
->nti
));
1818 (void) strlcpy(ntin
, op
->nti
, sizeof (ntin
));
1819 (void) strlcpy(ip
->nto
, ntout
, sizeof (ip
->nto
));
1820 (void) strlcpy(ntout
, op
->nto
, sizeof (ntout
));
1821 ip
->mapflg
= mapflag
;
1822 mapflag
= op
->mapflg
;
1823 (void) strlcpy(ip
->mi
, mapin
, sizeof (ip
->mi
));
1824 (void) strlcpy(mapin
, op
->mi
, sizeof (mapin
));
1825 (void) strlcpy(ip
->mo
, mapout
, sizeof (ip
->mo
));
1826 (void) strlcpy(mapout
, op
->mo
, sizeof (mapout
));
1828 ip
->authtype
= auth_type
;
1829 auth_type
= op
->authtype
;
1839 (void) signal(SIGINT
, oldintr
);
1850 (void) printf("\n");
1851 (void) fflush(stdout
);
1855 longjmp(ptabort
, 1);
1859 proxtrans(char *cmd
, char *local
, char *remote
)
1862 int tmptype
, oldtype
= 0, secndflag
= 0, nfnd
;
1863 extern jmp_buf ptabort
;
1866 int ipv4_addr
= IN6_IS_ADDR_V4MAPPED(&remctladdr
.sin6_addr
);
1868 if (strcmp(cmd
, "RETR"))
1871 cmd2
= runique
? "STOU" : "STOR";
1872 if (command(ipv4_addr
? "PASV" : "EPSV") != COMPLETE
) {
1874 "proxy server does not support third part transfers.\n");
1880 (void) printf("No primary connection\n");
1885 if (type
!= tmptype
) {
1902 if (command(ipv4_addr
? "PORT %s" : "EPRT %s", pasv
) != COMPLETE
) {
1922 if (setjmp(ptabort
))
1924 oldintr
= signal(SIGINT
, (void (*)())abortpt
);
1925 if (command("%s %s", cmd
, remote
) != PRELIM
) {
1926 (void) signal(SIGINT
, oldintr
);
1949 if (command("%s %s", cmd2
, local
) != PRELIM
)
1955 (void) signal(SIGINT
, oldintr
);
1974 (void) printf("local: %s remote: %s\n", local
, remote
);
1977 (void) signal(SIGINT
, SIG_IGN
);
1979 if (strcmp(cmd
, "RETR") && !proxy
)
1981 else if ((strcmp(cmd
, "RETR") == 0) && proxy
)
1983 if (!cpend
&& !secndflag
) { /* only here if cmd = "STOR" (proxy=1) */
1984 if (command("%s %s", cmd2
, local
) != PRELIM
) {
2005 (void) fprintf(ctrl_out
, "%c%c", IAC
, IP
);
2006 (void) fflush(ctrl_out
);
2008 *(msg
+1) = (char)DM
;
2009 if (send(fileno(ctrl_out
), msg
, 2, MSG_OOB
)
2012 (void) fprintf(ctrl_out
, "ABOR\r\n");
2013 (void) fflush(ctrl_out
);
2015 FD_SET(fileno(ctrl_in
), &mask
);
2016 if ((nfnd
= empty(&mask
, 10,
2017 fileno(ctrl_in
) + 1)) <= 0) {
2032 (void) signal(SIGINT
, oldintr
);
2038 (void) fprintf(ctrl_out
, "%c%c", IAC
, IP
);
2039 (void) fflush(ctrl_out
);
2041 *(msg
+1) = (char)DM
;
2042 if (send(fileno(ctrl_out
), msg
, 2, MSG_OOB
) != 2)
2044 (void) fprintf(ctrl_out
, "ABOR\r\n");
2045 (void) fflush(ctrl_out
);
2047 FD_SET(fileno(ctrl_in
), &mask
);
2048 if ((nfnd
= empty(&mask
, 10, fileno(ctrl_in
) + 1)) <= 0) {
2060 if (!cpend
&& !secndflag
) { /* only if cmd = "RETR" (proxy=1) */
2061 if (command("%s %s", cmd2
, local
) != PRELIM
) {
2082 (void) fprintf(ctrl_out
, "%c%c", IAC
, IP
);
2083 (void) fflush(ctrl_out
);
2085 *(msg
+1) = (char)DM
;
2086 if (send(fileno(ctrl_out
), msg
, 2, MSG_OOB
)
2089 (void) fprintf(ctrl_out
, "ABOR\r\n");
2090 (void) fflush(ctrl_out
);
2092 FD_SET(fileno(ctrl_in
), &mask
);
2093 if ((nfnd
= empty(&mask
, 10,
2094 fileno(ctrl_in
) + 1)) <= 0) {
2108 (void) signal(SIGINT
, oldintr
);
2115 (void) fprintf(ctrl_out
, "%c%c", IAC
, IP
);
2116 (void) fflush(ctrl_out
);
2118 *(msg
+1) = (char)DM
;
2119 if (send(fileno(ctrl_out
), msg
, 2, MSG_OOB
) != 2)
2121 (void) fprintf(ctrl_out
, "ABOR\r\n");
2122 (void) fflush(ctrl_out
);
2124 FD_SET(fileno(ctrl_in
), &mask
);
2125 if ((nfnd
= empty(&mask
, 10, fileno(ctrl_in
) + 1)) <= 0) {
2139 FD_SET(fileno(ctrl_in
), &mask
);
2140 if ((nfnd
= empty(&mask
, 10, fileno(ctrl_in
) + 1)) <= 0) {
2172 (void) signal(SIGINT
, oldintr
);
2177 reset(int argc
, char *argv
[])
2184 FD_SET(fileno(ctrl_in
), &mask
);
2185 if ((nfnd
= empty(&mask
, 0, fileno(ctrl_in
) + 1)) < 0) {
2189 } else if (nfnd
> 0) {
2196 gunique(char *local
)
2198 static char new[MAXPATHLEN
];
2199 char *cp
= rindex(local
, '/');
2205 d
= access(cp
? local
: ".", 2);
2212 if (strlcpy(new, local
, sizeof (new)) >= sizeof (new))
2213 (void) printf("gunique: too long: local %s, %d, new %d\n",
2214 local
, strlen(local
), sizeof (new));
2216 cp
= new + strlen(new);
2219 if (++count
== 100) {
2221 "runique: can't find unique file name.\n");
2230 if ((d
= access(new, 0)) < 0)
2234 else if (*(cp
- 2) == '.')
2237 *(cp
- 2) = *(cp
- 2) + 1;
2245 * This is a wrap-around function for inet_ntop(). In case the af is AF_INET6
2246 * and the address pointed by src is a IPv4-mapped IPv6 address, it
2247 * returns printable IPv4 address, not IPv4-mapped IPv6 address. In other cases
2248 * it behaves just like inet_ntop().
2251 inet_ntop_native(int af
, const void *src
, char *dst
, size_t size
)
2253 struct in_addr src4
;
2255 struct sockaddr_in
*sin
;
2256 struct sockaddr_in6
*sin6
;
2258 if (af
== AF_INET6
) {
2259 sin6
= (struct sockaddr_in6
*)src
;
2260 if (IN6_IS_ADDR_V4MAPPED(&sin6
->sin6_addr
)) {
2261 IN6_V4MAPPED_TO_INADDR(&sin6
->sin6_addr
, &src4
);
2262 result
= inet_ntop(AF_INET
, &src4
, dst
, size
);
2264 result
= inet_ntop(AF_INET6
, &sin6
->sin6_addr
,
2268 sin
= (struct sockaddr_in
*)src
;
2269 result
= inet_ntop(af
, &sin
->sin_addr
, dst
, size
);
2276 secure_command(char *cmd
)
2278 unsigned char *in
= NULL
, *out
= NULL
;
2282 if ((auth_type
!= AUTHTYPE_NONE
) && clevel
!= PROT_C
) {
2283 gss_buffer_desc in_buf
, out_buf
;
2284 OM_uint32 maj_stat
, min_stat
;
2286 /* secure_command (based on level) */
2287 if (auth_type
== AUTHTYPE_GSSAPI
) {
2288 OM_uint32 expire_time
;
2290 /* clevel = PROT_P; */
2292 in_buf
.length
= strlen(cmd
) + 1;
2294 maj_stat
= gss_context_time(&min_stat
, gcontext
,
2296 if (GSS_ERROR(maj_stat
)) {
2297 user_gss_error(maj_stat
, min_stat
,
2298 "gss context has expired");
2299 fatal("Your gss credentials have expired. "
2302 maj_stat
= gss_seal(&min_stat
, gcontext
,
2303 (clevel
== PROT_P
), /* private */
2305 &in_buf
, &conf_state
,
2307 if (maj_stat
!= GSS_S_COMPLETE
) {
2308 /* generally need to deal */
2309 user_gss_error(maj_stat
, min_stat
,
2310 (clevel
== PROT_P
) ?
2311 "gss_seal ENC didn't complete":
2312 "gss_seal MIC didn't complete");
2313 } else if ((clevel
== PROT_P
) && !conf_state
) {
2314 (void) fprintf(stderr
,
2315 "GSSAPI didn't encrypt message");
2316 out
= out_buf
.value
;
2319 (void) fprintf(stderr
,
2320 "sealed (%s) %d bytes\n",
2321 clevel
== PROT_P
? "ENC" : "MIC",
2324 out
= out_buf
.value
;
2327 /* Other auth types go here ... */
2328 inlen
= ((4 * out_buf
.length
) / 3) + 4;
2329 in
= (uchar_t
*)malloc(inlen
);
2331 gss_release_buffer(&min_stat
, &out_buf
);
2332 fatal("Memory error allocating space for response.");
2334 length
= out_buf
.length
;
2335 if (auth_error
= radix_encode(out
, in
, inlen
, &length
, 0)) {
2336 (void) fprintf(stderr
,
2337 "Couldn't base 64 encode command (%s)\n",
2338 radix_error(auth_error
));
2340 gss_release_buffer(&min_stat
, &out_buf
);
2344 (void) fprintf(ctrl_out
, "%s %s",
2345 clevel
== PROT_P
? "ENC" : "MIC", in
);
2348 gss_release_buffer(&min_stat
, &out_buf
);
2351 (void) fprintf(stderr
,
2352 "secure_command(%s)\nencoding %d bytes %s %s\n",
2354 (clevel
== PROT_P
) ? "ENC" : "MIC", in
);
2357 * auth_type = AUTHTYPE_NONE or
2358 * command channel is not protected
2360 fputs(cmd
, ctrl_out
);
2363 (void) fprintf(ctrl_out
, "\r\n");
2364 (void) fflush(ctrl_out
);
2368 unsigned int maxbuf
;
2369 unsigned char *ucbuf
;
2372 setpbsz(unsigned int size
)
2374 unsigned int actualbuf
;
2380 while ((ucbuf
= (unsigned char *)malloc(actualbuf
)) == NULL
) {
2384 perror("Error while trying to malloc PROT buffer:");
2388 oldverbose
= verbose
;
2390 reply_parse
= "PBSZ=";
2391 if (command("PBSZ %u", actualbuf
) != COMPLETE
)
2392 fatal("Cannot set PROT buffer size");
2394 if ((maxbuf
= (unsigned int) atol(reply_parse
)) > actualbuf
)
2399 verbose
= oldverbose
;
2403 * Do the base 64 decoding of the raw input buffer, b64_buf.
2404 * Also do the verification and decryption, if required.
2405 * retval contains the current error code number
2408 * (RFC 2228: error returns are 3 digit numbers of the form 5xy)
2409 * 5 if an error occurred
2412 decode_reply(uchar_t
*plain_buf
,
2423 if (!b64_buf
[0]) /* if there is no string, no problem */
2426 if ((auth_type
== AUTHTYPE_NONE
)) {
2427 (void) printf("Cannot decode reply:\n%d %s\n", code
, b64_buf
);
2433 case 631: /* 'safe' */
2437 case 632: /* 'private' */
2440 case 633: /* 'confidential' */
2444 (void) printf("Unknown reply: %d %s\n", code
, b64_buf
);
2448 /* decode the base64 encoded message */
2449 auth_error
= radix_encode(b64_buf
, plain_buf
, ilen
, &len
, 1);
2452 (void) printf("Can't base 64 decode reply %d (%s)\n\"%s\"\n",
2453 code
, radix_error(auth_error
), b64_buf
);
2457 if (auth_type
== AUTHTYPE_GSSAPI
) {
2458 gss_buffer_desc xmit_buf
, msg_buf
;
2459 OM_uint32 maj_stat
, min_stat
;
2460 int conf_state
= safe
;
2461 xmit_buf
.value
= plain_buf
;
2462 xmit_buf
.length
= len
;
2464 /* decrypt/verify the message */
2465 maj_stat
= gss_unseal(&min_stat
, gcontext
,
2466 &xmit_buf
, &msg_buf
, &conf_state
, NULL
);
2467 if (maj_stat
!= GSS_S_COMPLETE
) {
2468 user_gss_error(maj_stat
, min_stat
,
2469 "failed unsealing reply");
2472 if (msg_buf
.length
< ilen
- 2 - 1) {
2473 memcpy(plain_buf
, msg_buf
.value
, msg_buf
.length
);
2474 strcpy((char *)&plain_buf
[msg_buf
.length
], "\r\n");
2475 gss_release_buffer(&min_stat
, &msg_buf
);
2478 user_gss_error(maj_stat
, min_stat
,
2479 "reply was too long");
2482 } /* end if GSSAPI */
2484 /* Other auth types go here... */