/src/opensc/src/libopensc/pkcs15-cache.c
Line | Count | Source |
1 | | /* |
2 | | * pkcs15-cache.c: PKCS #15 file caching functions |
3 | | * |
4 | | * Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi> |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #ifdef HAVE_CONFIG_H |
22 | | #include "config.h" |
23 | | #endif |
24 | | |
25 | | #include <stdio.h> |
26 | | #include <stdlib.h> |
27 | | #include <string.h> |
28 | | #ifdef HAVE_UNISTD_H |
29 | | #include <unistd.h> |
30 | | #endif |
31 | | #include <sys/stat.h> |
32 | | #include <limits.h> |
33 | | #include <errno.h> |
34 | | #include <assert.h> |
35 | | |
36 | | #include "internal.h" |
37 | | #include "pkcs15.h" |
38 | | #include "common/compat_strlcpy.h" |
39 | | |
40 | 0 | #define RANDOM_UID_INDICATOR 0x08 |
41 | | static int generate_cache_filename(struct sc_pkcs15_card *p15card, |
42 | | const sc_path_t *path, |
43 | | char *buf, size_t bufsize) |
44 | 3.48k | { |
45 | 3.48k | char dir[PATH_MAX]; |
46 | 3.48k | char *last_update = NULL; |
47 | 3.48k | int r; |
48 | 3.48k | unsigned u; |
49 | 3.48k | size_t change_counter; |
50 | | |
51 | 3.48k | if (p15card->tokeninfo->serial_number == NULL |
52 | 1.51k | && (p15card->card->uid.len == 0 |
53 | 0 | || p15card->card->uid.value[0] == RANDOM_UID_INDICATOR)) |
54 | 1.51k | return SC_ERROR_INVALID_ARGUMENTS; |
55 | | |
56 | 3.48k | assert(path->len <= SC_MAX_PATH_SIZE); |
57 | 1.97k | r = sc_get_cache_dir(p15card->card->ctx, dir, sizeof(dir)); |
58 | 1.97k | if (r) |
59 | 0 | return r; |
60 | 1.97k | snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "/"); |
61 | | |
62 | 1.97k | last_update = sc_pkcs15_get_lastupdate(p15card); |
63 | 1.97k | if (!last_update) |
64 | 1.95k | last_update = "NODATE"; |
65 | | |
66 | 1.97k | if (p15card->tokeninfo->serial_number) { |
67 | 1.97k | snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), |
68 | 1.97k | "%s_%s", p15card->tokeninfo->serial_number, |
69 | 1.97k | last_update); |
70 | 1.97k | } else { |
71 | 0 | snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), |
72 | 0 | "uid-%s_%s", sc_dump_hex( |
73 | 0 | p15card->card->uid.value, |
74 | 0 | p15card->card->uid.len), last_update); |
75 | 0 | } |
76 | | |
77 | 1.97k | if (SC_SUCCESS == sc_card_ctl(p15card->card, SC_CARDCTL_GET_CHANGE_COUNTER, &change_counter)) |
78 | 11 | snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "_%" SC_FORMAT_LEN_SIZE_T "u", change_counter); |
79 | | |
80 | 1.97k | if (path->aid.len && |
81 | 1.39k | (path->type == SC_PATH_TYPE_FILE_ID || path->type == SC_PATH_TYPE_PATH)) { |
82 | 1.25k | snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "_"); |
83 | 10.0k | for (u = 0; u < path->aid.len; u++) |
84 | 8.78k | snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), |
85 | 8.78k | "%02X", path->aid.value[u]); |
86 | 1.25k | } |
87 | 713 | else if (path->type != SC_PATH_TYPE_PATH) { |
88 | 156 | return SC_ERROR_INVALID_ARGUMENTS; |
89 | 156 | } |
90 | | |
91 | 1.81k | if (path->len) { |
92 | 1.81k | size_t offs = 0; |
93 | | |
94 | 1.81k | if (path->len > 2 && memcmp(path->value, "\x3F\x00", 2) == 0) |
95 | 557 | offs = 2; |
96 | 1.81k | snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "_"); |
97 | 7.02k | for (u = 0; u < path->len - offs; u++) |
98 | 5.21k | snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), |
99 | 5.21k | "%02X", path->value[u + offs]); |
100 | 1.81k | } |
101 | | |
102 | 1.81k | if (!buf) |
103 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
104 | 1.81k | strlcpy(buf, dir, bufsize); |
105 | | |
106 | 1.81k | return SC_SUCCESS; |
107 | 1.81k | } |
108 | | |
109 | | int sc_pkcs15_read_cached_file(struct sc_pkcs15_card *p15card, |
110 | | const sc_path_t *path, |
111 | | u8 **buf, size_t *bufsize) |
112 | 5.68k | { |
113 | 5.68k | char fname[PATH_MAX]; |
114 | 5.68k | int rv; |
115 | 5.68k | FILE *f; |
116 | 5.68k | size_t count; |
117 | 5.68k | struct stat stbuf; |
118 | 5.68k | u8 *data = NULL; |
119 | | |
120 | 5.68k | if (path->len < 2) |
121 | 1.58k | return SC_ERROR_INVALID_ARGUMENTS; |
122 | | |
123 | | /* Accept full path or FILE-ID path with AID */ |
124 | 4.10k | if ((path->type != SC_PATH_TYPE_PATH) && (path->type != SC_PATH_TYPE_FILE_ID || path->aid.len == 0)) |
125 | 1.37k | return SC_ERROR_INVALID_ARGUMENTS; |
126 | | |
127 | 2.72k | sc_log(p15card->card->ctx, "try to read cache for %s", sc_print_path(path)); |
128 | 2.72k | rv = generate_cache_filename(p15card, path, fname, sizeof(fname)); |
129 | 2.72k | if (rv != SC_SUCCESS) |
130 | 1.06k | return rv; |
131 | 1.66k | sc_log(p15card->card->ctx, "read cached file %s", fname); |
132 | | |
133 | 1.66k | f = fopen(fname, "rb"); |
134 | 1.66k | if (!f) |
135 | 1.54k | return SC_ERROR_FILE_NOT_FOUND; |
136 | 117 | if (fstat(fileno(f), &stbuf)) { |
137 | 0 | fclose(f); |
138 | 0 | return SC_ERROR_FILE_NOT_FOUND; |
139 | 0 | } |
140 | | |
141 | 117 | if (path->count < 0) { |
142 | 75 | count = stbuf.st_size; |
143 | 75 | } |
144 | 42 | else { |
145 | 42 | count = path->count; |
146 | 42 | if (path->index + count > (size_t)stbuf.st_size) { |
147 | 40 | rv = SC_ERROR_FILE_NOT_FOUND; /* cache file bad? */ |
148 | 40 | goto err; |
149 | 40 | } |
150 | | |
151 | 2 | if (0 != fseek(f, (long)path->index, SEEK_SET)) { |
152 | 0 | rv = SC_ERROR_FILE_NOT_FOUND; |
153 | 0 | goto err; |
154 | 0 | } |
155 | 2 | } |
156 | | |
157 | 77 | if (*buf == NULL) { |
158 | 69 | data = malloc((size_t)stbuf.st_size); |
159 | 69 | if (data == NULL) { |
160 | 0 | rv = SC_ERROR_OUT_OF_MEMORY; |
161 | 0 | goto err; |
162 | 0 | } |
163 | 69 | } |
164 | 8 | else { |
165 | 8 | if (count > *bufsize) { |
166 | 5 | rv = SC_ERROR_BUFFER_TOO_SMALL; |
167 | 5 | goto err; |
168 | 5 | } |
169 | 3 | data = *buf; |
170 | 3 | } |
171 | | |
172 | 72 | if (count != fread(data, 1, count, f)) { |
173 | 0 | rv = SC_ERROR_BUFFER_TOO_SMALL; |
174 | 0 | goto err; |
175 | 0 | } |
176 | 72 | *buf = data; |
177 | 72 | *bufsize = count; |
178 | | |
179 | 72 | rv = SC_SUCCESS; |
180 | | |
181 | 117 | err: |
182 | 117 | if (rv != SC_SUCCESS) { |
183 | 45 | if (data != *buf) { |
184 | 5 | free(data); |
185 | 5 | } |
186 | 45 | } |
187 | | |
188 | 117 | fclose(f); |
189 | 117 | return rv; |
190 | 72 | } |
191 | | |
192 | | int sc_pkcs15_cache_file(struct sc_pkcs15_card *p15card, |
193 | | const sc_path_t *path, |
194 | | const u8 *buf, size_t bufsize) |
195 | 760 | { |
196 | 760 | char fname[PATH_MAX]; |
197 | 760 | int r; |
198 | 760 | long len; |
199 | 760 | FILE *f; |
200 | 760 | size_t c; |
201 | | |
202 | 760 | r = generate_cache_filename(p15card, path, fname, sizeof(fname)); |
203 | 760 | if (r != 0) |
204 | 605 | return r; |
205 | | |
206 | 155 | f = fopen(fname, "ab"); |
207 | | /* If the open failed because the cache directory does |
208 | | * not exist, create it and a re-try the fopen() call. |
209 | | */ |
210 | 155 | if (f == NULL && errno == ENOENT) { |
211 | 70 | if ((r = sc_make_cache_dir(p15card->card->ctx)) < 0) |
212 | 70 | return r; |
213 | 0 | f = fopen(fname, "ab"); |
214 | 0 | } |
215 | 85 | if (f == NULL) |
216 | 0 | return 0; |
217 | | |
218 | | /* we opened the file for appending so we should be at the end of file. |
219 | | * The ftell() will give use the length of the file */ |
220 | 85 | len = ftell(f); |
221 | 85 | if (len > path->index) { |
222 | | /* override previous cache records on this location */ |
223 | 18 | r = fseek(f, path->index, SEEK_SET); |
224 | 18 | if (r != 0) { |
225 | 0 | fclose(f); |
226 | 0 | return 0; |
227 | 0 | } |
228 | 67 | } else if (path->index > len) { |
229 | | /* We miss some bytes so we will not cache this chunk */ |
230 | 1 | fclose(f); |
231 | 1 | return 0; |
232 | 1 | } |
233 | | |
234 | 84 | c = fwrite(buf, 1, bufsize, f); |
235 | 84 | fclose(f); |
236 | 84 | if (c != bufsize) { |
237 | 0 | sc_log(p15card->card->ctx, |
238 | 0 | "fwrite() wrote only %"SC_FORMAT_LEN_SIZE_T"u bytes", |
239 | 0 | c); |
240 | 0 | unlink(fname); |
241 | 0 | return SC_ERROR_INTERNAL; |
242 | 0 | } |
243 | 84 | return 0; |
244 | 84 | } |