Browse code

new files (interpreter for scripted database updates)

git-svn: trunk@2024

Tomasz Kojm authored on 2006/06/15 22:06:52
Showing 3 changed files
... ...
@@ -1,3 +1,7 @@
1
+Thu Jun 15 15:03:55 CEST 2006 (tk)
2
+----------------------------------
3
+  * shared/cdiff.[ch]: new files (interpreter for scripted database updates)
4
+
1 5
 Thu Jun 15 13:57:38 CEST 2006 (tk)
2 6
 ----------------------------------
3 7
   * sigtool/sigtool.c: major cleanup
4 8
new file mode 100644
... ...
@@ -0,0 +1,567 @@
0
+/*
1
+ *  Copyright (C) 2006 Tomasz Kojm <tkojm@clamav.net>
2
+ *
3
+ *  This program is free software; you can redistribute it and/or modify
4
+ *  it under the terms of the GNU General Public License as published by
5
+ *  the Free Software Foundation; either version 2 of the License, or
6
+ *  (at your option) any later version.
7
+ *
8
+ *  This program is distributed in the hope that it will be useful,
9
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+ *  GNU General Public License for more details.
12
+ *
13
+ *  You should have received a copy of the GNU General Public License
14
+ *  along with this program; if not, write to the Free Software
15
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16
+ *  MA 02110-1301, USA.
17
+ */
18
+
19
+
20
+#if HAVE_CONFIG_H
21
+#include "clamav-config.h"
22
+#endif
23
+
24
+#include <stdio.h>
25
+#include <string.h>
26
+#include <ctype.h>
27
+#include <sys/types.h>
28
+#include <sys/stat.h>
29
+#include <unistd.h>
30
+
31
+#include "shared/memory.h"
32
+#include "shared/misc.h"
33
+
34
+#include "libclamav/str.h"
35
+#include "libclamav/others.h"
36
+#include "libclamav/cvd.h"
37
+
38
+
39
+struct cdiff_node {
40
+    unsigned int lineno;
41
+    char *str, *str2;
42
+    struct cdiff_node *next;
43
+};
44
+
45
+struct cdiff_ctx {
46
+    char *open_db;
47
+    struct cdiff_node *add_start, *add_last;
48
+    struct cdiff_node *del_start;
49
+    struct cdiff_node *xchg_start;
50
+};
51
+
52
+struct cdiff_cmd {
53
+    char *name;
54
+    unsigned short argc;
55
+    int (*handler)(const char *, struct cdiff_ctx *);
56
+};
57
+
58
+static int cdiff_cmd_open(const char *cmdstr, struct cdiff_ctx *ctx);
59
+static int cdiff_cmd_add(const char *cmdstr, struct cdiff_ctx *ctx);
60
+static int cdiff_cmd_del(const char *cmdstr, struct cdiff_ctx *ctx);
61
+static int cdiff_cmd_xchg(const char *cmdstr, struct cdiff_ctx *ctx);
62
+static int cdiff_cmd_close(const char *cmdstr, struct cdiff_ctx *ctx);
63
+
64
+static struct cdiff_cmd commands[] = {
65
+    /* OPEN db_name */
66
+    { "OPEN", 1, &cdiff_cmd_open },
67
+
68
+    /* ADD newsig */
69
+    { "ADD", 1, &cdiff_cmd_add },
70
+
71
+    /* DEL line_no some_first_bytes */
72
+    { "DEL", 2, &cdiff_cmd_del },
73
+
74
+    /* XCHG line_no some_first_bytes_of_old_line new_line */
75
+    { "XCHG", 3, &cdiff_cmd_xchg },
76
+
77
+    /* CLOSE */
78
+    { "CLOSE", 0, &cdiff_cmd_close },
79
+
80
+    /* MOVE src_db dst_db start_line first_16b end_line first_16b */
81
+    /* { "MOVE", 6, &cdiff_cmd_move }, */
82
+
83
+    { NULL, 0, NULL }
84
+};
85
+
86
+void cdiff_ctx_free(struct cdiff_ctx *ctx)
87
+{
88
+	struct cdiff_node *pt;
89
+
90
+
91
+    if(ctx->open_db) {
92
+	free(ctx->open_db);
93
+	ctx->open_db = NULL;
94
+    }
95
+
96
+    while(ctx->add_start) {
97
+	free(ctx->add_start->str);
98
+	pt = ctx->add_start;
99
+	ctx->add_start = ctx->add_start->next;
100
+	free(pt);
101
+    }
102
+
103
+    while(ctx->del_start) {
104
+	free(ctx->del_start->str);
105
+	pt = ctx->del_start;
106
+	ctx->del_start = ctx->del_start->next;
107
+	free(pt);
108
+    }
109
+
110
+    while(ctx->xchg_start) {
111
+	free(ctx->xchg_start->str);
112
+	free(ctx->xchg_start->str2);
113
+	pt = ctx->xchg_start;
114
+	ctx->xchg_start = ctx->xchg_start->next;
115
+	free(pt);
116
+    }
117
+}
118
+
119
+static char *cdiff_token(const char *line, unsigned int token)
120
+{
121
+	unsigned int counter = 0, i, j;
122
+	char *buffer;
123
+
124
+
125
+    for(i = 0; line[i] && counter != token; i++)
126
+	if(line[i] == ' ')
127
+	    counter++;
128
+
129
+    if(!line[i])
130
+	return NULL;
131
+
132
+    for(j = i; line[j]; j++)
133
+	if(line[j] == ' ')
134
+	    break;
135
+
136
+    if(i == j)
137
+	return NULL;
138
+
139
+    buffer = mmalloc(j - i + 1);
140
+    if(!buffer)
141
+	return NULL;
142
+
143
+    strncpy(buffer, line + i, j - i);
144
+    buffer[j - i] = '\0';
145
+
146
+    return buffer;
147
+}
148
+
149
+static int cdiff_cmd_open(const char *cmdstr, struct cdiff_ctx *ctx)
150
+{
151
+	char *db;
152
+	struct stat sb;
153
+	unsigned int i;
154
+
155
+
156
+    if(!(db = cdiff_token(cmdstr, 1))) {
157
+	logg("!cdiff_cmd_open: Can't get first argument\n");
158
+	return -1;
159
+    }
160
+
161
+    if(ctx->open_db) {
162
+	logg("!cdiff_cmd_open: %s not closed before opening %s\n", ctx->open_db, db);
163
+	free(db);
164
+	return -1;
165
+    }
166
+
167
+    for(i = 0; i < strlen(db); i++) {
168
+	if((db[i] != '.' && !isalnum(db[i])) || strchr("/\\", db[i])) {
169
+	    logg("!cdiff_cmd_open: Forbidden characters found in database name\n");
170
+	    free(db);
171
+	    return -1;
172
+	}
173
+    }
174
+
175
+    if(stat(db, &sb) == -1) {
176
+	logg("!cdiff_cmd_open: Can't stat database file %s\n", db);
177
+	free(db);
178
+	return -1;
179
+    }
180
+
181
+    ctx->open_db = db;
182
+    return 0;
183
+}
184
+
185
+static int cdiff_cmd_add(const char *cmdstr, struct cdiff_ctx *ctx)
186
+{
187
+	char *sig;
188
+	struct cdiff_node *new;
189
+
190
+
191
+    if(!(sig = cdiff_token(cmdstr, 1))) {
192
+	logg("!cdiff_cmd_add: Can't get first argument\n");
193
+	return -1;
194
+    }
195
+
196
+    new = mcalloc(1, sizeof(struct cdiff_node));
197
+    if(!new) {
198
+	logg("!cdiff_cmd_add: Can't allocate memory for cdiff_node\n");
199
+	free(sig);
200
+	return -1;
201
+    }
202
+    new->str = sig;
203
+
204
+    if(!ctx->add_last) {
205
+	ctx->add_start = ctx->add_last = new;
206
+    } else { 
207
+	ctx->add_last->next = new;
208
+	ctx->add_last = new;
209
+    }
210
+
211
+    return 0;
212
+}
213
+
214
+static int cdiff_cmd_del(const char *cmdstr, struct cdiff_ctx *ctx)
215
+{
216
+	char *arg;
217
+	struct cdiff_node *pt, *last, *new;
218
+	unsigned int lineno;
219
+
220
+
221
+    if(!(arg = cdiff_token(cmdstr, 1))) {
222
+	logg("!cdiff_cmd_del: Can't get first argument\n");
223
+	return -1;
224
+    }
225
+    lineno = (unsigned int) atoi(arg);
226
+    free(arg);
227
+
228
+    if(!(arg = cdiff_token(cmdstr, 2))) {
229
+	logg("!cdiff_cmd_del: Can't get second argument\n");
230
+	return -1;
231
+    }
232
+
233
+    new = mcalloc(1, sizeof(struct cdiff_node));
234
+    if(!new) {
235
+	logg("!cdiff_cmd_del: Can't allocate memory for cdiff_node\n");
236
+	free(arg);
237
+	return -1;
238
+    }
239
+    new->str = arg;
240
+    new->lineno = lineno;
241
+
242
+    if(!ctx->del_start) {
243
+
244
+	ctx->del_start = new;
245
+
246
+    } else { 
247
+
248
+	if(lineno < ctx->del_start->lineno) {
249
+	    new->next = ctx->del_start;
250
+	    ctx->del_start = new;
251
+
252
+	} else {
253
+	    pt = ctx->del_start;
254
+
255
+	    while(pt) {
256
+		last = pt;
257
+		if((pt->lineno < lineno) && (!pt->next || lineno < pt->next->lineno))
258
+		    break;
259
+
260
+		pt = pt->next;
261
+	    }
262
+
263
+	    new->next = last->next;
264
+	    last->next = new;
265
+	}
266
+    }
267
+
268
+    return 0;
269
+}
270
+
271
+static int cdiff_cmd_xchg(const char *cmdstr, struct cdiff_ctx *ctx)
272
+{
273
+	char *arg, *arg2;
274
+	struct cdiff_node *pt, *last, *new;
275
+	unsigned int lineno;
276
+
277
+
278
+    if(!(arg = cdiff_token(cmdstr, 1))) {
279
+	logg("!cdiff_cmd_xchg: Can't get first argument\n");
280
+	return -1;
281
+    }
282
+    lineno = (unsigned int) atoi(arg);
283
+    free(arg);
284
+
285
+    if(!(arg = cdiff_token(cmdstr, 2))) {
286
+	logg("!cdiff_cmd_xchg: Can't get second argument\n");
287
+	return -1;
288
+    }
289
+
290
+    if(!(arg2 = cdiff_token(cmdstr, 3))) {
291
+	free(arg);
292
+	logg("!cdiff_cmd_xchg: Can't get second argument\n");
293
+	return -1;
294
+    }
295
+
296
+    new = mcalloc(1, sizeof(struct cdiff_node));
297
+    if(!new) {
298
+	logg("!cdiff_cmd_xchg: Can't allocate memory for cdiff_node\n");
299
+	free(arg);
300
+	free(arg2);
301
+	return -1;
302
+    }
303
+    new->str = arg;
304
+    new->str2 = arg2;
305
+    new->lineno = lineno;
306
+
307
+    if(!ctx->xchg_start) {
308
+
309
+	ctx->xchg_start = new;
310
+
311
+    } else { 
312
+
313
+	if(lineno < ctx->xchg_start->lineno) {
314
+	    new->next = ctx->xchg_start;
315
+	    ctx->xchg_start = new;
316
+
317
+	} else {
318
+	    pt = ctx->xchg_start;
319
+
320
+	    while(pt) {
321
+		last = pt;
322
+		if((pt->lineno < lineno) && (!pt->next || lineno < pt->next->lineno))
323
+		    break;
324
+
325
+		pt = pt->next;
326
+	    }
327
+
328
+	    new->next = last->next;
329
+	    last->next = new;
330
+	}
331
+    }
332
+
333
+    return 0;
334
+}
335
+
336
+static int cdiff_cmd_close(const char *cmdstr, struct cdiff_ctx *ctx)
337
+{
338
+	struct cdiff_node *add, *del, *xchg;
339
+	unsigned int lines = 0;
340
+	char *tmp, line[1024];
341
+	FILE *fh, *tmpfh;
342
+
343
+
344
+    if(!ctx->open_db) {
345
+	logg("!cdiff_cmd_close: No database to close\n");
346
+	return -1;
347
+    }
348
+
349
+    add = ctx->add_start;
350
+    del = ctx->del_start;
351
+    xchg = ctx->xchg_start;
352
+
353
+    if(del || xchg) {
354
+
355
+	if(!(fh = fopen(ctx->open_db, "r"))) {
356
+	    logg("!cdiff_cmd_close: Can't open file %s for reading\n", ctx->open_db);
357
+	    return -1;
358
+	}
359
+
360
+	if(!(tmp = cli_gentemp("."))) {
361
+	    logg("!cdiff_cmd_close: Can't generate temporary name\n");
362
+	    fclose(fh);
363
+	    return -1;
364
+	}
365
+
366
+	if(!(tmpfh = fopen(tmp, "w"))) {
367
+	    logg("!cdiff_cmd_close: Can't open file %s for reading\n", tmp);
368
+	    fclose(fh);
369
+	    free(tmp);
370
+	    return -1;
371
+	}
372
+
373
+	while(fgets(line, sizeof(line), fh)) {
374
+	    lines++;
375
+
376
+	    if(del && del->lineno == lines) {
377
+		if(strncmp(line, del->str, strlen(del->str))) {
378
+		    fclose(fh);
379
+		    fclose(tmpfh);
380
+		    unlink(tmp);
381
+		    free(tmp);
382
+		    logg("!cdiff_cmd_close: Can't apply DEL at line %d\n", lines);
383
+		    return -1;
384
+		}
385
+
386
+		del = del->next;
387
+		continue;
388
+	    }
389
+
390
+	    if(xchg && xchg->lineno == lines) {
391
+		if(strncmp(line, xchg->str, strlen(xchg->str))) {
392
+		    fclose(fh);
393
+		    fclose(tmpfh);
394
+		    unlink(tmp);
395
+		    free(tmp);
396
+		    logg("!cdiff_cmd_close: Can't apply XCHG at line %d\n", lines);
397
+		    return -1;
398
+		}
399
+
400
+		if(fputs(xchg->str2, tmpfh) == EOF || fputc('\n', tmpfh) == EOF) {
401
+		    fclose(fh);
402
+		    fclose(tmpfh);
403
+		    unlink(tmp);
404
+		    logg("!cdiff_cmd_close: Can't write to %s\n", tmp);
405
+		    free(tmp);
406
+		    return -1;
407
+		}
408
+		xchg = xchg->next;
409
+		continue;
410
+	    }
411
+
412
+	    if(fputs(line, tmpfh) == EOF) {
413
+		fclose(fh);
414
+		fclose(tmpfh);
415
+		unlink(tmp);
416
+		logg("!cdiff_cmd_close: Can't write to %s\n", tmp);
417
+		free(tmp);
418
+		return -1;
419
+	    }
420
+	}
421
+
422
+	fclose(fh);
423
+	fclose(tmpfh);
424
+
425
+	if(del || xchg) {
426
+	    logg("!cdiff_cmd_close: Not all DEL/XCHG have been executed\n");
427
+	    unlink(tmp);
428
+	    free(tmp);
429
+	    return -1;
430
+	}
431
+
432
+	if(unlink(ctx->open_db) == -1) {
433
+	    logg("!cdiff_cmd_close: Can't unlink %s\n", ctx->open_db);
434
+	    unlink(tmp);
435
+	    free(tmp);
436
+	    return -1;
437
+	}
438
+
439
+	if(rename(tmp, ctx->open_db) == -1) {
440
+	    logg("!cdiff_cmd_close: Can't rename %s to %s\n", tmp, ctx->open_db);
441
+	    unlink(tmp);
442
+	    free(tmp);
443
+	    return -1;
444
+	}
445
+
446
+	free(tmp);
447
+    }
448
+
449
+    if(add) {
450
+
451
+	if(!(fh = fopen(ctx->open_db, "a"))) {
452
+	    logg("!cdiff_cmd_close: Can't open file %s for appending\n", ctx->open_db);
453
+	    return -1;
454
+	}
455
+
456
+	while(add) {
457
+	    if(fputs(add->str, fh) == EOF || fputc('\n', fh) == EOF) {
458
+		fclose(fh);
459
+		logg("!cdiff_cmd_close: Can't write to %s\n", ctx->open_db);
460
+		return -1;
461
+	    }
462
+	    add = add->next;
463
+	}
464
+    }
465
+
466
+    cdiff_ctx_free(ctx);
467
+
468
+    return 0;
469
+}
470
+
471
+int cdiff_apply(int fd)
472
+{
473
+	struct cdiff_ctx ctx;
474
+	FILE *fh;
475
+	char line[1024], *cmd_name, *tmp;
476
+	int (*cmd_handler)(const char *, struct cdiff_ctx *);
477
+	unsigned int lines = 0, cmds = 0;
478
+	int i, desc;
479
+
480
+
481
+    if((desc = dup(fd)) == -1) {
482
+	logg("!cdiff_apply: Can't duplicate descriptor %d\n", fd);
483
+	return -1;
484
+    }
485
+
486
+    if(!(fh = fdopen(desc, "r"))) {
487
+	logg("!cdiff_apply: fdopen() failed for descriptor %d\n", desc);
488
+	close(desc);
489
+	return -1;
490
+    }
491
+
492
+    memset(&ctx, 0, sizeof(ctx));
493
+
494
+    while(fgets(line, sizeof(line), fh)) {
495
+	lines++;
496
+	cli_chomp(line);
497
+	cmd_handler = NULL;
498
+
499
+	if(line[0] == '#' || !strlen(line))
500
+	    continue;
501
+
502
+	cmd_name = cdiff_token(line, 0);
503
+	if(!cmd_name) {
504
+	    logg("!cdiff_apply: Problem parsing line %d\n", lines);
505
+	    fclose(fh);
506
+	    cdiff_ctx_free(&ctx);
507
+	    return -1;
508
+	}
509
+
510
+	for(i = 0; commands[i].name; i++) {
511
+	    if(!strcmp(commands[i].name, cmd_name)) {
512
+		cmd_handler = commands[i].handler;
513
+		break;
514
+	    }
515
+	}
516
+
517
+	if(!cmd_handler) {
518
+	    logg("!cdiff_apply: Unknown command %s at line %d\n", cmd_name, lines);
519
+	    free(cmd_name);
520
+	    fclose(fh);
521
+	    cdiff_ctx_free(&ctx);
522
+	    return -1;
523
+	}
524
+
525
+	if(!(tmp = cdiff_token(line, commands[i].argc))) {
526
+	    logg("!cdiff_apply: Not enough arguments for %s at line %d\n", cmd_name, lines);
527
+	    free(cmd_name);
528
+	    fclose(fh);
529
+	    cdiff_ctx_free(&ctx);
530
+	    return -1;
531
+	}
532
+	free(tmp);
533
+
534
+	if((tmp = cdiff_token(line, commands[i].argc + 1))) {
535
+	    free(tmp);
536
+	    logg("!cdiff_apply: Too many arguments for %s at line %d\n", cmd_name, lines);
537
+	    free(cmd_name);
538
+	    fclose(fh);
539
+	    cdiff_ctx_free(&ctx);
540
+	    return -1;
541
+	}
542
+
543
+	if(cmd_handler(line, &ctx)) {
544
+	    logg("!cdiff_apply: Can't execute command %s at line %d\n", cmd_name, lines);
545
+	    fclose(fh);
546
+	    free(cmd_name);
547
+	    cdiff_ctx_free(&ctx);
548
+	    return -1;
549
+	} else {
550
+	    cmds++;
551
+	}
552
+
553
+	free(cmd_name);
554
+    }
555
+
556
+    fclose(fh);
557
+
558
+    if(ctx.open_db) {
559
+	logg("*cdiff_apply: File %s was not properly closed\n", ctx.open_db);
560
+	cdiff_ctx_free(&ctx);
561
+	return -1;
562
+    }
563
+
564
+    logg("*cdiff_apply: Parsed %d lines and executed %d commands\n", lines, cmds);
565
+    return 0;
566
+}
0 567
new file mode 100644
... ...
@@ -0,0 +1,25 @@
0
+/*
1
+ *  Copyright (C) 2006 Tomasz Kojm <tkojm@clamav.net>
2
+ *
3
+ *  This program is free software; you can redistribute it and/or modify
4
+ *  it under the terms of the GNU General Public License as published by
5
+ *  the Free Software Foundation; either version 2 of the License, or
6
+ *  (at your option) any later version.
7
+ *
8
+ *  This program is distributed in the hope that it will be useful,
9
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+ *  GNU General Public License for more details.
12
+ *
13
+ *  You should have received a copy of the GNU General Public License
14
+ *  along with this program; if not, write to the Free Software
15
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16
+ *  MA 02110-1301, USA.
17
+ */
18
+
19
+#ifndef __CDIFF_H
20
+#define __CDIFF_H
21
+
22
+int cdiff_apply(int fd);
23
+
24
+#endif