|
|
1.1 root 1: /****************************************************************************\
2: * INCLUDES, DEFINES
3: \****************************************************************************/
4: #define STRICT
5: #include <windows.h>
6: #include <stdio.h>
7: #include <stdlib.h>
8:
9: #define PERR(api) printf("\n%s: Error %d from %s on line %d", \
10: __FILE__, GetLastError(), api, __LINE__);
11: #define PMSG(msg) printf("\n%s line %d: %s", \
12: __FILE__, __LINE__, msg);
13:
14: // this event is signalled when the
15: // worker thread ends
16: //
17: HANDLE hServDoneEvent = NULL;
18: SERVICE_STATUS ssStatus; // current status of the service
19:
20: SERVICE_STATUS_HANDLE sshStatusHandle;
21: DWORD dwGlobalErr;
22: DWORD TID = 0;
23: HANDLE threadHandle = NULL;
24: HANDLE pipeHandle;
25:
26:
27: /****************************************************************************\
28: * FUNCTION PROTOTYPES
29: \****************************************************************************/
30:
31: VOID service_main(DWORD dwArgc, LPTSTR *lpszArgv);
32: VOID service_ctrl(DWORD dwCtrlCode);
33: BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
34: DWORD dwWin32ExitCode,
35: DWORD dwCheckPoint,
36: DWORD dwWaitHint);
37: VOID die(char *reason);
38: VOID worker_thread(VOID *notUsed);
39: VOID StopSimpleService(LPTSTR lpszMsg);
40: BOOL WriteSD_ToA_File(PSECURITY_DESCRIPTOR psdAbsoluteSD, LPTSTR lpszFileName);
41:
42:
43: /****************************************************************************\
44: * GLOBAL VARIABLES AND TYPEDEFS
45: \****************************************************************************/
46:
47: #define SZ_SD_BUF 100
48: #define SZ_SID_BUF 75
49: #define SZ_ACL_BUF 150
50:
51: UCHAR ucAbsSDBuf [SZ_SD_BUF] = "";
52: UCHAR ucEvrSDBuf [SZ_SD_BUF] = "";
53: UCHAR ucSIDBuf [SZ_SID_BUF] = "";
54: UCHAR ucPwrUsrsSIDBuf [SZ_SID_BUF] = "";
55: UCHAR ucACLBuf [SZ_ACL_BUF] = "";
56:
57: DWORD dwSID = SZ_SID_BUF;
58: DWORD dwDACL = SZ_ACL_BUF;
59: BOOL bFloppiesAreLocked;
60:
61: PSECURITY_DESCRIPTOR psdAbsoluteSD = (PSECURITY_DESCRIPTOR)&ucAbsSDBuf;
62: PSECURITY_DESCRIPTOR psdEveryoneSD = (PSECURITY_DESCRIPTOR)&ucEvrSDBuf;
63: PSID psidAdministrators = (PSID)&ucSIDBuf;
64: PSID psidPowerUsers = (PSID)&ucPwrUsrsSIDBuf;
65: PACL pNewDACL = (PACL)&ucACLBuf;
66:
67:
68:
69:
70: // main() --
71: // all main does is call StartServiceCtrlDispatcher
72: // to register the main service thread. When the
73: // API returns, the service has stopped, so exit.
74: //
75: VOID
76: main()
77: {
78: SERVICE_TABLE_ENTRY dispatchTable[] = {
79: { TEXT("SimpleService"), (LPSERVICE_MAIN_FUNCTION)service_main },
80: { NULL, NULL }
81: };
82:
83: #define FILE_TO_REDIRECT_STDOUT_TO "c:\\floplock.out"
84: freopen(FILE_TO_REDIRECT_STDOUT_TO,"w+",stdout);
85:
86: if (!StartServiceCtrlDispatcher(dispatchTable)) {
87: StopSimpleService("StartServiceCtrlDispatcher failed.");
88: }
89: }
90:
91:
92:
93: // service_main() --
94: // this function takes care of actually starting the service,
95: // informing the service controller at each step along the way.
96: // After launching the worker thread, it waits on the event
97: // that the worker thread will signal at its termination.
98: //
99: VOID
100: service_main(DWORD dwArgc, LPTSTR *lpszArgv)
101: {
102: DWORD dwWait;
103: SECURITY_ATTRIBUTES sa;
104:
105: // register our service control handler:
106: //
107: sshStatusHandle = RegisterServiceCtrlHandler(
108: TEXT("SimpleService"),
109: service_ctrl);
110:
111: if (!sshStatusHandle)
112: goto cleanup;
113:
114: // SERVICE_STATUS members that don't change in example
115: //
116: ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
117: ssStatus.dwServiceSpecificExitCode = 0;
118:
119:
120: // report the status to Service Control Manager.
121: //
122: if (!ReportStatusToSCMgr(
123: SERVICE_START_PENDING, // service state
124: NO_ERROR, // exit code
125: 1, // checkpoint
126: 3000)) // wait hint
127: goto cleanup;
128:
129: // create the event object. The control handler function signals
130: // this event when it receives the "stop" control code.
131: //
132: hServDoneEvent = CreateEvent(
133: NULL, // no security attributes
134: TRUE, // manual reset event
135: FALSE, // not-signalled
136: NULL); // no name
137:
138: if (hServDoneEvent == (HANDLE)NULL)
139: goto cleanup;
140:
141: // report the status to the service control manager.
142: //
143: if (!ReportStatusToSCMgr(
144: SERVICE_START_PENDING, // service state
145: NO_ERROR, // exit code
146: 2, // checkpoint
147: 3000)) // wait hint
148: goto cleanup;
149:
150: // Create a security descriptor that allows only local Administrators
151: // to do anything with the pipe. Since Domain administrators are
152: // normally also local Administrators, this will serve most needs
153:
154: /************************************************************************\
155: *
156: * Get SID of local Administrators
157: *
158: \************************************************************************/
159:
160: {
161: #define SZ_DOMAIN_BUF 40
162: #define SZ_PSNU_BUF 8
163: UCHAR ucDomainBuf [SZ_DOMAIN_BUF] = "";
164: UCHAR ucPSNUBuf [SZ_PSNU_BUF] = "";
165:
166: DWORD dwDomainName = SZ_DOMAIN_BUF;
167:
168: LPSTR lpszDomain = (LPSTR)&ucDomainBuf;
169: PSID_NAME_USE psnuType = (PSID_NAME_USE)&ucPSNUBuf;
170:
171: if(!LookupAccountName((LPSTR)NULL, /* local name */
172: "Administrators",
173: psidAdministrators,
174: &dwSID,
175: lpszDomain,
176: &dwDomainName,
177: psnuType))
178: { StopSimpleService("LookupAccountName");
179: }
180:
181: if (*psnuType != SidTypeAlias)
182: { StopSimpleService("LookupAccountName returned the wrong SID type");
183: }
184: }
185:
186: /************************************************************************\
187: *
188: * Get SID of Power Users
189: *
190: \************************************************************************/
191:
192: {
193: UCHAR ucDomainBuf [SZ_DOMAIN_BUF] = "";
194: UCHAR ucPSNUBuf [SZ_PSNU_BUF] = "";
195:
196: DWORD dwDomainName = SZ_DOMAIN_BUF;
197:
198: LPSTR lpszDomain = (LPSTR)&ucDomainBuf;
199: PSID_NAME_USE psnuType = (PSID_NAME_USE)&ucPSNUBuf;
200:
201: if(!LookupAccountName((LPSTR)NULL, /* local name */
202: "Power Users",
203: psidPowerUsers,
204: &dwSID,
205: lpszDomain,
206: &dwDomainName,
207: psnuType))
208: { StopSimpleService("LookupAccountName");
209: }
210:
211: if (*psnuType != SidTypeAlias)
212: { StopSimpleService("LookupAccountName returned the wrong SID type");
213: }
214: }
215:
216: /************************************************************************\
217: *
218: * Initialize new DACL
219: *
220: \************************************************************************/
221:
222: if (!InitializeAcl(pNewDACL,
223: dwDACL,
224: ACL_REVISION2))
225: { StopSimpleService("InitializeAcl");
226: }
227:
228: /************************************************************************\
229: *
230: * Allow All access for local Administrators only
231: *
232: \************************************************************************/
233:
234: if (!AddAccessAllowedAce(pNewDACL,
235: ACL_REVISION2,
236: FILE_ALL_ACCESS,
237: psidAdministrators))
238: { StopSimpleService("AddAccessAllowedAce");
239: }
240:
241: /************************************************************************\
242: *
243: * If we unlock the floppies when the service stops, then for the sake of
244: * consistency, we have to also allow Power Users on the Admin-only DACL,
245: * since Power Users can stop services. It would be inconsistent to try
246: * to lock Power Users away from their floppies if Power Users could get
247: * to the floppies simply by stopping the service
248: *
249: * It's still OK to use the same DACL for the pipe as for the floppies,
250: * that is, it's OK to let Power Users on the DACL for the pipe too. The
251: * reason is that it is not generally (and certainly not by default) the
252: * case that an account is a member of Power Users on more than their own
253: * machines. So, putting Power Users on the pipe let's Power Users admin
254: * the floppies via the pipe only on the machines on which they are
255: * actually Power Users, and again, on those machines they can stop the
256: * floppy-locking service as well
257: *
258: \************************************************************************/
259:
260: #define UNLOCK_AT_SERVICE_STOP (0==0)
261: if (UNLOCK_AT_SERVICE_STOP)
262: { if (!AddAccessAllowedAce(pNewDACL,
263: ACL_REVISION2,
264: FILE_ALL_ACCESS,
265: psidPowerUsers))
266: { StopSimpleService("AddAccessAllowedAce");
267: }
268: }
269:
270: /************************************************************************\
271: *
272: * Build SD in absolute format - first the Admins-only then the Everyone SD
273: *
274: \************************************************************************/
275:
276: if (!InitializeSecurityDescriptor(psdAbsoluteSD,
277: SECURITY_DESCRIPTOR_REVISION))
278: { StopSimpleService("InitializeSecurityDescriptor");
279: }
280:
281: if (!InitializeSecurityDescriptor(psdEveryoneSD,
282: SECURITY_DESCRIPTOR_REVISION))
283: { StopSimpleService("InitializeSecurityDescriptor");
284: }
285:
286: /************************************************************************\
287: *
288: * Set DACL into SD - first the Admins-only then the Everyone SD
289: *
290: \************************************************************************/
291:
292: if (!SetSecurityDescriptorDacl(psdAbsoluteSD,
293: TRUE, // fDaclPresent flag
294: pNewDACL,
295: FALSE)) // not a default DACL
296: { StopSimpleService("SetSecurityDescriptorDacl");
297: }
298:
299: if (!SetSecurityDescriptorDacl(psdEveryoneSD,
300: TRUE, // fDaclPresent flag
301: (PACL)NULL,
302: FALSE)) // not a default DACL
303: { StopSimpleService("SetSecurityDescriptorDacl");
304: }
305:
306: /************************************************************************\
307: *
308: * Check to see that SD is valid before attempting to write it to the file
309: *
310: \************************************************************************/
311:
312: if (!IsValidSecurityDescriptor(psdAbsoluteSD))
313: { StopSimpleService("IsValidSecurityDescriptor");
314: }
315:
316: sa.nLength = sizeof(sa);
317: sa.lpSecurityDescriptor = psdAbsoluteSD;
318: sa.bInheritHandle = TRUE; // why not... we spawn no processes
319:
320: // open our named pipe...
321: //
322: pipeHandle = CreateNamedPipe(
323: "\\\\.\\pipe\\sd_flppy", // name of pipe
324: PIPE_ACCESS_DUPLEX, // pipe open mode
325: PIPE_TYPE_MESSAGE |
326: PIPE_READMODE_MESSAGE |
327: PIPE_WAIT, // pipe IO type
328: 1, // number of instances
329: 0, // size of outbuf (0 == allocate as necessary)
330: 0, // size of inbuf
331: 1000, // default time-out value
332: &sa); // security attributes
333:
334: if (!pipeHandle) {
335: StopSimpleService("CreateNamedPipe");
336: return;
337: }
338:
339: // Set the same DACL onto the floppies
340: //
341:
342: /************************************************************************\
343: *
344: * Write SD to file system - first for A: then B:
345: *
346: \************************************************************************/
347:
348: if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\A:"))
349: { StopSimpleService("Write of DACL to A: failed");
350: }
351:
352: if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\B:"))
353: { StopSimpleService("Write of DACL to B: failed");
354: }
355:
356: bFloppiesAreLocked = TRUE;
357:
358: /************************************************************************\
359: *
360: * Works for CDROM drives as well - commented out as this samples is floppy
361: * only
362: *
363: \************************************************************************/
364: /*
365: if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\E:"))
366: { StopSimpleService("Write of DACL to E: failed");
367: }
368: */
369: /************************************************************************\
370: *
371: * Works for COM ports as well - commented out as this samples is floppy only
372: *
373: \************************************************************************/
374: /*
375: if (!WriteSD_ToA_File(psdAbsoluteSD,"COM1:"))
376: { StopSimpleService("Write of DACL to COM1: failed");
377: }
378: */
379:
380: // start the thread that performs the work of the service.
381: //
382: threadHandle = CreateThread(
383: NULL, // security attributes
384: 0, // stack size (0 means inherit parent's stack size)
385: (LPTHREAD_START_ROUTINE)worker_thread,
386: NULL, // argument to thread
387: 0, // thread creation flags
388: &TID); // pointer to thread ID
389:
390: if (!threadHandle)
391: goto cleanup;
392:
393: // report the status to the service control manager.
394: //
395: if (!ReportStatusToSCMgr(
396: SERVICE_RUNNING, // service state
397: NO_ERROR, // exit code
398: 0, // checkpoint
399: 0)) // wait hint
400: goto cleanup;
401:
402: // wait indefinitely until hServDoneEvent is signaled.
403: //
404: dwWait = WaitForSingleObject(
405: hServDoneEvent, // event object
406: INFINITE); // wait indefinitely
407:
408: cleanup:
409:
410: if (hServDoneEvent != NULL)
411: CloseHandle(hServDoneEvent);
412:
413:
414: // try to report the stopped status to the service control manager.
415: //
416: if (sshStatusHandle != 0)
417: (VOID)ReportStatusToSCMgr(
418: SERVICE_STOPPED,
419: dwGlobalErr,
420: 0,
421: 0);
422:
423: // When SERVICE MAIN FUNCTION returns in a single service
424: // process, the StartServiceCtrlDispatcher function in
425: // the main thread returns, terminating the process.
426: //
427: return;
428: }
429:
430:
431:
432: // service_ctrl() --
433: // this function is called by the Service Controller whenever
434: // someone calls ControlService in reference to our service.
435: //
436: VOID
437: service_ctrl(DWORD dwCtrlCode)
438: {
439: DWORD dwState = SERVICE_RUNNING;
440:
441: // Handle the requested control code.
442: //
443: switch(dwCtrlCode) {
444:
445: // Pause the service if it is running.
446: //
447: case SERVICE_CONTROL_PAUSE:
448:
449: if (ssStatus.dwCurrentState == SERVICE_RUNNING) {
450: SuspendThread(threadHandle);
451: dwState = SERVICE_PAUSED;
452: }
453: break;
454:
455: // Resume the paused service.
456: //
457: case SERVICE_CONTROL_CONTINUE:
458:
459: if (ssStatus.dwCurrentState == SERVICE_PAUSED) {
460: ResumeThread(threadHandle);
461: dwState = SERVICE_RUNNING;
462: }
463: break;
464:
465: // Stop the service.
466: //
467: case SERVICE_CONTROL_STOP:
468:
469: dwState = SERVICE_STOP_PENDING;
470:
471: // Report the status, specifying the checkpoint and waithint,
472: // before setting the termination event.
473: //
474: ReportStatusToSCMgr(
475: SERVICE_STOP_PENDING, // current state
476: NO_ERROR, // exit code
477: 1, // checkpoint
478: 3000); // waithint
479:
480: if (UNLOCK_AT_SERVICE_STOP)
481: { if (!WriteSD_ToA_File(psdEveryoneSD,"\\\\.\\A:"))
482: { StopSimpleService("Unlock of A: failed, see log file");
483: }
484: if (!WriteSD_ToA_File(psdEveryoneSD,"\\\\.\\B:"))
485: { StopSimpleService("Unlock of B: failed, see log file");
486: }
487:
488: bFloppiesAreLocked = FALSE;
489: }
490:
491: SetEvent(hServDoneEvent);
492: return;
493:
494: // Update the service status.
495: //
496: case SERVICE_CONTROL_INTERROGATE:
497: break;
498:
499: // invalid control code
500: //
501: default:
502: break;
503:
504: }
505:
506: // send a status response.
507: //
508: ReportStatusToSCMgr(dwState, NO_ERROR, 0, 0);
509: }
510:
511:
512:
513: // worker_thread() --
514: // this function does the actual nuts and bolts work that
515: // the service requires. It will also Pause or Stop when
516: // asked by the service_ctrl function.
517: //
518: VOID
519: worker_thread(VOID *notUsed)
520: {
521: char inbuf[180];
522: char outbuf[180];
523: BOOL ret;
524: DWORD bytesRead;
525: DWORD bytesWritten;
526: DWORD dwLen;
527:
528: // okay, our pipe has been created, let's enter the simple
529: // processing loop...
530: //
531: while (1) {
532:
533: // wait for a connection...
534: //
535: ConnectNamedPipe(pipeHandle, NULL);
536:
537: // grab whatever's coming through the pipe...
538: //
539: ret = ReadFile(
540: pipeHandle, // file to read from
541: inbuf, // address of input buffer
542: sizeof(inbuf), // number of bytes to read
543: &bytesRead, // number of bytes read
544: NULL); // overlapped stuff, not needed
545:
546: if (!ret)
547: // pipe's broken... go back and reconnect
548: //
549: continue;
550:
551: switch (inbuf[0])
552: { case 'U':
553: dwLen = sprintf(outbuf,"Floppies were unlocked");
554:
555: if (!WriteSD_ToA_File(psdEveryoneSD,"\\\\.\\A:"))
556: { dwLen += sprintf(outbuf+dwLen,", unlock of A: failed, see log file");
557: }
558: if (!WriteSD_ToA_File(psdEveryoneSD,"\\\\.\\B:"))
559: { dwLen += sprintf(outbuf+dwLen,", unlock of B: failed, see log file");
560: }
561:
562: bFloppiesAreLocked = FALSE;
563: break;
564:
565: case 'L':
566: dwLen = sprintf(outbuf,"Floppies were locked");
567:
568: if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\A:"))
569: { dwLen += sprintf(outbuf+dwLen,", lock of A: failed, see log file");
570: }
571: if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\B:"))
572: { dwLen += sprintf(outbuf+dwLen,", lock of B: failed, see log file");
573: }
574:
575: bFloppiesAreLocked = TRUE;
576: break;
577:
578: case 'Q':
579: if (bFloppiesAreLocked)
580: { sprintf(outbuf,"Floppy status is: Locked");
581: }
582: else
583: { sprintf(outbuf,"Floppy status is: Unlocked");
584: }
585: break;
586:
587: default :
588: sprintf(outbuf,"Bad operation passed in");
589: }
590:
591: // send it back out...
592: //
593: ret = WriteFile(
594: pipeHandle, // file to write to
595: outbuf, // address of output buffer
596: sizeof(outbuf), // number of bytes to write
597: &bytesWritten, // number of bytes written
598: NULL); // overlapped stuff, not needed
599:
600: if (!ret)
601: // pipe's broken... go back and reconnect
602: //
603: continue;
604:
605: // drop the connection...
606: //
607: DisconnectNamedPipe(pipeHandle);
608: }
609: }
610:
611:
612:
613: // utility functions...
614:
615:
616:
617: // ReportStatusToSCMgr() --
618: // This function is called by the ServMainFunc() and
619: // ServCtrlHandler() functions to update the service's status
620: // to the service control manager.
621: //
622: BOOL
623: ReportStatusToSCMgr(DWORD dwCurrentState,
624: DWORD dwWin32ExitCode,
625: DWORD dwCheckPoint,
626: DWORD dwWaitHint)
627: {
628: BOOL fResult;
629:
630: // Disable control requests until the service is started.
631: //
632: if (dwCurrentState == SERVICE_START_PENDING)
633: ssStatus.dwControlsAccepted = 0;
634: else
635: ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
636: SERVICE_ACCEPT_PAUSE_CONTINUE;
637:
638: // These SERVICE_STATUS members are set from parameters.
639: //
640: ssStatus.dwCurrentState = dwCurrentState;
641: ssStatus.dwWin32ExitCode = dwWin32ExitCode;
642: ssStatus.dwCheckPoint = dwCheckPoint;
643:
644: ssStatus.dwWaitHint = dwWaitHint;
645:
646: // Report the status of the service to the service control manager.
647: //
648: if (!(fResult = SetServiceStatus(
649: sshStatusHandle, // service reference handle
650: &ssStatus))) { // SERVICE_STATUS structure
651:
652: // If an error occurs, stop the service.
653: //
654: StopSimpleService("SetServiceStatus");
655: }
656: return fResult;
657: }
658:
659:
660:
661: // The StopSimpleService function can be used by any thread to report an
662: // error, or stop the service.
663: //
664: VOID
665: StopSimpleService(LPTSTR lpszMsg)
666: {
667: CHAR chMsg[256];
668: HANDLE hEventSource;
669: LPTSTR lpszStrings[2];
670:
671: dwGlobalErr = GetLastError();
672:
673: // Use event logging to log the error.
674: //
675: hEventSource = RegisterEventSource(NULL,
676: TEXT("SimpleService"));
677:
678: sprintf(chMsg, "SimpleService error: %d", dwGlobalErr);
679: lpszStrings[0] = chMsg;
680: lpszStrings[1] = lpszMsg;
681:
682: if (hEventSource != NULL) {
683: ReportEvent(hEventSource, // handle of event source
684: EVENTLOG_ERROR_TYPE, // event type
685: 0, // event category
686: 0, // event ID
687: NULL, // current user's SID
688: 2, // strings in lpszStrings
689: 0, // no bytes of raw data
690: lpszStrings, // array of error strings
691: NULL); // no raw data
692:
693: (VOID) DeregisterEventSource(hEventSource);
694: }
695:
696: // Set a termination event to stop SERVICE MAIN FUNCTION.
697: //
698: SetEvent(hServDoneEvent);
699: }
700:
701: /****************************************************************************\
702: *
703: * FUNCTION: WriteSD_ToA_File
704: *
705: \****************************************************************************/
706:
707: BOOL WriteSD_ToA_File(PSECURITY_DESCRIPTOR psdAbsoluteSD, LPTSTR lpszFileName)
708: {
709: DWORD dwErrorMode;
710: BOOL bStatus;
711:
712: /**************************************************************************\
713: *
714: * SetErrorMode so we don't get the error due to no floppy disk in the floppy
715: * drive
716: *
717: \**************************************************************************/
718:
719: dwErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
720:
721: /**************************************************************************\
722: *
723: * Write SD to file system
724: *
725: \**************************************************************************/
726:
727: bStatus = SetFileSecurity(lpszFileName,
728: (SECURITY_INFORMATION)(DACL_SECURITY_INFORMATION),
729: psdAbsoluteSD);
730:
731: /**************************************************************************\
732: *
733: * SetErrorMode back to its previous value
734: *
735: \**************************************************************************/
736:
737: SetErrorMode(dwErrorMode);
738:
739: if (!bStatus)
740: { if (ERROR_FILE_NOT_FOUND == GetLastError())
741: { printf("\nAttempted to lock %s, but it was not found",lpszFileName);
742: }
743: else
744: { PERR("SetFileSecurity");
745: return(FALSE);
746: }
747: }
748:
749: return(TRUE);
750: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.