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