1
2 /*
3
4 File: ftpproxy/ftp.c
5
6 Copyright (C) 1999, 2000 Wolfgang Zekoll <wzk@quietsche-entchen.de>
7 Copyright (C) 2000, 2003 Andreas Schoenberg <asg@ftpproxy.org>
8
9 This software is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23 */
24
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <stdarg.h>
31
32 #include <time.h>
33 #include <signal.h>
34 #include <sys/wait.h>
35 #include <ctype.h>
36 #include <errno.h>
37
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/fcntl.h>
41 #include <sys/socket.h>
42 #include <netdb.h>
43 #include <netinet/in.h>
44 #include <netinet/tcp.h>
45 #include <arpa/inet.h>
46 #include <syslog.h>
47 #include <sys/time.h>
48
49 #include "ftp.h"
50 #include "ip-lib.h"
51 #include "lib.h"
52
53
54 typedef struct _ftpcmd {
55 char name[20];
56 int par, ispath, useccp;
57 int resp;
58 int log;
59 } ftpcmd_t;
60
61 ftpcmd_t cmdtab[] = {
62
63 /*
64 * Einfache FTP Kommandos.
65 */
66
67 { "ABOR", 0, 0, 0, 225, 1 }, /* oder 226 */
68 { "ACCT", 1, 0, 0, 230, 0 },
69 { "CDUP", 1, 1, 1, 200, 1 },
70 { "CWD", 1, 1, 1, 250, 1 },
71 { "DELE", 1, 1, 1, 250, 1 },
72 { "NOOP", 0, 0, 0, 200, 0 },
73 { "MDTM", 1, 1, 1, 257, 1 },
74 { "MKD", 1, 1, 1, 257, 1 },
75 { "MODE", 1, 0, 0, 200, 0 },
76 { "PWD", 0, 0, 0, 257, 0 },
77 { "QUIT", 0, 0, 0, 221, 0 },
78 { "REIN", 0, 0, 0, 0, /* 220, */ 0 }, /* wird nicht unterstuetzt */
79 { "REST", 1, 0, 0, 350, 0 },
80 { "RNFR", 1, 1, 1, 350, 1 },
81 { "RNTO", 1, 1, 1, 250, 1 },
82 { "RMD", 1, 1, 1, 250, 1 },
83 { "SITE", 1, 0, 1, 200, 0 },
84 { "SIZE", 1, 1, 1, 213, 1 },
85 { "SMNT", 1, 0, 0, 250, 0 },
86 { "STAT", 1, 1, 1, 211, 0 }, /* oder 212, 213 */
87 { "STRU", 1, 0, 0, 0, /* 200, */ 0 }, /* wird nicht unterstuetzt */
88 { "SYST", 0, 0, 0, 215, 0 },
89 { "TYPE", 1, 0, 0, 200, 0 },
90 { "XCUP", 1, 1, 1, 200, 1 },
91 { "XCWD", 1, 1, 1, 250, 1 },
92 { "XMKD", 1, 1, 1, 257, 1 },
93 { "XPWD", 0, 0, 0, 257, 0 },
94 { "XRMD", 1, 1, 1, 250, 1 },
95
96 /*
97 * Nur der Vollstaendigkeit halber: FTP Kommandos die gesondert
98 * behandelt werden.
99 */
100
101 { "LIST", 1, 1, 1, 0, 0 },
102 { "NLST", 1, 1, 1, 0, 0 },
103 { "PORT", 1, 0, 0, 0, /* 200, */ 0 },
104 { "PASV", 0, 0, 0, 0, /* 200, */ 0 },
105 { "ALLO", 1, 0, 0, 0, /* 200, */ 0 },
106 { "RETR", 1, 1, 1, 0, 0 },
107 { "STOR", 1, 1, 1, 0, 0 },
108 { "STOU", 0, 0, 1, 0, 0 },
109 { "APPE", 1, 1, 1, 0, 0 },
110 { "HELP", 0, 0, 0, 0, 0 },
111 { "FEAT", 0, 0, 0, 0, 0 },
112 { "", 0, 0, 0, 0, 0 }
113 };
114
115
get_interface_info(int pfd,char * ip,int max)116 unsigned get_interface_info(int pfd, char *ip, int max)
117 {
118 int size;
119 unsigned int port;
120 struct sockaddr_in saddr;
121
122 size = sizeof(saddr);
123 if (getsockname(pfd, (struct sockaddr *) &saddr, &size) < 0) {
124 syslog(LOG_NOTICE, "-ERR: can't get interface info: %s", strerror(errno));
125 exit (-1);
126 }
127
128 copy_string(ip, (char *) inet_ntoa(saddr.sin_addr), max);
129 port = ntohs(saddr.sin_port);
130
131 return (port);
132 }
133
get_client_info(ftp_t * x,int pfd)134 int get_client_info(ftp_t *x, int pfd)
135 {
136 int size;
137 struct sockaddr_in saddr;
138 struct in_addr *addr;
139 struct hostent *hostp = NULL;
140
141 *x->client = 0;
142 size = sizeof(saddr);
143 if (getpeername(pfd, (struct sockaddr *) &saddr, &size) < 0 )
144 return (-1);
145
146 copy_string(x->client_ip, (char *) inet_ntoa(saddr.sin_addr), sizeof(x->client_ip));
147
148 if (x->config->numeric_only == 1)
149 copy_string(x->client, x->client_ip, sizeof(x->client));
150 else {
151 addr = &saddr.sin_addr,
152 hostp = gethostbyaddr((char *) addr,
153 sizeof (saddr.sin_addr.s_addr), AF_INET);
154
155 copy_string(x->client, hostp == NULL? x->client_ip: hostp->h_name, sizeof(x->client));
156 }
157
158 strlwr(x->client);
159
160 return (0);
161 }
162
163
164 /*
165 * Basic I/O functions
166 */
167
close_ch(ftp_t * x,dtc_t * ch)168 int close_ch(ftp_t *x, dtc_t *ch)
169 {
170 if (ch->isock >= 0)
171 close(ch->isock);
172
173 if (ch->osock >= 0)
174 close (ch->osock);
175
176 ch->isock = -1;
177 ch->osock = -1;
178 ch->state = 0;
179 ch->operation = 0;
180 ch->seen150 = 0;
181
182 return (0);
183 }
184
getc_fd(ftp_t * x,int fd)185 int getc_fd(ftp_t *x, int fd)
186 {
187 int c;
188 bio_t *bio;
189
190 if (fd == 0)
191 bio = &x->cbuf;
192 else if (fd == x->fd.server)
193 bio = &x->sbuf;
194 else {
195 syslog(LOG_NOTICE, "-ERR: internal bio/fd error");
196 exit (1);
197 }
198
199 if (bio->here >= bio->len) {
200 int rc, max, bytes, earlyreported;
201 struct timeval tov;
202 fd_set available, fdset;
203
204 bio->len = bio->here = 0;
205 earlyreported = 0;
206
207 FD_ZERO(&fdset);
208 FD_SET(fd, &fdset);
209 /* x->fd.max = fd; */
210 max = fd;
211
212 if (x->ch.operation == 0)
213 /* nichts */ ;
214 else if (x->ch.state == PORT_LISTEN) {
215 if (x->ch.mode == MODE_PORT) {
216 FD_SET(x->ch.osock, &fdset);
217 if (x->ch.osock > max)
218 max = x->ch.osock;
219
220 x->ch.active = x->ch.osock;
221 }
222 else if (x->ch.mode == MODE_PASSIVE) {
223 FD_SET(x->ch.isock, &fdset);
224 if (x->ch.isock > max)
225 max = x->ch.isock;
226
227 x->ch.active = x->ch.isock;
228 }
229 else {
230 syslog(LOG_NOTICE, "-ERR: internal mode error");
231 exit (-1);
232 }
233 }
234 else if (x->ch.state == PORT_CONNECTED && x->ch.seen150 == 1) {
235 FD_SET(x->ch.active, &fdset);
236 if (x->ch.active > max)
237 max = x->ch.active;
238 }
239
240 bytes = 0;
241 while (1) {
242 /* memmove(&available, &fdset, sizeof(fd_set)); */
243 available = fdset;
244 tov.tv_sec = x->config->timeout;
245 tov.tv_usec = 0;
246
247 if (debug >= 2)
248 fprintf (stderr, "select max= %d\n", max);
249
250 rc = select(max + 1, &available, (fd_set *) NULL, (fd_set *) NULL, &tov);
251 if (rc < 0) {
252 syslog(LOG_NOTICE, "select() error: %s\n", strerror(errno));
253 break;
254 }
255 else if (rc == 0) {
256 syslog(LOG_NOTICE, "connection timed out: client= %s, server= %s:%u",
257 x->client, x->server.name, x->server.port);
258 return (-1);
259 }
260
261 if (FD_ISSET(fd, &available)) {
262 if ((bytes = read(fd, bio->buffer, sizeof(bio->buffer) - 2)) <= 0) {
263 if (debug != 0) {
264 if (bytes == 0)
265 fprintf (stderr, "received zero bytes on fd %d\n", fd);
266 else
267 fprintf (stderr, "received %d bytes on fd %d, errno= %d, error= %s\n", bytes, fd, errno, strerror(errno));
268 }
269
270 return (-1);
271 }
272
273 break;
274 }
275 else if (FD_ISSET(x->ch.active, &available)) {
276 if (x->ch.state == PORT_LISTEN) {
277 int sock, adrlen;
278 struct sockaddr_in adr;
279
280 earlyreported = 0;
281 adrlen = sizeof(struct sockaddr);
282 sock = accept(x->ch.active, (struct sockaddr *) &adr, &adrlen);
283 if (debug != 0)
284 fprintf (stderr, "accept() on socket\n");
285
286 if (sock < 0) {
287 syslog(LOG_NOTICE, "-ERR: accept error: %s", strerror(errno));
288 exit (1);
289 }
290 else {
291 char remote[80];
292
293 copy_string(remote, inet_ntoa(adr.sin_addr), sizeof(remote));
294 if (debug)
295 fprintf (stderr, "connection from %s\n", remote);
296
297 /*
298 * Gegenstelle ueberpruefen.
299 */
300
301 if (x->ch.mode == MODE_PORT) {
302 if (strcmp(x->server.ipnum, remote) != 0) {
303 if (x->config->allow_anyremote != 0)
304 /* configuration tells us not to care -- 31JAN02asg */ ;
305 else {
306 syslog(LOG_NOTICE, "-ERR: unexpected connect: %s, expected= %s", remote, x->server.ipnum);
307 exit (1);
308 }
309 }
310 }
311 else {
312 if (strcmp(x->client_ip, remote) != 0) {
313 if (x->config->allow_anyremote != 0)
314 /* ok -- 31JAN02asg */ ;
315 else {
316 syslog(LOG_NOTICE, "-ERR: unexpected connect: %s, expected= %s", remote, x->client_ip);
317 exit (1);
318 }
319 }
320 }
321 }
322
323 /*
324 * Datenkanal zur anderen Seite aufbauen.
325 */
326
327 if (x->ch.mode == MODE_PORT) {
328 dup2(sock, x->ch.osock);
329 close (sock);
330 x->ch.state = PORT_CONNECTED;
331 if (debug)
332 fprintf (stderr, "osock= %d\n", x->ch.osock);
333
334 if ((x->ch.isock = openip(x->ch.client.ipnum, x->ch.client.port, x->interface, x->config->dataport)) < 0) {
335 syslog(LOG_NOTICE, "-ERR: can't connect to client: %s", strerror(errno));
336 exit (1);
337 }
338
339 if (debug)
340 fprintf (stderr, "isock= %d\n", x->ch.isock);
341 }
342 else if (x->ch.mode == MODE_PASSIVE) {
343 dup2(sock, x->ch.isock);
344 close (sock);
345 x->ch.state = PORT_CONNECTED;
346 if (debug)
347 fprintf (stderr, "isock= %d\n", x->ch.isock);
348
349 if ((x->ch.osock = openip(x->ch.server.ipnum, x->ch.server.port, x->config->sourceip, 0)) < 0) {
350 syslog(LOG_NOTICE, "-ERR: can't connect to server: %s", strerror(errno));
351 exit (1);
352 }
353
354 if (debug)
355 fprintf (stderr, "osock= %d\n", x->ch.osock);
356 }
357
358
359 /*
360 * Setzen der Datenquelle (Server oder Client).
361 */
362
363 if (x->ch.operation == OP_GET) {
364 x->ch.active = x->ch.osock;
365 x->ch.other = x->ch.isock;
366 }
367 else if (x->ch.operation == OP_PUT) {
368 x->ch.active = x->ch.isock;
369 x->ch.other = x->ch.osock;
370 }
371 else {
372 syslog(LOG_NOTICE, "-ERR: transfer operation error");
373 exit (1);
374 }
375
376 if (x->ch.seen150 == 0) {
377
378 /*
379 * And finally ... another attempt to solve the short
380 * data transmission timing problem: If we didn't receive
381 * the 150 response yet from the server we deactivate the
382 * data channel until we have the 150 -- 030406asg
383 */
384
385 if (debug >= 2)
386 fprintf (stderr, "150 not seen, deactivating data channel\n");
387
388 FD_ZERO(&fdset);
389 FD_SET(fd, &fdset);
390 max = fd;
391 }
392 else {
393 if (debug >= 2)
394 fprintf (stderr, "150 already seen, activating data channel\n");
395
396 FD_ZERO(&fdset);
397 FD_SET(fd, &fdset);
398 FD_SET(x->ch.active, &fdset);
399 max = (fd > x->ch.active)? fd: x->ch.active;
400 }
401
402 if (debug)
403 fprintf (stderr, "active= %d, other= %d\n", x->ch.active, x->ch.other);
404
405 x->ch.bytes = 0;
406 x->ch.started = time(NULL);
407 }
408 else if (x->ch.state == PORT_CONNECTED) {
409 int wrote;
410 char buffer[FTPMAXBSIZE + 10];
411
412 if (x->ch.operation == 0) {
413 if (earlyreported == 0) {
414 earlyreported = 1;
415 syslog(LOG_NOTICE, "early write/read event, sleeping 2 seconds");
416 sleep(2);
417 continue;
418 }
419 }
420
421 bytes = read(x->ch.active, buffer, x->config->bsize /* sizeof(buffer) */ );
422
423 /*
424 * Handling servers that close the data connection -- 24APR02asg
425 */
426
427 wrote = 0;
428 if ((bytes > 0) && ((wrote = write(x->ch.other, buffer, bytes)) == bytes))
429 x->ch.bytes += bytes;
430 else {
431 if (wrote < 0)
432 syslog(LOG_NOTICE, "error writing data channel, error= %s", strerror(errno));
433
434 if (debug)
435 fprintf (stderr, "closing data connection\n");
436
437 close_ch(x, &x->ch);
438 FD_ZERO(&fdset);
439 FD_SET(fd, &fdset);
440 max = fd;
441
442 return (1);
443 }
444 }
445 }
446 }
447
448 bio->len = bytes;
449 bio->here = 0;
450 }
451
452 if (bio->here >= bio->len)
453 return (-1);
454
455 c = (unsigned char) bio->buffer[bio->here++];
456 return (c);
457 }
458
readline_fd(ftp_t * x,int fd,char * line,int size)459 char *readline_fd(ftp_t *x, int fd, char *line, int size)
460 {
461 int c, k;
462
463 *line = 0;
464 size = size - 2;
465
466 c = getc_fd(x, fd);
467 if (c < 0)
468 return (NULL);
469 else if (c == 1) {
470 strcpy(line, "\001");
471 return (line);
472 }
473
474 k = 0;
475 while (c > 0 && c != '\n' && c != 0) {
476 if (k < size)
477 line[k++] = c;
478
479 c = getc_fd(x, fd);
480 }
481
482 line[k] = 0;
483 noctrl(line);
484
485 k = 0;
486 while ((c = (unsigned char ) line[k]) != 0 && c > 126)
487 k++;
488
489 if (k > 0)
490 copy_string(line, &line[k], size);
491
492 return (line);
493 }
494
495
cfgets(ftp_t * x,char * line,int size)496 char *cfgets(ftp_t *x, char *line, int size)
497 {
498 char *p;
499
500 *line = 0;
501 if ((p = readline_fd(x, 0, line, size)) == NULL)
502 return (NULL);
503 else if (debug != 0)
504 fprintf (stderr, "CLI >>>: %s\n", p);
505
506 return (line);
507 }
508
cfputs(ftp_t * x,char * line)509 int cfputs(ftp_t *x, char *line)
510 {
511 char buffer[310];
512
513 if (debug)
514 fprintf (stderr, ">>> CLI: %s\n", line);
515
516 snprintf (buffer, sizeof(buffer) - 2, "%s\r\n", line);
517 write(1, buffer, strlen(buffer));
518
519 return (0);
520 }
521
522
sfgets(ftp_t * x,char * line,int size)523 char *sfgets(ftp_t *x, char *line, int size)
524 {
525 char *p;
526
527 *line = 0;
528 if ((p = readline_fd(x, x->fd.server, line, size)) == NULL)
529 return (NULL);
530 else if (debug != 0)
531 fprintf (stderr, "SVR >>>: %s\n", p);
532
533 return (line);
534 }
535
sfputs(ftp_t * x,char * format,...)536 int sfputs(ftp_t *x, char *format, ...)
537 {
538 int len;
539 char buffer[310];
540 va_list ap;
541
542 va_start(ap, format);
543 vsnprintf (buffer, sizeof(buffer) - 10, format, ap);
544 va_end(ap);
545
546 if (debug)
547 fprintf (stderr, ">>> SVR: %s\n", buffer);
548
549 /*
550 * There are firewalls that don't like command to be split in
551 * two packets. Notice: the `- 10' above is really important
552 * to protect the proxy against buffer overflows.
553 */
554
555 strcat(buffer, "\r\n");
556 len = strlen(buffer);
557
558 /*
559 * SIGPIPE is catched but then ignored, we have to handle it
560 * one our own now -- 24APR02asg
561 */
562
563 if (write(x->fd.server, buffer, len) != len) {
564 syslog(LOG_NOTICE, "-ERR: error writing control connect, error= %s", strerror(errno));
565 exit (1);
566 }
567
568 /*
569 * write(x->fd.server, buffer, strlen(buffer));
570 * write(x->fd.server, "\r\n", 2);
571 */
572 return (0);
573 }
574
sfputc(ftp_t * x,char * command,char * parameter,char * line,int size,char ** here)575 int sfputc(ftp_t *x, char *command, char *parameter, char *line, int size, char **here)
576 {
577 int rc;
578 char *p, buffer[300];
579
580 if (command != NULL && *command != 0) {
581 if (parameter != NULL && *parameter != 0)
582 snprintf (buffer, sizeof(buffer) - 2, "%s %s", command, skip_ws(parameter));
583 else
584 copy_string(buffer, command, sizeof(buffer));
585
586 sfputs(x, "%s", buffer);
587 }
588
589 if (sfgets(x, line, size) == NULL) {
590 if (debug != 0)
591 fprintf (stderr, "server disappered in sfputc(), pos #1\n");
592
593 return (-1);
594 }
595 else if (strlen(line) < 3) {
596 if (debug != 0)
597 fprintf (stderr, "short server reply in sfputc()\n");
598
599 return (-1);
600 }
601
602 rc = atoi(line);
603 if (line[3] != ' ' && line[3] != 0) {
604 while (1) {
605 if (sfgets(x, line, size) == NULL) {
606 syslog(LOG_NOTICE, "-ERR: lost server while reading client greeting: %s", x->server.name);
607 exit (1);
608 }
609
610 if (strlen(line) < 3)
611 /* line too short to be response's last line */ ;
612 else if (line[3] != ' ' && line[3] != 0)
613 /* neither white space nor EOL at position #4 */ ;
614 else if (line[0] >= '0' && line[0] <= '9' && atoi(line) == rc)
615 break; /* status code followed by EOL or blank detected */
616 }
617 }
618
619 if (here != NULL) {
620 p = skip_ws(&line[3]);
621 *here = p;
622 }
623
624 return (rc);
625 }
626
627
628
doquit(ftp_t * x)629 int doquit(ftp_t *x)
630 {
631 int rc;
632 char resp[200];
633
634 if ((rc = sfputc(x, "QUIT", "", resp, sizeof(resp), NULL)) != 221)
635 syslog(LOG_NOTICE, "unexpected resonse to QUIT: %s", resp);
636
637 cfputs(x, "221 goodbye");
638 syslog(LOG_NOTICE, "%d QUIT", rc);
639
640 return (0);
641 }
642
643
_getipnum(char * line,char ** here,char * ip,int size)644 char *_getipnum(char *line, char **here, char *ip, int size)
645 {
646 int c, i, k;
647
648 copy_string(ip, line, size);
649 k = 0;
650 for (i=0; (c = ip[i]) != 0; i++) {
651 if (c == ',') {
652 if (k < 3) {
653 ip[i] = '.';
654 k++;
655 }
656 else {
657 ip[i++] = 0;
658 break;
659 }
660 }
661 }
662
663 if (here != NULL)
664 *here = &line[i];
665
666 return (ip);
667 }
668
_getport(char * line,char ** here)669 unsigned long _getport(char *line, char **here)
670 {
671 unsigned long port;
672 char *p;
673
674 p = line;
675 port = strtoul(p, &p, 10);
676 if (*p != ',')
677 return (0);
678
679 p++;
680 port = (port << 8) + strtoul(p, &p, 10);
681 if (here != NULL)
682 *here = p;
683
684 return (port);
685 }
686
doport(ftp_t * x,char * command,char * par)687 int doport(ftp_t *x, char *command, char *par)
688 {
689 int c, rc;
690 char *p, line[200];
691 dtc_t *ch;
692
693 ch = &x->ch;
694 _getipnum(par, &p, ch->client.ipnum, sizeof(ch->client.ipnum));
695 ch->client.port = _getport(p, &p);
696 if (debug)
697 fprintf (stderr, "client listens on %s:%u\n", ch->client.ipnum, ch->client.port);
698
699 get_interface_info(x->fd.server, ch->outside.ipnum, sizeof(ch->outside.ipnum));
700 ch->osock = bind_to_port(ch->outside.ipnum, 0);
701 ch->outside.port = get_interface_info(ch->osock, line, sizeof(line));
702 if (debug)
703 fprintf (stderr, "listening on %s:%u\n", ch->outside.ipnum, ch->outside.port);
704
705 copy_string(line, ch->outside.ipnum, sizeof(line));
706 for (p=line; (c = *p) != 0; p++) {
707 if (c == '.')
708 *p = ',';
709 }
710
711 *p++ = ',';
712 snprintf (p, 20, "%u,%u", ch->outside.port >> 8, ch->outside.port & 0xFF);
713
714
715 /* Open port first */
716 ch->isock = -1;
717 ch->mode = MODE_PORT;
718 ch->state = PORT_LISTEN;
719
720 /* then send PORT cmd */
721 rc = sfputc(x, "PORT", line, line, sizeof(line), &p);
722
723 /* check return code */
724 if (rc != 200){
725 cfputs(x, "500 not accepted");
726 close_ch(x, &x->ch);
727 }
728 else
729 cfputs(x, "200 ok, port allocated");
730
731
732
733 /* if (rc != 200)
734 cfputs(x, "500 not accepted");
735 else {
736 cfputs(x, "200 ok, port allocated");
737
738 ch->isock = -1;
739 ch->mode = MODE_PORT;
740 ch->state = PORT_LISTEN;
741 }
742 */
743
744 *ch->command = 0;
745 return (rc);
746 }
747
dopasv(ftp_t * x,char * command,char * par)748 int dopasv(ftp_t *x, char *command, char *par)
749 {
750 int c, k, rc;
751 char *p, line[200];
752 dtc_t *ch;
753
754 ch = &x->ch;
755 rc = sfputc(x, "PASV", "", line, sizeof(line), &p);
756 if (rc != 227) {
757 cfputs(x, "500 not accepted");
758 return (0);
759 }
760
761
762 /*
763 * Ende der Port-Koordinaten im Server-Response suchen.
764 */
765
766 k = strlen(line);
767 while (k > 0 && isdigit(line[k-1]) == 0)
768 k--;
769
770 if (isdigit(line[k-1])) {
771 line[k--] = 0;
772 while (k > 0 && (isdigit(line[k-1]) || line[k-1] == ','))
773 k--;
774 }
775
776 /*
777 * line[k] sollte jetzt auf die erste Ziffer des PASV Response
778 * zeigen.
779 */
780
781 if (isdigit(line[k]) == 0) {
782 syslog(LOG_NOTICE, "can't locate passive response: %s", line);
783 cfputs(x, "500 not accepted");
784 return (0);
785 }
786
787 /*
788 * Auslesen der PASV IP-Nummer und des Ports.
789 */
790
791 p = &line[k];
792 _getipnum(p, &p, ch->server.ipnum, sizeof(ch->server.ipnum));
793 ch->server.port = _getport(p, &p);
794 if (debug)
795 fprintf (stderr, "server listens on %s:%u\n", ch->server.ipnum, ch->server.port);
796
797 get_interface_info(0, ch->inside.ipnum, sizeof(ch->inside.ipnum));
798 ch->isock = bind_to_port(ch->inside.ipnum, 0);
799 ch->inside.port = get_interface_info(ch->isock, line, sizeof(line));
800 if (debug)
801 fprintf (stderr, "listening on %s:%u\n", ch->inside.ipnum, ch->inside.port);
802
803 snprintf (line, sizeof(line) - 2, "227 Entering Passive Mode (%s,%u,%u)",
804 ch->inside.ipnum,
805 ch->inside.port >> 8, ch->inside.port & 0xFF);
806 for (p=line; (c = *p) != 0; p++) {
807 if (c == '.')
808 *p = ',';
809 }
810
811 cfputs(x, line);
812 ch->osock = -1;
813 ch->mode = MODE_PASSIVE;
814 ch->state = PORT_LISTEN;
815
816 *ch->command = 0;
817 ch->operation = 0;
818
819 return (rc);
820 }
821
822
dofeat(ftp_t * x)823 int dofeat(ftp_t *x)
824 {
825 /*
826 * Not so easy because we have to align with the server response.
827 */
828
829 int rc;
830 char *p, word[80], serverfeature[80], line[300];
831 static char *proxyfeatlist = "SIZE:MDTM";
832
833 sfputs(x, "%s", "FEAT");
834 if (sfgets(x, line, sizeof(line)) == NULL) {
835 syslog(LOG_NOTICE, "monitor: server not responding");
836 exit (1);
837 }
838
839 rc = atoi(line);
840 if (rc != 211) {
841 /* kein FEAT Support */ ;
842 cfputs(x, "502 command not implemented");
843 return (1);
844 }
845
846
847 cfputs(x, "211-feature list follows");
848 while (1) {
849 if (sfgets(x, line, sizeof(line)) == NULL) {
850 syslog(LOG_NOTICE, "lost server in FEAT response");
851 exit (1);
852 }
853 else if (*line != ' ') {
854
855 /*
856 * RFC2389 specifies exactly one space in this
857 * multi-line response. Nothing else.
858 */
859
860 break;
861 }
862
863
864 /* Get feature from server response ...
865 */
866
867 copy_string(serverfeature, line, sizeof(serverfeature));
868 strupr(serverfeature);
869
870
871 /* ... and compare it against our feature list
872 */
873
874
875 p = proxyfeatlist;
876 while (*get_quoted(&p, ':', word, sizeof(word)) != 0) {
877 if (strcmp(word, serverfeature) == 0) {
878 snprintf (line, sizeof(line) - 4, " %s", word);
879 cfputs(x, line);
880 break;
881 }
882 }
883 }
884
885 cfputs(x, "211 end");
886 return (0);
887 }
888
setvar(ftp_t * x,char * var,char * value)889 int setvar(ftp_t *x, char *var, char *value)
890 {
891 char varname[200];
892
893 #if defined SOLARIS
894 snprintf (varname, sizeof(varname) - 2, "%s%s=%s", x->config->varname, var, value != NULL? value: "");
895 putenv(varname);
896 #else
897 snprintf (varname, sizeof(varname) - 2, "%s%s", x->config->varname, var);
898 setenv(varname, value != NULL? value: "", 1);
899 #endif
900
901 return (0);
902 }
903
set_variables(ftp_t * x)904 int set_variables(ftp_t *x)
905 {
906 char val[200];
907
908 setvar(x, "INTERFACE", x->interface);
909 snprintf (val, sizeof(val) - 2, "%u", x->port);
910 setvar(x, "PORT", val);
911
912 setvar(x, "CLIENT", x->client_ip);
913 setvar(x, "CLIENTNAME", x->client);
914
915 setvar(x, "SERVER", x->server.ipnum);
916 snprintf (val, sizeof(val) - 2, "%u", x->server.port);
917 setvar(x, "SERVERPORT", val);
918
919 setvar(x, "SERVERNAME", x->server.name);
920 setvar(x, "SERVERLOGIN", x->username);
921 setvar(x, "USERNAME", x->local.username);
922 setvar(x, "PASSWD", x->local.password);
923
924 return (0);
925 }
926
run_acp(ftp_t * x)927 int run_acp(ftp_t *x)
928 {
929 int rc, pid, pfd[2];
930 char line[300];
931
932 if (*x->config->acp == 0)
933 return (0);
934
935 rc = 0;
936 if (pipe(pfd) != 0) {
937 syslog(LOG_NOTICE, "-ERR: can't pipe: %s", strerror(errno));
938 exit (1);
939 }
940 else if ((pid = fork()) < 0) {
941 syslog(LOG_NOTICE, "-ERR: can't fork acp: %s", strerror(errno));
942 exit (1);
943 }
944 else if (pid == 0) {
945 int argc;
946 char *argv[32];
947
948 close(0); /* Das acp kann nicht vom client lesen. */
949 dup2(pfd[1], 2); /* stderr wird vom parent gelesen. */
950 close(pfd[0]);
951 set_variables(x);
952
953 copy_string(line, x->config->acp, sizeof(line));
954 argc = split(line, argv, ' ', 30);
955 argv[argc] = NULL;
956 execvp(argv[0], argv);
957
958 syslog(LOG_NOTICE, "-ERR: can't exec acp %s: %s", argv[0], strerror(errno));
959 exit (1);
960 }
961 else {
962 int len;
963 char message[300];
964
965 close(pfd[1]);
966 *message = 0;
967 if ((len = read(pfd[0], message, sizeof(message) - 2)) < 0)
968 len = 0;
969
970 message[len] = 0;
971 noctrl(message);
972 close(pfd[0]);
973
974 if (waitpid(pid, &rc, 0) < 0) {
975 syslog(LOG_NOTICE, "-ERR: error while waiting for acp: %s", strerror(errno));
976 exit (1);
977 }
978
979 rc = WIFEXITED(rc) != 0? WEXITSTATUS(rc): 1;
980 if (*message == 0)
981 copy_string(message, rc == 0? "access granted": "access denied", sizeof(message));
982
983 if (*message != 0)
984 syslog(LOG_NOTICE, "%s (rc= %d)", message, rc);
985 }
986
987 return (rc);
988 }
989
getvarname(char ** here,char * var,int size)990 static char *getvarname(char **here, char *var, int size)
991 {
992 int c, k;
993
994 size = size - 2;
995 k = 0;
996 while ((c = **here) != 0) {
997 *here += 1;
998 if (c == ' ' || c == '\t' || c == '=')
999 break;
1000
1001 if (k < size)
1002 var[k++] = c;
1003 }
1004
1005 var[k] = 0;
1006 strupr(var);
1007 *here = skip_ws(*here);
1008
1009 return (var);
1010 }
1011
run_ctp(ftp_t * x)1012 int run_ctp(ftp_t *x)
1013 {
1014 int rc, pid, pfd[2];
1015 char line[300];
1016 FILE *fp;
1017
1018 if (*x->config->ctp == 0)
1019 return (0);
1020
1021 rc = 0;
1022 if (pipe(pfd) != 0) {
1023 syslog(LOG_NOTICE, "-ERR: can't pipe: %s", strerror(errno));
1024 exit (1);
1025 }
1026 else if ((pid = fork()) < 0) {
1027 syslog(LOG_NOTICE, "-ERR: can't fork trp: %s", strerror(errno));
1028 exit (1);
1029 }
1030 else if (pid == 0) {
1031 int argc;
1032 char *argv[32];
1033
1034 close(0); /* Das trp kann nicht vom client lesen. */
1035 dup2(pfd[1], 1); /* stdout wird vom parent gelesen. */
1036 close(pfd[0]);
1037 set_variables(x);
1038
1039 copy_string(line, x->config->ctp, sizeof(line));
1040 argc = split(line, argv, ' ', 30);
1041 argv[argc] = NULL;
1042 execvp(argv[0], argv);
1043
1044 syslog(LOG_NOTICE, "-ERR: can't exec trp %s: %s",
1045 argv[0], strerror(errno));
1046 exit (1);
1047 }
1048 else {
1049 char *p, var[80], line[300];
1050
1051 close(pfd[1]);
1052 fp = fdopen(pfd[0], "r");
1053 while (fgets(line, sizeof(line), fp)) {
1054 p = skip_ws(noctrl(line));
1055 getvarname(&p, var, sizeof(var));
1056
1057 if (strcmp(var, "SERVERNAME") == 0 || strcmp(var, "SERVER") == 0)
1058 copy_string(x->server.name, p, sizeof(x->server.name));
1059 else if (strcmp(var, "SERVERLOGIN") == 0 || strcmp(var, "LOGIN") == 0)
1060 copy_string(x->username, p, sizeof(x->username));
1061 else if (strcmp(var, "SERVERPASSWD") == 0 || strcmp(var, "PASSWD") == 0)
1062 copy_string(x->password, p, sizeof(x->password));
1063 else if (strcmp(var, "SERVERPORT") == 0 || strcmp(var, "PORT") == 0)
1064 x->server.port = atoi(p);
1065
1066 /*
1067 * Enable the trp to send error messages.
1068 */
1069
1070 else if (strcmp(var, "-ERR") == 0 || strcmp(var, "-ERR:") == 0) {
1071 syslog(LOG_NOTICE, "-ERR: %s", skip_ws(p));
1072 exit (1);
1073 }
1074 }
1075
1076 fclose(fp);
1077
1078 /*
1079 * In standalone mode we do not receive the SIGCHLD because
1080 * we set it to SIG_IGN -- 030406asg
1081 */
1082
1083 if (x->config->standalone == 0 && waitpid(pid, &rc, 0) < 0) {
1084 syslog(LOG_NOTICE, "-ERR: error while waiting for trp: %s", strerror(errno));
1085 exit (1);
1086 }
1087
1088 rc = WIFEXITED(rc) != 0? WEXITSTATUS(rc): 1;
1089 if (rc != 0) {
1090 syslog(LOG_NOTICE, "-ERR: trp signals error condition, rc= %d", rc);
1091 exit (1);
1092 }
1093 }
1094
1095 return (rc);
1096 }
1097
get_ftpdir(ftp_t * x)1098 int get_ftpdir(ftp_t *x)
1099 {
1100 int rc, len;
1101 char *p, *start, line[300];
1102 static char *quotes = "'\"'`";
1103
1104 sfputs(x, "%s", "PWD");
1105 if (sfgets(x, line, sizeof(line)) == NULL) {
1106 syslog(LOG_NOTICE, "monitor: server not responding");
1107 exit (1);
1108 }
1109
1110 rc = strtol(line, &p, 10);
1111 if (rc != 257) {
1112 syslog(LOG_NOTICE, "monitor: PWD status: %d", rc);
1113 exit (1);
1114 }
1115
1116 p = skip_ws(p);
1117 if (*p == 0) {
1118 syslog(LOG_NOTICE, "monitor: directory unset");
1119 exit (1);
1120 }
1121
1122
1123 if ((start = strchr(p, '/')) == NULL) {
1124 syslog(LOG_NOTICE, "monitor: can't find directory in string: %s", p);
1125 exit (1);
1126 }
1127
1128 get_word(&start, x->cwd, sizeof(x->cwd));
1129 if ((len = strlen(x->cwd)) > 0 && strchr(quotes, x->cwd[len-1]) != NULL)
1130 x->cwd[len - 1] = 0;
1131
1132 if (*x->cwd != '/') {
1133 syslog(LOG_NOTICE, "monitor: invalid path: %s", x->cwd);
1134 exit (1);
1135 }
1136
1137 syslog(LOG_NOTICE, "cwd: %s", x->cwd);
1138 return (0);
1139 }
1140
get_ftppath(ftp_t * x,char * path)1141 int get_ftppath(ftp_t *x, char *path)
1142 {
1143 int i, k, n, m;
1144 char cwp[200], ftpdir[200], pbuf[200];
1145 char *part[DIR_MAXDEPTH+5], *dir[DIR_MAXDEPTH+5];
1146
1147 /*
1148 * Zuerst wird das aktuelle Verzeichnis (der ftppath) in seine
1149 * Einzelteile zerlegt ...
1150 */
1151
1152 if (*path == '/') {
1153
1154 /*
1155 * ... Ausnahme: die path-Angabe ist absolut ...
1156 */
1157
1158 dir[0] = "";
1159 n = 1;
1160 }
1161 else {
1162 copy_string(ftpdir, x->cwd, sizeof(ftpdir));
1163 if (*ftpdir != 0 && strcmp(ftpdir, "/") != 0)
1164 n = split(ftpdir, part, '/', DIR_MAXDEPTH);
1165 else {
1166 dir[0] = "";
1167 n = 1;
1168 }
1169 }
1170
1171 /*
1172 * ... danach der path. Die path Teile werden unter Beachtung
1173 * der ueblichen Regeln an die Teile des aktuellen Verzeichnisses
1174 * angehangen ...
1175 */
1176
1177 copy_string(pbuf, path, sizeof(pbuf));
1178 m = split(pbuf, dir, '/', 15);
1179 for (i=0; i<m; i++) {
1180 if (*dir[i] == 0)
1181 /* zwei aufeinander folgende `/' */ ;
1182 else if (strcmp(dir[i], ".") == 0)
1183 /* nichts */ ;
1184 else if (strcmp(dir[i], "..") == 0) {
1185 if (n > 1)
1186 n = n - 1;
1187 }
1188 else
1189 part[n++] = dir[i];
1190
1191 if (n < 1 || n >= DIR_MAXDEPTH)
1192 return (1); /* ungueltiges Verzeichnis */
1193 }
1194
1195 /*
1196 * ... und das Ergebnis wieder zusammengesetzt.
1197 */
1198
1199 if (n <= 1) {
1200 strcpy(cwp, "/");
1201 }
1202 else {
1203 k = 0;
1204 for (i=1; i<n; i++) {
1205 if ((k + strlen(part[i]) + 1 + 2) >= sizeof(dir))
1206 return (1); /* Name zu lang */
1207
1208 cwp[k++] = '/';
1209 strcpy(&cwp[k], part[i]);
1210 k += strlen(&cwp[k]);
1211 }
1212
1213 cwp[k] = 0;
1214 }
1215
1216 /*
1217 * Der normalisierte path auf das Objekt (Datei oder Verzeichnis,
1218 * ist hier egal) ist fertig.
1219 */
1220
1221 copy_string(x->filepath, cwp, sizeof(x->filepath));
1222 return (0);
1223 }
1224
run_ccp(ftp_t * x,char * cmd,char * par)1225 int run_ccp(ftp_t *x, char *cmd, char *par)
1226 {
1227 int rc, pid, pfd[2], lfd[2];
1228 char message[300], line[300];
1229
1230 /*
1231 * Wenn kein ccp angegeben ist ist alles erlaubt.
1232 */
1233
1234 if (*x->config->ccp == 0)
1235 return (CCP_OK);
1236
1237
1238 /*
1239 * Der Vorgang fuer ccp's ist fast gleich mit dem fuer acp's.
1240 */
1241
1242 rc = 0;
1243 if (pipe(pfd) != 0 || pipe(lfd)) {
1244 syslog(LOG_NOTICE, "-ERR: can't pipe: %s", strerror(errno));
1245 exit (1);
1246 }
1247 else if ((pid = fork()) < 0) {
1248 syslog(LOG_NOTICE, "-ERR: can't fork ccp: %s", strerror(errno));
1249 exit (1);
1250 }
1251 else if (pid == 0) {
1252 int argc;
1253 char *argv[32];
1254
1255 dup2(pfd[1], 2); /* stderr nach FTP Client */
1256 close(pfd[0]);
1257
1258 dup2(lfd[1], 1); /* stdout nach syslog */
1259 close(lfd[0]);
1260
1261 close(0);
1262 set_variables(x);
1263
1264 setvar(x, "COMMAND", cmd);
1265 setvar(x, "PARAMETER", par);
1266
1267 setvar(x, "SESSION", x->session);
1268 snprintf (line, sizeof(line) - 2, "%d", x->ccpcoll);
1269 setvar(x, "CCPCOLL", line);
1270
1271 setvar(x, "FTPHOME", x->home);
1272 setvar(x, "FTPPATH", x->filepath);
1273
1274 copy_string(line, x->config->ccp, sizeof(line));
1275 argc = split(line, argv, ' ', 30);
1276 argv[argc] = NULL;
1277 execvp(argv[0], argv);
1278
1279 syslog(LOG_NOTICE, "-ERR: can't exec ccp %s: %s", argv[0], strerror(errno));
1280 exit (1);
1281 }
1282 else {
1283 int len;
1284
1285 /*
1286 * Nicht gebrauchte fd's schliessen.
1287 */
1288
1289 close(pfd[1]);
1290 close(lfd[1]);
1291
1292
1293 /*
1294 * syslog Meldung lesen und entsprechende pipe schliessen.
1295 */
1296
1297 *message = 0;
1298 if ((len = read(lfd[0], message, sizeof(message) - 2)) < 0)
1299 len = 0;
1300
1301 message[len] = 0;
1302 noctrl(message);
1303 close(lfd[0]);
1304
1305 if (*message != 0)
1306 syslog(LOG_NOTICE, "%s", message);
1307
1308
1309
1310 /*
1311 * Fehlermeldung lesen, pipe schliessen.
1312 */
1313
1314 *message = 0;
1315 if ((len = read(pfd[0], message, sizeof(message) - 2)) < 0)
1316 len = 0;
1317
1318 message[len] = 0;
1319 noctrl(message);
1320 close(pfd[0]);
1321
1322
1323 /*
1324 * return code holen.
1325 */
1326
1327 if (waitpid(pid, &rc, 0) < 0) {
1328 syslog(LOG_NOTICE, "-ERR: error while waiting for ccp: %s", strerror(errno));
1329 exit (1);
1330 }
1331
1332 rc = WIFEXITED(rc) != 0? WEXITSTATUS(rc): 1;
1333 if (rc == 0)
1334 return (CCP_OK);
1335
1336 if (*message == 0)
1337 copy_string(message, "permission denied", sizeof(message));
1338
1339 /*
1340 * snprintf (command, sizeof(command) - 2, "%s%s%s", cmd, (par != 0? " ": ""), par);
1341 * syslog(LOG_NOTICE, "ccp: -ERR: %s@%s: %s: %s: rc= %d",
1342 * x->username, x->server.name,
1343 * command, message, rc);
1344 */
1345 }
1346
1347 x->ccpcoll++;
1348 if (isdigit(*message))
1349 cfputs(x, message);
1350 else {
1351 snprintf (line, sizeof(line) - 2, "553 %s", message);
1352 cfputs(x, line);
1353 }
1354
1355 /* cfputs(x, "553 permission denied."); */
1356
1357 return (CCP_ERROR);
1358 }
1359
1360
1361 /*
1362 * dologin() accepts now blanks with in and at the end of
1363 * passwords - 22JAN02asg
1364 */
1365
dologin(ftp_t * x)1366 int dologin(ftp_t *x)
1367 {
1368 int c, i, rc;
1369 char *p, word[80], line[300];
1370 struct hostent *hostp;
1371 struct sockaddr_in saddr;
1372
1373 while (1) {
1374 if (readline_fd(x, 0, line, sizeof(line)) == NULL)
1375 return (1);
1376
1377 if (x->config->allow_passwdblanks == 0)
1378 p = noctrl(line);
1379 else {
1380 p = line;
1381 for (i=strlen(line)-1; i>=0; i--) {
1382 if ((c = line[i]) != '\n' && c != '\r') {
1383 line[i+1] = 0;
1384 break;
1385 }
1386 }
1387 }
1388
1389 get_word(&p, word, sizeof(word));
1390 strupr(word);
1391 if (strcmp(word, "USER") == 0) {
1392 get_word(&p, x->username, sizeof(x->username));
1393 cfputs(x, "331 password required");
1394 }
1395 else if (strcmp(word, "PASS") == 0) {
1396 if (*x->username == 0) {
1397 cfputs(x, "503 give USER first");
1398 continue;
1399 }
1400
1401 if (x->config->allow_passwdblanks == 0)
1402 get_word(&p, x->password, sizeof(x->password));
1403 else
1404 copy_string(x->password, p, sizeof(x->password));
1405
1406 break;
1407 }
1408 else if (strcmp(word, "QUIT") == 0) {
1409 cfputs(x, "221 goodbye");
1410 return (2);
1411 }
1412 else {
1413 cfputs(x, "530 login first");
1414 }
1415 }
1416
1417
1418 if (*x->config->ctp != 0) {
1419
1420 /*
1421 * We are extremly liberate here with server selection
1422 * if we have a dynamic control program, we accept
1423 * anything here -- 030404asg
1424 */
1425
1426 if ((p = strchr(x->username, '@')) == NULL && (p = strchr(x->username, '%')) == NULL)
1427 *x->server.name = 0;
1428 else if (x->config->use_last_at == 0) {
1429 *p++ = 0;
1430 copy_string(x->server.name, p, sizeof(x->server.name));
1431 }
1432 else {
1433 if ((p = strrchr(x->username, '@')) == NULL)
1434 p = strrchr(x->username, '%');
1435
1436 *p++ = 0;
1437 copy_string(x->server.name, p, sizeof(x->server.name));
1438 }
1439 }
1440 else if (x->config->selectserver == 0) {
1441 if ((p = strchr(x->username, '@')) != NULL && (p = strchr(x->username, '%')) != NULL) {
1442 cfputs(x, "500 service unavailable");
1443 syslog(LOG_NOTICE, "-ERR: hostname supplied: %s", p);
1444 exit (1);
1445 }
1446
1447 copy_string(x->server.name, x->config->server, sizeof(x->server.name));
1448 }
1449 else {
1450
1451 /*
1452 * Normally we search for the first '@' so that the client can
1453 * not use "proxy hopping". The option "-u" can override
1454 * this behaviour.
1455 */
1456
1457 if (x->config->use_last_at == 0) {
1458 if ((p = strchr(x->username, '@')) == NULL && (p = strchr(x->username, '%')) == NULL) {
1459 cfputs(x, "500 service unavailable");
1460 syslog(LOG_NOTICE, "-ERR: missing hostname");
1461 exit (1);
1462 }
1463 }
1464 else {
1465 if ((p = strrchr(x->username, '@')) == NULL && (p = strrchr(x->username, '%')) == NULL) {
1466 cfputs(x, "500 service unavailable");
1467 syslog(LOG_NOTICE, "-ERR: missing hostname");
1468 exit (1);
1469 }
1470 }
1471
1472
1473 *p++ = 0;
1474 copy_string(x->server.name, p, sizeof(x->server.name));
1475
1476 /*
1477 * Den Server auf der Serverliste suchen, wenn eine Liste
1478 * vorhanden ist.
1479 */
1480
1481 /*
1482 * Checking the server against the given list is done later now,
1483 * see below. Code quoted -- 030404asg
1484 *
1485 * if ((p = x->config->serverlist) != NULL && *p != 0) {
1486 * int permitted;
1487 * char pattern[80];
1488 *
1489 * permitted = 0;
1490 * while ((p = skip_ws(p)), *get_quoted(&p, ',', pattern, sizeof(pattern)) != 0) {
1491 * noctrl(pattern);
1492 * if (strpcmp(x->server.name, pattern) == 0) {
1493 * permitted = 1;
1494 * break;
1495 * }
1496 * }
1497 *
1498 * if (permitted == 0) {
1499 * cfputs(x, "500 service unavailable");
1500 * syslog(LOG_NOTICE, "-ERR: hostname not permitted: %s", x->server.name);
1501 * exit (1);
1502 * }
1503 * }
1504 */
1505 }
1506
1507
1508
1509 /*
1510 * Wenn vorhanden Proxy Login und Passwort auslesen.
1511 */
1512
1513 if ((p = strchr(x->username, ':')) != NULL) {
1514 *p++ = 0;
1515 copy_string(x->local.username, x->username, sizeof(x->local.username));
1516 copy_string(x->username, p, sizeof(x->username));
1517 }
1518
1519 if ((p = strchr(x->password, ':')) != NULL) {
1520 *p++ = 0;
1521 copy_string(x->local.password, x->password, sizeof(x->local.password));
1522 copy_string(x->password, p, sizeof(x->password));
1523 }
1524
1525 /*
1526 * Call the dynamic configuration program.
1527 */
1528
1529 if (*x->config->ctp != 0) {
1530 x->server.port = get_port(x->server.name, 21);
1531
1532 if (run_ctp(x) != 0)
1533 exit (0); /* Never happens, we exit in run_ctp() */
1534
1535 if (debug != 0) {
1536 fprintf (stderr, "trp debug: server= %s:%u, login= %s, passwd= %s",
1537 x->server.name, x->server.port,
1538 x->username, x->password);
1539 }
1540 }
1541
1542
1543 /*
1544 * Get port an IP number of server. Moved code here -- 030404asg
1545 */
1546
1547 x->server.port = get_port(x->server.name, 21);
1548 if ((hostp = gethostbyname(x->server.name)) == NULL) {
1549 cfputs(x, "500 service unavailable");
1550 syslog(LOG_NOTICE, "-ERR: can't resolve hostname: %s", x->server.name);
1551 exit (1);
1552 }
1553
1554 memcpy(&saddr.sin_addr, hostp->h_addr, hostp->h_length);
1555 copy_string(x->server.ipnum, inet_ntoa(saddr.sin_addr), sizeof(x->server.ipnum));
1556
1557
1558 /*
1559 * Call the access control program to check if the proxy
1560 * request is allowed. Moved code here -- 030404asg
1561 */
1562
1563 if (*x->config->acp != 0) {
1564 if (run_acp(x) != 0)
1565 exit (0);
1566 }
1567
1568
1569 /*
1570 * Verification if the destination server is on the given list
1571 * is done now here.
1572 *
1573 * Notice: Prior to this change you could give a fixed desination
1574 * server as command line argument and a list of allowed server
1575 * too. Meaningless because the proxy didn't care when the `server
1576 * selection' option wasn't turned on. Now also the fixed server
1577 * is checked against the list.
1578 *
1579 * I don't expect that this breaks an already running configuration
1580 * because as said above this configuration was senseless in earlier
1581 * proxy versions -- 030404asg
1582 */
1583
1584 if ((p = x->config->serverlist) != NULL && *p != 0) {
1585 int permitted;
1586 char pattern[80];
1587
1588 permitted = 0;
1589 while ((p = skip_ws(p)), *get_quoted(&p, ',', pattern, sizeof(pattern)) != 0) {
1590 noctrl(pattern);
1591 if (strpcmp(x->server.name, pattern) == 0) {
1592 permitted = 1;
1593 break;
1594 }
1595 }
1596
1597 if (permitted == 0) {
1598 cfputs(x, "500 service unavailable");
1599 syslog(LOG_NOTICE, "-ERR: hostname not permitted: %s", x->server.name);
1600 exit (1);
1601 }
1602 }
1603
1604
1605 /*
1606 * Establish connection to the server
1607 */
1608
1609 if ((x->fd.server = openip(x->server.name, x->server.port, x->config->sourceip, 0)) < 0) {
1610 cfputs(x, "500 service unavailable");
1611 syslog(LOG_NOTICE, "-ERR: can't connect to server: %s", x->server.name);
1612 exit (1);
1613 }
1614
1615 syslog(LOG_NOTICE, "connected to server: %s", x->server.name);
1616
1617
1618 if (sfputc(x, NULL, NULL, line, sizeof(line), NULL) != 220) {
1619 cfputs(x, "500 service unavailable");
1620 syslog(LOG_NOTICE, "-ERR: unexpected server greeting: %s", line);
1621 exit (1);
1622 }
1623
1624 /*
1625 * Login auf FTP-Server.
1626 *
1627 * Complete rewrite because of servers wanting no password after
1628 * login of anonymous user.
1629 */
1630
1631 rc = sfputc(x, "USER", x->username, line, sizeof(line), NULL);
1632
1633 if (rc == 230) {
1634 cfputs(x, "230 login accepted");
1635 syslog(LOG_NOTICE, "login accepted: %s@%s, no password needed.", x->username, x->server.name);
1636 return (0);
1637 }
1638 else if (rc != 331) {
1639 cfputs(x, "500 service unavailable");
1640 syslog(LOG_NOTICE, "-ERR: unexpected reply to USER: %s", line);
1641 exit (1);
1642 }
1643 else if (sfputc(x, "PASS", x->password, line, sizeof(line), NULL) != 230) {
1644 cfputs(x, "530 bad login");
1645 syslog(LOG_NOTICE, "-ERR: reply to PASS: %s", line);
1646 exit (1);
1647 }
1648
1649 cfputs(x, "230 login accepted");
1650 syslog(LOG_NOTICE, "login accepted: %s@%s", x->username, x->server.name);
1651
1652 return (0);
1653
1654 /*
1655 if (sfputc(x, "USER", x->username, line, sizeof(line), NULL) != 331) {
1656 cfputs(x, "500 service unavailable");
1657 syslog(LOG_NOTICE, "-ERR: unexpected reply to USER: %s", line);
1658 exit (1);
1659 }
1660 else if (sfputc(x, "PASS", x->password, line, sizeof(line), NULL) != 230) {
1661 cfputs(x, "530 bad login");
1662 syslog(LOG_NOTICE, "-ERR: reply to PASS: %s", line);
1663 exit (1);
1664 }
1665
1666 cfputs(x, "230 login accepted");
1667 syslog(LOG_NOTICE, "login accepted: %s@%s", x->username, x->server.name);
1668
1669 return (0);
1670 */
1671
1672
1673 }
1674
1675
1676
signal_handler(int sig)1677 void signal_handler(int sig)
1678 {
1679 /*
1680 * Changed the way we handle broken pipes (broken control or
1681 * data connection). We ignore it here but write() returns -1
1682 * and errno is set to EPIPE which is checked.
1683 */
1684
1685 if (sig == SIGPIPE) {
1686 signal(SIGPIPE, signal_handler);
1687 return;
1688 }
1689
1690 syslog(LOG_NOTICE, "-ERR: received signal #%d", sig);
1691 exit (1);
1692 }
1693
set_signals(void)1694 int set_signals(void)
1695 {
1696 signal(SIGHUP, signal_handler);
1697 signal(SIGINT, signal_handler);
1698 signal(SIGQUIT, signal_handler);
1699 signal(SIGSEGV, signal_handler);
1700 signal(SIGPIPE, signal_handler);
1701 signal(SIGALRM, signal_handler);
1702 signal(SIGTERM, signal_handler);
1703 signal(SIGUSR1, signal_handler);
1704 signal(SIGUSR2, signal_handler);
1705
1706 return (0);
1707 }
1708
1709
getcmd(char * name)1710 ftpcmd_t *getcmd(char *name)
1711 {
1712 int i;
1713
1714 for (i=0; cmdtab[i].name[0] != 0; i++) {
1715 if (strcmp(cmdtab[i].name, name) == 0)
1716 return (&cmdtab[i]);
1717 }
1718
1719 return (NULL);
1720 }
1721
1722
proxy_request(config_t * config)1723 int proxy_request(config_t *config)
1724 {
1725 int rc;
1726 char *p, command[200], parameter[200], line[300];
1727 ftpcmd_t *cmd;
1728 ftp_t *x;
1729
1730 set_signals();
1731
1732 /*
1733 * Set socket options to prevent us from the rare case that
1734 * we transfer data to/from the client before the client has
1735 * seen our "150 ..." message.
1736 * Seems so that is doesn't work on all systems.
1737 * So temporary only enable it on linux.
1738 */
1739
1740 #if defined(__linux__)
1741
1742 rc = 1;
1743 if (setsockopt(1, SOL_TCP, TCP_NODELAY, &rc, sizeof(rc)) != 0)
1744 syslog(LOG_NOTICE, "can't set TCP_NODELAY, error= %s", strerror(errno));
1745
1746 #endif
1747
1748 if (config->bsize <= 0)
1749 config->bsize = 1024;
1750 else if (config->bsize > FTPMAXBSIZE)
1751 config->bsize = FTPMAXBSIZE;
1752
1753 x = allocate(sizeof(ftp_t));
1754 x->config = config;
1755 snprintf (x->session, sizeof(x->session) - 2, "%lu-%u", time(NULL), getpid());
1756
1757
1758 /*
1759 * Fix potential problems after immediate initial unseccsesful
1760 * up/downloads. Wasn't a problem since we all do a LIST
1761 * at first.
1762 */
1763
1764 x->ch.isock = -1;
1765 x->ch.osock = -1;
1766
1767
1768 if (get_client_info(x, 0) < 0) {
1769 syslog(LOG_NOTICE, "-ERR: can't get client info: %s", strerror(errno));
1770 exit (1);
1771 }
1772
1773 x->port = get_interface_info(0, x->interface, sizeof(x->interface));
1774 syslog(LOG_NOTICE, "connected to client: %s, interface= %s:%u", x->client,
1775 x->interface, x->port);
1776
1777 if (*x->config->configfile != 0) {
1778 if (readconfig(x->config, x->config->configfile, x->interface) == 0) {
1779 cfputs(x, "421 not available");
1780 syslog(LOG_NOTICE, "-ERR: unconfigured interface: %s", x->interface);
1781 exit (1);
1782 }
1783 }
1784
1785 syslog(LOG_NOTICE, "info: monitor mode: %s, ccp: %s",
1786 x->config->monitor == 0? "off": "on",
1787 *x->config->ccp == 0? "<unset>": x->config->ccp);
1788
1789 cfputs(x, "220 server ready - login please");
1790 if ((rc = dologin(x)) < 0)
1791 return (1);
1792 else if (rc == 2)
1793 return (0);
1794
1795
1796 /*
1797 * Open the xferlog if we have one.
1798 */
1799
1800 if (*x->config->xferlog != 0) {
1801 if (*x->server.name == 0)
1802 copy_string(x->logusername, x->username, sizeof(x->logusername));
1803 else if (x->server.port != 21)
1804 snprintf (x->logusername, sizeof(x->logusername), "%s@%s:%u", x->username, x->server.name, x->server.port);
1805 else
1806 snprintf (x->logusername, sizeof(x->logusername), "%s@%s", x->username, x->server.name);
1807
1808 x->xlfp = fopen(x->config->xferlog, "a");
1809 if (x->xlfp == NULL) {
1810 syslog(LOG_NOTICE, "-WARN: can't open xferlog: %s, error= %s",
1811 x->config->xferlog, strerror(errno));
1812 }
1813 }
1814
1815 if (x->config->monitor) {
1816 get_ftpdir(x);
1817 copy_string(x->home, x->cwd, sizeof(x->home));
1818 }
1819
1820 while ((p = cfgets(x, line, sizeof(line))) != NULL) {
1821 if (*p == '\001') {
1822 if (*x->ch.command != 0) {
1823 syslog(LOG_NOTICE, "%s %s: %ld bytes", x->ch.command, x->ch.filename, x->ch.bytes);
1824
1825 if (x->xlfp != NULL) {
1826 unsigned long now;
1827 char date[80];
1828
1829 /*
1830 * Write xferlog entry but notice that (1) session are never
1831 * flagged as anonymous and (2) the transfer type is always
1832 * binary (type flag was added to data channel but is
1833 * actually not used. 10MAY04wzk
1834 */
1835
1836 now = time(NULL);
1837 copy_string(date, ctime(&now), sizeof(date));
1838 fprintf (x->xlfp, "%s %lu %s %lu %s %c %c %c %c %s %s %d %s %c\n",
1839 date,
1840 now - x->ch.started,
1841 x->client_ip,
1842 x->ch.bytes,
1843 x->ch.filename,
1844 'b', /* x->ch.type == TYPE_ASC? 'a': 'b', */
1845 '-',
1846 strcmp(x->ch.command, "RETR")? 'i': 'o',
1847 'u', /* x->isanonymous == 1? 'a': 'u', */
1848 x->logusername,
1849 "ftp", 1, x->logusername, 'c');
1850 fflush(x->xlfp);
1851 }
1852 }
1853
1854 /*
1855 * Handle multiline server responses after the
1856 * data transfer.
1857 */
1858
1859 sfputc(x, NULL, NULL, line, sizeof(line), NULL);
1860 cfputs(x, line);
1861
1862 continue;
1863 }
1864
1865 p = noctrl(line);
1866 get_word(&p, command, sizeof(command));
1867 strupr(command);
1868
1869 if ((cmd = getcmd(command)) == NULL || cmd->resp == -1) {
1870 cfputs(x, "502 command not implemented");
1871 syslog(LOG_NOTICE, "command not implemented: %s", command);
1872 continue;
1873 }
1874
1875 *x->filepath = 0;
1876 if (cmd->par == 0)
1877 *parameter = 0;
1878 else {
1879 if (strcmp(command, "CDUP") == 0)
1880 strcpy(parameter, "..");
1881 else if (strcmp(command, "SITE") == 0)
1882 copy_string(parameter, p, sizeof(parameter));
1883 else {
1884 if (x->config->allow_blanks != 0)
1885 copy_string(parameter, p, sizeof(parameter));
1886 else
1887 get_word(&p, parameter, sizeof(parameter));
1888
1889 if (*parameter == 0) {
1890 if (strcmp(command, "LIST") == 0 || strcmp(command, "NLST") == 0)
1891 /* nichts, ist ok */ ;
1892 else {
1893 syslog(LOG_NOTICE, "parameter required: %s", command);
1894 exit (1);
1895 }
1896 }
1897 }
1898
1899 if (cmd->ispath != 0) {
1900 if (x->config->monitor) {
1901 if ((strcmp(command, "LIST") == 0 || strcmp(command, "NLST") == 0)
1902 && *parameter == 0) {
1903
1904 /*
1905 * Sonderfall: wir simulieren `*' als Parameter.
1906 */
1907
1908 get_ftppath(x, "*");
1909 }
1910 else
1911 get_ftppath(x, parameter);
1912 }
1913 }
1914 }
1915
1916
1917 if (cmd->useccp != 0) {
1918 if (run_ccp(x, command, parameter) != CCP_OK)
1919 continue;
1920 }
1921
1922
1923 if (strcmp(command, "QUIT") == 0) {
1924 /* run_ccp(x, "QUIT", ""); */
1925 doquit(x);
1926 break;
1927 }
1928 else if (strcmp(command, "PORT") == 0)
1929 doport(x, command, parameter);
1930 else if (strcmp(command, "FEAT") == 0)
1931 dofeat(x);
1932 else if (strcmp(command, "PASV") == 0)
1933 dopasv(x, command, parameter);
1934 else if (strcmp(command, "LIST") == 0 || strcmp(command, "NLST") == 0) {
1935 x->ch.operation = OP_GET; /* fuer PASV mode */
1936 rc = sfputc(x, command, parameter, line, sizeof(line), NULL);
1937 if (rc == 125 || rc == 150) {
1938 x->ch.operation = OP_GET;
1939 x->ch.seen150 = 1;
1940 if (debug >= 2)
1941 fprintf (stderr, "received 150 response\n");
1942 }
1943 else
1944 close_ch(x, &x->ch);
1945
1946 cfputs(x, line);
1947 *x->ch.command = 0;
1948 }
1949 else if (strcmp(command, "RETR") == 0) {
1950 x->ch.operation = OP_GET; /* fuer PASV mode */
1951 rc = sfputc(x, "RETR", parameter, line, sizeof(line), NULL);
1952 if (rc == 125 || rc == 150) {
1953 x->ch.operation = OP_GET;
1954 x->ch.seen150 = 1;
1955 if (debug >= 2)
1956 fprintf (stderr, "received 150 response\n");
1957 }
1958 else
1959 close_ch(x, &x->ch);
1960
1961 cfputs(x, line);
1962 copy_string(x->ch.command, "RETR", sizeof(x->ch.command));
1963 copy_string(x->ch.filename, x->config->monitor != 0? x->filepath: parameter, sizeof(x->ch.filename));
1964
1965 if (extralog != 0)
1966 syslog(LOG_NOTICE, "%d RETR %s", rc, (x->config->monitor != 0)? parameter: x->filepath);
1967 }
1968 else if (strcmp(command, "STOR") == 0 || strcmp(command, "APPE") == 0 || strcmp(command, "STOU") == 0) {
1969 x->ch.operation = OP_PUT; /* fuer PASV mode */
1970 rc = sfputc(x, command, parameter, line, sizeof(line), NULL);
1971 if (rc == 125 || rc == 150) {
1972 x->ch.operation = OP_PUT;
1973 x->ch.seen150 = 1;
1974 if (debug >= 2)
1975 fprintf (stderr, "received 150 response\n");
1976
1977 copy_string(x->ch.command, command, sizeof(x->ch.command));
1978 }
1979 else
1980 close_ch(x, &x->ch);
1981
1982 cfputs(x, line);
1983 copy_string(x->ch.filename, x->config->monitor != 0? x->filepath: parameter, sizeof(x->ch.filename));
1984 if (extralog != 0) {
1985 if (strcmp(command, "STOU") == 0)
1986 syslog(LOG_NOTICE, "%d %s %s", rc, command, "-");
1987 else
1988 syslog(LOG_NOTICE, "%d %s %s", rc, command, x->ch.filename);
1989 }
1990 }
1991 else {
1992 if (strcmp(command, "CDUP") == 0)
1993 *parameter = 0;
1994
1995 rc = sfputc(x, command, parameter, line, sizeof(line), NULL);
1996 cfputs(x, line);
1997 if (extralog != 0 && cmd->log != 0) {
1998 if (x->config->monitor != 0 && cmd->ispath != 0)
1999 syslog(LOG_NOTICE, "%d %s %s", rc, command, x->filepath);
2000 else
2001 syslog(LOG_NOTICE, "%d %s%s%s", rc, command, *parameter != 0? " ": "", parameter);
2002 }
2003
2004 if (strcmp(command, "CWD") == 0 || strcmp(command, "CDUP") == 0) {
2005 if (x->config->monitor)
2006 get_ftpdir(x);
2007 }
2008 }
2009 }
2010
2011 if (*x->config->ccp != 0)
2012 run_ccp(x, "+EXIT", x->session);
2013
2014 syslog(LOG_NOTICE, "+OK: proxy terminating");
2015 return (0);
2016 }
2017
2018
2019
2020