void http_callback_auth(httpd *webserver, request *r) { t_client *client; httpVar * token; char *mac; if ((token = httpdGetVariableByName(r, "token"))) { /* They supplied variable "token" */ if (!(mac = arp_get(r->clientAddr))) { /* We could not get their MAC address */ debug(LOG_ERR, "Failed to retrieve MAC address for ip %s", r->clientAddr); send_http_page(r, "WiFiDog Error", "Failed to retrieve your MAC address"); } else { /* We have their MAC address */ LOCK_CLIENT_LIST(); if ((client = client_list_find(r->clientAddr, mac)) == NULL) { debug(LOG_DEBUG, "New client for %s", r->clientAddr); client_list_append(r->clientAddr, mac, token->value); } else { debug(LOG_DEBUG, "Client for %s is already in the client list", client->ip); } UNLOCK_CLIENT_LIST(); authenticate_client(r); free(mac); } } else { /* They did not supply variable "token" */ send_http_page(r, "WiFiDog error", "Invalid token"); } }
void http_callback_auth(httpd * webserver, request * r) { t_client *client; httpVar *token; char *mac; httpVar *logout = httpdGetVariableByName(r, "logout"); const s_config *config = config_get_config(); if ((token = httpdGetVariableByName(r, "token"))) { /* They supplied variable "token" */ if (!(mac = arp_get(r->clientAddr))) { /* We could not get their MAC address */ debug(LOG_ERR, "Failed to retrieve MAC address for ip %s", r->clientAddr); send_http_page(r, "WiFiDog Error", "Failed to retrieve your MAC address"); } else { t_redir_node *node; int index = 0; LOCK_REDIR(); node = redir_list_find(mac); if (node) { index = node->wlindex; } UNLOCK_REDIR(); /* We have their MAC address */ LOCK_CLIENT_LIST(); if ((client = client_list_find(r->clientAddr, mac)) == NULL) { debug(LOG_DEBUG, "New client for %s", r->clientAddr); client = client_list_add(r->clientAddr, mac, token->value); client->fw_connection_state = FW_MARK_REDIR; client->counters.active_duration = config->sessiontimeout[index-1]; } else if (logout) { logout_client(client); } else { debug(LOG_DEBUG, "Client for %s is already in the client list", client->ip); } UNLOCK_CLIENT_LIST(); if (!logout) { /* applies for case 1 and 3 from above if */ authenticate_client(r); } free(mac); } } else { /* They did not supply variable "token" */ send_http_page(r, "WiFiDog error", "Invalid token"); } }
/** @brief Sends a redirect to the web browser * @param r The request * @param url The url to redirect to * @param text The text to include in the redirect header and the manual redirect link title. NULL is acceptable */ void http_send_redirect(request *r, char *url, char *text) { char *message = NULL; char *header = NULL; char *response = NULL; /* Re-direct them to auth server */ debug(LOG_DEBUG, "Redirecting client browser to %s", url); safe_asprintf(&header, "Location: %s", url ); if(text) { safe_asprintf(&response, "307 %s\n", text ); } else { safe_asprintf(&response, "307 %s\n", "Redirecting" ); } httpdSetResponse(r, response); httpdAddHeader(r, header); free(response); free(header); safe_asprintf(&message, "Please <a href='%s'>click here</a>.", url); send_http_page(r, text ? text : "Redirection to message", message); free(message); }
void http_callback_status(httpd * webserver, request * r) { const s_config *config = config_get_config(); char *status = NULL; char *buf; if (config->httpdusername && (strcmp(config->httpdusername, r->request.authUser) || strcmp(config->httpdpassword, r->request.authPassword))) { debug(LOG_INFO, "Status page requested, forcing authentication"); httpdForceAuthenticate(r, config->httpdrealm); return; } status = get_status_text(); safe_asprintf(&buf, "<pre>%s</pre>", status); send_http_page(r, "WiFiDog Status", buf); free(buf); free(status); }
/** The 404 handler is also responsible for redirecting to the auth server */ void http_callback_404(httpd * webserver, request * r, int error_code) { char tmp_url[MAX_BUF], *url, *mac; s_config *config = config_get_config(); t_auth_serv *auth_server = get_auth_server(); memset(tmp_url, 0, sizeof(tmp_url)); /* * XXX Note the code below assumes that the client's request is a plain * http request to a standard port. At any rate, this handler is called only * if the internet/auth server is down so it's not a huge loss, but still. */ snprintf(tmp_url, (sizeof(tmp_url) - 1), "http://%s%s%s%s", r->request.host, r->request.path, r->request.query[0] ? "?" : "", r->request.query); url = httpdUrlEncode(tmp_url); if (!is_online()) { /* The internet connection is down at the moment - apologize and do not redirect anywhere */ char *buf; safe_asprintf(&buf, "<p>We apologize, but it seems that the internet connection that powers this hotspot is temporarily unavailable.</p>" "<p>If at all possible, please notify the owners of this hotspot that the internet connection is out of service.</p>" "<p>The maintainers of this network are aware of this disruption. We hope that this situation will be resolved soon.</p>" "<p>In a while please <a href='%s'>click here</a> to try your request again.</p>", tmp_url); send_http_page(r, "Uh oh! Internet access unavailable!", buf); free(buf); debug(LOG_INFO, "Sent %s an apology since I am not online - no point sending them to auth server", r->clientAddr); } else if (!is_auth_online()) { /* The auth server is down at the moment - apologize and do not redirect anywhere */ char *buf; safe_asprintf(&buf, "<p>We apologize, but it seems that we are currently unable to re-direct you to the login screen.</p>" "<p>The maintainers of this network are aware of this disruption. We hope that this situation will be resolved soon.</p>" "<p>In a couple of minutes please <a href='%s'>click here</a> to try your request again.</p>", tmp_url); send_http_page(r, "Uh oh! Login screen unavailable!", buf); free(buf); debug(LOG_INFO, "Sent %s an apology since auth server not online - no point sending them to auth server", r->clientAddr); } else { /* Re-direct them to auth server */ char *urlFragment; if (!(mac = arp_get(r->clientAddr))) { /* We could not get their MAC address */ debug(LOG_INFO, "Failed to retrieve MAC address for ip %s, so not putting in the login request", r->clientAddr); safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&ip=%s&url=%s", auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, r->clientAddr, url); } else { debug(LOG_INFO, "Got client MAC address for ip %s: %s", r->clientAddr, mac); safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&ip=%s&mac=%s&url=%s", auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, r->clientAddr, mac, url); free(mac); } // if host is not in whitelist, maybe not in conf or domain'IP changed, it will go to here. debug(LOG_INFO, "Check host %s is in whitelist or not", r->request.host); // e.g. www.example.com t_firewall_rule *rule; //e.g. example.com is in whitelist // if request http://www.example.com/, it's not equal example.com. for (rule = get_ruleset("global"); rule != NULL; rule = rule->next) { debug(LOG_INFO, "rule mask %s", rule->mask); if (strstr(r->request.host, rule->mask) == NULL) { debug(LOG_INFO, "host %s is not in %s, continue", r->request.host, rule->mask); continue; } int host_length = strlen(r->request.host); int mask_length = strlen(rule->mask); if (host_length != mask_length) { char prefix[1024] = { 0 }; // must be *.example.com, if not have ".", maybe Phishing. e.g. phishingexample.com strncpy(prefix, r->request.host, host_length - mask_length - 1); // e.g. www strcat(prefix, "."); // www. strcat(prefix, rule->mask); // www.example.com if (strcasecmp(r->request.host, prefix) == 0) { debug(LOG_INFO, "allow subdomain"); fw_allow_host(r->request.host); http_send_redirect(r, tmp_url, "allow subdomain"); free(url); free(urlFragment); return; } } else { // e.g. "example.com" is in conf, so it had been parse to IP and added into "iptables allow" when wifidog start. but then its' A record(IP) changed, it will go to here. debug(LOG_INFO, "allow domain again, because IP changed"); fw_allow_host(r->request.host); http_send_redirect(r, tmp_url, "allow domain"); free(url); free(urlFragment); return; } } debug(LOG_INFO, "Captured %s requesting [%s] and re-directing them to login page", r->clientAddr, url); http_send_redirect_to_auth(r, urlFragment, "Redirect to login page"); free(urlFragment); } free(url); }
void http_callback_about(httpd * webserver, request * r) { send_http_page(r, "About WiFiDog", "This is WiFiDog version <strong>" VERSION "</strong>"); }
void http_callback_wifidog(httpd * webserver, request * r) { send_http_page(r, "WiFiDog", "Please use the menu to navigate the features of this WiFiDog installation."); }
/** The 404 handler is also responsible for redirecting to the auth server */ void http_callback_404(httpd *webserver, request *r) { char tmp_url[MAX_BUF], *url, *mac; s_config *config = config_get_config(); t_auth_serv *auth_server = get_auth_server(); memset(tmp_url, 0, sizeof(tmp_url)); /* * XXX Note the code below assumes that the client's request is a plain * http request to a standard port. At any rate, this handler is called only * if the internet/auth server is down so it's not a huge loss, but still. */ snprintf(tmp_url, (sizeof(tmp_url) - 1), "http://%s%s%s%s", r->request.host, r->request.path, r->request.query[0] ? "?" : "", r->request.query); url = httpdUrlEncode(tmp_url); if (!is_online()) { /* The internet connection is down at the moment - apologize and do not redirect anywhere */ char * buf; safe_asprintf(&buf, "<p>We apologize, but it seems that the internet connection that powers this hotspot is temporarily unavailable.</p>" "<p>If at all possible, please notify the owners of this hotspot that the internet connection is out of service.</p>" "<p>The maintainers of this network are aware of this disruption. We hope that this situation will be resolved soon.</p>" "<p>In a while please <a href='%s'>click here</a> to try your request again.</p>", tmp_url); send_http_page(r, "Uh oh! Internet access unavailable!", buf); free(buf); debug(LOG_INFO, "Sent %s an apology since I am not online - no point sending them to auth server", r->clientAddr); } else if (!is_auth_online()) { /* The auth server is down at the moment - apologize and do not redirect anywhere */ char * buf; safe_asprintf(&buf, "<p>We apologize, but it seems that we are currently unable to re-direct you to the login screen.</p>" "<p>The maintainers of this network are aware of this disruption. We hope that this situation will be resolved soon.</p>" "<p>In a couple of minutes please <a href='%s'>click here</a> to try your request again.</p>", tmp_url); send_http_page(r, "Uh oh! Login screen unavailable!", buf); free(buf); debug(LOG_INFO, "Sent %s an apology since auth server not online - no point sending them to auth server", r->clientAddr); } else { //hector add 2014/3/18 get_oauth_iplist(); fw_set_oauthservers(); //hector end /* Re-direct them to auth server */ char *urlFragment; if (!(mac = arp_get(r->clientAddr))) { /* We could not get their MAC address */ debug(LOG_INFO, "Failed to retrieve MAC address for ip %s, so not putting in the login request", r->clientAddr); safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&url=%s", auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, url); } else { debug(LOG_INFO, "Got client MAC address for ip %s: %s", r->clientAddr, mac); safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&mac=%s&url=%s", auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, mac, url); } debug(LOG_INFO, "Captured %s requesting [%s] and re-directing them to login page", r->clientAddr, url); http_send_redirect_to_auth(r, urlFragment, "Redirect to login page"); free(urlFragment); } free(url); }
void http_callback_auth(httpd *webserver, request *r) { t_client *client; httpVar * token; char *mac; httpVar *logout = httpdGetVariableByName(r, "logout"); if ((token = httpdGetVariableByName(r, "token"))) { /* They supplied variable "token" */ if (!(mac = arp_get(r->clientAddr))) { /* We could not get their MAC address */ debug(LOG_ERR, "Failed to retrieve MAC address for ip %s", r->clientAddr); send_http_page(r, "WiFiDog Error", "Failed to retrieve your MAC address"); } else { /* We have their MAC address */ LOCK_CLIENT_LIST(); if ((client = client_list_find(r->clientAddr, mac)) == NULL) { debug(LOG_DEBUG, "New client for %s", r->clientAddr); client_list_append(r->clientAddr, mac, token->value); } else if (logout) { t_authresponse authresponse; s_config *config = config_get_config(); unsigned long long incoming = client->counters.incoming; unsigned long long outgoing = client->counters.outgoing; char *ip = safe_strdup(client->ip); char *urlFragment = NULL; t_auth_serv *auth_server = get_auth_server(); fw_deny(client->ip, client->mac, client->fw_connection_state); client_list_delete(client); debug(LOG_DEBUG, "Got logout from %s", client->ip); /* Advertise the logout if we have an auth server */ if (config->auth_servers != NULL) { UNLOCK_CLIENT_LIST(); auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, ip, mac, token->value, incoming, outgoing); LOCK_CLIENT_LIST(); /* Re-direct them to auth server */ debug(LOG_INFO, "Got manual logout from client ip %s, mac %s, token %s" "- redirecting them to logout message", client->ip, client->mac, client->token); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_ACCOUNT_LOGGED_OUT ); http_send_redirect_to_auth(r, urlFragment, "Redirect to logout message"); free(urlFragment); } free(ip); } else { debug(LOG_DEBUG, "Client for %s is already in the client list", client->ip); } UNLOCK_CLIENT_LIST(); if (!logout) { authenticate_client(r); } free(mac); } } else { /* They did not supply variable "token" */ send_http_page(r, "WiFiDog error", "Invalid token"); } }
/** Authenticates a single client against the central server and returns when done * Alters the firewall rules depending on what the auth server says @param r httpd request struct */ void authenticate_client(request * r) { t_client *client, *tmp; t_authresponse auth_response; char *token; httpVar *var; char *urlFragment = NULL; s_config *config = NULL; t_auth_serv *auth_server = NULL; LOCK_CLIENT_LIST(); client = client_dup(client_list_find_by_ip(r->clientAddr)); UNLOCK_CLIENT_LIST(); if (client == NULL) { debug(LOG_ERR, "authenticate_client(): Could not find client for %s", r->clientAddr); return; } /* Users could try to log in(so there is a valid token in * request) even after they have logged in, try to deal with * this */ if ((var = httpdGetVariableByName(r, "token")) != NULL) { token = safe_strdup(var->value); } else { token = safe_strdup(client->token); } /* * At this point we've released the lock while we do an HTTP request since it could * take multiple seconds to do and the gateway would effectively be frozen if we * kept the lock. */ auth_server_request(&auth_response, REQUEST_TYPE_LOGIN, client->ip, client->mac, token, 0, 0); LOCK_CLIENT_LIST(); /* can't trust the client to still exist after n seconds have passed */ tmp = client_list_find_by_client(client); if (NULL == tmp) { debug(LOG_ERR, "authenticate_client(): Could not find client node for %s (%s)", client->ip, client->mac); UNLOCK_CLIENT_LIST(); client_list_destroy(client); /* Free the cloned client */ free(token); return; } client_list_destroy(client); /* Free the cloned client */ client = tmp; if (strcmp(token, client->token) != 0) { /* If token changed, save it. */ free(client->token); client->token = token; } else { free(token); } /* Prepare some variables we'll need below */ config = config_get_config(); auth_server = get_auth_server(); switch (auth_response.authcode) { case AUTH_ERROR: /* Error talking to central server */ debug(LOG_ERR, "Got ERROR from central server authenticating token %s from %s at %s", client->token, client->ip, client->mac); send_http_page(r, "Error!", "Error: We did not get a valid answer from the central server"); break; case AUTH_DENIED: /* Central server said invalid token */ debug(LOG_INFO, "Got DENIED from central server authenticating token %s from %s at %s - deleting from firewall and redirecting them to denied message", client->token, client->ip, client->mac); fw_deny(client); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_DENIED); http_send_redirect_to_auth(r, urlFragment, "Redirect to denied message"); free(urlFragment); break; case AUTH_VALIDATION: /* They just got validated for X minutes to check their email */ debug(LOG_INFO, "Got VALIDATION from central server authenticating token %s from %s at %s" "- adding to firewall and redirecting them to activate message", client->token, client->ip, client->mac); fw_allow(client, FW_MARK_PROBATION); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_ACTIVATE_ACCOUNT); http_send_redirect_to_auth(r, urlFragment, "Redirect to activate message"); free(urlFragment); break; case AUTH_ALLOWED: /* Logged in successfully as a regular account */ debug(LOG_INFO, "Got ALLOWED from central server authenticating token %s from %s at %s - " "adding to firewall and redirecting them to portal", client->token, client->ip, client->mac); fw_allow(client, FW_MARK_KNOWN); // add by zp debug(LOG_INFO,"goto fw_allow()..."); served_this_session++; safe_asprintf(&urlFragment, "%sgw_id=%s", auth_server->authserv_portal_script_path_fragment, config->gw_id); // modify by zp http_send_redirect_to_auth(r, urlFragment, "Redirect to portal"); //char * text = "advertisement"; //http_send_redirect_to_advertisement(r, urlFragment, text); free(urlFragment); break; case AUTH_VALIDATION_FAILED: /* Client had X minutes to validate account by email and didn't = too late */ debug(LOG_INFO, "Got VALIDATION_FAILED from central server authenticating token %s from %s at %s " "- redirecting them to failed_validation message", client->token, client->ip, client->mac); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_ACCOUNT_VALIDATION_FAILED); http_send_redirect_to_auth(r, urlFragment, "Redirect to failed validation message"); free(urlFragment); break; default: debug(LOG_WARNING, "I don't know what the validation code %d means for token %s from %s at %s - sending error message", auth_response.authcode, client->token, client->ip, client->mac); send_http_page(r, "Internal Error", "We can not validate your request at this time"); break; } UNLOCK_CLIENT_LIST(); return; }
/** Authenticates a single client against the central server and returns when done * Alters the firewall rules depending on what the auth server says @param r httpd request struct */ void authenticate_client(request *r, char *gw_id) { t_client *client; t_authresponse auth_response; char *mac, *token; char *urlFragment = NULL; s_config *config = NULL; t_auth_serv *auth_server = NULL; LOCK_CLIENT_LIST(); client = client_list_find_by_ip(r->clientAddr); if (client == NULL) { debug(LOG_ERR, "Could not find client for %s", r->clientAddr); UNLOCK_CLIENT_LIST(); return; } mac = safe_strdup(client->mac); token = safe_strdup(client->token); UNLOCK_CLIENT_LIST(); /* * At this point we've released the lock while we do an HTTP request since it could * take multiple seconds to do and the gateway would effectively be frozen if we * kept the lock. */ auth_server_request(&auth_response, REQUEST_TYPE_LOGIN, r->clientAddr, mac, token, 0, 0, gw_id); LOCK_CLIENT_LIST(); /* can't trust the client to still exist after n seconds have passed */ client = client_list_find(r->clientAddr, mac); if (client == NULL) { debug(LOG_ERR, "Could not find client node for %s (%s)", r->clientAddr, mac); UNLOCK_CLIENT_LIST(); free(token); free(mac); return; } free(token); free(mac); /* Prepare some variables we'll need below */ config = config_get_config(); auth_server = get_auth_server(); switch(auth_response.authcode) { case AUTH_ERROR: /* Error talking to central server */ debug(LOG_ERR, "Got %d from central server authenticating token %s from %s at %s", auth_response, client->token, client->ip, client->mac); send_http_page(r, "Error!", "Error: We did not get a valid answer from the central server"); break; case AUTH_DENIED: /* Central server said invalid token */ debug(LOG_INFO, "Got DENIED from central server authenticating token %s from %s at %s - redirecting them to denied message", client->token, client->ip, client->mac); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_DENIED ); http_send_redirect_to_auth(r, urlFragment, "Redirect to portal", gw_id); //set connection logged out (xperimental) //snprintf(,client->token, client->ip, client->mac) /*{ char mysqlCmd[256]; sprintf(mysqlCmd,"echo \"DELETE FROM connections WHERE token='%s';\"|mysql -uauthpuppy -pauthpuppydev authpuppy > /tmp/wifidog_deauth_mysql_result",client->token); debug(LOG_WARNING,"issuing this would help: %s",mysqlCmd); //system(mysqlCmd);//kills wifidog somehow *g }*/ free(urlFragment); //for race conditions, remove from firewall fw_deny(client->ip, client->mac, client->fw_connection_state); //experimental delete client from list client_list_delete(client); break; case AUTH_VALIDATION: /* They just got validated for X minutes to check their email */ debug(LOG_INFO, "Got VALIDATION from central server authenticating token %s from %s at %s" "- adding to firewall and redirecting them to activate message", client->token, client->ip, client->mac); client->fw_connection_state = FW_MARK_PROBATION; fw_allow(client->ip, client->mac, FW_MARK_PROBATION); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_ACTIVATE_ACCOUNT ); http_send_redirect_to_auth(r, urlFragment, "Redirect to activate message", gw_id); free(urlFragment); break; case AUTH_ALLOWED: /* Logged in successfully as a regular account */ debug(LOG_INFO, "Got ALLOWED from central server authenticating token %s from %s at %s - " "adding to firewall and redirecting them to portal", client->token, client->ip, client->mac); client->fw_connection_state = FW_MARK_KNOWN; fw_allow(client->ip, client->mac, FW_MARK_KNOWN); served_this_session++; safe_asprintf(&urlFragment, "%sgw_id=%s", auth_server->authserv_portal_script_path_fragment, gw_id ); http_send_redirect_to_auth(r, urlFragment, "Redirect to portal", gw_id); free(urlFragment); break; case AUTH_VALIDATION_FAILED: /* Client had X minutes to validate account by email and didn't = too late */ debug(LOG_INFO, "Got VALIDATION_FAILED from central server authenticating token %s from %s at %s " "- redirecting them to failed_validation message", client->token, client->ip, client->mac); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_ACCOUNT_VALIDATION_FAILED ); http_send_redirect_to_auth(r, urlFragment, "Redirect to failed validation message", gw_id); free(urlFragment); break; default: debug(LOG_WARNING, "I don't know what the validation code %d means for token %s from %s at %s - sending error message", auth_response.authcode, client->token, client->ip, client->mac); send_http_page(r, "Internal Error", "We can not validate your request at this time"); break; } UNLOCK_CLIENT_LIST(); return; }