FTPDaemonCore.cpp
上传用户:surprise9
上传日期:2007-01-04
资源大小:426k
文件大小:56k
源码类别:

Ftp客户端

开发平台:

Visual C++

  1. // This is part of the WAR SOFTWARE SERIES initiated by Jarle Aase
  2. // Copyright 1996 by Jarle Aase. All rights reserved.
  3. // See the "War Software Series Licende Agreement" for details concerning 
  4. // use and distribution.
  5. // ---
  6. // This source code, executables and programs containing source code or
  7. // binaries or proprietetary technology from the War Software Series are
  8. // NOT alloed used, viewed or tested by any governmental agencies in
  9. // any countries. This includes the government, departments, police, 
  10. // military etc.
  11. // ---
  12. // This file is intended for use with Tab space = 2
  13. // Created and maintained in MSVC Developer Studio
  14. // ---
  15. // NAME : FTPDaemonCore.cpp
  16. // PURPOSE : Basic FTP Daemon classes
  17. // PROGRAM : 
  18. // DATE : Sept. 27 1996
  19. // AUTHOR : Jarle Aase
  20. // ---
  21. // REVISION HISTORY
  22. // 
  23. #include "stdafx.h"
  24. #define FTP_NAMES
  25. #include "ftp.h"
  26. #include "FTPDaemonCore.h"
  27. #include "Unix.h"
  28. #ifdef _DEBUG
  29. #define new DEBUG_NEW
  30. #undef THIS_FILE
  31. static char THIS_FILE[] = __FILE__;
  32. #endif
  33. ////////////////////////////////////////////////////////////////////
  34. // FTPD Command parser
  35. enum // Token ID's
  36. {
  37. TOK_USER = TOK_START_TAB,     TOK_PASS, TOK_ACCT, TOK_REIN, TOK_XCUP,
  38. TOK_PORT, TOK_PASV, TOK_TYPE, TOK_STRU, TOK_MODE, TOK_RETR, TOK_STOR, 
  39. TOK_APPE, TOK_MLFL, TOK_MAIL, TOK_MSND, TOK_MSOM, TOK_MSAM, TOK_MRSQ, 
  40. TOK_MRCP, TOK_ALLO, TOK_REST, TOK_RNFR, TOK_RNTO, TOK_ABOR, TOK_DELE, 
  41. TOK_CWD,  TOK_LIST, TOK_NLST, TOK_SITE, TOK_STAT, TOK_XCWD, TOK_XMKD,
  42. TOK_HELP, TOK_NOOP, TOK_MKD,  TOK_RMD,  TOK_PWD,  TOK_CDUP, TOK_STOU, 
  43. TOK_SMNT, TOK_SYST, TOK_SIZE, TOK_MDTM, TOK_XRMD, TOK_XPWD, TOK_QUIT,
  44. // SITE
  45. TOK_CHMOD, TOK_CHOWN, TOK_CHGRP, TOK_CHCMT, TOK_FSYSSTAT,
  46. };
  47. // Command tokens
  48. static STokenTab BaseTokens[] =
  49. {
  50. {TOK_QUIT, "QUIT" },
  51. {TOK_USER, "USER" },
  52. {TOK_PASS, "PASS" },
  53. {TOK_ACCT, "ACCT" },
  54. {TOK_REIN, "REIN" },
  55. {TOK_QUIT, "QUIT" },
  56. {TOK_PORT, "PORT" },
  57. {TOK_PASV, "PASV" },
  58. {TOK_TYPE, "TYPE" },
  59. {TOK_STRU, "STRU" },
  60. {TOK_MODE, "MODE" },
  61. {TOK_RETR, "RETR" },
  62. {TOK_STOR, "STOR" },
  63. {TOK_APPE, "APPE" },
  64. {TOK_MLFL, "MLFL" },
  65. {TOK_MAIL, "MAIL" },
  66. {TOK_MSND, "MSND" },
  67. {TOK_MSOM, "MSOM" },
  68. {TOK_MSAM, "MSAM" },
  69. {TOK_MRSQ, "MRSQ" },
  70. {TOK_MRCP, "MRCP" },
  71. {TOK_ALLO, "ALLO" },
  72. {TOK_REST, "REST" },
  73. {TOK_RNFR, "RNFR" },
  74. {TOK_RNTO, "RNTO" },
  75. {TOK_ABOR, "ABOR" },
  76. {TOK_DELE, "DELE" },
  77. {TOK_CWD,  "CWD" },
  78. {TOK_XCWD, "XCWD" },
  79. {TOK_LIST, "LIST" },
  80. {TOK_NLST, "NLST" },
  81. {TOK_SITE, "SITE" },
  82. {TOK_STAT, "STAT" },
  83. {TOK_HELP, "HELP" },
  84. {TOK_NOOP, "NOOP" },
  85. {TOK_MKD,  "MKD" },
  86. {TOK_RMD,  "RMD" },
  87. {TOK_PWD,  "PWD" },
  88. {TOK_XMKD, "XMKD" },
  89. {TOK_XRMD, "XRMD" },
  90. {TOK_XPWD, "XPWD" },
  91. {TOK_CDUP, "CDUP" },
  92. {TOK_XCUP, "XCUP" },
  93. {TOK_STOU, "STOU" },
  94. {TOK_SMNT, "SMNT" },
  95. {TOK_SYST, "SYST" },
  96. {TOK_SIZE, "SIZE" },
  97. {TOK_MDTM, "MDTM" },
  98. // SITE
  99. {TOK_CHMOD,"CHMOD"},
  100. {TOK_CHOWN,"CHOWN"},
  101. {TOK_CHGRP,"CHGRP"},
  102. {TOK_CHCMT,"CHCMT"},
  103. {TOK_FSYSSTAT,"FSYSSTAT"},
  104. {TOK_INVALID, "" }
  105. };
  106. enum // Commands recognized on this level
  107. {
  108. CMD_USER = CMD_START_TREE,    CMD_PASS, CMD_ACCT, CMD_REIN, CMD_QUIT, 
  109. CMD_PORT, CMD_PASV, CMD_TYPE, CMD_STRU, CMD_MODE, CMD_RETR, CMD_STOR, 
  110. CMD_APPE, CMD_MLFL, CMD_MAIL, CMD_MSND, CMD_MSOM, CMD_MSAM, CMD_MRSQ, 
  111. CMD_MRCP, CMD_ALLO, CMD_REST, CMD_RNFR, CMD_RNTO, CMD_ABOR, CMD_DELE, 
  112. CMD_CWD,  CMD_LIST, CMD_NLST, CMD_SITE, CMD_STAT,  
  113. CMD_HELP, CMD_NOOP, CMD_MKD,  CMD_RMD,  CMD_PWD,  CMD_CDUP, CMD_STOU, 
  114. CMD_SMNT, CMD_SYST, CMD_SIZE, CMD_MDTM,
  115. // SITE
  116. CMD_CHMOD, CMD_CHGRP, CMD_CHOWN, CMD_CHCMT, CMD_FSYSSTAT,
  117. };
  118. static SCommandTree SiteCmds[] =
  119. {
  120. {TOK_CHMOD, CMD_CHMOD, PROCESS,  CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "SITE CHMOD <sp> mode <sp> file ..." },
  121. {TOK_CHOWN, CMD_CHOWN, PROCESS,  CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "SITE CHOWN <sp> user <sp> file..." },
  122. {TOK_CHGRP, CMD_CHGRP, PROCESS,  CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "SITE CHGRP <sp> class <sp> file..." },
  123. {TOK_CHCMT, CMD_CHCMT, PROCESS,  CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "SITE CHCMT <sp> "comment" <sp> file..."},
  124. {TOK_FSYSSTAT, CMD_FSYSSTAT, PROCESS, CMDF_NOPARAM,  NULL, ' ', LEX_WANT_CMD, "SITE FSYSSTAT"},
  125. {TOK_INVALID, CMD_INVALID, 0,  0,  NULL, 0,   0,             NULL}
  126. };
  127. // Command tree
  128. static SCommandTree BaseCmds[] =
  129. {
  130. {TOK_USER, CMD_USER, PRELOGIN, CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "USER <sp> username"},
  131. {TOK_PASS, CMD_PASS, GOTNAME,  CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "PASS <sp> password" },
  132. {TOK_QUIT, CMD_QUIT, PRELOGIN, 0,  NULL, ' ', LEX_WANT_CMD, "QUIT (end session)" },
  133. {TOK_ACCT, CMD_ACCT, PROCESS,  CMDF_NOT_IMPLEMENTED, NULL, ' ', LEX_WANT_CMD, "ACCT (specify account)" },
  134. {TOK_REIN, CMD_REIN, PROCESS,  CMDF_NOT_IMPLEMENTED, NULL, ' ', LEX_WANT_CMD, "REIN (reinitialize server state)" },
  135. {TOK_PORT, CMD_PORT, PRELOGIN, CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "PORT <sp> b0, b1, b2, b3, b4" },
  136. {TOK_PASV, CMD_PASV, PRELOGIN, CMDF_NOPARAM,         NULL, ' ', LEX_WANT_CMD, "PASV (set server in passive mode)" },
  137. {TOK_TYPE, CMD_TYPE, PRELOGIN, CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "TYPE <sp> [ A | E | I | L ]" },
  138. {TOK_STRU, CMD_STRU, PROCESS,  CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "STRU (specify file structure)" },
  139. {TOK_MODE, CMD_MODE, PRELOGIN, CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "MODE (specify transfer mode)" },
  140. {TOK_RETR, CMD_RETR, PROCESS,  CMDF_PARAMETER|CMDF_PARSE_CMD_LINE,       NULL, ' ', LEX_WANT_CMD, "RETR <sp> file-name" },
  141. {TOK_STOR, CMD_STOR, PROCESS,  CMDF_PARAMETER|CMDF_PARSE_CMD_LINE,       NULL, ' ', LEX_WANT_CMD, "STOR <sp> file-name" },
  142. {TOK_APPE, CMD_APPE, PROCESS,  CMDF_PARAMETER|CMDF_PARSE_CMD_LINE,       NULL, ' ', LEX_WANT_CMD, "APPE <sp> file-name" },
  143. {TOK_MLFL, CMD_MLFL, PROCESS,  CMDF_NOT_IMPLEMENTED, NULL, ' ', LEX_WANT_CMD, "MLFL (mail file)" },
  144. {TOK_MAIL, CMD_MAIL, PROCESS,  CMDF_NOT_IMPLEMENTED, NULL, ' ', LEX_WANT_CMD, "MAIL (mail to user)" },
  145. {TOK_MSND, CMD_MSND, PROCESS,  CMDF_NOT_IMPLEMENTED, NULL, ' ', LEX_WANT_CMD, "MSND (mail send to terminal)" },
  146. {TOK_MSOM, CMD_MSOM, PROCESS,  CMDF_NOT_IMPLEMENTED, NULL, ' ', LEX_WANT_CMD, "MSOM (mail send to terminal or mailbox)" },
  147. {TOK_MSAM, CMD_MSAM, PROCESS,  CMDF_NOT_IMPLEMENTED, NULL, ' ', LEX_WANT_CMD, "MSAM (mail send to terminal and mailbox)" },
  148. {TOK_MRSQ, CMD_MRSQ, PROCESS,  CMDF_NOT_IMPLEMENTED, NULL, ' ', LEX_WANT_CMD, "MRSQ (mail recipient scheme question)" },
  149. {TOK_MRCP, CMD_MRCP, PROCESS,  CMDF_NOT_IMPLEMENTED, NULL, ' ', LEX_WANT_CMD, "MRCP (mail recipient)" },
  150. {TOK_ALLO, CMD_ALLO, PROCESS,  CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "ALLO <sp> bytes" },
  151. {TOK_REST, CMD_REST, PRELOGIN, CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "REST <sp> byte offset" },
  152. {TOK_RNFR, CMD_RNFR, PROCESS,  CMDF_PARAMETER|CMDF_PARSE_CMD_LINE,       NULL, ' ', LEX_WANT_CMD, "RNFR <sp> file-name" },
  153. {TOK_RNTO, CMD_RNTO, PROCESS,  CMDF_PARAMETER|CMDF_PARSE_CMD_LINE,       NULL, ' ', LEX_WANT_CMD, "RNTO <sp> file-name" },
  154. {TOK_ABOR, CMD_ABOR, PROCESS,  0,                    NULL, ' ', LEX_WANT_CMD, "(abort operation)" },
  155. {TOK_DELE, CMD_DELE, PROCESS,  CMDF_PARAMETER|CMDF_PARSE_CMD_LINE,       NULL, ' ', LEX_WANT_CMD, "DELE <sp> file-name" },
  156. {TOK_CWD,  CMD_CWD,  PROCESS,  CMDF_PARSE_CMD_LINE,                    NULL, ' ', LEX_WANT_CMD, "CWD [ <sp> directory-name ]" },
  157. {TOK_XCWD, CMD_CWD,  PROCESS,  CMDF_PARSE_CMD_LINE,                    NULL, ' ', LEX_WANT_CMD, "XCWD [ <sp> directory-name ]" },
  158. {TOK_LIST, CMD_LIST, PROCESS,  CMDF_PARSE_CMD_LINE,                    NULL, ' ', LEX_WANT_CMD, "LIST [ <sp> path-name ]" },
  159. {TOK_NLST, CMD_NLST, PROCESS,  CMDF_PARSE_CMD_LINE,                    NULL, ' ', LEX_WANT_CMD, "NLST [ <sp> path-name ]" },
  160. {TOK_SITE, CMD_SITE, PRELOGIN, CMDF_PARAMETER,       SiteCmds, ' ', LEX_WANT_CMD, "SITE site-cmd [ <sp> arguments ]" },
  161. {TOK_STAT, CMD_STAT, PROCESS,  0,                    NULL, ' ', LEX_WANT_CMD, "STAT [ <sp> path-name ]" },
  162. {TOK_HELP, CMD_HELP, PRELOGIN, 0,                    NULL, ' ', LEX_WANT_CMD, "HELP [ <sp> <string> ]" },
  163. {TOK_NOOP, CMD_NOOP, PRELOGIN, CMDF_NOPARAM,         NULL, ' ', LEX_WANT_CMD, "NOOP (no operation)" },
  164. {TOK_MKD,  CMD_MKD,  PROCESS,  CMDF_PARAMETER|CMDF_PARSE_CMD_LINE,       NULL, ' ', LEX_WANT_CMD, "MKD <sp> path-name" },
  165. {TOK_XMKD, CMD_MKD,  PROCESS,  CMDF_PARAMETER|CMDF_PARSE_CMD_LINE,       NULL, ' ', LEX_WANT_CMD, "XMKD <sp> path-name" },
  166. {TOK_RMD,  CMD_RMD,  PROCESS,  CMDF_PARAMETER|CMDF_PARSE_CMD_LINE,       NULL, ' ', LEX_WANT_CMD, "RMD <sp> path-name" },
  167. {TOK_XRMD, CMD_RMD,  PROCESS,  CMDF_PARAMETER|CMDF_PARSE_CMD_LINE,       NULL, ' ', LEX_WANT_CMD, "XRMD <sp> path-name" },
  168. {TOK_PWD,  CMD_PWD,  PROCESS,  CMDF_NOPARAM,         NULL, ' ', LEX_WANT_CMD, "PWD (return current directory)" },
  169. {TOK_XPWD, CMD_PWD,  PROCESS,  CMDF_NOPARAM,         NULL, ' ', LEX_WANT_CMD, "XPWD (return current directory)" },
  170. {TOK_CDUP, CMD_CDUP, PROCESS,  0,                    NULL, ' ', LEX_WANT_CMD, "CDUP (change to parent directory)" },
  171. {TOK_XCUP, CMD_CDUP, PROCESS,  0,                    NULL, ' ', LEX_WANT_CMD, "CDUP (change to parent directory)" },
  172. {TOK_STOU, CMD_STOU, PROCESS,  CMDF_PARAMETER,       NULL, ' ', LEX_WANT_CMD, "STOU <sp> file-name" },
  173. {TOK_SMNT, CMD_SMNT, PROCESS,  CMDF_NOT_IMPLEMENTED, NULL, ' ', LEX_WANT_CMD, "SMNT (structure mount)" },
  174. {TOK_SYST, CMD_SYST, PRELOGIN, CMDF_NOPARAM,        NULL, ' ', LEX_WANT_CMD, "SYST (get type of operating system)" },
  175. {TOK_SIZE, CMD_SIZE, PROCESS,  CMDF_PARAMETER|CMDF_PARSE_CMD_LINE,       NULL, ' ', LEX_WANT_CMD, "SIZE <sp> path-name" },
  176. {TOK_MDTM, CMD_MDTM, PROCESS,  CMDF_PARAMETER|CMDF_PARSE_CMD_LINE,       NULL, ' ', LEX_WANT_CMD, "MDTM <sp> path-name" },
  177. {TOK_INVALID, CMD_INVALID, 0,  0,                    NULL, 0,   0,             NULL}
  178. };
  179. CFTPDParser::CFTPDParser()
  180. {
  181. m_Commands = (SCommandTree *) BaseCmds;
  182. m_Tokens = (STokenTab *) BaseTokens;
  183. }
  184. // The FTP protocol command interface is fairly simple.
  185. // We don't call the regular CCmdParser::ParseCmd() but do the parsing
  186. // ourself.
  187. int CFTPDParser::ParseCmd(LPCSTR CmdLine, CCmdArgs& Args, int Level, BOOL& DoParseCmdLine)
  188. {
  189. int TokenID;
  190. LPCSTR LexCmdLine = CmdLine;
  191. SCommandTreeDef *CmdPtr = m_Commands;
  192. again:
  193. TokenID = yyLex(&LexCmdLine, m_Tokens, ' ', LEX_WANT_CMD, Args);
  194. if (TokenID < TOK_START_TAB)
  195. return CMD_PARSE_ERROR; // Error
  196. // Find the command ID
  197. while(CmdPtr && (CmdPtr->TokenID != TokenID) && (CmdPtr->TokenID != TOK_INVALID))
  198. ++CmdPtr;
  199. if (!CmdPtr)
  200. return CMD_UNKNOWN_COMMAND;
  201. if (CmdPtr->NextLevel)
  202. {
  203. ASSERT(CmdPtr->CommandID == CMD_SITE);
  204. CmdPtr = CmdPtr->NextLevel;
  205. goto again;
  206. }
  207. // Try to get parameter
  208. TokenID = yyLex(&LexCmdLine, m_Tokens, 0, LEX_WANT_STRING, Args);
  209. // Check for login level and availibility
  210. if (CmdPtr->AccessLevel > Level)
  211. return CMD_BAD_LEVEL;
  212. // Check for required parameter
  213. if ((CmdPtr->Flags & CMDF_PARAMETER)
  214. && (TokenID == TOK_END_OF_TOKENS))
  215. return CMD_MISSING_PARAMETER;
  216. // Check for no parameter
  217. if ((CmdPtr->Flags & CMDF_NOPARAM)
  218. && (TokenID != TOK_END_OF_TOKENS))
  219. return CMD_UNKNOWN_PARAMETER;
  220. // Is the command implemented?
  221. if (CmdPtr->Flags & CMDF_NOT_IMPLEMENTED)
  222. return CMD_NOT_IMPLEMENTED;
  223. DoParseCmdLine = (CmdPtr->Flags & CMDF_PARSE_CMD_LINE) != 0;
  224. return CmdPtr->CommandID;
  225. }
  226. ////////////////////////////////////////////////////////////////////
  227. // CFTPDaemonCore
  228. CFtpDaemonCore *CFtpDaemonCore::m_pCFtpDaemonCore = NULL;
  229. CFtpDaemonCore::CFtpDaemonCore()
  230. {
  231. m_pCFtpDaemonCore = this;
  232. }
  233. CFtpDaemonCore::~CFtpDaemonCore()
  234. {
  235. m_Options.SaveAll();
  236. CUserFsys::CloseFileSystem();
  237. m_pCFtpDaemonCore = NULL;
  238. }
  239. // Initialize and go online
  240. BOOL CFtpDaemonCore::Create(LPCSTR IniFile, CLog *Log)
  241. {
  242. m_Log = Log;
  243. m_Options.Create(NULL,IniFile,"FTPD", COPTION_FTPD_CORE);
  244. m_Options.LoadAll();
  245. // Start the file system
  246. if (!CUserFsys::FsysIsStarted())
  247. {
  248. if (!CUserFsys::StartFileSystem(NULL))
  249. return FALSE;
  250. }
  251. CDaemonBase::GetSvr()->RefreshStats();
  252. if (!m_Listen.Initialize(m_Options.m_Port, "FTP", m_Options.m_IPname))
  253. {
  254. return FALSE;
  255. }
  256. return TRUE;
  257. }
  258. void CFtpDaemonCore::LogMsg(int flag, LPCSTR Format, ...)
  259. {
  260. CString cBuf;
  261. if (!ShouldLog(m_Log, flag))
  262. return;
  263. ASSERT(AfxIsValidString(Format, FALSE));
  264. ASSERT(m_Log != NULL);
  265. ASSERT(AfxIsValidAddress(m_Log,sizeof(CLog)));
  266. cBuf.Format("FTPD: %s", Format);
  267. va_list argList;
  268. va_start(argList, Format);
  269. m_Log->LogMsgV(flag, cBuf, argList);
  270. va_end(argList);
  271. }
  272. /////////////////////////////////////////////////////////////////////////////////
  273. // FTP server listen socket
  274. void CFTPDCoreListenSock::OnAccept( int nErrorCode )
  275. {
  276. try
  277. {
  278. _OnAccept(nErrorCode);
  279. }
  280. catch(CSocketException *pExc)
  281. {
  282. LogMsg(LOGF_DEBUG,"CFTPDCoreListenSock::OnAccept(%d) - Caught exception '%s' from module %s",
  283. nErrorCode, pExc->m_ErrorText, pExc->m_ErrorText);
  284. if (!OnHandleWinsockErr(pExc->m_ErrorNum))
  285. delete this;
  286. delete pExc;
  287. }
  288. catch(...)
  289. {
  290. LogMsg(LOGF_ERROR,"CFTPDCoreListenSock::OnAccept(%d) - Caught unknown exception", nErrorCode);
  291. }
  292. }
  293. void CFTPDCoreListenSock::_OnAccept( int nErrorCode )
  294. {
  295. int err;
  296. CSock::OnAccept(nErrorCode);
  297. if (nErrorCode)
  298. return;
  299. CFTPDCoreCtrlSock *NewSocket = new CFTPDCoreCtrlSock;
  300. // EXT module
  301. if (err = PrcExt(CAPIHandler::OnPreFTPDAccept,0,(WPARAM)&NewSocket,(LPARAM)this))
  302. {
  303. if (err == CFuncList::AbortError)
  304. delete NewSocket;
  305. return;
  306. }
  307. try
  308. {
  309. if (!DoAccept(NewSocket))
  310. {
  311. delete NewSocket;
  312. return;
  313. }
  314. }
  315. catch(CSocketException *pExc)
  316. {
  317. if (pExc->m_pSock == NewSocket)
  318. {
  319. LogMsg(LOGF_DEBUG,"CFTPDCoreListenSock::_OnAccept(%d) - Caught exception '%s' from module %s. Connecting socket is being killed.",
  320. nErrorCode, pExc->m_ErrorText, pExc->m_ErrorText);
  321. delete NewSocket;
  322. delete pExc;
  323. return;
  324. }
  325. // Can't handle this here...
  326. throw pExc;
  327. }
  328. catch(...)
  329. {
  330. LogMsg(LOGF_ERROR,"CFTPDCoreListenSock::_OnAccept(%d) - Caught unknown exception", nErrorCode);
  331. return;
  332. }
  333. // EXT module
  334. if (err = PrcExt(CAPIHandler::OnPostFTPDAccept,0,(WPARAM)&NewSocket,(LPARAM)this))
  335. {
  336. if (err == CFuncList::AbortError)
  337. delete NewSocket;
  338. return;
  339. }
  340. // Intitialize connection
  341. NewSocket->EnableMacros();
  342. NewSocket->SendCtrlMsg(220,"[$systemname] ([$programname] [$programversion]) ready [%c][+sysmsg0.txt]");
  343. }
  344. BOOL CFTPDCoreListenSock::Initialize(int PortNumber, LPCSTR ServiceName, LPCSTR ListenIP)
  345. {
  346. if (!PortNumber)
  347. PortNumber = 21; // FTP
  348. if (!ServiceName)
  349. ServiceName = "FTP";
  350. m_Type = LT_FTP;
  351. BOOL IsOnline = CDaemonServiceSocket::Initialize(PortNumber,ServiceName, ListenIP);
  352. CDaemonStatusSvr::SetOnline(IsOnline);
  353. return IsOnline;
  354. }
  355. /////////////////////////////////////////////////////////////////////////////////
  356. // FTP server Control Socket
  357. // This is the FTP server module
  358. IMPLEMENT_DYNAMIC(CFTPDCoreCtrlSock, CTextSock);
  359. CFTPDCoreCtrlSock::CFTPDCoreCtrlSock()
  360. {
  361. SOCKADDR_IN *s_in = (SOCKADDR_IN *)&m_Sockaddr;
  362. m_ArgSave.Empty();
  363. m_Fsys = NULL;
  364. m_DataSock = NULL;
  365. // Set RFC 959 default values.
  366. m_FTPmode = MODE_S;
  367. m_FTPtype = TYPE_A;
  368. m_FTPstru = STRU_F;
  369. m_FTPform = FORM_N;
  370. memset(&m_Sockaddr, 0, sizeof(struct sockaddr));
  371. // Increase login counter
  372. CDaemonStatusSvr::IncUserCnt(TRUE);
  373. PrcExt(CAPIHandler::OnFTPDCoreCtrlSock,0,0,(LPARAM)this);
  374. }
  375. CFTPDCoreCtrlSock::~CFTPDCoreCtrlSock()
  376. {
  377. LogMsg(LOGF_DEBUG,"~CFTPDCoreCtrlSock() - %s.", m_DataSock ? "deleting data socket" : "no datasocket");
  378. if (m_DataSock)
  379. delete m_DataSock;
  380. //Log out from file system
  381. if (m_Fsys)
  382. m_Fsys->Logout();
  383. // Decrease login counter
  384. CDaemonStatusSvr::IncUserCnt(FALSE);
  385. }
  386. void CFTPDCoreCtrlSock::IncXferCnt(BOOL Add)
  387. {
  388. CDaemonStatusSvr::IncXferCnt(Add);
  389. }
  390. void CFTPDCoreCtrlSock::OnClose( int nErrorCode )
  391. {
  392. m_SuspendOnClose = TRUE; // Turn it on - just in case...
  393. try
  394. {
  395. CTextSock::OnClose(nErrorCode);
  396. CSocketException::Throw(this, "CFTPDCoreCtrlSock::OnClose()", nErrorCode, NULL);
  397. }
  398. catch(CSocketException *pExc)
  399. {
  400. LogMsg(LOGF_DEBUG,"CFTPDCoreCtrlSock::OnClose(%d) - Caught exception '%s' from module %s",
  401. nErrorCode, pExc->m_ErrorText, pExc->m_ErrorText);
  402. if (!OnHandleWinsockErr(pExc->m_ErrorNum))
  403. delete this;
  404. delete pExc;
  405. }
  406. catch(...)
  407. {
  408. LogMsg(LOGF_ERROR,"CFTPDCoreListenSock::OnClose(%d) - Caught unknown exception", nErrorCode);
  409. return;
  410. }
  411. }
  412. void CFTPDCoreCtrlSock::OnReceive( int nErrorCode )
  413. {
  414. try
  415. {
  416. CTextSock::OnReceive(nErrorCode);
  417. }
  418. catch(CSocketException *pExc)
  419. {
  420. LogMsg(LOGF_DEBUG,"CFTPDCoreCtrlSock::OnReceive(%d) - Caught exception '%s' from module %s",
  421. nErrorCode, pExc->m_ErrorText, pExc->m_ErrorText);
  422. if (!OnHandleWinsockErr(pExc->m_ErrorNum))
  423. delete this;
  424. delete pExc;
  425. }
  426. catch(...)
  427. {
  428. LogMsg(LOGF_ERROR,"CFTPDCoreListenSock::OnReceive(%d) - Caught unknown exception", nErrorCode);
  429. return;
  430. }
  431. }
  432. void CFTPDCoreCtrlSock::OnSend( int nErrorCode )
  433. {
  434. try
  435. {
  436. CTextSock::OnSend(nErrorCode);
  437. }
  438. catch(CSocketException *pExc)
  439. {
  440. LogMsg(LOGF_DEBUG,"CFTPDCoreCtrlSock::OnSend(%d) - Caught exception '%s' from module %s",
  441. nErrorCode, pExc->m_ErrorText, pExc->m_ErrorText);
  442. if (!OnHandleWinsockErr(pExc->m_ErrorNum))
  443. delete this;
  444. delete pExc;
  445. }
  446. catch(...)
  447. {
  448. LogMsg(LOGF_ERROR,"CFTPDCoreListenSock::OnSend(%d) - Caught unknown exception", nErrorCode);
  449. return;
  450. }
  451. }
  452. void CFTPDCoreCtrlSock::OnConnect( int nErrorCode )
  453. {
  454. try
  455. {
  456. _OnConnect(nErrorCode);
  457. }
  458. catch(CSocketException *pExc)
  459. {
  460. LogMsg(LOGF_DEBUG,"CFTPDCoreCtrlSock::OnConnect(%d) - Caught exception '%s' from module %s",
  461. nErrorCode, pExc->m_ErrorText, pExc->m_ErrorText);
  462. if (!OnHandleWinsockErr(pExc->m_ErrorNum))
  463. delete this;
  464. delete pExc;
  465. return;
  466. }
  467. catch(...)
  468. {
  469. LogMsg(LOGF_ERROR,"CFTPDCoreListenSock::OnConnect(%d) - Caught unknown exception", nErrorCode);
  470. return;
  471. }
  472. SetIdleTime(1000 * 60 * 3); // 3 minuts idle time on login
  473. m_Timer.Reset();
  474. }
  475. void CFTPDCoreCtrlSock::_OnConnect( int nErrorCode )
  476. {
  477. CTextSock::OnConnect(nErrorCode);
  478. // Initialize the sockaddr
  479. ASSERT(CFtpDaemonCore::m_pCFtpDaemonCore != NULL);
  480. SOCKADDR_IN *s_in = (SOCKADDR_IN *)&m_Sockaddr;
  481. int Len = sizeof(struct sockaddr);
  482. GetPeerName(&m_Sockaddr,&Len);
  483. s_in->sin_family = AF_INET;
  484. s_in->sin_port = htons(CFtpDaemonCore::m_pCFtpDaemonCore->m_Options.m_Port);
  485. }
  486. void CFTPDCoreCtrlSock::Virgin()
  487. {
  488. CTextSock::Virgin();
  489. }
  490. BOOL CFTPDCoreCtrlSock::ProcessTelnetNegotiation(int ch1, int ch2)
  491. {
  492. return CTextSock::ProcessTelnetNegotiation(ch1, ch2);
  493. }
  494. void CFTPDCoreCtrlSock::InsertPendingText()
  495. {
  496. CTextSock::InsertPendingText();
  497. }
  498. enum // Macro Table 
  499. {
  500. MT_DIRMSG, MT_DISKFREE, MT_USERTYPE, MT_CMAX, MT_CAMAX
  501. };
  502. MACROTABLE BaseMacros[] = 
  503. {
  504. {"diskfree", MT_DISKFREE,"Free disk space in the current directory."},
  505. {"dirmsg", MT_DIRMSG, "Directory change message"},
  506. {"usertype",        MT_USERTYPE,"User type. Anonymous, user or administrator"},
  507. {"maxusers", MT_CMAX, "Max number of users online."},
  508. {"maxanons", MT_CAMAX, "Max number of anonymous users online."},
  509. {"", 0, ""}
  510. };
  511. BOOL CFTPDCoreCtrlSock::ExpandMacro(LPSTR *To, LPCSTR MacroName, int AvailBytes)
  512. {
  513.  if (CTextSock::ExpandMacro(To, MacroName, AvailBytes))
  514. return TRUE;
  515. CString Macro("");
  516. if (*MacroName == '$')
  517. {
  518. for(MACROTABLE *pMT = BaseMacros; *pMT->Name; pMT++)
  519. {
  520. if (!stricmp(pMT->Name, MacroName + 1))
  521. {
  522. switch(pMT->Symb)
  523. {
  524. case MT_USERTYPE:
  525. if (m_IsLoggedInAnonymously)
  526. Macro = "anonymous";
  527. else if (CUsr::IsAdmin(m_User))
  528. Macro = "supervisor";
  529. else
  530. Macro = "user";
  531. break;
  532. case MT_DIRMSG:
  533. {
  534. /*
  535. CString Path;
  536. Path.Format("%s\.message.txt", m_CWD);
  537. CFsys::GetFsys()->DosPath(Path.GetBuffer(1));
  538. Path.ReleaseBuffer();
  539. FILE *fp = fopen(Path,"r");
  540. if (fp)
  541. {
  542. char buf[1024];
  543. while(fgets(buf, sizeof(buf), fp))
  544. Macro += buf;
  545. fclose(fp);
  546. }
  547. */
  548. }
  549. break;
  550. case MT_DISKFREE:
  551. {
  552. /*
  553. CString Path(m_CWD);
  554. CFsys::GetFsys()->DosPath(Path.GetBuffer(1));
  555. Path.ReleaseBuffer();
  556. __int64 MySize = GetFreeDiskSpace(Path);
  557. char buf[128];
  558. sprintf(buf, "%I64d", MySize);
  559. Macro = buf;
  560. */
  561. }
  562. break;
  563. case MT_CAMAX: 
  564. Macro = COptions::GetOption(
  565. COPTION_FTPD_CORE,
  566. FTPDCORE_OPTIONS__MAX_ANON_CONNECTOIONS);
  567. break;
  568. case MT_CMAX:
  569. Macro = COptions::GetOption(
  570. COPTION_FTPD_CORE,
  571. FTPDCORE_OPTIONS__MAX_CONNECTIONS);
  572. break;
  573. default:
  574. Macro.Format("(Macro '%s' is not yet available)", MacroName);
  575. break;
  576. }
  577. break;
  578. }
  579. }
  580. }
  581. else
  582. {
  583. // File name
  584. FILE *fp;
  585. CString Fname;
  586. if (*MacroName == '+')
  587. {
  588. Fname = MacroName + 1;
  589. Macro = "rn";
  590. }
  591. else
  592. Fname = MacroName;
  593. CString Upath;
  594. /*if (strpbrk(Fname,"/\:"))
  595. {
  596. CFsys::GetFsys()->UnixPath(Upath.GetBuffer(1));
  597. Upath.ReleaseBuffer();
  598. CFsys::GetFsys()->MkPath(m_RootDir, m_CWD, Fname, Upath.GetBuffer(MAX_PATH));
  599. if (!CFsys::GetFsys()->CheckPermission(m_User, m_RootDir, Upath, FALSE, NODE_READ))
  600. {
  601. denied:
  602. LogMsg(LOGF_SECURITY,"CFTPDCoreCtrlSock::ExpandMacro(%s) - Permission denied to file!", MacroName);
  603. Macro.Format("(Permission denied to file '%s')", Fname);
  604. goto done;
  605. }
  606. CFsys::GetFsys()->DosPath(Upath.GetBuffer(1));
  607. }
  608. else*/ if (!strnicmp("sysmsg", Fname, 6))
  609. {
  610. Upath = Fname;
  611. }
  612. /*else
  613. goto denied;*/
  614. if (Upath && *Upath)
  615. {
  616. if ((fp = fopen(Upath,"r")) != NULL)
  617. {
  618. {
  619. char buf[512];
  620. while(fgets(buf, sizeof(buf), fp))
  621. Macro += buf;
  622. }
  623. fclose(fp);
  624. int OfsSave = m_InsertOffset;
  625. m_InsertOffset += (*To - &m_OutBuf[CBufferSock::m_BufferUsed]);
  626. SendCtrlMsg(m_LastRcode, Macro, TRUE, FALSE);
  627. *To = &m_OutBuf[CBufferSock::m_BufferUsed];
  628. m_InsertOffset = OfsSave;
  629. return TRUE;
  630. }
  631. else
  632. {
  633. LogMsg(LOGF_DEBUG,"CFTPDCoreCtrlSock::ExpandMacro(%s) - Unable to open file.", MacroName);
  634. return TRUE;
  635. }
  636. }
  637. }
  638. //done:
  639. int Len = Macro.GetLength();
  640. if (Len && (Len < AvailBytes))
  641. {
  642. memcpy(*To, Macro, Len);
  643. *To = *To + Len;
  644. return TRUE;
  645. }
  646. return FALSE;
  647. }
  648. // Return TRUE if the socket still exist
  649. BOOL CFTPDCoreCtrlSock::OnCommand(LPCSTR Text)
  650. {
  651. BOOL DoParseCmdLine = FALSE;
  652. if (!CTextSock::OnCommand(Text))
  653. return FALSE;
  654. m_LastCommandText = Text;
  655. // EXT module
  656. if (PrcSockExt(CSock::iOnCommand,0,(WPARAM)0,(LPARAM)&Text))
  657. return TRUE;
  658. m_Args.PrepereNew();
  659. m_UnixArgs.PrepereNew();
  660. int CmdID = m_Parser.ParseCmd(Text,m_Args, m_State, DoParseCmdLine);
  661. if (DoParseCmdLine)
  662. {
  663. m_Fsys->PrepereCommandLine(CmdID);
  664. return TRUE;
  665. }
  666. else
  667. return OnCommand(CmdID);
  668. }
  669. BOOL CFTPDCoreCtrlSock::OnCommand(int CmdID)
  670. {
  671. BOOL Rval = TRUE;
  672. switch(CmdID)
  673. {
  674. case CMD_USER:
  675. m_Restart = 0; m_ArgSave.Empty();
  676. if (m_User = CUsr::Login(LT_FTP,m_Args[1], NULL, this))
  677. goto logged_in;
  678. m_State = GOTNAME;
  679. m_ArgSave = m_Args[1];
  680. break;
  681. case CMD_PASS:
  682. m_Restart = 0;
  683. logged_in:
  684. if (m_User = CUsr::Login(LT_FTP, m_ArgSave, m_Args[1], this))
  685. {
  686. if (!OnLogin(m_Args))
  687. return FALSE;
  688. SendMsg(230,"User %s logged in. Access restrictions apply.", m_LoginName);
  689. m_State = PROCESS;
  690. }
  691. else
  692. m_State = PRELOGIN; // Try again...
  693. m_ArgSave.Empty();
  694. break;
  695. case CMD_ACCT:
  696. m_Restart = 0; m_ArgSave.Empty();
  697. if (!OnAcct(m_Args))
  698. return FALSE;
  699. break;
  700. case CMD_QUIT:
  701. m_Restart = 0; m_ArgSave.Empty();
  702. if (!OnQuit(m_Args))
  703. return FALSE;
  704. break;
  705. case CMD_REIN:
  706. m_Restart = 0; m_ArgSave.Empty();
  707. if (!OnRein(m_Args))
  708. return FALSE;
  709. break;
  710. case CMD_PORT:
  711. m_ArgSave.Empty();
  712. if (!OnPort(m_Args))
  713. return FALSE;
  714. break;
  715. case CMD_PASV:
  716. m_ArgSave.Empty();
  717. if (!OnPasv(m_Args))
  718. return FALSE;
  719. break;
  720. case CMD_TYPE:
  721. m_ArgSave.Empty();
  722. if (!OnType(m_Args))
  723. return FALSE;
  724. break;
  725. case CMD_STRU:
  726. m_ArgSave.Empty();
  727. if (!OnStru(m_Args))
  728. return FALSE;
  729. break;
  730. case CMD_MODE:
  731. m_ArgSave.Empty();
  732. if (!OnMode(m_Args))
  733. return FALSE;
  734. break;
  735. case CMD_RETR:
  736. m_ArgSave.Empty();
  737. if (!OnRetr(m_Args))
  738. return FALSE;
  739. m_Restart = 0;
  740. break;
  741. case CMD_STOR:
  742. m_ArgSave.Empty();
  743. if (!OnStor(m_Args))
  744. return FALSE;
  745. m_Restart = 0;
  746. break;
  747. case CMD_APPE:
  748. m_ArgSave.Empty();
  749. if (!OnAppe(m_Args))
  750. return FALSE;
  751. m_Restart = 0;
  752. break;
  753. case CMD_ALLO:
  754. m_ArgSave.Empty();
  755. if (!OnAllo(m_Args))
  756. return FALSE;
  757. break;
  758. case CMD_REST:
  759. m_Restart = 0; m_ArgSave.Empty();
  760. if (!OnRest(m_Args))
  761. return FALSE;
  762. break;
  763. case CMD_RNFR:
  764. m_Restart = 0;
  765. m_ArgSave = m_Args[1];
  766. if (!OnRnFr(m_Args))
  767. return FALSE;
  768. break;
  769. case CMD_RNTO:
  770. m_Restart = 0;
  771. if (!OnRnTo(m_Args))
  772. return FALSE;
  773. m_ArgSave.Empty();
  774. break;
  775. case CMD_ABOR:
  776. m_Restart = 0; m_ArgSave.Empty();
  777. if (!OnAbor(m_Args))
  778. return FALSE;
  779. break;
  780. case CMD_DELE:
  781. m_Restart = 0; m_ArgSave.Empty();
  782. if (!OnDele(m_Args))
  783. return FALSE;
  784. break;
  785. case CMD_CWD:
  786. m_Restart = 0; m_ArgSave.Empty();
  787. if (!OnCwd(m_Args))
  788. return FALSE;
  789. break;
  790. case CMD_LIST:
  791. m_Restart = 0; m_ArgSave.Empty();
  792. if (!OnList(m_Args))
  793. return FALSE;
  794. break;
  795. case CMD_NLST:
  796. m_Restart = 0; m_ArgSave.Empty();
  797. if (!OnNlst(m_Args))
  798. return FALSE;
  799. break;
  800. case CMD_SITE:
  801. m_Restart = 0; m_ArgSave.Empty();
  802. if (!OnSite(m_Args))
  803. return FALSE;
  804. break;
  805. case CMD_STAT:
  806. m_Restart = 0; m_ArgSave.Empty();
  807. if (!OnStat(m_Args))
  808. return FALSE;
  809. break;
  810. case CMD_HELP:
  811. m_Restart = 0; m_ArgSave.Empty();
  812. if (!OnHelp(m_Args))
  813. return FALSE;
  814. break;
  815. case CMD_NOOP:
  816. m_Restart = 0; m_ArgSave.Empty();
  817. if (!OnNoop(m_Args))
  818. return FALSE;
  819. break;
  820. case CMD_MKD:
  821. m_Restart = 0; m_ArgSave.Empty();
  822. if (!OnMkd(m_Args))
  823. return FALSE;
  824. break;
  825. case CMD_RMD:
  826. m_Restart = 0; m_ArgSave.Empty();
  827. if (!OnRmd(m_Args))
  828. return FALSE;
  829. case CMD_PWD:
  830. m_Restart = 0; m_ArgSave.Empty();
  831. if (!OnPwd(m_Args))
  832. return FALSE;
  833. break;
  834. case CMD_CDUP:
  835. m_Restart = 0; m_ArgSave.Empty();
  836. if (!OnCdUp(m_Args))
  837. return FALSE;
  838. break;
  839. case CMD_STOU:
  840. m_Restart = 0; m_ArgSave.Empty();
  841. if (!OnStou(m_Args))
  842. return FALSE;
  843. break;
  844. case CMD_SMNT:
  845. m_Restart = 0; m_ArgSave.Empty();
  846. if (!OnSmnt(m_Args))
  847. return FALSE;
  848. break;
  849. case CMD_SYST:
  850. m_Restart = 0; m_ArgSave.Empty();
  851. if (!OnSyst(m_Args))
  852. return FALSE;
  853. break;
  854. case CMD_SIZE:
  855. m_ArgSave.Empty();
  856. if (!OnSize(m_Args))
  857. return FALSE;
  858. break;
  859. case CMD_MDTM:
  860. m_ArgSave.Empty();
  861. if (!OnMdtm(m_Args))
  862. return FALSE;
  863. break;
  864. // SITE commands
  865. case CMD_CHMOD:
  866. m_Restart = 0; m_ArgSave.Empty();
  867. if (!OnSiteChmod(m_Args))
  868. return FALSE;
  869. break;
  870. case CMD_FSYSSTAT:
  871. m_Restart = 0; m_ArgSave.Empty();
  872. if (!OnSiteFsysstat(m_Args))
  873. return FALSE;
  874. break;
  875. // Command errors
  876. case CMD_MISSING_PARAMETER:
  877. SendMsg(501,"Missing parameter in command %s", m_LastCommandText);
  878. break;
  879. case CMD_UNKNOWN_COMMAND:
  880. SendMsg(500, "%s: unrecognized command.", m_LastCommandText);
  881. break;
  882. case CMD_NOT_IMPLEMENTED:
  883. SendMsg(502, "%s: command not implemented.", m_LastCommandText);
  884. break;
  885. case CMD_BAD_LEVEL:
  886. m_Restart = 0; m_ArgSave.Empty();
  887. SendMsg(530, "Please login with USER and PASS.");
  888. break;
  889. case CMD_PARSE_ERROR:
  890. case CMD_UNKNOWN_PARAMETER:
  891. SendMsg(500,"'%s': command not understood.", m_LastCommandText);
  892. break;
  893. default:
  894. SendMsg(502,"%s: Command not implemented.", m_Args[0]);
  895. break;
  896. }
  897. m_PrevCmdID = CmdID;
  898. return Rval;
  899. }
  900. /////////////////////////////////////////////////////////////////////////////////
  901. // FTP server implementation functions
  902. BOOL CFTPDCoreCtrlSock::OnQuit(CCmdArgs& Args)
  903. {
  904. SendCtrlMsg(221, "Goodbye.");
  905. LogMsg(LOGF_INOUT,"User from %s logging off.", m_PeerName);
  906. CSocketException::Throw(this, "CFTPDCoreCtrlSock::OnQuit()", 0, "User logged out");
  907. return FALSE; // Socket is deleted
  908. }
  909. BOOL CFTPDCoreCtrlSock::OnLogin(CCmdArgs& Args)
  910. {
  911. // Set idle time
  912. SetIdleTime(CUsr::GetRecursiveParam(m_User, "IdleTime", 3 * 60) * 1000);
  913. SetLogonTime(CUsr::GetRecursiveParam(m_User, "LoginTime", 0) * 60000);
  914. NotifyLogin(ENL_UPDATE, "");
  915. m_Fsys = new CFTPDFsys((LPVOID *)&m_Fsys);
  916. if (!m_Fsys->Create(this))
  917. {
  918. delete m_Fsys;
  919. m_Fsys = NULL;
  920. SendMsg(421, "Internal error - unable to initialize your file system. Goodbye");
  921. LogMsg(LOGF_ERROR,"Unable to initialize the users file system.");
  922. CSocketException::Throw(this, "CFTPDCoreCtrlSock::OnLogin()", 0, "Unable to initialize file system");
  923. }
  924. return TRUE;
  925. }
  926. BOOL CFTPDCoreCtrlSock::OnAcct(CCmdArgs& Args)
  927. {
  928. SendMsg(200,"ACCT Command ok.");
  929. return TRUE;
  930. }
  931. BOOL CFTPDCoreCtrlSock::OnRein(CCmdArgs& Args)
  932. {
  933. SendMsg(502,"%s: Command not implemented.", m_Args[0]);
  934. return TRUE;
  935. }
  936. BOOL CFTPDCoreCtrlSock::OnPort(CCmdArgs& Args)
  937. {
  938. SOCKADDR_IN *s_in = (SOCKADDR_IN *)&m_Sockaddr;
  939. SOCKADDR_IN sin;
  940. int i1, i2, i3, i4, i5, i6;
  941. if (sscanf(m_Args[1],"%d,%d,%d,%d,%d,%d", &i1, &i2, &i3, &i4, &i5, &i6) != 6)
  942. {
  943. SendMsg(501,"'%s': Must be 6 digits.", Args.Arg(1));
  944. return TRUE;
  945. }
  946. sin.sin_addr.S_un.S_un_b.s_b1 = (unsigned char)i1;
  947. sin.sin_addr.S_un.S_un_b.s_b2 = (unsigned char)i2;
  948. sin.sin_addr.S_un.S_un_b.s_b3 = (unsigned char)i3;
  949. sin.sin_addr.S_un.S_un_b.s_b4 = (unsigned char)i4;
  950. sin.sin_port = htons((i5 << 8) | i6);
  951. if ((ntohs(sin.sin_port) > 1023) && (s_in->sin_addr.s_addr > 0)) 
  952. {
  953. SendMsg(200, "PORT command successful.");
  954. s_in->sin_addr.S_un.S_addr = sin.sin_addr.S_un.S_addr;
  955. s_in->sin_port = sin.sin_port;
  956. }
  957. else 
  958. {
  959. LogMsg(LOGF_SECURITY, "CFTPDCoreCtrlSock::OnPort(%s): refused PORT %lX,%d", 
  960. Args.Arg(1), sin.sin_addr.s_addr, ntohs(sin.sin_port));
  961. SendMsg(500, "Illegal PORT Command");
  962. }
  963. LogMsg(LOGF_DEBUG,"OnPort(%s): PORT %lX,%d.", Args.Arg(1), sin.sin_addr.s_addr, ntohs(sin.sin_port));
  964. return TRUE;
  965. }
  966. BOOL CFTPDCoreCtrlSock::OnPasv(CCmdArgs& Args)
  967. {
  968. return m_DataSock->Create(this, &m_DataSock, m_FTPmode, m_FTPstru, m_FTPform, 
  969. m_FTPtype, &m_Sockaddr, TRUE);
  970. }
  971. BOOL CFTPDCoreCtrlSock::OnType(CCmdArgs& Args)
  972. {
  973. // Parse the type.
  974. int cmd_form, cmd_type, cmd_bytesz, TokenID;
  975. LPCSTR LexCmdLine = Args.Arg(1);
  976. TokenID = m_Parser.yyLex(&LexCmdLine, m_Parser.m_Tokens, ' ', LEX_WANT_CHAR, Args);
  977. if (TokenID != TOK_CHAR)
  978. {
  979. unknown_type:
  980. SendMsg(501,"'%s %s': unknown type.", Args.Arg(0), Args.Arg(1));
  981. return TRUE;
  982. }
  983. ASSERT(Args.m_argc == 3);
  984. switch(toupper(*Args.Arg(2)))
  985. {
  986. case 'A':
  987. cmd_type = TYPE_A;
  988. cmd_form = FORM_N;
  989. // Check for form parameter
  990. check_form:
  991. TokenID = m_Parser.yyLex(&LexCmdLine, m_Parser.m_Tokens, ' ', LEX_WANT_CHAR, Args);
  992. if (TokenID == TOK_CHAR)
  993. {
  994. ASSERT(Args.m_argc == 4);
  995. switch(toupper(*Args.Arg(3)))
  996. {
  997. case 'N': cmd_form = FORM_N; break;
  998. case 'T': cmd_form = FORM_T; break;
  999. case 'C': cmd_form = FORM_C; break;
  1000. default:
  1001. SendMsg(501,"'%s %s': unknown form (%s).", Args.Arg(0), Args.Arg(1), Args.Arg(3));
  1002. return TRUE;
  1003. }
  1004. }
  1005. // Validiate...
  1006. if (cmd_form == FORM_N) 
  1007. {
  1008. SendMsg(200, "Type set to A.");
  1009. m_FTPtype = cmd_type;
  1010. m_FTPform = cmd_form;
  1011. else
  1012. SendMsg(504, "Form must be N.");
  1013. break;
  1014. case 'E':
  1015. SendMsg(504, "Type E not implemented.");
  1016. goto check_form;
  1017. case 'I':
  1018. SendMsg(200, "Type set to I.");
  1019. m_FTPtype = TYPE_I;
  1020. break;
  1021. case 'L':
  1022. cmd_bytesz = 8;
  1023. cmd_type = TYPE_L;
  1024. // Check for bytesize parameter
  1025. TokenID = m_Parser.yyLex(&LexCmdLine, m_Parser.m_Tokens, ' ', LEX_WANT_INT, Args);
  1026. if (TokenID == TOK_CHAR)
  1027. {
  1028. ASSERT(Args.m_argc == 4);
  1029. cmd_bytesz = atoi(Args.Arg(3));
  1030. }
  1031. else if (atoi(Args.Arg(2) + 1))
  1032. {
  1033. // This is for a bug in the BBN ftp 
  1034. cmd_bytesz = atoi(Args.Arg(2) + 1);
  1035. }
  1036. if (cmd_bytesz == 8)
  1037. {
  1038. SendMsg(200, "Type set to L (byte size 8).");
  1039. m_FTPtype = cmd_type;
  1040. else
  1041. SendMsg(504, "Byte size must be 8.");
  1042. break;
  1043. default:
  1044. goto unknown_type;
  1045. }
  1046. return TRUE;
  1047. }
  1048. BOOL CFTPDCoreCtrlSock::OnStru(CCmdArgs& Args)
  1049. {
  1050. int TokenID;
  1051. LPCSTR LexCmdLine = Args.Arg(1);
  1052. TokenID = m_Parser.yyLex(&LexCmdLine, m_Parser.m_Tokens, ' ', LEX_WANT_CHAR, Args);
  1053. if (TokenID != TOK_CHAR)
  1054. {
  1055. SendMsg(501,"'%s %s': unknown struct.", Args.Arg(0), Args.Arg(1));
  1056. return TRUE;
  1057. }
  1058. ASSERT(Args.m_argc == 3);
  1059. switch(toupper(*Args.Arg(2)))
  1060. {
  1061. case 'F':
  1062. m_FTPstru = STRU_F;
  1063. SendMsg(200, "STRU F ok.");
  1064. break;
  1065. default:
  1066. SendMsg(504, "Unimplemented STRU type.");
  1067. return TRUE;
  1068. }
  1069. return TRUE;
  1070. }
  1071. BOOL CFTPDCoreCtrlSock::OnMode(CCmdArgs& Args)
  1072. {
  1073. int TokenID;
  1074. LPCSTR LexCmdLine = Args.Arg(1);
  1075. TokenID = m_Parser.yyLex(&LexCmdLine, m_Parser.m_Tokens, ' ', LEX_WANT_CHAR, Args);
  1076. if (TokenID != TOK_CHAR)
  1077. {
  1078. SendMsg(501,"'%s %s': unknown mode.", Args.Arg(0), Args.Arg(1));
  1079. return TRUE;
  1080. }
  1081. ASSERT(Args.m_argc == 3);
  1082. switch(toupper(*Args.Arg(2)))
  1083. {
  1084. case 'S':
  1085. m_FTPmode = MODE_S;
  1086. SendMsg(200, "MODE S ok.");
  1087. break;
  1088. default:
  1089. SendMsg(504, "Unimplemented MODE type.");
  1090. return TRUE;
  1091. }
  1092. return TRUE;
  1093. }
  1094. BOOL CFTPDCoreCtrlSock::OnRetr(CCmdArgs& Args)
  1095. {
  1096. return DoRetr(Args, 0);
  1097. }
  1098. BOOL CFTPDCoreCtrlSock::OnStor(CCmdArgs& Args)
  1099. {
  1100. return DoStor(Args, 0);
  1101. }
  1102. BOOL CFTPDCoreCtrlSock::OnAppe(CCmdArgs& Args)
  1103. {
  1104. return DoStor(Args, XMITF_APPE);
  1105. }
  1106. BOOL CFTPDCoreCtrlSock::OnAllo(CCmdArgs& Args)
  1107. {
  1108. SendMsg(502,"%s: Command not implemented.", Args.Arg(0));
  1109. return TRUE;
  1110. }
  1111. BOOL CFTPDCoreCtrlSock::OnRest(CCmdArgs& Args)
  1112. {
  1113. m_Restart = atoi(Args.Arg(1));
  1114. SendMsg(350, "Restarting at byte offset %u. Send STORE or RETRIEVE to initiate transfer.", 
  1115. m_Restart);
  1116. return TRUE;
  1117. }
  1118. BOOL CFTPDCoreCtrlSock::OnRnFr(CCmdArgs& Args)
  1119. {
  1120. if (m_UnixArgs.m_argc != 2)
  1121. {
  1122. LogMsg(LOGF_DEBUG,"OnRnFr() - Ambigous RNFR command: %s", Args[1]);
  1123. SendMsg(550,"Ambigous RNFR command: %s", Args[1]);
  1124. return TRUE;
  1125. }
  1126. m_ArgSave = m_UnixArgs[1];
  1127. SendMsg(350, "RNFR Ok. Ready for destination name.");
  1128. return TRUE;
  1129. }
  1130. BOOL CFTPDCoreCtrlSock::OnRnTo(CCmdArgs& Args)
  1131. {
  1132. CString cFnameBuf;
  1133. if (m_PrevCmdID != CMD_RNFR)
  1134. {
  1135. SendMsg(503,"Bad sequence of commands.");
  1136. return TRUE;
  1137. }
  1138. if (m_UnixArgs.m_argc != 2)
  1139. {
  1140. LogMsg(LOGF_DEBUG,"OnRnTo() - Ambigous RNFR command: %s", m_UnixArgs[1]);
  1141. SendMsg(550,"Ambigous RNFR command: %s", m_UnixArgs[1]);
  1142. return TRUE;
  1143. }
  1144. ASSERT(AfxIsValidString(m_ArgSave));
  1145. if (!m_Fsys->MoveFile(m_ArgSave, m_UnixArgs[1]))
  1146. {
  1147. LogMsg(LOGF_DEBUG,"OnRnTo() - RenamePath(%s,%s) failed before callback.", m_ArgSave, cFnameBuf);
  1148. SendMsg(550,"Permission denied.");
  1149. return TRUE;
  1150. }
  1151. return TRUE;
  1152. }
  1153. BOOL CFTPDCoreCtrlSock::OnAbor(CCmdArgs& Args)
  1154. {
  1155. if (m_DataSock)
  1156. {
  1157. ASSERT(AfxIsValidAddress(m_DataSock,sizeof(CFTPDataSock)));
  1158. m_DataSock->m_HaveToldUserThatTransfereIsComplete = TRUE;
  1159. delete m_DataSock;
  1160. }
  1161. SendMsg(225, "ABOR command successful.");
  1162. return TRUE;
  1163. }
  1164. BOOL CFTPDCoreCtrlSock::OnDele(CCmdArgs& Args)
  1165. {
  1166. return DoDele(Args);
  1167. }
  1168. BOOL CFTPDCoreCtrlSock::OnCwd(CCmdArgs& Args)
  1169. {
  1170. // Expand the command line to allow "CD war*"
  1171. if (m_UnixArgs.m_argc > 2)
  1172. {
  1173. // The pattern matching routines returned more than one path...
  1174. SendMsg(550,"Ambigous CWD command.");
  1175. }
  1176. else if (!DoChdir((m_UnixArgs.m_argc == 2) ? m_UnixArgs.Arg(1) : NULL))
  1177. {
  1178. // Failed
  1179. SendMsg(550,"Permission denied.");
  1180. }
  1181. return TRUE;
  1182. }
  1183. BOOL CFTPDCoreCtrlSock::OnList(CCmdArgs& Args)
  1184. {
  1185. return ProcessList("-lAf", Args);
  1186. }
  1187. BOOL CFTPDCoreCtrlSock::OnNlst(CCmdArgs& Args)
  1188. {
  1189. return ProcessList("", Args);
  1190. }
  1191. BOOL CFTPDCoreCtrlSock::OnSite(CCmdArgs& Args)
  1192. {
  1193. // EXT module
  1194. if (PrcSockExt(CSock::iOnSITECmd,0,(WPARAM)0,(LPARAM)&Args))
  1195. return TRUE;
  1196. SendMsg(502,"%s: Command not implemented.", Args.Arg(0));
  1197. return TRUE;
  1198. }
  1199. BOOL CFTPDCoreCtrlSock::OnStat(CCmdArgs& Args)
  1200. {
  1201. if (Args.m_argc == 2)
  1202. {
  1203. // STAT path command
  1204. SendMsg(504,"STAT <path> command not implemented.");
  1205. return TRUE;
  1206. }
  1207. else
  1208. {
  1209. CWarString cBuf;
  1210. ASSERT(Args.m_argc == 1);
  1211. // Stat command without 
  1212. SendCtrlMsg(211,"[$systemname] FTP server status:", TRUE, FALSE);
  1213. SendMsg(0,"n     Version [$programname] [$programversion]");
  1214. if (!isdigit(m_DNSName[0]))
  1215. cBuf.Format("%s (%s)", m_DNSName, m_PeerName);
  1216. else
  1217. cBuf.Format("%s", m_DNSName);
  1218. SendMsg(0,"     Connected to %s", cBuf);
  1219. if (m_State >= PROCESS)
  1220. {
  1221. if (m_IsLoggedInAnonymously)
  1222. SendMsg(0, "     Logged in anonymously");
  1223. else
  1224. SendMsg(0, "     Logged in as %s", m_LoginName);
  1225. }
  1226. else if (m_State == GOTNAME)
  1227. SendMsg(0, "     Waiting for password");
  1228. else if (m_State == PRELOGIN)
  1229. SendMsg(0, "     Waiting for user name");
  1230. else
  1231. SendMsg(0, "     Unknown internal state %d", m_Type);
  1232.     
  1233. cBuf.Format("     TYPE: %s", SafeStringIndex(typenames, m_FTPtype, 5));
  1234. if ((m_FTPtype == TYPE_A) || (m_FTPtype == TYPE_E))
  1235. cBuf.FormatCat(", FORM: %s", SafeStringIndex(formnames, m_FTPform, 4));
  1236.     if (m_FTPtype == TYPE_L)
  1237.         cBuf.FormatCat(" %d", 8);
  1238.     cBuf.FormatCat("; STRUcture: %s; transfer MODE: %s", 
  1239. SafeStringIndex(strunames, m_FTPstru, 4), SafeStringIndex(modenames,m_FTPmode, 4));
  1240. SendMsg(0, "%s", cBuf);
  1241.     if (m_DataSock)
  1242.         SendMsg(0, "     Data connection ready/open"); 
  1243. else
  1244.         SendMsg(0, "     No data connection");
  1245.     SendMsg(211, "End of status");
  1246. }
  1247. return TRUE;
  1248. }
  1249. BOOL CFTPDCoreCtrlSock::OnHelp(CCmdArgs& Args)
  1250. {
  1251. CString cBuf = "";
  1252. STokenTabDef *Token;
  1253. SCommandTreeDef *Cmd;
  1254. int Index = 0;
  1255. if (Args.m_argc == 2)
  1256. {
  1257. LPCSTR CmdName = Args.Arg(1);
  1258. // Help on a command
  1259. for(Token = BaseTokens; Token->TokenID != TOK_INVALID; Token++)
  1260. {
  1261. // Lookup cmd
  1262. if (!stricmp(CmdName,Token->Token))
  1263. {
  1264. for(Cmd = BaseCmds; Cmd->CommandID != CMD_INVALID; Cmd++)
  1265. {
  1266. if (Cmd->TokenID == Token->TokenID)
  1267. {
  1268. SendMsg(214,"Syntax: %s", Cmd->CommandSyntax);
  1269. break;
  1270. }
  1271. }
  1272. break;
  1273. }
  1274. }
  1275. if (!Cmd || !Token)
  1276. SendMsg(502,"Unknown command %s", CmdName);
  1277. }
  1278. else
  1279. {
  1280. // Just list all commands
  1281. SendCtrlMsg(214, "The following commands are recognized. (* =>'s unimplemented)", TRUE);
  1282. SendCtrlMsg(0,"n", TRUE, FALSE);
  1283. for(Token = BaseTokens; Token->TokenID != TOK_INVALID; Token++)
  1284. {
  1285. // Lookup cmd
  1286. for(Cmd = BaseCmds; Cmd->CommandID != CMD_INVALID; Cmd++)
  1287. {
  1288. if (Cmd->TokenID == Token->TokenID)
  1289. {
  1290. cBuf += "   ";
  1291. cBuf += Token->Token;
  1292. cBuf += (Cmd->Flags & CMDF_NOT_IMPLEMENTED) ? '*' : ' ';
  1293. if (strlen(Token->Token) == 3)
  1294. cBuf += ' ';
  1295. if (!(++Index % 8))
  1296. {
  1297. cBuf += 'n';
  1298. SendCtrlMsg(0, cBuf, TRUE);
  1299. cBuf = "";
  1300. }
  1301. break;
  1302. }
  1303. }
  1304. }
  1305. if (cBuf.GetLength())
  1306. {
  1307. cBuf += 'n';
  1308. SendCtrlMsg(0, cBuf, TRUE);
  1309. }
  1310. SendMsg(214, "Direct comments to [$email]");
  1311. }
  1312. return TRUE;
  1313. }
  1314. BOOL CFTPDCoreCtrlSock::OnNoop(CCmdArgs& Args)
  1315. {
  1316. SendMsg(200, "NOOP command successful.");
  1317. return TRUE;
  1318. }
  1319. BOOL CFTPDCoreCtrlSock::OnMkd(CCmdArgs& Args)
  1320. {
  1321. return DoMkDir(Args);
  1322. }
  1323. BOOL CFTPDCoreCtrlSock::OnRmd(CCmdArgs& Args)
  1324. {
  1325. return DoDele(Args);
  1326. }
  1327. BOOL CFTPDCoreCtrlSock::OnPwd(CCmdArgs& Args)
  1328. {
  1329. SendMsg(257, ""%s" is current directory.", m_Fsys->m_CWD);
  1330. return TRUE;
  1331. }
  1332. BOOL CFTPDCoreCtrlSock::OnCdUp(CCmdArgs& Args)
  1333. {
  1334. m_UnixArgs.AddArg("CD");
  1335. m_UnixArgs.AddArg("..");
  1336. OnCwd(Args);
  1337. return TRUE;
  1338. }
  1339. BOOL CFTPDCoreCtrlSock::OnStou(CCmdArgs& Args)
  1340. {
  1341. return DoStor(Args, XMITF_UNIQUE);
  1342. }
  1343. BOOL CFTPDCoreCtrlSock::OnSmnt(CCmdArgs& Args)
  1344. {
  1345. SendMsg(502,"%s: Command not implemented.", Args.Arg(0));
  1346. return TRUE;
  1347. }
  1348. BOOL CFTPDCoreCtrlSock::OnSyst(CCmdArgs& Args)
  1349. {
  1350. SendMsg(215, "UNIX Type: L8 Server: "War FTPD light 2.01a" OS: "%s"", OsName());
  1351. return TRUE;
  1352. }
  1353. BOOL CFTPDCoreCtrlSock::OnSize(CCmdArgs& Args)
  1354. {
  1355. CString cBuf, cFnameBuf;
  1356. switch(m_FTPtype)
  1357. {
  1358. case TYPE_L:
  1359.     case TYPE_I:
  1360. case TYPE_A:
  1361. {
  1362. if (m_UnixArgs.m_argc != 2)
  1363. {
  1364. LogMsg(LOGF_DEBUG,"OnSize() - Ambigous SIZE command: %s", Args.Arg(1));
  1365. SendMsg(550,"Ambigous SIZE command: %s", Args.Arg(1));
  1366. return TRUE;
  1367. }
  1368. if (!m_Fsys->Size(m_UnixArgs[1]))
  1369. {
  1370. LogMsg(LOGF_DEBUG,"OnSize() - FindFirstFile(%s) failed before callback.", m_UnixArgs[1]);
  1371. SendMsg(451,"Server error.");
  1372. }
  1373. }
  1374. break;
  1375. default:
  1376. SendMsg(504, "SIZE not implemented for Type %c.", "?AEIL"[max((unsigned)m_FTPtype, 5)]);
  1377. }
  1378. return TRUE;
  1379. }
  1380. /*
  1381.  * MDTM is not in RFC959, but Postel has blessed it and
  1382.  * it will be in the updated RFC.
  1383.  *
  1384.  * Return modification time of file as an ISO 3307
  1385.  * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx
  1386.  * where xxx is the fractional second (of any precision,
  1387.  * not necessarily 3 digits)
  1388.  */
  1389. BOOL CFTPDCoreCtrlSock::OnMdtm(CCmdArgs& Args)
  1390. {
  1391. if (m_UnixArgs.m_argc != 2)
  1392. {
  1393. LogMsg(LOGF_DEBUG,"OnMdtm() - Ambigous SIZE command: %s", Args.Arg(1));
  1394. SendMsg(550,"Ambigous SIZE command: %s", Args.Arg(1));
  1395. return TRUE;
  1396. }
  1397. if (!m_Fsys->Mdtm(m_UnixArgs[1]))
  1398. {
  1399. LogMsg(LOGF_DEBUG,"Mdtm(%s) - failed before callback.", m_UnixArgs[1]);
  1400. SendMsg(451,"Server error.");
  1401. return TRUE;
  1402. }
  1403. return TRUE;
  1404. }
  1405. ///////////////////////////////////////////////////////////////////////////////
  1406. // Support functions
  1407. // Process LIST and NLST commands.
  1408. BOOL CFTPDCoreCtrlSock::ProcessList(LPCSTR LineArguments, CCmdArgs& Args)
  1409. {
  1410. CString cBuf;
  1411. static LPSTR Cmd = "/bin/ls";
  1412. m_UnixArgs.Replace(0,Cmd);
  1413. if (LineArguments && *LineArguments)
  1414. m_UnixArgs.Insert(1,LineArguments);
  1415. m_Fsys->m_FsysPath3 = LineArguments ? LineArguments : "";
  1416. return m_Fsys->List();
  1417. }
  1418. BOOL CFTPDCoreCtrlSock::CallbackProcessList(int nErrorCode)
  1419. {
  1420. if (nErrorCode)
  1421. {
  1422. SendMsg(550, "Failed to execute %s, error code %d.", m_UnixArgs.Arg(0), nErrorCode);
  1423. LogMsg(LOGF_WARNINGS,"ProcessList() - Failed to execute %s, error code %d.", m_UnixArgs.Arg(0), nErrorCode);
  1424. return TRUE;
  1425. }
  1426. if (!m_DataSock->Create(this, &m_DataSock, m_FTPmode, m_FTPstru, m_FTPform, m_FTPtype, &m_Sockaddr, FALSE))
  1427. {
  1428. ASSERT(AfxIsValidAddress(m_DataSock, sizeof(CFTPDataSock)));
  1429. LogMsg(LOGF_WARNINGS,"ProcessList() - Failed to create data socket.");
  1430. return TRUE;
  1431. }
  1432. CString cBuf;
  1433. cBuf.Format("%s%s%s", m_UnixArgs.Arg(0), m_Fsys->m_FsysPath3.IsEmpty() ? "" : " ", m_Fsys->m_FsysPath3);
  1434. try
  1435. {
  1436. if (!m_DataSock->SendFile(m_Fsys->m_FsysPath2, cBuf, TRUE, m_Restart, 0))
  1437. {
  1438. // SendFile() has already told the user the reason for this and destroyed the socket...
  1439. LogMsg(LOGF_DEBUG,"ProcessList() - SendFile() failed.");
  1440. return TRUE;
  1441. }
  1442. }
  1443. catch(CSocketException *pExc)
  1444. {
  1445. LogMsg(LOGF_DEBUG,"CFTPDCoreCtrlSock::CallbackProcessList(%d) - Caught exception '%s' from module %s",
  1446. nErrorCode, pExc->m_ErrorText, pExc->m_ErrorText);
  1447. if (pExc->m_pSock == (CSock *)m_DataSock)
  1448. {
  1449. delete m_DataSock;
  1450. m_DataSock = NULL;
  1451. delete pExc;
  1452. return FALSE;
  1453. }
  1454. throw pExc; // We can't handle this...
  1455. }
  1456. return TRUE;
  1457. }
  1458. // Change directory. Does not inform user about errors.
  1459. BOOL CFTPDCoreCtrlSock::DoChdir(LPCSTR Path)
  1460. {
  1461. return m_Fsys->ChDir(Path);
  1462. }
  1463. // Send a file to the remote host
  1464. BOOL CFTPDCoreCtrlSock::DoRetr(CCmdArgs& Args, DWORD Flags)
  1465. {
  1466. CString cBuf, cFnameBuf;
  1467. if (m_UnixArgs.m_argc > 2)
  1468. {
  1469. LogMsg(LOGF_DEBUG,"DoRetr() - Ambigous RETR command: %s", Args.Arg(1));
  1470. SendMsg(550,"Ambigous RETR command: %s", Args.Arg(1));
  1471. return TRUE;
  1472. }
  1473. if (!m_DataSock->Create(this, &m_DataSock, m_FTPmode, m_FTPstru, m_FTPform, m_FTPtype, &m_Sockaddr, FALSE))
  1474. {
  1475. ASSERT(AfxIsValidAddress(m_DataSock, sizeof(CFTPDataSock)));
  1476. LogMsg(LOGF_WARNINGS,"DoRetr() - Failed to create data socket.");
  1477. return TRUE;
  1478. }
  1479. m_DataSock->m_pFile = new CWarFile(m_Fsys);
  1480. ASSERT((Flags & XMITF_APPE) == 0);
  1481. if (!m_DataSock->SendFile(m_UnixArgs.Arg(1), cBuf, Flags & XMITF_TEMP, m_Restart, 0))
  1482. {
  1483. // SendFile() has already told the user the reason for this and destroyed the socket...
  1484. LogMsg(LOGF_DEBUG,"DoRetr() - SendFile() failed.");
  1485. return TRUE;
  1486. }
  1487. return TRUE;
  1488. }
  1489. // Receive a file from the remote host
  1490. BOOL CFTPDCoreCtrlSock::DoStor(CCmdArgs& Args, DWORD Flags)
  1491. {
  1492. CString cBuf, cFnameBuf;
  1493. DWORD FTPflags = 0;
  1494. if (m_UnixArgs.m_argc > 2)
  1495. {
  1496. LogMsg(LOGF_DEBUG,"DoStor() - Ambigous STOR command: %s", Args.Arg(1));
  1497. SendMsg(550,"Ambigous RETR command: %s", Args.Arg(1));
  1498. return TRUE;
  1499. }
  1500. // Handle unique
  1501. if (Flags & XMITF_UNIQUE)
  1502. {
  1503. FTPflags |= CWarFile::UNIQUE_NAME;
  1504. }
  1505. // Handle for APPEND mode
  1506. if (Flags & XMITF_APPE)
  1507. {
  1508. if (m_Restart)
  1509. {
  1510. LogMsg(LOGF_DEBUG,"DoStor() - Can't combine APPE and REST");
  1511. SendMsg(550,"Can't combine APPE and REST");
  1512. return TRUE;
  1513. }
  1514. m_Restart = FLEN_MAX;
  1515. }
  1516. if (!m_DataSock->Create(
  1517. this, &m_DataSock, m_FTPmode, m_FTPstru, m_FTPform, m_FTPtype, &m_Sockaddr, FALSE, FTPflags))
  1518. {
  1519. ASSERT(AfxIsValidAddress(m_DataSock, sizeof(CFTPDataSock)));
  1520. LogMsg(LOGF_WARNINGS,"DoRetr() - Failed to create data socket.");
  1521. return TRUE;
  1522. }
  1523. m_DataSock->m_pFile = new CWarFile(m_Fsys);
  1524. if (!m_DataSock->ReceiveFile(m_UnixArgs.Arg(1), cBuf, 0, m_Restart, 0))
  1525. {
  1526. // ReceiveFile() has already told the user the reason for this and destroyed the socket...
  1527. LogMsg(LOGF_DEBUG,"DoStor() - ReceiveFile() failed.");
  1528. return TRUE;
  1529. }
  1530. return TRUE;
  1531. }
  1532. BOOL CFTPDCoreCtrlSock::MkUniquePath(CString& cFnameBuf)
  1533. {
  1534. ASSERT(AfxIsValidString(cFnameBuf));
  1535. CString cBuf = cFnameBuf;
  1536. HANDLE h;
  1537. int cnt = 0;
  1538. while((h = CreateFile(
  1539. cBuf,
  1540. GENERIC_WRITE,
  1541. 0,
  1542. NULL,
  1543. CREATE_NEW,
  1544. FILE_FLAG_DELETE_ON_CLOSE,
  1545. NULL)) == INVALID_HANDLE_VALUE)
  1546. {
  1547. int err;
  1548. if ((err = GetLastError()) != ERROR_FILE_EXISTS)
  1549. {
  1550. LogMsg(LOGF_DEBUG,"MkUniquePath(%s) - Got unexpected error: %s.", 
  1551. cFnameBuf, GetLastErrorText(err));
  1552. return FALSE;
  1553. }
  1554. if (++cnt > 20)
  1555. {
  1556. LogMsg(LOGF_DEBUG,"MkUniquePath(%s) - Failed. Tried %d names.", 
  1557. cFnameBuf, cnt - 1);
  1558. return FALSE;
  1559. }
  1560. cBuf.Format("%s%d", cFnameBuf, cnt);
  1561. }
  1562. ASSERT(h != INVALID_HANDLE_VALUE);
  1563. CloseHandle(h);
  1564. LogMsg(LOGF_DEBUG,"MkUniquePath(%s) - Found unique filename: %s.", 
  1565. cFnameBuf, cBuf);
  1566. cFnameBuf = cBuf;
  1567. return TRUE;
  1568. }
  1569. BOOL CFTPDCoreCtrlSock::DoDele(CCmdArgs& Args)
  1570. {
  1571. if (m_UnixArgs.m_argc != 2)
  1572. {
  1573. LogMsg(LOGF_DEBUG,"DoDele() - Ambigous %s command: %s", Args[0], m_UnixArgs[1]);
  1574. SendMsg(550,"Ambigous %s command: %s", Args[0], m_UnixArgs[1]);
  1575. return TRUE;
  1576. }
  1577. if (!m_Fsys->DeleteGeneric(m_UnixArgs[1]))
  1578. {
  1579. LogMsg(LOGF_DEBUG,"DoDele() - Failed to delete before callback: %s", Args[1]);
  1580. SendMsg(550,"Server error. Failed to delete.");
  1581. return TRUE;
  1582. }
  1583. return TRUE;
  1584. }
  1585. BOOL CFTPDCoreCtrlSock::DoMkDir(CCmdArgs& Args)
  1586. {
  1587. if (!m_Fsys->CreateDirectory(Args[1]))
  1588. {
  1589. LogMsg(LOGF_DEBUG,"DoMkDir() - Failed to create directory before callback: %s", Args.Arg(1));
  1590. SendMsg(550,"Server error. Failed to cerate directory.");
  1591. }
  1592. return TRUE;
  1593. }
  1594. BOOL CFTPDCoreCtrlSock::OnSiteChmod(CCmdArgs &Args)
  1595. {
  1596. CCmdArgs MyArgs("chmod", Args[2], m_Parser);
  1597. if (!m_Fsys->ChMod(MyArgs))
  1598. {
  1599. SendMsg(451, "chmod failed.");
  1600. LogMsg(LOGF_WARNINGS,"chmod failed before callback");
  1601. }
  1602. return TRUE;
  1603. }
  1604. BOOL CFTPDCoreCtrlSock::OnSiteFsysstat(CCmdArgs &Args)
  1605. {
  1606. CCmdArgs MyArgs("chmod", Args[2], m_Parser);
  1607. if (!m_Fsys->FsysStat())
  1608. {
  1609. SendMsg(451, "Site Fsysstat failed.");
  1610. LogMsg(LOGF_WARNINGS,"OnSiteFsysstat failed before callback");
  1611. }
  1612. return TRUE;
  1613. }
  1614. //////////////////////////////////////////////////////////////////////////////////////////
  1615. // CFTPDFsys
  1616. CFTPDFsys::CFTPDFsys(LPVOID *pRef)
  1617. :CUserFsys(pRef)
  1618. {
  1619. ;
  1620. }
  1621. BOOL CFTPDFsys::SetOnHold()
  1622. {
  1623. m_AsyncSelectMaskSaved = m_pSock->m_AsyncSelectMask;
  1624. m_StateSaved = m_pSock->m_State;
  1625. // Prevent socket read/write events
  1626. m_pSock->m_AsyncSelectMask &= ~(FD_READ | FD_WRITE);
  1627. m_pSock->AsyncSelect(m_pSock->m_AsyncSelectMask);
  1628. // Set block state
  1629. m_pSock->m_State = HOLD;
  1630. return TRUE;
  1631. }
  1632. void CFTPDFsys::ReleaseHold()
  1633. {
  1634. m_pSock->m_State = m_StateSaved;
  1635. m_pSock->m_AsyncSelectMask = m_AsyncSelectMaskSaved;
  1636. m_pSock->AsyncSelect(m_pSock->m_AsyncSelectMask);
  1637. }
  1638. void CFTPDFsys::CheckForZombie()
  1639. {
  1640. CUserFsys::CheckForZombie();
  1641. }
  1642. BOOL CFTPDFsys::Create(CFTPDCoreCtrlSock *pSock)
  1643. {
  1644. ASSERT(m_pRef != NULL);
  1645. m_pSock = pSock;
  1646. m_IsAdmin = CUsr::IsAdmin(m_pSock->m_User);
  1647. USER Class = CUsr::GetUserClass(m_pSock->m_User);
  1648. CString Roots, Home;
  1649. CString AssignToName;
  1650. CString UmaskStr;
  1651. USER AssignTo = INVALID_USER_VALUE;
  1652. DWORD Umask = 0;
  1653. CUsr::GetRecursiveParam(m_pSock->m_User, "root", "", Roots);
  1654. CUsr::GetRecursiveParam(m_pSock->m_User, "home", "", Home);
  1655. CUsr::GetRecursiveParam(m_pSock->m_User, "AssignFilesTo", "", AssignToName);
  1656. CUsr::GetRecursiveParam(m_pSock->m_User, "Umask", "", UmaskStr);
  1657. sscanf(UmaskStr, "%o", &Umask);
  1658. if (!AssignToName.IsEmpty())
  1659. AssignTo = CUsr::FindUser(UT_USER, (LPCSTR)AssignToName);
  1660. return CUserFsys::Create(Roots, Home, m_pSock->m_User, Class, pSock->m_SocketName, Umask, AssignTo);
  1661. }
  1662. // Called after the file system is initialized
  1663. // for the user
  1664. BOOL CFTPDFsys::OnCreate(int nErrorCode)
  1665. {
  1666. CUserFsys::OnCreate(nErrorCode);
  1667. if (nErrorCode)
  1668. {
  1669. m_pSock->SendMsg(421, "Internal error - unable to initialize your file system. Goodbye");
  1670. m_pSock->LogMsg(LOGF_ERROR,"Unable to initialize the users file system.");
  1671. delete m_pSock;
  1672. return FALSE;
  1673. }
  1674. m_pSock->m_State = PROCESS;
  1675. return TRUE;
  1676. }
  1677. /////////////////////////////////////////////////////////////////////////////////////
  1678. // High level calls for CFTPDFsys
  1679. BOOL CFTPDFsys::PrepereCommandLine(int CmdIDtoRemember)
  1680. {
  1681. m_FsysPath1.Empty();
  1682. m_lParam = (LPARAM)CmdIDtoRemember;
  1683. for(int Index = 0; Index < m_pSock->m_Args.m_argc; Index++)
  1684. {
  1685. if (!m_FsysPath1.IsEmpty())
  1686. m_FsysPath1 += 'n';
  1687. m_FsysPath1 += m_pSock->m_Args[Index];
  1688. }
  1689. return ProcessRequest(FSM_PRPCMDLINE, (WPARAM)this, 0);
  1690. }
  1691. BOOL CFTPDFsys::OnPrpCmdLine(int nErrorCode)
  1692. {
  1693. LPSTR p = m_FsysPath1.GetBuffer(1);
  1694. for(p = strtok(p, "n"); p; p = strtok(NULL, "n"))
  1695. {
  1696. m_pSock->m_UnixArgs.AddArg(p);
  1697. }
  1698. return m_pSock->OnCommand((int)m_lParam);
  1699. }
  1700. BOOL CFTPDFsys::List()
  1701. {
  1702. m_FsysPath1.Empty();
  1703. for(int Index = 0; Index < m_pSock->m_UnixArgs.m_argc; Index++)
  1704. {
  1705. if (!m_FsysPath1.IsEmpty())
  1706. m_FsysPath1 += 'n';
  1707. m_FsysPath1 += m_pSock->m_UnixArgs.Arg(Index);
  1708. }
  1709. return ProcessRequest(FSM_LIST, (WPARAM)this, 0);
  1710. }
  1711. BOOL CFTPDFsys::OnList(int nErrorCode)
  1712. {
  1713. return m_pSock->CallbackProcessList(nErrorCode);
  1714. }
  1715. CString CFTPDFsys::GetFullPath(LPCSTR Path, DWORD AccessFlags)
  1716. {
  1717. ASSERT(FALSE);
  1718. return "/";
  1719. }
  1720. BOOL CFTPDFsys::RenamePath(LPCSTR OldName, LPCSTR NewName)
  1721. {
  1722. return TRUE;
  1723. }
  1724. BOOL CFTPDFsys::CheckPermission(LPCSTR Path, BOOL IsDir, int PermsWanted)
  1725. {
  1726. return TRUE;
  1727. }
  1728. BOOL CFTPDFsys::ChDir(LPCSTR Path)
  1729. {
  1730. m_CallbackID = CB_CHDIR;
  1731. return CUserFsys::ChDir(Path);
  1732. }
  1733. BOOL CFTPDFsys::Mdtm(LPCSTR Path)
  1734. {
  1735. m_CallbackID = CB_MDTM;
  1736. return CUserFsys::Stat(Path);
  1737. }
  1738. BOOL CFTPDFsys::Size(LPCSTR Path)
  1739. {
  1740. m_CallbackID = CB_SIZE;
  1741. return CUserFsys::Stat(Path);
  1742. }
  1743. BOOL CFTPDFsys::OnChdir(int nErrorCode)
  1744. {
  1745. switch(m_CallbackID)
  1746. {
  1747. case CB_CHDIR:
  1748. return CallbackChDir(nErrorCode);
  1749. }
  1750. return CUserFsys::OnChdir(nErrorCode);
  1751. }
  1752. BOOL CFTPDFsys::CallbackChDir(int nErrorCode)
  1753. {
  1754. if (nErrorCode)
  1755. {
  1756. m_pSock->SendMsg(550, "Permission denied.");
  1757. }
  1758. else
  1759. {
  1760. m_pSock->SendMsg(250, ""%s" is current directory.", m_CWD);
  1761. }
  1762. return nErrorCode == 0;
  1763. }
  1764. BOOL CFTPDFsys::OnChmod(int nErrorCode)
  1765. {
  1766. if (nErrorCode && m_Output.IsEmpty())
  1767. {
  1768. m_pSock->SendMsg(551, "chmod failed.");
  1769. m_pSock->LogMsg(LOGF_WARNINGS,"chmod failed after callback, error %d", nErrorCode);
  1770. }
  1771. else
  1772. {
  1773. m_pSock->SuspendMacros();
  1774. m_pSock->SendMsg(200, "chmod: %s", m_Output);
  1775. m_pSock->EnableMacros();
  1776. }
  1777. return TRUE;
  1778. }
  1779. BOOL CFTPDFsys::OnFsysStat(int nErrorCode)
  1780. {
  1781. if (nErrorCode && m_Output.IsEmpty())
  1782. {
  1783. m_pSock->SendMsg(551, "SITE FSYSSTAT failed.");
  1784. m_pSock->LogMsg(LOGF_WARNINGS,"OnFsysStat failed after callback, error %d", nErrorCode);
  1785. }
  1786. else
  1787. {
  1788. m_pSock->SuspendMacros();
  1789. m_pSock->SendMsg(200, "%s", m_Output);
  1790. m_pSock->EnableMacros();
  1791. }
  1792. return TRUE;
  1793. }
  1794. BOOL CFTPDFsys::OnCreateDirectory(int nErrorCode)
  1795. {
  1796. if (nErrorCode && m_Output.IsEmpty())
  1797. {
  1798. m_pSock->SendMsg(551, "Permission denied.");
  1799. m_pSock->LogMsg(LOGF_WARNINGS,"OnCreateDirectory failed after callback, error %d", nErrorCode);
  1800. }
  1801. else
  1802. {
  1803. m_pSock->SendMsg(257, "Directory created");
  1804. }
  1805. return TRUE;
  1806. }
  1807. BOOL CFTPDFsys::OnDeleteDirectory(int nErrorCode)
  1808. {
  1809. return OnDelete(nErrorCode);
  1810. }
  1811. BOOL CFTPDFsys::OnDeleteFile(int nErrorCode)
  1812. {
  1813. return OnDelete(nErrorCode);
  1814. }
  1815. BOOL CFTPDFsys::OnDeleteGeneric(int nErrorCode)
  1816. {
  1817. return OnDelete(nErrorCode);
  1818. }
  1819. BOOL CFTPDFsys::OnDelete(int nErrorCode)
  1820. {
  1821. if (nErrorCode && m_Output.IsEmpty())
  1822. {
  1823. m_pSock->SendMsg(551, "Permission denied.");
  1824. m_pSock->LogMsg(LOGF_WARNINGS,"OnDelete failed after callback, error %d", nErrorCode);
  1825. }
  1826. else
  1827. {
  1828. m_pSock->SendMsg(250, "%s is deleted", m_FsysPath1);
  1829. }
  1830. return TRUE;
  1831. }
  1832. BOOL CFTPDFsys::OnMoveFile(int nErrorCode)
  1833. {
  1834. if (nErrorCode && m_Output.IsEmpty())
  1835. {
  1836. m_pSock->SendMsg(551, "Permission denied.");
  1837. m_pSock->LogMsg(LOGF_WARNINGS,"OnDelete failed after callback, error %d", nErrorCode);
  1838. }
  1839. else
  1840. {
  1841. m_pSock->LogMsg(LOGF_FILEACC,"Renamed/moved %s to %s",m_FsysPath1, m_FsysPath2);
  1842. m_pSock->SendMsg(250,"RNTO command successful.");
  1843. }
  1844. return TRUE;
  1845. }
  1846. BOOL CFTPDFsys::OnStat(int nErrorCode)
  1847. {
  1848. switch(m_CallbackID)
  1849. {
  1850. case CB_SIZE:
  1851. return OnStatSize(nErrorCode);
  1852. case CB_MDTM:
  1853. return OnStatMDTM(nErrorCode);
  1854. }
  1855. return FALSE;
  1856. }
  1857. BOOL CFTPDFsys::OnStatSize(int nErrorCode)
  1858. {
  1859. char buf[32];
  1860. if (nErrorCode)
  1861. {
  1862. m_pSock->SendMsg(551, "Permission denied.");
  1863. m_pSock->LogMsg(LOGF_WARNINGS,"OnStatSize failed after callback, error %d", nErrorCode);
  1864. return TRUE;
  1865. }
  1866. if (m_FilePerms & NODE_DIR)
  1867. {
  1868. m_pSock->LogMsg(LOGF_DEBUG,"OnStatSize() - Not a plain file.");
  1869. m_pSock->SendMsg(550, "%s: not a plain file.", m_FsysPath1);
  1870. return TRUE;
  1871. }
  1872. sprintf(buf,"%I64d", m_FileLen);
  1873. m_pSock->SendMsg(213, "%s", buf);
  1874. return TRUE;
  1875. }
  1876. BOOL CFTPDFsys::OnStatMDTM(int nErrorCode)
  1877. {
  1878. if (nErrorCode)
  1879. {
  1880. m_pSock->SendMsg(551, "Permission denied.");
  1881. m_pSock->LogMsg(LOGF_WARNINGS,"OnStatMDTM failed after callback, error %d", nErrorCode);
  1882. return TRUE;
  1883. }
  1884. if (m_FilePerms & NODE_DIR)
  1885. {
  1886. m_pSock->LogMsg(LOGF_DEBUG,"OnMdtm() - Not a plain file.");
  1887. m_pSock->SendMsg(550, "%s: not a plain file.", m_FsysPath1);
  1888. return TRUE;
  1889. }
  1890. FILETIME lt;
  1891. SYSTEMTIME st;
  1892. FileTimeToLocalFileTime(&m_FileTime,&lt);
  1893. FileTimeToSystemTime(&lt,&st);
  1894. m_pSock->SendMsg(213, "%04d%02d%02d%02d%02d%02d.%d",
  1895. st.wYear,
  1896. st.wMonth,
  1897. st.wDay,
  1898. st.wHour,
  1899. st.wMinute,
  1900. st.wSecond,
  1901. st.wMilliseconds);
  1902. return TRUE;
  1903. }