Annotation of embedaddon/strongswan/src/libcharon/processing/jobs/adopt_children_job.c, revision 1.1.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>