|
|
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.