/* * An authority demon for the outside FTP server. * Based on old code from TMI2. * Written by Turrican, September 1999. */ #include <network.h> #define MAX_LIFE 36000 inherit SERVER; class ftp_session { int fd; string token; int timestamp; string user; } protected void create() { server::create(); SetSocketType(STREAM); SetDestructOnClose(1); Sockets = ([]); call_out("setup", 2); call_out("clean_sockets", 3600); } /* create() */ /** @ignore yes */ protected void setup() { if (eventCreateSocket(PORT_FTPAUTH) < 0) { if (this_object()) { destruct(this_object()); } } } /* setup() */ /** @ignore yes */ protected void eventNewConnection(int fd) { class ftp_session sess; string address, host; server::eventNewConnection(fd); address = socket_address(fd); /* If this is not coming from localhost, disconnect. */ if ((sscanf(address, "%s %*d", host) != 2) || (host != "127.0.0.1")) { eventWrite(fd, "", 1); return; } sess = new(class ftp_session, fd : fd); Sockets[fd] = sess; } /* eventNewConnection() */ /** @ignore yes */ protected string get_path(string str) { string *array, *array1; int i; if (str == "/") return "/"; array = explode(str, "/") - ({ "" }); array1 = ({ }); for (i = 0; i < sizeof(array); i++) { if (array[i] == "..") { if (sizeof(array1)) { array1 = array1[0..<2]; } } else if (array[i] != ".") { array1 += ({ array[i] }); } } if (sizeof(array1)) str = implode(array1, "/"); else str = ""; return "/" + str; } /* get_path() */ /** @ignore yes */ protected void eventRead(int fd, string str) { class ftp_session sess = Sockets[fd]; string name, rest, ret, token, type, path; int timestamp; if (!sess) { eventWrite(fd, "DENIED\n", 1); return; } if (str == "mudname") { eventWrite(fd, sprintf("OKAY: %s\n", mud_name())); return; } if (sscanf(str, "%s %s", name, rest) != 2) { eventWrite(fd, "Syntax error\n", 1); return; } name = lower_case(name); if (rest == "request login") { int anon = 0; if (name == "ftp") { anon = 1; } if (!(anon || creatorp(name))) { eventWrite(fd, "DENIED\n"); return; } timestamp = time(); token = crypt("" + timestamp, "" + random(12000)); sess->token = token; sess->timestamp = timestamp; sess->user = name; if (anon) { ret = sprintf("OKAY: %s * /pub\n", token); } else { ret = sprintf("OKAY: %s %s /w/%s\n", token, PLAYER_H->get_password(name), name); } eventWrite(fd, ret); return; } if (sscanf(rest, "%s %s %s", token, type, path) != 3) { eventWrite(fd, "Syntax error\n", 1); return; } if ((token != sess->token) || ((time() - sess->timestamp) > MAX_LIFE)) { eventWrite(fd, "DENIED\n"); return; } path = get_path(path); switch (type) { case "read": if (file_size(path) == -2) { path += "/*"; } ret = (master()->valid_read(path, name, "read_file") ? "OKAY\n" : "DENIED\n"); eventWrite(fd, ret); break; case "write": if (file_size(path) == -2) { path += "/*"; } ret = (master()->valid_write(path, name, "write_file") ? "OKAY\n" : "DENIED\n"); eventWrite(fd, ret); break; default: eventWrite(fd, "DENIED\n"); break; } } /* eventRead() */ /** @ignore yes */ protected void eventSocketClosed(int fd) { class ftp_session sess = Sockets[fd]; if (!sess) { return; } map_delete(Sockets, fd); } /* eventSocketClosed() */ /** @ignore yes */ protected void clean_sockets() { class ftp_session sess; foreach (sess in values(Sockets)) { if (!sess->timestamp) { sess->timestamp = time(); continue; } if (time() - sess->timestamp > MAX_LIFE) { eventWrite(sess->fd, "Timeout\n", 1); } } call_out("clean_sockets", 3600); } /* clean_sockets() */ /** @ignore yes */ string *query_connections() { class ftp_session val; string *list; list = ({ }); foreach (val in values(Sockets)) { if (val->user) { list += ({ capitalize(val->user) }); } else { list += ({ "login" }); } } return list; } /* query_connections() */