Annotation of embedaddon/strongswan/src/libimcv/imv/imv_database.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2013-2015 Andreas Steffen
        !             3:  * HSR Hochschule fuer Technik Rapperswil
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify it
        !             6:  * under the terms of the GNU General Public License as published by the
        !             7:  * Free Software Foundation; either version 2 of the License, or (at your
        !             8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !             9:  *
        !            10:  * This program is distributed in the hope that it will be useful, but
        !            11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            13:  * for more details.
        !            14:  */
        !            15: 
        !            16: #define _GNU_SOURCE
        !            17: 
        !            18: #include <stdio.h>
        !            19: #include <stdarg.h>
        !            20: #include <string.h>
        !            21: #include <time.h>
        !            22: 
        !            23: #include "imv_database.h"
        !            24: 
        !            25: #include <tncif_identity.h>
        !            26: 
        !            27: #include <utils/debug.h>
        !            28: #include <threading/mutex.h>
        !            29: 
        !            30: typedef struct private_imv_database_t private_imv_database_t;
        !            31: 
        !            32: /**
        !            33:  * Private data of a imv_database_t object.
        !            34:  */
        !            35: struct private_imv_database_t {
        !            36: 
        !            37:        /**
        !            38:         * Public imv_database_t interface.
        !            39:         */
        !            40:        imv_database_t public;
        !            41: 
        !            42:        /**
        !            43:         * database instance
        !            44:         */
        !            45:        database_t *db;
        !            46: 
        !            47:        /**
        !            48:         * policy script
        !            49:         */
        !            50:        char *script;
        !            51: 
        !            52: };
        !            53: 
        !            54: METHOD(imv_database_t, get_database, database_t*,
        !            55:        private_imv_database_t *this)
        !            56: {
        !            57:        return this->db;
        !            58: }
        !            59: 
        !            60: /**
        !            61:  * Create a session entry in the IMV database
        !            62:  */
        !            63: static bool create_session(private_imv_database_t *this, imv_session_t *session)
        !            64: {
        !            65:        enumerator_t *enumerator, *e;
        !            66:        imv_os_info_t *os_info;
        !            67:        chunk_t device_id;
        !            68:        tncif_identity_t *tnc_id;
        !            69:        TNC_ConnectionID conn_id;
        !            70:        char *product, *device;
        !            71:        int session_id = 0, pid = 0, did = 0, trusted = 0, created;
        !            72:        bool first = TRUE, success = TRUE;
        !            73: 
        !            74:        /* get product info string */
        !            75:        os_info = session->get_os_info(session);
        !            76:        product = os_info->get_info(os_info);
        !            77:        if (!product)
        !            78:        {
        !            79:                DBG1(DBG_IMV, "imv_db: product info is not available");
        !            80:                return FALSE;
        !            81:        }
        !            82: 
        !            83:        /* get primary key of product info string if it exists */
        !            84:        e = this->db->query(this->db,
        !            85:                        "SELECT id FROM products WHERE name = ?", DB_TEXT, product, DB_INT);
        !            86:        if (e)
        !            87:        {
        !            88:                e->enumerate(e, &pid);
        !            89:                e->destroy(e);
        !            90:        }
        !            91: 
        !            92:        /* if product info string has not been found - register it */
        !            93:        if (!pid)
        !            94:        {
        !            95:                this->db->execute(this->db, &pid,
        !            96:                        "INSERT INTO products (name) VALUES (?)", DB_TEXT, product);
        !            97:        }
        !            98: 
        !            99:        if (!pid)
        !           100:        {
        !           101:                DBG1(DBG_IMV, "imv_db: registering product info failed");
        !           102:                return FALSE;
        !           103:        }
        !           104: 
        !           105:        /* get device ID string */
        !           106:        if (!session->get_device_id(session, &device_id))
        !           107:        {
        !           108:                DBG1(DBG_IMV, "imv_db: device ID is not available");
        !           109:                return FALSE;
        !           110:        }
        !           111:        device = strndup(device_id.ptr, device_id.len);
        !           112: 
        !           113:        /* get primary key of device ID if it exists */
        !           114:        e = this->db->query(this->db,
        !           115:                        "SELECT id, trusted FROM devices WHERE value = ? AND product = ?",
        !           116:                         DB_TEXT, device, DB_INT, pid, DB_INT, DB_INT);
        !           117:        if (e)
        !           118:        {
        !           119:                e->enumerate(e, &did, &trusted);
        !           120:                e->destroy(e);
        !           121:        }
        !           122: 
        !           123:        /* if device ID is trusted, set trust in session */
        !           124:        if (trusted)
        !           125:        {
        !           126:                session->set_device_trust(session, TRUE);
        !           127:        }
        !           128: 
        !           129:        /* if device ID has not been found - register it */
        !           130:        if (!did)
        !           131:        {
        !           132:                this->db->execute(this->db, &did,
        !           133:                        "INSERT INTO devices "
        !           134:                        "(value, description, product, trusted, inactive) "
        !           135:                        "VALUES (?, '', ?, 0, 0)", DB_TEXT, device, DB_INT, pid);
        !           136:        }
        !           137:        free(device);
        !           138: 
        !           139:        if (!did)
        !           140:        {
        !           141:                DBG1(DBG_IMV, "imv_db: registering device ID failed");
        !           142:                return FALSE;
        !           143:        }
        !           144: 
        !           145:        /* create a new session entry */
        !           146:        created = time(NULL);
        !           147:        conn_id = session->get_connection_id(session);
        !           148:        this->db->execute(this->db, &session_id,
        !           149:                        "INSERT INTO sessions (time, connection, product, device) "
        !           150:                        "VALUES (?, ?, ?, ?)",
        !           151:                        DB_INT, created, DB_INT, conn_id, DB_INT, pid, DB_INT, did);
        !           152: 
        !           153:        if (session_id)
        !           154:        {
        !           155:                DBG2(DBG_IMV, "assigned session ID %d to Connection ID %d",
        !           156:                                           session_id, conn_id);
        !           157:        }
        !           158:        else
        !           159:        {
        !           160:                DBG1(DBG_IMV, "imv_db: registering session failed");
        !           161:                return FALSE;
        !           162:        }
        !           163:        session->set_session_id(session, session_id, pid, did);
        !           164:        session->set_creation_time(session, created);
        !           165: 
        !           166:        enumerator = session->create_ar_identities_enumerator(session);
        !           167:        while (enumerator->enumerate(enumerator, &tnc_id))
        !           168:        {
        !           169:                pen_type_t ar_id_type;
        !           170:                chunk_t ar_id_value;
        !           171:                int ar_id = 0, si_id = 0;
        !           172: 
        !           173:                ar_id_type = tnc_id->get_identity_type(tnc_id);
        !           174:                ar_id_value = tnc_id->get_identity_value(tnc_id);
        !           175: 
        !           176:                if (ar_id_type.vendor_id != PEN_TCG || ar_id_value.len == 0)
        !           177:                {
        !           178:                        continue;
        !           179:                }
        !           180: 
        !           181:                /* get primary key of AR identity if it exists */
        !           182:                e = this->db->query(this->db,
        !           183:                                "SELECT id FROM identities WHERE type = ? AND value = ?",
        !           184:                                DB_INT, ar_id_type.type, DB_BLOB, ar_id_value, DB_INT);
        !           185:                if (e)
        !           186:                {
        !           187:                        e->enumerate(e, &ar_id);
        !           188:                        e->destroy(e);
        !           189:                }
        !           190: 
        !           191:                /* if AR identity has not been found - register it */
        !           192:                if (!ar_id)
        !           193:                {
        !           194:                        this->db->execute(this->db, &ar_id,
        !           195:                                "INSERT INTO identities (type, value) VALUES (?, ?)",
        !           196:                                 DB_INT, ar_id_type.type, DB_BLOB, ar_id_value);
        !           197:                }
        !           198:                if (!ar_id)
        !           199:                {
        !           200:                        DBG1(DBG_IMV, "imv_db: registering access requestor failed");
        !           201:                        success = FALSE;
        !           202:                        break;
        !           203:                }
        !           204: 
        !           205:                this->db->execute(this->db, &si_id,
        !           206:                                "INSERT INTO sessions_identities (session_id, identity_id) "
        !           207:                                "VALUES (?, ?)",
        !           208:                                 DB_INT, session_id, DB_INT, ar_id);
        !           209: 
        !           210:                if (!si_id)
        !           211:                {
        !           212:                        DBG1(DBG_IMV, "imv_db: assigning identity to session failed");
        !           213:                        success = FALSE;
        !           214:                        break;
        !           215:                }
        !           216: 
        !           217:                if (first)
        !           218:                {
        !           219:                        this->db->execute(this->db, NULL,
        !           220:                                "UPDATE sessions SET identity = ? WHERE id = ?",
        !           221:                                 DB_INT, ar_id, DB_INT, session_id);
        !           222:                        first = FALSE;
        !           223:                }
        !           224:        }
        !           225:        enumerator->destroy(enumerator);
        !           226: 
        !           227:        return success;
        !           228: }
        !           229: 
        !           230: static bool add_workitems(private_imv_database_t *this, imv_session_t *session)
        !           231: {
        !           232:        char *arg_str;
        !           233:        int id, arg_int, rec_fail, rec_noresult;
        !           234:        imv_workitem_t *workitem;
        !           235:        imv_workitem_type_t type;
        !           236:        enumerator_t *e;
        !           237: 
        !           238:        e = this->db->query(this->db,
        !           239:                        "SELECT id, type, arg_str, arg_int, rec_fail, rec_noresult "
        !           240:                        "FROM workitems WHERE session = ?",
        !           241:                         DB_INT, session->get_session_id(session, NULL, NULL),
        !           242:                         DB_INT, DB_INT, DB_TEXT, DB_INT,DB_INT, DB_INT);
        !           243:        if (!e)
        !           244:        {
        !           245:                DBG1(DBG_IMV, "imv_db: no workitem enumerator returned");
        !           246:                return FALSE;
        !           247:        }
        !           248:        while (e->enumerate(e, &id, &type, &arg_str, &arg_int, &rec_fail,
        !           249:                                                   &rec_noresult))
        !           250:        {
        !           251:                DBG2(DBG_IMV, "%N workitem %d", imv_workitem_type_names, type, id);
        !           252:                workitem = imv_workitem_create(id, type, arg_str, arg_int, rec_fail,
        !           253:                                                                           rec_noresult);
        !           254:                session->insert_workitem(session, workitem);
        !           255:        }
        !           256:        e->destroy(e);
        !           257: 
        !           258:        return TRUE;
        !           259: }
        !           260: 
        !           261: METHOD(imv_database_t, add_recommendation, void,
        !           262:        private_imv_database_t *this, imv_session_t *session,
        !           263:        TNC_IMV_Action_Recommendation rec)
        !           264: {
        !           265:        /* add final recommendation to session DB entry */
        !           266:        this->db->execute(this->db, NULL,
        !           267:                        "UPDATE sessions SET rec = ? WHERE id = ?",
        !           268:                         DB_INT, rec, DB_INT, session->get_session_id(session, NULL, NULL));
        !           269: }
        !           270: 
        !           271: METHOD(imv_database_t, policy_script, bool,
        !           272:        private_imv_database_t *this, imv_session_t *session, bool start)
        !           273: {
        !           274:        char command[512], resp[128], *last;
        !           275:        FILE *shell;
        !           276: 
        !           277:        if (start)
        !           278:        {
        !           279:                if (session->get_policy_started(session))
        !           280:                {
        !           281:                        DBG1(DBG_IMV, "policy script as already been started");
        !           282:                        return FALSE;
        !           283:                }
        !           284: 
        !           285:                /* add product info and device ID to session DB entry */
        !           286:                if (!create_session(this, session))
        !           287:                {
        !           288:                        return FALSE;
        !           289:                }
        !           290:        }
        !           291:        else
        !           292:        {
        !           293:                if (!session->get_policy_started(session))
        !           294:                {
        !           295:                        DBG1(DBG_IMV, "policy script as already been stopped");
        !           296:                        return FALSE;
        !           297:                }
        !           298:        }
        !           299: 
        !           300:        /* call the policy script */
        !           301:        snprintf(command, sizeof(command), "2>&1 %s %s %d",
        !           302:                         this->script, start ? "start" : "stop",
        !           303:                         session->get_session_id(session, NULL, NULL));
        !           304:        DBG3(DBG_IMV, "running policy script: %s", command);
        !           305: 
        !           306:        shell = popen(command, "r");
        !           307:        if (shell == NULL)
        !           308:        {
        !           309:                DBG1(DBG_IMV, "could not execute policy script '%s'",
        !           310:                         this->script);
        !           311:                return FALSE;
        !           312:        }
        !           313:        while (TRUE)
        !           314:        {
        !           315:                if (fgets(resp, sizeof(resp), shell) == NULL)
        !           316:                {
        !           317:                        if (ferror(shell))
        !           318:                        {
        !           319:                                DBG1(DBG_IMV, "error reading output from policy script");
        !           320:                        }
        !           321:                        break;
        !           322:                }
        !           323:                else
        !           324:                {
        !           325:                        last = resp + strlen(resp) - 1;
        !           326:                        if (last >= resp && *last == '\n')
        !           327:                        {
        !           328:                                /* replace trailing '\n' */
        !           329:                                *last = '\0';
        !           330:                        }
        !           331:                        DBG1(DBG_IMV, "policy: %s", resp);
        !           332:                }
        !           333:        }
        !           334:        pclose(shell);
        !           335: 
        !           336:        if (start)
        !           337:        {
        !           338:                /* add workitem list generated by policy manager to session object */
        !           339:                if (!add_workitems(this, session))
        !           340:                {
        !           341:                        return FALSE;
        !           342:                }
        !           343:                session->set_policy_started(session, TRUE);
        !           344:        }
        !           345:        else
        !           346:        {
        !           347:                session->set_policy_started(session, FALSE);
        !           348:        }
        !           349: 
        !           350:        return TRUE;
        !           351: }
        !           352: 
        !           353: METHOD(imv_database_t, finalize_workitem, bool,
        !           354:        private_imv_database_t *this, imv_workitem_t *workitem)
        !           355: {
        !           356:        char *result;
        !           357:        int rec;
        !           358: 
        !           359:        rec = workitem->get_result(workitem, &result);
        !           360: 
        !           361:        return this->db->execute(this->db, NULL,
        !           362:                                "UPDATE workitems SET result = ?, rec_final = ? WHERE id = ?",
        !           363:                                DB_TEXT, result, DB_INT, rec,
        !           364:                                DB_INT, workitem->get_id(workitem)) == 1;
        !           365: }
        !           366: 
        !           367: METHOD(imv_database_t, destroy, void,
        !           368:        private_imv_database_t *this)
        !           369: {
        !           370:        DESTROY_IF(this->db);
        !           371:        free(this);
        !           372: }
        !           373: 
        !           374: /**
        !           375:  * See header
        !           376:  */
        !           377: imv_database_t *imv_database_create(char *uri, char *script)
        !           378: {
        !           379:        private_imv_database_t *this;
        !           380: 
        !           381:        INIT(this,
        !           382:                .public = {
        !           383:                        .get_database = _get_database,
        !           384:                        .policy_script = _policy_script,
        !           385:                        .finalize_workitem = _finalize_workitem,
        !           386:                        .add_recommendation = _add_recommendation,
        !           387:                        .destroy = _destroy,
        !           388:                },
        !           389:                .db = lib->db->create(lib->db, uri),
        !           390:                .script = script,
        !           391:        );
        !           392: 
        !           393:        if (!this->db)
        !           394:        {
        !           395:                DBG1(DBG_IMV,
        !           396:                         "failed to connect to IMV database '%s'", uri);
        !           397:                destroy(this);
        !           398:                return NULL;
        !           399:        }
        !           400: 
        !           401:        return &this->public;
        !           402: }

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