199ebb4caSwyllys /* 299ebb4caSwyllys * CDDL HEADER START 399ebb4caSwyllys * 499ebb4caSwyllys * The contents of this file are subject to the terms of the 599ebb4caSwyllys * Common Development and Distribution License (the "License"). 699ebb4caSwyllys * You may not use this file except in compliance with the License. 799ebb4caSwyllys * 899ebb4caSwyllys * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 999ebb4caSwyllys * or http://www.opensolaris.org/os/licensing. 1099ebb4caSwyllys * See the License for the specific language governing permissions 1199ebb4caSwyllys * and limitations under the License. 1299ebb4caSwyllys * 1399ebb4caSwyllys * When distributing Covered Code, include this CDDL HEADER in each 1499ebb4caSwyllys * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1599ebb4caSwyllys * If applicable, add the following below this CDDL HEADER, with the 1699ebb4caSwyllys * fields enclosed by brackets "[]" replaced with your own identifying 1799ebb4caSwyllys * information: Portions Copyright [yyyy] [name of copyright owner] 1899ebb4caSwyllys * 1999ebb4caSwyllys * CDDL HEADER END 2099ebb4caSwyllys */ 2199ebb4caSwyllys /* 22*30a5e8faSwyllys * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 2399ebb4caSwyllys * Use is subject to license terms. 2499ebb4caSwyllys */ 2599ebb4caSwyllys 2699ebb4caSwyllys #pragma ident "%Z%%M% %I% %E% SMI" 2799ebb4caSwyllys 2899ebb4caSwyllys #include <stdio.h> 2999ebb4caSwyllys #include <stdlib.h> 3099ebb4caSwyllys #include <string.h> 3199ebb4caSwyllys #include <ctype.h> 3299ebb4caSwyllys #include <malloc.h> 3399ebb4caSwyllys #include <libgen.h> 3499ebb4caSwyllys #include <fcntl.h> 3599ebb4caSwyllys #include <errno.h> 3699ebb4caSwyllys #include <cryptoutil.h> 3799ebb4caSwyllys #include "common.h" 3899ebb4caSwyllys #include <kmfapi.h> 3999ebb4caSwyllys 4099ebb4caSwyllys int 4199ebb4caSwyllys pk_download(int argc, char *argv[]) 4299ebb4caSwyllys { 4399ebb4caSwyllys int rv; 4499ebb4caSwyllys int opt; 4599ebb4caSwyllys extern int optind_av; 4699ebb4caSwyllys extern char *optarg_av; 4799ebb4caSwyllys int oclass = 0; 4899ebb4caSwyllys char *url = NULL; 4999ebb4caSwyllys char *http_proxy = NULL; 5099ebb4caSwyllys char *dir = NULL; 5199ebb4caSwyllys char *outfile = NULL; 5299ebb4caSwyllys char *proxy = NULL; 5399ebb4caSwyllys int proxy_port = 0; 5499ebb4caSwyllys KMF_HANDLE_T kmfhandle = NULL; 5599ebb4caSwyllys KMF_ENCODE_FORMAT format; 5699ebb4caSwyllys KMF_RETURN ch_rv = KMF_OK; 5799ebb4caSwyllys char *fullpath = NULL; 5899ebb4caSwyllys KMF_DATA cert = {NULL, 0}; 5999ebb4caSwyllys KMF_DATA cert_der = {NULL, 0}; 6099ebb4caSwyllys 6199ebb4caSwyllys while ((opt = getopt_av(argc, argv, 6299ebb4caSwyllys "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) { 6399ebb4caSwyllys 6499ebb4caSwyllys if (EMPTYSTRING(optarg_av)) 6599ebb4caSwyllys return (PK_ERR_USAGE); 6699ebb4caSwyllys switch (opt) { 6799ebb4caSwyllys case 't': 6899ebb4caSwyllys if (oclass) 6999ebb4caSwyllys return (PK_ERR_USAGE); 7099ebb4caSwyllys oclass = OT2Int(optarg_av); 7199ebb4caSwyllys if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ))) 7299ebb4caSwyllys return (PK_ERR_USAGE); 7399ebb4caSwyllys break; 7499ebb4caSwyllys case 'u': 7599ebb4caSwyllys if (url) 7699ebb4caSwyllys return (PK_ERR_USAGE); 7799ebb4caSwyllys url = optarg_av; 7899ebb4caSwyllys break; 7999ebb4caSwyllys case 'h': 8099ebb4caSwyllys if (http_proxy) 8199ebb4caSwyllys return (PK_ERR_USAGE); 8299ebb4caSwyllys http_proxy = optarg_av; 8399ebb4caSwyllys break; 8499ebb4caSwyllys case 'o': 8599ebb4caSwyllys if (outfile) 8699ebb4caSwyllys return (PK_ERR_USAGE); 8799ebb4caSwyllys outfile = optarg_av; 8899ebb4caSwyllys break; 8999ebb4caSwyllys case 'd': 9099ebb4caSwyllys if (dir) 9199ebb4caSwyllys return (PK_ERR_USAGE); 9299ebb4caSwyllys dir = optarg_av; 9399ebb4caSwyllys break; 9499ebb4caSwyllys default: 9599ebb4caSwyllys cryptoerror(LOG_STDERR, gettext( 9699ebb4caSwyllys "unrecognized download option '%s'\n"), 9799ebb4caSwyllys argv[optind_av]); 9899ebb4caSwyllys return (PK_ERR_USAGE); 9999ebb4caSwyllys } 10099ebb4caSwyllys } 10199ebb4caSwyllys 10299ebb4caSwyllys /* No additional args allowed. */ 10399ebb4caSwyllys argc -= optind_av; 10499ebb4caSwyllys argv += optind_av; 10599ebb4caSwyllys if (argc) { 10699ebb4caSwyllys return (PK_ERR_USAGE); 10799ebb4caSwyllys } 10899ebb4caSwyllys 10999ebb4caSwyllys /* Check the dir and outfile options */ 11099ebb4caSwyllys if (outfile == NULL) { 11199ebb4caSwyllys /* If outfile is not specified, use the basename of URI */ 11299ebb4caSwyllys outfile = basename(url); 11399ebb4caSwyllys } 11499ebb4caSwyllys 11599ebb4caSwyllys fullpath = get_fullpath(dir, outfile); 11699ebb4caSwyllys if (fullpath == NULL) { 11799ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile " 11899ebb4caSwyllys "option value \n")); 11999ebb4caSwyllys return (PK_ERR_USAGE); 12099ebb4caSwyllys } 12199ebb4caSwyllys /* Check if the file exists and might be overwritten. */ 12299ebb4caSwyllys if (access(fullpath, F_OK) == 0) { 12399ebb4caSwyllys cryptoerror(LOG_STDERR, 124*30a5e8faSwyllys gettext("Warning: file \"%s\" exists, " 125*30a5e8faSwyllys "will be overwritten."), fullpath); 12699ebb4caSwyllys if (yesno(gettext("Continue with download? "), 12799ebb4caSwyllys gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { 12899ebb4caSwyllys return (0); 12999ebb4caSwyllys } 13099ebb4caSwyllys } else { 13199ebb4caSwyllys rv = verify_file(fullpath); 13299ebb4caSwyllys if (rv != KMF_OK) { 13399ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("The file (%s) " 134*30a5e8faSwyllys "cannot be created.\n"), fullpath); 13599ebb4caSwyllys return (PK_ERR_USAGE); 13699ebb4caSwyllys } 13799ebb4caSwyllys } 13899ebb4caSwyllys 13999ebb4caSwyllys 14099ebb4caSwyllys /* URI MUST be specified */ 14199ebb4caSwyllys if (url == NULL) { 14299ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("A URL must be specified\n")); 14399ebb4caSwyllys rv = PK_ERR_USAGE; 14499ebb4caSwyllys goto end; 14599ebb4caSwyllys } 14699ebb4caSwyllys 14799ebb4caSwyllys /* 14899ebb4caSwyllys * Get the http proxy from the command "http_proxy" option or the 14999ebb4caSwyllys * environment variable. The command option has a higher priority. 15099ebb4caSwyllys */ 15199ebb4caSwyllys if (http_proxy == NULL) 15299ebb4caSwyllys http_proxy = getenv("http_proxy"); 15399ebb4caSwyllys 15499ebb4caSwyllys if (http_proxy != NULL) { 15599ebb4caSwyllys char *ptmp = http_proxy; 15699ebb4caSwyllys char *proxy_port_s; 15799ebb4caSwyllys 15899ebb4caSwyllys if (strncasecmp(ptmp, "http://", 7) == 0) 15999ebb4caSwyllys ptmp += 7; /* skip the scheme prefix */ 16099ebb4caSwyllys 16199ebb4caSwyllys proxy = strtok(ptmp, ":"); 16299ebb4caSwyllys proxy_port_s = strtok(NULL, "\0"); 16399ebb4caSwyllys if (proxy_port_s != NULL) 16499ebb4caSwyllys proxy_port = strtol(proxy_port_s, NULL, 0); 16599ebb4caSwyllys else 16699ebb4caSwyllys proxy_port = 8080; 16799ebb4caSwyllys } 16899ebb4caSwyllys 16999ebb4caSwyllys /* If objtype is not specified, default to CRL */ 17099ebb4caSwyllys if (oclass == 0) { 17199ebb4caSwyllys oclass = PK_CRL_OBJ; 17299ebb4caSwyllys } 17399ebb4caSwyllys 174*30a5e8faSwyllys if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { 17599ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); 17699ebb4caSwyllys rv = PK_ERR_USAGE; 17799ebb4caSwyllys goto end; 17899ebb4caSwyllys } 17999ebb4caSwyllys 18099ebb4caSwyllys /* Now we are ready to download */ 18199ebb4caSwyllys if (oclass & PK_CRL_OBJ) { 182*30a5e8faSwyllys rv = kmf_download_crl(kmfhandle, url, proxy, proxy_port, 30, 18399ebb4caSwyllys fullpath, &format); 18499ebb4caSwyllys } else if (oclass & PK_CERT_OBJ) { 185*30a5e8faSwyllys rv = kmf_download_cert(kmfhandle, url, proxy, proxy_port, 30, 18699ebb4caSwyllys fullpath, &format); 18799ebb4caSwyllys } 18899ebb4caSwyllys 18999ebb4caSwyllys if (rv != KMF_OK) { 19099ebb4caSwyllys switch (rv) { 19199ebb4caSwyllys case KMF_ERR_BAD_URI: 19299ebb4caSwyllys cryptoerror(LOG_STDERR, 19399ebb4caSwyllys gettext("Error in parsing URI\n")); 19499ebb4caSwyllys rv = PK_ERR_USAGE; 19599ebb4caSwyllys break; 19699ebb4caSwyllys case KMF_ERR_OPEN_FILE: 19799ebb4caSwyllys cryptoerror(LOG_STDERR, 19899ebb4caSwyllys gettext("Error in opening file\n")); 19999ebb4caSwyllys rv = PK_ERR_USAGE; 20099ebb4caSwyllys break; 20199ebb4caSwyllys case KMF_ERR_WRITE_FILE: 20299ebb4caSwyllys cryptoerror(LOG_STDERR, 20399ebb4caSwyllys gettext("Error in writing file\n")); 20499ebb4caSwyllys rv = PK_ERR_USAGE; 20599ebb4caSwyllys break; 20699ebb4caSwyllys case KMF_ERR_BAD_CRLFILE: 20799ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("Not a CRL file\n")); 20899ebb4caSwyllys rv = PK_ERR_USAGE; 20999ebb4caSwyllys break; 21099ebb4caSwyllys case KMF_ERR_BAD_CERTFILE: 21199ebb4caSwyllys cryptoerror(LOG_STDERR, 21299ebb4caSwyllys gettext("Not a certificate file\n")); 21399ebb4caSwyllys rv = PK_ERR_USAGE; 21499ebb4caSwyllys break; 21599ebb4caSwyllys case KMF_ERR_MEMORY: 21699ebb4caSwyllys cryptoerror(LOG_STDERR, 21799ebb4caSwyllys gettext("Not enough memory\n")); 21899ebb4caSwyllys rv = PK_ERR_SYSTEM; 21999ebb4caSwyllys break; 22099ebb4caSwyllys default: 22199ebb4caSwyllys cryptoerror(LOG_STDERR, 22299ebb4caSwyllys gettext("Error in downloading the file.\n")); 22399ebb4caSwyllys rv = PK_ERR_SYSTEM; 22499ebb4caSwyllys break; 22599ebb4caSwyllys } 22699ebb4caSwyllys goto end; 22799ebb4caSwyllys } 22899ebb4caSwyllys 22999ebb4caSwyllys /* 23099ebb4caSwyllys * If the file is successfully downloaded, we also check the date. 23199ebb4caSwyllys * If the downloaded file is outdated, give a warning. 23299ebb4caSwyllys */ 23399ebb4caSwyllys if (oclass & PK_CRL_OBJ) { 234*30a5e8faSwyllys ch_rv = kmf_check_crl_date(kmfhandle, fullpath); 23599ebb4caSwyllys } else { /* certificate */ 236*30a5e8faSwyllys ch_rv = kmf_read_input_file(kmfhandle, fullpath, &cert); 23799ebb4caSwyllys if (ch_rv != KMF_OK) 23899ebb4caSwyllys goto end; 23999ebb4caSwyllys 24099ebb4caSwyllys if (format == KMF_FORMAT_PEM) { 24199ebb4caSwyllys int len; 242*30a5e8faSwyllys ch_rv = kmf_pem_to_der(cert.Data, cert.Length, 24399ebb4caSwyllys &cert_der.Data, &len); 24499ebb4caSwyllys if (ch_rv != KMF_OK) 24599ebb4caSwyllys goto end; 24699ebb4caSwyllys cert_der.Length = (size_t)len; 24799ebb4caSwyllys } 24899ebb4caSwyllys 249*30a5e8faSwyllys ch_rv = kmf_check_cert_date(kmfhandle, 25099ebb4caSwyllys format == KMF_FORMAT_ASN1 ? &cert : &cert_der); 25199ebb4caSwyllys } 25299ebb4caSwyllys 25399ebb4caSwyllys end: 25499ebb4caSwyllys if (ch_rv == KMF_ERR_VALIDITY_PERIOD) { 25599ebb4caSwyllys cryptoerror(LOG_STDERR, 25699ebb4caSwyllys gettext("Warning: the downloaded file is expired.\n")); 25799ebb4caSwyllys } else if (ch_rv != KMF_OK) { 25899ebb4caSwyllys cryptoerror(LOG_STDERR, 25999ebb4caSwyllys gettext("Warning: failed to check the validity.\n")); 26099ebb4caSwyllys } 26199ebb4caSwyllys 26299ebb4caSwyllys if (fullpath) 26399ebb4caSwyllys free(fullpath); 26499ebb4caSwyllys 265*30a5e8faSwyllys kmf_free_data(&cert); 266*30a5e8faSwyllys kmf_free_data(&cert_der); 26799ebb4caSwyllys 268*30a5e8faSwyllys (void) kmf_finalize(kmfhandle); 26999ebb4caSwyllys return (rv); 27099ebb4caSwyllys } 271