xref: /titanic_50/usr/src/psm/stand/boot/sparc/common/wanboot.c (revision 694c35faa87b858ecdadfe4fc592615f4eefbb07)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5986fd29aSsetje  * Common Development and Distribution License (the "License").
6986fd29aSsetje  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*c8551b44SJerry Gilliam  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/promif.h>
287c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h>
297c478bd9Sstevel@tonic-gate #include <sys/bootvfs.h>
307c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
317c478bd9Sstevel@tonic-gate #include <netinet/in.h>
327c478bd9Sstevel@tonic-gate #include <sys/wanboot_impl.h>
337c478bd9Sstevel@tonic-gate #include <boot_http.h>
347c478bd9Sstevel@tonic-gate #include <aes.h>
357c478bd9Sstevel@tonic-gate #include <des3.h>
367c478bd9Sstevel@tonic-gate #include <cbc.h>
377c478bd9Sstevel@tonic-gate #include <hmac_sha1.h>
387c478bd9Sstevel@tonic-gate #include <sys/sha1.h>
397c478bd9Sstevel@tonic-gate #include <sys/sha1_consts.h>
407c478bd9Sstevel@tonic-gate #include <bootlog.h>
417c478bd9Sstevel@tonic-gate #include <parseURL.h>
427c478bd9Sstevel@tonic-gate #include <netboot_paths.h>
437c478bd9Sstevel@tonic-gate #include <netinet/inetutil.h>
447c478bd9Sstevel@tonic-gate #include <sys/salib.h>
457c478bd9Sstevel@tonic-gate #include <inet/mac.h>
467c478bd9Sstevel@tonic-gate #include <inet/ipv4.h>
477c478bd9Sstevel@tonic-gate #include <dhcp_impl.h>
487c478bd9Sstevel@tonic-gate #include <inet/dhcpv4.h>
497c478bd9Sstevel@tonic-gate #include <bootinfo.h>
507c478bd9Sstevel@tonic-gate #include <wanboot_conf.h>
517c478bd9Sstevel@tonic-gate #include "boot_plat.h"
527c478bd9Sstevel@tonic-gate #include "ramdisk.h"
537c478bd9Sstevel@tonic-gate #include "wbcli.h"
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /*
567c478bd9Sstevel@tonic-gate  * Types of downloads
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate #define	MINIINFO	"miniinfo"
597c478bd9Sstevel@tonic-gate #define	MINIROOT	"miniroot"
607c478bd9Sstevel@tonic-gate #define	WANBOOTFS	"wanbootfs"
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #define	WANBOOT_RETRY_NOMAX	-1
637c478bd9Sstevel@tonic-gate #define	WANBOOT_RETRY_ROOT_MAX	50
647c478bd9Sstevel@tonic-gate #define	WANBOOT_RETRY_MAX	5
657c478bd9Sstevel@tonic-gate #define	WANBOOT_RETRY_SECS	5
667c478bd9Sstevel@tonic-gate #define	WANBOOT_RETRY_MAX_SECS	30
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate  * Our read requests should timeout after 25 seconds
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate #define	SOCKET_READ_TIMEOUT	25
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * Experimentation has shown that an 8K download buffer is optimal
757c478bd9Sstevel@tonic-gate  */
76986fd29aSsetje #define	HTTP_XFER_SIZE		8192
77986fd29aSsetje static char	buffer[HTTP_XFER_SIZE];
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate bc_handle_t	bc_handle;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate extern int	determine_fstype_and_mountroot(char *);
827c478bd9Sstevel@tonic-gate extern uint64_t	get_ticks(void);
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * The following is used to determine whether the certs and private key
867c478bd9Sstevel@tonic-gate  * files will be in PEM format or PKCS12 format.  'use_p12' is zero
877c478bd9Sstevel@tonic-gate  * to use PEM format, and 1 when PKCS12 format is to be used.  It is
887c478bd9Sstevel@tonic-gate  * done this way, as a global, so that it can be patched if needs be
897c478bd9Sstevel@tonic-gate  * using the OBP debugger.
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate uint32_t	use_p12 = 1;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate #define	CONTENT_LENGTH		"Content-Length"
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate #define	NONCELEN	(2 * HMAC_DIGEST_LEN) /* two hex nibbles/byte */
967c478bd9Sstevel@tonic-gate #define	WANBOOTFS_NONCE_FILE	"/nonce"
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate static char nonce[NONCELEN + 1];
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate enum URLtype {
1017c478bd9Sstevel@tonic-gate 	URLtype_wanbootfs = 0,
1027c478bd9Sstevel@tonic-gate 	URLtype_miniroot = 1
1037c478bd9Sstevel@tonic-gate };
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate static char *URLtoCGIcontent[] = {
1067c478bd9Sstevel@tonic-gate 	"bootfs",
1077c478bd9Sstevel@tonic-gate 	"rootfs"
1087c478bd9Sstevel@tonic-gate };
1097c478bd9Sstevel@tonic-gate #define	CGIcontent(urltype)	URLtoCGIcontent[urltype]
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /* Encryption algorithms */
1127c478bd9Sstevel@tonic-gate typedef enum {
1137c478bd9Sstevel@tonic-gate 	ENCR_NONE,
1147c478bd9Sstevel@tonic-gate 	ENCR_3DES,
1157c478bd9Sstevel@tonic-gate 	ENCR_AES
1167c478bd9Sstevel@tonic-gate } encr_type_t;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /* Hash algorithms */
1197c478bd9Sstevel@tonic-gate typedef enum {
1207c478bd9Sstevel@tonic-gate 	HASH_NONE,
1217c478bd9Sstevel@tonic-gate 	HASH_HMAC_SHA1
1227c478bd9Sstevel@tonic-gate } hash_type_t;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * Keys ...
1267c478bd9Sstevel@tonic-gate  */
1277c478bd9Sstevel@tonic-gate static encr_type_t	encr_type = ENCR_NONE;
1287c478bd9Sstevel@tonic-gate static unsigned char	*g_encr_key = NULL;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate static hash_type_t	hash_type = HASH_NONE;
1317c478bd9Sstevel@tonic-gate static unsigned char	*g_hash_key = NULL;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate void
print_errors(const char * func,http_handle_t handle)1347c478bd9Sstevel@tonic-gate print_errors(const char *func, http_handle_t handle)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	char const *msg;
1377c478bd9Sstevel@tonic-gate 	ulong_t err;
1387c478bd9Sstevel@tonic-gate 	uint_t src;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	while ((err = http_get_lasterr(handle, &src)) != 0) {
1417c478bd9Sstevel@tonic-gate 		msg = http_errorstr(src, err);
1427c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_ALERT,
1437c478bd9Sstevel@tonic-gate 		    "%s: errsrc %u, err %lu (0x%lx)", func, src, err, err);
1447c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_ALERT, "%s", msg);
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * This routine is called by a consumer to determine whether or not a
1507c478bd9Sstevel@tonic-gate  * retry should be attempted. If a retry is in order (depends upon the
1517c478bd9Sstevel@tonic-gate  * 'retry_cnt' and 'retry_max' arguments), then this routine will print a
1527c478bd9Sstevel@tonic-gate  * message indicating this is the case and will determine an appropriate
1537c478bd9Sstevel@tonic-gate  * "sleep" time before retrying. The "sleep" time will depend upon the
1547c478bd9Sstevel@tonic-gate  * 'retry_cnt' and will max out at WANBOOT_RETRY_MAX_SECS.
1557c478bd9Sstevel@tonic-gate  *
1567c478bd9Sstevel@tonic-gate  * Returns:
1577c478bd9Sstevel@tonic-gate  *	 B_TRUE  = retry is in order
1587c478bd9Sstevel@tonic-gate  *	 B_FALSE = retry limit exceeded
1597c478bd9Sstevel@tonic-gate  */
1607c478bd9Sstevel@tonic-gate boolean_t
wanboot_retry(int retry_cnt,int retry_max)1617c478bd9Sstevel@tonic-gate wanboot_retry(int retry_cnt, int retry_max)
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate 	unsigned int seconds;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	if (retry_max == WANBOOT_RETRY_NOMAX || retry_cnt <= retry_max) {
1667c478bd9Sstevel@tonic-gate 		seconds = WANBOOT_RETRY_SECS * retry_cnt;
1677c478bd9Sstevel@tonic-gate 		if (seconds > WANBOOT_RETRY_MAX_SECS) {
1687c478bd9Sstevel@tonic-gate 			seconds = WANBOOT_RETRY_MAX_SECS;
1697c478bd9Sstevel@tonic-gate 		}
1707c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_INFO,
1717c478bd9Sstevel@tonic-gate 		    "Will retry in %d seconds ...", seconds);
1727c478bd9Sstevel@tonic-gate 		(void) sleep(seconds);
1737c478bd9Sstevel@tonic-gate 		return (B_TRUE);
1747c478bd9Sstevel@tonic-gate 	} else {
1757c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_INFO,
1767c478bd9Sstevel@tonic-gate 		    "Maximum retries exceeded.");
1777c478bd9Sstevel@tonic-gate 		return (B_FALSE);
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  * Determine which encryption algorithm the client is configured to use.
1837c478bd9Sstevel@tonic-gate  * WAN boot determines which key to use by order of priority.  That is
1847c478bd9Sstevel@tonic-gate  * multiple encryption keys may exist in the PROM, but the first one found
1857c478bd9Sstevel@tonic-gate  * (while searching in a preferred order) is the one that will be used.
1867c478bd9Sstevel@tonic-gate  */
1877c478bd9Sstevel@tonic-gate static void
init_encryption(void)1887c478bd9Sstevel@tonic-gate init_encryption(void)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	static unsigned char	key[WANBOOT_MAXKEYLEN];
1917c478bd9Sstevel@tonic-gate 	size_t			len = sizeof (key);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	if (bootinfo_get(BI_AES_KEY, (char *)&key, &len, NULL) ==
1947c478bd9Sstevel@tonic-gate 	    BI_E_SUCCESS) {
1957c478bd9Sstevel@tonic-gate 		encr_type = ENCR_AES;
1967c478bd9Sstevel@tonic-gate 		g_encr_key = key;
1977c478bd9Sstevel@tonic-gate 	} else if (bootinfo_get(BI_3DES_KEY, (char *)&key, &len, NULL) ==
1987c478bd9Sstevel@tonic-gate 	    BI_E_SUCCESS) {
1997c478bd9Sstevel@tonic-gate 		encr_type = ENCR_3DES;
2007c478bd9Sstevel@tonic-gate 		g_encr_key = key;
2017c478bd9Sstevel@tonic-gate 	}
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate /*
2057c478bd9Sstevel@tonic-gate  * Determine whether the client is configured to use hashing.
2067c478bd9Sstevel@tonic-gate  */
2077c478bd9Sstevel@tonic-gate static void
init_hashing(void)2087c478bd9Sstevel@tonic-gate init_hashing(void)
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate 	static unsigned char	key[WANBOOT_HMAC_KEY_SIZE];
2117c478bd9Sstevel@tonic-gate 	size_t			len = sizeof (key);
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	if (bootinfo_get(BI_SHA1_KEY, (char *)&key, &len, NULL) ==
2147c478bd9Sstevel@tonic-gate 	    BI_E_SUCCESS) {
2157c478bd9Sstevel@tonic-gate 		hash_type = HASH_HMAC_SHA1;
2167c478bd9Sstevel@tonic-gate 		g_hash_key = key;
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate /*
2217c478bd9Sstevel@tonic-gate  * Read some CPU-specific rapidly-varying data (assumed to be of length
2227c478bd9Sstevel@tonic-gate  * sizeof (hrtime_t) in the non-SPARC case), and digestify it to further
2237c478bd9Sstevel@tonic-gate  * randomize the output.
2247c478bd9Sstevel@tonic-gate  */
2257c478bd9Sstevel@tonic-gate char *
generate_nonce(void)2267c478bd9Sstevel@tonic-gate generate_nonce(void)
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate 	uint64_t	t;
2297c478bd9Sstevel@tonic-gate 	SHA1_CTX	c;
2307c478bd9Sstevel@tonic-gate 	unsigned char	digest[HMAC_DIGEST_LEN];
2317c478bd9Sstevel@tonic-gate 	uint_t		nlen = sizeof (nonce);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	int		err;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	/*
2367c478bd9Sstevel@tonic-gate 	 * Read SPARC %tick register or x86 TSC
2377c478bd9Sstevel@tonic-gate 	 */
2387c478bd9Sstevel@tonic-gate 	t = get_ticks();
2397c478bd9Sstevel@tonic-gate 	SHA1Init(&c);
2407c478bd9Sstevel@tonic-gate 	SHA1Update(&c, (const uint8_t *)&t, sizeof (t));
2417c478bd9Sstevel@tonic-gate 	SHA1Final(digest, &c);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	err = octet_to_hexascii(digest, sizeof (digest), nonce, &nlen);
2447c478bd9Sstevel@tonic-gate 	if (err != 0) {
2457c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
2467c478bd9Sstevel@tonic-gate 		    "cannot convert nonce to ASCII: error %d", err);
2477c478bd9Sstevel@tonic-gate 		return (NULL);
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 	nonce[NONCELEN] = '\0';
2507c478bd9Sstevel@tonic-gate 	return (nonce);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * Given a server URL, builds a URL to request one of the wanboot
2557c478bd9Sstevel@tonic-gate  * datastreams.
2567c478bd9Sstevel@tonic-gate  *
2577c478bd9Sstevel@tonic-gate  * Returns:
2587c478bd9Sstevel@tonic-gate  *	-1 = Non-recoverable error
2597c478bd9Sstevel@tonic-gate  *	 0 = Success
2607c478bd9Sstevel@tonic-gate  */
2617c478bd9Sstevel@tonic-gate static int
build_request_url(url_t * req_url,enum URLtype ut,const url_t * server_url)2627c478bd9Sstevel@tonic-gate build_request_url(url_t *req_url, enum URLtype ut, const url_t *server_url)
2637c478bd9Sstevel@tonic-gate {
2647c478bd9Sstevel@tonic-gate 	char		clid[WB_MAX_CID_LEN];
2657c478bd9Sstevel@tonic-gate 	size_t		clen;
2667c478bd9Sstevel@tonic-gate 	char		wid[WB_MAX_CID_LEN * 2 + 1];
2677c478bd9Sstevel@tonic-gate 	uint_t		wlen;
2687c478bd9Sstevel@tonic-gate 	struct in_addr	ip;
2697c478bd9Sstevel@tonic-gate 	struct in_addr	mask;
2707c478bd9Sstevel@tonic-gate 	char		*netstr;
2717c478bd9Sstevel@tonic-gate 	char		*ppath;
2727c478bd9Sstevel@tonic-gate 	size_t		plen;
2737c478bd9Sstevel@tonic-gate 	const char	reqstr[] = "/?CONTENT=%s&IP=%s&CID=%s";
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	/*
2767c478bd9Sstevel@tonic-gate 	 * Initialize the request
2777c478bd9Sstevel@tonic-gate 	 */
2787c478bd9Sstevel@tonic-gate 	*req_url = *server_url;
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	/*
2817c478bd9Sstevel@tonic-gate 	 * Build the network number string
2827c478bd9Sstevel@tonic-gate 	 */
2837c478bd9Sstevel@tonic-gate 	ipv4_getipaddr(&ip);
2847c478bd9Sstevel@tonic-gate 	ipv4_getnetmask(&mask);
2857c478bd9Sstevel@tonic-gate 	ip.s_addr = ip.s_addr & mask.s_addr;
2867c478bd9Sstevel@tonic-gate 	netstr = inet_ntoa(ip);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	/*
2897c478bd9Sstevel@tonic-gate 	 * Get the wan id
2907c478bd9Sstevel@tonic-gate 	 */
2917c478bd9Sstevel@tonic-gate 	clen = sizeof (clid);
2927c478bd9Sstevel@tonic-gate 	if (bootinfo_get(BI_CLIENT_ID, clid, &clen, NULL) != BI_E_SUCCESS) {
2937c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
2947c478bd9Sstevel@tonic-gate 		    "Cannot retrieve the client ID");
2957c478bd9Sstevel@tonic-gate 		return (-1);
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 	wlen = sizeof (wid);
2987c478bd9Sstevel@tonic-gate 	(void) octet_to_hexascii(clid, clen, wid, &wlen);
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	/*
3017c478bd9Sstevel@tonic-gate 	 * Build the request, making sure that the length of the
3027c478bd9Sstevel@tonic-gate 	 * constructed URL falls within the supported maximum.
3037c478bd9Sstevel@tonic-gate 	 */
3047c478bd9Sstevel@tonic-gate 	plen = strlen(req_url->abspath);
3057c478bd9Sstevel@tonic-gate 	ppath = req_url->abspath + plen;
3067c478bd9Sstevel@tonic-gate 	if (snprintf(ppath, URL_MAX_PATHLEN - plen, reqstr,
3077c478bd9Sstevel@tonic-gate 	    CGIcontent(ut), netstr, wid) >= URL_MAX_PATHLEN - plen) {
3087c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
3097c478bd9Sstevel@tonic-gate 		    "The URL path length of the %s request is greater than "
3107c478bd9Sstevel@tonic-gate 		    "the maximum of %d", CGIcontent(ut), URL_MAX_PATHLEN);
3117c478bd9Sstevel@tonic-gate 		return (-1);
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	/*
3157c478bd9Sstevel@tonic-gate 	 * If the URL type requires a nonce, then supply it.
3167c478bd9Sstevel@tonic-gate 	 * It will be returned in the reply to detect attempted
3177c478bd9Sstevel@tonic-gate 	 * replays.
3187c478bd9Sstevel@tonic-gate 	 */
3197c478bd9Sstevel@tonic-gate 	if (ut == URLtype_wanbootfs) {
3207c478bd9Sstevel@tonic-gate 		char	*n = generate_nonce();
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 		if (n != NULL) {
3237c478bd9Sstevel@tonic-gate 			plen += strlen("&NONCE=") + NONCELEN;
3247c478bd9Sstevel@tonic-gate 			if (plen > URL_MAX_PATHLEN)
3257c478bd9Sstevel@tonic-gate 				return (-1);
3267c478bd9Sstevel@tonic-gate 			(void) strcat(req_url->abspath, "&NONCE=");
3277c478bd9Sstevel@tonic-gate 			(void) strcat(req_url->abspath, n);
3287c478bd9Sstevel@tonic-gate 		}
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	return (0);
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate /*
3357c478bd9Sstevel@tonic-gate  * This routine reads data from an HTTP connection into a buffer.
3367c478bd9Sstevel@tonic-gate  *
3377c478bd9Sstevel@tonic-gate  * Returns:
3387c478bd9Sstevel@tonic-gate  *	 0 = Success
3397c478bd9Sstevel@tonic-gate  *	 1 = HTTP download error
3407c478bd9Sstevel@tonic-gate  */
3417c478bd9Sstevel@tonic-gate static int
read_bytes(http_handle_t handle,char * buffer,size_t cnt)3427c478bd9Sstevel@tonic-gate read_bytes(http_handle_t handle, char *buffer, size_t cnt)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate 	int len;
3457c478bd9Sstevel@tonic-gate 	size_t i;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i += len) {
3487c478bd9Sstevel@tonic-gate 		len = http_read_body(handle, &buffer[i], cnt - i);
3497c478bd9Sstevel@tonic-gate 		if (len <= 0) {
3507c478bd9Sstevel@tonic-gate 			print_errors("http_read_body", handle);
3517c478bd9Sstevel@tonic-gate 			return (1);
3527c478bd9Sstevel@tonic-gate 		}
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 	return (0);
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate  * This routine compares two hash digests, one computed by the server and
3597c478bd9Sstevel@tonic-gate  * the other computed by the client to verify that a transmitted message
3607c478bd9Sstevel@tonic-gate  * was received without corruption.
3617c478bd9Sstevel@tonic-gate  *
3627c478bd9Sstevel@tonic-gate  * Notes:
3637c478bd9Sstevel@tonic-gate  *	The client only computes a digest if it is configured with a
3647c478bd9Sstevel@tonic-gate  *	hash key. If it is not, then the server should not have a hash
3657c478bd9Sstevel@tonic-gate  *	key for the client either and therefore should have sent a
3667c478bd9Sstevel@tonic-gate  *	zero filled digest.
3677c478bd9Sstevel@tonic-gate  *
3687c478bd9Sstevel@tonic-gate  * Returns:
3697c478bd9Sstevel@tonic-gate  *	 B_TRUE  = digest was verified
3707c478bd9Sstevel@tonic-gate  *	 B_FALSE = digest did not verify
3717c478bd9Sstevel@tonic-gate  */
3727c478bd9Sstevel@tonic-gate static boolean_t
verify_digests(const char * what,unsigned char * cdigest,unsigned char * sdigest)3737c478bd9Sstevel@tonic-gate verify_digests(const char *what, unsigned char *cdigest, unsigned char *sdigest)
3747c478bd9Sstevel@tonic-gate {
3757c478bd9Sstevel@tonic-gate 	static char	null_digest[HMAC_DIGEST_LEN];
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	if (bcmp(sdigest, cdigest, HMAC_DIGEST_LEN) != 0) {
3787c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
3797c478bd9Sstevel@tonic-gate 		    "%s: invalid hash digest", what);
3807c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
3817c478bd9Sstevel@tonic-gate 		    "This may signify a client/server key mismatch");
3827c478bd9Sstevel@tonic-gate 		if (bcmp(sdigest, null_digest, HMAC_DIGEST_LEN) == 0) {
3837c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_CRIT,
3847c478bd9Sstevel@tonic-gate 			    "(client has key but wrong signature_type?)");
3857c478bd9Sstevel@tonic-gate 		} else if (bcmp(cdigest, null_digest, HMAC_DIGEST_LEN) == 0) {
3867c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_CRIT,
3877c478bd9Sstevel@tonic-gate 			    "(signature_type specified but no client key?)");
3887c478bd9Sstevel@tonic-gate 		}
3897c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
3907c478bd9Sstevel@tonic-gate 		    "or possible corruption of the image in transit");
3917c478bd9Sstevel@tonic-gate 		return (B_FALSE);
3927c478bd9Sstevel@tonic-gate 	}
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	return (B_TRUE);
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate /*
3987c478bd9Sstevel@tonic-gate  * This routine reads the part of a multipart message that contains a
3997c478bd9Sstevel@tonic-gate  * hash digest. Errors in reading the digest are differentiated from
4007c478bd9Sstevel@tonic-gate  * other kinds of errors so that the caller can decide whether or
4017c478bd9Sstevel@tonic-gate  * not a retry is worthwhile.
4027c478bd9Sstevel@tonic-gate  *
4037c478bd9Sstevel@tonic-gate  * Note:
4047c478bd9Sstevel@tonic-gate  *	The hash digest can either be an HMAC digest or it can be
4057c478bd9Sstevel@tonic-gate  *	a zero length message (representing no hash digest).
4067c478bd9Sstevel@tonic-gate  *
4077c478bd9Sstevel@tonic-gate  * Returns:
4087c478bd9Sstevel@tonic-gate  *	-1 = Non-recoverable error
4097c478bd9Sstevel@tonic-gate  *	 0 = Success
4107c478bd9Sstevel@tonic-gate  *	 1 = HTTP download error
4117c478bd9Sstevel@tonic-gate  */
4127c478bd9Sstevel@tonic-gate static int
read_digest(const char * what,http_handle_t handle,unsigned char * sdigest)4137c478bd9Sstevel@tonic-gate read_digest(const char *what, http_handle_t handle, unsigned char *sdigest)
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate 	char *lenstr;
4167c478bd9Sstevel@tonic-gate 	size_t digest_size;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	/*
4197c478bd9Sstevel@tonic-gate 	 * Process the HMAC digest header.
4207c478bd9Sstevel@tonic-gate 	 */
4217c478bd9Sstevel@tonic-gate 	if (http_process_part_headers(handle, NULL) != 0) {
4227c478bd9Sstevel@tonic-gate 		print_errors("http_process_part_headers", handle);
4237c478bd9Sstevel@tonic-gate 		return (1);
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 	lenstr = http_get_header_value(handle, CONTENT_LENGTH);
4267c478bd9Sstevel@tonic-gate 	if (lenstr == NULL) {
4277c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_ALERT,
4287c478bd9Sstevel@tonic-gate 		    "%s: error getting digest length", what);
4297c478bd9Sstevel@tonic-gate 		return (1);
4307c478bd9Sstevel@tonic-gate 	}
4317c478bd9Sstevel@tonic-gate 	digest_size = (size_t)strtol(lenstr, NULL, 10);
4327c478bd9Sstevel@tonic-gate 	free(lenstr);
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	/*
4357c478bd9Sstevel@tonic-gate 	 * Validate the HMAC digest length.
4367c478bd9Sstevel@tonic-gate 	 */
4377c478bd9Sstevel@tonic-gate 	if (digest_size != HMAC_DIGEST_LEN) {
4387c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
4397c478bd9Sstevel@tonic-gate 		    "%s: error validating response - invalid digest size",
4407c478bd9Sstevel@tonic-gate 		    what);
4417c478bd9Sstevel@tonic-gate 		return (-1);
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	/*
4457c478bd9Sstevel@tonic-gate 	 * Read the HMAC digest.
4467c478bd9Sstevel@tonic-gate 	 */
4477c478bd9Sstevel@tonic-gate 	if (read_bytes(handle, (char *)sdigest, digest_size) != 0) {
4487c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_ALERT,
4497c478bd9Sstevel@tonic-gate 		    "%s: error reading digest", what);
4507c478bd9Sstevel@tonic-gate 		return (1);
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	return (0);
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate /*
4577c478bd9Sstevel@tonic-gate  * This routine reads data from an HTTP connection and writes the data
4587c478bd9Sstevel@tonic-gate  * to a ramdisk. It also, optionally computes a hash digest of the processed
4597c478bd9Sstevel@tonic-gate  * data. This routine may be called to continue writing a previously aborted
4607c478bd9Sstevel@tonic-gate  * write. If this is the case, then the offset will be non-zero and the write
4617c478bd9Sstevel@tonic-gate  * pointer into the ramdisk will be positioned correctly by the caller.
4627c478bd9Sstevel@tonic-gate  *
4637c478bd9Sstevel@tonic-gate  * Returns:
4647c478bd9Sstevel@tonic-gate  *	-1 = Non-recoverable error
4657c478bd9Sstevel@tonic-gate  *	 0 = Success
4667c478bd9Sstevel@tonic-gate  *	 1 = HTTP download error
4677c478bd9Sstevel@tonic-gate  */
4687c478bd9Sstevel@tonic-gate static int
write_msg_to_ramdisk(const char * what,caddr_t addr,http_handle_t handle,size_t ramdisk_size,off_t * offset,SHA1_CTX * sha)469986fd29aSsetje write_msg_to_ramdisk(const char *what, caddr_t addr, http_handle_t handle,
4707c478bd9Sstevel@tonic-gate     size_t ramdisk_size, off_t *offset, SHA1_CTX *sha)
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate 	int len;
4737c478bd9Sstevel@tonic-gate 	long nleft;
4747c478bd9Sstevel@tonic-gate 	static int bootlog_message_interval;
4757c478bd9Sstevel@tonic-gate 	static int bootlog_progress;
4767c478bd9Sstevel@tonic-gate 	int ret;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	/*
4797c478bd9Sstevel@tonic-gate 	 * Read the data and write it to the ramdisk.
4807c478bd9Sstevel@tonic-gate 	 */
4817c478bd9Sstevel@tonic-gate 	if (*offset == 0) {
4827c478bd9Sstevel@tonic-gate 		bootlog_progress = 0;
4837c478bd9Sstevel@tonic-gate 		bootlog_message_interval = ramdisk_size / sizeof (buffer);
4847c478bd9Sstevel@tonic-gate 		if (bootlog_message_interval < 500)
4857c478bd9Sstevel@tonic-gate 			bootlog_message_interval /= 5;
4867c478bd9Sstevel@tonic-gate 		else
4877c478bd9Sstevel@tonic-gate 			bootlog_message_interval /= 50;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_VERBOSE,
4907c478bd9Sstevel@tonic-gate 		    "Reading %s file system (%ld kB)",
4917c478bd9Sstevel@tonic-gate 		    what, ramdisk_size / 1024);
4927c478bd9Sstevel@tonic-gate 	} else {
4937c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_VERBOSE,
4947c478bd9Sstevel@tonic-gate 		    "Continuing read of %s file system (%ld kB)",
4957c478bd9Sstevel@tonic-gate 		    what, ramdisk_size / 1024);
4967c478bd9Sstevel@tonic-gate 	}
497986fd29aSsetje 	for (ret = 0; ret == 0 && *offset < ramdisk_size;
498986fd29aSsetje 	    *offset += len, addr += len) {
4997c478bd9Sstevel@tonic-gate 		nleft = ramdisk_size - *offset;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		if (nleft > sizeof (buffer))
5027c478bd9Sstevel@tonic-gate 			nleft = sizeof (buffer);
5037c478bd9Sstevel@tonic-gate 
504986fd29aSsetje 		len = http_read_body(handle, addr, nleft);
5057c478bd9Sstevel@tonic-gate 		if (len <= 0) {
5067c478bd9Sstevel@tonic-gate 			print_errors("http_read_body", handle);
5077c478bd9Sstevel@tonic-gate 			/*
5087c478bd9Sstevel@tonic-gate 			 * In the case of a partial failure, http_read_body()
5097c478bd9Sstevel@tonic-gate 			 * returns into 'len', 1 - the number of bytes read.
5107c478bd9Sstevel@tonic-gate 			 * So, a -65 means 64 bytes read and an error occurred.
5117c478bd9Sstevel@tonic-gate 			 */
5127c478bd9Sstevel@tonic-gate 			if (len != 0) {
5137c478bd9Sstevel@tonic-gate 				len = -(len + 1);
5147c478bd9Sstevel@tonic-gate 			}
5157c478bd9Sstevel@tonic-gate 			ret = 1;
5167c478bd9Sstevel@tonic-gate 		}
5177c478bd9Sstevel@tonic-gate 		if (sha != NULL) {
518986fd29aSsetje 			HMACUpdate(sha, (uchar_t *)addr, (size_t)len);
5197c478bd9Sstevel@tonic-gate 		}
5207c478bd9Sstevel@tonic-gate 		if (bootlog_progress == bootlog_message_interval) {
5217c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_PROGRESS,
5227c478bd9Sstevel@tonic-gate 			    "%s: Read %ld of %ld kB (%ld%%)", what,
5237c478bd9Sstevel@tonic-gate 			    *offset / 1024, ramdisk_size / 1024,
5247c478bd9Sstevel@tonic-gate 			    *offset * 100 / ramdisk_size);
5257c478bd9Sstevel@tonic-gate 			bootlog_progress = 0;
5267c478bd9Sstevel@tonic-gate 		} else {
5277c478bd9Sstevel@tonic-gate 			bootlog_progress++;
5287c478bd9Sstevel@tonic-gate 		}
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 	if (ret == 0) {
5317c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_PROGRESS,
5327c478bd9Sstevel@tonic-gate 		    "%s: Read %ld of %ld kB (%ld%%)", what,
5337c478bd9Sstevel@tonic-gate 		    *offset / 1024, ramdisk_size / 1024,
5347c478bd9Sstevel@tonic-gate 		    *offset * 100 / ramdisk_size);
5357c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_INFO, "%s: Download complete", what);
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 	return (ret);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate  * This routine is called with a bootinfo parameter name.  If the parameter
5427c478bd9Sstevel@tonic-gate  * has a value it should be a URL, and this will be used to initialize the
5437c478bd9Sstevel@tonic-gate  * http_url structure.
5447c478bd9Sstevel@tonic-gate  *
5457c478bd9Sstevel@tonic-gate  * Returns:
5467c478bd9Sstevel@tonic-gate  *	-1 = Non-recoverable error
5477c478bd9Sstevel@tonic-gate  *	 0 = Success
5487c478bd9Sstevel@tonic-gate  *	 1 = DHCP option not set
5497c478bd9Sstevel@tonic-gate  */
5507c478bd9Sstevel@tonic-gate static int
get_url(char * name,url_t * url)5517c478bd9Sstevel@tonic-gate get_url(char *name, url_t *url)
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate 	char	buf[URL_MAX_STRLEN];
5547c478bd9Sstevel@tonic-gate 	size_t	len;
5557c478bd9Sstevel@tonic-gate 	int	ret;
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	bzero(buf, sizeof (buf));
5587c478bd9Sstevel@tonic-gate 	len = sizeof (buf) - 1;
5597c478bd9Sstevel@tonic-gate 	if (bootinfo_get(name, buf, &len, NULL) != BI_E_SUCCESS || len == 0) {
5607c478bd9Sstevel@tonic-gate 		return (1);
5617c478bd9Sstevel@tonic-gate 	}
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	/*
5647c478bd9Sstevel@tonic-gate 	 * Parse the URL.
5657c478bd9Sstevel@tonic-gate 	 */
5667c478bd9Sstevel@tonic-gate 	ret = url_parse(buf, url);
5677c478bd9Sstevel@tonic-gate 	if (ret != URL_PARSE_SUCCESS) {
5687c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
5697c478bd9Sstevel@tonic-gate 		    "Unable to parse URL %s", buf);
5707c478bd9Sstevel@tonic-gate 		return (-1);
5717c478bd9Sstevel@tonic-gate 	}
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	return (0);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate /*
5777c478bd9Sstevel@tonic-gate  * This routine initiates an HTTP request and returns a handle so that
5787c478bd9Sstevel@tonic-gate  * the caller can process the response.
5797c478bd9Sstevel@tonic-gate  *
5807c478bd9Sstevel@tonic-gate  * Notes:
5817c478bd9Sstevel@tonic-gate  *	Requests may be either secure or not. If the request is secure, then
5827c478bd9Sstevel@tonic-gate  *	this routine assumes that a wanboot file system exists and
5837c478bd9Sstevel@tonic-gate  *	uses its contents to provide the HTTP library with the information
5847c478bd9Sstevel@tonic-gate  *	that will be required by SSL.
5857c478bd9Sstevel@tonic-gate  *
5867c478bd9Sstevel@tonic-gate  *	In order to facilitate transmission retries, this routine supports
5877c478bd9Sstevel@tonic-gate  *	range requests. A caller may request a range by providing a non-zero
5887c478bd9Sstevel@tonic-gate  *	offset. In which case, a range request is made that ranges from the
5897c478bd9Sstevel@tonic-gate  *	offet to the end of the file.
5907c478bd9Sstevel@tonic-gate  *
5917c478bd9Sstevel@tonic-gate  *	If the client is configured to use an HTTP proxy, then this routine
5927c478bd9Sstevel@tonic-gate  *	will make the HTTP library aware of the proxy.
5937c478bd9Sstevel@tonic-gate  *
5947c478bd9Sstevel@tonic-gate  *	Any HTTP errors encountered in downloading or processing the message
5957c478bd9Sstevel@tonic-gate  *	are not deemed unrecoverable errors. The caller can simply try the
5967c478bd9Sstevel@tonic-gate  *	request once again.
5977c478bd9Sstevel@tonic-gate  *
5987c478bd9Sstevel@tonic-gate  * Returns:
5997c478bd9Sstevel@tonic-gate  *	-1 = Non-recoverable error
6007c478bd9Sstevel@tonic-gate  *	 0 = Success
6017c478bd9Sstevel@tonic-gate  *	 1 = HTTP download error
6027c478bd9Sstevel@tonic-gate  */
6037c478bd9Sstevel@tonic-gate static int
establish_http_connection(const char * what,http_handle_t * handlep,url_t * url,offset_t offset)6047c478bd9Sstevel@tonic-gate establish_http_connection(const char *what, http_handle_t *handlep,
605cb4c2b01Svh115876     url_t *url, offset_t offset)
6067c478bd9Sstevel@tonic-gate {
6077c478bd9Sstevel@tonic-gate 	static boolean_t	is_auth_file_init = B_FALSE;
6087c478bd9Sstevel@tonic-gate 	static boolean_t	is_proxy_init = B_FALSE;
6097c478bd9Sstevel@tonic-gate 	static boolean_t	proxy_exists = B_FALSE;
6107c478bd9Sstevel@tonic-gate 	static url_hport_t	proxy_hp;
6117c478bd9Sstevel@tonic-gate 	http_respinfo_t		*resp;
6127c478bd9Sstevel@tonic-gate 	char			buf[URL_MAX_STRLEN];
6137c478bd9Sstevel@tonic-gate 	size_t			len = sizeof (buf) - 1;
6147c478bd9Sstevel@tonic-gate 	int			ret;
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	/* Check for HTTP proxy */
6177c478bd9Sstevel@tonic-gate 	if (!is_proxy_init &&
6187c478bd9Sstevel@tonic-gate 	    bootinfo_get(BI_HTTP_PROXY, buf, &len, NULL) == BI_E_SUCCESS &&
6197c478bd9Sstevel@tonic-gate 	    strlen(buf) > 0) {
6207c478bd9Sstevel@tonic-gate 		/*
6217c478bd9Sstevel@tonic-gate 		 * Parse the hostport.
6227c478bd9Sstevel@tonic-gate 		 */
6237c478bd9Sstevel@tonic-gate 		ret = url_parse_hostport(buf, &proxy_hp, URL_DFLT_PROXY_PORT);
6247c478bd9Sstevel@tonic-gate 		if (ret == URL_PARSE_SUCCESS) {
6257c478bd9Sstevel@tonic-gate 			proxy_exists = B_TRUE;
6267c478bd9Sstevel@tonic-gate 		} else {
6277c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_CRIT,
6287c478bd9Sstevel@tonic-gate 			    "%s is not set to a valid hostport value",
6297c478bd9Sstevel@tonic-gate 			    BI_HTTP_PROXY);
6307c478bd9Sstevel@tonic-gate 			return (-1);
6317c478bd9Sstevel@tonic-gate 		}
6327c478bd9Sstevel@tonic-gate 		is_proxy_init = B_TRUE;
6337c478bd9Sstevel@tonic-gate 	}
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	http_set_p12_format(use_p12);
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	/*
6387c478bd9Sstevel@tonic-gate 	 * Initialize the handle that will be used for the request.
6397c478bd9Sstevel@tonic-gate 	 */
6407c478bd9Sstevel@tonic-gate 	*handlep = http_srv_init(url);
6417c478bd9Sstevel@tonic-gate 	if (*handlep == NULL) {
6427c478bd9Sstevel@tonic-gate 		print_errors("http_srv_init", NULL);
6437c478bd9Sstevel@tonic-gate 		return (-1);
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	/*
6477c478bd9Sstevel@tonic-gate 	 * Is the request a secure one? If it is, then we need to do further
6487c478bd9Sstevel@tonic-gate 	 * setup. Search the wanboot file system for files that will be
6497c478bd9Sstevel@tonic-gate 	 * needed by SSL.
6507c478bd9Sstevel@tonic-gate 	 */
6517c478bd9Sstevel@tonic-gate 	if (url->https) {
6527c478bd9Sstevel@tonic-gate 		char		*cas;
6537c478bd9Sstevel@tonic-gate 		boolean_t	client_authentication = B_FALSE;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 		if (http_set_random_file(*handlep, "/dev/urandom") < 0) {
6567c478bd9Sstevel@tonic-gate 			print_errors("http_set_random_file", *handlep);
6577c478bd9Sstevel@tonic-gate 			(void) http_srv_close(*handlep);
6587c478bd9Sstevel@tonic-gate 			return (-1);
6597c478bd9Sstevel@tonic-gate 		}
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 		/*
6627c478bd9Sstevel@tonic-gate 		 * We only need to initialize the CA once as it is not handle
6637c478bd9Sstevel@tonic-gate 		 * specific.
6647c478bd9Sstevel@tonic-gate 		 */
6657c478bd9Sstevel@tonic-gate 		if (!is_auth_file_init) {
6667c478bd9Sstevel@tonic-gate 			if (http_set_certificate_authority_file(NB_CA_CERT_PATH)
6677c478bd9Sstevel@tonic-gate 			    < 0) {
6687c478bd9Sstevel@tonic-gate 				print_errors(
6697c478bd9Sstevel@tonic-gate 				    "http_set_certificate_authority_file",
6707c478bd9Sstevel@tonic-gate 				    *handlep);
6717c478bd9Sstevel@tonic-gate 				(void) http_srv_close(*handlep);
6727c478bd9Sstevel@tonic-gate 				return (-1);
6737c478bd9Sstevel@tonic-gate 			}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 			is_auth_file_init = B_TRUE;
6767c478bd9Sstevel@tonic-gate 		}
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 		/*
6797c478bd9Sstevel@tonic-gate 		 * The client certificate and key will not exist unless
6807c478bd9Sstevel@tonic-gate 		 * client authentication has been configured. If it is
6817c478bd9Sstevel@tonic-gate 		 * configured then the webserver will have added these
6827c478bd9Sstevel@tonic-gate 		 * files to the wanboot file system and the HTTP library
6837c478bd9Sstevel@tonic-gate 		 * needs to be made aware of their existence.
6847c478bd9Sstevel@tonic-gate 		 */
6857c478bd9Sstevel@tonic-gate 		if ((cas = bootconf_get(&bc_handle,
6867c478bd9Sstevel@tonic-gate 		    BC_CLIENT_AUTHENTICATION)) != NULL &&
6877c478bd9Sstevel@tonic-gate 		    strcmp(cas, "yes") == 0) {
6887c478bd9Sstevel@tonic-gate 			client_authentication = B_TRUE;
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 			if (http_set_client_certificate_file(*handlep,
6917c478bd9Sstevel@tonic-gate 			    NB_CLIENT_CERT_PATH) < 0) {
6927c478bd9Sstevel@tonic-gate 				print_errors("http_set_client_certificate_file",
6937c478bd9Sstevel@tonic-gate 				    *handlep);
6947c478bd9Sstevel@tonic-gate 				(void) http_srv_close(*handlep);
6957c478bd9Sstevel@tonic-gate 				return (-1);
6967c478bd9Sstevel@tonic-gate 			}
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 			if (http_set_private_key_file(*handlep,
6997c478bd9Sstevel@tonic-gate 			    NB_CLIENT_KEY_PATH) < 0) {
7007c478bd9Sstevel@tonic-gate 				print_errors("http_set_private_key_file",
7017c478bd9Sstevel@tonic-gate 				    *handlep);
7027c478bd9Sstevel@tonic-gate 				(void) http_srv_close(*handlep);
7037c478bd9Sstevel@tonic-gate 				return (-1);
7047c478bd9Sstevel@tonic-gate 			}
7057c478bd9Sstevel@tonic-gate 		}
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 		/*
7087c478bd9Sstevel@tonic-gate 		 * We do not really need to set this unless client
7097c478bd9Sstevel@tonic-gate 		 * authentication is configured or unless pkcs12 files
7107c478bd9Sstevel@tonic-gate 		 * are used.
7117c478bd9Sstevel@tonic-gate 		 */
7127c478bd9Sstevel@tonic-gate 		if ((client_authentication || use_p12) &&
7137c478bd9Sstevel@tonic-gate 		    http_set_password(*handlep, WANBOOT_PASSPHRASE) < 0) {
7147c478bd9Sstevel@tonic-gate 			print_errors("http_set_password", *handlep);
7157c478bd9Sstevel@tonic-gate 			(void) http_srv_close(*handlep);
7167c478bd9Sstevel@tonic-gate 			return (-1);
7177c478bd9Sstevel@tonic-gate 		}
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	/*
7217c478bd9Sstevel@tonic-gate 	 * If the client is using a proxy, tell the library.
7227c478bd9Sstevel@tonic-gate 	 */
7237c478bd9Sstevel@tonic-gate 	if (proxy_exists) {
7247c478bd9Sstevel@tonic-gate 		if (http_set_proxy(*handlep, &proxy_hp) != 0) {
7257c478bd9Sstevel@tonic-gate 			print_errors("http_set_proxy", *handlep);
7267c478bd9Sstevel@tonic-gate 			(void) http_srv_close(*handlep);
7277c478bd9Sstevel@tonic-gate 			return (-1);
7287c478bd9Sstevel@tonic-gate 		}
7297c478bd9Sstevel@tonic-gate 	}
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	(void) http_set_socket_read_timeout(*handlep, SOCKET_READ_TIMEOUT);
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	/*
7347c478bd9Sstevel@tonic-gate 	 * Ok, connect to the webserver.
7357c478bd9Sstevel@tonic-gate 	 */
7367c478bd9Sstevel@tonic-gate 	if (http_srv_connect(*handlep) == -1) {
7377c478bd9Sstevel@tonic-gate 		print_errors("http_srv_connect", *handlep);
7387c478bd9Sstevel@tonic-gate 		(void) http_srv_close(*handlep);
7397c478bd9Sstevel@tonic-gate 		return (1);
7407c478bd9Sstevel@tonic-gate 	}
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	/*
7437c478bd9Sstevel@tonic-gate 	 * If the offset is 0, then we assume that we want the entire
7447c478bd9Sstevel@tonic-gate 	 * message. If the offset is not 0, then we assume that we are
7457c478bd9Sstevel@tonic-gate 	 * retrying a previously interrupted transfer and thus we make
7467c478bd9Sstevel@tonic-gate 	 * a range request.
7477c478bd9Sstevel@tonic-gate 	 */
7487c478bd9Sstevel@tonic-gate 	if (offset == 0) {
7497c478bd9Sstevel@tonic-gate 		if ((ret = http_get_request(*handlep, url->abspath)) == 0) {
7507c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_VERBOSE,
7517c478bd9Sstevel@tonic-gate 			    "%s: http_get_request: sent", what);
7527c478bd9Sstevel@tonic-gate 		} else {
7537c478bd9Sstevel@tonic-gate 			print_errors("http_get_request", *handlep);
7547c478bd9Sstevel@tonic-gate 			(void) http_srv_close(*handlep);
7557c478bd9Sstevel@tonic-gate 			return (1);
7567c478bd9Sstevel@tonic-gate 		}
7577c478bd9Sstevel@tonic-gate 	} else {
7587c478bd9Sstevel@tonic-gate 		if ((ret = http_get_range_request(*handlep, url->abspath,
7597c478bd9Sstevel@tonic-gate 		    offset, 0)) == 0) {
7607c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_VERBOSE,
7617c478bd9Sstevel@tonic-gate 			    "%s: http_get_range_request: sent", what);
7627c478bd9Sstevel@tonic-gate 		} else {
7637c478bd9Sstevel@tonic-gate 			print_errors("http_get_range_request", *handlep);
7647c478bd9Sstevel@tonic-gate 			(void) http_srv_close(*handlep);
7657c478bd9Sstevel@tonic-gate 			return (1);
7667c478bd9Sstevel@tonic-gate 		}
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	/*
7707c478bd9Sstevel@tonic-gate 	 * Tell the library to read in the response headers.
7717c478bd9Sstevel@tonic-gate 	 */
7727c478bd9Sstevel@tonic-gate 	ret = http_process_headers(*handlep, &resp);
7737c478bd9Sstevel@tonic-gate 	if (ret == -1) {
7747c478bd9Sstevel@tonic-gate 		print_errors("http_process_headers", *handlep);
7757c478bd9Sstevel@tonic-gate 		(void) http_srv_close(*handlep);
7767c478bd9Sstevel@tonic-gate 		return (1);
7777c478bd9Sstevel@tonic-gate 	}
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	/*
7807c478bd9Sstevel@tonic-gate 	 * Check for a valid response code.
7817c478bd9Sstevel@tonic-gate 	 */
7827c478bd9Sstevel@tonic-gate 	if ((offset == 0 && resp->code != 200) ||
7837c478bd9Sstevel@tonic-gate 	    (offset != 0 && resp->code != 206)) {
7847c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_ALERT,
7857c478bd9Sstevel@tonic-gate 		    "%s: Request returned code %d", what, resp->code);
7867c478bd9Sstevel@tonic-gate 		if (resp->statusmsg != NULL && resp->statusmsg[0] != '\0')
7877c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_ALERT,
7887c478bd9Sstevel@tonic-gate 			    "%s", resp->statusmsg);
7897c478bd9Sstevel@tonic-gate 		http_free_respinfo(resp);
7907c478bd9Sstevel@tonic-gate 		(void) http_srv_close(*handlep);
7917c478bd9Sstevel@tonic-gate 		return (1);
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 	http_free_respinfo(resp);
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	/*
7967c478bd9Sstevel@tonic-gate 	 * Success.
7977c478bd9Sstevel@tonic-gate 	 */
7987c478bd9Sstevel@tonic-gate 	return (0);
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate /*
8027c478bd9Sstevel@tonic-gate  * This routine is called by get_miniinfo() to receive the reply
8037c478bd9Sstevel@tonic-gate  * to the request for the miniroot metadata. The reply is a two
8047c478bd9Sstevel@tonic-gate  * part multipart message. The first part of the message contains
8057c478bd9Sstevel@tonic-gate  * the miniroot file size. The second part of the message contains
8067c478bd9Sstevel@tonic-gate  * a hash digest of the miniroot as computed by the server. This
8077c478bd9Sstevel@tonic-gate  * routine receives both message parts and returns them to the caller.
8087c478bd9Sstevel@tonic-gate  *
8097c478bd9Sstevel@tonic-gate  * Notes:
8107c478bd9Sstevel@tonic-gate  *	If the miniroot is going to be downloaded securely or if the
8117c478bd9Sstevel@tonic-gate  *	the server has no hash key for the client, then the hash digest
8127c478bd9Sstevel@tonic-gate  *	downloaded contains all zeros.
8137c478bd9Sstevel@tonic-gate  *
8147c478bd9Sstevel@tonic-gate  *	Any HTTP errors encountered in downloading or processing the message
8157c478bd9Sstevel@tonic-gate  *	are not deemed unrecoverable errors. That is, get_miniinfo()
8167c478bd9Sstevel@tonic-gate  *	tries re-requesting the message and tries processing it again.
8177c478bd9Sstevel@tonic-gate  *
8187c478bd9Sstevel@tonic-gate  * Returns:
8197c478bd9Sstevel@tonic-gate  *	-1 = Non-recoverable error
8207c478bd9Sstevel@tonic-gate  *	 0 = Success
8217c478bd9Sstevel@tonic-gate  *	 1 = HTTP download error
8227c478bd9Sstevel@tonic-gate  */
8237c478bd9Sstevel@tonic-gate static int
process_miniinfo(http_handle_t handle,size_t * mini_size,unsigned char * sdigest)8247c478bd9Sstevel@tonic-gate process_miniinfo(http_handle_t handle, size_t *mini_size,
8257c478bd9Sstevel@tonic-gate     unsigned char *sdigest)
8267c478bd9Sstevel@tonic-gate {
8277c478bd9Sstevel@tonic-gate 	char	*lenstr;
8287c478bd9Sstevel@tonic-gate 	size_t	cnt;
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	/*
8317c478bd9Sstevel@tonic-gate 	 * Process the file size header.
8327c478bd9Sstevel@tonic-gate 	 */
8337c478bd9Sstevel@tonic-gate 	if (http_process_part_headers(handle, NULL) != 0) {
8347c478bd9Sstevel@tonic-gate 		print_errors("http_process_part_headers", handle);
8357c478bd9Sstevel@tonic-gate 		return (1);
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 	lenstr = http_get_header_value(handle, CONTENT_LENGTH);
8387c478bd9Sstevel@tonic-gate 	if (lenstr == NULL) {
8397c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_ALERT, "%s: error getting length "
8407c478bd9Sstevel@tonic-gate 		    "of first part of multipart message", MINIINFO);
8417c478bd9Sstevel@tonic-gate 		return (1);
8427c478bd9Sstevel@tonic-gate 	}
8437c478bd9Sstevel@tonic-gate 	cnt = (size_t)strtol(lenstr, NULL, 10);
8447c478bd9Sstevel@tonic-gate 	free(lenstr);
8457c478bd9Sstevel@tonic-gate 	if (cnt == 0 || cnt >= sizeof (buffer)) {
8467c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_ALERT, "%s: length of first part "
8477c478bd9Sstevel@tonic-gate 		    "of multipart message not a legal size", MINIINFO);
8487c478bd9Sstevel@tonic-gate 		return (1);
8497c478bd9Sstevel@tonic-gate 	}
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	if (read_bytes(handle, buffer, cnt) != 0) {
8527c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_ALERT,
8537c478bd9Sstevel@tonic-gate 		    "%s: error reading miniroot size", MINIINFO);
8547c478bd9Sstevel@tonic-gate 		return (1);
8557c478bd9Sstevel@tonic-gate 	}
8567c478bd9Sstevel@tonic-gate 	buffer[cnt] = '\0';
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	*mini_size = (size_t)strtol(buffer, NULL, 10);
8597c478bd9Sstevel@tonic-gate 	if (*mini_size == 0) {
8607c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_ALERT, "%s: body of first part "
8617c478bd9Sstevel@tonic-gate 		    "of multipart message not a legal size", MINIINFO);
8627c478bd9Sstevel@tonic-gate 		return (1);
8637c478bd9Sstevel@tonic-gate 	}
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	return (read_digest(MINIINFO, handle, sdigest));
8667c478bd9Sstevel@tonic-gate }
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate /*
8697c478bd9Sstevel@tonic-gate  * This routine is called by get_miniroot() to retrieve the miniroot
8707c478bd9Sstevel@tonic-gate  * metadata (miniroot size and a hash digest). This routine sends an
8717c478bd9Sstevel@tonic-gate  * HTTP GET request to the webserver to request the download of the
8727c478bd9Sstevel@tonic-gate  * miniroot metadata and relies on process_miniinfo() to receive the
8737c478bd9Sstevel@tonic-gate  * reply, process it and ultimately return to it the miniroot size and
8747c478bd9Sstevel@tonic-gate  * the hash digest.
8757c478bd9Sstevel@tonic-gate  *
8767c478bd9Sstevel@tonic-gate  * Note:
8777c478bd9Sstevel@tonic-gate  *	Any HTTP errors encountered in downloading or processing the message
8787c478bd9Sstevel@tonic-gate  *	are not deemed unrecoverable errors. That is, get_miniinfo() should
8797c478bd9Sstevel@tonic-gate  *	try re-requesting the message and try processing again.
8807c478bd9Sstevel@tonic-gate  *
8817c478bd9Sstevel@tonic-gate  * Returns:
8827c478bd9Sstevel@tonic-gate  *	-1 = Non-recoverable error
8837c478bd9Sstevel@tonic-gate  *	 0 = Success
8847c478bd9Sstevel@tonic-gate  */
8857c478bd9Sstevel@tonic-gate int
get_miniinfo(const url_t * server_url,size_t * mini_size,unsigned char * sdigest)8867c478bd9Sstevel@tonic-gate get_miniinfo(const url_t *server_url, size_t *mini_size,
8877c478bd9Sstevel@tonic-gate     unsigned char *sdigest)
8887c478bd9Sstevel@tonic-gate {
8897c478bd9Sstevel@tonic-gate 	http_handle_t	handle;
8907c478bd9Sstevel@tonic-gate 	url_t		req_url;
8917c478bd9Sstevel@tonic-gate 	int		retry_cnt = 0;
8927c478bd9Sstevel@tonic-gate 	int		retry_max = WANBOOT_RETRY_MAX;
8937c478bd9Sstevel@tonic-gate 	int		ret;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	/*
8967c478bd9Sstevel@tonic-gate 	 * Build the URL to request the miniroot info.
8977c478bd9Sstevel@tonic-gate 	 */
8987c478bd9Sstevel@tonic-gate 	if (build_request_url(&req_url, URLtype_miniroot, server_url) == -1) {
8997c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
9007c478bd9Sstevel@tonic-gate 		    "Can't build the URL to make the %s request",
9017c478bd9Sstevel@tonic-gate 		    CGIcontent(URLtype_miniroot));
9027c478bd9Sstevel@tonic-gate 		return (-1);
9037c478bd9Sstevel@tonic-gate 	}
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	/*
9067c478bd9Sstevel@tonic-gate 	 * Go get the miniroot info. If we fail reading the
9077c478bd9Sstevel@tonic-gate 	 * response we re-request the info in its entirety.
9087c478bd9Sstevel@tonic-gate 	 */
9097c478bd9Sstevel@tonic-gate 	bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading miniroot info");
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	do {
9127c478bd9Sstevel@tonic-gate 		if ((ret = establish_http_connection(MINIINFO, &handle,
9137c478bd9Sstevel@tonic-gate 		    &req_url, 0)) < 0) {
9147c478bd9Sstevel@tonic-gate 			break;
9157c478bd9Sstevel@tonic-gate 		} else if (ret > 0) {
9167c478bd9Sstevel@tonic-gate 			if (wanboot_retry(++retry_cnt, retry_max)) {
9177c478bd9Sstevel@tonic-gate 				continue;
9187c478bd9Sstevel@tonic-gate 			} else {
9197c478bd9Sstevel@tonic-gate 				break;
9207c478bd9Sstevel@tonic-gate 			}
9217c478bd9Sstevel@tonic-gate 		}
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 		if ((ret = process_miniinfo(handle, mini_size,
9247c478bd9Sstevel@tonic-gate 		    sdigest)) > 0) {
9257c478bd9Sstevel@tonic-gate 			if (!wanboot_retry(++retry_cnt, retry_max)) {
9267c478bd9Sstevel@tonic-gate 				(void) http_srv_close(handle);
9277c478bd9Sstevel@tonic-gate 				break;
9287c478bd9Sstevel@tonic-gate 			}
9297c478bd9Sstevel@tonic-gate 		}
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 		(void) http_srv_close(handle);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	} while (ret > 0);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	/*
9367c478bd9Sstevel@tonic-gate 	 * Success.
9377c478bd9Sstevel@tonic-gate 	 */
9387c478bd9Sstevel@tonic-gate 	if (ret == 0) {
9397c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_VERBOSE,
9407c478bd9Sstevel@tonic-gate 		    "Miniroot info download successful");
9417c478bd9Sstevel@tonic-gate 		return (0);
9427c478bd9Sstevel@tonic-gate 	} else {
9437c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
9447c478bd9Sstevel@tonic-gate 		    "Miniroot info download aborted");
9457c478bd9Sstevel@tonic-gate 		return (-1);
9467c478bd9Sstevel@tonic-gate 	}
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate /*
9507c478bd9Sstevel@tonic-gate  * This routine is called by get_miniroot() to receive the reply to
9517c478bd9Sstevel@tonic-gate  * the request for the miniroot download. The miniroot is written
9527c478bd9Sstevel@tonic-gate  * to ramdisk as it is received and a hash digest is optionally computed
9537c478bd9Sstevel@tonic-gate  * as it does so. The miniroot is downloaded as one large message.
9547c478bd9Sstevel@tonic-gate  * Because the message is so large, this routine is prepared to deal
9557c478bd9Sstevel@tonic-gate  * with errors in the middle of download. If an error occurs during
9567c478bd9Sstevel@tonic-gate  * download, then this message processes all received data up to the
9577c478bd9Sstevel@tonic-gate  * point of the error and returns to get_miniroot() an error signifying
9587c478bd9Sstevel@tonic-gate  * that a download error has occurred. Presumably, get_miniroot()
9597c478bd9Sstevel@tonic-gate  * re-requests the remaining part of the miniroot not yet processed and
9607c478bd9Sstevel@tonic-gate  * calls this routine back to process the reply. When this routine
9617c478bd9Sstevel@tonic-gate  * returns succesfully, it returns a devpath to the ramdisk and the
9627c478bd9Sstevel@tonic-gate  * computed hash (if computed).
9637c478bd9Sstevel@tonic-gate  *
9647c478bd9Sstevel@tonic-gate  * Note:
9657c478bd9Sstevel@tonic-gate  *	In order to facilitate reentry, the ramdisk is left open
9667c478bd9Sstevel@tonic-gate  *	and the original miniroot_size and HMAC handle are kept
9677c478bd9Sstevel@tonic-gate  *	static.
9687c478bd9Sstevel@tonic-gate  *
9697c478bd9Sstevel@tonic-gate  * Returns:
9707c478bd9Sstevel@tonic-gate  *	-1 = Non-recoverable error
9717c478bd9Sstevel@tonic-gate  *	 0 = Success
9727c478bd9Sstevel@tonic-gate  *	 1 = HTTP download error
9737c478bd9Sstevel@tonic-gate  */
9747c478bd9Sstevel@tonic-gate static int
process_miniroot(http_handle_t handle,hash_type_t htype,size_t length,char ** devpath,off_t * offset,unsigned char * cdigest)9757c478bd9Sstevel@tonic-gate process_miniroot(http_handle_t handle, hash_type_t htype,
9767c478bd9Sstevel@tonic-gate     size_t length, char **devpath, off_t *offset, unsigned char *cdigest)
9777c478bd9Sstevel@tonic-gate {
9787c478bd9Sstevel@tonic-gate 	static SHA1_CTX	sha;
9797c478bd9Sstevel@tonic-gate 	static size_t	miniroot_size;
980986fd29aSsetje 	static caddr_t	miniroot_vaddr = NULL;
9817c478bd9Sstevel@tonic-gate 	int		ret;
9827c478bd9Sstevel@tonic-gate 
983986fd29aSsetje 	if (miniroot_vaddr == NULL) {
9847c478bd9Sstevel@tonic-gate 		if (htype == HASH_HMAC_SHA1) {
9857c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_INFO,
9867c478bd9Sstevel@tonic-gate 			    "%s: Authentication will use HMAC-SHA1", MINIROOT);
9877c478bd9Sstevel@tonic-gate 			HMACInit(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE);
9887c478bd9Sstevel@tonic-gate 		}
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 		miniroot_size = length;
9917c478bd9Sstevel@tonic-gate 
992986fd29aSsetje 		miniroot_vaddr = create_ramdisk(RD_ROOTFS, miniroot_size,
993986fd29aSsetje 		    devpath);
9947c478bd9Sstevel@tonic-gate 	}
9957c478bd9Sstevel@tonic-gate 
996986fd29aSsetje 	miniroot_vaddr += *offset;
9977c478bd9Sstevel@tonic-gate 
998986fd29aSsetje 	if ((ret = write_msg_to_ramdisk(MINIROOT, miniroot_vaddr, handle,
999986fd29aSsetje 	    miniroot_size, offset, (htype == HASH_NONE) ? NULL : &sha)) != 0) {
10007c478bd9Sstevel@tonic-gate 		return (ret);
10017c478bd9Sstevel@tonic-gate 	}
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	if (htype != HASH_NONE) {
10047c478bd9Sstevel@tonic-gate 		HMACFinal(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE, cdigest);
10057c478bd9Sstevel@tonic-gate 	}
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	return (0);
10087c478bd9Sstevel@tonic-gate }
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate /*
10117c478bd9Sstevel@tonic-gate  * This routine retrieves the miniroot from the webserver. The miniroot
10127c478bd9Sstevel@tonic-gate  * is retrieved in two steps. First a request is made to the server
10137c478bd9Sstevel@tonic-gate  * to retrieve miniroot metadata (miniroot size and a hash digest).
10147c478bd9Sstevel@tonic-gate  * The second request actually results in the download of the miniroot.
10157c478bd9Sstevel@tonic-gate  *
10167c478bd9Sstevel@tonic-gate  * This routine relies on get_miniinfo() to make and process
10177c478bd9Sstevel@tonic-gate  * the request for the miniroot metadata and returns the
10187c478bd9Sstevel@tonic-gate  * miniroot size and the hash digest of the miniroot as computed by
10197c478bd9Sstevel@tonic-gate  * the server.
10207c478bd9Sstevel@tonic-gate  *
10217c478bd9Sstevel@tonic-gate  * If get_miniinfo() returns successfully, then this routine sends
10227c478bd9Sstevel@tonic-gate  * an HTTP GET request to the webserver to request download of the
10237c478bd9Sstevel@tonic-gate  * miniroot. This routine relies on process_miniroot() to receive
10247c478bd9Sstevel@tonic-gate  * the reply, process it and ultimately return to it a device path to
10257c478bd9Sstevel@tonic-gate  * a ramdisk containing the miniroot and a client computed hash digest.
10267c478bd9Sstevel@tonic-gate  * This routine verifies that the client computed hash digest matches
10277c478bd9Sstevel@tonic-gate  * the one retrieved by get_miniinfo().
10287c478bd9Sstevel@tonic-gate  *
10297c478bd9Sstevel@tonic-gate  * If an error occurs in the transfer of the miniroot from the server
10307c478bd9Sstevel@tonic-gate  * to the client, then the client re-requests the download of the
10317c478bd9Sstevel@tonic-gate  * miniroot using a range request and only requests the part of the
10327c478bd9Sstevel@tonic-gate  * miniroot not previously downloaded and written to ramdisk. The
10337c478bd9Sstevel@tonic-gate  * process_miniroot() routine has the intelligence to recognize that
10347c478bd9Sstevel@tonic-gate  * it is processing a range request. Errors not related to the actual
10357c478bd9Sstevel@tonic-gate  * message download are deemed unrecoverable.
10367c478bd9Sstevel@tonic-gate  *
10377c478bd9Sstevel@tonic-gate  * Note:
10387c478bd9Sstevel@tonic-gate  *	If the client request for the miniroot is a secure request or
10397c478bd9Sstevel@tonic-gate  *	if the server is not configured with a hash key for the client,
10407c478bd9Sstevel@tonic-gate  *	then the hash digest downloaded from the server will contain
10417c478bd9Sstevel@tonic-gate  *	all zeros. This routine verifies that the server and client are
10427c478bd9Sstevel@tonic-gate  *	in-sync with respect to the need for hash verification.
10437c478bd9Sstevel@tonic-gate  *
10447c478bd9Sstevel@tonic-gate  * Returns:
10457c478bd9Sstevel@tonic-gate  *	-1 = Non-recoverable error
10467c478bd9Sstevel@tonic-gate  *	 0 = Success
10477c478bd9Sstevel@tonic-gate  */
10487c478bd9Sstevel@tonic-gate int
get_miniroot(char ** devpath)10497c478bd9Sstevel@tonic-gate get_miniroot(char **devpath)
10507c478bd9Sstevel@tonic-gate {
10517c478bd9Sstevel@tonic-gate 	http_handle_t	handle;
10527c478bd9Sstevel@tonic-gate 	unsigned char	cdigest[HMAC_DIGEST_LEN];
10537c478bd9Sstevel@tonic-gate 	unsigned char	sdigest[HMAC_DIGEST_LEN];
10547c478bd9Sstevel@tonic-gate 	char		*urlstr;
10557c478bd9Sstevel@tonic-gate 	url_t		server_url;
10567c478bd9Sstevel@tonic-gate 	size_t		mini_size;
10577c478bd9Sstevel@tonic-gate 	off_t		offset;
10587c478bd9Sstevel@tonic-gate 	int		plen;
10597c478bd9Sstevel@tonic-gate 	int		retry_cnt = 0;
10607c478bd9Sstevel@tonic-gate 	int		retry_max = WANBOOT_RETRY_ROOT_MAX;
10617c478bd9Sstevel@tonic-gate 	int		ret;
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	/*
10647c478bd9Sstevel@tonic-gate 	 * Get the miniroot URL.
10657c478bd9Sstevel@tonic-gate 	 */
10667c478bd9Sstevel@tonic-gate 	if ((urlstr = bootconf_get(&bc_handle, BC_ROOT_SERVER)) == NULL) {
10677c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
10687c478bd9Sstevel@tonic-gate 		    "Missing root_server URL");
10697c478bd9Sstevel@tonic-gate 		return (-1);
10707c478bd9Sstevel@tonic-gate 	} else if (url_parse(urlstr, &server_url) != URL_PARSE_SUCCESS) {
10717c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
10727c478bd9Sstevel@tonic-gate 		    "Unable to parse URL %s", urlstr);
10737c478bd9Sstevel@tonic-gate 		return (-1);
10747c478bd9Sstevel@tonic-gate 	}
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	/*
10777c478bd9Sstevel@tonic-gate 	 * We must get the miniroot info before we can request
10787c478bd9Sstevel@tonic-gate 	 * the miniroot itself.
10797c478bd9Sstevel@tonic-gate 	 */
10807c478bd9Sstevel@tonic-gate 	if (get_miniinfo(&server_url, &mini_size, sdigest) != 0) {
10817c478bd9Sstevel@tonic-gate 		return (-1);
10827c478bd9Sstevel@tonic-gate 	}
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	plen = sizeof (server_url.abspath);
10857c478bd9Sstevel@tonic-gate 	if ((urlstr = bootconf_get(&bc_handle, BC_ROOT_FILE)) == NULL ||
10867c478bd9Sstevel@tonic-gate 	    strlcpy(server_url.abspath, urlstr, plen) >= plen) {
10877c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
10887c478bd9Sstevel@tonic-gate 		    "Cannot retrieve the miniroot path");
10897c478bd9Sstevel@tonic-gate 		return (-1);
10907c478bd9Sstevel@tonic-gate 	}
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	/*
10937c478bd9Sstevel@tonic-gate 	 * Go get the miniroot. If we fail reading the response
10947c478bd9Sstevel@tonic-gate 	 * then we re-request only the range we have yet to read,
10957c478bd9Sstevel@tonic-gate 	 * unless the error was "unrecoverable" in which case we
10967c478bd9Sstevel@tonic-gate 	 * re-request the entire file system.
10977c478bd9Sstevel@tonic-gate 	 */
10987c478bd9Sstevel@tonic-gate 	bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading miniroot");
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	bzero(cdigest, sizeof (cdigest));
11017c478bd9Sstevel@tonic-gate 	offset = 0;
11027c478bd9Sstevel@tonic-gate 	do {
11037c478bd9Sstevel@tonic-gate 		if ((ret = establish_http_connection(MINIROOT, &handle,
11047c478bd9Sstevel@tonic-gate 		    &server_url, offset)) < 0) {
11057c478bd9Sstevel@tonic-gate 			break;
11067c478bd9Sstevel@tonic-gate 		} else if (ret > 0) {
11077c478bd9Sstevel@tonic-gate 			if (wanboot_retry(++retry_cnt, retry_max)) {
11087c478bd9Sstevel@tonic-gate 				continue;
11097c478bd9Sstevel@tonic-gate 			} else {
11107c478bd9Sstevel@tonic-gate 				break;
11117c478bd9Sstevel@tonic-gate 			}
11127c478bd9Sstevel@tonic-gate 		}
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 		if ((ret = process_miniroot(handle,
11157c478bd9Sstevel@tonic-gate 		    server_url.https ? HASH_NONE : hash_type,
11167c478bd9Sstevel@tonic-gate 		    mini_size, devpath, &offset, cdigest)) > 0) {
11177c478bd9Sstevel@tonic-gate 			if (!wanboot_retry(++retry_cnt, retry_max)) {
11187c478bd9Sstevel@tonic-gate 				(void) http_srv_close(handle);
11197c478bd9Sstevel@tonic-gate 				break;
11207c478bd9Sstevel@tonic-gate 			}
11217c478bd9Sstevel@tonic-gate 		}
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 		(void) http_srv_close(handle);
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	} while (ret > 0);
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	/*
11287c478bd9Sstevel@tonic-gate 	 * Validate the computed digest against the one received.
11297c478bd9Sstevel@tonic-gate 	 */
11307c478bd9Sstevel@tonic-gate 	if (ret != 0 || !verify_digests(MINIROOT, cdigest, sdigest)) {
11317c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
11327c478bd9Sstevel@tonic-gate 		    "Miniroot download aborted");
11337c478bd9Sstevel@tonic-gate 		return (-1);
11347c478bd9Sstevel@tonic-gate 	}
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	bootlog("wanboot", BOOTLOG_VERBOSE, "Miniroot download successful");
11377c478bd9Sstevel@tonic-gate 	return (0);
11387c478bd9Sstevel@tonic-gate }
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate /*
11417c478bd9Sstevel@tonic-gate  * This routine is called to finish the decryption process.
11427c478bd9Sstevel@tonic-gate  * Its purpose is to free the resources allocated by the
11437c478bd9Sstevel@tonic-gate  * encryption init routines.
11447c478bd9Sstevel@tonic-gate  */
11457c478bd9Sstevel@tonic-gate static void
encr_fini(encr_type_t etype,void * eh)11467c478bd9Sstevel@tonic-gate encr_fini(encr_type_t etype, void *eh)
11477c478bd9Sstevel@tonic-gate {
11487c478bd9Sstevel@tonic-gate 	switch (etype) {
11497c478bd9Sstevel@tonic-gate 	case ENCR_3DES:
11507c478bd9Sstevel@tonic-gate 		des3_fini(eh);
11517c478bd9Sstevel@tonic-gate 		break;
11527c478bd9Sstevel@tonic-gate 	case ENCR_AES:
11537c478bd9Sstevel@tonic-gate 		aes_fini(eh);
11547c478bd9Sstevel@tonic-gate 		break;
11557c478bd9Sstevel@tonic-gate 	default:
11567c478bd9Sstevel@tonic-gate 		break;
11577c478bd9Sstevel@tonic-gate 	}
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate /*
1161986fd29aSsetje  * This routine is called by process_wanbootfs() to decrypt the encrypted
1162986fd29aSsetje  * file system from ramdisk in place.  The method of decryption
11637c478bd9Sstevel@tonic-gate  * (algorithm) will have already been determined by process_wanbootfs()
11647c478bd9Sstevel@tonic-gate  * and the cbc_handle passed to this routine will already have been
11657c478bd9Sstevel@tonic-gate  * initialized appropriately.
11667c478bd9Sstevel@tonic-gate  *
11677c478bd9Sstevel@tonic-gate  * Returns:
11687c478bd9Sstevel@tonic-gate  *	-1 = Non-recoverable error
11697c478bd9Sstevel@tonic-gate  *	 0 = Success
11707c478bd9Sstevel@tonic-gate  */
11717c478bd9Sstevel@tonic-gate static int
decrypt_wanbootfs(caddr_t addr,cbc_handle_t * ch,uint8_t * iv,size_t wanbootfs_size)1172986fd29aSsetje decrypt_wanbootfs(caddr_t addr, cbc_handle_t *ch, uint8_t *iv,
1173986fd29aSsetje     size_t wanbootfs_size)
11747c478bd9Sstevel@tonic-gate {
1175986fd29aSsetje 	if (!cbc_decrypt(ch, (uint8_t *)addr, wanbootfs_size, iv)) {
11767c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
11777c478bd9Sstevel@tonic-gate 		    "%s: cbc decrypt error", WANBOOTFS);
11787c478bd9Sstevel@tonic-gate 		return (-1);
11797c478bd9Sstevel@tonic-gate 	}
11807c478bd9Sstevel@tonic-gate 	return (0);
11817c478bd9Sstevel@tonic-gate }
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate /*
11847c478bd9Sstevel@tonic-gate  * This routine is called by get_wanbootfs() to receive the reply to
11857c478bd9Sstevel@tonic-gate  * the request for the wanboot file system. The reply is a multipart message.
11867c478bd9Sstevel@tonic-gate  * The first part of the message is the file system (which may or may
11877c478bd9Sstevel@tonic-gate  * not be encrypted).  If encrypted, then the first block of the message
11887c478bd9Sstevel@tonic-gate  * part is the CBC IV value used by the server to encrypt the remaining
11897c478bd9Sstevel@tonic-gate  * part of the message part and is used by the client to decrypt it. The
11907c478bd9Sstevel@tonic-gate  * second message part is a hash digest of the first part (the file
11917c478bd9Sstevel@tonic-gate  * system) as computed by the server. If no hash key is configured
11927c478bd9Sstevel@tonic-gate  * for the client, then the hash digest simply contains all zeros. This
11937c478bd9Sstevel@tonic-gate  * routine receives both message parts. The file system is written to ramdisk
11947c478bd9Sstevel@tonic-gate  * as it is received and simultaneously computes a hash digest (if a hash
11957c478bd9Sstevel@tonic-gate  * key exists). Once the entire part is received, if the file system is
11967c478bd9Sstevel@tonic-gate  * encrypted, it is read from ramdisk, decrypted and rewritten back to
11977c478bd9Sstevel@tonic-gate  * ramdisk. The server computed hash digest is then read and along with the
11987c478bd9Sstevel@tonic-gate  * ramdisk device path and the client computed hash digest is returned to the
11997c478bd9Sstevel@tonic-gate  * caller.
12007c478bd9Sstevel@tonic-gate  *
12017c478bd9Sstevel@tonic-gate  * Notes:
12027c478bd9Sstevel@tonic-gate  *	In order to decrypt the file system and to compute the client
12037c478bd9Sstevel@tonic-gate  *	hash digest, an encryption key and a hash key is retrieved from
12047c478bd9Sstevel@tonic-gate  *	the PROM (or the wanboot interpreter). The non-existence of these
12057c478bd9Sstevel@tonic-gate  *	keys has implications on how the message response is processed and
12067c478bd9Sstevel@tonic-gate  *	it is assumed that the server is configured identically.
12077c478bd9Sstevel@tonic-gate  *
12087c478bd9Sstevel@tonic-gate  *	Any HTTP errors encountered in downloading or processing the message
12097c478bd9Sstevel@tonic-gate  *	are not deemed unrecoverable errors. That is, get_wanbootfs() will
12107c478bd9Sstevel@tonic-gate  *	try re-requesting the message and will try processing it again.
12117c478bd9Sstevel@tonic-gate  *
12127c478bd9Sstevel@tonic-gate  * Returns:
12137c478bd9Sstevel@tonic-gate  *	-1 = Non-recoverable error
12147c478bd9Sstevel@tonic-gate  *	 0 = Success
12157c478bd9Sstevel@tonic-gate  *	 1 = HTTP download error
12167c478bd9Sstevel@tonic-gate  */
12177c478bd9Sstevel@tonic-gate static int
process_wanbootfs(http_handle_t handle,char ** devpath,unsigned char * cdigest,unsigned char * sdigest)12187c478bd9Sstevel@tonic-gate process_wanbootfs(http_handle_t handle, char **devpath,
12197c478bd9Sstevel@tonic-gate     unsigned char *cdigest, unsigned char *sdigest)
12207c478bd9Sstevel@tonic-gate {
12217c478bd9Sstevel@tonic-gate 	/* iv[] must be sized to store the largest possible encryption block */
12227c478bd9Sstevel@tonic-gate 	uint8_t		iv[WANBOOT_MAXBLOCKLEN];
12237c478bd9Sstevel@tonic-gate 	cbc_handle_t	ch;
12247c478bd9Sstevel@tonic-gate 	void		*eh;
12257c478bd9Sstevel@tonic-gate 	SHA1_CTX	sha;
12267c478bd9Sstevel@tonic-gate 	char		*lenstr;
12277c478bd9Sstevel@tonic-gate 	size_t		wanbootfs_size;
12287c478bd9Sstevel@tonic-gate 	size_t		block_size;
12297c478bd9Sstevel@tonic-gate 	off_t		offset;
1230986fd29aSsetje 	static caddr_t	bootfs_vaddr = NULL;
12317c478bd9Sstevel@tonic-gate 	int		ret;
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	switch (hash_type) {
12347c478bd9Sstevel@tonic-gate 	case HASH_HMAC_SHA1:
12357c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_INFO,
12367c478bd9Sstevel@tonic-gate 		    "%s: Authentication will use HMAC-SHA1", WANBOOTFS);
12377c478bd9Sstevel@tonic-gate 		HMACInit(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE);
12387c478bd9Sstevel@tonic-gate 		break;
12397c478bd9Sstevel@tonic-gate 	case HASH_NONE:
12407c478bd9Sstevel@tonic-gate 		break;
12417c478bd9Sstevel@tonic-gate 	default:
12427c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
12437c478bd9Sstevel@tonic-gate 		    "%s: unrecognized hash type", WANBOOTFS);
12447c478bd9Sstevel@tonic-gate 		return (-1);
12457c478bd9Sstevel@tonic-gate 	}
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	switch (encr_type) {
12487c478bd9Sstevel@tonic-gate 	case ENCR_3DES:
12497c478bd9Sstevel@tonic-gate 		bootlog("wanboot",
12507c478bd9Sstevel@tonic-gate 		    BOOTLOG_INFO, "%s: Decryption will use 3DES", WANBOOTFS);
12517c478bd9Sstevel@tonic-gate 		if (des3_init(&eh) != 0) {
12527c478bd9Sstevel@tonic-gate 			return (-1);
12537c478bd9Sstevel@tonic-gate 		}
12547c478bd9Sstevel@tonic-gate 		block_size = DES3_BLOCK_SIZE;
12557c478bd9Sstevel@tonic-gate 		des3_key(eh, g_encr_key);
12567c478bd9Sstevel@tonic-gate 		cbc_makehandle(&ch, eh, DES3_KEY_SIZE, block_size,
12577c478bd9Sstevel@tonic-gate 		    DES3_IV_SIZE, des3_encrypt, des3_decrypt);
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 		break;
12607c478bd9Sstevel@tonic-gate 	case ENCR_AES:
12617c478bd9Sstevel@tonic-gate 		bootlog("wanboot",
12627c478bd9Sstevel@tonic-gate 		    BOOTLOG_INFO, "%s: Decryption will use AES", WANBOOTFS);
12637c478bd9Sstevel@tonic-gate 		if (aes_init(&eh) != 0) {
12647c478bd9Sstevel@tonic-gate 			return (-1);
12657c478bd9Sstevel@tonic-gate 		}
12667c478bd9Sstevel@tonic-gate 		block_size = AES_BLOCK_SIZE;
12677c478bd9Sstevel@tonic-gate 		aes_key(eh, g_encr_key, AES_128_KEY_SIZE);
12687c478bd9Sstevel@tonic-gate 		cbc_makehandle(&ch, eh, AES_128_KEY_SIZE, block_size,
12697c478bd9Sstevel@tonic-gate 		    AES_IV_SIZE, aes_encrypt, aes_decrypt);
12707c478bd9Sstevel@tonic-gate 		break;
12717c478bd9Sstevel@tonic-gate 	case ENCR_NONE:
12727c478bd9Sstevel@tonic-gate 		break;
12737c478bd9Sstevel@tonic-gate 	default:
12747c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
12757c478bd9Sstevel@tonic-gate 		    "%s: unrecognized encryption type", WANBOOTFS);
12767c478bd9Sstevel@tonic-gate 		return (-1);
12777c478bd9Sstevel@tonic-gate 	}
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate 	/*
12807c478bd9Sstevel@tonic-gate 	 * Process the header.
12817c478bd9Sstevel@tonic-gate 	 */
12827c478bd9Sstevel@tonic-gate 	if (http_process_part_headers(handle, NULL) != 0) {
12837c478bd9Sstevel@tonic-gate 		print_errors("http_process_part_headers", handle);
12847c478bd9Sstevel@tonic-gate 		return (1);
12857c478bd9Sstevel@tonic-gate 	}
12867c478bd9Sstevel@tonic-gate 	lenstr = http_get_header_value(handle, CONTENT_LENGTH);
12877c478bd9Sstevel@tonic-gate 	if (lenstr == NULL) {
12887c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_ALERT, "%s: error getting length "
12897c478bd9Sstevel@tonic-gate 		    "of first part of multipart message", WANBOOTFS);
12907c478bd9Sstevel@tonic-gate 		return (1);
12917c478bd9Sstevel@tonic-gate 	}
12927c478bd9Sstevel@tonic-gate 	wanbootfs_size = (size_t)strtol(lenstr, NULL, 10);
12937c478bd9Sstevel@tonic-gate 	free(lenstr);
12947c478bd9Sstevel@tonic-gate 	if (wanbootfs_size == 0) {
12957c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_ALERT, "%s: length of first part "
12967c478bd9Sstevel@tonic-gate 		    "of multipart message not a legal size", WANBOOTFS);
12977c478bd9Sstevel@tonic-gate 		return (1);
12987c478bd9Sstevel@tonic-gate 	}
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 	/*
13017c478bd9Sstevel@tonic-gate 	 * If encrypted, then read the iv.
13027c478bd9Sstevel@tonic-gate 	 */
13037c478bd9Sstevel@tonic-gate 	if (encr_type != ENCR_NONE) {
13047c478bd9Sstevel@tonic-gate 		if (read_bytes(handle, (char *)iv, block_size) != 0) {
13057c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_ALERT,
13067c478bd9Sstevel@tonic-gate 			    "%s: error reading hash iv", WANBOOTFS);
13077c478bd9Sstevel@tonic-gate 			return (1);
13087c478bd9Sstevel@tonic-gate 		}
13097c478bd9Sstevel@tonic-gate 		wanbootfs_size -= block_size;
13107c478bd9Sstevel@tonic-gate 		if (hash_type != HASH_NONE) {
13117c478bd9Sstevel@tonic-gate 			HMACUpdate(&sha, (uchar_t *)iv, block_size);
13127c478bd9Sstevel@tonic-gate 		}
13137c478bd9Sstevel@tonic-gate 	}
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	/*
13167c478bd9Sstevel@tonic-gate 	 * We can only create the ramdisk once. So, if we've
13177c478bd9Sstevel@tonic-gate 	 * already created it, then it means we've re-entered
13187c478bd9Sstevel@tonic-gate 	 * this routine from an earlier partial failure. Use
13197c478bd9Sstevel@tonic-gate 	 * the already existing ramdisk and seek back to the
13207c478bd9Sstevel@tonic-gate 	 * beginning of the file.
13217c478bd9Sstevel@tonic-gate 	 */
1322986fd29aSsetje 	if (bootfs_vaddr == NULL) {
1323986fd29aSsetje 		bootfs_vaddr = create_ramdisk(RD_BOOTFS, wanbootfs_size,
1324986fd29aSsetje 		    devpath);
13257c478bd9Sstevel@tonic-gate 	}
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 	offset = 0;
13287c478bd9Sstevel@tonic-gate 
1329986fd29aSsetje 	if ((ret = write_msg_to_ramdisk(WANBOOTFS, bootfs_vaddr, handle,
1330986fd29aSsetje 	    wanbootfs_size, &offset, (hash_type == HASH_NONE) ? NULL : &sha))
1331986fd29aSsetje 	    != 0) {
13327c478bd9Sstevel@tonic-gate 		return (ret);
13337c478bd9Sstevel@tonic-gate 	}
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	if (hash_type != HASH_NONE) {
13367c478bd9Sstevel@tonic-gate 		HMACFinal(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE, cdigest);
13377c478bd9Sstevel@tonic-gate 	}
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	/*
13407c478bd9Sstevel@tonic-gate 	 * If encrypted, then decrypt it.
13417c478bd9Sstevel@tonic-gate 	 */
13427c478bd9Sstevel@tonic-gate 	if (encr_type != ENCR_NONE) {
1343986fd29aSsetje 		ret = decrypt_wanbootfs(bootfs_vaddr, &ch, iv, wanbootfs_size);
13447c478bd9Sstevel@tonic-gate 		if (ret != 0) {
13457c478bd9Sstevel@tonic-gate 			encr_fini(encr_type, eh);
13467c478bd9Sstevel@tonic-gate 			return (-1);
13477c478bd9Sstevel@tonic-gate 		}
13487c478bd9Sstevel@tonic-gate 		encr_fini(encr_type, eh);
13497c478bd9Sstevel@tonic-gate 	}
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 	return (read_digest(WANBOOTFS, handle, sdigest));
13527c478bd9Sstevel@tonic-gate }
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate /*
13557c478bd9Sstevel@tonic-gate  * This routine sends an HTTP GET request to the webserver to
13567c478bd9Sstevel@tonic-gate  * request the wanboot file system for the client. The server
13577c478bd9Sstevel@tonic-gate  * will reply by sending a multipart message. This routine will rely
13587c478bd9Sstevel@tonic-gate  * on process_wanbootfs() to receive the multipart message, process it
13597c478bd9Sstevel@tonic-gate  * and ultimately return to it a device path to a ramdisk containing
13607c478bd9Sstevel@tonic-gate  * the wanboot file system, a client computed hash digest and a
13617c478bd9Sstevel@tonic-gate  * server computed hash digest. This routine will verify that the
13627c478bd9Sstevel@tonic-gate  * client computed hash digest matches the one sent by the server. This
13637c478bd9Sstevel@tonic-gate  * routine will also verify that the nonce received in the reply matches
13647c478bd9Sstevel@tonic-gate  * the one sent in the request.
13657c478bd9Sstevel@tonic-gate  *
13667c478bd9Sstevel@tonic-gate  * If an error occurs in the transfer of the message from the server
13677c478bd9Sstevel@tonic-gate  * to the client, then the client re-requests the download in its
13687c478bd9Sstevel@tonic-gate  * entirety. Errors not related to the actual message download are
13697c478bd9Sstevel@tonic-gate  * deemed unrecoverable.
13707c478bd9Sstevel@tonic-gate  *
13717c478bd9Sstevel@tonic-gate  * Returns:
13727c478bd9Sstevel@tonic-gate  *	-1 = Non-recoverable error
13737c478bd9Sstevel@tonic-gate  *	 0 = Success
13747c478bd9Sstevel@tonic-gate  */
13757c478bd9Sstevel@tonic-gate int
get_wanbootfs(const url_t * server_url)13767c478bd9Sstevel@tonic-gate get_wanbootfs(const url_t *server_url)
13777c478bd9Sstevel@tonic-gate {
13787c478bd9Sstevel@tonic-gate 	http_handle_t	handle;
13797c478bd9Sstevel@tonic-gate 	unsigned char	cdigest[HMAC_DIGEST_LEN];
13807c478bd9Sstevel@tonic-gate 	unsigned char	sdigest[HMAC_DIGEST_LEN];
13817c478bd9Sstevel@tonic-gate 	url_t		req_url;
13827c478bd9Sstevel@tonic-gate 	char		*devpath;
13837c478bd9Sstevel@tonic-gate 	int		ret;
13847c478bd9Sstevel@tonic-gate 	int		fd;
13857c478bd9Sstevel@tonic-gate 	char		buf[NONCELEN + 1];
13867c478bd9Sstevel@tonic-gate 	int		retry_cnt = 0;
13877c478bd9Sstevel@tonic-gate 	int		retry_max = WANBOOT_RETRY_MAX;
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate 	/*
13907c478bd9Sstevel@tonic-gate 	 * Build the URL to request the wanboot file system. This URL
13917c478bd9Sstevel@tonic-gate 	 * will include the CGI script name and the IP, CID, and
13927c478bd9Sstevel@tonic-gate 	 * NONCE parameters.
13937c478bd9Sstevel@tonic-gate 	 */
13947c478bd9Sstevel@tonic-gate 	if (build_request_url(&req_url, URLtype_wanbootfs, server_url) == -1) {
13957c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
13967c478bd9Sstevel@tonic-gate 		    "Can't build the URL to make the %s request",
13977c478bd9Sstevel@tonic-gate 		    CGIcontent(URLtype_wanbootfs));
13987c478bd9Sstevel@tonic-gate 		return (-1);
13997c478bd9Sstevel@tonic-gate 	}
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	/*
14027c478bd9Sstevel@tonic-gate 	 * Go get the wanboot file system. If we fail reading the
14037c478bd9Sstevel@tonic-gate 	 * response we re-request the entire file system.
14047c478bd9Sstevel@tonic-gate 	 */
14057c478bd9Sstevel@tonic-gate 	bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading wanboot file system");
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	bzero(cdigest, sizeof (cdigest));
14087c478bd9Sstevel@tonic-gate 	do {
14097c478bd9Sstevel@tonic-gate 		if ((ret = establish_http_connection(WANBOOTFS, &handle,
14107c478bd9Sstevel@tonic-gate 		    &req_url, 0)) < 0) {
14117c478bd9Sstevel@tonic-gate 			break;
14127c478bd9Sstevel@tonic-gate 		} else if (ret > 0) {
14137c478bd9Sstevel@tonic-gate 			if (wanboot_retry(++retry_cnt, retry_max)) {
14147c478bd9Sstevel@tonic-gate 				continue;
14157c478bd9Sstevel@tonic-gate 			} else {
14167c478bd9Sstevel@tonic-gate 				break;
14177c478bd9Sstevel@tonic-gate 			}
14187c478bd9Sstevel@tonic-gate 		}
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 		if ((ret = process_wanbootfs(handle, &devpath,
14217c478bd9Sstevel@tonic-gate 		    cdigest, sdigest)) > 0) {
14227c478bd9Sstevel@tonic-gate 			if (!wanboot_retry(++retry_cnt, retry_max)) {
14237c478bd9Sstevel@tonic-gate 				(void) http_srv_close(handle);
14247c478bd9Sstevel@tonic-gate 				break;
14257c478bd9Sstevel@tonic-gate 			}
14267c478bd9Sstevel@tonic-gate 		}
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 		(void) http_srv_close(handle);
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 	} while (ret > 0);
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 	/*
14337c478bd9Sstevel@tonic-gate 	 * Validate the computed digest against the one received.
14347c478bd9Sstevel@tonic-gate 	 */
14357c478bd9Sstevel@tonic-gate 	if (ret != 0 ||
14367c478bd9Sstevel@tonic-gate 	    !verify_digests(WANBOOTFS, cdigest, sdigest)) {
14377c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
14387c478bd9Sstevel@tonic-gate 		    "The wanboot file system download aborted");
14397c478bd9Sstevel@tonic-gate 		return (-1);
14407c478bd9Sstevel@tonic-gate 	}
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	/*
14437c478bd9Sstevel@tonic-gate 	 * Mount the wanboot file system.
14447c478bd9Sstevel@tonic-gate 	 */
14457c478bd9Sstevel@tonic-gate 	if (determine_fstype_and_mountroot(devpath) != VFS_SUCCESS) {
14467c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
14477c478bd9Sstevel@tonic-gate 		    "Could not mount the wanboot filesystem.");
14487c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
14497c478bd9Sstevel@tonic-gate 		    "This may signify a client/server key mismatch");
14507c478bd9Sstevel@tonic-gate 		if (encr_type != ENCR_NONE) {
14517c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_CRIT,
14527c478bd9Sstevel@tonic-gate 			    "(client has key but wrong encryption_type?)");
14537c478bd9Sstevel@tonic-gate 		} else {
14547c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_CRIT,
14557c478bd9Sstevel@tonic-gate 			    "(encryption_type specified but no client key?)");
14567c478bd9Sstevel@tonic-gate 		}
14577c478bd9Sstevel@tonic-gate 		return (-1);
14587c478bd9Sstevel@tonic-gate 	}
14597c478bd9Sstevel@tonic-gate 	bootlog("wanboot", BOOTLOG_VERBOSE,
14607c478bd9Sstevel@tonic-gate 	    "The wanboot file system has been mounted");
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 	/*
14637c478bd9Sstevel@tonic-gate 	 * The wanboot file system should contain a nonce. Read it
14647c478bd9Sstevel@tonic-gate 	 * and compare it against the nonce sent in the request.
14657c478bd9Sstevel@tonic-gate 	 */
14667c478bd9Sstevel@tonic-gate 	if ((fd = open(WANBOOTFS_NONCE_FILE, O_RDONLY)) == -1) {
14677c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
14687c478bd9Sstevel@tonic-gate 		    "No nonce found in the wanboot file system");
14697c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
14707c478bd9Sstevel@tonic-gate 		    "The wanboot file system download aborted");
14717c478bd9Sstevel@tonic-gate 		return (-1);
14727c478bd9Sstevel@tonic-gate 	}
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 	if (read(fd, buf, NONCELEN) != NONCELEN ||
14757c478bd9Sstevel@tonic-gate 	    bcmp(nonce, buf, NONCELEN) != 0) {
14767c478bd9Sstevel@tonic-gate 		(void) close(fd);
14777c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
14787c478bd9Sstevel@tonic-gate 		    "Invalid nonce found in the wanboot file system");
14797c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
14807c478bd9Sstevel@tonic-gate 		    "The wanboot file system download aborted");
14817c478bd9Sstevel@tonic-gate 		return (-1);
14827c478bd9Sstevel@tonic-gate 	}
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate 	(void) close(fd);
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate 	bootlog("wanboot", BOOTLOG_VERBOSE,
14877c478bd9Sstevel@tonic-gate 	    "The wanboot file system download was successful");
14887c478bd9Sstevel@tonic-gate 	return (0);
14897c478bd9Sstevel@tonic-gate }
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate static boolean_t
init_netdev(char * bpath)14927c478bd9Sstevel@tonic-gate init_netdev(char *bpath)
14937c478bd9Sstevel@tonic-gate {
1494fa9e4066Sahrens 	pnode_t		anode;
14957c478bd9Sstevel@tonic-gate 	int		proplen;
1496*c8551b44SJerry Gilliam 	char		netalias[OBP_MAXPATHLEN];
1497*c8551b44SJerry Gilliam 	static char	devpath[OBP_MAXPATHLEN];
1498*c8551b44SJerry Gilliam 	char		*p;
1499*c8551b44SJerry Gilliam 
1500*c8551b44SJerry Gilliam 	bzero(netalias, sizeof (netalias));
1501*c8551b44SJerry Gilliam 	bzero(devpath, sizeof (devpath));
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	/*
15047c478bd9Sstevel@tonic-gate 	 * Wanboot will either have loaded over the network (in which case
15057c478bd9Sstevel@tonic-gate 	 * bpath will name a network device), or from CD-ROM or disk.  In
1506*c8551b44SJerry Gilliam 	 * either case ensure that the 'net' alias corresponds to a network
15077c478bd9Sstevel@tonic-gate 	 * device, and that if a network boot was performed that it is
15087c478bd9Sstevel@tonic-gate 	 * identical to bpath.  This is so that the interface name can always
15097c478bd9Sstevel@tonic-gate 	 * be determined for CD-ROM or disk boots, and for manually-configured
15107c478bd9Sstevel@tonic-gate 	 * network boots.  The latter restriction may be relaxed in the future.
15117c478bd9Sstevel@tonic-gate 	 */
15127c478bd9Sstevel@tonic-gate 	anode = prom_alias_node();
1513*c8551b44SJerry Gilliam 	if ((proplen = prom_getproplen(anode, "net")) <= 0 ||
1514*c8551b44SJerry Gilliam 	    proplen > sizeof (netalias)) {
1515*c8551b44SJerry Gilliam 		goto error;
1516*c8551b44SJerry Gilliam 	}
15177c478bd9Sstevel@tonic-gate 	(void) prom_getprop(anode, "net", (caddr_t)netalias);
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate 	/*
1520*c8551b44SJerry Gilliam 	 * Strip boot arguments from the net device to form
1521*c8551b44SJerry Gilliam 	 * the boot device path, returned as netdev_path.
15227c478bd9Sstevel@tonic-gate 	 */
1523*c8551b44SJerry Gilliam 	if (strlcpy(devpath, netalias, sizeof (devpath)) >= sizeof (devpath))
1524*c8551b44SJerry Gilliam 		goto error;
1525*c8551b44SJerry Gilliam 	if ((p = strchr(devpath, ':')) != NULL) {
15267c478bd9Sstevel@tonic-gate 		*p = '\0';
15277c478bd9Sstevel@tonic-gate 	}
15287c478bd9Sstevel@tonic-gate 
1529*c8551b44SJerry Gilliam 	if (!is_netdev(netalias)) {
1530*c8551b44SJerry Gilliam 		bootlog("wanboot", BOOTLOG_CRIT, "'net'=%s\n", netalias);
1531*c8551b44SJerry Gilliam 		goto error;
1532*c8551b44SJerry Gilliam 	}
1533*c8551b44SJerry Gilliam 
1534*c8551b44SJerry Gilliam 	if (is_netdev(bpath)) {
15357c478bd9Sstevel@tonic-gate 		/*
15367c478bd9Sstevel@tonic-gate 		 * If bpath is a network device path, then v2path
15377c478bd9Sstevel@tonic-gate 		 * will be a copy of this sans device arguments.
15387c478bd9Sstevel@tonic-gate 		 */
1539*c8551b44SJerry Gilliam 		if (strcmp(v2path, devpath) != 0) {
1540*c8551b44SJerry Gilliam 			bootlog("wanboot", BOOTLOG_CRIT,
1541*c8551b44SJerry Gilliam 			    "'net'=%s\n", netalias);
15427c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_CRIT,
15437c478bd9Sstevel@tonic-gate 			    "wanboot requires that the 'net' alias refers to ");
15447c478bd9Sstevel@tonic-gate 			bootlog("wanboot", BOOTLOG_CRIT,
15457c478bd9Sstevel@tonic-gate 			    "the network device path from which it loaded");
15467c478bd9Sstevel@tonic-gate 			return (B_FALSE);
15477c478bd9Sstevel@tonic-gate 		}
1548*c8551b44SJerry Gilliam 	} else {
1549*c8551b44SJerry Gilliam 		bpath = netalias;
15507c478bd9Sstevel@tonic-gate 	}
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 	/*
1553*c8551b44SJerry Gilliam 	 * Configure the network and return the network device.
1554*c8551b44SJerry Gilliam 	 */
1555*c8551b44SJerry Gilliam 	bootlog("wanboot", BOOTLOG_INFO, "configuring %s\n", bpath);
1556*c8551b44SJerry Gilliam 	netdev_path = devpath;
1557*c8551b44SJerry Gilliam 	mac_init(bpath);
1558*c8551b44SJerry Gilliam 	return (B_TRUE);
1559*c8551b44SJerry Gilliam 
1560*c8551b44SJerry Gilliam error:
1561*c8551b44SJerry Gilliam 	/*
15627c478bd9Sstevel@tonic-gate 	 * If we haven't established a device path for a network interface,
15637c478bd9Sstevel@tonic-gate 	 * then we're doomed.
15647c478bd9Sstevel@tonic-gate 	 */
15657c478bd9Sstevel@tonic-gate 	bootlog("wanboot", BOOTLOG_CRIT,
15667c478bd9Sstevel@tonic-gate 	    "No network device available for wanboot!");
15677c478bd9Sstevel@tonic-gate 	bootlog("wanboot", BOOTLOG_CRIT,
15687c478bd9Sstevel@tonic-gate 	    "(Ensure that the 'net' alias is set correctly)");
15697c478bd9Sstevel@tonic-gate 	return (B_FALSE);
15707c478bd9Sstevel@tonic-gate }
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate /*
15737c478bd9Sstevel@tonic-gate  * This implementation of bootprog() is used solely by wanboot.
15747c478bd9Sstevel@tonic-gate  *
15757c478bd9Sstevel@tonic-gate  * The basic algorithm is as follows:
15767c478bd9Sstevel@tonic-gate  *
15777c478bd9Sstevel@tonic-gate  * - The wanboot options (those specified using the "-o" flag) are processed,
15787c478bd9Sstevel@tonic-gate  *   and if necessary the wanboot interpreter is invoked to collect other
15797c478bd9Sstevel@tonic-gate  *   options.
15807c478bd9Sstevel@tonic-gate  *
15817c478bd9Sstevel@tonic-gate  * - The wanboot filesystem (containing certificates, wanboot.conf file, etc.)
15827c478bd9Sstevel@tonic-gate  *   is then downloaded into the bootfs ramdisk, which is mounted for use
15837c478bd9Sstevel@tonic-gate  *   by OpenSSL, access to wanboot.conf, etc.
15847c478bd9Sstevel@tonic-gate  *
15857c478bd9Sstevel@tonic-gate  * - The wanboot miniroot is downloaded over http/https into the rootfs
15867c478bd9Sstevel@tonic-gate  *   ramdisk.  The bootfs filesystem is unmounted, and the rootfs filesystem
1587986fd29aSsetje  *   is booted.
15887c478bd9Sstevel@tonic-gate  */
15897c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15907c478bd9Sstevel@tonic-gate int
bootprog(char * bpath,char * bargs,boolean_t user_specified_filename)15917c478bd9Sstevel@tonic-gate bootprog(char *bpath, char *bargs, boolean_t user_specified_filename)
15927c478bd9Sstevel@tonic-gate {
15937c478bd9Sstevel@tonic-gate 	char		*miniroot_path;
15947c478bd9Sstevel@tonic-gate 	url_t		server_url;
15957c478bd9Sstevel@tonic-gate 	int		ret;
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 	if (!init_netdev(bpath)) {
15987c478bd9Sstevel@tonic-gate 		return (-1);
15997c478bd9Sstevel@tonic-gate 	}
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate 	if (!bootinfo_init()) {
16027c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT, "Cannot initialize bootinfo");
16037c478bd9Sstevel@tonic-gate 		return (-1);
16047c478bd9Sstevel@tonic-gate 	}
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	/*
16077c478bd9Sstevel@tonic-gate 	 * Get default values from PROM, etc., process any boot arguments
16087c478bd9Sstevel@tonic-gate 	 * (specified with the "-o" option), and initialize the interface.
16097c478bd9Sstevel@tonic-gate 	 */
16107c478bd9Sstevel@tonic-gate 	if (!wanboot_init_interface(wanboot_arguments)) {
16117c478bd9Sstevel@tonic-gate 		return (-1);
16127c478bd9Sstevel@tonic-gate 	}
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 	/*
16157c478bd9Sstevel@tonic-gate 	 * Determine which encryption and hashing algorithms the client
16167c478bd9Sstevel@tonic-gate 	 * is configured to use.
16177c478bd9Sstevel@tonic-gate 	 */
16187c478bd9Sstevel@tonic-gate 	init_encryption();
16197c478bd9Sstevel@tonic-gate 	init_hashing();
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate 	/*
16227c478bd9Sstevel@tonic-gate 	 * Get the bootserver value.  Should be of the form:
16237c478bd9Sstevel@tonic-gate 	 *	http://host[:port]/abspath.
16247c478bd9Sstevel@tonic-gate 	 */
16257c478bd9Sstevel@tonic-gate 	ret = get_url(BI_BOOTSERVER, &server_url);
16267c478bd9Sstevel@tonic-gate 	if (ret != 0) {
16277c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
16287c478bd9Sstevel@tonic-gate 		    "Unable to retrieve the bootserver URL");
16297c478bd9Sstevel@tonic-gate 		return (-1);
16307c478bd9Sstevel@tonic-gate 	}
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 	/*
16337c478bd9Sstevel@tonic-gate 	 * Get the wanboot file system and mount it. Contains metdata
16347c478bd9Sstevel@tonic-gate 	 * needed by wanboot.
16357c478bd9Sstevel@tonic-gate 	 */
16367c478bd9Sstevel@tonic-gate 	if (get_wanbootfs(&server_url) != 0) {
16377c478bd9Sstevel@tonic-gate 		return (-1);
16387c478bd9Sstevel@tonic-gate 	}
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	/*
16417c478bd9Sstevel@tonic-gate 	 * Check that there is a valid wanboot.conf file in the wanboot
16427c478bd9Sstevel@tonic-gate 	 * file system.
16437c478bd9Sstevel@tonic-gate 	 */
16447c478bd9Sstevel@tonic-gate 	if (bootconf_init(&bc_handle, NULL) != BC_E_NOERROR) {
16457c478bd9Sstevel@tonic-gate 		bootlog("wanboot", BOOTLOG_CRIT,
16467c478bd9Sstevel@tonic-gate 		    "wanboot.conf error (code=%d)", bc_handle.bc_error_code);
16477c478bd9Sstevel@tonic-gate 		return (-1);
16487c478bd9Sstevel@tonic-gate 	}
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 	/*
16517c478bd9Sstevel@tonic-gate 	 * Set the time
16527c478bd9Sstevel@tonic-gate 	 */
16537c478bd9Sstevel@tonic-gate 	init_boot_time();
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	/*
16567c478bd9Sstevel@tonic-gate 	 * Verify that URLs in wanboot.conf can be reached, etc.
16577c478bd9Sstevel@tonic-gate 	 */
16587c478bd9Sstevel@tonic-gate 	if (!wanboot_verify_config()) {
16597c478bd9Sstevel@tonic-gate 		return (-1);
16607c478bd9Sstevel@tonic-gate 	}
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 	/*
16637c478bd9Sstevel@tonic-gate 	 * Retrieve the miniroot.
16647c478bd9Sstevel@tonic-gate 	 */
16657c478bd9Sstevel@tonic-gate 	if (get_miniroot(&miniroot_path) != 0) {
16667c478bd9Sstevel@tonic-gate 		return (-1);
16677c478bd9Sstevel@tonic-gate 	}
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	/*
16707c478bd9Sstevel@tonic-gate 	 * We don't need the wanboot file system mounted anymore and
16717c478bd9Sstevel@tonic-gate 	 * should unmount it so that we can mount the miniroot.
16727c478bd9Sstevel@tonic-gate 	 */
16737c478bd9Sstevel@tonic-gate 	(void) unmountroot();
16747c478bd9Sstevel@tonic-gate 
1675986fd29aSsetje 	boot_ramdisk(RD_ROOTFS);
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate 	return (0);
16787c478bd9Sstevel@tonic-gate }
1679