Annotation of embedaddon/strongswan/src/libimcv/pts/pts_database.c, revision 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>