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