/*****************************************************************************\ * 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_port.c 1251 2005-03-06 22:24:29Z morth $ */ #include "system.h" #include "commands.h" #include "connection.h" #include "main.h" #include "events.h" int command_port(connection_t *conn, const char *arg, int expected) { int a1, a2, a3, a4, p1, p2; unsigned int port; struct sockaddr_in *addr4, addr; if(conn->epsvOnly) { reply(conn, "503 You've chosen to disable the PORT command, use EPSV."); return 0; } switch(sscanf(arg, "%d,%d,%d,%d,%d,%d", &a1, &a2, &a3, &a4, &p1, &p2)) { case 6: if(a1 < 0 || a1 > 255 || a2 < 0 || a2 > 255 || a3 < 0 || a3 > 255 || a4 < 0 || a4 > 255 || p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255) { reply(conn, "501 Invalid port specification."); return 0; } addr.sin_addr.s_addr = htonl(a1 << 24 | a2 << 16 | a3 << 8 | a4); port = p1 << 8 | p2; if(!conn->server->allowLowPorts && port < 1024) { syslog (LOG_NOTICE, "%d: PORT with low port: %d", conn->id, port); reply(conn, "501 Port < 1024 not allowed."); return 0; } port = htons(port); addr4 = (struct sockaddr_in*)&conn->rDataAddr; if(!conn->user->allowForeign) { if(addr4->sin_family != AF_INET || addr4->sin_addr.s_addr != addr.sin_addr.s_addr) { syslog (LOG_NOTICE, "%d: PORT with foreign address", conn->id); reply(conn, "501 Foreign address not allowed."); return 0; } } else if (!conn->user->allowOutOfRange && conn->server->numRanges) { addr.sin_family = AF_INET; for (a1 = 0; a1 < conn->server->numRanges; a1++) { if (check_range ((struct sockaddr*)&addr, (struct sockaddr*)&conn->server->ranges[a1].addr, (struct sockaddr*)&conn->server->ranges[a1].mask)) break; } if (a1 == conn->server->numRanges) { syslog (LOG_NOTICE, "%d: PORT out of range", conn->id); reply (conn, "501 Address out of allowed range."); } } addr4->sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN addr4->sin_len = sizeof(struct sockaddr_in); #endif addr4->sin_port = port; addr4->sin_addr.s_addr = addr.sin_addr.s_addr; conn->passive = 0; reply(conn, "200 Port set successfully."); break; default: reply(conn, "501 Invalid port specification."); break; } return 0; } int command_lprt (connection_t *conn, const char *arg, int expected) { int a[16], p[2]; unsigned char ca[16], cp[2]; int i, prt, al, pl; struct sockaddr_in addr4; struct sockaddr_in6 addr6; char buf[1024]; if (conn->epsvOnly) { reply (conn, "503 You've chosen to disable the LPRT command, use EPSV."); return 0; } if (sscanf (arg, "%d,%d,%s", &prt, &al, buf) == 3) { if (prt != 4 && prt != 6) { reply (conn, "521 Supported address families are (4,6)"); return 0; } if ((prt == 4 && al != 4) || (prt == 6 && al != 16)) { reply (conn, "500 Invalid address length."); return 0; } for (i = 0; i < al; i++) { if (sscanf (buf, "%d,%s", a + i, buf) != 2) { reply (conn, "501 Number of fields doesn't match length given."); return 0; } if (a[i] < 0 || a[i] > 255) { reply (conn, "500 Invalid long port specification."); return 0; } ca[i] = a[i]; } if (sscanf (buf, "%d,%s", &pl, buf) == 2) { if (pl != 2) { reply (conn, "500 Invalid port length."); return 0; } if (sscanf (buf, "%d,%d", &p[0], &p[1]) != 2) { reply (conn, "501 Number of fields doesn't match length given."); return 0; } cp[0] = p[0]; cp[1] = p[1]; pl = ntohs (*(unsigned short*)cp); if(!conn->server->allowLowPorts && pl < 1024) { syslog (LOG_NOTICE, "%d: LPRT with low port: %d", conn->id, prt); reply(conn, "501 Port < 1024 not allowed."); return 0; } switch (prt) { case 4: addr4.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN addr4.sin_len = sizeof (struct sockaddr_in); #endif addr4.sin_port = *(unsigned short*)cp; addr4.sin_addr.s_addr = *(unsigned int*)ca; if (!conn->user->allowForeign) { if (!same_addr ((struct sockaddr*)&conn->rDataAddr, (struct sockaddr*)&addr4, 0)) { syslog (LOG_NOTICE, "%d: LPRT with foreign address", conn->id); reply(conn, "501 Foreign address not allowed."); return 0; } } else if (!conn->user->allowOutOfRange && conn->server->numRanges) { for (i = 0; i < conn->server->numRanges; i++) { if (check_range ((struct sockaddr*)&addr4, (struct sockaddr*)&conn->server->ranges[i].addr, (struct sockaddr*)&conn->server->ranges[i].mask)) break; } if (i == conn->server->numRanges) { syslog (LOG_NOTICE, "%d: LPRT out of range", conn->id); reply (conn, "501 Address out of allowed range."); } } memcpy (&conn->rDataAddr, &addr4, sizeof (struct sockaddr_in)); reply (conn, "200 Port set successfully."); return 0; case 6: addr6.sin6_family = AF_INET6; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN addr6.sin6_len = sizeof (struct sockaddr_in6); #endif addr6.sin6_port = *(unsigned short*)cp; memcpy (&addr6.sin6_addr, ca, 16); if (!conn->user->allowForeign) { if (!same_addr ((struct sockaddr*)&conn->rDataAddr, (struct sockaddr*)&addr6, 0)) { syslog (LOG_NOTICE, "%d: LPRT with foreign address", conn->id); reply(conn, "501 Foreign address not allowed."); return 0; } } else if (!conn->user->allowOutOfRange && conn->server->numRanges) { for (i = 0; i < conn->server->numRanges; i++) { if (check_range ((struct sockaddr*)&addr6, (struct sockaddr*)&conn->server->ranges[i].addr, (struct sockaddr*)&conn->server->ranges[i].mask)) break; } if (i == conn->server->numRanges) { syslog (LOG_NOTICE, "%d: LPRT out of range", conn->id); reply (conn, "501 Address out of allowed range."); } } memcpy (&conn->rDataAddr, &addr6, sizeof (struct sockaddr_in6)); reply (conn, "200 Port set successfully."); return 0; } } } reply (conn, "500 Invalid long port specification."); return 0; } int command_eprt(connection_t *conn, const char *arg, int expected) { unsigned char d = *arg++; char *narg; int prt, i; const char *addr, *port; struct addrinfo hints = {0}, *res; if(conn->epsvOnly) { reply(conn, "503 You've chosen to disable the EPRT command, use EPSV."); return 0; } if(d < 33 || d > 126) { if (d) syslog (LOG_NOTICE, "%d: EPRT with invalid delimeter: %d", conn->id, d); reply(conn, "501 Delimeter missing or invalid."); return 0; } narg = strchr(arg, d); if(!narg) { reply(conn, "501 Protocol field missing."); return 0; } *narg++ = 0; prt = atoi(arg); if(prt < 1 || prt > 2) { syslog (LOG_NOTICE, "%d: EPRT with invalid protocol: %d", conn->id, prt); reply(conn, "522 Invalid protocol, use (1,2)"); return 0; } arg = narg; narg = strchr(arg, d); if(!narg) { reply(conn, "501 Address field missing."); return 0; } *narg++ = 0; addr = arg; arg = narg; narg = strchr(arg, d); if(!narg) { reply(conn, "501 Port field missing."); return 0; } *narg++ = 0; port = arg; hints.ai_flags = AI_NUMERICHOST; hints.ai_socktype = SOCK_STREAM; switch(prt) { case 1: hints.ai_family = AF_INET; break; case 2: hints.ai_family = AF_INET6; break; } if(getaddrinfo(addr, port, &hints, &res) || !res) { reply(conn, "501 Invalid address specification."); return 0; } switch(res->ai_family) { case AF_INET: prt = ntohs(((struct sockaddr_in*)res->ai_addr)->sin_port); break; case AF_INET6: prt = ntohs(((struct sockaddr_in6*)res->ai_addr)->sin6_port); break; } if(!conn->user->allowForeign) { if (!same_addr((struct sockaddr*)&conn->rDataAddr, res->ai_addr, 0)) { syslog (LOG_NOTICE, "%d: EPRT with foreign address", conn->id); reply(conn, "501 Foreign address not allowed."); return 0; } } else if (!conn->user->allowOutOfRange && conn->server->numRanges) { for (i = 0; i < conn->server->numRanges; i++) { if (check_range (res->ai_addr, (struct sockaddr*)&conn->server->ranges[i].addr, (struct sockaddr*)&conn->server->ranges[i].mask)) break; } if (i == conn->server->numRanges) { syslog (LOG_NOTICE, "%d: EPRT out of range", conn->id); reply (conn, "501 Address out of allowed range."); } } if(!conn->server->allowLowPorts && prt < 1024) { syslog (LOG_NOTICE, "%d: EPRT with low port: %d", conn->id, prt); reply(conn, "501 Port < 1024 not allowed."); return 0; } memcpy(&conn->rDataAddr, res->ai_addr, res->ai_addrlen); conn->passive = 0; freeaddrinfo(res); reply(conn, "200 Port set successfully."); return 0; } int command_pasv(connection_t *conn, const char *arg, int expected) { int hport; unsigned char *ap; if(conn->epsvOnly) { reply(conn, "503 You've chosen to disable the PASV command, use EPSV."); return 0; } if(conn->lDataAddr.ss_family != AF_INET) { reply(conn, "500 Not an Internet version 4 connection, use EPSV."); return 0; } conn->passive = 0; conn->passiveAccepted = 0; if(conn->dataSock >= 0) { /* * We know there's no transfer in progress, so safe to assume we can * silently close this. */ close(conn->dataSock); remove_read_fd(conn->dataSock); remove_write_fd(conn->dataSock); conn->dataSock = -1; } conn->dataSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(conn->dataSock < 0) { syslog (LOG_ERR, "%d: Failed to create passive socket: %m", conn->id); reply(conn, "425 Failed to create socket: %s.", strerror(errno)); return 0; } for(hport = conn->server->minPasvPort; hport <= conn->server->maxPasvPort; hport++) { ((struct sockaddr_in*)&conn->lDataAddr)->sin_port = htons(hport); if(!bind(conn->dataSock, (struct sockaddr*)&conn->lDataAddr, sizeof(struct sockaddr_in))) break; } if(hport > conn->server->maxPasvPort) { syslog (LOG_ERR, "%d: Failed to bind passive socket: %m", conn->id); reply(conn, "425 Failed to bind socket: %s.", strerror(errno)); close(conn->dataSock); conn->dataSock = -1; return 0; } if(listen(conn->dataSock, 1)) { syslog (LOG_ERR, "%d: Failed to listen on passive socket: %m", conn->id); reply(conn, "425 Failed to listen on socket: %s.", strerror(errno)); close(conn->dataSock); conn->dataSock = -1; return 0; } add_read_fd(conn->dataSock, passive_acceptor, conn); conn->passive = 1; ap = (unsigned char*)&((struct sockaddr_in*)&conn->lDataAddr)->sin_addr; reply(conn, "227 Entering passive mode (%u,%u,%u,%u,%u,%u)", ap[0], ap[1], ap[2], ap[3], hport >> 8 & 0xFF, hport & 0xFF); return 0; } int command_lpsv (connection_t *conn, const char *arg, int expected) { in_port_t *port; int hport, al; unsigned char *ca, *cp; if(conn->epsvOnly) { reply(conn, "503 You've chosen to disable the LPSV command, use EPSV."); return 0; } if (conn->dataSock >= 0) { /* * We know there's no transfer in progress, so safe to assume we can * silently close this. */ close (conn->dataSock); remove_read_fd (conn->dataSock); remove_write_fd (conn->dataSock); conn->dataSock = -1; } conn->passive = 0; conn->passiveAccepted = 0; switch (conn->lDataAddr.ss_family) { case AF_INET: port = &((struct sockaddr_in*)&conn->lDataAddr)->sin_port; al = sizeof (struct sockaddr_in); break; case AF_INET6: port = &((struct sockaddr_in6*)&conn->lDataAddr)->sin6_port; al = sizeof (struct sockaddr_in6); break; default: reply(conn, "500 Unknown address family."); return 0; } conn->dataSock = socket (conn->lDataAddr.ss_family, SOCK_STREAM, IPPROTO_TCP); if (conn->dataSock < 0) { syslog (LOG_ERR, "%d: Failed to create passive socket: %m", conn->id); reply (conn, "425 Failed to create socket: %s.", strerror (errno)); return 0; } for (hport = conn->server->minPasvPort; hport <= conn->server->maxPasvPort; hport++) { *port = htons (hport); if(!bind (conn->dataSock, (struct sockaddr*)&conn->lDataAddr, al)) break; } if (hport > conn->server->maxPasvPort) { syslog (LOG_ERR, "%d: Failed to bind passive socket: %m", conn->id); reply (conn, "425 Failed to bind socket: %s.", strerror (errno)); close (conn->dataSock); conn->dataSock = -1; return 0; } if (listen (conn->dataSock, 1)) { syslog (LOG_ERR, "%d: Failed to listen on passive socket: %m", conn->id); reply (conn, "425 Failed to listen on socket: %s.", strerror(errno)); close (conn->dataSock); conn->dataSock = -1; return 0; } conn->passive = 1; add_read_fd (conn->dataSock, passive_acceptor, conn); cp = (unsigned char*)port; switch (conn->lDataAddr.ss_family) { case AF_INET: ca = (unsigned char*)&((struct sockaddr_in*)&conn->lDataAddr)->sin_addr; reply (conn, "228 Entering Long Passive Mode (4,4,%d,%d,%d,%d,2,%d,%d)", ca[0], ca[1], ca[2], ca[3], cp[0], cp[1]); break; case AF_INET6: ca = (unsigned char*)&((struct sockaddr_in6*)&conn->lDataAddr)->sin6_addr; // Breaking a reply format makes it broken in the locale/messages file. reply (conn, "228 Entering Long Passive Mode (6,16,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,2,%d,%d)", ca[0], ca[1], ca[2], ca[3], ca[4], ca[5], ca[6], ca[7], ca[8], ca[9], ca[10], ca[11], ca[12], ca[13], ca[14], ca[15], cp[0], cp[1]); break; } return 0; } int command_epsv(connection_t *conn, const char *arg, int expected) { in_port_t *port; int hport, al; if(!strcasecmp(arg, "ALL")) { if(conn->epsvOnly) reply(conn, "200 Already in EPSV ALL mode."); else { conn->epsvOnly = 1; reply(conn, "200 EPSV ALL mode entered."); } return 0; } else if (strlen (arg)) { if (!strcmp (arg, "1")) { if (conn->lDataAddr.ss_family != AF_INET) { reply (conn, "522 Must use same protocol as control connection."); return 0; } } else if (!strcmp (arg, "2")) { if (conn->lDataAddr.ss_family != AF_INET6) { reply (conn, "522 Must use same protocol as control connection."); return 0; } } else { reply (conn, "522 Unknown protocol number."); return 0; } } if(conn->dataSock >= 0) { /* * We know there's no transfer in progress, so safe to assume we can * silently close this. */ close(conn->dataSock); remove_read_fd(conn->dataSock); remove_write_fd(conn->dataSock); conn->dataSock = -1; } conn->passive = 0; conn->passiveAccepted = 0; switch(conn->lDataAddr.ss_family) { case AF_INET: port = &((struct sockaddr_in*)&conn->lDataAddr)->sin_port; al = sizeof(struct sockaddr_in); break; case AF_INET6: port = &((struct sockaddr_in6*)&conn->lDataAddr)->sin6_port; al = sizeof(struct sockaddr_in6); break; default: reply(conn, "500 Unknown address family."); return 0; } conn->dataSock = socket(conn->lDataAddr.ss_family, SOCK_STREAM, IPPROTO_TCP); if(conn->dataSock < 0) { syslog (LOG_ERR, "%d: Failed to create passive socket: %m", conn->id); reply(conn, "425 Failed to create socket: %s.", strerror(errno)); return 0; } for(hport = conn->server->minPasvPort; hport <= conn->server->maxPasvPort; hport++) { *port = htons(hport); if(!bind(conn->dataSock, (struct sockaddr*)&conn->lDataAddr, al)) break; } if(hport > conn->server->maxPasvPort) { syslog (LOG_ERR, "%d: Failed to bind passive socket: %m", conn->id); reply(conn, "425 Failed to bind socket: %s.", strerror(errno)); close(conn->dataSock); conn->dataSock = -1; return 0; } if(listen(conn->dataSock, 1)) { syslog (LOG_ERR, "%d: Failed to listen on passive socket: %m", conn->id); reply(conn, "425 Failed to listen on socket: %s.", strerror(errno)); close(conn->dataSock); conn->dataSock = -1; return 0; } conn->passive = 1; add_read_fd(conn->dataSock, passive_acceptor, conn); reply(conn, "229 Entering extended passive mode (|||%d|)", hport); return 0; }