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