Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20141024' into...
[qemu.git] / libcacard / vreader.c
blob0315dd89201cfe775ca5f1bf9e0acf947b1cdd50
1 /*
2 * emulate the reader
4 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
5 * See the COPYING.LIB file in the top-level directory.
6 */
8 #ifdef G_LOG_DOMAIN
9 #undef G_LOG_DOMAIN
10 #endif
11 #define G_LOG_DOMAIN "libcacard"
13 #include "qemu-common.h"
15 #include "vcard.h"
16 #include "vcard_emul.h"
17 #include "card_7816.h"
18 #include "vreader.h"
19 #include "vevent.h"
20 #include "cac.h" /* just for debugging defines */
22 #define LIBCACARD_LOG_DOMAIN "libcacard"
24 struct VReaderStruct {
25 int reference_count;
26 VCard *card;
27 char *name;
28 vreader_id_t id;
29 CompatGMutex lock;
30 VReaderEmul *reader_private;
31 VReaderEmulFree reader_private_free;
35 * Debug helpers
38 static const char *
39 apdu_ins_to_string(int ins)
41 switch (ins) {
42 case VCARD7816_INS_MANAGE_CHANNEL:
43 return "manage channel";
44 case VCARD7816_INS_EXTERNAL_AUTHENTICATE:
45 return "external authenticate";
46 case VCARD7816_INS_GET_CHALLENGE:
47 return "get challenge";
48 case VCARD7816_INS_INTERNAL_AUTHENTICATE:
49 return "internal authenticate";
50 case VCARD7816_INS_ERASE_BINARY:
51 return "erase binary";
52 case VCARD7816_INS_READ_BINARY:
53 return "read binary";
54 case VCARD7816_INS_WRITE_BINARY:
55 return "write binary";
56 case VCARD7816_INS_UPDATE_BINARY:
57 return "update binary";
58 case VCARD7816_INS_READ_RECORD:
59 return "read record";
60 case VCARD7816_INS_WRITE_RECORD:
61 return "write record";
62 case VCARD7816_INS_UPDATE_RECORD:
63 return "update record";
64 case VCARD7816_INS_APPEND_RECORD:
65 return "append record";
66 case VCARD7816_INS_ENVELOPE:
67 return "envelope";
68 case VCARD7816_INS_PUT_DATA:
69 return "put data";
70 case VCARD7816_INS_GET_DATA:
71 return "get data";
72 case VCARD7816_INS_SELECT_FILE:
73 return "select file";
74 case VCARD7816_INS_VERIFY:
75 return "verify";
76 case VCARD7816_INS_GET_RESPONSE:
77 return "get response";
78 case CAC_GET_PROPERTIES:
79 return "get properties";
80 case CAC_GET_ACR:
81 return "get acr";
82 case CAC_READ_BUFFER:
83 return "read buffer";
84 case CAC_UPDATE_BUFFER:
85 return "update buffer";
86 case CAC_SIGN_DECRYPT:
87 return "sign decrypt";
88 case CAC_GET_CERTIFICATE:
89 return "get certificate";
91 return "unknown";
94 /* manage locking */
95 static inline void
96 vreader_lock(VReader *reader)
98 g_mutex_lock(&reader->lock);
101 static inline void
102 vreader_unlock(VReader *reader)
104 g_mutex_unlock(&reader->lock);
108 * vreader constructor
110 VReader *
111 vreader_new(const char *name, VReaderEmul *private,
112 VReaderEmulFree private_free)
114 VReader *reader;
116 reader = g_new(VReader, 1);
117 g_mutex_init(&reader->lock);
118 reader->reference_count = 1;
119 reader->name = g_strdup(name);
120 reader->card = NULL;
121 reader->id = (vreader_id_t)-1;
122 reader->reader_private = private;
123 reader->reader_private_free = private_free;
124 return reader;
127 /* get a reference */
128 VReader*
129 vreader_reference(VReader *reader)
131 if (reader == NULL) {
132 return NULL;
134 vreader_lock(reader);
135 reader->reference_count++;
136 vreader_unlock(reader);
137 return reader;
140 /* free a reference */
141 void
142 vreader_free(VReader *reader)
144 if (reader == NULL) {
145 return;
147 vreader_lock(reader);
148 if (reader->reference_count-- > 1) {
149 vreader_unlock(reader);
150 return;
152 vreader_unlock(reader);
153 g_mutex_clear(&reader->lock);
154 if (reader->card) {
155 vcard_free(reader->card);
157 g_free(reader->name);
158 if (reader->reader_private_free) {
159 reader->reader_private_free(reader->reader_private);
161 g_free(reader);
164 static VCard *
165 vreader_get_card(VReader *reader)
167 VCard *card;
169 vreader_lock(reader);
170 card = vcard_reference(reader->card);
171 vreader_unlock(reader);
172 return card;
175 VReaderStatus
176 vreader_card_is_present(VReader *reader)
178 VCard *card = vreader_get_card(reader);
180 if (card == NULL) {
181 return VREADER_NO_CARD;
183 vcard_free(card);
184 return VREADER_OK;
187 vreader_id_t
188 vreader_get_id(VReader *reader)
190 if (reader == NULL) {
191 return (vreader_id_t)-1;
193 return reader->id;
196 VReaderStatus
197 vreader_set_id(VReader *reader, vreader_id_t id)
199 if (reader == NULL) {
200 return VREADER_NO_CARD;
202 reader->id = id;
203 return VREADER_OK;
206 const char *
207 vreader_get_name(VReader *reader)
209 if (reader == NULL) {
210 return NULL;
212 return reader->name;
215 VReaderEmul *
216 vreader_get_private(VReader *reader)
218 return reader->reader_private;
221 static VReaderStatus
222 vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len)
224 VCard *card = vreader_get_card(reader);
226 if (card == NULL) {
227 return VREADER_NO_CARD;
230 * clean up our state
232 vcard_reset(card, power);
233 if (atr) {
234 vcard_get_atr(card, atr, len);
236 vcard_free(card); /* free our reference */
237 return VREADER_OK;
240 VReaderStatus
241 vreader_power_on(VReader *reader, unsigned char *atr, int *len)
243 return vreader_reset(reader, VCARD_POWER_ON, atr, len);
246 VReaderStatus
247 vreader_power_off(VReader *reader)
249 return vreader_reset(reader, VCARD_POWER_OFF, NULL, 0);
253 VReaderStatus
254 vreader_xfr_bytes(VReader *reader,
255 unsigned char *send_buf, int send_buf_len,
256 unsigned char *receive_buf, int *receive_buf_len)
258 VCardAPDU *apdu;
259 VCardResponse *response = NULL;
260 VCardStatus card_status;
261 unsigned short status;
262 VCard *card = vreader_get_card(reader);
264 if (card == NULL) {
265 return VREADER_NO_CARD;
268 apdu = vcard_apdu_new(send_buf, send_buf_len, &status);
269 if (apdu == NULL) {
270 response = vcard_make_response(status);
271 card_status = VCARD_DONE;
272 } else {
273 g_debug("%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s",
274 __func__, apdu->a_cla, apdu->a_ins, apdu->a_p1, apdu->a_p2,
275 apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->a_ins));
276 card_status = vcard_process_apdu(card, apdu, &response);
277 if (response) {
278 g_debug("%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)",
279 __func__, response->b_status, response->b_sw1,
280 response->b_sw2, response->b_len, response->b_total_len);
283 assert(card_status == VCARD_DONE && response);
284 int size = MIN(*receive_buf_len, response->b_total_len);
285 memcpy(receive_buf, response->b_data, size);
286 *receive_buf_len = size;
287 vcard_response_delete(response);
288 vcard_apdu_delete(apdu);
289 vcard_free(card); /* free our reference */
290 return VREADER_OK;
293 struct VReaderListStruct {
294 VReaderListEntry *head;
295 VReaderListEntry *tail;
298 struct VReaderListEntryStruct {
299 VReaderListEntry *next;
300 VReaderListEntry *prev;
301 VReader *reader;
305 static VReaderListEntry *
306 vreader_list_entry_new(VReader *reader)
308 VReaderListEntry *new_reader_list_entry;
310 new_reader_list_entry = g_new0(VReaderListEntry, 1);
311 new_reader_list_entry->reader = vreader_reference(reader);
312 return new_reader_list_entry;
315 static void
316 vreader_list_entry_delete(VReaderListEntry *entry)
318 if (entry == NULL) {
319 return;
321 vreader_free(entry->reader);
322 g_free(entry);
326 static VReaderList *
327 vreader_list_new(void)
329 VReaderList *new_reader_list;
331 new_reader_list = g_new0(VReaderList, 1);
332 return new_reader_list;
335 void
336 vreader_list_delete(VReaderList *list)
338 VReaderListEntry *current_entry;
339 VReaderListEntry *next_entry;
340 for (current_entry = vreader_list_get_first(list); current_entry;
341 current_entry = next_entry) {
342 next_entry = vreader_list_get_next(current_entry);
343 vreader_list_entry_delete(current_entry);
345 g_free(list);
349 VReaderListEntry *
350 vreader_list_get_first(VReaderList *list)
352 return list ? list->head : NULL;
355 VReaderListEntry *
356 vreader_list_get_next(VReaderListEntry *current)
358 return current ? current->next : NULL;
361 VReader *
362 vreader_list_get_reader(VReaderListEntry *entry)
364 return entry ? vreader_reference(entry->reader) : NULL;
367 static void
368 vreader_queue(VReaderList *list, VReaderListEntry *entry)
370 if (entry == NULL) {
371 return;
373 entry->next = NULL;
374 entry->prev = list->tail;
375 if (list->head) {
376 list->tail->next = entry;
377 } else {
378 list->head = entry;
380 list->tail = entry;
383 static void
384 vreader_dequeue(VReaderList *list, VReaderListEntry *entry)
386 if (entry == NULL) {
387 return;
389 if (entry->next == NULL) {
390 list->tail = entry->prev;
391 } else if (entry->prev == NULL) {
392 list->head = entry->next;
393 } else {
394 entry->prev->next = entry->next;
395 entry->next->prev = entry->prev;
397 if ((list->tail == NULL) || (list->head == NULL)) {
398 list->head = list->tail = NULL;
400 entry->next = entry->prev = NULL;
403 static VReaderList *vreader_list;
404 static CompatGMutex vreader_list_mutex;
406 static void
407 vreader_list_init(void)
409 vreader_list = vreader_list_new();
412 static void
413 vreader_list_lock(void)
415 g_mutex_lock(&vreader_list_mutex);
418 static void
419 vreader_list_unlock(void)
421 g_mutex_unlock(&vreader_list_mutex);
424 static VReaderList *
425 vreader_copy_list(VReaderList *list)
427 VReaderList *new_list;
428 VReaderListEntry *current_entry;
430 new_list = vreader_list_new();
431 if (new_list == NULL) {
432 return NULL;
434 for (current_entry = vreader_list_get_first(list); current_entry;
435 current_entry = vreader_list_get_next(current_entry)) {
436 VReader *reader = vreader_list_get_reader(current_entry);
437 VReaderListEntry *new_entry = vreader_list_entry_new(reader);
439 vreader_free(reader);
440 vreader_queue(new_list, new_entry);
442 return new_list;
445 VReaderList *
446 vreader_get_reader_list(void)
448 VReaderList *new_reader_list;
450 vreader_list_lock();
451 new_reader_list = vreader_copy_list(vreader_list);
452 vreader_list_unlock();
453 return new_reader_list;
456 VReader *
457 vreader_get_reader_by_id(vreader_id_t id)
459 VReader *reader = NULL;
460 VReaderListEntry *current_entry;
462 if (id == (vreader_id_t) -1) {
463 return NULL;
466 vreader_list_lock();
467 for (current_entry = vreader_list_get_first(vreader_list); current_entry;
468 current_entry = vreader_list_get_next(current_entry)) {
469 VReader *creader = vreader_list_get_reader(current_entry);
470 if (creader->id == id) {
471 reader = creader;
472 break;
474 vreader_free(creader);
476 vreader_list_unlock();
477 return reader;
480 VReader *
481 vreader_get_reader_by_name(const char *name)
483 VReader *reader = NULL;
484 VReaderListEntry *current_entry;
486 vreader_list_lock();
487 for (current_entry = vreader_list_get_first(vreader_list); current_entry;
488 current_entry = vreader_list_get_next(current_entry)) {
489 VReader *creader = vreader_list_get_reader(current_entry);
490 if (strcmp(creader->name, name) == 0) {
491 reader = creader;
492 break;
494 vreader_free(creader);
496 vreader_list_unlock();
497 return reader;
500 /* called from card_emul to initialize the readers */
501 VReaderStatus
502 vreader_add_reader(VReader *reader)
504 VReaderListEntry *reader_entry;
506 reader_entry = vreader_list_entry_new(reader);
507 if (reader_entry == NULL) {
508 return VREADER_OUT_OF_MEMORY;
510 vreader_list_lock();
511 vreader_queue(vreader_list, reader_entry);
512 vreader_list_unlock();
513 vevent_queue_vevent(vevent_new(VEVENT_READER_INSERT, reader, NULL));
514 return VREADER_OK;
518 VReaderStatus
519 vreader_remove_reader(VReader *reader)
521 VReaderListEntry *current_entry;
523 vreader_list_lock();
524 for (current_entry = vreader_list_get_first(vreader_list); current_entry;
525 current_entry = vreader_list_get_next(current_entry)) {
526 if (current_entry->reader == reader) {
527 break;
530 vreader_dequeue(vreader_list, current_entry);
531 vreader_list_unlock();
532 vreader_list_entry_delete(current_entry);
533 vevent_queue_vevent(vevent_new(VEVENT_READER_REMOVE, reader, NULL));
534 return VREADER_OK;
538 * Generate VEVENT_CARD_INSERT or VEVENT_CARD_REMOVE based on vreader
539 * state. Separated from vreader_insert_card to allow replaying events
540 * for a given state.
542 void
543 vreader_queue_card_event(VReader *reader)
545 vevent_queue_vevent(vevent_new(
546 reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader,
547 reader->card));
551 * insert/remove a new card. for removal, card == NULL
553 VReaderStatus
554 vreader_insert_card(VReader *reader, VCard *card)
556 vreader_lock(reader);
557 if (reader->card) {
558 /* decrement reference count */
559 vcard_free(reader->card);
560 reader->card = NULL;
562 reader->card = vcard_reference(card);
563 vreader_unlock(reader);
564 vreader_queue_card_event(reader);
565 return VREADER_OK;
569 * initialize all the static reader structures
571 void
572 vreader_init(void)
574 vreader_list_init();