POP3Svr.cpp
上传用户:woshihumen
上传日期:2013-07-18
资源大小:484k
文件大小:33k
源码类别:

Email服务器

开发平台:

Visual C++

  1. /*
  2.  *  XMail by Davide Libenzi ( Intranet and Internet mail server )
  3.  *  Copyright (C) 1999,..,2004  Davide Libenzi
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  *
  19.  *  Davide Libenzi <davidel@xmailserver.org>
  20.  *
  21.  */
  22. #include "SysInclude.h"
  23. #include "SysDep.h"
  24. #include "SvrDefines.h"
  25. #include "ShBlocks.h"
  26. #include "SList.h"
  27. #include "BuffSock.h"
  28. #include "ResLocks.h"
  29. #include "MiscUtils.h"
  30. #include "StrUtils.h"
  31. #include "MD5.h"
  32. #include "SvrUtils.h"
  33. #include "UsrUtils.h"
  34. #include "UsrAuth.h"
  35. #include "POP3Svr.h"
  36. #include "POP3Utils.h"
  37. #include "MessQueue.h"
  38. #include "MailDomains.h"
  39. #include "MailConfig.h"
  40. #include "AppDefines.h"
  41. #include "MailSvr.h"
  42. #define POP3SRV_ACCEPT_TIMEOUT  4
  43. #define STD_POP3_TIMEOUT        30
  44. #define POP3_LISTEN_SIZE        64
  45. #define POP3_WAIT_SLEEP         2
  46. #define MAX_CLIENTS_WAIT        300
  47. #define POP3_IPMAP_FILE         "pop3.ipmap.tab"
  48. #define POP3_LOG_FILE           "pop3"
  49. #define POP3_SERVER_NAME        "[" APP_NAME_VERSION_STR " POP3 Server]"
  50. enum POP3States {
  51. stateInit,
  52. stateUser,
  53. stateLogged,
  54. stateExit
  55. };
  56. struct POP3Session {
  57. int iPOP3State;
  58. SHB_HANDLE hShbPOP3;
  59. POP3Config *pPOP3Cfg;
  60. SVRCFG_HANDLE hSvrConfig;
  61. int iBadLoginWait;
  62. SYS_INET_ADDR PeerInfo;
  63. char szSvrFQDN[MAX_HOST_NAME];
  64. char szSvrDomain[MAX_HOST_NAME];
  65. char szUser[MAX_ADDR_NAME];
  66. char szPassword[256];
  67. POP3_HANDLE hPOPSession;
  68. char szTimeStamp[256];
  69. };
  70. static POP3Config *POP3GetConfigCopy(SHB_HANDLE hShbPOP3);
  71. static int POP3ThreadCountAdd(long lCount, SHB_HANDLE hShbPOP3, POP3Config * pPOP3Cfg = NULL);
  72. static int POP3LogEnabled(SHB_HANDLE hShbPOP3, POP3Config * pPOP3Cfg = NULL);
  73. static int POP3CheckPeerIP(SYS_SOCKET SockFD);
  74. static unsigned int POP3ClientThread(void *pThreadData);
  75. static int POP3CheckSysResources(SVRCFG_HANDLE hSvrConfig);
  76. static int POP3InitSession(SHB_HANDLE hShbPOP3, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  77. static int POP3LogSession(POP3Session & POP3S);
  78. static int POP3HandleSession(SHB_HANDLE hShbPOP3, BSOCK_HANDLE hBSock);
  79. static void POP3ClearSession(POP3Session & POP3S);
  80. static int POP3HandleCommand(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  81. static int POP3HandleCmd_USER(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  82. static int POP3HandleBadLogin(BSOCK_HANDLE hBSock, POP3Session & POP3S);
  83. static int POP3HandleCmd_PASS(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  84. static int POP3HandleCmd_APOP(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  85. static int POP3HandleCmd_STAT(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  86. static int POP3HandleCmd_LIST(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  87. static int POP3HandleCmd_UIDL(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  88. static int POP3HandleCmd_QUIT(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  89. static int POP3HandleCmd_RETR(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  90. static int POP3HandleCmd_TOP(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  91. static int POP3HandleCmd_DELE(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  92. static int POP3HandleCmd_NOOP(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  93. static int POP3HandleCmd_LAST(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  94. static int POP3HandleCmd_RSET(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S);
  95. static POP3Config *POP3GetConfigCopy(SHB_HANDLE hShbPOP3)
  96. {
  97. POP3Config *pPOP3Cfg = (POP3Config *) ShbLock(hShbPOP3);
  98. if (pPOP3Cfg == NULL)
  99. return (NULL);
  100. POP3Config *pPOP3CfgCopy = (POP3Config *) SysAlloc(sizeof(POP3Config));
  101. if (pPOP3CfgCopy != NULL)
  102. memcpy(pPOP3CfgCopy, pPOP3Cfg, sizeof(POP3Config));
  103. ShbUnlock(hShbPOP3);
  104. return (pPOP3CfgCopy);
  105. }
  106. static int POP3ThreadCountAdd(long lCount, SHB_HANDLE hShbPOP3, POP3Config * pPOP3Cfg)
  107. {
  108. int iDoUnlock = 0;
  109. if (pPOP3Cfg == NULL) {
  110. if ((pPOP3Cfg = (POP3Config *) ShbLock(hShbPOP3)) == NULL)
  111. return (ErrGetErrorCode());
  112. ++iDoUnlock;
  113. }
  114. if ((pPOP3Cfg->lThreadCount + lCount) > pPOP3Cfg->lMaxThreads) {
  115. if (iDoUnlock)
  116. ShbUnlock(hShbPOP3);
  117. ErrSetErrorCode(ERR_SERVER_BUSY);
  118. return (ERR_SERVER_BUSY);
  119. }
  120. pPOP3Cfg->lThreadCount += lCount;
  121. if (iDoUnlock)
  122. ShbUnlock(hShbPOP3);
  123. return (0);
  124. }
  125. static int POP3LogEnabled(SHB_HANDLE hShbPOP3, POP3Config * pPOP3Cfg)
  126. {
  127. int iDoUnlock = 0;
  128. if (pPOP3Cfg == NULL) {
  129. if ((pPOP3Cfg = (POP3Config *) ShbLock(hShbPOP3)) == NULL)
  130. return (ErrGetErrorCode());
  131. ++iDoUnlock;
  132. }
  133. unsigned long ulFlags = pPOP3Cfg->ulFlags;
  134. if (iDoUnlock)
  135. ShbUnlock(hShbPOP3);
  136. return ((ulFlags & POP3F_LOG_ENABLED) ? 1 : 0);
  137. }
  138. static int POP3CheckPeerIP(SYS_SOCKET SockFD)
  139. {
  140. char szIPMapFile[SYS_MAX_PATH] = "";
  141. CfgGetRootPath(szIPMapFile, sizeof(szIPMapFile));
  142. StrNCat(szIPMapFile, POP3_IPMAP_FILE, sizeof(szIPMapFile));
  143. if (SysExistFile(szIPMapFile)) {
  144. SYS_INET_ADDR PeerInfo;
  145. if (SysGetPeerInfo(SockFD, PeerInfo) < 0)
  146. return (ErrGetErrorCode());
  147. if (MscCheckAllowedIP(szIPMapFile, PeerInfo, true) < 0)
  148. return (ErrGetErrorCode());
  149. }
  150. return (0);
  151. }
  152. static unsigned int POP3ClientThread(void *pThreadData)
  153. {
  154. SYS_SOCKET SockFD = (SYS_SOCKET) (unsigned long) pThreadData;
  155. ///////////////////////////////////////////////////////////////////////////////
  156. //  Link socket to the bufferer
  157. ///////////////////////////////////////////////////////////////////////////////
  158. BSOCK_HANDLE hBSock = BSckAttach(SockFD);
  159. if (hBSock == INVALID_BSOCK_HANDLE) {
  160. ErrorPush();
  161. SysLogMessage(LOG_LEV_ERROR, "%sn", ErrGetErrorString());
  162. SysCloseSocket(SockFD);
  163. return (ErrorPop());
  164. }
  165. ///////////////////////////////////////////////////////////////////////////////
  166. //  Check IP permission
  167. ///////////////////////////////////////////////////////////////////////////////
  168. if (POP3CheckPeerIP(SockFD) < 0) {
  169. ErrorPush();
  170. UPopSendErrorResponse(hBSock, ErrGetErrorCode(), STD_POP3_TIMEOUT);
  171. BSckDetach(hBSock, 1);
  172. return (ErrorPop());
  173. }
  174. ///////////////////////////////////////////////////////////////////////////////
  175. //  Increase threads count
  176. ///////////////////////////////////////////////////////////////////////////////
  177. if (POP3ThreadCountAdd(+1, hShbPOP3) < 0) {
  178. ErrorPush();
  179. UPopSendErrorResponse(hBSock, ErrGetErrorCode(), STD_POP3_TIMEOUT);
  180. BSckDetach(hBSock, 1);
  181. return (ErrorPop());
  182. }
  183. ///////////////////////////////////////////////////////////////////////////////
  184. //  Handle client session
  185. ///////////////////////////////////////////////////////////////////////////////
  186. POP3HandleSession(hShbPOP3, hBSock);
  187. ///////////////////////////////////////////////////////////////////////////////
  188. //  Decrease thread count
  189. ///////////////////////////////////////////////////////////////////////////////
  190. POP3ThreadCountAdd(-1, hShbPOP3);
  191. ///////////////////////////////////////////////////////////////////////////////
  192. //  Unlink socket to the bufferer and close it
  193. ///////////////////////////////////////////////////////////////////////////////
  194. BSckDetach(hBSock, 1);
  195. return (0);
  196. }
  197. unsigned int POP3ThreadProc(void *pThreadData)
  198. {
  199. POP3Config *pPOP3Cfg = (POP3Config *) ShbLock(hShbPOP3);
  200. if (pPOP3Cfg == NULL) {
  201. ErrorPush();
  202. SysLogMessage(LOG_LEV_ERROR, "%sn", ErrGetErrorString());
  203. return (ErrorPop());
  204. }
  205. int iNumSockFDs = 0;
  206. SYS_SOCKET SockFDs[MAX_POP3_ACCEPT_ADDRESSES];
  207. if (MscCreateServerSockets(pPOP3Cfg->iNumAddr, pPOP3Cfg->SvrAddr, pPOP3Cfg->iPort,
  208.    POP3_LISTEN_SIZE, SockFDs, iNumSockFDs) < 0) {
  209. ErrorPush();
  210. SysLogMessage(LOG_LEV_ERROR, "%sn", ErrGetErrorString());
  211. ShbUnlock(hShbPOP3);
  212. return (ErrorPop());
  213. }
  214. ShbUnlock(hShbPOP3);
  215. SysLogMessage(LOG_LEV_MESSAGE, "%s startedn", POP3_SERVER_NAME);
  216. for (;;) {
  217. int iNumConnSockFD = 0;
  218. SYS_SOCKET ConnSockFD[MAX_POP3_ACCEPT_ADDRESSES];
  219. if (MscAcceptServerConnection(SockFDs, iNumSockFDs, ConnSockFD,
  220.       iNumConnSockFD, POP3SRV_ACCEPT_TIMEOUT) < 0) {
  221. unsigned long ulFlags = POP3F_STOP_SERVER;
  222. pPOP3Cfg = (POP3Config *) ShbLock(hShbPOP3);
  223. if (pPOP3Cfg != NULL)
  224. ulFlags = pPOP3Cfg->ulFlags;
  225. ShbUnlock(hShbPOP3);
  226. if (ulFlags & POP3F_STOP_SERVER)
  227. break;
  228. else
  229. continue;
  230. }
  231. for (int ss = 0; ss < iNumConnSockFD; ss++) {
  232. SYS_THREAD hClientThread =
  233.     SysCreateServiceThread(POP3ClientThread, ConnSockFD[ss]);
  234. if (hClientThread != SYS_INVALID_THREAD)
  235. SysCloseThread(hClientThread, 0);
  236. else
  237. SysCloseSocket(ConnSockFD[ss]);
  238. }
  239. }
  240. for (int ss = 0; ss < iNumSockFDs; ss++)
  241. SysCloseSocket(SockFDs[ss]);
  242. ///////////////////////////////////////////////////////////////////////////////
  243. //  Wait for client completion
  244. ///////////////////////////////////////////////////////////////////////////////
  245. for (int iTotalWait = 0; (iTotalWait < MAX_CLIENTS_WAIT); iTotalWait += POP3_WAIT_SLEEP) {
  246. pPOP3Cfg = (POP3Config *) ShbLock(hShbPOP3);
  247. if (pPOP3Cfg == NULL)
  248. break;
  249. long lThreadCount = pPOP3Cfg->lThreadCount;
  250. ShbUnlock(hShbPOP3);
  251. if (lThreadCount == 0)
  252. break;
  253. SysSleep(POP3_WAIT_SLEEP);
  254. }
  255. SysLogMessage(LOG_LEV_MESSAGE, "%s stoppedn", POP3_SERVER_NAME);
  256. return (0);
  257. }
  258. static int POP3CheckSysResources(SVRCFG_HANDLE hSvrConfig)
  259. {
  260. ///////////////////////////////////////////////////////////////////////////////
  261. //  Check virtual memory
  262. ///////////////////////////////////////////////////////////////////////////////
  263. int iMinValue = SvrGetConfigInt("Pop3MinVirtMemSpace", -1, hSvrConfig);
  264. if ((iMinValue > 0) && (SvrCheckVirtMemSpace(1024 * (unsigned long) iMinValue) < 0))
  265. return (ErrGetErrorCode());
  266. return (0);
  267. }
  268. static int POP3InitSession(SHB_HANDLE hShbPOP3, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  269. {
  270. ZeroData(POP3S);
  271. POP3S.iPOP3State = stateInit;
  272. POP3S.hShbPOP3 = hShbPOP3;
  273. POP3S.hSvrConfig = INVALID_SVRCFG_HANDLE;
  274. POP3S.pPOP3Cfg = NULL;
  275. POP3S.hPOPSession = INVALID_POP3_HANDLE;
  276. if ((POP3S.hSvrConfig = SvrGetConfigHandle()) == INVALID_SVRCFG_HANDLE)
  277. return (ErrGetErrorCode());
  278. if ((POP3CheckSysResources(POP3S.hSvrConfig) < 0) ||
  279.     (SysGetPeerInfo(BSckGetAttachedSocket(hBSock), POP3S.PeerInfo) < 0)) {
  280. SvrReleaseConfigHandle(POP3S.hSvrConfig);
  281. return (ErrGetErrorCode());
  282. }
  283. ///////////////////////////////////////////////////////////////////////////////
  284. //  Get connection socket host name
  285. ///////////////////////////////////////////////////////////////////////////////
  286. char szIP[128] = "???.???.???.???";
  287. if (MscGetSockHost(BSckGetAttachedSocket(hBSock), POP3S.szSvrFQDN) < 0)
  288. StrSNCpy(POP3S.szSvrFQDN, SysInetNToA(POP3S.PeerInfo, szIP));
  289. else {
  290. ///////////////////////////////////////////////////////////////////////////////
  291. //  Try to get a valid domain from the FQDN
  292. ///////////////////////////////////////////////////////////////////////////////
  293. if (MDomGetClientDomain(POP3S.szSvrFQDN, POP3S.szSvrDomain,
  294. sizeof(POP3S.szSvrDomain) - 1) < 0)
  295. StrSNCpy(POP3S.szSvrDomain, POP3S.szSvrFQDN);
  296. }
  297. ///////////////////////////////////////////////////////////////////////////////
  298. //  If "POP3Domain" is defined, it's taken as default POP3 domain that means
  299. //  that users of such domain can log using only the name part of their email
  300. //  address
  301. ///////////////////////////////////////////////////////////////////////////////
  302. char *pszDefDomain = SvrGetConfigVar(POP3S.hSvrConfig, "POP3Domain");
  303. if (pszDefDomain != NULL) {
  304. StrSNCpy(POP3S.szSvrDomain, pszDefDomain);
  305. SysFree(pszDefDomain);
  306. }
  307. ///////////////////////////////////////////////////////////////////////////////
  308. //  As a last tentative We try to get "RootDomain" to set POP3 domain
  309. ///////////////////////////////////////////////////////////////////////////////
  310. if (IsEmptyString(POP3S.szSvrDomain)) {
  311. char *pszRootDomain = SvrGetConfigVar(POP3S.hSvrConfig, "RootDomain");
  312. if (pszRootDomain == NULL) {
  313. SvrReleaseConfigHandle(POP3S.hSvrConfig);
  314. ErrSetErrorCode(ERR_NO_DOMAIN);
  315. return (ERR_NO_DOMAIN);
  316. }
  317. StrSNCpy(POP3S.szSvrDomain, pszRootDomain);
  318. SysFree(pszRootDomain);
  319. }
  320. if ((POP3S.pPOP3Cfg = POP3GetConfigCopy(hShbPOP3)) == NULL) {
  321. SvrReleaseConfigHandle(POP3S.hSvrConfig);
  322. return (ErrGetErrorCode());
  323. }
  324. POP3S.iBadLoginWait = POP3S.pPOP3Cfg->iBadLoginWait;
  325. ///////////////////////////////////////////////////////////////////////////////
  326. //  Create timestamp for APOP command
  327. ///////////////////////////////////////////////////////////////////////////////
  328. sprintf(POP3S.szTimeStamp, "<%lu.%lu@%s>",
  329. (unsigned long) time(NULL), SysGetCurrentThreadId(), POP3S.szSvrDomain);
  330. return (0);
  331. }
  332. static int POP3LogSession(POP3Session & POP3S)
  333. {
  334. char szTime[256] = "";
  335. MscGetTimeNbrString(szTime, sizeof(szTime) - 1);
  336. RLCK_HANDLE hResLock = RLckLockEX(SVR_LOGS_DIR SYS_SLASH_STR POP3_LOG_FILE);
  337. if (hResLock == INVALID_RLCK_HANDLE)
  338. return (ErrGetErrorCode());
  339. char szIP[128] = "???.???.???.???";
  340. MscFileLog(POP3_LOG_FILE, ""%s""
  341.    "t"%s""
  342.    "t"%s""
  343.    "t"%s""
  344.    "t"%s""
  345.    "t"%s""
  346.    "n", POP3S.szSvrFQDN, POP3S.szSvrDomain, SysInetNToA(POP3S.PeerInfo, szIP),
  347.    szTime, POP3S.szUser, POP3S.szPassword);
  348. RLckUnlockEX(hResLock);
  349. return (0);
  350. }
  351. static int POP3HandleSession(SHB_HANDLE hShbPOP3, BSOCK_HANDLE hBSock)
  352. {
  353. ///////////////////////////////////////////////////////////////////////////////
  354. //  Session structure declaration and init
  355. ///////////////////////////////////////////////////////////////////////////////
  356. POP3Session POP3S;
  357. if (POP3InitSession(hShbPOP3, hBSock, POP3S) < 0) {
  358. ErrorPush();
  359. UPopSendErrorResponse(hBSock, ErrGetErrorCode(), STD_POP3_TIMEOUT);
  360. return (ErrorPop());
  361. }
  362. char szIP[128] = "???.???.???.???";
  363. SysLogMessage(LOG_LEV_MESSAGE, "POP3 client connection from [%s]n",
  364.       SysInetNToA(POP3S.PeerInfo, szIP));
  365. ///////////////////////////////////////////////////////////////////////////////
  366. //  Send welcome message
  367. ///////////////////////////////////////////////////////////////////////////////
  368. char szTime[256] = "";
  369. MscGetTimeStr(szTime, sizeof(szTime) - 1);
  370. if (BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout,
  371.     "+OK %s %s service ready; %s", POP3S.szTimeStamp,
  372.     POP3_SERVER_NAME, szTime) < 0) {
  373. POP3ClearSession(POP3S);
  374. return (ErrGetErrorCode());
  375. }
  376. ///////////////////////////////////////////////////////////////////////////////
  377. //  Command loop
  378. ///////////////////////////////////////////////////////////////////////////////
  379. char szCommand[1024] = "";
  380. while (!SvrInShutdown() && (POP3S.iPOP3State != stateExit) &&
  381.        (BSckGetString(hBSock, szCommand, sizeof(szCommand) - 1,
  382.       POP3S.pPOP3Cfg->iSessionTimeout) != NULL) &&
  383.        (MscCmdStringCheck(szCommand) == 0)) {
  384. ///////////////////////////////////////////////////////////////////////////////
  385. //  Retrieve a fresh new copy of configuration and test shutdown flag
  386. ///////////////////////////////////////////////////////////////////////////////
  387. SysFree(POP3S.pPOP3Cfg);
  388. POP3S.pPOP3Cfg = POP3GetConfigCopy(hShbPOP3);
  389. if ((POP3S.pPOP3Cfg == NULL) || (POP3S.pPOP3Cfg->ulFlags & POP3F_STOP_SERVER))
  390. break;
  391. ///////////////////////////////////////////////////////////////////////////////
  392. //  Handle coomand
  393. ///////////////////////////////////////////////////////////////////////////////
  394. POP3HandleCommand(szCommand, hBSock, POP3S);
  395. }
  396. SysLogMessage(LOG_LEV_MESSAGE, "POP3 client exit [%s]n",
  397.       SysInetNToA(POP3S.PeerInfo, szIP));
  398. POP3ClearSession(POP3S);
  399. return (0);
  400. }
  401. static void POP3ClearSession(POP3Session & POP3S)
  402. {
  403. if (POP3S.hPOPSession != INVALID_POP3_HANDLE) {
  404. UPopReleaseSession(POP3S.hPOPSession, (POP3S.iPOP3State == stateExit) ? 1 : 0);
  405. POP3S.hPOPSession = INVALID_POP3_HANDLE;
  406. }
  407. if (POP3S.hSvrConfig != INVALID_SVRCFG_HANDLE)
  408. SvrReleaseConfigHandle(POP3S.hSvrConfig), POP3S.hSvrConfig =
  409.     INVALID_SVRCFG_HANDLE;
  410. if (POP3S.pPOP3Cfg != NULL)
  411. SysFree(POP3S.pPOP3Cfg), POP3S.pPOP3Cfg = NULL;
  412. }
  413. static int POP3HandleCommand(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  414. {
  415. int iCmdResult = -1;
  416. if (StrCmdMatch(pszCommand, "USER"))
  417. iCmdResult = POP3HandleCmd_USER(pszCommand, hBSock, POP3S);
  418. else if (StrCmdMatch(pszCommand, "PASS"))
  419. iCmdResult = POP3HandleCmd_PASS(pszCommand, hBSock, POP3S);
  420. else if (StrCmdMatch(pszCommand, "APOP"))
  421. iCmdResult = POP3HandleCmd_APOP(pszCommand, hBSock, POP3S);
  422. else if (StrCmdMatch(pszCommand, "STAT"))
  423. iCmdResult = POP3HandleCmd_STAT(pszCommand, hBSock, POP3S);
  424. else if (StrCmdMatch(pszCommand, "LIST"))
  425. iCmdResult = POP3HandleCmd_LIST(pszCommand, hBSock, POP3S);
  426. else if (StrCmdMatch(pszCommand, "UIDL"))
  427. iCmdResult = POP3HandleCmd_UIDL(pszCommand, hBSock, POP3S);
  428. else if (StrCmdMatch(pszCommand, "QUIT"))
  429. iCmdResult = POP3HandleCmd_QUIT(pszCommand, hBSock, POP3S);
  430. else if (StrCmdMatch(pszCommand, "RETR"))
  431. iCmdResult = POP3HandleCmd_RETR(pszCommand, hBSock, POP3S);
  432. else if (StrCmdMatch(pszCommand, "TOP"))
  433. iCmdResult = POP3HandleCmd_TOP(pszCommand, hBSock, POP3S);
  434. else if (StrCmdMatch(pszCommand, "DELE"))
  435. iCmdResult = POP3HandleCmd_DELE(pszCommand, hBSock, POP3S);
  436. else if (StrCmdMatch(pszCommand, "NOOP"))
  437. iCmdResult = POP3HandleCmd_NOOP(pszCommand, hBSock, POP3S);
  438. else if (StrCmdMatch(pszCommand, "LAST"))
  439. iCmdResult = POP3HandleCmd_LAST(pszCommand, hBSock, POP3S);
  440. else if (StrCmdMatch(pszCommand, "RSET"))
  441. iCmdResult = POP3HandleCmd_RSET(pszCommand, hBSock, POP3S);
  442. else
  443. BSckSendString(hBSock, "-ERR Invalid command", POP3S.pPOP3Cfg->iTimeout);
  444. return (iCmdResult);
  445. }
  446. static int POP3HandleCmd_USER(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  447. {
  448. if (POP3S.iPOP3State != stateInit) {
  449. BSckSendString(hBSock, "-ERR Command not valid here", POP3S.pPOP3Cfg->iTimeout);
  450. return (-1);
  451. }
  452. char **ppszTokens = StrTokenize(pszCommand, " ");
  453. if ((ppszTokens == NULL) || (StrStringsCount(ppszTokens) != 2)) {
  454. if (ppszTokens != NULL)
  455. StrFreeStrings(ppszTokens);
  456. POP3S.iPOP3State = stateInit;
  457. BSckSendString(hBSock, "-ERR Invalid syntax", POP3S.pPOP3Cfg->iTimeout);
  458. return (-1);
  459. }
  460. char szAccountUser[MAX_ADDR_NAME] = "";
  461. char szAccountDomain[MAX_HOST_NAME] = "";
  462. if (StrSplitString
  463.     (ppszTokens[1], POP3_USER_SPLITTERS, szAccountUser, sizeof(szAccountUser),
  464.      szAccountDomain, sizeof(szAccountDomain)) < 0) {
  465. StrFreeStrings(ppszTokens);
  466. BSckSendString(hBSock, "-ERR Invalid username", POP3S.pPOP3Cfg->iTimeout);
  467. return (-1);
  468. }
  469. StrFreeStrings(ppszTokens);
  470. StrSNCpy(POP3S.szUser, szAccountUser);
  471. if (strlen(szAccountDomain) > 0)
  472. StrSNCpy(POP3S.szSvrDomain, szAccountDomain);
  473. POP3S.iPOP3State = stateUser;
  474. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout,
  475. "+OK Password required for %s@%s", POP3S.szUser, POP3S.szSvrDomain);
  476. return (0);
  477. }
  478. static int POP3HandleBadLogin(BSOCK_HANDLE hBSock, POP3Session & POP3S)
  479. {
  480. if (POP3S.pPOP3Cfg->ulFlags & POP3F_HANG_ON_BADLOGIN) {
  481. ///////////////////////////////////////////////////////////////////////////////
  482. //  Exit if POP3F_HANG_ON_BADLOGIN is set
  483. ///////////////////////////////////////////////////////////////////////////////
  484. POP3S.iPOP3State = stateExit;
  485. } else {
  486. ///////////////////////////////////////////////////////////////////////////////
  487. //  Otherwise sleep and doubles the sleeptime
  488. ///////////////////////////////////////////////////////////////////////////////
  489. SysSleep(POP3S.iBadLoginWait);
  490. POP3S.iBadLoginWait += POP3S.iBadLoginWait;
  491. POP3S.iPOP3State = stateInit;
  492. }
  493. BSckSendString(hBSock, "-ERR Invalid auth or access denied", POP3S.pPOP3Cfg->iTimeout);
  494. return (0);
  495. }
  496. static int POP3HandleCmd_PASS(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  497. {
  498. if (POP3S.iPOP3State != stateUser) {
  499. BSckSendString(hBSock, "-ERR Command not valid here", POP3S.pPOP3Cfg->iTimeout);
  500. return (-1);
  501. }
  502. char **ppszTokens = StrTokenize(pszCommand, " ");
  503. if ((ppszTokens == NULL) || (StrStringsCount(ppszTokens) != 2)) {
  504. if (ppszTokens != NULL)
  505. StrFreeStrings(ppszTokens);
  506. POP3S.iPOP3State = stateInit;
  507. BSckSendString(hBSock, "-ERR Invalid syntax", POP3S.pPOP3Cfg->iTimeout);
  508. return (-1);
  509. }
  510. StrSNCpy(POP3S.szPassword, ppszTokens[1]);
  511. StrFreeStrings(ppszTokens);
  512. ///////////////////////////////////////////////////////////////////////////////
  513. //  Log POP3 session
  514. ///////////////////////////////////////////////////////////////////////////////
  515. if (POP3LogEnabled(POP3S.hShbPOP3, POP3S.pPOP3Cfg))
  516. POP3LogSession(POP3S);
  517. ///////////////////////////////////////////////////////////////////////////////
  518. //  Check the presence of external authentication modules. If authentication
  519. //  succeed "pszPassword" is set to NULL that instruct "UPopBuildSession"
  520. //  to not make local authentication
  521. ///////////////////////////////////////////////////////////////////////////////
  522. char const *pszPassword = POP3S.szPassword;
  523. int iAuthResult = UAthAuthenticateUser(AUTH_SERVICE_POP3,
  524.        POP3S.szSvrDomain, POP3S.szUser, POP3S.szPassword);
  525. if (iAuthResult < 0) {
  526. if (iAuthResult != ERR_NO_EXTERNAL_AUTH_DEFINED) {
  527. ErrorPush();
  528. POP3HandleBadLogin(hBSock, POP3S);
  529. return (ErrorPop());
  530. }
  531. } else
  532. pszPassword = NULL;
  533. ///////////////////////////////////////////////////////////////////////////////
  534. //  Create POP3 session
  535. ///////////////////////////////////////////////////////////////////////////////
  536. if ((POP3S.hPOPSession = UPopBuildSession(POP3S.szSvrDomain, POP3S.szUser,
  537.   pszPassword,
  538.   &POP3S.PeerInfo)) == INVALID_POP3_HANDLE) {
  539. ErrorPush();
  540. POP3HandleBadLogin(hBSock, POP3S);
  541. return (ErrorPop());
  542. }
  543. ///////////////////////////////////////////////////////////////////////////////
  544. //  Save the user connection IP to use for SMTP authentication
  545. ///////////////////////////////////////////////////////////////////////////////
  546. UPopSaveUserIP(POP3S.hPOPSession);
  547. POP3S.iPOP3State = stateLogged;
  548. int iMsgCount = UPopGetSessionMsgCurrent(POP3S.hPOPSession);
  549. unsigned long ulMBSize = UPopGetSessionMBSize(POP3S.hPOPSession);
  550. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout,
  551. "+OK Maildrop has %d messages (%lu bytes)", iMsgCount, ulMBSize);
  552. return (0);
  553. }
  554. static int POP3HandleCmd_APOP(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  555. {
  556. if (POP3S.iPOP3State != stateInit) {
  557. BSckSendString(hBSock, "-ERR Command not valid here", POP3S.pPOP3Cfg->iTimeout);
  558. return (-1);
  559. }
  560. char **ppszTokens = StrTokenize(pszCommand, " ");
  561. if ((ppszTokens == NULL) || (StrStringsCount(ppszTokens) != 3)) {
  562. if (ppszTokens != NULL)
  563. StrFreeStrings(ppszTokens);
  564. POP3S.iPOP3State = stateInit;
  565. BSckSendString(hBSock, "-ERR Invalid syntax", POP3S.pPOP3Cfg->iTimeout);
  566. return (-1);
  567. }
  568. ///////////////////////////////////////////////////////////////////////////////
  569. //  Process parameters
  570. ///////////////////////////////////////////////////////////////////////////////
  571. char szAccountUser[MAX_ADDR_NAME] = "";
  572. char szAccountDomain[MAX_HOST_NAME] = "";
  573. if (StrSplitString
  574.     (ppszTokens[1], POP3_USER_SPLITTERS, szAccountUser, sizeof(szAccountUser),
  575.      szAccountDomain, sizeof(szAccountDomain)) < 0) {
  576. StrFreeStrings(ppszTokens);
  577. BSckSendString(hBSock, "-ERR Invalid username", POP3S.pPOP3Cfg->iTimeout);
  578. return (-1);
  579. }
  580. StrSNCpy(POP3S.szUser, szAccountUser);
  581. StrSNCpy(POP3S.szPassword, ppszTokens[2]);
  582. if (strlen(szAccountDomain) > 0)
  583. StrSNCpy(POP3S.szSvrDomain, szAccountDomain);
  584. StrFreeStrings(ppszTokens);
  585. ///////////////////////////////////////////////////////////////////////////////
  586. //  Log POP3 session
  587. ///////////////////////////////////////////////////////////////////////////////
  588. if (POP3LogEnabled(POP3S.hShbPOP3, POP3S.pPOP3Cfg))
  589. POP3LogSession(POP3S);
  590. ///////////////////////////////////////////////////////////////////////////////
  591. //  Check the presence of external authentication modules. If authentication
  592. //  succeed "pszPassword" is set to NULL that instruct "UPopBuildSession"
  593. //  to not make local authentication
  594. ///////////////////////////////////////////////////////////////////////////////
  595. char const *pszPassword = POP3S.szPassword;
  596. int iAuthResult = UAthAuthenticateUser(AUTH_SERVICE_POP3,
  597.        POP3S.szSvrDomain, POP3S.szUser, POP3S.szPassword);
  598. if (iAuthResult < 0) {
  599. if (iAuthResult != ERR_NO_EXTERNAL_AUTH_DEFINED) {
  600. ErrorPush();
  601. POP3HandleBadLogin(hBSock, POP3S);
  602. return (ErrorPop());
  603. }
  604. } else
  605. pszPassword = NULL;
  606. ///////////////////////////////////////////////////////////////////////////////
  607. //  Do APOP authentication ( only if the external one is not performed )
  608. ///////////////////////////////////////////////////////////////////////////////
  609. if ((pszPassword != NULL) &&
  610.     (UPopAuthenticateAPOP(POP3S.szSvrDomain, POP3S.szUser, POP3S.szTimeStamp,
  611.   pszPassword) < 0)) {
  612. ErrorPush();
  613. POP3HandleBadLogin(hBSock, POP3S);
  614. return (ErrorPop());
  615. }
  616. ///////////////////////////////////////////////////////////////////////////////
  617. //  Create POP3 session ( the NULL as third parameter force to not perform
  618. //  user authentication that has been done before )
  619. ///////////////////////////////////////////////////////////////////////////////
  620. if ((POP3S.hPOPSession = UPopBuildSession(POP3S.szSvrDomain, POP3S.szUser,
  621.   NULL, &POP3S.PeerInfo)) == INVALID_POP3_HANDLE)
  622. {
  623. ErrorPush();
  624. POP3HandleBadLogin(hBSock, POP3S);
  625. return (ErrorPop());
  626. }
  627. ///////////////////////////////////////////////////////////////////////////////
  628. //  Save the user connection IP to use for SMTP authentication
  629. ///////////////////////////////////////////////////////////////////////////////
  630. UPopSaveUserIP(POP3S.hPOPSession);
  631. POP3S.iPOP3State = stateLogged;
  632. int iMsgCount = UPopGetSessionMsgCurrent(POP3S.hPOPSession);
  633. unsigned long ulMBSize = UPopGetSessionMBSize(POP3S.hPOPSession);
  634. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout,
  635. "+OK Maildrop has %d messages (%lu bytes)", iMsgCount, ulMBSize);
  636. return (0);
  637. }
  638. static int POP3HandleCmd_STAT(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  639. {
  640. if (POP3S.iPOP3State != stateLogged) {
  641. BSckSendString(hBSock, "-ERR Command not valid here", POP3S.pPOP3Cfg->iTimeout);
  642. return (-1);
  643. }
  644. int iMsgCount = UPopGetSessionMsgCurrent(POP3S.hPOPSession);
  645. unsigned long ulMBSize = UPopGetSessionMBSize(POP3S.hPOPSession);
  646. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout, "+OK %d %lu", iMsgCount, ulMBSize);
  647. return (0);
  648. }
  649. static int POP3HandleCmd_LIST(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  650. {
  651. if (POP3S.iPOP3State != stateLogged) {
  652. BSckSendString(hBSock, "-ERR Command not valid here", POP3S.pPOP3Cfg->iTimeout);
  653. return (-1);
  654. }
  655. int iMsgIndex = -1;
  656. int iNumArgs = sscanf(pszCommand, "%*s %d", &iMsgIndex);
  657. if (iNumArgs < 1) {
  658. int iMsgCount = UPopGetSessionMsgCurrent(POP3S.hPOPSession);
  659. int iMsgTotal = UPopGetSessionMsgTotal(POP3S.hPOPSession);
  660. unsigned long ulMBSize = UPopGetSessionMBSize(POP3S.hPOPSession);
  661. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout,
  662. "+OK %d %lu", iMsgCount, ulMBSize);
  663. for (int ii = 0; ii < iMsgTotal; ii++) {
  664. unsigned long ulMessageSize = 0;
  665. if (UPopGetMessageSize(POP3S.hPOPSession, ii + 1, ulMessageSize) == 0) {
  666. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout,
  667. "%d %lu", ii + 1, ulMessageSize);
  668. }
  669. }
  670. BSckSendString(hBSock, ".", POP3S.pPOP3Cfg->iTimeout);
  671. } else {
  672. unsigned long ulMessageSize = 0;
  673. if (UPopGetMessageSize(POP3S.hPOPSession, iMsgIndex, ulMessageSize) < 0)
  674. BSckSendString(hBSock, "-ERR No such message", POP3S.pPOP3Cfg->iTimeout);
  675. else {
  676. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout,
  677. "+OK %d %lu", iMsgIndex, ulMessageSize);
  678. }
  679. }
  680. return (0);
  681. }
  682. static int POP3HandleCmd_UIDL(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  683. {
  684. if (POP3S.iPOP3State != stateLogged) {
  685. BSckSendString(hBSock, "-ERR Command not valid here", POP3S.pPOP3Cfg->iTimeout);
  686. return (-1);
  687. }
  688. int iMsgIndex = -1;
  689. int iNumArgs = sscanf(pszCommand, "%*s %d", &iMsgIndex);
  690. if (iNumArgs < 1) {
  691. int iMsgCount = UPopGetSessionMsgCurrent(POP3S.hPOPSession);
  692. int iMsgTotal = UPopGetSessionMsgTotal(POP3S.hPOPSession);
  693. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout, "+OK %d", iMsgCount);
  694. for (int ii = 0; ii < iMsgTotal; ii++) {
  695. char szMessageUIDL[256] = "";
  696. if (UPopGetMessageUIDL(POP3S.hPOPSession, ii + 1, szMessageUIDL) == 0) {
  697. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout,
  698. "%d %s", ii + 1, szMessageUIDL);
  699. }
  700. }
  701. BSckSendString(hBSock, ".", POP3S.pPOP3Cfg->iTimeout);
  702. } else {
  703. char szMessageUIDL[256] = "";
  704. if (UPopGetMessageUIDL(POP3S.hPOPSession, iMsgIndex, szMessageUIDL) < 0)
  705. BSckSendString(hBSock, "-ERR No such message", POP3S.pPOP3Cfg->iTimeout);
  706. else {
  707. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout,
  708. "+OK %d %s", iMsgIndex, szMessageUIDL);
  709. }
  710. }
  711. return (0);
  712. }
  713. static int POP3HandleCmd_QUIT(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  714. {
  715. POP3S.iPOP3State = stateExit;
  716. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout,
  717. "+OK %s closing session", POP3_SERVER_NAME);
  718. return (0);
  719. }
  720. static int POP3HandleCmd_RETR(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  721. {
  722. if (POP3S.iPOP3State != stateLogged) {
  723. BSckSendString(hBSock, "-ERR Command not valid here", POP3S.pPOP3Cfg->iTimeout);
  724. return (-1);
  725. }
  726. int iMsgIndex = -1;
  727. if (sscanf(pszCommand, "%*s %d", &iMsgIndex) < 1) {
  728. BSckSendString(hBSock, "-ERR Invalid syntax", POP3S.pPOP3Cfg->iTimeout);
  729. return (-1);
  730. }
  731. return (UPopSessionSendMsg(POP3S.hPOPSession, iMsgIndex, hBSock));
  732. }
  733. static int POP3HandleCmd_TOP(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  734. {
  735. if (POP3S.iPOP3State != stateLogged) {
  736. BSckSendString(hBSock, "-ERR Command not valid here", POP3S.pPOP3Cfg->iTimeout);
  737. return (-1);
  738. }
  739. int iMsgIndex = -1;
  740. int iNumLines = 0;
  741. if (sscanf(pszCommand, "%*s %d %d", &iMsgIndex, &iNumLines) < 2) {
  742. BSckSendString(hBSock, "-ERR Invalid syntax", POP3S.pPOP3Cfg->iTimeout);
  743. return (-1);
  744. }
  745. return (UPopSessionTopMsg(POP3S.hPOPSession, iMsgIndex, iNumLines, hBSock));
  746. }
  747. static int POP3HandleCmd_DELE(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  748. {
  749. if (POP3S.iPOP3State != stateLogged) {
  750. BSckSendString(hBSock, "-ERR Command not valid here", POP3S.pPOP3Cfg->iTimeout);
  751. return (-1);
  752. }
  753. int iMsgIndex = -1;
  754. if (sscanf(pszCommand, "%*s %d", &iMsgIndex) < 1) {
  755. BSckSendString(hBSock, "-ERR Invalid syntax", POP3S.pPOP3Cfg->iTimeout);
  756. return (-1);
  757. }
  758. if (UPopDeleteMessage(POP3S.hPOPSession, iMsgIndex) < 0) {
  759. UPopSendErrorResponse(hBSock, ErrGetErrorCode(), POP3S.pPOP3Cfg->iTimeout);
  760. return (ErrGetErrorCode());
  761. }
  762. BSckSendString(hBSock, "+OK Message deleted", POP3S.pPOP3Cfg->iTimeout);
  763. return (0);
  764. }
  765. static int POP3HandleCmd_NOOP(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  766. {
  767. if (POP3S.iPOP3State != stateLogged) {
  768. BSckSendString(hBSock, "-ERR Command not valid here", POP3S.pPOP3Cfg->iTimeout);
  769. return (-1);
  770. }
  771. int iMsgCount = UPopGetSessionMsgCurrent(POP3S.hPOPSession);
  772. unsigned long ulMBSize = UPopGetSessionMBSize(POP3S.hPOPSession);
  773. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout,
  774. "+OK Maildrop has %d messages (%lu bytes)", iMsgCount, ulMBSize);
  775. return (0);
  776. }
  777. static int POP3HandleCmd_LAST(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  778. {
  779. if (POP3S.iPOP3State != stateLogged) {
  780. BSckSendString(hBSock, "-ERR Command not valid here", POP3S.pPOP3Cfg->iTimeout);
  781. return (-1);
  782. }
  783. int iMsgLast = UPopGetSessionLastAccessed(POP3S.hPOPSession);
  784. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout, "+OK %d", iMsgLast);
  785. return (0);
  786. }
  787. static int POP3HandleCmd_RSET(const char *pszCommand, BSOCK_HANDLE hBSock, POP3Session & POP3S)
  788. {
  789. if (POP3S.iPOP3State != stateLogged) {
  790. BSckSendString(hBSock, "-ERR Command not valid here", POP3S.pPOP3Cfg->iTimeout);
  791. return (-1);
  792. }
  793. UPopResetSession(POP3S.hPOPSession);
  794. int iMsgCount = UPopGetSessionMsgCurrent(POP3S.hPOPSession);
  795. unsigned long ulMBSize = UPopGetSessionMBSize(POP3S.hPOPSession);
  796. BSckVSendString(hBSock, POP3S.pPOP3Cfg->iTimeout,
  797. "+OK Maildrop has %d messages (%lu bytes)", iMsgCount, ulMBSize);
  798. return (0);
  799. }