Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/tasks/xauth.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2011 Martin Willi
        !             3:  * Copyright (C) 2011 revosec AG
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify it
        !             6:  * under the terms of the GNU General Public License as published by the
        !             7:  * Free Software Foundation; either version 2 of the License, or (at your
        !             8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !             9:  *
        !            10:  * This program is distributed in the hope that it will be useful, but
        !            11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            13:  * for more details.
        !            14:  */
        !            15: 
        !            16: #include "xauth.h"
        !            17: 
        !            18: #include <daemon.h>
        !            19: #include <encoding/payloads/cp_payload.h>
        !            20: #include <processing/jobs/adopt_children_job.h>
        !            21: #include <sa/ikev1/tasks/mode_config.h>
        !            22: 
        !            23: typedef struct private_xauth_t private_xauth_t;
        !            24: 
        !            25: /**
        !            26:  * Status types exchanged
        !            27:  */
        !            28: typedef enum {
        !            29:        XAUTH_FAILED = 0,
        !            30:        XAUTH_OK = 1,
        !            31: } xauth_status_t;
        !            32: 
        !            33: /**
        !            34:  * Private members of a xauth_t task.
        !            35:  */
        !            36: struct private_xauth_t {
        !            37: 
        !            38:        /**
        !            39:         * Public methods and task_t interface.
        !            40:         */
        !            41:        xauth_t public;
        !            42: 
        !            43:        /**
        !            44:         * Assigned IKE_SA.
        !            45:         */
        !            46:        ike_sa_t *ike_sa;
        !            47: 
        !            48:        /**
        !            49:         * Are we the XAUTH initiator?
        !            50:         */
        !            51:        bool initiator;
        !            52: 
        !            53:        /**
        !            54:         * XAuth backend to use
        !            55:         */
        !            56:        xauth_method_t *xauth;
        !            57: 
        !            58:        /**
        !            59:         * XAuth username
        !            60:         */
        !            61:        identification_t *user;
        !            62: 
        !            63:        /**
        !            64:         * Generated configuration payload
        !            65:         */
        !            66:        cp_payload_t *cp;
        !            67: 
        !            68:        /**
        !            69:         * received identifier
        !            70:         */
        !            71:        uint16_t identifier;
        !            72: 
        !            73:        /**
        !            74:         * status of Xauth exchange
        !            75:         */
        !            76:        xauth_status_t status;
        !            77: 
        !            78:        /**
        !            79:         * Queue a Mode Config Push mode after completing XAuth?
        !            80:         */
        !            81:        bool mode_config_push;
        !            82: };
        !            83: 
        !            84: /**
        !            85:  * Load XAuth backend
        !            86:  */
        !            87: static xauth_method_t *load_method(private_xauth_t* this)
        !            88: {
        !            89:        identification_t *server, *peer;
        !            90:        enumerator_t *enumerator;
        !            91:        xauth_method_t *xauth;
        !            92:        xauth_role_t role;
        !            93:        peer_cfg_t *peer_cfg;
        !            94:        auth_cfg_t *auth;
        !            95:        char *name;
        !            96: 
        !            97:        if (this->initiator)
        !            98:        {
        !            99:                server = this->ike_sa->get_my_id(this->ike_sa);
        !           100:                peer = this->ike_sa->get_other_id(this->ike_sa);
        !           101:                role = XAUTH_SERVER;
        !           102:        }
        !           103:        else
        !           104:        {
        !           105:                peer = this->ike_sa->get_my_id(this->ike_sa);
        !           106:                server = this->ike_sa->get_other_id(this->ike_sa);
        !           107:                role = XAUTH_PEER;
        !           108:        }
        !           109:        peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
        !           110:        enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !this->initiator);
        !           111:        if (!enumerator->enumerate(enumerator, &auth) ||
        !           112:                (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
        !           113:        {
        !           114:                if (!enumerator->enumerate(enumerator, &auth) ||
        !           115:                        (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
        !           116:                {
        !           117:                        DBG1(DBG_CFG, "no XAuth authentication round found");
        !           118:                        enumerator->destroy(enumerator);
        !           119:                        return NULL;
        !           120:                }
        !           121:        }
        !           122:        name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND);
        !           123:        this->user = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY);
        !           124:        enumerator->destroy(enumerator);
        !           125:        if (!this->initiator && this->user)
        !           126:        {       /* use XAUTH username, if configured */
        !           127:                peer = this->user;
        !           128:        }
        !           129:        xauth = charon->xauth->create_instance(charon->xauth, name, role,
        !           130:                                                                                   server, peer);
        !           131:        if (!xauth)
        !           132:        {
        !           133:                if (name)
        !           134:                {
        !           135:                        DBG1(DBG_CFG, "no XAuth method found for '%s'", name);
        !           136:                }
        !           137:                else
        !           138:                {
        !           139:                        DBG1(DBG_CFG, "no XAuth method found");
        !           140:                }
        !           141:        }
        !           142:        return xauth;
        !           143: }
        !           144: 
        !           145: /**
        !           146:  * Check if XAuth connection is allowed to succeed
        !           147:  */
        !           148: static bool allowed(private_xauth_t *this)
        !           149: {
        !           150:        if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager,
        !           151:                                                                                                 this->ike_sa, FALSE))
        !           152:        {
        !           153:                DBG1(DBG_IKE, "cancelling XAuth due to uniqueness policy");
        !           154:                return FALSE;
        !           155:        }
        !           156:        if (!charon->bus->authorize(charon->bus, FALSE))
        !           157:        {
        !           158:                DBG1(DBG_IKE, "XAuth authorization hook forbids IKE_SA, cancelling");
        !           159:                return FALSE;
        !           160:        }
        !           161:        if (!charon->bus->authorize(charon->bus, TRUE))
        !           162:        {
        !           163:                DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling");
        !           164:                return FALSE;
        !           165:        }
        !           166:        return TRUE;
        !           167: }
        !           168: 
        !           169: /**
        !           170:  * Set IKE_SA to established state
        !           171:  */
        !           172: static bool establish(private_xauth_t *this)
        !           173: {
        !           174:        DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
        !           175:                 this->ike_sa->get_name(this->ike_sa),
        !           176:                 this->ike_sa->get_unique_id(this->ike_sa),
        !           177:                 this->ike_sa->get_my_host(this->ike_sa),
        !           178:                 this->ike_sa->get_my_id(this->ike_sa),
        !           179:                 this->ike_sa->get_other_host(this->ike_sa),
        !           180:                 this->ike_sa->get_other_id(this->ike_sa));
        !           181: 
        !           182:        this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
        !           183:        charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
        !           184: 
        !           185:        return TRUE;
        !           186: }
        !           187: 
        !           188: /**
        !           189:  * Check if we are compliant to a given peer config
        !           190:  */
        !           191: static bool is_compliant(private_xauth_t *this, peer_cfg_t *peer_cfg, bool log)
        !           192: {
        !           193:        bool complies = TRUE;
        !           194:        enumerator_t *e1, *e2;
        !           195:        auth_cfg_t *c1, *c2;
        !           196: 
        !           197:        e1 = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
        !           198:        e2 = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, FALSE);
        !           199:        while (e1->enumerate(e1, &c1))
        !           200:        {
        !           201:                if (!e2->enumerate(e2, &c2) || !c2->complies(c2, c1, log))
        !           202:                {
        !           203:                        complies = FALSE;
        !           204:                        break;
        !           205:                }
        !           206:        }
        !           207:        e1->destroy(e1);
        !           208:        e2->destroy(e2);
        !           209: 
        !           210:        return complies;
        !           211: }
        !           212: 
        !           213: /**
        !           214:  * Check if we are compliant to current config, switch to another if not
        !           215:  */
        !           216: static bool select_compliant_config(private_xauth_t *this)
        !           217: {
        !           218:        peer_cfg_t *peer_cfg = NULL, *old, *current;
        !           219:        identification_t *my_id, *other_id;
        !           220:        host_t *my_host, *other_host;
        !           221:        enumerator_t *enumerator;
        !           222:        bool aggressive;
        !           223: 
        !           224:        old = this->ike_sa->get_peer_cfg(this->ike_sa);
        !           225:        if (is_compliant(this, old, TRUE))
        !           226:        {       /* current config is fine */
        !           227:                return TRUE;
        !           228:        }
        !           229:        DBG1(DBG_CFG, "selected peer config '%s' unacceptable",
        !           230:                 old->get_name(old));
        !           231:        aggressive = old->use_aggressive(old);
        !           232: 
        !           233:        my_host = this->ike_sa->get_my_host(this->ike_sa);
        !           234:        other_host = this->ike_sa->get_other_host(this->ike_sa);
        !           235:        my_id = this->ike_sa->get_my_id(this->ike_sa);
        !           236:        other_id = this->ike_sa->get_other_id(this->ike_sa);
        !           237:        enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
        !           238:                                                                my_host, other_host, my_id, other_id, IKEV1);
        !           239:        while (enumerator->enumerate(enumerator, &current))
        !           240:        {
        !           241:                if (!current->equals(current, old) &&
        !           242:                        current->use_aggressive(current) == aggressive &&
        !           243:                        is_compliant(this, current, FALSE))
        !           244:                {
        !           245:                        peer_cfg = current;
        !           246:                        break;
        !           247:                }
        !           248:        }
        !           249:        if (peer_cfg)
        !           250:        {
        !           251:                DBG1(DBG_CFG, "switching to peer config '%s'",
        !           252:                         peer_cfg->get_name(peer_cfg));
        !           253:                this->ike_sa->set_peer_cfg(this->ike_sa, peer_cfg);
        !           254:        }
        !           255:        else
        !           256:        {
        !           257:                DBG1(DBG_CFG, "no alternative config found");
        !           258:        }
        !           259:        enumerator->destroy(enumerator);
        !           260: 
        !           261:        return peer_cfg != NULL;
        !           262: }
        !           263: 
        !           264: /**
        !           265:  * Create auth config after successful authentication
        !           266:  */
        !           267: static bool add_auth_cfg(private_xauth_t *this, identification_t *id, bool local)
        !           268: {
        !           269:        auth_cfg_t *auth;
        !           270: 
        !           271:        auth = auth_cfg_create();
        !           272:        auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
        !           273:        if (id)
        !           274:        {
        !           275:                auth->add(auth, AUTH_RULE_XAUTH_IDENTITY, id->clone(id));
        !           276:        }
        !           277:        auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), FALSE);
        !           278:        this->ike_sa->add_auth_cfg(this->ike_sa, local, auth);
        !           279: 
        !           280:        return select_compliant_config(this);
        !           281: }
        !           282: 
        !           283: METHOD(task_t, build_i_status, status_t,
        !           284:        private_xauth_t *this, message_t *message)
        !           285: {
        !           286:        cp_payload_t *cp;
        !           287: 
        !           288:        cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_SET);
        !           289:        cp->add_attribute(cp,
        !           290:                        configuration_attribute_create_value(XAUTH_STATUS, this->status));
        !           291: 
        !           292:        message->add_payload(message, (payload_t *)cp);
        !           293: 
        !           294:        return NEED_MORE;
        !           295: }
        !           296: 
        !           297: METHOD(task_t, process_i_status, status_t,
        !           298:        private_xauth_t *this, message_t *message)
        !           299: {
        !           300:        cp_payload_t *cp;
        !           301:        adopt_children_job_t *job;
        !           302: 
        !           303:        cp = (cp_payload_t*)message->get_payload(message, PLV1_CONFIGURATION);
        !           304:        if (!cp || cp->get_type(cp) != CFG_ACK)
        !           305:        {
        !           306:                DBG1(DBG_IKE, "received invalid XAUTH status response");
        !           307:                return FAILED;
        !           308:        }
        !           309:        if (this->status != XAUTH_OK)
        !           310:        {
        !           311:                DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication");
        !           312:                return FAILED;
        !           313:        }
        !           314:        if (!establish(this))
        !           315:        {
        !           316:                return FAILED;
        !           317:        }
        !           318:        this->ike_sa->set_condition(this->ike_sa, COND_XAUTH_AUTHENTICATED, TRUE);
        !           319:        job = adopt_children_job_create(this->ike_sa->get_id(this->ike_sa));
        !           320:        if (this->mode_config_push)
        !           321:        {
        !           322:                job->queue_task(job,
        !           323:                                (task_t*)mode_config_create(this->ike_sa, TRUE, FALSE));
        !           324:        }
        !           325:        lib->processor->queue_job(lib->processor, (job_t*)job);
        !           326:        return SUCCESS;
        !           327: }
        !           328: 
        !           329: METHOD(task_t, build_i, status_t,
        !           330:        private_xauth_t *this, message_t *message)
        !           331: {
        !           332:        if (!this->xauth)
        !           333:        {
        !           334:                cp_payload_t *cp = NULL;
        !           335: 
        !           336:                this->xauth = load_method(this);
        !           337:                if (!this->xauth)
        !           338:                {
        !           339:                        return FAILED;
        !           340:                }
        !           341:                switch (this->xauth->initiate(this->xauth, &cp))
        !           342:                {
        !           343:                        case NEED_MORE:
        !           344:                                break;
        !           345:                        case SUCCESS:
        !           346:                                DESTROY_IF(cp);
        !           347:                                if (add_auth_cfg(this, NULL, FALSE) && allowed(this))
        !           348:                                {
        !           349:                                        this->status = XAUTH_OK;
        !           350:                                }
        !           351:                                this->public.task.process = _process_i_status;
        !           352:                                return build_i_status(this, message);
        !           353:                        default:
        !           354:                                return FAILED;
        !           355:                }
        !           356:                message->add_payload(message, (payload_t *)cp);
        !           357:                return NEED_MORE;
        !           358:        }
        !           359: 
        !           360:        if (this->cp)
        !           361:        {       /* send previously generated payload */
        !           362:                message->add_payload(message, (payload_t *)this->cp);
        !           363:                this->cp = NULL;
        !           364:                return NEED_MORE;
        !           365:        }
        !           366:        return FAILED;
        !           367: }
        !           368: 
        !           369: METHOD(task_t, build_r_ack, status_t,
        !           370:        private_xauth_t *this, message_t *message)
        !           371: {
        !           372:        cp_payload_t *cp;
        !           373: 
        !           374:        cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_ACK);
        !           375:        cp->set_identifier(cp, this->identifier);
        !           376:        cp->add_attribute(cp,
        !           377:                        configuration_attribute_create_chunk(
        !           378:                                        PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_STATUS, chunk_empty));
        !           379: 
        !           380:        message->add_payload(message, (payload_t *)cp);
        !           381: 
        !           382:        if (this->status == XAUTH_OK && allowed(this) && establish(this))
        !           383:        {
        !           384:                return SUCCESS;
        !           385:        }
        !           386:        return FAILED;
        !           387: }
        !           388: 
        !           389: METHOD(task_t, process_r, status_t,
        !           390:        private_xauth_t *this, message_t *message)
        !           391: {
        !           392:        cp_payload_t *cp;
        !           393: 
        !           394:        if (!this->xauth)
        !           395:        {
        !           396:                this->xauth = load_method(this);
        !           397:                if (!this->xauth)
        !           398:                {       /* send empty reply */
        !           399:                        return NEED_MORE;
        !           400:                }
        !           401:        }
        !           402:        cp = (cp_payload_t*)message->get_payload(message, PLV1_CONFIGURATION);
        !           403:        if (!cp)
        !           404:        {
        !           405:                DBG1(DBG_IKE, "configuration payload missing in XAuth request");
        !           406:                return FAILED;
        !           407:        }
        !           408:        if (cp->get_type(cp) == CFG_REQUEST)
        !           409:        {
        !           410:                switch (this->xauth->process(this->xauth, cp, &this->cp))
        !           411:                {
        !           412:                        case NEED_MORE:
        !           413:                                return NEED_MORE;
        !           414:                        case SUCCESS:
        !           415:                        case FAILED:
        !           416:                        default:
        !           417:                                break;
        !           418:                }
        !           419:                this->cp = NULL;
        !           420:                return NEED_MORE;
        !           421:        }
        !           422:        if (cp->get_type(cp) == CFG_SET)
        !           423:        {
        !           424:                configuration_attribute_t *attribute;
        !           425:                enumerator_t *enumerator;
        !           426: 
        !           427:                enumerator = cp->create_attribute_enumerator(cp);
        !           428:                while (enumerator->enumerate(enumerator, &attribute))
        !           429:                {
        !           430:                        if (attribute->get_type(attribute) == XAUTH_STATUS)
        !           431:                        {
        !           432:                                this->status = attribute->get_value(attribute);
        !           433:                        }
        !           434:                }
        !           435:                enumerator->destroy(enumerator);
        !           436:                if (this->status == XAUTH_OK &&
        !           437:                        add_auth_cfg(this, this->xauth->get_identity(this->xauth), TRUE))
        !           438:                {
        !           439:                        DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) successful",
        !           440:                                 this->xauth->get_identity(this->xauth));
        !           441:                }
        !           442:                else
        !           443:                {
        !           444:                        DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) failed",
        !           445:                                 this->xauth->get_identity(this->xauth));
        !           446:                }
        !           447:        }
        !           448:        this->identifier = cp->get_identifier(cp);
        !           449:        this->public.task.build = _build_r_ack;
        !           450:        return NEED_MORE;
        !           451: }
        !           452: 
        !           453: METHOD(task_t, build_r, status_t,
        !           454:        private_xauth_t *this, message_t *message)
        !           455: {
        !           456:        if (!this->cp)
        !           457:        {       /* send empty reply if building data failed */
        !           458:                this->cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REPLY);
        !           459:        }
        !           460:        message->add_payload(message, (payload_t *)this->cp);
        !           461:        this->cp = NULL;
        !           462:        return NEED_MORE;
        !           463: }
        !           464: 
        !           465: METHOD(task_t, process_i, status_t,
        !           466:        private_xauth_t *this, message_t *message)
        !           467: {
        !           468:        identification_t *id;
        !           469:        cp_payload_t *cp;
        !           470: 
        !           471:        cp = (cp_payload_t*)message->get_payload(message, PLV1_CONFIGURATION);
        !           472:        if (!cp)
        !           473:        {
        !           474:                DBG1(DBG_IKE, "configuration payload missing in XAuth response");
        !           475:                return FAILED;
        !           476:        }
        !           477:        switch (this->xauth->process(this->xauth, cp, &this->cp))
        !           478:        {
        !           479:                case NEED_MORE:
        !           480:                        return NEED_MORE;
        !           481:                case SUCCESS:
        !           482:                        id = this->xauth->get_identity(this->xauth);
        !           483:                        DBG1(DBG_IKE, "XAuth authentication of '%Y' successful", id);
        !           484:                        if (add_auth_cfg(this, id, FALSE) && allowed(this))
        !           485:                        {
        !           486:                                this->status = XAUTH_OK;
        !           487:                        }
        !           488:                        break;
        !           489:                case FAILED:
        !           490:                        DBG1(DBG_IKE, "XAuth authentication of '%Y' failed",
        !           491:                                 this->xauth->get_identity(this->xauth));
        !           492:                        break;
        !           493:                default:
        !           494:                        return FAILED;
        !           495:        }
        !           496:        this->public.task.build = _build_i_status;
        !           497:        this->public.task.process = _process_i_status;
        !           498:        return NEED_MORE;
        !           499: }
        !           500: 
        !           501: METHOD(task_t, get_type, task_type_t,
        !           502:        private_xauth_t *this)
        !           503: {
        !           504:        return TASK_XAUTH;
        !           505: }
        !           506: 
        !           507: METHOD(task_t, migrate, void,
        !           508:        private_xauth_t *this, ike_sa_t *ike_sa)
        !           509: {
        !           510:        DESTROY_IF(this->xauth);
        !           511:        DESTROY_IF(this->cp);
        !           512: 
        !           513:        this->ike_sa = ike_sa;
        !           514:        this->xauth = NULL;
        !           515:        this->cp = NULL;
        !           516:        this->user = NULL;
        !           517:        this->status = XAUTH_FAILED;
        !           518: 
        !           519:        if (this->initiator)
        !           520:        {
        !           521:                this->public.task.build = _build_i;
        !           522:                this->public.task.process = _process_i;
        !           523:        }
        !           524:        else
        !           525:        {
        !           526:                this->public.task.build = _build_r;
        !           527:                this->public.task.process = _process_r;
        !           528:        }
        !           529: }
        !           530: 
        !           531: METHOD(xauth_t, queue_mode_config_push, void,
        !           532:        private_xauth_t *this)
        !           533: {
        !           534:        this->mode_config_push = TRUE;
        !           535: }
        !           536: 
        !           537: METHOD(task_t, destroy, void,
        !           538:        private_xauth_t *this)
        !           539: {
        !           540:        DESTROY_IF(this->xauth);
        !           541:        DESTROY_IF(this->cp);
        !           542:        free(this);
        !           543: }
        !           544: 
        !           545: /*
        !           546:  * Described in header.
        !           547:  */
        !           548: xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator)
        !           549: {
        !           550:        private_xauth_t *this;
        !           551: 
        !           552:        INIT(this,
        !           553:                .public = {
        !           554:                        .task = {
        !           555:                                .get_type = _get_type,
        !           556:                                .migrate = _migrate,
        !           557:                                .destroy = _destroy,
        !           558:                        },
        !           559:                        .queue_mode_config_push = _queue_mode_config_push,
        !           560:                },
        !           561:                .initiator = initiator,
        !           562:                .ike_sa = ike_sa,
        !           563:                .status = XAUTH_FAILED,
        !           564:        );
        !           565: 
        !           566:        if (initiator)
        !           567:        {
        !           568:                this->public.task.build = _build_i;
        !           569:                this->public.task.process = _process_i;
        !           570:        }
        !           571:        else
        !           572:        {
        !           573:                this->public.task.build = _build_r;
        !           574:                this->public.task.process = _process_r;
        !           575:        }
        !           576:        return &this->public;
        !           577: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>