download.c revision 5051:cbbb7c8b40a9
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <ctype.h>
32#include <malloc.h>
33#include <libgen.h>
34#include <fcntl.h>
35#include <errno.h>
36#include <cryptoutil.h>
37#include "common.h"
38#include <kmfapi.h>
39
40int
41pk_download(int argc, char *argv[])
42{
43	int rv;
44	int opt;
45	extern int	optind_av;
46	extern char	*optarg_av;
47	int oclass = 0;
48	char *url = NULL;
49	char *http_proxy = NULL;
50	char *dir = NULL;
51	char *outfile = NULL;
52	char *proxy = NULL;
53	int  proxy_port = 0;
54	KMF_HANDLE_T	kmfhandle = NULL;
55	KMF_ENCODE_FORMAT format;
56	KMF_RETURN ch_rv = KMF_OK;
57	char *fullpath = NULL;
58	KMF_DATA cert = {NULL, 0};
59	KMF_DATA cert_der = {NULL, 0};
60
61	while ((opt = getopt_av(argc, argv,
62	    "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) {
63
64		if (EMPTYSTRING(optarg_av))
65			return (PK_ERR_USAGE);
66		switch (opt) {
67		case 't':
68			if (oclass)
69				return (PK_ERR_USAGE);
70			oclass = OT2Int(optarg_av);
71			if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ)))
72				return (PK_ERR_USAGE);
73			break;
74		case 'u':
75			if (url)
76				return (PK_ERR_USAGE);
77			url = optarg_av;
78			break;
79		case 'h':
80			if (http_proxy)
81				return (PK_ERR_USAGE);
82			http_proxy = optarg_av;
83			break;
84		case 'o':
85			if (outfile)
86				return (PK_ERR_USAGE);
87			outfile = optarg_av;
88			break;
89		case 'd':
90			if (dir)
91				return (PK_ERR_USAGE);
92			dir = optarg_av;
93			break;
94		default:
95			cryptoerror(LOG_STDERR, gettext(
96			    "unrecognized download option '%s'\n"),
97			    argv[optind_av]);
98			return (PK_ERR_USAGE);
99		}
100	}
101
102	/* No additional args allowed. */
103	argc -= optind_av;
104	argv += optind_av;
105	if (argc) {
106		return (PK_ERR_USAGE);
107	}
108
109	/* Check the dir and outfile options */
110	if (outfile == NULL) {
111		/* If outfile is not specified, use the basename of URI */
112		outfile = basename(url);
113	}
114
115	fullpath = get_fullpath(dir, outfile);
116	if (fullpath == NULL) {
117		cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile "
118		    "option value \n"));
119		return (PK_ERR_USAGE);
120	}
121	/* Check if the file exists and might be overwritten. */
122	if (access(fullpath, F_OK) == 0) {
123		cryptoerror(LOG_STDERR,
124		    gettext("Warning: file \"%s\" exists, "
125		    "will be overwritten."), fullpath);
126		if (yesno(gettext("Continue with download? "),
127		    gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
128			return (0);
129		}
130	} else {
131		rv = verify_file(fullpath);
132		if (rv != KMF_OK) {
133			cryptoerror(LOG_STDERR, gettext("The file (%s) "
134			    "cannot be created.\n"), fullpath);
135			return (PK_ERR_USAGE);
136		}
137	}
138
139
140	/* URI MUST be specified */
141	if (url == NULL) {
142		cryptoerror(LOG_STDERR, gettext("A URL must be specified\n"));
143		rv = PK_ERR_USAGE;
144		goto end;
145	}
146
147	/*
148	 * Get the http proxy from the command "http_proxy" option or the
149	 * environment variable.  The command option has a higher priority.
150	 */
151	if (http_proxy == NULL)
152		http_proxy = getenv("http_proxy");
153
154	if (http_proxy != NULL) {
155		char *ptmp = http_proxy;
156		char *proxy_port_s;
157
158		if (strncasecmp(ptmp, "http://", 7) == 0)
159			ptmp += 7;	/* skip the scheme prefix */
160
161		proxy = strtok(ptmp, ":");
162		proxy_port_s = strtok(NULL, "\0");
163		if (proxy_port_s != NULL)
164			proxy_port = strtol(proxy_port_s, NULL, 0);
165		else
166			proxy_port = 8080;
167	}
168
169	/* If objtype is not specified, default to CRL */
170	if (oclass == 0) {
171		oclass = PK_CRL_OBJ;
172	}
173
174	if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
175		cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
176		rv = PK_ERR_USAGE;
177		goto end;
178	}
179
180	/* Now we are ready to download */
181	if (oclass & PK_CRL_OBJ) {
182		rv = kmf_download_crl(kmfhandle, url, proxy, proxy_port, 30,
183		    fullpath, &format);
184	} else if (oclass & PK_CERT_OBJ) {
185		rv = kmf_download_cert(kmfhandle, url, proxy, proxy_port, 30,
186		    fullpath, &format);
187	}
188
189	if (rv != KMF_OK) {
190		switch (rv) {
191		case KMF_ERR_BAD_URI:
192			cryptoerror(LOG_STDERR,
193			    gettext("Error in parsing URI\n"));
194			rv = PK_ERR_USAGE;
195			break;
196		case KMF_ERR_OPEN_FILE:
197			cryptoerror(LOG_STDERR,
198			    gettext("Error in opening file\n"));
199			rv = PK_ERR_USAGE;
200			break;
201		case KMF_ERR_WRITE_FILE:
202			cryptoerror(LOG_STDERR,
203			    gettext("Error in writing file\n"));
204			rv = PK_ERR_USAGE;
205			break;
206		case KMF_ERR_BAD_CRLFILE:
207			cryptoerror(LOG_STDERR, gettext("Not a CRL file\n"));
208			rv = PK_ERR_USAGE;
209			break;
210		case KMF_ERR_BAD_CERTFILE:
211			cryptoerror(LOG_STDERR,
212			    gettext("Not a certificate file\n"));
213			rv = PK_ERR_USAGE;
214			break;
215		case KMF_ERR_MEMORY:
216			cryptoerror(LOG_STDERR,
217			    gettext("Not enough memory\n"));
218			rv = PK_ERR_SYSTEM;
219			break;
220		default:
221			cryptoerror(LOG_STDERR,
222			    gettext("Error in downloading the file.\n"));
223			rv = PK_ERR_SYSTEM;
224			break;
225		}
226		goto end;
227	}
228
229	/*
230	 * If the file is successfully downloaded, we also check the date.
231	 * If the downloaded file is outdated, give a warning.
232	 */
233	if (oclass & PK_CRL_OBJ) {
234		ch_rv = kmf_check_crl_date(kmfhandle, fullpath);
235	} else { /* certificate */
236		ch_rv = kmf_read_input_file(kmfhandle, fullpath, &cert);
237		if (ch_rv != KMF_OK)
238			goto end;
239
240		if (format == KMF_FORMAT_PEM) {
241			int len;
242			ch_rv = kmf_pem_to_der(cert.Data, cert.Length,
243			    &cert_der.Data, &len);
244			if (ch_rv != KMF_OK)
245				goto end;
246			cert_der.Length = (size_t)len;
247		}
248
249		ch_rv = kmf_check_cert_date(kmfhandle,
250		    format == KMF_FORMAT_ASN1 ? &cert : &cert_der);
251	}
252
253end:
254	if (ch_rv == KMF_ERR_VALIDITY_PERIOD) {
255		cryptoerror(LOG_STDERR,
256		    gettext("Warning: the downloaded file is expired.\n"));
257	} else if (ch_rv != KMF_OK) {
258		cryptoerror(LOG_STDERR,
259		    gettext("Warning: failed to check the validity.\n"));
260	}
261
262	if (fullpath)
263		free(fullpath);
264
265	kmf_free_data(&cert);
266	kmf_free_data(&cert_der);
267
268	(void) kmf_finalize(kmfhandle);
269	return (rv);
270}
271