Coverage Report

Created: 2026-09-14 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
#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
538
#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
338
mscfs_t *mscfs_new(void) {
46
338
  mscfs_t *fs = malloc(sizeof(mscfs_t));
47
338
  if (!fs)
48
0
    return NULL;
49
338
  memset(fs, 0, sizeof(mscfs_t));
50
338
  memcpy(fs->currentPath, "\x3F\x00", 2);
51
338
  return fs;
52
338
}
53
54
338
void mscfs_free(mscfs_t *fs) {
55
338
  mscfs_clear_cache(fs);
56
338
  free(fs);
57
338
}
58
59
676
void mscfs_clear_cache(mscfs_t* fs) {
60
676
  if(!fs->cache.array) {
61
540
    return;
62
540
  }
63
136
  free(fs->cache.array);
64
136
  fs->cache.array = NULL;
65
136
  fs->cache.totalSize = 0;
66
136
  fs->cache.size = 0;
67
136
}
68
69
static int mscfs_is_ignored(mscfs_t* fs, msc_id objectId)
70
53.4k
{
71
53.4k
  int ignored = 0;
72
53.4k
  const u8** ptr = ignoredFiles;
73
160k
  while(ptr && *ptr && !ignored) {
74
106k
    if(0 == memcmp(objectId.id, *ptr, 4))
75
196
      ignored = 1;
76
106k
    ptr++;
77
106k
  }
78
53.4k
  return ignored;
79
53.4k
}
80
81
53.2k
#define MAX_FILES 10000
82
int mscfs_push_file(mscfs_t* fs, mscfs_file_t *file)
83
53.2k
{
84
53.2k
  mscfs_cache_t *cache = &fs->cache;
85
53.2k
  if (cache->size >= MAX_FILES)
86
1
    return SC_ERROR_INTERNAL;
87
53.2k
  if(!cache->array || cache->size == cache->totalSize) {
88
538
    int length = cache->totalSize + MSCFS_CACHE_INCREMENT;
89
538
    mscfs_file_t *oldArray;
90
538
    cache->totalSize = length;
91
538
    oldArray = cache->array;
92
538
    cache->array = malloc(sizeof(mscfs_file_t) * length);
93
538
    if(!cache->array)
94
0
      return MSCFS_NO_MEMORY;
95
538
    if(oldArray) {
96
402
      memcpy(cache->array, oldArray, sizeof(mscfs_file_t) * cache->size);
97
402
      free(oldArray);
98
402
    }
99
538
  }
100
53.2k
  cache->array[cache->size] = *file;
101
53.2k
  cache->size++;
102
53.2k
  return SC_SUCCESS;
103
53.2k
}
104
105
338
int mscfs_update_cache(mscfs_t* fs) {
106
338
  mscfs_file_t file;
107
338
  int r;
108
338
  mscfs_clear_cache(fs);
109
338
  r = fs->listFile(&file, 1, fs->udata);
110
338
  if(r == 0)
111
2
    return 0;
112
336
  else if(r < 0)
113
196
    return r;
114
53.4k
  while(1) {
115
53.4k
    if(!mscfs_is_ignored(fs, file.objectId)) {
116
      /* Check if its a directory in the root */
117
53.2k
      u8* oid = file.objectId.id;
118
53.2k
      if(oid[2] == 0 && oid[3] == 0) {
119
1.69k
        oid[2] = oid[0];
120
1.69k
        oid[3] = oid[1];
121
1.69k
        oid[0] = 0x3F;
122
1.69k
        oid[1] = 0x00;
123
1.69k
        file.ef = 0;
124
51.5k
      } else  {
125
51.5k
        file.ef = 1; /* File is a working elementary file */
126
51.5k
      }
127
128
53.2k
      r = mscfs_push_file(fs, &file);
129
53.2k
      if (r != SC_SUCCESS)
130
1
        return r;
131
53.2k
    }
132
53.4k
    r = fs->listFile(&file, 0, fs->udata);
133
53.4k
    if(r == 0)
134
69
      break;
135
53.4k
    else if(r < 0)
136
70
      return r;
137
53.4k
  }
138
69
  return fs->cache.size;
139
140
}
140
141
int mscfs_check_cache(mscfs_t* fs)
142
338
{
143
338
  int r = SC_SUCCESS;
144
338
  if(!fs->cache.array) {
145
338
    r = mscfs_update_cache(fs);
146
338
  }
147
338
  return r;
148
338
}
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
  if (fs == NULL || path == NULL || file_data == NULL)
220
0
    return SC_ERROR_INTERNAL;
221
0
  rc = mscfs_lookup_path(fs, path, pathlen, &fullPath, 0);
222
0
  if (rc != SC_SUCCESS) {
223
0
    return rc;
224
0
  }
225
226
  /* Obtain file information while checking if it exists */
227
0
  rc = mscfs_check_cache(fs);
228
0
  if (rc < 0)
229
0
    return rc;
230
0
  if(idx) *idx = -1;
231
0
  for(x = 0; x < fs->cache.size; x++) {
232
0
    *file_data = &fs->cache.array[x];
233
0
    if (*file_data) {
234
0
      msc_id objectId;
235
0
      objectId = (*file_data)->objectId;
236
0
      if(0 == memcmp(objectId.id, fullPath.id, 4)) {
237
0
        if (idx)
238
0
          *idx = x;
239
0
        break;
240
0
      }
241
0
      *file_data = NULL;
242
0
    }
243
0
  }
244
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))) {
245
0
    static mscfs_file_t ROOT_FILE;
246
0
    ROOT_FILE.ef = 0;
247
0
    ROOT_FILE.size = 0;
248
    /* Faked Root ID */
249
0
    ROOT_FILE.objectId = rootId;
250
251
0
    ROOT_FILE.read = 0;
252
0
    ROOT_FILE.write = 0x02; /* User Pin access */
253
0
    ROOT_FILE.delete = 0x02;
254
255
0
    *file_data = &ROOT_FILE;
256
0
    if(idx) *idx = -2;
257
0
  } else if(*file_data == NULL) {
258
0
    return MSCFS_FILE_NOT_FOUND;
259
0
  }
260
261
0
  return 0;
262
0
}