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
39struct 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
57struct 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
67void
68init_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
88TSS_RESULT
89platform_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
134void
135config_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
166int
167get_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 */
190int
191get_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 */
228void
229tcsd_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
246int
247tcsd_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
264TSS_RESULT
265read_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
638TSS_RESULT
639read_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
653void
654free_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
667void
668conf_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
682static int
683get_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
704TSS_RESULT
705conf_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	*/
795if (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
804TSS_RESULT
805ps_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