15252Sdinak /*
25252Sdinak * CDDL HEADER START
35252Sdinak *
45252Sdinak * The contents of this file are subject to the terms of the
55252Sdinak * Common Development and Distribution License (the "License").
65252Sdinak * You may not use this file except in compliance with the License.
75252Sdinak *
85252Sdinak * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95252Sdinak * or http://www.opensolaris.org/os/licensing.
105252Sdinak * See the License for the specific language governing permissions
115252Sdinak * and limitations under the License.
125252Sdinak *
135252Sdinak * When distributing Covered Code, include this CDDL HEADER in each
145252Sdinak * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155252Sdinak * If applicable, add the following below this CDDL HEADER, with the
165252Sdinak * fields enclosed by brackets "[]" replaced with your own identifying
175252Sdinak * information: Portions Copyright [yyyy] [name of copyright owner]
185252Sdinak *
195252Sdinak * CDDL HEADER END
205252Sdinak */
215252Sdinak /*
22*8309SAnthony.Scarpino@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
235252Sdinak * Use is subject to license terms.
245252Sdinak */
255252Sdinak
265252Sdinak #include <stdio.h>
275252Sdinak #include <string.h>
285252Sdinak #include <fcntl.h>
295252Sdinak #include <sys/types.h>
305252Sdinak #include <sys/stat.h>
315252Sdinak #include <errno.h>
325252Sdinak #include <locale.h>
335252Sdinak #include <cryptoutil.h>
345252Sdinak
355252Sdinak /*
365252Sdinak * Read file into buffer. Used to read raw key data or initialization
375252Sdinak * vector data. Buffer must be freed by caller using free().
385252Sdinak *
395252Sdinak * If file is a regular file, entire file is read and dlen is set
405252Sdinak * to the number of bytes read. Otherwise, dlen should first be set
415252Sdinak * to the number of bytes requested and will be reset to actual number
425252Sdinak * of bytes returned.
435252Sdinak *
44*8309SAnthony.Scarpino@Sun.COM * Return 0 on success and errno on error.
455252Sdinak */
465252Sdinak int
pkcs11_read_data(char * filename,void ** dbuf,size_t * dlen)475252Sdinak pkcs11_read_data(char *filename, void **dbuf, size_t *dlen)
485252Sdinak {
49*8309SAnthony.Scarpino@Sun.COM int fd = -1;
505252Sdinak struct stat statbuf;
515252Sdinak boolean_t plain_file;
525252Sdinak void *filebuf = NULL;
535252Sdinak size_t filesize = 0;
54*8309SAnthony.Scarpino@Sun.COM int ret = 0;
555252Sdinak
565252Sdinak if (filename == NULL || dbuf == NULL || dlen == NULL)
575252Sdinak return (-1);
585252Sdinak
595252Sdinak if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == -1) {
60*8309SAnthony.Scarpino@Sun.COM ret = errno;
615252Sdinak cryptoerror(LOG_STDERR, gettext("cannot open %s"), filename);
62*8309SAnthony.Scarpino@Sun.COM goto error;
635252Sdinak }
645252Sdinak
655252Sdinak if (fstat(fd, &statbuf) == -1) {
66*8309SAnthony.Scarpino@Sun.COM ret = errno;
675252Sdinak cryptoerror(LOG_STDERR, gettext("cannot stat %s"), filename);
68*8309SAnthony.Scarpino@Sun.COM goto error;
695252Sdinak }
705252Sdinak
715252Sdinak if (S_ISREG(statbuf.st_mode)) {
725252Sdinak /* read the entire regular file */
735252Sdinak filesize = statbuf.st_size;
745252Sdinak plain_file = B_TRUE;
755252Sdinak } else {
765252Sdinak /* read requested bytes from special file */
775252Sdinak filesize = *dlen;
785252Sdinak plain_file = B_FALSE;
795252Sdinak }
805252Sdinak
815252Sdinak if (filesize == 0) {
825252Sdinak /*
835252Sdinak * for decrypt this is an error; for digest this is ok;
845252Sdinak * make it ok here but also set dbuf = NULL and dlen = 0
855252Sdinak * to indicate there was no data to read and caller can
865252Sdinak * retranslate that to an error if it wishes.
875252Sdinak */
885252Sdinak (void) close(fd);
895252Sdinak *dbuf = NULL;
905252Sdinak *dlen = 0;
915252Sdinak return (0);
925252Sdinak }
935252Sdinak
945252Sdinak if ((filebuf = malloc(filesize)) == NULL) {
95*8309SAnthony.Scarpino@Sun.COM ret = errno;
96*8309SAnthony.Scarpino@Sun.COM cryptoerror(LOG_STDERR, gettext("malloc: %s"), strerror(ret));
97*8309SAnthony.Scarpino@Sun.COM goto error;
985252Sdinak }
995252Sdinak
1005252Sdinak if (plain_file) {
1015252Sdinak /* either it got read or it didn't */
1025252Sdinak if (read(fd, filebuf, filesize) != filesize) {
103*8309SAnthony.Scarpino@Sun.COM ret = errno;
1045252Sdinak cryptoerror(LOG_STDERR,
1055252Sdinak gettext("error reading file %s: %s"), filename,
106*8309SAnthony.Scarpino@Sun.COM strerror(ret));
107*8309SAnthony.Scarpino@Sun.COM goto error;
1085252Sdinak }
1095252Sdinak } else {
1105252Sdinak /* reading from special file may need some coaxing */
1115252Sdinak char *marker = (char *)filebuf;
1125252Sdinak size_t left = filesize;
1135252Sdinak ssize_t nread;
1145252Sdinak
1155252Sdinak for (/* */; left > 0; marker += nread, left -= nread) {
1165252Sdinak /* keep reading it's going well */
1175252Sdinak nread = read(fd, marker, left);
118*8309SAnthony.Scarpino@Sun.COM if (nread > 0 || (nread == 0 && errno == EINTR)) {
119*8309SAnthony.Scarpino@Sun.COM errno = 0;
1205252Sdinak continue;
121*8309SAnthony.Scarpino@Sun.COM }
1225252Sdinak
1235252Sdinak /* might have to be good enough for caller */
1245252Sdinak if (nread == 0 && errno == EAGAIN)
1255252Sdinak break;
1265252Sdinak
1275252Sdinak /* anything else is an error */
128*8309SAnthony.Scarpino@Sun.COM if (errno) {
129*8309SAnthony.Scarpino@Sun.COM ret = errno;
130*8309SAnthony.Scarpino@Sun.COM cryptoerror(LOG_STDERR,
131*8309SAnthony.Scarpino@Sun.COM gettext("error reading file %s: %s"),
132*8309SAnthony.Scarpino@Sun.COM filename, strerror(ret));
133*8309SAnthony.Scarpino@Sun.COM goto error;
134*8309SAnthony.Scarpino@Sun.COM }
1355252Sdinak }
1365252Sdinak /* reset to actual number of bytes read */
1375252Sdinak filesize -= left;
1385252Sdinak }
1395252Sdinak
1405252Sdinak (void) close(fd);
1415252Sdinak *dbuf = filebuf;
1425252Sdinak *dlen = filesize;
1435252Sdinak return (0);
144*8309SAnthony.Scarpino@Sun.COM
145*8309SAnthony.Scarpino@Sun.COM error:
146*8309SAnthony.Scarpino@Sun.COM if (fd != -1)
147*8309SAnthony.Scarpino@Sun.COM (void) close(fd);
148*8309SAnthony.Scarpino@Sun.COM
149*8309SAnthony.Scarpino@Sun.COM return (ret);
1505252Sdinak }
151