mirror of
https://github.com/glest/glest-source.git
synced 2025-08-16 05:13:59 +02:00
- got my plumbers suit on and added the plumbing for FTP file xfers
This commit is contained in:
177
source/shared_lib/sources/feathery_ftp/ftpAccount.c
Normal file
177
source/shared_lib/sources/feathery_ftp/ftpAccount.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* Feathery FTP-Server <https://sourceforge.net/projects/feathery>
|
||||
* Copyright (C) 2005-2010 Andreas Martin (andreas.martin@linuxmail.org)
|
||||
*
|
||||
* ftpAccount.c - User account handling
|
||||
*
|
||||
* User account management is based on username, password and
|
||||
* access-rights. An account can be created with the function
|
||||
* ftpCreateAccount.
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ftpTypes.h"
|
||||
#include "ftpConfig.h"
|
||||
#include "ftp.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief User account data
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char name[MAXLEN_USERNAME]; ///< user name
|
||||
char passw[MAXLEN_PASSWORD]; ///< password of the account
|
||||
char ftpRoot[MAX_PATH_LEN]; ///< root path of the user account on the server
|
||||
int ftpRootLen; ///< length of ftpRoot
|
||||
int accRights; ///< access rights of a account
|
||||
|
||||
}ftpUserAccount_S;
|
||||
|
||||
/**
|
||||
* @brief Array which holds all registered user accounts
|
||||
*/
|
||||
LOCAL ftpUserAccount_S ftpUsers[MAX_USERS];
|
||||
|
||||
/**
|
||||
* @brief Creates a new user account
|
||||
*
|
||||
* The translated path depends on the current working directory of the
|
||||
* session and the root path of the session. In addition the path will
|
||||
* be normalized.
|
||||
* @todo normalize root and check if normalized path really exists
|
||||
*
|
||||
* @param name user name
|
||||
* @param passw account password
|
||||
* @param root root directory of the account
|
||||
* @param acc access rights, can be any combination of the following flags:
|
||||
* - FTP_ACC_RD read access
|
||||
* - FTP_ACC_WR write access
|
||||
* - FTP_ACC_LS access to directory listing
|
||||
* - FTP_ACC_DIR changing of working dir allowed
|
||||
*
|
||||
* @return 0 on success; -1 if MAX_USERS is reached
|
||||
*/
|
||||
int ftpCreateAccount(const char* name, const char* passw, const char* root, int acc)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = ftpFindAccount(name); // check if account already exists
|
||||
if(n > 0)
|
||||
{
|
||||
ftpUsers[n - 1].name[0] = '\0'; // delete account
|
||||
}
|
||||
|
||||
for(n = 0; n < MAX_USERS; n++)
|
||||
{
|
||||
if(ftpUsers[n].name[0] == '\0')
|
||||
{
|
||||
strncpy(ftpUsers[n].name, name, MAXLEN_USERNAME);
|
||||
strncpy(ftpUsers[n].passw, passw, MAXLEN_PASSWORD);
|
||||
strncpy(ftpUsers[n].ftpRoot, root, MAX_PATH_LEN);
|
||||
ftpUsers[n].ftpRootLen = strlen(root);
|
||||
ftpUsers[n].accRights = acc;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the account id for a user name
|
||||
*
|
||||
* The function searches ftpUsers for the passed user name.
|
||||
* The returned account id is the index + 1 in ftpUsers.
|
||||
*
|
||||
* @param name user name
|
||||
*
|
||||
* @return 0 if user is not found; 1 to MAX_USERS+1 if user is found
|
||||
*/
|
||||
int ftpFindAccount(const char* name)
|
||||
{
|
||||
int n;
|
||||
|
||||
if(name[0] != '\0')
|
||||
for(n = 0; n < MAX_USERS; n++)
|
||||
if(!strncmp(ftpUsers[n].name, name, MAXLEN_USERNAME))
|
||||
return n + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the password of a user account
|
||||
*
|
||||
* Compares the passed password to the saved password in ftpUsers
|
||||
*
|
||||
* @param userId user account id
|
||||
* @param passw password
|
||||
*
|
||||
* @return - 0: password is correct
|
||||
* - -1: invalid user account id
|
||||
* - else: incorrect password
|
||||
*/
|
||||
int ftpCheckPassword(int userId, const char* passw)
|
||||
{
|
||||
if(!userId)
|
||||
return -1;
|
||||
else if(ftpUsers[userId - 1].passw[0] == '\0')
|
||||
return 0;
|
||||
else
|
||||
return strncmp(ftpUsers[userId - 1].passw, passw, MAXLEN_PASSWORD);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the account has the needed rights
|
||||
*
|
||||
* Compares the passed access rights to the saved rights in ftpUsers
|
||||
*
|
||||
* @param userId user account id
|
||||
* @param accRights needed access rights
|
||||
*
|
||||
* @return - 0: the needed access rights are fulfilled
|
||||
* - -1: invalid user account id
|
||||
*/
|
||||
int ftpCheckAccRights(int userId, int accRights)
|
||||
{
|
||||
if(!userId)
|
||||
return -1;
|
||||
|
||||
if((ftpUsers[userId - 1].accRights & accRights) == accRights)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the root directory of a account
|
||||
*
|
||||
* @param userId user account id
|
||||
* @param len length of the returned path
|
||||
*
|
||||
* @return root directory name or NULL if the user account id is invalid
|
||||
*/
|
||||
const char* ftpGetRoot(int userId, int* len)
|
||||
{
|
||||
if(!userId)
|
||||
return NULL;
|
||||
if(len)
|
||||
*len = ftpUsers[userId - 1].ftpRootLen;
|
||||
|
||||
return ftpUsers[userId - 1].ftpRoot;
|
||||
}
|
939
source/shared_lib/sources/feathery_ftp/ftpCmds.c
Executable file
939
source/shared_lib/sources/feathery_ftp/ftpCmds.c
Executable file
@@ -0,0 +1,939 @@
|
||||
/* FEATHERY FTP-Server
|
||||
* Copyright (C) 2005-2010 Andreas Martin (andreas.martin@linuxmail.org)
|
||||
* <https://sourceforge.net/projects/feathery>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
DECLARATIVE SPECIFICATIONS
|
||||
|
||||
5.1. MINIMUM IMPLEMENTATION
|
||||
|
||||
In order to make FTP workable without needless error messages, the
|
||||
following minimum implementation is required for all servers:
|
||||
|
||||
TYPE - ASCII Non-print
|
||||
MODE - Stream
|
||||
STRUCTURE - File, Record
|
||||
COMMANDS - USER, QUIT, PORT,
|
||||
TYPE, MODE, STRU,
|
||||
for the default values
|
||||
RETR, STOR,
|
||||
NOOP.
|
||||
|
||||
The default values for transfer parameters are:
|
||||
|
||||
TYPE - ASCII Non-print
|
||||
MODE - Stream
|
||||
STRU - File
|
||||
|
||||
All hosts must accept the above as the standard defaults.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "ftpTypes.h"
|
||||
#include "ftpConfig.h"
|
||||
#include "ftp.h"
|
||||
#include "ftpIfc.h"
|
||||
#include "ftpMessages.h"
|
||||
|
||||
|
||||
LOCAL uint8_t scratchBuf[LEN_SCRATCHBUF];
|
||||
|
||||
int ftpSendMsg(msgmode_E mode, int sessionId, int ret, const char* msg)
|
||||
{
|
||||
int sentlen = 0;
|
||||
int len = strlen(msg);
|
||||
char buf[6];
|
||||
|
||||
if(mode == MSG_QUOTE)
|
||||
{
|
||||
sprintf((char*)buf, "%03d \"", ret);
|
||||
sentlen += ftpSend(ftpGetSession(sessionId)->ctrlSocket, buf, 5);
|
||||
sentlen += ftpSend(ftpGetSession(sessionId)->ctrlSocket, msg, len);
|
||||
sentlen += ftpSend(ftpGetSession(sessionId)->ctrlSocket, "\"\r\n", 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf((char*)buf, "%03d ", ret);
|
||||
sentlen += ftpSend(ftpGetSession(sessionId)->ctrlSocket, buf, 4);
|
||||
sentlen += ftpSend(ftpGetSession(sessionId)->ctrlSocket, msg, len);
|
||||
sentlen += ftpSend(ftpGetSession(sessionId)->ctrlSocket, "\r\n", 2);
|
||||
}
|
||||
|
||||
#if DBG_LOG
|
||||
printf("%02d <-- %s%s\n", sessionId, buf, msg);
|
||||
#endif
|
||||
|
||||
return sentlen;
|
||||
}
|
||||
|
||||
int ftpExecTransmission(int sessionId)
|
||||
{
|
||||
int finished = FALSE;
|
||||
int len;
|
||||
ftpSession_S *pSession = ftpGetSession(sessionId);
|
||||
transmission_S *pTrans = &pSession->activeTrans;
|
||||
int rxLen;
|
||||
|
||||
|
||||
pSession->timeLastCmd = ftpGetUnixTime();
|
||||
switch(pTrans->op)
|
||||
{
|
||||
case OP_RETR:
|
||||
len = ftpReadFile(scratchBuf, 1, LEN_SCRATCHBUF, pTrans->fsHandle);
|
||||
if(len > 0)
|
||||
{
|
||||
pTrans->fileSize -= len;
|
||||
if(ftpSend(pTrans->dataSocket, scratchBuf, len))
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 426, ftpMsg000);
|
||||
finished = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 451, ftpMsg001);
|
||||
finished = TRUE;
|
||||
}
|
||||
|
||||
if(pTrans->fileSize == 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 226, ftpMsg002);
|
||||
finished = TRUE;
|
||||
}
|
||||
break;
|
||||
case OP_STOR:
|
||||
rxLen = 0;
|
||||
do
|
||||
{
|
||||
len = ftpReceive(pTrans->dataSocket, &scratchBuf[rxLen], LEN_SCRATCHBUF - rxLen);
|
||||
|
||||
if(len <= 0)
|
||||
break;
|
||||
|
||||
rxLen += len;
|
||||
}while(rxLen < LEN_SCRATCHBUF);
|
||||
|
||||
if(rxLen > 0)
|
||||
{
|
||||
if(ftpWriteFile(scratchBuf, 1, rxLen, pTrans->fsHandle) != rxLen)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 451, ftpMsg001);
|
||||
finished = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if(len <= 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 226, ftpMsg003);
|
||||
finished = TRUE;
|
||||
}
|
||||
|
||||
break;
|
||||
case OP_LIST:
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(finished)
|
||||
{
|
||||
ftpCloseTransmission(sessionId);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdUser(int sessionId, const char* args, int len)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 331, ftpMsg004);
|
||||
ftpGetSession(sessionId)->userId = ftpFindAccount(args);
|
||||
return 0;
|
||||
}
|
||||
LOCAL int ftpCmdPass(int sessionId, const char* args, int len)
|
||||
{
|
||||
if(!ftpCheckPassword(ftpGetSession(sessionId)->userId, args))
|
||||
{
|
||||
ftpAuthSession(sessionId);
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 230, ftpMsg005);
|
||||
}
|
||||
else
|
||||
{
|
||||
ftpGetSession(sessionId)->userId = 0;
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 530, ftpMsg006);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
LOCAL int ftpCmdSyst(int sessionId, const char* args, int len)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 215, "UNIX Type: L8");
|
||||
|
||||
return 0;
|
||||
}
|
||||
LOCAL int ftpCmdPort(int sessionId, const char* args, int len)
|
||||
{
|
||||
char clientIp[16];
|
||||
uint16_t clientPort;
|
||||
|
||||
int commaCnt = 0;
|
||||
int n;
|
||||
char* p;
|
||||
|
||||
for(n = 0; args[n] != '\0'; n++)
|
||||
{
|
||||
if(commaCnt <= 3) // Ip-Adresse
|
||||
{
|
||||
if(args[n] == ',')
|
||||
{
|
||||
commaCnt++;
|
||||
if(commaCnt < 4)
|
||||
clientIp[n] = '.';
|
||||
else
|
||||
clientIp[n] = '\0';
|
||||
}
|
||||
else
|
||||
clientIp[n] = args[n];
|
||||
}
|
||||
else // Port-Nummer
|
||||
{
|
||||
p = (char*)&args[n];
|
||||
clientPort = (uint16_t)(strtoul(p, &p, 0) << 8);
|
||||
p++;
|
||||
clientPort |= strtoul(p, &p, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO Derzeit wird die übergebene IP nicht beachtet, sondern nur die IP des Control-Sockets verwendet
|
||||
clientIp[0] = clientIp[0];
|
||||
if(ftpGetSession(sessionId)->passiveDataSocket >= 0)
|
||||
{
|
||||
ftpCloseSocket(ftpGetSession(sessionId)->passiveDataSocket);
|
||||
ftpGetSession(sessionId)->passiveDataSocket = -1;
|
||||
}
|
||||
ftpGetSession(sessionId)->remoteDataPort = clientPort;
|
||||
ftpGetSession(sessionId)->passive = FALSE;
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 200, ftpMsg007);
|
||||
|
||||
return 0;
|
||||
}
|
||||
LOCAL int ftpCmdNoop(int sessionId, const char* args, int len)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 200, ftpMsg008);
|
||||
|
||||
return 0;
|
||||
}
|
||||
LOCAL int ftpCmdQuit(int sessionId, const char* args, int len)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 221, ftpMsg009);
|
||||
return -1;
|
||||
|
||||
}
|
||||
LOCAL int ftpCmdAbor(int sessionId, const char* args, int len)
|
||||
{
|
||||
ftpCloseTransmission(sessionId);
|
||||
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 226, ftpMsg040);
|
||||
return 0;
|
||||
|
||||
}
|
||||
#define ALL 0x80
|
||||
#define LIST 1
|
||||
#define NLST 2
|
||||
#define MLST 4
|
||||
#define MLSD 8
|
||||
LOCAL int sendListing(socket_t dataSocket, int sessionId, const char* path, int format)
|
||||
{
|
||||
void *dir;
|
||||
const char monName[12][4] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
dir = ftpOpenDir(path);
|
||||
if(dir)
|
||||
{
|
||||
const char* dirEntry;
|
||||
int len;
|
||||
int err = 0;
|
||||
ftpTime_S currTime = {0};
|
||||
ftpPathInfo_S fileInfo;
|
||||
|
||||
ftpGetLocalTime(&currTime);
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 150, ftpMsg010);
|
||||
|
||||
#if DBG_LOG
|
||||
printf("about to read dir contents [%s]\n", path);
|
||||
#endif
|
||||
|
||||
int haveAnySuccessfulFiles = 0;
|
||||
while((dirEntry = ftpReadDir(dir)) != NULL)
|
||||
{
|
||||
char * realPath = ftpGetRealPath(sessionId, dirEntry, FALSE);
|
||||
int statResult = ftpStat(realPath, &fileInfo);
|
||||
#if DBG_LOG
|
||||
printf("ftpGetRealPath() returned [%s] stat() = %d\n", realPath, statResult);
|
||||
#endif
|
||||
|
||||
if(statResult == 0)
|
||||
{
|
||||
if((format & ALL) == 0)
|
||||
{
|
||||
if(dirEntry[0] == '.')
|
||||
continue;
|
||||
}
|
||||
if(format & LIST)
|
||||
{
|
||||
switch(fileInfo.type)
|
||||
{
|
||||
default:
|
||||
case TYPE_FILE:
|
||||
scratchBuf[0] = '-';
|
||||
break;
|
||||
case TYPE_DIR:
|
||||
scratchBuf[0] = 'd';
|
||||
break;
|
||||
case TYPE_LINK:
|
||||
scratchBuf[0] = 'l';
|
||||
break;
|
||||
}
|
||||
|
||||
if(currTime.year == fileInfo.mTime.year)
|
||||
{
|
||||
len = sprintf((char*)&scratchBuf[1], "rwxrwxrwx %4u %-8s %-8s %8u %s %02d %02d:%02d %s\r\n",
|
||||
fileInfo.links,
|
||||
fileInfo.user,
|
||||
fileInfo.group,
|
||||
fileInfo.size,
|
||||
monName[fileInfo.mTime.month - 1],
|
||||
fileInfo.mTime.day,
|
||||
fileInfo.mTime.hour,
|
||||
fileInfo.mTime.minute,
|
||||
dirEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = sprintf((char*)&scratchBuf[1], "rwxrwxrwx %4u %-8s %-8s %8u %s %02d %5d %s\r\n",
|
||||
fileInfo.links,
|
||||
fileInfo.user,
|
||||
fileInfo.group,
|
||||
fileInfo.size,
|
||||
monName[fileInfo.mTime.month - 1],
|
||||
fileInfo.mTime.day,
|
||||
fileInfo.mTime.year,
|
||||
dirEntry);
|
||||
}
|
||||
ftpSend(dataSocket, scratchBuf, len + 1);
|
||||
haveAnySuccessfulFiles = 1;
|
||||
}
|
||||
else if(format & NLST)
|
||||
{
|
||||
len = sprintf((char*)scratchBuf, "%s\r\n", dirEntry);
|
||||
ftpSend(dataSocket, scratchBuf, len);
|
||||
haveAnySuccessfulFiles = 1;
|
||||
}
|
||||
else if(format & MLSD)
|
||||
{
|
||||
if(!strcmp("..", dirEntry))
|
||||
len = sprintf((char*)scratchBuf, "Type=pdir");
|
||||
else
|
||||
{
|
||||
switch(fileInfo.type)
|
||||
{
|
||||
default:
|
||||
case TYPE_FILE:
|
||||
len = sprintf((char*)scratchBuf, "Type=file");
|
||||
break;
|
||||
case TYPE_DIR:
|
||||
len = sprintf((char*)scratchBuf, "Type=dir");
|
||||
break;
|
||||
case TYPE_LINK:
|
||||
len = sprintf((char*)scratchBuf, "Type=OS.unix=slink");
|
||||
break;
|
||||
}
|
||||
}
|
||||
ftpSend(dataSocket, scratchBuf, len);
|
||||
len = sprintf((char*)scratchBuf, ";Size=%u;Modify=%04d%02d%02d%02d%02d%02d;Perm=r; %s\r\n",
|
||||
fileInfo.size,
|
||||
fileInfo.mTime.year,
|
||||
fileInfo.mTime.month,
|
||||
fileInfo.mTime.day,
|
||||
fileInfo.mTime.hour,
|
||||
fileInfo.mTime.minute,
|
||||
fileInfo.mTime.second,
|
||||
dirEntry);
|
||||
ftpSend(dataSocket, scratchBuf, len);
|
||||
haveAnySuccessfulFiles = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = 1;
|
||||
//break;
|
||||
}
|
||||
}
|
||||
|
||||
ftpCloseDir(dir);
|
||||
if(err && haveAnySuccessfulFiles == 0)
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 451, ftpMsg039);
|
||||
else
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 226, ftpMsg013);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DBG_LOG
|
||||
printf("opendir [%s] returned errno: %#x\n", path,errno);
|
||||
#endif
|
||||
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 451, ftpMsg038);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdList(int sessionId, const char* args, int len)
|
||||
{
|
||||
const char* realPath;
|
||||
socket_t s;
|
||||
//#### Funktioniert nicht wenn Pfad übergeben wird
|
||||
/* if(args[0] != '\0')
|
||||
{
|
||||
if(args[0] != '-')
|
||||
realPath = ftpGetRealPath(sessionId, args);
|
||||
}
|
||||
else*/
|
||||
realPath = ftpGetRealPath(sessionId, ftpGetSession(sessionId)->workingDir, TRUE);
|
||||
|
||||
if(ftpGetSession(sessionId)->passive == FALSE)
|
||||
{
|
||||
s = ftpEstablishDataConnection(FALSE, &ftpGetSession(sessionId)->remoteIp, &ftpGetSession(sessionId)->remoteDataPort);
|
||||
if(s < 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 425, ftpMsg011);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s = ftpAcceptDataConnection(ftpGetSession(sessionId)->passiveDataSocket);
|
||||
if(s < 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 425, ftpMsg012);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
sendListing(s, sessionId, realPath, LIST);
|
||||
ftpCloseSocket(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdNlst(int sessionId, const char* args, int len)
|
||||
{
|
||||
//#### -List kann auch Argumente haben
|
||||
const char* realPath;
|
||||
socket_t s;
|
||||
|
||||
/* if(pfad übergeben)
|
||||
realPath = ftpGetRealPath(sessionId, args);
|
||||
else*/
|
||||
realPath = ftpGetRealPath(sessionId, ftpGetSession(sessionId)->workingDir, TRUE);
|
||||
|
||||
if(ftpGetSession(sessionId)->passive == FALSE)
|
||||
{
|
||||
s = ftpEstablishDataConnection(FALSE, &ftpGetSession(sessionId)->remoteIp, &ftpGetSession(sessionId)->remoteDataPort);
|
||||
if(s < 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 425, ftpMsg011);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s = ftpAcceptDataConnection(ftpGetSession(sessionId)->passiveDataSocket);
|
||||
if(s < 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 425, ftpMsg012);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
sendListing(s, sessionId, realPath, NLST);
|
||||
ftpCloseSocket(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdRetr(int sessionId, const char* args, int len)
|
||||
{
|
||||
ftpPathInfo_S fileInfo;
|
||||
const char* realPath = ftpGetRealPath(sessionId, args, TRUE);
|
||||
socket_t s;
|
||||
void *fp;
|
||||
|
||||
if(ftpStat(realPath, &fileInfo) || (fileInfo.type != TYPE_FILE)) // file accessible?
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 550, ftpMsg032);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if(ftpGetSession(sessionId)->passive == FALSE)
|
||||
{
|
||||
s = ftpEstablishDataConnection(FALSE, &ftpGetSession(sessionId)->remoteIp, &ftpGetSession(sessionId)->remoteDataPort);
|
||||
if(s < 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 425, ftpMsg011);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s = ftpAcceptDataConnection(ftpGetSession(sessionId)->passiveDataSocket);
|
||||
if(s < 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 425, ftpMsg012);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 150, ftpMsg014);
|
||||
|
||||
fp = ftpOpenFile(realPath, "rb");
|
||||
if(fp)
|
||||
{
|
||||
ftpOpenTransmission(sessionId, OP_RETR, fp, s, fileInfo.size);
|
||||
ftpExecTransmission(sessionId);
|
||||
}
|
||||
else
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 451, ftpMsg015);
|
||||
ftpCloseSocket(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdStor(int sessionId, const char* args, int len)
|
||||
{
|
||||
socket_t s;
|
||||
void* fp;
|
||||
const char* realPath = ftpGetRealPath(sessionId, args, TRUE);
|
||||
|
||||
if(ftpGetSession(sessionId)->passive == FALSE)
|
||||
{
|
||||
s = ftpEstablishDataConnection(FALSE, &ftpGetSession(sessionId)->remoteIp, &ftpGetSession(sessionId)->remoteDataPort);
|
||||
if(s < 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 425, ftpMsg011);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s = ftpAcceptDataConnection(ftpGetSession(sessionId)->passiveDataSocket);
|
||||
if(s < 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 425, ftpMsg012);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 150, ftpMsg016);
|
||||
|
||||
fp = ftpOpenFile(realPath, "wb");
|
||||
if(fp)
|
||||
{
|
||||
ftpOpenTransmission(sessionId, OP_STOR, fp, s, 0);
|
||||
ftpExecTransmission(sessionId);
|
||||
}
|
||||
else
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 451, ftpMsg015);
|
||||
ftpCloseSocket(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdDele(int sessionId, const char* args, int len)
|
||||
{
|
||||
const char* realPath = ftpGetRealPath(sessionId, args, TRUE);
|
||||
if(ftpRemoveFile(realPath))
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 450, ftpMsg018);
|
||||
else
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 250, ftpMsg019);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdMkd(int sessionId, const char* args, int len)
|
||||
{
|
||||
const char* realPath = ftpGetRealPath(sessionId, args, TRUE);
|
||||
if(ftpMakeDir(realPath))
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 550, ftpMsg020);
|
||||
else
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 250, ftpMsg021);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdRmd(int sessionId, const char* args, int len)
|
||||
{
|
||||
const char* realPath = ftpGetRealPath(sessionId, args, TRUE);
|
||||
if(ftpRemoveDir(realPath))
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 550, ftpMsg022);
|
||||
else
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 250, ftpMsg023);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdPwd(int sessionId, const char* args, int len)
|
||||
{
|
||||
if(ftpGetSession(sessionId)->workingDir[0])
|
||||
ftpSendMsg(MSG_QUOTE, sessionId, 257, ftpGetSession(sessionId)->workingDir);
|
||||
else
|
||||
ftpSendMsg(MSG_QUOTE, sessionId, 257, "/");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdCwd(int sessionId, const char* args, int len)
|
||||
{
|
||||
if(ftpChangeDir(sessionId, args) == 0)
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 250, ftpMsg024);
|
||||
else
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 550, ftpMsg025);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdType(int sessionId, const char* args, int len)
|
||||
{
|
||||
switch(args[0])
|
||||
{
|
||||
case 'I':
|
||||
case 'i':
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 200, ftpMsg026);
|
||||
ftpGetSession(sessionId)->binary = TRUE;
|
||||
break;
|
||||
case 'A':
|
||||
case 'a':
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 200, ftpMsg027);
|
||||
ftpGetSession(sessionId)->binary = FALSE;
|
||||
break;
|
||||
default:
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 504, ftpMsg028);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdPasv(int sessionId, const char* args, int len)
|
||||
{
|
||||
uint16_t port;
|
||||
uint32_t ip;
|
||||
char str[50];
|
||||
socket_t s;
|
||||
|
||||
if(ftpGetSession(sessionId)->passiveDataSocket >= 0)
|
||||
{
|
||||
ftpCloseSocket(ftpGetSession(sessionId)->passiveDataSocket);
|
||||
ftpGetSession(sessionId)->passiveDataSocket = -1;
|
||||
}
|
||||
s = ftpEstablishDataConnection(TRUE, &ip, &port);
|
||||
if(s < 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 425, ftpMsg012);
|
||||
return 1;
|
||||
}
|
||||
ftpGetSession(sessionId)->passiveDataSocket = s;
|
||||
sprintf(str, "%s (%d,%d,%d,%d,%d,%d)",
|
||||
ftpMsg029,
|
||||
(ip >> 24) & 0xFF,
|
||||
(ip >> 16) & 0xFF,
|
||||
(ip >> 8) & 0xFF,
|
||||
ip & 0xFF,
|
||||
(port >> 8) & 0xFF,
|
||||
port & 0xFF);
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 227, str);
|
||||
ftpGetSession(sessionId)->passive = TRUE;
|
||||
return 0;
|
||||
}
|
||||
LOCAL int ftpCmdCdup(int sessionId, const char* args, int len)
|
||||
{
|
||||
return ftpCmdCwd(sessionId, "..", 2);
|
||||
}
|
||||
LOCAL int ftpCmdStru(int sessionId, const char* args, int len)
|
||||
{
|
||||
switch(args[0])
|
||||
{
|
||||
case 'F':
|
||||
case 'f':
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 200, ftpMsg030);
|
||||
break;
|
||||
default:
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 504, ftpMsg031);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if RFC3659
|
||||
LOCAL int ftpCmdSize(int sessionId, const char* args, int len)
|
||||
{
|
||||
int ret;
|
||||
char str[12];
|
||||
ftpPathInfo_S fileInfo;
|
||||
const char* realPath = ftpGetRealPath(sessionId, args, TRUE);
|
||||
|
||||
ret = ftpStat(realPath, &fileInfo);
|
||||
if(ret)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 550, ftpMsg032);
|
||||
return 2;
|
||||
}
|
||||
|
||||
sprintf(str, "%d", fileInfo.size);
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 213, str);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdMdtm(int sessionId, const char* args, int len)
|
||||
{
|
||||
int ret;
|
||||
char str[15];
|
||||
ftpPathInfo_S fileInfo;
|
||||
const char* realPath = ftpGetRealPath(sessionId, args, TRUE);
|
||||
|
||||
ret = ftpStat(realPath, &fileInfo);
|
||||
if(ret)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 550, ftpMsg032);
|
||||
return 2;
|
||||
}
|
||||
|
||||
sprintf(str, "%04d%02d%02d%02d%02d%02d", fileInfo.mTime.year,
|
||||
fileInfo.mTime.month,
|
||||
fileInfo.mTime.day,
|
||||
fileInfo.mTime.hour,
|
||||
fileInfo.mTime.minute,
|
||||
fileInfo.mTime.second);
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 213, str);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL int ftpCmdMlst(int sessionId, const char* args, int len)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 550, "MLST command not implemented");
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*LOCAL int ftpCmdMlsd(int sessionId, const char* args, int len)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 550, "MLSD command not implemented");
|
||||
|
||||
return 0;
|
||||
}*/
|
||||
LOCAL int ftpCmdMlsd(int sessionId, const char* args, int len)
|
||||
{
|
||||
const char* realPath;
|
||||
socket_t s;
|
||||
//#### Funktioniert nicht wenn Pfad übergeben wird
|
||||
/* if(args[0] != '\0')
|
||||
{
|
||||
if(args[0] != '-')
|
||||
realPath = ftpGetRealPath(sessionId, args);
|
||||
}
|
||||
else*/
|
||||
realPath = ftpGetRealPath(sessionId, ftpGetSession(sessionId)->workingDir, TRUE);
|
||||
|
||||
if(ftpGetSession(sessionId)->passive == FALSE)
|
||||
{
|
||||
s = ftpEstablishDataConnection(FALSE, &ftpGetSession(sessionId)->remoteIp, &ftpGetSession(sessionId)->remoteDataPort);
|
||||
if(s < 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 425, ftpMsg011);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s = ftpAcceptDataConnection(ftpGetSession(sessionId)->passiveDataSocket);
|
||||
if(s < 0)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 425, ftpMsg012);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
sendListing(s, sessionId, realPath, MLSD);
|
||||
ftpCloseSocket(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char cmdToken[5]; ///< command-string
|
||||
int tokLen; ///< len of cmdToken
|
||||
int neededRights; ///< required access rights for executing the command
|
||||
int needLogin; ///< if TRUE, command needs successful authentication via USER and PASS
|
||||
int reportFeat; ///< if TRUE, command is reported via FEAT
|
||||
int duringTransfer; ///< if TRUE, command can be executed during a file transfer
|
||||
int (*handler)(int, const char*, int); ///< handler function
|
||||
}ftpCommand_S;
|
||||
|
||||
static const ftpCommand_S cmds[] = {
|
||||
{"USER", 4, 0, FALSE, FALSE, FALSE, ftpCmdUser},
|
||||
{"PASS", 4, 0, FALSE, FALSE, FALSE, ftpCmdPass},
|
||||
{"SYST", 4, 0, TRUE, FALSE, FALSE, ftpCmdSyst},
|
||||
{"PORT", 4, 0, TRUE, FALSE, FALSE, ftpCmdPort},
|
||||
{"NOOP", 4, 0, TRUE, FALSE, FALSE, ftpCmdNoop},
|
||||
{"QUIT", 4, 0, FALSE, FALSE, TRUE, ftpCmdQuit},
|
||||
{"ABOR", 4, 0, FALSE, FALSE, TRUE, ftpCmdAbor},
|
||||
{"LIST", 4, FTP_ACC_LS, TRUE, FALSE, FALSE, ftpCmdList},
|
||||
{"NLST", 4, FTP_ACC_LS, TRUE, FALSE, FALSE, ftpCmdNlst},
|
||||
{"PWD", 3, FTP_ACC_RD, TRUE, FALSE, FALSE, ftpCmdPwd},
|
||||
{"XPWD", 4, FTP_ACC_DIR, TRUE, FALSE, FALSE, ftpCmdPwd},
|
||||
{"TYPE", 4, 0, TRUE, FALSE, FALSE, ftpCmdType},
|
||||
{"PASV", 4, 0, TRUE, FALSE, FALSE, ftpCmdPasv},
|
||||
{"CWD", 3, FTP_ACC_DIR, TRUE, FALSE, FALSE, ftpCmdCwd},
|
||||
{"CDUP", 4, FTP_ACC_DIR, TRUE, FALSE, FALSE, ftpCmdCdup},
|
||||
{"STRU", 4, 0, TRUE, FALSE, FALSE, ftpCmdStru},
|
||||
{"RETR", 4, FTP_ACC_RD, TRUE, FALSE, FALSE, ftpCmdRetr},
|
||||
{"STOR", 4, FTP_ACC_WR, TRUE, FALSE, FALSE, ftpCmdStor},
|
||||
{"DELE", 4, FTP_ACC_WR, TRUE, FALSE, FALSE, ftpCmdDele},
|
||||
{"MKD" , 3, FTP_ACC_WR, TRUE, FALSE, FALSE, ftpCmdMkd},
|
||||
{"XMKD", 4, FTP_ACC_WR, TRUE, FALSE, FALSE, ftpCmdMkd},
|
||||
{"RMD" , 3, FTP_ACC_WR, TRUE, FALSE, FALSE, ftpCmdRmd},
|
||||
{"XRMD", 4, FTP_ACC_WR, TRUE, FALSE, FALSE, ftpCmdRmd},
|
||||
#if RFC3659
|
||||
{"SIZE", 4, FTP_ACC_RD, TRUE, TRUE, FALSE, ftpCmdSize},
|
||||
{"MDTM", 4, FTP_ACC_RD, TRUE, TRUE, FALSE, ftpCmdMdtm},
|
||||
{"MLST", 4, FTP_ACC_RD, TRUE, TRUE, FALSE, ftpCmdMlst},
|
||||
{"MLSD", 4, FTP_ACC_LS, TRUE, TRUE, FALSE, ftpCmdMlsd}
|
||||
#endif
|
||||
};
|
||||
|
||||
int execFtpCmd(int sessionId, const char* cmd, int cmdlen)
|
||||
{
|
||||
int n;
|
||||
int ret = 0;
|
||||
|
||||
ftpSession_S *pSession = ftpGetSession(sessionId);
|
||||
|
||||
|
||||
for(n = 0; n < ARRAY_SIZE(cmds); n++)
|
||||
{
|
||||
if(!strncmp(cmds[n].cmdToken, cmd, cmds[n].tokLen))
|
||||
{
|
||||
int i = cmds[n].tokLen;
|
||||
|
||||
if(cmds[n].needLogin)
|
||||
{
|
||||
if((pSession->userId == 0) || (pSession->authenticated == FALSE))
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 530, ftpMsg033);
|
||||
return 0;
|
||||
}
|
||||
if(ftpCheckAccRights(pSession->userId, cmds[n].neededRights))
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 550, ftpMsg034);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if((pSession->activeTrans.op != OP_NOP)) // transfer in progress?
|
||||
{
|
||||
if(cmds[n].duringTransfer == FALSE) // command during transfer allowed?
|
||||
return 0; // no => silently discard command
|
||||
}
|
||||
|
||||
while(cmd[i] != '\0')
|
||||
{
|
||||
if((cmd[i] != ' ') && (cmd[i] != '\t'))
|
||||
break;
|
||||
|
||||
i++;
|
||||
}
|
||||
ret = cmds[n].handler(sessionId, &cmd[i], strlen(&cmd[i])); // execute command
|
||||
pSession->timeLastCmd = ftpGetUnixTime();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 500, cmd); // reject unknown commands
|
||||
pSession->timeLastCmd = ftpGetUnixTime();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ftpParseCmd(int sessionId)
|
||||
{
|
||||
ftpSession_S *pSession;
|
||||
int len;
|
||||
int c;
|
||||
socket_t ctrlSocket;
|
||||
|
||||
pSession = ftpGetSession(sessionId);
|
||||
len = pSession->rxBufWriteIdx;
|
||||
ctrlSocket = pSession->ctrlSocket;
|
||||
|
||||
if((pSession->rxBuf[len - 1] == '\n') &&
|
||||
(pSession->rxBuf[len - 2] == '\r') ) // command correctly terminated?
|
||||
{
|
||||
pSession->rxBuf[len - 2] = '\0';
|
||||
pSession->rxBufWriteIdx = 0;
|
||||
|
||||
for(c = 0; c < len; c++) // convert command token to uppercase
|
||||
{
|
||||
if(isspace(pSession->rxBuf[c]))
|
||||
break;
|
||||
pSession->rxBuf[c] = toupper(pSession->rxBuf[c]);
|
||||
}
|
||||
|
||||
#if DBG_LOG
|
||||
printf("%02d --> %s\n", sessionId, pSession->rxBuf);
|
||||
#endif
|
||||
|
||||
if(execFtpCmd(sessionId, pSession->rxBuf, len - 2) == -1)
|
||||
{
|
||||
ftpUntrackSocket(ctrlSocket);
|
||||
ftpCloseSession(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
if(pSession->rxBufWriteIdx >= LEN_RXBUF) // overflow of receive buffer?
|
||||
{
|
||||
pSession->rxBufWriteIdx = 0;
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 500, ftpMsg035);
|
||||
#if DBG_LOG
|
||||
printf("Receive buffer overflow. Received data discarded.\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
171
source/shared_lib/sources/feathery_ftp/ftpLib.c
Normal file
171
source/shared_lib/sources/feathery_ftp/ftpLib.c
Normal file
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Feathery FTP-Server <https://sourceforge.net/projects/feathery>
|
||||
* Copyright (C) 2005-2010 Andreas Martin (andreas.martin@linuxmail.org)
|
||||
*
|
||||
* ftpLib.c - Global helper functions
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "ftpTypes.h"
|
||||
#include "ftpConfig.h"
|
||||
#include "ftp.h"
|
||||
#include "ftpIfc.h"
|
||||
|
||||
/**
|
||||
* @brief Removes the trailing slash of a directory path
|
||||
*
|
||||
* @param path directory path
|
||||
*
|
||||
* @return len of path
|
||||
*/
|
||||
int ftpRemoveTrailingSlash(char* path)
|
||||
{
|
||||
int len = strlen(path);
|
||||
|
||||
if(len > 1)
|
||||
{
|
||||
len--;
|
||||
if(path[len] == '/')
|
||||
path[len] = '\0';
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes double slashes in a path
|
||||
*
|
||||
* e. g. "//a//b//c" will be converted to "a/b/c"
|
||||
*
|
||||
* @param path directory path
|
||||
*/
|
||||
void ftpRemoveDoubleSlash(char* path)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = path;
|
||||
|
||||
while(*p != '\0')
|
||||
{
|
||||
if((p[0] == '/') && (p[1] == '/'))
|
||||
ftpStrcpy(p, &p[1]);
|
||||
else
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Merges multiple path strings
|
||||
*
|
||||
* The function catenates all passed strings to a new string and assures that
|
||||
* the result does not exceed MAX_PATH_LEN. The last parameter has to be
|
||||
* NULL.
|
||||
* @todo Not all embedded environments support variadic functions, or they are
|
||||
* too expensive.
|
||||
*
|
||||
* @param dest user name
|
||||
*
|
||||
* @return Pointer to dest
|
||||
*/
|
||||
char* ftpMergePaths(char* dest, ...)
|
||||
{
|
||||
const char* src;
|
||||
char* dst = dest;
|
||||
int len = 0;
|
||||
va_list args;
|
||||
|
||||
va_start(args, dest);
|
||||
|
||||
while((src = va_arg(args, const char*)))
|
||||
{
|
||||
while((*src != '\0') && (len < MAX_PATH_LEN-1))
|
||||
{
|
||||
*dst++ = *src++;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
va_end(args);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine the unix-time
|
||||
*
|
||||
* The function reads the clock from the target-layer and converts it to the
|
||||
* unix-time. The code is taken from http://de.wikipedia.org/wiki/Unixzeit
|
||||
*
|
||||
* @return seconds since 1. Januar 1970 00:00
|
||||
*/
|
||||
uint32_t ftpGetUnixTime(void)
|
||||
{
|
||||
ftpTime_S t;
|
||||
uint32_t unixTime = 0;
|
||||
int j;
|
||||
|
||||
ftpGetLocalTime(&t);
|
||||
|
||||
for(j=1970;j<t.year;j++) // leap years
|
||||
{
|
||||
if(j%4==0 && (j%100!=0 || j%400==0))
|
||||
unixTime+=(366*24*60*60);
|
||||
else
|
||||
unixTime+=(365*24*60*60);
|
||||
}
|
||||
for(j=1;j<t.month;j++) // days per month 31/30/29/28
|
||||
{
|
||||
if(j==1 || j==3 || j==5 || j==7 || j==8 || j==10 || j==12)
|
||||
unixTime+=(31*24*60*60); // months with 31 days
|
||||
if(j==4 || j==6 || j==9 || j==11)
|
||||
unixTime+=(30*24*60*60); // months with 30 days
|
||||
if( (j==2) && (t.year%4==0 && (t.year%100!=0 || t.year%400==0)) )
|
||||
unixTime+=(29*24*60*60);
|
||||
else
|
||||
unixTime+=(28*24*60*60);
|
||||
}
|
||||
unixTime+=((t.day-1)*24*60*60);
|
||||
unixTime+=(t.hour*60*60);
|
||||
unixTime+=t.minute*60;
|
||||
unixTime+=t.second;
|
||||
|
||||
return unixTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief copy a string
|
||||
*
|
||||
* The reason why feathery has its own strcpy is that in some cases src is
|
||||
* part of dest and src > dest. Because ANSI-C explicitly declares that case
|
||||
* as undefined our strcpy guarantees to copy from lower to higher
|
||||
* addresses.
|
||||
*
|
||||
* @param dest destination string
|
||||
* @param src Null-terminated source string
|
||||
*
|
||||
* @return destination string
|
||||
*/
|
||||
char *ftpStrcpy(char *dest, const char *src)
|
||||
{
|
||||
char *d = dest;
|
||||
const char *s = src;
|
||||
|
||||
while (*d++ = *s++);
|
||||
return dest;
|
||||
}
|
66
source/shared_lib/sources/feathery_ftp/ftpMessages.c
Normal file
66
source/shared_lib/sources/feathery_ftp/ftpMessages.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Feathery FTP-Server <https://sourceforge.net/projects/feathery>
|
||||
* Copyright (C) 2005-2010 Andreas Martin (andreas.martin@linuxmail.org)
|
||||
*
|
||||
* ftpMessages.c - FTP-Server messages
|
||||
*
|
||||
* This Module defines all message-strings the servers sends to
|
||||
* clients. If someone needs to translate the server user interface
|
||||
* to a different language this is the only file to be touched.
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
const char ftpMsg000[] = "Data connection error";
|
||||
const char ftpMsg001[] = "File error";
|
||||
const char ftpMsg002[] = "File send OK";
|
||||
const char ftpMsg003[] = "File received OK";
|
||||
const char ftpMsg004[] = "Please specify the password";
|
||||
const char ftpMsg005[] = "Login successful";
|
||||
const char ftpMsg006[] = "Login failed";
|
||||
const char ftpMsg007[] = "PORT command successful. Consider using PASV.";
|
||||
const char ftpMsg008[] = "NOOP command successful";
|
||||
const char ftpMsg009[] = "Goodby";
|
||||
const char ftpMsg010[] = "Here comes the listing";
|
||||
const char ftpMsg011[] = "Could not establish data connection.";
|
||||
const char ftpMsg012[] = "Could not establish passive data connection.";
|
||||
const char ftpMsg013[] = "Directory send OK";
|
||||
const char ftpMsg014[] = "Sending file...";
|
||||
const char ftpMsg015[] = "Could not open file.";
|
||||
const char ftpMsg016[] = "Receiving file...";
|
||||
const char ftpMsg018[] = "Could not delete file";
|
||||
const char ftpMsg019[] = "File deleted";
|
||||
const char ftpMsg020[] = "Could create directory";
|
||||
const char ftpMsg021[] = "Directory created";
|
||||
const char ftpMsg022[] = "Could remove directory";
|
||||
const char ftpMsg023[] = "Directory removed";
|
||||
const char ftpMsg024[] = "Directory successfully changed";
|
||||
const char ftpMsg025[] = "Failed to change directory";
|
||||
const char ftpMsg026[] = "Switching to binary mode";
|
||||
const char ftpMsg027[] = "Switching to ascii mode";
|
||||
const char ftpMsg028[] = "Unknown type-code";
|
||||
const char ftpMsg029[] = "Entering passive mode";
|
||||
const char ftpMsg030[] = "Switching to file mode";
|
||||
const char ftpMsg031[] = "Only file mode supported";
|
||||
const char ftpMsg032[] = "Invalid path";
|
||||
const char ftpMsg033[] = "Please login with USER and PASS.";
|
||||
const char ftpMsg034[] = "Permission denied.";
|
||||
const char ftpMsg035[] = "Line too long.";
|
||||
const char ftpMsg036[] = "Timeout.";
|
||||
const char ftpMsg037[] = "Hi";
|
||||
const char ftpMsg038[] = "Could not open directory.";
|
||||
const char ftpMsg039[] = "Could not read directory.";
|
||||
const char ftpMsg040[] = "Aborted.";
|
217
source/shared_lib/sources/feathery_ftp/ftpRuntime.c
Normal file
217
source/shared_lib/sources/feathery_ftp/ftpRuntime.c
Normal file
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Feathery FTP-Server <https://sourceforge.net/projects/feathery>
|
||||
* Copyright (C) 2005-2010 Andreas Martin (andreas.martin@linuxmail.org)
|
||||
*
|
||||
* ftpRuntime.c - ftp-server runtime environment
|
||||
*
|
||||
* This is the central module of feathery. It defines all runtime functions
|
||||
* of feathery. That is startup, state, main-thread an shutdown.
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ftpTypes.h"
|
||||
#include "ftpConfig.h"
|
||||
#include "ftp.h"
|
||||
#include "ftpMessages.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief server-sockets that listens for incoming connections
|
||||
*/
|
||||
LOCAL socket_t server;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initializes and starts the server
|
||||
*
|
||||
*
|
||||
* @return - 0: server started successfully
|
||||
* - -1: could not create server socket
|
||||
*/
|
||||
int ftpStart(void)
|
||||
{
|
||||
server = -1; // set server socket to invalid value
|
||||
|
||||
#if DBG_LOG
|
||||
printf("Feathery FTP-Server\n");
|
||||
#endif
|
||||
|
||||
ftpArchInit();
|
||||
#if DBG_LOG
|
||||
printf(". Creating server socket");
|
||||
#endif
|
||||
|
||||
server = ftpCreateServerSocket(); // create main listener socket
|
||||
if(server < 0)
|
||||
{
|
||||
#if DBG_LOG
|
||||
printf("\t\terror\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if DBG_LOG
|
||||
printf("\t\tok\n");
|
||||
printf("Server successfully startet\n");
|
||||
#endif
|
||||
|
||||
ftpTrackSocket(server); // add socket to "watchlist"
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if the server has something to do
|
||||
*
|
||||
* In order of avoid blocking of ftpExecute this function can be used to
|
||||
* determine if the server has something to do. You can call this function in
|
||||
* a loop and everytime it returns nonezero its time to call ftpExecute().
|
||||
* @todo implement me
|
||||
*
|
||||
* @return 0 noting to do; else server has received some data
|
||||
*/
|
||||
int ftpState(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Main server-thread
|
||||
*
|
||||
* Manages all client connections and active transmitions. In addtition
|
||||
* all received control-strings are dispatched to the command-module.
|
||||
* Note, the function blocks if there is nothing to do.
|
||||
*/
|
||||
void ftpExecute(void)
|
||||
{
|
||||
int n;
|
||||
int socksRdy;
|
||||
ftpSession_S *pSession;
|
||||
int sessionId;
|
||||
int activeJobs;
|
||||
|
||||
|
||||
activeJobs = ftpGetActiveTransCnt(); // are there any active transmitions?
|
||||
for(n = 0; (activeJobs > 0) && (n < MAX_CONNECTIONS); n++)
|
||||
{
|
||||
pSession = ftpGetSession(n);
|
||||
if(pSession->activeTrans.op) // has this session an active transmition?
|
||||
{
|
||||
ftpExecTransmission(n); // do the job
|
||||
activeJobs--;
|
||||
}
|
||||
}
|
||||
|
||||
//if(ftpGetActiveTransCnt()) // don't block if there's still something to do
|
||||
socksRdy = ftpSelect(TRUE);
|
||||
//else
|
||||
// socksRdy = ftpSelect(FALSE);
|
||||
if(socksRdy > 0)
|
||||
{
|
||||
if(ftpTestSocket(server)) // server listner-socket signaled?
|
||||
{
|
||||
socket_t clientSocket;
|
||||
ip_t remoteIP;
|
||||
port_t remotePort;
|
||||
|
||||
socksRdy--;
|
||||
clientSocket = ftpAcceptServerConnection(server, &remoteIP, &remotePort);
|
||||
if(clientSocket >= 0)
|
||||
{
|
||||
sessionId = ftpOpenSession(clientSocket, remoteIP, remotePort);
|
||||
if(sessionId >= 0)
|
||||
{
|
||||
ftpTrackSocket(clientSocket);
|
||||
ftpSendMsg(MSG_NORMAL, sessionId, 220, ftpMsg037);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DBG_LOG
|
||||
printf("Connection refused; Session limit reached.\n");
|
||||
#endif
|
||||
ftpCloseSocket(clientSocket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(n = 0; (socksRdy > 0) && (n < MAX_CONNECTIONS); n++)
|
||||
{
|
||||
pSession = ftpGetSession(n);
|
||||
if(pSession->open)
|
||||
{
|
||||
socket_t ctrlSocket = pSession->ctrlSocket;
|
||||
|
||||
if(ftpTestSocket(ctrlSocket))
|
||||
{
|
||||
int len;
|
||||
socksRdy--;
|
||||
len = ftpReceive(ctrlSocket,
|
||||
&pSession->rxBuf[pSession->rxBufWriteIdx],
|
||||
LEN_RXBUF - pSession->rxBufWriteIdx);
|
||||
if(len <= 0) // has client shutdown the connection?
|
||||
{
|
||||
ftpUntrackSocket(ctrlSocket);
|
||||
ftpCloseSession(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
pSession->rxBufWriteIdx += len;
|
||||
ftpParseCmd(n);
|
||||
}
|
||||
}
|
||||
/// @bug Session-Timeout-Management doesn't work
|
||||
if((ftpGetUnixTime() - pSession->timeLastCmd) > SESSION_TIMEOUT)
|
||||
{
|
||||
ftpSendMsg(MSG_NORMAL, n, 421, ftpMsg036);
|
||||
ftpUntrackSocket(ctrlSocket);
|
||||
ftpCloseSession(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Shut down the server
|
||||
*
|
||||
* Cuts all tcp-connections and frees all used resources.
|
||||
|
||||
* @return 0
|
||||
*/
|
||||
int ftpShutdown(void)
|
||||
{
|
||||
int n;
|
||||
ftpUntrackSocket(server);
|
||||
ftpCloseSocket(server);
|
||||
|
||||
for(n = 0; n < MAX_CONNECTIONS; n++)
|
||||
{
|
||||
if(ftpGetSession(n)->open)
|
||||
{
|
||||
ftpUntrackSocket(ftpGetSession(n)->ctrlSocket);
|
||||
ftpCloseSession(n);
|
||||
}
|
||||
}
|
||||
|
||||
ftpArchCleanup();
|
||||
|
||||
return 0;
|
||||
}
|
38
source/shared_lib/sources/feathery_ftp/ftpServer.c
Normal file
38
source/shared_lib/sources/feathery_ftp/ftpServer.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/* FEATHERY FTP-Server
|
||||
* Copyright (C) 2005-2010 Andreas Martin (andreas.martin@linuxmail.org)
|
||||
* <https://sourceforge.net/projects/feathery>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
|
||||
#include "ftpIfc.h"
|
||||
int main(void)
|
||||
{
|
||||
ftpCreateAccount("anonymous", "", "./", FTP_ACC_RD | FTP_ACC_LS | FTP_ACC_DIR);
|
||||
ftpCreateAccount("nothing", "", "./", 0);
|
||||
ftpCreateAccount("reader", "", "./", FTP_ACC_RD);
|
||||
ftpCreateAccount("writer", "", "./", FTP_ACC_WR);
|
||||
ftpCreateAccount("lister", "", "./", FTP_ACC_LS);
|
||||
ftpCreateAccount("admin", "xxx", "./", FTP_ACC_RD | FTP_ACC_WR | FTP_ACC_LS | FTP_ACC_DIR);
|
||||
|
||||
ftpStart();
|
||||
while(1)
|
||||
ftpExecute();
|
||||
ftpShutdown();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
344
source/shared_lib/sources/feathery_ftp/ftpSession.c
Normal file
344
source/shared_lib/sources/feathery_ftp/ftpSession.c
Normal file
@@ -0,0 +1,344 @@
|
||||
/**
|
||||
* Feathery FTP-Server <https://sourceforge.net/projects/feathery>
|
||||
* Copyright (C) 2005-2010 Andreas Martin (andreas.martin@linuxmail.org)
|
||||
*
|
||||
* ftpSession.c - Session handling of connected clients
|
||||
*
|
||||
* A ftp session is a TCP connection between the server and a ftp client.
|
||||
* Each session has its own unique session id. The session id refers
|
||||
* (index in session[]) to a struct ftpSession_S which holds all
|
||||
* relevant data. The virtual chroot environment is also part of the
|
||||
* session management.
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ftpTypes.h"
|
||||
#include "ftpConfig.h"
|
||||
#include "ftp.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief array that holds the data of all ftp sessions
|
||||
*
|
||||
* The index represents the session ID.
|
||||
*/
|
||||
LOCAL ftpSession_S sessions[MAX_CONNECTIONS];
|
||||
|
||||
/**
|
||||
* @brief number of active file or directory transmission
|
||||
*/
|
||||
LOCAL int actTransCnt;
|
||||
|
||||
/**
|
||||
* @brief Scratch-buffer for path manipulation
|
||||
*/
|
||||
LOCAL char pathScratchBuf[MAX_PATH_LEN];
|
||||
|
||||
|
||||
/**
|
||||
* @brief Opens a ftp session
|
||||
*
|
||||
* Searches in 'sessions' for an empty entry and inits the session data.
|
||||
* Call this function after accepting a tcp connection from a ftp client.
|
||||
*
|
||||
* @param ctrlSocket control socket which initiated the the ftp session
|
||||
* @param remoteIp IP address of the client
|
||||
* @param remotePort TCP-Port of the client
|
||||
*
|
||||
* @return session id or -1 if session limit is reached
|
||||
*/
|
||||
int ftpOpenSession(socket_t ctrlSocket, ip_t remoteIp, port_t remotePort)
|
||||
{
|
||||
int n;
|
||||
for(n = 0; n < MAX_CONNECTIONS; n++)
|
||||
{
|
||||
if(!sessions[n].open)
|
||||
{
|
||||
sessions[n].open = TRUE;
|
||||
sessions[n].authenticated = FALSE;
|
||||
sessions[n].userId = 0;
|
||||
sessions[n].workingDir[0] = '\0';
|
||||
sessions[n].remoteIp = remoteIp;
|
||||
sessions[n].remotePort = remotePort;
|
||||
sessions[n].remoteDataPort = 0;
|
||||
sessions[n].passive = FALSE;
|
||||
sessions[n].binary = TRUE;
|
||||
sessions[n].timeLastCmd = ftpGetUnixTime();
|
||||
sessions[n].ctrlSocket = ctrlSocket;
|
||||
sessions[n].passiveDataSocket = -1;
|
||||
sessions[n].rxBufWriteIdx = 0;
|
||||
sessions[n].activeTrans.op = OP_NOP;
|
||||
sessions[n].activeTrans.fsHandle = NULL;
|
||||
sessions[n].activeTrans.dataSocket = -1;
|
||||
sessions[n].activeTrans.fileSize = 0;
|
||||
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Marks the current ftp session as 'authenticated'
|
||||
*
|
||||
* @param id Session id
|
||||
*
|
||||
* @return 0
|
||||
*/
|
||||
int ftpAuthSession(int id)
|
||||
{
|
||||
sessions[id].authenticated = TRUE;
|
||||
strcpy(sessions[id].workingDir, "/");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Closes a ftp session
|
||||
*
|
||||
* Closes the TCP control connection and releases the session struct.
|
||||
*
|
||||
* @param id Session id
|
||||
*
|
||||
* @return 0
|
||||
*/
|
||||
int ftpCloseSession(int id)
|
||||
{
|
||||
ftpCloseSocket(sessions[id].ctrlSocket);
|
||||
ftpCloseTransmission(id);
|
||||
|
||||
sessions[id].open = FALSE;
|
||||
|
||||
#if DBG_LOG
|
||||
printf("Session %d closed\n", id);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns pointer to session struct
|
||||
*
|
||||
* @param id Session id
|
||||
*
|
||||
* @return pointer to session data
|
||||
*/
|
||||
ftpSession_S* ftpGetSession(int id)
|
||||
{
|
||||
return &sessions[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Normalizes a path string
|
||||
*
|
||||
* The function resolves all dot and doubledot directory entries in the
|
||||
* passed path. If the normalized path refers beyond root, root is returned.
|
||||
*
|
||||
* @param path string of an absolute path
|
||||
*
|
||||
* @return 0
|
||||
*/
|
||||
LOCAL int normalizePath(char* path)
|
||||
{
|
||||
char *in;
|
||||
char *r = NULL;
|
||||
|
||||
r = path;
|
||||
in = path;
|
||||
|
||||
while((in = strchr(in, '/')))
|
||||
{
|
||||
if(!strncmp(in, "/./", 3))
|
||||
{
|
||||
ftpStrcpy(in, &in[2]);
|
||||
continue;
|
||||
}
|
||||
if(!strcmp(in, "/."))
|
||||
{
|
||||
in[1] = '\0';
|
||||
continue;
|
||||
}
|
||||
if(!strncmp(in, "/../", 4))
|
||||
{
|
||||
*in = '\0';
|
||||
r = strrchr(path, '/');
|
||||
if(r == NULL)
|
||||
r = path;
|
||||
ftpStrcpy(r, &in[3]);
|
||||
in = r;
|
||||
continue;
|
||||
}
|
||||
if(!strcmp(in, "/.."))
|
||||
{
|
||||
*in = '\0';
|
||||
r = strrchr(path, '/');
|
||||
if(r)
|
||||
{
|
||||
if(r == path)
|
||||
r[1] = '\0';
|
||||
else
|
||||
*r = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
in[0] = '/';
|
||||
in[1] = '\0';
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
in++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Translate a ftp session path to server path
|
||||
*
|
||||
* The translated path depends on the current working directory of the
|
||||
* session and the root path of the session. In addition the path will
|
||||
* be normalized.
|
||||
* The server path is generated as followed:
|
||||
* passed path is relative => server path = ftp user root + session working dir + path
|
||||
* passed path is absolute => server path = ftp user root + path
|
||||
*
|
||||
* @param id Session id
|
||||
* @param path ftp session path (can be relative or absolute)
|
||||
* @param if != 0 dot and doubledot directories will be resolved
|
||||
*
|
||||
* @return translated absolute server path
|
||||
*/
|
||||
const char* ftpGetRealPath(int id, const char* path, int normalize)
|
||||
{
|
||||
const char* ftpRoot;
|
||||
int len;
|
||||
|
||||
ftpRoot = ftpGetRoot(sessions[id].userId, &len);
|
||||
|
||||
#if DBG_LOG
|
||||
printf("ftpGetRealPath path [%s] ftpRoot [%s] sessions[id].workingDir [%s]\n", path, ftpRoot, sessions[id].workingDir);
|
||||
#endif
|
||||
|
||||
pathScratchBuf[0]='\0';
|
||||
if(path[0] == '/' || strcmp(path,sessions[id].workingDir) == 0) // absolute path?
|
||||
{
|
||||
ftpMergePaths(pathScratchBuf, ftpRoot, path, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
ftpMergePaths(pathScratchBuf, ftpRoot, sessions[id].workingDir, "/", path, NULL);
|
||||
//ftpMergePaths(pathScratchBuf, ftpRoot, path, NULL);
|
||||
}
|
||||
|
||||
#if DBG_LOG
|
||||
printf("#2 ftpGetRealPath path [%s] ftpRoot [%s]\n", path, ftpRoot);
|
||||
#endif
|
||||
|
||||
ftpRemoveDoubleSlash(pathScratchBuf);
|
||||
if(normalize) {
|
||||
normalizePath(pathScratchBuf);
|
||||
}
|
||||
ftpRemoveTrailingSlash(pathScratchBuf);
|
||||
|
||||
#if DBG_LOG
|
||||
printf("#2 ftpGetRealPath path [%s] ftpRoot [%s] pathScratchBuf [%s]\n", path, ftpRoot, pathScratchBuf);
|
||||
#endif
|
||||
|
||||
return pathScratchBuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Change the current working directory of the session
|
||||
*
|
||||
* @param id Session id
|
||||
* @param path destination ftp path (can be relative or absolute)
|
||||
*
|
||||
* @return 0 on success; -2 if the directory doesn't exist
|
||||
*/
|
||||
int ftpChangeDir(int id, const char* path)
|
||||
{
|
||||
ftpPathInfo_S fileInfo;
|
||||
const char* realPath = ftpGetRealPath(id, path, TRUE);
|
||||
int len;
|
||||
|
||||
|
||||
ftpGetRoot(sessions[id].userId, &len); // determine len of root-path
|
||||
if(len == 1) // if len == 1 root-path == '/'
|
||||
len = 0;
|
||||
|
||||
#if DBG_LOG
|
||||
printf("ftpChangeDir path [%s] realPath [%s] sessions[id].workingDir [%s]\n", path, realPath, sessions[id].workingDir);
|
||||
#endif
|
||||
|
||||
if(ftpStat(realPath, &fileInfo) || (fileInfo.type != TYPE_DIR)) // directory accessible?
|
||||
return -2;
|
||||
|
||||
strncpy(sessions[id].workingDir, &realPath[len], MAX_PATH_LEN); // apply path
|
||||
if(sessions[id].workingDir[0] == '\0')
|
||||
strcpy(sessions[id].workingDir, "/");
|
||||
|
||||
#if DBG_LOG
|
||||
printf("ftpChangeDir path [%s] realPath [%s] NEW sessions[id].workingDir [%s]\n", path, realPath, sessions[id].workingDir);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo documentation
|
||||
*/
|
||||
void ftpOpenTransmission(int id, operation_E op, void* fsHandle, socket_t dataSocket, uint32_t fileSize)
|
||||
{
|
||||
actTransCnt++;
|
||||
sessions[id].activeTrans.op = op;
|
||||
sessions[id].activeTrans.fsHandle = fsHandle;
|
||||
sessions[id].activeTrans.dataSocket = dataSocket;
|
||||
sessions[id].activeTrans.fileSize = fileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo documentation
|
||||
*/
|
||||
void ftpCloseTransmission(int id)
|
||||
{
|
||||
if(sessions[id].activeTrans.op != OP_NOP) // is thera an active transmission?
|
||||
{
|
||||
ftpCloseSocket(sessions[id].activeTrans.dataSocket);
|
||||
if(sessions[id].activeTrans.op == OP_LIST)
|
||||
{
|
||||
ftpCloseDir(sessions[id].activeTrans.fsHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
ftpCloseFile(sessions[id].activeTrans.fsHandle);
|
||||
}
|
||||
sessions[id].activeTrans.op = OP_NOP;
|
||||
actTransCnt--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo documentation
|
||||
*/
|
||||
int ftpGetActiveTransCnt(void)
|
||||
{
|
||||
return actTransCnt;
|
||||
}
|
383
source/shared_lib/sources/feathery_ftp/ftpTargetPosix.c
Normal file
383
source/shared_lib/sources/feathery_ftp/ftpTargetPosix.c
Normal file
@@ -0,0 +1,383 @@
|
||||
/* FEATHERY FTP-Server
|
||||
* Copyright (C) 2005-2010 Andreas Martin (andreas.martin@linuxmail.org)
|
||||
* <https://sourceforge.net/projects/feathery>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <dirent.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "ftpTypes.h"
|
||||
#include "ftpConfig.h"
|
||||
#include "ftp.h"
|
||||
|
||||
ip_t ownIp;
|
||||
|
||||
LOCAL fd_set watchedSockets;
|
||||
LOCAL fd_set signaledSockets;
|
||||
LOCAL int maxSockNr;
|
||||
|
||||
|
||||
void ftpArchInit(void)
|
||||
{
|
||||
ownIp = 0;
|
||||
maxSockNr = 0;
|
||||
FD_ZERO(&watchedSockets);
|
||||
FD_ZERO(&signaledSockets);
|
||||
}
|
||||
|
||||
void ftpArchCleanup(void)
|
||||
{
|
||||
}
|
||||
|
||||
int ftpGetLocalTime(ftpTime_S *t)
|
||||
{
|
||||
struct tm *pTime;
|
||||
time_t tim;
|
||||
|
||||
time(&tim);
|
||||
pTime = localtime(&tim);
|
||||
if(pTime)
|
||||
{
|
||||
t->year = (uint16_t)pTime->tm_year + 1900;
|
||||
t->month = (uint8_t)pTime->tm_mon + 1;
|
||||
t->day = (uint8_t)pTime->tm_mday;
|
||||
t->hour = (uint8_t)pTime->tm_hour;
|
||||
t->minute = (uint8_t)pTime->tm_min;
|
||||
t->second = (uint8_t)pTime->tm_sec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void* ftpOpenDir(const char* path)
|
||||
{
|
||||
return opendir(path);
|
||||
}
|
||||
|
||||
const char* ftpReadDir(void* dirHandle)
|
||||
{
|
||||
struct dirent* dirEntry;
|
||||
|
||||
dirEntry = readdir(dirHandle);
|
||||
if(dirEntry)
|
||||
return dirEntry->d_name;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ftpCloseDir(void* dirHandle)
|
||||
{
|
||||
return closedir(dirHandle);
|
||||
}
|
||||
|
||||
int ftpStat(const char* path, ftpPathInfo_S *info)
|
||||
{
|
||||
struct stat fileInfo = {0};
|
||||
struct tm *pTime;
|
||||
struct passwd *pw;
|
||||
struct group *gr;
|
||||
|
||||
if(!stat(path, &fileInfo))
|
||||
{
|
||||
if(S_ISREG(fileInfo.st_mode))
|
||||
info->type = TYPE_FILE;
|
||||
else if(S_ISDIR(fileInfo.st_mode))
|
||||
info->type = TYPE_DIR;
|
||||
else
|
||||
info->type = TYPE_LINK;
|
||||
|
||||
pTime = localtime(&fileInfo.st_mtime);
|
||||
if(pTime)
|
||||
{
|
||||
info->mTime.year = (uint16_t)pTime->tm_year + 1900;
|
||||
info->mTime.month = (uint8_t)pTime->tm_mon + 1;
|
||||
info->mTime.day = (uint8_t)pTime->tm_mday;
|
||||
info->mTime.hour = (uint8_t)pTime->tm_hour;
|
||||
info->mTime.minute = (uint8_t)pTime->tm_min;
|
||||
info->mTime.second = (uint8_t)pTime->tm_sec;
|
||||
}
|
||||
pTime = localtime(&fileInfo.st_ctime);
|
||||
if(pTime)
|
||||
{
|
||||
info->cTime.year = (uint16_t)pTime->tm_year + 1900;
|
||||
info->cTime.month = (uint8_t)pTime->tm_mon + 1;
|
||||
info->cTime.day = (uint8_t)pTime->tm_mday;
|
||||
info->cTime.hour = (uint8_t)pTime->tm_hour;
|
||||
info->cTime.minute = (uint8_t)pTime->tm_min;
|
||||
info->cTime.second = (uint8_t)pTime->tm_sec;
|
||||
}
|
||||
pTime = localtime(&fileInfo.st_atime);
|
||||
if(pTime)
|
||||
{
|
||||
info->aTime.year = (uint16_t)pTime->tm_year + 1900;
|
||||
info->aTime.month = (uint8_t)pTime->tm_mon + 1;
|
||||
info->aTime.day = (uint8_t)pTime->tm_mday;
|
||||
info->aTime.hour = (uint8_t)pTime->tm_hour;
|
||||
info->aTime.minute = (uint8_t)pTime->tm_min;
|
||||
info->aTime.second = (uint8_t)pTime->tm_sec;
|
||||
}
|
||||
|
||||
info->size = (uint32_t)fileInfo.st_size;
|
||||
info->links = (int)fileInfo.st_nlink;
|
||||
|
||||
pw = getpwuid(fileInfo.st_uid);
|
||||
if(pw)
|
||||
strncpy(info->user, pw->pw_name, sizeof(info->user));
|
||||
else
|
||||
sprintf(info->user, "%04d", fileInfo.st_uid);
|
||||
|
||||
gr = getgrgid(fileInfo.st_gid);
|
||||
if(gr)
|
||||
strncpy(info->group, gr->gr_name, sizeof(info->group));
|
||||
else
|
||||
sprintf(info->group, "%04d", fileInfo.st_gid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ftpMakeDir(const char* path)
|
||||
{
|
||||
return mkdir(path, S_IRUSR | S_IWUSR);
|
||||
}
|
||||
|
||||
int ftpRemoveDir(const char* path)
|
||||
{
|
||||
return rmdir(path);
|
||||
}
|
||||
|
||||
int ftpCloseSocket(socket_t s)
|
||||
{
|
||||
return close(s);
|
||||
}
|
||||
|
||||
int ftpSend(socket_t s, const void *data, int len)
|
||||
{
|
||||
int currLen = 0;
|
||||
|
||||
do
|
||||
{
|
||||
currLen = send(s, data, len, 0);
|
||||
if(currLen >= 0)
|
||||
{
|
||||
len -= currLen;
|
||||
data = (uint8_t*)data + currLen;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
}while(len > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftpReceive(socket_t s, void *data, int len)
|
||||
{
|
||||
return recv(s, data, len, 0);
|
||||
}
|
||||
|
||||
socket_t ftpEstablishDataConnection(int passive, ip_t *ip, port_t *port)
|
||||
{
|
||||
socket_t dataSocket;
|
||||
struct sockaddr_in clientAddr;
|
||||
struct sockaddr_in myAddr;
|
||||
int on = 1;
|
||||
unsigned len;
|
||||
dataSocket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(dataSocket < 0)
|
||||
return -1;
|
||||
|
||||
if(!passive)
|
||||
{
|
||||
if(setsockopt(dataSocket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
|
||||
{
|
||||
close(dataSocket);
|
||||
return -1;
|
||||
}
|
||||
myAddr.sin_family = AF_INET;
|
||||
myAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
myAddr.sin_port = htons(20);
|
||||
if(bind(dataSocket, (struct sockaddr *)&myAddr, sizeof(myAddr)))
|
||||
{
|
||||
close(dataSocket);
|
||||
return -1;
|
||||
}
|
||||
clientAddr.sin_family = AF_INET;
|
||||
clientAddr.sin_addr.s_addr = htonl(*ip);
|
||||
clientAddr.sin_port = htons(*port);
|
||||
if(connect(dataSocket, (struct sockaddr *)&clientAddr, sizeof(clientAddr)))
|
||||
{
|
||||
close(dataSocket);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
myAddr.sin_family = AF_INET;
|
||||
myAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
myAddr.sin_port = htons(0);
|
||||
if(bind(dataSocket, (struct sockaddr *)&myAddr, sizeof(myAddr)))
|
||||
{
|
||||
close(dataSocket);
|
||||
return -1;
|
||||
}
|
||||
len = sizeof(myAddr);
|
||||
if(getsockname(dataSocket, (struct sockaddr *)&myAddr, &len)) // Port des Server-Sockets ermitteln
|
||||
{
|
||||
close(dataSocket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*port = ntohs(myAddr.sin_port);
|
||||
*ip = ownIp;
|
||||
|
||||
if(listen(dataSocket, 1))
|
||||
{
|
||||
close(dataSocket);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return dataSocket;
|
||||
}
|
||||
|
||||
socket_t ftpAcceptDataConnection(socket_t listner)
|
||||
{
|
||||
struct sockaddr_in clientinfo;
|
||||
unsigned len;
|
||||
socket_t dataSocket;
|
||||
|
||||
len = sizeof(clientinfo);
|
||||
|
||||
dataSocket = accept(listner, (struct sockaddr *)&clientinfo, &len);
|
||||
if(dataSocket < 0)
|
||||
dataSocket = -1;
|
||||
|
||||
close(listner); // Server-Socket wird nicht mehr gebrauch deshalb schließen
|
||||
return dataSocket;
|
||||
}
|
||||
|
||||
socket_t ftpCreateServerSocket(void)
|
||||
{
|
||||
int theServer;
|
||||
struct sockaddr_in serverinfo;
|
||||
unsigned len;
|
||||
|
||||
theServer = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(theServer < 0)
|
||||
return -1;
|
||||
|
||||
serverinfo.sin_family = AF_INET;
|
||||
serverinfo.sin_addr.s_addr = INADDR_ANY;
|
||||
serverinfo.sin_port = htons(61358);
|
||||
len = sizeof(serverinfo);
|
||||
|
||||
if(bind(theServer, (struct sockaddr *)&serverinfo, len))
|
||||
{
|
||||
ftpCloseSocket(theServer);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if(listen(theServer, 3))
|
||||
{
|
||||
ftpCloseSocket(theServer);
|
||||
return -3;
|
||||
}
|
||||
|
||||
return (socket_t)theServer;
|
||||
}
|
||||
|
||||
socket_t ftpAcceptServerConnection(socket_t server, ip_t *remoteIP, port_t *remotePort)
|
||||
{
|
||||
struct sockaddr_in sockinfo;
|
||||
socket_t clientSocket;
|
||||
unsigned len;
|
||||
|
||||
len = sizeof(sockinfo);
|
||||
|
||||
clientSocket = accept(server, (struct sockaddr *)&sockinfo, &len);
|
||||
*remoteIP = ntohl(sockinfo.sin_addr.s_addr);
|
||||
*remotePort = ntohs(sockinfo.sin_port);
|
||||
|
||||
if(!ownIp) // kennen wir schon die eigene IP?
|
||||
{
|
||||
len = sizeof(sockinfo);
|
||||
if(getsockname(clientSocket, (struct sockaddr *)&sockinfo, &len))
|
||||
{
|
||||
#if DBG_LOG
|
||||
printf("getsockname error\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
ownIp = ntohl(sockinfo.sin_addr.s_addr); // eigene IP-Adresse abspeichern (wird dir PASV benätigt)
|
||||
}
|
||||
#if DBG_LOG
|
||||
printf("Verbindung mit %s auf Port %d akzeptiert.\n", inet_ntoa(sockinfo.sin_addr), *remotePort);
|
||||
#endif
|
||||
return clientSocket;
|
||||
}
|
||||
|
||||
int ftpTrackSocket(socket_t s)
|
||||
{
|
||||
if(s > maxSockNr)
|
||||
maxSockNr = s;
|
||||
FD_SET(s, &watchedSockets);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftpUntrackSocket(socket_t s)
|
||||
{
|
||||
FD_CLR(s, &watchedSockets);
|
||||
// TODO hier sollte eine Möglichkeit geschaffen werden um maxSockNr anzupassen
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftpTestSocket(socket_t s)
|
||||
{
|
||||
return FD_ISSET(s, &signaledSockets);
|
||||
}
|
||||
|
||||
int ftpSelect(int poll)
|
||||
{
|
||||
signaledSockets = watchedSockets;
|
||||
|
||||
if(poll)
|
||||
{
|
||||
struct timeval t = {0};
|
||||
return select(maxSockNr+1, &signaledSockets, NULL, NULL, &t);
|
||||
}
|
||||
else
|
||||
return select(maxSockNr+1, &signaledSockets, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
#endif
|
420
source/shared_lib/sources/feathery_ftp/ftpTargetWin32.c
Normal file
420
source/shared_lib/sources/feathery_ftp/ftpTargetWin32.c
Normal file
@@ -0,0 +1,420 @@
|
||||
/* FEATHERY FTP-Server
|
||||
* Copyright (C) 2005-2010 Andreas Martin (andreas.martin@linuxmail.org)
|
||||
* <https://sourceforge.net/projects/feathery>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "ftpTypes.h"
|
||||
#include "ftpConfig.h"
|
||||
#include "ftp.h"
|
||||
|
||||
#pragma comment(lib, "ws2_32")
|
||||
#pragma comment(lib, "MSWSOCK")
|
||||
|
||||
ip_t ownIp;
|
||||
|
||||
LOCAL fd_set watchedSockets;
|
||||
LOCAL fd_set signaledSockets;
|
||||
LOCAL int maxSockNr;
|
||||
|
||||
void ftpArchInit(void)
|
||||
{
|
||||
WSADATA wsaData;
|
||||
ownIp = 0;
|
||||
maxSockNr = 0;
|
||||
FD_ZERO(&watchedSockets);
|
||||
WSAStartup(MAKEWORD(2, 0),&wsaData);
|
||||
}
|
||||
|
||||
void ftpArchCleanup(void)
|
||||
{
|
||||
WSACleanup(); // WINSOCK freigeben
|
||||
}
|
||||
|
||||
int ftpGetLocalTime(ftpTime_S *t)
|
||||
{
|
||||
struct tm *pTime;
|
||||
time_t tim;
|
||||
|
||||
time(&tim);
|
||||
pTime = localtime(&tim);
|
||||
if(pTime)
|
||||
{
|
||||
t->year = (uint16_t)pTime->tm_year + 1900;
|
||||
t->month = (uint8_t)pTime->tm_mon + 1;
|
||||
t->day = (uint8_t)pTime->tm_mday;
|
||||
t->hour = (uint8_t)pTime->tm_hour;
|
||||
t->minute = (uint8_t)pTime->tm_min;
|
||||
t->second = (uint8_t)pTime->tm_sec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE findHandle;
|
||||
char path[MAX_PATH_LEN];
|
||||
}readDir_S;
|
||||
|
||||
void* ftpOpenDir(const char* path)
|
||||
{
|
||||
readDir_S* p = malloc(sizeof(readDir_S));
|
||||
|
||||
if(p)
|
||||
{
|
||||
p->findHandle = INVALID_HANDLE_VALUE;
|
||||
strcpy(p->path, path);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
const char* ftpReadDir(void* dirHandle)
|
||||
{
|
||||
WIN32_FIND_DATA findData;
|
||||
readDir_S* p = dirHandle;
|
||||
|
||||
if(dirHandle == NULL)
|
||||
return NULL;
|
||||
|
||||
if(p->findHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if(strcmp(p->path, "/"))
|
||||
strcat(p->path, "/*");
|
||||
else
|
||||
strcat(p->path, "*");
|
||||
|
||||
p->findHandle = FindFirstFile(p->path, &findData);
|
||||
if(p->findHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
strcpy(p->path, findData.cFileName);
|
||||
return p->path;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(FindNextFile(p->findHandle, &findData))
|
||||
{
|
||||
strcpy(p->path, findData.cFileName);
|
||||
return p->path;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ftpCloseDir(void* dirHandle)
|
||||
{
|
||||
readDir_S* p = dirHandle;
|
||||
|
||||
if(dirHandle)
|
||||
{
|
||||
FindClose(p->findHandle);
|
||||
free(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftpStat(const char* path, ftpPathInfo_S *info)
|
||||
{
|
||||
struct stat fileInfo = {0};
|
||||
struct tm *pTime;
|
||||
|
||||
if(!stat(path, &fileInfo))
|
||||
{
|
||||
if(fileInfo.st_mode & _S_IFREG)
|
||||
info->type = TYPE_FILE;
|
||||
else if(fileInfo.st_mode & _S_IFDIR)
|
||||
info->type = TYPE_DIR;
|
||||
else
|
||||
info->type = TYPE_LINK;
|
||||
|
||||
pTime = localtime(&fileInfo.st_mtime);
|
||||
if(pTime)
|
||||
{
|
||||
info->mTime.year = (uint16_t)pTime->tm_year + 1900;
|
||||
info->mTime.month = (uint8_t)pTime->tm_mon + 1;
|
||||
info->mTime.day = (uint8_t)pTime->tm_mday;
|
||||
info->mTime.hour = (uint8_t)pTime->tm_hour;
|
||||
info->mTime.minute = (uint8_t)pTime->tm_min;
|
||||
info->mTime.second = (uint8_t)pTime->tm_sec;
|
||||
}
|
||||
pTime = localtime(&fileInfo.st_ctime);
|
||||
if(pTime)
|
||||
{
|
||||
info->cTime.year = (uint16_t)pTime->tm_year + 1900;
|
||||
info->cTime.month = (uint8_t)pTime->tm_mon + 1;
|
||||
info->cTime.day = (uint8_t)pTime->tm_mday;
|
||||
info->cTime.hour = (uint8_t)pTime->tm_hour;
|
||||
info->cTime.minute = (uint8_t)pTime->tm_min;
|
||||
info->cTime.second = (uint8_t)pTime->tm_sec;
|
||||
}
|
||||
pTime = localtime(&fileInfo.st_atime);
|
||||
if(pTime)
|
||||
{
|
||||
info->aTime.year = (uint16_t)pTime->tm_year + 1900;
|
||||
info->aTime.month = (uint8_t)pTime->tm_mon + 1;
|
||||
info->aTime.day = (uint8_t)pTime->tm_mday;
|
||||
info->aTime.hour = (uint8_t)pTime->tm_hour;
|
||||
info->aTime.minute = (uint8_t)pTime->tm_min;
|
||||
info->aTime.second = (uint8_t)pTime->tm_sec;
|
||||
}
|
||||
|
||||
info->size = (uint32_t)fileInfo.st_size;
|
||||
info->links = (int)fileInfo.st_nlink;
|
||||
|
||||
strncpy(info->user, "ftp", sizeof(info->user));
|
||||
strncpy(info->group, "ftp", sizeof(info->group));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ftpMakeDir(const char* path)
|
||||
{
|
||||
|
||||
return !CreateDirectory(path, NULL);
|
||||
}
|
||||
|
||||
int ftpRemoveDir(const char* path)
|
||||
{
|
||||
return !RemoveDirectory(path);
|
||||
}
|
||||
|
||||
|
||||
int ftpCloseSocket(socket_t s)
|
||||
{
|
||||
return closesocket((SOCKET)s);
|
||||
}
|
||||
|
||||
int ftpSend(socket_t s, const void *data, int len)
|
||||
{
|
||||
int currLen = 0;
|
||||
|
||||
do
|
||||
{
|
||||
currLen = send((SOCKET)s, data, len, 0);
|
||||
if(currLen >= 0)
|
||||
{
|
||||
len -= currLen;
|
||||
data = (uint8_t*)data + currLen;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
}while(len > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftpReceive(socket_t s, void *data, int len)
|
||||
{
|
||||
return recv(s, data, len, 0);
|
||||
}
|
||||
|
||||
socket_t ftpEstablishDataConnection(int passive, ip_t *ip, port_t *port)
|
||||
{
|
||||
SOCKET dataSocket;
|
||||
struct sockaddr_in clientAddr;
|
||||
struct sockaddr_in myAddr;
|
||||
BOOL on = 1;
|
||||
unsigned len;
|
||||
dataSocket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(dataSocket < 0)
|
||||
return -1;
|
||||
|
||||
if(!passive)
|
||||
{
|
||||
if(setsockopt(dataSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)))
|
||||
{
|
||||
closesocket(dataSocket);
|
||||
return -1;
|
||||
}
|
||||
myAddr.sin_family = AF_INET;
|
||||
myAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
myAddr.sin_port = htons(20);
|
||||
if(bind(dataSocket, (struct sockaddr *)&myAddr, sizeof(myAddr)))
|
||||
{
|
||||
closesocket(dataSocket);
|
||||
return -1;
|
||||
}
|
||||
clientAddr.sin_family = AF_INET;
|
||||
clientAddr.sin_addr.s_addr = htonl(*ip);
|
||||
clientAddr.sin_port = htons(*port);
|
||||
if(connect(dataSocket, (struct sockaddr *)&clientAddr, sizeof(clientAddr)))
|
||||
{
|
||||
closesocket(dataSocket);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
myAddr.sin_family = AF_INET;
|
||||
myAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
myAddr.sin_port = htons(0);
|
||||
if(bind(dataSocket, (struct sockaddr *)&myAddr, sizeof(myAddr)))
|
||||
{
|
||||
closesocket(dataSocket);
|
||||
return -1;
|
||||
}
|
||||
len = sizeof(myAddr);
|
||||
if(getsockname(dataSocket, (struct sockaddr *)&myAddr, &len)) // Port des Server-Sockets ermitteln
|
||||
{
|
||||
closesocket(dataSocket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*port = ntohs(myAddr.sin_port);
|
||||
*ip = ownIp;
|
||||
|
||||
if(listen(dataSocket, 1))
|
||||
{
|
||||
closesocket(dataSocket);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return (socket_t)dataSocket;
|
||||
}
|
||||
|
||||
socket_t ftpAcceptDataConnection(socket_t listner)
|
||||
{
|
||||
struct sockaddr_in clientinfo;
|
||||
unsigned len;
|
||||
SOCKET dataSocket;
|
||||
|
||||
len = sizeof(clientinfo);
|
||||
|
||||
dataSocket = accept(listner, (struct sockaddr *)&clientinfo, &len);
|
||||
if(dataSocket < 0)
|
||||
dataSocket = -1;
|
||||
|
||||
closesocket(listner); // Server-Socket wird nicht mehr gebrauch deshalb schließen
|
||||
return (socket_t)dataSocket;
|
||||
}
|
||||
|
||||
socket_t ftpCreateServerSocket(void)
|
||||
{
|
||||
SOCKET theServer;
|
||||
struct sockaddr_in serverinfo;
|
||||
unsigned len;
|
||||
|
||||
theServer = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(theServer < 0)
|
||||
return -1;
|
||||
|
||||
serverinfo.sin_family = AF_INET;
|
||||
serverinfo.sin_addr.s_addr = INADDR_ANY;
|
||||
serverinfo.sin_port = htons(21);
|
||||
len = sizeof(serverinfo);
|
||||
|
||||
int val = 1;
|
||||
#ifndef WIN32
|
||||
setsockopt(theServer, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||
#else
|
||||
setsockopt(theServer, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
|
||||
#endif
|
||||
|
||||
if(bind(theServer, (struct sockaddr *)&serverinfo, len))
|
||||
{
|
||||
ftpCloseSocket(theServer);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if(listen(theServer, 3))
|
||||
{
|
||||
ftpCloseSocket(theServer);
|
||||
return -3;
|
||||
}
|
||||
|
||||
return (socket_t)theServer;
|
||||
}
|
||||
|
||||
socket_t ftpAcceptServerConnection(socket_t server, ip_t *remoteIP, port_t *remotePort)
|
||||
{
|
||||
struct sockaddr_in sockinfo;
|
||||
socket_t clientSocket;
|
||||
int len;
|
||||
|
||||
len = sizeof(sockinfo);
|
||||
|
||||
clientSocket = accept(server, (struct sockaddr *)&sockinfo, &len);
|
||||
*remoteIP = ntohl(sockinfo.sin_addr.s_addr);
|
||||
*remotePort = ntohs(sockinfo.sin_port);
|
||||
|
||||
if(!ownIp) // kennen wir schon die eigene IP?
|
||||
{
|
||||
len = sizeof(sockinfo);
|
||||
if(getsockname(clientSocket, (struct sockaddr *)&sockinfo, &len))
|
||||
{
|
||||
#if DBG_LOG
|
||||
printf("getsockname error\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
ownIp = ntohl(sockinfo.sin_addr.s_addr); // eigene IP-Adresse abspeichern (wird dir PASV benätigt)
|
||||
}
|
||||
#if DBG_LOG
|
||||
printf("Verbindung mit %s auf Port %d akzeptiert.\n", inet_ntoa(sockinfo.sin_addr), *remotePort);
|
||||
#endif
|
||||
return clientSocket;
|
||||
}
|
||||
|
||||
int ftpTrackSocket(socket_t s)
|
||||
{
|
||||
if(s > maxSockNr)
|
||||
maxSockNr = s;
|
||||
FD_SET(s, &watchedSockets);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftpUntrackSocket(socket_t s)
|
||||
{
|
||||
FD_CLR((SOCKET)s, &watchedSockets);
|
||||
// TODO hier sollte eine Möglichkeit geschaffen werden um maxSockNr anzupassen
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftpTestSocket(socket_t s)
|
||||
{
|
||||
return FD_ISSET(s, &signaledSockets);
|
||||
}
|
||||
|
||||
int ftpSelect(int poll)
|
||||
{
|
||||
signaledSockets = watchedSockets;
|
||||
|
||||
if(poll)
|
||||
{
|
||||
struct timeval t = {0};
|
||||
return select(maxSockNr+1, &signaledSockets, NULL, NULL, &t);
|
||||
}
|
||||
else
|
||||
return select(maxSockNr+1, &signaledSockets, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user