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
20*12234Swyllys.ingersoll@sun.com *
21*12234Swyllys.ingersoll@sun.com * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
223089Swyllys */
233089Swyllys
243089Swyllys #include <stdio.h>
253089Swyllys #include <stdlib.h>
263089Swyllys #include <string.h>
273089Swyllys #include <ctype.h>
283089Swyllys #include <malloc.h>
293089Swyllys #include <libgen.h>
303089Swyllys #include <fcntl.h>
313089Swyllys #include <errno.h>
323089Swyllys #include <cryptoutil.h>
333089Swyllys #include "common.h"
343089Swyllys #include <kmfapi.h>
353089Swyllys
363089Swyllys int
pk_download(int argc,char * argv[])373089Swyllys pk_download(int argc, char *argv[])
383089Swyllys {
393089Swyllys int rv;
403089Swyllys int opt;
413089Swyllys extern int optind_av;
423089Swyllys extern char *optarg_av;
433089Swyllys int oclass = 0;
443089Swyllys char *url = NULL;
453089Swyllys char *http_proxy = NULL;
463089Swyllys char *dir = NULL;
473089Swyllys char *outfile = NULL;
483089Swyllys char *proxy = NULL;
493089Swyllys int proxy_port = 0;
503089Swyllys KMF_HANDLE_T kmfhandle = NULL;
513089Swyllys KMF_ENCODE_FORMAT format;
523089Swyllys KMF_RETURN ch_rv = KMF_OK;
533089Swyllys char *fullpath = NULL;
543089Swyllys KMF_DATA cert = {NULL, 0};
553089Swyllys KMF_DATA cert_der = {NULL, 0};
563089Swyllys
573089Swyllys while ((opt = getopt_av(argc, argv,
583089Swyllys "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) {
593089Swyllys
603089Swyllys if (EMPTYSTRING(optarg_av))
613089Swyllys return (PK_ERR_USAGE);
623089Swyllys switch (opt) {
633089Swyllys case 't':
643089Swyllys if (oclass)
653089Swyllys return (PK_ERR_USAGE);
663089Swyllys oclass = OT2Int(optarg_av);
673089Swyllys if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ)))
683089Swyllys return (PK_ERR_USAGE);
693089Swyllys break;
703089Swyllys case 'u':
713089Swyllys if (url)
723089Swyllys return (PK_ERR_USAGE);
733089Swyllys url = optarg_av;
743089Swyllys break;
753089Swyllys case 'h':
763089Swyllys if (http_proxy)
773089Swyllys return (PK_ERR_USAGE);
783089Swyllys http_proxy = optarg_av;
793089Swyllys break;
803089Swyllys case 'o':
813089Swyllys if (outfile)
823089Swyllys return (PK_ERR_USAGE);
833089Swyllys outfile = optarg_av;
843089Swyllys break;
853089Swyllys case 'd':
863089Swyllys if (dir)
873089Swyllys return (PK_ERR_USAGE);
883089Swyllys dir = optarg_av;
893089Swyllys break;
903089Swyllys default:
913089Swyllys cryptoerror(LOG_STDERR, gettext(
923089Swyllys "unrecognized download option '%s'\n"),
933089Swyllys argv[optind_av]);
943089Swyllys return (PK_ERR_USAGE);
953089Swyllys }
963089Swyllys }
973089Swyllys
983089Swyllys /* No additional args allowed. */
993089Swyllys argc -= optind_av;
1003089Swyllys argv += optind_av;
1013089Swyllys if (argc) {
1023089Swyllys return (PK_ERR_USAGE);
1033089Swyllys }
1043089Swyllys
1053089Swyllys /* Check the dir and outfile options */
1063089Swyllys if (outfile == NULL) {
1073089Swyllys /* If outfile is not specified, use the basename of URI */
1083089Swyllys outfile = basename(url);
1093089Swyllys }
1103089Swyllys
1113089Swyllys fullpath = get_fullpath(dir, outfile);
1123089Swyllys if (fullpath == NULL) {
1133089Swyllys cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile "
1143089Swyllys "option value \n"));
1153089Swyllys return (PK_ERR_USAGE);
1163089Swyllys }
1173089Swyllys /* Check if the file exists and might be overwritten. */
118*12234Swyllys.ingersoll@sun.com if (verify_file(fullpath) != KMF_OK) {
1193089Swyllys cryptoerror(LOG_STDERR,
1205051Swyllys gettext("Warning: file \"%s\" exists, "
1215051Swyllys "will be overwritten."), fullpath);
1223089Swyllys if (yesno(gettext("Continue with download? "),
1233089Swyllys gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
1243089Swyllys return (0);
1253089Swyllys }
1263089Swyllys }
1273089Swyllys /* URI MUST be specified */
1283089Swyllys if (url == NULL) {
1293089Swyllys cryptoerror(LOG_STDERR, gettext("A URL must be specified\n"));
1303089Swyllys rv = PK_ERR_USAGE;
1313089Swyllys goto end;
1323089Swyllys }
1333089Swyllys
1343089Swyllys /*
1353089Swyllys * Get the http proxy from the command "http_proxy" option or the
1363089Swyllys * environment variable. The command option has a higher priority.
1373089Swyllys */
1383089Swyllys if (http_proxy == NULL)
1393089Swyllys http_proxy = getenv("http_proxy");
1403089Swyllys
1413089Swyllys if (http_proxy != NULL) {
1423089Swyllys char *ptmp = http_proxy;
1433089Swyllys char *proxy_port_s;
1443089Swyllys
1453089Swyllys if (strncasecmp(ptmp, "http://", 7) == 0)
1463089Swyllys ptmp += 7; /* skip the scheme prefix */
1473089Swyllys
1483089Swyllys proxy = strtok(ptmp, ":");
1493089Swyllys proxy_port_s = strtok(NULL, "\0");
1503089Swyllys if (proxy_port_s != NULL)
1513089Swyllys proxy_port = strtol(proxy_port_s, NULL, 0);
1523089Swyllys else
1533089Swyllys proxy_port = 8080;
1543089Swyllys }
1553089Swyllys
1563089Swyllys /* If objtype is not specified, default to CRL */
1573089Swyllys if (oclass == 0) {
1583089Swyllys oclass = PK_CRL_OBJ;
1593089Swyllys }
1603089Swyllys
1615051Swyllys if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
1623089Swyllys cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
1633089Swyllys rv = PK_ERR_USAGE;
1643089Swyllys goto end;
1653089Swyllys }
1663089Swyllys
1673089Swyllys /* Now we are ready to download */
1683089Swyllys if (oclass & PK_CRL_OBJ) {
1695051Swyllys rv = kmf_download_crl(kmfhandle, url, proxy, proxy_port, 30,
1703089Swyllys fullpath, &format);
1713089Swyllys } else if (oclass & PK_CERT_OBJ) {
1725051Swyllys rv = kmf_download_cert(kmfhandle, url, proxy, proxy_port, 30,
1733089Swyllys fullpath, &format);
1743089Swyllys }
1753089Swyllys
1763089Swyllys if (rv != KMF_OK) {
1773089Swyllys switch (rv) {
1783089Swyllys case KMF_ERR_BAD_URI:
1793089Swyllys cryptoerror(LOG_STDERR,
1803089Swyllys gettext("Error in parsing URI\n"));
1813089Swyllys rv = PK_ERR_USAGE;
1823089Swyllys break;
1833089Swyllys case KMF_ERR_OPEN_FILE:
1843089Swyllys cryptoerror(LOG_STDERR,
1853089Swyllys gettext("Error in opening file\n"));
1863089Swyllys rv = PK_ERR_USAGE;
1873089Swyllys break;
1883089Swyllys case KMF_ERR_WRITE_FILE:
1893089Swyllys cryptoerror(LOG_STDERR,
1903089Swyllys gettext("Error in writing file\n"));
1913089Swyllys rv = PK_ERR_USAGE;
1923089Swyllys break;
1933089Swyllys case KMF_ERR_BAD_CRLFILE:
1943089Swyllys cryptoerror(LOG_STDERR, gettext("Not a CRL file\n"));
1953089Swyllys rv = PK_ERR_USAGE;
1963089Swyllys break;
1973089Swyllys case KMF_ERR_BAD_CERTFILE:
1983089Swyllys cryptoerror(LOG_STDERR,
1993089Swyllys gettext("Not a certificate file\n"));
2003089Swyllys rv = PK_ERR_USAGE;
2013089Swyllys break;
2023089Swyllys case KMF_ERR_MEMORY:
2033089Swyllys cryptoerror(LOG_STDERR,
2043089Swyllys gettext("Not enough memory\n"));
2053089Swyllys rv = PK_ERR_SYSTEM;
2063089Swyllys break;
2073089Swyllys default:
2083089Swyllys cryptoerror(LOG_STDERR,
2093089Swyllys gettext("Error in downloading the file.\n"));
2103089Swyllys rv = PK_ERR_SYSTEM;
2113089Swyllys break;
2123089Swyllys }
2133089Swyllys goto end;
2143089Swyllys }
2153089Swyllys
2163089Swyllys /*
2173089Swyllys * If the file is successfully downloaded, we also check the date.
2183089Swyllys * If the downloaded file is outdated, give a warning.
2193089Swyllys */
2203089Swyllys if (oclass & PK_CRL_OBJ) {
2215051Swyllys ch_rv = kmf_check_crl_date(kmfhandle, fullpath);
2223089Swyllys } else { /* certificate */
2235051Swyllys ch_rv = kmf_read_input_file(kmfhandle, fullpath, &cert);
2243089Swyllys if (ch_rv != KMF_OK)
2253089Swyllys goto end;
2263089Swyllys
2273089Swyllys if (format == KMF_FORMAT_PEM) {
2283089Swyllys int len;
2295051Swyllys ch_rv = kmf_pem_to_der(cert.Data, cert.Length,
2303089Swyllys &cert_der.Data, &len);
2313089Swyllys if (ch_rv != KMF_OK)
2323089Swyllys goto end;
2333089Swyllys cert_der.Length = (size_t)len;
2343089Swyllys }
2353089Swyllys
2365051Swyllys ch_rv = kmf_check_cert_date(kmfhandle,
2373089Swyllys format == KMF_FORMAT_ASN1 ? &cert : &cert_der);
2383089Swyllys }
2393089Swyllys
2403089Swyllys end:
2413089Swyllys if (ch_rv == KMF_ERR_VALIDITY_PERIOD) {
2423089Swyllys cryptoerror(LOG_STDERR,
2433089Swyllys gettext("Warning: the downloaded file is expired.\n"));
2443089Swyllys } else if (ch_rv != KMF_OK) {
2453089Swyllys cryptoerror(LOG_STDERR,
2463089Swyllys gettext("Warning: failed to check the validity.\n"));
2473089Swyllys }
2483089Swyllys
2493089Swyllys if (fullpath)
2503089Swyllys free(fullpath);
2513089Swyllys
2525051Swyllys kmf_free_data(&cert);
2535051Swyllys kmf_free_data(&cert_der);
2543089Swyllys
2555051Swyllys (void) kmf_finalize(kmfhandle);
2563089Swyllys return (rv);
2573089Swyllys }
258