Add cleanup code for html/telnet server
[olsrd.git] / src / olsr_comport_http.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41 #include <string.h>
42
43 #include "common/autobuf.h"
44 #include "common/avl.h"
45 #include "olsr_logging.h"
46 #include "olsr_cookie.h"
47 #include "olsr_comport.h"
48 #include "olsr_comport_http.h"
49 #include "olsr_cfg.h"
50
51 #define HTTP_VERSION "HTTP/1.1"
52
53 static struct olsr_cookie_info *htmlsite_cookie;
54 struct avl_tree http_handler_tree;
55
56 /**Response types */
57 static char http_200_response[] = "OK";
58 static char http_400_response[] = "Bad Request";
59 static char http_401_response[] = "Unauthorized";
60 static char http_403_response[] = "Forbidden";
61 static char http_404_response[] = "Not Found";
62 static char http_413_response[] = "Request Entity Too Large";
63 static char http_501_response[] = "Not Implemented";
64 static char http_503_response[] = "Service Unavailable";
65
66 /* sample for a static html page */
67 static void init_test(void) {
68   static char content[] = "<html><body>Yes, you got it !</body></html>";
69   static char path[] = "/";
70   static char acl[] = "d2lraTpwZWRpYQ=="; /* base 64 .. this is "wikipedia" */
71   static char *aclPtr[] = { acl };
72   struct olsr_html_site *site;
73
74   site = olsr_com_add_htmlsite(path, content, strlen(content));
75   olsr_com_set_htmlsite_acl_auth(site, NULL, 1, aclPtr);
76 }
77
78 void
79 olsr_com_init_http(void) {
80   avl_init(&http_handler_tree, &avl_comp_strcasecmp);
81
82   htmlsite_cookie = olsr_alloc_cookie("comport http sites", OLSR_COOKIE_TYPE_MEMORY);
83   olsr_cookie_set_memory_size(htmlsite_cookie, sizeof(struct olsr_html_site));
84
85   init_test();
86 }
87
88 void olsr_com_destroy_http(void) {
89   struct olsr_html_site *site;
90   OLSR_FOR_ALL_HTML_ENTRIES(site) {
91     olsr_com_remove_htmlsite(site);
92   } OLSR_FOR_ALL_HTML_ENTRIES_END(site)
93 }
94
95 struct olsr_html_site *
96 olsr_com_add_htmlsite(char *path, char *content, size_t length) {
97   struct olsr_html_site *site;
98
99   site = olsr_cookie_malloc(htmlsite_cookie);
100   site->node.key = strdup(path);
101
102   site->static_site = true;
103   site->site_data = content;
104   site->site_length = length;
105
106   avl_insert(&http_handler_tree, &site->node, AVL_DUP_NO);
107   return site;
108 }
109
110 struct olsr_html_site *
111 olsr_com_add_htmlhandler(void(*sitehandler)(struct autobuf *buf, char *path, int parameter_count, char *parameters[]),
112     char *path) {
113   struct olsr_html_site *site;
114
115   site = olsr_cookie_malloc(htmlsite_cookie);
116   site->node.key = strdup(path);
117
118   site->static_site = false;
119   site->sitehandler = sitehandler;
120
121   avl_insert(&http_handler_tree, &site->node, AVL_DUP_NO);
122   return site;
123 }
124
125 void
126 olsr_com_remove_htmlsite(struct olsr_html_site *site) {
127   avl_delete(&http_handler_tree, &site->node);
128   free(site->node.key);
129   olsr_cookie_free(htmlsite_cookie, site);
130 }
131
132 void
133 olsr_com_set_htmlsite_acl_auth(struct olsr_html_site *site, struct ip_acl *ipacl, int auth_count, char **auth_entries) {
134   site->acl = ipacl;
135   site->auth_count = auth_count;
136   site->auth = auth_entries;
137 }
138
139 /* handle the html site. returns true on successful handling (even if it was unauthorized)
140  * false if we did not find a site
141 */
142 bool
143 olsr_com_handle_htmlsite(struct comport_connection *con, char *path,
144     char *fullpath, int para_count, char **para) {
145   char *str;
146   int i;
147   struct olsr_html_site *site;
148
149   site = (struct olsr_html_site *)avl_find(&http_handler_tree, path);
150   if (site == NULL) {
151     return false;
152   }
153
154   /* check if username/password is necessary */
155   if (site->auth) {
156     /* test for correct ACL */
157     char key[256] = { 0 };
158
159     con->send_as = HTTP_401_UNAUTHORIZED;
160
161     str = strstr(con->in.buf, "\nAuthorization: Basic ");
162     if (str != NULL && sscanf(str + 1, "%*s %*s %s\n", key) == 1) {
163       OLSR_DEBUG(LOG_COMPORT, "ACL string received: %s\n", key);
164       for (i = 0; i < site->auth_count; i++) {
165         if (strcmp(site->auth[i], key) == 0) {
166           con->send_as = HTTP_200_OK;
167           break;
168         }
169       }
170     }
171     if (con->send_as == HTTP_401_UNAUTHORIZED) {
172       return true;
173     }
174   }
175
176   /* check if ip is allowed */
177   if (site->acl != NULL && !ip_acl_acceptable(site->acl, &con->addr, olsr_cnf->ip_version)) {
178     con->send_as = HTTP_403_FORBIDDEN;
179     return true;
180   }
181
182   /* call site handler */
183   if (site->static_site) {
184     abuf_memcpy(&con->out, site->site_data, site->site_length);
185   } else {
186     site->sitehandler(&con->out, fullpath, para_count, para);
187   }
188   con->send_as = HTTP_200_OK;
189   return true;
190 }
191
192 void
193 olsr_com_build_httpheader(struct comport_connection *con) {
194   struct autobuf buf;
195   time_t currtime;
196
197   abuf_init(&buf, 1024);
198
199   abuf_appendf(&buf, "%s %d %s\r\n", HTTP_VERSION, con->send_as, olsr_com_get_http_message(con->send_as));
200
201   /* Date */
202   time(&currtime);
203   abuf_strftime(&buf, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", localtime(&currtime));
204
205   /* Server version */
206   abuf_appendf(&buf, "Server: %s %s %s %s\r\n", olsrd_version, build_date, build_host, HTTP_VERSION);
207
208   /* connection-type */
209   abuf_puts(&buf, "Connection: closed\r\n");
210
211   /* MIME type */
212   abuf_appendf(&buf, "Content-type: text/%s\r\n", con->send_as != HTTP_PLAIN ? "html" : "plain");
213
214   /* Content length */
215   if (con->out.len > 0) {
216     abuf_appendf(&buf, "Content-length: %u\r\n", con->out.len);
217   }
218
219   if (con->send_as == HTTP_401_UNAUTHORIZED) {
220     abuf_appendf(&buf, "WWW-Authenticate: Basic realm=\"%s\"\r\n", "RealmName");
221   }
222   /* Cache-control
223    * No caching dynamic pages
224    */
225   abuf_puts(&buf, "Cache-Control: no-cache\r\n");
226
227   if (con->send_as == HTTP_PLAIN) {
228     abuf_puts(&buf, "Accept-Ranges: bytes\r\n");
229   }
230   /* End header */
231   abuf_puts(&buf, "\r\n");
232
233   abuf_memcpy_prefix(&con->out, buf.buf, buf.len);
234   OLSR_DEBUG(LOG_PLUGINS, "HEADER:\n%s", buf.buf);
235
236   abuf_free(&buf);
237 }
238
239 void
240 olsr_com_create_httperror(struct comport_connection *con) {
241   abuf_appendf(&con->out, "<body><h1>HTTP error %d: %s</h1></body>", con->send_as, olsr_com_get_http_message(con->send_as));
242 }
243
244 char *
245 olsr_com_get_http_message(enum http_header_type type) {
246   static char nothing[] = "";
247
248   switch (type) {
249     case HTTP_PLAIN:
250     case HTTP_200_OK:
251       return http_200_response;
252     case HTTP_400_BAD_REQ:
253       return http_400_response;
254     case HTTP_401_UNAUTHORIZED:
255       return http_401_response;
256     case HTTP_403_FORBIDDEN:
257       return http_403_response;
258     case HTTP_404_NOT_FOUND:
259       return http_404_response;
260     case HTTP_413_REQUEST_TOO_LARGE:
261       return http_413_response;
262     case HTTP_501_NOT_IMPLEMENTED:
263       return http_501_response;
264     case HTTP_503_SERVICE_UNAVAILABLE:
265       return http_503_response;
266     default:
267       return nothing;
268   }
269 }
270
271 void olsr_com_decode_url(char *str) {
272   char *dst = str;
273
274   while (*str) {
275     if (*str == '%') {
276       int value = 0;
277
278       str++;
279       sscanf(str, "%02x", &value);
280       *dst++ = (char) value;
281       str += 2;
282     } else {
283       *dst++ = *str++;
284     }
285   }
286   *dst = 0;
287 }