|
|
1.1 ! root 1: #include <windows.h> ! 2: #include <winspool.h> ! 3: #include <winsplp.h> ! 4: #include <stdio.h> ! 5: #include <string.h> ! 6: #include <stdlib.h> ! 7: #include <wchar.h> ! 8: #include "spltypes.h" ! 9: #include "local.h" ! 10: #include "dialogs.h" ! 11: ! 12: ! 13: /* Definitions for MonitorThread: ! 14: */ ! 15: #define TRANSMISSION_DATA_SIZE 100 ! 16: ! 17: typedef struct _TRANSMISSION ! 18: { ! 19: HANDLE hPipe; ! 20: WCHAR Data[TRANSMISSION_DATA_SIZE]; ! 21: LPOVERLAPPED pOverlapped; ! 22: INT PipeInstance; ! 23: HANDLE hPrinter; ! 24: DWORD JobId; ! 25: HANDLE hFile; ! 26: PINIPORT pIniPort; ! 27: } ! 28: TRANSMISSION, *PTRANSMISSION; ! 29: ! 30: extern WCHAR szWindows[]; ! 31: extern WCHAR szINIKey_TransmissionRetryTimeout[]; ! 32: WCHAR *Network = L"Net:"; ! 33: ! 34: BOOL ! 35: CreateMonitorThread( ! 36: PINIPORT pIniPort ! 37: ); ! 38: ! 39: VOID ! 40: CompleteRead( ! 41: DWORD Error, ! 42: DWORD ByteCount, ! 43: LPOVERLAPPED pOverlapped ! 44: ); ! 45: ! 46: PSECURITY_DESCRIPTOR ! 47: CreateNamedPipeSecurityDescriptor( ! 48: VOID ! 49: ); ! 50: ! 51: BOOL ! 52: BuildPrintObjectProtection( ! 53: IN ULONG AceCount, ! 54: IN PSID *AceSid, ! 55: IN ACCESS_MASK *AceMask, ! 56: IN BYTE *InheritFlags, ! 57: IN PSID WorldSid, ! 58: IN PGENERIC_MAPPING GenericMap, ! 59: OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor ! 60: ); ! 61: ! 62: BOOL ! 63: PortExists( ! 64: LPWSTR pName, ! 65: LPWSTR pPortName, ! 66: PDWORD pError ! 67: ); ! 68: ! 69: #define offsetof(type, identifier) (DWORD)(&(((type)0)->identifier)) ! 70: ! 71: #if DBG ! 72: DWORD GLOBAL_DEBUG_FLAGS = DBG_ERROR | DBG_WARNING; ! 73: #endif ! 74: ! 75: HANDLE hInst; ! 76: ! 77: DWORD PortInfo1Offsets[]={offsetof(LPPORT_INFO_1, pName), ! 78: (DWORD)-1}; ! 79: ! 80: WCHAR szPorts[] = L"ports"; ! 81: WCHAR szPortsEx[] = L"portsex"; /* Extra ports values */ ! 82: WCHAR szFILE[] = L"FILE:"; ! 83: WCHAR szCOM[] = L"COM"; ! 84: WCHAR szLPT[] = L"LPT"; ! 85: ! 86: /* These globals are needed so that AddPort can call ! 87: * SPOOLSS!EnumPorts to see whether the port to be added ! 88: * already exists. ! 89: * They will be initialized the first time AddPort is called. ! 90: */ ! 91: HMODULE hSpoolssDll = NULL; ! 92: FARPROC pfnSpoolssEnumPorts = NULL; ! 93: ! 94: #define IS_FILE_PORT(pName) \ ! 95: !wcsicmp( pName, szFILE ) ! 96: ! 97: #define IS_COM_PORT(pName) \ ! 98: !wcsnicmp( pName, szCOM, 3 ) ! 99: ! 100: #define IS_LPT_PORT(pName) \ ! 101: !wcsnicmp( pName, szLPT, 3 ) ! 102: ! 103: #define IS_NOT_LOCAL_PORT(pName, pLocalMonitorName) \ ! 104: wcsicmp( pName, pLocalMonitorName ) ! 105: ! 106: ! 107: LPWSTR ! 108: GetPortName( ! 109: HWND hWnd ! 110: ); ! 111: VOID ! 112: ConfigCOMPort( ! 113: HWND hWnd ! 114: ); ! 115: BOOL ! 116: ConfigLPTPort( ! 117: HWND hWnd ! 118: ); ! 119: ! 120: ! 121: PINIPORT pIniFirstPort; ! 122: CRITICAL_SECTION SpoolerSection; ! 123: ! 124: VOID ! 125: RemoveColon( ! 126: LPWSTR pName ! 127: ) ! 128: { ! 129: DWORD Length; ! 130: ! 131: // Remove that damm trailing colon ! 132: ! 133: Length = wcslen(pName); ! 134: ! 135: if (pName[Length-1] == L':') ! 136: pName[Length-1] = 0; ! 137: ! 138: } ! 139: ! 140: BOOL ! 141: LibMain( ! 142: HANDLE hModule, ! 143: DWORD dwReason, ! 144: LPVOID lpRes ! 145: ) ! 146: { ! 147: if (dwReason != DLL_PROCESS_ATTACH) ! 148: return TRUE; ! 149: ! 150: hInst = hModule; ! 151: ! 152: return TRUE; ! 153: ! 154: UNREFERENCED_PARAMETER( lpRes ); ! 155: } ! 156: ! 157: ! 158: PINIPORT ! 159: CreatePortEntry( ! 160: LPWSTR pPortName ! 161: ) ! 162: { ! 163: DWORD cb; ! 164: PINIPORT pIniPort, pPort; ! 165: ! 166: if (!lstrcmpi(pPortName, Network)) ! 167: return FALSE; ! 168: ! 169: cb = sizeof(INIPORT) + wcslen(pPortName)*sizeof(WCHAR) + sizeof(WCHAR); ! 170: ! 171: EnterSplSem( ); ! 172: ! 173: pIniPort=AllocSplMem(cb); ! 174: ! 175: LeaveSplSem( ); ! 176: ! 177: if( pIniPort ) ! 178: { ! 179: pIniPort->pName = wcscpy((LPWSTR)(pIniPort+1), pPortName); ! 180: pIniPort->cb = cb; ! 181: pIniPort->pNext = 0; ! 182: pIniPort->signature = IPO_SIGNATURE; ! 183: ! 184: if (pPort = pIniFirstPort) { ! 185: ! 186: while (pPort->pNext) ! 187: pPort = pPort->pNext; ! 188: ! 189: pPort->pNext = pIniPort; ! 190: ! 191: } else ! 192: ! 193: pIniFirstPort = pIniPort; ! 194: } ! 195: ! 196: return pIniPort; ! 197: } ! 198: ! 199: ! 200: BOOL ! 201: DeletePortEntry( ! 202: LPWSTR pPortName ! 203: ) ! 204: { ! 205: DWORD cb; ! 206: PINIPORT pPort, pPrevPort; ! 207: ! 208: cb = sizeof(INIPORT) + wcslen(pPortName)*sizeof(WCHAR) + sizeof(WCHAR); ! 209: ! 210: pPort = pIniFirstPort; ! 211: while (pPort && lstrcmpi(pPort->pName, pPortName)) { ! 212: pPrevPort = pPort; ! 213: pPort = pPort->pNext; ! 214: } ! 215: ! 216: if (pPort) { ! 217: if (pPort == pIniFirstPort) { ! 218: pIniFirstPort = pPort->pNext; ! 219: } else { ! 220: pPrevPort->pNext = pPort->pNext; ! 221: } ! 222: FreeSplMem (pPort, cb); ! 223: ! 224: return TRUE; ! 225: } ! 226: else ! 227: return FALSE; ! 228: } ! 229: ! 230: ! 231: BOOL ! 232: InitializeMonitor( ! 233: LPWSTR pRegistryRoot ! 234: ) ! 235: { ! 236: LPWSTR pPorts, pFirstPort; ! 237: DWORD cbAlloc=4096; ! 238: ! 239: InitializeCriticalSection(&SpoolerSection); ! 240: ! 241: EnterSplSem(); ! 242: ! 243: if (!(pPorts=AllocSplMem(cbAlloc))) { ! 244: ! 245: DBGMSG(DBG_ERROR, ("Failed to alloc %d bytes for ports.", cbAlloc)); ! 246: return FALSE; ! 247: } ! 248: ! 249: GetProfileString(szPorts, NULL, L"", pPorts, cbAlloc); ! 250: ! 251: pFirstPort=pPorts; // Remember the beginning so we can free it later ! 252: ! 253: // We now have all the ports ! 254: ! 255: while (*pPorts) { ! 256: ! 257: CreatePortEntry(pPorts); ! 258: ! 259: pPorts+=wcslen(pPorts)+1; ! 260: } ! 261: ! 262: FreeSplMem(pFirstPort, cbAlloc); ! 263: ! 264: LeaveSplSem(); ! 265: ! 266: return TRUE; ! 267: } ! 268: ! 269: DWORD ! 270: GetPortSize( ! 271: PINIPORT pIniPort, ! 272: DWORD Level ! 273: ) ! 274: { ! 275: DWORD cb; ! 276: ! 277: switch (Level) { ! 278: ! 279: case 1: ! 280: ! 281: cb=sizeof(PORT_INFO_1) + ! 282: wcslen(pIniPort->pName)*sizeof(WCHAR) + sizeof(WCHAR); ! 283: break; ! 284: ! 285: default: ! 286: cb = 0; ! 287: break; ! 288: } ! 289: ! 290: return cb; ! 291: } ! 292: ! 293: // We are being a bit naughty here as we are not sure exactly how much ! 294: // memory to allocate for the source strings. We will just assume that ! 295: // PORT_INFO_2 is the biggest structure around for the moment. ! 296: ! 297: LPBYTE ! 298: CopyIniPortToPort( ! 299: PINIPORT pIniPort, ! 300: DWORD Level, ! 301: LPBYTE pPortInfo, ! 302: LPBYTE pEnd ! 303: ) ! 304: { ! 305: LPWSTR SourceStrings[sizeof(PORT_INFO_1)/sizeof(LPWSTR)]; ! 306: LPWSTR *pSourceStrings=SourceStrings; ! 307: PPORT_INFO_1 pPort1 = (PPORT_INFO_1)pPortInfo; ! 308: DWORD *pOffsets; ! 309: ! 310: switch (Level) { ! 311: ! 312: case 1: ! 313: pOffsets = PortInfo1Offsets; ! 314: break; ! 315: ! 316: default: ! 317: return pEnd; ! 318: } ! 319: ! 320: switch (Level) { ! 321: ! 322: case 1: ! 323: *pSourceStrings++=pIniPort->pName; ! 324: ! 325: pEnd = PackStrings(SourceStrings, pPortInfo, pOffsets, pEnd); ! 326: ! 327: break; ! 328: ! 329: default: ! 330: return pEnd; ! 331: } ! 332: ! 333: return pEnd; ! 334: } ! 335: ! 336: BOOL ! 337: EnumPorts( ! 338: LPWSTR pName, ! 339: DWORD Level, ! 340: LPBYTE pPorts, ! 341: DWORD cbBuf, ! 342: LPDWORD pcbNeeded, ! 343: LPDWORD pcReturned ! 344: ) ! 345: { ! 346: PINIPORT pIniPort; ! 347: DWORD cb; ! 348: LPBYTE pEnd; ! 349: DWORD LastError=0; ! 350: ! 351: EnterSplSem(); ! 352: ! 353: cb=0; ! 354: ! 355: pIniPort=pIniFirstPort; ! 356: ! 357: while (pIniPort) { ! 358: cb+=GetPortSize(pIniPort, Level); ! 359: pIniPort=pIniPort->pNext; ! 360: } ! 361: ! 362: *pcbNeeded=cb; ! 363: ! 364: if (cb <= cbBuf) { ! 365: ! 366: pEnd=pPorts+cbBuf; ! 367: *pcReturned=0; ! 368: ! 369: pIniPort=pIniFirstPort; ! 370: while (pIniPort) { ! 371: pEnd = CopyIniPortToPort(pIniPort, Level, pPorts, pEnd); ! 372: switch (Level) { ! 373: case 1: ! 374: pPorts+=sizeof(PORT_INFO_1); ! 375: break; ! 376: } ! 377: pIniPort=pIniPort->pNext; ! 378: (*pcReturned)++; ! 379: } ! 380: ! 381: } else ! 382: ! 383: LastError = ERROR_INSUFFICIENT_BUFFER; ! 384: ! 385: LeaveSplSem(); ! 386: ! 387: if (LastError) { ! 388: ! 389: SetLastError(LastError); ! 390: return FALSE; ! 391: ! 392: } else ! 393: ! 394: return TRUE; ! 395: } ! 396: ! 397: #define NEXTVAL(pch) \ ! 398: while( *pch && ( *pch != L',' ) ) \ ! 399: pch++; \ ! 400: if( *pch ) \ ! 401: pch++ ! 402: ! 403: ! 404: BOOL ! 405: GetIniCommValues( ! 406: LPWSTR pName, ! 407: LPDCB pdcb, ! 408: LPCOMMTIMEOUTS pcto ! 409: ) ! 410: { ! 411: WCHAR IniEntry[20]; ! 412: ! 413: *IniEntry = L'\0'; ! 414: ! 415: GetProfileString( szPorts, pName, L"", IniEntry, sizeof IniEntry ); ! 416: ! 417: BuildCommDCB(IniEntry, pdcb); ! 418: ! 419: pcto->WriteTotalTimeoutConstant = GetProfileInt(szWindows, ! 420: szINIKey_TransmissionRetryTimeout, ! 421: 45 ); ! 422: pcto->WriteTotalTimeoutConstant*=1000; ! 423: return TRUE; ! 424: } ! 425: ! 426: ! 427: BOOL ! 428: OpenPort( ! 429: LPWSTR pName, ! 430: PHANDLE pHandle ! 431: ) ! 432: { ! 433: PINIPORT pIniPort; ! 434: ! 435: EnterSplSem(); ! 436: pIniPort = FindPort(pName); ! 437: ! 438: if (pIniPort) { ! 439: ! 440: *pHandle = pIniPort; ! 441: ! 442: CreateMonitorThread(pIniPort); ! 443: LeaveSplSem(); ! 444: ! 445: return TRUE; ! 446: ! 447: } else { ! 448: ! 449: DBGMSG(DBG_ERROR, ("localmon!OpenPort %s : Failed\n", pName)); ! 450: ! 451: LeaveSplSem(); ! 452: return FALSE; ! 453: } ! 454: } ! 455: ! 456: ! 457: BOOL ! 458: StartDocPort( ! 459: HANDLE hPort, ! 460: LPWSTR pPrinterName, ! 461: DWORD JobId, ! 462: DWORD Level, ! 463: LPBYTE pDocInfo ! 464: ) ! 465: { ! 466: PINIPORT pIniPort = (PINIPORT)hPort; ! 467: LPWSTR pPortName; ! 468: DCB dcb; ! 469: COMMTIMEOUTS cto; ! 470: WCHAR TempDosDeviceName[MAX_PATH]; ! 471: HANDLE hToken; ! 472: ! 473: UNREFERENCED_PARAMETER( Level ); ! 474: UNREFERENCED_PARAMETER( pDocInfo ); ! 475: ! 476: DBGMSG(DBG_TRACE, ("StartDocPort(%08x, %ws, %d, %d, %08x)\n", ! 477: hPort, pPrinterName, JobId, Level, pDocInfo)); ! 478: ! 479: EnterSplSem(); ! 480: pIniPort->pPrinterName = AllocSplStr(pPrinterName); ! 481: LeaveSplSem(); ! 482: ! 483: if (pIniPort->pPrinterName) { ! 484: ! 485: if (OpenPrinter(pPrinterName, &pIniPort->hPrinter, NULL)) { ! 486: ! 487: pIniPort->JobId = JobId; ! 488: ! 489: pPortName = pIniPort->pName; ! 490: ! 491: if (!IS_FILE_PORT (pPortName)) { ! 492: ! 493: LPWSTR pName; ! 494: ! 495: if (pIniPort->Status & PP_MONITORRUNNING) { ! 496: ! 497: WCHAR DeviceNames[MAX_PATH]; ! 498: WCHAR DosDeviceName[MAX_PATH]; ! 499: WCHAR *pDeviceNames=DeviceNames; ! 500: ! 501: wcscpy(DosDeviceName, pIniPort->pName); ! 502: RemoveColon(DosDeviceName); ! 503: ! 504: hToken = RevertToPrinterSelf(); ! 505: ! 506: QueryDosDevice(DosDeviceName, ! 507: DeviceNames, ! 508: sizeof(DeviceNames)); ! 509: ! 510: if (!lstrcmpi(pDeviceNames, pIniPort->pNewDeviceName)) { ! 511: ! 512: pDeviceNames+=wcslen(pDeviceNames)+1; ! 513: } ! 514: ! 515: wcscpy(TempDosDeviceName, L"NONSPOOLED_"); ! 516: wcscat(TempDosDeviceName, pIniPort->pName); ! 517: RemoveColon(TempDosDeviceName); ! 518: ! 519: DefineDosDevice(DDD_RAW_TARGET_PATH, TempDosDeviceName, pDeviceNames); ! 520: ! 521: ImpersonatePrinterClient(hToken); ! 522: ! 523: wcscpy(TempDosDeviceName, L"\\\\.\\NONSPOOLED_"); ! 524: wcscat(TempDosDeviceName, pIniPort->pName); ! 525: RemoveColon(TempDosDeviceName); ! 526: ! 527: pName = TempDosDeviceName; ! 528: ! 529: } else ! 530: pName = pIniPort->pName; ! 531: ! 532: pIniPort->hFile = CreateFile(pName, GENERIC_WRITE, ! 533: FILE_SHARE_READ, NULL, OPEN_ALWAYS, ! 534: FILE_ATTRIBUTE_NORMAL | ! 535: FILE_FLAG_SEQUENTIAL_SCAN, NULL); ! 536: ! 537: if (pIniPort->hFile == INVALID_HANDLE_VALUE) { ! 538: ! 539: if (pIniPort->Status & PP_MONITORRUNNING) { ! 540: ! 541: wcscpy(TempDosDeviceName, L"NONSPOOLED_"); ! 542: wcscat(TempDosDeviceName, pIniPort->pName); ! 543: RemoveColon(TempDosDeviceName); ! 544: ! 545: DefineDosDevice(DDD_REMOVE_DEFINITION, TempDosDeviceName, NULL); ! 546: } ! 547: EnterSplSem(); ! 548: FreeSplStr(pIniPort->pPrinterName); ! 549: LeaveSplSem(); ! 550: return FALSE; ! 551: } ! 552: ! 553: SetEndOfFile(pIniPort->hFile); ! 554: ! 555: if (IS_COM_PORT (pPortName)) { ! 556: ! 557: if (GetCommState (pIniPort->hFile, &dcb)) { ! 558: ! 559: GetCommTimeouts(pIniPort->hFile, &cto); ! 560: GetIniCommValues (pPortName, &dcb, &cto); ! 561: SetCommState (pIniPort->hFile, &dcb); ! 562: SetCommTimeouts(pIniPort->hFile, &cto); ! 563: ! 564: } else { ! 565: ! 566: DBGMSG( DBG_ERROR, ("ERROR: Failed to set Comm State") ); ! 567: } ! 568: } ! 569: ! 570: else if (IS_LPT_PORT (pPortName)) { ! 571: ! 572: if (GetCommTimeouts(pIniPort->hFile, &cto)) { ! 573: cto.WriteTotalTimeoutConstant = GetProfileInt(szWindows, ! 574: szINIKey_TransmissionRetryTimeout, ! 575: 45 ); ! 576: cto.WriteTotalTimeoutConstant*=1000; ! 577: SetCommTimeouts(pIniPort->hFile, &cto); ! 578: ! 579: } else { ! 580: ! 581: DBGMSG( DBG_ERROR, ("ERROR: Failed to set Comm State") ); ! 582: } ! 583: } ! 584: ! 585: } else { ! 586: ! 587: HANDLE hToken; ! 588: int rc; ! 589: HANDLE hFile; ! 590: ! 591: hToken = RevertToPrinterSelf(); ! 592: ! 593: ! 594: rc = DialogBoxParam( hInst, ! 595: MAKEINTRESOURCE( DLG_PRINTTOFILE ), ! 596: NULL, (DLGPROC)PrintToFileDlg, ! 597: (LPARAM)&hFile ); ! 598: ! 599: ImpersonatePrinterClient(hToken); ! 600: ! 601: if( rc == -1 ) { ! 602: ! 603: EnterSplSem(); ! 604: FreeSplStr(pIniPort->pPrinterName); ! 605: LeaveSplSem(); ! 606: return FALSE; ! 607: ! 608: } else if( rc == 0 ) { ! 609: ! 610: EnterSplSem(); ! 611: FreeSplStr(pIniPort->pPrinterName); ! 612: LeaveSplSem(); ! 613: SetLastError(ERROR_PRINT_CANCELLED); ! 614: return FALSE; ! 615: ! 616: } else { ! 617: ! 618: pIniPort->hFile = hFile; ! 619: } ! 620: ! 621: SetEndOfFile(pIniPort->hFile); ! 622: } ! 623: ! 624: } else { ! 625: EnterSplSem( ); ! 626: FreeSplStr(pIniPort->pPrinterName); ! 627: LeaveSplSem( ); ! 628: } ! 629: } ! 630: ! 631: if (pIniPort->hFile == INVALID_HANDLE_VALUE) { ! 632: DBGMSG(DBG_ERROR, ("StartDocPort FAILED %x\n", GetLastError())); ! 633: if (pIniPort->pPrinterName) { ! 634: EnterSplSem(); ! 635: FreeSplStr(pIniPort->pPrinterName); ! 636: LeaveSplSem(); ! 637: } ! 638: return FALSE; ! 639: } else { ! 640: return TRUE; ! 641: } ! 642: } ! 643: ! 644: BOOL ! 645: ReadPort( ! 646: HANDLE hPort, ! 647: LPBYTE pBuffer, ! 648: DWORD cbBuf, ! 649: LPDWORD pcbRead ! 650: ) ! 651: { ! 652: PINIPORT pIniPort = (PINIPORT)hPort; ! 653: BOOL rc; ! 654: ! 655: DBGMSG(DBG_TRACE, ("ReadPort(%08x, %08x, %d)\n", hPort, pBuffer, cbBuf)); ! 656: ! 657: rc = ReadFile(pIniPort->hFile, pBuffer, cbBuf, pcbRead, NULL); ! 658: ! 659: DBGMSG(DBG_TRACE, ("ReadPort returns %d; %d bytes read\n", rc, *pcbRead)); ! 660: ! 661: return rc; ! 662: } ! 663: ! 664: BOOL ! 665: WritePort( ! 666: HANDLE hPort, ! 667: LPBYTE pBuffer, ! 668: DWORD cbBuf, ! 669: LPDWORD pcbWritten ! 670: ) ! 671: { ! 672: PINIPORT pIniPort = (PINIPORT)hPort; ! 673: BOOL rc; ! 674: ! 675: DBGMSG(DBG_TRACE, ("WritePort(%08x, %08x, %d)\n", hPort, pBuffer, cbBuf)); ! 676: ! 677: rc = WriteFile(pIniPort->hFile, pBuffer, cbBuf, pcbWritten, NULL); ! 678: ! 679: DBGMSG(DBG_TRACE, ("WritePort returns %d; %d bytes written\n", rc, *pcbWritten)); ! 680: ! 681: return rc; ! 682: } ! 683: ! 684: BOOL ! 685: EndDocPort( ! 686: HANDLE hPort ! 687: ) ! 688: { ! 689: PINIPORT pIniPort = (PINIPORT)hPort; ! 690: WCHAR TempDosDeviceName[MAX_PATH]; ! 691: ! 692: DBGMSG(DBG_TRACE, ("EndDocPort(%08x)\n", hPort)); ! 693: ! 694: CloseHandle(pIniPort->hFile); ! 695: ! 696: SetJob(pIniPort->hPrinter, pIniPort->JobId, 0, NULL, JOB_CONTROL_CANCEL); ! 697: ! 698: ClosePrinter(pIniPort->hPrinter); ! 699: ! 700: EnterSplSem(); ! 701: ! 702: if (pIniPort->Status & PP_MONITORRUNNING) { ! 703: ! 704: wcscpy(TempDosDeviceName, L"NONSPOOLED_"); ! 705: wcscat(TempDosDeviceName, pIniPort->pName); ! 706: RemoveColon(TempDosDeviceName); ! 707: ! 708: DefineDosDevice(DDD_REMOVE_DEFINITION, TempDosDeviceName, NULL); ! 709: } ! 710: ! 711: FreeSplStr(pIniPort->pPrinterName); ! 712: ! 713: LeaveSplSem(); ! 714: ! 715: return TRUE; ! 716: } ! 717: ! 718: BOOL ! 719: ClosePort( ! 720: HANDLE hPort ! 721: ) ! 722: { ! 723: PINIPORT pIniPort = (PINIPORT)hPort; ! 724: ! 725: // Now destroy the monitor ! 726: ! 727: if (pIniPort->Status & PP_MONITORRUNNING) { ! 728: pIniPort->Status &= ~PP_MONITORRUNNING; ! 729: pIniPort->Status &= ~PP_RUNMONITOR; ! 730: SetEvent(pIniPort->Semaphore); ! 731: } ! 732: ! 733: return TRUE; ! 734: } ! 735: ! 736: BOOL ! 737: DeletePort( ! 738: LPWSTR pName, ! 739: HWND hWnd, ! 740: LPWSTR pPortName ! 741: ) ! 742: { ! 743: BOOL rc; ! 744: ! 745: if( !hWnd ) ! 746: hWnd == GetDesktopWindow( ); ! 747: ! 748: EnterSplSem(); ! 749: ! 750: if (rc = DeletePortEntry( pPortName )) ! 751: WriteProfileString(szPorts, pPortName, NULL); ! 752: ! 753: LeaveSplSem(); ! 754: ! 755: return rc; ! 756: ! 757: UNREFERENCED_PARAMETER( pName ); ! 758: } ! 759: ! 760: BOOL ! 761: AddPort( ! 762: LPWSTR pName, ! 763: HWND hWnd, ! 764: LPWSTR pMonitorName ! 765: ) ! 766: { ! 767: LPWSTR pPortName; ! 768: DWORD ThreadId; ! 769: DWORD WindowThreadId; ! 770: BOOL rc = TRUE; ! 771: DWORD Error; ! 772: BOOL DoAddPort = TRUE; ! 773: WCHAR szLocalMonitor[MAX_PATH+1]; ! 774: ! 775: ! 776: LoadString(hInst, IDS_LOCALMONITOR, szLocalMonitor, MAX_PATH); ! 777: if (IS_NOT_LOCAL_PORT( pMonitorName, szLocalMonitor)) { ! 778: ! 779: // If pMonitorName != "Local Port", we have an ! 780: // invalid Monitor name ! 781: SetLastError(ERROR_INVALID_PARAMETER); ! 782: return(FALSE); ! 783: } ! 784: ! 785: ThreadId = GetCurrentThreadId( ); ! 786: WindowThreadId = GetWindowThreadProcessId(hWnd, NULL); ! 787: ! 788: if (!AttachThreadInput(ThreadId, WindowThreadId, TRUE)) ! 789: DBGMSG(DBG_WARNING, ("AttachThreadInput failed: Error %d\n", GetLastError())); ! 790: ! 791: /* Get the user to enter a port name: ! 792: */ ! 793: pPortName = GetPortName( hWnd ); ! 794: ! 795: if( pPortName ) ! 796: { ! 797: if( PortExists( pName, pPortName, &Error ) ) ! 798: { ! 799: Message( hWnd, MSG_ERROR, IDS_LOCALMONITOR, ! 800: IDS_PORTALREADYEXISTS_S, pPortName ); ! 801: ! 802: DoAddPort = FALSE; ! 803: ! 804: /* In this case, the error was handled, and the user was ! 805: * notified with a message box, so we return true to ensure ! 806: * that the caller doesn't have to do so too. ! 807: */ ! 808: rc = TRUE; ! 809: } ! 810: ! 811: else if( Error != NO_ERROR ) ! 812: { ! 813: DBGMSG(DBG_ERROR, ("Error %d occurred checking whether port exists\n", ! 814: Error)); ! 815: DoAddPort = FALSE; ! 816: rc = FALSE; ! 817: } ! 818: ! 819: if( DoAddPort ) ! 820: { ! 821: /* Now, let's see if it's a COM port: ! 822: */ ! 823: if( IS_COM_PORT( pPortName ) ) ! 824: ! 825: ConfigCOMPort( hWnd ); ! 826: ! 827: else ! 828: /* No, well maybe it's an LPT? ! 829: */ ! 830: if( IS_LPT_PORT( pPortName ) ) ! 831: ! 832: ConfigLPTPort( hWnd ); ! 833: ! 834: ! 835: if( CreatePortEntry( pPortName ) ) { ! 836: if (!WriteProfileString(szPorts, pPortName, L"")) { ! 837: DeletePortEntry(pPortName); ! 838: rc = FALSE; ! 839: } ! 840: } ! 841: else ! 842: rc = FALSE; ! 843: } ! 844: ! 845: } ! 846: ! 847: AttachThreadInput(WindowThreadId, ThreadId, FALSE); ! 848: ! 849: return rc; ! 850: } ! 851: ! 852: ! 853: /* PortExists ! 854: * ! 855: * Calls EnumPorts to check whether the port name already exists. ! 856: * This asks every monitor, rather than just this one. ! 857: * The function will return TRUE if the specified port is in the list. ! 858: * If an error occurs, the return is FALSE and the variable pointed ! 859: * to by pError contains the return from GetLastError(). ! 860: * The caller must therefore always check that *pError == NO_ERROR. ! 861: */ ! 862: BOOL ! 863: PortExists( ! 864: LPWSTR pName, ! 865: LPWSTR pPortName, ! 866: PDWORD pError ! 867: ) ! 868: { ! 869: DWORD cbNeeded; ! 870: DWORD cReturned; ! 871: DWORD cbPorts; ! 872: LPPORT_INFO_1 pPorts; ! 873: DWORD i; ! 874: BOOL Found = TRUE; ! 875: ! 876: *pError = NO_ERROR; ! 877: ! 878: if (!hSpoolssDll) { ! 879: ! 880: hSpoolssDll = LoadLibrary(L"SPOOLSS.DLL"); ! 881: ! 882: if (hSpoolssDll) { ! 883: pfnSpoolssEnumPorts = GetProcAddress(hSpoolssDll, ! 884: "EnumPortsW"); ! 885: if (!pfnSpoolssEnumPorts) { ! 886: ! 887: *pError = GetLastError(); ! 888: FreeLibrary(hSpoolssDll); ! 889: hSpoolssDll = NULL; ! 890: } ! 891: ! 892: } else { ! 893: ! 894: *pError = GetLastError(); ! 895: } ! 896: } ! 897: ! 898: if (!pfnSpoolssEnumPorts) ! 899: return FALSE; ! 900: ! 901: ! 902: if (!(*pfnSpoolssEnumPorts)(pName, 1, NULL, 0, &cbNeeded, &cReturned)) ! 903: { ! 904: if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) ! 905: { ! 906: cbPorts = cbNeeded; ! 907: ! 908: EnterSplSem(); ! 909: pPorts = AllocSplMem(cbPorts); ! 910: LeaveSplSem(); ! 911: ! 912: if (pPorts) ! 913: { ! 914: if ((*pfnSpoolssEnumPorts)(pName, 1, (LPBYTE)pPorts, cbPorts, ! 915: &cbNeeded, &cReturned)) ! 916: { ! 917: Found = FALSE; ! 918: ! 919: for (i = 0; i < cReturned; i++) ! 920: { ! 921: if (!lstrcmpi(pPorts[i].pName, pPortName)) ! 922: Found = TRUE; ! 923: } ! 924: } ! 925: } ! 926: ! 927: EnterSplSem(); ! 928: FreeSplMem(pPorts, cbPorts); ! 929: LeaveSplSem(); ! 930: } ! 931: } ! 932: ! 933: else ! 934: Found = FALSE; ! 935: ! 936: ! 937: return Found; ! 938: } ! 939: ! 940: ! 941: ! 942: /* ConfigurePort ! 943: * ! 944: */ ! 945: BOOL ! 946: ConfigurePort( ! 947: LPWSTR pName, ! 948: HWND hWnd, ! 949: LPWSTR pPortName ! 950: ) ! 951: { ! 952: DWORD ThreadId; ! 953: DWORD WindowThreadId; ! 954: ! 955: ThreadId = GetCurrentThreadId( ); ! 956: WindowThreadId = GetWindowThreadProcessId(hWnd, NULL); ! 957: ! 958: if (!AttachThreadInput(ThreadId, WindowThreadId, TRUE)) ! 959: DBGMSG(DBG_WARNING, ("AttachThreadInput failed: Error %d\n", GetLastError())); ! 960: ! 961: if( IS_COM_PORT( pPortName ) ) ! 962: ! 963: ConfigCOMPort( hWnd ); ! 964: ! 965: else ! 966: /* No, well maybe it's an LPT? ! 967: */ ! 968: if( IS_LPT_PORT( pPortName ) ) ! 969: ! 970: ConfigLPTPort( hWnd ); ! 971: ! 972: else ! 973: Message( hWnd, MSG_INFORMATION, IDS_LOCALMONITOR, ! 974: IDS_NOTHING_TO_CONFIGURE ); ! 975: ! 976: AttachThreadInput(WindowThreadId, ThreadId, FALSE); ! 977: ! 978: return TRUE; ! 979: } ! 980: ! 981: ! 982: /* GetPortName ! 983: * ! 984: * Puts up a dialog containing a free entry field. ! 985: * The dialog allocates a string for the name, if a selection is made. ! 986: */ ! 987: LPWSTR ! 988: GetPortName( ! 989: HWND hWnd ! 990: ) ! 991: { ! 992: LPWSTR pPortName; ! 993: ! 994: if( DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_PORTNAME), hWnd, ! 995: (DLGPROC)PortNameDlg, (LPARAM)&pPortName ) != IDOK ) ! 996: pPortName = NULL; ! 997: ! 998: return pPortName; ! 999: } ! 1000: ! 1001: /* From Control Panel's control.h: ! 1002: */ ! 1003: #define CHILD_PORTS 4 ! 1004: ! 1005: /* From cpl.h: ! 1006: */ ! 1007: #define CPL_INIT 1 ! 1008: #define CPL_DBLCLK 5 ! 1009: #define CPL_EXIT 7 ! 1010: ! 1011: /* Hack: ! 1012: */ ! 1013: #define CHILD_PORTS_HELPID 2 ! 1014: ! 1015: /* ConfigCOMPort ! 1016: * ! 1017: * Calls the Control Panel Ports applet ! 1018: * to permit user to set Baud rate etc. ! 1019: */ ! 1020: typedef void (WINAPI *CFGPROC)(HWND, ULONG, ULONG, ULONG); ! 1021: ! 1022: ! 1023: VOID ! 1024: ConfigCOMPort( ! 1025: HWND hWnd ! 1026: ) ! 1027: { ! 1028: HANDLE hLibrary; ! 1029: CFGPROC pfnCplApplet; ! 1030: ! 1031: if( hLibrary = LoadLibrary( L"MAIN.CPL" ) ) { ! 1032: ! 1033: if( pfnCplApplet = (CFGPROC)GetProcAddress( hLibrary, "CPlApplet" ) ) { ! 1034: (*pfnCplApplet)( hWnd, CPL_INIT, 0, 0 ); ! 1035: (*pfnCplApplet)( hWnd, CPL_DBLCLK, CHILD_PORTS_HELPID, CHILD_PORTS ); ! 1036: (*pfnCplApplet)( hWnd, CPL_EXIT, 0, 0 ); ! 1037: } ! 1038: ! 1039: FreeLibrary( hLibrary ); ! 1040: } ! 1041: } ! 1042: ! 1043: ! 1044: /* ConfigLPTPort ! 1045: * ! 1046: * Calls a dialog box which prompts the user to enter timeout and retry ! 1047: * values for the port concerned. ! 1048: * The dialog writes the information to the registry (win.ini for now). ! 1049: */ ! 1050: BOOL ! 1051: ConfigLPTPort( ! 1052: HWND hWnd ! 1053: ) ! 1054: { ! 1055: DialogBox( hInst, MAKEINTRESOURCE( DLG_CONFIGURE_LPT ), ! 1056: hWnd, (DLGPROC)ConfigureLPTPortDlg ); ! 1057: ! 1058: return TRUE; ! 1059: } ! 1060: ! 1061: VOID ! 1062: MonitorThread( ! 1063: PINIPORT pIniPort ! 1064: ); ! 1065: ! 1066: BOOL ! 1067: CreateMonitorThread( ! 1068: PINIPORT pIniPort ! 1069: ) ! 1070: { ! 1071: if (!(pIniPort->Status & PP_THREADRUNNING)) { ! 1072: ! 1073: pIniPort->Status |= PP_RUNTHREAD; ! 1074: ! 1075: pIniPort->Semaphore=CreateEvent(NULL, FALSE, FALSE, NULL); ! 1076: ! 1077: pIniPort->AccessSem=CreateSemaphore(NULL, 1, 256,NULL); ! 1078: ! 1079: pIniPort->ThreadHandle = CreateThread(NULL, 16*1024, ! 1080: (LPTHREAD_START_ROUTINE)MonitorThread, ! 1081: pIniPort, ! 1082: 0, &pIniPort->ThreadId); ! 1083: ! 1084: pIniPort->Status |= PP_THREADRUNNING; ! 1085: ! 1086: } else { ! 1087: ! 1088: DBGMSG(DBG_ERROR, ("localmon!MonitorThread already running %x\n", ! 1089: pIniPort->Status)); ! 1090: } ! 1091: ! 1092: return TRUE; ! 1093: } ! 1094: ! 1095: #define NUMBER_OF_PIPE_INSTANCES 10 ! 1096: ! 1097: VOID ! 1098: MonitorThread( ! 1099: PINIPORT pIniPort ! 1100: ) ! 1101: { ! 1102: WCHAR NewNtDeviceName[MAX_PATH]; ! 1103: WCHAR OldNtDeviceName[MAX_PATH]; ! 1104: WCHAR DosDeviceName[MAX_PATH]; ! 1105: WCHAR szPipeName[MAX_PATH]; ! 1106: HANDLE hPipe[NUMBER_OF_PIPE_INSTANCES]; ! 1107: HANDLE hEvent[NUMBER_OF_PIPE_INSTANCES+1]; // One extra event for semaphore ! 1108: DWORD WaitResult; ! 1109: DWORD i; ! 1110: DWORD Error; ! 1111: OVERLAPPED OverLapped; ! 1112: OVERLAPPED Overlapped[NUMBER_OF_PIPE_INSTANCES]; ! 1113: LPOVERLAPPED pOverlapped; ! 1114: PTRANSMISSION pTransmission; ! 1115: SECURITY_ATTRIBUTES SecurityAttributes; ! 1116: ! 1117: EnterSplSem(); ! 1118: ! 1119: wcscpy(DosDeviceName, pIniPort->pName); ! 1120: RemoveColon(DosDeviceName); ! 1121: ! 1122: if (!QueryDosDevice(DosDeviceName, OldNtDeviceName, ! 1123: sizeof(OldNtDeviceName)/sizeof(OldNtDeviceName[0]))) { ! 1124: LeaveSplSem(); ! 1125: return; ! 1126: } ! 1127: ! 1128: SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); ! 1129: ! 1130: SecurityAttributes.lpSecurityDescriptor = CreateNamedPipeSecurityDescriptor(); ! 1131: ! 1132: SecurityAttributes.bInheritHandle = FALSE; ! 1133: ! 1134: wcscpy(NewNtDeviceName, L"\\Device\\NamedPipe\\Spooler\\"); ! 1135: wcscat(NewNtDeviceName, pIniPort->pName); ! 1136: RemoveColon(NewNtDeviceName); ! 1137: ! 1138: DefineDosDevice(DDD_RAW_TARGET_PATH, DosDeviceName, NewNtDeviceName); ! 1139: ! 1140: pIniPort->pNewDeviceName = AllocSplStr(NewNtDeviceName); ! 1141: ! 1142: LeaveSplSem(); ! 1143: ! 1144: wsprintf(szPipeName, L"\\\\.\\Pipe\\Spooler\\%ws", pIniPort->pName); ! 1145: RemoveColon(szPipeName); ! 1146: ! 1147: pIniPort->Status |= PP_MONITORRUNNING; ! 1148: ! 1149: memset(&OverLapped, 0, sizeof(OVERLAPPED)); ! 1150: ! 1151: /* Put the semaphore event in the extra member of the event array: ! 1152: */ ! 1153: hEvent[NUMBER_OF_PIPE_INSTANCES] = pIniPort->Semaphore; ! 1154: ! 1155: /* Create several instances of a named pipe, create an event for each, ! 1156: * and connect to wait for a client: ! 1157: */ ! 1158: for( i = 0; i < NUMBER_OF_PIPE_INSTANCES; i++ ) ! 1159: { ! 1160: hPipe[i] = CreateNamedPipe(szPipeName, PIPE_ACCESS_DUPLEX | ! 1161: FILE_FLAG_OVERLAPPED, ! 1162: PIPE_WAIT | PIPE_READMODE_BYTE | ! 1163: PIPE_TYPE_BYTE, ! 1164: PIPE_UNLIMITED_INSTANCES, ! 1165: 4096, ! 1166: 64*1024, // 64k ! 1167: 0, ! 1168: &SecurityAttributes); ! 1169: if( hPipe[i] == (HANDLE)-1 ) ! 1170: { ! 1171: DBGMSG( DBG_ERROR, ( "CreateNamedPipe of %s failed. Error %d\n", ! 1172: szPipeName, GetLastError( ) ) ); ! 1173: pIniPort->Status &= ~PP_THREADRUNNING; ! 1174: return; ! 1175: } ! 1176: ! 1177: hEvent[i] = Overlapped[i].hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); ! 1178: ! 1179: if( !hEvent[i] ) ! 1180: { ! 1181: DBGMSG( DBG_ERROR, ( "CreateEvent failed. Error %d\n", GetLastError( ) ) ); ! 1182: pIniPort->Status &= ~PP_THREADRUNNING; ! 1183: return; ! 1184: } ! 1185: ! 1186: if( !ConnectNamedPipe( hPipe[i], &Overlapped[i] ) ) ! 1187: { ! 1188: Error = GetLastError( ); ! 1189: ! 1190: if( Error == ERROR_IO_PENDING ) ! 1191: { ! 1192: DBGMSG( DBG_INFO, ( "ConnectNamedPipe %d, IO pending\n", i ) ); ! 1193: } ! 1194: else ! 1195: { ! 1196: DBGMSG( DBG_ERROR, ( "ConnectNamedPipe failed. Error %d\n", GetLastError( ) ) ); ! 1197: pIniPort->Status &= ~PP_THREADRUNNING; ! 1198: return; ! 1199: } ! 1200: } ! 1201: } ! 1202: ! 1203: ! 1204: while( TRUE ) ! 1205: { ! 1206: DBGMSG( DBG_INFO, ( "Waiting to connect...\n" ) ); ! 1207: ! 1208: /* WaitForMultipleObjectsEx should return the index of the pipe instance ! 1209: * that is in signalled state. Any other value except WAIT_IO_COMPLETION ! 1210: * is an error: ! 1211: */ ! 1212: while ((WaitResult = WaitForMultipleObjectsEx( NUMBER_OF_PIPE_INSTANCES + 1, ! 1213: hEvent, ! 1214: FALSE, // wait for any ! 1215: INFINITE, ! 1216: TRUE )) == WAIT_IO_COMPLETION) ! 1217: /* do nothing */ ; ! 1218: ! 1219: DBGMSG( DBG_INFO, ( "\nWaitForMultipleObjectsEx returned %d\n", WaitResult ) ); ! 1220: ! 1221: if( ( WaitResult >= NUMBER_OF_PIPE_INSTANCES ) ! 1222: &&( WaitResult != WAIT_IO_COMPLETION ) ) ! 1223: { ! 1224: DBGMSG( DBG_INFO, ( "WaitForMultipleObjects returned %d; Last error = %d\n", ! 1225: WaitResult, GetLastError( ) ) ); ! 1226: EnterSplSem(); ! 1227: ! 1228: // if (pIniPort->pPreviousNtDeviceName) { ! 1229: ! 1230: wcscpy(DosDeviceName, pIniPort->pName); ! 1231: RemoveColon(DosDeviceName); ! 1232: ! 1233: wcscpy(NewNtDeviceName, L"\\Device\\NamedPipe\\Spooler\\"); ! 1234: wcscat(NewNtDeviceName, pIniPort->pName); ! 1235: RemoveColon(NewNtDeviceName); ! 1236: ! 1237: DefineDosDevice(DDD_REMOVE_DEFINITION | ! 1238: DDD_EXACT_MATCH_ON_REMOVE | ! 1239: DDD_RAW_TARGET_PATH, ! 1240: DosDeviceName, ! 1241: NewNtDeviceName); ! 1242: // } ! 1243: ! 1244: for( i = 0; i < NUMBER_OF_PIPE_INSTANCES; i++ ) { ! 1245: ! 1246: if( !CloseHandle( hPipe[i] ) ) { ! 1247: DBGMSG( DBG_ERROR, ( "localspl: CloseHandle failed %d %d\n", hPipe[i], GetLastError( ) ) ); ! 1248: } ! 1249: ! 1250: if( !CloseHandle( hEvent[i] ) ) { ! 1251: DBGMSG( DBG_ERROR, ( "localspl: CloseHandle failed %d %d\n", hPipe[i], GetLastError( ) ) ); ! 1252: } ! 1253: } ! 1254: ! 1255: pIniPort->Status &= ~PP_THREADRUNNING; ! 1256: ! 1257: LeaveSplSem(); ! 1258: SplOutSem(); ! 1259: return; ! 1260: } ! 1261: ! 1262: i = WaitResult; ! 1263: ! 1264: ! 1265: /* Set up the transmission structure with the handles etc. needed by ! 1266: * the completion callback routine: ! 1267: */ ! 1268: pOverlapped = (LPOVERLAPPED)LocalAlloc( LMEM_ZEROINIT, sizeof( OVERLAPPED ) ); ! 1269: pTransmission = (PTRANSMISSION)LocalAlloc( LMEM_ZEROINIT, sizeof( TRANSMISSION ) ); ! 1270: ! 1271: if( pOverlapped && pTransmission ) ! 1272: { ! 1273: /* hEvent isn't used in Win32. ! 1274: * We can use it for our own data: ! 1275: */ ! 1276: pTransmission->hPipe = hPipe[i]; ! 1277: pOverlapped->hEvent = (HANDLE)pTransmission; ! 1278: pTransmission->pOverlapped = &Overlapped[i]; ! 1279: pTransmission->PipeInstance = i; ! 1280: pTransmission->hPrinter = NULL; ! 1281: pTransmission->hFile = NULL; // CompleteRead will initialise this ! 1282: pTransmission->pIniPort = pIniPort; ! 1283: ! 1284: if( !ReadFileEx( hPipe[i], pTransmission->Data, TRANSMISSION_DATA_SIZE, ! 1285: pOverlapped, CompleteRead ) ) ! 1286: { ! 1287: DBGMSG( DBG_ERROR, ( "ReadFileEx[%d] Failed with %d\n", i, GetLastError( ) ) ); ! 1288: ! 1289: if (GetLastError() == ERROR_BROKEN_PIPE) ! 1290: { ! 1291: /* If the pipe has broken, we must disconnect ! 1292: * then reconnect for further transmissions ! 1293: * to succeed: ! 1294: */ ! 1295: DisconnectNamedPipe( hPipe[i] ); ! 1296: ! 1297: if( !ConnectNamedPipe( hPipe[i], &Overlapped[i] ) ) ! 1298: { ! 1299: Error = GetLastError( ); ! 1300: ! 1301: if( Error == ERROR_IO_PENDING ) ! 1302: { ! 1303: DBGMSG( DBG_INFO, ( "re-ConnectNamedPipe %d, IO pending\n", ! 1304: pTransmission->PipeInstance ) ); ! 1305: } ! 1306: else ! 1307: { ! 1308: DBGMSG( DBG_ERROR, ( "re-ConnectNamedPipe %d failed. Error %d\n", ! 1309: pTransmission->PipeInstance, GetLastError( ) ) ); ! 1310: } ! 1311: } ! 1312: } ! 1313: ! 1314: LocalFree( pTransmission ); ! 1315: LocalFree( pOverlapped ); ! 1316: ! 1317: } ! 1318: else ! 1319: { ! 1320: DBGMSG( DBG_INFO, ( "ReadFileEx succeeded" ) ); ! 1321: ! 1322: } ! 1323: } ! 1324: } ! 1325: } ! 1326: ! 1327: ! 1328: ! 1329: #define ADDJOB_INFO_SIZE ( sizeof( ADDJOB_INFO_1 ) + MAX_PATH ) ! 1330: ! 1331: VOID CompleteRead( DWORD Error, DWORD ByteCount, LPOVERLAPPED pOverlapped ) ! 1332: { ! 1333: PTRANSMISSION pTransmission; ! 1334: DWORD BytesWritten; ! 1335: BOOL ReadResult; ! 1336: DWORD cbNeeded; ! 1337: HANDLE hFile; ! 1338: WCHAR szDefaultPrinter[MAX_PATH]; ! 1339: ! 1340: pTransmission = (PTRANSMISSION)pOverlapped->hEvent; ! 1341: ! 1342: DBGMSG( DBG_INFO, ( "CompleteRead: Pipe Instance %d; Error = %d; ByteCount = %d\n", ! 1343: pTransmission->PipeInstance, Error, ByteCount ) ); ! 1344: ! 1345: if (!ImpersonateNamedPipeClient(pTransmission->hPipe)) ! 1346: DBGMSG( DBG_ERROR, ("ImpersonateNamedPipeClient failed %d\n", ! 1347: GetLastError())); ! 1348: ! 1349: if( pTransmission->hFile == NULL ) ! 1350: { ! 1351: PADDJOB_INFO_1 pAddJobInfo; ! 1352: BYTE AddJobInfo[ADDJOB_INFO_SIZE]; ! 1353: ! 1354: pAddJobInfo = (PADDJOB_INFO_1)AddJobInfo; ! 1355: ! 1356: OpenProfileUserMapping(); ! 1357: ! 1358: GetProfileString(L"windows", L"device", L"", szDefaultPrinter, ! 1359: sizeof(szDefaultPrinter)/sizeof(szDefaultPrinter[0])); ! 1360: ! 1361: CloseProfileUserMapping(); ! 1362: ! 1363: wcstok(szDefaultPrinter, L","); ! 1364: ! 1365: /* Open the port (???) !!! ! 1366: */ ! 1367: if( !OpenPrinter( szDefaultPrinter, &pTransmission->hPrinter, NULL ) ) ! 1368: { ! 1369: DBGMSG( DBG_ERROR, ( "OpenPrinter failed: Error %d", GetLastError( ) ) ); ! 1370: return; ! 1371: } ! 1372: ! 1373: memset( &AddJobInfo, '\0', ADDJOB_INFO_SIZE ); ! 1374: ! 1375: if( AddJob( pTransmission->hPrinter, 1, AddJobInfo, ADDJOB_INFO_SIZE, &cbNeeded ) ) ! 1376: { ! 1377: DBGMSG( DBG_INFO, ( "AddJob: JobId = %d\n", pAddJobInfo->JobId ) ); ! 1378: ! 1379: hFile = CreateFile( pAddJobInfo->Path, ! 1380: GENERIC_WRITE, ! 1381: FILE_SHARE_READ, ! 1382: NULL, // PSECURITY_DESCRIPTOR ! 1383: CREATE_ALWAYS, ! 1384: FILE_FLAG_SEQUENTIAL_SCAN, ! 1385: NULL ); ! 1386: ! 1387: if( hFile != INVALID_HANDLE_VALUE ) ! 1388: { ! 1389: DBGMSG( DBG_INFO, ( "File created\n" ) ); ! 1390: ! 1391: pTransmission->JobId = pAddJobInfo->JobId; ! 1392: pTransmission->hFile = hFile; ! 1393: ! 1394: } ! 1395: else ! 1396: { ! 1397: DBGMSG( DBG_ERROR, ( "CreateFile %s failed: Error %d\n", ! 1398: pAddJobInfo->Path, GetLastError( ) ) ); ! 1399: } ! 1400: } ! 1401: else ! 1402: { ! 1403: DBGMSG( DBG_ERROR, ( "AddJob failed: Error %d\n", GetLastError( ) ) ); ! 1404: } ! 1405: } ! 1406: ! 1407: if( Error == NO_ERROR ) ! 1408: { ! 1409: if( !WriteFile( pTransmission->hFile, ! 1410: pTransmission->Data, ! 1411: ByteCount, ! 1412: &BytesWritten, ! 1413: NULL ) ) ! 1414: { ! 1415: DBGMSG( DBG_ERROR, ( "WriteFile failed: Error %d\n", GetLastError( ) ) ); ! 1416: } ! 1417: ! 1418: memset( pTransmission->Data, '\0', TRANSMISSION_DATA_SIZE ); ! 1419: ! 1420: ReadResult = ReadFileEx( pTransmission->hPipe, pTransmission->Data, ! 1421: TRANSMISSION_DATA_SIZE, pOverlapped, CompleteRead ); ! 1422: ! 1423: if( ReadResult == FALSE ) ! 1424: { ! 1425: Error = GetLastError( ); ! 1426: DBGMSG( DBG_ERROR, ( "ReadFileEx failed: Error %d\n", Error ) ); ! 1427: } ! 1428: } ! 1429: ! 1430: if( Error != NO_ERROR ) ! 1431: { ! 1432: DisconnectNamedPipe( pTransmission->hPipe ); ! 1433: ! 1434: if( !ConnectNamedPipe( pTransmission->hPipe, pTransmission->pOverlapped ) ) ! 1435: { ! 1436: Error = GetLastError( ); ! 1437: ! 1438: if( Error == ERROR_IO_PENDING ) ! 1439: { ! 1440: DBGMSG( DBG_INFO, ( "re-ConnectNamedPipe %d, IO pending\n", ! 1441: pTransmission->PipeInstance ) ); ! 1442: } ! 1443: else ! 1444: { ! 1445: DBGMSG( DBG_ERROR, ("re-ConnectNamedPipe %d failed. Error %d\n", ! 1446: pTransmission->PipeInstance, GetLastError( ) ) ); ! 1447: } ! 1448: } ! 1449: ! 1450: if( !CloseHandle( pTransmission->hFile ) ) ! 1451: { ! 1452: DBGMSG( DBG_ERROR, ( "CloseHandle failed: Error %d\n", GetLastError( ) ) ); ! 1453: } ! 1454: ! 1455: if( !ScheduleJob( pTransmission->hPrinter, pTransmission->JobId ) ) ! 1456: { ! 1457: DBGMSG( DBG_ERROR, ( "ScheduleJob failed: Error %d\n", GetLastError( ) ) ); ! 1458: } ! 1459: ! 1460: ClosePrinter(pTransmission->hPrinter); ! 1461: ! 1462: LocalFree( pTransmission ); ! 1463: LocalFree( pOverlapped ); ! 1464: ! 1465: DBGMSG( DBG_INFO, ( "\nEnd of transmission\n" ) ); ! 1466: } ! 1467: ! 1468: /* !!! HACK HACK HACK swapping in and out of impersonation doesn't work ! 1469: if (!RevertToSelf()) ! 1470: DBGMSG( DBG_ERROR, ( "RevertToSelf failed: Error %d\n", GetLastError( ) ) ); ! 1471: */ ! 1472: } ! 1473: ! 1474: ! 1475: ! 1476: ! 1477: /* CreateNamedPipeSecurityDescriptor ! 1478: * ! 1479: * Creates a security descriptor giving everyone access ! 1480: * ! 1481: * Arguments: None ! 1482: * ! 1483: * Return: The security descriptor returned by BuildPrintObjectProtection. ! 1484: * ! 1485: */ ! 1486: #define MAX_ACE 2 ! 1487: #define DBGCHK( Condition, ErrorInfo ) \ ! 1488: if( Condition ) DBGMSG( DBG_ERROR, ErrorInfo ) ! 1489: ! 1490: PSECURITY_DESCRIPTOR ! 1491: CreateNamedPipeSecurityDescriptor( ! 1492: VOID ! 1493: ) ! 1494: { ! 1495: PSID AceSid[MAX_ACE]; // Don't expect more than MAX_ACE ACEs in any of these. ! 1496: ACCESS_MASK AceMask[MAX_ACE]; // Access masks corresponding to Sids ! 1497: BYTE InheritFlags[MAX_ACE]; // ! 1498: ULONG AceCount; ! 1499: SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY; ! 1500: PSID WorldSid; ! 1501: PSECURITY_DESCRIPTOR ServerSD; ! 1502: BOOL OK; ! 1503: ! 1504: // ! 1505: // Printer SD ! 1506: // ! 1507: ! 1508: AceCount = 0; ! 1509: ! 1510: /* World SID */ ! 1511: ! 1512: OK = AllocateAndInitializeSid( &WorldSidAuthority, 1, ! 1513: SECURITY_WORLD_RID, ! 1514: 0, 0, 0, 0, 0, 0, 0, ! 1515: &WorldSid ); ! 1516: ! 1517: DBGCHK( !OK, ( "Couldn't Allocate and initialize SID" ) ); ! 1518: ! 1519: AceSid[AceCount] = WorldSid; ! 1520: AceMask[AceCount] = GENERIC_ALL; ! 1521: InheritFlags[AceCount] = 0; ! 1522: AceCount++; ! 1523: ! 1524: OK = BuildPrintObjectProtection( AceCount, ! 1525: AceSid, ! 1526: AceMask, ! 1527: InheritFlags, ! 1528: WorldSid, ! 1529: NULL, ! 1530: &ServerSD ); ! 1531: ! 1532: FreeSid( WorldSid ); ! 1533: ! 1534: return ServerSD; ! 1535: } ! 1536: ! 1537: ! 1538: BOOL ! 1539: BuildPrintObjectProtection( ! 1540: IN ULONG AceCount, ! 1541: IN PSID *AceSid, ! 1542: IN ACCESS_MASK *AceMask, ! 1543: IN BYTE *InheritFlags, ! 1544: IN PSID WorldSid, ! 1545: IN PGENERIC_MAPPING GenericMap, ! 1546: OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor ! 1547: ) ! 1548: ! 1549: /*++ ! 1550: ! 1551: ! 1552: Routine Description: ! 1553: ! 1554: This routine builds a self-relative security descriptor ready ! 1555: to be applied to one of the print manager objects. ! 1556: ! 1557: If so indicated, a pointer to the last RID of the SID in the last ! 1558: ACE of the DACL is returned and a flag set indicating that the RID ! 1559: must be replaced before the security descriptor is applied to an object. ! 1560: This is to support USER object protection, which must grant some ! 1561: access to the user represented by the object. ! 1562: ! 1563: The owner and group of each security descriptor will be set ! 1564: to: ! 1565: ! 1566: Owner: Administrators Alias ! 1567: Group: Administrators Alias ! 1568: ! 1569: ! 1570: The SACL of each of these objects will be set to: ! 1571: ! 1572: ! 1573: Audit ! 1574: Success | Fail ! 1575: WORLD ! 1576: (Write | Delete | WriteDacl | AccessSystemSecurity) ! 1577: ! 1578: ! 1579: ! 1580: Arguments: ! 1581: ! 1582: AceCount - The number of ACEs to be included in the DACL. ! 1583: ! 1584: AceSid - Points to an array of SIDs to be granted access by the DACL. ! 1585: If the target SAM object is a User object, then the last entry ! 1586: in this array is expected to be the SID of an account within the ! 1587: domain with the last RID not yet set. The RID will be set during ! 1588: actual account creation. ! 1589: ! 1590: AceMask - Points to an array of accesses to be granted by the DACL. ! 1591: The n'th entry of this array corresponds to the n'th entry of ! 1592: the AceSid array. These masks should not include any generic ! 1593: access types. ! 1594: ! 1595: InheritOnly - Inidicates whether each ace is inherit only or not. ! 1596: ! 1597: GenericMap - Points to a generic mapping for the target object type. ! 1598: ! 1599: ! 1600: UserObject - Indicates whether the target SAM object is a User object ! 1601: or not. If TRUE (it is a User object), then the resultant ! 1602: protection will be set up indicating Rid replacement is necessary. ! 1603: ! 1604: Result - Receives a pointer to the resultant protection information. ! 1605: All access masks in ACLs in the result are mapped to standard and ! 1606: specific accesses. ! 1607: ! 1608: ! 1609: Return Value: ! 1610: ! 1611: TBS. ! 1612: ! 1613: --*/ ! 1614: { ! 1615: ! 1616: ! 1617: ! 1618: SECURITY_DESCRIPTOR Absolute; ! 1619: PSECURITY_DESCRIPTOR Relative; ! 1620: PACL TmpAcl; ! 1621: PACCESS_ALLOWED_ACE TmpAce; ! 1622: ULONG SDLength; ! 1623: ULONG DaclLength; ! 1624: ULONG i; ! 1625: BOOL OK; ! 1626: ! 1627: // ! 1628: // The approach is to set up an absolute security descriptor that ! 1629: // looks like what we want and then copy it to make a self-relative ! 1630: // security descriptor. ! 1631: // ! 1632: ! 1633: OK = InitializeSecurityDescriptor( &Absolute, ! 1634: SECURITY_DESCRIPTOR_REVISION1 ); ! 1635: ! 1636: DBGCHK( !OK, ( "Failed to initialize security descriptor. Error %d", GetLastError() ) ); ! 1637: ! 1638: // ! 1639: // Owner ! 1640: // ! 1641: // No owner -- OK?? ! 1642: ! 1643: OK = SetSecurityDescriptorOwner( &Absolute, NULL, FALSE ); ! 1644: ! 1645: DBGCHK( !OK, ( "Failed to set security descriptor owner. Error %d", GetLastError() ) ); ! 1646: ! 1647: ! 1648: // ! 1649: // Group ! 1650: // ! 1651: ! 1652: OK = SetSecurityDescriptorGroup( &Absolute, WorldSid, FALSE ); ! 1653: ! 1654: DBGCHK( !OK, ( "Failed to set security descriptor group. Error %d", GetLastError() ) ); ! 1655: ! 1656: ! 1657: ! 1658: ! 1659: // ! 1660: // Discretionary ACL ! 1661: // ! 1662: // Calculate its length, ! 1663: // Allocate it, ! 1664: // Initialize it, ! 1665: // Add each ACE ! 1666: // Set ACE as InheritOnly if necessary ! 1667: // Add it to the security descriptor ! 1668: // ! 1669: ! 1670: DaclLength = (ULONG)sizeof(ACL); ! 1671: for (i=0; i<AceCount; i++) { ! 1672: ! 1673: DaclLength += GetLengthSid( AceSid[i] ) + ! 1674: (ULONG)sizeof(ACCESS_ALLOWED_ACE) - ! 1675: (ULONG)sizeof(ULONG); //Subtract out SidStart field length ! 1676: } ! 1677: ! 1678: EnterSplSem( ); ! 1679: TmpAcl = AllocSplMem( DaclLength ); ! 1680: LeaveSplSem( ); ! 1681: ! 1682: DBGCHK( !TmpAcl, ( "Out of heap space: Can't allocate ACL." ) ); ! 1683: ! 1684: OK = InitializeAcl( TmpAcl, DaclLength, ACL_REVISION2 ); ! 1685: ! 1686: DBGCHK( !OK, ( "Failed to set initialize ACL. Error %d", GetLastError() ) ); ! 1687: ! 1688: for (i=0; i<AceCount; i++) ! 1689: { ! 1690: OK = AddAccessAllowedAce ( TmpAcl, ACL_REVISION2, AceMask[i], AceSid[i] ); ! 1691: ! 1692: DBGCHK( !OK, ( "Failed to add access-allowed ACE. Error %d", GetLastError() ) ); ! 1693: ! 1694: if (InheritFlags[i] != 0) ! 1695: { ! 1696: OK = GetAce( TmpAcl, i, (LPVOID *)&TmpAce ); ! 1697: DBGCHK( !OK, ( "Failed to get ACE. Error %d", GetLastError() ) ); ! 1698: ! 1699: TmpAce->Header.AceFlags = InheritFlags[i]; ! 1700: } ! 1701: } ! 1702: ! 1703: OK = SetSecurityDescriptorDacl (&Absolute, TRUE, TmpAcl, FALSE ); ! 1704: DBGCHK( !OK, ( "Failed to set security descriptor DACL. Error %d", GetLastError() ) ); ! 1705: ! 1706: ! 1707: ! 1708: // ! 1709: // Convert the Security Descriptor to Self-Relative ! 1710: // ! 1711: // Get the length needed ! 1712: // Allocate that much memory ! 1713: // Copy it ! 1714: // Free the generated absolute ACLs ! 1715: // ! 1716: ! 1717: SDLength = GetSecurityDescriptorLength( &Absolute ); ! 1718: ! 1719: EnterSplSem( ); ! 1720: Relative = AllocSplMem( SDLength ); ! 1721: LeaveSplSem( ); ! 1722: ! 1723: DBGCHK( !Relative, ( "Out of heap space: Can't allocate security descriptor" ) ); ! 1724: ! 1725: OK = MakeSelfRelativeSD(&Absolute, Relative, &SDLength ); ! 1726: ! 1727: DBGCHK( !OK, ( "Failed to create self-relative security descriptor DACL. Error %d", GetLastError() ) ); ! 1728: ! 1729: EnterSplSem( ); ! 1730: FreeSplMem( Absolute.Dacl, DaclLength ); ! 1731: LeaveSplSem( ); ! 1732: ! 1733: *ppSecurityDescriptor = Relative; ! 1734: ! 1735: return( OK ); ! 1736: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.