1 /***************************************************************************
2     begin       : Mon Mar 01 2004
3     copyright   : (C) 2020 by Martin Preuss
4     email       : martin@libchipcard.de
5 
6  ***************************************************************************
7  *          Please see toplevel file COPYING for license details           *
8  ***************************************************************************/
9 
10 #ifdef HAVE_CONFIG_H
11 # include <config.h>
12 #endif
13 
14 
15 #include "job_commit_bpd.h"
16 #include "aqhbci/banking/user_l.h"
17 
18 #include "aqbanking/i18n_l.h"
19 
20 #include <gwenhywfar/db.h>
21 #include <gwenhywfar/debug.h>
22 
23 
24 
25 
26 /* ------------------------------------------------------------------------------------------------
27  * forward declarations
28  * ------------------------------------------------------------------------------------------------
29  */
30 
31 static int _getJobGroup(GWEN_DB_NODE *dbJob, const char *groupName, GWEN_DB_NODE **pResult);
32 static void _readLanguages(GWEN_DB_NODE *dbRd, AH_BPD *bpd);
33 static void _readVersions(GWEN_DB_NODE *dbRd, AH_BPD *bpd);
34 static void _readCommParams(GWEN_DB_NODE *dbJob, AH_BPD *bpd);
35 static void _readPinTanBpd(GWEN_DB_NODE *dbJob, AH_BPD *bpd, int protocolVersion);
36 static void _readBpdJobs(GWEN_DB_NODE *dbJob, AH_BPD *bpd, GWEN_MSGENGINE *msgEngine);
37 static int _isBpdJobSegment(GWEN_MSGENGINE *msgEngine, const char *segmentName, int segmentVersion);
38 static void _dumpBpdAddr(const AH_BPD_ADDR *ba);
39 
40 
41 
42 /* ------------------------------------------------------------------------------------------------
43  * implementations
44  * ------------------------------------------------------------------------------------------------
45  */
46 
47 
48 
AH_Job_Commit_Bpd(AH_JOB * j)49 int AH_Job_Commit_Bpd(AH_JOB *j)
50 {
51   GWEN_DB_NODE *dbJob    ;
52   GWEN_DB_NODE *dbRd=NULL;
53   AH_BPD *bpd;
54   const char *p;
55   int rv;
56   AB_USER *user;
57   GWEN_MSGENGINE *msgEngine;
58 
59   user=AH_Job_GetUser(j);
60   msgEngine=AH_User_GetMsgEngine(user);
61   assert(msgEngine);
62 
63   //dbJob=GWEN_DB_GetFirstGroup(j->jobResponses);
64   dbJob=AH_Job_GetResponses(j);
65 
66   rv=_getJobGroup(dbJob, "bpd", &dbRd);
67   if (rv<0) {
68     if (rv!=GWEN_ERROR_NOT_FOUND) {
69       DBG_INFO(AQHBCI_LOGDOMAIN, "here (%d)", rv);
70       return rv;
71     }
72     DBG_INFO(AQHBCI_LOGDOMAIN, "No BPD in response for job %s", AH_Job_GetName(j));
73     /*GWEN_DB_Dump(j->jobResponses, 2);*/
74     return 0;
75   }
76 
77   DBG_NOTICE(AQHBCI_LOGDOMAIN, "Found BPD, replacing existing");
78 
79   /* create new BPD */
80   bpd=AH_Bpd_new();
81 
82   /* read version */
83   AH_Bpd_SetBpdVersion(bpd, GWEN_DB_GetIntValue(dbRd, "version", 0, 0));
84 
85   /* read bank name */
86   p=GWEN_DB_GetCharValue(dbRd, "name", 0, 0);
87   if (p)
88     AH_Bpd_SetBankName(bpd, p);
89 
90   /* read message and job limits */
91   AH_Bpd_SetJobTypesPerMsg(bpd, GWEN_DB_GetIntValue(dbRd, "jobtypespermsg", 0, 0));
92   AH_Bpd_SetMaxMsgSize(bpd, GWEN_DB_GetIntValue(dbRd, "maxmsgsize", 0, 0));
93 
94   _readLanguages(dbRd, bpd);
95   _readVersions(dbRd, bpd);
96   _readCommParams(dbJob, bpd);
97   _readPinTanBpd(dbJob, bpd, GWEN_MsgEngine_GetProtocolVersion(msgEngine));
98   _readBpdJobs(dbJob, bpd, msgEngine);
99 
100   /* set BPD */
101   AH_User_SetBpd(user, bpd);
102   return 0;
103 }
104 
105 
106 
_getJobGroup(GWEN_DB_NODE * dbJob,const char * groupName,GWEN_DB_NODE ** pResult)107 int _getJobGroup(GWEN_DB_NODE *dbJob, const char *groupName, GWEN_DB_NODE **pResult)
108 {
109   GWEN_DB_NODE *dbRd;
110 
111   dbRd=GWEN_DB_GetGroup(dbJob, GWEN_PATH_FLAGS_NAMEMUSTEXIST, groupName);
112   if (dbRd==NULL) {
113     DBG_DEBUG(AQHBCI_LOGDOMAIN, "Group \"%s\" not found in response", groupName);
114     return GWEN_ERROR_NOT_FOUND;
115   }
116 
117   dbRd=GWEN_DB_GetGroup(dbRd, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "data");
118   if (dbRd==NULL) {
119     DBG_ERROR(AQHBCI_LOGDOMAIN, "Missing \"data\" group inside group \"%s\"", groupName);
120     return GWEN_ERROR_INVALID;
121   }
122 
123   dbRd=GWEN_DB_GetGroup(dbRd, GWEN_PATH_FLAGS_NAMEMUSTEXIST, groupName);
124   if (dbRd==NULL) {
125     DBG_ERROR(AQHBCI_LOGDOMAIN, "Missing effective group \"%s\" inside response", groupName);
126     return GWEN_ERROR_INVALID;
127   }
128 
129   *pResult=dbRd;
130   return 0;
131 }
132 
133 
134 
_readLanguages(GWEN_DB_NODE * dbRd,AH_BPD * bpd)135 void _readLanguages(GWEN_DB_NODE *dbRd, AH_BPD *bpd)
136 {
137   GWEN_DB_NODE *n;
138 
139   /* read languages */
140   n=GWEN_DB_GetGroup(dbRd, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "languages");
141   if (n) {
142     int i;
143 
144     for (i=0;; i++) {
145       int k;
146 
147       k=GWEN_DB_GetIntValue(n, "language", i, 0);
148       if (k) {
149         if (AH_Bpd_AddLanguage(bpd, k)) {
150           DBG_ERROR(AQHBCI_LOGDOMAIN, "Too many languages (%d)", i);
151           break;
152         }
153       }
154       else
155         break;
156     } /* for */
157   } /* if languages */
158 
159 }
160 
161 
162 
_readVersions(GWEN_DB_NODE * dbRd,AH_BPD * bpd)163 void _readVersions(GWEN_DB_NODE *dbRd, AH_BPD *bpd)
164 {
165   GWEN_DB_NODE *n;
166 
167   /* read supported version */
168   n=GWEN_DB_GetGroup(dbRd, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "versions");
169   if (n) {
170     int i;
171 
172     for (i=0;; i++) {
173       int k;
174 
175       k=GWEN_DB_GetIntValue(n, "version", i, 0);
176       if (k) {
177         if (AH_Bpd_AddHbciVersion(bpd, k)) {
178           DBG_ERROR(AQHBCI_LOGDOMAIN, "Too many versions (%d)", i);
179           break;
180         }
181       }
182       else
183         break;
184     } /* for */
185   } /* if versions */
186 }
187 
188 
189 
_readCommParams(GWEN_DB_NODE * dbJob,AH_BPD * bpd)190 void _readCommParams(GWEN_DB_NODE *dbJob, AH_BPD *bpd)
191 {
192   int rv;
193   GWEN_DB_NODE *dbRd=NULL;
194 
195   /* communication parameters */
196   rv=_getJobGroup(dbJob, "ComData", &dbRd);
197   if (rv==0) {
198     GWEN_DB_NODE *currService;
199 
200     DBG_DEBUG(AQHBCI_LOGDOMAIN, "Found communication infos");
201 
202     currService=GWEN_DB_FindFirstGroup(dbRd, "service");
203     while (currService) {
204       AH_BPD_ADDR *ba;
205 
206       ba=AH_BpdAddr_FromDb(currService);
207       if (ba) {
208         _dumpBpdAddr(ba); /* debug */
209         AH_Bpd_AddAddr(bpd, ba);
210       }
211       currService=GWEN_DB_FindNextGroup(currService, "service");
212     }
213   } /* if ComData found */
214 }
215 
216 
217 
_readPinTanBpd(GWEN_DB_NODE * dbJob,AH_BPD * bpd,int protocolVersion)218 void _readPinTanBpd(GWEN_DB_NODE *dbJob, AH_BPD *bpd, int protocolVersion)
219 {
220   int rv;
221   GWEN_DB_NODE *dbRd=NULL;
222 
223   /* special extension of BPD for PIN/TAN mode */
224   rv=_getJobGroup(dbJob, "PinTanBPD", &dbRd);
225   if (rv==0) {
226     GWEN_DB_NODE *bn;
227     GWEN_DB_NODE *currJob;
228 
229     bn=AH_Bpd_GetBpdJobs(bpd, protocolVersion);
230     assert(bn);
231 
232     currJob=GWEN_DB_FindFirstGroup(dbRd, "job");
233     while (currJob) {
234       const char *jobName;
235       int needTAN;
236       GWEN_DB_NODE *dbJob;
237 
238       jobName=GWEN_DB_GetCharValue(currJob, "job", 0, 0);
239       assert(jobName);
240       dbJob=GWEN_DB_GetGroup(bn, GWEN_DB_FLAGS_DEFAULT, jobName);
241       assert(dbJob);
242       needTAN=strcasecmp(GWEN_DB_GetCharValue(currJob, "needTan", 0, "N"), "J")==0;
243       GWEN_DB_SetIntValue(dbJob, GWEN_DB_FLAGS_OVERWRITE_VARS, "needTan", needTAN);
244       currJob=GWEN_DB_FindNextGroup(currJob, "job");
245     } /* while */
246   } /* if PIN/TAN extension found */
247 }
248 
249 
250 
_readBpdJobs(GWEN_DB_NODE * dbJob,AH_BPD * bpd,GWEN_MSGENGINE * msgEngine)251 void _readBpdJobs(GWEN_DB_NODE *dbJob, AH_BPD *bpd, GWEN_MSGENGINE *msgEngine)
252 {
253   GWEN_DB_NODE *n;
254 
255   /* check for BPD jobs */
256   n=GWEN_DB_GetFirstGroup(dbJob);
257   while (n) {
258     GWEN_DB_NODE *dbRd;
259 
260     dbRd=GWEN_DB_GetGroup(n, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "data");
261     if (dbRd)
262       dbRd=GWEN_DB_GetFirstGroup(dbRd);
263     if (dbRd) {
264       const char *segmentName;
265       int segmentVersion;
266 
267       /* check for BPD job */
268       segmentName=GWEN_DB_GroupName(dbRd);
269       segmentVersion=GWEN_DB_GetIntValue(dbRd, "head/version", 0, 0);
270       if (_isBpdJobSegment(msgEngine, segmentName, segmentVersion)) {
271         GWEN_DB_NODE *dbBpdJobs;
272         GWEN_DB_NODE *dbNewBpdJob;
273         char numbuffer[32];
274 
275         DBG_NOTICE(AQHBCI_LOGDOMAIN, "Found BPD job \"%s\"", segmentName);
276         dbBpdJobs=AH_Bpd_GetBpdJobs(bpd, GWEN_MsgEngine_GetProtocolVersion(msgEngine));
277         assert(dbBpdJobs);
278         dbNewBpdJob=GWEN_DB_GetGroup(dbBpdJobs, GWEN_DB_FLAGS_DEFAULT, segmentName);
279         assert(dbNewBpdJob);
280 
281         if (GWEN_Text_NumToString(segmentVersion, numbuffer, sizeof(numbuffer)-1, 0)<1) {
282           DBG_NOTICE(AQHBCI_LOGDOMAIN, "Buffer too small");
283           abort();
284         }
285         dbNewBpdJob=GWEN_DB_GetGroup(dbNewBpdJob, GWEN_DB_FLAGS_OVERWRITE_GROUPS, numbuffer);
286         assert(dbNewBpdJob);
287 
288         GWEN_DB_AddGroupChildren(dbNewBpdJob, dbRd);
289         /* remove "head" and "segment" group */
290         GWEN_DB_DeleteGroup(dbNewBpdJob, "head");
291         GWEN_DB_DeleteGroup(dbNewBpdJob, "segment");
292         DBG_DEBUG(AQHBCI_LOGDOMAIN, "Added BPD Job %s:%d", segmentName, segmentVersion);
293       }
294     }
295     n=GWEN_DB_GetNextGroup(n);
296   } /* while */
297 }
298 
299 
300 
_isBpdJobSegment(GWEN_MSGENGINE * msgEngine,const char * segmentName,int segmentVersion)301 int _isBpdJobSegment(GWEN_MSGENGINE *msgEngine, const char *segmentName, int segmentVersion)
302 {
303   GWEN_XMLNODE *xmlDescrForSegNameAndVer;
304 
305   DBG_DEBUG(AQHBCI_LOGDOMAIN, "Checking whether \"%s\" version %d is a BPD job", segmentName, segmentVersion);
306   /* get segment description (first try id, then code) */
307   xmlDescrForSegNameAndVer=GWEN_MsgEngine_FindNodeByProperty(msgEngine, "SEG", "id", segmentVersion, segmentName);
308   if (xmlDescrForSegNameAndVer==NULL)
309     xmlDescrForSegNameAndVer=GWEN_MsgEngine_FindNodeByProperty(msgEngine, "SEG", "code", segmentVersion, segmentName);
310   if (xmlDescrForSegNameAndVer) {
311     DBG_DEBUG(AQHBCI_LOGDOMAIN, "Found a candidate");
312     if (atoi(GWEN_XMLNode_GetProperty(xmlDescrForSegNameAndVer, "isbpdjob", "0"))) {
313       DBG_DEBUG(AQHBCI_LOGDOMAIN, "Segment \"%s\" is a BPD job", segmentName);
314       return 1;
315     }
316     else {
317       DBG_DEBUG(AQHBCI_LOGDOMAIN, "Segment \"%s\" is known but not as a BPD job", segmentName);
318     }
319   }
320   else {
321     DBG_WARN(AQHBCI_LOGDOMAIN, "Did not find segment \"%s\" (%d)", segmentName, segmentVersion);
322   }
323   return 0;
324 }
325 
326 
327 
_dumpBpdAddr(const AH_BPD_ADDR * ba)328 void _dumpBpdAddr(const AH_BPD_ADDR *ba)
329 {
330   GWEN_BUFFER *tbuf;
331   const char *s;
332 
333   tbuf=GWEN_Buffer_new(0, 256, 0, 1);
334 
335   switch (AH_BpdAddr_GetType(ba)) {
336   case AH_BPD_AddrTypeTCP:
337     GWEN_Buffer_AppendString(tbuf, "TCP: ");
338     break;
339   case AH_BPD_AddrTypeBTX:
340     GWEN_Buffer_AppendString(tbuf, "BTX: ");
341     break;
342   case AH_BPD_AddrTypeSSL:
343     GWEN_Buffer_AppendString(tbuf, "SSL: ");
344     break;
345   default:
346     GWEN_Buffer_AppendString(tbuf, "<UNK>: ");
347     break;
348   }
349 
350   s=AH_BpdAddr_GetAddr(ba);
351   if (s && *s)
352     GWEN_Buffer_AppendString(tbuf, s);
353   else
354     GWEN_Buffer_AppendString(tbuf, "<empty>");
355 
356   s=AH_BpdAddr_GetSuffix(ba);
357   if (s && *s) {
358     GWEN_Buffer_AppendString(tbuf, ", ");
359     GWEN_Buffer_AppendString(tbuf, s);
360   }
361 
362   GWEN_Buffer_AppendString(tbuf, ", ");
363   switch (AH_BpdAddr_GetFType(ba)) {
364   case AH_BPD_FilterTypeNone:
365     GWEN_Buffer_AppendString(tbuf, "none");
366     break;
367   case AH_BPD_FilterTypeBase64:
368     GWEN_Buffer_AppendString(tbuf, "base64");
369     break;
370   case AH_BPD_FilterTypeUUE:
371     GWEN_Buffer_AppendString(tbuf, "uue");
372     break;
373   default:
374     GWEN_Buffer_AppendString(tbuf, "<unk>");
375     break;
376   }
377 
378   DBG_DEBUG(AQHBCI_LOGDOMAIN, "Server address found: %s", GWEN_Buffer_GetStart(tbuf));
379   GWEN_Gui_ProgressLog2(0,
380                         GWEN_LoggerLevel_Info,
381                         I18N("Server address found: %s"),
382                         GWEN_Buffer_GetStart(tbuf));
383   GWEN_Buffer_free(tbuf);
384 }
385 
386 
387