/** * @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); }
static int check_token_is_valid(struct MHD_Connection *connection, t_client *client) { /* token check */ struct collect_query_key query_key = { .key = "token" }; MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &collect_query_key, &query_key); /* token not found in query string */ if (!query_key.value) return 0; /* token doesn't match */ if (strcmp(client->token, query_key.value)) return 0; return 1; } /** * @brief try_to_authenticate * @param connection * @param client * @param host * @param url * @return */ static int try_to_authenticate(struct MHD_Connection *connection, t_client *client, const char *host, const char *url) { /* a successful auth looks like * http://192.168.42.1:2050/nodogsplash_auth/?redir=http%3A%2F%2Fberlin.freifunk.net%2F&tok=94c4cdd2 * when authaction -> http://192.168.42.1:2050/nodogsplash_auth/ */ s_config *config = config_get_config(); /* we are checking here for the second '/' of /denydir/ */ if (check_authdir_match(url, config->authdir)) { /* matched to authdir */ if (check_token_is_valid(connection, client)) { return 1; /* valid token */ } } else if (check_authdir_match(url, config->denydir)) { /* matched to deauth */ /* TODO: do we need denydir? */ return 0; } return 0; }
/** * @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); }
static int check_token_is_valid(struct MHD_Connection *connection, t_client *client) { /* token check */ struct collect_query_key token_key = { .key = "token" }; struct collect_query_key tok_key = { .key = "tok" }; MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &collect_query_key, &token_key); MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &collect_query_key, &tok_key); /* token not found in query string */ if (!token_key.value && !tok_key.value) return 0; if (token_key.value && !strcmp(client->token, token_key.value)) return 1; if (tok_key.value && !strcmp(client->token, tok_key.value)) return 1; return 0; } /** * @brief try_to_authenticate * @param connection * @param client * @param host * @param url * @return */ static int try_to_authenticate(struct MHD_Connection *connection, t_client *client, const char *host, const char *url) { /* a successful auth looks like * http://192.168.42.1:2050/nodogsplash_auth/?redir=http%3A%2F%2Fberlin.freifunk.net%2F&tok=94c4cdd2 * when authaction -> http://192.168.42.1:2050/nodogsplash_auth/ */ s_config *config = config_get_config(); /* we are checking here for the second '/' of /denydir/ */ if (check_authdir_match(url, config->authdir)) { /* matched to authdir */ if (check_token_is_valid(connection, client)) { return 1; /* valid token */ } } else if (check_authdir_match(url, config->denydir)) { /* matched to deauth */ /* TODO: do we need denydir? */ return 0; } return 0; } /** * @brief authenticate the client and redirect them * @param connection * @param ip_addr - needs to be freed * @param mac - needs to be freed * @param redirect_url - redirect the client to this url * @return */ static int authenticate_client(struct MHD_Connection *connection, const char *ip_addr, const char *mac, const char *redirect_url, t_client *client) { /* TODO: handle redirect_url == NULL */ auth_client_action(ip_addr, mac, AUTH_MAKE_AUTHENTICATED); if (redirect_url) return send_redirect_temp(connection, redirect_url); else return send_error(connection, 200); }