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

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 "StrUtils.h"
  29. #include "ResLocks.h"
  30. #include "MiscUtils.h"
  31. #include "SvrUtils.h"
  32. #include "UsrUtils.h"
  33. #include "ExtAliases.h"
  34. #include "UsrMailList.h"
  35. #include "MessQueue.h"
  36. #include "SMTPUtils.h"
  37. #include "MailConfig.h"
  38. #include "AppDefines.h"
  39. #include "MailSvr.h"
  40. #include "FINGSvr.h"
  41. #define FINGSRV_ACCEPT_TIMEOUT  4
  42. #define FING_LISTEN_SIZE        64
  43. #define FING_WAIT_SLEEP         2
  44. #define MAX_CLIENTS_WAIT        300
  45. #define FING_IPMAP_FILE         "finger.ipmap.tab"
  46. #define FING_LOG_FILE           "finger"
  47. #define FING_SERVER_NAME        "[" APP_NAME_VERSION_STR " FINGER Server]"
  48. static int FINGCheckPeerIP(SYS_SOCKET SockFD);
  49. static FINGConfig *FINGGetConfigCopy(SHB_HANDLE hShbFING);
  50. static int FINGLogEnabled(SHB_HANDLE hShbFING, FINGConfig * pFINGCfg = NULL);
  51. static unsigned int FINGClientThread(void *pThreadData);
  52. static int FINGLogSession(char const *pszSockHost, char const *pszSockDomain,
  53.   SYS_INET_ADDR & PeerInfo, char const *pszQuery);
  54. static int FINGHandleSession(SHB_HANDLE hShbFING, BSOCK_HANDLE hBSock);
  55. static int FINGProcessQuery(char const *pszQuery, BSOCK_HANDLE hBSock,
  56.     FINGConfig * pFINGCfg, char const *pszSockDomain,
  57.     SVRCFG_HANDLE hSvrConfig);
  58. static int FINGDumpUser(char const *pszUser, char const *pszDomain,
  59. BSOCK_HANDLE hBSock, FINGConfig * pFINGCfg);
  60. static int FINGDumpMailingList(UserInfo * pUI, BSOCK_HANDLE hBSock, FINGConfig * pFINGCfg);
  61. static int FINGCheckPeerIP(SYS_SOCKET SockFD)
  62. {
  63. char szIPMapFile[SYS_MAX_PATH] = "";
  64. CfgGetRootPath(szIPMapFile, sizeof(szIPMapFile));
  65. StrNCat(szIPMapFile, FING_IPMAP_FILE, sizeof(szIPMapFile));
  66. if (SysExistFile(szIPMapFile)) {
  67. SYS_INET_ADDR PeerInfo;
  68. if (SysGetPeerInfo(SockFD, PeerInfo) < 0)
  69. return (ErrGetErrorCode());
  70. if (MscCheckAllowedIP(szIPMapFile, PeerInfo, true) < 0)
  71. return (ErrGetErrorCode());
  72. }
  73. return (0);
  74. }
  75. static FINGConfig *FINGGetConfigCopy(SHB_HANDLE hShbFING)
  76. {
  77. FINGConfig *pFINGCfg = (FINGConfig *) ShbLock(hShbFING);
  78. if (pFINGCfg == NULL)
  79. return (NULL);
  80. FINGConfig *pFINGCfgCopy = (FINGConfig *) SysAlloc(sizeof(FINGConfig));
  81. if (pFINGCfgCopy != NULL)
  82. memcpy(pFINGCfgCopy, pFINGCfg, sizeof(FINGConfig));
  83. ShbUnlock(hShbFING);
  84. return (pFINGCfgCopy);
  85. }
  86. static int FINGLogEnabled(SHB_HANDLE hShbFING, FINGConfig * pFINGCfg)
  87. {
  88. int iDoUnlock = 0;
  89. if (pFINGCfg == NULL) {
  90. if ((pFINGCfg = (FINGConfig *) ShbLock(hShbFING)) == NULL)
  91. return (ErrGetErrorCode());
  92. ++iDoUnlock;
  93. }
  94. unsigned long ulFlags = pFINGCfg->ulFlags;
  95. if (iDoUnlock)
  96. ShbUnlock(hShbFING);
  97. return ((ulFlags & FINGF_LOG_ENABLED) ? 1 : 0);
  98. }
  99. static unsigned int FINGClientThread(void *pThreadData)
  100. {
  101. SYS_SOCKET SockFD = (SYS_SOCKET) (unsigned long) pThreadData;
  102. ///////////////////////////////////////////////////////////////////////////////
  103. //  Check peer IP address serivce access permissions
  104. ///////////////////////////////////////////////////////////////////////////////
  105. if (FINGCheckPeerIP(SockFD) < 0) {
  106. ErrorPush();
  107. SysLogMessage(LOG_LEV_ERROR, "%sn", ErrGetErrorString());
  108. SysCloseSocket(SockFD);
  109. return (ErrorPop());
  110. }
  111. ///////////////////////////////////////////////////////////////////////////////
  112. //  Increase threads count
  113. ///////////////////////////////////////////////////////////////////////////////
  114. FINGConfig *pFINGCfg = (FINGConfig *) ShbLock(hShbFING);
  115. if (pFINGCfg == NULL) {
  116. ErrorPush();
  117. SysLogMessage(LOG_LEV_ERROR, "%sn", ErrGetErrorString());
  118. SysCloseSocket(SockFD);
  119. return (ErrorPop());
  120. }
  121. ++pFINGCfg->lThreadCount;
  122. ShbUnlock(hShbFING);
  123. ///////////////////////////////////////////////////////////////////////////////
  124. //  Link socket to the bufferer
  125. ///////////////////////////////////////////////////////////////////////////////
  126. BSOCK_HANDLE hBSock = BSckAttach(SockFD);
  127. if (hBSock == INVALID_BSOCK_HANDLE) {
  128. ErrorPush();
  129. SysLogMessage(LOG_LEV_ERROR, "%sn", ErrGetErrorString());
  130. SysCloseSocket(SockFD);
  131. return (ErrorPop());
  132. }
  133. ///////////////////////////////////////////////////////////////////////////////
  134. //  Handle client session
  135. ///////////////////////////////////////////////////////////////////////////////
  136. FINGHandleSession(hShbFING, hBSock);
  137. ///////////////////////////////////////////////////////////////////////////////
  138. //  Unlink socket to the bufferer and close it
  139. ///////////////////////////////////////////////////////////////////////////////
  140. BSckDetach(hBSock, 1);
  141. ///////////////////////////////////////////////////////////////////////////////
  142. //  Decrease thread count
  143. ///////////////////////////////////////////////////////////////////////////////
  144. pFINGCfg = (FINGConfig *) ShbLock(hShbFING);
  145. if (pFINGCfg == NULL) {
  146. ErrorPush();
  147. SysLogMessage(LOG_LEV_ERROR, "%sn", ErrGetErrorString());
  148. return (ErrorPop());
  149. }
  150. --pFINGCfg->lThreadCount;
  151. ShbUnlock(hShbFING);
  152. return (0);
  153. }
  154. unsigned int FINGThreadProc(void *pThreadData)
  155. {
  156. FINGConfig *pFINGCfg = (FINGConfig *) ShbLock(hShbFING);
  157. if (pFINGCfg == NULL) {
  158. ErrorPush();
  159. SysLogMessage(LOG_LEV_ERROR, "%sn", ErrGetErrorString());
  160. return (ErrorPop());
  161. }
  162. int iNumSockFDs = 0;
  163. SYS_SOCKET SockFDs[MAX_FING_ACCEPT_ADDRESSES];
  164. if (MscCreateServerSockets(pFINGCfg->iNumAddr, pFINGCfg->SvrAddr, pFINGCfg->iPort,
  165.    FING_LISTEN_SIZE, SockFDs, iNumSockFDs) < 0) {
  166. ErrorPush();
  167. SysLogMessage(LOG_LEV_ERROR, "%sn", ErrGetErrorString());
  168. ShbUnlock(hShbFING);
  169. return (ErrorPop());
  170. }
  171. ShbUnlock(hShbFING);
  172. SysLogMessage(LOG_LEV_MESSAGE, "%s startedn", FING_SERVER_NAME);
  173. for (;;) {
  174. int iNumConnSockFD = 0;
  175. SYS_SOCKET ConnSockFD[MAX_FING_ACCEPT_ADDRESSES];
  176. if (MscAcceptServerConnection(SockFDs, iNumSockFDs, ConnSockFD,
  177.       iNumConnSockFD, FINGSRV_ACCEPT_TIMEOUT) < 0) {
  178. unsigned long ulFlags = FINGF_STOP_SERVER;
  179. pFINGCfg = (FINGConfig *) ShbLock(hShbFING);
  180. if (pFINGCfg != NULL)
  181. ulFlags = pFINGCfg->ulFlags;
  182. ShbUnlock(hShbFING);
  183. if (ulFlags & FINGF_STOP_SERVER)
  184. break;
  185. else
  186. continue;
  187. }
  188. for (int ss = 0; ss < iNumConnSockFD; ss++) {
  189. SYS_THREAD hClientThread =
  190.     SysCreateServiceThread(FINGClientThread, ConnSockFD[ss]);
  191. if (hClientThread != SYS_INVALID_THREAD)
  192. SysCloseThread(hClientThread, 0);
  193. else
  194. SysCloseSocket(ConnSockFD[ss]);
  195. }
  196. }
  197. for (int ss = 0; ss < iNumSockFDs; ss++)
  198. SysCloseSocket(SockFDs[ss]);
  199. ///////////////////////////////////////////////////////////////////////////////
  200. //  Wait for clients completion
  201. ///////////////////////////////////////////////////////////////////////////////
  202. for (int iTotalWait = 0; (iTotalWait < MAX_CLIENTS_WAIT); iTotalWait += FING_WAIT_SLEEP) {
  203. pFINGCfg = (FINGConfig *) ShbLock(hShbFING);
  204. if (pFINGCfg == NULL)
  205. break;
  206. long lThreadCount = pFINGCfg->lThreadCount;
  207. ShbUnlock(hShbFING);
  208. if (lThreadCount == 0)
  209. break;
  210. SysSleep(FING_WAIT_SLEEP);
  211. }
  212. SysLogMessage(LOG_LEV_MESSAGE, "%s stoppedn", FING_SERVER_NAME);
  213. return (0);
  214. }
  215. static int FINGLogSession(char const *pszSockHost, char const *pszSockDomain,
  216.   SYS_INET_ADDR & PeerInfo, char const *pszQuery)
  217. {
  218. char szTime[256] = "";
  219. MscGetTimeNbrString(szTime, sizeof(szTime) - 1);
  220. RLCK_HANDLE hResLock = RLckLockEX(SVR_LOGS_DIR SYS_SLASH_STR FING_LOG_FILE);
  221. if (hResLock == INVALID_RLCK_HANDLE)
  222. return (ErrGetErrorCode());
  223. char szIP[128] = "???.???.???.???";
  224. MscFileLog(FING_LOG_FILE, ""%s""
  225.    "t"%s""
  226.    "t"%s""
  227.    "t"%s""
  228.    "t"%s""
  229.    "n", pszSockHost, pszSockDomain, SysInetNToA(PeerInfo, szIP),
  230.    szTime, pszQuery);
  231. RLckUnlockEX(hResLock);
  232. return (0);
  233. }
  234. static int FINGHandleSession(SHB_HANDLE hShbFING, BSOCK_HANDLE hBSock)
  235. {
  236. FINGConfig *pFINGCfg = FINGGetConfigCopy(hShbFING);
  237. ///////////////////////////////////////////////////////////////////////////////
  238. //  Get client socket info
  239. ///////////////////////////////////////////////////////////////////////////////
  240. SYS_INET_ADDR PeerInfo;
  241. if (SysGetPeerInfo(BSckGetAttachedSocket(hBSock), PeerInfo) < 0) {
  242. ErrorPush();
  243. BSckSendString(hBSock, ErrGetErrorString(ErrorFetch()), pFINGCfg->iTimeout);
  244. SysFree(pFINGCfg);
  245. SysLogMessage(LOG_LEV_ERROR, "%sn", ErrGetErrorString(ErrorFetch()));
  246. return (ErrorPop());
  247. }
  248. ///////////////////////////////////////////////////////////////////////////////
  249. //  Get server socket FQDN
  250. ///////////////////////////////////////////////////////////////////////////////
  251. char szSvrFQDN[MAX_HOST_NAME] = "";
  252. if (MscGetSockHost(BSckGetAttachedSocket(hBSock), szSvrFQDN) < 0) {
  253. ErrorPush();
  254. BSckSendString(hBSock, ErrGetErrorString(ErrorFetch()), pFINGCfg->iTimeout);
  255. SysFree(pFINGCfg);
  256. SysLogMessage(LOG_LEV_ERROR, "%sn", ErrGetErrorString(ErrorFetch()));
  257. return (ErrorPop());
  258. }
  259. char szSockHost[MAX_HOST_NAME] = "";
  260. char szSockDomain[MAX_HOST_NAME] = "";
  261. MscSplitFQDN(szSvrFQDN, szSockHost, szSockDomain);
  262. char szIP[128] = "???.???.???.???";
  263. SysLogMessage(LOG_LEV_MESSAGE, "FINGER client connection from [%s]n",
  264.       SysInetNToA(PeerInfo, szIP));
  265. char szQuery[1024] = "";
  266. if ((BSckGetString(hBSock, szQuery, sizeof(szQuery) - 1, pFINGCfg->iTimeout) != NULL) &&
  267.     (MscCmdStringCheck(szQuery) == 0)) {
  268. ///////////////////////////////////////////////////////////////////////////////
  269. //  Log FINGER question
  270. ///////////////////////////////////////////////////////////////////////////////
  271. if (FINGLogEnabled(hShbFING))
  272. FINGLogSession(szSockHost, szSockDomain, PeerInfo, szQuery);
  273. SysLogMessage(LOG_LEV_MESSAGE, "FINGER query [%s] : "%s"n",
  274.       SysInetNToA(PeerInfo, szIP), szQuery);
  275. SVRCFG_HANDLE hSvrConfig = SvrGetConfigHandle();
  276. FINGProcessQuery(szQuery, hBSock, pFINGCfg, szSockDomain, hSvrConfig);
  277. if (hSvrConfig != INVALID_SVRCFG_HANDLE)
  278. SvrReleaseConfigHandle(hSvrConfig);
  279. }
  280. SysFree(pFINGCfg);
  281. SysLogMessage(LOG_LEV_MESSAGE, "FINGER client exit [%s]n", SysInetNToA(PeerInfo, szIP));
  282. return (0);
  283. }
  284. static int FINGProcessQuery(char const *pszQuery, BSOCK_HANDLE hBSock,
  285.     FINGConfig * pFINGCfg, char const *pszSockDomain,
  286.     SVRCFG_HANDLE hSvrConfig)
  287. {
  288. ///////////////////////////////////////////////////////////////////////////////
  289. //  Check for verbose query
  290. ///////////////////////////////////////////////////////////////////////////////
  291. int iVerbose = 0;
  292. if (pszQuery[0] == '/') {
  293. if (toupper(pszQuery[1]) != 'W') {
  294. BSckSendString(hBSock, "Invalid query", pFINGCfg->iTimeout);
  295. ErrSetErrorCode(ERR_FINGER_QUERY_FORMAT);
  296. return (ERR_FINGER_QUERY_FORMAT);
  297. }
  298. ++iVerbose;
  299. pszQuery += 2;
  300. }
  301. ///////////////////////////////////////////////////////////////////////////////
  302. //  Discard spaces
  303. ///////////////////////////////////////////////////////////////////////////////
  304. for (; *pszQuery == ' '; pszQuery++);
  305. if (*pszQuery == '') {
  306. BSckSendString(hBSock, "Empty query not allowed", pFINGCfg->iTimeout);
  307. ErrSetErrorCode(ERR_FINGER_QUERY_FORMAT);
  308. return (ERR_FINGER_QUERY_FORMAT);
  309. }
  310. ///////////////////////////////////////////////////////////////////////////////
  311. //  Split user-domain
  312. ///////////////////////////////////////////////////////////////////////////////
  313. char szUser[MAX_ADDR_NAME] = "";
  314. char szDomain[MAX_ADDR_NAME] = "";
  315. if (strchr(pszQuery, '@') != NULL) {
  316. if (USmtpSplitEmailAddr(pszQuery, szUser, szDomain) < 0) {
  317. ErrorPush();
  318. BSckSendString(hBSock, "Invalid query", pFINGCfg->iTimeout);
  319. return (ErrorPop());
  320. }
  321. } else
  322. StrSNCpy(szUser, pszQuery);
  323. ///////////////////////////////////////////////////////////////////////////////
  324. //  Check if indirect query
  325. ///////////////////////////////////////////////////////////////////////////////
  326. if (strchr(szDomain, '@') != NULL) {
  327. BSckSendString(hBSock, "Indirect query not allowed", pFINGCfg->iTimeout);
  328. ErrSetErrorCode(ERR_FINGER_QUERY_FORMAT);
  329. return (ERR_FINGER_QUERY_FORMAT);
  330. }
  331. ///////////////////////////////////////////////////////////////////////////////
  332. //  Setup domain name in case of username only query
  333. ///////////////////////////////////////////////////////////////////////////////
  334. if (IsEmptyString(szDomain)) {
  335. if (SvrConfigVar("POP3Domain", szDomain, sizeof(szDomain), hSvrConfig) < 0) {
  336. if (strlen(pszSockDomain) == 0) {
  337. if (SvrConfigVar
  338.     ("RootDomain", szDomain, sizeof(szDomain), hSvrConfig) < 0) {
  339. ErrorPush();
  340. BSckSendString(hBSock, "User not found",
  341.        pFINGCfg->iTimeout);
  342. return (ErrorPop());
  343. }
  344. } else
  345. StrSNCpy(szDomain, pszSockDomain);
  346. }
  347. }
  348. ///////////////////////////////////////////////////////////////////////////////
  349. //  Dump user
  350. ///////////////////////////////////////////////////////////////////////////////
  351. if (FINGDumpUser(szUser, szDomain, hBSock, pFINGCfg) < 0) {
  352. ErrorPush();
  353. BSckSendString(hBSock, "User not found", pFINGCfg->iTimeout);
  354. return (ErrorPop());
  355. }
  356. return (0);
  357. }
  358. static int FINGDumpUser(char const *pszUser, char const *pszDomain,
  359. BSOCK_HANDLE hBSock, FINGConfig * pFINGCfg)
  360. {
  361. ///////////////////////////////////////////////////////////////////////////////
  362. //  Lookup user
  363. ///////////////////////////////////////////////////////////////////////////////
  364. char szRealAddr[MAX_ADDR_NAME] = "";
  365. UserInfo *pUI = UsrGetUserByNameOrAlias(pszDomain, pszUser, szRealAddr);
  366. if (pUI != NULL) {
  367. if (UsrGetUserType(pUI) == usrTypeUser) {
  368. ///////////////////////////////////////////////////////////////////////////////
  369. //  Local user case
  370. ///////////////////////////////////////////////////////////////////////////////
  371. char *pszRealName = UsrGetUserInfoVar(pUI, "RealName");
  372. char *pszHomePage = UsrGetUserInfoVar(pUI, "HomePage");
  373. char szRespBuffer[2048] = "";
  374. sprintf(szRespBuffer,
  375. "EMail       : %srn"
  376. "  Real Name : %srn"
  377. "  Home Page : %s",
  378. szRealAddr,
  379. (pszRealName != NULL) ? pszRealName : "??",
  380. (pszHomePage != NULL) ? pszHomePage : "??");
  381. BSckSendString(hBSock, szRespBuffer, pFINGCfg->iTimeout);
  382. if (pszRealName != NULL)
  383. SysFree(pszRealName);
  384. if (pszHomePage != NULL)
  385. SysFree(pszHomePage);
  386. } else {
  387. ///////////////////////////////////////////////////////////////////////////////
  388. //  Local mailing list case
  389. ///////////////////////////////////////////////////////////////////////////////
  390. FINGDumpMailingList(pUI, hBSock, pFINGCfg);
  391. }
  392. UsrFreeUserInfo(pUI);
  393. } else {
  394. ErrSetErrorCode(ERR_USER_NOT_FOUND);
  395. return (ERR_USER_NOT_FOUND);
  396. }
  397. return (0);
  398. }
  399. static int FINGDumpMailingList(UserInfo * pUI, BSOCK_HANDLE hBSock, FINGConfig * pFINGCfg)
  400. {
  401. USRML_HANDLE hUsersDB = UsrMLOpenDB(pUI);
  402. if (hUsersDB == INVALID_USRML_HANDLE)
  403. return (ErrGetErrorCode());
  404. ///////////////////////////////////////////////////////////////////////////////
  405. //  Mailing list scan
  406. ///////////////////////////////////////////////////////////////////////////////
  407. MLUserInfo *pMLUI = UsrMLGetFirstUser(hUsersDB);
  408. for (; pMLUI != NULL; pMLUI = UsrMLGetNextUser(hUsersDB)) {
  409. char szUser[MAX_ADDR_NAME] = "";
  410. char szDomain[MAX_ADDR_NAME] = "";
  411. if (USmtpSplitEmailAddr(pMLUI->pszAddress, szUser, szDomain) < 0) {
  412. ErrorPush();
  413. UsrMLFreeUser(pMLUI);
  414. UsrMLCloseDB(hUsersDB);
  415. return (ErrorPop());
  416. }
  417. ///////////////////////////////////////////////////////////////////////////////
  418. //  Dump user
  419. ///////////////////////////////////////////////////////////////////////////////
  420. FINGDumpUser(szUser, szDomain, hBSock, pFINGCfg);
  421. UsrMLFreeUser(pMLUI);
  422. }
  423. UsrMLCloseDB(hUsersDB);
  424. return (0);
  425. }