📄 ftp.c
字号:
copy_string(x->username, p, sizeof(x->username)); } if ((p = strchr(x->password, ':')) != NULL) { *p++ = 0; copy_string(x->local.password, x->password, sizeof(x->local.password)); copy_string(x->password, p, sizeof(x->password)); } /* * Call the dynamic configuration program. */ if (*x->config->ctp != 0) { x->server.port = get_port(x->server.name, 21); if (run_ctp(x) != 0) exit (0); /* Never happens, we exit in run_ctp() */ if (debug != 0) { fprintf (stderr, "trp debug: server= %s:%u, login= %s, passwd= %s", x->server.name, x->server.port, x->username, x->password); } } /* * Get port an IP number of server. Moved code here -- 030404asg */ x->server.port = get_port(x->server.name, 21); if ((hostp = gethostbyname(x->server.name)) == NULL) { cfputs(x, "500 service unavailable"); syslog(LOG_NOTICE, "-ERR: can't resolve hostname: %s", x->server.name); exit (1); } memcpy(&saddr.sin_addr, hostp->h_addr, hostp->h_length); copy_string(x->server.ipnum, inet_ntoa(saddr.sin_addr), sizeof(x->server.ipnum)); /* * Call the access control program to check if the proxy * request is allowed. Moved code here -- 030404asg */ if (*x->config->acp != 0) { if (run_acp(x) != 0) exit (0); } /* * Verification if the destination server is on the given list * is done now here. * * Notice: Prior to this change you could give a fixed desination * server as command line argument and a list of allowed server * too. Meaningless because the proxy didn't care when the `server * selection' option wasn't turned on. Now also the fixed server * is checked against the list. * * I don't expect that this breaks an already running configuration * because as said above this configuration was senseless in earlier * proxy versions -- 030404asg */ if ((p = x->config->serverlist) != NULL && *p != 0) { int permitted; char pattern[80]; permitted = 0; while ((p = skip_ws(p)), *get_quoted(&p, ',', pattern, sizeof(pattern)) != 0) { noctrl(pattern); if (strpcmp(x->server.name, pattern) == 0) { permitted = 1; break; } } if (permitted == 0) { cfputs(x, "500 service unavailable"); syslog(LOG_NOTICE, "-ERR: hostname not permitted: %s", x->server.name); exit (1); } } /* * Establish connection to the server */ if ((x->fd.server = openip(x->server.name, x->server.port, x->config->sourceip, 0)) < 0) { cfputs(x, "500 service unavailable"); syslog(LOG_NOTICE, "-ERR: can't connect to server: %s", x->server.name); exit (1); } syslog(LOG_NOTICE, "connected to server: %s", x->server.name); if (sfputc(x, NULL, NULL, line, sizeof(line), NULL) != 220) { cfputs(x, "500 service unavailable"); syslog(LOG_NOTICE, "-ERR: unexpected server greeting: %s", line); exit (1); } /* * Login auf FTP-Server. * * Complete rewrite because of servers wanting no password after * login of anonymous user. */ rc = sfputc(x, "USER", x->username, line, sizeof(line), NULL); if (rc == 230) { cfputs(x, "230 login accepted"); syslog(LOG_NOTICE, "login accepted: %s@%s, no password needed.", x->username, x->server.name); return (0); } else if (rc != 331) { cfputs(x, "500 service unavailable"); syslog(LOG_NOTICE, "-ERR: unexpected reply to USER: %s", line); exit (1); } else if (sfputc(x, "PASS", x->password, line, sizeof(line), NULL) != 230) { cfputs(x, "530 bad login"); syslog(LOG_NOTICE, "-ERR: reply to PASS: %s", line); exit (1); } cfputs(x, "230 login accepted"); syslog(LOG_NOTICE, "login accepted: %s@%s", x->username, x->server.name); return (0);/* if (sfputc(x, "USER", x->username, line, sizeof(line), NULL) != 331) { cfputs(x, "500 service unavailable"); syslog(LOG_NOTICE, "-ERR: unexpected reply to USER: %s", line); exit (1); } else if (sfputc(x, "PASS", x->password, line, sizeof(line), NULL) != 230) { cfputs(x, "530 bad login"); syslog(LOG_NOTICE, "-ERR: reply to PASS: %s", line); exit (1); } cfputs(x, "230 login accepted"); syslog(LOG_NOTICE, "login accepted: %s@%s", x->username, x->server.name); return (0);*/}void signal_handler(int sig){ /* * Changed the way we handle broken pipes (broken control or * data connection). We ignore it here but write() returns -1 * and errno is set to EPIPE which is checked. */ if (sig == SIGPIPE) { signal(SIGPIPE, signal_handler); return; } syslog(LOG_NOTICE, "-ERR: received signal #%d", sig); exit (1);}int set_signals(void){ signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); signal(SIGQUIT, signal_handler); signal(SIGSEGV, signal_handler); signal(SIGPIPE, signal_handler); signal(SIGALRM, signal_handler); signal(SIGTERM, signal_handler); signal(SIGUSR1, signal_handler); signal(SIGUSR2, signal_handler); return (0);}ftpcmd_t *getcmd(char *name){ int i; for (i=0; cmdtab[i].name[0] != 0; i++) { if (strcmp(cmdtab[i].name, name) == 0) return (&cmdtab[i]); } return (NULL);}int proxy_request(config_t *config){ int rc; char *p, command[200], parameter[200], line[300]; ftpcmd_t *cmd; ftp_t *x; set_signals(); /* * Set socket options to prevent us from the rare case that * we transfer data to/from the client before the client has * seen our "150 ..." message. * Seems so that is doesn't work on all systems. * So temporary only enable it on linux. */#if defined(__linux__) rc = 1; if (setsockopt(1, SOL_TCP, TCP_NODELAY, &rc, sizeof(rc)) != 0) syslog(LOG_NOTICE, "can't set TCP_NODELAY, error= %s", strerror(errno));#endif if (config->bsize <= 0) config->bsize = 1024; else if (config->bsize > FTPMAXBSIZE) config->bsize = FTPMAXBSIZE; x = allocate(sizeof(ftp_t)); x->config = config; snprintf (x->session, sizeof(x->session) - 2, "%lu-%u", time(NULL), getpid()); /* * Fix potential problems after immediate initial unseccsesful * up/downloads. Wasn't a problem since we all do a LIST * at first. */ x->ch.isock = -1; x->ch.osock = -1; if (get_client_info(x, 0) < 0) { syslog(LOG_NOTICE, "-ERR: can't get client info: %s", strerror(errno)); exit (1); } x->port = get_interface_info(0, x->interface, sizeof(x->interface)); syslog(LOG_NOTICE, "connected to client: %s, interface= %s:%u", x->client, x->interface, x->port); if (*x->config->configfile != 0) { if (readconfig(x->config, x->config->configfile, x->interface) == 0) { cfputs(x, "421 not available"); syslog(LOG_NOTICE, "-ERR: unconfigured interface: %s", x->interface); exit (1); } } syslog(LOG_NOTICE, "info: monitor mode: %s, ccp: %s", x->config->monitor == 0? "off": "on", *x->config->ccp == 0? "<unset>": x->config->ccp); cfputs(x, "220 server ready - login please"); if ((rc = dologin(x)) < 0) return (1); else if (rc == 2) return (0); /* * Open the xferlog if we have one. */ if (*x->config->xferlog != 0) { if (*x->server.name == 0) copy_string(x->logusername, x->username, sizeof(x->logusername)); else if (x->server.port != 21) snprintf (x->logusername, sizeof(x->logusername), "%s@%s:%u", x->username, x->server.name, x->server.port); else snprintf (x->logusername, sizeof(x->logusername), "%s@%s", x->username, x->server.name); x->xlfp = fopen(x->config->xferlog, "a"); if (x->xlfp == NULL) { syslog(LOG_NOTICE, "-WARN: can't open xferlog: %s, error= %s", x->config->xferlog, strerror(errno)); } } if (x->config->monitor) { get_ftpdir(x); copy_string(x->home, x->cwd, sizeof(x->home)); } while ((p = cfgets(x, line, sizeof(line))) != NULL) { if (*p == '\001') { if (*x->ch.command != 0) { syslog(LOG_NOTICE, "%s %s: %ld bytes", x->ch.command, x->ch.filename, x->ch.bytes); if (x->xlfp != NULL) { unsigned long now; char date[80]; /* * Write xferlog entry but notice that (1) session are never * flagged as anonymous and (2) the transfer type is always * binary (type flag was added to data channel but is * actually not used. 10MAY04wzk */ now = time(NULL); copy_string(date, ctime(&now), sizeof(date)); fprintf (x->xlfp, "%s %lu %s %lu %s %c %c %c %c %s %s %d %s %c\n", date, now - x->ch.started, x->client_ip, x->ch.bytes, x->ch.filename, 'b', /* x->ch.type == TYPE_ASC? 'a': 'b', */ '-', strcmp(x->ch.command, "RETR")? 'i': 'o', 'u', /* x->isanonymous == 1? 'a': 'u', */ x->logusername, "ftp", 1, x->logusername, 'c'); fflush(x->xlfp); } } /* * Handle multiline server responses after the * data transfer. */ sfputc(x, NULL, NULL, line, sizeof(line), NULL); cfputs(x, line); continue; } p = noctrl(line); get_word(&p, command, sizeof(command)); strupr(command); if ((cmd = getcmd(command)) == NULL || cmd->resp == -1) { cfputs(x, "502 command not implemented"); syslog(LOG_NOTICE, "command not implemented: %s", command); continue; } *x->filepath = 0; if (cmd->par == 0) *parameter = 0; else { if (strcmp(command, "CDUP") == 0) strcpy(parameter, ".."); else if (strcmp(command, "SITE") == 0) copy_string(parameter, p, sizeof(parameter)); else { if (x->config->allow_blanks != 0) copy_string(parameter, p, sizeof(parameter)); else get_word(&p, parameter, sizeof(parameter)); if (*parameter == 0) { if (strcmp(command, "LIST") == 0 || strcmp(command, "NLST") == 0) /* nichts, ist ok */ ; else { syslog(LOG_NOTICE, "parameter required: %s", command); exit (1); } } } if (cmd->ispath != 0) { if (x->config->monitor) { if ((strcmp(command, "LIST") == 0 || strcmp(command, "NLST") == 0) && *parameter == 0) { /* * Sonderfall: wir simulieren `*' als Parameter. */ get_ftppath(x, "*"); } else get_ftppath(x, parameter); } } } if (cmd->useccp != 0) { if (run_ccp(x, command, parameter) != CCP_OK) continue; } if (strcmp(command, "QUIT") == 0) {/* run_ccp(x, "QUIT", ""); */ doquit(x); break; } else if (strcmp(command, "PORT") == 0) doport(x, command, parameter); else if (strcmp(command, "FEAT") == 0) dofeat(x); else if (strcmp(command, "PASV") == 0) dopasv(x, command, parameter); else if (strcmp(command, "LIST") == 0 || strcmp(command, "NLST") == 0) { x->ch.operation = OP_GET; /* fuer PASV mode */ rc = sfputc(x, command, parameter, line, sizeof(line), NULL); if (rc == 125 || rc == 150) { x->ch.operation = OP_GET; x->ch.seen150 = 1; if (debug >= 2) fprintf (stderr, "received 150 response\n"); } else close_ch(x, &x->ch); cfputs(x, line); *x->ch.command = 0; } else if (strcmp(command, "RETR") == 0) { x->ch.operation = OP_GET; /* fuer PASV mode */ rc = sfputc(x, "RETR", parameter, line, sizeof(line), NULL); if (rc == 125 || rc == 150) { x->ch.operation = OP_GET; x->ch.seen150 = 1; if (debug >= 2) fprintf (stderr, "received 150 response\n"); } else close_ch(x, &x->ch); cfputs(x, line); copy_string(x->ch.command, "RETR", sizeof(x->ch.command)); copy_string(x->ch.filename, x->config->monitor != 0? x->filepath: parameter, sizeof(x->ch.filename)); if (extralog != 0) syslog(LOG_NOTICE, "%d RETR %s", rc, (x->config->monitor != 0)? parameter: x->filepath); } else if (strcmp(command, "STOR") == 0 || strcmp(command, "APPE") == 0 || strcmp(command, "STOU") == 0) { x->ch.operation = OP_PUT; /* fuer PASV mode */ rc = sfputc(x, command, parameter, line, sizeof(line), NULL); if (rc == 125 || rc == 150) { x->ch.operation = OP_PUT; x->ch.seen150 = 1; if (debug >= 2) fprintf (stderr, "received 150 response\n"); copy_string(x->ch.command, command, sizeof(x->ch.command)); } else close_ch(x, &x->ch); cfputs(x, line); copy_string(x->ch.filename, x->config->monitor != 0? x->filepath: parameter, sizeof(x->ch.filename)); if (extralog != 0) { if (strcmp(command, "STOU") == 0) syslog(LOG_NOTICE, "%d %s %s", rc, command, "-"); else syslog(LOG_NOTICE, "%d %s %s", rc, command, x->ch.filename); } } else { if (strcmp(command, "CDUP") == 0) *parameter = 0; rc = sfputc(x, command, parameter, line, sizeof(line), NULL); cfputs(x, line); if (extralog != 0 && cmd->log != 0) { if (x->config->monitor != 0 && cmd->ispath != 0) syslog(LOG_NOTICE, "%d %s %s", rc, command, x->filepath); else syslog(LOG_NOTICE, "%d %s%s%s", rc, command, *parameter != 0? " ": "", parameter); } if (strcmp(command, "CWD") == 0 || strcmp(command, "CDUP") == 0) { if (x->config->monitor) get_ftpdir(x); } } } if (*x->config->ccp != 0) run_ccp(x, "+EXIT", x->session); syslog(LOG_NOTICE, "+OK: proxy terminating"); return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -