root/trunk/wifidog/src/http.c

Revision 1464, 11.3 KB (checked in by benoitg, 9 months ago)

Commit patch by Etienne CHAMPETIER to fix buffer overflow on long urls reported in #836

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/********************************************************************\
2 * This program is free software; you can redistribute it and/or    *
3 * modify it under the terms of the GNU General Public License as   *
4 * published by the Free Software Foundation; either version 2 of   *
5 * the License, or (at your option) any later version.              *
6 *                                                                  *
7 * This program is distributed in the hope that it will be useful,  *
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
10 * GNU General Public License for more details.                     *
11 *                                                                  *
12 * You should have received a copy of the GNU General Public License*
13 * along with this program; if not, contact:                        *
14 *                                                                  *
15 * Free Software Foundation           Voice:  +1-617-542-5942       *
16 * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
17 * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
18 *                                                                  *
19 \********************************************************************/
20
21/* $Id$ */
22/** @file http.c
23  @brief HTTP IO functions
24  @author Copyright (C) 2004 Philippe April <papril777@yahoo.com>
25  @author Copyright (C) 2007 Benoit Grégoire
26  @author Copyright (C) 2007 David Bird <david@coova.com>
27
28 */
29
30#define _GNU_SOURCE
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <pthread.h>
35#include <string.h>
36#include <unistd.h>
37#include <syslog.h>
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <fcntl.h>
41#include <errno.h>
42
43#include "httpd.h"
44
45#include "safe.h"
46#include "debug.h"
47#include "conf.h"
48#include "auth.h"
49#include "firewall.h"
50#include "http.h"
51#include "httpd.h"
52#include "client_list.h"
53#include "common.h"
54#include "centralserver.h"
55
56#include "util.h"
57
58#include "../config.h"
59
60extern pthread_mutex_t  client_list_mutex;
61
62/** The 404 handler is also responsible for redirecting to the auth server */
63void
64http_callback_404(httpd *webserver, request *r)
65{
66        char tmp_url[MAX_BUF],
67                        *url,
68                        *mac;
69        s_config        *config = config_get_config();
70        t_auth_serv     *auth_server = get_auth_server();
71
72        memset(tmp_url, 0, sizeof(tmp_url));
73        /*
74         * XXX Note the code below assumes that the client's request is a plain
75         * http request to a standard port. At any rate, this handler is called only
76         * if the internet/auth server is down so it's not a huge loss, but still.
77         */
78        snprintf(tmp_url, (sizeof(tmp_url) - 1), "http://%s%s%s%s",
79                        r->request.host,
80                        r->request.path,
81                        r->request.query[0] ? "?" : "",
82                        r->request.query);
83        url = httpdUrlEncode(tmp_url);
84
85        if (!is_online()) {
86                /* The internet connection is down at the moment  - apologize and do not redirect anywhere */
87                char * buf;
88                safe_asprintf(&buf, 
89                        "<p>We apologize, but it seems that the internet connection that powers this hotspot is temporarily unavailable.</p>"
90                        "<p>If at all possible, please notify the owners of this hotspot that the internet connection is out of service.</p>"
91                        "<p>The maintainers of this network are aware of this disruption.  We hope that this situation will be resolved soon.</p>"
92                        "<p>In a while please <a href='%s'>click here</a> to try your request again.</p>", tmp_url);
93
94                send_http_page(r, "Uh oh! Internet access unavailable!", buf);
95                free(buf);
96                debug(LOG_INFO, "Sent %s an apology since I am not online - no point sending them to auth server", r->clientAddr);
97        }
98        else if (!is_auth_online()) {
99                /* The auth server is down at the moment - apologize and do not redirect anywhere */
100                char * buf;
101                safe_asprintf(&buf, 
102                        "<p>We apologize, but it seems that we are currently unable to re-direct you to the login screen.</p>"
103                        "<p>The maintainers of this network are aware of this disruption.  We hope that this situation will be resolved soon.</p>"
104                        "<p>In a couple of minutes please <a href='%s'>click here</a> to try your request again.</p>", tmp_url);
105
106                send_http_page(r, "Uh oh! Login screen unavailable!", buf);
107                free(buf);
108                debug(LOG_INFO, "Sent %s an apology since auth server not online - no point sending them to auth server", r->clientAddr);
109        }
110        else {
111                /* Re-direct them to auth server */
112                char *urlFragment;
113
114                if (!(mac = arp_get(r->clientAddr))) {
115                        /* We could not get their MAC address */
116                        debug(LOG_INFO, "Failed to retrieve MAC address for ip %s, so not putting in the login request", r->clientAddr);
117                        safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&url=%s",
118                                auth_server->authserv_login_script_path_fragment,
119                                config->gw_address,
120                                config->gw_port, 
121                                config->gw_id,
122                                url);
123                } else {                       
124                        debug(LOG_INFO, "Got client MAC address for ip %s: %s", r->clientAddr, mac);
125                        safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&mac=%s&url=%s",
126                                auth_server->authserv_login_script_path_fragment,
127                                config->gw_address,
128                                config->gw_port, 
129                                config->gw_id,
130                                mac,
131                                url);
132                }
133
134                debug(LOG_INFO, "Captured %s requesting [%s] and re-directing them to login page", r->clientAddr, url);
135                http_send_redirect_to_auth(r, urlFragment, "Redirect to login page");
136                free(urlFragment);
137        }
138        free(url);
139}
140
141void 
142http_callback_wifidog(httpd *webserver, request *r)
143{
144        send_http_page(r, "WiFiDog", "Please use the menu to navigate the features of this WiFiDog installation.");
145}
146
147void 
148http_callback_about(httpd *webserver, request *r)
149{
150        send_http_page(r, "About WiFiDog", "This is WiFiDog version <strong>" VERSION "</strong>");
151}
152
153void 
154http_callback_status(httpd *webserver, request *r)
155{
156        const s_config *config = config_get_config();
157        char * status = NULL;
158        char *buf;
159
160        if (config->httpdusername && 
161                        (strcmp(config->httpdusername, r->request.authUser) ||
162                         strcmp(config->httpdpassword, r->request.authPassword))) {
163                debug(LOG_INFO, "Status page requested, forcing authentication");
164                httpdForceAuthenticate(r, config->httpdrealm);
165                return;
166        }
167
168        status = get_status_text();
169        safe_asprintf(&buf, "<pre>%s</pre>", status);
170        send_http_page(r, "WiFiDog Status", buf);
171        free(buf);
172        free(status);
173}
174/** @brief Convenience function to redirect the web browser to the auth server
175 * @param r The request
176 * @param urlFragment The end of the auth server URL to redirect to (the part after path)
177 * @param text The text to include in the redirect header ant the mnual redirect title */
178void http_send_redirect_to_auth(request *r, char *urlFragment, char *text)
179{
180        char *protocol = NULL;
181        int port = 80;
182        t_auth_serv     *auth_server = get_auth_server();
183
184        if (auth_server->authserv_use_ssl) {
185                protocol = "https";
186                port = auth_server->authserv_ssl_port;
187        } else {
188                protocol = "http";
189                port = auth_server->authserv_http_port;
190        }
191                                       
192        char *url = NULL;
193        safe_asprintf(&url, "%s://%s:%d%s%s",
194                protocol,
195                auth_server->authserv_hostname,
196                port,
197                auth_server->authserv_path,
198                urlFragment
199        );
200        http_send_redirect(r, url, text);
201        free(url);     
202}
203
204/** @brief Sends a redirect to the web browser
205 * @param r The request
206 * @param url The url to redirect to
207 * @param text The text to include in the redirect header and the manual redirect link title.  NULL is acceptable */
208void http_send_redirect(request *r, char *url, char *text)
209{
210                char *message = NULL;
211                char *header = NULL;
212                char *response = NULL;
213                                                        /* Re-direct them to auth server */
214                debug(LOG_DEBUG, "Redirecting client browser to %s", url);
215                safe_asprintf(&header, "Location: %s",
216                        url
217                );
218                if(text) {
219                        safe_asprintf(&response, "307 %s\n",
220                                text
221                        );     
222                }
223                else {
224                        safe_asprintf(&response, "307 %s\n",
225                                "Redirecting"
226                        );             
227                }       
228                httpdSetResponse(r, response);
229                httpdAddHeader(r, header);
230                free(response);
231                free(header);   
232                safe_asprintf(&message, "Please <a href='%s'>click here</a>.", url);
233                send_http_page(r, text ? text : "Redirection to message", message);
234                free(message);
235}
236
237void 
238http_callback_auth(httpd *webserver, request *r)
239{
240        t_client        *client;
241        httpVar * token;
242        char    *mac;
243        httpVar *logout = httpdGetVariableByName(r, "logout");
244        if ((token = httpdGetVariableByName(r, "token"))) {
245                /* They supplied variable "token" */
246                if (!(mac = arp_get(r->clientAddr))) {
247                        /* We could not get their MAC address */
248                        debug(LOG_ERR, "Failed to retrieve MAC address for ip %s", r->clientAddr);
249                        send_http_page(r, "WiFiDog Error", "Failed to retrieve your MAC address");
250                } else {
251                        /* We have their MAC address */
252
253                        LOCK_CLIENT_LIST();
254                       
255                        if ((client = client_list_find(r->clientAddr, mac)) == NULL) {
256                                debug(LOG_DEBUG, "New client for %s", r->clientAddr);
257                                client_list_append(r->clientAddr, mac, token->value);
258                        } else if (logout) {
259                            t_authresponse  authresponse;
260                            s_config *config = config_get_config();
261                            unsigned long long incoming = client->counters.incoming;
262                            unsigned long long outgoing = client->counters.outgoing;
263                            char *ip = safe_strdup(client->ip);
264                            char *urlFragment = NULL;
265                            t_auth_serv *auth_server = get_auth_server();
266                                                               
267                            fw_deny(client->ip, client->mac, client->fw_connection_state);
268                            client_list_delete(client);
269                            debug(LOG_DEBUG, "Got logout from %s", client->ip);
270                           
271                            /* Advertise the logout if we have an auth server */
272                            if (config->auth_servers != NULL) {
273                                        UNLOCK_CLIENT_LIST();
274                                        auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, ip, mac, token->value, 
275                                                                            incoming, outgoing);
276                                        LOCK_CLIENT_LIST();
277                                       
278                                        /* Re-direct them to auth server */
279                                        debug(LOG_INFO, "Got manual logout from client ip %s, mac %s, token %s"
280                                        "- redirecting them to logout message", client->ip, client->mac, client->token);
281                                        safe_asprintf(&urlFragment, "%smessage=%s",
282                                                auth_server->authserv_msg_script_path_fragment,
283                                                GATEWAY_MESSAGE_ACCOUNT_LOGGED_OUT
284                                        );
285                                        http_send_redirect_to_auth(r, urlFragment, "Redirect to logout message");
286                                        free(urlFragment);
287                            }
288                            free(ip);
289                        } 
290                        else {
291                                debug(LOG_DEBUG, "Client for %s is already in the client list", client->ip);
292                        }
293                        UNLOCK_CLIENT_LIST();
294                        if (!logout) {
295                                authenticate_client(r);
296                        }
297                        free(mac);
298                }
299        } else {
300                /* They did not supply variable "token" */
301                send_http_page(r, "WiFiDog error", "Invalid token");
302        }
303}
304
305void send_http_page(request *r, const char *title, const char* message)
306{
307    s_config    *config = config_get_config();
308    char *buffer;
309    struct stat stat_info;
310    int fd;
311    ssize_t written;
312
313    fd=open(config->htmlmsgfile, O_RDONLY);
314    if (fd==-1) {
315        debug(LOG_CRIT, "Failed to open HTML message file %s: %s", config->htmlmsgfile, strerror(errno));
316        return;
317    }
318
319    if (fstat(fd, &stat_info)==-1) {
320        debug(LOG_CRIT, "Failed to stat HTML message file: %s", strerror(errno));
321        close(fd);
322        return;
323    }
324
325    buffer=(char*)safe_malloc(stat_info.st_size+1);
326    written=read(fd, buffer, stat_info.st_size);
327    if (written==-1) {
328        debug(LOG_CRIT, "Failed to read HTML message file: %s", strerror(errno));
329        free(buffer);
330        close(fd);
331        return;
332    }
333    close(fd);
334
335    buffer[written]=0;
336    httpdAddVariable(r, "title", title);
337    httpdAddVariable(r, "message", message);
338    httpdAddVariable(r, "nodeID", config->gw_id);
339    httpdOutput(r, buffer);
340    free(buffer);
341}
342
Note: See TracBrowser for help on using the browser.