/src/opensc/src/libopensc/sc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * sc.c: General 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 <ctype.h> |
27 | | #include <stdlib.h> |
28 | | #include <string.h> |
29 | | #include <assert.h> |
30 | | #ifdef HAVE_SYS_MMAN_H |
31 | | #include <sys/mman.h> |
32 | | #endif |
33 | | #ifdef ENABLE_OPENSSL |
34 | | #include <openssl/crypto.h> /* for OPENSSL_cleanse */ |
35 | | #endif |
36 | | |
37 | | |
38 | | #include "internal.h" |
39 | | |
40 | | #ifdef PACKAGE_VERSION |
41 | | static const char *sc_version = PACKAGE_VERSION; |
42 | | #else |
43 | | static const char *sc_version = "(undef)"; |
44 | | #endif |
45 | | |
46 | | #ifdef _WIN32 |
47 | | #include <windows.h> |
48 | | #define PAGESIZE 0 |
49 | | #else |
50 | | #include <sys/mman.h> |
51 | | #include <limits.h> |
52 | | #include <unistd.h> |
53 | | #ifndef PAGESIZE |
54 | | #define PAGESIZE 0 |
55 | | #endif |
56 | | #endif |
57 | | |
58 | | const char *sc_get_version(void) |
59 | 0 | { |
60 | 0 | return sc_version; |
61 | 0 | } |
62 | | |
63 | | int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen) |
64 | 0 | { |
65 | 0 | const char *sc_hex_to_bin_separators = " :"; |
66 | 0 | if (in == NULL || out == NULL || outlen == NULL) { |
67 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
68 | 0 | } |
69 | | |
70 | 0 | int byte_needs_nibble = 0; |
71 | 0 | int r = SC_SUCCESS; |
72 | 0 | size_t left = *outlen; |
73 | 0 | u8 byte = 0; |
74 | 0 | while (*in != '\0' && 0 != left) { |
75 | 0 | char c = *in++; |
76 | 0 | u8 nibble; |
77 | 0 | if ('0' <= c && c <= '9') |
78 | 0 | nibble = c - '0'; |
79 | 0 | else if ('a' <= c && c <= 'f') |
80 | 0 | nibble = c - 'a' + 10; |
81 | 0 | else if ('A' <= c && c <= 'F') |
82 | 0 | nibble = c - 'A' + 10; |
83 | 0 | else { |
84 | 0 | if (strchr(sc_hex_to_bin_separators, (int) c)) { |
85 | 0 | if (byte_needs_nibble) { |
86 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
87 | 0 | goto err; |
88 | 0 | } |
89 | 0 | continue; |
90 | 0 | } |
91 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
92 | 0 | goto err; |
93 | 0 | } |
94 | | |
95 | 0 | if (byte_needs_nibble) { |
96 | 0 | byte |= nibble; |
97 | 0 | *out++ = (u8) byte; |
98 | 0 | left--; |
99 | 0 | byte_needs_nibble = 0; |
100 | 0 | } else { |
101 | 0 | byte = nibble << 4; |
102 | 0 | byte_needs_nibble = 1; |
103 | 0 | } |
104 | 0 | } |
105 | | |
106 | 0 | if (left == *outlen && 1 == byte_needs_nibble && 0 != left) { |
107 | | /* no output written so far, but we have a valid nibble in the upper |
108 | | * bits. Allow this special case. */ |
109 | 0 | *out = (u8) byte>>4; |
110 | 0 | left--; |
111 | 0 | byte_needs_nibble = 0; |
112 | 0 | } |
113 | | |
114 | | /* for ease of implementation we only accept completely hexed bytes. */ |
115 | 0 | if (byte_needs_nibble) { |
116 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
117 | 0 | goto err; |
118 | 0 | } |
119 | | |
120 | | /* skip all trailing separators to see if we missed something */ |
121 | 0 | while (*in != '\0') { |
122 | 0 | if (NULL == strchr(sc_hex_to_bin_separators, (int) *in)) |
123 | 0 | break; |
124 | 0 | in++; |
125 | 0 | } |
126 | 0 | if (*in != '\0') { |
127 | 0 | r = SC_ERROR_BUFFER_TOO_SMALL; |
128 | 0 | goto err; |
129 | 0 | } |
130 | | |
131 | 0 | err: |
132 | 0 | *outlen -= left; |
133 | 0 | return r; |
134 | 0 | } |
135 | | |
136 | | int sc_bin_to_hex(const u8 *in, size_t in_len, char *out, size_t out_len, |
137 | | int in_sep) |
138 | 0 | { |
139 | 0 | if (in == NULL || out == NULL) { |
140 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
141 | 0 | } |
142 | | |
143 | 0 | if (in_sep > 0) { |
144 | 0 | if (out_len < in_len*3 || out_len < 1) |
145 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
146 | 0 | } else { |
147 | 0 | if (out_len < in_len*2 + 1) |
148 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
149 | 0 | } |
150 | | |
151 | 0 | const char hex[] = "0123456789abcdef"; |
152 | 0 | while (in_len) { |
153 | 0 | unsigned char value = *in++; |
154 | 0 | *out++ = hex[(value >> 4) & 0xF]; |
155 | 0 | *out++ = hex[ value & 0xF]; |
156 | 0 | in_len--; |
157 | 0 | if (in_len && in_sep > 0) |
158 | 0 | *out++ = (char)in_sep; |
159 | 0 | } |
160 | 0 | *out = '\0'; |
161 | |
|
162 | 0 | return SC_SUCCESS; |
163 | 0 | } |
164 | | |
165 | | /* |
166 | | * Right trim all non-printable characters |
167 | | */ |
168 | 0 | size_t sc_right_trim(u8 *buf, size_t len) { |
169 | |
|
170 | 0 | size_t i; |
171 | |
|
172 | 0 | if (!buf) |
173 | 0 | return 0; |
174 | | |
175 | 0 | if (len > 0) { |
176 | 0 | for(i = len-1; i > 0; i--) { |
177 | 0 | if(!isprint(buf[i])) { |
178 | 0 | buf[i] = '\0'; |
179 | 0 | len--; |
180 | 0 | continue; |
181 | 0 | } |
182 | 0 | break; |
183 | 0 | } |
184 | 0 | } |
185 | 0 | return len; |
186 | 0 | } |
187 | | |
188 | | u8 *ulong2bebytes(u8 *buf, unsigned long x) |
189 | 0 | { |
190 | 0 | if (buf != NULL) { |
191 | 0 | buf[3] = (u8) (x & 0xff); |
192 | 0 | buf[2] = (u8) ((x >> 8) & 0xff); |
193 | 0 | buf[1] = (u8) ((x >> 16) & 0xff); |
194 | 0 | buf[0] = (u8) ((x >> 24) & 0xff); |
195 | 0 | } |
196 | 0 | return buf; |
197 | 0 | } |
198 | | |
199 | | u8 *ushort2bebytes(u8 *buf, unsigned short x) |
200 | 0 | { |
201 | 0 | if (buf != NULL) { |
202 | 0 | buf[1] = (u8) (x & 0xff); |
203 | 0 | buf[0] = (u8) ((x >> 8) & 0xff); |
204 | 0 | } |
205 | 0 | return buf; |
206 | 0 | } |
207 | | |
208 | | unsigned long bebytes2ulong(const u8 *buf) |
209 | 0 | { |
210 | 0 | if (buf == NULL) |
211 | 0 | return 0UL; |
212 | 0 | return (unsigned long)buf[0] << 24 |
213 | 0 | | (unsigned long)buf[1] << 16 |
214 | 0 | | (unsigned long)buf[2] << 8 |
215 | 0 | | (unsigned long)buf[3]; |
216 | 0 | } |
217 | | |
218 | | unsigned short bebytes2ushort(const u8 *buf) |
219 | 0 | { |
220 | 0 | if (buf == NULL) |
221 | 0 | return 0U; |
222 | 0 | return (unsigned short)buf[0] << 8 |
223 | 0 | | (unsigned short)buf[1]; |
224 | 0 | } |
225 | | |
226 | | unsigned short lebytes2ushort(const u8 *buf) |
227 | 0 | { |
228 | 0 | if (buf == NULL) |
229 | 0 | return 0U; |
230 | 0 | return (unsigned short)buf[1] << 8 |
231 | 0 | | (unsigned short)buf[0]; |
232 | 0 | } |
233 | | |
234 | | unsigned long lebytes2ulong(const u8 *buf) |
235 | 0 | { |
236 | 0 | if (buf == NULL) |
237 | 0 | return 0UL; |
238 | 0 | return (unsigned long)buf[3] << 24 |
239 | 0 | | (unsigned long)buf[2] << 16 |
240 | 0 | | (unsigned long)buf[1] << 8 |
241 | 0 | | (unsigned long)buf[0]; |
242 | 0 | } |
243 | | |
244 | | void set_string(char **strp, const char *value) |
245 | 0 | { |
246 | 0 | if (strp == NULL) { |
247 | 0 | return; |
248 | 0 | } |
249 | | |
250 | 0 | free(*strp); |
251 | 0 | *strp = value ? strdup(value) : NULL; |
252 | 0 | } |
253 | | |
254 | | void sc_init_oid(struct sc_object_id *oid) |
255 | 0 | { |
256 | 0 | int ii; |
257 | |
|
258 | 0 | if (!oid) |
259 | 0 | return; |
260 | 0 | for (ii=0; ii<SC_MAX_OBJECT_ID_OCTETS; ii++) |
261 | 0 | oid->value[ii] = -1; |
262 | 0 | } |
263 | | |
264 | | int sc_format_oid(struct sc_object_id *oid, const char *in) |
265 | 0 | { |
266 | 0 | int ii, ret = SC_ERROR_INVALID_ARGUMENTS; |
267 | 0 | const char *p; |
268 | 0 | char *q; |
269 | |
|
270 | 0 | if (oid == NULL || in == NULL) |
271 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
272 | | |
273 | 0 | sc_init_oid(oid); |
274 | |
|
275 | 0 | p = in; |
276 | 0 | for (ii=0; ii < SC_MAX_OBJECT_ID_OCTETS; ii++) { |
277 | 0 | oid->value[ii] = (int)strtol(p, &q, 10); |
278 | 0 | if (!*q) |
279 | 0 | break; |
280 | | |
281 | 0 | if (!(q[0] == '.' && isdigit((unsigned char)q[1]))) |
282 | 0 | goto out; |
283 | | |
284 | 0 | p = q + 1; |
285 | 0 | } |
286 | | |
287 | 0 | if (!sc_valid_oid(oid)) |
288 | 0 | goto out; |
289 | | |
290 | 0 | ret = SC_SUCCESS; |
291 | 0 | out: |
292 | 0 | if (ret) |
293 | 0 | sc_init_oid(oid); |
294 | |
|
295 | 0 | return ret; |
296 | 0 | } |
297 | | |
298 | | int sc_compare_oid(const struct sc_object_id *oid1, const struct sc_object_id *oid2) |
299 | 0 | { |
300 | 0 | int i; |
301 | |
|
302 | 0 | if (oid1 == NULL || oid2 == NULL) { |
303 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
304 | 0 | } |
305 | | |
306 | 0 | for (i = 0; i < SC_MAX_OBJECT_ID_OCTETS; i++) { |
307 | 0 | if (oid1->value[i] != oid2->value[i]) |
308 | 0 | return 0; |
309 | 0 | if (oid1->value[i] == -1) |
310 | 0 | break; |
311 | 0 | } |
312 | | |
313 | 0 | return 1; |
314 | 0 | } |
315 | | |
316 | | |
317 | | int sc_valid_oid(const struct sc_object_id *oid) |
318 | 0 | { |
319 | 0 | int ii; |
320 | |
|
321 | 0 | if (!oid) |
322 | 0 | return 0; |
323 | 0 | if (oid->value[0] == -1 || oid->value[1] == -1) |
324 | 0 | return 0; |
325 | 0 | if (oid->value[0] > 2 || oid->value[1] > 39) |
326 | 0 | return 0; |
327 | 0 | for (ii=0;ii<SC_MAX_OBJECT_ID_OCTETS;ii++) |
328 | 0 | if (oid->value[ii]) |
329 | 0 | break; |
330 | 0 | if (ii==SC_MAX_OBJECT_ID_OCTETS) |
331 | 0 | return 0; |
332 | 0 | return 1; |
333 | 0 | } |
334 | | |
335 | | |
336 | | int sc_detect_card_presence(sc_reader_t *reader) |
337 | 0 | { |
338 | 0 | int r; |
339 | 0 | LOG_FUNC_CALLED(reader->ctx); |
340 | 0 | if (reader->ops->detect_card_presence == NULL) |
341 | 0 | LOG_FUNC_RETURN(reader->ctx, SC_ERROR_NOT_SUPPORTED); |
342 | | |
343 | 0 | r = reader->ops->detect_card_presence(reader); |
344 | | |
345 | | // Check that we get sane return value from backend |
346 | | // detect_card_presence should return 0 if no card is present. |
347 | 0 | if (r && !(r & SC_READER_CARD_PRESENT)) |
348 | 0 | LOG_FUNC_RETURN(reader->ctx, SC_ERROR_INTERNAL); |
349 | | |
350 | 0 | LOG_FUNC_RETURN(reader->ctx, r); |
351 | 0 | } |
352 | | |
353 | | int sc_path_set(sc_path_t *path, int type, const u8 *id, size_t id_len, |
354 | | int idx, int count) |
355 | 0 | { |
356 | 0 | if (path == NULL || id == NULL || id_len == 0 || id_len > SC_MAX_PATH_SIZE) |
357 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
358 | | |
359 | 0 | memset(path, 0, sizeof(*path)); |
360 | 0 | memcpy(path->value, id, id_len); |
361 | 0 | path->len = id_len; |
362 | 0 | path->type = type; |
363 | 0 | path->index = idx; |
364 | 0 | path->count = count; |
365 | |
|
366 | 0 | return SC_SUCCESS; |
367 | 0 | } |
368 | | |
369 | | void sc_format_path(const char *str, sc_path_t *path) |
370 | 0 | { |
371 | 0 | int type = SC_PATH_TYPE_PATH; |
372 | |
|
373 | 0 | if (path) { |
374 | 0 | memset(path, 0, sizeof(*path)); |
375 | 0 | if (*str == 'i' || *str == 'I') { |
376 | 0 | type = SC_PATH_TYPE_FILE_ID; |
377 | 0 | str++; |
378 | 0 | } |
379 | 0 | path->len = sizeof(path->value); |
380 | 0 | if (sc_hex_to_bin(str, path->value, &path->len) >= 0) { |
381 | 0 | path->type = type; |
382 | 0 | } |
383 | 0 | path->count = -1; |
384 | 0 | } |
385 | 0 | } |
386 | | |
387 | | int sc_append_path(sc_path_t *dest, const sc_path_t *src) |
388 | 0 | { |
389 | 0 | return sc_concatenate_path(dest, dest, src); |
390 | 0 | } |
391 | | |
392 | | int sc_append_path_id(sc_path_t *dest, const u8 *id, size_t idlen) |
393 | 0 | { |
394 | 0 | if (dest->len + idlen > SC_MAX_PATH_SIZE) |
395 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
396 | 0 | memcpy(dest->value + dest->len, id, idlen); |
397 | 0 | dest->len += idlen; |
398 | 0 | return SC_SUCCESS; |
399 | 0 | } |
400 | | |
401 | | int sc_append_file_id(sc_path_t *dest, unsigned int fid) |
402 | 0 | { |
403 | 0 | u8 id[2] = { fid >> 8, fid & 0xff }; |
404 | |
|
405 | 0 | return sc_append_path_id(dest, id, 2); |
406 | 0 | } |
407 | | |
408 | | int sc_concatenate_path(sc_path_t *d, const sc_path_t *p1, const sc_path_t *p2) |
409 | 0 | { |
410 | 0 | sc_path_t tpath; |
411 | |
|
412 | 0 | if (d == NULL || p1 == NULL || p2 == NULL) |
413 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
414 | | |
415 | 0 | if (p1->type == SC_PATH_TYPE_DF_NAME || p2->type == SC_PATH_TYPE_DF_NAME) |
416 | | /* we do not support concatenation of AIDs at the moment */ |
417 | 0 | return SC_ERROR_NOT_SUPPORTED; |
418 | | |
419 | 0 | if (p1->len + p2->len > SC_MAX_PATH_SIZE) |
420 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
421 | | |
422 | 0 | memset(&tpath, 0, sizeof(sc_path_t)); |
423 | 0 | memcpy(tpath.value, p1->value, p1->len); |
424 | 0 | memcpy(tpath.value + p1->len, p2->value, p2->len); |
425 | 0 | tpath.len = p1->len + p2->len; |
426 | 0 | tpath.type = SC_PATH_TYPE_PATH; |
427 | | /* use 'index' and 'count' entry of the second path object */ |
428 | 0 | tpath.index = p2->index; |
429 | 0 | tpath.count = p2->count; |
430 | | /* the result is currently always as path */ |
431 | 0 | tpath.type = SC_PATH_TYPE_PATH; |
432 | |
|
433 | 0 | *d = tpath; |
434 | |
|
435 | 0 | return SC_SUCCESS; |
436 | 0 | } |
437 | | |
438 | | const char *sc_print_path(const sc_path_t *path) |
439 | 0 | { |
440 | 0 | static char buffer[SC_MAX_PATH_STRING_SIZE + SC_MAX_AID_STRING_SIZE]; |
441 | |
|
442 | 0 | if (sc_path_print(buffer, sizeof(buffer), path) != SC_SUCCESS) |
443 | 0 | buffer[0] = '\0'; |
444 | |
|
445 | 0 | return buffer; |
446 | 0 | } |
447 | | |
448 | | int sc_path_print(char *buf, size_t buflen, const sc_path_t *path) |
449 | 0 | { |
450 | 0 | size_t i; |
451 | |
|
452 | 0 | if (buf == NULL || path == NULL) |
453 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
454 | | |
455 | 0 | if (buflen < path->len * 2 + path->aid.len * 2 + 3) |
456 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
457 | | |
458 | 0 | buf[0] = '\0'; |
459 | 0 | if (path->aid.len) { |
460 | 0 | for (i = 0; i < path->aid.len; i++) |
461 | 0 | snprintf(buf + strlen(buf), buflen - strlen(buf), "%02x", path->aid.value[i]); |
462 | 0 | snprintf(buf + strlen(buf), buflen - strlen(buf), "::"); |
463 | 0 | } |
464 | |
|
465 | 0 | for (i = 0; i < path->len; i++) |
466 | 0 | snprintf(buf + strlen(buf), buflen - strlen(buf), "%02x", path->value[i]); |
467 | 0 | if (!path->aid.len && path->type == SC_PATH_TYPE_DF_NAME) |
468 | 0 | snprintf(buf + strlen(buf), buflen - strlen(buf), "::"); |
469 | |
|
470 | 0 | return SC_SUCCESS; |
471 | 0 | } |
472 | | |
473 | | int sc_compare_path(const sc_path_t *path1, const sc_path_t *path2) |
474 | 0 | { |
475 | 0 | return path1->len == path2->len |
476 | 0 | && !memcmp(path1->value, path2->value, path1->len); |
477 | 0 | } |
478 | | |
479 | | int sc_compare_path_prefix(const sc_path_t *prefix, const sc_path_t *path) |
480 | 0 | { |
481 | 0 | sc_path_t tpath; |
482 | |
|
483 | 0 | if (prefix->len > path->len) |
484 | 0 | return 0; |
485 | | |
486 | 0 | tpath = *path; |
487 | 0 | tpath.len = prefix->len; |
488 | |
|
489 | 0 | return sc_compare_path(&tpath, prefix); |
490 | 0 | } |
491 | | |
492 | | const sc_path_t *sc_get_mf_path(void) |
493 | 0 | { |
494 | 0 | static const sc_path_t mf_path = { |
495 | 0 | {0x3f, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 2, |
496 | 0 | 0, |
497 | 0 | 0, |
498 | 0 | SC_PATH_TYPE_PATH, |
499 | 0 | {{0},0} |
500 | 0 | }; |
501 | 0 | return &mf_path; |
502 | 0 | } |
503 | | |
504 | | int sc_file_add_acl_entry(sc_file_t *file, unsigned int operation, |
505 | | unsigned int method, unsigned long key_ref) |
506 | 0 | { |
507 | 0 | sc_acl_entry_t *p, *_new; |
508 | |
|
509 | 0 | if (file == NULL || operation >= SC_MAX_AC_OPS) { |
510 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
511 | 0 | } |
512 | | |
513 | 0 | switch (method) { |
514 | 0 | case SC_AC_NEVER: |
515 | 0 | sc_file_clear_acl_entries(file, operation); |
516 | 0 | file->acl[operation] = (sc_acl_entry_t *) 1; |
517 | 0 | return SC_SUCCESS; |
518 | 0 | case SC_AC_NONE: |
519 | 0 | sc_file_clear_acl_entries(file, operation); |
520 | 0 | file->acl[operation] = (sc_acl_entry_t *) 2; |
521 | 0 | return SC_SUCCESS; |
522 | 0 | case SC_AC_UNKNOWN: |
523 | 0 | sc_file_clear_acl_entries(file, operation); |
524 | 0 | file->acl[operation] = (sc_acl_entry_t *) 3; |
525 | 0 | return SC_SUCCESS; |
526 | 0 | default: |
527 | | /* NONE and UNKNOWN get zapped when a new AC is added. |
528 | | * If the ACL is NEVER, additional entries will be |
529 | | * dropped silently. */ |
530 | 0 | if (file->acl[operation] == (sc_acl_entry_t *) 1) |
531 | 0 | return SC_SUCCESS; |
532 | 0 | if (file->acl[operation] == (sc_acl_entry_t *) 2 |
533 | 0 | || file->acl[operation] == (sc_acl_entry_t *) 3) |
534 | 0 | file->acl[operation] = NULL; |
535 | 0 | } |
536 | | |
537 | | /* If the entry is already present (e.g. due to the mapping) |
538 | | * of the card's AC with OpenSC's), don't add it again. */ |
539 | 0 | for (p = file->acl[operation]; p != NULL; p = p->next) { |
540 | 0 | if ((p->method == method) && (p->key_ref == key_ref)) |
541 | 0 | return SC_SUCCESS; |
542 | 0 | } |
543 | | |
544 | 0 | _new = malloc(sizeof(sc_acl_entry_t)); |
545 | 0 | if (_new == NULL) |
546 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
547 | 0 | _new->method = method; |
548 | 0 | _new->key_ref = (unsigned)key_ref; |
549 | 0 | _new->next = NULL; |
550 | |
|
551 | 0 | p = file->acl[operation]; |
552 | 0 | if (p == NULL) { |
553 | 0 | file->acl[operation] = _new; |
554 | 0 | return SC_SUCCESS; |
555 | 0 | } |
556 | 0 | while (p->next != NULL) |
557 | 0 | p = p->next; |
558 | 0 | p->next = _new; |
559 | |
|
560 | 0 | return SC_SUCCESS; |
561 | 0 | } |
562 | | |
563 | | const sc_acl_entry_t * sc_file_get_acl_entry(const sc_file_t *file, |
564 | | unsigned int operation) |
565 | 0 | { |
566 | 0 | sc_acl_entry_t *p; |
567 | 0 | static const sc_acl_entry_t e_never = { |
568 | 0 | SC_AC_NEVER, SC_AC_KEY_REF_NONE, NULL |
569 | 0 | }; |
570 | 0 | static const sc_acl_entry_t e_none = { |
571 | 0 | SC_AC_NONE, SC_AC_KEY_REF_NONE, NULL |
572 | 0 | }; |
573 | 0 | static const sc_acl_entry_t e_unknown = { |
574 | 0 | SC_AC_UNKNOWN, SC_AC_KEY_REF_NONE, NULL |
575 | 0 | }; |
576 | |
|
577 | 0 | if (file == NULL || operation >= SC_MAX_AC_OPS) { |
578 | 0 | return NULL; |
579 | 0 | } |
580 | | |
581 | 0 | p = file->acl[operation]; |
582 | 0 | if (p == (sc_acl_entry_t *) 1) |
583 | 0 | return &e_never; |
584 | 0 | if (p == (sc_acl_entry_t *) 2) |
585 | 0 | return &e_none; |
586 | 0 | if (p == (sc_acl_entry_t *) 3) |
587 | 0 | return &e_unknown; |
588 | | |
589 | 0 | return file->acl[operation]; |
590 | 0 | } |
591 | | |
592 | | void sc_file_clear_acl_entries(sc_file_t *file, unsigned int operation) |
593 | 0 | { |
594 | 0 | sc_acl_entry_t *e; |
595 | |
|
596 | 0 | if (file == NULL || operation >= SC_MAX_AC_OPS) { |
597 | 0 | return; |
598 | 0 | } |
599 | | |
600 | 0 | e = file->acl[operation]; |
601 | 0 | if (e == (sc_acl_entry_t *) 1 || |
602 | 0 | e == (sc_acl_entry_t *) 2 || |
603 | 0 | e == (sc_acl_entry_t *) 3) { |
604 | 0 | file->acl[operation] = NULL; |
605 | 0 | return; |
606 | 0 | } |
607 | | |
608 | 0 | while (e != NULL) { |
609 | 0 | sc_acl_entry_t *tmp = e->next; |
610 | 0 | free(e); |
611 | 0 | e = tmp; |
612 | 0 | } |
613 | 0 | file->acl[operation] = NULL; |
614 | 0 | } |
615 | | |
616 | | sc_file_t * sc_file_new(void) |
617 | 0 | { |
618 | 0 | sc_file_t *file = (sc_file_t *)calloc(1, sizeof(sc_file_t)); |
619 | 0 | if (file == NULL) |
620 | 0 | return NULL; |
621 | | |
622 | 0 | file->magic = SC_FILE_MAGIC; |
623 | 0 | return file; |
624 | 0 | } |
625 | | |
626 | | void sc_file_free(sc_file_t *file) |
627 | 0 | { |
628 | 0 | unsigned int i; |
629 | 0 | if (file == NULL || !sc_file_valid(file)) |
630 | 0 | return; |
631 | 0 | file->magic = 0; |
632 | 0 | for (i = 0; i < SC_MAX_AC_OPS; i++) |
633 | 0 | sc_file_clear_acl_entries(file, i); |
634 | 0 | if (file->sec_attr) |
635 | 0 | free(file->sec_attr); |
636 | 0 | if (file->prop_attr) |
637 | 0 | free(file->prop_attr); |
638 | 0 | if (file->type_attr) |
639 | 0 | free(file->type_attr); |
640 | 0 | if (file->encoded_content) |
641 | 0 | free(file->encoded_content); |
642 | 0 | free(file); |
643 | 0 | } |
644 | | |
645 | | void sc_file_dup(sc_file_t **dest, const sc_file_t *src) |
646 | 0 | { |
647 | 0 | sc_file_t *newf; |
648 | 0 | const sc_acl_entry_t *e; |
649 | 0 | unsigned int op; |
650 | |
|
651 | 0 | *dest = NULL; |
652 | 0 | if (!sc_file_valid(src)) |
653 | 0 | return; |
654 | 0 | newf = sc_file_new(); |
655 | 0 | if (newf == NULL) |
656 | 0 | return; |
657 | 0 | *dest = newf; |
658 | |
|
659 | 0 | memcpy(&newf->path, &src->path, sizeof(struct sc_path)); |
660 | 0 | memcpy(&newf->name, &src->name, sizeof(src->name)); |
661 | 0 | newf->namelen = src->namelen; |
662 | 0 | newf->type = src->type; |
663 | 0 | newf->shareable = src->shareable; |
664 | 0 | newf->ef_structure = src->ef_structure; |
665 | 0 | newf->size = src->size; |
666 | 0 | newf->id = src->id; |
667 | 0 | newf->status = src->status; |
668 | 0 | for (op = 0; op < SC_MAX_AC_OPS; op++) { |
669 | 0 | newf->acl[op] = NULL; |
670 | 0 | e = sc_file_get_acl_entry(src, op); |
671 | 0 | if (e != NULL) { |
672 | 0 | if (sc_file_add_acl_entry(newf, op, e->method, e->key_ref) < 0) |
673 | 0 | goto err; |
674 | 0 | } |
675 | 0 | } |
676 | 0 | newf->record_length = src->record_length; |
677 | 0 | newf->record_count = src->record_count; |
678 | |
|
679 | 0 | if (sc_file_set_sec_attr(newf, src->sec_attr, src->sec_attr_len) < 0) |
680 | 0 | goto err; |
681 | 0 | if (sc_file_set_prop_attr(newf, src->prop_attr, src->prop_attr_len) < 0) |
682 | 0 | goto err; |
683 | 0 | if (sc_file_set_type_attr(newf, src->type_attr, src->type_attr_len) < 0) |
684 | 0 | goto err; |
685 | 0 | if (sc_file_set_content(newf, src->encoded_content, src->encoded_content_len) < 0) |
686 | 0 | goto err; |
687 | 0 | return; |
688 | 0 | err: |
689 | 0 | sc_file_free(newf); |
690 | 0 | *dest = NULL; |
691 | 0 | } |
692 | | |
693 | | int sc_file_set_sec_attr(sc_file_t *file, const u8 *sec_attr, |
694 | | size_t sec_attr_len) |
695 | 0 | { |
696 | 0 | u8 *tmp; |
697 | 0 | if (!sc_file_valid(file)) { |
698 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
699 | 0 | } |
700 | | |
701 | 0 | if (sec_attr == NULL || sec_attr_len == 0) { |
702 | 0 | if (file->sec_attr != NULL) |
703 | 0 | free(file->sec_attr); |
704 | 0 | file->sec_attr = NULL; |
705 | 0 | file->sec_attr_len = 0; |
706 | 0 | return 0; |
707 | 0 | } |
708 | 0 | tmp = (u8 *) realloc(file->sec_attr, sec_attr_len); |
709 | 0 | if (!tmp) { |
710 | 0 | if (file->sec_attr) |
711 | 0 | free(file->sec_attr); |
712 | 0 | file->sec_attr = NULL; |
713 | 0 | file->sec_attr_len = 0; |
714 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
715 | 0 | } |
716 | 0 | file->sec_attr = tmp; |
717 | 0 | memcpy(file->sec_attr, sec_attr, sec_attr_len); |
718 | 0 | file->sec_attr_len = sec_attr_len; |
719 | |
|
720 | 0 | return 0; |
721 | 0 | } |
722 | | |
723 | | int sc_file_set_prop_attr(sc_file_t *file, const u8 *prop_attr, |
724 | | size_t prop_attr_len) |
725 | 0 | { |
726 | 0 | u8 *tmp; |
727 | 0 | if (!sc_file_valid(file)) { |
728 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
729 | 0 | } |
730 | | |
731 | 0 | if (prop_attr == NULL || prop_attr_len == 0) { |
732 | 0 | if (file->prop_attr != NULL) |
733 | 0 | free(file->prop_attr); |
734 | 0 | file->prop_attr = NULL; |
735 | 0 | file->prop_attr_len = 0; |
736 | 0 | return SC_SUCCESS; |
737 | 0 | } |
738 | 0 | tmp = (u8 *) realloc(file->prop_attr, prop_attr_len); |
739 | 0 | if (!tmp) { |
740 | 0 | if (file->prop_attr) |
741 | 0 | free(file->prop_attr); |
742 | 0 | file->prop_attr = NULL; |
743 | 0 | file->prop_attr_len = 0; |
744 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
745 | 0 | } |
746 | 0 | file->prop_attr = tmp; |
747 | 0 | memcpy(file->prop_attr, prop_attr, prop_attr_len); |
748 | 0 | file->prop_attr_len = prop_attr_len; |
749 | |
|
750 | 0 | return SC_SUCCESS; |
751 | 0 | } |
752 | | |
753 | | int sc_file_set_type_attr(sc_file_t *file, const u8 *type_attr, |
754 | | size_t type_attr_len) |
755 | 0 | { |
756 | 0 | u8 *tmp; |
757 | 0 | if (!sc_file_valid(file)) { |
758 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
759 | 0 | } |
760 | | |
761 | 0 | if (type_attr == NULL || type_attr_len == 0) { |
762 | 0 | if (file->type_attr != NULL) |
763 | 0 | free(file->type_attr); |
764 | 0 | file->type_attr = NULL; |
765 | 0 | file->type_attr_len = 0; |
766 | 0 | return SC_SUCCESS; |
767 | 0 | } |
768 | 0 | tmp = (u8 *) realloc(file->type_attr, type_attr_len); |
769 | 0 | if (!tmp) { |
770 | 0 | if (file->type_attr) |
771 | 0 | free(file->type_attr); |
772 | 0 | file->type_attr = NULL; |
773 | 0 | file->type_attr_len = 0; |
774 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
775 | 0 | } |
776 | 0 | file->type_attr = tmp; |
777 | 0 | memcpy(file->type_attr, type_attr, type_attr_len); |
778 | 0 | file->type_attr_len = type_attr_len; |
779 | |
|
780 | 0 | return SC_SUCCESS; |
781 | 0 | } |
782 | | |
783 | | |
784 | | int sc_file_set_content(sc_file_t *file, const u8 *content, |
785 | | size_t content_len) |
786 | 0 | { |
787 | 0 | u8 *tmp; |
788 | 0 | if (!sc_file_valid(file)) { |
789 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
790 | 0 | } |
791 | | |
792 | 0 | if (content == NULL || content_len == 0) { |
793 | 0 | if (file->encoded_content != NULL) |
794 | 0 | free(file->encoded_content); |
795 | 0 | file->encoded_content = NULL; |
796 | 0 | file->encoded_content_len = 0; |
797 | 0 | return SC_SUCCESS; |
798 | 0 | } |
799 | | |
800 | 0 | tmp = (u8 *) realloc(file->encoded_content, content_len); |
801 | 0 | if (!tmp) { |
802 | 0 | if (file->encoded_content) |
803 | 0 | free(file->encoded_content); |
804 | 0 | file->encoded_content = NULL; |
805 | 0 | file->encoded_content_len = 0; |
806 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
807 | 0 | } |
808 | | |
809 | 0 | file->encoded_content = tmp; |
810 | 0 | memcpy(file->encoded_content, content, content_len); |
811 | 0 | file->encoded_content_len = content_len; |
812 | |
|
813 | 0 | return SC_SUCCESS; |
814 | 0 | } |
815 | | |
816 | | |
817 | 0 | int sc_file_valid(const sc_file_t *file) { |
818 | 0 | if (file == NULL) |
819 | 0 | return 0; |
820 | 0 | return file->magic == SC_FILE_MAGIC; |
821 | 0 | } |
822 | | |
823 | | int _sc_parse_atr(sc_reader_t *reader) |
824 | 0 | { |
825 | 0 | u8 *p = reader->atr.value; |
826 | 0 | int atr_len = (int) reader->atr.len; |
827 | 0 | int n_hist, x; |
828 | 0 | int tx[4] = {-1, -1, -1, -1}; |
829 | 0 | int i, FI, DI; |
830 | 0 | const int Fi_table[] = { |
831 | 0 | 372, 372, 558, 744, 1116, 1488, 1860, -1, |
832 | 0 | -1, 512, 768, 1024, 1536, 2048, -1, -1 }; |
833 | 0 | const int f_table[] = { |
834 | 0 | 40, 50, 60, 80, 120, 160, 200, -1, |
835 | 0 | -1, 50, 75, 100, 150, 200, -1, -1 }; |
836 | 0 | const int Di_table[] = { |
837 | 0 | -1, 1, 2, 4, 8, 16, 32, -1, |
838 | 0 | 12, 20, -1, -1, -1, -1, -1, -1 }; |
839 | |
|
840 | 0 | reader->atr_info.hist_bytes_len = 0; |
841 | 0 | reader->atr_info.hist_bytes = NULL; |
842 | |
|
843 | 0 | if (atr_len == 0) { |
844 | 0 | sc_log(reader->ctx, "empty ATR - card not present?\n"); |
845 | 0 | return SC_ERROR_INTERNAL; |
846 | 0 | } |
847 | | |
848 | 0 | if (p[0] != 0x3B && p[0] != 0x3F) { |
849 | 0 | sc_log(reader->ctx, "invalid sync byte in ATR: 0x%02X\n", p[0]); |
850 | 0 | return SC_ERROR_INTERNAL; |
851 | 0 | } |
852 | 0 | n_hist = p[1] & 0x0F; |
853 | 0 | x = p[1] >> 4; |
854 | 0 | p += 2; |
855 | 0 | atr_len -= 2; |
856 | 0 | for (i = 0; i < 4 && atr_len > 0; i++) { |
857 | 0 | if (x & (1 << i)) { |
858 | 0 | tx[i] = *p; |
859 | 0 | p++; |
860 | 0 | atr_len--; |
861 | 0 | } else |
862 | 0 | tx[i] = -1; |
863 | 0 | } |
864 | 0 | if (tx[0] >= 0) { |
865 | 0 | reader->atr_info.FI = FI = tx[0] >> 4; |
866 | 0 | reader->atr_info.DI = DI = tx[0] & 0x0F; |
867 | 0 | reader->atr_info.Fi = Fi_table[FI]; |
868 | 0 | reader->atr_info.f = f_table[FI]; |
869 | 0 | reader->atr_info.Di = Di_table[DI]; |
870 | 0 | } else { |
871 | 0 | reader->atr_info.Fi = -1; |
872 | 0 | reader->atr_info.f = -1; |
873 | 0 | reader->atr_info.Di = -1; |
874 | 0 | } |
875 | 0 | if (tx[2] >= 0) |
876 | 0 | reader->atr_info.N = tx[3]; |
877 | 0 | else |
878 | 0 | reader->atr_info.N = -1; |
879 | 0 | while (tx[3] > 0 && tx[3] & 0xF0 && atr_len > 0) { |
880 | 0 | x = tx[3] >> 4; |
881 | 0 | for (i = 0; i < 4 && atr_len > 0; i++) { |
882 | 0 | if (x & (1 << i)) { |
883 | 0 | tx[i] = *p; |
884 | 0 | p++; |
885 | 0 | atr_len--; |
886 | 0 | } else |
887 | 0 | tx[i] = -1; |
888 | 0 | } |
889 | 0 | } |
890 | 0 | if (atr_len <= 0) |
891 | 0 | return SC_SUCCESS; |
892 | 0 | if (n_hist > atr_len) |
893 | 0 | n_hist = atr_len; |
894 | 0 | reader->atr_info.hist_bytes_len = n_hist; |
895 | 0 | reader->atr_info.hist_bytes = p; |
896 | 0 | return SC_SUCCESS; |
897 | 0 | } |
898 | | |
899 | | void *sc_mem_secure_alloc(size_t len) |
900 | 0 | { |
901 | 0 | void *p; |
902 | |
|
903 | | #ifdef _WIN32 |
904 | | p = VirtualAlloc(NULL, len, MEM_COMMIT, PAGE_READWRITE); |
905 | | if (p != NULL) { |
906 | | VirtualLock(p, len); |
907 | | } |
908 | | #else |
909 | 0 | p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
910 | 0 | if (p != NULL) { |
911 | 0 | mlock(p, len); |
912 | 0 | } |
913 | 0 | #endif |
914 | |
|
915 | 0 | return p; |
916 | 0 | } |
917 | | |
918 | | void sc_mem_secure_free(void *ptr, size_t len) |
919 | 0 | { |
920 | | #ifdef _WIN32 |
921 | | VirtualUnlock(ptr, len); |
922 | | VirtualFree(ptr, 0, MEM_RELEASE); |
923 | | #else |
924 | 0 | munlock(ptr, len); |
925 | 0 | munmap(ptr, len); |
926 | 0 | #endif |
927 | 0 | } |
928 | | |
929 | | void sc_mem_clear(void *ptr, size_t len) |
930 | 0 | { |
931 | 0 | if (len > 0) { |
932 | | #ifdef HAVE_MEMSET_S |
933 | | memset_s(ptr, len, 0, len); |
934 | | #elif _WIN32 |
935 | | SecureZeroMemory(ptr, len); |
936 | | #elif HAVE_EXPLICIT_BZERO |
937 | | explicit_bzero(ptr, len); |
938 | | #elif ENABLE_OPENSSL |
939 | | OPENSSL_cleanse(ptr, len); |
940 | | #else |
941 | | memset(ptr, 0, len); |
942 | | #endif |
943 | 0 | } |
944 | 0 | } |
945 | | |
946 | | int sc_mem_reverse(unsigned char *buf, size_t len) |
947 | 0 | { |
948 | 0 | unsigned char ch; |
949 | 0 | size_t ii; |
950 | |
|
951 | 0 | if (!buf || !len) |
952 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
953 | | |
954 | 0 | for (ii = 0; ii < len / 2; ii++) { |
955 | 0 | ch = *(buf + ii); |
956 | 0 | *(buf + ii) = *(buf + len - 1 - ii); |
957 | 0 | *(buf + len - 1 - ii) = ch; |
958 | 0 | } |
959 | |
|
960 | 0 | return SC_SUCCESS; |
961 | 0 | } |
962 | | |
963 | | static int |
964 | | sc_remote_apdu_allocate(struct sc_remote_data *rdata, |
965 | | struct sc_remote_apdu **new_rapdu) |
966 | 0 | { |
967 | 0 | struct sc_remote_apdu *rapdu = NULL, *rr; |
968 | |
|
969 | 0 | if (!rdata) |
970 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
971 | | |
972 | 0 | rapdu = calloc(1, sizeof(struct sc_remote_apdu)); |
973 | 0 | if (rapdu == NULL) |
974 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
975 | | |
976 | 0 | rapdu->apdu.data = &rapdu->sbuf[0]; |
977 | 0 | rapdu->apdu.resp = &rapdu->rbuf[0]; |
978 | 0 | rapdu->apdu.resplen = sizeof(rapdu->rbuf); |
979 | |
|
980 | 0 | if (new_rapdu) |
981 | 0 | *new_rapdu = rapdu; |
982 | |
|
983 | 0 | if (rdata->data == NULL) { |
984 | 0 | rdata->data = rapdu; |
985 | 0 | rdata->length = 1; |
986 | 0 | return SC_SUCCESS; |
987 | 0 | } |
988 | | |
989 | 0 | for (rr = rdata->data; rr->next; rr = rr->next) |
990 | 0 | ; |
991 | 0 | rr->next = rapdu; |
992 | 0 | rdata->length++; |
993 | |
|
994 | 0 | return SC_SUCCESS; |
995 | 0 | } |
996 | | |
997 | | static void |
998 | | sc_remote_apdu_free (struct sc_remote_data *rdata) |
999 | 0 | { |
1000 | 0 | struct sc_remote_apdu *rapdu = NULL; |
1001 | |
|
1002 | 0 | if (!rdata) |
1003 | 0 | return; |
1004 | | |
1005 | 0 | rapdu = rdata->data; |
1006 | 0 | while(rapdu) { |
1007 | 0 | struct sc_remote_apdu *rr = rapdu->next; |
1008 | |
|
1009 | 0 | free(rapdu); |
1010 | 0 | rapdu = rr; |
1011 | 0 | } |
1012 | 0 | } |
1013 | | |
1014 | | void sc_remote_data_init(struct sc_remote_data *rdata) |
1015 | 0 | { |
1016 | 0 | if (!rdata) |
1017 | 0 | return; |
1018 | 0 | memset(rdata, 0, sizeof(struct sc_remote_data)); |
1019 | |
|
1020 | 0 | rdata->alloc = sc_remote_apdu_allocate; |
1021 | 0 | rdata->free = sc_remote_apdu_free; |
1022 | 0 | } |
1023 | | |
1024 | | static unsigned long sc_CRC_tab32[256]; |
1025 | | static int sc_CRC_tab32_initialized = 0; |
1026 | | unsigned sc_crc32(const unsigned char *value, size_t len) |
1027 | 0 | { |
1028 | 0 | size_t ii, jj; |
1029 | 0 | unsigned long crc; |
1030 | 0 | unsigned long index, long_c; |
1031 | |
|
1032 | 0 | if (!sc_CRC_tab32_initialized) { |
1033 | 0 | for (ii=0; ii<256; ii++) { |
1034 | 0 | crc = (unsigned long) ii; |
1035 | 0 | for (jj=0; jj<8; jj++) { |
1036 | 0 | if ( crc & 0x00000001L ) |
1037 | 0 | crc = ( crc >> 1 ) ^ 0xEDB88320l; |
1038 | 0 | else |
1039 | 0 | crc = crc >> 1; |
1040 | 0 | } |
1041 | 0 | sc_CRC_tab32[ii] = crc; |
1042 | 0 | } |
1043 | 0 | sc_CRC_tab32_initialized = 1; |
1044 | 0 | } |
1045 | |
|
1046 | 0 | crc = 0xffffffffL; |
1047 | 0 | for (ii=0; ii<len; ii++) { |
1048 | 0 | long_c = 0x000000ffL & (unsigned long) (*(value + ii)); |
1049 | 0 | index = crc ^ long_c; |
1050 | 0 | crc = (crc >> 8) ^ sc_CRC_tab32[ index & 0xff ]; |
1051 | 0 | } |
1052 | |
|
1053 | 0 | crc ^= 0xffffffff; |
1054 | 0 | return crc%0xffff; |
1055 | 0 | } |
1056 | | |
1057 | | const u8 *sc_compacttlv_find_tag(const u8 *buf, size_t len, u8 tag, size_t *outlen) |
1058 | 0 | { |
1059 | 0 | if (buf != NULL) { |
1060 | 0 | size_t idx; |
1061 | 0 | u8 plain_tag = tag & 0xF0; |
1062 | 0 | size_t expected_len = tag & 0x0F; |
1063 | |
|
1064 | 0 | for (idx = 0; idx < len; idx++) { |
1065 | 0 | if ((buf[idx] & 0xF0) == plain_tag && idx + expected_len < len && |
1066 | 0 | (expected_len == 0 || expected_len == (buf[idx] & 0x0F))) { |
1067 | 0 | if (outlen != NULL) |
1068 | 0 | *outlen = buf[idx] & 0x0F; |
1069 | 0 | return buf + (idx + 1); |
1070 | 0 | } |
1071 | 0 | idx += (buf[idx] & 0x0F); |
1072 | 0 | } |
1073 | 0 | } |
1074 | 0 | return NULL; |
1075 | 0 | } |
1076 | | |
1077 | | /**************************** mutex functions ************************/ |
1078 | | |
1079 | | int sc_mutex_create(const sc_context_t *ctx, void **mutex) |
1080 | 0 | { |
1081 | 0 | if (ctx == NULL) |
1082 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1083 | 0 | if (ctx->thread_ctx != NULL && ctx->thread_ctx->create_mutex != NULL) |
1084 | 0 | return ctx->thread_ctx->create_mutex(mutex); |
1085 | 0 | else |
1086 | 0 | return SC_SUCCESS; |
1087 | 0 | } |
1088 | | |
1089 | | int sc_mutex_lock(const sc_context_t *ctx, void *mutex) |
1090 | 0 | { |
1091 | 0 | if (ctx == NULL) |
1092 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1093 | 0 | if (ctx->thread_ctx != NULL && ctx->thread_ctx->lock_mutex != NULL) |
1094 | 0 | return ctx->thread_ctx->lock_mutex(mutex); |
1095 | 0 | else |
1096 | 0 | return SC_SUCCESS; |
1097 | 0 | } |
1098 | | |
1099 | | int sc_mutex_unlock(const sc_context_t *ctx, void *mutex) |
1100 | 0 | { |
1101 | 0 | if (ctx == NULL) |
1102 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1103 | 0 | if (ctx->thread_ctx != NULL && ctx->thread_ctx->unlock_mutex != NULL) |
1104 | 0 | return ctx->thread_ctx->unlock_mutex(mutex); |
1105 | 0 | else |
1106 | 0 | return SC_SUCCESS; |
1107 | 0 | } |
1108 | | |
1109 | | int sc_mutex_destroy(const sc_context_t *ctx, void *mutex) |
1110 | 0 | { |
1111 | 0 | if (ctx == NULL) |
1112 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1113 | 0 | if (ctx->thread_ctx != NULL && ctx->thread_ctx->destroy_mutex != NULL) |
1114 | 0 | return ctx->thread_ctx->destroy_mutex(mutex); |
1115 | 0 | else |
1116 | 0 | return SC_SUCCESS; |
1117 | 0 | } |
1118 | | |
1119 | | unsigned long sc_thread_id(const sc_context_t *ctx) |
1120 | 0 | { |
1121 | 0 | if (ctx == NULL || ctx->thread_ctx == NULL || |
1122 | 0 | ctx->thread_ctx->thread_id == NULL) |
1123 | 0 | return 0UL; |
1124 | 0 | else |
1125 | 0 | return ctx->thread_ctx->thread_id(); |
1126 | 0 | } |
1127 | | |
1128 | | void sc_free(void *p) |
1129 | 0 | { |
1130 | 0 | free(p); |
1131 | 0 | } |