/*****************************************************************************\ * Copyright (c) 2002 Pelle Johansson. * * All rights reserved. * * * * This file is part of the moftpd package. Use and distribution of * * this software is governed by the terms in the file LICENCE, which * * should have come with this package. * \*****************************************************************************/ /* $moftpd: com_misc.c 1251 2005-03-06 22:24:29Z morth $ */ #include "system.h" #include "commands.h" #include "connection.h" #include "utf8fs/memory.h" #include "accounter.h" extern command_t siteCommands[]; /* Miscellaneous commands */ int command_abor(connection_t *conn, const char *arg, int expected) { switch (close_data_connection (conn)) { case -1: return 1; case 0: reply (conn, "226 Abort successful."); return 0; default: reply (conn, "426 Data connection closed."); reply (conn, "226 Abort successful."); return 0; } } int command_site (connection_t *conn, const char *arg, int expected) { const char *narg, *cname; command_t *cmd; narg = strchr (arg, ' '); if (narg) { cname = talloc (narg - arg + 1); if (!cname) { reply (conn, "500 %s", strerror (errno)); return 0; } strncpy ((char*)cname, arg, narg++ - arg); } else { cname = arg; narg = ""; } if (!strlen (cname)) { reply (conn, "500 Need a command name."); return 0; } for (cmd = siteCommands; cmd->name; cmd++) { if (!strcasecmp(cmd->name, cname)) { if (conn->working && !cmd->whileWorking) reply (conn, "500 Please wait until the server is ready."); else if (!conn->authed && !cmd->unauthed) reply(conn, "503 Please login."); else if (cmd->handler (conn, narg, expected)) return 1; break; } } if (!cmd->name) reply(conn, "500 No such command SITE %s.", cname); return 0; } int command_noop(connection_t *conn, const char *arg, int expected) { reply(conn, "200 No action taken."); return 0; } int command_host (connection_t *conn, const char *arg, int expected) { struct sockaddr_storage lAddr, rAddr; server_t *serv; int l; if (conn->inLookUp || conn->authed #ifdef USE_TLS || conn->tlsControl #endif ) { reply (conn, "503 Too late to switch host, please connect again."); return 0; } l = sizeof(lAddr); getsockname(conn->sock, (struct sockaddr*)&lAddr, &l); l = sizeof(rAddr); getpeername(conn->sock, (struct sockaddr*)&rAddr, &l); if (!arg[0]) { reply (conn, "200-You can connect to these hosts (* = current):"); serv = NULL; while ((serv = find_server ((struct sockaddr*)&lAddr, (struct sockaddr*)&rAddr, serv))) { if (serv == conn->server) reply (conn, " %s*", serv->name); else reply (conn, " %s", serv->name); } reply (conn, "200 End of hosts."); return 0; } serv = find_named_server (arg, 0, (struct sockaddr*)&rAddr, NULL); if (serv) { int i, port = -1; if (serv == conn->server) { reply (conn, "220 Already at %s.", serv->name); return 0; } switch(lAddr.ss_family) { case AF_INET: port = ntohs (((struct sockaddr_in*)&lAddr)->sin_port); break; case AF_INET6: port = ntohs (((struct sockaddr_in6*)&lAddr)->sin6_port); break; } for(i = 0; i < serv->numPorts; i++) if(serv->ports[i] == port) break; if (i < serv->numPorts) { char rhost[NI_MAXHOST]; if (getnameinfo ((struct sockaddr*)&rAddr, l, rhost, sizeof (rhost), NULL, 0, NI_NUMERICHOST)) strcpy (rhost, "unknown"); if (accounter (conn->accSock, "CONNECT %s %s\n", rhost, serv->name)) { syslog (LOG_ERR, "%d: Error in acocunter: %m", conn->id); reply (conn, "500 Error: %s.", strerror (errno)); } else { conn->oldserver = conn->server; conn->server = pattach (serv, conn); syslog (LOG_INFO, "%d: Switching to %s.", conn->id, conn->server->name); conn->accWait = acWelcome; } return 0; } } reply (conn, "500 No such host."); return 0; } int sitecommand_admin (connection_t *conn, const char *arg, int expected) { char buf[4097]; int i; buf[0] = i = 0; if (!strcasecmp (arg, "LIST")) { if (conn->user->adminPrivs & admList) { if (accounter (conn->accSock, "LIST\n")) reply (conn, "500 %s.", strerror (errno)); else { reply (conn, "200-Connections (id: pid ip server user account email action):"); conn->accWait = acList; } return 0; } } else if (!strncasecmp (arg, "MSG ", 4)) { if (conn->user->adminPrivs & admMsg) { if (sscanf (arg + 4, "%d %[^\n]", &i, buf) < 2) reply (conn, "501 Not enough arguments."); else if (accounter (conn->accSock, "MSG %d %s\n", i, buf)) reply (conn, "500 %s.", strerror (errno)); else conn->accWait = acMsg; return 0; } } else if (!strncasecmp (arg, "MSGALL ", 7)) { if (conn->user->adminPrivs & admMsg) { if (sscanf (arg + 7, "%[^\n]", buf) < 1) reply (conn, "501 Not enough arguments."); else if (accounter (conn->accSock, "MSGALL %s\n", buf)) reply (conn, "500 %s.", strerror (errno)); else conn->accWait = acMsg; return 0; } } else if (!strncasecmp (arg, "ABORT ", 6)) { if (conn->user->adminPrivs & admAbort) { if (sscanf (arg + 6, "%d %[^\n]", &i, buf) < 1) reply (conn, "501 Not enough arguments."); else if (accounter (conn->accSock, "ABORT %d %s\n", i, buf)) reply (conn, "500 %s.", strerror (errno)); else conn->accWait = acAbort; return 0; } } else if (!strncasecmp (arg, "DISCONNECT ", 11)) { if (conn->user->adminPrivs & admDisconnect) { if (sscanf (arg + 11, "%d %[^\n]", &i, buf) < 1) reply (conn, "501 Not enough arguments."); else if (accounter (conn->accSock, "DISCONNECT %d %s\n", i, buf)) reply (conn, "500 %s.", strerror (errno)); else conn->accWait = acDisconnect; return 0; } } else if (!strncasecmp (arg, "DISCABORT ", 10)) { if ((conn->user->adminPrivs & (admDisconnect | admAbort)) == (admDisconnect | admAbort)) { if (sscanf (arg + 10, "%d %[^\n]", &i, buf) < 1) reply (conn, "501 Not enough arguments."); else if (accounter (conn->accSock, "DISCABORT %d %s\n", i, buf)) reply (conn, "500 %s.", strerror (errno)); else conn->accWait = acDisconnect; return 0; } } else if (!strcasecmp (arg, "RELOAD")) { if (conn->user->adminPrivs & admReload) { if (accounter (conn->accSock, "RELOAD\n")) reply (conn, "500 %s.", strerror (errno)); else reply (conn, "200 Reloading configuration file."); return 0; } } else { reply (conn, "500 Unknown admin command %s.", arg); return 0; } reply (conn, "500 Access denied."); syslog (LOG_NOTICE, "%d: No access to SITE ADMIN %s", conn->id, arg); return 0; }