17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 523a1cceaSRoger A. Faulkner * Common Development and Distribution License (the "License"). 623a1cceaSRoger A. Faulkner * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate 2223a1cceaSRoger A. Faulkner /* 2323a1cceaSRoger A. Faulkner * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 2470f9559bSTheo Schlossnagle * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved. 2523a1cceaSRoger A. Faulkner */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <errno.h> 287c478bd9Sstevel@tonic-gate #include <sys/types.h> 297c478bd9Sstevel@tonic-gate #include <sys/socket.h> 307c478bd9Sstevel@tonic-gate #include <netinet/in.h> 317c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 327c478bd9Sstevel@tonic-gate #include <ctype.h> 337c478bd9Sstevel@tonic-gate #include <stdio.h> 347c478bd9Sstevel@tonic-gate #include <strings.h> 357c478bd9Sstevel@tonic-gate #include <stdlib.h> 367c478bd9Sstevel@tonic-gate #include <netdb.h> 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <openssl/ssl.h> 397c478bd9Sstevel@tonic-gate #include <openssl/err.h> 407c478bd9Sstevel@tonic-gate #include <openssl/rand.h> 417c478bd9Sstevel@tonic-gate #include <openssl/pkcs12.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate /* this must be included after ssl.h to avoid re-defining 'offsetof' */ 447c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #include <boot_http.h> 477c478bd9Sstevel@tonic-gate #include <socket_inet.h> 487c478bd9Sstevel@tonic-gate #include <p12access.h> 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #include "bootlog.h" 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #define BOOT_HTTP_MAJOR_VERSION 1 537c478bd9Sstevel@tonic-gate #define BOOT_HTTP_MINOR_VERSION 0 547c478bd9Sstevel@tonic-gate #define BOOT_HTTP_MICRO_VERSION 0 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate static boot_http_ver_t boot_http_ver = { 577c478bd9Sstevel@tonic-gate BOOT_HTTP_MAJOR_VERSION, 587c478bd9Sstevel@tonic-gate BOOT_HTTP_MINOR_VERSION, 597c478bd9Sstevel@tonic-gate BOOT_HTTP_MICRO_VERSION 607c478bd9Sstevel@tonic-gate }; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate static int early_err; /* Error from before error occurred */ 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate static boolean_t verbosemode = B_FALSE; 657c478bd9Sstevel@tonic-gate static char *cipher_list = NULL; /* Ciphers supported (if not default) */ 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate typedef struct { 687c478bd9Sstevel@tonic-gate int i; /* current position in buffer */ 697c478bd9Sstevel@tonic-gate int n; /* number of bytes in buffer */ 707c478bd9Sstevel@tonic-gate char buf[512]; /* buffer */ 717c478bd9Sstevel@tonic-gate } buf_struct_t; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate typedef struct { 747c478bd9Sstevel@tonic-gate uint_t errsrc; /* Source of this error */ 757c478bd9Sstevel@tonic-gate ulong_t error; /* Which error? */ 767c478bd9Sstevel@tonic-gate } errent_t; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate typedef enum { 807c478bd9Sstevel@tonic-gate HTTP_REQ_TYPE_HEAD = 1, 817c478bd9Sstevel@tonic-gate HTTP_REQ_TYPE_GET 827c478bd9Sstevel@tonic-gate } http_req_t; 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate #define FAILSAFE 20 /* Max # empty lines to accept */ 857c478bd9Sstevel@tonic-gate #define DEFAULT_TIMEOUT 10 /* Default socket read timeout value */ 867c478bd9Sstevel@tonic-gate #define HTTP_CONN_INFO 0x90919293 /* Identifies a http_conn_t struct */ 877c478bd9Sstevel@tonic-gate #define ESTACK_SIZE 20 /* Size of the stack */ 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate typedef struct http_conn_t { 907c478bd9Sstevel@tonic-gate uint_t signature; /* Cookie indicating this is a handle */ 917c478bd9Sstevel@tonic-gate int fd; /* Connection's fd... */ 927c478bd9Sstevel@tonic-gate SSL_CTX *ctx; 937c478bd9Sstevel@tonic-gate void *ssl; /* Handle to ssl data structure */ 947c478bd9Sstevel@tonic-gate int read_timeout; /* Timeout to use on read requests in sec */ 957c478bd9Sstevel@tonic-gate char *basic_auth_userid; /* Basic authentication user ID */ 967c478bd9Sstevel@tonic-gate char *basic_auth_password; /* and password */ 977c478bd9Sstevel@tonic-gate char is_multipart; /* B_TRUE if doing multipart/mixed download */ 987c478bd9Sstevel@tonic-gate char is_firstpart; /* B_TRUE if first part in a multipart xfer */ 997c478bd9Sstevel@tonic-gate char is_firstchunk; /* B_TRUE if first chunk in chunked xfer */ 1007c478bd9Sstevel@tonic-gate char is_chunked; /* B_TRUE if message body is chunked */ 1017c478bd9Sstevel@tonic-gate boolean_t keepalive; 1027c478bd9Sstevel@tonic-gate struct sockaddr_in host_addr; /* Address of host */ 1037c478bd9Sstevel@tonic-gate url_t uri; /* The current URI */ 1047c478bd9Sstevel@tonic-gate url_hport_t proxy; /* The proxy info */ 1057c478bd9Sstevel@tonic-gate boolean_t proxied; /* Connection is proxied */ 1067c478bd9Sstevel@tonic-gate char *random_file; /* File with seed info for pseudo random */ 1077c478bd9Sstevel@tonic-gate /* number generator */ 1087c478bd9Sstevel@tonic-gate char *client_cert_file; /* File holding client's certificate */ 1097c478bd9Sstevel@tonic-gate char *private_key_file; /* File with the private key */ 1107c478bd9Sstevel@tonic-gate char *file_password; /* file with password to key or pkcs12 file. */ 1117c478bd9Sstevel@tonic-gate http_respinfo_t resp; /* Response summary info */ 1127c478bd9Sstevel@tonic-gate char **resphdr; /* Array of header response lines */ 1137c478bd9Sstevel@tonic-gate buf_struct_t inbuf; 1147c478bd9Sstevel@tonic-gate char *boundary; /* Boundary text (multipart downloads only) */ 1157c478bd9Sstevel@tonic-gate uint_t boundary_len; /* Length of boundary string */ 1167c478bd9Sstevel@tonic-gate uint_t numerrs; 1177c478bd9Sstevel@tonic-gate uint_t nexterr; /* Next error to return */ 1187c478bd9Sstevel@tonic-gate ssize_t body_size; /* Size of message body or chunk */ 1197c478bd9Sstevel@tonic-gate ssize_t body_read; /* # of bytes of body_size processed */ 1207c478bd9Sstevel@tonic-gate ssize_t body_size_tot; /* Total message body size */ 1217c478bd9Sstevel@tonic-gate ssize_t body_read_tot; /* # of bytes of body_size_tot processed */ 1227c478bd9Sstevel@tonic-gate errent_t errs[ESTACK_SIZE]; /* stack of errors on the last request */ 1237c478bd9Sstevel@tonic-gate /* (libssl can return multiple errors on one */ 1247c478bd9Sstevel@tonic-gate /* operation) */ 1257c478bd9Sstevel@tonic-gate } http_conn_t; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * Convenient macros for accessing fields in connection structure. 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate #define CONN_HOSTNAME c_id->uri.hport.hostname 1317c478bd9Sstevel@tonic-gate #define CONN_PORT c_id->uri.hport.port 1327c478bd9Sstevel@tonic-gate #define CONN_ABSPATH c_id->uri.abspath 1337c478bd9Sstevel@tonic-gate #define CONN_HTTPS c_id->uri.https 1347c478bd9Sstevel@tonic-gate #define CONN_PROXY_HOSTNAME c_id->proxy.hostname 1357c478bd9Sstevel@tonic-gate #define CONN_PROXY_PORT c_id->proxy.port 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate #define RESET_ERR(c_id) (c_id)->numerrs = 0, (c_id)->nexterr = 0 1387c478bd9Sstevel@tonic-gate #define SET_ERR(c_id, src, err) if ((c_id)->numerrs < ESTACK_SIZE) \ 1397c478bd9Sstevel@tonic-gate (c_id)->errs[(c_id)->numerrs].errsrc = (src), \ 1407c478bd9Sstevel@tonic-gate (c_id)->errs[(c_id)->numerrs ++].error = (err) 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate #define GET_ERR(c_id, e_src, e_code) \ 1437c478bd9Sstevel@tonic-gate if ((c_id)->nexterr < (c_id)->numerrs) \ 1447c478bd9Sstevel@tonic-gate (e_src) = (c_id)->errs[((c_id)->nexterr)].errsrc, \ 1457c478bd9Sstevel@tonic-gate (e_code) = (c_id)->errs[((c_id)->nexterr)++].error; \ 1467c478bd9Sstevel@tonic-gate else \ 1477c478bd9Sstevel@tonic-gate (e_src) = 0, (e_code) = 0 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * Macro used to increment message body read counters 1517c478bd9Sstevel@tonic-gate */ 1527c478bd9Sstevel@tonic-gate #define INC_BREAD_CNT(bool, bcnt) \ 1537c478bd9Sstevel@tonic-gate if (bool) { \ 1547c478bd9Sstevel@tonic-gate bcnt--; \ 1557c478bd9Sstevel@tonic-gate c_id->body_read++;\ 1567c478bd9Sstevel@tonic-gate c_id->body_read_tot++; \ 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate static int ssl_init = 0; /* 1 when ssl has been initialized */ 1607c478bd9Sstevel@tonic-gate static char *ca_verify_file; /* List of trusted CA's */ 1617c478bd9Sstevel@tonic-gate static int verify_depth = 16; /* Certificate chain depth to verify */ 1627c478bd9Sstevel@tonic-gate static int p12_format = 0; /* Default to PEM format */ 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /* prototypes for local functions */ 166cb4c2b01Svh115876 static int http_req(http_handle_t, const char *, http_req_t, offset_t, 167cb4c2b01Svh115876 offset_t); 1687c478bd9Sstevel@tonic-gate static boolean_t http_check_conn(http_conn_t *); 1697c478bd9Sstevel@tonic-gate static SSL_CTX *initialize_ctx(http_conn_t *); 1707c478bd9Sstevel@tonic-gate static int tcp_connect(http_conn_t *, const char *, uint16_t); 1717c478bd9Sstevel@tonic-gate static int readline(http_conn_t *, int, char *, int); 1727c478bd9Sstevel@tonic-gate static int proxy_connect(http_conn_t *); 1737c478bd9Sstevel@tonic-gate static int check_cert_chain(http_conn_t *, char *); 1747c478bd9Sstevel@tonic-gate static void print_ciphers(SSL *); 1757c478bd9Sstevel@tonic-gate static int read_headerlines(http_conn_t *, boolean_t); 1767c478bd9Sstevel@tonic-gate static void free_response(http_conn_t *, int); 1777c478bd9Sstevel@tonic-gate static int free_ctx_ssl(http_conn_t *); 1787c478bd9Sstevel@tonic-gate static int get_chunk_header(http_conn_t *); 1797c478bd9Sstevel@tonic-gate static int init_bread(http_conn_t *); 1807c478bd9Sstevel@tonic-gate static int get_msgcnt(http_conn_t *, ssize_t *); 18123a1cceaSRoger A. Faulkner static int getaline(http_conn_t *, char *, int, boolean_t); 1827c478bd9Sstevel@tonic-gate static int getbytes(http_conn_t *, char *, int); 1837c478bd9Sstevel@tonic-gate static int http_srv_send(http_conn_t *, const void *, size_t); 1847c478bd9Sstevel@tonic-gate static int http_srv_recv(http_conn_t *, void *, size_t); 1857c478bd9Sstevel@tonic-gate static void handle_ssl_error(http_conn_t *, int); 1867c478bd9Sstevel@tonic-gate static int count_digits(int); 1877c478bd9Sstevel@tonic-gate static int hexdigit(char); 1887c478bd9Sstevel@tonic-gate static char *eat_ws(const char *); 1897c478bd9Sstevel@tonic-gate static boolean_t startswith(const char **strp, const char *starts); 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* ---------------------- public functions ----------------------- */ 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate /* 1947c478bd9Sstevel@tonic-gate * http_set_p12_format - Set flag indicating that certs & keys will be in 1957c478bd9Sstevel@tonic-gate * pkcs12 format. 1967c478bd9Sstevel@tonic-gate * 1977c478bd9Sstevel@tonic-gate * Default is PEM certs. When this is called, the default can be changed to 1987c478bd9Sstevel@tonic-gate * pcs12 format. 1997c478bd9Sstevel@tonic-gate */ 2007c478bd9Sstevel@tonic-gate void 2017c478bd9Sstevel@tonic-gate http_set_p12_format(int on_off) 2027c478bd9Sstevel@tonic-gate { 2037c478bd9Sstevel@tonic-gate p12_format = on_off; 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate /* 2077c478bd9Sstevel@tonic-gate * http_get_version - Get current boot http support version 2087c478bd9Sstevel@tonic-gate * 2097c478bd9Sstevel@tonic-gate * pVer = http_get_version(); 2107c478bd9Sstevel@tonic-gate * 2117c478bd9Sstevel@tonic-gate * Arguments: 2127c478bd9Sstevel@tonic-gate * None. 2137c478bd9Sstevel@tonic-gate * 2147c478bd9Sstevel@tonic-gate * Returns: 2157c478bd9Sstevel@tonic-gate * Pointer to struct with version information. 2167c478bd9Sstevel@tonic-gate * 2177c478bd9Sstevel@tonic-gate * Returns the version of the http support in the current library. This 2187c478bd9Sstevel@tonic-gate * is a struct with unsigned integsrs for <major>, <minor> and 2197c478bd9Sstevel@tonic-gate * <micro> version numbers. <major> changes when an incompatible change 2207c478bd9Sstevel@tonic-gate * is made. <minor> changes when an upwardly-compatible API change is 2217c478bd9Sstevel@tonic-gate * made. <micro> consists of bug fixes, etc. 2227c478bd9Sstevel@tonic-gate */ 2237c478bd9Sstevel@tonic-gate boot_http_ver_t const * 2247c478bd9Sstevel@tonic-gate http_get_version(void) 2257c478bd9Sstevel@tonic-gate { 2267c478bd9Sstevel@tonic-gate return (&boot_http_ver); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * http_set_verbose - Turn verbose on/off 2317c478bd9Sstevel@tonic-gate * 2327c478bd9Sstevel@tonic-gate * http_set_verbose(on_off); 2337c478bd9Sstevel@tonic-gate * 2347c478bd9Sstevel@tonic-gate * Arguments: 2357c478bd9Sstevel@tonic-gate * on_off - When TRUE, turn verbose mode one. When FALSE, turn 2367c478bd9Sstevel@tonic-gate * verbose off. 2377c478bd9Sstevel@tonic-gate * 2387c478bd9Sstevel@tonic-gate * Returns: 2397c478bd9Sstevel@tonic-gate * None. 2407c478bd9Sstevel@tonic-gate * 2417c478bd9Sstevel@tonic-gate * When enabled, information is logged to bootlog (or the Solaris equivalent). 2427c478bd9Sstevel@tonic-gate */ 2437c478bd9Sstevel@tonic-gate void 2447c478bd9Sstevel@tonic-gate http_set_verbose(boolean_t on_off) 2457c478bd9Sstevel@tonic-gate { 2467c478bd9Sstevel@tonic-gate verbosemode = on_off; 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * http_set_cipher_list - Change the list of ciphers that can be used. 2517c478bd9Sstevel@tonic-gate * 2527c478bd9Sstevel@tonic-gate * ret = http_set_cipher_list(handle, list); 2537c478bd9Sstevel@tonic-gate * 2547c478bd9Sstevel@tonic-gate * Arguments: 2557c478bd9Sstevel@tonic-gate * list - List of ciphers that can be used. 2567c478bd9Sstevel@tonic-gate * 2577c478bd9Sstevel@tonic-gate * Returns: 2587c478bd9Sstevel@tonic-gate * 0 - Success 2597c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 2607c478bd9Sstevel@tonic-gate */ 2617c478bd9Sstevel@tonic-gate int 2627c478bd9Sstevel@tonic-gate http_set_cipher_list(const char *list) 2637c478bd9Sstevel@tonic-gate { 2647c478bd9Sstevel@tonic-gate early_err = 0; 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate if (list != NULL) { 2677c478bd9Sstevel@tonic-gate list = strdup(list); 2687c478bd9Sstevel@tonic-gate if (list == NULL) { 2697c478bd9Sstevel@tonic-gate early_err = EHTTP_NOMEM; 2707c478bd9Sstevel@tonic-gate return (-1); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate free(cipher_list); 2757c478bd9Sstevel@tonic-gate cipher_list = (char *)list; 2767c478bd9Sstevel@tonic-gate return (0); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * http_srv_init - Set up a structure for a connection. 2817c478bd9Sstevel@tonic-gate * 2827c478bd9Sstevel@tonic-gate * handle = http_srv_init(url); 2837c478bd9Sstevel@tonic-gate * 2847c478bd9Sstevel@tonic-gate * Arguments: 2857c478bd9Sstevel@tonic-gate * url - the structure that contains the URI. 2867c478bd9Sstevel@tonic-gate * 2877c478bd9Sstevel@tonic-gate * Returns: 2887c478bd9Sstevel@tonic-gate * != NULL - A handle for referring to this connection. 2897c478bd9Sstevel@tonic-gate * == NULL - An error occurred. Get the exact error from 2907c478bd9Sstevel@tonic-gate * http_get_lasterr(). 2917c478bd9Sstevel@tonic-gate */ 2927c478bd9Sstevel@tonic-gate http_handle_t 2937c478bd9Sstevel@tonic-gate http_srv_init(const url_t *url) 2947c478bd9Sstevel@tonic-gate { 2957c478bd9Sstevel@tonic-gate http_conn_t *c_id; 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate early_err = 0; 2987c478bd9Sstevel@tonic-gate if (url == NULL) { 2997c478bd9Sstevel@tonic-gate early_err = EHTTP_BADARG; 3007c478bd9Sstevel@tonic-gate return (NULL); 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate if ((c_id = malloc(sizeof (*c_id))) == NULL) { 3047c478bd9Sstevel@tonic-gate early_err = EHTTP_NOMEM; 3057c478bd9Sstevel@tonic-gate return (NULL); 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate bzero(c_id, sizeof (*c_id)); 3097c478bd9Sstevel@tonic-gate c_id->uri = *url; 3107c478bd9Sstevel@tonic-gate c_id->proxied = B_FALSE; 3117c478bd9Sstevel@tonic-gate c_id->read_timeout = DEFAULT_TIMEOUT; 3127c478bd9Sstevel@tonic-gate c_id->keepalive = B_TRUE; 3137c478bd9Sstevel@tonic-gate c_id->fd = -1; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* Do this at the end, just in case.... */ 3167c478bd9Sstevel@tonic-gate c_id->signature = HTTP_CONN_INFO; 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate return (c_id); 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /* 3227c478bd9Sstevel@tonic-gate * http_conn_is_https - Determine whether the scheme is http or https. 3237c478bd9Sstevel@tonic-gate * 3247c478bd9Sstevel@tonic-gate * B_TRUE - Connection is an SSL connection. 3257c478bd9Sstevel@tonic-gate * B_FALSE - Connection isn't SSL. 3267c478bd9Sstevel@tonic-gate * 3277c478bd9Sstevel@tonic-gate * ret = http_conn_is_https(handle, boolean_t *bool); 3287c478bd9Sstevel@tonic-gate * 3297c478bd9Sstevel@tonic-gate * Arguments: 3307c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 3317c478bd9Sstevel@tonic-gate * bool - Ptr to boolean in which to place result 3327c478bd9Sstevel@tonic-gate * 3337c478bd9Sstevel@tonic-gate * Returns: 3347c478bd9Sstevel@tonic-gate * 0 - Success 3357c478bd9Sstevel@tonic-gate * -1 - Some error occurred. 3367c478bd9Sstevel@tonic-gate */ 3377c478bd9Sstevel@tonic-gate int 3387c478bd9Sstevel@tonic-gate http_conn_is_https(http_handle_t handle, boolean_t *bool) 3397c478bd9Sstevel@tonic-gate { 3407c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 3437c478bd9Sstevel@tonic-gate return (-1); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate *bool = CONN_HTTPS; 3467c478bd9Sstevel@tonic-gate return (0); 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate /* 3507c478bd9Sstevel@tonic-gate * http_set_proxy - Establish the proxy name/port. 3517c478bd9Sstevel@tonic-gate * 3527c478bd9Sstevel@tonic-gate * ret = http_set_proxy(handle, proxy); 3537c478bd9Sstevel@tonic-gate * 3547c478bd9Sstevel@tonic-gate * Arguments: 3557c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 3567c478bd9Sstevel@tonic-gate * proxy - The hostport definition for the proxy. If NULL, 3577c478bd9Sstevel@tonic-gate * The next connect will not use a proxy. 3587c478bd9Sstevel@tonic-gate * 3597c478bd9Sstevel@tonic-gate * Returns: 3607c478bd9Sstevel@tonic-gate * 0 - Success 3617c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 3627c478bd9Sstevel@tonic-gate */ 3637c478bd9Sstevel@tonic-gate int 3647c478bd9Sstevel@tonic-gate http_set_proxy(http_handle_t handle, const url_hport_t *proxy) 3657c478bd9Sstevel@tonic-gate { 3667c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 3697c478bd9Sstevel@tonic-gate return (-1); 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate if (proxy != NULL) { 3727c478bd9Sstevel@tonic-gate c_id->proxy = *proxy; 3737c478bd9Sstevel@tonic-gate c_id->proxied = B_TRUE; 3747c478bd9Sstevel@tonic-gate } else { 3757c478bd9Sstevel@tonic-gate CONN_PROXY_HOSTNAME[0] = '\0'; 3767c478bd9Sstevel@tonic-gate c_id->proxied = B_FALSE; 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate return (0); 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* 3837c478bd9Sstevel@tonic-gate * http_set_keepalive - Set keepalive for this connection. 3847c478bd9Sstevel@tonic-gate * 3857c478bd9Sstevel@tonic-gate * http_set_keepalive(handle, on_off); 3867c478bd9Sstevel@tonic-gate * 3877c478bd9Sstevel@tonic-gate * Arguments: 3887c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 3897c478bd9Sstevel@tonic-gate * on_off - Boolean turning keepalive on (TRUE) or off (FALSE) 3907c478bd9Sstevel@tonic-gate * 3917c478bd9Sstevel@tonic-gate * Returns: 3927c478bd9Sstevel@tonic-gate * 0 - Success. 3937c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 3947c478bd9Sstevel@tonic-gate * 3957c478bd9Sstevel@tonic-gate * This setting takes effect next time a connection is opened using this 3967c478bd9Sstevel@tonic-gate * handle. 3977c478bd9Sstevel@tonic-gate */ 3987c478bd9Sstevel@tonic-gate int 3997c478bd9Sstevel@tonic-gate http_set_keepalive(http_handle_t handle, boolean_t on_off) 4007c478bd9Sstevel@tonic-gate { 4017c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 4047c478bd9Sstevel@tonic-gate return (-1); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate c_id->keepalive = on_off; 4077c478bd9Sstevel@tonic-gate return (0); 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* 4117c478bd9Sstevel@tonic-gate * http_set_socket_read_timeout - Set the timeout reads 4127c478bd9Sstevel@tonic-gate * 4137c478bd9Sstevel@tonic-gate * http_set_socket_read_timeout(handle, timeout); 4147c478bd9Sstevel@tonic-gate * 4157c478bd9Sstevel@tonic-gate * Arguments: 4167c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 4177c478bd9Sstevel@tonic-gate * timeout - Timeout, in seconds. Zero will default to 10 second 4187c478bd9Sstevel@tonic-gate * timeouts. 4197c478bd9Sstevel@tonic-gate * 4207c478bd9Sstevel@tonic-gate * Returns: 4217c478bd9Sstevel@tonic-gate * 0 - Success. 4227c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 4237c478bd9Sstevel@tonic-gate * 4247c478bd9Sstevel@tonic-gate * This setting takes effect beginning with the next read operation on this 4257c478bd9Sstevel@tonic-gate * connection. 4267c478bd9Sstevel@tonic-gate */ 4277c478bd9Sstevel@tonic-gate int 4287c478bd9Sstevel@tonic-gate http_set_socket_read_timeout(http_handle_t handle, uint_t timout) 4297c478bd9Sstevel@tonic-gate { 4307c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 4337c478bd9Sstevel@tonic-gate return (-1); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate c_id->read_timeout = (timout) ? timout : DEFAULT_TIMEOUT; 4367c478bd9Sstevel@tonic-gate return (0); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate /* 4407c478bd9Sstevel@tonic-gate * http_set_basic_auth - Set the basic authorization user ID and password 4417c478bd9Sstevel@tonic-gate * 4427c478bd9Sstevel@tonic-gate * ret = http_set_basic_auth(handle, userid, password); 4437c478bd9Sstevel@tonic-gate * 4447c478bd9Sstevel@tonic-gate * Arguments: 4457c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 4467c478bd9Sstevel@tonic-gate * userid - ID to pass as part of http/https request 4477c478bd9Sstevel@tonic-gate * password- Password which goes with the user ID 4487c478bd9Sstevel@tonic-gate * 4497c478bd9Sstevel@tonic-gate * Returns: 4507c478bd9Sstevel@tonic-gate * 0 - Success 4517c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 4527c478bd9Sstevel@tonic-gate * 4537c478bd9Sstevel@tonic-gate * This must be set before a https connection is made. 4547c478bd9Sstevel@tonic-gate */ 4557c478bd9Sstevel@tonic-gate int 4567c478bd9Sstevel@tonic-gate http_set_basic_auth(http_handle_t handle, const char *userid, 4577c478bd9Sstevel@tonic-gate const char *password) 4587c478bd9Sstevel@tonic-gate { 4597c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 4627c478bd9Sstevel@tonic-gate return (-1); 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate if (password == NULL || userid == NULL || userid[0] == '\0') { 4657c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 4667c478bd9Sstevel@tonic-gate return (-1); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate userid = strdup(userid); 4707c478bd9Sstevel@tonic-gate password = strdup(password); 4717c478bd9Sstevel@tonic-gate if (userid == NULL || password == NULL) { 4727c478bd9Sstevel@tonic-gate free((void *)userid); 4737c478bd9Sstevel@tonic-gate free((void *)password); 4747c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 4757c478bd9Sstevel@tonic-gate return (-1); 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate free(c_id->basic_auth_userid); 4797c478bd9Sstevel@tonic-gate c_id->basic_auth_userid = (char *)userid; 4807c478bd9Sstevel@tonic-gate free(c_id->basic_auth_password); 4817c478bd9Sstevel@tonic-gate c_id->basic_auth_password = (char *)password; 4827c478bd9Sstevel@tonic-gate return (0); 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate /* 4867c478bd9Sstevel@tonic-gate * http_set_random_file - See the pseudo random number generator with file data 4877c478bd9Sstevel@tonic-gate * 4887c478bd9Sstevel@tonic-gate * ret = http_set_random_file(handle, filename); 4897c478bd9Sstevel@tonic-gate * 4907c478bd9Sstevel@tonic-gate * Arguments: 4917c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 4927c478bd9Sstevel@tonic-gate * filename 4937c478bd9Sstevel@tonic-gate * - filename (including path) with random number seed. 4947c478bd9Sstevel@tonic-gate * 4957c478bd9Sstevel@tonic-gate * Returns: 4967c478bd9Sstevel@tonic-gate * 0 - Success 4977c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 4987c478bd9Sstevel@tonic-gate * 4997c478bd9Sstevel@tonic-gate * This must be set before a https connection is made. 5007c478bd9Sstevel@tonic-gate */ 5017c478bd9Sstevel@tonic-gate int 5027c478bd9Sstevel@tonic-gate http_set_random_file(http_handle_t handle, const char *fname) 5037c478bd9Sstevel@tonic-gate { 5047c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 5077c478bd9Sstevel@tonic-gate return (-1); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate if (fname != NULL) { 5107c478bd9Sstevel@tonic-gate fname = strdup(fname); 5117c478bd9Sstevel@tonic-gate if (fname == NULL) { 5127c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 5137c478bd9Sstevel@tonic-gate return (-1); 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate free(c_id->random_file); 5187c478bd9Sstevel@tonic-gate c_id->random_file = (char *)fname; 5197c478bd9Sstevel@tonic-gate return (0); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate /* 5237c478bd9Sstevel@tonic-gate * http_set_certificate_authority_file - Set the CA file. 5247c478bd9Sstevel@tonic-gate * 5257c478bd9Sstevel@tonic-gate * ret = http_set_certificate_authority_file(filename); 5267c478bd9Sstevel@tonic-gate * 5277c478bd9Sstevel@tonic-gate * Arguments: 5287c478bd9Sstevel@tonic-gate * filename- File with the certificate authority certs 5297c478bd9Sstevel@tonic-gate * 5307c478bd9Sstevel@tonic-gate * Returns: 5317c478bd9Sstevel@tonic-gate * 0 - Success 5327c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 5337c478bd9Sstevel@tonic-gate * 5347c478bd9Sstevel@tonic-gate * This must be set before https connections to the servers is done. 5357c478bd9Sstevel@tonic-gate */ 5367c478bd9Sstevel@tonic-gate int 5377c478bd9Sstevel@tonic-gate http_set_certificate_authority_file(const char *fname) 5387c478bd9Sstevel@tonic-gate { 5397c478bd9Sstevel@tonic-gate early_err = 0; 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate if (fname != NULL) { 5427c478bd9Sstevel@tonic-gate fname = strdup(fname); 5437c478bd9Sstevel@tonic-gate if (fname == NULL) { 5447c478bd9Sstevel@tonic-gate early_err = EHTTP_NOMEM; 5457c478bd9Sstevel@tonic-gate return (-1); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate free(ca_verify_file); 5507c478bd9Sstevel@tonic-gate ca_verify_file = (char *)fname; 5517c478bd9Sstevel@tonic-gate return (0); 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /* 5557c478bd9Sstevel@tonic-gate * http_set_client_certificate_file - Set the file containing the PKCS#12 5567c478bd9Sstevel@tonic-gate * client certificate and optionally its certificate chain. 5577c478bd9Sstevel@tonic-gate * 5587c478bd9Sstevel@tonic-gate * ret = http_set_client_certificate_file(handle, filename); 5597c478bd9Sstevel@tonic-gate * 5607c478bd9Sstevel@tonic-gate * Arguments: 5617c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 5627c478bd9Sstevel@tonic-gate * filename- File (including path) containing certificate, etc. 5637c478bd9Sstevel@tonic-gate * 5647c478bd9Sstevel@tonic-gate * Returns: 5657c478bd9Sstevel@tonic-gate * 0 - Success 5667c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 5677c478bd9Sstevel@tonic-gate * 5687c478bd9Sstevel@tonic-gate * This must be set before the handle is used to make a https connection 5697c478bd9Sstevel@tonic-gate * which will require a client certificate. 5707c478bd9Sstevel@tonic-gate */ 5717c478bd9Sstevel@tonic-gate int 5727c478bd9Sstevel@tonic-gate http_set_client_certificate_file(http_handle_t handle, const char *fname) 5737c478bd9Sstevel@tonic-gate { 5747c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 5777c478bd9Sstevel@tonic-gate return (-1); 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate if (fname != NULL) { 5807c478bd9Sstevel@tonic-gate fname = strdup(fname); 5817c478bd9Sstevel@tonic-gate if (fname == NULL) { 5827c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 5837c478bd9Sstevel@tonic-gate return (-1); 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate free(c_id->client_cert_file); 5887c478bd9Sstevel@tonic-gate c_id->client_cert_file = (char *)fname; 5897c478bd9Sstevel@tonic-gate return (0); 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate /* 5937c478bd9Sstevel@tonic-gate * http_set_password - Set the password for the private key or pkcs12 file. 5947c478bd9Sstevel@tonic-gate * 5957c478bd9Sstevel@tonic-gate * ret = http_set_password(handle, password); 5967c478bd9Sstevel@tonic-gate * 5977c478bd9Sstevel@tonic-gate * Arguments: 5987c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 5997c478bd9Sstevel@tonic-gate * password- Password for the client's private key file or pkcs12 file. 6007c478bd9Sstevel@tonic-gate * 6017c478bd9Sstevel@tonic-gate * Returns: 6027c478bd9Sstevel@tonic-gate * 0 - Success 6037c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 6047c478bd9Sstevel@tonic-gate * 6057c478bd9Sstevel@tonic-gate * This must be set before the handle is used to make a https connection. 6067c478bd9Sstevel@tonic-gate */ 6077c478bd9Sstevel@tonic-gate int 6087c478bd9Sstevel@tonic-gate http_set_password(http_handle_t handle, const char *password) 6097c478bd9Sstevel@tonic-gate { 6107c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 6137c478bd9Sstevel@tonic-gate return (-1); 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate if (password != NULL) { 6167c478bd9Sstevel@tonic-gate password = strdup(password); 6177c478bd9Sstevel@tonic-gate if (password == NULL) { 6187c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 6197c478bd9Sstevel@tonic-gate return (-1); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate free(c_id->file_password); 6247c478bd9Sstevel@tonic-gate c_id->file_password = (char *)password; 6257c478bd9Sstevel@tonic-gate return (0); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate /* 6297c478bd9Sstevel@tonic-gate * http_set_key_file_password - Set the password for the private key 6307c478bd9Sstevel@tonic-gate * file. 6317c478bd9Sstevel@tonic-gate * 6327c478bd9Sstevel@tonic-gate * ret = http_set_key_file_password(handle, password); 6337c478bd9Sstevel@tonic-gate * 6347c478bd9Sstevel@tonic-gate * Arguments: 6357c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 6367c478bd9Sstevel@tonic-gate * password- Password for the client's private key file. 6377c478bd9Sstevel@tonic-gate * 6387c478bd9Sstevel@tonic-gate * Returns: 6397c478bd9Sstevel@tonic-gate * 0 - Success 6407c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 6417c478bd9Sstevel@tonic-gate * 6427c478bd9Sstevel@tonic-gate * This must be set before the handle is used to make a https connection. 6437c478bd9Sstevel@tonic-gate */ 6447c478bd9Sstevel@tonic-gate int 6457c478bd9Sstevel@tonic-gate http_set_key_file_password(http_handle_t handle, const char *password) 6467c478bd9Sstevel@tonic-gate { 6477c478bd9Sstevel@tonic-gate return (http_set_password(handle, password)); 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate /* 6517c478bd9Sstevel@tonic-gate * http_set_private_key_file - Set the file containing the PKCS#12 6527c478bd9Sstevel@tonic-gate * private key for this client. 6537c478bd9Sstevel@tonic-gate * 6547c478bd9Sstevel@tonic-gate * ret = http_set_private_key_file(handle, filename); 6557c478bd9Sstevel@tonic-gate * 6567c478bd9Sstevel@tonic-gate * Arguments: 6577c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 6587c478bd9Sstevel@tonic-gate * filename- File (including path) containing the private key. 6597c478bd9Sstevel@tonic-gate * 6607c478bd9Sstevel@tonic-gate * Returns: 6617c478bd9Sstevel@tonic-gate * 0 - Success 6627c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 6637c478bd9Sstevel@tonic-gate * 6647c478bd9Sstevel@tonic-gate * This must be set before the handle is used to make a https connection. 6657c478bd9Sstevel@tonic-gate */ 6667c478bd9Sstevel@tonic-gate int 6677c478bd9Sstevel@tonic-gate http_set_private_key_file(http_handle_t handle, const char *fname) 6687c478bd9Sstevel@tonic-gate { 6697c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 6727c478bd9Sstevel@tonic-gate return (-1); 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate if (fname != NULL) { 6757c478bd9Sstevel@tonic-gate fname = strdup(fname); 6767c478bd9Sstevel@tonic-gate if (fname == NULL) { 6777c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 6787c478bd9Sstevel@tonic-gate return (-1); 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate free(c_id->private_key_file); 6837c478bd9Sstevel@tonic-gate c_id->private_key_file = (char *)fname; 6847c478bd9Sstevel@tonic-gate return (0); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 6887c478bd9Sstevel@tonic-gate * http_srv_connect - Establish a connection to the server 6897c478bd9Sstevel@tonic-gate * 6907c478bd9Sstevel@tonic-gate * ret = http_srv_connect(handle); 6917c478bd9Sstevel@tonic-gate * 6927c478bd9Sstevel@tonic-gate * Arguments: 6937c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 6947c478bd9Sstevel@tonic-gate * 6957c478bd9Sstevel@tonic-gate * Returns: 6967c478bd9Sstevel@tonic-gate * 0 - Success 6977c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr() for specifics. 6987c478bd9Sstevel@tonic-gate */ 6997c478bd9Sstevel@tonic-gate int 7007c478bd9Sstevel@tonic-gate http_srv_connect(http_handle_t handle) 7017c478bd9Sstevel@tonic-gate { 7027c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 7037c478bd9Sstevel@tonic-gate SSL_CTX *ctx = NULL; 7047c478bd9Sstevel@tonic-gate int retval; 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate ERR_clear_error(); 7077c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 7087c478bd9Sstevel@tonic-gate return (-1); 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate if (CONN_HTTPS) { 7117c478bd9Sstevel@tonic-gate /* Build our SSL context (this function sets any errors) */ 7127c478bd9Sstevel@tonic-gate ctx = initialize_ctx(c_id); 7137c478bd9Sstevel@tonic-gate if (ctx == NULL) { 7147c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 7157c478bd9Sstevel@tonic-gate "http_srv_connect: initialize_ctx returned NULL"); 7167c478bd9Sstevel@tonic-gate return (-1); 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate /* Connect the TCP socket */ 7217c478bd9Sstevel@tonic-gate if (c_id->proxied) { 7227c478bd9Sstevel@tonic-gate c_id->fd = proxy_connect(c_id); 7237c478bd9Sstevel@tonic-gate } else { 7247c478bd9Sstevel@tonic-gate c_id->fd = tcp_connect(c_id, CONN_HOSTNAME, CONN_PORT); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate if (c_id->fd < 0) { 7287c478bd9Sstevel@tonic-gate if (ctx != NULL) 7297c478bd9Sstevel@tonic-gate SSL_CTX_free(ctx); 7307c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 7317c478bd9Sstevel@tonic-gate "http_srv_connect: %s returned %d", 7327c478bd9Sstevel@tonic-gate (c_id->proxied) ? "proxy_connect" : "tcp_connect", 7337c478bd9Sstevel@tonic-gate c_id->fd); 7347c478bd9Sstevel@tonic-gate return (-1); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate if (CONN_HTTPS) { 7387c478bd9Sstevel@tonic-gate /* Connect the SSL socket */ 7397c478bd9Sstevel@tonic-gate if ((c_id->ssl = SSL_new(ctx)) == NULL) { 7407c478bd9Sstevel@tonic-gate ulong_t err; 7417c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 7427c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 7437c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 7447c478bd9Sstevel@tonic-gate "http_srv_connect: SSL_new returned " 7457c478bd9Sstevel@tonic-gate "NULL"); 7467c478bd9Sstevel@tonic-gate (void) free_ctx_ssl(c_id); 7477c478bd9Sstevel@tonic-gate return (-1); 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate if (verbosemode) 7507c478bd9Sstevel@tonic-gate print_ciphers(c_id->ssl); 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate /* Ensure automatic negotiations will do things right */ 7537c478bd9Sstevel@tonic-gate SSL_set_connect_state(c_id->ssl); 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate if (SSL_set_fd(c_id->ssl, c_id->fd) == 0) { 7567c478bd9Sstevel@tonic-gate ulong_t err; 7577c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 7587c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 7597c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 7607c478bd9Sstevel@tonic-gate "http_srv_connect: SSL_set_fd returned 0"); 7617c478bd9Sstevel@tonic-gate (void) free_ctx_ssl(c_id); 7627c478bd9Sstevel@tonic-gate return (-1); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate if ((retval = SSL_connect(c_id->ssl)) <= 0) { 7667c478bd9Sstevel@tonic-gate handle_ssl_error(c_id, retval); 7677c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 7687c478bd9Sstevel@tonic-gate "http_srv_connect: SSL_connect"); 7697c478bd9Sstevel@tonic-gate (void) free_ctx_ssl(c_id); 7707c478bd9Sstevel@tonic-gate return (-1); 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate if (check_cert_chain(c_id, CONN_HOSTNAME) != 0) { 7747c478bd9Sstevel@tonic-gate (void) free_ctx_ssl(c_id); 7757c478bd9Sstevel@tonic-gate return (-1); 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate if (verbosemode) 7797c478bd9Sstevel@tonic-gate print_ciphers(c_id->ssl); 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate return (0); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /* 7867c478bd9Sstevel@tonic-gate * http_head_request - Issue http HEAD request 7877c478bd9Sstevel@tonic-gate * 7887c478bd9Sstevel@tonic-gate * ret = http_head_request(handle, abs_path); 7897c478bd9Sstevel@tonic-gate * 7907c478bd9Sstevel@tonic-gate * Arguments: 7917c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 7927c478bd9Sstevel@tonic-gate * abs_path- File name portion of the URI, beginning with a /. Query, 7937c478bd9Sstevel@tonic-gate * segment, etc are allowed. 7947c478bd9Sstevel@tonic-gate * 7957c478bd9Sstevel@tonic-gate * Returns: 7967c478bd9Sstevel@tonic-gate * 0 - Success 7977c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 7987c478bd9Sstevel@tonic-gate */ 7997c478bd9Sstevel@tonic-gate int 8007c478bd9Sstevel@tonic-gate http_head_request(http_handle_t handle, const char *abs_path) 8017c478bd9Sstevel@tonic-gate { 8027c478bd9Sstevel@tonic-gate return (http_req(handle, abs_path, HTTP_REQ_TYPE_HEAD, 0, 0)); 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate /* 8067c478bd9Sstevel@tonic-gate * http_get_request - Issue http GET request without a range. 8077c478bd9Sstevel@tonic-gate * 8087c478bd9Sstevel@tonic-gate * ret = http_get_request(handle, abs_path); 8097c478bd9Sstevel@tonic-gate * 8107c478bd9Sstevel@tonic-gate * Arguments: 8117c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 8127c478bd9Sstevel@tonic-gate * abs_path- File name portion of the URI, beginning with a /. Query, 8137c478bd9Sstevel@tonic-gate * segment, etc are allowed. 8147c478bd9Sstevel@tonic-gate * 8157c478bd9Sstevel@tonic-gate * Returns: 8167c478bd9Sstevel@tonic-gate * 0 - Success 8177c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 8187c478bd9Sstevel@tonic-gate */ 8197c478bd9Sstevel@tonic-gate int 8207c478bd9Sstevel@tonic-gate http_get_request(http_handle_t handle, const char *abs_path) 8217c478bd9Sstevel@tonic-gate { 8227c478bd9Sstevel@tonic-gate return (http_req(handle, abs_path, HTTP_REQ_TYPE_GET, -1, 0)); 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate * http_get_range_request - Issue http GET request using a range. 8277c478bd9Sstevel@tonic-gate * 8287c478bd9Sstevel@tonic-gate * ret = http_get_range_request(handle, abs_path, curpos, len); 8297c478bd9Sstevel@tonic-gate * 8307c478bd9Sstevel@tonic-gate * Arguments: 8317c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 8327c478bd9Sstevel@tonic-gate * abs_path- File name portion of the URI, beginning with a /. Query, 8337c478bd9Sstevel@tonic-gate * segment, etc are allowed. 8347c478bd9Sstevel@tonic-gate * curpos - >=0 - Beginning of range 8357c478bd9Sstevel@tonic-gate * len - = 0 - Range ends at the end of the file 8367c478bd9Sstevel@tonic-gate * > 0 - Length of range. 8377c478bd9Sstevel@tonic-gate * 8387c478bd9Sstevel@tonic-gate * Returns: 8397c478bd9Sstevel@tonic-gate * 0 - Success 8407c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 8417c478bd9Sstevel@tonic-gate */ 8427c478bd9Sstevel@tonic-gate int 8437c478bd9Sstevel@tonic-gate http_get_range_request(http_handle_t handle, const char *abs_path, 844cb4c2b01Svh115876 offset_t curpos, offset_t len) 8457c478bd9Sstevel@tonic-gate { 8467c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 8497c478bd9Sstevel@tonic-gate return (-1); 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate if (curpos < 0) { 8527c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 8537c478bd9Sstevel@tonic-gate return (-1); 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate return (http_req(handle, abs_path, HTTP_REQ_TYPE_GET, curpos, len)); 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate /* 8607c478bd9Sstevel@tonic-gate * http_free_respinfo - Free a respinfo structure 8617c478bd9Sstevel@tonic-gate * 8627c478bd9Sstevel@tonic-gate * ret = http_free_respinfo(resp); 8637c478bd9Sstevel@tonic-gate * 8647c478bd9Sstevel@tonic-gate * Arguments: 8657c478bd9Sstevel@tonic-gate * resp - respinfo structure presumably allocated by 8667c478bd9Sstevel@tonic-gate * http_process_headers() or http_process_part_headers() 8677c478bd9Sstevel@tonic-gate * 8687c478bd9Sstevel@tonic-gate * Note that if resp is NULL, then this results in a NOOP. 8697c478bd9Sstevel@tonic-gate * 8707c478bd9Sstevel@tonic-gate */ 8717c478bd9Sstevel@tonic-gate void 8727c478bd9Sstevel@tonic-gate http_free_respinfo(http_respinfo_t *resp) 8737c478bd9Sstevel@tonic-gate { 8747c478bd9Sstevel@tonic-gate if (resp == NULL) { 8757c478bd9Sstevel@tonic-gate return; 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate if (resp->statusmsg != NULL) { 8797c478bd9Sstevel@tonic-gate free(resp->statusmsg); 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate free(resp); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate /* 8857c478bd9Sstevel@tonic-gate * http_process_headers - Read in the header lines from the response 8867c478bd9Sstevel@tonic-gate * 8877c478bd9Sstevel@tonic-gate * ret = http_process_headers(handle, resp); 8887c478bd9Sstevel@tonic-gate * 8897c478bd9Sstevel@tonic-gate * Arguments: 8907c478bd9Sstevel@tonic-gate * handle - Handle associated with the connection where the request 8917c478bd9Sstevel@tonic-gate * was made. 8927c478bd9Sstevel@tonic-gate * resp - Summary information about the response. 8937c478bd9Sstevel@tonic-gate * 8947c478bd9Sstevel@tonic-gate * Returns: 8957c478bd9Sstevel@tonic-gate * 0 - Success 8967c478bd9Sstevel@tonic-gate * < 0 - An error occurred. Specifics of the error can 8977c478bd9Sstevel@tonic-gate * be gotten using http_get_lasterr(). 8987c478bd9Sstevel@tonic-gate * 8997c478bd9Sstevel@tonic-gate * Process the HTTP headers in the response. Check for a valid response 9007c478bd9Sstevel@tonic-gate * status line. Allocate and return response information via the 'resp' 9017c478bd9Sstevel@tonic-gate * argument. Header lines are stored locally, are are returned using calls 9027c478bd9Sstevel@tonic-gate * to http_get_response_header() and http_get_header_value(). 9037c478bd9Sstevel@tonic-gate * 9047c478bd9Sstevel@tonic-gate * Note that the errors will be set in the http_conn_t struct before the 9057c478bd9Sstevel@tonic-gate * function which detected the error returns. 9067c478bd9Sstevel@tonic-gate * 9077c478bd9Sstevel@tonic-gate * Note that if resp is non-NULL, then upon a successful return, information 9087c478bd9Sstevel@tonic-gate * about the status line, the code in the status line and the number of 9097c478bd9Sstevel@tonic-gate * header lines are returned in the http_respinfo_t structure. The caller is 9107c478bd9Sstevel@tonic-gate * responsible for freeing the resources allocated to this structure via 9117c478bd9Sstevel@tonic-gate * http_free_respinfo(). 9127c478bd9Sstevel@tonic-gate * 9137c478bd9Sstevel@tonic-gate * Note that the counters used to read message bodies are initialized here. 9147c478bd9Sstevel@tonic-gate * 9157c478bd9Sstevel@tonic-gate * Calling this function replaces the header information which is 9167c478bd9Sstevel@tonic-gate * queried using http_get_response_header() and http_get_header_value(). 9177c478bd9Sstevel@tonic-gate * Once this function is called, headers read by the previous call 9187c478bd9Sstevel@tonic-gate * to http_process_headers() or http_process_part_headers() is lost. 9197c478bd9Sstevel@tonic-gate */ 9207c478bd9Sstevel@tonic-gate int 9217c478bd9Sstevel@tonic-gate http_process_headers(http_handle_t handle, http_respinfo_t **resp) 9227c478bd9Sstevel@tonic-gate { 9237c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 9247c478bd9Sstevel@tonic-gate http_respinfo_t *lresp; 9257c478bd9Sstevel@tonic-gate char line[MAXHOSTNAMELEN]; 9267c478bd9Sstevel@tonic-gate char *ptr; 9277c478bd9Sstevel@tonic-gate int i; 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate ERR_clear_error(); 9307c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 9317c478bd9Sstevel@tonic-gate return (-1); 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate if (resp != NULL) { 9347c478bd9Sstevel@tonic-gate if ((lresp = malloc(sizeof (http_respinfo_t))) == NULL) { 9357c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 9367c478bd9Sstevel@tonic-gate return (-1); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate bzero(lresp, sizeof (http_respinfo_t)); 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate /* 9437c478bd9Sstevel@tonic-gate * check the response status line, expecting 9447c478bd9Sstevel@tonic-gate * HTTP/1.1 200 OK 9457c478bd9Sstevel@tonic-gate */ 94623a1cceaSRoger A. Faulkner i = getaline(c_id, line, sizeof (line), B_FALSE); 9477c478bd9Sstevel@tonic-gate if (i == 0) { 9487c478bd9Sstevel@tonic-gate if (resp != NULL) { 9497c478bd9Sstevel@tonic-gate *resp = lresp; 9507c478bd9Sstevel@tonic-gate } 9517c478bd9Sstevel@tonic-gate return (0); 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate if (i < 0) { 9557c478bd9Sstevel@tonic-gate /* 9567c478bd9Sstevel@tonic-gate * Cause of I/O error was already put into 9577c478bd9Sstevel@tonic-gate * error stack. This is an additional error. 9587c478bd9Sstevel@tonic-gate */ 9597c478bd9Sstevel@tonic-gate http_free_respinfo(lresp); 9607c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NODATA); 9617c478bd9Sstevel@tonic-gate return (-1); 9627c478bd9Sstevel@tonic-gate } 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate free_response(c_id, B_TRUE); 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate if (verbosemode) 9677c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_VERBOSE, "http_process_headers: %s", line); 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate ptr = line; 9707c478bd9Sstevel@tonic-gate if (strncmp(ptr, "HTTP/1.1", 8) != 0) { 9717c478bd9Sstevel@tonic-gate http_free_respinfo(lresp); 9727c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOT_1_1); 9737c478bd9Sstevel@tonic-gate return (-1); 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate /* skip to the code */ 9777c478bd9Sstevel@tonic-gate ptr += 8; 9787c478bd9Sstevel@tonic-gate while (isspace(*ptr)) 9797c478bd9Sstevel@tonic-gate ptr++; 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate /* make sure it's three digits */ 9827c478bd9Sstevel@tonic-gate i = 0; 9837c478bd9Sstevel@tonic-gate while (isdigit(ptr[i])) 9847c478bd9Sstevel@tonic-gate i++; 9857c478bd9Sstevel@tonic-gate if (i != 3) { 9867c478bd9Sstevel@tonic-gate http_free_respinfo(lresp); 9877c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADHDR); 9887c478bd9Sstevel@tonic-gate return (-1); 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate c_id->resp.code = strtol(ptr, NULL, 10); 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate /* skip to the message */ 9937c478bd9Sstevel@tonic-gate ptr += 3; 9947c478bd9Sstevel@tonic-gate while (isspace(*ptr)) 9957c478bd9Sstevel@tonic-gate ptr++; 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate /* save the message */ 9987c478bd9Sstevel@tonic-gate c_id->resp.statusmsg = malloc(strlen(ptr) + 1); 9997c478bd9Sstevel@tonic-gate if (c_id->resp.statusmsg == NULL) { 10007c478bd9Sstevel@tonic-gate http_free_respinfo(lresp); 10017c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 10027c478bd9Sstevel@tonic-gate return (-1); 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate (void) strcpy(c_id->resp.statusmsg, ptr); 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate if ((i = read_headerlines(c_id, B_FALSE)) < 0) { 10077c478bd9Sstevel@tonic-gate /* 10087c478bd9Sstevel@tonic-gate * Error stack was already set at a lower level. 10097c478bd9Sstevel@tonic-gate * 'statusmsg' will be cleaned up next time 10107c478bd9Sstevel@tonic-gate * headers are read. 10117c478bd9Sstevel@tonic-gate */ 10127c478bd9Sstevel@tonic-gate http_free_respinfo(lresp); 10137c478bd9Sstevel@tonic-gate return (-1); 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate /* 10177c478bd9Sstevel@tonic-gate * See if there is a 'content-type: multipart/mixed' line in the 10187c478bd9Sstevel@tonic-gate * headers. If so, get the boundary string. 10197c478bd9Sstevel@tonic-gate */ 10207c478bd9Sstevel@tonic-gate ptr = http_get_header_value(handle, "Content-Type"); 10217c478bd9Sstevel@tonic-gate if (ptr != NULL) { 10227c478bd9Sstevel@tonic-gate char *ptr2; 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate ptr2 = ptr; 10257c478bd9Sstevel@tonic-gate while (isspace(*ptr2)) 10267c478bd9Sstevel@tonic-gate ptr2 ++; 10277c478bd9Sstevel@tonic-gate if (startswith((const char **)&ptr2, "Multipart/Mixed;")) { 10287c478bd9Sstevel@tonic-gate while (isspace(*ptr2)) 10297c478bd9Sstevel@tonic-gate ptr2 ++; 10307c478bd9Sstevel@tonic-gate if (startswith((const char **)&ptr2, "Boundary=")) { 10317c478bd9Sstevel@tonic-gate if (ptr2[0] == '"') { 10327c478bd9Sstevel@tonic-gate ptr2 ++; 10337c478bd9Sstevel@tonic-gate if (ptr2[strlen(ptr2) - 1] == '"') 10347c478bd9Sstevel@tonic-gate ptr2[strlen(ptr2) - 1] = '\0'; 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate c_id->boundary = strdup(ptr2); 10377c478bd9Sstevel@tonic-gate if (c_id->boundary == NULL) { 10387c478bd9Sstevel@tonic-gate free(ptr); 10397c478bd9Sstevel@tonic-gate http_free_respinfo(lresp); 10407c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, 10417c478bd9Sstevel@tonic-gate EHTTP_NOMEM); 10427c478bd9Sstevel@tonic-gate return (-1); 10437c478bd9Sstevel@tonic-gate } 10447c478bd9Sstevel@tonic-gate c_id->boundary_len = strlen(c_id->boundary); 10457c478bd9Sstevel@tonic-gate c_id->is_multipart = B_TRUE; 10467c478bd9Sstevel@tonic-gate c_id->is_firstpart = B_TRUE; 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate free(ptr); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate /* 10537c478bd9Sstevel@tonic-gate * Initialize the counters used to process message bodies. 10547c478bd9Sstevel@tonic-gate */ 10557c478bd9Sstevel@tonic-gate if (init_bread(c_id) != 0) { 10567c478bd9Sstevel@tonic-gate /* 10577c478bd9Sstevel@tonic-gate * Error stack was already set at a lower level. 10587c478bd9Sstevel@tonic-gate */ 10597c478bd9Sstevel@tonic-gate http_free_respinfo(lresp); 10607c478bd9Sstevel@tonic-gate return (-1); 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate /* Copy fields to the caller's structure */ 10647c478bd9Sstevel@tonic-gate if (resp != NULL) { 10657c478bd9Sstevel@tonic-gate lresp->code = c_id->resp.code; 10667c478bd9Sstevel@tonic-gate lresp->nresphdrs = c_id->resp.nresphdrs; 10677c478bd9Sstevel@tonic-gate lresp->statusmsg = strdup(c_id->resp.statusmsg); 10687c478bd9Sstevel@tonic-gate if (lresp->statusmsg == NULL) { 10697c478bd9Sstevel@tonic-gate http_free_respinfo(lresp); 10707c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 10717c478bd9Sstevel@tonic-gate return (-1); 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate *resp = lresp; 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate return (0); 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate /* 10807c478bd9Sstevel@tonic-gate * http_process_part_headers - Read in part boundary and header lines for the 10817c478bd9Sstevel@tonic-gate * next part of a multipart message. 10827c478bd9Sstevel@tonic-gate * 10837c478bd9Sstevel@tonic-gate * ret = http_process_part_headers(handle, resp); 10847c478bd9Sstevel@tonic-gate * 10857c478bd9Sstevel@tonic-gate * Arguments: 10867c478bd9Sstevel@tonic-gate * handle - Handle associated with the connection where the request 10877c478bd9Sstevel@tonic-gate * was made. 10887c478bd9Sstevel@tonic-gate * resp - Return address for summary information about the 10897c478bd9Sstevel@tonic-gate * header block. 10907c478bd9Sstevel@tonic-gate * 10917c478bd9Sstevel@tonic-gate * Returns: 10927c478bd9Sstevel@tonic-gate * = 1 - The end part was found. 10937c478bd9Sstevel@tonic-gate * = 0 - Success, with header info returned in 'resp' 10947c478bd9Sstevel@tonic-gate * = -1 - An error occurred. Specifics of the error can 10957c478bd9Sstevel@tonic-gate * be gotten using http_get_lasterr(). 10967c478bd9Sstevel@tonic-gate * 10977c478bd9Sstevel@tonic-gate * This function reads any \r\n sequences (empty lines) and expects to get 10987c478bd9Sstevel@tonic-gate * a boundary line as the next non-empty line. It then reads header lines 10997c478bd9Sstevel@tonic-gate * (content-length, etc) until it gets another empty lines, which ends the 11007c478bd9Sstevel@tonic-gate * header section. 11017c478bd9Sstevel@tonic-gate * 11027c478bd9Sstevel@tonic-gate * Note that if resp is non-NULL, then upon a successful return, information 11037c478bd9Sstevel@tonic-gate * about the the number of header lines is returned in the http_respinfo_t 11047c478bd9Sstevel@tonic-gate * structure. The caller is responsible for freeing the resources allocated 11057c478bd9Sstevel@tonic-gate * to this structure via http_free_respinfo(). 11067c478bd9Sstevel@tonic-gate * 11077c478bd9Sstevel@tonic-gate * Headers values can be returned using http_get_response_header() and 11087c478bd9Sstevel@tonic-gate * http_get_header_value(). 11097c478bd9Sstevel@tonic-gate * 11107c478bd9Sstevel@tonic-gate * Calling this function replaces the header information which is 11117c478bd9Sstevel@tonic-gate * queried using http_get_response_header() and http_get_header_value(). 11127c478bd9Sstevel@tonic-gate * Once this function is called, information returned by the previous call 11137c478bd9Sstevel@tonic-gate * to http_process_headers() or http_process_part_headers() is gone. 11147c478bd9Sstevel@tonic-gate */ 11157c478bd9Sstevel@tonic-gate int 11167c478bd9Sstevel@tonic-gate http_process_part_headers(http_handle_t handle, http_respinfo_t **resp) 11177c478bd9Sstevel@tonic-gate { 11187c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 11197c478bd9Sstevel@tonic-gate char line[MAXHOSTNAMELEN]; 11207c478bd9Sstevel@tonic-gate int count; 11217c478bd9Sstevel@tonic-gate int limit; 11227c478bd9Sstevel@tonic-gate int i; 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate ERR_clear_error(); 11257c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 11267c478bd9Sstevel@tonic-gate return (-1); 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate if (c_id->is_multipart == 0) { 11297c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOTMULTI); 11307c478bd9Sstevel@tonic-gate return (-1); 11317c478bd9Sstevel@tonic-gate } 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate /* 11347c478bd9Sstevel@tonic-gate * Figure out how many empty lines to allow. Before the first 11357c478bd9Sstevel@tonic-gate * boundary of the transmission, there can be any number of 11367c478bd9Sstevel@tonic-gate * empty lines (from 0 up). Limit these to some reasonable 11377c478bd9Sstevel@tonic-gate * failsafe. 11387c478bd9Sstevel@tonic-gate * 11397c478bd9Sstevel@tonic-gate * For the 2nd and later boundaries, there is supposed to be 11407c478bd9Sstevel@tonic-gate * one crlf pair. However, many implementations don't require 11417c478bd9Sstevel@tonic-gate * it. So don't require it. 11427c478bd9Sstevel@tonic-gate */ 11437c478bd9Sstevel@tonic-gate if (c_id->is_firstpart) { 11447c478bd9Sstevel@tonic-gate limit = FAILSAFE; 11457c478bd9Sstevel@tonic-gate c_id->is_firstpart = B_FALSE; 11467c478bd9Sstevel@tonic-gate } else 11477c478bd9Sstevel@tonic-gate limit = 1; 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate /* Look for the boundary line. */ 11507c478bd9Sstevel@tonic-gate count = 0; 115123a1cceaSRoger A. Faulkner while ((i = getaline(c_id, line, sizeof (line), B_TRUE)) == 0 && 11527c478bd9Sstevel@tonic-gate count < FAILSAFE) 11537c478bd9Sstevel@tonic-gate count ++; 11547c478bd9Sstevel@tonic-gate if (i < 0 || count > limit) { 11557c478bd9Sstevel@tonic-gate /* 11567c478bd9Sstevel@tonic-gate * If I/O error, cause was already put into 11577c478bd9Sstevel@tonic-gate * error stack. This is an additional error. 11587c478bd9Sstevel@tonic-gate */ 11597c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOBOUNDARY); 11607c478bd9Sstevel@tonic-gate return (-1); 11617c478bd9Sstevel@tonic-gate } 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate free_response(c_id, B_FALSE); 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate if (verbosemode) 11667c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_VERBOSE, 11677c478bd9Sstevel@tonic-gate "http_process_part_headers: %s", line); 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate /* Look for boundary line - '--<boundary text> */ 11707c478bd9Sstevel@tonic-gate if (line[0] != '-' || line[1] != '-' || 11717c478bd9Sstevel@tonic-gate strncmp(&line[2], c_id->boundary, c_id->boundary_len) != 0) { 11727c478bd9Sstevel@tonic-gate /* No boundary line.... */ 11737c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOBOUNDARY); 11747c478bd9Sstevel@tonic-gate return (-1); 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate /* Is this the end-of-parts boundary (ends with a trailing '--') */ 11787c478bd9Sstevel@tonic-gate if (strcmp(&line[c_id->boundary_len + 2], "--") == 0) { 11797c478bd9Sstevel@tonic-gate return (1); 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate free_response(c_id, B_FALSE); 11837c478bd9Sstevel@tonic-gate if (read_headerlines(c_id, B_TRUE) < 0) { 11847c478bd9Sstevel@tonic-gate /* Error stack was already set at a lower level. */ 11857c478bd9Sstevel@tonic-gate return (-1); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate /* Copy fields to the caller's structure */ 11897c478bd9Sstevel@tonic-gate if (resp != NULL) { 11907c478bd9Sstevel@tonic-gate if ((*resp = malloc(sizeof (http_respinfo_t))) == NULL) { 11917c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 11927c478bd9Sstevel@tonic-gate return (-1); 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate bzero(*resp, sizeof (http_respinfo_t)); 11957c478bd9Sstevel@tonic-gate (*resp)->code = ' '; 11967c478bd9Sstevel@tonic-gate (*resp)->nresphdrs = c_id->resp.nresphdrs; 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate return (0); 12007c478bd9Sstevel@tonic-gate } 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate /* 12037c478bd9Sstevel@tonic-gate * http_get_response_header - Get a line from the response header 12047c478bd9Sstevel@tonic-gate * 12057c478bd9Sstevel@tonic-gate * ret = http_get_response_header(handle, whichline); 12067c478bd9Sstevel@tonic-gate * 12077c478bd9Sstevel@tonic-gate * Arguments: 12087c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 12097c478bd9Sstevel@tonic-gate * whichline - Which line of the header to return. This must be between 12107c478bd9Sstevel@tonic-gate * zero and resp.nresphdrs which was returned by the call to 12117c478bd9Sstevel@tonic-gate * http_process_headers(). 12127c478bd9Sstevel@tonic-gate * 12137c478bd9Sstevel@tonic-gate * Returns: 12147c478bd9Sstevel@tonic-gate * ptr - Points to a copy of the header line. 12157c478bd9Sstevel@tonic-gate * NULL - An error occurred. Check http_get_lasterr(). 12167c478bd9Sstevel@tonic-gate */ 12177c478bd9Sstevel@tonic-gate char * 12187c478bd9Sstevel@tonic-gate http_get_response_header(http_handle_t handle, uint_t which) 12197c478bd9Sstevel@tonic-gate { 12207c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 12217c478bd9Sstevel@tonic-gate char *res; 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 12247c478bd9Sstevel@tonic-gate return (NULL); 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate if (which >= c_id->resp.nresphdrs) { 12277c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_OORANGE); 12287c478bd9Sstevel@tonic-gate return (NULL); 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate res = strdup(c_id->resphdr[which]); 12327c478bd9Sstevel@tonic-gate if (res == NULL) { 12337c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 12347c478bd9Sstevel@tonic-gate return (NULL); 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate return (res); 12377c478bd9Sstevel@tonic-gate } 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate /* 12407c478bd9Sstevel@tonic-gate * http_get_header_value - Get the value of a header line. 12417c478bd9Sstevel@tonic-gate * 12427c478bd9Sstevel@tonic-gate * ret = http_get_header_value(handle, what); 12437c478bd9Sstevel@tonic-gate * 12447c478bd9Sstevel@tonic-gate * Arguments: 12457c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 12467c478bd9Sstevel@tonic-gate * what - The field name to look up. 12477c478bd9Sstevel@tonic-gate * 12487c478bd9Sstevel@tonic-gate * Returns: 12497c478bd9Sstevel@tonic-gate * ptr - Points to a copy of the header value. 12507c478bd9Sstevel@tonic-gate * NULL - An error occurred. Check http_get_lasterr(). 12517c478bd9Sstevel@tonic-gate */ 12527c478bd9Sstevel@tonic-gate char * 12537c478bd9Sstevel@tonic-gate http_get_header_value(http_handle_t handle, const char *field_name) 12547c478bd9Sstevel@tonic-gate { 12557c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 12567c478bd9Sstevel@tonic-gate char *ptr; 12577c478bd9Sstevel@tonic-gate char *res; 12587c478bd9Sstevel@tonic-gate int i; 12597c478bd9Sstevel@tonic-gate int n; 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 12627c478bd9Sstevel@tonic-gate return (NULL); 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate if (field_name == NULL || field_name[0] == '\0') { 12657c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 12667c478bd9Sstevel@tonic-gate return (NULL); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate for (i = 0; i < c_id->resp.nresphdrs; i++) { 12707c478bd9Sstevel@tonic-gate ptr = c_id->resphdr[i]; 12717c478bd9Sstevel@tonic-gate n = strlen(field_name); 12727c478bd9Sstevel@tonic-gate if (strncasecmp(field_name, ptr, n) == 0 && ptr[n] == ':') { 12737c478bd9Sstevel@tonic-gate ptr += n + 1; 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate while (isspace(*ptr)) 12767c478bd9Sstevel@tonic-gate ptr++; 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate res = strdup(ptr); 12797c478bd9Sstevel@tonic-gate if (res == NULL) { 12807c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 12817c478bd9Sstevel@tonic-gate return (NULL); 12827c478bd9Sstevel@tonic-gate } 12837c478bd9Sstevel@tonic-gate return (res); 12847c478bd9Sstevel@tonic-gate } 12857c478bd9Sstevel@tonic-gate } 12867c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMATCH); 12877c478bd9Sstevel@tonic-gate return (NULL); 12887c478bd9Sstevel@tonic-gate } 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate /* 12917c478bd9Sstevel@tonic-gate * http_read_body - Read the HTTP response body. 12927c478bd9Sstevel@tonic-gate * 12937c478bd9Sstevel@tonic-gate * ret = http_read_body(handle, recv_buf_ptr, recv_buf_size); 12947c478bd9Sstevel@tonic-gate * 12957c478bd9Sstevel@tonic-gate * Arguments: 12967c478bd9Sstevel@tonic-gate * handle - Handle associated with the relevant connection 12977c478bd9Sstevel@tonic-gate * recv_buf_ptr - Points to buffer to receive buffer 12987c478bd9Sstevel@tonic-gate * recv_buf_size - Length in bytes of buffer. 12997c478bd9Sstevel@tonic-gate * 13007c478bd9Sstevel@tonic-gate * Returns: 13017c478bd9Sstevel@tonic-gate * n - Number of bytes read.. 13027c478bd9Sstevel@tonic-gate * < 0 - An error occurred. This is (the number of bytes gotten + 1), 13037c478bd9Sstevel@tonic-gate * negated. In other words, if 'n' bytes were read and then an 13047c478bd9Sstevel@tonic-gate * error occurred, this will return (-(n+1)). So zero bytes 13057c478bd9Sstevel@tonic-gate * were read and then an error occurs, this will return -1. If 13067c478bd9Sstevel@tonic-gate * 1 byte was read, it will return -2, etc. Specifics of the 13077c478bd9Sstevel@tonic-gate * error can be gotten using http_get_lasterr(). 13087c478bd9Sstevel@tonic-gate * 13097c478bd9Sstevel@tonic-gate * Note that the errors will be set in the http_conn_t struct before the 13107c478bd9Sstevel@tonic-gate * function which detected the error returns. 13117c478bd9Sstevel@tonic-gate */ 13127c478bd9Sstevel@tonic-gate int 13137c478bd9Sstevel@tonic-gate http_read_body(http_handle_t handle, char *recv_buf_ptr, size_t recv_buf_size) 13147c478bd9Sstevel@tonic-gate { 13157c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate ERR_clear_error(); 13187c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 13197c478bd9Sstevel@tonic-gate return (-1); 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate if (recv_buf_ptr == NULL || recv_buf_size == 0) { 13227c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 13237c478bd9Sstevel@tonic-gate return (-1); 13247c478bd9Sstevel@tonic-gate } 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate return (getbytes(c_id, recv_buf_ptr, recv_buf_size)); 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate /* 13307c478bd9Sstevel@tonic-gate * http_srv_disconnect - Get rid of the connection to the server without 13317c478bd9Sstevel@tonic-gate * freeing the http_conn_t structure. 13327c478bd9Sstevel@tonic-gate * 13337c478bd9Sstevel@tonic-gate * ret = http_srv_disconnect(handle); 13347c478bd9Sstevel@tonic-gate * 13357c478bd9Sstevel@tonic-gate * Arguments: 13367c478bd9Sstevel@tonic-gate * handle - Handle associated with the connection 13377c478bd9Sstevel@tonic-gate * 13387c478bd9Sstevel@tonic-gate * Returns: 13397c478bd9Sstevel@tonic-gate * 0 - Success 13407c478bd9Sstevel@tonic-gate * -1 - An error occurred. Specifics of the error can 13417c478bd9Sstevel@tonic-gate * be gotten using http_get_lasterr(). 13427c478bd9Sstevel@tonic-gate */ 13437c478bd9Sstevel@tonic-gate int 13447c478bd9Sstevel@tonic-gate http_srv_disconnect(http_handle_t handle) 13457c478bd9Sstevel@tonic-gate { 13467c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 13477c478bd9Sstevel@tonic-gate int err_ret; 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate ERR_clear_error(); 13507c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 13517c478bd9Sstevel@tonic-gate return (-1); 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate err_ret = free_ctx_ssl(c_id); 13547c478bd9Sstevel@tonic-gate bzero(&c_id->inbuf, sizeof (c_id->inbuf)); 13557c478bd9Sstevel@tonic-gate free_response(c_id, B_TRUE); 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate return (err_ret); 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate /* 13617c478bd9Sstevel@tonic-gate * http_srv_close - Close the connection and clean up the http_conn_t 13627c478bd9Sstevel@tonic-gate * structure. 13637c478bd9Sstevel@tonic-gate * 13647c478bd9Sstevel@tonic-gate * http_srv_close(handle); 13657c478bd9Sstevel@tonic-gate * 13667c478bd9Sstevel@tonic-gate * Arguments: 13677c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 13687c478bd9Sstevel@tonic-gate * 13697c478bd9Sstevel@tonic-gate * Returns: 13707c478bd9Sstevel@tonic-gate * 0 - Success 13717c478bd9Sstevel@tonic-gate * -1 - An error occurred. Specifics of the error can 13727c478bd9Sstevel@tonic-gate * be gotten using http_get_lasterr(). 13737c478bd9Sstevel@tonic-gate */ 13747c478bd9Sstevel@tonic-gate int 13757c478bd9Sstevel@tonic-gate http_srv_close(http_handle_t handle) 13767c478bd9Sstevel@tonic-gate { 13777c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 13787c478bd9Sstevel@tonic-gate int err_ret = 0; 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 13817c478bd9Sstevel@tonic-gate return (-1); 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate if (c_id->ctx != NULL || c_id->ssl != NULL || c_id->fd != -1) 13847c478bd9Sstevel@tonic-gate err_ret = http_srv_disconnect(handle); 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate free(c_id->basic_auth_userid); 13877c478bd9Sstevel@tonic-gate free(c_id->basic_auth_password); 13887c478bd9Sstevel@tonic-gate free(c_id->resp.statusmsg); 13897c478bd9Sstevel@tonic-gate free(c_id->client_cert_file); 13907c478bd9Sstevel@tonic-gate free(c_id->private_key_file); 13917c478bd9Sstevel@tonic-gate free(c_id->random_file); 13927c478bd9Sstevel@tonic-gate free(c_id->file_password); 13937c478bd9Sstevel@tonic-gate c_id->signature = 0; 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate free(c_id); 13967c478bd9Sstevel@tonic-gate return (err_ret); 13977c478bd9Sstevel@tonic-gate } 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate /* 14007c478bd9Sstevel@tonic-gate * http_get_conn_info - Return current information about the connection 14017c478bd9Sstevel@tonic-gate * 14027c478bd9Sstevel@tonic-gate * err = http_get_conn_info(handle); 14037c478bd9Sstevel@tonic-gate * 14047c478bd9Sstevel@tonic-gate * Arguments: 14057c478bd9Sstevel@tonic-gate * handle - Handle associated with the connection in question 14067c478bd9Sstevel@tonic-gate * 14077c478bd9Sstevel@tonic-gate * Returns: 14087c478bd9Sstevel@tonic-gate * non_NULL- Points to structure 14097c478bd9Sstevel@tonic-gate * NULL - An error exists. Check http_get_lasterr(). 14107c478bd9Sstevel@tonic-gate */ 14117c478bd9Sstevel@tonic-gate http_conninfo_t * 14127c478bd9Sstevel@tonic-gate http_get_conn_info(http_handle_t handle) 14137c478bd9Sstevel@tonic-gate { 14147c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 14157c478bd9Sstevel@tonic-gate http_conninfo_t *info; 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 14187c478bd9Sstevel@tonic-gate return (NULL); 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate info = malloc(sizeof (*info)); 14217c478bd9Sstevel@tonic-gate if (info == NULL) { 14227c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 14237c478bd9Sstevel@tonic-gate return (NULL); 14247c478bd9Sstevel@tonic-gate } 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate bzero(info, sizeof (*info)); 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate info->uri = c_id->uri; 14297c478bd9Sstevel@tonic-gate info->proxy = c_id->proxy; 14307c478bd9Sstevel@tonic-gate info->keepalive = c_id->keepalive; 14317c478bd9Sstevel@tonic-gate info->read_timeout = c_id->read_timeout; 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate return (info); 14347c478bd9Sstevel@tonic-gate } 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate /* 14377c478bd9Sstevel@tonic-gate * http_get_lasterr - Return the next error on the last operation 14387c478bd9Sstevel@tonic-gate * 14397c478bd9Sstevel@tonic-gate * err = http_get_lasterr(handle, errsrc); 14407c478bd9Sstevel@tonic-gate * 14417c478bd9Sstevel@tonic-gate * Arguments: 14427c478bd9Sstevel@tonic-gate * handle - Handle associated with the connection in question 14437c478bd9Sstevel@tonic-gate * If no valid handle exists yet, this can be NULL. 14447c478bd9Sstevel@tonic-gate * However, it must be checked with the very next call. 14457c478bd9Sstevel@tonic-gate * errsrc - Returns the Sources of errors (ERRSRC_* values). 14467c478bd9Sstevel@tonic-gate * 14477c478bd9Sstevel@tonic-gate * Returns: 14487c478bd9Sstevel@tonic-gate * 0 - No error exists 14497c478bd9Sstevel@tonic-gate * <> 0 - The error. 14507c478bd9Sstevel@tonic-gate */ 14517c478bd9Sstevel@tonic-gate ulong_t 14527c478bd9Sstevel@tonic-gate http_get_lasterr(http_handle_t handle, uint_t *errsrc) 14537c478bd9Sstevel@tonic-gate { 14547c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 14557c478bd9Sstevel@tonic-gate ulong_t src; 14567c478bd9Sstevel@tonic-gate ulong_t err; 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate if (c_id == NULL || c_id->signature != HTTP_CONN_INFO) { 14597c478bd9Sstevel@tonic-gate if (errsrc) 14607c478bd9Sstevel@tonic-gate *errsrc = ERRSRC_LIBHTTP; 14617c478bd9Sstevel@tonic-gate err = early_err; 14627c478bd9Sstevel@tonic-gate early_err = 0; 14637c478bd9Sstevel@tonic-gate return (err); 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate GET_ERR(c_id, src, err); 14677c478bd9Sstevel@tonic-gate if (src == 0 && err == 0) { 14687c478bd9Sstevel@tonic-gate if (errsrc) 14697c478bd9Sstevel@tonic-gate *errsrc = ERRSRC_LIBHTTP; 14707c478bd9Sstevel@tonic-gate err = early_err; 14717c478bd9Sstevel@tonic-gate early_err = 0; 14727c478bd9Sstevel@tonic-gate return (err); 14737c478bd9Sstevel@tonic-gate } 14747c478bd9Sstevel@tonic-gate if (errsrc) 14757c478bd9Sstevel@tonic-gate *errsrc = src; 14767c478bd9Sstevel@tonic-gate return (err); 14777c478bd9Sstevel@tonic-gate } 14787c478bd9Sstevel@tonic-gate 14797c478bd9Sstevel@tonic-gate /* 14807c478bd9Sstevel@tonic-gate * http_decode_err - Decode a libssl error 14817c478bd9Sstevel@tonic-gate * 14827c478bd9Sstevel@tonic-gate * err = http_decode_err(err, errlib, errfunc, errcode); 14837c478bd9Sstevel@tonic-gate * 14847c478bd9Sstevel@tonic-gate * Arguments: 14857c478bd9Sstevel@tonic-gate * err - libssl/libcrypto error returned. 14867c478bd9Sstevel@tonic-gate * errlib - returns libssl/libcrypto sublibrary that caused the error 14877c478bd9Sstevel@tonic-gate * errfunc - returns function in that library 14887c478bd9Sstevel@tonic-gate * errcode - returns error code 14897c478bd9Sstevel@tonic-gate * 14907c478bd9Sstevel@tonic-gate * Returns: 14917c478bd9Sstevel@tonic-gate * None other than the above. 14927c478bd9Sstevel@tonic-gate */ 14937c478bd9Sstevel@tonic-gate void 14947c478bd9Sstevel@tonic-gate http_decode_err(ulong_t err, int *errlib, int *errfunc, int *errcode) 14957c478bd9Sstevel@tonic-gate { 14967c478bd9Sstevel@tonic-gate if (errlib) 14977c478bd9Sstevel@tonic-gate *errlib = ERR_GET_LIB(err); 14987c478bd9Sstevel@tonic-gate if (errfunc) 14997c478bd9Sstevel@tonic-gate *errfunc = ERR_GET_FUNC(err); 15007c478bd9Sstevel@tonic-gate if (errcode) 15017c478bd9Sstevel@tonic-gate *errcode = ERR_GET_REASON(err); 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate /* ---------------------- private functions ----------------------- */ 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate /* 15077c478bd9Sstevel@tonic-gate * http_req - Issue http request (either HEAD or GET) 15087c478bd9Sstevel@tonic-gate * 15097c478bd9Sstevel@tonic-gate * ret = http_req(handle, abs_path, reqtype, curpos, len); 15107c478bd9Sstevel@tonic-gate * 15117c478bd9Sstevel@tonic-gate * Arguments: 15127c478bd9Sstevel@tonic-gate * handle - Handle associated with the desired connection 15137c478bd9Sstevel@tonic-gate * abs_path- File name portion of the URI, beginning with a /. Query, 15147c478bd9Sstevel@tonic-gate * segment, etc are allowed. 15157c478bd9Sstevel@tonic-gate * type - HTTP_REQ_TYPE_HEAD or HTTP_REQ_TYPE_GET 15167c478bd9Sstevel@tonic-gate * 15177c478bd9Sstevel@tonic-gate * In the case of GET requests, 15187c478bd9Sstevel@tonic-gate * curpos- -1 - Range not used 15197c478bd9Sstevel@tonic-gate * >=0 - Beginning of range 15207c478bd9Sstevel@tonic-gate * len - 0 - Range ends at the end of the file 15217c478bd9Sstevel@tonic-gate * >0 - Length of range. 15227c478bd9Sstevel@tonic-gate * 15237c478bd9Sstevel@tonic-gate * Returns: 15247c478bd9Sstevel@tonic-gate * 0 - Success 15257c478bd9Sstevel@tonic-gate * -1 - An error occurred. Check http_get_lasterr(). 15267c478bd9Sstevel@tonic-gate */ 15277c478bd9Sstevel@tonic-gate static int 15287c478bd9Sstevel@tonic-gate http_req(http_handle_t handle, const char *abs_path, http_req_t type, 1529cb4c2b01Svh115876 offset_t curpos, offset_t len) 15307c478bd9Sstevel@tonic-gate { 15317c478bd9Sstevel@tonic-gate http_conn_t *c_id = handle; 15327c478bd9Sstevel@tonic-gate char *request; 15337c478bd9Sstevel@tonic-gate char *reqtypename; 15347c478bd9Sstevel@tonic-gate char *newreq; 15357c478bd9Sstevel@tonic-gate int requestlen; 15367c478bd9Sstevel@tonic-gate int retval; 15377c478bd9Sstevel@tonic-gate int j; 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate ERR_clear_error(); 15407c478bd9Sstevel@tonic-gate if (!http_check_conn(c_id)) 15417c478bd9Sstevel@tonic-gate return (-1); 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate if (abs_path == NULL || abs_path[0] == '\0') { 15447c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 15457c478bd9Sstevel@tonic-gate return (-1); 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate /* Determine the name for the request type */ 15497c478bd9Sstevel@tonic-gate switch (type) { 15507c478bd9Sstevel@tonic-gate case HTTP_REQ_TYPE_GET: 15517c478bd9Sstevel@tonic-gate reqtypename = "GET"; 15527c478bd9Sstevel@tonic-gate if (curpos < 0 && curpos != -1) { 15537c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 15547c478bd9Sstevel@tonic-gate return (-1); 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate break; 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate case HTTP_REQ_TYPE_HEAD: 15597c478bd9Sstevel@tonic-gate reqtypename = "HEAD"; 15607c478bd9Sstevel@tonic-gate break; 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate default: 15637c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 15647c478bd9Sstevel@tonic-gate return (-1); 15657c478bd9Sstevel@tonic-gate } 15667c478bd9Sstevel@tonic-gate 15677c478bd9Sstevel@tonic-gate /* Do rudimentary checks on the absolute path */ 15687c478bd9Sstevel@tonic-gate if (abs_path == NULL || *abs_path != '/') { 15697c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG); 15707c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, "http_req: invalid file path"); 15717c478bd9Sstevel@tonic-gate if (abs_path != NULL) 15727c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, " %s", abs_path); 15737c478bd9Sstevel@tonic-gate return (-1); 15747c478bd9Sstevel@tonic-gate } 15757c478bd9Sstevel@tonic-gate (void) strlcpy(CONN_ABSPATH, abs_path, MAXHOSTNAMELEN); 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate /* 15787c478bd9Sstevel@tonic-gate * Size the request. 15797c478bd9Sstevel@tonic-gate * 15807c478bd9Sstevel@tonic-gate * With proxy: 15817c478bd9Sstevel@tonic-gate * reqtypename + " http://" + host + ":" + port + path + 15827c478bd9Sstevel@tonic-gate * " HTTP/1.1\r\n" + 15837c478bd9Sstevel@tonic-gate * Without proxy: 15847c478bd9Sstevel@tonic-gate * reqtypename + " " + path + " HTTP/1.1\r\n" + 15857c478bd9Sstevel@tonic-gate */ 15867c478bd9Sstevel@tonic-gate requestlen = strlen(reqtypename) + 8 + strlen(CONN_HOSTNAME) + 1 + 15877c478bd9Sstevel@tonic-gate count_digits(CONN_PORT) + strlen(CONN_ABSPATH) + 11; 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* 15907c478bd9Sstevel@tonic-gate * Plus the rest: 15917c478bd9Sstevel@tonic-gate * "Host: " + targethost + ":" + count_digits(port) + "\r\n" + 15927c478bd9Sstevel@tonic-gate * "Connection: Keep-Alive\r\n" plus trailing "\r\n\0" 15937c478bd9Sstevel@tonic-gate */ 15947c478bd9Sstevel@tonic-gate requestlen += 6 + strlen(CONN_HOSTNAME) + 1 + 15957c478bd9Sstevel@tonic-gate count_digits(CONN_PORT) + 2 + 24 + 3; 15967c478bd9Sstevel@tonic-gate if ((request = malloc(requestlen)) == NULL) { 15977c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 15987c478bd9Sstevel@tonic-gate return (-1); 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate /* The request line */ 16027c478bd9Sstevel@tonic-gate if (c_id->proxied && c_id->ssl == NULL) { 16037c478bd9Sstevel@tonic-gate j = snprintf(request, requestlen, 16047c478bd9Sstevel@tonic-gate "%s http://%s:%d%s HTTP/1.1\r\n", 16057c478bd9Sstevel@tonic-gate reqtypename, CONN_HOSTNAME, CONN_PORT, 16067c478bd9Sstevel@tonic-gate CONN_ABSPATH); 16077c478bd9Sstevel@tonic-gate } else { 16087c478bd9Sstevel@tonic-gate j = snprintf(request, requestlen, "%s %s HTTP/1.1\r\n", 16097c478bd9Sstevel@tonic-gate reqtypename, CONN_ABSPATH); 16107c478bd9Sstevel@tonic-gate } 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate /* Ancillary headers */ 16137c478bd9Sstevel@tonic-gate j += snprintf(&request[j], requestlen - j, "Host: %s:%d\r\n", 16147c478bd9Sstevel@tonic-gate CONN_HOSTNAME, CONN_PORT); 16157c478bd9Sstevel@tonic-gate if (!c_id->keepalive) 16167c478bd9Sstevel@tonic-gate j += snprintf(&request[j], requestlen - j, 16177c478bd9Sstevel@tonic-gate "Connection: close\r\n"); 16187c478bd9Sstevel@tonic-gate else 16197c478bd9Sstevel@tonic-gate j += snprintf(&request[j], requestlen - j, 16207c478bd9Sstevel@tonic-gate "Connection: Keep-Alive\r\n"); 16217c478bd9Sstevel@tonic-gate /* 16227c478bd9Sstevel@tonic-gate * We only send the range header on GET requests 16237c478bd9Sstevel@tonic-gate * 16247c478bd9Sstevel@tonic-gate * "Range: bytes=" + from + "-" + end + "\r\n" or 16257c478bd9Sstevel@tonic-gate * "Range: bytes=" + from + "-" "\r\n" 16267c478bd9Sstevel@tonic-gate */ 16277c478bd9Sstevel@tonic-gate if (type == HTTP_REQ_TYPE_GET && curpos >= 0) { 1628cb4c2b01Svh115876 offset_t endpos; 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate requestlen += 13 + count_digits(curpos) + 1 + 2; 16317c478bd9Sstevel@tonic-gate if (len > 0) { 16327c478bd9Sstevel@tonic-gate endpos = curpos + len - 1; 16337c478bd9Sstevel@tonic-gate requestlen += count_digits(endpos); 16347c478bd9Sstevel@tonic-gate } 16357c478bd9Sstevel@tonic-gate 16367c478bd9Sstevel@tonic-gate if ((newreq = realloc(request, requestlen)) == NULL) { 16377c478bd9Sstevel@tonic-gate free(request); 16387c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 16397c478bd9Sstevel@tonic-gate return (-1); 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate request = newreq; 16427c478bd9Sstevel@tonic-gate 1643e00d7246Svh115876 j += sprintf(&request[j], "Range: bytes=%lld-", curpos); 16447c478bd9Sstevel@tonic-gate if (len > 0) 1645e00d7246Svh115876 j += sprintf(&request[j], "%lld", endpos); 16467c478bd9Sstevel@tonic-gate j += sprintf(&request[j], "\r\n"); 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate /* 16507c478bd9Sstevel@tonic-gate * Authorization is added only if provided (RFC 2617, Section 2) 16517c478bd9Sstevel@tonic-gate * 16527c478bd9Sstevel@tonic-gate * "Authorization: Basic " + authencstr + "\r\n" 16537c478bd9Sstevel@tonic-gate */ 16547c478bd9Sstevel@tonic-gate if (c_id->basic_auth_userid && c_id->basic_auth_password) { 16557c478bd9Sstevel@tonic-gate char *authstr; 16567c478bd9Sstevel@tonic-gate char *authencstr; 16577c478bd9Sstevel@tonic-gate int authlen; 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate /* 16607c478bd9Sstevel@tonic-gate * Allow for concat(basic_auth_userid ":" basic_auth_password) 16617c478bd9Sstevel@tonic-gate */ 16627c478bd9Sstevel@tonic-gate authlen = strlen(c_id->basic_auth_userid) + 2 + 16637c478bd9Sstevel@tonic-gate strlen(c_id->basic_auth_password); 16647c478bd9Sstevel@tonic-gate if ((authstr = malloc(authlen + 1)) == NULL) { 16657c478bd9Sstevel@tonic-gate free(request); 16667c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 16677c478bd9Sstevel@tonic-gate return (-1); 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate (void) snprintf(authstr, authlen + 1, "%s:%s", 16707c478bd9Sstevel@tonic-gate c_id->basic_auth_userid, c_id->basic_auth_password); 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate /* 3 bytes encoded as 4 (round up) with null termination */ 16737c478bd9Sstevel@tonic-gate if ((authencstr = malloc((authlen + 2) / 3 * 4 + 1)) == NULL) { 16747c478bd9Sstevel@tonic-gate free(authstr); 16757c478bd9Sstevel@tonic-gate free(request); 16767c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 16777c478bd9Sstevel@tonic-gate return (-1); 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate (void) EVP_EncodeBlock((unsigned char *)authencstr, 16817c478bd9Sstevel@tonic-gate (unsigned char *)authstr, authlen); 16827c478bd9Sstevel@tonic-gate 16837c478bd9Sstevel@tonic-gate /* 16847c478bd9Sstevel@tonic-gate * Finally do concat(Authorization: Basic " authencstr "\r\n") 16857c478bd9Sstevel@tonic-gate */ 16867c478bd9Sstevel@tonic-gate requestlen += 21 + strlen(authencstr) + 2; 16877c478bd9Sstevel@tonic-gate if ((newreq = realloc(request, requestlen)) == NULL) { 16887c478bd9Sstevel@tonic-gate free(authencstr); 16897c478bd9Sstevel@tonic-gate free(authstr); 16907c478bd9Sstevel@tonic-gate free(request); 16917c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 16927c478bd9Sstevel@tonic-gate return (-1); 16937c478bd9Sstevel@tonic-gate } 16947c478bd9Sstevel@tonic-gate request = newreq; 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate j += snprintf(&request[j], requestlen - j, 16977c478bd9Sstevel@tonic-gate "Authorization: Basic %s\r\n", authencstr); 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate free(authencstr); 17007c478bd9Sstevel@tonic-gate free(authstr); 17017c478bd9Sstevel@tonic-gate } 17027c478bd9Sstevel@tonic-gate 17037c478bd9Sstevel@tonic-gate j += sprintf(&request[j], "\r\n"); 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate if (verbosemode) 17067c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_VERBOSE, "%s", request); 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate /* send the HTTP request */ 17097c478bd9Sstevel@tonic-gate retval = http_srv_send(c_id, request, j); 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate free(request); 17127c478bd9Sstevel@tonic-gate if (retval != j) { 17137c478bd9Sstevel@tonic-gate /* Assume error in was set by send request. */ 17147c478bd9Sstevel@tonic-gate return (-1); 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate return (0); 17187c478bd9Sstevel@tonic-gate } 17197c478bd9Sstevel@tonic-gate 17207c478bd9Sstevel@tonic-gate /* 17217c478bd9Sstevel@tonic-gate * password_cb - Callback to get private key password and return it 17227c478bd9Sstevel@tonic-gate * to SSL. (Used for PEM certificates only.) 17237c478bd9Sstevel@tonic-gate * 17247c478bd9Sstevel@tonic-gate * len = passwd_cb(buf, buflen, rwflag, userdata); 17257c478bd9Sstevel@tonic-gate * 17267c478bd9Sstevel@tonic-gate * Arguments: 17277c478bd9Sstevel@tonic-gate * buf - Buffer for the password 17287c478bd9Sstevel@tonic-gate * buflen - Length of 'buf' 17297c478bd9Sstevel@tonic-gate * rwflag - password will be used for reading/decryption (== 0) 17307c478bd9Sstevel@tonic-gate * or writing/encryption (== 1). 17317c478bd9Sstevel@tonic-gate * userdata - Points to connection-specific information. 17327c478bd9Sstevel@tonic-gate * 17337c478bd9Sstevel@tonic-gate * Returns: 17347c478bd9Sstevel@tonic-gate * > 0 - Length of password that was put into 'buf'. 17357c478bd9Sstevel@tonic-gate * 0 - No password was returned (usually error occurred) 17367c478bd9Sstevel@tonic-gate * 17377c478bd9Sstevel@tonic-gate * NOTE: The password code is not thread safe 17387c478bd9Sstevel@tonic-gate */ 17397c478bd9Sstevel@tonic-gate /* ARGSUSED */ 17407c478bd9Sstevel@tonic-gate static int 17417c478bd9Sstevel@tonic-gate password_cb(char *buf, int buflen, int rwflag, void *userdata) 17427c478bd9Sstevel@tonic-gate { 17437c478bd9Sstevel@tonic-gate http_conn_t *c_id = userdata; 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate if (c_id == NULL || c_id->signature != HTTP_CONN_INFO) 17467c478bd9Sstevel@tonic-gate return (0); 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate if (c_id->file_password == NULL || 17497c478bd9Sstevel@tonic-gate buflen < strlen(c_id->file_password) + 1) 17507c478bd9Sstevel@tonic-gate return (0); 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate return (strlcpy(buf, c_id->file_password, buflen)); 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate /* 17567c478bd9Sstevel@tonic-gate * initialize_ctx - Initialize the context for a connection. 17577c478bd9Sstevel@tonic-gate * 17587c478bd9Sstevel@tonic-gate * ctx = initialize_ctx(c_id); 17597c478bd9Sstevel@tonic-gate * 17607c478bd9Sstevel@tonic-gate * Arguments: 17617c478bd9Sstevel@tonic-gate * None. 17627c478bd9Sstevel@tonic-gate * 17637c478bd9Sstevel@tonic-gate * Returns: 17647c478bd9Sstevel@tonic-gate * non-NULL - Points to ctx structure. 17657c478bd9Sstevel@tonic-gate * NULL - An error occurred. Any cleanup is done and error 17667c478bd9Sstevel@tonic-gate * information is in the error stack. 17677c478bd9Sstevel@tonic-gate */ 17687c478bd9Sstevel@tonic-gate static SSL_CTX * 17697c478bd9Sstevel@tonic-gate initialize_ctx(http_conn_t *c_id) 17707c478bd9Sstevel@tonic-gate { 177170f9559bSTheo Schlossnagle #if OPENSSL_VERSION_NUMBER < 0x10000000L 17727c478bd9Sstevel@tonic-gate SSL_METHOD *meth; 177370f9559bSTheo Schlossnagle #else 177470f9559bSTheo Schlossnagle const SSL_METHOD *meth; 177570f9559bSTheo Schlossnagle #endif 17767c478bd9Sstevel@tonic-gate SSL_CTX *ctx; 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate ERR_clear_error(); 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate /* Global system initialization */ 17817c478bd9Sstevel@tonic-gate if (ssl_init == 0) { 17827c478bd9Sstevel@tonic-gate sunw_crypto_init(); 17837c478bd9Sstevel@tonic-gate SSL_load_error_strings(); 17847c478bd9Sstevel@tonic-gate ssl_init = 1; 17857c478bd9Sstevel@tonic-gate } 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate /* Create our context */ 17887c478bd9Sstevel@tonic-gate meth = SSLv3_client_method(); 17897c478bd9Sstevel@tonic-gate if ((ctx = SSL_CTX_new(meth)) == NULL) { 17907c478bd9Sstevel@tonic-gate ulong_t err; 17917c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 17927c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 17937c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 17947c478bd9Sstevel@tonic-gate "initialize_ctx: SSL_CTX_new returned NULL"); 17957c478bd9Sstevel@tonic-gate return (NULL); 17967c478bd9Sstevel@tonic-gate } 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate /* 17997c478bd9Sstevel@tonic-gate * Ensure that any renegotiations for blocking connections will 18007c478bd9Sstevel@tonic-gate * be done automatically. (The alternative is to return partial 18017c478bd9Sstevel@tonic-gate * reads to the caller and let it oversee the renegotiations.) 18027c478bd9Sstevel@tonic-gate */ 18037c478bd9Sstevel@tonic-gate if (SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY) == 0) { 18047c478bd9Sstevel@tonic-gate ulong_t err; 18057c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 18067c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 18077c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 18087c478bd9Sstevel@tonic-gate "initialize_ctx: SSL_CTX_set_mode returned 0"); 18097c478bd9Sstevel@tonic-gate (void) SSL_CTX_free(ctx); 18107c478bd9Sstevel@tonic-gate return (NULL); 18117c478bd9Sstevel@tonic-gate } 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate /* set cipher list if provided */ 18147c478bd9Sstevel@tonic-gate if (cipher_list != NULL) { 18157c478bd9Sstevel@tonic-gate if (!SSL_CTX_set_cipher_list(ctx, cipher_list)) { 18167c478bd9Sstevel@tonic-gate ulong_t err; 18177c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 18187c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 18197c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 18207c478bd9Sstevel@tonic-gate "initialize_ctx: Error in cipher list"); 18217c478bd9Sstevel@tonic-gate SSL_CTX_free(ctx); 18227c478bd9Sstevel@tonic-gate return (NULL); 18237c478bd9Sstevel@tonic-gate } 18247c478bd9Sstevel@tonic-gate } 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate /* 18277c478bd9Sstevel@tonic-gate * We attempt to use the client_certificate_file for the private 18287c478bd9Sstevel@tonic-gate * key input scheme *only* in the absence of private_key_file. In 18297c478bd9Sstevel@tonic-gate * this instance the scheme will be the same as that used for the 18307c478bd9Sstevel@tonic-gate * certificate input. 18317c478bd9Sstevel@tonic-gate */ 18327c478bd9Sstevel@tonic-gate 18337c478bd9Sstevel@tonic-gate /* Load our certificates */ 18347c478bd9Sstevel@tonic-gate if (c_id->client_cert_file != NULL) { 18357c478bd9Sstevel@tonic-gate if (p12_format) { 18367c478bd9Sstevel@tonic-gate /* Load pkcs12-formated files */ 18377c478bd9Sstevel@tonic-gate if (sunw_p12_use_certfile(ctx, c_id->client_cert_file, 18387c478bd9Sstevel@tonic-gate c_id->file_password) 18397c478bd9Sstevel@tonic-gate <= 0) { 18407c478bd9Sstevel@tonic-gate ulong_t err; 18417c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 18427c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 18437c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 18447c478bd9Sstevel@tonic-gate "initialize_ctx: Couldn't read " 18457c478bd9Sstevel@tonic-gate "PKCS12 certificate file"); 18467c478bd9Sstevel@tonic-gate SSL_CTX_free(ctx); 18477c478bd9Sstevel@tonic-gate return (NULL); 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate } else { 18507c478bd9Sstevel@tonic-gate /* Load PEM-formated files */ 18517c478bd9Sstevel@tonic-gate if (SSL_CTX_use_certificate_file(ctx, 18527c478bd9Sstevel@tonic-gate c_id->client_cert_file, SSL_FILETYPE_PEM) <= 0) { 18537c478bd9Sstevel@tonic-gate ulong_t err; 18547c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 18557c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 18567c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 18577c478bd9Sstevel@tonic-gate "initialize_ctx: Couldn't read " 18587c478bd9Sstevel@tonic-gate "PEM certificate file"); 18597c478bd9Sstevel@tonic-gate SSL_CTX_free(ctx); 18607c478bd9Sstevel@tonic-gate return (NULL); 18617c478bd9Sstevel@tonic-gate } 18627c478bd9Sstevel@tonic-gate } 18637c478bd9Sstevel@tonic-gate if (c_id->private_key_file == NULL) 18647c478bd9Sstevel@tonic-gate c_id->private_key_file = c_id->client_cert_file; 18657c478bd9Sstevel@tonic-gate } 18667c478bd9Sstevel@tonic-gate 18677c478bd9Sstevel@tonic-gate /* Load our keys */ 18687c478bd9Sstevel@tonic-gate if (p12_format) { 18697c478bd9Sstevel@tonic-gate /* Load pkcs12-formated files */ 18707c478bd9Sstevel@tonic-gate if (c_id->private_key_file != NULL) { 18717c478bd9Sstevel@tonic-gate if (sunw_p12_use_keyfile(ctx, c_id->private_key_file, 18727c478bd9Sstevel@tonic-gate c_id->file_password) 18737c478bd9Sstevel@tonic-gate <= 0) { 18747c478bd9Sstevel@tonic-gate ulong_t err; 18757c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 18767c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 18777c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 18787c478bd9Sstevel@tonic-gate "initialize_ctx: Couldn't read " 18797c478bd9Sstevel@tonic-gate "PKCS12 key file"); 18807c478bd9Sstevel@tonic-gate SSL_CTX_free(ctx); 18817c478bd9Sstevel@tonic-gate return (NULL); 18827c478bd9Sstevel@tonic-gate } 18837c478bd9Sstevel@tonic-gate } 18847c478bd9Sstevel@tonic-gate } else { 18857c478bd9Sstevel@tonic-gate /* Load PEM-formated files */ 18867c478bd9Sstevel@tonic-gate SSL_CTX_set_default_passwd_cb(ctx, password_cb); 18877c478bd9Sstevel@tonic-gate SSL_CTX_set_default_passwd_cb_userdata(ctx, c_id); 18887c478bd9Sstevel@tonic-gate if (c_id->private_key_file != NULL) { 18897c478bd9Sstevel@tonic-gate if (SSL_CTX_use_PrivateKey_file(ctx, 18907c478bd9Sstevel@tonic-gate c_id->private_key_file, SSL_FILETYPE_PEM) <= 0) { 18917c478bd9Sstevel@tonic-gate ulong_t err; 18927c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 18937c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 18947c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 18957c478bd9Sstevel@tonic-gate "initialize_ctx: Couldn't read " 18967c478bd9Sstevel@tonic-gate "PEM key file"); 18977c478bd9Sstevel@tonic-gate SSL_CTX_free(ctx); 18987c478bd9Sstevel@tonic-gate return (NULL); 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate } 19017c478bd9Sstevel@tonic-gate } 19027c478bd9Sstevel@tonic-gate 19037c478bd9Sstevel@tonic-gate /* Load the CAs we trust */ 19047c478bd9Sstevel@tonic-gate if (ca_verify_file != NULL) { 19057c478bd9Sstevel@tonic-gate if (p12_format) { 19067c478bd9Sstevel@tonic-gate if (sunw_p12_use_trustfile(ctx, ca_verify_file, 19077c478bd9Sstevel@tonic-gate c_id->file_password) 19087c478bd9Sstevel@tonic-gate <= 0) { 19097c478bd9Sstevel@tonic-gate ulong_t err; 19107c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 19117c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 19127c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 19137c478bd9Sstevel@tonic-gate "initialize_ctx: Couldn't read " 19147c478bd9Sstevel@tonic-gate "PKCS12 CA list file"); 19157c478bd9Sstevel@tonic-gate SSL_CTX_free(ctx); 19167c478bd9Sstevel@tonic-gate return (NULL); 19177c478bd9Sstevel@tonic-gate } 19187c478bd9Sstevel@tonic-gate } else { 19197c478bd9Sstevel@tonic-gate if (SSL_CTX_load_verify_locations(ctx, ca_verify_file, 19207c478bd9Sstevel@tonic-gate NULL) == 0) { 19217c478bd9Sstevel@tonic-gate ulong_t err; 19227c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 19237c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 19247c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 19257c478bd9Sstevel@tonic-gate "initialize_ctx: Couldn't read PEM" 19267c478bd9Sstevel@tonic-gate " CA list file"); 19277c478bd9Sstevel@tonic-gate SSL_CTX_free(ctx); 19287c478bd9Sstevel@tonic-gate return (NULL); 19297c478bd9Sstevel@tonic-gate } 19307c478bd9Sstevel@tonic-gate } 19317c478bd9Sstevel@tonic-gate } 19327c478bd9Sstevel@tonic-gate 19337c478bd9Sstevel@tonic-gate SSL_CTX_set_verify_depth(ctx, verify_depth); 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate /* Load randomness */ 19367c478bd9Sstevel@tonic-gate if (c_id->random_file != NULL && 19377c478bd9Sstevel@tonic-gate RAND_load_file(c_id->random_file, 1024 * 1024) <= 0) { 19387c478bd9Sstevel@tonic-gate ulong_t err; 19397c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 19407c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 19417c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 19427c478bd9Sstevel@tonic-gate "initialize_ctx: Couldn't load random file"); 19437c478bd9Sstevel@tonic-gate SSL_CTX_free(ctx); 19447c478bd9Sstevel@tonic-gate return (NULL); 19457c478bd9Sstevel@tonic-gate } 19467c478bd9Sstevel@tonic-gate if (RAND_status() <= 0) { 19477c478bd9Sstevel@tonic-gate ulong_t err; 19487c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 19497c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 19507c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 19517c478bd9Sstevel@tonic-gate "initialize_ctx: PRNG not seeded"); 19527c478bd9Sstevel@tonic-gate SSL_CTX_free(ctx); 19537c478bd9Sstevel@tonic-gate return (NULL); 19547c478bd9Sstevel@tonic-gate } 19557c478bd9Sstevel@tonic-gate 19567c478bd9Sstevel@tonic-gate return (ctx); 19577c478bd9Sstevel@tonic-gate } 19587c478bd9Sstevel@tonic-gate 19597c478bd9Sstevel@tonic-gate /* 19607c478bd9Sstevel@tonic-gate * tcp_connect - Set up a TCP connection. 19617c478bd9Sstevel@tonic-gate * 19627c478bd9Sstevel@tonic-gate * sock = tcp_connect(c_id, hostname, port); 19637c478bd9Sstevel@tonic-gate * 19647c478bd9Sstevel@tonic-gate * Arguments: 19657c478bd9Sstevel@tonic-gate * c_id - Structure associated with the desired connection 19667c478bd9Sstevel@tonic-gate * hostname - the host to connect to 19677c478bd9Sstevel@tonic-gate * port - the port to connect to 19687c478bd9Sstevel@tonic-gate * 19697c478bd9Sstevel@tonic-gate * Returns: 19707c478bd9Sstevel@tonic-gate * >= 0 - Socket number. 19717c478bd9Sstevel@tonic-gate * -1 - Error occurred. Error information is set in the 19727c478bd9Sstevel@tonic-gate * error stack. Any cleanup is done. 19737c478bd9Sstevel@tonic-gate * 19747c478bd9Sstevel@tonic-gate * This function established a connection to the target host. When 19757c478bd9Sstevel@tonic-gate * it returns, the connection is ready for a HEAD or GET request. 19767c478bd9Sstevel@tonic-gate */ 19777c478bd9Sstevel@tonic-gate static int 19787c478bd9Sstevel@tonic-gate tcp_connect(http_conn_t *c_id, const char *hostname, uint16_t port) 19797c478bd9Sstevel@tonic-gate { 19807c478bd9Sstevel@tonic-gate struct hostent *hp; 19817c478bd9Sstevel@tonic-gate struct sockaddr_in addr; 19827c478bd9Sstevel@tonic-gate int sock; 19837c478bd9Sstevel@tonic-gate int status; 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate if ((hp = gethostbyname(hostname)) == NULL) { 19867c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_RESOLVE, h_errno); 19877c478bd9Sstevel@tonic-gate return (-1); 19887c478bd9Sstevel@tonic-gate } 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate bzero(&addr, sizeof (addr)); 19917c478bd9Sstevel@tonic-gate /* LINTED */ 19927c478bd9Sstevel@tonic-gate addr.sin_addr = *(struct in_addr *)hp->h_addr; 19937c478bd9Sstevel@tonic-gate addr.sin_family = AF_INET; 19947c478bd9Sstevel@tonic-gate addr.sin_port = htons(port); 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 19977c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_SYSTEM, errno); 19987c478bd9Sstevel@tonic-gate return (-1); 19997c478bd9Sstevel@tonic-gate } 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate status = connect(sock, (struct sockaddr *)&addr, sizeof (addr)); 20027c478bd9Sstevel@tonic-gate if (status < 0) { 20037c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_SYSTEM, errno); 20047c478bd9Sstevel@tonic-gate (void) socket_close(sock); 20057c478bd9Sstevel@tonic-gate return (-1); 20067c478bd9Sstevel@tonic-gate } 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate c_id->host_addr = addr; /* save for future sendto calls */ 20097c478bd9Sstevel@tonic-gate c_id->fd = sock; 20107c478bd9Sstevel@tonic-gate 20117c478bd9Sstevel@tonic-gate return (sock); 20127c478bd9Sstevel@tonic-gate } 20137c478bd9Sstevel@tonic-gate 20147c478bd9Sstevel@tonic-gate /* 20157c478bd9Sstevel@tonic-gate * readline - Get a line from the socket. Discard the end-of-line 20167c478bd9Sstevel@tonic-gate * (CR or CR/LF or LF). 20177c478bd9Sstevel@tonic-gate * 20187c478bd9Sstevel@tonic-gate * ret = readline(c_id, sock, buf, len); 20197c478bd9Sstevel@tonic-gate * 20207c478bd9Sstevel@tonic-gate * Arguments: 20217c478bd9Sstevel@tonic-gate * c_id - Structure associated with the desired connection 20227c478bd9Sstevel@tonic-gate * sock - Socket to read 20237c478bd9Sstevel@tonic-gate * buf - Buffer for the line 20247c478bd9Sstevel@tonic-gate * len - Length of the buffer 20257c478bd9Sstevel@tonic-gate * 20267c478bd9Sstevel@tonic-gate * Returns: 20277c478bd9Sstevel@tonic-gate * 0 - Success. 'buf' contains the line. 20287c478bd9Sstevel@tonic-gate * -1 - Error occurred. Error information is set in the 20297c478bd9Sstevel@tonic-gate * error stack. 20307c478bd9Sstevel@tonic-gate */ 20317c478bd9Sstevel@tonic-gate static int 20327c478bd9Sstevel@tonic-gate readline(http_conn_t *c_id, int sock, char *buf, int len) 20337c478bd9Sstevel@tonic-gate { 20347c478bd9Sstevel@tonic-gate int n, r; 20357c478bd9Sstevel@tonic-gate char *ptr = buf; 20367c478bd9Sstevel@tonic-gate 20377c478bd9Sstevel@tonic-gate for (n = 0; n < len; n++) { 20387c478bd9Sstevel@tonic-gate r = socket_read(sock, ptr, 1, c_id->read_timeout); 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate if (r < 0) { 20417c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_SYSTEM, errno); 20427c478bd9Sstevel@tonic-gate return (-1); 20437c478bd9Sstevel@tonic-gate } else if (r == 0) { 20447c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_WARNING, "Readline: no data"); 20457c478bd9Sstevel@tonic-gate return (0); 20467c478bd9Sstevel@tonic-gate } 20477c478bd9Sstevel@tonic-gate 20487c478bd9Sstevel@tonic-gate if (*ptr == '\n') { 20497c478bd9Sstevel@tonic-gate *ptr = '\0'; 20507c478bd9Sstevel@tonic-gate 20517c478bd9Sstevel@tonic-gate /* Strip off the CR if it's there */ 20527c478bd9Sstevel@tonic-gate if (buf[n-1] == '\r') { 20537c478bd9Sstevel@tonic-gate buf[n-1] = '\0'; 20547c478bd9Sstevel@tonic-gate n--; 20557c478bd9Sstevel@tonic-gate } 20567c478bd9Sstevel@tonic-gate 20577c478bd9Sstevel@tonic-gate return (n); 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate ptr++; 20617c478bd9Sstevel@tonic-gate } 20627c478bd9Sstevel@tonic-gate 20637c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_WARNING, "readline: Buffer too short\n"); 20647c478bd9Sstevel@tonic-gate return (0); 20657c478bd9Sstevel@tonic-gate } 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate /* 20687c478bd9Sstevel@tonic-gate * proxy_connect - Set up a proxied TCP connection to the target host. 20697c478bd9Sstevel@tonic-gate * 20707c478bd9Sstevel@tonic-gate * sock = proxy_connect(c_id); 20717c478bd9Sstevel@tonic-gate * 20727c478bd9Sstevel@tonic-gate * Arguments: 20737c478bd9Sstevel@tonic-gate * c_id - Structure associated with the desired connection 20747c478bd9Sstevel@tonic-gate * 20757c478bd9Sstevel@tonic-gate * Returns: 20767c478bd9Sstevel@tonic-gate * >= 0 - Socket number. 20777c478bd9Sstevel@tonic-gate * -1 - Error occurred. Error information is set in the 20787c478bd9Sstevel@tonic-gate * error stack. Any cleanup is done. 20797c478bd9Sstevel@tonic-gate * 20807c478bd9Sstevel@tonic-gate * This function established a connection to the proxy and then sends 20817c478bd9Sstevel@tonic-gate * the request to connect to the target host. It reads the response 20827c478bd9Sstevel@tonic-gate * (the status line and any headers). When it returns, the connection 20837c478bd9Sstevel@tonic-gate * is ready for a HEAD or GET request. 20847c478bd9Sstevel@tonic-gate */ 20857c478bd9Sstevel@tonic-gate static int 20867c478bd9Sstevel@tonic-gate proxy_connect(http_conn_t *c_id) 20877c478bd9Sstevel@tonic-gate { 20887c478bd9Sstevel@tonic-gate struct sockaddr_in addr; 20897c478bd9Sstevel@tonic-gate int sock; 20907c478bd9Sstevel@tonic-gate char buf[1024]; 20917c478bd9Sstevel@tonic-gate char *ptr; 20927c478bd9Sstevel@tonic-gate int i; 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate if ((sock = tcp_connect(c_id, CONN_PROXY_HOSTNAME, 20957c478bd9Sstevel@tonic-gate CONN_PROXY_PORT)) < 0) { 20967c478bd9Sstevel@tonic-gate return (-1); 20977c478bd9Sstevel@tonic-gate } 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate if (!CONN_HTTPS) { 21007c478bd9Sstevel@tonic-gate return (sock); 21017c478bd9Sstevel@tonic-gate } 21027c478bd9Sstevel@tonic-gate 21037c478bd9Sstevel@tonic-gate /* Now that we're connected, do the proxy request */ 21047c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 21057c478bd9Sstevel@tonic-gate "CONNECT %s:%d HTTP/1.0\r\n\r\n", CONN_HOSTNAME, CONN_PORT); 21067c478bd9Sstevel@tonic-gate 21077c478bd9Sstevel@tonic-gate /* socket_write sets the errors */ 21087c478bd9Sstevel@tonic-gate if (socket_write(sock, buf, strlen(buf), &addr) <= 0) { 21097c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_SYSTEM, errno); 21107c478bd9Sstevel@tonic-gate (void) socket_close(sock); 21117c478bd9Sstevel@tonic-gate return (-1); 21127c478bd9Sstevel@tonic-gate } 21137c478bd9Sstevel@tonic-gate 21147c478bd9Sstevel@tonic-gate /* And read the response */ 21157c478bd9Sstevel@tonic-gate i = readline(c_id, sock, buf, sizeof (buf)); 21167c478bd9Sstevel@tonic-gate if (i <= 0) { 21177c478bd9Sstevel@tonic-gate if (i == 0) 21187c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NORESP); 21197c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 21207c478bd9Sstevel@tonic-gate "proxy_connect: Empty response from proxy"); 21217c478bd9Sstevel@tonic-gate (void) socket_close(sock); 21227c478bd9Sstevel@tonic-gate return (-1); 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate ptr = buf; 21267c478bd9Sstevel@tonic-gate if (strncmp(ptr, "HTTP", 4) != 0) { 21277c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOT_1_1); 21287c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 21297c478bd9Sstevel@tonic-gate "proxy_connect: Unrecognized protocol"); 21307c478bd9Sstevel@tonic-gate (void) socket_close(sock); 21317c478bd9Sstevel@tonic-gate return (-1); 21327c478bd9Sstevel@tonic-gate } 21337c478bd9Sstevel@tonic-gate 21347c478bd9Sstevel@tonic-gate /* skip to the code */ 21357c478bd9Sstevel@tonic-gate ptr += 4; 21367c478bd9Sstevel@tonic-gate while (*ptr != ' ' && *ptr != '\0') 21377c478bd9Sstevel@tonic-gate ptr++; 21387c478bd9Sstevel@tonic-gate while (*ptr == ' ' && *ptr != '\0') 21397c478bd9Sstevel@tonic-gate ptr++; 21407c478bd9Sstevel@tonic-gate 21417c478bd9Sstevel@tonic-gate /* make sure it's three digits */ 21427c478bd9Sstevel@tonic-gate if (strncmp(ptr, "200", 3) != 0) { 21437c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADRESP); 21447c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 21457c478bd9Sstevel@tonic-gate "proxy_connect: Received error from proxy server"); 21467c478bd9Sstevel@tonic-gate (void) socket_close(sock); 21477c478bd9Sstevel@tonic-gate return (-1); 21487c478bd9Sstevel@tonic-gate } 21497c478bd9Sstevel@tonic-gate ptr += 3; 21507c478bd9Sstevel@tonic-gate if (isdigit(*ptr)) { 21517c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADRESP); 21527c478bd9Sstevel@tonic-gate (void) socket_close(sock); 21537c478bd9Sstevel@tonic-gate return (-1); 21547c478bd9Sstevel@tonic-gate } 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate /* Look for the blank line that signals end of proxy header */ 21577c478bd9Sstevel@tonic-gate while ((i = readline(c_id, sock, buf, sizeof (buf))) > 0) 21587c478bd9Sstevel@tonic-gate ; 21597c478bd9Sstevel@tonic-gate 21607c478bd9Sstevel@tonic-gate if (i < 0) { 21617c478bd9Sstevel@tonic-gate (void) socket_close(sock); 21627c478bd9Sstevel@tonic-gate return (-1); 21637c478bd9Sstevel@tonic-gate } 21647c478bd9Sstevel@tonic-gate 21657c478bd9Sstevel@tonic-gate return (sock); 21667c478bd9Sstevel@tonic-gate } 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate /* 21697c478bd9Sstevel@tonic-gate * check_cert_chain - Check if we have a valid certificate chain. 21707c478bd9Sstevel@tonic-gate * 21717c478bd9Sstevel@tonic-gate * ret = check_cert_chain(c_id, host); 21727c478bd9Sstevel@tonic-gate * 21737c478bd9Sstevel@tonic-gate * Arguments: 21747c478bd9Sstevel@tonic-gate * c_id - Connection info. 21757c478bd9Sstevel@tonic-gate * host - Name to compare with the common name in the certificate. 21767c478bd9Sstevel@tonic-gate * 21777c478bd9Sstevel@tonic-gate * Returns: 21787c478bd9Sstevel@tonic-gate * 0 - Certificate chain and common name are both OK. 21797c478bd9Sstevel@tonic-gate * -1 - Certificate chain and/or common name is not valid. 21807c478bd9Sstevel@tonic-gate */ 21817c478bd9Sstevel@tonic-gate static int 21827c478bd9Sstevel@tonic-gate check_cert_chain(http_conn_t *c_id, char *host) 21837c478bd9Sstevel@tonic-gate { 21847c478bd9Sstevel@tonic-gate X509 *peer; 21857c478bd9Sstevel@tonic-gate char peer_CN[256]; 21867c478bd9Sstevel@tonic-gate long verify_err; 21877c478bd9Sstevel@tonic-gate 21887c478bd9Sstevel@tonic-gate if ((verify_err = SSL_get_verify_result(c_id->ssl)) != X509_V_OK) { 21897c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_VERIFERR, verify_err); 21907c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 21917c478bd9Sstevel@tonic-gate "check_cert_chain: Certificate doesn't verify"); 21927c478bd9Sstevel@tonic-gate return (-1); 21937c478bd9Sstevel@tonic-gate } 21947c478bd9Sstevel@tonic-gate 21957c478bd9Sstevel@tonic-gate /* 21967c478bd9Sstevel@tonic-gate * Check the cert chain. The chain length 21977c478bd9Sstevel@tonic-gate * is automatically checked by OpenSSL when we 21987c478bd9Sstevel@tonic-gate * set the verify depth in the ctx 21997c478bd9Sstevel@tonic-gate * 22007c478bd9Sstevel@tonic-gate * All we need to do here is check that the CN 22017c478bd9Sstevel@tonic-gate * matches 22027c478bd9Sstevel@tonic-gate */ 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate /* Check the common name */ 22057c478bd9Sstevel@tonic-gate if ((peer = SSL_get_peer_certificate(c_id->ssl)) == NULL) { 22067c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOCERT); 22077c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 22087c478bd9Sstevel@tonic-gate "check_cert_chain: Peer did not present a certificate"); 22097c478bd9Sstevel@tonic-gate return (-1); 22107c478bd9Sstevel@tonic-gate } 22117c478bd9Sstevel@tonic-gate (void) X509_NAME_get_text_by_NID(X509_get_subject_name(peer), 22127c478bd9Sstevel@tonic-gate NID_commonName, peer_CN, 256); 22137c478bd9Sstevel@tonic-gate 22147c478bd9Sstevel@tonic-gate if (verbosemode) 22157c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_VERBOSE, 22167c478bd9Sstevel@tonic-gate "server cert's peer_CN is %s, host is %s", peer_CN, host); 22177c478bd9Sstevel@tonic-gate 22187c478bd9Sstevel@tonic-gate if (strcasecmp(peer_CN, host)) { 22197c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMATCH); 22207c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 22217c478bd9Sstevel@tonic-gate "check_cert_chain: Common name doesn't match host name"); 22227c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_CRIT, 22237c478bd9Sstevel@tonic-gate "peer_CN = %s, host = %s", peer_CN, host); 22247c478bd9Sstevel@tonic-gate return (-1); 22257c478bd9Sstevel@tonic-gate } 22267c478bd9Sstevel@tonic-gate 22277c478bd9Sstevel@tonic-gate return (0); 22287c478bd9Sstevel@tonic-gate } 22297c478bd9Sstevel@tonic-gate 22307c478bd9Sstevel@tonic-gate /* 22317c478bd9Sstevel@tonic-gate * print_ciphers - Print the list of ciphers for debugging. 22327c478bd9Sstevel@tonic-gate * 22337c478bd9Sstevel@tonic-gate * print_ciphers(ssl); 22347c478bd9Sstevel@tonic-gate * 22357c478bd9Sstevel@tonic-gate * Arguments: 22367c478bd9Sstevel@tonic-gate * ssl - SSL connection. 22377c478bd9Sstevel@tonic-gate * 22387c478bd9Sstevel@tonic-gate * Returns: 22397c478bd9Sstevel@tonic-gate * none 22407c478bd9Sstevel@tonic-gate */ 22417c478bd9Sstevel@tonic-gate static void 22427c478bd9Sstevel@tonic-gate print_ciphers(SSL *ssl) 22437c478bd9Sstevel@tonic-gate { 22447c478bd9Sstevel@tonic-gate SSL_CIPHER *c; 22457c478bd9Sstevel@tonic-gate STACK_OF(SSL_CIPHER) *sk; 22467c478bd9Sstevel@tonic-gate int i; 22477c478bd9Sstevel@tonic-gate const char *name; 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate if (ssl == NULL) 22507c478bd9Sstevel@tonic-gate return; 22517c478bd9Sstevel@tonic-gate 22527c478bd9Sstevel@tonic-gate sk = SSL_get_ciphers(ssl); 22537c478bd9Sstevel@tonic-gate if (sk == NULL) 22547c478bd9Sstevel@tonic-gate return; 22557c478bd9Sstevel@tonic-gate 22567c478bd9Sstevel@tonic-gate for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { 2257*d7141854SRobert Mustacchi /* LINTED */ 22587c478bd9Sstevel@tonic-gate c = sk_SSL_CIPHER_value(sk, i); 22597c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_VERBOSE, "%08lx %s", c->id, c->name); 22607c478bd9Sstevel@tonic-gate } 22617c478bd9Sstevel@tonic-gate name = SSL_get_cipher_name(ssl); 22627c478bd9Sstevel@tonic-gate if (name == NULL) 22637c478bd9Sstevel@tonic-gate name = ""; 22647c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_VERBOSE, "Current cipher = %s", name); 22657c478bd9Sstevel@tonic-gate } 22667c478bd9Sstevel@tonic-gate 22677c478bd9Sstevel@tonic-gate /* 22687c478bd9Sstevel@tonic-gate * read_headerlines - Get the header lines from the server. This reads 22697c478bd9Sstevel@tonic-gate * lines until it gets a empty line indicating end of headers. 22707c478bd9Sstevel@tonic-gate * 22717c478bd9Sstevel@tonic-gate * ret = read_headerlines(c_id); 22727c478bd9Sstevel@tonic-gate * 22737c478bd9Sstevel@tonic-gate * Arguments: 22747c478bd9Sstevel@tonic-gate * c_id - Info about the connection being read. 22757c478bd9Sstevel@tonic-gate * bread - TRUE if the headerlines are part of the message body. 22767c478bd9Sstevel@tonic-gate * 22777c478bd9Sstevel@tonic-gate * Returns: 22787c478bd9Sstevel@tonic-gate * 0 - Header lines were read. 22797c478bd9Sstevel@tonic-gate * -1 - Error occurred. The errors information is already in 22807c478bd9Sstevel@tonic-gate * the error stack. 22817c478bd9Sstevel@tonic-gate * 22827c478bd9Sstevel@tonic-gate * Read the lines. If the current line begins with a space or tab, it is 22837c478bd9Sstevel@tonic-gate * a continuation. Take the new line and append it to the end of the 22847c478bd9Sstevel@tonic-gate * previous line rather than making an entry for another line in 22857c478bd9Sstevel@tonic-gate * c_id->resphdr. 22867c478bd9Sstevel@tonic-gate * 22877c478bd9Sstevel@tonic-gate * Note that I/O errors are put into the error stack by http_srv_recv(), 228823a1cceaSRoger A. Faulkner * which is called by getaline(). 22897c478bd9Sstevel@tonic-gate */ 22907c478bd9Sstevel@tonic-gate static int 22917c478bd9Sstevel@tonic-gate read_headerlines(http_conn_t *c_id, boolean_t bread) 22927c478bd9Sstevel@tonic-gate { 22937c478bd9Sstevel@tonic-gate char line[MAXHOSTNAMELEN]; 22947c478bd9Sstevel@tonic-gate char **new_buf; 22957c478bd9Sstevel@tonic-gate char *ptr; 22967c478bd9Sstevel@tonic-gate int next; 22977c478bd9Sstevel@tonic-gate int cur; 22987c478bd9Sstevel@tonic-gate int n; 22997c478bd9Sstevel@tonic-gate 23007c478bd9Sstevel@tonic-gate /* process headers, stop when we get to an empty line */ 23017c478bd9Sstevel@tonic-gate cur = 0; 23027c478bd9Sstevel@tonic-gate next = 0; 230323a1cceaSRoger A. Faulkner while ((n = getaline(c_id, line, sizeof (line), bread)) > 0) { 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate if (verbosemode) 23067c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_VERBOSE, 23077c478bd9Sstevel@tonic-gate "read_headerlines: %s", line); 23087c478bd9Sstevel@tonic-gate /* 23097c478bd9Sstevel@tonic-gate * See if this is a continuation line (first col is a 23107c478bd9Sstevel@tonic-gate * space or a tab) 23117c478bd9Sstevel@tonic-gate */ 23127c478bd9Sstevel@tonic-gate if (line[0] != ' ' && line[0] != ' ') { 23137c478bd9Sstevel@tonic-gate cur = next; 23147c478bd9Sstevel@tonic-gate next ++; 23157c478bd9Sstevel@tonic-gate new_buf = 23167c478bd9Sstevel@tonic-gate realloc(c_id->resphdr, (cur + 1) * sizeof (void *)); 23177c478bd9Sstevel@tonic-gate if (new_buf == NULL) { 23187c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 23197c478bd9Sstevel@tonic-gate return (-1); 23207c478bd9Sstevel@tonic-gate } 23217c478bd9Sstevel@tonic-gate c_id->resphdr = new_buf; 23227c478bd9Sstevel@tonic-gate 23237c478bd9Sstevel@tonic-gate c_id->resphdr[cur] = strdup(line); 23247c478bd9Sstevel@tonic-gate if (c_id->resphdr[cur] == NULL) { 23257c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 23267c478bd9Sstevel@tonic-gate return (-1); 23277c478bd9Sstevel@tonic-gate } 23287c478bd9Sstevel@tonic-gate } else { 23297c478bd9Sstevel@tonic-gate ptr = line; 23307c478bd9Sstevel@tonic-gate while (isspace(*ptr)) 23317c478bd9Sstevel@tonic-gate ptr ++; 23327c478bd9Sstevel@tonic-gate c_id->resphdr[cur] = realloc(c_id->resphdr[cur], 23337c478bd9Sstevel@tonic-gate strlen(c_id->resphdr[cur]) + strlen(ptr) + 1); 23347c478bd9Sstevel@tonic-gate if (c_id->resphdr[cur] == NULL) { 23357c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM); 23367c478bd9Sstevel@tonic-gate return (-1); 23377c478bd9Sstevel@tonic-gate } 23387c478bd9Sstevel@tonic-gate (void) strcat(c_id->resphdr[cur], ptr); 23397c478bd9Sstevel@tonic-gate } 23407c478bd9Sstevel@tonic-gate ptr = &(c_id->resphdr[cur][strlen(c_id->resphdr[cur]) - 1]); 23417c478bd9Sstevel@tonic-gate while (ptr > c_id->resphdr[cur] && isspace(*ptr)) 23427c478bd9Sstevel@tonic-gate ptr --; 23437c478bd9Sstevel@tonic-gate } 23447c478bd9Sstevel@tonic-gate c_id->resp.nresphdrs = next; 23457c478bd9Sstevel@tonic-gate 23467c478bd9Sstevel@tonic-gate /* Cause of any I/O error was already put into error stack. */ 23477c478bd9Sstevel@tonic-gate return (n >= 0 ? 0 : -1); 23487c478bd9Sstevel@tonic-gate } 23497c478bd9Sstevel@tonic-gate 23507c478bd9Sstevel@tonic-gate static void 23517c478bd9Sstevel@tonic-gate free_response(http_conn_t *c_id, int free_boundary) 23527c478bd9Sstevel@tonic-gate { 23537c478bd9Sstevel@tonic-gate int i; 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate /* free memory from previous calls */ 23567c478bd9Sstevel@tonic-gate if (c_id->resp.statusmsg != NULL) { 23577c478bd9Sstevel@tonic-gate free(c_id->resp.statusmsg); 23587c478bd9Sstevel@tonic-gate c_id->resp.statusmsg = NULL; 23597c478bd9Sstevel@tonic-gate } 23607c478bd9Sstevel@tonic-gate for (i = 0; i < c_id->resp.nresphdrs; i++) { 23617c478bd9Sstevel@tonic-gate free(c_id->resphdr[i]); 23627c478bd9Sstevel@tonic-gate c_id->resphdr[i] = NULL; 23637c478bd9Sstevel@tonic-gate } 23647c478bd9Sstevel@tonic-gate c_id->resp.nresphdrs = 0; 23657c478bd9Sstevel@tonic-gate if (c_id->resphdr != NULL) { 23667c478bd9Sstevel@tonic-gate free(c_id->resphdr); 23677c478bd9Sstevel@tonic-gate c_id->resphdr = NULL; 23687c478bd9Sstevel@tonic-gate } 23697c478bd9Sstevel@tonic-gate 23707c478bd9Sstevel@tonic-gate if (free_boundary && c_id->boundary) { 23717c478bd9Sstevel@tonic-gate free(c_id->boundary); 23727c478bd9Sstevel@tonic-gate c_id->boundary = NULL; 23737c478bd9Sstevel@tonic-gate c_id->is_multipart = B_FALSE; 23747c478bd9Sstevel@tonic-gate } 23757c478bd9Sstevel@tonic-gate } 23767c478bd9Sstevel@tonic-gate 23777c478bd9Sstevel@tonic-gate static int 23787c478bd9Sstevel@tonic-gate free_ctx_ssl(http_conn_t *c_id) 23797c478bd9Sstevel@tonic-gate { 23807c478bd9Sstevel@tonic-gate int err_ret = 0; 23817c478bd9Sstevel@tonic-gate 23827c478bd9Sstevel@tonic-gate if (c_id->ssl != NULL) { 23837c478bd9Sstevel@tonic-gate if (SSL_shutdown(c_id->ssl) <= 0) { 23847c478bd9Sstevel@tonic-gate ulong_t err; 23857c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 23867c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 23877c478bd9Sstevel@tonic-gate err_ret = -1; 23887c478bd9Sstevel@tonic-gate } 23897c478bd9Sstevel@tonic-gate SSL_free(c_id->ssl); 23907c478bd9Sstevel@tonic-gate c_id->ssl = NULL; 23917c478bd9Sstevel@tonic-gate } 23927c478bd9Sstevel@tonic-gate 23937c478bd9Sstevel@tonic-gate if (c_id->fd != -1 && socket_close(c_id->fd) < 0) { 23947c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_SYSTEM, errno); 23957c478bd9Sstevel@tonic-gate err_ret = -1; 23967c478bd9Sstevel@tonic-gate } 23977c478bd9Sstevel@tonic-gate c_id->fd = -1; 23987c478bd9Sstevel@tonic-gate 23997c478bd9Sstevel@tonic-gate if (c_id->ctx != NULL) { 24007c478bd9Sstevel@tonic-gate SSL_CTX_free(c_id->ctx); 24017c478bd9Sstevel@tonic-gate c_id->ctx = NULL; 24027c478bd9Sstevel@tonic-gate } 24037c478bd9Sstevel@tonic-gate 24047c478bd9Sstevel@tonic-gate return (err_ret); 24057c478bd9Sstevel@tonic-gate } 24067c478bd9Sstevel@tonic-gate 24077c478bd9Sstevel@tonic-gate /* 24087c478bd9Sstevel@tonic-gate * get_chunk_header - Get a chunk header line 24097c478bd9Sstevel@tonic-gate * 24107c478bd9Sstevel@tonic-gate * Arguments: 24117c478bd9Sstevel@tonic-gate * c_id - Structure describing the connection in question. 24127c478bd9Sstevel@tonic-gate * 24137c478bd9Sstevel@tonic-gate * Returns: 24147c478bd9Sstevel@tonic-gate * >=0 - Length of next chunk 24157c478bd9Sstevel@tonic-gate * -1 - Error occurred. The error information is in the error stack. 24167c478bd9Sstevel@tonic-gate */ 24177c478bd9Sstevel@tonic-gate static int 24187c478bd9Sstevel@tonic-gate get_chunk_header(http_conn_t *c_id) 24197c478bd9Sstevel@tonic-gate { 24207c478bd9Sstevel@tonic-gate char line[MAXHOSTNAMELEN]; 24217c478bd9Sstevel@tonic-gate char *ptr; 24227c478bd9Sstevel@tonic-gate int value; 24237c478bd9Sstevel@tonic-gate int ok; 24247c478bd9Sstevel@tonic-gate int i; 24257c478bd9Sstevel@tonic-gate 24267c478bd9Sstevel@tonic-gate /* 24277c478bd9Sstevel@tonic-gate * Determine whether an extra crlf pair will precede the 24287c478bd9Sstevel@tonic-gate * chunk header. For the first one, there is no preceding 24297c478bd9Sstevel@tonic-gate * crlf. For later chunks, there is one crlf. 24307c478bd9Sstevel@tonic-gate */ 24317c478bd9Sstevel@tonic-gate if (c_id->is_firstchunk) { 24327c478bd9Sstevel@tonic-gate ok = 1; 24337c478bd9Sstevel@tonic-gate c_id->is_firstchunk = B_FALSE; 24347c478bd9Sstevel@tonic-gate } else { 243523a1cceaSRoger A. Faulkner ok = ((i = getaline(c_id, line, sizeof (line), B_FALSE)) == 0); 24367c478bd9Sstevel@tonic-gate } 24377c478bd9Sstevel@tonic-gate 24387c478bd9Sstevel@tonic-gate if (ok) 243923a1cceaSRoger A. Faulkner i = getaline(c_id, line, sizeof (line), B_FALSE); 24407c478bd9Sstevel@tonic-gate if (!ok || i < 0) { 24417c478bd9Sstevel@tonic-gate /* 24427c478bd9Sstevel@tonic-gate * If I/O error, the Cause was already put into 24437c478bd9Sstevel@tonic-gate * error stack. This is an additional error. 24447c478bd9Sstevel@tonic-gate */ 24457c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOHEADER); 24467c478bd9Sstevel@tonic-gate return (-1); 24477c478bd9Sstevel@tonic-gate } 24487c478bd9Sstevel@tonic-gate 24497c478bd9Sstevel@tonic-gate if (verbosemode) 24507c478bd9Sstevel@tonic-gate libbootlog(BOOTLOG_VERBOSE, "get_chunk_header: <%s>", line); 24517c478bd9Sstevel@tonic-gate 24527c478bd9Sstevel@tonic-gate 24537c478bd9Sstevel@tonic-gate /* 24547c478bd9Sstevel@tonic-gate * The first (and probably only) field in the line is the hex 24557c478bd9Sstevel@tonic-gate * length of the chunk. 24567c478bd9Sstevel@tonic-gate */ 24577c478bd9Sstevel@tonic-gate ptr = line; 24587c478bd9Sstevel@tonic-gate value = 0; 24597c478bd9Sstevel@tonic-gate while (*ptr != '\0' && (i = hexdigit(*ptr)) >= 0) { 24607c478bd9Sstevel@tonic-gate value = (value << 4) + i; 24617c478bd9Sstevel@tonic-gate ptr ++; 24627c478bd9Sstevel@tonic-gate } 24637c478bd9Sstevel@tonic-gate 24647c478bd9Sstevel@tonic-gate return (value); 24657c478bd9Sstevel@tonic-gate } 24667c478bd9Sstevel@tonic-gate 24677c478bd9Sstevel@tonic-gate /* 24687c478bd9Sstevel@tonic-gate * init_bread - Initialize the counters used to read message bodies. 24697c478bd9Sstevel@tonic-gate * 24707c478bd9Sstevel@tonic-gate * Arguments: 24717c478bd9Sstevel@tonic-gate * c_id - Structure describing the connection in question. 24727c478bd9Sstevel@tonic-gate * 24737c478bd9Sstevel@tonic-gate * Returns: 24747c478bd9Sstevel@tonic-gate * 0 - Success 24757c478bd9Sstevel@tonic-gate * -1 - Error occurred. The error information is in the error stack. 24767c478bd9Sstevel@tonic-gate * 24777c478bd9Sstevel@tonic-gate * This routine will determine whether the message body being received is 24787c478bd9Sstevel@tonic-gate * chunked or non-chunked. Once determined, the counters used to read 24797c478bd9Sstevel@tonic-gate * message bodies will be initialized. 24807c478bd9Sstevel@tonic-gate */ 24817c478bd9Sstevel@tonic-gate static int 24827c478bd9Sstevel@tonic-gate init_bread(http_conn_t *c_id) 24837c478bd9Sstevel@tonic-gate { 24847c478bd9Sstevel@tonic-gate char *hdr; 24857c478bd9Sstevel@tonic-gate char *ptr; 24867c478bd9Sstevel@tonic-gate boolean_t sized = B_FALSE; 24877c478bd9Sstevel@tonic-gate 24887c478bd9Sstevel@tonic-gate /* 24897c478bd9Sstevel@tonic-gate * Assume non-chunked reads until proven otherwise. 24907c478bd9Sstevel@tonic-gate */ 24917c478bd9Sstevel@tonic-gate c_id->is_chunked = B_FALSE; 24927c478bd9Sstevel@tonic-gate c_id->is_firstchunk = B_FALSE; 24937c478bd9Sstevel@tonic-gate hdr = http_get_header_value(c_id, "Content-Length"); 24947c478bd9Sstevel@tonic-gate if (hdr != NULL) { 24957c478bd9Sstevel@tonic-gate c_id->body_size = strtol(hdr, NULL, 10); 24967c478bd9Sstevel@tonic-gate if (c_id->body_size == 0 && errno != 0) { 24977c478bd9Sstevel@tonic-gate free(hdr); 24987c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADSIZE); 24997c478bd9Sstevel@tonic-gate return (-1); 25007c478bd9Sstevel@tonic-gate } 25017c478bd9Sstevel@tonic-gate free(hdr); 25027c478bd9Sstevel@tonic-gate sized = B_TRUE; 25037c478bd9Sstevel@tonic-gate } 25047c478bd9Sstevel@tonic-gate 25057c478bd9Sstevel@tonic-gate /* 25067c478bd9Sstevel@tonic-gate * If size was not determined above, then see if this is a 25077c478bd9Sstevel@tonic-gate * chunked message. Keep in mind that the first chunk size is 25087c478bd9Sstevel@tonic-gate * "special". 25097c478bd9Sstevel@tonic-gate */ 25107c478bd9Sstevel@tonic-gate if (!sized) { 25117c478bd9Sstevel@tonic-gate hdr = http_get_header_value(c_id, "Transfer-Encoding"); 25127c478bd9Sstevel@tonic-gate if (hdr != NULL) { 25137c478bd9Sstevel@tonic-gate ptr = eat_ws(hdr); 25147c478bd9Sstevel@tonic-gate if (startswith((const char **)&ptr, "chunked;") || 25157c478bd9Sstevel@tonic-gate strcasecmp(ptr, "chunked") == 0) { 25167c478bd9Sstevel@tonic-gate c_id->is_firstchunk = B_TRUE; 25177c478bd9Sstevel@tonic-gate c_id->is_chunked = B_TRUE; 25187c478bd9Sstevel@tonic-gate } 25197c478bd9Sstevel@tonic-gate free(hdr); 25207c478bd9Sstevel@tonic-gate if (c_id->is_chunked) { 25217c478bd9Sstevel@tonic-gate c_id->body_size = get_chunk_header(c_id); 25227c478bd9Sstevel@tonic-gate if (c_id->body_size == -1) { 25237c478bd9Sstevel@tonic-gate /* 25247c478bd9Sstevel@tonic-gate * Error stack was already set at a 25257c478bd9Sstevel@tonic-gate * lower level. 25267c478bd9Sstevel@tonic-gate */ 25277c478bd9Sstevel@tonic-gate return (-1); 25287c478bd9Sstevel@tonic-gate } 25297c478bd9Sstevel@tonic-gate sized = B_TRUE; 25307c478bd9Sstevel@tonic-gate } 25317c478bd9Sstevel@tonic-gate } 25327c478bd9Sstevel@tonic-gate } 25337c478bd9Sstevel@tonic-gate 25347c478bd9Sstevel@tonic-gate /* 25357c478bd9Sstevel@tonic-gate * Well, isn't this a fine predicament? It wasn't chunked or 25367c478bd9Sstevel@tonic-gate * non-chunked as far as we can tell. 25377c478bd9Sstevel@tonic-gate */ 25387c478bd9Sstevel@tonic-gate if (!sized) { 25397c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADSIZE); 25407c478bd9Sstevel@tonic-gate return (-1); 25417c478bd9Sstevel@tonic-gate } 25427c478bd9Sstevel@tonic-gate 25437c478bd9Sstevel@tonic-gate c_id->body_read = 0; 25447c478bd9Sstevel@tonic-gate c_id->body_size_tot = c_id->body_size; 25457c478bd9Sstevel@tonic-gate c_id->body_read_tot = 0; 25467c478bd9Sstevel@tonic-gate 25477c478bd9Sstevel@tonic-gate return (0); 25487c478bd9Sstevel@tonic-gate } 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate /* 25517c478bd9Sstevel@tonic-gate * get_msgcnt - Get the number of bytes left in the message body or chunk. 25527c478bd9Sstevel@tonic-gate * 25537c478bd9Sstevel@tonic-gate * Arguments: 25547c478bd9Sstevel@tonic-gate * c_id - Structure describing the connection in question. 25557c478bd9Sstevel@tonic-gate * msgcnt - Where to store the message count. 25567c478bd9Sstevel@tonic-gate * 25577c478bd9Sstevel@tonic-gate * Returns: 25587c478bd9Sstevel@tonic-gate * 0 - Success 25597c478bd9Sstevel@tonic-gate * -1 - Error occurred. The error information is in the error stack. 25607c478bd9Sstevel@tonic-gate * 25617c478bd9Sstevel@tonic-gate * Note that if the message being read is not chunked, then the byte count 25627c478bd9Sstevel@tonic-gate * is simply the message size minus the bytes read thus far. In the case of 25637c478bd9Sstevel@tonic-gate * chunked messages, the byte count returned will be the number of bytes 25647c478bd9Sstevel@tonic-gate * left in the chunk. If the current chunk has been exhausted, then this 25657c478bd9Sstevel@tonic-gate * routine will determine the size of the next chunk. When the next chunk 25667c478bd9Sstevel@tonic-gate * size is zero, the message has been read in its entirety. 25677c478bd9Sstevel@tonic-gate */ 25687c478bd9Sstevel@tonic-gate static int 25697c478bd9Sstevel@tonic-gate get_msgcnt(http_conn_t *c_id, ssize_t *msgcnt) 25707c478bd9Sstevel@tonic-gate { 25717c478bd9Sstevel@tonic-gate /* 25727c478bd9Sstevel@tonic-gate * If there are more bytes in the message, then return. 25737c478bd9Sstevel@tonic-gate */ 25747c478bd9Sstevel@tonic-gate *msgcnt = c_id->body_size - c_id->body_read; 25757c478bd9Sstevel@tonic-gate if (*msgcnt != 0) { 25767c478bd9Sstevel@tonic-gate return (0); 25777c478bd9Sstevel@tonic-gate } 25787c478bd9Sstevel@tonic-gate /* 25797c478bd9Sstevel@tonic-gate * If this is not a chunked message and the body has been 25807c478bd9Sstevel@tonic-gate * read, then we're done. 25817c478bd9Sstevel@tonic-gate */ 25827c478bd9Sstevel@tonic-gate if (!c_id->is_chunked) { 25837c478bd9Sstevel@tonic-gate return (0); 25847c478bd9Sstevel@tonic-gate } 25857c478bd9Sstevel@tonic-gate 25867c478bd9Sstevel@tonic-gate /* 25877c478bd9Sstevel@tonic-gate * We're looking at a chunked message whose immediate 25887c478bd9Sstevel@tonic-gate * chunk has been totally processed. See if there is 25897c478bd9Sstevel@tonic-gate * another chunk. 25907c478bd9Sstevel@tonic-gate */ 25917c478bd9Sstevel@tonic-gate c_id->body_size = get_chunk_header(c_id); 25927c478bd9Sstevel@tonic-gate if (c_id->body_size == -1) { 25937c478bd9Sstevel@tonic-gate /* 25947c478bd9Sstevel@tonic-gate * Error stack was already set at a 25957c478bd9Sstevel@tonic-gate * lower level. 25967c478bd9Sstevel@tonic-gate */ 25977c478bd9Sstevel@tonic-gate return (-1); 25987c478bd9Sstevel@tonic-gate } 25997c478bd9Sstevel@tonic-gate 26007c478bd9Sstevel@tonic-gate /* 26017c478bd9Sstevel@tonic-gate * No bytes of this chunk have been processed yet. 26027c478bd9Sstevel@tonic-gate */ 26037c478bd9Sstevel@tonic-gate c_id->body_read = 0; 26047c478bd9Sstevel@tonic-gate 26057c478bd9Sstevel@tonic-gate /* 26067c478bd9Sstevel@tonic-gate * A zero length chunk signals the end of the 26077c478bd9Sstevel@tonic-gate * message body and chunking. 26087c478bd9Sstevel@tonic-gate */ 26097c478bd9Sstevel@tonic-gate if (c_id->body_size == 0) { 26107c478bd9Sstevel@tonic-gate c_id->is_chunked = B_FALSE; 26117c478bd9Sstevel@tonic-gate return (0); 26127c478bd9Sstevel@tonic-gate } 26137c478bd9Sstevel@tonic-gate 26147c478bd9Sstevel@tonic-gate /* 26157c478bd9Sstevel@tonic-gate * There is another chunk. 26167c478bd9Sstevel@tonic-gate */ 26177c478bd9Sstevel@tonic-gate c_id->body_size_tot += c_id->body_size; 26187c478bd9Sstevel@tonic-gate *msgcnt = c_id->body_size - c_id->body_read; 26197c478bd9Sstevel@tonic-gate 26207c478bd9Sstevel@tonic-gate return (0); 26217c478bd9Sstevel@tonic-gate } 26227c478bd9Sstevel@tonic-gate 26237c478bd9Sstevel@tonic-gate /* 262423a1cceaSRoger A. Faulkner * getaline - Get lines of data from the HTTP response, up to 'len' bytes. 26257c478bd9Sstevel@tonic-gate * NOTE: the line will not end with a NULL if all 'len' bytes 26267c478bd9Sstevel@tonic-gate * were read. 26277c478bd9Sstevel@tonic-gate * 26287c478bd9Sstevel@tonic-gate * Arguments: 26297c478bd9Sstevel@tonic-gate * c_id - Structure describing the connection in question. 26307c478bd9Sstevel@tonic-gate * line - Where to store the data. 26317c478bd9Sstevel@tonic-gate * len - Maximum number of bytes in the line. 26327c478bd9Sstevel@tonic-gate * bread - TRUE if the lines are part of the message body. 26337c478bd9Sstevel@tonic-gate * 26347c478bd9Sstevel@tonic-gate * Returns: 26357c478bd9Sstevel@tonic-gate * >=0 - The number of bytes successfully read. 26367c478bd9Sstevel@tonic-gate * <0 - An error occurred. This is (the number of bytes gotten + 1), 26377c478bd9Sstevel@tonic-gate * negated. In other words, if 'n' bytes were read and then an 26387c478bd9Sstevel@tonic-gate * error occurred, this will return (-(n+1)). So zero bytes read 26397c478bd9Sstevel@tonic-gate * and then an error occurs, this will return -1. If 1 bytes 26407c478bd9Sstevel@tonic-gate * was read, it will return -2, etc. 26417c478bd9Sstevel@tonic-gate * 26427c478bd9Sstevel@tonic-gate * Specifics of the error can be gotten using http_get_lasterr(); 26437c478bd9Sstevel@tonic-gate * 26447c478bd9Sstevel@tonic-gate * Note that I/O errors are put into the error stack by http_srv_recv().1 26457c478bd9Sstevel@tonic-gate */ 26467c478bd9Sstevel@tonic-gate static int 264723a1cceaSRoger A. Faulkner getaline(http_conn_t *c_id, char *line, int len, boolean_t bread) 26487c478bd9Sstevel@tonic-gate { 26497c478bd9Sstevel@tonic-gate int i = 0; 26507c478bd9Sstevel@tonic-gate ssize_t msgcnt = 0; 26517c478bd9Sstevel@tonic-gate ssize_t cnt; 26527c478bd9Sstevel@tonic-gate 26537c478bd9Sstevel@tonic-gate while (i < len) { 26547c478bd9Sstevel@tonic-gate /* 26557c478bd9Sstevel@tonic-gate * Special processing required for message body reads. 26567c478bd9Sstevel@tonic-gate */ 26577c478bd9Sstevel@tonic-gate if (bread) { 26587c478bd9Sstevel@tonic-gate /* 26597c478bd9Sstevel@tonic-gate * See if there is another chunk. Obviously, in the 26607c478bd9Sstevel@tonic-gate * case of non-chunked messages, there won't be. 26617c478bd9Sstevel@tonic-gate * But in either case, chunked or not, if msgcnt 26627c478bd9Sstevel@tonic-gate * is still zero after the call to get_msgcnt(), 26637c478bd9Sstevel@tonic-gate * then we're done. 26647c478bd9Sstevel@tonic-gate */ 26657c478bd9Sstevel@tonic-gate if (msgcnt == 0) { 26667c478bd9Sstevel@tonic-gate if (get_msgcnt(c_id, &msgcnt) == -1) { 26677c478bd9Sstevel@tonic-gate return (-(i+1)); 26687c478bd9Sstevel@tonic-gate } 26697c478bd9Sstevel@tonic-gate if (msgcnt == 0) { 26707c478bd9Sstevel@tonic-gate break; 26717c478bd9Sstevel@tonic-gate } 26727c478bd9Sstevel@tonic-gate } 26737c478bd9Sstevel@tonic-gate cnt = MIN(msgcnt, sizeof (c_id->inbuf.buf)); 26747c478bd9Sstevel@tonic-gate } else { 26757c478bd9Sstevel@tonic-gate cnt = sizeof (c_id->inbuf.buf); 26767c478bd9Sstevel@tonic-gate } 26777c478bd9Sstevel@tonic-gate 26787c478bd9Sstevel@tonic-gate /* read more data if buffer empty */ 26797c478bd9Sstevel@tonic-gate if (c_id->inbuf.i == c_id->inbuf.n) { 26807c478bd9Sstevel@tonic-gate c_id->inbuf.i = 0; 26817c478bd9Sstevel@tonic-gate c_id->inbuf.n = http_srv_recv(c_id, c_id->inbuf.buf, 26827c478bd9Sstevel@tonic-gate cnt); 26837c478bd9Sstevel@tonic-gate if (c_id->inbuf.n == 0) { 26847c478bd9Sstevel@tonic-gate return (i); 26857c478bd9Sstevel@tonic-gate } 26867c478bd9Sstevel@tonic-gate if (c_id->inbuf.n < 0) { 26877c478bd9Sstevel@tonic-gate return (-(i+1)); 26887c478bd9Sstevel@tonic-gate } 26897c478bd9Sstevel@tonic-gate } 26907c478bd9Sstevel@tonic-gate /* skip CR */ 26917c478bd9Sstevel@tonic-gate if (c_id->inbuf.buf[c_id->inbuf.i] == '\r') { 26927c478bd9Sstevel@tonic-gate INC_BREAD_CNT(bread, msgcnt); 26937c478bd9Sstevel@tonic-gate c_id->inbuf.i++; 26947c478bd9Sstevel@tonic-gate continue; 26957c478bd9Sstevel@tonic-gate } 26967c478bd9Sstevel@tonic-gate if (c_id->inbuf.buf[c_id->inbuf.i] == '\n') { 26977c478bd9Sstevel@tonic-gate INC_BREAD_CNT(bread, msgcnt); 26987c478bd9Sstevel@tonic-gate c_id->inbuf.i++; 26997c478bd9Sstevel@tonic-gate line[i] = '\0'; 27007c478bd9Sstevel@tonic-gate return (i); 27017c478bd9Sstevel@tonic-gate } 27027c478bd9Sstevel@tonic-gate /* copy buf from internal buffer */ 27037c478bd9Sstevel@tonic-gate INC_BREAD_CNT(bread, msgcnt); 27047c478bd9Sstevel@tonic-gate line[i++] = c_id->inbuf.buf[c_id->inbuf.i++]; 27057c478bd9Sstevel@tonic-gate } 27067c478bd9Sstevel@tonic-gate return (i); 27077c478bd9Sstevel@tonic-gate } 27087c478bd9Sstevel@tonic-gate 27097c478bd9Sstevel@tonic-gate /* 27107c478bd9Sstevel@tonic-gate * getbytes - Get a block from the HTTP response. Used for the HTTP body. 27117c478bd9Sstevel@tonic-gate * 27127c478bd9Sstevel@tonic-gate * Arguments: 27137c478bd9Sstevel@tonic-gate * c_id - Structure describing the connection in question. 27147c478bd9Sstevel@tonic-gate * line - Where to store the data. 27157c478bd9Sstevel@tonic-gate * len - Maximum number of bytes in the block. 27167c478bd9Sstevel@tonic-gate * 27177c478bd9Sstevel@tonic-gate * Returns: 27187c478bd9Sstevel@tonic-gate * >=0 - The number of bytes successfully read. 27197c478bd9Sstevel@tonic-gate * <0 - An error occurred. This is (the number of bytes gotten + 1), 27207c478bd9Sstevel@tonic-gate * negated. In other words, if 'n' bytes were read and then an 27217c478bd9Sstevel@tonic-gate * error occurred, this will return (-(n+1)). So zero bytes read 27227c478bd9Sstevel@tonic-gate * and then an error occurs, this will return -1. If 1 bytes 27237c478bd9Sstevel@tonic-gate * was read, it will return -2, etc. 27247c478bd9Sstevel@tonic-gate * 27257c478bd9Sstevel@tonic-gate * Specifics of the error can be gotten using http_get_lasterr(); 27267c478bd9Sstevel@tonic-gate * 27277c478bd9Sstevel@tonic-gate * Note that all reads performed here assume that a message body is being 27287c478bd9Sstevel@tonic-gate * read. If this changes in the future, then the logic should more closely 272923a1cceaSRoger A. Faulkner * resemble getaline(). 27307c478bd9Sstevel@tonic-gate * 27317c478bd9Sstevel@tonic-gate * Note that I/O errors are put into the error stack by http_srv_recv(). 27327c478bd9Sstevel@tonic-gate */ 27337c478bd9Sstevel@tonic-gate static int 27347c478bd9Sstevel@tonic-gate getbytes(http_conn_t *c_id, char *line, int len) 27357c478bd9Sstevel@tonic-gate { 27367c478bd9Sstevel@tonic-gate int i = 0; 27377c478bd9Sstevel@tonic-gate ssize_t msgcnt = 0; 27387c478bd9Sstevel@tonic-gate ssize_t cnt; 27397c478bd9Sstevel@tonic-gate int nbytes; 27407c478bd9Sstevel@tonic-gate 27417c478bd9Sstevel@tonic-gate while (i < len) { 27427c478bd9Sstevel@tonic-gate /* 27437c478bd9Sstevel@tonic-gate * See if there is another chunk. Obviously, in the 27447c478bd9Sstevel@tonic-gate * case of non-chunked messages, there won't be. 27457c478bd9Sstevel@tonic-gate * But in either case, chunked or not, if msgcnt 27467c478bd9Sstevel@tonic-gate * is still zero after the call to get_msgcnt(), then 27477c478bd9Sstevel@tonic-gate * we're done. 27487c478bd9Sstevel@tonic-gate */ 27497c478bd9Sstevel@tonic-gate if (msgcnt == 0) { 27507c478bd9Sstevel@tonic-gate if (get_msgcnt(c_id, &msgcnt) == -1) { 27517c478bd9Sstevel@tonic-gate return (-(i+1)); 27527c478bd9Sstevel@tonic-gate } 27537c478bd9Sstevel@tonic-gate if (msgcnt == 0) { 27547c478bd9Sstevel@tonic-gate break; 27557c478bd9Sstevel@tonic-gate } 27567c478bd9Sstevel@tonic-gate } 27577c478bd9Sstevel@tonic-gate 27587c478bd9Sstevel@tonic-gate cnt = MIN(msgcnt, len - i); 27597c478bd9Sstevel@tonic-gate 27607c478bd9Sstevel@tonic-gate if (c_id->inbuf.n != c_id->inbuf.i) { 27617c478bd9Sstevel@tonic-gate nbytes = (int)MIN(cnt, c_id->inbuf.n - c_id->inbuf.i); 27627c478bd9Sstevel@tonic-gate (void) memcpy(line, &c_id->inbuf.buf[c_id->inbuf.i], 27637c478bd9Sstevel@tonic-gate nbytes); 27647c478bd9Sstevel@tonic-gate c_id->inbuf.i += nbytes; 27657c478bd9Sstevel@tonic-gate } else { 27667c478bd9Sstevel@tonic-gate nbytes = http_srv_recv(c_id, line, cnt); 27677c478bd9Sstevel@tonic-gate if (nbytes == 0) { 27687c478bd9Sstevel@tonic-gate return (i); 27697c478bd9Sstevel@tonic-gate } 27707c478bd9Sstevel@tonic-gate if (nbytes < 0) { 27717c478bd9Sstevel@tonic-gate return (-(i+1)); 27727c478bd9Sstevel@tonic-gate } 27737c478bd9Sstevel@tonic-gate } 27747c478bd9Sstevel@tonic-gate 27757c478bd9Sstevel@tonic-gate i += nbytes; 27767c478bd9Sstevel@tonic-gate line += nbytes; 27777c478bd9Sstevel@tonic-gate msgcnt -= nbytes; 27787c478bd9Sstevel@tonic-gate c_id->body_read += nbytes; 27797c478bd9Sstevel@tonic-gate c_id->body_read_tot += nbytes; 27807c478bd9Sstevel@tonic-gate } 27817c478bd9Sstevel@tonic-gate 27827c478bd9Sstevel@tonic-gate return (i); 27837c478bd9Sstevel@tonic-gate } 27847c478bd9Sstevel@tonic-gate 27857c478bd9Sstevel@tonic-gate static int 27867c478bd9Sstevel@tonic-gate http_srv_send(http_conn_t *c_id, const void *buf, size_t nbyte) 27877c478bd9Sstevel@tonic-gate { 27887c478bd9Sstevel@tonic-gate int retval; 27897c478bd9Sstevel@tonic-gate 27907c478bd9Sstevel@tonic-gate if (c_id->ssl != NULL) { 27917c478bd9Sstevel@tonic-gate if ((retval = SSL_write(c_id->ssl, buf, nbyte)) <= 0) { 27927c478bd9Sstevel@tonic-gate handle_ssl_error(c_id, retval); 27937c478bd9Sstevel@tonic-gate } 27947c478bd9Sstevel@tonic-gate return (retval); 27957c478bd9Sstevel@tonic-gate } else { 27967c478bd9Sstevel@tonic-gate retval = socket_write(c_id->fd, buf, nbyte, &c_id->host_addr); 27977c478bd9Sstevel@tonic-gate if (retval < 0) { 27987c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_SYSTEM, errno); 27997c478bd9Sstevel@tonic-gate return (-1); 28007c478bd9Sstevel@tonic-gate } 28017c478bd9Sstevel@tonic-gate return (retval); 28027c478bd9Sstevel@tonic-gate } 28037c478bd9Sstevel@tonic-gate } 28047c478bd9Sstevel@tonic-gate 28057c478bd9Sstevel@tonic-gate static int 28067c478bd9Sstevel@tonic-gate http_srv_recv(http_conn_t *c_id, void *buf, size_t nbyte) 28077c478bd9Sstevel@tonic-gate { 28087c478bd9Sstevel@tonic-gate int retval; 28097c478bd9Sstevel@tonic-gate 28107c478bd9Sstevel@tonic-gate if (c_id->ssl != NULL) { 28117c478bd9Sstevel@tonic-gate if ((retval = SSL_read(c_id->ssl, buf, nbyte)) <= 0) { 28127c478bd9Sstevel@tonic-gate handle_ssl_error(c_id, retval); 28137c478bd9Sstevel@tonic-gate } 28147c478bd9Sstevel@tonic-gate return (retval); 28157c478bd9Sstevel@tonic-gate } else { 28167c478bd9Sstevel@tonic-gate retval = socket_read(c_id->fd, buf, nbyte, c_id->read_timeout); 28177c478bd9Sstevel@tonic-gate if (retval < 0) { 28187c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_SYSTEM, errno); 28197c478bd9Sstevel@tonic-gate return (-1); 28207c478bd9Sstevel@tonic-gate } 28217c478bd9Sstevel@tonic-gate return (retval); 28227c478bd9Sstevel@tonic-gate } 28237c478bd9Sstevel@tonic-gate } 28247c478bd9Sstevel@tonic-gate 28257c478bd9Sstevel@tonic-gate static boolean_t 28267c478bd9Sstevel@tonic-gate http_check_conn(http_conn_t *c_id) 28277c478bd9Sstevel@tonic-gate { 28287c478bd9Sstevel@tonic-gate early_err = 0; 28297c478bd9Sstevel@tonic-gate if (c_id == NULL || c_id->signature != HTTP_CONN_INFO) { 28307c478bd9Sstevel@tonic-gate early_err = EHTTP_BADARG; 28317c478bd9Sstevel@tonic-gate return (B_FALSE); 28327c478bd9Sstevel@tonic-gate } 28337c478bd9Sstevel@tonic-gate RESET_ERR(c_id); 28347c478bd9Sstevel@tonic-gate return (B_TRUE); 28357c478bd9Sstevel@tonic-gate } 28367c478bd9Sstevel@tonic-gate 28377c478bd9Sstevel@tonic-gate static void 28387c478bd9Sstevel@tonic-gate handle_ssl_error(http_conn_t *c_id, int retval) 28397c478bd9Sstevel@tonic-gate { 28407c478bd9Sstevel@tonic-gate ulong_t err; 28417c478bd9Sstevel@tonic-gate 28427c478bd9Sstevel@tonic-gate err = SSL_get_error(c_id->ssl, retval); 28437c478bd9Sstevel@tonic-gate 28447c478bd9Sstevel@tonic-gate switch (err) { 28457c478bd9Sstevel@tonic-gate case SSL_ERROR_NONE: 28467c478bd9Sstevel@tonic-gate return; 28477c478bd9Sstevel@tonic-gate 28487c478bd9Sstevel@tonic-gate case SSL_ERROR_ZERO_RETURN: 28497c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_CONCLOSED); 28507c478bd9Sstevel@tonic-gate return; 28517c478bd9Sstevel@tonic-gate 28527c478bd9Sstevel@tonic-gate case SSL_ERROR_WANT_READ: 28537c478bd9Sstevel@tonic-gate case SSL_ERROR_WANT_WRITE: 28547c478bd9Sstevel@tonic-gate case SSL_ERROR_WANT_CONNECT: 28557c478bd9Sstevel@tonic-gate case SSL_ERROR_WANT_X509_LOOKUP: 28567c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_UNEXPECTED); 28577c478bd9Sstevel@tonic-gate return; 28587c478bd9Sstevel@tonic-gate 28597c478bd9Sstevel@tonic-gate case SSL_ERROR_SYSCALL: 28607c478bd9Sstevel@tonic-gate err = ERR_get_error(); 28617c478bd9Sstevel@tonic-gate if (err == 0) 28627c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_EOFERR); 28637c478bd9Sstevel@tonic-gate else if (err == (ulong_t)-1) 28647c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_SYSTEM, errno); 28657c478bd9Sstevel@tonic-gate else { 28667c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 28677c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) 28687c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 28697c478bd9Sstevel@tonic-gate } 28707c478bd9Sstevel@tonic-gate return; 28717c478bd9Sstevel@tonic-gate 28727c478bd9Sstevel@tonic-gate case SSL_ERROR_SSL: 28737c478bd9Sstevel@tonic-gate while ((err = ERR_get_error()) != 0) { 28747c478bd9Sstevel@tonic-gate SET_ERR(c_id, ERRSRC_LIBSSL, err); 28757c478bd9Sstevel@tonic-gate } 28767c478bd9Sstevel@tonic-gate return; 28777c478bd9Sstevel@tonic-gate } 28787c478bd9Sstevel@tonic-gate } 28797c478bd9Sstevel@tonic-gate 28807c478bd9Sstevel@tonic-gate static int 28817c478bd9Sstevel@tonic-gate count_digits(int value) 28827c478bd9Sstevel@tonic-gate { 28837c478bd9Sstevel@tonic-gate int count = 1; 28847c478bd9Sstevel@tonic-gate 28857c478bd9Sstevel@tonic-gate if (value < 0) { 28867c478bd9Sstevel@tonic-gate count++; 28877c478bd9Sstevel@tonic-gate value = -value; 28887c478bd9Sstevel@tonic-gate } 28897c478bd9Sstevel@tonic-gate 28907c478bd9Sstevel@tonic-gate while (value > 9) { 28917c478bd9Sstevel@tonic-gate value /= 10; 28927c478bd9Sstevel@tonic-gate count++; 28937c478bd9Sstevel@tonic-gate } 28947c478bd9Sstevel@tonic-gate return (count); 28957c478bd9Sstevel@tonic-gate } 28967c478bd9Sstevel@tonic-gate 28977c478bd9Sstevel@tonic-gate static int 28987c478bd9Sstevel@tonic-gate hexdigit(char ch) 28997c478bd9Sstevel@tonic-gate { 29007c478bd9Sstevel@tonic-gate if (ch >= '0' && ch <= '9') 29017c478bd9Sstevel@tonic-gate return (ch - '0'); 29027c478bd9Sstevel@tonic-gate if (ch >= 'A' && ch <= 'F') 29037c478bd9Sstevel@tonic-gate return (ch - 'A' + 10); 29047c478bd9Sstevel@tonic-gate if (ch >= 'a' && ch <= 'f') 29057c478bd9Sstevel@tonic-gate return (ch - 'a' + 10); 29067c478bd9Sstevel@tonic-gate return (-1); 29077c478bd9Sstevel@tonic-gate } 29087c478bd9Sstevel@tonic-gate 29097c478bd9Sstevel@tonic-gate static char * 29107c478bd9Sstevel@tonic-gate eat_ws(const char *buf) 29117c478bd9Sstevel@tonic-gate { 29127c478bd9Sstevel@tonic-gate char *ptr = (char *)buf; 29137c478bd9Sstevel@tonic-gate 29147c478bd9Sstevel@tonic-gate while (isspace(*ptr)) 29157c478bd9Sstevel@tonic-gate ptr++; 29167c478bd9Sstevel@tonic-gate 29177c478bd9Sstevel@tonic-gate return (ptr); 29187c478bd9Sstevel@tonic-gate } 29197c478bd9Sstevel@tonic-gate 29207c478bd9Sstevel@tonic-gate static boolean_t 29217c478bd9Sstevel@tonic-gate startswith(const char **strp, const char *starts) 29227c478bd9Sstevel@tonic-gate { 29237c478bd9Sstevel@tonic-gate int len = strlen(starts); 29247c478bd9Sstevel@tonic-gate 29257c478bd9Sstevel@tonic-gate if (strncasecmp(*strp, starts, len) == 0) { 29267c478bd9Sstevel@tonic-gate *strp += len; 29277c478bd9Sstevel@tonic-gate return (B_TRUE); 29287c478bd9Sstevel@tonic-gate } 29297c478bd9Sstevel@tonic-gate return (B_FALSE); 29307c478bd9Sstevel@tonic-gate } 2931