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>