Roxen.git
/
server
/
protocols
/
ftp.pike
version
»
Context lines:
10
20
40
80
file
none
3
Roxen.git/server/protocols/ftp.pike:2058:
if (!file) { file = ([ "error":404 ]); } send(550, ({ sprintf(LOCALE(94, "'%s': %s: No such file or directory."), cmd, f) })); break; } session->conf->log(file, session); }
+
private void send_welcome()
+
{
+
string s = port_obj->query_option("FTPWelcome");
+
+
s = replace(s,
+
({ "$roxen_version", "$roxen_build", "$full_version",
+
"$pike_version", "$ident",
+
"$site", }),
+
({ roxen->roxen_ver, roxen->roxen_build,
+
roxen->real_version, version(), roxen->version(),
+
conf->query_name(), }));
+
+
send(220, s/"\n", 1);
+
}
+
private mapping open_file(string fname, object session, string cmd) { object|array|mapping file; file = stat_file(fname, session); // The caller is assumed to have made a new session object for us // but not to set not_query in it.. session->not_query = fname;
Roxen.git/server/protocols/ftp.pike:2963:
if (session_limit <= 0) return 1; if (session_limit <= (port_obj->ftp_sessions[user])) { return 0; // Session limit reached. } return 1; }
+
Configuration find_conf()
+
//! Return the conf for the first default server we find.
+
//! If no default server is found, return the first conf found.
+
{
+
Configuration conf;
+
foreach(port_obj->sorted_urls, string url) {
+
mapping(string:mixed) port_info = port_obj->urls[url];
+
if (!port_info) {
+
continue;
+
}
+
if (!conf) {
+
conf = port_info->conf;
+
}
+
if (port_info->conf->query("default_server")) {
+
conf = port_info->conf;
+
return conf;
+
}
+
}
+
return conf;
+
}
+
+
Configuration find_conf_for_host(string hostname)
+
{
+
if (!hostname) {
+
return 0;
+
}
+
hostname = lower_case(hostname);
+
foreach(port_obj->sorted_urls, string url) {
+
mapping(string:mixed) port_info = port_obj->urls[url];
+
if (!port_info) {
+
continue;
+
}
+
if (glob(lower_case(port_info->hostname) + "*", hostname)) {
+
return port_info->conf;
+
}
+
}
+
// Try again different approach.
+
// NB: Don't merge this loop with the one above since we want to try glob()
+
// on all confiured hostnames (globs or not) before trying with
+
// has_prefix().
+
foreach(port_obj->sorted_urls, string url) {
+
mapping(string:mixed) port_info = port_obj->urls[url];
+
if (!port_info) {
+
continue;
+
}
+
if (has_prefix(lower_case(port_info->hostname), hostname)) {
+
return port_info->conf;
+
}
+
}
+
return 0;
+
}
+
/* * FTP commands begin here */ // Set to 1 by EPSV ALL. int epsv_only; void ftp_REIN(string|int args) { logout();
Roxen.git/server/protocols/ftp.pike:2990:
dataport_addr = 0; dataport_port = 0; mode = "A"; cwd = "/"; auth_user = 0; user = password = 0; curr_pipe = 0; restart_point = 0; logged_in = 0; roxen.set_locale();
+
m_delete(master_session->misc, "host");
m_delete(master_session->misc, "accept-language");
-
+
master_session->cached_url_base = 0;
master_session->misc->pref_languages->languages = ({});
-
+
master_session->conf = conf = find_conf();
if (pasv_port) { destruct(pasv_port); pasv_port = 0; } if (args != 1) { // Not called by QUIT or AUTH. low_send(220, ({ LOCALE(106, "Server ready for new user.") })); // RFC 4217 13: // When this command is processed by the server, the TLS // session(s) MUST be cleared and the control and data // connections revert to unprotected, clear communications. to_send->put(2); // End TLS marker. use_ssl = SSL_NONE; busy = 0; next_cmd(); } }
-
+
void ftp_HOST(string args)
+
{
+
if (!expect_argument("HOST", args)) return;
+
+
if (logged_in) {
+
// RFC 7151 3:
+
// Server-FTP processes MUST treat a situation in which the
+
// HOST command is issued after the user has been
+
// authenticated as an erroneous sequence of commands and
+
// return a 503 reply.
+
send(503, ({ LOCALE(204, "HOST not allowed after login.") }));
+
return;
+
}
+
+
if (args[0] == '[') {
+
// IPv6 literal address.
+
if (args[-1] != ']') {
+
send(501, ({ LOCALE(205, "Invalid HOST syntax.") }));
+
return;
+
}
+
} else if (has_value(args, ":")) {
+
send(501, ({ LOCALE(205, "Invalid HOST syntax.") }));
+
return;
+
}
+
+
// FIXME: For IPv4 and IPv6 literal addresses, validate that
+
// the address matches our port.
+
//
+
// RFC 7151 3.1:
+
// That being said, if the IPv4 or IPv6 literal address
+
// specified by the client does not match the literal address
+
// for the server, the server MUST respond with a 504 reply to
+
// indicate that the IPv4 or IPv6 literal address is not valid.
+
+
if (!roxen.is_ip(args)) {
+
args = lower_case(args);
+
+
Configuration new_conf = find_conf_for_host(args);
+
+
if (!new_conf) {
+
send(504, ({ LOCALE(206, "Unknown host.") }));
+
return;
+
}
+
master_session->conf = conf = new_conf;
+
master_session->misc->host = args;
+
master_session->cached_url_base = 0;
+
+
// Support delayed loading.
+
if (!conf->inited) {
+
conf->enable_all_modules();
+
}
+
}
+
+
send_welcome();
+
}
+
void ftp_AUTH(string args) { if (!expect_argument("AUTH", args)) return; args = upper_case(replace(args, ({ " ", "\t" }), ({ "", "" }))); // RFC 4217 17: // To request the TLS protocol in accordance with this document, // the client MUST use 'TLS' //
Roxen.git/server/protocols/ftp.pike:3533:
if ((((int)segments[3]) <= 0) || (((int)segments[3]) > 65535)) { send(501, ({ sprintf(LOCALE(146, "Bad port number: '%s'"), segments[3]) })); return; } dataport_addr = segments[2]; dataport_port = (int)segments[3]; if (pasv_port) { destruct(pasv_port); }
-
send(200, ({ sprintf(LOCALE(147, "EPRT command ok (%
d
port %d)"),
+
send(200, ({ sprintf(LOCALE(147, "EPRT command ok (%
s
port %d)"),
dataport_addr, dataport_port) })); } void ftp_PASV(string args) { // Required by RFC 1123 4.1.2.6 int min; int max; if (epsv_only) {
Roxen.git/server/protocols/ftp.pike:4484:
Inside #if 0
} else if (!conf->extra_statistics->ftp->commands) { conf->extra_statistics->ftp->commands = ([ cmd:1 ]); } else { conf->extra_statistics->ftp->commands[cmd]++; } #endif /* 0 */ if (cmd_help[cmd]) { if (!logged_in) { if (!(< "REIN", "USER", "PASS", "SYST", "AUTH",
-
"ACCT", "QUIT", "ABOR", "HELP", "FEAT" >)[cmd]) {
+
"ACCT", "QUIT", "ABOR", "HELP", "FEAT"
,
"HOST"
>)[cmd]) {
send(530, ({ LOCALE(200, "You need to login first.") })); return; } } if (!port_obj->query_option("rfc2428_support") && (< "EPRT", "EPSV" >)[cmd]) { send(502, ({ sprintf(LOCALE(201, "support for '%s' is disabled."), cmd) })); return; }
Roxen.git/server/protocols/ftp.pike:4605:
port_obj->sessions--; if (master_session) { destruct(master_session); } } void create(object fd, object c) { port_obj = c;
-
// FIXME: Only supports one configuration!
-
conf =
port
_
obj->urls[port_obj->sorted_urls[0]]->
conf;
+
conf =
find
_conf
()
;
// Support delayed loading. if (!conf->inited) { conf->enable_all_modules(); } #if 0 werror("FTP: conf:%O\n" "FTP:urls:%O\n", mkmapping(indices(conf), values(conf)), port_obj->urls);
Roxen.git/server/protocols/ftp.pike:4640:
master_session->misc->pref_languages = PrefLanguages(); ::create(fd, got_command, 0, con_closed, ([])); array a = fd->query_address(1)/" "; local_addr = a[0]; local_port = (int)a[1]; e_mode = has_value(local_addr, ":")?"2":"1"; call_out(timeout, FTP2_TIMEOUT);
-
string s = c->query
_
option
(
"FTPWelcome"
);
-
-
s = replace(s,
-
({ "$roxen_version", "$roxen_build", "$full_version",
-
"$pike_version", "$ident", }),
-
({ roxen->roxen_ver, roxen->roxen_build,
-
roxen->real_version, version(), roxen->version() }));
-
-
send(220, s/"\n", 1);
+
send
_
welcome
();
} }; void create(object f, object c) { if (f) { c->sessions++; c->ftp_users++; if (f->set_keepalive) { // Try to keep stupid firewalls from killing // the connection during long uploads. f->set_keepalive(1); } FTPSession(f, c); } }