xref: /titanic_50/usr/src/lib/libpkg/common/pkgweb.c (revision 4656d4747c8743290bfbe910c64cd75eb4e4af8d)
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
set_passphrase_prompt(char * newprompt)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
set_passphrase_passarg(char * newpassarg)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
get_proxy_port(PKG_ERR * err,char ** proxy,ushort_t * port)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
path_valid(char * path)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
web_cleanup(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
web_session_control(PKG_ERR * err,char * url,char * dwnld_dir,keystore_handle_t keystore,char * proxy,ushort_t proxy_port,int retries,int timeout,int nointeract,char ** fname)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
get_signature(PKG_ERR * err,char * ids_name,struct pkgdev * devp,PKCS7 ** result)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
echo_out(int nointeract,char * fmt,...)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
strip_port(char * proxy)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
set_web_install(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
is_web_install(void)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
web_disconnect(void)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
check_dwnld_dir(PKG_ERR * err,char * dwnld_dir)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
ds_validate_signature(PKG_ERR * err,struct pkgdev * pkgdev,char ** pkgs,char * ids_name,PKCS7 * p7,STACK_OF (X509)* cas,url_hport_t * proxy,int nointeract)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
validate_signature(PKG_ERR * err,char * name,BIO * indata,PKCS7 * p7,STACK_OF (X509)* cas,url_hport_t * proxy,int nointeract)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
web_verify(int ok,X509_STORE_CTX * ctx)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
get_time_string(ASN1_GENERALIZEDTIME * intime)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
get_ocsp_uri(X509 * cert,char ** uri)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
ocsp_verify(PKG_ERR * err,X509 * cert,X509 * issuer,char * uri,url_hport_t * proxy,STACK_OF (X509)* cas)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
get_issuer(X509 ** issuer,X509_STORE_CTX * ctx,X509 * x)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
parse_url_proxy(PKG_ERR * err,char * url,char * proxy,ushort_t proxy_port)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
web_setup(PKG_ERR * err)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
web_connect(PKG_ERR * err)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
write_ca_file(PKG_ERR * err,char * tmpdir,STACK_OF (X509)* cacerts,char * passwd)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
web_send_request(PKG_ERR * err,int request_type,int cp,int ep)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
web_eval_headers(PKG_ERR * err)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
web_get_file(PKG_ERR * err,char * dwnld_dir,int nointeract,char ** fname)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
make_link(char * dwnld_dir,char * bname)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 *
get_startof_string(char * path,char token)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 *
get_endof_string(char * path,char token)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
progress_setup(int nointeract,ulong_t size_of_load)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
progress_report(int nointeract,ulong_t position)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
progress_finish(int nointeract)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
init_session(void)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
ck_dwnld_dir_space(PKG_ERR * err,char * dwnld_dir,ulong_t bytes_needed)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 *
get_unique_filename(char * dir,char * last_modified)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 *
replace_token(char * path,char oldtoken,char newtoken)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
trim(char * str)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
dequote(char * str)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
get_ENV_proxy(PKG_ERR * err,char ** proxy)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
get_ENV_proxyport(PKG_ERR * err,ushort_t * port)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
remove_dwnld_file(char * path)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 *
condense_lastmodified(char * last_modified)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
backoff()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
reset_backoff()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
_get_random_info(void * buf,int size)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
pkg_passphrase_cb(char * buf,int size,int rw,void * data)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