|
|
1.1 root 1: /* Copyright (C) 2004 TrueCrypt Team, truecrypt.org
2: This product uses components written by Paul Le Roux <[email protected]> */
3:
4: #include "TCdefs.h"
5: #include <process.h>
6:
7: #include "ntservice.h"
8:
9: #include "crypto.h"
10: #include "apidrvr.h"
11:
12: #include "dismount.h"
13: #include <mountdev.h>
14:
15: /* current status of the service */
16: SERVICE_STATUS ssStatus;
17:
18: /* handle for reporting back to the SCM */
19: SERVICE_STATUS_HANDLE sshStatusHandle = 0;
20:
21: /* stop event; used at shutdown */
22: HANDLE hServerStopEvent = NULL;
23:
24: /* Handle to the device driver */
25: HANDLE hDriver = INVALID_HANDLE_VALUE;
26:
27: /* main() calls StartServiceCtrlDispatcher to register the main service
28: thread. When the this call returns, the service has stopped, so exit. */
29:
30: int main (int argc, char **argv)
31: {
32: SERVICE_TABLE_ENTRY dispatchTable[]=
33: {
34: {SZSERVICENAME, (LPSERVICE_MAIN_FUNCTION) service_main},
35: {NULL, NULL}
36: };
37:
38: if (StartServiceCtrlDispatcher (dispatchTable) == 0)
39: AddToMessageLog ("StartServiceCtrlDispatcher failed.");
40: }
41:
42: /* service_main, this routine performs the service initialization and then
43: calls the user defined ServiceStart() routine to perform majority of the
44: work. */
45:
46: void WINAPI
47: service_main (DWORD dwArgc, LPSTR * lpszArgv)
48: {
49: /* register our service control handler: */
50: sshStatusHandle = RegisterServiceCtrlHandler (SZSERVICENAME, service_ctrl);
51: if (sshStatusHandle == 0)
52: return;
53:
54: ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
55: ssStatus.dwServiceSpecificExitCode = 0;
56:
57: /* report the status to the service control manager. */
58: if (!ReportStatusToSCMgr (
59: SERVICE_START_PENDING, /* service state */
60: NO_ERROR, /* exit code */
61: 3000)) /* wait hint */
62: return;
63:
64: ServiceStart (dwArgc, lpszArgv);
65: }
66:
67: /* service_ctrl, this function is called by the SCM whenever ControlService()
68: is called on this service. */
69:
70: void WINAPI
71: service_ctrl (DWORD dwCtrlCode)
72: {
73: /* Handle the requested control code. */
74: switch (dwCtrlCode)
75: {
76: case SERVICE_CONTROL_STOP:
77: {
78: DWORD os_error;
79: int err;
80: UnmountAllVolumes (NULL, &os_error, &err);
81:
82: /* Stop the service. SERVICE_STOP_PENDING should be reported
83: before setting the Stop Event - hServerStopEvent - in
84: ServiceStop(). This avoids a race condition which may
85: result in a 1053 - The Service did not respond... error. */
86: ReportStatusToSCMgr (SERVICE_STOP_PENDING, NO_ERROR, 0);
87: ServiceStop ();
88: }
89: return;
90:
91: case SERVICE_CONTROL_SHUTDOWN:
92: {
93: DWORD os_error;
94: int err;
95: UnmountAllVolumes (NULL, &os_error, &err);
96: }
97: break;
98:
99: case SERVICE_CONTROL_INTERROGATE:
100: /* Update the service status. */
101: break;
102:
103: default:
104: /* invalid control code */
105: break;
106:
107: }
108:
109: ReportStatusToSCMgr (ssStatus.dwCurrentState, NO_ERROR, 0);
110: }
111:
112: /* ReportStatusToSCMgr, sets the current status of the service and reports it
113: to the Service Control Manager */
114:
115: BOOL
116: ReportStatusToSCMgr (DWORD dwCurrentState, /* the state of the service */
117: DWORD dwWin32ExitCode, /* error code to report */
118: DWORD dwWaitHint) /* worst case estimate to next
119: checkpoint */
120: {
121: static DWORD dwCheckPoint = 1;
122: BOOL fResult = TRUE;
123:
124: if (dwCurrentState == SERVICE_START_PENDING)
125: ssStatus.dwControlsAccepted = 0;
126: else
127: ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
128:
129: ssStatus.dwCurrentState = dwCurrentState;
130: ssStatus.dwWin32ExitCode = dwWin32ExitCode;
131: ssStatus.dwWaitHint = dwWaitHint;
132:
133: if ((dwCurrentState == SERVICE_RUNNING) ||
134: (dwCurrentState == SERVICE_STOPPED))
135: ssStatus.dwCheckPoint = 0;
136: else
137: ssStatus.dwCheckPoint = dwCheckPoint++;
138:
139: /* Report the status of the service to the service control manager. */
140:
141: if (!(fResult = SetServiceStatus (sshStatusHandle, &ssStatus)))
142: {
143: AddToMessageLog ("SetServiceStatus");
144: }
145:
146: return fResult;
147: }
148:
149:
150: /* AddToMessageLog, allows any thread to log an error message */
151:
152: void
153: AddToMessageLog (LPSTR lpszMsg)
154: {
155: char szMsg[256];
156: HANDLE hEventSource;
157: LPSTR lpszStrings[2];
158: DWORD dwErr = GetLastError ();
159:
160: /* Use event logging to log the error */
161:
162: hEventSource = RegisterEventSource (NULL, SZSERVICENAME);
163:
164: sprintf (szMsg, "%s error: %d", SZSERVICENAME, dwErr);
165: lpszStrings[0] = szMsg;
166: lpszStrings[1] = lpszMsg;
167:
168: if (hEventSource != NULL)
169: {
170: ReportEvent (hEventSource, /* handle of event source */
171: EVENTLOG_ERROR_TYPE, /* event type */
172: 0, /* event category */
173: 0, /* event ID */
174: NULL, /* current user 's SID */
175: 2, /* strings in lpszStrings */
176: 0, /* no bytes of raw data */
177: lpszStrings, /* array of error strings */
178: NULL); /* no raw data */
179:
180: DeregisterEventSource (hEventSource);
181: }
182: }
183:
184: /* GetLastErrorText, copies error message text to string */
185:
186: LPSTR
187: GetLastErrorText (LPSTR lpszBuf, DWORD dwSize)
188: {
189: DWORD dwRet;
190: LPSTR lpszTemp = NULL;
191:
192: dwRet = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
193: NULL,
194: GetLastError (),
195: LANG_NEUTRAL,
196: (LPSTR) & lpszTemp,
197: 0,
198: NULL);
199:
200: /* supplied buffer is not long enough */
201: if (dwRet == 0 || ((long) dwSize < (long) dwRet + 14))
202: lpszBuf[0] = '\0';
203: else
204: {
205: lpszTemp[lstrlen (lpszTemp) - 2] = '\0'; /* remove cr and newline
206: character */
207: sprintf (lpszBuf, "%s (0x%x)", lpszTemp, GetLastError ());
208: }
209:
210: if (lpszTemp != NULL)
211: LocalFree ((HLOCAL) lpszTemp);
212:
213: return lpszBuf;
214: }
215:
216: void
217: ServiceStart (DWORD dwArgc, LPTSTR * lpszArgv)
218: {
219: DWORD dwWait, dwResult = ERROR_GEN_FAILURE;
220: HANDLE hPipe = INVALID_HANDLE_VALUE;
221: HANDLE hEvents[2] = {NULL, NULL};
222: OVERLAPPED os;
223: PSECURITY_DESCRIPTOR pSD = NULL;
224: SECURITY_ATTRIBUTES sa;
225: TCHAR szIn[80];
226: TCHAR szOut[80];
227: LPTSTR lpszPipeName = "\\\\.\\pipe\\truecryptservice";
228: BOOL bRet;
229: DWORD cbRead;
230: DWORD cbWritten;
231:
232: if (!ReportStatusToSCMgr (
233: SERVICE_START_PENDING, /* service state */
234: NO_ERROR, /* exit code */
235: 3000)) /* wait hint */
236: goto error;
237:
238: hServerStopEvent = CreateEvent (
239: NULL, /* no security
240: attributes */
241: TRUE, /* manual reset event */
242: FALSE, /* not-signalled */
243: NULL); /* no name */
244:
245: if (hServerStopEvent == NULL)
246: goto error;
247:
248: if (!ReportStatusToSCMgr (
249: SERVICE_START_PENDING, /* service state */
250: NO_ERROR, /* exit code */
251: 3000)) /* wait hint */
252: goto error;
253:
254: /* Try to open a handle to the device driver. It will be closed
255: later. */
256: hDriver = CreateFile (WIN32_ROOT_PREFIX, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
257: if (hDriver == INVALID_HANDLE_VALUE)
258: {
259: handleWin32Error (NULL);
260: goto error;
261: }
262:
263: if (!ReportStatusToSCMgr (
264: SERVICE_START_PENDING, /* service state */
265: NO_ERROR, /* exit code */
266: 3000)) /* wait hint */
267: goto error;
268:
269: /* create the event object object use in overlapped i/o */
270: hEvents[1] = CreateEvent (
271: NULL, /* no security attributes */
272: TRUE, /* manual reset event */
273: FALSE, /* not-signalled */
274: NULL); /* no name */
275:
276: if (hEvents[1] == NULL)
277: goto error;
278:
279: if (!ReportStatusToSCMgr (
280: SERVICE_START_PENDING, /* service state */
281: NO_ERROR, /* exit code */
282: 3000)) /* wait hint */
283: goto error;
284:
285: /* create a security descriptor that allows anyone to write to the
286: pipe */
287: pSD = (PSECURITY_DESCRIPTOR) malloc (SECURITY_DESCRIPTOR_MIN_LENGTH);
288:
289: if (pSD == NULL)
290: goto error;
291:
292: if (InitializeSecurityDescriptor (pSD, SECURITY_DESCRIPTOR_REVISION) == 0)
293: goto error;
294:
295: /* add a NULL disc.ACL to the security descriptor. */
296: if (SetSecurityDescriptorDacl (pSD, TRUE, (PACL) NULL, FALSE) == 0)
297: goto error;
298:
299: sa.nLength = sizeof (sa);
300: sa.lpSecurityDescriptor = pSD;
301: sa.bInheritHandle = TRUE;
302:
303: if (!ReportStatusToSCMgr (
304: SERVICE_START_PENDING, /* service state */
305: NO_ERROR, /* exit code */
306: 3000)) /* wait hint */
307: goto error;
308:
309: hPipe = CreateNamedPipe (
310: lpszPipeName, /* name of pipe */
311: FILE_FLAG_OVERLAPPED |
312: PIPE_ACCESS_DUPLEX, /* pipe open mode */
313: PIPE_TYPE_MESSAGE |
314: PIPE_READMODE_MESSAGE |
315: PIPE_WAIT, /* pipe IO type */
316: 1, /* number of instances */
317: 0, /* size of outbuf (0 ==
318: allocate as necessary) */
319: 0, /* size of inbuf */
320: 1000, /* default time-out value */
321: &sa); /* security attributes */
322:
323: if (hPipe == INVALID_HANDLE_VALUE)
324: {
325: AddToMessageLog (TEXT ("Unable to create named pipe"));
326: goto error;
327: }
328:
329: hEvents[0] = hServerStopEvent;
330:
331: if (!ReportStatusToSCMgr (
332: SERVICE_RUNNING, /* service state */
333: NO_ERROR, /* exit code */
334: 0)) /* wait hint */
335: goto error;
336:
337: for (;;)
338: {
339: int nDosDriveNo = -1, err;
340: DWORD os_error;
341:
342: /* init the overlapped structure */
343: memset (&os, 0, sizeof (OVERLAPPED));
344: os.hEvent = hEvents[1];
345: ResetEvent (hEvents[1]);
346:
347: /* wait for a connection... */
348: ConnectNamedPipe (hPipe, &os);
349:
350: if (GetLastError ()== ERROR_IO_PENDING)
351: {
352: dwWait = WaitForMultipleObjects (2, hEvents, FALSE, INFINITE);
353: if (dwWait != WAIT_OBJECT_0 + 1) /* not overlapped i/o
354: event - error
355: occurred, */
356: break; /* or server stop signaled */
357: }
358:
359: /* init the overlapped structure */
360: memset (&os, 0, sizeof (OVERLAPPED));
361: os.hEvent = hEvents[1];
362: ResetEvent (hEvents[1]);
363:
364: /* grab whatever's coming through the pipe... */
365: bRet = ReadFile (
366: hPipe, /* file to read from */
367: szIn, /* address of input buffer */
368: sizeof (szIn), /* number of bytes to
369: read */
370: &cbRead, /* number of bytes read */
371: &os); /* overlapped stuff, not
372: needed */
373:
374: if (bRet == FALSE && (GetLastError ()== ERROR_IO_PENDING))
375: {
376: dwWait = WaitForMultipleObjects (2, hEvents, FALSE, INFINITE);
377: if (dwWait != WAIT_OBJECT_0 + 1) /* not overlapped i/o
378: event - error
379: occurred, */
380: break; /* or server stop signaled */
381: }
382:
383: sscanf (szIn, "%s %d", szOut, &nDosDriveNo);
384:
385: if (strcmp (szOut, "mount") == 0)
386: {
387: BOOL bResult;
388: HANDLE mountManager;
389: char dosName[3] = {0,':',0}, szDevice[64];
390:
391: dosName[0] = (char) (nDosDriveNo + 'A');
392: sprintf (szDevice, "%s%c", NT_MOUNT_PREFIX, dosName[0]);
393:
394: // Notify Mount Manager of volume arrival
395: mountManager = CreateFileW (MOUNTMGR_DOS_DEVICE_NAME, FILE_READ_DATA|FILE_WRITE_DATA, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
396: if(mountManager != INVALID_HANDLE_VALUE)
397: {
398: WCHAR arrVolume[64], tmp[] = {0,0};
399: char buf[200];
400: PMOUNTMGR_TARGET_NAME in = (PMOUNTMGR_TARGET_NAME) buf;
401:
402: tmp[0] = (WCHAR)dosName[0];
403: wcscpy (arrVolume, TC_MOUNT_PREFIX);
404: wcscat (arrVolume, tmp);
405:
406: in->DeviceNameLength = (USHORT) wcslen(arrVolume) * 2;
407: wcscpy(in->DeviceName, arrVolume);
408:
409: bResult = DeviceIoControl (mountManager, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, in,
410: sizeof (in->DeviceNameLength) + wcslen(arrVolume) * 2, 0, 0, &dwResult, NULL);
411:
412: CloseHandle (mountManager);
413: }
414:
415: // Create drive letter link
416: if(!DefineDosDevice (DDD_RAW_TARGET_PATH, dosName, szDevice))
417: sprintf (szOut, "-ERR 1 %d", GetLastError());
418: else
419: sprintf (szOut, "+OK mounted");
420:
421: }
422: else if (strcmp (szOut, "unmount") == 0)
423: {
424: if (UnmountVolume (nDosDriveNo, &os_error, &err) == FALSE)
425: {
426: sprintf (szOut, "-ERR %d %lu", err, os_error);
427: }
428: else
429: {
430: sprintf (szOut, "+OK unmounted");
431: }
432: }
433: else if (strcmp (szOut, "unmountall") == 0)
434: {
435: if (UnmountAllVolumes (NULL, &os_error, &err) == FALSE)
436: {
437: sprintf (szOut, "-ERR %d %lu", err, os_error);
438: }
439: else
440: {
441: sprintf (szOut, "+OK unmounted");
442: }
443: }
444: else
445: {
446: sprintf (szOut, "-ERR invalid command");
447: }
448:
449: /* init the overlapped structure */
450: memset (&os, 0, sizeof (OVERLAPPED));
451: os.hEvent = hEvents[1];
452: ResetEvent (hEvents[1]);
453:
454: /* send it back out... */
455: bRet = WriteFile (
456: hPipe, /* file to write to */
457: szOut, /* address of output buffer */
458: sizeof (szOut), /* number of bytes to
459: write */
460: &cbWritten, /* number of bytes
461: written */
462: &os); /* overlapped stuff, not
463: needed */
464:
465: if (bRet == FALSE && (GetLastError ()== ERROR_IO_PENDING))
466: {
467: dwWait = WaitForMultipleObjects (2, hEvents, FALSE, INFINITE);
468: if (dwWait != WAIT_OBJECT_0 + 1) /* not overlapped i/o
469: event - error
470: occurred, */
471: break; /* or server stop signaled */
472: }
473:
474: /* drop the connection... */
475: DisconnectNamedPipe (hPipe);
476: }
477:
478:
479: dwResult = NO_ERROR;
480:
481: error:
482: if (hServerStopEvent != NULL)
483: CloseHandle (hServerStopEvent);
484:
485: if (hEvents[1] != NULL)
486: CloseHandle (hEvents[1]);
487:
488: if (hDriver != INVALID_HANDLE_VALUE)
489: CloseHandle (hDriver);
490:
491: if (hPipe != INVALID_HANDLE_VALUE)
492: CloseHandle (hPipe);
493:
494: if (pSD != NULL)
495: free (pSD);
496:
497: ReportStatusToSCMgr (SERVICE_STOPPED, dwResult, 0);
498: }
499:
500: void
501: ServiceStop ()
502: {
503: if (hServerStopEvent != NULL)
504: SetEvent (hServerStopEvent);
505: }
506:
507: void
508: handleWin32Error (HWND dummy)
509: {
510: char tmp[256] =
511: {0};
512:
513: if (dummy); /* Remove warning */
514:
515: GetLastErrorText (tmp, sizeof (tmp));
516:
517: AddToMessageLog (tmp);
518: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.