1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 /* EXPORT DELETE START */ 30 #include <sys/promif.h> 31 #include <sys/obpdefs.h> 32 #include <sys/bootvfs.h> 33 #include <sys/bootconf.h> 34 #include <netinet/in.h> 35 #include <sys/wanboot_impl.h> 36 #include <boot_http.h> 37 #include <aes.h> 38 #include <des3.h> 39 #include <cbc.h> 40 #include <hmac_sha1.h> 41 #include <sys/sha1.h> 42 #include <sys/sha1_consts.h> 43 #include <bootlog.h> 44 #include <parseURL.h> 45 #include <netboot_paths.h> 46 #include <netinet/inetutil.h> 47 #include <sys/salib.h> 48 #include <inet/mac.h> 49 #include <inet/ipv4.h> 50 #include <dhcp_impl.h> 51 #include <inet/dhcpv4.h> 52 #include <bootinfo.h> 53 #include <wanboot_conf.h> 54 #include "boot_plat.h" 55 #include "ramdisk.h" 56 #include "wbcli.h" 57 58 /* 59 * Types of downloads 60 */ 61 #define MINIINFO "miniinfo" 62 #define MINIROOT "miniroot" 63 #define WANBOOTFS "wanbootfs" 64 65 #define WANBOOT_RETRY_NOMAX -1 66 #define WANBOOT_RETRY_ROOT_MAX 50 67 #define WANBOOT_RETRY_MAX 5 68 #define WANBOOT_RETRY_SECS 5 69 #define WANBOOT_RETRY_MAX_SECS 30 70 71 /* 72 * Our read requests should timeout after 25 seconds 73 */ 74 #define SOCKET_READ_TIMEOUT 25 75 76 /* 77 * Experimentation has shown that an 8K download buffer is optimal 78 */ 79 #define HTTP_XFER_SIZE 8192 80 static char buffer[HTTP_XFER_SIZE]; 81 82 bc_handle_t bc_handle; 83 84 extern int determine_fstype_and_mountroot(char *); 85 extern uint64_t get_ticks(void); 86 87 /* 88 * The following is used to determine whether the certs and private key 89 * files will be in PEM format or PKCS12 format. 'use_p12' is zero 90 * to use PEM format, and 1 when PKCS12 format is to be used. It is 91 * done this way, as a global, so that it can be patched if needs be 92 * using the OBP debugger. 93 */ 94 uint32_t use_p12 = 1; 95 96 #define CONTENT_LENGTH "Content-Length" 97 98 #define NONCELEN (2 * HMAC_DIGEST_LEN) /* two hex nibbles/byte */ 99 #define WANBOOTFS_NONCE_FILE "/nonce" 100 101 static char nonce[NONCELEN + 1]; 102 103 enum URLtype { 104 URLtype_wanbootfs = 0, 105 URLtype_miniroot = 1 106 }; 107 108 static char *URLtoCGIcontent[] = { 109 "bootfs", 110 "rootfs" 111 }; 112 #define CGIcontent(urltype) URLtoCGIcontent[urltype] 113 114 /* Encryption algorithms */ 115 typedef enum { 116 ENCR_NONE, 117 ENCR_3DES, 118 ENCR_AES 119 } encr_type_t; 120 121 /* Hash algorithms */ 122 typedef enum { 123 HASH_NONE, 124 HASH_HMAC_SHA1 125 } hash_type_t; 126 127 /* 128 * Keys ... 129 */ 130 static encr_type_t encr_type = ENCR_NONE; 131 static unsigned char *g_encr_key = NULL; 132 133 static hash_type_t hash_type = HASH_NONE; 134 static unsigned char *g_hash_key = NULL; 135 136 void 137 print_errors(const char *func, http_handle_t handle) 138 { 139 char const *msg; 140 ulong_t err; 141 uint_t src; 142 143 while ((err = http_get_lasterr(handle, &src)) != 0) { 144 msg = http_errorstr(src, err); 145 bootlog("wanboot", BOOTLOG_ALERT, 146 "%s: errsrc %u, err %lu (0x%lx)", func, src, err, err); 147 bootlog("wanboot", BOOTLOG_ALERT, "%s", msg); 148 } 149 } 150 151 /* 152 * This routine is called by a consumer to determine whether or not a 153 * retry should be attempted. If a retry is in order (depends upon the 154 * 'retry_cnt' and 'retry_max' arguments), then this routine will print a 155 * message indicating this is the case and will determine an appropriate 156 * "sleep" time before retrying. The "sleep" time will depend upon the 157 * 'retry_cnt' and will max out at WANBOOT_RETRY_MAX_SECS. 158 * 159 * Returns: 160 * B_TRUE = retry is in order 161 * B_FALSE = retry limit exceeded 162 */ 163 boolean_t 164 wanboot_retry(int retry_cnt, int retry_max) 165 { 166 unsigned int seconds; 167 168 if (retry_max == WANBOOT_RETRY_NOMAX || retry_cnt <= retry_max) { 169 seconds = WANBOOT_RETRY_SECS * retry_cnt; 170 if (seconds > WANBOOT_RETRY_MAX_SECS) { 171 seconds = WANBOOT_RETRY_MAX_SECS; 172 } 173 bootlog("wanboot", BOOTLOG_INFO, 174 "Will retry in %d seconds ...", seconds); 175 (void) sleep(seconds); 176 return (B_TRUE); 177 } else { 178 bootlog("wanboot", BOOTLOG_INFO, 179 "Maximum retries exceeded."); 180 return (B_FALSE); 181 } 182 } 183 184 /* 185 * Determine which encryption algorithm the client is configured to use. 186 * WAN boot determines which key to use by order of priority. That is 187 * multiple encryption keys may exist in the PROM, but the first one found 188 * (while searching in a preferred order) is the one that will be used. 189 */ 190 static void 191 init_encryption(void) 192 { 193 static unsigned char key[WANBOOT_MAXKEYLEN]; 194 size_t len = sizeof (key); 195 196 if (bootinfo_get(BI_AES_KEY, (char *)&key, &len, NULL) == 197 BI_E_SUCCESS) { 198 encr_type = ENCR_AES; 199 g_encr_key = key; 200 } else if (bootinfo_get(BI_3DES_KEY, (char *)&key, &len, NULL) == 201 BI_E_SUCCESS) { 202 encr_type = ENCR_3DES; 203 g_encr_key = key; 204 } 205 } 206 207 /* 208 * Determine whether the client is configured to use hashing. 209 */ 210 static void 211 init_hashing(void) 212 { 213 static unsigned char key[WANBOOT_HMAC_KEY_SIZE]; 214 size_t len = sizeof (key); 215 216 if (bootinfo_get(BI_SHA1_KEY, (char *)&key, &len, NULL) == 217 BI_E_SUCCESS) { 218 hash_type = HASH_HMAC_SHA1; 219 g_hash_key = key; 220 } 221 } 222 223 /* 224 * Read some CPU-specific rapidly-varying data (assumed to be of length 225 * sizeof (hrtime_t) in the non-SPARC case), and digestify it to further 226 * randomize the output. 227 */ 228 char * 229 generate_nonce(void) 230 { 231 uint64_t t; 232 SHA1_CTX c; 233 unsigned char digest[HMAC_DIGEST_LEN]; 234 uint_t nlen = sizeof (nonce); 235 236 int err; 237 238 /* 239 * Read SPARC %tick register or x86 TSC 240 */ 241 t = get_ticks(); 242 SHA1Init(&c); 243 SHA1Update(&c, (const uint8_t *)&t, sizeof (t)); 244 SHA1Final(digest, &c); 245 246 err = octet_to_hexascii(digest, sizeof (digest), nonce, &nlen); 247 if (err != 0) { 248 bootlog("wanboot", BOOTLOG_CRIT, 249 "cannot convert nonce to ASCII: error %d", err); 250 return (NULL); 251 } 252 nonce[NONCELEN] = '\0'; 253 return (nonce); 254 } 255 256 /* 257 * Given a server URL, builds a URL to request one of the wanboot 258 * datastreams. 259 * 260 * Returns: 261 * -1 = Non-recoverable error 262 * 0 = Success 263 */ 264 static int 265 build_request_url(url_t *req_url, enum URLtype ut, const url_t *server_url) 266 { 267 char clid[WB_MAX_CID_LEN]; 268 size_t clen; 269 char wid[WB_MAX_CID_LEN * 2 + 1]; 270 uint_t wlen; 271 struct in_addr ip; 272 struct in_addr mask; 273 char *netstr; 274 char *ppath; 275 size_t plen; 276 const char reqstr[] = "/?CONTENT=%s&IP=%s&CID=%s"; 277 278 /* 279 * Initialize the request 280 */ 281 *req_url = *server_url; 282 283 /* 284 * Build the network number string 285 */ 286 ipv4_getipaddr(&ip); 287 ipv4_getnetmask(&mask); 288 ip.s_addr = ip.s_addr & mask.s_addr; 289 netstr = inet_ntoa(ip); 290 291 /* 292 * Get the wan id 293 */ 294 clen = sizeof (clid); 295 if (bootinfo_get(BI_CLIENT_ID, clid, &clen, NULL) != BI_E_SUCCESS) { 296 bootlog("wanboot", BOOTLOG_CRIT, 297 "Cannot retrieve the client ID"); 298 return (-1); 299 } 300 wlen = sizeof (wid); 301 (void) octet_to_hexascii(clid, clen, wid, &wlen); 302 303 /* 304 * Build the request, making sure that the length of the 305 * constructed URL falls within the supported maximum. 306 */ 307 plen = strlen(req_url->abspath); 308 ppath = req_url->abspath + plen; 309 if (snprintf(ppath, URL_MAX_PATHLEN - plen, reqstr, 310 CGIcontent(ut), netstr, wid) >= URL_MAX_PATHLEN - plen) { 311 bootlog("wanboot", BOOTLOG_CRIT, 312 "The URL path length of the %s request is greater than " 313 "the maximum of %d", CGIcontent(ut), URL_MAX_PATHLEN); 314 return (-1); 315 } 316 317 /* 318 * If the URL type requires a nonce, then supply it. 319 * It will be returned in the reply to detect attempted 320 * replays. 321 */ 322 if (ut == URLtype_wanbootfs) { 323 char *n = generate_nonce(); 324 325 if (n != NULL) { 326 plen += strlen("&NONCE=") + NONCELEN; 327 if (plen > URL_MAX_PATHLEN) 328 return (-1); 329 (void) strcat(req_url->abspath, "&NONCE="); 330 (void) strcat(req_url->abspath, n); 331 } 332 } 333 334 return (0); 335 } 336 337 /* 338 * This routine reads data from an HTTP connection into a buffer. 339 * 340 * Returns: 341 * 0 = Success 342 * 1 = HTTP download error 343 */ 344 static int 345 read_bytes(http_handle_t handle, char *buffer, size_t cnt) 346 { 347 int len; 348 size_t i; 349 350 for (i = 0; i < cnt; i += len) { 351 len = http_read_body(handle, &buffer[i], cnt - i); 352 if (len <= 0) { 353 print_errors("http_read_body", handle); 354 return (1); 355 } 356 } 357 return (0); 358 } 359 360 /* 361 * This routine compares two hash digests, one computed by the server and 362 * the other computed by the client to verify that a transmitted message 363 * was received without corruption. 364 * 365 * Notes: 366 * The client only computes a digest if it is configured with a 367 * hash key. If it is not, then the server should not have a hash 368 * key for the client either and therefore should have sent a 369 * zero filled digest. 370 * 371 * Returns: 372 * B_TRUE = digest was verified 373 * B_FALSE = digest did not verify 374 */ 375 static boolean_t 376 verify_digests(const char *what, unsigned char *cdigest, unsigned char *sdigest) 377 { 378 static char null_digest[HMAC_DIGEST_LEN]; 379 380 if (bcmp(sdigest, cdigest, HMAC_DIGEST_LEN) != 0) { 381 bootlog("wanboot", BOOTLOG_CRIT, 382 "%s: invalid hash digest", what); 383 bootlog("wanboot", BOOTLOG_CRIT, 384 "This may signify a client/server key mismatch"); 385 if (bcmp(sdigest, null_digest, HMAC_DIGEST_LEN) == 0) { 386 bootlog("wanboot", BOOTLOG_CRIT, 387 "(client has key but wrong signature_type?)"); 388 } else if (bcmp(cdigest, null_digest, HMAC_DIGEST_LEN) == 0) { 389 bootlog("wanboot", BOOTLOG_CRIT, 390 "(signature_type specified but no client key?)"); 391 } 392 bootlog("wanboot", BOOTLOG_CRIT, 393 "or possible corruption of the image in transit"); 394 return (B_FALSE); 395 } 396 397 return (B_TRUE); 398 } 399 400 /* 401 * This routine reads the part of a multipart message that contains a 402 * hash digest. Errors in reading the digest are differentiated from 403 * other kinds of errors so that the caller can decide whether or 404 * not a retry is worthwhile. 405 * 406 * Note: 407 * The hash digest can either be an HMAC digest or it can be 408 * a zero length message (representing no hash digest). 409 * 410 * Returns: 411 * -1 = Non-recoverable error 412 * 0 = Success 413 * 1 = HTTP download error 414 */ 415 static int 416 read_digest(const char *what, http_handle_t handle, unsigned char *sdigest) 417 { 418 char *lenstr; 419 size_t digest_size; 420 421 /* 422 * Process the HMAC digest header. 423 */ 424 if (http_process_part_headers(handle, NULL) != 0) { 425 print_errors("http_process_part_headers", handle); 426 return (1); 427 } 428 lenstr = http_get_header_value(handle, CONTENT_LENGTH); 429 if (lenstr == NULL) { 430 bootlog("wanboot", BOOTLOG_ALERT, 431 "%s: error getting digest length", what); 432 return (1); 433 } 434 digest_size = (size_t)strtol(lenstr, NULL, 10); 435 free(lenstr); 436 437 /* 438 * Validate the HMAC digest length. 439 */ 440 if (digest_size != HMAC_DIGEST_LEN) { 441 bootlog("wanboot", BOOTLOG_CRIT, 442 "%s: error validating response - invalid digest size", 443 what); 444 return (-1); 445 } 446 447 /* 448 * Read the HMAC digest. 449 */ 450 if (read_bytes(handle, (char *)sdigest, digest_size) != 0) { 451 bootlog("wanboot", BOOTLOG_ALERT, 452 "%s: error reading digest", what); 453 return (1); 454 } 455 456 return (0); 457 } 458 459 /* 460 * This routine reads data from an HTTP connection and writes the data 461 * to a ramdisk. It also, optionally computes a hash digest of the processed 462 * data. This routine may be called to continue writing a previously aborted 463 * write. If this is the case, then the offset will be non-zero and the write 464 * pointer into the ramdisk will be positioned correctly by the caller. 465 * 466 * Returns: 467 * -1 = Non-recoverable error 468 * 0 = Success 469 * 1 = HTTP download error 470 */ 471 static int 472 write_msg_to_ramdisk(const char *what, caddr_t addr, http_handle_t handle, 473 size_t ramdisk_size, off_t *offset, SHA1_CTX *sha) 474 { 475 int len; 476 long nleft; 477 static int bootlog_message_interval; 478 static int bootlog_progress; 479 int ret; 480 481 /* 482 * Read the data and write it to the ramdisk. 483 */ 484 if (*offset == 0) { 485 bootlog_progress = 0; 486 bootlog_message_interval = ramdisk_size / sizeof (buffer); 487 if (bootlog_message_interval < 500) 488 bootlog_message_interval /= 5; 489 else 490 bootlog_message_interval /= 50; 491 492 bootlog("wanboot", BOOTLOG_VERBOSE, 493 "Reading %s file system (%ld kB)", 494 what, ramdisk_size / 1024); 495 } else { 496 bootlog("wanboot", BOOTLOG_VERBOSE, 497 "Continuing read of %s file system (%ld kB)", 498 what, ramdisk_size / 1024); 499 } 500 for (ret = 0; ret == 0 && *offset < ramdisk_size; 501 *offset += len, addr += len) { 502 nleft = ramdisk_size - *offset; 503 504 if (nleft > sizeof (buffer)) 505 nleft = sizeof (buffer); 506 507 len = http_read_body(handle, addr, nleft); 508 if (len <= 0) { 509 print_errors("http_read_body", handle); 510 /* 511 * In the case of a partial failure, http_read_body() 512 * returns into 'len', 1 - the number of bytes read. 513 * So, a -65 means 64 bytes read and an error occurred. 514 */ 515 if (len != 0) { 516 len = -(len + 1); 517 } 518 ret = 1; 519 } 520 if (sha != NULL) { 521 HMACUpdate(sha, (uchar_t *)addr, (size_t)len); 522 } 523 if (bootlog_progress == bootlog_message_interval) { 524 bootlog("wanboot", BOOTLOG_PROGRESS, 525 "%s: Read %ld of %ld kB (%ld%%)", what, 526 *offset / 1024, ramdisk_size / 1024, 527 *offset * 100 / ramdisk_size); 528 bootlog_progress = 0; 529 } else { 530 bootlog_progress++; 531 } 532 } 533 if (ret == 0) { 534 bootlog("wanboot", BOOTLOG_PROGRESS, 535 "%s: Read %ld of %ld kB (%ld%%)", what, 536 *offset / 1024, ramdisk_size / 1024, 537 *offset * 100 / ramdisk_size); 538 bootlog("wanboot", BOOTLOG_INFO, "%s: Download complete", what); 539 } 540 return (ret); 541 } 542 543 /* 544 * This routine is called with a bootinfo parameter name. If the parameter 545 * has a value it should be a URL, and this will be used to initialize the 546 * http_url structure. 547 * 548 * Returns: 549 * -1 = Non-recoverable error 550 * 0 = Success 551 * 1 = DHCP option not set 552 */ 553 static int 554 get_url(char *name, url_t *url) 555 { 556 char buf[URL_MAX_STRLEN]; 557 size_t len; 558 int ret; 559 560 bzero(buf, sizeof (buf)); 561 len = sizeof (buf) - 1; 562 if (bootinfo_get(name, buf, &len, NULL) != BI_E_SUCCESS || len == 0) { 563 return (1); 564 } 565 566 /* 567 * Parse the URL. 568 */ 569 ret = url_parse(buf, url); 570 if (ret != URL_PARSE_SUCCESS) { 571 bootlog("wanboot", BOOTLOG_CRIT, 572 "Unable to parse URL %s", buf); 573 return (-1); 574 } 575 576 return (0); 577 } 578 579 /* 580 * This routine initiates an HTTP request and returns a handle so that 581 * the caller can process the response. 582 * 583 * Notes: 584 * Requests may be either secure or not. If the request is secure, then 585 * this routine assumes that a wanboot file system exists and 586 * uses its contents to provide the HTTP library with the information 587 * that will be required by SSL. 588 * 589 * In order to facilitate transmission retries, this routine supports 590 * range requests. A caller may request a range by providing a non-zero 591 * offset. In which case, a range request is made that ranges from the 592 * offet to the end of the file. 593 * 594 * If the client is configured to use an HTTP proxy, then this routine 595 * will make the HTTP library aware of the proxy. 596 * 597 * Any HTTP errors encountered in downloading or processing the message 598 * are not deemed unrecoverable errors. The caller can simply try the 599 * request once again. 600 * 601 * Returns: 602 * -1 = Non-recoverable error 603 * 0 = Success 604 * 1 = HTTP download error 605 */ 606 static int 607 establish_http_connection(const char *what, http_handle_t *handlep, 608 url_t *url, offset_t offset) 609 { 610 static boolean_t is_auth_file_init = B_FALSE; 611 static boolean_t is_proxy_init = B_FALSE; 612 static boolean_t proxy_exists = B_FALSE; 613 static url_hport_t proxy_hp; 614 http_respinfo_t *resp; 615 char buf[URL_MAX_STRLEN]; 616 size_t len = sizeof (buf) - 1; 617 int ret; 618 619 /* Check for HTTP proxy */ 620 if (!is_proxy_init && 621 bootinfo_get(BI_HTTP_PROXY, buf, &len, NULL) == BI_E_SUCCESS && 622 strlen(buf) > 0) { 623 /* 624 * Parse the hostport. 625 */ 626 ret = url_parse_hostport(buf, &proxy_hp, URL_DFLT_PROXY_PORT); 627 if (ret == URL_PARSE_SUCCESS) { 628 proxy_exists = B_TRUE; 629 } else { 630 bootlog("wanboot", BOOTLOG_CRIT, 631 "%s is not set to a valid hostport value", 632 BI_HTTP_PROXY); 633 return (-1); 634 } 635 is_proxy_init = B_TRUE; 636 } 637 638 http_set_p12_format(use_p12); 639 640 /* 641 * Initialize the handle that will be used for the request. 642 */ 643 *handlep = http_srv_init(url); 644 if (*handlep == NULL) { 645 print_errors("http_srv_init", NULL); 646 return (-1); 647 } 648 649 /* 650 * Is the request a secure one? If it is, then we need to do further 651 * setup. Search the wanboot file system for files that will be 652 * needed by SSL. 653 */ 654 if (url->https) { 655 char *cas; 656 boolean_t client_authentication = B_FALSE; 657 658 if (http_set_random_file(*handlep, "/dev/urandom") < 0) { 659 print_errors("http_set_random_file", *handlep); 660 (void) http_srv_close(*handlep); 661 return (-1); 662 } 663 664 /* 665 * We only need to initialize the CA once as it is not handle 666 * specific. 667 */ 668 if (!is_auth_file_init) { 669 if (http_set_certificate_authority_file(NB_CA_CERT_PATH) 670 < 0) { 671 print_errors( 672 "http_set_certificate_authority_file", 673 *handlep); 674 (void) http_srv_close(*handlep); 675 return (-1); 676 } 677 678 is_auth_file_init = B_TRUE; 679 } 680 681 /* 682 * The client certificate and key will not exist unless 683 * client authentication has been configured. If it is 684 * configured then the webserver will have added these 685 * files to the wanboot file system and the HTTP library 686 * needs to be made aware of their existence. 687 */ 688 if ((cas = bootconf_get(&bc_handle, 689 BC_CLIENT_AUTHENTICATION)) != NULL && 690 strcmp(cas, "yes") == 0) { 691 client_authentication = B_TRUE; 692 693 if (http_set_client_certificate_file(*handlep, 694 NB_CLIENT_CERT_PATH) < 0) { 695 print_errors("http_set_client_certificate_file", 696 *handlep); 697 (void) http_srv_close(*handlep); 698 return (-1); 699 } 700 701 if (http_set_private_key_file(*handlep, 702 NB_CLIENT_KEY_PATH) < 0) { 703 print_errors("http_set_private_key_file", 704 *handlep); 705 (void) http_srv_close(*handlep); 706 return (-1); 707 } 708 } 709 710 /* 711 * We do not really need to set this unless client 712 * authentication is configured or unless pkcs12 files 713 * are used. 714 */ 715 if ((client_authentication || use_p12) && 716 http_set_password(*handlep, WANBOOT_PASSPHRASE) < 0) { 717 print_errors("http_set_password", *handlep); 718 (void) http_srv_close(*handlep); 719 return (-1); 720 } 721 } 722 723 /* 724 * If the client is using a proxy, tell the library. 725 */ 726 if (proxy_exists) { 727 if (http_set_proxy(*handlep, &proxy_hp) != 0) { 728 print_errors("http_set_proxy", *handlep); 729 (void) http_srv_close(*handlep); 730 return (-1); 731 } 732 } 733 734 (void) http_set_socket_read_timeout(*handlep, SOCKET_READ_TIMEOUT); 735 736 /* 737 * Ok, connect to the webserver. 738 */ 739 if (http_srv_connect(*handlep) == -1) { 740 print_errors("http_srv_connect", *handlep); 741 (void) http_srv_close(*handlep); 742 return (1); 743 } 744 745 /* 746 * If the offset is 0, then we assume that we want the entire 747 * message. If the offset is not 0, then we assume that we are 748 * retrying a previously interrupted transfer and thus we make 749 * a range request. 750 */ 751 if (offset == 0) { 752 if ((ret = http_get_request(*handlep, url->abspath)) == 0) { 753 bootlog("wanboot", BOOTLOG_VERBOSE, 754 "%s: http_get_request: sent", what); 755 } else { 756 print_errors("http_get_request", *handlep); 757 (void) http_srv_close(*handlep); 758 return (1); 759 } 760 } else { 761 if ((ret = http_get_range_request(*handlep, url->abspath, 762 offset, 0)) == 0) { 763 bootlog("wanboot", BOOTLOG_VERBOSE, 764 "%s: http_get_range_request: sent", what); 765 } else { 766 print_errors("http_get_range_request", *handlep); 767 (void) http_srv_close(*handlep); 768 return (1); 769 } 770 } 771 772 /* 773 * Tell the library to read in the response headers. 774 */ 775 ret = http_process_headers(*handlep, &resp); 776 if (ret == -1) { 777 print_errors("http_process_headers", *handlep); 778 (void) http_srv_close(*handlep); 779 return (1); 780 } 781 782 /* 783 * Check for a valid response code. 784 */ 785 if ((offset == 0 && resp->code != 200) || 786 (offset != 0 && resp->code != 206)) { 787 bootlog("wanboot", BOOTLOG_ALERT, 788 "%s: Request returned code %d", what, resp->code); 789 if (resp->statusmsg != NULL && resp->statusmsg[0] != '\0') 790 bootlog("wanboot", BOOTLOG_ALERT, 791 "%s", resp->statusmsg); 792 http_free_respinfo(resp); 793 (void) http_srv_close(*handlep); 794 return (1); 795 } 796 http_free_respinfo(resp); 797 798 /* 799 * Success. 800 */ 801 return (0); 802 } 803 804 /* 805 * This routine is called by get_miniinfo() to receive the reply 806 * to the request for the miniroot metadata. The reply is a two 807 * part multipart message. The first part of the message contains 808 * the miniroot file size. The second part of the message contains 809 * a hash digest of the miniroot as computed by the server. This 810 * routine receives both message parts and returns them to the caller. 811 * 812 * Notes: 813 * If the miniroot is going to be downloaded securely or if the 814 * the server has no hash key for the client, then the hash digest 815 * downloaded contains all zeros. 816 * 817 * Any HTTP errors encountered in downloading or processing the message 818 * are not deemed unrecoverable errors. That is, get_miniinfo() 819 * tries re-requesting the message and tries processing it again. 820 * 821 * Returns: 822 * -1 = Non-recoverable error 823 * 0 = Success 824 * 1 = HTTP download error 825 */ 826 static int 827 process_miniinfo(http_handle_t handle, size_t *mini_size, 828 unsigned char *sdigest) 829 { 830 char *lenstr; 831 size_t cnt; 832 833 /* 834 * Process the file size header. 835 */ 836 if (http_process_part_headers(handle, NULL) != 0) { 837 print_errors("http_process_part_headers", handle); 838 return (1); 839 } 840 lenstr = http_get_header_value(handle, CONTENT_LENGTH); 841 if (lenstr == NULL) { 842 bootlog("wanboot", BOOTLOG_ALERT, "%s: error getting length " 843 "of first part of multipart message", MINIINFO); 844 return (1); 845 } 846 cnt = (size_t)strtol(lenstr, NULL, 10); 847 free(lenstr); 848 if (cnt == 0 || cnt >= sizeof (buffer)) { 849 bootlog("wanboot", BOOTLOG_ALERT, "%s: length of first part " 850 "of multipart message not a legal size", MINIINFO); 851 return (1); 852 } 853 854 if (read_bytes(handle, buffer, cnt) != 0) { 855 bootlog("wanboot", BOOTLOG_ALERT, 856 "%s: error reading miniroot size", MINIINFO); 857 return (1); 858 } 859 buffer[cnt] = '\0'; 860 861 *mini_size = (size_t)strtol(buffer, NULL, 10); 862 if (*mini_size == 0) { 863 bootlog("wanboot", BOOTLOG_ALERT, "%s: body of first part " 864 "of multipart message not a legal size", MINIINFO); 865 return (1); 866 } 867 868 return (read_digest(MINIINFO, handle, sdigest)); 869 } 870 871 /* 872 * This routine is called by get_miniroot() to retrieve the miniroot 873 * metadata (miniroot size and a hash digest). This routine sends an 874 * HTTP GET request to the webserver to request the download of the 875 * miniroot metadata and relies on process_miniinfo() to receive the 876 * reply, process it and ultimately return to it the miniroot size and 877 * the hash digest. 878 * 879 * Note: 880 * Any HTTP errors encountered in downloading or processing the message 881 * are not deemed unrecoverable errors. That is, get_miniinfo() should 882 * try re-requesting the message and try processing again. 883 * 884 * Returns: 885 * -1 = Non-recoverable error 886 * 0 = Success 887 */ 888 int 889 get_miniinfo(const url_t *server_url, size_t *mini_size, 890 unsigned char *sdigest) 891 { 892 http_handle_t handle; 893 url_t req_url; 894 int retry_cnt = 0; 895 int retry_max = WANBOOT_RETRY_MAX; 896 int ret; 897 898 /* 899 * Build the URL to request the miniroot info. 900 */ 901 if (build_request_url(&req_url, URLtype_miniroot, server_url) == -1) { 902 bootlog("wanboot", BOOTLOG_CRIT, 903 "Can't build the URL to make the %s request", 904 CGIcontent(URLtype_miniroot)); 905 return (-1); 906 } 907 908 /* 909 * Go get the miniroot info. If we fail reading the 910 * response we re-request the info in its entirety. 911 */ 912 bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading miniroot info"); 913 914 do { 915 if ((ret = establish_http_connection(MINIINFO, &handle, 916 &req_url, 0)) < 0) { 917 break; 918 } else if (ret > 0) { 919 if (wanboot_retry(++retry_cnt, retry_max)) { 920 continue; 921 } else { 922 break; 923 } 924 } 925 926 if ((ret = process_miniinfo(handle, mini_size, 927 sdigest)) > 0) { 928 if (!wanboot_retry(++retry_cnt, retry_max)) { 929 (void) http_srv_close(handle); 930 break; 931 } 932 } 933 934 (void) http_srv_close(handle); 935 936 } while (ret > 0); 937 938 /* 939 * Success. 940 */ 941 if (ret == 0) { 942 bootlog("wanboot", BOOTLOG_VERBOSE, 943 "Miniroot info download successful"); 944 return (0); 945 } else { 946 bootlog("wanboot", BOOTLOG_CRIT, 947 "Miniroot info download aborted"); 948 return (-1); 949 } 950 } 951 952 /* 953 * This routine is called by get_miniroot() to receive the reply to 954 * the request for the miniroot download. The miniroot is written 955 * to ramdisk as it is received and a hash digest is optionally computed 956 * as it does so. The miniroot is downloaded as one large message. 957 * Because the message is so large, this routine is prepared to deal 958 * with errors in the middle of download. If an error occurs during 959 * download, then this message processes all received data up to the 960 * point of the error and returns to get_miniroot() an error signifying 961 * that a download error has occurred. Presumably, get_miniroot() 962 * re-requests the remaining part of the miniroot not yet processed and 963 * calls this routine back to process the reply. When this routine 964 * returns succesfully, it returns a devpath to the ramdisk and the 965 * computed hash (if computed). 966 * 967 * Note: 968 * In order to facilitate reentry, the ramdisk is left open 969 * and the original miniroot_size and HMAC handle are kept 970 * static. 971 * 972 * Returns: 973 * -1 = Non-recoverable error 974 * 0 = Success 975 * 1 = HTTP download error 976 */ 977 static int 978 process_miniroot(http_handle_t handle, hash_type_t htype, 979 size_t length, char **devpath, off_t *offset, unsigned char *cdigest) 980 { 981 static SHA1_CTX sha; 982 static size_t miniroot_size; 983 static caddr_t miniroot_vaddr = NULL; 984 int ret; 985 986 if (miniroot_vaddr == NULL) { 987 if (htype == HASH_HMAC_SHA1) { 988 bootlog("wanboot", BOOTLOG_INFO, 989 "%s: Authentication will use HMAC-SHA1", MINIROOT); 990 HMACInit(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE); 991 } 992 993 miniroot_size = length; 994 995 miniroot_vaddr = create_ramdisk(RD_ROOTFS, miniroot_size, 996 devpath); 997 } 998 999 miniroot_vaddr += *offset; 1000 1001 if ((ret = write_msg_to_ramdisk(MINIROOT, miniroot_vaddr, handle, 1002 miniroot_size, offset, (htype == HASH_NONE) ? NULL : &sha)) != 0) { 1003 return (ret); 1004 } 1005 1006 if (htype != HASH_NONE) { 1007 HMACFinal(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE, cdigest); 1008 } 1009 1010 return (0); 1011 } 1012 1013 /* 1014 * This routine retrieves the miniroot from the webserver. The miniroot 1015 * is retrieved in two steps. First a request is made to the server 1016 * to retrieve miniroot metadata (miniroot size and a hash digest). 1017 * The second request actually results in the download of the miniroot. 1018 * 1019 * This routine relies on get_miniinfo() to make and process 1020 * the request for the miniroot metadata and returns the 1021 * miniroot size and the hash digest of the miniroot as computed by 1022 * the server. 1023 * 1024 * If get_miniinfo() returns successfully, then this routine sends 1025 * an HTTP GET request to the webserver to request download of the 1026 * miniroot. This routine relies on process_miniroot() to receive 1027 * the reply, process it and ultimately return to it a device path to 1028 * a ramdisk containing the miniroot and a client computed hash digest. 1029 * This routine verifies that the client computed hash digest matches 1030 * the one retrieved by get_miniinfo(). 1031 * 1032 * If an error occurs in the transfer of the miniroot from the server 1033 * to the client, then the client re-requests the download of the 1034 * miniroot using a range request and only requests the part of the 1035 * miniroot not previously downloaded and written to ramdisk. The 1036 * process_miniroot() routine has the intelligence to recognize that 1037 * it is processing a range request. Errors not related to the actual 1038 * message download are deemed unrecoverable. 1039 * 1040 * Note: 1041 * If the client request for the miniroot is a secure request or 1042 * if the server is not configured with a hash key for the client, 1043 * then the hash digest downloaded from the server will contain 1044 * all zeros. This routine verifies that the server and client are 1045 * in-sync with respect to the need for hash verification. 1046 * 1047 * Returns: 1048 * -1 = Non-recoverable error 1049 * 0 = Success 1050 */ 1051 int 1052 get_miniroot(char **devpath) 1053 { 1054 http_handle_t handle; 1055 unsigned char cdigest[HMAC_DIGEST_LEN]; 1056 unsigned char sdigest[HMAC_DIGEST_LEN]; 1057 char *urlstr; 1058 url_t server_url; 1059 size_t mini_size; 1060 off_t offset; 1061 int plen; 1062 int retry_cnt = 0; 1063 int retry_max = WANBOOT_RETRY_ROOT_MAX; 1064 int ret; 1065 1066 /* 1067 * Get the miniroot URL. 1068 */ 1069 if ((urlstr = bootconf_get(&bc_handle, BC_ROOT_SERVER)) == NULL) { 1070 bootlog("wanboot", BOOTLOG_CRIT, 1071 "Missing root_server URL"); 1072 return (-1); 1073 } else if (url_parse(urlstr, &server_url) != URL_PARSE_SUCCESS) { 1074 bootlog("wanboot", BOOTLOG_CRIT, 1075 "Unable to parse URL %s", urlstr); 1076 return (-1); 1077 } 1078 1079 /* 1080 * We must get the miniroot info before we can request 1081 * the miniroot itself. 1082 */ 1083 if (get_miniinfo(&server_url, &mini_size, sdigest) != 0) { 1084 return (-1); 1085 } 1086 1087 plen = sizeof (server_url.abspath); 1088 if ((urlstr = bootconf_get(&bc_handle, BC_ROOT_FILE)) == NULL || 1089 strlcpy(server_url.abspath, urlstr, plen) >= plen) { 1090 bootlog("wanboot", BOOTLOG_CRIT, 1091 "Cannot retrieve the miniroot path"); 1092 return (-1); 1093 } 1094 1095 /* 1096 * Go get the miniroot. If we fail reading the response 1097 * then we re-request only the range we have yet to read, 1098 * unless the error was "unrecoverable" in which case we 1099 * re-request the entire file system. 1100 */ 1101 bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading miniroot"); 1102 1103 bzero(cdigest, sizeof (cdigest)); 1104 offset = 0; 1105 do { 1106 if ((ret = establish_http_connection(MINIROOT, &handle, 1107 &server_url, offset)) < 0) { 1108 break; 1109 } else if (ret > 0) { 1110 if (wanboot_retry(++retry_cnt, retry_max)) { 1111 continue; 1112 } else { 1113 break; 1114 } 1115 } 1116 1117 if ((ret = process_miniroot(handle, 1118 server_url.https ? HASH_NONE : hash_type, 1119 mini_size, devpath, &offset, cdigest)) > 0) { 1120 if (!wanboot_retry(++retry_cnt, retry_max)) { 1121 (void) http_srv_close(handle); 1122 break; 1123 } 1124 } 1125 1126 (void) http_srv_close(handle); 1127 1128 } while (ret > 0); 1129 1130 /* 1131 * Validate the computed digest against the one received. 1132 */ 1133 if (ret != 0 || !verify_digests(MINIROOT, cdigest, sdigest)) { 1134 bootlog("wanboot", BOOTLOG_CRIT, 1135 "Miniroot download aborted"); 1136 return (-1); 1137 } 1138 1139 bootlog("wanboot", BOOTLOG_VERBOSE, "Miniroot download successful"); 1140 return (0); 1141 } 1142 1143 /* 1144 * This routine is called to finish the decryption process. 1145 * Its purpose is to free the resources allocated by the 1146 * encryption init routines. 1147 */ 1148 static void 1149 encr_fini(encr_type_t etype, void *eh) 1150 { 1151 switch (etype) { 1152 case ENCR_3DES: 1153 des3_fini(eh); 1154 break; 1155 case ENCR_AES: 1156 aes_fini(eh); 1157 break; 1158 default: 1159 break; 1160 } 1161 } 1162 1163 /* 1164 * This routine is called by process_wanbootfs() to decrypt the encrypted 1165 * file system from ramdisk in place. The method of decryption 1166 * (algorithm) will have already been determined by process_wanbootfs() 1167 * and the cbc_handle passed to this routine will already have been 1168 * initialized appropriately. 1169 * 1170 * Returns: 1171 * -1 = Non-recoverable error 1172 * 0 = Success 1173 */ 1174 static int 1175 decrypt_wanbootfs(caddr_t addr, cbc_handle_t *ch, uint8_t *iv, 1176 size_t wanbootfs_size) 1177 { 1178 if (!cbc_decrypt(ch, (uint8_t *)addr, wanbootfs_size, iv)) { 1179 bootlog("wanboot", BOOTLOG_CRIT, 1180 "%s: cbc decrypt error", WANBOOTFS); 1181 return (-1); 1182 } 1183 return (0); 1184 } 1185 1186 /* 1187 * This routine is called by get_wanbootfs() to receive the reply to 1188 * the request for the wanboot file system. The reply is a multipart message. 1189 * The first part of the message is the file system (which may or may 1190 * not be encrypted). If encrypted, then the first block of the message 1191 * part is the CBC IV value used by the server to encrypt the remaining 1192 * part of the message part and is used by the client to decrypt it. The 1193 * second message part is a hash digest of the first part (the file 1194 * system) as computed by the server. If no hash key is configured 1195 * for the client, then the hash digest simply contains all zeros. This 1196 * routine receives both message parts. The file system is written to ramdisk 1197 * as it is received and simultaneously computes a hash digest (if a hash 1198 * key exists). Once the entire part is received, if the file system is 1199 * encrypted, it is read from ramdisk, decrypted and rewritten back to 1200 * ramdisk. The server computed hash digest is then read and along with the 1201 * ramdisk device path and the client computed hash digest is returned to the 1202 * caller. 1203 * 1204 * Notes: 1205 * In order to decrypt the file system and to compute the client 1206 * hash digest, an encryption key and a hash key is retrieved from 1207 * the PROM (or the wanboot interpreter). The non-existence of these 1208 * keys has implications on how the message response is processed and 1209 * it is assumed that the server is configured identically. 1210 * 1211 * Any HTTP errors encountered in downloading or processing the message 1212 * are not deemed unrecoverable errors. That is, get_wanbootfs() will 1213 * try re-requesting the message and will try processing it again. 1214 * 1215 * Returns: 1216 * -1 = Non-recoverable error 1217 * 0 = Success 1218 * 1 = HTTP download error 1219 */ 1220 static int 1221 process_wanbootfs(http_handle_t handle, char **devpath, 1222 unsigned char *cdigest, unsigned char *sdigest) 1223 { 1224 /* iv[] must be sized to store the largest possible encryption block */ 1225 uint8_t iv[WANBOOT_MAXBLOCKLEN]; 1226 cbc_handle_t ch; 1227 void *eh; 1228 SHA1_CTX sha; 1229 char *lenstr; 1230 size_t wanbootfs_size; 1231 size_t block_size; 1232 off_t offset; 1233 static caddr_t bootfs_vaddr = NULL; 1234 int ret; 1235 1236 switch (hash_type) { 1237 case HASH_HMAC_SHA1: 1238 bootlog("wanboot", BOOTLOG_INFO, 1239 "%s: Authentication will use HMAC-SHA1", WANBOOTFS); 1240 HMACInit(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE); 1241 break; 1242 case HASH_NONE: 1243 break; 1244 default: 1245 bootlog("wanboot", BOOTLOG_CRIT, 1246 "%s: unrecognized hash type", WANBOOTFS); 1247 return (-1); 1248 } 1249 1250 switch (encr_type) { 1251 case ENCR_3DES: 1252 bootlog("wanboot", 1253 BOOTLOG_INFO, "%s: Decryption will use 3DES", WANBOOTFS); 1254 if (des3_init(&eh) != 0) { 1255 return (-1); 1256 } 1257 block_size = DES3_BLOCK_SIZE; 1258 des3_key(eh, g_encr_key); 1259 cbc_makehandle(&ch, eh, DES3_KEY_SIZE, block_size, 1260 DES3_IV_SIZE, des3_encrypt, des3_decrypt); 1261 1262 break; 1263 case ENCR_AES: 1264 bootlog("wanboot", 1265 BOOTLOG_INFO, "%s: Decryption will use AES", WANBOOTFS); 1266 if (aes_init(&eh) != 0) { 1267 return (-1); 1268 } 1269 block_size = AES_BLOCK_SIZE; 1270 aes_key(eh, g_encr_key, AES_128_KEY_SIZE); 1271 cbc_makehandle(&ch, eh, AES_128_KEY_SIZE, block_size, 1272 AES_IV_SIZE, aes_encrypt, aes_decrypt); 1273 break; 1274 case ENCR_NONE: 1275 break; 1276 default: 1277 bootlog("wanboot", BOOTLOG_CRIT, 1278 "%s: unrecognized encryption type", WANBOOTFS); 1279 return (-1); 1280 } 1281 1282 /* 1283 * Process the header. 1284 */ 1285 if (http_process_part_headers(handle, NULL) != 0) { 1286 print_errors("http_process_part_headers", handle); 1287 return (1); 1288 } 1289 lenstr = http_get_header_value(handle, CONTENT_LENGTH); 1290 if (lenstr == NULL) { 1291 bootlog("wanboot", BOOTLOG_ALERT, "%s: error getting length " 1292 "of first part of multipart message", WANBOOTFS); 1293 return (1); 1294 } 1295 wanbootfs_size = (size_t)strtol(lenstr, NULL, 10); 1296 free(lenstr); 1297 if (wanbootfs_size == 0) { 1298 bootlog("wanboot", BOOTLOG_ALERT, "%s: length of first part " 1299 "of multipart message not a legal size", WANBOOTFS); 1300 return (1); 1301 } 1302 1303 /* 1304 * If encrypted, then read the iv. 1305 */ 1306 if (encr_type != ENCR_NONE) { 1307 if (read_bytes(handle, (char *)iv, block_size) != 0) { 1308 bootlog("wanboot", BOOTLOG_ALERT, 1309 "%s: error reading hash iv", WANBOOTFS); 1310 return (1); 1311 } 1312 wanbootfs_size -= block_size; 1313 if (hash_type != HASH_NONE) { 1314 HMACUpdate(&sha, (uchar_t *)iv, block_size); 1315 } 1316 } 1317 1318 /* 1319 * We can only create the ramdisk once. So, if we've 1320 * already created it, then it means we've re-entered 1321 * this routine from an earlier partial failure. Use 1322 * the already existing ramdisk and seek back to the 1323 * beginning of the file. 1324 */ 1325 if (bootfs_vaddr == NULL) { 1326 bootfs_vaddr = create_ramdisk(RD_BOOTFS, wanbootfs_size, 1327 devpath); 1328 } 1329 1330 offset = 0; 1331 1332 if ((ret = write_msg_to_ramdisk(WANBOOTFS, bootfs_vaddr, handle, 1333 wanbootfs_size, &offset, (hash_type == HASH_NONE) ? NULL : &sha)) 1334 != 0) { 1335 return (ret); 1336 } 1337 1338 if (hash_type != HASH_NONE) { 1339 HMACFinal(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE, cdigest); 1340 } 1341 1342 /* 1343 * If encrypted, then decrypt it. 1344 */ 1345 if (encr_type != ENCR_NONE) { 1346 ret = decrypt_wanbootfs(bootfs_vaddr, &ch, iv, wanbootfs_size); 1347 if (ret != 0) { 1348 encr_fini(encr_type, eh); 1349 return (-1); 1350 } 1351 encr_fini(encr_type, eh); 1352 } 1353 1354 return (read_digest(WANBOOTFS, handle, sdigest)); 1355 } 1356 1357 /* 1358 * This routine sends an HTTP GET request to the webserver to 1359 * request the wanboot file system for the client. The server 1360 * will reply by sending a multipart message. This routine will rely 1361 * on process_wanbootfs() to receive the multipart message, process it 1362 * and ultimately return to it a device path to a ramdisk containing 1363 * the wanboot file system, a client computed hash digest and a 1364 * server computed hash digest. This routine will verify that the 1365 * client computed hash digest matches the one sent by the server. This 1366 * routine will also verify that the nonce received in the reply matches 1367 * the one sent in the request. 1368 * 1369 * If an error occurs in the transfer of the message from the server 1370 * to the client, then the client re-requests the download in its 1371 * entirety. Errors not related to the actual message download are 1372 * deemed unrecoverable. 1373 * 1374 * Returns: 1375 * -1 = Non-recoverable error 1376 * 0 = Success 1377 */ 1378 int 1379 get_wanbootfs(const url_t *server_url) 1380 { 1381 http_handle_t handle; 1382 unsigned char cdigest[HMAC_DIGEST_LEN]; 1383 unsigned char sdigest[HMAC_DIGEST_LEN]; 1384 url_t req_url; 1385 char *devpath; 1386 int ret; 1387 int fd; 1388 char buf[NONCELEN + 1]; 1389 int retry_cnt = 0; 1390 int retry_max = WANBOOT_RETRY_MAX; 1391 1392 /* 1393 * Build the URL to request the wanboot file system. This URL 1394 * will include the CGI script name and the IP, CID, and 1395 * NONCE parameters. 1396 */ 1397 if (build_request_url(&req_url, URLtype_wanbootfs, server_url) == -1) { 1398 bootlog("wanboot", BOOTLOG_CRIT, 1399 "Can't build the URL to make the %s request", 1400 CGIcontent(URLtype_wanbootfs)); 1401 return (-1); 1402 } 1403 1404 /* 1405 * Go get the wanboot file system. If we fail reading the 1406 * response we re-request the entire file system. 1407 */ 1408 bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading wanboot file system"); 1409 1410 bzero(cdigest, sizeof (cdigest)); 1411 do { 1412 if ((ret = establish_http_connection(WANBOOTFS, &handle, 1413 &req_url, 0)) < 0) { 1414 break; 1415 } else if (ret > 0) { 1416 if (wanboot_retry(++retry_cnt, retry_max)) { 1417 continue; 1418 } else { 1419 break; 1420 } 1421 } 1422 1423 if ((ret = process_wanbootfs(handle, &devpath, 1424 cdigest, sdigest)) > 0) { 1425 if (!wanboot_retry(++retry_cnt, retry_max)) { 1426 (void) http_srv_close(handle); 1427 break; 1428 } 1429 } 1430 1431 (void) http_srv_close(handle); 1432 1433 } while (ret > 0); 1434 1435 /* 1436 * Validate the computed digest against the one received. 1437 */ 1438 if (ret != 0 || 1439 !verify_digests(WANBOOTFS, cdigest, sdigest)) { 1440 bootlog("wanboot", BOOTLOG_CRIT, 1441 "The wanboot file system download aborted"); 1442 return (-1); 1443 } 1444 1445 /* 1446 * Mount the wanboot file system. 1447 */ 1448 if (determine_fstype_and_mountroot(devpath) != VFS_SUCCESS) { 1449 bootlog("wanboot", BOOTLOG_CRIT, 1450 "Could not mount the wanboot filesystem."); 1451 bootlog("wanboot", BOOTLOG_CRIT, 1452 "This may signify a client/server key mismatch"); 1453 if (encr_type != ENCR_NONE) { 1454 bootlog("wanboot", BOOTLOG_CRIT, 1455 "(client has key but wrong encryption_type?)"); 1456 } else { 1457 bootlog("wanboot", BOOTLOG_CRIT, 1458 "(encryption_type specified but no client key?)"); 1459 } 1460 return (-1); 1461 } 1462 bootlog("wanboot", BOOTLOG_VERBOSE, 1463 "The wanboot file system has been mounted"); 1464 1465 /* 1466 * The wanboot file system should contain a nonce. Read it 1467 * and compare it against the nonce sent in the request. 1468 */ 1469 if ((fd = open(WANBOOTFS_NONCE_FILE, O_RDONLY)) == -1) { 1470 bootlog("wanboot", BOOTLOG_CRIT, 1471 "No nonce found in the wanboot file system"); 1472 bootlog("wanboot", BOOTLOG_CRIT, 1473 "The wanboot file system download aborted"); 1474 return (-1); 1475 } 1476 1477 if (read(fd, buf, NONCELEN) != NONCELEN || 1478 bcmp(nonce, buf, NONCELEN) != 0) { 1479 (void) close(fd); 1480 bootlog("wanboot", BOOTLOG_CRIT, 1481 "Invalid nonce found in the wanboot file system"); 1482 bootlog("wanboot", BOOTLOG_CRIT, 1483 "The wanboot file system download aborted"); 1484 return (-1); 1485 } 1486 1487 (void) close(fd); 1488 1489 bootlog("wanboot", BOOTLOG_VERBOSE, 1490 "The wanboot file system download was successful"); 1491 return (0); 1492 } 1493 1494 static boolean_t 1495 init_netdev(char *bpath) 1496 { 1497 pnode_t anode; 1498 int proplen; 1499 static char netalias[OBP_MAXPATHLEN]; 1500 1501 /* 1502 * Wanboot will either have loaded over the network (in which case 1503 * bpath will name a network device), or from CD-ROM or disk. In 1504 * both cases ensure that the 'net' alias corresponds to a network 1505 * device, and that if a network boot was performed that it is 1506 * identical to bpath. This is so that the interface name can always 1507 * be determined for CD-ROM or disk boots, and for manually-configured 1508 * network boots. The latter restriction may be relaxed in the future. 1509 */ 1510 anode = prom_alias_node(); 1511 if ((proplen = prom_getproplen(anode, "net")) > 0 && 1512 proplen < sizeof (netalias)) { 1513 (void) prom_getprop(anode, "net", (caddr_t)netalias); 1514 1515 if (is_netdev(netalias)) { 1516 char *p; 1517 1518 /* 1519 * Strip device arguments from netalias[]. 1520 */ 1521 if ((p = strchr(netalias, ':')) != NULL) { 1522 *p = '\0'; 1523 } 1524 1525 /* 1526 * If bpath is a network device path, then v2path 1527 * will be a copy of this sans device arguments. 1528 */ 1529 if (!is_netdev(bpath) || 1530 strcmp(v2path, netalias) == 0) { 1531 /* 1532 * Stash the netdev_path bootprop value, then 1533 * initialize the hardware and return success. 1534 */ 1535 netdev_path = netalias; 1536 mac_init(bpath); 1537 return (B_TRUE); 1538 } 1539 1540 bootlog("wanboot", BOOTLOG_CRIT, 1541 "wanboot requires that the 'net' alias refers to "); 1542 bootlog("wanboot", BOOTLOG_CRIT, 1543 "the network device path from which it loaded"); 1544 return (B_FALSE); 1545 } 1546 } 1547 1548 /* 1549 * If we haven't established a device path for a network interface, 1550 * then we're doomed. 1551 */ 1552 bootlog("wanboot", BOOTLOG_CRIT, 1553 "No network device available for wanboot!"); 1554 bootlog("wanboot", BOOTLOG_CRIT, 1555 "(Ensure that the 'net' alias is set correctly)"); 1556 return (B_FALSE); 1557 } 1558 1559 /* 1560 * This implementation of bootprog() is used solely by wanboot. 1561 * 1562 * The basic algorithm is as follows: 1563 * 1564 * - The wanboot options (those specified using the "-o" flag) are processed, 1565 * and if necessary the wanboot interpreter is invoked to collect other 1566 * options. 1567 * 1568 * - The wanboot filesystem (containing certificates, wanboot.conf file, etc.) 1569 * is then downloaded into the bootfs ramdisk, which is mounted for use 1570 * by OpenSSL, access to wanboot.conf, etc. 1571 * 1572 * - The wanboot miniroot is downloaded over http/https into the rootfs 1573 * ramdisk. The bootfs filesystem is unmounted, and the rootfs filesystem 1574 * is booted. 1575 */ 1576 /* EXPORT DELETE END */ 1577 /*ARGSUSED*/ 1578 int 1579 bootprog(char *bpath, char *bargs, boolean_t user_specified_filename) 1580 { 1581 /* EXPORT DELETE START */ 1582 char *miniroot_path; 1583 url_t server_url; 1584 int ret; 1585 1586 if (!init_netdev(bpath)) { 1587 return (-1); 1588 } 1589 1590 if (!bootinfo_init()) { 1591 bootlog("wanboot", BOOTLOG_CRIT, "Cannot initialize bootinfo"); 1592 return (-1); 1593 } 1594 1595 /* 1596 * Get default values from PROM, etc., process any boot arguments 1597 * (specified with the "-o" option), and initialize the interface. 1598 */ 1599 if (!wanboot_init_interface(wanboot_arguments)) { 1600 return (-1); 1601 } 1602 1603 /* 1604 * Determine which encryption and hashing algorithms the client 1605 * is configured to use. 1606 */ 1607 init_encryption(); 1608 init_hashing(); 1609 1610 /* 1611 * Get the bootserver value. Should be of the form: 1612 * http://host[:port]/abspath. 1613 */ 1614 ret = get_url(BI_BOOTSERVER, &server_url); 1615 if (ret != 0) { 1616 bootlog("wanboot", BOOTLOG_CRIT, 1617 "Unable to retrieve the bootserver URL"); 1618 return (-1); 1619 } 1620 1621 /* 1622 * Get the wanboot file system and mount it. Contains metdata 1623 * needed by wanboot. 1624 */ 1625 if (get_wanbootfs(&server_url) != 0) { 1626 return (-1); 1627 } 1628 1629 /* 1630 * Check that there is a valid wanboot.conf file in the wanboot 1631 * file system. 1632 */ 1633 if (bootconf_init(&bc_handle, NULL) != BC_E_NOERROR) { 1634 bootlog("wanboot", BOOTLOG_CRIT, 1635 "wanboot.conf error (code=%d)", bc_handle.bc_error_code); 1636 return (-1); 1637 } 1638 1639 /* 1640 * Set the time 1641 */ 1642 init_boot_time(); 1643 1644 /* 1645 * Verify that URLs in wanboot.conf can be reached, etc. 1646 */ 1647 if (!wanboot_verify_config()) { 1648 return (-1); 1649 } 1650 1651 /* 1652 * Retrieve the miniroot. 1653 */ 1654 if (get_miniroot(&miniroot_path) != 0) { 1655 return (-1); 1656 } 1657 1658 /* 1659 * We don't need the wanboot file system mounted anymore and 1660 * should unmount it so that we can mount the miniroot. 1661 */ 1662 (void) unmountroot(); 1663 1664 boot_ramdisk(RD_ROOTFS); 1665 1666 /* EXPORT DELETE END */ 1667 return (0); 1668 } 1669