Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

460 lines
15 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. iissmtp.cxx
  5. Abstract:
  6. This module defines the SMTP_IIS_SERVICE class
  7. Author:
  8. Johnson Apacible (JohnsonA) June-04-1996
  9. Rohan Phillips (Rohanp) Feb-04-1997 - modified for smtp
  10. --*/
  11. #define INCL_INETSRV_INCS
  12. #include "smtpinc.h"
  13. #include <smtpinet.h>
  14. #include "aqstore.hxx"
  15. //
  16. // External reference to SEO helpers
  17. //
  18. extern HRESULT RegisterPlatSEOInstance(DWORD dwInstanceID);
  19. BOOL
  20. SMTP_IIS_SERVICE::AddInstanceInfo(
  21. IN DWORD dwInstance,
  22. IN BOOL fMigrateRoots
  23. )
  24. {
  25. HRESULT hr;
  26. PSMTP_SERVER_INSTANCE pInstance;
  27. MB mb( (IMDCOM*) QueryMDObject() );
  28. TraceFunctEnterEx((LPARAM)this, "SMTP_IIS_SERVICE::AddInstanceInfo");
  29. //
  30. // Register the instance for server events
  31. //
  32. DebugTrace((LPARAM)this, "Registering SEO for instance %u", dwInstance);
  33. hr = RegisterPlatSEOInstance(dwInstance);
  34. if (FAILED(hr))
  35. {
  36. char szInst[10];
  37. ErrorTrace((LPARAM)this, "Instance %d: RegisterSEOInstance returned %08x",
  38. dwInstance, hr);
  39. _itoa((int)dwInstance, szInst, 10);
  40. SmtpLogEventEx(SEO_REGISTER_INSTANCE_FAILED,
  41. szInst,
  42. hr);
  43. }
  44. //
  45. // Create the new instance
  46. //
  47. pInstance = new SMTP_SERVER_INSTANCE(
  48. this,
  49. dwInstance,
  50. IPPORT_SMTP,
  51. QueryRegParamKey(),
  52. SMTP_ANONYMOUS_SECRET_W,
  53. SMTP_ROOT_SECRET_W,
  54. fMigrateRoots
  55. );
  56. if(pInstance == NULL)
  57. {
  58. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  59. TraceFunctLeaveEx((LPARAM)this);
  60. return FALSE;
  61. }
  62. if (m_fCreatingInstance)
  63. {
  64. //We just received the notification for the creation of the metabase
  65. //object for a VS... none of the config information is there. We do
  66. //not want to attempt starting, becuase we will log that we cannot
  67. //find out config info in the event log!
  68. DebugTrace((LPARAM)this,"Instnace not started on metabase creation");
  69. SetLastError( ERROR_SERVICE_DISABLED );
  70. TraceFunctLeaveEx((LPARAM)this);
  71. return FALSE ;
  72. }
  73. return AddInstanceInfoHelper( pInstance );
  74. } // SMTP_IIS_SERVICE::AddInstanceInfo
  75. DWORD
  76. SMTP_IIS_SERVICE::DisconnectUsersByInstance(
  77. IN IIS_SERVER_INSTANCE * pInstance
  78. )
  79. /*++
  80. Virtual callback invoked by IIS_SERVER_INSTANCE::StopInstance() to
  81. disconnect all users associated with the given instance.
  82. Arguments:
  83. pInstance - All users associated with this instance will be
  84. forcibly disconnected.
  85. --*/
  86. {
  87. ((SMTP_SERVER_INSTANCE *)pInstance)->DisconnectAllConnections();
  88. return NO_ERROR;
  89. } // SMTP_IIS_SERVICE::DisconnectUsersByInstance
  90. DWORD
  91. SMTP_IIS_SERVICE::GetServiceConfigInfoSize(
  92. IN DWORD dwLevel
  93. )
  94. {
  95. switch (dwLevel) {
  96. case 1:
  97. return sizeof(SMTP_CONFIG_INFO);
  98. }
  99. return 0;
  100. } // SMTP_IIS_SERVICE::GetServerConfigInfoSize
  101. VOID
  102. SMTP_IIS_SERVICE::StartHintFunction()
  103. {
  104. if (QueryCurrentServiceState() == SERVICE_START_PENDING )
  105. {
  106. UpdateServiceStatus(SERVICE_START_PENDING, NO_ERROR, m_dwStartHint,SERVICE_START_WAIT_HINT);
  107. m_dwStartHint++;
  108. }
  109. }
  110. SMTP_IIS_SERVICE::SMTP_IIS_SERVICE(
  111. IN LPCSTR pszServiceName,
  112. IN LPCSTR pszModuleName,
  113. IN LPCSTR pszRegParamKey,
  114. IN DWORD dwServiceId,
  115. IN ULONGLONG SvcLocId,
  116. IN BOOL MultipleInstanceSupport,
  117. IN DWORD cbAcceptExRecvBuffer,
  118. IN ATQ_CONNECT_CALLBACK pfnConnect,
  119. IN ATQ_COMPLETION pfnConnectEx,
  120. IN ATQ_COMPLETION pfnIoCompletion
  121. ) : IIS_SERVICE( pszServiceName,
  122. pszModuleName,
  123. pszRegParamKey,
  124. dwServiceId,
  125. SvcLocId,
  126. MultipleInstanceSupport,
  127. cbAcceptExRecvBuffer,
  128. pfnConnect,
  129. pfnConnectEx,
  130. pfnIoCompletion
  131. )
  132. {
  133. MB mb( (IMDCOM*) QueryMDObject() );
  134. DWORD MaxPoolThreadValue = 0;
  135. TraceFunctEnterEx((LPARAM)this, "SMTP_IIS_SERVICE::SMTP_IIS_SERVICE");
  136. m_OldMaxPoolThreadValue = 0;
  137. m_cMaxSystemRoutingThreads = 0;
  138. m_cCurrentSystemRoutingThreads = 0;
  139. m_fHaveResetPrincipalNames = FALSE;
  140. //
  141. // configure the number of SMTP routing threads and IIS pool threads.
  142. //
  143. m_dwStartHint = 2;
  144. m_OldMaxPoolThreadValue = 0;
  145. MaxPoolThreadValue = (DWORD)AtqGetInfo(AtqMaxPoolThreads);
  146. if(MaxPoolThreadValue < 15)
  147. m_OldMaxPoolThreadValue = (DWORD)AtqSetInfo(AtqMaxPoolThreads, 15);
  148. m_fCreatingInstance = FALSE;
  149. InitializeListHead(&m_InstanceInfoList);
  150. TraceFunctLeaveEx((LPARAM)this);
  151. } // SMTP_IIS_SERVICE::SMTP_IIS_SERVICE
  152. BOOL
  153. SMTP_IIS_SERVICE::AggregateStatistics(
  154. IN PCHAR pDestination,
  155. IN PCHAR pSource
  156. )
  157. {
  158. LPSMTP_STATISTICS_0 pStatDest = (LPSMTP_STATISTICS_0) pDestination;
  159. LPSMTP_STATISTICS_0 pStatSrc = (LPSMTP_STATISTICS_0) pSource;
  160. if ((NULL == pDestination) || (NULL == pSource))
  161. {
  162. return FALSE;
  163. }
  164. pStatDest->BytesSentTotal += pStatSrc->BytesSentTotal;
  165. pStatDest->BytesRcvdTotal += pStatSrc->BytesRcvdTotal;
  166. pStatDest->BytesSentMsg += pStatSrc->BytesSentMsg;
  167. pStatDest->BytesRcvdMsg += pStatSrc->BytesRcvdMsg;
  168. pStatDest->NumMsgRecvd += pStatSrc->NumMsgRecvd;
  169. pStatDest->NumRcptsRecvd += pStatSrc->NumRcptsRecvd;
  170. pStatDest->NumRcptsRecvdLocal += pStatSrc->NumRcptsRecvdLocal;
  171. pStatDest->NumRcptsRecvdRemote += pStatSrc->NumRcptsRecvdRemote;
  172. pStatDest->MsgsRefusedDueToSize += pStatSrc->MsgsRefusedDueToSize;
  173. pStatDest->MsgsRefusedDueToNoCAddrObjects += pStatSrc->MsgsRefusedDueToNoCAddrObjects;
  174. pStatDest->MsgsRefusedDueToNoMailObjects += pStatSrc->MsgsRefusedDueToNoMailObjects;
  175. pStatDest->NumMsgsDelivered += pStatSrc->NumMsgsDelivered;
  176. pStatDest->NumDeliveryRetries += pStatSrc->NumDeliveryRetries;
  177. pStatDest->NumMsgsForwarded += pStatSrc->NumMsgsForwarded;
  178. pStatDest->NumNDRGenerated += pStatSrc->NumNDRGenerated;
  179. pStatDest->LocalQueueLength += pStatSrc->LocalQueueLength;
  180. pStatDest->RetryQueueLength += pStatSrc->RetryQueueLength;
  181. pStatDest->NumMailFileHandles += pStatSrc->NumMailFileHandles;
  182. pStatDest->NumQueueFileHandles += pStatSrc->NumQueueFileHandles;
  183. pStatDest->CatQueueLength += pStatSrc->CatQueueLength;
  184. pStatDest->NumMsgsSent += pStatSrc->NumMsgsSent;
  185. pStatDest->NumRcptsSent += pStatSrc->NumRcptsSent;
  186. pStatDest->NumSendRetries += pStatSrc->NumSendRetries;
  187. pStatDest->RemoteQueueLength += pStatSrc->RemoteQueueLength;
  188. pStatDest->NumDnsQueries += pStatSrc->NumDnsQueries;
  189. pStatDest->RemoteRetryQueueLength += pStatSrc->RemoteRetryQueueLength;
  190. pStatDest->NumConnInOpen += pStatSrc->NumConnInOpen;
  191. pStatDest->NumConnInClose += pStatSrc->NumConnInClose;
  192. pStatDest->NumConnOutOpen += pStatSrc->NumConnOutOpen;
  193. pStatDest->NumConnOutClose += pStatSrc->NumConnOutClose;
  194. pStatDest->NumConnOutRefused += pStatSrc->NumConnOutRefused;
  195. pStatDest->NumProtocolErrs += pStatSrc->NumProtocolErrs;
  196. pStatDest->DirectoryDrops += pStatSrc->DirectoryDrops;
  197. pStatDest->RoutingTableLookups += pStatSrc->RoutingTableLookups;
  198. pStatDest->ETRNMessages += pStatSrc->ETRNMessages;
  199. pStatDest->TimeOfLastClear += pStatSrc->TimeOfLastClear;
  200. pStatDest->MsgsBadmailNoRecipients += pStatSrc->MsgsBadmailNoRecipients;
  201. pStatDest->MsgsBadmailHopCountExceeded += pStatSrc->MsgsBadmailHopCountExceeded;
  202. pStatDest->MsgsBadmailFailureGeneral += pStatSrc->MsgsBadmailFailureGeneral;
  203. pStatDest->MsgsBadmailBadPickupFile += pStatSrc->MsgsBadmailBadPickupFile;
  204. pStatDest->MsgsBadmailEvent += pStatSrc->MsgsBadmailEvent;
  205. pStatDest->MsgsBadmailNdrOfDsn += pStatSrc->MsgsBadmailNdrOfDsn;
  206. pStatDest->MsgsPendingRouting += pStatSrc->MsgsPendingRouting;
  207. pStatDest->MsgsPendingUnreachableLink += pStatSrc->MsgsPendingUnreachableLink;
  208. pStatDest->SubmittedMessages += pStatSrc->SubmittedMessages;
  209. pStatDest->DSNFailures += pStatSrc->DSNFailures;
  210. pStatDest->MsgsInLocalDelivery += pStatSrc->MsgsInLocalDelivery;
  211. return TRUE;
  212. }
  213. SMTP_IIS_SERVICE::~SMTP_IIS_SERVICE()
  214. {
  215. if(m_OldMaxPoolThreadValue != 0)
  216. AtqSetInfo(AtqMaxPoolThreads, m_OldMaxPoolThreadValue);
  217. }
  218. VOID
  219. SMTP_IIS_SERVICE::MDChangeNotify(
  220. MD_CHANGE_OBJECT * pcoChangeList
  221. )
  222. /*++
  223. This method handles the metabase change notification for this service
  224. Arguments:
  225. pcoChangeList - path and id that has changed
  226. --*/
  227. {
  228. DWORD i;
  229. BOOL fSslModified = FALSE;
  230. LPSTR szIdString = NULL;
  231. BOOL fSetCreatingInstance = FALSE;
  232. AcquireServiceLock();
  233. if (!m_fCreatingInstance)
  234. {
  235. //Check if this is a creation event.... if we are just creating the
  236. //class key in smtpsvc/<instance>, then this is the notify we get
  237. //when admin is creating an instance. We should bail early so we
  238. //do not attempt to create an instance and log bogus errors in
  239. //the event log. If m_fCreatingInstance is set to TRUE... we will
  240. //not try to start the instance (by calling AddInstanceInfoHelper)
  241. //Parse the string and see if the last thing is the instance ID.. .we
  242. //expect it to be in the form of:
  243. // /LM/{service_name}/{instance_id}/
  244. if (pcoChangeList->pszMDPath)
  245. {
  246. szIdString = (LPSTR)pcoChangeList->pszMDPath +
  247. sizeof(SMTP_MD_ROOT_PATH) - 2*sizeof(CHAR);
  248. }
  249. //We are now at the '/' before the instance id
  250. if (szIdString && (szIdString[0] == '/') && (szIdString[1] != '\0'))
  251. {
  252. //We have a possible winner... check for <n>/\0
  253. do {szIdString++;} while (*szIdString && isdigit((UCHAR)*szIdString));
  254. //If the last 2 characters are '/' and '\0'... we need to look further
  255. if ((szIdString[0] == '/') && (szIdString[1] == '\0'))
  256. {
  257. //Since all of this work is to avoid trying to start when
  258. //admin creates a new virtual server, we would be well advised
  259. //to only bail early in the exact case of admin adding a virtual
  260. //server instance. They always create the key type first, so
  261. //we will check for it
  262. if ((MD_CHANGE_TYPE_ADD_OBJECT & pcoChangeList->dwMDChangeType) &&
  263. (1 == pcoChangeList->dwMDNumDataIDs) &&
  264. (MD_KEY_TYPE == pcoChangeList->pdwMDDataIDs[0]))
  265. {
  266. //This is the notify that causes IIS to try and make us start
  267. //before we have any config information. If we call,
  268. //IIS_SERVICE::MDChangeNotify it will turn around and start
  269. //our instance. .
  270. m_fCreatingInstance = TRUE;
  271. //This thread needs to unset it. While the instance is created
  272. //we will get other notifies (on this thread) when IIS sets
  273. //the service state.
  274. fSetCreatingInstance = TRUE;
  275. }
  276. }
  277. }
  278. }
  279. IIS_SERVICE::MDChangeNotify( pcoChangeList );
  280. //The above call is were m_fCreatingInstance is used...reset it if we set it
  281. if (fSetCreatingInstance)
  282. m_fCreatingInstance = FALSE;
  283. for ( i = 0; i < pcoChangeList->dwMDNumDataIDs; i++ )
  284. {
  285. switch ( pcoChangeList->pdwMDDataIDs[i] )
  286. {
  287. case MD_SSL_PUBLIC_KEY:
  288. case MD_SSL_PRIVATE_KEY:
  289. case MD_SSL_KEY_PASSWORD:
  290. fSslModified = TRUE;
  291. break;
  292. default:
  293. break;
  294. }
  295. }
  296. if ( !fSslModified && g_pSslKeysNotify )
  297. {
  298. if ( strlen( (LPSTR)pcoChangeList->pszMDPath ) >= sizeof("/LM/SMTPSVC/SSLKeys" )-1 &&
  299. !_memicmp( pcoChangeList->pszMDPath,
  300. "/LM/SMTPSVC/SSLKeys",
  301. sizeof("/LM/SMTPSVC/SSLKeys" )-1 ) )
  302. {
  303. fSslModified = TRUE;
  304. }
  305. }
  306. if ( fSslModified && g_pSslKeysNotify )
  307. {
  308. (g_pSslKeysNotify)( SIMSSL_NOTIFY_MAPPER_SSLKEYS_CHANGED, this );
  309. }
  310. ReleaseServiceLock();
  311. }
  312. /*++
  313. Name:
  314. APIERR SMTP_IIS_SERVICE::LoadAdvancedQueueingDll()
  315. Description:
  316. This method reads from the metabase to see if an advanced queueing dll
  317. has been set and loads it if so. If no dll is set then the default is
  318. loaded.
  319. Returns:
  320. NO_ERROR on success
  321. Whatever error occurred on failure
  322. --*/
  323. APIERR SMTP_IIS_SERVICE::LoadAdvancedQueueingDll()
  324. {
  325. char szValueName[MAX_PATH + 1];
  326. char szAQDll[MAX_PATH + 1];
  327. STR TempString;
  328. DWORD fRet;
  329. MB mb( (IMDCOM*)g_pInetSvc->QueryMDObject() );
  330. TraceFunctEnterEx((LPARAM)this, "SMTP_IIS_SERVICE::LoadAdvancedQueueingDll()");
  331. lstrcpy(szValueName, g_pInetSvc->QueryMDPath());
  332. if ( !mb.Open( szValueName, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE) )
  333. {
  334. return ERROR_SERVICE_DISABLED;
  335. }
  336. TempString.Reset();
  337. szAQDll[0] = '\0';
  338. if (fRet = mb.GetStr("", MD_AQUEUE_DLL, IIS_MD_UT_FILE, &TempString, METADATA_INHERIT, ""))
  339. {
  340. lstrcpyn(szAQDll, TempString.QueryStr(), MAX_PATH);
  341. DebugTrace((LPARAM)this, "Loading extended advanced queueing DLL %s", szAQDll);
  342. }
  343. if (!fRet || (szAQDll[0] == '\0'))
  344. {
  345. lstrcpyn(szAQDll, AQ_DLL_NAME, MAX_PATH);
  346. DebugTrace((LPARAM)this, "No extended advanced queueing DLL set, loading %s\n", szAQDll);
  347. }
  348. if(!LoadAdvancedQueueing(szAQDll))
  349. {
  350. HRESULT err = GetLastError();
  351. ErrorTrace((LPARAM)this, "LoadAdvancedQueueing failed, %u", err);
  352. SmtpLogEvent(SMTP_EVENT_FAILED_TO_LOAD_AQUEUE, 0, (const CHAR **)NULL, 0);
  353. if(err == NO_ERROR)
  354. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  355. mb.Close();
  356. TraceFunctLeaveEx((LPARAM)this);
  357. return err;
  358. }
  359. mb.Close();
  360. TraceFunctLeaveEx((LPARAM)this);
  361. return NO_ERROR;
  362. }