Annotation of embedaddon/strongswan/src/libimcv/imv/imv_database.c, revision 1.1.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>