OpenSolaris_b135/cmd/cmd-crypto/pktool/download.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <malloc.h>
#include <libgen.h>
#include <fcntl.h>
#include <errno.h>
#include <cryptoutil.h>
#include "common.h"
#include <kmfapi.h>

int
pk_download(int argc, char *argv[])
{
	int rv;
	int opt;
	extern int	optind_av;
	extern char	*optarg_av;
	int oclass = 0;
	char *url = NULL;
	char *http_proxy = NULL;
	char *dir = NULL;
	char *outfile = NULL;
	char *proxy = NULL;
	int  proxy_port = 0;
	KMF_HANDLE_T	kmfhandle = NULL;
	KMF_ENCODE_FORMAT format;
	KMF_RETURN ch_rv = KMF_OK;
	char *fullpath = NULL;
	KMF_DATA cert = {NULL, 0};
	KMF_DATA cert_der = {NULL, 0};

	while ((opt = getopt_av(argc, argv,
	    "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) {

		if (EMPTYSTRING(optarg_av))
			return (PK_ERR_USAGE);
		switch (opt) {
		case 't':
			if (oclass)
				return (PK_ERR_USAGE);
			oclass = OT2Int(optarg_av);
			if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ)))
				return (PK_ERR_USAGE);
			break;
		case 'u':
			if (url)
				return (PK_ERR_USAGE);
			url = optarg_av;
			break;
		case 'h':
			if (http_proxy)
				return (PK_ERR_USAGE);
			http_proxy = optarg_av;
			break;
		case 'o':
			if (outfile)
				return (PK_ERR_USAGE);
			outfile = optarg_av;
			break;
		case 'd':
			if (dir)
				return (PK_ERR_USAGE);
			dir = optarg_av;
			break;
		default:
			cryptoerror(LOG_STDERR, gettext(
			    "unrecognized download option '%s'\n"),
			    argv[optind_av]);
			return (PK_ERR_USAGE);
		}
	}

	/* No additional args allowed. */
	argc -= optind_av;
	argv += optind_av;
	if (argc) {
		return (PK_ERR_USAGE);
	}

	/* Check the dir and outfile options */
	if (outfile == NULL) {
		/* If outfile is not specified, use the basename of URI */
		outfile = basename(url);
	}

	fullpath = get_fullpath(dir, outfile);
	if (fullpath == NULL) {
		cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile "
		    "option value \n"));
		return (PK_ERR_USAGE);
	}
	/* Check if the file exists and might be overwritten. */
	if (access(fullpath, F_OK) == 0) {
		cryptoerror(LOG_STDERR,
		    gettext("Warning: file \"%s\" exists, "
		    "will be overwritten."), fullpath);
		if (yesno(gettext("Continue with download? "),
		    gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
			return (0);
		}
	} else {
		rv = verify_file(fullpath);
		if (rv != KMF_OK) {
			cryptoerror(LOG_STDERR, gettext("The file (%s) "
			    "cannot be created.\n"), fullpath);
			return (PK_ERR_USAGE);
		}
	}


	/* URI MUST be specified */
	if (url == NULL) {
		cryptoerror(LOG_STDERR, gettext("A URL must be specified\n"));
		rv = PK_ERR_USAGE;
		goto end;
	}

	/*
	 * Get the http proxy from the command "http_proxy" option or the
	 * environment variable.  The command option has a higher priority.
	 */
	if (http_proxy == NULL)
		http_proxy = getenv("http_proxy");

	if (http_proxy != NULL) {
		char *ptmp = http_proxy;
		char *proxy_port_s;

		if (strncasecmp(ptmp, "http://", 7) == 0)
			ptmp += 7;	/* skip the scheme prefix */

		proxy = strtok(ptmp, ":");
		proxy_port_s = strtok(NULL, "\0");
		if (proxy_port_s != NULL)
			proxy_port = strtol(proxy_port_s, NULL, 0);
		else
			proxy_port = 8080;
	}

	/* If objtype is not specified, default to CRL */
	if (oclass == 0) {
		oclass = PK_CRL_OBJ;
	}

	if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
		cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
		rv = PK_ERR_USAGE;
		goto end;
	}

	/* Now we are ready to download */
	if (oclass & PK_CRL_OBJ) {
		rv = kmf_download_crl(kmfhandle, url, proxy, proxy_port, 30,
		    fullpath, &format);
	} else if (oclass & PK_CERT_OBJ) {
		rv = kmf_download_cert(kmfhandle, url, proxy, proxy_port, 30,
		    fullpath, &format);
	}

	if (rv != KMF_OK) {
		switch (rv) {
		case KMF_ERR_BAD_URI:
			cryptoerror(LOG_STDERR,
			    gettext("Error in parsing URI\n"));
			rv = PK_ERR_USAGE;
			break;
		case KMF_ERR_OPEN_FILE:
			cryptoerror(LOG_STDERR,
			    gettext("Error in opening file\n"));
			rv = PK_ERR_USAGE;
			break;
		case KMF_ERR_WRITE_FILE:
			cryptoerror(LOG_STDERR,
			    gettext("Error in writing file\n"));
			rv = PK_ERR_USAGE;
			break;
		case KMF_ERR_BAD_CRLFILE:
			cryptoerror(LOG_STDERR, gettext("Not a CRL file\n"));
			rv = PK_ERR_USAGE;
			break;
		case KMF_ERR_BAD_CERTFILE:
			cryptoerror(LOG_STDERR,
			    gettext("Not a certificate file\n"));
			rv = PK_ERR_USAGE;
			break;
		case KMF_ERR_MEMORY:
			cryptoerror(LOG_STDERR,
			    gettext("Not enough memory\n"));
			rv = PK_ERR_SYSTEM;
			break;
		default:
			cryptoerror(LOG_STDERR,
			    gettext("Error in downloading the file.\n"));
			rv = PK_ERR_SYSTEM;
			break;
		}
		goto end;
	}

	/*
	 * If the file is successfully downloaded, we also check the date.
	 * If the downloaded file is outdated, give a warning.
	 */
	if (oclass & PK_CRL_OBJ) {
		ch_rv = kmf_check_crl_date(kmfhandle, fullpath);
	} else { /* certificate */
		ch_rv = kmf_read_input_file(kmfhandle, fullpath, &cert);
		if (ch_rv != KMF_OK)
			goto end;

		if (format == KMF_FORMAT_PEM) {
			int len;
			ch_rv = kmf_pem_to_der(cert.Data, cert.Length,
			    &cert_der.Data, &len);
			if (ch_rv != KMF_OK)
				goto end;
			cert_der.Length = (size_t)len;
		}

		ch_rv = kmf_check_cert_date(kmfhandle,
		    format == KMF_FORMAT_ASN1 ? &cert : &cert_der);
	}

end:
	if (ch_rv == KMF_ERR_VALIDITY_PERIOD) {
		cryptoerror(LOG_STDERR,
		    gettext("Warning: the downloaded file is expired.\n"));
	} else if (ch_rv != KMF_OK) {
		cryptoerror(LOG_STDERR,
		    gettext("Warning: failed to check the validity.\n"));
	}

	if (fullpath)
		free(fullpath);

	kmf_free_data(&cert);
	kmf_free_data(&cert_der);

	(void) kmf_finalize(kmfhandle);
	return (rv);
}