Annotation of embedaddon/strongswan/src/libimcv/imv/imv_policy_manager.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: #include "imv_policy_manager_usage.h"
                     17: #include "imv_workitem.h"
                     18: 
                     19: #include <library.h>
                     20: #include <utils/debug.h>
                     21: 
                     22: #include <tncif_names.h>
                     23: 
                     24: #include <stdlib.h>
                     25: #include <stdio.h>
                     26: #include <time.h>
                     27: 
                     28: /* The default policy group #1 is assumed to always exist */
                     29: #define DEFAULT_GROUP_ID       1
                     30: 
                     31: /**
                     32:  * global debug output variables
                     33:  */
                     34: static int debug_level = 1;
                     35: static bool stderr_quiet = FALSE;
                     36: 
                     37: /**
                     38:  * attest dbg function
                     39:  */
                     40: static void stderr_dbg(debug_t group, level_t level, char *fmt, ...)
                     41: {
                     42:        va_list args;
                     43: 
                     44:        if (level <= debug_level)
                     45:        {
                     46:                if (!stderr_quiet)
                     47:                {
                     48:                        va_start(args, fmt);
                     49:                        vfprintf(stderr, fmt, args);
                     50:                        fprintf(stderr, "\n");
                     51:                        va_end(args);
                     52:                }
                     53:        }
                     54: }
                     55: 
                     56: /**
                     57:  * Collect all enforcements by iterating up through parent groups
                     58:  */
                     59: static bool iterate_enforcements(database_t *db, int device_id, int session_id,
                     60:                                                                 int group_id)
                     61: {
                     62:        int id, type, file, dir, arg_int, parent, policy, max_age;
                     63:        int p_rec_fail, p_rec_noresult, e_rec_fail, e_rec_noresult, latest_rec;
                     64:        bool latest_success;
                     65:        char *argument;
                     66:        time_t now;
                     67:        enumerator_t *e, *e1, *e2;
                     68: 
                     69:        now = time(NULL);
                     70: 
                     71:        while (group_id)
                     72:        {
                     73:                e1 = db->query(db,
                     74:                                "SELECT e.id, p.type, p.argument, p.file, p.dir, p.rec_fail, "
                     75:                                "p.rec_noresult, e.policy, e.max_age, e.rec_fail, e.rec_noresult "
                     76:                                "FROM enforcements AS e JOIN policies as p ON e.policy = p.id "
                     77:                                "WHERE e.group_id = ?", DB_INT, group_id,
                     78:                                 DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT, DB_INT,
                     79:                                 DB_INT, DB_INT, DB_INT, DB_INT);
                     80:                if (!e1)
                     81:                {
                     82:                        return FALSE;
                     83:                }
                     84:                while (e1->enumerate(e1, &id, &type, &argument, &file, &dir,
                     85:                                                                 &p_rec_fail, &p_rec_noresult, &policy, &max_age,
                     86:                                                                 &e_rec_fail, &e_rec_noresult))
                     87:                {
                     88:                        /* check if the latest measurement of the device was successful */
                     89:                        latest_success = FALSE;
                     90: 
                     91:                        if (device_id)
                     92:                        {
                     93:                                e2 = db->query(db,
                     94:                                                "SELECT r.rec FROM results AS r "
                     95:                                                "JOIN sessions AS s ON s.id = r.session "
                     96:                                                "WHERE r.policy = ? AND s.device = ? AND s.time > ? "
                     97:                                                "ORDER BY s.time DESC",
                     98:                                                DB_INT, policy, DB_INT, device_id,
                     99:                                                DB_UINT, now - max_age, DB_INT);
                    100:                                if (!e2)
                    101:                                {
                    102:                                        e1->destroy(e1);
                    103:                                        return FALSE;
                    104:                                }
                    105:                                if (e2->enumerate(e2, &latest_rec) &&
                    106:                                        latest_rec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW)
                    107:                                {
                    108:                                        latest_success = TRUE;
                    109:                                }
                    110:                                e2->destroy(e2);
                    111:                        }
                    112: 
                    113:                        if (latest_success)
                    114:                        {
                    115:                                /*skipping enforcement */
                    116:                                printf("skipping enforcement %d\n", id);
                    117:                                continue;
                    118:                        }
                    119: 
                    120:                        /* determine arg_int */
                    121:                        switch ((imv_workitem_type_t)type)
                    122:                        {
                    123:                                case IMV_WORKITEM_FILE_REF_MEAS:
                    124:                                case IMV_WORKITEM_FILE_MEAS:
                    125:                                case IMV_WORKITEM_FILE_META:
                    126:                                        arg_int = file;
                    127:                                        break;
                    128:                                case IMV_WORKITEM_DIR_REF_MEAS:
                    129:                                case IMV_WORKITEM_DIR_MEAS:
                    130:                                case IMV_WORKITEM_DIR_META:
                    131:                                        arg_int = dir;
                    132:                                        break;
                    133:                                case IMV_WORKITEM_SWID_TAGS:
                    134:                                        /* software [identifier] inventory by default */
                    135:                                        arg_int = 0;
                    136: 
                    137:                                        /* software identifiers only? */
                    138:                                        if (device_id && strchr(argument, 'R'))
                    139:                                        {
                    140:                                                /* get last EID in order to set earliest EID */
                    141:                                                e2 = db->query(db,
                    142:                                                        "SELECT eid FROM swid_events where device == ? "
                    143:                                                        "ORDER BY eid DESC", DB_UINT, device_id, DB_INT);
                    144:                                                if (e2)
                    145:                                                {
                    146:                                                        if (e2->enumerate(e2, &arg_int))
                    147:                                                        {
                    148:                                                                arg_int++;
                    149:                                                        }
                    150:                                                        else
                    151:                                                        {
                    152:                                                                arg_int = 1;
                    153:                                                        }
                    154:                                                        e2->destroy(e2);
                    155:                                                }
                    156:                                        }
                    157:                                        break;
                    158:                                default:
                    159:                                        arg_int = 0;
                    160:                        }
                    161: 
                    162:                        /* insert a workitem */
                    163:                        if (db->execute(db, NULL,
                    164:                                "INSERT INTO workitems (session, enforcement, type, arg_str, "
                    165:                                "arg_int, rec_fail, rec_noresult) VALUES (?, ?, ?, ?, ?, ?, ?)",
                    166:                                DB_INT, session_id, DB_INT, id, DB_INT, type, DB_TEXT, argument,
                    167:                                DB_INT, arg_int, DB_INT, e_rec_fail ? e_rec_fail : p_rec_fail,
                    168:                                DB_INT, e_rec_noresult ? e_rec_noresult : p_rec_noresult) != 1)
                    169:                        {
                    170:                                e1->destroy(e1);
                    171:                                fprintf(stderr, "could not insert workitem\n");
                    172:                                return FALSE;
                    173:                        }
                    174:                }
                    175:                e1->destroy(e1);
                    176: 
                    177:                e = db->query(db,
                    178:                                "SELECT parent FROM groups WHERE id = ?",
                    179:                                 DB_INT, group_id, DB_INT);
                    180:                if (!e)
                    181:                {
                    182:                        return FALSE;
                    183:                }
                    184:                if (e->enumerate(e, &parent))
                    185:                {
                    186:                        group_id = parent;
                    187:                }
                    188:                else
                    189:                {
                    190:                        fprintf(stderr, "group information not found\n");
                    191:                        group_id = 0;
                    192:                }
                    193:                e->destroy(e);
                    194:        }
                    195:        return TRUE;
                    196: }
                    197: 
                    198: static bool policy_start(database_t *db, int session_id)
                    199: {
                    200:        enumerator_t *e;
                    201:        int device_id, product_id, gid, group_id = DEFAULT_GROUP_ID;
                    202:        u_int created;
                    203: 
                    204:        /* get session data */
                    205:        e = db->query(db,
                    206:                        "SELECT s.device, s.product, d.created FROM sessions AS s "
                    207:                        "LEFT JOIN devices AS d ON s.device = d.id WHERE s.id = ?",
                    208:                         DB_INT, session_id, DB_INT, DB_INT, DB_UINT);
                    209:        if (!e || !e->enumerate(e, &device_id, &product_id, &created))
                    210:        {
                    211:                DESTROY_IF(e);
                    212:                fprintf(stderr, "session %d not found\n", session_id);
                    213:                return FALSE;
                    214:        }
                    215:        e->destroy(e);
                    216: 
                    217:        /* if a device ID with a creation date exists, get all group memberships */
                    218:        if (device_id && created)
                    219:        {
                    220:                e = db->query(db,
                    221:                                "SELECT group_id FROM groups_members WHERE device_id = ?",
                    222:                                 DB_INT, device_id, DB_INT);
                    223:                if (!e)
                    224:                {
                    225:                        return FALSE;
                    226:                }
                    227:                while (e->enumerate(e, &group_id))
                    228:                {
                    229:                        if (!iterate_enforcements(db, device_id, session_id, group_id))
                    230:                        {
                    231:                                e->destroy(e);
                    232:                                return FALSE;
                    233:                        }
                    234:                }
                    235:                e->destroy(e);
                    236: 
                    237:                return TRUE;
                    238:        }
                    239: 
                    240:        /* determine if a default product group exists */
                    241:        e = db->query(db,
                    242:                        "SELECT group_id FROM groups_product_defaults "
                    243:                        "WHERE product_id = ?", DB_INT, product_id, DB_INT);
                    244:        if (!e)
                    245:        {
                    246:                return FALSE;
                    247:        }
                    248:        if (e->enumerate(e, &gid))
                    249:        {
                    250:                group_id = gid;
                    251:        }
                    252:        e->destroy(e);
                    253: 
                    254:        if (device_id && !created)
                    255:        {
                    256:                /* assign a newly created device to a default group */
                    257:                if (db->execute(db, NULL,
                    258:                        "INSERT INTO groups_members (device_id, group_id) "
                    259:                        "VALUES (?, ?)", DB_INT, device_id, DB_INT, group_id) != 1)
                    260:                {
                    261:                        fprintf(stderr, "could not assign device to a default group\n");
                    262:                        return FALSE;
                    263:                }
                    264: 
                    265:                /* set the creation date if it hasn't been set yet */
                    266:                if (db->execute(db, NULL,
                    267:                                "UPDATE devices SET created = ? WHERE id = ?",
                    268:                                DB_UINT, time(NULL), DB_INT, device_id) != 1)
                    269:                {
                    270:                        fprintf(stderr, "creation date of device could not be set\n");
                    271:                        return FALSE;
                    272:                }
                    273:        }
                    274: 
                    275:        return iterate_enforcements(db, device_id, session_id, group_id);
                    276: }
                    277: 
                    278: static bool policy_stop(database_t *db, int session_id)
                    279: {
                    280:        enumerator_t *e;
                    281:        int rec, policy, final_rec, id_type;
                    282:        chunk_t id_value;
                    283:        char *result, *format, *ip_address = NULL;
                    284:        char command[512];
                    285:        bool success = TRUE;
                    286: 
                    287:        /* store all workitem results for this session in the results table */
                    288:        e = db->query(db,
                    289:                        "SELECT w.rec_final, w.result, e.policy FROM workitems AS w "
                    290:                        "JOIN enforcements AS e ON w.enforcement = e.id "
                    291:                        "WHERE w.session = ? AND w.result IS NOT NULL",
                    292:                         DB_INT, session_id, DB_INT, DB_TEXT, DB_INT);
                    293:        if (e)
                    294:        {
                    295:                while (e->enumerate(e, &rec, &result, &policy))
                    296:                {
                    297:                        db->execute(db, NULL,
                    298:                                "INSERT INTO results (session, policy, rec, result) "
                    299:                                "VALUES (?, ?, ?, ?)", DB_INT, session_id, DB_INT, policy,
                    300:                                 DB_INT, rec, DB_TEXT, result);
                    301:                }
                    302:                e->destroy(e);
                    303:        }
                    304:        else
                    305:        {
                    306:                success = FALSE;
                    307:        }
                    308: 
                    309:        /* delete all workitems for this session from the database */
                    310:        if (db->execute(db, NULL,
                    311:                                        "DELETE FROM workitems WHERE session = ?",
                    312:                                        DB_UINT, session_id) < 0)
                    313:        {
                    314:                success = FALSE;
                    315:        }
                    316: 
                    317:        final_rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
                    318: 
                    319:        /* retrieve the final recommendation for this session */
                    320:        e = db->query(db,
                    321:                        "SELECT rec FROM sessions WHERE id = ?",
                    322:                         DB_INT, session_id, DB_INT);
                    323:        if (e)
                    324:        {
                    325:                if (!e->enumerate(e, &final_rec))
                    326:                {
                    327:                        success = FALSE;
                    328:                }
                    329:                e->destroy(e);
                    330:        }
                    331:        else
                    332:        {
                    333:                success = FALSE;
                    334:        }
                    335: 
                    336:        /* retrieve client IP address for this session */
                    337:        e = db->query(db,
                    338:                        "SELECT i.type, i.value FROM identities AS i "
                    339:                        "JOIN sessions_identities AS si ON si.identity_id = i.id "
                    340:                        "WHERE si.session_id = ? AND (i.type = ? OR i.type = ?)",
                    341:                         DB_INT, session_id, DB_INT, TNC_ID_IPV4_ADDR, DB_INT,
                    342:                         TNC_ID_IPV6_ADDR, DB_INT, DB_BLOB);
                    343:        if (e)
                    344:        {
                    345:                if (e->enumerate(e, &id_type, &id_value))
                    346:                {
                    347:                        ip_address = strndup(id_value.ptr, id_value.len);
                    348:                }
                    349:                else
                    350:                {
                    351:                        success = FALSE;
                    352:                }
                    353:                e->destroy(e);
                    354:        }
                    355:        else
                    356:        {
                    357:                success = FALSE;
                    358:        }
                    359: 
                    360:        fprintf(stderr, "recommendation for access requestor %s is %N\n",
                    361:                        ip_address ? ip_address : "0.0.0.0",
                    362:                        TNC_IMV_Action_Recommendation_names, final_rec);
                    363: 
                    364:        if (final_rec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW)
                    365:        {
                    366:                format = lib->settings->get_str(lib->settings,
                    367:                                                "imv_policy_manager.command_allow", NULL);
                    368:        }
                    369:        else
                    370:        {
                    371:                format = lib->settings->get_str(lib->settings,
                    372:                                                "imv_policy_manager.command_block", NULL);
                    373:        }
                    374:        if (format && ip_address)
                    375:        {
                    376:                /* the IP address can occur at most twice in the command string */
                    377:                snprintf(command, sizeof(command), format, ip_address, ip_address);
                    378:                success = system(command) == 0;
                    379:                fprintf(stderr, "%s system command: %s\n",
                    380:                            success ? "successful" : "failed", command);
                    381:        }
                    382:        free(ip_address);
                    383: 
                    384:        return success;
                    385: }
                    386: 
                    387: int main(int argc, char *argv[])
                    388: {
                    389:        database_t *db;
                    390:        char *uri;
                    391:        int session_id;
                    392:        bool start, success;
                    393: 
                    394:        /* enable attest debugging hook */
                    395:        dbg = stderr_dbg;
                    396: 
                    397:        atexit(library_deinit);
                    398: 
                    399:        /* initialize library */
                    400:        if (!library_init(NULL, "imv_policy_manager"))
                    401:        {
                    402:                exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
                    403:        }
                    404:        if (!lib->plugins->load(lib->plugins,
                    405:                        lib->settings->get_str(lib->settings, "imv_policy_manager.load",
                    406:                                 "sqlite")))
                    407:        {
                    408:                exit(SS_RC_INITIALIZATION_FAILED);
                    409:        }
                    410: 
                    411:        if (argc < 3)
                    412:        {
                    413:                usage();
                    414:                exit(SS_RC_INITIALIZATION_FAILED);
                    415:        }
                    416:        if (streq(argv[1], "start"))
                    417:        {
                    418:                start = TRUE;
                    419:        }
                    420:        else if (streq(argv[1], "stop"))
                    421:        {
                    422:                start = FALSE;
                    423:        }
                    424:        else
                    425:        {
                    426:                usage();
                    427:                exit(SS_RC_INITIALIZATION_FAILED);
                    428:        }
                    429: 
                    430:        session_id = atoi(argv[2]);
                    431: 
                    432:        /* attach IMV database */
                    433:        uri = lib->settings->get_str(lib->settings,
                    434:                        "imv_policy_manager.database",
                    435:                        lib->settings->get_str(lib->settings,
                    436:                                "charon.imcv.database",
                    437:                                lib->settings->get_str(lib->settings,
                    438:                                        "libimcv.database", NULL)));
                    439:        if (!uri)
                    440:        {
                    441:                fprintf(stderr, "database uri not defined.\n");
                    442:                exit(SS_RC_INITIALIZATION_FAILED);
                    443:        }
                    444: 
                    445:        db = lib->db->create(lib->db, uri);
                    446:        if (!db)
                    447:        {
                    448:                fprintf(stderr, "opening database failed.\n");
                    449:                exit(SS_RC_INITIALIZATION_FAILED);
                    450:        }
                    451: 
                    452:        if (start)
                    453:        {
                    454:                success = policy_start(db, session_id);
                    455:        }
                    456:        else
                    457:        {
                    458:                success = policy_stop(db, session_id);
                    459:        }
                    460:        db->destroy(db);
                    461: 
                    462:        fprintf(stderr, "imv_policy_manager %s %s\n", start ? "start" : "stop",
                    463:                        success ? "successful" : "failed");
                    464: 
                    465:        exit(EXIT_SUCCESS);
                    466: }

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