1 /* $KAME: ftp.c,v 1.11 2001/07/02 14:36:49 itojun Exp $ */
4 * Copyright (C) 1997 and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * $FreeBSD: src/usr.sbin/faithd/ftp.c,v 1.2.2.5 2002/04/28 05:40:29 suz Exp $
32 * $DragonFly: src/usr.sbin/faithd/ftp.c,v 1.4 2003/11/16 14:10:45 eirikn Exp $
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/ioctl.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
55 static char rbuf
[MSS
];
56 static char sbuf
[MSS
];
57 static int passivemode
= 0;
58 static int wport4
= -1; /* listen() to active */
59 static int wport6
= -1; /* listen() to passive */
60 static int port4
= -1; /* active: inbound passive: outbound */
61 static int port6
= -1; /* active: outbound passive: inbound */
62 static struct sockaddr_storage data4
; /* server data address */
63 static struct sockaddr_storage data6
; /* client data address */
64 static int epsvall
= 0;
67 enum state
{ NONE
, LPRT
, EPRT
, PORT
, LPSV
, EPSV
, PASV
};
69 enum state
{ NONE
, LPRT
, EPRT
, LPSV
, EPSV
};
72 static int ftp_activeconn(void);
73 static int ftp_passiveconn(void);
74 static int ftp_copy(int, int);
75 static int ftp_copyresult(int, int, enum state
);
76 static int ftp_copycommand(int, int, enum state
*);
79 ftp_relay(int ctl6
, int ctl4
)
83 enum state state
= NONE
;
86 syslog(LOG_INFO
, "starting ftp control connection");
90 FD_SET(ctl4
, &readfds
);
91 FD_SET(ctl6
, &readfds
);
93 FD_SET(port4
, &readfds
);
95 FD_SET(port6
, &readfds
);
98 FD_SET(wport4
, &readfds
);
100 FD_SET(wport6
, &readfds
);
102 tv
.tv_sec
= FAITH_TIMEOUT
;
105 error
= select(256, &readfds
, NULL
, NULL
, &tv
);
107 exit_failure("select: %s", strerror(errno
));
109 exit_failure("connection timeout");
112 * The order of the following checks does (slightly) matter.
113 * It is important to visit all checks (do not use "continue"),
114 * otherwise some of the pipe may become full and we cannot
117 if (FD_ISSET(ctl6
, &readfds
)) {
119 * copy control connection from the client.
120 * command translation is necessary.
122 error
= ftp_copycommand(ctl6
, ctl4
, &state
);
130 exit_success("terminating ftp control connection");
136 if (FD_ISSET(ctl4
, &readfds
)) {
138 * copy control connection from the server
139 * translation of result code is necessary.
141 error
= ftp_copyresult(ctl4
, ctl6
, state
);
149 exit_success("terminating ftp control connection");
155 if (0 <= port4
&& 0 <= port6
&& FD_ISSET(port4
, &readfds
)) {
157 * copy data connection.
158 * no special treatment necessary.
160 if (FD_ISSET(port4
, &readfds
))
161 error
= ftp_copy(port4
, port6
);
169 syslog(LOG_INFO
, "terminating data connection");
175 if (0 <= port4
&& 0 <= port6
&& FD_ISSET(port6
, &readfds
)) {
177 * copy data connection.
178 * no special treatment necessary.
180 if (FD_ISSET(port6
, &readfds
))
181 error
= ftp_copy(port6
, port4
);
189 syslog(LOG_INFO
, "terminating data connection");
196 if (wport4
&& FD_ISSET(wport4
, &readfds
)) {
198 * establish active data connection from the server.
202 if (wport6
&& FD_ISSET(wport6
, &readfds
)) {
204 * establish passive data connection from the client.
212 exit_failure("%s", strerror(errno
));
221 struct timeval timeout
;
224 /* get active connection from server */
226 FD_SET(wport4
, &set
);
227 timeout
.tv_sec
= 120;
228 timeout
.tv_usec
= -1;
230 if (select(wport4
+ 1, &set
, NULL
, NULL
, &timeout
) == 0
231 || (port4
= accept(wport4
, (struct sockaddr
*)&data4
, &n
)) < 0) {
234 syslog(LOG_INFO
, "active mode data connection failed");
238 /* ask active connection to client */
239 sa
= (struct sockaddr
*)&data6
;
240 port6
= socket(sa
->sa_family
, SOCK_STREAM
, 0);
245 syslog(LOG_INFO
, "active mode data connection failed");
248 error
= connect(port6
, sa
, sa
->sa_len
);
253 port6
= port4
= wport4
= -1;
254 syslog(LOG_INFO
, "active mode data connection failed");
258 syslog(LOG_INFO
, "active mode data connection established");
263 ftp_passiveconn(void)
268 struct timeval timeout
;
271 /* get passive connection from client */
273 FD_SET(wport6
, &set
);
274 timeout
.tv_sec
= 120;
277 if (select(wport6
+ 1, &set
, NULL
, NULL
, &timeout
) == 0
278 || (port6
= accept(wport6
, (struct sockaddr
*)&data6
, &n
)) < 0) {
281 syslog(LOG_INFO
, "passive mode data connection failed");
285 /* ask passive connection to server */
286 sa
= (struct sockaddr
*)&data4
;
287 port4
= socket(sa
->sa_family
, SOCK_STREAM
, 0);
292 syslog(LOG_INFO
, "passive mode data connection failed");
295 error
= connect(port4
, sa
, sa
->sa_len
);
300 wport6
= port4
= port6
= -1;
301 syslog(LOG_INFO
, "passive mode data connection failed");
305 syslog(LOG_INFO
, "passive mode data connection established");
310 ftp_copy(int src
, int dst
)
315 /* OOB data handling */
316 error
= ioctl(src
, SIOCATMARK
, &atmark
);
317 if (error
!= -1 && atmark
== 1) {
318 n
= read(src
, rbuf
, 1);
321 send(dst
, rbuf
, n
, MSG_OOB
);
323 n
= read(src
, rbuf
, sizeof(rbuf
));
331 n
= read(src
, rbuf
, sizeof(rbuf
));
342 exit_failure("%s", strerror(errno
));
344 return 0; /* to make gcc happy */
348 ftp_copyresult(int src
, int dst
, enum state state
)
355 /* OOB data handling */
356 error
= ioctl(src
, SIOCATMARK
, &atmark
);
357 if (error
!= -1 && atmark
== 1) {
358 n
= read(src
, rbuf
, 1);
361 send(dst
, rbuf
, n
, MSG_OOB
);
363 n
= read(src
, rbuf
, sizeof(rbuf
));
371 n
= read(src
, rbuf
, sizeof(rbuf
));
384 for (i
= 0; i
< 3; i
++) {
399 /* param points to first non-command token, if any */
400 while (*param
&& isspace(*param
))
408 if (!passivemode
&& rbuf
[0] == '1') {
409 if (ftp_activeconn() < 0) {
410 n
= snprintf(rbuf
, sizeof(rbuf
),
411 "425 Cannot open data connetion\r\n");
418 /* expecting "200 PORT command successful." */
422 p
= strstr(rbuf
, "PORT");
424 p
[0] = (state
== LPRT
) ? 'L' : 'E';
435 /* expecting "200 EPRT command successful." */
439 p
= strstr(rbuf
, "EPRT");
454 * expecting "227 Entering Passive Mode (x,x,x,x,x,x,x)"
455 * (in some cases result comes without paren)
466 unsigned int ho
[4], po
[2];
467 struct sockaddr_in
*sin
;
468 struct sockaddr_in6
*sin6
;
473 * PASV result -> LPSV/EPSV result
476 while (*p
&& *p
!= '(' && !isdigit(*p
)) /*)*/
479 goto passivefail0
; /*XXX*/
482 n
= sscanf(p
, "%u,%u,%u,%u,%u,%u",
483 &ho
[0], &ho
[1], &ho
[2], &ho
[3], &po
[0], &po
[1]);
485 goto passivefail0
; /*XXX*/
487 /* keep PORT parameter */
488 memset(&data4
, 0, sizeof(data4
));
489 sin
= (struct sockaddr_in
*)&data4
;
490 sin
->sin_len
= sizeof(*sin
);
491 sin
->sin_family
= AF_INET
;
492 sin
->sin_addr
.s_addr
= 0;
493 for (n
= 0; n
< 4; n
++) {
494 sin
->sin_addr
.s_addr
|=
495 htonl((ho
[n
] & 0xff) << ((3 - n
) * 8));
497 sin
->sin_port
= htons(((po
[0] & 0xff) << 8) | (po
[1] & 0xff));
499 /* get ready for passive data connection */
500 memset(&data6
, 0, sizeof(data6
));
501 sin6
= (struct sockaddr_in6
*)&data6
;
502 sin6
->sin6_len
= sizeof(*sin6
);
503 sin6
->sin6_family
= AF_INET6
;
504 wport6
= socket(sin6
->sin6_family
, SOCK_STREAM
, 0);
507 n
= snprintf(sbuf
, sizeof(sbuf
),
508 "500 could not translate from PASV\r\n");
515 error
= setsockopt(wport6
, IPPROTO_IPV6
, IPV6_FAITH
,
518 exit_failure("setsockopt(IPV6_FAITH): %s", strerror(errno
));
521 error
= bind(wport6
, (struct sockaddr
*)sin6
, sin6
->sin6_len
);
527 error
= listen(wport6
, 1);
534 /* transmit LPSV or EPSV */
536 * addr from dst, port from wport6
539 error
= getsockname(wport6
, (struct sockaddr
*)&data6
, &n
);
545 sin6
= (struct sockaddr_in6
*)&data6
;
546 port
= sin6
->sin6_port
;
549 error
= getsockname(dst
, (struct sockaddr
*)&data6
, &n
);
555 sin6
= (struct sockaddr_in6
*)&data6
;
556 sin6
->sin6_port
= port
;
561 a
= (char *)&sin6
->sin6_addr
;
562 p
= (char *)&sin6
->sin6_port
;
563 n
= snprintf(sbuf
, sizeof(sbuf
),
564 "228 Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)\r\n",
565 6, 16, UC(a
[0]), UC(a
[1]), UC(a
[2]), UC(a
[3]),
566 UC(a
[4]), UC(a
[5]), UC(a
[6]), UC(a
[7]),
567 UC(a
[8]), UC(a
[9]), UC(a
[10]), UC(a
[11]),
568 UC(a
[12]), UC(a
[13]), UC(a
[14]), UC(a
[15]),
569 2, UC(p
[0]), UC(p
[1]));
574 n
= snprintf(sbuf
, sizeof(sbuf
),
575 "229 Entering Extended Passive Mode (|||%d|)\r\n",
576 ntohs(sin6
->sin6_port
));
584 /* expecting "229 Entering Extended Passive Mode (|||x|)" */
596 struct sockaddr_in
*sin
;
597 struct sockaddr_in6
*sin6
;
600 * EPSV result -> PORT result
603 while (*p
&& *p
!= '(') /*)*/
606 goto passivefail1
; /*XXX*/
608 n
= sscanf(p
, "|||%hu|", &port
);
610 goto passivefail1
; /*XXX*/
612 /* keep EPRT parameter */
614 error
= getpeername(src
, (struct sockaddr
*)&data4
, &n
);
616 goto passivefail1
; /*XXX*/
617 sin6
= (struct sockaddr_in6
*)&data4
;
618 sin6
->sin6_port
= htons(port
);
620 /* get ready for passive data connection */
621 memset(&data6
, 0, sizeof(data6
));
622 sin
= (struct sockaddr_in
*)&data6
;
623 sin
->sin_len
= sizeof(*sin
);
624 sin
->sin_family
= AF_INET
;
625 wport6
= socket(sin
->sin_family
, SOCK_STREAM
, 0);
628 n
= snprintf(sbuf
, sizeof(sbuf
),
629 "500 could not translate from EPSV\r\n");
636 error
= setsockopt(wport6
, IPPROTO_IP
, IP_FAITH
,
639 exit_error("setsockopt(IP_FAITH): %s", strerror(errno
));
642 error
= bind(wport6
, (struct sockaddr
*)sin
, sin
->sin_len
);
648 error
= listen(wport6
, 1);
657 * addr from dst, port from wport6
660 error
= getsockname(wport6
, (struct sockaddr
*)&data6
, &n
);
666 sin
= (struct sockaddr_in
*)&data6
;
667 port
= sin
->sin_port
;
670 error
= getsockname(dst
, (struct sockaddr
*)&data6
, &n
);
676 sin
= (struct sockaddr_in
*)&data6
;
677 sin
->sin_port
= port
;
682 a
= (char *)&sin
->sin_addr
;
683 p
= (char *)&sin
->sin_port
;
684 n
= snprintf(sbuf
, sizeof(sbuf
),
685 "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",
686 UC(a
[0]), UC(a
[1]), UC(a
[2]), UC(a
[3]),
697 exit_failure("%s", strerror(errno
));
699 return 0; /* to make gcc happy */
703 ftp_copycommand(int src
, int dst
, enum state
*state
)
707 unsigned int af
, hal
, ho
[16], pal
, po
[2];
710 struct sockaddr_in
*sin
;
711 struct sockaddr_in6
*sin6
;
715 /* OOB data handling */
716 error
= ioctl(src
, SIOCATMARK
, &atmark
);
717 if (error
!= -1 && atmark
== 1) {
718 n
= read(src
, rbuf
, 1);
721 send(dst
, rbuf
, n
, MSG_OOB
);
723 n
= read(src
, rbuf
, sizeof(rbuf
));
731 n
= read(src
, rbuf
, sizeof(rbuf
));
750 for (i
= 0; i
< 4; i
++) {
752 /* invalid command */
756 *q
++ = islower(*p
) ? toupper(*p
) : *p
;
760 /* invalid command */
766 /* param points to first non-command token, if any */
767 while (*param
&& isspace(*param
))
775 if (strcmp(cmd
, "LPRT") == 0 && param
) {
785 wport4
= wport6
= port4
= port6
= -1;
788 n
= snprintf(sbuf
, sizeof(sbuf
), "501 %s disallowed in EPSV ALL\r\n",
795 "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
796 &af
, &hal
, &ho
[0], &ho
[1], &ho
[2], &ho
[3],
797 &ho
[4], &ho
[5], &ho
[6], &ho
[7],
798 &ho
[8], &ho
[9], &ho
[10], &ho
[11],
799 &ho
[12], &ho
[13], &ho
[14], &ho
[15],
800 &pal
, &po
[0], &po
[1]);
801 if (n
!= 21 || af
!= 6 || hal
!= 16|| pal
!= 2) {
802 n
= snprintf(sbuf
, sizeof(sbuf
),
803 "501 illegal parameter to LPRT\r\n");
808 /* keep LPRT parameter */
809 memset(&data6
, 0, sizeof(data6
));
810 sin6
= (struct sockaddr_in6
*)&data6
;
811 sin6
->sin6_len
= sizeof(*sin6
);
812 sin6
->sin6_family
= AF_INET6
;
813 for (n
= 0; n
< 16; n
++)
814 sin6
->sin6_addr
.s6_addr
[n
] = ho
[n
];
815 sin6
->sin6_port
= htons(((po
[0] & 0xff) << 8) | (po
[1] & 0xff));
818 /* get ready for active data connection */
820 error
= getsockname(dst
, (struct sockaddr
*)&data4
, &n
);
823 n
= snprintf(sbuf
, sizeof(sbuf
),
824 "500 could not translate to PORT\r\n");
828 if (((struct sockaddr
*)&data4
)->sa_family
!= AF_INET
)
830 sin
= (struct sockaddr_in
*)&data4
;
832 wport4
= socket(sin
->sin_family
, SOCK_STREAM
, 0);
835 error
= bind(wport4
, (struct sockaddr
*)sin
, sin
->sin_len
);
841 error
= listen(wport4
, 1);
850 error
= getsockname(wport4
, (struct sockaddr
*)&data4
, &n
);
856 if (((struct sockaddr
*)&data4
)->sa_family
!= AF_INET
) {
861 sin
= (struct sockaddr_in
*)&data4
;
862 a
= (char *)&sin
->sin_addr
;
863 p
= (char *)&sin
->sin_port
;
864 n
= snprintf(sbuf
, sizeof(sbuf
), "PORT %d,%d,%d,%d,%d,%d\r\n",
865 UC(a
[0]), UC(a
[1]), UC(a
[2]), UC(a
[3]),
871 } else if (strcmp(cmd
, "EPRT") == 0 && param
) {
875 char *afp
, *hostp
, *portp
;
876 struct addrinfo hints
, *res
;
884 wport4
= wport6
= port4
= port6
= -1;
887 n
= snprintf(sbuf
, sizeof(sbuf
), "501 %s disallowed in EPSV ALL\r\n",
894 ch
= *p
++; /* boundary character */
896 while (*p
&& *p
!= ch
)
900 n
= snprintf(sbuf
, sizeof(sbuf
),
901 "501 illegal parameter to EPRT\r\n");
907 while (*p
&& *p
!= ch
)
913 while (*p
&& *p
!= ch
)
919 n
= sscanf(afp
, "%d", &af
);
920 if (n
!= 1 || af
!= 2) {
921 n
= snprintf(sbuf
, sizeof(sbuf
),
922 "501 unsupported address family to EPRT\r\n");
926 memset(&hints
, 0, sizeof(hints
));
927 hints
.ai_family
= AF_UNSPEC
;
928 hints
.ai_socktype
= SOCK_STREAM
;
929 error
= getaddrinfo(hostp
, portp
, &hints
, &res
);
931 n
= snprintf(sbuf
, sizeof(sbuf
),
932 "501 EPRT: %s\r\n", gai_strerror(error
));
937 n
= snprintf(sbuf
, sizeof(sbuf
),
938 "501 EPRT: %s resolved to multiple addresses\r\n", hostp
);
943 memcpy(&data6
, res
->ai_addr
, res
->ai_addrlen
);
946 } else if (strcmp(cmd
, "LPSV") == 0 && !param
) {
956 wport4
= wport6
= port4
= port6
= -1;
959 n
= snprintf(sbuf
, sizeof(sbuf
), "501 %s disallowed in EPSV ALL\r\n",
966 n
= snprintf(sbuf
, sizeof(sbuf
), "PASV\r\n");
969 passivemode
= 0; /* to be set to 1 later */
971 } else if (strcmp(cmd
, "EPSV") == 0 && !param
) {
979 wport4
= wport6
= port4
= port6
= -1;
981 n
= snprintf(sbuf
, sizeof(sbuf
), "PASV\r\n");
984 passivemode
= 0; /* to be set to 1 later */
986 } else if (strcmp(cmd
, "EPSV") == 0 && param
987 && strncasecmp(param
, "ALL", 3) == 0 && isspace(param
[3])) {
992 n
= snprintf(sbuf
, sizeof(sbuf
), "200 EPSV ALL command successful.\r\n");
996 } else if (strcmp(cmd
, "PORT") == 0 && param
) {
1000 char host
[NI_MAXHOST
], serv
[NI_MAXSERV
];
1008 wport4
= wport6
= port4
= port6
= -1;
1011 n
= sscanf(p
, "%u,%u,%u,%u,%u,%u",
1012 &ho
[0], &ho
[1], &ho
[2], &ho
[3], &po
[0], &po
[1]);
1014 n
= snprintf(sbuf
, sizeof(sbuf
),
1015 "501 illegal parameter to PORT\r\n");
1016 write(src
, sbuf
, n
);
1020 memset(&data6
, 0, sizeof(data6
));
1021 sin
= (struct sockaddr_in
*)&data6
;
1022 sin
->sin_len
= sizeof(*sin
);
1023 sin
->sin_family
= AF_INET
;
1024 sin
->sin_addr
.s_addr
= htonl(
1025 ((ho
[0] & 0xff) << 24) | ((ho
[1] & 0xff) << 16) |
1026 ((ho
[2] & 0xff) << 8) | (ho
[3] & 0xff));
1027 sin
->sin_port
= htons(((po
[0] & 0xff) << 8) | (po
[1] & 0xff));
1029 /* get ready for active data connection */
1031 error
= getsockname(dst
, (struct sockaddr
*)&data4
, &n
);
1034 n
= snprintf(sbuf
, sizeof(sbuf
),
1035 "500 could not translate to EPRT\r\n");
1036 write(src
, sbuf
, n
);
1039 if (((struct sockaddr
*)&data4
)->sa_family
!= AF_INET6
)
1042 ((struct sockaddr_in6
*)&data4
)->sin6_port
= 0;
1043 sa
= (struct sockaddr
*)&data4
;
1044 wport4
= socket(sa
->sa_family
, SOCK_STREAM
, 0);
1047 error
= bind(wport4
, sa
, sa
->sa_len
);
1053 error
= listen(wport4
, 1);
1062 error
= getsockname(wport4
, (struct sockaddr
*)&data4
, &n
);
1069 sa
= (struct sockaddr
*)&data4
;
1070 if (getnameinfo(sa
, sa
->sa_len
, host
, sizeof(host
),
1071 serv
, sizeof(serv
), NI_NUMERICHOST
| NI_NUMERICSERV
)) {
1076 n
= snprintf(sbuf
, sizeof(sbuf
), "EPRT |%d|%s|%s|\r\n", af
, host
, serv
);
1077 write(dst
, sbuf
, n
);
1081 } else if (strcmp(cmd
, "PASV") == 0 && !param
) {
1092 wport4
= wport6
= port4
= port6
= -1;
1095 n
= snprintf(sbuf
, sizeof(sbuf
), "EPSV\r\n");
1096 write(dst
, sbuf
, n
);
1098 passivemode
= 0; /* to be set to 1 later */
1101 } else if (strcmp(cmd
, "PORT") == 0 || strcmp(cmd
, "PASV") == 0) {
1105 n
= snprintf(sbuf
, sizeof(sbuf
), "502 %s not implemented.\r\n", cmd
);
1106 write(src
, sbuf
, n
);
1109 } else if (passivemode
1110 && (strcmp(cmd
, "STOR") == 0
1111 || strcmp(cmd
, "STOU") == 0
1112 || strcmp(cmd
, "RETR") == 0
1113 || strcmp(cmd
, "LIST") == 0
1114 || strcmp(cmd
, "NLST") == 0
1115 || strcmp(cmd
, "APPE") == 0)) {
1117 * commands with data transfer. need to care about passive
1118 * mode data connection.
1121 if (ftp_passiveconn() < 0) {
1122 n
= snprintf(sbuf
, sizeof(sbuf
), "425 Cannot open data connetion\r\n");
1123 write(src
, sbuf
, n
);
1125 /* simply relay the command */
1126 write(dst
, rbuf
, n
);
1132 /* simply relay it */
1134 write(dst
, rbuf
, n
);
1139 exit_failure("%s", strerror(errno
));
1141 return 0; /* to make gcc happy */