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 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <malloc.h>
29 #include <libgen.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <cryptoutil.h>
33 #include "common.h"
34 #include <kmfapi.h>
35
36 int
pk_download(int argc,char * argv[])37 pk_download(int argc, char *argv[])
38 {
39 int rv;
40 int opt;
41 extern int optind_av;
42 extern char *optarg_av;
43 int oclass = 0;
44 char *url = NULL;
45 char *http_proxy = NULL;
46 char *dir = NULL;
47 char *outfile = NULL;
48 char *proxy = NULL;
49 int proxy_port = 0;
50 KMF_HANDLE_T kmfhandle = NULL;
51 KMF_ENCODE_FORMAT format;
52 KMF_RETURN ch_rv = KMF_OK;
53 char *fullpath = NULL;
54 KMF_DATA cert = { 0, NULL };
55 KMF_DATA cert_der = { 0, NULL };
56
57 while ((opt = getopt_av(argc, argv,
58 "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) {
59
60 if (EMPTYSTRING(optarg_av))
61 return (PK_ERR_USAGE);
62 switch (opt) {
63 case 't':
64 if (oclass)
65 return (PK_ERR_USAGE);
66 oclass = OT2Int(optarg_av);
67 if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ)))
68 return (PK_ERR_USAGE);
69 break;
70 case 'u':
71 if (url)
72 return (PK_ERR_USAGE);
73 url = optarg_av;
74 break;
75 case 'h':
76 if (http_proxy)
77 return (PK_ERR_USAGE);
78 http_proxy = optarg_av;
79 break;
80 case 'o':
81 if (outfile)
82 return (PK_ERR_USAGE);
83 outfile = optarg_av;
84 break;
85 case 'd':
86 if (dir)
87 return (PK_ERR_USAGE);
88 dir = optarg_av;
89 break;
90 default:
91 cryptoerror(LOG_STDERR, gettext(
92 "unrecognized download option '%s'\n"),
93 argv[optind_av]);
94 return (PK_ERR_USAGE);
95 }
96 }
97
98 /* No additional args allowed. */
99 argc -= optind_av;
100 argv += optind_av;
101 if (argc) {
102 return (PK_ERR_USAGE);
103 }
104
105 /* Check the dir and outfile options */
106 if (outfile == NULL) {
107 /* If outfile is not specified, use the basename of URI */
108 outfile = basename(url);
109 }
110
111 fullpath = get_fullpath(dir, outfile);
112 if (fullpath == NULL) {
113 cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile "
114 "option value \n"));
115 return (PK_ERR_USAGE);
116 }
117 /* Check if the file exists and might be overwritten. */
118 if (verify_file(fullpath) != KMF_OK) {
119 cryptoerror(LOG_STDERR,
120 gettext("Warning: file \"%s\" exists, "
121 "will be overwritten."), fullpath);
122 if (yesno(gettext("Continue with download? "),
123 gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
124 return (0);
125 }
126 }
127 /* URI MUST be specified */
128 if (url == NULL) {
129 cryptoerror(LOG_STDERR, gettext("A URL must be specified\n"));
130 rv = PK_ERR_USAGE;
131 goto end;
132 }
133
134 /*
135 * Get the http proxy from the command "http_proxy" option or the
136 * environment variable. The command option has a higher priority.
137 */
138 if (http_proxy == NULL)
139 http_proxy = getenv("http_proxy");
140
141 if (http_proxy != NULL) {
142 char *ptmp = http_proxy;
143 char *proxy_port_s;
144
145 if (strncasecmp(ptmp, "http://", 7) == 0)
146 ptmp += 7; /* skip the scheme prefix */
147
148 proxy = strtok(ptmp, ":");
149 proxy_port_s = strtok(NULL, "\0");
150 if (proxy_port_s != NULL)
151 proxy_port = strtol(proxy_port_s, NULL, 0);
152 else
153 proxy_port = 8080;
154 }
155
156 /* If objtype is not specified, default to CRL */
157 if (oclass == 0) {
158 oclass = PK_CRL_OBJ;
159 }
160
161 if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
162 cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
163 rv = PK_ERR_USAGE;
164 goto end;
165 }
166
167 /* Now we are ready to download */
168 if (oclass & PK_CRL_OBJ) {
169 rv = kmf_download_crl(kmfhandle, url, proxy, proxy_port, 30,
170 fullpath, &format);
171 } else if (oclass & PK_CERT_OBJ) {
172 rv = kmf_download_cert(kmfhandle, url, proxy, proxy_port, 30,
173 fullpath, &format);
174 }
175
176 if (rv != KMF_OK) {
177 switch (rv) {
178 case KMF_ERR_BAD_URI:
179 cryptoerror(LOG_STDERR,
180 gettext("Error in parsing URI\n"));
181 rv = PK_ERR_USAGE;
182 break;
183 case KMF_ERR_OPEN_FILE:
184 cryptoerror(LOG_STDERR,
185 gettext("Error in opening file\n"));
186 rv = PK_ERR_USAGE;
187 break;
188 case KMF_ERR_WRITE_FILE:
189 cryptoerror(LOG_STDERR,
190 gettext("Error in writing file\n"));
191 rv = PK_ERR_USAGE;
192 break;
193 case KMF_ERR_BAD_CRLFILE:
194 cryptoerror(LOG_STDERR, gettext("Not a CRL file\n"));
195 rv = PK_ERR_USAGE;
196 break;
197 case KMF_ERR_BAD_CERTFILE:
198 cryptoerror(LOG_STDERR,
199 gettext("Not a certificate file\n"));
200 rv = PK_ERR_USAGE;
201 break;
202 case KMF_ERR_MEMORY:
203 cryptoerror(LOG_STDERR,
204 gettext("Not enough memory\n"));
205 rv = PK_ERR_SYSTEM;
206 break;
207 default:
208 cryptoerror(LOG_STDERR,
209 gettext("Error in downloading the file.\n"));
210 rv = PK_ERR_SYSTEM;
211 break;
212 }
213 goto end;
214 }
215
216 /*
217 * If the file is successfully downloaded, we also check the date.
218 * If the downloaded file is outdated, give a warning.
219 */
220 if (oclass & PK_CRL_OBJ) {
221 ch_rv = kmf_check_crl_date(kmfhandle, fullpath);
222 } else { /* certificate */
223 ch_rv = kmf_read_input_file(kmfhandle, fullpath, &cert);
224 if (ch_rv != KMF_OK)
225 goto end;
226
227 if (format == KMF_FORMAT_PEM) {
228 int len;
229 ch_rv = kmf_pem_to_der(cert.Data, cert.Length,
230 &cert_der.Data, &len);
231 if (ch_rv != KMF_OK)
232 goto end;
233 cert_der.Length = (size_t)len;
234 }
235
236 ch_rv = kmf_check_cert_date(kmfhandle,
237 format == KMF_FORMAT_ASN1 ? &cert : &cert_der);
238 }
239
240 end:
241 if (ch_rv == KMF_ERR_VALIDITY_PERIOD) {
242 cryptoerror(LOG_STDERR,
243 gettext("Warning: the downloaded file is expired.\n"));
244 } else if (ch_rv != KMF_OK) {
245 cryptoerror(LOG_STDERR,
246 gettext("Warning: failed to check the validity.\n"));
247 }
248
249 if (fullpath)
250 free(fullpath);
251
252 kmf_free_data(&cert);
253 kmf_free_data(&cert_der);
254
255 (void) kmf_finalize(kmfhandle);
256 return (rv);
257 }
258