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, ¬_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>