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