Annotation of ntddk/src/print/localmon/localmon.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.