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