Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(229)

Side by Side Diff: tpmd/windows/tpmd.c

Issue 660204: Upgrade to tpm-emulator version 0.7. (Closed)
Patch Set: Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tpmd/windows/control_tpmd.bat ('k') | tpmd_dev/CMakeLists.txt » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* Software-based Trusted Platform Module (TPM) Emulator
2 * Copyright (C) 2004-2010 Mario Strasser <mast@gmx.net>
3 * Copyright (C) 2009 Domenic Schroeder
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 2 of the License,
8 * or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * $Id: tpmd.c 389 2010-02-18 09:52:11Z mast $
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <stdarg.h>
24 #include <fcntl.h>
25 #include <sys/stat.h>
26 #include <sys/time.h>
27 #include <windows.h>
28 #include <wincrypt.h>
29 #include "config.h"
30 #include "tpm/tpm_emulator.h"
31
32 #define SERVICE_NAME "tpmd"
33
34 static volatile int stopflag = 0;
35 static int is_service = 0;
36 static int opt_debug = 0;
37 static int opt_foreground = 0;
38 static const char *opt_pipe_name = TPM_DEVICE_NAME;
39 static const char *opt_storage_file = TPM_STORAGE_NAME;
40 static const char *opt_log_file = TPM_LOG_FILE;
41 static int tpm_startup = 2;
42 static uint32_t tpm_config = 0;
43 static HCRYPTPROV rand_ch;
44 static SERVICE_STATUS_HANDLE status_handle;
45 static DWORD current_status;
46
47 void *tpm_malloc(size_t size)
48 {
49 return malloc(size);
50 }
51
52 void tpm_free(/*const*/ void *ptr)
53 {
54 if (ptr != NULL) free((void*)ptr);
55 }
56
57 void tpm_log(int priority, const char *fmt, ...)
58 {
59 FILE *file;
60 va_list ap, bp;
61 va_start(ap, fmt);
62 va_copy(bp, ap);
63 file = fopen(opt_log_file, "a");
64 if (file != NULL) {
65 vfprintf(file, fmt, ap);
66 fclose(file);
67 }
68 va_end(ap);
69 if (!is_service && (priority != TPM_LOG_DEBUG || opt_debug)) {
70 vprintf(fmt, bp);
71 }
72 va_end(bp);
73 }
74
75 void tpm_get_extern_random_bytes(void *buf, size_t nbytes)
76 {
77 CryptGenRandom(rand_ch, nbytes, (BYTE*)buf);
78 }
79
80 uint64_t tpm_get_ticks(void)
81 {
82 static uint64_t old_t = 0;
83 uint64_t new_t, res_t;
84 struct timeval tv;
85 gettimeofday(&tv, NULL);
86 new_t = (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec;
87 res_t = (old_t > 0) ? new_t - old_t : 0;
88 old_t = new_t;
89 return res_t;
90 }
91
92 int tpm_write_to_storage(uint8_t *data, size_t data_length)
93 {
94 int fh;
95 ssize_t res;
96 fh = open(opt_storage_file, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY,
97 S_IRUSR | S_IWUSR);
98 if (fh < 0) return -1;
99 while (data_length > 0) {
100 res = write(fh, data, data_length);
101 if (res < 0) {
102 close(fh);
103 return -1;
104 }
105 data_length -= res;
106 data += res;
107 }
108 close(fh);
109 return 0;
110 }
111
112 int tpm_read_from_storage(uint8_t **data, size_t *data_length)
113 {
114 int fh;
115 ssize_t res;
116 size_t total_length;
117 fh = open(opt_storage_file, O_RDONLY | O_BINARY);
118 if (fh < 0) return -1;
119 total_length = lseek(fh, 0, SEEK_END);
120 lseek(fh, 0, SEEK_SET);
121 *data = tpm_malloc(total_length);
122 if (*data == NULL) {
123 close(fh);
124 return -1;
125 }
126 *data_length = 0;
127 while (total_length > 0) {
128 res = read(fh, &(*data)[*data_length], total_length);
129 if (res < 0) {
130 close(fh);
131 tpm_free(*data);
132 return -1;
133 }
134 if (res == 0) break;
135 *data_length += res;
136 total_length -= res;
137 }
138 close(fh);
139 return 0;
140 }
141
142 static void print_usage(char *name)
143 {
144 printf("usage: %s [-d] [-f] [-s storage file] [-u windows pipe name] "
145 "[-l log file] [-h] [startup mode]\n", name);
146 printf(" d : enable debug mode\n");
147 printf(" f : forces the application to run in the foreground\n");
148 printf(" s : storage file to use (default: %s)\n", opt_storage_file);
149 printf(" u : windows named pipe name to use (default: %s)\n", opt_pipe_name );
150 printf(" l : name of the log file (default: %s)\n", opt_log_file);
151 printf(" h : print this help message\n");
152 printf(" startup mode : must be 'clear', "
153 "'save' (default) or 'deactivated\n");
154 }
155
156 static int parse_options(int argc, char **argv)
157 {
158 char c;
159 info("parsing options");
160 while ((c = getopt (argc, argv, "dfs:u:o:g:c:h")) != -1) {
161 debug("handling option '-%c'", c);
162 switch (c) {
163 case 'd':
164 opt_debug = 1;
165 debug("debug mode enabled");
166 break;
167 case 'f':
168 debug("application is forced to run in foreground");
169 opt_foreground = 1;
170 break;
171 case 's':
172 opt_storage_file = optarg;
173 debug("using storage file '%s'", opt_storage_file);
174 break;
175 case 'u':
176 opt_pipe_name = optarg;
177 debug("using named pipe '%s'", opt_pipe_name);
178 break;
179 case 'l':
180 opt_log_file = optarg;
181 debug("using log file '%s'", opt_log_file);
182 break;
183 case 'c':
184 tpm_config = strtol(optarg, NULL, 0);
185 break;
186 case '?':
187 error("unknown option '-%c'", optopt);
188 print_usage(argv[0]);
189 return -1;
190 case 'h':
191 default:
192 print_usage(argv[0]);
193 return -1;
194 }
195 }
196 if (optind < argc && argv[optind][0] != 0) {
197 debug("startup mode = '%s'", argv[optind]);
198 if (!strcmp(argv[optind], "clear")) {
199 tpm_startup = 1;
200 } else if (!strcmp(argv[optind], "save")) {
201 tpm_startup = 2;
202 } else if (!strcmp(argv[optind], "deactivated")) {
203 tpm_startup = 3;
204 } else {
205 error("invalid startup mode '%s'; must be 'clear', "
206 "'save' (default) or 'deactivated", argv[optind]);
207 print_usage(argv[0]);
208 return 0;
209 }
210 } else {
211 /* if no startup mode is given assume save if a configuration
212 file is available, clear otherwise */
213 int fh = open(opt_storage_file, O_RDONLY);
214 if (fh < 0) {
215 tpm_startup = 1;
216 info("no startup mode was specified; asuming 'clear'");
217 } else {
218 tpm_startup = 2;
219 close(fh);
220 }
221 }
222 return 0;
223 }
224
225 static const char *get_error(void)
226 {
227 static char buf[512];
228 memset(buf, 0, sizeof(buf));
229 FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
230 "", GetLastError(), 0, buf, sizeof(buf), NULL);
231 return buf;
232 }
233
234 static int init_random(void)
235 {
236 info("initializing crypto context for RNG");
237 BOOL res = CryptAcquireContext(&rand_ch, NULL, NULL,
238 PROV_RSA_FULL, CRYPT_SILENT);
239 if (!res) {
240 /* try it again with CRYPT_NEWKEYSET enabled */
241 res = CryptAcquireContext(&rand_ch, NULL, NULL,
242 PROV_RSA_FULL, CRYPT_SILENT | CRYPT_NEWKEYSET) ;
243 }
244 if (!res) {
245 error("CryptAcquireContext() failed: %s", get_error());
246 return -1;
247 }
248 return 0;
249 }
250
251 BOOL signal_handler(DWORD event)
252 {
253 info("signal received: %d", event);
254 stopflag = 1;
255 /* unblock ConnectNamedPipe() */
256 HANDLE ph = CreateFile(opt_pipe_name, GENERIC_READ | GENERIC_WRITE,
257 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
258 if (ph != INVALID_HANDLE_VALUE) CloseHandle(ph);
259 return TRUE;
260 }
261
262 static int init_signal_handler(void)
263 {
264 info("installing signal handler");
265 if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)signal_handler,TRUE)) {
266 error("SetConsoleCtrlHandler() failed: %s", get_error());
267 return -1;
268 }
269 return 0;
270 }
271
272 static int mkdirs(const char *path)
273 {
274 char *copy = strdup(path);
275 char *p = strchr(copy + 1, '/');
276 while (p != NULL) {
277 *p = '\0';
278 if ((mkdir(copy) == -1) && (errno != EEXIST)) {
279 free(copy);
280 return errno;
281 }
282 *p = '/';
283 p = strchr(p + 1, '/');
284 }
285 free(copy);
286 return 0;
287 }
288
289 static void main_loop(void)
290 {
291 HANDLE ph;
292 DWORD in_len;
293 uint32_t out_len;
294 BYTE in[TPM_CMD_BUF_SIZE];
295 uint8_t *out;
296
297 info("staring main loop");
298 /* open named pipe */
299 ph = CreateNamedPipe(opt_pipe_name, PIPE_ACCESS_DUPLEX,
300 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
301 PIPE_UNLIMITED_INSTANCES, TPM_CMD_BUF_SIZE,
302 TPM_CMD_BUF_SIZE, 0, NULL);
303 if (ph == INVALID_HANDLE_VALUE) {
304 error("CreateNamedPipe() failed: %s", get_error());
305 return;
306 }
307 /* init tpm emulator */
308 mkdirs(opt_storage_file);
309 debug("initializing TPM emulator");
310 tpm_emulator_init(tpm_startup, tpm_config);
311 /* start command processing */
312 while (!stopflag) {
313 /* wait for incomming connections */
314 debug("waiting for connections...");
315 if (!ConnectNamedPipe(ph, NULL)) {
316 error("ConnectNamedPipe() failed: %s", get_error());
317 break;
318 }
319 if (stopflag) break;
320 /* receive and handle commands */
321 in_len = 0;
322 do {
323 if (!ReadFile(ph, in, sizeof(in), &in_len, NULL)) {
324 error("ReadFile() failed: %s", get_error());
325 }
326 if (in_len > 0) {
327 debug("received %d bytes", in_len);
328 out = NULL;
329 if (tpm_handle_command(in, in_len, &out, &out_len) != 0) {
330 error("tpm_handle_command() failed");
331 } else {
332 debug("sending %d bytes", out_len);
333 DWORD res, len = 0;
334 while (len < out_len) {
335 if (!WriteFile(ph, out, out_len, &res, NULL)) {
336 error("WriteFile(%d) failed: %s",
337 out_len - len, strerror(errno));
338 break;
339 }
340 len += res;
341 }
342 tpm_free(out);
343 }
344 }
345 } while (in_len > 0 && !stopflag);
346 DisconnectNamedPipe(ph);
347 }
348 /* shutdown tpm emulator */
349 tpm_emulator_shutdown();
350 /* close socket */
351 CloseHandle(ph);
352 info("main loop stopped");
353 }
354
355 BOOL updateServiceStatus(DWORD currentState, DWORD winExitCode,
356 DWORD exitCode, DWORD checkPoint, DWORD waitHint)
357 {
358 SERVICE_STATUS status;
359
360 /* if this is a service update the status, otherwise return success */
361 if (!is_service) return TRUE;
362 current_status = currentState;
363 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
364 status.dwCurrentState = currentState;
365 /* once the service is up and running, it accepts
366 the events stop and shutdown */
367 if (currentState == SERVICE_START_PENDING) {
368 status.dwControlsAccepted = 0;
369 } else {
370 status.dwControlsAccepted = SERVICE_ACCEPT_STOP
371 | SERVICE_ACCEPT_SHUTDOWN;
372 }
373 status.dwWin32ExitCode = winExitCode;
374 status.dwServiceSpecificExitCode = exitCode;
375 status.dwCheckPoint = checkPoint;
376 status.dwWaitHint = waitHint;
377 return SetServiceStatus(status_handle, &status);
378 }
379
380 void serviceCtrlHandler(DWORD code)
381 {
382 switch (code) {
383 /* stop service if told so or in the case of a system shutdown */
384 case SERVICE_CONTROL_STOP:
385 case SERVICE_CONTROL_SHUTDOWN:
386 updateServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000);
387 signal_handler(CTRL_CLOSE_EVENT);
388 break;
389 /* report the current status of the service to the SCM */
390 case SERVICE_CONTROL_INTERROGATE:
391 updateServiceStatus(current_status, NO_ERROR, 0, 0, 0);
392 break;
393 }
394 }
395
396 void serviceMain(int argc, char **argv)
397 {
398 info("starting TPM Emulator daemon (1.2.%d.%d-%d)",
399 VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD);
400 /* first of all register the control handler function of the service */
401 if (is_service) {
402 status_handle = RegisterServiceCtrlHandler(
403 SERVICE_NAME, (LPHANDLER_FUNCTION)serviceCtrlHandler);
404 }
405 if (argc > 0 && parse_options(argc, argv) != 0) {
406 updateServiceStatus(SERVICE_STOPPED,
407 ERROR_SERVICE_SPECIFIC_ERROR, 1, 0, 0);
408 return;
409 }
410 /* init logging */
411 mkdirs(opt_log_file);
412 /* init signal handler */
413 if (init_signal_handler() != 0) {
414 updateServiceStatus(SERVICE_STOPPED,
415 ERROR_SERVICE_SPECIFIC_ERROR, 1, 0, 0);
416 return;
417 }
418 /* init random number generator */
419 if (init_random() != 0) {
420 updateServiceStatus(SERVICE_STOPPED,
421 ERROR_SERVICE_SPECIFIC_ERROR, 1, 0, 0);
422 return;
423 }
424 /* start main processing loop */
425 updateServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);
426 main_loop();
427 info("stopping TPM Emulator daemon");
428 CryptReleaseContext(rand_ch, 0);
429 updateServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0, 0);
430 }
431
432 int main(int argc, char **argv)
433 {
434 if (parse_options(argc, argv) != 0) return EXIT_FAILURE;
435 if (opt_foreground) {
436 is_service = 0;
437 serviceMain(0, NULL);
438 return EXIT_SUCCESS;
439 } else {
440 SERVICE_TABLE_ENTRY service_table[] = {
441 { (LPTSTR)SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)serviceMain },
442 { NULL, NULL } };
443 is_service = 1;
444 StartServiceCtrlDispatcher(service_table);
445 return GetLastError();
446 }
447 }
448
OLDNEW
« no previous file with comments | « tpmd/windows/control_tpmd.bat ('k') | tpmd_dev/CMakeLists.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698