1c9bd843ebc00801cc418156a3893362a1dc872edinak/*
1c9bd843ebc00801cc418156a3893362a1dc872edinak * CDDL HEADER START
1c9bd843ebc00801cc418156a3893362a1dc872edinak *
1c9bd843ebc00801cc418156a3893362a1dc872edinak * The contents of this file are subject to the terms of the
1c9bd843ebc00801cc418156a3893362a1dc872edinak * Common Development and Distribution License (the "License").
1c9bd843ebc00801cc418156a3893362a1dc872edinak * You may not use this file except in compliance with the License.
1c9bd843ebc00801cc418156a3893362a1dc872edinak *
1c9bd843ebc00801cc418156a3893362a1dc872edinak * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1c9bd843ebc00801cc418156a3893362a1dc872edinak * or http://www.opensolaris.org/os/licensing.
1c9bd843ebc00801cc418156a3893362a1dc872edinak * See the License for the specific language governing permissions
1c9bd843ebc00801cc418156a3893362a1dc872edinak * and limitations under the License.
1c9bd843ebc00801cc418156a3893362a1dc872edinak *
1c9bd843ebc00801cc418156a3893362a1dc872edinak * When distributing Covered Code, include this CDDL HEADER in each
1c9bd843ebc00801cc418156a3893362a1dc872edinak * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1c9bd843ebc00801cc418156a3893362a1dc872edinak * If applicable, add the following below this CDDL HEADER, with the
1c9bd843ebc00801cc418156a3893362a1dc872edinak * fields enclosed by brackets "[]" replaced with your own identifying
1c9bd843ebc00801cc418156a3893362a1dc872edinak * information: Portions Copyright [yyyy] [name of copyright owner]
1c9bd843ebc00801cc418156a3893362a1dc872edinak *
1c9bd843ebc00801cc418156a3893362a1dc872edinak * CDDL HEADER END
1c9bd843ebc00801cc418156a3893362a1dc872edinak */
1c9bd843ebc00801cc418156a3893362a1dc872edinak/*
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
1c9bd843ebc00801cc418156a3893362a1dc872edinak * Use is subject to license terms.
1c9bd843ebc00801cc418156a3893362a1dc872edinak */
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak#include <stdio.h>
1c9bd843ebc00801cc418156a3893362a1dc872edinak#include <string.h>
1c9bd843ebc00801cc418156a3893362a1dc872edinak#include <fcntl.h>
1c9bd843ebc00801cc418156a3893362a1dc872edinak#include <sys/types.h>
1c9bd843ebc00801cc418156a3893362a1dc872edinak#include <sys/stat.h>
1c9bd843ebc00801cc418156a3893362a1dc872edinak#include <errno.h>
1c9bd843ebc00801cc418156a3893362a1dc872edinak#include <locale.h>
1c9bd843ebc00801cc418156a3893362a1dc872edinak#include <cryptoutil.h>
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak/*
1c9bd843ebc00801cc418156a3893362a1dc872edinak * Read file into buffer. Used to read raw key data or initialization
1c9bd843ebc00801cc418156a3893362a1dc872edinak * vector data. Buffer must be freed by caller using free().
1c9bd843ebc00801cc418156a3893362a1dc872edinak *
1c9bd843ebc00801cc418156a3893362a1dc872edinak * If file is a regular file, entire file is read and dlen is set
1c9bd843ebc00801cc418156a3893362a1dc872edinak * to the number of bytes read. Otherwise, dlen should first be set
1c9bd843ebc00801cc418156a3893362a1dc872edinak * to the number of bytes requested and will be reset to actual number
1c9bd843ebc00801cc418156a3893362a1dc872edinak * of bytes returned.
1c9bd843ebc00801cc418156a3893362a1dc872edinak *
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino * Return 0 on success and errno on error.
1c9bd843ebc00801cc418156a3893362a1dc872edinak */
1c9bd843ebc00801cc418156a3893362a1dc872edinakint
1c9bd843ebc00801cc418156a3893362a1dc872edinakpkcs11_read_data(char *filename, void **dbuf, size_t *dlen)
1c9bd843ebc00801cc418156a3893362a1dc872edinak{
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino int fd = -1;
1c9bd843ebc00801cc418156a3893362a1dc872edinak struct stat statbuf;
1c9bd843ebc00801cc418156a3893362a1dc872edinak boolean_t plain_file;
1c9bd843ebc00801cc418156a3893362a1dc872edinak void *filebuf = NULL;
1c9bd843ebc00801cc418156a3893362a1dc872edinak size_t filesize = 0;
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino int ret = 0;
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak if (filename == NULL || dbuf == NULL || dlen == NULL)
1c9bd843ebc00801cc418156a3893362a1dc872edinak return (-1);
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == -1) {
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino ret = errno;
1c9bd843ebc00801cc418156a3893362a1dc872edinak cryptoerror(LOG_STDERR, gettext("cannot open %s"), filename);
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino goto error;
1c9bd843ebc00801cc418156a3893362a1dc872edinak }
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak if (fstat(fd, &statbuf) == -1) {
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino ret = errno;
1c9bd843ebc00801cc418156a3893362a1dc872edinak cryptoerror(LOG_STDERR, gettext("cannot stat %s"), filename);
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino goto error;
1c9bd843ebc00801cc418156a3893362a1dc872edinak }
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak if (S_ISREG(statbuf.st_mode)) {
1c9bd843ebc00801cc418156a3893362a1dc872edinak /* read the entire regular file */
1c9bd843ebc00801cc418156a3893362a1dc872edinak filesize = statbuf.st_size;
1c9bd843ebc00801cc418156a3893362a1dc872edinak plain_file = B_TRUE;
1c9bd843ebc00801cc418156a3893362a1dc872edinak } else {
1c9bd843ebc00801cc418156a3893362a1dc872edinak /* read requested bytes from special file */
1c9bd843ebc00801cc418156a3893362a1dc872edinak filesize = *dlen;
1c9bd843ebc00801cc418156a3893362a1dc872edinak plain_file = B_FALSE;
1c9bd843ebc00801cc418156a3893362a1dc872edinak }
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak if (filesize == 0) {
1c9bd843ebc00801cc418156a3893362a1dc872edinak /*
1c9bd843ebc00801cc418156a3893362a1dc872edinak * for decrypt this is an error; for digest this is ok;
1c9bd843ebc00801cc418156a3893362a1dc872edinak * make it ok here but also set dbuf = NULL and dlen = 0
1c9bd843ebc00801cc418156a3893362a1dc872edinak * to indicate there was no data to read and caller can
1c9bd843ebc00801cc418156a3893362a1dc872edinak * retranslate that to an error if it wishes.
1c9bd843ebc00801cc418156a3893362a1dc872edinak */
1c9bd843ebc00801cc418156a3893362a1dc872edinak (void) close(fd);
1c9bd843ebc00801cc418156a3893362a1dc872edinak *dbuf = NULL;
1c9bd843ebc00801cc418156a3893362a1dc872edinak *dlen = 0;
1c9bd843ebc00801cc418156a3893362a1dc872edinak return (0);
1c9bd843ebc00801cc418156a3893362a1dc872edinak }
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak if ((filebuf = malloc(filesize)) == NULL) {
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino ret = errno;
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino cryptoerror(LOG_STDERR, gettext("malloc: %s"), strerror(ret));
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino goto error;
1c9bd843ebc00801cc418156a3893362a1dc872edinak }
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak if (plain_file) {
1c9bd843ebc00801cc418156a3893362a1dc872edinak /* either it got read or it didn't */
1c9bd843ebc00801cc418156a3893362a1dc872edinak if (read(fd, filebuf, filesize) != filesize) {
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino ret = errno;
1c9bd843ebc00801cc418156a3893362a1dc872edinak cryptoerror(LOG_STDERR,
1c9bd843ebc00801cc418156a3893362a1dc872edinak gettext("error reading file %s: %s"), filename,
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino strerror(ret));
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino goto error;
1c9bd843ebc00801cc418156a3893362a1dc872edinak }
1c9bd843ebc00801cc418156a3893362a1dc872edinak } else {
1c9bd843ebc00801cc418156a3893362a1dc872edinak /* reading from special file may need some coaxing */
1c9bd843ebc00801cc418156a3893362a1dc872edinak char *marker = (char *)filebuf;
1c9bd843ebc00801cc418156a3893362a1dc872edinak size_t left = filesize;
1c9bd843ebc00801cc418156a3893362a1dc872edinak ssize_t nread;
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak for (/* */; left > 0; marker += nread, left -= nread) {
1c9bd843ebc00801cc418156a3893362a1dc872edinak /* keep reading it's going well */
1c9bd843ebc00801cc418156a3893362a1dc872edinak nread = read(fd, marker, left);
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino if (nread > 0 || (nread == 0 && errno == EINTR)) {
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino errno = 0;
1c9bd843ebc00801cc418156a3893362a1dc872edinak continue;
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino }
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak /* might have to be good enough for caller */
1c9bd843ebc00801cc418156a3893362a1dc872edinak if (nread == 0 && errno == EAGAIN)
1c9bd843ebc00801cc418156a3893362a1dc872edinak break;
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak /* anything else is an error */
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino if (errno) {
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino ret = errno;
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino cryptoerror(LOG_STDERR,
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino gettext("error reading file %s: %s"),
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino filename, strerror(ret));
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino goto error;
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino }
1c9bd843ebc00801cc418156a3893362a1dc872edinak }
1c9bd843ebc00801cc418156a3893362a1dc872edinak /* reset to actual number of bytes read */
1c9bd843ebc00801cc418156a3893362a1dc872edinak filesize -= left;
1c9bd843ebc00801cc418156a3893362a1dc872edinak }
1c9bd843ebc00801cc418156a3893362a1dc872edinak
1c9bd843ebc00801cc418156a3893362a1dc872edinak (void) close(fd);
1c9bd843ebc00801cc418156a3893362a1dc872edinak *dbuf = filebuf;
1c9bd843ebc00801cc418156a3893362a1dc872edinak *dlen = filesize;
1c9bd843ebc00801cc418156a3893362a1dc872edinak return (0);
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpinoerror:
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino if (fd != -1)
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino (void) close(fd);
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino
a7e661a2db6ff10cd43a089e7f4dcbd0cfd609f1Anthony Scarpino return (ret);
1c9bd843ebc00801cc418156a3893362a1dc872edinak}