ncftp for win32 3.0.3
[reactos.git] / reactos / apps / utils / net / ncftp / ncftp / util.c
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
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
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
176 OutOfMemory(void)
177 {
178 (void) fprintf(stderr, "Out of memory!\n");
179 exit(1);
180 } /* OutOfMemory */
181
182
183
184 void
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 *
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
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
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 *
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
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 *
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 *
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 *
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
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
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
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
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
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
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
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. */
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 *
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
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
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)
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