Esempio n. 1
0
static PurpleXmlNode *
pounce_to_xmlnode(PurplePounce *pounce)
{
	PurpleXmlNode *node, *child;
	PurpleAccount *pouncer;
	PurplePounceEvent events;
	PurplePounceOption options;

	pouncer = purple_pounce_get_pouncer(pounce);
	events  = purple_pounce_get_events(pounce);
	options = purple_pounce_get_options(pounce);

	node = purple_xmlnode_new("pounce");
	purple_xmlnode_set_attrib(node, "ui", pounce->ui_type);

	child = purple_xmlnode_new_child(node, "account");
	purple_xmlnode_set_attrib(child, "protocol", purple_account_get_protocol_id(pouncer));
	purple_xmlnode_insert_data(child,
			purple_normalize(pouncer, purple_account_get_username(pouncer)), -1);

	child = purple_xmlnode_new_child(node, "pouncee");
	purple_xmlnode_insert_data(child, purple_pounce_get_pouncee(pounce), -1);

	/* Write pounce options */
	child = purple_xmlnode_new_child(node, "options");
	if (options & PURPLE_POUNCE_OPTION_AWAY)
		add_option_to_xmlnode(child, "on-away");

	/* Write pounce events */
	child = purple_xmlnode_new_child(node, "events");
	if (events & PURPLE_POUNCE_SIGNON)
		add_event_to_xmlnode(child, "sign-on");
	if (events & PURPLE_POUNCE_SIGNOFF)
		add_event_to_xmlnode(child, "sign-off");
	if (events & PURPLE_POUNCE_AWAY)
		add_event_to_xmlnode(child, "away");
	if (events & PURPLE_POUNCE_AWAY_RETURN)
		add_event_to_xmlnode(child, "return-from-away");
	if (events & PURPLE_POUNCE_IDLE)
		add_event_to_xmlnode(child, "idle");
	if (events & PURPLE_POUNCE_IDLE_RETURN)
		add_event_to_xmlnode(child, "return-from-idle");
	if (events & PURPLE_POUNCE_TYPING)
		add_event_to_xmlnode(child, "start-typing");
	if (events & PURPLE_POUNCE_TYPED)
		add_event_to_xmlnode(child, "typed");
	if (events & PURPLE_POUNCE_TYPING_STOPPED)
		add_event_to_xmlnode(child, "stop-typing");
	if (events & PURPLE_POUNCE_MESSAGE_RECEIVED)
		add_event_to_xmlnode(child, "message-received");

	/* Write pounce actions */
	child = purple_xmlnode_new_child(node, "actions");
	g_hash_table_foreach(pounce->actions, action_parameter_list_to_xmlnode, child);

	if (purple_pounce_get_save(pounce))
		purple_xmlnode_new_child(node, "save");

	return node;
}
Esempio n. 2
0
static void jabber_iq_version_parse(JabberStream *js, const char *from,
                                    JabberIqType type, const char *id,
                                    PurpleXmlNode *packet)
{
	JabberIq *iq;
	PurpleXmlNode *query;

	if(type == JABBER_IQ_GET) {
		GHashTable *ui_info;
		const char *ui_name = NULL, *ui_version = NULL;
#if 0
		char *os = NULL;
		if(!purple_prefs_get_bool("/plugins/prpl/jabber/hide_os")) {
			struct utsname osinfo;

			uname(&osinfo);
			os = g_strdup_printf("%s %s %s", osinfo.sysname, osinfo.release,
					osinfo.machine);
		}
#endif

		iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:version");
		if (from)
			purple_xmlnode_set_attrib(iq->node, "to", from);
		jabber_iq_set_id(iq, id);

		query = purple_xmlnode_get_child(iq->node, "query");

		ui_info = purple_core_get_ui_info();

		if(NULL != ui_info) {
			ui_name = g_hash_table_lookup(ui_info, "name");
			ui_version = g_hash_table_lookup(ui_info, "version");
		}

		if(NULL != ui_name && NULL != ui_version) {
			char *version_complete = g_strdup_printf("%s (libpurple " VERSION ")", ui_version);
			purple_xmlnode_insert_data(purple_xmlnode_new_child(query, "name"), ui_name, -1);
			purple_xmlnode_insert_data(purple_xmlnode_new_child(query, "version"), version_complete, -1);
			g_free(version_complete);
		} else {
			purple_xmlnode_insert_data(purple_xmlnode_new_child(query, "name"), "libpurple", -1);
			purple_xmlnode_insert_data(purple_xmlnode_new_child(query, "version"), VERSION, -1);
		}

#if 0
		if(os) {
			purple_xmlnode_insert_data(purple_xmlnode_new_child(query, "os"), os, -1);
			g_free(os);
		}
#endif

		jabber_iq_send(iq);
	}
}
Esempio n. 3
0
static gboolean
msn_oim_request_helper(MsnOimRequestData *data)
{
    MsnSession *session = data->oim->session;

    if (data->send) {
        /* The Sending of OIM's uses a different token for some reason. */
        PurpleXmlNode *ticket;
        ticket = purple_xmlnode_get_child(data->body, "Header/Ticket");
        purple_xmlnode_set_attrib(ticket, "passport",
                                  msn_nexus_get_token_str(session->nexus, MSN_AUTH_LIVE_SECURE));
    }
    else
    {
        PurpleXmlNode *passport;
        PurpleXmlNode *xml_t;
        PurpleXmlNode *xml_p;
        GHashTable *token;
        const char *msn_t;
        const char *msn_p;

        token = msn_nexus_get_token(session->nexus, MSN_AUTH_MESSENGER_WEB);
        g_return_val_if_fail(token != NULL, FALSE);

        msn_t = g_hash_table_lookup(token, "t");
        msn_p = g_hash_table_lookup(token, "p");

        g_return_val_if_fail(msn_t != NULL, FALSE);
        g_return_val_if_fail(msn_p != NULL, FALSE);

        passport = purple_xmlnode_get_child(data->body, "Header/PassportCookie");
        xml_t = purple_xmlnode_get_child(passport, "t");
        xml_p = purple_xmlnode_get_child(passport, "p");

        /* frees old token text, or the 'EMPTY' text if first time */
        purple_xmlnode_free(xml_t->child);
        purple_xmlnode_free(xml_p->child);

        purple_xmlnode_insert_data(xml_t, msn_t, -1);
        purple_xmlnode_insert_data(xml_p, msn_p, -1);
    }

    msn_soap_service_send_message(session->soap,
                                  msn_soap_message_new(data->action, purple_xmlnode_copy(data->body)),
                                  data->host, data->url, FALSE, msn_oim_request_cb, data);

    return FALSE;
}
Esempio n. 4
0
static void finish_plaintext_authentication(JabberStream *js)
{
	JabberIq *iq;
	PurpleXmlNode *query, *x;

	iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
	query = purple_xmlnode_get_child(iq->node, "query");
	x = purple_xmlnode_new_child(query, "username");
	purple_xmlnode_insert_data(x, js->user->node, -1);
	x = purple_xmlnode_new_child(query, "resource");
	purple_xmlnode_insert_data(x, js->user->resource, -1);
	x = purple_xmlnode_new_child(query, "password");
	purple_xmlnode_insert_data(x, purple_connection_get_password(js->gc), -1);
	jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
	jabber_iq_send(iq);
}
Esempio n. 5
0
void jabber_auth_start_old(JabberStream *js)
{
	PurpleAccount *account;
	JabberIq *iq;
	PurpleXmlNode *query, *username;

	account = purple_connection_get_account(js->gc);

	/*
	 * We can end up here without encryption if the server doesn't support
	 * <stream:features/> and we're not using old-style SSL.  If the user
	 * is requiring SSL/TLS, we need to enforce it.
	 */
	if (!jabber_stream_is_ssl(js) &&
			g_str_equal("require_tls",
				purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS))) {
		purple_connection_error(js->gc,
			PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
			_("You require encryption, but it is not available on this server."));
		return;
	}

	if (js->registration) {
		jabber_register_start(js);
		return;
	}

	/*
	 * IQ Auth doesn't have support for resource binding, so we need to pick a
	 * default resource so it will work properly.  jabberd14 throws an error and
	 * iChat server just fails silently.
	 */
	if (!js->user->resource || *js->user->resource == '\0') {
		g_free(js->user->resource);
		js->user->resource = g_strdup("Home");
	}

