1 /* ftp.c
2  *
3  * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft.
4  * All rights reserved.
5  *
6  */
7 
8 #define _libncftp_ftp_c_
9 #include "syshdrs.h"
10 
11 char gLibNcFTPVersion[64] = kLibraryVersion;
12 
13 #ifdef NO_SIGNALS
14 char gNoSignalsMarker[] = "@(#) LibNcFTP - NO_SIGNALS";
15 #else
16 
17 static int gGotSig = 0;
18 #ifdef HAVE_SIGSETJMP
19 static sigjmp_buf gCancelConnectJmp;
20 #else
21 static jmp_buf gCancelConnectJmp;
22 #endif
23 
24 #endif
25 
26 
27 #ifndef lint
28 static char gCopyright[] = "@(#) LibNcFTP Copyright 1995-2000, by Mike Gleason.  All rights reserved.";
29 #endif
30 
31 #ifdef HAVE_LIBSOCKS5
32 #	define SOCKS 5
33 #	include <socks.h>
34 #else
35 #	ifdef HAVE_LIBSOCKS
36 #		define accept		Raccept
37 #		define connect		Rconnect
38 #		define getsockname	Rgetsockname
39 #		define listen		Rlisten
40 #	endif
41 #endif
42 
43 
44 
45 
46 /* On entry, you should have 'host' be set to a symbolic name (like
47  * cse.unl.edu), or set to a numeric address (like 129.93.3.1).
48  * If the function fails, it will return NULL, but if the host was
49  * a numeric style address, you'll have the ip_address to fall back on.
50  */
51 
52 static struct hostent *
GetHostEntry(char * host,struct in_addr * ip_address)53 GetHostEntry(char *host, struct in_addr *ip_address)
54 {
55 	struct in_addr ip;
56 	struct hostent *hp;
57 
58 	/* See if the host was given in the dotted IP format, like "36.44.0.2."
59 	 * If it was, inet_addr will convert that to a 32-bit binary value;
60 	 * it not, inet_addr will return (-1L).
61 	 */
62 	ip.s_addr = inet_addr(host);
63 	if (ip.s_addr != INADDR_NONE) {
64 		hp = NULL;
65 	} else {
66 		/* No IP address, so it must be a hostname, like ftp.wustl.edu. */
67 		hp = gethostbyname(host);
68 		if (hp != NULL)
69 			(void) memcpy(&ip.s_addr, hp->h_addr_list[0], (size_t) hp->h_length);
70 	}
71 	if (ip_address != NULL)
72 		*ip_address = ip;
73 	return (hp);
74 }	/* GetHostEntry */
75 
76 
77 
78 
79 /* Makes every effort to return a fully qualified domain name. */
80 int
GetOurHostName(char * host,size_t siz)81 GetOurHostName(char *host, size_t siz)
82 {
83 #ifdef HOSTNAME
84 	/* You can hardcode in the name if this routine doesn't work
85 	 * the way you want it to.
86 	 */
87 	Strncpy(host, HOSTNAME, siz);
88 	return (1);		/* Success */
89 #else
90 	struct hostent *hp;
91 	int result;
92 	char **curAlias;
93 	char domain[64];
94 	char *cp;
95 	int rc;
96 
97 	host[0] = '\0';
98 	result = gethostname(host, (int) siz);
99 	if ((result < 0) || (host[0] == '\0')) {
100 		return (-1);
101 	}
102 
103 	if (strchr(host, '.') != NULL) {
104 		/* gethostname returned full name (like "cse.unl.edu"), instead
105 		 * of just the node name (like "cse").
106 		 */
107 		return (2);		/* Success */
108 	}
109 
110 	hp = gethostbyname(host);
111 	if (hp != NULL) {
112 		/* Maybe the host entry has the full name. */
113 		cp = strchr((char *) hp->h_name, '.');
114 		if ((cp != NULL) && (cp[1] != '\0')) {
115 			/* The 'name' field for the host entry had full name. */
116 			(void) Strncpy(host, (char *) hp->h_name, siz);
117 			return (3);		/* Success */
118 		}
119 
120 		/* Now try the list of aliases, to see if any of those look real. */
121 		for (curAlias = hp->h_aliases; *curAlias != NULL; curAlias++) {
122 			cp = strchr(*curAlias, '.');
123 			if ((cp != NULL) && (cp[1] != '\0')) {
124 				(void) Strncpy(host, *curAlias, siz);
125 				return (4);		/* Success */
126 			}
127 		}
128 	}
129 
130 	/* Otherwise, we just have the node name.  See if we can get the
131 	 * domain name ourselves.
132 	 */
133 #ifdef DOMAINNAME
134 	(void) STRNCPY(domain, DOMAINNAME);
135 	rc = 5;
136 #else
137 	rc = -1;
138 	domain[0] = '\0';
139 #	if defined(HAVE_RES_INIT) && defined(HAVE__RES_DEFDNAME)
140 	if (domain[0] == '\0') {
141 		(void) res_init();
142 		if ((_res.defdname != NULL) && (_res.defdname[0] != '\0')) {
143 			(void) STRNCPY(domain, _res.defdname);
144 			rc = 6;
145 		}
146 	}
147 #	endif	/* HAVE_RES_INIT && HAVE__RES_DEFDNAME */
148 
149 	if (domain[0] == '\0') {
150 		FILE *fp;
151 		char line[256];
152 		char *tok;
153 
154 		fp = fopen("/etc/resolv.conf", "r");
155 		if (fp != NULL) {
156 			(void) memset(line, 0, sizeof(line));
157 			while (fgets(line, sizeof(line) - 1, fp) != NULL) {
158 				if (!isalpha((int) line[0]))
159 					continue;	/* Skip comment lines. */
160 				tok = strtok(line, " \t\n\r");
161 				if (tok == NULL)
162 					continue;	/* Impossible */
163 				if (strcmp(tok, "domain") == 0) {
164 					tok = strtok(NULL, " \t\n\r");
165 					if (tok == NULL)
166 						continue;	/* syntax error */
167 					(void) STRNCPY(domain, tok);
168 					rc = 7;
169 					break;	/* Done. */
170 				}
171 			}
172 			(void) fclose(fp);
173 		}
174 	}
175 #endif	/* DOMAINNAME */
176 
177 	if (domain[0] != '\0') {
178 		/* Supposedly, it's legal for a domain name with
179 		 * a period at the end.
180 		 */
181 		cp = domain + strlen(domain) - 1;
182 		if (*cp == '.')
183 			*cp = '\0';
184 		if (domain[0] != '.')
185 			(void) Strncat(host, ".", siz);
186 		(void) Strncat(host, domain, siz);
187 	}
188 	if (rc < 0)
189 		host[0] = '\0';
190 	return(rc);	/* Success */
191 #endif	/* !HOSTNAME */
192 }	/* GetOurHostName */
193 
194 
195 
196 void
CloseControlConnection(const FTPCIPtr cip)197 CloseControlConnection(const FTPCIPtr cip)
198 {
199 	/* This will close each file, if it was open. */
200 #ifdef NO_SIGNALS
201 	SClose(cip->ctrlSocketR, 3);
202 	cip->ctrlSocketR = kClosedFileDescriptor;
203 	cip->ctrlSocketW = kClosedFileDescriptor;
204 	DisposeSReadlineInfo(&cip->ctrlSrl);
205 #else	/* NO_SIGNALS */
206 	if (cip->ctrlTimeout > 0)
207 		(void) alarm(cip->ctrlTimeout);
208 	CloseFile(&cip->cin);
209 	CloseFile(&cip->cout);
210 	cip->ctrlSocketR = kClosedFileDescriptor;
211 	cip->ctrlSocketW = kClosedFileDescriptor;
212 	if (cip->ctrlTimeout > 0)
213 		(void) alarm(0);
214 #endif	/* NO_SIGNALS */
215 	cip->connected = 0;
216 	cip->loggedIn = 0;
217 }	/* CloseControlConnection */
218 
219 
220 
221 static int
GetSocketAddress(const FTPCIPtr cip,int sockfd,struct sockaddr_in * saddr)222 GetSocketAddress(const FTPCIPtr cip, int sockfd, struct sockaddr_in *saddr)
223 {
224 	int len = (int) sizeof (struct sockaddr_in);
225 	int result = 0;
226 
227 	if (getsockname(sockfd, (struct sockaddr *)saddr, &len) < 0) {
228 		Error(cip, kDoPerror, "Could not get socket name.\n");
229 		cip->errNo = kErrGetSockName;
230 		result = kErrGetSockName;
231 	}
232 	return (result);
233 }	/* GetSocketAddress */
234 
235 
236 
237 
238 int
SetKeepAlive(const FTPCIPtr cip,int sockfd)239 SetKeepAlive(const FTPCIPtr cip, int sockfd)
240 {
241 #ifndef SO_KEEPALIVE
242 	cip->errNo = kErrSetKeepAlive;
243 	return (kErrSetKeepAlive);
244 #else
245 	int opt;
246 
247 	opt = 1;
248 
249 	if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, (int) sizeof(opt)) < 0) {
250 		/* Error(cip, kDoPerror, "Could not set keep-alive mode.\n"); */
251 		cip->errNo = kErrSetKeepAlive;
252 		return (kErrSetKeepAlive);
253 	}
254 	return (kNoErr);
255 #endif	/* SO_KEEPALIVE */
256 }	/* SetKeepAlive */
257 
258 
259 
260 
261 int
SetLinger(const FTPCIPtr cip,int sockfd,int onoff)262 SetLinger(const FTPCIPtr cip, int sockfd, int onoff)
263 {
264 #ifndef SO_LINGER
265 	cip->errNo = kErrSetLinger;
266 	return (kErrSetLinger);
267 #else
268 	struct linger li;
269 
270 	if (onoff != 0) {
271 		li.l_onoff = 1;
272 		li.l_linger = 120;	/* 2 minutes, but system ignores field. */
273 	} else {
274 		li.l_onoff = 0;
275 		li.l_linger = 0;
276 	}
277 	/* Have the system make an effort to deliver any unsent data,
278 	 * even after we close the connection.
279 	 */
280 	if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char *) &li, (int) sizeof(li)) < 0) {
281 		/* Error(cip, kDoPerror, "Could not set linger mode.\n"); */
282 		cip->errNo = kErrSetLinger;
283 		return (kErrSetLinger);
284 	}
285 	return (kNoErr);
286 #endif	/* SO_LINGER */
287 }	/* SetLinger */
288 
289 
290 
291 
292 #ifdef IP_TOS
293 int
SetTypeOfService(const FTPCIPtr cip,int sockfd,int tosType)294 SetTypeOfService(const FTPCIPtr cip, int sockfd, int tosType)
295 {
296 	/* Specify to the router what type of connection this is, so it
297 	 * can prioritize packets.
298 	 */
299 	if (setsockopt(sockfd, IPPROTO_IP, IP_TOS, (char *) &tosType, (int) sizeof(tosType)) < 0) {
300 		/* Error(cip, kDoPerror, "Could not set type of service.\n"); */
301 		cip->errNo = kErrSetTypeOfService;
302 		return (kErrSetTypeOfService);
303 	}
304 	return (kNoErr);
305 }	/* SetTypeOfService */
306 #endif	/* IP_TOS */
307 
308 
309 
310 
311 #ifdef SO_OOBINLINE
312 int
SetInlineOutOfBandData(const FTPCIPtr cip,int sockfd)313 SetInlineOutOfBandData(const FTPCIPtr cip, int sockfd)
314 {
315 	int on = 1;
316 
317 	if (setsockopt(sockfd, SOL_SOCKET, SO_OOBINLINE, (char *) &on, (int) sizeof(on)) < 0) {
318 		Error(cip, kDoPerror, "Could not set out of band inline mode.\n");
319 		cip->errNo = kErrSetOutOfBandInline;
320 		return (kErrSetOutOfBandInline);
321 	}
322 	return (kNoErr);
323 }	/* SetInlineOutOfBandData */
324 #endif /* SO_OOBINLINE */
325 
326 
327 
328 
329 #ifndef NO_SIGNALS
330 
331 static void
CancelConnect(int signum)332 CancelConnect(int signum)
333 {
334 	gGotSig = signum;
335 #ifdef HAVE_SIGSETJMP
336 	siglongjmp(gCancelConnectJmp, 1);
337 #else
338 	longjmp(gCancelConnectJmp, 1);
339 #endif	/* HAVE_SIGSETJMP */
340 }	/* CancelConnect */
341 
342 #endif	/* NO_SIGNALS */
343 
344 
345 
346 int
OpenControlConnection(const FTPCIPtr cip,char * host,unsigned int port)347 OpenControlConnection(const FTPCIPtr cip, char *host, unsigned int port)
348 {
349 	struct in_addr ip_address;
350 	int err = 0;
351 	int result;
352 	int oerrno;
353 	volatile int sockfd = -1;
354 	volatile int sock2fd = -1;
355 	ResponsePtr rp;
356 	char **volatile curaddr;
357 	struct hostent *hp;
358 	char *volatile fhost;
359 	unsigned int fport;
360 #ifndef NO_SIGNALS
361 	volatile FTPSigProc osigint;
362 	volatile FTPSigProc osigalrm;
363 	volatile FTPCIPtr vcip;
364 	int sj;
365 #endif	/* NO_SIGNALS */
366 	const char *firstLine, *secondLine, *srvr;
367 
368 	LIBNCFTP_USE_VAR(gLibNcFTPVersion);
369 	LIBNCFTP_USE_VAR(gCopyright);
370 #ifdef NO_SIGNALS
371 	LIBNCFTP_USE_VAR(gNoSignalsMarker);
372 #endif	/* NO_SIGNALS */
373 
374 	if (cip->firewallType == kFirewallNotInUse) {
375 		fhost = host;
376 		fport = port;
377 	} else {
378 		fhost = cip->firewallHost;
379 		fport = cip->firewallPort;
380 	}
381 	if (fport == 0)
382 		fport = cip->lip->defaultPort;
383 
384 	/* Since we're the client, we just have to get a socket() and
385 	 * connect() it.
386 	 */
387 	(void) ZERO(cip->servCtlAddr);
388 	cip->cin = NULL;
389 	cip->cout = NULL;
390 
391 	/* Make sure we use network byte-order. */
392 	fport = (unsigned int) htons((unsigned short) fport);
393 
394 	cip->servCtlAddr.sin_port = (unsigned short) fport;
395 
396 	hp = GetHostEntry(fhost, &ip_address);
397 
398 	if (hp == NULL) {
399 		/* Okay, no Host entry, but maybe we have a numeric address
400 		 * in ip_address we can try.
401 		 */
402 		if (ip_address.s_addr == INADDR_NONE) {
403 			Error(cip, kDontPerror, "%s: unknown host.\n", fhost);
404 			cip->errNo = kErrHostUnknown;
405 			return (kErrHostUnknown);
406 		}
407 		cip->servCtlAddr.sin_family = AF_INET;
408 		cip->servCtlAddr.sin_addr.s_addr = ip_address.s_addr;
409 	} else {
410 		cip->servCtlAddr.sin_family = hp->h_addrtype;
411 		/* We'll fill in the rest of the structure below. */
412 	}
413 
414 	/* After obtaining a socket, try to connect it to a remote
415 	 * address.  If we didn't get a host entry, we will only have
416 	 * one thing to try (ip_address);  if we do have one, we can try
417 	 * every address in the list from the host entry.
418 	 */
419 
420 	if (hp == NULL) {
421 		/* Since we're given a single raw address, and not a host entry,
422 		 * we can only try this one address and not any other addresses
423 		 * that could be present for a site with a host entry.
424 		 */
425 
426 		if ((sockfd = socket(cip->servCtlAddr.sin_family, SOCK_STREAM, 0)) < 0) {
427 			Error(cip, kDoPerror, "Could not get a socket.\n");
428 			cip->errNo = kErrNewStreamSocket;
429 			return (kErrNewStreamSocket);
430 		}
431 
432 		/* This doesn't do anything if you left these
433 		 * at their defaults (zero).  Otherwise it
434 		 * tries to set the buffer size to the
435 		 * size specified.
436 		 */
437 		(void) SetSockBufSize(sockfd, cip->ctrlSocketRBufSize, cip->ctrlSocketSBufSize);
438 
439 #ifdef NO_SIGNALS
440 		err = SConnect(sockfd, &cip->servCtlAddr, (int) cip->connTimeout);
441 
442 		if (err < 0) {
443 			oerrno = errno;
444 			(void) SClose(sockfd, 3);
445 			errno = oerrno;
446 			sockfd = -1;
447 		}
448 #else	/* NO_SIGNALS */
449 		osigint = (volatile FTPSigProc) signal(SIGINT, CancelConnect);
450 		if (cip->connTimeout > 0) {
451 			osigalrm = (volatile FTPSigProc) signal(SIGALRM, CancelConnect);
452 			(void) alarm(cip->connTimeout);
453 		}
454 
455 		vcip = cip;
456 
457 #ifdef HAVE_SIGSETJMP
458 		sj = sigsetjmp(gCancelConnectJmp, 1);
459 #else
460 		sj = setjmp(gCancelConnectJmp);
461 #endif	/* HAVE_SIGSETJMP */
462 
463 		if (sj != 0) {
464 			/* Interrupted by a signal. */
465 			(void) closesocket(sockfd);
466 			(void) signal(SIGINT, (FTPSigProc) osigint);
467 			if (vcip->connTimeout > 0) {
468 				(void) alarm(0);
469 				(void) signal(SIGALRM, (FTPSigProc) osigalrm);
470 			}
471 			if (gGotSig == SIGINT) {
472 				result = vcip->errNo = kErrConnectMiscErr;
473 				Error(vcip, kDontPerror, "Connection attempt canceled.\n");
474 				(void) kill(getpid(), SIGINT);
475 			} else if (gGotSig == SIGALRM) {
476 				result = vcip->errNo = kErrConnectRetryableErr;
477 				Error(vcip, kDontPerror, "Connection attempt timed-out.\n");
478 				(void) kill(getpid(), SIGALRM);
479 			} else {
480 				result = vcip->errNo = kErrConnectMiscErr;
481 				Error(vcip, kDontPerror, "Connection attempt failed due to an unexpected signal (%d).\n", gGotSig);
482 			}
483 			return (result);
484 		} else  {
485 			err = connect(sockfd, (struct sockaddr *) &cip->servCtlAddr,
486 				      (int) sizeof (cip->servCtlAddr));
487 			if (cip->connTimeout > 0) {
488 				(void) alarm(0);
489 				(void) signal(SIGALRM, (FTPSigProc) osigalrm);
490 			}
491 			(void) signal(SIGINT, (FTPSigProc) osigint);
492 		}
493 
494 		if (err < 0) {
495 			oerrno = errno;
496 			(void) closesocket(sockfd);
497 			errno = oerrno;
498 			sockfd = -1;
499 		}
500 #endif	/* NO_SIGNALS */
501 	} else {
502 		/* We can try each address in the list.  We'll quit when we
503 		 * run out of addresses to try or get a successful connection.
504 		 */
505 		for (curaddr = hp->h_addr_list; *curaddr != NULL; curaddr++) {
506 			if ((sockfd = socket(cip->servCtlAddr.sin_family, SOCK_STREAM, 0)) < 0) {
507 				Error(cip, kDoPerror, "Could not get a socket.\n");
508 				cip->errNo = kErrNewStreamSocket;
509 				return (kErrNewStreamSocket);
510 			}
511 			/* This could overwrite the address field in the structure,
512 			 * but this is okay because the structure has a junk field
513 			 * just for this purpose.
514 			 */
515 			(void) memcpy(&cip->servCtlAddr.sin_addr, *curaddr, (size_t) hp->h_length);
516 
517 			/* This doesn't do anything if you left these
518 			 * at their defaults (zero).  Otherwise it
519 			 * tries to set the buffer size to the
520 			 * size specified.
521 			 */
522 			(void) SetSockBufSize(sockfd, cip->ctrlSocketRBufSize, cip->ctrlSocketSBufSize);
523 
524 #ifdef NO_SIGNALS
525 			err = SConnect(sockfd, &cip->servCtlAddr, (int) cip->connTimeout);
526 
527 			if (err == 0)
528 				break;
529 			oerrno = errno;
530 			(void) SClose(sockfd, 3);
531 			errno = oerrno;
532 			sockfd = -1;
533 #else	/* NO_SIGNALS */
534 
535 			osigint = (volatile FTPSigProc) signal(SIGINT, CancelConnect);
536 			if (cip->connTimeout > 0) {
537 				osigalrm = (volatile FTPSigProc) signal(SIGALRM, CancelConnect);
538 				(void) alarm(cip->connTimeout);
539 			}
540 
541 			vcip = cip;
542 #ifdef HAVE_SIGSETJMP
543 			sj = sigsetjmp(gCancelConnectJmp, 1);
544 #else
545 			sj = setjmp(gCancelConnectJmp);
546 #endif	/* HAVE_SIGSETJMP */
547 
548 			if (sj != 0) {
549 				/* Interrupted by a signal. */
550 				(void) closesocket(sockfd);
551 				(void) signal(SIGINT, (FTPSigProc) osigint);
552 				if (vcip->connTimeout > 0) {
553 					(void) alarm(0);
554 					(void) signal(SIGALRM, (FTPSigProc) osigalrm);
555 				}
556 				if (gGotSig == SIGINT) {
557 					result = vcip->errNo = kErrConnectMiscErr;
558 					Error(vcip, kDontPerror, "Connection attempt canceled.\n");
559 					(void) kill(getpid(), SIGINT);
560 				} else if (gGotSig == SIGALRM) {
561 					result = vcip->errNo = kErrConnectRetryableErr;
562 					Error(vcip, kDontPerror, "Connection attempt timed-out.\n");
563 					(void) kill(getpid(), SIGALRM);
564 				} else {
565 					result = vcip->errNo = kErrConnectMiscErr;
566 					Error(vcip, kDontPerror, "Connection attempt failed due to an unexpected signal (%d).\n", gGotSig);
567 				}
568 				return (result);
569 			} else {
570 				err = connect(sockfd, (struct sockaddr *) &cip->servCtlAddr,
571 					      (int) sizeof (cip->servCtlAddr));
572 				if (cip->connTimeout > 0) {
573 					(void) alarm(0);
574 					(void) signal(SIGALRM, (FTPSigProc) osigalrm);
575 				}
576 				(void) signal(SIGINT, (FTPSigProc) osigint);
577 			}
578 
579 			if (err == 0)
580 				break;
581 			oerrno = errno;
582 			(void) closesocket(sockfd);
583 			errno = oerrno;
584 			sockfd = -1;
585 #endif /* NO_SIGNALS */
586 		}
587 	}
588 
589 	if (err < 0) {
590 		/* Could not connect.  Close up shop and go home. */
591 
592 		/* If possible, tell the caller if they should bother
593 		 * calling back later.
594 		 */
595 		switch (errno) {
596 #ifdef ENETDOWN
597 			case ENETDOWN:
598 #elif defined(WSAENETDOWN)
599 			case WSAENETDOWN:
600 #endif
601 #ifdef ENETUNREACH
602 			case ENETUNREACH:
603 #elif defined(WSAENETUNREACH)
604 			case WSAENETUNREACH:
605 #endif
606 #ifdef ECONNABORTED
607 			case ECONNABORTED:
608 #elif defined(WSAECONNABORTED)
609 			case WSAECONNABORTED:
610 #endif
611 #ifdef ETIMEDOUT
612 			case ETIMEDOUT:
613 #elif defined(WSAETIMEDOUT)
614 			case WSAETIMEDOUT:
615 #endif
616 #ifdef EHOSTDOWN
617 			case EHOSTDOWN:
618 #elif defined(WSAEHOSTDOWN)
619 			case WSAEHOSTDOWN:
620 #endif
621 #ifdef ECONNRESET
622 			case ECONNRESET:
623 #elif defined(WSAECONNRESET)
624 			case WSAECONNRESET:
625 #endif
626 				Error(cip, kDoPerror, "Could not connect to %s -- try again later.\n", fhost);
627 				result = cip->errNo = kErrConnectRetryableErr;
628 				break;
629 #ifdef ECONNREFUSED
630 			case ECONNREFUSED:
631 #elif defined(WSAECONNREFUSED)
632 			case WSAECONNREFUSED:
633 #endif
634 				Error(cip, kDoPerror, "Could not connect to %s.\n", fhost);
635 				result = cip->errNo = kErrConnectRefused;
636 				break;
637 			default:
638 				Error(cip, kDoPerror, "Could not connect to %s.\n", fhost);
639 				result = cip->errNo = kErrConnectMiscErr;
640 		}
641 		goto fatal;
642 	}
643 
644 	/* Get our end of the socket address for later use. */
645 	if ((result = GetSocketAddress(cip, sockfd, &cip->ourCtlAddr)) < 0)
646 		goto fatal;
647 
648 #ifdef SO_OOBINLINE
649 	/* We want Out-of-band data to appear in the regular stream,
650 	 * since we can handle TELNET.
651 	 */
652 	(void) SetInlineOutOfBandData(cip, sockfd);
653 #endif
654 	(void) SetKeepAlive(cip, sockfd);
655 	(void) SetLinger(cip, sockfd, 0);	/* Don't need it for ctrl. */
656 
657 #if defined(IP_TOS) && defined(IPTOS_LOWDELAY)
658 	/* Control connection is somewhat interactive, so quick response
659 	 * is desired.
660 	 */
661 	(void) SetTypeOfService(cip, sockfd, IPTOS_LOWDELAY);
662 #endif
663 
664 #ifdef NO_SIGNALS
665 	cip->ctrlSocketR = sockfd;
666 	cip->ctrlSocketW = sockfd;
667 	cip->cout = NULL;
668 	cip->cin = NULL;
669 	sock2fd = kClosedFileDescriptor;
670 
671 	if (InitSReadlineInfo(&cip->ctrlSrl, sockfd, cip->srlBuf, sizeof(cip->srlBuf), (int) cip->ctrlTimeout, 1) < 0) {
672 		result = kErrFdopenW;
673 		cip->errNo = kErrFdopenW;
674 		Error(cip, kDoPerror, "Could not fdopen.\n");
675 		goto fatal;
676 	}
677 #else	/* NO_SIGNALS */
678 	if ((sock2fd = dup(sockfd)) < 0) {
679 		result = kErrDupSocket;
680 		cip->errNo = kErrDupSocket;
681 		Error(cip, kDoPerror, "Could not duplicate a file descriptor.\n");
682 		goto fatal;
683 	}
684 
685 	/* Now setup the FILE pointers for use with the Std I/O library
686 	 * routines.
687 	 */
688 	if ((cip->cin = fdopen(sockfd, "r")) == NULL) {
689 		result = kErrFdopenR;
690 		cip->errNo = kErrFdopenR;
691 		Error(cip, kDoPerror, "Could not fdopen.\n");
692 		goto fatal;
693 	}
694 
695 	if ((cip->cout = fdopen(sock2fd, "w")) == NULL) {
696 		result = kErrFdopenW;
697 		cip->errNo = kErrFdopenW;
698 		Error(cip, kDoPerror, "Could not fdopen.\n");
699 		CloseFile(&cip->cin);
700 		sockfd = kClosedFileDescriptor;
701 		goto fatal;
702 	}
703 
704 	cip->ctrlSocketR = sockfd;
705 	cip->ctrlSocketW = sockfd;
706 
707 	/* We'll be reading and writing lines, so use line buffering.  This
708 	 * is necessary since the stdio library will use full buffering
709 	 * for all streams not associated with the tty.
710 	 */
711 #ifdef HAVE_SETLINEBUF
712 	setlinebuf(cip->cin);
713 	setlinebuf(cip->cout);
714 #else
715 	(void) SETVBUF(cip->cin, NULL, _IOLBF, (size_t) BUFSIZ);
716 	(void) SETVBUF(cip->cout, NULL, _IOLBF, (size_t) BUFSIZ);
717 #endif
718 #endif	/* NO_SIGNALS */
719 
720 #ifdef HAVE_INET_NTOP	/* Mostly to workaround bug in IRIX 6.5's inet_ntoa */
721 	(void) memset(cip->ip, 0, sizeof(cip->ip));
722 	(void) inet_ntop(AF_INET, &cip->servCtlAddr.sin_addr, cip->ip, sizeof(cip->ip) - 1);
723 #else
724 	(void) STRNCPY(cip->ip, inet_ntoa(cip->servCtlAddr.sin_addr));
725 #endif
726 	if ((hp == NULL) || (hp->h_name == NULL))
727 		(void) STRNCPY(cip->actualHost, fhost);
728 	else
729 		(void) STRNCPY(cip->actualHost, (char *) hp->h_name);
730 
731 	/* Read the startup message from the server. */
732 	rp = InitResponse();
733 	if (rp == NULL) {
734 		Error(cip, kDontPerror, "Malloc failed.\n");
735 		cip->errNo = kErrMallocFailed;
736 		result = cip->errNo;
737 		goto fatal;
738 	}
739 
740 	result = GetResponse(cip, rp);
741 	if ((result < 0) && (rp->msg.first == NULL)) {
742 		goto fatal;
743 	}
744 	if (rp->msg.first != NULL) {
745 		cip->serverType = kServerTypeUnknown;
746 		srvr = NULL;
747 		firstLine = rp->msg.first->line;
748 		secondLine = NULL;
749 		if (rp->msg.first->next != NULL)
750 			secondLine = rp->msg.first->next->line;
751 
752 		if (strstr(firstLine, "Version wu-") != NULL) {
753 			cip->serverType = kServerTypeWuFTPd;
754 			srvr = "wu-ftpd";
755 		} else if (strstr(firstLine, "NcFTPd") != NULL) {
756 			cip->serverType = kServerTypeNcFTPd;
757 			srvr = "NcFTPd Server";
758 		} else if (STRNEQ("ProFTPD", firstLine, 7)) {
759 			cip->serverType = kServerTypeProFTPD;
760 			srvr = "ProFTPD";
761 		} else if (strstr(firstLine, "Microsoft FTP Service") != NULL) {
762 			cip->serverType = kServerTypeMicrosoftFTP;
763 			srvr = "Microsoft FTP Service";
764 		} else if (strstr(firstLine, "(NetWare ") != NULL) {
765 			cip->serverType = kServerTypeNetWareFTP;
766 			srvr = "NetWare FTP Service";
767 		} else if (STRNEQ("WFTPD", firstLine, 5)) {
768 			cip->serverType = kServerTypeWFTPD;
769 			srvr = "WFTPD";
770 		} else if (STRNEQ("Serv-U FTP", firstLine, 10)) {
771 			cip->serverType = kServerTypeServ_U;
772 			srvr = "Serv-U FTP-Server";
773 		} else if (strstr(firstLine, "VFTPD") != NULL) {
774 			cip->serverType = kServerTypeVFTPD;
775 			srvr = "VFTPD";
776 		} else if (STRNEQ("FTP-Max", firstLine, 7)) {
777 			cip->serverType = kServerTypeFTP_Max;
778 			srvr = "FTP-Max";
779 		} else if (strstr(firstLine, "Roxen") != NULL) {
780 			cip->serverType = kServerTypeRoxen;
781 			srvr = "Roxen";
782 		} else if (strstr(firstLine, "WS_FTP") != NULL) {
783 			cip->serverType = kServerTypeWS_FTP;
784 			srvr = "WS_FTP Server";
785 		} else if ((secondLine != NULL) && (strstr(secondLine, "WarFTP") != NULL)) {
786 			cip->serverType = kServerTypeWarFTPd;
787 			srvr = "WarFTPd";
788 		}
789 
790 		if (srvr != NULL)
791 			PrintF(cip, "Remote server is running %s.\n", srvr);
792 
793 		/* Do the application's connect message callback, if present. */
794 		if ((cip->onConnectMsgProc != 0) && (rp->codeType < 4))
795 			(*cip->onConnectMsgProc)(cip, rp);
796 	}
797 
798 	if (rp->codeType >= 4) {
799 		/* They probably hung up on us right away.  That's too bad,
800 		 * but we can tell the caller that they can call back later
801 		 * and try again.
802 		 */
803 		DoneWithResponse(cip, rp);
804 		result = kErrConnectRetryableErr;
805 		Error(cip, kDontPerror, "Server hungup immediately after connect.\n");
806 		cip->errNo = kErrConnectRetryableErr;
807 		goto fatal;
808 	}
809 	if (result < 0)		/* Some other error occurred during connect message */
810 		goto fatal;
811 	cip->connected = 1;
812 	DoneWithResponse(cip, rp);
813 	return (kNoErr);
814 
815 fatal:
816 	if (sockfd > 0)
817 		(void) closesocket(sockfd);
818 	if (sock2fd > 0)
819 		(void) closesocket(sock2fd);
820 	CloseFile(&cip->cin);
821 	CloseFile(&cip->cout);
822 	cip->ctrlSocketR = kClosedFileDescriptor;
823 	cip->ctrlSocketW = kClosedFileDescriptor;
824 	return (result);
825 }	/* OpenControlConnection */
826 
827 
828 
829 
830 void
CloseDataConnection(const FTPCIPtr cip)831 CloseDataConnection(const FTPCIPtr cip)
832 {
833 	if (cip->dataSocket != kClosedFileDescriptor) {
834 #ifdef NO_SIGNALS
835 		SClose(cip->dataSocket, 3);
836 #else	/* NO_SIGNALS */
837 		if (cip->xferTimeout > 0)
838 			(void) alarm(cip->xferTimeout);
839 		(void) closesocket(cip->dataSocket);
840 		if (cip->xferTimeout > 0)
841 			(void) alarm(0);
842 #endif	/* NO_SIGNALS */
843 		cip->dataSocket = kClosedFileDescriptor;
844 	}
845 	memset(&cip->ourDataAddr, 0, sizeof(cip->ourDataAddr));
846 	memset(&cip->servDataAddr, 0, sizeof(cip->servDataAddr));
847 }	/* CloseDataConnection */
848 
849 
850 
851 
852 int
SetStartOffset(const FTPCIPtr cip,longest_int restartPt)853 SetStartOffset(const FTPCIPtr cip, longest_int restartPt)
854 {
855 	ResponsePtr rp;
856 	int result;
857 
858 	if (restartPt != (longest_int) 0) {
859 		rp = InitResponse();
860 		if (rp == NULL) {
861 			Error(cip, kDontPerror, "Malloc failed.\n");
862 			cip->errNo = kErrMallocFailed;
863 			return (cip->errNo);
864 		}
865 
866 		/* Force reset to offset zero. */
867 		if (restartPt == (longest_int) -1)
868 			restartPt = (longest_int) 0;
869 #ifdef PRINTF_LONG_LONG
870 		result = RCmd(cip, rp,
871 		"REST " PRINTF_LONG_LONG,
872 		restartPt);
873 #else
874 		result = RCmd(cip, rp, "REST %ld", (long) restartPt);
875 #endif
876 
877 		if (result < 0) {
878 			return (result);
879 		} else if (result == 3) {
880 			cip->hasREST = kCommandAvailable;
881 			DoneWithResponse(cip, rp);
882 		} else if (UNIMPLEMENTED_CMD(rp->code)) {
883 			cip->hasREST = kCommandNotAvailable;
884 			DoneWithResponse(cip, rp);
885 			cip->errNo = kErrSetStartPoint;
886 			return (kErrSetStartPoint);
887 		} else {
888 			DoneWithResponse(cip, rp);
889 			cip->errNo = kErrSetStartPoint;
890 			return (kErrSetStartPoint);
891 		}
892 	}
893 	return (0);
894 }	/* SetStartOffset */
895 
896 
897 
898 static int
SendPort(const FTPCIPtr cip,struct sockaddr_in * saddr)899 SendPort(const FTPCIPtr cip, struct sockaddr_in *saddr)
900 {
901 	char *a, *p;
902 	int result;
903 	ResponsePtr rp;
904 
905 	rp = InitResponse();
906 	if (rp == NULL) {
907 		Error(cip, kDontPerror, "Malloc failed.\n");
908 		cip->errNo = kErrMallocFailed;
909 		return (cip->errNo);
910 	}
911 
912 	/* These will point to data in network byte order. */
913 	a = (char *) &saddr->sin_addr;
914 	p = (char *) &saddr->sin_port;
915 #define UC(x) (int) (((int) x) & 0xff)
916 
917 	/* Need to tell the other side which host (the address) and
918 	 * which process (port) on that host to send data to.
919 	 */
920 	result = RCmd(cip, rp, "PORT %d,%d,%d,%d,%d,%d",
921 		UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
922 
923 	if (result < 0) {
924 		return (result);
925 	} else if (result != 2) {
926 		/* A 500'ish response code means the PORT command failed. */
927 		DoneWithResponse(cip, rp);
928 		cip->errNo = kErrPORTFailed;
929 		return (cip->errNo);
930 	}
931 	DoneWithResponse(cip, rp);
932 	return (kNoErr);
933 }	/* SendPort */
934 
935 
936 
937 
938 static int
Passive(const FTPCIPtr cip,struct sockaddr_in * saddr,int * weird)939 Passive(const FTPCIPtr cip, struct sockaddr_in *saddr, int *weird)
940 {
941 	ResponsePtr rp;
942 	int i[6], j;
943 	unsigned char n[6];
944 	char *cp;
945 	int result;
946 
947 	rp = InitResponse();
948 	if (rp == NULL) {
949 		Error(cip, kDontPerror, "Malloc failed.\n");
950 		cip->errNo = kErrMallocFailed;
951 		return (cip->errNo);
952 	}
953 
954 	result = RCmd(cip, rp, "PASV");
955 	if (result < 0)
956 		goto done;
957 
958 	if (rp->codeType != 2) {
959 		/* Didn't understand or didn't want passive port selection. */
960 		cip->errNo = result = kErrPASVFailed;
961 		goto done;
962 	}
963 
964 	/* The other side returns a specification in the form of
965 	 * an internet address as the first four integers (each
966 	 * integer stands for 8-bits of the real 32-bit address),
967 	 * and two more integers for the port (16-bit port).
968 	 *
969 	 * It should give us something like:
970 	 * "Entering Passive Mode (129,93,33,1,10,187)", so look for
971 	 * digits with sscanf() starting 24 characters down the string.
972 	 */
973 	for (cp = rp->msg.first->line; ; cp++) {
974 		if (*cp == '\0') {
975 			Error(cip, kDontPerror, "Cannot parse PASV response: %s\n", rp->msg.first->line);
976 			goto done;
977 		}
978 		if (isdigit((int) *cp))
979 			break;
980 	}
981 
982 	if (sscanf(cp, "%d,%d,%d,%d,%d,%d",
983 			&i[0], &i[1], &i[2], &i[3], &i[4], &i[5]) != 6) {
984 		Error(cip, kDontPerror, "Cannot parse PASV response: %s\n", rp->msg.first->line);
985 		goto done;
986 	}
987 
988 	for (j=0, *weird = 0; j<6; j++) {
989 		/* Some ftp servers return bogus port octets, such as
990 		 * boombox.micro.umn.edu.  Let the caller know if we got a
991 		 * weird looking octet.
992 		 */
993 		if ((i[j] < 0) || (i[j] > 255))
994 			*weird = *weird + 1;
995 		n[j] = (unsigned char) (i[j] & 0xff);
996 	}
997 
998 	(void) memcpy(&saddr->sin_addr, &n[0], (size_t) 4);
999 	(void) memcpy(&saddr->sin_port, &n[4], (size_t) 2);
1000 
1001 	result = kNoErr;
1002 done:
1003 	DoneWithResponse(cip, rp);
1004 	return (result);
1005 }	/* Passive */
1006 
1007 
1008 
1009 
1010 static int
BindToEphemeralPortNumber(int sockfd,struct sockaddr_in * addrp,int ephemLo,int ephemHi)1011 BindToEphemeralPortNumber(int sockfd, struct sockaddr_in *addrp, int ephemLo, int ephemHi)
1012 {
1013 	int i;
1014 	int result;
1015 	int rangesize;
1016 	unsigned short port;
1017 
1018 	addrp->sin_family = AF_INET;
1019 	if (((int) ephemLo == 0) || ((int) ephemLo >= (int) ephemHi)) {
1020 		/* Do it the normal way.  System will
1021 		 * pick one, typically in the range
1022 		 * of 1024-4999.
1023 		 */
1024 		addrp->sin_port = 0;	/* Let system pick one. */
1025 
1026 		result = bind(sockfd, (struct sockaddr *) addrp, sizeof(struct sockaddr_in));
1027 	} else {
1028 		rangesize = (int) ((int) ephemHi - (int) ephemLo);
1029 		result = 0;
1030 		for (i=0; i<10; i++) {
1031 			port = (unsigned short) (((int) rand() % rangesize) + (int) ephemLo);
1032 			addrp->sin_port = port;
1033 
1034 			result = bind(sockfd, (struct sockaddr *) addrp, sizeof(struct sockaddr_in));
1035 			if (result == 0)
1036 				break;
1037 			if ((errno != 999)
1038 				/* This next line is just fodder to
1039 				 * shut the compiler up about variable
1040 				 * not being used.
1041 				 */
1042 				&& (gCopyright[0] != '\0'))
1043 				break;
1044 		}
1045 	}
1046 	return (result);
1047 }	/* BindToEphemeralPortNumber */
1048 
1049 
1050 
1051 
1052 int
OpenDataConnection(const FTPCIPtr cip,int mode)1053 OpenDataConnection(const FTPCIPtr cip, int mode)
1054 {
1055 	int dataSocket;
1056 	int weirdPort;
1057 	int result;
1058 
1059 	/* Before we can transfer any data, and before we even ask the
1060 	 * remote server to start transferring via RETR/NLST/etc, we have
1061 	 * to setup the connection.
1062 	 */
1063 
1064 tryPort2:
1065 	weirdPort = 0;
1066 	result = 0;
1067 	CloseDataConnection(cip);	/* In case we didn't before... */
1068 
1069 	dataSocket = socket(AF_INET, SOCK_STREAM, 0);
1070 	if (dataSocket < 0) {
1071 		Error(cip, kDoPerror, "Could not get a data socket.\n");
1072 		result = kErrNewStreamSocket;
1073 		cip->errNo = kErrNewStreamSocket;
1074 		return result;
1075 	}
1076 
1077 	/* This doesn't do anything if you left these
1078 	 * at their defaults (zero).  Otherwise it
1079 	 * tries to set the buffer size to the
1080 	 * size specified.
1081 	 */
1082 	(void) SetSockBufSize(dataSocket, cip->dataSocketRBufSize, cip->dataSocketSBufSize);
1083 
1084 	if ((cip->hasPASV == kCommandNotAvailable) || (mode == kSendPortMode)) {
1085 tryPort:
1086 		cip->ourDataAddr = cip->ourCtlAddr;
1087 		cip->ourDataAddr.sin_family = AF_INET;
1088 
1089 #ifdef HAVE_LIBSOCKS
1090 		cip->ourDataAddr.sin_port = 0;
1091 		if (Rbind(dataSocket, (struct sockaddr *) &cip->ourDataAddr,
1092 			(int) sizeof (cip->ourDataAddr),
1093 			cip->servCtlAddr.sin_addr.s_addr) < 0)
1094 #else
1095 		if (BindToEphemeralPortNumber(dataSocket, &cip->ourDataAddr, (int) cip->ephemLo, (int) cip->ephemHi) < 0)
1096 #endif
1097 		{
1098 			Error(cip, kDoPerror, "Could not bind the data socket");
1099 			result = kErrBindDataSocket;
1100 			cip->errNo = kErrBindDataSocket;
1101 			goto bad;
1102 		}
1103 
1104 		/* Need to do this so we can figure out which port the system
1105 		 * gave to us.
1106 		 */
1107 		if ((result = GetSocketAddress(cip, dataSocket, &cip->ourDataAddr)) < 0)
1108 			goto bad;
1109 
1110 		if (listen(dataSocket, 1) < 0) {
1111 			Error(cip, kDoPerror, "listen failed");
1112 			result = kErrListenDataSocket;
1113 			cip->errNo = kErrListenDataSocket;
1114 			goto bad;
1115 		}
1116 
1117 		if ((result = SendPort(cip, &cip->ourDataAddr)) < 0)
1118 			goto bad;
1119 
1120 		cip->dataPortMode = kSendPortMode;
1121 	} else {
1122 		/* Passive mode.  Let the other side decide where to send. */
1123 
1124 		cip->servDataAddr = cip->servCtlAddr;
1125 		cip->servDataAddr.sin_family = AF_INET;
1126 		cip->ourDataAddr = cip->ourCtlAddr;
1127 		cip->ourDataAddr.sin_family = AF_INET;
1128 
1129 		if (Passive(cip, &cip->servDataAddr, &weirdPort) < 0) {
1130 			Error(cip, kDontPerror, "Passive mode refused.\n");
1131 			cip->hasPASV = kCommandNotAvailable;
1132 
1133 			/* We can try using regular PORT commands, which are required
1134 			 * by all FTP protocol compliant programs, if you said so.
1135 			 *
1136 			 * We don't do this automatically, because if your host
1137 			 * is running a firewall you (probably) do not want SendPort
1138 			 * FTP for security reasons.
1139 			 */
1140 			if (mode == kFallBackToSendPortMode)
1141 				goto tryPort;
1142 			result = kErrPassiveModeFailed;
1143 			cip->errNo = kErrPassiveModeFailed;
1144 			goto bad;
1145 		}
1146 
1147 #ifdef HAVE_LIBSOCKS
1148 		cip->ourDataAddr.sin_port = 0;
1149 		if (Rbind(dataSocket, (struct sockaddr *) &cip->ourDataAddr,
1150 			(int) sizeof (cip->ourDataAddr),
1151 			cip->servCtlAddr.sin_addr.s_addr) < 0)
1152 #else
1153 		if (BindToEphemeralPortNumber(dataSocket, &cip->ourDataAddr, (int) cip->ephemLo, (int) cip->ephemHi) < 0)
1154 #endif
1155 		{
1156 			Error(cip, kDoPerror, "Could not bind the data socket");
1157 			result = kErrBindDataSocket;
1158 			cip->errNo = kErrBindDataSocket;
1159 			goto bad;
1160 		}
1161 
1162 #ifdef NO_SIGNALS
1163 		result = SConnect(dataSocket, &cip->servDataAddr, (int) cip->connTimeout);
1164 #else	/* NO_SIGNALS */
1165 		if (cip->connTimeout > 0)
1166 			(void) alarm(cip->connTimeout);
1167 
1168 		result = connect(dataSocket, (struct sockaddr *) &cip->servDataAddr, (int) sizeof(cip->servDataAddr));
1169 		if (cip->connTimeout > 0)
1170 			(void) alarm(0);
1171 #endif	/* NO_SIGNALS */
1172 
1173 #ifdef NO_SIGNALS
1174 		if (result == kTimeoutErr) {
1175 			if (mode == kFallBackToSendPortMode) {
1176 				Error(cip, kDontPerror, "Data connection timed out.\n");
1177 				Error(cip, kDontPerror, "Falling back to PORT instead of PASV mode.\n");
1178 				(void) closesocket(dataSocket);
1179 				cip->hasPASV = kCommandNotAvailable;
1180 				goto tryPort2;
1181 			}
1182 			Error(cip, kDontPerror, "Data connection timed out.\n");
1183 			result = kErrConnectDataSocket;
1184 			cip->errNo = kErrConnectDataSocket;
1185 		} else
1186 #endif	/* NO_SIGNALS */
1187 
1188 		if (result < 0) {
1189 #ifdef ECONNREFUSED
1190 			if ((weirdPort > 0) && (errno == ECONNREFUSED)) {
1191 #elif defined(WSAECONNREFUSED)
1192 			if ((weirdPort > 0) && (errno == WSAECONNREFUSED)) {
1193 #endif
1194 				Error(cip, kDontPerror, "Server sent back a bogus port number.\nI will fall back to PORT instead of PASV mode.\n");
1195 				if (mode == kFallBackToSendPortMode) {
1196 					(void) closesocket(dataSocket);
1197 					cip->hasPASV = kCommandNotAvailable;
1198 					goto tryPort2;
1199 				}
1200 				result = kErrServerSentBogusPortNumber;
1201 				cip->errNo = kErrServerSentBogusPortNumber;
1202 				goto bad;
1203 			}
1204 			if (mode == kFallBackToSendPortMode) {
1205 				Error(cip, kDoPerror, "connect failed.\n");
1206 				Error(cip, kDontPerror, "Falling back to PORT instead of PASV mode.\n");
1207 				(void) closesocket(dataSocket);
1208 				cip->hasPASV = kCommandNotAvailable;
1209 				goto tryPort2;
1210 			}
1211 			Error(cip, kDoPerror, "connect failed.\n");
1212 			result = kErrConnectDataSocket;
1213 			cip->errNo = kErrConnectDataSocket;
1214 			goto bad;
1215 		}
1216 
1217 		/* Need to do this so we can figure out which port the system
1218 		 * gave to us.
1219 		 */
1220 		if ((result = GetSocketAddress(cip, dataSocket, &cip->ourDataAddr)) < 0)
1221 			goto bad;
1222 
1223 		cip->dataPortMode = kPassiveMode;
1224 		cip->hasPASV = kCommandAvailable;
1225 	}
1226 
1227 	(void) SetLinger(cip, dataSocket, 1);
1228 	(void) SetKeepAlive(cip, dataSocket);
1229 
1230 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
1231 	/* Data connection is a non-interactive data stream, so
1232 	 * high throughput is desired, at the expense of low
1233 	 * response time.
1234 	 */
1235 	(void) SetTypeOfService(cip, dataSocket, IPTOS_THROUGHPUT);
1236 #endif
1237 
1238 	cip->dataSocket = dataSocket;
1239 	return (0);
1240 bad:
1241 	(void) closesocket(dataSocket);
1242 	return (result);
1243 }	/* OpenDataConnection */
1244 
1245 
1246 
1247 
1248 int
1249 AcceptDataConnection(const FTPCIPtr cip)
1250 {
1251 	int newSocket;
1252 #ifndef NO_SIGNALS
1253 	int len;
1254 #endif
1255 	unsigned short remoteDataPort;
1256 	unsigned short remoteCtrlPort;
1257 
1258 	/* If we did a PORT, we have some things to finish up.
1259 	 * If we did a PASV, we're ready to go.
1260 	 */
1261 	if (cip->dataPortMode == kSendPortMode) {
1262 		/* Accept will give us back the server's data address;  at the
1263 		 * moment we don't do anything with it though.
1264 		 */
1265 		memset(&cip->servDataAddr, 0, sizeof(cip->servDataAddr));
1266 
1267 #ifdef NO_SIGNALS
1268 		newSocket = SAccept(cip->dataSocket, &cip->servDataAddr, (int) cip->connTimeout);
1269 #else	/* NO_SIGNALS */
1270 		len = (int) sizeof(cip->servDataAddr);
1271 		if (cip->connTimeout > 0)
1272 			(void) alarm(cip->connTimeout);
1273 		newSocket = accept(cip->dataSocket, (struct sockaddr *) &cip->servDataAddr, &len);
1274 		if (cip->connTimeout > 0)
1275 			(void) alarm(0);
1276 #endif	/* NO_SIGNALS */
1277 
1278 		(void) closesocket(cip->dataSocket);
1279 		if (newSocket < 0) {
1280 			Error(cip, kDoPerror, "Could not accept a data connection.\n");
1281 			cip->dataSocket = kClosedFileDescriptor;
1282 			cip->errNo = kErrAcceptDataSocket;
1283 			return (kErrAcceptDataSocket);
1284 		}
1285 
1286 		if (cip->require20 != 0) {
1287 			remoteDataPort = ntohs(cip->servDataAddr.sin_port);
1288 			remoteCtrlPort = ntohs(cip->servCtlAddr.sin_port);
1289 			if ((int) remoteDataPort != ((int) remoteCtrlPort - 1)) {
1290 				Error(cip, kDontPerror, "Data connection did not originate on correct port!\n");
1291 				(void) closesocket(newSocket);
1292 				cip->dataSocket = kClosedFileDescriptor;
1293 				cip->errNo = kErrAcceptDataSocket;
1294 				return (kErrAcceptDataSocket);
1295 			} else if (memcmp(&cip->servDataAddr.sin_addr.s_addr, &cip->servCtlAddr.sin_addr.s_addr, sizeof(cip->servDataAddr.sin_addr.s_addr)) != 0) {
1296 				Error(cip, kDontPerror, "Data connection did not originate from remote server!\n");
1297 				(void) closesocket(newSocket);
1298 				cip->dataSocket = kClosedFileDescriptor;
1299 				cip->errNo = kErrAcceptDataSocket;
1300 				return (kErrAcceptDataSocket);
1301 			}
1302 		}
1303 
1304 		cip->dataSocket = newSocket;
1305 	}
1306 
1307 	return (0);
1308 }	/* AcceptDataConnection */
1309 
1310 
1311 
1312 
1313 void
1314 HangupOnServer(const FTPCIPtr cip)
1315 {
1316 	/* Since we want to close both sides of the connection for each
1317 	 * socket, we can just have them closed with close() instead of
1318 	 * using shutdown().
1319 	 */
1320 	CloseControlConnection(cip);
1321 	CloseDataConnection(cip);
1322 }	/* HangupOnServer */
1323 
1324 
1325 
1326 
1327 void
1328 SendTelnetInterrupt(const FTPCIPtr cip)
1329 {
1330 	char msg[4];
1331 
1332 	/* 1. User system inserts the Telnet "Interrupt Process" (IP) signal
1333 	 *    in the Telnet stream.
1334 	 */
1335 
1336 	if (cip->cout != NULL)
1337 		(void) fflush(cip->cout);
1338 
1339 	msg[0] = (char) (unsigned char) IAC;
1340 	msg[1] = (char) (unsigned char) IP;
1341 	(void) send(cip->ctrlSocketW, msg, 2, 0);
1342 
1343 	/* 2. User system sends the Telnet "Sync" signal. */
1344 #if 1
1345 	msg[0] = (char) (unsigned char) IAC;
1346 	msg[1] = (char) (unsigned char) DM;
1347 	if (send(cip->ctrlSocketW, msg, 2, MSG_OOB) != 2)
1348 		Error(cip, kDoPerror, "Could not send an urgent message.\n");
1349 #else
1350 	/* "Send IAC in urgent mode instead of DM because UNIX places oob mark
1351 	 * after urgent byte rather than before as now is protocol," says
1352 	 * the BSD ftp code.
1353 	 */
1354 	msg[0] = (char) (unsigned char) IAC;
1355 	if (send(cip->ctrlSocketW, msg, 1, MSG_OOB) != 1)
1356 		Error(cip, kDoPerror, "Could not send an urgent message.\n");
1357 	(void) fprintf(cip->cout, "%c", DM);
1358 	(void) fflush(cip->cout);
1359 #endif
1360 }	/* SendTelnetInterrupt */
1361 
1362 /* eof FTP.c */
1363