Annotation of embedaddon/strongswan/src/libimcv/plugins/imc_scanner/imc_scanner.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2011-2015 Andreas Steffen
        !             3:  * HSR Hochschule fuer Technik Rapperswil
        !             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 "imc_scanner_state.h"
        !            17: 
        !            18: #include <imc/imc_agent.h>
        !            19: #include <imc/imc_msg.h>
        !            20: #include <ietf/ietf_attr.h>
        !            21: #include <ietf/ietf_attr_attr_request.h>
        !            22: #include <ietf/ietf_attr_port_filter.h>
        !            23: 
        !            24: #include <tncif_pa_subtypes.h>
        !            25: 
        !            26: #include <pen/pen.h>
        !            27: #include <utils/lexparser.h>
        !            28: #include <utils/debug.h>
        !            29: 
        !            30: #include <stdio.h>
        !            31: 
        !            32: /* IMC definitions */
        !            33: 
        !            34: static const char imc_name[] = "Scanner";
        !            35: 
        !            36: static pen_type_t msg_types[] = {
        !            37:        { PEN_IETF, PA_SUBTYPE_IETF_FIREWALL }
        !            38: };
        !            39: 
        !            40: static imc_agent_t *imc_scanner;
        !            41: 
        !            42: /**
        !            43:  * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
        !            44:  */
        !            45: TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
        !            46:                                                          TNC_Version min_version,
        !            47:                                                          TNC_Version max_version,
        !            48:                                                          TNC_Version *actual_version)
        !            49: {
        !            50:        if (imc_scanner)
        !            51:        {
        !            52:                DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
        !            53:                return TNC_RESULT_ALREADY_INITIALIZED;
        !            54:        }
        !            55:        imc_scanner = imc_agent_create(imc_name, msg_types, countof(msg_types),
        !            56:                                                                   imc_id, actual_version);
        !            57:        if (!imc_scanner)
        !            58:        {
        !            59:                return TNC_RESULT_FATAL;
        !            60:        }
        !            61:        if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
        !            62:        {
        !            63:                DBG1(DBG_IMC, "no common IF-IMC version");
        !            64:                return TNC_RESULT_NO_COMMON_VERSION;
        !            65:        }
        !            66:        return TNC_RESULT_SUCCESS;
        !            67: }
        !            68: 
        !            69: /**
        !            70:  * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
        !            71:  */
        !            72: TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
        !            73:                                                                                  TNC_ConnectionID connection_id,
        !            74:                                                                                  TNC_ConnectionState new_state)
        !            75: {
        !            76:        imc_state_t *state;
        !            77: 
        !            78:        if (!imc_scanner)
        !            79:        {
        !            80:                DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
        !            81:                return TNC_RESULT_NOT_INITIALIZED;
        !            82:        }
        !            83:        switch (new_state)
        !            84:        {
        !            85:                case TNC_CONNECTION_STATE_CREATE:
        !            86:                        state = imc_scanner_state_create(connection_id);
        !            87:                        return imc_scanner->create_state(imc_scanner, state);
        !            88:                case TNC_CONNECTION_STATE_DELETE:
        !            89:                        return imc_scanner->delete_state(imc_scanner, connection_id);
        !            90:                default:
        !            91:                        return imc_scanner->change_state(imc_scanner, connection_id,
        !            92:                                                                                         new_state, NULL);
        !            93:        }
        !            94: }
        !            95: 
        !            96: /**
        !            97:  * Determine all TCP and UDP server sockets listening on physical interfaces
        !            98:  */
        !            99: static bool do_netstat(ietf_attr_port_filter_t *attr)
        !           100: {
        !           101:        FILE *file;
        !           102:        char buf[BUF_LEN];
        !           103:        chunk_t line, token;
        !           104:        int n = 0;
        !           105:        bool success = FALSE;
        !           106:        const char system_v4[]   = "127.0.1.1";
        !           107:        const char loopback_v4[] = "127.0.0.1";
        !           108:        const char loopback_v6[] = "::1";
        !           109: 
        !           110:        /* Open a pipe stream for reading the output of the netstat command */
        !           111:        file = popen("/bin/netstat -n -l -p -4 -6 --inet", "r");
        !           112:        if (!file)
        !           113:        {
        !           114:                DBG1(DBG_IMC, "failed to run netstat command");
        !           115:                return FALSE;
        !           116:        }
        !           117: 
        !           118:        /* Read the output a line at a time */
        !           119:        while (fgets(buf, sizeof(buf), file))
        !           120:        {
        !           121:                u_char *pos;
        !           122:                uint8_t new_protocol, protocol;
        !           123:                uint16_t new_port, port;
        !           124:                int i;
        !           125:                enumerator_t *enumerator;
        !           126:                bool allowed, found = FALSE;
        !           127: 
        !           128:                DBG2(DBG_IMC, "%.*s", (int)(strlen(buf)-1), buf);
        !           129: 
        !           130:                if (n++ < 2)
        !           131:                {
        !           132:                        /* skip the first two header lines */
        !           133:                        continue;
        !           134:                }
        !           135:                line = chunk_create(buf, strlen(buf));
        !           136: 
        !           137:                /* Extract the IP protocol type */
        !           138:                if (!extract_token(&token, ' ', &line))
        !           139:                {
        !           140:                        DBG1(DBG_IMC, "protocol field in netstat output not found");
        !           141:                        goto end;
        !           142:                }
        !           143:                if (match("tcp", &token) || match("tcp6", &token))
        !           144:                {
        !           145:                        new_protocol = IPPROTO_TCP;
        !           146:                }
        !           147:                else if (match("udp", &token) || match("udp6", &token))
        !           148:                {
        !           149:                        new_protocol = IPPROTO_UDP;
        !           150:                }
        !           151:                else
        !           152:                {
        !           153:                        DBG1(DBG_IMC, "skipped unknown IP protocol in netstat output");
        !           154:                        continue;
        !           155:                }
        !           156: 
        !           157:                /* Skip the Recv-Q and Send-Q fields */
        !           158:                for (i = 0; i < 3; i++)
        !           159:                {
        !           160:                        if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
        !           161:                        {
        !           162:                                token = chunk_empty;
        !           163:                                break;
        !           164:                        }
        !           165:                }
        !           166:                if (token.len == 0)
        !           167:                {
        !           168:                        DBG1(DBG_IMC, "local address field in netstat output not found");
        !           169:                        goto end;
        !           170:                }
        !           171: 
        !           172:                /* Find the local port appended to the local address */
        !           173:                pos = token.ptr + token.len;
        !           174:                while (*--pos != ':' && --token.len);
        !           175:                if (*pos != ':')
        !           176:                {
        !           177:                        DBG1(DBG_IMC, "local port field in netstat output not found");
        !           178:                        goto end;
        !           179:                }
        !           180:                token.len--;
        !           181: 
        !           182:                /* ignore ports of IPv4 and IPv6 loopback interfaces
        !           183:                   and the internal system IPv4 address */
        !           184:                if ((token.len == strlen(system_v4) &&
        !           185:                                memeq(system_v4, token.ptr, token.len)) ||
        !           186:                        (token.len == strlen(loopback_v4) &&
        !           187:                                memeq(loopback_v4, token.ptr, token.len)) ||
        !           188:                        (token.len == strlen(loopback_v6) &&
        !           189:                                memeq(loopback_v6, token.ptr, token.len)))
        !           190:                {
        !           191:                        continue;
        !           192:                }
        !           193: 
        !           194:                /* convert the port string to an integer */
        !           195:                new_port = atoi(pos+1);
        !           196: 
        !           197:                /* check if the there is already a port entry */
        !           198:                enumerator = attr->create_port_enumerator(attr);
        !           199:                while (enumerator->enumerate(enumerator, &allowed, &protocol, &port))
        !           200:                {
        !           201:                        if (new_port == port && new_protocol == protocol)
        !           202:                        {
        !           203:                                found = TRUE;
        !           204:                        }
        !           205:                }
        !           206:                enumerator->destroy(enumerator);
        !           207: 
        !           208:                /* Skip the duplicate port entry */
        !           209:                if (found)
        !           210:                {
        !           211:                        continue;
        !           212:                }
        !           213: 
        !           214:                /* Add new port entry */
        !           215:                attr->add_port(attr, FALSE, new_protocol, new_port);
        !           216:        }
        !           217: 
        !           218:        /* Successfully completed the parsing of the netstat output */
        !           219:        success = TRUE;
        !           220: 
        !           221: end:
        !           222:        /* Close the pipe stream */
        !           223:        pclose(file);
        !           224:        return success;
        !           225: }
        !           226: 
        !           227: /**
        !           228:  * Add IETF Port Filter attribute to the send queue
        !           229:  */
        !           230: static TNC_Result add_port_filter(imc_msg_t *msg)
        !           231: {
        !           232:        pa_tnc_attr_t *attr;
        !           233:        ietf_attr_port_filter_t *attr_port_filter;
        !           234: 
        !           235:        attr = ietf_attr_port_filter_create(pen_type_create(PEN_IETF,
        !           236:                                                                                IETF_ATTR_PORT_FILTER));
        !           237:        attr->set_noskip_flag(attr, TRUE);
        !           238:        attr_port_filter = (ietf_attr_port_filter_t*)attr;
        !           239:        if (!do_netstat(attr_port_filter))
        !           240:        {
        !           241:                attr->destroy(attr);
        !           242:                return TNC_RESULT_FATAL;
        !           243:        }
        !           244:        msg->add_attribute(msg, attr);
        !           245: 
        !           246:        return TNC_RESULT_SUCCESS;
        !           247: }
        !           248: 
        !           249: /**
        !           250:  * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
        !           251:  */
        !           252: TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
        !           253:                                                                  TNC_ConnectionID connection_id)
        !           254: {
        !           255:        imc_state_t *state;
        !           256:        imc_msg_t *out_msg;
        !           257:        TNC_Result result = TNC_RESULT_SUCCESS;
        !           258: 
        !           259:        if (!imc_scanner)
        !           260:        {
        !           261:                DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
        !           262:                return TNC_RESULT_NOT_INITIALIZED;
        !           263:        }
        !           264:        if (!imc_scanner->get_state(imc_scanner, connection_id, &state))
        !           265:        {
        !           266:                return TNC_RESULT_FATAL;
        !           267:        }
        !           268:        if (lib->settings->get_bool(lib->settings,
        !           269:                                                        "%s.plugins.imc-scanner.push_info", TRUE, lib->ns))
        !           270:        {
        !           271:                out_msg = imc_msg_create(imc_scanner, state, connection_id, imc_id,
        !           272:                                                                 TNC_IMVID_ANY, msg_types[0]);
        !           273:                result = add_port_filter(out_msg);
        !           274:                if (result == TNC_RESULT_SUCCESS)
        !           275:                {
        !           276:                        /* send PA-TNC message with the excl flag not set */
        !           277:                        result = out_msg->send(out_msg, FALSE);
        !           278:                }
        !           279:                out_msg->destroy(out_msg);
        !           280:        }
        !           281: 
        !           282:        return result;
        !           283: }
        !           284: 
        !           285: static TNC_Result receive_message(imc_msg_t *in_msg)
        !           286: {
        !           287:        imc_msg_t *out_msg;
        !           288:        enumerator_t *enumerator;
        !           289:        pa_tnc_attr_t *attr;
        !           290:        pen_type_t attr_type;
        !           291:        TNC_Result result = TNC_RESULT_SUCCESS;
        !           292:        bool fatal_error = FALSE;
        !           293: 
        !           294:        /* generate an outgoing PA-TNC message - we might need it */
        !           295:        out_msg = imc_msg_create_as_reply(in_msg);
        !           296: 
        !           297:        /* parse received PA-TNC message and handle local and remote errors */
        !           298:        result = in_msg->receive(in_msg, out_msg, &fatal_error);
        !           299:        if (result != TNC_RESULT_SUCCESS)
        !           300:        {
        !           301:                out_msg->destroy(out_msg);
        !           302:                return result;
        !           303:        }
        !           304: 
        !           305:        /* analyze PA-TNC attributes */
        !           306:        enumerator = in_msg->create_attribute_enumerator(in_msg);
        !           307:        while (enumerator->enumerate(enumerator, &attr))
        !           308:        {
        !           309:                attr_type = attr->get_type(attr);
        !           310: 
        !           311:                if (attr_type.vendor_id != PEN_IETF)
        !           312:                {
        !           313:                        continue;
        !           314:                }
        !           315:                if (attr_type.type == IETF_ATTR_ATTRIBUTE_REQUEST)
        !           316:                {
        !           317:                        ietf_attr_attr_request_t *attr_cast;
        !           318:                        pen_type_t *entry;
        !           319:                        enumerator_t *e;
        !           320: 
        !           321:                        attr_cast = (ietf_attr_attr_request_t*)attr;
        !           322: 
        !           323:                        e = attr_cast->create_enumerator(attr_cast);
        !           324:                        while (e->enumerate(e, &entry))
        !           325:                        {
        !           326:                                if (entry->vendor_id != PEN_IETF)
        !           327:                                {
        !           328:                                        continue;
        !           329:                                }
        !           330:                                switch (entry->type)
        !           331:                                {
        !           332:                                        case IETF_ATTR_PORT_FILTER:
        !           333:                                                result = add_port_filter(out_msg);
        !           334:                                                break;
        !           335:                                        default:
        !           336:                                                break;
        !           337:                                }
        !           338:                        }
        !           339:                        e->destroy(e);
        !           340:                }
        !           341:        }
        !           342:        enumerator->destroy(enumerator);
        !           343: 
        !           344:        if (fatal_error)
        !           345:        {
        !           346:                result = TNC_RESULT_FATAL;
        !           347:        }
        !           348:        else if (result == TNC_RESULT_SUCCESS)
        !           349:        {
        !           350:                /* send PA-TNC message with the EXCL flag set */
        !           351:                result = out_msg->send(out_msg, TRUE);
        !           352:        }
        !           353:        out_msg->destroy(out_msg);
        !           354: 
        !           355:        return result;
        !           356: }
        !           357: 
        !           358: /**
        !           359:  * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
        !           360: 
        !           361:  */
        !           362: TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
        !           363:                                                                  TNC_ConnectionID connection_id,
        !           364:                                                                  TNC_BufferReference msg,
        !           365:                                                                  TNC_UInt32 msg_len,
        !           366:                                                                  TNC_MessageType msg_type)
        !           367: {
        !           368:        imc_state_t *state;
        !           369:        imc_msg_t *in_msg;
        !           370:        TNC_Result result;
        !           371: 
        !           372:        if (!imc_scanner)
        !           373:        {
        !           374:                DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
        !           375:                return TNC_RESULT_NOT_INITIALIZED;
        !           376:        }
        !           377:        if (!imc_scanner->get_state(imc_scanner, connection_id, &state))
        !           378:        {
        !           379:                return TNC_RESULT_FATAL;
        !           380:        }
        !           381: 
        !           382:        in_msg = imc_msg_create_from_data(imc_scanner, state, connection_id,
        !           383:                                                                          msg_type, chunk_create(msg, msg_len));
        !           384:        result = receive_message(in_msg);
        !           385:        in_msg->destroy(in_msg);
        !           386: 
        !           387:        return result;
        !           388: }
        !           389: 
        !           390: /**
        !           391:  * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
        !           392:  */
        !           393: TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
        !           394:                                                                          TNC_ConnectionID connection_id,
        !           395:                                                                          TNC_UInt32 msg_flags,
        !           396:                                                                          TNC_BufferReference msg,
        !           397:                                                                          TNC_UInt32 msg_len,
        !           398:                                                                          TNC_VendorID msg_vid,
        !           399:                                                                          TNC_MessageSubtype msg_subtype,
        !           400:                                                                          TNC_UInt32 src_imv_id,
        !           401:                                                                          TNC_UInt32 dst_imc_id)
        !           402: {
        !           403:        imc_state_t *state;
        !           404:        imc_msg_t *in_msg;
        !           405:        TNC_Result result;
        !           406: 
        !           407:        if (!imc_scanner)
        !           408:        {
        !           409:                DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
        !           410:                return TNC_RESULT_NOT_INITIALIZED;
        !           411:        }
        !           412:        if (!imc_scanner->get_state(imc_scanner, connection_id, &state))
        !           413:        {
        !           414:                return TNC_RESULT_FATAL;
        !           415:        }
        !           416:        in_msg = imc_msg_create_from_long_data(imc_scanner, state, connection_id,
        !           417:                                                                src_imv_id, dst_imc_id, msg_vid, msg_subtype,
        !           418:                                                                chunk_create(msg, msg_len));
        !           419:        result = receive_message(in_msg);
        !           420:        in_msg->destroy(in_msg);
        !           421: 
        !           422:        return result;
        !           423: }
        !           424: 
        !           425: /**
        !           426:  * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
        !           427:  */
        !           428: TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
        !           429:                                                           TNC_ConnectionID connection_id)
        !           430: {
        !           431:        if (!imc_scanner)
        !           432:        {
        !           433:                DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
        !           434:                return TNC_RESULT_NOT_INITIALIZED;
        !           435:        }
        !           436:        return TNC_RESULT_SUCCESS;
        !           437: }
        !           438: 
        !           439: /**
        !           440:  * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
        !           441:  */
        !           442: TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
        !           443: {
        !           444:        if (!imc_scanner)
        !           445:        {
        !           446:                DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
        !           447:                return TNC_RESULT_NOT_INITIALIZED;
        !           448:        }
        !           449:        imc_scanner->destroy(imc_scanner);
        !           450:        imc_scanner = NULL;
        !           451: 
        !           452:        return TNC_RESULT_SUCCESS;
        !           453: }
        !           454: 
        !           455: /**
        !           456:  * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
        !           457:  */
        !           458: TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
        !           459:                                                                           TNC_TNCC_BindFunctionPointer bind_function)
        !           460: {
        !           461:        if (!imc_scanner)
        !           462:        {
        !           463:                DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
        !           464:                return TNC_RESULT_NOT_INITIALIZED;
        !           465:        }
        !           466:        return imc_scanner->bind_functions(imc_scanner, bind_function);
        !           467: }

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