8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / common / net / wanboot / boot_http.c
blob213d5e44c6e7d38743654c13231e200eb463fdcc
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <ctype.h>
33 #include <stdio.h>
34 #include <strings.h>
35 #include <stdlib.h>
36 #include <netdb.h>
38 #include <openssl/ssl.h>
39 #include <openssl/err.h>
40 #include <openssl/rand.h>
41 #include <openssl/pkcs12.h>
43 /* this must be included after ssl.h to avoid re-defining 'offsetof' */
44 #include <sys/sysmacros.h>
46 #include <boot_http.h>
47 #include <socket_inet.h>
48 #include <p12access.h>
50 #include "bootlog.h"
52 #define BOOT_HTTP_MAJOR_VERSION 1
53 #define BOOT_HTTP_MINOR_VERSION 0
54 #define BOOT_HTTP_MICRO_VERSION 0
56 static boot_http_ver_t boot_http_ver = {
57 BOOT_HTTP_MAJOR_VERSION,
58 BOOT_HTTP_MINOR_VERSION,
59 BOOT_HTTP_MICRO_VERSION
62 static int early_err; /* Error from before error occurred */
64 static boolean_t verbosemode = B_FALSE;
65 static char *cipher_list = NULL; /* Ciphers supported (if not default) */
67 typedef struct {
68 int i; /* current position in buffer */
69 int n; /* number of bytes in buffer */
70 char buf[512]; /* buffer */
71 } buf_struct_t;
73 typedef struct {
74 uint_t errsrc; /* Source of this error */
75 ulong_t error; /* Which error? */
76 } errent_t;
79 typedef enum {
80 HTTP_REQ_TYPE_HEAD = 1,
81 HTTP_REQ_TYPE_GET
82 } http_req_t;
84 #define FAILSAFE 20 /* Max # empty lines to accept */
85 #define DEFAULT_TIMEOUT 10 /* Default socket read timeout value */
86 #define HTTP_CONN_INFO 0x90919293 /* Identifies a http_conn_t struct */
87 #define ESTACK_SIZE 20 /* Size of the stack */
89 typedef struct http_conn_t {
90 uint_t signature; /* Cookie indicating this is a handle */
91 int fd; /* Connection's fd... */
92 SSL_CTX *ctx;
93 void *ssl; /* Handle to ssl data structure */
94 int read_timeout; /* Timeout to use on read requests in sec */
95 char *basic_auth_userid; /* Basic authentication user ID */
96 char *basic_auth_password; /* and password */
97 char is_multipart; /* B_TRUE if doing multipart/mixed download */
98 char is_firstpart; /* B_TRUE if first part in a multipart xfer */
99 char is_firstchunk; /* B_TRUE if first chunk in chunked xfer */
100 char is_chunked; /* B_TRUE if message body is chunked */
101 boolean_t keepalive;
102 struct sockaddr_in host_addr; /* Address of host */
103 url_t uri; /* The current URI */
104 url_hport_t proxy; /* The proxy info */
105 boolean_t proxied; /* Connection is proxied */
106 char *random_file; /* File with seed info for pseudo random */
107 /* number generator */
108 char *client_cert_file; /* File holding client's certificate */
109 char *private_key_file; /* File with the private key */
110 char *file_password; /* file with password to key or pkcs12 file. */
111 http_respinfo_t resp; /* Response summary info */
112 char **resphdr; /* Array of header response lines */
113 buf_struct_t inbuf;
114 char *boundary; /* Boundary text (multipart downloads only) */
115 uint_t boundary_len; /* Length of boundary string */
116 uint_t numerrs;
117 uint_t nexterr; /* Next error to return */
118 ssize_t body_size; /* Size of message body or chunk */
119 ssize_t body_read; /* # of bytes of body_size processed */
120 ssize_t body_size_tot; /* Total message body size */
121 ssize_t body_read_tot; /* # of bytes of body_size_tot processed */
122 errent_t errs[ESTACK_SIZE]; /* stack of errors on the last request */
123 /* (libssl can return multiple errors on one */
124 /* operation) */
125 } http_conn_t;
128 * Convenient macros for accessing fields in connection structure.
130 #define CONN_HOSTNAME c_id->uri.hport.hostname
131 #define CONN_PORT c_id->uri.hport.port
132 #define CONN_ABSPATH c_id->uri.abspath
133 #define CONN_HTTPS c_id->uri.https
134 #define CONN_PROXY_HOSTNAME c_id->proxy.hostname
135 #define CONN_PROXY_PORT c_id->proxy.port
137 #define RESET_ERR(c_id) (c_id)->numerrs = 0, (c_id)->nexterr = 0
138 #define SET_ERR(c_id, src, err) if ((c_id)->numerrs < ESTACK_SIZE) \
139 (c_id)->errs[(c_id)->numerrs].errsrc = (src), \
140 (c_id)->errs[(c_id)->numerrs ++].error = (err)
142 #define GET_ERR(c_id, e_src, e_code) \
143 if ((c_id)->nexterr < (c_id)->numerrs) \
144 (e_src) = (c_id)->errs[((c_id)->nexterr)].errsrc, \
145 (e_code) = (c_id)->errs[((c_id)->nexterr)++].error; \
146 else \
147 (e_src) = 0, (e_code) = 0
150 * Macro used to increment message body read counters
152 #define INC_BREAD_CNT(bool, bcnt) \
153 if (bool) { \
154 bcnt--; \
155 c_id->body_read++;\
156 c_id->body_read_tot++; \
159 static int ssl_init = 0; /* 1 when ssl has been initialized */
160 static char *ca_verify_file; /* List of trusted CA's */
161 static int verify_depth = 16; /* Certificate chain depth to verify */
162 static int p12_format = 0; /* Default to PEM format */
165 /* prototypes for local functions */
166 static int http_req(http_handle_t, const char *, http_req_t, offset_t,
167 offset_t);
168 static boolean_t http_check_conn(http_conn_t *);
169 static SSL_CTX *initialize_ctx(http_conn_t *);
170 static int tcp_connect(http_conn_t *, const char *, uint16_t);
171 static int readline(http_conn_t *, int, char *, int);
172 static int proxy_connect(http_conn_t *);
173 static int check_cert_chain(http_conn_t *, char *);
174 static void print_ciphers(SSL *);
175 static int read_headerlines(http_conn_t *, boolean_t);
176 static void free_response(http_conn_t *, int);
177 static int free_ctx_ssl(http_conn_t *);
178 static int get_chunk_header(http_conn_t *);
179 static int init_bread(http_conn_t *);
180 static int get_msgcnt(http_conn_t *, ssize_t *);
181 static int getaline(http_conn_t *, char *, int, boolean_t);
182 static int getbytes(http_conn_t *, char *, int);
183 static int http_srv_send(http_conn_t *, const void *, size_t);
184 static int http_srv_recv(http_conn_t *, void *, size_t);
185 static void handle_ssl_error(http_conn_t *, int);
186 static int count_digits(int);
187 static int hexdigit(char);
188 static char *eat_ws(const char *);
189 static boolean_t startswith(const char **strp, const char *starts);
191 /* ---------------------- public functions ----------------------- */
194 * http_set_p12_format - Set flag indicating that certs & keys will be in
195 * pkcs12 format.
197 * Default is PEM certs. When this is called, the default can be changed to
198 * pcs12 format.
200 void
201 http_set_p12_format(int on_off)
203 p12_format = on_off;
207 * http_get_version - Get current boot http support version
209 * pVer = http_get_version();
211 * Arguments:
212 * None.
214 * Returns:
215 * Pointer to struct with version information.
217 * Returns the version of the http support in the current library. This
218 * is a struct with unsigned integsrs for <major>, <minor> and
219 * <micro> version numbers. <major> changes when an incompatible change
220 * is made. <minor> changes when an upwardly-compatible API change is
221 * made. <micro> consists of bug fixes, etc.
223 boot_http_ver_t const *
224 http_get_version(void)
226 return (&boot_http_ver);
230 * http_set_verbose - Turn verbose on/off
232 * http_set_verbose(on_off);
234 * Arguments:
235 * on_off - When TRUE, turn verbose mode one. When FALSE, turn
236 * verbose off.
238 * Returns:
239 * None.
241 * When enabled, information is logged to bootlog (or the Solaris equivalent).
243 void
244 http_set_verbose(boolean_t on_off)
246 verbosemode = on_off;
250 * http_set_cipher_list - Change the list of ciphers that can be used.
252 * ret = http_set_cipher_list(handle, list);
254 * Arguments:
255 * list - List of ciphers that can be used.
257 * Returns:
258 * 0 - Success
259 * -1 - An error occurred. Check http_get_lasterr().
262 http_set_cipher_list(const char *list)
264 early_err = 0;
266 if (list != NULL) {
267 list = strdup(list);
268 if (list == NULL) {
269 early_err = EHTTP_NOMEM;
270 return (-1);
274 free(cipher_list);
275 cipher_list = (char *)list;
276 return (0);
280 * http_srv_init - Set up a structure for a connection.
282 * handle = http_srv_init(url);
284 * Arguments:
285 * url - the structure that contains the URI.
287 * Returns:
288 * != NULL - A handle for referring to this connection.
289 * == NULL - An error occurred. Get the exact error from
290 * http_get_lasterr().
292 http_handle_t
293 http_srv_init(const url_t *url)
295 http_conn_t *c_id;
297 early_err = 0;
298 if (url == NULL) {
299 early_err = EHTTP_BADARG;
300 return (NULL);
303 if ((c_id = malloc(sizeof (*c_id))) == NULL) {
304 early_err = EHTTP_NOMEM;
305 return (NULL);
308 bzero(c_id, sizeof (*c_id));
309 c_id->uri = *url;
310 c_id->proxied = B_FALSE;
311 c_id->read_timeout = DEFAULT_TIMEOUT;
312 c_id->keepalive = B_TRUE;
313 c_id->fd = -1;
315 /* Do this at the end, just in case.... */
316 c_id->signature = HTTP_CONN_INFO;
318 return (c_id);
322 * http_conn_is_https - Determine whether the scheme is http or https.
324 * B_TRUE - Connection is an SSL connection.
325 * B_FALSE - Connection isn't SSL.
327 * ret = http_conn_is_https(handle, boolean_t *bool);
329 * Arguments:
330 * handle - Handle associated with the desired connection
331 * bool - Ptr to boolean in which to place result
333 * Returns:
334 * 0 - Success
335 * -1 - Some error occurred.
338 http_conn_is_https(http_handle_t handle, boolean_t *bool)
340 http_conn_t *c_id = handle;
342 if (!http_check_conn(c_id))
343 return (-1);
345 *bool = CONN_HTTPS;
346 return (0);
350 * http_set_proxy - Establish the proxy name/port.
352 * ret = http_set_proxy(handle, proxy);
354 * Arguments:
355 * handle - Handle associated with the desired connection
356 * proxy - The hostport definition for the proxy. If NULL,
357 * The next connect will not use a proxy.
359 * Returns:
360 * 0 - Success
361 * -1 - An error occurred. Check http_get_lasterr().
364 http_set_proxy(http_handle_t handle, const url_hport_t *proxy)
366 http_conn_t *c_id = handle;
368 if (!http_check_conn(c_id))
369 return (-1);
371 if (proxy != NULL) {
372 c_id->proxy = *proxy;
373 c_id->proxied = B_TRUE;
374 } else {
375 CONN_PROXY_HOSTNAME[0] = '\0';
376 c_id->proxied = B_FALSE;
379 return (0);
383 * http_set_keepalive - Set keepalive for this connection.
385 * http_set_keepalive(handle, on_off);
387 * Arguments:
388 * handle - Handle associated with the desired connection
389 * on_off - Boolean turning keepalive on (TRUE) or off (FALSE)
391 * Returns:
392 * 0 - Success.
393 * -1 - An error occurred. Check http_get_lasterr().
395 * This setting takes effect next time a connection is opened using this
396 * handle.
399 http_set_keepalive(http_handle_t handle, boolean_t on_off)
401 http_conn_t *c_id = handle;
403 if (!http_check_conn(c_id))
404 return (-1);
406 c_id->keepalive = on_off;
407 return (0);
411 * http_set_socket_read_timeout - Set the timeout reads
413 * http_set_socket_read_timeout(handle, timeout);
415 * Arguments:
416 * handle - Handle associated with the desired connection
417 * timeout - Timeout, in seconds. Zero will default to 10 second
418 * timeouts.
420 * Returns:
421 * 0 - Success.
422 * -1 - An error occurred. Check http_get_lasterr().
424 * This setting takes effect beginning with the next read operation on this
425 * connection.
428 http_set_socket_read_timeout(http_handle_t handle, uint_t timout)
430 http_conn_t *c_id = handle;
432 if (!http_check_conn(c_id))
433 return (-1);
435 c_id->read_timeout = (timout) ? timout : DEFAULT_TIMEOUT;
436 return (0);
440 * http_set_basic_auth - Set the basic authorization user ID and password
442 * ret = http_set_basic_auth(handle, userid, password);
444 * Arguments:
445 * handle - Handle associated with the desired connection
446 * userid - ID to pass as part of http/https request
447 * password- Password which goes with the user ID
449 * Returns:
450 * 0 - Success
451 * -1 - An error occurred. Check http_get_lasterr().
453 * This must be set before a https connection is made.
456 http_set_basic_auth(http_handle_t handle, const char *userid,
457 const char *password)
459 http_conn_t *c_id = handle;
461 if (!http_check_conn(c_id))
462 return (-1);
464 if (password == NULL || userid == NULL || userid[0] == '\0') {
465 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
466 return (-1);
469 userid = strdup(userid);
470 password = strdup(password);
471 if (userid == NULL || password == NULL) {
472 free((void *)userid);
473 free((void *)password);
474 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
475 return (-1);
478 free(c_id->basic_auth_userid);
479 c_id->basic_auth_userid = (char *)userid;
480 free(c_id->basic_auth_password);
481 c_id->basic_auth_password = (char *)password;
482 return (0);
486 * http_set_random_file - See the pseudo random number generator with file data
488 * ret = http_set_random_file(handle, filename);
490 * Arguments:
491 * handle - Handle associated with the desired connection
492 * filename
493 * - filename (including path) with random number seed.
495 * Returns:
496 * 0 - Success
497 * -1 - An error occurred. Check http_get_lasterr().
499 * This must be set before a https connection is made.
502 http_set_random_file(http_handle_t handle, const char *fname)
504 http_conn_t *c_id = handle;
506 if (!http_check_conn(c_id))
507 return (-1);
509 if (fname != NULL) {
510 fname = strdup(fname);
511 if (fname == NULL) {
512 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
513 return (-1);
517 free(c_id->random_file);
518 c_id->random_file = (char *)fname;
519 return (0);
523 * http_set_certificate_authority_file - Set the CA file.
525 * ret = http_set_certificate_authority_file(filename);
527 * Arguments:
528 * filename- File with the certificate authority certs
530 * Returns:
531 * 0 - Success
532 * -1 - An error occurred. Check http_get_lasterr().
534 * This must be set before https connections to the servers is done.
537 http_set_certificate_authority_file(const char *fname)
539 early_err = 0;
541 if (fname != NULL) {
542 fname = strdup(fname);
543 if (fname == NULL) {
544 early_err = EHTTP_NOMEM;
545 return (-1);
549 free(ca_verify_file);
550 ca_verify_file = (char *)fname;
551 return (0);
555 * http_set_client_certificate_file - Set the file containing the PKCS#12
556 * client certificate and optionally its certificate chain.
558 * ret = http_set_client_certificate_file(handle, filename);
560 * Arguments:
561 * handle - Handle associated with the desired connection
562 * filename- File (including path) containing certificate, etc.
564 * Returns:
565 * 0 - Success
566 * -1 - An error occurred. Check http_get_lasterr().
568 * This must be set before the handle is used to make a https connection
569 * which will require a client certificate.
572 http_set_client_certificate_file(http_handle_t handle, const char *fname)
574 http_conn_t *c_id = handle;
576 if (!http_check_conn(c_id))
577 return (-1);
579 if (fname != NULL) {
580 fname = strdup(fname);
581 if (fname == NULL) {
582 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
583 return (-1);
587 free(c_id->client_cert_file);
588 c_id->client_cert_file = (char *)fname;
589 return (0);
593 * http_set_password - Set the password for the private key or pkcs12 file.
595 * ret = http_set_password(handle, password);
597 * Arguments:
598 * handle - Handle associated with the desired connection
599 * password- Password for the client's private key file or pkcs12 file.
601 * Returns:
602 * 0 - Success
603 * -1 - An error occurred. Check http_get_lasterr().
605 * This must be set before the handle is used to make a https connection.
608 http_set_password(http_handle_t handle, const char *password)
610 http_conn_t *c_id = handle;
612 if (!http_check_conn(c_id))
613 return (-1);
615 if (password != NULL) {
616 password = strdup(password);
617 if (password == NULL) {
618 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
619 return (-1);
623 free(c_id->file_password);
624 c_id->file_password = (char *)password;
625 return (0);
629 * http_set_key_file_password - Set the password for the private key
630 * file.
632 * ret = http_set_key_file_password(handle, password);
634 * Arguments:
635 * handle - Handle associated with the desired connection
636 * password- Password for the client's private key file.
638 * Returns:
639 * 0 - Success
640 * -1 - An error occurred. Check http_get_lasterr().
642 * This must be set before the handle is used to make a https connection.
645 http_set_key_file_password(http_handle_t handle, const char *password)
647 return (http_set_password(handle, password));
651 * http_set_private_key_file - Set the file containing the PKCS#12
652 * private key for this client.
654 * ret = http_set_private_key_file(handle, filename);
656 * Arguments:
657 * handle - Handle associated with the desired connection
658 * filename- File (including path) containing the private key.
660 * Returns:
661 * 0 - Success
662 * -1 - An error occurred. Check http_get_lasterr().
664 * This must be set before the handle is used to make a https connection.
667 http_set_private_key_file(http_handle_t handle, const char *fname)
669 http_conn_t *c_id = handle;
671 if (!http_check_conn(c_id))
672 return (-1);
674 if (fname != NULL) {
675 fname = strdup(fname);
676 if (fname == NULL) {
677 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
678 return (-1);
682 free(c_id->private_key_file);
683 c_id->private_key_file = (char *)fname;
684 return (0);
688 * http_srv_connect - Establish a connection to the server
690 * ret = http_srv_connect(handle);
692 * Arguments:
693 * handle - Handle associated with the desired connection
695 * Returns:
696 * 0 - Success
697 * -1 - An error occurred. Check http_get_lasterr() for specifics.
700 http_srv_connect(http_handle_t handle)
702 http_conn_t *c_id = handle;
703 SSL_CTX *ctx = NULL;
704 int retval;
706 ERR_clear_error();
707 if (!http_check_conn(c_id))
708 return (-1);
710 if (CONN_HTTPS) {
711 /* Build our SSL context (this function sets any errors) */
712 ctx = initialize_ctx(c_id);
713 if (ctx == NULL) {
714 libbootlog(BOOTLOG_CRIT,
715 "http_srv_connect: initialize_ctx returned NULL");
716 return (-1);
720 /* Connect the TCP socket */
721 if (c_id->proxied) {
722 c_id->fd = proxy_connect(c_id);
723 } else {
724 c_id->fd = tcp_connect(c_id, CONN_HOSTNAME, CONN_PORT);
727 if (c_id->fd < 0) {
728 if (ctx != NULL)
729 SSL_CTX_free(ctx);
730 libbootlog(BOOTLOG_CRIT, "http_srv_connect: %s returned %d",
731 (c_id->proxied) ? "proxy_connect" : "tcp_connect",
732 c_id->fd);
733 return (-1);
736 if (CONN_HTTPS) {
737 /* Connect the SSL socket */
738 if ((c_id->ssl = SSL_new(ctx)) == NULL) {
739 ulong_t err;
740 while ((err = ERR_get_error()) != 0)
741 SET_ERR(c_id, ERRSRC_LIBSSL, err);
742 libbootlog(BOOTLOG_CRIT,
743 "http_srv_connect: SSL_new returned "
744 "NULL");
745 (void) free_ctx_ssl(c_id);
746 return (-1);
748 if (verbosemode)
749 print_ciphers(c_id->ssl);
751 /* Ensure automatic negotiations will do things right */
752 SSL_set_connect_state(c_id->ssl);
754 if (SSL_set_fd(c_id->ssl, c_id->fd) == 0) {
755 ulong_t err;
756 while ((err = ERR_get_error()) != 0)
757 SET_ERR(c_id, ERRSRC_LIBSSL, err);
758 libbootlog(BOOTLOG_CRIT,
759 "http_srv_connect: SSL_set_fd returned 0");
760 (void) free_ctx_ssl(c_id);
761 return (-1);
764 if ((retval = SSL_connect(c_id->ssl)) <= 0) {
765 handle_ssl_error(c_id, retval);
766 libbootlog(BOOTLOG_CRIT,
767 "http_srv_connect: SSL_connect");
768 (void) free_ctx_ssl(c_id);
769 return (-1);
772 if (check_cert_chain(c_id, CONN_HOSTNAME) != 0) {
773 (void) free_ctx_ssl(c_id);
774 return (-1);
777 if (verbosemode)
778 print_ciphers(c_id->ssl);
781 return (0);
785 * http_head_request - Issue http HEAD request
787 * ret = http_head_request(handle, abs_path);
789 * Arguments:
790 * handle - Handle associated with the desired connection
791 * abs_path- File name portion of the URI, beginning with a /. Query,
792 * segment, etc are allowed.
794 * Returns:
795 * 0 - Success
796 * -1 - An error occurred. Check http_get_lasterr().
799 http_head_request(http_handle_t handle, const char *abs_path)
801 return (http_req(handle, abs_path, HTTP_REQ_TYPE_HEAD, 0, 0));
805 * http_get_request - Issue http GET request without a range.
807 * ret = http_get_request(handle, abs_path);
809 * Arguments:
810 * handle - Handle associated with the desired connection
811 * abs_path- File name portion of the URI, beginning with a /. Query,
812 * segment, etc are allowed.
814 * Returns:
815 * 0 - Success
816 * -1 - An error occurred. Check http_get_lasterr().
819 http_get_request(http_handle_t handle, const char *abs_path)
821 return (http_req(handle, abs_path, HTTP_REQ_TYPE_GET, -1, 0));
825 * http_get_range_request - Issue http GET request using a range.
827 * ret = http_get_range_request(handle, abs_path, curpos, len);
829 * Arguments:
830 * handle - Handle associated with the desired connection
831 * abs_path- File name portion of the URI, beginning with a /. Query,
832 * segment, etc are allowed.
833 * curpos - >=0 - Beginning of range
834 * len - = 0 - Range ends at the end of the file
835 * > 0 - Length of range.
837 * Returns:
838 * 0 - Success
839 * -1 - An error occurred. Check http_get_lasterr().
842 http_get_range_request(http_handle_t handle, const char *abs_path,
843 offset_t curpos, offset_t len)
845 http_conn_t *c_id = handle;
847 if (!http_check_conn(c_id))
848 return (-1);
850 if (curpos < 0) {
851 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
852 return (-1);
855 return (http_req(handle, abs_path, HTTP_REQ_TYPE_GET, curpos, len));
859 * http_free_respinfo - Free a respinfo structure
861 * ret = http_free_respinfo(resp);
863 * Arguments:
864 * resp - respinfo structure presumably allocated by
865 * http_process_headers() or http_process_part_headers()
867 * Note that if resp is NULL, then this results in a NOOP.
870 void
871 http_free_respinfo(http_respinfo_t *resp)
873 if (resp == NULL) {
874 return;
877 if (resp->statusmsg != NULL) {
878 free(resp->statusmsg);
880 free(resp);
884 * http_process_headers - Read in the header lines from the response
886 * ret = http_process_headers(handle, resp);
888 * Arguments:
889 * handle - Handle associated with the connection where the request
890 * was made.
891 * resp - Summary information about the response.
893 * Returns:
894 * 0 - Success
895 * < 0 - An error occurred. Specifics of the error can
896 * be gotten using http_get_lasterr().
898 * Process the HTTP headers in the response. Check for a valid response
899 * status line. Allocate and return response information via the 'resp'
900 * argument. Header lines are stored locally, are are returned using calls
901 * to http_get_response_header() and http_get_header_value().
903 * Note that the errors will be set in the http_conn_t struct before the
904 * function which detected the error returns.
906 * Note that if resp is non-NULL, then upon a successful return, information
907 * about the status line, the code in the status line and the number of
908 * header lines are returned in the http_respinfo_t structure. The caller is
909 * responsible for freeing the resources allocated to this structure via
910 * http_free_respinfo().
912 * Note that the counters used to read message bodies are initialized here.
914 * Calling this function replaces the header information which is
915 * queried using http_get_response_header() and http_get_header_value().
916 * Once this function is called, headers read by the previous call
917 * to http_process_headers() or http_process_part_headers() is lost.
920 http_process_headers(http_handle_t handle, http_respinfo_t **resp)
922 http_conn_t *c_id = handle;
923 http_respinfo_t *lresp;
924 char line[MAXHOSTNAMELEN];
925 char *ptr;
926 int i;
928 ERR_clear_error();
929 if (!http_check_conn(c_id))
930 return (-1);
932 if (resp != NULL) {
933 if ((lresp = malloc(sizeof (http_respinfo_t))) == NULL) {
934 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
935 return (-1);
938 bzero(lresp, sizeof (http_respinfo_t));
942 * check the response status line, expecting
943 * HTTP/1.1 200 OK
945 i = getaline(c_id, line, sizeof (line), B_FALSE);
946 if (i == 0) {
947 if (resp != NULL) {
948 *resp = lresp;
950 return (0);
953 if (i < 0) {
955 * Cause of I/O error was already put into
956 * error stack. This is an additional error.
958 http_free_respinfo(lresp);
959 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NODATA);
960 return (-1);
963 free_response(c_id, B_TRUE);
965 if (verbosemode)
966 libbootlog(BOOTLOG_VERBOSE, "http_process_headers: %s", line);
968 ptr = line;
969 if (strncmp(ptr, "HTTP/1.1", 8) != 0) {
970 http_free_respinfo(lresp);
971 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOT_1_1);
972 return (-1);
975 /* skip to the code */
976 ptr += 8;
977 while (isspace(*ptr))
978 ptr++;
980 /* make sure it's three digits */
981 i = 0;
982 while (isdigit(ptr[i]))
983 i++;
984 if (i != 3) {
985 http_free_respinfo(lresp);
986 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADHDR);
987 return (-1);
989 c_id->resp.code = strtol(ptr, NULL, 10);
991 /* skip to the message */
992 ptr += 3;
993 while (isspace(*ptr))
994 ptr++;
996 /* save the message */
997 c_id->resp.statusmsg = malloc(strlen(ptr) + 1);
998 if (c_id->resp.statusmsg == NULL) {
999 http_free_respinfo(lresp);
1000 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1001 return (-1);
1003 (void) strcpy(c_id->resp.statusmsg, ptr);
1005 if ((i = read_headerlines(c_id, B_FALSE)) < 0) {
1007 * Error stack was already set at a lower level.
1008 * 'statusmsg' will be cleaned up next time
1009 * headers are read.
1011 http_free_respinfo(lresp);
1012 return (-1);
1016 * See if there is a 'content-type: multipart/mixed' line in the
1017 * headers. If so, get the boundary string.
1019 ptr = http_get_header_value(handle, "Content-Type");
1020 if (ptr != NULL) {
1021 char *ptr2;
1023 ptr2 = ptr;
1024 while (isspace(*ptr2))
1025 ptr2 ++;
1026 if (startswith((const char **)&ptr2, "Multipart/Mixed;")) {
1027 while (isspace(*ptr2))
1028 ptr2 ++;
1029 if (startswith((const char **)&ptr2, "Boundary=")) {
1030 if (ptr2[0] == '"') {
1031 ptr2 ++;
1032 if (ptr2[strlen(ptr2) - 1] == '"')
1033 ptr2[strlen(ptr2) - 1] = '\0';
1035 c_id->boundary = strdup(ptr2);
1036 if (c_id->boundary == NULL) {
1037 free(ptr);
1038 http_free_respinfo(lresp);
1039 SET_ERR(c_id, ERRSRC_LIBHTTP,
1040 EHTTP_NOMEM);
1041 return (-1);
1043 c_id->boundary_len = strlen(c_id->boundary);
1044 c_id->is_multipart = B_TRUE;
1045 c_id->is_firstpart = B_TRUE;
1048 free(ptr);
1052 * Initialize the counters used to process message bodies.
1054 if (init_bread(c_id) != 0) {
1056 * Error stack was already set at a lower level.
1058 http_free_respinfo(lresp);
1059 return (-1);
1062 /* Copy fields to the caller's structure */
1063 if (resp != NULL) {
1064 lresp->code = c_id->resp.code;
1065 lresp->nresphdrs = c_id->resp.nresphdrs;
1066 lresp->statusmsg = strdup(c_id->resp.statusmsg);
1067 if (lresp->statusmsg == NULL) {
1068 http_free_respinfo(lresp);
1069 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1070 return (-1);
1072 *resp = lresp;
1075 return (0);
1079 * http_process_part_headers - Read in part boundary and header lines for the
1080 * next part of a multipart message.
1082 * ret = http_process_part_headers(handle, resp);
1084 * Arguments:
1085 * handle - Handle associated with the connection where the request
1086 * was made.
1087 * resp - Return address for summary information about the
1088 * header block.
1090 * Returns:
1091 * = 1 - The end part was found.
1092 * = 0 - Success, with header info returned in 'resp'
1093 * = -1 - An error occurred. Specifics of the error can
1094 * be gotten using http_get_lasterr().
1096 * This function reads any \r\n sequences (empty lines) and expects to get
1097 * a boundary line as the next non-empty line. It then reads header lines
1098 * (content-length, etc) until it gets another empty lines, which ends the
1099 * header section.
1101 * Note that if resp is non-NULL, then upon a successful return, information
1102 * about the the number of header lines is returned in the http_respinfo_t
1103 * structure. The caller is responsible for freeing the resources allocated
1104 * to this structure via http_free_respinfo().
1106 * Headers values can be returned using http_get_response_header() and
1107 * http_get_header_value().
1109 * Calling this function replaces the header information which is
1110 * queried using http_get_response_header() and http_get_header_value().
1111 * Once this function is called, information returned by the previous call
1112 * to http_process_headers() or http_process_part_headers() is gone.
1115 http_process_part_headers(http_handle_t handle, http_respinfo_t **resp)
1117 http_conn_t *c_id = handle;
1118 char line[MAXHOSTNAMELEN];
1119 int count;
1120 int limit;
1121 int i;
1123 ERR_clear_error();
1124 if (!http_check_conn(c_id))
1125 return (-1);
1127 if (c_id->is_multipart == 0) {
1128 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOTMULTI);
1129 return (-1);
1133 * Figure out how many empty lines to allow. Before the first
1134 * boundary of the transmission, there can be any number of
1135 * empty lines (from 0 up). Limit these to some reasonable
1136 * failsafe.
1138 * For the 2nd and later boundaries, there is supposed to be
1139 * one crlf pair. However, many implementations don't require
1140 * it. So don't require it.
1142 if (c_id->is_firstpart) {
1143 limit = FAILSAFE;
1144 c_id->is_firstpart = B_FALSE;
1145 } else
1146 limit = 1;
1148 /* Look for the boundary line. */
1149 count = 0;
1150 while ((i = getaline(c_id, line, sizeof (line), B_TRUE)) == 0 &&
1151 count < FAILSAFE)
1152 count ++;
1153 if (i < 0 || count > limit) {
1155 * If I/O error, cause was already put into
1156 * error stack. This is an additional error.
1158 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOBOUNDARY);
1159 return (-1);
1162 free_response(c_id, B_FALSE);
1164 if (verbosemode)
1165 libbootlog(BOOTLOG_VERBOSE,
1166 "http_process_part_headers: %s", line);
1168 /* Look for boundary line - '--<boundary text> */
1169 if (line[0] != '-' || line[1] != '-' ||
1170 strncmp(&line[2], c_id->boundary, c_id->boundary_len) != 0) {
1171 /* No boundary line.... */
1172 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOBOUNDARY);
1173 return (-1);
1176 /* Is this the end-of-parts boundary (ends with a trailing '--') */
1177 if (strcmp(&line[c_id->boundary_len + 2], "--") == 0) {
1178 return (1);
1181 free_response(c_id, B_FALSE);
1182 if (read_headerlines(c_id, B_TRUE) < 0) {
1183 /* Error stack was already set at a lower level. */
1184 return (-1);
1187 /* Copy fields to the caller's structure */
1188 if (resp != NULL) {
1189 if ((*resp = malloc(sizeof (http_respinfo_t))) == NULL) {
1190 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1191 return (-1);
1193 bzero(*resp, sizeof (http_respinfo_t));
1194 (*resp)->code = ' ';
1195 (*resp)->nresphdrs = c_id->resp.nresphdrs;
1198 return (0);
1202 * http_get_response_header - Get a line from the response header
1204 * ret = http_get_response_header(handle, whichline);
1206 * Arguments:
1207 * handle - Handle associated with the desired connection
1208 * whichline - Which line of the header to return. This must be between
1209 * zero and resp.nresphdrs which was returned by the call to
1210 * http_process_headers().
1212 * Returns:
1213 * ptr - Points to a copy of the header line.
1214 * NULL - An error occurred. Check http_get_lasterr().
1216 char *
1217 http_get_response_header(http_handle_t handle, uint_t which)
1219 http_conn_t *c_id = handle;
1220 char *res;
1222 if (!http_check_conn(c_id))
1223 return (NULL);
1225 if (which >= c_id->resp.nresphdrs) {
1226 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_OORANGE);
1227 return (NULL);
1230 res = strdup(c_id->resphdr[which]);
1231 if (res == NULL) {
1232 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1233 return (NULL);
1235 return (res);
1239 * http_get_header_value - Get the value of a header line.
1241 * ret = http_get_header_value(handle, what);
1243 * Arguments:
1244 * handle - Handle associated with the desired connection
1245 * what - The field name to look up.
1247 * Returns:
1248 * ptr - Points to a copy of the header value.
1249 * NULL - An error occurred. Check http_get_lasterr().
1251 char *
1252 http_get_header_value(http_handle_t handle, const char *field_name)
1254 http_conn_t *c_id = handle;
1255 char *ptr;
1256 char *res;
1257 int i;
1258 int n;
1260 if (!http_check_conn(c_id))
1261 return (NULL);
1263 if (field_name == NULL || field_name[0] == '\0') {
1264 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1265 return (NULL);
1268 for (i = 0; i < c_id->resp.nresphdrs; i++) {
1269 ptr = c_id->resphdr[i];
1270 n = strlen(field_name);
1271 if (strncasecmp(field_name, ptr, n) == 0 && ptr[n] == ':') {
1272 ptr += n + 1;
1274 while (isspace(*ptr))
1275 ptr++;
1277 res = strdup(ptr);
1278 if (res == NULL) {
1279 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1280 return (NULL);
1282 return (res);
1285 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMATCH);
1286 return (NULL);
1290 * http_read_body - Read the HTTP response body.
1292 * ret = http_read_body(handle, recv_buf_ptr, recv_buf_size);
1294 * Arguments:
1295 * handle - Handle associated with the relevant connection
1296 * recv_buf_ptr - Points to buffer to receive buffer
1297 * recv_buf_size - Length in bytes of buffer.
1299 * Returns:
1300 * n - Number of bytes read..
1301 * < 0 - An error occurred. This is (the number of bytes gotten + 1),
1302 * negated. In other words, if 'n' bytes were read and then an
1303 * error occurred, this will return (-(n+1)). So zero bytes
1304 * were read and then an error occurs, this will return -1. If
1305 * 1 byte was read, it will return -2, etc. Specifics of the
1306 * error can be gotten using http_get_lasterr().
1308 * Note that the errors will be set in the http_conn_t struct before the
1309 * function which detected the error returns.
1312 http_read_body(http_handle_t handle, char *recv_buf_ptr, size_t recv_buf_size)
1314 http_conn_t *c_id = handle;
1316 ERR_clear_error();
1317 if (!http_check_conn(c_id))
1318 return (-1);
1320 if (recv_buf_ptr == NULL || recv_buf_size == 0) {
1321 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1322 return (-1);
1325 return (getbytes(c_id, recv_buf_ptr, recv_buf_size));
1329 * http_srv_disconnect - Get rid of the connection to the server without
1330 * freeing the http_conn_t structure.
1332 * ret = http_srv_disconnect(handle);
1334 * Arguments:
1335 * handle - Handle associated with the connection
1337 * Returns:
1338 * 0 - Success
1339 * -1 - An error occurred. Specifics of the error can
1340 * be gotten using http_get_lasterr().
1343 http_srv_disconnect(http_handle_t handle)
1345 http_conn_t *c_id = handle;
1346 int err_ret;
1348 ERR_clear_error();
1349 if (!http_check_conn(c_id))
1350 return (-1);
1352 err_ret = free_ctx_ssl(c_id);
1353 bzero(&c_id->inbuf, sizeof (c_id->inbuf));
1354 free_response(c_id, B_TRUE);
1356 return (err_ret);
1360 * http_srv_close - Close the connection and clean up the http_conn_t
1361 * structure.
1363 * http_srv_close(handle);
1365 * Arguments:
1366 * handle - Handle associated with the desired connection
1368 * Returns:
1369 * 0 - Success
1370 * -1 - An error occurred. Specifics of the error can
1371 * be gotten using http_get_lasterr().
1374 http_srv_close(http_handle_t handle)
1376 http_conn_t *c_id = handle;
1377 int err_ret = 0;
1379 if (!http_check_conn(c_id))
1380 return (-1);
1382 if (c_id->ctx != NULL || c_id->ssl != NULL || c_id->fd != -1)
1383 err_ret = http_srv_disconnect(handle);
1385 free(c_id->basic_auth_userid);
1386 free(c_id->basic_auth_password);
1387 free(c_id->resp.statusmsg);
1388 free(c_id->client_cert_file);
1389 free(c_id->private_key_file);
1390 free(c_id->random_file);
1391 free(c_id->file_password);
1392 c_id->signature = 0;
1394 free(c_id);
1395 return (err_ret);
1399 * http_get_conn_info - Return current information about the connection
1401 * err = http_get_conn_info(handle);
1403 * Arguments:
1404 * handle - Handle associated with the connection in question
1406 * Returns:
1407 * non_NULL- Points to structure
1408 * NULL - An error exists. Check http_get_lasterr().
1410 http_conninfo_t *
1411 http_get_conn_info(http_handle_t handle)
1413 http_conn_t *c_id = handle;
1414 http_conninfo_t *info;
1416 if (!http_check_conn(c_id))
1417 return (NULL);
1419 info = malloc(sizeof (*info));
1420 if (info == NULL) {
1421 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1422 return (NULL);
1425 bzero(info, sizeof (*info));
1427 info->uri = c_id->uri;
1428 info->proxy = c_id->proxy;
1429 info->keepalive = c_id->keepalive;
1430 info->read_timeout = c_id->read_timeout;
1432 return (info);
1436 * http_get_lasterr - Return the next error on the last operation
1438 * err = http_get_lasterr(handle, errsrc);
1440 * Arguments:
1441 * handle - Handle associated with the connection in question
1442 * If no valid handle exists yet, this can be NULL.
1443 * However, it must be checked with the very next call.
1444 * errsrc - Returns the Sources of errors (ERRSRC_* values).
1446 * Returns:
1447 * 0 - No error exists
1448 * <> 0 - The error.
1450 ulong_t
1451 http_get_lasterr(http_handle_t handle, uint_t *errsrc)
1453 http_conn_t *c_id = handle;
1454 ulong_t src;
1455 ulong_t err;
1457 if (c_id == NULL || c_id->signature != HTTP_CONN_INFO) {
1458 if (errsrc)
1459 *errsrc = ERRSRC_LIBHTTP;
1460 err = early_err;
1461 early_err = 0;
1462 return (err);
1465 GET_ERR(c_id, src, err);
1466 if (src == 0 && err == 0) {
1467 if (errsrc)
1468 *errsrc = ERRSRC_LIBHTTP;
1469 err = early_err;
1470 early_err = 0;
1471 return (err);
1473 if (errsrc)
1474 *errsrc = src;
1475 return (err);
1479 * http_decode_err - Decode a libssl error
1481 * err = http_decode_err(err, errlib, errfunc, errcode);
1483 * Arguments:
1484 * err - libssl/libcrypto error returned.
1485 * errlib - returns libssl/libcrypto sublibrary that caused the error
1486 * errfunc - returns function in that library
1487 * errcode - returns error code
1489 * Returns:
1490 * None other than the above.
1492 void
1493 http_decode_err(ulong_t err, int *errlib, int *errfunc, int *errcode)
1495 if (errlib)
1496 *errlib = ERR_GET_LIB(err);
1497 if (errfunc)
1498 *errfunc = ERR_GET_FUNC(err);
1499 if (errcode)
1500 *errcode = ERR_GET_REASON(err);
1503 /* ---------------------- private functions ----------------------- */
1506 * http_req - Issue http request (either HEAD or GET)
1508 * ret = http_req(handle, abs_path, reqtype, curpos, len);
1510 * Arguments:
1511 * handle - Handle associated with the desired connection
1512 * abs_path- File name portion of the URI, beginning with a /. Query,
1513 * segment, etc are allowed.
1514 * type - HTTP_REQ_TYPE_HEAD or HTTP_REQ_TYPE_GET
1516 * In the case of GET requests,
1517 * curpos- -1 - Range not used
1518 * >=0 - Beginning of range
1519 * len - 0 - Range ends at the end of the file
1520 * >0 - Length of range.
1522 * Returns:
1523 * 0 - Success
1524 * -1 - An error occurred. Check http_get_lasterr().
1526 static int
1527 http_req(http_handle_t handle, const char *abs_path, http_req_t type,
1528 offset_t curpos, offset_t len)
1530 http_conn_t *c_id = handle;
1531 char *request;
1532 char *reqtypename;
1533 char *newreq;
1534 int requestlen;
1535 int retval;
1536 int j;
1538 ERR_clear_error();
1539 if (!http_check_conn(c_id))
1540 return (-1);
1542 if (abs_path == NULL || abs_path[0] == '\0') {
1543 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1544 return (-1);
1547 /* Determine the name for the request type */
1548 switch (type) {
1549 case HTTP_REQ_TYPE_GET:
1550 reqtypename = "GET";
1551 if (curpos < 0 && curpos != -1) {
1552 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1553 return (-1);
1555 break;
1557 case HTTP_REQ_TYPE_HEAD:
1558 reqtypename = "HEAD";
1559 break;
1561 default:
1562 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1563 return (-1);
1566 /* Do rudimentary checks on the absolute path */
1567 if (abs_path == NULL || *abs_path != '/') {
1568 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADARG);
1569 libbootlog(BOOTLOG_CRIT, "http_req: invalid file path");
1570 if (abs_path != NULL)
1571 libbootlog(BOOTLOG_CRIT, " %s", abs_path);
1572 return (-1);
1574 (void) strlcpy(CONN_ABSPATH, abs_path, MAXHOSTNAMELEN);
1577 * Size the request.
1579 * With proxy:
1580 * reqtypename + " http://" + host + ":" + port + path +
1581 * " HTTP/1.1\r\n" +
1582 * Without proxy:
1583 * reqtypename + " " + path + " HTTP/1.1\r\n" +
1585 requestlen = strlen(reqtypename) + 8 + strlen(CONN_HOSTNAME) + 1 +
1586 count_digits(CONN_PORT) + strlen(CONN_ABSPATH) + 11;
1589 * Plus the rest:
1590 * "Host: " + targethost + ":" + count_digits(port) + "\r\n" +
1591 * "Connection: Keep-Alive\r\n" plus trailing "\r\n\0"
1593 requestlen += 6 + strlen(CONN_HOSTNAME) + 1 +
1594 count_digits(CONN_PORT) + 2 + 24 + 3;
1595 if ((request = malloc(requestlen)) == NULL) {
1596 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1597 return (-1);
1600 /* The request line */
1601 if (c_id->proxied && c_id->ssl == NULL) {
1602 j = snprintf(request, requestlen,
1603 "%s http://%s:%d%s HTTP/1.1\r\n",
1604 reqtypename, CONN_HOSTNAME, CONN_PORT,
1605 CONN_ABSPATH);
1606 } else {
1607 j = snprintf(request, requestlen, "%s %s HTTP/1.1\r\n",
1608 reqtypename, CONN_ABSPATH);
1611 /* Ancillary headers */
1612 j += snprintf(&request[j], requestlen - j, "Host: %s:%d\r\n",
1613 CONN_HOSTNAME, CONN_PORT);
1614 if (!c_id->keepalive)
1615 j += snprintf(&request[j], requestlen - j,
1616 "Connection: close\r\n");
1617 else
1618 j += snprintf(&request[j], requestlen - j,
1619 "Connection: Keep-Alive\r\n");
1621 * We only send the range header on GET requests
1623 * "Range: bytes=" + from + "-" + end + "\r\n" or
1624 * "Range: bytes=" + from + "-" "\r\n"
1626 if (type == HTTP_REQ_TYPE_GET && curpos >= 0) {
1627 offset_t endpos;
1629 requestlen += 13 + count_digits(curpos) + 1 + 2;
1630 if (len > 0) {
1631 endpos = curpos + len - 1;
1632 requestlen += count_digits(endpos);
1635 if ((newreq = realloc(request, requestlen)) == NULL) {
1636 free(request);
1637 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1638 return (-1);
1640 request = newreq;
1642 j += sprintf(&request[j], "Range: bytes=%lld-", curpos);
1643 if (len > 0)
1644 j += sprintf(&request[j], "%lld", endpos);
1645 j += sprintf(&request[j], "\r\n");
1649 * Authorization is added only if provided (RFC 2617, Section 2)
1651 * "Authorization: Basic " + authencstr + "\r\n"
1653 if (c_id->basic_auth_userid && c_id->basic_auth_password) {
1654 char *authstr;
1655 char *authencstr;
1656 int authlen;
1659 * Allow for concat(basic_auth_userid ":" basic_auth_password)
1661 authlen = strlen(c_id->basic_auth_userid) + 2 +
1662 strlen(c_id->basic_auth_password);
1663 if ((authstr = malloc(authlen + 1)) == NULL) {
1664 free(request);
1665 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1666 return (-1);
1668 (void) snprintf(authstr, authlen + 1, "%s:%s",
1669 c_id->basic_auth_userid, c_id->basic_auth_password);
1671 /* 3 bytes encoded as 4 (round up) with null termination */
1672 if ((authencstr = malloc((authlen + 2) / 3 * 4 + 1)) == NULL) {
1673 free(authstr);
1674 free(request);
1675 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1676 return (-1);
1679 (void) EVP_EncodeBlock((unsigned char *)authencstr,
1680 (unsigned char *)authstr, authlen);
1683 * Finally do concat(Authorization: Basic " authencstr "\r\n")
1685 requestlen += 21 + strlen(authencstr) + 2;
1686 if ((newreq = realloc(request, requestlen)) == NULL) {
1687 free(authencstr);
1688 free(authstr);
1689 free(request);
1690 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
1691 return (-1);
1693 request = newreq;
1695 j += snprintf(&request[j], requestlen - j,
1696 "Authorization: Basic %s\r\n", authencstr);
1698 free(authencstr);
1699 free(authstr);
1702 j += sprintf(&request[j], "\r\n");
1704 if (verbosemode)
1705 libbootlog(BOOTLOG_VERBOSE, "%s", request);
1707 /* send the HTTP request */
1708 retval = http_srv_send(c_id, request, j);
1710 free(request);
1711 if (retval != j) {
1712 /* Assume error in was set by send request. */
1713 return (-1);
1716 return (0);
1720 * password_cb - Callback to get private key password and return it
1721 * to SSL. (Used for PEM certificates only.)
1723 * len = passwd_cb(buf, buflen, rwflag, userdata);
1725 * Arguments:
1726 * buf - Buffer for the password
1727 * buflen - Length of 'buf'
1728 * rwflag - password will be used for reading/decryption (== 0)
1729 * or writing/encryption (== 1).
1730 * userdata - Points to connection-specific information.
1732 * Returns:
1733 * > 0 - Length of password that was put into 'buf'.
1734 * 0 - No password was returned (usually error occurred)
1736 * NOTE: The password code is not thread safe
1738 /* ARGSUSED */
1739 static int
1740 password_cb(char *buf, int buflen, int rwflag, void *userdata)
1742 http_conn_t *c_id = userdata;
1744 if (c_id == NULL || c_id->signature != HTTP_CONN_INFO)
1745 return (0);
1747 if (c_id->file_password == NULL ||
1748 buflen < strlen(c_id->file_password) + 1)
1749 return (0);
1751 return (strlcpy(buf, c_id->file_password, buflen));
1755 * initialize_ctx - Initialize the context for a connection.
1757 * ctx = initialize_ctx(c_id);
1759 * Arguments:
1760 * None.
1762 * Returns:
1763 * non-NULL - Points to ctx structure.
1764 * NULL - An error occurred. Any cleanup is done and error
1765 * information is in the error stack.
1767 static SSL_CTX *
1768 initialize_ctx(http_conn_t *c_id)
1770 #if OPENSSL_VERSION_NUMBER < 0x10000000L
1771 SSL_METHOD *meth;
1772 #else
1773 const SSL_METHOD *meth;
1774 #endif
1775 SSL_CTX *ctx;
1777 ERR_clear_error();
1779 /* Global system initialization */
1780 if (ssl_init == 0) {
1781 sunw_crypto_init();
1782 SSL_load_error_strings();
1783 ssl_init = 1;
1786 /* Create our context */
1787 meth = SSLv3_client_method();
1788 if ((ctx = SSL_CTX_new(meth)) == NULL) {
1789 ulong_t err;
1790 while ((err = ERR_get_error()) != 0)
1791 SET_ERR(c_id, ERRSRC_LIBSSL, err);
1792 libbootlog(BOOTLOG_CRIT,
1793 "initialize_ctx: SSL_CTX_new returned NULL");
1794 return (NULL);
1798 * Ensure that any renegotiations for blocking connections will
1799 * be done automatically. (The alternative is to return partial
1800 * reads to the caller and let it oversee the renegotiations.)
1802 if (SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY) == 0) {
1803 ulong_t err;
1804 while ((err = ERR_get_error()) != 0)
1805 SET_ERR(c_id, ERRSRC_LIBSSL, err);
1806 libbootlog(BOOTLOG_CRIT,
1807 "initialize_ctx: SSL_CTX_set_mode returned 0");
1808 (void) SSL_CTX_free(ctx);
1809 return (NULL);
1812 /* set cipher list if provided */
1813 if (cipher_list != NULL) {
1814 if (!SSL_CTX_set_cipher_list(ctx, cipher_list)) {
1815 ulong_t err;
1816 while ((err = ERR_get_error()) != 0)
1817 SET_ERR(c_id, ERRSRC_LIBSSL, err);
1818 libbootlog(BOOTLOG_CRIT,
1819 "initialize_ctx: Error in cipher list");
1820 SSL_CTX_free(ctx);
1821 return (NULL);
1826 * We attempt to use the client_certificate_file for the private
1827 * key input scheme *only* in the absence of private_key_file. In
1828 * this instance the scheme will be the same as that used for the
1829 * certificate input.
1832 /* Load our certificates */
1833 if (c_id->client_cert_file != NULL) {
1834 if (p12_format) {
1835 /* Load pkcs12-formated files */
1836 if (sunw_p12_use_certfile(ctx, c_id->client_cert_file,
1837 c_id->file_password)
1838 <= 0) {
1839 ulong_t err;
1840 while ((err = ERR_get_error()) != 0)
1841 SET_ERR(c_id, ERRSRC_LIBSSL, err);
1842 libbootlog(BOOTLOG_CRIT,
1843 "initialize_ctx: Couldn't read "
1844 "PKCS12 certificate file");
1845 SSL_CTX_free(ctx);
1846 return (NULL);
1848 } else {
1849 /* Load PEM-formated files */
1850 if (SSL_CTX_use_certificate_file(ctx,
1851 c_id->client_cert_file, SSL_FILETYPE_PEM) <= 0) {
1852 ulong_t err;
1853 while ((err = ERR_get_error()) != 0)
1854 SET_ERR(c_id, ERRSRC_LIBSSL, err);
1855 libbootlog(BOOTLOG_CRIT,
1856 "initialize_ctx: Couldn't read "
1857 "PEM certificate file");
1858 SSL_CTX_free(ctx);
1859 return (NULL);
1862 if (c_id->private_key_file == NULL)
1863 c_id->private_key_file = c_id->client_cert_file;
1866 /* Load our keys */
1867 if (p12_format) {
1868 /* Load pkcs12-formated files */
1869 if (c_id->private_key_file != NULL) {
1870 if (sunw_p12_use_keyfile(ctx, c_id->private_key_file,
1871 c_id->file_password)
1872 <= 0) {
1873 ulong_t err;
1874 while ((err = ERR_get_error()) != 0)
1875 SET_ERR(c_id, ERRSRC_LIBSSL, err);
1876 libbootlog(BOOTLOG_CRIT,
1877 "initialize_ctx: Couldn't read "
1878 "PKCS12 key file");
1879 SSL_CTX_free(ctx);
1880 return (NULL);
1883 } else {
1884 /* Load PEM-formated files */
1885 SSL_CTX_set_default_passwd_cb(ctx, password_cb);
1886 SSL_CTX_set_default_passwd_cb_userdata(ctx, c_id);
1887 if (c_id->private_key_file != NULL) {
1888 if (SSL_CTX_use_PrivateKey_file(ctx,
1889 c_id->private_key_file, SSL_FILETYPE_PEM) <= 0) {
1890 ulong_t err;
1891 while ((err = ERR_get_error()) != 0)
1892 SET_ERR(c_id, ERRSRC_LIBSSL, err);
1893 libbootlog(BOOTLOG_CRIT,
1894 "initialize_ctx: Couldn't read "
1895 "PEM key file");
1896 SSL_CTX_free(ctx);
1897 return (NULL);
1902 /* Load the CAs we trust */
1903 if (ca_verify_file != NULL) {
1904 if (p12_format) {
1905 if (sunw_p12_use_trustfile(ctx, ca_verify_file,
1906 c_id->file_password)
1907 <= 0) {
1908 ulong_t err;
1909 while ((err = ERR_get_error()) != 0)
1910 SET_ERR(c_id, ERRSRC_LIBSSL, err);
1911 libbootlog(BOOTLOG_CRIT,
1912 "initialize_ctx: Couldn't read "
1913 "PKCS12 CA list file");
1914 SSL_CTX_free(ctx);
1915 return (NULL);
1917 } else {
1918 if (SSL_CTX_load_verify_locations(ctx, ca_verify_file,
1919 NULL) == 0) {
1920 ulong_t err;
1921 while ((err = ERR_get_error()) != 0)
1922 SET_ERR(c_id, ERRSRC_LIBSSL, err);
1923 libbootlog(BOOTLOG_CRIT,
1924 "initialize_ctx: Couldn't read PEM"
1925 " CA list file");
1926 SSL_CTX_free(ctx);
1927 return (NULL);
1932 SSL_CTX_set_verify_depth(ctx, verify_depth);
1934 /* Load randomness */
1935 if (c_id->random_file != NULL &&
1936 RAND_load_file(c_id->random_file, 1024 * 1024) <= 0) {
1937 ulong_t err;
1938 while ((err = ERR_get_error()) != 0)
1939 SET_ERR(c_id, ERRSRC_LIBSSL, err);
1940 libbootlog(BOOTLOG_CRIT,
1941 "initialize_ctx: Couldn't load random file");
1942 SSL_CTX_free(ctx);
1943 return (NULL);
1945 if (RAND_status() <= 0) {
1946 ulong_t err;
1947 while ((err = ERR_get_error()) != 0)
1948 SET_ERR(c_id, ERRSRC_LIBSSL, err);
1949 libbootlog(BOOTLOG_CRIT,
1950 "initialize_ctx: PRNG not seeded");
1951 SSL_CTX_free(ctx);
1952 return (NULL);
1955 return (ctx);
1959 * tcp_connect - Set up a TCP connection.
1961 * sock = tcp_connect(c_id, hostname, port);
1963 * Arguments:
1964 * c_id - Structure associated with the desired connection
1965 * hostname - the host to connect to
1966 * port - the port to connect to
1968 * Returns:
1969 * >= 0 - Socket number.
1970 * -1 - Error occurred. Error information is set in the
1971 * error stack. Any cleanup is done.
1973 * This function established a connection to the target host. When
1974 * it returns, the connection is ready for a HEAD or GET request.
1976 static int
1977 tcp_connect(http_conn_t *c_id, const char *hostname, uint16_t port)
1979 struct hostent *hp;
1980 struct sockaddr_in addr;
1981 int sock;
1982 int status;
1984 if ((hp = gethostbyname(hostname)) == NULL) {
1985 SET_ERR(c_id, ERRSRC_RESOLVE, h_errno);
1986 return (-1);
1989 bzero(&addr, sizeof (addr));
1990 /* LINTED */
1991 addr.sin_addr = *(struct in_addr *)hp->h_addr;
1992 addr.sin_family = AF_INET;
1993 addr.sin_port = htons(port);
1995 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
1996 SET_ERR(c_id, ERRSRC_SYSTEM, errno);
1997 return (-1);
2000 status = connect(sock, (struct sockaddr *)&addr, sizeof (addr));
2001 if (status < 0) {
2002 SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2003 (void) socket_close(sock);
2004 return (-1);
2007 c_id->host_addr = addr; /* save for future sendto calls */
2008 c_id->fd = sock;
2010 return (sock);
2014 * readline - Get a line from the socket. Discard the end-of-line
2015 * (CR or CR/LF or LF).
2017 * ret = readline(c_id, sock, buf, len);
2019 * Arguments:
2020 * c_id - Structure associated with the desired connection
2021 * sock - Socket to read
2022 * buf - Buffer for the line
2023 * len - Length of the buffer
2025 * Returns:
2026 * 0 - Success. 'buf' contains the line.
2027 * -1 - Error occurred. Error information is set in the
2028 * error stack.
2030 static int
2031 readline(http_conn_t *c_id, int sock, char *buf, int len)
2033 int n, r;
2034 char *ptr = buf;
2036 for (n = 0; n < len; n++) {
2037 r = socket_read(sock, ptr, 1, c_id->read_timeout);
2039 if (r < 0) {
2040 SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2041 return (-1);
2042 } else if (r == 0) {
2043 libbootlog(BOOTLOG_WARNING, "Readline: no data");
2044 return (0);
2047 if (*ptr == '\n') {
2048 *ptr = '\0';
2050 /* Strip off the CR if it's there */
2051 if (buf[n-1] == '\r') {
2052 buf[n-1] = '\0';
2053 n--;
2056 return (n);
2059 ptr++;
2062 libbootlog(BOOTLOG_WARNING, "readline: Buffer too short\n");
2063 return (0);
2067 * proxy_connect - Set up a proxied TCP connection to the target host.
2069 * sock = proxy_connect(c_id);
2071 * Arguments:
2072 * c_id - Structure associated with the desired connection
2074 * Returns:
2075 * >= 0 - Socket number.
2076 * -1 - Error occurred. Error information is set in the
2077 * error stack. Any cleanup is done.
2079 * This function established a connection to the proxy and then sends
2080 * the request to connect to the target host. It reads the response
2081 * (the status line and any headers). When it returns, the connection
2082 * is ready for a HEAD or GET request.
2084 static int
2085 proxy_connect(http_conn_t *c_id)
2087 struct sockaddr_in addr;
2088 int sock;
2089 char buf[1024];
2090 char *ptr;
2091 int i;
2093 if ((sock = tcp_connect(c_id, CONN_PROXY_HOSTNAME,
2094 CONN_PROXY_PORT)) < 0) {
2095 return (-1);
2098 if (!CONN_HTTPS) {
2099 return (sock);
2102 /* Now that we're connected, do the proxy request */
2103 (void) snprintf(buf, sizeof (buf),
2104 "CONNECT %s:%d HTTP/1.0\r\n\r\n", CONN_HOSTNAME, CONN_PORT);
2106 /* socket_write sets the errors */
2107 if (socket_write(sock, buf, strlen(buf), &addr) <= 0) {
2108 SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2109 (void) socket_close(sock);
2110 return (-1);
2113 /* And read the response */
2114 i = readline(c_id, sock, buf, sizeof (buf));
2115 if (i <= 0) {
2116 if (i == 0)
2117 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NORESP);
2118 libbootlog(BOOTLOG_CRIT,
2119 "proxy_connect: Empty response from proxy");
2120 (void) socket_close(sock);
2121 return (-1);
2124 ptr = buf;
2125 if (strncmp(ptr, "HTTP", 4) != 0) {
2126 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOT_1_1);
2127 libbootlog(BOOTLOG_CRIT,
2128 "proxy_connect: Unrecognized protocol");
2129 (void) socket_close(sock);
2130 return (-1);
2133 /* skip to the code */
2134 ptr += 4;
2135 while (*ptr != ' ' && *ptr != '\0')
2136 ptr++;
2137 while (*ptr == ' ' && *ptr != '\0')
2138 ptr++;
2140 /* make sure it's three digits */
2141 if (strncmp(ptr, "200", 3) != 0) {
2142 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADRESP);
2143 libbootlog(BOOTLOG_CRIT,
2144 "proxy_connect: Received error from proxy server");
2145 (void) socket_close(sock);
2146 return (-1);
2148 ptr += 3;
2149 if (isdigit(*ptr)) {
2150 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADRESP);
2151 (void) socket_close(sock);
2152 return (-1);
2155 /* Look for the blank line that signals end of proxy header */
2156 while ((i = readline(c_id, sock, buf, sizeof (buf))) > 0)
2159 if (i < 0) {
2160 (void) socket_close(sock);
2161 return (-1);
2164 return (sock);
2168 * check_cert_chain - Check if we have a valid certificate chain.
2170 * ret = check_cert_chain(c_id, host);
2172 * Arguments:
2173 * c_id - Connection info.
2174 * host - Name to compare with the common name in the certificate.
2176 * Returns:
2177 * 0 - Certificate chain and common name are both OK.
2178 * -1 - Certificate chain and/or common name is not valid.
2180 static int
2181 check_cert_chain(http_conn_t *c_id, char *host)
2183 X509 *peer;
2184 char peer_CN[256];
2185 long verify_err;
2187 if ((verify_err = SSL_get_verify_result(c_id->ssl)) != X509_V_OK) {
2188 SET_ERR(c_id, ERRSRC_VERIFERR, verify_err);
2189 libbootlog(BOOTLOG_CRIT,
2190 "check_cert_chain: Certificate doesn't verify");
2191 return (-1);
2195 * Check the cert chain. The chain length
2196 * is automatically checked by OpenSSL when we
2197 * set the verify depth in the ctx
2199 * All we need to do here is check that the CN
2200 * matches
2203 /* Check the common name */
2204 if ((peer = SSL_get_peer_certificate(c_id->ssl)) == NULL) {
2205 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOCERT);
2206 libbootlog(BOOTLOG_CRIT,
2207 "check_cert_chain: Peer did not present a certificate");
2208 return (-1);
2210 (void) X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
2211 NID_commonName, peer_CN, 256);
2213 if (verbosemode)
2214 libbootlog(BOOTLOG_VERBOSE,
2215 "server cert's peer_CN is %s, host is %s", peer_CN, host);
2217 if (strcasecmp(peer_CN, host)) {
2218 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMATCH);
2219 libbootlog(BOOTLOG_CRIT,
2220 "check_cert_chain: Common name doesn't match host name");
2221 libbootlog(BOOTLOG_CRIT,
2222 "peer_CN = %s, host = %s", peer_CN, host);
2223 return (-1);
2226 return (0);
2230 * print_ciphers - Print the list of ciphers for debugging.
2232 * print_ciphers(ssl);
2234 * Arguments:
2235 * ssl - SSL connection.
2237 * Returns:
2238 * none
2240 static void
2241 print_ciphers(SSL *ssl)
2243 SSL_CIPHER *c;
2244 STACK_OF(SSL_CIPHER) *sk;
2245 int i;
2246 const char *name;
2248 if (ssl == NULL)
2249 return;
2251 sk = SSL_get_ciphers(ssl);
2252 if (sk == NULL)
2253 return;
2255 for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
2256 /* LINTED */
2257 c = sk_SSL_CIPHER_value(sk, i);
2258 libbootlog(BOOTLOG_VERBOSE, "%08lx %s", c->id, c->name);
2260 name = SSL_get_cipher_name(ssl);
2261 if (name == NULL)
2262 name = "";
2263 libbootlog(BOOTLOG_VERBOSE, "Current cipher = %s", name);
2267 * read_headerlines - Get the header lines from the server. This reads
2268 * lines until it gets a empty line indicating end of headers.
2270 * ret = read_headerlines(c_id);
2272 * Arguments:
2273 * c_id - Info about the connection being read.
2274 * bread - TRUE if the headerlines are part of the message body.
2276 * Returns:
2277 * 0 - Header lines were read.
2278 * -1 - Error occurred. The errors information is already in
2279 * the error stack.
2281 * Read the lines. If the current line begins with a space or tab, it is
2282 * a continuation. Take the new line and append it to the end of the
2283 * previous line rather than making an entry for another line in
2284 * c_id->resphdr.
2286 * Note that I/O errors are put into the error stack by http_srv_recv(),
2287 * which is called by getaline().
2289 static int
2290 read_headerlines(http_conn_t *c_id, boolean_t bread)
2292 char line[MAXHOSTNAMELEN];
2293 char **new_buf;
2294 char *ptr;
2295 int next;
2296 int cur;
2297 int n;
2299 /* process headers, stop when we get to an empty line */
2300 cur = 0;
2301 next = 0;
2302 while ((n = getaline(c_id, line, sizeof (line), bread)) > 0) {
2304 if (verbosemode)
2305 libbootlog(BOOTLOG_VERBOSE,
2306 "read_headerlines: %s", line);
2308 * See if this is a continuation line (first col is a
2309 * space or a tab)
2311 if (line[0] != ' ' && line[0] != ' ') {
2312 cur = next;
2313 next ++;
2314 new_buf =
2315 realloc(c_id->resphdr, (cur + 1) * sizeof (void *));
2316 if (new_buf == NULL) {
2317 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
2318 return (-1);
2320 c_id->resphdr = new_buf;
2322 c_id->resphdr[cur] = strdup(line);
2323 if (c_id->resphdr[cur] == NULL) {
2324 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
2325 return (-1);
2327 } else {
2328 ptr = line;
2329 while (isspace(*ptr))
2330 ptr ++;
2331 c_id->resphdr[cur] = realloc(c_id->resphdr[cur],
2332 strlen(c_id->resphdr[cur]) + strlen(ptr) + 1);
2333 if (c_id->resphdr[cur] == NULL) {
2334 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOMEM);
2335 return (-1);
2337 (void) strcat(c_id->resphdr[cur], ptr);
2339 ptr = &(c_id->resphdr[cur][strlen(c_id->resphdr[cur]) - 1]);
2340 while (ptr > c_id->resphdr[cur] && isspace(*ptr))
2341 ptr --;
2343 c_id->resp.nresphdrs = next;
2345 /* Cause of any I/O error was already put into error stack. */
2346 return (n >= 0 ? 0 : -1);
2349 static void
2350 free_response(http_conn_t *c_id, int free_boundary)
2352 int i;
2354 /* free memory from previous calls */
2355 if (c_id->resp.statusmsg != NULL) {
2356 free(c_id->resp.statusmsg);
2357 c_id->resp.statusmsg = NULL;
2359 for (i = 0; i < c_id->resp.nresphdrs; i++) {
2360 free(c_id->resphdr[i]);
2361 c_id->resphdr[i] = NULL;
2363 c_id->resp.nresphdrs = 0;
2364 if (c_id->resphdr != NULL) {
2365 free(c_id->resphdr);
2366 c_id->resphdr = NULL;
2369 if (free_boundary && c_id->boundary) {
2370 free(c_id->boundary);
2371 c_id->boundary = NULL;
2372 c_id->is_multipart = B_FALSE;
2376 static int
2377 free_ctx_ssl(http_conn_t *c_id)
2379 int err_ret = 0;
2381 if (c_id->ssl != NULL) {
2382 if (SSL_shutdown(c_id->ssl) <= 0) {
2383 ulong_t err;
2384 while ((err = ERR_get_error()) != 0)
2385 SET_ERR(c_id, ERRSRC_LIBSSL, err);
2386 err_ret = -1;
2388 SSL_free(c_id->ssl);
2389 c_id->ssl = NULL;
2392 if (c_id->fd != -1 && socket_close(c_id->fd) < 0) {
2393 SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2394 err_ret = -1;
2396 c_id->fd = -1;
2398 if (c_id->ctx != NULL) {
2399 SSL_CTX_free(c_id->ctx);
2400 c_id->ctx = NULL;
2403 return (err_ret);
2407 * get_chunk_header - Get a chunk header line
2409 * Arguments:
2410 * c_id - Structure describing the connection in question.
2412 * Returns:
2413 * >=0 - Length of next chunk
2414 * -1 - Error occurred. The error information is in the error stack.
2416 static int
2417 get_chunk_header(http_conn_t *c_id)
2419 char line[MAXHOSTNAMELEN];
2420 char *ptr;
2421 int value;
2422 int ok;
2423 int i;
2426 * Determine whether an extra crlf pair will precede the
2427 * chunk header. For the first one, there is no preceding
2428 * crlf. For later chunks, there is one crlf.
2430 if (c_id->is_firstchunk) {
2431 ok = 1;
2432 c_id->is_firstchunk = B_FALSE;
2433 } else {
2434 ok = ((i = getaline(c_id, line, sizeof (line), B_FALSE)) == 0);
2437 if (ok)
2438 i = getaline(c_id, line, sizeof (line), B_FALSE);
2439 if (!ok || i < 0) {
2441 * If I/O error, the Cause was already put into
2442 * error stack. This is an additional error.
2444 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_NOHEADER);
2445 return (-1);
2448 if (verbosemode)
2449 libbootlog(BOOTLOG_VERBOSE, "get_chunk_header: <%s>", line);
2453 * The first (and probably only) field in the line is the hex
2454 * length of the chunk.
2456 ptr = line;
2457 value = 0;
2458 while (*ptr != '\0' && (i = hexdigit(*ptr)) >= 0) {
2459 value = (value << 4) + i;
2460 ptr ++;
2463 return (value);
2467 * init_bread - Initialize the counters used to read message bodies.
2469 * Arguments:
2470 * c_id - Structure describing the connection in question.
2472 * Returns:
2473 * 0 - Success
2474 * -1 - Error occurred. The error information is in the error stack.
2476 * This routine will determine whether the message body being received is
2477 * chunked or non-chunked. Once determined, the counters used to read
2478 * message bodies will be initialized.
2480 static int
2481 init_bread(http_conn_t *c_id)
2483 char *hdr;
2484 char *ptr;
2485 boolean_t sized = B_FALSE;
2488 * Assume non-chunked reads until proven otherwise.
2490 c_id->is_chunked = B_FALSE;
2491 c_id->is_firstchunk = B_FALSE;
2492 hdr = http_get_header_value(c_id, "Content-Length");
2493 if (hdr != NULL) {
2494 c_id->body_size = strtol(hdr, NULL, 10);
2495 if (c_id->body_size == 0 && errno != 0) {
2496 free(hdr);
2497 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADSIZE);
2498 return (-1);
2500 free(hdr);
2501 sized = B_TRUE;
2505 * If size was not determined above, then see if this is a
2506 * chunked message. Keep in mind that the first chunk size is
2507 * "special".
2509 if (!sized) {
2510 hdr = http_get_header_value(c_id, "Transfer-Encoding");
2511 if (hdr != NULL) {
2512 ptr = eat_ws(hdr);
2513 if (startswith((const char **)&ptr, "chunked;") ||
2514 strcasecmp(ptr, "chunked") == 0) {
2515 c_id->is_firstchunk = B_TRUE;
2516 c_id->is_chunked = B_TRUE;
2518 free(hdr);
2519 if (c_id->is_chunked) {
2520 c_id->body_size = get_chunk_header(c_id);
2521 if (c_id->body_size == -1) {
2523 * Error stack was already set at a
2524 * lower level.
2526 return (-1);
2528 sized = B_TRUE;
2534 * Well, isn't this a fine predicament? It wasn't chunked or
2535 * non-chunked as far as we can tell.
2537 if (!sized) {
2538 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_BADSIZE);
2539 return (-1);
2542 c_id->body_read = 0;
2543 c_id->body_size_tot = c_id->body_size;
2544 c_id->body_read_tot = 0;
2546 return (0);
2550 * get_msgcnt - Get the number of bytes left in the message body or chunk.
2552 * Arguments:
2553 * c_id - Structure describing the connection in question.
2554 * msgcnt - Where to store the message count.
2556 * Returns:
2557 * 0 - Success
2558 * -1 - Error occurred. The error information is in the error stack.
2560 * Note that if the message being read is not chunked, then the byte count
2561 * is simply the message size minus the bytes read thus far. In the case of
2562 * chunked messages, the byte count returned will be the number of bytes
2563 * left in the chunk. If the current chunk has been exhausted, then this
2564 * routine will determine the size of the next chunk. When the next chunk
2565 * size is zero, the message has been read in its entirety.
2567 static int
2568 get_msgcnt(http_conn_t *c_id, ssize_t *msgcnt)
2571 * If there are more bytes in the message, then return.
2573 *msgcnt = c_id->body_size - c_id->body_read;
2574 if (*msgcnt != 0) {
2575 return (0);
2578 * If this is not a chunked message and the body has been
2579 * read, then we're done.
2581 if (!c_id->is_chunked) {
2582 return (0);
2586 * We're looking at a chunked message whose immediate
2587 * chunk has been totally processed. See if there is
2588 * another chunk.
2590 c_id->body_size = get_chunk_header(c_id);
2591 if (c_id->body_size == -1) {
2593 * Error stack was already set at a
2594 * lower level.
2596 return (-1);
2600 * No bytes of this chunk have been processed yet.
2602 c_id->body_read = 0;
2605 * A zero length chunk signals the end of the
2606 * message body and chunking.
2608 if (c_id->body_size == 0) {
2609 c_id->is_chunked = B_FALSE;
2610 return (0);
2614 * There is another chunk.
2616 c_id->body_size_tot += c_id->body_size;
2617 *msgcnt = c_id->body_size - c_id->body_read;
2619 return (0);
2623 * getaline - Get lines of data from the HTTP response, up to 'len' bytes.
2624 * NOTE: the line will not end with a NULL if all 'len' bytes
2625 * were read.
2627 * Arguments:
2628 * c_id - Structure describing the connection in question.
2629 * line - Where to store the data.
2630 * len - Maximum number of bytes in the line.
2631 * bread - TRUE if the lines are part of the message body.
2633 * Returns:
2634 * >=0 - The number of bytes successfully read.
2635 * <0 - An error occurred. This is (the number of bytes gotten + 1),
2636 * negated. In other words, if 'n' bytes were read and then an
2637 * error occurred, this will return (-(n+1)). So zero bytes read
2638 * and then an error occurs, this will return -1. If 1 bytes
2639 * was read, it will return -2, etc.
2641 * Specifics of the error can be gotten using http_get_lasterr();
2643 * Note that I/O errors are put into the error stack by http_srv_recv().1
2645 static int
2646 getaline(http_conn_t *c_id, char *line, int len, boolean_t bread)
2648 int i = 0;
2649 ssize_t msgcnt = 0;
2650 ssize_t cnt;
2652 while (i < len) {
2654 * Special processing required for message body reads.
2656 if (bread) {
2658 * See if there is another chunk. Obviously, in the
2659 * case of non-chunked messages, there won't be.
2660 * But in either case, chunked or not, if msgcnt
2661 * is still zero after the call to get_msgcnt(),
2662 * then we're done.
2664 if (msgcnt == 0) {
2665 if (get_msgcnt(c_id, &msgcnt) == -1) {
2666 return (-(i+1));
2668 if (msgcnt == 0) {
2669 break;
2672 cnt = MIN(msgcnt, sizeof (c_id->inbuf.buf));
2673 } else {
2674 cnt = sizeof (c_id->inbuf.buf);
2677 /* read more data if buffer empty */
2678 if (c_id->inbuf.i == c_id->inbuf.n) {
2679 c_id->inbuf.i = 0;
2680 c_id->inbuf.n = http_srv_recv(c_id, c_id->inbuf.buf,
2681 cnt);
2682 if (c_id->inbuf.n == 0) {
2683 return (i);
2685 if (c_id->inbuf.n < 0) {
2686 return (-(i+1));
2689 /* skip CR */
2690 if (c_id->inbuf.buf[c_id->inbuf.i] == '\r') {
2691 INC_BREAD_CNT(bread, msgcnt);
2692 c_id->inbuf.i++;
2693 continue;
2695 if (c_id->inbuf.buf[c_id->inbuf.i] == '\n') {
2696 INC_BREAD_CNT(bread, msgcnt);
2697 c_id->inbuf.i++;
2698 line[i] = '\0';
2699 return (i);
2701 /* copy buf from internal buffer */
2702 INC_BREAD_CNT(bread, msgcnt);
2703 line[i++] = c_id->inbuf.buf[c_id->inbuf.i++];
2705 return (i);
2709 * getbytes - Get a block from the HTTP response. Used for the HTTP body.
2711 * Arguments:
2712 * c_id - Structure describing the connection in question.
2713 * line - Where to store the data.
2714 * len - Maximum number of bytes in the block.
2716 * Returns:
2717 * >=0 - The number of bytes successfully read.
2718 * <0 - An error occurred. This is (the number of bytes gotten + 1),
2719 * negated. In other words, if 'n' bytes were read and then an
2720 * error occurred, this will return (-(n+1)). So zero bytes read
2721 * and then an error occurs, this will return -1. If 1 bytes
2722 * was read, it will return -2, etc.
2724 * Specifics of the error can be gotten using http_get_lasterr();
2726 * Note that all reads performed here assume that a message body is being
2727 * read. If this changes in the future, then the logic should more closely
2728 * resemble getaline().
2730 * Note that I/O errors are put into the error stack by http_srv_recv().
2732 static int
2733 getbytes(http_conn_t *c_id, char *line, int len)
2735 int i = 0;
2736 ssize_t msgcnt = 0;
2737 ssize_t cnt;
2738 int nbytes;
2740 while (i < len) {
2742 * See if there is another chunk. Obviously, in the
2743 * case of non-chunked messages, there won't be.
2744 * But in either case, chunked or not, if msgcnt
2745 * is still zero after the call to get_msgcnt(), then
2746 * we're done.
2748 if (msgcnt == 0) {
2749 if (get_msgcnt(c_id, &msgcnt) == -1) {
2750 return (-(i+1));
2752 if (msgcnt == 0) {
2753 break;
2757 cnt = MIN(msgcnt, len - i);
2759 if (c_id->inbuf.n != c_id->inbuf.i) {
2760 nbytes = (int)MIN(cnt, c_id->inbuf.n - c_id->inbuf.i);
2761 (void) memcpy(line, &c_id->inbuf.buf[c_id->inbuf.i],
2762 nbytes);
2763 c_id->inbuf.i += nbytes;
2764 } else {
2765 nbytes = http_srv_recv(c_id, line, cnt);
2766 if (nbytes == 0) {
2767 return (i);
2769 if (nbytes < 0) {
2770 return (-(i+1));
2774 i += nbytes;
2775 line += nbytes;
2776 msgcnt -= nbytes;
2777 c_id->body_read += nbytes;
2778 c_id->body_read_tot += nbytes;
2781 return (i);
2784 static int
2785 http_srv_send(http_conn_t *c_id, const void *buf, size_t nbyte)
2787 int retval;
2789 if (c_id->ssl != NULL) {
2790 if ((retval = SSL_write(c_id->ssl, buf, nbyte)) <= 0) {
2791 handle_ssl_error(c_id, retval);
2793 return (retval);
2794 } else {
2795 retval = socket_write(c_id->fd, buf, nbyte, &c_id->host_addr);
2796 if (retval < 0) {
2797 SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2798 return (-1);
2800 return (retval);
2804 static int
2805 http_srv_recv(http_conn_t *c_id, void *buf, size_t nbyte)
2807 int retval;
2809 if (c_id->ssl != NULL) {
2810 if ((retval = SSL_read(c_id->ssl, buf, nbyte)) <= 0) {
2811 handle_ssl_error(c_id, retval);
2813 return (retval);
2814 } else {
2815 retval = socket_read(c_id->fd, buf, nbyte, c_id->read_timeout);
2816 if (retval < 0) {
2817 SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2818 return (-1);
2820 return (retval);
2824 static boolean_t
2825 http_check_conn(http_conn_t *c_id)
2827 early_err = 0;
2828 if (c_id == NULL || c_id->signature != HTTP_CONN_INFO) {
2829 early_err = EHTTP_BADARG;
2830 return (B_FALSE);
2832 RESET_ERR(c_id);
2833 return (B_TRUE);
2836 static void
2837 handle_ssl_error(http_conn_t *c_id, int retval)
2839 ulong_t err;
2841 err = SSL_get_error(c_id->ssl, retval);
2843 switch (err) {
2844 case SSL_ERROR_NONE:
2845 return;
2847 case SSL_ERROR_ZERO_RETURN:
2848 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_CONCLOSED);
2849 return;
2851 case SSL_ERROR_WANT_READ:
2852 case SSL_ERROR_WANT_WRITE:
2853 case SSL_ERROR_WANT_CONNECT:
2854 case SSL_ERROR_WANT_X509_LOOKUP:
2855 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_UNEXPECTED);
2856 return;
2858 case SSL_ERROR_SYSCALL:
2859 err = ERR_get_error();
2860 if (err == 0)
2861 SET_ERR(c_id, ERRSRC_LIBHTTP, EHTTP_EOFERR);
2862 else if (err == (ulong_t)-1)
2863 SET_ERR(c_id, ERRSRC_SYSTEM, errno);
2864 else {
2865 SET_ERR(c_id, ERRSRC_LIBSSL, err);
2866 while ((err = ERR_get_error()) != 0)
2867 SET_ERR(c_id, ERRSRC_LIBSSL, err);
2869 return;
2871 case SSL_ERROR_SSL:
2872 while ((err = ERR_get_error()) != 0) {
2873 SET_ERR(c_id, ERRSRC_LIBSSL, err);
2875 return;
2879 static int
2880 count_digits(int value)
2882 int count = 1;
2884 if (value < 0) {
2885 count++;
2886 value = -value;
2889 while (value > 9) {
2890 value /= 10;
2891 count++;
2893 return (count);
2896 static int
2897 hexdigit(char ch)
2899 if (ch >= '0' && ch <= '9')
2900 return (ch - '0');
2901 if (ch >= 'A' && ch <= 'F')
2902 return (ch - 'A' + 10);
2903 if (ch >= 'a' && ch <= 'f')
2904 return (ch - 'a' + 10);
2905 return (-1);
2908 static char *
2909 eat_ws(const char *buf)
2911 char *ptr = (char *)buf;
2913 while (isspace(*ptr))
2914 ptr++;
2916 return (ptr);
2919 static boolean_t
2920 startswith(const char **strp, const char *starts)
2922 int len = strlen(starts);
2924 if (strncasecmp(*strp, starts, len) == 0) {
2925 *strp += len;
2926 return (B_TRUE);
2928 return (B_FALSE);