/** * @brief authenticated - called for all request from authenticated clients. * @param connection * @param ip_addr * @param mac * @param url * @param client * @return * * It's unsual to received request from clients which are already authed. * Happens when the user: * - clicked in multiple windows on "accept" -> redirect to origin - no checking * - when the user reloaded a splashpage -> redirect to origin * - when a user calls deny url -> deauth it */ static int authenticated(struct MHD_Connection *connection, const char *ip_addr, const char *mac, const char *url, t_client *client) { s_config *config = config_get_config(); const char *redirect_url; const char *host = NULL; char redirect_to_us[128]; MHD_get_connection_values(connection, MHD_HEADER_KIND, get_host_value_callback, &host); if (is_splashpage(host, url) || check_authdir_match(url, config->authdir)) { redirect_url = get_redirect_url(connection); /* TODO: what should we do when we get such request? */ if (redirect_url == NULL || strlen(redirect_url) == 0) return show_splashpage(connection, client); else return authenticate_client(connection, ip_addr, mac, redirect_url, client); } else if (check_authdir_match(url, config->denydir)) { auth_client_action(ip_addr, mac, AUTH_MAKE_DEAUTHENTICATED); snprintf(redirect_to_us, 128, "http://%s:%u/", config->gw_address, config->gw_port); return send_redirect_temp(connection, redirect_to_us); } /* user doesn't wants the splashpage or tried to auth itself */ return serve_file(connection, client, url); }
/** * @brief preauthenticated - called for all request of a client in this state. * @param connection * @param ip_addr * @param mac * @return */ static int preauthenticated(struct MHD_Connection *connection, const char *ip_addr, const char *mac, const char *url, t_client *client) { char *host = NULL; const char *redirect_url; s_config *config = config_get_config(); if (!client) { client = add_client(ip_addr); if (!client) return send_error(connection, 503); } MHD_get_connection_values(connection, MHD_HEADER_KIND, get_host_value_callback, &host); /* check if this is a redirect querty with a foreign host as target */ if(is_foreign_hosts(connection, host)) { return redirect_to_splashpage(connection, client, host, url); } /* request is directed to us */ /* check if client wants to be authenticated */ if(check_authdir_match(url, config->authdir)) { /* Only the first request will redirected to config->redirectURL. * When the client reloads a page when it's authenticated, it should be redirected * to their origin url */ if (config->redirectURL) redirect_url = config->redirectURL; else redirect_url = get_redirect_url(connection); if (try_to_authenticate(connection, client, host, url)) { return authenticate_client(connection, ip_addr, mac, redirect_url, client); } else { /* user used an invalid token, redirect to splashpage but hold query "redir" intact */ return encode_and_redirect_to_splashpage(connection, redirect_url); } } if(is_splashpage(host, url)) { return show_splashpage(connection, client); } /* no special handling left - try to serve static content to the user */ return serve_file(connection, client, url); }
/** * @brief authenticated - called for all request from authenticated clients. * @param connection * @param ip_addr * @param mac * @param url * @param client * @return * * It's unsual to received request from clients which are already authed. * Happens when the user: * - clicked in multiple windows on "accept" -> redirect to origin - no checking * - when the user reloaded a splashpage -> redirect to origin * - when a user calls deny url -> deauth it */ static int authenticated(struct MHD_Connection *connection, const char *ip_addr, const char *mac, const char *url, t_client *client) { s_config *config = config_get_config(); const char *redirect_url; const char *host = NULL; char redirect_to_us[128]; MHD_get_connection_values(connection, MHD_HEADER_KIND, get_host_value_callback, &host); if (is_splashpage(host, url) || check_authdir_match(url, config->authdir)) { redirect_url = get_redirect_url(connection); /* TODO: what should we do when we get such request? */ if (redirect_url == NULL || strlen(redirect_url) == 0) return show_splashpage(connection, client); else return authenticate_client(connection, ip_addr, mac, redirect_url, client); } else if (check_authdir_match(url, config->denydir)) { auth_client_action(ip_addr, mac, AUTH_MAKE_DEAUTHENTICATED); snprintf(redirect_to_us, 128, "http://%s:%u/", config->gw_address, config->gw_port); return send_redirect_temp(connection, redirect_to_us); } /* check if this is an late request meaning the user tries to get the internet, but ended up here, * because the iptables rule came to late */ if (is_foreign_hosts(connection, host)) { /* might happen if the firewall rule isn't yet installed */ return send_refresh(connection); } /* user doesn't wants the splashpage or tried to auth itself */ return serve_file(connection, client, url); }
/** * @brief show_splashpage is called when the client clicked on Ok as well when the client doesn't know us yet. * @param connection * @param client * @return */ static int show_splashpage(struct MHD_Connection *connection, t_client *client) { struct MHD_Response *response; struct templater templor; s_config *config = config_get_config(); int ret = -1; char filename[PATH_MAX]; const char *mimetype; int size = 0, bytes = 0; int splashpage_fd; char *splashpage_result; char *splashpage_tmpl; snprintf(filename, PATH_MAX, "%s/%s",config->webroot ,config->splashpage); splashpage_fd = open(filename, O_RDONLY); if (splashpage_fd < 0) return send_error(connection, 404); mimetype = lookup_mimetype(filename); /* input size */ size = lseek(splashpage_fd, 0, SEEK_END); lseek(splashpage_fd, 0, SEEK_SET); /* we TMPLVAR_SIZE for template variables */ splashpage_tmpl = calloc(1, size); splashpage_result = calloc(1, size + TMPLVAR_SIZE); while (bytes < size) { ret = read(splashpage_fd, splashpage_tmpl+bytes, size-bytes); if (ret < 0) { free(splashpage_result); free(splashpage_tmpl); close(splashpage_fd); return send_error(connection, 503); } bytes += ret; } char *uptime = get_uptime_string(); char *nclients = NULL; char *maxclients = NULL; char *denyaction = NULL; char *authaction = NULL; char *authtarget = NULL; const char *redirect_url = NULL; char redirect_url_encoded[2048]; char *imagesdir = NULL; char *pagesdir = NULL; memset(redirect_url_encoded, 0, sizeof(redirect_url_encoded)); redirect_url = get_redirect_url(connection); if (redirect_url) { uh_urlencode(redirect_url_encoded, sizeof(redirect_url_encoded), redirect_url, strlen(redirect_url)); } safe_asprintf(&nclients, "%d", get_client_list_length()); safe_asprintf(&maxclients, "%d", config->maxclients); safe_asprintf(&denyaction, "http://%s:%d/%s/", config->gw_address, config->gw_port, config->denydir); safe_asprintf(&authaction, "http://%s:%d/%s/", config->gw_address, config->gw_port, config->authdir); safe_asprintf(&authtarget, "http://%s:%d/%s/?token=%s&redir=%s", config->gw_address, config->gw_port, config->authdir, client->token, redirect_url_encoded); safe_asprintf(&authaction, "http://%s:%d/%s/", config->gw_address, config->gw_port, config->authdir); safe_asprintf(&pagesdir, "/%s", config->pagesdir); safe_asprintf(&imagesdir, "/%s", config->imagesdir); tmpl_init_templor(&templor); tmpl_set_variable(&templor, "authaction", authaction); tmpl_set_variable(&templor, "authtarget", authtarget); tmpl_set_variable(&templor, "clientip", client->ip); tmpl_set_variable(&templor, "clientmac", client->mac); // tmpl_set_variable(&templor, "content", VERSION); tmpl_set_variable(&templor, "denyaction", denyaction); tmpl_set_variable(&templor, "error_msg", ""); tmpl_set_variable(&templor, "gatewaymac", config->gw_mac); tmpl_set_variable(&templor, "gatewayname", config->gw_name); tmpl_set_variable(&templor, "imagesdir", imagesdir); tmpl_set_variable(&templor, "pagesdir", pagesdir); tmpl_set_variable(&templor, "maxclients", maxclients); tmpl_set_variable(&templor, "nclients", nclients); tmpl_set_variable(&templor, "redir", redirect_url); tmpl_set_variable(&templor, "tok", client->token); tmpl_set_variable(&templor, "uptime", uptime); tmpl_set_variable(&templor, "version", VERSION); tmpl_parse(&templor, splashpage_result, size + TMPLVAR_SIZE, splashpage_tmpl, size); free(authaction); free(denyaction); free(maxclients); free(nclients); free(uptime); free(splashpage_tmpl); free(imagesdir); response = MHD_create_response_from_buffer(strlen(splashpage_result), (void *)splashpage_result, MHD_RESPMEM_MUST_FREE); if (!response) { close(splashpage_fd); return send_error(connection, 503); } MHD_add_response_header(response, "Content-Type", mimetype); ret = MHD_queue_response(connection, MHD_HTTP_OK, response); MHD_destroy_response(response); close(splashpage_fd); return ret; }