예제 #1
0
JabberData *
jabber_data_create_from_xml(xmlnode *tag)
{
    JabberData *data = g_new0(JabberData, 1);
    gsize size;
    gpointer raw_data = NULL;

    if (data == NULL) {
        purple_debug_error("jabber", "Could not allocate data object\n");
        g_free(data);
        return NULL;
    }

    /* check if this is a "data" tag */
    if (strcmp(tag->name, "data") != 0) {
        purple_debug_error("jabber", "Invalid data element");
        g_free(data);
        return NULL;
    }

    data->cid = g_strdup(xmlnode_get_attrib(tag, "cid"));
    data->type = g_strdup(xmlnode_get_attrib(tag, "type"));

    raw_data = xmlnode_get_data(tag);
    data->data = purple_base64_decode(raw_data, &size);
    data->size = size;

    g_free(raw_data);

    return data;
}
예제 #2
0
static void
jabber_vcard_parse_avatar(JabberStream *js, const char *from,
                          JabberIqType type, const char *id,
                          xmlnode *packet, gpointer blah)
{
	JabberBuddy *jb = NULL;
	xmlnode *vcard, *photo, *binval, *fn, *nick;
	char *text;

	if(!from)
		return;

	jb = jabber_buddy_find(js, from, TRUE);

	js->pending_avatar_requests = g_slist_remove(js->pending_avatar_requests, jb);

	if((vcard = xmlnode_get_child(packet, "vCard")) ||
			(vcard = xmlnode_get_child_with_namespace(packet, "query", "vcard-temp"))) {
		/* The logic here regarding the nickname and full name is copied from
		 * buddy.c:jabber_vcard_parse. */
		gchar *nickname = NULL;
		if ((fn = xmlnode_get_child(vcard, "FN")))
			nickname = xmlnode_get_data(fn);

		if ((nick = xmlnode_get_child(vcard, "NICKNAME"))) {
			char *tmp = xmlnode_get_data(nick);
			char *bare_jid = jabber_get_bare_jid(from);
			if (tmp && strstr(bare_jid, tmp) == NULL) {
				g_free(nickname);
				nickname = tmp;
			} else if (tmp)
				g_free(tmp);

			g_free(bare_jid);
		}

		if (nickname) {
			serv_got_alias(js->gc, from, nickname);
			g_free(nickname);
		}

		if ((photo = xmlnode_get_child(vcard, "PHOTO")) &&
				(binval = xmlnode_get_child(photo, "BINVAL")) &&
				(text = xmlnode_get_data(binval))) {
			guchar *data;
			gsize size;

			data = purple_base64_decode(text, &size);
			if (data) {
				gchar *hash = jabber_calculate_data_hash(data, size, "sha1");
				purple_buddy_icons_set_for_user(js->gc->account, from, data,
				                                size, hash);
				g_free(hash);
			}

			g_free(text);
		}
	}
}
예제 #3
0
파일: test_util.c 프로젝트: bf4/pidgin-mac
END_TEST

START_TEST(test_util_base64_decode)
{
	gsize sz;
	guchar *out = purple_base64_decode("b3d0LXl0cm9mAA==", &sz);
	fail_unless(sz == 10, NULL);
	fail_unless(strcmp("owt-ytrof", out) == 0, NULL);
	g_free(out);
}
예제 #4
0
static JabberSaslState
jabber_cyrus_handle_challenge(JabberStream *js, xmlnode *packet,
                              xmlnode **reply, char **error)
{
	char *enc_in = xmlnode_get_data(packet);
	unsigned char *dec_in;
	char *enc_out;
	const char *c_out;
	unsigned int clen;
	gsize declen;

	dec_in = purple_base64_decode(enc_in, &declen);

	js->sasl_state = sasl_client_step(js->sasl, (char*)dec_in, declen,
					  NULL, &c_out, &clen);
	g_free(enc_in);
	g_free(dec_in);
	if (js->sasl_state != SASL_CONTINUE && js->sasl_state != SASL_OK) {
		gchar *tmp = g_strdup_printf(_("SASL error: %s"),
				sasl_errdetail(js->sasl));
		purple_debug_error("jabber", "Error is %d : %s\n",
				js->sasl_state, sasl_errdetail(js->sasl));
		*error = tmp;
		return JABBER_SASL_STATE_FAIL;
	} else {
		xmlnode *response = xmlnode_new("response");
		xmlnode_set_namespace(response, NS_XMPP_SASL);
		if (clen > 0) {
			/* Cyrus SASL 2.1.22 appears to contain code to add the charset
			 * to the response for DIGEST-MD5 but there is no possibility
			 * it will be executed.
			 *
			 * My reading of the digestmd5 plugin indicates the username and
			 * realm are always encoded in UTF-8 (they seem to be the values
			 * we pass in), so we need to ensure charset=utf-8 is set.
			 */
			if (!purple_strequal(js->current_mech, "DIGEST-MD5") ||
					strstr(c_out, ",charset="))
				/* If we're not using DIGEST-MD5 or Cyrus SASL is fixed */
				enc_out = purple_base64_encode((unsigned char*)c_out, clen);
			else {
				char *tmp = g_strdup_printf("%s,charset=utf-8", c_out);
				enc_out = purple_base64_encode((unsigned char*)tmp, clen + 14);
				g_free(tmp);
			}

			xmlnode_insert_data(response, enc_out, -1);
			g_free(enc_out);
		}

		*reply = response;
		return JABBER_SASL_STATE_CONTINUE;
	}
}
예제 #5
0
void
purple_pn_xfer_got_invite(struct pn_peer_call *call,
                          const char *branch,
                          const char *context)
{
    PurpleAccount *account;
    PurpleXfer *xfer;
    char *bin;
    gsize bin_len;
    guint32 file_size;
    char *file_name;
    gunichar2 *uni_name;

    account = msn_session_get_user_data (pn_peer_link_get_session (call->link));

    call->cb = xfer_completed_cb;
    call->end_cb = xfer_end_cb;
    call->progress_cb = xfer_progress_cb;
    call->branch = g_strdup(branch);

    call->pending = TRUE;

    xfer = purple_xfer_new(account, PURPLE_XFER_RECEIVE,
                           pn_peer_link_get_passport (call->link));
    if (xfer)
    {
        bin = (char *)purple_base64_decode(context, &bin_len);
        file_size = GUINT32_FROM_LE(*(gsize *)(bin + 8));

        uni_name = (gunichar2 *)(bin + 20);
        while(*uni_name != 0 && ((char *)uni_name - (bin + 20)) < MAX_FILE_NAME_LEN) {
            *uni_name = GUINT16_FROM_LE(*uni_name);
            uni_name++;
        }

        file_name = g_utf16_to_utf8((const gunichar2 *)(bin + 20), -1,
                                    NULL, NULL, NULL);

        g_free(bin);

        purple_xfer_set_filename(xfer, file_name);
        purple_xfer_set_size(xfer, file_size);
        purple_xfer_set_init_fnc(xfer, xfer_init);
        purple_xfer_set_request_denied_fnc(xfer, xfer_cancel);
        purple_xfer_set_cancel_recv_fnc(xfer, xfer_cancel);

        call->xfer = xfer;
        purple_xfer_ref(call->xfer);

        xfer->data = call;

        purple_xfer_request(xfer);
    }
}
예제 #6
0
static JabberSaslState
scram_handle_success(JabberStream *js, PurpleXmlNode *packet, char **error)
{
	JabberScramData *data = js->auth_mech_data;
	char *enc_in, *dec_in;
	char *dec_out = NULL;
	gsize len;

	enc_in = purple_xmlnode_get_data(packet);
	if (data->step != 3 && (!enc_in || *enc_in == '\0')) {
		*error = g_strdup(_("Invalid challenge from server"));
		g_free(enc_in);
		return JABBER_SASL_STATE_FAIL;
	}

	if (data->step == 3) {
		/*
		 * If the server took the slow approach (sending the verifier
		 * as a challenge/response pair), we get here.
		 */
		g_free(enc_in);
		return JABBER_SASL_STATE_OK;
	}

	if (data->step != 2) {
		*error = g_strdup(_("Unexpected response from server"));
		g_free(enc_in);
		return JABBER_SASL_STATE_FAIL;
	}

	dec_in = (gchar *)purple_base64_decode(enc_in, &len);
	g_free(enc_in);
	if (!dec_in || len != strlen(dec_in)) {
		/* Danger afoot; SCRAM shouldn't contain NUL bytes */
		g_free(dec_in);
		*error = g_strdup(_("Malicious challenge from server"));
		return JABBER_SASL_STATE_FAIL;
	}

	purple_debug_misc("jabber", "decoded success: %s\n", dec_in);

	if (!jabber_scram_feed_parser(data, dec_in, &dec_out) || dec_out != NULL) {
		g_free(dec_in);
		g_free(dec_out);
		*error = g_strdup(_("Invalid challenge from server"));
		return JABBER_SASL_STATE_FAIL;
	}

	g_free(dec_in);
	/* Hooray */
	return JABBER_SASL_STATE_OK;
}
예제 #7
0
파일: cipher.c 프로젝트: Distrotech/pidgin
/*------------------------------------------------------------------------
 * Decrypt a message using transport-layer encryption.
 *
 *  @param session	The MXit session object
 *	@param message	The encrypted message data (is base64-encoded).
 *  @return			The decrypted message.  Must be g_free'd when no longer needed.
 */
