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 /* 23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved. 25 */ 26 27 #include <errno.h> 28 #include <sys/types.h> 29 #include <sys/socket.h> 30 #include <netinet/in.h> 31 #include <arpa/inet.h> 32 #include <ctype.h> 33 #include <stdio.h> 34 #include <strings.h> 35 #include <stdlib.h> 36 #include <netdb.h> 37 38 #include <openssl/ssl.h> 39 #include <openssl/err.h> 40 #include <openssl/rand.h> 41 #include <openssl/pkcs12.h> 42 43 /* this must be included after ssl.h to avoid re-defining 'offsetof' */ 44 #include <sys/sysmacros.h> 45 46 #include <boot_http.h> 47 #include <socket_inet.h> 48 #include <p12access.h> 49 50 #include "bootlog.h" 51 52 #define BOOT_HTTP_MAJOR_VERSION 1 53 #define BOOT_HTTP_MINOR_VERSION 0 54 #define BOOT_HTTP_MICRO_VERSION 0 55 56 static boot_http_ver_t boot_http_ver = { 57 BOOT_HTTP_MAJOR_VERSION, 58 BOOT_HTTP_MINOR_VERSION, 59 BOOT_HTTP_MICRO_VERSION 60 }; 61 62 static int early_err; /* Error from before error occurred */ 63 64 static boolean_t verbosemode = B_FALSE; 65 static char *cipher_list = NULL; /* Ciphers supported (if not default) */ 66 67 typedef struct { 68 int i; /* current position in buffer */ 69 int n; /* number of bytes in buffer */ 70 char buf[512]; /* buffer */ 71 } buf_struct_t; 72 73 typedef struct { 74 uint_t errsrc; /* Source of this error */ 75 ulong_t error; /* Which error? */ 76 } errent_t; 77 78 79 typedef enum { 80 HTTP_REQ_TYPE_HEAD = 1, 81 HTTP_REQ_TYPE_GET 82 } http_req_t; 83 84 #define FAILSAFE 20 /* Max # empty lines to accept */ 85 #define DEFAULT_TIMEOUT 10 /* Default socket read timeout value */ 86 #define HTTP_CONN_INFO 0x90919293 /* Identifies a http_conn_t struct */ 87 #define ESTACK_SIZE 20 /* Size of the stack */ 88 89 typedef struct http_conn_t { 90 uint_t signature; /* Cookie indicating this is a handle */ 91 int fd; /* Connection's fd... */ 92 SSL_CTX *ctx; 93 void *ssl; /* Handle to ssl data structure */ 94 int read_timeout; /* Timeout to use on read requests in sec */ 95 char *basic_auth_userid; /* Basic authentication user ID */ 96 char *basic_auth_password; /* and password */ 97 char is_multipart; /* B_TRUE if doing multipart/mixed download */ 98 char is_firstpart; /* B_TRUE if first part in a multipart xfer */ 99 char is_firstchunk; /* B_TRUE if first chunk in chunked xfer */ 100 char is_chunked; /* B_TRUE if message body is chunked */ 101 boolean_t keepalive; 102 struct sockaddr_in host_addr; /* Address of host */ 103 url_t uri; /* The current URI */ 104 url_hport_t proxy; /* The proxy info */ 105 boolean_t proxied; /* Connection is proxied */ 106 char *random_file; /* File with seed info for pseudo random */ 107 /* number generator */ 108 char *client_cert_file; /* File holding client's certificate */ 109 char *private_key_file; /* File with the private key */ 110 char *file_password; /* file with password to key or pkcs12 file. */ 111 http_respinfo_t resp; /* Response summary info */ 112 char **resphdr; /* Array of header response lines */ 113 buf_struct_t inbuf; 114 char *boundary; /* Boundary text (multipart downloads only) */ 115 uint_t boundary_len; /* Length of boundary string */ 116 uint_t numerrs; 117 uint_t nexterr; /* Next error to return */ 118 ssize_t body_size; /* Size of message body or chunk */ 119 ssize_t body_read; /* # of bytes of body_size processed */ 120 ssize_t body_size_tot; /* Total message body size */ 121 ssize_t body_read_tot; /* # of bytes of body_size_tot processed */ 122 errent_t errs[ESTACK_SIZE]; /* stack of errors on the last request */ 123 /* (libssl can return multiple errors on one */ 124 /* operation) */ 125 } http_conn_t; 126 127 /* 128 * Convenient macros for accessing fields in connection structure. 129 */ 130 #define CONN_HOSTNAME c_id->uri.hport.hostname 131 #define CONN_PORT c_id->uri.hport.port 132 #define CONN_ABSPATH c_id->uri.abspath 133 #define CONN_HTTPS c_id->uri.https 134 #define CONN_PROXY_HOSTNAME c_id->proxy.hostname 135 #define CONN_PROXY_PORT c_id->proxy.port 136 137 #define RESET_ERR(c_id) (c_id)->numerrs = 0, (c_id)->nexterr = 0 138 #define SET_ERR(c_id, src, err) if ((c_id)->numerrs < ESTACK_SIZE) \ 139 (c_id)->errs[(c_id)->numerrs].errsrc = (src), \ 140 (c_id)->errs[(c_id)->numerrs ++].error = (err) 141 142 #define GET_ERR(c_id, e_src, e_code) \ 143 if ((c_id)->nexterr < (c_id)->numerrs) \ 144 (e_src) = (c_id)->errs[((c_id)->nexterr)].errsrc, \ 145 (e_code) = (c_id)->errs[((c_id)->nexterr)++].error; \ 146 else \ 147 (e_src) = 0, (e_code) = 0 148 149 /* 150 * Macro used to increment message body read counters 151 */ 152 #define INC_BREAD_CNT(bool, bcnt) \ 153 if (bool) { \ 154 bcnt--; \ 155 c_id->body_read++;\ 156 c_id->body_read_tot++; \ 157 } 158 159 static int ssl_init = 0; /* 1 when ssl has been initialized */ 160 static char *ca_verify_file; /* List of trusted CA's */ 161 static int verify_depth = 16; /* Certificate chain depth to verify */ 162 static int p12_format = 0; /* Default to PEM format */ 163 164 165 /* prototypes for local functions */ 166 static int http_req(http_handle_t, const char *, http_req_t, offset_t, 167 offset_t); 168 static boolean_t http_check_conn(http_conn_t *); 169 static SSL_CTX *initialize_ctx(http_conn_t *); 170 static int tcp_connect(http_conn_t *, const char *, uint16_t); 171 static int readline(http_conn_t *, int, char *, int); 172 static int proxy_connect(http_conn_t *); 173 static int check_cert_chain(http_conn_t *, char *); 174 static void print_ciphers(SSL *); 175 static int read_headerlines(http_conn_t *, boolean_t); 176 static void free_response(http_conn_t *, int); 177 static int free_ctx_ssl(http_conn_t *); 178 static int get_chunk_header(http_conn_t *); 179 static int init_bread(http_conn_t *); 180 static int get_msgcnt(http_conn_t *, ssize_t *); 181 static int getaline(http_conn_t *, char *, int, boolean_t); 182 static int getbytes(http_conn_t *, char *, int); 183 static int http_srv_send(http_conn_t *, const void *, size_t); 184 static int http_srv_recv(http_conn_t *, void *, size_t); 185 static void handle_ssl_error(http_conn_t *, int); 186 static int count_digits(int); 187 static int hexdigit(char); 188 static char *eat_ws(const char *); 189 static boolean_t startswith(const char **strp, const char *starts); 190 191 /* ---------------------- public functions ----------------------- */ 192 193 /* 194 * http_set_p12_format - Set flag indicating that certs & keys will be in 195 * pkcs12 format. 196 * 197 * Default is PEM certs. When this is called, the default can be changed to 198 * pcs12 format. 199 */ 200 void 201 http_set_p12_format(int on_off) 202 { 203 p12_format = on_off; 204 } 205 206 /* 207 * http_get_version - Get current boot http support version 208 * 209 * pVer = http_get_version(); 210 * 211 * Arguments: 212 * None. 213 * 214 * Returns: 215 * Pointer to struct with version information. 216 * 217 * Returns the version of the http support in the current library. This 218 * is a struct with unsigned integsrs for <major>, <minor> and 219 * <micro> version numbers. <major> changes when an incompatible change 220 * is made. <minor> changes when an upwardly-compatible API change is 221 * made. <micro> consists of bug fixes, etc. 222 */ 223 boot_http_ver_t const * 224 http_get_version(void) 225 { 226 return (&boot_http_ver); 227 } 228 229 /* 230 * http_set_verbose - Turn verbose on/off 231 * 232 * http_set_verbose(on_off); 233 * 234 * Arguments: 235 * on_off - When TRUE, turn verbose mode one. When FALSE, turn 236 * verbose off. 237 * 238 * Returns: 239 * None. 240 * 241 * When enabled, information is logged to bootlog (or the Solaris equivalent). 242 */ 243 void 244 http_set_verbose(boolean_t on_off) 245 { 246 verbosemode = on_off; 247 } 248 249 /* 250 * http_set_cipher_list - Change the list of ciphers that can be used. 251 * 252 * ret = http_set_cipher_list(handle, list); 253 * 254 * Arguments: 255 * list - List of ciphers that can be used. 256 * 257 * Returns: 258 * 0 - Success 259 * -1 - An error occurred. Check http_get_lasterr(). 260 */ 261 int 262 http_set_cipher_list(const char *list) 263 { 264 early_err = 0; 265 266 if (list != NULL) { 267 list = strdup(list); 268 if (list == NULL) { 269 early_err = EHTTP_NOMEM; 270 return (-1); 271 } 272 } 273 274 free(cipher_list); 275 cipher_list = (char *)list; 276 return (0); 277 } 278 279 /* 280 * http_srv_init - Set up a structure for a connection. 281 * 282 * handle = http_srv_init(url); 283 * 284 * Arguments: 285 * url - the structure that contains the URI. 286 * 287 * Returns: 288 * != NULL - A handle for referring to this connection. 289 * == NULL - An error occurred. Get the exact error from 290 * http_get_lasterr(). 291 */ 292 http_handle_t 293 http_srv_init(const url_t *url) 294 { 295 http_conn_t *c_id; 296 297 early_err = 0; 298 if (url == NULL) { 299 early_err = EHTTP_BADARG; 300 return (NULL); 301 } 302 303 if ((c_id = malloc(sizeof (*c_id))) == NULL) { 304 early_err = EHTTP_NOMEM; 305 return (NULL); 306 } 307 308 bzero(c_id, sizeof (*c_id)); 309 c_id->uri = *url; 310 c_id->proxied = B_FALSE; 311 c_id->read_timeout = DEFAULT_TIMEOUT; 312 c_id->keepalive = B_TRUE; 313 c_id->fd = -1; 314 315 /* Do this at the end, just in case.... */ 316 c_id->signature = HTTP_CONN_INFO; 317 318 return (c_id); 319 } 320 321 /* 322 * http_conn_is_https - Determine whether the scheme is http or https. 323 * 324 * B_TRUE - Connection is an SSL connection. 325 * B_FALSE - Connection isn't SSL. 326 * 327 * ret = http_conn_is_https(handle, boolean_t *bool); 328 * 329 * Arguments: 330 * handle - Handle associated with the desired connection 331 * bool - Ptr to boolean in which to place result 332 * 333 * Returns: 334 * 0 - Success 335 * -1 - Some error occurred. 336 */ 337 int 338 http_conn_is_https(http_handle_t handle, boolean_t *bool) 339 { 340 http_conn_t *c_id = handle; 341 342 if (!http_check_conn(c_id)) 343 return (-1); 344 345 *bool = CONN_HTTPS; 346 return (0); 347 } 348 349 /* 350 * http_set_proxy - Establish the proxy name/port. 351 * 352 * ret = http_set_proxy(handle, proxy); 353 * 354 * Arguments: 355 * handle - Handle associated with the desired connection 356 * proxy - The hostport definition for the proxy. If NULL, 357 * The next connect will not use a proxy. 358 * 359 * Returns: 360 * 0 - Success 361 * -1 - An error occurred. Check http_get_lasterr(). 362 */ 363 int 364 http_set_proxy(http_handle_t handle, const url_hport_t *proxy) 365 { 366 http_conn_t *c_id = handle; 367 368 if (!http_check_conn(c_id)) 369 return (-1); 370 371 if (proxy != NULL) { 372 c_id->proxy = *proxy; 373 c_id->proxied = B_TRUE; 374 } else { 375 CONN_PROXY_HOSTNAME[0] = '\0'; 376 c_id->proxied = B_FALSE; 377 } 378 379 return (0); 380 } 381 382 /* 383 * http_set_keepalive - Set keepalive for this connection. 384 * 385 * http_set_keepalive(handle, on_off); 386 * 387 * Arguments: 388 * handle - Handle associated with the desired connection 389 * on_off - Boolean turning keepalive on (TRUE) or off (FALSE) 390 * 391 * Returns: 392 * 0 - Success. 393 * -1 - An error occurred. Check http_get_lasterr(). 394 * 395 * This setting takes effect next time a connection is opened using this 396 * handle. 397 */ 398 int 399 http_set_keepalive(http_handle_t handle, boolean_t on_off) 400 { 401 http_conn_t *c_id = handle; 402 403 if (!http_check_conn(c_id)) 404 return (-1); 405 406 c_id->keepalive = on_off; 407 return (0); 408 } 409 410 /* 411 * http_set_socket_read_timeout - Set the timeout reads 412 * 413 * http_set_socket_read_timeout(handle, timeout); 414 * 415 * Arguments: 416 * handle - Handle associated with the desired connection 417 * timeout - Timeout, in seconds. Zero will default to 10 second 418 * timeouts. 419 * 420 * Returns: 421 * 0 - Success. 422 * -1 - An error occurred. Check http_get_lasterr(). 423 * 424 * This setting takes effect beginning with the next read operation on this 425 * connection. 426 */ 427 int 428 http_set_socket_read_timeout(http_handle_t handle, uint_t timout) 429 { 430 http_conn_t *c_id = handle; 431 432 if (!http_check_conn(c_id)) 433 return (-1); 434 435 c_id->read_timeout = (timout) ? timout : DEFAULT_TIMEOUT; 436 return (0); 437 } 438 439 /* 440 * http_set_basic_auth - Set the basic authorization user ID and password 441 * 442 * ret = http_set_basic_auth(handle, userid, password); 443 * 444 * Arguments: 445 * handle - Handle associated with the desired connection 446 * userid - ID to pass as part of http/https request 447 * password- Password which goes with the user ID 448 * 449 * Returns: 450 * 0 - Success 451 * -1 - An error occurred. Check http_get_lasterr(). 452 * 453 * This must be set before a https connection is made. 454 */ 455 int 456 http_set_basic_auth(http_handle_t handle, const char *userid, 457 const char *password) 458 { 459 http_conn_t *c_id = handle; 460 461 if (!http_check_conn(c_id)) 462 return (-1); 463 464 if (password == NULL || userid == NULL || userid[0] == '\0') { 465 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 466 return (-1); 467 } 468 469 userid = strdup(userid); 470 password = strdup(password); 471 if (userid == NULL || password == NULL) { 472 free((void *)userid); 473 free((void *)password); 474 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 475 return (-1); 476 } 477 478 free(c_id->basic_auth_userid); 479 c_id->basic_auth_userid = (char *)userid; 480 free(c_id->basic_auth_password); 481 c_id->basic_auth_password = (char *)password; 482 return (0); 483 } 484 485 /* 486 * http_set_random_file - See the pseudo random number generator with file data 487 * 488 * ret = http_set_random_file(handle, filename); 489 * 490 * Arguments: 491 * handle - Handle associated with the desired connection 492 * filename 493 * - filename (including path) with random number seed. 494 * 495 * Returns: 496 * 0 - Success 497 * -1 - An error occurred. Check http_get_lasterr(). 498 * 499 * This must be set before a https connection is made. 500 */ 501 int 502 http_set_random_file(http_handle_t handle, const char *fname) 503 { 504 http_conn_t *c_id = handle; 505 506 if (!http_check_conn(c_id)) 507 return (-1); 508 509 if (fname != NULL) { 510 fname = strdup(fname); 511 if (fname == NULL) { 512 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 513 return (-1); 514 } 515 } 516 517 free(c_id->random_file); 518 c_id->random_file = (char *)fname; 519 return (0); 520 } 521 522 /* 523 * http_set_certificate_authority_file - Set the CA file. 524 * 525 * ret = http_set_certificate_authority_file(filename); 526 * 527 * Arguments: 528 * filename- File with the certificate authority certs 529 * 530 * Returns: 531 * 0 - Success 532 * -1 - An error occurred. Check http_get_lasterr(). 533 * 534 * This must be set before https connections to the servers is done. 535 */ 536 int 537 http_set_certificate_authority_file(const char *fname) 538 { 539 early_err = 0; 540 541 if (fname != NULL) { 542 fname = strdup(fname); 543 if (fname == NULL) { 544 early_err = EHTTP_NOMEM; 545 return (-1); 546 } 547 } 548 549 free(ca_verify_file); 550 ca_verify_file = (char *)fname; 551 return (0); 552 } 553 554 /* 555 * http_set_client_certificate_file - Set the file containing the PKCS#12 556 * client certificate and optionally its certificate chain. 557 * 558 * ret = http_set_client_certificate_file(handle, filename); 559 * 560 * Arguments: 561 * handle - Handle associated with the desired connection 562 * filename- File (including path) containing certificate, etc. 563 * 564 * Returns: 565 * 0 - Success 566 * -1 - An error occurred. Check http_get_lasterr(). 567 * 568 * This must be set before the handle is used to make a https connection 569 * which will require a client certificate. 570 */ 571 int 572 http_set_client_certificate_file(http_handle_t handle, const char *fname) 573 { 574 http_conn_t *c_id = handle; 575 576 if (!http_check_conn(c_id)) 577 return (-1); 578 579 if (fname != NULL) { 580 fname = strdup(fname); 581 if (fname == NULL) { 582 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 583 return (-1); 584 } 585 } 586 587 free(c_id->client_cert_file); 588 c_id->client_cert_file = (char *)fname; 589 return (0); 590 } 591 592 /* 593 * http_set_password - Set the password for the private key or pkcs12 file. 594 * 595 * ret = http_set_password(handle, password); 596 * 597 * Arguments: 598 * handle - Handle associated with the desired connection 599 * password- Password for the client's private key file or pkcs12 file. 600 * 601 * Returns: 602 * 0 - Success 603 * -1 - An error occurred. Check http_get_lasterr(). 604 * 605 * This must be set before the handle is used to make a https connection. 606 */ 607 int 608 http_set_password(http_handle_t handle, const char *password) 609 { 610 http_conn_t *c_id = handle; 611 612 if (!http_check_conn(c_id)) 613 return (-1); 614 615 if (password != NULL) { 616 password = strdup(password); 617 if (password == NULL) { 618 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 619 return (-1); 620 } 621 } 622 623 free(c_id->file_password); 624 c_id->file_password = (char *)password; 625 return (0); 626 } 627 628 /* 629 * http_set_key_file_password - Set the password for the private key 630 * file. 631 * 632 * ret = http_set_key_file_password(handle, password); 633 * 634 * Arguments: 635 * handle - Handle associated with the desired connection 636 * password- Password for the client's private key file. 637 * 638 * Returns: 639 * 0 - Success 640 * -1 - An error occurred. Check http_get_lasterr(). 641 * 642 * This must be set before the handle is used to make a https connection. 643 */ 644 int 645 http_set_key_file_password(http_handle_t handle, const char *password) 646 { 647 return (http_set_password(handle, password)); 648 } 649 650 /* 651 * http_set_private_key_file - Set the file containing the PKCS#12 652 * private key for this client. 653 * 654 * ret = http_set_private_key_file(handle, filename); 655 * 656 * Arguments: 657 * handle - Handle associated with the desired connection 658 * filename- File (including path) containing the private key. 659 * 660 * Returns: 661 * 0 - Success 662 * -1 - An error occurred. Check http_get_lasterr(). 663 * 664 * This must be set before the handle is used to make a https connection. 665 */ 666 int 667 http_set_private_key_file(http_handle_t handle, const char *fname) 668 { 669 http_conn_t *c_id = handle; 670 671 if (!http_check_conn(c_id)) 672 return (-1); 673 674 if (fname != NULL) { 675 fname = strdup(fname); 676 if (fname == NULL) { 677 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 678 return (-1); 679 } 680 } 681 682 free(c_id->private_key_file); 683 c_id->private_key_file = (char *)fname; 684 return (0); 685 } 686 687 /* 688 * http_srv_connect - Establish a connection to the server 689 * 690 * ret = http_srv_connect(handle); 691 * 692 * Arguments: 693 * handle - Handle associated with the desired connection 694 * 695 * Returns: 696 * 0 - Success 697 * -1 - An error occurred. Check http_get_lasterr() for specifics. 698 */ 699 int 700 http_srv_connect(http_handle_t handle) 701 { 702 http_conn_t *c_id = handle; 703 SSL_CTX *ctx = NULL; 704 int retval; 705 706 ERR_clear_error(); 707 if (!http_check_conn(c_id)) 708 return (-1); 709 710 if (CONN_HTTPS) { 711 /* Build our SSL context (this function sets any errors) */ 712 ctx = initialize_ctx(c_id); 713 if (ctx == NULL) { 714 libbootlog(BOOTLOG_CRIT, 715 "http_srv_connect: initialize_ctx returned NULL"); 716 return (-1); 717 } 718 } 719 720 /* Connect the TCP socket */ 721 if (c_id->proxied) { 722 c_id->fd = proxy_connect(c_id); 723 } else { 724 c_id->fd = tcp_connect(c_id, CONN_HOSTNAME, CONN_PORT); 725 } 726 727 if (c_id->fd < 0) { 728 if (ctx != NULL) 729 SSL_CTX_free(ctx); 730 libbootlog(BOOTLOG_CRIT, 731 "http_srv_connect: %s returned %d", 732 (c_id->proxied) ? "proxy_connect" : "tcp_connect", 733 c_id->fd); 734 return (-1); 735 } 736 737 if (CONN_HTTPS) { 738 /* Connect the SSL socket */ 739 if ((c_id->ssl = SSL_new(ctx)) == NULL) { 740 ulong_t err; 741 while ((err = ERR_get_error()) != 0) 742 SET_ERR(c_id, ERRSRC_LIBSSL, err); 743 libbootlog(BOOTLOG_CRIT, 744 "http_srv_connect: SSL_new returned " 745 "NULL"); 746 (void) free_ctx_ssl(c_id); 747 return (-1); 748 } 749 if (verbosemode) 750 print_ciphers(c_id->ssl); 751 752 /* Ensure automatic negotiations will do things right */ 753 SSL_set_connect_state(c_id->ssl); 754 755 if (SSL_set_fd(c_id->ssl, c_id->fd) == 0) { 756 ulong_t err; 757 while ((err = ERR_get_error()) != 0) 758 SET_ERR(c_id, ERRSRC_LIBSSL, err); 759 libbootlog(BOOTLOG_CRIT, 760 "http_srv_connect: SSL_set_fd returned 0"); 761 (void) free_ctx_ssl(c_id); 762 return (-1); 763 } 764 765 if ((retval = SSL_connect(c_id->ssl)) <= 0) { 766 handle_ssl_error(c_id, retval); 767 libbootlog(BOOTLOG_CRIT, 768 "http_srv_connect: SSL_connect"); 769 (void) free_ctx_ssl(c_id); 770 return (-1); 771 } 772 773 if (check_cert_chain(c_id, CONN_HOSTNAME) != 0) { 774 (void) free_ctx_ssl(c_id); 775 return (-1); 776 } 777 778 if (verbosemode) 779 print_ciphers(c_id->ssl); 780 } 781 782 return (0); 783 } 784 785 /* 786 * http_head_request - Issue http HEAD request 787 * 788 * ret = http_head_request(handle, abs_path); 789 * 790 * Arguments: 791 * handle - Handle associated with the desired connection 792 * abs_path- File name portion of the URI, beginning with a /. Query, 793 * segment, etc are allowed. 794 * 795 * Returns: 796 * 0 - Success 797 * -1 - An error occurred. Check http_get_lasterr(). 798 */ 799 int 800 http_head_request(http_handle_t handle, const char *abs_path) 801 { 802 return (http_req(handle, abs_path, HTTP_REQ_TYPE_HEAD, 0, 0)); 803 } 804 805 /* 806 * http_get_request - Issue http GET request without a range. 807 * 808 * ret = http_get_request(handle, abs_path); 809 * 810 * Arguments: 811 * handle - Handle associated with the desired connection 812 * abs_path- File name portion of the URI, beginning with a /. Query, 813 * segment, etc are allowed. 814 * 815 * Returns: 816 * 0 - Success 817 * -1 - An error occurred. Check http_get_lasterr(). 818 */ 819 int 820 http_get_request(http_handle_t handle, const char *abs_path) 821 { 822 return (http_req(handle, abs_path, HTTP_REQ_TYPE_GET, -1, 0)); 823 } 824 825 /* 826 * http_get_range_request - Issue http GET request using a range. 827 * 828 * ret = http_get_range_request(handle, abs_path, curpos, len); 829 * 830 * Arguments: 831 * handle - Handle associated with the desired connection 832 * abs_path- File name portion of the URI, beginning with a /. Query, 833 * segment, etc are allowed. 834 * curpos - >=0 - Beginning of range 835 * len - = 0 - Range ends at the end of the file 836 * > 0 - Length of range. 837 * 838 * Returns: 839 * 0 - Success 840 * -1 - An error occurred. Check http_get_lasterr(). 841 */ 842 int 843 http_get_range_request(http_handle_t handle, const char *abs_path, 844 offset_t curpos, offset_t len) 845 { 846 http_conn_t *c_id = handle; 847 848 if (!http_check_conn(c_id)) 849 return (-1); 850 851 if (curpos < 0) { 852 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 853 return (-1); 854 } 855 856 return (http_req(handle, abs_path, HTTP_REQ_TYPE_GET, curpos, len)); 857 } 858 859 /* 860 * http_free_respinfo - Free a respinfo structure 861 * 862 * ret = http_free_respinfo(resp); 863 * 864 * Arguments: 865 * resp - respinfo structure presumably allocated by 866 * http_process_headers() or http_process_part_headers() 867 * 868 * Note that if resp is NULL, then this results in a NOOP. 869 * 870 */ 871 void 872 http_free_respinfo(http_respinfo_t *resp) 873 { 874 if (resp == NULL) { 875 return; 876 } 877 878 if (resp->statusmsg != NULL) { 879 free(resp->statusmsg); 880 } 881 free(resp); 882 } 883 884 /* 885 * http_process_headers - Read in the header lines from the response 886 * 887 * ret = http_process_headers(handle, resp); 888 * 889 * Arguments: 890 * handle - Handle associated with the connection where the request 891 * was made. 892 * resp - Summary information about the response. 893 * 894 * Returns: 895 * 0 - Success 896 * < 0 - An error occurred. Specifics of the error can 897 * be gotten using http_get_lasterr(). 898 * 899 * Process the HTTP headers in the response. Check for a valid response 900 * status line. Allocate and return response information via the 'resp' 901 * argument. Header lines are stored locally, are are returned using calls 902 * to http_get_response_header() and http_get_header_value(). 903 * 904 * Note that the errors will be set in the http_conn_t struct before the 905 * function which detected the error returns. 906 * 907 * Note that if resp is non-NULL, then upon a successful return, information 908 * about the status line, the code in the status line and the number of 909 * header lines are returned in the http_respinfo_t structure. The caller is 910 * responsible for freeing the resources allocated to this structure via 911 * http_free_respinfo(). 912 * 913 * Note that the counters used to read message bodies are initialized here. 914 * 915 * Calling this function replaces the header information which is 916 * queried using http_get_response_header() and http_get_header_value(). 917 * Once this function is called, headers read by the previous call 918 * to http_process_headers() or http_process_part_headers() is lost. 919 */ 920 int 921 http_process_headers(http_handle_t handle, http_respinfo_t **resp) 922 { 923 http_conn_t *c_id = handle; 924 http_respinfo_t *lresp; 925 char line[MAXHOSTNAMELEN]; 926 char *ptr; 927 int i; 928 929 ERR_clear_error(); 930 if (!http_check_conn(c_id)) 931 return (-1); 932 933 if (resp != NULL) { 934 if ((lresp = malloc(sizeof (http_respinfo_t))) == NULL) { 935 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 936 return (-1); 937 } 938 939 bzero(lresp, sizeof (http_respinfo_t)); 940 } 941 942 /* 943 * check the response status line, expecting 944 * HTTP/1.1 200 OK 945 */ 946 i = getaline(c_id, line, sizeof (line), B_FALSE); 947 if (i == 0) { 948 if (resp != NULL) { 949 *resp = lresp; 950 } 951 return (0); 952 } 953 954 if (i < 0) { 955 /* 956 * Cause of I/O error was already put into 957 * error stack. This is an additional error. 958 */ 959 http_free_respinfo(lresp); 960 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NODATA); 961 return (-1); 962 } 963 964 free_response(c_id, B_TRUE); 965 966 if (verbosemode) 967 libbootlog(BOOTLOG_VERBOSE, "http_process_headers: %s", line); 968 969 ptr = line; 970 if (strncmp(ptr, "HTTP/1.1", 8) != 0) { 971 http_free_respinfo(lresp); 972 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOT_1_1); 973 return (-1); 974 } 975 976 /* skip to the code */ 977 ptr += 8; 978 while (isspace(*ptr)) 979 ptr++; 980 981 /* make sure it's three digits */ 982 i = 0; 983 while (isdigit(ptr[i])) 984 i++; 985 if (i != 3) { 986 http_free_respinfo(lresp); 987 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADHDR); 988 return (-1); 989 } 990 c_id->resp.code = strtol(ptr, NULL, 10); 991 992 /* skip to the message */ 993 ptr += 3; 994 while (isspace(*ptr)) 995 ptr++; 996 997 /* save the message */ 998 c_id->resp.statusmsg = malloc(strlen(ptr) + 1); 999 if (c_id->resp.statusmsg == NULL) { 1000 http_free_respinfo(lresp); 1001 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 1002 return (-1); 1003 } 1004 (void) strcpy(c_id->resp.statusmsg, ptr); 1005 1006 if ((i = read_headerlines(c_id, B_FALSE)) < 0) { 1007 /* 1008 * Error stack was already set at a lower level. 1009 * 'statusmsg' will be cleaned up next time 1010 * headers are read. 1011 */ 1012 http_free_respinfo(lresp); 1013 return (-1); 1014 } 1015 1016 /* 1017 * See if there is a 'content-type: multipart/mixed' line in the 1018 * headers. If so, get the boundary string. 1019 */ 1020 ptr = http_get_header_value(handle, "Content-Type"); 1021 if (ptr != NULL) { 1022 char *ptr2; 1023 1024 ptr2 = ptr; 1025 while (isspace(*ptr2)) 1026 ptr2 ++; 1027 if (startswith((const char **)&ptr2, "Multipart/Mixed;")) { 1028 while (isspace(*ptr2)) 1029 ptr2 ++; 1030 if (startswith((const char **)&ptr2, "Boundary=")) { 1031 if (ptr2[0] == '"') { 1032 ptr2 ++; 1033 if (ptr2[strlen(ptr2) - 1] == '"') 1034 ptr2[strlen(ptr2) - 1] = '\0'; 1035 } 1036 c_id->boundary = strdup(ptr2); 1037 if (c_id->boundary == NULL) { 1038 free(ptr); 1039 http_free_respinfo(lresp); 1040 SET_ERR(c_id, ERRSRC_LIBHTTP, 1041 EHTTP_NOMEM); 1042 return (-1); 1043 } 1044 c_id->boundary_len = strlen(c_id->boundary); 1045 c_id->is_multipart = B_TRUE; 1046 c_id->is_firstpart = B_TRUE; 1047 } 1048 } 1049 free(ptr); 1050 } 1051 1052 /* 1053 * Initialize the counters used to process message bodies. 1054 */ 1055 if (init_bread(c_id) != 0) { 1056 /* 1057 * Error stack was already set at a lower level. 1058 */ 1059 http_free_respinfo(lresp); 1060 return (-1); 1061 } 1062 1063 /* Copy fields to the caller's structure */ 1064 if (resp != NULL) { 1065 lresp->code = c_id->resp.code; 1066 lresp->nresphdrs = c_id->resp.nresphdrs; 1067 lresp->statusmsg = strdup(c_id->resp.statusmsg); 1068 if (lresp->statusmsg == NULL) { 1069 http_free_respinfo(lresp); 1070 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 1071 return (-1); 1072 } 1073 *resp = lresp; 1074 } 1075 1076 return (0); 1077 } 1078 1079 /* 1080 * http_process_part_headers - Read in part boundary and header lines for the 1081 * next part of a multipart message. 1082 * 1083 * ret = http_process_part_headers(handle, resp); 1084 * 1085 * Arguments: 1086 * handle - Handle associated with the connection where the request 1087 * was made. 1088 * resp - Return address for summary information about the 1089 * header block. 1090 * 1091 * Returns: 1092 * = 1 - The end part was found. 1093 * = 0 - Success, with header info returned in 'resp' 1094 * = -1 - An error occurred. Specifics of the error can 1095 * be gotten using http_get_lasterr(). 1096 * 1097 * This function reads any \r\n sequences (empty lines) and expects to get 1098 * a boundary line as the next non-empty line. It then reads header lines 1099 * (content-length, etc) until it gets another empty lines, which ends the 1100 * header section. 1101 * 1102 * Note that if resp is non-NULL, then upon a successful return, information 1103 * about the the number of header lines is returned in the http_respinfo_t 1104 * structure. The caller is responsible for freeing the resources allocated 1105 * to this structure via http_free_respinfo(). 1106 * 1107 * Headers values can be returned using http_get_response_header() and 1108 * http_get_header_value(). 1109 * 1110 * Calling this function replaces the header information which is 1111 * queried using http_get_response_header() and http_get_header_value(). 1112 * Once this function is called, information returned by the previous call 1113 * to http_process_headers() or http_process_part_headers() is gone. 1114 */ 1115 int 1116 http_process_part_headers(http_handle_t handle, http_respinfo_t **resp) 1117 { 1118 http_conn_t *c_id = handle; 1119 char line[MAXHOSTNAMELEN]; 1120 int count; 1121 int limit; 1122 int i; 1123 1124 ERR_clear_error(); 1125 if (!http_check_conn(c_id)) 1126 return (-1); 1127 1128 if (c_id->is_multipart == 0) { 1129 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOTMULTI); 1130 return (-1); 1131 } 1132 1133 /* 1134 * Figure out how many empty lines to allow. Before the first 1135 * boundary of the transmission, there can be any number of 1136 * empty lines (from 0 up). Limit these to some reasonable 1137 * failsafe. 1138 * 1139 * For the 2nd and later boundaries, there is supposed to be 1140 * one crlf pair. However, many implementations don't require 1141 * it. So don't require it. 1142 */ 1143 if (c_id->is_firstpart) { 1144 limit = FAILSAFE; 1145 c_id->is_firstpart = B_FALSE; 1146 } else 1147 limit = 1; 1148 1149 /* Look for the boundary line. */ 1150 count = 0; 1151 while ((i = getaline(c_id, line, sizeof (line), B_TRUE)) == 0 && 1152 count < FAILSAFE) 1153 count ++; 1154 if (i < 0 || count > limit) { 1155 /* 1156 * If I/O error, cause was already put into 1157 * error stack. This is an additional error. 1158 */ 1159 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOBOUNDARY); 1160 return (-1); 1161 } 1162 1163 free_response(c_id, B_FALSE); 1164 1165 if (verbosemode) 1166 libbootlog(BOOTLOG_VERBOSE, 1167 "http_process_part_headers: %s", line); 1168 1169 /* Look for boundary line - '--<boundary text> */ 1170 if (line[0] != '-' || line[1] != '-' || 1171 strncmp(&line[2], c_id->boundary, c_id->boundary_len) != 0) { 1172 /* No boundary line.... */ 1173 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOBOUNDARY); 1174 return (-1); 1175 } 1176 1177 /* Is this the end-of-parts boundary (ends with a trailing '--') */ 1178 if (strcmp(&line[c_id->boundary_len + 2], "--") == 0) { 1179 return (1); 1180 } 1181 1182 free_response(c_id, B_FALSE); 1183 if (read_headerlines(c_id, B_TRUE) < 0) { 1184 /* Error stack was already set at a lower level. */ 1185 return (-1); 1186 } 1187 1188 /* Copy fields to the caller's structure */ 1189 if (resp != NULL) { 1190 if ((*resp = malloc(sizeof (http_respinfo_t))) == NULL) { 1191 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 1192 return (-1); 1193 } 1194 bzero(*resp, sizeof (http_respinfo_t)); 1195 (*resp)->code = ' '; 1196 (*resp)->nresphdrs = c_id->resp.nresphdrs; 1197 } 1198 1199 return (0); 1200 } 1201 1202 /* 1203 * http_get_response_header - Get a line from the response header 1204 * 1205 * ret = http_get_response_header(handle, whichline); 1206 * 1207 * Arguments: 1208 * handle - Handle associated with the desired connection 1209 * whichline - Which line of the header to return. This must be between 1210 * zero and resp.nresphdrs which was returned by the call to 1211 * http_process_headers(). 1212 * 1213 * Returns: 1214 * ptr - Points to a copy of the header line. 1215 * NULL - An error occurred. Check http_get_lasterr(). 1216 */ 1217 char * 1218 http_get_response_header(http_handle_t handle, uint_t which) 1219 { 1220 http_conn_t *c_id = handle; 1221 char *res; 1222 1223 if (!http_check_conn(c_id)) 1224 return (NULL); 1225 1226 if (which >= c_id->resp.nresphdrs) { 1227 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_OORANGE); 1228 return (NULL); 1229 } 1230 1231 res = strdup(c_id->resphdr[which]); 1232 if (res == NULL) { 1233 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 1234 return (NULL); 1235 } 1236 return (res); 1237 } 1238 1239 /* 1240 * http_get_header_value - Get the value of a header line. 1241 * 1242 * ret = http_get_header_value(handle, what); 1243 * 1244 * Arguments: 1245 * handle - Handle associated with the desired connection 1246 * what - The field name to look up. 1247 * 1248 * Returns: 1249 * ptr - Points to a copy of the header value. 1250 * NULL - An error occurred. Check http_get_lasterr(). 1251 */ 1252 char * 1253 http_get_header_value(http_handle_t handle, const char *field_name) 1254 { 1255 http_conn_t *c_id = handle; 1256 char *ptr; 1257 char *res; 1258 int i; 1259 int n; 1260 1261 if (!http_check_conn(c_id)) 1262 return (NULL); 1263 1264 if (field_name == NULL || field_name[0] == '\0') { 1265 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 1266 return (NULL); 1267 } 1268 1269 for (i = 0; i < c_id->resp.nresphdrs; i++) { 1270 ptr = c_id->resphdr[i]; 1271 n = strlen(field_name); 1272 if (strncasecmp(field_name, ptr, n) == 0 && ptr[n] == ':') { 1273 ptr += n + 1; 1274 1275 while (isspace(*ptr)) 1276 ptr++; 1277 1278 res = strdup(ptr); 1279 if (res == NULL) { 1280 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 1281 return (NULL); 1282 } 1283 return (res); 1284 } 1285 } 1286 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMATCH); 1287 return (NULL); 1288 } 1289 1290 /* 1291 * http_read_body - Read the HTTP response body. 1292 * 1293 * ret = http_read_body(handle, recv_buf_ptr, recv_buf_size); 1294 * 1295 * Arguments: 1296 * handle - Handle associated with the relevant connection 1297 * recv_buf_ptr - Points to buffer to receive buffer 1298 * recv_buf_size - Length in bytes of buffer. 1299 * 1300 * Returns: 1301 * n - Number of bytes read.. 1302 * < 0 - An error occurred. This is (the number of bytes gotten + 1), 1303 * negated. In other words, if 'n' bytes were read and then an 1304 * error occurred, this will return (-(n+1)). So zero bytes 1305 * were read and then an error occurs, this will return -1. If 1306 * 1 byte was read, it will return -2, etc. Specifics of the 1307 * error can be gotten using http_get_lasterr(). 1308 * 1309 * Note that the errors will be set in the http_conn_t struct before the 1310 * function which detected the error returns. 1311 */ 1312 int 1313 http_read_body(http_handle_t handle, char *recv_buf_ptr, size_t recv_buf_size) 1314 { 1315 http_conn_t *c_id = handle; 1316 1317 ERR_clear_error(); 1318 if (!http_check_conn(c_id)) 1319 return (-1); 1320 1321 if (recv_buf_ptr == NULL || recv_buf_size == 0) { 1322 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 1323 return (-1); 1324 } 1325 1326 return (getbytes(c_id, recv_buf_ptr, recv_buf_size)); 1327 } 1328 1329 /* 1330 * http_srv_disconnect - Get rid of the connection to the server without 1331 * freeing the http_conn_t structure. 1332 * 1333 * ret = http_srv_disconnect(handle); 1334 * 1335 * Arguments: 1336 * handle - Handle associated with the connection 1337 * 1338 * Returns: 1339 * 0 - Success 1340 * -1 - An error occurred. Specifics of the error can 1341 * be gotten using http_get_lasterr(). 1342 */ 1343 int 1344 http_srv_disconnect(http_handle_t handle) 1345 { 1346 http_conn_t *c_id = handle; 1347 int err_ret; 1348 1349 ERR_clear_error(); 1350 if (!http_check_conn(c_id)) 1351 return (-1); 1352 1353 err_ret = free_ctx_ssl(c_id); 1354 bzero(&c_id->inbuf, sizeof (c_id->inbuf)); 1355 free_response(c_id, B_TRUE); 1356 1357 return (err_ret); 1358 } 1359 1360 /* 1361 * http_srv_close - Close the connection and clean up the http_conn_t 1362 * structure. 1363 * 1364 * http_srv_close(handle); 1365 * 1366 * Arguments: 1367 * handle - Handle associated with the desired connection 1368 * 1369 * Returns: 1370 * 0 - Success 1371 * -1 - An error occurred. Specifics of the error can 1372 * be gotten using http_get_lasterr(). 1373 */ 1374 int 1375 http_srv_close(http_handle_t handle) 1376 { 1377 http_conn_t *c_id = handle; 1378 int err_ret = 0; 1379 1380 if (!http_check_conn(c_id)) 1381 return (-1); 1382 1383 if (c_id->ctx != NULL || c_id->ssl != NULL || c_id->fd != -1) 1384 err_ret = http_srv_disconnect(handle); 1385 1386 free(c_id->basic_auth_userid); 1387 free(c_id->basic_auth_password); 1388 free(c_id->resp.statusmsg); 1389 free(c_id->client_cert_file); 1390 free(c_id->private_key_file); 1391 free(c_id->random_file); 1392 free(c_id->file_password); 1393 c_id->signature = 0; 1394 1395 free(c_id); 1396 return (err_ret); 1397 } 1398 1399 /* 1400 * http_get_conn_info - Return current information about the connection 1401 * 1402 * err = http_get_conn_info(handle); 1403 * 1404 * Arguments: 1405 * handle - Handle associated with the connection in question 1406 * 1407 * Returns: 1408 * non_NULL- Points to structure 1409 * NULL - An error exists. Check http_get_lasterr(). 1410 */ 1411 http_conninfo_t * 1412 http_get_conn_info(http_handle_t handle) 1413 { 1414 http_conn_t *c_id = handle; 1415 http_conninfo_t *info; 1416 1417 if (!http_check_conn(c_id)) 1418 return (NULL); 1419 1420 info = malloc(sizeof (*info)); 1421 if (info == NULL) { 1422 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 1423 return (NULL); 1424 } 1425 1426 bzero(info, sizeof (*info)); 1427 1428 info->uri = c_id->uri; 1429 info->proxy = c_id->proxy; 1430 info->keepalive = c_id->keepalive; 1431 info->read_timeout = c_id->read_timeout; 1432 1433 return (info); 1434 } 1435 1436 /* 1437 * http_get_lasterr - Return the next error on the last operation 1438 * 1439 * err = http_get_lasterr(handle, errsrc); 1440 * 1441 * Arguments: 1442 * handle - Handle associated with the connection in question 1443 * If no valid handle exists yet, this can be NULL. 1444 * However, it must be checked with the very next call. 1445 * errsrc - Returns the Sources of errors (ERRSRC_* values). 1446 * 1447 * Returns: 1448 * 0 - No error exists 1449 * <> 0 - The error. 1450 */ 1451 ulong_t 1452 http_get_lasterr(http_handle_t handle, uint_t *errsrc) 1453 { 1454 http_conn_t *c_id = handle; 1455 ulong_t src; 1456 ulong_t err; 1457 1458 if (c_id == NULL || c_id->signature != HTTP_CONN_INFO) { 1459 if (errsrc) 1460 *errsrc = ERRSRC_LIBHTTP; 1461 err = early_err; 1462 early_err = 0; 1463 return (err); 1464 } 1465 1466 GET_ERR(c_id, src, err); 1467 if (src == 0 && err == 0) { 1468 if (errsrc) 1469 *errsrc = ERRSRC_LIBHTTP; 1470 err = early_err; 1471 early_err = 0; 1472 return (err); 1473 } 1474 if (errsrc) 1475 *errsrc = src; 1476 return (err); 1477 } 1478 1479 /* 1480 * http_decode_err - Decode a libssl error 1481 * 1482 * err = http_decode_err(err, errlib, errfunc, errcode); 1483 * 1484 * Arguments: 1485 * err - libssl/libcrypto error returned. 1486 * errlib - returns libssl/libcrypto sublibrary that caused the error 1487 * errfunc - returns function in that library 1488 * errcode - returns error code 1489 * 1490 * Returns: 1491 * None other than the above. 1492 */ 1493 void 1494 http_decode_err(ulong_t err, int *errlib, int *errfunc, int *errcode) 1495 { 1496 if (errlib) 1497 *errlib = ERR_GET_LIB(err); 1498 if (errfunc) 1499 *errfunc = ERR_GET_FUNC(err); 1500 if (errcode) 1501 *errcode = ERR_GET_REASON(err); 1502 } 1503 1504 /* ---------------------- private functions ----------------------- */ 1505 1506 /* 1507 * http_req - Issue http request (either HEAD or GET) 1508 * 1509 * ret = http_req(handle, abs_path, reqtype, curpos, len); 1510 * 1511 * Arguments: 1512 * handle - Handle associated with the desired connection 1513 * abs_path- File name portion of the URI, beginning with a /. Query, 1514 * segment, etc are allowed. 1515 * type - HTTP_REQ_TYPE_HEAD or HTTP_REQ_TYPE_GET 1516 * 1517 * In the case of GET requests, 1518 * curpos- -1 - Range not used 1519 * >=0 - Beginning of range 1520 * len - 0 - Range ends at the end of the file 1521 * >0 - Length of range. 1522 * 1523 * Returns: 1524 * 0 - Success 1525 * -1 - An error occurred. Check http_get_lasterr(). 1526 */ 1527 static int 1528 http_req(http_handle_t handle, const char *abs_path, http_req_t type, 1529 offset_t curpos, offset_t len) 1530 { 1531 http_conn_t *c_id = handle; 1532 char *request; 1533 char *reqtypename; 1534 char *newreq; 1535 int requestlen; 1536 int retval; 1537 int j; 1538 1539 ERR_clear_error(); 1540 if (!http_check_conn(c_id)) 1541 return (-1); 1542 1543 if (abs_path == NULL || abs_path[0] == '\0') { 1544 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 1545 return (-1); 1546 } 1547 1548 /* Determine the name for the request type */ 1549 switch (type) { 1550 case HTTP_REQ_TYPE_GET: 1551 reqtypename = "GET"; 1552 if (curpos < 0 && curpos != -1) { 1553 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 1554 return (-1); 1555 } 1556 break; 1557 1558 case HTTP_REQ_TYPE_HEAD: 1559 reqtypename = "HEAD"; 1560 break; 1561 1562 default: 1563 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 1564 return (-1); 1565 } 1566 1567 /* Do rudimentary checks on the absolute path */ 1568 if (abs_path == NULL || *abs_path != '/') { 1569 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 1570 libbootlog(BOOTLOG_CRIT, "http_req: invalid file path"); 1571 if (abs_path != NULL) 1572 libbootlog(BOOTLOG_CRIT, " %s", abs_path); 1573 return (-1); 1574 } 1575 (void) strlcpy(CONN_ABSPATH, abs_path, MAXHOSTNAMELEN); 1576 1577 /* 1578 * Size the request. 1579 * 1580 * With proxy: 1581 * reqtypename + " http://" + host + ":" + port + path + 1582 * " HTTP/1.1\r\n" + 1583 * Without proxy: 1584 * reqtypename + " " + path + " HTTP/1.1\r\n" + 1585 */ 1586 requestlen = strlen(reqtypename) + 8 + strlen(CONN_HOSTNAME) + 1 + 1587 count_digits(CONN_PORT) + strlen(CONN_ABSPATH) + 11; 1588 1589 /* 1590 * Plus the rest: 1591 * "Host: " + targethost + ":" + count_digits(port) + "\r\n" + 1592 * "Connection: Keep-Alive\r\n" plus trailing "\r\n\0" 1593 */ 1594 requestlen += 6 + strlen(CONN_HOSTNAME) + 1 + 1595 count_digits(CONN_PORT) + 2 + 24 + 3; 1596 if ((request = malloc(requestlen)) == NULL) { 1597 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 1598 return (-1); 1599 } 1600 1601 /* The request line */ 1602 if (c_id->proxied && c_id->ssl == NULL) { 1603 j = snprintf(request, requestlen, 1604 "%s http://%s:%d%s HTTP/1.1\r\n", 1605 reqtypename, CONN_HOSTNAME, CONN_PORT, 1606 CONN_ABSPATH); 1607 } else { 1608 j = snprintf(request, requestlen, "%s %s HTTP/1.1\r\n", 1609 reqtypename, CONN_ABSPATH); 1610 } 1611 1612 /* Ancillary headers */ 1613 j += snprintf(&request[j], requestlen - j, "Host: %s:%d\r\n", 1614 CONN_HOSTNAME, CONN_PORT); 1615 if (!c_id->keepalive) 1616 j += snprintf(&request[j], requestlen - j, 1617 "Connection: close\r\n"); 1618 else 1619 j += snprintf(&request[j], requestlen - j, 1620 "Connection: Keep-Alive\r\n"); 1621 /* 1622 * We only send the range header on GET requests 1623 * 1624 * "Range: bytes=" + from + "-" + end + "\r\n" or 1625 * "Range: bytes=" + from + "-" "\r\n" 1626 */ 1627 if (type == HTTP_REQ_TYPE_GET && curpos >= 0) { 1628 offset_t endpos; 1629 1630 requestlen += 13 + count_digits(curpos) + 1 + 2; 1631 if (len > 0) { 1632 endpos = curpos + len - 1; 1633 requestlen += count_digits(endpos); 1634 } 1635 1636 if ((newreq = realloc(request, requestlen)) == NULL) { 1637 free(request); 1638 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 1639 return (-1); 1640 } 1641 request = newreq; 1642 1643 j += sprintf(&request[j], "Range: bytes=%lld-", curpos); 1644 if (len > 0) 1645 j += sprintf(&request[j], "%lld", endpos); 1646 j += sprintf(&request[j], "\r\n"); 1647 } 1648 1649 /* 1650 * Authorization is added only if provided (RFC 2617, Section 2) 1651 * 1652 * "Authorization: Basic " + authencstr + "\r\n" 1653 */ 1654 if (c_id->basic_auth_userid && c_id->basic_auth_password) { 1655 char *authstr; 1656 char *authencstr; 1657 int authlen; 1658 1659 /* 1660 * Allow for concat(basic_auth_userid ":" basic_auth_password) 1661 */ 1662 authlen = strlen(c_id->basic_auth_userid) + 2 + 1663 strlen(c_id->basic_auth_password); 1664 if ((authstr = malloc(authlen + 1)) == NULL) { 1665 free(request); 1666 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 1667 return (-1); 1668 } 1669 (void) snprintf(authstr, authlen + 1, "%s:%s", 1670 c_id->basic_auth_userid, c_id->basic_auth_password); 1671 1672 /* 3 bytes encoded as 4 (round up) with null termination */ 1673 if ((authencstr = malloc((authlen + 2) / 3 * 4 + 1)) == NULL) { 1674 free(authstr); 1675 free(request); 1676 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 1677 return (-1); 1678 } 1679 1680 (void) EVP_EncodeBlock((unsigned char *)authencstr, 1681 (unsigned char *)authstr, authlen); 1682 1683 /* 1684 * Finally do concat(Authorization: Basic " authencstr "\r\n") 1685 */ 1686 requestlen += 21 + strlen(authencstr) + 2; 1687 if ((newreq = realloc(request, requestlen)) == NULL) { 1688 free(authencstr); 1689 free(authstr); 1690 free(request); 1691 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 1692 return (-1); 1693 } 1694 request = newreq; 1695 1696 j += snprintf(&request[j], requestlen - j, 1697 "Authorization: Basic %s\r\n", authencstr); 1698 1699 free(authencstr); 1700 free(authstr); 1701 } 1702 1703 j += sprintf(&request[j], "\r\n"); 1704 1705 if (verbosemode) 1706 libbootlog(BOOTLOG_VERBOSE, "%s", request); 1707 1708 /* send the HTTP request */ 1709 retval = http_srv_send(c_id, request, j); 1710 1711 free(request); 1712 if (retval != j) { 1713 /* Assume error in was set by send request. */ 1714 return (-1); 1715 } 1716 1717 return (0); 1718 } 1719 1720 /* 1721 * password_cb - Callback to get private key password and return it 1722 * to SSL. (Used for PEM certificates only.) 1723 * 1724 * len = passwd_cb(buf, buflen, rwflag, userdata); 1725 * 1726 * Arguments: 1727 * buf - Buffer for the password 1728 * buflen - Length of 'buf' 1729 * rwflag - password will be used for reading/decryption (== 0) 1730 * or writing/encryption (== 1). 1731 * userdata - Points to connection-specific information. 1732 * 1733 * Returns: 1734 * > 0 - Length of password that was put into 'buf'. 1735 * 0 - No password was returned (usually error occurred) 1736 * 1737 * NOTE: The password code is not thread safe 1738 */ 1739 /* ARGSUSED */ 1740 static int 1741 password_cb(char *buf, int buflen, int rwflag, void *userdata) 1742 { 1743 http_conn_t *c_id = userdata; 1744 1745 if (c_id == NULL || c_id->signature != HTTP_CONN_INFO) 1746 return (0); 1747 1748 if (c_id->file_password == NULL || 1749 buflen < strlen(c_id->file_password) + 1) 1750 return (0); 1751 1752 return (strlcpy(buf, c_id->file_password, buflen)); 1753 } 1754 1755 /* 1756 * initialize_ctx - Initialize the context for a connection. 1757 * 1758 * ctx = initialize_ctx(c_id); 1759 * 1760 * Arguments: 1761 * None. 1762 * 1763 * Returns: 1764 * non-NULL - Points to ctx structure. 1765 * NULL - An error occurred. Any cleanup is done and error 1766 * information is in the error stack. 1767 */ 1768 static SSL_CTX * 1769 initialize_ctx(http_conn_t *c_id) 1770 { 1771 #if OPENSSL_VERSION_NUMBER < 0x10000000L 1772 SSL_METHOD *meth; 1773 #else 1774 const SSL_METHOD *meth; 1775 #endif 1776 SSL_CTX *ctx; 1777 1778 ERR_clear_error(); 1779 1780 /* Global system initialization */ 1781 if (ssl_init == 0) { 1782 sunw_crypto_init(); 1783 SSL_load_error_strings(); 1784 ssl_init = 1; 1785 } 1786 1787 /* Create our context */ 1788 meth = SSLv3_client_method(); 1789 if ((ctx = SSL_CTX_new(meth)) == NULL) { 1790 ulong_t err; 1791 while ((err = ERR_get_error()) != 0) 1792 SET_ERR(c_id, ERRSRC_LIBSSL, err); 1793 libbootlog(BOOTLOG_CRIT, 1794 "initialize_ctx: SSL_CTX_new returned NULL"); 1795 return (NULL); 1796 } 1797 1798 /* 1799 * Ensure that any renegotiations for blocking connections will 1800 * be done automatically. (The alternative is to return partial 1801 * reads to the caller and let it oversee the renegotiations.) 1802 */ 1803 if (SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY) == 0) { 1804 ulong_t err; 1805 while ((err = ERR_get_error()) != 0) 1806 SET_ERR(c_id, ERRSRC_LIBSSL, err); 1807 libbootlog(BOOTLOG_CRIT, 1808 "initialize_ctx: SSL_CTX_set_mode returned 0"); 1809 (void) SSL_CTX_free(ctx); 1810 return (NULL); 1811 } 1812 1813 /* set cipher list if provided */ 1814 if (cipher_list != NULL) { 1815 if (!SSL_CTX_set_cipher_list(ctx, cipher_list)) { 1816 ulong_t err; 1817 while ((err = ERR_get_error()) != 0) 1818 SET_ERR(c_id, ERRSRC_LIBSSL, err); 1819 libbootlog(BOOTLOG_CRIT, 1820 "initialize_ctx: Error in cipher list"); 1821 SSL_CTX_free(ctx); 1822 return (NULL); 1823 } 1824 } 1825 1826 /* 1827 * We attempt to use the client_certificate_file for the private 1828 * key input scheme *only* in the absence of private_key_file. In 1829 * this instance the scheme will be the same as that used for the 1830 * certificate input. 1831 */ 1832 1833 /* Load our certificates */ 1834 if (c_id->client_cert_file != NULL) { 1835 if (p12_format) { 1836 /* Load pkcs12-formated files */ 1837 if (sunw_p12_use_certfile(ctx, c_id->client_cert_file, 1838 c_id->file_password) 1839 <= 0) { 1840 ulong_t err; 1841 while ((err = ERR_get_error()) != 0) 1842 SET_ERR(c_id, ERRSRC_LIBSSL, err); 1843 libbootlog(BOOTLOG_CRIT, 1844 "initialize_ctx: Couldn't read " 1845 "PKCS12 certificate file"); 1846 SSL_CTX_free(ctx); 1847 return (NULL); 1848 } 1849 } else { 1850 /* Load PEM-formated files */ 1851 if (SSL_CTX_use_certificate_file(ctx, 1852 c_id->client_cert_file, SSL_FILETYPE_PEM) <= 0) { 1853 ulong_t err; 1854 while ((err = ERR_get_error()) != 0) 1855 SET_ERR(c_id, ERRSRC_LIBSSL, err); 1856 libbootlog(BOOTLOG_CRIT, 1857 "initialize_ctx: Couldn't read " 1858 "PEM certificate file"); 1859 SSL_CTX_free(ctx); 1860 return (NULL); 1861 } 1862 } 1863 if (c_id->private_key_file == NULL) 1864 c_id->private_key_file = c_id->client_cert_file; 1865 } 1866 1867 /* Load our keys */ 1868 if (p12_format) { 1869 /* Load pkcs12-formated files */ 1870 if (c_id->private_key_file != NULL) { 1871 if (sunw_p12_use_keyfile(ctx, c_id->private_key_file, 1872 c_id->file_password) 1873 <= 0) { 1874 ulong_t err; 1875 while ((err = ERR_get_error()) != 0) 1876 SET_ERR(c_id, ERRSRC_LIBSSL, err); 1877 libbootlog(BOOTLOG_CRIT, 1878 "initialize_ctx: Couldn't read " 1879 "PKCS12 key file"); 1880 SSL_CTX_free(ctx); 1881 return (NULL); 1882 } 1883 } 1884 } else { 1885 /* Load PEM-formated files */ 1886 SSL_CTX_set_default_passwd_cb(ctx, password_cb); 1887 SSL_CTX_set_default_passwd_cb_userdata(ctx, c_id); 1888 if (c_id->private_key_file != NULL) { 1889 if (SSL_CTX_use_PrivateKey_file(ctx, 1890 c_id->private_key_file, SSL_FILETYPE_PEM) <= 0) { 1891 ulong_t err; 1892 while ((err = ERR_get_error()) != 0) 1893 SET_ERR(c_id, ERRSRC_LIBSSL, err); 1894 libbootlog(BOOTLOG_CRIT, 1895 "initialize_ctx: Couldn't read " 1896 "PEM key file"); 1897 SSL_CTX_free(ctx); 1898 return (NULL); 1899 } 1900 } 1901 } 1902 1903 /* Load the CAs we trust */ 1904 if (ca_verify_file != NULL) { 1905 if (p12_format) { 1906 if (sunw_p12_use_trustfile(ctx, ca_verify_file, 1907 c_id->file_password) 1908 <= 0) { 1909 ulong_t err; 1910 while ((err = ERR_get_error()) != 0) 1911 SET_ERR(c_id, ERRSRC_LIBSSL, err); 1912 libbootlog(BOOTLOG_CRIT, 1913 "initialize_ctx: Couldn't read " 1914 "PKCS12 CA list file"); 1915 SSL_CTX_free(ctx); 1916 return (NULL); 1917 } 1918 } else { 1919 if (SSL_CTX_load_verify_locations(ctx, ca_verify_file, 1920 NULL) == 0) { 1921 ulong_t err; 1922 while ((err = ERR_get_error()) != 0) 1923 SET_ERR(c_id, ERRSRC_LIBSSL, err); 1924 libbootlog(BOOTLOG_CRIT, 1925 "initialize_ctx: Couldn't read PEM" 1926 " CA list file"); 1927 SSL_CTX_free(ctx); 1928 return (NULL); 1929 } 1930 } 1931 } 1932 1933 SSL_CTX_set_verify_depth(ctx, verify_depth); 1934 1935 /* Load randomness */ 1936 if (c_id->random_file != NULL && 1937 RAND_load_file(c_id->random_file, 1024 * 1024) <= 0) { 1938 ulong_t err; 1939 while ((err = ERR_get_error()) != 0) 1940 SET_ERR(c_id, ERRSRC_LIBSSL, err); 1941 libbootlog(BOOTLOG_CRIT, 1942 "initialize_ctx: Couldn't load random file"); 1943 SSL_CTX_free(ctx); 1944 return (NULL); 1945 } 1946 if (RAND_status() <= 0) { 1947 ulong_t err; 1948 while ((err = ERR_get_error()) != 0) 1949 SET_ERR(c_id, ERRSRC_LIBSSL, err); 1950 libbootlog(BOOTLOG_CRIT, 1951 "initialize_ctx: PRNG not seeded"); 1952 SSL_CTX_free(ctx); 1953 return (NULL); 1954 } 1955 1956 return (ctx); 1957 } 1958 1959 /* 1960 * tcp_connect - Set up a TCP connection. 1961 * 1962 * sock = tcp_connect(c_id, hostname, port); 1963 * 1964 * Arguments: 1965 * c_id - Structure associated with the desired connection 1966 * hostname - the host to connect to 1967 * port - the port to connect to 1968 * 1969 * Returns: 1970 * >= 0 - Socket number. 1971 * -1 - Error occurred. Error information is set in the 1972 * error stack. Any cleanup is done. 1973 * 1974 * This function established a connection to the target host. When 1975 * it returns, the connection is ready for a HEAD or GET request. 1976 */ 1977 static int 1978 tcp_connect(http_conn_t *c_id, const char *hostname, uint16_t port) 1979 { 1980 struct hostent *hp; 1981 struct sockaddr_in addr; 1982 int sock; 1983 int status; 1984 1985 if ((hp = gethostbyname(hostname)) == NULL) { 1986 SET_ERR(c_id, ERRSRC_RESOLVE, h_errno); 1987 return (-1); 1988 } 1989 1990 bzero(&addr, sizeof (addr)); 1991 /* LINTED */ 1992 addr.sin_addr = *(struct in_addr *)hp->h_addr; 1993 addr.sin_family = AF_INET; 1994 addr.sin_port = htons(port); 1995 1996 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 1997 SET_ERR(c_id, ERRSRC_SYSTEM, errno); 1998 return (-1); 1999 } 2000 2001 status = connect(sock, (struct sockaddr *)&addr, sizeof (addr)); 2002 if (status < 0) { 2003 SET_ERR(c_id, ERRSRC_SYSTEM, errno); 2004 (void) socket_close(sock); 2005 return (-1); 2006 } 2007 2008 c_id->host_addr = addr; /* save for future sendto calls */ 2009 c_id->fd = sock; 2010 2011 return (sock); 2012 } 2013 2014 /* 2015 * readline - Get a line from the socket. Discard the end-of-line 2016 * (CR or CR/LF or LF). 2017 * 2018 * ret = readline(c_id, sock, buf, len); 2019 * 2020 * Arguments: 2021 * c_id - Structure associated with the desired connection 2022 * sock - Socket to read 2023 * buf - Buffer for the line 2024 * len - Length of the buffer 2025 * 2026 * Returns: 2027 * 0 - Success. 'buf' contains the line. 2028 * -1 - Error occurred. Error information is set in the 2029 * error stack. 2030 */ 2031 static int 2032 readline(http_conn_t *c_id, int sock, char *buf, int len) 2033 { 2034 int n, r; 2035 char *ptr = buf; 2036 2037 for (n = 0; n < len; n++) { 2038 r = socket_read(sock, ptr, 1, c_id->read_timeout); 2039 2040 if (r < 0) { 2041 SET_ERR(c_id, ERRSRC_SYSTEM, errno); 2042 return (-1); 2043 } else if (r == 0) { 2044 libbootlog(BOOTLOG_WARNING, "Readline: no data"); 2045 return (0); 2046 } 2047 2048 if (*ptr == '\n') { 2049 *ptr = '\0'; 2050 2051 /* Strip off the CR if it's there */ 2052 if (buf[n-1] == '\r') { 2053 buf[n-1] = '\0'; 2054 n--; 2055 } 2056 2057 return (n); 2058 } 2059 2060 ptr++; 2061 } 2062 2063 libbootlog(BOOTLOG_WARNING, "readline: Buffer too short\n"); 2064 return (0); 2065 } 2066 2067 /* 2068 * proxy_connect - Set up a proxied TCP connection to the target host. 2069 * 2070 * sock = proxy_connect(c_id); 2071 * 2072 * Arguments: 2073 * c_id - Structure associated with the desired connection 2074 * 2075 * Returns: 2076 * >= 0 - Socket number. 2077 * -1 - Error occurred. Error information is set in the 2078 * error stack. Any cleanup is done. 2079 * 2080 * This function established a connection to the proxy and then sends 2081 * the request to connect to the target host. It reads the response 2082 * (the status line and any headers). When it returns, the connection 2083 * is ready for a HEAD or GET request. 2084 */ 2085 static int 2086 proxy_connect(http_conn_t *c_id) 2087 { 2088 struct sockaddr_in addr; 2089 int sock; 2090 char buf[1024]; 2091 char *ptr; 2092 int i; 2093 2094 if ((sock = tcp_connect(c_id, CONN_PROXY_HOSTNAME, 2095 CONN_PROXY_PORT)) < 0) { 2096 return (-1); 2097 } 2098 2099 if (!CONN_HTTPS) { 2100 return (sock); 2101 } 2102 2103 /* Now that we're connected, do the proxy request */ 2104 (void) snprintf(buf, sizeof (buf), 2105 "CONNECT %s:%d HTTP/1.0\r\n\r\n", CONN_HOSTNAME, CONN_PORT); 2106 2107 /* socket_write sets the errors */ 2108 if (socket_write(sock, buf, strlen(buf), &addr) <= 0) { 2109 SET_ERR(c_id, ERRSRC_SYSTEM, errno); 2110 (void) socket_close(sock); 2111 return (-1); 2112 } 2113 2114 /* And read the response */ 2115 i = readline(c_id, sock, buf, sizeof (buf)); 2116 if (i <= 0) { 2117 if (i == 0) 2118 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NORESP); 2119 libbootlog(BOOTLOG_CRIT, 2120 "proxy_connect: Empty response from proxy"); 2121 (void) socket_close(sock); 2122 return (-1); 2123 } 2124 2125 ptr = buf; 2126 if (strncmp(ptr, "HTTP", 4) != 0) { 2127 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOT_1_1); 2128 libbootlog(BOOTLOG_CRIT, 2129 "proxy_connect: Unrecognized protocol"); 2130 (void) socket_close(sock); 2131 return (-1); 2132 } 2133 2134 /* skip to the code */ 2135 ptr += 4; 2136 while (*ptr != ' ' && *ptr != '\0') 2137 ptr++; 2138 while (*ptr == ' ' && *ptr != '\0') 2139 ptr++; 2140 2141 /* make sure it's three digits */ 2142 if (strncmp(ptr, "200", 3) != 0) { 2143 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADRESP); 2144 libbootlog(BOOTLOG_CRIT, 2145 "proxy_connect: Received error from proxy server"); 2146 (void) socket_close(sock); 2147 return (-1); 2148 } 2149 ptr += 3; 2150 if (isdigit(*ptr)) { 2151 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADRESP); 2152 (void) socket_close(sock); 2153 return (-1); 2154 } 2155 2156 /* Look for the blank line that signals end of proxy header */ 2157 while ((i = readline(c_id, sock, buf, sizeof (buf))) > 0) 2158 ; 2159 2160 if (i < 0) { 2161 (void) socket_close(sock); 2162 return (-1); 2163 } 2164 2165 return (sock); 2166 } 2167 2168 /* 2169 * check_cert_chain - Check if we have a valid certificate chain. 2170 * 2171 * ret = check_cert_chain(c_id, host); 2172 * 2173 * Arguments: 2174 * c_id - Connection info. 2175 * host - Name to compare with the common name in the certificate. 2176 * 2177 * Returns: 2178 * 0 - Certificate chain and common name are both OK. 2179 * -1 - Certificate chain and/or common name is not valid. 2180 */ 2181 static int 2182 check_cert_chain(http_conn_t *c_id, char *host) 2183 { 2184 X509 *peer; 2185 char peer_CN[256]; 2186 long verify_err; 2187 2188 if ((verify_err = SSL_get_verify_result(c_id->ssl)) != X509_V_OK) { 2189 SET_ERR(c_id, ERRSRC_VERIFERR, verify_err); 2190 libbootlog(BOOTLOG_CRIT, 2191 "check_cert_chain: Certificate doesn't verify"); 2192 return (-1); 2193 } 2194 2195 /* 2196 * Check the cert chain. The chain length 2197 * is automatically checked by OpenSSL when we 2198 * set the verify depth in the ctx 2199 * 2200 * All we need to do here is check that the CN 2201 * matches 2202 */ 2203 2204 /* Check the common name */ 2205 if ((peer = SSL_get_peer_certificate(c_id->ssl)) == NULL) { 2206 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOCERT); 2207 libbootlog(BOOTLOG_CRIT, 2208 "check_cert_chain: Peer did not present a certificate"); 2209 return (-1); 2210 } 2211 (void) X509_NAME_get_text_by_NID(X509_get_subject_name(peer), 2212 NID_commonName, peer_CN, 256); 2213 2214 if (verbosemode) 2215 libbootlog(BOOTLOG_VERBOSE, 2216 "server cert's peer_CN is %s, host is %s", peer_CN, host); 2217 2218 if (strcasecmp(peer_CN, host)) { 2219 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMATCH); 2220 libbootlog(BOOTLOG_CRIT, 2221 "check_cert_chain: Common name doesn't match host name"); 2222 libbootlog(BOOTLOG_CRIT, 2223 "peer_CN = %s, host = %s", peer_CN, host); 2224 return (-1); 2225 } 2226 2227 return (0); 2228 } 2229 2230 /* 2231 * print_ciphers - Print the list of ciphers for debugging. 2232 * 2233 * print_ciphers(ssl); 2234 * 2235 * Arguments: 2236 * ssl - SSL connection. 2237 * 2238 * Returns: 2239 * none 2240 */ 2241 static void 2242 print_ciphers(SSL *ssl) 2243 { 2244 SSL_CIPHER *c; 2245 STACK_OF(SSL_CIPHER) *sk; 2246 int i; 2247 const char *name; 2248 2249 if (ssl == NULL) 2250 return; 2251 2252 sk = SSL_get_ciphers(ssl); 2253 if (sk == NULL) 2254 return; 2255 2256 for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { 2257 c = sk_SSL_CIPHER_value(sk, i); 2258 libbootlog(BOOTLOG_VERBOSE, "%08lx %s", c->id, c->name); 2259 } 2260 name = SSL_get_cipher_name(ssl); 2261 if (name == NULL) 2262 name = ""; 2263 libbootlog(BOOTLOG_VERBOSE, "Current cipher = %s", name); 2264 } 2265 2266 /* 2267 * read_headerlines - Get the header lines from the server. This reads 2268 * lines until it gets a empty line indicating end of headers. 2269 * 2270 * ret = read_headerlines(c_id); 2271 * 2272 * Arguments: 2273 * c_id - Info about the connection being read. 2274 * bread - TRUE if the headerlines are part of the message body. 2275 * 2276 * Returns: 2277 * 0 - Header lines were read. 2278 * -1 - Error occurred. The errors information is already in 2279 * the error stack. 2280 * 2281 * Read the lines. If the current line begins with a space or tab, it is 2282 * a continuation. Take the new line and append it to the end of the 2283 * previous line rather than making an entry for another line in 2284 * c_id->resphdr. 2285 * 2286 * Note that I/O errors are put into the error stack by http_srv_recv(), 2287 * which is called by getaline(). 2288 */ 2289 static int 2290 read_headerlines(http_conn_t *c_id, boolean_t bread) 2291 { 2292 char line[MAXHOSTNAMELEN]; 2293 char **new_buf; 2294 char *ptr; 2295 int next; 2296 int cur; 2297 int n; 2298 2299 /* process headers, stop when we get to an empty line */ 2300 cur = 0; 2301 next = 0; 2302 while ((n = getaline(c_id, line, sizeof (line), bread)) > 0) { 2303 2304 if (verbosemode) 2305 libbootlog(BOOTLOG_VERBOSE, 2306 "read_headerlines: %s", line); 2307 /* 2308 * See if this is a continuation line (first col is a 2309 * space or a tab) 2310 */ 2311 if (line[0] != ' ' && line[0] != ' ') { 2312 cur = next; 2313 next ++; 2314 new_buf = 2315 realloc(c_id->resphdr, (cur + 1) * sizeof (void *)); 2316 if (new_buf == NULL) { 2317 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 2318 return (-1); 2319 } 2320 c_id->resphdr = new_buf; 2321 2322 c_id->resphdr[cur] = strdup(line); 2323 if (c_id->resphdr[cur] == NULL) { 2324 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 2325 return (-1); 2326 } 2327 } else { 2328 ptr = line; 2329 while (isspace(*ptr)) 2330 ptr ++; 2331 c_id->resphdr[cur] = realloc(c_id->resphdr[cur], 2332 strlen(c_id->resphdr[cur]) + strlen(ptr) + 1); 2333 if (c_id->resphdr[cur] == NULL) { 2334 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 2335 return (-1); 2336 } 2337 (void) strcat(c_id->resphdr[cur], ptr); 2338 } 2339 ptr = &(c_id->resphdr[cur][strlen(c_id->resphdr[cur]) - 1]); 2340 while (ptr > c_id->resphdr[cur] && isspace(*ptr)) 2341 ptr --; 2342 } 2343 c_id->resp.nresphdrs = next; 2344 2345 /* Cause of any I/O error was already put into error stack. */ 2346 return (n >= 0 ? 0 : -1); 2347 } 2348 2349 static void 2350 free_response(http_conn_t *c_id, int free_boundary) 2351 { 2352 int i; 2353 2354 /* free memory from previous calls */ 2355 if (c_id->resp.statusmsg != NULL) { 2356 free(c_id->resp.statusmsg); 2357 c_id->resp.statusmsg = NULL; 2358 } 2359 for (i = 0; i < c_id->resp.nresphdrs; i++) { 2360 free(c_id->resphdr[i]); 2361 c_id->resphdr[i] = NULL; 2362 } 2363 c_id->resp.nresphdrs = 0; 2364 if (c_id->resphdr != NULL) { 2365 free(c_id->resphdr); 2366 c_id->resphdr = NULL; 2367 } 2368 2369 if (free_boundary && c_id->boundary) { 2370 free(c_id->boundary); 2371 c_id->boundary = NULL; 2372 c_id->is_multipart = B_FALSE; 2373 } 2374 } 2375 2376 static int 2377 free_ctx_ssl(http_conn_t *c_id) 2378 { 2379 int err_ret = 0; 2380 2381 if (c_id->ssl != NULL) { 2382 if (SSL_shutdown(c_id->ssl) <= 0) { 2383 ulong_t err; 2384 while ((err = ERR_get_error()) != 0) 2385 SET_ERR(c_id, ERRSRC_LIBSSL, err); 2386 err_ret = -1; 2387 } 2388 SSL_free(c_id->ssl); 2389 c_id->ssl = NULL; 2390 } 2391 2392 if (c_id->fd != -1 && socket_close(c_id->fd) < 0) { 2393 SET_ERR(c_id, ERRSRC_SYSTEM, errno); 2394 err_ret = -1; 2395 } 2396 c_id->fd = -1; 2397 2398 if (c_id->ctx != NULL) { 2399 SSL_CTX_free(c_id->ctx); 2400 c_id->ctx = NULL; 2401 } 2402 2403 return (err_ret); 2404 } 2405 2406 /* 2407 * get_chunk_header - Get a chunk header line 2408 * 2409 * Arguments: 2410 * c_id - Structure describing the connection in question. 2411 * 2412 * Returns: 2413 * >=0 - Length of next chunk 2414 * -1 - Error occurred. The error information is in the error stack. 2415 */ 2416 static int 2417 get_chunk_header(http_conn_t *c_id) 2418 { 2419 char line[MAXHOSTNAMELEN]; 2420 char *ptr; 2421 int value; 2422 int ok; 2423 int i; 2424 2425 /* 2426 * Determine whether an extra crlf pair will precede the 2427 * chunk header. For the first one, there is no preceding 2428 * crlf. For later chunks, there is one crlf. 2429 */ 2430 if (c_id->is_firstchunk) { 2431 ok = 1; 2432 c_id->is_firstchunk = B_FALSE; 2433 } else { 2434 ok = ((i = getaline(c_id, line, sizeof (line), B_FALSE)) == 0); 2435 } 2436 2437 if (ok) 2438 i = getaline(c_id, line, sizeof (line), B_FALSE); 2439 if (!ok || i < 0) { 2440 /* 2441 * If I/O error, the Cause was already put into 2442 * error stack. This is an additional error. 2443 */ 2444 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOHEADER); 2445 return (-1); 2446 } 2447 2448 if (verbosemode) 2449 libbootlog(BOOTLOG_VERBOSE, "get_chunk_header: <%s>", line); 2450 2451 2452 /* 2453 * The first (and probably only) field in the line is the hex 2454 * length of the chunk. 2455 */ 2456 ptr = line; 2457 value = 0; 2458 while (*ptr != '\0' && (i = hexdigit(*ptr)) >= 0) { 2459 value = (value << 4) + i; 2460 ptr ++; 2461 } 2462 2463 return (value); 2464 } 2465 2466 /* 2467 * init_bread - Initialize the counters used to read message bodies. 2468 * 2469 * Arguments: 2470 * c_id - Structure describing the connection in question. 2471 * 2472 * Returns: 2473 * 0 - Success 2474 * -1 - Error occurred. The error information is in the error stack. 2475 * 2476 * This routine will determine whether the message body being received is 2477 * chunked or non-chunked. Once determined, the counters used to read 2478 * message bodies will be initialized. 2479 */ 2480 static int 2481 init_bread(http_conn_t *c_id) 2482 { 2483 char *hdr; 2484 char *ptr; 2485 boolean_t sized = B_FALSE; 2486 2487 /* 2488 * Assume non-chunked reads until proven otherwise. 2489 */ 2490 c_id->is_chunked = B_FALSE; 2491 c_id->is_firstchunk = B_FALSE; 2492 hdr = http_get_header_value(c_id, "Content-Length"); 2493 if (hdr != NULL) { 2494 c_id->body_size = strtol(hdr, NULL, 10); 2495 if (c_id->body_size == 0 && errno != 0) { 2496 free(hdr); 2497 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADSIZE); 2498 return (-1); 2499 } 2500 free(hdr); 2501 sized = B_TRUE; 2502 } 2503 2504 /* 2505 * If size was not determined above, then see if this is a 2506 * chunked message. Keep in mind that the first chunk size is 2507 * "special". 2508 */ 2509 if (!sized) { 2510 hdr = http_get_header_value(c_id, "Transfer-Encoding"); 2511 if (hdr != NULL) { 2512 ptr = eat_ws(hdr); 2513 if (startswith((const char **)&ptr, "chunked;") || 2514 strcasecmp(ptr, "chunked") == 0) { 2515 c_id->is_firstchunk = B_TRUE; 2516 c_id->is_chunked = B_TRUE; 2517 } 2518 free(hdr); 2519 if (c_id->is_chunked) { 2520 c_id->body_size = get_chunk_header(c_id); 2521 if (c_id->body_size == -1) { 2522 /* 2523 * Error stack was already set at a 2524 * lower level. 2525 */ 2526 return (-1); 2527 } 2528 sized = B_TRUE; 2529 } 2530 } 2531 } 2532 2533 /* 2534 * Well, isn't this a fine predicament? It wasn't chunked or 2535 * non-chunked as far as we can tell. 2536 */ 2537 if (!sized) { 2538 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADSIZE); 2539 return (-1); 2540 } 2541 2542 c_id->body_read = 0; 2543 c_id->body_size_tot = c_id->body_size; 2544 c_id->body_read_tot = 0; 2545 2546 return (0); 2547 } 2548 2549 /* 2550 * get_msgcnt - Get the number of bytes left in the message body or chunk. 2551 * 2552 * Arguments: 2553 * c_id - Structure describing the connection in question. 2554 * msgcnt - Where to store the message count. 2555 * 2556 * Returns: 2557 * 0 - Success 2558 * -1 - Error occurred. The error information is in the error stack. 2559 * 2560 * Note that if the message being read is not chunked, then the byte count 2561 * is simply the message size minus the bytes read thus far. In the case of 2562 * chunked messages, the byte count returned will be the number of bytes 2563 * left in the chunk. If the current chunk has been exhausted, then this 2564 * routine will determine the size of the next chunk. When the next chunk 2565 * size is zero, the message has been read in its entirety. 2566 */ 2567 static int 2568 get_msgcnt(http_conn_t *c_id, ssize_t *msgcnt) 2569 { 2570 /* 2571 * If there are more bytes in the message, then return. 2572 */ 2573 *msgcnt = c_id->body_size - c_id->body_read; 2574 if (*msgcnt != 0) { 2575 return (0); 2576 } 2577 /* 2578 * If this is not a chunked message and the body has been 2579 * read, then we're done. 2580 */ 2581 if (!c_id->is_chunked) { 2582 return (0); 2583 } 2584 2585 /* 2586 * We're looking at a chunked message whose immediate 2587 * chunk has been totally processed. See if there is 2588 * another chunk. 2589 */ 2590 c_id->body_size = get_chunk_header(c_id); 2591 if (c_id->body_size == -1) { 2592 /* 2593 * Error stack was already set at a 2594 * lower level. 2595 */ 2596 return (-1); 2597 } 2598 2599 /* 2600 * No bytes of this chunk have been processed yet. 2601 */ 2602 c_id->body_read = 0; 2603 2604 /* 2605 * A zero length chunk signals the end of the 2606 * message body and chunking. 2607 */ 2608 if (c_id->body_size == 0) { 2609 c_id->is_chunked = B_FALSE; 2610 return (0); 2611 } 2612 2613 /* 2614 * There is another chunk. 2615 */ 2616 c_id->body_size_tot += c_id->body_size; 2617 *msgcnt = c_id->body_size - c_id->body_read; 2618 2619 return (0); 2620 } 2621 2622 /* 2623 * getaline - Get lines of data from the HTTP response, up to 'len' bytes. 2624 * NOTE: the line will not end with a NULL if all 'len' bytes 2625 * were read. 2626 * 2627 * Arguments: 2628 * c_id - Structure describing the connection in question. 2629 * line - Where to store the data. 2630 * len - Maximum number of bytes in the line. 2631 * bread - TRUE if the lines are part of the message body. 2632 * 2633 * Returns: 2634 * >=0 - The number of bytes successfully read. 2635 * <0 - An error occurred. This is (the number of bytes gotten + 1), 2636 * negated. In other words, if 'n' bytes were read and then an 2637 * error occurred, this will return (-(n+1)). So zero bytes read 2638 * and then an error occurs, this will return -1. If 1 bytes 2639 * was read, it will return -2, etc. 2640 * 2641 * Specifics of the error can be gotten using http_get_lasterr(); 2642 * 2643 * Note that I/O errors are put into the error stack by http_srv_recv().1 2644 */ 2645 static int 2646 getaline(http_conn_t *c_id, char *line, int len, boolean_t bread) 2647 { 2648 int i = 0; 2649 ssize_t msgcnt = 0; 2650 ssize_t cnt; 2651 2652 while (i < len) { 2653 /* 2654 * Special processing required for message body reads. 2655 */ 2656 if (bread) { 2657 /* 2658 * See if there is another chunk. Obviously, in the 2659 * case of non-chunked messages, there won't be. 2660 * But in either case, chunked or not, if msgcnt 2661 * is still zero after the call to get_msgcnt(), 2662 * then we're done. 2663 */ 2664 if (msgcnt == 0) { 2665 if (get_msgcnt(c_id, &msgcnt) == -1) { 2666 return (-(i+1)); 2667 } 2668 if (msgcnt == 0) { 2669 break; 2670 } 2671 } 2672 cnt = MIN(msgcnt, sizeof (c_id->inbuf.buf)); 2673 } else { 2674 cnt = sizeof (c_id->inbuf.buf); 2675 } 2676 2677 /* read more data if buffer empty */ 2678 if (c_id->inbuf.i == c_id->inbuf.n) { 2679 c_id->inbuf.i = 0; 2680 c_id->inbuf.n = http_srv_recv(c_id, c_id->inbuf.buf, 2681 cnt); 2682 if (c_id->inbuf.n == 0) { 2683 return (i); 2684 } 2685 if (c_id->inbuf.n < 0) { 2686 return (-(i+1)); 2687 } 2688 } 2689 /* skip CR */ 2690 if (c_id->inbuf.buf[c_id->inbuf.i] == '\r') { 2691 INC_BREAD_CNT(bread, msgcnt); 2692 c_id->inbuf.i++; 2693 continue; 2694 } 2695 if (c_id->inbuf.buf[c_id->inbuf.i] == '\n') { 2696 INC_BREAD_CNT(bread, msgcnt); 2697 c_id->inbuf.i++; 2698 line[i] = '\0'; 2699 return (i); 2700 } 2701 /* copy buf from internal buffer */ 2702 INC_BREAD_CNT(bread, msgcnt); 2703 line[i++] = c_id->inbuf.buf[c_id->inbuf.i++]; 2704 } 2705 return (i); 2706 } 2707 2708 /* 2709 * getbytes - Get a block from the HTTP response. Used for the HTTP body. 2710 * 2711 * Arguments: 2712 * c_id - Structure describing the connection in question. 2713 * line - Where to store the data. 2714 * len - Maximum number of bytes in the block. 2715 * 2716 * Returns: 2717 * >=0 - The number of bytes successfully read. 2718 * <0 - An error occurred. This is (the number of bytes gotten + 1), 2719 * negated. In other words, if 'n' bytes were read and then an 2720 * error occurred, this will return (-(n+1)). So zero bytes read 2721 * and then an error occurs, this will return -1. If 1 bytes 2722 * was read, it will return -2, etc. 2723 * 2724 * Specifics of the error can be gotten using http_get_lasterr(); 2725 * 2726 * Note that all reads performed here assume that a message body is being 2727 * read. If this changes in the future, then the logic should more closely 2728 * resemble getaline(). 2729 * 2730 * Note that I/O errors are put into the error stack by http_srv_recv(). 2731 */ 2732 static int 2733 getbytes(http_conn_t *c_id, char *line, int len) 2734 { 2735 int i = 0; 2736 ssize_t msgcnt = 0; 2737 ssize_t cnt; 2738 int nbytes; 2739 2740 while (i < len) { 2741 /* 2742 * See if there is another chunk. Obviously, in the 2743 * case of non-chunked messages, there won't be. 2744 * But in either case, chunked or not, if msgcnt 2745 * is still zero after the call to get_msgcnt(), then 2746 * we're done. 2747 */ 2748 if (msgcnt == 0) { 2749 if (get_msgcnt(c_id, &msgcnt) == -1) { 2750 return (-(i+1)); 2751 } 2752 if (msgcnt == 0) { 2753 break; 2754 } 2755 } 2756 2757 cnt = MIN(msgcnt, len - i); 2758 2759 if (c_id->inbuf.n != c_id->inbuf.i) { 2760 nbytes = (int)MIN(cnt, c_id->inbuf.n - c_id->inbuf.i); 2761 (void) memcpy(line, &c_id->inbuf.buf[c_id->inbuf.i], 2762 nbytes); 2763 c_id->inbuf.i += nbytes; 2764 } else { 2765 nbytes = http_srv_recv(c_id, line, cnt); 2766 if (nbytes == 0) { 2767 return (i); 2768 } 2769 if (nbytes < 0) { 2770 return (-(i+1)); 2771 } 2772 } 2773 2774 i += nbytes; 2775 line += nbytes; 2776 msgcnt -= nbytes; 2777 c_id->body_read += nbytes; 2778 c_id->body_read_tot += nbytes; 2779 } 2780 2781 return (i); 2782 } 2783 2784 static int 2785 http_srv_send(http_conn_t *c_id, const void *buf, size_t nbyte) 2786 { 2787 int retval; 2788 2789 if (c_id->ssl != NULL) { 2790 if ((retval = SSL_write(c_id->ssl, buf, nbyte)) <= 0) { 2791 handle_ssl_error(c_id, retval); 2792 } 2793 return (retval); 2794 } else { 2795 retval = socket_write(c_id->fd, buf, nbyte, &c_id->host_addr); 2796 if (retval < 0) { 2797 SET_ERR(c_id, ERRSRC_SYSTEM, errno); 2798 return (-1); 2799 } 2800 return (retval); 2801 } 2802 } 2803 2804 static int 2805 http_srv_recv(http_conn_t *c_id, void *buf, size_t nbyte) 2806 { 2807 int retval; 2808 2809 if (c_id->ssl != NULL) { 2810 if ((retval = SSL_read(c_id->ssl, buf, nbyte)) <= 0) { 2811 handle_ssl_error(c_id, retval); 2812 } 2813 return (retval); 2814 } else { 2815 retval = socket_read(c_id->fd, buf, nbyte, c_id->read_timeout); 2816 if (retval < 0) { 2817 SET_ERR(c_id, ERRSRC_SYSTEM, errno); 2818 return (-1); 2819 } 2820 return (retval); 2821 } 2822 } 2823 2824 static boolean_t 2825 http_check_conn(http_conn_t *c_id) 2826 { 2827 early_err = 0; 2828 if (c_id == NULL || c_id->signature != HTTP_CONN_INFO) { 2829 early_err = EHTTP_BADARG; 2830 return (B_FALSE); 2831 } 2832 RESET_ERR(c_id); 2833 return (B_TRUE); 2834 } 2835 2836 static void 2837 handle_ssl_error(http_conn_t *c_id, int retval) 2838 { 2839 ulong_t err; 2840 2841 err = SSL_get_error(c_id->ssl, retval); 2842 2843 switch (err) { 2844 case SSL_ERROR_NONE: 2845 return; 2846 2847 case SSL_ERROR_ZERO_RETURN: 2848 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_CONCLOSED); 2849 return; 2850 2851 case SSL_ERROR_WANT_READ: 2852 case SSL_ERROR_WANT_WRITE: 2853 case SSL_ERROR_WANT_CONNECT: 2854 case SSL_ERROR_WANT_X509_LOOKUP: 2855 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_UNEXPECTED); 2856 return; 2857 2858 case SSL_ERROR_SYSCALL: 2859 err = ERR_get_error(); 2860 if (err == 0) 2861 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_EOFERR); 2862 else if (err == (ulong_t)-1) 2863 SET_ERR(c_id, ERRSRC_SYSTEM, errno); 2864 else { 2865 SET_ERR(c_id, ERRSRC_LIBSSL, err); 2866 while ((err = ERR_get_error()) != 0) 2867 SET_ERR(c_id, ERRSRC_LIBSSL, err); 2868 } 2869 return; 2870 2871 case SSL_ERROR_SSL: 2872 while ((err = ERR_get_error()) != 0) { 2873 SET_ERR(c_id, ERRSRC_LIBSSL, err); 2874 } 2875 return; 2876 } 2877 } 2878 2879 static int 2880 count_digits(int value) 2881 { 2882 int count = 1; 2883 2884 if (value < 0) { 2885 count++; 2886 value = -value; 2887 } 2888 2889 while (value > 9) { 2890 value /= 10; 2891 count++; 2892 } 2893 return (count); 2894 } 2895 2896 static int 2897 hexdigit(char ch) 2898 { 2899 if (ch >= '0' && ch <= '9') 2900 return (ch - '0'); 2901 if (ch >= 'A' && ch <= 'F') 2902 return (ch - 'A' + 10); 2903 if (ch >= 'a' && ch <= 'f') 2904 return (ch - 'a' + 10); 2905 return (-1); 2906 } 2907 2908 static char * 2909 eat_ws(const char *buf) 2910 { 2911 char *ptr = (char *)buf; 2912 2913 while (isspace(*ptr)) 2914 ptr++; 2915 2916 return (ptr); 2917 } 2918 2919 static boolean_t 2920 startswith(const char **strp, const char *starts) 2921 { 2922 int len = strlen(starts); 2923 2924 if (strncasecmp(*strp, starts, len) == 0) { 2925 *strp += len; 2926 return (B_TRUE); 2927 } 2928 return (B_FALSE); 2929 }