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