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