void http_callback_logout(httpd *webserver, request *r) { t_client *client; s_config *config = config_get_config(); LOCK_CLIENT_LIST(); client = client_list_find_by_ip(r->clientAddr); /* Send logout to auth server if client is logged in */ if (client != NULL) { t_authresponse authresponse; char *ip = strdup(client->ip); char *mac = strdup(client->mac); char *token = strdup(client->token); unsigned long long incoming = client->counters.incoming; unsigned long long outgoing = client->counters.outgoing; debug(LOG_INFO, "Got manual logout from client ip %s, mac %s, token %s", client->ip, client->mac, client->token); fw_deny(client->ip, client->mac, client->fw_connection_state); client_list_delete(client); /* Unlock client list here since auth_server_request may take a while */ UNLOCK_CLIENT_LIST(); /* Advertise the logout if we have an auth server */ if (config->auth_servers != NULL) { auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, ip, mac, token, incoming, outgoing); } free(ip); free(mac); free(token); } else { /* Do nothing if the client is not in the client list (i.e. not logged in) */ debug(LOG_INFO, "Got manual logout from client %s, but client not in list", r->clientAddr); UNLOCK_CLIENT_LIST(); } if (config->auth_servers != NULL) { /* Re-direct them to auth server */ char *urlFragment = NULL; t_auth_serv *auth_server = get_auth_server(); 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); } }
/** * @brief Logout a client and report to auth server. * * This function assumes it is being called with the client lock held! This * function remove the client from the client list and free its memory, so * client is no langer valid when this method returns. * * @param client Points to the client to be logged out */ void logout_client(t_client * client) { t_authresponse authresponse; const s_config *config = config_get_config(); fw_deny(client); client_list_remove(client); /* Advertise the logout if we have an auth server */ if (config->auth_servers != NULL) { UNLOCK_CLIENT_LIST(); auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, client->ip, client->mac, client->token, client->counters.incoming, client->counters.outgoing); if (authresponse.authcode == AUTH_ERROR) debug(LOG_WARNING, "Auth server error when reporting logout"); LOCK_CLIENT_LIST(); } client_free_node(client); }
void update_trusted_mac_list_status(void) { t_authresponse authresponse; t_trusted_mac *p1 = NULL, *tmac_list = NULL; s_config *config = config_get_config(); if(trusted_mac_list_dup(&tmac_list) == 0) { debug(LOG_INFO, "update_trusted_mac_list_status: list is empty"); return; } for(p1 = tmac_list; p1 != NULL; p1 = p1->next) { update_trusted_mac_status(p1); debug(LOG_INFO, "update_trusted_mac_list_status: %s %s %d", p1->ip, p1->mac, p1->is_online); if (config->auth_servers != NULL && p1->is_online) { auth_server_request(&authresponse, REQUEST_TYPE_COUNTERS, p1->ip, p1->mac, "null", 0, 0, 0, 0, 0, 0, "null", is_device_wired(p1->mac)); } } clear_dup_trusted_mac_list(tmac_list); }
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"); } }
/**Probably a misnomer, this function actually refreshes the entire client list's traffic counter, re-authenticates every client with the central server and update's the central servers traffic counters and notifies it if a client has logged-out. * @todo Make this function smaller and use sub-fonctions */ void fw_sync_with_authserver(void) { t_authresponse authresponse; t_client *p1, *p2, *worklist, *tmp; s_config *config = config_get_config(); if (-1 == iptables_fw_counters_update()) { debug(LOG_ERR, "Could not get counters from firewall!"); return; } LOCK_CLIENT_LIST(); /* XXX Ideally, from a thread safety PoV, this function should build a list of client pointers, * iterate over the list and have an explicit "client still valid" check while list is locked. * That way clients can disappear during the cycle with no risk of trashing the heap or getting * a SIGSEGV. */ client_list_dup(&worklist); UNLOCK_CLIENT_LIST(); for (p1 = p2 = worklist; NULL != p1; p1 = p2) { p2 = p1->next; /* Ping the client, if he responds it'll keep activity on the link. * However, if the firewall blocks it, it will not help. The suggested * way to deal witht his is to keep the DHCP lease time extremely * short: Shorter than config->checkinterval * config->clienttimeout */ icmp_ping(p1->ip); /* Update the counters on the remote server only if we have an auth server */ if (config->auth_servers != NULL) { auth_server_request(&authresponse, REQUEST_TYPE_COUNTERS, p1->ip, p1->mac, p1->token, p1->counters.incoming, p1->counters.outgoing, p1->counters.incoming_delta, p1->counters.outgoing_delta); } time_t current_time = time(NULL); debug(LOG_INFO, "Checking client %s for timeout: Last updated %ld (%ld seconds ago), timeout delay %ld seconds, current time %ld, ", p1->ip, p1->counters.last_updated, current_time - p1->counters.last_updated, config->checkinterval * config->clienttimeout, current_time); if (p1->counters.last_updated + (config->checkinterval * config->clienttimeout) <= current_time) { /* Timing out user */ debug(LOG_INFO, "%s - Inactive for more than %ld seconds, removing client and denying in firewall", p1->ip, config->checkinterval * config->clienttimeout); LOCK_CLIENT_LIST(); tmp = client_list_find_by_client(p1); if (NULL != tmp) { logout_client(tmp); } else { debug(LOG_NOTICE, "Client was already removed. Not logging out."); } UNLOCK_CLIENT_LIST(); } else { /* * This handles any change in * the status this allows us * to change the status of a * user while he's connected * * Only run if we have an auth server * configured! */ LOCK_CLIENT_LIST(); tmp = client_list_find_by_client(p1); if (NULL == tmp) { UNLOCK_CLIENT_LIST(); debug(LOG_NOTICE, "Client was already removed. Skipping auth processing"); continue; /* Next client please */ } if (config->auth_servers != NULL) { switch (authresponse.authcode) { case AUTH_DENIED: debug(LOG_NOTICE, "%s - Denied. Removing client and firewall rules", tmp->ip); fw_deny(tmp); client_list_delete(tmp); break; case AUTH_VALIDATION_FAILED: debug(LOG_NOTICE, "%s - Validation timeout, now denied. Removing client and firewall rules", tmp->ip); fw_deny(tmp); client_list_delete(tmp); break; case AUTH_ALLOWED: if (tmp->fw_connection_state != FW_MARK_KNOWN) { debug(LOG_INFO, "%s - Access has changed to allowed, refreshing firewall and clearing counters", tmp->ip); //WHY did we deny, then allow!?!? benoitg 2007-06-21 //fw_deny(tmp->ip, tmp->mac, tmp->fw_connection_state); /* XXX this was possibly to avoid dupes. */ if (tmp->fw_connection_state != FW_MARK_PROBATION) { tmp->counters.incoming_delta = tmp->counters.outgoing_delta = tmp->counters.incoming = tmp->counters.outgoing = 0; } else { //We don't want to clear counters if the user was in validation, it probably already transmitted data.. debug(LOG_INFO, "%s - Skipped clearing counters after all, the user was previously in validation", tmp->ip); } fw_allow(tmp, FW_MARK_KNOWN); } break; case AUTH_VALIDATION: /* * Do nothing, user * is in validation * period */ debug(LOG_INFO, "%s - User in validation period", tmp->ip); break; case AUTH_ERROR: debug(LOG_WARNING, "Error communicating with auth server - leaving %s as-is for now", tmp->ip); break; default: debug(LOG_ERR, "I do not know about authentication code %d", authresponse.authcode); break; } } UNLOCK_CLIENT_LIST(); } } client_list_destroy(worklist); }
/** 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; }