#ifdef HAVE_CYRUS_SASL
	/* If we have Cyrus SASL, then passwords will have been set
	 * to OPTIONAL for this protocol. So, we need to do our own
	 * password prompting here
	 */

	if (!purple_connection_get_password(js->gc)) {
		purple_account_request_password(account, G_CALLBACK(auth_old_pass_cb), G_CALLBACK(auth_no_pass_cb), js->gc);
		return;
	}
#endif
	iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:auth");

	query = purple_xmlnode_get_child(iq->node, "query");
	username = purple_xmlnode_new_child(query, "username");
	purple_xmlnode_insert_data(username, js->user->node, -1);

	jabber_iq_set_callback(iq, auth_old_cb, NULL);

	jabber_iq_send(iq);
}
Esempio n. 6
0
static void jabber_time_parse(JabberStream *js, const char *from,
                              JabberIqType type, const char *id,
                              PurpleXmlNode *child)
{
	JabberIq *iq;
	time_t now_t;
	struct tm *tm;

	time(&now_t);

	if(type == JABBER_IQ_GET) {
		PurpleXmlNode *tzo, *utc;
		const char *date, *tz;

		iq = jabber_iq_new(js, JABBER_IQ_RESULT);
		jabber_iq_set_id(iq, id);
		if (from)
			purple_xmlnode_set_attrib(iq->node, "to", from);

		child = purple_xmlnode_new_child(iq->node, child->name);
		purple_xmlnode_set_namespace(child, NS_ENTITY_TIME);

		/* <tzo>-06:00</tzo> */
		tm = localtime(&now_t);
		tz = purple_get_tzoff_str(tm, TRUE);
		tzo = purple_xmlnode_new_child(child, "tzo");
		purple_xmlnode_insert_data(tzo, tz, -1);

		/* <utc>2006-12-19T17:58:35Z</utc> */
		tm = gmtime(&now_t);
		date = purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", tm);
		utc = purple_xmlnode_new_child(child, "utc");
		purple_xmlnode_insert_data(utc, date, -1);

		jabber_iq_send(iq);
	} else {
		/* TODO: Errors */
	}
}
Esempio n. 7
0
static void
purple_xmlnode_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len)
{
    struct _xmlnode_parser_data *xpd = user_data;

    if(!xpd->current || xpd->error)
        return;

    if(!text || !text_len)
        return;

    purple_xmlnode_insert_data(xpd->current, (const char*) text, text_len);
}
Esempio n. 8
0
static void
action_parameter_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
{
	const char *name, *param_value;
	PurpleXmlNode *node, *child;

	name        = (const char *)key;
	param_value = (const char *)value;
	node        = (PurpleXmlNode *)user_data;

	child = purple_xmlnode_new_child(node, "param");
	purple_xmlnode_set_attrib(child, "name", name);
	purple_xmlnode_insert_data(child, param_value, -1);
}
Esempio n. 9
0
static void do_nick_set(JabberStream *js, const char *nick) {
	PurpleXmlNode *publish, *nicknode;

	publish = purple_xmlnode_new("publish");
	purple_xmlnode_set_attrib(publish,"node","http://jabber.org/protocol/nick");
	nicknode = purple_xmlnode_new_child(purple_xmlnode_new_child(publish, "item"), "nick");
	purple_xmlnode_set_namespace(nicknode, "http://jabber.org/protocol/nick");

	if(nick && nick[0] != '\0')
		purple_xmlnode_insert_data(nicknode, nick, -1);

	jabber_pep_publish(js, publish);
	/* publish is freed by jabber_pep_publish -> jabber_iq_send -> jabber_iq_free
		(yay for well-defined memory management rules) */
}
Esempio n. 10
0
void
jabber_ibb_session_send_data(JabberIBBSession *sess, gconstpointer data,
                             gsize size)
{
	JabberIBBSessionState state = jabber_ibb_session_get_state(sess);

	purple_debug_info("jabber", "sending data block of %" G_GSIZE_FORMAT " bytes on IBB stream\n",
		size);

	if (state != JABBER_IBB_SESSION_OPENED) {
		purple_debug_error("jabber",
			"trying to send data on a non-open IBB session\n");
	} else if (size > jabber_ibb_session_get_max_data_size(sess)) {
		purple_debug_error("jabber",
			"trying to send a too large packet in the IBB session\n");
	} else {
		JabberIq *set = jabber_iq_new(jabber_ibb_session_get_js(sess),
			JABBER_IQ_SET);
		PurpleXmlNode *data_element = purple_xmlnode_new("data");
		char *base64 = purple_base64_encode(data, size);
		char seq[10];
		g_snprintf(seq, sizeof(seq), "%u", jabber_ibb_session_get_send_seq(sess));

		purple_xmlnode_set_attrib(set->node, "to", jabber_ibb_session_get_who(sess));
		purple_xmlnode_set_namespace(data_element, NS_IBB);
		purple_xmlnode_set_attrib(data_element, "sid", jabber_ibb_session_get_sid(sess));
		purple_xmlnode_set_attrib(data_element, "seq", seq);
		purple_xmlnode_insert_data(data_element, base64, -1);

		purple_xmlnode_insert_child(set->node, data_element);

		purple_debug_info("jabber",
			"IBB: setting send <iq/> callback for session %p %s\n", sess,
			sess->sid);
		jabber_iq_set_callback(set, jabber_ibb_session_send_acknowledge_cb, sess);
		sess->last_iq_id = g_strdup(purple_xmlnode_get_attrib(set->node, "id"));
		purple_debug_info("jabber", "IBB: set sess->last_iq_id: %s\n",
			sess->last_iq_id);
		jabber_iq_send(set);

		g_free(base64);
		(sess->send_seq)++;
	}
}
Esempio n. 11
0
JabberIq *
jingle_session_redirect_packet(JingleSession *session, const gchar *sid)
{
	JabberIq *iq = jingle_session_terminate_packet(session,
			"alternative-session");
	PurpleXmlNode *alt_session;

	if (sid == NULL)
		return iq;

	alt_session = purple_xmlnode_get_child(iq->node,
			"jingle/reason/alternative-session");

	if (alt_session != NULL) {
		PurpleXmlNode *sid_node = purple_xmlnode_new_child(alt_session, "sid");
		purple_xmlnode_insert_data(sid_node, sid, -1);
	}
	return iq;
}
Esempio n. 12
0
static void
xep_ft_si_result(PurpleXfer *xfer, const char *to)
{
	PurpleXmlNode *si_node, *feature, *field, *value, *x;
	XepIq *iq;
	XepXfer *xf;
	BonjourData *bd;

	if(!to || !xfer)
		return;
	xf = purple_xfer_get_protocol_data(xfer);
	if(!xf)
		return;

	bd = xf->data;

	purple_debug_info("bonjour", "xep file transfer stream initialization result.\n");
	iq = xep_iq_new(bd, XEP_IQ_RESULT, to, bonjour_get_jid(bd->jabber_data->account), xf->iq_id);
	if(iq == NULL)
		return;

	si_node = purple_xmlnode_new_child(iq->node, "si");
	purple_xmlnode_set_namespace(si_node, "http://jabber.org/protocol/si");
	/*purple_xmlnode_set_attrib(si_node, "profile", "http://jabber.org/protocol/si/profile/file-transfer");*/

	feature = purple_xmlnode_new_child(si_node, "feature");
	purple_xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg");

	x = purple_xmlnode_new_child(feature, "x");
	purple_xmlnode_set_namespace(x, "jabber:x:data");
	purple_xmlnode_set_attrib(x, "type", "submit");

	field = purple_xmlnode_new_child(x, "field");
	purple_xmlnode_set_attrib(field, "var", "stream-method");

	value = purple_xmlnode_new_child(field, "value");
	purple_xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1);

	xep_iq_send_and_free(iq);
}
Esempio n. 13
0
static void
xep_ft_si_reject(BonjourData *bd, const char *id, const char *to, const char *error_code, const char *error_type)
{
	PurpleXmlNode *error_node;
	XepIq *iq;

	g_return_if_fail(error_code != NULL);
	g_return_if_fail(error_type != NULL);

	if(!to || !id) {
		purple_debug_info("bonjour", "xep file transfer stream initialization error.\n");
		return;
	}

	iq = xep_iq_new(bd, XEP_IQ_ERROR, to, bonjour_get_jid(bd->jabber_data->account), id);
	if(iq == NULL)
		return;

	error_node = purple_xmlnode_new_child(iq->node, "error");
	purple_xmlnode_set_attrib(error_node, "code", error_code);
	purple_xmlnode_set_attrib(error_node, "type", error_type);

	/* TODO: Make this better */
	if (!strcmp(error_code, "403")) {
		PurpleXmlNode *tmp_node = purple_xmlnode_new_child(error_node, "forbidden");
		purple_xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas");

		tmp_node = purple_xmlnode_new_child(error_node, "text");
		purple_xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas");
		purple_xmlnode_insert_data(tmp_node, "Offer Declined", -1);
	} else if (!strcmp(error_code, "404")) {
		PurpleXmlNode *tmp_node = purple_xmlnode_new_child(error_node, "item-not-found");
		purple_xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas");
	}

	xep_iq_send_and_free(iq);
}
Esempio n. 14
0
gboolean
jabber_mood_set(JabberStream *js, const char *mood, const char *text)
{
	const PurpleMood *target_mood = NULL;
	PurpleXmlNode *publish, *moodnode;

	if (mood && *mood) {
		target_mood = find_mood_by_name(mood);
		/* Mood specified, but is invalid --
		 * fail so that the command can handle this.
		 */
		if (!target_mood)
			return FALSE;
	}

	publish = purple_xmlnode_new("publish");
	purple_xmlnode_set_attrib(publish,"node","http://jabber.org/protocol/mood");
	moodnode = purple_xmlnode_new_child(purple_xmlnode_new_child(publish, "item"), "mood");
	purple_xmlnode_set_namespace(moodnode, "http://jabber.org/protocol/mood");

	if (target_mood) {
		/* If target_mood is not NULL, then
		 * target_mood->mood == mood, and is a valid element name.
		 */
	    purple_xmlnode_new_child(moodnode, mood);

		/* Only set text when setting a mood */
		if (text && *text) {
			PurpleXmlNode *textnode = purple_xmlnode_new_child(moodnode, "text");
			purple_xmlnode_insert_data(textnode, text, -1);
		}
	}

	jabber_pep_publish(js, publish);
	return TRUE;
}
Esempio n. 15
0
static void
xep_ft_si_offer(PurpleXfer *xfer, const gchar *to)
{
	PurpleXmlNode *si_node, *feature, *field, *file, *x;
	XepIq *iq;
	XepXfer *xf = purple_xfer_get_protocol_data(xfer);
	BonjourData *bd = NULL;
	char buf[32];

	if(!xf)
		return;

	bd = xf->data;
	if(!bd)
		return;

	purple_debug_info("bonjour", "xep file transfer stream initialization offer-id=%d.\n", next_id);

	/* Assign stream id. */
	g_free(xf->iq_id);
	xf->iq_id = g_strdup_printf("%u", next_id++);
	iq = xep_iq_new(xf->data, XEP_IQ_SET, to, bonjour_get_jid(bd->jabber_data->account), xf->iq_id);
	if(iq == NULL)
		return;

	/*Construct Stream initialization offer message.*/
	si_node = purple_xmlnode_new_child(iq->node, "si");
	purple_xmlnode_set_namespace(si_node, "http://jabber.org/protocol/si");
	purple_xmlnode_set_attrib(si_node, "profile", "http://jabber.org/protocol/si/profile/file-transfer");
	g_free(xf->sid);
	xf->sid = g_strdup(xf->iq_id);
	purple_xmlnode_set_attrib(si_node, "id", xf->sid);

	file = purple_xmlnode_new_child(si_node, "file");
	purple_xmlnode_set_namespace(file, "http://jabber.org/protocol/si/profile/file-transfer");
	purple_xmlnode_set_attrib(file, "name", purple_xfer_get_filename(xfer));
	g_snprintf(buf, sizeof(buf), "%" G_GOFFSET_FORMAT, purple_xfer_get_size(xfer));
	purple_xmlnode_set_attrib(file, "size", buf);

	feature = purple_xmlnode_new_child(si_node, "feature");
	purple_xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg");

	x = purple_xmlnode_new_child(feature, "x");
	purple_xmlnode_set_namespace(x, "jabber:x:data");
	purple_xmlnode_set_attrib(x, "type", "form");

	field = purple_xmlnode_new_child(x, "field");
	purple_xmlnode_set_attrib(field, "var", "stream-method");
	purple_xmlnode_set_attrib(field, "type", "list-single");

	if (xf->mode & XEP_BYTESTREAMS) {
		PurpleXmlNode *option = purple_xmlnode_new_child(field, "option");
		PurpleXmlNode *value = purple_xmlnode_new_child(option, "value");
		purple_xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1);
	}
	if (xf->mode & XEP_IBB) {
		PurpleXmlNode *option = purple_xmlnode_new_child(field, "option");
		PurpleXmlNode *value = purple_xmlnode_new_child(option, "value");
		purple_xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);
	}

	xep_iq_send_and_free(iq);
}
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;
}
Esempio n. 17
0
static JabberSaslState
scram_start(JabberStream *js, PurpleXmlNode *mechanisms, PurpleXmlNode **out, char **error)
{
	PurpleXmlNode *reply;
	JabberScramData *data;
	guint64 cnonce;
#ifdef CHANNEL_BINDING
	gboolean binding_supported = TRUE;
#endif
	gchar *dec_out, *enc_out;
	gchar *prepped_node, *tmp;
	gchar *prepped_pass;

	prepped_node = jabber_saslprep(js->user->node);
	if (!prepped_node) {
		*error = g_strdup(_("Unable to canonicalize username"));
		return JABBER_SASL_STATE_FAIL;
	}

	tmp = escape_username(prepped_node);
	g_free(prepped_node);
	prepped_node = tmp;

	prepped_pass = jabber_saslprep(purple_connection_get_password(js->gc));
	if (!prepped_pass) {
		g_free(prepped_node);
		*error = g_strdup(_("Unable to canonicalize password"));
		return JABBER_SASL_STATE_FAIL;
	}

	data = js->auth_mech_data = g_new0(JabberScramData, 1);
	data->hash = mech_to_hash(js->auth_mech->name);
	data->password = prepped_pass;

#ifdef CHANNEL_BINDING
	if (strstr(js->auth_mech_name, "-PLUS"))
		data->channel_binding = TRUE;
#endif
	cnonce = ((guint64)g_random_int() << 32) | g_random_int();
	data->cnonce = purple_base64_encode((guchar *)&cnonce, sizeof(cnonce));

	data->auth_message = g_string_new(NULL);
	g_string_printf(data->auth_message, "n=%s,r=%s",
			prepped_node, data->cnonce);
	g_free(prepped_node);

	data->step = 1;

	reply = purple_xmlnode_new("auth");
	purple_xmlnode_set_namespace(reply, NS_XMPP_SASL);
	purple_xmlnode_set_attrib(reply, "mechanism", js->auth_mech->name);

	/* TODO: Channel binding */
	dec_out = g_strdup_printf("%c,,%s", 'n', data->auth_message->str);
	enc_out = purple_base64_encode((guchar *)dec_out, strlen(dec_out));
	purple_debug_misc("jabber", "initial SCRAM message '%s'\n", dec_out);

	purple_xmlnode_insert_data(reply, enc_out, -1);

	g_free(enc_out);
	g_free(dec_out);

	*out = reply;
	return JABBER_SASL_STATE_CONTINUE;
}
Esempio n. 18
0
static void auth_old_cb(JabberStream *js, const char *from,
                        JabberIqType type, const char *id,
                        PurpleXmlNode *packet, gpointer data)
{
	JabberIq *iq;
	PurpleXmlNode *query, *x;
	const char *pw = purple_connection_get_password(js->gc);

	if (type == JABBER_IQ_ERROR) {
		PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
		char *msg = jabber_parse_error(js, packet, &reason);
		purple_connection_error(js->gc, reason, msg);
		g_free(msg);
	} else if (type == JABBER_IQ_RESULT) {
		query = purple_xmlnode_get_child(packet, "query");
		if (js->stream_id && *js->stream_id &&
				purple_xmlnode_get_child(query, "digest")) {
			char *s, *hash;

			iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
			query = purple_xmlnode_get_child(iq->node, "query");
			x = purple_xmlnode_new_child(query, "username");
			purple_xmlnode_insert_data(x, js->user->node, -1);
			x = purple_xmlnode_new_child(query, "resource");
			purple_xmlnode_insert_data(x, js->user->resource, -1);

			x = purple_xmlnode_new_child(query, "digest");
			s = g_strdup_printf("%s%s", js->stream_id, pw);
			hash = jabber_calculate_data_hash(s, strlen(s), "sha1");
			purple_xmlnode_insert_data(x, hash, -1);
			g_free(hash);
			g_free(s);
			jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
			jabber_iq_send(iq);
		} else if ((x = purple_xmlnode_get_child(query, "crammd5"))) {
			/* For future reference, this appears to be a custom OS X extension
			 * to non-SASL authentication.
			 */
			const char *challenge;
			gchar digest[33];
			PurpleCipher *hmac;
			PurpleHash *md5;
			gssize diglen;

			/* Calculate the MHAC-MD5 digest */
			md5 = purple_md5_hash_new();
			hmac = purple_hmac_cipher_new(md5);
			challenge = purple_xmlnode_get_attrib(x, "challenge");
			purple_cipher_set_key(hmac, (guchar *)pw, strlen(pw));
			purple_cipher_append(hmac, (guchar *)challenge, strlen(challenge));
			diglen = purple_cipher_digest_to_str(hmac, digest, 33);
			g_object_unref(hmac);
			g_object_unref(md5);

			g_return_if_fail(diglen > 0);

			/* Create the response query */
			iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
			query = purple_xmlnode_get_child(iq->node, "query");

			x = purple_xmlnode_new_child(query, "username");
			purple_xmlnode_insert_data(x, js->user->node, -1);
			x = purple_xmlnode_new_child(query, "resource");
			purple_xmlnode_insert_data(x, js->user->resource, -1);

			x = purple_xmlnode_new_child(query, "crammd5");

			purple_xmlnode_insert_data(x, digest, 32);

			jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
			jabber_iq_send(iq);

		} else if(purple_xmlnode_get_child(query, "password")) {
			PurpleAccount *account = purple_connection_get_account(js->gc);
			if(!jabber_stream_is_ssl(js) && !purple_account_get_bool(account,
						"auth_plain_in_clear", FALSE)) {
				char *msg = g_strdup_printf(_("%s requires plaintext authentication over an unencrypted connection.  Allow this and continue authentication?"),
											purple_account_get_username(account));
				purple_request_yes_no(js->gc, _("Plaintext Authentication"),
						_("Plaintext Authentication"),
						msg,
						1,
						purple_request_cpar_from_account(account),
						account, allow_plaintext_auth,
						disallow_plaintext_auth);
				g_free(msg);
				return;
			}
			finish_plaintext_authentication(js);
		} else {
			purple_connection_error(js->gc,
				PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
				_("Server does not use any supported authentication method"));
			return;
		}
	}
}
Esempio n. 19
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;
}