13089Swyllys /* 23089Swyllys * CDDL HEADER START 33089Swyllys * 43089Swyllys * The contents of this file are subject to the terms of the 53089Swyllys * Common Development and Distribution License (the "License"). 63089Swyllys * You may not use this file except in compliance with the License. 73089Swyllys * 83089Swyllys * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93089Swyllys * or http://www.opensolaris.org/os/licensing. 103089Swyllys * See the License for the specific language governing permissions 113089Swyllys * and limitations under the License. 123089Swyllys * 133089Swyllys * When distributing Covered Code, include this CDDL HEADER in each 143089Swyllys * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153089Swyllys * If applicable, add the following below this CDDL HEADER, with the 163089Swyllys * fields enclosed by brackets "[]" replaced with your own identifying 173089Swyllys * information: Portions Copyright [yyyy] [name of copyright owner] 183089Swyllys * 193089Swyllys * CDDL HEADER END 203089Swyllys */ 213089Swyllys /* 22*5051Swyllys * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 233089Swyllys * Use is subject to license terms. 243089Swyllys */ 253089Swyllys 263089Swyllys #pragma ident "%Z%%M% %I% %E% SMI" 273089Swyllys 283089Swyllys #include <stdio.h> 293089Swyllys #include <stdlib.h> 303089Swyllys #include <string.h> 313089Swyllys #include <ctype.h> 323089Swyllys #include <malloc.h> 333089Swyllys #include <libgen.h> 343089Swyllys #include <fcntl.h> 353089Swyllys #include <errno.h> 363089Swyllys #include <cryptoutil.h> 373089Swyllys #include "common.h" 383089Swyllys #include <kmfapi.h> 393089Swyllys 403089Swyllys int 413089Swyllys pk_download(int argc, char *argv[]) 423089Swyllys { 433089Swyllys int rv; 443089Swyllys int opt; 453089Swyllys extern int optind_av; 463089Swyllys extern char *optarg_av; 473089Swyllys int oclass = 0; 483089Swyllys char *url = NULL; 493089Swyllys char *http_proxy = NULL; 503089Swyllys char *dir = NULL; 513089Swyllys char *outfile = NULL; 523089Swyllys char *proxy = NULL; 533089Swyllys int proxy_port = 0; 543089Swyllys KMF_HANDLE_T kmfhandle = NULL; 553089Swyllys KMF_ENCODE_FORMAT format; 563089Swyllys KMF_RETURN ch_rv = KMF_OK; 573089Swyllys char *fullpath = NULL; 583089Swyllys KMF_DATA cert = {NULL, 0}; 593089Swyllys KMF_DATA cert_der = {NULL, 0}; 603089Swyllys 613089Swyllys while ((opt = getopt_av(argc, argv, 623089Swyllys "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) { 633089Swyllys 643089Swyllys if (EMPTYSTRING(optarg_av)) 653089Swyllys return (PK_ERR_USAGE); 663089Swyllys switch (opt) { 673089Swyllys case 't': 683089Swyllys if (oclass) 693089Swyllys return (PK_ERR_USAGE); 703089Swyllys oclass = OT2Int(optarg_av); 713089Swyllys if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ))) 723089Swyllys return (PK_ERR_USAGE); 733089Swyllys break; 743089Swyllys case 'u': 753089Swyllys if (url) 763089Swyllys return (PK_ERR_USAGE); 773089Swyllys url = optarg_av; 783089Swyllys break; 793089Swyllys case 'h': 803089Swyllys if (http_proxy) 813089Swyllys return (PK_ERR_USAGE); 823089Swyllys http_proxy = optarg_av; 833089Swyllys break; 843089Swyllys case 'o': 853089Swyllys if (outfile) 863089Swyllys return (PK_ERR_USAGE); 873089Swyllys outfile = optarg_av; 883089Swyllys break; 893089Swyllys case 'd': 903089Swyllys if (dir) 913089Swyllys return (PK_ERR_USAGE); 923089Swyllys dir = optarg_av; 933089Swyllys break; 943089Swyllys default: 953089Swyllys cryptoerror(LOG_STDERR, gettext( 963089Swyllys "unrecognized download option '%s'\n"), 973089Swyllys argv[optind_av]); 983089Swyllys return (PK_ERR_USAGE); 993089Swyllys } 1003089Swyllys } 1013089Swyllys 1023089Swyllys /* No additional args allowed. */ 1033089Swyllys argc -= optind_av; 1043089Swyllys argv += optind_av; 1053089Swyllys if (argc) { 1063089Swyllys return (PK_ERR_USAGE); 1073089Swyllys } 1083089Swyllys 1093089Swyllys /* Check the dir and outfile options */ 1103089Swyllys if (outfile == NULL) { 1113089Swyllys /* If outfile is not specified, use the basename of URI */ 1123089Swyllys outfile = basename(url); 1133089Swyllys } 1143089Swyllys 1153089Swyllys fullpath = get_fullpath(dir, outfile); 1163089Swyllys if (fullpath == NULL) { 1173089Swyllys cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile " 1183089Swyllys "option value \n")); 1193089Swyllys return (PK_ERR_USAGE); 1203089Swyllys } 1213089Swyllys /* Check if the file exists and might be overwritten. */ 1223089Swyllys if (access(fullpath, F_OK) == 0) { 1233089Swyllys cryptoerror(LOG_STDERR, 124*5051Swyllys gettext("Warning: file \"%s\" exists, " 125*5051Swyllys "will be overwritten."), fullpath); 1263089Swyllys if (yesno(gettext("Continue with download? "), 1273089Swyllys gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { 1283089Swyllys return (0); 1293089Swyllys } 1303089Swyllys } else { 1313089Swyllys rv = verify_file(fullpath); 1323089Swyllys if (rv != KMF_OK) { 1333089Swyllys cryptoerror(LOG_STDERR, gettext("The file (%s) " 134*5051Swyllys "cannot be created.\n"), fullpath); 1353089Swyllys return (PK_ERR_USAGE); 1363089Swyllys } 1373089Swyllys } 1383089Swyllys 1393089Swyllys 1403089Swyllys /* URI MUST be specified */ 1413089Swyllys if (url == NULL) { 1423089Swyllys cryptoerror(LOG_STDERR, gettext("A URL must be specified\n")); 1433089Swyllys rv = PK_ERR_USAGE; 1443089Swyllys goto end; 1453089Swyllys } 1463089Swyllys 1473089Swyllys /* 1483089Swyllys * Get the http proxy from the command "http_proxy" option or the 1493089Swyllys * environment variable. The command option has a higher priority. 1503089Swyllys */ 1513089Swyllys if (http_proxy == NULL) 1523089Swyllys http_proxy = getenv("http_proxy"); 1533089Swyllys 1543089Swyllys if (http_proxy != NULL) { 1553089Swyllys char *ptmp = http_proxy; 1563089Swyllys char *proxy_port_s; 1573089Swyllys 1583089Swyllys if (strncasecmp(ptmp, "http://", 7) == 0) 1593089Swyllys ptmp += 7; /* skip the scheme prefix */ 1603089Swyllys 1613089Swyllys proxy = strtok(ptmp, ":"); 1623089Swyllys proxy_port_s = strtok(NULL, "\0"); 1633089Swyllys if (proxy_port_s != NULL) 1643089Swyllys proxy_port = strtol(proxy_port_s, NULL, 0); 1653089Swyllys else 1663089Swyllys proxy_port = 8080; 1673089Swyllys } 1683089Swyllys 1693089Swyllys /* If objtype is not specified, default to CRL */ 1703089Swyllys if (oclass == 0) { 1713089Swyllys oclass = PK_CRL_OBJ; 1723089Swyllys } 1733089Swyllys 174*5051Swyllys if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { 1753089Swyllys cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); 1763089Swyllys rv = PK_ERR_USAGE; 1773089Swyllys goto end; 1783089Swyllys } 1793089Swyllys 1803089Swyllys /* Now we are ready to download */ 1813089Swyllys if (oclass & PK_CRL_OBJ) { 182*5051Swyllys rv = kmf_download_crl(kmfhandle, url, proxy, proxy_port, 30, 1833089Swyllys fullpath, &format); 1843089Swyllys } else if (oclass & PK_CERT_OBJ) { 185*5051Swyllys rv = kmf_download_cert(kmfhandle, url, proxy, proxy_port, 30, 1863089Swyllys fullpath, &format); 1873089Swyllys } 1883089Swyllys 1893089Swyllys if (rv != KMF_OK) { 1903089Swyllys switch (rv) { 1913089Swyllys case KMF_ERR_BAD_URI: 1923089Swyllys cryptoerror(LOG_STDERR, 1933089Swyllys gettext("Error in parsing URI\n")); 1943089Swyllys rv = PK_ERR_USAGE; 1953089Swyllys break; 1963089Swyllys case KMF_ERR_OPEN_FILE: 1973089Swyllys cryptoerror(LOG_STDERR, 1983089Swyllys gettext("Error in opening file\n")); 1993089Swyllys rv = PK_ERR_USAGE; 2003089Swyllys break; 2013089Swyllys case KMF_ERR_WRITE_FILE: 2023089Swyllys cryptoerror(LOG_STDERR, 2033089Swyllys gettext("Error in writing file\n")); 2043089Swyllys rv = PK_ERR_USAGE; 2053089Swyllys break; 2063089Swyllys case KMF_ERR_BAD_CRLFILE: 2073089Swyllys cryptoerror(LOG_STDERR, gettext("Not a CRL file\n")); 2083089Swyllys rv = PK_ERR_USAGE; 2093089Swyllys break; 2103089Swyllys case KMF_ERR_BAD_CERTFILE: 2113089Swyllys cryptoerror(LOG_STDERR, 2123089Swyllys gettext("Not a certificate file\n")); 2133089Swyllys rv = PK_ERR_USAGE; 2143089Swyllys break; 2153089Swyllys case KMF_ERR_MEMORY: 2163089Swyllys cryptoerror(LOG_STDERR, 2173089Swyllys gettext("Not enough memory\n")); 2183089Swyllys rv = PK_ERR_SYSTEM; 2193089Swyllys break; 2203089Swyllys default: 2213089Swyllys cryptoerror(LOG_STDERR, 2223089Swyllys gettext("Error in downloading the file.\n")); 2233089Swyllys rv = PK_ERR_SYSTEM; 2243089Swyllys break; 2253089Swyllys } 2263089Swyllys goto end; 2273089Swyllys } 2283089Swyllys 2293089Swyllys /* 2303089Swyllys * If the file is successfully downloaded, we also check the date. 2313089Swyllys * If the downloaded file is outdated, give a warning. 2323089Swyllys */ 2333089Swyllys if (oclass & PK_CRL_OBJ) { 234*5051Swyllys ch_rv = kmf_check_crl_date(kmfhandle, fullpath); 2353089Swyllys } else { /* certificate */ 236*5051Swyllys ch_rv = kmf_read_input_file(kmfhandle, fullpath, &cert); 2373089Swyllys if (ch_rv != KMF_OK) 2383089Swyllys goto end; 2393089Swyllys 2403089Swyllys if (format == KMF_FORMAT_PEM) { 2413089Swyllys int len; 242*5051Swyllys ch_rv = kmf_pem_to_der(cert.Data, cert.Length, 2433089Swyllys &cert_der.Data, &len); 2443089Swyllys if (ch_rv != KMF_OK) 2453089Swyllys goto end; 2463089Swyllys cert_der.Length = (size_t)len; 2473089Swyllys } 2483089Swyllys 249*5051Swyllys ch_rv = kmf_check_cert_date(kmfhandle, 2503089Swyllys format == KMF_FORMAT_ASN1 ? &cert : &cert_der); 2513089Swyllys } 2523089Swyllys 2533089Swyllys end: 2543089Swyllys if (ch_rv == KMF_ERR_VALIDITY_PERIOD) { 2553089Swyllys cryptoerror(LOG_STDERR, 2563089Swyllys gettext("Warning: the downloaded file is expired.\n")); 2573089Swyllys } else if (ch_rv != KMF_OK) { 2583089Swyllys cryptoerror(LOG_STDERR, 2593089Swyllys gettext("Warning: failed to check the validity.\n")); 2603089Swyllys } 2613089Swyllys 2623089Swyllys if (fullpath) 2633089Swyllys free(fullpath); 2643089Swyllys 265*5051Swyllys kmf_free_data(&cert); 266*5051Swyllys kmf_free_data(&cert_der); 2673089Swyllys 268*5051Swyllys (void) kmf_finalize(kmfhandle); 2693089Swyllys return (rv); 2703089Swyllys } 271