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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 /* EXPORT DELETE START */ 31 #include <sys/promif.h> 32 #include <sys/obpdefs.h> 33 #include <sys/bootvfs.h> 34 #include <sys/bootconf.h> 35 #include <netinet/in.h> 36 #include <sys/wanboot_impl.h> 37 #include <boot_http.h> 38 #include <aes.h> 39 #include <des3.h> 40 #include <cbc.h> 41 #include <hmac_sha1.h> 42 #include <sys/sha1.h> 43 #include <sys/sha1_consts.h> 44 #include <bootlog.h> 45 #include <parseURL.h> 46 #include <netboot_paths.h> 47 #include <netinet/inetutil.h> 48 #include <sys/salib.h> 49 #include <inet/mac.h> 50 #include <inet/ipv4.h> 51 #include <dhcp_impl.h> 52 #include <inet/dhcpv4.h> 53 #include <bootinfo.h> 54 #include <wanboot_conf.h> 55 #include "boot_plat.h" 56 #include "ramdisk.h" 57 #include "wbcli.h" 58 59 /* 60 * Types of downloads 61 */ 62 #define MINIINFO "miniinfo" 63 #define MINIROOT "miniroot" 64 #define WANBOOTFS "wanbootfs" 65 66 #define WANBOOT_RETRY_NOMAX -1 67 #define WANBOOT_RETRY_ROOT_MAX 50 68 #define WANBOOT_RETRY_MAX 5 69 #define WANBOOT_RETRY_SECS 5 70 #define WANBOOT_RETRY_MAX_SECS 30 71 72 /* 73 * Our read requests should timeout after 25 seconds 74 */ 75 #define SOCKET_READ_TIMEOUT 25 76 77 /* 78 * Experimentation has shown that an 8K download buffer is optimal 79 */ 80 static char buffer[8192]; 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, int fd, 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; *offset += len) { 501 nleft = ramdisk_size - *offset; 502 503 if (nleft > sizeof (buffer)) 504 nleft = sizeof (buffer); 505 506 len = http_read_body(handle, buffer, nleft); 507 if (len <= 0) { 508 print_errors("http_read_body", handle); 509 /* 510 * In the case of a partial failure, http_read_body() 511 * returns into 'len', 1 - the number of bytes read. 512 * So, a -65 means 64 bytes read and an error occurred. 513 */ 514 if (len != 0) { 515 len = -(len + 1); 516 } 517 ret = 1; 518 } 519 if (sha != NULL) { 520 HMACUpdate(sha, (uchar_t *)buffer, (size_t)len); 521 } 522 if (prom_write(fd, buffer, (size_t)len, 0, 0) != (ssize_t)len) { 523 bootlog("wanboot", BOOTLOG_CRIT, 524 "%s: write to ramdisk failed", what); 525 ret = -1; 526 continue; 527 } 528 if (bootlog_progress == bootlog_message_interval) { 529 bootlog("wanboot", BOOTLOG_PROGRESS, 530 "%s: Read %ld of %ld kB (%ld%%)", what, 531 *offset / 1024, ramdisk_size / 1024, 532 *offset * 100 / ramdisk_size); 533 bootlog_progress = 0; 534 } else { 535 bootlog_progress++; 536 } 537 } 538 if (ret == 0) { 539 bootlog("wanboot", BOOTLOG_PROGRESS, 540 "%s: Read %ld of %ld kB (%ld%%)", what, 541 *offset / 1024, ramdisk_size / 1024, 542 *offset * 100 / ramdisk_size); 543 bootlog("wanboot", BOOTLOG_INFO, "%s: Download complete", what); 544 } 545 return (ret); 546 } 547 548 /* 549 * This routine is called with a bootinfo parameter name. If the parameter 550 * has a value it should be a URL, and this will be used to initialize the 551 * http_url structure. 552 * 553 * Returns: 554 * -1 = Non-recoverable error 555 * 0 = Success 556 * 1 = DHCP option not set 557 */ 558 static int 559 get_url(char *name, url_t *url) 560 { 561 char buf[URL_MAX_STRLEN]; 562 size_t len; 563 int ret; 564 565 bzero(buf, sizeof (buf)); 566 len = sizeof (buf) - 1; 567 if (bootinfo_get(name, buf, &len, NULL) != BI_E_SUCCESS || len == 0) { 568 return (1); 569 } 570 571 /* 572 * Parse the URL. 573 */ 574 ret = url_parse(buf, url); 575 if (ret != URL_PARSE_SUCCESS) { 576 bootlog("wanboot", BOOTLOG_CRIT, 577 "Unable to parse URL %s", buf); 578 return (-1); 579 } 580 581 return (0); 582 } 583 584 /* 585 * This routine initiates an HTTP request and returns a handle so that 586 * the caller can process the response. 587 * 588 * Notes: 589 * Requests may be either secure or not. If the request is secure, then 590 * this routine assumes that a wanboot file system exists and 591 * uses its contents to provide the HTTP library with the information 592 * that will be required by SSL. 593 * 594 * In order to facilitate transmission retries, this routine supports 595 * range requests. A caller may request a range by providing a non-zero 596 * offset. In which case, a range request is made that ranges from the 597 * offet to the end of the file. 598 * 599 * If the client is configured to use an HTTP proxy, then this routine 600 * will make the HTTP library aware of the proxy. 601 * 602 * Any HTTP errors encountered in downloading or processing the message 603 * are not deemed unrecoverable errors. The caller can simply try the 604 * request once again. 605 * 606 * Returns: 607 * -1 = Non-recoverable error 608 * 0 = Success 609 * 1 = HTTP download error 610 */ 611 static int 612 establish_http_connection(const char *what, http_handle_t *handlep, 613 url_t *url, offset_t offset) 614 { 615 static boolean_t is_auth_file_init = B_FALSE; 616 static boolean_t is_proxy_init = B_FALSE; 617 static boolean_t proxy_exists = B_FALSE; 618 static url_hport_t proxy_hp; 619 http_respinfo_t *resp; 620 char buf[URL_MAX_STRLEN]; 621 size_t len = sizeof (buf) - 1; 622 int ret; 623 624 /* Check for HTTP proxy */ 625 if (!is_proxy_init && 626 bootinfo_get(BI_HTTP_PROXY, buf, &len, NULL) == BI_E_SUCCESS && 627 strlen(buf) > 0) { 628 /* 629 * Parse the hostport. 630 */ 631 ret = url_parse_hostport(buf, &proxy_hp, URL_DFLT_PROXY_PORT); 632 if (ret == URL_PARSE_SUCCESS) { 633 proxy_exists = B_TRUE; 634 } else { 635 bootlog("wanboot", BOOTLOG_CRIT, 636 "%s is not set to a valid hostport value", 637 BI_HTTP_PROXY); 638 return (-1); 639 } 640 is_proxy_init = B_TRUE; 641 } 642 643 http_set_p12_format(use_p12); 644 645 /* 646 * Initialize the handle that will be used for the request. 647 */ 648 *handlep = http_srv_init(url); 649 if (*handlep == NULL) { 650 print_errors("http_srv_init", NULL); 651 return (-1); 652 } 653 654 /* 655 * Is the request a secure one? If it is, then we need to do further 656 * setup. Search the wanboot file system for files that will be 657 * needed by SSL. 658 */ 659 if (url->https) { 660 char *cas; 661 boolean_t client_authentication = B_FALSE; 662 663 if (http_set_random_file(*handlep, "/dev/urandom") < 0) { 664 print_errors("http_set_random_file", *handlep); 665 (void) http_srv_close(*handlep); 666 return (-1); 667 } 668 669 /* 670 * We only need to initialize the CA once as it is not handle 671 * specific. 672 */ 673 if (!is_auth_file_init) { 674 if (http_set_certificate_authority_file(NB_CA_CERT_PATH) 675 < 0) { 676 print_errors( 677 "http_set_certificate_authority_file", 678 *handlep); 679 (void) http_srv_close(*handlep); 680 return (-1); 681 } 682 683 is_auth_file_init = B_TRUE; 684 } 685 686 /* 687 * The client certificate and key will not exist unless 688 * client authentication has been configured. If it is 689 * configured then the webserver will have added these 690 * files to the wanboot file system and the HTTP library 691 * needs to be made aware of their existence. 692 */ 693 if ((cas = bootconf_get(&bc_handle, 694 BC_CLIENT_AUTHENTICATION)) != NULL && 695 strcmp(cas, "yes") == 0) { 696 client_authentication = B_TRUE; 697 698 if (http_set_client_certificate_file(*handlep, 699 NB_CLIENT_CERT_PATH) < 0) { 700 print_errors("http_set_client_certificate_file", 701 *handlep); 702 (void) http_srv_close(*handlep); 703 return (-1); 704 } 705 706 if (http_set_private_key_file(*handlep, 707 NB_CLIENT_KEY_PATH) < 0) { 708 print_errors("http_set_private_key_file", 709 *handlep); 710 (void) http_srv_close(*handlep); 711 return (-1); 712 } 713 } 714 715 /* 716 * We do not really need to set this unless client 717 * authentication is configured or unless pkcs12 files 718 * are used. 719 */ 720 if ((client_authentication || use_p12) && 721 http_set_password(*handlep, WANBOOT_PASSPHRASE) < 0) { 722 print_errors("http_set_password", *handlep); 723 (void) http_srv_close(*handlep); 724 return (-1); 725 } 726 } 727 728 /* 729 * If the client is using a proxy, tell the library. 730 */ 731 if (proxy_exists) { 732 if (http_set_proxy(*handlep, &proxy_hp) != 0) { 733 print_errors("http_set_proxy", *handlep); 734 (void) http_srv_close(*handlep); 735 return (-1); 736 } 737 } 738 739 (void) http_set_socket_read_timeout(*handlep, SOCKET_READ_TIMEOUT); 740 741 /* 742 * Ok, connect to the webserver. 743 */ 744 if (http_srv_connect(*handlep) == -1) { 745 print_errors("http_srv_connect", *handlep); 746 (void) http_srv_close(*handlep); 747 return (1); 748 } 749 750 /* 751 * If the offset is 0, then we assume that we want the entire 752 * message. If the offset is not 0, then we assume that we are 753 * retrying a previously interrupted transfer and thus we make 754 * a range request. 755 */ 756 if (offset == 0) { 757 if ((ret = http_get_request(*handlep, url->abspath)) == 0) { 758 bootlog("wanboot", BOOTLOG_VERBOSE, 759 "%s: http_get_request: sent", what); 760 } else { 761 print_errors("http_get_request", *handlep); 762 (void) http_srv_close(*handlep); 763 return (1); 764 } 765 } else { 766 if ((ret = http_get_range_request(*handlep, url->abspath, 767 offset, 0)) == 0) { 768 bootlog("wanboot", BOOTLOG_VERBOSE, 769 "%s: http_get_range_request: sent", what); 770 } else { 771 print_errors("http_get_range_request", *handlep); 772 (void) http_srv_close(*handlep); 773 return (1); 774 } 775 } 776 777 /* 778 * Tell the library to read in the response headers. 779 */ 780 ret = http_process_headers(*handlep, &resp); 781 if (ret == -1) { 782 print_errors("http_process_headers", *handlep); 783 (void) http_srv_close(*handlep); 784 return (1); 785 } 786 787 /* 788 * Check for a valid response code. 789 */ 790 if ((offset == 0 && resp->code != 200) || 791 (offset != 0 && resp->code != 206)) { 792 bootlog("wanboot", BOOTLOG_ALERT, 793 "%s: Request returned code %d", what, resp->code); 794 if (resp->statusmsg != NULL && resp->statusmsg[0] != '\0') 795 bootlog("wanboot", BOOTLOG_ALERT, 796 "%s", resp->statusmsg); 797 http_free_respinfo(resp); 798 (void) http_srv_close(*handlep); 799 return (1); 800 } 801 http_free_respinfo(resp); 802 803 /* 804 * Success. 805 */ 806 return (0); 807 } 808 809 /* 810 * This routine is called by get_miniinfo() to receive the reply 811 * to the request for the miniroot metadata. The reply is a two 812 * part multipart message. The first part of the message contains 813 * the miniroot file size. The second part of the message contains 814 * a hash digest of the miniroot as computed by the server. This 815 * routine receives both message parts and returns them to the caller. 816 * 817 * Notes: 818 * If the miniroot is going to be downloaded securely or if the 819 * the server has no hash key for the client, then the hash digest 820 * downloaded contains all zeros. 821 * 822 * Any HTTP errors encountered in downloading or processing the message 823 * are not deemed unrecoverable errors. That is, get_miniinfo() 824 * tries re-requesting the message and tries processing it again. 825 * 826 * Returns: 827 * -1 = Non-recoverable error 828 * 0 = Success 829 * 1 = HTTP download error 830 */ 831 static int 832 process_miniinfo(http_handle_t handle, size_t *mini_size, 833 unsigned char *sdigest) 834 { 835 char *lenstr; 836 size_t cnt; 837 838 /* 839 * Process the file size header. 840 */ 841 if (http_process_part_headers(handle, NULL) != 0) { 842 print_errors("http_process_part_headers", handle); 843 return (1); 844 } 845 lenstr = http_get_header_value(handle, CONTENT_LENGTH); 846 if (lenstr == NULL) { 847 bootlog("wanboot", BOOTLOG_ALERT, "%s: error getting length " 848 "of first part of multipart message", MINIINFO); 849 return (1); 850 } 851 cnt = (size_t)strtol(lenstr, NULL, 10); 852 free(lenstr); 853 if (cnt == 0 || cnt >= sizeof (buffer)) { 854 bootlog("wanboot", BOOTLOG_ALERT, "%s: length of first part " 855 "of multipart message not a legal size", MINIINFO); 856 return (1); 857 } 858 859 if (read_bytes(handle, buffer, cnt) != 0) { 860 bootlog("wanboot", BOOTLOG_ALERT, 861 "%s: error reading miniroot size", MINIINFO); 862 return (1); 863 } 864 buffer[cnt] = '\0'; 865 866 *mini_size = (size_t)strtol(buffer, NULL, 10); 867 if (*mini_size == 0) { 868 bootlog("wanboot", BOOTLOG_ALERT, "%s: body of first part " 869 "of multipart message not a legal size", MINIINFO); 870 return (1); 871 } 872 873 return (read_digest(MINIINFO, handle, sdigest)); 874 } 875 876 /* 877 * This routine is called by get_miniroot() to retrieve the miniroot 878 * metadata (miniroot size and a hash digest). This routine sends an 879 * HTTP GET request to the webserver to request the download of the 880 * miniroot metadata and relies on process_miniinfo() to receive the 881 * reply, process it and ultimately return to it the miniroot size and 882 * the hash digest. 883 * 884 * Note: 885 * Any HTTP errors encountered in downloading or processing the message 886 * are not deemed unrecoverable errors. That is, get_miniinfo() should 887 * try re-requesting the message and try processing again. 888 * 889 * Returns: 890 * -1 = Non-recoverable error 891 * 0 = Success 892 */ 893 int 894 get_miniinfo(const url_t *server_url, size_t *mini_size, 895 unsigned char *sdigest) 896 { 897 http_handle_t handle; 898 url_t req_url; 899 int retry_cnt = 0; 900 int retry_max = WANBOOT_RETRY_MAX; 901 int ret; 902 903 /* 904 * Build the URL to request the miniroot info. 905 */ 906 if (build_request_url(&req_url, URLtype_miniroot, server_url) == -1) { 907 bootlog("wanboot", BOOTLOG_CRIT, 908 "Can't build the URL to make the %s request", 909 CGIcontent(URLtype_miniroot)); 910 return (-1); 911 } 912 913 /* 914 * Go get the miniroot info. If we fail reading the 915 * response we re-request the info in its entirety. 916 */ 917 bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading miniroot info"); 918 919 do { 920 if ((ret = establish_http_connection(MINIINFO, &handle, 921 &req_url, 0)) < 0) { 922 break; 923 } else if (ret > 0) { 924 if (wanboot_retry(++retry_cnt, retry_max)) { 925 continue; 926 } else { 927 break; 928 } 929 } 930 931 if ((ret = process_miniinfo(handle, mini_size, 932 sdigest)) > 0) { 933 if (!wanboot_retry(++retry_cnt, retry_max)) { 934 (void) http_srv_close(handle); 935 break; 936 } 937 } 938 939 (void) http_srv_close(handle); 940 941 } while (ret > 0); 942 943 /* 944 * Success. 945 */ 946 if (ret == 0) { 947 bootlog("wanboot", BOOTLOG_VERBOSE, 948 "Miniroot info download successful"); 949 return (0); 950 } else { 951 bootlog("wanboot", BOOTLOG_CRIT, 952 "Miniroot info download aborted"); 953 return (-1); 954 } 955 } 956 957 /* 958 * This routine is called by get_miniroot() to receive the reply to 959 * the request for the miniroot download. The miniroot is written 960 * to ramdisk as it is received and a hash digest is optionally computed 961 * as it does so. The miniroot is downloaded as one large message. 962 * Because the message is so large, this routine is prepared to deal 963 * with errors in the middle of download. If an error occurs during 964 * download, then this message processes all received data up to the 965 * point of the error and returns to get_miniroot() an error signifying 966 * that a download error has occurred. Presumably, get_miniroot() 967 * re-requests the remaining part of the miniroot not yet processed and 968 * calls this routine back to process the reply. When this routine 969 * returns succesfully, it returns a devpath to the ramdisk and the 970 * computed hash (if computed). 971 * 972 * Note: 973 * In order to facilitate reentry, the ramdisk is left open 974 * and the original miniroot_size and HMAC handle are kept 975 * static. 976 * 977 * Returns: 978 * -1 = Non-recoverable error 979 * 0 = Success 980 * 1 = HTTP download error 981 */ 982 static int 983 process_miniroot(http_handle_t handle, hash_type_t htype, 984 size_t length, char **devpath, off_t *offset, unsigned char *cdigest) 985 { 986 static SHA1_CTX sha; 987 static size_t miniroot_size; 988 static int fd = -1; 989 int ret; 990 991 if (fd == -1) { 992 if (htype == HASH_HMAC_SHA1) { 993 bootlog("wanboot", BOOTLOG_INFO, 994 "%s: Authentication will use HMAC-SHA1", MINIROOT); 995 HMACInit(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE); 996 } 997 998 miniroot_size = length; 999 1000 fd = create_ramdisk(RD_ROOTFS, miniroot_size, devpath); 1001 } 1002 1003 if (prom_seek(fd, *offset) == -1) { 1004 bootlog("wanboot", BOOTLOG_CRIT, 1005 "%s: prom_seek error", MINIROOT); 1006 return (-1); 1007 } 1008 1009 if ((ret = write_msg_to_ramdisk(MINIROOT, fd, handle, miniroot_size, 1010 offset, (htype == HASH_NONE) ? NULL : &sha)) != 0) { 1011 if (ret < 0) { 1012 /* 1013 * Reentry not supported. 1014 */ 1015 (void) prom_close(fd); 1016 } 1017 return (ret); 1018 } 1019 1020 if (htype != HASH_NONE) { 1021 HMACFinal(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE, cdigest); 1022 } 1023 1024 (void) prom_close(fd); 1025 1026 return (0); 1027 } 1028 1029 /* 1030 * This routine retrieves the miniroot from the webserver. The miniroot 1031 * is retrieved in two steps. First a request is made to the server 1032 * to retrieve miniroot metadata (miniroot size and a hash digest). 1033 * The second request actually results in the download of the miniroot. 1034 * 1035 * This routine relies on get_miniinfo() to make and process 1036 * the request for the miniroot metadata and returns the 1037 * miniroot size and the hash digest of the miniroot as computed by 1038 * the server. 1039 * 1040 * If get_miniinfo() returns successfully, then this routine sends 1041 * an HTTP GET request to the webserver to request download of the 1042 * miniroot. This routine relies on process_miniroot() to receive 1043 * the reply, process it and ultimately return to it a device path to 1044 * a ramdisk containing the miniroot and a client computed hash digest. 1045 * This routine verifies that the client computed hash digest matches 1046 * the one retrieved by get_miniinfo(). 1047 * 1048 * If an error occurs in the transfer of the miniroot from the server 1049 * to the client, then the client re-requests the download of the 1050 * miniroot using a range request and only requests the part of the 1051 * miniroot not previously downloaded and written to ramdisk. The 1052 * process_miniroot() routine has the intelligence to recognize that 1053 * it is processing a range request. Errors not related to the actual 1054 * message download are deemed unrecoverable. 1055 * 1056 * Note: 1057 * If the client request for the miniroot is a secure request or 1058 * if the server is not configured with a hash key for the client, 1059 * then the hash digest downloaded from the server will contain 1060 * all zeros. This routine verifies that the server and client are 1061 * in-sync with respect to the need for hash verification. 1062 * 1063 * Returns: 1064 * -1 = Non-recoverable error 1065 * 0 = Success 1066 */ 1067 int 1068 get_miniroot(char **devpath) 1069 { 1070 http_handle_t handle; 1071 unsigned char cdigest[HMAC_DIGEST_LEN]; 1072 unsigned char sdigest[HMAC_DIGEST_LEN]; 1073 char *urlstr; 1074 url_t server_url; 1075 size_t mini_size; 1076 off_t offset; 1077 int plen; 1078 int retry_cnt = 0; 1079 int retry_max = WANBOOT_RETRY_ROOT_MAX; 1080 int ret; 1081 1082 /* 1083 * Get the miniroot URL. 1084 */ 1085 if ((urlstr = bootconf_get(&bc_handle, BC_ROOT_SERVER)) == NULL) { 1086 bootlog("wanboot", BOOTLOG_CRIT, 1087 "Missing root_server URL"); 1088 return (-1); 1089 } else if (url_parse(urlstr, &server_url) != URL_PARSE_SUCCESS) { 1090 bootlog("wanboot", BOOTLOG_CRIT, 1091 "Unable to parse URL %s", urlstr); 1092 return (-1); 1093 } 1094 1095 /* 1096 * We must get the miniroot info before we can request 1097 * the miniroot itself. 1098 */ 1099 if (get_miniinfo(&server_url, &mini_size, sdigest) != 0) { 1100 return (-1); 1101 } 1102 1103 plen = sizeof (server_url.abspath); 1104 if ((urlstr = bootconf_get(&bc_handle, BC_ROOT_FILE)) == NULL || 1105 strlcpy(server_url.abspath, urlstr, plen) >= plen) { 1106 bootlog("wanboot", BOOTLOG_CRIT, 1107 "Cannot retrieve the miniroot path"); 1108 return (-1); 1109 } 1110 1111 /* 1112 * Go get the miniroot. If we fail reading the response 1113 * then we re-request only the range we have yet to read, 1114 * unless the error was "unrecoverable" in which case we 1115 * re-request the entire file system. 1116 */ 1117 bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading miniroot"); 1118 1119 bzero(cdigest, sizeof (cdigest)); 1120 offset = 0; 1121 do { 1122 if ((ret = establish_http_connection(MINIROOT, &handle, 1123 &server_url, offset)) < 0) { 1124 break; 1125 } else if (ret > 0) { 1126 if (wanboot_retry(++retry_cnt, retry_max)) { 1127 continue; 1128 } else { 1129 break; 1130 } 1131 } 1132 1133 if ((ret = process_miniroot(handle, 1134 server_url.https ? HASH_NONE : hash_type, 1135 mini_size, devpath, &offset, cdigest)) > 0) { 1136 if (!wanboot_retry(++retry_cnt, retry_max)) { 1137 (void) http_srv_close(handle); 1138 break; 1139 } 1140 } 1141 1142 (void) http_srv_close(handle); 1143 1144 } while (ret > 0); 1145 1146 /* 1147 * Validate the computed digest against the one received. 1148 */ 1149 if (ret != 0 || !verify_digests(MINIROOT, cdigest, sdigest)) { 1150 bootlog("wanboot", BOOTLOG_CRIT, 1151 "Miniroot download aborted"); 1152 return (-1); 1153 } 1154 1155 bootlog("wanboot", BOOTLOG_VERBOSE, "Miniroot download successful"); 1156 return (0); 1157 } 1158 1159 /* 1160 * This routine is called to finish the decryption process. 1161 * Its purpose is to free the resources allocated by the 1162 * encryption init routines. 1163 */ 1164 static void 1165 encr_fini(encr_type_t etype, void *eh) 1166 { 1167 switch (etype) { 1168 case ENCR_3DES: 1169 des3_fini(eh); 1170 break; 1171 case ENCR_AES: 1172 aes_fini(eh); 1173 break; 1174 default: 1175 break; 1176 } 1177 } 1178 1179 /* 1180 * This routine is called by process_wanbootfs() to read the encrypted 1181 * file system from ramdisk and decrypt it. This routine will rewrite 1182 * the file system back to ramdisk in place. The method of decryption 1183 * (algorithm) will have already been determined by process_wanbootfs() 1184 * and the cbc_handle passed to this routine will already have been 1185 * initialized appropriately. 1186 * 1187 * Returns: 1188 * -1 = Non-recoverable error 1189 * 0 = Success 1190 */ 1191 static int 1192 decrypt_wanbootfs(int fd, cbc_handle_t *ch, uint8_t *iv, 1193 size_t block_size, size_t wanbootfs_size) 1194 { 1195 size_t total; 1196 size_t len; 1197 size_t nleft; 1198 size_t max_read_size; 1199 1200 max_read_size = (sizeof (buffer) / block_size) * block_size; 1201 for (total = 0; total < wanbootfs_size; total += len) { 1202 if (prom_seek(fd, total) == -1) { 1203 bootlog("wanboot", BOOTLOG_CRIT, 1204 "%s: prom_seek error", WANBOOTFS); 1205 return (-1); 1206 } 1207 nleft = wanbootfs_size - total; 1208 if (nleft > max_read_size) 1209 nleft = max_read_size; 1210 len = prom_read(fd, buffer, nleft, 0, 0); 1211 if (len != nleft) { 1212 bootlog("wanboot", BOOTLOG_CRIT, 1213 "%s: prom_read error", WANBOOTFS); 1214 return (-1); 1215 } 1216 if (!cbc_decrypt(ch, (uint8_t *)buffer, len, iv)) { 1217 bootlog("wanboot", BOOTLOG_CRIT, 1218 "%s: cbc decrypt error", WANBOOTFS); 1219 return (-1); 1220 } 1221 if (prom_seek(fd, total) == -1) { 1222 bootlog("wanboot", BOOTLOG_CRIT, 1223 "%s: prom_seek error", WANBOOTFS); 1224 return (-1); 1225 } 1226 if (prom_write(fd, buffer, len, 0, 0) != len) { 1227 bootlog("wanboot", BOOTLOG_CRIT, 1228 "%s: prom_write error", WANBOOTFS); 1229 return (-1); 1230 } 1231 } 1232 return (0); 1233 } 1234 1235 /* 1236 * This routine is called by get_wanbootfs() to receive the reply to 1237 * the request for the wanboot file system. The reply is a multipart message. 1238 * The first part of the message is the file system (which may or may 1239 * not be encrypted). If encrypted, then the first block of the message 1240 * part is the CBC IV value used by the server to encrypt the remaining 1241 * part of the message part and is used by the client to decrypt it. The 1242 * second message part is a hash digest of the first part (the file 1243 * system) as computed by the server. If no hash key is configured 1244 * for the client, then the hash digest simply contains all zeros. This 1245 * routine receives both message parts. The file system is written to ramdisk 1246 * as it is received and simultaneously computes a hash digest (if a hash 1247 * key exists). Once the entire part is received, if the file system is 1248 * encrypted, it is read from ramdisk, decrypted and rewritten back to 1249 * ramdisk. The server computed hash digest is then read and along with the 1250 * ramdisk device path and the client computed hash digest is returned to the 1251 * caller. 1252 * 1253 * Notes: 1254 * In order to decrypt the file system and to compute the client 1255 * hash digest, an encryption key and a hash key is retrieved from 1256 * the PROM (or the wanboot interpreter). The non-existence of these 1257 * keys has implications on how the message response is processed and 1258 * it is assumed that the server is configured identically. 1259 * 1260 * Any HTTP errors encountered in downloading or processing the message 1261 * are not deemed unrecoverable errors. That is, get_wanbootfs() will 1262 * try re-requesting the message and will try processing it again. 1263 * 1264 * Returns: 1265 * -1 = Non-recoverable error 1266 * 0 = Success 1267 * 1 = HTTP download error 1268 */ 1269 static int 1270 process_wanbootfs(http_handle_t handle, char **devpath, 1271 unsigned char *cdigest, unsigned char *sdigest) 1272 { 1273 /* iv[] must be sized to store the largest possible encryption block */ 1274 uint8_t iv[WANBOOT_MAXBLOCKLEN]; 1275 cbc_handle_t ch; 1276 void *eh; 1277 SHA1_CTX sha; 1278 char *lenstr; 1279 size_t wanbootfs_size; 1280 size_t block_size; 1281 off_t offset; 1282 static int fd = -1; 1283 int ret; 1284 1285 switch (hash_type) { 1286 case HASH_HMAC_SHA1: 1287 bootlog("wanboot", BOOTLOG_INFO, 1288 "%s: Authentication will use HMAC-SHA1", WANBOOTFS); 1289 HMACInit(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE); 1290 break; 1291 case HASH_NONE: 1292 break; 1293 default: 1294 bootlog("wanboot", BOOTLOG_CRIT, 1295 "%s: unrecognized hash type", WANBOOTFS); 1296 return (-1); 1297 } 1298 1299 switch (encr_type) { 1300 case ENCR_3DES: 1301 bootlog("wanboot", 1302 BOOTLOG_INFO, "%s: Decryption will use 3DES", WANBOOTFS); 1303 if (des3_init(&eh) != 0) { 1304 return (-1); 1305 } 1306 block_size = DES3_BLOCK_SIZE; 1307 des3_key(eh, g_encr_key); 1308 cbc_makehandle(&ch, eh, DES3_KEY_SIZE, block_size, 1309 DES3_IV_SIZE, des3_encrypt, des3_decrypt); 1310 1311 break; 1312 case ENCR_AES: 1313 bootlog("wanboot", 1314 BOOTLOG_INFO, "%s: Decryption will use AES", WANBOOTFS); 1315 if (aes_init(&eh) != 0) { 1316 return (-1); 1317 } 1318 block_size = AES_BLOCK_SIZE; 1319 aes_key(eh, g_encr_key, AES_128_KEY_SIZE); 1320 cbc_makehandle(&ch, eh, AES_128_KEY_SIZE, block_size, 1321 AES_IV_SIZE, aes_encrypt, aes_decrypt); 1322 break; 1323 case ENCR_NONE: 1324 break; 1325 default: 1326 bootlog("wanboot", BOOTLOG_CRIT, 1327 "%s: unrecognized encryption type", WANBOOTFS); 1328 return (-1); 1329 } 1330 1331 /* 1332 * Process the header. 1333 */ 1334 if (http_process_part_headers(handle, NULL) != 0) { 1335 print_errors("http_process_part_headers", handle); 1336 return (1); 1337 } 1338 lenstr = http_get_header_value(handle, CONTENT_LENGTH); 1339 if (lenstr == NULL) { 1340 bootlog("wanboot", BOOTLOG_ALERT, "%s: error getting length " 1341 "of first part of multipart message", WANBOOTFS); 1342 return (1); 1343 } 1344 wanbootfs_size = (size_t)strtol(lenstr, NULL, 10); 1345 free(lenstr); 1346 if (wanbootfs_size == 0) { 1347 bootlog("wanboot", BOOTLOG_ALERT, "%s: length of first part " 1348 "of multipart message not a legal size", WANBOOTFS); 1349 return (1); 1350 } 1351 1352 /* 1353 * If encrypted, then read the iv. 1354 */ 1355 if (encr_type != ENCR_NONE) { 1356 if (read_bytes(handle, (char *)iv, block_size) != 0) { 1357 bootlog("wanboot", BOOTLOG_ALERT, 1358 "%s: error reading hash iv", WANBOOTFS); 1359 return (1); 1360 } 1361 wanbootfs_size -= block_size; 1362 if (hash_type != HASH_NONE) { 1363 HMACUpdate(&sha, (uchar_t *)iv, block_size); 1364 } 1365 } 1366 1367 /* 1368 * We can only create the ramdisk once. So, if we've 1369 * already created it, then it means we've re-entered 1370 * this routine from an earlier partial failure. Use 1371 * the already existing ramdisk and seek back to the 1372 * beginning of the file. 1373 */ 1374 if (fd == -1) { 1375 fd = create_ramdisk(RD_BOOTFS, wanbootfs_size, devpath); 1376 } 1377 1378 offset = 0; 1379 if (prom_seek(fd, offset) == -1) { 1380 bootlog("wanboot", BOOTLOG_CRIT, 1381 "%s: prom_seek error", WANBOOTFS); 1382 return (-1); 1383 } 1384 1385 if ((ret = write_msg_to_ramdisk(WANBOOTFS, fd, handle, wanbootfs_size, 1386 &offset, (hash_type == HASH_NONE) ? NULL : &sha)) != 0) { 1387 if (ret < 0) { 1388 /* 1389 * Reentry not supported. 1390 */ 1391 (void) prom_close(fd); 1392 } 1393 return (ret); 1394 } 1395 1396 if (hash_type != HASH_NONE) { 1397 HMACFinal(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE, cdigest); 1398 } 1399 1400 /* 1401 * If encrypted, then decrypt it. 1402 */ 1403 if (encr_type != ENCR_NONE) { 1404 ret = decrypt_wanbootfs(fd, &ch, iv, block_size, 1405 wanbootfs_size); 1406 if (ret != 0) { 1407 encr_fini(encr_type, eh); 1408 (void) prom_close(fd); 1409 return (-1); 1410 } 1411 encr_fini(encr_type, eh); 1412 } 1413 1414 (void) prom_close(fd); 1415 1416 return (read_digest(WANBOOTFS, handle, sdigest)); 1417 } 1418 1419 /* 1420 * This routine sends an HTTP GET request to the webserver to 1421 * request the wanboot file system for the client. The server 1422 * will reply by sending a multipart message. This routine will rely 1423 * on process_wanbootfs() to receive the multipart message, process it 1424 * and ultimately return to it a device path to a ramdisk containing 1425 * the wanboot file system, a client computed hash digest and a 1426 * server computed hash digest. This routine will verify that the 1427 * client computed hash digest matches the one sent by the server. This 1428 * routine will also verify that the nonce received in the reply matches 1429 * the one sent in the request. 1430 * 1431 * If an error occurs in the transfer of the message from the server 1432 * to the client, then the client re-requests the download in its 1433 * entirety. Errors not related to the actual message download are 1434 * deemed unrecoverable. 1435 * 1436 * Returns: 1437 * -1 = Non-recoverable error 1438 * 0 = Success 1439 */ 1440 int 1441 get_wanbootfs(const url_t *server_url) 1442 { 1443 http_handle_t handle; 1444 unsigned char cdigest[HMAC_DIGEST_LEN]; 1445 unsigned char sdigest[HMAC_DIGEST_LEN]; 1446 url_t req_url; 1447 char *devpath; 1448 int ret; 1449 int fd; 1450 char buf[NONCELEN + 1]; 1451 int retry_cnt = 0; 1452 int retry_max = WANBOOT_RETRY_MAX; 1453 1454 /* 1455 * Build the URL to request the wanboot file system. This URL 1456 * will include the CGI script name and the IP, CID, and 1457 * NONCE parameters. 1458 */ 1459 if (build_request_url(&req_url, URLtype_wanbootfs, server_url) == -1) { 1460 bootlog("wanboot", BOOTLOG_CRIT, 1461 "Can't build the URL to make the %s request", 1462 CGIcontent(URLtype_wanbootfs)); 1463 return (-1); 1464 } 1465 1466 /* 1467 * Go get the wanboot file system. If we fail reading the 1468 * response we re-request the entire file system. 1469 */ 1470 bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading wanboot file system"); 1471 1472 bzero(cdigest, sizeof (cdigest)); 1473 do { 1474 if ((ret = establish_http_connection(WANBOOTFS, &handle, 1475 &req_url, 0)) < 0) { 1476 break; 1477 } else if (ret > 0) { 1478 if (wanboot_retry(++retry_cnt, retry_max)) { 1479 continue; 1480 } else { 1481 break; 1482 } 1483 } 1484 1485 if ((ret = process_wanbootfs(handle, &devpath, 1486 cdigest, sdigest)) > 0) { 1487 if (!wanboot_retry(++retry_cnt, retry_max)) { 1488 (void) http_srv_close(handle); 1489 break; 1490 } 1491 } 1492 1493 (void) http_srv_close(handle); 1494 1495 } while (ret > 0); 1496 1497 /* 1498 * Validate the computed digest against the one received. 1499 */ 1500 if (ret != 0 || 1501 !verify_digests(WANBOOTFS, cdigest, sdigest)) { 1502 bootlog("wanboot", BOOTLOG_CRIT, 1503 "The wanboot file system download aborted"); 1504 return (-1); 1505 } 1506 1507 /* 1508 * Mount the wanboot file system. 1509 */ 1510 if (determine_fstype_and_mountroot(devpath) != VFS_SUCCESS) { 1511 bootlog("wanboot", BOOTLOG_CRIT, 1512 "Could not mount the wanboot filesystem."); 1513 bootlog("wanboot", BOOTLOG_CRIT, 1514 "This may signify a client/server key mismatch"); 1515 if (encr_type != ENCR_NONE) { 1516 bootlog("wanboot", BOOTLOG_CRIT, 1517 "(client has key but wrong encryption_type?)"); 1518 } else { 1519 bootlog("wanboot", BOOTLOG_CRIT, 1520 "(encryption_type specified but no client key?)"); 1521 } 1522 return (-1); 1523 } 1524 bootlog("wanboot", BOOTLOG_VERBOSE, 1525 "The wanboot file system has been mounted"); 1526 1527 /* 1528 * The wanboot file system should contain a nonce. Read it 1529 * and compare it against the nonce sent in the request. 1530 */ 1531 if ((fd = open(WANBOOTFS_NONCE_FILE, O_RDONLY)) == -1) { 1532 bootlog("wanboot", BOOTLOG_CRIT, 1533 "No nonce found in the wanboot file system"); 1534 bootlog("wanboot", BOOTLOG_CRIT, 1535 "The wanboot file system download aborted"); 1536 return (-1); 1537 } 1538 1539 if (read(fd, buf, NONCELEN) != NONCELEN || 1540 bcmp(nonce, buf, NONCELEN) != 0) { 1541 (void) close(fd); 1542 bootlog("wanboot", BOOTLOG_CRIT, 1543 "Invalid nonce found in the wanboot file system"); 1544 bootlog("wanboot", BOOTLOG_CRIT, 1545 "The wanboot file system download aborted"); 1546 return (-1); 1547 } 1548 1549 (void) close(fd); 1550 1551 bootlog("wanboot", BOOTLOG_VERBOSE, 1552 "The wanboot file system download was successful"); 1553 return (0); 1554 } 1555 1556 static boolean_t 1557 init_netdev(char *bpath) 1558 { 1559 pnode_t anode; 1560 int proplen; 1561 static char netalias[OBP_MAXPATHLEN]; 1562 1563 /* 1564 * Wanboot will either have loaded over the network (in which case 1565 * bpath will name a network device), or from CD-ROM or disk. In 1566 * both cases ensure that the 'net' alias corresponds to a network 1567 * device, and that if a network boot was performed that it is 1568 * identical to bpath. This is so that the interface name can always 1569 * be determined for CD-ROM or disk boots, and for manually-configured 1570 * network boots. The latter restriction may be relaxed in the future. 1571 */ 1572 anode = prom_alias_node(); 1573 if ((proplen = prom_getproplen(anode, "net")) > 0 && 1574 proplen < sizeof (netalias)) { 1575 (void) prom_getprop(anode, "net", (caddr_t)netalias); 1576 1577 if (is_netdev(netalias)) { 1578 char *p; 1579 1580 /* 1581 * Strip device arguments from netalias[]. 1582 */ 1583 if ((p = strchr(netalias, ':')) != NULL) { 1584 *p = '\0'; 1585 } 1586 1587 /* 1588 * If bpath is a network device path, then v2path 1589 * will be a copy of this sans device arguments. 1590 */ 1591 if (!is_netdev(bpath) || 1592 strcmp(v2path, netalias) == 0) { 1593 /* 1594 * Stash the netdev_path bootprop value, then 1595 * initialize the hardware and return success. 1596 */ 1597 netdev_path = netalias; 1598 mac_init(netalias); 1599 return (B_TRUE); 1600 } 1601 1602 bootlog("wanboot", BOOTLOG_CRIT, 1603 "wanboot requires that the 'net' alias refers to "); 1604 bootlog("wanboot", BOOTLOG_CRIT, 1605 "the network device path from which it loaded"); 1606 return (B_FALSE); 1607 } 1608 } 1609 1610 /* 1611 * If we haven't established a device path for a network interface, 1612 * then we're doomed. 1613 */ 1614 bootlog("wanboot", BOOTLOG_CRIT, 1615 "No network device available for wanboot!"); 1616 bootlog("wanboot", BOOTLOG_CRIT, 1617 "(Ensure that the 'net' alias is set correctly)"); 1618 return (B_FALSE); 1619 } 1620 1621 /* 1622 * This implementation of bootprog() is used solely by wanboot. 1623 * 1624 * The basic algorithm is as follows: 1625 * 1626 * - The wanboot options (those specified using the "-o" flag) are processed, 1627 * and if necessary the wanboot interpreter is invoked to collect other 1628 * options. 1629 * 1630 * - The wanboot filesystem (containing certificates, wanboot.conf file, etc.) 1631 * is then downloaded into the bootfs ramdisk, which is mounted for use 1632 * by OpenSSL, access to wanboot.conf, etc. 1633 * 1634 * - The wanboot miniroot is downloaded over http/https into the rootfs 1635 * ramdisk. The bootfs filesystem is unmounted, and the rootfs filesystem 1636 * is mounted. 1637 */ 1638 /* EXPORT DELETE END */ 1639 /*ARGSUSED*/ 1640 int 1641 bootprog(char *bpath, char *bargs, boolean_t user_specified_filename) 1642 { 1643 /* EXPORT DELETE START */ 1644 char *miniroot_path; 1645 url_t server_url; 1646 int ret; 1647 1648 if (!init_netdev(bpath)) { 1649 return (-1); 1650 } 1651 1652 if (!bootinfo_init()) { 1653 bootlog("wanboot", BOOTLOG_CRIT, "Cannot initialize bootinfo"); 1654 return (-1); 1655 } 1656 1657 /* 1658 * Get default values from PROM, etc., process any boot arguments 1659 * (specified with the "-o" option), and initialize the interface. 1660 */ 1661 if (!wanboot_init_interface(wanboot_arguments)) { 1662 return (-1); 1663 } 1664 1665 /* 1666 * Determine which encryption and hashing algorithms the client 1667 * is configured to use. 1668 */ 1669 init_encryption(); 1670 init_hashing(); 1671 1672 /* 1673 * Get the bootserver value. Should be of the form: 1674 * http://host[:port]/abspath. 1675 */ 1676 ret = get_url(BI_BOOTSERVER, &server_url); 1677 if (ret != 0) { 1678 bootlog("wanboot", BOOTLOG_CRIT, 1679 "Unable to retrieve the bootserver URL"); 1680 return (-1); 1681 } 1682 1683 /* 1684 * Get the wanboot file system and mount it. Contains metdata 1685 * needed by wanboot. 1686 */ 1687 if (get_wanbootfs(&server_url) != 0) { 1688 return (-1); 1689 } 1690 1691 /* 1692 * Check that there is a valid wanboot.conf file in the wanboot 1693 * file system. 1694 */ 1695 if (bootconf_init(&bc_handle, NULL) != BC_E_NOERROR) { 1696 bootlog("wanboot", BOOTLOG_CRIT, 1697 "wanboot.conf error (code=%d)", bc_handle.bc_error_code); 1698 return (-1); 1699 } 1700 1701 /* 1702 * Set the time 1703 */ 1704 init_boot_time(); 1705 1706 /* 1707 * Verify that URLs in wanboot.conf can be reached, etc. 1708 */ 1709 if (!wanboot_verify_config()) { 1710 return (-1); 1711 } 1712 1713 /* 1714 * Retrieve the miniroot. 1715 */ 1716 if (get_miniroot(&miniroot_path) != 0) { 1717 return (-1); 1718 } 1719 1720 /* 1721 * We don't need the wanboot file system mounted anymore and 1722 * should unmount it so that we can mount the miniroot. 1723 */ 1724 (void) unmountroot(); 1725 1726 /* 1727 * Mount the miniroot. 1728 */ 1729 if (determine_fstype_and_mountroot(miniroot_path) != VFS_SUCCESS) { 1730 bootlog("wanboot", BOOTLOG_CRIT, 1731 "Could not mount miniroot filesystem"); 1732 return (-1); 1733 } 1734 bootlog("wanboot", BOOTLOG_VERBOSE, "The miniroot has been mounted"); 1735 1736 v2path = "/ramdisk-rootfs:a"; 1737 bootlog("wanboot", BOOTLOG_VERBOSE, "device path '%s'", v2path); 1738 1739 /* 1740 * kernname (default-name) might have changed if mountroot() called 1741 * boot_nfs_mountroot(), and it called set_default_filename(). 1742 */ 1743 if (! user_specified_filename) 1744 (void) strcpy(filename, kernname); 1745 1746 bootlog("wanboot", BOOTLOG_VERBOSE, 1747 "standalone = `%s', args = `%s'", filename, bargs); 1748 1749 set_client_bootargs(filename, bargs); 1750 1751 /* 1752 * We're done with the mac interface that was initialized by 1753 * mac_init() inside init_netdev(). 1754 */ 1755 mac_fini(); 1756 1757 bootconf_end(&bc_handle); 1758 bootinfo_end(); 1759 1760 /* EXPORT DELETE END */ 1761 return (0); 1762 } 1763