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 40 int 41 pk_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 253 end: 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