/src/opensc/src/libopensc/muscle-filesystem.c
Line | Count | Source |
1 | | /* |
2 | | * muscle-filesystem.c: Support for MuscleCard Applet from musclecard.com |
3 | | * |
4 | | * Copyright (C) 2006, Identity Alliance, Thomas Harning <support@identityalliance.com> |
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 <memory.h> |
26 | | #include <stdio.h> |
27 | | |
28 | | #include "libopensc/muscle-filesystem.h" |
29 | | #include "libopensc/errors.h" |
30 | | |
31 | 0 | #define MSCFS_NO_MEMORY SC_ERROR_OUT_OF_MEMORY |
32 | 4.09k | #define MSCFS_INVALID_ARGS SC_ERROR_INVALID_ARGUMENTS |
33 | 2.83k | #define MSCFS_FILE_NOT_FOUND SC_ERROR_FILE_NOT_FOUND |
34 | 6.19k | #define MSCFS_CACHE_INCREMENT 128 |
35 | | |
36 | | static msc_id rootId = { { 0x3F, 0x00, 0x3F, 0x00 } }; |
37 | | |
38 | | static const u8* ignoredFiles[] = { |
39 | | (const u8*)"l0\0\0", |
40 | | (const u8*)"L0\0\0", |
41 | | NULL |
42 | | }; |
43 | | |
44 | 8.26k | mscfs_t *mscfs_new(void) { |
45 | 8.26k | mscfs_t *fs = malloc(sizeof(mscfs_t)); |
46 | 8.26k | if (!fs) |
47 | 0 | return NULL; |
48 | 8.26k | memset(fs, 0, sizeof(mscfs_t)); |
49 | 8.26k | memcpy(fs->currentPath, "\x3F\x00", 2); |
50 | 8.26k | return fs; |
51 | 8.26k | } |
52 | | |
53 | 8.26k | void mscfs_free(mscfs_t *fs) { |
54 | 8.26k | mscfs_clear_cache(fs); |
55 | 8.26k | free(fs); |
56 | 8.26k | } |
57 | | |
58 | 24.4k | void mscfs_clear_cache(mscfs_t* fs) { |
59 | 24.4k | if(!fs->cache.array) { |
60 | 21.4k | return; |
61 | 21.4k | } |
62 | 3.03k | free(fs->cache.array); |
63 | 3.03k | fs->cache.array = NULL; |
64 | 3.03k | fs->cache.totalSize = 0; |
65 | 3.03k | fs->cache.size = 0; |
66 | 3.03k | } |
67 | | |
68 | | static int mscfs_is_ignored(mscfs_t* fs, msc_id objectId) |
69 | 426k | { |
70 | 426k | int ignored = 0; |
71 | 426k | const u8** ptr = ignoredFiles; |
72 | 1.27M | while(ptr && *ptr && !ignored) { |
73 | 852k | if(0 == memcmp(objectId.id, *ptr, 4)) |
74 | 1.80k | ignored = 1; |
75 | 852k | ptr++; |
76 | 852k | } |
77 | 426k | return ignored; |
78 | 426k | } |
79 | | |
80 | 424k | #define MAX_FILES 10000 |
81 | | int mscfs_push_file(mscfs_t* fs, mscfs_file_t *file) |
82 | 424k | { |
83 | 424k | mscfs_cache_t *cache = &fs->cache; |
84 | 424k | if (cache->size >= MAX_FILES) |
85 | 7 | return SC_ERROR_INTERNAL; |
86 | 424k | if(!cache->array || cache->size == cache->totalSize) { |
87 | 6.19k | int length = cache->totalSize + MSCFS_CACHE_INCREMENT; |
88 | 6.19k | mscfs_file_t *oldArray; |
89 | 6.19k | cache->totalSize = length; |
90 | 6.19k | oldArray = cache->array; |
91 | 6.19k | cache->array = malloc(sizeof(mscfs_file_t) * length); |
92 | 6.19k | if(!cache->array) |
93 | 0 | return MSCFS_NO_MEMORY; |
94 | 6.19k | if(oldArray) { |
95 | 3.16k | memcpy(cache->array, oldArray, sizeof(mscfs_file_t) * cache->size); |
96 | 3.16k | free(oldArray); |
97 | 3.16k | } |
98 | 6.19k | } |
99 | 424k | cache->array[cache->size] = *file; |
100 | 424k | cache->size++; |
101 | 424k | return SC_SUCCESS; |
102 | 424k | } |
103 | | |
104 | 15.8k | int mscfs_update_cache(mscfs_t* fs) { |
105 | 15.8k | mscfs_file_t file; |
106 | 15.8k | int r; |
107 | 15.8k | mscfs_clear_cache(fs); |
108 | 15.8k | r = fs->listFile(&file, 1, fs->udata); |
109 | 15.8k | if(r == 0) |
110 | 604 | return 0; |
111 | 15.2k | else if(r < 0) |
112 | 11.9k | return r; |
113 | 426k | while(1) { |
114 | 426k | if(!mscfs_is_ignored(fs, file.objectId)) { |
115 | | /* Check if its a directory in the root */ |
116 | 424k | u8* oid = file.objectId.id; |
117 | 424k | if(oid[2] == 0 && oid[3] == 0) { |
118 | 186k | oid[2] = oid[0]; |
119 | 186k | oid[3] = oid[1]; |
120 | 186k | oid[0] = 0x3F; |
121 | 186k | oid[1] = 0x00; |
122 | 186k | file.ef = 0; |
123 | 238k | } else { |
124 | 238k | file.ef = 1; /* File is a working elementary file */ |
125 | 238k | } |
126 | | |
127 | 424k | r = mscfs_push_file(fs, &file); |
128 | 424k | if (r != SC_SUCCESS) |
129 | 7 | return r; |
130 | 424k | } |
131 | 426k | r = fs->listFile(&file, 0, fs->udata); |
132 | 426k | if(r == 0) |
133 | 1.13k | break; |
134 | 425k | else if(r < 0) |
135 | 2.13k | return r; |
136 | 426k | } |
137 | 1.13k | return fs->cache.size; |
138 | 3.27k | } |
139 | | |
140 | | int mscfs_check_cache(mscfs_t* fs) |
141 | 175k | { |
142 | 175k | int r = SC_SUCCESS; |
143 | 175k | if(!fs->cache.array) { |
144 | 15.8k | r = mscfs_update_cache(fs); |
145 | 15.8k | } |
146 | 175k | return r; |
147 | 175k | } |
148 | | |
149 | | int mscfs_lookup_path(mscfs_t* fs, const u8 *path, size_t pathlen, msc_id* objectId, int isDirectory) |
150 | 14.8k | { |
151 | 14.8k | u8* oid = objectId->id; |
152 | 14.8k | if ((pathlen & 1) != 0) /* not divisible by 2 */ |
153 | 3.98k | return MSCFS_INVALID_ARGS; |
154 | 10.8k | if(isDirectory) { |
155 | | /* Directory must be right next to root */ |
156 | 0 | if ((pathlen == 4 && 0 == memcmp(path, "\x3F\x00", 2)) || |
157 | 0 | (pathlen == 2 && 0 == memcmp(fs->currentPath, "\x3F\x00", 2))) { |
158 | 0 | oid[0] = path[pathlen - 2]; |
159 | 0 | oid[1] = path[pathlen - 1]; |
160 | 0 | oid[2] = oid[3] = 0; |
161 | 0 | } else { |
162 | 0 | return MSCFS_INVALID_ARGS; |
163 | 0 | } |
164 | 0 | } |
165 | 10.8k | oid[0] = fs->currentPath[0]; |
166 | 10.8k | oid[1] = fs->currentPath[1]; |
167 | | /* Chop off the root in the path */ |
168 | 10.8k | if(pathlen > 2 && memcmp(path, "\x3F\x00", 2) == 0) { |
169 | 8.67k | path += 2; |
170 | 8.67k | pathlen -= 2; |
171 | 8.67k | oid[0] = 0x3F; |
172 | 8.67k | oid[1] = 0x00; |
173 | 8.67k | } |
174 | | /* Limit to a single directory */ |
175 | 10.8k | if(pathlen > 4) |
176 | 108 | return MSCFS_INVALID_ARGS; |
177 | | /* Reset to root */ |
178 | 10.7k | if(pathlen == 2 && 0 == memcmp(path, "\x3F\x00", 2)) { |
179 | 1.05k | oid[0] = oid[2] = path[0]; |
180 | 1.05k | oid[1] = oid[3] = path[1]; |
181 | 9.71k | } else if(pathlen == 2) { /* Path preserved for current-path */ |
182 | 5.47k | oid[2] = path[0]; |
183 | 5.47k | oid[3] = path[1]; |
184 | 5.47k | } else if(pathlen == 4) { |
185 | 3.96k | oid[0] = path[0]; |
186 | 3.96k | oid[1] = path[1]; |
187 | 3.96k | oid[2] = path[2]; |
188 | 3.96k | oid[3] = path[3]; |
189 | 3.96k | } |
190 | | |
191 | 10.7k | return 0; |
192 | 10.8k | } |
193 | | |
194 | | int mscfs_lookup_local(mscfs_t* fs, const int id, msc_id* objectId) |
195 | 2 | { |
196 | 2 | u8* oid = objectId->id; |
197 | 2 | oid[0] = fs->currentPath[0]; |
198 | 2 | oid[1] = fs->currentPath[1]; |
199 | 2 | oid[2] = (id >> 8) & 0xFF; |
200 | 2 | oid[3] = id & 0xFF; |
201 | 2 | return 0; |
202 | 2 | } |
203 | | |
204 | | /* -1 any, 0 DF, 1 EF */ |
205 | | int mscfs_check_selection(mscfs_t *fs, int requiredItem) |
206 | 6.41k | { |
207 | 6.41k | if(fs->currentPath[0] == 0 && fs->currentPath[1] == 0) |
208 | 1 | return MSCFS_INVALID_ARGS; |
209 | 6.41k | if(requiredItem == 1 && fs->currentFile[0] == 0 && fs->currentFile[1] == 0) |
210 | 0 | return MSCFS_INVALID_ARGS; |
211 | 6.41k | return 0; |
212 | 6.41k | } |
213 | | |
214 | | int mscfs_loadFileInfo(mscfs_t* fs, const u8 *path, size_t pathlen, mscfs_file_t **file_data, int* idx) |
215 | 14.8k | { |
216 | 14.8k | msc_id fullPath = {{0, 0, 0, 0}}; |
217 | 14.8k | int x, rc; |
218 | 14.8k | if (fs == NULL || path == NULL || file_data == NULL) |
219 | 0 | return SC_ERROR_INTERNAL; |
220 | 14.8k | rc = mscfs_lookup_path(fs, path, pathlen, &fullPath, 0); |
221 | 14.8k | if (rc != SC_SUCCESS) { |
222 | 4.09k | return rc; |
223 | 4.09k | } |
224 | | |
225 | | /* Obtain file information while checking if it exists */ |
226 | 10.7k | rc = mscfs_check_cache(fs); |
227 | 10.7k | if (rc < 0) |
228 | 200 | return rc; |
229 | 10.5k | if(idx) *idx = -1; |
230 | 902k | for(x = 0; x < fs->cache.size; x++) { |
231 | 896k | *file_data = &fs->cache.array[x]; |
232 | 896k | if (*file_data) { |
233 | 896k | msc_id objectId; |
234 | 896k | objectId = (*file_data)->objectId; |
235 | 896k | if(0 == memcmp(objectId.id, fullPath.id, 4)) { |
236 | 4.76k | if (idx) |
237 | 4.57k | *idx = x; |
238 | 4.76k | break; |
239 | 4.76k | } |
240 | 892k | *file_data = NULL; |
241 | 892k | } |
242 | 896k | } |
243 | 10.5k | if(*file_data == NULL && (0 == memcmp("\x3F\x00\x00\x00", fullPath.id, 4) || 0 == memcmp("\x3F\x00\x50\x15", fullPath.id, 4 ) || 0 == memcmp("\x3F\x00\x3F\x00", fullPath.id, 4))) { |
244 | 2.95k | static mscfs_file_t ROOT_FILE; |
245 | 2.95k | ROOT_FILE.ef = 0; |
246 | 2.95k | ROOT_FILE.size = 0; |
247 | | /* Faked Root ID */ |
248 | 2.95k | ROOT_FILE.objectId = rootId; |
249 | | |
250 | 2.95k | ROOT_FILE.read = 0; |
251 | 2.95k | ROOT_FILE.write = 0x02; /* User Pin access */ |
252 | 2.95k | ROOT_FILE.delete = 0x02; |
253 | | |
254 | 2.95k | *file_data = &ROOT_FILE; |
255 | 2.95k | if(idx) *idx = -2; |
256 | 7.60k | } else if(*file_data == NULL) { |
257 | 2.83k | return MSCFS_FILE_NOT_FOUND; |
258 | 2.83k | } |
259 | | |
260 | 7.72k | return 0; |
261 | 10.5k | } |