Mercurial > pidgin
view libpurple/protocols/msn/nexus.c @ 20671:4dd60add6a7c
Further cleanup of the msn prpl including preventing the authorization request callback from crashing if triggered after the account is disconnected. Also removal of some extraneous debuggery, there is more that needs to be removed.
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Fri, 28 Sep 2007 01:57:55 +0000 |
parents | 2c8c6d77f12c |
children | 48ee7ec3426d |
line wrap: on
line source
/** * @file nexus.c MSN Nexus functions * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include "msn.h" #include "soap.h" #include "nexus.h" #include "notification.h" #undef NEXUS_LOGIN_TWN /*Local Function Prototype*/ static gboolean nexus_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc); /************************************************************************** * Main **************************************************************************/ MsnNexus * msn_nexus_new(MsnSession *session) { MsnNexus *nexus; nexus = g_new0(MsnNexus, 1); nexus->session = session; /*we must use SSL connection to do Windows Live ID authentication*/ nexus->soapconn = msn_soap_new(session,nexus,1); nexus->challenge_data = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); return nexus; } void msn_nexus_destroy(MsnNexus *nexus) { if (nexus->challenge_data != NULL) g_hash_table_destroy(nexus->challenge_data); msn_soap_destroy(nexus->soapconn); g_free(nexus); } #if 0 /* khc */ /************************************************************************** * Util **************************************************************************/ static gssize msn_ssl_read(MsnNexus *nexus) { gssize len; char temp_buf[4096]; if ((len = purple_ssl_read(nexus->gsc, temp_buf, sizeof(temp_buf))) > 0) { nexus->read_buf = g_realloc(nexus->read_buf, nexus->read_len + len + 1); strncpy(nexus->read_buf + nexus->read_len, temp_buf, len); nexus->read_len += len; nexus->read_buf[nexus->read_len] = '\0'; } return len; } static void nexus_write_cb(gpointer data, gint source, PurpleInputCondition cond) { MsnNexus *nexus = data; int len, total_len; total_len = strlen(nexus->write_buf); len = purple_ssl_write(nexus->gsc, nexus->write_buf + nexus->written_len, total_len - nexus->written_len); if (len < 0 && errno == EAGAIN) return; else if (len <= 0) { purple_input_remove(nexus->input_handler); nexus->input_handler = 0; /* TODO: notify of the error */ return; } nexus->written_len += len; if (nexus->written_len < total_len) return; purple_input_remove(nexus->input_handler); nexus->input_handler = 0; g_free(nexus->write_buf); nexus->write_buf = NULL; nexus->written_len = 0; nexus->written_cb(nexus, source, 0); } #endif /************************************************************************** * Login **************************************************************************/ static void nexus_login_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) { MsnSession *session; session = soapconn->session; g_return_if_fail(session != NULL); soapconn->gsc = NULL; msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication:Unable to connect")); /* the above line will result in nexus being destroyed, so we don't want * to destroy it here, or we'd crash */ } /*process the SOAP reply, get the Authentication Info*/ static gboolean nexus_login_read_cb(MsnSoapConn *soapconn) { MsnNexus *nexus; MsnSession *session; char *base, *c; char *msn_twn_t,*msn_twn_p; char *login_params; char **elems, **cur, **tokens; char * cert_str; nexus = soapconn->parent; g_return_val_if_fail(nexus != NULL, TRUE); session = nexus->session; g_return_val_if_fail(session != NULL, FALSE); /*reply OK, we should process the SOAP body*/ purple_debug_info("MSN Nexus","TWN Server Windows Live ID Reply OK!\n"); //TODO: we should parse it using XML #ifdef NEXUS_LOGIN_TWN base = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_START_TOKEN); base += strlen(TWN_START_TOKEN); c = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_END_TOKEN); #else base = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_LIVE_START_TOKEN); base += strlen(TWN_LIVE_START_TOKEN); c = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_LIVE_END_TOKEN); #endif login_params = g_strndup(base, c - base); // purple_debug_info("msn", "TWN Cert: {%s}\n", login_params); /* Parse the challenge data. */ elems = g_strsplit(login_params, "&", 0); for (cur = elems; *cur != NULL; cur++){ tokens = g_strsplit(*cur, "=", 2); g_hash_table_insert(nexus->challenge_data, tokens[0], tokens[1]); /* Don't free each of the tokens, only the array. */ g_free(tokens); } g_strfreev(elems); msn_twn_t = (char *)g_hash_table_lookup(nexus->challenge_data, "t"); msn_twn_p = (char *)g_hash_table_lookup(nexus->challenge_data, "p"); /*setup the t and p parameter for session*/ if (session->passport_info.t != NULL){ g_free(session->passport_info.t); } session->passport_info.t = g_strdup(msn_twn_t); if (session->passport_info.p != NULL) g_free(session->passport_info.p); session->passport_info.p = g_strdup(msn_twn_p); cert_str = g_strdup_printf("t=%s&p=%s",msn_twn_t,msn_twn_p); msn_got_login_params(session, cert_str); purple_debug_info("MSN Nexus","Close nexus connection!\n"); g_free(cert_str); g_free(login_params); msn_nexus_destroy(nexus); session->nexus = NULL; return FALSE; } static void nexus_login_written_cb(MsnSoapConn *soapconn) { soapconn->read_cb = nexus_login_read_cb; // msn_soap_read_cb(data,source,cond); } /*when connect, do the SOAP Style windows Live ID authentication */ gboolean nexus_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) { MsnNexus * nexus; MsnSession *session; char *ru,*lc,*id,*tw,*ct,*kpp,*kv,*ver,*rn,*tpf; char *fs0,*fs; char *username, *password; char *request_str, *head, *tail; #ifdef NEXUS_LOGIN_TWN char *challenge_str; #else char *rst1_str,*rst2_str,*rst3_str; #endif purple_debug_info("MSN Nexus","Starting Windows Live ID authentication\n"); g_return_val_if_fail(soapconn != NULL, FALSE); nexus = soapconn->parent; g_return_val_if_fail(nexus != NULL, TRUE); session = soapconn->session; g_return_val_if_fail(session != NULL, FALSE); msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING); msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE); /*prepare the Windows Live ID authentication token*/ username = g_strdup(purple_account_get_username(session->account)); password = g_strdup(purple_connection_get_password(session->account->gc)); lc = (char *)g_hash_table_lookup(nexus->challenge_data, "lc"); id = (char *)g_hash_table_lookup(nexus->challenge_data, "id"); tw = (char *)g_hash_table_lookup(nexus->challenge_data, "tw"); fs0= (char *)g_hash_table_lookup(nexus->challenge_data, "fs"); ru = (char *)g_hash_table_lookup(nexus->challenge_data, "ru"); ct = (char *)g_hash_table_lookup(nexus->challenge_data, "ct"); kpp= (char *)g_hash_table_lookup(nexus->challenge_data, "kpp"); kv = (char *)g_hash_table_lookup(nexus->challenge_data, "kv"); ver= (char *)g_hash_table_lookup(nexus->challenge_data, "ver"); rn = (char *)g_hash_table_lookup(nexus->challenge_data, "rn"); tpf= (char *)g_hash_table_lookup(nexus->challenge_data, "tpf"); /* * add some fail-safe code to avoid windows Purple Crash bug #1540454 * If any of these string is NULL, will return Authentication Fail! * for when windows g_strdup_printf() implementation get NULL point,It crashed! */ if(!(lc && id && tw && ru && ct && kpp && kv && ver && tpf)){ purple_debug_error("MSN Nexus","WLM Authenticate Key Error!\n"); msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication Failed")); g_free(username); g_free(password); purple_ssl_close(gsc); msn_nexus_destroy(nexus); session->nexus = NULL; return FALSE; } /* * in old MSN NS server's "USR TWN S" return,didn't include fs string * so we use a default "1" for fs. */ if(fs0){ fs = g_strdup(fs0); }else{ fs = g_strdup("1"); } #ifdef NEXUS_LOGIN_TWN challenge_str = g_strdup_printf( "lc=%s&id=%s&tw=%s&fs=%s&ru=%s&ct=%s&kpp=%s&kv=%s&ver=%s&rn=%s&tpf=%s\r\n", lc,id,tw,fs,ru,ct,kpp,kv,ver,rn,tpf ); /*build the SOAP windows Live ID XML body */ tail = g_strdup_printf(TWN_ENVELOP_TEMPLATE,username,password,challenge_str ); g_free(challenge_str); #else rst1_str = g_strdup_printf( "id=%s&tw=%s&fs=%s&kpp=%s&kv=%s&ver=%s&rn=%s", id,tw,fs,kpp,kv,ver,rn ); rst2_str = g_strdup_printf( "fs=%s&id=%s&kv=%s&rn=%s&tw=%s&ver=%s", fs,id,kv,rn,tw,ver ); rst3_str = g_strdup_printf("id=%s",id); tail = g_strdup_printf(TWN_LIVE_ENVELOP_TEMPLATE,username,password,rst1_str,rst2_str,rst3_str); g_free(rst1_str); g_free(rst2_str); g_free(rst3_str); #endif g_free(fs); soapconn->login_path = g_strdup(TWN_POST_URL); head = g_strdup_printf( "POST %s HTTP/1.1\r\n" "Accept: text/*\r\n" "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n" "Host: %s\r\n" "Content-Length: %" G_GSIZE_FORMAT "\r\n" "Connection: Keep-Alive\r\n" "Cache-Control: no-cache\r\n\r\n", soapconn->login_path, soapconn->login_host, strlen(tail)); request_str = g_strdup_printf("%s%s", head,tail); #ifdef MSN_SOAP_DEBUG purple_debug_misc("MSN Nexus", "TWN Sending:\n%s\n", request_str); #endif g_free(head); g_free(tail); g_free(username); g_free(password); /*prepare to send the SOAP request*/ msn_soap_write(soapconn, request_str, nexus_login_written_cb); return TRUE; } #if 0 /* khc */ static void nexus_connect_written_cb(gpointer data, gint source, PurpleInputCondition cond) { MsnNexus *nexus = data; int len; char *da_login; char *base, *c; if (nexus->input_handler == 0) /* TODO: Use purple_ssl_input_add()? */ nexus->input_handler = purple_input_add(nexus->gsc->fd, PURPLE_INPUT_READ, nexus_connect_written_cb, nexus); /* Get the PassportURLs line. */ len = msn_ssl_read(nexus); if (len < 0 && errno == EAGAIN) return; else if (len < 0) { purple_input_remove(nexus->input_handler); nexus->input_handler = 0; g_free(nexus->read_buf); nexus->read_buf = NULL; nexus->read_len = 0; /* TODO: error handling */ return; } if (g_strstr_len(nexus->read_buf, nexus->read_len, "\r\n\r\n") == NULL) return; purple_input_remove(nexus->input_handler); nexus->input_handler = 0; base = strstr(nexus->read_buf, "PassportURLs"); if (base == NULL) { g_free(nexus->read_buf); nexus->read_buf = NULL; nexus->read_len = 0; return; } if ((da_login = strstr(base, "DALogin=")) != NULL) { /* skip over "DALogin=" */ da_login += 8; if ((c = strchr(da_login, ',')) != NULL) *c = '\0'; if ((c = strchr(da_login, '/')) != NULL) { nexus->login_path = g_strdup(c); *c = '\0'; } nexus->login_host = g_strdup(da_login); } g_free(nexus->read_buf); nexus->read_buf = NULL; nexus->read_len = 0; purple_ssl_close(nexus->gsc); /* Now begin the connection to the login server. */ nexus->gsc = purple_ssl_connect(nexus->session->account, nexus->login_host, PURPLE_SSL_DEFAULT_PORT, login_connect_cb, login_error_cb, nexus); } #endif /************************************************************************** * Connect **************************************************************************/ #if 0 /* khc */ static void nexus_connect_cb(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond) { MsnNexus *nexus; MsnSession *session; nexus = data; g_return_if_fail(nexus != NULL); session = nexus->session; g_return_if_fail(session != NULL); msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH); nexus->write_buf = g_strdup("GET /rdr/pprdr.asp\r\n\r\n"); nexus->written_len = 0; nexus->read_len = 0; nexus->written_cb = nexus_connect_written_cb; nexus->input_handler = purple_input_add(gsc->fd, PURPLE_INPUT_WRITE, nexus_write_cb, nexus); nexus_write_cb(nexus, gsc->fd, PURPLE_INPUT_WRITE); } #endif void msn_nexus_connect(MsnNexus *nexus) { /* Authenticate via Windows Live ID. */ msn_soap_init(nexus->soapconn, MSN_TWN_SERVER, 1, nexus_login_connect_cb, nexus_login_error_cb); msn_soap_connect(nexus->soapconn); }