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

1.1       misho       1: /*
                      2:  * Copyright (C) 2011 Sansar Choinyambuu
                      3:  * Copyright (C) 2014 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: #include "pts_file_meas.h"
                     18: 
                     19: #include <collections/linked_list.h>
                     20: #include <utils/debug.h>
                     21: 
                     22: #include <sys/stat.h>
                     23: #include <libgen.h>
                     24: #include <errno.h>
                     25: 
                     26: typedef struct private_pts_file_meas_t private_pts_file_meas_t;
                     27: 
                     28: /**
                     29:  * Private data of a pts_file_meas_t object.
                     30:  *
                     31:  */
                     32: struct private_pts_file_meas_t {
                     33: 
                     34:        /**
                     35:         * Public pts_file_meas_t interface.
                     36:         */
                     37:        pts_file_meas_t public;
                     38: 
                     39:        /**
                     40:         * ID of PTS File Measurement Request
                     41:         */
                     42:        uint16_t request_id;
                     43: 
                     44:        /**
                     45:         * List of File Measurements
                     46:         */
                     47:        linked_list_t *list;
                     48: };
                     49: 
                     50: typedef struct entry_t entry_t;
                     51: 
                     52: /**
                     53:  * PTS File Measurement entry
                     54:  */
                     55: struct entry_t {
                     56:        char     *filename;
                     57:        chunk_t  measurement;
                     58: };
                     59: 
                     60: /**
                     61:  * Free an entry_t object
                     62:  */
                     63: static void free_entry(entry_t *entry)
                     64: {
                     65:        if (entry)
                     66:        {
                     67:                free(entry->filename);
                     68:                free(entry->measurement.ptr);
                     69:                free(entry);
                     70:        }
                     71: }
                     72: 
                     73: METHOD(pts_file_meas_t, get_request_id, uint16_t,
                     74:        private_pts_file_meas_t *this)
                     75: {
                     76:        return this->request_id;
                     77: }
                     78: 
                     79: METHOD(pts_file_meas_t, get_file_count, int,
                     80:        private_pts_file_meas_t *this)
                     81: {
                     82:        return this->list->get_count(this->list);
                     83: }
                     84: 
                     85: METHOD(pts_file_meas_t, add, void,
                     86:        private_pts_file_meas_t *this, char *filename, chunk_t measurement)
                     87: {
                     88:        entry_t *entry;
                     89: 
                     90:        entry = malloc_thing(entry_t);
                     91:        entry->filename = strdup(filename);
                     92:        entry->measurement = chunk_clone(measurement);
                     93: 
                     94:        this->list->insert_last(this->list, entry);
                     95: }
                     96: 
                     97: CALLBACK(entry_filter, bool,
                     98:        void *null, enumerator_t *orig, va_list args)
                     99: {
                    100:        entry_t *entry;
                    101:        chunk_t *measurement;
                    102:        char **filename;
                    103: 
                    104:        VA_ARGS_VGET(args, filename, measurement);
                    105: 
                    106:        if (orig->enumerate(orig, &entry))
                    107:        {
                    108:                *filename = entry->filename;
                    109:                *measurement = entry->measurement;
                    110:                return TRUE;
                    111:        }
                    112:        return FALSE;
                    113: }
                    114: 
                    115: METHOD(pts_file_meas_t, create_enumerator, enumerator_t*,
                    116:        private_pts_file_meas_t *this)
                    117: {
                    118:        return enumerator_create_filter(this->list->create_enumerator(this->list),
                    119:                                                                        entry_filter, NULL, NULL);
                    120: }
                    121: 
                    122: METHOD(pts_file_meas_t, check, bool,
                    123:        private_pts_file_meas_t *this, pts_database_t *pts_db, int pid,
                    124:        pts_meas_algorithms_t algo)
                    125: {
                    126:        enumerator_t *enumerator, *e;
                    127:        entry_t *entry;
                    128:        chunk_t hash;
                    129:        int count_ok = 0, count_not_found = 0, count_differ = 0;
                    130:        status_t status;
                    131: 
                    132:        enumerator = this->list->create_enumerator(this->list);
                    133:        while (enumerator->enumerate(enumerator, &entry))
                    134:        {
                    135:                status = NOT_FOUND;
                    136: 
                    137:                e = pts_db->create_file_meas_enumerator(pts_db, pid, algo,
                    138:                                                                                                entry->filename);
                    139:                if (e)
                    140:                {
                    141:                        while (e->enumerate(e, &hash))
                    142:                        {
                    143:                                if (chunk_equals(entry->measurement, hash))
                    144:                                {
                    145:                                        status = SUCCESS;
                    146:                                        break;
                    147:                                }
                    148:                                else
                    149:                                {
                    150:                                        status = VERIFY_ERROR;
                    151:                                }
                    152:                        }
                    153:                        e->destroy(e);
                    154:                }
                    155:                else
                    156:                {
                    157:                        status = FAILED;
                    158:                }
                    159: 
                    160:                switch (status)
                    161:                {
                    162:                        case SUCCESS:
                    163:                                DBG3(DBG_PTS, "  %#B for '%s' is ok", &entry->measurement,
                    164:                                                                                                           entry->filename);
                    165:                                count_ok++;
                    166:                                break;
                    167:                        case NOT_FOUND:
                    168:                                DBG2(DBG_PTS, "  %#B for '%s' not found", &entry->measurement,
                    169:                                                                                                                   entry->filename);
                    170:                                count_not_found++;
                    171:                                break;
                    172:                        case VERIFY_ERROR:
                    173:                                DBG1(DBG_PTS, "  %#B for '%s' differs", &entry->measurement,
                    174:                                                                                                                 entry->filename);
                    175:                                count_differ++;
                    176:                                break;
                    177:                        case FAILED:
                    178:                        default:
                    179:                                DBG1(DBG_PTS, "  %#B for '%s' failed", &entry->measurement,
                    180:                                                                                                                entry->filename);
                    181:                }
                    182:        }
                    183:        enumerator->destroy(enumerator);
                    184: 
                    185:        DBG1(DBG_PTS, "%d measurements, %d ok, %d not found, %d differ",
                    186:                 this->list->get_count(this->list),
                    187:                 count_ok, count_not_found, count_differ);
                    188:        return TRUE;
                    189: }
                    190: 
                    191: METHOD(pts_file_meas_t, verify, bool,
                    192:        private_pts_file_meas_t *this, enumerator_t *e_hash, bool is_dir)
                    193: {
                    194:        int fid, fid_last = 0;
                    195:        char *filename;
                    196:        uint8_t measurement_buf[HASH_SIZE_SHA512], *hex_meas_buf;
                    197:        chunk_t measurement, hex_meas;
                    198:        entry_t *entry;
                    199:        enumerator_t *enumerator = NULL;
                    200:        bool found = FALSE, match = FALSE, success = TRUE;
                    201: 
                    202:        while (e_hash->enumerate(e_hash, &fid, &filename, &hex_meas_buf))
                    203:        {
                    204:                if (fid != fid_last)
                    205:                {
                    206:                        if (found && !match)
                    207:                        {
                    208:                                /* no matching hash value found for last filename */
                    209:                                success = FALSE;
                    210:                                DBG1(DBG_PTS, "  %#B for '%s' is incorrect",
                    211:                                         &entry->measurement, entry->filename);
                    212:                                enumerator->destroy(enumerator);
                    213:                        }
                    214: 
                    215:                        /* get a new filename from the database */
                    216:                        found = FALSE;
                    217:                        match = FALSE;
                    218:                        fid_last = fid;
                    219: 
                    220:                        /**
                    221:                         * check if we find an entry for this filename
                    222:                         * in the PTS measurement list
                    223:                        */
                    224:                        enumerator = this->list->create_enumerator(this->list);
                    225:                        while (enumerator->enumerate(enumerator, &entry))
                    226:                        {
                    227:                                if (!is_dir || streq(filename, entry->filename))
                    228:                                {
                    229:                                        found = TRUE;
                    230:                                        break;
                    231:                                }
                    232:                        }
                    233: 
                    234:                        /* no PTS measurement returned for this filename */
                    235:                        if (!found)
                    236:                        {
                    237:                                success = FALSE;
                    238:                                DBG1(DBG_PTS, "  no measurement found for '%s'", filename);
                    239:                                enumerator->destroy(enumerator);
                    240:                        }
                    241:                }
                    242: 
                    243:                if (found && !match)
                    244:                {
                    245:                        hex_meas = chunk_from_str(hex_meas_buf);
                    246:                        measurement = chunk_from_hex(hex_meas, measurement_buf);
                    247: 
                    248:                        if (chunk_equals(measurement, entry->measurement))
                    249:                        {
                    250:                                match = TRUE;
                    251:                                DBG2(DBG_PTS, "  %#B for '%s' is ok",
                    252:                                         &entry->measurement, entry->filename);
                    253:                                enumerator->destroy(enumerator);
                    254:                        }
                    255:                }
                    256:        }
                    257: 
                    258:        if (found && !match)
                    259:        {
                    260:                /* no matching hash value found for the very last filename */
                    261:                success = FALSE;
                    262:                DBG1(DBG_PTS, "  %#B for '%s' is incorrect",
                    263:                         &entry->measurement, entry->filename);
                    264:                        enumerator->destroy(enumerator);
                    265:        }
                    266: 
                    267:        return success;
                    268: }
                    269: 
                    270: METHOD(pts_file_meas_t, destroy, void,
                    271:        private_pts_file_meas_t *this)
                    272: {
                    273:        this->list->destroy_function(this->list, (void *)free_entry);
                    274:        free(this);
                    275: }
                    276: 
                    277: /**
                    278:  * See header
                    279:  */
                    280: pts_file_meas_t *pts_file_meas_create(uint16_t request_id)
                    281: {
                    282:        private_pts_file_meas_t *this;
                    283: 
                    284:        INIT(this,
                    285:                .public = {
                    286:                        .get_request_id = _get_request_id,
                    287:                        .get_file_count = _get_file_count,
                    288:                        .add = _add,
                    289:                        .create_enumerator = _create_enumerator,
                    290:                        .check = _check,
                    291:                        .verify = _verify,
                    292:                        .destroy = _destroy,
                    293:                },
                    294:                .request_id = request_id,
                    295:                .list = linked_list_create(),
                    296:        );
                    297: 
                    298:        return &this->public;
                    299: }
                    300: 
                    301: /**
                    302:  * Hash a file with a given absolute pathname
                    303:  */
                    304: static bool hash_file(hasher_t *hasher, char *pathname, u_char *hash)
                    305: {
                    306:        u_char buffer[4096];
                    307:        size_t bytes_read;
                    308:        bool success = TRUE;
                    309:        FILE *file;
                    310: 
                    311:        file = fopen(pathname, "rb");
                    312:        if (!file)
                    313:        {
                    314:                DBG1(DBG_PTS,"  file '%s' can not be opened, %s", pathname,
                    315:                         strerror(errno));
                    316:                return FALSE;
                    317:        }
                    318:        while (TRUE)
                    319:        {
                    320:                bytes_read = fread(buffer, 1, sizeof(buffer), file);
                    321:                if (bytes_read > 0)
                    322:                {
                    323:                        if (!hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL))
                    324:                        {
                    325:                                DBG1(DBG_PTS, "  hasher increment error");
                    326:                                success = FALSE;
                    327:                                break;
                    328:                        }
                    329:                }
                    330:                else
                    331:                {
                    332:                        if (!hasher->get_hash(hasher, chunk_empty, hash))
                    333:                        {
                    334:                                DBG1(DBG_PTS, "  hasher finalize error");
                    335:                                success = FALSE;
                    336:                        }
                    337:                        break;
                    338:                }
                    339:        }
                    340:        fclose(file);
                    341: 
                    342:        return success;
                    343: }
                    344: 
                    345: /**
                    346:  * See header
                    347:  */
                    348: pts_file_meas_t *pts_file_meas_create_from_path(uint16_t request_id,
                    349:                                                        char *pathname, bool is_dir, bool use_rel_name,
                    350:                                                        pts_meas_algorithms_t alg)
                    351: {
                    352:        private_pts_file_meas_t *this;
                    353:        hash_algorithm_t hash_alg;
                    354:        hasher_t *hasher;
                    355:        u_char hash[HASH_SIZE_SHA384];
                    356:        chunk_t measurement;
                    357:        char* filename;
                    358:        bool success = TRUE;
                    359: 
                    360:        /* Create a hasher and a hash measurement buffer */
                    361:        hash_alg = pts_meas_algo_to_hash(alg);
                    362:        hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
                    363:        if (!hasher)
                    364:        {
                    365:                DBG1(DBG_PTS, "hasher %N not available", hash_algorithm_names, hash_alg);
                    366:                return NULL;
                    367:        }
                    368:        measurement = chunk_create(hash, hasher->get_hash_size(hasher));
                    369:        this = (private_pts_file_meas_t*)pts_file_meas_create(request_id);
                    370: 
                    371:        if (is_dir)
                    372:        {
                    373:                enumerator_t *enumerator;
                    374:                char *rel_name, *abs_name;
                    375:                struct stat st;
                    376: 
                    377:                enumerator = enumerator_create_directory(pathname);
                    378:                if (!enumerator)
                    379:                {
                    380:                        DBG1(DBG_PTS, "  directory '%s' can not be opened, %s", pathname,
                    381:                                 strerror(errno));
                    382:                        success = FALSE;
                    383:                        goto end;
                    384:                }
                    385:                while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
                    386:                {
                    387:                        /* measure regular files only */
                    388:                        if (S_ISREG(st.st_mode) && *rel_name != '.')
                    389:                        {
                    390:                                if (!hash_file(hasher, abs_name, hash))
                    391:                                {
                    392:                                        continue;
                    393:                                }
                    394:                                filename = use_rel_name ? rel_name : abs_name;
                    395:                                DBG2(DBG_PTS, "  %#B for '%s'", &measurement, filename);
                    396:                                add(this, filename, measurement);
                    397:                        }
                    398:                }
                    399:                enumerator->destroy(enumerator);
                    400:        }
                    401:        else
                    402:        {
                    403:                if (!hash_file(hasher, pathname, hash))
                    404:                {
                    405:                        success = FALSE;
                    406:                        goto end;
                    407:                }
                    408:                filename = use_rel_name ? path_basename(pathname) : strdup(pathname);
                    409:                DBG2(DBG_PTS, "  %#B for '%s'", &measurement, filename);
                    410:                add(this, filename, measurement);
                    411:                free(filename);
                    412:        }
                    413: 
                    414: end:
                    415:        hasher->destroy(hasher);
                    416:        if (success)
                    417:        {
                    418:                return &this->public;
                    419:        }
                    420:        else
                    421:        {
                    422:                destroy(this);
                    423:                return NULL;
                    424:        }
                    425: }

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