10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*12899Sdminer@opensolaris.org  * Common Development and Distribution License (the "License").
6*12899Sdminer@opensolaris.org  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12899Sdminer@opensolaris.org  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <stdio.h>
260Sstevel@tonic-gate #include <stdlib.h>
270Sstevel@tonic-gate #include <strings.h>
280Sstevel@tonic-gate #include <string.h>
290Sstevel@tonic-gate #include <libgen.h>
300Sstevel@tonic-gate #include <unistd.h>
310Sstevel@tonic-gate #include <fcntl.h>
320Sstevel@tonic-gate #include <errno.h>
330Sstevel@tonic-gate #include <netdb.h>
340Sstevel@tonic-gate #include <libnvpair.h>
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/wait.h>
370Sstevel@tonic-gate #include <sys/stat.h>
380Sstevel@tonic-gate #include <sys/param.h>
390Sstevel@tonic-gate #include <sys/sysmacros.h>
400Sstevel@tonic-gate #include <sys/mman.h>
410Sstevel@tonic-gate #include <sys/socket.h>
42*12899Sdminer@opensolaris.org #include <sys/utsname.h>
430Sstevel@tonic-gate #include <sys/wanboot_impl.h>
440Sstevel@tonic-gate #include <netinet/in.h>
450Sstevel@tonic-gate #include <arpa/inet.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate #include <openssl/crypto.h>
480Sstevel@tonic-gate #include <openssl/x509.h>
490Sstevel@tonic-gate #include <openssl/x509v3.h>
500Sstevel@tonic-gate #include <openssl/pem.h>
510Sstevel@tonic-gate #include <openssl/pkcs12.h>
520Sstevel@tonic-gate #include <openssl/evp.h>
530Sstevel@tonic-gate #include <openssl/err.h>
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #include <p12aux.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate #include <parseURL.h>
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate  * These can be replaced with wanbootutil.h once the openssl interfaces
600Sstevel@tonic-gate  * are moved to libwanboot.
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate #include <wanboot/key_util.h>
630Sstevel@tonic-gate #include <wanboot/key_xdr.h>
640Sstevel@tonic-gate #include <hmac_sha1.h>
650Sstevel@tonic-gate 
660Sstevel@tonic-gate #include <netboot_paths.h>
670Sstevel@tonic-gate #include <wanboot_conf.h>
680Sstevel@tonic-gate 
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate  * Exit status:
710Sstevel@tonic-gate  */
720Sstevel@tonic-gate #define	WBCGI_STATUS_OK		0
730Sstevel@tonic-gate #define	WBCGI_STATUS_ERR	1
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #define	WBCGI_FILE_EXISTS(file, statbuf) \
760Sstevel@tonic-gate 	(stat(file, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
770Sstevel@tonic-gate 
780Sstevel@tonic-gate #define	WBCGI_DIR_EXISTS(dir, statbuf) \
790Sstevel@tonic-gate 	(stat(dir, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
800Sstevel@tonic-gate 
810Sstevel@tonic-gate #define	WBCGI_HMAC_PATH		"/usr/lib/inet/wanboot/hmac"
820Sstevel@tonic-gate #define	WBCGI_ENCR_PATH		"/usr/lib/inet/wanboot/encr"
830Sstevel@tonic-gate #define	WBCGI_KEYMGMT_PATH	"/usr/lib/inet/wanboot/keymgmt"
840Sstevel@tonic-gate #define	WBCGI_MKISOFS_PATH	"/bin/mkisofs"
850Sstevel@tonic-gate 
860Sstevel@tonic-gate #define	WBCGI_DEV_URANDOM	"/dev/urandom"
870Sstevel@tonic-gate 
880Sstevel@tonic-gate #define	WBCGI_CONTENT_TYPE	"Content-Type: "
890Sstevel@tonic-gate #define	WBCGI_CONTENT_LENGTH	"Content-Length: "
900Sstevel@tonic-gate #define	WBCGI_WANBOOT_BNDTXT	"WANBoot_Part_Boundary"
910Sstevel@tonic-gate #define	WBCGI_CRNL		"\r\n"
920Sstevel@tonic-gate 
930Sstevel@tonic-gate #define	WBCGI_CNSTR		"CN="
940Sstevel@tonic-gate #define	WBCGI_CNSTR_LEN		(sizeof (WBCGI_CNSTR) - 1)
950Sstevel@tonic-gate #define	WBCGI_NAMESEP		",/\n\r"
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #define	WBCGI_MAXBUF		256
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate  * Possible return values from netboot_ftw():
1010Sstevel@tonic-gate  */
1020Sstevel@tonic-gate #define	WBCGI_FTW_CBOK		2	/* CB terminated walk OK */
1030Sstevel@tonic-gate #define	WBCGI_FTW_CBCONT	1	/* CB wants walk should continue */
1040Sstevel@tonic-gate #define	WBCGI_FTW_DONE		0	/* Walk terminated without CBERR/CBOK */
1050Sstevel@tonic-gate #define	WBCGI_FTW_CBERR		-1	/* CB terminated walk with err */
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate  * getsubopt() is used to map one of the contents[] keywords
1090Sstevel@tonic-gate  * to one of these types
1100Sstevel@tonic-gate  */
1110Sstevel@tonic-gate #define	WBCGI_CONTENT_ERROR	-1
1120Sstevel@tonic-gate #define	WBCGI_CONTENT_BOOTFILE	0
1130Sstevel@tonic-gate #define	WBCGI_CONTENT_BOOTFS	1
1140Sstevel@tonic-gate #define	WBCGI_CONTENT_ROOTFS	2
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate static char *contents[] =
1170Sstevel@tonic-gate 	{ "bootfile", "bootfs", "rootfs", NULL };
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /*
1200Sstevel@tonic-gate  * getsubopt() is used to parse the query string for
1210Sstevel@tonic-gate  * the keywords defined by queryopts[]
1220Sstevel@tonic-gate  */
1230Sstevel@tonic-gate #define	WBCGI_QUERYOPT_CONTENT	0
1240Sstevel@tonic-gate #define	WBCGI_QUERYOPT_NET	1
1250Sstevel@tonic-gate #define	WBCGI_QUERYOPT_CID	2
1260Sstevel@tonic-gate #define	WBCGI_QUERYOPT_NONCE	3
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate static char *queryopts[] =
1290Sstevel@tonic-gate 	{ "CONTENT", "IP", "CID", "NONCE", NULL };
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate static bc_handle_t	bc_handle;
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate static char *
status_msg(int status)1350Sstevel@tonic-gate status_msg(int status)
1360Sstevel@tonic-gate {
1370Sstevel@tonic-gate 	char	*msg;
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	switch (status) {
1400Sstevel@tonic-gate 	case 400:
1410Sstevel@tonic-gate 		msg = "Bad Request";
1420Sstevel@tonic-gate 		break;
1430Sstevel@tonic-gate 	case 403:
1440Sstevel@tonic-gate 		msg = "Forbidden";
1450Sstevel@tonic-gate 		break;
1460Sstevel@tonic-gate 	case 500:
1470Sstevel@tonic-gate 		msg = "Internal Server Error";
1480Sstevel@tonic-gate 		break;
1490Sstevel@tonic-gate 	default:
1500Sstevel@tonic-gate 		msg = "Unknown status";
1510Sstevel@tonic-gate 		break;
1520Sstevel@tonic-gate 	}
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	return (msg);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate static void
print_status(int status,const char * spec_msg)1580Sstevel@tonic-gate print_status(int status, const char *spec_msg)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate 	if (spec_msg == NULL) {
1610Sstevel@tonic-gate 		spec_msg = "";
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	(void) fprintf(stdout, "Status: %d %s %s%s", status,
1650Sstevel@tonic-gate 	    status_msg(status), spec_msg, WBCGI_CRNL);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate static char *
make_path(const char * root,const char * suffix)1690Sstevel@tonic-gate make_path(const char *root, const char *suffix)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate 	char	path[MAXPATHLEN];
1720Sstevel@tonic-gate 	char	*ptr = NULL;
1730Sstevel@tonic-gate 	int	chars;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	if ((chars = snprintf(path, sizeof (path),
1760Sstevel@tonic-gate 	    "%s/%s", root, suffix)) < 0 || chars > sizeof (path) ||
1770Sstevel@tonic-gate 	    (ptr = strdup(path)) == NULL) {
1780Sstevel@tonic-gate 		print_status(500, "(error making path)");
1790Sstevel@tonic-gate 	}
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	return (ptr);
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate static void
free_path(char ** pathp)1850Sstevel@tonic-gate free_path(char **pathp)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	if (*pathp != NULL) {
1880Sstevel@tonic-gate 		free(*pathp);
1890Sstevel@tonic-gate 		*pathp = NULL;
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate static char *
gen_tmppath(const char * prefix,const char * net,const char * cid)1940Sstevel@tonic-gate gen_tmppath(const char *prefix, const char *net, const char *cid)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate 	pid_t	pid;
1970Sstevel@tonic-gate 	time_t	secs;
1980Sstevel@tonic-gate 	int	chars;
1990Sstevel@tonic-gate 	char	path[MAXPATHLEN];
2000Sstevel@tonic-gate 	char	*ptr = NULL;
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	if ((pid = getpid()) < 0 || (secs = time(NULL)) < 0 ||
2030Sstevel@tonic-gate 	    (chars = snprintf(path, sizeof (path), "/tmp/%s_%s_%s_%ld_%ld",
2040Sstevel@tonic-gate 	    prefix, net, cid, pid, secs)) < 0 || chars > sizeof (path) ||
2050Sstevel@tonic-gate 	    (ptr = strdup(path)) == NULL) {
2060Sstevel@tonic-gate 		print_status(500, "(error creating temporary filename)");
2070Sstevel@tonic-gate 	}
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	return (ptr);
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate /*
2130Sstevel@tonic-gate  * File I/O stuff:
2140Sstevel@tonic-gate  */
2150Sstevel@tonic-gate static boolean_t
write_buffer(int fd,const void * buffer,size_t buflen)2160Sstevel@tonic-gate write_buffer(int fd, const void *buffer, size_t buflen)
2170Sstevel@tonic-gate {
2180Sstevel@tonic-gate 	size_t		nwritten;
2190Sstevel@tonic-gate 	ssize_t		nbytes;
2200Sstevel@tonic-gate 	const char	*buf = buffer;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	for (nwritten = 0; nwritten < buflen; nwritten += nbytes) {
2230Sstevel@tonic-gate 		nbytes = write(fd, &buf[nwritten], buflen - nwritten);
2240Sstevel@tonic-gate 		if (nbytes <= 0) {
2250Sstevel@tonic-gate 			return (B_FALSE);
2260Sstevel@tonic-gate 		}
2270Sstevel@tonic-gate 	}
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	return (B_TRUE);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate static boolean_t
write_file(int ofd,const char * filename,size_t size)2330Sstevel@tonic-gate write_file(int ofd, const char *filename, size_t size)
2340Sstevel@tonic-gate {
2350Sstevel@tonic-gate 	boolean_t	ret = B_TRUE;
2360Sstevel@tonic-gate 	int		ifd;
2370Sstevel@tonic-gate 	char		buf[1024];
2380Sstevel@tonic-gate 	size_t		rlen;
2390Sstevel@tonic-gate 	ssize_t		wlen;
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	if ((ifd = open(filename, O_RDONLY)) < 0) {
2420Sstevel@tonic-gate 		return (B_FALSE);
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	for (; size != 0; size -= wlen) {
2460Sstevel@tonic-gate 		rlen = (size < sizeof (buf)) ? size : sizeof (buf);
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 		if ((wlen = read(ifd, buf, rlen)) < 0 ||
2490Sstevel@tonic-gate 		    !write_buffer(ofd, buf, wlen)) {
2500Sstevel@tonic-gate 			ret = B_FALSE;
2510Sstevel@tonic-gate 			break;
2520Sstevel@tonic-gate 		}
2530Sstevel@tonic-gate 	}
2540Sstevel@tonic-gate 	(void) close(ifd);
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	return (ret);
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate static boolean_t
copy_file(const char * src,const char * dest)2600Sstevel@tonic-gate copy_file(const char *src, const char *dest)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate 	boolean_t	ret = B_FALSE;
2630Sstevel@tonic-gate 	char		message[WBCGI_MAXBUF];
2640Sstevel@tonic-gate 	const size_t	chunksize = 16 * PAGESIZE;
2650Sstevel@tonic-gate 	size_t		validsize;
2660Sstevel@tonic-gate 	size_t		nwritten = 0;
2670Sstevel@tonic-gate 	size_t		nbytes = 0;
2680Sstevel@tonic-gate 	off_t		roff;
2690Sstevel@tonic-gate 	int		mflags = MAP_PRIVATE;
2700Sstevel@tonic-gate 	char		*buf = NULL;
2710Sstevel@tonic-gate 	struct stat	st;
2720Sstevel@tonic-gate 	int		rfd = -1;
2730Sstevel@tonic-gate 	int		wfd = -1;
2740Sstevel@tonic-gate 	int		chars;
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	if ((rfd = open(src, O_RDONLY)) < 0 ||
2770Sstevel@tonic-gate 	    (wfd = open(dest, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR)) < 0 ||
2780Sstevel@tonic-gate 	    fstat(rfd, &st) == -1) {
2790Sstevel@tonic-gate 		goto cleanup;
2800Sstevel@tonic-gate 	}
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	for (nbytes = st.st_size, roff = 0; nwritten < nbytes;
2830Sstevel@tonic-gate 	    nwritten += validsize, roff += validsize) {
2840Sstevel@tonic-gate 		buf = mmap(buf, chunksize, PROT_READ, mflags, rfd, roff);
2850Sstevel@tonic-gate 		if (buf == MAP_FAILED) {
2860Sstevel@tonic-gate 			goto cleanup;
2870Sstevel@tonic-gate 		}
2880Sstevel@tonic-gate 		mflags |= MAP_FIXED;
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 		validsize = MIN(chunksize, nbytes - nwritten);
2910Sstevel@tonic-gate 		if (!write_buffer(wfd, buf, validsize)) {
2920Sstevel@tonic-gate 			(void) munmap(buf, chunksize);
2930Sstevel@tonic-gate 			goto cleanup;
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	}
2970Sstevel@tonic-gate 	if (buf != NULL) {
2980Sstevel@tonic-gate 		(void) munmap(buf, chunksize);
2990Sstevel@tonic-gate 	}
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	ret = B_TRUE;
3020Sstevel@tonic-gate cleanup:
3030Sstevel@tonic-gate 	if (ret == B_FALSE) {
3040Sstevel@tonic-gate 		if ((chars = snprintf(message, sizeof (message),
3050Sstevel@tonic-gate 		    "error copying %s to %s", src, dest)) > 0 &&
3060Sstevel@tonic-gate 		    chars <= sizeof (message)) {
3070Sstevel@tonic-gate 			print_status(500, message);
3080Sstevel@tonic-gate 		} else {
3090Sstevel@tonic-gate 			print_status(500, NULL);
3100Sstevel@tonic-gate 		}
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 	if (rfd != -1) {
3130Sstevel@tonic-gate 		(void) close(rfd);
3140Sstevel@tonic-gate 	}
3150Sstevel@tonic-gate 	if (wfd != -1) {
3160Sstevel@tonic-gate 		(void) close(wfd);
3170Sstevel@tonic-gate 	}
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	return (ret);
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate static boolean_t
create_nonce(const char * noncepath,const char * nonce)3230Sstevel@tonic-gate create_nonce(const char *noncepath, const char *nonce)
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate 	boolean_t	ret = B_TRUE;
3260Sstevel@tonic-gate 	int		fd;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	if ((fd = open(noncepath,
3290Sstevel@tonic-gate 	    O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
3300Sstevel@tonic-gate 	    !write_buffer(fd, nonce, strlen(nonce))) {
3310Sstevel@tonic-gate 		print_status(500, "(error creating nonce file)");
3320Sstevel@tonic-gate 		ret = B_FALSE;
3330Sstevel@tonic-gate 	}
3340Sstevel@tonic-gate 	if (fd != -1) {
3350Sstevel@tonic-gate 		(void) close(fd);
3360Sstevel@tonic-gate 	}
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	return (ret);
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate static boolean_t
create_timestamp(const char * timestamppath,const char * timestamp)3420Sstevel@tonic-gate create_timestamp(const char *timestamppath, const char *timestamp)
3430Sstevel@tonic-gate {
3440Sstevel@tonic-gate 	boolean_t	ret = B_TRUE;
3450Sstevel@tonic-gate 	int		fd;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	if ((fd = open(timestamppath,
3480Sstevel@tonic-gate 	    O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
3490Sstevel@tonic-gate 	    !write_buffer(fd, timestamp, strlen(timestamp))) {
3500Sstevel@tonic-gate 		print_status(500, "(error creating timestamp file)");
3510Sstevel@tonic-gate 		ret = B_FALSE;
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 	if (fd != -1) {
3540Sstevel@tonic-gate 		(void) close(fd);
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	return (ret);
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate static boolean_t
create_urandom(const char * urandompath)3610Sstevel@tonic-gate create_urandom(const char *urandompath)
3620Sstevel@tonic-gate {
3630Sstevel@tonic-gate 	boolean_t	ret = B_TRUE;
3640Sstevel@tonic-gate 	int		fd;
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	if ((fd = open(urandompath,
3670Sstevel@tonic-gate 	    O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
3680Sstevel@tonic-gate 	    !write_file(fd, WBCGI_DEV_URANDOM, 32 * 1024)) {
3690Sstevel@tonic-gate 		print_status(500, "(error creating urandom file)");
3700Sstevel@tonic-gate 		ret = B_FALSE;
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 	if (fd != -1) {
3730Sstevel@tonic-gate 		(void) close(fd);
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	return (ret);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate static boolean_t
create_null_hash(const char * hashpath)3800Sstevel@tonic-gate create_null_hash(const char *hashpath)
3810Sstevel@tonic-gate {
3820Sstevel@tonic-gate 	boolean_t	ret = B_TRUE;
3830Sstevel@tonic-gate 	int		fd;
3840Sstevel@tonic-gate 	static char	null_hash[HMAC_DIGEST_LEN];
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	if ((fd = open(hashpath,
3870Sstevel@tonic-gate 	    O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
3880Sstevel@tonic-gate 	    !write_buffer(fd, null_hash, sizeof (null_hash))) {
3890Sstevel@tonic-gate 		print_status(500, "(error creating null hash)");
3900Sstevel@tonic-gate 		ret = B_FALSE;
3910Sstevel@tonic-gate 	}
3920Sstevel@tonic-gate 	if (fd != -1) {
3930Sstevel@tonic-gate 		(void) close(fd);
3940Sstevel@tonic-gate 	}
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	return (ret);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate static char *
determine_doc_root(void)4010Sstevel@tonic-gate determine_doc_root(void)
4020Sstevel@tonic-gate {
4030Sstevel@tonic-gate 	char	*doc_root;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	/*
4060Sstevel@tonic-gate 	 * If DOCUMENT_ROOT is valid, use that.
4070Sstevel@tonic-gate 	 */
4080Sstevel@tonic-gate 	if ((doc_root = getenv("DOCUMENT_ROOT")) == NULL ||
4090Sstevel@tonic-gate 	    strlen(doc_root) == 0) {
4100Sstevel@tonic-gate 		/*
4110Sstevel@tonic-gate 		 * No DOCUMENT_ROOT - try PATH_TRANSLATED.
4120Sstevel@tonic-gate 		 */
4130Sstevel@tonic-gate 		if ((doc_root = getenv("PATH_TRANSLATED")) == NULL ||
4140Sstevel@tonic-gate 		    strlen(doc_root) == 0) {
4150Sstevel@tonic-gate 			/*
4160Sstevel@tonic-gate 			 * Can't determine the document root.
4170Sstevel@tonic-gate 			 */
4180Sstevel@tonic-gate 			return (NULL);
4190Sstevel@tonic-gate 		}
4200Sstevel@tonic-gate 	}
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	return (doc_root);
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate static boolean_t
get_request_info(int * contentp,char ** netp,char ** cidp,char ** noncep,char ** docrootp)4260Sstevel@tonic-gate get_request_info(int *contentp, char **netp, char **cidp, char **noncep,
4270Sstevel@tonic-gate     char **docrootp)
4280Sstevel@tonic-gate {
4290Sstevel@tonic-gate 	char	*method;
4300Sstevel@tonic-gate 	char	*query_string;
4310Sstevel@tonic-gate 	char	*value;
4320Sstevel@tonic-gate 	char	*junk;
4330Sstevel@tonic-gate 	int	i;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	if ((method = getenv("REQUEST_METHOD")) == NULL ||
4360Sstevel@tonic-gate 	    strncasecmp(method, "GET", strlen("GET") != 0)) {
4370Sstevel@tonic-gate 		print_status(403, "(GET method expected)");
4380Sstevel@tonic-gate 		return (B_FALSE);
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	if ((query_string = getenv("QUERY_STRING")) == NULL) {
4420Sstevel@tonic-gate 		print_status(400, "(empty query string)");
4430Sstevel@tonic-gate 		return (B_FALSE);
4440Sstevel@tonic-gate 	}
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	for (i = 0; i < strlen(query_string); i++) {
4470Sstevel@tonic-gate 		if (query_string[i] == '&') {
4480Sstevel@tonic-gate 			query_string[i] = ',';
4490Sstevel@tonic-gate 		}
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	*contentp = WBCGI_CONTENT_ERROR;
4530Sstevel@tonic-gate 	*netp = *cidp = *noncep = NULL;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	if ((*docrootp = determine_doc_root()) == NULL) {
4560Sstevel@tonic-gate 		print_status(400, "(unable to determine document root)");
4570Sstevel@tonic-gate 		return (B_FALSE);
4580Sstevel@tonic-gate 	}
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	while (*query_string != '\0') {
4610Sstevel@tonic-gate 		switch (getsubopt(&query_string, queryopts, &value)) {
4620Sstevel@tonic-gate 		case WBCGI_QUERYOPT_CONTENT:
4630Sstevel@tonic-gate 			*contentp = getsubopt(&value, contents, &junk);
4640Sstevel@tonic-gate 			break;
4650Sstevel@tonic-gate 		case WBCGI_QUERYOPT_NET:
4660Sstevel@tonic-gate 			*netp = value;
4670Sstevel@tonic-gate 			break;
4680Sstevel@tonic-gate 		case WBCGI_QUERYOPT_CID:
4690Sstevel@tonic-gate 			*cidp = value;
4700Sstevel@tonic-gate 			break;
4710Sstevel@tonic-gate 		case WBCGI_QUERYOPT_NONCE:
4720Sstevel@tonic-gate 			*noncep = value;
4730Sstevel@tonic-gate 			break;
4740Sstevel@tonic-gate 		default:
4750Sstevel@tonic-gate 			print_status(400, "(illegal query string)");
4760Sstevel@tonic-gate 			return (B_FALSE);
4770Sstevel@tonic-gate 			break;
4780Sstevel@tonic-gate 		}
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	switch (*contentp) {
4820Sstevel@tonic-gate 	default:
4830Sstevel@tonic-gate 		print_status(400, "(missing or illegal CONTENT)");
4840Sstevel@tonic-gate 		return (B_FALSE);
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	case WBCGI_CONTENT_BOOTFS:
4870Sstevel@tonic-gate 		if (*netp == NULL || *cidp == NULL || *noncep == NULL) {
4880Sstevel@tonic-gate 			print_status(400,
4890Sstevel@tonic-gate 			    "(CONTENT, IP, CID and NONCE required)");
4900Sstevel@tonic-gate 			return (B_FALSE);
4910Sstevel@tonic-gate 		}
4920Sstevel@tonic-gate 		break;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	case WBCGI_CONTENT_BOOTFILE:
4950Sstevel@tonic-gate 	case WBCGI_CONTENT_ROOTFS:
4960Sstevel@tonic-gate 		if (*netp == NULL || *cidp == NULL || *docrootp == NULL) {
4970Sstevel@tonic-gate 			print_status(400,
4980Sstevel@tonic-gate 			    "(CONTENT, IP, CID and DOCUMENT_ROOT required)");
4990Sstevel@tonic-gate 			return (B_FALSE);
5000Sstevel@tonic-gate 		}
5010Sstevel@tonic-gate 		break;
5020Sstevel@tonic-gate 	}
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	return (B_TRUE);
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate static boolean_t
encrypt_payload(const char * payload,const char * encr_payload,const char * keyfile,const char * encryption_type)5080Sstevel@tonic-gate encrypt_payload(const char *payload, const char *encr_payload,
5090Sstevel@tonic-gate     const char *keyfile, const char *encryption_type)
5100Sstevel@tonic-gate {
5110Sstevel@tonic-gate 	struct stat	sbuf;
5120Sstevel@tonic-gate 	int		chars;
5130Sstevel@tonic-gate 	char		cmd[MAXPATHLEN];
5140Sstevel@tonic-gate 	FILE		*fp;
5150Sstevel@tonic-gate 	int		status;
5160Sstevel@tonic-gate 	char		msg[WBCGI_MAXBUF];
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(payload, sbuf)) {
5190Sstevel@tonic-gate 		print_status(500, "(encrypt_payload: missing payload)");
5200Sstevel@tonic-gate 		return (B_FALSE);
5210Sstevel@tonic-gate 	}
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	if ((chars = snprintf(cmd, sizeof (cmd),
5240Sstevel@tonic-gate 	    "%s -o type=%s -k %s < %s > %s", WBCGI_ENCR_PATH,
5250Sstevel@tonic-gate 	    encryption_type, keyfile, payload, encr_payload)) < 0 ||
5260Sstevel@tonic-gate 	    chars > sizeof (cmd)) {
5270Sstevel@tonic-gate 		print_status(500, "(encrypt_payload: buffer overflow)");
5280Sstevel@tonic-gate 		return (B_FALSE);
5290Sstevel@tonic-gate 	}
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	if ((fp = popen(cmd, "w")) == NULL) {
5320Sstevel@tonic-gate 		print_status(500, "(encrypt_payload: missing/file error)");
5330Sstevel@tonic-gate 		return (B_FALSE);
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 	if ((status = WEXITSTATUS(pclose(fp))) != 0) {
5360Sstevel@tonic-gate 		(void) snprintf(msg, sizeof (msg),
5370Sstevel@tonic-gate 		    "(encrypt_payload: failed, status=%d)", status);
5380Sstevel@tonic-gate 		print_status(500, msg);
5390Sstevel@tonic-gate 		return (B_FALSE);
5400Sstevel@tonic-gate 	}
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(encr_payload, sbuf)) {
5430Sstevel@tonic-gate 		print_status(500, "(encrypt_payload: bad encrypted file)");
5440Sstevel@tonic-gate 		return (B_FALSE);
5450Sstevel@tonic-gate 	}
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	return (B_TRUE);
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate static boolean_t
hash_payload(const char * payload,const char * payload_hash,const char * keyfile)5510Sstevel@tonic-gate hash_payload(const char *payload, const char *payload_hash,
5520Sstevel@tonic-gate     const char *keyfile)
5530Sstevel@tonic-gate {
5540Sstevel@tonic-gate 	struct stat	sbuf;
5550Sstevel@tonic-gate 	int		chars;
5560Sstevel@tonic-gate 	char		cmd[MAXPATHLEN];
5570Sstevel@tonic-gate 	FILE		*fp;
5580Sstevel@tonic-gate 	int		status;
5590Sstevel@tonic-gate 	char		msg[WBCGI_MAXBUF];
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(payload, sbuf)) {
5620Sstevel@tonic-gate 		print_status(500, "(hash_payload: missing payload)");
5630Sstevel@tonic-gate 		return (B_FALSE);
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	if ((chars = snprintf(cmd, sizeof (cmd), "%s -i %s -k %s > %s",
5670Sstevel@tonic-gate 	    WBCGI_HMAC_PATH, payload, keyfile, payload_hash)) < 0 ||
5680Sstevel@tonic-gate 	    chars > sizeof (cmd)) {
5690Sstevel@tonic-gate 		print_status(500, "(hash_payload: buffer overflow)");
5700Sstevel@tonic-gate 		return (B_FALSE);
5710Sstevel@tonic-gate 	}
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	if ((fp = popen(cmd, "w")) == NULL) {
5740Sstevel@tonic-gate 		print_status(500, "(hash_payload: missing/file error)");
5750Sstevel@tonic-gate 		return (B_FALSE);
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 	if ((status = WEXITSTATUS(pclose(fp))) != 0) {
5780Sstevel@tonic-gate 		(void) snprintf(msg, sizeof (msg),
5790Sstevel@tonic-gate 		    "(hash_payload: failed, status=%d)", status);
5800Sstevel@tonic-gate 		print_status(500, msg);
5810Sstevel@tonic-gate 		return (B_FALSE);
5820Sstevel@tonic-gate 	}
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(payload_hash, sbuf) ||
5850Sstevel@tonic-gate 	    sbuf.st_size < HMAC_DIGEST_LEN) {
5860Sstevel@tonic-gate 		print_status(500, "(hash_payload: bad signature file)");
5870Sstevel@tonic-gate 		return (B_FALSE);
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	return (B_TRUE);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate static boolean_t
extract_keystore(const char * path,const char * keystorepath)5940Sstevel@tonic-gate extract_keystore(const char *path, const char *keystorepath)
5950Sstevel@tonic-gate {
5960Sstevel@tonic-gate 	struct stat	sbuf;
5970Sstevel@tonic-gate 	int		chars;
5980Sstevel@tonic-gate 	char		cmd[MAXPATHLEN];
5990Sstevel@tonic-gate 	FILE		*fp;
6000Sstevel@tonic-gate 	int		status;
6010Sstevel@tonic-gate 	char		msg[WBCGI_MAXBUF];
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(path, sbuf)) {
6040Sstevel@tonic-gate 		print_status(500, "(extract_keystore: missing keystore)");
6050Sstevel@tonic-gate 		return (B_FALSE);
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	if ((chars = snprintf(cmd, sizeof (cmd),
6090Sstevel@tonic-gate 	    "%s -x -f %s -s %s -o type=rsa",
6100Sstevel@tonic-gate 	    WBCGI_KEYMGMT_PATH, keystorepath, path)) < 0 ||
6110Sstevel@tonic-gate 	    chars > sizeof (cmd)) {
6120Sstevel@tonic-gate 		print_status(500, "(extract_keystore: buffer overflow)");
6130Sstevel@tonic-gate 		return (B_FALSE);
6140Sstevel@tonic-gate 	}
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	if ((fp = popen(cmd, "w")) == NULL) {
6170Sstevel@tonic-gate 		print_status(500, "(extract_keystore: missing/file error)");
6180Sstevel@tonic-gate 		return (B_FALSE);
6190Sstevel@tonic-gate 	}
6200Sstevel@tonic-gate 	if ((status = WEXITSTATUS(pclose(fp))) != 0) {
6210Sstevel@tonic-gate 		(void) snprintf(msg, sizeof (msg),
6220Sstevel@tonic-gate 		    "(extract_keystore: failed, status=%d)", status);
6230Sstevel@tonic-gate 		print_status(500, msg);
6240Sstevel@tonic-gate 		return (B_FALSE);
6250Sstevel@tonic-gate 	}
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(keystorepath, sbuf)) {
6280Sstevel@tonic-gate 		print_status(500, "(extract_keystore: failed to create)");
6290Sstevel@tonic-gate 		return (B_FALSE);
6300Sstevel@tonic-gate 	}
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	return (B_TRUE);
6330Sstevel@tonic-gate }
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate static boolean_t
mkisofs(const char * image_dir,const char * image)6360Sstevel@tonic-gate mkisofs(const char *image_dir, const char *image)
6370Sstevel@tonic-gate {
6380Sstevel@tonic-gate 	struct stat	sbuf;
6390Sstevel@tonic-gate 	int		chars;
6400Sstevel@tonic-gate 	char		cmd[MAXPATHLEN];
6410Sstevel@tonic-gate 	FILE		*fp;
6420Sstevel@tonic-gate 	int		status;
6430Sstevel@tonic-gate 	char		msg[WBCGI_MAXBUF];
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	if (!WBCGI_DIR_EXISTS(image_dir, sbuf)) {
6460Sstevel@tonic-gate 		print_status(500, "(mksiofs: missing image_dir)");
6470Sstevel@tonic-gate 		return (B_FALSE);
6480Sstevel@tonic-gate 	}
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	if ((chars = snprintf(cmd, sizeof (cmd), "%s -quiet -o %s -r %s",
6510Sstevel@tonic-gate 	    WBCGI_MKISOFS_PATH, image, image_dir)) < 0 ||
6520Sstevel@tonic-gate 	    chars > sizeof (cmd)) {
6530Sstevel@tonic-gate 		print_status(500, "(mkisofs: buffer overflow)");
6540Sstevel@tonic-gate 		return (B_FALSE);
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	if ((fp = popen(cmd, "w")) == NULL) {
6580Sstevel@tonic-gate 		print_status(500, "(mkisofs: missing/file error)");
6590Sstevel@tonic-gate 		return (B_FALSE);
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 	if ((status = WEXITSTATUS(pclose(fp))) != 0) {
6620Sstevel@tonic-gate 		(void) snprintf(msg, sizeof (msg),
6630Sstevel@tonic-gate 		    "(mkisofs: failed, status=%d)", status);
6640Sstevel@tonic-gate 		print_status(500, msg);
6650Sstevel@tonic-gate 		return (B_FALSE);
6660Sstevel@tonic-gate 	}
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(image, sbuf)) {
6690Sstevel@tonic-gate 		print_status(500, "(mksiofs: failed to create image)");
6700Sstevel@tonic-gate 		return (B_FALSE);
6710Sstevel@tonic-gate 	}
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	return (B_TRUE);
6740Sstevel@tonic-gate }
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate /*
6770Sstevel@tonic-gate  * This function, when invoked with a file name, optional network and
678*12899Sdminer@opensolaris.org  * client ID strings, and callback function will search for the file
679*12899Sdminer@opensolaris.org  * in the following locations:
680*12899Sdminer@opensolaris.org  *
681*12899Sdminer@opensolaris.org  * NB_NETBOOT_ROOT/<network>/<client id>/<file>
682*12899Sdminer@opensolaris.org  * NB_NETBOOT_ROOT/<client id>/<file>
683*12899Sdminer@opensolaris.org  * NB_NETBOOT_ROOT/<network>/<file>
684*12899Sdminer@opensolaris.org  * NB_NETBOOT_ROOT/<file>
685*12899Sdminer@opensolaris.org  *
686*12899Sdminer@opensolaris.org  * The callback function is invoked each time the file is found until
687*12899Sdminer@opensolaris.org  * we have searched all of the above locations or the callback function
688*12899Sdminer@opensolaris.org  * returns a value other than WBCGI_FTW_CBCONT.
6890Sstevel@tonic-gate  *
6900Sstevel@tonic-gate  * Arguments:
6910Sstevel@tonic-gate  *	filename - Name of file to search for.
6920Sstevel@tonic-gate  *	net      - Optional network number to include in search hierarchy.
6930Sstevel@tonic-gate  *	cid      - Optional client ID to include in search hierarchy.
6940Sstevel@tonic-gate  *	cb       - Callback function to be called when file is found.
6950Sstevel@tonic-gate  *	arg	 - Argument to be supplied to the callback funtion.
6960Sstevel@tonic-gate  *
6970Sstevel@tonic-gate  * Returns:
6980Sstevel@tonic-gate  *	WBCGI_FTW_DONE, WBCGI_FTW_CBOK or WBCGI_FTW_CBERR.
6990Sstevel@tonic-gate  */
7000Sstevel@tonic-gate static int
netboot_ftw(const char * filename,const char * net,const char * cid,int (* cb)(const char *,void * arg),void * arg)7010Sstevel@tonic-gate netboot_ftw(const char *filename, const char *net, const char *cid,
7020Sstevel@tonic-gate     int (*cb)(const char *, void *arg), void *arg)
7030Sstevel@tonic-gate {
704*12899Sdminer@opensolaris.org 	char		ckpath[4][MAXPATHLEN];
7050Sstevel@tonic-gate 	int		ret;
7060Sstevel@tonic-gate 	struct		stat buf;
707*12899Sdminer@opensolaris.org 	int		i = 0;
7080Sstevel@tonic-gate 
709*12899Sdminer@opensolaris.org 	if (snprintf(ckpath[i++], MAXPATHLEN, "%s%s", NB_NETBOOT_ROOT, filename)
710*12899Sdminer@opensolaris.org 	    >= MAXPATHLEN)
7110Sstevel@tonic-gate 		return (WBCGI_FTW_CBERR);
712*12899Sdminer@opensolaris.org 
713*12899Sdminer@opensolaris.org 	if (net != NULL && snprintf(ckpath[i++], MAXPATHLEN, "%s%s/%s",
714*12899Sdminer@opensolaris.org 	    NB_NETBOOT_ROOT, net, filename) >= MAXPATHLEN)
715*12899Sdminer@opensolaris.org 		return (WBCGI_FTW_CBERR);
7160Sstevel@tonic-gate 
717*12899Sdminer@opensolaris.org 	if (cid != NULL) {
718*12899Sdminer@opensolaris.org 		if (snprintf(ckpath[i++], MAXPATHLEN, "%s%s/%s",
719*12899Sdminer@opensolaris.org 		    NB_NETBOOT_ROOT, cid, filename) >= MAXPATHLEN)
7200Sstevel@tonic-gate 			return (WBCGI_FTW_CBERR);
721*12899Sdminer@opensolaris.org 
722*12899Sdminer@opensolaris.org 		if (net != NULL && snprintf(ckpath[i++], MAXPATHLEN,
723*12899Sdminer@opensolaris.org 		    "%s%s/%s/%s", NB_NETBOOT_ROOT, net, cid, filename) >=
724*12899Sdminer@opensolaris.org 		    MAXPATHLEN)
7250Sstevel@tonic-gate 			return (WBCGI_FTW_CBERR);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	/*
7290Sstevel@tonic-gate 	 * Loop through hierarchy and check for file existence.
7300Sstevel@tonic-gate 	 */
731*12899Sdminer@opensolaris.org 	while (i > 0) {
732*12899Sdminer@opensolaris.org 		--i;
733*12899Sdminer@opensolaris.org 		if (WBCGI_FILE_EXISTS(ckpath[i], buf)) {
734*12899Sdminer@opensolaris.org 			if ((ret = cb(ckpath[i], arg)) != WBCGI_FTW_CBCONT)
7350Sstevel@tonic-gate 				return (ret);
7360Sstevel@tonic-gate 		}
7370Sstevel@tonic-gate 	}
738*12899Sdminer@opensolaris.org 	return (WBCGI_FTW_DONE);
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate /*ARGSUSED*/
7420Sstevel@tonic-gate static int
noact_cb(const char * path,void * arg)7430Sstevel@tonic-gate noact_cb(const char *path, void *arg)
7440Sstevel@tonic-gate {
7450Sstevel@tonic-gate 	return (WBCGI_FTW_CBOK);
7460Sstevel@tonic-gate }
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate static int
set_pathname(const char * path,void * pathname)7490Sstevel@tonic-gate set_pathname(const char *path, void *pathname)
7500Sstevel@tonic-gate {
7510Sstevel@tonic-gate 	*(char **)pathname = strdup((char *)path);
7520Sstevel@tonic-gate 	return (WBCGI_FTW_CBOK);
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate static int
create_keystore(const char * path,void * keystorepath)7560Sstevel@tonic-gate create_keystore(const char *path, void *keystorepath)
7570Sstevel@tonic-gate {
7580Sstevel@tonic-gate 	if (!extract_keystore(path, (char *)keystorepath)) {
7590Sstevel@tonic-gate 		return (WBCGI_FTW_CBERR);
7600Sstevel@tonic-gate 	}
7610Sstevel@tonic-gate 	return (WBCGI_FTW_CBOK);
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate static int
copy_certstore(const char * path,void * certstorepath)7650Sstevel@tonic-gate copy_certstore(const char *path, void *certstorepath)
7660Sstevel@tonic-gate {
7670Sstevel@tonic-gate 	if (!copy_file(path, (char *)certstorepath)) {
7680Sstevel@tonic-gate 		return (WBCGI_FTW_CBERR);
7690Sstevel@tonic-gate 	}
7700Sstevel@tonic-gate 	return (WBCGI_FTW_CBOK);
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate /*
7740Sstevel@tonic-gate  * Add the certs found in the trustfile found in path (a trust store) to
7750Sstevel@tonic-gate  * the file found at bootfs_dir/truststore.  If necessary, create the
7760Sstevel@tonic-gate  * output file.
7770Sstevel@tonic-gate  */
7780Sstevel@tonic-gate static int
build_trustfile(const char * path,void * truststorepath)7790Sstevel@tonic-gate build_trustfile(const char *path, void *truststorepath)
7800Sstevel@tonic-gate {
7810Sstevel@tonic-gate 	int		ret = WBCGI_FTW_CBERR;
7820Sstevel@tonic-gate 	STACK_OF(X509)	*i_anchors = NULL;
7830Sstevel@tonic-gate 	STACK_OF(X509)	*o_anchors = NULL;
7840Sstevel@tonic-gate 	char		message[WBCGI_MAXBUF];
7850Sstevel@tonic-gate 	PKCS12		*p12 = NULL;
7860Sstevel@tonic-gate 	FILE		*rfp = NULL;
7870Sstevel@tonic-gate 	FILE		*wfp = NULL;
7880Sstevel@tonic-gate 	struct stat	i_st;
7890Sstevel@tonic-gate 	struct stat	o_st;
7900Sstevel@tonic-gate 	X509		*x = NULL;
7910Sstevel@tonic-gate 	int		errtype = 0;
7920Sstevel@tonic-gate 	int		wfd = -1;
7930Sstevel@tonic-gate 	int		chars;
7940Sstevel@tonic-gate 	int		i;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(path, i_st)) {
7970Sstevel@tonic-gate 		goto cleanup;
7980Sstevel@tonic-gate 	}
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	if (WBCGI_FILE_EXISTS((char *)truststorepath, o_st)) {
8010Sstevel@tonic-gate 		/*
8020Sstevel@tonic-gate 		 * If we are inadvertantly writing to the input file.
8030Sstevel@tonic-gate 		 * return success.
8040Sstevel@tonic-gate 		 * XXX Pete: how can this happen, and why success?
8050Sstevel@tonic-gate 		 */
8060Sstevel@tonic-gate 		if (i_st.st_ino == o_st.st_ino) {
8070Sstevel@tonic-gate 			ret = WBCGI_FTW_CBCONT;
8080Sstevel@tonic-gate 			goto cleanup;
8090Sstevel@tonic-gate 		}
8100Sstevel@tonic-gate 		if ((wfp = fopen((char *)truststorepath, "r+")) == NULL) {
8110Sstevel@tonic-gate 			goto cleanup;
8120Sstevel@tonic-gate 		}
8130Sstevel@tonic-gate 		/*
8140Sstevel@tonic-gate 		 * Read what's already there, so that new information
8150Sstevel@tonic-gate 		 * can be added.
8160Sstevel@tonic-gate 		 */
8170Sstevel@tonic-gate 		if ((p12 = d2i_PKCS12_fp(wfp, NULL)) == NULL) {
8180Sstevel@tonic-gate 			errtype = 1;
8190Sstevel@tonic-gate 			goto cleanup;
8200Sstevel@tonic-gate 		}
8210Sstevel@tonic-gate 		i = sunw_PKCS12_parse(p12, WANBOOT_PASSPHRASE, DO_NONE, NULL,
8220Sstevel@tonic-gate 		    0, NULL, NULL, NULL, &o_anchors);
8230Sstevel@tonic-gate 		if (i <= 0) {
8240Sstevel@tonic-gate 			errtype = 1;
8250Sstevel@tonic-gate 			goto cleanup;
8260Sstevel@tonic-gate 		}
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 		PKCS12_free(p12);
8290Sstevel@tonic-gate 		p12 = NULL;
8300Sstevel@tonic-gate 	} else {
8310Sstevel@tonic-gate 		if (errno != ENOENT) {
8320Sstevel@tonic-gate 			chars = snprintf(message, sizeof (message),
8330Sstevel@tonic-gate 			    "(error accessing file %s, error %s)",
8340Sstevel@tonic-gate 			    path, strerror(errno));
8350Sstevel@tonic-gate 			if (chars > 0 && chars < sizeof (message))
8360Sstevel@tonic-gate 				print_status(500, message);
8370Sstevel@tonic-gate 			else
8380Sstevel@tonic-gate 				print_status(500, NULL);
8390Sstevel@tonic-gate 			return (WBCGI_FTW_CBERR);
8400Sstevel@tonic-gate 		}
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 		/*
8430Sstevel@tonic-gate 		 * Note: We could copy the file to the new trustfile, but
8440Sstevel@tonic-gate 		 * we can't verify the password that way.  Therefore, copy
8450Sstevel@tonic-gate 		 * it by reading it.
8460Sstevel@tonic-gate 		 */
8470Sstevel@tonic-gate 		if ((wfd = open((char *)truststorepath,
8480Sstevel@tonic-gate 		    O_CREAT|O_EXCL|O_RDWR, 0700)) < 0) {
8490Sstevel@tonic-gate 			goto cleanup;
8500Sstevel@tonic-gate 		}
8510Sstevel@tonic-gate 		if ((wfp = fdopen(wfd, "w+")) == NULL) {
8520Sstevel@tonic-gate 			goto cleanup;
8530Sstevel@tonic-gate 		}
8540Sstevel@tonic-gate 		o_anchors = sk_X509_new_null();
8550Sstevel@tonic-gate 		if (o_anchors == NULL) {
8560Sstevel@tonic-gate 			goto cleanup;
8570Sstevel@tonic-gate 		}
8580Sstevel@tonic-gate 	}
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	if ((rfp = fopen(path, "r")) == NULL) {
8610Sstevel@tonic-gate 		goto cleanup;
8620Sstevel@tonic-gate 	}
8630Sstevel@tonic-gate 	if ((p12 = d2i_PKCS12_fp(rfp, NULL)) == NULL) {
8640Sstevel@tonic-gate 		errtype = 1;
8650Sstevel@tonic-gate 		goto cleanup;
8660Sstevel@tonic-gate 	}
8670Sstevel@tonic-gate 	i = sunw_PKCS12_parse(p12, WANBOOT_PASSPHRASE, DO_NONE, NULL, 0, NULL,
8680Sstevel@tonic-gate 	    NULL, NULL, &i_anchors);
8690Sstevel@tonic-gate 	if (i <= 0) {
8700Sstevel@tonic-gate 		errtype = 1;
8710Sstevel@tonic-gate 		goto cleanup;
8720Sstevel@tonic-gate 	}
8730Sstevel@tonic-gate 	PKCS12_free(p12);
8740Sstevel@tonic-gate 	p12 = NULL;
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	/*
8770Sstevel@tonic-gate 	 * Merge the two stacks of pkcs12 certs.
8780Sstevel@tonic-gate 	 */
8790Sstevel@tonic-gate 	for (i = 0; i < sk_X509_num(i_anchors); i++) {
8800Sstevel@tonic-gate 		/* LINTED */
8810Sstevel@tonic-gate 		x = sk_X509_delete(i_anchors, i);
8820Sstevel@tonic-gate 		(void) sk_X509_push(o_anchors, x);
8830Sstevel@tonic-gate 	}
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	/*
8860Sstevel@tonic-gate 	 * Create the pkcs12 structure from the modified input stack and
8870Sstevel@tonic-gate 	 * then write out that structure.
8880Sstevel@tonic-gate 	 */
8890Sstevel@tonic-gate 	p12 = sunw_PKCS12_create((const char *)WANBOOT_PASSPHRASE, NULL, NULL,
8900Sstevel@tonic-gate 	    o_anchors);
8910Sstevel@tonic-gate 	if (p12 == NULL) {
8920Sstevel@tonic-gate 		goto cleanup;
8930Sstevel@tonic-gate 	}
8940Sstevel@tonic-gate 	rewind(wfp);
8950Sstevel@tonic-gate 	if (i2d_PKCS12_fp(wfp, p12) == 0) {
8960Sstevel@tonic-gate 		goto cleanup;
8970Sstevel@tonic-gate 	}
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	ret = WBCGI_FTW_CBCONT;
9000Sstevel@tonic-gate cleanup:
9010Sstevel@tonic-gate 	if (ret == WBCGI_FTW_CBERR) {
9020Sstevel@tonic-gate 		if (errtype == 1) {
9030Sstevel@tonic-gate 			chars = snprintf(message, sizeof (message),
9040Sstevel@tonic-gate 			    "(internal PKCS12 error while copying %s to %s)",
9050Sstevel@tonic-gate 			    path, (char *)truststorepath);
9060Sstevel@tonic-gate 		} else {
9070Sstevel@tonic-gate 			chars = snprintf(message, sizeof (message),
9080Sstevel@tonic-gate 			    "(error copying %s to %s)",
9090Sstevel@tonic-gate 			    path, (char *)truststorepath);
9100Sstevel@tonic-gate 		}
9110Sstevel@tonic-gate 		if (chars > 0 && chars <= sizeof (message)) {
9120Sstevel@tonic-gate 			print_status(500, message);
9130Sstevel@tonic-gate 		} else {
9140Sstevel@tonic-gate 			print_status(500, NULL);
9150Sstevel@tonic-gate 		}
9160Sstevel@tonic-gate 	}
9170Sstevel@tonic-gate 	if (rfp != NULL) {
9180Sstevel@tonic-gate 		(void) fclose(rfp);
9190Sstevel@tonic-gate 	}
9200Sstevel@tonic-gate 	if (wfp != NULL) {
9210Sstevel@tonic-gate 		/* Will also close wfd */
9220Sstevel@tonic-gate 		(void) fclose(wfp);
9230Sstevel@tonic-gate 	}
9240Sstevel@tonic-gate 	if (p12 != NULL) {
9250Sstevel@tonic-gate 		PKCS12_free(p12);
9260Sstevel@tonic-gate 	}
9270Sstevel@tonic-gate 	if (i_anchors != NULL) {
9280Sstevel@tonic-gate 		sk_X509_pop_free(i_anchors, X509_free);
9290Sstevel@tonic-gate 	}
9300Sstevel@tonic-gate 	if (o_anchors != NULL) {
9310Sstevel@tonic-gate 		sk_X509_pop_free(o_anchors, X509_free);
9320Sstevel@tonic-gate 	}
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	return (ret);
9350Sstevel@tonic-gate }
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate static boolean_t
check_key_type(const char * keyfile,const char * keytype,int flag)9380Sstevel@tonic-gate check_key_type(const char *keyfile, const char *keytype, int flag)
9390Sstevel@tonic-gate {
9400Sstevel@tonic-gate 	boolean_t	ret = B_FALSE;
9410Sstevel@tonic-gate 	FILE		*key_fp = NULL;
9420Sstevel@tonic-gate 	wbku_key_attr_t	ka;
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 	/*
9450Sstevel@tonic-gate 	 * Map keytype into the ka structure
9460Sstevel@tonic-gate 	 */
9470Sstevel@tonic-gate 	if (wbku_str_to_keyattr(keytype, &ka, flag) != WBKU_SUCCESS) {
9480Sstevel@tonic-gate 		goto cleanup;
9490Sstevel@tonic-gate 	}
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	/*
9520Sstevel@tonic-gate 	 * Open the key file for reading.
9530Sstevel@tonic-gate 	 */
9540Sstevel@tonic-gate 	if ((key_fp = fopen(keyfile, "r")) == NULL) {
9550Sstevel@tonic-gate 		goto cleanup;
9560Sstevel@tonic-gate 	}
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	/*
9590Sstevel@tonic-gate 	 * Find the valid client key, if it exists.
9600Sstevel@tonic-gate 	 */
9610Sstevel@tonic-gate 	if (wbku_find_key(key_fp, NULL, &ka, NULL, B_FALSE) != WBKU_SUCCESS) {
9620Sstevel@tonic-gate 		goto cleanup;
9630Sstevel@tonic-gate 	}
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	ret = B_TRUE;
9660Sstevel@tonic-gate cleanup:
9670Sstevel@tonic-gate 	if (key_fp != NULL) {
9680Sstevel@tonic-gate 		(void) fclose(key_fp);
9690Sstevel@tonic-gate 	}
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	return (ret);
9720Sstevel@tonic-gate }
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate static boolean_t
resolve_hostname(const char * hostname,nvlist_t * nvl,boolean_t may_be_crap)9750Sstevel@tonic-gate resolve_hostname(const char *hostname, nvlist_t *nvl, boolean_t may_be_crap)
9760Sstevel@tonic-gate {
9770Sstevel@tonic-gate 	struct sockaddr_in	sin;
9780Sstevel@tonic-gate 	struct hostent		*hp;
979*12899Sdminer@opensolaris.org 	struct utsname		un;
980*12899Sdminer@opensolaris.org 	static char 		myname[SYS_NMLN] = { '\0' };
981*12899Sdminer@opensolaris.org 	char			*cp = NULL;
982*12899Sdminer@opensolaris.org 	char			msg[WBCGI_MAXBUF];
9830Sstevel@tonic-gate 
984*12899Sdminer@opensolaris.org 	/*
985*12899Sdminer@opensolaris.org 	 *  Initialize cached nodename
986*12899Sdminer@opensolaris.org 	 */
987*12899Sdminer@opensolaris.org 	if (strlen(myname) == 0) {
988*12899Sdminer@opensolaris.org 		if (uname(&un) == -1) {
989*12899Sdminer@opensolaris.org 			(void) snprintf(msg, sizeof (msg),
990*12899Sdminer@opensolaris.org 			    "(unable to retrieve uname, errno %d)", errno);
991*12899Sdminer@opensolaris.org 			print_status(500, msg);
992*12899Sdminer@opensolaris.org 			return (B_FALSE);
9930Sstevel@tonic-gate 		}
994*12899Sdminer@opensolaris.org 		(void) strcpy(myname, un.nodename);
9950Sstevel@tonic-gate 	}
9960Sstevel@tonic-gate 
997*12899Sdminer@opensolaris.org 	/*
998*12899Sdminer@opensolaris.org 	 * If hostname is local node name, return the address this
999*12899Sdminer@opensolaris.org 	 * request came in on, which is supplied as SERVER_ADDR in the
1000*12899Sdminer@opensolaris.org 	 * cgi environment.  This ensures we don't send back a possible
1001*12899Sdminer@opensolaris.org 	 * alternate address that may be unreachable from the client's
1002*12899Sdminer@opensolaris.org 	 * network.  Otherwise, just resolve with nameservice.
1003*12899Sdminer@opensolaris.org 	 */
1004*12899Sdminer@opensolaris.org 	if ((strcmp(hostname, myname) != 0) ||
1005*12899Sdminer@opensolaris.org 	    ((cp = getenv("SERVER_ADDR")) == NULL)) {
1006*12899Sdminer@opensolaris.org 		if (((hp = gethostbyname(hostname)) == NULL) ||
1007*12899Sdminer@opensolaris.org 		    (hp->h_addrtype != AF_INET) ||
1008*12899Sdminer@opensolaris.org 		    (hp->h_length != sizeof (struct in_addr))) {
1009*12899Sdminer@opensolaris.org 			if (!may_be_crap) {
1010*12899Sdminer@opensolaris.org 				print_status(500, "(error resolving hostname)");
1011*12899Sdminer@opensolaris.org 			}
1012*12899Sdminer@opensolaris.org 			return (may_be_crap);
1013*12899Sdminer@opensolaris.org 		}
1014*12899Sdminer@opensolaris.org 		(void) memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
1015*12899Sdminer@opensolaris.org 		cp = inet_ntoa(sin.sin_addr);
1016*12899Sdminer@opensolaris.org 	}
1017*12899Sdminer@opensolaris.org 
1018*12899Sdminer@opensolaris.org 	if (nvlist_add_string(nvl, (char *)hostname, cp) != 0) {
10190Sstevel@tonic-gate 		print_status(500, "(error adding hostname to nvlist)");
10200Sstevel@tonic-gate 		return (B_FALSE);
10210Sstevel@tonic-gate 	}
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	return (B_TRUE);
10240Sstevel@tonic-gate }
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate /*
10270Sstevel@tonic-gate  * one_name() is called for each certificate found and is passed the string
10280Sstevel@tonic-gate  * that X509_NAME_oneline() returns.  Its job is to find the common name and
10290Sstevel@tonic-gate  * determine whether it is a host name; if it is then a line suitable for
10300Sstevel@tonic-gate  * inclusion in /etc/inet/hosts is written to that file.
10310Sstevel@tonic-gate  */
10320Sstevel@tonic-gate static boolean_t
one_name(const char * namestr,nvlist_t * nvl)10330Sstevel@tonic-gate one_name(const char *namestr, nvlist_t *nvl)
10340Sstevel@tonic-gate {
10350Sstevel@tonic-gate 	boolean_t	ret = B_TRUE;
10360Sstevel@tonic-gate 	char		*p;
10370Sstevel@tonic-gate 	char		*q;
10380Sstevel@tonic-gate 	char		c;
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	if (namestr != NULL &&
10410Sstevel@tonic-gate 	    (p = strstr(namestr, WBCGI_CNSTR)) != NULL) {
10420Sstevel@tonic-gate 		p += WBCGI_CNSTR_LEN;
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 		if ((q = strpbrk(p, WBCGI_NAMESEP)) != NULL) {
10450Sstevel@tonic-gate 			c = *q;
10460Sstevel@tonic-gate 			*q = '\0';
10470Sstevel@tonic-gate 			ret = resolve_hostname(p, nvl, B_TRUE);
10480Sstevel@tonic-gate 			*q = c;
10490Sstevel@tonic-gate 		} else {
10500Sstevel@tonic-gate 			ret = resolve_hostname(p, nvl, B_TRUE);
10510Sstevel@tonic-gate 		}
10520Sstevel@tonic-gate 	}
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	return (ret);
10550Sstevel@tonic-gate }
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate /*
10580Sstevel@tonic-gate  * Loop through the certificates in a file
10590Sstevel@tonic-gate  */
10600Sstevel@tonic-gate static int
get_hostnames(const char * path,void * nvl)10610Sstevel@tonic-gate get_hostnames(const char *path, void *nvl)
10620Sstevel@tonic-gate {
10630Sstevel@tonic-gate 	int		ret = WBCGI_FTW_CBERR;
10640Sstevel@tonic-gate 	STACK_OF(X509)	*certs = NULL;
10650Sstevel@tonic-gate 	PKCS12		*p12 = NULL;
10660Sstevel@tonic-gate 	char		message[WBCGI_MAXBUF];
10670Sstevel@tonic-gate 	char		buf[WBCGI_MAXBUF + 1];
10680Sstevel@tonic-gate 	FILE		*rfp = NULL;
10690Sstevel@tonic-gate 	X509		*x = NULL;
10700Sstevel@tonic-gate 	int		errtype = 0;
10710Sstevel@tonic-gate 	int		chars;
10720Sstevel@tonic-gate 	int		i;
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	if ((rfp = fopen(path, "r")) == NULL) {
10750Sstevel@tonic-gate 		goto cleanup;
10760Sstevel@tonic-gate 	}
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 	if ((p12 = d2i_PKCS12_fp(rfp, NULL)) == NULL) {
10790Sstevel@tonic-gate 		errtype = 1;
10800Sstevel@tonic-gate 		goto cleanup;
10810Sstevel@tonic-gate 	}
10820Sstevel@tonic-gate 	i = sunw_PKCS12_parse(p12, WANBOOT_PASSPHRASE, DO_NONE, NULL, 0, NULL,
10830Sstevel@tonic-gate 	    NULL, NULL, &certs);
10840Sstevel@tonic-gate 	if (i <= 0) {
10850Sstevel@tonic-gate 		errtype = 1;
10860Sstevel@tonic-gate 		goto cleanup;
10870Sstevel@tonic-gate 	}
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 	PKCS12_free(p12);
10900Sstevel@tonic-gate 	p12 = NULL;
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	for (i = 0; i < sk_X509_num(certs); i++) {
10930Sstevel@tonic-gate 		/* LINTED */
10940Sstevel@tonic-gate 		x = sk_X509_value(certs, i);
10950Sstevel@tonic-gate 		if (!one_name(sunw_issuer_attrs(x, buf, sizeof (buf) - 1),
10960Sstevel@tonic-gate 		    nvl)) {
10970Sstevel@tonic-gate 			goto cleanup;
10980Sstevel@tonic-gate 		}
10990Sstevel@tonic-gate 	}
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	ret = WBCGI_FTW_CBCONT;
11020Sstevel@tonic-gate cleanup:
11030Sstevel@tonic-gate 	if (ret == WBCGI_FTW_CBERR) {
11040Sstevel@tonic-gate 		if (errtype == 1) {
11050Sstevel@tonic-gate 			chars = snprintf(message, sizeof (message),
11060Sstevel@tonic-gate 			    "(internal PKCS12 error reading %s)", path);
11070Sstevel@tonic-gate 		} else {
11080Sstevel@tonic-gate 			chars = snprintf(message, sizeof (message),
11090Sstevel@tonic-gate 			    "error reading %s", path);
11100Sstevel@tonic-gate 		}
11110Sstevel@tonic-gate 		if (chars > 0 && chars <= sizeof (message)) {
11120Sstevel@tonic-gate 			print_status(500, message);
11130Sstevel@tonic-gate 		} else {
11140Sstevel@tonic-gate 			print_status(500, NULL);
11150Sstevel@tonic-gate 		}
11160Sstevel@tonic-gate 	}
11170Sstevel@tonic-gate 	if (rfp != NULL) {
11180Sstevel@tonic-gate 		(void) fclose(rfp);
11190Sstevel@tonic-gate 	}
11200Sstevel@tonic-gate 	if (p12 != NULL) {
11210Sstevel@tonic-gate 		PKCS12_free(p12);
11220Sstevel@tonic-gate 	}
11230Sstevel@tonic-gate 	if (certs != NULL) {
11240Sstevel@tonic-gate 		sk_X509_pop_free(certs, X509_free);
11250Sstevel@tonic-gate 	}
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 	return (ret);
11280Sstevel@tonic-gate }
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate /*
11310Sstevel@tonic-gate  * Create a hosts file by extracting hosts from client and truststore
11320Sstevel@tonic-gate  * files.  Use the CN. Then we should copy that file to the inet dir.
11330Sstevel@tonic-gate  */
11340Sstevel@tonic-gate static boolean_t
create_hostsfile(const char * hostsfile,const char * net,const char * cid)11350Sstevel@tonic-gate create_hostsfile(const char *hostsfile, const char *net, const char *cid)
11360Sstevel@tonic-gate {
11370Sstevel@tonic-gate 	boolean_t	ret = B_FALSE;
11380Sstevel@tonic-gate 	nvlist_t	*nvl;
11390Sstevel@tonic-gate 	nvpair_t	*nvp;
11400Sstevel@tonic-gate 	FILE		*hostfp = NULL;
11410Sstevel@tonic-gate 	int		hostfd = -1;
11420Sstevel@tonic-gate 	int		i;
11430Sstevel@tonic-gate 	char		*hostslist;
11440Sstevel@tonic-gate 	const char	*bc_urls[] = { BC_ROOT_SERVER, BC_BOOT_LOGGER, NULL };
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	/*
11470Sstevel@tonic-gate 	 * Allocate nvlist handle to store our hostname/IP pairs.
11480Sstevel@tonic-gate 	 */
11490Sstevel@tonic-gate 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
11500Sstevel@tonic-gate 		print_status(500, "(error allocating hostname nvlist)");
11510Sstevel@tonic-gate 		goto cleanup;
11520Sstevel@tonic-gate 	}
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate 	/*
11550Sstevel@tonic-gate 	 * Extract and resolve hostnames from CNs.
11560Sstevel@tonic-gate 	 */
11570Sstevel@tonic-gate 	if (netboot_ftw(NB_CLIENT_CERT, net, cid,
11580Sstevel@tonic-gate 	    get_hostnames, nvl) == WBCGI_FTW_CBERR ||
11590Sstevel@tonic-gate 	    netboot_ftw(NB_CA_CERT, net, cid,
11600Sstevel@tonic-gate 	    get_hostnames, nvl) == WBCGI_FTW_CBERR) {
11610Sstevel@tonic-gate 		goto cleanup;
11620Sstevel@tonic-gate 	}
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 	/*
11650Sstevel@tonic-gate 	 * Extract and resolve hostnames from any URLs in bootconf.
11660Sstevel@tonic-gate 	 */
11670Sstevel@tonic-gate 	for (i = 0; bc_urls[i] != NULL; ++i) {
11680Sstevel@tonic-gate 		char	*urlstr;
11690Sstevel@tonic-gate 		url_t	url;
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 		if ((urlstr = bootconf_get(&bc_handle, bc_urls[i])) != NULL &&
11720Sstevel@tonic-gate 		    url_parse(urlstr, &url) == URL_PARSE_SUCCESS) {
11730Sstevel@tonic-gate 			if (!resolve_hostname(url.hport.hostname,
11740Sstevel@tonic-gate 			    nvl, B_FALSE)) {
11750Sstevel@tonic-gate 				goto cleanup;
11760Sstevel@tonic-gate 			}
11770Sstevel@tonic-gate 		}
11780Sstevel@tonic-gate 	}
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 	/*
11810Sstevel@tonic-gate 	 * If there is a resolve-hosts list in bootconf, resolve those
11820Sstevel@tonic-gate 	 * hostnames too.
11830Sstevel@tonic-gate 	 */
11840Sstevel@tonic-gate 	if ((hostslist = bootconf_get(&bc_handle, BC_RESOLVE_HOSTS)) != NULL) {
11850Sstevel@tonic-gate 		char	*hostname;
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 		for (hostname = strtok(hostslist, ","); hostname != NULL;
11880Sstevel@tonic-gate 		    hostname = strtok(NULL, ",")) {
11890Sstevel@tonic-gate 			if (!resolve_hostname(hostname, nvl, B_FALSE)) {
11900Sstevel@tonic-gate 				goto cleanup;
11910Sstevel@tonic-gate 			}
11920Sstevel@tonic-gate 		}
11930Sstevel@tonic-gate 	}
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 	/*
11960Sstevel@tonic-gate 	 * Now write the hostname/IP pairs gathered to the hosts file.
11970Sstevel@tonic-gate 	 */
11980Sstevel@tonic-gate 	if ((hostfd = open(hostsfile,
11990Sstevel@tonic-gate 	    O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
12000Sstevel@tonic-gate 	    (hostfp = fdopen(hostfd, "w+")) == NULL) {
12010Sstevel@tonic-gate 		print_status(500, "(error creating hosts file)");
12020Sstevel@tonic-gate 		goto cleanup;
12030Sstevel@tonic-gate 	}
12040Sstevel@tonic-gate 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
12050Sstevel@tonic-gate 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
12060Sstevel@tonic-gate 		char	*hostname;
12070Sstevel@tonic-gate 		char	*ipstr;
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 		hostname = nvpair_name(nvp);
12100Sstevel@tonic-gate 		if (nvpair_value_string(nvp, &ipstr) != 0) {
12110Sstevel@tonic-gate 			print_status(500, "(nvl error writing hosts file)");
12120Sstevel@tonic-gate 			goto cleanup;
12130Sstevel@tonic-gate 		}
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 		if (fprintf(hostfp, "%s\t%s\n", ipstr, hostname) < 0) {
12160Sstevel@tonic-gate 			print_status(500, "(error writing hosts file)");
12170Sstevel@tonic-gate 			goto cleanup;
12180Sstevel@tonic-gate 		}
12190Sstevel@tonic-gate 	}
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 	ret = B_TRUE;
12220Sstevel@tonic-gate cleanup:
12230Sstevel@tonic-gate 	if (nvl != NULL) {
12240Sstevel@tonic-gate 		nvlist_free(nvl);
12250Sstevel@tonic-gate 	}
12260Sstevel@tonic-gate 	if (hostfp != NULL) {
12270Sstevel@tonic-gate 		/*
12280Sstevel@tonic-gate 		 * hostfd is automatically closed as well.
12290Sstevel@tonic-gate 		 */
12300Sstevel@tonic-gate 		(void) fclose(hostfp);
12310Sstevel@tonic-gate 	}
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 	return (ret);
12340Sstevel@tonic-gate }
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate static boolean_t
bootfile_payload(const char * docroot,char ** bootpathp)12370Sstevel@tonic-gate bootfile_payload(const char *docroot, char **bootpathp)
12380Sstevel@tonic-gate {
12390Sstevel@tonic-gate 	boolean_t	ret = B_FALSE;
12400Sstevel@tonic-gate 	char		*boot_file;
12410Sstevel@tonic-gate 	struct stat	sbuf;
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 	if ((boot_file = bootconf_get(&bc_handle, BC_BOOT_FILE)) == NULL) {
12440Sstevel@tonic-gate 		print_status(500, "(boot_file must be specified)");
12450Sstevel@tonic-gate 		goto cleanup;
12460Sstevel@tonic-gate 	}
12470Sstevel@tonic-gate 	if ((*bootpathp = make_path(docroot, boot_file)) == NULL) {
12480Sstevel@tonic-gate 		goto cleanup;
12490Sstevel@tonic-gate 	}
12500Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(*bootpathp, sbuf)) {
12510Sstevel@tonic-gate 		print_status(500, "(boot_file missing)");
12520Sstevel@tonic-gate 		goto cleanup;
12530Sstevel@tonic-gate 	}
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 	ret = B_TRUE;
12560Sstevel@tonic-gate cleanup:
12570Sstevel@tonic-gate 	return (ret);
12580Sstevel@tonic-gate }
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate /*
12610Sstevel@tonic-gate  * Create the wanboot file system whose contents are determined by the
12620Sstevel@tonic-gate  * security configuration specified in bootconf.
12630Sstevel@tonic-gate  */
12640Sstevel@tonic-gate static boolean_t
wanbootfs_payload(const char * net,const char * cid,const char * nonce,const char * bootconf,char ** wanbootfs_imagep)12650Sstevel@tonic-gate wanbootfs_payload(const char *net, const char *cid, const char *nonce,
12660Sstevel@tonic-gate     const char *bootconf, char **wanbootfs_imagep)
12670Sstevel@tonic-gate {
12680Sstevel@tonic-gate 	int		ret = B_FALSE;
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	char		*server_authentication;
12710Sstevel@tonic-gate 	char		*client_authentication;
12720Sstevel@tonic-gate 	char		*scf;
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 	char		*bootfs_dir = NULL;
12750Sstevel@tonic-gate 	char		*bootfs_etc_dir = NULL;
12760Sstevel@tonic-gate 	char		*bootfs_etc_inet_dir = NULL;
12770Sstevel@tonic-gate 	char		*bootfs_dev_dir = NULL;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 	char		*systemconf = NULL;
12800Sstevel@tonic-gate 	char		*keystorepath = NULL;
12810Sstevel@tonic-gate 	char		*certstorepath = NULL;
12820Sstevel@tonic-gate 	char		*truststorepath = NULL;
12830Sstevel@tonic-gate 	char		*bootconfpath = NULL;
12840Sstevel@tonic-gate 	char		*systemconfpath = NULL;
12850Sstevel@tonic-gate 	char		*urandompath = NULL;
12860Sstevel@tonic-gate 	char		*noncepath = NULL;
12870Sstevel@tonic-gate 	char		*hostspath = NULL;
12880Sstevel@tonic-gate 	char		*etc_hostspath = NULL;
12890Sstevel@tonic-gate 	char		*timestamppath = NULL;
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 	boolean_t	authenticate_client;
12920Sstevel@tonic-gate 	boolean_t	authenticate_server;
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 	struct stat	sbuf;
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 	/*
12970Sstevel@tonic-gate 	 * Initialize SSL stuff.
12980Sstevel@tonic-gate 	 */
12990Sstevel@tonic-gate 	sunw_crypto_init();
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	/*
13020Sstevel@tonic-gate 	 * Get the security strategy values.
13030Sstevel@tonic-gate 	 */
13040Sstevel@tonic-gate 	client_authentication = bootconf_get(&bc_handle,
13050Sstevel@tonic-gate 	    BC_CLIENT_AUTHENTICATION);
13060Sstevel@tonic-gate 	authenticate_client = (client_authentication != NULL &&
13070Sstevel@tonic-gate 	    strcmp(client_authentication, "yes") == 0);
13080Sstevel@tonic-gate 	server_authentication = bootconf_get(&bc_handle,
13090Sstevel@tonic-gate 	    BC_SERVER_AUTHENTICATION);
13100Sstevel@tonic-gate 	authenticate_server = (server_authentication != NULL &&
13110Sstevel@tonic-gate 	    strcmp(server_authentication, "yes") == 0);
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 	/*
13140Sstevel@tonic-gate 	 * Make a temporary directory structure for the wanboot file system.
13150Sstevel@tonic-gate 	 */
13160Sstevel@tonic-gate 	if ((bootfs_dir = gen_tmppath("bootfs_dir", net, cid)) == NULL ||
13170Sstevel@tonic-gate 	    (bootfs_etc_dir = make_path(bootfs_dir, "etc")) == NULL ||
13180Sstevel@tonic-gate 	    (bootfs_etc_inet_dir = make_path(bootfs_etc_dir, "inet")) == NULL ||
13190Sstevel@tonic-gate 	    (bootfs_dev_dir = make_path(bootfs_dir, "dev")) == NULL) {
13200Sstevel@tonic-gate 		goto cleanup;
13210Sstevel@tonic-gate 	}
13220Sstevel@tonic-gate 	if (mkdirp(bootfs_dir, 0700) ||
13230Sstevel@tonic-gate 	    mkdirp(bootfs_etc_dir, 0700) ||
13240Sstevel@tonic-gate 	    mkdirp(bootfs_etc_inet_dir, 0700) ||
13250Sstevel@tonic-gate 	    mkdirp(bootfs_dev_dir, 0700)) {
13260Sstevel@tonic-gate 		print_status(500, "(error creating wanbootfs dir structure)");
13270Sstevel@tonic-gate 		goto cleanup;
13280Sstevel@tonic-gate 	}
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	if (authenticate_client) {
13310Sstevel@tonic-gate 		/*
13320Sstevel@tonic-gate 		 * Add the client private key.
13330Sstevel@tonic-gate 		 */
13340Sstevel@tonic-gate 		if ((keystorepath = make_path(bootfs_dir,
13350Sstevel@tonic-gate 		    NB_CLIENT_KEY)) == NULL ||
13360Sstevel@tonic-gate 		    netboot_ftw(NB_CLIENT_KEY, net, cid,
13370Sstevel@tonic-gate 		    create_keystore, keystorepath) != WBCGI_FTW_CBOK) {
13380Sstevel@tonic-gate 			goto cleanup;
13390Sstevel@tonic-gate 		}
13400Sstevel@tonic-gate 
13410Sstevel@tonic-gate 		/*
13420Sstevel@tonic-gate 		 * Add the client certificate.
13430Sstevel@tonic-gate 		 */
13440Sstevel@tonic-gate 		if ((certstorepath = make_path(bootfs_dir,
13450Sstevel@tonic-gate 		    NB_CLIENT_CERT)) == NULL ||
13460Sstevel@tonic-gate 		    netboot_ftw(NB_CLIENT_CERT, net, cid,
13470Sstevel@tonic-gate 		    copy_certstore, certstorepath) != WBCGI_FTW_CBOK) {
13480Sstevel@tonic-gate 			goto cleanup;
13490Sstevel@tonic-gate 		}
13500Sstevel@tonic-gate 	}
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate 	if (authenticate_client || authenticate_server) {
13530Sstevel@tonic-gate 		/*
13540Sstevel@tonic-gate 		 * Add the trustfile; at least one truststore must exist.
13550Sstevel@tonic-gate 		 */
13560Sstevel@tonic-gate 		if ((truststorepath = make_path(bootfs_dir,
13570Sstevel@tonic-gate 		    NB_CA_CERT)) == NULL) {
13580Sstevel@tonic-gate 			goto cleanup;
13590Sstevel@tonic-gate 		}
13600Sstevel@tonic-gate 		if (netboot_ftw(NB_CA_CERT, net, cid,
13610Sstevel@tonic-gate 		    noact_cb, NULL) != WBCGI_FTW_CBOK) {
13620Sstevel@tonic-gate 			print_status(500, "(truststore not found)");
13630Sstevel@tonic-gate 		}
13640Sstevel@tonic-gate 		if (netboot_ftw(NB_CA_CERT, net, cid,
1365*12899Sdminer@opensolaris.org 		    build_trustfile, truststorepath) == WBCGI_FTW_CBERR) {
13660Sstevel@tonic-gate 			goto cleanup;
13670Sstevel@tonic-gate 		}
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 		/*
13700Sstevel@tonic-gate 		 * Create the /dev/urandom file.
13710Sstevel@tonic-gate 		 */
13720Sstevel@tonic-gate 		if ((urandompath = make_path(bootfs_dev_dir,
13730Sstevel@tonic-gate 		    "urandom")) == NULL ||
13740Sstevel@tonic-gate 		    !create_urandom(urandompath)) {
13750Sstevel@tonic-gate 			goto cleanup;
13760Sstevel@tonic-gate 		}
13770Sstevel@tonic-gate 	}
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	/*
13800Sstevel@tonic-gate 	 * Add the wanboot.conf(4) file.
13810Sstevel@tonic-gate 	 */
13820Sstevel@tonic-gate 	if ((bootconfpath = make_path(bootfs_dir, NB_WANBOOT_CONF)) == NULL ||
13830Sstevel@tonic-gate 	    !copy_file(bootconf, bootconfpath)) {
13840Sstevel@tonic-gate 		goto cleanup;
13850Sstevel@tonic-gate 	}
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	/*
13880Sstevel@tonic-gate 	 * Add the system_conf file if present.
13890Sstevel@tonic-gate 	 */
13900Sstevel@tonic-gate 	if ((scf = bootconf_get(&bc_handle, BC_SYSTEM_CONF)) != NULL) {
13910Sstevel@tonic-gate 		if (netboot_ftw(scf, net, cid,
13920Sstevel@tonic-gate 		    set_pathname, &systemconf) != WBCGI_FTW_CBOK) {
13930Sstevel@tonic-gate 			print_status(500, "(system_conf file not found)");
13940Sstevel@tonic-gate 			goto cleanup;
13950Sstevel@tonic-gate 		}
13960Sstevel@tonic-gate 		if ((systemconfpath = make_path(bootfs_dir,
13970Sstevel@tonic-gate 		    NB_SYSTEM_CONF)) == NULL ||
13980Sstevel@tonic-gate 		    !copy_file(systemconf, systemconfpath)) {
13990Sstevel@tonic-gate 			goto cleanup;
14000Sstevel@tonic-gate 		}
14010Sstevel@tonic-gate 	}
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 	/*
14040Sstevel@tonic-gate 	 * Create the /nonce file.
14050Sstevel@tonic-gate 	 */
14060Sstevel@tonic-gate 	if ((noncepath = make_path(bootfs_dir, "nonce")) == NULL ||
14070Sstevel@tonic-gate 	    !create_nonce(noncepath, nonce)) {
14080Sstevel@tonic-gate 		goto cleanup;
14090Sstevel@tonic-gate 	}
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	/*
14120Sstevel@tonic-gate 	 * Create an /etc/inet/hosts file by extracting hostnames from CN,
14130Sstevel@tonic-gate 	 * URLs in bootconf and resolve-hosts in bootconf.
14140Sstevel@tonic-gate 	 */
14150Sstevel@tonic-gate 	if ((hostspath = make_path(bootfs_etc_inet_dir, "hosts")) == NULL ||
14160Sstevel@tonic-gate 	    !create_hostsfile(hostspath, net, cid)) {
14170Sstevel@tonic-gate 		goto cleanup;
14180Sstevel@tonic-gate 	}
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	/*
14210Sstevel@tonic-gate 	 * We would like to create a symbolic link etc/hosts -> etc/inet/hosts,
14220Sstevel@tonic-gate 	 * but unfortunately the HSFS support in the standalone doesn't handle
14230Sstevel@tonic-gate 	 * symlinks.
14240Sstevel@tonic-gate 	 */
14250Sstevel@tonic-gate 	if ((etc_hostspath = make_path(bootfs_etc_dir, "hosts")) == NULL ||
14260Sstevel@tonic-gate 	    !copy_file(hostspath, etc_hostspath)) {
14270Sstevel@tonic-gate 		goto cleanup;
14280Sstevel@tonic-gate 	}
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 	/*
14310Sstevel@tonic-gate 	 * Create the /timestamp file.
14320Sstevel@tonic-gate 	 */
14330Sstevel@tonic-gate 	if ((timestamppath = make_path(bootfs_dir, "timestamp")) == NULL ||
14340Sstevel@tonic-gate 	    !create_timestamp(timestamppath, "timestamp")) {
14350Sstevel@tonic-gate 		goto cleanup;
14360Sstevel@tonic-gate 	}
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	/*
14390Sstevel@tonic-gate 	 * Create an HSFS file system for the directory.
14400Sstevel@tonic-gate 	 */
14410Sstevel@tonic-gate 	if ((*wanbootfs_imagep = gen_tmppath("wanbootfs", net, cid)) == NULL ||
14420Sstevel@tonic-gate 	    !mkisofs(bootfs_dir, *wanbootfs_imagep)) {
14430Sstevel@tonic-gate 		goto cleanup;
14440Sstevel@tonic-gate 	}
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 	ret = B_TRUE;
14470Sstevel@tonic-gate cleanup:
14480Sstevel@tonic-gate 	/*
14490Sstevel@tonic-gate 	 * Clean up temporary files and directories.
14500Sstevel@tonic-gate 	 */
14510Sstevel@tonic-gate 	if (keystorepath != NULL &&
14520Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(keystorepath, sbuf)) {
14530Sstevel@tonic-gate 		(void) unlink(keystorepath);
14540Sstevel@tonic-gate 	}
14550Sstevel@tonic-gate 	if (certstorepath != NULL &&
14560Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(certstorepath, sbuf)) {
14570Sstevel@tonic-gate 		(void) unlink(certstorepath);
14580Sstevel@tonic-gate 	}
14590Sstevel@tonic-gate 	if (truststorepath != NULL &&
14600Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(truststorepath, sbuf)) {
14610Sstevel@tonic-gate 		(void) unlink(truststorepath);
14620Sstevel@tonic-gate 	}
14630Sstevel@tonic-gate 	if (bootconfpath != NULL &&
14640Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(bootconfpath, sbuf)) {
14650Sstevel@tonic-gate 		(void) unlink(bootconfpath);
14660Sstevel@tonic-gate 	}
14670Sstevel@tonic-gate 	if (systemconfpath != NULL &&
14680Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(systemconfpath, sbuf)) {
14690Sstevel@tonic-gate 		(void) unlink(systemconfpath);
14700Sstevel@tonic-gate 	}
14710Sstevel@tonic-gate 	if (urandompath != NULL &&
14720Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(urandompath, sbuf)) {
14730Sstevel@tonic-gate 		(void) unlink(urandompath);
14740Sstevel@tonic-gate 	}
14750Sstevel@tonic-gate 	if (noncepath != NULL &&
14760Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(noncepath, sbuf)) {
14770Sstevel@tonic-gate 		(void) unlink(noncepath);
14780Sstevel@tonic-gate 	}
14790Sstevel@tonic-gate 	if (hostspath != NULL &&
14800Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(hostspath, sbuf)) {
14810Sstevel@tonic-gate 		(void) unlink(hostspath);
14820Sstevel@tonic-gate 	}
14830Sstevel@tonic-gate 	if (etc_hostspath != NULL &&
14840Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(etc_hostspath, sbuf)) {
14850Sstevel@tonic-gate 		(void) unlink(etc_hostspath);
14860Sstevel@tonic-gate 	}
14870Sstevel@tonic-gate 	if (timestamppath != NULL &&
14880Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(timestamppath, sbuf)) {
14890Sstevel@tonic-gate 		(void) unlink(timestamppath);
14900Sstevel@tonic-gate 	}
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	if (bootfs_etc_inet_dir != NULL &&
14930Sstevel@tonic-gate 	    WBCGI_DIR_EXISTS(bootfs_etc_inet_dir, sbuf)) {
14940Sstevel@tonic-gate 		(void) rmdir(bootfs_etc_inet_dir);
14950Sstevel@tonic-gate 	}
14960Sstevel@tonic-gate 	if (bootfs_etc_dir != NULL &&
14970Sstevel@tonic-gate 	    WBCGI_DIR_EXISTS(bootfs_etc_dir, sbuf)) {
14980Sstevel@tonic-gate 		(void) rmdir(bootfs_etc_dir);
14990Sstevel@tonic-gate 	}
15000Sstevel@tonic-gate 	if (bootfs_dev_dir != NULL &&
15010Sstevel@tonic-gate 	    WBCGI_DIR_EXISTS(bootfs_dev_dir, sbuf)) {
15020Sstevel@tonic-gate 		(void) rmdir(bootfs_dev_dir);
15030Sstevel@tonic-gate 	}
15040Sstevel@tonic-gate 	if (bootfs_dir != NULL &&
15050Sstevel@tonic-gate 	    WBCGI_DIR_EXISTS(bootfs_dir, sbuf)) {
15060Sstevel@tonic-gate 		(void) rmdir(bootfs_dir);
15070Sstevel@tonic-gate 	}
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate 	/*
15100Sstevel@tonic-gate 	 * Free allocated memory.
15110Sstevel@tonic-gate 	 */
15120Sstevel@tonic-gate 	free_path(&bootfs_dir);
15130Sstevel@tonic-gate 	free_path(&bootfs_etc_dir);
15140Sstevel@tonic-gate 	free_path(&bootfs_etc_inet_dir);
15150Sstevel@tonic-gate 	free_path(&bootfs_dev_dir);
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	free_path(&systemconf);
15180Sstevel@tonic-gate 	free_path(&keystorepath);
15190Sstevel@tonic-gate 	free_path(&certstorepath);
15200Sstevel@tonic-gate 	free_path(&truststorepath);
15210Sstevel@tonic-gate 	free_path(&bootconfpath);
15220Sstevel@tonic-gate 	free_path(&systemconfpath);
15230Sstevel@tonic-gate 	free_path(&urandompath);
15240Sstevel@tonic-gate 	free_path(&noncepath);
15250Sstevel@tonic-gate 	free_path(&hostspath);
15260Sstevel@tonic-gate 	free_path(&etc_hostspath);
15270Sstevel@tonic-gate 	free_path(&timestamppath);
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 	return (ret);
15300Sstevel@tonic-gate }
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate static boolean_t
miniroot_payload(const char * net,const char * cid,const char * docroot,char ** rootpathp,char ** rootinfop,boolean_t * https_rootserverp)15330Sstevel@tonic-gate miniroot_payload(const char *net, const char *cid, const char *docroot,
15340Sstevel@tonic-gate     char **rootpathp, char **rootinfop, boolean_t *https_rootserverp)
15350Sstevel@tonic-gate {
15360Sstevel@tonic-gate 	boolean_t	ret = B_FALSE;
15370Sstevel@tonic-gate 	char		*root_server;
15380Sstevel@tonic-gate 	char		*root_file;
15390Sstevel@tonic-gate 	url_t		url;
15400Sstevel@tonic-gate 	struct stat	sbuf;
15410Sstevel@tonic-gate 	char		sizebuf[WBCGI_MAXBUF];
15420Sstevel@tonic-gate 	int		chars;
15430Sstevel@tonic-gate 	int		fd = -1;
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	if ((root_server = bootconf_get(&bc_handle, BC_ROOT_SERVER)) == NULL) {
15460Sstevel@tonic-gate 		print_status(500, "(root_server must be specified)");
15470Sstevel@tonic-gate 		goto cleanup;
15480Sstevel@tonic-gate 	}
15490Sstevel@tonic-gate 	if (url_parse(root_server, &url) != URL_PARSE_SUCCESS) {
15500Sstevel@tonic-gate 		print_status(500, "(root_server URL is invalid)");
15510Sstevel@tonic-gate 	}
15520Sstevel@tonic-gate 	*https_rootserverp = url.https;
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate 	if ((root_file = bootconf_get(&bc_handle, BC_ROOT_FILE)) == NULL) {
15550Sstevel@tonic-gate 		print_status(500, "(rootfile must be specified)");
15560Sstevel@tonic-gate 		goto cleanup;
15570Sstevel@tonic-gate 	}
15580Sstevel@tonic-gate 	if ((*rootpathp = make_path(docroot, root_file)) == NULL) {
15590Sstevel@tonic-gate 		goto cleanup;
15600Sstevel@tonic-gate 	}
15610Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(*rootpathp, sbuf)) {
15620Sstevel@tonic-gate 		print_status(500, "(root filesystem image missing)");
15630Sstevel@tonic-gate 		goto cleanup;
15640Sstevel@tonic-gate 	}
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 	if ((*rootinfop = gen_tmppath("mrinfo", net, cid)) == NULL) {
15670Sstevel@tonic-gate 		goto cleanup;
15680Sstevel@tonic-gate 	}
15690Sstevel@tonic-gate 	if ((chars = snprintf(sizebuf, sizeof (sizebuf), "%ld",
15700Sstevel@tonic-gate 	    sbuf.st_size)) < 0 || chars > sizeof (sizebuf) ||
15710Sstevel@tonic-gate 	    (fd = open(*rootinfop,
15720Sstevel@tonic-gate 	    O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
15730Sstevel@tonic-gate 	    !write_buffer(fd, sizebuf, strlen(sizebuf))) {
15740Sstevel@tonic-gate 		print_status(500, "(error creating miniroot info file)");
15750Sstevel@tonic-gate 		goto cleanup;
15760Sstevel@tonic-gate 	}
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	ret = B_TRUE;
15790Sstevel@tonic-gate cleanup:
15800Sstevel@tonic-gate 	if (fd != -1) {
15810Sstevel@tonic-gate 		(void) close(fd);
15820Sstevel@tonic-gate 	}
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate 	return (ret);
15850Sstevel@tonic-gate }
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate static boolean_t
deliver_payload(const char * payload,const char * payload_hash)15880Sstevel@tonic-gate deliver_payload(const char *payload, const char *payload_hash)
15890Sstevel@tonic-gate {
15900Sstevel@tonic-gate 	int		fd = fileno(stdout);
15910Sstevel@tonic-gate 	struct stat	payload_buf, hash_buf;
15920Sstevel@tonic-gate 	int		chars;
15930Sstevel@tonic-gate 	char		main_header[WBCGI_MAXBUF];
15940Sstevel@tonic-gate 	char		multi_header[WBCGI_MAXBUF];
15950Sstevel@tonic-gate 	char		multi_header1[WBCGI_MAXBUF];
15960Sstevel@tonic-gate 	char		multi_header2[WBCGI_MAXBUF];
15970Sstevel@tonic-gate 	char		multi_end[WBCGI_MAXBUF];
15980Sstevel@tonic-gate 	size_t		msglen;
15990Sstevel@tonic-gate 
16000Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(payload, payload_buf) ||
16010Sstevel@tonic-gate 	    !WBCGI_FILE_EXISTS(payload_hash, hash_buf)) {
16020Sstevel@tonic-gate 		print_status(500, "(payload/hash file(s) missing)");
16030Sstevel@tonic-gate 		return (B_FALSE);
16040Sstevel@tonic-gate 	}
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate 	/*
16070Sstevel@tonic-gate 	 * Multi-part header.
16080Sstevel@tonic-gate 	 */
16090Sstevel@tonic-gate 	if ((chars = snprintf(multi_header, sizeof (multi_header),
16100Sstevel@tonic-gate 	    "%s--%s%s%sapplication/octet-stream%s%s", WBCGI_CRNL,
16110Sstevel@tonic-gate 	    WBCGI_WANBOOT_BNDTXT, WBCGI_CRNL, WBCGI_CONTENT_TYPE, WBCGI_CRNL,
16120Sstevel@tonic-gate 	    WBCGI_CONTENT_LENGTH)) < 0 || chars > sizeof (multi_header)) {
16130Sstevel@tonic-gate 		print_status(500, "(error creating multi_header)");
16140Sstevel@tonic-gate 		return (B_FALSE);
16150Sstevel@tonic-gate 	}
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 	/*
16180Sstevel@tonic-gate 	 * Multi-part header for part one.
16190Sstevel@tonic-gate 	 */
16200Sstevel@tonic-gate 	if ((chars = snprintf(multi_header1, sizeof (multi_header1),
16210Sstevel@tonic-gate 	    "%s%ld%s%s", multi_header, payload_buf.st_size, WBCGI_CRNL,
16220Sstevel@tonic-gate 	    WBCGI_CRNL)) < 0 || chars > sizeof (multi_header1)) {
16230Sstevel@tonic-gate 		print_status(500, "(error creating multi_header1)");
16240Sstevel@tonic-gate 		return (B_FALSE);
16250Sstevel@tonic-gate 	}
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 	/*
16280Sstevel@tonic-gate 	 * Multi-part header for part two.
16290Sstevel@tonic-gate 	 */
16300Sstevel@tonic-gate 	if ((chars = snprintf(multi_header2, sizeof (multi_header2),
16310Sstevel@tonic-gate 	    "%s%ld%s%s", multi_header, hash_buf.st_size, WBCGI_CRNL,
16320Sstevel@tonic-gate 	    WBCGI_CRNL)) < 0 || chars > sizeof (multi_header2)) {
16330Sstevel@tonic-gate 		print_status(500, "(error creating multi_header2)");
16340Sstevel@tonic-gate 		return (B_FALSE);
16350Sstevel@tonic-gate 	}
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 	/*
16380Sstevel@tonic-gate 	 * End-of-parts Trailer.
16390Sstevel@tonic-gate 	 */
16400Sstevel@tonic-gate 	if ((chars = snprintf(multi_end, sizeof (multi_end),
16410Sstevel@tonic-gate 	    "%s--%s--%s", WBCGI_CRNL, WBCGI_WANBOOT_BNDTXT,
16420Sstevel@tonic-gate 	    WBCGI_CRNL)) < 0 || chars > sizeof (multi_end)) {
16430Sstevel@tonic-gate 		print_status(500, "(error creating multi_end)");
16440Sstevel@tonic-gate 		return (B_FALSE);
16450Sstevel@tonic-gate 	}
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	/*
16480Sstevel@tonic-gate 	 * Message header.
16490Sstevel@tonic-gate 	 */
16500Sstevel@tonic-gate 	msglen = payload_buf.st_size +  hash_buf.st_size +
16510Sstevel@tonic-gate 	    strlen(multi_header1) + strlen(multi_header2) + strlen(multi_end);
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 	if ((chars = snprintf(main_header, sizeof (main_header),
16540Sstevel@tonic-gate 	    "%s%u%s%smultipart/mixed; boundary=%s%s%s", WBCGI_CONTENT_LENGTH,
16550Sstevel@tonic-gate 	    msglen, WBCGI_CRNL, WBCGI_CONTENT_TYPE, WBCGI_WANBOOT_BNDTXT,
16560Sstevel@tonic-gate 	    WBCGI_CRNL, WBCGI_CRNL)) < 0 || chars > sizeof (main_header)) {
16570Sstevel@tonic-gate 		print_status(500, "(error creating main_header)");
16580Sstevel@tonic-gate 		return (B_FALSE);
16590Sstevel@tonic-gate 	}
16600Sstevel@tonic-gate 
16610Sstevel@tonic-gate 	/*
16620Sstevel@tonic-gate 	 * Write the message out.  If things fall apart during this then
16630Sstevel@tonic-gate 	 * there's no way to report the error back to the client.
16640Sstevel@tonic-gate 	 */
16650Sstevel@tonic-gate 	if (!write_buffer(fd, main_header, strlen(main_header)) ||
16660Sstevel@tonic-gate 	    !write_buffer(fd, multi_header1, strlen(multi_header1)) ||
16670Sstevel@tonic-gate 	    !write_file(fd, payload, payload_buf.st_size) ||
16680Sstevel@tonic-gate 	    !write_buffer(fd, multi_header2, strlen(multi_header2)) ||
16690Sstevel@tonic-gate 	    !write_file(fd, payload_hash, hash_buf.st_size) ||
16700Sstevel@tonic-gate 	    !write_buffer(fileno(stdout), multi_end, strlen(multi_end))) {
16710Sstevel@tonic-gate 		return (B_FALSE);
16720Sstevel@tonic-gate 	}
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	return (B_TRUE);
16750Sstevel@tonic-gate }
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate /*ARGSUSED*/
16790Sstevel@tonic-gate int
main(int argc,char ** argv)16800Sstevel@tonic-gate main(int argc, char **argv)
16810Sstevel@tonic-gate {
16820Sstevel@tonic-gate 	int		ret = WBCGI_STATUS_ERR;
16830Sstevel@tonic-gate 	struct stat	sbuf;
16840Sstevel@tonic-gate 	int		content;
16850Sstevel@tonic-gate 	char		*net;
16860Sstevel@tonic-gate 	char		*cid;
16870Sstevel@tonic-gate 	char		*nonce;
16880Sstevel@tonic-gate 	char		*docroot;
16890Sstevel@tonic-gate 	char		*payload;
16900Sstevel@tonic-gate 	char		*signature_type;
16910Sstevel@tonic-gate 	char		*encryption_type;
16920Sstevel@tonic-gate 	char		*bootconf = NULL;
16930Sstevel@tonic-gate 	char		*keyfile = NULL;
16940Sstevel@tonic-gate 	char		*bootpath = NULL;
16950Sstevel@tonic-gate 	char		*wanbootfs_image = NULL;
16960Sstevel@tonic-gate 	char		*rootpath = NULL;
16970Sstevel@tonic-gate 	char		*miniroot_info = NULL;
16980Sstevel@tonic-gate 	char		*encr_payload = NULL;
16990Sstevel@tonic-gate 	char		*payload_hash = NULL;
17000Sstevel@tonic-gate 	boolean_t	https_rootserver;
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate 	/*
17030Sstevel@tonic-gate 	 * Process the query string.
17040Sstevel@tonic-gate 	 */
17050Sstevel@tonic-gate 	if (!get_request_info(&content, &net, &cid, &nonce, &docroot)) {
17060Sstevel@tonic-gate 		goto cleanup;
17070Sstevel@tonic-gate 	}
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate 	/*
17100Sstevel@tonic-gate 	 * Sanity check that the netboot directory exists.
17110Sstevel@tonic-gate 	 */
17120Sstevel@tonic-gate 	if (!WBCGI_DIR_EXISTS(NB_NETBOOT_ROOT, sbuf)) {
17130Sstevel@tonic-gate 		print_status(500, "(" NB_NETBOOT_ROOT " does not exist)");
17140Sstevel@tonic-gate 		goto cleanup;
17150Sstevel@tonic-gate 	}
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 	/*
17180Sstevel@tonic-gate 	 * Get absolute bootconf pathname.
17190Sstevel@tonic-gate 	 */
17200Sstevel@tonic-gate 	if (netboot_ftw(NB_WANBOOT_CONF, net, cid,
17210Sstevel@tonic-gate 	    set_pathname, &bootconf) != WBCGI_FTW_CBOK) {
17220Sstevel@tonic-gate 		print_status(500, "(wanboot.conf not found)");
17230Sstevel@tonic-gate 		goto cleanup;
17240Sstevel@tonic-gate 	}
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 	/*
17270Sstevel@tonic-gate 	 * Initialize bc_handle from the given wanboot.conf file.
17280Sstevel@tonic-gate 	 */
17290Sstevel@tonic-gate 	if (bootconf_init(&bc_handle, bootconf) != BC_SUCCESS) {
17300Sstevel@tonic-gate 		char	message[WBCGI_MAXBUF];
17310Sstevel@tonic-gate 		int	chars;
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate 		chars = snprintf(message, sizeof (message),
17340Sstevel@tonic-gate 		    "(wanboot.conf error: %s)", bootconf_errmsg(&bc_handle));
17350Sstevel@tonic-gate 		if (chars > 0 && chars < sizeof (message))
17360Sstevel@tonic-gate 			print_status(500, message);
17370Sstevel@tonic-gate 		else
17380Sstevel@tonic-gate 			print_status(500, "(wanboot.conf error)");
17390Sstevel@tonic-gate 		goto cleanup;
17400Sstevel@tonic-gate 	}
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 	/*
17430Sstevel@tonic-gate 	 * Get and check signature and encryption types,
17440Sstevel@tonic-gate 	 * presence of helper utilities, keystore, etc.
17450Sstevel@tonic-gate 	 */
17460Sstevel@tonic-gate 	if ((signature_type = bootconf_get(&bc_handle,
17470Sstevel@tonic-gate 	    BC_SIGNATURE_TYPE)) != NULL) {
17480Sstevel@tonic-gate 		if (!WBCGI_FILE_EXISTS(WBCGI_HMAC_PATH, sbuf)) {
17490Sstevel@tonic-gate 			print_status(500, "(hmac utility not found)");
17500Sstevel@tonic-gate 			goto cleanup;
17510Sstevel@tonic-gate 		}
1752*12899Sdminer@opensolaris.org 		if (keyfile == NULL && netboot_ftw(NB_CLIENT_KEY, net, cid,
1753*12899Sdminer@opensolaris.org 		    set_pathname, &keyfile) != WBCGI_FTW_CBOK) {
17540Sstevel@tonic-gate 			print_status(500, "(keystore not found)");
17550Sstevel@tonic-gate 			goto cleanup;
17560Sstevel@tonic-gate 		}
17570Sstevel@tonic-gate 		if (!check_key_type(keyfile, signature_type, WBKU_HASH_KEY)) {
17580Sstevel@tonic-gate 			print_status(500, "(hash key not found)");
17590Sstevel@tonic-gate 			goto cleanup;
17600Sstevel@tonic-gate 		}
17610Sstevel@tonic-gate 	}
17620Sstevel@tonic-gate 	if ((encryption_type = bootconf_get(&bc_handle,
17630Sstevel@tonic-gate 	    BC_ENCRYPTION_TYPE)) != NULL) {
17640Sstevel@tonic-gate 		if (signature_type == NULL) {
17650Sstevel@tonic-gate 			print_status(500, "(encrypted but not signed)");
17660Sstevel@tonic-gate 			goto cleanup;
17670Sstevel@tonic-gate 		}
17680Sstevel@tonic-gate 		if (!WBCGI_FILE_EXISTS(WBCGI_ENCR_PATH, sbuf)) {
17690Sstevel@tonic-gate 			print_status(500, "(encr utility not found)");
17700Sstevel@tonic-gate 			goto cleanup;
17710Sstevel@tonic-gate 		}
1772*12899Sdminer@opensolaris.org 		if (keyfile == NULL && netboot_ftw(NB_CLIENT_KEY, net, cid,
1773*12899Sdminer@opensolaris.org 		    set_pathname, &keyfile) != WBCGI_FTW_CBOK) {
17740Sstevel@tonic-gate 			print_status(500, "(keystore not found)");
17750Sstevel@tonic-gate 			goto cleanup;
17760Sstevel@tonic-gate 		}
17770Sstevel@tonic-gate 		if (!check_key_type(keyfile, encryption_type, WBKU_ENCR_KEY)) {
17780Sstevel@tonic-gate 			print_status(500, "(encr key not found)");
17790Sstevel@tonic-gate 			goto cleanup;
17800Sstevel@tonic-gate 		}
17810Sstevel@tonic-gate 	}
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate 	/*
17840Sstevel@tonic-gate 	 * Determine/create our payload.
17850Sstevel@tonic-gate 	 */
17860Sstevel@tonic-gate 	switch (content) {
17870Sstevel@tonic-gate 	case WBCGI_CONTENT_BOOTFILE:
17880Sstevel@tonic-gate 		if (!bootfile_payload(docroot, &bootpath)) {
17890Sstevel@tonic-gate 			goto cleanup;
17900Sstevel@tonic-gate 		}
17910Sstevel@tonic-gate 		payload = bootpath;
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 		break;
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 	case WBCGI_CONTENT_BOOTFS:
17960Sstevel@tonic-gate 		if (!wanbootfs_payload(net, cid, nonce,
17970Sstevel@tonic-gate 		    bootconf, &wanbootfs_image)) {
17980Sstevel@tonic-gate 			goto cleanup;
17990Sstevel@tonic-gate 		}
18000Sstevel@tonic-gate 		payload = wanbootfs_image;
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 		break;
18030Sstevel@tonic-gate 
18040Sstevel@tonic-gate 	case WBCGI_CONTENT_ROOTFS:
18050Sstevel@tonic-gate 		if (!miniroot_payload(net, cid, docroot,
18060Sstevel@tonic-gate 		    &rootpath, &miniroot_info, &https_rootserver)) {
18070Sstevel@tonic-gate 			goto cleanup;
18080Sstevel@tonic-gate 		}
18090Sstevel@tonic-gate 		payload = rootpath;
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate 		break;
18120Sstevel@tonic-gate 	}
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate 	/*
18150Sstevel@tonic-gate 	 * Encrypt the payload if necessary.
18160Sstevel@tonic-gate 	 */
18170Sstevel@tonic-gate 	if (content != WBCGI_CONTENT_BOOTFILE &&
18180Sstevel@tonic-gate 	    content != WBCGI_CONTENT_ROOTFS &&
18190Sstevel@tonic-gate 	    encryption_type != NULL) {
18200Sstevel@tonic-gate 		if ((encr_payload = gen_tmppath("encr", net, cid)) == NULL) {
18210Sstevel@tonic-gate 			goto cleanup;
18220Sstevel@tonic-gate 		}
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 		if (!encrypt_payload(payload, encr_payload, keyfile,
18250Sstevel@tonic-gate 		    encryption_type)) {
18260Sstevel@tonic-gate 			goto cleanup;
18270Sstevel@tonic-gate 		}
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 		payload = encr_payload;
18300Sstevel@tonic-gate 	}
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate 	/*
18330Sstevel@tonic-gate 	 * Compute the hash (actual or null).
18340Sstevel@tonic-gate 	 */
18350Sstevel@tonic-gate 	if ((payload_hash = gen_tmppath("hash", net, cid)) == NULL) {
18360Sstevel@tonic-gate 		goto cleanup;
18370Sstevel@tonic-gate 	}
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 	if (signature_type != NULL &&
18400Sstevel@tonic-gate 	    (content != WBCGI_CONTENT_ROOTFS || !https_rootserver)) {
18410Sstevel@tonic-gate 		if (!hash_payload(payload, payload_hash, keyfile)) {
18420Sstevel@tonic-gate 			goto cleanup;
18430Sstevel@tonic-gate 		}
18440Sstevel@tonic-gate 	} else {
18450Sstevel@tonic-gate 		if (!create_null_hash(payload_hash)) {
18460Sstevel@tonic-gate 			goto cleanup;
18470Sstevel@tonic-gate 		}
18480Sstevel@tonic-gate 	}
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 	/*
18510Sstevel@tonic-gate 	 * For the rootfs the actual payload transmitted is the file
18520Sstevel@tonic-gate 	 * containing the size of the rootfs (as a string of ascii digits);
18530Sstevel@tonic-gate 	 * point payload at this instead.
18540Sstevel@tonic-gate 	 */
18550Sstevel@tonic-gate 	if (content == WBCGI_CONTENT_ROOTFS) {
18560Sstevel@tonic-gate 		payload = miniroot_info;
18570Sstevel@tonic-gate 	}
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 	/*
18600Sstevel@tonic-gate 	 * Finally, deliver the payload and hash as a multipart message.
18610Sstevel@tonic-gate 	 */
18620Sstevel@tonic-gate 	if (!deliver_payload(payload, payload_hash)) {
18630Sstevel@tonic-gate 		goto cleanup;
18640Sstevel@tonic-gate 	}
18650Sstevel@tonic-gate 
18660Sstevel@tonic-gate 	ret = WBCGI_STATUS_OK;
18670Sstevel@tonic-gate cleanup:
18680Sstevel@tonic-gate 	/*
18690Sstevel@tonic-gate 	 * Clean up temporary files.
18700Sstevel@tonic-gate 	 */
18710Sstevel@tonic-gate 	if (wanbootfs_image != NULL &&
18720Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(wanbootfs_image, sbuf)) {
18730Sstevel@tonic-gate 		(void) unlink(wanbootfs_image);
18740Sstevel@tonic-gate 	}
18750Sstevel@tonic-gate 	if (miniroot_info != NULL &&
18760Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(miniroot_info, sbuf)) {
18770Sstevel@tonic-gate 		(void) unlink(miniroot_info);
18780Sstevel@tonic-gate 	}
18790Sstevel@tonic-gate 	if (encr_payload != NULL &&
18800Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(encr_payload, sbuf)) {
18810Sstevel@tonic-gate 		(void) unlink(encr_payload);
18820Sstevel@tonic-gate 	}
18830Sstevel@tonic-gate 	if (payload_hash != NULL &&
18840Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(payload_hash, sbuf)) {
18850Sstevel@tonic-gate 		(void) unlink(payload_hash);
18860Sstevel@tonic-gate 	}
18870Sstevel@tonic-gate 
18880Sstevel@tonic-gate 	/*
18890Sstevel@tonic-gate 	 * Free up any allocated strings.
18900Sstevel@tonic-gate 	 */
18910Sstevel@tonic-gate 	free_path(&bootconf);
18920Sstevel@tonic-gate 	free_path(&keyfile);
18930Sstevel@tonic-gate 	free_path(&bootpath);
18940Sstevel@tonic-gate 	free_path(&wanbootfs_image);
18950Sstevel@tonic-gate 	free_path(&rootpath);
18960Sstevel@tonic-gate 	free_path(&miniroot_info);
18970Sstevel@tonic-gate 	free_path(&encr_payload);
18980Sstevel@tonic-gate 	free_path(&payload_hash);
18990Sstevel@tonic-gate 
19000Sstevel@tonic-gate 	bootconf_end(&bc_handle);
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 	return (ret);
19030Sstevel@tonic-gate }
1904