Annotation of embedaddon/strongswan/src/medsrv/controller/peer_controller.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2008 Martin Willi
                      3:  * Copyright (C) 2008 Philip Boetschi, Adrian Doerig
                      4:  * HSR Hochschule fuer Technik Rapperswil
                      5:  *
                      6:  * This program is free software; you can redistribute it and/or modify it
                      7:  * under the terms of the GNU General Public License as published by the
                      8:  * Free Software Foundation; either version 2 of the License, or (at your
                      9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     10:  *
                     11:  * This program is distributed in the hope that it will be useful, but
                     12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     14:  * for more details.
                     15:  */
                     16: 
                     17: #define _GNU_SOURCE
                     18: #include <string.h>
                     19: 
                     20: #include "peer_controller.h"
                     21: 
                     22: #include <library.h>
                     23: #include <utils/debug.h>
                     24: #include <asn1/asn1.h>
                     25: #include <asn1/oid.h>
                     26: #include <utils/identification.h>
                     27: #include <credentials/keys/public_key.h>
                     28: 
                     29: typedef struct private_peer_controller_t private_peer_controller_t;
                     30: 
                     31: /**
                     32:  * private data of the peer_controller
                     33:  */
                     34: struct private_peer_controller_t {
                     35: 
                     36:        /**
                     37:         * public functions
                     38:         */
                     39:        peer_controller_t public;
                     40: 
                     41:        /**
                     42:         * active user session
                     43:         */
                     44:        user_t *user;
                     45: 
                     46:        /**
                     47:         * underlying database
                     48:         */
                     49:        database_t *db;
                     50: };
                     51: 
                     52: /**
                     53:  * list the configured peer configs
                     54:  */
                     55: static void list(private_peer_controller_t *this, fast_request_t *request)
                     56: {
                     57:        enumerator_t *query;
                     58: 
                     59:        query = this->db->query(this->db,
                     60:                        "SELECT id, alias, keyid FROM peer WHERE user = ? ORDER BY alias",
                     61:                        DB_UINT, this->user->get_user(this->user),
                     62:                        DB_UINT, DB_TEXT, DB_BLOB);
                     63: 
                     64:        if (query)
                     65:        {
                     66:                u_int id;
                     67:                char *alias;
                     68:                chunk_t keyid;
                     69:                identification_t *identifier;
                     70: 
                     71:                while (query->enumerate(query, &id, &alias, &keyid))
                     72:                {
                     73:                        request->setf(request, "peers.%d.alias=%s", id, alias);
                     74:                        identifier = identification_create_from_encoding(ID_KEY_ID, keyid);
                     75:                        request->setf(request, "peers.%d.identifier=%Y", id, identifier);
                     76:                        identifier->destroy(identifier);
                     77:                }
                     78:                query->destroy(query);
                     79:        }
                     80:        request->render(request, "templates/peer/list.cs");
                     81: }
                     82: 
                     83: /**
                     84:  * verify a peer alias
                     85:  */
                     86: static bool verify_alias(private_peer_controller_t *this, fast_request_t *request,
                     87:                                                 char *alias)
                     88: {
                     89:        if (!alias || *alias == '\0')
                     90:        {
                     91:                request->setf(request, "error=Alias is missing.");
                     92:                return FALSE;
                     93:        }
                     94:        while (*alias != '\0')
                     95:        {
                     96:                switch (*alias)
                     97:                {
                     98:                        case 'a' ... 'z':
                     99:                        case 'A' ... 'Z':
                    100:                        case '0' ... '9':
                    101:                        case '-':
                    102:                        case '_':
                    103:                        case '@':
                    104:                        case '.':
                    105:                                alias++;
                    106:                                continue;
                    107:                        default:
                    108:                                request->setf(request, "error=Alias invalid, "
                    109:                                                          "valid characters: A-Z a-z 0-9 - _ @ .");
                    110:                                return FALSE;
                    111:                }
                    112:        }
                    113:        return TRUE;
                    114: }
                    115: 
                    116: /**
                    117:  * parse and verify a public key
                    118:  */
                    119: static bool parse_public_key(private_peer_controller_t *this,
                    120:                                                         fast_request_t *request, char *public_key,
                    121:                                                         chunk_t *encoding, chunk_t *keyid)
                    122: {
                    123:        public_key_t *public;
                    124:        chunk_t blob, id;
                    125: 
                    126:        if (!public_key || *public_key == '\0')
                    127:        {
                    128:                request->setf(request, "error=Public key is missing.");
                    129:                return FALSE;
                    130:        }
                    131:        blob = chunk_clone(chunk_create(public_key, strlen(public_key)));
                    132:        public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
                    133:                                                                BUILD_BLOB_PEM, blob,
                    134:                                                                BUILD_END);
                    135:        chunk_free(&blob);
                    136:        if (!public)
                    137:        {
                    138:                request->setf(request, "error=Parsing public key failed.");
                    139:                return FALSE;
                    140:        }
                    141:        /* TODO: use get_encoding() with an encoding type */
                    142:        if (!public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &id) ||
                    143:                !public->get_encoding(public, PUBKEY_SPKI_ASN1_DER, encoding))
                    144:        {
                    145:                request->setf(request, "error=Encoding public key failed.");
                    146:                return FALSE;
                    147:        }
                    148:        *keyid = chunk_clone(id);
                    149:        public->destroy(public);
                    150:        return TRUE;
                    151: }
                    152: 
                    153: /**
                    154:  * register a new peer
                    155:  */
                    156: static void add(private_peer_controller_t *this, fast_request_t *request)
                    157: {
                    158:        char *alias = "", *public_key = "";
                    159: 
                    160:        if (request->get_query_data(request, "back"))
                    161:        {
                    162:                return request->redirect(request, "peer/list");
                    163:        }
                    164:        while (request->get_query_data(request, "add"))
                    165:        {
                    166:                chunk_t encoding, keyid;
                    167: 
                    168:                alias = request->get_query_data(request, "alias");
                    169:                public_key = request->get_query_data(request, "public_key");
                    170: 
                    171:                if (!verify_alias(this, request, alias))
                    172:                {
                    173:                        break;
                    174:                }
                    175:                if (!parse_public_key(this, request, public_key, &encoding, &keyid))
                    176:                {
                    177:                        break;
                    178:                }
                    179:                if (this->db->execute(this->db, NULL,
                    180:                                                  "INSERT INTO peer (user, alias, public_key, keyid) "
                    181:                                                  "VALUES (?, ?, ?, ?)",
                    182:                                                  DB_UINT, this->user->get_user(this->user),
                    183:                                                  DB_TEXT, alias, DB_BLOB, encoding,
                    184:                                                  DB_BLOB, keyid) <= 0)
                    185:                {
                    186:                        request->setf(request, "error=Peer already exists.");
                    187:                        free(keyid.ptr);
                    188:                        free(encoding.ptr);
                    189:                        break;
                    190:                }
                    191:                free(keyid.ptr);
                    192:                free(encoding.ptr);
                    193:                return request->redirect(request, "peer/list");
                    194:        }
                    195:        request->set(request, "alias", alias);
                    196:        request->set(request, "public_key", public_key);
                    197: 
                    198:        return request->render(request, "templates/peer/add.cs");
                    199: }
                    200: 
                    201: /**
                    202:  * pem encode a public key into an allocated string
                    203:  */
                    204: char* pem_encode(chunk_t der)
                    205: {
                    206:        static const char *begin = "-----BEGIN PUBLIC KEY-----\n";
                    207:        static const char *end = "-----END PUBLIC KEY-----";
                    208:        size_t len;
                    209:        char *pem;
                    210:        chunk_t base64;
                    211:        int i = 0;
                    212: 
                    213:        base64 = chunk_to_base64(der, NULL);
                    214:        len = strlen(begin) + base64.len + base64.len/64 + strlen(end) + 2;
                    215:        pem = malloc(len + 1);
                    216: 
                    217:        strcpy(pem, begin);
                    218:        do
                    219:        {
                    220:                strncat(pem, base64.ptr + i, 64);
                    221:                strcat(pem, "\n");
                    222:                i += 64;
                    223:        }
                    224:        while (i < base64.len - 2);
                    225:        strcat(pem, end);
                    226: 
                    227:        free(base64.ptr);
                    228:        return pem;
                    229: }
                    230: 
                    231: /**
                    232:  * edit a peer
                    233:  */
                    234: static void edit(private_peer_controller_t *this, fast_request_t *request, int id)
                    235: {
                    236:        char *alias = "", *public_key = "", *pem;
                    237:        chunk_t encoding, keyid;
                    238: 
                    239:        if (request->get_query_data(request, "back"))
                    240:        {
                    241:                return request->redirect(request, "peer/list");
                    242:        }
                    243:        if (request->get_query_data(request, "delete"))
                    244:        {
                    245:                this->db->execute(this->db, NULL,
                    246:                                                  "DELETE FROM peer WHERE id = ? AND user = ?",
                    247:                                                  DB_INT, id, DB_UINT, this->user->get_user(this->user));
                    248:                return request->redirect(request, "peer/list");
                    249:        }
                    250:        if (request->get_query_data(request, "save"))
                    251:        {
                    252:                while (TRUE)
                    253:                {
                    254:                        alias = request->get_query_data(request, "alias");
                    255:                        public_key = request->get_query_data(request, "public_key");
                    256: 
                    257:                        if (!verify_alias(this, request, alias))
                    258:                        {
                    259:                                break;
                    260:                        }
                    261:                        if (!parse_public_key(this, request, public_key, &encoding, &keyid))
                    262:                        {
                    263:                                break;
                    264:                        }
                    265:                        if (this->db->execute(this->db, NULL,
                    266:                                  "UPDATE peer SET alias = ?, public_key = ?, keyid = ? "
                    267:                                  "WHERE id = ? AND user = ?",
                    268:                                  DB_TEXT, alias, DB_BLOB, encoding, DB_BLOB, keyid,
                    269:                                  DB_INT, id, DB_UINT, this->user->get_user(this->user)) < 0)
                    270:                        {
                    271:                                request->setf(request, "error=Peer already exists.");
                    272:                                free(keyid.ptr);
                    273:                                free(encoding.ptr);
                    274:                                break;
                    275:                        }
                    276:                        free(keyid.ptr);
                    277:                        free(encoding.ptr);
                    278:                        return request->redirect(request, "peer/list");
                    279:                }
                    280:        }
                    281:        else
                    282:        {
                    283:                enumerator_t *query = this->db->query(this->db,
                    284:                                "SELECT alias, public_key FROM peer WHERE id = ? AND user = ?",
                    285:                                DB_INT, id, DB_UINT, this->user->get_user(this->user),
                    286:                                DB_TEXT, DB_BLOB);
                    287:                if (query && query->enumerate(query, &alias, &encoding))
                    288:                {
                    289:                        alias = strdupa(alias);
                    290:                        pem = pem_encode(encoding);
                    291:                        public_key = strdupa(pem);
                    292:                        free(pem);
                    293:                }
                    294:                else
                    295:                {
                    296:                        return request->redirect(request, "peer/list");
                    297:                }
                    298:                DESTROY_IF(query);
                    299:        }
                    300:        request->set(request, "alias", alias);
                    301:        request->set(request, "public_key", public_key);
                    302:        return request->render(request, "templates/peer/edit.cs");
                    303: }
                    304: 
                    305: /**
                    306:  * delete a peer from the database
                    307:  */
                    308: static void delete(private_peer_controller_t *this, fast_request_t *request, int id)
                    309: {
                    310:        this->db->execute(this->db, NULL,
                    311:                                          "DELETE FROM peer WHERE id = ? AND user = ?",
                    312:                                          DB_INT, id, DB_UINT, this->user->get_user(this->user));
                    313: }
                    314: 
                    315: METHOD(fast_controller_t, get_name, char*,
                    316:        private_peer_controller_t *this)
                    317: {
                    318:        return "peer";
                    319: }
                    320: 
                    321: METHOD(fast_controller_t, handle, void,
                    322:        private_peer_controller_t *this, fast_request_t *request, char *action,
                    323:        char *idstr, char *p3, char *p4, char *p5)
                    324: {
                    325:        if (action)
                    326:        {
                    327:                int id = 0;
                    328:                if (idstr)
                    329:                {
                    330:                        id = atoi(idstr);
                    331:                }
                    332: 
                    333:                if (streq(action, "list"))
                    334:                {
                    335:                        return list(this, request);
                    336:                }
                    337:                else if (streq(action, "add"))
                    338:                {
                    339:                        return add(this, request);
                    340:                }
                    341:                else if (streq(action, "edit") && id)
                    342:                {
                    343:                        return edit(this, request, id);
                    344:                }
                    345:                else if (streq(action, "delete") && id)
                    346:                {
                    347:                        delete(this, request, id);
                    348:                }
                    349:        }
                    350:        request->redirect(request, "peer/list");
                    351: }
                    352: 
                    353: METHOD(fast_controller_t, destroy, void,
                    354:        private_peer_controller_t *this)
                    355: {
                    356:        free(this);
                    357: }
                    358: 
                    359: /*
                    360:  * see header file
                    361:  */
                    362: fast_controller_t *peer_controller_create(user_t *user, database_t *db)
                    363: {
                    364:        private_peer_controller_t *this;
                    365: 
                    366:        INIT(this,
                    367:                .public = {
                    368:                        .controller = {
                    369:                                .get_name = _get_name,
                    370:                                .handle = _handle,
                    371:                                .destroy = _destroy,
                    372:                        },
                    373:                },
                    374:                .user = user,
                    375:                .db = db,
                    376:        );
                    377: 
                    378:        return &this->public.controller;
                    379: }

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