0
|
1 /* ftpsbr.c - simple FTP client library (why doesn't BSD have one?!?) */
|
|
2
|
|
3 #ifndef lint
|
|
4 static char ident[] = "@(#)$Id$";
|
|
5 #endif
|
|
6
|
|
7 #include "../h/mh.h"
|
|
8 #include "../h/mhn.h"
|
|
9 #ifdef FTP
|
|
10 #include <ctype.h>
|
|
11 #ifdef SVR4
|
|
12 #undef NULLVP /* stdio.h */
|
|
13 #endif
|
|
14 #include <stdio.h>
|
|
15 #include <arpa/ftp.h>
|
|
16 #ifdef __STDC__
|
|
17 #include <stdarg.h>
|
|
18 #else
|
|
19 #include <varargs.h>
|
|
20 #endif
|
|
21
|
|
22 #ifdef __STDC__
|
|
23 static int command(int arg1, ...);
|
|
24 #else
|
|
25 static int command();
|
|
26 #endif
|
|
27
|
|
28 static int ftp_quit(), ftp_read(), initconn(),
|
|
29 dataconn(), _command(), getreply();
|
|
30
|
|
31 /* DATA */
|
|
32
|
|
33 #define v_debug debugsw
|
|
34 #define v_verbose verbosw
|
|
35
|
|
36
|
|
37 static int ftp_fd = NOTOK;
|
|
38 static int data_fd = NOTOK;
|
|
39
|
|
40 static int v_noise;
|
|
41
|
|
42 extern int v_debug;
|
|
43 extern int v_verbose;
|
|
44
|
|
45 /* */
|
|
46
|
|
47 #if defined(SYS5) && defined(AUX)
|
|
48 #define u_short ushort
|
|
49 #define u_long ulong
|
|
50 #endif
|
|
51
|
|
52 #include <sys/types.h>
|
|
53 #include <sys/socket.h>
|
|
54 #include <netinet/in.h>
|
|
55 #include <netdb.h>
|
|
56
|
|
57 #if defined(BIND) && !defined(h_addr)
|
|
58 #define h_addr h_addr_list[0]
|
|
59 #endif
|
|
60
|
|
61 #define inaddr_copy(hp,sin) \
|
|
62 bcopy ((hp) -> h_addr, (char *) &((sin) -> sin_addr), (hp) -> h_length)
|
|
63
|
|
64
|
|
65 struct hostent *gethostbystring ();
|
|
66
|
|
67 /* */
|
|
68
|
|
69 #ifdef __CYGWIN32__
|
|
70 #include <errno.h>
|
|
71 #endif
|
|
72 extern int errno;
|
|
73 #if !defined(BSD44) && !defined(__GNU_LIBRARY__)
|
|
74 extern int sys_nerr;
|
|
75 extern char *sys_errlist[];
|
|
76 #endif
|
|
77 #ifdef __NetBSD__ /* XXX */
|
|
78 #include <errno.h>
|
|
79 #endif
|
|
80
|
|
81
|
|
82 #define start_tcp_client(sock,priv) \
|
|
83 socket (AF_INET, SOCK_STREAM, 0)
|
|
84
|
|
85 #define join_tcp_server(fd, sock) \
|
|
86 connect ((fd), (struct sockaddr *) (sock), sizeof *(sock))
|
|
87
|
|
88
|
|
89 /* ARGSUSED */
|
|
90
|
|
91 static int start_tcp_server (sock, backlog, opt1, opt2)
|
|
92 struct sockaddr_in *sock;
|
|
93 int backlog,
|
|
94 opt1,
|
|
95 opt2;
|
|
96 {
|
|
97 int eindex,
|
|
98 sd;
|
|
99
|
|
100 if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == NOTOK)
|
|
101 return NOTOK;
|
|
102
|
|
103 if (bind (sd, (struct sockaddr *) sock, sizeof *sock) == NOTOK) {
|
|
104 eindex = errno;
|
|
105 (void) close (sd);
|
|
106 errno = eindex;
|
|
107 }
|
|
108 else
|
|
109 (void) listen (sd, backlog);
|
|
110
|
|
111 return sd;
|
|
112 }
|
|
113
|
|
114 static int __len__;
|
|
115 #define join_tcp_client(fd,sock) \
|
|
116 accept ((fd), (struct sockaddr *) (sock), \
|
|
117 (__len__ = sizeof *(sock), &__len__))
|
|
118
|
|
119
|
|
120 #define read_tcp_socket read
|
|
121 #define write_tcp_socket write
|
|
122 #define close_tcp_socket close
|
|
123
|
|
124 /* */
|
|
125
|
|
126 static void _asprintf (bp, what, ap) /* fmt, args, ... */
|
|
127 register char *bp;
|
|
128 char *what;
|
|
129 va_list ap;
|
|
130 {
|
|
131 register int eindex;
|
|
132 char *fmt;
|
|
133
|
|
134 eindex = errno;
|
|
135
|
|
136 *bp = '\0';
|
|
137 fmt = va_arg (ap, char *);
|
|
138
|
|
139 if (fmt) {
|
|
140 #ifndef VSPRINTF
|
|
141 struct _iobuf iob;
|
|
142 #endif
|
|
143
|
|
144 #ifndef VSPRINTF
|
|
145 #ifdef pyr
|
|
146 bzero ((char *) &iob, sizeof iob);
|
|
147 iob._file = _NFILE;
|
|
148 #endif
|
|
149 iob._flag = _IOWRT | _IOSTRG;
|
|
150 #if !defined(vax) && !defined(pyr) && !defined(sequent)
|
|
151 iob._ptr = (unsigned char *) bp;
|
|
152 #else
|
|
153 iob._ptr = bp;
|
|
154 #endif
|
|
155 iob._cnt = BUFSIZ;
|
|
156 _doprnt (fmt, ap, &iob);
|
|
157 (void) putc ('\0', &iob);
|
|
158 #else
|
|
159 (void) vsprintf (bp, fmt, ap);
|
|
160 #endif
|
|
161 bp += strlen (bp);
|
|
162
|
|
163 }
|
|
164
|
|
165 if (what) {
|
|
166 if (*what) {
|
|
167 (void) sprintf (bp, " %s: ", what);
|
|
168 bp += strlen (bp);
|
|
169 }
|
|
170 if (0 < eindex && eindex < sys_nerr)
|
|
171 (void) strcpy (bp, sys_errlist[eindex]);
|
|
172 else
|
|
173 (void) sprintf (bp, "Error %d", eindex);
|
|
174 bp += strlen (bp);
|
|
175 }
|
|
176
|
|
177 errno = eindex;
|
|
178 }
|
|
179
|
|
180 /* */
|
|
181
|
|
182 int ftp_get (host, user, password, cwd, remote, local, ascii, stayopen)
|
|
183 char *host,
|
|
184 *user,
|
|
185 *password,
|
|
186 *cwd,
|
|
187 *remote,
|
|
188 *local;
|
|
189 int ascii,
|
|
190 stayopen;
|
|
191 {
|
|
192 return ftp_trans (host, user, password, cwd, remote, local, "RETR", ascii,
|
|
193 stayopen);
|
|
194 }
|
|
195
|
|
196 /* */
|
|
197
|
|
198 int ftp_trans (host, user, password, cwd, remote, local, cmd, ascii,
|
|
199 stayopen)
|
|
200 char *host,
|
|
201 *user,
|
|
202 *password,
|
|
203 *cwd,
|
|
204 *remote,
|
|
205 *local,
|
|
206 *cmd;
|
|
207 int ascii,
|
|
208 stayopen;
|
|
209 {
|
|
210 int result;
|
|
211
|
|
212 if (stayopen <= 0) {
|
|
213 result = ftp_quit ();
|
|
214 if (host == NULL)
|
|
215 return result;
|
|
216 }
|
|
217
|
|
218 if (ftp_fd == NOTOK) {
|
|
219 struct sockaddr_in in_socket;
|
|
220 register struct hostent *hp;
|
|
221 register struct servent *sp;
|
|
222
|
|
223 if ((sp = getservbyname ("ftp", "tcp")) == NULL) {
|
|
224 fprintf (stderr, "tcp/ftp: unknown service");
|
|
225 return NOTOK;
|
|
226 }
|
|
227 if ((hp = gethostbystring (host)) == NULL) {
|
|
228 fprintf (stderr, "%s: unknown host\n", host);
|
|
229 return NOTOK;
|
|
230 }
|
|
231 in_socket.sin_family = hp -> h_addrtype;
|
|
232 inaddr_copy (hp, &in_socket);
|
|
233 in_socket.sin_port = sp -> s_port;
|
|
234
|
|
235 if ((ftp_fd = start_tcp_client ((struct sockaddr_in *) NULL, 0))
|
|
236 == NOTOK) {
|
|
237 perror (host);
|
|
238 return NOTOK;
|
|
239 }
|
|
240 if (join_tcp_server (ftp_fd, &in_socket) == NOTOK) {
|
|
241 perror (host);
|
|
242 (void) close_tcp_socket (ftp_fd), ftp_fd = NOTOK;
|
|
243 return NOTOK;
|
|
244 }
|
|
245 (void) getreply (1, 0);
|
|
246
|
|
247 if (v_verbose) {
|
|
248 fprintf (stdout, "Connected to %s\n", host);
|
|
249 (void) fflush (stdout);
|
|
250 }
|
|
251
|
|
252 if (user) {
|
|
253 if ((result = command (0, "USER %s", user)) == CONTINUE)
|
|
254 result = command (1, "PASS %s", password);
|
|
255 if (result != COMPLETE) {
|
|
256 result = NOTOK;
|
|
257 goto out;
|
|
258 }
|
|
259 }
|
|
260
|
|
261 if (remote == NULL)
|
|
262 return OK;
|
|
263 }
|
|
264
|
|
265 if (cwd && ((result = command (0, "CWD %s", cwd)) != COMPLETE
|
|
266 && result != CONTINUE)) {
|
|
267 result = NOTOK;
|
|
268 goto out;
|
|
269 }
|
|
270
|
|
271 if (command (1, ascii ? "TYPE A" : "TYPE I") != COMPLETE) {
|
|
272 result = NOTOK;
|
|
273 goto out;
|
|
274 }
|
|
275
|
|
276 result = ftp_read (remote, local, cmd, ascii);
|
|
277
|
|
278 out: ;
|
|
279 if (result != OK || !stayopen)
|
|
280 (void) ftp_quit ();
|
|
281
|
|
282 return result;
|
|
283 }
|
|
284
|
|
285 /* */
|
|
286
|
|
287 static int ftp_quit ()
|
|
288 {
|
|
289 int n;
|
|
290
|
|
291 if (ftp_fd == NOTOK)
|
|
292 return OK;
|
|
293
|
|
294 n = command (1, "QUIT");
|
|
295
|
|
296 (void) close_tcp_socket (ftp_fd), ftp_fd = NOTOK;
|
|
297
|
|
298 return (n == 0 || n == COMPLETE ? OK : NOTOK);
|
|
299 }
|
|
300
|
|
301 /* */
|
|
302
|
|
303 static int ftp_read (remote, local, cmd, ascii)
|
|
304 char *remote,
|
|
305 *local,
|
|
306 *cmd;
|
|
307 int ascii;
|
|
308 {
|
|
309 int istdio = 0,
|
|
310 istore;
|
|
311 register int cc;
|
|
312 int expectingreply = 0;
|
|
313 char buffer[BUFSIZ];
|
|
314 FILE *fp = NULL;
|
|
315
|
|
316 if (initconn () == NOTOK)
|
|
317 goto bad;
|
|
318
|
|
319 v_noise = v_verbose;
|
|
320 if (command (-1, *remote ? "%s %s" : "%s", cmd, remote) != PRELIM)
|
|
321 goto bad;
|
|
322
|
|
323 expectingreply++;
|
|
324 if (dataconn () == NOTOK) {
|
|
325 bad: ;
|
|
326 if (fp && !istdio)
|
|
327 (void) fclose (fp);
|
|
328 if (data_fd != NOTOK)
|
|
329 (void) close_tcp_socket (data_fd), data_fd = NOTOK;
|
|
330 if (expectingreply)
|
|
331 (void) getreply (-2, 0);
|
|
332
|
|
333 return NOTOK;
|
|
334 }
|
|
335
|
|
336 istore = !strcmp (cmd, "STOR");
|
|
337
|
|
338 if (istdio = !strcmp (local, "-"))
|
|
339 fp = istore ? stdin : stdout;
|
|
340 else
|
|
341 if ((fp = fopen (local, istore ? "r" : "w")) == NULL) {
|
|
342 perror (local);
|
|
343 goto bad;
|
|
344 }
|
|
345
|
|
346 if (istore) {
|
|
347 if (ascii) {
|
|
348 int c;
|
|
349 FILE *out;
|
|
350
|
|
351 if (!(out = fdopen (data_fd, "w"))) {
|
|
352 perror ("fdopen");
|
|
353 goto bad;
|
|
354 }
|
|
355
|
|
356 while ((c = getc (fp)) != EOF) {
|
|
357 if (c == '\n')
|
|
358 (void) putc ('\r', out);
|
|
359 if (putc (c, out) == EOF) {
|
|
360 perror ("putc");
|
|
361 (void) fclose (out);
|
|
362 data_fd = NOTOK;
|
|
363 goto bad;
|
|
364 }
|
|
365 }
|
|
366
|
|
367 (void) fclose (out);
|
|
368 data_fd = NOTOK;
|
|
369 }
|
|
370 else {
|
|
371 while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, fp)) >0)
|
|
372 if (write_tcp_socket (data_fd, buffer, cc) != cc) {
|
|
373 perror ("write_tcp_socket");
|
|
374 goto bad;
|
|
375 }
|
|
376
|
|
377 (void) close_tcp_socket (data_fd), data_fd = NOTOK;
|
|
378 }
|
|
379 }
|
|
380 else {
|
|
381 if (ascii) {
|
|
382 int c;
|
|
383 FILE *in;
|
|
384
|
|
385 if (!(in = fdopen (data_fd, "r"))) {
|
|
386 perror ("fdopen");
|
|
387 goto bad;
|
|
388 }
|
|
389
|
|
390 while ((c = getc (in)) != EOF) {
|
|
391 if (c == '\r')
|
|
392 switch (c = getc (in)) {
|
|
393 case EOF:
|
|
394 case '\0':
|
|
395 c = '\r';
|
|
396 break;
|
|
397
|
|
398 case '\n':
|
|
399 break;
|
|
400
|
|
401 default:
|
|
402 (void) putc ('\r', fp);
|
|
403 break;
|
|
404 }
|
|
405
|
|
406 if (putc (c, fp) == EOF) {
|
|
407 perror ("putc");
|
|
408 (void) fclose (in);
|
|
409 data_fd = NOTOK;
|
|
410 goto bad;
|
|
411 }
|
|
412 }
|
|
413
|
|
414 (void) fclose (in);
|
|
415 data_fd = NOTOK;
|
|
416 }
|
|
417 else {
|
|
418 while ((cc = read_tcp_socket (data_fd, buffer, sizeof buffer)) > 0)
|
|
419 if (fwrite (buffer, sizeof *buffer, cc, fp) == 0) {
|
|
420 perror ("fwrite");
|
|
421 goto bad;
|
|
422 }
|
|
423 if (cc < 0) {
|
|
424 perror ("read_tcp_socket");
|
|
425 goto bad;
|
|
426 }
|
|
427
|
|
428 (void) close_tcp_socket (data_fd), data_fd = NOTOK;
|
|
429 }
|
|
430 }
|
|
431
|
|
432 if (!istdio)
|
|
433 (void) fclose (fp);
|
|
434
|
|
435 v_noise = v_verbose;
|
|
436 return (getreply (1, 0) == COMPLETE ? OK : NOTOK);
|
|
437 }
|
|
438
|
|
439 /* */
|
|
440
|
|
441 static int initconn ()
|
|
442 {
|
|
443 int len;
|
|
444 register char *a,
|
|
445 *p;
|
|
446 struct sockaddr_in in_socket;
|
|
447
|
|
448 if (getsockname (ftp_fd, (struct sockaddr *) &in_socket,
|
|
449 (len = sizeof in_socket, &len)) == NOTOK) {
|
|
450 perror ("getsockname");
|
|
451 return NOTOK;
|
|
452 }
|
|
453 in_socket.sin_port = 0;
|
|
454 if ((data_fd = start_tcp_server (&in_socket, 1, 0, 0)) == NOTOK) {
|
|
455 perror ("start_tcp_server");
|
|
456 return NOTOK;
|
|
457 }
|
|
458
|
|
459 if (getsockname (data_fd, (struct sockaddr *) &in_socket,
|
|
460 (len = sizeof in_socket, &len)) == NOTOK) {
|
|
461 perror ("getsockname");
|
|
462 return NOTOK;
|
|
463 }
|
|
464
|
|
465 a = (char *) &in_socket.sin_addr;
|
|
466 p = (char *) &in_socket.sin_port;
|
|
467
|
|
468 #define UC(b) (((int) b) & 0xff)
|
|
469 if (command (1, "PORT %d,%d,%d,%d,%d,%d",
|
|
470 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
|
|
471 UC(p[0]), UC(p[1])) == COMPLETE)
|
|
472 return OK;
|
|
473
|
|
474 return NOTOK;
|
|
475 }
|
|
476
|
|
477 /* */
|
|
478
|
|
479 static int dataconn ()
|
|
480 {
|
|
481 int fd;
|
|
482 struct sockaddr_in in_socket;
|
|
483
|
|
484 if ((fd = join_tcp_client (data_fd, &in_socket)) == NOTOK) {
|
|
485 perror ("join_tcp_client");
|
|
486 return NOTOK;
|
|
487 }
|
|
488 (void) close_tcp_socket (data_fd);
|
|
489 data_fd = fd;
|
|
490
|
|
491 return OK;
|
|
492 }
|
|
493
|
|
494 /* */
|
|
495
|
|
496 #ifndef lint
|
|
497 #ifdef __STDC__
|
|
498 static int command (int arg1, ...)
|
|
499 {
|
|
500 int val;
|
|
501 va_list ap;
|
|
502
|
|
503 va_start (ap, arg1);
|
|
504
|
|
505 val = _command (arg1, ap);
|
|
506
|
|
507 va_end (ap);
|
|
508
|
|
509 return val;
|
|
510 }
|
|
511 #else
|
|
512 static int command (va_alist)
|
|
513 va_dcl
|
|
514 {
|
|
515 int val;
|
|
516 va_list ap;
|
|
517
|
|
518 va_start (ap);
|
|
519
|
|
520 val = va_arg (ap, int);
|
|
521 val = _command (val, ap);
|
|
522
|
|
523 va_end (ap);
|
|
524
|
|
525 return val;
|
|
526 }
|
|
527 #endif
|
|
528
|
|
529 static int _command (complete, ap)
|
|
530 int complete;
|
|
531 va_list ap;
|
|
532 {
|
|
533 int len;
|
|
534 char buffer[BUFSIZ];
|
|
535
|
|
536 if (ftp_fd == NOTOK)
|
|
537 return NOTOK;
|
|
538
|
|
539 _asprintf (buffer, NULLCP, ap);
|
|
540 if (v_debug)
|
|
541 fprintf (stderr, "<--- %s\n", buffer);
|
|
542
|
|
543 (void) strcat (buffer, "\r\n");
|
|
544 len = strlen (buffer);
|
|
545
|
|
546 if (write_tcp_socket (ftp_fd, buffer, len) != len) {
|
|
547 perror ("write_tcp_socket");
|
|
548 return NOTOK;
|
|
549 }
|
|
550
|
|
551 return (getreply (complete, !strcmp (buffer, "QUIT")));
|
|
552 }
|
|
553 #else
|
|
554 /* VARARGS2 */
|
|
555
|
|
556 static int command (complete, fmt)
|
|
557 int complete;
|
|
558 char *fmt;
|
|
559 {
|
|
560 return command (complete, fmt);
|
|
561 }
|
|
562 #endif
|
|
563
|
|
564 /* */
|
|
565
|
|
566 static int getreply (complete, expecteof)
|
|
567 int complete,
|
|
568 expecteof;
|
|
569 {
|
|
570 for (;;) {
|
|
571 register int code,
|
|
572 dig,
|
|
573 n;
|
|
574 int continuation;
|
|
575 register char *bp;
|
|
576 char buffer[BUFSIZ];
|
|
577
|
|
578 code = dig = n = continuation = 0;
|
|
579 bp = buffer;
|
|
580
|
|
581 for (;;) {
|
|
582 char c;
|
|
583
|
|
584 if (read_tcp_socket (ftp_fd, &c, 1) < 1) {
|
|
585 if (expecteof)
|
|
586 return OK;
|
|
587
|
|
588 perror ("read_tcp_socket");
|
|
589 return DONE;
|
|
590 }
|
|
591 if (c == '\n')
|
|
592 break;
|
|
593 *bp++ = c != '\r' ? c : '\0';
|
|
594
|
|
595 dig++;
|
|
596 if (dig < 4) {
|
|
597 if (isdigit(c))
|
|
598 code = code * 10 + (c - '0');
|
|
599 else /* XXX: naughty FTP... */
|
|
600 if (isspace (c))
|
|
601 continuation++;
|
|
602 }
|
|
603 else
|
|
604 if (dig == 4 && c == '-')
|
|
605 continuation++;
|
|
606 if (n == 0)
|
|
607 n = c;
|
|
608 }
|
|
609
|
|
610 if (v_debug)
|
|
611 fprintf (stderr, "---> %s\n", buffer);
|
|
612 if (continuation)
|
|
613 continue;
|
|
614
|
|
615 n -= '0';
|
|
616
|
|
617 if (v_noise) {
|
|
618 fprintf (stdout, "%s\n", buffer);
|
|
619 (void) fflush (stdout);
|
|
620 v_noise = 0;
|
|
621 }
|
|
622 else
|
|
623 if ((complete == -1 && n != PRELIM)
|
|
624 || (complete == 0 && n != CONTINUE && n != COMPLETE)
|
|
625 || (complete == 1 && n != COMPLETE))
|
|
626 fprintf (stderr, "%s\n", buffer);
|
|
627
|
|
628 return n;
|
|
629 }
|
|
630 }
|
|
631 #endif
|