1 /***************************************************************************
2  begin       : Mon Oct 28 2019
3  copyright   : (C) 2019 by Martin Preuss
4  email       : martin@libchipcard.de
5 
6  ***************************************************************************
7  * This file is part of the project "AqBanking".                           *
8  * Please see toplevel file COPYING of that project for license details.   *
9  ***************************************************************************/
10 
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14 
15 
16 #include "./session.h"
17 
18 #include "parser/parser.h"
19 
20 #include "aqbanking/version.h"
21 
22 #include <gwenhywfar/gwenhywfar.h>
23 #include <gwenhywfar/directory.h>
24 #include <gwenhywfar/misc.h>
25 #include <gwenhywfar/debug.h>
26 #include <gwenhywfar/text.h>
27 #include <gwenhywfar/syncio_file.h>
28 
29 
30 /* ------------------------------------------------------------------------------------------------
31  * forward declarations
32  * ------------------------------------------------------------------------------------------------
33  */
34 
35 
36 static int _anonHnsha(const uint8_t *psegment, unsigned int slen, GWEN_SYNCIO *sio);
37 static int _anonHkpae(const uint8_t *psegment, unsigned int slen, GWEN_SYNCIO *sio);
38 static int _setCharValue(GWEN_DB_NODE *n, uint32_t flags, const char *path, const char *val);
39 
40 
41 /* ------------------------------------------------------------------------------------------------
42  * implementations
43  * ------------------------------------------------------------------------------------------------
44  */
45 
46 
47 
AQFINTS_Session_LogMessage(AQFINTS_SESSION * sess,const uint8_t * ptrLogData,uint32_t lenLogData,int rec,int crypt)48 void AQFINTS_Session_LogMessage(AQFINTS_SESSION *sess,
49                                 const uint8_t *ptrLogData,
50                                 uint32_t lenLogData,
51                                 int rec,
52                                 int crypt)
53 {
54   GWEN_DB_NODE *db;
55   GWEN_SYNCIO *sio;
56   unsigned int bsize;
57   const char *logFile;
58   int vmajor, vminor, vpatchlevel, vbuild;
59   char vbuf[32];
60   int rv;
61 
62   assert(sess);
63 
64   logFile=AQFINTS_Session_GetLogFile(sess);
65   if (!logFile) {
66     DBG_ERROR(AQFINTS_LOGDOMAIN, "No log file, logging disabled for this dialog");
67     return;
68   }
69   DBG_INFO(AQFINTS_LOGDOMAIN, "Logging to file [%s]", logFile);
70 
71   db=GWEN_DB_Group_new("header");
72 
73   GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "hbciVersion", AQFINTS_Session_GetHbciVersion(sess));
74 
75   _setCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "crypt", crypt?"yes":"no");
76   _setCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "sender", rec?"bank":"user");
77   _setCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "direction", rec?"inbound":"outbound");
78   GWEN_Version(&vmajor, &vminor, &vpatchlevel, &vbuild);
79   snprintf(vbuf, sizeof(vbuf)-1, "%d.%d.%d.%d", vmajor, vminor, vpatchlevel, vbuild);
80   vbuf[sizeof(vbuf)-1]=0;
81   _setCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "gwenhywfar", vbuf);
82   _setCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "aqhbci", AQBANKING_VERSION_FULL_STRING);
83   _setCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "appname", AQFINTS_Session_GetAppRegKey(sess));
84   _setCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "appversion", AQFINTS_Session_GetAppVersion(sess));
85   GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "size", lenLogData);
86   if (GWEN_Directory_GetPath(logFile, GWEN_PATH_FLAGS_VARIABLE)) {
87     DBG_ERROR(AQFINTS_LOGDOMAIN, "Path \"%s\" is not available, cannot log", logFile);
88     GWEN_DB_Group_free(db);
89     return;
90   }
91 
92   sio=GWEN_SyncIo_File_new(logFile, GWEN_SyncIo_File_CreationMode_OpenAlways);
93   GWEN_SyncIo_AddFlags(sio,
94                        GWEN_SYNCIO_FILE_FLAGS_READ |
95                        GWEN_SYNCIO_FILE_FLAGS_WRITE |
96                        GWEN_SYNCIO_FILE_FLAGS_UREAD |
97                        GWEN_SYNCIO_FILE_FLAGS_UWRITE |
98                        GWEN_SYNCIO_FILE_FLAGS_APPEND);
99   rv=GWEN_SyncIo_Connect(sio);
100   if (rv<0) {
101     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
102     GWEN_SyncIo_free(sio);
103     GWEN_DB_Group_free(db);
104     return;
105   }
106 
107   /* write header */
108   rv=GWEN_DB_WriteToIo(db, sio,
109                        GWEN_DB_FLAGS_WRITE_SUBGROUPS |
110                        GWEN_DB_FLAGS_DETAILED_GROUPS |
111                        GWEN_DB_FLAGS_USE_COLON|
112                        GWEN_DB_FLAGS_OMIT_TYPES);
113   if (rv<0) {
114     DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
115     GWEN_SyncIo_Disconnect(sio);
116     GWEN_SyncIo_free(sio);
117     GWEN_DB_Group_free(db);
118     return;
119   }
120 
121   /* append empty line to separate header from data */
122   rv=GWEN_SyncIo_WriteForced(sio, (const uint8_t *) "\n", 1);
123   if (rv<0) {
124     DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
125     GWEN_SyncIo_Disconnect(sio);
126     GWEN_SyncIo_free(sio);
127     GWEN_DB_Group_free(db);
128     return;
129   }
130 
131   /* write data */
132   bsize=lenLogData;
133   if (bsize) {
134     const uint8_t *p;
135     unsigned int bleft;
136 
137     bleft=bsize;
138     p=ptrLogData;
139     while (bleft) {
140       const uint8_t *segEnd;
141       unsigned int slen;
142 
143       if (*p=='\'') {
144         rv=GWEN_SyncIo_WriteForced(sio, p, 1);
145         if (rv<0) {
146           DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
147           GWEN_SyncIo_Disconnect(sio);
148           GWEN_SyncIo_free(sio);
149           GWEN_DB_Group_free(db);
150           return;
151         }
152 
153         p++;
154         bleft--;
155       }
156       else {
157         segEnd=(const uint8_t *) strchr((const char *) p, '\'');
158         if (segEnd==NULL) {
159           /* no segment end found, write rest of the buffer */
160           rv=GWEN_SyncIo_WriteForced(sio, p, bleft);
161           if (rv<0) {
162             DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
163             GWEN_SyncIo_Disconnect(sio);
164             GWEN_SyncIo_free(sio);
165             GWEN_DB_Group_free(db);
166             return;
167           }
168           break;
169         }
170 
171         assert(segEnd);
172         slen=segEnd-p+1;
173         assert(slen);
174 
175         if (strncasecmp((const char *) p, "HNSHA:", 6)==0)
176           rv=_anonHnsha(p, slen, sio);
177         else if (strncasecmp((const char *) p, "HKPAE:", 6)==0 || strncasecmp((const char *) p, "DKPAE:", 6)==0)
178           rv=_anonHkpae(p, slen, sio);
179         /* add more segments with confidential data here */
180         else {
181           unsigned int l;
182 
183           l=slen;
184           rv=GWEN_SyncIo_WriteForced(sio, (const uint8_t *)p, l);
185         }
186         if (rv<0) {
187           DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
188           GWEN_SyncIo_Disconnect(sio);
189           GWEN_SyncIo_free(sio);
190           GWEN_DB_Group_free(db);
191           return;
192         }
193 
194         bleft-=slen;
195         p=segEnd+1;
196       }
197     } /* while bleft */
198   }
199 
200   /* add LF for better readability */
201   rv=GWEN_SyncIo_WriteForced(sio, (const uint8_t *) "\n", 1);
202   if (rv<0) {
203     DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
204     GWEN_SyncIo_Disconnect(sio);
205     GWEN_SyncIo_free(sio);
206     GWEN_DB_Group_free(db);
207     return;
208   }
209 
210   /* close layer */
211   rv=GWEN_SyncIo_Disconnect(sio);
212   if (rv<0) {
213     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
214     GWEN_SyncIo_free(sio);
215     return;
216   }
217 
218   GWEN_SyncIo_free(sio);
219 
220   GWEN_DB_Group_free(db);
221   DBG_DEBUG(AQFINTS_LOGDOMAIN, "Message logged");
222 }
223 
224 
225 
_anonHnsha(const uint8_t * psegment,unsigned int slen,GWEN_SYNCIO * sio)226 int _anonHnsha(const uint8_t *psegment, unsigned int slen, GWEN_SYNCIO *sio)
227 {
228   int plusCount=0;
229   int lastWasEscape=0;
230   int segDone=0;
231   const uint8_t *p;
232   unsigned int count;
233 
234   p=psegment;
235   count=slen;
236   while (*p && !segDone && count--) {
237     int normalChar=1;
238     int err;
239 
240     err=0;
241     if (lastWasEscape) {
242       lastWasEscape=0;
243       normalChar=0;
244     }
245     else {
246       if (*p=='?') {
247         lastWasEscape=1;
248       }
249       else {
250         if (*p=='\'')
251           segDone=1;
252         else if (*p=='+')
253           plusCount++;
254         lastWasEscape=0;
255       }
256     }
257     if (plusCount>=3 && normalChar && *p!='+' && *p!='\'' && *p!=':')
258       err=GWEN_SyncIo_WriteForced(sio, (const uint8_t *) "*", 1);
259     else
260       err=GWEN_SyncIo_WriteForced(sio, p, 1);
261     if (err<0) {
262       DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", err);
263       return err;
264     }
265 
266     p++;
267   } /* while */
268 
269   return 0;
270 }
271 
272 
273 
_anonHkpae(const uint8_t * psegment,unsigned int slen,GWEN_SYNCIO * sio)274 int _anonHkpae(const uint8_t *psegment, unsigned int slen, GWEN_SYNCIO *sio)
275 {
276   int plusCount=0;
277   int lastWasEscape=0;
278   int segDone=0;
279   const uint8_t *p;
280   unsigned int count;
281 
282   p=psegment;
283   count=slen;
284   while (*p && !segDone && count--) {
285     int normalChar=1;
286     int err;
287 
288     err=0;
289     if (lastWasEscape) {
290       lastWasEscape=0;
291       normalChar=0;
292     }
293     else {
294       if (*p=='?') {
295         lastWasEscape=1;
296       }
297       else {
298         if (*p=='\'')
299           segDone=1;
300         else if (*p=='+')
301           plusCount++;
302         lastWasEscape=0;
303       }
304     }
305     if (plusCount>=1 && normalChar && *p!='+' && *p!='\'' && *p!=':')
306       err=GWEN_SyncIo_WriteForced(sio, (const uint8_t *) "*", 1);
307     else
308       err=GWEN_SyncIo_WriteForced(sio, p, 1);
309     if (err<0) {
310       DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", err);
311       return err;
312     }
313 
314     p++;
315   } /* while */
316 
317   return 0;
318 }
319 
320 
321 
322 
_setCharValue(GWEN_DB_NODE * n,uint32_t flags,const char * path,const char * val)323 int _setCharValue(GWEN_DB_NODE *n, uint32_t flags, const char *path, const char *val)
324 {
325   return GWEN_DB_SetCharValue(n, flags, path, val?val:"<empty>");
326 }
327 
328 
329 
330 
331 
332