handle zero size Base64 conversions
[strongswan.git] / src / libfast / session.c
1 /*
2 * Copyright (C) 2007 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
16 #define _GNU_SOURCE
17
18 #include "session.h"
19
20 #include <string.h>
21 #include <fcgiapp.h>
22 #include <stdio.h>
23
24 #include <utils/linked_list.h>
25
26 #define COOKIE_LEN 16
27
28 typedef struct private_session_t private_session_t;
29
30 /**
31 * private data of the task manager
32 */
33 struct private_session_t {
34
35 /**
36 * public functions
37 */
38 session_t public;
39
40 /**
41 * session ID
42 */
43 char sid[COOKIE_LEN * 2 + 1];
44
45 /**
46 * have we sent the session cookie?
47 */
48 bool cookie_sent;
49
50 /**
51 * list of controller instances controller_t
52 */
53 linked_list_t *controllers;
54
55 /**
56 * list of filter instances filter_t
57 */
58 linked_list_t *filters;
59
60 /**
61 * user defined session context
62 */
63 context_t *context;
64 };
65
66 /**
67 * Implementation of session_t.add_controller.
68 */
69 static void add_controller(private_session_t *this, controller_t *controller)
70 {
71 this->controllers->insert_last(this->controllers, controller);
72 }
73
74 /**
75 * Implementation of session_t.add_filter.
76 */
77 static void add_filter(private_session_t *this, filter_t *filter)
78 {
79 this->filters->insert_last(this->filters, filter);
80 }
81
82 /**
83 * Create a session ID and a cookie
84 */
85 static void create_sid(private_session_t *this)
86 {
87 char buf[COOKIE_LEN];
88 rng_t *rng;
89
90 memset(buf, 0, sizeof(buf));
91 memset(this->sid, 0, sizeof(this->sid));
92 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
93 if (rng)
94 {
95 rng->get_bytes(rng, sizeof(buf), buf);
96 rng->destroy(rng);
97 }
98 chunk_to_hex(chunk_create(buf, sizeof(buf)), this->sid, FALSE);
99 }
100
101 /**
102 * run all registered filters
103 */
104 static bool run_filter(private_session_t *this, request_t *request, char *p0,
105 char *p1, char *p2, char *p3, char *p4, char *p5)
106 {
107 enumerator_t *enumerator;
108 filter_t *filter;
109
110 enumerator = this->filters->create_enumerator(this->filters);
111 while (enumerator->enumerate(enumerator, &filter))
112 {
113 if (!filter->run(filter, request, p0, p1, p2, p3, p4, p5))
114 {
115 enumerator->destroy(enumerator);
116 return FALSE;
117 }
118 }
119 enumerator->destroy(enumerator);
120 return TRUE;
121 }
122
123 /**
124 * Implementation of session_t.process.
125 */
126 static void process(private_session_t *this, request_t *request)
127 {
128 char *pos, *start, *param[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
129 enumerator_t *enumerator;
130 bool handled = FALSE;
131 controller_t *current;
132 int i = 0;
133
134 if (!this->cookie_sent)
135 {
136 request->add_cookie(request, "SID", this->sid);
137 this->cookie_sent = TRUE;
138 }
139
140 start = request->get_path(request);
141 if (start)
142 {
143 if (*start == '/')
144 {
145 start++;
146 }
147 while ((pos = strchr(start, '/')) != NULL && i < 5)
148 {
149 param[i++] = strndupa(start, pos - start);
150 start = pos + 1;
151 }
152 param[i] = strdupa(start);
153
154 if (run_filter(this, request, param[0], param[1], param[2], param[3],
155 param[4], param[5]))
156 {
157 enumerator = this->controllers->create_enumerator(this->controllers);
158 while (enumerator->enumerate(enumerator, &current))
159 {
160 if (streq(current->get_name(current), param[0]))
161 {
162 current->handle(current, request, param[1], param[2],
163 param[3], param[4], param[5]);
164 handled = TRUE;
165 break;
166 }
167 }
168 enumerator->destroy(enumerator);
169 }
170 else
171 {
172 handled = TRUE;
173 }
174 }
175 if (!handled)
176 {
177 if (this->controllers->get_first(this->controllers,
178 (void**)&current) == SUCCESS)
179 {
180 request->streamf(request,
181 "Status: 301 Moved permanently\nLocation: %s/%s\n\n",
182 request->get_base(request), current->get_name(current));
183 }
184 }
185 }
186
187 /**
188 * Implementation of session_t.get_sid.
189 */
190 static char* get_sid(private_session_t *this)
191 {
192 return this->sid;
193 }
194
195 /**
196 * Implementation of session_t.destroy
197 */
198 static void destroy(private_session_t *this)
199 {
200 this->controllers->destroy_offset(this->controllers, offsetof(controller_t, destroy));
201 this->filters->destroy_offset(this->filters, offsetof(filter_t, destroy));
202 DESTROY_IF(this->context);
203 free(this);
204 }
205
206 /*
207 * see header file
208 */
209 session_t *session_create(context_t *context)
210 {
211 private_session_t *this = malloc_thing(private_session_t);
212
213 this->public.add_controller = (void(*)(session_t*, controller_t*))add_controller;
214 this->public.add_filter = (void(*)(session_t*, filter_t*))add_filter;
215 this->public.process = (void(*)(session_t*,request_t*))process;
216 this->public.get_sid = (char*(*)(session_t*))get_sid;
217 this->public.destroy = (void(*)(session_t*))destroy;
218
219 create_sid(this);
220 this->cookie_sent = FALSE;
221 this->controllers = linked_list_create();
222 this->filters = linked_list_create();
223 this->context = context;
224
225 return &this->public;
226 }
227