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