15c51f124SMoriah Waterland /* 25c51f124SMoriah Waterland * CDDL HEADER START 35c51f124SMoriah Waterland * 45c51f124SMoriah Waterland * The contents of this file are subject to the terms of the 55c51f124SMoriah Waterland * Common Development and Distribution License (the "License"). 65c51f124SMoriah Waterland * You may not use this file except in compliance with the License. 75c51f124SMoriah Waterland * 85c51f124SMoriah Waterland * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95c51f124SMoriah Waterland * or http://www.opensolaris.org/os/licensing. 105c51f124SMoriah Waterland * See the License for the specific language governing permissions 115c51f124SMoriah Waterland * and limitations under the License. 125c51f124SMoriah Waterland * 135c51f124SMoriah Waterland * When distributing Covered Code, include this CDDL HEADER in each 145c51f124SMoriah Waterland * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155c51f124SMoriah Waterland * If applicable, add the following below this CDDL HEADER, with the 165c51f124SMoriah Waterland * fields enclosed by brackets "[]" replaced with your own identifying 175c51f124SMoriah Waterland * information: Portions Copyright [yyyy] [name of copyright owner] 185c51f124SMoriah Waterland * 195c51f124SMoriah Waterland * CDDL HEADER END 205c51f124SMoriah Waterland */ 215c51f124SMoriah Waterland 225c51f124SMoriah Waterland /* 235c51f124SMoriah Waterland * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 245c51f124SMoriah Waterland * Use is subject to license terms. 255c51f124SMoriah Waterland */ 265c51f124SMoriah Waterland 275c51f124SMoriah Waterland /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 285c51f124SMoriah Waterland /* All Rights Reserved */ 295c51f124SMoriah Waterland 305c51f124SMoriah Waterland 315c51f124SMoriah Waterland #include <stdio.h> 325c51f124SMoriah Waterland #include <limits.h> 335c51f124SMoriah Waterland #include <stdlib.h> 345c51f124SMoriah Waterland #include <unistd.h> 355c51f124SMoriah Waterland #include <string.h> 365c51f124SMoriah Waterland #include <pkglocs.h> 375c51f124SMoriah Waterland #include <locale.h> 385c51f124SMoriah Waterland #include <libintl.h> 395c51f124SMoriah Waterland #include <libgen.h> 405c51f124SMoriah Waterland #include <signal.h> 415c51f124SMoriah Waterland #include <sys/stat.h> 425c51f124SMoriah Waterland #include <sys/statvfs.h> 435c51f124SMoriah Waterland #include <sys/types.h> 445c51f124SMoriah Waterland #include <fcntl.h> 455c51f124SMoriah Waterland #include <dirent.h> 465c51f124SMoriah Waterland #include <boot_http.h> 475c51f124SMoriah Waterland #include <errno.h> 485c51f124SMoriah Waterland #include <ctype.h> 495c51f124SMoriah Waterland #include <openssl/pkcs7.h> 505c51f124SMoriah Waterland #include <openssl/ocsp.h> 515c51f124SMoriah Waterland #include <openssl/pkcs12.h> 525c51f124SMoriah Waterland #include <openssl/err.h> 535c51f124SMoriah Waterland #include <openssl/x509.h> 545c51f124SMoriah Waterland #include <openssl/pem.h> 555c51f124SMoriah Waterland #include <openssl/evp.h> 565c51f124SMoriah Waterland #include <openssl/rand.h> 575c51f124SMoriah Waterland #include <openssl/x509v3.h> 585c51f124SMoriah Waterland #include "pkglib.h" 595c51f124SMoriah Waterland #include "pkglibmsgs.h" 605c51f124SMoriah Waterland #include "pkglocale.h" 615c51f124SMoriah Waterland #include "keystore.h" 625c51f124SMoriah Waterland #include "pkgweb.h" 635c51f124SMoriah Waterland #include "pkgerr.h" 645c51f124SMoriah Waterland #include "p12lib.h" 655c51f124SMoriah Waterland 665c51f124SMoriah Waterland /* fixed format when making an OCSP request */ 675c51f124SMoriah Waterland #define OCSP_REQUEST_FORMAT \ 685c51f124SMoriah Waterland "POST %s HTTP/1.0\r\n" \ 695c51f124SMoriah Waterland "Content-Type: application/ocsp-request\r\n" \ 705c51f124SMoriah Waterland "Content-Length: %d\r\n\r\n" 715c51f124SMoriah Waterland 725c51f124SMoriah Waterland /* 735c51f124SMoriah Waterland * no security is afforded by using this phrase to "encrypt" CA certificates, 745c51f124SMoriah Waterland * but it might aid in debugging and has to be non-null 755c51f124SMoriah Waterland */ 765c51f124SMoriah Waterland #define WEB_CA_PHRASE "schizophrenic" 775c51f124SMoriah Waterland 785c51f124SMoriah Waterland /* This one needs the ': ' at the end */ 795c51f124SMoriah Waterland #define CONTENT_TYPE_HDR "Content-Type" 805c51f124SMoriah Waterland #define CONTENT_DISPOSITION_HDR "Content-Disposition" 815c51f124SMoriah Waterland #define CONTENT_OCSP_RESP "application/ocsp-response" 825c51f124SMoriah Waterland #define CONTENT_LENGTH_HDR "Content-Length" 835c51f124SMoriah Waterland #define LAST_MODIFIED_HDR "Last-Modified" 845c51f124SMoriah Waterland #define OCSP_BUFSIZ 1024 855c51f124SMoriah Waterland 865c51f124SMoriah Waterland /* 875c51f124SMoriah Waterland * default amount of time that is allowed for error when checking 885c51f124SMoriah Waterland * OCSP response validity. 895c51f124SMoriah Waterland * For example, if this is set to 5 minutes, then if a response 905c51f124SMoriah Waterland * is issued that is valid from 12:00 to 1:00, then we will 915c51f124SMoriah Waterland * accept it if the local time is between 11:55 and 1:05. 925c51f124SMoriah Waterland * This takes care of not-quite-synchronized server and client clocks. 935c51f124SMoriah Waterland */ 945c51f124SMoriah Waterland #define OCSP_VALIDITY_PERIOD (5 * 60) 955c51f124SMoriah Waterland 965c51f124SMoriah Waterland /* this value is defined by getpassphrase(3c) manpage */ 975c51f124SMoriah Waterland #define MAX_PHRASELEN 257 985c51f124SMoriah Waterland 995c51f124SMoriah Waterland /* Max length of "enter password again" prompt message */ 1005c51f124SMoriah Waterland #define MAX_VERIFY_MSGLEN 1024 1015c51f124SMoriah Waterland 1025c51f124SMoriah Waterland /* local prototypes */ 1035c51f124SMoriah Waterland static boolean_t remove_dwnld_file(char *); 1045c51f124SMoriah Waterland static boolean_t get_ENV_proxyport(PKG_ERR *, ushort_t *); 1055c51f124SMoriah Waterland static boolean_t make_link(char *, char *); 1065c51f124SMoriah Waterland static WebStatus web_send_request(PKG_ERR *, int, int, int); 1075c51f124SMoriah Waterland static boolean_t web_eval_headers(PKG_ERR *); 1085c51f124SMoriah Waterland static WebStatus web_get_file(PKG_ERR *, char *, int, char **); 1095c51f124SMoriah Waterland static boolean_t ck_dwnld_dir_space(PKG_ERR *, char *, ulong_t); 1105c51f124SMoriah Waterland static WebStatus web_connect(PKG_ERR *); 1115c51f124SMoriah Waterland static boolean_t web_setup(PKG_ERR *); 1125c51f124SMoriah Waterland static boolean_t check_dwnld_dir(PKG_ERR *, char *); 1135c51f124SMoriah Waterland static boolean_t parse_url_proxy(PKG_ERR *, char *, char *, ushort_t); 1145c51f124SMoriah Waterland static boolean_t web_disconnect(void); 1155c51f124SMoriah Waterland static char *get_unique_filename(char *, char *); 1165c51f124SMoriah Waterland static boolean_t get_ENV_proxy(PKG_ERR *, char **); 1175c51f124SMoriah Waterland static char *condense_lastmodified(char *); 1185c51f124SMoriah Waterland static int web_verify(int, X509_STORE_CTX *); 1195c51f124SMoriah Waterland static int get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); 1205c51f124SMoriah Waterland static boolean_t get_ocsp_uri(X509 *, char **); 1215c51f124SMoriah Waterland static OCSPStatus ocsp_verify(PKG_ERR *, X509 *, X509 *, char *, url_hport_t *, 1225c51f124SMoriah Waterland STACK_OF(X509) *); 1235c51f124SMoriah Waterland static char *get_time_string(ASN1_GENERALIZEDTIME *); 1245c51f124SMoriah Waterland static char *write_ca_file(PKG_ERR *, char *, STACK_OF(X509) *, char *); 1255c51f124SMoriah Waterland static boolean_t _get_random_info(void *, int); 1265c51f124SMoriah Waterland static boolean_t init_session(void); 1275c51f124SMoriah Waterland static void progress_setup(int, ulong_t); 1285c51f124SMoriah Waterland static void progress_report(int, ulong_t); 1295c51f124SMoriah Waterland static void progress_finish(int); 1305c51f124SMoriah Waterland static char *replace_token(char *, char, char); 1315c51f124SMoriah Waterland static void dequote(char *); 1325c51f124SMoriah Waterland static void trim(char *); 1335c51f124SMoriah Waterland 1345c51f124SMoriah Waterland 1355c51f124SMoriah Waterland /* 1365c51f124SMoriah Waterland * structure used to hold data passed back to the 1375c51f124SMoriah Waterland * X509 verify callback routine in validate_signature() 1385c51f124SMoriah Waterland */ 1395c51f124SMoriah Waterland typedef struct { 1405c51f124SMoriah Waterland url_hport_t *proxy; 1415c51f124SMoriah Waterland PKG_ERR *err; 1425c51f124SMoriah Waterland STACK_OF(X509) *cas; 1435c51f124SMoriah Waterland } verify_cb_data_t; 1445c51f124SMoriah Waterland 1455c51f124SMoriah Waterland /* Progress bar variables */ 1465c51f124SMoriah Waterland static ulong_t const_increment, const_divider, completed, const_completed; 1475c51f124SMoriah Waterland 1485c51f124SMoriah Waterland /* current network backoff wait period */ 1495c51f124SMoriah Waterland static int cur_backoff = 0; 1505c51f124SMoriah Waterland 1515c51f124SMoriah Waterland /* download session context handle */ 1525c51f124SMoriah Waterland static WEB_SESSION *ps; 1535c51f124SMoriah Waterland 1545c51f124SMoriah Waterland static int webpkg_install = 0; 1555c51f124SMoriah Waterland static char *prompt = NULL; 1565c51f124SMoriah Waterland static char *passarg = NULL; 1575c51f124SMoriah Waterland 1585c51f124SMoriah Waterland 1595c51f124SMoriah Waterland /* ~~~~~~~~~~~~~~ Public Functions ~~~~~~~~~~~~~~~~~~~ */ 1605c51f124SMoriah Waterland 1615c51f124SMoriah Waterland /* 1625c51f124SMoriah Waterland * Name: set_prompt 1635c51f124SMoriah Waterland * Description: Specifies the prompt to use with the pkglib 1645c51f124SMoriah Waterland * passphrase callback routine. 1655c51f124SMoriah Waterland * 1665c51f124SMoriah Waterland * Arguments: newprompt - The prompt to display 1675c51f124SMoriah Waterland * 1685c51f124SMoriah Waterland * Returns : NONE 1695c51f124SMoriah Waterland */ 1705c51f124SMoriah Waterland void 1715c51f124SMoriah Waterland set_passphrase_prompt(char *newprompt) 1725c51f124SMoriah Waterland { 1735c51f124SMoriah Waterland prompt = newprompt; 1745c51f124SMoriah Waterland } 1755c51f124SMoriah Waterland 1765c51f124SMoriah Waterland /* 1775c51f124SMoriah Waterland * Name: set_passarg 1785c51f124SMoriah Waterland * Description: Specifies the passphrase retrieval method 1795c51f124SMoriah Waterland * to use with the pkglib 1805c51f124SMoriah Waterland * passphrase callback routine. 1815c51f124SMoriah Waterland * 1825c51f124SMoriah Waterland * Arguments: newpassarg - The new password retrieval arg 1835c51f124SMoriah Waterland * 1845c51f124SMoriah Waterland * Returns : NONE 1855c51f124SMoriah Waterland */ 1865c51f124SMoriah Waterland void 1875c51f124SMoriah Waterland set_passphrase_passarg(char *newpassarg) 1885c51f124SMoriah Waterland { 1895c51f124SMoriah Waterland passarg = newpassarg; 1905c51f124SMoriah Waterland } 1915c51f124SMoriah Waterland 1925c51f124SMoriah Waterland /* 1935c51f124SMoriah Waterland * Name: get_proxy_port 1945c51f124SMoriah Waterland * Description: Resolves proxy specification 1955c51f124SMoriah Waterland * 1965c51f124SMoriah Waterland * Arguments: err - where to record any errors. 1975c51f124SMoriah Waterland * proxy - Location to store result - if *proxy is not 1985c51f124SMoriah Waterland * null, then it will be validated, but not changed 1995c51f124SMoriah Waterland * 2005c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 2015c51f124SMoriah Waterland * on success, *proxy and *port are set to either 2025c51f124SMoriah Waterland * the user-supplied proxy and port, or the 2035c51f124SMoriah Waterland * ones found in the environment variables 2045c51f124SMoriah Waterland * HTTPPROXY and/or HTTPROXYPORT 2055c51f124SMoriah Waterland */ 2065c51f124SMoriah Waterland boolean_t 2075c51f124SMoriah Waterland get_proxy_port(PKG_ERR *err, char **proxy, ushort_t *port) 2085c51f124SMoriah Waterland { 2095c51f124SMoriah Waterland if (*proxy != NULL) { 2105c51f124SMoriah Waterland if (!path_valid(*proxy)) { 2115c51f124SMoriah Waterland /* bad proxy supplied */ 2125c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2135c51f124SMoriah Waterland gettext(ERR_BAD_PROXY), *proxy); 2145c51f124SMoriah Waterland return (B_FALSE); 2155c51f124SMoriah Waterland } 2165c51f124SMoriah Waterland if (!get_ENV_proxyport(err, port)) { 2175c51f124SMoriah Waterland /* env set, but bad */ 2185c51f124SMoriah Waterland return (B_FALSE); 2195c51f124SMoriah Waterland } 2205c51f124SMoriah Waterland } else { 2215c51f124SMoriah Waterland if (!get_ENV_proxy(err, proxy)) { 2225c51f124SMoriah Waterland /* environment variable set, but bad */ 2235c51f124SMoriah Waterland return (B_FALSE); 2245c51f124SMoriah Waterland } 2255c51f124SMoriah Waterland if ((*proxy != NULL) && !path_valid(*proxy)) { 2265c51f124SMoriah Waterland /* env variable set, but bad */ 2275c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 2285c51f124SMoriah Waterland gettext(ERR_BAD_PROXY), *proxy); 2295c51f124SMoriah Waterland return (B_FALSE); 2305c51f124SMoriah Waterland } 2315c51f124SMoriah Waterland if (!get_ENV_proxyport(err, port)) { 2325c51f124SMoriah Waterland /* env variable set, but bad */ 2335c51f124SMoriah Waterland return (B_FALSE); 2345c51f124SMoriah Waterland } 2355c51f124SMoriah Waterland } 2365c51f124SMoriah Waterland return (B_TRUE); 2375c51f124SMoriah Waterland } 2385c51f124SMoriah Waterland 2395c51f124SMoriah Waterland /* 2405c51f124SMoriah Waterland * Name: path_valid 2415c51f124SMoriah Waterland * Description: Checks a string for being a valid path 2425c51f124SMoriah Waterland * 2435c51f124SMoriah Waterland * Arguments: path - path to validate 2445c51f124SMoriah Waterland * 2455c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise. 2465c51f124SMoriah Waterland * B_FALSE means path was null, too long (>PATH_MAX), 2475c51f124SMoriah Waterland * or too short (<1) 2485c51f124SMoriah Waterland */ 2495c51f124SMoriah Waterland boolean_t 2505c51f124SMoriah Waterland path_valid(char *path) 2515c51f124SMoriah Waterland { 2525c51f124SMoriah Waterland if (path == NULL) { 2535c51f124SMoriah Waterland return (B_FALSE); 2545c51f124SMoriah Waterland } else if (strlen(path) > PATH_MAX) { 2555c51f124SMoriah Waterland return (B_FALSE); 2565c51f124SMoriah Waterland } else if (strlen(path) >= 1) { 2575c51f124SMoriah Waterland return (B_TRUE); 2585c51f124SMoriah Waterland } else { 2595c51f124SMoriah Waterland /* path < 1 */ 2605c51f124SMoriah Waterland return (B_FALSE); 2615c51f124SMoriah Waterland } 2625c51f124SMoriah Waterland } 2635c51f124SMoriah Waterland 2645c51f124SMoriah Waterland /* 2655c51f124SMoriah Waterland * Name: web_cleanup 2665c51f124SMoriah Waterland * Description: Deletes temp files, closes, frees memory taken 2675c51f124SMoriah Waterland * by 'ps' static structure 2685c51f124SMoriah Waterland * 2695c51f124SMoriah Waterland * Arguments: none 2705c51f124SMoriah Waterland * 2715c51f124SMoriah Waterland * Returns : none 2725c51f124SMoriah Waterland */ 2735c51f124SMoriah Waterland void 2745c51f124SMoriah Waterland web_cleanup(void) 2755c51f124SMoriah Waterland { 2765c51f124SMoriah Waterland PKG_ERR *err; 2775c51f124SMoriah Waterland 2785c51f124SMoriah Waterland if (ps == NULL) 2795c51f124SMoriah Waterland return; 2805c51f124SMoriah Waterland 2815c51f124SMoriah Waterland err = pkgerr_new(); 2825c51f124SMoriah Waterland 2835c51f124SMoriah Waterland if (ps->keystore) { 2845c51f124SMoriah Waterland (void) close_keystore(err, ps->keystore, NULL); 2855c51f124SMoriah Waterland } 2865c51f124SMoriah Waterland 2875c51f124SMoriah Waterland ps->keystore = NULL; 2885c51f124SMoriah Waterland 2895c51f124SMoriah Waterland pkgerr_free(err); 2905c51f124SMoriah Waterland 2915c51f124SMoriah Waterland if (ps->uniqfile) { 2925c51f124SMoriah Waterland (void) remove_dwnld_file(ps->uniqfile); 2935c51f124SMoriah Waterland free(ps->uniqfile); 2945c51f124SMoriah Waterland ps->uniqfile = NULL; 2955c51f124SMoriah Waterland } 2965c51f124SMoriah Waterland if (ps->link) { 2975c51f124SMoriah Waterland (void) remove_dwnld_file(ps->link); 2985c51f124SMoriah Waterland free(ps->link); 2995c51f124SMoriah Waterland ps->link = NULL; 3005c51f124SMoriah Waterland } 3015c51f124SMoriah Waterland if (ps->dwnld_dir) { 3025c51f124SMoriah Waterland (void) rmdir(ps->dwnld_dir); 3035c51f124SMoriah Waterland ps->dwnld_dir = NULL; 3045c51f124SMoriah Waterland } 3055c51f124SMoriah Waterland if (ps->errstr) { 3065c51f124SMoriah Waterland free(ps->errstr); 3075c51f124SMoriah Waterland ps->errstr = NULL; 3085c51f124SMoriah Waterland } 3095c51f124SMoriah Waterland 3105c51f124SMoriah Waterland if (ps->content) { 3115c51f124SMoriah Waterland free(ps->content); 3125c51f124SMoriah Waterland ps->content = NULL; 3135c51f124SMoriah Waterland } 3145c51f124SMoriah Waterland 3155c51f124SMoriah Waterland if (ps->resp) { 3165c51f124SMoriah Waterland http_free_respinfo(ps->resp); 3175c51f124SMoriah Waterland ps->resp = NULL; 3185c51f124SMoriah Waterland } 3195c51f124SMoriah Waterland 3205c51f124SMoriah Waterland if (ps) { 3215c51f124SMoriah Waterland free(ps); 3225c51f124SMoriah Waterland ps = NULL; 3235c51f124SMoriah Waterland } 3245c51f124SMoriah Waterland } 3255c51f124SMoriah Waterland 3265c51f124SMoriah Waterland /* 3275c51f124SMoriah Waterland * Name: web_session_control 3285c51f124SMoriah Waterland * Description: Downloads an arbitrary URL and saves to disk. 3295c51f124SMoriah Waterland * 3305c51f124SMoriah Waterland * Arguments: err - where to record any errors. 3315c51f124SMoriah Waterland * url - URL pointing to content to download - can be 3325c51f124SMoriah Waterland * http:// or https:// 3335c51f124SMoriah Waterland * dwnld_dir - Directory to download into 3345c51f124SMoriah Waterland * keystore - keystore to use for accessing trusted 3355c51f124SMoriah Waterland * certs when downloading using SSL 3365c51f124SMoriah Waterland * proxy - HTTP proxy to use, or NULL for no proxy 3375c51f124SMoriah Waterland * proxy_port - HTTP proxy port to use, ignored 3385c51f124SMoriah Waterland * if proxy is NULL 3395c51f124SMoriah Waterland * passarg - method to retrieve password 3405c51f124SMoriah Waterland * retries - # of times to retry download before 3415c51f124SMoriah Waterland * giving up 3425c51f124SMoriah Waterland * timeout - how long to wait before retrying, 3435c51f124SMoriah Waterland * when download is interrupted 3445c51f124SMoriah Waterland * nointeract - if non-zero, do not output 3455c51f124SMoriah Waterland * download progress to screen 3465c51f124SMoriah Waterland * 3475c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 3485c51f124SMoriah Waterland */ 3495c51f124SMoriah Waterland boolean_t 3505c51f124SMoriah Waterland web_session_control(PKG_ERR *err, char *url, char *dwnld_dir, 3515c51f124SMoriah Waterland keystore_handle_t keystore, char *proxy, ushort_t proxy_port, 3525c51f124SMoriah Waterland int retries, int timeout, int nointeract, char **fname) 3535c51f124SMoriah Waterland { 3545c51f124SMoriah Waterland int i; 3555c51f124SMoriah Waterland boolean_t ret = B_TRUE; 3565c51f124SMoriah Waterland boolean_t retrieved = B_FALSE; 3575c51f124SMoriah Waterland 3585c51f124SMoriah Waterland if (!init_session()) { 3595c51f124SMoriah Waterland ret = B_FALSE; 3605c51f124SMoriah Waterland goto cleanup; 3615c51f124SMoriah Waterland } 3625c51f124SMoriah Waterland 3635c51f124SMoriah Waterland if (!parse_url_proxy(err, url, proxy, proxy_port)) { 3645c51f124SMoriah Waterland ret = B_FALSE; 3655c51f124SMoriah Waterland goto cleanup; 3665c51f124SMoriah Waterland } 3675c51f124SMoriah Waterland 3685c51f124SMoriah Waterland ps->timeout = timeout; 3695c51f124SMoriah Waterland 3705c51f124SMoriah Waterland if (keystore != NULL) 3715c51f124SMoriah Waterland ps->keystore = keystore; 3725c51f124SMoriah Waterland 3735c51f124SMoriah Waterland if (dwnld_dir != NULL) 3745c51f124SMoriah Waterland ps->dwnld_dir = xstrdup(dwnld_dir); 3755c51f124SMoriah Waterland else { 3765c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_NO_DWNLD_DIR)); 3775c51f124SMoriah Waterland ret = B_FALSE; 3785c51f124SMoriah Waterland goto cleanup; 3795c51f124SMoriah Waterland } 3805c51f124SMoriah Waterland 3815c51f124SMoriah Waterland if (!check_dwnld_dir(err, dwnld_dir)) { 3825c51f124SMoriah Waterland ret = B_FALSE; 3835c51f124SMoriah Waterland goto cleanup; 3845c51f124SMoriah Waterland } 3855c51f124SMoriah Waterland 3865c51f124SMoriah Waterland for (i = 0; i < retries && !retrieved; i++) { 3875c51f124SMoriah Waterland if (!web_setup(err)) { 3885c51f124SMoriah Waterland ret = B_FALSE; 3895c51f124SMoriah Waterland goto cleanup; 3905c51f124SMoriah Waterland } 3915c51f124SMoriah Waterland 3925c51f124SMoriah Waterland switch (web_connect(err)) { 3935c51f124SMoriah Waterland /* time out and wait a little bit for these failures */ 3945c51f124SMoriah Waterland case WEB_OK: 3955c51f124SMoriah Waterland /* were able to connect */ 3965c51f124SMoriah Waterland reset_backoff(); 3975c51f124SMoriah Waterland break; 3985c51f124SMoriah Waterland case WEB_TIMEOUT: 3995c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_TIMEOUT)); 4005c51f124SMoriah Waterland (void) web_disconnect(); 4015c51f124SMoriah Waterland backoff(); 4025c51f124SMoriah Waterland continue; 4035c51f124SMoriah Waterland 4045c51f124SMoriah Waterland case WEB_CONNREFUSED: 4055c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_CONNREF), 4065c51f124SMoriah Waterland ps->url.hport.hostname); 4075c51f124SMoriah Waterland (void) web_disconnect(); 4085c51f124SMoriah Waterland backoff(); 4095c51f124SMoriah Waterland continue; 4105c51f124SMoriah Waterland case WEB_HOSTDOWN: 4115c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_HOSTDWN), 4125c51f124SMoriah Waterland ps->url.hport.hostname); 4135c51f124SMoriah Waterland (void) web_disconnect(); 4145c51f124SMoriah Waterland backoff(); 4155c51f124SMoriah Waterland continue; 4165c51f124SMoriah Waterland 4175c51f124SMoriah Waterland default: 4185c51f124SMoriah Waterland /* every other failure is a hard failure, so bail */ 4195c51f124SMoriah Waterland ret = B_FALSE; 4205c51f124SMoriah Waterland goto cleanup; 4215c51f124SMoriah Waterland } 4225c51f124SMoriah Waterland 4235c51f124SMoriah Waterland switch (web_send_request(err, HTTP_REQ_TYPE_HEAD, 4245c51f124SMoriah Waterland ps->data.cur_pos, ps->data.content_length)) { 4255c51f124SMoriah Waterland case WEB_OK: 4265c51f124SMoriah Waterland /* were able to connect */ 4275c51f124SMoriah Waterland reset_backoff(); 4285c51f124SMoriah Waterland break; 4295c51f124SMoriah Waterland case WEB_TIMEOUT: 4305c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_TIMEOUT)); 4315c51f124SMoriah Waterland (void) web_disconnect(); 4325c51f124SMoriah Waterland backoff(); 4335c51f124SMoriah Waterland continue; 4345c51f124SMoriah Waterland 4355c51f124SMoriah Waterland case WEB_CONNREFUSED: 4365c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_CONNREF), 4375c51f124SMoriah Waterland ps->url.hport.hostname); 4385c51f124SMoriah Waterland (void) web_disconnect(); 4395c51f124SMoriah Waterland backoff(); 4405c51f124SMoriah Waterland continue; 4415c51f124SMoriah Waterland case WEB_HOSTDOWN: 4425c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_HOSTDWN), 4435c51f124SMoriah Waterland ps->url.hport.hostname); 4445c51f124SMoriah Waterland (void) web_disconnect(); 4455c51f124SMoriah Waterland backoff(); 4465c51f124SMoriah Waterland continue; 4475c51f124SMoriah Waterland default: 4485c51f124SMoriah Waterland /* every other case is failure, so bail */ 4495c51f124SMoriah Waterland ret = B_FALSE; 4505c51f124SMoriah Waterland goto cleanup; 4515c51f124SMoriah Waterland } 4525c51f124SMoriah Waterland 4535c51f124SMoriah Waterland if (!web_eval_headers(err)) { 4545c51f124SMoriah Waterland ret = B_FALSE; 4555c51f124SMoriah Waterland goto cleanup; 4565c51f124SMoriah Waterland } 4575c51f124SMoriah Waterland 4585c51f124SMoriah Waterland switch (web_get_file(err, dwnld_dir, nointeract, fname)) { 4595c51f124SMoriah Waterland case WEB_OK: 4605c51f124SMoriah Waterland /* were able to retrieve file */ 4615c51f124SMoriah Waterland retrieved = B_TRUE; 4625c51f124SMoriah Waterland reset_backoff(); 4635c51f124SMoriah Waterland break; 4645c51f124SMoriah Waterland 4655c51f124SMoriah Waterland case WEB_TIMEOUT: 4665c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_TIMEOUT)); 4675c51f124SMoriah Waterland (void) web_disconnect(); 4685c51f124SMoriah Waterland backoff(); 4695c51f124SMoriah Waterland continue; 4705c51f124SMoriah Waterland 4715c51f124SMoriah Waterland case WEB_CONNREFUSED: 4725c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_CONNREF), 4735c51f124SMoriah Waterland ps->url.hport.hostname); 4745c51f124SMoriah Waterland (void) web_disconnect(); 4755c51f124SMoriah Waterland backoff(); 4765c51f124SMoriah Waterland continue; 4775c51f124SMoriah Waterland case WEB_HOSTDOWN: 4785c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_HOSTDWN), 4795c51f124SMoriah Waterland ps->url.hport.hostname); 4805c51f124SMoriah Waterland (void) web_disconnect(); 4815c51f124SMoriah Waterland backoff(); 4825c51f124SMoriah Waterland continue; 4835c51f124SMoriah Waterland default: 4845c51f124SMoriah Waterland /* every other failure is a hard failure, so bail */ 4855c51f124SMoriah Waterland ret = B_FALSE; 4865c51f124SMoriah Waterland goto cleanup; 4875c51f124SMoriah Waterland } 4885c51f124SMoriah Waterland } 4895c51f124SMoriah Waterland 4905c51f124SMoriah Waterland if (!retrieved) { 4915c51f124SMoriah Waterland /* max retries attempted */ 4925c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 4935c51f124SMoriah Waterland gettext(ERR_DWNLD_FAILED), retries); 4945c51f124SMoriah Waterland ret = B_FALSE; 4955c51f124SMoriah Waterland } 4965c51f124SMoriah Waterland cleanup: 4975c51f124SMoriah Waterland (void) web_disconnect(); 4985c51f124SMoriah Waterland if (!ret) { 4995c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_DWNLD), url); 5005c51f124SMoriah Waterland } 5015c51f124SMoriah Waterland return (ret); 5025c51f124SMoriah Waterland } 5035c51f124SMoriah Waterland 5045c51f124SMoriah Waterland /* 5055c51f124SMoriah Waterland * Name: get_signature 5065c51f124SMoriah Waterland * Description: retrieves signature from signed package. 5075c51f124SMoriah Waterland * 5085c51f124SMoriah Waterland * Arguments: err - where to record any errors. 5095c51f124SMoriah Waterland * ids_name - name of package stream, for error reporting 5105c51f124SMoriah Waterland * devp - Device on which package resides that we 5115c51f124SMoriah Waterland * result - where to store resulting PKCS7 signature 5125c51f124SMoriah Waterland * 5135c51f124SMoriah Waterland * Returns : B_TRUE - package is signed and signature returned OR 5145c51f124SMoriah Waterland * package is not signed, in which case result is NULL 5155c51f124SMoriah Waterland * 5165c51f124SMoriah Waterland * B_FALSE - there were problems accessing signature, 5175c51f124SMoriah Waterland * and it is unknown whether it is signed or not. Errors 5185c51f124SMoriah Waterland * recorded in 'err'. 5195c51f124SMoriah Waterland */ 5205c51f124SMoriah Waterland boolean_t 5215c51f124SMoriah Waterland get_signature(PKG_ERR *err, char *ids_name, struct pkgdev *devp, PKCS7 **result) 5225c51f124SMoriah Waterland { 5235c51f124SMoriah Waterland char path[PATH_MAX]; 5245c51f124SMoriah Waterland int len, fd = -1; 5255c51f124SMoriah Waterland struct stat buf; 5265c51f124SMoriah Waterland FILE *fp = NULL; 5275c51f124SMoriah Waterland boolean_t ret = B_TRUE; 5285c51f124SMoriah Waterland BIO *sig_in = NULL; 5295c51f124SMoriah Waterland PKCS7 *p7 = NULL; 5305c51f124SMoriah Waterland 5315c51f124SMoriah Waterland /* 5325c51f124SMoriah Waterland * look for signature. If one was in the stream, 5335c51f124SMoriah Waterland * it is now extracted 5345c51f124SMoriah Waterland */ 5355c51f124SMoriah Waterland if (((len = snprintf(path, PATH_MAX, "%s/%s", devp->dirname, 5365c51f124SMoriah Waterland SIGNATURE_FILENAME)) >= PATH_MAX) || (len < 0)) { 5375c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), ids_name); 5385c51f124SMoriah Waterland ret = B_FALSE; 5395c51f124SMoriah Waterland goto cleanup; 5405c51f124SMoriah Waterland } 5415c51f124SMoriah Waterland 5425c51f124SMoriah Waterland if ((fd = open(path, O_RDONLY|O_NONBLOCK)) == -1) { 5435c51f124SMoriah Waterland /* 5445c51f124SMoriah Waterland * only if the signature is non-existant 5455c51f124SMoriah Waterland * do we "pass" 5465c51f124SMoriah Waterland */ 5475c51f124SMoriah Waterland if (errno != ENOENT) { 5485c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_OPENSIG), 5495c51f124SMoriah Waterland strerror(errno)); 5505c51f124SMoriah Waterland ret = B_FALSE; 5515c51f124SMoriah Waterland goto cleanup; 5525c51f124SMoriah Waterland } 5535c51f124SMoriah Waterland } else { 5545c51f124SMoriah Waterland /* found sig file. parse it. */ 5555c51f124SMoriah Waterland if (fstat(fd, &buf) == -1) { 5565c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 5575c51f124SMoriah Waterland gettext(ERR_OPENSIG), strerror(errno)); 5585c51f124SMoriah Waterland ret = B_FALSE; 5595c51f124SMoriah Waterland goto cleanup; 5605c51f124SMoriah Waterland } 5615c51f124SMoriah Waterland 5625c51f124SMoriah Waterland if (!S_ISREG(buf.st_mode)) { 5635c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_OPENSIG), 5645c51f124SMoriah Waterland (gettext(ERR_NOT_REG))); 5655c51f124SMoriah Waterland ret = B_FALSE; 5665c51f124SMoriah Waterland goto cleanup; 5675c51f124SMoriah Waterland } 5685c51f124SMoriah Waterland 5695c51f124SMoriah Waterland if ((fp = fdopen(fd, "r")) == NULL) { 5705c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 5715c51f124SMoriah Waterland gettext(ERR_OPENSIG), strerror(errno)); 5725c51f124SMoriah Waterland ret = B_FALSE; 5735c51f124SMoriah Waterland goto cleanup; 5745c51f124SMoriah Waterland } 5755c51f124SMoriah Waterland 5765c51f124SMoriah Waterland /* 5775c51f124SMoriah Waterland * read in signature. If it's invalid, we 5785c51f124SMoriah Waterland * punt, unless we're ignoring it 5795c51f124SMoriah Waterland */ 5805c51f124SMoriah Waterland if ((sig_in = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) { 5815c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 5825c51f124SMoriah Waterland gettext(ERR_OPENSIG), strerror(errno)); 5835c51f124SMoriah Waterland goto cleanup; 5845c51f124SMoriah Waterland } 5855c51f124SMoriah Waterland 5865c51f124SMoriah Waterland if ((p7 = PEM_read_bio_PKCS7(sig_in, 5875c51f124SMoriah Waterland NULL, NULL, NULL)) == NULL) { 5885c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG), 5895c51f124SMoriah Waterland ids_name); 5905c51f124SMoriah Waterland ret = B_FALSE; 5915c51f124SMoriah Waterland goto cleanup; 5925c51f124SMoriah Waterland } 5935c51f124SMoriah Waterland *result = p7; 5945c51f124SMoriah Waterland p7 = NULL; 5955c51f124SMoriah Waterland } 5965c51f124SMoriah Waterland 5975c51f124SMoriah Waterland cleanup: 5985c51f124SMoriah Waterland if (sig_in) 5995c51f124SMoriah Waterland (void) BIO_free(sig_in); 6005c51f124SMoriah Waterland if (fp) 6015c51f124SMoriah Waterland (void) fclose(fp); 6025c51f124SMoriah Waterland if (fd != -1) 6035c51f124SMoriah Waterland (void) close(fd); 6045c51f124SMoriah Waterland if (p7) 6055c51f124SMoriah Waterland (void) PKCS7_free(p7); 6065c51f124SMoriah Waterland 6075c51f124SMoriah Waterland return (ret); 6085c51f124SMoriah Waterland } 6095c51f124SMoriah Waterland 6105c51f124SMoriah Waterland /* 6115c51f124SMoriah Waterland * Name: echo_out 6125c51f124SMoriah Waterland * Description: Conditionally output a message to stdout 6135c51f124SMoriah Waterland * 6145c51f124SMoriah Waterland * Arguments: nointeract - if non-zero, do not output anything 6155c51f124SMoriah Waterland * fmt - print format 6165c51f124SMoriah Waterland * ... - print arguments 6175c51f124SMoriah Waterland * 6185c51f124SMoriah Waterland * Returns : none 6195c51f124SMoriah Waterland */ 620*4656d474SGarrett D'Amore /*PRINTFLIKE2*/ 6215c51f124SMoriah Waterland void 6225c51f124SMoriah Waterland echo_out(int nointeract, char *fmt, ...) 6235c51f124SMoriah Waterland { 6245c51f124SMoriah Waterland va_list ap; 6255c51f124SMoriah Waterland 6265c51f124SMoriah Waterland va_start(ap, fmt); 6275c51f124SMoriah Waterland 6285c51f124SMoriah Waterland if (nointeract) 6295c51f124SMoriah Waterland return; 6305c51f124SMoriah Waterland 6315c51f124SMoriah Waterland (void) vfprintf(stdout, fmt, ap); 6325c51f124SMoriah Waterland 6335c51f124SMoriah Waterland va_end(ap); 6345c51f124SMoriah Waterland 6355c51f124SMoriah Waterland (void) putc('\n', stdout); 6365c51f124SMoriah Waterland } 6375c51f124SMoriah Waterland 6385c51f124SMoriah Waterland /* 6395c51f124SMoriah Waterland * Name: strip_port 6405c51f124SMoriah Waterland * Description: Returns "port" portion of a "hostname:port" string 6415c51f124SMoriah Waterland * 6425c51f124SMoriah Waterland * Arguments: proxy - full "hostname:port" string pointer 6435c51f124SMoriah Waterland * 6445c51f124SMoriah Waterland * Returns : the "port" portion of a "hostname:port" string, 6455c51f124SMoriah Waterland * converted to a decimal integer, or (int)0 6465c51f124SMoriah Waterland * if string contains no :port suffix. 6475c51f124SMoriah Waterland */ 6485c51f124SMoriah Waterland ushort_t 6495c51f124SMoriah Waterland strip_port(char *proxy) 6505c51f124SMoriah Waterland { 6515c51f124SMoriah Waterland char *tmp_port; 6525c51f124SMoriah Waterland 6535c51f124SMoriah Waterland if ((tmp_port = strpbrk(proxy, ":")) != NULL) 6545c51f124SMoriah Waterland return (atoi(tmp_port)); 6555c51f124SMoriah Waterland else 6565c51f124SMoriah Waterland return (0); 6575c51f124SMoriah Waterland } 6585c51f124SMoriah Waterland 6595c51f124SMoriah Waterland /* 6605c51f124SMoriah Waterland * Name: set_web_install 6615c51f124SMoriah Waterland * Description: Sets flag indicating we are doing a web-based install 6625c51f124SMoriah Waterland * 6635c51f124SMoriah Waterland * Arguments: none 6645c51f124SMoriah Waterland * 6655c51f124SMoriah Waterland * Returns : none 6665c51f124SMoriah Waterland */ 6675c51f124SMoriah Waterland void 6685c51f124SMoriah Waterland set_web_install(void) 6695c51f124SMoriah Waterland { 6705c51f124SMoriah Waterland webpkg_install++; 6715c51f124SMoriah Waterland } 6725c51f124SMoriah Waterland 6735c51f124SMoriah Waterland /* 6745c51f124SMoriah Waterland * Name: is_web_install 6755c51f124SMoriah Waterland * Description: Determines whether we are doing a web-based install 6765c51f124SMoriah Waterland * 6775c51f124SMoriah Waterland * Arguments: none 6785c51f124SMoriah Waterland * 6795c51f124SMoriah Waterland * Returns : non-zero if we are doing a web-based install, 0 otherwise 6805c51f124SMoriah Waterland */ 6815c51f124SMoriah Waterland int 6825c51f124SMoriah Waterland is_web_install(void) 6835c51f124SMoriah Waterland { 6845c51f124SMoriah Waterland return (webpkg_install); 6855c51f124SMoriah Waterland } 6865c51f124SMoriah Waterland 6875c51f124SMoriah Waterland /* ~~~~~~~~~~~~~~ Private Functions ~~~~~~~~~~~~~~~~~~~ */ 6885c51f124SMoriah Waterland 6895c51f124SMoriah Waterland /* 6905c51f124SMoriah Waterland * Name: web_disconnect 6915c51f124SMoriah Waterland * Description: Disconnects connection to web server 6925c51f124SMoriah Waterland * 6935c51f124SMoriah Waterland * Arguments: none 6945c51f124SMoriah Waterland * 6955c51f124SMoriah Waterland * Returns : B_TRUE - successful disconnect, B_FALSE otherwise 6965c51f124SMoriah Waterland * Temp certificiate files are deleted, 6975c51f124SMoriah Waterland * if one was used to initiate the connection 6985c51f124SMoriah Waterland * (such as when using SSL) 6995c51f124SMoriah Waterland */ 7005c51f124SMoriah Waterland static boolean_t 7015c51f124SMoriah Waterland web_disconnect(void) 7025c51f124SMoriah Waterland { 7035c51f124SMoriah Waterland if (ps->certfile) { 7045c51f124SMoriah Waterland (void) unlink(ps->certfile); 7055c51f124SMoriah Waterland } 7065c51f124SMoriah Waterland if (http_srv_disconnect(ps->hps) == 0) 7075c51f124SMoriah Waterland if (http_srv_close(ps->hps) == 0) 7085c51f124SMoriah Waterland return (B_TRUE); 7095c51f124SMoriah Waterland 7105c51f124SMoriah Waterland return (B_FALSE); 7115c51f124SMoriah Waterland } 7125c51f124SMoriah Waterland 7135c51f124SMoriah Waterland /* 7145c51f124SMoriah Waterland * Name: check_dwnld_dir 7155c51f124SMoriah Waterland * Description: Creates temp download directory 7165c51f124SMoriah Waterland * 7175c51f124SMoriah Waterland * Arguments: err - where to record any errors. 7185c51f124SMoriah Waterland * dwnld_dir - name of directory to create 7195c51f124SMoriah Waterland * 7205c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 7215c51f124SMoriah Waterland * on success, directory is created with 7225c51f124SMoriah Waterland * safe permissions 7235c51f124SMoriah Waterland */ 7245c51f124SMoriah Waterland static boolean_t 7255c51f124SMoriah Waterland check_dwnld_dir(PKG_ERR *err, char *dwnld_dir) 7265c51f124SMoriah Waterland { 7275c51f124SMoriah Waterland DIR *dirp; 7285c51f124SMoriah Waterland 7295c51f124SMoriah Waterland /* 7305c51f124SMoriah Waterland * Check the directory passed in. If it doesn't exist, create it 7315c51f124SMoriah Waterland * with strict permissions 7325c51f124SMoriah Waterland */ 7335c51f124SMoriah Waterland if ((dirp = opendir(dwnld_dir)) == NULL) { 7345c51f124SMoriah Waterland if (mkdir(dwnld_dir, 0744) == -1) { 7355c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), 7365c51f124SMoriah Waterland dwnld_dir); 7375c51f124SMoriah Waterland return (B_FALSE); 7385c51f124SMoriah Waterland } 7395c51f124SMoriah Waterland } 7405c51f124SMoriah Waterland if (dirp) { 7415c51f124SMoriah Waterland (void) closedir(dirp); 7425c51f124SMoriah Waterland } 7435c51f124SMoriah Waterland return (B_TRUE); 7445c51f124SMoriah Waterland } 7455c51f124SMoriah Waterland 7465c51f124SMoriah Waterland /* 7475c51f124SMoriah Waterland * Name: ds_validate_signature 7485c51f124SMoriah Waterland * Description: Validates signature found in a package datastream 7495c51f124SMoriah Waterland * 7505c51f124SMoriah Waterland * Arguments: err - where to record any errors. 7515c51f124SMoriah Waterland * pkgdev - Package context handle of package to verify 7525c51f124SMoriah Waterland * pkgs - Null-terminated List of package name to verify 7535c51f124SMoriah Waterland * ids_name - Pathname to stream to validate 7545c51f124SMoriah Waterland * p7 - PKCS7 signature decoded from stream header 7555c51f124SMoriah Waterland * cas - List of trusted CA certificates 7565c51f124SMoriah Waterland * proxy - Proxy to use when doing online validation (OCSP) 7575c51f124SMoriah Waterland * nointeract - if non-zero, do not output to screen 7585c51f124SMoriah Waterland * 7595c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 7605c51f124SMoriah Waterland * success means signature was completely validated, 7615c51f124SMoriah Waterland * and contents of stream checked against signature. 7625c51f124SMoriah Waterland */ 7635c51f124SMoriah Waterland boolean_t 7645c51f124SMoriah Waterland ds_validate_signature(PKG_ERR *err, struct pkgdev *pkgdev, char **pkgs, 7655c51f124SMoriah Waterland char *ids_name, PKCS7 *p7, STACK_OF(X509) *cas, 7665c51f124SMoriah Waterland url_hport_t *proxy, int nointeract) 7675c51f124SMoriah Waterland { 7685c51f124SMoriah Waterland BIO *p7_bio; 7695c51f124SMoriah Waterland boolean_t ret = B_TRUE; 7705c51f124SMoriah Waterland 7715c51f124SMoriah Waterland /* make sure it's a Signed PKCS7 message */ 7725c51f124SMoriah Waterland if (!PKCS7_type_is_signed(p7)) { 7735c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG_TYPE), 7745c51f124SMoriah Waterland ids_name); 7755c51f124SMoriah Waterland ret = B_FALSE; 7765c51f124SMoriah Waterland goto cleanup; 7775c51f124SMoriah Waterland } 7785c51f124SMoriah Waterland 7795c51f124SMoriah Waterland /* initialize PKCS7 object to be filled in */ 7805c51f124SMoriah Waterland if (!PKCS7_get_detached(p7)) { 7815c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG_DT), 7825c51f124SMoriah Waterland ids_name); 7835c51f124SMoriah Waterland ret = B_FALSE; 7845c51f124SMoriah Waterland goto cleanup; 7855c51f124SMoriah Waterland } 7865c51f124SMoriah Waterland 7875c51f124SMoriah Waterland /* dump header and packages into BIO to calculate the message digest */ 7885c51f124SMoriah Waterland if ((p7_bio = PKCS7_dataInit(p7, NULL)) == NULL) { 7895c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG), 7905c51f124SMoriah Waterland ids_name); 7915c51f124SMoriah Waterland ret = B_FALSE; 7925c51f124SMoriah Waterland goto cleanup; 7935c51f124SMoriah Waterland } 7945c51f124SMoriah Waterland 7955c51f124SMoriah Waterland if ((BIO_ds_dump_header(err, p7_bio) != 0) || 7965c51f124SMoriah Waterland (BIO_ds_dump(err, ids_name, p7_bio) != 0)) { 7975c51f124SMoriah Waterland ret = B_FALSE; 7985c51f124SMoriah Waterland goto cleanup; 7995c51f124SMoriah Waterland } 8005c51f124SMoriah Waterland (void) BIO_flush(p7_bio); 8015c51f124SMoriah Waterland 8025c51f124SMoriah Waterland /* validate the stream and its signature */ 8035c51f124SMoriah Waterland if (!validate_signature(err, ids_name, p7_bio, p7, cas, 8045c51f124SMoriah Waterland proxy, nointeract)) { 8055c51f124SMoriah Waterland ret = B_FALSE; 8065c51f124SMoriah Waterland goto cleanup; 8075c51f124SMoriah Waterland } 8085c51f124SMoriah Waterland 8095c51f124SMoriah Waterland /* reset device stream (really bad performance for tapes) */ 8105c51f124SMoriah Waterland (void) ds_close(1); 8115c51f124SMoriah Waterland (void) ds_init(ids_name, pkgs, pkgdev->norewind); 8125c51f124SMoriah Waterland 8135c51f124SMoriah Waterland cleanup: 8145c51f124SMoriah Waterland return (ret); 8155c51f124SMoriah Waterland } 8165c51f124SMoriah Waterland 8175c51f124SMoriah Waterland 8185c51f124SMoriah Waterland /* 8195c51f124SMoriah Waterland * Name: validate_signature 8205c51f124SMoriah Waterland * Description: Validates signature of an arbitrary stream of bits 8215c51f124SMoriah Waterland * 8225c51f124SMoriah Waterland * Arguments: err - where to record any errors. 8235c51f124SMoriah Waterland * name - Descriptive name of object being validated, 8245c51f124SMoriah Waterland * for good error reporting messages 8255c51f124SMoriah Waterland * indata - BIO object to read stream bits from 8265c51f124SMoriah Waterland * p7 - PKCS7 signature of stream 8275c51f124SMoriah Waterland * cas - List of trusted CA certificates 8285c51f124SMoriah Waterland * proxy - Proxy to use when doing online validation (OCSP) 8295c51f124SMoriah Waterland * nointeract - if non-zero, do not output to screen 8305c51f124SMoriah Waterland * 8315c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 8325c51f124SMoriah Waterland * success means signature was completely validated, 8335c51f124SMoriah Waterland * and contents of stream checked against signature. 8345c51f124SMoriah Waterland */ 8355c51f124SMoriah Waterland boolean_t 8365c51f124SMoriah Waterland validate_signature(PKG_ERR *err, char *name, BIO *indata, PKCS7 *p7, 8375c51f124SMoriah Waterland STACK_OF(X509) *cas, url_hport_t *proxy, int nointeract) 8385c51f124SMoriah Waterland { 8395c51f124SMoriah Waterland STACK_OF(PKCS7_SIGNER_INFO) *sec_sinfos = NULL; 8405c51f124SMoriah Waterland 8415c51f124SMoriah Waterland PKCS7_SIGNER_INFO *signer = NULL; 8425c51f124SMoriah Waterland X509_STORE *sec_truststore = NULL; 8435c51f124SMoriah Waterland X509_STORE_CTX *ctx = NULL; 8445c51f124SMoriah Waterland X509 *signer_cert = NULL, *issuer = NULL; 8455c51f124SMoriah Waterland STACK_OF(X509) *chaincerts = NULL; 8465c51f124SMoriah Waterland int i, k; 8475c51f124SMoriah Waterland unsigned long errcode; 8485c51f124SMoriah Waterland const char *err_data = NULL; 8495c51f124SMoriah Waterland const char *err_reason = NULL; 8505c51f124SMoriah Waterland char *err_string; 8515c51f124SMoriah Waterland int err_flags; 8525c51f124SMoriah Waterland verify_cb_data_t verify_data; 8535c51f124SMoriah Waterland char *signer_sname; 8545c51f124SMoriah Waterland char *signer_iname; 8555c51f124SMoriah Waterland PKCS7_ISSUER_AND_SERIAL *ias; 8565c51f124SMoriah Waterland boolean_t ret = B_TRUE; 8575c51f124SMoriah Waterland 8585c51f124SMoriah Waterland /* only support signed PKCS7 signatures */ 8595c51f124SMoriah Waterland if (!PKCS7_type_is_signed(p7)) { 8605c51f124SMoriah Waterland PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_WRONG_PKCS7_TYPE); 8615c51f124SMoriah Waterland ret = B_FALSE; 8625c51f124SMoriah Waterland goto cleanup; 8635c51f124SMoriah Waterland } 8645c51f124SMoriah Waterland 8655c51f124SMoriah Waterland /* initialize temporary internal trust store used for verification */ 8665c51f124SMoriah Waterland sec_truststore = X509_STORE_new(); 8675c51f124SMoriah Waterland 8685c51f124SMoriah Waterland for (i = 0; i < sk_X509_num(cas); i++) { 8695c51f124SMoriah Waterland if (X509_STORE_add_cert(sec_truststore, 8705c51f124SMoriah Waterland sk_X509_value(cas, i)) == 0) { 8715c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, gettext(ERR_MEM)); 8725c51f124SMoriah Waterland ret = B_FALSE; 8735c51f124SMoriah Waterland goto cleanup; 8745c51f124SMoriah Waterland } 8755c51f124SMoriah Waterland } 8765c51f124SMoriah Waterland 8775c51f124SMoriah Waterland /* get signers from the signature */ 8785c51f124SMoriah Waterland if ((sec_sinfos = PKCS7_get_signer_info(p7)) == NULL) { 8795c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG), name); 8805c51f124SMoriah Waterland ret = B_FALSE; 8815c51f124SMoriah Waterland goto cleanup; 8825c51f124SMoriah Waterland } 8835c51f124SMoriah Waterland 8845c51f124SMoriah Waterland /* verify each signer found in the PKCS7 signature */ 8855c51f124SMoriah Waterland for (k = 0; k < sk_PKCS7_SIGNER_INFO_num(sec_sinfos); k++) { 8865c51f124SMoriah Waterland signer = sk_PKCS7_SIGNER_INFO_value(sec_sinfos, k); 8875c51f124SMoriah Waterland signer_cert = PKCS7_cert_from_signer_info(p7, signer); 8885c51f124SMoriah Waterland signer_sname = get_subject_display_name(signer_cert); 8895c51f124SMoriah Waterland signer_iname = get_issuer_display_name(signer_cert); 8905c51f124SMoriah Waterland 8915c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_VERIFY), signer_sname); 8925c51f124SMoriah Waterland 8935c51f124SMoriah Waterland /* find the issuer of the current cert */ 8945c51f124SMoriah Waterland chaincerts = p7->d.sign->cert; 8955c51f124SMoriah Waterland ias = signer->issuer_and_serial; 8965c51f124SMoriah Waterland issuer = X509_find_by_issuer_and_serial(chaincerts, 8975c51f124SMoriah Waterland ias->issuer, ias->serial); 8985c51f124SMoriah Waterland 8995c51f124SMoriah Waterland /* were we not able to find the issuer cert */ 9005c51f124SMoriah Waterland if (issuer == NULL) { 9015c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 9025c51f124SMoriah Waterland gettext(ERR_VERIFY_ISSUER), 9035c51f124SMoriah Waterland signer_iname, signer_sname); 9045c51f124SMoriah Waterland ret = B_FALSE; 9055c51f124SMoriah Waterland goto cleanup; 9065c51f124SMoriah Waterland } 9075c51f124SMoriah Waterland 9085c51f124SMoriah Waterland /* Lets verify */ 9095c51f124SMoriah Waterland if ((ctx = X509_STORE_CTX_new()) == NULL) { 9105c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, gettext(ERR_MEM)); 9115c51f124SMoriah Waterland ret = B_FALSE; 9125c51f124SMoriah Waterland goto cleanup; 9135c51f124SMoriah Waterland } 9145c51f124SMoriah Waterland (void) X509_STORE_CTX_init(ctx, sec_truststore, 9155c51f124SMoriah Waterland issuer, chaincerts); 9165c51f124SMoriah Waterland (void) X509_STORE_CTX_set_purpose(ctx, 9175c51f124SMoriah Waterland X509_PURPOSE_ANY); 9185c51f124SMoriah Waterland 9195c51f124SMoriah Waterland /* callback will perform OCSP on certificates with OCSP data */ 9205c51f124SMoriah Waterland X509_STORE_CTX_set_verify_cb(ctx, web_verify); 9215c51f124SMoriah Waterland 9225c51f124SMoriah Waterland /* pass needed data into callback through the app_data handle */ 9235c51f124SMoriah Waterland verify_data.proxy = proxy; 9245c51f124SMoriah Waterland verify_data.cas = cas; 9255c51f124SMoriah Waterland verify_data.err = err; 9265c51f124SMoriah Waterland (void) X509_STORE_CTX_set_app_data(ctx, &verify_data); 9275c51f124SMoriah Waterland 9285c51f124SMoriah Waterland /* first verify the certificate chain */ 9295c51f124SMoriah Waterland i = X509_verify_cert(ctx); 9305c51f124SMoriah Waterland if (i <= 0 && ctx->error != X509_V_ERR_CERT_HAS_EXPIRED) { 9315c51f124SMoriah Waterland signer_sname = 9325c51f124SMoriah Waterland get_subject_display_name(ctx->current_cert); 9335c51f124SMoriah Waterland signer_iname = 9345c51f124SMoriah Waterland get_issuer_display_name(ctx->current_cert); 9355c51f124SMoriah Waterland /* if the verify context holds an error, print it */ 9365c51f124SMoriah Waterland if (ctx->error != X509_V_OK) { 9375c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, 9385c51f124SMoriah Waterland gettext(ERR_VERIFY_SIG), signer_sname, 9395c51f124SMoriah Waterland signer_iname, 9405c51f124SMoriah Waterland (char *)X509_verify_cert_error_string(ctx->error)); 9415c51f124SMoriah Waterland } else { 9425c51f124SMoriah Waterland /* some other error. print them all. */ 9435c51f124SMoriah Waterland while ((errcode = ERR_get_error_line_data(NULL, 9445c51f124SMoriah Waterland NULL, &err_data, &err_flags)) != 0) { 945*4656d474SGarrett D'Amore size_t errsz; 9465c51f124SMoriah Waterland err_reason = 9475c51f124SMoriah Waterland ERR_reason_error_string(errcode); 9485c51f124SMoriah Waterland if (err_reason == NULL) { 9495c51f124SMoriah Waterland err_reason = 9505c51f124SMoriah Waterland gettext(ERR_SIG_INT); 9515c51f124SMoriah Waterland } 9525c51f124SMoriah Waterland 9535c51f124SMoriah Waterland if (!(err_flags & ERR_TXT_STRING)) { 9545c51f124SMoriah Waterland err_data = 9555c51f124SMoriah Waterland gettext(ERR_SIG_INT); 9565c51f124SMoriah Waterland } 957*4656d474SGarrett D'Amore errsz = strlen(err_reason) + 958*4656d474SGarrett D'Amore strlen(err_data) + 3; 959*4656d474SGarrett D'Amore err_string = xmalloc(errsz); 960*4656d474SGarrett D'Amore (void) snprintf(err_string, errsz, 961*4656d474SGarrett D'Amore "%s: %s", err_reason, err_data); 9625c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, 9635c51f124SMoriah Waterland gettext(ERR_VERIFY_SIG), 9645c51f124SMoriah Waterland signer_sname, signer_iname, 9655c51f124SMoriah Waterland err_string); 9665c51f124SMoriah Waterland free(err_string); 9675c51f124SMoriah Waterland } 9685c51f124SMoriah Waterland } 9695c51f124SMoriah Waterland ret = B_FALSE; 9705c51f124SMoriah Waterland goto cleanup; 9715c51f124SMoriah Waterland } 9725c51f124SMoriah Waterland 9735c51f124SMoriah Waterland /* now verify the signature */ 9745c51f124SMoriah Waterland i = PKCS7_signatureVerify(indata, p7, signer, issuer); 9755c51f124SMoriah Waterland 9765c51f124SMoriah Waterland if (i <= 0) { 9775c51f124SMoriah Waterland /* print out any OpenSSL-specific errors */ 9785c51f124SMoriah Waterland signer_sname = 9795c51f124SMoriah Waterland get_subject_display_name(ctx->current_cert); 9805c51f124SMoriah Waterland signer_iname = 9815c51f124SMoriah Waterland get_subject_display_name(ctx->current_cert); 9825c51f124SMoriah Waterland while ((errcode = ERR_get_error_line_data(NULL, 9835c51f124SMoriah Waterland NULL, &err_data, &err_flags)) != 0) { 9845c51f124SMoriah Waterland err_reason = 9855c51f124SMoriah Waterland ERR_reason_error_string(errcode); 9865c51f124SMoriah Waterland if (err_reason == NULL) { 9875c51f124SMoriah Waterland err_reason = 9885c51f124SMoriah Waterland gettext(ERR_SIG_INT); 9895c51f124SMoriah Waterland } 9905c51f124SMoriah Waterland 9915c51f124SMoriah Waterland if (!(err_flags & ERR_TXT_STRING)) { 9925c51f124SMoriah Waterland err_data = 9935c51f124SMoriah Waterland gettext(ERR_SIG_INT); 9945c51f124SMoriah Waterland } 9955c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, 9965c51f124SMoriah Waterland gettext(ERR_VERIFY_SIG), signer_sname, 9975c51f124SMoriah Waterland signer_iname, err_reason); 9985c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, 9995c51f124SMoriah Waterland gettext(ERR_VERIFY_SIG), signer_sname, 10005c51f124SMoriah Waterland signer_iname, err_data); 10015c51f124SMoriah Waterland } 10025c51f124SMoriah Waterland ret = B_FALSE; 10035c51f124SMoriah Waterland goto cleanup; 10045c51f124SMoriah Waterland } 10055c51f124SMoriah Waterland 10065c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_VERIFY_OK), signer_sname); 10075c51f124SMoriah Waterland } 10085c51f124SMoriah Waterland 10095c51f124SMoriah Waterland /* signature(s) verified successfully */ 10105c51f124SMoriah Waterland cleanup: 10115c51f124SMoriah Waterland if (ctx) 10125c51f124SMoriah Waterland X509_STORE_CTX_cleanup(ctx); 10135c51f124SMoriah Waterland return (ret); 10145c51f124SMoriah Waterland } 10155c51f124SMoriah Waterland 10165c51f124SMoriah Waterland /* 10175c51f124SMoriah Waterland * Name: web_verify 10185c51f124SMoriah Waterland * Description: Callback used by PKCS7_dataVerify when 10195c51f124SMoriah Waterland * verifying a certificate chain. 10205c51f124SMoriah Waterland * 10215c51f124SMoriah Waterland * Arguments: err - where to record any errors. 10225c51f124SMoriah Waterland * ctx - The context handle of the current verification operation 10235c51f124SMoriah Waterland * 10245c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 10255c51f124SMoriah Waterland * if it's '0' (not OK) we simply return it, since the 10265c51f124SMoriah Waterland * verification operation has already determined that the 10275c51f124SMoriah Waterland * cert is invalid. if 'ok' is non-zero, then we do our 10285c51f124SMoriah Waterland * checks, and return 0 or 1 based on if the cert is 10295c51f124SMoriah Waterland * invalid or valid. 10305c51f124SMoriah Waterland */ 10315c51f124SMoriah Waterland static int 10325c51f124SMoriah Waterland web_verify(int ok, X509_STORE_CTX *ctx) 10335c51f124SMoriah Waterland { 10345c51f124SMoriah Waterland X509 *curr_cert; 10355c51f124SMoriah Waterland X509 *curr_issuer; 10365c51f124SMoriah Waterland char *uri; 10375c51f124SMoriah Waterland url_hport_t *proxy; 10385c51f124SMoriah Waterland PKG_ERR *err = NULL; 10395c51f124SMoriah Waterland STACK_OF(X509) *cas; 10405c51f124SMoriah Waterland if (!ok) { 10415c51f124SMoriah Waterland /* don't override a verify failure */ 10425c51f124SMoriah Waterland return (ok); 10435c51f124SMoriah Waterland } 10445c51f124SMoriah Waterland 10455c51f124SMoriah Waterland 10465c51f124SMoriah Waterland /* get app data supplied through callback context */ 10475c51f124SMoriah Waterland err = ((verify_cb_data_t *)X509_STORE_CTX_get_app_data(ctx))->err; 10485c51f124SMoriah Waterland proxy = ((verify_cb_data_t *)X509_STORE_CTX_get_app_data(ctx))->proxy; 10495c51f124SMoriah Waterland cas = ((verify_cb_data_t *)X509_STORE_CTX_get_app_data(ctx))->cas; 10505c51f124SMoriah Waterland 10515c51f124SMoriah Waterland /* Check revocation status */ 10525c51f124SMoriah Waterland curr_cert = X509_STORE_CTX_get_current_cert(ctx); 10535c51f124SMoriah Waterland 10545c51f124SMoriah Waterland /* this shouldn't happen */ 10555c51f124SMoriah Waterland if (curr_cert == NULL) { 10565c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, gettext(ERR_PKG_INTERNAL), 10575c51f124SMoriah Waterland __FILE__, __LINE__); 10585c51f124SMoriah Waterland return (0); 10595c51f124SMoriah Waterland } 10605c51f124SMoriah Waterland 10615c51f124SMoriah Waterland /* don't perform OCSP unless cert has required OCSP extensions */ 10625c51f124SMoriah Waterland if (get_ocsp_uri(curr_cert, &uri)) { 10635c51f124SMoriah Waterland if (get_issuer(&curr_issuer, ctx, curr_cert) <= 0) { 10645c51f124SMoriah Waterland /* no issuer! */ 10655c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, 10665c51f124SMoriah Waterland gettext(ERR_PKG_INTERNAL), 10675c51f124SMoriah Waterland __FILE__, __LINE__); 10685c51f124SMoriah Waterland return (0); 10695c51f124SMoriah Waterland } 10705c51f124SMoriah Waterland 10715c51f124SMoriah Waterland /* 10725c51f124SMoriah Waterland * ok we have the current cert 10735c51f124SMoriah Waterland * and its issuer. Do the OCSP check 10745c51f124SMoriah Waterland */ 10755c51f124SMoriah Waterland 10765c51f124SMoriah Waterland /* 10775c51f124SMoriah Waterland * OCSP extensions are, by, RFC 2459, never critical 10785c51f124SMoriah Waterland * extensions, therefore, we only fail if we were able 10795c51f124SMoriah Waterland * to explicitly contact an OCSP responder, and that 10805c51f124SMoriah Waterland * responder did not indicate the cert was valid. We 10815c51f124SMoriah Waterland * also fail if user-supplied data could not be parsed 10825c51f124SMoriah Waterland * or we run out of memory. We succeeed for "soft" 10835c51f124SMoriah Waterland * failures, such as not being able to connect to the 10845c51f124SMoriah Waterland * OCSP responder, or trying to use if the OCSP URI 10855c51f124SMoriah Waterland * indicates SSL must be used (which we do not 10865c51f124SMoriah Waterland * support) 10875c51f124SMoriah Waterland */ 10885c51f124SMoriah Waterland switch (ocsp_verify(err, curr_cert, curr_issuer, 10895c51f124SMoriah Waterland uri, proxy, cas)) { 10905c51f124SMoriah Waterland case OCSPMem: /* Ran out of memory */ 10915c51f124SMoriah Waterland case OCSPInternal: /* Some internal error */ 10925c51f124SMoriah Waterland case OCSPVerify: /* OCSP responder indicated fail */ 10935c51f124SMoriah Waterland return (0); 10945c51f124SMoriah Waterland } 10955c51f124SMoriah Waterland /* all other cases are success, or soft failures */ 10965c51f124SMoriah Waterland pkgerr_clear(err); 10975c51f124SMoriah Waterland } 10985c51f124SMoriah Waterland 10995c51f124SMoriah Waterland return (ok); 11005c51f124SMoriah Waterland } 11015c51f124SMoriah Waterland 11025c51f124SMoriah Waterland /* 11035c51f124SMoriah Waterland * Name: get_time_string 11045c51f124SMoriah Waterland * Description: Generates a human-readable string from an ASN1_GENERALIZED_TIME 11055c51f124SMoriah Waterland * 11065c51f124SMoriah Waterland * Arguments: intime - The time to convert 11075c51f124SMoriah Waterland * 11085c51f124SMoriah Waterland * Returns : A pointer to a static string representing the passed-in time. 11095c51f124SMoriah Waterland */ 11105c51f124SMoriah Waterland static char 11115c51f124SMoriah Waterland *get_time_string(ASN1_GENERALIZEDTIME *intime) 11125c51f124SMoriah Waterland { 11135c51f124SMoriah Waterland 11145c51f124SMoriah Waterland static char time[ATTR_MAX]; 11155c51f124SMoriah Waterland BIO *mem; 11165c51f124SMoriah Waterland char *p; 11175c51f124SMoriah Waterland 11185c51f124SMoriah Waterland if (intime == NULL) { 11195c51f124SMoriah Waterland return (NULL); 11205c51f124SMoriah Waterland } 11215c51f124SMoriah Waterland if ((mem = BIO_new(BIO_s_mem())) == NULL) { 11225c51f124SMoriah Waterland return (NULL); 11235c51f124SMoriah Waterland } 11245c51f124SMoriah Waterland 11255c51f124SMoriah Waterland if (ASN1_GENERALIZEDTIME_print(mem, intime) == 0) { 11265c51f124SMoriah Waterland (void) BIO_free(mem); 11275c51f124SMoriah Waterland return (NULL); 11285c51f124SMoriah Waterland } 11295c51f124SMoriah Waterland 11305c51f124SMoriah Waterland if (BIO_gets(mem, time, ATTR_MAX) <= 0) { 11315c51f124SMoriah Waterland (void) BIO_free(mem); 11325c51f124SMoriah Waterland return (NULL); 11335c51f124SMoriah Waterland } 11345c51f124SMoriah Waterland 11355c51f124SMoriah Waterland (void) BIO_free(mem); 11365c51f124SMoriah Waterland 11375c51f124SMoriah Waterland /* trim the end of the string */ 11385c51f124SMoriah Waterland for (p = time + strlen(time) - 1; isspace(*p); p--) { 11395c51f124SMoriah Waterland *p = '\0'; 11405c51f124SMoriah Waterland } 11415c51f124SMoriah Waterland 11425c51f124SMoriah Waterland return (time); 11435c51f124SMoriah Waterland } 11445c51f124SMoriah Waterland 11455c51f124SMoriah Waterland /* 11465c51f124SMoriah Waterland * Name: get_ocsp_uri 11475c51f124SMoriah Waterland * Description: Examines an X509 certificate and retrieves the embedded 11485c51f124SMoriah Waterland * OCSP Responder URI if one exists. 11495c51f124SMoriah Waterland * 11505c51f124SMoriah Waterland * Arguments: cert - The cert to inspect 11515c51f124SMoriah Waterland * uri - pointer where the newly-allocated URI is placed, if found 11525c51f124SMoriah Waterland * 11535c51f124SMoriah Waterland * Returns : Success if the URI was found. Appropriate status otherwise. 11545c51f124SMoriah Waterland */ 11555c51f124SMoriah Waterland static boolean_t 11565c51f124SMoriah Waterland get_ocsp_uri(X509 *cert, char **uri) 11575c51f124SMoriah Waterland { 11585c51f124SMoriah Waterland AUTHORITY_INFO_ACCESS *aia; 11595c51f124SMoriah Waterland ACCESS_DESCRIPTION *ad; 11605c51f124SMoriah Waterland int i; 11615c51f124SMoriah Waterland 11625c51f124SMoriah Waterland if (getenv("PKGWEB_TEST_OCSP")) { 11635c51f124SMoriah Waterland *uri = xstrdup(getenv("PKGWEB_TEST_OCSP")); 11645c51f124SMoriah Waterland return (B_TRUE); 11655c51f124SMoriah Waterland } 11665c51f124SMoriah Waterland 11675c51f124SMoriah Waterland /* get the X509v3 extension holding the OCSP URI */ 11685c51f124SMoriah Waterland if ((aia = X509_get_ext_d2i(cert, NID_info_access, 11695c51f124SMoriah Waterland NULL, NULL)) != NULL) { 11705c51f124SMoriah Waterland for (i = 0; i < sk_ACCESS_DESCRIPTION_num(aia); i++) { 11715c51f124SMoriah Waterland ad = sk_ACCESS_DESCRIPTION_value(aia, i); 11725c51f124SMoriah Waterland if (OBJ_obj2nid(ad->method) == NID_ad_OCSP) { 11735c51f124SMoriah Waterland if (ad->location->type == GEN_URI) { 11745c51f124SMoriah Waterland *uri = 11755c51f124SMoriah Waterland xstrdup((char *)ASN1_STRING_data(ad->location->d.ia5)); 11765c51f124SMoriah Waterland return (B_TRUE); 11775c51f124SMoriah Waterland } 11785c51f124SMoriah Waterland } 11795c51f124SMoriah Waterland } 11805c51f124SMoriah Waterland } 11815c51f124SMoriah Waterland 11825c51f124SMoriah Waterland /* no URI was found */ 11835c51f124SMoriah Waterland return (B_FALSE); 11845c51f124SMoriah Waterland } 11855c51f124SMoriah Waterland 11865c51f124SMoriah Waterland /* 11875c51f124SMoriah Waterland * Name: ocsp_verify 11885c51f124SMoriah Waterland * Description: Attempts to contact an OCSP Responder and ascertain the validity 11895c51f124SMoriah Waterland * of an X509 certificate. 11905c51f124SMoriah Waterland * 11915c51f124SMoriah Waterland * Arguments: err - Error object to add error messages to 11925c51f124SMoriah Waterland * cert - The cert to validate 11935c51f124SMoriah Waterland * issuer - The certificate of the issuer of 'cert' 11945c51f124SMoriah Waterland * uri - The OCSP Responder URI 11955c51f124SMoriah Waterland * cas - The trusted CA certificates used to verify the 11965c51f124SMoriah Waterland * signed OCSP response 11975c51f124SMoriah Waterland * Returns : Success - The OCSP Responder reported a 'good' 11985c51f124SMoriah Waterland * status for the cert otherwise, appropriate 11995c51f124SMoriah Waterland * error is returned. 12005c51f124SMoriah Waterland */ 12015c51f124SMoriah Waterland static OCSPStatus 12025c51f124SMoriah Waterland ocsp_verify(PKG_ERR *err, X509 *cert, X509 *issuer, 12035c51f124SMoriah Waterland char *uri, url_hport_t *proxy, STACK_OF(X509) *cas) 12045c51f124SMoriah Waterland { 12055c51f124SMoriah Waterland OCSP_CERTID *id; 12065c51f124SMoriah Waterland OCSP_REQUEST *req; 12075c51f124SMoriah Waterland OCSP_RESPONSE *resp; 12085c51f124SMoriah Waterland OCSP_BASICRESP *bs; 12095c51f124SMoriah Waterland BIO *cbio, *mem; 12105c51f124SMoriah Waterland char ocspbuf[OCSP_BUFSIZ]; 12115c51f124SMoriah Waterland char *host = NULL, *portstr = NULL, *path = "/", *p, *q, *r; 12125c51f124SMoriah Waterland int port, status, reason; 12135c51f124SMoriah Waterland int len, retval, respcode, use_ssl = 0; 12145c51f124SMoriah Waterland ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; 12155c51f124SMoriah Waterland char *subjname; 12165c51f124SMoriah Waterland time_t currtime; 12175c51f124SMoriah Waterland char currtimestr[ATTR_MAX]; 12185c51f124SMoriah Waterland unsigned long errcode; 12195c51f124SMoriah Waterland const char *err_reason; 12205c51f124SMoriah Waterland 12215c51f124SMoriah Waterland subjname = get_subject_display_name(cert); 12225c51f124SMoriah Waterland 12235c51f124SMoriah Waterland /* parse the URI into its constituent parts */ 12245c51f124SMoriah Waterland if (OCSP_parse_url(uri, &host, &portstr, &path, &use_ssl) == NULL) { 12255c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_PARSE), uri); 12265c51f124SMoriah Waterland return (OCSPParse); 12275c51f124SMoriah Waterland } 12285c51f124SMoriah Waterland 12295c51f124SMoriah Waterland /* we don't currently support SSL-based OCSP Responders */ 12305c51f124SMoriah Waterland if (use_ssl) { 12315c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_UNSUP), uri); 12325c51f124SMoriah Waterland return (OCSPUnsupported); 12335c51f124SMoriah Waterland } 12345c51f124SMoriah Waterland 12355c51f124SMoriah Waterland /* default port if none specified */ 12365c51f124SMoriah Waterland if (portstr == NULL) { 12375c51f124SMoriah Waterland port = (int)URL_DFLT_SRVR_PORT; 12385c51f124SMoriah Waterland } else { 12395c51f124SMoriah Waterland port = (int)strtoul(portstr, &r, 10); 12405c51f124SMoriah Waterland if (*r != '\0') { 12415c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 12425c51f124SMoriah Waterland gettext(ERR_OCSP_PARSE), uri); 12435c51f124SMoriah Waterland return (OCSPParse); 12445c51f124SMoriah Waterland } 12455c51f124SMoriah Waterland } 12465c51f124SMoriah Waterland 12475c51f124SMoriah Waterland /* allocate new request structure */ 12485c51f124SMoriah Waterland if ((req = OCSP_REQUEST_new()) == NULL) { 12495c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); 12505c51f124SMoriah Waterland return (OCSPMem); 12515c51f124SMoriah Waterland } 12525c51f124SMoriah Waterland 12535c51f124SMoriah Waterland /* convert cert and issuer fields into OCSP request data */ 12545c51f124SMoriah Waterland if ((id = OCSP_cert_to_id(NULL, cert, issuer)) == NULL) { 12555c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_PKG_INTERNAL), 12565c51f124SMoriah Waterland __FILE__, __LINE__); 12575c51f124SMoriah Waterland return (OCSPInternal); 12585c51f124SMoriah Waterland } 12595c51f124SMoriah Waterland 12605c51f124SMoriah Waterland /* fill out request structure with request data */ 12615c51f124SMoriah Waterland if ((OCSP_request_add0_id(req, id)) == NULL) { 12625c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_PKG_INTERNAL), 12635c51f124SMoriah Waterland __FILE__, __LINE__); 12645c51f124SMoriah Waterland return (OCSPInternal); 12655c51f124SMoriah Waterland } 12665c51f124SMoriah Waterland 12675c51f124SMoriah Waterland /* add nonce */ 1268*4656d474SGarrett D'Amore (void) OCSP_request_add1_nonce(req, NULL, -1); 12695c51f124SMoriah Waterland 12705c51f124SMoriah Waterland /* connect to host, or proxy */ 12715c51f124SMoriah Waterland if (proxy != NULL) { 12725c51f124SMoriah Waterland if ((cbio = BIO_new_connect(proxy->hostname)) == NULL) { 12735c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); 12745c51f124SMoriah Waterland return (OCSPMem); 12755c51f124SMoriah Waterland } 12765c51f124SMoriah Waterland 12775c51f124SMoriah Waterland /* 12785c51f124SMoriah Waterland * BIO_set_conn_int_port takes an int *, so let's give it one 12795c51f124SMoriah Waterland * rather than an ushort_t * 12805c51f124SMoriah Waterland */ 12815c51f124SMoriah Waterland port = proxy->port; 12825c51f124SMoriah Waterland (void) BIO_set_conn_int_port(cbio, &port); 12835c51f124SMoriah Waterland if (BIO_do_connect(cbio) <= 0) { 12845c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 12855c51f124SMoriah Waterland gettext(ERR_OCSP_CONNECT), 12865c51f124SMoriah Waterland proxy->hostname, port); 12875c51f124SMoriah Waterland return (OCSPConnect); 12885c51f124SMoriah Waterland } 12895c51f124SMoriah Waterland } else { 12905c51f124SMoriah Waterland if ((cbio = BIO_new_connect(host)) == NULL) { 12915c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); 12925c51f124SMoriah Waterland return (OCSPMem); 12935c51f124SMoriah Waterland } 12945c51f124SMoriah Waterland 12955c51f124SMoriah Waterland (void) BIO_set_conn_int_port(cbio, &port); 12965c51f124SMoriah Waterland if (BIO_do_connect(cbio) <= 0) { 12975c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 12985c51f124SMoriah Waterland gettext(ERR_OCSP_CONNECT), 12995c51f124SMoriah Waterland host, port); 13005c51f124SMoriah Waterland return (OCSPConnect); 13015c51f124SMoriah Waterland } 13025c51f124SMoriah Waterland } 13035c51f124SMoriah Waterland 13045c51f124SMoriah Waterland /* calculate length of binary request data */ 13055c51f124SMoriah Waterland len = i2d_OCSP_REQUEST(req, NULL); 13065c51f124SMoriah Waterland 13075c51f124SMoriah Waterland /* send the request headers */ 13085c51f124SMoriah Waterland if (proxy != NULL) { 13095c51f124SMoriah Waterland retval = BIO_printf(cbio, OCSP_REQUEST_FORMAT, uri, len); 13105c51f124SMoriah Waterland } else { 13115c51f124SMoriah Waterland retval = BIO_printf(cbio, OCSP_REQUEST_FORMAT, path, len); 13125c51f124SMoriah Waterland } 13135c51f124SMoriah Waterland 13145c51f124SMoriah Waterland if (retval <= 0) { 13155c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_SEND), host); 13165c51f124SMoriah Waterland return (OCSPRequest); 13175c51f124SMoriah Waterland } 13185c51f124SMoriah Waterland 13195c51f124SMoriah Waterland /* send the request binary data */ 13205c51f124SMoriah Waterland if (i2d_OCSP_REQUEST_bio(cbio, req) <= 0) { 13215c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_SEND), host); 13225c51f124SMoriah Waterland return (OCSPRequest); 13235c51f124SMoriah Waterland } 13245c51f124SMoriah Waterland 13255c51f124SMoriah Waterland /* 13265c51f124SMoriah Waterland * read the response into a memory BIO, so we can 'gets' 13275c51f124SMoriah Waterland * (socket bio's don't support BIO_gets) 13285c51f124SMoriah Waterland */ 13295c51f124SMoriah Waterland if ((mem = BIO_new(BIO_s_mem())) == NULL) { 13305c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); 13315c51f124SMoriah Waterland return (OCSPMem); 13325c51f124SMoriah Waterland } 13335c51f124SMoriah Waterland 13345c51f124SMoriah Waterland while ((len = BIO_read(cbio, ocspbuf, OCSP_BUFSIZ))) { 13355c51f124SMoriah Waterland if (len < 0) { 13365c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 13375c51f124SMoriah Waterland gettext(ERR_OCSP_READ), host); 13385c51f124SMoriah Waterland return (OCSPRequest); 13395c51f124SMoriah Waterland } 13405c51f124SMoriah Waterland if (BIO_write(mem, ocspbuf, len) != len) { 13415c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); 13425c51f124SMoriah Waterland return (OCSPMem); 13435c51f124SMoriah Waterland } 13445c51f124SMoriah Waterland } 13455c51f124SMoriah Waterland 13465c51f124SMoriah Waterland /* now get the first line of the response */ 13475c51f124SMoriah Waterland if (BIO_gets(mem, ocspbuf, OCSP_BUFSIZ) <= 0) { 13485c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_RESP_PARSE)); 13495c51f124SMoriah Waterland return (OCSPRequest); 13505c51f124SMoriah Waterland } 13515c51f124SMoriah Waterland 13525c51f124SMoriah Waterland /* parse the header response */ 13535c51f124SMoriah Waterland /* it should look like "HTTP/x.x 200 OK" */ 13545c51f124SMoriah Waterland 13555c51f124SMoriah Waterland /* skip past the protocol info */ 13565c51f124SMoriah Waterland for (p = ocspbuf; (*p != '\0') && !isspace(*p); p++) 13575c51f124SMoriah Waterland continue; 13585c51f124SMoriah Waterland 13595c51f124SMoriah Waterland /* skip past whitespace betwen protocol and start of response code */ 13605c51f124SMoriah Waterland while ((*p != '\0') && isspace(*p)) { 13615c51f124SMoriah Waterland p++; 13625c51f124SMoriah Waterland } 13635c51f124SMoriah Waterland 13645c51f124SMoriah Waterland if (*p == '\0') { 13655c51f124SMoriah Waterland /* premature end */ 13665c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 13675c51f124SMoriah Waterland gettext(ERR_OCSP_RESP_PARSE), ocspbuf); 13685c51f124SMoriah Waterland return (OCSPRequest); 13695c51f124SMoriah Waterland } 13705c51f124SMoriah Waterland 13715c51f124SMoriah Waterland /* find end of response code */ 13725c51f124SMoriah Waterland for (q = p; (*q != NULL) && !isspace(*q); q++) 13735c51f124SMoriah Waterland continue; 13745c51f124SMoriah Waterland 13755c51f124SMoriah Waterland /* mark end of response code */ 13765c51f124SMoriah Waterland *q++ = '\0'; 13775c51f124SMoriah Waterland 13785c51f124SMoriah Waterland /* parse response code */ 13795c51f124SMoriah Waterland respcode = strtoul(p, &r, 10); 13805c51f124SMoriah Waterland if (*r != '\0') { 13815c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 13825c51f124SMoriah Waterland gettext(ERR_OCSP_RESP_PARSE), ocspbuf); 13835c51f124SMoriah Waterland return (OCSPRequest); 13845c51f124SMoriah Waterland } 13855c51f124SMoriah Waterland 13865c51f124SMoriah Waterland /* now find beginning of the response string */ 13875c51f124SMoriah Waterland while ((*q != NULL) && isspace(*q)) { 13885c51f124SMoriah Waterland q++; 13895c51f124SMoriah Waterland } 13905c51f124SMoriah Waterland 13915c51f124SMoriah Waterland /* trim whitespace from end of message */ 13925c51f124SMoriah Waterland for (r = (q + strlen(q) - 1); isspace(*r); r--) { 13935c51f124SMoriah Waterland *r = '\0'; 13945c51f124SMoriah Waterland } 13955c51f124SMoriah Waterland 13965c51f124SMoriah Waterland /* response must be OK */ 13975c51f124SMoriah Waterland if (respcode != 200) { 13985c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 13995c51f124SMoriah Waterland gettext(ERR_OCSP_RESP_NOTOK), 200, 14005c51f124SMoriah Waterland respcode, q); 14015c51f124SMoriah Waterland return (OCSPRequest); 14025c51f124SMoriah Waterland } 14035c51f124SMoriah Waterland 14045c51f124SMoriah Waterland /* read headers, looking for content-type or a blank line */ 14055c51f124SMoriah Waterland while (BIO_gets(mem, ocspbuf, OCSP_BUFSIZ) > 0) { 14065c51f124SMoriah Waterland 14075c51f124SMoriah Waterland /* if we get a content type, make sure it's the right type */ 14085c51f124SMoriah Waterland if (ci_strneq(ocspbuf, CONTENT_TYPE_HDR, 14095c51f124SMoriah Waterland strlen(CONTENT_TYPE_HDR))) { 14105c51f124SMoriah Waterland 14115c51f124SMoriah Waterland /* look for the delimiting : */ 14125c51f124SMoriah Waterland p = strchr(ocspbuf + strlen(CONTENT_TYPE_HDR), ':'); 14135c51f124SMoriah Waterland 14145c51f124SMoriah Waterland if (p == NULL) { 14155c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 14165c51f124SMoriah Waterland gettext(ERR_OCSP_RESP_PARSE), ocspbuf); 14175c51f124SMoriah Waterland return (OCSPResponder); 14185c51f124SMoriah Waterland } 14195c51f124SMoriah Waterland 14205c51f124SMoriah Waterland /* skip over ':' */ 14215c51f124SMoriah Waterland p++; 14225c51f124SMoriah Waterland 14235c51f124SMoriah Waterland /* find beginning of the content type */ 14245c51f124SMoriah Waterland while ((*p != NULL) && isspace(*p)) { 14255c51f124SMoriah Waterland p++; 14265c51f124SMoriah Waterland } 14275c51f124SMoriah Waterland 14285c51f124SMoriah Waterland if (!ci_strneq(p, CONTENT_OCSP_RESP, 14295c51f124SMoriah Waterland strlen(CONTENT_OCSP_RESP))) { 14305c51f124SMoriah Waterland /* response is not right type */ 14315c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 14325c51f124SMoriah Waterland gettext(ERR_OCSP_RESP_TYPE), 14335c51f124SMoriah Waterland p, CONTENT_OCSP_RESP); 14345c51f124SMoriah Waterland return (OCSPResponder); 14355c51f124SMoriah Waterland } 14365c51f124SMoriah Waterland 14375c51f124SMoriah Waterland /* continue with next header line */ 14385c51f124SMoriah Waterland continue; 14395c51f124SMoriah Waterland } 14405c51f124SMoriah Waterland 14415c51f124SMoriah Waterland /* scan looking for a character */ 14425c51f124SMoriah Waterland for (p = ocspbuf; (*p != '\0') && isspace(*p); p++) { 14435c51f124SMoriah Waterland continue; 14445c51f124SMoriah Waterland } 14455c51f124SMoriah Waterland /* 14465c51f124SMoriah Waterland * if we got to the end of the line with 14475c51f124SMoriah Waterland * no chars, then this is a blank line 14485c51f124SMoriah Waterland */ 14495c51f124SMoriah Waterland if (*p == '\0') { 14505c51f124SMoriah Waterland break; 14515c51f124SMoriah Waterland } 14525c51f124SMoriah Waterland } 14535c51f124SMoriah Waterland 14545c51f124SMoriah Waterland 14555c51f124SMoriah Waterland if (*p != '\0') { 14565c51f124SMoriah Waterland /* last line was not blank */ 14575c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 14585c51f124SMoriah Waterland gettext(ERR_OCSP_RESP_PARSE), ocspbuf); 14595c51f124SMoriah Waterland return (OCSPResponder); 14605c51f124SMoriah Waterland } 14615c51f124SMoriah Waterland 14625c51f124SMoriah Waterland /* now read in the binary response */ 14635c51f124SMoriah Waterland if ((resp = d2i_OCSP_RESPONSE_bio(mem, NULL)) == NULL) { 14645c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_READ), host); 14655c51f124SMoriah Waterland return (OCSPResponder); 14665c51f124SMoriah Waterland } 14675c51f124SMoriah Waterland 14685c51f124SMoriah Waterland /* free temp BIOs */ 14695c51f124SMoriah Waterland (void) BIO_free(mem); 14705c51f124SMoriah Waterland (void) BIO_free_all(cbio); 14715c51f124SMoriah Waterland cbio = NULL; 14725c51f124SMoriah Waterland 14735c51f124SMoriah Waterland /* make sure request was successful */ 14745c51f124SMoriah Waterland if (OCSP_response_status(resp) != OCSP_RESPONSE_STATUS_SUCCESSFUL) { 14755c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_RESP_NOTOK), 14765c51f124SMoriah Waterland OCSP_RESPONSE_STATUS_SUCCESSFUL, 14775c51f124SMoriah Waterland OCSP_response_status(resp), 14785c51f124SMoriah Waterland OCSP_response_status_str(OCSP_response_status(resp))); 14795c51f124SMoriah Waterland return (OCSPResponder); 14805c51f124SMoriah Waterland } 14815c51f124SMoriah Waterland 14825c51f124SMoriah Waterland /* parse binary response into internal structure */ 14835c51f124SMoriah Waterland if ((bs = OCSP_response_get1_basic(resp)) == NULL) { 14845c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_READ), host); 14855c51f124SMoriah Waterland return (OCSPParse); 14865c51f124SMoriah Waterland } 14875c51f124SMoriah Waterland 14885c51f124SMoriah Waterland /* 14895c51f124SMoriah Waterland * From here to the end of the code, the return values 14905c51f124SMoriah Waterland * should be hard failures 14915c51f124SMoriah Waterland */ 14925c51f124SMoriah Waterland 14935c51f124SMoriah Waterland /* verify the response, warn if no nonce */ 14945c51f124SMoriah Waterland if (OCSP_check_nonce(req, bs) <= 0) { 14955c51f124SMoriah Waterland logerr(pkg_gt(WRN_OCSP_RESP_NONCE)); 14965c51f124SMoriah Waterland } 14975c51f124SMoriah Waterland 14985c51f124SMoriah Waterland if (OCSP_basic_verify(bs, cas, NULL, OCSP_TRUSTOTHER) <= 0) { 14995c51f124SMoriah Waterland while ((errcode = ERR_get_error()) != NULL) { 15005c51f124SMoriah Waterland err_reason = ERR_reason_error_string(errcode); 15015c51f124SMoriah Waterland if (err_reason == NULL) { 15025c51f124SMoriah Waterland err_reason = 15035c51f124SMoriah Waterland gettext(ERR_SIG_INT); 15045c51f124SMoriah Waterland } 15055c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, (char *)err_reason); 15065c51f124SMoriah Waterland } 15075c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_VERIFY_FAIL), 15085c51f124SMoriah Waterland uri); 15095c51f124SMoriah Waterland return (OCSPVerify); 15105c51f124SMoriah Waterland } 15115c51f124SMoriah Waterland 15125c51f124SMoriah Waterland /* check the validity of our certificate */ 15135c51f124SMoriah Waterland if (OCSP_resp_find_status(bs, id, &status, &reason, 15145c51f124SMoriah Waterland &rev, &thisupd, &nextupd) == NULL) { 15155c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 15165c51f124SMoriah Waterland gettext(ERR_OCSP_VERIFY_NO_STATUS), subjname); 15175c51f124SMoriah Waterland return (OCSPVerify); 15185c51f124SMoriah Waterland } 15195c51f124SMoriah Waterland 15205c51f124SMoriah Waterland if ((currtime = time(NULL)) == (time_t)-1) { 15215c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 15225c51f124SMoriah Waterland gettext(ERR_OCSP_VERIFY_NOTIME)); 15235c51f124SMoriah Waterland return (OCSPVerify); 15245c51f124SMoriah Waterland } 15255c51f124SMoriah Waterland 15265c51f124SMoriah Waterland (void) strlcpy(currtimestr, ctime(&currtime), ATTR_MAX); 15275c51f124SMoriah Waterland 15285c51f124SMoriah Waterland /* trim end */ 15295c51f124SMoriah Waterland for (r = currtimestr + strlen(currtimestr) - 1; 15305c51f124SMoriah Waterland isspace(*r); r--) { 15315c51f124SMoriah Waterland *r = '\0'; 15325c51f124SMoriah Waterland } 15335c51f124SMoriah Waterland 15345c51f124SMoriah Waterland if (!OCSP_check_validity(thisupd, nextupd, 15355c51f124SMoriah Waterland OCSP_VALIDITY_PERIOD, -1)) { 15365c51f124SMoriah Waterland if (nextupd != NULL) { 15375c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 15385c51f124SMoriah Waterland gettext(ERR_OCSP_VERIFY_VALIDITY), 15395c51f124SMoriah Waterland get_time_string(thisupd), get_time_string(nextupd), 15405c51f124SMoriah Waterland currtimestr); 15415c51f124SMoriah Waterland } else { 15425c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 15435c51f124SMoriah Waterland gettext(ERR_OCSP_VERIFY_VALIDITY), 15445c51f124SMoriah Waterland get_time_string(thisupd), 15455c51f124SMoriah Waterland currtimestr); 15465c51f124SMoriah Waterland } 15475c51f124SMoriah Waterland return (OCSPVerify); 15485c51f124SMoriah Waterland } 15495c51f124SMoriah Waterland 15505c51f124SMoriah Waterland if (status != V_OCSP_CERTSTATUS_GOOD) { 15515c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 15525c51f124SMoriah Waterland gettext(ERR_OCSP_VERIFY_STATUS), subjname, 15535c51f124SMoriah Waterland OCSP_cert_status_str(status)); 15545c51f124SMoriah Waterland return (OCSPVerify); 15555c51f124SMoriah Waterland } 15565c51f124SMoriah Waterland 15575c51f124SMoriah Waterland /* everythign checks out */ 15585c51f124SMoriah Waterland return (OCSPSuccess); 15595c51f124SMoriah Waterland } 15605c51f124SMoriah Waterland 15615c51f124SMoriah Waterland /* 15625c51f124SMoriah Waterland * Name: get_issuer 15635c51f124SMoriah Waterland * Description: Attempts to find the issuing certificate for a given certificate 15645c51f124SMoriah Waterland * This will look in both the list of trusted certificates found in 15655c51f124SMoriah Waterland * the X509_STORE_CTX structure, as well as the list of untrusted 15665c51f124SMoriah Waterland * chain certificates found in the X509_STORE_CTX structure. 15675c51f124SMoriah Waterland * Arguments: 15685c51f124SMoriah Waterland * issuer - The resulting issuer cert is placed here, if found 15695c51f124SMoriah Waterland * ctx - The current verification context 15705c51f124SMoriah Waterland * x - The certificate whose issuer we are looking for 15715c51f124SMoriah Waterland * Returns : Success - The issuer cert was found and placed in *issuer. 15725c51f124SMoriah Waterland * otherwise, appropriate error is returned. 15735c51f124SMoriah Waterland */ 15745c51f124SMoriah Waterland static int 15755c51f124SMoriah Waterland get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) 15765c51f124SMoriah Waterland { 15775c51f124SMoriah Waterland int i, ok; 15785c51f124SMoriah Waterland 15795c51f124SMoriah Waterland /* 15805c51f124SMoriah Waterland * first look in the list of trusted 15815c51f124SMoriah Waterland * certs, using the context's method to do so 15825c51f124SMoriah Waterland */ 15835c51f124SMoriah Waterland if ((ok = ctx->get_issuer(issuer, ctx, x)) > 0) { 15845c51f124SMoriah Waterland return (ok); 15855c51f124SMoriah Waterland } 15865c51f124SMoriah Waterland 15875c51f124SMoriah Waterland if (ctx->untrusted != NULL) { 15885c51f124SMoriah Waterland /* didn't find it in trusted certs, look through untrusted */ 15895c51f124SMoriah Waterland for (i = 0; i < sk_X509_num(ctx->untrusted); i++) { 15905c51f124SMoriah Waterland if (X509_check_issued(sk_X509_value(ctx->untrusted, i), 15915c51f124SMoriah Waterland x) == X509_V_OK) { 15925c51f124SMoriah Waterland *issuer = sk_X509_value(ctx->untrusted, i); 15935c51f124SMoriah Waterland return (1); 15945c51f124SMoriah Waterland } 15955c51f124SMoriah Waterland } 15965c51f124SMoriah Waterland } 15975c51f124SMoriah Waterland *issuer = NULL; 15985c51f124SMoriah Waterland return (0); 15995c51f124SMoriah Waterland } 16005c51f124SMoriah Waterland 16015c51f124SMoriah Waterland /* 16025c51f124SMoriah Waterland * Name: parse_url_proxy 16035c51f124SMoriah Waterland * Description: Parses URL and optional proxy specification, populates static 16045c51f124SMoriah Waterland * 'ps' structure 16055c51f124SMoriah Waterland * 16065c51f124SMoriah Waterland * Arguments: err - where to record any errors. 16075c51f124SMoriah Waterland * url - URL to parse 16085c51f124SMoriah Waterland * proxy - proxy to parse, or NULL for no proxy 16095c51f124SMoriah Waterland * proxy_port - Default proxy port to use if no proxy 16105c51f124SMoriah Waterland * port specified in 'proxy' 16115c51f124SMoriah Waterland * 16125c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 16135c51f124SMoriah Waterland * on success, 'ps->url' and 'ps->proxy' are populated 16145c51f124SMoriah Waterland * with parsed data. 16155c51f124SMoriah Waterland */ 16165c51f124SMoriah Waterland static boolean_t 16175c51f124SMoriah Waterland parse_url_proxy(PKG_ERR *err, char *url, char *proxy, ushort_t proxy_port) 16185c51f124SMoriah Waterland { 16195c51f124SMoriah Waterland boolean_t ret = B_TRUE; 16205c51f124SMoriah Waterland if (!path_valid(url)) { 16215c51f124SMoriah Waterland ret = B_FALSE; 16225c51f124SMoriah Waterland goto cleanup; 16235c51f124SMoriah Waterland } 16245c51f124SMoriah Waterland 16255c51f124SMoriah Waterland if (url_parse(url, &ps->url) != URL_PARSE_SUCCESS) { 16265c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_PARSE_URL), url); 16275c51f124SMoriah Waterland ret = B_FALSE; 16285c51f124SMoriah Waterland goto cleanup; 16295c51f124SMoriah Waterland } 16305c51f124SMoriah Waterland 16315c51f124SMoriah Waterland if (proxy != NULL) { 16325c51f124SMoriah Waterland if (url_parse_hostport(proxy, &ps->proxy, proxy_port) 16335c51f124SMoriah Waterland != URL_PARSE_SUCCESS) { 16345c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 16355c51f124SMoriah Waterland gettext(ERR_BAD_PROXY), proxy); 16365c51f124SMoriah Waterland ret = B_FALSE; 16375c51f124SMoriah Waterland goto cleanup; 16385c51f124SMoriah Waterland } 16395c51f124SMoriah Waterland } 16405c51f124SMoriah Waterland 16415c51f124SMoriah Waterland cleanup: 16425c51f124SMoriah Waterland return (ret); 16435c51f124SMoriah Waterland } 16445c51f124SMoriah Waterland 16455c51f124SMoriah Waterland /* 16465c51f124SMoriah Waterland * Name: web_setup 16475c51f124SMoriah Waterland * Description: Initializes http library settings 16485c51f124SMoriah Waterland * 16495c51f124SMoriah Waterland * Arguments: err - where to record any errors. 16505c51f124SMoriah Waterland * 16515c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 16525c51f124SMoriah Waterland */ 16535c51f124SMoriah Waterland static boolean_t 16545c51f124SMoriah Waterland web_setup(PKG_ERR *err) 16555c51f124SMoriah Waterland { 16565c51f124SMoriah Waterland boolean_t ret = B_TRUE; 16575c51f124SMoriah Waterland static boolean_t keepalive = B_TRUE; 16585c51f124SMoriah Waterland 16595c51f124SMoriah Waterland if ((ps->hps = http_srv_init(&ps->url)) == NULL) { 16605c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); 16615c51f124SMoriah Waterland ret = B_FALSE; 16625c51f124SMoriah Waterland goto cleanup; 16635c51f124SMoriah Waterland } 16645c51f124SMoriah Waterland 16655c51f124SMoriah Waterland if (getenv("WEBPKG_DEBUG") != NULL) { 16665c51f124SMoriah Waterland http_set_verbose(B_TRUE); 16675c51f124SMoriah Waterland } 16685c51f124SMoriah Waterland 16695c51f124SMoriah Waterland if (ps->proxy.hostname[0] != '\0' && 16705c51f124SMoriah Waterland http_set_proxy(ps->hps, &ps->proxy) != 0) { 16715c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); 16725c51f124SMoriah Waterland ret = B_FALSE; 16735c51f124SMoriah Waterland goto cleanup; 16745c51f124SMoriah Waterland } 16755c51f124SMoriah Waterland if (http_set_keepalive(ps->hps, keepalive) != 0) { 16765c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); 16775c51f124SMoriah Waterland ret = B_FALSE; 16785c51f124SMoriah Waterland goto cleanup; 16795c51f124SMoriah Waterland } 16805c51f124SMoriah Waterland if (http_set_socket_read_timeout(ps->hps, ps->timeout) != 0) { 16815c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); 16825c51f124SMoriah Waterland ret = B_FALSE; 16835c51f124SMoriah Waterland goto cleanup; 16845c51f124SMoriah Waterland } 16855c51f124SMoriah Waterland if (http_set_random_file(ps->hps, RANDOM) != 0) { 16865c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); 16875c51f124SMoriah Waterland ret = B_FALSE; 16885c51f124SMoriah Waterland goto cleanup; 16895c51f124SMoriah Waterland } 16905c51f124SMoriah Waterland 16915c51f124SMoriah Waterland (void) http_set_p12_format(B_TRUE); 16925c51f124SMoriah Waterland 16935c51f124SMoriah Waterland cleanup: 16945c51f124SMoriah Waterland return (ret); 16955c51f124SMoriah Waterland } 16965c51f124SMoriah Waterland 16975c51f124SMoriah Waterland /* 16985c51f124SMoriah Waterland * Name: web_connect 16995c51f124SMoriah Waterland * Description: Makes connection with URL stored in static 'ps' structure. 17005c51f124SMoriah Waterland * 17015c51f124SMoriah Waterland * Arguments: err - where to record any errors. 17025c51f124SMoriah Waterland * 17035c51f124SMoriah Waterland * Returns : WEB_OK - connection successful 17045c51f124SMoriah Waterland * WEB_VERIFY_SETUP - Unable to complete necessary 17055c51f124SMoriah Waterland * SSL setup 17065c51f124SMoriah Waterland * WEB_CONNREFUSED - Connection was refused to web site 17075c51f124SMoriah Waterland * WEB_HOSTDOWN - Host was not responding to request 17085c51f124SMoriah Waterland * WEB_NOCONNECT - Some other connection failure 17095c51f124SMoriah Waterland */ 17105c51f124SMoriah Waterland static WebStatus 17115c51f124SMoriah Waterland web_connect(PKG_ERR *err) 17125c51f124SMoriah Waterland { 17135c51f124SMoriah Waterland STACK_OF(X509) *sec_cas = NULL; 17145c51f124SMoriah Waterland char *path; 17155c51f124SMoriah Waterland WebStatus ret = WEB_OK; 17165c51f124SMoriah Waterland ulong_t errcode; 17175c51f124SMoriah Waterland uint_t errsrc; 17185c51f124SMoriah Waterland int my_errno = 0; 17195c51f124SMoriah Waterland const char *libhttperr = NULL; 17205c51f124SMoriah Waterland 17215c51f124SMoriah Waterland if (ps->url.https == B_TRUE) { 17225c51f124SMoriah Waterland /* get CA certificates */ 17235c51f124SMoriah Waterland if (find_ca_certs(err, ps->keystore, &sec_cas) != 0) { 17245c51f124SMoriah Waterland ret = WEB_VERIFY_SETUP; 17255c51f124SMoriah Waterland goto cleanup; 17265c51f124SMoriah Waterland } 17275c51f124SMoriah Waterland 17285c51f124SMoriah Waterland if (sk_X509_num(sec_cas) < 1) { 17295c51f124SMoriah Waterland /* no trusted websites */ 17305c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 17315c51f124SMoriah Waterland gettext(ERR_KEYSTORE_NOTRUST)); 17325c51f124SMoriah Waterland ret = WEB_VERIFY_SETUP; 17335c51f124SMoriah Waterland goto cleanup; 17345c51f124SMoriah Waterland } 17355c51f124SMoriah Waterland 17365c51f124SMoriah Waterland /* 17375c51f124SMoriah Waterland * write out all CA certs to temp file. libwanboot should 17385c51f124SMoriah Waterland * have an interface for giving it a list of trusted certs 17395c51f124SMoriah Waterland * through an in-memory structure, but currently that does 17405c51f124SMoriah Waterland * not exist 17415c51f124SMoriah Waterland */ 17425c51f124SMoriah Waterland if ((path = write_ca_file(err, ps->dwnld_dir, sec_cas, 17435c51f124SMoriah Waterland WEB_CA_PHRASE)) == NULL) { 17445c51f124SMoriah Waterland ret = WEB_VERIFY_SETUP; 17455c51f124SMoriah Waterland goto cleanup; 17465c51f124SMoriah Waterland } 17475c51f124SMoriah Waterland 17485c51f124SMoriah Waterland ps->certfile = path; 17495c51f124SMoriah Waterland if (http_set_password(ps->hps, WEB_CA_PHRASE) != 0) { 17505c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 17515c51f124SMoriah Waterland gettext(ERR_HTTPS_PASSWD)); 17525c51f124SMoriah Waterland ret = WEB_VERIFY_SETUP; 17535c51f124SMoriah Waterland goto cleanup; 17545c51f124SMoriah Waterland } 17555c51f124SMoriah Waterland 17565c51f124SMoriah Waterland if (http_set_certificate_authority_file(path) != 0) { 17575c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 17585c51f124SMoriah Waterland gettext(ERR_HTTPS_CA)); 17595c51f124SMoriah Waterland ret = WEB_VERIFY_SETUP; 17605c51f124SMoriah Waterland goto cleanup; 17615c51f124SMoriah Waterland } 17625c51f124SMoriah Waterland } 17635c51f124SMoriah Waterland 17645c51f124SMoriah Waterland if (http_srv_connect(ps->hps) != 0) { 17655c51f124SMoriah Waterland while ((errcode = http_get_lasterr(ps->hps, &errsrc)) != 0) { 17665c51f124SMoriah Waterland /* Have an error - is it EINTR? */ 17675c51f124SMoriah Waterland if (errsrc == ERRSRC_SYSTEM) { 17685c51f124SMoriah Waterland my_errno = errcode; 17695c51f124SMoriah Waterland break; 17705c51f124SMoriah Waterland } else if (libhttperr == NULL) { 17715c51f124SMoriah Waterland /* save the first non-system error message */ 17725c51f124SMoriah Waterland libhttperr = http_errorstr(errsrc, errcode); 17735c51f124SMoriah Waterland } 17745c51f124SMoriah Waterland } 17755c51f124SMoriah Waterland switch (my_errno) { 17765c51f124SMoriah Waterland case EINTR: 17775c51f124SMoriah Waterland case ETIMEDOUT: 17785c51f124SMoriah Waterland /* Timed out. Try, try again */ 17795c51f124SMoriah Waterland ret = WEB_TIMEOUT; 17805c51f124SMoriah Waterland break; 17815c51f124SMoriah Waterland case ECONNREFUSED: 17825c51f124SMoriah Waterland ret = WEB_CONNREFUSED; 17835c51f124SMoriah Waterland break; 17845c51f124SMoriah Waterland case EHOSTDOWN: 17855c51f124SMoriah Waterland ret = WEB_HOSTDOWN; 17865c51f124SMoriah Waterland break; 17875c51f124SMoriah Waterland default: 17885c51f124SMoriah Waterland /* some other fatal error */ 17895c51f124SMoriah Waterland ret = WEB_NOCONNECT; 17905c51f124SMoriah Waterland if (libhttperr == NULL) { 17915c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 17925c51f124SMoriah Waterland gettext(ERR_INIT_CONN), 17935c51f124SMoriah Waterland ps->url.hport.hostname); 17945c51f124SMoriah Waterland } else { 17955c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 17965c51f124SMoriah Waterland gettext(ERR_HTTP), libhttperr); 17975c51f124SMoriah Waterland } 17985c51f124SMoriah Waterland break; 17995c51f124SMoriah Waterland } 18005c51f124SMoriah Waterland } 18015c51f124SMoriah Waterland cleanup: 18025c51f124SMoriah Waterland return (ret); 18035c51f124SMoriah Waterland } 18045c51f124SMoriah Waterland 18055c51f124SMoriah Waterland /* 18065c51f124SMoriah Waterland * Name: write_ca_file 18075c51f124SMoriah Waterland * Description: Writes out a PKCS12 file containing all trusted certs 18085c51f124SMoriah Waterland * found in keystore recorded in static 'ps' structure 18095c51f124SMoriah Waterland * 18105c51f124SMoriah Waterland * This routine is used because the libwanboot library's 18115c51f124SMoriah Waterland * HTTPS routines cannot accept trusted certificates 18125c51f124SMoriah Waterland * through an in-memory structure, when initiating an 18135c51f124SMoriah Waterland * SSL connection. They must be in a PKCS12, which is 18145c51f124SMoriah Waterland * admittedly a poor interface. 18155c51f124SMoriah Waterland * 18165c51f124SMoriah Waterland * Arguments: err - where to record any errors. 18175c51f124SMoriah Waterland * tmpdir - Directory to write certificate file in 18185c51f124SMoriah Waterland * cacerts - Certs to write out 18195c51f124SMoriah Waterland * passwd - password used to encrypt certs 18205c51f124SMoriah Waterland * 18215c51f124SMoriah Waterland * Returns : path to resulting file, if successfullly written, 18225c51f124SMoriah Waterland * otherwise NULL. 18235c51f124SMoriah Waterland */ 18245c51f124SMoriah Waterland static char 18255c51f124SMoriah Waterland *write_ca_file(PKG_ERR *err, char *tmpdir, STACK_OF(X509) *cacerts, 18265c51f124SMoriah Waterland char *passwd) 18275c51f124SMoriah Waterland { 18285c51f124SMoriah Waterland int fd, len; 18295c51f124SMoriah Waterland FILE *fp; 18305c51f124SMoriah Waterland PKCS12 *p12 = NULL; 18315c51f124SMoriah Waterland char *ret = NULL; 18325c51f124SMoriah Waterland static char tmp_file[PATH_MAX] = ""; 18335c51f124SMoriah Waterland struct stat buf; 18345c51f124SMoriah Waterland 18355c51f124SMoriah Waterland if (!path_valid(tmpdir)) { 18365c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), tmpdir); 18375c51f124SMoriah Waterland goto cleanup; 18385c51f124SMoriah Waterland } 18395c51f124SMoriah Waterland 18405c51f124SMoriah Waterland /* mkstemp replaces XXXXXX with a unique string */ 18415c51f124SMoriah Waterland if (((len = snprintf(tmp_file, PATH_MAX, "%s/%sXXXXXX", tmpdir, 18425c51f124SMoriah Waterland "cert")) < 0) || 18435c51f124SMoriah Waterland (len >= PATH_MAX)) { 18445c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), tmpdir); 18455c51f124SMoriah Waterland goto cleanup; 18465c51f124SMoriah Waterland } 18475c51f124SMoriah Waterland 18485c51f124SMoriah Waterland if ((fd = mkstemp(tmp_file)) == -1) { 18495c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTMPFIL), tmp_file); 18505c51f124SMoriah Waterland goto cleanup; 18515c51f124SMoriah Waterland } 18525c51f124SMoriah Waterland 18535c51f124SMoriah Waterland if (fstat(fd, &buf) == -1) { 18545c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTMPFIL), tmp_file); 18555c51f124SMoriah Waterland goto cleanup; 18565c51f124SMoriah Waterland } 18575c51f124SMoriah Waterland 18585c51f124SMoriah Waterland if (!S_ISREG(buf.st_mode)) { 18595c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTMPFIL), tmp_file); 18605c51f124SMoriah Waterland goto cleanup; 18615c51f124SMoriah Waterland } 18625c51f124SMoriah Waterland 18635c51f124SMoriah Waterland if ((fp = fdopen(fd, "w")) == NULL) { 18645c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTMPFIL), tmp_file); 18655c51f124SMoriah Waterland goto cleanup; 18665c51f124SMoriah Waterland } 18675c51f124SMoriah Waterland 18685c51f124SMoriah Waterland if ((p12 = sunw_PKCS12_create(passwd, NULL, NULL, cacerts)) == NULL) { 18695c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 18705c51f124SMoriah Waterland gettext(ERR_KEYSTORE_FORM), tmp_file); 18715c51f124SMoriah Waterland goto cleanup; 18725c51f124SMoriah Waterland } 18735c51f124SMoriah Waterland 18745c51f124SMoriah Waterland if (i2d_PKCS12_fp(fp, p12) == 0) { 18755c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 18765c51f124SMoriah Waterland gettext(ERR_KEYSTORE_FORM), tmp_file); 18775c51f124SMoriah Waterland goto cleanup; 18785c51f124SMoriah Waterland } 18795c51f124SMoriah Waterland 18805c51f124SMoriah Waterland (void) fflush(fp); 18815c51f124SMoriah Waterland (void) fclose(fp); 18825c51f124SMoriah Waterland (void) close(fd); 18835c51f124SMoriah Waterland fp = NULL; 18845c51f124SMoriah Waterland fd = -1; 18855c51f124SMoriah Waterland ret = tmp_file; 18865c51f124SMoriah Waterland 18875c51f124SMoriah Waterland cleanup: 18885c51f124SMoriah Waterland if (p12 != NULL) 18895c51f124SMoriah Waterland PKCS12_free(p12); 18905c51f124SMoriah Waterland if (fp != NULL) 18915c51f124SMoriah Waterland (void) fclose(fp); 18925c51f124SMoriah Waterland if (fd != -1) { 18935c51f124SMoriah Waterland (void) close(fd); 18945c51f124SMoriah Waterland (void) unlink(tmp_file); 18955c51f124SMoriah Waterland } 18965c51f124SMoriah Waterland 18975c51f124SMoriah Waterland return (ret); 18985c51f124SMoriah Waterland } 18995c51f124SMoriah Waterland 19005c51f124SMoriah Waterland /* 19015c51f124SMoriah Waterland * Name: web_send_request 19025c51f124SMoriah Waterland * Description: Sends an HTTP request for a file to the 19035c51f124SMoriah Waterland * web server being communicated with in the static 19045c51f124SMoriah Waterland * 'ps' structure 19055c51f124SMoriah Waterland * 19065c51f124SMoriah Waterland * Arguments: err - where to record any errors. 19075c51f124SMoriah Waterland * request_type - HTTP_REQ_TYPE_HEAD to send an HTTP HEAD request, 19085c51f124SMoriah Waterland * or HTTP_REQ_TYPE_GET to send an HTTP GET request 19095c51f124SMoriah Waterland * cp - 19105c51f124SMoriah Waterland * Returns : WEB_OK - request sent successfully 19115c51f124SMoriah Waterland * WEB_CONNREFUSED - Connection was refused to web site 19125c51f124SMoriah Waterland * WEB_HOSTDOWN - Host was not responding to request 19135c51f124SMoriah Waterland * WEB_NOCONNECT - Some other connection failure 19145c51f124SMoriah Waterland */ 19155c51f124SMoriah Waterland static WebStatus 19165c51f124SMoriah Waterland web_send_request(PKG_ERR *err, int request_type, int cp, int ep) 19175c51f124SMoriah Waterland { 19185c51f124SMoriah Waterland WebStatus ret = WEB_OK; 19195c51f124SMoriah Waterland ulong_t errcode; 19205c51f124SMoriah Waterland uint_t errsrc; 19215c51f124SMoriah Waterland int my_errno = 0; 19225c51f124SMoriah Waterland const char *libhttperr = NULL; 19235c51f124SMoriah Waterland switch (request_type) { 19245c51f124SMoriah Waterland case HTTP_REQ_TYPE_HEAD: 19255c51f124SMoriah Waterland if ((http_head_request(ps->hps, ps->url.abspath)) != 0) { 19265c51f124SMoriah Waterland while ((errcode = http_get_lasterr(ps->hps, 19275c51f124SMoriah Waterland &errsrc)) != 0) { 19285c51f124SMoriah Waterland /* Have an error - is it EINTR? */ 19295c51f124SMoriah Waterland if (errsrc == ERRSRC_SYSTEM) { 19305c51f124SMoriah Waterland my_errno = errcode; 19315c51f124SMoriah Waterland break; 19325c51f124SMoriah Waterland } else if (libhttperr == NULL) { 19335c51f124SMoriah Waterland /* save first non-system error message */ 19345c51f124SMoriah Waterland libhttperr = 19355c51f124SMoriah Waterland http_errorstr(errsrc, errcode); 19365c51f124SMoriah Waterland } 19375c51f124SMoriah Waterland } 19385c51f124SMoriah Waterland switch (my_errno) { 19395c51f124SMoriah Waterland case EINTR: 19405c51f124SMoriah Waterland case ETIMEDOUT: 19415c51f124SMoriah Waterland /* Timed out. Try, try again */ 19425c51f124SMoriah Waterland ret = WEB_TIMEOUT; 19435c51f124SMoriah Waterland break; 19445c51f124SMoriah Waterland case ECONNREFUSED: 19455c51f124SMoriah Waterland ret = WEB_CONNREFUSED; 19465c51f124SMoriah Waterland break; 19475c51f124SMoriah Waterland case EHOSTDOWN: 19485c51f124SMoriah Waterland ret = WEB_HOSTDOWN; 19495c51f124SMoriah Waterland break; 19505c51f124SMoriah Waterland default: 19515c51f124SMoriah Waterland /* some other fatal error */ 19525c51f124SMoriah Waterland ret = WEB_NOCONNECT; 19535c51f124SMoriah Waterland if (libhttperr == NULL) { 19545c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 19555c51f124SMoriah Waterland gettext(ERR_INIT_CONN), 19565c51f124SMoriah Waterland ps->url.hport.hostname); 19575c51f124SMoriah Waterland } else { 19585c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 19595c51f124SMoriah Waterland gettext(ERR_HTTP), libhttperr); 19605c51f124SMoriah Waterland } 19615c51f124SMoriah Waterland break; 19625c51f124SMoriah Waterland } 19635c51f124SMoriah Waterland goto cleanup; 19645c51f124SMoriah Waterland } 19655c51f124SMoriah Waterland break; 19665c51f124SMoriah Waterland 19675c51f124SMoriah Waterland case HTTP_REQ_TYPE_GET: 19685c51f124SMoriah Waterland if (cp && ep) { 19695c51f124SMoriah Waterland if (http_get_range_request(ps->hps, ps->url.abspath, 19705c51f124SMoriah Waterland cp, ep - cp) != 0) { 19715c51f124SMoriah Waterland while ((errcode = http_get_lasterr(ps->hps, 19725c51f124SMoriah Waterland &errsrc)) != 0) { 19735c51f124SMoriah Waterland /* Have an error - is it EINTR? */ 19745c51f124SMoriah Waterland if (errsrc == ERRSRC_SYSTEM) { 19755c51f124SMoriah Waterland my_errno = errcode; 19765c51f124SMoriah Waterland break; 19775c51f124SMoriah Waterland } else { 19785c51f124SMoriah Waterland /* 19795c51f124SMoriah Waterland * save first non-system 19805c51f124SMoriah Waterland * error message 19815c51f124SMoriah Waterland */ 19825c51f124SMoriah Waterland libhttperr = 19835c51f124SMoriah Waterland http_errorstr(errsrc, 19845c51f124SMoriah Waterland errcode); 19855c51f124SMoriah Waterland } 19865c51f124SMoriah Waterland } 19875c51f124SMoriah Waterland switch (my_errno) { 19885c51f124SMoriah Waterland case EINTR: 19895c51f124SMoriah Waterland case ETIMEDOUT: 19905c51f124SMoriah Waterland /* Timed out. Try, try again */ 19915c51f124SMoriah Waterland ret = WEB_TIMEOUT; 19925c51f124SMoriah Waterland break; 19935c51f124SMoriah Waterland case ECONNREFUSED: 19945c51f124SMoriah Waterland ret = WEB_CONNREFUSED; 19955c51f124SMoriah Waterland break; 19965c51f124SMoriah Waterland case EHOSTDOWN: 19975c51f124SMoriah Waterland ret = WEB_HOSTDOWN; 19985c51f124SMoriah Waterland break; 19995c51f124SMoriah Waterland default: 20005c51f124SMoriah Waterland /* some other fatal error */ 20015c51f124SMoriah Waterland ret = WEB_NOCONNECT; 20025c51f124SMoriah Waterland if (libhttperr == NULL) { 20035c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 20045c51f124SMoriah Waterland gettext(ERR_INIT_CONN), 20055c51f124SMoriah Waterland ps->url.hport.hostname); 20065c51f124SMoriah Waterland } else { 20075c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 20085c51f124SMoriah Waterland gettext(ERR_HTTP), 20095c51f124SMoriah Waterland libhttperr); 20105c51f124SMoriah Waterland } 20115c51f124SMoriah Waterland break; 20125c51f124SMoriah Waterland } 20135c51f124SMoriah Waterland goto cleanup; 20145c51f124SMoriah Waterland } 20155c51f124SMoriah Waterland 20165c51f124SMoriah Waterland if (!web_eval_headers(err)) { 20175c51f124SMoriah Waterland ret = WEB_NOCONNECT; 20185c51f124SMoriah Waterland goto cleanup; 20195c51f124SMoriah Waterland } 20205c51f124SMoriah Waterland } else { 20215c51f124SMoriah Waterland if ((http_get_request(ps->hps, ps->url.abspath)) 20225c51f124SMoriah Waterland != 0) { 20235c51f124SMoriah Waterland while ((errcode = http_get_lasterr(ps->hps, 20245c51f124SMoriah Waterland &errsrc)) != 0) { 20255c51f124SMoriah Waterland /* Have an error - is it EINTR? */ 20265c51f124SMoriah Waterland if (errsrc == ERRSRC_SYSTEM) { 20275c51f124SMoriah Waterland my_errno = errcode; 20285c51f124SMoriah Waterland break; 20295c51f124SMoriah Waterland } else { 20305c51f124SMoriah Waterland /* 20315c51f124SMoriah Waterland * save the first non-system 20325c51f124SMoriah Waterland * error message 20335c51f124SMoriah Waterland */ 20345c51f124SMoriah Waterland libhttperr = 20355c51f124SMoriah Waterland http_errorstr(errsrc, 20365c51f124SMoriah Waterland errcode); 20375c51f124SMoriah Waterland } 20385c51f124SMoriah Waterland } 20395c51f124SMoriah Waterland switch (my_errno) { 20405c51f124SMoriah Waterland case EINTR: 20415c51f124SMoriah Waterland case ETIMEDOUT: 20425c51f124SMoriah Waterland /* Timed out. Try, try again */ 20435c51f124SMoriah Waterland ret = WEB_TIMEOUT; 20445c51f124SMoriah Waterland break; 20455c51f124SMoriah Waterland case ECONNREFUSED: 20465c51f124SMoriah Waterland ret = WEB_CONNREFUSED; 20475c51f124SMoriah Waterland break; 20485c51f124SMoriah Waterland case EHOSTDOWN: 20495c51f124SMoriah Waterland ret = WEB_HOSTDOWN; 20505c51f124SMoriah Waterland break; 20515c51f124SMoriah Waterland default: 20525c51f124SMoriah Waterland /* some other fatal error */ 20535c51f124SMoriah Waterland ret = WEB_NOCONNECT; 20545c51f124SMoriah Waterland if (libhttperr == NULL) { 20555c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 20565c51f124SMoriah Waterland gettext(ERR_INIT_CONN), 20575c51f124SMoriah Waterland ps->url.hport.hostname); 20585c51f124SMoriah Waterland } else { 20595c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 20605c51f124SMoriah Waterland gettext(ERR_HTTP), 20615c51f124SMoriah Waterland libhttperr); 20625c51f124SMoriah Waterland } 20635c51f124SMoriah Waterland break; 20645c51f124SMoriah Waterland } 20655c51f124SMoriah Waterland goto cleanup; 20665c51f124SMoriah Waterland } 20675c51f124SMoriah Waterland 20685c51f124SMoriah Waterland if (!web_eval_headers(err)) { 20695c51f124SMoriah Waterland ret = WEB_NOCONNECT; 20705c51f124SMoriah Waterland goto cleanup; 20715c51f124SMoriah Waterland } 20725c51f124SMoriah Waterland } 20735c51f124SMoriah Waterland break; 20745c51f124SMoriah Waterland default: 20755c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, gettext(ERR_PKG_INTERNAL), 20765c51f124SMoriah Waterland __FILE__, __LINE__); 20775c51f124SMoriah Waterland } 20785c51f124SMoriah Waterland 20795c51f124SMoriah Waterland cleanup: 20805c51f124SMoriah Waterland return (ret); 20815c51f124SMoriah Waterland } 20825c51f124SMoriah Waterland 20835c51f124SMoriah Waterland /* 20845c51f124SMoriah Waterland * Name: web_eval_headers 20855c51f124SMoriah Waterland * Description: Evaluates HTTP headers returned during an HTTP request. 20865c51f124SMoriah Waterland * This must be called before calling 20875c51f124SMoriah Waterland * http_get_header_value(). 20885c51f124SMoriah Waterland * 20895c51f124SMoriah Waterland * Arguments: err - where to record any errors. 20905c51f124SMoriah Waterland * 20915c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 20925c51f124SMoriah Waterland */ 20935c51f124SMoriah Waterland static boolean_t 20945c51f124SMoriah Waterland web_eval_headers(PKG_ERR *err) 20955c51f124SMoriah Waterland { 20965c51f124SMoriah Waterland const char *http_err; 20975c51f124SMoriah Waterland ulong_t herr; 20985c51f124SMoriah Waterland uint_t errsrc; 20995c51f124SMoriah Waterland 21005c51f124SMoriah Waterland if (http_process_headers(ps->hps, &ps->resp) != 0) { 21015c51f124SMoriah Waterland if ((ps->resp != NULL) && (ps->resp->statusmsg != NULL)) { 21025c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_HTTP), 21035c51f124SMoriah Waterland ps->resp->statusmsg); 21045c51f124SMoriah Waterland } 21055c51f124SMoriah Waterland 21065c51f124SMoriah Waterland herr = http_get_lasterr(ps->hps, &errsrc); 21075c51f124SMoriah Waterland http_err = http_errorstr(errsrc, herr); 21085c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_HTTP), 21095c51f124SMoriah Waterland http_err); 21105c51f124SMoriah Waterland return (B_FALSE); 21115c51f124SMoriah Waterland } 21125c51f124SMoriah Waterland return (B_TRUE); 21135c51f124SMoriah Waterland } 21145c51f124SMoriah Waterland 21155c51f124SMoriah Waterland /* 21165c51f124SMoriah Waterland * Name: web_get_file 21175c51f124SMoriah Waterland * Description: Downloads the file URL from the website, all of 21185c51f124SMoriah Waterland * which are recorded in the static 'ps' struct 21195c51f124SMoriah Waterland * 21205c51f124SMoriah Waterland * Arguments: err - where to record any errors. 21215c51f124SMoriah Waterland * dwnld_dir - Directory to download file into 21225c51f124SMoriah Waterland * device - Where to store path to resulting 21235c51f124SMoriah Waterland * file 21245c51f124SMoriah Waterland * nointeract - if non-zero, do not output 21255c51f124SMoriah Waterland * progress 21265c51f124SMoriah Waterland * fname - name of downloaded file link in the dwnld_dir 21275c51f124SMoriah Waterland * 21285c51f124SMoriah Waterland * Returns : WEB_OK - download successful 21295c51f124SMoriah Waterland * WEB_CONNREFUSED - Connection was refused to web site 21305c51f124SMoriah Waterland * WEB_HOSTDOWN - Host was not responding to request 21315c51f124SMoriah Waterland * WEB_GET_FAIL - Unable to initialize download 21325c51f124SMoriah Waterland * state (temp file creation, header parsing, etc) 21335c51f124SMoriah Waterland * WEB_NOCONNECT - Some other connection failure 21345c51f124SMoriah Waterland */ 21355c51f124SMoriah Waterland static WebStatus 21365c51f124SMoriah Waterland web_get_file(PKG_ERR *err, char *dwnld_dir, int nointeract, char **fname) 21375c51f124SMoriah Waterland { 21385c51f124SMoriah Waterland int i, fd; 21395c51f124SMoriah Waterland int n = 0; 21405c51f124SMoriah Waterland ulong_t abs_pos = 0; 21415c51f124SMoriah Waterland char *head_val = NULL; 21425c51f124SMoriah Waterland char *lastmod_val = NULL; 21435c51f124SMoriah Waterland char *bname = NULL; 21445c51f124SMoriah Waterland struct stat status; 21455c51f124SMoriah Waterland WebStatus ret = WEB_OK; 21465c51f124SMoriah Waterland WebStatus req_ret; 21475c51f124SMoriah Waterland ulong_t errcode; 21485c51f124SMoriah Waterland uint_t errsrc; 21495c51f124SMoriah Waterland int my_errno = 0; 21505c51f124SMoriah Waterland const char *libhttperr = NULL; 21515c51f124SMoriah Waterland char *disp; 21525c51f124SMoriah Waterland char tmp_file[PATH_MAX]; 21535c51f124SMoriah Waterland int len; 21545c51f124SMoriah Waterland 21555c51f124SMoriah Waterland ps->data.prev_cont_length = 21565c51f124SMoriah Waterland ps->data.content_length = 21575c51f124SMoriah Waterland ps->data.cur_pos = 0; 21585c51f124SMoriah Waterland 21595c51f124SMoriah Waterland if ((head_val = http_get_header_value(ps->hps, 21605c51f124SMoriah Waterland CONTENT_LENGTH_HDR)) != NULL) { 21615c51f124SMoriah Waterland ps->data.content_length = atol(head_val); 21625c51f124SMoriah Waterland } else { 21635c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_NO_HEAD_VAL), 21645c51f124SMoriah Waterland CONTENT_LENGTH_HDR); 21655c51f124SMoriah Waterland ret = WEB_GET_FAIL; 21665c51f124SMoriah Waterland goto cleanup; 21675c51f124SMoriah Waterland } 21685c51f124SMoriah Waterland 21695c51f124SMoriah Waterland free(head_val); 21705c51f124SMoriah Waterland head_val = NULL; 21715c51f124SMoriah Waterland 21725c51f124SMoriah Waterland if ((head_val = http_get_header_value(ps->hps, 21735c51f124SMoriah Waterland CONTENT_DISPOSITION_HDR)) != NULL) { 21745c51f124SMoriah Waterland /* "inline; parm=val; parm=val */ 21755c51f124SMoriah Waterland if ((disp = strtok(head_val, "; \t\n\f\r")) != NULL) { 21765c51f124SMoriah Waterland /* disp = "inline" */ 21775c51f124SMoriah Waterland while ((disp = strtok(NULL, "; \t\n\f\r")) != NULL) { 21785c51f124SMoriah Waterland /* disp = "parm=val" */ 21795c51f124SMoriah Waterland if (ci_strneq(disp, "filename=", 9)) { 21805c51f124SMoriah Waterland bname = xstrdup(basename(disp + 9)); 21815c51f124SMoriah Waterland trim(bname); 21825c51f124SMoriah Waterland dequote(bname); 21835c51f124SMoriah Waterland } 21845c51f124SMoriah Waterland } 21855c51f124SMoriah Waterland } 21865c51f124SMoriah Waterland free(head_val); 21875c51f124SMoriah Waterland head_val = NULL; 21885c51f124SMoriah Waterland } 21895c51f124SMoriah Waterland 21905c51f124SMoriah Waterland if (bname == NULL) { 21915c51f124SMoriah Waterland /* 21925c51f124SMoriah Waterland * couldn't determine filename from header value, 21935c51f124SMoriah Waterland * so take basename of URL 21945c51f124SMoriah Waterland */ 21955c51f124SMoriah Waterland if ((bname = get_endof_string(ps->url.abspath, '/')) == NULL) { 21965c51f124SMoriah Waterland /* URL is bad */ 21975c51f124SMoriah Waterland pkgerr_add(err, PKGERR_PARSE, 21985c51f124SMoriah Waterland gettext(ERR_PARSE_URL), ps->url.abspath); 21995c51f124SMoriah Waterland ret = WEB_GET_FAIL; 22005c51f124SMoriah Waterland goto cleanup; 22015c51f124SMoriah Waterland } 22025c51f124SMoriah Waterland } 22035c51f124SMoriah Waterland 22045c51f124SMoriah Waterland *fname = bname; 22055c51f124SMoriah Waterland 22065c51f124SMoriah Waterland if ((head_val = http_get_header_value(ps->hps, LAST_MODIFIED_HDR)) 22075c51f124SMoriah Waterland != NULL) { 22085c51f124SMoriah Waterland 22095c51f124SMoriah Waterland if ((lastmod_val = condense_lastmodified(head_val)) == NULL) { 22105c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_BAD_HEAD_VAL), 22115c51f124SMoriah Waterland LAST_MODIFIED_HDR, head_val); 22125c51f124SMoriah Waterland ret = WEB_GET_FAIL; 22135c51f124SMoriah Waterland goto cleanup; 22145c51f124SMoriah Waterland } 22155c51f124SMoriah Waterland free(head_val); 22165c51f124SMoriah Waterland head_val = NULL; 22175c51f124SMoriah Waterland 22185c51f124SMoriah Waterland if ((ps->uniqfile = get_unique_filename(dwnld_dir, 22195c51f124SMoriah Waterland lastmod_val)) == NULL) { 22205c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_OPEN_TMP)); 22215c51f124SMoriah Waterland ret = WEB_GET_FAIL; 22225c51f124SMoriah Waterland goto cleanup; 22235c51f124SMoriah Waterland } 22245c51f124SMoriah Waterland 22255c51f124SMoriah Waterland free(lastmod_val); 22265c51f124SMoriah Waterland lastmod_val = NULL; 22275c51f124SMoriah Waterland 22285c51f124SMoriah Waterland if ((fd = open(ps->uniqfile, 22295c51f124SMoriah Waterland O_NONBLOCK|O_RDWR|O_APPEND|O_CREAT|O_EXCL, 22305c51f124SMoriah Waterland 640)) == -1) { 22315c51f124SMoriah Waterland 22325c51f124SMoriah Waterland /* 22335c51f124SMoriah Waterland * A partial downloaded file 22345c51f124SMoriah Waterland * already exists, so open it. 22355c51f124SMoriah Waterland */ 22365c51f124SMoriah Waterland if ((fd = open(ps->uniqfile, 22375c51f124SMoriah Waterland O_NONBLOCK|O_RDWR|O_APPEND)) != -1) { 22385c51f124SMoriah Waterland if (fstat(fd, &status) == -1 || 22395c51f124SMoriah Waterland !S_ISREG(status.st_mode)) { 22405c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 22415c51f124SMoriah Waterland gettext(ERR_DWNLD_NO_CONT), 22425c51f124SMoriah Waterland ps->uniqfile); 22435c51f124SMoriah Waterland ret = WEB_GET_FAIL; 22445c51f124SMoriah Waterland goto cleanup; 22455c51f124SMoriah Waterland } else { 22465c51f124SMoriah Waterland echo_out(nointeract, 22475c51f124SMoriah Waterland gettext(MSG_DWNLD_PART), 22485c51f124SMoriah Waterland ps->uniqfile, 22495c51f124SMoriah Waterland status.st_size); 22505c51f124SMoriah Waterland ps->data.prev_cont_length = 22515c51f124SMoriah Waterland status.st_size; 22525c51f124SMoriah Waterland } 22535c51f124SMoriah Waterland } else { 22545c51f124SMoriah Waterland /* unable to open partial file */ 22555c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 22565c51f124SMoriah Waterland gettext(ERR_DWNLD_NO_CONT), 22575c51f124SMoriah Waterland ps->uniqfile); 22585c51f124SMoriah Waterland ret = WEB_GET_FAIL; 22595c51f124SMoriah Waterland goto cleanup; 22605c51f124SMoriah Waterland } 22615c51f124SMoriah Waterland } 22625c51f124SMoriah Waterland } else { 22635c51f124SMoriah Waterland /* 22645c51f124SMoriah Waterland * no "Last-Modified" header, so this file is not eligible for 22655c51f124SMoriah Waterland * spooling and "resuming last download" operations 22665c51f124SMoriah Waterland */ 22675c51f124SMoriah Waterland ps->spool = B_FALSE; 22685c51f124SMoriah Waterland 22695c51f124SMoriah Waterland /* mkstemp replaces XXXXXX with a unique string */ 22705c51f124SMoriah Waterland if (((len = snprintf(tmp_file, PATH_MAX, 22715c51f124SMoriah Waterland "%s/%sXXXXXX", dwnld_dir, "stream")) < 0) || 22725c51f124SMoriah Waterland (len >= PATH_MAX)) { 22735c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 22745c51f124SMoriah Waterland gettext(MSG_NOTEMP), dwnld_dir); 22755c51f124SMoriah Waterland ret = WEB_GET_FAIL; 22765c51f124SMoriah Waterland goto cleanup; 22775c51f124SMoriah Waterland } 22785c51f124SMoriah Waterland 22795c51f124SMoriah Waterland if ((fd = mkstemp(tmp_file)) == -1) { 22805c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 22815c51f124SMoriah Waterland gettext(MSG_NOTMPFIL), tmp_file); 22825c51f124SMoriah Waterland ret = WEB_GET_FAIL; 22835c51f124SMoriah Waterland goto cleanup; 22845c51f124SMoriah Waterland } 22855c51f124SMoriah Waterland 22865c51f124SMoriah Waterland if (fstat(fd, &status) == -1 || 22875c51f124SMoriah Waterland !S_ISREG(status.st_mode)) { 22885c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 22895c51f124SMoriah Waterland gettext(ERR_DWNLD_NO_CONT), 22905c51f124SMoriah Waterland ps->uniqfile); 22915c51f124SMoriah Waterland ret = WEB_GET_FAIL; 22925c51f124SMoriah Waterland goto cleanup; 22935c51f124SMoriah Waterland } 22945c51f124SMoriah Waterland 22955c51f124SMoriah Waterland ps->data.prev_cont_length = 0; 22965c51f124SMoriah Waterland ps->uniqfile = xstrdup(tmp_file); 22975c51f124SMoriah Waterland } 22985c51f124SMoriah Waterland 22995c51f124SMoriah Waterland /* File has already been completely downloaded */ 23005c51f124SMoriah Waterland if (ps->data.prev_cont_length == ps->data.content_length) { 23015c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_PREV), ps->uniqfile); 23025c51f124SMoriah Waterland ps->data.cur_pos = ps->data.prev_cont_length; 23035c51f124SMoriah Waterland if (!make_link(dwnld_dir, bname)) { 23045c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), 23055c51f124SMoriah Waterland dwnld_dir); 23065c51f124SMoriah Waterland ret = WEB_GET_FAIL; 23075c51f124SMoriah Waterland goto cleanup; 23085c51f124SMoriah Waterland } 23095c51f124SMoriah Waterland /* we're done, so cleanup and return success */ 23105c51f124SMoriah Waterland goto cleanup; 23115c51f124SMoriah Waterland } else if (ps->data.prev_cont_length != 0) { 23125c51f124SMoriah Waterland ps->data.cur_pos = ps->data.prev_cont_length; 23135c51f124SMoriah Waterland } 23145c51f124SMoriah Waterland 23155c51f124SMoriah Waterland if (!ck_dwnld_dir_space(err, dwnld_dir, 23165c51f124SMoriah Waterland (ps->data.prev_cont_length != 0) ? 23175c51f124SMoriah Waterland (ps->data.content_length - ps->data.cur_pos) : 23185c51f124SMoriah Waterland ps->data.content_length)) { 23195c51f124SMoriah Waterland ret = WEB_GET_FAIL; 23205c51f124SMoriah Waterland goto cleanup; 23215c51f124SMoriah Waterland } 23225c51f124SMoriah Waterland 23235c51f124SMoriah Waterland if ((req_ret = web_send_request(err, HTTP_REQ_TYPE_GET, 23245c51f124SMoriah Waterland ps->data.cur_pos, ps->data.content_length)) != WEB_OK) { 23255c51f124SMoriah Waterland ret = req_ret; 23265c51f124SMoriah Waterland goto cleanup; 23275c51f124SMoriah Waterland } 23285c51f124SMoriah Waterland 23295c51f124SMoriah Waterland if (ps->data.prev_cont_length != 0) 23305c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_CONT)); 23315c51f124SMoriah Waterland else 23325c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD)); 23335c51f124SMoriah Waterland 23345c51f124SMoriah Waterland progress_setup(nointeract, ps->data.content_length); 23355c51f124SMoriah Waterland 23365c51f124SMoriah Waterland /* Download the file a BLOCK at a time */ 23375c51f124SMoriah Waterland while (ps->data.cur_pos < ps->data.content_length) { 23385c51f124SMoriah Waterland progress_report(nointeract, abs_pos); 23395c51f124SMoriah Waterland i = ((ps->data.content_length - ps->data.cur_pos) < BLOCK) ? 23405c51f124SMoriah Waterland (ps->data.content_length - ps->data.cur_pos) 23415c51f124SMoriah Waterland : BLOCK; 23425c51f124SMoriah Waterland if ((n = http_read_body(ps->hps, ps->content, i)) <= 0) { 23435c51f124SMoriah Waterland while ((errcode = http_get_lasterr(ps->hps, 23445c51f124SMoriah Waterland &errsrc)) != 0) { 23455c51f124SMoriah Waterland /* Have an error - is it EINTR? */ 23465c51f124SMoriah Waterland if (errsrc == ERRSRC_SYSTEM) { 23475c51f124SMoriah Waterland my_errno = errcode; 23485c51f124SMoriah Waterland break; 23495c51f124SMoriah Waterland } else { 23505c51f124SMoriah Waterland /* 23515c51f124SMoriah Waterland * save first non-system 23525c51f124SMoriah Waterland * error message 23535c51f124SMoriah Waterland */ 23545c51f124SMoriah Waterland libhttperr = 23555c51f124SMoriah Waterland http_errorstr(errsrc, errcode); 23565c51f124SMoriah Waterland } 23575c51f124SMoriah Waterland } 23585c51f124SMoriah Waterland switch (my_errno) { 23595c51f124SMoriah Waterland case EINTR: 23605c51f124SMoriah Waterland case ETIMEDOUT: 23615c51f124SMoriah Waterland /* Timed out. Try, try again */ 23625c51f124SMoriah Waterland ret = WEB_TIMEOUT; 23635c51f124SMoriah Waterland break; 23645c51f124SMoriah Waterland case ECONNREFUSED: 23655c51f124SMoriah Waterland ret = WEB_CONNREFUSED; 23665c51f124SMoriah Waterland break; 23675c51f124SMoriah Waterland case EHOSTDOWN: 23685c51f124SMoriah Waterland ret = WEB_HOSTDOWN; 23695c51f124SMoriah Waterland break; 23705c51f124SMoriah Waterland default: 23715c51f124SMoriah Waterland /* some other fatal error */ 23725c51f124SMoriah Waterland ret = WEB_NOCONNECT; 23735c51f124SMoriah Waterland if (libhttperr == NULL) { 23745c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 23755c51f124SMoriah Waterland gettext(ERR_INIT_CONN), 23765c51f124SMoriah Waterland ps->url.hport.hostname); 23775c51f124SMoriah Waterland } else { 23785c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 23795c51f124SMoriah Waterland gettext(ERR_HTTP), libhttperr); 23805c51f124SMoriah Waterland } 23815c51f124SMoriah Waterland break; 23825c51f124SMoriah Waterland } 23835c51f124SMoriah Waterland goto cleanup; 23845c51f124SMoriah Waterland } 23855c51f124SMoriah Waterland if ((n = write(fd, ps->content, n)) == 0) { 23865c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_WRITE), 23875c51f124SMoriah Waterland ps->uniqfile, strerror(errno)); 23885c51f124SMoriah Waterland ret = WEB_GET_FAIL; 23895c51f124SMoriah Waterland goto cleanup; 23905c51f124SMoriah Waterland } 23915c51f124SMoriah Waterland ps->data.cur_pos += n; 23925c51f124SMoriah Waterland abs_pos += n; 23935c51f124SMoriah Waterland } 23945c51f124SMoriah Waterland 23955c51f124SMoriah Waterland progress_finish(nointeract); 23965c51f124SMoriah Waterland echo_out(nointeract, gettext(MSG_DWNLD_COMPLETE)); 23975c51f124SMoriah Waterland 23985c51f124SMoriah Waterland if (!make_link(dwnld_dir, bname)) { 23995c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), 24005c51f124SMoriah Waterland dwnld_dir); 24015c51f124SMoriah Waterland ret = WEB_GET_FAIL; 24025c51f124SMoriah Waterland goto cleanup; 24035c51f124SMoriah Waterland } 24045c51f124SMoriah Waterland 24055c51f124SMoriah Waterland cleanup: 24065c51f124SMoriah Waterland sync(); 24075c51f124SMoriah Waterland if (fd != -1) { 24085c51f124SMoriah Waterland (void) close(fd); 24095c51f124SMoriah Waterland } 24105c51f124SMoriah Waterland 24115c51f124SMoriah Waterland if (head_val != NULL) 24125c51f124SMoriah Waterland free(head_val); 24135c51f124SMoriah Waterland 24145c51f124SMoriah Waterland if (lastmod_val != NULL) 24155c51f124SMoriah Waterland free(lastmod_val); 24165c51f124SMoriah Waterland 24175c51f124SMoriah Waterland return (ret); 24185c51f124SMoriah Waterland } 24195c51f124SMoriah Waterland 24205c51f124SMoriah Waterland /* 24215c51f124SMoriah Waterland * Name: make_link 24225c51f124SMoriah Waterland * Description: Create new link to file being downloaded 24235c51f124SMoriah Waterland * 24245c51f124SMoriah Waterland * Arguments: dwnld_dir - directory in which downloaded file exists 24255c51f124SMoriah Waterland * bname - name of link 24265c51f124SMoriah Waterland * 24275c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 24285c51f124SMoriah Waterland */ 24295c51f124SMoriah Waterland static boolean_t 24305c51f124SMoriah Waterland make_link(char *dwnld_dir, char *bname) 24315c51f124SMoriah Waterland { 24325c51f124SMoriah Waterland int len; 24335c51f124SMoriah Waterland 24345c51f124SMoriah Waterland if ((ps->link = (char *)xmalloc(PATH_MAX)) == NULL) 24355c51f124SMoriah Waterland return (B_FALSE); 24365c51f124SMoriah Waterland if (((len = snprintf(ps->link, PATH_MAX, "%s/%s", 24375c51f124SMoriah Waterland dwnld_dir, bname)) < 0) || 24385c51f124SMoriah Waterland len >= PATH_MAX) 24395c51f124SMoriah Waterland return (B_FALSE); 24405c51f124SMoriah Waterland 24415c51f124SMoriah Waterland (void) link(ps->uniqfile, ps->link); 24425c51f124SMoriah Waterland 24435c51f124SMoriah Waterland return (B_TRUE); 24445c51f124SMoriah Waterland } 24455c51f124SMoriah Waterland 24465c51f124SMoriah Waterland /* 24475c51f124SMoriah Waterland * Name: get_startof_string 24485c51f124SMoriah Waterland * Description: searches string for token, returns a newly-allocated 24495c51f124SMoriah Waterland * substring of the given string up to, but not 24505c51f124SMoriah Waterland * including, token. for example 24515c51f124SMoriah Waterland * get_startof_string("abcd", 'c') will return "ab" 24525c51f124SMoriah Waterland * 24535c51f124SMoriah Waterland * Arguments: path - path to split 24545c51f124SMoriah Waterland * token - character to split on 24555c51f124SMoriah Waterland * 24565c51f124SMoriah Waterland * Returns : substring of 'path', up to, but not including, 24575c51f124SMoriah Waterland * token, if token appears in path. Otherwise, 24585c51f124SMoriah Waterland * returns NULL. 24595c51f124SMoriah Waterland */ 24605c51f124SMoriah Waterland char * 24615c51f124SMoriah Waterland get_startof_string(char *path, char token) 24625c51f124SMoriah Waterland { 24635c51f124SMoriah Waterland char *p, *p2; 24645c51f124SMoriah Waterland 24655c51f124SMoriah Waterland if (path == NULL) 24665c51f124SMoriah Waterland return (NULL); 24675c51f124SMoriah Waterland 24685c51f124SMoriah Waterland p = xstrdup(path); 24695c51f124SMoriah Waterland 24705c51f124SMoriah Waterland p2 = strchr(p, token); 24715c51f124SMoriah Waterland if (p2 == NULL) { 24725c51f124SMoriah Waterland free(p); 24735c51f124SMoriah Waterland return (NULL); 24745c51f124SMoriah Waterland } else { 24755c51f124SMoriah Waterland *p2 = '\0'; 24765c51f124SMoriah Waterland return (p); 24775c51f124SMoriah Waterland } 24785c51f124SMoriah Waterland } 24795c51f124SMoriah Waterland 24805c51f124SMoriah Waterland /* 24815c51f124SMoriah Waterland * Name: get_endof_string 24825c51f124SMoriah Waterland * Description: searches string for token, returns a 24835c51f124SMoriah Waterland * newly-allocated substring of the given string, 24845c51f124SMoriah Waterland * starting at character following token, to end of 24855c51f124SMoriah Waterland * string. 24865c51f124SMoriah Waterland * 24875c51f124SMoriah Waterland * for example get_end_string("abcd", 'c') 24885c51f124SMoriah Waterland * will return "d" 24895c51f124SMoriah Waterland * 24905c51f124SMoriah Waterland * Arguments: path - path to split 24915c51f124SMoriah Waterland * token - character to split on 24925c51f124SMoriah Waterland * 24935c51f124SMoriah Waterland * Returns : substring of 'path', beginning at character 24945c51f124SMoriah Waterland * following token, to end of string, if 24955c51f124SMoriah Waterland * token appears in path. Otherwise, 24965c51f124SMoriah Waterland * returns NULL. 24975c51f124SMoriah Waterland */ 24985c51f124SMoriah Waterland char * 24995c51f124SMoriah Waterland get_endof_string(char *path, char token) 25005c51f124SMoriah Waterland { 25015c51f124SMoriah Waterland char *p, *p2; 25025c51f124SMoriah Waterland 25035c51f124SMoriah Waterland if (path == NULL) 25045c51f124SMoriah Waterland return (NULL); 25055c51f124SMoriah Waterland 25065c51f124SMoriah Waterland p = xstrdup(path); 25075c51f124SMoriah Waterland 25085c51f124SMoriah Waterland if ((p2 = strrchr(p, token)) == NULL) { 25095c51f124SMoriah Waterland return (NULL); 25105c51f124SMoriah Waterland } 25115c51f124SMoriah Waterland 25125c51f124SMoriah Waterland return (p2 + 1); 25135c51f124SMoriah Waterland } 25145c51f124SMoriah Waterland 25155c51f124SMoriah Waterland /* 25165c51f124SMoriah Waterland * Name: progress_setup 25175c51f124SMoriah Waterland * Description: Initialize session for reporting progress 25185c51f124SMoriah Waterland * 25195c51f124SMoriah Waterland * Arguments: nointeract - if non-zero, do not do anything 25205c51f124SMoriah Waterland * ulong_t - size of job to report progress for 25215c51f124SMoriah Waterland * 25225c51f124SMoriah Waterland * Returns : none 25235c51f124SMoriah Waterland */ 25245c51f124SMoriah Waterland static void 25255c51f124SMoriah Waterland progress_setup(int nointeract, ulong_t size_of_load) 25265c51f124SMoriah Waterland { 25275c51f124SMoriah Waterland ulong_t divisor; 25285c51f124SMoriah Waterland ulong_t term_width = TERM_WIDTH; 25295c51f124SMoriah Waterland 25305c51f124SMoriah Waterland if (nointeract) 25315c51f124SMoriah Waterland return; 25325c51f124SMoriah Waterland 25335c51f124SMoriah Waterland if (size_of_load > MED_DWNLD && size_of_load < LARGE_DWNLD) 25345c51f124SMoriah Waterland divisor = MED_DIVISOR; 25355c51f124SMoriah Waterland else if (size_of_load > LARGE_DWNLD) { 25365c51f124SMoriah Waterland term_width = TERM_WIDTH - 8; 25375c51f124SMoriah Waterland divisor = LARGE_DIVISOR; 25385c51f124SMoriah Waterland } else 25395c51f124SMoriah Waterland divisor = SMALL_DIVISOR; 25405c51f124SMoriah Waterland 25415c51f124SMoriah Waterland const_increment = size_of_load / term_width; 25425c51f124SMoriah Waterland const_divider = size_of_load / divisor; 25435c51f124SMoriah Waterland const_completed = 100 / divisor; 25445c51f124SMoriah Waterland } 25455c51f124SMoriah Waterland 25465c51f124SMoriah Waterland /* 25475c51f124SMoriah Waterland * Name: progress_report 25485c51f124SMoriah Waterland * Description: Report progress for current progress context, 25495c51f124SMoriah Waterland * to stderr 25505c51f124SMoriah Waterland * 25515c51f124SMoriah Waterland * Arguments: nointeract - if non-zero, do not do anything 25525c51f124SMoriah Waterland * position - how far along in the job to report. 25535c51f124SMoriah Waterland * This should be <= size used during progress_setup 25545c51f124SMoriah Waterland * 25555c51f124SMoriah Waterland * Returns : none 25565c51f124SMoriah Waterland */ 25575c51f124SMoriah Waterland static void 25585c51f124SMoriah Waterland progress_report(int nointeract, ulong_t position) 25595c51f124SMoriah Waterland { 25605c51f124SMoriah Waterland static ulong_t increment; 25615c51f124SMoriah Waterland static ulong_t divider; 25625c51f124SMoriah Waterland 25635c51f124SMoriah Waterland if (nointeract) 25645c51f124SMoriah Waterland return; 25655c51f124SMoriah Waterland 25665c51f124SMoriah Waterland if (position == 0) { 25675c51f124SMoriah Waterland increment = const_increment; 25685c51f124SMoriah Waterland divider = const_divider; 25695c51f124SMoriah Waterland } 25705c51f124SMoriah Waterland if (position > increment && position < divider) { 25715c51f124SMoriah Waterland (void) putc('.', stderr); 25725c51f124SMoriah Waterland increment += const_increment; 25735c51f124SMoriah Waterland } else if (position > divider) { 25745c51f124SMoriah Waterland completed += const_completed; 25755c51f124SMoriah Waterland (void) fprintf(stderr, "%ld%c", completed, '%'); 25765c51f124SMoriah Waterland increment += const_increment; 25775c51f124SMoriah Waterland divider += const_divider; 25785c51f124SMoriah Waterland } 25795c51f124SMoriah Waterland } 25805c51f124SMoriah Waterland 25815c51f124SMoriah Waterland /* 25825c51f124SMoriah Waterland * Name: progress_finish 25835c51f124SMoriah Waterland * Description: Finalize session for reporting progress. 25845c51f124SMoriah Waterland * "100%" is reported to screen 25855c51f124SMoriah Waterland * 25865c51f124SMoriah Waterland * Arguments: nointeract - if non-zero, do not do anything 25875c51f124SMoriah Waterland * 25885c51f124SMoriah Waterland * Returns : none 25895c51f124SMoriah Waterland */ 25905c51f124SMoriah Waterland static void 25915c51f124SMoriah Waterland progress_finish(int nointeract) 25925c51f124SMoriah Waterland { 25935c51f124SMoriah Waterland if (nointeract) 25945c51f124SMoriah Waterland return; 25955c51f124SMoriah Waterland 25965c51f124SMoriah Waterland (void) fprintf(stderr, "%d%c\n", 100, '%'); 25975c51f124SMoriah Waterland } 25985c51f124SMoriah Waterland 25995c51f124SMoriah Waterland /* 26005c51f124SMoriah Waterland * Name: init_session 26015c51f124SMoriah Waterland * Description: Initializes static 'ps' structure with default 26025c51f124SMoriah Waterland * values 26035c51f124SMoriah Waterland * 26045c51f124SMoriah Waterland * Arguments: none 26055c51f124SMoriah Waterland * 26065c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 26075c51f124SMoriah Waterland */ 26085c51f124SMoriah Waterland static boolean_t 26095c51f124SMoriah Waterland init_session(void) 26105c51f124SMoriah Waterland { 26115c51f124SMoriah Waterland if ((ps = (WEB_SESSION *) 26125c51f124SMoriah Waterland xmalloc(sizeof (WEB_SESSION))) == NULL) { 26135c51f124SMoriah Waterland return (B_FALSE); 26145c51f124SMoriah Waterland } 26155c51f124SMoriah Waterland (void) memset(ps, 0, sizeof (*ps)); 26165c51f124SMoriah Waterland 26175c51f124SMoriah Waterland if ((ps->content = (char *)xmalloc(BLOCK)) == NULL) { 26185c51f124SMoriah Waterland return (B_FALSE); 26195c51f124SMoriah Waterland } 26205c51f124SMoriah Waterland 26215c51f124SMoriah Waterland (void) memset(ps->content, 0, BLOCK); 26225c51f124SMoriah Waterland 26235c51f124SMoriah Waterland ps->data.cur_pos = 0UL; 26245c51f124SMoriah Waterland ps->data.content_length = 0UL; 26255c51f124SMoriah Waterland ps->url.https = B_FALSE; 26265c51f124SMoriah Waterland ps->uniqfile = NULL; 26275c51f124SMoriah Waterland ps->link = NULL; 26285c51f124SMoriah Waterland ps->dwnld_dir = NULL; 26295c51f124SMoriah Waterland ps->spool = B_TRUE; 26305c51f124SMoriah Waterland ps->errstr = NULL; 26315c51f124SMoriah Waterland ps->keystore = NULL; 26325c51f124SMoriah Waterland 26335c51f124SMoriah Waterland return (B_TRUE); 26345c51f124SMoriah Waterland } 26355c51f124SMoriah Waterland 26365c51f124SMoriah Waterland /* 26375c51f124SMoriah Waterland * Name: ck_downld_dir_space 26385c51f124SMoriah Waterland * Description: Verify enough space exists in directory to hold file 26395c51f124SMoriah Waterland * 26405c51f124SMoriah Waterland * Arguments: err - where to record any errors. 26415c51f124SMoriah Waterland * dwnld_dir - Directory to check available space in 26425c51f124SMoriah Waterland * bytes_needed - How many bytes are need 26435c51f124SMoriah Waterland * 26445c51f124SMoriah Waterland * Returns : B_TRUE - enough space exists in dwnld_dir to hold 26455c51f124SMoriah Waterland * bytes_needed bytes, otherwise B_FALSE 26465c51f124SMoriah Waterland */ 26475c51f124SMoriah Waterland static boolean_t 26485c51f124SMoriah Waterland ck_dwnld_dir_space(PKG_ERR *err, char *dwnld_dir, ulong_t bytes_needed) 26495c51f124SMoriah Waterland { 26505c51f124SMoriah Waterland u_longlong_t bytes_avail; 26515c51f124SMoriah Waterland u_longlong_t block_pad; 26525c51f124SMoriah Waterland struct statvfs64 status; 26535c51f124SMoriah Waterland 26545c51f124SMoriah Waterland if (statvfs64(dwnld_dir, &status)) { 26555c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_TMPDIR), dwnld_dir); 26565c51f124SMoriah Waterland return (B_FALSE); 26575c51f124SMoriah Waterland } 26585c51f124SMoriah Waterland 26595c51f124SMoriah Waterland block_pad = (status.f_frsize ? status.f_frsize : status.f_bsize); 26605c51f124SMoriah Waterland bytes_avail = status.f_bavail * block_pad; 26615c51f124SMoriah Waterland 26625c51f124SMoriah Waterland if ((((u_longlong_t)bytes_needed) + block_pad) > bytes_avail) { 26635c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_DISK_SPACE), 26645c51f124SMoriah Waterland dwnld_dir, 26655c51f124SMoriah Waterland (((u_longlong_t)bytes_needed) + block_pad) / 1024ULL, 26665c51f124SMoriah Waterland bytes_avail / 1024ULL); 26675c51f124SMoriah Waterland return (B_FALSE); 26685c51f124SMoriah Waterland } 26695c51f124SMoriah Waterland 26705c51f124SMoriah Waterland return (B_TRUE); 26715c51f124SMoriah Waterland } 26725c51f124SMoriah Waterland 26735c51f124SMoriah Waterland /* 26745c51f124SMoriah Waterland * Description: 26755c51f124SMoriah Waterland * This function returns a unique file name based on the parts of the 26765c51f124SMoriah Waterland * URI. This is done to enable partially downloaded files to be resumed. 26775c51f124SMoriah Waterland * Arguments: 26785c51f124SMoriah Waterland * dir - The directory that should contain the filename. 26795c51f124SMoriah Waterland * last_modified - A string representing the date of last modification, 26805c51f124SMoriah Waterland * used as part of generating unique name 26815c51f124SMoriah Waterland * Returns: 26825c51f124SMoriah Waterland * A valid filename or NULL. 26835c51f124SMoriah Waterland */ 26845c51f124SMoriah Waterland 26855c51f124SMoriah Waterland static char * 26865c51f124SMoriah Waterland get_unique_filename(char *dir, char *last_modified) 26875c51f124SMoriah Waterland { 26885c51f124SMoriah Waterland char *buf, *buf2, *beg_str; 26895c51f124SMoriah Waterland int len; 26905c51f124SMoriah Waterland 26915c51f124SMoriah Waterland if ((buf = (char *)xmalloc(PATH_MAX)) == NULL) { 26925c51f124SMoriah Waterland return (NULL); 26935c51f124SMoriah Waterland } 26945c51f124SMoriah Waterland if ((buf2 = (char *)xmalloc(PATH_MAX)) == NULL) { 26955c51f124SMoriah Waterland return (NULL); 26965c51f124SMoriah Waterland } 26975c51f124SMoriah Waterland 26985c51f124SMoriah Waterland /* prepare strings for being cat'ed onto */ 26995c51f124SMoriah Waterland buf[0] = buf2[0] = '\0'; 27005c51f124SMoriah Waterland /* 27015c51f124SMoriah Waterland * No validation of the path is done here. We just construct the path 27025c51f124SMoriah Waterland * and it must be validated later 27035c51f124SMoriah Waterland */ 27045c51f124SMoriah Waterland 27055c51f124SMoriah Waterland if (dir) { 27065c51f124SMoriah Waterland if (((len = snprintf(buf2, PATH_MAX, "%s/", dir)) < 0) || 27075c51f124SMoriah Waterland (len >= PATH_MAX)) 27085c51f124SMoriah Waterland return (NULL); 27095c51f124SMoriah Waterland } else { 27105c51f124SMoriah Waterland return (NULL); 27115c51f124SMoriah Waterland } 27125c51f124SMoriah Waterland 27135c51f124SMoriah Waterland if (ps->url.abspath) 27145c51f124SMoriah Waterland if (strlcat(buf, ps->url.abspath, PATH_MAX) >= PATH_MAX) 27155c51f124SMoriah Waterland return (NULL); 27165c51f124SMoriah Waterland if (ps->url.hport.hostname) 27175c51f124SMoriah Waterland if (isdigit((int)ps->url.hport.hostname[0])) { 27185c51f124SMoriah Waterland if (strlcat(buf, ps->url.hport.hostname, PATH_MAX) 27195c51f124SMoriah Waterland >= PATH_MAX) 27205c51f124SMoriah Waterland return (NULL); 27215c51f124SMoriah Waterland } else { 27225c51f124SMoriah Waterland if ((beg_str = 27235c51f124SMoriah Waterland get_startof_string(ps->url.hport.hostname, '.')) 27245c51f124SMoriah Waterland != NULL) 27255c51f124SMoriah Waterland if (strlcat(buf, beg_str, PATH_MAX) >= PATH_MAX) 27265c51f124SMoriah Waterland return (NULL); 27275c51f124SMoriah Waterland } 27285c51f124SMoriah Waterland if (last_modified != NULL) 27295c51f124SMoriah Waterland if (strlcat(buf, last_modified, PATH_MAX) >= PATH_MAX) 27305c51f124SMoriah Waterland return (NULL); 27315c51f124SMoriah Waterland 27325c51f124SMoriah Waterland if ((buf = replace_token(buf, '/', '_')) != NULL) { 27335c51f124SMoriah Waterland if (strlcat(buf2, buf, PATH_MAX) >= PATH_MAX) { 27345c51f124SMoriah Waterland return (NULL); 27355c51f124SMoriah Waterland } else { 27365c51f124SMoriah Waterland if (buf) free(buf); 27375c51f124SMoriah Waterland return (buf2); 27385c51f124SMoriah Waterland } 27395c51f124SMoriah Waterland } else { 27405c51f124SMoriah Waterland if (buf) free(buf); 27415c51f124SMoriah Waterland if (buf2) free(buf2); 27425c51f124SMoriah Waterland return (NULL); 27435c51f124SMoriah Waterland } 27445c51f124SMoriah Waterland } 27455c51f124SMoriah Waterland 27465c51f124SMoriah Waterland /* 27475c51f124SMoriah Waterland * Description: 27485c51f124SMoriah Waterland * Removes token(s) consisting of one character from any path. 27495c51f124SMoriah Waterland * Arguments: 27505c51f124SMoriah Waterland * path - The path to search for the token in. 27515c51f124SMoriah Waterland * token - The token to search for 27525c51f124SMoriah Waterland * Returns: 27535c51f124SMoriah Waterland * The path with all tokens removed or NULL. 27545c51f124SMoriah Waterland */ 27555c51f124SMoriah Waterland static char * 27565c51f124SMoriah Waterland replace_token(char *path, char oldtoken, char newtoken) 27575c51f124SMoriah Waterland { 27585c51f124SMoriah Waterland char *newpath, *p; 27595c51f124SMoriah Waterland 27605c51f124SMoriah Waterland if ((path == NULL) || (oldtoken == '\0') || (newtoken == '\0')) { 27615c51f124SMoriah Waterland return (NULL); 27625c51f124SMoriah Waterland } 27635c51f124SMoriah Waterland 27645c51f124SMoriah Waterland newpath = xstrdup(path); 27655c51f124SMoriah Waterland 27665c51f124SMoriah Waterland for (p = newpath; *p != '\0'; p++) { 27675c51f124SMoriah Waterland if (*p == oldtoken) { 27685c51f124SMoriah Waterland *p = newtoken; 27695c51f124SMoriah Waterland } 27705c51f124SMoriah Waterland } 27715c51f124SMoriah Waterland 27725c51f124SMoriah Waterland return (newpath); 27735c51f124SMoriah Waterland } 27745c51f124SMoriah Waterland 27755c51f124SMoriah Waterland /* 27765c51f124SMoriah Waterland * Name: trim 27775c51f124SMoriah Waterland * Description: Trims whitespace from a string 27785c51f124SMoriah Waterland * has been registered) 27795c51f124SMoriah Waterland * Scope: private 27805c51f124SMoriah Waterland * Arguments: string - string to trim. It is assumed 27815c51f124SMoriah Waterland * this string is writable up to it's entire 27825c51f124SMoriah Waterland * length. 27835c51f124SMoriah Waterland * Returns: none 27845c51f124SMoriah Waterland */ 27855c51f124SMoriah Waterland static void 27865c51f124SMoriah Waterland trim(char *str) 27875c51f124SMoriah Waterland { 27885c51f124SMoriah Waterland int len, i; 27895c51f124SMoriah Waterland if (str == NULL) { 27905c51f124SMoriah Waterland return; 27915c51f124SMoriah Waterland } 27925c51f124SMoriah Waterland 27935c51f124SMoriah Waterland len = strlen(str); 27945c51f124SMoriah Waterland /* strip from front */ 27955c51f124SMoriah Waterland while (isspace(*str)) { 27965c51f124SMoriah Waterland for (i = 0; i < len; i++) { 27975c51f124SMoriah Waterland str[i] = str[i+1]; 27985c51f124SMoriah Waterland } 27995c51f124SMoriah Waterland } 28005c51f124SMoriah Waterland 28015c51f124SMoriah Waterland /* strip from back */ 28025c51f124SMoriah Waterland len = strlen(str); 28035c51f124SMoriah Waterland while (isspace(str[len-1])) { 28045c51f124SMoriah Waterland len--; 28055c51f124SMoriah Waterland } 28065c51f124SMoriah Waterland str[len] = '\0'; 28075c51f124SMoriah Waterland } 28085c51f124SMoriah Waterland 28095c51f124SMoriah Waterland /* 28105c51f124SMoriah Waterland * Description: 28115c51f124SMoriah Waterland * Resolves double quotes 28125c51f124SMoriah Waterland * Arguments: 28135c51f124SMoriah Waterland * str - The string to resolve 28145c51f124SMoriah Waterland * Returns: 28155c51f124SMoriah Waterland * None 28165c51f124SMoriah Waterland */ 28175c51f124SMoriah Waterland static void 28185c51f124SMoriah Waterland dequote(char *str) 28195c51f124SMoriah Waterland { 28205c51f124SMoriah Waterland char *cp; 28215c51f124SMoriah Waterland 28225c51f124SMoriah Waterland if ((str == NULL) || (str[0] != '"')) { 28235c51f124SMoriah Waterland /* no quotes */ 28245c51f124SMoriah Waterland return; 28255c51f124SMoriah Waterland } 28265c51f124SMoriah Waterland 28275c51f124SMoriah Waterland /* remove first quote */ 2828*4656d474SGarrett D'Amore (void) memmove(str, str + 1, strlen(str) - 1); 28295c51f124SMoriah Waterland 28305c51f124SMoriah Waterland /* 28315c51f124SMoriah Waterland * scan string looking for ending quote. 28325c51f124SMoriah Waterland * escaped quotes like \" don't count 28335c51f124SMoriah Waterland */ 28345c51f124SMoriah Waterland cp = str; 28355c51f124SMoriah Waterland 28365c51f124SMoriah Waterland while (*cp != '\0') { 28375c51f124SMoriah Waterland switch (*cp) { 28385c51f124SMoriah Waterland case '\\': 28395c51f124SMoriah Waterland /* found an escaped character */ 28405c51f124SMoriah Waterland /* make sure end of string is not '\' */ 28415c51f124SMoriah Waterland if (*++cp != '\0') { 28425c51f124SMoriah Waterland cp++; 28435c51f124SMoriah Waterland } 28445c51f124SMoriah Waterland break; 28455c51f124SMoriah Waterland 28465c51f124SMoriah Waterland case '"': 28475c51f124SMoriah Waterland *cp = '\0'; 28485c51f124SMoriah Waterland break; 28495c51f124SMoriah Waterland default: 28505c51f124SMoriah Waterland cp++; 28515c51f124SMoriah Waterland } 28525c51f124SMoriah Waterland } 28535c51f124SMoriah Waterland } 28545c51f124SMoriah Waterland 28555c51f124SMoriah Waterland /* 28565c51f124SMoriah Waterland * Name: get_ENV_proxy 28575c51f124SMoriah Waterland * Description: Retrieves setting of proxy env variable 28585c51f124SMoriah Waterland * 28595c51f124SMoriah Waterland * Arguments: err - where to record any errors. 28605c51f124SMoriah Waterland * proxy - where to store proxy 28615c51f124SMoriah Waterland * 28625c51f124SMoriah Waterland * Returns : B_TRUE - http proxy was found and valid, stored in proxy 28635c51f124SMoriah Waterland * B_FALSE - error, errors recorded in err 28645c51f124SMoriah Waterland */ 28655c51f124SMoriah Waterland static boolean_t 28665c51f124SMoriah Waterland get_ENV_proxy(PKG_ERR *err, char **proxy) 28675c51f124SMoriah Waterland { 28685c51f124SMoriah Waterland char *buf; 28695c51f124SMoriah Waterland 28705c51f124SMoriah Waterland if ((buf = getenv("HTTPPROXY")) != NULL) { 28715c51f124SMoriah Waterland if (!path_valid(buf)) { 28725c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 28735c51f124SMoriah Waterland gettext(ERR_ILL_ENV), "HTTPPROXY", buf); 28745c51f124SMoriah Waterland return (B_FALSE); 28755c51f124SMoriah Waterland } else { 28765c51f124SMoriah Waterland *proxy = buf; 28775c51f124SMoriah Waterland return (B_TRUE); 28785c51f124SMoriah Waterland } 28795c51f124SMoriah Waterland } else { 28805c51f124SMoriah Waterland /* try the other env variable */ 28815c51f124SMoriah Waterland if ((buf = getenv("http_proxy")) != NULL) { 28825c51f124SMoriah Waterland if (!path_valid(buf)) { 28835c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 28845c51f124SMoriah Waterland gettext(ERR_ILL_ENV), "http_proxy", buf); 28855c51f124SMoriah Waterland return (B_FALSE); 28865c51f124SMoriah Waterland } 28875c51f124SMoriah Waterland if (!strneq(buf, "http://", 7)) { 28885c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 28895c51f124SMoriah Waterland gettext(ERR_ILL_ENV), "http_proxy", buf); 28905c51f124SMoriah Waterland return (B_FALSE); 28915c51f124SMoriah Waterland } 28925c51f124SMoriah Waterland 28935c51f124SMoriah Waterland /* skip over the http:// part of the proxy "url" */ 28945c51f124SMoriah Waterland *proxy = buf + 7; 28955c51f124SMoriah Waterland return (B_TRUE); 28965c51f124SMoriah Waterland } 28975c51f124SMoriah Waterland } 28985c51f124SMoriah Waterland 28995c51f124SMoriah Waterland /* either the env variable(s) were set and valid, or not set */ 29005c51f124SMoriah Waterland return (B_TRUE); 29015c51f124SMoriah Waterland } 29025c51f124SMoriah Waterland 29035c51f124SMoriah Waterland /* 29045c51f124SMoriah Waterland * Name: get_ENV_proxyport 29055c51f124SMoriah Waterland * Description: Retrieves setting of PROXYPORT env variable 29065c51f124SMoriah Waterland * 29075c51f124SMoriah Waterland * Arguments: err - where to record any errors. 29085c51f124SMoriah Waterland * port - where to store resulting port 29095c51f124SMoriah Waterland * 29105c51f124SMoriah Waterland * Returns : B_TRUE - string found in PROXYPORT variable, converted 29115c51f124SMoriah Waterland * to decimal integer, if it exists 29125c51f124SMoriah Waterland * and is valid. Or, PROXYPORT not set, port set to 1. 29135c51f124SMoriah Waterland * B_FALSE - env variable set, but invalid 29145c51f124SMoriah Waterland * (not a number for example) 29155c51f124SMoriah Waterland */ 29165c51f124SMoriah Waterland static boolean_t 29175c51f124SMoriah Waterland get_ENV_proxyport(PKG_ERR *err, ushort_t *port) 29185c51f124SMoriah Waterland { 29195c51f124SMoriah Waterland char *buf; 29205c51f124SMoriah Waterland ushort_t newport; 29215c51f124SMoriah Waterland buf = getenv("HTTPPROXYPORT"); 29225c51f124SMoriah Waterland if (buf != NULL) { 29235c51f124SMoriah Waterland if (!path_valid(buf)) { 29245c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 29255c51f124SMoriah Waterland gettext(ERR_ILL_ENV), "HTTPPROXYPORT", buf); 29265c51f124SMoriah Waterland return (B_FALSE); 29275c51f124SMoriah Waterland } 29285c51f124SMoriah Waterland if ((newport = atoi(buf)) == 0) { 29295c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, 29305c51f124SMoriah Waterland gettext(ERR_ILL_ENV), "HTTPPROXYPORT", buf); 29315c51f124SMoriah Waterland return (B_FALSE); 29325c51f124SMoriah Waterland } 29335c51f124SMoriah Waterland *port = newport; 29345c51f124SMoriah Waterland return (B_TRUE); 29355c51f124SMoriah Waterland } else { 29365c51f124SMoriah Waterland *port = 1; 29375c51f124SMoriah Waterland return (B_TRUE); 29385c51f124SMoriah Waterland } 29395c51f124SMoriah Waterland } 29405c51f124SMoriah Waterland 29415c51f124SMoriah Waterland /* 29425c51f124SMoriah Waterland * Name: remove_dwnld_file 29435c51f124SMoriah Waterland * Description: Removes newly-downloaded file if completely downloaded. 29445c51f124SMoriah Waterland * 29455c51f124SMoriah Waterland * Arguments: path - path to file to remove 29465c51f124SMoriah Waterland * 29475c51f124SMoriah Waterland * Returns : B_TRUE - success, B_FALSE otherwise 29485c51f124SMoriah Waterland * if it's '0' (not OK) we simply return it, since the 29495c51f124SMoriah Waterland * verification operation has already determined that the 29505c51f124SMoriah Waterland * cert is invalid. if 'ok' is non-zero, then we do our 29515c51f124SMoriah Waterland * checks, and return 0 or 1 based on if the cert is 29525c51f124SMoriah Waterland * invalid or valid. 29535c51f124SMoriah Waterland */ 29545c51f124SMoriah Waterland static boolean_t 29555c51f124SMoriah Waterland remove_dwnld_file(char *path) 29565c51f124SMoriah Waterland { 29575c51f124SMoriah Waterland if (path && path != NULL) { 29585c51f124SMoriah Waterland /* 29595c51f124SMoriah Waterland * Only remove the downloaded file if it has been completely 29605c51f124SMoriah Waterland * downloaded, or is not eligible for spooling 29615c51f124SMoriah Waterland */ 29625c51f124SMoriah Waterland if ((!ps->spool) || 29635c51f124SMoriah Waterland (ps->data.cur_pos >= ps->data.content_length)) { 29645c51f124SMoriah Waterland (void) unlink(path); 29655c51f124SMoriah Waterland } 29665c51f124SMoriah Waterland } else { 29675c51f124SMoriah Waterland return (B_FALSE); 29685c51f124SMoriah Waterland } 29695c51f124SMoriah Waterland return (B_TRUE); 29705c51f124SMoriah Waterland } 29715c51f124SMoriah Waterland 29725c51f124SMoriah Waterland /* 29735c51f124SMoriah Waterland * Name: condense_lastmodifided 29745c51f124SMoriah Waterland * Description: generates a substring of a last-modified string, 29755c51f124SMoriah Waterland * and removes colons. 29765c51f124SMoriah Waterland * 29775c51f124SMoriah Waterland * Arguments: last_modified - string of the form 29785c51f124SMoriah Waterland * "Wed, 23 Oct 2002 21:59:45 GMT" 29795c51f124SMoriah Waterland * 29805c51f124SMoriah Waterland * Returns : 29815c51f124SMoriah Waterland * new string, consisting of hours/minutes/seconds only, 29825c51f124SMoriah Waterland * sans any colons. 29835c51f124SMoriah Waterland */ 29845c51f124SMoriah Waterland char * 29855c51f124SMoriah Waterland condense_lastmodified(char *last_modified) 29865c51f124SMoriah Waterland { 29875c51f124SMoriah Waterland char *p, *p2; 29885c51f124SMoriah Waterland 29895c51f124SMoriah Waterland /* 29905c51f124SMoriah Waterland * Last-Modified: Wed, 23 Oct 2002 21:59:45 GMT 29915c51f124SMoriah Waterland * Strip the hours, minutes and seconds, without the ':'s, from 29925c51f124SMoriah Waterland * the above string, void of the ':". 29935c51f124SMoriah Waterland */ 29945c51f124SMoriah Waterland 29955c51f124SMoriah Waterland if (last_modified == NULL) 29965c51f124SMoriah Waterland return (NULL); 29975c51f124SMoriah Waterland 29985c51f124SMoriah Waterland if ((p = xstrdup(last_modified)) == NULL) 29995c51f124SMoriah Waterland return (NULL); 30005c51f124SMoriah Waterland p2 = (strstr(p, ":") - 2); 30015c51f124SMoriah Waterland p2[8] = '\0'; 30025c51f124SMoriah Waterland return (replace_token(p2, ':', '_')); 30035c51f124SMoriah Waterland } 30045c51f124SMoriah Waterland 30055c51f124SMoriah Waterland /* 30065c51f124SMoriah Waterland * Name: backoff 30075c51f124SMoriah Waterland * Description: sleeps for a certain # of seconds after a network 30085c51f124SMoriah Waterland * failure. 30095c51f124SMoriah Waterland * Scope: public 30105c51f124SMoriah Waterland * Arguments: none 30115c51f124SMoriah Waterland * Returns: none 30125c51f124SMoriah Waterland */ 30135c51f124SMoriah Waterland void 30145c51f124SMoriah Waterland backoff() 30155c51f124SMoriah Waterland { 30165c51f124SMoriah Waterland static boolean_t initted = B_FALSE; 30175c51f124SMoriah Waterland int backoff; 30185c51f124SMoriah Waterland long seed; 30195c51f124SMoriah Waterland 30205c51f124SMoriah Waterland if (!initted) { 30215c51f124SMoriah Waterland /* seed the rng */ 30225c51f124SMoriah Waterland (void) _get_random_info(&seed, sizeof (seed)); 30235c51f124SMoriah Waterland srand48(seed); 30245c51f124SMoriah Waterland initted = B_TRUE; 30255c51f124SMoriah Waterland } 30265c51f124SMoriah Waterland 3027*4656d474SGarrett D'Amore backoff = (int)(drand48() * (double)cur_backoff); 30285c51f124SMoriah Waterland (void) sleep(backoff); 30295c51f124SMoriah Waterland if (cur_backoff < MAX_BACKOFF) { 30305c51f124SMoriah Waterland /* 30315c51f124SMoriah Waterland * increase maximum time we might wait 30325c51f124SMoriah Waterland * next time so as to fall off over 30335c51f124SMoriah Waterland * time. 30345c51f124SMoriah Waterland */ 30355c51f124SMoriah Waterland cur_backoff *= BACKOFF_FACTOR; 30365c51f124SMoriah Waterland } 30375c51f124SMoriah Waterland } 30385c51f124SMoriah Waterland 30395c51f124SMoriah Waterland /* 30405c51f124SMoriah Waterland * Name: reset_backoff 30415c51f124SMoriah Waterland * Description: notifies the backoff service that whatever was 30425c51f124SMoriah Waterland * being backoff succeeded. 30435c51f124SMoriah Waterland * Scope: public 30445c51f124SMoriah Waterland * Arguments: none 30455c51f124SMoriah Waterland * Returns: none 30465c51f124SMoriah Waterland */ 30475c51f124SMoriah Waterland void 30485c51f124SMoriah Waterland reset_backoff() 30495c51f124SMoriah Waterland { 30505c51f124SMoriah Waterland cur_backoff = MIN_BACKOFF; 30515c51f124SMoriah Waterland } 30525c51f124SMoriah Waterland 30535c51f124SMoriah Waterland /* 30545c51f124SMoriah Waterland * Name: _get_random_info 30555c51f124SMoriah Waterland * Description: generate an amount of random bits. Currently 30565c51f124SMoriah Waterland * only a small amount (a long long) can be 30575c51f124SMoriah Waterland * generated at one time. 30585c51f124SMoriah Waterland * Scope: private 30595c51f124SMoriah Waterland * Arguments: buf - [RO, *RW] (char *) 30605c51f124SMoriah Waterland * Buffer to copy bits into 30615c51f124SMoriah Waterland * size - amount to copy 30625c51f124SMoriah Waterland * Returns: B_TRUE on success, B_FALSE otherwise. The buffer is filled 30635c51f124SMoriah Waterland * with the amount of bytes of random data specified. 30645c51f124SMoriah Waterland */ 30655c51f124SMoriah Waterland static boolean_t 30665c51f124SMoriah Waterland _get_random_info(void *buf, int size) 30675c51f124SMoriah Waterland { 30685c51f124SMoriah Waterland struct timeval tv; 30695c51f124SMoriah Waterland typedef struct { 30705c51f124SMoriah Waterland long low_time; 30715c51f124SMoriah Waterland long hostid; 30725c51f124SMoriah Waterland } randomness; 30735c51f124SMoriah Waterland randomness r; 30745c51f124SMoriah Waterland 30755c51f124SMoriah Waterland /* if the RANDOM file exists, use it */ 30765c51f124SMoriah Waterland if (access(RANDOM, R_OK) == 0) { 30775c51f124SMoriah Waterland if ((RAND_load_file(RANDOM, 1024 * 1024)) > 0) { 30785c51f124SMoriah Waterland if (RAND_bytes((uchar_t *)buf, size) == 1) { 30795c51f124SMoriah Waterland /* success */ 30805c51f124SMoriah Waterland return (B_TRUE); 30815c51f124SMoriah Waterland } 30825c51f124SMoriah Waterland } 30835c51f124SMoriah Waterland } 30845c51f124SMoriah Waterland 30855c51f124SMoriah Waterland /* couldn't use RANDOM file, so fallback to time of day and hostid */ 30865c51f124SMoriah Waterland (void) gettimeofday(&tv, (struct timezone *)0); 30875c51f124SMoriah Waterland 30885c51f124SMoriah Waterland /* Wouldn't it be nice if we could hash these */ 30895c51f124SMoriah Waterland r.low_time = tv.tv_usec; 30905c51f124SMoriah Waterland r.hostid = gethostid(); 30915c51f124SMoriah Waterland 30925c51f124SMoriah Waterland if (sizeof (r) < size) { 30935c51f124SMoriah Waterland /* 30945c51f124SMoriah Waterland * Can't copy correctly 30955c51f124SMoriah Waterland */ 30965c51f124SMoriah Waterland return (B_FALSE); 30975c51f124SMoriah Waterland } 30985c51f124SMoriah Waterland (void) memcpy(buf, &r, size); 30995c51f124SMoriah Waterland return (B_TRUE); 31005c51f124SMoriah Waterland } 31015c51f124SMoriah Waterland 31025c51f124SMoriah Waterland /* 31035c51f124SMoriah Waterland * Name: pkg_passphrase_cb 31045c51f124SMoriah Waterland * Description: Default callback that applications can use when 31055c51f124SMoriah Waterland * a passphrase is needed. This routine collects 31065c51f124SMoriah Waterland * a passphrase from the user using the given 31075c51f124SMoriah Waterland * passphrase retrieval method set with 31085c51f124SMoriah Waterland * set_passphrase_passarg(). If the method 31095c51f124SMoriah Waterland * indicates an interactive prompt, then the 31105c51f124SMoriah Waterland * prompt set with set_passphrase_prompt() 31115c51f124SMoriah Waterland * is displayed. 31125c51f124SMoriah Waterland * 31135c51f124SMoriah Waterland * Arguments: buf - Buffer to copy passphrase into 31145c51f124SMoriah Waterland * size - Max amount to copy to buf 31155c51f124SMoriah Waterland * rw - Whether this passphrase is needed 31165c51f124SMoriah Waterland * to read something off disk, or 31175c51f124SMoriah Waterland * write something to disk. Applications 31185c51f124SMoriah Waterland * typically want to ask twice when getting 31195c51f124SMoriah Waterland * a passphrase for writing something. 31205c51f124SMoriah Waterland * data - application-specific data. In this 31215c51f124SMoriah Waterland * callback, data is a pointer to 31225c51f124SMoriah Waterland * a keystore_passphrase_data structure. 31235c51f124SMoriah Waterland * 31245c51f124SMoriah Waterland * Returns: Length of passphrase collected, or -1 on error. 31255c51f124SMoriah Waterland * Errors recorded in 'err' object in the *data. 31265c51f124SMoriah Waterland */ 31275c51f124SMoriah Waterland int 31285c51f124SMoriah Waterland pkg_passphrase_cb(char *buf, int size, int rw, void *data) 31295c51f124SMoriah Waterland { 31305c51f124SMoriah Waterland BIO *pwdbio = NULL; 31315c51f124SMoriah Waterland char passphrase_copy[MAX_PHRASELEN + 1]; 31325c51f124SMoriah Waterland PKG_ERR *err; 31335c51f124SMoriah Waterland int passlen; 31345c51f124SMoriah Waterland char *ws; 31355c51f124SMoriah Waterland char prompt_copy[MAX_VERIFY_MSGLEN]; 31365c51f124SMoriah Waterland char *passphrase; 31375c51f124SMoriah Waterland char *arg; 31385c51f124SMoriah Waterland 31395c51f124SMoriah Waterland err = ((keystore_passphrase_data *)data)->err; 31405c51f124SMoriah Waterland 31415c51f124SMoriah Waterland if (passarg == NULL) { 31425c51f124SMoriah Waterland arg = "console"; 31435c51f124SMoriah Waterland } else { 31445c51f124SMoriah Waterland arg = passarg; 31455c51f124SMoriah Waterland } 31465c51f124SMoriah Waterland 31475c51f124SMoriah Waterland /* default method of collecting password is by prompting */ 31485c51f124SMoriah Waterland if (ci_streq(arg, "console")) { 31495c51f124SMoriah Waterland if ((passphrase = getpassphrase(prompt)) == NULL) { 31505c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 31515c51f124SMoriah Waterland gettext(MSG_NOPASS), arg); 31525c51f124SMoriah Waterland return (-1); 31535c51f124SMoriah Waterland } 31545c51f124SMoriah Waterland 31555c51f124SMoriah Waterland if (rw) { 31565c51f124SMoriah Waterland /* 31575c51f124SMoriah Waterland * if the password is being supplied for 31585c51f124SMoriah Waterland * writing something to disk, verify it first 31595c51f124SMoriah Waterland */ 31605c51f124SMoriah Waterland 31615c51f124SMoriah Waterland /* make a copy (getpassphrase overwrites) */ 3162*4656d474SGarrett D'Amore (void) strlcpy(passphrase_copy, passphrase, 31635c51f124SMoriah Waterland MAX_PHRASELEN + 1); 31645c51f124SMoriah Waterland 31655c51f124SMoriah Waterland if (((passlen = snprintf(prompt_copy, 31665c51f124SMoriah Waterland MAX_VERIFY_MSGLEN, "%s: %s", 31675c51f124SMoriah Waterland gettext(MSG_PASSWD_AGAIN), 31685c51f124SMoriah Waterland prompt)) < 0) || 31695c51f124SMoriah Waterland (passlen >= (MAX_PHRASELEN + 1))) { 31705c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 31715c51f124SMoriah Waterland gettext(MSG_NOPASS), arg); 31725c51f124SMoriah Waterland return (-1); 31735c51f124SMoriah Waterland } 31745c51f124SMoriah Waterland 31755c51f124SMoriah Waterland if ((passphrase = 31765c51f124SMoriah Waterland getpassphrase(prompt_copy)) == NULL) { 31775c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 31785c51f124SMoriah Waterland gettext(MSG_NOPASS), arg); 31795c51f124SMoriah Waterland return (-1); 31805c51f124SMoriah Waterland } 31815c51f124SMoriah Waterland 31825c51f124SMoriah Waterland if (!streq(passphrase_copy, passphrase)) { 31835c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, 31845c51f124SMoriah Waterland gettext(MSG_PASSWD_NOMATCH)); 31855c51f124SMoriah Waterland return (-1); 31865c51f124SMoriah Waterland } 31875c51f124SMoriah Waterland } 31885c51f124SMoriah Waterland } else if (ci_strneq(arg, "pass:", 5)) { 31895c51f124SMoriah Waterland passphrase = arg + 5; 31905c51f124SMoriah Waterland } else if (ci_strneq(arg, "env:", 4)) { 31915c51f124SMoriah Waterland passphrase = getenv(arg + 4); 31925c51f124SMoriah Waterland } else if (ci_strneq(arg, "file:", 5)) { 31935c51f124SMoriah Waterland 31945c51f124SMoriah Waterland /* open file for reading */ 31955c51f124SMoriah Waterland if ((pwdbio = BIO_new_file(arg + 5, "r")) == NULL) { 31965c51f124SMoriah Waterland pkgerr_add(err, PKGERR_EXIST, 31975c51f124SMoriah Waterland gettext(MSG_PASSWD_FILE), arg + 5); 31985c51f124SMoriah Waterland return (-1); 31995c51f124SMoriah Waterland } 32005c51f124SMoriah Waterland 32015c51f124SMoriah Waterland /* read first line */ 32025c51f124SMoriah Waterland if (((passlen = BIO_gets(pwdbio, buf, size)) < 1) || 32035c51f124SMoriah Waterland (passlen > size)) { 32045c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, gettext(MSG_PASSWD_FILE), 32055c51f124SMoriah Waterland arg + 5); 32065c51f124SMoriah Waterland return (-1); 32075c51f124SMoriah Waterland } 32085c51f124SMoriah Waterland BIO_free_all(pwdbio); 32095c51f124SMoriah Waterland pwdbio = NULL; 32105c51f124SMoriah Waterland 32115c51f124SMoriah Waterland if (passlen == size) { 32125c51f124SMoriah Waterland /* 32135c51f124SMoriah Waterland * password was maximum length, so there is 32145c51f124SMoriah Waterland * no null terminator. null-terminate it 32155c51f124SMoriah Waterland */ 32165c51f124SMoriah Waterland buf[size - 1] = '\0'; 32175c51f124SMoriah Waterland } 32185c51f124SMoriah Waterland 32195c51f124SMoriah Waterland /* first newline found is end of passwd, so nuke it */ 32205c51f124SMoriah Waterland if ((ws = strchr(buf, '\n')) != NULL) { 32215c51f124SMoriah Waterland *ws = '\0'; 32225c51f124SMoriah Waterland } 32235c51f124SMoriah Waterland return (strlen(buf)); 32245c51f124SMoriah Waterland } else { 32255c51f124SMoriah Waterland /* unrecognized passphrase */ 32265c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 32275c51f124SMoriah Waterland gettext(MSG_BADPASSARG), arg); 32285c51f124SMoriah Waterland return (-1); 32295c51f124SMoriah Waterland } 32305c51f124SMoriah Waterland 32315c51f124SMoriah Waterland if (passphrase == NULL) { 32325c51f124SMoriah Waterland /* unable to collect passwd from given source */ 32335c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 32345c51f124SMoriah Waterland gettext(MSG_NOPASS), arg); 32355c51f124SMoriah Waterland return (-1); 32365c51f124SMoriah Waterland } 32375c51f124SMoriah Waterland 3238*4656d474SGarrett D'Amore (void) strlcpy(buf, passphrase, size); 32395c51f124SMoriah Waterland return (strlen(buf)); 32405c51f124SMoriah Waterland } 3241