Annotation of embedaddon/strongswan/src/libcharon/plugins/systime_fix/systime_fix_plugin.c, revision 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, ¬_before, ¬_after))
! 103: {
! 104: DBG1(DBG_CFG, "certificate '%Y' invalid "
! 105: "(valid from %T to %T)", cert->get_subject(cert),
! 106: ¬_before, FALSE, ¬_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>