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