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 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 = {NULL, 0}; 55 KMF_DATA cert_der = {NULL, 0}; 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