Return to adopt_children_job.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / processing / jobs |
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: }