Annotation of embedaddon/strongswan/src/libimcv/pts/pts_database.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2011-2012 Sansar Choinyambuu
                      3:  * Copyright (C) 2012-2017 Andreas Steffen
                      4:  * HSR Hochschule fuer Technik Rapperswil
                      5:  *
                      6:  * This program is free software; you can redistribute it and/or modify it
                      7:  * under the terms of the GNU General Public License as published by the
                      8:  * Free Software Foundation; either version 2 of the License, or (at your
                      9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     10:  *
                     11:  * This program is distributed in the hope that it will be useful, but
                     12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     14:  * for more details.
                     15:  */
                     16: 
                     17: #define _GNU_SOURCE
                     18: #include <stdio.h>
                     19: #include <libgen.h>
                     20: 
                     21: #include "pts_database.h"
                     22: 
                     23: #include <utils/debug.h>
                     24: #include <crypto/hashers/hasher.h>
                     25: 
                     26: 
                     27: typedef struct private_pts_database_t private_pts_database_t;
                     28: 
                     29: /**
                     30:  * Private data of a pts_database_t object.
                     31:  *
                     32:  */
                     33: struct private_pts_database_t {
                     34: 
                     35:        /**
                     36:         * Public pts_database_t interface.
                     37:         */
                     38:        pts_database_t public;
                     39: 
                     40:        /**
                     41:         * database instance
                     42:         */
                     43:        database_t *db;
                     44: 
                     45: };
                     46: 
                     47: METHOD(pts_database_t, get_pathname, char*,
                     48:        private_pts_database_t *this, bool is_dir, int id)
                     49: {
                     50:        enumerator_t *e;
                     51:        char *path, *name, *sep, *pathname = NULL;
                     52: 
                     53:        if (is_dir)
                     54:        {
                     55:                e = this->db->query(this->db,
                     56:                                "SELECT path FROM directories WHERE id = ?",
                     57:                                 DB_INT, id, DB_TEXT);
                     58:                if (!e || !e->enumerate(e, &path))
                     59:                {
                     60:                        pathname = NULL;
                     61:                }
                     62:                else
                     63:                {
                     64:                        pathname = strdup(path);
                     65:                }
                     66:        }
                     67:        else
                     68:        {
                     69:                e = this->db->query(this->db,
                     70:                                "SELECT d.path, f.name FROM files AS f "
                     71:                                "JOIN directories AS d ON d.id = f.dir WHERE f.id = ?",
                     72:                                 DB_INT, id, DB_TEXT, DB_TEXT);
                     73:                if (e && e->enumerate(e, &path, &name))
                     74:                {
                     75:                        if (path[0] == '/')
                     76:                        {       /* Unix style absolute path */
                     77:                                sep = "/";
                     78:                        }
                     79:                        else
                     80:                        {       /* Windows absolute path */
                     81:                                sep = "\\";
                     82:                        }
                     83:                        if (asprintf(&pathname, "%s%s%s",
                     84:                                                 path, streq(path, "/") ? "" : sep, name) == -1)
                     85:                        {
                     86:                                pathname = NULL;
                     87:                        }
                     88:                }
                     89:        }
                     90:        DESTROY_IF(e);
                     91: 
                     92:        return pathname;
                     93: }
                     94: 
                     95: METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*,
                     96:        private_pts_database_t *this, int pid, pts_meas_algorithms_t algo,
                     97:        bool is_dir, int id)
                     98: {
                     99:        enumerator_t *e;
                    100: 
                    101:        if (is_dir)
                    102:        {
                    103:                e = this->db->query(this->db,
                    104:                                "SELECT f.id, f.name, fh.hash FROM file_hashes AS fh "
                    105:                                "JOIN files AS f ON f.id = fh.file "
                    106:                                "JOIN directories as d ON d.id = f.dir "
                    107:                                "JOIN versions as v ON v.id = fh.version "
                    108:                                "WHERE v.product = ? AND fh.algo = ? AND d.id = ? "
                    109:                                "ORDER BY f.name",
                    110:                                DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_TEXT);
                    111:        }
                    112:        else
                    113:        {
                    114:                e = this->db->query(this->db,
                    115:                                "SELECT f.id, f.name, fh.hash FROM file_hashes AS fh "
                    116:                                "JOIN files AS f ON f.id = fh.file "
                    117:                                "JOIN versions AS v ON v.id = fh.version "
                    118:                                "WHERE v.product = ? AND fh.algo = ? AND fh.file = ?",
                    119:                                DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_TEXT);
                    120:        }
                    121:        return e;
                    122: }
                    123: 
                    124: 
                    125: METHOD(pts_database_t, get_product_version, bool,
                    126:        private_pts_database_t *this, int pid, int *vid)
                    127: {
                    128:        enumerator_t *e;
                    129:        int pkg_id;
                    130: 
                    131:        /* does empty package name already exist? */
                    132:        e = this->db->query(this->db,
                    133:                        "SELECT id FROM packages WHERE name = ''", DB_INT);
                    134:        if (!e)
                    135:        {
                    136:                return FALSE;
                    137:        }
                    138:        if (!e->enumerate(e, &pkg_id))
                    139:        {
                    140:                /* create generic product version entry */
                    141:                if (this->db->execute(this->db, &pkg_id,
                    142:                                "INSERT INTO packages (name) VALUES ('')") != 1)
                    143:                {
                    144:                        DBG1(DBG_PTS, "could not insert package into database");
                    145:                        e->destroy(e);
                    146:                        return FALSE;
                    147:                }
                    148:        }
                    149:        e->destroy(e);
                    150: 
                    151:        /* does generic product version already exist? */
                    152:        e = this->db->query(this->db,
                    153:                        "SELECT id FROM versions WHERE product = ? AND package = ?",
                    154:                         DB_INT, pid, DB_INT, pkg_id);
                    155:        if (!e)
                    156:        {
                    157:                return FALSE;
                    158:        }
                    159:        if (!e->enumerate(e, vid))
                    160:        {
                    161:                /* create generic product version entry */
                    162:                if (this->db->execute(this->db, vid,
                    163:                                "INSERT INTO versions (product, package) VALUES (?, ?)",
                    164:                                 DB_INT, pid, DB_INT, pkg_id) != 1)
                    165:                {
                    166:                        DBG1(DBG_PTS, "could not insert version into database");
                    167:                        e->destroy(e);
                    168:                        return FALSE;
                    169:                }
                    170:        }
                    171:        e->destroy(e);
                    172: 
                    173:        return TRUE;
                    174: }
                    175: 
                    176: METHOD(pts_database_t, add_file_measurement, bool,
                    177:        private_pts_database_t *this, int vid, pts_meas_algorithms_t algo,
                    178:        chunk_t measurement, char *filename, bool is_dir, int id)
                    179: {
                    180:        enumerator_t *e;
                    181:        char *name;
                    182:        uint8_t hash_buf[HASH_SIZE_SHA512];
                    183:        uint8_t hex_meas_buf[2*HASH_SIZE_SHA512+1], *hex_hash_buf;
                    184:        chunk_t hash, hex_hash, hex_meas;
                    185:        int hash_id, fid;
                    186:        bool success = TRUE;
                    187: 
                    188:        if (is_dir)
                    189:        {
                    190:                /* does filename entry already exist? */
                    191:                e = this->db->query(this->db,
                    192:                                "SELECT id FROM files WHERE name = ? AND dir = ?",
                    193:                                 DB_TEXT, filename, DB_INT, id, DB_INT);
                    194:                if (!e)
                    195:                {
                    196:                        return FALSE;
                    197:                }
                    198:                if (!e->enumerate(e, &fid))
                    199:                {
                    200:                        /* create filename entry */
                    201:                        if (this->db->execute(this->db, &fid,
                    202:                                        "INSERT INTO files (name, dir) VALUES (?, ?)",
                    203:                                         DB_TEXT, filename, DB_INT, id) != 1)
                    204:                        {
                    205:                                DBG1(DBG_PTS, "could not insert filename into database");
                    206:                                success = FALSE;
                    207:                        }
                    208:                }
                    209:                e->destroy(e);
                    210:        }
                    211:        else
                    212:        {
                    213:                fid = id;
                    214: 
                    215:                /* verify filename */
                    216:                e = this->db->query(this->db,
                    217:                                 "SELECT name FROM files WHERE id = ?", DB_INT, fid, DB_TEXT);
                    218:                if (!e)
                    219:                {
                    220:                        return FALSE;
                    221:                }
                    222:                if (!e->enumerate(e, &name) || !streq(name, filename))
                    223:                {
                    224:                        DBG1(DBG_PTS, "filename of reference measurement does not match");
                    225:                        success = FALSE;
                    226:                }
                    227:                e->destroy(e);
                    228:        }
                    229: 
                    230:        if (!success)
                    231:        {
                    232:                return FALSE;
                    233:        }
                    234: 
                    235:        /* does hash measurement value already exist? */
                    236:        e = this->db->query(this->db,
                    237:                        "SELECT id, hash FROM file_hashes "
                    238:                        "WHERE algo = ? AND file = ? AND version = ?",
                    239:                         DB_INT, algo, DB_INT, fid, DB_INT, vid, DB_INT, DB_TEXT);
                    240:        if (!e)
                    241:        {
                    242:                return FALSE;
                    243:        }
                    244:        if (e->enumerate(e, &hash_id, &hex_hash_buf))
                    245:        {
                    246:                hex_hash = chunk_from_str(hex_hash_buf);
                    247:                hash = chunk_from_hex(hex_hash, hash_buf);
                    248: 
                    249:                if (!chunk_equals(measurement, hash))
                    250:                {
                    251:                        /* update hash measurement value */
                    252:                        if (this->db->execute(this->db, &hash_id,
                    253:                                        "UPDATE file_hashes SET hash = ? WHERE id = ?",
                    254:                                         DB_BLOB, measurement, DB_INT, hash_id) != 1)
                    255:                        {
                    256:                                success = FALSE;
                    257:                        }
                    258:                }
                    259:        }
                    260:        else
                    261:        {
                    262:                hex_meas = chunk_to_hex(measurement, hex_meas_buf, FALSE);
                    263:                hex_meas_buf[hex_meas.len] = '\0';
                    264: 
                    265:                /* insert hash measurement value */
                    266:                if (this->db->execute(this->db, &hash_id,
                    267:                                "INSERT INTO file_hashes (file, version, algo, hash) "
                    268:                                "VALUES (?, ?, ?, ?)", DB_INT, fid, DB_INT, vid,
                    269:                                 DB_INT, algo, DB_TEXT, hex_meas_buf) != 1)
                    270:                {
                    271:                        success = FALSE;
                    272:                }
                    273:        }
                    274:        e->destroy(e);
                    275: 
                    276:        return success;
                    277: }
                    278: 
                    279: METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*,
                    280:        private_pts_database_t *this, int pid, pts_meas_algorithms_t algo,
                    281:        char *filename)
                    282: {
                    283:        enumerator_t *e;
                    284:        char *dir, *file;
                    285: 
                    286:        if (strlen(filename) < 1)
                    287:        {
                    288:                return NULL;
                    289:        }
                    290: 
                    291:        /* separate filename into directory and basename components */
                    292:        dir = path_dirname(filename);
                    293:        file = path_basename(filename);
                    294: 
                    295:        if (*dir == '.')
                    296:        {       /* relative pathname */
                    297:                e = this->db->query(this->db,
                    298:                                "SELECT fh.hash FROM file_hashes AS fh "
                    299:                                "JOIN files AS f ON f.id = fh.file "
                    300:                                "JOIN versions AS v ON v.id = fh.version "
                    301:                                "WHERE v.product = ? AND f.name = ? AND fh.algo = ? "
                    302:                                "ORDER BY v.time DESC",
                    303:                                DB_INT, pid, DB_TEXT, file, DB_INT, algo, DB_TEXT);
                    304:        }
                    305:        else
                    306:        {       /* absolute pathname */
                    307:                int did;
                    308: 
                    309:                /* find directory entry first */
                    310:                e = this->db->query(this->db,
                    311:                                "SELECT id FROM directories WHERE path = ?",
                    312:                                DB_TEXT, dir, DB_INT);
                    313: 
                    314:                if (!e || !e->enumerate(e, &did))
                    315:                {
                    316:                        goto err;
                    317:                }
                    318:                e->destroy(e);
                    319: 
                    320:                e = this->db->query(this->db,
                    321:                                "SELECT fh.hash FROM file_hashes AS fh "
                    322:                                "JOIN files AS f ON f.id = fh.file "
                    323:                                "JOIN versions AS v ON v.id = fh.version "
                    324:                                "WHERE v.product = ? AND f.dir = ? AND f.name = ? AND fh.algo = ? "
                    325:                                "ORDER BY v.time DESC",
                    326:                                DB_INT, pid, DB_INT, did, DB_TEXT, file, DB_INT, algo, DB_TEXT);
                    327:        }
                    328: 
                    329: err:
                    330:        free(file);
                    331:        free(dir);
                    332: 
                    333:        return e;
                    334: }
                    335: 
                    336: METHOD(pts_database_t, check_comp_measurement, status_t,
                    337:        private_pts_database_t *this, chunk_t measurement, int cid, int aik_id,
                    338:        int seq_no, int pcr, pts_meas_algorithms_t algo)
                    339: {
                    340:        enumerator_t *e;
                    341:        chunk_t hash;
                    342:        status_t status = NOT_FOUND;
                    343: 
                    344:        e = this->db->query(this->db,
                    345:                                        "SELECT hash FROM component_hashes "
                    346:                                        "WHERE component = ?  AND key = ? "
                    347:                                        "AND seq_no = ? AND pcr = ? AND algo = ? ",
                    348:                                        DB_INT, cid, DB_INT, aik_id, DB_INT, seq_no,
                    349:                                        DB_INT, pcr, DB_INT, algo, DB_BLOB);
                    350:        if (!e)
                    351:        {
                    352:                DBG1(DBG_PTS, "no database query enumerator returned");
                    353:                return FAILED;
                    354:        }
                    355: 
                    356:        while (e->enumerate(e, &hash))
                    357:        {
                    358:                if (chunk_equals(hash, measurement))
                    359:                {
                    360:                        status = SUCCESS;
                    361:                        break;
                    362:                }
                    363:                else
                    364:                {
                    365:                        DBG1(DBG_PTS, "PCR %2d no matching component measurement #%d "
                    366:                                                  "found in database", pcr, seq_no);
                    367:                        DBG1(DBG_PTS, "  expected: %#B", &hash);
                    368:                        DBG1(DBG_PTS, "  received: %#B", &measurement);
                    369:                        status = VERIFY_ERROR;
                    370:                        break;
                    371:                }
                    372:        }
                    373:        e->destroy(e);
                    374: 
                    375:        if (status == NOT_FOUND)
                    376:        {
                    377:                DBG1(DBG_PTS, "PCR %2d no measurement #%d "
                    378:                                          "found in database", pcr, seq_no);
                    379:        }
                    380: 
                    381:        return status;
                    382: }
                    383: 
                    384: METHOD(pts_database_t, insert_comp_measurement, status_t,
                    385:        private_pts_database_t *this, chunk_t measurement, int cid, int aik_id,
                    386:        int seq_no, int pcr, pts_meas_algorithms_t algo)
                    387: {
                    388:        int id;
                    389: 
                    390:        if (this->db->execute(this->db, &id,
                    391:                                        "INSERT INTO component_hashes "
                    392:                                        "(component, key, seq_no, pcr, algo, hash) "
                    393:                                        "VALUES (?, ?, ?, ?, ?, ?)",
                    394:                                        DB_INT, cid, DB_INT, aik_id, DB_INT, seq_no, DB_INT, pcr,
                    395:                                        DB_INT, algo, DB_BLOB, measurement) == 1)
                    396:        {
                    397:                return SUCCESS;
                    398:        }
                    399: 
                    400:        DBG1(DBG_PTS, "could not insert component measurement into database");
                    401:        return FAILED;
                    402: }
                    403: 
                    404: METHOD(pts_database_t, delete_comp_measurements, int,
                    405:        private_pts_database_t *this, int cid, int aik_id)
                    406: {
                    407:        return this->db->execute(this->db, NULL,
                    408:                                        "DELETE FROM component_hashes "
                    409:                                        "WHERE component = ? AND key = ?",
                    410:                                        DB_INT, cid, DB_INT, aik_id);
                    411: }
                    412: 
                    413: METHOD(pts_database_t, get_comp_measurement_count, status_t,
                    414:        private_pts_database_t *this, pts_comp_func_name_t *comp_name,
                    415:        int aik_id, pts_meas_algorithms_t algo, int *cid, int *count)
                    416: {
                    417:        enumerator_t *e;
                    418:        status_t status = SUCCESS;
                    419: 
                    420:        /* Initialize count */
                    421:        *count = 0;
                    422: 
                    423:        /* Get the primary key of the Component Functional Name */
                    424:        e = this->db->query(this->db,
                    425:                                "SELECT id FROM components "
                    426:                        "       WHERE vendor_id = ?  AND name = ? AND qualifier = ?",
                    427:                                DB_INT, comp_name->get_vendor_id(comp_name),
                    428:                                DB_INT, comp_name->get_name(comp_name),
                    429:                                DB_INT, comp_name->get_qualifier(comp_name),
                    430:                                DB_INT);
                    431:        if (!e)
                    432:        {
                    433:                DBG1(DBG_PTS, "no database query enumerator returned");
                    434:                return FAILED;
                    435:        }
                    436:        if (!e->enumerate(e, cid))
                    437:        {
                    438:                DBG1(DBG_PTS, "component functional name not found in database");
                    439:                e->destroy(e);
                    440:                return FAILED;
                    441:        }
                    442:        e->destroy(e);
                    443: 
                    444:        /* Get the number of stored measurements for a given AIK and component */
                    445:        e = this->db->query(this->db,
                    446:                                "SELECT COUNT(*) FROM component_hashes AS ch "
                    447:                                "WHERE component = ?  AND key = ? AND algo = ?",
                    448:                                DB_INT, *cid, DB_INT, aik_id, DB_INT, algo, DB_INT);
                    449:        if (!e)
                    450:        {
                    451:                DBG1(DBG_PTS, "no database query enumerator returned");
                    452:                return FAILED;
                    453:        }
                    454:        if (!e->enumerate(e, count))
                    455:        {
                    456:                DBG1(DBG_PTS, "no component measurement count returned from database");
                    457:                status = FAILED;
                    458:        }
                    459:        e->destroy(e);
                    460: 
                    461:        return status;
                    462: }
                    463: 
                    464: METHOD(pts_database_t, destroy, void,
                    465:        private_pts_database_t *this)
                    466: {
                    467:        free(this);
                    468: }
                    469: 
                    470: /**
                    471:  * See header
                    472:  */
                    473: pts_database_t *pts_database_create(imv_database_t *imv_db)
                    474: {
                    475:        private_pts_database_t *this;
                    476: 
                    477:        if (!imv_db)
                    478:        {
                    479:                return NULL;
                    480:        }
                    481: 
                    482:        INIT(this,
                    483:                .public = {
                    484:                        .get_pathname = _get_pathname,
                    485:                        .create_file_hash_enumerator = _create_file_hash_enumerator,
                    486:                        .get_product_version = _get_product_version,
                    487:                        .add_file_measurement = _add_file_measurement,
                    488:                        .create_file_meas_enumerator = _create_file_meas_enumerator,
                    489:                        .check_comp_measurement = _check_comp_measurement,
                    490:                        .insert_comp_measurement = _insert_comp_measurement,
                    491:                        .delete_comp_measurements = _delete_comp_measurements,
                    492:                        .get_comp_measurement_count = _get_comp_measurement_count,
                    493:                        .destroy = _destroy,
                    494:                },
                    495:                .db = imv_db->get_database(imv_db),
                    496:        );
                    497: 
                    498:        return &this->public;
                    499: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>