OSDN Git Service

cleanup
[openpts/openpts.git] / src / aide.c
1 /*
2  * This file is part of the OpenPTS project.
3  *
4  * The Initial Developer of the Original Code is International
5  * Business Machines Corporation. Portions created by IBM
6  * Corporation are Copyright (C) 2010 International Business
7  * Machines Corporation. All Rights Reserved.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the Common Public License as published by
11  * IBM Corporation; either version 1 of the License, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * Common Public License for more details.
18  *
19  * You should have received a copy of the Common Public License
20  * along with this program; if not, a copy can be viewed at
21  * http://www.opensource.org/licenses/cpl1.0.php.
22  */
23
24 /**
25  * \file src/aide.c
26  * \brief AIDE I/F APIs
27  * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
28  * @date 2010-06-13
29  * cleanup 2012-01-05 SM
30  *
31  * 1) Integrity check with AIDE
32  *
33  *  $ ./configure --with-aide
34  *  $ make
35  *
36  * 2) Integrity check with AIDE and SQLite (fast?)
37  *
38  *  # yum install sqlite-devel
39  *
40  *  $ ./configure --with-aide --with-sqlite
41  *  $ make
42  *
43  *
44  * 3) Performance
45  *
46  *   simple list   30sec
47  *   hash table    36sec
48  *   SQLite        XXsec
49  *   PostgreSQL    XXsec (TBD)
50  *
51  * hash table
52  *   http://www.gnu.org/s/libc/manual/html_node/Hash-Search-Function.html
53  *
54  * binary digest did not work well, thus try base64 string in stead binary blob.
55  * 
56  *   digest - md ptr
57  *   name - in ptr
58  */
59
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63
64 #define __USE_GNU
65 #include <search.h>  // hash table
66 #include <errno.h>
67
68 #ifdef CONFIG_SQLITE
69 #include <sqlite3.h>
70 #endif
71
72 #include <zlib.h>
73
74 #include <openpts.h>
75
76 /**
77  * new AIDE_METADATA
78  *
79  * TODO(munetoh) new -> add?
80  */
81 AIDE_METADATA * newAideMetadata() {
82     AIDE_METADATA *metadata;
83     metadata = (AIDE_METADATA *) xmalloc(sizeof(AIDE_METADATA));
84     if (metadata == NULL) {
85         // LOG(LOG_ERR, "no memory\n");
86         return NULL;
87     }
88     memset(metadata, 0, sizeof(AIDE_METADATA));
89
90     return metadata;
91 }
92
93
94
95 /**
96  * free AIDE_METADATA
97  *
98  * TODO(munetoh) sep. all and single
99  */
100 void freeAideMetadata(AIDE_METADATA *md) {
101     /* check */
102     if (md == NULL) {
103         LOG(LOG_ERR, "null input");
104         return;
105     }
106
107     if (md->next != NULL) {
108         freeAideMetadata(md->next);
109     }
110
111     /* free */
112     if (md->name != NULL) xfree(md->name);
113     if (md->lname != NULL) xfree(md->lname);
114     if (md->sha1 != NULL) xfree(md->sha1);
115     if (md->sha256 != NULL) xfree(md->sha256);
116     if (md->ima_name != NULL) xfree(md->ima_name);
117     if (md->hash_key != NULL) xfree(md->hash_key);
118
119     xfree(md);
120     md = NULL;
121
122     return;
123 }
124
125 /**
126  * add
127  */
128 int addAideMetadata(AIDE_CONTEXT *ctx, AIDE_METADATA *md) {
129     int rc = 0;
130
131     /* check */
132     if (ctx == NULL) {
133         LOG(LOG_ERR, "null input");
134         return PTS_FATAL;
135     }
136     if (md == NULL) {
137         LOG(LOG_ERR, "null input");
138         return PTS_FATAL;
139     }
140
141     /* update ctx*/
142     if (ctx->start == NULL) {
143         /* first metadata */
144         ctx->start = md;
145         ctx->end = md;
146     } else {
147         ctx->end->next = md;
148         md->prev = ctx->end;
149         ctx->end = md;
150     }
151     ctx->metadata_num++;
152
153     return rc;
154 }
155
156 // #define AIDE_CHBY_LIST 1
157 #define AIDE_CHBY_LIST 0
158
159 #define AIDE_HASH_TABLE_SIZE 16000
160
161 // check hash size
162 // user time
163 // 10 0.315
164 // 20 0.642
165 #define AIDE_HASH_CHECK_SIZE SHA1_DIGEST_SIZE
166 // #define AIDE_HASH_CHECK_SIZE 20
167
168 /**
169  * new AIDE_CONTEXT
170  */
171 AIDE_CONTEXT * newAideContext() {
172     int rc;
173     AIDE_CONTEXT *ctx;
174
175     ctx = xmalloc(sizeof(AIDE_CONTEXT));
176     if (ctx == NULL) {
177         LOG(LOG_ERR, "no memory");
178         return NULL;
179     }
180     memset(ctx, 0, sizeof(AIDE_CONTEXT));
181
182     /* hash tables */
183     // TODO set the size in openpts.h
184     ctx->aide_md_table = xmalloc(sizeof(struct hsearch_data));
185     // TODO ck null
186     memset(ctx->aide_md_table, 0, sizeof(struct hsearch_data));
187     rc = hcreate_r(AIDE_HASH_TABLE_SIZE, ctx->aide_md_table);  // hash table for metadata
188     if (rc == 0) {
189         LOG(LOG_ERR, "hcreate faild, errno=%x\n", errno);
190         goto error;
191     }
192     ctx->aide_md_table_size = 0;
193
194     ctx->aide_in_table = xmalloc(sizeof(struct hsearch_data));
195     if (ctx->aide_in_table == NULL) {
196         LOG(LOG_ERR, "no memory");
197         goto error;
198     }
199     memset(ctx->aide_in_table, 0, sizeof(struct hsearch_data));
200     //  4096 full
201     rc = hcreate_r(AIDE_HASH_TABLE_SIZE, ctx->aide_in_table);  // hash table for ignore name
202     if (rc == 0) {
203         LOG(LOG_ERR, "hcreate faild\n");
204         goto error;
205     }
206     ctx->aide_in_table_size = 0;
207
208     DEBUG("newAideContext %p\n", ctx);
209     return ctx;
210
211   error:
212     if (ctx != NULL) xfree(ctx);
213     return NULL;
214 }
215
216 /**
217  *
218  */
219 void freeAideIgnoreList(AIDE_LIST *list) {
220     /* check */
221     if (list == NULL) {
222         LOG(LOG_ERR, "null input");
223         return;
224     }
225
226     if (list->next != NULL) {
227         freeAideIgnoreList(list->next);
228     }
229
230
231     /* Free */
232     if (list->name != NULL) {
233         xfree(list->name);
234     }
235
236     xfree(list);
237
238     return;
239 }
240
241 /**
242  * free AIDE_CONTEXT
243  */
244 void freeAideContext(AIDE_CONTEXT *ctx) {
245     /* check */
246     if (ctx == NULL) {
247         LOG(LOG_ERR, "ctx is NULL\n");
248         return;
249     }
250     DEBUG("freeAideContext %p \n", ctx);
251
252     // DEBUG("aide_md_table_size = %d\n", ctx->aide_md_table_size);
253     // DEBUG("aide_in_table_size = %d\n", ctx->aide_in_table_size);
254
255     /* hash tables */
256     hdestroy_r(ctx->aide_md_table);
257     hdestroy_r(ctx->aide_in_table);
258
259     xfree(ctx->aide_md_table);
260     xfree(ctx->aide_in_table);
261
262 #ifdef CONFIG_SQLITE
263     if (ctx->sqlite_db != NULL) {
264         /* close DB */
265         sqlite3_close(ctx->sqlite_db);
266     }
267 #endif
268
269     /* free metadata chain */
270     if (ctx->start != NULL) {
271         freeAideMetadata(ctx->start);
272     }
273
274     /* free ignore list */
275     if (ctx->ignore_name_start != NULL) {
276         // DEBUG("free tx->ignore_name_start\n");
277         freeAideIgnoreList(ctx->ignore_name_start);
278     }
279
280     xfree(ctx);
281     return;
282 }
283
284
285 /**
286  * load AIDE db file (giped)
287
288  name    lname attr       sha1                         sha256
289  /bin/vi 0     1073750017 C9ID19uSxnrv/Bt0uYbloaVO1SQ= VTYuAxsuG4pmWHP9ZCTO1KUsYk2uwTvwiCJ/OxzsVd0=
290  /bin 0 1 0 0
291  /bin/dnsdomainname hostname 3 0 0
292  
293  */
294
295 #define AIDE_SPEC_BUF_SIZE 1024
296 #define AIDE_MAX_ITEM_NUM  20
297 #define AIDE_MAX_ITEM_SIZE 10
298
299 // TODO(munetoh) add more...
300 #define AIDE_ITEM_NAME    0  // char
301 #define AIDE_ITEM_LNAME   1  // int
302 #define AIDE_ITEM_ATTR    2  // int
303 #define AIDE_ITEM_SHA1    3  // base64
304 #define AIDE_ITEM_SHA256  4  // base64
305 #define AIDE_ITEM_SHA512  5  // base64
306 #define AIDE_ITEM_PERM    6  //
307 #define AIDE_ITEM_UID     7  //
308 #define AIDE_ITEM_GID     8  //
309 #define AIDE_ITEM_ACL     9  //
310 #define AIDE_ITEM_XATTRS 10  //
311
312 int getAideItemIndex(char *buf) {
313     if (!strncmp(buf, "name", 4)) {
314         return AIDE_ITEM_NAME;
315     } else if (!strncmp(buf, "lname", 5)) {
316         return AIDE_ITEM_LNAME;
317     } else if (!strncmp(buf, "attr", 4)) {
318         return AIDE_ITEM_ATTR;
319     } else if (!strncmp(buf, "sha1", 4)) {
320         return AIDE_ITEM_SHA1;
321     } else if (!strncmp(buf, "sha256", 6)) {
322         return AIDE_ITEM_SHA256;
323     } else if (!strncmp(buf, "sha512", 6)) {
324         return AIDE_ITEM_SHA512;
325     } else if (!strncmp(buf, "perm", 4)) {
326         return AIDE_ITEM_PERM;
327     } else if (!strncmp(buf, "acl", 4)) {
328         return AIDE_ITEM_ACL;
329     } else if (!strncmp(buf, "uid", 4)) {
330         return AIDE_ITEM_UID;
331     } else if (!strncmp(buf, "gid", 4)) {
332         return AIDE_ITEM_GID;
333     } else if (!strncmp(buf, "xattrs", 6)) {
334         return AIDE_ITEM_XATTRS;
335     } else {
336         LOG(LOG_ERR, "Unknown AIDE item [%s]\n", buf);
337         return -1;
338     }
339 }
340
341
342 /**
343  * load AIDE database from file
344  *
345  *   filename base64(digest)
346  * Return
347  *   num of meatdata
348  *   -1 ERROR
349  *
350  * caller
351  *  ir.c
352  */
353 int loadAideDatabaseFile(AIDE_CONTEXT *ctx, char *filename) {
354     gzFile fp;
355     char buf[AIDE_SPEC_BUF_SIZE];
356     int  items[AIDE_MAX_ITEM_NUM];
357     int  item_num = 0;
358     char *ptr;
359     char *end;
360     char *sep;
361     AIDE_METADATA *md;
362     int body = 0;
363     int i;
364     int is_null;
365     int len;
366     ENTRY e;  // htable
367     ENTRY *ep;
368     int rc;
369     char *sha1_b64_ptr;
370
371     DEBUG_CAL("loadAideDatabaseFile - start, filename=[%s]\n", filename);
372
373     /* check */
374     if (ctx == NULL) {
375         LOG(LOG_ERR, "null input");
376         return -1;
377     }
378     if (filename == NULL) {
379         LOG(LOG_ERR, "null input");
380         return -1;
381     }
382
383     fp = gzopen(filename, "r");
384     if (fp == NULL) {
385         LOG(LOG_ERR, "%s missing\n", filename);
386         return -1;
387     }
388
389     while (gzgets(fp, buf, sizeof(buf)) != NULL) {
390         if (!strncmp(buf, "#", 1)) {
391         } else if (!strncmp(buf, "@@begin_db", 10)) {
392             body = 1;
393         } else if (!strncmp(buf, "@@end_db", 8)) {
394             body = 0;
395         } else if (!strncmp(buf, "@@db_spec", 9)) {
396             /* check item def */
397             ptr = &buf[10];
398             end = buf + strlen(buf);
399             item_num = 0;
400
401             /* loop */
402             while (ptr < end) {
403                 /* skip space */
404                 while ((ptr < end) && (*ptr == 0x20)) {
405                     // skip
406                     ptr++;
407                 }
408
409                 /* find sep */
410                 sep = strstr(ptr, " ");
411                 if (sep == NULL) {
412                     LOG(LOG_ERR, "bad data, %s\n", buf);
413                     return -1;
414                 } else {
415                     // terminate at " "
416                     *sep = 0;
417                 }
418                 /* get item code */
419                 items[item_num] = getAideItemIndex(ptr);
420
421                 if (items[item_num] < 0) {
422                     LOG(LOG_ERR, "Bad spec\n");
423                     return -1;
424                 }
425                 item_num++;
426
427                 if (sep + 3 > end) break;  // TODO(munetoh)
428                 ptr = sep + 1;
429             }
430             body = 2;
431
432             if (item_num > AIDE_MAX_ITEM_NUM) {
433                 LOG(LOG_ERR, "loadAideDatabaseFile - %d items > %d \n", item_num, AIDE_MAX_ITEM_NUM);
434                 return -1;
435             }
436             DEBUG("loadAideDatabaseFile - has %d items\n", item_num);
437         } else if (body == 2) { /* DB items */
438             /* new MD */
439             md = newAideMetadata();
440
441             /* check item  */
442             ptr = buf;
443             end = buf + strlen(buf);
444             sep = buf;
445
446             // *end = 0;  // TODO(munetoh) remove \n
447
448             sha1_b64_ptr = NULL;
449
450             /* loop */
451             for (i = 0; i < item_num; i++) {
452                 /* space -> \0 */
453                 if (i != item_num - 1) {
454                     sep = strstr(ptr, " ");
455                     if (sep == NULL) {
456                         LOG(LOG_ERR, "bad data, %s\n", buf);
457                         freeAideMetadata(md);
458                         return -1;
459                     } else {
460                         *sep = 0;  // set \0
461                     }
462                 }
463
464                 /* check the null string*/
465                 if (!strncmp(ptr, "0", strlen(ptr))) {
466                     is_null = 1;
467                 } else if (!strncmp(ptr, "0\n", strlen(ptr))) {
468                     is_null = 1;
469                 } else {
470                     is_null = 0;
471                 }
472
473                 switch (items[i]) {
474                     case AIDE_ITEM_NAME:   // char
475                         if (!is_null) {
476                             md->name = smalloc_assert(ptr);
477                         }
478                         break;
479                     case AIDE_ITEM_LNAME:  // char
480                         if (!is_null) {
481                             md->lname = smalloc_assert(ptr);
482                         }
483                         break;
484                     case AIDE_ITEM_ATTR:   // int
485                         md->attr = atoi(ptr);
486                         break;
487                     case AIDE_ITEM_SHA1:   // base64
488                         if (!is_null) {
489                             sha1_b64_ptr = ptr;
490                             md->sha1 = decodeBase64(
491                                 (char *)ptr,
492                                 SHA1_BASE64_DIGEST_SIZE,
493                                 &len);
494                             if (md->sha1 == NULL) {
495                                 LOG(LOG_ERR, "decodeBase64 fail");
496                                 goto close;
497                             }
498                             if (len != SHA1_DIGEST_SIZE) {
499                                 LOG(LOG_ERR, "bad SHA1 size %d  %s\n", len, ptr);
500                                 printHex("digest", md->sha1, len, "\n");
501                             }
502                         }
503                         break;
504                     case AIDE_ITEM_SHA256:  // base64
505                         if (!is_null) {
506                             md->sha256 = decodeBase64(
507                                 (char *)ptr,
508                                 SHA256_BASE64_DIGEST_SIZE,
509                                 &len);
510                             if (md->sha256 == NULL) {
511                                 LOG(LOG_ERR, "decodeBase64 fail");
512                                 goto close;
513                             }
514                             if (len != SHA256_DIGEST_SIZE) {
515                                 LOG(LOG_ERR, "bad SHA256 size %d\n", len);
516                                 OUTPUT("base64 [%s] => [", ptr);
517                                 printHex("", (BYTE *)ptr, 2, " ");
518                                 OUTPUT("][\n");
519                                 printHex("", md->sha256, len, " ");
520                                 OUTPUT("]\n");
521                             }
522                         }
523                         break;
524                     case AIDE_ITEM_SHA512:  // base64
525                         if (!is_null) {
526                             md->sha512 = decodeBase64(
527                                 (char *)ptr,
528                                 SHA512_BASE64_DIGEST_SIZE,
529                                 &len);
530                             if (md->sha512 == NULL) {
531                                 LOG(LOG_ERR, "decodeBase64 fail");
532                                 goto close;
533                             }
534                             if (len != SHA512_DIGEST_SIZE) {
535                                 LOG(LOG_ERR, "bad SHA512 size %d\n", len);
536                                 OUTPUT("base64 [%s] => [", ptr);
537                                 printHex("", (BYTE *)ptr, 2, "");
538                                 OUTPUT("][\n");
539                                 printHex("", md->sha512, len, "");
540                                 OUTPUT("]\n");
541                             }
542                         }
543                         break;
544                     case AIDE_ITEM_XATTRS:
545                         // DEBUG("AIDE_ITEM_XATTRS\n");
546                         break;
547                     default:
548                         // DEBUG("Unknown item[%d] %d\n", i, items[i]);
549                         break;
550                 }  // switch
551                 ptr = sep + 1;
552             }  // for
553
554             /* update ctx */
555             md->status = OPENPTS_AIDE_MD_STATUS_NEW;
556             addAideMetadata(ctx, md);
557
558             /* save to the hash table */
559             if (sha1_b64_ptr != NULL) {
560                 // TODO SHA1 only, add hash agility later
561                 /* alloc hash key */
562                 sha1_b64_ptr[SHA1_BASE64_DIGEST_SIZE] = 0;  // jXgiZyt0yUbP4QhAq9WFsLF/FL4=  28
563                 md->hash_key = xmalloc(strlen(sha1_b64_ptr) +1);
564                 // TODO check NULL
565                 memcpy(md->hash_key, sha1_b64_ptr, strlen(sha1_b64_ptr) + 1);
566
567                 e.key = (char *)md->hash_key;
568                 e.data = (void *)md;
569                 rc = hsearch_r(e, ENTER, &ep, ctx->aide_md_table);
570
571                 if (rc == 0) {
572                     if (errno == ENOMEM) {
573                         LOG(LOG_ERR, "  hsearch_r failed, table is full, errno=%x\n", errno);
574                     } else {
575                         LOG(LOG_ERR, "  hsearch_r failed, errno=%x\n", errno);
576                     }
577                 }
578                 // CAUTION too many messages, use for debugging the unit test
579                 // DEBUG("Hash Table <-  %4d [%s] %s\n", ctx->aide_md_table_size, md->hash_key, md->name);
580                 ctx->aide_md_table_size++;
581             }
582 #if 0
583             if (ctx->start == NULL) {
584                 ctx->start = md;
585                 ctx->end = md;
586             } else {
587                 ctx->end->next = md;
588                 md->prev = ctx->end;
589                 ctx->end = md;
590             }
591             ctx->metadata_num++;
592 #endif
593         } else {
594             // ignore
595         }  // if
596     }  // while
597  close:
598     gzclose(fp);
599     DEBUG("loadAideDatabaseFile - has %d entries\n", ctx->metadata_num);
600     DEBUG_CAL("loadAideDatabaseFile - done\n");
601
602     return ctx->metadata_num;
603 }
604
605
606 /**
607  * read AIDE ignore name
608  *
609  * Return
610  *    PTS_SUCCESS
611  *    PTS_OS_ERROR
612  * caller
613  *  ir.c
614  */
615 int readAideIgnoreNameFile(AIDE_CONTEXT *ctx, char *filename) {
616     int rc = PTS_SUCCESS;
617     FILE *fp;
618     char line[BUF_SIZE];
619     int len;
620     int cnt = 0;
621     AIDE_LIST *list;
622     ENTRY e;  // htable
623     ENTRY *ep;
624
625     DEBUG_CAL("readAideIgnoreNameFile - start, filename=[%s]\n", filename);
626
627     /* check */
628     if (ctx == NULL) {
629         LOG(LOG_ERR, "null input");
630         return PTS_FATAL;
631     }
632     if (filename == NULL) {
633         LOG(LOG_ERR, "null input");
634         return PTS_FATAL;
635     }
636
637     /* Open file for read */
638     fp = fopen(filename, "r");
639     if (fp == NULL) {
640         DEBUG("%s missing\n", filename);
641         return PTS_FATAL;
642     }
643
644     /* parse */
645     while (fgets(line, BUF_SIZE, fp) != NULL) {  // read line
646         /* ignore comment, null line */
647         if (line[0] == '#') {
648             // comment
649         } else {
650             /* name=value line*/
651             /* remove CR */
652             len = strlen(line);
653             if (line[len-1] == 0x0a) line[len-1] = 0;
654
655             DEBUG("%4d [%s]\n", cnt, line);
656
657             /* new  */
658             list = xmalloc(sizeof(AIDE_LIST));
659             if (list == NULL) {
660                 LOG(LOG_ERR, "no mem\n");
661                 rc = PTS_OS_ERROR;
662                 goto error;  // return -1;
663             }
664             memset(list, 0, sizeof(AIDE_LIST));
665             list->name = smalloc_assert(line);
666
667             /* add to chain */
668             if (ctx->ignore_name_start == NULL) {
669                 /* first entry */
670                 ctx->ignore_name_start = list;
671                 ctx->ignore_name_end = list;
672                 list->next = NULL;
673             } else {
674                 /* next entry */
675                 ctx->ignore_name_end->next = list;
676                 ctx->ignore_name_end = list;
677                 list->next = NULL;
678             }
679
680             /* hash table */
681             e.key = list->name;
682             e.data = (void *)list;
683             rc = hsearch_r(e, ENTER, &ep, ctx->aide_in_table);
684             if (rc == 0) {
685                 if (errno == ENOMEM) {
686                     LOG(LOG_ERR, "  hsearch_r failed, ignore name table is full, errno=%x\n", errno);
687                 } else {
688                     LOG(LOG_ERR, "  hsearch_r failed, errno=%x\n", errno);
689                 }
690             }
691             ctx->aide_in_table_size++;
692
693             cnt++;
694         }  // #
695     }  // while
696
697   error:
698     fclose(fp);
699
700     DEBUG_CAL("readAideIgnoreNameFile - done, num = %d\n", cnt);
701
702     return rc;
703 }
704
705
706 /**
707  * print all AIDE data, for TEST and DEBUG
708  */
709 int printAideData(AIDE_CONTEXT *ctx) {
710     AIDE_METADATA *md;
711     int i;
712
713     DEBUG_CAL("printAideData - start\n");
714     DEBUG("printAideData - num = %d\n", ctx->metadata_num);
715
716     /* check*/
717     if (ctx == NULL) {
718         LOG(LOG_ERR, "null input");
719         return  PTS_FATAL;
720     }
721
722     md = ctx->start;
723
724     for (i = 0; i < ctx->metadata_num; i++) {
725         OUTPUT("%4d ", i);
726         if ( md->name  != NULL) OUTPUT("%30s ", md->name);
727         if ( md->lname != NULL) OUTPUT("%20s ", md->lname);
728         if ( md->attr  != 0)    OUTPUT("%08X ", md->attr);
729         if (md->sha1   != NULL)
730             printHex("", md->sha1, 20, " ");
731         else
732             OUTPUT("                                        -");
733
734         if (md->sha256 != NULL)
735             printHex("", md->sha256, 32, " ");
736         else
737             OUTPUT("                                                                -");
738
739         OUTPUT(" <<\n");
740         md = md->next;
741     }
742
743     DEBUG_CAL("printAideData - end\n");
744
745     return PTS_SUCCESS;
746 }
747
748 #if 1
749 int hexcmp(BYTE *d1, BYTE *d2, int len) {
750     int i;
751
752     for (i = 0; i < len; i++) {
753         if (d1[i] != d2[i]) {
754             return -1;
755         }
756     }
757     // HIT
758     return 0;
759 }
760 #endif
761
762 // TODO(munetoh) how this work?
763 void copyAideMetadata(AIDE_METADATA *dst, AIDE_METADATA *src) {
764     if (dst->name == NULL) {
765         dst->name = xmalloc(strlen(src->name) + 1);
766         memcpy(dst->name, src->name, strlen(src->name) + 1);
767     }
768 }
769
770 #if 0
771 /**
772  * check AIDE MD vs given MD (SHA1)
773  *
774  * TODO(munetoh) obsolute use checkEventByAide()
775  */
776 int checkFileByAide(AIDE_CONTEXT *ctx, AIDE_METADATA *metadata) {
777     AIDE_METADATA *md;
778     int i;
779
780     if (ctx == NULL) {
781         return -1;
782     }
783
784     if (metadata == NULL) {
785         return -1;
786     }
787
788     md = ctx->start;
789
790     for (i = 0; i < ctx->metadata_num; i++) {
791         if (md == NULL) {
792             return -1;
793         }
794         if ((metadata->sha1 != NULL) && (md->sha1 != NULL)) {
795             if (!hexcmp(metadata->sha1, md->sha1, SHA1_DIGEST_SIZE)) {
796                 /* hit */
797                 DEBUG_FSM("checkFileByAide - HIT name=[%s]\n", md->name);
798                 md->status = OPENPTS_AIDE_MD_STATUS_HIT;
799                 copyAideMetadata(metadata, md);
800                 return 0;
801             }
802         }
803         md = md->next;
804     }
805     DEBUG_FSM("checkFileByAide - MISS\n");
806     return -2;
807 }
808 #endif
809
810 /**
811  *
812  * return 
813  *    -1: MISS
814  *     0: HIT
815  *    -2: ERROR
816  */
817 int checkIgnoreList(AIDE_CONTEXT *ctx, char *name) {
818     AIDE_LIST *list;
819     int len;
820
821     /* check */
822     if (ctx == NULL) {
823         LOG(LOG_ERR, "null input");
824         return -2;
825     }
826     if (name == NULL) {
827         LOG(LOG_ERR, "checkIgnoreList() - name is null\n");
828         return -2;
829     }
830
831     list = ctx->ignore_name_start;
832     while (list != NULL) {
833         // TODO(munetoh)  not check the all string
834         if (list->name != NULL) {
835             len = strlen(list->name);
836             if (!strncmp(name, list->name, len)) {
837                 /* Hit */
838                 DEBUG("HIT %s\n", name);
839                 return 0;
840             }
841         } else {
842             LOG(LOG_ERR, "checkIgnoreList() - list->name is null\n");
843             return -2;
844         }
845
846         list = list->next;
847     }
848
849     return -1;
850 }
851
852
853 /**
854  * check Eventlog with AIDE DB
855  *
856  * IMA
857  * event->rgbEvent[0] - [20] <= SHA1 digest of the File
858  *
859  * Return
860  *   -1: ERROR
861  *    0: HIT
862  *    1: IGNORE
863  *    2: MISS
864  *
865  * skip this check 33sec -> 2sec
866  * 
867  */
868 int checkEventByAide(AIDE_CONTEXT *ctx, OPENPTS_PCR_EVENT_WRAPPER *eventWrapper) {
869     TSS_PCR_EVENT *event;
870     char *name;
871     int rc = 0;
872     char *buf;
873     int buf_len;
874 #ifdef CONFIG_SQLITE
875 #else
876     AIDE_METADATA *md;
877 #if AIDE_CHBY_LIST
878     int i;
879 #else
880     ENTRY e;
881     ENTRY *ep;
882 #endif  //  AIDE_CHBY_LIST
883 #endif  //  CONFIG_SQLITE
884
885     // DEBUG("checkEventByAide - start\n");
886
887     if (ctx == NULL) {
888         LOG(LOG_ERR, "checkEventByAide - AIDE_CONTEXT is NULL\n");
889         return -1;
890     }
891
892     if (eventWrapper == NULL) {
893         LOG(LOG_ERR, "OcheckEventByAide - PENPTS_PCR_EVENT_WRAPPER is NULL\n");
894         return -1;
895     }
896
897     event = eventWrapper->event;
898
899     // 20100627 ignore pseudo event
900     if (event->eventType == OPENPTS_PSEUDO_EVENT_TYPE) {
901         LOG(LOG_ERR, "validateImaMeasurement - event->eventType == OPENPTS_PSEUDO_EVENT_TYPE\n");
902         return 1;
903     }
904
905     if (event->rgbEvent == NULL) {
906         DEBUG("no event\n");
907         return -1;
908     }
909
910     if (event->ulPcrValueLength != SHA1_DIGEST_SIZE) {
911         DEBUG("bad digest size\n");
912         return -1;
913     }
914
915     /* OK, let's find the HIT */
916 #ifdef CONFIG_SQLITE
917     /* base64 */
918     buf = encodeBase64(
919             event->rgbEvent,
920             20
921             &buf_len);
922     if (buf == NULL) {
923         LOG(LOG_ERR, "encodeBase64 fail");
924         return -1;
925     }
926     rc = verifyBySQLite(ctx, (char*)buf);
927     xfree(buf);
928
929     if (rc == OPENPTS_RESULT_VALID) {
930         /* hit */
931         // md = (AIDE_METADATA *) ep->data;
932         // DEBUG_FSM("checkFileByAide - HIT name=[%s]\n", md->name);
933         // md->status = OPENPTS_AIDE_MD_STATUS_HIT;
934         // md->event_wrapper = eventWrapper;  // n:1
935         // eventWrapper->aide_metadata = md;  // 1:n
936         // this output many lines:-P
937         // DEBUG("HIT  [%s] \n",b64);
938         return 0;
939     }
940 #else  // CONFIG_SQLITE
941 #if AIDE_CHBY_LIST
942     md = ctx->start;
943
944     for (i = 0; i < ctx->metadata_num; i++) {
945         if (md == NULL) {
946             DEBUG("AIDE MeataData is NULL\n");
947             return -1;
948         }
949
950         if (md->sha1 != NULL) {
951             if (memcmp(event->rgbEvent, md->sha1, SHA1_DIGEST_SIZE) == 0) {
952                 /* hit */
953                 DEBUG_FSM("checkFileByAide - HIT name=[%s]\n", md->name);
954                 md->status = OPENPTS_AIDE_MD_STATUS_HIT;
955                 md->event_wrapper = eventWrapper;  // n:1
956                 eventWrapper->aide_metadata = md;  // 1:n
957                 // copyAideMetadata(metadata, md);
958                 return 0;
959             }
960         }
961         md = md->next;
962     }
963     DEBUG_FSM("checkFileByAide - MISS\n");
964 #else  // hashtable
965
966     buf = encodeBase64(
967             event->rgbEvent,
968             20,
969             &buf_len);
970     if (buf == NULL) {
971         LOG(LOG_ERR, "encodeBase64 fail");
972         return -1;
973     }
974     e.key = (char *) buf;  // size?
975     e.data = NULL;  // just initialized for static analysys
976
977     // before (list)
978     //   real  0m36.896s
979     //   user  0m33.913s
980     //
981     // after (hash) BINARY
982     //   real  0m33.002s
983     //   user  0m30.093s
984     //
985     // after (hash) BASE64 :-(
986     //   real  0m39.148s
987     //   user  0m36.529s
988     //
989     // skip
990     //   real  0m2.506s
991     //   user  0m0.109s
992
993     rc = hsearch_r(e, FIND, &ep, ctx->aide_md_table);
994     if (rc != 0) {
995         /* hit */
996         // DEBUG("MD HIT\n");
997         md = (AIDE_METADATA *) ep->data;
998         DEBUG_FSM("checkFileByAide - HIT name=[%s]\n", md->name);
999         md->status = OPENPTS_AIDE_MD_STATUS_HIT;
1000         md->event_wrapper = eventWrapper;  // n:1
1001         eventWrapper->aide_metadata = md;  // 1:n
1002         // DEBUG("HIT  [%s] %s\n",b64, md->name);
1003         return 0;
1004     } else {
1005         // DEBUG("MISS [%s] MISS\n",b64);
1006     }
1007
1008 #endif
1009 #endif  // CONFIG_SQLITE
1010
1011     /* check ignore list */
1012
1013     // TODO(munetoh)
1014     name = (char *)event->rgbEvent;
1015     name += SHA1_DIGEST_SIZE;
1016     /* add '\n' */
1017     name = snmalloc(name, (event->ulEventLength - SHA1_DIGEST_SIZE));
1018
1019 #if 1
1020     rc = checkIgnoreList(ctx, name);
1021     if (rc == 0) {
1022         // HIT
1023         xfree(name);
1024         return 1;  // IGNORE
1025     }
1026
1027     xfree(name);
1028     return 2;
1029 #else
1030     xfree(name);
1031     return 1;  // force
1032 #endif
1033 }
1034
1035
1036 /**
1037  * Get AIDE metadata by name
1038  * 
1039  * "name" must be unique but
1040  * if multiple entries has sama name this returns first one. :-P 
1041  */
1042 AIDE_METADATA *getMetadataFromAideByName(AIDE_CONTEXT *ctx, char *name) {
1043     AIDE_METADATA *md;
1044     int i;
1045
1046     /* check */
1047     if (ctx == NULL) {
1048         LOG(LOG_ERR, "null input");
1049         return NULL;
1050     }
1051     if (name == NULL) {
1052         LOG(LOG_ERR, "null input");
1053         return NULL;
1054     }
1055
1056     md = ctx->start;
1057
1058     for (i = 0; i < ctx->metadata_num; i++) {
1059         if (md == NULL) {
1060             return NULL;
1061         }
1062         if (md->name != NULL) {
1063             if (!strcmp(md->name, name)) {
1064                 /* hit */
1065                 DEBUG("checkFileByAide HIT %s\n", name);
1066                 return md;
1067             }
1068         }
1069         md = md->next;
1070     }
1071     return NULL;
1072 }
1073
1074 /**
1075  * Convert the following char to %XX
1076  *
1077  *  Caller have to free out buffer; 
1078  *
1079  *  Return 
1080  *    New length
1081  *    -1 ERROR
1082  *
1083  *   "%20"
1084  * % "%25"
1085  * : "%3A"
1086  * @ "%40"
1087  * [ "%5B"
1088  * ] "%5D"
1089  * { "%7B"
1090  * } "%7D"
1091  * ~ "%7E"
1092 */
1093 int escapeFilename(char **out, char *in) {
1094     char *buf;
1095     int len;
1096     int i, j;
1097
1098     /* check */
1099     if (in == NULL) {
1100         LOG(LOG_ERR, "null input");
1101         return -1;
1102     }
1103     len = strlen(in);
1104
1105     /*  rough malloc new buffer */
1106     buf = xmalloc(len*3);
1107     if (buf == NULL) {
1108         LOG(LOG_ERR, "no memory");
1109         return -1;
1110     }
1111
1112     /* convert */
1113     j = 0;
1114     for (i = 0; i < len; i++) {
1115         if (in[i] == 0x20) {
1116             buf[j]     = '%';
1117             buf[j + 1] = '2';
1118             buf[j + 2] = '0';
1119             j +=3;
1120         } else if (in[i] == 0x25) {
1121             buf[j]     = '%';
1122             buf[j + 1] = '2';
1123             buf[j + 2] = '5';
1124             j +=3;
1125         } else if (in[i] == 0x3A) {
1126             buf[j]     = '%';
1127             buf[j + 1] = '3';
1128             buf[j + 2] = 'A';
1129             j +=3;
1130         } else if (in[i] == 0x40) {
1131             buf[j]     = '%';
1132             buf[j + 1] = '4';
1133             buf[j + 2] = '0';
1134             j +=3;
1135         } else if (in[i] == 0x5B) {
1136             buf[j]     = '%';
1137             buf[j + 1] = '5';
1138             buf[j + 2] = 'B';
1139             j +=3;
1140         } else if (in[i] == 0x5D) {
1141             buf[j]     = '%';
1142             buf[j + 1] = '5';
1143             buf[j + 2] = 'D';
1144             j +=3;
1145         } else if (in[i] == 0x7B) {
1146             buf[j]     = '%';
1147             buf[j + 1] = '7';
1148             buf[j + 2] = 'B';
1149             j +=3;
1150         } else if (in[i] == 0x7D) {
1151             buf[j]     = '%';
1152             buf[j + 1] = '7';
1153             buf[j + 2] = 'D';
1154             j +=3;
1155         } else if (in[i] == 0x7E) {
1156             buf[j]     = '%';
1157             buf[j + 1] = '7';
1158             buf[j + 2] = 'E';
1159             j +=3;
1160         } else {
1161             buf[j] = in[i];
1162             j++;
1163         }
1164     }
1165     buf[j] = 0;
1166
1167     *out = buf;
1168     return j;
1169 }
1170
1171
1172 /**
1173  * Convert IML TSS/file(ptscd.conf) to AIDE DB
1174  *
1175  * ctx       get the IML before call this func
1176  * filename  output AIDE DB filename
1177  *
1178  * TODO(munetoh) IMA_31 only 
1179  */
1180 int convertImlToAideDbFile(OPENPTS_CONTEXT *ctx, char *filename) {
1181     gzFile fp;
1182     int i = 0;
1183     OPENPTS_SNAPSHOT *ss;
1184     OPENPTS_PCR_EVENT_WRAPPER *eventWrapper;
1185     TSS_PCR_EVENT *event;
1186     char *buf;
1187     int buf_len;
1188     char *aide_filename = NULL;
1189     int len;
1190
1191     DEBUG_CAL("convertImlToAideDbFile %s\n", filename);
1192
1193     /* check */
1194     if (ctx == NULL) {
1195         LOG(LOG_ERR, "null input");
1196         return -1;
1197     }
1198     if (filename == NULL) {
1199         LOG(LOG_ERR, "null input");
1200         return -1;
1201     }
1202
1203     /* file open for write */
1204     fp = gzopen(filename, "wb");
1205     if (fp == NULL) {
1206         LOG(LOG_ERR, "%s fail to open\n", filename);
1207         return -1;
1208     }
1209
1210     /* Header */
1211     gzprintf(fp, "@@begin_db\n");
1212     gzprintf(fp, "# This file was generated by OpenPTS\n");
1213     gzprintf(fp, "@@db_spec name sha1 \n");
1214
1215     /* IMLs */
1216     ss = getSnapshotFromTable(ctx->ss_table, 10, 1);  // TODO def or conf
1217     if (ss == NULL) {
1218         LOG(LOG_ERR, "events is missing\n");
1219         goto close;
1220     }
1221     eventWrapper = ss->start;
1222     if (eventWrapper == NULL) {
1223         LOG(LOG_ERR, "events is missing\n");
1224         goto close;
1225     }
1226
1227     event = eventWrapper->event;
1228
1229     // DEBUG("PCR[%d]\n", ss->pcrIndex);
1230     // DEBUG("event_num %d\n", ss->event_num);
1231
1232     // for (i = 0; i < ctx->eventNum; i++) {
1233     for (i = 0; i < ctx->ss_table->event_num; i++) {  // TODO ss->event_num?
1234         // DEBUG("SM DEBUG event %p\n",event);
1235
1236         if (event == NULL) {
1237             LOG(LOG_ERR, "event is NULL\n");
1238             goto close;
1239         }
1240
1241         if (event->rgbEvent == NULL) {
1242             LOG(LOG_ERR, "event->rgbEvent is NULL\n");
1243             goto close;
1244         }
1245
1246         // TODO 2010-10-05 SM
1247         // AIDE convert the following chars in filename
1248         // SPACE 0x20  ->  "%20"
1249         // @     0x40  ->  "%40"
1250         // [ "%5B"
1251         // ] "%5D"
1252         // % "%25"
1253         // : "%3A"
1254         // { "%7B"
1255         // } "%7D"
1256         // ~ "%7E"
1257
1258         // gzprintf(fp, "%s ",&eventWrapper->event->rgbEvent[20]);
1259
1260         /* filename (allocated) */
1261         len = escapeFilename(&aide_filename, (char *) &eventWrapper->event->rgbEvent[20]);
1262         if (len < 0) {
1263             LOG(LOG_ERR, "convertImlToAideDbFile - no mem?\n");
1264             gzprintf(fp, "bad_filename ");
1265         } else {
1266             gzprintf(fp, "%s ", aide_filename);
1267             xfree(aide_filename);
1268             aide_filename = NULL;
1269         }
1270
1271         /* digest */
1272         buf = encodeBase64(
1273             (unsigned char *)event->rgbEvent,
1274             SHA1_DIGEST_SIZE,
1275             &buf_len);
1276         if (buf == NULL) {
1277             LOG(LOG_ERR, "encodeBase64 fail");
1278             goto close;
1279         }
1280         gzprintf(fp, "%s \n", buf);
1281         xfree(buf);
1282
1283         eventWrapper = eventWrapper->next_pcr;
1284         if (eventWrapper == NULL) break;
1285         event = eventWrapper->event;
1286     }
1287
1288     /* Footer */
1289     gzprintf(fp, "@@end_db\n");
1290
1291     /* file close */
1292     gzseek(fp, 1L, SEEK_CUR);  // add one \n
1293   close:
1294     gzclose(fp);
1295     if (aide_filename != NULL) xfree(aide_filename);
1296
1297     DEBUG("convertImlToAideDbFile - done\n");
1298
1299     return i+1;  // event num
1300 }
1301
1302 /**
1303  * reduce the size of AIDE DB
1304  *
1305  *                     reduced
1306  *  AIDE-DB  IMA-IML   AIDE-DB
1307  *  --------------------------
1308  *     O        O         O
1309  *     O        -         -
1310  *     -        O         -
1311  *     -        -         -
1312  *  --------------------------
1313  *
1314  *
1315  * return AIDE entry count
1316  *
1317  */
1318 int writeReducedAidbDatabase(AIDE_CONTEXT *ctx, char *filename) {
1319     gzFile fp;
1320     AIDE_METADATA *md;
1321     int i;
1322     int cnt = 0;
1323     char *buf;
1324     int buf_len;
1325
1326     DEBUG("writeReducedAidbDatabase %s\n", filename);
1327
1328     /* check */
1329     if (ctx == NULL) {
1330         LOG(LOG_ERR, "null input");
1331         return -1;
1332     }
1333     if (filename == NULL) {
1334         LOG(LOG_ERR, "null input");
1335         return -1;
1336     }
1337
1338     /* file open for write */
1339     fp = gzopen(filename, "wb");
1340     if (fp == NULL) {
1341         LOG(LOG_ERR, "%s fail to open\n", filename);
1342         return -1;
1343     }
1344
1345     /* Header */
1346     gzprintf(fp, "@@begin_db\n");
1347     gzprintf(fp, "# This file was generated by OpenPTS\n");
1348     gzprintf(fp, "@@db_spec name sha1 \n");
1349
1350     /* scan */
1351     md = ctx->start;
1352
1353     for (i = 0; i < ctx->metadata_num; i++) {
1354         if (md == NULL) {
1355             return -1;
1356         }
1357
1358         if (md->status == OPENPTS_AIDE_MD_STATUS_HIT) {
1359             buf = encodeBase64(
1360                 (unsigned char *)md->sha1,
1361                 SHA1_DIGEST_SIZE,
1362                 &buf_len);
1363             if (buf == NULL) {
1364                 LOG(LOG_ERR, "encodeBase64 fail");
1365                 return -1;
1366             }
1367             gzprintf(fp, "%s ", md->name);
1368             gzprintf(fp, "%s \n", buf);
1369             xfree(buf);
1370             cnt++;
1371         }
1372
1373         md = md->next;
1374     }
1375
1376     /* Footer */
1377     gzprintf(fp, "@@end_db\n");
1378
1379     /* file close */
1380     gzseek(fp, 1L, SEEK_CUR);  // add one \n
1381     gzclose(fp);
1382
1383     DEBUG("convertImlToAideDbFile - done\n");
1384
1385
1386     return cnt;
1387 }
1388
1389 #ifdef CONFIG_SQLITE
1390 /**
1391  * Convert AIDE BD file to SQLite DB file 
1392  *
1393  * Return 
1394  *  0 PTS_SUCCESS success
1395  *    PTS_INTERNAL_ERROR  ERROR
1396  */
1397 int convertAideDbfileToSQLiteDbFile(char * aide_filename, char * sqlite_filename) {
1398     int rc = PTS_SUCCESS;
1399     AIDE_CONTEXT *ctx;
1400     sqlite3 *db;
1401     int i;
1402     int j;
1403     AIDE_METADATA *md;
1404     char *err;
1405     char *sql;
1406
1407     /* check */
1408     if (aide_filename == NULL) {
1409         LOG(LOG_ERR, "AIDE file is null\n");
1410         return PTS_INTERNAL_ERROR;
1411     }
1412     if (sqlite_filename == NULL) {
1413         LOG(LOG_ERR, "sqlite file is null\n");
1414         return PTS_INTERNAL_ERROR;
1415     }
1416
1417
1418     /* new AIDE context */
1419     ctx = newAideContext();
1420
1421     /* read AIDE DB file -> ctx */
1422     rc = loadAideDatabaseFile(ctx, aide_filename);
1423     if (rc < 0) {
1424         LOG(LOG_ERR, "read AIDE DB %s fail, rc = %d", aide_filename, rc);
1425         return -1;
1426     }
1427
1428
1429     /* SQLite */
1430
1431     /* rm existing DB file */
1432     remove(sqlite_filename);
1433
1434     /* open */
1435     sqlite3_open(sqlite_filename, &db);
1436     if (db == NULL) {
1437         LOG(LOG_ERR, "open AIDE DB fail\n");
1438         rc = PTS_INTERNAL_ERROR;
1439         goto free;
1440     }
1441
1442     sqlite3_exec(db,
1443         "CREATE TABLE sample (id INTEGER PRIMARY KEY, digest TEXT NOT NULL, "
1444         "name TEXT NOT NULL, state INTEGER NOT NULL)",
1445         NULL, NULL, &err);
1446     // DEBUG("CREATE err=%s\n", err);
1447
1448     /* */
1449     sqlite3_exec(db, "BEGIN", NULL, NULL, &err);
1450     // DEBUG("BEGIN err=%s\n", err);
1451
1452     /* add */
1453     md = ctx->start;
1454     j = 0;
1455     for (i = 0; i < ctx->metadata_num; i++) {
1456         if (md->hash_key != NULL) {
1457             sql = sqlite3_mprintf(
1458                 "INSERT INTO sample (id, digest, name, state)  VALUES (%d, '%s','%s', %d)",
1459                     j, md->hash_key, md->name, 0);
1460             sqlite3_exec(db, sql, NULL, NULL, &err);
1461             // DEBUG("INSERT err=%s\n", err);
1462             j++;
1463         }
1464         md = md->next;
1465     }
1466
1467     /* */
1468     sqlite3_exec(db, "COMMIT", NULL, NULL, &err);
1469     // DEBUG("COMMIT err=%s\n", err);
1470
1471     /* INDEX */
1472     sqlite3_exec(db, "CREATE INDEX digestindex ON sample(digest)", NULL, NULL, &err);
1473     // DEBUG("CREATE INDEX err=%s\n", err);
1474
1475     /* close */
1476     sqlite3_close(db);
1477
1478     /* Good */
1479     rc = PTS_SUCCESS;
1480
1481   free:
1482     freeAideContext(ctx);
1483
1484     return rc;
1485 }
1486
1487 /**
1488  * load (open) SQLite DB file 
1489  */
1490 int loadSQLiteDatabaseFile(AIDE_CONTEXT *ctx, char *filename) {
1491     /* check */
1492     if (ctx == NULL) {
1493         LOG(LOG_ERR, "ctx == NULL\n");
1494         return PTS_INTERNAL_ERROR;
1495     }
1496     if (filename == NULL) {
1497         LOG(LOG_ERR, "filename == NULL\n");
1498         return PTS_INTERNAL_ERROR;
1499     }
1500
1501     /* open */
1502     sqlite3_open(filename, &ctx->sqlite_db);
1503     if (ctx->sqlite_db == NULL) {
1504         LOG(LOG_ERR, "open AIDE SQLite DB %s fail\n", filename);
1505         return PTS_INTERNAL_ERROR;
1506     }
1507
1508     return PTS_SUCCESS;
1509 }
1510
1511 /**
1512  * Veify 
1513  */
1514 int verifyBySQLite(AIDE_CONTEXT *ctx, char * key) {
1515     char *err;
1516     char *sql;
1517     char **result;
1518     int row, col;
1519
1520     /* check */
1521     if (ctx == NULL) {
1522         LOG(LOG_ERR, "ctx == NULL\n");
1523         return PTS_INTERNAL_ERROR;
1524     }
1525     if (ctx->sqlite_db == NULL) {
1526         LOG(LOG_ERR, "ctx->sqlite_db == NULL\n");
1527         return PTS_INTERNAL_ERROR;
1528     }
1529
1530     sql = sqlite3_mprintf("SELECT * from sample where digest = '%s'", key);
1531     sqlite3_get_table(ctx->sqlite_db, sql, &result, &row, &col, &err);
1532
1533     if (row >= 1) {
1534         return OPENPTS_RESULT_VALID;
1535     }
1536
1537     /* free */
1538     sqlite3_free(sql);
1539     sqlite3_free(err);
1540     sqlite3_free_table(result);
1541
1542     return OPENPTS_RESULT_UNKNOWN;
1543 }
1544 #endif  // CONFIG_SQLITE