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
http_set_p12_format(int on_off)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 *
http_get_version(void)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
http_set_verbose(boolean_t on_off)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
http_set_cipher_list(const char * list)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
http_srv_init(const url_t * url)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
http_conn_is_https(http_handle_t handle,boolean_t * bool)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
http_set_proxy(http_handle_t handle,const url_hport_t * proxy)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
http_set_keepalive(http_handle_t handle,boolean_t on_off)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
http_set_socket_read_timeout(http_handle_t handle,uint_t timout)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
http_set_basic_auth(http_handle_t handle,const char * userid,const char * password)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
http_set_random_file(http_handle_t handle,const char * fname)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
http_set_certificate_authority_file(const char * fname)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
http_set_client_certificate_file(http_handle_t handle,const char * fname)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
http_set_password(http_handle_t handle,const char * password)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
http_set_key_file_password(http_handle_t handle,const char * password)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
http_set_private_key_file(http_handle_t handle,const char * fname)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
http_srv_connect(http_handle_t handle)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
http_head_request(http_handle_t handle,const char * abs_path)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
http_get_request(http_handle_t handle,const char * abs_path)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
http_get_range_request(http_handle_t handle,const char * abs_path,offset_t curpos,offset_t len)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
http_free_respinfo(http_respinfo_t * resp)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
http_process_headers(http_handle_t handle,http_respinfo_t ** resp)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
http_process_part_headers(http_handle_t handle,http_respinfo_t ** resp)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 *
http_get_response_header(http_handle_t handle,uint_t which)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 *
http_get_header_value(http_handle_t handle,const char * field_name)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
http_read_body(http_handle_t handle,char * recv_buf_ptr,size_t recv_buf_size)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
http_srv_disconnect(http_handle_t handle)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
http_srv_close(http_handle_t handle)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 *
http_get_conn_info(http_handle_t handle)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
http_get_lasterr(http_handle_t handle,uint_t * errsrc)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
http_decode_err(ulong_t err,int * errlib,int * errfunc,int * errcode)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
http_req(http_handle_t handle,const char * abs_path,http_req_t type,offset_t curpos,offset_t len)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
password_cb(char * buf,int buflen,int rwflag,void * userdata)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 *
initialize_ctx(http_conn_t * c_id)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
tcp_connect(http_conn_t * c_id,const char * hostname,uint16_t port)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
readline(http_conn_t * c_id,int sock,char * buf,int len)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
proxy_connect(http_conn_t * c_id)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
check_cert_chain(http_conn_t * c_id,char * host)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
print_ciphers(SSL * ssl)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
read_headerlines(http_conn_t * c_id,boolean_t bread)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
free_response(http_conn_t * c_id,int free_boundary)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
free_ctx_ssl(http_conn_t * c_id)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
get_chunk_header(http_conn_t * c_id)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
init_bread(http_conn_t * c_id)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
get_msgcnt(http_conn_t * c_id,ssize_t * msgcnt)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
getaline(http_conn_t * c_id,char * line,int len,boolean_t bread)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
getbytes(http_conn_t * c_id,char * line,int len)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
http_srv_send(http_conn_t * c_id,const void * buf,size_t nbyte)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
http_srv_recv(http_conn_t * c_id,void * buf,size_t nbyte)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
http_check_conn(http_conn_t * c_id)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
handle_ssl_error(http_conn_t * c_id,int retval)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
count_digits(int value)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
hexdigit(char ch)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 *
eat_ws(const char * buf)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
startswith(const char ** strp,const char * starts)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