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