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