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.

1584 lines
38 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. util.c
  5. Abstract:
  6. This module provides all the utility functions for the Routing Layer and
  7. the local Print Providor
  8. Author:
  9. Dave Snipp (DaveSn) 15-Mar-1991
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "local.h"
  15. #include <winddiui.h>
  16. #include <winsock2.h>
  17. #include <wininet.h>
  18. LPWSTR *ppszOtherNames = NULL; // Contains szMachineName, DNS name, and all other machine name forms
  19. DWORD cOtherNames = 0; // Number of other names
  20. WCHAR *gszDrvConvert = L",DrvConvert";
  21. //
  22. // Lowercase, just like win31 for WM_WININICHANGE
  23. //
  24. WCHAR *szDevices=L"devices";
  25. WCHAR *szWindows=L"windows";
  26. #define NUM_INTERACTIVE_RIDS 1
  27. extern DWORD RouterCacheSize;
  28. extern PROUTERCACHE RouterCacheTable;
  29. typedef struct _DEVMODECHG_INFO {
  30. DWORD signature;
  31. HANDLE hDrvModule;
  32. FARPROC pfnConvertDevMode;
  33. } DEVMODECHG_INFO, *PDEVMODECHG_INFO;
  34. #define DMC_SIGNATURE 'DMC' /* 'DMC' is the signature value */
  35. DWORD
  36. RouterIsOlderThan(
  37. DWORD i,
  38. DWORD j
  39. );
  40. VOID
  41. FreeOtherNames(LPWSTR **ppszMyOtherNames, DWORD *cOtherNames);
  42. LPWSTR
  43. AnsiToUnicodeStringWithAlloc(LPSTR pAnsi);
  44. BOOL
  45. DeleteSubKeyTree(
  46. HKEY ParentHandle,
  47. WCHAR SubKeyName[]
  48. )
  49. {
  50. LONG Error;
  51. DWORD Index;
  52. HKEY KeyHandle;
  53. BOOL RetValue;
  54. WCHAR ChildKeyName[ MAX_PATH ];
  55. DWORD ChildKeyNameLength;
  56. Error = RegOpenKeyEx(
  57. ParentHandle,
  58. SubKeyName,
  59. 0,
  60. KEY_READ | KEY_WRITE,
  61. &KeyHandle
  62. );
  63. if (Error != ERROR_SUCCESS) {
  64. SetLastError(Error);
  65. return(FALSE);
  66. }
  67. ChildKeyNameLength = MAX_PATH;
  68. Index = 0; // Don't increment this Index
  69. while ((Error = RegEnumKeyEx(
  70. KeyHandle,
  71. Index,
  72. ChildKeyName,
  73. &ChildKeyNameLength,
  74. NULL,
  75. NULL,
  76. NULL,
  77. NULL
  78. )) == ERROR_SUCCESS) {
  79. RetValue = DeleteSubKeyTree( KeyHandle, ChildKeyName );
  80. if (RetValue == FALSE) {
  81. // Error -- couldn't delete the sub key
  82. RegCloseKey(KeyHandle);
  83. return(FALSE);
  84. }
  85. ChildKeyNameLength = MAX_PATH;
  86. }
  87. Error = RegCloseKey(
  88. KeyHandle
  89. );
  90. if (Error != ERROR_SUCCESS) {
  91. return(FALSE);
  92. }
  93. Error = RegDeleteKey(
  94. ParentHandle,
  95. SubKeyName
  96. );
  97. if (Error != ERROR_SUCCESS) {
  98. return(FALSE);
  99. }
  100. // Return Success - the key has successfully been deleted
  101. return(TRUE);
  102. }
  103. LPWSTR RemoveOrderEntry(
  104. LPWSTR szOrderString,
  105. DWORD cbStringSize,
  106. LPWSTR szOrderEntry,
  107. LPDWORD pcbBytesReturned
  108. )
  109. {
  110. LPWSTR lpMem, psz, temp;
  111. if (szOrderString == NULL) {
  112. *pcbBytesReturned = 0;
  113. return(NULL);
  114. }
  115. if (lpMem = AllocSplMem( cbStringSize)) {
  116. temp = szOrderString;
  117. psz = lpMem;
  118. while (*temp) {
  119. if (!lstrcmpi(temp, szOrderEntry)) { // we need to remove
  120. temp += lstrlen(temp)+1; // this entry in Order
  121. continue;
  122. }
  123. lstrcpy(psz,temp);
  124. psz += lstrlen(temp)+1;
  125. temp += lstrlen(temp)+1;
  126. }
  127. *psz = L'\0';
  128. *pcbBytesReturned = (DWORD) ((psz - lpMem)+1)*sizeof(WCHAR);
  129. return(lpMem);
  130. }
  131. *pcbBytesReturned = 0;
  132. return(lpMem);
  133. }
  134. LPWSTR AppendOrderEntry(
  135. LPWSTR szOrderString,
  136. DWORD cbStringSize,
  137. LPWSTR szOrderEntry,
  138. LPDWORD pcbBytesReturned
  139. )
  140. {
  141. LPWSTR lpMem, temp, psz;
  142. DWORD cb = 0;
  143. BOOL bExists = FALSE;
  144. if ((szOrderString == NULL) && (szOrderEntry == NULL)) {
  145. *pcbBytesReturned = 0;
  146. return(NULL);
  147. }
  148. if (szOrderString == NULL) {
  149. cb = wcslen(szOrderEntry)*sizeof(WCHAR)+ sizeof(WCHAR) + sizeof(WCHAR);
  150. if (lpMem = AllocSplMem(cb)){
  151. wcscpy(lpMem, szOrderEntry);
  152. *pcbBytesReturned = cb;
  153. } else {
  154. *pcbBytesReturned = 0;
  155. }
  156. return lpMem;
  157. }
  158. if (lpMem = AllocSplMem( cbStringSize + wcslen(szOrderEntry)*sizeof(WCHAR)
  159. + sizeof(WCHAR))){
  160. temp = szOrderString;
  161. psz = lpMem;
  162. while (*temp) {
  163. if (!lstrcmpi(temp, szOrderEntry)) { // Make sure we don't
  164. bExists = TRUE; // duplicate entries
  165. }
  166. lstrcpy(psz, temp);
  167. psz += lstrlen(temp)+ 1;
  168. temp += lstrlen(temp)+1;
  169. }
  170. if (!bExists) { // if it doesn't exist
  171. lstrcpy(psz, szOrderEntry); // add the entry
  172. psz += lstrlen(szOrderEntry)+1;
  173. }
  174. *psz = L'\0'; // the second null character
  175. *pcbBytesReturned = (DWORD) ((psz - lpMem) + 1)* sizeof(WCHAR);
  176. }
  177. return(lpMem);
  178. }
  179. typedef struct {
  180. DWORD dwType;
  181. DWORD dwMessage;
  182. WPARAM wParam;
  183. LPARAM lParam;
  184. } MESSAGE, *PMESSAGE;
  185. VOID
  186. SendMessageThread(
  187. PMESSAGE pMessage);
  188. BOOL
  189. BroadcastMessage(
  190. DWORD dwType,
  191. DWORD dwMessage,
  192. WPARAM wParam,
  193. LPARAM lParam)
  194. {
  195. HANDLE hThread;
  196. DWORD ThreadId;
  197. PMESSAGE pMessage;
  198. BOOL bReturn = FALSE;
  199. pMessage = AllocSplMem(sizeof(MESSAGE));
  200. if (pMessage) {
  201. pMessage->dwType = dwType;
  202. pMessage->dwMessage = dwMessage;
  203. pMessage->wParam = wParam;
  204. pMessage->lParam = lParam;
  205. //
  206. // We should have a queue of events to broadcast and then have a
  207. // single thread pulling them off the queue until there is nothing
  208. // left and then that thread could go away.
  209. //
  210. // The current design can lead to a huge number of threads being
  211. // created and torn down in both this and csrss process.
  212. //
  213. hThread = CreateThread(NULL, 0,
  214. (LPTHREAD_START_ROUTINE)SendMessageThread,
  215. (LPVOID)pMessage,
  216. 0,
  217. &ThreadId);
  218. if (hThread) {
  219. CloseHandle(hThread);
  220. bReturn = TRUE;
  221. } else {
  222. FreeSplMem(pMessage);
  223. }
  224. }
  225. return bReturn;
  226. }
  227. // The Broadcasts are done on a separate thread, the reason it CSRSS
  228. // will create a server side thread when we call user and we don't want
  229. // that to be pared up with the RPC thread which is in the spooss server.
  230. // We want it to go away the moment we have completed the SendMessage.
  231. // We also call SendNotifyMessage since we don't care if the broadcasts
  232. // are syncronous this uses less resources since usually we don't have more
  233. // than one broadcast.
  234. VOID
  235. SendMessageThread(
  236. PMESSAGE pMessage)
  237. {
  238. switch (pMessage->dwType) {
  239. case BROADCAST_TYPE_MESSAGE:
  240. SendNotifyMessage(HWND_BROADCAST,
  241. pMessage->dwMessage,
  242. pMessage->wParam,
  243. pMessage->lParam);
  244. break;
  245. case BROADCAST_TYPE_CHANGEDEFAULT:
  246. //
  247. // Same order and strings as win31.
  248. //
  249. SendNotifyMessage(HWND_BROADCAST,
  250. WM_WININICHANGE,
  251. 0,
  252. (LPARAM)szDevices);
  253. SendNotifyMessage(HWND_BROADCAST,
  254. WM_WININICHANGE,
  255. 0,
  256. (LPARAM)szWindows);
  257. break;
  258. }
  259. FreeSplMem(pMessage);
  260. ExitThread(0);
  261. }
  262. BOOL
  263. IsNamedPipeRpcCall(
  264. VOID
  265. )
  266. {
  267. unsigned int uType;
  268. //
  269. //
  270. //
  271. return ERROR_SUCCESS == I_RpcBindingInqTransportType(NULL, &uType) &&
  272. uType != TRANSPORT_TYPE_LPC;
  273. }
  274. BOOL
  275. IsLocalCall(
  276. VOID
  277. )
  278. {
  279. HANDLE hToken;
  280. BOOL bStatus;
  281. DWORD dwError;
  282. PSID pTestSid = NULL;
  283. PSID pCurSid;
  284. DWORD cbSize = 0;
  285. DWORD cbRequired = 0;
  286. DWORD i;
  287. BOOL bRet = FALSE;
  288. BOOL bMember;
  289. DWORD dwSaveLastError = GetLastError();
  290. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  291. unsigned int uType;
  292. dwError = I_RpcBindingInqTransportType(NULL, &uType);
  293. if ( dwError == RPC_S_NO_CALL_ACTIVE ) {
  294. //
  295. // KM call
  296. //
  297. return TRUE;
  298. }
  299. if ( dwError == ERROR_SUCCESS ) {
  300. if ( uType != TRANSPORT_TYPE_LPC ) {
  301. //
  302. // Not LRPC so call is remote
  303. //
  304. return FALSE;
  305. }
  306. } else {
  307. //
  308. // This should not fail. So we'll assert on chk bld and
  309. // continue looking at SIDS on fre builds
  310. //
  311. SPLASSERT( dwError != ERROR_SUCCESS);
  312. }
  313. bStatus = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken);
  314. if (!bStatus) {
  315. // Couldn't open the thread's token, nothing much we can do
  316. DBGMSG(DBG_TRACE,("Error: couldn't open the thread's Access token %d\n", GetLastError()));
  317. return FALSE;
  318. }
  319. if ( !AllocateAndInitializeSid(&sia,
  320. 1,
  321. SECURITY_NETWORK_RID,
  322. 0, 0, 0, 0, 0, 0, 0,
  323. &pTestSid) ) {
  324. DBGMSG(DBG_TRACE,
  325. ("Error: could not AllocateAndInitializeSid -%d\n",
  326. GetLastError()));
  327. goto Done;
  328. }
  329. if( !CheckTokenMembership( hToken,
  330. pTestSid,
  331. &bMember )){
  332. DBGMSG(DBG_TRACE,
  333. ("Error: CheckTokenMembership failed %d\n",
  334. GetLastError()));
  335. goto Done;
  336. }
  337. if( !bMember ){
  338. //
  339. // Not a member, so no match for network sid. Therefore local.
  340. //
  341. bRet = TRUE;
  342. }
  343. Done:
  344. if ( pTestSid )
  345. FreeSid(pTestSid);
  346. CloseHandle(hToken);
  347. SetLastError( dwSaveLastError );
  348. return bRet;
  349. }
  350. LPPROVIDOR
  351. FindEntryinRouterCache(
  352. LPWSTR pPrinterName
  353. )
  354. {
  355. DWORD i;
  356. if (!pPrinterName)
  357. return NULL;
  358. DBGMSG(DBG_TRACE, ("FindEntryinRouterCache with %ws\n", pPrinterName));
  359. if (RouterCacheSize == 0 ) {
  360. DBGMSG(DBG_TRACE, ("FindEntryInRouterCache with %ws returning -1 (zero cache)\n", pPrinterName));
  361. return NULL;
  362. }
  363. for (i = 0; i < RouterCacheSize; i++ ) {
  364. if (RouterCacheTable[i].bAvailable) {
  365. if (!_wcsicmp(RouterCacheTable[i].pPrinterName, pPrinterName)) {
  366. //
  367. // update the time stamp so that it is current and not old
  368. //
  369. GetSystemTime(&RouterCacheTable[i].st);
  370. //
  371. //
  372. //
  373. DBGMSG(DBG_TRACE, ("FindEntryinRouterCache returning with %d\n", i));
  374. return RouterCacheTable[i].pProvidor;
  375. }
  376. }
  377. }
  378. DBGMSG(DBG_TRACE, ("FindEntryinRouterCache returning with -1\n"));
  379. return NULL;
  380. }
  381. DWORD
  382. AddEntrytoRouterCache(
  383. LPWSTR pPrinterName,
  384. LPPROVIDOR pProvidor
  385. )
  386. {
  387. DWORD LRUEntry = (DWORD)-1;
  388. DWORD i;
  389. DBGMSG(DBG_TRACE, ("AddEntrytoRouterCache with %ws\n", pPrinterName));
  390. if (RouterCacheSize == 0 ) {
  391. DBGMSG(DBG_TRACE, ("AddEntrytoRouterCache with %ws returning -1 (zero cache)\n", pPrinterName));
  392. return (DWORD)-1;
  393. }
  394. for (i = 0; i < RouterCacheSize; i++ ) {
  395. if (!RouterCacheTable[i].bAvailable) {
  396. //
  397. // Found an available entry; use it
  398. // fill in the name of the printer and the providor
  399. // that supports this printer.
  400. //
  401. break;
  402. } else {
  403. if ((LRUEntry == -1) || (i == RouterIsOlderThan(i, LRUEntry))){
  404. LRUEntry = i;
  405. }
  406. }
  407. }
  408. if (i == RouterCacheSize) {
  409. //
  410. // We have no available entries so we need to use
  411. // the LRUEntry which is busy
  412. //
  413. FreeSplStr(RouterCacheTable[LRUEntry].pPrinterName);
  414. RouterCacheTable[LRUEntry].bAvailable = FALSE;
  415. i = LRUEntry;
  416. }
  417. if ((RouterCacheTable[i].pPrinterName = AllocSplStr(pPrinterName)) == NULL){
  418. //
  419. // Alloc failed so we're kinda hosed so return -1
  420. //
  421. return (DWORD)-1;
  422. }
  423. RouterCacheTable[i].bAvailable = TRUE;
  424. RouterCacheTable[i].pProvidor = pProvidor;
  425. //
  426. // update the time stamp so that we know when this entry was made
  427. //
  428. GetSystemTime(&RouterCacheTable[i].st);
  429. DBGMSG(DBG_TRACE, ("AddEntrytoRouterCache returning with %d\n", i));
  430. return i;
  431. }
  432. VOID
  433. DeleteEntryfromRouterCache(
  434. LPWSTR pPrinterName
  435. )
  436. {
  437. DWORD i;
  438. if (RouterCacheSize == 0) {
  439. DBGMSG(DBG_TRACE, ("DeleteEntryfromRouterCache with %ws returning -1 (zero cache)\n", pPrinterName));
  440. return;
  441. }
  442. DBGMSG(DBG_TRACE, ("DeleteEntryFromRouterCache with %ws\n", pPrinterName));
  443. for (i = 0; i < RouterCacheSize; i++ ) {
  444. if (RouterCacheTable[i].bAvailable) {
  445. if (!_wcsicmp(RouterCacheTable[i].pPrinterName, pPrinterName)) {
  446. //
  447. // reset the available flag on this node
  448. //
  449. FreeSplStr(RouterCacheTable[i].pPrinterName);
  450. RouterCacheTable[i].pProvidor = NULL;
  451. RouterCacheTable[i].bAvailable = FALSE;
  452. DBGMSG(DBG_TRACE, ("DeleteEntryFromRouterCache returning after deleting the %d th entry\n", i));
  453. return;
  454. }
  455. }
  456. }
  457. DBGMSG(DBG_TRACE, ("DeleteEntryFromRouterCache returning after not finding an entry to delete\n"));
  458. }
  459. DWORD
  460. RouterIsOlderThan(
  461. DWORD i,
  462. DWORD j
  463. )
  464. {
  465. SYSTEMTIME *pi, *pj;
  466. DWORD iMs, jMs;
  467. DBGMSG(DBG_TRACE, ("RouterIsOlderThan entering with i %d j %d\n", i, j));
  468. pi = &(RouterCacheTable[i].st);
  469. pj = &(RouterCacheTable[j].st);
  470. DBGMSG(DBG_TRACE, ("Index i %d - %d:%d:%d:%d:%d:%d:%d\n",
  471. i, pi->wYear, pi->wMonth, pi->wDay, pi->wHour, pi->wMinute, pi->wSecond, pi->wMilliseconds));
  472. DBGMSG(DBG_TRACE,("Index j %d - %d:%d:%d:%d:%d:%d:%d\n",
  473. j, pj->wYear, pj->wMonth, pj->wDay, pj->wHour, pj->wMinute, pj->wSecond, pj->wMilliseconds));
  474. if (pi->wYear < pj->wYear) {
  475. DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", i));
  476. return(i);
  477. } else if (pi->wYear > pj->wYear) {
  478. DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", j));
  479. return(j);
  480. } else if (pi->wMonth < pj->wMonth) {
  481. DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", i));
  482. return(i);
  483. } else if (pi->wMonth > pj->wMonth) {
  484. DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", j));
  485. return(j);
  486. } else if (pi->wDay < pj->wDay) {
  487. DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", i));
  488. return(i);
  489. } else if (pi->wDay > pj->wDay) {
  490. DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", j));
  491. return(j);
  492. } else {
  493. iMs = ((((pi->wHour * 60) + pi->wMinute)*60) + pi->wSecond)* 1000 + pi->wMilliseconds;
  494. jMs = ((((pj->wHour * 60) + pj->wMinute)*60) + pj->wSecond)* 1000 + pj->wMilliseconds;
  495. if (iMs <= jMs) {
  496. DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", i));
  497. return(i);
  498. } else {
  499. DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", j));
  500. return(j);
  501. }
  502. }
  503. }
  504. /*++
  505. Routine Name
  506. ImpersonationToken
  507. Routine Description:
  508. This routine checks if a token is a primary token or an impersonation
  509. token.
  510. Arguments:
  511. hToken - impersonation token or primary token of the process
  512. Return Value:
  513. TRUE, if the token is an impersonation token
  514. FALSE, otherwise.
  515. --*/
  516. BOOL
  517. ImpersonationToken(
  518. IN HANDLE hToken
  519. )
  520. {
  521. BOOL bRet = TRUE;
  522. TOKEN_TYPE eTokenType;
  523. DWORD cbNeeded;
  524. DWORD LastError;
  525. //
  526. // Preserve the last error. Some callers of ImpersonatePrinterClient (which
  527. // calls ImpersonationToken) rely on the fact that ImpersonatePrinterClient
  528. // does not alter the last error.
  529. //
  530. LastError = GetLastError();
  531. //
  532. // Get the token type from the thread token. The token comes
  533. // from RevertToPrinterSelf. An impersonation token cannot be
  534. // queried, because RevertToPRinterSelf doesn't open it with
  535. // TOKEN_QUERY access. That's why we assume that hToken is
  536. // an impersonation token by default
  537. //
  538. if (GetTokenInformation(hToken,
  539. TokenType,
  540. &eTokenType,
  541. sizeof(eTokenType),
  542. &cbNeeded))
  543. {
  544. bRet = eTokenType == TokenImpersonation;
  545. }
  546. SetLastError(LastError);
  547. return bRet;
  548. }
  549. /*++
  550. Routine Name
  551. RevertToPrinterSelf
  552. Routine Description:
  553. This routine will revert to the local system. It returns the token that
  554. ImpersonatePrinterClient then uses to imersonate the client again. If the
  555. current thread doesn't impersonate, then the function merely returns the
  556. primary token of the process. (instead of returning NULL) Thus we honor
  557. a request for reverting to printer self, even if the thread is not impersonating.
  558. Arguments:
  559. None.
  560. Return Value:
  561. NULL, if the function failed
  562. HANDLE to token, otherwise.
  563. --*/
  564. HANDLE
  565. RevertToPrinterSelf(
  566. VOID
  567. )
  568. {
  569. HANDLE NewToken, OldToken;
  570. NTSTATUS Status;
  571. NewToken = NULL;
  572. Status = NtOpenThreadToken(NtCurrentThread(),
  573. TOKEN_IMPERSONATE,
  574. TRUE,
  575. &OldToken);
  576. if (NT_SUCCESS(Status))
  577. {
  578. //
  579. // We are currently impersonating
  580. //
  581. Status = NtSetInformationThread(NtCurrentThread(),
  582. ThreadImpersonationToken,
  583. (PVOID)&NewToken,
  584. (ULONG)sizeof(HANDLE));
  585. }
  586. else if (Status == STATUS_NO_TOKEN)
  587. {
  588. //
  589. // We are not impersonating
  590. //
  591. Status = NtOpenProcessToken(NtCurrentProcess(),
  592. TOKEN_QUERY,
  593. &OldToken);
  594. }
  595. if (!NT_SUCCESS(Status))
  596. {
  597. SetLastError(Status);
  598. return NULL;
  599. }
  600. return OldToken;
  601. }
  602. /*++
  603. Routine Name
  604. ImpersonatePrinterClient
  605. Routine Description:
  606. This routine attempts to set the passed in hToken as the token for the
  607. current thread. If hToken is not an impersonation token, then the routine
  608. will simply close the token.
  609. Arguments:
  610. hToken - impersonation token or primary token of the process
  611. Return Value:
  612. TRUE, if the function succeeds in setting hToken
  613. FALSE, otherwise.
  614. --*/
  615. BOOL
  616. ImpersonatePrinterClient(
  617. HANDLE hToken)
  618. {
  619. NTSTATUS Status;
  620. //
  621. // Check if we have an impersonation token
  622. //
  623. if (ImpersonationToken(hToken))
  624. {
  625. Status = NtSetInformationThread(NtCurrentThread(),
  626. ThreadImpersonationToken,
  627. (PVOID)&hToken,
  628. (ULONG)sizeof(HANDLE));
  629. if (!NT_SUCCESS(Status))
  630. {
  631. SetLastError(Status);
  632. return FALSE;
  633. }
  634. }
  635. NtClose(hToken);
  636. return TRUE;
  637. }
  638. HANDLE
  639. LoadDriver(
  640. LPWSTR pDriverFile)
  641. {
  642. UINT uOldErrorMode;
  643. fnWinSpoolDrv fnList;
  644. HANDLE hReturn = NULL;
  645. if (!pDriverFile || !*pDriverFile) {
  646. // Nothing to load
  647. return hReturn;
  648. }
  649. uOldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  650. if (SplInitializeWinSpoolDrv(&fnList)) {
  651. hReturn = (*(fnList.pfnRefCntLoadDriver))(pDriverFile,
  652. LOAD_WITH_ALTERED_SEARCH_PATH,
  653. 0, FALSE);
  654. }
  655. (VOID)SetErrorMode(uOldErrorMode);
  656. return hReturn;
  657. }
  658. VOID
  659. UnloadDriver(
  660. HANDLE hModule
  661. )
  662. {
  663. fnWinSpoolDrv fnList;
  664. if (SplInitializeWinSpoolDrv(&fnList)) {
  665. (* (fnList.pfnRefCntUnloadDriver))(hModule, TRUE);
  666. }
  667. }
  668. VOID
  669. UnloadDriverFile(
  670. IN OUT HANDLE hDevModeChgInfo
  671. )
  672. /*++
  673. Description:
  674. Does a FreeLibrary on the driver file and frees memory
  675. Arguments:
  676. hDevModeChgInfo - A handle returned by LoadDriverFiletoConvertDevmode
  677. Return Value:
  678. None
  679. --*/
  680. {
  681. PDEVMODECHG_INFO pDevModeChgInfo = (PDEVMODECHG_INFO) hDevModeChgInfo;
  682. SPLASSERT(pDevModeChgInfo &&
  683. pDevModeChgInfo->signature == DMC_SIGNATURE);
  684. if ( pDevModeChgInfo && pDevModeChgInfo->signature == DMC_SIGNATURE ) {
  685. if ( pDevModeChgInfo->hDrvModule ) {
  686. UnloadDriver(pDevModeChgInfo->hDrvModule);
  687. }
  688. FreeSplMem((LPVOID)pDevModeChgInfo);
  689. }
  690. }
  691. HANDLE
  692. LoadDriverFiletoConvertDevmode(
  693. IN LPWSTR pDriverFile
  694. )
  695. /*++
  696. Description:
  697. Does a LoadLibrary on the driver file given. This will give a handle
  698. which can be used to do devmode conversion later using
  699. CallDrvDevModeConversion.
  700. Caller should call UnloadDriverFile to do a FreeLibrary and free memory
  701. Note: Driver will call OpenPrinter to spooler
  702. Arguments:
  703. pDriverFile - Full path of the driver file to do a LoadLibrary
  704. Return Value:
  705. A handle value to be used to make calls to CallDrvDevModeConversion,
  706. NULL on error
  707. --*/
  708. {
  709. PDEVMODECHG_INFO pDevModeChgInfo = NULL;
  710. BOOL bFail = TRUE;
  711. DWORD dwNeeded;
  712. SPLASSERT(pDriverFile != NULL);
  713. pDevModeChgInfo = (PDEVMODECHG_INFO) AllocSplMem(sizeof(*pDevModeChgInfo));
  714. if ( !pDevModeChgInfo ) {
  715. DBGMSG(DBG_WARNING, ("printer.c: Memory allocation failed for DEVMODECHG_INFO\n"));
  716. goto Cleanup;
  717. }
  718. pDevModeChgInfo->signature = DMC_SIGNATURE;
  719. pDevModeChgInfo->hDrvModule = LoadDriver(pDriverFile);
  720. if ( !pDevModeChgInfo->hDrvModule ) {
  721. DBGMSG(DBG_WARNING,("LoadDriverFiletoConvertDevmode: Can't load driver file %ws\n", pDriverFile));
  722. goto Cleanup;
  723. }
  724. //
  725. // Some third party driver may not be providing DrvConvertDevMode
  726. //
  727. pDevModeChgInfo->pfnConvertDevMode = GetProcAddress(pDevModeChgInfo->hDrvModule,
  728. "DrvConvertDevMode");
  729. if ( !pDevModeChgInfo->pfnConvertDevMode )
  730. goto Cleanup;
  731. bFail = FALSE;
  732. Cleanup:
  733. if ( bFail ) {
  734. if ( pDevModeChgInfo ) {
  735. UnloadDriverFile((HANDLE)pDevModeChgInfo);
  736. }
  737. return (HANDLE) NULL;
  738. } else {
  739. return (HANDLE) pDevModeChgInfo;
  740. }
  741. }
  742. DWORD
  743. CallDrvDevModeConversion(
  744. IN HANDLE hDevModeChgInfo,
  745. IN LPWSTR pszPrinterName,
  746. IN LPBYTE pDevMode1,
  747. IN OUT LPBYTE *ppDevMode2,
  748. IN OUT LPDWORD pdwOutDevModeSize,
  749. IN DWORD dwConvertMode,
  750. IN BOOL bAlloc
  751. )
  752. /*++
  753. Description:
  754. Does deve mode conversion by calling driver
  755. If bAlloc is TRUE routine will do the allocation using AllocSplMem
  756. Note: Driver is going to call OpenPrinter.
  757. Arguments:
  758. hDevModeChgInfo - Points to DEVMODECHG_INFO
  759. pszPrinterName - Printer name
  760. pInDevMode - Input devmode (will be NULL for CDM_DRIVER_DEFAULT)
  761. *pOutDevMode - Points to output devmode
  762. pdwOutDevModeSize - Output devmode size on succesful return
  763. if !bAlloc this will give input buffer size
  764. dwConvertMode - Devmode conversion mode to give to driver
  765. bAllocate - Tells the routine to do allocation to *pOutPrinter
  766. If bAllocate is TRUE and no devmode conversion is required
  767. call will fail.
  768. Return Value:
  769. Returns last error
  770. --*/
  771. {
  772. DWORD dwBufSize, dwSize, dwLastError = ERROR_SUCCESS;
  773. LPDEVMODE pInDevMode = (LPDEVMODE)pDevMode1,
  774. *ppOutDevMode = (LPDEVMODE *) ppDevMode2;
  775. PDEVMODECHG_INFO pDevModeChgInfo = (PDEVMODECHG_INFO) hDevModeChgInfo;
  776. PWSTR pszDrvConvert = pszPrinterName;
  777. if ( !pDevModeChgInfo ||
  778. pDevModeChgInfo->signature != DMC_SIGNATURE ||
  779. !pDevModeChgInfo->pfnConvertDevMode ) {
  780. SPLASSERT(pDevModeChgInfo &&
  781. pDevModeChgInfo->signature == DMC_SIGNATURE &&
  782. pDevModeChgInfo->pfnConvertDevMode);
  783. return ERROR_INVALID_PARAMETER;
  784. }
  785. //
  786. // We decorate the pszPrinterName with ",DrvConvert" to prevent drivers from
  787. // infinitely recursing by calling GetPrinter inside ConvertDevMode
  788. //
  789. if (wcsstr(pszPrinterName, gszDrvConvert)) {
  790. return ERROR_INVALID_PARAMETER;
  791. }
  792. if (!(pszDrvConvert = AutoCat(pszPrinterName, gszDrvConvert))) {
  793. return GetLastError();
  794. }
  795. DBGMSG(DBG_INFO,("Convert DevMode %d\n", dwConvertMode));
  796. #if DBG
  797. #else
  798. try {
  799. #endif
  800. if ( bAlloc ) {
  801. //
  802. // If we have to do allocation first find size neeeded
  803. //
  804. *pdwOutDevModeSize = 0;
  805. *ppOutDevMode = NULL;
  806. (*pDevModeChgInfo->pfnConvertDevMode)(pszDrvConvert,
  807. pInDevMode,
  808. NULL,
  809. pdwOutDevModeSize,
  810. dwConvertMode);
  811. dwLastError = GetLastError();
  812. if ( dwLastError != ERROR_INSUFFICIENT_BUFFER ) {
  813. DBGMSG(DBG_WARNING,
  814. ("CallDrvDevModeConversion: Unexpected error %d\n",
  815. GetLastError()));
  816. if (dwLastError == ERROR_SUCCESS) {
  817. SPLASSERT(dwLastError != ERROR_SUCCESS);
  818. // if driver doesn't fail the above call, it is a broken driver and probably
  819. // failed a HeapAlloc, which doesn't SetLastError()
  820. SetLastError(dwLastError = ERROR_NOT_ENOUGH_MEMORY);
  821. }
  822. #if DBG
  823. goto Cleanup;
  824. #else
  825. leave;
  826. #endif
  827. }
  828. *ppOutDevMode = AllocSplMem(*pdwOutDevModeSize);
  829. if ( !*ppOutDevMode ) {
  830. dwLastError = GetLastError();
  831. #if DBG
  832. goto Cleanup;
  833. #else
  834. leave;
  835. #endif
  836. }
  837. }
  838. dwBufSize = *pdwOutDevModeSize;
  839. if ( !(*pDevModeChgInfo->pfnConvertDevMode)(
  840. pszDrvConvert,
  841. pInDevMode,
  842. ppOutDevMode ? *ppOutDevMode
  843. : NULL,
  844. pdwOutDevModeSize,
  845. dwConvertMode) ) {
  846. dwLastError = GetLastError();
  847. if (dwLastError == ERROR_SUCCESS) {
  848. SPLASSERT(dwLastError != ERROR_SUCCESS);
  849. // if driver doesn't fail the above call, it is a broken driver and probably
  850. // failed a HeapAlloc, which doesn't SetLastError()
  851. SetLastError(dwLastError = ERROR_NOT_ENOUGH_MEMORY);
  852. }
  853. } else {
  854. dwLastError = ERROR_SUCCESS;
  855. }
  856. #if DBG
  857. Cleanup:
  858. #else
  859. } except(1) {
  860. DBGMSG(DBG_ERROR,
  861. ("CallDrvDevModeConversion: Exception from driver\n"));
  862. dwLastError = GetExceptionCode();
  863. SetLastError(dwLastError);
  864. }
  865. #endif
  866. //
  867. // If we allocated mmeory free it and zero the pointer
  868. //
  869. if ( dwLastError != ERROR_SUCCESS && bAlloc && *ppOutDevMode ) {
  870. FreeSplMem(*ppOutDevMode);
  871. *ppOutDevMode = 0;
  872. *pdwOutDevModeSize = 0;
  873. }
  874. if ( dwLastError != ERROR_SUCCESS &&
  875. dwLastError != ERROR_INSUFFICIENT_BUFFER ) {
  876. DBGMSG(DBG_WARNING, ("DevmodeConvert unexpected error %d\n", dwLastError));
  877. }
  878. if ( dwLastError == ERROR_SUCCESS ) {
  879. dwSize = (*ppOutDevMode)->dmSize + (*ppOutDevMode)->dmDriverExtra;
  880. //
  881. // Did the driver return correct size as per the devmode?
  882. //
  883. if ( *pdwOutDevModeSize != dwSize ) {
  884. DBGMSG(DBG_ERROR,
  885. ("Driver says outsize is %d, really %d\n",
  886. *pdwOutDevModeSize, dwSize));
  887. *pdwOutDevModeSize = dwSize;
  888. }
  889. //
  890. // Is it a valid devmode which did not overwrite the buffer?
  891. //
  892. if ( *pdwOutDevModeSize < MIN_DEVMODE_SIZEW ||
  893. *pdwOutDevModeSize > dwBufSize ) {
  894. DBGMSG(DBG_ERROR,
  895. ("Bad devmode from the driver size %d, buffer %d",
  896. *pdwOutDevModeSize, dwBufSize));
  897. dwLastError = ERROR_INVALID_PARAMETER;
  898. if ( bAlloc ) {
  899. FreeSplMem(*ppOutDevMode);
  900. *ppOutDevMode = NULL;
  901. }
  902. *pdwOutDevModeSize = 0;
  903. }
  904. }
  905. FreeSplMem(pszDrvConvert);
  906. return dwLastError;
  907. }
  908. BOOL
  909. BuildOtherNamesFromMachineName(
  910. LPWSTR **ppszMyOtherNames,
  911. DWORD *cOtherNames
  912. )
  913. /*++
  914. Routine Description:
  915. This routine builds list of names other than the machine name that
  916. can be used to call spooler APIs.
  917. --*/
  918. {
  919. HANDLE hModule;
  920. struct hostent *HostEnt, *(*Fngethostbyname)(LPTSTR);
  921. struct in_addr *ptr;
  922. INT (*FnWSAStartup)(WORD, LPWSADATA);
  923. DWORD Index, Count;
  924. WSADATA WSAData;
  925. VOID (*FnWSACleanup)();
  926. LPSTR (*Fninet_ntoa)(struct in_addr);
  927. WORD wVersion;
  928. BOOL bRet = FALSE;
  929. DWORD dwRet;
  930. SPLASSERT(cOtherNames && ppszMyOtherNames);
  931. *cOtherNames = 0;
  932. wVersion = MAKEWORD(1, 1);
  933. dwRet = WSAStartup(wVersion, &WSAData);
  934. if (dwRet) {
  935. DBGMSG(DBG_WARNING, ("BuildOtherNamesFromMachineName: WSAStartup failed\n"));
  936. SetLastError(dwRet);
  937. return FALSE;
  938. }
  939. HostEnt = gethostbyname(NULL);
  940. if (HostEnt) {
  941. for (*cOtherNames = 0 ; HostEnt->h_addr_list[*cOtherNames] ; ++(*cOtherNames))
  942. ;
  943. *cOtherNames += 2; // Add one for DNS and one for machine name
  944. *ppszMyOtherNames = (LPWSTR *) AllocSplMem(*cOtherNames*sizeof *ppszMyOtherNames);
  945. if ( !*ppszMyOtherNames ) {
  946. *cOtherNames = 0;
  947. goto Cleanup;
  948. }
  949. (*ppszMyOtherNames)[0] = AllocSplStr(szMachineName + 2); // Exclude the leading double-backslash
  950. (*ppszMyOtherNames)[1] = AnsiToUnicodeStringWithAlloc(HostEnt->h_name);
  951. for (Index = 0 ; HostEnt->h_addr_list[Index] ; ++Index) {
  952. ptr = (struct in_addr *) HostEnt->h_addr_list[Index];
  953. (*ppszMyOtherNames)[Index+2] = AnsiToUnicodeStringWithAlloc(inet_ntoa(*ptr));
  954. }
  955. // check for allocation failures
  956. for (Index = 0 ; Index < *cOtherNames ; ++Index) {
  957. if ( !(*ppszMyOtherNames)[Index] ) {
  958. FreeOtherNames(ppszMyOtherNames, cOtherNames);
  959. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  960. goto Cleanup;
  961. }
  962. }
  963. bRet = TRUE;
  964. } else {
  965. DBGMSG(DBG_WARNING, ("BuildOtherNamesFromMachineName: gethostbyname failed for with %d\n", GetLastError()));
  966. }
  967. Cleanup:
  968. WSACleanup();
  969. return bRet;
  970. }
  971. VOID
  972. FreeOtherNames(LPWSTR **ppszMyOtherNames, DWORD *cOtherNames)
  973. {
  974. DWORD i;
  975. for( i = 0 ; i < *cOtherNames ; ++i)
  976. FreeSplMem((*ppszMyOtherNames)[i]);
  977. FreeSplMem(*ppszMyOtherNames);
  978. }
  979. LPWSTR
  980. AnsiToUnicodeStringWithAlloc(
  981. LPSTR pAnsi
  982. )
  983. /*++
  984. Description:
  985. Convert ANSI string to UNICODE. Routine allocates memory from the heap
  986. which should be freed by the caller.
  987. Arguments:
  988. pAnsi - Points to the ANSI string
  989. Return Vlaue:
  990. Pointer to UNICODE string
  991. --*/
  992. {
  993. LPWSTR pUnicode;
  994. DWORD rc;
  995. rc = MultiByteToWideChar(CP_ACP,
  996. MB_PRECOMPOSED,
  997. pAnsi,
  998. -1,
  999. NULL,
  1000. 0);
  1001. rc *= sizeof(WCHAR);
  1002. if ( !rc || !(pUnicode = (LPWSTR) AllocSplMem(rc)) )
  1003. return NULL;
  1004. rc = MultiByteToWideChar(CP_ACP,
  1005. MB_PRECOMPOSED,
  1006. pAnsi,
  1007. -1,
  1008. pUnicode,
  1009. rc);
  1010. if ( rc )
  1011. return pUnicode;
  1012. else {
  1013. FreeSplMem(pUnicode);
  1014. return NULL;
  1015. }
  1016. }
  1017. /*++
  1018. Routine Description
  1019. Determines whether or not a machine name contains the local machine name.
  1020. Localspl enum calls fail if pName != local machine name (\\Machine).
  1021. Remote enum provider is then called. The remote enum provider must check
  1022. if the UNC name refers to the local machine, and fail if it does to avoid
  1023. endless recursion.
  1024. Arguments:
  1025. LPWSTR pName - UNC name.
  1026. Return Value:
  1027. TRUE: pName == \\szMachineName\...
  1028. - or -
  1029. pName == \\szMachineName
  1030. FALSE: anything else
  1031. Author: swilson
  1032. --*/
  1033. BOOL
  1034. MyUNCName(
  1035. LPWSTR pNameStart
  1036. )
  1037. {
  1038. PWCHAR pMachine = szMachineName;
  1039. LPWSTR pName;
  1040. DWORD i;
  1041. extern LPWSTR *ppszOtherNames; // Contains szMachineName, DNS name, and all other machine name forms
  1042. extern DWORD cOtherNames;
  1043. if (!pNameStart || !*pNameStart) // This differs from MyName(), which returns TRUE
  1044. return FALSE;
  1045. if (*pNameStart == L'\\' && *(pNameStart + 1) == L'\\') {
  1046. for (i = 0 , pName = pNameStart + 2 ; i < cOtherNames ; ++i , pName = pNameStart + 2) {
  1047. for(pMachine = ppszOtherNames[i] ;
  1048. *pName && towupper(*pName) == towupper(*pMachine) ;
  1049. ++pName, ++pMachine)
  1050. ;
  1051. if(!*pMachine && (!*pName || *pName == L'\\'))
  1052. return TRUE;
  1053. }
  1054. }
  1055. return FALSE;
  1056. }
  1057. BOOL
  1058. SplIsUpgrade(
  1059. VOID
  1060. )
  1061. {
  1062. return dwUpgradeFlag;
  1063. }
  1064. PWSTR
  1065. AutoCat(
  1066. PCWSTR pszInput,
  1067. PCWSTR pszCat
  1068. )
  1069. {
  1070. PWSTR pszOut;
  1071. if (!pszCat) {
  1072. pszOut = AllocSplStr(pszInput);
  1073. } else if (pszInput) {
  1074. pszOut = AllocSplMem((wcslen(pszInput) + wcslen(pszCat) + 1)*sizeof(WCHAR));
  1075. if (pszOut) {
  1076. wcscpy(pszOut, pszInput);
  1077. wcscat(pszOut, pszCat);
  1078. }
  1079. } else {
  1080. pszOut = AllocSplStr(pszCat);
  1081. }
  1082. return pszOut;
  1083. }
  1084. PBIDI_RESPONSE_CONTAINER
  1085. RouterAllocBidiResponseContainer(
  1086. DWORD Count
  1087. )
  1088. {
  1089. DWORD MemSize = 0;
  1090. //
  1091. // Add the size of the container - the size of the first data element
  1092. //
  1093. MemSize += (sizeof(BIDI_RESPONSE_CONTAINER) - sizeof(BIDI_RESPONSE_DATA));
  1094. //
  1095. // Add the size of all the returned RESPONSE_DATA elements
  1096. //
  1097. MemSize += (Count * sizeof(BIDI_RESPONSE_DATA));
  1098. return((PBIDI_RESPONSE_CONTAINER) MIDL_user_allocate(MemSize));
  1099. }
  1100. /*++
  1101. Routine Name
  1102. GetAPDPolicy
  1103. Routine Description:
  1104. This function reads a DWORD value from the location
  1105. HKEY\pszRelPath\pszValueName. We use this function for
  1106. preserving the AddPrinterDrivers policy value when the
  1107. LanMan Print Services print provider is deleted from
  1108. the system.
  1109. Arguments:
  1110. hKey - key tree
  1111. pszRelPath - relative path of the value to be get
  1112. pszValueName - value name
  1113. pValue - pointer to memory to store a dword value
  1114. Return Value:
  1115. ERROR_SUCCESS - the value was retrieved
  1116. Win32 error code - an error occured
  1117. --*/
  1118. DWORD
  1119. GetAPDPolicy(
  1120. IN HKEY hKey,
  1121. IN LPCWSTR pszRelPath,
  1122. IN LPCWSTR pszValueName,
  1123. IN LPDWORD pValue
  1124. )
  1125. {
  1126. DWORD Error = ERROR_INVALID_PARAMETER;
  1127. if (hKey && pszRelPath && pszValueName && pValue)
  1128. {
  1129. HKEY hRelKey = NULL;
  1130. *pValue = 0;
  1131. //
  1132. // Check if we have a value in the new location already
  1133. //
  1134. if ((Error = RegOpenKeyEx(hKey,
  1135. pszRelPath,
  1136. 0,
  1137. KEY_READ,
  1138. &hRelKey)) == ERROR_SUCCESS)
  1139. {
  1140. DWORD cbData = sizeof(DWORD);
  1141. Error = RegQueryValueEx(hRelKey,
  1142. pszValueName,
  1143. NULL,
  1144. NULL,
  1145. (LPBYTE)pValue,
  1146. &cbData);
  1147. RegCloseKey(hRelKey);
  1148. }
  1149. }
  1150. return Error;
  1151. }
  1152. /*++
  1153. Routine Name
  1154. SetAPDPolicy
  1155. Routine Description:
  1156. This function writes a DWORD value to the location
  1157. HKEY\pszRelPath\pszValueName. We use this function for
  1158. preserving the AddPrinterDrivers policy value when the
  1159. LanMan Print Services print provider is deleted from
  1160. the system.
  1161. Arguments:
  1162. hKey - key tree
  1163. pszRelPath - relative path of the value to be set
  1164. pszValueName - value name to be set
  1165. Value - dword value to be set
  1166. Return Value:
  1167. ERROR_SUCCESS - the value was set sucessfully
  1168. Win32 error code - an error occured and the value was not set
  1169. --*/
  1170. DWORD
  1171. SetAPDPolicy(
  1172. IN HKEY hKey,
  1173. IN LPCWSTR pszRelPath,
  1174. IN LPCWSTR pszValueName,
  1175. IN DWORD Value
  1176. )
  1177. {
  1178. DWORD Error = ERROR_INVALID_PARAMETER;
  1179. if (hKey && pszRelPath && pszValueName)
  1180. {
  1181. HKEY hRelKey = NULL;
  1182. //
  1183. // Check if we have a value in the new location already
  1184. //
  1185. if ((Error = RegCreateKeyEx(hKey,
  1186. pszRelPath,
  1187. 0,
  1188. NULL,
  1189. 0,
  1190. KEY_ALL_ACCESS,
  1191. NULL,
  1192. &hRelKey,
  1193. NULL)) == ERROR_SUCCESS)
  1194. {
  1195. Error = RegSetValueEx(hRelKey,
  1196. pszValueName,
  1197. 0,
  1198. REG_DWORD,
  1199. (LPBYTE)&Value,
  1200. sizeof(DWORD));
  1201. RegCloseKey(hRelKey);
  1202. }
  1203. }
  1204. return Error;
  1205. }