From a10269d912d02b74c3e64c9914b803460a35cf68 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 2 Nov 2010 10:47:05 +0100 Subject: [PATCH] Add login handling to WISPr command line client --- tools/wispr.c | 452 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 240 insertions(+), 212 deletions(-) diff --git a/tools/wispr.c b/tools/wispr.c index 99c0b69..fcf99d2 100644 --- a/tools/wispr.c +++ b/tools/wispr.c @@ -46,34 +46,121 @@ static void sig_term(int sig) g_main_loop_quit(main_loop); } -enum wispr_pages { - WISPR_PAGE_NONE, - WISPR_PAGE_REDIRECT, - WISPR_PAGE_PROXY, - WISPR_PAGE_AUTHENTICATION_REPLY, - WISPR_PAGE_AUTHENTICATION_POLL_REPLY, - WISPR_PAGE_LOGOFF_REPLY, - WISPR_PAGE_ABORT_LOGIN_REPLY, +static const char *message_type_to_string(int message_type) +{ + switch (message_type) { + case 100: + return "Initial redirect message"; + case 110: + return "Proxy notification"; + case 120: + return "Authentication notification"; + case 130: + return "Logoff notification"; + case 140: + return "Response to Authentication Poll"; + case 150: + return "Response to Abort Login"; + } + + return NULL; +} + +static const char *response_code_to_string(int response_code) +{ + switch (response_code) { + case 0: + return "No error"; + case 50: + return "Login succeeded"; + case 100: + return "Login failed"; + case 102: + return "RADIUS server error/timeout"; + case 105: + return "RADIUS server not enabled"; + case 150: + return "Logoff succeeded"; + case 151: + return "Login aborted"; + case 200: + return "Proxy detection/repeat operation"; + case 201: + return "Authentication pending"; + case 255: + return "Access gateway internal error"; + } + + return NULL; +} + +struct wispr_msg { + gboolean has_error; + const char *current_element; + int message_type; + int response_code; + char *login_url; + char *logoff_url; }; -enum wispr_elements { - WISPR_NONE, - WISPR_ACCESS_PROCEDURE, - WISPR_ACCESS_LOCATION, - WISPR_LOCATION_NAME, - WISPR_LOGIN_URL, - WISPR_ABORT_LOGIN_URL, - WISPR_MESSAGE_TYPE, - WISPR_RESPONSE_CODE, - WISPR_NEXT_URL, - WISPR_DELAY, - WISPR_REPLY_MESSAGE, - WISPR_LOGIN_RESULTS_URL, - WISPR_LOGOFF_URL, +static inline void wispr_msg_init(struct wispr_msg *msg) +{ + msg->has_error = FALSE; + msg->current_element = NULL; + + msg->message_type = -1; + msg->response_code = -1; + + g_free(msg->login_url); + msg->login_url = NULL; + + g_free(msg->logoff_url); + msg->logoff_url = NULL; +} + +struct wispr_session { + GWeb *web; + GWebParser *parser; + guint request; + struct wispr_msg msg; + const char *username; + const char *password; + const char *originurl; + char *formdata; }; -static enum wispr_pages current_page = WISPR_NONE; -static enum wispr_elements current_element = WISPR_NONE; +static struct { + const char *str; + enum { + WISPR_ELEMENT_NONE, + WISPR_ELEMENT_ACCESS_PROCEDURE, + WISPR_ELEMENT_ACCESS_LOCATION, + WISPR_ELEMENT_LOCATION_NAME, + WISPR_ELEMENT_LOGIN_URL, + WISPR_ELEMENT_ABORT_LOGIN_URL, + WISPR_ELEMENT_MESSAGE_TYPE, + WISPR_ELEMENT_RESPONSE_CODE, + WISPR_ELEMENT_NEXT_URL, + WISPR_ELEMENT_DELAY, + WISPR_ELEMENT_REPLY_MESSAGE, + WISPR_ELEMENT_LOGIN_RESULTS_URL, + WISPR_ELEMENT_LOGOFF_URL, + } element; +} wispr_element_map[] = { + { "AccessProcedure", WISPR_ELEMENT_ACCESS_PROCEDURE }, + { "AccessLocation", WISPR_ELEMENT_ACCESS_LOCATION }, + { "LocationName", WISPR_ELEMENT_LOCATION_NAME }, + { "LoginURL", WISPR_ELEMENT_LOGIN_URL }, + { "AbortLoginURL", WISPR_ELEMENT_ABORT_LOGIN_URL }, + { "MessageType", WISPR_ELEMENT_MESSAGE_TYPE }, + { "ResponseCode", WISPR_ELEMENT_RESPONSE_CODE }, + { "NextURL", WISPR_ELEMENT_NEXT_URL }, + { "Delay", WISPR_ELEMENT_DELAY }, + { "ReplyMessage", WISPR_ELEMENT_REPLY_MESSAGE }, + { "LoginResultsURL", WISPR_ELEMENT_LOGIN_RESULTS_URL }, + { "LogoffURL", WISPR_ELEMENT_LOGOFF_URL }, + { NULL, WISPR_ELEMENT_NONE }, +}; static void start_element_handler(GMarkupParseContext *context, const gchar *element_name, @@ -81,188 +168,69 @@ static void start_element_handler(GMarkupParseContext *context, const gchar **attribute_values, gpointer user_data, GError **error) { - if (g_str_equal(element_name, "Redirect") == TRUE) - current_page = WISPR_PAGE_REDIRECT; - else if (g_str_equal(element_name, "Proxy") == TRUE) - current_page = WISPR_PAGE_PROXY; - else if (g_str_equal(element_name, "AuthenticationReply") == TRUE) - current_page = WISPR_PAGE_AUTHENTICATION_REPLY; - else if (g_str_equal(element_name, "AuthenticationPollReply") == TRUE) - current_page = WISPR_PAGE_AUTHENTICATION_POLL_REPLY; - else if (g_str_equal(element_name, "LogoffReply") == TRUE) - current_page = WISPR_PAGE_LOGOFF_REPLY; - else if (g_str_equal(element_name, "AbortLoginReply") == TRUE) - current_page = WISPR_PAGE_ABORT_LOGIN_REPLY; - else - current_page = WISPR_PAGE_NONE; - - if (g_str_equal(element_name, "AccessProcedure") == TRUE) - current_element = WISPR_ACCESS_PROCEDURE; - else if (g_str_equal(element_name, "AccessLocation") == TRUE) - current_element = WISPR_ACCESS_LOCATION; - else if (g_str_equal(element_name, "LocationName") == TRUE) - current_element = WISPR_LOCATION_NAME; - else if (g_str_equal(element_name, "LoginURL") == TRUE) - current_element = WISPR_LOGIN_URL; - else if (g_str_equal(element_name, "AbortLoginURL") == TRUE) - current_element = WISPR_ABORT_LOGIN_URL; - else if (g_str_equal(element_name, "MessageType") == TRUE) - current_element = WISPR_MESSAGE_TYPE; - else if (g_str_equal(element_name, "ResponseCode") == TRUE) - current_element = WISPR_RESPONSE_CODE; - else if (g_str_equal(element_name, "NextURL") == TRUE) - current_element = WISPR_NEXT_URL; - else if (g_str_equal(element_name, "Delay") == TRUE) - current_element = WISPR_DELAY; - else if (g_str_equal(element_name, "ReplyMessage") == TRUE) - current_element = WISPR_REPLY_MESSAGE; - else if (g_str_equal(element_name, "LoginResultsURL") == TRUE) - current_element = WISPR_LOGIN_RESULTS_URL; - else if (g_str_equal(element_name, "LogoffURL") == TRUE) - current_element = WISPR_LOGOFF_URL; - else - current_element = WISPR_NONE; + struct wispr_msg *msg = user_data; + + msg->current_element = element_name; } static void end_element_handler(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error) { - current_page = WISPR_PAGE_NONE; + struct wispr_msg *msg = user_data; - current_element = WISPR_NONE; + msg->current_element = NULL; } static void text_handler(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error) { - int value; - - switch (current_page) { - case WISPR_PAGE_NONE: - break; - case WISPR_PAGE_REDIRECT: - printf("[ Redirect ]\n"); - break; - case WISPR_PAGE_PROXY: - printf("[ Proxy ]\n"); - break; - case WISPR_PAGE_AUTHENTICATION_REPLY: - printf("[ Authentication reply ]\n"); - break; - case WISPR_PAGE_AUTHENTICATION_POLL_REPLY: - printf("[ Authentication poll reply ]\n"); - break; - case WISPR_PAGE_LOGOFF_REPLY: - printf("[ Logoff reply ]\n"); - break; - case WISPR_PAGE_ABORT_LOGIN_REPLY: - printf("[ Abort login reply ]\n"); - break; - } - - switch (current_element) { - case WISPR_NONE: - break; - case WISPR_ACCESS_PROCEDURE: - printf("Access procedure: %s\n", text); - break; - case WISPR_ACCESS_LOCATION: - printf("Access location: %s\n", text); - break; - case WISPR_LOCATION_NAME: - printf("Location name: %s\n", text); - break; - case WISPR_LOGIN_URL: - printf("Login URL: %s\n", text); - break; - case WISPR_ABORT_LOGIN_URL: - printf("Abort login URL: %s\n", text); - break; - case WISPR_MESSAGE_TYPE: - value = atoi(text); - printf("Message type: %d\n", value); - switch (value) { - case 100: - printf(" Initial redirect message\n"); - break; - case 110: - printf(" Proxy notification\n"); - break; - case 120: - printf(" Authentication notification\n"); - break; - case 130: - printf(" Logoff notification\n"); - break; - case 140: - printf(" Response to Authentication Poll\n"); - break; - case 150: - printf(" Response to Abort Login\n"); - break; - } - break; - case WISPR_RESPONSE_CODE: - value = atoi(text); - printf("Response code: %d\n", value); - switch (value) { - case 0: - printf(" No error\n"); - break; - case 50: - printf(" Login succeeded (Access ACCEPT)\n"); - break; - case 100: - printf(" Login failed (Access REJECT)\n"); + struct wispr_msg *msg = user_data; + int i; + + if (msg->current_element == NULL) + return; + + for (i = 0; wispr_element_map[i].str; i++) { + if (g_str_equal(wispr_element_map[i].str, + msg->current_element) == FALSE) + continue; + + switch (wispr_element_map[i].element) { + case WISPR_ELEMENT_NONE: + case WISPR_ELEMENT_ACCESS_PROCEDURE: + case WISPR_ELEMENT_ACCESS_LOCATION: + case WISPR_ELEMENT_LOCATION_NAME: break; - case 102: - printf(" RADIUS server error/timeout\n"); + case WISPR_ELEMENT_LOGIN_URL: + g_free(msg->login_url); + msg->login_url = g_strdup(text); break; - case 105: - printf(" RADIUS server not enabled\n"); + case WISPR_ELEMENT_ABORT_LOGIN_URL: break; - case 150: - printf(" Logoff succeeded\n"); + case WISPR_ELEMENT_MESSAGE_TYPE: + msg->message_type = atoi(text); break; - case 151: - printf(" Login aborted\n"); + case WISPR_ELEMENT_RESPONSE_CODE: + msg->response_code = atoi(text); break; - case 200: - printf(" Proxy detection/repeat operation\n"); - break; - case 201: - printf(" Authentication pending\n"); - break; - case 255: - printf(" Access gateway internal error\n"); + case WISPR_ELEMENT_NEXT_URL: + case WISPR_ELEMENT_DELAY: + case WISPR_ELEMENT_REPLY_MESSAGE: + case WISPR_ELEMENT_LOGIN_RESULTS_URL: + case WISPR_ELEMENT_LOGOFF_URL: break; } - break; - case WISPR_NEXT_URL: - printf("Next URL: %s\n", text); - break; - case WISPR_DELAY: - value = atoi(text); - printf("Delay: %d seconds\n", value); - break; - case WISPR_REPLY_MESSAGE: - printf("Reply message: %s\n", text); - break; - case WISPR_LOGIN_RESULTS_URL: - printf("Login results URL: %s\n", text); - break; - case WISPR_LOGOFF_URL: - printf("Logoff URL: %s\n", text); - break; } } static void error_handler(GMarkupParseContext *context, GError *error, gpointer user_data) { - printf("%s\n", error->message); + struct wispr_msg *msg = user_data; + + msg->has_error = TRUE; } static const GMarkupParser wispr_parser = { @@ -275,52 +243,95 @@ static const GMarkupParser wispr_parser = { static void parser_callback(const char *str, gpointer user_data) { + struct wispr_session *wispr = user_data; GMarkupParseContext *context; gboolean result; //printf("%s\n", str); context = g_markup_parse_context_new(&wispr_parser, - G_MARKUP_TREAT_CDATA_AS_TEXT, NULL, NULL); + G_MARKUP_TREAT_CDATA_AS_TEXT, &wispr->msg, NULL); result = g_markup_parse_context_parse(context, str, strlen(str), NULL); - - result = g_markup_parse_context_end_parse(context, NULL); + if (result == TRUE) + result = g_markup_parse_context_end_parse(context, NULL); g_markup_parse_context_free(context); } -static guint request_id; -static GWebParser *request_parser; +static gboolean wispr_input(const guint8 **data, gsize *length, + gpointer user_data) +{ + struct wispr_session *wispr = user_data; + + g_free(wispr->formdata); + wispr->formdata = g_strdup_printf("button=Login&UserName=%s&" + "Password=%s&FNAME=0&OriginatingServer=%s", + wispr->username, wispr->password, wispr->originurl); -static gboolean web_result(GWebResult *result, gpointer user_data) + *data = (guint8 *) wispr->formdata; + *length = strlen(wispr->formdata); + + return FALSE; +} + +static gboolean wispr_result(GWebResult *result, gpointer user_data) { + struct wispr_session *wispr = user_data; const guint8 *chunk; gsize length; guint16 status; gdouble elapsed; - status = g_web_result_get_status(result); - if (status == 200) - goto done; - g_web_result_get_chunk(result, &chunk, &length); if (length > 0) { //printf("%s\n", (char *) chunk); - g_web_parser_feed_data(request_parser, chunk, length); + g_web_parser_feed_data(wispr->parser, chunk, length); return TRUE; } - g_web_parser_end_data(request_parser); + g_web_parser_end_data(wispr->parser); + + status = g_web_result_get_status(result); -done: g_print("status: %03u\n", status); elapsed = g_timer_elapsed(timer, NULL); g_print("elapse: %f seconds\n", elapsed); + if (wispr->msg.message_type < 0) + goto done; + + printf("Message type: %s (%d)\n", + message_type_to_string(wispr->msg.message_type), + wispr->msg.message_type); + printf("Response code: %s (%d)\n", + response_code_to_string(wispr->msg.response_code), + wispr->msg.response_code); + if (wispr->msg.login_url != NULL) + printf("Login URL: %s\n", wispr->msg.login_url); + if (wispr->msg.logoff_url != NULL) + printf("Logoff URL: %s\n", wispr->msg.logoff_url); + printf("\n"); + + if (status == 302 && wispr->msg.message_type == 100) { + wispr->request = g_web_request_post(wispr->web, + wispr->msg.login_url, + "application/x-www-form-urlencoded", + wispr_input, wispr_result, wispr); + + wispr_msg_init(&wispr->msg); + + return FALSE; + } else if (status == 200 && wispr->msg.message_type == 120) { + int code = wispr->msg.response_code; + printf("Login process: %s\n", + code == 50 ? "SUCCESS" : "FAILURE"); + } + +done: g_main_loop_quit(main_loop); return FALSE; @@ -328,6 +339,8 @@ done: static gboolean option_debug = FALSE; static gchar *option_nameserver = NULL; +static gchar *option_username = NULL; +static gchar *option_password = NULL; static gchar *option_url = NULL; static GOptionEntry options[] = { @@ -335,7 +348,11 @@ static GOptionEntry options[] = { "Enable debug output" }, { "nameserver", 'n', 0, G_OPTION_ARG_STRING, &option_nameserver, "Specify nameserver", "ADDRESS" }, - { "url", 'u', 0, G_OPTION_ARG_STRING, &option_url, + { "username", 'u', 0, G_OPTION_ARG_STRING, &option_username, + "Specify username", "USERNAME" }, + { "password", 'p', 0, G_OPTION_ARG_STRING, &option_password, + "Specify password", "PASSWORD" }, + { "url", 'U', 0, G_OPTION_ARG_STRING, &option_url, "Specify arbitrary request", "URL" }, { NULL }, }; @@ -345,7 +362,7 @@ int main(int argc, char *argv[]) GOptionContext *context; GError *error = NULL; struct sigaction sa; - GWeb *web; + struct wispr_session wispr; int index = 0; context = g_option_context_new(NULL); @@ -362,43 +379,46 @@ int main(int argc, char *argv[]) g_option_context_free(context); - web = g_web_new(index); - if (web == NULL) { + memset(&wispr, 0, sizeof(wispr)); + wispr_msg_init(&wispr.msg); + + wispr.web = g_web_new(index); + if (wispr.web == NULL) { fprintf(stderr, "Failed to create web service\n"); return 1; } if (option_debug == TRUE) - g_web_set_debug(web, web_debug, "WEB"); + g_web_set_debug(wispr.web, web_debug, "WEB"); main_loop = g_main_loop_new(NULL, FALSE); if (option_nameserver != NULL) { - g_web_add_nameserver(web, option_nameserver); + g_web_add_nameserver(wispr.web, option_nameserver); g_free(option_nameserver); } - g_web_set_accept(web, NULL); - g_web_set_user_agent(web, "SmartClient/%s wispr", VERSION); - g_web_set_close_connection(web, TRUE); + g_web_set_accept(wispr.web, NULL); + g_web_set_user_agent(wispr.web, "SmartClient/%s wispr", VERSION); + g_web_set_close_connection(wispr.web, TRUE); if (option_url == NULL) option_url = g_strdup(DEFAULT_URL); + wispr.username = option_username; + wispr.password = option_password; + wispr.originurl = option_url; + timer = g_timer_new(); - request_parser = g_web_parser_new("", - parser_callback, NULL); - - g_web_parser_ref(request_parser); - g_web_parser_unref(request_parser); + parser_callback, &wispr); - request_id = g_web_request_get(web, option_url, web_result, NULL); - - g_free(option_url); + wispr.request = g_web_request_get(wispr.web, option_url, + wispr_result, &wispr); - if (request_id == 0) { + if (wispr.request == 0) { fprintf(stderr, "Failed to start request\n"); return 1; } @@ -412,9 +432,17 @@ int main(int argc, char *argv[]) g_timer_destroy(timer); - g_web_unref(web); + if (wispr.request > 0) + g_web_cancel_request(wispr.web, wispr.request); + + g_web_parser_unref(wispr.parser); + g_web_unref(wispr.web); g_main_loop_unref(main_loop); + g_free(option_username); + g_free(option_password); + g_free(option_url); + return 0; } -- 2.7.4