1#define THREADED
2#include "../common/common.c"
3
4// Taken some code from gnu tls documentation,
5// This example is a very simple echo server which supports X.509
6// authentication, using the RSA ciphersuites.
7// This file has the leading comment of... /* This example code is
8// placed in the public domain. */
9// so there :>
10
11#include <gcrypt.h>
12#include <gnutls/gnutls.h>
13
14#include <libHX/init.h>
15#include <libHX/defs.h>
16#include <libHX/map.h>
17#include <libHX/string.h>
18
19#define KEYFILE "/opt/fusion/ssl/key.pem"
20#define CERTFILE "/opt/fusion/ssl/cert.pem"
21#define CAFILE "/opt/fusion/ssl/ca.pem"
22#define CRLFILE "/opt/fusion/ssl/crl.pem"
23
24gnutls_certificate_credentials_t x509_cred;
25gnutls_priority_t priority_cache;
26
27static gnutls_session_t
28initialize_tls_session (void)
29{
30 gnutls_session_t session;
31
32 gnutls_init (&session, GNUTLS_SERVER);
33
34 gnutls_priority_set (session, priority_cache);
35
36 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
37
38 /*
39 *request client certificate if any.
40 */
41 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
42
43 return session;
44}
45
46
47struct HXmap *dict;
48
49struct data {
50 void *data;
51 size_t length;
52};
53
54struct data *gather_data(gnutls_session_t session, char *key, size_t length)
55{
56 unsigned char buffer[length];
57 int offset, ret;
58 struct data *data;
59
60 for(offset = 0; offset < length; ) {
61 ret = gnutls_record_recv(session, buffer + offset, (length -
62 offset) > 65535 ? 65535 : (length - offset));
63 if(ret <= 0) return NULL;
64 offset += ret;
65 }
66
67 data = malloc(sizeof(struct data));
68 if(! data) return NULL;
69 data->data = HX_memdup(buffer, length);
70 if(!data->data) {
71 free(data);
72 return NULL;
73 }
74 data->length = length;
75
76 //printf("gather data: returning %08x, data->length = %d\n", data,
77 // data->length);
78 //fflush(stdout);
79
80 return data;
81}
82
83#define NOKEY "// No key was specified\n"
84#define NOTFOUND "// Key was not found\n"
85#define KEYFOUND "// Key exists\n"
86#define NOMEM "// Not enough memory to allocate\n"
87#define UPDATEOK "// Updated successfully\n"
88
89int update_data(gnutls_session_t session, char *key, size_t length)
90{
91 struct data *data;
92 size_t offset;
93 int ret;
94
95 data = HXmap_get(dict, key);
96 if(! data) {
97 gnutls_record_send(session, NOTFOUND, strlen(NOTFOUND));
98 return -1;
99 }
100
101 if(length > data->length) {
102 void *tmp;
103 tmp = realloc(data->data, length);
104 if(! tmp) {
105 gnutls_record_send(session, NOMEM, strlen(NOMEM));
106 return -1;
107 }
108 data->data = tmp;
109 }
110
111 for(offset = 0; offset < length; ) {
112 ret = gnutls_record_recv(session, data->data + offset,
113 (length - offset) > 65535 ? 65535 : (length - offset));
114 if(ret <= 0) return 0;
115 offset += ret;
116 }
117
118 gnutls_record_send(session, UPDATEOK, strlen(UPDATEOK));
119
120 data->length = length;
121 return 0;
122}
123
124int send_data(gnutls_session_t session, char *key, struct data *data)
125{
126 int offset, ret;
127 int to_send;
128
129 char *msg;
130
131 asprintf(&msg, "// Sending %d bytes\n", data->length);
132 gnutls_record_send(session, msg, strlen(msg));
133 free(msg);
134
135 for(offset = 0; offset < data->length; ) {
136 int tosend;
137 tosend = (data->length - offset) > 65535 ? 65535 :
138 (data->length - offset);
139 ret = gnutls_record_send(session, data->data + offset,
140 tosend);
141 if(ret <= 0) return -1;
142 offset += ret;
143 }
144 return 0;
145}
146
147void *free_data(void *ptr)
148{
149 struct data *data;
150 data = (struct data *)(ptr);
151
152 //printf("in free data, got %08x\n", (unsigned int)data);
153 if(data) {
154 if(data->data) {
155 free(data->data);
156 }
157 free(data);
158 }
159}
160
161void new_dict()
162{
163 struct HXmap_ops mops;
164 if(dict) HXmap_free(dict);
165
166 memset(&mops, 0, sizeof(mops));
167 mops.d_free = free_data;
168
169 dict = HXmap_init5(HXMAPT_HASH, HXMAP_SKEY | HXMAP_CKEY, &mops,
170 0, sizeof(struct data));
171}
172
173
174void *keyval_thread(void *arg)
175{
176 int fd = (int)arg;
177 int ret;
178 struct data *data;
179 int cont;
180
181 gnutls_session_t session;
182 session = initialize_tls_session ();
183
184 gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) fd);
185 ret = gnutls_handshake (session);
186
187 if (ret < 0) {
188 char *msg;
189
190 close (fd);
191 gnutls_deinit (session);
192
193 msg = NULL;
194 asprintf(&msg, "*** Handshake has failed (%s)\n\n",
195 gnutls_strerror(ret));
196 write(fd, msg, strlen(msg));
197 close(fd);
198 free(msg);
199 }
200
201#define BANNER "// Welcome to KeyValDaemon. Type 'h' for help information\n"
202 gnutls_record_send(session, BANNER, strlen(BANNER));
203
204 cont = 1;
205 while(cont) {
206 char cmdbuf[512], *p;
207 char *args[6], *msg;
208 int argcnt, i;
209
210 memset(cmdbuf, 0, sizeof(cmdbuf));
211 ret = gnutls_record_recv(session, cmdbuf, sizeof(cmdbuf));
212 if(ret <= 0) break;
213
214 p = strchr(cmdbuf, '\r');
215 if(p) *p = 0;
216 p = strchr(cmdbuf, '\n');
217 if(p) *p = 0;
218
219 memset(args, 0, sizeof(args));
220 argcnt = HX_split5(cmdbuf, " ", 6, args);
221
222#if 0
223 for(i = 0; i < argcnt; i++) {
224 asprintf(&msg, "args[%d] = \"%s\"\n", i, args[i]);
225 gnutls_record_send(session, msg, strlen(msg));
226 free(msg);
227 }
228#endif
229
230
231
232 switch(args[0][0]) {
233 case 'h':
234#define HELP \
235"// f <key> - find entry and see if it exists\n" \
236"// s <key> <bytes> - store an entry with key and <bytes> lenght of data\n" \
237"// g <key> - read data from key\n" \
238"// d <key> - delete key/data\n" \
239"// X - delete all data and restart\n"
240// XXX, loop over HXmap and display data?
241
242 gnutls_record_send(session, HELP, strlen(HELP));
243 break;
244 case 'd':
245 if(! args[1]) {
246 gnutls_record_send(session, NOKEY, strlen(NOKEY));
247 } else {
248 void *data;
249
250 data = HXmap_del(dict, args[1]);
251 if(data) {
252 gnutls_record_send(session, KEYFOUND,
253 strlen(KEYFOUND));
254 } else {
255 gnutls_record_send(session, NOTFOUND,
256 strlen(NOTFOUND));
257 }
258 }
259 break;
260 case 's': // set
261 data = gather_data(session, args[1], atoi(args[2]));
262 if(data != NULL) {
263#define NEWKEY "// New key added!\n"
264 printf("args[1] = %08x/%s, data = %08x\n",
265 args[1], args[1], data);
266 HXmap_add(dict, args[1], data);
267 gnutls_record_send(session, NEWKEY,
268 strlen(NEWKEY));
269 } else {
270#define ADDERROR "// Unable to add new entry, problem getting data\n"
271 gnutls_record_send(session, ADDERROR,
272 strlen(ADDERROR));
273 }
274 break;
275 case 'u': // update
276 update_data(session, args[1], atoi(args[2]));
277 break;
278 case 'f': // find
279 if(! args[1]) {
280 gnutls_record_send(session, NOKEY,
281 strlen(NOKEY));
282 } else {
283 if(HXmap_find(dict, args[1]) == NULL) {
284 gnutls_record_send(session,
285 NOTFOUND, strlen(NOTFOUND));
286 } else {
287 gnutls_record_send(session,
288 KEYFOUND, strlen(KEYFOUND));
289 }
290 }
291
292 break;
293
294 case 'g': // get
295 if(! args[1]) {
296 gnutls_record_send(session, NOKEY,
297 strlen(NOKEY));
298 } else {
299 if((data = HXmap_get(dict, args[1]))
300 == NULL) {
301 gnutls_record_send(session, NOTFOUND,
302 strlen(NOTFOUND));
303 } else {
304 send_data(session, args[1], data);
305 }
306 }
307 break;
308 case 'e':
309 cont = 0;
310 break;
311 case 'X':
312 new_dict();
313#define NEWDICT "// New dictionary installed\n"
314 gnutls_record_send(session, NEWDICT,
315 strlen(NEWDICT));
316 break;
317 default:
318#define UC "// Unknown Command, please see 'h' for help information\n"
319
320 gnutls_record_send(session, UC, strlen(UC));
321 break;
322 }
323 }
324
325
326#define GB "// Good bye!\n"
327 gnutls_record_send(session, GB, strlen(GB));
328 gnutls_bye(session, GNUTLS_SHUT_WR);
329
330 close(fd);
331 gnutls_deinit(session);
332
333 return NULL;
334}
335
336#define DH_BITS 512
337
338static gnutls_dh_params_t dh_params;
339
340static int generate_dh_params (void)
341{
342 /*
343 * Generate Diffie-Hellman parameters - for use with DHE
344 * kx algorithms. When short bit length is used, it might
345 * be wise to regenerate parameters.
346 *
347 */
348 gnutls_dh_params_init (&dh_params);
349 gnutls_dh_params_generate2 (dh_params, DH_BITS);
350
351 return 0;
352}
353
354GCRY_THREAD_OPTION_PTHREAD_IMPL;
355
356int main(int argc, char **argv)
357{
358 int fd, i;
359
360 HX_init();
361
362 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
363 gnutls_global_init();
364
365 gnutls_certificate_allocate_credentials (&x509_cred);
366 gnutls_certificate_set_x509_trust_file (x509_cred, CAFILE,
367 GNUTLS_X509_FMT_PEM);
368
369 gnutls_certificate_set_x509_crl_file (x509_cred, CRLFILE,
370 GNUTLS_X509_FMT_PEM);
371
372 gnutls_certificate_set_x509_key_file (x509_cred, CERTFILE, KEYFILE,
373 GNUTLS_X509_FMT_PEM);
374
375 generate_dh_params ();
376
377 gnutls_priority_init (&priority_cache, "NORMAL", NULL);
378 gnutls_certificate_set_dh_params (x509_cred, dh_params);
379
380 new_dict();
381
382 signal(SIGPIPE, SIG_IGN);
383
384 background_process(NAME, UID, GID);
385 serve_forever_threaded(PORT, keyval_thread);
386}
387