1 /* util.c
2  *
3  * Copyright (c) 1992-2001 by Mike Gleason.
4  * All rights reserved.
5  *
6  */
7 
8 #include "syshdrs.h"
9 #include "shell.h"
10 #include "trace.h"
11 #include "util.h"
12 
13 uid_t gUid;
14 char gUser[32];
15 char gHome[256];
16 char gShell[256];
17 char gOurDirectoryPath[260];
18 char gOurInstallationPath[260];
19 #ifdef ncftp
20 static int gResolveSig;
21 #endif
22 
23 #if defined(WIN32) || defined(_WINDOWS)
24 #elif defined(HAVE_SIGSETJMP)
25 sigjmp_buf gGetHostByNameJmp;
26 #else	/* HAVE_SIGSETJMP */
27 jmp_buf gGetHostByNameJmp;
28 #endif	/* HAVE_SIGSETJMP */
29 
30 #ifndef HAVE_MEMMOVE
31 void *memmove(void *dst0, void *src0, size_t length);
32 #endif
33 
34 static const unsigned char B64EncodeTable[64] =
35 {
36 	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
37 	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
38 	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
39 	'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
40 	'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
41 	'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
42 	'w', 'x', 'y', 'z', '0', '1', '2', '3',
43 	'4', '5', '6', '7', '8', '9', '+', '/'
44 };
45 
46 static const unsigned char B64DecodeTable[256] =
47 {
48 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 000-007 */
49 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 010-017 */
50 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 020-027 */
51 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 030-037 */
52 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 040-047 */
53 	'\177', '\177', '\177', '\76', '\177', '\177', '\177', '\77',	/* 050-057 */
54 	'\64', '\65', '\66', '\67', '\70', '\71', '\72', '\73',		/* 060-067 */
55 	'\74', '\75', '\177', '\177', '\177', '\100', '\177', '\177',	/* 070-077 */
56 	'\177', '\0', '\1', '\2', '\3', '\4', '\5', '\6',	/* 100-107 */
57 	'\7', '\10', '\11', '\12', '\13', '\14', '\15', '\16',	/* 110-117 */
58 	'\17', '\20', '\21', '\22', '\23', '\24', '\25', '\26',		/* 120-127 */
59 	'\27', '\30', '\31', '\177', '\177', '\177', '\177', '\177',	/* 130-137 */
60 	'\177', '\32', '\33', '\34', '\35', '\36', '\37', '\40',	/* 140-147 */
61 	'\41', '\42', '\43', '\44', '\45', '\46', '\47', '\50',		/* 150-157 */
62 	'\51', '\52', '\53', '\54', '\55', '\56', '\57', '\60',		/* 160-167 */
63 	'\61', '\62', '\63', '\177', '\177', '\177', '\177', '\177',	/* 170-177 */
64 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 200-207 */
65 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 210-217 */
66 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 220-227 */
67 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 230-237 */
68 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 240-247 */
69 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 250-257 */
70 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 260-267 */
71 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 270-277 */
72 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 300-307 */
73 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 310-317 */
74 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 320-327 */
75 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 330-337 */
76 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 340-347 */
77 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 350-357 */
78 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 360-367 */
79 	'\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177',		/* 370-377 */
80 };
81 
82 void
ToBase64(void * dst0,const void * src0,size_t n,int terminate)83 ToBase64(void *dst0, const void *src0, size_t n, int terminate)
84 {
85 	unsigned char *dst;
86 	const unsigned char *src, *srclim;
87 	unsigned int c0, c1, c2;
88 	unsigned int ch;
89 
90 	src = src0;
91 	srclim = src + n;
92 	dst = dst0;
93 
94 	while (src < srclim) {
95 		c0 = *src++;
96 		if (src < srclim) {
97 			c1 = *src++;
98 		} else {
99 			c1 = 0;
100 		}
101 		if (src < srclim) {
102 			c2 = *src++;
103 		} else {
104 			c2 = 0;
105 		}
106 
107 		ch = c0 >> 2;
108 		dst[0] = B64EncodeTable[ch & 077];
109 
110 		ch = ((c0 << 4) & 060) | ((c1 >> 4) & 017);
111 		dst[1] = B64EncodeTable[ch & 077];
112 
113 		ch = ((c1 << 2) & 074) | ((c2 >> 6) & 03);
114 		dst[2] = B64EncodeTable[ch & 077];
115 
116 		ch = (c2 & 077);
117 		dst[3] = B64EncodeTable[ch & 077];
118 
119 		dst += 4;
120 	}
121 	if (terminate != 0)
122 		*dst = '\0';
123 }						       /* ToBase64 */
124 
125 
126 
127 void
FromBase64(void * dst0,const void * src0,size_t n,int terminate)128 FromBase64(void *dst0, const void *src0, size_t n, int terminate)
129 {
130 	unsigned char *dst;
131 	const unsigned char *src, *srclim;
132 	unsigned int c0, c1, c2, c3;
133 	unsigned int ch;
134 
135 	src = src0;
136 	srclim = src + n;
137 	dst = dst0;
138 
139 	while (src < srclim) {
140 		c0 = *src++;
141 		if (src < srclim) {
142 			c1 = *src++;
143 		} else {
144 			c1 = 0;
145 		}
146 		if (src < srclim) {
147 			c2 = *src++;
148 		} else {
149 			c2 = 0;
150 		}
151 		if (src < srclim) {
152 			c3 = *src++;
153 		} else {
154 			c3 = 0;
155 		}
156 
157 		ch = (((unsigned int) B64DecodeTable[c0]) << 2) | (((unsigned int) B64DecodeTable[c1]) >> 4);
158 		dst[0] = (unsigned char) ch;
159 
160 		ch = (((unsigned int) B64DecodeTable[c1]) << 4) | (((unsigned int) B64DecodeTable[c2]) >> 2);
161 		dst[1] = (unsigned char) ch;
162 
163 		ch = (((unsigned int) B64DecodeTable[c2]) << 6) | (((unsigned int) B64DecodeTable[c3]));
164 		dst[2] = (unsigned char) ch;
165 
166 		dst += 3;
167 	}
168 	if (terminate != 0)
169 		*dst = '\0';
170 }						       /* FromBase64 */
171 
172 /* This should only be called if the program wouldn't function
173  * usefully without the memory requested.
174  */
175 void
OutOfMemory(void)176 OutOfMemory(void)
177 {
178 	(void) fprintf(stderr, "Out of memory!\n");
179 	exit(1);
180 }	/* OutOfMemory */
181 
182 
183 
184 void
MyInetAddr(char * dst,size_t siz,char ** src,int i)185 MyInetAddr(char *dst, size_t siz, char **src, int i)
186 {
187 	struct in_addr *ia;
188 #ifndef HAVE_INET_NTOP
189 	char *cp;
190 #endif
191 
192 	(void) Strncpy(dst, "???", siz);
193 	if (src != (char **) 0) {
194 		ia = (struct in_addr *) src[i];
195 #ifdef HAVE_INET_NTOP	/* Mostly to workaround bug in IRIX 6.5's inet_ntoa */
196 		(void) inet_ntop(AF_INET, ia, dst, siz - 1);
197 #else
198 		cp = inet_ntoa(*ia);
199 		if ((cp != (char *) 0) && (cp != (char *) -1) && (cp[0] != '\0'))
200 			(void) Strncpy(dst, cp, siz);
201 #endif
202 	}
203 }	/* MyInetAddr */
204 
205 
206 
207 
208 /* On entry, you should have 'host' be set to a symbolic name (like
209  * cse.unl.edu), or set to a numeric address (like 129.93.3.1).
210  * If the function fails, it will return NULL, but if the host was
211  * a numeric style address, you'll have the ip_address to fall back on.
212  */
213 
214 struct hostent *
GetHostEntry(const char * host,struct in_addr * ip_address)215 GetHostEntry(const char *host, struct in_addr *ip_address)
216 {
217 	struct in_addr ip;
218 	struct hostent *hp;
219 
220 	/* See if the host was given in the dotted IP format, like "36.44.0.2."
221 	 * If it was, inet_addr will convert that to a 32-bit binary value;
222 	 * it not, inet_addr will return (-1L).
223 	 */
224 	ip.s_addr = inet_addr(host);
225 	if (ip.s_addr != INADDR_NONE) {
226 		hp = gethostbyaddr((char *) &ip, (int) sizeof(ip), AF_INET);
227 	} else {
228 		/* No IP address, so it must be a hostname, like ftp.wustl.edu. */
229 		hp = gethostbyname(host);
230 		if (hp != NULL)
231 			ip = * (struct in_addr *) hp->h_addr_list;
232 	}
233 	if (ip_address != NULL)
234 		*ip_address = ip;
235 	return (hp);
236 }	/* GetHostEntry */
237 
238 
239 
240 /* This simplifies a pathname, by converting it to the
241  * equivalent of "cd $dir ; dir=`pwd`".  In other words,
242  * if $PWD==/usr/spool/uucp, and you had a path like
243  * "$PWD/../tmp////./../xx/", it would be converted to
244  * "/usr/spool/xx".
245  */
246 void
CompressPath(char * const dst,const char * const src,const size_t dsize)247 CompressPath(char *const dst, const char *const src, const size_t dsize)
248 {
249 	int c;
250 	const char *s;
251 	char *d, *lim;
252 	char *a, *b;
253 
254 	if (src[0] == '\0') {
255 		*dst = '\0';
256 		return;
257 	}
258 
259 	s = src;
260 	d = dst;
261 	lim = d + dsize - 1;	/* leave room for nul byte. */
262 	for (;;) {
263 		c = *s;
264 		if (c == '.') {
265 			if (((s == src) || (s[-1] == '/')) && ((s[1] == '/') || (s[1] == '\0'))) {
266 				/* Don't copy "./" */
267 				if (s[1] == '/')
268 					++s;
269 				++s;
270 			} else if (d < lim) {
271 				*d++ = *s++;
272 			} else {
273 				++s;
274 			}
275 		} else if (c == '/') {
276 			/* Don't copy multiple slashes. */
277 			if (d < lim)
278 				*d++ = *s++;
279 			else
280 				++s;
281 			for (;;) {
282 				c = *s;
283 				if (c == '/') {
284 					/* Don't copy multiple slashes. */
285 					++s;
286 				} else if (c == '.') {
287 					c = s[1];
288 					if (c == '/') {
289 						/* Skip "./" */
290 						s += 2;
291 					} else if (c == '\0') {
292 						/* Skip "./" */
293 						s += 1;
294 					} else {
295 						break;
296 					}
297 				} else {
298 					break;
299 				}
300 			}
301 		} else if (c == '\0') {
302 			/* Remove trailing slash. */
303 			if ((d[-1] == '/') && (d > (dst + 1)))
304 				d[-1] = '\0';
305 			*d = '\0';
306 			break;
307 		} else if (d < lim) {
308 			*d++ = *s++;
309 		} else {
310 			++s;
311 		}
312 	}
313 	a = dst;
314 
315 	/* fprintf(stderr, "<%s>\n", dst); */
316 	/* Go through and remove .. in the path when we know what the
317 	 * parent directory is.  After we get done with this, the only
318 	 * .. nodes in the path will be at the front.
319 	 */
320 	while (*a != '\0') {
321 		b = a;
322 		for (;;) {
323 			/* Get the next node in the path. */
324 			if (*a == '\0')
325 				return;
326 			if (*a == '/') {
327 				++a;
328 				break;
329 			}
330 			++a;
331 		}
332 		if ((b[0] == '.') && (b[1] == '.')) {
333 			if (b[2] == '/') {
334 				/* We don't know what the parent of this
335 				 * node would be.
336 				 */
337 				continue;
338 			}
339 		}
340 		if ((a[0] == '.') && (a[1] == '.')) {
341 			if (a[2] == '/') {
342 				/* Remove the .. node and the one before it. */
343 				if ((b == dst) && (*dst == '/'))
344 					(void) memmove(b + 1, a + 3, strlen(a + 3) + 1);
345 				else
346 					(void) memmove(b, a + 3, strlen(a + 3) + 1);
347 				a = dst;	/* Start over. */
348 			} else if (a[2] == '\0') {
349 				/* Remove a trailing .. like:  /aaa/bbb/.. */
350 				if ((b <= dst + 1) && (*dst == '/'))
351 					dst[1] = '\0';
352 				else
353 					b[-1] = '\0';
354 				a = dst;	/* Start over. */
355 			} else {
356 				/* continue processing this node.
357 				 * It is probably some bogus path,
358 				 * like ".../", "..foo/", etc.
359 				 */
360 			}
361 		}
362 	}
363 }	/* CompressPath */
364 
365 
366 
367 void
PathCat(char * const dst,const size_t dsize,const char * const cwd,const char * const src)368 PathCat(char *const dst, const size_t dsize, const char *const cwd, const char *const src)
369 {
370 	char *cp;
371 	char tmp[512];
372 
373 	if (src[0] == '/') {
374 		CompressPath(dst, src, dsize);
375 		return;
376 	}
377 	cp = Strnpcpy(tmp, (char *) cwd, sizeof(tmp) - 1);
378 	*cp++ = '/';
379 	*cp = '\0';
380 	(void) Strnpcat(cp, (char *) src, sizeof(tmp) - (cp - tmp));
381 	CompressPath(dst, tmp, dsize);
382 }	/* PathCat */
383 
384 
385 
386 char *
FileToURL(char * url,size_t urlsize,const char * const fn,const char * const rcwd,const char * const startdir,const char * const user,const char * const pass,const char * const hname,const unsigned int port)387 FileToURL(char *url, size_t urlsize, const char *const fn, const char *const rcwd, const char *const startdir, const char *const user, const char *const pass, const char *const hname, const unsigned int port)
388 {
389 	size_t ulen, dsize;
390 	char *dst, pbuf[32];
391 	int isUser;
392 
393 	/* //<user>:<password>@<host>:<port>/<url-path> */
394 	/* Note that if an absolute path is given,
395 	 * you need to escape the first entry, i.e. /pub -> %2Fpub
396 	 */
397 	(void) Strncpy(url, "ftp://", urlsize);
398 	isUser = 0;
399 	if ((user != NULL) && (user[0] != '\0') && (strcmp(user, "anonymous") != 0) && (strcmp(user, "ftp") != 0)) {
400 		isUser = 1;
401 		(void) Strncat(url, user, urlsize);
402 		if ((pass != NULL) && (pass[0] != '\0')) {
403 			(void) Strncat(url, ":", urlsize);
404 			(void) Strncat(url, "PASSWORD", urlsize);
405 		}
406 		(void) Strncat(url, "@", urlsize);
407 	}
408 	(void) Strncat(url, hname, urlsize);
409 	if ((port != 21) && (port != 0)) {
410 		(void) sprintf(pbuf, ":%u", (unsigned int) port);
411 		(void) Strncat(url, pbuf, urlsize);
412 	}
413 
414 	ulen = strlen(url);
415 	dst = url + ulen;
416 	dsize = urlsize - ulen;
417 	PathCat(dst, dsize, rcwd, fn);
418 	if ((startdir != NULL) && (startdir[0] != '\0') && (startdir[1] /* i.e. not "/" */ != '\0')) {
419 		if (strncmp(dst, startdir, strlen(startdir)) == 0) {
420 			/* Form relative URL. */
421 			memmove(dst, dst + strlen(startdir), strlen(dst) - strlen(startdir) + 1);
422 		} else if (isUser != 0) {
423 			/* Absolute URL, but different from start dir.
424 			 * Make sure to use %2f as first slash so that
425 			 * the translation uses "/pub" instead of "pub"
426 			 * since the / characters are just delimiters.
427 			 */
428 			dst[dsize - 1] = '\0';
429 			dst[dsize - 2] = '\0';
430 			dst[dsize - 3] = '\0';
431 			dst[dsize - 4] = '\0';
432 			memmove(dst + 4, dst + 1, strlen(dst + 1));
433 			dst[0] = '/';
434 			dst[1] = '%';
435 			dst[2] = '2';
436 			dst[3] = 'F';
437 		}
438 	}
439 
440 	return (url);
441 }	/* FileToURL */
442 
443 
444 
445 
446 /* This will abbreviate a string so that it fits into max characters.
447  * It will use ellipses as appropriate.  Make sure the string has
448  * at least max + 1 characters allocated for it.
449  */
450 void
AbbrevStr(char * dst,const char * src,size_t max,int mode)451 AbbrevStr(char *dst, const char *src, size_t max, int mode)
452 {
453 	int len;
454 
455 	len = (int) strlen(src);
456 	if (len > (int) max) {
457 		if (mode == 0) {
458 			/* ...Put ellipses at left */
459 			(void) strcpy(dst, "...");
460 			(void) Strncat(dst, (char *) src + len - (int) max + 3, max + 1);
461 		} else {
462 			/* Put ellipses at right... */
463 			(void) Strncpy(dst, (char *) src, max + 1);
464 			(void) strcpy(dst + max - 3, "...");
465 		}
466 	} else {
467 		(void) Strncpy(dst, (char *) src, max + 1);
468 	}
469 }	/* AbbrevStr */
470 
471 
472 
473 
474 char *
Path(char * const dst,const size_t siz,const char * const parent,const char * const fname)475 Path(char *const dst, const size_t siz, const char *const parent, const char *const fname)
476 {
477 	(void) Strncpy(dst, parent, siz);
478 	(void) Strncat(dst, LOCAL_PATH_DELIM_STR, siz);
479 	return (Strncat(dst, fname, siz));
480 }	/* Path */
481 
482 
483 
484 
485 char *
OurDirectoryPath(char * const dst,const size_t siz,const char * const fname)486 OurDirectoryPath(char *const dst, const size_t siz, const char *const fname)
487 {
488 	return (Path(dst, siz, gOurDirectoryPath, fname));
489 }	/* OurDirectoryPath */
490 
491 
492 
493 char *
OurInstallationPath(char * const dst,const size_t siz,const char * const fname)494 OurInstallationPath(char *const dst, const size_t siz, const char *const fname)
495 {
496 	return (Path(dst, siz, gOurInstallationPath, fname));
497 }	/* OurInstallationPath */
498 
499 
500 
501 
502 /* Create, if necessary, a directory in the user's home directory to
503  * put our incredibly important stuff in.
504  */
505 void
InitOurDirectory(void)506 InitOurDirectory(void)
507 {
508 #if defined(WIN32) || defined(_WINDOWS)
509 	DWORD dwType, dwSize;
510 	HKEY hkey;
511 	char *cp;
512 	int rc;
513 
514 	ZeroMemory(gOurDirectoryPath, (DWORD) sizeof(gOurDirectoryPath));
515 	ZeroMemory(gOurInstallationPath, (DWORD) sizeof(gOurInstallationPath));
516 
517 	if (RegOpenKeyEx(
518 		HKEY_LOCAL_MACHINE,
519 		"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\ncftp.exe",
520 		(DWORD) 0,
521 		KEY_QUERY_VALUE,
522 		&hkey) == ERROR_SUCCESS)
523 	{
524 		dwSize = (DWORD) (sizeof(gOurInstallationPath) - 1);
525 		dwType = 0;
526 		if (RegQueryValueEx(
527 			hkey,
528 			NULL,
529 			(DWORD *) 0,
530 			&dwType,
531 			(LPBYTE) gOurInstallationPath,
532 			&dwSize) == ERROR_SUCCESS)
533 		{
534 			// This gave us the path to ncftp.exe;
535 			// But we use a subdirectory in that directory.
536 			//
537 			cp = StrRFindLocalPathDelim(gOurInstallationPath);
538 			if (cp == NULL)
539 				ZeroMemory(gOurInstallationPath, (DWORD) sizeof(gOurInstallationPath));
540 			else
541 				ZeroMemory(cp, (DWORD) (cp - gOurInstallationPath));
542 		}
543 		RegCloseKey(hkey);
544 	}
545 
546 	if (gOurInstallationPath[0] == '\0') {
547 		if (GetModuleFileName(NULL, gOurInstallationPath, (DWORD) sizeof(gOurInstallationPath) - 1) <= 0) {
548 			ZeroMemory(gOurInstallationPath, (DWORD) sizeof(gOurInstallationPath));
549 		} else {
550 			// This gave us the path to the current .exe;
551 			// But we use a subdirectory in that directory.
552 			//
553 			cp = StrRFindLocalPathDelim(gOurInstallationPath);
554 			if (cp == NULL)
555 				ZeroMemory(gOurInstallationPath, (DWORD) sizeof(gOurInstallationPath));
556 			else
557 				ZeroMemory(cp, (DWORD) (cp - gOurInstallationPath));
558 		}
559 	}
560 
561 	if (gOurInstallationPath[0] != '\0') {
562 		if ((cp = getenv("NCFTPDIR")) != NULL) {
563 			if (*cp == '"')
564 				cp++;
565 			(void) STRNCPY(gOurDirectoryPath, cp);
566 			cp = strrchr(gOurDirectoryPath, '"');
567 			if ((cp != NULL) && (cp[1] == '\0'))
568 				*cp = '\0';
569 		} else if ((cp = getenv("HOME")) != NULL) {
570 			if (*cp == '"')
571 				cp++;
572 			(void) STRNCPY(gOurDirectoryPath, cp);
573 			cp = strrchr(gOurDirectoryPath, '"');
574 			if ((cp != NULL) && (cp[1] == '\0'))
575 				*cp = '\0';
576 		} else {
577 			STRNCPY(gOurDirectoryPath, gOurInstallationPath);
578 			if (gUser[0] == '\0') {
579 				STRNCAT(gOurDirectoryPath, "\\Users\\default");
580 			} else {
581 				STRNCAT(gOurDirectoryPath, "\\Users\\");
582 				STRNCAT(gOurDirectoryPath, gUser);
583 			}
584 		}
585 		rc = MkDirs(gOurDirectoryPath, 00755);
586 	}
587 
588 #else
589 	struct stat st;
590 	char *cp;
591 
592 #ifdef BINDIR
593 	(void) STRNCPY(gOurInstallationPath, BINDIR);
594 #else
595 	memset(gOurInstallationPath, 0, sizeof(gOurInstallationPath));
596 #endif
597 
598 	cp = getenv("NCFTPDIR");
599 	if (cp != NULL) {
600 		(void) STRNCPY(gOurDirectoryPath, cp);
601 	} else if (STREQ(gHome, "/")) {
602 		/* Don't create it if you're root and your home directory
603 		 * is the root directory.
604 		 *
605 		 * If you are root and you want to store your ncftp
606 		 * config files, move your home directory somewhere else,
607 		 * such as /root or /home/root.
608 		 */
609 		gOurDirectoryPath[0] = '\0';
610 		return;
611 	} else {
612 		(void) Path(gOurDirectoryPath,
613 			sizeof(gOurDirectoryPath),
614 			gHome,
615 			kOurDirectoryName
616 		);
617 	}
618 
619 	if (stat(gOurDirectoryPath, &st) < 0) {
620 		if (mkdir(gOurDirectoryPath, 00755) < 0) {
621 			gOurDirectoryPath[0] = '\0';
622 		}
623 	}
624 #endif
625 }	/* InitOurDirectory */
626 
627 
628 
629 void
InitUserInfo(void)630 InitUserInfo(void)
631 {
632 #if defined(WIN32) || defined(_WINDOWS)
633 	DWORD nSize;
634 	char *cp;
635 
636 	memset(gUser, 0, sizeof(gUser));
637 	nSize = sizeof(gUser) - 1;
638 	if (! GetUserName(gUser, &nSize))
639 		STRNCPY(gUser, "default");
640 
641 	memset(gHome, 0, sizeof(gHome));
642 	(void) GetTempPath((DWORD) sizeof(gHome) - 1, gHome);
643 	cp = strrchr(gHome, '\\');
644 	if ((cp != NULL) && (cp[1] == '\0'))
645 		*cp = '\0';
646 
647 	memset(gShell, 0, sizeof(gShell));
648 #else
649 	struct passwd *pwptr;
650 	char *envp;
651 
652 	gUid = geteuid();
653 	pwptr = getpwuid(gUid);
654 
655 	if (pwptr == NULL) {
656 		envp = getenv("LOGNAME");
657 		if (envp == NULL) {
658 			(void) fprintf(stderr, "Who are you?\n");
659 			(void) fprintf(stderr, "You have a user id number of %d, but no username associated with it.\n", (int) gUid);
660 			(void) STRNCPY(gUser, "unknown");
661 		} else {
662 			(void) STRNCPY(gUser, envp);
663 		}
664 
665 		envp = getenv("HOME");
666 		if (envp == NULL)
667 			(void) STRNCPY(gHome, "/");
668 		else
669 			(void) STRNCPY(gHome, envp);
670 
671 		envp = getenv("SHELL");
672 		if (envp == NULL)
673 			(void) STRNCPY(gShell, "/bin/sh");
674 		else
675 			(void) STRNCPY(gShell, envp);
676 	} else {
677 		/* Copy home directory. */
678 		(void) STRNCPY(gHome, pwptr->pw_dir);
679 
680 		/* Copy user name. */
681 		(void) STRNCPY(gUser, pwptr->pw_name);
682 
683 		/* Copy shell. */
684 		(void) STRNCPY(gShell, pwptr->pw_shell);
685 	}
686 #endif
687 
688 	InitOurDirectory();
689 }	/* InitUserInfo */
690 
691 
692 
693 
694 int
MayUseFirewall(const char * const hn,int firewallType,const char * const firewallExceptionList)695 MayUseFirewall(const char *const hn, int firewallType, const char *const firewallExceptionList)
696 {
697 #ifdef HAVE_STRSTR
698 	char buf[256];
699 	char *tok;
700 	char *parse;
701 #endif /* HAVE_STRSTR */
702 
703 	if (firewallType == kFirewallNotInUse)
704 		return (0);
705 
706 	if (firewallExceptionList[0] == '\0') {
707 		if (strchr(hn, '.') == NULL) {
708 			/* Unqualified host name,
709 			 * assume it is in local domain.
710 			 */
711 			return (0);
712 		} else {
713 			return (1);
714 		}
715 	}
716 
717 	if (strchr(hn, '.') == NULL) {
718 		/* Unqualified host name,
719 		 * assume it is in local domain.
720 		 *
721 		 * If "localdomain" is in the exception list,
722 		 * do not use the firewall for this host.
723 		 */
724 		(void) STRNCPY(buf, firewallExceptionList);
725 		for (parse = buf; (tok = strtok(parse, ", \n\t\r")) != NULL; parse = NULL) {
726 			if (strcmp(tok, "localdomain") == 0)
727 				return (0);
728 		}
729 		/* fall through */
730 	}
731 
732 #ifdef HAVE_STRSTR
733 	(void) STRNCPY(buf, firewallExceptionList);
734 	for (parse = buf; (tok = strtok(parse, ", \n\t\r")) != NULL; parse = NULL) {
735 		/* See if host or domain was from exclusion list
736 		 * matches the host to open.
737 		 */
738 		if (strstr(hn, tok) != NULL)
739 			return (0);
740 	}
741 #endif /* HAVE_STRSTR */
742 	return (1);
743 }	/* MayUseFirewall */
744 
745 
746 
747 int
StrToBool(const char * const s)748 StrToBool(const char *const s)
749 {
750 	int c;
751 	int result;
752 
753 	c = *s;
754 	if (isupper(c))
755 		c = tolower(c);
756 	result = 0;
757 	switch (c) {
758 		case 'f':			       /* false */
759 			/*FALLTHROUGH*/
760 		case 'n':			       /* no */
761 			break;
762 		case 'o':			       /* test for "off" and "on" */
763 			c = (int) s[1];
764 			if (isupper(c))
765 				c = tolower(c);
766 			if (c == 'f')
767 				break;
768 			/*FALLTHROUGH*/
769 		case 't':			       /* true */
770 			/*FALLTHROUGH*/
771 		case 'y':			       /* yes */
772 			result = 1;
773 			break;
774 		default:			       /* 1, 0, -1, other number? */
775 			if (atoi(s) != 0)
776 				result = 1;
777 	}
778 	return result;
779 }						       /* StrToBool */
780 
781 
782 
783 
784 void
AbsoluteToRelative(char * const dst,const size_t dsize,const char * const dir,const char * const root,const size_t rootlen)785 AbsoluteToRelative(char *const dst, const size_t dsize, const char *const dir, const char *const root, const size_t rootlen)
786 {
787 	*dst = '\0';
788 	if (strcmp(dir, root) != 0) {
789 		if (strcmp(root, "/") == 0) {
790 			(void) Strncpy(dst, dir + 1, dsize);
791 		} else if ((strncmp(root, dir, rootlen) == 0) && (dir[rootlen] == '/')) {
792 			(void) Strncpy(dst, dir + rootlen + 1, dsize);
793 		} else {
794 			/* Still absolute. */
795 			(void) Strncpy(dst, dir, dsize);
796 		}
797 	}
798 }	/* AbsoluteToRelative */
799 
800 
801 
802 
803 #if defined(WIN32) || defined(_WINDOWS)
804 #else
805 
806 /* Some commands may want to jump back to the start too. */
807 static void
CancelGetHostByName(int sigNum)808 CancelGetHostByName(int sigNum)
809 {
810 #ifdef ncftp
811 	gResolveSig = sigNum;
812 #endif
813 #ifdef HAVE_SIGSETJMP
814 	siglongjmp(gGetHostByNameJmp, (sigNum != 0) ? 1 : 0);
815 #else	/* HAVE_SIGSETJMP */
816 	longjmp(gGetHostByNameJmp, (sigNum != 0) ? 1 : 0);
817 #endif	/* HAVE_SIGSETJMP */
818 }	/* CancelGetHostByName */
819 
820 #endif
821 
822 
823 
824 
825 int
GetHostByName(char * const volatile dst,size_t dsize,const char * const hn,int t)826 GetHostByName(char *const volatile dst, size_t dsize, const char *const hn, int t)
827 {
828 #if defined(WIN32) || defined(_WINDOWS)
829 	struct hostent *hp;
830 	struct in_addr ina;
831 
832 	if (inet_addr(hn) != (unsigned long) 0xFFFFFFFF) {
833 		/* Address is an IP address string, which is what we want. */
834 		(void) Strncpy(dst, hn, dsize);
835 		return (0);
836 	}
837 
838 	hp = gethostbyname(hn);
839 	if (hp != NULL) {
840 		(void) memcpy(&ina.s_addr, hp->h_addr_list[0], (size_t) hp->h_length);
841 		(void) Strncpy(dst, inet_ntoa(ina), dsize);
842 		return (0);
843 	}
844 
845 #else
846 	int sj;
847 	vsigproc_t osigpipe, osigint, osigalrm;
848 	struct hostent *hp;
849 #ifndef HAVE_INET_NTOP
850 	struct in_addr ina;
851 #endif
852 
853 #ifdef HAVE_INET_ATON
854 	if (inet_aton(hn, &ina) != 0) {
855 		/* Address is an IP address string, which is what we want. */
856 		(void) Strncpy(dst, hn, dsize);
857 		return (0);
858 	}
859 #else
860 	if (inet_addr(hn) != (unsigned long) 0xFFFFFFFF) {
861 		/* Address is an IP address string, which is what we want. */
862 		(void) Strncpy(dst, hn, dsize);
863 		return (0);
864 	}
865 #endif
866 
867 #ifdef HAVE_SIGSETJMP
868 	osigpipe = osigint = osigalrm = (sigproc_t) 0;
869 	sj = sigsetjmp(gGetHostByNameJmp, 1);
870 #else	/* HAVE_SIGSETJMP */
871 	osigpipe = osigint = osigalrm = (sigproc_t) 0;
872 	sj = setjmp(gGetHostByNameJmp);
873 #endif	/* HAVE_SIGSETJMP */
874 
875 	if (sj != 0) {
876 		/* Caught a signal. */
877 		(void) alarm(0);
878 		(void) NcSignal(SIGPIPE, osigpipe);
879 		(void) NcSignal(SIGINT, osigint);
880 		(void) NcSignal(SIGALRM, osigalrm);
881 #ifdef ncftp
882 		Trace(0, "Canceled GetHostByName because of signal %d.\n", gResolveSig);
883 #endif
884 	} else {
885 		osigpipe = NcSignal(SIGPIPE, CancelGetHostByName);
886 		osigint = NcSignal(SIGINT, CancelGetHostByName);
887 		osigalrm = NcSignal(SIGALRM, CancelGetHostByName);
888 		if (t > 0)
889 			(void) alarm((unsigned int) t);
890 		hp = gethostbyname(hn);
891 		if (t > 0)
892 			(void) alarm(0);
893 		(void) NcSignal(SIGPIPE, osigpipe);
894 		(void) NcSignal(SIGINT, osigint);
895 		(void) NcSignal(SIGALRM, osigalrm);
896 		if (hp != NULL) {
897 #ifdef HAVE_INET_NTOP	/* Mostly to workaround bug in IRIX 6.5's inet_ntoa */
898 			(void) memset(dst, 0, dsize);
899 			(void) inet_ntop(AF_INET, hp->h_addr_list[0], dst, dsize - 1);
900 #else
901 			(void) memcpy(&ina.s_addr, hp->h_addr_list[0], (size_t) hp->h_length);
902 			(void) Strncpy(dst, inet_ntoa(ina), dsize);
903 #endif
904 			return (0);
905 		}
906 	}
907 #endif	/* !Windows */
908 
909 	*dst = '\0';
910 	return (-1);
911 }	/* GetHostByName */
912 
913 
914 
915 
916 /* Converts a date string, like "19930602204445" into to a time_t.  */
UnDate(char * dstr)917 time_t UnDate(char *dstr)
918 {
919 #ifndef HAVE_MKTIME
920 	return ((time_t) -1);
921 #else
922 	struct tm ut, *t;
923 	time_t now;
924 	time_t result = (time_t) -1;
925 
926 	(void) time(&now);
927 	t = localtime(&now);
928 
929 	/* Copy the whole structure of the 'tm' pointed to by t, so it will
930 	 * also set all fields we don't specify explicitly to be the same as
931 	 * they were in t.  That way we copy non-standard fields such as
932 	 * tm_gmtoff, if it exists or not.
933 	 */
934 	ut = *t;
935 
936 	/* The time we get back from the server is (should be) in UTC. */
937 	if (sscanf(dstr, "%04d%02d%02d%02d%02d%02d",
938 		&ut.tm_year,
939 		&ut.tm_mon,
940 		&ut.tm_mday,
941 		&ut.tm_hour,
942 		&ut.tm_min,
943 		&ut.tm_sec) == 6)
944 	{
945 		--ut.tm_mon;
946 		ut.tm_year -= 1900;
947 		result = mktime(&ut);
948 	}
949 	return result;
950 #endif	/* HAVE_MKTIME */
951 }	/* UnDate */
952 
953 
954 
955 
956 #ifndef HAVE_MEMMOVE
957 /* This code is derived from software contributed to Berkeley by
958  * Chris Torek.
959  */
960 
961 /*
962  * sizeof(word) MUST BE A POWER OF TWO
963  * SO THAT wmask BELOW IS ALL ONES
964  */
965 typedef	int word;		/* "word" used for optimal copy speed */
966 
967 #define	wsize	sizeof(word)
968 #define	wmask	(wsize - 1)
969 
970 /*
971  * Copy a block of memory, handling overlap.
972  * This is the routine that actually implements
973  * (the portable versions of) bcopy, memcpy, and memmove.
974  */
975 void *
memmove(void * dst0,void * src0,size_t length)976 memmove(void *dst0, void *src0, size_t length)
977 {
978 	register char *dst = (char *) dst0;
979 	register const char *src = (char *) src0;
980 	register size_t t;
981 
982 	if (length == 0 || dst == src)		/* nothing to do */
983 		return dst;
984 
985 	/*
986 	 * Macros: loop-t-times; and loop-t-times, t>0
987 	 */
988 #define	TLOOP(s) if (t) TLOOP1(s)
989 #define	TLOOP1(s) do { s; } while (--t)
990 
991 	if ((unsigned long)dst < (unsigned long)src) {
992 		/*
993 		 * Copy forward.
994 		 */
995 		t = (int)src;	/* only need low bits */
996 		if ((t | (int)dst) & wmask) {
997 			/*
998 			 * Try to align operands.  This cannot be done
999 			 * unless the low bits match.
1000 			 */
1001 			if ((t ^ (int)dst) & wmask || length < wsize)
1002 				t = length;
1003 			else
1004 				t = wsize - (t & wmask);
1005 			length -= t;
1006 			TLOOP1(*dst++ = *src++);
1007 		}
1008 		/*
1009 		 * Copy whole words, then mop up any trailing bytes.
1010 		 */
1011 		t = length / wsize;
1012 		TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
1013 		t = length & wmask;
1014 		TLOOP(*dst++ = *src++);
1015 	} else {
1016 		/*
1017 		 * Copy backwards.  Otherwise essentially the same.
1018 		 * Alignment works as before, except that it takes
1019 		 * (t&wmask) bytes to align, not wsize-(t&wmask).
1020 		 */
1021 		src += length;
1022 		dst += length;
1023 		t = (int)src;
1024 		if ((t | (int)dst) & wmask) {
1025 			if ((t ^ (int)dst) & wmask || length <= wsize)
1026 				t = length;
1027 			else
1028 				t &= wmask;
1029 			length -= t;
1030 			TLOOP1(*--dst = *--src);
1031 		}
1032 		t = length / wsize;
1033 		TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
1034 		t = length & wmask;
1035 		TLOOP(*--dst = *--src);
1036 	}
1037 
1038 	return(dst0);
1039 }	/* MemMove */
1040 #endif	/* ! HAVE_MEMMOVE */
1041 
1042 
1043 
1044 
1045 #if defined(HAVE_STRCOLL) && !defined(HAVE_STRNCOLL)
1046 int
strncoll(const char * a,const char * b,size_t n)1047 strncoll(const char *a, const char *b, size_t n)
1048 {
1049 	int rc;
1050 
1051 	if (n < 511) {
1052 		char sa[512], sb[512];
1053 
1054 		memset(sa, 0, sizeof(sa));
1055 		memset(sb, 0, sizeof(sb));
1056 		(void) strncpy(sa, a, n);
1057 		(void) strncpy(sb, b, n);
1058 		rc = (strcoll(sa, sb));
1059 		return (rc);
1060 	} else {
1061 		char *ma, *mb;
1062 
1063 		n += 5;			/* enough for a 32-bit zero char. */
1064 		ma = (char *) malloc(n);
1065 		if (ma == NULL)
1066 			return (0);	/* panic */
1067 		mb = (char *) malloc(n);
1068 		if (mb == NULL) {
1069 			free(ma);
1070 			return (0);	/* panic */
1071 		}
1072 		(void) strncpy(ma, a, n);
1073 		(void) strncpy(mb, b, n);
1074 		rc = (strcoll(ma, mb));
1075 		free(ma);
1076 		free(mb);
1077 		return (rc);
1078 	}
1079 }	/* strncoll */
1080 #endif
1081 
1082 
1083 
1084 
1085 int
DecodeDirectoryURL(const FTPCIPtr cip,char * url,LineListPtr cdlist,char * fn,size_t fnsize)1086 DecodeDirectoryURL(
1087 	const FTPCIPtr cip,	/* area pointed to may be modified */
1088 	char *url,		/* always modified */
1089 	LineListPtr cdlist,	/* always modified */
1090 	char *fn,		/* always modified */
1091 	size_t fnsize
1092 )
1093 {
1094 	int rc;
1095 	char urlstr2[256];
1096 	char *cp;
1097 
1098 	/* Add a trailing slash, if needed, i.e., convert
1099 	 * "ftp://ftp.gnu.org/pub/gnu" to
1100 	 * "ftp://ftp.gnu.org/pub/gnu/"
1101 	 *
1102 	 * We also generalize and assume that if the user specified
1103 	 * something with a .extension that the user was intending
1104 	 * to specify a file instead of a directory.
1105 	 */
1106 	cp = strrchr(url, '/');
1107 	if ((cp != NULL) && (cp[1] != '\0') && (strchr(cp, '.') == NULL)) {
1108 
1109 		(void) STRNCPY(urlstr2, url);
1110 		(void) STRNCAT(urlstr2, "/");
1111 		url = urlstr2;
1112 	}
1113 	rc = FTPDecodeURL(cip, url, cdlist, fn, fnsize, NULL, NULL);
1114 	return (rc);
1115 }	/* DecodeDirectoryURL */
1116 
1117 
1118 
1119 
1120 #if defined(WIN32) || defined(_WINDOWS)
SysPerror(const char * const errMsg)1121 void SysPerror(const char *const errMsg)
1122 {
1123 	char reason[128];
1124 
1125 	FormatMessage(
1126 		FORMAT_MESSAGE_FROM_SYSTEM,
1127 		NULL,
1128 		GetLastError(),
1129 		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1130 		reason,
1131 		(DWORD) sizeof(reason),
1132 		NULL
1133 		);
1134 
1135 	if (reason[strlen(reason) - 1] == '\n')
1136 		reason[strlen(reason) - 1] = '\0';
1137 	(void) fprintf(stderr, "%s: %s\n", errMsg, reason);
1138 }	/* SysPerror */
1139 #endif
1140