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