char* mxit_decrypt_message( struct MXitSession* session, char* message )
{
	guchar*			raw_message;
	gsize			raw_len;
	char			exkey[512];
	GString*		decoded		= NULL;
	unsigned int	i;

	/* remove optional header: <mxitencrypted ver="5.2"/> */
	if ( strncmp( message, ENCRYPT_HEADER, strlen( ENCRYPT_HEADER ) ) == 0 )
		message += strlen( ENCRYPT_HEADER );

	/* base64 decode the message */
	raw_message = purple_base64_decode( message, &raw_len );

	/* AES-encrypted data is always blocks of 16 bytes */
	if ( ( raw_len == 0 ) || ( raw_len % 16 != 0 ) )
		return NULL;

	/* build the AES key */
	ExpandKey( (unsigned char*) transport_layer_key( session ), (unsigned char*) exkey );

	/* AES decrypt each block */
	decoded = g_string_sized_new( raw_len );
	for ( i = 0; i < raw_len; i += 16 ) {
		char	block[16];

		Decrypt( (unsigned char*) raw_message + i, (unsigned char*) exkey, (unsigned char*) block );
		g_string_append_len( decoded, block, 16 );
	}
	g_free( raw_message );

	/* check that the decrypted message starts with header: <mxit/> */
	if ( strncmp( decoded->str, SECRET_HEADER, strlen( SECRET_HEADER ) != 0 ) ) {
		g_string_free( decoded, TRUE );
		return NULL;			/* message could not be decrypted */
	}

	/* remove ISO10126 padding */
	padding_remove( decoded );

	/* remove encryption header */
	g_string_erase( decoded, 0, strlen( SECRET_HEADER ) );

	return g_string_free( decoded, FALSE );
}
예제 #8
0
static JabberSaslState
jabber_cyrus_handle_success(JabberStream *js, xmlnode *packet,
                            char **error)
{
	const void *x;

	/* The SASL docs say that if the client hasn't returned OK yet, we
	 * should try one more round against it
	 */
	if (js->sasl_state != SASL_OK) {
		char *enc_in = xmlnode_get_data(packet);
		unsigned char *dec_in = NULL;
		const char *c_out;
		unsigned int clen;
		gsize declen = 0;

		if(enc_in != NULL)
			dec_in = purple_base64_decode(enc_in, &declen);

		js->sasl_state = sasl_client_step(js->sasl, (char*)dec_in, declen, NULL, &c_out, &clen);

		g_free(enc_in);
		g_free(dec_in);

		if (js->sasl_state != SASL_OK) {
			/* This happens when the server sends back jibberish
			 * in the "additional data with success" case.
			 * Seen with Wildfire 3.0.1.
			 */
			*error = g_strdup(_("Invalid response from server"));
			return JABBER_SASL_STATE_FAIL;
		}
	}

	/* If we've negotiated a security layer, we need to enable it */
	if (js->sasl) {
		sasl_getprop(js->sasl, SASL_SSF, &x);
		if (*(int *)x > 0) {
			sasl_getprop(js->sasl, SASL_MAXOUTBUF, &x);
			js->sasl_maxbuf = *(int *)x;
		}
	}

	return JABBER_SASL_STATE_OK;
}
예제 #9
0
파일: data.c 프로젝트: psunkari/spicebird
JabberData *
jabber_data_create_from_xml(xmlnode *tag)
{
    JabberData *data;
    gchar *raw_data = NULL;
    const gchar *cid, *type;

    /* check if this is a "data" tag */
    if (strcmp(tag->name, "data") != 0) {
        purple_debug_error("jabber", "Invalid data element\n");
        return NULL;
    }

    cid = xmlnode_get_attrib(tag, "cid");
    type = xmlnode_get_attrib(tag, "type");

    if (!cid || !type) {
        purple_debug_error("jabber", "cid or type missing\n");
        return NULL;
    }

    raw_data = xmlnode_get_data(tag);

    if (raw_data == NULL || *raw_data == '\0') {
        purple_debug_error("jabber", "data element was empty");
        g_free(raw_data);
        return NULL;
    }

    data = g_new0(JabberData, 1);
    data->data = purple_base64_decode(raw_data, &data->size);
    g_free(raw_data);

    if (data->data == NULL) {
        purple_debug_error("jabber", "Malformed base64 data\n");
        g_free(data);
        return NULL;
    }

    data->cid = g_strdup(cid);
    data->type = g_strdup(type);

    return data;
}
예제 #10
0
void
msn_switchboard_show_ink(MsnSwitchBoard *swboard, const char *passport,
                         const char *data)
{
	PurpleConnection *gc;
	guchar *image_data;
	size_t image_len;
	int imgid;
	char *image_msg;

	if (!purple_str_has_prefix(data, "base64:"))
	{
		purple_debug_error("msn", "Ignoring Ink not in Base64 format.\n");
		return;
	}

	gc = purple_account_get_connection(swboard->session->account);

	data += sizeof("base64:") - 1;
	image_data = purple_base64_decode(data, &image_len);
	if (!image_data || !image_len) 
	{
		purple_debug_error("msn", "Unable to decode Ink from Base64 format.\n");
		return;
	}

	imgid = purple_imgstore_add_with_id(image_data, image_len, NULL);
	image_msg = g_strdup_printf("<IMG ID='%d'/>", imgid);

	if (swboard->current_users > 1 ||
		((swboard->conv != NULL) &&
		 purple_conversation_get_type(swboard->conv) == PURPLE_CONV_TYPE_CHAT))
		serv_got_chat_in(gc, swboard->chat_id, passport, 0, image_msg,
						 time(NULL));
	else
		serv_got_im(gc, passport, image_msg, 0, time(NULL));

	purple_imgstore_unref_by_id(imgid);
	g_free(image_msg);
}
예제 #11
0
파일: clientlogin.c 프로젝트: jrcjc/chimein
static void start_oscar_session_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message)
{
    OscarData *od;
    PurpleConnection *gc;
    char *host, *cookie;
    char *tls_certname = NULL;
    unsigned short port;
    guint8 *cookiedata;
    gsize cookiedata_len;

    od = user_data;
    gc = od->gc;

    od->url_data = NULL;

    if (error_message != NULL || len == 0) {
        gchar *tmp;
        /* Note to translators: The first %s is a URL, the second is an
           error message. */
        tmp = g_strdup_printf(_("Error requesting %s: %s"),
                              URL_START_OSCAR_SESSION, error_message);
        purple_connection_error_reason(gc,
                                       PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
        g_free(tmp);
        return;
    }

    if (!parse_start_oscar_session_response(gc, url_text, len, &host, &port, &cookie, &tls_certname))
        return;

    cookiedata = purple_base64_decode(cookie, &cookiedata_len);
    oscar_connect_to_bos(gc, od, host, port, cookiedata, cookiedata_len, tls_certname);
    g_free(cookiedata);

    g_free(host);
    g_free(cookie);
    g_free(tls_certname);
}
예제 #12
0
static void
pb_set_base64_icon_for_buddy(const gchar *base64_icon, PurpleBuddy *buddy)
{
	PurpleBuddyIcon *icon;
	guchar *icon_data;
	gsize icon_len;
	gchar *checksum;
	const gchar *old_checksum;
	
	checksum = g_strdup_printf("%ud", g_str_hash(base64_icon));
	old_checksum = purple_buddy_icons_get_checksum_for_user(buddy);
	if (old_checksum && purple_strequal(old_checksum, checksum)) {
		g_free(checksum);
		return;
	}
	
	icon_data = purple_base64_decode(base64_icon, &icon_len);
	
	icon = purple_buddy_icon_new(purple_buddy_get_account(buddy), purple_buddy_get_name(buddy), icon_data, icon_len, checksum);
	
	g_free(icon_data);
	g_free(checksum);
}
예제 #13
0
파일: nexus.c 프로젝트: Lilitana/Pidgin
static gboolean
nexus_parse_collection(MsnNexus *nexus, int id, xmlnode *collection)
{
	xmlnode *node;
	gboolean result;

	node = xmlnode_get_child(collection, "RequestSecurityTokenResponse");

	if (!node)
		return FALSE;

	result = TRUE;
	for (; node && result; node = node->next) {
		xmlnode *endpoint = xmlnode_get_child(node, "AppliesTo/EndpointReference/Address");
		char *address = xmlnode_get_data(endpoint);

		if (g_str_equal(address, "http://Passport.NET/tb")) {
			/* This node contains the stuff for updating tokens. */
			char *data;
			xmlnode *cipher = xmlnode_get_child(node, "RequestedSecurityToken/EncryptedData/CipherData/CipherValue");
			xmlnode *secret = xmlnode_get_child(node, "RequestedProofToken/BinarySecret");

			g_free(nexus->cipher);
			nexus->cipher = xmlnode_get_data(cipher);
			data = xmlnode_get_data(secret);
			g_free(nexus->secret);
			nexus->secret = (char *)purple_base64_decode(data, NULL);
			g_free(data);

		} else {
			result = nexus_parse_token(nexus, id, node);
		}
		g_free(address);
	}

	return result;
}
예제 #14
0
gboolean
jabber_scram_feed_parser(JabberScramData *data, gchar *in, gchar **out)
{
	gboolean ret;

	g_return_val_if_fail(data != NULL, FALSE);

	g_string_append_c(data->auth_message, ',');
	g_string_append(data->auth_message, in);

	if (data->step == 1) {
		gchar *nonce, *proof;
		GString *salt;
		guint iterations;

		ret = parse_server_step1(data, in, &nonce, &salt, &iterations);
		if (!ret)
			return FALSE;

		g_string_append_c(data->auth_message, ',');

		/* "biws" is the base64 encoding of "n,,". I promise. */
		g_string_append_printf(data->auth_message, "c=%s,r=%s", "biws", nonce);
#ifdef CHANNEL_BINDING
#error fix this
#endif

		ret = jabber_scram_calc_proofs(data, salt, iterations);

		g_string_free(salt, TRUE);
		salt = NULL;
		if (!ret) {
			g_free(nonce);
			return FALSE;
		}

		proof = purple_base64_encode((guchar *)data->client_proof->str, data->client_proof->len);
		*out = g_strdup_printf("c=%s,r=%s,p=%s", "biws", nonce, proof);
		g_free(nonce);
		g_free(proof);
	} else if (data->step == 2) {
		gchar *server_sig, *enc_server_sig;
		gsize len;

		ret = parse_server_step2(data, in, &enc_server_sig);
		if (!ret)
			return FALSE;

		server_sig = (gchar *)purple_base64_decode(enc_server_sig, &len);
		g_free(enc_server_sig);

		if (server_sig == NULL || len != data->server_signature->len) {
			g_free(server_sig);
			return FALSE;
		}

		if (0 != memcmp(server_sig, data->server_signature->str, len)) {
			g_free(server_sig);
			return FALSE;
		}
		g_free(server_sig);

		*out = NULL;
	} else {
		purple_debug_error("jabber", "SCRAM: There is no step %d\n", data->step);
		return FALSE;
	}

	return TRUE;
}
예제 #15
0
파일: mxit.c 프로젝트: Draghtnod/pidgin
/*------------------------------------------------------------------------
 * Handle an URI clicked on the UI
 *
 * @param link	the link name which has been clicked
 */
static void* mxit_link_click( const char* link64 )
{
	PurpleAccount*		account;
	PurpleConnection*	gc;
	gchar**				parts		= NULL;
	gchar*				link		= NULL;
	gsize				len;
	gboolean			is_command	= FALSE;

	purple_debug_info( MXIT_PLUGIN_ID, "mxit_link_click (%s)\n", link64 );

	if ( g_ascii_strncasecmp( link64, MXIT_LINK_PREFIX, strlen( MXIT_LINK_PREFIX ) ) != 0 ) {
		/* this is not for us */
		goto skip;
	}

	/* decode the base64 payload */
	link = (gchar*) purple_base64_decode( link64 + strlen( MXIT_LINK_PREFIX ), &len );
	purple_debug_info( MXIT_PLUGIN_ID, "Clicked Link: '%s'\n", link );

	parts = g_strsplit( link, "|", 6 );

	/* check if this is a valid mxit link */
	if ( ( !parts ) || ( !parts[0] ) || ( !parts[1] ) || ( !parts[2] ) || ( !parts[3] ) || ( !parts[4] ) || ( !parts[5] ) ) {
		/* this is not for us */
		goto skip;
	}
	else if ( g_ascii_strcasecmp( parts[0], MXIT_LINK_KEY ) != 0 ) {
		/* this is not for us */
		goto skip;
	}

	/* find the account */
	account = purple_accounts_find( parts[1], parts[2] );
	if ( !account )
		goto skip;
	gc = purple_account_get_connection( account );
	if ( !gc )
		goto skip;

	/* determine if it's a command-response to send */
	is_command = ( atoi( parts[4] ) == 1 );

	/* send click message back to MXit */
	mxit_send_message( purple_connection_get_protocol_data( gc ), parts[3], parts[5], FALSE, is_command );

	g_free( link );
	link = NULL;
	g_strfreev( parts );
	parts = NULL;

	return (void*) link64;

skip:
	/* this is not an internal mxit link */

	if ( link )
		g_free( link );
	link = NULL;

	if ( parts )
		g_strfreev( parts );
	parts = NULL;

	if ( mxit_pidgin_uri_cb )
		return mxit_pidgin_uri_cb( link64 );
	else
		return (void*) link64;
}
예제 #16
0
static gboolean
parse_server_step1(JabberScramData *data, const char *challenge,
                   gchar **out_nonce, GString **out_salt, guint *out_iterations)
{
	char **tokens;
	char *token, *decoded, *tmp;
	gsize len;
	char *nonce = NULL;
	GString *salt = NULL;
	guint iterations;

	tokens = g_strsplit(challenge, ",", -1);
	if (tokens == NULL)
		return FALSE;

	token = tokens[0];
	if (token[0] != 'r' || token[1] != '=')
		goto err;

	/* Ensure that the first cnonce_len bytes of the nonce are the original
	 * cnonce we sent to the server.
	 */
	if (0 != strncmp(data->cnonce, token + 2, strlen(data->cnonce)))
		goto err;

	nonce = g_strdup(token + 2);

	/* The Salt, base64-encoded */
	token = tokens[1];
	if (token[0] != 's' || token[1] != '=')
		goto err;

	decoded = (gchar *)purple_base64_decode(token + 2, &len);
	if (!decoded || *decoded == '\0') {
		g_free(decoded);
		goto err;
	}
	salt = g_string_new_len(decoded, len);
	g_free(decoded);

	/* The iteration count */
	token = tokens[2];
	if (token[0] != 'i' || token[1] != '=' || token[2] == '\0')
		goto err;

	/* Validate the string */
	for (tmp = token + 2; *tmp; ++tmp)
		if (!g_ascii_isdigit(*tmp))
			goto err;

	iterations = strtoul(token + 2, NULL, 10);

	g_strfreev(tokens);
	*out_nonce = nonce;
	*out_salt = salt;
	*out_iterations = iterations;
	return TRUE;

err:
	g_free(nonce);
	if (salt)
		g_string_free(salt, TRUE);
	g_strfreev(tokens);
	return FALSE;
}
static JabberSaslState
digest_md5_handle_challenge(JabberStream *js, PurpleXmlNode *packet,
                            PurpleXmlNode **response, char **msg)
{
	PurpleXmlNode *reply = NULL;
	char *enc_in = purple_xmlnode_get_data(packet);
	char *dec_in;
	char *enc_out;
	GHashTable *parts;
	JabberSaslState state = JABBER_SASL_STATE_CONTINUE;

	if (!enc_in) {
		*msg = g_strdup(_("Invalid response from server"));
		return JABBER_SASL_STATE_FAIL;
	}

	dec_in = (char *)purple_base64_decode(enc_in, NULL);
	purple_debug_misc("jabber", "decoded challenge (%"
			G_GSIZE_FORMAT "): %s\n",
			strlen(dec_in),
			dec_in);

	parts = jabber_auth_digest_md5_parse(dec_in);

	if (g_hash_table_lookup(parts, "rspauth")) {
		char *rspauth = g_hash_table_lookup(parts, "rspauth");
		char *expected_rspauth = js->auth_mech_data;

		if (rspauth && purple_strequal(rspauth, expected_rspauth)) {
			reply = purple_xmlnode_new("response");
			purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);
		} else {
			*msg = g_strdup(_("Invalid challenge from server"));
			state = JABBER_SASL_STATE_FAIL;
		}
		g_free(js->auth_mech_data);
		js->auth_mech_data = NULL;
	} else {
		/* assemble a response, and send it */
		/* see RFC 2831 */
		char *realm;
		char *nonce;

		/* Make sure the auth string contains everything that should be there.
		   This isn't everything in RFC2831, but it is what we need. */

		nonce = g_hash_table_lookup(parts, "nonce");

		/* we're actually supposed to prompt the user for a realm if
		 * the server doesn't send one, but that really complicates things,
		 * so i'm not gonna worry about it until is poses a problem to
		 * someone, or I get really bored */
		realm = g_hash_table_lookup(parts, "realm");
		if(!realm)
			realm = js->user->domain;

		if (nonce == NULL || realm == NULL) {
			*msg = g_strdup(_("Invalid challenge from server"));
			state = JABBER_SASL_STATE_FAIL;
		} else {
			GString *response = g_string_new("");
			char *a2;
			char *auth_resp;
			char *cnonce;

			cnonce = g_strdup_printf("%x%u%x", g_random_int(), (int)time(NULL),
					g_random_int());

			a2 = g_strdup_printf("AUTHENTICATE:xmpp/%s", realm);
			auth_resp = generate_response_value(js->user,
					purple_connection_get_password(js->gc), nonce, cnonce, a2, realm);
			g_free(a2);

			a2 = g_strdup_printf(":xmpp/%s", realm);
			js->auth_mech_data = generate_response_value(js->user,
					purple_connection_get_password(js->gc), nonce, cnonce, a2, realm);
			g_free(a2);

			g_string_append_printf(response, "username=\"%s\"", js->user->node);
			g_string_append_printf(response, ",realm=\"%s\"", realm);
			g_string_append_printf(response, ",nonce=\"%s\"", nonce);
			g_string_append_printf(response, ",cnonce=\"%s\"", cnonce);
			g_string_append_printf(response, ",nc=00000001");
			g_string_append_printf(response, ",qop=auth");
			g_string_append_printf(response, ",digest-uri=\"xmpp/%s\"", realm);
			g_string_append_printf(response, ",response=%s", auth_resp);
			g_string_append_printf(response, ",charset=utf-8");

			g_free(auth_resp);
			g_free(cnonce);

			enc_out = purple_base64_encode((guchar *)response->str, response->len);

			purple_debug_misc("jabber", "decoded response (%"
					G_GSIZE_FORMAT "): %s\n",
					response->len, response->str);

			reply = purple_xmlnode_new("response");
			purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);
			purple_xmlnode_insert_data(reply, enc_out, -1);

			g_free(enc_out);

			g_string_free(response, TRUE);
		}
	}

	g_free(enc_in);
	g_free(dec_in);
	g_hash_table_destroy(parts);

	*response = reply;
	return state;
}
예제 #18
0
파일: nexus.c 프로젝트: Lilitana/Pidgin
static void
nexus_got_update_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data)
{
	MsnNexusUpdateData *ud = data;
	MsnNexus *nexus = ud->nexus;
	char iv[8] = {0,0,0,0,0,0,0,0};
	xmlnode *enckey;
	char *tmp;
	char *nonce;
	gsize len;
	char *key;
	GSList *updates;

#if 0
	char *decrypted_pp;
#endif
	char *decrypted_data;

	if (resp == NULL)
		return;

	purple_debug_info("msn", "Got Update Response for %s.\n", ticket_domains[ud->id][SSO_VALID_TICKET_DOMAIN]);

	enckey = xmlnode_get_child(resp->xml, "Header/Security/DerivedKeyToken");
	while (enckey) {
		if (g_str_equal(xmlnode_get_attrib(enckey, "Id"), "EncKey"))
			break;
		enckey = xmlnode_get_next_twin(enckey);
	}
	if (!enckey) {
		purple_debug_error("msn", "Invalid response in token update.\n");
		return;
	}

	tmp = xmlnode_get_data(xmlnode_get_child(enckey, "Nonce"));
	nonce = (char *)purple_base64_decode(tmp, &len);
	key = rps_create_key(nexus->secret, 24, nonce, len);
	g_free(tmp);
	g_free(nonce);

#if 0
	/* Don't know what this is for yet */
	tmp = xmlnode_get_data(xmlnode_get_child(resp->xml,
		"Header/EncryptedPP/EncryptedData/CipherData/CipherValue"));
	if (tmp) {
		decrypted_pp = des3_cbc(key, iv, tmp, len, TRUE);
		g_free(tmp);
		purple_debug_info("msn", "Got Response Header EncryptedPP: %s\n", decrypted_pp);
		g_free(decrypted_pp);
	}
#endif

	tmp = xmlnode_get_data(xmlnode_get_child(resp->xml,
		"Body/EncryptedData/CipherData/CipherValue"));
	if (tmp) {
		char *unescaped;
		xmlnode *rstresponse;

		unescaped = (char *)purple_base64_decode(tmp, &len);
		g_free(tmp);

		decrypted_data = des3_cbc(key, iv, unescaped, len, TRUE);
		g_free(unescaped);
		purple_debug_info("msn", "Got Response Body EncryptedData: %s\n", decrypted_data);

		rstresponse = xmlnode_from_str(decrypted_data, -1);
		if (g_str_equal(rstresponse->name, "RequestSecurityTokenResponse"))
			nexus_parse_token(nexus, ud->id, rstresponse);
		else
			nexus_parse_collection(nexus, ud->id, rstresponse);
		g_free(decrypted_data);
	}

	updates = nexus->tokens[ud->id].updates;
	nexus->tokens[ud->id].updates = NULL;
	while (updates != NULL) {
		MsnNexusUpdateCallback *update = updates->data;
		if (update->cb)
			purple_timeout_add(0, update->cb, update->data);
		g_free(update);
		updates = g_slist_delete_link(updates, updates);
	}

	g_free(ud);
	g_free(key);
}
예제 #19
0
파일: nexus.c 프로젝트: Lilitana/Pidgin
static char *
msn_rps_encrypt(MsnNexus *nexus)
{
	char usr_key_base[MSN_USER_KEY_SIZE], *usr_key;
	const char magic1[] = "SESSION KEY HASH";
	const char magic2[] = "SESSION KEY ENCRYPTION";
	PurpleCipherContext *hmac;
	size_t len;
	guchar *hash;
	char *key1, *key2, *key3;
	gsize key1_len;
	const char *iv;
	char *nonce_fixed;
	char *cipher;
	char *response;

	usr_key = &usr_key_base[0];
	/* Header */
	msn_push32le(usr_key, 28);                  /* Header size */
	msn_push32le(usr_key, CRYPT_MODE_CBC);      /* Crypt mode */
	msn_push32le(usr_key, CIPHER_TRIPLE_DES);   /* Cipher type */
	msn_push32le(usr_key, HASH_SHA1);           /* Hash type */
	msn_push32le(usr_key, 8);                   /* IV size */
	msn_push32le(usr_key, 20);                  /* Hash size */
	msn_push32le(usr_key, 72);                  /* Cipher size */
	/* Data */
	iv = usr_key;
	msn_push32le(usr_key, rand());
	msn_push32le(usr_key, rand());
	hash = (guchar *)usr_key;
	usr_key += 20;  /* Remaining is cipher data */

	key1 = (char *)purple_base64_decode((const char *)nexus->tokens[MSN_AUTH_MESSENGER].secret, &key1_len);
	key2 = rps_create_key(key1, key1_len, magic1, sizeof(magic1) - 1);
	key3 = rps_create_key(key1, key1_len, magic2, sizeof(magic2) - 1);

	len = strlen(nexus->nonce);
	hmac = purple_cipher_context_new_by_name("hmac", NULL);
	purple_cipher_context_set_option(hmac, "hash", "sha1");
	purple_cipher_context_set_key_with_len(hmac, (guchar *)key2, 24);
	purple_cipher_context_append(hmac, (guchar *)nexus->nonce, len);
	purple_cipher_context_digest(hmac, 20, hash, NULL);
	purple_cipher_context_destroy(hmac);

	/* 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, iv, nonce_fixed, len + 8, FALSE);
	g_free(nonce_fixed);

	memcpy(usr_key, cipher, 72);

	g_free(key1);
	g_free(key2);
	g_free(key3);
	g_free(cipher);

	response = purple_base64_encode((guchar *)usr_key_base, MSN_USER_KEY_SIZE);

	return response;
}
예제 #20
0
/*Post the Offline Instant Message to User Conversation*/
static void
msn_oim_report_to_user(MsnOimRecvData *rdata, const char *msg_str)
{
	MsnMessage *message;
	const char *date;
	const char *from;
	const char *boundary;
	char *decode_msg = NULL;
	gsize body_len;
	char **tokens;
	char *passport = NULL;
	time_t stamp;

	message = msn_message_new(MSN_MSG_UNKNOWN);

	msn_message_parse_payload(message, msg_str, strlen(msg_str),
	                          MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM);
	purple_debug_info("msn", "oim body:{%s}\n", message->body);

	boundary = msn_message_get_attr(message, "boundary");

	if (boundary != NULL) {
		char *bounds;
		char **part;

		bounds = g_strdup_printf("--%s" MSG_OIM_LINE_DEM, boundary);
		tokens = g_strsplit(message->body, bounds, 0);

		/* tokens+1 to skip the "This is a multipart message..." text */
		for (part = tokens+1; *part != NULL; part++) {
			MsnMessage *multipart;
			const char *type;
			multipart = msn_message_new(MSN_MSG_UNKNOWN);
			msn_message_parse_payload(multipart, *part, strlen(*part),
			                          MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM);

			type = msn_message_get_content_type(multipart);
			if (type && !strcmp(type, "text/plain")) {
				decode_msg = (char *)purple_base64_decode(multipart->body, &body_len);
				msn_message_destroy(multipart);
				break;
			}
			msn_message_destroy(multipart);
		}

		g_strfreev(tokens);
		g_free(bounds);

		if (decode_msg == NULL) {
			purple_debug_error("msn", "Couldn't find text/plain OIM message.\n");
			msn_message_destroy(message);
			return;
		}
	} else {
		decode_msg = (char *)purple_base64_decode(message->body, &body_len);
	}

	from = msn_message_get_attr(message, "X-OIM-originatingSource");

	/* Match number to user's mobile number, FROM is a phone number
	   if the other side pages you using your phone number */
	if (from && !strncmp(from, "tel:+", 5)) {
		MsnUser *user =	msn_userlist_find_user_with_mobile_phone(
				rdata->oim->session->userlist, from + 4);

		if (user && user->passport)
			passport = g_strdup(user->passport);
	}

	if (passport == NULL) {
		char *start, *end;

		from = msn_message_get_attr(message, "From");

		tokens = g_strsplit(from, " ", 2);
		if (tokens[1] != NULL)
			from = (const char *)tokens[1];

		start = strchr(from, '<');
		if (start != NULL) {
			start++;
			end = strchr(from, '>');
			if (end != NULL)
				passport = g_strndup(start, end - start);
		}
		if (passport == NULL)
			passport = g_strdup(_("Unknown"));

		g_strfreev(tokens);
	}

	date = msn_message_get_attr(message, "Date");
	stamp = msn_oim_parse_timestamp(date);
	purple_debug_info("msn", "oim Date:{%s},passport{%s}\n",
	                  date, passport);

	serv_got_im(rdata->oim->session->account->gc, passport, decode_msg, 0,
	            stamp);

	/*Now get the oim message ID from the oim_list.
	 * and append to read list to prepare for deleting the Offline Message when sign out
	 */
	msn_oim_post_delete_msg(rdata);

	g_free(passport);
	g_free(decode_msg);
	msn_message_destroy(message);
}
예제 #21
0
static JabberSaslState
scram_handle_challenge(JabberStream *js, PurpleXmlNode *challenge, PurpleXmlNode **out, char **error)
{
	JabberScramData *data = js->auth_mech_data;
	PurpleXmlNode *reply;
	gchar *enc_in, *dec_in = NULL;
	gchar *enc_out = NULL, *dec_out = NULL;
	gsize len;
	JabberSaslState state = JABBER_SASL_STATE_FAIL;

	enc_in = purple_xmlnode_get_data(challenge);
	if (!enc_in || *enc_in == '\0') {
		reply = purple_xmlnode_new("abort");
		purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);
		data->step = -1;
		*error = g_strdup(_("Invalid challenge from server"));
		goto out;
	}

	dec_in = (gchar *)purple_base64_decode(enc_in, &len);
	if (!dec_in || len != strlen(dec_in)) {
		/* Danger afoot; SCRAM shouldn't contain NUL bytes */
		reply = purple_xmlnode_new("abort");
		purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);
		data->step = -1;
		*error = g_strdup(_("Malicious challenge from server"));
		goto out;
	}

	purple_debug_misc("jabber", "decoded challenge: %s\n", dec_in);

	if (!jabber_scram_feed_parser(data, dec_in, &dec_out)) {
		reply = purple_xmlnode_new("abort");
		purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);
		data->step = -1;
		*error = g_strdup(_("Invalid challenge from server"));
		goto out;
	}

	data->step += 1;

	reply = purple_xmlnode_new("response");
	purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);

	purple_debug_misc("jabber", "decoded response: %s\n", dec_out ? dec_out : "(null)");
	if (dec_out) {
		enc_out = purple_base64_encode((guchar *)dec_out, strlen(dec_out));
		purple_xmlnode_insert_data(reply, enc_out, -1);
	}

	state = JABBER_SASL_STATE_CONTINUE;

