17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 522ce47f7SDavid Miner * Common Development and Distribution License (the "License"). 622ce47f7SDavid Miner * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2222ce47f7SDavid Miner * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 2333f5ff17SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <stdio.h> 277c478bd9Sstevel@tonic-gate #include <stdlib.h> 287c478bd9Sstevel@tonic-gate #include <strings.h> 297c478bd9Sstevel@tonic-gate #include <string.h> 307c478bd9Sstevel@tonic-gate #include <libgen.h> 317c478bd9Sstevel@tonic-gate #include <unistd.h> 327c478bd9Sstevel@tonic-gate #include <fcntl.h> 337c478bd9Sstevel@tonic-gate #include <errno.h> 347c478bd9Sstevel@tonic-gate #include <netdb.h> 357c478bd9Sstevel@tonic-gate #include <libnvpair.h> 367c478bd9Sstevel@tonic-gate #include <sys/types.h> 377c478bd9Sstevel@tonic-gate #include <sys/wait.h> 387c478bd9Sstevel@tonic-gate #include <sys/stat.h> 397c478bd9Sstevel@tonic-gate #include <sys/param.h> 407c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 417c478bd9Sstevel@tonic-gate #include <sys/mman.h> 427c478bd9Sstevel@tonic-gate #include <sys/socket.h> 4322ce47f7SDavid Miner #include <sys/utsname.h> 447c478bd9Sstevel@tonic-gate #include <sys/wanboot_impl.h> 457c478bd9Sstevel@tonic-gate #include <netinet/in.h> 467c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #include <openssl/crypto.h> 497c478bd9Sstevel@tonic-gate #include <openssl/x509.h> 507c478bd9Sstevel@tonic-gate #include <openssl/x509v3.h> 517c478bd9Sstevel@tonic-gate #include <openssl/pem.h> 527c478bd9Sstevel@tonic-gate #include <openssl/pkcs12.h> 537c478bd9Sstevel@tonic-gate #include <openssl/evp.h> 547c478bd9Sstevel@tonic-gate #include <openssl/err.h> 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate #include <p12aux.h> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #include <parseURL.h> 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * These can be replaced with wanbootutil.h once the openssl interfaces 617c478bd9Sstevel@tonic-gate * are moved to libwanboot. 627c478bd9Sstevel@tonic-gate */ 637c478bd9Sstevel@tonic-gate #include <wanboot/key_util.h> 647c478bd9Sstevel@tonic-gate #include <wanboot/key_xdr.h> 657c478bd9Sstevel@tonic-gate #include <hmac_sha1.h> 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate #include <netboot_paths.h> 687c478bd9Sstevel@tonic-gate #include <wanboot_conf.h> 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /* 717c478bd9Sstevel@tonic-gate * Exit status: 727c478bd9Sstevel@tonic-gate */ 737c478bd9Sstevel@tonic-gate #define WBCGI_STATUS_OK 0 747c478bd9Sstevel@tonic-gate #define WBCGI_STATUS_ERR 1 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate #define WBCGI_FILE_EXISTS(file, statbuf) \ 777c478bd9Sstevel@tonic-gate (stat(file, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate #define WBCGI_DIR_EXISTS(dir, statbuf) \ 807c478bd9Sstevel@tonic-gate (stat(dir, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate #define WBCGI_HMAC_PATH "/usr/lib/inet/wanboot/hmac" 837c478bd9Sstevel@tonic-gate #define WBCGI_ENCR_PATH "/usr/lib/inet/wanboot/encr" 847c478bd9Sstevel@tonic-gate #define WBCGI_KEYMGMT_PATH "/usr/lib/inet/wanboot/keymgmt" 857c478bd9Sstevel@tonic-gate #define WBCGI_MKISOFS_PATH "/bin/mkisofs" 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate #define WBCGI_DEV_URANDOM "/dev/urandom" 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate #define WBCGI_CONTENT_TYPE "Content-Type: " 907c478bd9Sstevel@tonic-gate #define WBCGI_CONTENT_LENGTH "Content-Length: " 917c478bd9Sstevel@tonic-gate #define WBCGI_WANBOOT_BNDTXT "WANBoot_Part_Boundary" 927c478bd9Sstevel@tonic-gate #define WBCGI_CRNL "\r\n" 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate #define WBCGI_CNSTR "CN=" 957c478bd9Sstevel@tonic-gate #define WBCGI_CNSTR_LEN (sizeof (WBCGI_CNSTR) - 1) 967c478bd9Sstevel@tonic-gate #define WBCGI_NAMESEP ",/\n\r" 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate #define WBCGI_MAXBUF 256 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* 1017c478bd9Sstevel@tonic-gate * Possible return values from netboot_ftw(): 1027c478bd9Sstevel@tonic-gate */ 1037c478bd9Sstevel@tonic-gate #define WBCGI_FTW_CBOK 2 /* CB terminated walk OK */ 1047c478bd9Sstevel@tonic-gate #define WBCGI_FTW_CBCONT 1 /* CB wants walk should continue */ 1057c478bd9Sstevel@tonic-gate #define WBCGI_FTW_DONE 0 /* Walk terminated without CBERR/CBOK */ 1067c478bd9Sstevel@tonic-gate #define WBCGI_FTW_CBERR -1 /* CB terminated walk with err */ 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * getsubopt() is used to map one of the contents[] keywords 1107c478bd9Sstevel@tonic-gate * to one of these types 1117c478bd9Sstevel@tonic-gate */ 1127c478bd9Sstevel@tonic-gate #define WBCGI_CONTENT_ERROR -1 1137c478bd9Sstevel@tonic-gate #define WBCGI_CONTENT_BOOTFILE 0 1147c478bd9Sstevel@tonic-gate #define WBCGI_CONTENT_BOOTFS 1 1157c478bd9Sstevel@tonic-gate #define WBCGI_CONTENT_ROOTFS 2 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate static char *contents[] = 1187c478bd9Sstevel@tonic-gate { "bootfile", "bootfs", "rootfs", NULL }; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * getsubopt() is used to parse the query string for 1227c478bd9Sstevel@tonic-gate * the keywords defined by queryopts[] 1237c478bd9Sstevel@tonic-gate */ 1247c478bd9Sstevel@tonic-gate #define WBCGI_QUERYOPT_CONTENT 0 1257c478bd9Sstevel@tonic-gate #define WBCGI_QUERYOPT_NET 1 1267c478bd9Sstevel@tonic-gate #define WBCGI_QUERYOPT_CID 2 1277c478bd9Sstevel@tonic-gate #define WBCGI_QUERYOPT_NONCE 3 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate static char *queryopts[] = 1307c478bd9Sstevel@tonic-gate { "CONTENT", "IP", "CID", "NONCE", NULL }; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate static bc_handle_t bc_handle; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate static char * 1367c478bd9Sstevel@tonic-gate status_msg(int status) 1377c478bd9Sstevel@tonic-gate { 1387c478bd9Sstevel@tonic-gate char *msg; 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate switch (status) { 1417c478bd9Sstevel@tonic-gate case 400: 1427c478bd9Sstevel@tonic-gate msg = "Bad Request"; 1437c478bd9Sstevel@tonic-gate break; 1447c478bd9Sstevel@tonic-gate case 403: 1457c478bd9Sstevel@tonic-gate msg = "Forbidden"; 1467c478bd9Sstevel@tonic-gate break; 1477c478bd9Sstevel@tonic-gate case 500: 1487c478bd9Sstevel@tonic-gate msg = "Internal Server Error"; 1497c478bd9Sstevel@tonic-gate break; 1507c478bd9Sstevel@tonic-gate default: 1517c478bd9Sstevel@tonic-gate msg = "Unknown status"; 1527c478bd9Sstevel@tonic-gate break; 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate return (msg); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate static void 1597c478bd9Sstevel@tonic-gate print_status(int status, const char *spec_msg) 1607c478bd9Sstevel@tonic-gate { 1617c478bd9Sstevel@tonic-gate if (spec_msg == NULL) { 1627c478bd9Sstevel@tonic-gate spec_msg = ""; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "Status: %d %s %s%s", status, 1667c478bd9Sstevel@tonic-gate status_msg(status), spec_msg, WBCGI_CRNL); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate static char * 1707c478bd9Sstevel@tonic-gate make_path(const char *root, const char *suffix) 1717c478bd9Sstevel@tonic-gate { 1727c478bd9Sstevel@tonic-gate char path[MAXPATHLEN]; 1737c478bd9Sstevel@tonic-gate char *ptr = NULL; 1747c478bd9Sstevel@tonic-gate int chars; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate if ((chars = snprintf(path, sizeof (path), 1777c478bd9Sstevel@tonic-gate "%s/%s", root, suffix)) < 0 || chars > sizeof (path) || 1787c478bd9Sstevel@tonic-gate (ptr = strdup(path)) == NULL) { 1797c478bd9Sstevel@tonic-gate print_status(500, "(error making path)"); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate return (ptr); 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate static void 1867c478bd9Sstevel@tonic-gate free_path(char **pathp) 1877c478bd9Sstevel@tonic-gate { 1887c478bd9Sstevel@tonic-gate if (*pathp != NULL) { 1897c478bd9Sstevel@tonic-gate free(*pathp); 1907c478bd9Sstevel@tonic-gate *pathp = NULL; 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate static char * 1957c478bd9Sstevel@tonic-gate gen_tmppath(const char *prefix, const char *net, const char *cid) 1967c478bd9Sstevel@tonic-gate { 1977c478bd9Sstevel@tonic-gate pid_t pid; 1987c478bd9Sstevel@tonic-gate time_t secs; 1997c478bd9Sstevel@tonic-gate int chars; 2007c478bd9Sstevel@tonic-gate char path[MAXPATHLEN]; 2017c478bd9Sstevel@tonic-gate char *ptr = NULL; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate if ((pid = getpid()) < 0 || (secs = time(NULL)) < 0 || 2047c478bd9Sstevel@tonic-gate (chars = snprintf(path, sizeof (path), "/tmp/%s_%s_%s_%ld_%ld", 2057c478bd9Sstevel@tonic-gate prefix, net, cid, pid, secs)) < 0 || chars > sizeof (path) || 2067c478bd9Sstevel@tonic-gate (ptr = strdup(path)) == NULL) { 2077c478bd9Sstevel@tonic-gate print_status(500, "(error creating temporary filename)"); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate return (ptr); 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * File I/O stuff: 2157c478bd9Sstevel@tonic-gate */ 2167c478bd9Sstevel@tonic-gate static boolean_t 2177c478bd9Sstevel@tonic-gate write_buffer(int fd, const void *buffer, size_t buflen) 2187c478bd9Sstevel@tonic-gate { 2197c478bd9Sstevel@tonic-gate size_t nwritten; 2207c478bd9Sstevel@tonic-gate ssize_t nbytes; 2217c478bd9Sstevel@tonic-gate const char *buf = buffer; 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate for (nwritten = 0; nwritten < buflen; nwritten += nbytes) { 2247c478bd9Sstevel@tonic-gate nbytes = write(fd, &buf[nwritten], buflen - nwritten); 2257c478bd9Sstevel@tonic-gate if (nbytes <= 0) { 2267c478bd9Sstevel@tonic-gate return (B_FALSE); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate return (B_TRUE); 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate static boolean_t 2347c478bd9Sstevel@tonic-gate write_file(int ofd, const char *filename, size_t size) 2357c478bd9Sstevel@tonic-gate { 2367c478bd9Sstevel@tonic-gate boolean_t ret = B_TRUE; 2377c478bd9Sstevel@tonic-gate int ifd; 2387c478bd9Sstevel@tonic-gate char buf[1024]; 2397c478bd9Sstevel@tonic-gate size_t rlen; 2407c478bd9Sstevel@tonic-gate ssize_t wlen; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate if ((ifd = open(filename, O_RDONLY)) < 0) { 2437c478bd9Sstevel@tonic-gate return (B_FALSE); 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate for (; size != 0; size -= wlen) { 2477c478bd9Sstevel@tonic-gate rlen = (size < sizeof (buf)) ? size : sizeof (buf); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate if ((wlen = read(ifd, buf, rlen)) < 0 || 2507c478bd9Sstevel@tonic-gate !write_buffer(ofd, buf, wlen)) { 2517c478bd9Sstevel@tonic-gate ret = B_FALSE; 2527c478bd9Sstevel@tonic-gate break; 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate (void) close(ifd); 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate return (ret); 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate static boolean_t 2617c478bd9Sstevel@tonic-gate copy_file(const char *src, const char *dest) 2627c478bd9Sstevel@tonic-gate { 2637c478bd9Sstevel@tonic-gate boolean_t ret = B_FALSE; 2647c478bd9Sstevel@tonic-gate char message[WBCGI_MAXBUF]; 2657c478bd9Sstevel@tonic-gate const size_t chunksize = 16 * PAGESIZE; 2667c478bd9Sstevel@tonic-gate size_t validsize; 2677c478bd9Sstevel@tonic-gate size_t nwritten = 0; 2687c478bd9Sstevel@tonic-gate size_t nbytes = 0; 2697c478bd9Sstevel@tonic-gate off_t roff; 2707c478bd9Sstevel@tonic-gate int mflags = MAP_PRIVATE; 2717c478bd9Sstevel@tonic-gate char *buf = NULL; 2727c478bd9Sstevel@tonic-gate struct stat st; 2737c478bd9Sstevel@tonic-gate int rfd = -1; 2747c478bd9Sstevel@tonic-gate int wfd = -1; 2757c478bd9Sstevel@tonic-gate int chars; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if ((rfd = open(src, O_RDONLY)) < 0 || 2787c478bd9Sstevel@tonic-gate (wfd = open(dest, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR)) < 0 || 2797c478bd9Sstevel@tonic-gate fstat(rfd, &st) == -1) { 2807c478bd9Sstevel@tonic-gate goto cleanup; 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate for (nbytes = st.st_size, roff = 0; nwritten < nbytes; 2847c478bd9Sstevel@tonic-gate nwritten += validsize, roff += validsize) { 2857c478bd9Sstevel@tonic-gate buf = mmap(buf, chunksize, PROT_READ, mflags, rfd, roff); 2867c478bd9Sstevel@tonic-gate if (buf == MAP_FAILED) { 2877c478bd9Sstevel@tonic-gate goto cleanup; 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate mflags |= MAP_FIXED; 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate validsize = MIN(chunksize, nbytes - nwritten); 2927c478bd9Sstevel@tonic-gate if (!write_buffer(wfd, buf, validsize)) { 2937c478bd9Sstevel@tonic-gate (void) munmap(buf, chunksize); 2947c478bd9Sstevel@tonic-gate goto cleanup; 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate if (buf != NULL) { 2997c478bd9Sstevel@tonic-gate (void) munmap(buf, chunksize); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate ret = B_TRUE; 3037c478bd9Sstevel@tonic-gate cleanup: 3047c478bd9Sstevel@tonic-gate if (ret == B_FALSE) { 3057c478bd9Sstevel@tonic-gate if ((chars = snprintf(message, sizeof (message), 3067c478bd9Sstevel@tonic-gate "error copying %s to %s", src, dest)) > 0 && 3077c478bd9Sstevel@tonic-gate chars <= sizeof (message)) { 3087c478bd9Sstevel@tonic-gate print_status(500, message); 3097c478bd9Sstevel@tonic-gate } else { 3107c478bd9Sstevel@tonic-gate print_status(500, NULL); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate if (rfd != -1) { 3147c478bd9Sstevel@tonic-gate (void) close(rfd); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate if (wfd != -1) { 3177c478bd9Sstevel@tonic-gate (void) close(wfd); 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate return (ret); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate static boolean_t 3247c478bd9Sstevel@tonic-gate create_nonce(const char *noncepath, const char *nonce) 3257c478bd9Sstevel@tonic-gate { 3267c478bd9Sstevel@tonic-gate boolean_t ret = B_TRUE; 3277c478bd9Sstevel@tonic-gate int fd; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate if ((fd = open(noncepath, 3307c478bd9Sstevel@tonic-gate O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 || 3317c478bd9Sstevel@tonic-gate !write_buffer(fd, nonce, strlen(nonce))) { 3327c478bd9Sstevel@tonic-gate print_status(500, "(error creating nonce file)"); 3337c478bd9Sstevel@tonic-gate ret = B_FALSE; 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate if (fd != -1) { 3367c478bd9Sstevel@tonic-gate (void) close(fd); 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate return (ret); 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate static boolean_t 3437c478bd9Sstevel@tonic-gate create_timestamp(const char *timestamppath, const char *timestamp) 3447c478bd9Sstevel@tonic-gate { 3457c478bd9Sstevel@tonic-gate boolean_t ret = B_TRUE; 3467c478bd9Sstevel@tonic-gate int fd; 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate if ((fd = open(timestamppath, 3497c478bd9Sstevel@tonic-gate O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 || 3507c478bd9Sstevel@tonic-gate !write_buffer(fd, timestamp, strlen(timestamp))) { 3517c478bd9Sstevel@tonic-gate print_status(500, "(error creating timestamp file)"); 3527c478bd9Sstevel@tonic-gate ret = B_FALSE; 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate if (fd != -1) { 3557c478bd9Sstevel@tonic-gate (void) close(fd); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate return (ret); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate static boolean_t 3627c478bd9Sstevel@tonic-gate create_urandom(const char *urandompath) 3637c478bd9Sstevel@tonic-gate { 3647c478bd9Sstevel@tonic-gate boolean_t ret = B_TRUE; 3657c478bd9Sstevel@tonic-gate int fd; 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate if ((fd = open(urandompath, 3687c478bd9Sstevel@tonic-gate O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 || 3697c478bd9Sstevel@tonic-gate !write_file(fd, WBCGI_DEV_URANDOM, 32 * 1024)) { 3707c478bd9Sstevel@tonic-gate print_status(500, "(error creating urandom file)"); 3717c478bd9Sstevel@tonic-gate ret = B_FALSE; 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate if (fd != -1) { 3747c478bd9Sstevel@tonic-gate (void) close(fd); 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate return (ret); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate static boolean_t 3817c478bd9Sstevel@tonic-gate create_null_hash(const char *hashpath) 3827c478bd9Sstevel@tonic-gate { 3837c478bd9Sstevel@tonic-gate boolean_t ret = B_TRUE; 3847c478bd9Sstevel@tonic-gate int fd; 3857c478bd9Sstevel@tonic-gate static char null_hash[HMAC_DIGEST_LEN]; 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate if ((fd = open(hashpath, 3887c478bd9Sstevel@tonic-gate O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 || 3897c478bd9Sstevel@tonic-gate !write_buffer(fd, null_hash, sizeof (null_hash))) { 3907c478bd9Sstevel@tonic-gate print_status(500, "(error creating null hash)"); 3917c478bd9Sstevel@tonic-gate ret = B_FALSE; 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate if (fd != -1) { 3947c478bd9Sstevel@tonic-gate (void) close(fd); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate return (ret); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate static char * 4027c478bd9Sstevel@tonic-gate determine_doc_root(void) 4037c478bd9Sstevel@tonic-gate { 4047c478bd9Sstevel@tonic-gate char *doc_root; 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate /* 4077c478bd9Sstevel@tonic-gate * If DOCUMENT_ROOT is valid, use that. 4087c478bd9Sstevel@tonic-gate */ 4097c478bd9Sstevel@tonic-gate if ((doc_root = getenv("DOCUMENT_ROOT")) == NULL || 4107c478bd9Sstevel@tonic-gate strlen(doc_root) == 0) { 4117c478bd9Sstevel@tonic-gate /* 4127c478bd9Sstevel@tonic-gate * No DOCUMENT_ROOT - try PATH_TRANSLATED. 4137c478bd9Sstevel@tonic-gate */ 4147c478bd9Sstevel@tonic-gate if ((doc_root = getenv("PATH_TRANSLATED")) == NULL || 4157c478bd9Sstevel@tonic-gate strlen(doc_root) == 0) { 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * Can't determine the document root. 4187c478bd9Sstevel@tonic-gate */ 4197c478bd9Sstevel@tonic-gate return (NULL); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate return (doc_root); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate static boolean_t 4277c478bd9Sstevel@tonic-gate get_request_info(int *contentp, char **netp, char **cidp, char **noncep, 4287c478bd9Sstevel@tonic-gate char **docrootp) 4297c478bd9Sstevel@tonic-gate { 4307c478bd9Sstevel@tonic-gate char *method; 4317c478bd9Sstevel@tonic-gate char *query_string; 4327c478bd9Sstevel@tonic-gate char *value; 4337c478bd9Sstevel@tonic-gate char *junk; 4347c478bd9Sstevel@tonic-gate int i; 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate if ((method = getenv("REQUEST_METHOD")) == NULL || 4377c478bd9Sstevel@tonic-gate strncasecmp(method, "GET", strlen("GET") != 0)) { 4387c478bd9Sstevel@tonic-gate print_status(403, "(GET method expected)"); 4397c478bd9Sstevel@tonic-gate return (B_FALSE); 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate if ((query_string = getenv("QUERY_STRING")) == NULL) { 4437c478bd9Sstevel@tonic-gate print_status(400, "(empty query string)"); 4447c478bd9Sstevel@tonic-gate return (B_FALSE); 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate for (i = 0; i < strlen(query_string); i++) { 4487c478bd9Sstevel@tonic-gate if (query_string[i] == '&') { 4497c478bd9Sstevel@tonic-gate query_string[i] = ','; 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate *contentp = WBCGI_CONTENT_ERROR; 4547c478bd9Sstevel@tonic-gate *netp = *cidp = *noncep = NULL; 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate if ((*docrootp = determine_doc_root()) == NULL) { 4577c478bd9Sstevel@tonic-gate print_status(400, "(unable to determine document root)"); 4587c478bd9Sstevel@tonic-gate return (B_FALSE); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate while (*query_string != '\0') { 4627c478bd9Sstevel@tonic-gate switch (getsubopt(&query_string, queryopts, &value)) { 4637c478bd9Sstevel@tonic-gate case WBCGI_QUERYOPT_CONTENT: 4647c478bd9Sstevel@tonic-gate *contentp = getsubopt(&value, contents, &junk); 4657c478bd9Sstevel@tonic-gate break; 4667c478bd9Sstevel@tonic-gate case WBCGI_QUERYOPT_NET: 4677c478bd9Sstevel@tonic-gate *netp = value; 4687c478bd9Sstevel@tonic-gate break; 4697c478bd9Sstevel@tonic-gate case WBCGI_QUERYOPT_CID: 4707c478bd9Sstevel@tonic-gate *cidp = value; 4717c478bd9Sstevel@tonic-gate break; 4727c478bd9Sstevel@tonic-gate case WBCGI_QUERYOPT_NONCE: 4737c478bd9Sstevel@tonic-gate *noncep = value; 4747c478bd9Sstevel@tonic-gate break; 4757c478bd9Sstevel@tonic-gate default: 4767c478bd9Sstevel@tonic-gate print_status(400, "(illegal query string)"); 4777c478bd9Sstevel@tonic-gate return (B_FALSE); 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate switch (*contentp) { 4827c478bd9Sstevel@tonic-gate default: 4837c478bd9Sstevel@tonic-gate print_status(400, "(missing or illegal CONTENT)"); 4847c478bd9Sstevel@tonic-gate return (B_FALSE); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate case WBCGI_CONTENT_BOOTFS: 4877c478bd9Sstevel@tonic-gate if (*netp == NULL || *cidp == NULL || *noncep == NULL) { 4887c478bd9Sstevel@tonic-gate print_status(400, 4897c478bd9Sstevel@tonic-gate "(CONTENT, IP, CID and NONCE required)"); 4907c478bd9Sstevel@tonic-gate return (B_FALSE); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate break; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate case WBCGI_CONTENT_BOOTFILE: 4957c478bd9Sstevel@tonic-gate case WBCGI_CONTENT_ROOTFS: 4967c478bd9Sstevel@tonic-gate if (*netp == NULL || *cidp == NULL || *docrootp == NULL) { 4977c478bd9Sstevel@tonic-gate print_status(400, 4987c478bd9Sstevel@tonic-gate "(CONTENT, IP, CID and DOCUMENT_ROOT required)"); 4997c478bd9Sstevel@tonic-gate return (B_FALSE); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate break; 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate return (B_TRUE); 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate static boolean_t 5087c478bd9Sstevel@tonic-gate encrypt_payload(const char *payload, const char *encr_payload, 5097c478bd9Sstevel@tonic-gate const char *keyfile, const char *encryption_type) 5107c478bd9Sstevel@tonic-gate { 5117c478bd9Sstevel@tonic-gate struct stat sbuf; 5127c478bd9Sstevel@tonic-gate int chars; 5137c478bd9Sstevel@tonic-gate char cmd[MAXPATHLEN]; 5147c478bd9Sstevel@tonic-gate FILE *fp; 5157c478bd9Sstevel@tonic-gate int status; 5167c478bd9Sstevel@tonic-gate char msg[WBCGI_MAXBUF]; 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(payload, sbuf)) { 5197c478bd9Sstevel@tonic-gate print_status(500, "(encrypt_payload: missing payload)"); 5207c478bd9Sstevel@tonic-gate return (B_FALSE); 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate if ((chars = snprintf(cmd, sizeof (cmd), 5247c478bd9Sstevel@tonic-gate "%s -o type=%s -k %s < %s > %s", WBCGI_ENCR_PATH, 5257c478bd9Sstevel@tonic-gate encryption_type, keyfile, payload, encr_payload)) < 0 || 5267c478bd9Sstevel@tonic-gate chars > sizeof (cmd)) { 5277c478bd9Sstevel@tonic-gate print_status(500, "(encrypt_payload: buffer overflow)"); 5287c478bd9Sstevel@tonic-gate return (B_FALSE); 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate if ((fp = popen(cmd, "w")) == NULL) { 5327c478bd9Sstevel@tonic-gate print_status(500, "(encrypt_payload: missing/file error)"); 5337c478bd9Sstevel@tonic-gate return (B_FALSE); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate if ((status = WEXITSTATUS(pclose(fp))) != 0) { 5367c478bd9Sstevel@tonic-gate (void) snprintf(msg, sizeof (msg), 5377c478bd9Sstevel@tonic-gate "(encrypt_payload: failed, status=%d)", status); 5387c478bd9Sstevel@tonic-gate print_status(500, msg); 5397c478bd9Sstevel@tonic-gate return (B_FALSE); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(encr_payload, sbuf)) { 5437c478bd9Sstevel@tonic-gate print_status(500, "(encrypt_payload: bad encrypted file)"); 5447c478bd9Sstevel@tonic-gate return (B_FALSE); 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate return (B_TRUE); 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate static boolean_t 5517c478bd9Sstevel@tonic-gate hash_payload(const char *payload, const char *payload_hash, 5527c478bd9Sstevel@tonic-gate const char *keyfile) 5537c478bd9Sstevel@tonic-gate { 5547c478bd9Sstevel@tonic-gate struct stat sbuf; 5557c478bd9Sstevel@tonic-gate int chars; 5567c478bd9Sstevel@tonic-gate char cmd[MAXPATHLEN]; 5577c478bd9Sstevel@tonic-gate FILE *fp; 5587c478bd9Sstevel@tonic-gate int status; 5597c478bd9Sstevel@tonic-gate char msg[WBCGI_MAXBUF]; 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(payload, sbuf)) { 5627c478bd9Sstevel@tonic-gate print_status(500, "(hash_payload: missing payload)"); 5637c478bd9Sstevel@tonic-gate return (B_FALSE); 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate if ((chars = snprintf(cmd, sizeof (cmd), "%s -i %s -k %s > %s", 5677c478bd9Sstevel@tonic-gate WBCGI_HMAC_PATH, payload, keyfile, payload_hash)) < 0 || 5687c478bd9Sstevel@tonic-gate chars > sizeof (cmd)) { 5697c478bd9Sstevel@tonic-gate print_status(500, "(hash_payload: buffer overflow)"); 5707c478bd9Sstevel@tonic-gate return (B_FALSE); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate if ((fp = popen(cmd, "w")) == NULL) { 5747c478bd9Sstevel@tonic-gate print_status(500, "(hash_payload: missing/file error)"); 5757c478bd9Sstevel@tonic-gate return (B_FALSE); 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate if ((status = WEXITSTATUS(pclose(fp))) != 0) { 5787c478bd9Sstevel@tonic-gate (void) snprintf(msg, sizeof (msg), 5797c478bd9Sstevel@tonic-gate "(hash_payload: failed, status=%d)", status); 5807c478bd9Sstevel@tonic-gate print_status(500, msg); 5817c478bd9Sstevel@tonic-gate return (B_FALSE); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(payload_hash, sbuf) || 5857c478bd9Sstevel@tonic-gate sbuf.st_size < HMAC_DIGEST_LEN) { 5867c478bd9Sstevel@tonic-gate print_status(500, "(hash_payload: bad signature file)"); 5877c478bd9Sstevel@tonic-gate return (B_FALSE); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate return (B_TRUE); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate static boolean_t 5947c478bd9Sstevel@tonic-gate extract_keystore(const char *path, const char *keystorepath) 5957c478bd9Sstevel@tonic-gate { 5967c478bd9Sstevel@tonic-gate struct stat sbuf; 5977c478bd9Sstevel@tonic-gate int chars; 5987c478bd9Sstevel@tonic-gate char cmd[MAXPATHLEN]; 5997c478bd9Sstevel@tonic-gate FILE *fp; 6007c478bd9Sstevel@tonic-gate int status; 6017c478bd9Sstevel@tonic-gate char msg[WBCGI_MAXBUF]; 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(path, sbuf)) { 6047c478bd9Sstevel@tonic-gate print_status(500, "(extract_keystore: missing keystore)"); 6057c478bd9Sstevel@tonic-gate return (B_FALSE); 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate if ((chars = snprintf(cmd, sizeof (cmd), 6097c478bd9Sstevel@tonic-gate "%s -x -f %s -s %s -o type=rsa", 6107c478bd9Sstevel@tonic-gate WBCGI_KEYMGMT_PATH, keystorepath, path)) < 0 || 6117c478bd9Sstevel@tonic-gate chars > sizeof (cmd)) { 6127c478bd9Sstevel@tonic-gate print_status(500, "(extract_keystore: buffer overflow)"); 6137c478bd9Sstevel@tonic-gate return (B_FALSE); 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate if ((fp = popen(cmd, "w")) == NULL) { 6177c478bd9Sstevel@tonic-gate print_status(500, "(extract_keystore: missing/file error)"); 6187c478bd9Sstevel@tonic-gate return (B_FALSE); 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate if ((status = WEXITSTATUS(pclose(fp))) != 0) { 6217c478bd9Sstevel@tonic-gate (void) snprintf(msg, sizeof (msg), 6227c478bd9Sstevel@tonic-gate "(extract_keystore: failed, status=%d)", status); 6237c478bd9Sstevel@tonic-gate print_status(500, msg); 6247c478bd9Sstevel@tonic-gate return (B_FALSE); 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(keystorepath, sbuf)) { 6287c478bd9Sstevel@tonic-gate print_status(500, "(extract_keystore: failed to create)"); 6297c478bd9Sstevel@tonic-gate return (B_FALSE); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate return (B_TRUE); 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate static boolean_t 6367c478bd9Sstevel@tonic-gate mkisofs(const char *image_dir, const char *image) 6377c478bd9Sstevel@tonic-gate { 6387c478bd9Sstevel@tonic-gate struct stat sbuf; 6397c478bd9Sstevel@tonic-gate int chars; 6407c478bd9Sstevel@tonic-gate char cmd[MAXPATHLEN]; 6417c478bd9Sstevel@tonic-gate FILE *fp; 6427c478bd9Sstevel@tonic-gate int status; 6437c478bd9Sstevel@tonic-gate char msg[WBCGI_MAXBUF]; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate if (!WBCGI_DIR_EXISTS(image_dir, sbuf)) { 6467c478bd9Sstevel@tonic-gate print_status(500, "(mksiofs: missing image_dir)"); 6477c478bd9Sstevel@tonic-gate return (B_FALSE); 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate if ((chars = snprintf(cmd, sizeof (cmd), "%s -quiet -o %s -r %s", 6517c478bd9Sstevel@tonic-gate WBCGI_MKISOFS_PATH, image, image_dir)) < 0 || 6527c478bd9Sstevel@tonic-gate chars > sizeof (cmd)) { 6537c478bd9Sstevel@tonic-gate print_status(500, "(mkisofs: buffer overflow)"); 6547c478bd9Sstevel@tonic-gate return (B_FALSE); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate if ((fp = popen(cmd, "w")) == NULL) { 6587c478bd9Sstevel@tonic-gate print_status(500, "(mkisofs: missing/file error)"); 6597c478bd9Sstevel@tonic-gate return (B_FALSE); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate if ((status = WEXITSTATUS(pclose(fp))) != 0) { 6627c478bd9Sstevel@tonic-gate (void) snprintf(msg, sizeof (msg), 6637c478bd9Sstevel@tonic-gate "(mkisofs: failed, status=%d)", status); 6647c478bd9Sstevel@tonic-gate print_status(500, msg); 6657c478bd9Sstevel@tonic-gate return (B_FALSE); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(image, sbuf)) { 6697c478bd9Sstevel@tonic-gate print_status(500, "(mksiofs: failed to create image)"); 6707c478bd9Sstevel@tonic-gate return (B_FALSE); 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate return (B_TRUE); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate /* 6777c478bd9Sstevel@tonic-gate * This function, when invoked with a file name, optional network and 67822ce47f7SDavid Miner * client ID strings, and callback function will search for the file 67922ce47f7SDavid Miner * in the following locations: 68022ce47f7SDavid Miner * 68122ce47f7SDavid Miner * NB_NETBOOT_ROOT/<network>/<client id>/<file> 68222ce47f7SDavid Miner * NB_NETBOOT_ROOT/<client id>/<file> 68322ce47f7SDavid Miner * NB_NETBOOT_ROOT/<network>/<file> 68422ce47f7SDavid Miner * NB_NETBOOT_ROOT/<file> 68522ce47f7SDavid Miner * 68622ce47f7SDavid Miner * The callback function is invoked each time the file is found until 68722ce47f7SDavid Miner * we have searched all of the above locations or the callback function 68822ce47f7SDavid Miner * returns a value other than WBCGI_FTW_CBCONT. 6897c478bd9Sstevel@tonic-gate * 6907c478bd9Sstevel@tonic-gate * Arguments: 6917c478bd9Sstevel@tonic-gate * filename - Name of file to search for. 6927c478bd9Sstevel@tonic-gate * net - Optional network number to include in search hierarchy. 6937c478bd9Sstevel@tonic-gate * cid - Optional client ID to include in search hierarchy. 6947c478bd9Sstevel@tonic-gate * cb - Callback function to be called when file is found. 6957c478bd9Sstevel@tonic-gate * arg - Argument to be supplied to the callback funtion. 6967c478bd9Sstevel@tonic-gate * 6977c478bd9Sstevel@tonic-gate * Returns: 6987c478bd9Sstevel@tonic-gate * WBCGI_FTW_DONE, WBCGI_FTW_CBOK or WBCGI_FTW_CBERR. 6997c478bd9Sstevel@tonic-gate */ 7007c478bd9Sstevel@tonic-gate static int 7017c478bd9Sstevel@tonic-gate netboot_ftw(const char *filename, const char *net, const char *cid, 7027c478bd9Sstevel@tonic-gate int (*cb)(const char *, void *arg), void *arg) 7037c478bd9Sstevel@tonic-gate { 70422ce47f7SDavid Miner char ckpath[4][MAXPATHLEN]; 7057c478bd9Sstevel@tonic-gate int ret; 7067c478bd9Sstevel@tonic-gate struct stat buf; 70722ce47f7SDavid Miner int i = 0; 7087c478bd9Sstevel@tonic-gate 70922ce47f7SDavid Miner if (snprintf(ckpath[i++], MAXPATHLEN, "%s%s", NB_NETBOOT_ROOT, filename) 71022ce47f7SDavid Miner >= MAXPATHLEN) 7117c478bd9Sstevel@tonic-gate return (WBCGI_FTW_CBERR); 7127c478bd9Sstevel@tonic-gate 71322ce47f7SDavid Miner if (net != NULL && snprintf(ckpath[i++], MAXPATHLEN, "%s%s/%s", 71422ce47f7SDavid Miner NB_NETBOOT_ROOT, net, filename) >= MAXPATHLEN) 7157c478bd9Sstevel@tonic-gate return (WBCGI_FTW_CBERR); 71622ce47f7SDavid Miner 7177c478bd9Sstevel@tonic-gate if (cid != NULL) { 71822ce47f7SDavid Miner if (snprintf(ckpath[i++], MAXPATHLEN, "%s%s/%s", 71922ce47f7SDavid Miner NB_NETBOOT_ROOT, cid, filename) >= MAXPATHLEN) 7207c478bd9Sstevel@tonic-gate return (WBCGI_FTW_CBERR); 72122ce47f7SDavid Miner 72222ce47f7SDavid Miner if (net != NULL && snprintf(ckpath[i++], MAXPATHLEN, 72322ce47f7SDavid Miner "%s%s/%s/%s", NB_NETBOOT_ROOT, net, cid, filename) >= 72422ce47f7SDavid Miner MAXPATHLEN) 72522ce47f7SDavid Miner return (WBCGI_FTW_CBERR); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate /* 7297c478bd9Sstevel@tonic-gate * Loop through hierarchy and check for file existence. 7307c478bd9Sstevel@tonic-gate */ 73122ce47f7SDavid Miner while (i > 0) { 73222ce47f7SDavid Miner --i; 73322ce47f7SDavid Miner if (WBCGI_FILE_EXISTS(ckpath[i], buf)) { 73422ce47f7SDavid Miner if ((ret = cb(ckpath[i], arg)) != WBCGI_FTW_CBCONT) 7357c478bd9Sstevel@tonic-gate return (ret); 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate return (WBCGI_FTW_DONE); 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7427c478bd9Sstevel@tonic-gate static int 7437c478bd9Sstevel@tonic-gate noact_cb(const char *path, void *arg) 7447c478bd9Sstevel@tonic-gate { 7457c478bd9Sstevel@tonic-gate return (WBCGI_FTW_CBOK); 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate static int 7497c478bd9Sstevel@tonic-gate set_pathname(const char *path, void *pathname) 7507c478bd9Sstevel@tonic-gate { 7517c478bd9Sstevel@tonic-gate *(char **)pathname = strdup((char *)path); 7527c478bd9Sstevel@tonic-gate return (WBCGI_FTW_CBOK); 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate static int 7567c478bd9Sstevel@tonic-gate create_keystore(const char *path, void *keystorepath) 7577c478bd9Sstevel@tonic-gate { 7587c478bd9Sstevel@tonic-gate if (!extract_keystore(path, (char *)keystorepath)) { 7597c478bd9Sstevel@tonic-gate return (WBCGI_FTW_CBERR); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate return (WBCGI_FTW_CBOK); 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate static int 7657c478bd9Sstevel@tonic-gate copy_certstore(const char *path, void *certstorepath) 7667c478bd9Sstevel@tonic-gate { 7677c478bd9Sstevel@tonic-gate if (!copy_file(path, (char *)certstorepath)) { 7687c478bd9Sstevel@tonic-gate return (WBCGI_FTW_CBERR); 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate return (WBCGI_FTW_CBOK); 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate /* 7747c478bd9Sstevel@tonic-gate * Add the certs found in the trustfile found in path (a trust store) to 7757c478bd9Sstevel@tonic-gate * the file found at bootfs_dir/truststore. If necessary, create the 7767c478bd9Sstevel@tonic-gate * output file. 7777c478bd9Sstevel@tonic-gate */ 7787c478bd9Sstevel@tonic-gate static int 7797c478bd9Sstevel@tonic-gate build_trustfile(const char *path, void *truststorepath) 7807c478bd9Sstevel@tonic-gate { 7817c478bd9Sstevel@tonic-gate int ret = WBCGI_FTW_CBERR; 7827c478bd9Sstevel@tonic-gate STACK_OF(X509) *i_anchors = NULL; 7837c478bd9Sstevel@tonic-gate STACK_OF(X509) *o_anchors = NULL; 7847c478bd9Sstevel@tonic-gate char message[WBCGI_MAXBUF]; 7857c478bd9Sstevel@tonic-gate PKCS12 *p12 = NULL; 7867c478bd9Sstevel@tonic-gate FILE *rfp = NULL; 7877c478bd9Sstevel@tonic-gate FILE *wfp = NULL; 7887c478bd9Sstevel@tonic-gate struct stat i_st; 7897c478bd9Sstevel@tonic-gate struct stat o_st; 7907c478bd9Sstevel@tonic-gate X509 *x = NULL; 7917c478bd9Sstevel@tonic-gate int errtype = 0; 7927c478bd9Sstevel@tonic-gate int wfd = -1; 7937c478bd9Sstevel@tonic-gate int chars; 7947c478bd9Sstevel@tonic-gate int i; 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(path, i_st)) { 7977c478bd9Sstevel@tonic-gate goto cleanup; 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate if (WBCGI_FILE_EXISTS((char *)truststorepath, o_st)) { 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * If we are inadvertantly writing to the input file. 8037c478bd9Sstevel@tonic-gate * return success. 8047c478bd9Sstevel@tonic-gate * XXX Pete: how can this happen, and why success? 8057c478bd9Sstevel@tonic-gate */ 8067c478bd9Sstevel@tonic-gate if (i_st.st_ino == o_st.st_ino) { 8077c478bd9Sstevel@tonic-gate ret = WBCGI_FTW_CBCONT; 8087c478bd9Sstevel@tonic-gate goto cleanup; 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate if ((wfp = fopen((char *)truststorepath, "r+")) == NULL) { 8117c478bd9Sstevel@tonic-gate goto cleanup; 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate /* 8147c478bd9Sstevel@tonic-gate * Read what's already there, so that new information 8157c478bd9Sstevel@tonic-gate * can be added. 8167c478bd9Sstevel@tonic-gate */ 8177c478bd9Sstevel@tonic-gate if ((p12 = d2i_PKCS12_fp(wfp, NULL)) == NULL) { 8187c478bd9Sstevel@tonic-gate errtype = 1; 8197c478bd9Sstevel@tonic-gate goto cleanup; 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate i = sunw_PKCS12_parse(p12, WANBOOT_PASSPHRASE, DO_NONE, NULL, 8227c478bd9Sstevel@tonic-gate 0, NULL, NULL, NULL, &o_anchors); 8237c478bd9Sstevel@tonic-gate if (i <= 0) { 8247c478bd9Sstevel@tonic-gate errtype = 1; 8257c478bd9Sstevel@tonic-gate goto cleanup; 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate PKCS12_free(p12); 8297c478bd9Sstevel@tonic-gate p12 = NULL; 8307c478bd9Sstevel@tonic-gate } else { 8317c478bd9Sstevel@tonic-gate if (errno != ENOENT) { 8327c478bd9Sstevel@tonic-gate chars = snprintf(message, sizeof (message), 8337c478bd9Sstevel@tonic-gate "(error accessing file %s, error %s)", 8347c478bd9Sstevel@tonic-gate path, strerror(errno)); 8357c478bd9Sstevel@tonic-gate if (chars > 0 && chars < sizeof (message)) 8367c478bd9Sstevel@tonic-gate print_status(500, message); 8377c478bd9Sstevel@tonic-gate else 8387c478bd9Sstevel@tonic-gate print_status(500, NULL); 8397c478bd9Sstevel@tonic-gate return (WBCGI_FTW_CBERR); 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate /* 8437c478bd9Sstevel@tonic-gate * Note: We could copy the file to the new trustfile, but 8447c478bd9Sstevel@tonic-gate * we can't verify the password that way. Therefore, copy 8457c478bd9Sstevel@tonic-gate * it by reading it. 8467c478bd9Sstevel@tonic-gate */ 8477c478bd9Sstevel@tonic-gate if ((wfd = open((char *)truststorepath, 8487c478bd9Sstevel@tonic-gate O_CREAT|O_EXCL|O_RDWR, 0700)) < 0) { 8497c478bd9Sstevel@tonic-gate goto cleanup; 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate if ((wfp = fdopen(wfd, "w+")) == NULL) { 8527c478bd9Sstevel@tonic-gate goto cleanup; 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate o_anchors = sk_X509_new_null(); 8557c478bd9Sstevel@tonic-gate if (o_anchors == NULL) { 8567c478bd9Sstevel@tonic-gate goto cleanup; 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate if ((rfp = fopen(path, "r")) == NULL) { 8617c478bd9Sstevel@tonic-gate goto cleanup; 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate if ((p12 = d2i_PKCS12_fp(rfp, NULL)) == NULL) { 8647c478bd9Sstevel@tonic-gate errtype = 1; 8657c478bd9Sstevel@tonic-gate goto cleanup; 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate i = sunw_PKCS12_parse(p12, WANBOOT_PASSPHRASE, DO_NONE, NULL, 0, NULL, 8687c478bd9Sstevel@tonic-gate NULL, NULL, &i_anchors); 8697c478bd9Sstevel@tonic-gate if (i <= 0) { 8707c478bd9Sstevel@tonic-gate errtype = 1; 8717c478bd9Sstevel@tonic-gate goto cleanup; 8727c478bd9Sstevel@tonic-gate } 8737c478bd9Sstevel@tonic-gate PKCS12_free(p12); 8747c478bd9Sstevel@tonic-gate p12 = NULL; 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate /* 8777c478bd9Sstevel@tonic-gate * Merge the two stacks of pkcs12 certs. 8787c478bd9Sstevel@tonic-gate */ 8797c478bd9Sstevel@tonic-gate for (i = 0; i < sk_X509_num(i_anchors); i++) { 880*d7141854SRobert Mustacchi /* LINTED */ 8817c478bd9Sstevel@tonic-gate x = sk_X509_delete(i_anchors, i); 8827c478bd9Sstevel@tonic-gate (void) sk_X509_push(o_anchors, x); 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate /* 8867c478bd9Sstevel@tonic-gate * Create the pkcs12 structure from the modified input stack and 8877c478bd9Sstevel@tonic-gate * then write out that structure. 8887c478bd9Sstevel@tonic-gate */ 8897c478bd9Sstevel@tonic-gate p12 = sunw_PKCS12_create((const char *)WANBOOT_PASSPHRASE, NULL, NULL, 8907c478bd9Sstevel@tonic-gate o_anchors); 8917c478bd9Sstevel@tonic-gate if (p12 == NULL) { 8927c478bd9Sstevel@tonic-gate goto cleanup; 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate rewind(wfp); 8957c478bd9Sstevel@tonic-gate if (i2d_PKCS12_fp(wfp, p12) == 0) { 8967c478bd9Sstevel@tonic-gate goto cleanup; 8977c478bd9Sstevel@tonic-gate } 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate ret = WBCGI_FTW_CBCONT; 9007c478bd9Sstevel@tonic-gate cleanup: 9017c478bd9Sstevel@tonic-gate if (ret == WBCGI_FTW_CBERR) { 9027c478bd9Sstevel@tonic-gate if (errtype == 1) { 9037c478bd9Sstevel@tonic-gate chars = snprintf(message, sizeof (message), 9047c478bd9Sstevel@tonic-gate "(internal PKCS12 error while copying %s to %s)", 9057c478bd9Sstevel@tonic-gate path, (char *)truststorepath); 9067c478bd9Sstevel@tonic-gate } else { 9077c478bd9Sstevel@tonic-gate chars = snprintf(message, sizeof (message), 9087c478bd9Sstevel@tonic-gate "(error copying %s to %s)", 9097c478bd9Sstevel@tonic-gate path, (char *)truststorepath); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate if (chars > 0 && chars <= sizeof (message)) { 9127c478bd9Sstevel@tonic-gate print_status(500, message); 9137c478bd9Sstevel@tonic-gate } else { 9147c478bd9Sstevel@tonic-gate print_status(500, NULL); 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate if (rfp != NULL) { 9187c478bd9Sstevel@tonic-gate (void) fclose(rfp); 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate if (wfp != NULL) { 9217c478bd9Sstevel@tonic-gate /* Will also close wfd */ 9227c478bd9Sstevel@tonic-gate (void) fclose(wfp); 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate if (p12 != NULL) { 9257c478bd9Sstevel@tonic-gate PKCS12_free(p12); 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate if (i_anchors != NULL) { 9287c478bd9Sstevel@tonic-gate sk_X509_pop_free(i_anchors, X509_free); 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate if (o_anchors != NULL) { 9317c478bd9Sstevel@tonic-gate sk_X509_pop_free(o_anchors, X509_free); 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate return (ret); 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate static boolean_t 9387c478bd9Sstevel@tonic-gate check_key_type(const char *keyfile, const char *keytype, int flag) 9397c478bd9Sstevel@tonic-gate { 9407c478bd9Sstevel@tonic-gate boolean_t ret = B_FALSE; 9417c478bd9Sstevel@tonic-gate FILE *key_fp = NULL; 9427c478bd9Sstevel@tonic-gate wbku_key_attr_t ka; 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate /* 9457c478bd9Sstevel@tonic-gate * Map keytype into the ka structure 9467c478bd9Sstevel@tonic-gate */ 9477c478bd9Sstevel@tonic-gate if (wbku_str_to_keyattr(keytype, &ka, flag) != WBKU_SUCCESS) { 9487c478bd9Sstevel@tonic-gate goto cleanup; 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate /* 9527c478bd9Sstevel@tonic-gate * Open the key file for reading. 9537c478bd9Sstevel@tonic-gate */ 9547c478bd9Sstevel@tonic-gate if ((key_fp = fopen(keyfile, "r")) == NULL) { 9557c478bd9Sstevel@tonic-gate goto cleanup; 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate /* 9597c478bd9Sstevel@tonic-gate * Find the valid client key, if it exists. 9607c478bd9Sstevel@tonic-gate */ 9617c478bd9Sstevel@tonic-gate if (wbku_find_key(key_fp, NULL, &ka, NULL, B_FALSE) != WBKU_SUCCESS) { 9627c478bd9Sstevel@tonic-gate goto cleanup; 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate ret = B_TRUE; 9667c478bd9Sstevel@tonic-gate cleanup: 9677c478bd9Sstevel@tonic-gate if (key_fp != NULL) { 9687c478bd9Sstevel@tonic-gate (void) fclose(key_fp); 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate return (ret); 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate static boolean_t 9757c478bd9Sstevel@tonic-gate resolve_hostname(const char *hostname, nvlist_t *nvl, boolean_t may_be_crap) 9767c478bd9Sstevel@tonic-gate { 9777c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 9787c478bd9Sstevel@tonic-gate struct hostent *hp; 97922ce47f7SDavid Miner struct utsname un; 98022ce47f7SDavid Miner static char myname[SYS_NMLN] = { '\0' }; 98122ce47f7SDavid Miner char *cp = NULL; 98222ce47f7SDavid Miner char msg[WBCGI_MAXBUF]; 9837c478bd9Sstevel@tonic-gate 98422ce47f7SDavid Miner /* 98522ce47f7SDavid Miner * Initialize cached nodename 98622ce47f7SDavid Miner */ 98722ce47f7SDavid Miner if (strlen(myname) == 0) { 98822ce47f7SDavid Miner if (uname(&un) == -1) { 98922ce47f7SDavid Miner (void) snprintf(msg, sizeof (msg), 99022ce47f7SDavid Miner "(unable to retrieve uname, errno %d)", errno); 99122ce47f7SDavid Miner print_status(500, msg); 99222ce47f7SDavid Miner return (B_FALSE); 99322ce47f7SDavid Miner } 99422ce47f7SDavid Miner (void) strcpy(myname, un.nodename); 99522ce47f7SDavid Miner } 99622ce47f7SDavid Miner 99722ce47f7SDavid Miner /* 99822ce47f7SDavid Miner * If hostname is local node name, return the address this 99922ce47f7SDavid Miner * request came in on, which is supplied as SERVER_ADDR in the 100022ce47f7SDavid Miner * cgi environment. This ensures we don't send back a possible 100122ce47f7SDavid Miner * alternate address that may be unreachable from the client's 100222ce47f7SDavid Miner * network. Otherwise, just resolve with nameservice. 100322ce47f7SDavid Miner */ 100422ce47f7SDavid Miner if ((strcmp(hostname, myname) != 0) || 100522ce47f7SDavid Miner ((cp = getenv("SERVER_ADDR")) == NULL)) { 10067c478bd9Sstevel@tonic-gate if (((hp = gethostbyname(hostname)) == NULL) || 10077c478bd9Sstevel@tonic-gate (hp->h_addrtype != AF_INET) || 10087c478bd9Sstevel@tonic-gate (hp->h_length != sizeof (struct in_addr))) { 10097c478bd9Sstevel@tonic-gate if (!may_be_crap) { 10107c478bd9Sstevel@tonic-gate print_status(500, "(error resolving hostname)"); 10117c478bd9Sstevel@tonic-gate } 10127c478bd9Sstevel@tonic-gate return (may_be_crap); 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate (void) memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); 101522ce47f7SDavid Miner cp = inet_ntoa(sin.sin_addr); 101622ce47f7SDavid Miner } 10177c478bd9Sstevel@tonic-gate 101822ce47f7SDavid Miner if (nvlist_add_string(nvl, (char *)hostname, cp) != 0) { 10197c478bd9Sstevel@tonic-gate print_status(500, "(error adding hostname to nvlist)"); 10207c478bd9Sstevel@tonic-gate return (B_FALSE); 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate return (B_TRUE); 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate /* 10277c478bd9Sstevel@tonic-gate * one_name() is called for each certificate found and is passed the string 10287c478bd9Sstevel@tonic-gate * that X509_NAME_oneline() returns. Its job is to find the common name and 10297c478bd9Sstevel@tonic-gate * determine whether it is a host name; if it is then a line suitable for 10307c478bd9Sstevel@tonic-gate * inclusion in /etc/inet/hosts is written to that file. 10317c478bd9Sstevel@tonic-gate */ 10327c478bd9Sstevel@tonic-gate static boolean_t 10337c478bd9Sstevel@tonic-gate one_name(const char *namestr, nvlist_t *nvl) 10347c478bd9Sstevel@tonic-gate { 10357c478bd9Sstevel@tonic-gate boolean_t ret = B_TRUE; 10367c478bd9Sstevel@tonic-gate char *p; 10377c478bd9Sstevel@tonic-gate char *q; 10387c478bd9Sstevel@tonic-gate char c; 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate if (namestr != NULL && 10417c478bd9Sstevel@tonic-gate (p = strstr(namestr, WBCGI_CNSTR)) != NULL) { 10427c478bd9Sstevel@tonic-gate p += WBCGI_CNSTR_LEN; 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate if ((q = strpbrk(p, WBCGI_NAMESEP)) != NULL) { 10457c478bd9Sstevel@tonic-gate c = *q; 10467c478bd9Sstevel@tonic-gate *q = '\0'; 10477c478bd9Sstevel@tonic-gate ret = resolve_hostname(p, nvl, B_TRUE); 10487c478bd9Sstevel@tonic-gate *q = c; 10497c478bd9Sstevel@tonic-gate } else { 10507c478bd9Sstevel@tonic-gate ret = resolve_hostname(p, nvl, B_TRUE); 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate return (ret); 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate /* 10587c478bd9Sstevel@tonic-gate * Loop through the certificates in a file 10597c478bd9Sstevel@tonic-gate */ 10607c478bd9Sstevel@tonic-gate static int 10617c478bd9Sstevel@tonic-gate get_hostnames(const char *path, void *nvl) 10627c478bd9Sstevel@tonic-gate { 10637c478bd9Sstevel@tonic-gate int ret = WBCGI_FTW_CBERR; 10647c478bd9Sstevel@tonic-gate STACK_OF(X509) *certs = NULL; 10657c478bd9Sstevel@tonic-gate PKCS12 *p12 = NULL; 10667c478bd9Sstevel@tonic-gate char message[WBCGI_MAXBUF]; 10677c478bd9Sstevel@tonic-gate char buf[WBCGI_MAXBUF + 1]; 10687c478bd9Sstevel@tonic-gate FILE *rfp = NULL; 10697c478bd9Sstevel@tonic-gate X509 *x = NULL; 10707c478bd9Sstevel@tonic-gate int errtype = 0; 10717c478bd9Sstevel@tonic-gate int chars; 10727c478bd9Sstevel@tonic-gate int i; 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate if ((rfp = fopen(path, "r")) == NULL) { 10757c478bd9Sstevel@tonic-gate goto cleanup; 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate if ((p12 = d2i_PKCS12_fp(rfp, NULL)) == NULL) { 10797c478bd9Sstevel@tonic-gate errtype = 1; 10807c478bd9Sstevel@tonic-gate goto cleanup; 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate i = sunw_PKCS12_parse(p12, WANBOOT_PASSPHRASE, DO_NONE, NULL, 0, NULL, 10837c478bd9Sstevel@tonic-gate NULL, NULL, &certs); 10847c478bd9Sstevel@tonic-gate if (i <= 0) { 10857c478bd9Sstevel@tonic-gate errtype = 1; 10867c478bd9Sstevel@tonic-gate goto cleanup; 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate PKCS12_free(p12); 10907c478bd9Sstevel@tonic-gate p12 = NULL; 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate for (i = 0; i < sk_X509_num(certs); i++) { 1093*d7141854SRobert Mustacchi /* LINTED */ 10947c478bd9Sstevel@tonic-gate x = sk_X509_value(certs, i); 10957c478bd9Sstevel@tonic-gate if (!one_name(sunw_issuer_attrs(x, buf, sizeof (buf) - 1), 10967c478bd9Sstevel@tonic-gate nvl)) { 10977c478bd9Sstevel@tonic-gate goto cleanup; 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate ret = WBCGI_FTW_CBCONT; 11027c478bd9Sstevel@tonic-gate cleanup: 11037c478bd9Sstevel@tonic-gate if (ret == WBCGI_FTW_CBERR) { 11047c478bd9Sstevel@tonic-gate if (errtype == 1) { 11057c478bd9Sstevel@tonic-gate chars = snprintf(message, sizeof (message), 11067c478bd9Sstevel@tonic-gate "(internal PKCS12 error reading %s)", path); 11077c478bd9Sstevel@tonic-gate } else { 11087c478bd9Sstevel@tonic-gate chars = snprintf(message, sizeof (message), 11097c478bd9Sstevel@tonic-gate "error reading %s", path); 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate if (chars > 0 && chars <= sizeof (message)) { 11127c478bd9Sstevel@tonic-gate print_status(500, message); 11137c478bd9Sstevel@tonic-gate } else { 11147c478bd9Sstevel@tonic-gate print_status(500, NULL); 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate } 11177c478bd9Sstevel@tonic-gate if (rfp != NULL) { 11187c478bd9Sstevel@tonic-gate (void) fclose(rfp); 11197c478bd9Sstevel@tonic-gate } 11207c478bd9Sstevel@tonic-gate if (p12 != NULL) { 11217c478bd9Sstevel@tonic-gate PKCS12_free(p12); 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate if (certs != NULL) { 11247c478bd9Sstevel@tonic-gate sk_X509_pop_free(certs, X509_free); 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate return (ret); 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate /* 11317c478bd9Sstevel@tonic-gate * Create a hosts file by extracting hosts from client and truststore 11327c478bd9Sstevel@tonic-gate * files. Use the CN. Then we should copy that file to the inet dir. 11337c478bd9Sstevel@tonic-gate */ 11347c478bd9Sstevel@tonic-gate static boolean_t 11357c478bd9Sstevel@tonic-gate create_hostsfile(const char *hostsfile, const char *net, const char *cid) 11367c478bd9Sstevel@tonic-gate { 11377c478bd9Sstevel@tonic-gate boolean_t ret = B_FALSE; 11387c478bd9Sstevel@tonic-gate nvlist_t *nvl; 11397c478bd9Sstevel@tonic-gate nvpair_t *nvp; 11407c478bd9Sstevel@tonic-gate FILE *hostfp = NULL; 11417c478bd9Sstevel@tonic-gate int hostfd = -1; 11427c478bd9Sstevel@tonic-gate int i; 11437c478bd9Sstevel@tonic-gate char *hostslist; 11447c478bd9Sstevel@tonic-gate const char *bc_urls[] = { BC_ROOT_SERVER, BC_BOOT_LOGGER, NULL }; 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate /* 11477c478bd9Sstevel@tonic-gate * Allocate nvlist handle to store our hostname/IP pairs. 11487c478bd9Sstevel@tonic-gate */ 11497c478bd9Sstevel@tonic-gate if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 11507c478bd9Sstevel@tonic-gate print_status(500, "(error allocating hostname nvlist)"); 11517c478bd9Sstevel@tonic-gate goto cleanup; 11527c478bd9Sstevel@tonic-gate } 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate /* 11557c478bd9Sstevel@tonic-gate * Extract and resolve hostnames from CNs. 11567c478bd9Sstevel@tonic-gate */ 11577c478bd9Sstevel@tonic-gate if (netboot_ftw(NB_CLIENT_CERT, net, cid, 11587c478bd9Sstevel@tonic-gate get_hostnames, nvl) == WBCGI_FTW_CBERR || 11597c478bd9Sstevel@tonic-gate netboot_ftw(NB_CA_CERT, net, cid, 11607c478bd9Sstevel@tonic-gate get_hostnames, nvl) == WBCGI_FTW_CBERR) { 11617c478bd9Sstevel@tonic-gate goto cleanup; 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate /* 11657c478bd9Sstevel@tonic-gate * Extract and resolve hostnames from any URLs in bootconf. 11667c478bd9Sstevel@tonic-gate */ 11677c478bd9Sstevel@tonic-gate for (i = 0; bc_urls[i] != NULL; ++i) { 11687c478bd9Sstevel@tonic-gate char *urlstr; 11697c478bd9Sstevel@tonic-gate url_t url; 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate if ((urlstr = bootconf_get(&bc_handle, bc_urls[i])) != NULL && 11727c478bd9Sstevel@tonic-gate url_parse(urlstr, &url) == URL_PARSE_SUCCESS) { 11737c478bd9Sstevel@tonic-gate if (!resolve_hostname(url.hport.hostname, 11747c478bd9Sstevel@tonic-gate nvl, B_FALSE)) { 11757c478bd9Sstevel@tonic-gate goto cleanup; 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate } 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate /* 11817c478bd9Sstevel@tonic-gate * If there is a resolve-hosts list in bootconf, resolve those 11827c478bd9Sstevel@tonic-gate * hostnames too. 11837c478bd9Sstevel@tonic-gate */ 11847c478bd9Sstevel@tonic-gate if ((hostslist = bootconf_get(&bc_handle, BC_RESOLVE_HOSTS)) != NULL) { 11857c478bd9Sstevel@tonic-gate char *hostname; 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate for (hostname = strtok(hostslist, ","); hostname != NULL; 11887c478bd9Sstevel@tonic-gate hostname = strtok(NULL, ",")) { 11897c478bd9Sstevel@tonic-gate if (!resolve_hostname(hostname, nvl, B_FALSE)) { 11907c478bd9Sstevel@tonic-gate goto cleanup; 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate /* 11967c478bd9Sstevel@tonic-gate * Now write the hostname/IP pairs gathered to the hosts file. 11977c478bd9Sstevel@tonic-gate */ 11987c478bd9Sstevel@tonic-gate if ((hostfd = open(hostsfile, 11997c478bd9Sstevel@tonic-gate O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 || 12007c478bd9Sstevel@tonic-gate (hostfp = fdopen(hostfd, "w+")) == NULL) { 12017c478bd9Sstevel@tonic-gate print_status(500, "(error creating hosts file)"); 12027c478bd9Sstevel@tonic-gate goto cleanup; 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 12057c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(nvl, nvp)) { 12067c478bd9Sstevel@tonic-gate char *hostname; 12077c478bd9Sstevel@tonic-gate char *ipstr; 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate hostname = nvpair_name(nvp); 12107c478bd9Sstevel@tonic-gate if (nvpair_value_string(nvp, &ipstr) != 0) { 12117c478bd9Sstevel@tonic-gate print_status(500, "(nvl error writing hosts file)"); 12127c478bd9Sstevel@tonic-gate goto cleanup; 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate if (fprintf(hostfp, "%s\t%s\n", ipstr, hostname) < 0) { 12167c478bd9Sstevel@tonic-gate print_status(500, "(error writing hosts file)"); 12177c478bd9Sstevel@tonic-gate goto cleanup; 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate ret = B_TRUE; 12227c478bd9Sstevel@tonic-gate cleanup: 12237c478bd9Sstevel@tonic-gate if (nvl != NULL) { 12247c478bd9Sstevel@tonic-gate nvlist_free(nvl); 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate if (hostfp != NULL) { 12277c478bd9Sstevel@tonic-gate /* 12287c478bd9Sstevel@tonic-gate * hostfd is automatically closed as well. 12297c478bd9Sstevel@tonic-gate */ 12307c478bd9Sstevel@tonic-gate (void) fclose(hostfp); 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate return (ret); 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate static boolean_t 12377c478bd9Sstevel@tonic-gate bootfile_payload(const char *docroot, char **bootpathp) 12387c478bd9Sstevel@tonic-gate { 12397c478bd9Sstevel@tonic-gate boolean_t ret = B_FALSE; 12407c478bd9Sstevel@tonic-gate char *boot_file; 12417c478bd9Sstevel@tonic-gate struct stat sbuf; 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate if ((boot_file = bootconf_get(&bc_handle, BC_BOOT_FILE)) == NULL) { 12447c478bd9Sstevel@tonic-gate print_status(500, "(boot_file must be specified)"); 12457c478bd9Sstevel@tonic-gate goto cleanup; 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate if ((*bootpathp = make_path(docroot, boot_file)) == NULL) { 12487c478bd9Sstevel@tonic-gate goto cleanup; 12497c478bd9Sstevel@tonic-gate } 12507c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(*bootpathp, sbuf)) { 12517c478bd9Sstevel@tonic-gate print_status(500, "(boot_file missing)"); 12527c478bd9Sstevel@tonic-gate goto cleanup; 12537c478bd9Sstevel@tonic-gate } 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate ret = B_TRUE; 12567c478bd9Sstevel@tonic-gate cleanup: 12577c478bd9Sstevel@tonic-gate return (ret); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate /* 12617c478bd9Sstevel@tonic-gate * Create the wanboot file system whose contents are determined by the 12627c478bd9Sstevel@tonic-gate * security configuration specified in bootconf. 12637c478bd9Sstevel@tonic-gate */ 12647c478bd9Sstevel@tonic-gate static boolean_t 12657c478bd9Sstevel@tonic-gate wanbootfs_payload(const char *net, const char *cid, const char *nonce, 12667c478bd9Sstevel@tonic-gate const char *bootconf, char **wanbootfs_imagep) 12677c478bd9Sstevel@tonic-gate { 12687c478bd9Sstevel@tonic-gate int ret = B_FALSE; 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate char *server_authentication; 12717c478bd9Sstevel@tonic-gate char *client_authentication; 12727c478bd9Sstevel@tonic-gate char *scf; 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate char *bootfs_dir = NULL; 12757c478bd9Sstevel@tonic-gate char *bootfs_etc_dir = NULL; 12767c478bd9Sstevel@tonic-gate char *bootfs_etc_inet_dir = NULL; 12777c478bd9Sstevel@tonic-gate char *bootfs_dev_dir = NULL; 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate char *systemconf = NULL; 12807c478bd9Sstevel@tonic-gate char *keystorepath = NULL; 12817c478bd9Sstevel@tonic-gate char *certstorepath = NULL; 12827c478bd9Sstevel@tonic-gate char *truststorepath = NULL; 12837c478bd9Sstevel@tonic-gate char *bootconfpath = NULL; 12847c478bd9Sstevel@tonic-gate char *systemconfpath = NULL; 12857c478bd9Sstevel@tonic-gate char *urandompath = NULL; 12867c478bd9Sstevel@tonic-gate char *noncepath = NULL; 12877c478bd9Sstevel@tonic-gate char *hostspath = NULL; 12887c478bd9Sstevel@tonic-gate char *etc_hostspath = NULL; 12897c478bd9Sstevel@tonic-gate char *timestamppath = NULL; 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate boolean_t authenticate_client; 12927c478bd9Sstevel@tonic-gate boolean_t authenticate_server; 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate struct stat sbuf; 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate /* 12977c478bd9Sstevel@tonic-gate * Initialize SSL stuff. 12987c478bd9Sstevel@tonic-gate */ 12997c478bd9Sstevel@tonic-gate sunw_crypto_init(); 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate /* 13027c478bd9Sstevel@tonic-gate * Get the security strategy values. 13037c478bd9Sstevel@tonic-gate */ 13047c478bd9Sstevel@tonic-gate client_authentication = bootconf_get(&bc_handle, 13057c478bd9Sstevel@tonic-gate BC_CLIENT_AUTHENTICATION); 13067c478bd9Sstevel@tonic-gate authenticate_client = (client_authentication != NULL && 13077c478bd9Sstevel@tonic-gate strcmp(client_authentication, "yes") == 0); 13087c478bd9Sstevel@tonic-gate server_authentication = bootconf_get(&bc_handle, 13097c478bd9Sstevel@tonic-gate BC_SERVER_AUTHENTICATION); 13107c478bd9Sstevel@tonic-gate authenticate_server = (server_authentication != NULL && 13117c478bd9Sstevel@tonic-gate strcmp(server_authentication, "yes") == 0); 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate /* 13147c478bd9Sstevel@tonic-gate * Make a temporary directory structure for the wanboot file system. 13157c478bd9Sstevel@tonic-gate */ 13167c478bd9Sstevel@tonic-gate if ((bootfs_dir = gen_tmppath("bootfs_dir", net, cid)) == NULL || 13177c478bd9Sstevel@tonic-gate (bootfs_etc_dir = make_path(bootfs_dir, "etc")) == NULL || 13187c478bd9Sstevel@tonic-gate (bootfs_etc_inet_dir = make_path(bootfs_etc_dir, "inet")) == NULL || 13197c478bd9Sstevel@tonic-gate (bootfs_dev_dir = make_path(bootfs_dir, "dev")) == NULL) { 13207c478bd9Sstevel@tonic-gate goto cleanup; 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate if (mkdirp(bootfs_dir, 0700) || 13237c478bd9Sstevel@tonic-gate mkdirp(bootfs_etc_dir, 0700) || 13247c478bd9Sstevel@tonic-gate mkdirp(bootfs_etc_inet_dir, 0700) || 13257c478bd9Sstevel@tonic-gate mkdirp(bootfs_dev_dir, 0700)) { 13267c478bd9Sstevel@tonic-gate print_status(500, "(error creating wanbootfs dir structure)"); 13277c478bd9Sstevel@tonic-gate goto cleanup; 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate if (authenticate_client) { 13317c478bd9Sstevel@tonic-gate /* 13327c478bd9Sstevel@tonic-gate * Add the client private key. 13337c478bd9Sstevel@tonic-gate */ 13347c478bd9Sstevel@tonic-gate if ((keystorepath = make_path(bootfs_dir, 13357c478bd9Sstevel@tonic-gate NB_CLIENT_KEY)) == NULL || 13367c478bd9Sstevel@tonic-gate netboot_ftw(NB_CLIENT_KEY, net, cid, 13377c478bd9Sstevel@tonic-gate create_keystore, keystorepath) != WBCGI_FTW_CBOK) { 13387c478bd9Sstevel@tonic-gate goto cleanup; 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate /* 13427c478bd9Sstevel@tonic-gate * Add the client certificate. 13437c478bd9Sstevel@tonic-gate */ 13447c478bd9Sstevel@tonic-gate if ((certstorepath = make_path(bootfs_dir, 13457c478bd9Sstevel@tonic-gate NB_CLIENT_CERT)) == NULL || 13467c478bd9Sstevel@tonic-gate netboot_ftw(NB_CLIENT_CERT, net, cid, 13477c478bd9Sstevel@tonic-gate copy_certstore, certstorepath) != WBCGI_FTW_CBOK) { 13487c478bd9Sstevel@tonic-gate goto cleanup; 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate if (authenticate_client || authenticate_server) { 13537c478bd9Sstevel@tonic-gate /* 13547c478bd9Sstevel@tonic-gate * Add the trustfile; at least one truststore must exist. 13557c478bd9Sstevel@tonic-gate */ 13567c478bd9Sstevel@tonic-gate if ((truststorepath = make_path(bootfs_dir, 13577c478bd9Sstevel@tonic-gate NB_CA_CERT)) == NULL) { 13587c478bd9Sstevel@tonic-gate goto cleanup; 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate if (netboot_ftw(NB_CA_CERT, net, cid, 13617c478bd9Sstevel@tonic-gate noact_cb, NULL) != WBCGI_FTW_CBOK) { 13627c478bd9Sstevel@tonic-gate print_status(500, "(truststore not found)"); 13637c478bd9Sstevel@tonic-gate } 13647c478bd9Sstevel@tonic-gate if (netboot_ftw(NB_CA_CERT, net, cid, 13657c478bd9Sstevel@tonic-gate build_trustfile, truststorepath) == WBCGI_FTW_CBERR) { 13667c478bd9Sstevel@tonic-gate goto cleanup; 13677c478bd9Sstevel@tonic-gate } 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate /* 13707c478bd9Sstevel@tonic-gate * Create the /dev/urandom file. 13717c478bd9Sstevel@tonic-gate */ 13727c478bd9Sstevel@tonic-gate if ((urandompath = make_path(bootfs_dev_dir, 13737c478bd9Sstevel@tonic-gate "urandom")) == NULL || 13747c478bd9Sstevel@tonic-gate !create_urandom(urandompath)) { 13757c478bd9Sstevel@tonic-gate goto cleanup; 13767c478bd9Sstevel@tonic-gate } 13777c478bd9Sstevel@tonic-gate } 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate /* 13807c478bd9Sstevel@tonic-gate * Add the wanboot.conf(4) file. 13817c478bd9Sstevel@tonic-gate */ 13827c478bd9Sstevel@tonic-gate if ((bootconfpath = make_path(bootfs_dir, NB_WANBOOT_CONF)) == NULL || 13837c478bd9Sstevel@tonic-gate !copy_file(bootconf, bootconfpath)) { 13847c478bd9Sstevel@tonic-gate goto cleanup; 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate /* 13887c478bd9Sstevel@tonic-gate * Add the system_conf file if present. 13897c478bd9Sstevel@tonic-gate */ 13907c478bd9Sstevel@tonic-gate if ((scf = bootconf_get(&bc_handle, BC_SYSTEM_CONF)) != NULL) { 13917c478bd9Sstevel@tonic-gate if (netboot_ftw(scf, net, cid, 13927c478bd9Sstevel@tonic-gate set_pathname, &systemconf) != WBCGI_FTW_CBOK) { 13937c478bd9Sstevel@tonic-gate print_status(500, "(system_conf file not found)"); 13947c478bd9Sstevel@tonic-gate goto cleanup; 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate if ((systemconfpath = make_path(bootfs_dir, 13977c478bd9Sstevel@tonic-gate NB_SYSTEM_CONF)) == NULL || 13987c478bd9Sstevel@tonic-gate !copy_file(systemconf, systemconfpath)) { 13997c478bd9Sstevel@tonic-gate goto cleanup; 14007c478bd9Sstevel@tonic-gate } 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate /* 14047c478bd9Sstevel@tonic-gate * Create the /nonce file. 14057c478bd9Sstevel@tonic-gate */ 14067c478bd9Sstevel@tonic-gate if ((noncepath = make_path(bootfs_dir, "nonce")) == NULL || 14077c478bd9Sstevel@tonic-gate !create_nonce(noncepath, nonce)) { 14087c478bd9Sstevel@tonic-gate goto cleanup; 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate /* 14127c478bd9Sstevel@tonic-gate * Create an /etc/inet/hosts file by extracting hostnames from CN, 14137c478bd9Sstevel@tonic-gate * URLs in bootconf and resolve-hosts in bootconf. 14147c478bd9Sstevel@tonic-gate */ 14157c478bd9Sstevel@tonic-gate if ((hostspath = make_path(bootfs_etc_inet_dir, "hosts")) == NULL || 14167c478bd9Sstevel@tonic-gate !create_hostsfile(hostspath, net, cid)) { 14177c478bd9Sstevel@tonic-gate goto cleanup; 14187c478bd9Sstevel@tonic-gate } 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate /* 14217c478bd9Sstevel@tonic-gate * We would like to create a symbolic link etc/hosts -> etc/inet/hosts, 14227c478bd9Sstevel@tonic-gate * but unfortunately the HSFS support in the standalone doesn't handle 14237c478bd9Sstevel@tonic-gate * symlinks. 14247c478bd9Sstevel@tonic-gate */ 14257c478bd9Sstevel@tonic-gate if ((etc_hostspath = make_path(bootfs_etc_dir, "hosts")) == NULL || 14267c478bd9Sstevel@tonic-gate !copy_file(hostspath, etc_hostspath)) { 14277c478bd9Sstevel@tonic-gate goto cleanup; 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate /* 14317c478bd9Sstevel@tonic-gate * Create the /timestamp file. 14327c478bd9Sstevel@tonic-gate */ 14337c478bd9Sstevel@tonic-gate if ((timestamppath = make_path(bootfs_dir, "timestamp")) == NULL || 14347c478bd9Sstevel@tonic-gate !create_timestamp(timestamppath, "timestamp")) { 14357c478bd9Sstevel@tonic-gate goto cleanup; 14367c478bd9Sstevel@tonic-gate } 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate /* 14397c478bd9Sstevel@tonic-gate * Create an HSFS file system for the directory. 14407c478bd9Sstevel@tonic-gate */ 14417c478bd9Sstevel@tonic-gate if ((*wanbootfs_imagep = gen_tmppath("wanbootfs", net, cid)) == NULL || 14427c478bd9Sstevel@tonic-gate !mkisofs(bootfs_dir, *wanbootfs_imagep)) { 14437c478bd9Sstevel@tonic-gate goto cleanup; 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate ret = B_TRUE; 14477c478bd9Sstevel@tonic-gate cleanup: 14487c478bd9Sstevel@tonic-gate /* 14497c478bd9Sstevel@tonic-gate * Clean up temporary files and directories. 14507c478bd9Sstevel@tonic-gate */ 14517c478bd9Sstevel@tonic-gate if (keystorepath != NULL && 14527c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(keystorepath, sbuf)) { 14537c478bd9Sstevel@tonic-gate (void) unlink(keystorepath); 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate if (certstorepath != NULL && 14567c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(certstorepath, sbuf)) { 14577c478bd9Sstevel@tonic-gate (void) unlink(certstorepath); 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate if (truststorepath != NULL && 14607c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(truststorepath, sbuf)) { 14617c478bd9Sstevel@tonic-gate (void) unlink(truststorepath); 14627c478bd9Sstevel@tonic-gate } 14637c478bd9Sstevel@tonic-gate if (bootconfpath != NULL && 14647c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(bootconfpath, sbuf)) { 14657c478bd9Sstevel@tonic-gate (void) unlink(bootconfpath); 14667c478bd9Sstevel@tonic-gate } 14677c478bd9Sstevel@tonic-gate if (systemconfpath != NULL && 14687c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(systemconfpath, sbuf)) { 14697c478bd9Sstevel@tonic-gate (void) unlink(systemconfpath); 14707c478bd9Sstevel@tonic-gate } 14717c478bd9Sstevel@tonic-gate if (urandompath != NULL && 14727c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(urandompath, sbuf)) { 14737c478bd9Sstevel@tonic-gate (void) unlink(urandompath); 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate if (noncepath != NULL && 14767c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(noncepath, sbuf)) { 14777c478bd9Sstevel@tonic-gate (void) unlink(noncepath); 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate if (hostspath != NULL && 14807c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(hostspath, sbuf)) { 14817c478bd9Sstevel@tonic-gate (void) unlink(hostspath); 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate if (etc_hostspath != NULL && 14847c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(etc_hostspath, sbuf)) { 14857c478bd9Sstevel@tonic-gate (void) unlink(etc_hostspath); 14867c478bd9Sstevel@tonic-gate } 14877c478bd9Sstevel@tonic-gate if (timestamppath != NULL && 14887c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(timestamppath, sbuf)) { 14897c478bd9Sstevel@tonic-gate (void) unlink(timestamppath); 14907c478bd9Sstevel@tonic-gate } 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate if (bootfs_etc_inet_dir != NULL && 14937c478bd9Sstevel@tonic-gate WBCGI_DIR_EXISTS(bootfs_etc_inet_dir, sbuf)) { 14947c478bd9Sstevel@tonic-gate (void) rmdir(bootfs_etc_inet_dir); 14957c478bd9Sstevel@tonic-gate } 14967c478bd9Sstevel@tonic-gate if (bootfs_etc_dir != NULL && 14977c478bd9Sstevel@tonic-gate WBCGI_DIR_EXISTS(bootfs_etc_dir, sbuf)) { 14987c478bd9Sstevel@tonic-gate (void) rmdir(bootfs_etc_dir); 14997c478bd9Sstevel@tonic-gate } 15007c478bd9Sstevel@tonic-gate if (bootfs_dev_dir != NULL && 15017c478bd9Sstevel@tonic-gate WBCGI_DIR_EXISTS(bootfs_dev_dir, sbuf)) { 15027c478bd9Sstevel@tonic-gate (void) rmdir(bootfs_dev_dir); 15037c478bd9Sstevel@tonic-gate } 15047c478bd9Sstevel@tonic-gate if (bootfs_dir != NULL && 15057c478bd9Sstevel@tonic-gate WBCGI_DIR_EXISTS(bootfs_dir, sbuf)) { 15067c478bd9Sstevel@tonic-gate (void) rmdir(bootfs_dir); 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate /* 15107c478bd9Sstevel@tonic-gate * Free allocated memory. 15117c478bd9Sstevel@tonic-gate */ 15127c478bd9Sstevel@tonic-gate free_path(&bootfs_dir); 15137c478bd9Sstevel@tonic-gate free_path(&bootfs_etc_dir); 15147c478bd9Sstevel@tonic-gate free_path(&bootfs_etc_inet_dir); 15157c478bd9Sstevel@tonic-gate free_path(&bootfs_dev_dir); 15167c478bd9Sstevel@tonic-gate 15177c478bd9Sstevel@tonic-gate free_path(&systemconf); 15187c478bd9Sstevel@tonic-gate free_path(&keystorepath); 15197c478bd9Sstevel@tonic-gate free_path(&certstorepath); 15207c478bd9Sstevel@tonic-gate free_path(&truststorepath); 15217c478bd9Sstevel@tonic-gate free_path(&bootconfpath); 15227c478bd9Sstevel@tonic-gate free_path(&systemconfpath); 15237c478bd9Sstevel@tonic-gate free_path(&urandompath); 15247c478bd9Sstevel@tonic-gate free_path(&noncepath); 15257c478bd9Sstevel@tonic-gate free_path(&hostspath); 15267c478bd9Sstevel@tonic-gate free_path(&etc_hostspath); 15277c478bd9Sstevel@tonic-gate free_path(×tamppath); 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate return (ret); 15307c478bd9Sstevel@tonic-gate } 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate static boolean_t 15337c478bd9Sstevel@tonic-gate miniroot_payload(const char *net, const char *cid, const char *docroot, 15347c478bd9Sstevel@tonic-gate char **rootpathp, char **rootinfop, boolean_t *https_rootserverp) 15357c478bd9Sstevel@tonic-gate { 15367c478bd9Sstevel@tonic-gate boolean_t ret = B_FALSE; 15377c478bd9Sstevel@tonic-gate char *root_server; 15387c478bd9Sstevel@tonic-gate char *root_file; 15397c478bd9Sstevel@tonic-gate url_t url; 15407c478bd9Sstevel@tonic-gate struct stat sbuf; 15417c478bd9Sstevel@tonic-gate char sizebuf[WBCGI_MAXBUF]; 15427c478bd9Sstevel@tonic-gate int chars; 15437c478bd9Sstevel@tonic-gate int fd = -1; 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate if ((root_server = bootconf_get(&bc_handle, BC_ROOT_SERVER)) == NULL) { 15467c478bd9Sstevel@tonic-gate print_status(500, "(root_server must be specified)"); 15477c478bd9Sstevel@tonic-gate goto cleanup; 15487c478bd9Sstevel@tonic-gate } 15497c478bd9Sstevel@tonic-gate if (url_parse(root_server, &url) != URL_PARSE_SUCCESS) { 15507c478bd9Sstevel@tonic-gate print_status(500, "(root_server URL is invalid)"); 15517c478bd9Sstevel@tonic-gate } 15527c478bd9Sstevel@tonic-gate *https_rootserverp = url.https; 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate if ((root_file = bootconf_get(&bc_handle, BC_ROOT_FILE)) == NULL) { 15557c478bd9Sstevel@tonic-gate print_status(500, "(rootfile must be specified)"); 15567c478bd9Sstevel@tonic-gate goto cleanup; 15577c478bd9Sstevel@tonic-gate } 15587c478bd9Sstevel@tonic-gate if ((*rootpathp = make_path(docroot, root_file)) == NULL) { 15597c478bd9Sstevel@tonic-gate goto cleanup; 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(*rootpathp, sbuf)) { 15627c478bd9Sstevel@tonic-gate print_status(500, "(root filesystem image missing)"); 15637c478bd9Sstevel@tonic-gate goto cleanup; 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate if ((*rootinfop = gen_tmppath("mrinfo", net, cid)) == NULL) { 15677c478bd9Sstevel@tonic-gate goto cleanup; 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate if ((chars = snprintf(sizebuf, sizeof (sizebuf), "%ld", 15707c478bd9Sstevel@tonic-gate sbuf.st_size)) < 0 || chars > sizeof (sizebuf) || 15717c478bd9Sstevel@tonic-gate (fd = open(*rootinfop, 15727c478bd9Sstevel@tonic-gate O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 || 15737c478bd9Sstevel@tonic-gate !write_buffer(fd, sizebuf, strlen(sizebuf))) { 15747c478bd9Sstevel@tonic-gate print_status(500, "(error creating miniroot info file)"); 15757c478bd9Sstevel@tonic-gate goto cleanup; 15767c478bd9Sstevel@tonic-gate } 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate ret = B_TRUE; 15797c478bd9Sstevel@tonic-gate cleanup: 15807c478bd9Sstevel@tonic-gate if (fd != -1) { 15817c478bd9Sstevel@tonic-gate (void) close(fd); 15827c478bd9Sstevel@tonic-gate } 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate return (ret); 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate static boolean_t 15887c478bd9Sstevel@tonic-gate deliver_payload(const char *payload, const char *payload_hash) 15897c478bd9Sstevel@tonic-gate { 15907c478bd9Sstevel@tonic-gate int fd = fileno(stdout); 15917c478bd9Sstevel@tonic-gate struct stat payload_buf, hash_buf; 15927c478bd9Sstevel@tonic-gate int chars; 15937c478bd9Sstevel@tonic-gate char main_header[WBCGI_MAXBUF]; 15947c478bd9Sstevel@tonic-gate char multi_header[WBCGI_MAXBUF]; 15957c478bd9Sstevel@tonic-gate char multi_header1[WBCGI_MAXBUF]; 15967c478bd9Sstevel@tonic-gate char multi_header2[WBCGI_MAXBUF]; 15977c478bd9Sstevel@tonic-gate char multi_end[WBCGI_MAXBUF]; 15987c478bd9Sstevel@tonic-gate size_t msglen; 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(payload, payload_buf) || 16017c478bd9Sstevel@tonic-gate !WBCGI_FILE_EXISTS(payload_hash, hash_buf)) { 16027c478bd9Sstevel@tonic-gate print_status(500, "(payload/hash file(s) missing)"); 16037c478bd9Sstevel@tonic-gate return (B_FALSE); 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate /* 16077c478bd9Sstevel@tonic-gate * Multi-part header. 16087c478bd9Sstevel@tonic-gate */ 16097c478bd9Sstevel@tonic-gate if ((chars = snprintf(multi_header, sizeof (multi_header), 16107c478bd9Sstevel@tonic-gate "%s--%s%s%sapplication/octet-stream%s%s", WBCGI_CRNL, 16117c478bd9Sstevel@tonic-gate WBCGI_WANBOOT_BNDTXT, WBCGI_CRNL, WBCGI_CONTENT_TYPE, WBCGI_CRNL, 16127c478bd9Sstevel@tonic-gate WBCGI_CONTENT_LENGTH)) < 0 || chars > sizeof (multi_header)) { 16137c478bd9Sstevel@tonic-gate print_status(500, "(error creating multi_header)"); 16147c478bd9Sstevel@tonic-gate return (B_FALSE); 16157c478bd9Sstevel@tonic-gate } 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate /* 16187c478bd9Sstevel@tonic-gate * Multi-part header for part one. 16197c478bd9Sstevel@tonic-gate */ 16207c478bd9Sstevel@tonic-gate if ((chars = snprintf(multi_header1, sizeof (multi_header1), 16217c478bd9Sstevel@tonic-gate "%s%ld%s%s", multi_header, payload_buf.st_size, WBCGI_CRNL, 16227c478bd9Sstevel@tonic-gate WBCGI_CRNL)) < 0 || chars > sizeof (multi_header1)) { 16237c478bd9Sstevel@tonic-gate print_status(500, "(error creating multi_header1)"); 16247c478bd9Sstevel@tonic-gate return (B_FALSE); 16257c478bd9Sstevel@tonic-gate } 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate /* 16287c478bd9Sstevel@tonic-gate * Multi-part header for part two. 16297c478bd9Sstevel@tonic-gate */ 16307c478bd9Sstevel@tonic-gate if ((chars = snprintf(multi_header2, sizeof (multi_header2), 16317c478bd9Sstevel@tonic-gate "%s%ld%s%s", multi_header, hash_buf.st_size, WBCGI_CRNL, 16327c478bd9Sstevel@tonic-gate WBCGI_CRNL)) < 0 || chars > sizeof (multi_header2)) { 16337c478bd9Sstevel@tonic-gate print_status(500, "(error creating multi_header2)"); 16347c478bd9Sstevel@tonic-gate return (B_FALSE); 16357c478bd9Sstevel@tonic-gate } 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate /* 16387c478bd9Sstevel@tonic-gate * End-of-parts Trailer. 16397c478bd9Sstevel@tonic-gate */ 16407c478bd9Sstevel@tonic-gate if ((chars = snprintf(multi_end, sizeof (multi_end), 16417c478bd9Sstevel@tonic-gate "%s--%s--%s", WBCGI_CRNL, WBCGI_WANBOOT_BNDTXT, 16427c478bd9Sstevel@tonic-gate WBCGI_CRNL)) < 0 || chars > sizeof (multi_end)) { 16437c478bd9Sstevel@tonic-gate print_status(500, "(error creating multi_end)"); 16447c478bd9Sstevel@tonic-gate return (B_FALSE); 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate /* 16487c478bd9Sstevel@tonic-gate * Message header. 16497c478bd9Sstevel@tonic-gate */ 16507c478bd9Sstevel@tonic-gate msglen = payload_buf.st_size + hash_buf.st_size + 16517c478bd9Sstevel@tonic-gate strlen(multi_header1) + strlen(multi_header2) + strlen(multi_end); 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate if ((chars = snprintf(main_header, sizeof (main_header), 16547c478bd9Sstevel@tonic-gate "%s%u%s%smultipart/mixed; boundary=%s%s%s", WBCGI_CONTENT_LENGTH, 16557c478bd9Sstevel@tonic-gate msglen, WBCGI_CRNL, WBCGI_CONTENT_TYPE, WBCGI_WANBOOT_BNDTXT, 16567c478bd9Sstevel@tonic-gate WBCGI_CRNL, WBCGI_CRNL)) < 0 || chars > sizeof (main_header)) { 16577c478bd9Sstevel@tonic-gate print_status(500, "(error creating main_header)"); 16587c478bd9Sstevel@tonic-gate return (B_FALSE); 16597c478bd9Sstevel@tonic-gate } 16607c478bd9Sstevel@tonic-gate 16617c478bd9Sstevel@tonic-gate /* 16627c478bd9Sstevel@tonic-gate * Write the message out. If things fall apart during this then 16637c478bd9Sstevel@tonic-gate * there's no way to report the error back to the client. 16647c478bd9Sstevel@tonic-gate */ 16657c478bd9Sstevel@tonic-gate if (!write_buffer(fd, main_header, strlen(main_header)) || 16667c478bd9Sstevel@tonic-gate !write_buffer(fd, multi_header1, strlen(multi_header1)) || 16677c478bd9Sstevel@tonic-gate !write_file(fd, payload, payload_buf.st_size) || 16687c478bd9Sstevel@tonic-gate !write_buffer(fd, multi_header2, strlen(multi_header2)) || 16697c478bd9Sstevel@tonic-gate !write_file(fd, payload_hash, hash_buf.st_size) || 16707c478bd9Sstevel@tonic-gate !write_buffer(fileno(stdout), multi_end, strlen(multi_end))) { 16717c478bd9Sstevel@tonic-gate return (B_FALSE); 16727c478bd9Sstevel@tonic-gate } 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate return (B_TRUE); 16757c478bd9Sstevel@tonic-gate } 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 16797c478bd9Sstevel@tonic-gate int 16807c478bd9Sstevel@tonic-gate main(int argc, char **argv) 16817c478bd9Sstevel@tonic-gate { 16827c478bd9Sstevel@tonic-gate int ret = WBCGI_STATUS_ERR; 16837c478bd9Sstevel@tonic-gate struct stat sbuf; 16847c478bd9Sstevel@tonic-gate int content; 16857c478bd9Sstevel@tonic-gate char *net; 16867c478bd9Sstevel@tonic-gate char *cid; 16877c478bd9Sstevel@tonic-gate char *nonce; 16887c478bd9Sstevel@tonic-gate char *docroot; 16897c478bd9Sstevel@tonic-gate char *payload; 16907c478bd9Sstevel@tonic-gate char *signature_type; 16917c478bd9Sstevel@tonic-gate char *encryption_type; 16927c478bd9Sstevel@tonic-gate char *bootconf = NULL; 16937c478bd9Sstevel@tonic-gate char *keyfile = NULL; 16947c478bd9Sstevel@tonic-gate char *bootpath = NULL; 16957c478bd9Sstevel@tonic-gate char *wanbootfs_image = NULL; 16967c478bd9Sstevel@tonic-gate char *rootpath = NULL; 16977c478bd9Sstevel@tonic-gate char *miniroot_info = NULL; 16987c478bd9Sstevel@tonic-gate char *encr_payload = NULL; 16997c478bd9Sstevel@tonic-gate char *payload_hash = NULL; 17007c478bd9Sstevel@tonic-gate boolean_t https_rootserver; 17017c478bd9Sstevel@tonic-gate 17027c478bd9Sstevel@tonic-gate /* 17037c478bd9Sstevel@tonic-gate * Process the query string. 17047c478bd9Sstevel@tonic-gate */ 17057c478bd9Sstevel@tonic-gate if (!get_request_info(&content, &net, &cid, &nonce, &docroot)) { 17067c478bd9Sstevel@tonic-gate goto cleanup; 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate /* 17107c478bd9Sstevel@tonic-gate * Sanity check that the netboot directory exists. 17117c478bd9Sstevel@tonic-gate */ 17127c478bd9Sstevel@tonic-gate if (!WBCGI_DIR_EXISTS(NB_NETBOOT_ROOT, sbuf)) { 17137c478bd9Sstevel@tonic-gate print_status(500, "(" NB_NETBOOT_ROOT " does not exist)"); 17147c478bd9Sstevel@tonic-gate goto cleanup; 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate /* 17187c478bd9Sstevel@tonic-gate * Get absolute bootconf pathname. 17197c478bd9Sstevel@tonic-gate */ 17207c478bd9Sstevel@tonic-gate if (netboot_ftw(NB_WANBOOT_CONF, net, cid, 17217c478bd9Sstevel@tonic-gate set_pathname, &bootconf) != WBCGI_FTW_CBOK) { 17227c478bd9Sstevel@tonic-gate print_status(500, "(wanboot.conf not found)"); 17237c478bd9Sstevel@tonic-gate goto cleanup; 17247c478bd9Sstevel@tonic-gate } 17257c478bd9Sstevel@tonic-gate 17267c478bd9Sstevel@tonic-gate /* 17277c478bd9Sstevel@tonic-gate * Initialize bc_handle from the given wanboot.conf file. 17287c478bd9Sstevel@tonic-gate */ 17297c478bd9Sstevel@tonic-gate if (bootconf_init(&bc_handle, bootconf) != BC_SUCCESS) { 17307c478bd9Sstevel@tonic-gate char message[WBCGI_MAXBUF]; 17317c478bd9Sstevel@tonic-gate int chars; 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate chars = snprintf(message, sizeof (message), 17347c478bd9Sstevel@tonic-gate "(wanboot.conf error: %s)", bootconf_errmsg(&bc_handle)); 17357c478bd9Sstevel@tonic-gate if (chars > 0 && chars < sizeof (message)) 17367c478bd9Sstevel@tonic-gate print_status(500, message); 17377c478bd9Sstevel@tonic-gate else 17387c478bd9Sstevel@tonic-gate print_status(500, "(wanboot.conf error)"); 17397c478bd9Sstevel@tonic-gate goto cleanup; 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate /* 17437c478bd9Sstevel@tonic-gate * Get and check signature and encryption types, 17447c478bd9Sstevel@tonic-gate * presence of helper utilities, keystore, etc. 17457c478bd9Sstevel@tonic-gate */ 17467c478bd9Sstevel@tonic-gate if ((signature_type = bootconf_get(&bc_handle, 17477c478bd9Sstevel@tonic-gate BC_SIGNATURE_TYPE)) != NULL) { 17487c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(WBCGI_HMAC_PATH, sbuf)) { 17497c478bd9Sstevel@tonic-gate print_status(500, "(hmac utility not found)"); 17507c478bd9Sstevel@tonic-gate goto cleanup; 17517c478bd9Sstevel@tonic-gate } 175222ce47f7SDavid Miner if (keyfile == NULL && netboot_ftw(NB_CLIENT_KEY, net, cid, 17537c478bd9Sstevel@tonic-gate set_pathname, &keyfile) != WBCGI_FTW_CBOK) { 17547c478bd9Sstevel@tonic-gate print_status(500, "(keystore not found)"); 17557c478bd9Sstevel@tonic-gate goto cleanup; 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate if (!check_key_type(keyfile, signature_type, WBKU_HASH_KEY)) { 17587c478bd9Sstevel@tonic-gate print_status(500, "(hash key not found)"); 17597c478bd9Sstevel@tonic-gate goto cleanup; 17607c478bd9Sstevel@tonic-gate } 17617c478bd9Sstevel@tonic-gate } 17627c478bd9Sstevel@tonic-gate if ((encryption_type = bootconf_get(&bc_handle, 17637c478bd9Sstevel@tonic-gate BC_ENCRYPTION_TYPE)) != NULL) { 17647c478bd9Sstevel@tonic-gate if (signature_type == NULL) { 17657c478bd9Sstevel@tonic-gate print_status(500, "(encrypted but not signed)"); 17667c478bd9Sstevel@tonic-gate goto cleanup; 17677c478bd9Sstevel@tonic-gate } 17687c478bd9Sstevel@tonic-gate if (!WBCGI_FILE_EXISTS(WBCGI_ENCR_PATH, sbuf)) { 17697c478bd9Sstevel@tonic-gate print_status(500, "(encr utility not found)"); 17707c478bd9Sstevel@tonic-gate goto cleanup; 17717c478bd9Sstevel@tonic-gate } 177222ce47f7SDavid Miner if (keyfile == NULL && netboot_ftw(NB_CLIENT_KEY, net, cid, 17737c478bd9Sstevel@tonic-gate set_pathname, &keyfile) != WBCGI_FTW_CBOK) { 17747c478bd9Sstevel@tonic-gate print_status(500, "(keystore not found)"); 17757c478bd9Sstevel@tonic-gate goto cleanup; 17767c478bd9Sstevel@tonic-gate } 17777c478bd9Sstevel@tonic-gate if (!check_key_type(keyfile, encryption_type, WBKU_ENCR_KEY)) { 17787c478bd9Sstevel@tonic-gate print_status(500, "(encr key not found)"); 17797c478bd9Sstevel@tonic-gate goto cleanup; 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate } 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate /* 17847c478bd9Sstevel@tonic-gate * Determine/create our payload. 17857c478bd9Sstevel@tonic-gate */ 17867c478bd9Sstevel@tonic-gate switch (content) { 17877c478bd9Sstevel@tonic-gate case WBCGI_CONTENT_BOOTFILE: 17887c478bd9Sstevel@tonic-gate if (!bootfile_payload(docroot, &bootpath)) { 17897c478bd9Sstevel@tonic-gate goto cleanup; 17907c478bd9Sstevel@tonic-gate } 17917c478bd9Sstevel@tonic-gate payload = bootpath; 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate break; 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate case WBCGI_CONTENT_BOOTFS: 17967c478bd9Sstevel@tonic-gate if (!wanbootfs_payload(net, cid, nonce, 17977c478bd9Sstevel@tonic-gate bootconf, &wanbootfs_image)) { 17987c478bd9Sstevel@tonic-gate goto cleanup; 17997c478bd9Sstevel@tonic-gate } 18007c478bd9Sstevel@tonic-gate payload = wanbootfs_image; 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate break; 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate case WBCGI_CONTENT_ROOTFS: 18057c478bd9Sstevel@tonic-gate if (!miniroot_payload(net, cid, docroot, 18067c478bd9Sstevel@tonic-gate &rootpath, &miniroot_info, &https_rootserver)) { 18077c478bd9Sstevel@tonic-gate goto cleanup; 18087c478bd9Sstevel@tonic-gate } 18097c478bd9Sstevel@tonic-gate payload = rootpath; 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate break; 18127c478bd9Sstevel@tonic-gate } 18137c478bd9Sstevel@tonic-gate 18147c478bd9Sstevel@tonic-gate /* 18157c478bd9Sstevel@tonic-gate * Encrypt the payload if necessary. 18167c478bd9Sstevel@tonic-gate */ 18177c478bd9Sstevel@tonic-gate if (content != WBCGI_CONTENT_BOOTFILE && 18187c478bd9Sstevel@tonic-gate content != WBCGI_CONTENT_ROOTFS && 18197c478bd9Sstevel@tonic-gate encryption_type != NULL) { 18207c478bd9Sstevel@tonic-gate if ((encr_payload = gen_tmppath("encr", net, cid)) == NULL) { 18217c478bd9Sstevel@tonic-gate goto cleanup; 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate if (!encrypt_payload(payload, encr_payload, keyfile, 18257c478bd9Sstevel@tonic-gate encryption_type)) { 18267c478bd9Sstevel@tonic-gate goto cleanup; 18277c478bd9Sstevel@tonic-gate } 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate payload = encr_payload; 18307c478bd9Sstevel@tonic-gate } 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate /* 18337c478bd9Sstevel@tonic-gate * Compute the hash (actual or null). 18347c478bd9Sstevel@tonic-gate */ 18357c478bd9Sstevel@tonic-gate if ((payload_hash = gen_tmppath("hash", net, cid)) == NULL) { 18367c478bd9Sstevel@tonic-gate goto cleanup; 18377c478bd9Sstevel@tonic-gate } 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate if (signature_type != NULL && 18407c478bd9Sstevel@tonic-gate (content != WBCGI_CONTENT_ROOTFS || !https_rootserver)) { 18417c478bd9Sstevel@tonic-gate if (!hash_payload(payload, payload_hash, keyfile)) { 18427c478bd9Sstevel@tonic-gate goto cleanup; 18437c478bd9Sstevel@tonic-gate } 18447c478bd9Sstevel@tonic-gate } else { 18457c478bd9Sstevel@tonic-gate if (!create_null_hash(payload_hash)) { 18467c478bd9Sstevel@tonic-gate goto cleanup; 18477c478bd9Sstevel@tonic-gate } 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate /* 18517c478bd9Sstevel@tonic-gate * For the rootfs the actual payload transmitted is the file 18527c478bd9Sstevel@tonic-gate * containing the size of the rootfs (as a string of ascii digits); 18537c478bd9Sstevel@tonic-gate * point payload at this instead. 18547c478bd9Sstevel@tonic-gate */ 18557c478bd9Sstevel@tonic-gate if (content == WBCGI_CONTENT_ROOTFS) { 18567c478bd9Sstevel@tonic-gate payload = miniroot_info; 18577c478bd9Sstevel@tonic-gate } 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate /* 18607c478bd9Sstevel@tonic-gate * Finally, deliver the payload and hash as a multipart message. 18617c478bd9Sstevel@tonic-gate */ 18627c478bd9Sstevel@tonic-gate if (!deliver_payload(payload, payload_hash)) { 18637c478bd9Sstevel@tonic-gate goto cleanup; 18647c478bd9Sstevel@tonic-gate } 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate ret = WBCGI_STATUS_OK; 18677c478bd9Sstevel@tonic-gate cleanup: 18687c478bd9Sstevel@tonic-gate /* 18697c478bd9Sstevel@tonic-gate * Clean up temporary files. 18707c478bd9Sstevel@tonic-gate */ 18717c478bd9Sstevel@tonic-gate if (wanbootfs_image != NULL && 18727c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(wanbootfs_image, sbuf)) { 18737c478bd9Sstevel@tonic-gate (void) unlink(wanbootfs_image); 18747c478bd9Sstevel@tonic-gate } 18757c478bd9Sstevel@tonic-gate if (miniroot_info != NULL && 18767c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(miniroot_info, sbuf)) { 18777c478bd9Sstevel@tonic-gate (void) unlink(miniroot_info); 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate if (encr_payload != NULL && 18807c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(encr_payload, sbuf)) { 18817c478bd9Sstevel@tonic-gate (void) unlink(encr_payload); 18827c478bd9Sstevel@tonic-gate } 18837c478bd9Sstevel@tonic-gate if (payload_hash != NULL && 18847c478bd9Sstevel@tonic-gate WBCGI_FILE_EXISTS(payload_hash, sbuf)) { 18857c478bd9Sstevel@tonic-gate (void) unlink(payload_hash); 18867c478bd9Sstevel@tonic-gate } 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate /* 18897c478bd9Sstevel@tonic-gate * Free up any allocated strings. 18907c478bd9Sstevel@tonic-gate */ 18917c478bd9Sstevel@tonic-gate free_path(&bootconf); 18927c478bd9Sstevel@tonic-gate free_path(&keyfile); 18937c478bd9Sstevel@tonic-gate free_path(&bootpath); 18947c478bd9Sstevel@tonic-gate free_path(&wanbootfs_image); 18957c478bd9Sstevel@tonic-gate free_path(&rootpath); 18967c478bd9Sstevel@tonic-gate free_path(&miniroot_info); 18977c478bd9Sstevel@tonic-gate free_path(&encr_payload); 18987c478bd9Sstevel@tonic-gate free_path(&payload_hash); 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate bootconf_end(&bc_handle); 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate return (ret); 19037c478bd9Sstevel@tonic-gate } 1904