diff --git a/hostapd/hostapd_cli.1 b/hostapd/hostapd_cli.1 index 2fe4907..f2c0412 100644 --- a/hostapd/hostapd_cli.1 +++ b/hostapd/hostapd_cli.1 @@ -3,7 +3,7 @@ hostapd_cli \- hostapd command-line interface .SH SYNOPSIS .B hostapd_cli -[\-p] [\-i] [\-hv] [command..] +[\-p] [\-i] [\-a] [\-hv] [command..] .SH DESCRIPTION This manual page documents briefly the .B hostapd_cli @@ -38,6 +38,9 @@ Interface to listen on. Default: first interface found in socket path. .TP +.B \-a +Run in daemon mode executing the action file based on events from hostapd. +.TP .B \-h Show usage. .TP diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index 2cfaf58..804d3fb 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -105,6 +105,8 @@ static int hostapd_cli_attached = 0; static const char *ctrl_iface_dir = "/var/run/hostapd"; static char *ctrl_ifname = NULL; static int ping_interval = 5; +static char *action_file = NULL; +static const char *pid_file = NULL; static void usage(void) @@ -112,7 +114,7 @@ static void usage(void) fprintf(stderr, "%s\n", hostapd_cli_version); fprintf(stderr, "\n" - "usage: hostapd_cli [-p] [-i] [-hv] " + "usage: hostapd_cli [-p] [-i] [-hv] [-a] " "[-G] \\\n" " [command..]\n" "\n" @@ -121,6 +123,8 @@ static void usage(void) " -v shown version information\n" " -p path to find control sockets (default: " "/var/run/hostapd)\n" + " -a run in daemon mode executing the action" + " file based on events from hostapd\n" " -i Interface to listen on (default: first " "interface found in the\n" " socket path)\n\n" @@ -213,6 +217,49 @@ static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "MIB"); } + +static int hostapd_cli_exec(const char *program, const char *arg1, + const char *arg2) +{ + char *cmd; + size_t len; + int res; + int ret = 0; + + len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3; + cmd = os_malloc(len); + if (cmd == NULL) + return -1; + res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2); + if (res < 0 || (size_t) res >= len) { + os_free(cmd); + return -1; + } + cmd[len - 1] = '\0'; +#ifndef _WIN32_WCE + if (system(cmd) < 0) + ret = -1; +#endif /* _WIN32_WCE */ + os_free(cmd); + + return ret; +} + +static void hostapd_cli_action_process(char *msg, size_t len) +{ + const char *pos; + + pos = msg; + if (*pos == '<') { + pos = os_strchr(pos, '>'); + if (pos) + pos++; + else + pos = msg; + } + + hostapd_cli_exec(action_file, ctrl_ifname, pos); +} static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) @@ -520,7 +567,8 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) } -static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read) +static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, + int action_monitor) { int first = 1; if (ctrl_conn == NULL) @@ -530,10 +578,14 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read) size_t len = sizeof(buf) - 1; if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { buf[len] = '\0'; - if (in_read && first) - printf("\n"); - first = 0; - printf("%s\n", buf); + if (action_monitor) + hostapd_cli_action_process(buf, len); + else { + if (in_read && first) + printf("\n"); + first = 0; + printf("%s\n", buf); + } } else { printf("Could not read pending message.\n"); break; @@ -551,7 +603,7 @@ static void hostapd_cli_interactive(void) printf("\nInteractive mode\n\n"); do { - hostapd_cli_recv_pending(ctrl_conn, 0); + hostapd_cli_recv_pending(ctrl_conn, 0, 0); printf("> "); alarm(ping_interval); res = fgets(cmd, sizeof(cmd), stdin); @@ -591,6 +643,8 @@ static void hostapd_cli_interactive(void) static void hostapd_cli_terminate(int sig) { hostapd_cli_close_connection(); + if (pid_file) + os_daemonize_terminate(pid_file); exit(0); } @@ -614,10 +668,45 @@ static void hostapd_cli_alarm(int sig) } } if (ctrl_conn) - hostapd_cli_recv_pending(ctrl_conn, 1); + hostapd_cli_recv_pending(ctrl_conn, 1, 0); alarm(ping_interval); } +static void hostapd_cli_action(struct wpa_ctrl *ctrl) +{ + fd_set rfds; + int fd, res; + struct timeval tv; + char buf[256]; + size_t len; + + fd = wpa_ctrl_get_fd(ctrl); + + while (!hostapd_cli_quit) { + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = ping_interval; + tv.tv_usec = 0; + res = select(fd + 1, &rfds, NULL, NULL, &tv); + if (res < 0 && errno != EINTR) { + perror("select"); + break; + } + + if (FD_ISSET(fd, &rfds)) + hostapd_cli_recv_pending(ctrl, 0, 1); + else { + len = sizeof(buf) - 1; + if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, + hostapd_cli_action_process) < 0 || + len < 4 || os_memcmp(buf, "PONG", 4) != 0) { + printf("hostapd did not reply to PING " + "command - exiting\n"); + break; + } + } + } +} int main(int argc, char *argv[]) { @@ -629,7 +718,7 @@ int main(int argc, char *argv[]) return -1; for (;;) { - c = getopt(argc, argv, "hG:i:p:v"); + c = getopt(argc, argv, "hG:i:p:a:v"); if (c < 0) break; switch (c) { @@ -649,13 +738,16 @@ int main(int argc, char *argv[]) case 'p': ctrl_iface_dir = optarg; break; + case 'a': + action_file = optarg; + break; default: usage(); return -1; } } - interactive = argc == optind; + interactive = (argc == optind) && (action_file == NULL); if (interactive) { printf("%s\n\n%s\n\n", hostapd_cli_version, @@ -704,13 +796,21 @@ int main(int argc, char *argv[]) signal(SIGTERM, hostapd_cli_terminate); signal(SIGALRM, hostapd_cli_alarm); - if (interactive) { + if (interactive || action_file) { if (wpa_ctrl_attach(ctrl_conn) == 0) { hostapd_cli_attached = 1; } else { printf("Warning: Failed to attach to hostapd.\n"); + if (action_file) + return -1; } + } + + if (interactive) hostapd_cli_interactive(); + else if (action_file) { + os_daemonize(pid_file); + hostapd_cli_action(ctrl_conn); } else wpa_request(ctrl_conn, argc - optind, &argv[optind]); diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c index b901143..1dd03bb 100644 --- a/src/ap/authsrv.c +++ b/src/ap/authsrv.c @@ -104,6 +104,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd) srv.conf_ctx = conf; srv.eap_sim_db_priv = hapd->eap_sim_db_priv; srv.ssl_ctx = hapd->ssl_ctx; + srv.msg_ctx = hapd; srv.pac_opaque_encr_key = conf->pac_opaque_encr_key; srv.eap_fast_a_id = conf->eap_fast_a_id; srv.eap_fast_a_id_len = conf->eap_fast_a_id_len; diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 61ca690..1389012 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -29,6 +29,7 @@ #include "wmm.h" #include "wps_hostapd.h" #include "ap_config.h" +#include "common/wpa_ctrl.h" int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, @@ -131,6 +132,10 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) HOSTAPD_LEVEL_INFO, "disassociated"); sta = ap_get_sta(hapd, addr); + + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, + MAC2STR(sta->addr)); + if (sta == NULL) { wpa_printf(MSG_DEBUG, "Disassociation notification for " "unknown STA " MACSTR, MAC2STR(addr)); diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 69df06e..6281d1a 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -1612,6 +1612,7 @@ int ieee802_1x_init(struct hostapd_data *hapd) conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; conf.eap_server = hapd->conf->eap_server; conf.ssl_ctx = hapd->ssl_ctx; + conf.msg_ctx = hapd; conf.eap_sim_db_priv = hapd->eap_sim_db_priv; conf.eap_req_id_text = hapd->conf->eap_req_id_text; conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h index 27aa3ad..92400a5 100644 --- a/src/eap_server/eap.h +++ b/src/eap_server/eap.h @@ -91,6 +91,7 @@ struct eapol_callbacks { struct eap_config { void *ssl_ctx; + void *msg_ctx; void *eap_sim_db_priv; Boolean backend_auth; int eap_server; diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c index 6ac8aaa..4cab755 100644 --- a/src/eap_server/eap_server.c +++ b/src/eap_server/eap_server.c @@ -23,6 +23,7 @@ #include "common.h" #include "eap_i.h" #include "state_machine.h" +#include "common/wpa_ctrl.h" #define STATE_MACHINE_DATA struct eap_sm #define STATE_MACHINE_DEBUG_PREFIX "EAP" @@ -167,6 +168,9 @@ SM_STATE(EAP, INITIALIZE) } sm->num_rounds = 0; sm->method_pending = METHOD_PENDING_NONE; + + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED + MACSTR, MAC2STR(sm->peer_addr)); } @@ -196,6 +200,9 @@ SM_STATE(EAP, PICK_UP_METHOD) sm->currentMethod = EAP_TYPE_NONE; } } + + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD + "method=%u", sm->currentMethod); } @@ -410,6 +417,9 @@ SM_STATE(EAP, FAILURE) wpabuf_free(sm->lastReqData); sm->lastReqData = NULL; sm->eap_if.eapFail = TRUE; + + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE + MACSTR, MAC2STR(sm->peer_addr)); } @@ -424,6 +434,9 @@ SM_STATE(EAP, SUCCESS) if (sm->eap_if.eapKeyData) sm->eap_if.eapKeyAvailable = TRUE; sm->eap_if.eapSuccess = TRUE; + + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS + MACSTR, MAC2STR(sm->peer_addr)); } @@ -1210,6 +1223,7 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx, sm->eapol_cb = eapol_cb; sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */ sm->ssl_ctx = conf->ssl_ctx; + sm->msg_ctx = conf->msg_ctx; sm->eap_sim_db_priv = conf->eap_sim_db_priv; sm->backend_auth = conf->backend_auth; sm->eap_server = conf->eap_server; diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c index ca956eb..a1976e8 100644 --- a/src/eapol_auth/eapol_auth_sm.c +++ b/src/eapol_auth/eapol_auth_sm.c @@ -816,6 +816,7 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, os_memset(&eap_conf, 0, sizeof(eap_conf)); eap_conf.eap_server = eapol->conf.eap_server; eap_conf.ssl_ctx = eapol->conf.ssl_ctx; + eap_conf.msg_ctx = eapol->conf.msg_ctx; eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv; eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key; eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id; @@ -1030,6 +1031,7 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst, dst->individual_wep_key_len = src->individual_wep_key_len; dst->eap_server = src->eap_server; dst->ssl_ctx = src->ssl_ctx; + dst->msg_ctx = src->msg_ctx; dst->eap_sim_db_priv = src->eap_sim_db_priv; os_free(dst->eap_req_id_text); if (src->eap_req_id_text) { diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h index fed7c05..ef943ad 100644 --- a/src/eapol_auth/eapol_auth_sm.h +++ b/src/eapol_auth/eapol_auth_sm.h @@ -26,6 +26,7 @@ struct eapol_auth_config { int individual_wep_key_len; int eap_server; void *ssl_ctx; + void *msg_ctx; void *eap_sim_db_priv; char *eap_req_id_text; /* a copy of this will be allocated */ size_t eap_req_id_text_len; diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c index b1790c4..cd1bf9d 100644 --- a/src/radius/radius_server.c +++ b/src/radius/radius_server.c @@ -280,6 +280,11 @@ struct radius_server_data { * eap_req_id_text_len - Length of eap_req_id_text buffer in octets */ size_t eap_req_id_text_len; + + /* + * msg_ctx - Context data for wpa_msg() calls + */ + void *msg_ctx; }; @@ -486,6 +491,7 @@ radius_server_get_new_session(struct radius_server_data *data, os_memset(&eap_conf, 0, sizeof(eap_conf)); eap_conf.ssl_ctx = data->ssl_ctx; + eap_conf.msg_ctx = data->msg_ctx; eap_conf.eap_sim_db_priv = data->eap_sim_db_priv; eap_conf.backend_auth = TRUE; eap_conf.eap_server = 1; @@ -1229,6 +1235,7 @@ radius_server_init(struct radius_server_conf *conf) data->conf_ctx = conf->conf_ctx; data->eap_sim_db_priv = conf->eap_sim_db_priv; data->ssl_ctx = conf->ssl_ctx; + data->msg_ctx = conf->msg_ctx; data->ipv6 = conf->ipv6; if (conf->pac_opaque_encr_key) { data->pac_opaque_encr_key = os_malloc(16); diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h index 43942de..67420e4 100644 --- a/src/radius/radius_server.h +++ b/src/radius/radius_server.h @@ -189,6 +189,11 @@ struct radius_server_conf { * eap_req_id_text_len - Length of eap_req_id_text buffer in octets */ size_t eap_req_id_text_len; + + /* + * msg_ctx - Context data for wpa_msg() calls + */ + void *msg_ctx; };