Annotation of embedaddon/strongswan/src/libcharon/processing/jobs/adopt_children_job.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2015 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * Copyright (C) 2012 Martin Willi
! 6: * Copyright (C) 2012 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 "adopt_children_job.h"
! 20:
! 21: #include <daemon.h>
! 22: #include <collections/array.h>
! 23: #include <processing/jobs/delete_ike_sa_job.h>
! 24:
! 25: typedef struct private_adopt_children_job_t private_adopt_children_job_t;
! 26:
! 27: /**
! 28: * Private data of an adopt_children_job_t object.
! 29: */
! 30: struct private_adopt_children_job_t {
! 31:
! 32: /**
! 33: * Public adopt_children_job_t interface.
! 34: */
! 35: adopt_children_job_t public;
! 36:
! 37: /**
! 38: * IKE_SA id to adopt children from
! 39: */
! 40: ike_sa_id_t *id;
! 41:
! 42: /**
! 43: * Tasks queued for execution
! 44: */
! 45: array_t *tasks;
! 46: };
! 47:
! 48: METHOD(job_t, destroy, void,
! 49: private_adopt_children_job_t *this)
! 50: {
! 51: array_destroy_offset(this->tasks, offsetof(task_t, destroy));
! 52: this->id->destroy(this->id);
! 53: free(this);
! 54: }
! 55:
! 56: METHOD(adopt_children_job_t, queue_task, void,
! 57: private_adopt_children_job_t *this, task_t *task)
! 58: {
! 59: array_insert_create(&this->tasks, ARRAY_TAIL, task);
! 60: }
! 61:
! 62: /**
! 63: * Adopt child-creating tasks from the given IKE_SA
! 64: */
! 65: static u_int adopt_child_tasks(private_adopt_children_job_t *this,
! 66: ike_sa_t *ike_sa, task_queue_t queue)
! 67: {
! 68: enumerator_t *tasks;
! 69: task_t *task;
! 70: u_int count = 0;
! 71:
! 72: tasks = ike_sa->create_task_enumerator(ike_sa, queue);
! 73: while (tasks->enumerate(tasks, &task))
! 74: {
! 75: if (task->get_type(task) == TASK_QUICK_MODE)
! 76: {
! 77: ike_sa->remove_task(ike_sa, tasks);
! 78: queue_task(this, task);
! 79: count++;
! 80: }
! 81: }
! 82: tasks->destroy(tasks);
! 83: return count;
! 84: }
! 85:
! 86: METHOD(job_t, execute, job_requeue_t,
! 87: private_adopt_children_job_t *this)
! 88: {
! 89: identification_t *my_id, *other_id, *xauth;
! 90: host_t *me, *other, *vip;
! 91: peer_cfg_t *cfg;
! 92: linked_list_t *children, *vips;
! 93: enumerator_t *enumerator, *subenum;
! 94: ike_sa_id_t *id;
! 95: ike_sa_t *ike_sa;
! 96: child_sa_t *child_sa;
! 97: uint32_t unique;
! 98: u_int tasks = 0;
! 99:
! 100: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->id);
! 101: if (ike_sa)
! 102: {
! 103: /* get what we need from new SA */
! 104: unique = ike_sa->get_unique_id(ike_sa);
! 105: me = ike_sa->get_my_host(ike_sa);
! 106: me = me->clone(me);
! 107: other = ike_sa->get_other_host(ike_sa);
! 108: other = other->clone(other);
! 109: my_id = ike_sa->get_my_id(ike_sa);
! 110: my_id = my_id->clone(my_id);
! 111: other_id = ike_sa->get_other_id(ike_sa);
! 112: other_id = other_id->clone(other_id);
! 113: xauth = ike_sa->get_other_eap_id(ike_sa);
! 114: xauth = xauth->clone(xauth);
! 115: cfg = ike_sa->get_peer_cfg(ike_sa);
! 116: cfg->get_ref(cfg);
! 117:
! 118: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
! 119:
! 120: /* find old SA to adopt children and virtual IPs from */
! 121: vips = linked_list_create();
! 122: children = linked_list_create();
! 123: enumerator = charon->ike_sa_manager->create_id_enumerator(
! 124: charon->ike_sa_manager, my_id, xauth,
! 125: other->get_family(other));
! 126: while (enumerator->enumerate(enumerator, &id))
! 127: {
! 128: if (id->equals(id, this->id))
! 129: { /* not from self */
! 130: continue;
! 131: }
! 132: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
! 133: if (ike_sa)
! 134: {
! 135: if ((ike_sa->get_state(ike_sa) == IKE_ESTABLISHED ||
! 136: ike_sa->get_state(ike_sa) == IKE_PASSIVE) &&
! 137: me->equals(me, ike_sa->get_my_host(ike_sa)) &&
! 138: other->equals(other, ike_sa->get_other_host(ike_sa)) &&
! 139: other_id->equals(other_id, ike_sa->get_other_id(ike_sa)) &&
! 140: cfg->equals(cfg, ike_sa->get_peer_cfg(ike_sa)))
! 141: {
! 142: charon->bus->children_migrate(charon->bus, this->id, unique);
! 143: subenum = ike_sa->create_child_sa_enumerator(ike_sa);
! 144: while (subenum->enumerate(subenum, &child_sa))
! 145: {
! 146: ike_sa->remove_child_sa(ike_sa, subenum);
! 147: children->insert_last(children, child_sa);
! 148: }
! 149: subenum->destroy(subenum);
! 150:
! 151: subenum = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
! 152: while (subenum->enumerate(subenum, &vip))
! 153: {
! 154: vips->insert_last(vips, vip->clone(vip));
! 155: }
! 156: subenum->destroy(subenum);
! 157: /* this does not release the addresses, which is good, but
! 158: * it does trigger an assign_vips(FALSE) event, so we also
! 159: * trigger one below */
! 160: ike_sa->clear_virtual_ips(ike_sa, FALSE);
! 161:
! 162: tasks += adopt_child_tasks(this, ike_sa, TASK_QUEUE_ACTIVE);
! 163: tasks += adopt_child_tasks(this, ike_sa, TASK_QUEUE_QUEUED);
! 164:
! 165: if (children->get_count(children) || tasks ||
! 166: vips->get_count(vips))
! 167: {
! 168: DBG1(DBG_IKE, "detected reauth of existing IKE_SA, "
! 169: "adopting %d children, %d child tasks, and %d "
! 170: "virtual IPs", children->get_count(children),
! 171: tasks, vips->get_count(vips));
! 172: }
! 173: if (ike_sa->get_state(ike_sa) == IKE_PASSIVE)
! 174: {
! 175: charon->ike_sa_manager->checkin_and_destroy(
! 176: charon->ike_sa_manager, ike_sa);
! 177: }
! 178: else
! 179: {
! 180: lib->scheduler->schedule_job(lib->scheduler, (job_t*)
! 181: delete_ike_sa_job_create(ike_sa->get_id(ike_sa),
! 182: TRUE), 10);
! 183: charon->ike_sa_manager->checkin(
! 184: charon->ike_sa_manager, ike_sa);
! 185: }
! 186: }
! 187: else
! 188: {
! 189: charon->ike_sa_manager->checkin(
! 190: charon->ike_sa_manager, ike_sa);
! 191: }
! 192: if (children->get_count(children) || tasks ||
! 193: vips->get_count(vips))
! 194: {
! 195: break;
! 196: }
! 197: }
! 198: }
! 199: enumerator->destroy(enumerator);
! 200:
! 201: me->destroy(me);
! 202: other->destroy(other);
! 203: my_id->destroy(my_id);
! 204: other_id->destroy(other_id);
! 205: xauth->destroy(xauth);
! 206: cfg->destroy(cfg);
! 207:
! 208: if (children->get_count(children) || vips->get_count(vips))
! 209: {
! 210: /* adopt children by new SA */
! 211: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
! 212: this->id);
! 213: if (ike_sa)
! 214: {
! 215: while (children->remove_last(children,
! 216: (void**)&child_sa) == SUCCESS)
! 217: {
! 218: ike_sa->add_child_sa(ike_sa, child_sa);
! 219: }
! 220: if (vips->get_count(vips))
! 221: {
! 222: while (vips->remove_first(vips, (void**)&vip) == SUCCESS)
! 223: {
! 224: ike_sa->add_virtual_ip(ike_sa, FALSE, vip);
! 225: vip->destroy(vip);
! 226: }
! 227: charon->bus->assign_vips(charon->bus, ike_sa, TRUE);
! 228: }
! 229: charon->bus->children_migrate(charon->bus, NULL, 0);
! 230: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
! 231: }
! 232: }
! 233: children->destroy_offset(children, offsetof(child_sa_t, destroy));
! 234: /* FIXME: If we still have addresses here it means we weren't able to
! 235: * find the new SA anymore (while not very likely during a proper
! 236: * reauthentication, this theoretically could happen because the SA is
! 237: * not locked while we search for the old one). So the addresses here
! 238: * should be released properly to avoid leaking these leases. This is
! 239: * currently not possible, though, due to the changed interface of
! 240: * release_address(), which now takes a complete IKE_SA object. */
! 241: vips->destroy_offset(vips, offsetof(host_t, destroy));
! 242:
! 243: if (array_count(this->tasks))
! 244: {
! 245: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
! 246: this->id);
! 247: if (ike_sa)
! 248: {
! 249: task_t *task;
! 250:
! 251: while (array_remove(this->tasks, ARRAY_HEAD, &task))
! 252: {
! 253: task->migrate(task, ike_sa);
! 254: ike_sa->queue_task(ike_sa, task);
! 255: }
! 256: if (ike_sa->initiate(ike_sa, NULL, 0, NULL, NULL) == DESTROY_ME)
! 257: {
! 258: charon->ike_sa_manager->checkin_and_destroy(
! 259: charon->ike_sa_manager, ike_sa);
! 260: }
! 261: else
! 262: {
! 263: charon->ike_sa_manager->checkin(charon->ike_sa_manager,
! 264: ike_sa);
! 265: }
! 266: }
! 267: }
! 268: }
! 269: return JOB_REQUEUE_NONE;
! 270: }
! 271:
! 272: METHOD(job_t, get_priority, job_priority_t,
! 273: private_adopt_children_job_t *this)
! 274: {
! 275: return JOB_PRIO_HIGH;
! 276: }
! 277:
! 278: /**
! 279: * See header
! 280: */
! 281: adopt_children_job_t *adopt_children_job_create(ike_sa_id_t *id)
! 282: {
! 283: private_adopt_children_job_t *this;
! 284:
! 285: INIT(this,
! 286: .public = {
! 287: .job_interface = {
! 288: .execute = _execute,
! 289: .get_priority = _get_priority,
! 290: .destroy = _destroy,
! 291: },
! 292: .queue_task = _queue_task,
! 293: },
! 294: .id = id->clone(id),
! 295: );
! 296:
! 297: return &this->public;
! 298: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>