Annotation of embedaddon/strongswan/src/libcharon/plugins/systime_fix/systime_fix_plugin.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2013-2017 Tobias Brunner
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * Copyright (C) 2013 Martin Willi
                      6:  * Copyright (C) 2013 revosec AG
                      7:  *
                      8:  * This program is free software; you can redistribute it and/or modify it
                      9:  * under the terms of the GNU General Public License as published by the
                     10:  * Free Software Foundation; either version 2 of the License, or (at your
                     11:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     12:  *
                     13:  * This program is distributed in the hope that it will be useful, but
                     14:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     15:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     16:  * for more details.
                     17:  */
                     18: 
                     19: #include "systime_fix_plugin.h"
                     20: #include "systime_fix_validator.h"
                     21: 
                     22: #include <daemon.h>
                     23: #include <processing/jobs/callback_job.h>
                     24: #include <processing/jobs/delete_ike_sa_job.h>
                     25: #include <processing/jobs/rekey_ike_sa_job.h>
                     26: 
                     27: #include <time.h>
                     28: 
                     29: /**
                     30:  * Defining _XOPEN_SOURCE is difficult with libstrongswan includes,
                     31:  * declare function explicitly.
                     32:  */
                     33: char *strptime(const char *s, const char *format, struct tm *tm);
                     34: 
                     35: typedef struct private_systime_fix_plugin_t private_systime_fix_plugin_t;
                     36: 
                     37: /**
                     38:  * Private data of systime_fix plugin
                     39:  */
                     40: struct private_systime_fix_plugin_t {
                     41: 
                     42:        /**
                     43:         * Implements plugin interface
                     44:         */
                     45:        systime_fix_plugin_t public;
                     46: 
                     47:        /**
                     48:         * Certificate lifetime validator
                     49:         */
                     50:        systime_fix_validator_t *validator;
                     51: 
                     52:        /**
                     53:         * Interval we check for a now-valid system time, in seconds. 0 if disabled
                     54:         */
                     55:        u_int interval;
                     56: 
                     57:        /**
                     58:         * How long to wait for a valid system time, 0 to wait indefinitely
                     59:         */
                     60:        time_t timeout;
                     61: 
                     62:        /**
                     63:         * Timestamp where we start considering system time valid
                     64:         */
                     65:        time_t threshold;
                     66: 
                     67:        /**
                     68:         * Do we trigger reauth or delete when finding expired certificates?
                     69:         */
                     70:        bool reauth;
                     71: };
                     72: 
                     73: METHOD(plugin_t, get_name, char*,
                     74:        private_systime_fix_plugin_t *this)
                     75: {
                     76:        return "systime-fix";
                     77: }
                     78: 
                     79: /**
                     80:  * Check if all certificates associated to an IKE_SA have valid lifetimes
                     81:  */
                     82: static bool has_invalid_certs(ike_sa_t *ike_sa)
                     83: {
                     84:        enumerator_t *cfgs, *items;
                     85:        certificate_t *cert;
                     86:        auth_rule_t type;
                     87:        auth_cfg_t *auth;
                     88:        time_t not_before, not_after;
                     89:        bool valid = TRUE;
                     90: 
                     91:        cfgs = ike_sa->create_auth_cfg_enumerator(ike_sa, FALSE);
                     92:        while (valid && cfgs->enumerate(cfgs, &auth))
                     93:        {
                     94:                items = auth->create_enumerator(auth);
                     95:                while (valid && items->enumerate(items, &type, &cert))
                     96:                {
                     97:                        switch (type)
                     98:                        {
                     99:                                case AUTH_RULE_SUBJECT_CERT:
                    100:                                case AUTH_RULE_IM_CERT:
                    101:                                case AUTH_RULE_CA_CERT:
                    102:                                        if (!cert->get_validity(cert, NULL, &not_before, &not_after))
                    103:                                        {
                    104:                                                DBG1(DBG_CFG, "certificate '%Y' invalid "
                    105:                                                        "(valid from %T to %T)", cert->get_subject(cert),
                    106:                                                         &not_before, FALSE, &not_after, FALSE);
                    107:                                                valid = FALSE;
                    108:                                        }
                    109:                                        break;
                    110:                                default:
                    111:                                        break;
                    112:                        }
                    113:                }
                    114:                items->destroy(items);
                    115:        }
                    116:        cfgs->destroy(cfgs);
                    117: 
                    118:        if (valid)
                    119:        {
                    120:                DBG1(DBG_CFG, "all certificates have valid lifetimes");
                    121:        }
                    122:        return !valid;
                    123: }
                    124: 
                    125: /**
                    126:  * Check if we reached the timeout
                    127:  */
                    128: static inline bool timeout_reached(private_systime_fix_plugin_t *this)
                    129: {
                    130:        if (this->timeout == 0)
                    131:        {       /* disabled */
                    132:                return FALSE;
                    133:        }
                    134:        if (this->timeout <= this->interval)
                    135:        {
                    136:                return TRUE;
                    137:        }
                    138:        this->timeout -= this->interval;
                    139:        return FALSE;
                    140: }
                    141: 
                    142: /**
                    143:  * Check system time, reevaluate certificates
                    144:  */
                    145: static job_requeue_t check_systime(private_systime_fix_plugin_t *this)
                    146: {
                    147:        enumerator_t *enumerator;
                    148:        ike_sa_t *ike_sa;
                    149:        char *action;
                    150:        job_t *job;
                    151: 
                    152:        if (time(NULL) < this->threshold)
                    153:        {
                    154:                if (!timeout_reached(this))
                    155:                {
                    156:                        DBG2(DBG_CFG, "system time not valid, rechecking in %us",
                    157:                                 this->interval);
                    158:                        return JOB_RESCHEDULE(this->interval);
                    159:                }
                    160:                DBG1(DBG_CFG, "timeout reached while waiting for valid system time, "
                    161:                         "force rechecking certificates");
                    162:                /* force regular lifetime checks for new connections */
                    163:                lib->credmgr->remove_validator(lib->credmgr,
                    164:                                                                           &this->validator->validator);
                    165:        }
                    166:        else
                    167:        {
                    168:                DBG1(DBG_CFG, "system time got valid, rechecking certificates");
                    169:        }
                    170: 
                    171:        enumerator = charon->ike_sa_manager->create_enumerator(
                    172:                                                                                                charon->ike_sa_manager, TRUE);
                    173:        while (enumerator->enumerate(enumerator, &ike_sa))
                    174:        {
                    175:                if (has_invalid_certs(ike_sa))
                    176:                {
                    177:                        if (this->reauth)
                    178:                        {
                    179:                                action = "reauthenticating";
                    180:                                job = &rekey_ike_sa_job_create(ike_sa->get_id(ike_sa),
                    181:                                                                                           TRUE)->job_interface;
                    182:                        }
                    183:                        else
                    184:                        {
                    185:                                action = "deleting";
                    186:                                job = &delete_ike_sa_job_create(ike_sa->get_id(ike_sa),
                    187:                                                                                                TRUE)->job_interface;
                    188:                        }
                    189:                        DBG1(DBG_CFG, "%s[%d] has certificates not valid, %s IKE_SA",
                    190:                                 ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
                    191:                                 action);
                    192:                        lib->processor->queue_job(lib->processor, job);
                    193:                }
                    194:        }
                    195:        enumerator->destroy(enumerator);
                    196: 
                    197:        return JOB_REQUEUE_NONE;
                    198: }
                    199: 
                    200: /**
                    201:  * Load cert lifetime validator configuration
                    202:  */
                    203: static bool load_validator(private_systime_fix_plugin_t *this)
                    204: {
                    205:        struct tm tm = {
                    206:                .tm_mday = 1,
                    207:        };
                    208:        char *str, *fmt, buf[32];
                    209: 
                    210:        fmt = lib->settings->get_str(lib->settings,
                    211:                        "%s.plugins.%s.threshold_format", "%Y", lib->ns, get_name(this));
                    212:        str = lib->settings->get_str(lib->settings,
                    213:                        "%s.plugins.%s.threshold", NULL, lib->ns, get_name(this));
                    214:        if (!str)
                    215:        {
                    216:                DBG1(DBG_CFG, "no threshold configured for %s, disabled",
                    217:                         get_name(this));
                    218:                return FALSE;
                    219:        }
                    220:        if (strptime(str, fmt, &tm) == NULL)
                    221:        {
                    222:                DBG1(DBG_CFG, "threshold for %s invalid, disabled", get_name(this));
                    223:                return FALSE;
                    224:        }
                    225:        this->threshold = mktime(&tm);
                    226:        if (this->threshold == -1)
                    227:        {
                    228:                DBG1(DBG_CFG, "converting threshold for %s failed, disabled",
                    229:                         get_name(this));
                    230:                return FALSE;
                    231:        }
                    232:        if (time(NULL) >= this->threshold)
                    233:        {
                    234:                DBG1(DBG_CFG, "system time looks good, disabling %s", get_name(this));
                    235:                return FALSE;
                    236:        }
                    237: 
                    238:        DBG1(DBG_CFG, "enabling %s, threshold: %s", get_name(this),
                    239:                 asctime_r(&tm, buf));
                    240:        this->validator = systime_fix_validator_create(this->threshold);
                    241:        return TRUE;
                    242: }
                    243: 
                    244: /**
                    245:  * Load validator
                    246:  */
                    247: static bool plugin_cb(private_systime_fix_plugin_t *this,
                    248:                                          plugin_feature_t *feature, bool reg, void *cb_data)
                    249: {
                    250:        if (reg)
                    251:        {
                    252:                if (!load_validator(this))
                    253:                {
                    254:                        return FALSE;
                    255:                }
                    256:                lib->credmgr->add_validator(lib->credmgr, &this->validator->validator);
                    257:                if (this->interval != 0)
                    258:                {
                    259:                        DBG1(DBG_CFG, "starting system time check, interval: %us",
                    260:                                 this->interval);
                    261:                        lib->scheduler->schedule_job(lib->scheduler, (job_t*)
                    262:                                        callback_job_create((callback_job_cb_t)check_systime,
                    263:                                                                                this, NULL, NULL), this->interval);
                    264:                }
                    265:        }
                    266:        else
                    267:        {
                    268:                lib->credmgr->remove_validator(lib->credmgr,
                    269:                                                                           &this->validator->validator);
                    270:                this->validator->destroy(this->validator);
                    271:        }
                    272:        return TRUE;
                    273: }
                    274: 
                    275: METHOD(plugin_t, get_features, int,
                    276:        private_systime_fix_plugin_t *this, plugin_feature_t *features[])
                    277: {
                    278:        static plugin_feature_t f[] = {
                    279:                PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
                    280:                        PLUGIN_PROVIDE(CUSTOM, "systime-fix"),
                    281:        };
                    282:        *features = f;
                    283:        return countof(f);
                    284: }
                    285: 
                    286: METHOD(plugin_t, destroy, void,
                    287:        private_systime_fix_plugin_t *this)
                    288: {
                    289:        free(this);
                    290: }
                    291: 
                    292: /**
                    293:  * Plugin constructor
                    294:  */
                    295: plugin_t *systime_fix_plugin_create()
                    296: {
                    297:        private_systime_fix_plugin_t *this;
                    298: 
                    299:        INIT(this,
                    300:                .public = {
                    301:                        .plugin = {
                    302:                                .get_name = _get_name,
                    303:                                .get_features = _get_features,
                    304:                                .destroy = _destroy,
                    305:                        },
                    306:                },
                    307:                .interval = lib->settings->get_int(lib->settings,
                    308:                                                "%s.plugins.%s.interval", 0, lib->ns, get_name(this)),
                    309:                .timeout = lib->settings->get_time(lib->settings,
                    310:                                                "%s.plugins.%s.timeout", 0, lib->ns, get_name(this)),
                    311:                .reauth = lib->settings->get_bool(lib->settings,
                    312:                                                "%s.plugins.%s.reauth", FALSE, lib->ns, get_name(this)),
                    313:        );
                    314: 
                    315:        return &this->public.plugin;
                    316: }

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