Coverage Report

Created: 2026-10-28 06:53

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
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
}