Exemplo n.º 1
0
static void
auth_old_pass_cb(PurpleConnection *gc, PurpleRequestFields *fields)
{
	PurpleAccount *account;
	JabberStream *js;
	const char *entry;
	gboolean remember;

	/* TODO: the password prompt dialog doesn't get disposed if the account disconnects */
	PURPLE_ASSERT_CONNECTION_IS_VALID(gc);

	account = purple_connection_get_account(gc);
	js = purple_connection_get_protocol_data(gc);

	entry = purple_request_fields_get_string(fields, "password");
	remember = purple_request_fields_get_bool(fields, "remember");

	if (!entry || !*entry)
	{
		purple_notify_error(account, NULL,
			_("Password is required to sign on."), NULL,
			purple_request_cpar_from_connection(gc));
		return;
	}

	if (remember)
		purple_account_set_remember_password(account, TRUE);

	purple_account_set_password(account, entry, NULL, NULL);

	/* Restart our connection */
	jabber_auth_start_old(js);
}
Exemplo n.º 2
0
static JabberSaslState
jabber_cyrus_handle_failure(JabberStream *js, xmlnode *packet,
                            xmlnode **reply, char **error)
{
	if (js->auth_fail_count++ < 5) {
		if (js->current_mech && *js->current_mech) {
			char *pos;
			if ((pos = strstr(js->sasl_mechs->str, js->current_mech))) {
				g_string_erase(js->sasl_mechs, pos-js->sasl_mechs->str, strlen(js->current_mech));
			}
			/* Remove space which separated this mech from the next */
			if ((js->sasl_mechs->str)[0] == ' ') {
				g_string_erase(js->sasl_mechs, 0, 1);
			}
		}
		if (*js->sasl_mechs->str) {
			/* If we have remaining mechs to try, do so */
			sasl_dispose(&js->sasl);

			return jabber_auth_start_cyrus(js, reply, error);

		} else if ((js->auth_fail_count == 1) &&
				   (js->current_mech && g_str_equal(js->current_mech, "GSSAPI"))) {
			/* If we tried GSSAPI first, it failed, and it was the only method we had to try, try jabber:iq:auth
			 * for compatibility with iChat 10.5 Server and other jabberd based servers.
			 *
			 * iChat Server 10.5 and certain other corporate servers offer SASL GSSAPI by default, which is often
			 * not configured on the client side, and expects a fallback to jabber:iq:auth when it (predictably) fails.
			 *
			 * Note: xep-0078 points out that using jabber:iq:auth after a sasl failure is wrong. However,
			 * I believe this refers to actual authentication failure, not a simple lack of concordant mechanisms.
			 * Doing otherwise means that simply compiling with SASL support renders the client unable to connect to servers
			 * which would connect without issue otherwise. -evands
			 */
			sasl_dispose(&js->sasl);
			js->sasl = NULL;
			js->auth_mech = NULL;
			jabber_auth_start_old(js);
			return JABBER_SASL_STATE_CONTINUE;
		}
	}

	/* Nothing to send */
	return JABBER_SASL_STATE_FAIL;
}
Exemplo n.º 3
0
static JabberSaslState
jabber_auth_start_cyrus(JabberStream *js, xmlnode **reply, char **error)
{
	PurpleAccount *account;
	const char *clientout = NULL;
	char *enc_out;
	unsigned coutlen = 0;
	sasl_security_properties_t secprops;
	gboolean again;
	gboolean plaintext = TRUE;

	/* Set up security properties and options */
	secprops.min_ssf = 0;
	secprops.security_flags = SASL_SEC_NOANONYMOUS;

	account = purple_connection_get_account(js->gc);

	if (!jabber_stream_is_ssl(js)) {
		secprops.max_ssf = -1;
		secprops.maxbufsize = 4096;
		plaintext = purple_account_get_bool(account, "auth_plain_in_clear", FALSE);
		if (!plaintext)
			secprops.security_flags |= SASL_SEC_NOPLAINTEXT;
	} else {
		secprops.max_ssf = 0;
		secprops.maxbufsize = 0;
		plaintext = TRUE;
	}
	secprops.property_names = 0;
	secprops.property_values = 0;

	do {
		again = FALSE;

		js->sasl_state = sasl_client_new("xmpp", js->serverFQDN, NULL, NULL, js->sasl_cb, 0, &js->sasl);
		if (js->sasl_state==SASL_OK) {
			sasl_setprop(js->sasl, SASL_SEC_PROPS, &secprops);
			purple_debug_info("sasl", "Mechs found: %s\n", js->sasl_mechs->str);
			js->sasl_state = sasl_client_start(js->sasl, js->sasl_mechs->str, NULL, &clientout, &coutlen, &js->current_mech);
		}
		switch (js->sasl_state) {
			/* Success */
			case SASL_OK:
			case SASL_CONTINUE:
				break;
			case SASL_NOMECH:
				/* No mechanisms have offered to help */

				/* Firstly, if we don't have a password try
				 * to get one
				 */

				if (!purple_account_get_password(account)) {
					purple_account_request_password(account, G_CALLBACK(auth_pass_cb), G_CALLBACK(auth_no_pass_cb), js->gc);
					return JABBER_SASL_STATE_CONTINUE;

				/* If we've got a password, but aren't sending
				 * it in plaintext, see if we can turn on
				 * plaintext auth
				 */
				/* XXX Should we just check for PLAIN/LOGIN being offered mechanisms? */
				} else if (!plaintext) {
					char *msg = g_strdup_printf(_("%s may require 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, account, NULL, NULL, account,
							allow_cyrus_plaintext_auth,
							disallow_plaintext_auth);
					g_free(msg);
					return JABBER_SASL_STATE_CONTINUE;

				} else
					js->auth_fail_count++;

				if (js->auth_fail_count == 1 &&
					(js->sasl_mechs->str && g_str_equal(js->sasl_mechs->str, "GSSAPI"))) {
					/* If we tried GSSAPI first, it failed, and it was the only method we had to try, try jabber:iq:auth
					 * for compatibility with iChat 10.5 Server and other jabberd based servers.
					 *
					 * iChat Server 10.5 and certain other corporate servers offer SASL GSSAPI by default, which is often
					 * not configured on the client side, and expects a fallback to jabber:iq:auth when it (predictably) fails.
					 *
					 * Note: xep-0078 points out that using jabber:iq:auth after a sasl failure is wrong. However,
					 * I believe this refers to actual authentication failure, not a simple lack of concordant mechanisms.
					 * Doing otherwise means that simply compiling with SASL support renders the client unable to connect to servers
					 * which would connect without issue otherwise. -evands
					 */
					js->auth_mech = NULL;
					jabber_auth_start_old(js);
					return JABBER_SASL_STATE_CONTINUE;
				}

				break;

				/* Fatal errors. Give up and go home */
			case SASL_BADPARAM:
			case SASL_NOMEM:
				*error = g_strdup(_("SASL authentication failed"));
				break;

				/* For everything else, fail the mechanism and try again */
			default:
				purple_debug_info("sasl", "sasl_state is %d, failing the mech and trying again\n", js->sasl_state);

				js->auth_fail_count++;

				/*
				 * DAA: is this right?
				 * The manpage says that "mech" will contain the chosen mechanism on success.
				 * Presumably, if we get here that isn't the case and we shouldn't try again?
				 * I suspect that this never happens.
				 */
				/*
				 * SXW: Yes, this is right. What this handles is the situation where a
				 * mechanism, say GSSAPI, is tried. If that mechanism fails, it may be
				 * due to mechanism specific issues, so we want to try one of the other
				 * supported mechanisms. This code handles that case
				 */
				if (js->current_mech && *js->current_mech) {
					char *pos;
					if ((pos = strstr(js->sasl_mechs->str, js->current_mech))) {
						g_string_erase(js->sasl_mechs, pos-js->sasl_mechs->str, strlen(js->current_mech));
					}
					/* Remove space which separated this mech from the next */
					if ((js->sasl_mechs->str)[0] == ' ') {
						g_string_erase(js->sasl_mechs, 0, 1);
					}
					again = TRUE;
				}

				sasl_dispose(&js->sasl);
		}
	} while (again);

	if (js->sasl_state == SASL_CONTINUE || js->sasl_state == SASL_OK) {
		xmlnode *auth = xmlnode_new("auth");
		xmlnode_set_namespace(auth, NS_XMPP_SASL);
		xmlnode_set_attrib(auth, "mechanism", js->current_mech);

		xmlnode_set_attrib(auth, "xmlns:ga", "http://www.google.com/talk/protocol/auth");
		xmlnode_set_attrib(auth, "ga:client-uses-full-bind-result", "true");

		if (clientout) {
			if (coutlen == 0) {
				xmlnode_insert_data(auth, "=", -1);
			} else {
				enc_out = purple_base64_encode((unsigned char*)clientout, coutlen);
				xmlnode_insert_data(auth, enc_out, -1);
				g_free(enc_out);
			}
		}

		*reply = auth;
		return JABBER_SASL_STATE_CONTINUE;
	} else {
		return JABBER_SASL_STATE_FAIL;
	}
}