Annotation of embedaddon/strongswan/src/libimcv/imv/imv_policy_manager.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: #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>