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"); } }
void http_callback_disconnect(httpd * webserver, request * r) { const s_config *config = config_get_config(); /* XXX How do you change the status code for the response?? */ httpVar *token = httpdGetVariableByName(r, "token"); httpVar *mac = httpdGetVariableByName(r, "mac"); if (config->httpdusername && (strcmp(config->httpdusername, r->request.authUser) || strcmp(config->httpdpassword, r->request.authPassword))) { debug(LOG_INFO, "Disconnect requested, forcing authentication"); httpdForceAuthenticate(r, config->httpdrealm); return; } if (token && mac) { t_client *client; LOCK_CLIENT_LIST(); client = client_list_find_by_mac(mac->value); if (!client || strcmp(client->token, token->value)) { UNLOCK_CLIENT_LIST(); debug(LOG_INFO, "Disconnect %s with incorrect token %s", mac->value, token->value); httpdOutput(r, "Invalid token for MAC"); return; } /* TODO: get current firewall counters */ logout_client(client); UNLOCK_CLIENT_LIST(); } else { debug(LOG_INFO, "Disconnect called without both token and MAC given"); httpdOutput(r, "Both the token and MAC need to be specified"); return; } return; }
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_add(r->clientAddr, mac, token->value); } 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"); } }
/**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); }