out:
	g_free(enc_in);
	g_free(dec_in);
	g_free(enc_out);
	g_free(dec_out);

	*out = reply;
	return state;
}
예제 #22
0
void
jabber_ibb_parse(JabberStream *js, const char *who, JabberIqType type,
                 const char *id, PurpleXmlNode *child)
{
	const char *name = child->name;
	gboolean data  = g_str_equal(name, "data");
	gboolean close = g_str_equal(name, "close");
	gboolean open  = g_str_equal(name, "open");
	const gchar *sid = (data || close) ?
		purple_xmlnode_get_attrib(child, "sid") : NULL;
	JabberIBBSession *sess =
		sid ? g_hash_table_lookup(jabber_ibb_sessions, sid) : NULL;

	if (sess) {

		if (strcmp(who, jabber_ibb_session_get_who(sess)) != 0) {
			/* the iq comes from a different JID than the remote JID of the
			  session, ignore it */
			purple_debug_error("jabber",
				"Got IBB iq from wrong JID, ignoring\n");
		} else if (data) {
			const gchar *seq_attr = purple_xmlnode_get_attrib(child, "seq");
			guint16 seq = (seq_attr ? atoi(seq_attr) : 0);

			/* reject the data, and set the session in error if we get an
			  out-of-order packet */
			if (seq_attr && seq == jabber_ibb_session_get_recv_seq(sess)) {
				/* sequence # is the expected... */
				JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);

				jabber_iq_set_id(result, id);
				purple_xmlnode_set_attrib(result->node, "to", who);

				if (sess->data_received_cb) {
					gchar *base64 = purple_xmlnode_get_data(child);
					gsize size;
					gpointer rawdata = purple_base64_decode(base64, &size);

					g_free(base64);

					if (rawdata) {
						purple_debug_info("jabber",
							"got %" G_GSIZE_FORMAT " bytes of data on IBB stream\n",
							size);
						/* we accept other clients to send up to block-size
						 of _unencoded_ data, since there's been some confusions
						 regarding the interpretation of this attribute
						 (including previous versions of libpurple) */
						if (size > jabber_ibb_session_get_block_size(sess)) {
							purple_debug_error("jabber",
								"IBB: received a too large packet\n");
							if (sess->error_cb)
								sess->error_cb(sess);
							g_free(rawdata);
							return;
						} else {
							purple_debug_info("jabber",
								"calling IBB callback for received data\n");
							sess->data_received_cb(sess, rawdata, size);
						}
						g_free(rawdata);
					} else {
						purple_debug_error("jabber",
							"IBB: invalid BASE64 data received\n");
						if (sess->error_cb)
							sess->error_cb(sess);
						return;

					}
				}

				(sess->recv_seq)++;
				jabber_iq_send(result);

			} else {
				purple_debug_error("jabber",
					"Received an out-of-order/invalid IBB packet\n");
				sess->state = JABBER_IBB_SESSION_ERROR;

				if (sess->error_cb) {
					sess->error_cb(sess);
				}
			}
		} else if (close) {
			sess->state = JABBER_IBB_SESSION_CLOSED;
			purple_debug_info("jabber", "IBB: received close\n");

			if (sess->closed_cb) {
				purple_debug_info("jabber", "IBB: calling closed handler\n");
				sess->closed_cb(sess);
			}
		}
	} else if (open) {
		JabberIq *result;
		const GList *iterator;

		/* run all open handlers registered until one returns true */
		for (iterator = open_handlers ; iterator ;
			 iterator = g_list_next(iterator)) {
			JabberIBBOpenHandler *handler = iterator->data;

			if (handler(js, who, id, child)) {
				result = jabber_iq_new(js, JABBER_IQ_RESULT);
				purple_xmlnode_set_attrib(result->node, "to", who);
				jabber_iq_set_id(result, id);
				jabber_iq_send(result);
				return;
			}
		}
		/* no open callback returned success, reject */
		jabber_ibb_send_error_response(js, who, id);
	} else {
		/* send error reply */
		jabber_ibb_send_error_response(js, who, id);
	}
}
예제 #23
0
/*Post the Offline Instant Message to User Conversation*/
static void
msn_oim_report_to_user(MsnOimRecvData *rdata, const char *msg_str)
{
    MsnMessage *message;
    const char *date;
    const char *from;
    const char *boundary;
    char *decode_msg = NULL, *clean_msg = NULL;
    gsize body_len;
    char **tokens;
    char *passport = NULL;
    time_t stamp;
    const char *charset = NULL;

    message = msn_message_new(MSN_MSG_UNKNOWN);

    msn_message_parse_payload(message, msg_str, strlen(msg_str),
                              MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM);
    purple_debug_info("msn", "oim body:{%s}\n", message->body);

    boundary = msn_message_get_header_value(message, "boundary");

    if (boundary != NULL) {
        char *bounds;
        char **part;

        bounds = g_strdup_printf("--%s" MSG_OIM_LINE_DEM, boundary);
        tokens = g_strsplit(message->body, bounds, 0);

        /* tokens+1 to skip the "This is a multipart message..." text */
        for (part = tokens+1; *part != NULL; part++) {
            MsnMessage *multipart;
            const char *type;
            multipart = msn_message_new(MSN_MSG_UNKNOWN);
            msn_message_parse_payload(multipart, *part, strlen(*part),
                                      MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM);

            type = msn_message_get_content_type(multipart);
            if (type && !strcmp(type, "text/plain")) {
                decode_msg = (char *)purple_base64_decode(multipart->body, &body_len);
                charset = msn_message_get_charset(multipart);

                msn_message_unref(multipart);
                break;
            }
            msn_message_unref(multipart);
        }

        g_strfreev(tokens);
        g_free(bounds);

        if (decode_msg == NULL) {
            purple_debug_error("msn", "Couldn't find text/plain OIM message.\n");
            msn_message_unref(message);
            return;
        }
    } else {
        decode_msg = (char *)purple_base64_decode(message->body, &body_len);
        charset = msn_message_get_charset(message);
    }

    if (charset && !((g_ascii_strncasecmp(charset, "UTF-8", 5) == 0) || (g_ascii_strncasecmp(charset, "UTF8", 4) == 0))) {
        clean_msg = g_convert(decode_msg, body_len, "UTF-8", charset, NULL, NULL, NULL);

        if (!clean_msg) {
            char *clean = purple_utf8_salvage(decode_msg);

            purple_debug_error("msn", "Failed to convert charset from %s to UTF-8 for OIM message: %s\n", charset, clean);

            clean_msg = g_strdup_printf(_("%s (There was an error receiving this message. "
                                          "Converting the encoding from %s to UTF-8 failed.)"),
                                        clean, charset);
            g_free(clean);
        }

        g_free(decode_msg);

    } else if (!g_utf8_validate(decode_msg, body_len, NULL)) {
        char *clean = purple_utf8_salvage(decode_msg);

        purple_debug_error("msn", "Received an OIM message that is not UTF-8,"
                           " and no encoding specified: %s\n", clean);

        if (charset) {
            clean_msg = g_strdup_printf(_("%s (There was an error receiving this message."
                                          " The charset was %s, but it was not valid UTF-8.)"),
                                        clean, charset);
        } else {
            clean_msg = g_strdup_printf(_("%s (There was an error receiving this message."
                                          " The charset was missing, but it was not valid UTF-8.)"),
                                        clean);
        }

        g_free(clean);
        g_free(decode_msg);

    } else {
        clean_msg = decode_msg;
    }

    from = msn_message_get_header_value(message, "X-OIM-originatingSource");

    /* Match number to user's mobile number, FROM is a phone number
       if the other side pages you using your phone number */
    if (from && !strncmp(from, "tel:+", 5)) {
        MsnUser *user =	msn_userlist_find_user_with_mobile_phone(
                            rdata->oim->session->userlist, from + 4);

        if (user && user->passport)
            passport = g_strdup(user->passport);
    }

    if (passport == NULL) {
        char *start, *end;

        from = msn_message_get_header_value(message, "From");

        tokens = g_strsplit(from, " ", 2);
        if (tokens[1] != NULL)
            from = (const char *)tokens[1];

        start = strchr(from, '<');
        if (start != NULL) {
            start++;
            end = strchr(from, '>');
            if (end != NULL)
                passport = g_strndup(start, end - start);
        }
        if (passport == NULL)
            passport = g_strdup(_("Unknown"));

        g_strfreev(tokens);
    }

    date = msn_message_get_header_value(message, "Date");
    stamp = msn_oim_parse_timestamp(date);
    purple_debug_info("msn", "oim Date:{%s},passport{%s}\n",
                      date, passport);

    purple_serv_got_im(purple_account_get_connection(rdata->oim->session->account), passport, clean_msg, 0,
                       stamp);

    /*Now get the oim message ID from the oim_list.
     * and append to read list to prepare for deleting the Offline Message when sign out
     */
    msn_oim_post_delete_msg(rdata);

    g_free(passport);
    g_free(clean_msg);
    msn_message_unref(message);
}
예제 #24
0
static JabberSaslState
fb_handle_challenge(JabberStream *js, xmlnode *packet,
                            xmlnode **response, char **msg)
{
	xmlnode *reply = NULL;
	gchar *challenge;
	guchar *decoded;
	gsize decoded_len;
	gchar **pairs, *method, *nonce;
	gsize i;
	GString *request;
	gchar *enc_out;

	/* Get base64-encoded challenge from XML */
	challenge = xmlnode_get_data(packet);
	if (challenge == NULL) {
		*msg = g_strdup(_("Invalid response from server"));
		return JABBER_SASL_STATE_FAIL;
	}

	/* Decode challenge */
	decoded = purple_base64_decode(challenge, &decoded_len);
	if (decoded == NULL) {
		purple_debug_error("jabber", "X-FACEBOOK-PLATFORM challenge "
						   "wasn't valid base64: %s\n", challenge);
	
		*msg = g_strdup(_("Invalid response from server"));

		g_free(challenge);
		return JABBER_SASL_STATE_FAIL;
	}
	g_free(challenge);

	/* NULL-terminate the challenge so we can parse it */
	challenge = g_strndup((const gchar *)decoded, decoded_len);
	g_free(decoded);
	purple_debug_misc("jabber", "X-FACEBOOK-PLATFORM decoded "
					  "challenge is %s\n", challenge);

	/* Get method and nonce */
	method = NULL;
	nonce = NULL;
	pairs = g_strsplit(challenge, "&", 0);
	for (i = 0; pairs[i] != NULL; i++) {
		if (g_str_has_prefix(pairs[i], "method=")) {
			g_free(method);
			// TODO: Should url decode this value
			method = g_strdup(strchr(pairs[i], '=') + 1);
		} else if (g_str_has_prefix(pairs[i], "nonce=")) {
			g_free(nonce);
			// TODO: Should url decode this value
			nonce = g_strdup(strchr(pairs[i], '=') + 1);
		}
	}
	g_strfreev(pairs);
	if (!method || !nonce) {
		purple_debug_error("jabber", "X-FACEBOOK-PLATFORM challenge "
						   "is missing method or nonce: %s\n", challenge);
		*msg = g_strdup(_("Invalid response from server"));

		g_free(method);
		g_free(nonce);
		g_free(challenge);
		return JABBER_SASL_STATE_FAIL;
	}
	g_free(challenge);

	request = purple_fbapi_construct_request(purple_connection_get_account(js->gc),
											 method,
											 "v", "1.0",
											 "session_key", purple_connection_get_password(js->gc),
											 "nonce", nonce,
											 NULL);
	g_free(method);
	g_free(nonce);

	purple_debug_misc("jabber", "X-FACEBOOK-PLATFORM response before "
					  "encoding is %s\n", request->str);
	enc_out = purple_base64_encode((const guchar *)request->str, request->len);
	g_string_free(request, TRUE);

	reply = xmlnode_new("response");
	xmlnode_set_namespace(reply, NS_XMPP_SASL);
	xmlnode_insert_data(reply, enc_out, -1);

	g_free(enc_out);

	*response = reply;

	return JABBER_SASL_STATE_CONTINUE;
}
예제 #25
0
파일: slp.c 프로젝트: deadcow/msn-pecan
static void
got_sessionreq(MsnSlpCall *slpcall, const char *branch,
			   const char *euf_guid, const char *context)
{
	pecan_debug ("euf_guid=[%s]", euf_guid);

	if (!strcmp(euf_guid, "A4268EEC-FEC5-49E5-95C3-F126696BDBF6"))
	{
		/* Emoticon or UserDisplay */
		char *content;
		gsize len;
		MsnSlpSession *slpsession;
		MsnSlpLink *slplink;
		MsnSlpMessage *slpmsg;
		MsnObject *obj;
		char *msnobj_data;
		PecanBuffer *image;
		int type;

		/* Send Ok */
                content = pecan_strdup_printf("SessionID: %lu\r\n\r\n",
                                              slpcall->session_id);

		send_ok(slpcall, branch, "application/x-msnmsgr-sessionreqbody",
				content);

		g_free(content);

		slplink = slpcall->slplink;

		msnobj_data = (char *)purple_base64_decode(context, &len);
		obj = msn_object_new_from_string(msnobj_data);
		type = msn_object_get_type(obj);
		g_free(msnobj_data);

		if (type == MSN_OBJECT_USERTILE)
		{
			/* image is owned by a local object, not obj */
			image = msn_object_get_image(obj);
		}
#if PURPLE_VERSION_CHECK(2,5,0)
		else if (type == MSN_OBJECT_EMOTICON)
		{
			PurpleStoredImage *img;
			char *path;
			path = g_build_filename(purple_smileys_get_storing_dir(), msn_object_get_location(obj), NULL);
			img = purple_imgstore_new_from_file(path);
			image = pecan_buffer_new_memdup ((const gpointer) purple_imgstore_get_data (img),
							 purple_imgstore_get_size (img));
			purple_imgstore_unref(img);
			g_free(path);
		}
#endif /* PURPLE_VERSION_CHECK(2,5,0) */
		else
		{
			pecan_error ("Wrong object?");
			msn_object_destroy(obj);
			g_return_if_reached();
		}

		if (!image)
		{
                    pecan_error ("Wrong object");
                    msn_object_destroy (obj);
                    g_return_if_reached ();
		}

		msn_object_destroy(obj);

		{
			gchar *tmp;
			tmp = msn_object_to_string (obj);
			pecan_info ("object requested: %s", tmp);
			g_free (tmp);
		}

		slpsession = msn_slplink_find_slp_session(slplink,
												  slpcall->session_id);

		/* DATA PREP */
		slpmsg = msn_slpmsg_new(slplink);
		slpmsg->slpcall = slpcall;
		slpmsg->slpsession = slpsession;
		slpmsg->session_id = slpsession->id;
		msn_slpmsg_set_body(slpmsg, NULL, 4);
#ifdef PECAN_DEBUG_SLP
		slpmsg->info = "SLP DATA PREP";
#endif
		msn_slplink_queue_slpmsg(slplink, slpmsg);

		/* DATA */
		slpmsg = msn_slpmsg_new(slplink);
		slpmsg->slpcall = slpcall;
		slpmsg->slpsession = slpsession;
		slpmsg->flags = 0x20;
#ifdef PECAN_DEBUG_SLP
		slpmsg->info = "SLP DATA";
#endif
		msn_slpmsg_set_image (slpmsg, image);
		msn_slplink_queue_slpmsg(slplink, slpmsg);
	}
	else if (!strcmp(euf_guid, "5D3E02AB-6190-11D3-BBBB-00C04F795683"))
	{
		/* File Transfer */
		PurpleAccount *account;
		PurpleXfer *xfer;
		char *bin;
		gsize bin_len;
		guint32 file_size;
		char *file_name;
		gunichar2 *uni_name;

		account = slpcall->slplink->session->account;

		slpcall->cb = msn_xfer_completed_cb;
		slpcall->end_cb = msn_xfer_end_cb;
		slpcall->progress_cb = msn_xfer_progress_cb;
		slpcall->branch = g_strdup(branch);

		slpcall->pending = TRUE;

		xfer = purple_xfer_new(account, PURPLE_XFER_RECEIVE,
							   slpcall->slplink->remote_user);
		if (xfer)
		{
			bin = (char *)purple_base64_decode(context, &bin_len);
			file_size = GUINT32_FROM_LE(*(gsize *)(bin + 8));

			uni_name = (gunichar2 *)(bin + 20);
			while(*uni_name != 0 && ((char *)uni_name - (bin + 20)) < MAX_FILE_NAME_LEN) {
				*uni_name = GUINT16_FROM_LE(*uni_name);
				uni_name++;
			}

			file_name = g_utf16_to_utf8((const gunichar2 *)(bin + 20), -1,
										NULL, NULL, NULL);

			g_free(bin);

			purple_xfer_set_filename(xfer, file_name);
			purple_xfer_set_size(xfer, file_size);
			purple_xfer_set_init_fnc(xfer, msn_xfer_init);
			purple_xfer_set_request_denied_fnc(xfer, msn_xfer_cancel);
			purple_xfer_set_cancel_recv_fnc(xfer, msn_xfer_cancel);

			slpcall->xfer = xfer;
			purple_xfer_ref(slpcall->xfer);

			xfer->data = slpcall;

			purple_xfer_request(xfer);
		}
	}
}