xref: /netbsd-src/crypto/external/cpl/trousers/dist/src/tcsd/tcsd_conf.c (revision f89f6560d453f5e37386cc7938c072d2f528b9fa)
1 
2 /*
3  * Licensed Materials - Property of IBM
4  *
5  * trousers - An open source TCG Software Stack
6  *
7  * (C) Copyright International Business Machines Corp. 2004
8  *
9  */
10 
11 
12 #include <stdio.h>
13 #include <pwd.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <ctype.h>
18 #include <string.h>
19 #include <strings.h>
20 #include <errno.h>
21 #include <grp.h>
22 #include <stdlib.h>
23 
24 #ifdef SOLARIS
25 #include <libscf.h>
26 #endif
27 
28 #include "trousers/tss.h"
29 #include "trousers_types.h"
30 #include "tcs_tsp.h"
31 #include "tcs_utils.h"
32 #include "tcsps.h"
33 #include "tcslog.h"
34 #include "tcsd_wrap.h"
35 #include "tcsd.h"
36 #include "tcsd_ops.h"
37 
38 
39 struct tcsd_config_options options_list[] = {
40 	{"port", opt_port},
41 	{"num_threads", opt_max_threads},
42 	{"system_ps_file", opt_system_ps_file},
43 	{"firmware_log_file", opt_firmware_log},
44 	{"firmware_pcrs", opt_firmware_pcrs},
45 	{"kernel_log_file", opt_kernel_log},
46 	{"kernel_pcrs", opt_kernel_pcrs},
47 	{"platform_cred", opt_platform_cred},
48 	{"conformance_cred", opt_conformance_cred},
49 	{"endorsement_cred", opt_endorsement_cred},
50 	{"remote_ops", opt_remote_ops},
51 	{"enforce_exclusive_transport", opt_exclusive_transport},
52 	{"host_platform_class", opt_host_platform_class},
53 	{"all_platform_classes", opt_all_platform_classes},
54 	{NULL, 0}
55 };
56 
57 struct tcg_platform_spec tcg_platform_specs[] = {
58 	{"PC_11", TPM_PS_PC_11, TPM_PS_PC_11_URI},
59 	{"PC_12", TPM_PS_PC_12, TPM_PS_PC_12_URI},
60 	{"PDA_12", TPM_PS_PDA_12, TPM_PS_PDA_12_URI},
61 	{"SERVER_12", TPM_PS_Server_12, TPM_PS_Server_12_URI},
62 	{"MOBILE_12", TPM_PS_Mobile_12, TPM_PS_Mobile_12_URI},
63 	{NULL, 0, 0}
64 };
65 
66 
67 void
68 init_tcsd_config(struct tcsd_config *conf)
69 {
70 	conf->port = -1;
71 	conf->num_threads = -1;
72 	conf->system_ps_file = NULL;
73 	conf->system_ps_dir = NULL;
74 	conf->firmware_log_file = NULL;
75 	conf->firmware_pcrs = 0;
76 	conf->kernel_log_file = NULL;
77 	conf->kernel_pcrs = 0;
78 	conf->platform_cred = NULL;
79 	conf->conformance_cred = NULL;
80 	conf->endorsement_cred = NULL;
81 	memset(conf->remote_ops, 0, sizeof(conf->remote_ops));
82 	conf->unset = 0xffffffff;
83 	conf->exclusive_transport = 0;
84 	conf->host_platform_class = NULL;
85 	conf->all_platform_classes = NULL;
86 }
87 
88 TSS_RESULT
89 platform_class_list_append(struct tcsd_config *conf, char *specName, TSS_BOOL is_main)
90 {
91 	int i;
92 	struct platform_class *tmp, *new_class;
93 
94 	LogDebugFn("platform_class_list_append start:");
95 	for (i = 0; tcg_platform_specs[i].name; i++) {
96 		if (!strncasecmp(specName, tcg_platform_specs[i].name,
97 				 strlen(tcg_platform_specs[i].name))) {
98 			/* Allocate the new structure */
99 			new_class = malloc(sizeof(struct platform_class));
100 			if (new_class == NULL) {
101 				LogError("malloc of %zd bytes failed",
102 					 sizeof(struct platform_class));
103 				return TCSERR(TSS_E_OUTOFMEMORY);
104 			}
105 			new_class->simpleID = tcg_platform_specs[i].specNo;
106 			new_class->classURISize = strlen(tcg_platform_specs[i].specURI) + 1;
107 			new_class->classURI = malloc(new_class->classURISize);
108 			if (new_class->classURI == NULL) {
109 				LogError("malloc of %u bytes failed", new_class->classURISize);
110 				return TCSERR(TSS_E_OUTOFMEMORY);
111 			}
112 			memcpy(new_class->classURI, tcg_platform_specs[i].specURI,
113 			       new_class->classURISize);
114 
115 			/* Append to the start of the list */
116 			if (is_main) {
117 				tmp = conf->host_platform_class;
118 				conf->host_platform_class = new_class;
119 			} else {
120 				tmp = conf->all_platform_classes;
121 				conf->all_platform_classes = new_class;
122 			}
123 			new_class->next = tmp;
124 
125 			LogDebugFn("Platform Class Added.");
126 			return TSS_SUCCESS;
127 		}
128 	}
129 
130 	LogError("TCG Specification not supported: \"%s\"", specName);
131 	return TCSERR(TSS_E_INTERNAL_ERROR);
132 }
133 
134 void
135 config_set_defaults(struct tcsd_config *conf)
136 {
137 	/* give all unset options their default values */
138 	if (conf->unset & TCSD_OPTION_PORT)
139 		conf->port = TCSD_DEFAULT_PORT;
140 
141 	if (conf->unset & TCSD_OPTION_MAX_THREADS)
142 		conf->num_threads = TCSD_DEFAULT_MAX_THREADS;
143 
144 	if (conf->unset & TCSD_OPTION_FIRMWARE_PCRS)
145 		conf->firmware_pcrs = TCSD_DEFAULT_FIRMWARE_PCRS;
146 
147 	if (conf->unset & TCSD_OPTION_KERNEL_PCRS)
148 		conf->kernel_pcrs = TCSD_DEFAULT_KERNEL_PCRS;
149 
150 	/* these are strdup'd so we know we can free them at shutdown time */
151 	if (conf->unset & TCSD_OPTION_SYSTEM_PSFILE) {
152 		conf->system_ps_file = strdup(TCSD_DEFAULT_SYSTEM_PS_FILE);
153 		conf->system_ps_dir = strdup(TCSD_DEFAULT_SYSTEM_PS_DIR);
154 	}
155 
156 	if (conf->unset & TCSD_OPTION_FIRMWARE_LOGFILE)
157 		conf->firmware_log_file = strdup(TCSD_DEFAULT_FIRMWARE_LOG_FILE);
158 
159 	if (conf->unset & TCSD_OPTION_KERNEL_LOGFILE)
160 		conf->kernel_log_file = strdup(TCSD_DEFAULT_KERNEL_LOG_FILE);
161 
162 	if (conf->unset & TCSD_OPTION_HOST_PLATFORM_CLASS)
163 		platform_class_list_append(conf, "PC_12", TRUE);
164 }
165 
166 int
167 get_config_option(char *ptr, char **arg)
168 {
169 	int i;
170 
171 	for (i = 0; options_list[i].name; i++) {
172 		if (!strncasecmp(ptr, options_list[i].name, strlen(options_list[i].name))) {
173 			/* move ptr past our recognized token */
174 			ptr += strlen(options_list[i].name);
175 
176 			/* try to move ptr to the start of the option's argument */
177 			while (*ptr == '=' || *ptr == ' ' || *ptr == '\t')
178 				ptr++;
179 
180 			*arg = ptr;
181 			return options_list[i].option;
182 		}
183 	}
184 	/* on error we'll print the whole line to the log */
185 	*arg = ptr;
186 	return 0;
187 }
188 
189 /* copy a file path from a string into a newly malloc'd string */
190 int
191 get_file_path(char *ptr, char **dest)
192 {
193 	char tmp_buf[1024];
194 	int i = 0;
195 
196 	while (isalpha((unsigned char)*ptr) || isdigit((unsigned char)*ptr) ||
197 		*ptr == '/' || *ptr == '.' || *ptr == '#' || *ptr == '_' || *ptr == '-')
198 	{
199 		tmp_buf[i] = *ptr;
200 		ptr++;
201 		i++;
202 	}
203 
204 	/* move through whitespace after the path */
205 	while (*ptr == ' ' || *ptr == '\t')
206 		ptr++;
207 
208 	/* if we're not at a comment or EOL, there's junk */
209 	if (*ptr != '#' && *ptr != '\n') {
210 		*dest = ptr;
211 		return 1;
212 	}
213 
214 	/* too short a path */
215 	if (i == 0)
216 		return -1;
217 
218 	tmp_buf[i] = '\0';
219 	*dest = strdup(tmp_buf);
220 	if (*dest == NULL) {
221 		LogError("malloc of %zd bytes failed", strlen(tmp_buf));
222 	}
223 
224 	return 0;
225 }
226 
227 /* add an op ordinal, checking for duplicates along the way */
228 void
229 tcsd_add_op(int *remote_ops, int *op)
230 {
231 	int i = 0, j;
232 
233 	while (op[i] != 0) {
234 		j = 0;
235 		while (remote_ops[j] != 0) {
236 			if (remote_ops[j] == op[i]) {
237 				break;
238 			}
239 			j++;
240 		}
241 		remote_ops[j] = op[i];
242 		i++;
243 	}
244 }
245 
246 int
247 tcsd_set_remote_op(struct tcsd_config *conf, char *op_name)
248 {
249 	int i = 0;
250 
251 	while(tcsd_ops[i]) {
252 		if (!strcasecmp(tcsd_ops[i]->name, op_name)) {
253 			/* match found */
254 			tcsd_add_op(conf->remote_ops, tcsd_ops[i]->op);
255 			return 0;
256 		}
257 		i++;
258 	}
259 
260 	/* fail, op not found */
261 	return 1;
262 }
263 
264 TSS_RESULT
265 read_conf_line(char *buf, int line_num, struct tcsd_config *conf)
266 {
267 	char *ptr = buf, *tmp_ptr = NULL, *arg, *comma;
268 	int option, tmp_int;
269 	TSS_RESULT result;
270 
271 	if (ptr == NULL || *ptr == '\0' || *ptr == '#' || *ptr == '\n')
272 		return TSS_SUCCESS;
273 
274 	/* read through whitespace */
275 	while (*ptr == ' ' || *ptr == '\t')
276 		ptr++;
277 
278 	/* ignore comments */
279 	if (*ptr == '#')
280 		return TSS_SUCCESS;
281 
282 	option = get_config_option(ptr, &arg);
283 
284 	switch (option) {
285         case opt_port:
286 		tmp_int = atoi(arg);
287 		if (tmp_int < 0 || tmp_int > 65535) {
288 			LogError("Config option \"port\" out of range. %s:%d: \"%d\"",
289 					tcsd_config_file, line_num, tmp_int);
290 			return TCSERR(TSS_E_INTERNAL_ERROR);
291 		} else {
292 			conf->port = tmp_int;
293 			conf->unset &= ~TCSD_OPTION_PORT;
294 		}
295 		break;
296 	case opt_max_threads:
297 		tmp_int = atoi(arg);
298 		if (tmp_int <= 0) {
299 			LogError("Config option \"num_threads\" out of range. %s:%d: \"%d\"",
300 					tcsd_config_file, line_num, tmp_int);
301 			return TCSERR(TSS_E_INTERNAL_ERROR);
302 		} else {
303 			conf->num_threads = tmp_int;
304 			conf->unset &= ~TCSD_OPTION_MAX_THREADS;
305 		}
306 		break;
307 	case opt_firmware_pcrs:
308 		conf->unset &= ~TCSD_OPTION_FIRMWARE_PCRS;
309 		while (1) {
310 			comma = rindex(arg, ',');
311 
312 			if (comma == NULL) {
313 				if (!isdigit((unsigned char)*arg))
314 					break;
315 
316 				comma = arg;
317 				tmp_int = atoi(comma);
318 				if (tmp_int >= 0 && tmp_int < TCSD_MAX_PCRS)
319 					conf->firmware_pcrs |= (1 << tmp_int);
320 				else
321 					LogError("Config option \"firmware_pcrs\" is out of range."
322 						 "%s:%d: \"%d\"", tcsd_config_file, line_num,
323 						 tmp_int);
324 				break;
325 			}
326 
327 			*comma++ = '\0';
328 			tmp_int = atoi(comma);
329 			if (tmp_int >= 0 && tmp_int < TCSD_MAX_PCRS)
330 				conf->firmware_pcrs |= (1 << tmp_int);
331 			else
332 				LogError("Config option \"firmware_pcrs\" is out of range. "
333 					 "%s:%d: \"%d\"", tcsd_config_file, line_num, tmp_int);
334 		}
335 		break;
336 	case opt_kernel_pcrs:
337 		conf->unset &= ~TCSD_OPTION_KERNEL_PCRS;
338 		while (1) {
339 			comma = rindex(arg, ',');
340 
341 			if (comma == NULL) {
342 				if (!isdigit((unsigned char)*arg))
343 					break;
344 
345 				comma = arg;
346 				tmp_int = atoi(comma);
347 				if (tmp_int >= 0 && tmp_int < TCSD_MAX_PCRS)
348 					conf->kernel_pcrs |= (1 << tmp_int);
349 				else
350 					LogError("Config option \"kernel_pcrs\" is out of range. "
351 						 "%s:%d: \"%d\"", tcsd_config_file, line_num,
352 						 tmp_int);
353 				break;
354 			}
355 
356 			*comma++ = '\0';
357 			tmp_int = atoi(comma);
358 			if (tmp_int >= 0 && tmp_int < TCSD_MAX_PCRS)
359 				conf->kernel_pcrs |= (1 << tmp_int);
360 			else
361 				LogError("Config option \"kernel_pcrs\" is out of range. "
362 					 "%s:%d: \"%d\"", tcsd_config_file, line_num, tmp_int);
363 		}
364 		break;
365 	case opt_system_ps_file:
366 		if (*arg != '/') {
367 			LogError("Config option \"system_ps_dir\" must be an absolute path name. "
368 				 "%s:%d: \"%s\"", tcsd_config_file, line_num, arg);
369 		} else {
370 			char *dir_ptr;
371 			int rc;
372 
373 			if ((rc = get_file_path(arg, &tmp_ptr)) < 0) {
374 				LogError("Config option \"system_ps_file\" is invalid."
375 					 " %s:%d: \"%s\"", tcsd_config_file, line_num, arg);
376 				return TCSERR(TSS_E_INTERNAL_ERROR);
377 			} else if (rc > 0) {
378 				LogError("Config option \"system_ps_file\" is invalid. %s:%d:"
379 					 " \"%s\"", tcsd_config_file, line_num, tmp_ptr);
380 				return TCSERR(TSS_E_INTERNAL_ERROR);
381 			}
382 			if (tmp_ptr == NULL)
383 				return TCSERR(TSS_E_OUTOFMEMORY);
384 
385 			if (conf->system_ps_file)
386 				free(conf->system_ps_file);
387 			if (conf->system_ps_dir)
388 				free(conf->system_ps_dir);
389 
390 			/* break out the system ps directory from the file path */
391 			dir_ptr = rindex(tmp_ptr, '/');
392 			*dir_ptr = '\0';
393 			if (strlen(tmp_ptr) == 0)
394 				conf->system_ps_dir = strdup("/");
395 			else
396 				conf->system_ps_dir = strdup(tmp_ptr);
397 
398 			if (conf->system_ps_dir == NULL) {
399 				LogError("malloc failed.");
400 				free(tmp_ptr);
401 				return TCSERR(TSS_E_OUTOFMEMORY);
402 			}
403 			*dir_ptr = '/';
404 			conf->system_ps_file = tmp_ptr;
405 			conf->unset &= ~TCSD_OPTION_SYSTEM_PSFILE;
406 		}
407 		break;
408 	case opt_kernel_log:
409 		if (*arg != '/') {
410 			LogError("Config option \"kernel_log\" must be an absolute path name."
411 				 " %s:%d: \"%s\"", tcsd_config_file, line_num, arg);
412 		} else {
413 			int rc;
414 
415 			if ((rc = get_file_path(arg, &tmp_ptr)) < 0) {
416 				LogError("Config option \"kernel_log\" is invalid. %s:%d: \"%s\"",
417 					 tcsd_config_file, line_num, arg);
418 				return TCSERR(TSS_E_INTERNAL_ERROR);
419 			} else if (rc > 0) {
420 				LogError("Config option \"kernel_log\" is invalid. %s:%d: \"%s\"",
421 					 tcsd_config_file, line_num, tmp_ptr);
422 				return TCSERR(TSS_E_INTERNAL_ERROR);
423 			}
424 			if (tmp_ptr == NULL)
425 				return TCSERR(TSS_E_OUTOFMEMORY);
426 
427 			if (conf->kernel_log_file)
428 				free(conf->kernel_log_file);
429 
430 			conf->kernel_log_file = tmp_ptr;
431 			conf->unset &= ~TCSD_OPTION_KERNEL_LOGFILE;
432 		}
433 		break;
434 	case opt_firmware_log:
435 		if (*arg != '/') {
436 			LogError("Config option \"firmware_log\" must be an absolute path name."
437 				 " %s:%d: \"%s\"", tcsd_config_file, line_num, arg);
438 		} else {
439 			int rc;
440 
441 			if ((rc = get_file_path(arg, &tmp_ptr)) < 0) {
442 				LogError("Config option \"firmware_log\" is invalid. %s:%d: \"%s\"",
443 					 tcsd_config_file, line_num, arg);
444 				return TCSERR(TSS_E_INTERNAL_ERROR);
445 			} else if (rc > 0) {
446 				LogError("Config option \"firmware_log\" is invalid. %s:%d: \"%s\"",
447 					 tcsd_config_file, line_num, tmp_ptr);
448 				return TCSERR(TSS_E_INTERNAL_ERROR);
449 			}
450 			if (tmp_ptr == NULL)
451 				return TCSERR(TSS_E_OUTOFMEMORY);
452 
453 			if (conf->firmware_log_file)
454 				free(conf->firmware_log_file);
455 
456 			conf->firmware_log_file = tmp_ptr;
457 			conf->unset &= ~TCSD_OPTION_FIRMWARE_LOGFILE;
458 		}
459 		break;
460 	case opt_platform_cred:
461 		if (*arg != '/') {
462 			LogError("Config option \"platform_cred\" must be an absolute path name. "
463                                  "%s:%d: \"%s\"", tcsd_config_file, line_num, arg);
464 		} else {
465 			int rc;
466 
467 			if ((rc = get_file_path(arg, &tmp_ptr)) < 0) {
468 				LogError("Config option \"platform_cred\" is invalid. %s:%d: "
469                                          "\"%s\"", tcsd_config_file, line_num, arg);
470 				return TCSERR(TSS_E_INTERNAL_ERROR);
471 			} else if (rc > 0) {
472 				LogError("Config option \"platform_cred\" is invalid. %s:%d: "
473                                          "\"%s\"", tcsd_config_file, line_num, tmp_ptr);
474 				return TCSERR(TSS_E_INTERNAL_ERROR);
475 			}
476 			if (tmp_ptr == NULL)
477 				return TCSERR(TSS_E_OUTOFMEMORY);
478 
479 			if (conf->platform_cred)
480 				free(conf->platform_cred);
481 
482 			conf->platform_cred = tmp_ptr;
483 			conf->unset &= ~TCSD_OPTION_PLATFORM_CRED;
484 		}
485 		break;
486 	case opt_conformance_cred:
487 		if (*arg != '/') {
488 			LogError("Config option \"conformance_cred\" must be an absolute path name."
489                                  " %s:%d: \"%s\"", tcsd_config_file, line_num, arg);
490 		} else {
491 			int rc;
492 
493 			if ((rc = get_file_path(arg, &tmp_ptr)) < 0) {
494 				LogError("Config option \"conformance_cred\" is invalid. %s:%d: "
495                                          "\"%s\"", tcsd_config_file, line_num, arg);
496 				return TCSERR(TSS_E_INTERNAL_ERROR);
497 			} else if (rc > 0) {
498 				LogError("Config option \"conformance_cred\" is invalid. %s:%d: "
499                                          "\"%s\"", tcsd_config_file, line_num, tmp_ptr);
500 				return TCSERR(TSS_E_INTERNAL_ERROR);
501 			}
502 			if (tmp_ptr == NULL)
503 				return TCSERR(TSS_E_OUTOFMEMORY);
504 
505 			if (conf->conformance_cred)
506 				free(conf->conformance_cred);
507 
508 			conf->conformance_cred = tmp_ptr;
509 			conf->unset &= ~TCSD_OPTION_CONFORMANCE_CRED;
510 		}
511 		break;
512 	case opt_endorsement_cred:
513 		if (*arg != '/') {
514 			LogError("Config option \"endorsement_cred\" must be an absolute path name."
515                                  " %s:%d: \"%s\"", tcsd_config_file, line_num, arg);
516 		} else {
517 			int rc;
518 
519 			if ((rc = get_file_path(arg, &tmp_ptr)) < 0) {
520 				LogError("Config option \"endorsement_cred\" is invalid. %s:%d: "
521                                          "\"%s\"", tcsd_config_file, line_num, arg);
522 				return TCSERR(TSS_E_INTERNAL_ERROR);
523 			} else if (rc > 0) {
524 				LogError("Config option \"endorsement_cred\" is invalid. %s:%d: "
525                                          "\"%s\"", tcsd_config_file, line_num, tmp_ptr);
526 				return TCSERR(TSS_E_INTERNAL_ERROR);
527 			}
528 			if (tmp_ptr == NULL)
529 				return TCSERR(TSS_E_OUTOFMEMORY);
530 
531 			if (conf->endorsement_cred)
532 				free(conf->endorsement_cred);
533 
534 			conf->endorsement_cred = tmp_ptr;
535 			conf->unset &= ~TCSD_OPTION_ENDORSEMENT_CRED;
536 		}
537 		break;
538 	case opt_remote_ops:
539 		conf->unset &= ~TCSD_OPTION_REMOTE_OPS;
540 		comma = rindex(arg, '\n');
541 		*comma = '\0';
542 		while (1) {
543 			comma = rindex(arg, ',');
544 
545 			if (comma == NULL) {
546 				comma = arg;
547 
548 				if (comma != NULL) {
549 					if (tcsd_set_remote_op(conf, comma)) {
550 						LogError("Config option \"remote_ops\" is invalid. "
551 							 "%s:%d: \"%s\"", tcsd_config_file,
552 							 line_num, comma);
553 					}
554 				}
555 				break;
556 			}
557 
558 			*comma++ = '\0';
559 			if (tcsd_set_remote_op(conf, comma)) {
560 				LogError("Config option \"remote_ops\" is invalid. "
561 					 "%s:%d: \"%s\"", tcsd_config_file, line_num, comma);
562 			}
563 		}
564 		break;
565         case opt_exclusive_transport:
566 		tmp_int = atoi(arg);
567 		if (tmp_int < 0 || tmp_int > 1) {
568 			LogError("Config option \"enforce_exclusive_transport\" out of range."
569 				 " %s:%d: \"%d\"", tcsd_config_file, line_num, tmp_int);
570 			return TCSERR(TSS_E_INTERNAL_ERROR);
571 		} else {
572 			conf->exclusive_transport = tmp_int;
573 			conf->unset &= ~TCSD_OPTION_EXCLUSIVE_TRANSPORT;
574 		}
575 		break;
576 	case opt_host_platform_class:
577 		/* append the host class on the list */
578 		conf->unset &= ~TCSD_OPTION_HOST_PLATFORM_CLASS;
579 		comma = rindex(arg,'\n');
580 		*comma = '\0';
581 
582 		comma = rindex(arg,',');
583 		/* At least one comma: error - more than one host class defined */
584 		if (comma != NULL) {
585 			LogError("Config option \"host_platform_class\" error: more than one "
586 				 "defined. %s:%d: \"%s\"", tcsd_config_file, line_num, comma);
587 			return TCSERR(TSS_E_INTERNAL_ERROR);
588 		} else {
589 			comma = arg;
590 			/* Add the platform class on the list */
591 			if ((result = platform_class_list_append(conf, comma, TRUE))){
592 				LogError("Config option \"host_platform_class\" invalid. "
593 					 "%s:%d: \"%s\"", tcsd_config_file, line_num, comma);
594 				return result;
595 			}
596 		}
597 		break;
598 	case opt_all_platform_classes:
599 		/* append each of the comma separated values on the list */
600 		comma = rindex(arg, '\n');
601 		*comma = '\0';
602 		while (1) {
603 			comma = rindex(arg, ',');
604 
605 			if (comma == NULL) {
606 				comma = arg;
607 
608 				if (comma != NULL) {
609 					/* Add the platform class on the list */
610 					if ((result = platform_class_list_append(conf, comma,
611 										 FALSE))) {
612 						LogError("Config option \"all_platform_class\" "
613 							 "invalid. %s:%d: \"%s\"", tcsd_config_file,
614 							 line_num, comma);
615 						return result;
616 					}
617 				}
618 				break;
619 			}
620 			*comma++ = '\0';
621 			/* Add the platform class on the list */
622 			if ((result = platform_class_list_append(conf, comma, FALSE))) {
623 				LogError("Config option \"all_platform_class\" invalid. "
624 					 "%s:%d: \"%s\"", tcsd_config_file, line_num, comma);
625 				return result;
626 			}
627 		}
628 		break;
629 	default:
630 		/* bail out on any unknown option */
631 		LogError("Unknown config option %s:%d \"%s\"!", tcsd_config_file, line_num, arg);
632 		return TCSERR(TSS_E_INTERNAL_ERROR);
633 	}
634 
635 	return TSS_SUCCESS;
636 }
637 
638 TSS_RESULT
639 read_conf_file(FILE *f, struct tcsd_config *conf)
640 {
641 	int line_num = 0;
642 	char buf[1024];
643 
644 	while (fgets(buf, 1024, f)) {
645 		line_num++;
646 		if (read_conf_line(buf, line_num, conf))
647 			return TCSERR(TSS_E_INTERNAL_ERROR);
648 	}
649 
650 	return TSS_SUCCESS;
651 }
652 
653 void
654 free_platform_lists(struct platform_class *list)
655 {
656 	struct platform_class *tmp;
657 
658 	while (list != NULL){
659 		if (list->classURISize > 0)
660 			free(list->classURI);
661 		tmp = list->next;
662 		free(list);
663 		list = tmp;
664 	}
665 }
666 
667 void
668 conf_file_final(struct tcsd_config *conf)
669 {
670 	free(conf->system_ps_file);
671 	free(conf->system_ps_dir);
672 	free(conf->kernel_log_file);
673 	free(conf->firmware_log_file);
674 	free(conf->platform_cred);
675 	free(conf->conformance_cred);
676 	free(conf->endorsement_cred);
677 	free_platform_lists(conf->host_platform_class);
678 	free_platform_lists(conf->all_platform_classes);
679 }
680 
681 #ifdef SOLARIS
682 static int
683 get_smf_prop(const char *var, boolean_t def_val)
684 {
685 	scf_simple_prop_t *prop;
686 	uint8_t *val;
687 	boolean_t res = def_val;
688 	prop = scf_simple_prop_get(NULL, "svc:/application/security/tcsd:default",
689 		"config", var);
690 	if (prop) {
691 		if ((val = scf_simple_prop_next_boolean(prop)) != NULL)
692 			res = (*val == 0) ? B_FALSE : B_TRUE;
693 		scf_simple_prop_free(prop);
694 	}
695 	if (prop == NULL || val == NULL) {
696 		syslog(LOG_ALERT, "no value for config/%s (%s). "
697 			"Using default \"%s\"", var, scf_strerror(scf_error()),
698 			def_val ? "true" : "false");
699 	}
700 	return (res);
701 }
702 #endif
703 
704 TSS_RESULT
705 conf_file_init(struct tcsd_config *conf)
706 {
707 	FILE *f = NULL;
708 	struct stat stat_buf;
709 #ifndef SOLARIS
710 	struct group *grp;
711 	struct passwd *pw;
712 	mode_t mode = (S_IRUSR|S_IWUSR);
713 #endif /* SOLARIS */
714 	TSS_RESULT result;
715 
716 	init_tcsd_config(conf);
717 
718 #ifdef SOLARIS
719        /*
720 	* Solaris runs as Rajiv Andrade <srajiv@linux.vnet.:sys but with reduced privileges
721 	* so we don't need to create a new user/group and also so
722 	* we can have auditing support.  The permissions on
723 	* the tcsd configuration file are not checked on Solaris.
724 	*/
725 #endif
726 	/* look for a config file, create if it doesn't exist */
727 	if (stat(tcsd_config_file, &stat_buf) == -1) {
728 		if (errno == ENOENT) {
729 			/* no config file? use defaults */
730 			config_set_defaults(conf);
731 			LogInfo("Config file %s not found, using defaults.", tcsd_config_file);
732 			return TSS_SUCCESS;
733 		} else {
734 			LogError("stat(%s): %s", tcsd_config_file, strerror(errno));
735 			return TCSERR(TSS_E_INTERNAL_ERROR);
736 		}
737 	}
738 
739 #ifndef SOLARIS
740 	/* find the gid that owns the conf file */
741 	errno = 0;
742 	grp = getgrnam(TSS_GROUP_NAME);
743 	if (grp == NULL) {
744 		if (errno == 0) {
745 			LogError("Group \"%s\" not found, please add this group"
746 					" manually.", TSS_GROUP_NAME);
747 		} else {
748 			LogError("getgrnam(%s): %s", TSS_GROUP_NAME, strerror(errno));
749 		}
750 		return TCSERR(TSS_E_INTERNAL_ERROR);
751 	}
752 
753 	errno = 0;
754 	pw = getpwnam(TSS_USER_NAME);
755 	if (pw == NULL) {
756 		if (errno == 0) {
757 			LogError("User \"%s\" not found, please add this user"
758 					" manually.", TSS_USER_NAME);
759 		} else {
760 			LogError("getpwnam(%s): %s", TSS_USER_NAME, strerror(errno));
761 		}
762 		return TCSERR(TSS_E_INTERNAL_ERROR);
763 	}
764 
765 	/* make sure user/group TSS owns the conf file */
766 	if (pw->pw_uid != stat_buf.st_uid || grp->gr_gid != stat_buf.st_gid) {
767 		LogError("TCSD config file (%s) must be user/group %s/%s", tcsd_config_file,
768 				TSS_USER_NAME, TSS_GROUP_NAME);
769 		return TCSERR(TSS_E_INTERNAL_ERROR);
770 	}
771 
772 	/* make sure only the tss user can manipulate the config file */
773 	if (((stat_buf.st_mode & 0777) ^ mode) != 0) {
774 		LogError("TCSD config file (%s) must be mode 0600", tcsd_config_file);
775 		return TCSERR(TSS_E_INTERNAL_ERROR);
776 	}
777 #endif /* SOLARIS */
778 
779 	if ((f = fopen(tcsd_config_file, "r")) == NULL) {
780 		LogError("fopen(%s): %s", tcsd_config_file, strerror(errno));
781 		return TCSERR(TSS_E_INTERNAL_ERROR);
782 	}
783 
784 	result = read_conf_file(f, conf);
785 	fclose(f);
786 
787 	/* fill out any uninitialized options */
788 	config_set_defaults(conf);
789 
790 #ifdef SOLARIS
791 	/*
792 	* The SMF value for "local_only" overrides the config file and
793 	* disables all remote operations.
794 	*/
795 if (get_smf_prop("local_only", B_TRUE)) {
796 		(void) memset(conf->remote_ops, 0, sizeof(conf->remote_ops));
797 		conf->unset |= TCSD_OPTION_REMOTE_OPS;
798 
799 	}
800 #endif
801 	return result;
802 }
803 
804 TSS_RESULT
805 ps_dirs_init()
806 {
807 	struct stat stat_buf;
808 	mode_t mode = S_IRWXU; /* 0700 */
809 
810 	/* query the key storage directory to make sure it exists and is of the right mode */
811 	if (stat(tcsd_options.system_ps_dir, &stat_buf) == -1) {
812 		if (errno == ENOENT) {
813 			/* The dir DNE, create it with mode drwxrwxrwt */
814 			if (mkdir(tcsd_options.system_ps_dir, mode) == -1) {
815 				LogError("mkdir(%s) failed: %s. If you'd like to use %s to "
816 						"store your system persistent data, please"
817 						" create it. Otherwise, change the location"
818 						" in your tcsd config file.",
819 						tcsd_options.system_ps_dir, strerror(errno),
820 						tcsd_options.system_ps_dir);
821 				return TCSERR(TSS_E_INTERNAL_ERROR);
822 			}
823 		} else {
824 			LogError("stat failed: %s", strerror(errno));
825 			return TCSERR(TSS_E_INTERNAL_ERROR);
826 		}
827 	}
828 
829 	/* stat should not fail now */
830 	if (stat(tcsd_options.system_ps_dir, &stat_buf) == -1) {
831 		LogError("stat %s failed: %s", tcsd_options.system_ps_dir, strerror(errno));
832 		return TCSERR(TSS_E_INTERNAL_ERROR);
833 	}
834 
835 	/* tcsd_options.system_ps_dir should be a directory with mode equal to mode */
836 	if (!S_ISDIR(stat_buf.st_mode)) {
837 		LogError("PS dir %s is not a directory! Exiting.", tcsd_options.system_ps_dir);
838 		return TCSERR(TSS_E_INTERNAL_ERROR);
839 	} else if (((stat_buf.st_mode & 0777) ^ mode) != 0) {
840 		/* This path is likely to be hit since open &'s mode with ~umask */
841 		LogInfo("resetting mode of %s from %o to: %o", tcsd_options.system_ps_dir,
842 			(unsigned int) stat_buf.st_mode, (unsigned int) mode);
843 		if (chmod(tcsd_options.system_ps_dir, mode) == -1) {
844 			LogError("chmod(%s) failed: %s", tcsd_options.system_ps_dir,
845 				 strerror(errno));
846 			return TCSERR(TSS_E_INTERNAL_ERROR);
847 		}
848 	}
849 
850 	return TSS_SUCCESS;
851 }
852 
853