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