# HG changeset patch # User Elliott Sales de Andrade # Date 1198629252 0 # Node ID 25899ec348a4972d77b3e4d21c089a29dedd8042 # Parent 75be80ddeca52ab21f044fe8c235afd62eadd24e Patch 2 from Qulogic, this one adds SSO authentication committer: Ka-Hing Cheung diff -r 75be80ddeca5 -r 25899ec348a4 libpurple/protocols/msn/nexus.c --- a/libpurple/protocols/msn/nexus.c Wed Dec 26 00:33:39 2007 +0000 +++ b/libpurple/protocols/msn/nexus.c Wed Dec 26 00:34:12 2007 +0000 @@ -26,7 +26,24 @@ #include "nexus.h" #include "notification.h" -#undef NEXUS_LOGIN_TWN + +/************************************************************************** + * Valid Ticket Tokens + **************************************************************************/ + +#define SSO_VALID_TICKET_DOMAIN 0 +#define SSO_VALID_TICKET_POLICY 1 +static char *ticket_domains[][2] = { + /* http://msnpiki.msnfanatic.com/index.php/MSNP15:SSO */ + /* {"Domain", "Policy Ref URI"}, Purpose */ + {"messengerclear.live.com", NULL}, /* Authentication for messenger. */ + {"messenger.msn.com", "?id=507"}, /* Messenger website authentication. */ + {"contacts.msn.com", "MBI"}, /* Authentication for the Contact server. */ + {"messengersecure.live.com", "MBI_SSL"}, /* Unknown */ + {"spaces.live.com", "MBI"}, /* Authentication for the Windows Live Spaces */ + {"livecontacts.live.com", "MBI"}, /* Live Contacts API, a simplified version of the Contacts SOAP service */ + {"storage.live.com", "MBI"}, /* Storage REST API */ +}; /************************************************************************** * Main @@ -36,12 +53,17 @@ msn_nexus_new(MsnSession *session) { MsnNexus *nexus; + int i; nexus = g_new0(MsnNexus, 1); nexus->session = session; - nexus->challenge_data = g_hash_table_new_full(g_str_hash, - g_str_equal, g_free, g_free); + nexus->token_len = sizeof(ticket_domains) / sizeof(char *[2]); + nexus->tokens = g_malloc(sizeof(MsnTicketToken) * nexus->token_len); + + for (i = 0; i < nexus->token_len; i++) + nexus->tokens[i].token = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); return nexus; } @@ -49,47 +71,198 @@ void msn_nexus_destroy(MsnNexus *nexus) { - if (nexus->challenge_data != NULL) - g_hash_table_destroy(nexus->challenge_data); + int i; + for (i = 0; i < nexus->token_len; i++) { + g_hash_table_destroy(nexus->tokens[i].token); + g_free(nexus->tokens[i].secret); + } + + g_free(nexus->tokens); + g_free(nexus->policy); + g_free(nexus->nonce); + g_free(nexus); +} + +/************************************************************************** + * RPS/SSO Authentication + **************************************************************************/ + +static char * +sha1_hmac(const char *key, int key_len, const char *message, int msg_len) +{ + PurpleCipherContext *context; + char *result; + gboolean ret; + + context = purple_cipher_context_new_by_name("hmac", NULL); + purple_cipher_context_set_option(context, "hash", "sha1"); + purple_cipher_context_set_key_with_len(context, (guchar *)key, key_len); + + purple_cipher_context_append(context, (guchar *)message, msg_len); + result = g_malloc(20); + ret = purple_cipher_context_digest(context, 20, (guchar *)result, NULL); + + purple_cipher_context_destroy(context); + + return result; +} + +static char * +rps_create_key(const char *key, int key_len, const char *data, size_t data_len) +{ + char *hash1, *hash2, *hash3, *hash4; + char *result; + + hash1 = sha1_hmac(key, key_len, data, data_len); + hash1 = g_realloc(hash1, 20 + data_len); + memcpy(hash1 + 20, data, data_len); + hash2 = sha1_hmac(key, key_len, hash1, 20 + data_len); + + hash3 = sha1_hmac(key, key_len, hash1, 20); + + hash3 = g_realloc(hash3, 20 + data_len); + memcpy(hash3 + 20, data, data_len); + hash4 = sha1_hmac(key, key_len, hash3, 20 + data_len); + + result = g_malloc(24); + memcpy(result, hash2, 20); + memcpy(result + 20, hash4, 4); + + g_free(hash1); + g_free(hash2); + g_free(hash3); + g_free(hash4); + + return result; +} + +static char * +des3_cbc(const char *key, const char *iv, const char *data, int len) +{ + PurpleCipherContext *des3; + char *out; + size_t outlen; - g_free(nexus); + des3 = purple_cipher_context_new_by_name("des3", NULL); + purple_cipher_context_set_key(des3, (guchar *)key); + purple_cipher_context_set_batch_mode(des3, PURPLE_CIPHER_BATCH_MODE_CBC); + purple_cipher_context_set_iv(des3, (guchar *)iv, 8); + + out = g_malloc(len); + purple_cipher_context_encrypt(des3, (guchar *)data, len, (guchar *)out, &outlen); + + purple_cipher_context_destroy(des3); + + return out; +} + +#define CRYPT_MODE_CBC 1 +#define CIPHER_TRIPLE_DES 0x6603 +#define HASH_SHA1 0x8004 +static char * +msn_rps_encrypt(MsnNexus *nexus) +{ + MsnUsrKey *usr_key; + const char *magic1 = "WS-SecureConversationSESSION KEY HASH"; + const char *magic2 = "WS-SecureConversationSESSION KEY ENCRYPTION"; + size_t len; + char *hash; + char *key1, *key2, *key3; + gsize key1_len; + char *nonce_fixed; + char *cipher; + char *response; + + usr_key = g_malloc(sizeof(MsnUsrKey)); + usr_key->size = GUINT32_TO_LE(28); + usr_key->crypt_mode = GUINT32_TO_LE(CRYPT_MODE_CBC); + usr_key->cipher_type = GUINT32_TO_LE(CIPHER_TRIPLE_DES); + usr_key->hash_type = GUINT32_TO_LE(HASH_SHA1); + usr_key->iv_len = GUINT32_TO_LE(8); + usr_key->hash_len = GUINT32_TO_LE(20); + usr_key->cipher_len = GUINT32_TO_LE(72); + + key1 = (char *)purple_base64_decode((const char *)nexus->tokens[MSN_AUTH_MESSENGER].secret, &key1_len); + len = strlen(magic1); + key2 = rps_create_key(key1, key1_len, magic1, len); + len = strlen(magic2); + key3 = rps_create_key(key1, key1_len, magic2, len); + + usr_key->iv[0] = 0x46; //rand() % 256; + usr_key->iv[1] = 0xC4; + usr_key->iv[2] = 0x14; + usr_key->iv[3] = 0x9F; + usr_key->iv[4] = 0xFF; + usr_key->iv[5] = 0xFC; + usr_key->iv[6] = 0x91; + usr_key->iv[7] = 0x61; + + len = strlen(nexus->nonce); + hash = sha1_hmac(key2, 24, nexus->nonce, len); + + /* We need to pad this to 72 bytes, apparently */ + nonce_fixed = g_malloc(len + 8); + memcpy(nonce_fixed, nexus->nonce, len); + memset(nonce_fixed + len, 0x08, 8); + cipher = des3_cbc(key3, usr_key->iv, nonce_fixed, len + 8); + g_free(nonce_fixed); + + memcpy(usr_key->hash, hash, 20); + memcpy(usr_key->cipher, cipher, 72); + + g_free(key1); + g_free(key2); + g_free(key3); + g_free(hash); + g_free(cipher); + + response = purple_base64_encode((guchar *)usr_key, sizeof(MsnUsrKey)); + + g_free(usr_key); + + return response; } /************************************************************************** * Login **************************************************************************/ -static void -nexus_got_response_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) +static gboolean +nexus_parse_response(MsnNexus *nexus, xmlnode *xml) { - MsnNexus *nexus = data; - MsnSession *session = nexus->session; xmlnode *node; + gboolean result = FALSE; - if (resp == NULL) { - msn_session_set_error(session, MSN_ERROR_SERVCONN, _("Windows Live ID authentication:Unable to connect")); - return; - } + node = msn_soap_xml_get(xml, "Body/RequestSecurityTokenResponseCollection/RequestSecurityTokenResponse"); - node = msn_soap_xml_get(resp->xml, "Body/" - "RequestSecurityTokenResponseCollection/RequestSecurityTokenResponse"); + if (node) + node = node->next; /* The first one is not useful */ + else + return FALSE; for (; node; node = node->next) { - xmlnode *token = msn_soap_xml_get(node, - "RequestedSecurityToken/BinarySecurityToken"); + xmlnode *token = msn_soap_xml_get(node, "RequestedSecurityToken/BinarySecurityToken"); + xmlnode *secret = msn_soap_xml_get(node, "RequestedProofToken/BinarySecret"); + xmlnode *expires = msn_soap_xml_get(node, "LifeTime/Expires"); if (token) { char *token_str = xmlnode_get_data(token); + const char *id_str = xmlnode_get_attrib(token, "Id"); char **elems, **cur, **tokens; - char *msn_twn_t, *msn_twn_p, *cert_str; + int id; if (token_str == NULL) continue; + if (id_str == NULL) continue; + + id = atol(id_str + 7) - 1; /* 'Compact#' or 'PPToken#' */ + if (id >= nexus->token_len) + continue; /* Where did this come from? */ elems = g_strsplit(token_str, "&", 0); for (cur = elems; *cur != NULL; cur++){ tokens = g_strsplit(*cur, "=", 2); - g_hash_table_insert(nexus->challenge_data, tokens[0], tokens[1]); + g_hash_table_insert(nexus->tokens[id].token, tokens[0], tokens[1]); /* Don't free each of the tokens, only the array. */ g_free(tokens); } @@ -97,33 +270,55 @@ g_free(token_str); g_strfreev(elems); - msn_twn_t = g_hash_table_lookup(nexus->challenge_data, "t"); - msn_twn_p = 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 (secret) + nexus->tokens[id].secret = g_strdup(xmlnode_get_data(secret)); + else + nexus->tokens[id].secret = NULL; - 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); + /* Yay for MS using ISO-8601 */ + nexus->tokens[id].expiry = purple_str_to_time(xmlnode_get_data(expires), + FALSE, NULL, NULL, NULL); - purple_debug_info("MSN Nexus","Close nexus connection!\n"); - g_free(cert_str); - msn_nexus_destroy(nexus); - session->nexus = NULL; - - return; + purple_debug_info("msnp15", "Updated ticket for domain '%s'\n", + ticket_domains[id][SSO_VALID_TICKET_DOMAIN]); + result = TRUE; } } - /* we must have failed! */ - msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication: cannot find authenticate token in server response")); + return result; +} + +static void +nexus_got_response_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) +{ + MsnNexus *nexus = data; + MsnSession *session = nexus->session; + char *msn_twn_t, *msn_twn_p, *ticket; + char *response; + + if (resp == NULL) { + msn_session_set_error(session, MSN_ERROR_SERVCONN, _("Windows Live ID authentication:Unable to connect")); + return; + } + + if (!nexus_parse_response(nexus, resp->xml)) { + msn_session_set_error(session, MSN_ERROR_SERVCONN, _("Windows Live ID authentication:Invalid response")); + return; + } + + /*setup the t and p parameter for session*/ + msn_twn_t = g_hash_table_lookup(nexus->tokens[MSN_AUTH_MESSENGER].token, "t"); + msn_twn_p = g_hash_table_lookup(nexus->tokens[MSN_AUTH_MESSENGER].token, "p"); + g_free(session->passport_info.t); + session->passport_info.t = g_strdup(msn_twn_t); + g_free(session->passport_info.p); + session->passport_info.p = g_strdup(msn_twn_p); + + ticket = g_strdup_printf("t=%s&p=%s", msn_twn_t, msn_twn_p); + response = msn_rps_encrypt(nexus); + msn_got_login_params(session, ticket, response); + g_free(ticket); + g_free(response); } /*when connect, do the SOAP Style windows Live ID authentication */ @@ -131,92 +326,113 @@ msn_nexus_connect(MsnNexus *nexus) { MsnSession *session = nexus->session; - char *ru,*lc,*id,*tw,*ct,*kpp,*kv,*ver,*rn,*tpf; - char *fs0,*fs; char *username, *password; - char *tail; -#ifdef NEXUS_LOGIN_TWN - char *challenge_str; -#else - char *rst1_str,*rst2_str,*rst3_str; -#endif + GString *domains; + char *request; + int i; MsnSoapMessage *soap; - purple_debug_info("MSN Nexus","Starting Windows Live ID authentication\n"); 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_strndup(purple_connection_get_password(session->account->gc), 16); - 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"); + purple_debug_info("msnp15", "Logging on %s, with policy '%s', nonce '%s'\n", + username, nexus->policy, nexus->nonce); - /* - * 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); - msn_nexus_destroy(nexus); - session->nexus = NULL; - return; + domains = g_string_new(NULL); + for (i = 0; i < nexus->token_len; i++) { + g_string_append_printf(domains, MSN_SSO_RST_TEMPLATE, + i+1, + ticket_domains[i][SSO_VALID_TICKET_DOMAIN], + ticket_domains[i][SSO_VALID_TICKET_POLICY] != NULL ? + ticket_domains[i][SSO_VALID_TICKET_POLICY] : + nexus->policy); } - /* - * 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 - ); + request = g_strdup_printf(MSN_SSO_TEMPLATE, username, password, domains->str); + g_free(username); + g_free(password); + g_string_free(domains, TRUE); - /*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); - g_free(password); + soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1)); + g_free(request); + msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL, + nexus_got_response_cb, nexus); +} - soap = msn_soap_message_new(NULL, xmlnode_from_str(tail, -1)); - g_free(tail); - msn_soap_message_send(nexus->session, soap, MSN_TWN_SERVER, TWN_POST_URL, - nexus_got_response_cb, nexus); +static void +nexus_got_update_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) +{ + MsnNexus *nexus = data; + + nexus_parse_response(nexus, resp->xml); } +static void +msn_nexus_update_token(MsnNexus *nexus, int id) +{ + MsnSession *session = nexus->session; + char *username, *password; + char *domain; + char *request; + + MsnSoapMessage *soap; + + username = g_strdup(purple_account_get_username(session->account)); + password = g_strndup(purple_connection_get_password(session->account->gc), 16); + + purple_debug_info("msnp15", "Updating ticket for user '%s' on domain '%s'\n", + username, ticket_domains[id][SSO_VALID_TICKET_DOMAIN]); + + /* TODO: This really assumes if we send RSTn, the server responds with + Compactn, even if there is no RST(n-1). This needs checking. + */ + domain = g_strdup_printf(MSN_SSO_RST_TEMPLATE, + id, + ticket_domains[id][SSO_VALID_TICKET_DOMAIN], + ticket_domains[id][SSO_VALID_TICKET_POLICY] != NULL ? + ticket_domains[id][SSO_VALID_TICKET_POLICY] : + nexus->policy); + + request = g_strdup_printf(MSN_SSO_TEMPLATE, username, password, domain); + g_free(username); + g_free(password); + g_free(domain); + + soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1)); + g_free(request); + msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL, + nexus_got_update_cb, nexus); +} + +GHashTable * +msn_nexus_get_token(MsnNexus *nexus, MsnAuthDomains id) +{ + g_return_val_if_fail(nexus != NULL, NULL); + g_return_val_if_fail(id < nexus->token_len, NULL); + + if (time(NULL) > nexus->tokens[id].expiry) + msn_nexus_update_token(nexus, id); + + return g_hash_table_ref(nexus->tokens[id].token); +} + +char * +msn_nexus_get_token_str(MsnNexus *session, MsnAuthDomains id) +{ +#if 0 + GHashTable *token = msn_nexus_get_token(nexus, id); + GString *token_str; + + g_return_val_if_fail(token != NULL, NULL); + + token_str = g_string_new(NULL); + g_hash_table_foreach(token, GHFunc func, token_str); + + g_hash_table_unref (token); +#endif + return NULL; +} + diff -r 75be80ddeca5 -r 25899ec348a4 libpurple/protocols/msn/nexus.h --- a/libpurple/protocols/msn/nexus.h Wed Dec 26 00:33:39 2007 +0000 +++ b/libpurple/protocols/msn/nexus.h Wed Dec 26 00:34:12 2007 +0000 @@ -26,125 +26,115 @@ #include "soap.h" -/*#define MSN_TWN_SERVER "loginnet.passport.com"*/ -#define MSN_TWN_SERVER "login.live.com" - -#define TWN_START_TOKEN "" -#define TWN_END_TOKEN "" +/* Index into ticket_tokens in nexus.c Keep updated! */ +typedef enum +{ + MSN_AUTH_MESSENGER = 0, + MSN_AUTH_MESSENGER_WEB = 1, + MSN_AUTH_CONTACTS = 2, + MSN_AUTH_LIVE_UNKNOWN = 3, + MSN_AUTH_SPACES = 4, + MSN_AUTH_LIVE_CONTACTS = 5, + MSN_AUTH_STORAGE = 6 +} MsnAuthDomains; -#define TWN_POST_URL "/RST.srf" -#define TWN_ENVELOP_TEMPLATE ""\ - ""\ - "
"\ - ""\ - "{3:B}"\ - "4"\ - "1"\ - ""\ - "AQAAAAIAAABsYwQAAAAzMDg0"\ - ""\ - ""\ - ""\ - "%s"\ - "%s"\ - ""\ - ""\ - "
"\ - ""\ - ""\ - ""\ - "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ - ""\ - ""\ - "http://Passport.NET/tb"\ - ""\ - ""\ - ""\ - ""\ - "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ - ""\ - ""\ - "messenger.msn.com"\ - ""\ - ""\ - ""\ - ""\ - ""\ - ""\ - ""\ - "
" +#define MSN_SSO_SERVER "login.live.com" +#define SSO_POST_URL "/RST.srf" + +#define MSN_SSO_RST_TEMPLATE \ +""\ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ + ""\ + ""\ + "%s"\ + ""\ + ""\ + ""\ +"" -#define TWN_LIVE_START_TOKEN "" -#define TWN_LIVE_END_TOKEN "" -#define TWN_LIVE_ENVELOP_TEMPLATE ""\ -""\ - "
"\ - ""\ - "{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}"\ - "4"\ - "1"\ - ""\ - "AQAAAAIAAABsYwQAAAAyMDUy"\ - ""\ - ""\ - ""\ - "%s"\ - "%s"\ - ""\ - ""\ - "
"\ - ""\ - ""\ - ""\ - "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ - ""\ - ""\ - "http://Passport.NET/tb"\ - ""\ - ""\ - ""\ - ""\ - "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ - ""\ - ""\ - "messenger.msn.com"\ - ""\ - ""\ - ""\ - ""\ - ""\ - "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ - ""\ - ""\ - "contacts.msn.com"\ - ""\ - ""\ - ""\ - " "\ - ""\ - "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ - ""\ - ""\ - "voice.messenger.msn.com"\ - ""\ - " "\ - ""\ - ""\ - ""\ - ""\ +#define MSN_SSO_TEMPLATE ""\ +""\ + "
"\ + ""\ + "{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}"\ + "4"\ + "1"\ + ""\ + "AQAAAAIAAABsYwQAAAAxMDMz"\ + ""\ + ""\ + ""\ + "%s"\ + "%s"\ + ""\ + ""\ + "
"\ + ""\ + ""\ + ""\ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ + ""\ + ""\ + "http://Passport.NET/tb"\ + ""\ + ""\ + ""\ + "%s" /* Other RSTn tokens */\ + ""\ + ""\ "
" +typedef struct _MsnUsrKey MsnUsrKey; +struct _MsnUsrKey +{ + int size; // 28. Does not count data + int crypt_mode; // CRYPT_MODE_CBC (1) + int cipher_type; // TripleDES (0x6603) + int hash_type; // SHA1 (0x8004) + int iv_len; // 8 + int hash_len; // 20 + int cipher_len; // 72 + // Data + char iv[8]; + char hash[20]; + char cipher[72]; +}; + +typedef struct _MsnTicketToken MsnTicketToken; +struct _MsnTicketToken { + GHashTable *token; + char *secret; + time_t expiry; +}; + typedef struct _MsnNexus MsnNexus; struct _MsnNexus { MsnSession *session; - char * challenge_data_str; - GHashTable *challenge_data; + char *policy; + char *nonce; + + MsnTicketToken *tokens; + int token_len; }; void msn_nexus_connect(MsnNexus *nexus); MsnNexus *msn_nexus_new(MsnSession *session); void msn_nexus_destroy(MsnNexus *nexus); +GHashTable *msn_nexus_get_token(MsnNexus *session, MsnAuthDomains id); +char *msn_nexus_get_token_str(MsnNexus *session, MsnAuthDomains id); #endif /* _MSN_NEXUS_H_ */ + diff -r 75be80ddeca5 -r 25899ec348a4 libpurple/protocols/msn/notification.c --- a/libpurple/protocols/msn/notification.c Wed Dec 26 00:33:39 2007 +0000 +++ b/libpurple/protocols/msn/notification.c Wed Dec 26 00:34:12 2007 +0000 @@ -204,7 +204,7 @@ **************************************************************************/ void -msn_got_login_params(MsnSession *session, const char *login_params) +msn_got_login_params(MsnSession *session, const char *ticket, const char *response) { MsnCmdProc *cmdproc; @@ -212,7 +212,7 @@ msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_END); - msn_cmdproc_send(cmdproc, "USR", "TWN S %s", login_params); + msn_cmdproc_send(cmdproc, "USR", "SSO S %s %s", ticket, response); } static void @@ -221,8 +221,8 @@ PurpleAccount *account; account = cmdproc->session->account; - msn_cmdproc_send(cmdproc, "USR", "TWN I %s", - purple_account_get_username(account)); + + msn_cmdproc_send(cmdproc, "USR", "SSO I %s", purple_account_get_username(account)); } static void @@ -248,32 +248,14 @@ // msn_cmdproc_send(cmdproc, "SYN", "%s", "0"); //TODO we should use SOAP contact to fetch contact list } - else if (!g_ascii_strcasecmp(cmd->params[1], "TWN")) + else if (!g_ascii_strcasecmp(cmd->params[1], "SSO")) { - /* Passport authentication */ - char **elems, **cur, **tokens; + /* RPS authentication */ session->nexus = msn_nexus_new(session); - /* Parse the challenge data. */ - session->nexus->challenge_data_str = g_strdup(cmd->params[3]); - elems = g_strsplit(cmd->params[3], ",", 0); - - for (cur = elems; *cur != NULL; cur++) - { - tokens = g_strsplit(*cur, "=", 2); - if(tokens[0] && tokens[1]) - { - purple_debug_info("MSNP14","challenge %p,key:%s,value:%s\n", - session->nexus->challenge_data,tokens[0],tokens[1]); - g_hash_table_insert(session->nexus->challenge_data, tokens[0], tokens[1]); - /* Don't free each of the tokens, only the array. */ - g_free(tokens); - } else - g_strfreev(tokens); - } - - g_strfreev(elems); + session->nexus->policy = g_strdup(cmd->params[3]); + session->nexus->nonce = g_strdup(cmd->params[4]); msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_START);