home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************\
- * INCLUDES, DEFINES
- \****************************************************************************/
- #define STRICT
- #include <windows.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- #define PERR(api) printf("\n%s: Error %d from %s on line %d", \
- __FILE__, GetLastError(), api, __LINE__);
- #define PMSG(msg) printf("\n%s line %d: %s", \
- __FILE__, __LINE__, msg);
-
- // this event is signalled when the
- // worker thread ends
- //
- HANDLE hServDoneEvent = NULL;
- SERVICE_STATUS ssStatus; // current status of the service
-
- SERVICE_STATUS_HANDLE sshStatusHandle;
- DWORD dwGlobalErr;
- DWORD TID = 0;
- HANDLE threadHandle = NULL;
- HANDLE pipeHandle;
-
-
- /****************************************************************************\
- * FUNCTION PROTOTYPES
- \****************************************************************************/
-
- VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
- VOID WINAPI service_ctrl(DWORD dwCtrlCode);
- BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
- DWORD dwWin32ExitCode,
- DWORD dwCheckPoint,
- DWORD dwWaitHint);
- VOID die(char *reason);
- VOID worker_thread(VOID *notUsed);
- VOID StopSimpleService(LPTSTR lpszMsg);
- BOOL WriteSD_ToA_File(PSECURITY_DESCRIPTOR psdAbsoluteSD, LPTSTR lpszFileName);
-
-
- /****************************************************************************\
- * GLOBAL VARIABLES AND TYPEDEFS
- \****************************************************************************/
-
- #define SZ_SD_BUF 100
- #define SZ_SID_BUF 75
- #define SZ_ACL_BUF 150
-
- UCHAR ucAbsSDBuf [SZ_SD_BUF] = "";
- UCHAR ucEvrSDBuf [SZ_SD_BUF] = "";
- UCHAR ucSIDBuf [SZ_SID_BUF] = "";
- UCHAR ucPwrUsrsSIDBuf [SZ_SID_BUF] = "";
- UCHAR ucACLBuf [SZ_ACL_BUF] = "";
-
- DWORD dwSID = SZ_SID_BUF;
- DWORD dwDACL = SZ_ACL_BUF;
- BOOL bFloppiesAreLocked;
-
- PSECURITY_DESCRIPTOR psdAbsoluteSD = (PSECURITY_DESCRIPTOR)&ucAbsSDBuf;
- PSECURITY_DESCRIPTOR psdEveryoneSD = (PSECURITY_DESCRIPTOR)&ucEvrSDBuf;
- PSID psidAdministrators = (PSID)&ucSIDBuf;
- PSID psidPowerUsers = (PSID)&ucPwrUsrsSIDBuf;
- PACL pNewDACL = (PACL)&ucACLBuf;
-
-
-
- // main() --
- // all main does is call StartServiceCtrlDispatcher
- // to register the main service thread. When the
- // API returns, the service has stopped, so exit.
- //
- int
- main()
- {
-
- SERVICE_TABLE_ENTRY dispatchTable[] = {
- { TEXT("SimpleService"), (LPSERVICE_MAIN_FUNCTION)service_main },
- { NULL, NULL }
- };
-
- // check if Win32s, if so, display notice and terminate
- if( GetVersion() & 0x80000000 )
- {
- MessageBox( NULL,
- "This application cannot run on Windows 3.1 or Windows 95.\n"
- "This application will now terminate.",
- "SD_FLPPY",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND );
- return( 1 );
- }
-
- #define FILE_TO_REDIRECT_STDOUT_TO "c:\\floplock.out"
- // freopen(FILE_TO_REDIRECT_STDOUT_TO,"w+",stdout);
-
- if (!StartServiceCtrlDispatcher(dispatchTable)) {
- StopSimpleService("StartServiceCtrlDispatcher failed.");
- }
- }
-
-
-
- // service_main() --
- // this function takes care of actually starting the service,
- // informing the service controller at each step along the way.
- // After launching the worker thread, it waits on the event
- // that the worker thread will signal at its termination.
- //
- VOID WINAPI
- service_main(DWORD dwArgc, LPTSTR *lpszArgv)
- {
- DWORD dwWait;
- SECURITY_ATTRIBUTES sa;
-
- // register our service control handler:
- //
- sshStatusHandle = RegisterServiceCtrlHandler(
- TEXT("SimpleService"),
- service_ctrl);
-
- if (!sshStatusHandle)
- goto cleanup;
-
- // SERVICE_STATUS members that don't change in example
- //
- ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- ssStatus.dwServiceSpecificExitCode = 0;
-
-
- // report the status to Service Control Manager.
- //
- if (!ReportStatusToSCMgr(
- SERVICE_START_PENDING, // service state
- NO_ERROR, // exit code
- 1, // checkpoint
- 3000)) // wait hint
- goto cleanup;
-
- // create the event object. The control handler function signals
- // this event when it receives the "stop" control code.
- //
- hServDoneEvent = CreateEvent(
- NULL, // no security attributes
- TRUE, // manual reset event
- FALSE, // not-signalled
- NULL); // no name
-
- if (hServDoneEvent == (HANDLE)NULL)
- goto cleanup;
-
- // report the status to the service control manager.
- //
- if (!ReportStatusToSCMgr(
- SERVICE_START_PENDING, // service state
- NO_ERROR, // exit code
- 2, // checkpoint
- 3000)) // wait hint
- goto cleanup;
-
- // Create a security descriptor that allows only local Administrators
- // to do anything with the pipe. Since Domain administrators are
- // normally also local Administrators, this will serve most needs
-
- /************************************************************************\
- *
- * Build SIDs of local Administrators and Power Users. Note that the Power
- * Users group is defined on Windows NT machines, but not on Advanced
- * Server machines. This means that we will on Advanced Server machines
- * have a DACL that has an ACE (for Power Users) that will never be used
- *
- \************************************************************************/
-
- {
- SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
-
- InitializeSid( psidAdministrators, &siaNtAuthority, 2 );
- InitializeSid( psidPowerUsers, &siaNtAuthority, 2 );
-
- *(GetSidSubAuthority( psidAdministrators, 0 )) = SECURITY_BUILTIN_DOMAIN_RID;
- *(GetSidSubAuthority( psidPowerUsers, 0 )) = SECURITY_BUILTIN_DOMAIN_RID;
-
- *(GetSidSubAuthority( psidAdministrators, 1 )) = DOMAIN_ALIAS_RID_ADMINS;
- *(GetSidSubAuthority( psidPowerUsers, 1 )) = DOMAIN_ALIAS_RID_POWER_USERS;
- }
-
-
- /************************************************************************\
- *
- * Initialize new DACL
- *
- \************************************************************************/
-
- if (!InitializeAcl(pNewDACL,
- dwDACL,
- ACL_REVISION))
- { StopSimpleService("InitializeAcl");
- }
-
- /************************************************************************\
- *
- * Allow All access for local Administrators only
- *
- \************************************************************************/
-
- if (!AddAccessAllowedAce(pNewDACL,
- ACL_REVISION,
- FILE_ALL_ACCESS,
- psidAdministrators))
- { StopSimpleService("AddAccessAllowedAce");
- }
-
- /************************************************************************\
- *
- * If we unlock the floppies when the service stops, then for the sake of
- * consistency, we have to also allow Power Users on the Admin-only DACL,
- * since Power Users can stop services. It would be inconsistent to try
- * to lock Power Users away from their floppies if Power Users could get
- * to the floppies simply by stopping the service
- *
- * It's still OK to use the same DACL for the pipe as for the floppies,
- * that is, it's OK to let Power Users on the DACL for the pipe too. The
- * reason is that it is not generally (and certainly not by default) the
- * case that an account is a member of Power Users on more than their own
- * machines. So, putting Power Users on the pipe let's Power Users admin
- * the floppies via the pipe only on the machines on which they are
- * actually Power Users, and again, on those machines they can stop the
- * floppy-locking service as well
- *
- \************************************************************************/
-
- #define UNLOCK_AT_SERVICE_STOP (0==0)
- if (UNLOCK_AT_SERVICE_STOP)
- { if (!AddAccessAllowedAce(pNewDACL,
- ACL_REVISION,
- FILE_ALL_ACCESS,
- psidPowerUsers))
- { StopSimpleService("AddAccessAllowedAce");
- }
- }
-
- /************************************************************************\
- *
- * Build SD in absolute format - first the Admins-only then the Everyone SD
- *
- \************************************************************************/
-
- if (!InitializeSecurityDescriptor(psdAbsoluteSD,
- SECURITY_DESCRIPTOR_REVISION))
- { StopSimpleService("InitializeSecurityDescriptor");
- }
-
- if (!InitializeSecurityDescriptor(psdEveryoneSD,
- SECURITY_DESCRIPTOR_REVISION))
- { StopSimpleService("InitializeSecurityDescriptor");
- }
-
- /************************************************************************\
- *
- * Set DACL into SD - first the Admins-only then the Everyone SD
- *
- \************************************************************************/
-
- if (!SetSecurityDescriptorDacl(psdAbsoluteSD,
- TRUE, // fDaclPresent flag
- pNewDACL,
- FALSE)) // not a default DACL
- { StopSimpleService("SetSecurityDescriptorDacl");
- }
-
- if (!SetSecurityDescriptorDacl(psdEveryoneSD,
- TRUE, // fDaclPresent flag
- (PACL)NULL,
- FALSE)) // not a default DACL
- { StopSimpleService("SetSecurityDescriptorDacl");
- }
-
- /************************************************************************\
- *
- * Check to see that SD is valid before attempting to write it to the file
- *
- \************************************************************************/
-
- if (!IsValidSecurityDescriptor(psdAbsoluteSD))
- { StopSimpleService("IsValidSecurityDescriptor");
- }
-
- sa.nLength = sizeof(sa);
- sa.lpSecurityDescriptor = psdAbsoluteSD;
- sa.bInheritHandle = TRUE; // why not... we spawn no processes
-
- // open our named pipe...
- //
- pipeHandle = CreateNamedPipe(
- "\\\\.\\pipe\\sd_flppy", // name of pipe
- PIPE_ACCESS_DUPLEX, // pipe open mode
- PIPE_TYPE_MESSAGE |
- PIPE_READMODE_MESSAGE |
- PIPE_WAIT, // pipe IO type
- 1, // number of instances
- 0, // size of outbuf (0 == allocate as necessary)
- 0, // size of inbuf
- 1000, // default time-out value
- &sa); // security attributes
-
- if (!pipeHandle) {
- StopSimpleService("CreateNamedPipe");
- return;
- }
-
- // Set the same DACL onto the floppies
- //
-
- /************************************************************************\
- *
- * Write SD to file system - first for A: then B:
- *
- \************************************************************************/
-
- if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\A:"))
- { StopSimpleService("Write of DACL to A: failed");
- }
-
- if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\B:"))
- { StopSimpleService("Write of DACL to B: failed");
- }
-
- bFloppiesAreLocked = TRUE;
-
- /************************************************************************\
- *
- * only works for CDROM drives if you revoke the SeChangeNotify privilege
- * from Everyone in user manager
- *
- \************************************************************************/
- /*
- if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\E:"))
- { StopSimpleService("Write of DACL to E: failed");
- }
- */
- /************************************************************************\
- *
- * Works for COM ports as well - commented out as this samples is floppy only
- *
- \************************************************************************/
- /*
- if (!WriteSD_ToA_File(psdAbsoluteSD,"COM1:"))
- { StopSimpleService("Write of DACL to COM1: failed");
- }
- */
-
- // start the thread that performs the work of the service.
- //
- threadHandle = CreateThread(
- NULL, // security attributes
- 0, // stack size (0 means inherit parent's stack size)
- (LPTHREAD_START_ROUTINE)worker_thread,
- NULL, // argument to thread
- 0, // thread creation flags
- &TID); // pointer to thread ID
-
- if (!threadHandle)
- goto cleanup;
-
- // report the status to the service control manager.
- //
- if (!ReportStatusToSCMgr(
- SERVICE_RUNNING, // service state
- NO_ERROR, // exit code
- 0, // checkpoint
- 0)) // wait hint
- goto cleanup;
-
- // wait indefinitely until hServDoneEvent is signaled.
- //
- dwWait = WaitForSingleObject(
- hServDoneEvent, // event object
- INFINITE); // wait indefinitely
-
- cleanup:
-
- if (hServDoneEvent != NULL)
- CloseHandle(hServDoneEvent);
-
-
- // try to report the stopped status to the service control manager.
- //
- if (sshStatusHandle != 0)
- (VOID)ReportStatusToSCMgr(
- SERVICE_STOPPED,
- dwGlobalErr,
- 0,
- 0);
-
- // When SERVICE MAIN FUNCTION returns in a single service
- // process, the StartServiceCtrlDispatcher function in
- // the main thread returns, terminating the process.
- //
- return;
- }
-
-
-
- // service_ctrl() --
- // this function is called by the Service Controller whenever
- // someone calls ControlService in reference to our service.
- //
- VOID WINAPI
- service_ctrl(DWORD dwCtrlCode)
- {
- DWORD dwState = SERVICE_RUNNING;
-
- // Handle the requested control code.
- //
- switch(dwCtrlCode) {
-
- // Pause the service if it is running.
- //
- case SERVICE_CONTROL_PAUSE:
-
- if (ssStatus.dwCurrentState == SERVICE_RUNNING) {
- SuspendThread(threadHandle);
- dwState = SERVICE_PAUSED;
- }
- break;
-
- // Resume the paused service.
- //
- case SERVICE_CONTROL_CONTINUE:
-
- if (ssStatus.dwCurrentState == SERVICE_PAUSED) {
- ResumeThread(threadHandle);
- dwState = SERVICE_RUNNING;
- }
- break;
-
- // Stop the service.
- //
- case SERVICE_CONTROL_STOP:
-
- dwState = SERVICE_STOP_PENDING;
-
- // Report the status, specifying the checkpoint and waithint,
- // before setting the termination event.
- //
- ReportStatusToSCMgr(
- SERVICE_STOP_PENDING, // current state
- NO_ERROR, // exit code
- 1, // checkpoint
- 3000); // waithint
-
- if (UNLOCK_AT_SERVICE_STOP)
- { if (!WriteSD_ToA_File(psdEveryoneSD,"\\\\.\\A:"))
- { StopSimpleService("Unlock of A: failed, see log file");
- }
- if (!WriteSD_ToA_File(psdEveryoneSD,"\\\\.\\B:"))
- { StopSimpleService("Unlock of B: failed, see log file");
- }
-
- bFloppiesAreLocked = FALSE;
- }
-
- SetEvent(hServDoneEvent);
- return;
-
- // Update the service status.
- //
- case SERVICE_CONTROL_INTERROGATE:
- break;
-
- // invalid control code
- //
- default:
- break;
-
- }
-
- // send a status response.
- //
- ReportStatusToSCMgr(dwState, NO_ERROR, 0, 0);
- }
-
-
-
- // worker_thread() --
- // this function does the actual nuts and bolts work that
- // the service requires. It will also Pause or Stop when
- // asked by the service_ctrl function.
- //
- VOID
- worker_thread(VOID *notUsed)
- {
- char inbuf[180];
- char outbuf[180];
- BOOL ret;
- DWORD bytesRead;
- DWORD bytesWritten;
- DWORD dwLen;
-
- // okay, our pipe has been created, let's enter the simple
- // processing loop...
- //
- while (1) {
-
- // wait for a connection...
- //
- ConnectNamedPipe(pipeHandle, NULL);
-
- // grab whatever's coming through the pipe...
- //
- ret = ReadFile(
- pipeHandle, // file to read from
- inbuf, // address of input buffer
- sizeof(inbuf), // number of bytes to read
- &bytesRead, // number of bytes read
- NULL); // overlapped stuff, not needed
-
- if (!ret)
- // pipe's broken... go back and reconnect
- //
- continue;
-
- switch (inbuf[0])
- { case 'U':
- dwLen = sprintf(outbuf,"Floppies were unlocked");
-
- if (!WriteSD_ToA_File(psdEveryoneSD,"\\\\.\\A:"))
- { dwLen += sprintf(outbuf+dwLen,", unlock of A: failed, see log file");
- }
- if (!WriteSD_ToA_File(psdEveryoneSD,"\\\\.\\B:"))
- { dwLen += sprintf(outbuf+dwLen,", unlock of B: failed, see log file");
- }
-
- bFloppiesAreLocked = FALSE;
- break;
-
- case 'L':
- dwLen = sprintf(outbuf,"Floppies were locked");
-
- if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\A:"))
- { dwLen += sprintf(outbuf+dwLen,", lock of A: failed, see log file");
- }
- if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\B:"))
- { dwLen += sprintf(outbuf+dwLen,", lock of B: failed, see log file");
- }
-
- bFloppiesAreLocked = TRUE;
- break;
-
- case 'Q':
- if (bFloppiesAreLocked)
- { sprintf(outbuf,"Floppy status is: Locked");
- }
- else
- { sprintf(outbuf,"Floppy status is: Unlocked");
- }
- break;
-
- default :
- sprintf(outbuf,"Bad operation passed in");
- }
-
- // send it back out...
- //
- ret = WriteFile(
- pipeHandle, // file to write to
- outbuf, // address of output buffer
- sizeof(outbuf), // number of bytes to write
- &bytesWritten, // number of bytes written
- NULL); // overlapped stuff, not needed
-
- if (!ret)
- // pipe's broken... go back and reconnect
- //
- continue;
-
- // drop the connection...
- //
- DisconnectNamedPipe(pipeHandle);
- }
- }
-
-
-
- // utility functions...
-
-
-
- // ReportStatusToSCMgr() --
- // This function is called by the ServMainFunc() and
- // ServCtrlHandler() functions to update the service's status
- // to the service control manager.
- //
- BOOL
- ReportStatusToSCMgr(DWORD dwCurrentState,
- DWORD dwWin32ExitCode,
- DWORD dwCheckPoint,
- DWORD dwWaitHint)
- {
- BOOL fResult;
-
- // Disable control requests until the service is started.
- //
- if (dwCurrentState == SERVICE_START_PENDING)
- ssStatus.dwControlsAccepted = 0;
- else
- ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
- SERVICE_ACCEPT_PAUSE_CONTINUE;
-
- // These SERVICE_STATUS members are set from parameters.
- //
- ssStatus.dwCurrentState = dwCurrentState;
- ssStatus.dwWin32ExitCode = dwWin32ExitCode;
- ssStatus.dwCheckPoint = dwCheckPoint;
-
- ssStatus.dwWaitHint = dwWaitHint;
-
- // Report the status of the service to the service control manager.
- //
- if (!(fResult = SetServiceStatus(
- sshStatusHandle, // service reference handle
- &ssStatus))) { // SERVICE_STATUS structure
-
- // If an error occurs, stop the service.
- //
- StopSimpleService("SetServiceStatus");
- }
- return fResult;
- }
-
-
-
- // The StopSimpleService function can be used by any thread to report an
- // error, or stop the service.
- //
- VOID
- StopSimpleService(LPTSTR lpszMsg)
- {
- CHAR chMsg[256];
- HANDLE hEventSource;
- LPTSTR lpszStrings[2];
-
- dwGlobalErr = GetLastError();
-
- // Use event logging to log the error.
- //
- hEventSource = RegisterEventSource(NULL,
- TEXT("SimpleService"));
-
- sprintf(chMsg, "SimpleService error: %d", dwGlobalErr);
- lpszStrings[0] = chMsg;
- lpszStrings[1] = lpszMsg;
-
- if (hEventSource != NULL) {
- ReportEvent(hEventSource, // handle of event source
- EVENTLOG_ERROR_TYPE, // event type
- 0, // event category
- 0, // event ID
- NULL, // current user's SID
- 2, // strings in lpszStrings
- 0, // no bytes of raw data
- lpszStrings, // array of error strings
- NULL); // no raw data
-
- (VOID) DeregisterEventSource(hEventSource);
- }
-
- // Set a termination event to stop SERVICE MAIN FUNCTION.
- //
- SetEvent(hServDoneEvent);
- }
-
- /****************************************************************************\
- *
- * FUNCTION: WriteSD_ToA_File
- *
- \****************************************************************************/
-
- BOOL WriteSD_ToA_File(PSECURITY_DESCRIPTOR psdAbsoluteSD, LPTSTR lpszFileName)
- {
- DWORD dwErrorMode;
- BOOL bStatus;
-
- /**************************************************************************\
- *
- * SetErrorMode so we don't get the error due to no floppy disk in the floppy
- * drive
- *
- \**************************************************************************/
-
- dwErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
-
- /**************************************************************************\
- *
- * Write SD to file system
- *
- \**************************************************************************/
-
- bStatus = SetFileSecurity(lpszFileName,
- (SECURITY_INFORMATION)(DACL_SECURITY_INFORMATION),
- psdAbsoluteSD);
-
- /**************************************************************************\
- *
- * SetErrorMode back to its previous value
- *
- \**************************************************************************/
-
- SetErrorMode(dwErrorMode);
-
- if (!bStatus)
- { if (ERROR_FILE_NOT_FOUND == GetLastError())
- { printf("\nAttempted to lock %s, but it was not found",lpszFileName);
- }
- else
- { PERR("SetFileSecurity");
- return(FALSE);
- }
- }
-
- return(TRUE);
- }
-