OSDN Git Service

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