Home | History | Annotate | Line # | Download | only in tcsd
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 (at) 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
    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