1*5c51f124SMoriah Waterland /* 2*5c51f124SMoriah Waterland * CDDL HEADER START 3*5c51f124SMoriah Waterland * 4*5c51f124SMoriah Waterland * The contents of this file are subject to the terms of the 5*5c51f124SMoriah Waterland * Common Development and Distribution License (the "License"). 6*5c51f124SMoriah Waterland * You may not use this file except in compliance with the License. 7*5c51f124SMoriah Waterland * 8*5c51f124SMoriah Waterland * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5c51f124SMoriah Waterland * or http://www.opensolaris.org/os/licensing. 10*5c51f124SMoriah Waterland * See the License for the specific language governing permissions 11*5c51f124SMoriah Waterland * and limitations under the License. 12*5c51f124SMoriah Waterland * 13*5c51f124SMoriah Waterland * When distributing Covered Code, include this CDDL HEADER in each 14*5c51f124SMoriah Waterland * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5c51f124SMoriah Waterland * If applicable, add the following below this CDDL HEADER, with the 16*5c51f124SMoriah Waterland * fields enclosed by brackets "[]" replaced with your own identifying 17*5c51f124SMoriah Waterland * information: Portions Copyright [yyyy] [name of copyright owner] 18*5c51f124SMoriah Waterland * 19*5c51f124SMoriah Waterland * CDDL HEADER END 20*5c51f124SMoriah Waterland */ 21*5c51f124SMoriah Waterland 22*5c51f124SMoriah Waterland /* 23*5c51f124SMoriah Waterland * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*5c51f124SMoriah Waterland * Use is subject to license terms. 25*5c51f124SMoriah Waterland */ 26*5c51f124SMoriah Waterland 27*5c51f124SMoriah Waterland /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*5c51f124SMoriah Waterland /* All Rights Reserved */ 29*5c51f124SMoriah Waterland 30*5c51f124SMoriah Waterland 31*5c51f124SMoriah Waterland #include <stdio.h> 32*5c51f124SMoriah Waterland #include <limits.h> 33*5c51f124SMoriah Waterland #include <stdlib.h> 34*5c51f124SMoriah Waterland #include <unistd.h> 35*5c51f124SMoriah Waterland #include <string.h> 36*5c51f124SMoriah Waterland #include <pkglocs.h> 37*5c51f124SMoriah Waterland #include <locale.h> 38*5c51f124SMoriah Waterland #include <libintl.h> 39*5c51f124SMoriah Waterland #include <libgen.h> 40*5c51f124SMoriah Waterland #include <signal.h> 41*5c51f124SMoriah Waterland #include <sys/stat.h> 42*5c51f124SMoriah Waterland #include <sys/statvfs.h> 43*5c51f124SMoriah Waterland #include <sys/types.h> 44*5c51f124SMoriah Waterland #include <fcntl.h> 45*5c51f124SMoriah Waterland #include <dirent.h> 46*5c51f124SMoriah Waterland #include <boot_http.h> 47*5c51f124SMoriah Waterland #include <errno.h> 48*5c51f124SMoriah Waterland #include <ctype.h> 49*5c51f124SMoriah Waterland #include <openssl/pkcs7.h> 50*5c51f124SMoriah Waterland #include <openssl/ocsp.h> 51*5c51f124SMoriah Waterland #include <openssl/pkcs12.h> 52*5c51f124SMoriah Waterland #include <openssl/err.h> 53*5c51f124SMoriah Waterland #include <openssl/x509.h> 54*5c51f124SMoriah Waterland #include <openssl/pem.h> 55*5c51f124SMoriah Waterland #include <openssl/evp.h> 56*5c51f124SMoriah Waterland #include <openssl/rand.h> 57*5c51f124SMoriah Waterland #include <openssl/x509v3.h> 58*5c51f124SMoriah Waterland #include "pkglib.h" 59*5c51f124SMoriah Waterland #include "pkglibmsgs.h" 60*5c51f124SMoriah Waterland #include "pkglocale.h" 61*5c51f124SMoriah Waterland #include "keystore.h" 62*5c51f124SMoriah Waterland #include "pkgweb.h" 63*5c51f124SMoriah Waterland #include "pkgerr.h" 64*5c51f124SMoriah Waterland #include "p12lib.h" 65*5c51f124SMoriah Waterland 66*5c51f124SMoriah Waterland /* fixed format when making an OCSP request */ 67*5c51f124SMoriah Waterland #define OCSP_REQUEST_FORMAT \ 68*5c51f124SMoriah Waterland "POST %s HTTP/1.0\r\n" \ 69*5c51f124SMoriah Waterland "Content-Type: application/ocsp-request\r\n" \ 70*5c51f124SMoriah Waterland "Content-Length: %d\r\n\r\n" 71*5c51f124SMoriah Waterland 72*5c51f124SMoriah Waterland /* 73*5c51f124SMoriah Waterland * no security is afforded by using this phrase to "encrypt" CA certificates, 74*5c51f124SMoriah Waterland * but it might aid in debugging and has to be non-null 75*5c51f124SMoriah Waterland */ 76*5c51f124SMoriah Waterland #define WEB_CA_PHRASE "schizophrenic" 77*5c51f124SMoriah Waterland 78*5c51f124SMoriah Waterland /* This one needs the ': ' at the end */ 79*5c51f124SMoriah Waterland #define CONTENT_TYPE_HDR "Content-Type" 80*5c51f124SMoriah Waterland #define CONTENT_DISPOSITION_HDR "Content-Disposition" 81*5c51f124SMoriah Waterland #define CONTENT_OCSP_RESP "application/ocsp-response" 82*5c51f124SMoriah Waterland #define CONTENT_LENGTH_HDR "Content-Length" 83*5c51f124SMoriah Waterland #define LAST_MODIFIED_HDR "Last-Modified" 84*5c51f124SMoriah Waterland #define OCSP_BUFSIZ 1024 85*5c51f124SMoriah Waterland 86*5c51f124SMoriah Waterland /* 87*5c51f124SMoriah Waterland * default amount of time that is allowed for error when checking 88*5c51f124SMoriah Waterland * OCSP response validity. 89*5c51f124SMoriah Waterland * For example, if this is set to 5 minutes, then if a response 90*5c51f124SMoriah Waterland * is issued that is valid from 12:00 to 1:00, then we will 91*5c51f124SMoriah Waterland * accept it if the local time is between 11:55 and 1:05. 92*5c51f124SMoriah Waterland * This takes care of not-quite-synchronized server and client clocks. 93*5c51f124SMoriah Waterland */ 94*5c51f124SMoriah Waterland #define OCSP_VALIDITY_PERIOD (5 * 60) 95*5c51f124SMoriah Waterland 96*5c51f124SMoriah Waterland /* this value is defined by getpassphrase(3c) manpage */ 97*5c51f124SMoriah Waterland #define MAX_PHRASELEN 257 98*5c51f124SMoriah Waterland 99*5c51f124SMoriah Waterland /* Max length of "enter password again" prompt message */ 100*5c51f124SMoriah Waterland #define MAX_VERIFY_MSGLEN 1024 101*5c51f124SMoriah Waterland 102*5c51f124SMoriah Waterland /* local prototypes */ 103*5c51f124SMoriah Waterland static boolean_t remove_dwnld_file(char *); 104*5c51f124SMoriah Waterland static boolean_t get_ENV_proxyport(PKG_ERR *, ushort_t *); 105*5c51f124SMoriah Waterland static boolean_t make_link(char *, char *); 106*5c51f124SMoriah Waterland static WebStatus web_send_request(PKG_ERR *, int, int, int); 107*5c51f124SMoriah Waterland static boolean_t web_eval_headers(PKG_ERR *); 108*5c51f124SMoriah Waterland static WebStatus web_get_file(PKG_ERR *, char *, int, char **); 109*5c51f124SMoriah Waterland static boolean_t ck_dwnld_dir_space(PKG_ERR *, char *, ulong_t); 110*5c51f124SMoriah Waterland static WebStatus web_connect(PKG_ERR *); 111*5c51f124SMoriah Waterland static boolean_t web_setup(PKG_ERR *); 112*5c51f124SMoriah Waterland static boolean_t check_dwnld_dir(PKG_ERR *, char *); 113*5c51f124SMoriah Waterland static boolean_t parse_url_proxy(PKG_ERR *, char *, char *, ushort_t); 114*5c51f124SMoriah Waterland static boolean_t web_disconnect(void); 115*5c51f124SMoriah Waterland static char *get_unique_filename(char *, char *); 116*5c51f124SMoriah Waterland static boolean_t get_ENV_proxy(PKG_ERR *, char **); 117*5c51f124SMoriah Waterland static char *condense_lastmodified(char *); 118*5c51f124SMoriah Waterland static int web_verify(int, X509_STORE_CTX *); 119*5c51f124SMoriah Waterland static int get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); 120*5c51f124SMoriah Waterland static boolean_t get_ocsp_uri(X509 *, char **); 121*5c51f124SMoriah Waterland static OCSPStatus ocsp_verify(PKG_ERR *, X509 *, X509 *, char *, url_hport_t *, 122*5c51f124SMoriah Waterland STACK_OF(X509) *); 123*5c51f124SMoriah Waterland static char *get_time_string(ASN1_GENERALIZEDTIME *); 124*5c51f124SMoriah Waterland static char *write_ca_file(PKG_ERR *, char *, STACK_OF(X509) *, char *); 125*5c51f124SMoriah Waterland static boolean_t _get_random_info(void *, int); 126*5c51f124SMoriah Waterland static boolean_t init_session(void); 127*5c51f124SMoriah Waterland static void progress_setup(int, ulong_t); 128*5c51f124SMoriah Waterland static void progress_report(int, ulong_t); 129*5c51f124SMoriah Waterland static void progress_finish(int); 130*5c51f124SMoriah Waterland static char *replace_token(char *, char, char); 131*5c51f124SMoriah Waterland static void dequote(char *); 132*5c51f124SMoriah Waterland static void trim(char *); 133*5c51f124SMoriah Waterland 134*5c51f124SMoriah Waterland 135*5c51f124SMoriah Waterland /* 136*5c51f124SMoriah Waterland * structure used to hold data passed back to the 137*5c51f124SMoriah Waterland * X509 verify callback routine in validate_signature() 138*5c51f124SMoriah Waterland */ 139*5c51f124SMoriah Waterland typedef struct { 140*5c51f124SMoriah Waterland url_hport_t *proxy; 141*5c51f124SMoriah Waterland PKG_ERR *err; 142*5c51f124SMoriah Waterland STACK_OF(X509) *cas; 143*5c51f124SMoriah Waterland } verify_cb_data_t; 144*5c51f124SMoriah Waterland 145*5c51f124SMoriah Waterland /* Progress bar variables */ 146*5c51f124SMoriah Waterland static ulong_t const_increment, const_divider, completed, const_completed; 147*5c51f124SMoriah Waterland 148*5c51f124SMoriah Waterland /* current network backoff wait period */ 149*5c51f124SMoriah Waterland static int cur_backoff = 0; 150*5c51f124SMoriah Waterland 151*5c51f124SMoriah Waterland /* download session context handle */ 152*5c51f124SMoriah Waterland static WEB_SESSION *ps; 153*5c51f124SMoriah Waterland 154*5c51f124SMoriah Waterland static int webpkg_install = 0; 155*5c51f124SMoriah Waterland static char *prompt = NULL; 156*5c51f124SMoriah Waterland static char *passarg = NULL; 157*5c51f124SMoriah Waterland 158*5c51f124SMoriah Waterland 159*5c51f124SMoriah Waterland /* ~~~~~~~~~~~~~~ Public Functions ~~~~~~~~~~~~~~~~~~~ */ 160*5c51f124SMoriah Waterland 161*5c51f124SMoriah Waterland /* 162*5c51f124SMoriah Waterland * Name: set_prompt 163*5c51f124SMoriah Waterland * Description: Specifies the prompt to use with the pkglib 164*5c51f124SMoriah Waterland * passphrase callback routine. 165*5c51f124SMoriah Waterland * 166*5c51f124SMoriah Waterland * Arguments: newprompt - The prompt to display 167*5c51f124SMoriah Waterland * 168*5c51f124SMoriah Waterland * Returns : NONE 169*5c51f124SMoriah Waterland */ 170*5c51f124SMoriah Waterland void 171*5c51f124SMoriah Waterland set_passphrase_prompt(char *newprompt) 172*5c51f124SMoriah Waterland { 173*5c51f124SMoriah Waterland prompt = newprompt; 174*5c51f124SMoriah Waterland } 175*5c51f124SMoriah Waterland 176*5c51f124SMoriah Waterland /* 177*5c51f124SMoriah Waterland * Name: set_passarg 178*5c51f124SMoriah Waterland * Description: Specifies the passphrase retrieval method 179*5c51f124SMoriah Waterland * to use with the pkglib 180*5c51f124SMoriah Waterland * passphrase callback routine. 181*5c51f124SMoriah Waterland * 182*5c51f124SMoriah Waterland * Arguments: newpassarg - The new password retrieval arg 183*5c51f124SMoriah Waterland * 184*5c51f124SMoriah Waterland * Returns : NONE 185*5c51f124SMoriah Waterland */ 186*5c51f124SMoriah Waterland void 187*5c51f124SMoriah Waterland set_passphrase_passarg(char *newpassarg) 188*5c51f124SMoriah Waterland { 189*5c51f124SMoriah Waterland passarg = newpassarg; 190*5c51f124SMoriah Waterland } 191*5c51f124SMoriah Waterland 192*5c51f124SMoriah Waterland /* 193*5c51f124SMoriah Waterland * Name: get_proxy_port 194*5c51f124SMoriah Waterland * Description: Resolves proxy specification 195*5c51f124SMoriah Waterland * 196*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 197*5c51f124SMoriah Waterland * proxy - Location to store result - if *proxy is not 198*5c51f124SMoriah Waterland * null, then it will be validated, but not changed 199*5c51f124SMoriah Waterland * 200*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 201*5c51f124SMoriah Waterland * on success, *proxy and *port are set to either 202*5c51f124SMoriah Waterland * the user-supplied proxy and port, or the 203*5c51f124SMoriah Waterland * ones found in the environment variables 204*5c51f124SMoriah Waterland * HTTPPROXY and/or HTTPROXYPORT 205*5c51f124SMoriah Waterland */ 206*5c51f124SMoriah Waterland boolean_t 207*5c51f124SMoriah Waterland get_proxy_port(PKG_ERR *err, char **proxy, ushort_t *port) 208*5c51f124SMoriah Waterland { 209*5c51f124SMoriah Waterland if (*proxy != NULL) { 210*5c51f124SMoriah Waterland if (!path_valid(*proxy)) { 211*5c51f124SMoriah Waterland /* bad proxy supplied */ 212*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 213*5c51f124SMoriah Waterland gettext(ERR_BAD_PROXY), *proxy); 214*5c51f124SMoriah Waterland return (B_FALSE); 215*5c51f124SMoriah Waterland } 216*5c51f124SMoriah Waterland if (!get_ENV_proxyport(err, port)) { 217*5c51f124SMoriah Waterland /* env set, but bad */ 218*5c51f124SMoriah Waterland return (B_FALSE); 219*5c51f124SMoriah Waterland } 220*5c51f124SMoriah Waterland } else { 221*5c51f124SMoriah Waterland if (!get_ENV_proxy(err, proxy)) { 222*5c51f124SMoriah Waterland /* environment variable set, but bad */ 223*5c51f124SMoriah Waterland return (B_FALSE); 224*5c51f124SMoriah Waterland } 225*5c51f124SMoriah Waterland if ((*proxy != NULL) && !path_valid(*proxy)) { 226*5c51f124SMoriah Waterland /* env variable set, but bad */ 227*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 228*5c51f124SMoriah Waterland gettext(ERR_BAD_PROXY), *proxy); 229*5c51f124SMoriah Waterland return (B_FALSE); 230*5c51f124SMoriah Waterland } 231*5c51f124SMoriah Waterland if (!get_ENV_proxyport(err, port)) { 232*5c51f124SMoriah Waterland /* env variable set, but bad */ 233*5c51f124SMoriah Waterland return (B_FALSE); 234*5c51f124SMoriah Waterland } 235*5c51f124SMoriah Waterland } 236*5c51f124SMoriah Waterland return (B_TRUE); 237*5c51f124SMoriah Waterland } 238*5c51f124SMoriah Waterland 239*5c51f124SMoriah Waterland /* 240*5c51f124SMoriah Waterland * Name: path_valid 241*5c51f124SMoriah Waterland * Description: Checks a string for being a valid path 242*5c51f124SMoriah Waterland * 243*5c51f124SMoriah Waterland * Arguments: path - path to validate 244*5c51f124SMoriah Waterland * 245*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise. 246*5c51f124SMoriah Waterland * B_FALSE means path was null, too long (>PATH_MAX), 247*5c51f124SMoriah Waterland * or too short (<1) 248*5c51f124SMoriah Waterland */ 249*5c51f124SMoriah Waterland boolean_t 250*5c51f124SMoriah Waterland path_valid(char *path) 251*5c51f124SMoriah Waterland { 252*5c51f124SMoriah Waterland if (path == NULL) { 253*5c51f124SMoriah Waterland return (B_FALSE); 254*5c51f124SMoriah Waterland } else if (strlen(path) > PATH_MAX) { 255*5c51f124SMoriah Waterland return (B_FALSE); 256*5c51f124SMoriah Waterland } else if (strlen(path) >= 1) { 257*5c51f124SMoriah Waterland return (B_TRUE); 258*5c51f124SMoriah Waterland } else { 259*5c51f124SMoriah Waterland /* path < 1 */ 260*5c51f124SMoriah Waterland return (B_FALSE); 261*5c51f124SMoriah Waterland } 262*5c51f124SMoriah Waterland } 263*5c51f124SMoriah Waterland 264*5c51f124SMoriah Waterland /* 265*5c51f124SMoriah Waterland * Name: web_cleanup 266*5c51f124SMoriah Waterland * Description: Deletes temp files, closes, frees memory taken 267*5c51f124SMoriah Waterland * by 'ps' static structure 268*5c51f124SMoriah Waterland * 269*5c51f124SMoriah Waterland * Arguments: none 270*5c51f124SMoriah Waterland * 271*5c51f124SMoriah Waterland * Returns : none 272*5c51f124SMoriah Waterland */ 273*5c51f124SMoriah Waterland void 274*5c51f124SMoriah Waterland web_cleanup(void) 275*5c51f124SMoriah Waterland { 276*5c51f124SMoriah Waterland PKG_ERR *err; 277*5c51f124SMoriah Waterland 278*5c51f124SMoriah Waterland if (ps == NULL) 279*5c51f124SMoriah Waterland return; 280*5c51f124SMoriah Waterland 281*5c51f124SMoriah Waterland err = pkgerr_new(); 282*5c51f124SMoriah Waterland 283*5c51f124SMoriah Waterland if (ps->keystore) { 284*5c51f124SMoriah Waterland (void) close_keystore(err, ps->keystore, NULL); 285*5c51f124SMoriah Waterland } 286*5c51f124SMoriah Waterland 287*5c51f124SMoriah Waterland ps->keystore = NULL; 288*5c51f124SMoriah Waterland 289*5c51f124SMoriah Waterland pkgerr_free(err); 290*5c51f124SMoriah Waterland 291*5c51f124SMoriah Waterland if (ps->uniqfile) { 292*5c51f124SMoriah Waterland (void) remove_dwnld_file(ps->uniqfile); 293*5c51f124SMoriah Waterland free(ps->uniqfile); 294*5c51f124SMoriah Waterland ps->uniqfile = NULL; 295*5c51f124SMoriah Waterland } 296*5c51f124SMoriah Waterland if (ps->link) { 297*5c51f124SMoriah Waterland (void) remove_dwnld_file(ps->link); 298*5c51f124SMoriah Waterland free(ps->link); 299*5c51f124SMoriah Waterland ps->link = NULL; 300*5c51f124SMoriah Waterland } 301*5c51f124SMoriah Waterland if (ps->dwnld_dir) { 302*5c51f124SMoriah Waterland (void) rmdir(ps->dwnld_dir); 303*5c51f124SMoriah Waterland ps->dwnld_dir = NULL; 304*5c51f124SMoriah Waterland } 305*5c51f124SMoriah Waterland if (ps->errstr) { 306*5c51f124SMoriah Waterland free(ps->errstr); 307*5c51f124SMoriah Waterland ps->errstr = NULL; 308*5c51f124SMoriah Waterland } 309*5c51f124SMoriah Waterland 310*5c51f124SMoriah Waterland if (ps->content) { 311*5c51f124SMoriah Waterland free(ps->content); 312*5c51f124SMoriah Waterland ps->content = NULL; 313*5c51f124SMoriah Waterland } 314*5c51f124SMoriah Waterland 315*5c51f124SMoriah Waterland if (ps->resp) { 316*5c51f124SMoriah Waterland http_free_respinfo(ps->resp); 317*5c51f124SMoriah Waterland ps->resp = NULL; 318*5c51f124SMoriah Waterland } 319*5c51f124SMoriah Waterland 320*5c51f124SMoriah Waterland if (ps) { 321*5c51f124SMoriah Waterland free(ps); 322*5c51f124SMoriah Waterland ps = NULL; 323*5c51f124SMoriah Waterland } 324*5c51f124SMoriah Waterland } 325*5c51f124SMoriah Waterland 326*5c51f124SMoriah Waterland /* 327*5c51f124SMoriah Waterland * Name: web_session_control 328*5c51f124SMoriah Waterland * Description: Downloads an arbitrary URL and saves to disk. 329*5c51f124SMoriah Waterland * 330*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 331*5c51f124SMoriah Waterland * url - URL pointing to content to download - can be 332*5c51f124SMoriah Waterland * http:// or https:// 333*5c51f124SMoriah Waterland * dwnld_dir - Directory to download into 334*5c51f124SMoriah Waterland * keystore - keystore to use for accessing trusted 335*5c51f124SMoriah Waterland * certs when downloading using SSL 336*5c51f124SMoriah Waterland * proxy - HTTP proxy to use, or NULL for no proxy 337*5c51f124SMoriah Waterland * proxy_port - HTTP proxy port to use, ignored 338*5c51f124SMoriah Waterland * if proxy is NULL 339*5c51f124SMoriah Waterland * passarg - method to retrieve password 340*5c51f124SMoriah Waterland * retries - # of times to retry download before 341*5c51f124SMoriah Waterland * giving up 342*5c51f124SMoriah Waterland * timeout - how long to wait before retrying, 343*5c51f124SMoriah Waterland * when download is interrupted 344*5c51f124SMoriah Waterland * nointeract - if non-zero, do not output 345*5c51f124SMoriah Waterland * download progress to screen 346*5c51f124SMoriah Waterland * 347*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 348*5c51f124SMoriah Waterland */ 349*5c51f124SMoriah Waterland boolean_t 350*5c51f124SMoriah Waterland web_session_control(PKG_ERR *err, char *url, char *dwnld_dir, 351*5c51f124SMoriah Waterland keystore_handle_t keystore, char *proxy, ushort_t proxy_port, 352*5c51f124SMoriah Waterland int retries, int timeout, int nointeract, char **fname) 353*5c51f124SMoriah Waterland { 354*5c51f124SMoriah Waterland int i; 355*5c51f124SMoriah Waterland boolean_t ret = B_TRUE; 356*5c51f124SMoriah Waterland boolean_t retrieved = B_FALSE; 357*5c51f124SMoriah Waterland 358*5c51f124SMoriah Waterland if (!init_session()) { 359*5c51f124SMoriah Waterland ret = B_FALSE; 360*5c51f124SMoriah Waterland goto cleanup; 361*5c51f124SMoriah Waterland } 362*5c51f124SMoriah Waterland 363*5c51f124SMoriah Waterland if (!parse_url_proxy(err, url, proxy, proxy_port)) { 364*5c51f124SMoriah Waterland ret = B_FALSE; 365*5c51f124SMoriah Waterland goto cleanup; 366*5c51f124SMoriah Waterland } 367*5c51f124SMoriah Waterland 368*5c51f124SMoriah Waterland ps->timeout = timeout; 369*5c51f124SMoriah Waterland 370*5c51f124SMoriah Waterland if (keystore != NULL) 371*5c51f124SMoriah Waterland ps->keystore = keystore; 372*5c51f124SMoriah Waterland 373*5c51f124SMoriah Waterland if (dwnld_dir != NULL) 374*5c51f124SMoriah Waterland ps->dwnld_dir = xstrdup(dwnld_dir); 375*5c51f124SMoriah Waterland else { 376*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_NO_DWNLD_DIR)); 377*5c51f124SMoriah Waterland ret = B_FALSE; 378*5c51f124SMoriah Waterland goto cleanup; 379*5c51f124SMoriah Waterland } 380*5c51f124SMoriah Waterland 381*5c51f124SMoriah Waterland if (!check_dwnld_dir(err, dwnld_dir)) { 382*5c51f124SMoriah Waterland ret = B_FALSE; 383*5c51f124SMoriah Waterland goto cleanup; 384*5c51f124SMoriah Waterland } 385*5c51f124SMoriah Waterland 386*5c51f124SMoriah Waterland for (i = 0; i < retries && !retrieved; i++) { 387*5c51f124SMoriah Waterland if (!web_setup(err)) { 388*5c51f124SMoriah Waterland ret = B_FALSE; 389*5c51f124SMoriah Waterland goto cleanup; 390*5c51f124SMoriah Waterland } 391*5c51f124SMoriah Waterland 392*5c51f124SMoriah Waterland switch (web_connect(err)) { 393*5c51f124SMoriah Waterland /* time out and wait a little bit for these failures */ 394*5c51f124SMoriah Waterland case WEB_OK: 395*5c51f124SMoriah Waterland /* were able to connect */ 396*5c51f124SMoriah Waterland reset_backoff(); 397*5c51f124SMoriah Waterland break; 398*5c51f124SMoriah Waterland case WEB_TIMEOUT: 399*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_TIMEOUT)); 400*5c51f124SMoriah Waterland (void) web_disconnect(); 401*5c51f124SMoriah Waterland backoff(); 402*5c51f124SMoriah Waterland continue; 403*5c51f124SMoriah Waterland 404*5c51f124SMoriah Waterland case WEB_CONNREFUSED: 405*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_CONNREF), 406*5c51f124SMoriah Waterland ps->url.hport.hostname); 407*5c51f124SMoriah Waterland (void) web_disconnect(); 408*5c51f124SMoriah Waterland backoff(); 409*5c51f124SMoriah Waterland continue; 410*5c51f124SMoriah Waterland case WEB_HOSTDOWN: 411*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_HOSTDWN), 412*5c51f124SMoriah Waterland ps->url.hport.hostname); 413*5c51f124SMoriah Waterland (void) web_disconnect(); 414*5c51f124SMoriah Waterland backoff(); 415*5c51f124SMoriah Waterland continue; 416*5c51f124SMoriah Waterland 417*5c51f124SMoriah Waterland default: 418*5c51f124SMoriah Waterland /* every other failure is a hard failure, so bail */ 419*5c51f124SMoriah Waterland ret = B_FALSE; 420*5c51f124SMoriah Waterland goto cleanup; 421*5c51f124SMoriah Waterland } 422*5c51f124SMoriah Waterland 423*5c51f124SMoriah Waterland switch (web_send_request(err, HTTP_REQ_TYPE_HEAD, 424*5c51f124SMoriah Waterland ps->data.cur_pos, ps->data.content_length)) { 425*5c51f124SMoriah Waterland case WEB_OK: 426*5c51f124SMoriah Waterland /* were able to connect */ 427*5c51f124SMoriah Waterland reset_backoff(); 428*5c51f124SMoriah Waterland break; 429*5c51f124SMoriah Waterland case WEB_TIMEOUT: 430*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_TIMEOUT)); 431*5c51f124SMoriah Waterland (void) web_disconnect(); 432*5c51f124SMoriah Waterland backoff(); 433*5c51f124SMoriah Waterland continue; 434*5c51f124SMoriah Waterland 435*5c51f124SMoriah Waterland case WEB_CONNREFUSED: 436*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_CONNREF), 437*5c51f124SMoriah Waterland ps->url.hport.hostname); 438*5c51f124SMoriah Waterland (void) web_disconnect(); 439*5c51f124SMoriah Waterland backoff(); 440*5c51f124SMoriah Waterland continue; 441*5c51f124SMoriah Waterland case WEB_HOSTDOWN: 442*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_HOSTDWN), 443*5c51f124SMoriah Waterland ps->url.hport.hostname); 444*5c51f124SMoriah Waterland (void) web_disconnect(); 445*5c51f124SMoriah Waterland backoff(); 446*5c51f124SMoriah Waterland continue; 447*5c51f124SMoriah Waterland default: 448*5c51f124SMoriah Waterland /* every other case is failure, so bail */ 449*5c51f124SMoriah Waterland ret = B_FALSE; 450*5c51f124SMoriah Waterland goto cleanup; 451*5c51f124SMoriah Waterland } 452*5c51f124SMoriah Waterland 453*5c51f124SMoriah Waterland if (!web_eval_headers(err)) { 454*5c51f124SMoriah Waterland ret = B_FALSE; 455*5c51f124SMoriah Waterland goto cleanup; 456*5c51f124SMoriah Waterland } 457*5c51f124SMoriah Waterland 458*5c51f124SMoriah Waterland switch (web_get_file(err, dwnld_dir, nointeract, fname)) { 459*5c51f124SMoriah Waterland case WEB_OK: 460*5c51f124SMoriah Waterland /* were able to retrieve file */ 461*5c51f124SMoriah Waterland retrieved = B_TRUE; 462*5c51f124SMoriah Waterland reset_backoff(); 463*5c51f124SMoriah Waterland break; 464*5c51f124SMoriah Waterland 465*5c51f124SMoriah Waterland case WEB_TIMEOUT: 466*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_TIMEOUT)); 467*5c51f124SMoriah Waterland (void) web_disconnect(); 468*5c51f124SMoriah Waterland backoff(); 469*5c51f124SMoriah Waterland continue; 470*5c51f124SMoriah Waterland 471*5c51f124SMoriah Waterland case WEB_CONNREFUSED: 472*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_CONNREF), 473*5c51f124SMoriah Waterland ps->url.hport.hostname); 474*5c51f124SMoriah Waterland (void) web_disconnect(); 475*5c51f124SMoriah Waterland backoff(); 476*5c51f124SMoriah Waterland continue; 477*5c51f124SMoriah Waterland case WEB_HOSTDOWN: 478*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_HOSTDWN), 479*5c51f124SMoriah Waterland ps->url.hport.hostname); 480*5c51f124SMoriah Waterland (void) web_disconnect(); 481*5c51f124SMoriah Waterland backoff(); 482*5c51f124SMoriah Waterland continue; 483*5c51f124SMoriah Waterland default: 484*5c51f124SMoriah Waterland /* every other failure is a hard failure, so bail */ 485*5c51f124SMoriah Waterland ret = B_FALSE; 486*5c51f124SMoriah Waterland goto cleanup; 487*5c51f124SMoriah Waterland } 488*5c51f124SMoriah Waterland } 489*5c51f124SMoriah Waterland 490*5c51f124SMoriah Waterland if (!retrieved) { 491*5c51f124SMoriah Waterland /* max retries attempted */ 492*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 493*5c51f124SMoriah Waterland gettext(ERR_DWNLD_FAILED), retries); 494*5c51f124SMoriah Waterland ret = B_FALSE; 495*5c51f124SMoriah Waterland } 496*5c51f124SMoriah Waterland cleanup: 497*5c51f124SMoriah Waterland (void) web_disconnect(); 498*5c51f124SMoriah Waterland if (!ret) { 499*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_DWNLD), url); 500*5c51f124SMoriah Waterland } 501*5c51f124SMoriah Waterland return (ret); 502*5c51f124SMoriah Waterland } 503*5c51f124SMoriah Waterland 504*5c51f124SMoriah Waterland /* 505*5c51f124SMoriah Waterland * Name: get_signature 506*5c51f124SMoriah Waterland * Description: retrieves signature from signed package. 507*5c51f124SMoriah Waterland * 508*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 509*5c51f124SMoriah Waterland * ids_name - name of package stream, for error reporting 510*5c51f124SMoriah Waterland * devp - Device on which package resides that we 511*5c51f124SMoriah Waterland * result - where to store resulting PKCS7 signature 512*5c51f124SMoriah Waterland * 513*5c51f124SMoriah Waterland * Returns : B_TRUE - package is signed and signature returned OR 514*5c51f124SMoriah Waterland * package is not signed, in which case result is NULL 515*5c51f124SMoriah Waterland * 516*5c51f124SMoriah Waterland * B_FALSE - there were problems accessing signature, 517*5c51f124SMoriah Waterland * and it is unknown whether it is signed or not. Errors 518*5c51f124SMoriah Waterland * recorded in 'err'. 519*5c51f124SMoriah Waterland */ 520*5c51f124SMoriah Waterland boolean_t 521*5c51f124SMoriah Waterland get_signature(PKG_ERR *err, char *ids_name, struct pkgdev *devp, PKCS7 **result) 522*5c51f124SMoriah Waterland { 523*5c51f124SMoriah Waterland char path[PATH_MAX]; 524*5c51f124SMoriah Waterland int len, fd = -1; 525*5c51f124SMoriah Waterland struct stat buf; 526*5c51f124SMoriah Waterland FILE *fp = NULL; 527*5c51f124SMoriah Waterland boolean_t ret = B_TRUE; 528*5c51f124SMoriah Waterland BIO *sig_in = NULL; 529*5c51f124SMoriah Waterland PKCS7 *p7 = NULL; 530*5c51f124SMoriah Waterland 531*5c51f124SMoriah Waterland /* 532*5c51f124SMoriah Waterland * look for signature. If one was in the stream, 533*5c51f124SMoriah Waterland * it is now extracted 534*5c51f124SMoriah Waterland */ 535*5c51f124SMoriah Waterland if (((len = snprintf(path, PATH_MAX, "%s/%s", devp->dirname, 536*5c51f124SMoriah Waterland SIGNATURE_FILENAME)) >= PATH_MAX) || (len < 0)) { 537*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), ids_name); 538*5c51f124SMoriah Waterland ret = B_FALSE; 539*5c51f124SMoriah Waterland goto cleanup; 540*5c51f124SMoriah Waterland } 541*5c51f124SMoriah Waterland 542*5c51f124SMoriah Waterland if ((fd = open(path, O_RDONLY|O_NONBLOCK)) == -1) { 543*5c51f124SMoriah Waterland /* 544*5c51f124SMoriah Waterland * only if the signature is non-existant 545*5c51f124SMoriah Waterland * do we "pass" 546*5c51f124SMoriah Waterland */ 547*5c51f124SMoriah Waterland if (errno != ENOENT) { 548*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_OPENSIG), 549*5c51f124SMoriah Waterland strerror(errno)); 550*5c51f124SMoriah Waterland ret = B_FALSE; 551*5c51f124SMoriah Waterland goto cleanup; 552*5c51f124SMoriah Waterland } 553*5c51f124SMoriah Waterland } else { 554*5c51f124SMoriah Waterland /* found sig file. parse it. */ 555*5c51f124SMoriah Waterland if (fstat(fd, &buf) == -1) { 556*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 557*5c51f124SMoriah Waterland gettext(ERR_OPENSIG), strerror(errno)); 558*5c51f124SMoriah Waterland ret = B_FALSE; 559*5c51f124SMoriah Waterland goto cleanup; 560*5c51f124SMoriah Waterland } 561*5c51f124SMoriah Waterland 562*5c51f124SMoriah Waterland if (!S_ISREG(buf.st_mode)) { 563*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_OPENSIG), 564*5c51f124SMoriah Waterland (gettext(ERR_NOT_REG))); 565*5c51f124SMoriah Waterland ret = B_FALSE; 566*5c51f124SMoriah Waterland goto cleanup; 567*5c51f124SMoriah Waterland } 568*5c51f124SMoriah Waterland 569*5c51f124SMoriah Waterland if ((fp = fdopen(fd, "r")) == NULL) { 570*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 571*5c51f124SMoriah Waterland gettext(ERR_OPENSIG), strerror(errno)); 572*5c51f124SMoriah Waterland ret = B_FALSE; 573*5c51f124SMoriah Waterland goto cleanup; 574*5c51f124SMoriah Waterland } 575*5c51f124SMoriah Waterland 576*5c51f124SMoriah Waterland /* 577*5c51f124SMoriah Waterland * read in signature. If it's invalid, we 578*5c51f124SMoriah Waterland * punt, unless we're ignoring it 579*5c51f124SMoriah Waterland */ 580*5c51f124SMoriah Waterland if ((sig_in = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) { 581*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 582*5c51f124SMoriah Waterland gettext(ERR_OPENSIG), strerror(errno)); 583*5c51f124SMoriah Waterland goto cleanup; 584*5c51f124SMoriah Waterland } 585*5c51f124SMoriah Waterland 586*5c51f124SMoriah Waterland if ((p7 = PEM_read_bio_PKCS7(sig_in, 587*5c51f124SMoriah Waterland NULL, NULL, NULL)) == NULL) { 588*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG), 589*5c51f124SMoriah Waterland ids_name); 590*5c51f124SMoriah Waterland ret = B_FALSE; 591*5c51f124SMoriah Waterland goto cleanup; 592*5c51f124SMoriah Waterland } 593*5c51f124SMoriah Waterland *result = p7; 594*5c51f124SMoriah Waterland p7 = NULL; 595*5c51f124SMoriah Waterland } 596*5c51f124SMoriah Waterland 597*5c51f124SMoriah Waterland cleanup: 598*5c51f124SMoriah Waterland if (sig_in) 599*5c51f124SMoriah Waterland (void) BIO_free(sig_in); 600*5c51f124SMoriah Waterland if (fp) 601*5c51f124SMoriah Waterland (void) fclose(fp); 602*5c51f124SMoriah Waterland if (fd != -1) 603*5c51f124SMoriah Waterland (void) close(fd); 604*5c51f124SMoriah Waterland if (p7) 605*5c51f124SMoriah Waterland (void) PKCS7_free(p7); 606*5c51f124SMoriah Waterland 607*5c51f124SMoriah Waterland return (ret); 608*5c51f124SMoriah Waterland } 609*5c51f124SMoriah Waterland 610*5c51f124SMoriah Waterland /* 611*5c51f124SMoriah Waterland * Name: echo_out 612*5c51f124SMoriah Waterland * Description: Conditionally output a message to stdout 613*5c51f124SMoriah Waterland * 614*5c51f124SMoriah Waterland * Arguments: nointeract - if non-zero, do not output anything 615*5c51f124SMoriah Waterland * fmt - print format 616*5c51f124SMoriah Waterland * ... - print arguments 617*5c51f124SMoriah Waterland * 618*5c51f124SMoriah Waterland * Returns : none 619*5c51f124SMoriah Waterland */ 620*5c51f124SMoriah Waterland void 621*5c51f124SMoriah Waterland echo_out(int nointeract, char *fmt, ...) 622*5c51f124SMoriah Waterland { 623*5c51f124SMoriah Waterland va_list ap; 624*5c51f124SMoriah Waterland 625*5c51f124SMoriah Waterland va_start(ap, fmt); 626*5c51f124SMoriah Waterland 627*5c51f124SMoriah Waterland if (nointeract) 628*5c51f124SMoriah Waterland return; 629*5c51f124SMoriah Waterland 630*5c51f124SMoriah Waterland (void) vfprintf(stdout, fmt, ap); 631*5c51f124SMoriah Waterland 632*5c51f124SMoriah Waterland va_end(ap); 633*5c51f124SMoriah Waterland 634*5c51f124SMoriah Waterland (void) putc('\n', stdout); 635*5c51f124SMoriah Waterland } 636*5c51f124SMoriah Waterland 637*5c51f124SMoriah Waterland /* 638*5c51f124SMoriah Waterland * Name: strip_port 639*5c51f124SMoriah Waterland * Description: Returns "port" portion of a "hostname:port" string 640*5c51f124SMoriah Waterland * 641*5c51f124SMoriah Waterland * Arguments: proxy - full "hostname:port" string pointer 642*5c51f124SMoriah Waterland * 643*5c51f124SMoriah Waterland * Returns : the "port" portion of a "hostname:port" string, 644*5c51f124SMoriah Waterland * converted to a decimal integer, or (int)0 645*5c51f124SMoriah Waterland * if string contains no :port suffix. 646*5c51f124SMoriah Waterland */ 647*5c51f124SMoriah Waterland ushort_t 648*5c51f124SMoriah Waterland strip_port(char *proxy) 649*5c51f124SMoriah Waterland { 650*5c51f124SMoriah Waterland char *tmp_port; 651*5c51f124SMoriah Waterland 652*5c51f124SMoriah Waterland if ((tmp_port = strpbrk(proxy, ":")) != NULL) 653*5c51f124SMoriah Waterland return (atoi(tmp_port)); 654*5c51f124SMoriah Waterland else 655*5c51f124SMoriah Waterland return (0); 656*5c51f124SMoriah Waterland } 657*5c51f124SMoriah Waterland 658*5c51f124SMoriah Waterland /* 659*5c51f124SMoriah Waterland * Name: set_web_install 660*5c51f124SMoriah Waterland * Description: Sets flag indicating we are doing a web-based install 661*5c51f124SMoriah Waterland * 662*5c51f124SMoriah Waterland * Arguments: none 663*5c51f124SMoriah Waterland * 664*5c51f124SMoriah Waterland * Returns : none 665*5c51f124SMoriah Waterland */ 666*5c51f124SMoriah Waterland void 667*5c51f124SMoriah Waterland set_web_install(void) 668*5c51f124SMoriah Waterland { 669*5c51f124SMoriah Waterland webpkg_install++; 670*5c51f124SMoriah Waterland } 671*5c51f124SMoriah Waterland 672*5c51f124SMoriah Waterland /* 673*5c51f124SMoriah Waterland * Name: is_web_install 674*5c51f124SMoriah Waterland * Description: Determines whether we are doing a web-based install 675*5c51f124SMoriah Waterland * 676*5c51f124SMoriah Waterland * Arguments: none 677*5c51f124SMoriah Waterland * 678*5c51f124SMoriah Waterland * Returns : non-zero if we are doing a web-based install, 0 otherwise 679*5c51f124SMoriah Waterland */ 680*5c51f124SMoriah Waterland int 681*5c51f124SMoriah Waterland is_web_install(void) 682*5c51f124SMoriah Waterland { 683*5c51f124SMoriah Waterland return (webpkg_install); 684*5c51f124SMoriah Waterland } 685*5c51f124SMoriah Waterland 686*5c51f124SMoriah Waterland /* ~~~~~~~~~~~~~~ Private Functions ~~~~~~~~~~~~~~~~~~~ */ 687*5c51f124SMoriah Waterland 688*5c51f124SMoriah Waterland /* 689*5c51f124SMoriah Waterland * Name: web_disconnect 690*5c51f124SMoriah Waterland * Description: Disconnects connection to web server 691*5c51f124SMoriah Waterland * 692*5c51f124SMoriah Waterland * Arguments: none 693*5c51f124SMoriah Waterland * 694*5c51f124SMoriah Waterland * Returns : B_TRUE - successful disconnect, B_FALSE otherwise 695*5c51f124SMoriah Waterland * Temp certificiate files are deleted, 696*5c51f124SMoriah Waterland * if one was used to initiate the connection 697*5c51f124SMoriah Waterland * (such as when using SSL) 698*5c51f124SMoriah Waterland */ 699*5c51f124SMoriah Waterland static boolean_t 700*5c51f124SMoriah Waterland web_disconnect(void) 701*5c51f124SMoriah Waterland { 702*5c51f124SMoriah Waterland if (ps->certfile) { 703*5c51f124SMoriah Waterland (void) unlink(ps->certfile); 704*5c51f124SMoriah Waterland } 705*5c51f124SMoriah Waterland if (http_srv_disconnect(ps->hps) == 0) 706*5c51f124SMoriah Waterland if (http_srv_close(ps->hps) == 0) 707*5c51f124SMoriah Waterland return (B_TRUE); 708*5c51f124SMoriah Waterland 709*5c51f124SMoriah Waterland return (B_FALSE); 710*5c51f124SMoriah Waterland } 711*5c51f124SMoriah Waterland 712*5c51f124SMoriah Waterland /* 713*5c51f124SMoriah Waterland * Name: check_dwnld_dir 714*5c51f124SMoriah Waterland * Description: Creates temp download directory 715*5c51f124SMoriah Waterland * 716*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 717*5c51f124SMoriah Waterland * dwnld_dir - name of directory to create 718*5c51f124SMoriah Waterland * 719*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 720*5c51f124SMoriah Waterland * on success, directory is created with 721*5c51f124SMoriah Waterland * safe permissions 722*5c51f124SMoriah Waterland */ 723*5c51f124SMoriah Waterland static boolean_t 724*5c51f124SMoriah Waterland check_dwnld_dir(PKG_ERR *err, char *dwnld_dir) 725*5c51f124SMoriah Waterland { 726*5c51f124SMoriah Waterland DIR *dirp; 727*5c51f124SMoriah Waterland 728*5c51f124SMoriah Waterland /* 729*5c51f124SMoriah Waterland * Check the directory passed in. If it doesn't exist, create it 730*5c51f124SMoriah Waterland * with strict permissions 731*5c51f124SMoriah Waterland */ 732*5c51f124SMoriah Waterland if ((dirp = opendir(dwnld_dir)) == NULL) { 733*5c51f124SMoriah Waterland if (mkdir(dwnld_dir, 0744) == -1) { 734*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), 735*5c51f124SMoriah Waterland dwnld_dir); 736*5c51f124SMoriah Waterland return (B_FALSE); 737*5c51f124SMoriah Waterland } 738*5c51f124SMoriah Waterland } 739*5c51f124SMoriah Waterland if (dirp) { 740*5c51f124SMoriah Waterland (void) closedir(dirp); 741*5c51f124SMoriah Waterland } 742*5c51f124SMoriah Waterland return (B_TRUE); 743*5c51f124SMoriah Waterland } 744*5c51f124SMoriah Waterland 745*5c51f124SMoriah Waterland /* 746*5c51f124SMoriah Waterland * Name: ds_validate_signature 747*5c51f124SMoriah Waterland * Description: Validates signature found in a package datastream 748*5c51f124SMoriah Waterland * 749*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 750*5c51f124SMoriah Waterland * pkgdev - Package context handle of package to verify 751*5c51f124SMoriah Waterland * pkgs - Null-terminated List of package name to verify 752*5c51f124SMoriah Waterland * ids_name - Pathname to stream to validate 753*5c51f124SMoriah Waterland * p7 - PKCS7 signature decoded from stream header 754*5c51f124SMoriah Waterland * cas - List of trusted CA certificates 755*5c51f124SMoriah Waterland * proxy - Proxy to use when doing online validation (OCSP) 756*5c51f124SMoriah Waterland * nointeract - if non-zero, do not output to screen 757*5c51f124SMoriah Waterland * 758*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 759*5c51f124SMoriah Waterland * success means signature was completely validated, 760*5c51f124SMoriah Waterland * and contents of stream checked against signature. 761*5c51f124SMoriah Waterland */ 762*5c51f124SMoriah Waterland boolean_t 763*5c51f124SMoriah Waterland ds_validate_signature(PKG_ERR *err, struct pkgdev *pkgdev, char **pkgs, 764*5c51f124SMoriah Waterland char *ids_name, PKCS7 *p7, STACK_OF(X509) *cas, 765*5c51f124SMoriah Waterland url_hport_t *proxy, int nointeract) 766*5c51f124SMoriah Waterland { 767*5c51f124SMoriah Waterland BIO *p7_bio; 768*5c51f124SMoriah Waterland boolean_t ret = B_TRUE; 769*5c51f124SMoriah Waterland 770*5c51f124SMoriah Waterland /* make sure it's a Signed PKCS7 message */ 771*5c51f124SMoriah Waterland if (!PKCS7_type_is_signed(p7)) { 772*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG_TYPE), 773*5c51f124SMoriah Waterland ids_name); 774*5c51f124SMoriah Waterland ret = B_FALSE; 775*5c51f124SMoriah Waterland goto cleanup; 776*5c51f124SMoriah Waterland } 777*5c51f124SMoriah Waterland 778*5c51f124SMoriah Waterland /* initialize PKCS7 object to be filled in */ 779*5c51f124SMoriah Waterland if (!PKCS7_get_detached(p7)) { 780*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG_DT), 781*5c51f124SMoriah Waterland ids_name); 782*5c51f124SMoriah Waterland ret = B_FALSE; 783*5c51f124SMoriah Waterland goto cleanup; 784*5c51f124SMoriah Waterland } 785*5c51f124SMoriah Waterland 786*5c51f124SMoriah Waterland /* dump header and packages into BIO to calculate the message digest */ 787*5c51f124SMoriah Waterland if ((p7_bio = PKCS7_dataInit(p7, NULL)) == NULL) { 788*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG), 789*5c51f124SMoriah Waterland ids_name); 790*5c51f124SMoriah Waterland ret = B_FALSE; 791*5c51f124SMoriah Waterland goto cleanup; 792*5c51f124SMoriah Waterland } 793*5c51f124SMoriah Waterland 794*5c51f124SMoriah Waterland if ((BIO_ds_dump_header(err, p7_bio) != 0) || 795*5c51f124SMoriah Waterland (BIO_ds_dump(err, ids_name, p7_bio) != 0)) { 796*5c51f124SMoriah Waterland ret = B_FALSE; 797*5c51f124SMoriah Waterland goto cleanup; 798*5c51f124SMoriah Waterland } 799*5c51f124SMoriah Waterland (void) BIO_flush(p7_bio); 800*5c51f124SMoriah Waterland 801*5c51f124SMoriah Waterland /* validate the stream and its signature */ 802*5c51f124SMoriah Waterland if (!validate_signature(err, ids_name, p7_bio, p7, cas, 803*5c51f124SMoriah Waterland proxy, nointeract)) { 804*5c51f124SMoriah Waterland ret = B_FALSE; 805*5c51f124SMoriah Waterland goto cleanup; 806*5c51f124SMoriah Waterland } 807*5c51f124SMoriah Waterland 808*5c51f124SMoriah Waterland /* reset device stream (really bad performance for tapes) */ 809*5c51f124SMoriah Waterland (void) ds_close(1); 810*5c51f124SMoriah Waterland (void) ds_init(ids_name, pkgs, pkgdev->norewind); 811*5c51f124SMoriah Waterland 812*5c51f124SMoriah Waterland cleanup: 813*5c51f124SMoriah Waterland return (ret); 814*5c51f124SMoriah Waterland } 815*5c51f124SMoriah Waterland 816*5c51f124SMoriah Waterland 817*5c51f124SMoriah Waterland /* 818*5c51f124SMoriah Waterland * Name: validate_signature 819*5c51f124SMoriah Waterland * Description: Validates signature of an arbitrary stream of bits 820*5c51f124SMoriah Waterland * 821*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 822*5c51f124SMoriah Waterland * name - Descriptive name of object being validated, 823*5c51f124SMoriah Waterland * for good error reporting messages 824*5c51f124SMoriah Waterland * indata - BIO object to read stream bits from 825*5c51f124SMoriah Waterland * p7 - PKCS7 signature of stream 826*5c51f124SMoriah Waterland * cas - List of trusted CA certificates 827*5c51f124SMoriah Waterland * proxy - Proxy to use when doing online validation (OCSP) 828*5c51f124SMoriah Waterland * nointeract - if non-zero, do not output to screen 829*5c51f124SMoriah Waterland * 830*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 831*5c51f124SMoriah Waterland * success means signature was completely validated, 832*5c51f124SMoriah Waterland * and contents of stream checked against signature. 833*5c51f124SMoriah Waterland */ 834*5c51f124SMoriah Waterland boolean_t 835*5c51f124SMoriah Waterland validate_signature(PKG_ERR *err, char *name, BIO *indata, PKCS7 *p7, 836*5c51f124SMoriah Waterland STACK_OF(X509) *cas, url_hport_t *proxy, int nointeract) 837*5c51f124SMoriah Waterland { 838*5c51f124SMoriah Waterland STACK_OF(PKCS7_SIGNER_INFO) *sec_sinfos = NULL; 839*5c51f124SMoriah Waterland 840*5c51f124SMoriah Waterland PKCS7_SIGNER_INFO *signer = NULL; 841*5c51f124SMoriah Waterland X509_STORE *sec_truststore = NULL; 842*5c51f124SMoriah Waterland X509_STORE_CTX *ctx = NULL; 843*5c51f124SMoriah Waterland X509 *signer_cert = NULL, *issuer = NULL; 844*5c51f124SMoriah Waterland STACK_OF(X509) *chaincerts = NULL; 845*5c51f124SMoriah Waterland int i, k; 846*5c51f124SMoriah Waterland unsigned long errcode; 847*5c51f124SMoriah Waterland const char *err_data = NULL; 848*5c51f124SMoriah Waterland const char *err_reason = NULL; 849*5c51f124SMoriah Waterland char *err_string; 850*5c51f124SMoriah Waterland int err_flags; 851*5c51f124SMoriah Waterland verify_cb_data_t verify_data; 852*5c51f124SMoriah Waterland char *signer_sname; 853*5c51f124SMoriah Waterland char *signer_iname; 854*5c51f124SMoriah Waterland PKCS7_ISSUER_AND_SERIAL *ias; 855*5c51f124SMoriah Waterland boolean_t ret = B_TRUE; 856*5c51f124SMoriah Waterland 857*5c51f124SMoriah Waterland /* only support signed PKCS7 signatures */ 858*5c51f124SMoriah Waterland if (!PKCS7_type_is_signed(p7)) { 859*5c51f124SMoriah Waterland PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_WRONG_PKCS7_TYPE); 860*5c51f124SMoriah Waterland ret = B_FALSE; 861*5c51f124SMoriah Waterland goto cleanup; 862*5c51f124SMoriah Waterland } 863*5c51f124SMoriah Waterland 864*5c51f124SMoriah Waterland /* initialize temporary internal trust store used for verification */ 865*5c51f124SMoriah Waterland sec_truststore = X509_STORE_new(); 866*5c51f124SMoriah Waterland 867*5c51f124SMoriah Waterland for (i = 0; i < sk_X509_num(cas); i++) { 868*5c51f124SMoriah Waterland if (X509_STORE_add_cert(sec_truststore, 869*5c51f124SMoriah Waterland sk_X509_value(cas, i)) == 0) { 870*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, gettext(ERR_MEM)); 871*5c51f124SMoriah Waterland ret = B_FALSE; 872*5c51f124SMoriah Waterland goto cleanup; 873*5c51f124SMoriah Waterland } 874*5c51f124SMoriah Waterland } 875*5c51f124SMoriah Waterland 876*5c51f124SMoriah Waterland /* get signers from the signature */ 877*5c51f124SMoriah Waterland if ((sec_sinfos = PKCS7_get_signer_info(p7)) == NULL) { 878*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG), name); 879*5c51f124SMoriah Waterland ret = B_FALSE; 880*5c51f124SMoriah Waterland goto cleanup; 881*5c51f124SMoriah Waterland } 882*5c51f124SMoriah Waterland 883*5c51f124SMoriah Waterland /* verify each signer found in the PKCS7 signature */ 884*5c51f124SMoriah Waterland for (k = 0; k < sk_PKCS7_SIGNER_INFO_num(sec_sinfos); k++) { 885*5c51f124SMoriah Waterland signer = sk_PKCS7_SIGNER_INFO_value(sec_sinfos, k); 886*5c51f124SMoriah Waterland signer_cert = PKCS7_cert_from_signer_info(p7, signer); 887*5c51f124SMoriah Waterland signer_sname = get_subject_display_name(signer_cert); 888*5c51f124SMoriah Waterland signer_iname = get_issuer_display_name(signer_cert); 889*5c51f124SMoriah Waterland 890*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_VERIFY), signer_sname); 891*5c51f124SMoriah Waterland 892*5c51f124SMoriah Waterland /* find the issuer of the current cert */ 893*5c51f124SMoriah Waterland chaincerts = p7->d.sign->cert; 894*5c51f124SMoriah Waterland ias = signer->issuer_and_serial; 895*5c51f124SMoriah Waterland issuer = X509_find_by_issuer_and_serial(chaincerts, 896*5c51f124SMoriah Waterland ias->issuer, ias->serial); 897*5c51f124SMoriah Waterland 898*5c51f124SMoriah Waterland /* were we not able to find the issuer cert */ 899*5c51f124SMoriah Waterland if (issuer == NULL) { 900*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 901*5c51f124SMoriah Waterland gettext(ERR_VERIFY_ISSUER), 902*5c51f124SMoriah Waterland signer_iname, signer_sname); 903*5c51f124SMoriah Waterland ret = B_FALSE; 904*5c51f124SMoriah Waterland goto cleanup; 905*5c51f124SMoriah Waterland } 906*5c51f124SMoriah Waterland 907*5c51f124SMoriah Waterland /* Lets verify */ 908*5c51f124SMoriah Waterland if ((ctx = X509_STORE_CTX_new()) == NULL) { 909*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, gettext(ERR_MEM)); 910*5c51f124SMoriah Waterland ret = B_FALSE; 911*5c51f124SMoriah Waterland goto cleanup; 912*5c51f124SMoriah Waterland } 913*5c51f124SMoriah Waterland (void) X509_STORE_CTX_init(ctx, sec_truststore, 914*5c51f124SMoriah Waterland issuer, chaincerts); 915*5c51f124SMoriah Waterland (void) X509_STORE_CTX_set_purpose(ctx, 916*5c51f124SMoriah Waterland X509_PURPOSE_ANY); 917*5c51f124SMoriah Waterland 918*5c51f124SMoriah Waterland /* callback will perform OCSP on certificates with OCSP data */ 919*5c51f124SMoriah Waterland X509_STORE_CTX_set_verify_cb(ctx, web_verify); 920*5c51f124SMoriah Waterland 921*5c51f124SMoriah Waterland /* pass needed data into callback through the app_data handle */ 922*5c51f124SMoriah Waterland verify_data.proxy = proxy; 923*5c51f124SMoriah Waterland verify_data.cas = cas; 924*5c51f124SMoriah Waterland verify_data.err = err; 925*5c51f124SMoriah Waterland (void) X509_STORE_CTX_set_app_data(ctx, &verify_data); 926*5c51f124SMoriah Waterland 927*5c51f124SMoriah Waterland /* first verify the certificate chain */ 928*5c51f124SMoriah Waterland i = X509_verify_cert(ctx); 929*5c51f124SMoriah Waterland if (i <= 0 && ctx->error != X509_V_ERR_CERT_HAS_EXPIRED) { 930*5c51f124SMoriah Waterland signer_sname = 931*5c51f124SMoriah Waterland get_subject_display_name(ctx->current_cert); 932*5c51f124SMoriah Waterland signer_iname = 933*5c51f124SMoriah Waterland get_issuer_display_name(ctx->current_cert); 934*5c51f124SMoriah Waterland /* if the verify context holds an error, print it */ 935*5c51f124SMoriah Waterland if (ctx->error != X509_V_OK) { 936*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, 937*5c51f124SMoriah Waterland gettext(ERR_VERIFY_SIG), signer_sname, 938*5c51f124SMoriah Waterland signer_iname, 939*5c51f124SMoriah Waterland (char *)X509_verify_cert_error_string(ctx->error)); 940*5c51f124SMoriah Waterland } else { 941*5c51f124SMoriah Waterland /* some other error. print them all. */ 942*5c51f124SMoriah Waterland while ((errcode = ERR_get_error_line_data(NULL, 943*5c51f124SMoriah Waterland NULL, &err_data, &err_flags)) != 0) { 944*5c51f124SMoriah Waterland err_reason = 945*5c51f124SMoriah Waterland ERR_reason_error_string(errcode); 946*5c51f124SMoriah Waterland if (err_reason == NULL) { 947*5c51f124SMoriah Waterland err_reason = 948*5c51f124SMoriah Waterland gettext(ERR_SIG_INT); 949*5c51f124SMoriah Waterland } 950*5c51f124SMoriah Waterland 951*5c51f124SMoriah Waterland if (!(err_flags & ERR_TXT_STRING)) { 952*5c51f124SMoriah Waterland err_data = 953*5c51f124SMoriah Waterland gettext(ERR_SIG_INT); 954*5c51f124SMoriah Waterland } 955*5c51f124SMoriah Waterland err_string = 956*5c51f124SMoriah Waterland xmalloc(strlen(err_reason) + 957*5c51f124SMoriah Waterland strlen(err_data) + 3); 958*5c51f124SMoriah Waterland (void) sprintf(err_string, "%s: %s", 959*5c51f124SMoriah Waterland err_reason, err_data); 960*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, 961*5c51f124SMoriah Waterland gettext(ERR_VERIFY_SIG), 962*5c51f124SMoriah Waterland signer_sname, signer_iname, 963*5c51f124SMoriah Waterland err_string); 964*5c51f124SMoriah Waterland free(err_string); 965*5c51f124SMoriah Waterland } 966*5c51f124SMoriah Waterland } 967*5c51f124SMoriah Waterland ret = B_FALSE; 968*5c51f124SMoriah Waterland goto cleanup; 969*5c51f124SMoriah Waterland } 970*5c51f124SMoriah Waterland 971*5c51f124SMoriah Waterland /* now verify the signature */ 972*5c51f124SMoriah Waterland i = PKCS7_signatureVerify(indata, p7, signer, issuer); 973*5c51f124SMoriah Waterland 974*5c51f124SMoriah Waterland if (i <= 0) { 975*5c51f124SMoriah Waterland /* print out any OpenSSL-specific errors */ 976*5c51f124SMoriah Waterland signer_sname = 977*5c51f124SMoriah Waterland get_subject_display_name(ctx->current_cert); 978*5c51f124SMoriah Waterland signer_iname = 979*5c51f124SMoriah Waterland get_subject_display_name(ctx->current_cert); 980*5c51f124SMoriah Waterland while ((errcode = ERR_get_error_line_data(NULL, 981*5c51f124SMoriah Waterland NULL, &err_data, &err_flags)) != 0) { 982*5c51f124SMoriah Waterland err_reason = 983*5c51f124SMoriah Waterland ERR_reason_error_string(errcode); 984*5c51f124SMoriah Waterland if (err_reason == NULL) { 985*5c51f124SMoriah Waterland err_reason = 986*5c51f124SMoriah Waterland gettext(ERR_SIG_INT); 987*5c51f124SMoriah Waterland } 988*5c51f124SMoriah Waterland 989*5c51f124SMoriah Waterland if (!(err_flags & ERR_TXT_STRING)) { 990*5c51f124SMoriah Waterland err_data = 991*5c51f124SMoriah Waterland gettext(ERR_SIG_INT); 992*5c51f124SMoriah Waterland } 993*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, 994*5c51f124SMoriah Waterland gettext(ERR_VERIFY_SIG), signer_sname, 995*5c51f124SMoriah Waterland signer_iname, err_reason); 996*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, 997*5c51f124SMoriah Waterland gettext(ERR_VERIFY_SIG), signer_sname, 998*5c51f124SMoriah Waterland signer_iname, err_data); 999*5c51f124SMoriah Waterland } 1000*5c51f124SMoriah Waterland ret = B_FALSE; 1001*5c51f124SMoriah Waterland goto cleanup; 1002*5c51f124SMoriah Waterland } 1003*5c51f124SMoriah Waterland 1004*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_VERIFY_OK), signer_sname); 1005*5c51f124SMoriah Waterland } 1006*5c51f124SMoriah Waterland 1007*5c51f124SMoriah Waterland /* signature(s) verified successfully */ 1008*5c51f124SMoriah Waterland cleanup: 1009*5c51f124SMoriah Waterland if (ctx) 1010*5c51f124SMoriah Waterland X509_STORE_CTX_cleanup(ctx); 1011*5c51f124SMoriah Waterland return (ret); 1012*5c51f124SMoriah Waterland } 1013*5c51f124SMoriah Waterland 1014*5c51f124SMoriah Waterland /* 1015*5c51f124SMoriah Waterland * Name: web_verify 1016*5c51f124SMoriah Waterland * Description: Callback used by PKCS7_dataVerify when 1017*5c51f124SMoriah Waterland * verifying a certificate chain. 1018*5c51f124SMoriah Waterland * 1019*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 1020*5c51f124SMoriah Waterland * ctx - The context handle of the current verification operation 1021*5c51f124SMoriah Waterland * 1022*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 1023*5c51f124SMoriah Waterland * if it's '0' (not OK) we simply return it, since the 1024*5c51f124SMoriah Waterland * verification operation has already determined that the 1025*5c51f124SMoriah Waterland * cert is invalid. if 'ok' is non-zero, then we do our 1026*5c51f124SMoriah Waterland * checks, and return 0 or 1 based on if the cert is 1027*5c51f124SMoriah Waterland * invalid or valid. 1028*5c51f124SMoriah Waterland */ 1029*5c51f124SMoriah Waterland static int 1030*5c51f124SMoriah Waterland web_verify(int ok, X509_STORE_CTX *ctx) 1031*5c51f124SMoriah Waterland { 1032*5c51f124SMoriah Waterland X509 *curr_cert; 1033*5c51f124SMoriah Waterland X509 *curr_issuer; 1034*5c51f124SMoriah Waterland char *uri; 1035*5c51f124SMoriah Waterland url_hport_t *proxy; 1036*5c51f124SMoriah Waterland PKG_ERR *err = NULL; 1037*5c51f124SMoriah Waterland STACK_OF(X509) *cas; 1038*5c51f124SMoriah Waterland if (!ok) { 1039*5c51f124SMoriah Waterland /* don't override a verify failure */ 1040*5c51f124SMoriah Waterland return (ok); 1041*5c51f124SMoriah Waterland } 1042*5c51f124SMoriah Waterland 1043*5c51f124SMoriah Waterland 1044*5c51f124SMoriah Waterland /* get app data supplied through callback context */ 1045*5c51f124SMoriah Waterland err = ((verify_cb_data_t *)X509_STORE_CTX_get_app_data(ctx))->err; 1046*5c51f124SMoriah Waterland proxy = ((verify_cb_data_t *)X509_STORE_CTX_get_app_data(ctx))->proxy; 1047*5c51f124SMoriah Waterland cas = ((verify_cb_data_t *)X509_STORE_CTX_get_app_data(ctx))->cas; 1048*5c51f124SMoriah Waterland 1049*5c51f124SMoriah Waterland /* Check revocation status */ 1050*5c51f124SMoriah Waterland curr_cert = X509_STORE_CTX_get_current_cert(ctx); 1051*5c51f124SMoriah Waterland 1052*5c51f124SMoriah Waterland /* this shouldn't happen */ 1053*5c51f124SMoriah Waterland if (curr_cert == NULL) { 1054*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, gettext(ERR_PKG_INTERNAL), 1055*5c51f124SMoriah Waterland __FILE__, __LINE__); 1056*5c51f124SMoriah Waterland return (0); 1057*5c51f124SMoriah Waterland } 1058*5c51f124SMoriah Waterland 1059*5c51f124SMoriah Waterland /* don't perform OCSP unless cert has required OCSP extensions */ 1060*5c51f124SMoriah Waterland if (get_ocsp_uri(curr_cert, &uri)) { 1061*5c51f124SMoriah Waterland if (get_issuer(&curr_issuer, ctx, curr_cert) <= 0) { 1062*5c51f124SMoriah Waterland /* no issuer! */ 1063*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, 1064*5c51f124SMoriah Waterland gettext(ERR_PKG_INTERNAL), 1065*5c51f124SMoriah Waterland __FILE__, __LINE__); 1066*5c51f124SMoriah Waterland return (0); 1067*5c51f124SMoriah Waterland } 1068*5c51f124SMoriah Waterland 1069*5c51f124SMoriah Waterland /* 1070*5c51f124SMoriah Waterland * ok we have the current cert 1071*5c51f124SMoriah Waterland * and its issuer. Do the OCSP check 1072*5c51f124SMoriah Waterland */ 1073*5c51f124SMoriah Waterland 1074*5c51f124SMoriah Waterland /* 1075*5c51f124SMoriah Waterland * OCSP extensions are, by, RFC 2459, never critical 1076*5c51f124SMoriah Waterland * extensions, therefore, we only fail if we were able 1077*5c51f124SMoriah Waterland * to explicitly contact an OCSP responder, and that 1078*5c51f124SMoriah Waterland * responder did not indicate the cert was valid. We 1079*5c51f124SMoriah Waterland * also fail if user-supplied data could not be parsed 1080*5c51f124SMoriah Waterland * or we run out of memory. We succeeed for "soft" 1081*5c51f124SMoriah Waterland * failures, such as not being able to connect to the 1082*5c51f124SMoriah Waterland * OCSP responder, or trying to use if the OCSP URI 1083*5c51f124SMoriah Waterland * indicates SSL must be used (which we do not 1084*5c51f124SMoriah Waterland * support) 1085*5c51f124SMoriah Waterland */ 1086*5c51f124SMoriah Waterland switch (ocsp_verify(err, curr_cert, curr_issuer, 1087*5c51f124SMoriah Waterland uri, proxy, cas)) { 1088*5c51f124SMoriah Waterland case OCSPMem: /* Ran out of memory */ 1089*5c51f124SMoriah Waterland case OCSPInternal: /* Some internal error */ 1090*5c51f124SMoriah Waterland case OCSPVerify: /* OCSP responder indicated fail */ 1091*5c51f124SMoriah Waterland return (0); 1092*5c51f124SMoriah Waterland } 1093*5c51f124SMoriah Waterland /* all other cases are success, or soft failures */ 1094*5c51f124SMoriah Waterland pkgerr_clear(err); 1095*5c51f124SMoriah Waterland } 1096*5c51f124SMoriah Waterland 1097*5c51f124SMoriah Waterland return (ok); 1098*5c51f124SMoriah Waterland } 1099*5c51f124SMoriah Waterland 1100*5c51f124SMoriah Waterland /* 1101*5c51f124SMoriah Waterland * Name: get_time_string 1102*5c51f124SMoriah Waterland * Description: Generates a human-readable string from an ASN1_GENERALIZED_TIME 1103*5c51f124SMoriah Waterland * 1104*5c51f124SMoriah Waterland * Arguments: intime - The time to convert 1105*5c51f124SMoriah Waterland * 1106*5c51f124SMoriah Waterland * Returns : A pointer to a static string representing the passed-in time. 1107*5c51f124SMoriah Waterland */ 1108*5c51f124SMoriah Waterland static char 1109*5c51f124SMoriah Waterland *get_time_string(ASN1_GENERALIZEDTIME *intime) 1110*5c51f124SMoriah Waterland { 1111*5c51f124SMoriah Waterland 1112*5c51f124SMoriah Waterland static char time[ATTR_MAX]; 1113*5c51f124SMoriah Waterland BIO *mem; 1114*5c51f124SMoriah Waterland char *p; 1115*5c51f124SMoriah Waterland 1116*5c51f124SMoriah Waterland if (intime == NULL) { 1117*5c51f124SMoriah Waterland return (NULL); 1118*5c51f124SMoriah Waterland } 1119*5c51f124SMoriah Waterland if ((mem = BIO_new(BIO_s_mem())) == NULL) { 1120*5c51f124SMoriah Waterland return (NULL); 1121*5c51f124SMoriah Waterland } 1122*5c51f124SMoriah Waterland 1123*5c51f124SMoriah Waterland if (ASN1_GENERALIZEDTIME_print(mem, intime) == 0) { 1124*5c51f124SMoriah Waterland (void) BIO_free(mem); 1125*5c51f124SMoriah Waterland return (NULL); 1126*5c51f124SMoriah Waterland } 1127*5c51f124SMoriah Waterland 1128*5c51f124SMoriah Waterland if (BIO_gets(mem, time, ATTR_MAX) <= 0) { 1129*5c51f124SMoriah Waterland (void) BIO_free(mem); 1130*5c51f124SMoriah Waterland return (NULL); 1131*5c51f124SMoriah Waterland } 1132*5c51f124SMoriah Waterland 1133*5c51f124SMoriah Waterland (void) BIO_free(mem); 1134*5c51f124SMoriah Waterland 1135*5c51f124SMoriah Waterland /* trim the end of the string */ 1136*5c51f124SMoriah Waterland for (p = time + strlen(time) - 1; isspace(*p); p--) { 1137*5c51f124SMoriah Waterland *p = '\0'; 1138*5c51f124SMoriah Waterland } 1139*5c51f124SMoriah Waterland 1140*5c51f124SMoriah Waterland return (time); 1141*5c51f124SMoriah Waterland } 1142*5c51f124SMoriah Waterland 1143*5c51f124SMoriah Waterland /* 1144*5c51f124SMoriah Waterland * Name: get_ocsp_uri 1145*5c51f124SMoriah Waterland * Description: Examines an X509 certificate and retrieves the embedded 1146*5c51f124SMoriah Waterland * OCSP Responder URI if one exists. 1147*5c51f124SMoriah Waterland * 1148*5c51f124SMoriah Waterland * Arguments: cert - The cert to inspect 1149*5c51f124SMoriah Waterland * uri - pointer where the newly-allocated URI is placed, if found 1150*5c51f124SMoriah Waterland * 1151*5c51f124SMoriah Waterland * Returns : Success if the URI was found. Appropriate status otherwise. 1152*5c51f124SMoriah Waterland */ 1153*5c51f124SMoriah Waterland static boolean_t 1154*5c51f124SMoriah Waterland get_ocsp_uri(X509 *cert, char **uri) 1155*5c51f124SMoriah Waterland { 1156*5c51f124SMoriah Waterland AUTHORITY_INFO_ACCESS *aia; 1157*5c51f124SMoriah Waterland ACCESS_DESCRIPTION *ad; 1158*5c51f124SMoriah Waterland int i; 1159*5c51f124SMoriah Waterland 1160*5c51f124SMoriah Waterland if (getenv("PKGWEB_TEST_OCSP")) { 1161*5c51f124SMoriah Waterland *uri = xstrdup(getenv("PKGWEB_TEST_OCSP")); 1162*5c51f124SMoriah Waterland return (B_TRUE); 1163*5c51f124SMoriah Waterland } 1164*5c51f124SMoriah Waterland 1165*5c51f124SMoriah Waterland /* get the X509v3 extension holding the OCSP URI */ 1166*5c51f124SMoriah Waterland if ((aia = X509_get_ext_d2i(cert, NID_info_access, 1167*5c51f124SMoriah Waterland NULL, NULL)) != NULL) { 1168*5c51f124SMoriah Waterland for (i = 0; i < sk_ACCESS_DESCRIPTION_num(aia); i++) { 1169*5c51f124SMoriah Waterland ad = sk_ACCESS_DESCRIPTION_value(aia, i); 1170*5c51f124SMoriah Waterland if (OBJ_obj2nid(ad->method) == NID_ad_OCSP) { 1171*5c51f124SMoriah Waterland if (ad->location->type == GEN_URI) { 1172*5c51f124SMoriah Waterland *uri = 1173*5c51f124SMoriah Waterland xstrdup((char *)ASN1_STRING_data(ad->location->d.ia5)); 1174*5c51f124SMoriah Waterland return (B_TRUE); 1175*5c51f124SMoriah Waterland } 1176*5c51f124SMoriah Waterland } 1177*5c51f124SMoriah Waterland } 1178*5c51f124SMoriah Waterland } 1179*5c51f124SMoriah Waterland 1180*5c51f124SMoriah Waterland /* no URI was found */ 1181*5c51f124SMoriah Waterland return (B_FALSE); 1182*5c51f124SMoriah Waterland } 1183*5c51f124SMoriah Waterland 1184*5c51f124SMoriah Waterland /* 1185*5c51f124SMoriah Waterland * Name: ocsp_verify 1186*5c51f124SMoriah Waterland * Description: Attempts to contact an OCSP Responder and ascertain the validity 1187*5c51f124SMoriah Waterland * of an X509 certificate. 1188*5c51f124SMoriah Waterland * 1189*5c51f124SMoriah Waterland * Arguments: err - Error object to add error messages to 1190*5c51f124SMoriah Waterland * cert - The cert to validate 1191*5c51f124SMoriah Waterland * issuer - The certificate of the issuer of 'cert' 1192*5c51f124SMoriah Waterland * uri - The OCSP Responder URI 1193*5c51f124SMoriah Waterland * cas - The trusted CA certificates used to verify the 1194*5c51f124SMoriah Waterland * signed OCSP response 1195*5c51f124SMoriah Waterland * Returns : Success - The OCSP Responder reported a 'good' 1196*5c51f124SMoriah Waterland * status for the cert otherwise, appropriate 1197*5c51f124SMoriah Waterland * error is returned. 1198*5c51f124SMoriah Waterland */ 1199*5c51f124SMoriah Waterland static OCSPStatus 1200*5c51f124SMoriah Waterland ocsp_verify(PKG_ERR *err, X509 *cert, X509 *issuer, 1201*5c51f124SMoriah Waterland char *uri, url_hport_t *proxy, STACK_OF(X509) *cas) 1202*5c51f124SMoriah Waterland { 1203*5c51f124SMoriah Waterland OCSP_CERTID *id; 1204*5c51f124SMoriah Waterland OCSP_REQUEST *req; 1205*5c51f124SMoriah Waterland OCSP_RESPONSE *resp; 1206*5c51f124SMoriah Waterland OCSP_BASICRESP *bs; 1207*5c51f124SMoriah Waterland BIO *cbio, *mem; 1208*5c51f124SMoriah Waterland char ocspbuf[OCSP_BUFSIZ]; 1209*5c51f124SMoriah Waterland char *host = NULL, *portstr = NULL, *path = "/", *p, *q, *r; 1210*5c51f124SMoriah Waterland int port, status, reason; 1211*5c51f124SMoriah Waterland int len, retval, respcode, use_ssl = 0; 1212*5c51f124SMoriah Waterland ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; 1213*5c51f124SMoriah Waterland char *subjname; 1214*5c51f124SMoriah Waterland time_t currtime; 1215*5c51f124SMoriah Waterland char currtimestr[ATTR_MAX]; 1216*5c51f124SMoriah Waterland unsigned long errcode; 1217*5c51f124SMoriah Waterland const char *err_reason; 1218*5c51f124SMoriah Waterland 1219*5c51f124SMoriah Waterland subjname = get_subject_display_name(cert); 1220*5c51f124SMoriah Waterland 1221*5c51f124SMoriah Waterland /* parse the URI into its constituent parts */ 1222*5c51f124SMoriah Waterland if (OCSP_parse_url(uri, &host, &portstr, &path, &use_ssl) == NULL) { 1223*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_PARSE), uri); 1224*5c51f124SMoriah Waterland return (OCSPParse); 1225*5c51f124SMoriah Waterland } 1226*5c51f124SMoriah Waterland 1227*5c51f124SMoriah Waterland /* we don't currently support SSL-based OCSP Responders */ 1228*5c51f124SMoriah Waterland if (use_ssl) { 1229*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_UNSUP), uri); 1230*5c51f124SMoriah Waterland return (OCSPUnsupported); 1231*5c51f124SMoriah Waterland } 1232*5c51f124SMoriah Waterland 1233*5c51f124SMoriah Waterland /* default port if none specified */ 1234*5c51f124SMoriah Waterland if (portstr == NULL) { 1235*5c51f124SMoriah Waterland port = (int)URL_DFLT_SRVR_PORT; 1236*5c51f124SMoriah Waterland } else { 1237*5c51f124SMoriah Waterland port = (int)strtoul(portstr, &r, 10); 1238*5c51f124SMoriah Waterland if (*r != '\0') { 1239*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1240*5c51f124SMoriah Waterland gettext(ERR_OCSP_PARSE), uri); 1241*5c51f124SMoriah Waterland return (OCSPParse); 1242*5c51f124SMoriah Waterland } 1243*5c51f124SMoriah Waterland } 1244*5c51f124SMoriah Waterland 1245*5c51f124SMoriah Waterland /* allocate new request structure */ 1246*5c51f124SMoriah Waterland if ((req = OCSP_REQUEST_new()) == NULL) { 1247*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); 1248*5c51f124SMoriah Waterland return (OCSPMem); 1249*5c51f124SMoriah Waterland } 1250*5c51f124SMoriah Waterland 1251*5c51f124SMoriah Waterland /* convert cert and issuer fields into OCSP request data */ 1252*5c51f124SMoriah Waterland if ((id = OCSP_cert_to_id(NULL, cert, issuer)) == NULL) { 1253*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_PKG_INTERNAL), 1254*5c51f124SMoriah Waterland __FILE__, __LINE__); 1255*5c51f124SMoriah Waterland return (OCSPInternal); 1256*5c51f124SMoriah Waterland } 1257*5c51f124SMoriah Waterland 1258*5c51f124SMoriah Waterland /* fill out request structure with request data */ 1259*5c51f124SMoriah Waterland if ((OCSP_request_add0_id(req, id)) == NULL) { 1260*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_PKG_INTERNAL), 1261*5c51f124SMoriah Waterland __FILE__, __LINE__); 1262*5c51f124SMoriah Waterland return (OCSPInternal); 1263*5c51f124SMoriah Waterland } 1264*5c51f124SMoriah Waterland 1265*5c51f124SMoriah Waterland /* add nonce */ 1266*5c51f124SMoriah Waterland OCSP_request_add1_nonce(req, NULL, -1); 1267*5c51f124SMoriah Waterland 1268*5c51f124SMoriah Waterland /* connect to host, or proxy */ 1269*5c51f124SMoriah Waterland if (proxy != NULL) { 1270*5c51f124SMoriah Waterland if ((cbio = BIO_new_connect(proxy->hostname)) == NULL) { 1271*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); 1272*5c51f124SMoriah Waterland return (OCSPMem); 1273*5c51f124SMoriah Waterland } 1274*5c51f124SMoriah Waterland 1275*5c51f124SMoriah Waterland /* 1276*5c51f124SMoriah Waterland * BIO_set_conn_int_port takes an int *, so let's give it one 1277*5c51f124SMoriah Waterland * rather than an ushort_t * 1278*5c51f124SMoriah Waterland */ 1279*5c51f124SMoriah Waterland port = proxy->port; 1280*5c51f124SMoriah Waterland (void) BIO_set_conn_int_port(cbio, &port); 1281*5c51f124SMoriah Waterland if (BIO_do_connect(cbio) <= 0) { 1282*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1283*5c51f124SMoriah Waterland gettext(ERR_OCSP_CONNECT), 1284*5c51f124SMoriah Waterland proxy->hostname, port); 1285*5c51f124SMoriah Waterland return (OCSPConnect); 1286*5c51f124SMoriah Waterland } 1287*5c51f124SMoriah Waterland } else { 1288*5c51f124SMoriah Waterland if ((cbio = BIO_new_connect(host)) == NULL) { 1289*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); 1290*5c51f124SMoriah Waterland return (OCSPMem); 1291*5c51f124SMoriah Waterland } 1292*5c51f124SMoriah Waterland 1293*5c51f124SMoriah Waterland (void) BIO_set_conn_int_port(cbio, &port); 1294*5c51f124SMoriah Waterland if (BIO_do_connect(cbio) <= 0) { 1295*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1296*5c51f124SMoriah Waterland gettext(ERR_OCSP_CONNECT), 1297*5c51f124SMoriah Waterland host, port); 1298*5c51f124SMoriah Waterland return (OCSPConnect); 1299*5c51f124SMoriah Waterland } 1300*5c51f124SMoriah Waterland } 1301*5c51f124SMoriah Waterland 1302*5c51f124SMoriah Waterland /* calculate length of binary request data */ 1303*5c51f124SMoriah Waterland len = i2d_OCSP_REQUEST(req, NULL); 1304*5c51f124SMoriah Waterland 1305*5c51f124SMoriah Waterland /* send the request headers */ 1306*5c51f124SMoriah Waterland if (proxy != NULL) { 1307*5c51f124SMoriah Waterland retval = BIO_printf(cbio, OCSP_REQUEST_FORMAT, uri, len); 1308*5c51f124SMoriah Waterland } else { 1309*5c51f124SMoriah Waterland retval = BIO_printf(cbio, OCSP_REQUEST_FORMAT, path, len); 1310*5c51f124SMoriah Waterland } 1311*5c51f124SMoriah Waterland 1312*5c51f124SMoriah Waterland if (retval <= 0) { 1313*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_SEND), host); 1314*5c51f124SMoriah Waterland return (OCSPRequest); 1315*5c51f124SMoriah Waterland } 1316*5c51f124SMoriah Waterland 1317*5c51f124SMoriah Waterland /* send the request binary data */ 1318*5c51f124SMoriah Waterland if (i2d_OCSP_REQUEST_bio(cbio, req) <= 0) { 1319*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_SEND), host); 1320*5c51f124SMoriah Waterland return (OCSPRequest); 1321*5c51f124SMoriah Waterland } 1322*5c51f124SMoriah Waterland 1323*5c51f124SMoriah Waterland /* 1324*5c51f124SMoriah Waterland * read the response into a memory BIO, so we can 'gets' 1325*5c51f124SMoriah Waterland * (socket bio's don't support BIO_gets) 1326*5c51f124SMoriah Waterland */ 1327*5c51f124SMoriah Waterland if ((mem = BIO_new(BIO_s_mem())) == NULL) { 1328*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); 1329*5c51f124SMoriah Waterland return (OCSPMem); 1330*5c51f124SMoriah Waterland } 1331*5c51f124SMoriah Waterland 1332*5c51f124SMoriah Waterland while ((len = BIO_read(cbio, ocspbuf, OCSP_BUFSIZ))) { 1333*5c51f124SMoriah Waterland if (len < 0) { 1334*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1335*5c51f124SMoriah Waterland gettext(ERR_OCSP_READ), host); 1336*5c51f124SMoriah Waterland return (OCSPRequest); 1337*5c51f124SMoriah Waterland } 1338*5c51f124SMoriah Waterland if (BIO_write(mem, ocspbuf, len) != len) { 1339*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); 1340*5c51f124SMoriah Waterland return (OCSPMem); 1341*5c51f124SMoriah Waterland } 1342*5c51f124SMoriah Waterland } 1343*5c51f124SMoriah Waterland 1344*5c51f124SMoriah Waterland /* now get the first line of the response */ 1345*5c51f124SMoriah Waterland if (BIO_gets(mem, ocspbuf, OCSP_BUFSIZ) <= 0) { 1346*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_RESP_PARSE)); 1347*5c51f124SMoriah Waterland return (OCSPRequest); 1348*5c51f124SMoriah Waterland } 1349*5c51f124SMoriah Waterland 1350*5c51f124SMoriah Waterland /* parse the header response */ 1351*5c51f124SMoriah Waterland /* it should look like "HTTP/x.x 200 OK" */ 1352*5c51f124SMoriah Waterland 1353*5c51f124SMoriah Waterland /* skip past the protocol info */ 1354*5c51f124SMoriah Waterland for (p = ocspbuf; (*p != '\0') && !isspace(*p); p++) 1355*5c51f124SMoriah Waterland continue; 1356*5c51f124SMoriah Waterland 1357*5c51f124SMoriah Waterland /* skip past whitespace betwen protocol and start of response code */ 1358*5c51f124SMoriah Waterland while ((*p != '\0') && isspace(*p)) { 1359*5c51f124SMoriah Waterland p++; 1360*5c51f124SMoriah Waterland } 1361*5c51f124SMoriah Waterland 1362*5c51f124SMoriah Waterland if (*p == '\0') { 1363*5c51f124SMoriah Waterland /* premature end */ 1364*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1365*5c51f124SMoriah Waterland gettext(ERR_OCSP_RESP_PARSE), ocspbuf); 1366*5c51f124SMoriah Waterland return (OCSPRequest); 1367*5c51f124SMoriah Waterland } 1368*5c51f124SMoriah Waterland 1369*5c51f124SMoriah Waterland /* find end of response code */ 1370*5c51f124SMoriah Waterland for (q = p; (*q != NULL) && !isspace(*q); q++) 1371*5c51f124SMoriah Waterland continue; 1372*5c51f124SMoriah Waterland 1373*5c51f124SMoriah Waterland /* mark end of response code */ 1374*5c51f124SMoriah Waterland *q++ = '\0'; 1375*5c51f124SMoriah Waterland 1376*5c51f124SMoriah Waterland /* parse response code */ 1377*5c51f124SMoriah Waterland respcode = strtoul(p, &r, 10); 1378*5c51f124SMoriah Waterland if (*r != '\0') { 1379*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1380*5c51f124SMoriah Waterland gettext(ERR_OCSP_RESP_PARSE), ocspbuf); 1381*5c51f124SMoriah Waterland return (OCSPRequest); 1382*5c51f124SMoriah Waterland } 1383*5c51f124SMoriah Waterland 1384*5c51f124SMoriah Waterland /* now find beginning of the response string */ 1385*5c51f124SMoriah Waterland while ((*q != NULL) && isspace(*q)) { 1386*5c51f124SMoriah Waterland q++; 1387*5c51f124SMoriah Waterland } 1388*5c51f124SMoriah Waterland 1389*5c51f124SMoriah Waterland /* trim whitespace from end of message */ 1390*5c51f124SMoriah Waterland for (r = (q + strlen(q) - 1); isspace(*r); r--) { 1391*5c51f124SMoriah Waterland *r = '\0'; 1392*5c51f124SMoriah Waterland } 1393*5c51f124SMoriah Waterland 1394*5c51f124SMoriah Waterland /* response must be OK */ 1395*5c51f124SMoriah Waterland if (respcode != 200) { 1396*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1397*5c51f124SMoriah Waterland gettext(ERR_OCSP_RESP_NOTOK), 200, 1398*5c51f124SMoriah Waterland respcode, q); 1399*5c51f124SMoriah Waterland return (OCSPRequest); 1400*5c51f124SMoriah Waterland } 1401*5c51f124SMoriah Waterland 1402*5c51f124SMoriah Waterland /* read headers, looking for content-type or a blank line */ 1403*5c51f124SMoriah Waterland while (BIO_gets(mem, ocspbuf, OCSP_BUFSIZ) > 0) { 1404*5c51f124SMoriah Waterland 1405*5c51f124SMoriah Waterland /* if we get a content type, make sure it's the right type */ 1406*5c51f124SMoriah Waterland if (ci_strneq(ocspbuf, CONTENT_TYPE_HDR, 1407*5c51f124SMoriah Waterland strlen(CONTENT_TYPE_HDR))) { 1408*5c51f124SMoriah Waterland 1409*5c51f124SMoriah Waterland /* look for the delimiting : */ 1410*5c51f124SMoriah Waterland p = strchr(ocspbuf + strlen(CONTENT_TYPE_HDR), ':'); 1411*5c51f124SMoriah Waterland 1412*5c51f124SMoriah Waterland if (p == NULL) { 1413*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1414*5c51f124SMoriah Waterland gettext(ERR_OCSP_RESP_PARSE), ocspbuf); 1415*5c51f124SMoriah Waterland return (OCSPResponder); 1416*5c51f124SMoriah Waterland } 1417*5c51f124SMoriah Waterland 1418*5c51f124SMoriah Waterland /* skip over ':' */ 1419*5c51f124SMoriah Waterland p++; 1420*5c51f124SMoriah Waterland 1421*5c51f124SMoriah Waterland /* find beginning of the content type */ 1422*5c51f124SMoriah Waterland while ((*p != NULL) && isspace(*p)) { 1423*5c51f124SMoriah Waterland p++; 1424*5c51f124SMoriah Waterland } 1425*5c51f124SMoriah Waterland 1426*5c51f124SMoriah Waterland if (!ci_strneq(p, CONTENT_OCSP_RESP, 1427*5c51f124SMoriah Waterland strlen(CONTENT_OCSP_RESP))) { 1428*5c51f124SMoriah Waterland /* response is not right type */ 1429*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1430*5c51f124SMoriah Waterland gettext(ERR_OCSP_RESP_TYPE), 1431*5c51f124SMoriah Waterland p, CONTENT_OCSP_RESP); 1432*5c51f124SMoriah Waterland return (OCSPResponder); 1433*5c51f124SMoriah Waterland } 1434*5c51f124SMoriah Waterland 1435*5c51f124SMoriah Waterland /* continue with next header line */ 1436*5c51f124SMoriah Waterland continue; 1437*5c51f124SMoriah Waterland } 1438*5c51f124SMoriah Waterland 1439*5c51f124SMoriah Waterland /* scan looking for a character */ 1440*5c51f124SMoriah Waterland for (p = ocspbuf; (*p != '\0') && isspace(*p); p++) { 1441*5c51f124SMoriah Waterland continue; 1442*5c51f124SMoriah Waterland } 1443*5c51f124SMoriah Waterland /* 1444*5c51f124SMoriah Waterland * if we got to the end of the line with 1445*5c51f124SMoriah Waterland * no chars, then this is a blank line 1446*5c51f124SMoriah Waterland */ 1447*5c51f124SMoriah Waterland if (*p == '\0') { 1448*5c51f124SMoriah Waterland break; 1449*5c51f124SMoriah Waterland } 1450*5c51f124SMoriah Waterland } 1451*5c51f124SMoriah Waterland 1452*5c51f124SMoriah Waterland 1453*5c51f124SMoriah Waterland if (*p != '\0') { 1454*5c51f124SMoriah Waterland /* last line was not blank */ 1455*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1456*5c51f124SMoriah Waterland gettext(ERR_OCSP_RESP_PARSE), ocspbuf); 1457*5c51f124SMoriah Waterland return (OCSPResponder); 1458*5c51f124SMoriah Waterland } 1459*5c51f124SMoriah Waterland 1460*5c51f124SMoriah Waterland /* now read in the binary response */ 1461*5c51f124SMoriah Waterland if ((resp = d2i_OCSP_RESPONSE_bio(mem, NULL)) == NULL) { 1462*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_READ), host); 1463*5c51f124SMoriah Waterland return (OCSPResponder); 1464*5c51f124SMoriah Waterland } 1465*5c51f124SMoriah Waterland 1466*5c51f124SMoriah Waterland /* free temp BIOs */ 1467*5c51f124SMoriah Waterland (void) BIO_free(mem); 1468*5c51f124SMoriah Waterland (void) BIO_free_all(cbio); 1469*5c51f124SMoriah Waterland cbio = NULL; 1470*5c51f124SMoriah Waterland 1471*5c51f124SMoriah Waterland /* make sure request was successful */ 1472*5c51f124SMoriah Waterland if (OCSP_response_status(resp) != OCSP_RESPONSE_STATUS_SUCCESSFUL) { 1473*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_RESP_NOTOK), 1474*5c51f124SMoriah Waterland OCSP_RESPONSE_STATUS_SUCCESSFUL, 1475*5c51f124SMoriah Waterland OCSP_response_status(resp), 1476*5c51f124SMoriah Waterland OCSP_response_status_str(OCSP_response_status(resp))); 1477*5c51f124SMoriah Waterland return (OCSPResponder); 1478*5c51f124SMoriah Waterland } 1479*5c51f124SMoriah Waterland 1480*5c51f124SMoriah Waterland /* parse binary response into internal structure */ 1481*5c51f124SMoriah Waterland if ((bs = OCSP_response_get1_basic(resp)) == NULL) { 1482*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_READ), host); 1483*5c51f124SMoriah Waterland return (OCSPParse); 1484*5c51f124SMoriah Waterland } 1485*5c51f124SMoriah Waterland 1486*5c51f124SMoriah Waterland /* 1487*5c51f124SMoriah Waterland * From here to the end of the code, the return values 1488*5c51f124SMoriah Waterland * should be hard failures 1489*5c51f124SMoriah Waterland */ 1490*5c51f124SMoriah Waterland 1491*5c51f124SMoriah Waterland /* verify the response, warn if no nonce */ 1492*5c51f124SMoriah Waterland if (OCSP_check_nonce(req, bs) <= 0) { 1493*5c51f124SMoriah Waterland logerr(pkg_gt(WRN_OCSP_RESP_NONCE)); 1494*5c51f124SMoriah Waterland } 1495*5c51f124SMoriah Waterland 1496*5c51f124SMoriah Waterland if (OCSP_basic_verify(bs, cas, NULL, OCSP_TRUSTOTHER) <= 0) { 1497*5c51f124SMoriah Waterland while ((errcode = ERR_get_error()) != NULL) { 1498*5c51f124SMoriah Waterland err_reason = ERR_reason_error_string(errcode); 1499*5c51f124SMoriah Waterland if (err_reason == NULL) { 1500*5c51f124SMoriah Waterland err_reason = 1501*5c51f124SMoriah Waterland gettext(ERR_SIG_INT); 1502*5c51f124SMoriah Waterland } 1503*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, (char *)err_reason); 1504*5c51f124SMoriah Waterland } 1505*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_VERIFY_FAIL), 1506*5c51f124SMoriah Waterland uri); 1507*5c51f124SMoriah Waterland return (OCSPVerify); 1508*5c51f124SMoriah Waterland } 1509*5c51f124SMoriah Waterland 1510*5c51f124SMoriah Waterland /* check the validity of our certificate */ 1511*5c51f124SMoriah Waterland if (OCSP_resp_find_status(bs, id, &status, &reason, 1512*5c51f124SMoriah Waterland &rev, &thisupd, &nextupd) == NULL) { 1513*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1514*5c51f124SMoriah Waterland gettext(ERR_OCSP_VERIFY_NO_STATUS), subjname); 1515*5c51f124SMoriah Waterland return (OCSPVerify); 1516*5c51f124SMoriah Waterland } 1517*5c51f124SMoriah Waterland 1518*5c51f124SMoriah Waterland if ((currtime = time(NULL)) == (time_t)-1) { 1519*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1520*5c51f124SMoriah Waterland gettext(ERR_OCSP_VERIFY_NOTIME)); 1521*5c51f124SMoriah Waterland return (OCSPVerify); 1522*5c51f124SMoriah Waterland } 1523*5c51f124SMoriah Waterland 1524*5c51f124SMoriah Waterland (void) strlcpy(currtimestr, ctime(&currtime), ATTR_MAX); 1525*5c51f124SMoriah Waterland 1526*5c51f124SMoriah Waterland /* trim end */ 1527*5c51f124SMoriah Waterland for (r = currtimestr + strlen(currtimestr) - 1; 1528*5c51f124SMoriah Waterland isspace(*r); r--) { 1529*5c51f124SMoriah Waterland *r = '\0'; 1530*5c51f124SMoriah Waterland } 1531*5c51f124SMoriah Waterland 1532*5c51f124SMoriah Waterland if (!OCSP_check_validity(thisupd, nextupd, 1533*5c51f124SMoriah Waterland OCSP_VALIDITY_PERIOD, -1)) { 1534*5c51f124SMoriah Waterland if (nextupd != NULL) { 1535*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1536*5c51f124SMoriah Waterland gettext(ERR_OCSP_VERIFY_VALIDITY), 1537*5c51f124SMoriah Waterland get_time_string(thisupd), get_time_string(nextupd), 1538*5c51f124SMoriah Waterland currtimestr); 1539*5c51f124SMoriah Waterland } else { 1540*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1541*5c51f124SMoriah Waterland gettext(ERR_OCSP_VERIFY_VALIDITY), 1542*5c51f124SMoriah Waterland get_time_string(thisupd), 1543*5c51f124SMoriah Waterland currtimestr); 1544*5c51f124SMoriah Waterland } 1545*5c51f124SMoriah Waterland return (OCSPVerify); 1546*5c51f124SMoriah Waterland } 1547*5c51f124SMoriah Waterland 1548*5c51f124SMoriah Waterland if (status != V_OCSP_CERTSTATUS_GOOD) { 1549*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 1550*5c51f124SMoriah Waterland gettext(ERR_OCSP_VERIFY_STATUS), subjname, 1551*5c51f124SMoriah Waterland OCSP_cert_status_str(status)); 1552*5c51f124SMoriah Waterland return (OCSPVerify); 1553*5c51f124SMoriah Waterland } 1554*5c51f124SMoriah Waterland 1555*5c51f124SMoriah Waterland /* everythign checks out */ 1556*5c51f124SMoriah Waterland return (OCSPSuccess); 1557*5c51f124SMoriah Waterland } 1558*5c51f124SMoriah Waterland 1559*5c51f124SMoriah Waterland /* 1560*5c51f124SMoriah Waterland * Name: get_issuer 1561*5c51f124SMoriah Waterland * Description: Attempts to find the issuing certificate for a given certificate 1562*5c51f124SMoriah Waterland * This will look in both the list of trusted certificates found in 1563*5c51f124SMoriah Waterland * the X509_STORE_CTX structure, as well as the list of untrusted 1564*5c51f124SMoriah Waterland * chain certificates found in the X509_STORE_CTX structure. 1565*5c51f124SMoriah Waterland * Arguments: 1566*5c51f124SMoriah Waterland * issuer - The resulting issuer cert is placed here, if found 1567*5c51f124SMoriah Waterland * ctx - The current verification context 1568*5c51f124SMoriah Waterland * x - The certificate whose issuer we are looking for 1569*5c51f124SMoriah Waterland * Returns : Success - The issuer cert was found and placed in *issuer. 1570*5c51f124SMoriah Waterland * otherwise, appropriate error is returned. 1571*5c51f124SMoriah Waterland */ 1572*5c51f124SMoriah Waterland static int 1573*5c51f124SMoriah Waterland get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) 1574*5c51f124SMoriah Waterland { 1575*5c51f124SMoriah Waterland int i, ok; 1576*5c51f124SMoriah Waterland 1577*5c51f124SMoriah Waterland /* 1578*5c51f124SMoriah Waterland * first look in the list of trusted 1579*5c51f124SMoriah Waterland * certs, using the context's method to do so 1580*5c51f124SMoriah Waterland */ 1581*5c51f124SMoriah Waterland if ((ok = ctx->get_issuer(issuer, ctx, x)) > 0) { 1582*5c51f124SMoriah Waterland return (ok); 1583*5c51f124SMoriah Waterland } 1584*5c51f124SMoriah Waterland 1585*5c51f124SMoriah Waterland if (ctx->untrusted != NULL) { 1586*5c51f124SMoriah Waterland /* didn't find it in trusted certs, look through untrusted */ 1587*5c51f124SMoriah Waterland for (i = 0; i < sk_X509_num(ctx->untrusted); i++) { 1588*5c51f124SMoriah Waterland if (X509_check_issued(sk_X509_value(ctx->untrusted, i), 1589*5c51f124SMoriah Waterland x) == X509_V_OK) { 1590*5c51f124SMoriah Waterland *issuer = sk_X509_value(ctx->untrusted, i); 1591*5c51f124SMoriah Waterland return (1); 1592*5c51f124SMoriah Waterland } 1593*5c51f124SMoriah Waterland } 1594*5c51f124SMoriah Waterland } 1595*5c51f124SMoriah Waterland *issuer = NULL; 1596*5c51f124SMoriah Waterland return (0); 1597*5c51f124SMoriah Waterland } 1598*5c51f124SMoriah Waterland 1599*5c51f124SMoriah Waterland /* 1600*5c51f124SMoriah Waterland * Name: parse_url_proxy 1601*5c51f124SMoriah Waterland * Description: Parses URL and optional proxy specification, populates static 1602*5c51f124SMoriah Waterland * 'ps' structure 1603*5c51f124SMoriah Waterland * 1604*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 1605*5c51f124SMoriah Waterland * url - URL to parse 1606*5c51f124SMoriah Waterland * proxy - proxy to parse, or NULL for no proxy 1607*5c51f124SMoriah Waterland * proxy_port - Default proxy port to use if no proxy 1608*5c51f124SMoriah Waterland * port specified in 'proxy' 1609*5c51f124SMoriah Waterland * 1610*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 1611*5c51f124SMoriah Waterland * on success, 'ps->url' and 'ps->proxy' are populated 1612*5c51f124SMoriah Waterland * with parsed data. 1613*5c51f124SMoriah Waterland */ 1614*5c51f124SMoriah Waterland static boolean_t 1615*5c51f124SMoriah Waterland parse_url_proxy(PKG_ERR *err, char *url, char *proxy, ushort_t proxy_port) 1616*5c51f124SMoriah Waterland { 1617*5c51f124SMoriah Waterland boolean_t ret = B_TRUE; 1618*5c51f124SMoriah Waterland if (!path_valid(url)) { 1619*5c51f124SMoriah Waterland ret = B_FALSE; 1620*5c51f124SMoriah Waterland goto cleanup; 1621*5c51f124SMoriah Waterland } 1622*5c51f124SMoriah Waterland 1623*5c51f124SMoriah Waterland if (url_parse(url, &ps->url) != URL_PARSE_SUCCESS) { 1624*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_PARSE_URL), url); 1625*5c51f124SMoriah Waterland ret = B_FALSE; 1626*5c51f124SMoriah Waterland goto cleanup; 1627*5c51f124SMoriah Waterland } 1628*5c51f124SMoriah Waterland 1629*5c51f124SMoriah Waterland if (proxy != NULL) { 1630*5c51f124SMoriah Waterland if (url_parse_hostport(proxy, &ps->proxy, proxy_port) 1631*5c51f124SMoriah Waterland != URL_PARSE_SUCCESS) { 1632*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 1633*5c51f124SMoriah Waterland gettext(ERR_BAD_PROXY), proxy); 1634*5c51f124SMoriah Waterland ret = B_FALSE; 1635*5c51f124SMoriah Waterland goto cleanup; 1636*5c51f124SMoriah Waterland } 1637*5c51f124SMoriah Waterland } 1638*5c51f124SMoriah Waterland 1639*5c51f124SMoriah Waterland cleanup: 1640*5c51f124SMoriah Waterland return (ret); 1641*5c51f124SMoriah Waterland } 1642*5c51f124SMoriah Waterland 1643*5c51f124SMoriah Waterland /* 1644*5c51f124SMoriah Waterland * Name: web_setup 1645*5c51f124SMoriah Waterland * Description: Initializes http library settings 1646*5c51f124SMoriah Waterland * 1647*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 1648*5c51f124SMoriah Waterland * 1649*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 1650*5c51f124SMoriah Waterland */ 1651*5c51f124SMoriah Waterland static boolean_t 1652*5c51f124SMoriah Waterland web_setup(PKG_ERR *err) 1653*5c51f124SMoriah Waterland { 1654*5c51f124SMoriah Waterland boolean_t ret = B_TRUE; 1655*5c51f124SMoriah Waterland static boolean_t keepalive = B_TRUE; 1656*5c51f124SMoriah Waterland 1657*5c51f124SMoriah Waterland if ((ps->hps = http_srv_init(&ps->url)) == NULL) { 1658*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); 1659*5c51f124SMoriah Waterland ret = B_FALSE; 1660*5c51f124SMoriah Waterland goto cleanup; 1661*5c51f124SMoriah Waterland } 1662*5c51f124SMoriah Waterland 1663*5c51f124SMoriah Waterland if (getenv("WEBPKG_DEBUG") != NULL) { 1664*5c51f124SMoriah Waterland http_set_verbose(B_TRUE); 1665*5c51f124SMoriah Waterland } 1666*5c51f124SMoriah Waterland 1667*5c51f124SMoriah Waterland if (ps->proxy.hostname[0] != '\0' && 1668*5c51f124SMoriah Waterland http_set_proxy(ps->hps, &ps->proxy) != 0) { 1669*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); 1670*5c51f124SMoriah Waterland ret = B_FALSE; 1671*5c51f124SMoriah Waterland goto cleanup; 1672*5c51f124SMoriah Waterland } 1673*5c51f124SMoriah Waterland if (http_set_keepalive(ps->hps, keepalive) != 0) { 1674*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); 1675*5c51f124SMoriah Waterland ret = B_FALSE; 1676*5c51f124SMoriah Waterland goto cleanup; 1677*5c51f124SMoriah Waterland } 1678*5c51f124SMoriah Waterland if (http_set_socket_read_timeout(ps->hps, ps->timeout) != 0) { 1679*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); 1680*5c51f124SMoriah Waterland ret = B_FALSE; 1681*5c51f124SMoriah Waterland goto cleanup; 1682*5c51f124SMoriah Waterland } 1683*5c51f124SMoriah Waterland if (http_set_random_file(ps->hps, RANDOM) != 0) { 1684*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); 1685*5c51f124SMoriah Waterland ret = B_FALSE; 1686*5c51f124SMoriah Waterland goto cleanup; 1687*5c51f124SMoriah Waterland } 1688*5c51f124SMoriah Waterland 1689*5c51f124SMoriah Waterland (void) http_set_p12_format(B_TRUE); 1690*5c51f124SMoriah Waterland 1691*5c51f124SMoriah Waterland cleanup: 1692*5c51f124SMoriah Waterland return (ret); 1693*5c51f124SMoriah Waterland } 1694*5c51f124SMoriah Waterland 1695*5c51f124SMoriah Waterland /* 1696*5c51f124SMoriah Waterland * Name: web_connect 1697*5c51f124SMoriah Waterland * Description: Makes connection with URL stored in static 'ps' structure. 1698*5c51f124SMoriah Waterland * 1699*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 1700*5c51f124SMoriah Waterland * 1701*5c51f124SMoriah Waterland * Returns : WEB_OK - connection successful 1702*5c51f124SMoriah Waterland * WEB_VERIFY_SETUP - Unable to complete necessary 1703*5c51f124SMoriah Waterland * SSL setup 1704*5c51f124SMoriah Waterland * WEB_CONNREFUSED - Connection was refused to web site 1705*5c51f124SMoriah Waterland * WEB_HOSTDOWN - Host was not responding to request 1706*5c51f124SMoriah Waterland * WEB_NOCONNECT - Some other connection failure 1707*5c51f124SMoriah Waterland */ 1708*5c51f124SMoriah Waterland static WebStatus 1709*5c51f124SMoriah Waterland web_connect(PKG_ERR *err) 1710*5c51f124SMoriah Waterland { 1711*5c51f124SMoriah Waterland STACK_OF(X509) *sec_cas = NULL; 1712*5c51f124SMoriah Waterland char *path; 1713*5c51f124SMoriah Waterland WebStatus ret = WEB_OK; 1714*5c51f124SMoriah Waterland ulong_t errcode; 1715*5c51f124SMoriah Waterland uint_t errsrc; 1716*5c51f124SMoriah Waterland int my_errno = 0; 1717*5c51f124SMoriah Waterland const char *libhttperr = NULL; 1718*5c51f124SMoriah Waterland 1719*5c51f124SMoriah Waterland if (ps->url.https == B_TRUE) { 1720*5c51f124SMoriah Waterland /* get CA certificates */ 1721*5c51f124SMoriah Waterland if (find_ca_certs(err, ps->keystore, &sec_cas) != 0) { 1722*5c51f124SMoriah Waterland ret = WEB_VERIFY_SETUP; 1723*5c51f124SMoriah Waterland goto cleanup; 1724*5c51f124SMoriah Waterland } 1725*5c51f124SMoriah Waterland 1726*5c51f124SMoriah Waterland if (sk_X509_num(sec_cas) < 1) { 1727*5c51f124SMoriah Waterland /* no trusted websites */ 1728*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 1729*5c51f124SMoriah Waterland gettext(ERR_KEYSTORE_NOTRUST)); 1730*5c51f124SMoriah Waterland ret = WEB_VERIFY_SETUP; 1731*5c51f124SMoriah Waterland goto cleanup; 1732*5c51f124SMoriah Waterland } 1733*5c51f124SMoriah Waterland 1734*5c51f124SMoriah Waterland /* 1735*5c51f124SMoriah Waterland * write out all CA certs to temp file. libwanboot should 1736*5c51f124SMoriah Waterland * have an interface for giving it a list of trusted certs 1737*5c51f124SMoriah Waterland * through an in-memory structure, but currently that does 1738*5c51f124SMoriah Waterland * not exist 1739*5c51f124SMoriah Waterland */ 1740*5c51f124SMoriah Waterland if ((path = write_ca_file(err, ps->dwnld_dir, sec_cas, 1741*5c51f124SMoriah Waterland WEB_CA_PHRASE)) == NULL) { 1742*5c51f124SMoriah Waterland ret = WEB_VERIFY_SETUP; 1743*5c51f124SMoriah Waterland goto cleanup; 1744*5c51f124SMoriah Waterland } 1745*5c51f124SMoriah Waterland 1746*5c51f124SMoriah Waterland ps->certfile = path; 1747*5c51f124SMoriah Waterland if (http_set_password(ps->hps, WEB_CA_PHRASE) != 0) { 1748*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 1749*5c51f124SMoriah Waterland gettext(ERR_HTTPS_PASSWD)); 1750*5c51f124SMoriah Waterland ret = WEB_VERIFY_SETUP; 1751*5c51f124SMoriah Waterland goto cleanup; 1752*5c51f124SMoriah Waterland } 1753*5c51f124SMoriah Waterland 1754*5c51f124SMoriah Waterland if (http_set_certificate_authority_file(path) != 0) { 1755*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 1756*5c51f124SMoriah Waterland gettext(ERR_HTTPS_CA)); 1757*5c51f124SMoriah Waterland ret = WEB_VERIFY_SETUP; 1758*5c51f124SMoriah Waterland goto cleanup; 1759*5c51f124SMoriah Waterland } 1760*5c51f124SMoriah Waterland } 1761*5c51f124SMoriah Waterland 1762*5c51f124SMoriah Waterland if (http_srv_connect(ps->hps) != 0) { 1763*5c51f124SMoriah Waterland while ((errcode = http_get_lasterr(ps->hps, &errsrc)) != 0) { 1764*5c51f124SMoriah Waterland /* Have an error - is it EINTR? */ 1765*5c51f124SMoriah Waterland if (errsrc == ERRSRC_SYSTEM) { 1766*5c51f124SMoriah Waterland my_errno = errcode; 1767*5c51f124SMoriah Waterland break; 1768*5c51f124SMoriah Waterland } else if (libhttperr == NULL) { 1769*5c51f124SMoriah Waterland /* save the first non-system error message */ 1770*5c51f124SMoriah Waterland libhttperr = http_errorstr(errsrc, errcode); 1771*5c51f124SMoriah Waterland } 1772*5c51f124SMoriah Waterland } 1773*5c51f124SMoriah Waterland switch (my_errno) { 1774*5c51f124SMoriah Waterland case EINTR: 1775*5c51f124SMoriah Waterland case ETIMEDOUT: 1776*5c51f124SMoriah Waterland /* Timed out. Try, try again */ 1777*5c51f124SMoriah Waterland ret = WEB_TIMEOUT; 1778*5c51f124SMoriah Waterland break; 1779*5c51f124SMoriah Waterland case ECONNREFUSED: 1780*5c51f124SMoriah Waterland ret = WEB_CONNREFUSED; 1781*5c51f124SMoriah Waterland break; 1782*5c51f124SMoriah Waterland case EHOSTDOWN: 1783*5c51f124SMoriah Waterland ret = WEB_HOSTDOWN; 1784*5c51f124SMoriah Waterland break; 1785*5c51f124SMoriah Waterland default: 1786*5c51f124SMoriah Waterland /* some other fatal error */ 1787*5c51f124SMoriah Waterland ret = WEB_NOCONNECT; 1788*5c51f124SMoriah Waterland if (libhttperr == NULL) { 1789*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 1790*5c51f124SMoriah Waterland gettext(ERR_INIT_CONN), 1791*5c51f124SMoriah Waterland ps->url.hport.hostname); 1792*5c51f124SMoriah Waterland } else { 1793*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 1794*5c51f124SMoriah Waterland gettext(ERR_HTTP), libhttperr); 1795*5c51f124SMoriah Waterland } 1796*5c51f124SMoriah Waterland break; 1797*5c51f124SMoriah Waterland } 1798*5c51f124SMoriah Waterland } 1799*5c51f124SMoriah Waterland cleanup: 1800*5c51f124SMoriah Waterland return (ret); 1801*5c51f124SMoriah Waterland } 1802*5c51f124SMoriah Waterland 1803*5c51f124SMoriah Waterland /* 1804*5c51f124SMoriah Waterland * Name: write_ca_file 1805*5c51f124SMoriah Waterland * Description: Writes out a PKCS12 file containing all trusted certs 1806*5c51f124SMoriah Waterland * found in keystore recorded in static 'ps' structure 1807*5c51f124SMoriah Waterland * 1808*5c51f124SMoriah Waterland * This routine is used because the libwanboot library's 1809*5c51f124SMoriah Waterland * HTTPS routines cannot accept trusted certificates 1810*5c51f124SMoriah Waterland * through an in-memory structure, when initiating an 1811*5c51f124SMoriah Waterland * SSL connection. They must be in a PKCS12, which is 1812*5c51f124SMoriah Waterland * admittedly a poor interface. 1813*5c51f124SMoriah Waterland * 1814*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 1815*5c51f124SMoriah Waterland * tmpdir - Directory to write certificate file in 1816*5c51f124SMoriah Waterland * cacerts - Certs to write out 1817*5c51f124SMoriah Waterland * passwd - password used to encrypt certs 1818*5c51f124SMoriah Waterland * 1819*5c51f124SMoriah Waterland * Returns : path to resulting file, if successfullly written, 1820*5c51f124SMoriah Waterland * otherwise NULL. 1821*5c51f124SMoriah Waterland */ 1822*5c51f124SMoriah Waterland static char 1823*5c51f124SMoriah Waterland *write_ca_file(PKG_ERR *err, char *tmpdir, STACK_OF(X509) *cacerts, 1824*5c51f124SMoriah Waterland char *passwd) 1825*5c51f124SMoriah Waterland { 1826*5c51f124SMoriah Waterland int fd, len; 1827*5c51f124SMoriah Waterland FILE *fp; 1828*5c51f124SMoriah Waterland PKCS12 *p12 = NULL; 1829*5c51f124SMoriah Waterland char *ret = NULL; 1830*5c51f124SMoriah Waterland static char tmp_file[PATH_MAX] = ""; 1831*5c51f124SMoriah Waterland struct stat buf; 1832*5c51f124SMoriah Waterland 1833*5c51f124SMoriah Waterland if (!path_valid(tmpdir)) { 1834*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), tmpdir); 1835*5c51f124SMoriah Waterland goto cleanup; 1836*5c51f124SMoriah Waterland } 1837*5c51f124SMoriah Waterland 1838*5c51f124SMoriah Waterland /* mkstemp replaces XXXXXX with a unique string */ 1839*5c51f124SMoriah Waterland if (((len = snprintf(tmp_file, PATH_MAX, "%s/%sXXXXXX", tmpdir, 1840*5c51f124SMoriah Waterland "cert")) < 0) || 1841*5c51f124SMoriah Waterland (len >= PATH_MAX)) { 1842*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), tmpdir); 1843*5c51f124SMoriah Waterland goto cleanup; 1844*5c51f124SMoriah Waterland } 1845*5c51f124SMoriah Waterland 1846*5c51f124SMoriah Waterland if ((fd = mkstemp(tmp_file)) == -1) { 1847*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTMPFIL), tmp_file); 1848*5c51f124SMoriah Waterland goto cleanup; 1849*5c51f124SMoriah Waterland } 1850*5c51f124SMoriah Waterland 1851*5c51f124SMoriah Waterland if (fstat(fd, &buf) == -1) { 1852*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTMPFIL), tmp_file); 1853*5c51f124SMoriah Waterland goto cleanup; 1854*5c51f124SMoriah Waterland } 1855*5c51f124SMoriah Waterland 1856*5c51f124SMoriah Waterland if (!S_ISREG(buf.st_mode)) { 1857*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTMPFIL), tmp_file); 1858*5c51f124SMoriah Waterland goto cleanup; 1859*5c51f124SMoriah Waterland } 1860*5c51f124SMoriah Waterland 1861*5c51f124SMoriah Waterland if ((fp = fdopen(fd, "w")) == NULL) { 1862*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTMPFIL), tmp_file); 1863*5c51f124SMoriah Waterland goto cleanup; 1864*5c51f124SMoriah Waterland } 1865*5c51f124SMoriah Waterland 1866*5c51f124SMoriah Waterland if ((p12 = sunw_PKCS12_create(passwd, NULL, NULL, cacerts)) == NULL) { 1867*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 1868*5c51f124SMoriah Waterland gettext(ERR_KEYSTORE_FORM), tmp_file); 1869*5c51f124SMoriah Waterland goto cleanup; 1870*5c51f124SMoriah Waterland } 1871*5c51f124SMoriah Waterland 1872*5c51f124SMoriah Waterland if (i2d_PKCS12_fp(fp, p12) == 0) { 1873*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 1874*5c51f124SMoriah Waterland gettext(ERR_KEYSTORE_FORM), tmp_file); 1875*5c51f124SMoriah Waterland goto cleanup; 1876*5c51f124SMoriah Waterland } 1877*5c51f124SMoriah Waterland 1878*5c51f124SMoriah Waterland (void) fflush(fp); 1879*5c51f124SMoriah Waterland (void) fclose(fp); 1880*5c51f124SMoriah Waterland (void) close(fd); 1881*5c51f124SMoriah Waterland fp = NULL; 1882*5c51f124SMoriah Waterland fd = -1; 1883*5c51f124SMoriah Waterland ret = tmp_file; 1884*5c51f124SMoriah Waterland 1885*5c51f124SMoriah Waterland cleanup: 1886*5c51f124SMoriah Waterland if (p12 != NULL) 1887*5c51f124SMoriah Waterland PKCS12_free(p12); 1888*5c51f124SMoriah Waterland if (fp != NULL) 1889*5c51f124SMoriah Waterland (void) fclose(fp); 1890*5c51f124SMoriah Waterland if (fd != -1) { 1891*5c51f124SMoriah Waterland (void) close(fd); 1892*5c51f124SMoriah Waterland (void) unlink(tmp_file); 1893*5c51f124SMoriah Waterland } 1894*5c51f124SMoriah Waterland 1895*5c51f124SMoriah Waterland return (ret); 1896*5c51f124SMoriah Waterland } 1897*5c51f124SMoriah Waterland 1898*5c51f124SMoriah Waterland /* 1899*5c51f124SMoriah Waterland * Name: web_send_request 1900*5c51f124SMoriah Waterland * Description: Sends an HTTP request for a file to the 1901*5c51f124SMoriah Waterland * web server being communicated with in the static 1902*5c51f124SMoriah Waterland * 'ps' structure 1903*5c51f124SMoriah Waterland * 1904*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 1905*5c51f124SMoriah Waterland * request_type - HTTP_REQ_TYPE_HEAD to send an HTTP HEAD request, 1906*5c51f124SMoriah Waterland * or HTTP_REQ_TYPE_GET to send an HTTP GET request 1907*5c51f124SMoriah Waterland * cp - 1908*5c51f124SMoriah Waterland * Returns : WEB_OK - request sent successfully 1909*5c51f124SMoriah Waterland * WEB_CONNREFUSED - Connection was refused to web site 1910*5c51f124SMoriah Waterland * WEB_HOSTDOWN - Host was not responding to request 1911*5c51f124SMoriah Waterland * WEB_NOCONNECT - Some other connection failure 1912*5c51f124SMoriah Waterland */ 1913*5c51f124SMoriah Waterland static WebStatus 1914*5c51f124SMoriah Waterland web_send_request(PKG_ERR *err, int request_type, int cp, int ep) 1915*5c51f124SMoriah Waterland { 1916*5c51f124SMoriah Waterland WebStatus ret = WEB_OK; 1917*5c51f124SMoriah Waterland ulong_t errcode; 1918*5c51f124SMoriah Waterland uint_t errsrc; 1919*5c51f124SMoriah Waterland int my_errno = 0; 1920*5c51f124SMoriah Waterland const char *libhttperr = NULL; 1921*5c51f124SMoriah Waterland switch (request_type) { 1922*5c51f124SMoriah Waterland case HTTP_REQ_TYPE_HEAD: 1923*5c51f124SMoriah Waterland if ((http_head_request(ps->hps, ps->url.abspath)) != 0) { 1924*5c51f124SMoriah Waterland while ((errcode = http_get_lasterr(ps->hps, 1925*5c51f124SMoriah Waterland &errsrc)) != 0) { 1926*5c51f124SMoriah Waterland /* Have an error - is it EINTR? */ 1927*5c51f124SMoriah Waterland if (errsrc == ERRSRC_SYSTEM) { 1928*5c51f124SMoriah Waterland my_errno = errcode; 1929*5c51f124SMoriah Waterland break; 1930*5c51f124SMoriah Waterland } else if (libhttperr == NULL) { 1931*5c51f124SMoriah Waterland /* save first non-system error message */ 1932*5c51f124SMoriah Waterland libhttperr = 1933*5c51f124SMoriah Waterland http_errorstr(errsrc, errcode); 1934*5c51f124SMoriah Waterland } 1935*5c51f124SMoriah Waterland } 1936*5c51f124SMoriah Waterland switch (my_errno) { 1937*5c51f124SMoriah Waterland case EINTR: 1938*5c51f124SMoriah Waterland case ETIMEDOUT: 1939*5c51f124SMoriah Waterland /* Timed out. Try, try again */ 1940*5c51f124SMoriah Waterland ret = WEB_TIMEOUT; 1941*5c51f124SMoriah Waterland break; 1942*5c51f124SMoriah Waterland case ECONNREFUSED: 1943*5c51f124SMoriah Waterland ret = WEB_CONNREFUSED; 1944*5c51f124SMoriah Waterland break; 1945*5c51f124SMoriah Waterland case EHOSTDOWN: 1946*5c51f124SMoriah Waterland ret = WEB_HOSTDOWN; 1947*5c51f124SMoriah Waterland break; 1948*5c51f124SMoriah Waterland default: 1949*5c51f124SMoriah Waterland /* some other fatal error */ 1950*5c51f124SMoriah Waterland ret = WEB_NOCONNECT; 1951*5c51f124SMoriah Waterland if (libhttperr == NULL) { 1952*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 1953*5c51f124SMoriah Waterland gettext(ERR_INIT_CONN), 1954*5c51f124SMoriah Waterland ps->url.hport.hostname); 1955*5c51f124SMoriah Waterland } else { 1956*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 1957*5c51f124SMoriah Waterland gettext(ERR_HTTP), libhttperr); 1958*5c51f124SMoriah Waterland } 1959*5c51f124SMoriah Waterland break; 1960*5c51f124SMoriah Waterland } 1961*5c51f124SMoriah Waterland goto cleanup; 1962*5c51f124SMoriah Waterland } 1963*5c51f124SMoriah Waterland break; 1964*5c51f124SMoriah Waterland 1965*5c51f124SMoriah Waterland case HTTP_REQ_TYPE_GET: 1966*5c51f124SMoriah Waterland if (cp && ep) { 1967*5c51f124SMoriah Waterland if (http_get_range_request(ps->hps, ps->url.abspath, 1968*5c51f124SMoriah Waterland cp, ep - cp) != 0) { 1969*5c51f124SMoriah Waterland while ((errcode = http_get_lasterr(ps->hps, 1970*5c51f124SMoriah Waterland &errsrc)) != 0) { 1971*5c51f124SMoriah Waterland /* Have an error - is it EINTR? */ 1972*5c51f124SMoriah Waterland if (errsrc == ERRSRC_SYSTEM) { 1973*5c51f124SMoriah Waterland my_errno = errcode; 1974*5c51f124SMoriah Waterland break; 1975*5c51f124SMoriah Waterland } else { 1976*5c51f124SMoriah Waterland /* 1977*5c51f124SMoriah Waterland * save first non-system 1978*5c51f124SMoriah Waterland * error message 1979*5c51f124SMoriah Waterland */ 1980*5c51f124SMoriah Waterland libhttperr = 1981*5c51f124SMoriah Waterland http_errorstr(errsrc, 1982*5c51f124SMoriah Waterland errcode); 1983*5c51f124SMoriah Waterland } 1984*5c51f124SMoriah Waterland } 1985*5c51f124SMoriah Waterland switch (my_errno) { 1986*5c51f124SMoriah Waterland case EINTR: 1987*5c51f124SMoriah Waterland case ETIMEDOUT: 1988*5c51f124SMoriah Waterland /* Timed out. Try, try again */ 1989*5c51f124SMoriah Waterland ret = WEB_TIMEOUT; 1990*5c51f124SMoriah Waterland break; 1991*5c51f124SMoriah Waterland case ECONNREFUSED: 1992*5c51f124SMoriah Waterland ret = WEB_CONNREFUSED; 1993*5c51f124SMoriah Waterland break; 1994*5c51f124SMoriah Waterland case EHOSTDOWN: 1995*5c51f124SMoriah Waterland ret = WEB_HOSTDOWN; 1996*5c51f124SMoriah Waterland break; 1997*5c51f124SMoriah Waterland default: 1998*5c51f124SMoriah Waterland /* some other fatal error */ 1999*5c51f124SMoriah Waterland ret = WEB_NOCONNECT; 2000*5c51f124SMoriah Waterland if (libhttperr == NULL) { 2001*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2002*5c51f124SMoriah Waterland gettext(ERR_INIT_CONN), 2003*5c51f124SMoriah Waterland ps->url.hport.hostname); 2004*5c51f124SMoriah Waterland } else { 2005*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2006*5c51f124SMoriah Waterland gettext(ERR_HTTP), 2007*5c51f124SMoriah Waterland libhttperr); 2008*5c51f124SMoriah Waterland } 2009*5c51f124SMoriah Waterland break; 2010*5c51f124SMoriah Waterland } 2011*5c51f124SMoriah Waterland goto cleanup; 2012*5c51f124SMoriah Waterland } 2013*5c51f124SMoriah Waterland 2014*5c51f124SMoriah Waterland if (!web_eval_headers(err)) { 2015*5c51f124SMoriah Waterland ret = WEB_NOCONNECT; 2016*5c51f124SMoriah Waterland goto cleanup; 2017*5c51f124SMoriah Waterland } 2018*5c51f124SMoriah Waterland } else { 2019*5c51f124SMoriah Waterland if ((http_get_request(ps->hps, ps->url.abspath)) 2020*5c51f124SMoriah Waterland != 0) { 2021*5c51f124SMoriah Waterland while ((errcode = http_get_lasterr(ps->hps, 2022*5c51f124SMoriah Waterland &errsrc)) != 0) { 2023*5c51f124SMoriah Waterland /* Have an error - is it EINTR? */ 2024*5c51f124SMoriah Waterland if (errsrc == ERRSRC_SYSTEM) { 2025*5c51f124SMoriah Waterland my_errno = errcode; 2026*5c51f124SMoriah Waterland break; 2027*5c51f124SMoriah Waterland } else { 2028*5c51f124SMoriah Waterland /* 2029*5c51f124SMoriah Waterland * save the first non-system 2030*5c51f124SMoriah Waterland * error message 2031*5c51f124SMoriah Waterland */ 2032*5c51f124SMoriah Waterland libhttperr = 2033*5c51f124SMoriah Waterland http_errorstr(errsrc, 2034*5c51f124SMoriah Waterland errcode); 2035*5c51f124SMoriah Waterland } 2036*5c51f124SMoriah Waterland } 2037*5c51f124SMoriah Waterland switch (my_errno) { 2038*5c51f124SMoriah Waterland case EINTR: 2039*5c51f124SMoriah Waterland case ETIMEDOUT: 2040*5c51f124SMoriah Waterland /* Timed out. Try, try again */ 2041*5c51f124SMoriah Waterland ret = WEB_TIMEOUT; 2042*5c51f124SMoriah Waterland break; 2043*5c51f124SMoriah Waterland case ECONNREFUSED: 2044*5c51f124SMoriah Waterland ret = WEB_CONNREFUSED; 2045*5c51f124SMoriah Waterland break; 2046*5c51f124SMoriah Waterland case EHOSTDOWN: 2047*5c51f124SMoriah Waterland ret = WEB_HOSTDOWN; 2048*5c51f124SMoriah Waterland break; 2049*5c51f124SMoriah Waterland default: 2050*5c51f124SMoriah Waterland /* some other fatal error */ 2051*5c51f124SMoriah Waterland ret = WEB_NOCONNECT; 2052*5c51f124SMoriah Waterland if (libhttperr == NULL) { 2053*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2054*5c51f124SMoriah Waterland gettext(ERR_INIT_CONN), 2055*5c51f124SMoriah Waterland ps->url.hport.hostname); 2056*5c51f124SMoriah Waterland } else { 2057*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2058*5c51f124SMoriah Waterland gettext(ERR_HTTP), 2059*5c51f124SMoriah Waterland libhttperr); 2060*5c51f124SMoriah Waterland } 2061*5c51f124SMoriah Waterland break; 2062*5c51f124SMoriah Waterland } 2063*5c51f124SMoriah Waterland goto cleanup; 2064*5c51f124SMoriah Waterland } 2065*5c51f124SMoriah Waterland 2066*5c51f124SMoriah Waterland if (!web_eval_headers(err)) { 2067*5c51f124SMoriah Waterland ret = WEB_NOCONNECT; 2068*5c51f124SMoriah Waterland goto cleanup; 2069*5c51f124SMoriah Waterland } 2070*5c51f124SMoriah Waterland } 2071*5c51f124SMoriah Waterland break; 2072*5c51f124SMoriah Waterland default: 2073*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, gettext(ERR_PKG_INTERNAL), 2074*5c51f124SMoriah Waterland __FILE__, __LINE__); 2075*5c51f124SMoriah Waterland } 2076*5c51f124SMoriah Waterland 2077*5c51f124SMoriah Waterland cleanup: 2078*5c51f124SMoriah Waterland return (ret); 2079*5c51f124SMoriah Waterland } 2080*5c51f124SMoriah Waterland 2081*5c51f124SMoriah Waterland /* 2082*5c51f124SMoriah Waterland * Name: web_eval_headers 2083*5c51f124SMoriah Waterland * Description: Evaluates HTTP headers returned during an HTTP request. 2084*5c51f124SMoriah Waterland * This must be called before calling 2085*5c51f124SMoriah Waterland * http_get_header_value(). 2086*5c51f124SMoriah Waterland * 2087*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 2088*5c51f124SMoriah Waterland * 2089*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 2090*5c51f124SMoriah Waterland */ 2091*5c51f124SMoriah Waterland static boolean_t 2092*5c51f124SMoriah Waterland web_eval_headers(PKG_ERR *err) 2093*5c51f124SMoriah Waterland { 2094*5c51f124SMoriah Waterland const char *http_err; 2095*5c51f124SMoriah Waterland ulong_t herr; 2096*5c51f124SMoriah Waterland uint_t errsrc; 2097*5c51f124SMoriah Waterland 2098*5c51f124SMoriah Waterland if (http_process_headers(ps->hps, &ps->resp) != 0) { 2099*5c51f124SMoriah Waterland if ((ps->resp != NULL) && (ps->resp->statusmsg != NULL)) { 2100*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_HTTP), 2101*5c51f124SMoriah Waterland ps->resp->statusmsg); 2102*5c51f124SMoriah Waterland } 2103*5c51f124SMoriah Waterland 2104*5c51f124SMoriah Waterland herr = http_get_lasterr(ps->hps, &errsrc); 2105*5c51f124SMoriah Waterland http_err = http_errorstr(errsrc, herr); 2106*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_HTTP), 2107*5c51f124SMoriah Waterland http_err); 2108*5c51f124SMoriah Waterland return (B_FALSE); 2109*5c51f124SMoriah Waterland } 2110*5c51f124SMoriah Waterland return (B_TRUE); 2111*5c51f124SMoriah Waterland } 2112*5c51f124SMoriah Waterland 2113*5c51f124SMoriah Waterland /* 2114*5c51f124SMoriah Waterland * Name: web_get_file 2115*5c51f124SMoriah Waterland * Description: Downloads the file URL from the website, all of 2116*5c51f124SMoriah Waterland * which are recorded in the static 'ps' struct 2117*5c51f124SMoriah Waterland * 2118*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 2119*5c51f124SMoriah Waterland * dwnld_dir - Directory to download file into 2120*5c51f124SMoriah Waterland * device - Where to store path to resulting 2121*5c51f124SMoriah Waterland * file 2122*5c51f124SMoriah Waterland * nointeract - if non-zero, do not output 2123*5c51f124SMoriah Waterland * progress 2124*5c51f124SMoriah Waterland * fname - name of downloaded file link in the dwnld_dir 2125*5c51f124SMoriah Waterland * 2126*5c51f124SMoriah Waterland * Returns : WEB_OK - download successful 2127*5c51f124SMoriah Waterland * WEB_CONNREFUSED - Connection was refused to web site 2128*5c51f124SMoriah Waterland * WEB_HOSTDOWN - Host was not responding to request 2129*5c51f124SMoriah Waterland * WEB_GET_FAIL - Unable to initialize download 2130*5c51f124SMoriah Waterland * state (temp file creation, header parsing, etc) 2131*5c51f124SMoriah Waterland * WEB_NOCONNECT - Some other connection failure 2132*5c51f124SMoriah Waterland */ 2133*5c51f124SMoriah Waterland static WebStatus 2134*5c51f124SMoriah Waterland web_get_file(PKG_ERR *err, char *dwnld_dir, int nointeract, char **fname) 2135*5c51f124SMoriah Waterland { 2136*5c51f124SMoriah Waterland int i, fd; 2137*5c51f124SMoriah Waterland int n = 0; 2138*5c51f124SMoriah Waterland ulong_t abs_pos = 0; 2139*5c51f124SMoriah Waterland char *head_val = NULL; 2140*5c51f124SMoriah Waterland char *lastmod_val = NULL; 2141*5c51f124SMoriah Waterland char *bname = NULL; 2142*5c51f124SMoriah Waterland struct stat status; 2143*5c51f124SMoriah Waterland WebStatus ret = WEB_OK; 2144*5c51f124SMoriah Waterland WebStatus req_ret; 2145*5c51f124SMoriah Waterland ulong_t errcode; 2146*5c51f124SMoriah Waterland uint_t errsrc; 2147*5c51f124SMoriah Waterland int my_errno = 0; 2148*5c51f124SMoriah Waterland const char *libhttperr = NULL; 2149*5c51f124SMoriah Waterland char *disp; 2150*5c51f124SMoriah Waterland char tmp_file[PATH_MAX]; 2151*5c51f124SMoriah Waterland int len; 2152*5c51f124SMoriah Waterland 2153*5c51f124SMoriah Waterland ps->data.prev_cont_length = 2154*5c51f124SMoriah Waterland ps->data.content_length = 2155*5c51f124SMoriah Waterland ps->data.cur_pos = 0; 2156*5c51f124SMoriah Waterland 2157*5c51f124SMoriah Waterland if ((head_val = http_get_header_value(ps->hps, 2158*5c51f124SMoriah Waterland CONTENT_LENGTH_HDR)) != NULL) { 2159*5c51f124SMoriah Waterland ps->data.content_length = atol(head_val); 2160*5c51f124SMoriah Waterland } else { 2161*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_NO_HEAD_VAL), 2162*5c51f124SMoriah Waterland CONTENT_LENGTH_HDR); 2163*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2164*5c51f124SMoriah Waterland goto cleanup; 2165*5c51f124SMoriah Waterland } 2166*5c51f124SMoriah Waterland 2167*5c51f124SMoriah Waterland free(head_val); 2168*5c51f124SMoriah Waterland head_val = NULL; 2169*5c51f124SMoriah Waterland 2170*5c51f124SMoriah Waterland if ((head_val = http_get_header_value(ps->hps, 2171*5c51f124SMoriah Waterland CONTENT_DISPOSITION_HDR)) != NULL) { 2172*5c51f124SMoriah Waterland /* "inline; parm=val; parm=val */ 2173*5c51f124SMoriah Waterland if ((disp = strtok(head_val, "; \t\n\f\r")) != NULL) { 2174*5c51f124SMoriah Waterland /* disp = "inline" */ 2175*5c51f124SMoriah Waterland while ((disp = strtok(NULL, "; \t\n\f\r")) != NULL) { 2176*5c51f124SMoriah Waterland /* disp = "parm=val" */ 2177*5c51f124SMoriah Waterland if (ci_strneq(disp, "filename=", 9)) { 2178*5c51f124SMoriah Waterland bname = xstrdup(basename(disp + 9)); 2179*5c51f124SMoriah Waterland trim(bname); 2180*5c51f124SMoriah Waterland dequote(bname); 2181*5c51f124SMoriah Waterland } 2182*5c51f124SMoriah Waterland } 2183*5c51f124SMoriah Waterland } 2184*5c51f124SMoriah Waterland free(head_val); 2185*5c51f124SMoriah Waterland head_val = NULL; 2186*5c51f124SMoriah Waterland } 2187*5c51f124SMoriah Waterland 2188*5c51f124SMoriah Waterland if (bname == NULL) { 2189*5c51f124SMoriah Waterland /* 2190*5c51f124SMoriah Waterland * couldn't determine filename from header value, 2191*5c51f124SMoriah Waterland * so take basename of URL 2192*5c51f124SMoriah Waterland */ 2193*5c51f124SMoriah Waterland if ((bname = get_endof_string(ps->url.abspath, '/')) == NULL) { 2194*5c51f124SMoriah Waterland /* URL is bad */ 2195*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 2196*5c51f124SMoriah Waterland gettext(ERR_PARSE_URL), ps->url.abspath); 2197*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2198*5c51f124SMoriah Waterland goto cleanup; 2199*5c51f124SMoriah Waterland } 2200*5c51f124SMoriah Waterland } 2201*5c51f124SMoriah Waterland 2202*5c51f124SMoriah Waterland *fname = bname; 2203*5c51f124SMoriah Waterland 2204*5c51f124SMoriah Waterland if ((head_val = http_get_header_value(ps->hps, LAST_MODIFIED_HDR)) 2205*5c51f124SMoriah Waterland != NULL) { 2206*5c51f124SMoriah Waterland 2207*5c51f124SMoriah Waterland if ((lastmod_val = condense_lastmodified(head_val)) == NULL) { 2208*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_BAD_HEAD_VAL), 2209*5c51f124SMoriah Waterland LAST_MODIFIED_HDR, head_val); 2210*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2211*5c51f124SMoriah Waterland goto cleanup; 2212*5c51f124SMoriah Waterland } 2213*5c51f124SMoriah Waterland free(head_val); 2214*5c51f124SMoriah Waterland head_val = NULL; 2215*5c51f124SMoriah Waterland 2216*5c51f124SMoriah Waterland if ((ps->uniqfile = get_unique_filename(dwnld_dir, 2217*5c51f124SMoriah Waterland lastmod_val)) == NULL) { 2218*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_OPEN_TMP)); 2219*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2220*5c51f124SMoriah Waterland goto cleanup; 2221*5c51f124SMoriah Waterland } 2222*5c51f124SMoriah Waterland 2223*5c51f124SMoriah Waterland free(lastmod_val); 2224*5c51f124SMoriah Waterland lastmod_val = NULL; 2225*5c51f124SMoriah Waterland 2226*5c51f124SMoriah Waterland if ((fd = open(ps->uniqfile, 2227*5c51f124SMoriah Waterland O_NONBLOCK|O_RDWR|O_APPEND|O_CREAT|O_EXCL, 2228*5c51f124SMoriah Waterland 640)) == -1) { 2229*5c51f124SMoriah Waterland 2230*5c51f124SMoriah Waterland /* 2231*5c51f124SMoriah Waterland * A partial downloaded file 2232*5c51f124SMoriah Waterland * already exists, so open it. 2233*5c51f124SMoriah Waterland */ 2234*5c51f124SMoriah Waterland if ((fd = open(ps->uniqfile, 2235*5c51f124SMoriah Waterland O_NONBLOCK|O_RDWR|O_APPEND)) != -1) { 2236*5c51f124SMoriah Waterland if (fstat(fd, &status) == -1 || 2237*5c51f124SMoriah Waterland !S_ISREG(status.st_mode)) { 2238*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2239*5c51f124SMoriah Waterland gettext(ERR_DWNLD_NO_CONT), 2240*5c51f124SMoriah Waterland ps->uniqfile); 2241*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2242*5c51f124SMoriah Waterland goto cleanup; 2243*5c51f124SMoriah Waterland } else { 2244*5c51f124SMoriah Waterland echo_out(nointeract, 2245*5c51f124SMoriah Waterland gettext(MSG_DWNLD_PART), 2246*5c51f124SMoriah Waterland ps->uniqfile, 2247*5c51f124SMoriah Waterland status.st_size); 2248*5c51f124SMoriah Waterland ps->data.prev_cont_length = 2249*5c51f124SMoriah Waterland status.st_size; 2250*5c51f124SMoriah Waterland } 2251*5c51f124SMoriah Waterland } else { 2252*5c51f124SMoriah Waterland /* unable to open partial file */ 2253*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2254*5c51f124SMoriah Waterland gettext(ERR_DWNLD_NO_CONT), 2255*5c51f124SMoriah Waterland ps->uniqfile); 2256*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2257*5c51f124SMoriah Waterland goto cleanup; 2258*5c51f124SMoriah Waterland } 2259*5c51f124SMoriah Waterland } 2260*5c51f124SMoriah Waterland } else { 2261*5c51f124SMoriah Waterland /* 2262*5c51f124SMoriah Waterland * no "Last-Modified" header, so this file is not eligible for 2263*5c51f124SMoriah Waterland * spooling and "resuming last download" operations 2264*5c51f124SMoriah Waterland */ 2265*5c51f124SMoriah Waterland ps->spool = B_FALSE; 2266*5c51f124SMoriah Waterland 2267*5c51f124SMoriah Waterland /* mkstemp replaces XXXXXX with a unique string */ 2268*5c51f124SMoriah Waterland if (((len = snprintf(tmp_file, PATH_MAX, 2269*5c51f124SMoriah Waterland "%s/%sXXXXXX", dwnld_dir, "stream")) < 0) || 2270*5c51f124SMoriah Waterland (len >= PATH_MAX)) { 2271*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2272*5c51f124SMoriah Waterland gettext(MSG_NOTEMP), dwnld_dir); 2273*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2274*5c51f124SMoriah Waterland goto cleanup; 2275*5c51f124SMoriah Waterland } 2276*5c51f124SMoriah Waterland 2277*5c51f124SMoriah Waterland if ((fd = mkstemp(tmp_file)) == -1) { 2278*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2279*5c51f124SMoriah Waterland gettext(MSG_NOTMPFIL), tmp_file); 2280*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2281*5c51f124SMoriah Waterland goto cleanup; 2282*5c51f124SMoriah Waterland } 2283*5c51f124SMoriah Waterland 2284*5c51f124SMoriah Waterland if (fstat(fd, &status) == -1 || 2285*5c51f124SMoriah Waterland !S_ISREG(status.st_mode)) { 2286*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2287*5c51f124SMoriah Waterland gettext(ERR_DWNLD_NO_CONT), 2288*5c51f124SMoriah Waterland ps->uniqfile); 2289*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2290*5c51f124SMoriah Waterland goto cleanup; 2291*5c51f124SMoriah Waterland } 2292*5c51f124SMoriah Waterland 2293*5c51f124SMoriah Waterland ps->data.prev_cont_length = 0; 2294*5c51f124SMoriah Waterland ps->uniqfile = xstrdup(tmp_file); 2295*5c51f124SMoriah Waterland } 2296*5c51f124SMoriah Waterland 2297*5c51f124SMoriah Waterland /* File has already been completely downloaded */ 2298*5c51f124SMoriah Waterland if (ps->data.prev_cont_length == ps->data.content_length) { 2299*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_PREV), ps->uniqfile); 2300*5c51f124SMoriah Waterland ps->data.cur_pos = ps->data.prev_cont_length; 2301*5c51f124SMoriah Waterland if (!make_link(dwnld_dir, bname)) { 2302*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), 2303*5c51f124SMoriah Waterland dwnld_dir); 2304*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2305*5c51f124SMoriah Waterland goto cleanup; 2306*5c51f124SMoriah Waterland } 2307*5c51f124SMoriah Waterland /* we're done, so cleanup and return success */ 2308*5c51f124SMoriah Waterland goto cleanup; 2309*5c51f124SMoriah Waterland } else if (ps->data.prev_cont_length != 0) { 2310*5c51f124SMoriah Waterland ps->data.cur_pos = ps->data.prev_cont_length; 2311*5c51f124SMoriah Waterland } 2312*5c51f124SMoriah Waterland 2313*5c51f124SMoriah Waterland if (!ck_dwnld_dir_space(err, dwnld_dir, 2314*5c51f124SMoriah Waterland (ps->data.prev_cont_length != 0) ? 2315*5c51f124SMoriah Waterland (ps->data.content_length - ps->data.cur_pos) : 2316*5c51f124SMoriah Waterland ps->data.content_length)) { 2317*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2318*5c51f124SMoriah Waterland goto cleanup; 2319*5c51f124SMoriah Waterland } 2320*5c51f124SMoriah Waterland 2321*5c51f124SMoriah Waterland if ((req_ret = web_send_request(err, HTTP_REQ_TYPE_GET, 2322*5c51f124SMoriah Waterland ps->data.cur_pos, ps->data.content_length)) != WEB_OK) { 2323*5c51f124SMoriah Waterland ret = req_ret; 2324*5c51f124SMoriah Waterland goto cleanup; 2325*5c51f124SMoriah Waterland } 2326*5c51f124SMoriah Waterland 2327*5c51f124SMoriah Waterland if (ps->data.prev_cont_length != 0) 2328*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_CONT)); 2329*5c51f124SMoriah Waterland else 2330*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD)); 2331*5c51f124SMoriah Waterland 2332*5c51f124SMoriah Waterland progress_setup(nointeract, ps->data.content_length); 2333*5c51f124SMoriah Waterland 2334*5c51f124SMoriah Waterland /* Download the file a BLOCK at a time */ 2335*5c51f124SMoriah Waterland while (ps->data.cur_pos < ps->data.content_length) { 2336*5c51f124SMoriah Waterland progress_report(nointeract, abs_pos); 2337*5c51f124SMoriah Waterland i = ((ps->data.content_length - ps->data.cur_pos) < BLOCK) ? 2338*5c51f124SMoriah Waterland (ps->data.content_length - ps->data.cur_pos) 2339*5c51f124SMoriah Waterland : BLOCK; 2340*5c51f124SMoriah Waterland if ((n = http_read_body(ps->hps, ps->content, i)) <= 0) { 2341*5c51f124SMoriah Waterland while ((errcode = http_get_lasterr(ps->hps, 2342*5c51f124SMoriah Waterland &errsrc)) != 0) { 2343*5c51f124SMoriah Waterland /* Have an error - is it EINTR? */ 2344*5c51f124SMoriah Waterland if (errsrc == ERRSRC_SYSTEM) { 2345*5c51f124SMoriah Waterland my_errno = errcode; 2346*5c51f124SMoriah Waterland break; 2347*5c51f124SMoriah Waterland } else { 2348*5c51f124SMoriah Waterland /* 2349*5c51f124SMoriah Waterland * save first non-system 2350*5c51f124SMoriah Waterland * error message 2351*5c51f124SMoriah Waterland */ 2352*5c51f124SMoriah Waterland libhttperr = 2353*5c51f124SMoriah Waterland http_errorstr(errsrc, errcode); 2354*5c51f124SMoriah Waterland } 2355*5c51f124SMoriah Waterland } 2356*5c51f124SMoriah Waterland switch (my_errno) { 2357*5c51f124SMoriah Waterland case EINTR: 2358*5c51f124SMoriah Waterland case ETIMEDOUT: 2359*5c51f124SMoriah Waterland /* Timed out. Try, try again */ 2360*5c51f124SMoriah Waterland ret = WEB_TIMEOUT; 2361*5c51f124SMoriah Waterland break; 2362*5c51f124SMoriah Waterland case ECONNREFUSED: 2363*5c51f124SMoriah Waterland ret = WEB_CONNREFUSED; 2364*5c51f124SMoriah Waterland break; 2365*5c51f124SMoriah Waterland case EHOSTDOWN: 2366*5c51f124SMoriah Waterland ret = WEB_HOSTDOWN; 2367*5c51f124SMoriah Waterland break; 2368*5c51f124SMoriah Waterland default: 2369*5c51f124SMoriah Waterland /* some other fatal error */ 2370*5c51f124SMoriah Waterland ret = WEB_NOCONNECT; 2371*5c51f124SMoriah Waterland if (libhttperr == NULL) { 2372*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2373*5c51f124SMoriah Waterland gettext(ERR_INIT_CONN), 2374*5c51f124SMoriah Waterland ps->url.hport.hostname); 2375*5c51f124SMoriah Waterland } else { 2376*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2377*5c51f124SMoriah Waterland gettext(ERR_HTTP), libhttperr); 2378*5c51f124SMoriah Waterland } 2379*5c51f124SMoriah Waterland break; 2380*5c51f124SMoriah Waterland } 2381*5c51f124SMoriah Waterland goto cleanup; 2382*5c51f124SMoriah Waterland } 2383*5c51f124SMoriah Waterland if ((n = write(fd, ps->content, n)) == 0) { 2384*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_WRITE), 2385*5c51f124SMoriah Waterland ps->uniqfile, strerror(errno)); 2386*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2387*5c51f124SMoriah Waterland goto cleanup; 2388*5c51f124SMoriah Waterland } 2389*5c51f124SMoriah Waterland ps->data.cur_pos += n; 2390*5c51f124SMoriah Waterland abs_pos += n; 2391*5c51f124SMoriah Waterland } 2392*5c51f124SMoriah Waterland 2393*5c51f124SMoriah Waterland progress_finish(nointeract); 2394*5c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_COMPLETE)); 2395*5c51f124SMoriah Waterland 2396*5c51f124SMoriah Waterland if (!make_link(dwnld_dir, bname)) { 2397*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), 2398*5c51f124SMoriah Waterland dwnld_dir); 2399*5c51f124SMoriah Waterland ret = WEB_GET_FAIL; 2400*5c51f124SMoriah Waterland goto cleanup; 2401*5c51f124SMoriah Waterland } 2402*5c51f124SMoriah Waterland 2403*5c51f124SMoriah Waterland cleanup: 2404*5c51f124SMoriah Waterland sync(); 2405*5c51f124SMoriah Waterland if (fd != -1) { 2406*5c51f124SMoriah Waterland (void) close(fd); 2407*5c51f124SMoriah Waterland } 2408*5c51f124SMoriah Waterland 2409*5c51f124SMoriah Waterland if (head_val != NULL) 2410*5c51f124SMoriah Waterland free(head_val); 2411*5c51f124SMoriah Waterland 2412*5c51f124SMoriah Waterland if (lastmod_val != NULL) 2413*5c51f124SMoriah Waterland free(lastmod_val); 2414*5c51f124SMoriah Waterland 2415*5c51f124SMoriah Waterland return (ret); 2416*5c51f124SMoriah Waterland } 2417*5c51f124SMoriah Waterland 2418*5c51f124SMoriah Waterland /* 2419*5c51f124SMoriah Waterland * Name: make_link 2420*5c51f124SMoriah Waterland * Description: Create new link to file being downloaded 2421*5c51f124SMoriah Waterland * 2422*5c51f124SMoriah Waterland * Arguments: dwnld_dir - directory in which downloaded file exists 2423*5c51f124SMoriah Waterland * bname - name of link 2424*5c51f124SMoriah Waterland * 2425*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 2426*5c51f124SMoriah Waterland */ 2427*5c51f124SMoriah Waterland static boolean_t 2428*5c51f124SMoriah Waterland make_link(char *dwnld_dir, char *bname) 2429*5c51f124SMoriah Waterland { 2430*5c51f124SMoriah Waterland int len; 2431*5c51f124SMoriah Waterland 2432*5c51f124SMoriah Waterland if ((ps->link = (char *)xmalloc(PATH_MAX)) == NULL) 2433*5c51f124SMoriah Waterland return (B_FALSE); 2434*5c51f124SMoriah Waterland if (((len = snprintf(ps->link, PATH_MAX, "%s/%s", 2435*5c51f124SMoriah Waterland dwnld_dir, bname)) < 0) || 2436*5c51f124SMoriah Waterland len >= PATH_MAX) 2437*5c51f124SMoriah Waterland return (B_FALSE); 2438*5c51f124SMoriah Waterland 2439*5c51f124SMoriah Waterland (void) link(ps->uniqfile, ps->link); 2440*5c51f124SMoriah Waterland 2441*5c51f124SMoriah Waterland return (B_TRUE); 2442*5c51f124SMoriah Waterland } 2443*5c51f124SMoriah Waterland 2444*5c51f124SMoriah Waterland /* 2445*5c51f124SMoriah Waterland * Name: get_startof_string 2446*5c51f124SMoriah Waterland * Description: searches string for token, returns a newly-allocated 2447*5c51f124SMoriah Waterland * substring of the given string up to, but not 2448*5c51f124SMoriah Waterland * including, token. for example 2449*5c51f124SMoriah Waterland * get_startof_string("abcd", 'c') will return "ab" 2450*5c51f124SMoriah Waterland * 2451*5c51f124SMoriah Waterland * Arguments: path - path to split 2452*5c51f124SMoriah Waterland * token - character to split on 2453*5c51f124SMoriah Waterland * 2454*5c51f124SMoriah Waterland * Returns : substring of 'path', up to, but not including, 2455*5c51f124SMoriah Waterland * token, if token appears in path. Otherwise, 2456*5c51f124SMoriah Waterland * returns NULL. 2457*5c51f124SMoriah Waterland */ 2458*5c51f124SMoriah Waterland char * 2459*5c51f124SMoriah Waterland get_startof_string(char *path, char token) 2460*5c51f124SMoriah Waterland { 2461*5c51f124SMoriah Waterland char *p, *p2; 2462*5c51f124SMoriah Waterland 2463*5c51f124SMoriah Waterland if (path == NULL) 2464*5c51f124SMoriah Waterland return (NULL); 2465*5c51f124SMoriah Waterland 2466*5c51f124SMoriah Waterland p = xstrdup(path); 2467*5c51f124SMoriah Waterland 2468*5c51f124SMoriah Waterland p2 = strchr(p, token); 2469*5c51f124SMoriah Waterland if (p2 == NULL) { 2470*5c51f124SMoriah Waterland free(p); 2471*5c51f124SMoriah Waterland return (NULL); 2472*5c51f124SMoriah Waterland } else { 2473*5c51f124SMoriah Waterland *p2 = '\0'; 2474*5c51f124SMoriah Waterland return (p); 2475*5c51f124SMoriah Waterland } 2476*5c51f124SMoriah Waterland } 2477*5c51f124SMoriah Waterland 2478*5c51f124SMoriah Waterland /* 2479*5c51f124SMoriah Waterland * Name: get_endof_string 2480*5c51f124SMoriah Waterland * Description: searches string for token, returns a 2481*5c51f124SMoriah Waterland * newly-allocated substring of the given string, 2482*5c51f124SMoriah Waterland * starting at character following token, to end of 2483*5c51f124SMoriah Waterland * string. 2484*5c51f124SMoriah Waterland * 2485*5c51f124SMoriah Waterland * for example get_end_string("abcd", 'c') 2486*5c51f124SMoriah Waterland * will return "d" 2487*5c51f124SMoriah Waterland * 2488*5c51f124SMoriah Waterland * Arguments: path - path to split 2489*5c51f124SMoriah Waterland * token - character to split on 2490*5c51f124SMoriah Waterland * 2491*5c51f124SMoriah Waterland * Returns : substring of 'path', beginning at character 2492*5c51f124SMoriah Waterland * following token, to end of string, if 2493*5c51f124SMoriah Waterland * token appears in path. Otherwise, 2494*5c51f124SMoriah Waterland * returns NULL. 2495*5c51f124SMoriah Waterland */ 2496*5c51f124SMoriah Waterland char * 2497*5c51f124SMoriah Waterland get_endof_string(char *path, char token) 2498*5c51f124SMoriah Waterland { 2499*5c51f124SMoriah Waterland char *p, *p2; 2500*5c51f124SMoriah Waterland 2501*5c51f124SMoriah Waterland if (path == NULL) 2502*5c51f124SMoriah Waterland return (NULL); 2503*5c51f124SMoriah Waterland 2504*5c51f124SMoriah Waterland p = xstrdup(path); 2505*5c51f124SMoriah Waterland 2506*5c51f124SMoriah Waterland if ((p2 = strrchr(p, token)) == NULL) { 2507*5c51f124SMoriah Waterland return (NULL); 2508*5c51f124SMoriah Waterland } 2509*5c51f124SMoriah Waterland 2510*5c51f124SMoriah Waterland return (p2 + 1); 2511*5c51f124SMoriah Waterland } 2512*5c51f124SMoriah Waterland 2513*5c51f124SMoriah Waterland /* 2514*5c51f124SMoriah Waterland * Name: progress_setup 2515*5c51f124SMoriah Waterland * Description: Initialize session for reporting progress 2516*5c51f124SMoriah Waterland * 2517*5c51f124SMoriah Waterland * Arguments: nointeract - if non-zero, do not do anything 2518*5c51f124SMoriah Waterland * ulong_t - size of job to report progress for 2519*5c51f124SMoriah Waterland * 2520*5c51f124SMoriah Waterland * Returns : none 2521*5c51f124SMoriah Waterland */ 2522*5c51f124SMoriah Waterland static void 2523*5c51f124SMoriah Waterland progress_setup(int nointeract, ulong_t size_of_load) 2524*5c51f124SMoriah Waterland { 2525*5c51f124SMoriah Waterland ulong_t divisor; 2526*5c51f124SMoriah Waterland ulong_t term_width = TERM_WIDTH; 2527*5c51f124SMoriah Waterland 2528*5c51f124SMoriah Waterland if (nointeract) 2529*5c51f124SMoriah Waterland return; 2530*5c51f124SMoriah Waterland 2531*5c51f124SMoriah Waterland if (size_of_load > MED_DWNLD && size_of_load < LARGE_DWNLD) 2532*5c51f124SMoriah Waterland divisor = MED_DIVISOR; 2533*5c51f124SMoriah Waterland else if (size_of_load > LARGE_DWNLD) { 2534*5c51f124SMoriah Waterland term_width = TERM_WIDTH - 8; 2535*5c51f124SMoriah Waterland divisor = LARGE_DIVISOR; 2536*5c51f124SMoriah Waterland } else 2537*5c51f124SMoriah Waterland divisor = SMALL_DIVISOR; 2538*5c51f124SMoriah Waterland 2539*5c51f124SMoriah Waterland const_increment = size_of_load / term_width; 2540*5c51f124SMoriah Waterland const_divider = size_of_load / divisor; 2541*5c51f124SMoriah Waterland const_completed = 100 / divisor; 2542*5c51f124SMoriah Waterland } 2543*5c51f124SMoriah Waterland 2544*5c51f124SMoriah Waterland /* 2545*5c51f124SMoriah Waterland * Name: progress_report 2546*5c51f124SMoriah Waterland * Description: Report progress for current progress context, 2547*5c51f124SMoriah Waterland * to stderr 2548*5c51f124SMoriah Waterland * 2549*5c51f124SMoriah Waterland * Arguments: nointeract - if non-zero, do not do anything 2550*5c51f124SMoriah Waterland * position - how far along in the job to report. 2551*5c51f124SMoriah Waterland * This should be <= size used during progress_setup 2552*5c51f124SMoriah Waterland * 2553*5c51f124SMoriah Waterland * Returns : none 2554*5c51f124SMoriah Waterland */ 2555*5c51f124SMoriah Waterland static void 2556*5c51f124SMoriah Waterland progress_report(int nointeract, ulong_t position) 2557*5c51f124SMoriah Waterland { 2558*5c51f124SMoriah Waterland static ulong_t increment; 2559*5c51f124SMoriah Waterland static ulong_t divider; 2560*5c51f124SMoriah Waterland 2561*5c51f124SMoriah Waterland if (nointeract) 2562*5c51f124SMoriah Waterland return; 2563*5c51f124SMoriah Waterland 2564*5c51f124SMoriah Waterland if (position == 0) { 2565*5c51f124SMoriah Waterland increment = const_increment; 2566*5c51f124SMoriah Waterland divider = const_divider; 2567*5c51f124SMoriah Waterland } 2568*5c51f124SMoriah Waterland if (position > increment && position < divider) { 2569*5c51f124SMoriah Waterland (void) putc('.', stderr); 2570*5c51f124SMoriah Waterland increment += const_increment; 2571*5c51f124SMoriah Waterland } else if (position > divider) { 2572*5c51f124SMoriah Waterland completed += const_completed; 2573*5c51f124SMoriah Waterland (void) fprintf(stderr, "%ld%c", completed, '%'); 2574*5c51f124SMoriah Waterland increment += const_increment; 2575*5c51f124SMoriah Waterland divider += const_divider; 2576*5c51f124SMoriah Waterland } 2577*5c51f124SMoriah Waterland } 2578*5c51f124SMoriah Waterland 2579*5c51f124SMoriah Waterland /* 2580*5c51f124SMoriah Waterland * Name: progress_finish 2581*5c51f124SMoriah Waterland * Description: Finalize session for reporting progress. 2582*5c51f124SMoriah Waterland * "100%" is reported to screen 2583*5c51f124SMoriah Waterland * 2584*5c51f124SMoriah Waterland * Arguments: nointeract - if non-zero, do not do anything 2585*5c51f124SMoriah Waterland * 2586*5c51f124SMoriah Waterland * Returns : none 2587*5c51f124SMoriah Waterland */ 2588*5c51f124SMoriah Waterland static void 2589*5c51f124SMoriah Waterland progress_finish(int nointeract) 2590*5c51f124SMoriah Waterland { 2591*5c51f124SMoriah Waterland if (nointeract) 2592*5c51f124SMoriah Waterland return; 2593*5c51f124SMoriah Waterland 2594*5c51f124SMoriah Waterland (void) fprintf(stderr, "%d%c\n", 100, '%'); 2595*5c51f124SMoriah Waterland } 2596*5c51f124SMoriah Waterland 2597*5c51f124SMoriah Waterland /* 2598*5c51f124SMoriah Waterland * Name: init_session 2599*5c51f124SMoriah Waterland * Description: Initializes static 'ps' structure with default 2600*5c51f124SMoriah Waterland * values 2601*5c51f124SMoriah Waterland * 2602*5c51f124SMoriah Waterland * Arguments: none 2603*5c51f124SMoriah Waterland * 2604*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 2605*5c51f124SMoriah Waterland */ 2606*5c51f124SMoriah Waterland static boolean_t 2607*5c51f124SMoriah Waterland init_session(void) 2608*5c51f124SMoriah Waterland { 2609*5c51f124SMoriah Waterland if ((ps = (WEB_SESSION *) 2610*5c51f124SMoriah Waterland xmalloc(sizeof (WEB_SESSION))) == NULL) { 2611*5c51f124SMoriah Waterland return (B_FALSE); 2612*5c51f124SMoriah Waterland } 2613*5c51f124SMoriah Waterland (void) memset(ps, 0, sizeof (*ps)); 2614*5c51f124SMoriah Waterland 2615*5c51f124SMoriah Waterland if ((ps->content = (char *)xmalloc(BLOCK)) == NULL) { 2616*5c51f124SMoriah Waterland return (B_FALSE); 2617*5c51f124SMoriah Waterland } 2618*5c51f124SMoriah Waterland 2619*5c51f124SMoriah Waterland (void) memset(ps->content, 0, BLOCK); 2620*5c51f124SMoriah Waterland 2621*5c51f124SMoriah Waterland ps->data.cur_pos = 0UL; 2622*5c51f124SMoriah Waterland ps->data.content_length = 0UL; 2623*5c51f124SMoriah Waterland ps->url.https = B_FALSE; 2624*5c51f124SMoriah Waterland ps->uniqfile = NULL; 2625*5c51f124SMoriah Waterland ps->link = NULL; 2626*5c51f124SMoriah Waterland ps->dwnld_dir = NULL; 2627*5c51f124SMoriah Waterland ps->spool = B_TRUE; 2628*5c51f124SMoriah Waterland ps->errstr = NULL; 2629*5c51f124SMoriah Waterland ps->keystore = NULL; 2630*5c51f124SMoriah Waterland 2631*5c51f124SMoriah Waterland return (B_TRUE); 2632*5c51f124SMoriah Waterland } 2633*5c51f124SMoriah Waterland 2634*5c51f124SMoriah Waterland /* 2635*5c51f124SMoriah Waterland * Name: ck_downld_dir_space 2636*5c51f124SMoriah Waterland * Description: Verify enough space exists in directory to hold file 2637*5c51f124SMoriah Waterland * 2638*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 2639*5c51f124SMoriah Waterland * dwnld_dir - Directory to check available space in 2640*5c51f124SMoriah Waterland * bytes_needed - How many bytes are need 2641*5c51f124SMoriah Waterland * 2642*5c51f124SMoriah Waterland * Returns : B_TRUE - enough space exists in dwnld_dir to hold 2643*5c51f124SMoriah Waterland * bytes_needed bytes, otherwise B_FALSE 2644*5c51f124SMoriah Waterland */ 2645*5c51f124SMoriah Waterland static boolean_t 2646*5c51f124SMoriah Waterland ck_dwnld_dir_space(PKG_ERR *err, char *dwnld_dir, ulong_t bytes_needed) 2647*5c51f124SMoriah Waterland { 2648*5c51f124SMoriah Waterland u_longlong_t bytes_avail; 2649*5c51f124SMoriah Waterland u_longlong_t block_pad; 2650*5c51f124SMoriah Waterland struct statvfs64 status; 2651*5c51f124SMoriah Waterland 2652*5c51f124SMoriah Waterland if (statvfs64(dwnld_dir, &status)) { 2653*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_TMPDIR), dwnld_dir); 2654*5c51f124SMoriah Waterland return (B_FALSE); 2655*5c51f124SMoriah Waterland } 2656*5c51f124SMoriah Waterland 2657*5c51f124SMoriah Waterland block_pad = (status.f_frsize ? status.f_frsize : status.f_bsize); 2658*5c51f124SMoriah Waterland bytes_avail = status.f_bavail * block_pad; 2659*5c51f124SMoriah Waterland 2660*5c51f124SMoriah Waterland if ((((u_longlong_t)bytes_needed) + block_pad) > bytes_avail) { 2661*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_DISK_SPACE), 2662*5c51f124SMoriah Waterland dwnld_dir, 2663*5c51f124SMoriah Waterland (((u_longlong_t)bytes_needed) + block_pad) / 1024ULL, 2664*5c51f124SMoriah Waterland bytes_avail / 1024ULL); 2665*5c51f124SMoriah Waterland return (B_FALSE); 2666*5c51f124SMoriah Waterland } 2667*5c51f124SMoriah Waterland 2668*5c51f124SMoriah Waterland return (B_TRUE); 2669*5c51f124SMoriah Waterland } 2670*5c51f124SMoriah Waterland 2671*5c51f124SMoriah Waterland /* 2672*5c51f124SMoriah Waterland * Description: 2673*5c51f124SMoriah Waterland * This function returns a unique file name based on the parts of the 2674*5c51f124SMoriah Waterland * URI. This is done to enable partially downloaded files to be resumed. 2675*5c51f124SMoriah Waterland * Arguments: 2676*5c51f124SMoriah Waterland * dir - The directory that should contain the filename. 2677*5c51f124SMoriah Waterland * last_modified - A string representing the date of last modification, 2678*5c51f124SMoriah Waterland * used as part of generating unique name 2679*5c51f124SMoriah Waterland * Returns: 2680*5c51f124SMoriah Waterland * A valid filename or NULL. 2681*5c51f124SMoriah Waterland */ 2682*5c51f124SMoriah Waterland 2683*5c51f124SMoriah Waterland static char * 2684*5c51f124SMoriah Waterland get_unique_filename(char *dir, char *last_modified) 2685*5c51f124SMoriah Waterland { 2686*5c51f124SMoriah Waterland char *buf, *buf2, *beg_str; 2687*5c51f124SMoriah Waterland int len; 2688*5c51f124SMoriah Waterland 2689*5c51f124SMoriah Waterland if ((buf = (char *)xmalloc(PATH_MAX)) == NULL) { 2690*5c51f124SMoriah Waterland return (NULL); 2691*5c51f124SMoriah Waterland } 2692*5c51f124SMoriah Waterland if ((buf2 = (char *)xmalloc(PATH_MAX)) == NULL) { 2693*5c51f124SMoriah Waterland return (NULL); 2694*5c51f124SMoriah Waterland } 2695*5c51f124SMoriah Waterland 2696*5c51f124SMoriah Waterland /* prepare strings for being cat'ed onto */ 2697*5c51f124SMoriah Waterland buf[0] = buf2[0] = '\0'; 2698*5c51f124SMoriah Waterland /* 2699*5c51f124SMoriah Waterland * No validation of the path is done here. We just construct the path 2700*5c51f124SMoriah Waterland * and it must be validated later 2701*5c51f124SMoriah Waterland */ 2702*5c51f124SMoriah Waterland 2703*5c51f124SMoriah Waterland if (dir) { 2704*5c51f124SMoriah Waterland if (((len = snprintf(buf2, PATH_MAX, "%s/", dir)) < 0) || 2705*5c51f124SMoriah Waterland (len >= PATH_MAX)) 2706*5c51f124SMoriah Waterland return (NULL); 2707*5c51f124SMoriah Waterland } else { 2708*5c51f124SMoriah Waterland return (NULL); 2709*5c51f124SMoriah Waterland } 2710*5c51f124SMoriah Waterland 2711*5c51f124SMoriah Waterland if (ps->url.abspath) 2712*5c51f124SMoriah Waterland if (strlcat(buf, ps->url.abspath, PATH_MAX) >= PATH_MAX) 2713*5c51f124SMoriah Waterland return (NULL); 2714*5c51f124SMoriah Waterland if (ps->url.hport.hostname) 2715*5c51f124SMoriah Waterland if (isdigit((int)ps->url.hport.hostname[0])) { 2716*5c51f124SMoriah Waterland if (strlcat(buf, ps->url.hport.hostname, PATH_MAX) 2717*5c51f124SMoriah Waterland >= PATH_MAX) 2718*5c51f124SMoriah Waterland return (NULL); 2719*5c51f124SMoriah Waterland } else { 2720*5c51f124SMoriah Waterland if ((beg_str = 2721*5c51f124SMoriah Waterland get_startof_string(ps->url.hport.hostname, '.')) 2722*5c51f124SMoriah Waterland != NULL) 2723*5c51f124SMoriah Waterland if (strlcat(buf, beg_str, PATH_MAX) >= PATH_MAX) 2724*5c51f124SMoriah Waterland return (NULL); 2725*5c51f124SMoriah Waterland } 2726*5c51f124SMoriah Waterland if (last_modified != NULL) 2727*5c51f124SMoriah Waterland if (strlcat(buf, last_modified, PATH_MAX) >= PATH_MAX) 2728*5c51f124SMoriah Waterland return (NULL); 2729*5c51f124SMoriah Waterland 2730*5c51f124SMoriah Waterland if ((buf = replace_token(buf, '/', '_')) != NULL) { 2731*5c51f124SMoriah Waterland if (strlcat(buf2, buf, PATH_MAX) >= PATH_MAX) { 2732*5c51f124SMoriah Waterland return (NULL); 2733*5c51f124SMoriah Waterland } else { 2734*5c51f124SMoriah Waterland if (buf) free(buf); 2735*5c51f124SMoriah Waterland return (buf2); 2736*5c51f124SMoriah Waterland } 2737*5c51f124SMoriah Waterland } else { 2738*5c51f124SMoriah Waterland if (buf) free(buf); 2739*5c51f124SMoriah Waterland if (buf2) free(buf2); 2740*5c51f124SMoriah Waterland return (NULL); 2741*5c51f124SMoriah Waterland } 2742*5c51f124SMoriah Waterland } 2743*5c51f124SMoriah Waterland 2744*5c51f124SMoriah Waterland /* 2745*5c51f124SMoriah Waterland * Description: 2746*5c51f124SMoriah Waterland * Removes token(s) consisting of one character from any path. 2747*5c51f124SMoriah Waterland * Arguments: 2748*5c51f124SMoriah Waterland * path - The path to search for the token in. 2749*5c51f124SMoriah Waterland * token - The token to search for 2750*5c51f124SMoriah Waterland * Returns: 2751*5c51f124SMoriah Waterland * The path with all tokens removed or NULL. 2752*5c51f124SMoriah Waterland */ 2753*5c51f124SMoriah Waterland static char * 2754*5c51f124SMoriah Waterland replace_token(char *path, char oldtoken, char newtoken) 2755*5c51f124SMoriah Waterland { 2756*5c51f124SMoriah Waterland char *newpath, *p; 2757*5c51f124SMoriah Waterland 2758*5c51f124SMoriah Waterland if ((path == NULL) || (oldtoken == '\0') || (newtoken == '\0')) { 2759*5c51f124SMoriah Waterland return (NULL); 2760*5c51f124SMoriah Waterland } 2761*5c51f124SMoriah Waterland 2762*5c51f124SMoriah Waterland newpath = xstrdup(path); 2763*5c51f124SMoriah Waterland 2764*5c51f124SMoriah Waterland for (p = newpath; *p != '\0'; p++) { 2765*5c51f124SMoriah Waterland if (*p == oldtoken) { 2766*5c51f124SMoriah Waterland *p = newtoken; 2767*5c51f124SMoriah Waterland } 2768*5c51f124SMoriah Waterland } 2769*5c51f124SMoriah Waterland 2770*5c51f124SMoriah Waterland return (newpath); 2771*5c51f124SMoriah Waterland } 2772*5c51f124SMoriah Waterland 2773*5c51f124SMoriah Waterland /* 2774*5c51f124SMoriah Waterland * Name: trim 2775*5c51f124SMoriah Waterland * Description: Trims whitespace from a string 2776*5c51f124SMoriah Waterland * has been registered) 2777*5c51f124SMoriah Waterland * Scope: private 2778*5c51f124SMoriah Waterland * Arguments: string - string to trim. It is assumed 2779*5c51f124SMoriah Waterland * this string is writable up to it's entire 2780*5c51f124SMoriah Waterland * length. 2781*5c51f124SMoriah Waterland * Returns: none 2782*5c51f124SMoriah Waterland */ 2783*5c51f124SMoriah Waterland static void 2784*5c51f124SMoriah Waterland trim(char *str) 2785*5c51f124SMoriah Waterland { 2786*5c51f124SMoriah Waterland int len, i; 2787*5c51f124SMoriah Waterland if (str == NULL) { 2788*5c51f124SMoriah Waterland return; 2789*5c51f124SMoriah Waterland } 2790*5c51f124SMoriah Waterland 2791*5c51f124SMoriah Waterland len = strlen(str); 2792*5c51f124SMoriah Waterland /* strip from front */ 2793*5c51f124SMoriah Waterland while (isspace(*str)) { 2794*5c51f124SMoriah Waterland for (i = 0; i < len; i++) { 2795*5c51f124SMoriah Waterland str[i] = str[i+1]; 2796*5c51f124SMoriah Waterland } 2797*5c51f124SMoriah Waterland } 2798*5c51f124SMoriah Waterland 2799*5c51f124SMoriah Waterland /* strip from back */ 2800*5c51f124SMoriah Waterland len = strlen(str); 2801*5c51f124SMoriah Waterland while (isspace(str[len-1])) { 2802*5c51f124SMoriah Waterland len--; 2803*5c51f124SMoriah Waterland } 2804*5c51f124SMoriah Waterland str[len] = '\0'; 2805*5c51f124SMoriah Waterland } 2806*5c51f124SMoriah Waterland 2807*5c51f124SMoriah Waterland /* 2808*5c51f124SMoriah Waterland * Description: 2809*5c51f124SMoriah Waterland * Resolves double quotes 2810*5c51f124SMoriah Waterland * Arguments: 2811*5c51f124SMoriah Waterland * str - The string to resolve 2812*5c51f124SMoriah Waterland * Returns: 2813*5c51f124SMoriah Waterland * None 2814*5c51f124SMoriah Waterland */ 2815*5c51f124SMoriah Waterland static void 2816*5c51f124SMoriah Waterland dequote(char *str) 2817*5c51f124SMoriah Waterland { 2818*5c51f124SMoriah Waterland char *cp; 2819*5c51f124SMoriah Waterland 2820*5c51f124SMoriah Waterland if ((str == NULL) || (str[0] != '"')) { 2821*5c51f124SMoriah Waterland /* no quotes */ 2822*5c51f124SMoriah Waterland return; 2823*5c51f124SMoriah Waterland } 2824*5c51f124SMoriah Waterland 2825*5c51f124SMoriah Waterland /* remove first quote */ 2826*5c51f124SMoriah Waterland memmove(str, str + 1, strlen(str) - 1); 2827*5c51f124SMoriah Waterland 2828*5c51f124SMoriah Waterland /* 2829*5c51f124SMoriah Waterland * scan string looking for ending quote. 2830*5c51f124SMoriah Waterland * escaped quotes like \" don't count 2831*5c51f124SMoriah Waterland */ 2832*5c51f124SMoriah Waterland cp = str; 2833*5c51f124SMoriah Waterland 2834*5c51f124SMoriah Waterland while (*cp != '\0') { 2835*5c51f124SMoriah Waterland switch (*cp) { 2836*5c51f124SMoriah Waterland case '\\': 2837*5c51f124SMoriah Waterland /* found an escaped character */ 2838*5c51f124SMoriah Waterland /* make sure end of string is not '\' */ 2839*5c51f124SMoriah Waterland if (*++cp != '\0') { 2840*5c51f124SMoriah Waterland cp++; 2841*5c51f124SMoriah Waterland } 2842*5c51f124SMoriah Waterland break; 2843*5c51f124SMoriah Waterland 2844*5c51f124SMoriah Waterland case '"': 2845*5c51f124SMoriah Waterland *cp = '\0'; 2846*5c51f124SMoriah Waterland break; 2847*5c51f124SMoriah Waterland default: 2848*5c51f124SMoriah Waterland cp++; 2849*5c51f124SMoriah Waterland } 2850*5c51f124SMoriah Waterland } 2851*5c51f124SMoriah Waterland } 2852*5c51f124SMoriah Waterland 2853*5c51f124SMoriah Waterland /* 2854*5c51f124SMoriah Waterland * Name: get_ENV_proxy 2855*5c51f124SMoriah Waterland * Description: Retrieves setting of proxy env variable 2856*5c51f124SMoriah Waterland * 2857*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 2858*5c51f124SMoriah Waterland * proxy - where to store proxy 2859*5c51f124SMoriah Waterland * 2860*5c51f124SMoriah Waterland * Returns : B_TRUE - http proxy was found and valid, stored in proxy 2861*5c51f124SMoriah Waterland * B_FALSE - error, errors recorded in err 2862*5c51f124SMoriah Waterland */ 2863*5c51f124SMoriah Waterland static boolean_t 2864*5c51f124SMoriah Waterland get_ENV_proxy(PKG_ERR *err, char **proxy) 2865*5c51f124SMoriah Waterland { 2866*5c51f124SMoriah Waterland char *buf; 2867*5c51f124SMoriah Waterland 2868*5c51f124SMoriah Waterland if ((buf = getenv("HTTPPROXY")) != NULL) { 2869*5c51f124SMoriah Waterland if (!path_valid(buf)) { 2870*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2871*5c51f124SMoriah Waterland gettext(ERR_ILL_ENV), "HTTPPROXY", buf); 2872*5c51f124SMoriah Waterland return (B_FALSE); 2873*5c51f124SMoriah Waterland } else { 2874*5c51f124SMoriah Waterland *proxy = buf; 2875*5c51f124SMoriah Waterland return (B_TRUE); 2876*5c51f124SMoriah Waterland } 2877*5c51f124SMoriah Waterland } else { 2878*5c51f124SMoriah Waterland /* try the other env variable */ 2879*5c51f124SMoriah Waterland if ((buf = getenv("http_proxy")) != NULL) { 2880*5c51f124SMoriah Waterland if (!path_valid(buf)) { 2881*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2882*5c51f124SMoriah Waterland gettext(ERR_ILL_ENV), "http_proxy", buf); 2883*5c51f124SMoriah Waterland return (B_FALSE); 2884*5c51f124SMoriah Waterland } 2885*5c51f124SMoriah Waterland if (!strneq(buf, "http://", 7)) { 2886*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2887*5c51f124SMoriah Waterland gettext(ERR_ILL_ENV), "http_proxy", buf); 2888*5c51f124SMoriah Waterland return (B_FALSE); 2889*5c51f124SMoriah Waterland } 2890*5c51f124SMoriah Waterland 2891*5c51f124SMoriah Waterland /* skip over the http:// part of the proxy "url" */ 2892*5c51f124SMoriah Waterland *proxy = buf + 7; 2893*5c51f124SMoriah Waterland return (B_TRUE); 2894*5c51f124SMoriah Waterland } 2895*5c51f124SMoriah Waterland } 2896*5c51f124SMoriah Waterland 2897*5c51f124SMoriah Waterland /* either the env variable(s) were set and valid, or not set */ 2898*5c51f124SMoriah Waterland return (B_TRUE); 2899*5c51f124SMoriah Waterland } 2900*5c51f124SMoriah Waterland 2901*5c51f124SMoriah Waterland /* 2902*5c51f124SMoriah Waterland * Name: get_ENV_proxyport 2903*5c51f124SMoriah Waterland * Description: Retrieves setting of PROXYPORT env variable 2904*5c51f124SMoriah Waterland * 2905*5c51f124SMoriah Waterland * Arguments: err - where to record any errors. 2906*5c51f124SMoriah Waterland * port - where to store resulting port 2907*5c51f124SMoriah Waterland * 2908*5c51f124SMoriah Waterland * Returns : B_TRUE - string found in PROXYPORT variable, converted 2909*5c51f124SMoriah Waterland * to decimal integer, if it exists 2910*5c51f124SMoriah Waterland * and is valid. Or, PROXYPORT not set, port set to 1. 2911*5c51f124SMoriah Waterland * B_FALSE - env variable set, but invalid 2912*5c51f124SMoriah Waterland * (not a number for example) 2913*5c51f124SMoriah Waterland */ 2914*5c51f124SMoriah Waterland static boolean_t 2915*5c51f124SMoriah Waterland get_ENV_proxyport(PKG_ERR *err, ushort_t *port) 2916*5c51f124SMoriah Waterland { 2917*5c51f124SMoriah Waterland char *buf; 2918*5c51f124SMoriah Waterland ushort_t newport; 2919*5c51f124SMoriah Waterland buf = getenv("HTTPPROXYPORT"); 2920*5c51f124SMoriah Waterland if (buf != NULL) { 2921*5c51f124SMoriah Waterland if (!path_valid(buf)) { 2922*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2923*5c51f124SMoriah Waterland gettext(ERR_ILL_ENV), "HTTPPROXYPORT", buf); 2924*5c51f124SMoriah Waterland return (B_FALSE); 2925*5c51f124SMoriah Waterland } 2926*5c51f124SMoriah Waterland if ((newport = atoi(buf)) == 0) { 2927*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2928*5c51f124SMoriah Waterland gettext(ERR_ILL_ENV), "HTTPPROXYPORT", buf); 2929*5c51f124SMoriah Waterland return (B_FALSE); 2930*5c51f124SMoriah Waterland } 2931*5c51f124SMoriah Waterland *port = newport; 2932*5c51f124SMoriah Waterland return (B_TRUE); 2933*5c51f124SMoriah Waterland } else { 2934*5c51f124SMoriah Waterland *port = 1; 2935*5c51f124SMoriah Waterland return (B_TRUE); 2936*5c51f124SMoriah Waterland } 2937*5c51f124SMoriah Waterland } 2938*5c51f124SMoriah Waterland 2939*5c51f124SMoriah Waterland /* 2940*5c51f124SMoriah Waterland * Name: remove_dwnld_file 2941*5c51f124SMoriah Waterland * Description: Removes newly-downloaded file if completely downloaded. 2942*5c51f124SMoriah Waterland * 2943*5c51f124SMoriah Waterland * Arguments: path - path to file to remove 2944*5c51f124SMoriah Waterland * 2945*5c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 2946*5c51f124SMoriah Waterland * if it's '0' (not OK) we simply return it, since the 2947*5c51f124SMoriah Waterland * verification operation has already determined that the 2948*5c51f124SMoriah Waterland * cert is invalid. if 'ok' is non-zero, then we do our 2949*5c51f124SMoriah Waterland * checks, and return 0 or 1 based on if the cert is 2950*5c51f124SMoriah Waterland * invalid or valid. 2951*5c51f124SMoriah Waterland */ 2952*5c51f124SMoriah Waterland static boolean_t 2953*5c51f124SMoriah Waterland remove_dwnld_file(char *path) 2954*5c51f124SMoriah Waterland { 2955*5c51f124SMoriah Waterland if (path && path != NULL) { 2956*5c51f124SMoriah Waterland /* 2957*5c51f124SMoriah Waterland * Only remove the downloaded file if it has been completely 2958*5c51f124SMoriah Waterland * downloaded, or is not eligible for spooling 2959*5c51f124SMoriah Waterland */ 2960*5c51f124SMoriah Waterland if ((!ps->spool) || 2961*5c51f124SMoriah Waterland (ps->data.cur_pos >= ps->data.content_length)) { 2962*5c51f124SMoriah Waterland (void) unlink(path); 2963*5c51f124SMoriah Waterland } 2964*5c51f124SMoriah Waterland } else { 2965*5c51f124SMoriah Waterland return (B_FALSE); 2966*5c51f124SMoriah Waterland } 2967*5c51f124SMoriah Waterland return (B_TRUE); 2968*5c51f124SMoriah Waterland } 2969*5c51f124SMoriah Waterland 2970*5c51f124SMoriah Waterland /* 2971*5c51f124SMoriah Waterland * Name: condense_lastmodifided 2972*5c51f124SMoriah Waterland * Description: generates a substring of a last-modified string, 2973*5c51f124SMoriah Waterland * and removes colons. 2974*5c51f124SMoriah Waterland * 2975*5c51f124SMoriah Waterland * Arguments: last_modified - string of the form 2976*5c51f124SMoriah Waterland * "Wed, 23 Oct 2002 21:59:45 GMT" 2977*5c51f124SMoriah Waterland * 2978*5c51f124SMoriah Waterland * Returns : 2979*5c51f124SMoriah Waterland * new string, consisting of hours/minutes/seconds only, 2980*5c51f124SMoriah Waterland * sans any colons. 2981*5c51f124SMoriah Waterland */ 2982*5c51f124SMoriah Waterland char * 2983*5c51f124SMoriah Waterland condense_lastmodified(char *last_modified) 2984*5c51f124SMoriah Waterland { 2985*5c51f124SMoriah Waterland char *p, *p2; 2986*5c51f124SMoriah Waterland 2987*5c51f124SMoriah Waterland /* 2988*5c51f124SMoriah Waterland * Last-Modified: Wed, 23 Oct 2002 21:59:45 GMT 2989*5c51f124SMoriah Waterland * Strip the hours, minutes and seconds, without the ':'s, from 2990*5c51f124SMoriah Waterland * the above string, void of the ':". 2991*5c51f124SMoriah Waterland */ 2992*5c51f124SMoriah Waterland 2993*5c51f124SMoriah Waterland if (last_modified == NULL) 2994*5c51f124SMoriah Waterland return (NULL); 2995*5c51f124SMoriah Waterland 2996*5c51f124SMoriah Waterland if ((p = xstrdup(last_modified)) == NULL) 2997*5c51f124SMoriah Waterland return (NULL); 2998*5c51f124SMoriah Waterland p2 = (strstr(p, ":") - 2); 2999*5c51f124SMoriah Waterland p2[8] = '\0'; 3000*5c51f124SMoriah Waterland return (replace_token(p2, ':', '_')); 3001*5c51f124SMoriah Waterland } 3002*5c51f124SMoriah Waterland 3003*5c51f124SMoriah Waterland /* 3004*5c51f124SMoriah Waterland * Name: backoff 3005*5c51f124SMoriah Waterland * Description: sleeps for a certain # of seconds after a network 3006*5c51f124SMoriah Waterland * failure. 3007*5c51f124SMoriah Waterland * Scope: public 3008*5c51f124SMoriah Waterland * Arguments: none 3009*5c51f124SMoriah Waterland * Returns: none 3010*5c51f124SMoriah Waterland */ 3011*5c51f124SMoriah Waterland void 3012*5c51f124SMoriah Waterland backoff() 3013*5c51f124SMoriah Waterland { 3014*5c51f124SMoriah Waterland static boolean_t initted = B_FALSE; 3015*5c51f124SMoriah Waterland int backoff; 3016*5c51f124SMoriah Waterland long seed; 3017*5c51f124SMoriah Waterland 3018*5c51f124SMoriah Waterland if (!initted) { 3019*5c51f124SMoriah Waterland /* seed the rng */ 3020*5c51f124SMoriah Waterland (void) _get_random_info(&seed, sizeof (seed)); 3021*5c51f124SMoriah Waterland srand48(seed); 3022*5c51f124SMoriah Waterland initted = B_TRUE; 3023*5c51f124SMoriah Waterland } 3024*5c51f124SMoriah Waterland 3025*5c51f124SMoriah Waterland backoff = drand48() * (double)cur_backoff; 3026*5c51f124SMoriah Waterland (void) sleep(backoff); 3027*5c51f124SMoriah Waterland if (cur_backoff < MAX_BACKOFF) { 3028*5c51f124SMoriah Waterland /* 3029*5c51f124SMoriah Waterland * increase maximum time we might wait 3030*5c51f124SMoriah Waterland * next time so as to fall off over 3031*5c51f124SMoriah Waterland * time. 3032*5c51f124SMoriah Waterland */ 3033*5c51f124SMoriah Waterland cur_backoff *= BACKOFF_FACTOR; 3034*5c51f124SMoriah Waterland } 3035*5c51f124SMoriah Waterland } 3036*5c51f124SMoriah Waterland 3037*5c51f124SMoriah Waterland /* 3038*5c51f124SMoriah Waterland * Name: reset_backoff 3039*5c51f124SMoriah Waterland * Description: notifies the backoff service that whatever was 3040*5c51f124SMoriah Waterland * being backoff succeeded. 3041*5c51f124SMoriah Waterland * Scope: public 3042*5c51f124SMoriah Waterland * Arguments: none 3043*5c51f124SMoriah Waterland * Returns: none 3044*5c51f124SMoriah Waterland */ 3045*5c51f124SMoriah Waterland void 3046*5c51f124SMoriah Waterland reset_backoff() 3047*5c51f124SMoriah Waterland { 3048*5c51f124SMoriah Waterland cur_backoff = MIN_BACKOFF; 3049*5c51f124SMoriah Waterland } 3050*5c51f124SMoriah Waterland 3051*5c51f124SMoriah Waterland /* 3052*5c51f124SMoriah Waterland * Name: _get_random_info 3053*5c51f124SMoriah Waterland * Description: generate an amount of random bits. Currently 3054*5c51f124SMoriah Waterland * only a small amount (a long long) can be 3055*5c51f124SMoriah Waterland * generated at one time. 3056*5c51f124SMoriah Waterland * Scope: private 3057*5c51f124SMoriah Waterland * Arguments: buf - [RO, *RW] (char *) 3058*5c51f124SMoriah Waterland * Buffer to copy bits into 3059*5c51f124SMoriah Waterland * size - amount to copy 3060*5c51f124SMoriah Waterland * Returns: B_TRUE on success, B_FALSE otherwise. The buffer is filled 3061*5c51f124SMoriah Waterland * with the amount of bytes of random data specified. 3062*5c51f124SMoriah Waterland */ 3063*5c51f124SMoriah Waterland static boolean_t 3064*5c51f124SMoriah Waterland _get_random_info(void *buf, int size) 3065*5c51f124SMoriah Waterland { 3066*5c51f124SMoriah Waterland struct timeval tv; 3067*5c51f124SMoriah Waterland typedef struct { 3068*5c51f124SMoriah Waterland long low_time; 3069*5c51f124SMoriah Waterland long hostid; 3070*5c51f124SMoriah Waterland } randomness; 3071*5c51f124SMoriah Waterland randomness r; 3072*5c51f124SMoriah Waterland 3073*5c51f124SMoriah Waterland /* if the RANDOM file exists, use it */ 3074*5c51f124SMoriah Waterland if (access(RANDOM, R_OK) == 0) { 3075*5c51f124SMoriah Waterland if ((RAND_load_file(RANDOM, 1024 * 1024)) > 0) { 3076*5c51f124SMoriah Waterland if (RAND_bytes((uchar_t *)buf, size) == 1) { 3077*5c51f124SMoriah Waterland /* success */ 3078*5c51f124SMoriah Waterland return (B_TRUE); 3079*5c51f124SMoriah Waterland } 3080*5c51f124SMoriah Waterland } 3081*5c51f124SMoriah Waterland } 3082*5c51f124SMoriah Waterland 3083*5c51f124SMoriah Waterland /* couldn't use RANDOM file, so fallback to time of day and hostid */ 3084*5c51f124SMoriah Waterland (void) gettimeofday(&tv, (struct timezone *)0); 3085*5c51f124SMoriah Waterland 3086*5c51f124SMoriah Waterland /* Wouldn't it be nice if we could hash these */ 3087*5c51f124SMoriah Waterland r.low_time = tv.tv_usec; 3088*5c51f124SMoriah Waterland r.hostid = gethostid(); 3089*5c51f124SMoriah Waterland 3090*5c51f124SMoriah Waterland if (sizeof (r) < size) { 3091*5c51f124SMoriah Waterland /* 3092*5c51f124SMoriah Waterland * Can't copy correctly 3093*5c51f124SMoriah Waterland */ 3094*5c51f124SMoriah Waterland return (B_FALSE); 3095*5c51f124SMoriah Waterland } 3096*5c51f124SMoriah Waterland (void) memcpy(buf, &r, size); 3097*5c51f124SMoriah Waterland return (B_TRUE); 3098*5c51f124SMoriah Waterland } 3099*5c51f124SMoriah Waterland 3100*5c51f124SMoriah Waterland /* 3101*5c51f124SMoriah Waterland * Name: pkg_passphrase_cb 3102*5c51f124SMoriah Waterland * Description: Default callback that applications can use when 3103*5c51f124SMoriah Waterland * a passphrase is needed. This routine collects 3104*5c51f124SMoriah Waterland * a passphrase from the user using the given 3105*5c51f124SMoriah Waterland * passphrase retrieval method set with 3106*5c51f124SMoriah Waterland * set_passphrase_passarg(). If the method 3107*5c51f124SMoriah Waterland * indicates an interactive prompt, then the 3108*5c51f124SMoriah Waterland * prompt set with set_passphrase_prompt() 3109*5c51f124SMoriah Waterland * is displayed. 3110*5c51f124SMoriah Waterland * 3111*5c51f124SMoriah Waterland * Arguments: buf - Buffer to copy passphrase into 3112*5c51f124SMoriah Waterland * size - Max amount to copy to buf 3113*5c51f124SMoriah Waterland * rw - Whether this passphrase is needed 3114*5c51f124SMoriah Waterland * to read something off disk, or 3115*5c51f124SMoriah Waterland * write something to disk. Applications 3116*5c51f124SMoriah Waterland * typically want to ask twice when getting 3117*5c51f124SMoriah Waterland * a passphrase for writing something. 3118*5c51f124SMoriah Waterland * data - application-specific data. In this 3119*5c51f124SMoriah Waterland * callback, data is a pointer to 3120*5c51f124SMoriah Waterland * a keystore_passphrase_data structure. 3121*5c51f124SMoriah Waterland * 3122*5c51f124SMoriah Waterland * Returns: Length of passphrase collected, or -1 on error. 3123*5c51f124SMoriah Waterland * Errors recorded in 'err' object in the *data. 3124*5c51f124SMoriah Waterland */ 3125*5c51f124SMoriah Waterland int 3126*5c51f124SMoriah Waterland pkg_passphrase_cb(char *buf, int size, int rw, void *data) 3127*5c51f124SMoriah Waterland { 3128*5c51f124SMoriah Waterland BIO *pwdbio = NULL; 3129*5c51f124SMoriah Waterland char passphrase_copy[MAX_PHRASELEN + 1]; 3130*5c51f124SMoriah Waterland PKG_ERR *err; 3131*5c51f124SMoriah Waterland int passlen; 3132*5c51f124SMoriah Waterland char *ws; 3133*5c51f124SMoriah Waterland char prompt_copy[MAX_VERIFY_MSGLEN]; 3134*5c51f124SMoriah Waterland char *passphrase; 3135*5c51f124SMoriah Waterland char *arg; 3136*5c51f124SMoriah Waterland 3137*5c51f124SMoriah Waterland err = ((keystore_passphrase_data *)data)->err; 3138*5c51f124SMoriah Waterland 3139*5c51f124SMoriah Waterland if (passarg == NULL) { 3140*5c51f124SMoriah Waterland arg = "console"; 3141*5c51f124SMoriah Waterland } else { 3142*5c51f124SMoriah Waterland arg = passarg; 3143*5c51f124SMoriah Waterland } 3144*5c51f124SMoriah Waterland 3145*5c51f124SMoriah Waterland /* default method of collecting password is by prompting */ 3146*5c51f124SMoriah Waterland if (ci_streq(arg, "console")) { 3147*5c51f124SMoriah Waterland if ((passphrase = getpassphrase(prompt)) == NULL) { 3148*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 3149*5c51f124SMoriah Waterland gettext(MSG_NOPASS), arg); 3150*5c51f124SMoriah Waterland return (-1); 3151*5c51f124SMoriah Waterland } 3152*5c51f124SMoriah Waterland 3153*5c51f124SMoriah Waterland if (rw) { 3154*5c51f124SMoriah Waterland /* 3155*5c51f124SMoriah Waterland * if the password is being supplied for 3156*5c51f124SMoriah Waterland * writing something to disk, verify it first 3157*5c51f124SMoriah Waterland */ 3158*5c51f124SMoriah Waterland 3159*5c51f124SMoriah Waterland /* make a copy (getpassphrase overwrites) */ 3160*5c51f124SMoriah Waterland strlcpy(passphrase_copy, passphrase, 3161*5c51f124SMoriah Waterland MAX_PHRASELEN + 1); 3162*5c51f124SMoriah Waterland 3163*5c51f124SMoriah Waterland if (((passlen = snprintf(prompt_copy, 3164*5c51f124SMoriah Waterland MAX_VERIFY_MSGLEN, "%s: %s", 3165*5c51f124SMoriah Waterland gettext(MSG_PASSWD_AGAIN), 3166*5c51f124SMoriah Waterland prompt)) < 0) || 3167*5c51f124SMoriah Waterland (passlen >= (MAX_PHRASELEN + 1))) { 3168*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 3169*5c51f124SMoriah Waterland gettext(MSG_NOPASS), arg); 3170*5c51f124SMoriah Waterland return (-1); 3171*5c51f124SMoriah Waterland } 3172*5c51f124SMoriah Waterland 3173*5c51f124SMoriah Waterland if ((passphrase = 3174*5c51f124SMoriah Waterland getpassphrase(prompt_copy)) == NULL) { 3175*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 3176*5c51f124SMoriah Waterland gettext(MSG_NOPASS), arg); 3177*5c51f124SMoriah Waterland return (-1); 3178*5c51f124SMoriah Waterland } 3179*5c51f124SMoriah Waterland 3180*5c51f124SMoriah Waterland if (!streq(passphrase_copy, passphrase)) { 3181*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, 3182*5c51f124SMoriah Waterland gettext(MSG_PASSWD_NOMATCH)); 3183*5c51f124SMoriah Waterland return (-1); 3184*5c51f124SMoriah Waterland } 3185*5c51f124SMoriah Waterland } 3186*5c51f124SMoriah Waterland } else if (ci_strneq(arg, "pass:", 5)) { 3187*5c51f124SMoriah Waterland passphrase = arg + 5; 3188*5c51f124SMoriah Waterland } else if (ci_strneq(arg, "env:", 4)) { 3189*5c51f124SMoriah Waterland passphrase = getenv(arg + 4); 3190*5c51f124SMoriah Waterland } else if (ci_strneq(arg, "file:", 5)) { 3191*5c51f124SMoriah Waterland 3192*5c51f124SMoriah Waterland /* open file for reading */ 3193*5c51f124SMoriah Waterland if ((pwdbio = BIO_new_file(arg + 5, "r")) == NULL) { 3194*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_EXIST, 3195*5c51f124SMoriah Waterland gettext(MSG_PASSWD_FILE), arg + 5); 3196*5c51f124SMoriah Waterland return (-1); 3197*5c51f124SMoriah Waterland } 3198*5c51f124SMoriah Waterland 3199*5c51f124SMoriah Waterland /* read first line */ 3200*5c51f124SMoriah Waterland if (((passlen = BIO_gets(pwdbio, buf, size)) < 1) || 3201*5c51f124SMoriah Waterland (passlen > size)) { 3202*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, gettext(MSG_PASSWD_FILE), 3203*5c51f124SMoriah Waterland arg + 5); 3204*5c51f124SMoriah Waterland return (-1); 3205*5c51f124SMoriah Waterland } 3206*5c51f124SMoriah Waterland BIO_free_all(pwdbio); 3207*5c51f124SMoriah Waterland pwdbio = NULL; 3208*5c51f124SMoriah Waterland 3209*5c51f124SMoriah Waterland if (passlen == size) { 3210*5c51f124SMoriah Waterland /* 3211*5c51f124SMoriah Waterland * password was maximum length, so there is 3212*5c51f124SMoriah Waterland * no null terminator. null-terminate it 3213*5c51f124SMoriah Waterland */ 3214*5c51f124SMoriah Waterland buf[size - 1] = '\0'; 3215*5c51f124SMoriah Waterland } 3216*5c51f124SMoriah Waterland 3217*5c51f124SMoriah Waterland /* first newline found is end of passwd, so nuke it */ 3218*5c51f124SMoriah Waterland if ((ws = strchr(buf, '\n')) != NULL) { 3219*5c51f124SMoriah Waterland *ws = '\0'; 3220*5c51f124SMoriah Waterland } 3221*5c51f124SMoriah Waterland return (strlen(buf)); 3222*5c51f124SMoriah Waterland } else { 3223*5c51f124SMoriah Waterland /* unrecognized passphrase */ 3224*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 3225*5c51f124SMoriah Waterland gettext(MSG_BADPASSARG), arg); 3226*5c51f124SMoriah Waterland return (-1); 3227*5c51f124SMoriah Waterland } 3228*5c51f124SMoriah Waterland 3229*5c51f124SMoriah Waterland if (passphrase == NULL) { 3230*5c51f124SMoriah Waterland /* unable to collect passwd from given source */ 3231*5c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 3232*5c51f124SMoriah Waterland gettext(MSG_NOPASS), arg); 3233*5c51f124SMoriah Waterland return (-1); 3234*5c51f124SMoriah Waterland } 3235*5c51f124SMoriah Waterland 3236*5c51f124SMoriah Waterland strlcpy(buf, passphrase, size); 3237*5c51f124SMoriah Waterland return (strlen(buf)); 3238*5c51f124SMoriah Waterland } 3239