1 
2 
LC_Client_AddCardTypesByAtr(LC_CLIENT * cl,LC_CARD * card)3 int LC_Client_AddCardTypesByAtr(LC_CLIENT *cl, LC_CARD *card){
4   GWEN_XMLNODE *cardNode;
5   const unsigned char *atr;
6   unsigned int atrLen;
7   GWEN_BUFFER *hexAtr;
8   int types=0;
9   int done;
10 
11   DBG_DEBUG(0, "Adding card types...");
12 
13   /* get ATR, convert it to hex */
14   atrLen=LC_Card_GetAtr(card, &atr);
15   if (atr==0 || atrLen==0) {
16     DBG_INFO(0, "No ATR");
17     return 1;
18   }
19   hexAtr=GWEN_Buffer_new(0, 256, 0, 1);
20   if (GWEN_Text_ToHexBuffer((const char*)atr, atrLen, hexAtr, 0, 0, 0)) {
21     DBG_ERROR(LC_LOGDOMAIN, "Internal error");
22     abort();
23   }
24 
25   cardNode=GWEN_XMLNode_FindFirstTag(cl->cardNodes, "card", 0, 0);
26   if (!cardNode) {
27     DBG_ERROR(LC_LOGDOMAIN, "No card nodes.");
28     return -1;
29   }
30   while(cardNode) {
31     const char *name;
32     const char *tp;
33     const char *xtp;
34     int sameBaseType=0;
35 
36     name=GWEN_XMLNode_GetProperty(cardNode, "name", 0);
37     assert(name);
38     tp=GWEN_XMLNode_GetProperty(cardNode, "type", 0);
39 
40     DBG_VERBOUS(LC_LOGDOMAIN, "Checking card \"%s\"", name);
41     xtp=LC_Card_GetCardType(card);
42     sameBaseType=(tp && xtp && strcasecmp(tp, xtp)==0);
43     if (sameBaseType) {
44       GWEN_XMLNODE *nAtrs;
45 
46       nAtrs=GWEN_XMLNode_FindFirstTag(cardNode, "cardinfo", 0, 0);
47       if (nAtrs)
48         nAtrs=GWEN_XMLNode_FindFirstTag(nAtrs, "atrs", 0, 0);
49       if (nAtrs) {
50         GWEN_XMLNODE *nAtr;
51 
52         nAtr=GWEN_XMLNode_GetFirstTag(nAtrs);
53         while(nAtr) {
54           GWEN_XMLNODE *nData;
55 
56           nData=GWEN_XMLNode_GetFirstData(nAtr);
57           if (nData) {
58             const char *p;
59 
60             p=GWEN_XMLNode_GetData(nData);
61             if (p) {
62               GWEN_BUFFER *dbuf;
63 
64               /* compress ATR from XML file */
65               dbuf=GWEN_Buffer_new(0, 256, 0, 1);
66               while(*p) {
67                 if (!isspace(*p))
68                   GWEN_Buffer_AppendByte(dbuf, *p);
69                 p++;
70               } /* while */
71               if (-1!=GWEN_Text_ComparePattern(GWEN_Buffer_GetStart(hexAtr),
72                                                GWEN_Buffer_GetStart(dbuf),
73                                                0)) {
74                 DBG_DEBUG(LC_LOGDOMAIN, "Card \"%s\" matches ATR", name);
75                 if (LC_Card_AddCardType(card, name)) {
76                   DBG_INFO(LC_LOGDOMAIN, "Added card type \"%s\"", name);
77                   types++;
78                 }
79               }
80               GWEN_Buffer_free(dbuf);
81             } /* if data */
82           } /* if data node */
83           nAtr=GWEN_XMLNode_GetNextTag(nAtr);
84         } /* while */
85       } /* if atrs */
86     } /* if sameBaseType */
87     cardNode=GWEN_XMLNode_FindNextTag(cardNode, "card", 0, 0);
88   } /* while */
89   GWEN_Buffer_free(hexAtr);
90 
91   /* add all cards whose base types are contained in the list.
92    * repeat this as long as we added cards */
93   done=0;
94   while(!done) {
95     done=1;
96     cardNode=GWEN_XMLNode_FindFirstTag(cl->cardNodes, "card", 0, 0);
97     while(cardNode) {
98       const char *name;
99       const char *extends;
100 
101       name=GWEN_XMLNode_GetProperty(cardNode, "name", 0);
102       assert(name);
103       extends=GWEN_XMLNode_GetProperty(cardNode, "extends", 0);
104       if (extends) {
105         if (GWEN_StringList_HasString(LC_Card_GetCardTypes(card), extends)) {
106           if (LC_Card_AddCardType(card, name)) {
107             DBG_INFO(LC_LOGDOMAIN, "Added card type \"%s\"", name);
108             types++;
109             done=0;
110           }
111         }
112       }
113       cardNode=GWEN_XMLNode_FindNextTag(cardNode, "card", 0, 0);
114     }
115   } /* while */
116 
117   return (types!=0)?0:1;
118 }
119 
120 
121 
LC_Client__FindCommandInCardNode(GWEN_XMLNODE * node,const char * commandName,const char * driverType,const char * readerType)122 GWEN_XMLNODE *LC_Client__FindCommandInCardNode(GWEN_XMLNODE *node,
123                                                const char *commandName,
124                                                const char *driverType,
125                                                const char *readerType){
126   GWEN_XMLNODE *cmds;
127   GWEN_XMLNODE *n;
128 
129   DBG_INFO(LC_LOGDOMAIN,
130            "Searching in \"%s\" (%s/%s)",
131            GWEN_XMLNode_GetProperty(node, "name", "(noname)"),
132            driverType?driverType:"(none)",
133            readerType?readerType:"(none)");
134 
135   cmds=GWEN_XMLNode_FindNode(node,
136                              GWEN_XMLNodeTypeTag,
137                              "commands");
138   if (!cmds) {
139     DBG_INFO(LC_LOGDOMAIN, "No commands in card data");
140     return 0;
141   }
142 
143   /* first try exact match */
144   if (driverType && readerType) {
145     DBG_DEBUG(LC_LOGDOMAIN, "Searching for %s/%s/%s",
146               driverType, readerType, commandName);
147     n=GWEN_XMLNode_FindFirstTag(cmds,
148                                 "command",
149                                 "name",
150                                 commandName);
151     while(n) {
152       if (strcasecmp(GWEN_XMLNode_GetProperty(n, "driver", ""),
153                      driverType)==0 &&
154           strcasecmp(GWEN_XMLNode_GetProperty(n, "reader", ""),
155                      readerType)==0) {
156         DBG_DEBUG(LC_LOGDOMAIN,
157                   "Found command in %s/%s", driverType, readerType);
158         return n;
159       }
160       n=GWEN_XMLNode_FindNextTag(n, "command", "name", commandName);
161     } /* while */
162   }
163 
164   if (driverType) {
165     /* try match of driver only */
166     DBG_DEBUG(LC_LOGDOMAIN, "Searching for %s/%s",
167               driverType, commandName);
168     n=GWEN_XMLNode_FindFirstTag(cmds,
169                                 "command",
170                                 "name",
171                                 commandName);
172     while(n) {
173       if (strcasecmp(GWEN_XMLNode_GetProperty(n, "driver", ""),
174                      driverType)==0) {
175         DBG_DEBUG(LC_LOGDOMAIN, "Found command in %s", driverType);
176         return n;
177       }
178       n=GWEN_XMLNode_FindNextTag(n, "command", "name", commandName);
179     } /* while */
180   }
181 
182   /* try match of command name only */
183   DBG_DEBUG(LC_LOGDOMAIN, "Searching for %s", commandName);
184   n=GWEN_XMLNode_FindFirstTag(cmds,
185                               "command",
186                               "name",
187                               commandName);
188   while(n) {
189     if (!GWEN_XMLNode_GetProperty(n, "driver", 0))
190       return n;
191     n=GWEN_XMLNode_FindNextTag(n, "command", "name", commandName);
192   } /* while */
193 
194   return n;
195 }
196 
197 
198 
LC_Client_FindCommandInCardNode(GWEN_XMLNODE * node,const char * commandName,const char * driverType,const char * readerType)199 GWEN_XMLNODE *LC_Client_FindCommandInCardNode(GWEN_XMLNODE *node,
200                                               const char *commandName,
201                                               const char *driverType,
202                                               const char *readerType) {
203   GWEN_XMLNODE *n;
204 
205   n=LC_Client__FindCommandInCardNode(node, commandName,
206                                      driverType, readerType);
207   if (n==0)
208     n=LC_Client__FindCommandInCardNode(node, commandName,
209                                        driverType, 0);
210   if (n==0)
211     n=LC_Client__FindCommandInCardNode(node, commandName,
212                                        0, 0);
213 
214   return n;
215 }
216 
217 
218 
LC_Client_FindCommandInCardFamily(GWEN_XMLNODE * cardNodes,GWEN_STRINGLIST * handled,const char * cardType,const char * commandName,const char * driverType,const char * readerType)219 GWEN_XMLNODE *LC_Client_FindCommandInCardFamily(GWEN_XMLNODE *cardNodes,
220                                                 GWEN_STRINGLIST *handled,
221                                                 const char *cardType,
222                                                 const char *commandName,
223                                                 const char *driverType,
224                                                 const char *readerType){
225   GWEN_XMLNODE *node;
226 
227   DBG_DEBUG(LC_LOGDOMAIN, "Searching in family of \"%s\"", cardType);
228   node=GWEN_XMLNode_FindFirstTag(cardNodes, "card", "name", cardType);
229   if (node) {
230     while(node) {
231       GWEN_XMLNODE *n;
232       const char *parent;
233 
234       cardType=GWEN_XMLNode_GetProperty(node, "name", 0);
235       assert(cardType);
236       DBG_VERBOUS(LC_LOGDOMAIN, "Searching in \"%s\" (%s/%s)",
237                   GWEN_XMLNode_GetProperty(node, "name", "(noname)"),
238                   driverType?driverType:"(none)",
239                   readerType?readerType:"(none)");
240       if (!GWEN_StringList_HasString(handled, cardType)) {
241         n=LC_Client_FindCommandInCardNode(node, commandName,
242                                           driverType, readerType);
243         GWEN_StringList_AppendString(handled, cardType, 0, 1);
244         if (n) {
245           return n;
246         }
247       }
248       else {
249         DBG_INFO(LC_LOGDOMAIN, "Card type \"%s\" already handled",
250                  cardType);
251       }
252 
253       /* search in parents */
254       parent=GWEN_XMLNode_GetProperty(node, "extends", 0);
255       if (!parent) {
256         DBG_VERBOUS(LC_LOGDOMAIN, "Card type \"%s\" has no parent",
257                     GWEN_XMLNode_GetProperty(node, "name", "(noname)"));
258         break;
259       }
260       DBG_DEBUG(LC_LOGDOMAIN, "Searching for extended card \"%s\"", parent);
261       node=GWEN_XMLNode_FindFirstTag(cardNodes,
262                                      "card",
263                                      "name",
264                                      parent);
265       if (!node) {
266         DBG_WARN(LC_LOGDOMAIN,
267                  "Extended card \"%s\" not found",
268                  parent);
269         break;
270       }
271       DBG_DEBUG(LC_LOGDOMAIN, "Searching in parent \"%s\"", parent);
272     } /* while */
273   }
274   else {
275     DBG_INFO(LC_LOGDOMAIN, "Card \"%s\" not found", cardType);
276   }
277   DBG_DEBUG(0, "Command \"%s\" not found", commandName);
278   return 0;
279 }
280 
281 
282 
283 GWEN_XMLNODE*
LC_Client_FindCommandInCardTypes(GWEN_XMLNODE * cardNodes,const GWEN_STRINGLIST * cardTypes,const char * commandName,const char * driverType,const char * readerType)284 LC_Client_FindCommandInCardTypes(GWEN_XMLNODE *cardNodes,
285                                  const GWEN_STRINGLIST *cardTypes,
286                                  const char *commandName,
287                                  const char *driverType,
288                                  const char *readerType){
289   GWEN_STRINGLIST *handled;
290   GWEN_STRINGLISTENTRY *se;
291   GWEN_XMLNODE *node=0;
292 
293   handled=GWEN_StringList_new();
294   se=GWEN_StringList_FirstEntry(cardTypes);
295   while(se) {
296     const char *s;
297 
298     s=GWEN_StringListEntry_Data(se);
299     assert(s);
300 
301     DBG_INFO(LC_LOGDOMAIN,
302              "Searching in card type \"%s\"", s);
303     node=LC_Client_FindCommandInCardFamily(cardNodes,
304                                            handled,
305                                            s,
306                                            commandName,
307                                            driverType,
308                                            readerType);
309     if (node)
310       break;
311     se=GWEN_StringListEntry_Next(se);
312   } /* while */
313 
314   return node;
315 }
316 
317 
318 
LC_Client_FindCardCommand(LC_CLIENT * cl,LC_CARD * card,const char * commandName)319 GWEN_XMLNODE *LC_Client_FindCardCommand(LC_CLIENT *cl,
320                                         LC_CARD *card,
321                                         const char *commandName) {
322   GWEN_XMLNODE *n;
323 
324   n=LC_Card_GetCardNode(card);
325   if (n) {
326     const char *cardName;
327     GWEN_STRINGLIST *sl;
328 
329     cardName=GWEN_XMLNode_GetProperty(n, "name", 0);
330     assert(cardName);
331     DBG_INFO(LC_LOGDOMAIN, "Preselected card type \"%s\"", cardName);
332 
333     sl=GWEN_StringList_new();
334     n=LC_Client_FindCommandInCardFamily(cl->cardNodes,
335                                         sl,
336                                         cardName,
337                                         commandName,
338                                         LC_Card_GetDriverType(card),
339                                         LC_Card_GetReaderType(card));
340     GWEN_StringList_free(sl);
341     if (n)
342       return n;
343     return 0;
344   }
345   return LC_Client_FindCommandInCardTypes(cl->cardNodes,
346                                           LC_Card_GetCardTypes(card),
347                                           commandName,
348                                           LC_Card_GetDriverType(card),
349                                           LC_Card_GetReaderType(card));
350 }
351 
352 
353 
LC_Client_FindResultInNode(GWEN_XMLNODE * node,int sw1,int sw2)354 GWEN_XMLNODE *LC_Client_FindResultInNode(GWEN_XMLNODE *node,
355                                          int sw1, int sw2) {
356   GWEN_XMLNODE *rnode;
357   GWEN_XMLNODE *n;
358   int lsw1, lsw2;
359 
360   DBG_DEBUG(0, "Searching for result type of %02x/%02x", sw1, sw2);
361   while(node) {
362     rnode=GWEN_XMLNode_FindNode(node,
363                                 GWEN_XMLNodeTypeTag,
364                                 "results");
365     if (rnode) {
366       /* first try exact match */
367       n=GWEN_XMLNode_GetFirstTag(rnode);
368       while(n) {
369         if (1==sscanf(GWEN_XMLNode_GetProperty(n, "sw1", "-1"),
370                       "%i", &lsw1) &&
371             1==sscanf(GWEN_XMLNode_GetProperty(n, "sw2", "-1"),
372                       "%i", &lsw2)) {
373           DBG_VERBOUS(0, "Checking %02x/%02x", lsw1, lsw2);
374           if (lsw1==sw1 && lsw2==sw2) {
375             return n;
376           }
377         }
378         else {
379           DBG_WARN(0, "Bad SW1 or SW2 value");
380         }
381         n=GWEN_XMLNode_GetNextTag(n);
382       } /* while */
383 
384       /* try SW1 only */
385       n=GWEN_XMLNode_GetFirstTag(rnode);
386       while(n) {
387         if (1==sscanf(GWEN_XMLNode_GetProperty(n, "sw1", "-1"),
388                       "%i", &lsw1) &&
389             1==sscanf(GWEN_XMLNode_GetProperty(n, "sw2", "-1"),
390                       "%i", &lsw2)) {
391           if (lsw1==sw1 && lsw2==-1) {
392             return n;
393           }
394         }
395         else {
396           DBG_WARN(0, "Bad SW1 or SW2 value");
397         }
398         n=GWEN_XMLNode_GetNextTag(n);
399       } /* while */
400     } /* if rnode */
401 
402     /* select parent */
403     node=GWEN_XMLNode_GetParent(node);
404   }
405 
406   return 0;
407 }
408 
409 
410 
LC_Client_FindResult(LC_CLIENT * cl,GWEN_XMLNODE * cmdNode,int sw1,int sw2)411 GWEN_XMLNODE *LC_Client_FindResult(LC_CLIENT *cl,
412                                    GWEN_XMLNODE *cmdNode,
413                                    int sw1, int sw2) {
414   GWEN_XMLNODE *tmpNode;
415   GWEN_XMLNODE *rnode;
416 
417   /* first find result in command node */
418   rnode=LC_Client_FindResultInNode(cmdNode, sw1, sw2);
419   if (rnode)
420     return rnode;
421   rnode=LC_Client_FindResultInNode(cmdNode, -1, -1);
422   if (rnode)
423     return rnode;
424 
425   /* try in node <commands> */
426   tmpNode=GWEN_XMLNode_GetParent(cmdNode);
427   if (!tmpNode)
428     return 0;
429   rnode=LC_Client_FindResultInNode(tmpNode, sw1, sw2);
430   if (rnode)
431     return rnode;
432   rnode=LC_Client_FindResultInNode(tmpNode, -1, -1);
433   if (rnode)
434     return rnode;
435 
436   /* try in current card node */
437   tmpNode=GWEN_XMLNode_GetParent(tmpNode);
438   if (!tmpNode)
439     return 0;
440   rnode=LC_Client_FindResultInNode(tmpNode, sw1, sw2);
441   if (rnode)
442     return rnode;
443   rnode=LC_Client_FindResultInNode(tmpNode, -1, -1);
444   if (rnode)
445     return rnode;
446 
447   /* try in parents */
448   for(;;) {
449     const char *parent;
450 
451     parent=GWEN_XMLNode_GetProperty(tmpNode, "extends", 0);
452     if (!parent) {
453       break;
454     }
455     tmpNode=GWEN_XMLNode_FindFirstTag(cl->cardNodes,
456                                       "card",
457                                       "name",
458                                       parent);
459     if (!tmpNode)
460       break;
461 
462     rnode=LC_Client_FindResultInNode(tmpNode, sw1, sw2);
463     if (rnode) {
464       break;
465     }
466     rnode=LC_Client_FindResultInNode(tmpNode, -1, -1);
467     if (rnode) {
468       break;
469     }
470   } /* for */
471 
472   return rnode;
473 }
474 
475 
476 
LC_Client_FindResponseInNode(GWEN_XMLNODE * cmd,const char * typ)477 GWEN_XMLNODE *LC_Client_FindResponseInNode(GWEN_XMLNODE *cmd,
478                                            const char *typ) {
479   GWEN_XMLNODE *rnode;
480   GWEN_XMLNODE *n;
481   const char *ltyp;
482 
483   DBG_DEBUG(0, "Searching for response type \"%s\"", typ);
484   rnode=GWEN_XMLNode_FindNode(cmd,
485                               GWEN_XMLNodeTypeTag,
486                               "responses");
487   if (!rnode) {
488     DBG_DEBUG(0, "No <responses> tag in command definition");
489     return 0;
490   }
491 
492   /* first try exact match */
493   n=GWEN_XMLNode_GetFirstTag(rnode);
494   while(n) {
495     ltyp=GWEN_XMLNode_GetProperty(n, "type", 0);
496     if (ltyp) {
497       if (strcasecmp(ltyp, typ)==0)
498         return n;
499     }
500     n=GWEN_XMLNode_GetNextTag(n);
501   } /* while */
502 
503   /* then try a response without any type */
504   n=GWEN_XMLNode_GetFirstTag(rnode);
505   while(n) {
506     ltyp=GWEN_XMLNode_GetProperty(n, "type", 0);
507     if (!ltyp)
508       return n;
509     n=GWEN_XMLNode_GetNextTag(n);
510   } /* while */
511 
512   return 0;
513 }
514 
515 
516 
LC_Client_FindResponse(LC_CLIENT * cl,GWEN_XMLNODE * cmdNode,const char * typ)517 GWEN_XMLNODE *LC_Client_FindResponse(LC_CLIENT *cl,
518                                      GWEN_XMLNODE *cmdNode,
519                                      const char *typ) {
520   GWEN_XMLNODE *tmpNode;
521   GWEN_XMLNODE *rnode;
522 
523   /* first find response in command node */
524   rnode=LC_Client_FindResponseInNode(cmdNode, typ);
525   if (rnode)
526     return rnode;
527 
528   /* try in node <commands> */
529   tmpNode=GWEN_XMLNode_GetParent(cmdNode);
530   if (!tmpNode)
531     return 0;
532   rnode=LC_Client_FindResponseInNode(tmpNode, typ);
533   if (rnode)
534     return rnode;
535 
536   /* try in current card node */
537   tmpNode=GWEN_XMLNode_GetParent(tmpNode);
538   if (!tmpNode)
539     return 0;
540   rnode=LC_Client_FindResponseInNode(tmpNode, typ);
541   if (rnode)
542     return rnode;
543 
544   /* try in parents */
545   for(;;) {
546     const char *parent;
547 
548     parent=GWEN_XMLNode_GetProperty(tmpNode, "extends", 0);
549     if (!parent) {
550       break;
551     }
552     tmpNode=GWEN_XMLNode_FindFirstTag(cl->cardNodes,
553                                       "card",
554                                       "name",
555                                       parent);
556     if (!tmpNode)
557       break;
558 
559     rnode=LC_Client_FindResponseInNode(tmpNode, typ);
560     if (rnode) {
561       break;
562     }
563   } /* for */
564 
565   return rnode;
566 }
567 
568 
569 
LC_Client__BuildApdu(LC_CLIENT * cl,GWEN_XMLNODE * node,GWEN_DB_NODE * cmdData,GWEN_BUFFER * gbuf)570 LC_CLIENT_RESULT LC_Client__BuildApdu(LC_CLIENT *cl,
571 				      GWEN_XMLNODE *node,
572 				      GWEN_DB_NODE *cmdData,
573 				      GWEN_BUFFER *gbuf) {
574   GWEN_XMLNODE *sendNode;
575   GWEN_XMLNODE *dataNode;
576   GWEN_XMLNODE *apduNode;
577   GWEN_BUFFER *dataBuffer;
578   unsigned int i;
579   int j;
580 
581   assert(cl);
582 
583   sendNode=GWEN_XMLNode_FindNode(node, GWEN_XMLNodeTypeTag, "send");
584   if (!sendNode) {
585     DBG_INFO(LC_LOGDOMAIN,
586 	     "No <send> tag in command definition, do not execute");
587     return LC_Client_ResultDontExecute;
588   }
589 
590   apduNode=GWEN_XMLNode_FindNode(sendNode,
591                                  GWEN_XMLNodeTypeTag, "apdu");
592   if (!apduNode) {
593     DBG_ERROR(LC_LOGDOMAIN, "No <apdu> tag in command definition");
594     abort();
595   }
596 
597   dataBuffer=GWEN_Buffer_new(0, 256, 0, 1);
598   dataNode=GWEN_XMLNode_FindNode(sendNode,
599                                  GWEN_XMLNodeTypeTag, "data");
600   if (dataNode) {
601     /* there is a data node, sample data */
602     if (GWEN_MsgEngine_CreateMessageFromNode(cl->msgEngine,
603                                              dataNode,
604                                              dataBuffer,
605                                              cmdData)) {
606       DBG_ERROR(LC_LOGDOMAIN, "Error creating data for APDU");
607       GWEN_Buffer_free(dataBuffer);
608       GWEN_Buffer_AppendString(gbuf, "Error creating APDU data from command");
609       return -1;
610     }
611   }
612 
613   if (GWEN_MsgEngine_CreateMessageFromNode(cl->msgEngine,
614                                            apduNode,
615                                            gbuf,
616                                            cmdData)) {
617     DBG_ERROR(LC_LOGDOMAIN, "Error creating APDU");
618     GWEN_Buffer_free(dataBuffer);
619     GWEN_Buffer_AppendString(gbuf, "Error creating APDU from command");
620     return -1;
621   }
622 
623   i=GWEN_Buffer_GetUsedBytes(dataBuffer);
624   if (i) {
625     GWEN_Buffer_AppendByte(gbuf, (unsigned char)i);
626     GWEN_Buffer_AppendBuffer(gbuf, dataBuffer);
627   }
628   GWEN_Buffer_free(dataBuffer);
629 
630   j=0;
631   if (1!=sscanf(GWEN_XMLNode_GetProperty(apduNode, "lr", "0"),
632                 "%i", &j))
633     j=0;
634 
635   if (j!=-1) {
636     j=GWEN_DB_GetIntValue(cmdData, "lr", 0, -1);
637     if (j==-1) {
638       if (1!=sscanf(GWEN_XMLNode_GetProperty(apduNode, "lr", "-1"),
639                     "%i", &j))
640         j=-1;
641     }
642   }
643   if (j>=0)
644     GWEN_Buffer_AppendByte(gbuf, (unsigned char)j);
645 
646   return 0;
647 }
648 
649 
650 
LC_Client_ParseResult(LC_CLIENT * cl,GWEN_XMLNODE * node,GWEN_BUFFER * gbuf,GWEN_DB_NODE * rspData)651 int LC_Client_ParseResult(LC_CLIENT *cl,
652                           GWEN_XMLNODE *node,
653                           GWEN_BUFFER *gbuf,
654                           GWEN_DB_NODE *rspData){
655   unsigned int i;
656   int sw1, sw2;
657   GWEN_DB_NODE *dbTmp;
658   GWEN_XMLNODE *rnode;
659 
660   GWEN_Buffer_Rewind(gbuf); /* just in case ... */
661   i=GWEN_Buffer_GetUsedBytes(gbuf);
662   if (i<2) {
663     DBG_ERROR(LC_LOGDOMAIN, "Answer too small (less than 2 bytes)");
664     return -1;
665   }
666   sw1=(unsigned char)(GWEN_Buffer_GetStart(gbuf)[i-2]);
667   sw2=(unsigned char)(GWEN_Buffer_GetStart(gbuf)[i-1]);
668   GWEN_Buffer_Crop(gbuf, 0, i-2);
669   /* store result */
670   dbTmp=GWEN_DB_GetGroup(rspData,
671                          GWEN_DB_FLAGS_DEFAULT |
672                          GWEN_DB_FLAGS_OVERWRITE_GROUPS,
673                          "result");
674   assert(dbTmp);
675   GWEN_DB_SetIntValue(dbTmp, GWEN_DB_FLAGS_DEFAULT,
676                       "sw1", sw1);
677   GWEN_DB_SetIntValue(dbTmp, GWEN_DB_FLAGS_DEFAULT,
678                       "sw2", sw2);
679 
680   rnode=LC_Client_FindResult(cl, node, sw1, sw2);
681   if (rnode) {
682     const char *t;
683     GWEN_XMLNODE *tnode;
684     GWEN_BUFFER *txtbuf;
685     int first;
686 
687     t=GWEN_XMLNode_GetProperty(rnode, "type", "success");
688     DBG_INFO(0, "Result is: %s", t);
689     GWEN_DB_SetCharValue(dbTmp,
690                          GWEN_DB_FLAGS_DEFAULT,
691                          "type", t);
692     /* get text */
693     txtbuf=GWEN_Buffer_new(0, 256, 0, 1);
694     first=1;
695     tnode=GWEN_XMLNode_GetFirstData(rnode);
696     while(tnode) {
697       const char *p;
698 
699       p=GWEN_XMLNode_GetData(tnode);
700       if (p) {
701         if (!first)
702           GWEN_Buffer_AppendByte(txtbuf, ' ');
703         GWEN_Buffer_AppendString(txtbuf, p);
704       }
705       if (first)
706         first=0;
707       tnode=GWEN_XMLNode_GetNextData(tnode);
708     } /* while */
709 
710     if (GWEN_Buffer_GetUsedBytes(txtbuf))
711       GWEN_DB_SetCharValue(dbTmp, GWEN_DB_FLAGS_DEFAULT, "text",
712                            GWEN_Buffer_GetStart(txtbuf));
713     GWEN_Buffer_free(txtbuf);
714   }
715   else {
716     DBG_ERROR(LC_LOGDOMAIN,
717               "Result for %02x/%02x not found, assuming error",
718               sw1, sw2);
719     GWEN_DB_SetCharValue(dbTmp,
720                          GWEN_DB_FLAGS_DEFAULT,
721                          "type", "error");
722     GWEN_DB_SetCharValue(dbTmp,
723                          GWEN_DB_FLAGS_DEFAULT,
724                          "text", "Result not found");
725   }
726 
727   return 0;
728 }
729 
730 
731 
LC_Client_ParseResponse(LC_CLIENT * cl,GWEN_XMLNODE * node,GWEN_BUFFER * gbuf,GWEN_DB_NODE * rspData)732 int LC_Client_ParseResponse(LC_CLIENT *cl,
733                             GWEN_XMLNODE *node,
734                             GWEN_BUFFER *gbuf,
735                             GWEN_DB_NODE *rspData){
736   GWEN_DB_NODE *dbTmp;
737   GWEN_XMLNODE *rnode;
738   const char *p;
739 
740   assert(cl);
741 
742   GWEN_Buffer_Rewind(gbuf); /* just in case ... */
743 
744   p=GWEN_DB_GetCharValue(rspData, "result/type", 0, 0);
745   if (!p) {
746     DBG_ERROR(LC_LOGDOMAIN, "No result type given");
747     return -1;
748   }
749   dbTmp=GWEN_DB_GetGroup(rspData,
750                          GWEN_DB_FLAGS_DEFAULT |
751                          GWEN_DB_FLAGS_OVERWRITE_GROUPS,
752                          "response");
753   if (!dbTmp) {
754     DBG_ERROR(LC_LOGDOMAIN, "No matching response tag found");
755     return -1;
756   }
757 
758   rnode=LC_Client_FindResponse(cl, node, p);
759   if (!rnode) {
760     DBG_DEBUG(0, "Did not find response");
761     if (GWEN_Buffer_GetUsedBytes(gbuf)) {
762       GWEN_DB_SetBinValue(dbTmp,
763                           GWEN_DB_FLAGS_OVERWRITE_VARS,
764                           "data",
765                           GWEN_Buffer_GetStart(gbuf),
766                           GWEN_Buffer_GetUsedBytes(gbuf));
767     }
768   }
769   else {
770     if (GWEN_MsgEngine_ParseMessage(cl->msgEngine,
771                                     rnode,
772                                     gbuf,
773                                     dbTmp,
774                                     GWEN_MSGENGINE_READ_FLAGS_DEFAULT)){
775       DBG_ERROR(LC_LOGDOMAIN, "Error parsing response");
776       return -1;
777     }
778   }
779 
780   return 0;
781 }
782 
783 
784 
LC_Client_ParseAnswer(LC_CLIENT * cl,GWEN_XMLNODE * node,GWEN_BUFFER * gbuf,GWEN_DB_NODE * rspData)785 int LC_Client_ParseAnswer(LC_CLIENT *cl,
786                           GWEN_XMLNODE *node,
787                           GWEN_BUFFER *gbuf,
788                           GWEN_DB_NODE *rspData){
789   assert(cl);
790 
791   if (LC_Client_ParseResult(cl, node, gbuf, rspData)) {
792     DBG_INFO(0, "Error parsing result");
793     return -1;
794   }
795 
796   if (LC_Client_ParseResponse(cl, node, gbuf, rspData)){
797     DBG_INFO(0, "Error parsing response");
798     return -1;
799   }
800 
801   return 0;
802 }
803 
804 
805 
LC_Client_BuildApdu(LC_CLIENT * cl,LC_CARD * card,const char * command,GWEN_DB_NODE * cmdData,GWEN_BUFFER * buf)806 LC_CLIENT_RESULT LC_Client_BuildApdu(LC_CLIENT *cl,
807                                      LC_CARD *card,
808                                      const char *command,
809                                      GWEN_DB_NODE *cmdData,
810                                      GWEN_BUFFER *buf) {
811   GWEN_XMLNODE *node;
812   LC_CLIENT_RESULT res;
813 
814   DBG_INFO(LC_LOGDOMAIN, "Building APDU for command \"%s\"", command);
815   /* lookup card command */
816   DBG_INFO(LC_LOGDOMAIN, "- looking up command");
817   node=LC_Card_FindCommand(card, command);
818   if (!node) {
819     DBG_INFO(LC_LOGDOMAIN, "Command \"%s\" not found",
820              command);
821     return LC_Client_ResultNotFound;
822   }
823 
824   /* build APDU */
825   DBG_INFO(LC_LOGDOMAIN, "- building APDU");
826   res=LC_Client__BuildApdu(cl, node, cmdData, buf);
827   if (res!=LC_Client_ResultOk) {
828     DBG_INFO(LC_LOGDOMAIN,
829 	     "Error building APDU for command \"%s\" (%d)",
830 	     command, res);
831     return res;
832   }
833 
834   return LC_Client_ResultOk;
835 }
836 
837 
838 
LC_Client_ExecCommand(LC_CLIENT * cl,LC_CARD * card,const char * commandName,GWEN_DB_NODE * cmdData,GWEN_DB_NODE * rspData)839 LC_CLIENT_RESULT LC_Client_ExecCommand(LC_CLIENT *cl,
840                                        LC_CARD *card,
841                                        const char *commandName,
842                                        GWEN_DB_NODE *cmdData,
843                                        GWEN_DB_NODE *rspData) {
844   GWEN_XMLNODE *node;
845   GWEN_BUFFER *buf;
846   GWEN_BUFFER *rbuf;
847   LC_CLIENT_RESULT res;
848   LC_CLIENT_CMDTARGET t;
849   const char *s;
850 
851   DBG_INFO(LC_LOGDOMAIN, "Executing command \"%s\"", commandName);
852 
853   /* lookup card command */
854   DBG_INFO(LC_LOGDOMAIN, "- looking up command");
855   node=LC_Card_FindCommand(card, commandName);
856   if (!node) {
857     DBG_INFO(LC_LOGDOMAIN, "Command \"%s\" not found",
858              commandName);
859     return LC_Client_ResultNotFound;
860   }
861 
862   /* determine target of the command */
863   DBG_INFO(LC_LOGDOMAIN, "- determining target");
864   t=LC_Client_CmdTargetCard;
865   s=GWEN_XMLNode_GetProperty(node, "target", "card");
866   if (s) {
867     if (strcasecmp(s, "card")==0)
868       t=LC_Client_CmdTargetCard;
869     else if (strcasecmp(s, "reader")==0)
870       t=LC_Client_CmdTargetReader;
871     else {
872       DBG_ERROR(LC_LOGDOMAIN,
873                 "Invalid target given in command \"%s\": %s",
874                 commandName, s);
875       return LC_Client_ResultCfgError;
876     }
877   }
878 
879   /* build APDU */
880   DBG_INFO(LC_LOGDOMAIN, "- building APDU");
881   buf=GWEN_Buffer_new(0, 256, 0, 1);
882   res=LC_Client__BuildApdu(cl, node, cmdData, buf);
883   if (res!=LC_Client_ResultOk) {
884     DBG_INFO(LC_LOGDOMAIN,
885 	     "Error building APDU for command \"%s\" (%d)",
886 	     commandName, res);
887     GWEN_Buffer_free(buf);
888     return res;
889   }
890 
891   /* send APDU */
892   DBG_INFO(LC_LOGDOMAIN, "- sending APDU, waiting for answer");
893   rbuf=GWEN_Buffer_new(0, 256, 0, 1);
894   res=LC_Card_ExecApdu(card,
895                        GWEN_Buffer_GetStart(buf),
896                        GWEN_Buffer_GetUsedBytes(buf),
897                        rbuf,
898                        t);
899   if (res!=LC_Client_ResultOk) {
900     DBG_INFO(LC_LOGDOMAIN, "here (%d)", res);
901     GWEN_Buffer_free(rbuf);
902     GWEN_Buffer_free(buf);
903     return res;
904   }
905   GWEN_Buffer_free(buf);
906 
907   /* parse answer */
908   DBG_INFO(LC_LOGDOMAIN, "- parsing response");
909   if (LC_Client_ParseAnswer(cl, node, rbuf, rspData)) {
910     DBG_INFO(LC_LOGDOMAIN, "Error parsing answer");
911     GWEN_Buffer_free(rbuf);
912     return LC_Client_ResultCmdError;
913   }
914 
915   /* store response data */
916   if (GWEN_Buffer_GetUsedBytes(rbuf)) {
917     GWEN_DB_SetBinValue(rspData, GWEN_DB_FLAGS_OVERWRITE_VARS,
918                         "data",
919                         GWEN_Buffer_GetStart(rbuf),
920                         GWEN_Buffer_GetUsedBytes(rbuf));
921   }
922   GWEN_Buffer_free(rbuf);
923 
924   /* check for error result of command */
925   s=GWEN_DB_GetCharValue(rspData, "result/type", 0, "error");
926   if (strcasecmp(s, "success")!=0) {
927     DBG_INFO(LC_LOGDOMAIN, "Command execution error flagged by card (%s)",
928              s?s:"(none)");
929     return LC_Client_ResultCmdError;
930   }
931 
932   /* done */
933   return LC_Client_ResultOk;
934 }
935 
936 
937 
938 
939 
940 
941 
942 
943 
944