4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * Functions for accessing the wanboot.conf(4) file.
34 #include <sys/types.h>
36 #include <netboot_paths.h>
37 #include <wanboot_conf.h>
40 * Parser helper macros:
42 #define is_whitespace(c) ((c) == ' ' || (c) == '\t')
43 #define skip_whitespace(p) while (is_whitespace(*(p))) ++p
46 * Table of valid wanboot.conf(4) names:
48 static const char *bootconf_names
[] = {
54 BC_CLIENT_AUTHENTICATION
,
55 BC_SERVER_AUTHENTICATION
,
63 * Check whether 'name' is valid within wanboot.conf(4).
66 valid_name(const char *name
)
70 for (i
= 0; bootconf_names
[i
] != NULL
; ++i
) {
71 if (strcmp(name
, bootconf_names
[i
]) == 0) {
80 * parse_bootconf() parses a wanboot.conf(4) file and, if there are no
81 * errors, creates an nvpair list of the name-value pairs defined therein.
83 * Lines must be blank or of the form:
84 * [name=value] [# comment]
88 * B_FALSE - error (return code in handle->bc_error_code, line number
89 * on which the error occurred in handle->bc_error_pos)
92 parse_bootconf(bc_handle_t
*handle
, const char *bootconf
)
96 char line
[BC_MAX_LINE_LENGTH
];
98 if ((fp
= fopen(bootconf
, "r")) == NULL
) {
99 handle
->bc_error_code
= BC_E_ACCESS
;
103 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
104 handle
->bc_error_code
= BC_E_NVLIST
;
108 while (fgets(line
, sizeof (line
), fp
) != NULL
) {
111 char *ks
, *ke
, *vs
, *ve
;
114 ++(handle
->bc_error_pos
);
117 * Strip off the '\n' at the end of the line.
119 if ((i
= strlen(line
)) < 1) {
120 handle
->bc_error_code
= BC_E_IOERR
;
122 } else if (line
[i
- 1] != '\n') {
123 handle
->bc_error_code
= BC_E_TOO_LONG
;
129 * Skip leading whitespace.
134 * Blank line/comment-only line?
136 if (*p
== '\0' || *p
== '#') {
141 * Get start and end pointers to the 'name'.
144 while (!is_whitespace(*p
) && *p
!= '=') {
150 * Must be of the form "name=value"; skip leading and
151 * trailing whitespace.
158 handle
->bc_error_code
= BC_E_SYNTAX
;
163 * The 'value' may be quoted.
165 if (*p
== '"' || *p
== '\'') {
173 * Get start and end pointers to the 'value' string.
174 * Note that 'value' may be the empty string.
177 if (quote
!= '\0' || *p
!= '#') {
178 while (*p
!= '\0' && *p
!= quote
) {
180 * White space that is not part of a quoted
181 * value signals end of value.
183 if (is_whitespace(*p
) && quote
== '\0') {
192 * If 'value' string was quoted, ensure that there is a
193 * balancing close-quote and skip it.
199 handle
->bc_error_code
= BC_E_SYNTAX
;
205 * Verify line is well-formed; the rest of the line should
206 * be blank or comment.
209 if (*p
!= '\0' && *p
!= '#') {
210 handle
->bc_error_code
= BC_E_SYNTAX
;
215 * Nul-terminate both the 'name' and the 'value' string.
221 * Check that this is a valid parameter name.
223 if (!valid_name(ks
)) {
224 handle
->bc_error_code
= BC_E_UNKNOWN_NAME
;
229 * Add the name-value pair to the nvpair list.
231 if (nvlist_add_string(nvl
, ks
, vs
) != 0) {
232 handle
->bc_error_code
= BC_E_NVLIST
;
238 * Verify that we didn't exit the parsing loop because of an
242 handle
->bc_error_code
= BC_E_IOERR
;
248 * Close the file if open and free the nvlist if an error occurred.
250 if (fp
!= NULL
&& fclose(fp
) != 0) {
251 handle
->bc_error_code
= BC_E_IOERR
;
253 if (handle
->bc_error_code
!= BC_E_NOERROR
) {
263 handle
->bc_nvl
= nvl
;
269 * valid_encryption() validitate the encryption type value
273 * B_FALSE - error (return code in handle->bc_error_code)
276 valid_encryption(bc_handle_t
*handle
, boolean_t
*is_encrypted
)
278 nvlist_t
*nvl
= handle
->bc_nvl
;
282 * Until proven otherwise, encryption is not enabled.
284 *is_encrypted
= B_FALSE
;
287 * If encryption_type was specified then it must be either
288 * "3des", "aes" or "".
290 if (nvlist_lookup_string(nvl
, BC_ENCRYPTION_TYPE
, &strval
) == 0) {
291 if (strlen(strval
) > 0) {
292 if (strcmp(strval
, BC_ENCRYPTION_3DES
) != 0 &&
293 strcmp(strval
, BC_ENCRYPTION_AES
) != 0) {
294 handle
->bc_error_code
= BC_E_ENCRYPTION_ILLEGAL
;
297 *is_encrypted
= B_TRUE
;
304 * valid_signature() validates the signature type value
308 * B_FALSE - error (return code in handle->bc_error_code)
311 valid_signature(bc_handle_t
*handle
, boolean_t
*is_signed
)
313 nvlist_t
*nvl
= handle
->bc_nvl
;
317 * Until proven otherwise, signing is not enabled.
319 *is_signed
= B_FALSE
;
322 * If signature_type was specified then it must be either
325 if (nvlist_lookup_string(nvl
, BC_SIGNATURE_TYPE
, &strval
) == 0) {
326 if (strlen(strval
) > 0) {
327 if (strcmp(strval
, BC_SIGNATURE_SHA1
) != 0) {
328 handle
->bc_error_code
= BC_E_SIGNATURE_ILLEGAL
;
339 * valid_client_authentication() validates the client authentication value
343 * B_FALSE - error (return code in handle->bc_error_code)
346 valid_client_authentication(bc_handle_t
*handle
, boolean_t
*is_authenticated
)
348 nvlist_t
*nvl
= handle
->bc_nvl
;
352 * Until proven otherwise, authentication is not enabled.
354 *is_authenticated
= B_FALSE
;
357 * If client_authentication was specified then it must be either
360 if (nvlist_lookup_string(nvl
, BC_CLIENT_AUTHENTICATION
, &strval
) == 0) {
361 if (strcmp(strval
, BC_YES
) == 0) {
362 *is_authenticated
= B_TRUE
;
363 } else if (strcmp(strval
, BC_NO
) != 0) {
364 handle
->bc_error_code
= BC_E_CLIENT_AUTH_ILLEGAL
;
373 * valid_server_authentication() validates the server authentication value
377 * B_FALSE - error (return code in handle->bc_error_code)
380 valid_server_authentication(bc_handle_t
*handle
, boolean_t
*is_authenticated
)
382 nvlist_t
*nvl
= handle
->bc_nvl
;
386 * Until proven otherwise, authentication is not enabled.
388 *is_authenticated
= B_FALSE
;
391 * If server_authentication was specified then it must be either
394 if (nvlist_lookup_string(nvl
, BC_SERVER_AUTHENTICATION
, &strval
) == 0) {
395 if (strcmp(strval
, BC_YES
) == 0) {
396 *is_authenticated
= B_TRUE
;
397 } else if (strcmp(strval
, BC_NO
) != 0) {
398 handle
->bc_error_code
= BC_E_SERVER_AUTH_ILLEGAL
;
407 * valid_root_server() validates the root server and root file values
411 * B_FALSE - error (return code in handle->bc_error_code)
414 valid_root_server(bc_handle_t
*handle
, boolean_t
*is_https
)
416 nvlist_t
*nvl
= handle
->bc_nvl
;
421 * Until proven otherwise, assume not https.
426 * Check whether a root_server URL was specified, and if so whether
427 * it is a secure URL (of the form https://...).
429 if (nvlist_lookup_string(nvl
, BC_ROOT_SERVER
, &strval
) == 0) {
430 if (url_parse(strval
, &url
) != URL_PARSE_SUCCESS
) {
431 handle
->bc_error_code
= BC_E_ROOT_SERVER_BAD
;
434 *is_https
= url
.https
;
437 * Ensure that a root_file was also specified.
439 if (nvlist_lookup_string(nvl
, BC_ROOT_FILE
, &strval
) != 0 ||
440 strlen(strval
) == 0) {
441 handle
->bc_error_code
= BC_E_ROOT_FILE_ABSENT
;
445 handle
->bc_error_code
= BC_E_ROOT_SERVER_ABSENT
;
453 * valid_boot_logger() validates the boot_logger value
457 * B_FALSE - error (return code in handle->bc_error_code)
460 valid_boot_logger(bc_handle_t
*handle
, boolean_t
*is_https
)
462 nvlist_t
*nvl
= handle
->bc_nvl
;
467 * Until proven otherwise, assume not https.
472 * If boot_logger was specified, make sure that it is a valid URL.
474 if (nvlist_lookup_string(nvl
, BC_BOOT_LOGGER
, &strval
) == 0 &&
475 strlen(strval
) > 0) {
476 if (url_parse(strval
, &url
) != URL_PARSE_SUCCESS
) {
477 handle
->bc_error_code
= BC_E_BOOT_LOGGER_BAD
;
480 *is_https
= url
.https
;
487 * validate_bootconf() checks the consistency of the nvpair list representation
488 * of a wanboot.conf(4) file as returned by the parse_bootconf() function.
492 * B_FALSE - error (return code in handle->bc_error_code)
495 validate_bootconf(bc_handle_t
*handle
)
497 boolean_t is_encrypted
;
499 boolean_t client_is_authenticated
;
500 boolean_t server_is_authenticated
;
501 boolean_t rootserver_is_https
;
502 boolean_t bootlogger_is_https
;
505 * Check to make sure option values are valid.
507 if (!valid_encryption(handle
, &is_encrypted
) ||
508 !valid_signature(handle
, &is_signed
) ||
509 !valid_client_authentication(handle
, &client_is_authenticated
) ||
510 !valid_server_authentication(handle
, &server_is_authenticated
) ||
511 !valid_root_server(handle
, &rootserver_is_https
) ||
512 !valid_boot_logger(handle
, &bootlogger_is_https
))
516 * Now do consistency checking between bootconf settings.
518 if (is_encrypted
&& !is_signed
) {
519 handle
->bc_error_code
= BC_E_ENCRYPTED_NOT_SIGNED
;
522 if (client_is_authenticated
) {
523 if (!(is_encrypted
&& is_signed
)) {
524 handle
->bc_error_code
= BC_E_CLIENT_AUTH_NOT_ENCRYPTED
;
528 if (!server_is_authenticated
) {
529 handle
->bc_error_code
= BC_E_CLIENT_AUTH_NOT_SERVER
;
533 if (server_is_authenticated
) {
535 handle
->bc_error_code
= BC_E_SERVER_AUTH_NOT_SIGNED
;
539 if (!rootserver_is_https
) {
540 handle
->bc_error_code
= BC_E_SERVER_AUTH_NOT_HTTPS
;
543 } else if (rootserver_is_https
) {
544 handle
->bc_error_code
= BC_E_SERVER_AUTH_NOT_HTTP
;
546 } else if (bootlogger_is_https
) {
547 handle
->bc_error_code
= BC_E_BOOTLOGGER_AUTH_NOT_HTTP
;
556 * bootconf_end() cleans up once we're done accessing the nvpair list
557 * representation of wanboot.conf(4).
560 bootconf_end(bc_handle_t
*handle
)
562 if (handle
->bc_nvl
!= NULL
) {
563 nvlist_free(handle
->bc_nvl
);
564 handle
->bc_nvl
= NULL
;
569 * bootconf_init() must be called to initialize 'handle' before bootconf_get()
570 * can be used to access values from the wanboot.conf(4) file.
573 bootconf_init(bc_handle_t
*handle
, const char *bootconf
)
576 * Initalise the handle's fields to sensible values.
578 handle
->bc_nvl
= NULL
;
579 handle
->bc_error_code
= BC_E_NOERROR
;
580 handle
->bc_error_pos
= 0;
583 * Provide a default path for the bootconf file if none was given.
585 if (bootconf
== NULL
) {
586 bootconf
= NB_WANBOOT_CONF_PATH
;
590 * Check that we can successfully parse and validate the file.
592 if (parse_bootconf(handle
, bootconf
) && validate_bootconf(handle
)) {
597 * Parse/validate error; free any allocated resources.
599 bootconf_end(handle
);
605 * bootconf_get() returns the value of a parameter in the wanboot.conf(4) file.
608 * != NULL - the given value
609 * == NULL - value not found or is empty
612 bootconf_get(bc_handle_t
*handle
, const char *name
)
617 * Look up the name in bc_nvl and return its value if found.
619 if (handle
->bc_nvl
!= NULL
&&
620 nvlist_lookup_string(handle
->bc_nvl
, (char *)name
, &strval
) == 0) {
621 return (strlen(strval
) == 0 ? NULL
: strval
);