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 * 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 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 * 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 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 * 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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(×tamppath); 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate return (ret); 15300Sstevel@tonic-gate } 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate static boolean_t 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 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 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