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

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 "ResLocks.h"
  27. #include "StrUtils.h"
  28. #include "SList.h"
  29. #include "BuffSock.h"
  30. #include "MailConfig.h"
  31. #include "UsrUtils.h"
  32. #include "UsrAuth.h"
  33. #include "SvrUtils.h"
  34. #include "MiscUtils.h"
  35. #include "DNS.h"
  36. #include "DNSCache.h"
  37. #include "MessQueue.h"
  38. #include "SMAILUtils.h"
  39. #include "QueueUtils.h"
  40. #include "SMTPSvr.h"
  41. #include "SMTPUtils.h"
  42. #include "Base64Enc.h"
  43. #include "MD5.h"
  44. #include "MailSvr.h"
  45. #define STD_SMTP_TIMEOUT        STD_SERVER_TIMEOUT
  46. #define SMTPGW_LINE_MAX         1024
  47. #define SMTPGW_TABLE_FILE       "smtpgw.tab"
  48. #define SMTPFWD_LINE_MAX        1024
  49. #define SMTPFWD_TABLE_FILE      "smtpfwd.tab"
  50. #define SMTPRELAY_LINE_MAX      512
  51. #define SMTP_RELAY_FILE         "smtprelay.tab"
  52. #define MAX_MX_RECORDS          32
  53. #define SMTP_SPAMMERS_FILE      "spammers.tab"
  54. #define SMTP_SPAM_ADDRESS_FILE  "spam-address.tab"
  55. #define SPAMMERS_LINE_MAX       512
  56. #define SPAM_ADDRESS_LINE_MAX   512
  57. #define SMTPAUTH_LINE_MAX       512
  58. #define SMTP_EXTAUTH_TIMEOUT    60
  59. #define SMTP_EXTAUTH_PRIORITY   SYS_PRIORITY_NORMAL
  60. #define SMTP_EXTAUTH_SUCCESS    0
  61. #define RFC_SPECIALS            "()<>@,/\;:"[]*?"
  62. #define SMTPCH_SUPPORT_SIZE     (1 << 0)
  63. enum SmtpGwFileds {
  64. gwDomain = 0,
  65. gwGateway,
  66. gwMax
  67. };
  68. enum SmtpFwdFileds {
  69. fwdDomain = 0,
  70. fwdGateway,
  71. fwdMax
  72. };
  73. enum SmtpRelayFileds {
  74. rlyFromIP = 0,
  75. rlyFromMask,
  76. rlyMax
  77. };
  78. enum SpammerFileds {
  79. spmFromIP = 0,
  80. spmFromMask,
  81. spmMax
  82. };
  83. struct SmtpMXRecords {
  84. int iNumMXRecords;
  85. int iMXCost[MAX_MX_RECORDS];
  86. char *pszMXName[MAX_MX_RECORDS];
  87. int iCurrMxCost;
  88. };
  89. struct SmtpChannel {
  90. BSOCK_HANDLE hBSock;
  91. unsigned long ulFlags;
  92. unsigned long ulMaxMsgSize;
  93. SYS_INET_ADDR SvrAddr;
  94. char *pszServer;
  95. };
  96. static int USmtpWriteGateway(FILE * pGwFile, const char *pszDomain, const char *pszGateway);
  97. static char *USmtpGetGwTableFilePath(char *pszGwFilePath, int iMaxPath);
  98. static char *USmtpGetFwdTableFilePath(char *pszFwdFilePath, int iMaxPath);
  99. static char *USmtpGetRelayFilePath(char *pszRelayFilePath, int iMaxPath);
  100. static int USmtpSetError(SMTPError * pSMTPE, int iSTMPResponse, char const *pszSTMPResponse,
  101.  char const *pszServer);
  102. static int USmtpSetErrorServer(SMTPError * pSMTPE, char const *pszServer);
  103. static int USmtpResponseClass(int iResponseCode, int iResponseClass);
  104. static int USmtpGetResultCode(const char *pszResult);
  105. static int USmtpIsPartialResponse(char const *pszResponse);
  106. static int USmtpGetResponse(BSOCK_HANDLE hBSock, char *pszResponse, int iMaxResponse,
  107.     int iTimeout = STD_SMTP_TIMEOUT);
  108. static int USmtpSendCommand(BSOCK_HANDLE hBSock, const char *pszCommand,
  109.     char *pszResponse, int iMaxResponse, int iTimeout = STD_SMTP_TIMEOUT);
  110. static int USmtpGetServerAuthFile(char const *pszServer, char *pszAuthFilePath);
  111. static int USmtpDoPlainAuth(SmtpChannel * pSmtpCh, char const *pszServer,
  112.     char const *const *ppszAuthTokens, SMTPError * pSMTPE);
  113. static int USmtpDoLoginAuth(SmtpChannel * pSmtpCh, char const *pszServer,
  114.     char const *const *ppszAuthTokens, SMTPError * pSMTPE);
  115. static int USmtpDoCramMD5Auth(SmtpChannel * pSmtpCh, char const *pszServer,
  116.       char const *const *ppszAuthTokens, SMTPError * pSMTPE);
  117. static int USmtpExternalAuthSubstitute(char **ppszAuthTokens, char const *pszChallenge,
  118.        char const *pszSecret, char const *pszRespFile);
  119. static int USmtpDoExternAuth(SmtpChannel * pSmtpCh, char const *pszServer,
  120.      char **ppszAuthTokens, SMTPError * pSMTPE);
  121. static int USmtpServerAuthenticate(SmtpChannel * pSmtpCh, char const *pszServer,
  122.    SMTPError * pSMTPE);
  123. static int USmtpParseEhloResponse(SmtpChannel * pSmtpCh, char const *pszResponse);
  124. static int USmtpGetDomainMX(SVRCFG_HANDLE hSvrConfig, const char *pszDomain, char *&pszMXDomains);
  125. static char *USmtpGetSpammersFilePath(char *pszSpamFilePath, int iMaxPath);
  126. static char *USmtpGetSpamAddrFilePath(char *pszSpamFilePath, int iMaxPath);
  127. static char *USmtpGetGwTableFilePath(char *pszGwFilePath, int iMaxPath)
  128. {
  129. CfgGetRootPath(pszGwFilePath, iMaxPath);
  130. StrNCat(pszGwFilePath, SMTPGW_TABLE_FILE, iMaxPath);
  131. return (pszGwFilePath);
  132. }
  133. static char *USmtpGetFwdTableFilePath(char *pszFwdFilePath, int iMaxPath)
  134. {
  135. CfgGetRootPath(pszFwdFilePath, iMaxPath);
  136. StrNCat(pszFwdFilePath, SMTPFWD_TABLE_FILE, iMaxPath);
  137. return (pszFwdFilePath);
  138. }
  139. char **USmtpGetFwdGateways(SVRCFG_HANDLE hSvrConfig, const char *pszDomain)
  140. {
  141. char szFwdFilePath[SYS_MAX_PATH] = "";
  142. USmtpGetFwdTableFilePath(szFwdFilePath, sizeof(szFwdFilePath));
  143. char szResLock[SYS_MAX_PATH] = "";
  144. RLCK_HANDLE hResLock = RLckLockSH(CfgGetBasedPath(szFwdFilePath, szResLock,
  145.   sizeof(szResLock)));
  146. if (hResLock == INVALID_RLCK_HANDLE)
  147. return (NULL);
  148. FILE *pFwdFile = fopen(szFwdFilePath, "rt");
  149. if (pFwdFile == NULL) {
  150. RLckUnlockSH(hResLock);
  151. ErrSetErrorCode(ERR_SMTPFWD_FILE_NOT_FOUND);
  152. return (NULL);
  153. }
  154. char szFwdLine[SMTPFWD_LINE_MAX] = "";
  155. while (MscGetConfigLine(szFwdLine, sizeof(szFwdLine) - 1, pFwdFile) != NULL) {
  156. char **ppszStrings = StrGetTabLineStrings(szFwdLine);
  157. if (ppszStrings == NULL)
  158. continue;
  159. int iFieldsCount = StrStringsCount(ppszStrings);
  160. if ((iFieldsCount >= fwdMax) && StrIWildMatch(pszDomain, ppszStrings[fwdDomain])) {
  161. char **ppszFwdGws = NULL;
  162. if (ppszStrings[fwdGateway][0] == '#') {
  163. if ((ppszFwdGws =
  164.      StrTokenize(ppszStrings[fwdGateway] + 1, ",")) != NULL) {
  165. int iGwCount = StrStringsCount(ppszFwdGws);
  166. srand((unsigned int) time(NULL));
  167. for (int ii = 0; ii < (iGwCount / 2); ii++) {
  168. int iSwap1 = rand() % iGwCount;
  169. int iSwap2 = rand() % iGwCount;
  170. char *pszGw1 = ppszFwdGws[iSwap1];
  171. char *pszGw2 = ppszFwdGws[iSwap2];
  172. ppszFwdGws[iSwap1] = pszGw2;
  173. ppszFwdGws[iSwap2] = pszGw1;
  174. }
  175. }
  176. } else
  177. ppszFwdGws = StrTokenize(ppszStrings[fwdGateway], ",");
  178. StrFreeStrings(ppszStrings);
  179. fclose(pFwdFile);
  180. RLckUnlockSH(hResLock);
  181. return (ppszFwdGws);
  182. }
  183. StrFreeStrings(ppszStrings);
  184. }
  185. fclose(pFwdFile);
  186. RLckUnlockSH(hResLock);
  187. ErrSetErrorCode(ERR_SMTPFWD_NOT_FOUND);
  188. return (NULL);
  189. }
  190. static char *USmtpGetRelayFilePath(char *pszRelayFilePath, int iMaxPath)
  191. {
  192. CfgGetRootPath(pszRelayFilePath, iMaxPath);
  193. StrNCat(pszRelayFilePath, SMTP_RELAY_FILE, iMaxPath);
  194. return (pszRelayFilePath);
  195. }
  196. int USmtpGetGateway(SVRCFG_HANDLE hSvrConfig, const char *pszDomain, char *pszGateway)
  197. {
  198. char szGwFilePath[SYS_MAX_PATH] = "";
  199. USmtpGetGwTableFilePath(szGwFilePath, sizeof(szGwFilePath));
  200. char szResLock[SYS_MAX_PATH] = "";
  201. RLCK_HANDLE hResLock = RLckLockSH(CfgGetBasedPath(szGwFilePath, szResLock,
  202.   sizeof(szResLock)));
  203. if (hResLock == INVALID_RLCK_HANDLE)
  204. return (ErrGetErrorCode());
  205. FILE *pGwFile = fopen(szGwFilePath, "rt");
  206. if (pGwFile == NULL) {
  207. RLckUnlockSH(hResLock);
  208. ErrSetErrorCode(ERR_SMTPGW_FILE_NOT_FOUND);
  209. return (ERR_SMTPGW_FILE_NOT_FOUND);
  210. }
  211. char szGwLine[SMTPGW_LINE_MAX] = "";
  212. while (MscGetConfigLine(szGwLine, sizeof(szGwLine) - 1, pGwFile) != NULL) {
  213. char **ppszStrings = StrGetTabLineStrings(szGwLine);
  214. if (ppszStrings == NULL)
  215. continue;
  216. int iFieldsCount = StrStringsCount(ppszStrings);
  217. if ((iFieldsCount >= gwMax) && StrIWildMatch(pszDomain, ppszStrings[gwDomain])) {
  218. strcpy(pszGateway, ppszStrings[gwGateway]);
  219. StrFreeStrings(ppszStrings);
  220. fclose(pGwFile);
  221. RLckUnlockSH(hResLock);
  222. return (0);
  223. }
  224. StrFreeStrings(ppszStrings);
  225. }
  226. fclose(pGwFile);
  227. RLckUnlockSH(hResLock);
  228. ErrSetErrorCode(ERR_SMTPGW_NOT_FOUND);
  229. return (ERR_SMTPGW_NOT_FOUND);
  230. }
  231. static int USmtpWriteGateway(FILE * pGwFile, const char *pszDomain, const char *pszGateway)
  232. {
  233. ///////////////////////////////////////////////////////////////////////////////
  234. //  Domain
  235. ///////////////////////////////////////////////////////////////////////////////
  236. char *pszQuoted = StrQuote(pszDomain, '"');
  237. if (pszQuoted == NULL)
  238. return (ErrGetErrorCode());
  239. fprintf(pGwFile, "%st", pszQuoted);
  240. SysFree(pszQuoted);
  241. ///////////////////////////////////////////////////////////////////////////////
  242. //  Gateway
  243. ///////////////////////////////////////////////////////////////////////////////
  244. pszQuoted = StrQuote(pszGateway, '"');
  245. if (pszQuoted == NULL)
  246. return (ErrGetErrorCode());
  247. fprintf(pGwFile, "%sn", pszQuoted);
  248. SysFree(pszQuoted);
  249. return (0);
  250. }
  251. int USmtpAddGateway(const char *pszDomain, const char *pszGateway)
  252. {
  253. char szGwFilePath[SYS_MAX_PATH] = "";
  254. USmtpGetGwTableFilePath(szGwFilePath, sizeof(szGwFilePath));
  255. char szResLock[SYS_MAX_PATH] = "";
  256. RLCK_HANDLE hResLock = RLckLockEX(CfgGetBasedPath(szGwFilePath, szResLock,
  257.   sizeof(szResLock)));
  258. if (hResLock == INVALID_RLCK_HANDLE)
  259. return (ErrGetErrorCode());
  260. FILE *pGwFile = fopen(szGwFilePath, "r+t");
  261. if (pGwFile == NULL) {
  262. RLckUnlockEX(hResLock);
  263. ErrSetErrorCode(ERR_SMTPGW_FILE_NOT_FOUND);
  264. return (ERR_SMTPGW_FILE_NOT_FOUND);
  265. }
  266. char szGwLine[SMTPGW_LINE_MAX] = "";
  267. while (MscGetConfigLine(szGwLine, sizeof(szGwLine) - 1, pGwFile) != NULL) {
  268. char **ppszStrings = StrGetTabLineStrings(szGwLine);
  269. if (ppszStrings == NULL)
  270. continue;
  271. int iFieldsCount = StrStringsCount(ppszStrings);
  272. if ((iFieldsCount >= gwMax) && (stricmp(pszDomain, ppszStrings[gwDomain]) == 0) &&
  273.     (stricmp(pszGateway, ppszStrings[gwGateway]) == 0)) {
  274. StrFreeStrings(ppszStrings);
  275. fclose(pGwFile);
  276. RLckUnlockEX(hResLock);
  277. ErrSetErrorCode(ERR_GATEWAY_ALREADY_EXIST);
  278. return (ERR_GATEWAY_ALREADY_EXIST);
  279. }
  280. StrFreeStrings(ppszStrings);
  281. }
  282. fseek(pGwFile, 0, SEEK_END);
  283. if (USmtpWriteGateway(pGwFile, pszDomain, pszGateway) < 0) {
  284. fclose(pGwFile);
  285. RLckUnlockEX(hResLock);
  286. return (ErrGetErrorCode());
  287. }
  288. fclose(pGwFile);
  289. RLckUnlockEX(hResLock);
  290. return (0);
  291. }
  292. int USmtpRemoveGateway(const char *pszDomain)
  293. {
  294. char szGwFilePath[SYS_MAX_PATH] = "";
  295. USmtpGetGwTableFilePath(szGwFilePath, sizeof(szGwFilePath));
  296. char szTmpFile[SYS_MAX_PATH] = "";
  297. SysGetTmpFile(szTmpFile);
  298. char szResLock[SYS_MAX_PATH] = "";
  299. RLCK_HANDLE hResLock = RLckLockEX(CfgGetBasedPath(szGwFilePath, szResLock,
  300.   sizeof(szResLock)));
  301. if (hResLock == INVALID_RLCK_HANDLE)
  302. return (ErrGetErrorCode());
  303. FILE *pGwFile = fopen(szGwFilePath, "rt");
  304. if (pGwFile == NULL) {
  305. RLckUnlockEX(hResLock);
  306. ErrSetErrorCode(ERR_SMTPGW_FILE_NOT_FOUND);
  307. return (ERR_SMTPGW_FILE_NOT_FOUND);
  308. }
  309. FILE *pTmpFile = fopen(szTmpFile, "wt");
  310. if (pTmpFile == NULL) {
  311. fclose(pGwFile);
  312. RLckUnlockEX(hResLock);
  313. ErrSetErrorCode(ERR_FILE_CREATE);
  314. return (ERR_FILE_CREATE);
  315. }
  316. int iGatewayFound = 0;
  317. char szGwLine[SMTPGW_LINE_MAX] = "";
  318. while (MscGetConfigLine(szGwLine, sizeof(szGwLine) - 1, pGwFile, false) != NULL) {
  319. if (szGwLine[0] == TAB_COMMENT_CHAR) {
  320. fprintf(pTmpFile, "%sn", szGwLine);
  321. continue;
  322. }
  323. char **ppszStrings = StrGetTabLineStrings(szGwLine);
  324. if (ppszStrings == NULL)
  325. continue;
  326. int iFieldsCount = StrStringsCount(ppszStrings);
  327. if ((iFieldsCount >= gwMax) && (stricmp(pszDomain, ppszStrings[gwDomain]) == 0)) {
  328. ++iGatewayFound;
  329. } else
  330. fprintf(pTmpFile, "%sn", szGwLine);
  331. StrFreeStrings(ppszStrings);
  332. }
  333. fclose(pGwFile);
  334. fclose(pTmpFile);
  335. if (iGatewayFound == 0) {
  336. SysRemove(szTmpFile);
  337. RLckUnlockEX(hResLock);
  338. ErrSetErrorCode(ERR_GATEWAY_NOT_FOUND);
  339. return (ERR_GATEWAY_NOT_FOUND);
  340. }
  341. char szTmpGwFilePath[SYS_MAX_PATH] = "";
  342. sprintf(szTmpGwFilePath, "%s.tmp", szGwFilePath);
  343. if (MscMoveFile(szGwFilePath, szTmpGwFilePath) < 0) {
  344. ErrorPush();
  345. RLckUnlockEX(hResLock);
  346. return (ErrorPop());
  347. }
  348. if (MscMoveFile(szTmpFile, szGwFilePath) < 0) {
  349. ErrorPush();
  350. MscMoveFile(szTmpGwFilePath, szGwFilePath);
  351. RLckUnlockEX(hResLock);
  352. return (ErrorPop());
  353. }
  354. SysRemove(szTmpGwFilePath);
  355. RLckUnlockEX(hResLock);
  356. return (0);
  357. }
  358. int USmtpIsAllowedRelay(const SYS_INET_ADDR & PeerInfo, SVRCFG_HANDLE hSvrConfig)
  359. {
  360. char szRelayFilePath[SYS_MAX_PATH] = "";
  361. USmtpGetRelayFilePath(szRelayFilePath, sizeof(szRelayFilePath));
  362. char szResLock[SYS_MAX_PATH] = "";
  363. RLCK_HANDLE hResLock = RLckLockSH(CfgGetBasedPath(szRelayFilePath, szResLock,
  364.   sizeof(szResLock)));
  365. if (hResLock == INVALID_RLCK_HANDLE)
  366. return (ErrGetErrorCode());
  367. FILE *pRelayFile = fopen(szRelayFilePath, "rt");
  368. if (pRelayFile == NULL) {
  369. RLckUnlockSH(hResLock);
  370. ErrSetErrorCode(ERR_SMTPRELAY_FILE_NOT_FOUND);
  371. return (ERR_SMTPRELAY_FILE_NOT_FOUND);
  372. }
  373. NET_ADDRESS TestAddr;
  374. SysGetAddrAddress(PeerInfo, TestAddr);
  375. char szRelayLine[SMTPRELAY_LINE_MAX] = "";
  376. while (MscGetConfigLine(szRelayLine, sizeof(szRelayLine) - 1, pRelayFile) != NULL) {
  377. char **ppszStrings = StrGetTabLineStrings(szRelayLine);
  378. if (ppszStrings == NULL)
  379. continue;
  380. int iFieldsCount = StrStringsCount(ppszStrings);
  381. AddressFilter AF;
  382. if ((iFieldsCount > 0) &&
  383.     (MscLoadAddressFilter(ppszStrings, iFieldsCount, AF) == 0) &&
  384.     MscAddressMatch(AF, TestAddr)) {
  385. StrFreeStrings(ppszStrings);
  386. fclose(pRelayFile);
  387. RLckUnlockSH(hResLock);
  388. return (0);
  389. }
  390. StrFreeStrings(ppszStrings);
  391. }
  392. fclose(pRelayFile);
  393. RLckUnlockSH(hResLock);
  394. ErrSetErrorCode(ERR_RELAY_NOT_ALLOWED);
  395. return (ERR_RELAY_NOT_ALLOWED);
  396. }
  397. char **USmtpGetPathStrings(const char *pszMailCmd)
  398. {
  399. const char *pszOpen = strchr(pszMailCmd, '<');
  400. const char *pszClose = strchr(pszMailCmd, '>');
  401. if ((pszOpen == NULL) || (pszClose == NULL)) {
  402. ErrSetErrorCode(ERR_SMTP_PATH_PARSE_ERROR);
  403. return (NULL);
  404. }
  405. int iPathLength = (int) (pszClose - pszOpen) - 1;
  406. if ((iPathLength < 0) || (iPathLength >= MAX_SMTP_ADDRESS)) {
  407. ErrSetErrorCode(ERR_SMTP_PATH_PARSE_ERROR, pszMailCmd);
  408. return (NULL);
  409. }
  410. char *pszPath = (char *) SysAlloc(iPathLength + 1);
  411. if (pszPath == NULL)
  412. return (NULL);
  413. strncpy(pszPath, pszOpen + 1, iPathLength);
  414. pszPath[iPathLength] = '';
  415. char **ppszDomains = StrTokenize(pszPath, ",:");
  416. SysFree(pszPath);
  417. return (ppszDomains);
  418. }
  419. int USmtpSplitEmailAddr(const char *pszAddr, char *pszUser, char *pszDomain)
  420. {
  421. const char *pszAT = strchr(pszAddr, '@');
  422. if (pszAT == NULL) {
  423. ErrSetErrorCode(ERR_BAD_EMAIL_ADDR);
  424. return (ERR_BAD_EMAIL_ADDR);
  425. }
  426. int iUserLength = (int) (pszAT - pszAddr);
  427. int iDomainLength = strlen(pszAT + 1);
  428. if (pszUser != NULL) {
  429. if (iUserLength == 0) {
  430. ErrSetErrorCode(ERR_BAD_EMAIL_ADDR);
  431. return (ERR_BAD_EMAIL_ADDR);
  432. }
  433. iUserLength = Min(iUserLength, MAX_ADDR_NAME - 1);
  434. strncpy(pszUser, pszAddr, iUserLength);
  435. pszUser[iUserLength] = '';
  436. }
  437. if (pszDomain != NULL) {
  438. if (iDomainLength == 0) {
  439. ErrSetErrorCode(ERR_BAD_EMAIL_ADDR);
  440. return (ERR_BAD_EMAIL_ADDR);
  441. }
  442. StrNCpy(pszDomain, pszAT + 1, MAX_ADDR_NAME);
  443. }
  444. return (0);
  445. }
  446. int USmtpCheckAddressPart(char const *pszName)
  447. {
  448. for (; *pszName; pszName++)
  449. if ((*pszName <= ' ') || (*pszName == 127) ||
  450.     (strchr(RFC_SPECIALS, *pszName) != NULL)) {
  451. ErrSetErrorCode(ERR_BAD_RFCNAME);
  452. return (ERR_BAD_RFCNAME);
  453. }
  454. return (0);
  455. }
  456. int USmtpCheckAddress(char const *pszAddress)
  457. {
  458. char szUser[MAX_ADDR_NAME] = "";
  459. char szDomain[MAX_ADDR_NAME] = "";
  460. if ((USmtpSplitEmailAddr(pszAddress, szUser, szDomain) < 0) ||
  461.     (USmtpCheckAddressPart(szUser) < 0) || (USmtpCheckAddressPart(szDomain) < 0))
  462. return (ErrGetErrorCode());
  463. return (0);
  464. }
  465. int USmtpInitError(SMTPError * pSMTPE)
  466. {
  467. ZeroData(*pSMTPE);
  468. pSMTPE->iSTMPResponse = 0;
  469. pSMTPE->pszSTMPResponse = NULL;
  470. pSMTPE->pszServer = NULL;
  471. return (0);
  472. }
  473. static int USmtpSetError(SMTPError * pSMTPE, int iSTMPResponse, char const *pszSTMPResponse,
  474.  char const *pszServer)
  475. {
  476. pSMTPE->iSTMPResponse = iSTMPResponse;
  477. if (pSMTPE->pszSTMPResponse != NULL)
  478. SysFree(pSMTPE->pszSTMPResponse);
  479. if (pSMTPE->pszServer != NULL)
  480. SysFree(pSMTPE->pszServer);
  481. pSMTPE->pszSTMPResponse = SysStrDup(pszSTMPResponse);
  482. pSMTPE->pszServer = SysStrDup(pszServer);
  483. return (0);
  484. }
  485. static int USmtpSetErrorServer(SMTPError * pSMTPE, char const *pszServer)
  486. {
  487. if (pSMTPE->pszServer != NULL)
  488. SysFree(pSMTPE->pszServer);
  489. pSMTPE->pszServer = SysStrDup(pszServer);
  490. return (0);
  491. }
  492. bool USmtpIsFatalError(SMTPError const *pSMTPE)
  493. {
  494. return ((pSMTPE->iSTMPResponse == SMTP_FATAL_ERROR) ||
  495. ((pSMTPE->iSTMPResponse >= 500) && (pSMTPE->iSTMPResponse < 600)));
  496. }
  497. char const *USmtpGetErrorMessage(SMTPError const *pSMTPE)
  498. {
  499. return ((pSMTPE->pszSTMPResponse != NULL) ? pSMTPE->pszSTMPResponse : "");
  500. }
  501. int USmtpCleanupError(SMTPError * pSMTPE)
  502. {
  503. if (pSMTPE->pszSTMPResponse != NULL)
  504. SysFree(pSMTPE->pszSTMPResponse);
  505. if (pSMTPE->pszServer != NULL)
  506. SysFree(pSMTPE->pszServer);
  507. USmtpInitError(pSMTPE);
  508. return (0);
  509. }
  510. char *USmtpGetSMTPError(SMTPError * pSMTPE, char *pszError, int iMaxError)
  511. {
  512. char const *pszSmtpErr =
  513.     (pSMTPE != NULL) ? USmtpGetErrorMessage(pSMTPE) : DEFAULT_SMTP_ERR;
  514. if (IsEmptyString(pszSmtpErr))
  515. pszSmtpErr = DEFAULT_SMTP_ERR;
  516. StrNCpy(pszError, pszSmtpErr, iMaxError);
  517. return (pszError);
  518. }
  519. char const *USmtpGetErrorServer(SMTPError const *pSMTPE)
  520. {
  521. return ((pSMTPE->pszServer != NULL) ? pSMTPE->pszServer : "");
  522. }
  523. static int USmtpResponseClass(int iResponseCode, int iResponseClass)
  524. {
  525. return (((iResponseCode >= iResponseClass) &&
  526.  (iResponseCode < (iResponseClass + 100))) ? 1 : 0);
  527. }
  528. static int USmtpGetResultCode(const char *pszResult)
  529. {
  530. int ii;
  531. char szResCode[64] = "";
  532. for (ii = 0; (ii < sizeof(szResCode)) && isdigit(pszResult[ii]); ii++)
  533. szResCode[ii] = pszResult[ii];
  534. if ((ii == 0) || (ii == sizeof(szResCode))) {
  535. ErrSetErrorCode(ERR_BAD_SMTP_RESPONSE);
  536. return (ERR_BAD_SMTP_RESPONSE);
  537. }
  538. szResCode[ii] = '';
  539. return (atoi(szResCode));
  540. }
  541. static int USmtpIsPartialResponse(char const *pszResponse)
  542. {
  543. return (((strlen(pszResponse) >= 4) && (pszResponse[3] == '-')) ? 1 : 0);
  544. }
  545. static int USmtpGetResponse(BSOCK_HANDLE hBSock, char *pszResponse, int iMaxResponse,
  546.     int iTimeout)
  547. {
  548. int iResultCode = -1;
  549. int iResponseLenght = 0;
  550. char szPartial[1024] = "";
  551. SetEmptyString(pszResponse);
  552. do {
  553. int iLineLength = 0;
  554. if (BSckGetString(hBSock, szPartial, sizeof(szPartial) - 1, iTimeout,
  555.   &iLineLength) == NULL)
  556. return (ErrGetErrorCode());
  557. if ((iResponseLenght + 2) < iMaxResponse) {
  558. if (iResponseLenght > 0)
  559. strcat(pszResponse, "rn"), iResponseLenght += 2;
  560. int iCopyLenght = Min(iMaxResponse - 1 - iResponseLenght, iLineLength);
  561. if (iCopyLenght > 0) {
  562. strncpy(pszResponse + iResponseLenght, szPartial, iCopyLenght);
  563. iResponseLenght += iCopyLenght;
  564. pszResponse[iResponseLenght] = '';
  565. }
  566. }
  567. if ((iResultCode = USmtpGetResultCode(szPartial)) < 0)
  568. return (ErrGetErrorCode());
  569. } while (USmtpIsPartialResponse(szPartial));
  570. return (iResultCode);
  571. }
  572. static int USmtpSendCommand(BSOCK_HANDLE hBSock, const char *pszCommand,
  573.     char *pszResponse, int iMaxResponse, int iTimeout)
  574. {
  575. if (BSckSendString(hBSock, pszCommand, iTimeout) <= 0)
  576. return (ErrGetErrorCode());
  577. return (USmtpGetResponse(hBSock, pszResponse, iMaxResponse, iTimeout));
  578. }
  579. static int USmtpGetServerAuthFile(char const *pszServer, char *pszAuthFilePath)
  580. {
  581. int iRootedName = MscRootedName(pszServer);
  582. char szAuthPath[SYS_MAX_PATH] = "";
  583. UAthGetRootPath(AUTH_SERVICE_SMTP, szAuthPath, sizeof(szAuthPath));
  584. char const *pszDot = pszServer;
  585. while ((pszDot != NULL) && (strlen(pszDot) > 0)) {
  586. if (iRootedName)
  587. sprintf(pszAuthFilePath, "%s%stab", szAuthPath, pszDot);
  588. else
  589. sprintf(pszAuthFilePath, "%s%s.tab", szAuthPath, pszDot);
  590. if (SysExistFile(pszAuthFilePath))
  591. return (0);
  592. if ((pszDot = strchr(pszDot, '.')) != NULL)
  593. ++pszDot;
  594. }
  595. ErrSetErrorCode(ERR_NO_SMTP_AUTH_CONFIG);
  596. return (ERR_NO_SMTP_AUTH_CONFIG);
  597. }
  598. static int USmtpDoPlainAuth(SmtpChannel * pSmtpCh, char const *pszServer,
  599.     char const *const *ppszAuthTokens, SMTPError * pSMTPE)
  600. {
  601. if (StrStringsCount(ppszAuthTokens) < 3) {
  602. ErrSetErrorCode(ERR_BAD_SMTP_AUTH_CONFIG);
  603. return (ERR_BAD_SMTP_AUTH_CONFIG);
  604. }
  605. ///////////////////////////////////////////////////////////////////////////////
  606. //  Build plain text authentication token ( "" Username "" Password "" )
  607. ///////////////////////////////////////////////////////////////////////////////
  608. int iAuthLength = 1;
  609. char szAuthBuffer[2048] = "";
  610. strcpy(szAuthBuffer + iAuthLength, ppszAuthTokens[1]);
  611. iAuthLength += strlen(ppszAuthTokens[1]) + 1;
  612. strcpy(szAuthBuffer + iAuthLength, ppszAuthTokens[2]);
  613. iAuthLength += strlen(ppszAuthTokens[2]);
  614. unsigned int uEnc64Length = 0;
  615. char szEnc64Token[1024] = "";
  616. encode64(szAuthBuffer, iAuthLength, szEnc64Token, sizeof(szEnc64Token), &uEnc64Length);
  617. ///////////////////////////////////////////////////////////////////////////////
  618. //  Send AUTH command
  619. ///////////////////////////////////////////////////////////////////////////////
  620. int iSvrReponse;
  621. SysSNPrintf(szAuthBuffer, sizeof(szAuthBuffer) - 1, "AUTH PLAIN %s", szEnc64Token);
  622. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, szAuthBuffer,
  623.        szAuthBuffer,
  624.        sizeof(szAuthBuffer) - 1), 200)) {
  625. if (iSvrReponse > 0) {
  626. if (pSMTPE != NULL)
  627. USmtpSetError(pSMTPE, iSvrReponse, szAuthBuffer,
  628.       pSmtpCh->pszServer);
  629. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szAuthBuffer);
  630. }
  631. return (ErrGetErrorCode());
  632. }
  633. return (0);
  634. }
  635. static int USmtpDoLoginAuth(SmtpChannel * pSmtpCh, char const *pszServer,
  636.     char const *const *ppszAuthTokens, SMTPError * pSMTPE)
  637. {
  638. if (StrStringsCount(ppszAuthTokens) < 3) {
  639. ErrSetErrorCode(ERR_BAD_SMTP_AUTH_CONFIG);
  640. return (ERR_BAD_SMTP_AUTH_CONFIG);
  641. }
  642. ///////////////////////////////////////////////////////////////////////////////
  643. //  Send AUTH command
  644. ///////////////////////////////////////////////////////////////////////////////
  645. int iSvrReponse;
  646. char szAuthBuffer[1024] = "";
  647. sprintf(szAuthBuffer, "AUTH LOGIN");
  648. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, szAuthBuffer,
  649.        szAuthBuffer,
  650.        sizeof(szAuthBuffer) - 1), 300)) {
  651. if (iSvrReponse > 0) {
  652. if (pSMTPE != NULL)
  653. USmtpSetError(pSMTPE, iSvrReponse, szAuthBuffer,
  654.       pSmtpCh->pszServer);
  655. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szAuthBuffer);
  656. }
  657. return (ErrGetErrorCode());
  658. }
  659. ///////////////////////////////////////////////////////////////////////////////
  660. //  Send username
  661. ///////////////////////////////////////////////////////////////////////////////
  662. unsigned int uEnc64Length = 0;
  663. encode64(ppszAuthTokens[1], strlen(ppszAuthTokens[1]), szAuthBuffer,
  664.  sizeof(szAuthBuffer), &uEnc64Length);
  665. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, szAuthBuffer,
  666.        szAuthBuffer,
  667.        sizeof(szAuthBuffer) - 1), 300)) {
  668. if (iSvrReponse > 0) {
  669. if (pSMTPE != NULL)
  670. USmtpSetError(pSMTPE, iSvrReponse, szAuthBuffer,
  671.       pSmtpCh->pszServer);
  672. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szAuthBuffer);
  673. }
  674. return (ErrGetErrorCode());
  675. }
  676. ///////////////////////////////////////////////////////////////////////////////
  677. //  Send password
  678. ///////////////////////////////////////////////////////////////////////////////
  679. encode64(ppszAuthTokens[2], strlen(ppszAuthTokens[2]), szAuthBuffer,
  680.  sizeof(szAuthBuffer), &uEnc64Length);
  681. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, szAuthBuffer,
  682.        szAuthBuffer,
  683.        sizeof(szAuthBuffer) - 1), 200)) {
  684. if (iSvrReponse > 0) {
  685. if (pSMTPE != NULL)
  686. USmtpSetError(pSMTPE, iSvrReponse, szAuthBuffer,
  687.       pSmtpCh->pszServer);
  688. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szAuthBuffer);
  689. }
  690. return (ErrGetErrorCode());
  691. }
  692. return (0);
  693. }
  694. static int USmtpDoCramMD5Auth(SmtpChannel * pSmtpCh, char const *pszServer,
  695.       char const *const *ppszAuthTokens, SMTPError * pSMTPE)
  696. {
  697. if (StrStringsCount(ppszAuthTokens) < 3) {
  698. ErrSetErrorCode(ERR_BAD_SMTP_AUTH_CONFIG);
  699. return (ERR_BAD_SMTP_AUTH_CONFIG);
  700. }
  701. ///////////////////////////////////////////////////////////////////////////////
  702. //  Send AUTH command
  703. ///////////////////////////////////////////////////////////////////////////////
  704. int iSvrReponse;
  705. char szAuthBuffer[1024] = "";
  706. sprintf(szAuthBuffer, "AUTH CRAM-MD5");
  707. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, szAuthBuffer,
  708.        szAuthBuffer,
  709.        sizeof(szAuthBuffer) - 1), 300) ||
  710.     (strlen(szAuthBuffer) < 4)) {
  711. if (iSvrReponse > 0) {
  712. if (pSMTPE != NULL)
  713. USmtpSetError(pSMTPE, iSvrReponse, szAuthBuffer,
  714.       pSmtpCh->pszServer);
  715. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szAuthBuffer);
  716. }
  717. return (ErrGetErrorCode());
  718. }
  719. ///////////////////////////////////////////////////////////////////////////////
  720. //  Retrieve server challenge
  721. ///////////////////////////////////////////////////////////////////////////////
  722. unsigned int uDec64Length = 0;
  723. char *pszAuth = szAuthBuffer + 4;
  724. char szChallenge[1024] = "";
  725. if (decode64(pszAuth, strlen(pszAuth), szChallenge, &uDec64Length) != 0) {
  726. if (pSMTPE != NULL)
  727. USmtpSetError(pSMTPE, iSvrReponse, szAuthBuffer, pSmtpCh->pszServer);
  728. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szAuthBuffer);
  729. return (ERR_BAD_SERVER_RESPONSE);
  730. }
  731. ///////////////////////////////////////////////////////////////////////////////
  732. //  Compute MD5 response ( secret , challenge , digest )
  733. ///////////////////////////////////////////////////////////////////////////////
  734. if (MscCramMD5(ppszAuthTokens[2], szChallenge, szChallenge) < 0)
  735. return (ErrGetErrorCode());
  736. ///////////////////////////////////////////////////////////////////////////////
  737. //  Send response
  738. ///////////////////////////////////////////////////////////////////////////////
  739. unsigned int uEnc64Length = 0;
  740. char szResponse[1024] = "";
  741. SysSNPrintf(szResponse, sizeof(szResponse) - 1, "%s %s", ppszAuthTokens[1], szChallenge);
  742. encode64(szResponse, strlen(szResponse), szAuthBuffer,
  743.  sizeof(szAuthBuffer), &uEnc64Length);
  744. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, szAuthBuffer,
  745.        szAuthBuffer,
  746.        sizeof(szAuthBuffer) - 1), 200)) {
  747. if (iSvrReponse > 0) {
  748. if (pSMTPE != NULL)
  749. USmtpSetError(pSMTPE, iSvrReponse, szAuthBuffer,
  750.       pSmtpCh->pszServer);
  751. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szAuthBuffer);
  752. }
  753. return (ErrGetErrorCode());
  754. }
  755. return (0);
  756. }
  757. static int USmtpExternalAuthSubstitute(char **ppszAuthTokens, char const *pszChallenge,
  758.        char const *pszSecret, char const *pszRespFile)
  759. {
  760. for (int ii = 0; ppszAuthTokens[ii] != NULL; ii++) {
  761. if (strcmp(ppszAuthTokens[ii], "@@CHALL") == 0) {
  762. char *pszNewValue = SysStrDup(pszChallenge);
  763. if (pszNewValue == NULL)
  764. return (ErrGetErrorCode());
  765. SysFree(ppszAuthTokens[ii]);
  766. ppszAuthTokens[ii] = pszNewValue;
  767. } else if (strcmp(ppszAuthTokens[ii], "@@SECRT") == 0) {
  768. char *pszNewValue = SysStrDup(pszSecret);
  769. if (pszNewValue == NULL)
  770. return (ErrGetErrorCode());
  771. SysFree(ppszAuthTokens[ii]);
  772. ppszAuthTokens[ii] = pszNewValue;
  773. } else if (strcmp(ppszAuthTokens[ii], "@@RFILE") == 0) {
  774. char *pszNewValue = SysStrDup(pszRespFile);
  775. if (pszNewValue == NULL)
  776. return (ErrGetErrorCode());
  777. SysFree(ppszAuthTokens[ii]);
  778. ppszAuthTokens[ii] = pszNewValue;
  779. }
  780. }
  781. return (0);
  782. }
  783. static int USmtpDoExternAuth(SmtpChannel * pSmtpCh, char const *pszServer,
  784.      char **ppszAuthTokens, SMTPError * pSMTPE)
  785. {
  786. if (StrStringsCount(ppszAuthTokens) < 4) {
  787. ErrSetErrorCode(ERR_BAD_SMTP_AUTH_CONFIG);
  788. return (ERR_BAD_SMTP_AUTH_CONFIG);
  789. }
  790. ///////////////////////////////////////////////////////////////////////////////
  791. //  Send AUTH command
  792. ///////////////////////////////////////////////////////////////////////////////
  793. int iSvrReponse;
  794. char szAuthBuffer[1024] = "";
  795. SysSNPrintf(szAuthBuffer, sizeof(szAuthBuffer) - 1, "AUTH %s", ppszAuthTokens[1]);
  796. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, szAuthBuffer,
  797.        szAuthBuffer,
  798.        sizeof(szAuthBuffer) - 1), 300)) {
  799. if (iSvrReponse > 0) {
  800. if (pSMTPE != NULL)
  801. USmtpSetError(pSMTPE, iSvrReponse, szAuthBuffer,
  802.       pSmtpCh->pszServer);
  803. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szAuthBuffer);
  804. }
  805. return (ErrGetErrorCode());
  806. }
  807. ///////////////////////////////////////////////////////////////////////////////
  808. //  Retrieve server challenge
  809. ///////////////////////////////////////////////////////////////////////////////
  810. unsigned int uDec64Length = 0;
  811. char *pszAuth = szAuthBuffer + 4;
  812. char szChallenge[1024] = "";
  813. if ((strlen(szAuthBuffer) < 4) ||
  814.     (decode64(pszAuth, strlen(pszAuth), szChallenge, &uDec64Length) != 0)) {
  815. if (pSMTPE != NULL)
  816. USmtpSetError(pSMTPE, iSvrReponse, szAuthBuffer, pSmtpCh->pszServer);
  817. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szAuthBuffer);
  818. return (ERR_BAD_SERVER_RESPONSE);
  819. }
  820. ///////////////////////////////////////////////////////////////////////////////
  821. //  Create temp filename for module response and do macro substitution
  822. ///////////////////////////////////////////////////////////////////////////////
  823. char szRespFile[SYS_MAX_PATH] = "";
  824. SysGetTmpFile(szRespFile);
  825. USmtpExternalAuthSubstitute(ppszAuthTokens, szChallenge, ppszAuthTokens[2], szRespFile);
  826. ///////////////////////////////////////////////////////////////////////////////
  827. //  Call external program to compute the response
  828. ///////////////////////////////////////////////////////////////////////////////
  829. int iExitCode = -1;
  830. if (SysExec(ppszAuthTokens[3], &ppszAuthTokens[3], SMTP_EXTAUTH_TIMEOUT,
  831.     SMTP_EXTAUTH_PRIORITY, &iExitCode) < 0) {
  832. ErrorPush();
  833. CheckRemoveFile(szRespFile);
  834. return (ErrorPop());
  835. }
  836. if (iExitCode != SMTP_EXTAUTH_SUCCESS) {
  837. CheckRemoveFile(szRespFile);
  838. ErrSetErrorCode(ERR_BAD_EXTRNPRG_EXITCODE);
  839. return (ERR_BAD_EXTRNPRG_EXITCODE);
  840. }
  841. ///////////////////////////////////////////////////////////////////////////////
  842. //  Load response file
  843. ///////////////////////////////////////////////////////////////////////////////
  844. unsigned int uRespSize = 0;
  845. char *pAuthResp = (char *) MscLoadFile(szRespFile, uRespSize);
  846. CheckRemoveFile(szRespFile);
  847. if (pAuthResp == NULL)
  848. return (ErrGetErrorCode());
  849. while ((uRespSize > 0) &&
  850.        ((pAuthResp[uRespSize - 1] == 'r') || (pAuthResp[uRespSize - 1] == 'n')))
  851. --uRespSize;
  852. ///////////////////////////////////////////////////////////////////////////////
  853. //  Send response
  854. ///////////////////////////////////////////////////////////////////////////////
  855. unsigned int uEnc64Length = 0;
  856. encode64(pAuthResp, uRespSize, szAuthBuffer, sizeof(szAuthBuffer), &uEnc64Length);
  857. SysFree(pAuthResp);
  858. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, szAuthBuffer,
  859.        szAuthBuffer,
  860.        sizeof(szAuthBuffer) - 1), 200)) {
  861. if (iSvrReponse > 0) {
  862. if (pSMTPE != NULL)
  863. USmtpSetError(pSMTPE, iSvrReponse, szAuthBuffer,
  864.       pSmtpCh->pszServer);
  865. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szAuthBuffer);
  866. }
  867. return (ErrGetErrorCode());
  868. }
  869. return (0);
  870. }
  871. static int USmtpServerAuthenticate(SmtpChannel * pSmtpCh, char const *pszServer,
  872.    SMTPError * pSMTPE)
  873. {
  874. ///////////////////////////////////////////////////////////////////////////////
  875. //  Try to retrieve SMTP authentication config for  "pszServer"
  876. ///////////////////////////////////////////////////////////////////////////////
  877. char szAuthFilePath[SYS_MAX_PATH] = "";
  878. if (USmtpGetServerAuthFile(pszServer, szAuthFilePath) < 0)
  879. return (0);
  880. FILE *pAuthFile = fopen(szAuthFilePath, "rt");
  881. if (pAuthFile == NULL) {
  882. ErrSetErrorCode(ERR_FILE_OPEN, szAuthFilePath);
  883. return (ERR_FILE_OPEN);
  884. }
  885. char szAuthLine[SMTPAUTH_LINE_MAX] = "";
  886. while (MscGetConfigLine(szAuthLine, sizeof(szAuthLine) - 1, pAuthFile) != NULL) {
  887. char **ppszTokens = StrGetTabLineStrings(szAuthLine);
  888. if (ppszTokens == NULL)
  889. continue;
  890. int iFieldsCount = StrStringsCount(ppszTokens);
  891. if (iFieldsCount > 0) {
  892. int iAuthResult = 0;
  893. if (stricmp(ppszTokens[0], "plain") == 0)
  894. iAuthResult =
  895.     USmtpDoPlainAuth(pSmtpCh, pszServer, ppszTokens, pSMTPE);
  896. else if (stricmp(ppszTokens[0], "login") == 0)
  897. iAuthResult =
  898.     USmtpDoLoginAuth(pSmtpCh, pszServer, ppszTokens, pSMTPE);
  899. else if (stricmp(ppszTokens[0], "cram-md5") == 0)
  900. iAuthResult =
  901.     USmtpDoCramMD5Auth(pSmtpCh, pszServer, ppszTokens, pSMTPE);
  902. else if (stricmp(ppszTokens[0], "external") == 0)
  903. iAuthResult =
  904.     USmtpDoExternAuth(pSmtpCh, pszServer, ppszTokens, pSMTPE);
  905. else
  906. ErrSetErrorCode(iAuthResult =
  907. ERR_UNKNOWN_SMTP_AUTH, ppszTokens[0]);
  908. StrFreeStrings(ppszTokens);
  909. fclose(pAuthFile);
  910. return (iAuthResult);
  911. }
  912. StrFreeStrings(ppszTokens);
  913. }
  914. fclose(pAuthFile);
  915. return (0);
  916. }
  917. static int USmtpParseEhloResponse(SmtpChannel * pSmtpCh, char const *pszResponse)
  918. {
  919. char const *pszLine = pszResponse;
  920. for (; pszLine != NULL; pszLine = strchr(pszLine, 'n')) {
  921. if (*pszLine == 'n')
  922. ++pszLine;
  923. ///////////////////////////////////////////////////////////////////////////////
  924. //  Skip SMTP code and ' ' or '-'
  925. ///////////////////////////////////////////////////////////////////////////////
  926. if (strlen(pszLine) < 4)
  927. continue;
  928. pszLine += 4;
  929. ///////////////////////////////////////////////////////////////////////////////
  930. //  SIZE suport detection
  931. ///////////////////////////////////////////////////////////////////////////////
  932. if ((strnicmp(pszLine, "SIZE", CStringSize("SIZE")) == 0) &&
  933.     (strchr(" rn", pszLine[CStringSize("SIZE")]) != NULL)) {
  934. pSmtpCh->ulFlags |= SMTPCH_SUPPORT_SIZE;
  935. if ((pszLine[CStringSize("SIZE")] == ' ') &&
  936.     isdigit(pszLine[CStringSize("SIZE") + 1]))
  937. pSmtpCh->ulMaxMsgSize =
  938.     (unsigned long) atol(pszLine + CStringSize("SIZE") + 1);
  939. continue;
  940. }
  941. }
  942. return (0);
  943. }
  944. SMTPCH_HANDLE USmtpCreateChannel(const char *pszServer, const char *pszDomain, SMTPError * pSMTPE)
  945. {
  946. ///////////////////////////////////////////////////////////////////////////////
  947. //  Decode server address
  948. ///////////////////////////////////////////////////////////////////////////////
  949. int iPortNo = STD_SMTP_PORT;
  950. char szAddress[MAX_ADDR_NAME] = "";
  951. if (MscSplitAddressPort(pszServer, szAddress, iPortNo, STD_SMTP_PORT) < 0)
  952. return (INVALID_SMTPCH_HANDLE);
  953. SYS_INET_ADDR SvrAddr;
  954. if (MscGetServerAddress(szAddress, SvrAddr, iPortNo) < 0)
  955. return (INVALID_SMTPCH_HANDLE);
  956. SYS_SOCKET SockFD = SysCreateSocket(AF_INET, SOCK_STREAM, 0);
  957. if (SockFD == SYS_INVALID_SOCKET)
  958. return (INVALID_SMTPCH_HANDLE);
  959. if (SysConnect(SockFD, &SvrAddr, sizeof(SvrAddr), STD_SMTP_TIMEOUT) < 0) {
  960. SysCloseSocket(SockFD);
  961. return (INVALID_SMTPCH_HANDLE);
  962. }
  963. ///////////////////////////////////////////////////////////////////////////////
  964. //  Check if We need to supply an HELO host
  965. ///////////////////////////////////////////////////////////////////////////////
  966. char szHeloHost[MAX_HOST_NAME] = "";
  967. if (pszDomain == NULL) {
  968. ///////////////////////////////////////////////////////////////////////////////
  969. //  Get the DNS name of the local interface
  970. ///////////////////////////////////////////////////////////////////////////////
  971. if (MscGetSockHost(SockFD, szHeloHost) < 0) {
  972. SYS_INET_ADDR SockInfo;
  973. if (SysGetSockInfo(SockFD, SockInfo) < 0) {
  974. SysCloseSocket(SockFD);
  975. return (INVALID_SMTPCH_HANDLE);
  976. }
  977. char szIP[128] = "???.???.???.???";
  978. StrSNCpy(szHeloHost, SysInetNToA(SockInfo, szIP));
  979. }
  980. pszDomain = szHeloHost;
  981. }
  982. ///////////////////////////////////////////////////////////////////////////////
  983. //  Attach socket to buffered reader
  984. ///////////////////////////////////////////////////////////////////////////////
  985. BSOCK_HANDLE hBSock = BSckAttach(SockFD);
  986. if (hBSock == INVALID_BSOCK_HANDLE) {
  987. SysCloseSocket(SockFD);
  988. return (INVALID_SMTPCH_HANDLE);
  989. }
  990. ///////////////////////////////////////////////////////////////////////////////
  991. //  Read welcome message
  992. ///////////////////////////////////////////////////////////////////////////////
  993. SmtpChannel *pSmtpCh = (SmtpChannel *) SysAlloc(sizeof(SmtpChannel));
  994. if (pSmtpCh == NULL) {
  995. BSckDetach(hBSock, 1);
  996. return (INVALID_SMTPCH_HANDLE);
  997. }
  998. pSmtpCh->hBSock = hBSock;
  999. pSmtpCh->ulFlags = 0;
  1000. pSmtpCh->ulMaxMsgSize = 0;
  1001. pSmtpCh->SvrAddr = SvrAddr;
  1002. pSmtpCh->pszServer = SysStrDup(pszServer);
  1003. ///////////////////////////////////////////////////////////////////////////////
  1004. //  Read welcome message
  1005. ///////////////////////////////////////////////////////////////////////////////
  1006. int iSvrReponse = -1;
  1007. char szRTXBuffer[2048] = "";
  1008. if (!USmtpResponseClass(iSvrReponse = USmtpGetResponse(pSmtpCh->hBSock, szRTXBuffer,
  1009.        sizeof(szRTXBuffer) - 1), 200)) {
  1010. BSckDetach(pSmtpCh->hBSock, 1);
  1011. if (iSvrReponse > 0) {
  1012. if (pSMTPE != NULL)
  1013. USmtpSetError(pSMTPE, iSvrReponse, szRTXBuffer,
  1014.       pSmtpCh->pszServer);
  1015. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szRTXBuffer);
  1016. }
  1017. SysFree(pSmtpCh->pszServer);
  1018. SysFree(pSmtpCh);
  1019. return (INVALID_SMTPCH_HANDLE);
  1020. }
  1021. ///////////////////////////////////////////////////////////////////////////////
  1022. //  Try the EHLO ESMTP command before
  1023. ///////////////////////////////////////////////////////////////////////////////
  1024. SysSNPrintf(szRTXBuffer, sizeof(szRTXBuffer) - 1, "EHLO %s", pszDomain);
  1025. if (USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, szRTXBuffer,
  1026.       szRTXBuffer,
  1027.       sizeof(szRTXBuffer) - 1), 200)) {
  1028. ///////////////////////////////////////////////////////////////////////////////
  1029. //  Parse EHLO response
  1030. ///////////////////////////////////////////////////////////////////////////////
  1031. if (USmtpParseEhloResponse(pSmtpCh, szRTXBuffer) < 0) {
  1032. BSckDetach(pSmtpCh->hBSock, 1);
  1033. SysFree(pSmtpCh->pszServer);
  1034. SysFree(pSmtpCh);
  1035. return (INVALID_SMTPCH_HANDLE);
  1036. }
  1037. } else {
  1038. ///////////////////////////////////////////////////////////////////////////////
  1039. //  Send HELO and read result
  1040. ///////////////////////////////////////////////////////////////////////////////
  1041. SysSNPrintf(szRTXBuffer, sizeof(szRTXBuffer) - 1, "HELO %s", pszDomain);
  1042. if (!USmtpResponseClass
  1043.     (iSvrReponse =
  1044.      USmtpSendCommand(pSmtpCh->hBSock, szRTXBuffer, szRTXBuffer,
  1045.       sizeof(szRTXBuffer) - 1), 200)) {
  1046. BSckDetach(pSmtpCh->hBSock, 1);
  1047. if (iSvrReponse > 0) {
  1048. if (pSMTPE != NULL)
  1049. USmtpSetError(pSMTPE, iSvrReponse, szRTXBuffer,
  1050.       pSmtpCh->pszServer);
  1051. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szRTXBuffer);
  1052. }
  1053. SysFree(pSmtpCh->pszServer);
  1054. SysFree(pSmtpCh);
  1055. return (INVALID_SMTPCH_HANDLE);
  1056. }
  1057. }
  1058. ///////////////////////////////////////////////////////////////////////////////
  1059. //  Check if We need authentication
  1060. ///////////////////////////////////////////////////////////////////////////////
  1061. if (USmtpServerAuthenticate(pSmtpCh, szAddress, pSMTPE) < 0) {
  1062. USmtpCloseChannel((SMTPCH_HANDLE) pSmtpCh, 0, pSMTPE);
  1063. return (INVALID_SMTPCH_HANDLE);
  1064. }
  1065. return ((SMTPCH_HANDLE) pSmtpCh);
  1066. }
  1067. int USmtpCloseChannel(SMTPCH_HANDLE hSmtpCh, int iHardClose, SMTPError * pSMTPE)
  1068. {
  1069. SmtpChannel *pSmtpCh = (SmtpChannel *) hSmtpCh;
  1070. if (!iHardClose) {
  1071. ///////////////////////////////////////////////////////////////////////////////
  1072. //  Send QUIT and read result
  1073. ///////////////////////////////////////////////////////////////////////////////
  1074. int iSvrReponse = -1;
  1075. char szRTXBuffer[2048] = "";
  1076. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, "QUIT",
  1077.        szRTXBuffer,
  1078.        sizeof(szRTXBuffer) - 1),
  1079. 200)) {
  1080. BSckDetach(pSmtpCh->hBSock, 1);
  1081. if (iSvrReponse > 0) {
  1082. if (pSMTPE != NULL)
  1083. USmtpSetError(pSMTPE, iSvrReponse, szRTXBuffer,
  1084.       pSmtpCh->pszServer);
  1085. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szRTXBuffer);
  1086. }
  1087. SysFree(pSmtpCh->pszServer);
  1088. SysFree(pSmtpCh);
  1089. return (ErrGetErrorCode());
  1090. }
  1091. }
  1092. BSckDetach(pSmtpCh->hBSock, 1);
  1093. SysFree(pSmtpCh->pszServer);
  1094. SysFree(pSmtpCh);
  1095. return (0);
  1096. }
  1097. int USmtpChannelReset(SMTPCH_HANDLE hSmtpCh, SMTPError * pSMTPE)
  1098. {
  1099. SmtpChannel *pSmtpCh = (SmtpChannel *) hSmtpCh;
  1100. ///////////////////////////////////////////////////////////////////////////////
  1101. //  Send RSET and read result
  1102. ///////////////////////////////////////////////////////////////////////////////
  1103. int iSvrReponse = -1;
  1104. char szRTXBuffer[2048] = "";
  1105. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, "RSET",
  1106.        szRTXBuffer,
  1107.        sizeof(szRTXBuffer) - 1), 200)) {
  1108. if (iSvrReponse > 0) {
  1109. if (pSMTPE != NULL)
  1110. USmtpSetError(pSMTPE, iSvrReponse, szRTXBuffer,
  1111.       pSmtpCh->pszServer);
  1112. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szRTXBuffer);
  1113. }
  1114. return (ErrGetErrorCode());
  1115. }
  1116. return (0);
  1117. }
  1118. int USmtpSendMail(SMTPCH_HANDLE hSmtpCh, const char *pszFrom, const char *pszRcpt,
  1119.   FileSection const *pFS, SMTPError * pSMTPE)
  1120. {
  1121. SmtpChannel *pSmtpCh = (SmtpChannel *) hSmtpCh;
  1122. ///////////////////////////////////////////////////////////////////////////////
  1123. //  Check message size ( if the remote server support the SIZE extension )
  1124. ///////////////////////////////////////////////////////////////////////////////
  1125. unsigned long ulMessageSize = 0;
  1126. if (pSmtpCh->ulMaxMsgSize != 0) {
  1127. if (MscGetSectionSize(pFS, &ulMessageSize) < 0)
  1128. return (ErrGetErrorCode());
  1129. if (ulMessageSize >= pSmtpCh->ulMaxMsgSize) {
  1130. if (pSMTPE != NULL)
  1131. USmtpSetError(pSMTPE, SMTP_FATAL_ERROR,
  1132.       ErrGetErrorString(ERR_SMTPSRV_MSG_SIZE),
  1133.       pSmtpCh->pszServer);
  1134. ErrSetErrorCode(ERR_SMTPSRV_MSG_SIZE);
  1135. return (ERR_SMTPSRV_MSG_SIZE);
  1136. }
  1137. }
  1138. ///////////////////////////////////////////////////////////////////////////////
  1139. //  Send MAIL FROM: and read result
  1140. ///////////////////////////////////////////////////////////////////////////////
  1141. int iSvrReponse = -1;
  1142. char szRTXBuffer[2048] = "";
  1143. if (pSmtpCh->ulFlags & SMTPCH_SUPPORT_SIZE) {
  1144. if ((ulMessageSize == 0) && (MscGetSectionSize(pFS, &ulMessageSize) < 0))
  1145. return (ErrGetErrorCode());
  1146. SysSNPrintf(szRTXBuffer, sizeof(szRTXBuffer) - 1, "MAIL FROM:<%s> SIZE=%lu",
  1147.     pszFrom, ulMessageSize);
  1148. } else
  1149. SysSNPrintf(szRTXBuffer, sizeof(szRTXBuffer) - 1, "MAIL FROM:<%s>", pszFrom);
  1150. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, szRTXBuffer,
  1151.        szRTXBuffer,
  1152.        sizeof(szRTXBuffer) - 1), 200)) {
  1153. if (iSvrReponse > 0) {
  1154. if (pSMTPE != NULL)
  1155. USmtpSetError(pSMTPE, iSvrReponse, szRTXBuffer,
  1156.       pSmtpCh->pszServer);
  1157. ErrSetErrorCode(ERR_SMTP_BAD_MAIL_FROM, szRTXBuffer);
  1158. }
  1159. return (ErrGetErrorCode());
  1160. }
  1161. ///////////////////////////////////////////////////////////////////////////////
  1162. //  Send RCPT TO: and read result
  1163. ///////////////////////////////////////////////////////////////////////////////
  1164. SysSNPrintf(szRTXBuffer, sizeof(szRTXBuffer) - 1, "RCPT TO:<%s>", pszRcpt);
  1165. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, szRTXBuffer,
  1166.        szRTXBuffer,
  1167.        sizeof(szRTXBuffer) - 1), 200)) {
  1168. if (iSvrReponse > 0) {
  1169. if (pSMTPE != NULL)
  1170. USmtpSetError(pSMTPE, iSvrReponse, szRTXBuffer,
  1171.       pSmtpCh->pszServer);
  1172. ErrSetErrorCode(ERR_SMTP_BAD_RCPT_TO, szRTXBuffer);
  1173. }
  1174. return (ErrGetErrorCode());
  1175. }
  1176. ///////////////////////////////////////////////////////////////////////////////
  1177. //  Send DATA and read the "ready to receive"
  1178. ///////////////////////////////////////////////////////////////////////////////
  1179. if (!USmtpResponseClass(iSvrReponse = USmtpSendCommand(pSmtpCh->hBSock, "DATA",
  1180.        szRTXBuffer,
  1181.        sizeof(szRTXBuffer) - 1), 300)) {
  1182. if (iSvrReponse > 0) {
  1183. if (pSMTPE != NULL)
  1184. USmtpSetError(pSMTPE, iSvrReponse, szRTXBuffer,
  1185.       pSmtpCh->pszServer);
  1186. ErrSetErrorCode(ERR_SMTP_BAD_DATA, szRTXBuffer);
  1187. }
  1188. return (ErrGetErrorCode());
  1189. }
  1190. ///////////////////////////////////////////////////////////////////////////////
  1191. //  Send file
  1192. ///////////////////////////////////////////////////////////////////////////////
  1193. if (SysSendFile
  1194.     (BSckGetAttachedSocket(pSmtpCh->hBSock), pFS->szFilePath, pFS->ulStartOffset,
  1195.      pFS->ulEndOffset, STD_SMTP_TIMEOUT) < 0)
  1196. return (ErrGetErrorCode());
  1197. ///////////////////////////////////////////////////////////////////////////////
  1198. //  Send END OF DATA and read transfer result
  1199. ///////////////////////////////////////////////////////////////////////////////
  1200. if (BSckSendString(pSmtpCh->hBSock, ".", STD_SMTP_TIMEOUT) <= 0)
  1201. return (ErrGetErrorCode());
  1202. if (!USmtpResponseClass(iSvrReponse = USmtpGetResponse(pSmtpCh->hBSock, szRTXBuffer,
  1203.        sizeof(szRTXBuffer) - 1), 200)) {
  1204. if (iSvrReponse > 0) {
  1205. if (pSMTPE != NULL)
  1206. USmtpSetError(pSMTPE, iSvrReponse, szRTXBuffer,
  1207.       pSmtpCh->pszServer);
  1208. ErrSetErrorCode(ERR_BAD_SERVER_RESPONSE, szRTXBuffer);
  1209. }
  1210. return (ErrGetErrorCode());
  1211. }
  1212. return (0);
  1213. }
  1214. int USmtpSendMail(const char *pszServer, const char *pszDomain,
  1215.   const char *pszFrom, const char *pszRcpt, FileSection const *pFS,
  1216.   SMTPError * pSMTPE)
  1217. {
  1218. ///////////////////////////////////////////////////////////////////////////////
  1219. //  Set server host name inside the SMTP error structure
  1220. ///////////////////////////////////////////////////////////////////////////////
  1221. if (pSMTPE != NULL)
  1222. USmtpSetErrorServer(pSMTPE, pszServer);
  1223. ///////////////////////////////////////////////////////////////////////////////
  1224. //  Open STMP channel and try to send the message
  1225. ///////////////////////////////////////////////////////////////////////////////
  1226. SMTPCH_HANDLE hSmtpCh = USmtpCreateChannel(pszServer, pszDomain, pSMTPE);
  1227. if (hSmtpCh == INVALID_SMTPCH_HANDLE)
  1228. return (ErrGetErrorCode());
  1229. int iResultCode = USmtpSendMail(hSmtpCh, pszFrom, pszRcpt, pFS, pSMTPE);
  1230. USmtpCloseChannel(hSmtpCh, 0, pSMTPE);
  1231. return (iResultCode);
  1232. }
  1233. char *USmtpBuildRcptPath(char const *const *ppszRcptTo, SVRCFG_HANDLE hSvrConfig)
  1234. {
  1235. int iRcptCount = StrStringsCount(ppszRcptTo);
  1236. char szDestDomain[MAX_HOST_NAME] = "";
  1237. if (USmtpSplitEmailAddr(ppszRcptTo[0], NULL, szDestDomain) < 0)
  1238. return (NULL);
  1239. ///////////////////////////////////////////////////////////////////////////////
  1240. //  Try to get routing path, if not found simply return an address concat
  1241. //  of "ppszRcptTo"
  1242. ///////////////////////////////////////////////////////////////////////////////
  1243. char szSpecMXHost[1024] = "";
  1244. if (USmtpGetGateway(hSvrConfig, szDestDomain, szSpecMXHost) < 0)
  1245. return (USmlAddrConcat(ppszRcptTo));
  1246. char *pszSendRcpt = USmlAddrConcat(ppszRcptTo);
  1247. if (pszSendRcpt == NULL)
  1248. return (NULL);
  1249. char *pszRcptPath = (char *) SysAlloc(strlen(pszSendRcpt) + strlen(szSpecMXHost) + 2);
  1250. if (iRcptCount == 1)
  1251. sprintf(pszRcptPath, "%s:%s", szSpecMXHost, pszSendRcpt);
  1252. else
  1253. sprintf(pszRcptPath, "%s,%s", szSpecMXHost, pszSendRcpt);
  1254. SysFree(pszSendRcpt);
  1255. return (pszRcptPath);
  1256. }
  1257. char **USmtpGetMailExchangers(SVRCFG_HANDLE hSvrConfig, const char *pszDomain)
  1258. {
  1259. ///////////////////////////////////////////////////////////////////////////////
  1260. //  Try to get default gateways
  1261. ///////////////////////////////////////////////////////////////////////////////
  1262. char *pszDefaultGws = SvrGetConfigVar(hSvrConfig, "DefaultSMTPGateways");
  1263. if (pszDefaultGws == NULL) {
  1264. ErrSetErrorCode(ERR_NO_PREDEFINED_MX);
  1265. return (NULL);
  1266. }
  1267. char **ppszMXGWs = StrTokenize(pszDefaultGws, ",; trn");
  1268. SysFree(pszDefaultGws);
  1269. return (ppszMXGWs);
  1270. }
  1271. static int USmtpGetDomainMX(SVRCFG_HANDLE hSvrConfig, const char *pszDomain, char *&pszMXDomains)
  1272. {
  1273. ///////////////////////////////////////////////////////////////////////////////
  1274. //  Exist a configured list of smart DNS hosts ?
  1275. ///////////////////////////////////////////////////////////////////////////////
  1276. char *pszSmartDNS = SvrGetConfigVar(hSvrConfig, "SmartDNSHost");
  1277. int iQueryResult = CDNS_GetDomainMX(pszDomain, pszMXDomains, pszSmartDNS);
  1278. if (pszSmartDNS != NULL)
  1279. SysFree(pszSmartDNS);
  1280. return (iQueryResult);
  1281. }
  1282. int USmtpCheckMailDomain(SVRCFG_HANDLE hSvrConfig, char const *pszDomain)
  1283. {
  1284. char *pszMXDomains = NULL;
  1285. NET_ADDRESS NetAddr;
  1286. if (USmtpGetDomainMX(hSvrConfig, pszDomain, pszMXDomains) < 0) {
  1287. if (SysGetHostByName(pszDomain, NetAddr) < 0) {
  1288. ErrSetErrorCode(ERR_INVALID_MAIL_DOMAIN);
  1289. return (ERR_INVALID_MAIL_DOMAIN);
  1290. }
  1291. } else
  1292. SysFree(pszMXDomains);
  1293. return (0);
  1294. }
  1295. MXS_HANDLE USmtpGetMXFirst(SVRCFG_HANDLE hSvrConfig, const char *pszDomain, char *pszMXHost)
  1296. {
  1297. ///////////////////////////////////////////////////////////////////////////////
  1298. //  Make a DNS query for domain MXs
  1299. ///////////////////////////////////////////////////////////////////////////////
  1300. char *pszMXHosts = NULL;
  1301. if (USmtpGetDomainMX(hSvrConfig, pszDomain, pszMXHosts) < 0)
  1302. return (INVALID_MXS_HANDLE);
  1303. ///////////////////////////////////////////////////////////////////////////////
  1304. //  MX records structure allocation
  1305. ///////////////////////////////////////////////////////////////////////////////
  1306. SmtpMXRecords *pMXR = (SmtpMXRecords *) SysAlloc(sizeof(SmtpMXRecords));
  1307. if (pMXR == NULL) {
  1308. SysFree(pszMXHosts);
  1309. return (INVALID_MXS_HANDLE);
  1310. }
  1311. pMXR->iNumMXRecords = 0;
  1312. pMXR->iCurrMxCost = -1;
  1313. ///////////////////////////////////////////////////////////////////////////////
  1314. //  MX hosts string format = c:h[,c:h]  where "c = cost" and "h = hosts"
  1315. ///////////////////////////////////////////////////////////////////////////////
  1316. int iMXCost = INT_MAX;
  1317. int iCurrIndex = -1;
  1318. char *pszToken = NULL;
  1319. char *pszSavePtr = NULL;
  1320. pszToken = SysStrTok(pszMXHosts, ":, trn", &pszSavePtr);
  1321. while ((pMXR->iNumMXRecords < MAX_MX_RECORDS) && (pszToken != NULL)) {
  1322. ///////////////////////////////////////////////////////////////////////////////
  1323. //  Get MX cost
  1324. ///////////////////////////////////////////////////////////////////////////////
  1325. int iCost = atoi(pszToken);
  1326. if ((pszToken = SysStrTok(NULL, ":, trn", &pszSavePtr)) == NULL) {
  1327. for (--pMXR->iNumMXRecords; pMXR->iNumMXRecords >= 0;
  1328.      pMXR->iNumMXRecords--)
  1329. SysFree(pMXR->pszMXName[pMXR->iNumMXRecords]);
  1330. SysFree(pMXR);
  1331. SysFree(pszMXHosts);
  1332. ErrSetErrorCode(ERR_INVALID_MXRECS_STRING);
  1333. return (INVALID_MXS_HANDLE);
  1334. }
  1335. pMXR->iMXCost[pMXR->iNumMXRecords] = iCost;
  1336. pMXR->pszMXName[pMXR->iNumMXRecords] = SysStrDup(pszToken);
  1337. if ((iCost < iMXCost) && (iCost >= pMXR->iCurrMxCost)) {
  1338. iMXCost = iCost;
  1339. strcpy(pszMXHost, pMXR->pszMXName[pMXR->iNumMXRecords]);
  1340. iCurrIndex = pMXR->iNumMXRecords;
  1341. }
  1342. ++pMXR->iNumMXRecords;
  1343. pszToken = SysStrTok(NULL, ":, trn", &pszSavePtr);
  1344. }
  1345. SysFree(pszMXHosts);
  1346. if (iMXCost == INT_MAX) {
  1347. for (--pMXR->iNumMXRecords; pMXR->iNumMXRecords >= 0; pMXR->iNumMXRecords--)
  1348. SysFree(pMXR->pszMXName[pMXR->iNumMXRecords]);
  1349. SysFree(pMXR);
  1350. ErrSetErrorCode(ERR_INVALID_MXRECS_STRING);
  1351. return (INVALID_MXS_HANDLE);
  1352. }
  1353. pMXR->iCurrMxCost = iMXCost;
  1354. pMXR->iMXCost[iCurrIndex] = iMXCost - 1;
  1355. return ((MXS_HANDLE) pMXR);
  1356. }
  1357. int USmtpGetMXNext(MXS_HANDLE hMXSHandle, char *pszMXHost)
  1358. {
  1359. SmtpMXRecords *pMXR = (SmtpMXRecords *) hMXSHandle;
  1360. int iMXCost = INT_MAX;
  1361. int iCurrIndex = -1;
  1362. for (int ii = 0; ii < pMXR->iNumMXRecords; ii++) {
  1363. if ((pMXR->iMXCost[ii] < iMXCost) && (pMXR->iMXCost[ii] >= pMXR->iCurrMxCost)) {
  1364. iMXCost = pMXR->iMXCost[ii];
  1365. strcpy(pszMXHost, pMXR->pszMXName[ii]);
  1366. iCurrIndex = ii;
  1367. }
  1368. }
  1369. if (iMXCost == INT_MAX) {
  1370. ErrSetErrorCode(ERR_NO_MORE_MXRECORDS);
  1371. return (ERR_NO_MORE_MXRECORDS);
  1372. }
  1373. pMXR->iCurrMxCost = iMXCost;
  1374. pMXR->iMXCost[iCurrIndex] = iMXCost - 1;
  1375. return (0);
  1376. }
  1377. void USmtpMXSClose(MXS_HANDLE hMXSHandle)
  1378. {
  1379. SmtpMXRecords *pMXR = (SmtpMXRecords *) hMXSHandle;
  1380. for (--pMXR->iNumMXRecords; pMXR->iNumMXRecords >= 0; pMXR->iNumMXRecords--)
  1381. SysFree(pMXR->pszMXName[pMXR->iNumMXRecords]);
  1382. SysFree(pMXR);
  1383. }
  1384. bool USmtpDnsMapsContained(SYS_INET_ADDR const &PeerInfo, char const *pszMapsServer)
  1385. {
  1386. SYS_UINT8 AddrBytes[sizeof(NET_ADDRESS)];
  1387. SysGetAddrAddress(PeerInfo, *((NET_ADDRESS *) AddrBytes));
  1388. char szMapsQuery[256] = "";
  1389. sprintf(szMapsQuery, "%u.%u.%u.%u.%s",
  1390. (unsigned int) AddrBytes[3], (unsigned int) AddrBytes[2],
  1391. (unsigned int) AddrBytes[1], (unsigned int) AddrBytes[0], pszMapsServer);
  1392. NET_ADDRESS NetAddr;
  1393. return ((SysGetHostByName(szMapsQuery, NetAddr) < 0) ? false : true);
  1394. }
  1395. static char *USmtpGetSpammersFilePath(char *pszSpamFilePath, int iMaxPath)
  1396. {
  1397. CfgGetRootPath(pszSpamFilePath, iMaxPath);
  1398. StrNCat(pszSpamFilePath, SMTP_SPAMMERS_FILE, iMaxPath);
  1399. return (pszSpamFilePath);
  1400. }
  1401. int USmtpSpammerCheck(const SYS_INET_ADDR & PeerInfo, char *&pszInfo)
  1402. {
  1403. pszInfo = NULL;
  1404. char szSpammersFilePath[SYS_MAX_PATH] = "";
  1405. USmtpGetSpammersFilePath(szSpammersFilePath, sizeof(szSpammersFilePath));
  1406. char szResLock[SYS_MAX_PATH] = "";
  1407. RLCK_HANDLE hResLock = RLckLockSH(CfgGetBasedPath(szSpammersFilePath, szResLock,
  1408.   sizeof(szResLock)));
  1409. if (hResLock == INVALID_RLCK_HANDLE)
  1410. return (ErrGetErrorCode());
  1411. FILE *pSpammersFile = fopen(szSpammersFilePath, "rt");
  1412. if (pSpammersFile == NULL) {
  1413. RLckUnlockSH(hResLock);
  1414. ErrSetErrorCode(ERR_FILE_OPEN);
  1415. return (ERR_FILE_OPEN);
  1416. }
  1417. NET_ADDRESS TestAddr;
  1418. SysGetAddrAddress(PeerInfo, TestAddr);
  1419. char szSpammerLine[SPAMMERS_LINE_MAX] = "";
  1420. while (MscGetConfigLine(szSpammerLine, sizeof(szSpammerLine) - 1, pSpammersFile) != NULL) {
  1421. char **ppszStrings = StrGetTabLineStrings(szSpammerLine);
  1422. if (ppszStrings == NULL)
  1423. continue;
  1424. int iFieldsCount = StrStringsCount(ppszStrings);
  1425. if (iFieldsCount < 1) {
  1426. StrFreeStrings(ppszStrings);
  1427. continue;
  1428. }
  1429. int iAddrFields = 1;
  1430. if ((iFieldsCount > 1) && isdigit(ppszStrings[1][0]))
  1431. iAddrFields = 2;
  1432. AddressFilter AF;
  1433. if ((MscLoadAddressFilter(ppszStrings, iAddrFields, AF) == 0) &&
  1434.     MscAddressMatch(AF, TestAddr)) {
  1435. if (iFieldsCount > iAddrFields)
  1436. pszInfo = SysStrDup(ppszStrings[iAddrFields]);
  1437. StrFreeStrings(ppszStrings);
  1438. fclose(pSpammersFile);
  1439. RLckUnlockSH(hResLock);
  1440. char szIP[128] = "???.???.???.???";
  1441. ErrSetErrorCode(ERR_SPAMMER_IP, SysInetNToA(PeerInfo, szIP));
  1442. return (ERR_SPAMMER_IP);
  1443. }
  1444. StrFreeStrings(ppszStrings);
  1445. }
  1446. fclose(pSpammersFile);
  1447. RLckUnlockSH(hResLock);
  1448. return (0);
  1449. }
  1450. static char *USmtpGetSpamAddrFilePath(char *pszSpamFilePath, int iMaxPath)
  1451. {
  1452. CfgGetRootPath(pszSpamFilePath, iMaxPath);
  1453. StrNCat(pszSpamFilePath, SMTP_SPAM_ADDRESS_FILE, iMaxPath);
  1454. return (pszSpamFilePath);
  1455. }
  1456. int USmtpSpamAddressCheck(char const *pszAddress)
  1457. {
  1458. char szSpammersFilePath[SYS_MAX_PATH] = "";
  1459. USmtpGetSpamAddrFilePath(szSpammersFilePath, sizeof(szSpammersFilePath));
  1460. char szResLock[SYS_MAX_PATH] = "";
  1461. RLCK_HANDLE hResLock = RLckLockSH(CfgGetBasedPath(szSpammersFilePath, szResLock,
  1462.   sizeof(szResLock)));
  1463. if (hResLock == INVALID_RLCK_HANDLE)
  1464. return (ErrGetErrorCode());
  1465. FILE *pSpammersFile = fopen(szSpammersFilePath, "rt");
  1466. if (pSpammersFile == NULL) {
  1467. RLckUnlockSH(hResLock);
  1468. return (0);
  1469. }
  1470. char szSpammerLine[SPAM_ADDRESS_LINE_MAX] = "";
  1471. while (MscGetConfigLine(szSpammerLine, sizeof(szSpammerLine) - 1, pSpammersFile) != NULL) {
  1472. char **ppszStrings = StrGetTabLineStrings(szSpammerLine);
  1473. if (ppszStrings == NULL)
  1474. continue;
  1475. int iFieldsCount = StrStringsCount(ppszStrings);
  1476. if ((iFieldsCount > 0) && StrIWildMatch(pszAddress, ppszStrings[0])) {
  1477. StrFreeStrings(ppszStrings);
  1478. fclose(pSpammersFile);
  1479. RLckUnlockSH(hResLock);
  1480. ErrSetErrorCode(ERR_SPAM_ADDRESS, pszAddress);
  1481. return (ERR_SPAM_ADDRESS);
  1482. }
  1483. StrFreeStrings(ppszStrings);
  1484. }
  1485. fclose(pSpammersFile);
  1486. RLckUnlockSH(hResLock);
  1487. return (0);
  1488. }
  1489. int USmtpAddMessageInfo(FILE * pMsgFile, char const *pszClientDomain,
  1490. SYS_INET_ADDR const &PeerInfo, char const *pszServerDomain,
  1491. SYS_INET_ADDR const &SockInfo, char const *pszSmtpServerLogo)
  1492. {
  1493. char szTime[256] = "";
  1494. MscGetTimeStr(szTime, sizeof(szTime) - 1);
  1495. char szPeerIP[128] = "";
  1496. char szSockIP[128] = "";
  1497. SysInetNToA(PeerInfo, szPeerIP);
  1498. SysInetNToA(SockInfo, szSockIP);
  1499. ///////////////////////////////////////////////////////////////////////////////
  1500. //  Write message info. If You change the order ( or add new fields ) You must
  1501. //  arrange fields into the SmtpMsgInfo union defined in SMTPUtils.h
  1502. ///////////////////////////////////////////////////////////////////////////////
  1503. fprintf(pMsgFile, "%s;[%s]:%d;%s;[%s]:%d;%s;%srn",
  1504. pszClientDomain, szPeerIP, SysGetAddrPort(PeerInfo),
  1505. pszServerDomain, szSockIP, SysGetAddrPort(SockInfo), szTime, pszSmtpServerLogo);
  1506. return (0);
  1507. }
  1508. int USmtpWriteInfoLine(FILE * pSpoolFile, char const *pszClientAddr,
  1509.        char const *pszServerAddr, char const *pszTime)
  1510. {
  1511. fprintf(pSpoolFile, "%s;%s;%srn", pszClientAddr, pszServerAddr, pszTime);
  1512. return (0);
  1513. }
  1514. char *USmtpGetReceived(int iType, char const *pszAuth, char const *const *ppszMsgInfo,
  1515.        char const *pszMailFrom, char const *pszRcptTo, char const *pszMessageID)
  1516. {
  1517. char szFrom[MAX_SMTP_ADDRESS] = "";
  1518. char szRcpt[MAX_SMTP_ADDRESS] = "";
  1519. if ((USmlParseAddress(pszMailFrom, NULL, 0, szFrom, sizeof(szFrom) - 1) < 0) ||
  1520.     (USmlParseAddress(pszRcptTo, NULL, 0, szRcpt, sizeof(szRcpt) - 1) < 0))
  1521. return (NULL);
  1522. ///////////////////////////////////////////////////////////////////////////////
  1523. //  Parse special types to hide client info
  1524. ///////////////////////////////////////////////////////////////////////////////
  1525. bool bHideClient = false;
  1526. if (iType == RECEIVED_TYPE_AUTHSTD) {
  1527. bHideClient = (pszAuth != NULL) && !IsEmptyString(pszAuth);
  1528. iType = RECEIVED_TYPE_STD;
  1529. } else if (iType == RECEIVED_TYPE_AUTHVERBOSE) {
  1530. bHideClient = (pszAuth != NULL) && !IsEmptyString(pszAuth);
  1531. iType = RECEIVED_TYPE_VERBOSE;
  1532. }
  1533. ///////////////////////////////////////////////////////////////////////////////
  1534. //  Return "Received:" tag
  1535. ///////////////////////////////////////////////////////////////////////////////
  1536. char *pszReceived = NULL;
  1537. switch (iType) {
  1538. case (RECEIVED_TYPE_STRICT):
  1539. pszReceived = StrSprint("Received: from %srn"
  1540. "tby %s with %srn"
  1541. "tid <%s> for <%s> from <%s>;rn"
  1542. "t%srn", ppszMsgInfo[smsgiClientDomain],
  1543. ppszMsgInfo[smsgiServerDomain],
  1544. ppszMsgInfo[smsgiSeverName], pszMessageID, szRcpt, szFrom,
  1545. ppszMsgInfo[smsgiTime]);
  1546. break;
  1547. case (RECEIVED_TYPE_VERBOSE):
  1548. if (!bHideClient)
  1549. pszReceived = StrSprint("Received: from %s (%s)rn"
  1550. "tby %s (%s) with %srn"
  1551. "tid <%s> for <%s> from <%s>;rn"
  1552. "t%srn", ppszMsgInfo[smsgiClientDomain],
  1553. ppszMsgInfo[smsgiClientAddr],
  1554. ppszMsgInfo[smsgiServerDomain],
  1555. ppszMsgInfo[smsgiServerAddr],
  1556. ppszMsgInfo[smsgiSeverName], pszMessageID, szRcpt,
  1557. szFrom, ppszMsgInfo[smsgiTime]);
  1558. else
  1559. pszReceived = StrSprint("Received: from %srn"
  1560. "tby %s (%s) with %srn"
  1561. "tid <%s> for <%s> from <%s>;rn"
  1562. "t%srn", ppszMsgInfo[smsgiClientDomain],
  1563. ppszMsgInfo[smsgiServerDomain],
  1564. ppszMsgInfo[smsgiServerAddr],
  1565. ppszMsgInfo[smsgiSeverName], pszMessageID, szRcpt,
  1566. szFrom, ppszMsgInfo[smsgiTime]);
  1567. break;
  1568. case (RECEIVED_TYPE_STD):
  1569. default:
  1570. if (!bHideClient)
  1571. pszReceived = StrSprint("Received: from %s (%s)rn"
  1572. "tby %s with %srn"
  1573. "tid <%s> for <%s> from <%s>;rn"
  1574. "t%srn", ppszMsgInfo[smsgiClientDomain],
  1575. ppszMsgInfo[smsgiClientAddr],
  1576. ppszMsgInfo[smsgiServerDomain],
  1577. ppszMsgInfo[smsgiSeverName], pszMessageID, szRcpt,
  1578. szFrom, ppszMsgInfo[smsgiTime]);
  1579. else
  1580. pszReceived = StrSprint("Received: from %srn"
  1581. "tby %s with %srn"
  1582. "tid <%s> for <%s> from <%s>;rn"
  1583. "t%srn", ppszMsgInfo[smsgiClientDomain],
  1584. ppszMsgInfo[smsgiServerDomain],
  1585. ppszMsgInfo[smsgiSeverName], pszMessageID, szRcpt,
  1586. szFrom, ppszMsgInfo[smsgiTime]);
  1587. break;
  1588. }
  1589. return (pszReceived);
  1590. }