ReactOS 0.4.15-dev-7788-g1ad9096
open.c
Go to the documentation of this file.
1/* open.c
2 *
3 * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft.
4 * All rights reserved.
5 *
6 */
7
8#include "syshdrs.h"
9
10static void
12{
13 /* Requires the cip->bufSize field set,
14 * and the cip->buf set if the
15 * buffer is allocated.
16 */
17 if (cip->buf != NULL) {
18 (void) memset(cip->buf, 0, cip->bufSize);
19 free(cip->buf);
20 cip->buf = NULL;
21 }
22
23 if (cip->startingWorkingDirectory != NULL) {
26 }
27
28#if USE_SIO
30#endif
32} /* FTPDeallocateHost */
33
34
35
36
37
38static int
40{
41 char *buf;
42
43 /* Requires the cip->bufSize field set,
44 * and the cip->buf cleared if the
45 * buffer is not allocated.
46 */
47 if (cip->buf == NULL) {
48 buf = (char *) calloc((size_t) 1, cip->bufSize);
49 if (buf == NULL) {
50 Error(cip, kDontPerror, "Malloc failed.\n");
52 return (kErrMallocFailed);
53 }
54 cip->buf = buf;
55 }
56 return (kNoErr);
57} /* FTPAllocateHost */
58
59
60
61
62void
64{
65 if (lip == NULL)
66 return;
67 if (strcmp(lip->magic, kLibraryMagic))
68 return;
69
70 if (lip->htried == 0) {
71 (void) memset(lip->ourHostName, 0, sizeof(lip->ourHostName));
72 lip->hresult = GetOurHostName(lip->ourHostName, sizeof(lip->ourHostName));
73 }
74 lip->htried++;
75} /* FTPInitializeOurHostName */
76
77
78
79
80void
82{
83 if (lip == NULL)
84 return;
85 if (strcmp(lip->magic, kLibraryMagic))
86 return;
87
89
90 if (lip->defaultAnonPassword[0] == '\0') {
91#ifdef SPAM_PROBLEM_HAS_BEEN_SOLVED_FOREVER
93 (void) STRNCAT(lip->defaultAnonPassword, "@");
94
95 /* Default to the "user@" notation
96 * supported by NcFTPd and wu-ftpd.
97 */
98 if (lip->htried > 0)
100#else
101 (void) STRNCPY(lip->defaultAnonPassword, "NcFTP@");
102#endif
103 }
104} /* FTPInitializeAnonPassword */
105
106
107
108
109int
111{
112 ResponsePtr rp;
114 int anonLogin;
115 int sentpass = 0;
116 int fwloggedin;
117 int firstTime;
118 char cwd[512];
119
120 if (cip == NULL)
121 return (kErrBadParameter);
123 return (kErrBadParameter);
124
125 if (strcmp(cip->magic, kLibraryMagic))
126 return (kErrBadMagic);
127
128 anonLogin = 0;
129 if (cip->user[0] == '\0')
130 (void) STRNCPY(cip->user, "anonymous");
131 if ((strcmp(cip->user, "anonymous") == 0) || (strcmp(cip->user, "ftp") == 0)) {
132 anonLogin = 1;
133 /* Try to get the email address if you didn't specify
134 * a password when the user is anonymous.
135 */
136 if (cip->pass[0] == '\0') {
138 (void) STRNCPY(cip->pass, cip->lip->defaultAnonPassword);
139 }
140 }
141
142 rp = InitResponse();
143 if (rp == NULL) {
145 cip->errNo = kErrMallocFailed;
146 goto done2;
147 }
148
149 for (firstTime = 1, fwloggedin = 0; ; ) {
150 /* Here's a mini finite-automaton for the login process.
151 *
152 * Originally, the FTP protocol was designed to be entirely
153 * implementable from a FA. It could be done, but I don't think
154 * it's something an interactive process could be the most
155 * effective with.
156 */
157
158 if (firstTime != 0) {
159 rp->code = 220;
160 firstTime = 0;
161 } else if (result < 0) {
162 goto done;
163 }
164
165 switch (rp->code) {
166 case 220: /* Welcome, ready for new user. */
167 if ((cip->firewallType == kFirewallNotInUse) || (fwloggedin != 0)) {
168 ReInitResponse(cip, rp);
169 result = RCmd(cip, rp, "USER %s", cip->user);
170 } else if (cip->firewallType == kFirewallUserAtSite) {
171 ReInitResponse(cip, rp);
172 result = RCmd(cip, rp, "USER %s@%s", cip->user, cip->host);
173 } else if (cip->firewallType == kFirewallUserAtUserPassAtPass) {
174 ReInitResponse(cip, rp);
175 result = RCmd(cip, rp, "USER %s@%s@%s", cip->user, cip->firewallUser, cip->host);
176 } else if (cip->firewallType == kFirewallUserAtSiteFwuPassFwp) {
177 ReInitResponse(cip, rp);
178 result = RCmd(cip, rp, "USER %s@%s %s", cip->user, cip->host, cip->firewallUser);
179 } else if (cip->firewallType == kFirewallFwuAtSiteFwpUserPass) {
180 /* only reached when !fwloggedin */
181 ReInitResponse(cip, rp);
182 result = RCmd(cip, rp, "USER %s@%s", cip->firewallUser, cip->host);
183 } else if (cip->firewallType > kFirewallNotInUse) {
184 ReInitResponse(cip, rp);
185 result = RCmd(cip, rp, "USER %s", cip->firewallUser);
186 } else {
187 goto unknown;
188 }
189 break;
190
191 case 230: /* 230 User logged in, proceed. */
192 case 231: /* User name accepted. */
193 case 202: /* Command not implemented, superfluous at this site. */
194 if ((cip->firewallType == kFirewallNotInUse) || (fwloggedin != 0))
195 goto okay;
196
197 /* Now logged in to the firewall. */
198 fwloggedin++;
199
201 ReInitResponse(cip, rp);
202 result = RCmd(cip, rp, "USER %s@%s", cip->user, cip->host);
203 } else if (cip->firewallType == kFirewallUserAtUserPassAtPass) {
204 goto okay;
205 } else if (cip->firewallType == kFirewallOpenSite) {
206 ReInitResponse(cip, rp);
207 result = RCmd(cip, rp, "OPEN %s", cip->host);
208 } else if (cip->firewallType == kFirewallSiteSite) {
209 ReInitResponse(cip, rp);
210 result = RCmd(cip, rp, "SITE %s", cip->host);
211 } else if (cip->firewallType == kFirewallFwuAtSiteFwpUserPass) {
212 /* only reached when !fwloggedin */
213 ReInitResponse(cip, rp);
214 result = RCmd(cip, rp, "USER %s", cip->user);
215 } else /* kFirewallUserAtSite */ {
216 goto okay;
217 }
218 break;
219
220 case 421: /* 421 Service not available, closing control connection. */
222 goto done;
223
224 case 331: /* 331 User name okay, need password. */
225 if ((cip->firewallType == kFirewallNotInUse) || (fwloggedin != 0)) {
226 if ((cip->pass[0] == '\0') && (cip->passphraseProc != NoGetPassphraseProc))
227 (*cip->passphraseProc)(cip, &rp->msg, cip->pass, sizeof(cip->pass));
228 ReInitResponse(cip, rp);
229 result = RCmd(cip, rp, "PASS %s", cip->pass);
230 } else if (cip->firewallType == kFirewallUserAtSite) {
231 ReInitResponse(cip, rp);
232 result = RCmd(cip, rp, "PASS %s", cip->pass);
233 } else if (cip->firewallType == kFirewallUserAtUserPassAtPass) {
234 ReInitResponse(cip, rp);
235 result = RCmd(cip, rp, "PASS %s@%s", cip->pass, cip->firewallPass);
236 } else if (cip->firewallType == kFirewallUserAtSiteFwuPassFwp) {
237 ReInitResponse(cip, rp);
238 result = RCmd(cip, rp, "PASS %s", cip->pass);
239 } else if (cip->firewallType == kFirewallFwuAtSiteFwpUserPass) {
240 /* only reached when !fwloggedin */
241 ReInitResponse(cip, rp);
242 result = RCmd(cip, rp, "PASS %s", cip->firewallPass);
243 } else if (cip->firewallType > kFirewallNotInUse) {
244 ReInitResponse(cip, rp);
245 result = RCmd(cip, rp, "PASS %s", cip->firewallPass);
246 } else {
247 goto unknown;
248 }
249 sentpass++;
250 break;
251
252 case 332: /* 332 Need account for login. */
253 case 532: /* 532 Need account for storing files. */
254 if ((cip->firewallType == kFirewallNotInUse) || (fwloggedin != 0)) {
255 ReInitResponse(cip, rp);
256 result = RCmd(cip, rp, "ACCT %s", cip->acct);
257 } else if (cip->firewallType == kFirewallUserAtSiteFwuPassFwp) {
258 ReInitResponse(cip, rp);
259 result = RCmd(cip, rp, "ACCT %s", cip->firewallPass);
260 } else {
261 /* ACCT not supported on firewall. */
262 goto unknown;
263 }
264 break;
265
266 case 530: /* Not logged in. */
268 goto done;
269
270 case 501: /* Syntax error in parameters or arguments. */
271 case 503: /* Bad sequence of commands. */
272 case 550: /* Can't set guest privileges. */
273 goto done;
274
275 default:
276 unknown:
277 if (rp->msg.first == NULL) {
278 Error(cip, kDontPerror, "Lost connection during login.\n");
279 } else {
280 Error(cip, kDontPerror, "Unexpected response: %s\n",
281 rp->msg.first->line
282 );
283 }
284 goto done;
285 }
286 }
287
288okay:
289 /* Do the application's connect message callback, if present. */
290 if (cip->onLoginMsgProc != 0)
291 (*cip->onLoginMsgProc)(cip, rp);
292 DoneWithResponse(cip, rp);
293 result = 0;
294 cip->loggedIn = 1;
295
296 /* Make a note of what our root directory is.
297 * This is often different from "/" when not
298 * logged in anonymously.
299 */
300 if (cip->startingWorkingDirectory != NULL) {
303 }
304 if ((cip->doNotGetStartingWorkingDirectory == 0) &&
305 (FTPGetCWD(cip, cwd, sizeof(cwd)) == kNoErr))
306 {
308 }
309
310 /* When a new site is opened, ASCII mode is assumed (by protocol). */
311 cip->curTransferType = 'A';
312 PrintF(cip, "Logged in to %s as %s.\n", cip->host, cip->user);
313
314 /* Don't leave cleartext password in memory. */
315 if ((anonLogin == 0) && (cip->leavePass == 0))
316 (void) memset(cip->pass, '*', strlen(cip->pass));
317
318 if (result < 0)
319 cip->errNo = result;
320 return result;
321
322done:
323 DoneWithResponse(cip, rp);
324
325done2:
326 /* Don't leave cleartext password in memory. */
327 if ((anonLogin == 0) && (cip->leavePass == 0))
328 (void) memset(cip->pass, '*', strlen(cip->pass));
329 if (result < 0)
330 cip->errNo = result;
331 return result;
332} /* FTPLoginHost */
333
334
335
336
337static void
338FTPExamineMlstFeatures(const FTPCIPtr cip, const char *features)
339{
340 char buf[256], *feat;
341 int flags;
342
343 flags = 0;
344 STRNCPY(buf, features);
345 feat = strtok(buf, ";*");
346 while (feat != NULL) {
347 if (ISTRNEQ(feat, "OS.", 3))
348 feat += 3;
349 if (ISTREQ(feat, "type")) {
351 } else if (ISTREQ(feat, "size")) {
353 } else if (ISTREQ(feat, "modify")) {
355 } else if (ISTREQ(feat, "UNIX.mode")) {
357 } else if (ISTREQ(feat, "UNIX.owner")) {
359 } else if (ISTREQ(feat, "UNIX.group")) {
361 } else if (ISTREQ(feat, "perm")) {
363 } else if (ISTREQ(feat, "UNIX.uid")) {
365 } else if (ISTREQ(feat, "UNIX.gid")) {
367 } else if (ISTREQ(feat, "UNIX.gid")) {
369 }
370 feat = strtok(NULL, ";*");
371 }
372
373 cip->mlsFeatures = flags;
374} /* FTPExamineMlstFeatures */
375
376
377
378
379int
381{
382 ResponsePtr rp;
383 int result;
384 LinePtr lp;
385 char *cp, *p;
386
387 if (cip == NULL)
388 return (kErrBadParameter);
389 if (strcmp(cip->magic, kLibraryMagic))
390 return (kErrBadMagic);
391
392 if (cip->serverType == kServerTypeNetWareFTP) {
393 /* NetWare 5.00 server freaks out when
394 * you give it a command it doesn't
395 * recognize, so cheat here and return.
396 */
406 return (kNoErr);
407 }
408
409 rp = InitResponse();
410 if (rp == NULL) {
411 cip->errNo = kErrMallocFailed;
412 result = cip->errNo;
413 } else {
415 result = RCmd(cip, rp, "FEAT");
416 if (result < kNoErr) {
417 DoneWithResponse(cip, rp);
418 return (result);
419 } else if (result != 2) {
420 /* We cheat here and pre-populate some
421 * fields when the server is wu-ftpd.
422 * This server is very common and we
423 * know it has always had these.
424 */
425 if (cip->serverType == kServerTypeWuFTPd) {
431 } else if (cip->serverType == kServerTypeNcFTPd) {
437 }
438
439 /* Newer commands are only shown in FEAT,
440 * so we don't have to do the "try it,
441 * then save that it didn't work" thing.
442 */
445 } else {
447
448 for (lp = rp->msg.first; lp != NULL; lp = lp->next) {
449 /* If first character was not a space it is
450 * either:
451 *
452 * (a) The header line in the response;
453 * (b) The trailer line in the response;
454 * (c) A protocol violation.
455 */
456 cp = lp->line;
457 if (*cp++ != ' ')
458 continue;
459 if (ISTRNCMP(cp, "PASV", 4) == 0) {
461 } else if (ISTRNCMP(cp, "SIZE", 4) == 0) {
463 } else if (ISTRNCMP(cp, "MDTM", 4) == 0) {
465 } else if (ISTRNCMP(cp, "REST", 4) == 0) {
467 } else if (ISTRNCMP(cp, "UTIME", 5) == 0) {
469 } else if (ISTRNCMP(cp, "MLST", 4) == 0) {
472 FTPExamineMlstFeatures(cip, cp + 5);
473 } else if (ISTRNCMP(cp, "CLNT", 4) == 0) {
475 } else if (ISTRNCMP(cp, "Compliance Level: ", 18) == 0) {
476 /* Probably only NcFTPd will ever implement this.
477 * But we use it internally to differentiate
478 * between different NcFTPd implementations of
479 * IETF extensions.
480 */
481 cip->ietfCompatLevel = atoi(cp + 18);
482 }
483 }
484 }
485
486 ReInitResponse(cip, rp);
487 result = RCmd(cip, rp, "HELP SITE");
488 if (result == 2) {
489 for (lp = rp->msg.first; lp != NULL; lp = lp->next) {
490 cp = lp->line;
491 if (strstr(cp, "RETRBUFSIZE") != NULL)
493 if (strstr(cp, "RBUFSZ") != NULL)
495 /* See if RBUFSIZ matches (but not STORBUFSIZE) */
496 if (
497 ((p = strstr(cp, "RBUFSIZ")) != NULL) &&
498 (
499 (p == cp) ||
500 ((p > cp) && (!isupper(p[-1])))
501 )
502 )
504 if (strstr(cp, "STORBUFSIZE") != NULL)
506 if (strstr(cp, "SBUFSIZ") != NULL)
508 if (strstr(cp, "SBUFSZ") != NULL)
510 if (strstr(cp, "BUFSIZE") != NULL)
512 }
513 }
514 DoneWithResponse(cip, rp);
515 }
516
517 return (kNoErr);
518} /* FTPQueryFeatures */
519
520
521
522int
524{
525 ResponsePtr rp;
526 int result;
527
528 if (cip == NULL)
529 return (kErrBadParameter);
530 if (strcmp(cip->magic, kLibraryMagic))
531 return (kErrBadMagic);
532
533 /* Data connection shouldn't be open normally. */
536
537 result = kNoErr;
538 if (cip->connected != 0) {
539 rp = InitResponse();
540 if (rp == NULL) {
541 cip->errNo = kErrMallocFailed;
542 result = cip->errNo;
543 } else {
544 rp->eofOkay = 1; /* We are expecting EOF after this cmd. */
545 cip->eofOkay = 1;
546 (void) RCmd(cip, rp, "QUIT");
547 DoneWithResponse(cip, rp);
548 }
549 }
550
552
553 /* Dispose dynamic data structures, so you won't leak
554 * if you OpenHost with this again.
555 */
557 return (result);
558} /* FTPCloseHost */
559
560
561
562
563void
565{
566#ifdef SIGPIPE
567 FTPSigProc osigpipe;
568#endif
569
570 if (cip == NULL)
571 return;
572 if (strcmp(cip->magic, kLibraryMagic))
573 return;
574
575#ifdef SIGPIPE
576 osigpipe = signal(SIGPIPE, (FTPSigProc) SIG_IGN);
577#endif
578
579 /* Linger could cause close to block, so unset it. */
581 (void) SetLinger(cip, cip->dataSocket, 0);
582 CloseDataConnection(cip); /* Shouldn't be open normally. */
583
584 /* Linger should already be turned off for this. */
586
588
589#ifdef SIGPIPE
590 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
591#endif
592} /* FTPShutdownHost */
593
594
595
596
597void
598URLCopyToken(char *dst, size_t dsize, const char *src, size_t howmuch)
599{
600 char *dlim;
601 const char *slim;
602 unsigned int hc;
603 int c;
604 char h[4];
605
606 dlim = dst + dsize - 1; /* leave room for \0 */
607 slim = src + howmuch;
608 while (src < slim) {
609 c = *src++;
610 if (c == '\0')
611 break;
612 if (c == '%') {
613 /* hex representation */
614 if (src < slim + 2) {
615 h[0] = *src++;
616 h[1] = *src++;
617 h[2] = '\0';
618 hc = 0xeeff;
619 if ((sscanf(h, "%x", &hc) >= 0) && (hc != 0xeeff)) {
620 if (dst < dlim) {
621 *(unsigned char *)dst = (unsigned char) hc;
622 dst++;
623 }
624 }
625 } else {
626 break;
627 }
628 } else {
629 *dst++ = (char) c;
630 }
631 }
632 *dst = '\0';
633} /* URLCopyToken */
634
635
636
637
638int
640 const FTPCIPtr cip, /* area pointed to may be modified */
641 char *const url, /* always modified */
642 LineListPtr cdlist, /* always modified */
643 char *const fn, /* always modified */
644 const size_t fnsize,
645 int *const xtype, /* optional; may be modified */
646 int *const wantnlst /* optional; always modified */
647)
648{
649 char *cp;
650 char *hstart, *hend;
651 char *h2start;
652 char *at1;
653 char portstr[32];
654 int port;
655 int sc;
656 char *lastslash;
657 char *parsestr;
658 char *tok;
659 char subdir[128];
660 char *semi;
661
662 InitLineList(cdlist);
663 *fn = '\0';
664 if (wantnlst != NULL)
665 *wantnlst = 0;
666 if (xtype != NULL)
667 *xtype = kTypeBinary;
668
669 cp = NULL; /* shut up warnings */
670#ifdef HAVE_STRCASECMP
671 if (strncasecmp(url, "<URL:ftp://", 11) == 0) {
672 cp = url + strlen(url) - 1;
673 if (*cp != '>')
674 return (kMalformedURL); /* missing closing > */
675 *cp = '\0';
676 cp = url + 11;
677 } else if (strncasecmp(url, "ftp://", 6) == 0) {
678 cp = url + 6;
679 } else {
680 return (-1); /* not a RFC 1738 URL */
681 }
682#else /* HAVE_STRCASECMP */
683 if (strncmp(url, "<URL:ftp://", 11) == 0) {
684 cp = url + strlen(url) - 1;
685 if (*cp != '>')
686 return (kMalformedURL); /* missing closing > */
687 *cp = '\0';
688 cp = url + 11;
689 } else if (strncmp(url, "ftp://", 6) == 0) {
690 cp = url + 6;
691 } else {
692 return (-1); /* not a RFC 1738 URL */
693 }
694#endif /* HAVE_STRCASECMP */
695
696 /* //<user>:<password>@<host>:<port>/<url-path> */
697
698 at1 = NULL;
699 for (hstart = cp; ; cp++) {
700 if (*cp == '@') {
701 if (at1 == NULL)
702 at1 = cp;
703 else
704 return (kMalformedURL);
705 } else if ((*cp == '\0') || (*cp == '/')) {
706 hend = cp;
707 break;
708 }
709 }
710
711 sc = *hend;
712 *hend = '\0';
713 if (at1 == NULL) {
714 /* no user or password */
715 h2start = hstart;
716 } else {
717 *at1 = '\0';
718 cp = strchr(hstart, ':');
719 if (cp == NULL) {
720 /* whole thing is the user name then */
721 URLCopyToken(cip->user, sizeof(cip->user), hstart, (size_t) (at1 - hstart));
722 } else if (strchr(cp + 1, ':') != NULL) {
723 /* Too many colons */
724 return (kMalformedURL);
725 } else {
726 URLCopyToken(cip->user, sizeof(cip->user), hstart, (size_t) (cp - hstart));
727 URLCopyToken(cip->pass, sizeof(cip->pass), cp + 1, (size_t) (at1 - (cp + 1)));
728 }
729 *at1 = '@';
730 h2start = at1 + 1;
731 }
732
733 cp = strchr(h2start, ':');
734 if (cp == NULL) {
735 /* whole thing is the host then */
736 URLCopyToken(cip->host, sizeof(cip->host), h2start, (size_t) (hend - h2start));
737 } else if (strchr(cp + 1, ':') != NULL) {
738 /* Too many colons */
739 return (kMalformedURL);
740 } else {
741 URLCopyToken(cip->host, sizeof(cip->host), h2start, (size_t) (cp - h2start));
742 URLCopyToken(portstr, sizeof(portstr), cp + 1, (size_t) (hend - (cp + 1)));
743 port = atoi(portstr);
744 if (port > 0)
745 cip->port = port;
746 }
747
748 *hend = (char) sc;
749 if ((*hend == '\0') || ((*hend == '/') && (hend[1] == '\0'))) {
750 /* no path, okay */
751 return (0);
752 }
753
754 lastslash = strrchr(hend, '/');
755 if (lastslash == NULL) {
756 /* no path, okay */
757 return (0);
758 }
759 *lastslash = '\0';
760
761 if ((semi = strchr(lastslash + 1, ';')) != NULL) {
762 *semi++ = '\0';
763#ifdef HAVE_STRCASECMP
764 if (strcasecmp(semi, "type=i") == 0) {
765 if (xtype != NULL)
766 *xtype = kTypeBinary;
767 } else if (strcasecmp(semi, "type=a") == 0) {
768 if (xtype != NULL)
769 *xtype = kTypeAscii;
770 } else if (strcasecmp(semi, "type=b") == 0) {
771 if (xtype != NULL)
772 *xtype = kTypeBinary;
773 } else if (strcasecmp(semi, "type=d") == 0) {
774 if (wantnlst != NULL) {
775 *wantnlst = 1;
776 if (xtype != NULL)
777 *xtype = kTypeAscii;
778 } else {
779 /* You didn't want these. */
780 return (kMalformedURL);
781 }
782 }
783#else /* HAVE_STRCASECMP */
784 if (strcmp(semi, "type=i") == 0) {
785 if (xtype != NULL)
786 *xtype = kTypeBinary;
787 } else if (strcmp(semi, "type=a") == 0) {
788 if (xtype != NULL)
789 *xtype = kTypeAscii;
790 } else if (strcmp(semi, "type=b") == 0) {
791 if (xtype != NULL)
792 *xtype = kTypeBinary;
793 } else if (strcmp(semi, "type=d") == 0) {
794 if (wantnlst != NULL) {
795 *wantnlst = 1;
796 if (xtype != NULL)
797 *xtype = kTypeAscii;
798 } else {
799 /* You didn't want these. */
800 return (kMalformedURL);
801 }
802 }
803#endif /* HAVE_STRCASECMP */
804 }
805 URLCopyToken(fn, fnsize, lastslash + 1, strlen(lastslash + 1));
806 for (parsestr = hend; (tok = strtok(parsestr, "/")) != NULL; parsestr = NULL) {
807 URLCopyToken(subdir, sizeof(subdir), tok, strlen(tok));
808 (void) AddLine(cdlist, subdir);
809 }
810 *lastslash = '/';
811 return (kNoErr);
812} /* FTPDecodeURL */
813
814
815
816
817int
819{
820 int result;
821 time_t t0, t1;
822 int elapsed;
823 int dials;
824
825 if (cip == NULL)
826 return (kErrBadParameter);
827 if (strcmp(cip->magic, kLibraryMagic))
828 return (kErrBadMagic);
829
830 if (cip->host[0] == '\0') {
831 cip->errNo = kErrBadParameter;
832 return (kErrBadParameter);
833 }
834
835 for ( result = kErrConnectMiscErr, dials = 0;
836 cip->maxDials < 0 || dials < cip->maxDials;
837 dials++)
838 {
839 /* Allocate (or if the host was closed, reallocate)
840 * the transfer data buffer.
841 */
842 result = FTPAllocateHost(cip);
843 if (result < 0)
844 return (result);
845
846 if (dials > 0)
847 PrintF(cip, "Retry Number: %d\n", dials);
848 if (cip->redialStatusProc != 0)
849 (*cip->redialStatusProc)(cip, kRedialStatusDialing, dials);
850 (void) time(&t0);
851 result = OpenControlConnection(cip, cip->host, cip->port);
852 (void) time(&t1);
853 if (result == kNoErr) {
854 /* We were hooked up successfully. */
855 PrintF(cip, "Connected to %s.\n", cip->host);
856
857 result = FTPLoginHost(cip);
858 if (result == kNoErr) {
859 (void) FTPQueryFeatures(cip);
860 break;
861 }
862
863 /* Close and try again. */
864 (void) FTPCloseHost(cip);
865
866 /* Originally we also stopped retyring if
867 * we got kErrBadRemoteUser and non-anonymous,
868 * but some FTP servers apparently do their
869 * max user check after the username is sent.
870 */
871 if (result == kErrBadRemoteUserOrPassword /* || (result == kErrBadRemoteUser) */) {
872 if (strcmp(cip->user, "anonymous") != 0) {
873 /* Non-anonymous login was denied, and
874 * retrying is not going to help.
875 */
876 break;
877 }
878 }
880 /* Irrecoverable error, so don't bother redialing.
881 * The error message should have already been printed
882 * from OpenControlConnection().
883 */
884 PrintF(cip, "Cannot recover from miscellaneous open error %d.\n", result);
885 return result;
886 }
887
888 /* Retryable error, wait and then redial. */
889 if (cip->redialDelay > 0) {
890 /* But don't sleep if this is the last loop. */
891 if ((cip->maxDials < 0) || (dials < (cip->maxDials - 1))) {
892 elapsed = (int) (t1 - t0);
893 if (elapsed < cip->redialDelay) {
894 PrintF(cip, "Sleeping %u seconds.\n",
895 (unsigned) cip->redialDelay - elapsed);
896 if (cip->redialStatusProc != 0)
897 (*cip->redialStatusProc)(cip, kRedialStatusSleeping, cip->redialDelay - elapsed);
898 (void) sleep((unsigned) cip->redialDelay - elapsed);
899 }
900 }
901 }
902 }
903 return (result);
904} /* FTPOpenHost */
905
906
907
908
909int
911{
912 int result;
913 time_t t0, t1;
914 int elapsed;
915 int dials;
916
917 if (cip == NULL)
918 return (kErrBadParameter);
919 if (strcmp(cip->magic, kLibraryMagic))
920 return (kErrBadMagic);
921
922 if (cip->host[0] == '\0') {
923 cip->errNo = kErrBadParameter;
924 return (kErrBadParameter);
925 }
926
927 for ( result = kErrConnectMiscErr, dials = 0;
928 cip->maxDials < 0 || dials < cip->maxDials;
929 dials++)
930 {
931
932 /* Allocate (or if the host was closed, reallocate)
933 * the transfer data buffer.
934 */
935 result = FTPAllocateHost(cip);
936 if (result < 0)
937 return (result);
938
939 if (dials > 0)
940 PrintF(cip, "Retry Number: %d\n", dials);
941 if (cip->redialStatusProc != 0)
942 (*cip->redialStatusProc)(cip, kRedialStatusDialing, dials);
943 (void) time(&t0);
944 result = OpenControlConnection(cip, cip->host, cip->port);
945 (void) time(&t1);
946 if (result == kNoErr) {
947 /* We were hooked up successfully. */
948 PrintF(cip, "Connected to %s.\n", cip->host);
949
950 /* Not logging in... */
951 if (result == kNoErr)
952 break;
954 /* Irrecoverable error, so don't bother redialing.
955 * The error message should have already been printed
956 * from OpenControlConnection().
957 */
958 PrintF(cip, "Cannot recover from miscellaneous open error %d.\n", result);
959 return result;
960 }
961
962 /* Retryable error, wait and then redial. */
963 if (cip->redialDelay > 0) {
964 /* But don't sleep if this is the last loop. */
965 if ((cip->maxDials < 0) || (dials < (cip->maxDials - 1))) {
966 elapsed = (int) (t1 - t0);
967 if (elapsed < cip->redialDelay) {
968 PrintF(cip, "Sleeping %u seconds.\n",
969 (unsigned) cip->redialDelay - elapsed);
970 if (cip->redialStatusProc != 0)
971 (*cip->redialStatusProc)(cip, kRedialStatusSleeping, cip->redialDelay - elapsed);
972 (void) sleep((unsigned) cip->redialDelay - elapsed);
973 }
974 }
975 }
976 }
977 return (result);
978} /* FTPOpenHostNoLogin */
979
980
981
982
983int
984FTPInitConnectionInfo(const FTPLIPtr lip, const FTPCIPtr cip, size_t bufSize)
985{
986 size_t siz;
987
988 if ((lip == NULL) || (cip == NULL) || (bufSize == 0))
989 return (kErrBadParameter);
990
991 siz = sizeof(FTPConnectionInfo);
992 (void) memset(cip, 0, siz);
993
994 if (strcmp(lip->magic, kLibraryMagic))
995 return (kErrBadMagic);
996
997 cip->buf = NULL; /* denote that it needs to be allocated. */
998 cip->bufSize = bufSize;
999 cip->port = lip->defaultPort;
1000 cip->firewallPort = lip->defaultPort;
1011 cip->lip = lip;
1033 (void) STRNCPY(cip->user, "anonymous");
1034 return (kNoErr);
1035} /* FTPInitConnectionInfo */
1036
1037
1038
1039
1040int
1042{
1043 char *buf;
1044
1045 cip->lip = lip;
1046 cip->debugLog = NULL;
1047 cip->errLog = NULL;
1048 cip->debugLogProc = NULL;
1049 cip->errLogProc = NULL;
1050 cip->buf = NULL;
1051 cip->cin = NULL;
1052 cip->cout = NULL;
1053 cip->errNo = 0;
1054 cip->progress = NULL;
1055 cip->rname = NULL;
1056 cip->lname = NULL;
1057 cip->onConnectMsgProc = NULL;
1058 cip->redialStatusProc = NULL;
1059 cip->printResponseProc = NULL;
1060 cip->onLoginMsgProc = NULL;
1061 cip->passphraseProc = NULL;
1064
1065 (void) memset(&cip->lastFTPCmdResultLL, 0, sizeof(LineList));
1066
1067 /* Allocate a new buffer. */
1068 buf = (char *) calloc((size_t) 1, cip->bufSize);
1069 if (buf == NULL) {
1070 cip->errNo = kErrMallocFailed;
1071 return (kErrMallocFailed);
1072 }
1073 cip->buf = buf;
1074
1075 /* Reattach the FILE pointers for use with the Std I/O library
1076 * routines.
1077 */
1078 if ((cip->cin = _fdopen(cip->ctrlSocketR, "r")) == NULL) {
1079 cip->errNo = kErrFdopenR;
1082 return (kErrFdopenR);
1083 }
1084
1085 if ((cip->cout = _fdopen(cip->ctrlSocketW, "w")) == NULL) {
1086 CloseFile(&cip->cin);
1087 cip->errNo = kErrFdopenW;
1090 return (kErrFdopenW);
1091 }
1092
1093#if USE_SIO
1094 if (InitSReadlineInfo(&cip->ctrlSrl, cip->ctrlSocketR, cip->srlBuf, sizeof(cip->srlBuf), (int) cip->ctrlTimeout, 1) < 0) {
1095 cip->errNo = kErrFdopenW;
1096 CloseFile(&cip->cin);
1097 cip->errNo = kErrFdopenW;
1100 return (kErrFdopenW);
1101 }
1102#endif
1103 return (kNoErr);
1104} /* FTPRebuildConnectionInfo */
1105
1106
1107
1108
1109int
1111{
1112 struct servent *ftp;
1113
1114 if (lip == NULL)
1115 return (kErrBadParameter);
1116
1117 (void) memset(lip, 0, sizeof(FTPLibraryInfo));
1118 if ((ftp = getservbyname("ftp", "tcp")) == NULL)
1119 lip->defaultPort = (unsigned int) kDefaultFTPPort;
1120 else
1121 lip->defaultPort = (unsigned int) ntohs(ftp->s_port);
1122
1123 lip->init = 1;
1125
1126 /* We'll initialize the defaultAnonPassword field
1127 * later when we try the first anon ftp connection.
1128 */
1129
1130#ifdef HAVE_LIBSOCKS
1131 SOCKSinit("libncftp");
1132 lip->socksInit = 1;
1133#endif
1134 return (kNoErr);
1135} /* FTPInitLibrary */
1136
1137/* Open.c */
#define STRNCAT(d, s)
Definition: Strn.h:48
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
#define isupper(c)
Definition: acclib.h:71
char * strtok(char *String, const char *Delimiters)
Definition: utclib.c:338
char * strchr(const char *String, int ch)
Definition: utclib.c:501
#define STRNCPY(dst, src, n)
Definition: rdesktop.h:168
BOOL Error
Definition: chkdsk.c:66
#define SIGPIPE
Definition: signal.h:35
#define SIG_IGN
Definition: signal.h:48
#define free
Definition: debug_ros.c:5
#define NULL
Definition: types.h:112
static WCHAR unknown[MAX_STRING_RESOURCE_LEN]
Definition: object.c:1605
USHORT port
Definition: uri.c:228
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
unsigned char
Definition: typeof.h:29
__kernel_time_t time_t
Definition: linux.h:252
#define strncasecmp
Definition: fake.h:10
#define strcasecmp
Definition: fake.h:9
PSERVENT WSAAPI getservbyname(IN const char FAR *name, IN const char FAR *proto)
Definition: getxbyxx.c:500
GLenum src
Definition: glext.h:6340
const GLubyte * c
Definition: glext.h:8905
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum GLenum dst
Definition: glext.h:6340
GLbitfield flags
Definition: glext.h:7161
GLfloat GLfloat p
Definition: glext.h:8902
GLuint GLsizei bufSize
Definition: glext.h:6040
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
_Check_return_ _CRTIMP FILE *__cdecl _fdopen(_In_ int _FileHandle, _In_z_ const char *_Mode)
_Check_return_ _CRTIMP int __cdecl sscanf(_In_z_ const char *_Src, _In_z_ _Scanf_format_string_ const char *_Format,...)
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
#define c
Definition: ke_i.h:80
#define sleep
Definition: syshdrs.h:37
void InitLineList(LineListPtr list)
Definition: linelist.c:54
void DisposeLineListContents(LineListPtr list)
Definition: linelist.c:33
LinePtr AddLine(LineListPtr list, const char *buf1)
Definition: linelist.c:94
POINT cp
Definition: magnifier.c:59
__u16 time
Definition: mkdosfs.c:8
#define ntohs(x)
Definition: module.h:210
int FTPGetCWD(const FTPCIPtr cip, char *const newCwd, const size_t newCwdSize)
Definition: cmds.c:254
void CloseDataConnection(const FTPCIPtr cip)
Definition: ftp.c:831
int SetLinger(const FTPCIPtr cip, int sockfd, int onoff)
Definition: ftp.c:262
int GetOurHostName(char *host, size_t siz)
Definition: ftp.c:81
void CloseControlConnection(const FTPCIPtr cip)
Definition: ftp.c:197
int OpenControlConnection(const FTPCIPtr cip, char *host, unsigned int port)
Definition: ftp.c:347
static void FTPDeallocateHost(const FTPCIPtr cip)
Definition: open.c:11
int FTPOpenHostNoLogin(const FTPCIPtr cip)
Definition: open.c:910
void FTPShutdownHost(const FTPCIPtr cip)
Definition: open.c:564
int FTPInitConnectionInfo(const FTPLIPtr lip, const FTPCIPtr cip, size_t bufSize)
Definition: open.c:984
int FTPQueryFeatures(const FTPCIPtr cip)
Definition: open.c:380
static void FTPExamineMlstFeatures(const FTPCIPtr cip, const char *features)
Definition: open.c:338
void FTPInitializeOurHostName(const FTPLIPtr lip)
Definition: open.c:63
int FTPCloseHost(const FTPCIPtr cip)
Definition: open.c:523
int FTPOpenHost(const FTPCIPtr cip)
Definition: open.c:818
static int FTPAllocateHost(const FTPCIPtr cip)
Definition: open.c:39
void FTPInitializeAnonPassword(const FTPLIPtr lip)
Definition: open.c:81
int FTPRebuildConnectionInfo(const FTPLIPtr lip, const FTPCIPtr cip)
Definition: open.c:1041
int FTPLoginHost(const FTPCIPtr cip)
Definition: open.c:110
int FTPDecodeURL(const FTPCIPtr cip, char *const url, LineListPtr cdlist, char *const fn, const size_t fnsize, int *const xtype, int *const wantnlst)
Definition: open.c:639
int FTPInitLibrary(const FTPLIPtr lip)
Definition: open.c:1110
void URLCopyToken(char *dst, size_t dsize, const char *src, size_t howmuch)
Definition: open.c:598
void CloseFile(FILE **f)
Definition: util.c:327
void PrintF(const FTPCIPtr cip, const char *const fmt,...)
Definition: util.c:340
#define ISTREQ(a, b)
Definition: util.h:33
#define kDontPerror
Definition: util.h:45
#define kClosedFileDescriptor
Definition: util.h:47
#define ISTRNEQ(a, b, s)
Definition: util.h:34
#define ISTRNCMP
Definition: util.h:29
void DisposeSReadlineInfo(SReadlineInfo *)
Definition: SReadline.c:57
int InitSReadlineInfo(SReadlineInfo *, int, char *, size_t, int, int)
Definition: SReadline.c:24
static const WCHAR url[]
Definition: encode.c:1432
static WCHAR ftp[]
Definition: url.c:29
#define kDefaultCtrlTimeout
Definition: ncftp.h:322
#define kFirewallUserAtSite
Definition: ncftp.h:389
#define kFirewallLoginThenUserAtSite
Definition: ncftp.h:390
#define kDefaultMaxDials
Definition: ncftp.h:341
int RCmd(const FTPCIPtr, ResponsePtr, const char *,...)
Definition: rcmd.c:718
#define kMlsOptUNIXgid
Definition: ncftp.h:409
#define kFirewallSiteSite
Definition: ncftp.h:391
#define kMlsOptUnique
Definition: ncftp.h:410
#define kResponseNoPrint
Definition: ncftp.h:308
#define kTypeAscii
Definition: ncftp.h:353
#define kMlsOptSize
Definition: ncftp.h:402
#define kFirewallNotInUse
Definition: ncftp.h:388
void(* FTPSigProc)(int)
Definition: ncftp.h:76
#define kMlsOptModify
Definition: ncftp.h:403
#define kServerTypeNcFTPd
Definition: ncftp.h:463
#define kDefaultRedialDelay
Definition: ncftp.h:342
#define kCommandAvailable
Definition: ncftp.h:380
#define kFirewallUserAtUserPassAtPass
Definition: ncftp.h:393
#define kServerTypeWuFTPd
Definition: ncftp.h:462
#define kMalformedURL
Definition: ncftp.h:385
void DoneWithResponse(const FTPCIPtr, ResponsePtr)
Definition: rcmd.c:114
#define kMlsOptType
Definition: ncftp.h:401
#define kSendPortMode
Definition: ncftp.h:295
#define kRedialStatusDialing
Definition: ncftp.h:346
void FTPAbortDataTransfer(const FTPCIPtr cip)
Definition: rcmd.c:870
void GetUsrName(char *, size_t)
Definition: util.c:290
#define kDefaultConnTimeout
Definition: ncftp.h:321
#define kRedialStatusSleeping
Definition: ncftp.h:347
#define kDefaultXferTimeout
Definition: ncftp.h:320
#define kMlsOptUNIXgroup
Definition: ncftp.h:406
#define kServerTypeNetWareFTP
Definition: ncftp.h:472
void ReInitResponse(const FTPCIPtr, ResponsePtr)
Definition: rcmd.c:142
#define kCommandAvailabilityUnknown
Definition: ncftp.h:379
#define kLibraryMagic
Definition: ncftp.h:65
#define kFirewallFwuAtSiteFwpUserPass
Definition: ncftp.h:394
#define kMlsOptPerm
Definition: ncftp.h:407
#define kFirewallUserAtSiteFwuPassFwp
Definition: ncftp.h:395
#define kMlsOptUNIXmode
Definition: ncftp.h:404
#define kTypeBinary
Definition: ncftp.h:354
#define kMlsOptUNIXuid
Definition: ncftp.h:408
#define kResponseNoSave
Definition: ncftp.h:309
#define kMlsOptUNIXowner
Definition: ncftp.h:405
#define kCommandNotAvailable
Definition: ncftp.h:381
#define kFirewallOpenSite
Definition: ncftp.h:392
#define kDefaultFTPPort
Definition: ncftp.h:312
#define kFirewallLastType
Definition: ncftp.h:396
ResponsePtr InitResponse(void)
Definition: rcmd.c:38
#define NoGetPassphraseProc
Definition: ncftp.h:453
#define kDefaultAbortTimeout
Definition: ncftp.h:323
#define kErrConnectRetryableErr
Definition: ncftp_errno.h:36
#define kNoErr
Definition: ncftp_errno.h:9
#define kErrMallocFailed
Definition: ncftp_errno.h:40
#define kErrFdopenW
Definition: ncftp_errno.h:26
#define kErrConnectMiscErr
Definition: ncftp_errno.h:35
#define kErrFdopenR
Definition: ncftp_errno.h:25
#define kErrLoginFailed
Definition: ncftp_errno.h:73
#define kErrBadMagic
Definition: ncftp_errno.h:55
#define kErrBadParameter
Definition: ncftp_errno.h:56
#define kErrBadRemoteUser
Definition: ncftp_errno.h:71
#define kErrRemoteHostClosedConnection
Definition: ncftp_errno.h:75
#define kErrHostDisconnectedDuringLogin
Definition: ncftp_errno.h:70
#define kErrConnectRefused
Definition: ncftp_errno.h:37
#define kErrBadRemoteUserOrPassword
Definition: ncftp_errno.h:72
#define calloc
Definition: rosglue.h:14
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
int signal
Definition: except.c:82
#define memset(x, y, z)
Definition: compat.h:39
#define StrDup
Definition: shlwapi.h:1533
int firewallType
Definition: ncftp.h:221
FILE * cout
Definition: ncftp.h:189
int ietfCompatLevel
Definition: ncftp.h:233
unsigned int firewallPort
Definition: ncftp.h:220
FTPPrintResponseProc printResponseProc
Definition: ncftp.h:226
int curTransferType
Definition: ncftp.h:157
char srlBuf[768]
Definition: ncftp.h:239
FTPLogProc errLogProc
Definition: ncftp.h:148
int hasRETRBUFSIZE
Definition: ncftp.h:171
int doNotGetStartingWorkingDirectory
Definition: ncftp.h:237
char * startingWorkingDirectory
Definition: ncftp.h:158
char host[64]
Definition: ncftp.h:136
char magic[16]
Definition: ncftp.h:135
LineList lastFTPCmdResultLL
Definition: ncftp.h:215
unsigned int xferTimeout
Definition: ncftp.h:141
char firewallPass[64]
Definition: ncftp.h:219
unsigned int connTimeout
Definition: ncftp.h:142
int dataPortMode
Definition: ncftp.h:152
FTPProgressMeterProc progress
Definition: ncftp.h:198
int NLSTfileParamWorks
Definition: ncftp.h:180
int hasSTORBUFSIZE
Definition: ncftp.h:174
unsigned int abortTimeout
Definition: ncftp.h:144
const char * asciiFilenameExtensions
Definition: ncftp.h:246
FTPGetPassphraseProc passphraseProc
Definition: ncftp.h:242
FTPConnectMessageProc onConnectMsgProc
Definition: ncftp.h:224
FILE * debugLog
Definition: ncftp.h:145
FILE * errLog
Definition: ncftp.h:146
const char * rname
Definition: ncftp.h:208
FTPRedialStatusProc redialStatusProc
Definition: ncftp.h:225
const char * lname
Definition: ncftp.h:209
int STATfileParamWorks
Definition: ncftp.h:179
FTPLoginMessageProc onLoginMsgProc
Definition: ncftp.h:227
size_t bufSize
Definition: ncftp.h:187
unsigned int port
Definition: ncftp.h:140
FTPLIPtr lip
Definition: ncftp.h:149
char pass[64]
Definition: ncftp.h:138
SReadlineInfo ctrlSrl
Definition: ncftp.h:240
char firewallUser[64]
Definition: ncftp.h:218
unsigned int ctrlTimeout
Definition: ncftp.h:143
FILE * cin
Definition: ncftp.h:188
char acct[64]
Definition: ncftp.h:139
FTPLogProc debugLogProc
Definition: ncftp.h:147
char user[64]
Definition: ncftp.h:137
char * buf
Definition: ncftp.h:186
int socksInit
Definition: ncftp.h:116
char defaultAnonPassword[80]
Definition: ncftp.h:121
int hresult
Definition: ncftp.h:119
char magic[16]
Definition: ncftp.h:114
char ourHostName[64]
Definition: ncftp.h:118
int htried
Definition: ncftp.h:120
unsigned int defaultPort
Definition: ncftp.h:117
Definition: ncftp.h:84
LinePtr first
Definition: ncftp.h:85
Definition: ncftp.h:79
char * line
Definition: ncftp.h:81
LinePtr next
Definition: ncftp.h:80
Definition: ncftp.h:89
int eofOkay
Definition: ncftp.h:94
int printMode
Definition: ncftp.h:93
int code
Definition: ncftp.h:92
LineList msg
Definition: ncftp.h:90
static GLenum _GLUfuncptr fn
Definition: wgl_font.c:159