11c9bd843Sdinak /*
21c9bd843Sdinak  * CDDL HEADER START
31c9bd843Sdinak  *
41c9bd843Sdinak  * The contents of this file are subject to the terms of the
51c9bd843Sdinak  * Common Development and Distribution License (the "License").
61c9bd843Sdinak  * You may not use this file except in compliance with the License.
71c9bd843Sdinak  *
81c9bd843Sdinak  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91c9bd843Sdinak  * or http://www.opensolaris.org/os/licensing.
101c9bd843Sdinak  * See the License for the specific language governing permissions
111c9bd843Sdinak  * and limitations under the License.
121c9bd843Sdinak  *
131c9bd843Sdinak  * When distributing Covered Code, include this CDDL HEADER in each
141c9bd843Sdinak  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151c9bd843Sdinak  * If applicable, add the following below this CDDL HEADER, with the
161c9bd843Sdinak  * fields enclosed by brackets "[]" replaced with your own identifying
171c9bd843Sdinak  * information: Portions Copyright [yyyy] [name of copyright owner]
181c9bd843Sdinak  *
191c9bd843Sdinak  * CDDL HEADER END
201c9bd843Sdinak  */
211c9bd843Sdinak /*
22*a7e661a2SAnthony Scarpino  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
231c9bd843Sdinak  * Use is subject to license terms.
241c9bd843Sdinak  */
251c9bd843Sdinak 
261c9bd843Sdinak #include <stdio.h>
271c9bd843Sdinak #include <string.h>
281c9bd843Sdinak #include <fcntl.h>
291c9bd843Sdinak #include <sys/types.h>
301c9bd843Sdinak #include <sys/stat.h>
311c9bd843Sdinak #include <errno.h>
321c9bd843Sdinak #include <locale.h>
331c9bd843Sdinak #include <cryptoutil.h>
341c9bd843Sdinak 
351c9bd843Sdinak /*
361c9bd843Sdinak  * Read file into buffer.  Used to read raw key data or initialization
371c9bd843Sdinak  * vector data.  Buffer must be freed by caller using free().
381c9bd843Sdinak  *
391c9bd843Sdinak  * If file is a regular file, entire file is read and dlen is set
401c9bd843Sdinak  * to the number of bytes read.  Otherwise, dlen should first be set
411c9bd843Sdinak  * to the number of bytes requested and will be reset to actual number
421c9bd843Sdinak  * of bytes returned.
431c9bd843Sdinak  *
44*a7e661a2SAnthony Scarpino  * Return 0 on success and errno on error.
451c9bd843Sdinak  */
461c9bd843Sdinak int
pkcs11_read_data(char * filename,void ** dbuf,size_t * dlen)471c9bd843Sdinak pkcs11_read_data(char *filename, void **dbuf, size_t *dlen)
481c9bd843Sdinak {
49*a7e661a2SAnthony Scarpino 	int	fd = -1;
501c9bd843Sdinak 	struct stat statbuf;
511c9bd843Sdinak 	boolean_t plain_file;
521c9bd843Sdinak 	void	*filebuf = NULL;
531c9bd843Sdinak 	size_t	filesize = 0;
54*a7e661a2SAnthony Scarpino 	int ret = 0;
551c9bd843Sdinak 
561c9bd843Sdinak 	if (filename == NULL || dbuf == NULL || dlen == NULL)
571c9bd843Sdinak 		return (-1);
581c9bd843Sdinak 
591c9bd843Sdinak 	if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == -1) {
60*a7e661a2SAnthony Scarpino 		ret = errno;
611c9bd843Sdinak 		cryptoerror(LOG_STDERR, gettext("cannot open %s"), filename);
62*a7e661a2SAnthony Scarpino 		goto error;
631c9bd843Sdinak 	}
641c9bd843Sdinak 
651c9bd843Sdinak 	if (fstat(fd, &statbuf) == -1) {
66*a7e661a2SAnthony Scarpino 		ret = errno;
671c9bd843Sdinak 		cryptoerror(LOG_STDERR, gettext("cannot stat %s"), filename);
68*a7e661a2SAnthony Scarpino 		goto error;
691c9bd843Sdinak 	}
701c9bd843Sdinak 
711c9bd843Sdinak 	if (S_ISREG(statbuf.st_mode)) {
721c9bd843Sdinak 		/* read the entire regular file */
731c9bd843Sdinak 		filesize = statbuf.st_size;
741c9bd843Sdinak 		plain_file = B_TRUE;
751c9bd843Sdinak 	} else {
761c9bd843Sdinak 		/* read requested bytes from special file */
771c9bd843Sdinak 		filesize = *dlen;
781c9bd843Sdinak 		plain_file = B_FALSE;
791c9bd843Sdinak 	}
801c9bd843Sdinak 
811c9bd843Sdinak 	if (filesize == 0) {
821c9bd843Sdinak 		/*
831c9bd843Sdinak 		 * for decrypt this is an error; for digest this is ok;
841c9bd843Sdinak 		 * make it ok here but also set dbuf = NULL and dlen = 0
851c9bd843Sdinak 		 * to indicate there was no data to read and caller can
861c9bd843Sdinak 		 * retranslate that to an error if it wishes.
871c9bd843Sdinak 		 */
881c9bd843Sdinak 		(void) close(fd);
891c9bd843Sdinak 		*dbuf = NULL;
901c9bd843Sdinak 		*dlen = 0;
911c9bd843Sdinak 		return (0);
921c9bd843Sdinak 	}
931c9bd843Sdinak 
941c9bd843Sdinak 	if ((filebuf = malloc(filesize)) == NULL) {
95*a7e661a2SAnthony Scarpino 		ret = errno;
96*a7e661a2SAnthony Scarpino 		cryptoerror(LOG_STDERR, gettext("malloc: %s"), strerror(ret));
97*a7e661a2SAnthony Scarpino 		goto error;
981c9bd843Sdinak 	}
991c9bd843Sdinak 
1001c9bd843Sdinak 	if (plain_file) {
1011c9bd843Sdinak 		/* either it got read or it didn't */
1021c9bd843Sdinak 		if (read(fd, filebuf, filesize) != filesize) {
103*a7e661a2SAnthony Scarpino 			ret = errno;
1041c9bd843Sdinak 			cryptoerror(LOG_STDERR,
1051c9bd843Sdinak 			    gettext("error reading file %s: %s"), filename,
106*a7e661a2SAnthony Scarpino 			    strerror(ret));
107*a7e661a2SAnthony Scarpino 			goto error;
1081c9bd843Sdinak 		}
1091c9bd843Sdinak 	} else {
1101c9bd843Sdinak 		/* reading from special file may need some coaxing */
1111c9bd843Sdinak 		char	*marker = (char *)filebuf;
1121c9bd843Sdinak 		size_t	left = filesize;
1131c9bd843Sdinak 		ssize_t	nread;
1141c9bd843Sdinak 
1151c9bd843Sdinak 		for (/* */; left > 0; marker += nread, left -= nread) {
1161c9bd843Sdinak 			/* keep reading it's going well */
1171c9bd843Sdinak 			nread = read(fd, marker, left);
118*a7e661a2SAnthony Scarpino 			if (nread > 0 || (nread == 0 && errno == EINTR)) {
119*a7e661a2SAnthony Scarpino 				errno = 0;
1201c9bd843Sdinak 				continue;
121*a7e661a2SAnthony Scarpino 			}
1221c9bd843Sdinak 
1231c9bd843Sdinak 			/* might have to be good enough for caller */
1241c9bd843Sdinak 			if (nread == 0 && errno == EAGAIN)
1251c9bd843Sdinak 				break;
1261c9bd843Sdinak 
1271c9bd843Sdinak 			/* anything else is an error */
128*a7e661a2SAnthony Scarpino 			if (errno) {
129*a7e661a2SAnthony Scarpino 				ret = errno;
130*a7e661a2SAnthony Scarpino 				cryptoerror(LOG_STDERR,
131*a7e661a2SAnthony Scarpino 				    gettext("error reading file %s: %s"),
132*a7e661a2SAnthony Scarpino 				    filename, strerror(ret));
133*a7e661a2SAnthony Scarpino 				goto error;
134*a7e661a2SAnthony Scarpino 			}
1351c9bd843Sdinak 		}
1361c9bd843Sdinak 		/* reset to actual number of bytes read */
1371c9bd843Sdinak 		filesize -= left;
1381c9bd843Sdinak 	}
1391c9bd843Sdinak 
1401c9bd843Sdinak 	(void) close(fd);
1411c9bd843Sdinak 	*dbuf = filebuf;
1421c9bd843Sdinak 	*dlen = filesize;
1431c9bd843Sdinak 	return (0);
144*a7e661a2SAnthony Scarpino 
145*a7e661a2SAnthony Scarpino error:
146*a7e661a2SAnthony Scarpino 	if (fd != -1)
147*a7e661a2SAnthony Scarpino 		(void) close(fd);
148*a7e661a2SAnthony Scarpino 
149*a7e661a2SAnthony Scarpino 	return (ret);
1501c9bd843Sdinak }
151