1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*0Sstevel@tonic-gate 
28*0Sstevel@tonic-gate #include <stdio.h>
29*0Sstevel@tonic-gate #include <stdlib.h>
30*0Sstevel@tonic-gate #include <strings.h>
31*0Sstevel@tonic-gate #include <string.h>
32*0Sstevel@tonic-gate #include <libgen.h>
33*0Sstevel@tonic-gate #include <unistd.h>
34*0Sstevel@tonic-gate #include <fcntl.h>
35*0Sstevel@tonic-gate #include <errno.h>
36*0Sstevel@tonic-gate #include <netdb.h>
37*0Sstevel@tonic-gate #include <libnvpair.h>
38*0Sstevel@tonic-gate #include <sys/types.h>
39*0Sstevel@tonic-gate #include <sys/wait.h>
40*0Sstevel@tonic-gate #include <sys/stat.h>
41*0Sstevel@tonic-gate #include <sys/param.h>
42*0Sstevel@tonic-gate #include <sys/sysmacros.h>
43*0Sstevel@tonic-gate #include <sys/mman.h>
44*0Sstevel@tonic-gate #include <sys/socket.h>
45*0Sstevel@tonic-gate #include <sys/wanboot_impl.h>
46*0Sstevel@tonic-gate #include <netinet/in.h>
47*0Sstevel@tonic-gate #include <arpa/inet.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate #include <openssl/crypto.h>
50*0Sstevel@tonic-gate #include <openssl/x509.h>
51*0Sstevel@tonic-gate #include <openssl/x509v3.h>
52*0Sstevel@tonic-gate #include <openssl/pem.h>
53*0Sstevel@tonic-gate #include <openssl/pkcs12.h>
54*0Sstevel@tonic-gate #include <openssl/evp.h>
55*0Sstevel@tonic-gate #include <openssl/err.h>
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate #include <p12aux.h>
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate #include <parseURL.h>
60*0Sstevel@tonic-gate /*
61*0Sstevel@tonic-gate  * These can be replaced with wanbootutil.h once the openssl interfaces
62*0Sstevel@tonic-gate  * are moved to libwanboot.
63*0Sstevel@tonic-gate  */
64*0Sstevel@tonic-gate #include <wanboot/key_util.h>
65*0Sstevel@tonic-gate #include <wanboot/key_xdr.h>
66*0Sstevel@tonic-gate #include <hmac_sha1.h>
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate #include <netboot_paths.h>
69*0Sstevel@tonic-gate #include <wanboot_conf.h>
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate /*
72*0Sstevel@tonic-gate  * Exit status:
73*0Sstevel@tonic-gate  */
74*0Sstevel@tonic-gate #define	WBCGI_STATUS_OK		0
75*0Sstevel@tonic-gate #define	WBCGI_STATUS_ERR	1
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate #define	WBCGI_FILE_EXISTS(file, statbuf) \
78*0Sstevel@tonic-gate 	(stat(file, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate #define	WBCGI_DIR_EXISTS(dir, statbuf) \
81*0Sstevel@tonic-gate 	(stat(dir, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate #define	WBCGI_HMAC_PATH		"/usr/lib/inet/wanboot/hmac"
84*0Sstevel@tonic-gate #define	WBCGI_ENCR_PATH		"/usr/lib/inet/wanboot/encr"
85*0Sstevel@tonic-gate #define	WBCGI_KEYMGMT_PATH	"/usr/lib/inet/wanboot/keymgmt"
86*0Sstevel@tonic-gate #define	WBCGI_MKISOFS_PATH	"/bin/mkisofs"
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate #define	WBCGI_DEV_URANDOM	"/dev/urandom"
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate #define	WBCGI_CONTENT_TYPE	"Content-Type: "
91*0Sstevel@tonic-gate #define	WBCGI_CONTENT_LENGTH	"Content-Length: "
92*0Sstevel@tonic-gate #define	WBCGI_WANBOOT_BNDTXT	"WANBoot_Part_Boundary"
93*0Sstevel@tonic-gate #define	WBCGI_CRNL		"\r\n"
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate #define	WBCGI_CNSTR		"CN="
96*0Sstevel@tonic-gate #define	WBCGI_CNSTR_LEN		(sizeof (WBCGI_CNSTR) - 1)
97*0Sstevel@tonic-gate #define	WBCGI_NAMESEP		",/\n\r"
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate #define	WBCGI_MAXBUF		256
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate /*
102*0Sstevel@tonic-gate  * Possible return values from netboot_ftw():
103*0Sstevel@tonic-gate  */
104*0Sstevel@tonic-gate #define	WBCGI_FTW_CBOK		2	/* CB terminated walk OK */
105*0Sstevel@tonic-gate #define	WBCGI_FTW_CBCONT	1	/* CB wants walk should continue */
106*0Sstevel@tonic-gate #define	WBCGI_FTW_DONE		0	/* Walk terminated without CBERR/CBOK */
107*0Sstevel@tonic-gate #define	WBCGI_FTW_CBERR		-1	/* CB terminated walk with err */
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate /*
110*0Sstevel@tonic-gate  * getsubopt() is used to map one of the contents[] keywords
111*0Sstevel@tonic-gate  * to one of these types
112*0Sstevel@tonic-gate  */
113*0Sstevel@tonic-gate #define	WBCGI_CONTENT_ERROR	-1
114*0Sstevel@tonic-gate #define	WBCGI_CONTENT_BOOTFILE	0
115*0Sstevel@tonic-gate #define	WBCGI_CONTENT_BOOTFS	1
116*0Sstevel@tonic-gate #define	WBCGI_CONTENT_ROOTFS	2
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate static char *contents[] =
119*0Sstevel@tonic-gate 	{ "bootfile", "bootfs", "rootfs", NULL };
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate /*
122*0Sstevel@tonic-gate  * getsubopt() is used to parse the query string for
123*0Sstevel@tonic-gate  * the keywords defined by queryopts[]
124*0Sstevel@tonic-gate  */
125*0Sstevel@tonic-gate #define	WBCGI_QUERYOPT_CONTENT	0
126*0Sstevel@tonic-gate #define	WBCGI_QUERYOPT_NET	1
127*0Sstevel@tonic-gate #define	WBCGI_QUERYOPT_CID	2
128*0Sstevel@tonic-gate #define	WBCGI_QUERYOPT_NONCE	3
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate static char *queryopts[] =
131*0Sstevel@tonic-gate 	{ "CONTENT", "IP", "CID", "NONCE", NULL };
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate static bc_handle_t	bc_handle;
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate static char *
137*0Sstevel@tonic-gate status_msg(int status)
138*0Sstevel@tonic-gate {
139*0Sstevel@tonic-gate 	char	*msg;
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	switch (status) {
142*0Sstevel@tonic-gate 	case 400:
143*0Sstevel@tonic-gate 		msg = "Bad Request";
144*0Sstevel@tonic-gate 		break;
145*0Sstevel@tonic-gate 	case 403:
146*0Sstevel@tonic-gate 		msg = "Forbidden";
147*0Sstevel@tonic-gate 		break;
148*0Sstevel@tonic-gate 	case 500:
149*0Sstevel@tonic-gate 		msg = "Internal Server Error";
150*0Sstevel@tonic-gate 		break;
151*0Sstevel@tonic-gate 	default:
152*0Sstevel@tonic-gate 		msg = "Unknown status";
153*0Sstevel@tonic-gate 		break;
154*0Sstevel@tonic-gate 	}
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	return (msg);
157*0Sstevel@tonic-gate }
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate static void
160*0Sstevel@tonic-gate print_status(int status, const char *spec_msg)
161*0Sstevel@tonic-gate {
162*0Sstevel@tonic-gate 	if (spec_msg == NULL) {
163*0Sstevel@tonic-gate 		spec_msg = "";
164*0Sstevel@tonic-gate 	}
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	(void) fprintf(stdout, "Status: %d %s %s%s", status,
167*0Sstevel@tonic-gate 	    status_msg(status), spec_msg, WBCGI_CRNL);
168*0Sstevel@tonic-gate }
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate static char *
171*0Sstevel@tonic-gate make_path(const char *root, const char *suffix)
172*0Sstevel@tonic-gate {
173*0Sstevel@tonic-gate 	char	path[MAXPATHLEN];
174*0Sstevel@tonic-gate 	char	*ptr = NULL;
175*0Sstevel@tonic-gate 	int	chars;
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	if ((chars = snprintf(path, sizeof (path),
178*0Sstevel@tonic-gate 	    "%s/%s", root, suffix)) < 0 || chars > sizeof (path) ||
179*0Sstevel@tonic-gate 	    (ptr = strdup(path)) == NULL) {
180*0Sstevel@tonic-gate 		print_status(500, "(error making path)");
181*0Sstevel@tonic-gate 	}
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	return (ptr);
184*0Sstevel@tonic-gate }
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate static void
187*0Sstevel@tonic-gate free_path(char **pathp)
188*0Sstevel@tonic-gate {
189*0Sstevel@tonic-gate 	if (*pathp != NULL) {
190*0Sstevel@tonic-gate 		free(*pathp);
191*0Sstevel@tonic-gate 		*pathp = NULL;
192*0Sstevel@tonic-gate 	}
193*0Sstevel@tonic-gate }
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate static char *
196*0Sstevel@tonic-gate gen_tmppath(const char *prefix, const char *net, const char *cid)
197*0Sstevel@tonic-gate {
198*0Sstevel@tonic-gate 	pid_t	pid;
199*0Sstevel@tonic-gate 	time_t	secs;
200*0Sstevel@tonic-gate 	int	chars;
201*0Sstevel@tonic-gate 	char	path[MAXPATHLEN];
202*0Sstevel@tonic-gate 	char	*ptr = NULL;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	if ((pid = getpid()) < 0 || (secs = time(NULL)) < 0 ||
205*0Sstevel@tonic-gate 	    (chars = snprintf(path, sizeof (path), "/tmp/%s_%s_%s_%ld_%ld",
206*0Sstevel@tonic-gate 	    prefix, net, cid, pid, secs)) < 0 || chars > sizeof (path) ||
207*0Sstevel@tonic-gate 	    (ptr = strdup(path)) == NULL) {
208*0Sstevel@tonic-gate 		print_status(500, "(error creating temporary filename)");
209*0Sstevel@tonic-gate 	}
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	return (ptr);
212*0Sstevel@tonic-gate }
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate /*
215*0Sstevel@tonic-gate  * File I/O stuff:
216*0Sstevel@tonic-gate  */
217*0Sstevel@tonic-gate static boolean_t
218*0Sstevel@tonic-gate write_buffer(int fd, const void *buffer, size_t buflen)
219*0Sstevel@tonic-gate {
220*0Sstevel@tonic-gate 	size_t		nwritten;
221*0Sstevel@tonic-gate 	ssize_t		nbytes;
222*0Sstevel@tonic-gate 	const char	*buf = buffer;
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	for (nwritten = 0; nwritten < buflen; nwritten += nbytes) {
225*0Sstevel@tonic-gate 		nbytes = write(fd, &buf[nwritten], buflen - nwritten);
226*0Sstevel@tonic-gate 		if (nbytes <= 0) {
227*0Sstevel@tonic-gate 			return (B_FALSE);
228*0Sstevel@tonic-gate 		}
229*0Sstevel@tonic-gate 	}
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	return (B_TRUE);
232*0Sstevel@tonic-gate }
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate static boolean_t
235*0Sstevel@tonic-gate write_file(int ofd, const char *filename, size_t size)
236*0Sstevel@tonic-gate {
237*0Sstevel@tonic-gate 	boolean_t	ret = B_TRUE;
238*0Sstevel@tonic-gate 	int		ifd;
239*0Sstevel@tonic-gate 	char		buf[1024];
240*0Sstevel@tonic-gate 	size_t		rlen;
241*0Sstevel@tonic-gate 	ssize_t		wlen;
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	if ((ifd = open(filename, O_RDONLY)) < 0) {
244*0Sstevel@tonic-gate 		return (B_FALSE);
245*0Sstevel@tonic-gate 	}
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 	for (; size != 0; size -= wlen) {
248*0Sstevel@tonic-gate 		rlen = (size < sizeof (buf)) ? size : sizeof (buf);
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 		if ((wlen = read(ifd, buf, rlen)) < 0 ||
251*0Sstevel@tonic-gate 		    !write_buffer(ofd, buf, wlen)) {
252*0Sstevel@tonic-gate 			ret = B_FALSE;
253*0Sstevel@tonic-gate 			break;
254*0Sstevel@tonic-gate 		}
255*0Sstevel@tonic-gate 	}
256*0Sstevel@tonic-gate 	(void) close(ifd);
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	return (ret);
259*0Sstevel@tonic-gate }
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate static boolean_t
262*0Sstevel@tonic-gate copy_file(const char *src, const char *dest)
263*0Sstevel@tonic-gate {
264*0Sstevel@tonic-gate 	boolean_t	ret = B_FALSE;
265*0Sstevel@tonic-gate 	char		message[WBCGI_MAXBUF];
266*0Sstevel@tonic-gate 	const size_t	chunksize = 16 * PAGESIZE;
267*0Sstevel@tonic-gate 	size_t		validsize;
268*0Sstevel@tonic-gate 	size_t		nwritten = 0;
269*0Sstevel@tonic-gate 	size_t		nbytes = 0;
270*0Sstevel@tonic-gate 	off_t		roff;
271*0Sstevel@tonic-gate 	int		mflags = MAP_PRIVATE;
272*0Sstevel@tonic-gate 	char		*buf = NULL;
273*0Sstevel@tonic-gate 	struct stat	st;
274*0Sstevel@tonic-gate 	int		rfd = -1;
275*0Sstevel@tonic-gate 	int		wfd = -1;
276*0Sstevel@tonic-gate 	int		chars;
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	if ((rfd = open(src, O_RDONLY)) < 0 ||
279*0Sstevel@tonic-gate 	    (wfd = open(dest, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR)) < 0 ||
280*0Sstevel@tonic-gate 	    fstat(rfd, &st) == -1) {
281*0Sstevel@tonic-gate 		goto cleanup;
282*0Sstevel@tonic-gate 	}
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate 	for (nbytes = st.st_size, roff = 0; nwritten < nbytes;
285*0Sstevel@tonic-gate 	    nwritten += validsize, roff += validsize) {
286*0Sstevel@tonic-gate 		buf = mmap(buf, chunksize, PROT_READ, mflags, rfd, roff);
287*0Sstevel@tonic-gate 		if (buf == MAP_FAILED) {
288*0Sstevel@tonic-gate 			goto cleanup;
289*0Sstevel@tonic-gate 		}
290*0Sstevel@tonic-gate 		mflags |= MAP_FIXED;
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 		validsize = MIN(chunksize, nbytes - nwritten);
293*0Sstevel@tonic-gate 		if (!write_buffer(wfd, buf, validsize)) {
294*0Sstevel@tonic-gate 			(void) munmap(buf, chunksize);
295*0Sstevel@tonic-gate 			goto cleanup;
296*0Sstevel@tonic-gate 		}
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	}
299*0Sstevel@tonic-gate 	if (buf != NULL) {
300*0Sstevel@tonic-gate 		(void) munmap(buf, chunksize);
301*0Sstevel@tonic-gate 	}
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	ret = B_TRUE;
304*0Sstevel@tonic-gate cleanup:
305*0Sstevel@tonic-gate 	if (ret == B_FALSE) {
306*0Sstevel@tonic-gate 		if ((chars = snprintf(message, sizeof (message),
307*0Sstevel@tonic-gate 		    "error copying %s to %s", src, dest)) > 0 &&
308*0Sstevel@tonic-gate 		    chars <= sizeof (message)) {
309*0Sstevel@tonic-gate 			print_status(500, message);
310*0Sstevel@tonic-gate 		} else {
311*0Sstevel@tonic-gate 			print_status(500, NULL);
312*0Sstevel@tonic-gate 		}
313*0Sstevel@tonic-gate 	}
314*0Sstevel@tonic-gate 	if (rfd != -1) {
315*0Sstevel@tonic-gate 		(void) close(rfd);
316*0Sstevel@tonic-gate 	}
317*0Sstevel@tonic-gate 	if (wfd != -1) {
318*0Sstevel@tonic-gate 		(void) close(wfd);
319*0Sstevel@tonic-gate 	}
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	return (ret);
322*0Sstevel@tonic-gate }
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate static boolean_t
325*0Sstevel@tonic-gate create_nonce(const char *noncepath, const char *nonce)
326*0Sstevel@tonic-gate {
327*0Sstevel@tonic-gate 	boolean_t	ret = B_TRUE;
328*0Sstevel@tonic-gate 	int		fd;
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	if ((fd = open(noncepath,
331*0Sstevel@tonic-gate 	    O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
332*0Sstevel@tonic-gate 	    !write_buffer(fd, nonce, strlen(nonce))) {
333*0Sstevel@tonic-gate 		print_status(500, "(error creating nonce file)");
334*0Sstevel@tonic-gate 		ret = B_FALSE;
335*0Sstevel@tonic-gate 	}
336*0Sstevel@tonic-gate 	if (fd != -1) {
337*0Sstevel@tonic-gate 		(void) close(fd);
338*0Sstevel@tonic-gate 	}
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	return (ret);
341*0Sstevel@tonic-gate }
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate static boolean_t
344*0Sstevel@tonic-gate create_timestamp(const char *timestamppath, const char *timestamp)
345*0Sstevel@tonic-gate {
346*0Sstevel@tonic-gate 	boolean_t	ret = B_TRUE;
347*0Sstevel@tonic-gate 	int		fd;
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	if ((fd = open(timestamppath,
350*0Sstevel@tonic-gate 	    O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
351*0Sstevel@tonic-gate 	    !write_buffer(fd, timestamp, strlen(timestamp))) {
352*0Sstevel@tonic-gate 		print_status(500, "(error creating timestamp file)");
353*0Sstevel@tonic-gate 		ret = B_FALSE;
354*0Sstevel@tonic-gate 	}
355*0Sstevel@tonic-gate 	if (fd != -1) {
356*0Sstevel@tonic-gate 		(void) close(fd);
357*0Sstevel@tonic-gate 	}
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	return (ret);
360*0Sstevel@tonic-gate }
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate static boolean_t
363*0Sstevel@tonic-gate create_urandom(const char *urandompath)
364*0Sstevel@tonic-gate {
365*0Sstevel@tonic-gate 	boolean_t	ret = B_TRUE;
366*0Sstevel@tonic-gate 	int		fd;
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	if ((fd = open(urandompath,
369*0Sstevel@tonic-gate 	    O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
370*0Sstevel@tonic-gate 	    !write_file(fd, WBCGI_DEV_URANDOM, 32 * 1024)) {
371*0Sstevel@tonic-gate 		print_status(500, "(error creating urandom file)");
372*0Sstevel@tonic-gate 		ret = B_FALSE;
373*0Sstevel@tonic-gate 	}
374*0Sstevel@tonic-gate 	if (fd != -1) {
375*0Sstevel@tonic-gate 		(void) close(fd);
376*0Sstevel@tonic-gate 	}
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	return (ret);
379*0Sstevel@tonic-gate }
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate static boolean_t
382*0Sstevel@tonic-gate create_null_hash(const char *hashpath)
383*0Sstevel@tonic-gate {
384*0Sstevel@tonic-gate 	boolean_t	ret = B_TRUE;
385*0Sstevel@tonic-gate 	int		fd;
386*0Sstevel@tonic-gate 	static char	null_hash[HMAC_DIGEST_LEN];
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	if ((fd = open(hashpath,
389*0Sstevel@tonic-gate 	    O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
390*0Sstevel@tonic-gate 	    !write_buffer(fd, null_hash, sizeof (null_hash))) {
391*0Sstevel@tonic-gate 		print_status(500, "(error creating null hash)");
392*0Sstevel@tonic-gate 		ret = B_FALSE;
393*0Sstevel@tonic-gate 	}
394*0Sstevel@tonic-gate 	if (fd != -1) {
395*0Sstevel@tonic-gate 		(void) close(fd);
396*0Sstevel@tonic-gate 	}
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 	return (ret);
399*0Sstevel@tonic-gate }
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate static char *
403*0Sstevel@tonic-gate determine_doc_root(void)
404*0Sstevel@tonic-gate {
405*0Sstevel@tonic-gate 	char	*doc_root;
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 	/*
408*0Sstevel@tonic-gate 	 * If DOCUMENT_ROOT is valid, use that.
409*0Sstevel@tonic-gate 	 */
410*0Sstevel@tonic-gate 	if ((doc_root = getenv("DOCUMENT_ROOT")) == NULL ||
411*0Sstevel@tonic-gate 	    strlen(doc_root) == 0) {
412*0Sstevel@tonic-gate 		/*
413*0Sstevel@tonic-gate 		 * No DOCUMENT_ROOT - try PATH_TRANSLATED.
414*0Sstevel@tonic-gate 		 */
415*0Sstevel@tonic-gate 		if ((doc_root = getenv("PATH_TRANSLATED")) == NULL ||
416*0Sstevel@tonic-gate 		    strlen(doc_root) == 0) {
417*0Sstevel@tonic-gate 			/*
418*0Sstevel@tonic-gate 			 * Can't determine the document root.
419*0Sstevel@tonic-gate 			 */
420*0Sstevel@tonic-gate 			return (NULL);
421*0Sstevel@tonic-gate 		}
422*0Sstevel@tonic-gate 	}
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	return (doc_root);
425*0Sstevel@tonic-gate }
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate static boolean_t
428*0Sstevel@tonic-gate get_request_info(int *contentp, char **netp, char **cidp, char **noncep,
429*0Sstevel@tonic-gate     char **docrootp)
430*0Sstevel@tonic-gate {
431*0Sstevel@tonic-gate 	char	*method;
432*0Sstevel@tonic-gate 	char	*query_string;
433*0Sstevel@tonic-gate 	char	*value;
434*0Sstevel@tonic-gate 	char	*junk;
435*0Sstevel@tonic-gate 	int	i;
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	if ((method = getenv("REQUEST_METHOD")) == NULL ||
438*0Sstevel@tonic-gate 	    strncasecmp(method, "GET", strlen("GET") != 0)) {
439*0Sstevel@tonic-gate 		print_status(403, "(GET method expected)");
440*0Sstevel@tonic-gate 		return (B_FALSE);
441*0Sstevel@tonic-gate 	}
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate 	if ((query_string = getenv("QUERY_STRING")) == NULL) {
444*0Sstevel@tonic-gate 		print_status(400, "(empty query string)");
445*0Sstevel@tonic-gate 		return (B_FALSE);
446*0Sstevel@tonic-gate 	}
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate 	for (i = 0; i < strlen(query_string); i++) {
449*0Sstevel@tonic-gate 		if (query_string[i] == '&') {
450*0Sstevel@tonic-gate 			query_string[i] = ',';
451*0Sstevel@tonic-gate 		}
452*0Sstevel@tonic-gate 	}
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	*contentp = WBCGI_CONTENT_ERROR;
455*0Sstevel@tonic-gate 	*netp = *cidp = *noncep = NULL;
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 	if ((*docrootp = determine_doc_root()) == NULL) {
458*0Sstevel@tonic-gate 		print_status(400, "(unable to determine document root)");
459*0Sstevel@tonic-gate 		return (B_FALSE);
460*0Sstevel@tonic-gate 	}
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate 	while (*query_string != '\0') {
463*0Sstevel@tonic-gate 		switch (getsubopt(&query_string, queryopts, &value)) {
464*0Sstevel@tonic-gate 		case WBCGI_QUERYOPT_CONTENT:
465*0Sstevel@tonic-gate 			*contentp = getsubopt(&value, contents, &junk);
466*0Sstevel@tonic-gate 			break;
467*0Sstevel@tonic-gate 		case WBCGI_QUERYOPT_NET:
468*0Sstevel@tonic-gate 			*netp = value;
469*0Sstevel@tonic-gate 			break;
470*0Sstevel@tonic-gate 		case WBCGI_QUERYOPT_CID:
471*0Sstevel@tonic-gate 			*cidp = value;
472*0Sstevel@tonic-gate 			break;
473*0Sstevel@tonic-gate 		case WBCGI_QUERYOPT_NONCE:
474*0Sstevel@tonic-gate 			*noncep = value;
475*0Sstevel@tonic-gate 			break;
476*0Sstevel@tonic-gate 		default:
477*0Sstevel@tonic-gate 			print_status(400, "(illegal query string)");
478*0Sstevel@tonic-gate 			return (B_FALSE);
479*0Sstevel@tonic-gate 			break;
480*0Sstevel@tonic-gate 		}
481*0Sstevel@tonic-gate 	}
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	switch (*contentp) {
484*0Sstevel@tonic-gate 	default:
485*0Sstevel@tonic-gate 		print_status(400, "(missing or illegal CONTENT)");
486*0Sstevel@tonic-gate 		return (B_FALSE);
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	case WBCGI_CONTENT_BOOTFS:
489*0Sstevel@tonic-gate 		if (*netp == NULL || *cidp == NULL || *noncep == NULL) {
490*0Sstevel@tonic-gate 			print_status(400,
491*0Sstevel@tonic-gate 			    "(CONTENT, IP, CID and NONCE required)");
492*0Sstevel@tonic-gate 			return (B_FALSE);
493*0Sstevel@tonic-gate 		}
494*0Sstevel@tonic-gate 		break;
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 	case WBCGI_CONTENT_BOOTFILE:
497*0Sstevel@tonic-gate 	case WBCGI_CONTENT_ROOTFS:
498*0Sstevel@tonic-gate 		if (*netp == NULL || *cidp == NULL || *docrootp == NULL) {
499*0Sstevel@tonic-gate 			print_status(400,
500*0Sstevel@tonic-gate 			    "(CONTENT, IP, CID and DOCUMENT_ROOT required)");
501*0Sstevel@tonic-gate 			return (B_FALSE);
502*0Sstevel@tonic-gate 		}
503*0Sstevel@tonic-gate 		break;
504*0Sstevel@tonic-gate 	}
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	return (B_TRUE);
507*0Sstevel@tonic-gate }
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate static boolean_t
510*0Sstevel@tonic-gate encrypt_payload(const char *payload, const char *encr_payload,
511*0Sstevel@tonic-gate     const char *keyfile, const char *encryption_type)
512*0Sstevel@tonic-gate {
513*0Sstevel@tonic-gate 	struct stat	sbuf;
514*0Sstevel@tonic-gate 	int		chars;
515*0Sstevel@tonic-gate 	char		cmd[MAXPATHLEN];
516*0Sstevel@tonic-gate 	FILE		*fp;
517*0Sstevel@tonic-gate 	int		status;
518*0Sstevel@tonic-gate 	char		msg[WBCGI_MAXBUF];
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(payload, sbuf)) {
521*0Sstevel@tonic-gate 		print_status(500, "(encrypt_payload: missing payload)");
522*0Sstevel@tonic-gate 		return (B_FALSE);
523*0Sstevel@tonic-gate 	}
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 	if ((chars = snprintf(cmd, sizeof (cmd),
526*0Sstevel@tonic-gate 	    "%s -o type=%s -k %s < %s > %s", WBCGI_ENCR_PATH,
527*0Sstevel@tonic-gate 	    encryption_type, keyfile, payload, encr_payload)) < 0 ||
528*0Sstevel@tonic-gate 	    chars > sizeof (cmd)) {
529*0Sstevel@tonic-gate 		print_status(500, "(encrypt_payload: buffer overflow)");
530*0Sstevel@tonic-gate 		return (B_FALSE);
531*0Sstevel@tonic-gate 	}
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 	if ((fp = popen(cmd, "w")) == NULL) {
534*0Sstevel@tonic-gate 		print_status(500, "(encrypt_payload: missing/file error)");
535*0Sstevel@tonic-gate 		return (B_FALSE);
536*0Sstevel@tonic-gate 	}
537*0Sstevel@tonic-gate 	if ((status = WEXITSTATUS(pclose(fp))) != 0) {
538*0Sstevel@tonic-gate 		(void) snprintf(msg, sizeof (msg),
539*0Sstevel@tonic-gate 		    "(encrypt_payload: failed, status=%d)", status);
540*0Sstevel@tonic-gate 		print_status(500, msg);
541*0Sstevel@tonic-gate 		return (B_FALSE);
542*0Sstevel@tonic-gate 	}
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(encr_payload, sbuf)) {
545*0Sstevel@tonic-gate 		print_status(500, "(encrypt_payload: bad encrypted file)");
546*0Sstevel@tonic-gate 		return (B_FALSE);
547*0Sstevel@tonic-gate 	}
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 	return (B_TRUE);
550*0Sstevel@tonic-gate }
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate static boolean_t
553*0Sstevel@tonic-gate hash_payload(const char *payload, const char *payload_hash,
554*0Sstevel@tonic-gate     const char *keyfile)
555*0Sstevel@tonic-gate {
556*0Sstevel@tonic-gate 	struct stat	sbuf;
557*0Sstevel@tonic-gate 	int		chars;
558*0Sstevel@tonic-gate 	char		cmd[MAXPATHLEN];
559*0Sstevel@tonic-gate 	FILE		*fp;
560*0Sstevel@tonic-gate 	int		status;
561*0Sstevel@tonic-gate 	char		msg[WBCGI_MAXBUF];
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(payload, sbuf)) {
564*0Sstevel@tonic-gate 		print_status(500, "(hash_payload: missing payload)");
565*0Sstevel@tonic-gate 		return (B_FALSE);
566*0Sstevel@tonic-gate 	}
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 	if ((chars = snprintf(cmd, sizeof (cmd), "%s -i %s -k %s > %s",
569*0Sstevel@tonic-gate 	    WBCGI_HMAC_PATH, payload, keyfile, payload_hash)) < 0 ||
570*0Sstevel@tonic-gate 	    chars > sizeof (cmd)) {
571*0Sstevel@tonic-gate 		print_status(500, "(hash_payload: buffer overflow)");
572*0Sstevel@tonic-gate 		return (B_FALSE);
573*0Sstevel@tonic-gate 	}
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 	if ((fp = popen(cmd, "w")) == NULL) {
576*0Sstevel@tonic-gate 		print_status(500, "(hash_payload: missing/file error)");
577*0Sstevel@tonic-gate 		return (B_FALSE);
578*0Sstevel@tonic-gate 	}
579*0Sstevel@tonic-gate 	if ((status = WEXITSTATUS(pclose(fp))) != 0) {
580*0Sstevel@tonic-gate 		(void) snprintf(msg, sizeof (msg),
581*0Sstevel@tonic-gate 		    "(hash_payload: failed, status=%d)", status);
582*0Sstevel@tonic-gate 		print_status(500, msg);
583*0Sstevel@tonic-gate 		return (B_FALSE);
584*0Sstevel@tonic-gate 	}
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(payload_hash, sbuf) ||
587*0Sstevel@tonic-gate 	    sbuf.st_size < HMAC_DIGEST_LEN) {
588*0Sstevel@tonic-gate 		print_status(500, "(hash_payload: bad signature file)");
589*0Sstevel@tonic-gate 		return (B_FALSE);
590*0Sstevel@tonic-gate 	}
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate 	return (B_TRUE);
593*0Sstevel@tonic-gate }
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate static boolean_t
596*0Sstevel@tonic-gate extract_keystore(const char *path, const char *keystorepath)
597*0Sstevel@tonic-gate {
598*0Sstevel@tonic-gate 	struct stat	sbuf;
599*0Sstevel@tonic-gate 	int		chars;
600*0Sstevel@tonic-gate 	char		cmd[MAXPATHLEN];
601*0Sstevel@tonic-gate 	FILE		*fp;
602*0Sstevel@tonic-gate 	int		status;
603*0Sstevel@tonic-gate 	char		msg[WBCGI_MAXBUF];
604*0Sstevel@tonic-gate 
605*0Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(path, sbuf)) {
606*0Sstevel@tonic-gate 		print_status(500, "(extract_keystore: missing keystore)");
607*0Sstevel@tonic-gate 		return (B_FALSE);
608*0Sstevel@tonic-gate 	}
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	if ((chars = snprintf(cmd, sizeof (cmd),
611*0Sstevel@tonic-gate 	    "%s -x -f %s -s %s -o type=rsa",
612*0Sstevel@tonic-gate 	    WBCGI_KEYMGMT_PATH, keystorepath, path)) < 0 ||
613*0Sstevel@tonic-gate 	    chars > sizeof (cmd)) {
614*0Sstevel@tonic-gate 		print_status(500, "(extract_keystore: buffer overflow)");
615*0Sstevel@tonic-gate 		return (B_FALSE);
616*0Sstevel@tonic-gate 	}
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 	if ((fp = popen(cmd, "w")) == NULL) {
619*0Sstevel@tonic-gate 		print_status(500, "(extract_keystore: missing/file error)");
620*0Sstevel@tonic-gate 		return (B_FALSE);
621*0Sstevel@tonic-gate 	}
622*0Sstevel@tonic-gate 	if ((status = WEXITSTATUS(pclose(fp))) != 0) {
623*0Sstevel@tonic-gate 		(void) snprintf(msg, sizeof (msg),
624*0Sstevel@tonic-gate 		    "(extract_keystore: failed, status=%d)", status);
625*0Sstevel@tonic-gate 		print_status(500, msg);
626*0Sstevel@tonic-gate 		return (B_FALSE);
627*0Sstevel@tonic-gate 	}
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(keystorepath, sbuf)) {
630*0Sstevel@tonic-gate 		print_status(500, "(extract_keystore: failed to create)");
631*0Sstevel@tonic-gate 		return (B_FALSE);
632*0Sstevel@tonic-gate 	}
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	return (B_TRUE);
635*0Sstevel@tonic-gate }
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate static boolean_t
638*0Sstevel@tonic-gate mkisofs(const char *image_dir, const char *image)
639*0Sstevel@tonic-gate {
640*0Sstevel@tonic-gate 	struct stat	sbuf;
641*0Sstevel@tonic-gate 	int		chars;
642*0Sstevel@tonic-gate 	char		cmd[MAXPATHLEN];
643*0Sstevel@tonic-gate 	FILE		*fp;
644*0Sstevel@tonic-gate 	int		status;
645*0Sstevel@tonic-gate 	char		msg[WBCGI_MAXBUF];
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	if (!WBCGI_DIR_EXISTS(image_dir, sbuf)) {
648*0Sstevel@tonic-gate 		print_status(500, "(mksiofs: missing image_dir)");
649*0Sstevel@tonic-gate 		return (B_FALSE);
650*0Sstevel@tonic-gate 	}
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 	if ((chars = snprintf(cmd, sizeof (cmd), "%s -quiet -o %s -r %s",
653*0Sstevel@tonic-gate 	    WBCGI_MKISOFS_PATH, image, image_dir)) < 0 ||
654*0Sstevel@tonic-gate 	    chars > sizeof (cmd)) {
655*0Sstevel@tonic-gate 		print_status(500, "(mkisofs: buffer overflow)");
656*0Sstevel@tonic-gate 		return (B_FALSE);
657*0Sstevel@tonic-gate 	}
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	if ((fp = popen(cmd, "w")) == NULL) {
660*0Sstevel@tonic-gate 		print_status(500, "(mkisofs: missing/file error)");
661*0Sstevel@tonic-gate 		return (B_FALSE);
662*0Sstevel@tonic-gate 	}
663*0Sstevel@tonic-gate 	if ((status = WEXITSTATUS(pclose(fp))) != 0) {
664*0Sstevel@tonic-gate 		(void) snprintf(msg, sizeof (msg),
665*0Sstevel@tonic-gate 		    "(mkisofs: failed, status=%d)", status);
666*0Sstevel@tonic-gate 		print_status(500, msg);
667*0Sstevel@tonic-gate 		return (B_FALSE);
668*0Sstevel@tonic-gate 	}
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(image, sbuf)) {
671*0Sstevel@tonic-gate 		print_status(500, "(mksiofs: failed to create image)");
672*0Sstevel@tonic-gate 		return (B_FALSE);
673*0Sstevel@tonic-gate 	}
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 	return (B_TRUE);
676*0Sstevel@tonic-gate }
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate /*
679*0Sstevel@tonic-gate  * This function, when invoked with a file name, optional network and
680*0Sstevel@tonic-gate  * client * ID strings, and callback function will walk the directory
681*0Sstevel@tonic-gate  * hierarchy between the concatenation of NB_NETBOOT_ROOT, the network
682*0Sstevel@tonic-gate  * number, and client ID, invoking the callback function each time it
683*0Sstevel@tonic-gate  * finds a file with the specified name until the hierarchy walk
684*0Sstevel@tonic-gate  * terminates or the callback function returns a value other than
685*0Sstevel@tonic-gate  * WBCGI_FTW_CBCONT.
686*0Sstevel@tonic-gate  *
687*0Sstevel@tonic-gate  * Arguments:
688*0Sstevel@tonic-gate  *	filename - Name of file to search for.
689*0Sstevel@tonic-gate  *	net      - Optional network number to include in search hierarchy.
690*0Sstevel@tonic-gate  *	cid      - Optional client ID to include in search hierarchy.
691*0Sstevel@tonic-gate  *	cb       - Callback function to be called when file is found.
692*0Sstevel@tonic-gate  *	arg	 - Argument to be supplied to the callback funtion.
693*0Sstevel@tonic-gate  *
694*0Sstevel@tonic-gate  * Returns:
695*0Sstevel@tonic-gate  *	WBCGI_FTW_DONE, WBCGI_FTW_CBOK or WBCGI_FTW_CBERR.
696*0Sstevel@tonic-gate  */
697*0Sstevel@tonic-gate static int
698*0Sstevel@tonic-gate netboot_ftw(const char *filename, const char *net, const char *cid,
699*0Sstevel@tonic-gate     int (*cb)(const char *, void *arg), void *arg)
700*0Sstevel@tonic-gate {
701*0Sstevel@tonic-gate 	char		ckpath[MAXPATHLEN];
702*0Sstevel@tonic-gate 	char		*ptr;
703*0Sstevel@tonic-gate 	int		ret;
704*0Sstevel@tonic-gate 	struct		stat buf;
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 	/*
707*0Sstevel@tonic-gate 	 * All searches start at the root.
708*0Sstevel@tonic-gate 	 */
709*0Sstevel@tonic-gate 	if (strlcpy(ckpath, NB_NETBOOT_ROOT,
710*0Sstevel@tonic-gate 	    sizeof (ckpath)) >= sizeof (ckpath)) {
711*0Sstevel@tonic-gate 		return (WBCGI_FTW_CBERR);
712*0Sstevel@tonic-gate 	}
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 	/*
715*0Sstevel@tonic-gate 	 * Remaining part of path depends on 'net' and 'cid'. Note that
716*0Sstevel@tonic-gate 	 * it is not valid to have a NULL 'net', but non-NULL 'cid'.
717*0Sstevel@tonic-gate 	 */
718*0Sstevel@tonic-gate 	if (net == NULL && cid != NULL) {
719*0Sstevel@tonic-gate 		return (WBCGI_FTW_CBERR);
720*0Sstevel@tonic-gate 	}
721*0Sstevel@tonic-gate 	if (net != NULL) {
722*0Sstevel@tonic-gate 		if (strlcat(ckpath, net, sizeof (ckpath)) >= sizeof (ckpath) ||
723*0Sstevel@tonic-gate 		    strlcat(ckpath, "/", sizeof (ckpath)) >= sizeof (ckpath)) {
724*0Sstevel@tonic-gate 			return (WBCGI_FTW_CBERR);
725*0Sstevel@tonic-gate 		}
726*0Sstevel@tonic-gate 	}
727*0Sstevel@tonic-gate 	if (cid != NULL) {
728*0Sstevel@tonic-gate 		if (strlcat(ckpath, cid, sizeof (ckpath)) >= sizeof (ckpath) ||
729*0Sstevel@tonic-gate 		    strlcat(ckpath, "/", sizeof (ckpath)) >= sizeof (ckpath)) {
730*0Sstevel@tonic-gate 			return (WBCGI_FTW_CBERR);
731*0Sstevel@tonic-gate 		}
732*0Sstevel@tonic-gate 	}
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate 	/*
735*0Sstevel@tonic-gate 	 * Loop through hierarchy and check for file existence.
736*0Sstevel@tonic-gate 	 */
737*0Sstevel@tonic-gate 	for (;;) {
738*0Sstevel@tonic-gate 		if (strlcat(ckpath, filename,
739*0Sstevel@tonic-gate 		    sizeof (ckpath)) >= sizeof (ckpath)) {
740*0Sstevel@tonic-gate 			return (WBCGI_FTW_CBERR);
741*0Sstevel@tonic-gate 		}
742*0Sstevel@tonic-gate 		if (WBCGI_FILE_EXISTS(ckpath, buf)) {
743*0Sstevel@tonic-gate 			if ((ret = cb(ckpath, arg)) != WBCGI_FTW_CBCONT) {
744*0Sstevel@tonic-gate 				return (ret);
745*0Sstevel@tonic-gate 			}
746*0Sstevel@tonic-gate 		}
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate 		/*
749*0Sstevel@tonic-gate 		 * Remove last component (which would be the
750*0Sstevel@tonic-gate 		 * filename). If this leaves the root, then
751*0Sstevel@tonic-gate 		 * hierarchy search has been completed. Otherwise,
752*0Sstevel@tonic-gate 		 * remove the trailing directory and go try again.
753*0Sstevel@tonic-gate 		 */
754*0Sstevel@tonic-gate 		ptr = strrchr(ckpath, '/');
755*0Sstevel@tonic-gate 		*++ptr = '\0';
756*0Sstevel@tonic-gate 		if (strcmp(NB_NETBOOT_ROOT, ckpath) == 0) {
757*0Sstevel@tonic-gate 			return (WBCGI_FTW_DONE);
758*0Sstevel@tonic-gate 		} else {
759*0Sstevel@tonic-gate 			*--ptr = '\0';
760*0Sstevel@tonic-gate 			ptr = strrchr(ckpath, '/');
761*0Sstevel@tonic-gate 			*++ptr = '\0';
762*0Sstevel@tonic-gate 		}
763*0Sstevel@tonic-gate 	}
764*0Sstevel@tonic-gate }
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate /*ARGSUSED*/
767*0Sstevel@tonic-gate static int
768*0Sstevel@tonic-gate noact_cb(const char *path, void *arg)
769*0Sstevel@tonic-gate {
770*0Sstevel@tonic-gate 	return (WBCGI_FTW_CBOK);
771*0Sstevel@tonic-gate }
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate static int
774*0Sstevel@tonic-gate set_pathname(const char *path, void *pathname)
775*0Sstevel@tonic-gate {
776*0Sstevel@tonic-gate 	*(char **)pathname = strdup((char *)path);
777*0Sstevel@tonic-gate 	return (WBCGI_FTW_CBOK);
778*0Sstevel@tonic-gate }
779*0Sstevel@tonic-gate 
780*0Sstevel@tonic-gate static int
781*0Sstevel@tonic-gate create_keystore(const char *path, void *keystorepath)
782*0Sstevel@tonic-gate {
783*0Sstevel@tonic-gate 	if (!extract_keystore(path, (char *)keystorepath)) {
784*0Sstevel@tonic-gate 		return (WBCGI_FTW_CBERR);
785*0Sstevel@tonic-gate 	}
786*0Sstevel@tonic-gate 	return (WBCGI_FTW_CBOK);
787*0Sstevel@tonic-gate }
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate static int
790*0Sstevel@tonic-gate copy_certstore(const char *path, void *certstorepath)
791*0Sstevel@tonic-gate {
792*0Sstevel@tonic-gate 	if (!copy_file(path, (char *)certstorepath)) {
793*0Sstevel@tonic-gate 		return (WBCGI_FTW_CBERR);
794*0Sstevel@tonic-gate 	}
795*0Sstevel@tonic-gate 	return (WBCGI_FTW_CBOK);
796*0Sstevel@tonic-gate }
797*0Sstevel@tonic-gate 
798*0Sstevel@tonic-gate /*
799*0Sstevel@tonic-gate  * Add the certs found in the trustfile found in path (a trust store) to
800*0Sstevel@tonic-gate  * the file found at bootfs_dir/truststore.  If necessary, create the
801*0Sstevel@tonic-gate  * output file.
802*0Sstevel@tonic-gate  */
803*0Sstevel@tonic-gate static int
804*0Sstevel@tonic-gate build_trustfile(const char *path, void *truststorepath)
805*0Sstevel@tonic-gate {
806*0Sstevel@tonic-gate 	int		ret = WBCGI_FTW_CBERR;
807*0Sstevel@tonic-gate 	STACK_OF(X509)	*i_anchors = NULL;
808*0Sstevel@tonic-gate 	STACK_OF(X509)	*o_anchors = NULL;
809*0Sstevel@tonic-gate 	char		message[WBCGI_MAXBUF];
810*0Sstevel@tonic-gate 	PKCS12		*p12 = NULL;
811*0Sstevel@tonic-gate 	FILE		*rfp = NULL;
812*0Sstevel@tonic-gate 	FILE		*wfp = NULL;
813*0Sstevel@tonic-gate 	struct stat	i_st;
814*0Sstevel@tonic-gate 	struct stat	o_st;
815*0Sstevel@tonic-gate 	X509		*x = NULL;
816*0Sstevel@tonic-gate 	int		errtype = 0;
817*0Sstevel@tonic-gate 	int		wfd = -1;
818*0Sstevel@tonic-gate 	int		chars;
819*0Sstevel@tonic-gate 	int		i;
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(path, i_st)) {
822*0Sstevel@tonic-gate 		goto cleanup;
823*0Sstevel@tonic-gate 	}
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 	if (WBCGI_FILE_EXISTS((char *)truststorepath, o_st)) {
826*0Sstevel@tonic-gate 		/*
827*0Sstevel@tonic-gate 		 * If we are inadvertantly writing to the input file.
828*0Sstevel@tonic-gate 		 * return success.
829*0Sstevel@tonic-gate 		 * XXX Pete: how can this happen, and why success?
830*0Sstevel@tonic-gate 		 */
831*0Sstevel@tonic-gate 		if (i_st.st_ino == o_st.st_ino) {
832*0Sstevel@tonic-gate 			ret = WBCGI_FTW_CBCONT;
833*0Sstevel@tonic-gate 			goto cleanup;
834*0Sstevel@tonic-gate 		}
835*0Sstevel@tonic-gate 		if ((wfp = fopen((char *)truststorepath, "r+")) == NULL) {
836*0Sstevel@tonic-gate 			goto cleanup;
837*0Sstevel@tonic-gate 		}
838*0Sstevel@tonic-gate 		/*
839*0Sstevel@tonic-gate 		 * Read what's already there, so that new information
840*0Sstevel@tonic-gate 		 * can be added.
841*0Sstevel@tonic-gate 		 */
842*0Sstevel@tonic-gate 		if ((p12 = d2i_PKCS12_fp(wfp, NULL)) == NULL) {
843*0Sstevel@tonic-gate 			errtype = 1;
844*0Sstevel@tonic-gate 			goto cleanup;
845*0Sstevel@tonic-gate 		}
846*0Sstevel@tonic-gate 		i = sunw_PKCS12_parse(p12, WANBOOT_PASSPHRASE, DO_NONE, NULL,
847*0Sstevel@tonic-gate 		    0, NULL, NULL, NULL, &o_anchors);
848*0Sstevel@tonic-gate 		if (i <= 0) {
849*0Sstevel@tonic-gate 			errtype = 1;
850*0Sstevel@tonic-gate 			goto cleanup;
851*0Sstevel@tonic-gate 		}
852*0Sstevel@tonic-gate 
853*0Sstevel@tonic-gate 		PKCS12_free(p12);
854*0Sstevel@tonic-gate 		p12 = NULL;
855*0Sstevel@tonic-gate 	} else {
856*0Sstevel@tonic-gate 		if (errno != ENOENT) {
857*0Sstevel@tonic-gate 			chars = snprintf(message, sizeof (message),
858*0Sstevel@tonic-gate 			    "(error accessing file %s, error %s)",
859*0Sstevel@tonic-gate 			    path, strerror(errno));
860*0Sstevel@tonic-gate 			if (chars > 0 && chars < sizeof (message))
861*0Sstevel@tonic-gate 				print_status(500, message);
862*0Sstevel@tonic-gate 			else
863*0Sstevel@tonic-gate 				print_status(500, NULL);
864*0Sstevel@tonic-gate 			return (WBCGI_FTW_CBERR);
865*0Sstevel@tonic-gate 		}
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate 		/*
868*0Sstevel@tonic-gate 		 * Note: We could copy the file to the new trustfile, but
869*0Sstevel@tonic-gate 		 * we can't verify the password that way.  Therefore, copy
870*0Sstevel@tonic-gate 		 * it by reading it.
871*0Sstevel@tonic-gate 		 */
872*0Sstevel@tonic-gate 		if ((wfd = open((char *)truststorepath,
873*0Sstevel@tonic-gate 		    O_CREAT|O_EXCL|O_RDWR, 0700)) < 0) {
874*0Sstevel@tonic-gate 			goto cleanup;
875*0Sstevel@tonic-gate 		}
876*0Sstevel@tonic-gate 		if ((wfp = fdopen(wfd, "w+")) == NULL) {
877*0Sstevel@tonic-gate 			goto cleanup;
878*0Sstevel@tonic-gate 		}
879*0Sstevel@tonic-gate 		o_anchors = sk_X509_new_null();
880*0Sstevel@tonic-gate 		if (o_anchors == NULL) {
881*0Sstevel@tonic-gate 			goto cleanup;
882*0Sstevel@tonic-gate 		}
883*0Sstevel@tonic-gate 	}
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 	if ((rfp = fopen(path, "r")) == NULL) {
886*0Sstevel@tonic-gate 		goto cleanup;
887*0Sstevel@tonic-gate 	}
888*0Sstevel@tonic-gate 	if ((p12 = d2i_PKCS12_fp(rfp, NULL)) == NULL) {
889*0Sstevel@tonic-gate 		errtype = 1;
890*0Sstevel@tonic-gate 		goto cleanup;
891*0Sstevel@tonic-gate 	}
892*0Sstevel@tonic-gate 	i = sunw_PKCS12_parse(p12, WANBOOT_PASSPHRASE, DO_NONE, NULL, 0, NULL,
893*0Sstevel@tonic-gate 	    NULL, NULL, &i_anchors);
894*0Sstevel@tonic-gate 	if (i <= 0) {
895*0Sstevel@tonic-gate 		errtype = 1;
896*0Sstevel@tonic-gate 		goto cleanup;
897*0Sstevel@tonic-gate 	}
898*0Sstevel@tonic-gate 	PKCS12_free(p12);
899*0Sstevel@tonic-gate 	p12 = NULL;
900*0Sstevel@tonic-gate 
901*0Sstevel@tonic-gate 	/*
902*0Sstevel@tonic-gate 	 * Merge the two stacks of pkcs12 certs.
903*0Sstevel@tonic-gate 	 */
904*0Sstevel@tonic-gate 	for (i = 0; i < sk_X509_num(i_anchors); i++) {
905*0Sstevel@tonic-gate 		/* LINTED */
906*0Sstevel@tonic-gate 		x = sk_X509_delete(i_anchors, i);
907*0Sstevel@tonic-gate 		(void) sk_X509_push(o_anchors, x);
908*0Sstevel@tonic-gate 	}
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 	/*
911*0Sstevel@tonic-gate 	 * Create the pkcs12 structure from the modified input stack and
912*0Sstevel@tonic-gate 	 * then write out that structure.
913*0Sstevel@tonic-gate 	 */
914*0Sstevel@tonic-gate 	p12 = sunw_PKCS12_create((const char *)WANBOOT_PASSPHRASE, NULL, NULL,
915*0Sstevel@tonic-gate 	    o_anchors);
916*0Sstevel@tonic-gate 	if (p12 == NULL) {
917*0Sstevel@tonic-gate 		goto cleanup;
918*0Sstevel@tonic-gate 	}
919*0Sstevel@tonic-gate 	rewind(wfp);
920*0Sstevel@tonic-gate 	if (i2d_PKCS12_fp(wfp, p12) == 0) {
921*0Sstevel@tonic-gate 		goto cleanup;
922*0Sstevel@tonic-gate 	}
923*0Sstevel@tonic-gate 
924*0Sstevel@tonic-gate 	ret = WBCGI_FTW_CBCONT;
925*0Sstevel@tonic-gate cleanup:
926*0Sstevel@tonic-gate 	if (ret == WBCGI_FTW_CBERR) {
927*0Sstevel@tonic-gate 		if (errtype == 1) {
928*0Sstevel@tonic-gate 			chars = snprintf(message, sizeof (message),
929*0Sstevel@tonic-gate 			    "(internal PKCS12 error while copying %s to %s)",
930*0Sstevel@tonic-gate 			    path, (char *)truststorepath);
931*0Sstevel@tonic-gate 		} else {
932*0Sstevel@tonic-gate 			chars = snprintf(message, sizeof (message),
933*0Sstevel@tonic-gate 			    "(error copying %s to %s)",
934*0Sstevel@tonic-gate 			    path, (char *)truststorepath);
935*0Sstevel@tonic-gate 		}
936*0Sstevel@tonic-gate 		if (chars > 0 && chars <= sizeof (message)) {
937*0Sstevel@tonic-gate 			print_status(500, message);
938*0Sstevel@tonic-gate 		} else {
939*0Sstevel@tonic-gate 			print_status(500, NULL);
940*0Sstevel@tonic-gate 		}
941*0Sstevel@tonic-gate 	}
942*0Sstevel@tonic-gate 	if (rfp != NULL) {
943*0Sstevel@tonic-gate 		(void) fclose(rfp);
944*0Sstevel@tonic-gate 	}
945*0Sstevel@tonic-gate 	if (wfp != NULL) {
946*0Sstevel@tonic-gate 		/* Will also close wfd */
947*0Sstevel@tonic-gate 		(void) fclose(wfp);
948*0Sstevel@tonic-gate 	}
949*0Sstevel@tonic-gate 	if (p12 != NULL) {
950*0Sstevel@tonic-gate 		PKCS12_free(p12);
951*0Sstevel@tonic-gate 	}
952*0Sstevel@tonic-gate 	if (i_anchors != NULL) {
953*0Sstevel@tonic-gate 		sk_X509_pop_free(i_anchors, X509_free);
954*0Sstevel@tonic-gate 	}
955*0Sstevel@tonic-gate 	if (o_anchors != NULL) {
956*0Sstevel@tonic-gate 		sk_X509_pop_free(o_anchors, X509_free);
957*0Sstevel@tonic-gate 	}
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 	return (ret);
960*0Sstevel@tonic-gate }
961*0Sstevel@tonic-gate 
962*0Sstevel@tonic-gate static boolean_t
963*0Sstevel@tonic-gate check_key_type(const char *keyfile, const char *keytype, int flag)
964*0Sstevel@tonic-gate {
965*0Sstevel@tonic-gate 	boolean_t	ret = B_FALSE;
966*0Sstevel@tonic-gate 	FILE		*key_fp = NULL;
967*0Sstevel@tonic-gate 	wbku_key_attr_t	ka;
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate 	/*
970*0Sstevel@tonic-gate 	 * Map keytype into the ka structure
971*0Sstevel@tonic-gate 	 */
972*0Sstevel@tonic-gate 	if (wbku_str_to_keyattr(keytype, &ka, flag) != WBKU_SUCCESS) {
973*0Sstevel@tonic-gate 		goto cleanup;
974*0Sstevel@tonic-gate 	}
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate 	/*
977*0Sstevel@tonic-gate 	 * Open the key file for reading.
978*0Sstevel@tonic-gate 	 */
979*0Sstevel@tonic-gate 	if ((key_fp = fopen(keyfile, "r")) == NULL) {
980*0Sstevel@tonic-gate 		goto cleanup;
981*0Sstevel@tonic-gate 	}
982*0Sstevel@tonic-gate 
983*0Sstevel@tonic-gate 	/*
984*0Sstevel@tonic-gate 	 * Find the valid client key, if it exists.
985*0Sstevel@tonic-gate 	 */
986*0Sstevel@tonic-gate 	if (wbku_find_key(key_fp, NULL, &ka, NULL, B_FALSE) != WBKU_SUCCESS) {
987*0Sstevel@tonic-gate 		goto cleanup;
988*0Sstevel@tonic-gate 	}
989*0Sstevel@tonic-gate 
990*0Sstevel@tonic-gate 	ret = B_TRUE;
991*0Sstevel@tonic-gate cleanup:
992*0Sstevel@tonic-gate 	if (key_fp != NULL) {
993*0Sstevel@tonic-gate 		(void) fclose(key_fp);
994*0Sstevel@tonic-gate 	}
995*0Sstevel@tonic-gate 
996*0Sstevel@tonic-gate 	return (ret);
997*0Sstevel@tonic-gate }
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate static boolean_t
1000*0Sstevel@tonic-gate resolve_hostname(const char *hostname, nvlist_t *nvl, boolean_t may_be_crap)
1001*0Sstevel@tonic-gate {
1002*0Sstevel@tonic-gate 	struct sockaddr_in	sin;
1003*0Sstevel@tonic-gate 	struct hostent		*hp;
1004*0Sstevel@tonic-gate 
1005*0Sstevel@tonic-gate 	if (((hp = gethostbyname(hostname)) == NULL) ||
1006*0Sstevel@tonic-gate 	    (hp->h_addrtype != AF_INET) ||
1007*0Sstevel@tonic-gate 	    (hp->h_length != sizeof (struct in_addr))) {
1008*0Sstevel@tonic-gate 		if (!may_be_crap) {
1009*0Sstevel@tonic-gate 			print_status(500, "(error resolving hostname)");
1010*0Sstevel@tonic-gate 		}
1011*0Sstevel@tonic-gate 		return (may_be_crap);
1012*0Sstevel@tonic-gate 	}
1013*0Sstevel@tonic-gate 	(void) memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
1014*0Sstevel@tonic-gate 
1015*0Sstevel@tonic-gate 	if (nvlist_add_string(nvl,
1016*0Sstevel@tonic-gate 	    (char *)hostname, inet_ntoa(sin.sin_addr)) != 0) {
1017*0Sstevel@tonic-gate 		print_status(500, "(error adding hostname to nvlist)");
1018*0Sstevel@tonic-gate 		return (B_FALSE);
1019*0Sstevel@tonic-gate 	}
1020*0Sstevel@tonic-gate 
1021*0Sstevel@tonic-gate 	return (B_TRUE);
1022*0Sstevel@tonic-gate }
1023*0Sstevel@tonic-gate 
1024*0Sstevel@tonic-gate /*
1025*0Sstevel@tonic-gate  * one_name() is called for each certificate found and is passed the string
1026*0Sstevel@tonic-gate  * that X509_NAME_oneline() returns.  Its job is to find the common name and
1027*0Sstevel@tonic-gate  * determine whether it is a host name; if it is then a line suitable for
1028*0Sstevel@tonic-gate  * inclusion in /etc/inet/hosts is written to that file.
1029*0Sstevel@tonic-gate  */
1030*0Sstevel@tonic-gate static boolean_t
1031*0Sstevel@tonic-gate one_name(const char *namestr, nvlist_t *nvl)
1032*0Sstevel@tonic-gate {
1033*0Sstevel@tonic-gate 	boolean_t	ret = B_TRUE;
1034*0Sstevel@tonic-gate 	char		*p;
1035*0Sstevel@tonic-gate 	char		*q;
1036*0Sstevel@tonic-gate 	char		c;
1037*0Sstevel@tonic-gate 
1038*0Sstevel@tonic-gate 	if (namestr != NULL &&
1039*0Sstevel@tonic-gate 	    (p = strstr(namestr, WBCGI_CNSTR)) != NULL) {
1040*0Sstevel@tonic-gate 		p += WBCGI_CNSTR_LEN;
1041*0Sstevel@tonic-gate 
1042*0Sstevel@tonic-gate 		if ((q = strpbrk(p, WBCGI_NAMESEP)) != NULL) {
1043*0Sstevel@tonic-gate 			c = *q;
1044*0Sstevel@tonic-gate 			*q = '\0';
1045*0Sstevel@tonic-gate 			ret = resolve_hostname(p, nvl, B_TRUE);
1046*0Sstevel@tonic-gate 			*q = c;
1047*0Sstevel@tonic-gate 		} else {
1048*0Sstevel@tonic-gate 			ret = resolve_hostname(p, nvl, B_TRUE);
1049*0Sstevel@tonic-gate 		}
1050*0Sstevel@tonic-gate 	}
1051*0Sstevel@tonic-gate 
1052*0Sstevel@tonic-gate 	return (ret);
1053*0Sstevel@tonic-gate }
1054*0Sstevel@tonic-gate 
1055*0Sstevel@tonic-gate /*
1056*0Sstevel@tonic-gate  * Loop through the certificates in a file
1057*0Sstevel@tonic-gate  */
1058*0Sstevel@tonic-gate static int
1059*0Sstevel@tonic-gate get_hostnames(const char *path, void *nvl)
1060*0Sstevel@tonic-gate {
1061*0Sstevel@tonic-gate 	int		ret = WBCGI_FTW_CBERR;
1062*0Sstevel@tonic-gate 	STACK_OF(X509)	*certs = NULL;
1063*0Sstevel@tonic-gate 	PKCS12		*p12 = NULL;
1064*0Sstevel@tonic-gate 	char		message[WBCGI_MAXBUF];
1065*0Sstevel@tonic-gate 	char		buf[WBCGI_MAXBUF + 1];
1066*0Sstevel@tonic-gate 	FILE		*rfp = NULL;
1067*0Sstevel@tonic-gate 	X509		*x = NULL;
1068*0Sstevel@tonic-gate 	int		errtype = 0;
1069*0Sstevel@tonic-gate 	int		chars;
1070*0Sstevel@tonic-gate 	int		i;
1071*0Sstevel@tonic-gate 
1072*0Sstevel@tonic-gate 	if ((rfp = fopen(path, "r")) == NULL) {
1073*0Sstevel@tonic-gate 		goto cleanup;
1074*0Sstevel@tonic-gate 	}
1075*0Sstevel@tonic-gate 
1076*0Sstevel@tonic-gate 	if ((p12 = d2i_PKCS12_fp(rfp, NULL)) == NULL) {
1077*0Sstevel@tonic-gate 		errtype = 1;
1078*0Sstevel@tonic-gate 		goto cleanup;
1079*0Sstevel@tonic-gate 	}
1080*0Sstevel@tonic-gate 	i = sunw_PKCS12_parse(p12, WANBOOT_PASSPHRASE, DO_NONE, NULL, 0, NULL,
1081*0Sstevel@tonic-gate 	    NULL, NULL, &certs);
1082*0Sstevel@tonic-gate 	if (i <= 0) {
1083*0Sstevel@tonic-gate 		errtype = 1;
1084*0Sstevel@tonic-gate 		goto cleanup;
1085*0Sstevel@tonic-gate 	}
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 	PKCS12_free(p12);
1088*0Sstevel@tonic-gate 	p12 = NULL;
1089*0Sstevel@tonic-gate 
1090*0Sstevel@tonic-gate 	for (i = 0; i < sk_X509_num(certs); i++) {
1091*0Sstevel@tonic-gate 		/* LINTED */
1092*0Sstevel@tonic-gate 		x = sk_X509_value(certs, i);
1093*0Sstevel@tonic-gate 		if (!one_name(sunw_issuer_attrs(x, buf, sizeof (buf) - 1),
1094*0Sstevel@tonic-gate 		    nvl)) {
1095*0Sstevel@tonic-gate 			goto cleanup;
1096*0Sstevel@tonic-gate 		}
1097*0Sstevel@tonic-gate 	}
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate 	ret = WBCGI_FTW_CBCONT;
1100*0Sstevel@tonic-gate cleanup:
1101*0Sstevel@tonic-gate 	if (ret == WBCGI_FTW_CBERR) {
1102*0Sstevel@tonic-gate 		if (errtype == 1) {
1103*0Sstevel@tonic-gate 			chars = snprintf(message, sizeof (message),
1104*0Sstevel@tonic-gate 			    "(internal PKCS12 error reading %s)", path);
1105*0Sstevel@tonic-gate 		} else {
1106*0Sstevel@tonic-gate 			chars = snprintf(message, sizeof (message),
1107*0Sstevel@tonic-gate 			    "error reading %s", path);
1108*0Sstevel@tonic-gate 		}
1109*0Sstevel@tonic-gate 		if (chars > 0 && chars <= sizeof (message)) {
1110*0Sstevel@tonic-gate 			print_status(500, message);
1111*0Sstevel@tonic-gate 		} else {
1112*0Sstevel@tonic-gate 			print_status(500, NULL);
1113*0Sstevel@tonic-gate 		}
1114*0Sstevel@tonic-gate 	}
1115*0Sstevel@tonic-gate 	if (rfp != NULL) {
1116*0Sstevel@tonic-gate 		(void) fclose(rfp);
1117*0Sstevel@tonic-gate 	}
1118*0Sstevel@tonic-gate 	if (p12 != NULL) {
1119*0Sstevel@tonic-gate 		PKCS12_free(p12);
1120*0Sstevel@tonic-gate 	}
1121*0Sstevel@tonic-gate 	if (certs != NULL) {
1122*0Sstevel@tonic-gate 		sk_X509_pop_free(certs, X509_free);
1123*0Sstevel@tonic-gate 	}
1124*0Sstevel@tonic-gate 
1125*0Sstevel@tonic-gate 	return (ret);
1126*0Sstevel@tonic-gate }
1127*0Sstevel@tonic-gate 
1128*0Sstevel@tonic-gate /*
1129*0Sstevel@tonic-gate  * Create a hosts file by extracting hosts from client and truststore
1130*0Sstevel@tonic-gate  * files.  Use the CN. Then we should copy that file to the inet dir.
1131*0Sstevel@tonic-gate  */
1132*0Sstevel@tonic-gate static boolean_t
1133*0Sstevel@tonic-gate create_hostsfile(const char *hostsfile, const char *net, const char *cid)
1134*0Sstevel@tonic-gate {
1135*0Sstevel@tonic-gate 	boolean_t	ret = B_FALSE;
1136*0Sstevel@tonic-gate 	nvlist_t	*nvl;
1137*0Sstevel@tonic-gate 	nvpair_t	*nvp;
1138*0Sstevel@tonic-gate 	FILE		*hostfp = NULL;
1139*0Sstevel@tonic-gate 	int		hostfd = -1;
1140*0Sstevel@tonic-gate 	int		i;
1141*0Sstevel@tonic-gate 	char		*hostslist;
1142*0Sstevel@tonic-gate 	const char	*bc_urls[] = { BC_ROOT_SERVER, BC_BOOT_LOGGER, NULL };
1143*0Sstevel@tonic-gate 
1144*0Sstevel@tonic-gate 	/*
1145*0Sstevel@tonic-gate 	 * Allocate nvlist handle to store our hostname/IP pairs.
1146*0Sstevel@tonic-gate 	 */
1147*0Sstevel@tonic-gate 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
1148*0Sstevel@tonic-gate 		print_status(500, "(error allocating hostname nvlist)");
1149*0Sstevel@tonic-gate 		goto cleanup;
1150*0Sstevel@tonic-gate 	}
1151*0Sstevel@tonic-gate 
1152*0Sstevel@tonic-gate 	/*
1153*0Sstevel@tonic-gate 	 * Extract and resolve hostnames from CNs.
1154*0Sstevel@tonic-gate 	 */
1155*0Sstevel@tonic-gate 	if (netboot_ftw(NB_CLIENT_CERT, net, cid,
1156*0Sstevel@tonic-gate 	    get_hostnames, nvl) == WBCGI_FTW_CBERR ||
1157*0Sstevel@tonic-gate 	    netboot_ftw(NB_CA_CERT, net, cid,
1158*0Sstevel@tonic-gate 	    get_hostnames, nvl) == WBCGI_FTW_CBERR) {
1159*0Sstevel@tonic-gate 		goto cleanup;
1160*0Sstevel@tonic-gate 	}
1161*0Sstevel@tonic-gate 
1162*0Sstevel@tonic-gate 	/*
1163*0Sstevel@tonic-gate 	 * Extract and resolve hostnames from any URLs in bootconf.
1164*0Sstevel@tonic-gate 	 */
1165*0Sstevel@tonic-gate 	for (i = 0; bc_urls[i] != NULL; ++i) {
1166*0Sstevel@tonic-gate 		char	*urlstr;
1167*0Sstevel@tonic-gate 		url_t	url;
1168*0Sstevel@tonic-gate 
1169*0Sstevel@tonic-gate 		if ((urlstr = bootconf_get(&bc_handle, bc_urls[i])) != NULL &&
1170*0Sstevel@tonic-gate 		    url_parse(urlstr, &url) == URL_PARSE_SUCCESS) {
1171*0Sstevel@tonic-gate 			if (!resolve_hostname(url.hport.hostname,
1172*0Sstevel@tonic-gate 			    nvl, B_FALSE)) {
1173*0Sstevel@tonic-gate 				goto cleanup;
1174*0Sstevel@tonic-gate 			}
1175*0Sstevel@tonic-gate 		}
1176*0Sstevel@tonic-gate 	}
1177*0Sstevel@tonic-gate 
1178*0Sstevel@tonic-gate 	/*
1179*0Sstevel@tonic-gate 	 * If there is a resolve-hosts list in bootconf, resolve those
1180*0Sstevel@tonic-gate 	 * hostnames too.
1181*0Sstevel@tonic-gate 	 */
1182*0Sstevel@tonic-gate 	if ((hostslist = bootconf_get(&bc_handle, BC_RESOLVE_HOSTS)) != NULL) {
1183*0Sstevel@tonic-gate 		char	*hostname;
1184*0Sstevel@tonic-gate 
1185*0Sstevel@tonic-gate 		for (hostname = strtok(hostslist, ","); hostname != NULL;
1186*0Sstevel@tonic-gate 		    hostname = strtok(NULL, ",")) {
1187*0Sstevel@tonic-gate 			if (!resolve_hostname(hostname, nvl, B_FALSE)) {
1188*0Sstevel@tonic-gate 				goto cleanup;
1189*0Sstevel@tonic-gate 			}
1190*0Sstevel@tonic-gate 		}
1191*0Sstevel@tonic-gate 	}
1192*0Sstevel@tonic-gate 
1193*0Sstevel@tonic-gate 	/*
1194*0Sstevel@tonic-gate 	 * Now write the hostname/IP pairs gathered to the hosts file.
1195*0Sstevel@tonic-gate 	 */
1196*0Sstevel@tonic-gate 	if ((hostfd = open(hostsfile,
1197*0Sstevel@tonic-gate 	    O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
1198*0Sstevel@tonic-gate 	    (hostfp = fdopen(hostfd, "w+")) == NULL) {
1199*0Sstevel@tonic-gate 		print_status(500, "(error creating hosts file)");
1200*0Sstevel@tonic-gate 		goto cleanup;
1201*0Sstevel@tonic-gate 	}
1202*0Sstevel@tonic-gate 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
1203*0Sstevel@tonic-gate 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
1204*0Sstevel@tonic-gate 		char	*hostname;
1205*0Sstevel@tonic-gate 		char	*ipstr;
1206*0Sstevel@tonic-gate 
1207*0Sstevel@tonic-gate 		hostname = nvpair_name(nvp);
1208*0Sstevel@tonic-gate 		if (nvpair_value_string(nvp, &ipstr) != 0) {
1209*0Sstevel@tonic-gate 			print_status(500, "(nvl error writing hosts file)");
1210*0Sstevel@tonic-gate 			goto cleanup;
1211*0Sstevel@tonic-gate 		}
1212*0Sstevel@tonic-gate 
1213*0Sstevel@tonic-gate 		if (fprintf(hostfp, "%s\t%s\n", ipstr, hostname) < 0) {
1214*0Sstevel@tonic-gate 			print_status(500, "(error writing hosts file)");
1215*0Sstevel@tonic-gate 			goto cleanup;
1216*0Sstevel@tonic-gate 		}
1217*0Sstevel@tonic-gate 	}
1218*0Sstevel@tonic-gate 
1219*0Sstevel@tonic-gate 	ret = B_TRUE;
1220*0Sstevel@tonic-gate cleanup:
1221*0Sstevel@tonic-gate 	if (nvl != NULL) {
1222*0Sstevel@tonic-gate 		nvlist_free(nvl);
1223*0Sstevel@tonic-gate 	}
1224*0Sstevel@tonic-gate 	if (hostfp != NULL) {
1225*0Sstevel@tonic-gate 		/*
1226*0Sstevel@tonic-gate 		 * hostfd is automatically closed as well.
1227*0Sstevel@tonic-gate 		 */
1228*0Sstevel@tonic-gate 		(void) fclose(hostfp);
1229*0Sstevel@tonic-gate 	}
1230*0Sstevel@tonic-gate 
1231*0Sstevel@tonic-gate 	return (ret);
1232*0Sstevel@tonic-gate }
1233*0Sstevel@tonic-gate 
1234*0Sstevel@tonic-gate static boolean_t
1235*0Sstevel@tonic-gate bootfile_payload(const char *docroot, char **bootpathp)
1236*0Sstevel@tonic-gate {
1237*0Sstevel@tonic-gate 	boolean_t	ret = B_FALSE;
1238*0Sstevel@tonic-gate 	char		*boot_file;
1239*0Sstevel@tonic-gate 	struct stat	sbuf;
1240*0Sstevel@tonic-gate 
1241*0Sstevel@tonic-gate 	if ((boot_file = bootconf_get(&bc_handle, BC_BOOT_FILE)) == NULL) {
1242*0Sstevel@tonic-gate 		print_status(500, "(boot_file must be specified)");
1243*0Sstevel@tonic-gate 		goto cleanup;
1244*0Sstevel@tonic-gate 	}
1245*0Sstevel@tonic-gate 	if ((*bootpathp = make_path(docroot, boot_file)) == NULL) {
1246*0Sstevel@tonic-gate 		goto cleanup;
1247*0Sstevel@tonic-gate 	}
1248*0Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(*bootpathp, sbuf)) {
1249*0Sstevel@tonic-gate 		print_status(500, "(boot_file missing)");
1250*0Sstevel@tonic-gate 		goto cleanup;
1251*0Sstevel@tonic-gate 	}
1252*0Sstevel@tonic-gate 
1253*0Sstevel@tonic-gate 	ret = B_TRUE;
1254*0Sstevel@tonic-gate cleanup:
1255*0Sstevel@tonic-gate 	return (ret);
1256*0Sstevel@tonic-gate }
1257*0Sstevel@tonic-gate 
1258*0Sstevel@tonic-gate /*
1259*0Sstevel@tonic-gate  * Create the wanboot file system whose contents are determined by the
1260*0Sstevel@tonic-gate  * security configuration specified in bootconf.
1261*0Sstevel@tonic-gate  */
1262*0Sstevel@tonic-gate static boolean_t
1263*0Sstevel@tonic-gate wanbootfs_payload(const char *net, const char *cid, const char *nonce,
1264*0Sstevel@tonic-gate     const char *bootconf, char **wanbootfs_imagep)
1265*0Sstevel@tonic-gate {
1266*0Sstevel@tonic-gate 	int		ret = B_FALSE;
1267*0Sstevel@tonic-gate 
1268*0Sstevel@tonic-gate 	char		*server_authentication;
1269*0Sstevel@tonic-gate 	char		*client_authentication;
1270*0Sstevel@tonic-gate 	char		*scf;
1271*0Sstevel@tonic-gate 
1272*0Sstevel@tonic-gate 	char		*bootfs_dir = NULL;
1273*0Sstevel@tonic-gate 	char		*bootfs_etc_dir = NULL;
1274*0Sstevel@tonic-gate 	char		*bootfs_etc_inet_dir = NULL;
1275*0Sstevel@tonic-gate 	char		*bootfs_dev_dir = NULL;
1276*0Sstevel@tonic-gate 
1277*0Sstevel@tonic-gate 	char		*systemconf = NULL;
1278*0Sstevel@tonic-gate 	char		*keystorepath = NULL;
1279*0Sstevel@tonic-gate 	char		*certstorepath = NULL;
1280*0Sstevel@tonic-gate 	char		*truststorepath = NULL;
1281*0Sstevel@tonic-gate 	char		*bootconfpath = NULL;
1282*0Sstevel@tonic-gate 	char		*systemconfpath = NULL;
1283*0Sstevel@tonic-gate 	char		*urandompath = NULL;
1284*0Sstevel@tonic-gate 	char		*noncepath = NULL;
1285*0Sstevel@tonic-gate 	char		*hostspath = NULL;
1286*0Sstevel@tonic-gate 	char		*etc_hostspath = NULL;
1287*0Sstevel@tonic-gate 	char		*timestamppath = NULL;
1288*0Sstevel@tonic-gate 
1289*0Sstevel@tonic-gate 	boolean_t	authenticate_client;
1290*0Sstevel@tonic-gate 	boolean_t	authenticate_server;
1291*0Sstevel@tonic-gate 
1292*0Sstevel@tonic-gate 	struct stat	sbuf;
1293*0Sstevel@tonic-gate 
1294*0Sstevel@tonic-gate 	/*
1295*0Sstevel@tonic-gate 	 * Initialize SSL stuff.
1296*0Sstevel@tonic-gate 	 */
1297*0Sstevel@tonic-gate 	sunw_crypto_init();
1298*0Sstevel@tonic-gate 
1299*0Sstevel@tonic-gate 	/*
1300*0Sstevel@tonic-gate 	 * Get the security strategy values.
1301*0Sstevel@tonic-gate 	 */
1302*0Sstevel@tonic-gate 	client_authentication = bootconf_get(&bc_handle,
1303*0Sstevel@tonic-gate 	    BC_CLIENT_AUTHENTICATION);
1304*0Sstevel@tonic-gate 	authenticate_client = (client_authentication != NULL &&
1305*0Sstevel@tonic-gate 	    strcmp(client_authentication, "yes") == 0);
1306*0Sstevel@tonic-gate 	server_authentication = bootconf_get(&bc_handle,
1307*0Sstevel@tonic-gate 	    BC_SERVER_AUTHENTICATION);
1308*0Sstevel@tonic-gate 	authenticate_server = (server_authentication != NULL &&
1309*0Sstevel@tonic-gate 	    strcmp(server_authentication, "yes") == 0);
1310*0Sstevel@tonic-gate 
1311*0Sstevel@tonic-gate 	/*
1312*0Sstevel@tonic-gate 	 * Make a temporary directory structure for the wanboot file system.
1313*0Sstevel@tonic-gate 	 */
1314*0Sstevel@tonic-gate 	if ((bootfs_dir = gen_tmppath("bootfs_dir", net, cid)) == NULL ||
1315*0Sstevel@tonic-gate 	    (bootfs_etc_dir = make_path(bootfs_dir, "etc")) == NULL ||
1316*0Sstevel@tonic-gate 	    (bootfs_etc_inet_dir = make_path(bootfs_etc_dir, "inet")) == NULL ||
1317*0Sstevel@tonic-gate 	    (bootfs_dev_dir = make_path(bootfs_dir, "dev")) == NULL) {
1318*0Sstevel@tonic-gate 		goto cleanup;
1319*0Sstevel@tonic-gate 	}
1320*0Sstevel@tonic-gate 	if (mkdirp(bootfs_dir, 0700) ||
1321*0Sstevel@tonic-gate 	    mkdirp(bootfs_etc_dir, 0700) ||
1322*0Sstevel@tonic-gate 	    mkdirp(bootfs_etc_inet_dir, 0700) ||
1323*0Sstevel@tonic-gate 	    mkdirp(bootfs_dev_dir, 0700)) {
1324*0Sstevel@tonic-gate 		print_status(500, "(error creating wanbootfs dir structure)");
1325*0Sstevel@tonic-gate 		goto cleanup;
1326*0Sstevel@tonic-gate 	}
1327*0Sstevel@tonic-gate 
1328*0Sstevel@tonic-gate 	if (authenticate_client) {
1329*0Sstevel@tonic-gate 		/*
1330*0Sstevel@tonic-gate 		 * Add the client private key.
1331*0Sstevel@tonic-gate 		 */
1332*0Sstevel@tonic-gate 		if ((keystorepath = make_path(bootfs_dir,
1333*0Sstevel@tonic-gate 		    NB_CLIENT_KEY)) == NULL ||
1334*0Sstevel@tonic-gate 		    netboot_ftw(NB_CLIENT_KEY, net, cid,
1335*0Sstevel@tonic-gate 		    create_keystore, keystorepath) != WBCGI_FTW_CBOK) {
1336*0Sstevel@tonic-gate 			goto cleanup;
1337*0Sstevel@tonic-gate 		}
1338*0Sstevel@tonic-gate 
1339*0Sstevel@tonic-gate 		/*
1340*0Sstevel@tonic-gate 		 * Add the client certificate.
1341*0Sstevel@tonic-gate 		 */
1342*0Sstevel@tonic-gate 		if ((certstorepath = make_path(bootfs_dir,
1343*0Sstevel@tonic-gate 		    NB_CLIENT_CERT)) == NULL ||
1344*0Sstevel@tonic-gate 		    netboot_ftw(NB_CLIENT_CERT, net, cid,
1345*0Sstevel@tonic-gate 		    copy_certstore, certstorepath) != WBCGI_FTW_CBOK) {
1346*0Sstevel@tonic-gate 			goto cleanup;
1347*0Sstevel@tonic-gate 		}
1348*0Sstevel@tonic-gate 	}
1349*0Sstevel@tonic-gate 
1350*0Sstevel@tonic-gate 	if (authenticate_client || authenticate_server) {
1351*0Sstevel@tonic-gate 		/*
1352*0Sstevel@tonic-gate 		 * Add the trustfile; at least one truststore must exist.
1353*0Sstevel@tonic-gate 		 */
1354*0Sstevel@tonic-gate 		if ((truststorepath = make_path(bootfs_dir,
1355*0Sstevel@tonic-gate 		    NB_CA_CERT)) == NULL) {
1356*0Sstevel@tonic-gate 			goto cleanup;
1357*0Sstevel@tonic-gate 		}
1358*0Sstevel@tonic-gate 		if (netboot_ftw(NB_CA_CERT, net, cid,
1359*0Sstevel@tonic-gate 		    noact_cb, NULL) != WBCGI_FTW_CBOK) {
1360*0Sstevel@tonic-gate 			print_status(500, "(truststore not found)");
1361*0Sstevel@tonic-gate 		}
1362*0Sstevel@tonic-gate 		if (netboot_ftw(NB_CA_CERT, net, cid,
1363*0Sstevel@tonic-gate 			build_trustfile, truststorepath) == WBCGI_FTW_CBERR) {
1364*0Sstevel@tonic-gate 			goto cleanup;
1365*0Sstevel@tonic-gate 		}
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 		/*
1368*0Sstevel@tonic-gate 		 * Create the /dev/urandom file.
1369*0Sstevel@tonic-gate 		 */
1370*0Sstevel@tonic-gate 		if ((urandompath = make_path(bootfs_dev_dir,
1371*0Sstevel@tonic-gate 		    "urandom")) == NULL ||
1372*0Sstevel@tonic-gate 		    !create_urandom(urandompath)) {
1373*0Sstevel@tonic-gate 			goto cleanup;
1374*0Sstevel@tonic-gate 		}
1375*0Sstevel@tonic-gate 	}
1376*0Sstevel@tonic-gate 
1377*0Sstevel@tonic-gate 	/*
1378*0Sstevel@tonic-gate 	 * Add the wanboot.conf(4) file.
1379*0Sstevel@tonic-gate 	 */
1380*0Sstevel@tonic-gate 	if ((bootconfpath = make_path(bootfs_dir, NB_WANBOOT_CONF)) == NULL ||
1381*0Sstevel@tonic-gate 	    !copy_file(bootconf, bootconfpath)) {
1382*0Sstevel@tonic-gate 		goto cleanup;
1383*0Sstevel@tonic-gate 	}
1384*0Sstevel@tonic-gate 
1385*0Sstevel@tonic-gate 	/*
1386*0Sstevel@tonic-gate 	 * Add the system_conf file if present.
1387*0Sstevel@tonic-gate 	 */
1388*0Sstevel@tonic-gate 	if ((scf = bootconf_get(&bc_handle, BC_SYSTEM_CONF)) != NULL) {
1389*0Sstevel@tonic-gate 		if (netboot_ftw(scf, net, cid,
1390*0Sstevel@tonic-gate 		    set_pathname, &systemconf) != WBCGI_FTW_CBOK) {
1391*0Sstevel@tonic-gate 			print_status(500, "(system_conf file not found)");
1392*0Sstevel@tonic-gate 			goto cleanup;
1393*0Sstevel@tonic-gate 		}
1394*0Sstevel@tonic-gate 		if ((systemconfpath = make_path(bootfs_dir,
1395*0Sstevel@tonic-gate 		    NB_SYSTEM_CONF)) == NULL ||
1396*0Sstevel@tonic-gate 		    !copy_file(systemconf, systemconfpath)) {
1397*0Sstevel@tonic-gate 			goto cleanup;
1398*0Sstevel@tonic-gate 		}
1399*0Sstevel@tonic-gate 	}
1400*0Sstevel@tonic-gate 
1401*0Sstevel@tonic-gate 	/*
1402*0Sstevel@tonic-gate 	 * Create the /nonce file.
1403*0Sstevel@tonic-gate 	 */
1404*0Sstevel@tonic-gate 	if ((noncepath = make_path(bootfs_dir, "nonce")) == NULL ||
1405*0Sstevel@tonic-gate 	    !create_nonce(noncepath, nonce)) {
1406*0Sstevel@tonic-gate 		goto cleanup;
1407*0Sstevel@tonic-gate 	}
1408*0Sstevel@tonic-gate 
1409*0Sstevel@tonic-gate 	/*
1410*0Sstevel@tonic-gate 	 * Create an /etc/inet/hosts file by extracting hostnames from CN,
1411*0Sstevel@tonic-gate 	 * URLs in bootconf and resolve-hosts in bootconf.
1412*0Sstevel@tonic-gate 	 */
1413*0Sstevel@tonic-gate 	if ((hostspath = make_path(bootfs_etc_inet_dir, "hosts")) == NULL ||
1414*0Sstevel@tonic-gate 	    !create_hostsfile(hostspath, net, cid)) {
1415*0Sstevel@tonic-gate 		goto cleanup;
1416*0Sstevel@tonic-gate 	}
1417*0Sstevel@tonic-gate 
1418*0Sstevel@tonic-gate 	/*
1419*0Sstevel@tonic-gate 	 * We would like to create a symbolic link etc/hosts -> etc/inet/hosts,
1420*0Sstevel@tonic-gate 	 * but unfortunately the HSFS support in the standalone doesn't handle
1421*0Sstevel@tonic-gate 	 * symlinks.
1422*0Sstevel@tonic-gate 	 */
1423*0Sstevel@tonic-gate 	if ((etc_hostspath = make_path(bootfs_etc_dir, "hosts")) == NULL ||
1424*0Sstevel@tonic-gate 	    !copy_file(hostspath, etc_hostspath)) {
1425*0Sstevel@tonic-gate 		goto cleanup;
1426*0Sstevel@tonic-gate 	}
1427*0Sstevel@tonic-gate 
1428*0Sstevel@tonic-gate 	/*
1429*0Sstevel@tonic-gate 	 * Create the /timestamp file.
1430*0Sstevel@tonic-gate 	 */
1431*0Sstevel@tonic-gate 	if ((timestamppath = make_path(bootfs_dir, "timestamp")) == NULL ||
1432*0Sstevel@tonic-gate 	    !create_timestamp(timestamppath, "timestamp")) {
1433*0Sstevel@tonic-gate 		goto cleanup;
1434*0Sstevel@tonic-gate 	}
1435*0Sstevel@tonic-gate 
1436*0Sstevel@tonic-gate 	/*
1437*0Sstevel@tonic-gate 	 * Create an HSFS file system for the directory.
1438*0Sstevel@tonic-gate 	 */
1439*0Sstevel@tonic-gate 	if ((*wanbootfs_imagep = gen_tmppath("wanbootfs", net, cid)) == NULL ||
1440*0Sstevel@tonic-gate 	    !mkisofs(bootfs_dir, *wanbootfs_imagep)) {
1441*0Sstevel@tonic-gate 		goto cleanup;
1442*0Sstevel@tonic-gate 	}
1443*0Sstevel@tonic-gate 
1444*0Sstevel@tonic-gate 	ret = B_TRUE;
1445*0Sstevel@tonic-gate cleanup:
1446*0Sstevel@tonic-gate 	/*
1447*0Sstevel@tonic-gate 	 * Clean up temporary files and directories.
1448*0Sstevel@tonic-gate 	 */
1449*0Sstevel@tonic-gate 	if (keystorepath != NULL &&
1450*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(keystorepath, sbuf)) {
1451*0Sstevel@tonic-gate 		(void) unlink(keystorepath);
1452*0Sstevel@tonic-gate 	}
1453*0Sstevel@tonic-gate 	if (certstorepath != NULL &&
1454*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(certstorepath, sbuf)) {
1455*0Sstevel@tonic-gate 		(void) unlink(certstorepath);
1456*0Sstevel@tonic-gate 	}
1457*0Sstevel@tonic-gate 	if (truststorepath != NULL &&
1458*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(truststorepath, sbuf)) {
1459*0Sstevel@tonic-gate 		(void) unlink(truststorepath);
1460*0Sstevel@tonic-gate 	}
1461*0Sstevel@tonic-gate 	if (bootconfpath != NULL &&
1462*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(bootconfpath, sbuf)) {
1463*0Sstevel@tonic-gate 		(void) unlink(bootconfpath);
1464*0Sstevel@tonic-gate 	}
1465*0Sstevel@tonic-gate 	if (systemconfpath != NULL &&
1466*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(systemconfpath, sbuf)) {
1467*0Sstevel@tonic-gate 		(void) unlink(systemconfpath);
1468*0Sstevel@tonic-gate 	}
1469*0Sstevel@tonic-gate 	if (urandompath != NULL &&
1470*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(urandompath, sbuf)) {
1471*0Sstevel@tonic-gate 		(void) unlink(urandompath);
1472*0Sstevel@tonic-gate 	}
1473*0Sstevel@tonic-gate 	if (noncepath != NULL &&
1474*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(noncepath, sbuf)) {
1475*0Sstevel@tonic-gate 		(void) unlink(noncepath);
1476*0Sstevel@tonic-gate 	}
1477*0Sstevel@tonic-gate 	if (hostspath != NULL &&
1478*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(hostspath, sbuf)) {
1479*0Sstevel@tonic-gate 		(void) unlink(hostspath);
1480*0Sstevel@tonic-gate 	}
1481*0Sstevel@tonic-gate 	if (etc_hostspath != NULL &&
1482*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(etc_hostspath, sbuf)) {
1483*0Sstevel@tonic-gate 		(void) unlink(etc_hostspath);
1484*0Sstevel@tonic-gate 	}
1485*0Sstevel@tonic-gate 	if (timestamppath != NULL &&
1486*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(timestamppath, sbuf)) {
1487*0Sstevel@tonic-gate 		(void) unlink(timestamppath);
1488*0Sstevel@tonic-gate 	}
1489*0Sstevel@tonic-gate 
1490*0Sstevel@tonic-gate 	if (bootfs_etc_inet_dir != NULL &&
1491*0Sstevel@tonic-gate 	    WBCGI_DIR_EXISTS(bootfs_etc_inet_dir, sbuf)) {
1492*0Sstevel@tonic-gate 		(void) rmdir(bootfs_etc_inet_dir);
1493*0Sstevel@tonic-gate 	}
1494*0Sstevel@tonic-gate 	if (bootfs_etc_dir != NULL &&
1495*0Sstevel@tonic-gate 	    WBCGI_DIR_EXISTS(bootfs_etc_dir, sbuf)) {
1496*0Sstevel@tonic-gate 		(void) rmdir(bootfs_etc_dir);
1497*0Sstevel@tonic-gate 	}
1498*0Sstevel@tonic-gate 	if (bootfs_dev_dir != NULL &&
1499*0Sstevel@tonic-gate 	    WBCGI_DIR_EXISTS(bootfs_dev_dir, sbuf)) {
1500*0Sstevel@tonic-gate 		(void) rmdir(bootfs_dev_dir);
1501*0Sstevel@tonic-gate 	}
1502*0Sstevel@tonic-gate 	if (bootfs_dir != NULL &&
1503*0Sstevel@tonic-gate 	    WBCGI_DIR_EXISTS(bootfs_dir, sbuf)) {
1504*0Sstevel@tonic-gate 		(void) rmdir(bootfs_dir);
1505*0Sstevel@tonic-gate 	}
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate 	/*
1508*0Sstevel@tonic-gate 	 * Free allocated memory.
1509*0Sstevel@tonic-gate 	 */
1510*0Sstevel@tonic-gate 	free_path(&bootfs_dir);
1511*0Sstevel@tonic-gate 	free_path(&bootfs_etc_dir);
1512*0Sstevel@tonic-gate 	free_path(&bootfs_etc_inet_dir);
1513*0Sstevel@tonic-gate 	free_path(&bootfs_dev_dir);
1514*0Sstevel@tonic-gate 
1515*0Sstevel@tonic-gate 	free_path(&systemconf);
1516*0Sstevel@tonic-gate 	free_path(&keystorepath);
1517*0Sstevel@tonic-gate 	free_path(&certstorepath);
1518*0Sstevel@tonic-gate 	free_path(&truststorepath);
1519*0Sstevel@tonic-gate 	free_path(&bootconfpath);
1520*0Sstevel@tonic-gate 	free_path(&systemconfpath);
1521*0Sstevel@tonic-gate 	free_path(&urandompath);
1522*0Sstevel@tonic-gate 	free_path(&noncepath);
1523*0Sstevel@tonic-gate 	free_path(&hostspath);
1524*0Sstevel@tonic-gate 	free_path(&etc_hostspath);
1525*0Sstevel@tonic-gate 	free_path(&timestamppath);
1526*0Sstevel@tonic-gate 
1527*0Sstevel@tonic-gate 	return (ret);
1528*0Sstevel@tonic-gate }
1529*0Sstevel@tonic-gate 
1530*0Sstevel@tonic-gate static boolean_t
1531*0Sstevel@tonic-gate miniroot_payload(const char *net, const char *cid, const char *docroot,
1532*0Sstevel@tonic-gate     char **rootpathp, char **rootinfop, boolean_t *https_rootserverp)
1533*0Sstevel@tonic-gate {
1534*0Sstevel@tonic-gate 	boolean_t	ret = B_FALSE;
1535*0Sstevel@tonic-gate 	char		*root_server;
1536*0Sstevel@tonic-gate 	char		*root_file;
1537*0Sstevel@tonic-gate 	url_t		url;
1538*0Sstevel@tonic-gate 	struct stat	sbuf;
1539*0Sstevel@tonic-gate 	char		sizebuf[WBCGI_MAXBUF];
1540*0Sstevel@tonic-gate 	int		chars;
1541*0Sstevel@tonic-gate 	int		fd = -1;
1542*0Sstevel@tonic-gate 
1543*0Sstevel@tonic-gate 	if ((root_server = bootconf_get(&bc_handle, BC_ROOT_SERVER)) == NULL) {
1544*0Sstevel@tonic-gate 		print_status(500, "(root_server must be specified)");
1545*0Sstevel@tonic-gate 		goto cleanup;
1546*0Sstevel@tonic-gate 	}
1547*0Sstevel@tonic-gate 	if (url_parse(root_server, &url) != URL_PARSE_SUCCESS) {
1548*0Sstevel@tonic-gate 		print_status(500, "(root_server URL is invalid)");
1549*0Sstevel@tonic-gate 	}
1550*0Sstevel@tonic-gate 	*https_rootserverp = url.https;
1551*0Sstevel@tonic-gate 
1552*0Sstevel@tonic-gate 	if ((root_file = bootconf_get(&bc_handle, BC_ROOT_FILE)) == NULL) {
1553*0Sstevel@tonic-gate 		print_status(500, "(rootfile must be specified)");
1554*0Sstevel@tonic-gate 		goto cleanup;
1555*0Sstevel@tonic-gate 	}
1556*0Sstevel@tonic-gate 	if ((*rootpathp = make_path(docroot, root_file)) == NULL) {
1557*0Sstevel@tonic-gate 		goto cleanup;
1558*0Sstevel@tonic-gate 	}
1559*0Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(*rootpathp, sbuf)) {
1560*0Sstevel@tonic-gate 		print_status(500, "(root filesystem image missing)");
1561*0Sstevel@tonic-gate 		goto cleanup;
1562*0Sstevel@tonic-gate 	}
1563*0Sstevel@tonic-gate 
1564*0Sstevel@tonic-gate 	if ((*rootinfop = gen_tmppath("mrinfo", net, cid)) == NULL) {
1565*0Sstevel@tonic-gate 		goto cleanup;
1566*0Sstevel@tonic-gate 	}
1567*0Sstevel@tonic-gate 	if ((chars = snprintf(sizebuf, sizeof (sizebuf), "%ld",
1568*0Sstevel@tonic-gate 	    sbuf.st_size)) < 0 || chars > sizeof (sizebuf) ||
1569*0Sstevel@tonic-gate 	    (fd = open(*rootinfop,
1570*0Sstevel@tonic-gate 	    O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
1571*0Sstevel@tonic-gate 	    !write_buffer(fd, sizebuf, strlen(sizebuf))) {
1572*0Sstevel@tonic-gate 		print_status(500, "(error creating miniroot info file)");
1573*0Sstevel@tonic-gate 		goto cleanup;
1574*0Sstevel@tonic-gate 	}
1575*0Sstevel@tonic-gate 
1576*0Sstevel@tonic-gate 	ret = B_TRUE;
1577*0Sstevel@tonic-gate cleanup:
1578*0Sstevel@tonic-gate 	if (fd != -1) {
1579*0Sstevel@tonic-gate 		(void) close(fd);
1580*0Sstevel@tonic-gate 	}
1581*0Sstevel@tonic-gate 
1582*0Sstevel@tonic-gate 	return (ret);
1583*0Sstevel@tonic-gate }
1584*0Sstevel@tonic-gate 
1585*0Sstevel@tonic-gate static boolean_t
1586*0Sstevel@tonic-gate deliver_payload(const char *payload, const char *payload_hash)
1587*0Sstevel@tonic-gate {
1588*0Sstevel@tonic-gate 	int		fd = fileno(stdout);
1589*0Sstevel@tonic-gate 	struct stat	payload_buf, hash_buf;
1590*0Sstevel@tonic-gate 	int		chars;
1591*0Sstevel@tonic-gate 	char		main_header[WBCGI_MAXBUF];
1592*0Sstevel@tonic-gate 	char		multi_header[WBCGI_MAXBUF];
1593*0Sstevel@tonic-gate 	char		multi_header1[WBCGI_MAXBUF];
1594*0Sstevel@tonic-gate 	char		multi_header2[WBCGI_MAXBUF];
1595*0Sstevel@tonic-gate 	char		multi_end[WBCGI_MAXBUF];
1596*0Sstevel@tonic-gate 	size_t		msglen;
1597*0Sstevel@tonic-gate 
1598*0Sstevel@tonic-gate 	if (!WBCGI_FILE_EXISTS(payload, payload_buf) ||
1599*0Sstevel@tonic-gate 	    !WBCGI_FILE_EXISTS(payload_hash, hash_buf)) {
1600*0Sstevel@tonic-gate 		print_status(500, "(payload/hash file(s) missing)");
1601*0Sstevel@tonic-gate 		return (B_FALSE);
1602*0Sstevel@tonic-gate 	}
1603*0Sstevel@tonic-gate 
1604*0Sstevel@tonic-gate 	/*
1605*0Sstevel@tonic-gate 	 * Multi-part header.
1606*0Sstevel@tonic-gate 	 */
1607*0Sstevel@tonic-gate 	if ((chars = snprintf(multi_header, sizeof (multi_header),
1608*0Sstevel@tonic-gate 	    "%s--%s%s%sapplication/octet-stream%s%s", WBCGI_CRNL,
1609*0Sstevel@tonic-gate 	    WBCGI_WANBOOT_BNDTXT, WBCGI_CRNL, WBCGI_CONTENT_TYPE, WBCGI_CRNL,
1610*0Sstevel@tonic-gate 	    WBCGI_CONTENT_LENGTH)) < 0 || chars > sizeof (multi_header)) {
1611*0Sstevel@tonic-gate 		print_status(500, "(error creating multi_header)");
1612*0Sstevel@tonic-gate 		return (B_FALSE);
1613*0Sstevel@tonic-gate 	}
1614*0Sstevel@tonic-gate 
1615*0Sstevel@tonic-gate 	/*
1616*0Sstevel@tonic-gate 	 * Multi-part header for part one.
1617*0Sstevel@tonic-gate 	 */
1618*0Sstevel@tonic-gate 	if ((chars = snprintf(multi_header1, sizeof (multi_header1),
1619*0Sstevel@tonic-gate 	    "%s%ld%s%s", multi_header, payload_buf.st_size, WBCGI_CRNL,
1620*0Sstevel@tonic-gate 	    WBCGI_CRNL)) < 0 || chars > sizeof (multi_header1)) {
1621*0Sstevel@tonic-gate 		print_status(500, "(error creating multi_header1)");
1622*0Sstevel@tonic-gate 		return (B_FALSE);
1623*0Sstevel@tonic-gate 	}
1624*0Sstevel@tonic-gate 
1625*0Sstevel@tonic-gate 	/*
1626*0Sstevel@tonic-gate 	 * Multi-part header for part two.
1627*0Sstevel@tonic-gate 	 */
1628*0Sstevel@tonic-gate 	if ((chars = snprintf(multi_header2, sizeof (multi_header2),
1629*0Sstevel@tonic-gate 	    "%s%ld%s%s", multi_header, hash_buf.st_size, WBCGI_CRNL,
1630*0Sstevel@tonic-gate 	    WBCGI_CRNL)) < 0 || chars > sizeof (multi_header2)) {
1631*0Sstevel@tonic-gate 		print_status(500, "(error creating multi_header2)");
1632*0Sstevel@tonic-gate 		return (B_FALSE);
1633*0Sstevel@tonic-gate 	}
1634*0Sstevel@tonic-gate 
1635*0Sstevel@tonic-gate 	/*
1636*0Sstevel@tonic-gate 	 * End-of-parts Trailer.
1637*0Sstevel@tonic-gate 	 */
1638*0Sstevel@tonic-gate 	if ((chars = snprintf(multi_end, sizeof (multi_end),
1639*0Sstevel@tonic-gate 	    "%s--%s--%s", WBCGI_CRNL, WBCGI_WANBOOT_BNDTXT,
1640*0Sstevel@tonic-gate 	    WBCGI_CRNL)) < 0 || chars > sizeof (multi_end)) {
1641*0Sstevel@tonic-gate 		print_status(500, "(error creating multi_end)");
1642*0Sstevel@tonic-gate 		return (B_FALSE);
1643*0Sstevel@tonic-gate 	}
1644*0Sstevel@tonic-gate 
1645*0Sstevel@tonic-gate 	/*
1646*0Sstevel@tonic-gate 	 * Message header.
1647*0Sstevel@tonic-gate 	 */
1648*0Sstevel@tonic-gate 	msglen = payload_buf.st_size +  hash_buf.st_size +
1649*0Sstevel@tonic-gate 	    strlen(multi_header1) + strlen(multi_header2) + strlen(multi_end);
1650*0Sstevel@tonic-gate 
1651*0Sstevel@tonic-gate 	if ((chars = snprintf(main_header, sizeof (main_header),
1652*0Sstevel@tonic-gate 	    "%s%u%s%smultipart/mixed; boundary=%s%s%s", WBCGI_CONTENT_LENGTH,
1653*0Sstevel@tonic-gate 	    msglen, WBCGI_CRNL, WBCGI_CONTENT_TYPE, WBCGI_WANBOOT_BNDTXT,
1654*0Sstevel@tonic-gate 	    WBCGI_CRNL, WBCGI_CRNL)) < 0 || chars > sizeof (main_header)) {
1655*0Sstevel@tonic-gate 		print_status(500, "(error creating main_header)");
1656*0Sstevel@tonic-gate 		return (B_FALSE);
1657*0Sstevel@tonic-gate 	}
1658*0Sstevel@tonic-gate 
1659*0Sstevel@tonic-gate 	/*
1660*0Sstevel@tonic-gate 	 * Write the message out.  If things fall apart during this then
1661*0Sstevel@tonic-gate 	 * there's no way to report the error back to the client.
1662*0Sstevel@tonic-gate 	 */
1663*0Sstevel@tonic-gate 	if (!write_buffer(fd, main_header, strlen(main_header)) ||
1664*0Sstevel@tonic-gate 	    !write_buffer(fd, multi_header1, strlen(multi_header1)) ||
1665*0Sstevel@tonic-gate 	    !write_file(fd, payload, payload_buf.st_size) ||
1666*0Sstevel@tonic-gate 	    !write_buffer(fd, multi_header2, strlen(multi_header2)) ||
1667*0Sstevel@tonic-gate 	    !write_file(fd, payload_hash, hash_buf.st_size) ||
1668*0Sstevel@tonic-gate 	    !write_buffer(fileno(stdout), multi_end, strlen(multi_end))) {
1669*0Sstevel@tonic-gate 		return (B_FALSE);
1670*0Sstevel@tonic-gate 	}
1671*0Sstevel@tonic-gate 
1672*0Sstevel@tonic-gate 	return (B_TRUE);
1673*0Sstevel@tonic-gate }
1674*0Sstevel@tonic-gate 
1675*0Sstevel@tonic-gate 
1676*0Sstevel@tonic-gate /*ARGSUSED*/
1677*0Sstevel@tonic-gate int
1678*0Sstevel@tonic-gate main(int argc, char **argv)
1679*0Sstevel@tonic-gate {
1680*0Sstevel@tonic-gate 	int		ret = WBCGI_STATUS_ERR;
1681*0Sstevel@tonic-gate 	struct stat	sbuf;
1682*0Sstevel@tonic-gate 	int		content;
1683*0Sstevel@tonic-gate 	char		*net;
1684*0Sstevel@tonic-gate 	char		*cid;
1685*0Sstevel@tonic-gate 	char		*nonce;
1686*0Sstevel@tonic-gate 	char		*docroot;
1687*0Sstevel@tonic-gate 	char		*payload;
1688*0Sstevel@tonic-gate 	char		*signature_type;
1689*0Sstevel@tonic-gate 	char		*encryption_type;
1690*0Sstevel@tonic-gate 	char		*bootconf = NULL;
1691*0Sstevel@tonic-gate 	char		*keyfile = NULL;
1692*0Sstevel@tonic-gate 	char		*bootpath = NULL;
1693*0Sstevel@tonic-gate 	char		*wanbootfs_image = NULL;
1694*0Sstevel@tonic-gate 	char		*rootpath = NULL;
1695*0Sstevel@tonic-gate 	char		*miniroot_info = NULL;
1696*0Sstevel@tonic-gate 	char		*encr_payload = NULL;
1697*0Sstevel@tonic-gate 	char		*payload_hash = NULL;
1698*0Sstevel@tonic-gate 	boolean_t	https_rootserver;
1699*0Sstevel@tonic-gate 
1700*0Sstevel@tonic-gate 	/*
1701*0Sstevel@tonic-gate 	 * Process the query string.
1702*0Sstevel@tonic-gate 	 */
1703*0Sstevel@tonic-gate 	if (!get_request_info(&content, &net, &cid, &nonce, &docroot)) {
1704*0Sstevel@tonic-gate 		goto cleanup;
1705*0Sstevel@tonic-gate 	}
1706*0Sstevel@tonic-gate 
1707*0Sstevel@tonic-gate 	/*
1708*0Sstevel@tonic-gate 	 * Sanity check that the netboot directory exists.
1709*0Sstevel@tonic-gate 	 */
1710*0Sstevel@tonic-gate 	if (!WBCGI_DIR_EXISTS(NB_NETBOOT_ROOT, sbuf)) {
1711*0Sstevel@tonic-gate 		print_status(500, "(" NB_NETBOOT_ROOT " does not exist)");
1712*0Sstevel@tonic-gate 		goto cleanup;
1713*0Sstevel@tonic-gate 	}
1714*0Sstevel@tonic-gate 
1715*0Sstevel@tonic-gate 	/*
1716*0Sstevel@tonic-gate 	 * Get absolute bootconf pathname.
1717*0Sstevel@tonic-gate 	 */
1718*0Sstevel@tonic-gate 	if (netboot_ftw(NB_WANBOOT_CONF, net, cid,
1719*0Sstevel@tonic-gate 	    set_pathname, &bootconf) != WBCGI_FTW_CBOK) {
1720*0Sstevel@tonic-gate 		print_status(500, "(wanboot.conf not found)");
1721*0Sstevel@tonic-gate 		goto cleanup;
1722*0Sstevel@tonic-gate 	}
1723*0Sstevel@tonic-gate 
1724*0Sstevel@tonic-gate 	/*
1725*0Sstevel@tonic-gate 	 * Initialize bc_handle from the given wanboot.conf file.
1726*0Sstevel@tonic-gate 	 */
1727*0Sstevel@tonic-gate 	if (bootconf_init(&bc_handle, bootconf) != BC_SUCCESS) {
1728*0Sstevel@tonic-gate 		char	message[WBCGI_MAXBUF];
1729*0Sstevel@tonic-gate 		int	chars;
1730*0Sstevel@tonic-gate 
1731*0Sstevel@tonic-gate 		chars = snprintf(message, sizeof (message),
1732*0Sstevel@tonic-gate 		    "(wanboot.conf error: %s)", bootconf_errmsg(&bc_handle));
1733*0Sstevel@tonic-gate 		if (chars > 0 && chars < sizeof (message))
1734*0Sstevel@tonic-gate 			print_status(500, message);
1735*0Sstevel@tonic-gate 		else
1736*0Sstevel@tonic-gate 			print_status(500, "(wanboot.conf error)");
1737*0Sstevel@tonic-gate 		goto cleanup;
1738*0Sstevel@tonic-gate 	}
1739*0Sstevel@tonic-gate 
1740*0Sstevel@tonic-gate 	/*
1741*0Sstevel@tonic-gate 	 * Get and check signature and encryption types,
1742*0Sstevel@tonic-gate 	 * presence of helper utilities, keystore, etc.
1743*0Sstevel@tonic-gate 	 */
1744*0Sstevel@tonic-gate 	if ((signature_type = bootconf_get(&bc_handle,
1745*0Sstevel@tonic-gate 	    BC_SIGNATURE_TYPE)) != NULL) {
1746*0Sstevel@tonic-gate 		if (!WBCGI_FILE_EXISTS(WBCGI_HMAC_PATH, sbuf)) {
1747*0Sstevel@tonic-gate 			print_status(500, "(hmac utility not found)");
1748*0Sstevel@tonic-gate 			goto cleanup;
1749*0Sstevel@tonic-gate 		}
1750*0Sstevel@tonic-gate 		if (keyfile == NULL &&
1751*0Sstevel@tonic-gate 		    netboot_ftw(NB_CLIENT_KEY, net, cid,
1752*0Sstevel@tonic-gate 			set_pathname, &keyfile) != WBCGI_FTW_CBOK) {
1753*0Sstevel@tonic-gate 			print_status(500, "(keystore not found)");
1754*0Sstevel@tonic-gate 			goto cleanup;
1755*0Sstevel@tonic-gate 		}
1756*0Sstevel@tonic-gate 		if (!check_key_type(keyfile, signature_type, WBKU_HASH_KEY)) {
1757*0Sstevel@tonic-gate 			print_status(500, "(hash key not found)");
1758*0Sstevel@tonic-gate 			goto cleanup;
1759*0Sstevel@tonic-gate 		}
1760*0Sstevel@tonic-gate 	}
1761*0Sstevel@tonic-gate 	if ((encryption_type = bootconf_get(&bc_handle,
1762*0Sstevel@tonic-gate 	    BC_ENCRYPTION_TYPE)) != NULL) {
1763*0Sstevel@tonic-gate 		if (signature_type == NULL) {
1764*0Sstevel@tonic-gate 			print_status(500, "(encrypted but not signed)");
1765*0Sstevel@tonic-gate 			goto cleanup;
1766*0Sstevel@tonic-gate 		}
1767*0Sstevel@tonic-gate 		if (!WBCGI_FILE_EXISTS(WBCGI_ENCR_PATH, sbuf)) {
1768*0Sstevel@tonic-gate 			print_status(500, "(encr utility not found)");
1769*0Sstevel@tonic-gate 			goto cleanup;
1770*0Sstevel@tonic-gate 		}
1771*0Sstevel@tonic-gate 		if (keyfile == NULL &&
1772*0Sstevel@tonic-gate 		    netboot_ftw(NB_CLIENT_KEY, net, cid,
1773*0Sstevel@tonic-gate 			set_pathname, &keyfile) != WBCGI_FTW_CBOK) {
1774*0Sstevel@tonic-gate 			print_status(500, "(keystore not found)");
1775*0Sstevel@tonic-gate 			goto cleanup;
1776*0Sstevel@tonic-gate 		}
1777*0Sstevel@tonic-gate 		if (!check_key_type(keyfile, encryption_type, WBKU_ENCR_KEY)) {
1778*0Sstevel@tonic-gate 			print_status(500, "(encr key not found)");
1779*0Sstevel@tonic-gate 			goto cleanup;
1780*0Sstevel@tonic-gate 		}
1781*0Sstevel@tonic-gate 	}
1782*0Sstevel@tonic-gate 
1783*0Sstevel@tonic-gate 	/*
1784*0Sstevel@tonic-gate 	 * Determine/create our payload.
1785*0Sstevel@tonic-gate 	 */
1786*0Sstevel@tonic-gate 	switch (content) {
1787*0Sstevel@tonic-gate 	case WBCGI_CONTENT_BOOTFILE:
1788*0Sstevel@tonic-gate 		if (!bootfile_payload(docroot, &bootpath)) {
1789*0Sstevel@tonic-gate 			goto cleanup;
1790*0Sstevel@tonic-gate 		}
1791*0Sstevel@tonic-gate 		payload = bootpath;
1792*0Sstevel@tonic-gate 
1793*0Sstevel@tonic-gate 		break;
1794*0Sstevel@tonic-gate 
1795*0Sstevel@tonic-gate 	case WBCGI_CONTENT_BOOTFS:
1796*0Sstevel@tonic-gate 		if (!wanbootfs_payload(net, cid, nonce,
1797*0Sstevel@tonic-gate 		    bootconf, &wanbootfs_image)) {
1798*0Sstevel@tonic-gate 			goto cleanup;
1799*0Sstevel@tonic-gate 		}
1800*0Sstevel@tonic-gate 		payload = wanbootfs_image;
1801*0Sstevel@tonic-gate 
1802*0Sstevel@tonic-gate 		break;
1803*0Sstevel@tonic-gate 
1804*0Sstevel@tonic-gate 	case WBCGI_CONTENT_ROOTFS:
1805*0Sstevel@tonic-gate 		if (!miniroot_payload(net, cid, docroot,
1806*0Sstevel@tonic-gate 		    &rootpath, &miniroot_info, &https_rootserver)) {
1807*0Sstevel@tonic-gate 			goto cleanup;
1808*0Sstevel@tonic-gate 		}
1809*0Sstevel@tonic-gate 		payload = rootpath;
1810*0Sstevel@tonic-gate 
1811*0Sstevel@tonic-gate 		break;
1812*0Sstevel@tonic-gate 	}
1813*0Sstevel@tonic-gate 
1814*0Sstevel@tonic-gate 	/*
1815*0Sstevel@tonic-gate 	 * Encrypt the payload if necessary.
1816*0Sstevel@tonic-gate 	 */
1817*0Sstevel@tonic-gate 	if (content != WBCGI_CONTENT_BOOTFILE &&
1818*0Sstevel@tonic-gate 	    content != WBCGI_CONTENT_ROOTFS &&
1819*0Sstevel@tonic-gate 	    encryption_type != NULL) {
1820*0Sstevel@tonic-gate 		if ((encr_payload = gen_tmppath("encr", net, cid)) == NULL) {
1821*0Sstevel@tonic-gate 			goto cleanup;
1822*0Sstevel@tonic-gate 		}
1823*0Sstevel@tonic-gate 
1824*0Sstevel@tonic-gate 		if (!encrypt_payload(payload, encr_payload, keyfile,
1825*0Sstevel@tonic-gate 		    encryption_type)) {
1826*0Sstevel@tonic-gate 			goto cleanup;
1827*0Sstevel@tonic-gate 		}
1828*0Sstevel@tonic-gate 
1829*0Sstevel@tonic-gate 		payload = encr_payload;
1830*0Sstevel@tonic-gate 	}
1831*0Sstevel@tonic-gate 
1832*0Sstevel@tonic-gate 	/*
1833*0Sstevel@tonic-gate 	 * Compute the hash (actual or null).
1834*0Sstevel@tonic-gate 	 */
1835*0Sstevel@tonic-gate 	if ((payload_hash = gen_tmppath("hash", net, cid)) == NULL) {
1836*0Sstevel@tonic-gate 		goto cleanup;
1837*0Sstevel@tonic-gate 	}
1838*0Sstevel@tonic-gate 
1839*0Sstevel@tonic-gate 	if (signature_type != NULL &&
1840*0Sstevel@tonic-gate 	    (content != WBCGI_CONTENT_ROOTFS || !https_rootserver)) {
1841*0Sstevel@tonic-gate 		if (!hash_payload(payload, payload_hash, keyfile)) {
1842*0Sstevel@tonic-gate 			goto cleanup;
1843*0Sstevel@tonic-gate 		}
1844*0Sstevel@tonic-gate 	} else {
1845*0Sstevel@tonic-gate 		if (!create_null_hash(payload_hash)) {
1846*0Sstevel@tonic-gate 			goto cleanup;
1847*0Sstevel@tonic-gate 		}
1848*0Sstevel@tonic-gate 	}
1849*0Sstevel@tonic-gate 
1850*0Sstevel@tonic-gate 	/*
1851*0Sstevel@tonic-gate 	 * For the rootfs the actual payload transmitted is the file
1852*0Sstevel@tonic-gate 	 * containing the size of the rootfs (as a string of ascii digits);
1853*0Sstevel@tonic-gate 	 * point payload at this instead.
1854*0Sstevel@tonic-gate 	 */
1855*0Sstevel@tonic-gate 	if (content == WBCGI_CONTENT_ROOTFS) {
1856*0Sstevel@tonic-gate 		payload = miniroot_info;
1857*0Sstevel@tonic-gate 	}
1858*0Sstevel@tonic-gate 
1859*0Sstevel@tonic-gate 	/*
1860*0Sstevel@tonic-gate 	 * Finally, deliver the payload and hash as a multipart message.
1861*0Sstevel@tonic-gate 	 */
1862*0Sstevel@tonic-gate 	if (!deliver_payload(payload, payload_hash)) {
1863*0Sstevel@tonic-gate 		goto cleanup;
1864*0Sstevel@tonic-gate 	}
1865*0Sstevel@tonic-gate 
1866*0Sstevel@tonic-gate 	ret = WBCGI_STATUS_OK;
1867*0Sstevel@tonic-gate cleanup:
1868*0Sstevel@tonic-gate 	/*
1869*0Sstevel@tonic-gate 	 * Clean up temporary files.
1870*0Sstevel@tonic-gate 	 */
1871*0Sstevel@tonic-gate 	if (wanbootfs_image != NULL &&
1872*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(wanbootfs_image, sbuf)) {
1873*0Sstevel@tonic-gate 		(void) unlink(wanbootfs_image);
1874*0Sstevel@tonic-gate 	}
1875*0Sstevel@tonic-gate 	if (miniroot_info != NULL &&
1876*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(miniroot_info, sbuf)) {
1877*0Sstevel@tonic-gate 		(void) unlink(miniroot_info);
1878*0Sstevel@tonic-gate 	}
1879*0Sstevel@tonic-gate 	if (encr_payload != NULL &&
1880*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(encr_payload, sbuf)) {
1881*0Sstevel@tonic-gate 		(void) unlink(encr_payload);
1882*0Sstevel@tonic-gate 	}
1883*0Sstevel@tonic-gate 	if (payload_hash != NULL &&
1884*0Sstevel@tonic-gate 	    WBCGI_FILE_EXISTS(payload_hash, sbuf)) {
1885*0Sstevel@tonic-gate 		(void) unlink(payload_hash);
1886*0Sstevel@tonic-gate 	}
1887*0Sstevel@tonic-gate 
1888*0Sstevel@tonic-gate 	/*
1889*0Sstevel@tonic-gate 	 * Free up any allocated strings.
1890*0Sstevel@tonic-gate 	 */
1891*0Sstevel@tonic-gate 	free_path(&bootconf);
1892*0Sstevel@tonic-gate 	free_path(&keyfile);
1893*0Sstevel@tonic-gate 	free_path(&bootpath);
1894*0Sstevel@tonic-gate 	free_path(&wanbootfs_image);
1895*0Sstevel@tonic-gate 	free_path(&rootpath);
1896*0Sstevel@tonic-gate 	free_path(&miniroot_info);
1897*0Sstevel@tonic-gate 	free_path(&encr_payload);
1898*0Sstevel@tonic-gate 	free_path(&payload_hash);
1899*0Sstevel@tonic-gate 
1900*0Sstevel@tonic-gate 	bootconf_end(&bc_handle);
1901*0Sstevel@tonic-gate 
1902*0Sstevel@tonic-gate 	return (ret);
1903*0Sstevel@tonic-gate }
1904