fixed compiler warning
[strongswan.git] / src / charon / plugins / sql / sql_attribute.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * 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 * $Id$
16 */
17
18 #include "sql_attribute.h"
19
20 #include <daemon.h>
21
22 typedef struct private_sql_attribute_t private_sql_attribute_t;
23
24 /**
25 * private data of sql_attribute
26 */
27 struct private_sql_attribute_t {
28
29 /**
30 * public functions
31 */
32 sql_attribute_t public;
33
34 /**
35 * database connection
36 */
37 database_t *db;
38 };
39
40 /**
41 * convert a address blob to an ip of the correct family
42 */
43 static host_t *ip_from_chunk(chunk_t address)
44 {
45 switch (address.len)
46 {
47 case 4:
48 return host_create_from_chunk(AF_INET, address, 0);
49 case 16:
50 return host_create_from_chunk(AF_INET6, address, 0);
51 default:
52 return NULL;
53 }
54 }
55
56 /**
57 * increment a chunk, as it would reprensent a network order integer
58 */
59 static void increment_chunk(chunk_t chunk)
60 {
61 int i;
62
63 for (i = chunk.len - 1; i >= 0; i++)
64 {
65 if (++chunk.ptr[i] != 0)
66 {
67 return;
68 }
69 }
70 }
71
72 /**
73 * Lookup if we have an existing lease
74 */
75 static host_t* get_lease(private_sql_attribute_t *this,
76 char *name, identification_t *id)
77 {
78 enumerator_t *e;
79 chunk_t address;
80 host_t *ip = NULL;
81 int lease;
82
83 POS;
84 e = this->db->query(this->db,
85 "SELECT l.id, l.address FROM leases AS l "
86 "JOIN pools AS p ON l.pool = p.id "
87 "JOIN identities AS i ON l.identity = i.id "
88 "WHERE p.name = ? AND i.type = ? AND i.data = ? "
89 "AND (l.release ISNULL OR p.timeout ISNULL "
90 " OR (l.release < (p.timeout + l.acquire))) "
91 "ORDER BY l.acquire LIMIT 1", DB_TEXT, name,
92 DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id),
93 DB_INT, DB_BLOB);
94 if (e)
95 {
96 if (e->enumerate(e, &lease, &address))
97 {
98 if (this->db->execute(this->db, NULL,
99 "UPDATE leases SET release = NULL WHERE id = ?",
100 DB_INT, lease) > 0)
101 {
102 POS;
103 ip = ip_from_chunk(address);
104 }
105 }
106 e->destroy(e);
107 }
108 return ip;
109 }
110
111 /**
112 * Create a new lease entry for client
113 */
114 static host_t* create_lease(private_sql_attribute_t *this,
115 char *name, identification_t *id)
116 {
117 enumerator_t *e, *f;
118 chunk_t address;
119 host_t *ip = NULL;
120 int pool, identity = 0;
121 POS;
122
123 e = this->db->query(this->db,
124 "SELECT id, next FROM pools WHERE name = ? AND next <= end",
125 DB_TEXT, name,
126 DB_INT, DB_BLOB);
127 if (!e)
128 {
129 return NULL;
130 }
131 if (e->enumerate(e, &pool, &address))
132 {
133 f = this->db->query(this->db,
134 "SELECT id FROM identities WHERE type = ? AND data = ?",
135 DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id),
136 DB_INT);
137 if (f)
138 {
139 if (!f->enumerate(f, &identity))
140 {
141 this->db->execute(this->db, &identity,
142 "INSERT INTO identities (type, data) VALUES (?, ?)",
143 DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id));
144 }
145 f->destroy(f);
146 }
147 if (identity)
148 {
149 if (this->db->execute(this->db, NULL,
150 "INSERT INTO leases "
151 "(pool, address, identity) VALUES (?, ?, ?)",
152 DB_INT, pool, DB_BLOB, address, DB_INT, identity) > 0)
153 {
154 POS;
155 ip = ip_from_chunk(address);
156 increment_chunk(address);
157 this->db->execute(this->db, NULL,
158 "UPDATE pools set next = ? WHERE id = ?",
159 DB_BLOB, address, DB_INT, pool);
160 }
161 }
162 }
163 e->destroy(e);
164 return ip;
165 }
166
167 /**
168 * Implementation of attribute_provider_t.acquire_address
169 */
170 static host_t* acquire_address(private_sql_attribute_t *this,
171 char *name, identification_t *id,
172 auth_info_t *auth, host_t *requested)
173 {
174 host_t *ip;
175
176 ip = get_lease(this, name, id);
177 if (!ip)
178 {
179 ip = create_lease(this, name, id);
180 }
181 return ip;
182 }
183
184 /**
185 * Implementation of attribute_provider_t.release_address
186 */
187 static bool release_address(private_sql_attribute_t *this,
188 char *name, host_t *address)
189 {
190 if (this->db->execute(this->db, NULL,
191 "UPDATE leases SET release = DATE('NOW') WHERE "
192 "pool IN (SELECT id FROM pools WHERE name = ?) AND "
193 "address = ? "
194 "ORDER BY acquire LIMIT 1",
195 DB_TEXT, name, DB_BLOB, address->get_address(address)) > 0)
196 {
197 POS;
198 return TRUE;
199 }
200 return FALSE;
201 }
202
203 /**
204 * Implementation of sql_attribute_t.destroy
205 */
206 static void destroy(private_sql_attribute_t *this)
207 {
208 free(this);
209 }
210
211 /*
212 * see header file
213 */
214 sql_attribute_t *sql_attribute_create(database_t *db)
215 {
216 private_sql_attribute_t *this = malloc_thing(private_sql_attribute_t);
217
218 this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *,auth_info_t *, host_t *))acquire_address;
219 this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *))release_address;
220 this->public.destroy = (void(*)(sql_attribute_t*))destroy;
221
222 this->db = db;
223
224 return &this->public;
225 }
226