コード例 #1
0
static CamelAuthenticationResult
smtp_transport_authenticate_sync (CamelService *service,
                                  const gchar *mechanism,
                                  GCancellable *cancellable,
                                  GError **error)
{
	CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
	CamelAuthenticationResult result;
	CamelSasl *sasl;
	gchar *cmdbuf, *respbuf = NULL, *challenge;
	gboolean auth_challenge = FALSE;
	GError *local_error = NULL;

	if (mechanism == NULL) {
		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
			_("No SASL mechanism was specified"));
		return CAMEL_AUTHENTICATION_ERROR;
	}

	sasl = camel_sasl_new ("smtp", mechanism, service);
	if (sasl == NULL) {
		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
			_("No support for %s authentication"), mechanism);
		return CAMEL_AUTHENTICATION_ERROR;
	}

	challenge = camel_sasl_challenge_base64_sync (
		sasl, NULL, cancellable, &local_error);
	if (challenge) {
		auth_challenge = TRUE;
		cmdbuf = g_strdup_printf (
			"AUTH %s %s\r\n", mechanism, challenge);
		g_free (challenge);
	} else if (local_error) {
		d (fprintf (stderr, "[SMTP] SASL challenge failed: %s", local_error->message));
		g_propagate_error (error, local_error);
		g_object_unref (sasl);
		return CAMEL_AUTHENTICATION_ERROR;
	} else {
		cmdbuf = g_strdup_printf (
			"AUTH %s\r\n", mechanism);
	}

	d (fprintf (stderr, "[SMTP] sending: %s", cmdbuf));
	if (camel_stream_write_string (
		transport->ostream, cmdbuf,
		cancellable, error) == -1) {
		g_free (cmdbuf);
		g_prefix_error (error, _("AUTH command failed: "));
		goto lose;
	}
	g_free (cmdbuf);

	respbuf = camel_stream_buffer_read_line (
		CAMEL_STREAM_BUFFER (transport->istream),
		cancellable, error);
	d (fprintf (stderr, "[SMTP] received: %s\n", respbuf ? respbuf : "(null)"));

	while (!camel_sasl_get_authenticated (sasl)) {
		if (!respbuf) {
			g_prefix_error (error, _("AUTH command failed: "));
			transport->connected = FALSE;
			goto lose;
		}

		/* the server may have accepted our initial response */
		if (strncmp (respbuf, "235", 3) == 0)
			break;

		/* the server challenge/response should follow a 334 code */
		if (strncmp (respbuf, "334", 3) != 0) {
			smtp_set_error (
				transport, respbuf, cancellable, error);
			g_prefix_error (error, _("AUTH command failed: "));
			goto lose;
		}

		if (FALSE) {
		broken_smtp_server:
			d (fprintf (
				stderr, "[SMTP] Your SMTP server's implementation "
				"of the %s SASL\nauthentication mechanism is "
				"broken. Please report this to the\n"
				"appropriate vendor and suggest that they "
				"re-read rfc2554 again\nfor the first time "
				"(specifically Section 4).\n",
				mechanism));
		}

		/* eat whtspc */
		for (challenge = respbuf + 4; isspace (*challenge); challenge++);

		challenge = camel_sasl_challenge_base64_sync (
			sasl, challenge, cancellable, error);
		if (challenge == NULL)
			goto break_and_lose;

		g_free (respbuf);

		/* send our challenge */
		cmdbuf = g_strdup_printf ("%s\r\n", challenge);
		g_free (challenge);
		d (fprintf (stderr, "[SMTP] sending: %s", cmdbuf));
		if (camel_stream_write_string (
			transport->ostream, cmdbuf,
			cancellable, error) == -1) {
			g_free (cmdbuf);
			goto lose;
		}
		g_free (cmdbuf);

		/* get the server's response */
		respbuf = camel_stream_buffer_read_line (
			CAMEL_STREAM_BUFFER (transport->istream),
			cancellable, error);
		d (fprintf (stderr, "[SMTP] received: %s\n", respbuf ? respbuf : "(null)"));
	}

	if (respbuf == NULL)
		goto lose;

	/* Work around broken SASL implementations. */
	if (auth_challenge && strncmp (respbuf, "334", 3) == 0)
		goto broken_smtp_server;

	/* If our authentication data was rejected, destroy the
	 * password so that the user gets prompted to try again. */
	if (strncmp (respbuf, "535", 3) == 0) {
		result = CAMEL_AUTHENTICATION_REJECTED;

		/* Read the continuation, if the server returned it. */
		while (respbuf && respbuf[3] == '-') {
			g_free (respbuf);
			respbuf = camel_stream_buffer_read_line (
				CAMEL_STREAM_BUFFER (transport->istream),
				cancellable, error);
			d (fprintf (stderr, "[SMTP] received: %s\n", respbuf ? respbuf : "(null)"));
		}
	} else if (strncmp (respbuf, "235", 3) == 0)
		result = CAMEL_AUTHENTICATION_ACCEPTED;
	/* Catch any other errors. */
	else {
		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
			_("Bad authentication response from server."));
		goto lose;
	}

	goto exit;

break_and_lose:
	/* Get the server out of "waiting for continuation data" mode. */
	d (fprintf (stderr, "[SMTP] sending: *\n"));
	camel_stream_write (transport->ostream, "*\r\n", 3, cancellable, NULL);
	respbuf = camel_stream_buffer_read_line (
		CAMEL_STREAM_BUFFER (transport->istream), cancellable, NULL);
	d (fprintf (stderr, "[SMTP] received: %s\n", respbuf ? respbuf : "(null)"));

lose:
	result = CAMEL_AUTHENTICATION_ERROR;

exit:
	g_object_unref (sasl);
	g_free (respbuf);

	return result;
}
コード例 #2
0
ファイル: camel-pop3-store.c プロジェクト: Pecisk/eds-gtasks
static CamelAuthenticationResult
try_sasl (CamelPOP3Store *store,
          const gchar *mechanism,
          GCancellable *cancellable,
          GError **error)
{
	CamelPOP3Engine *pop3_engine;
	CamelPOP3Stream *pop3_stream;
	CamelNetworkSettings *network_settings;
	CamelAuthenticationResult result;
	CamelSettings *settings;
	CamelService *service;
	guchar *line, *resp;
	CamelSasl *sasl = NULL;
	gchar *string;
	gchar *host;
	guint len;
	gint ret;

	service = CAMEL_SERVICE (store);

	settings = camel_service_ref_settings (service);

	network_settings = CAMEL_NETWORK_SETTINGS (settings);
	host = camel_network_settings_dup_host (network_settings);

	g_object_unref (settings);

	pop3_engine = camel_pop3_store_ref_engine (store);
	if (!pop3_engine) {
		g_set_error_literal (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_UNAVAILABLE,
			_("You must be working online to complete this operation"));
		result = CAMEL_AUTHENTICATION_ERROR;
		goto exit;
	}

	pop3_stream = pop3_engine->stream;

	sasl = camel_sasl_new ("pop", mechanism, service);
	if (sasl == NULL) {
		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_URL_INVALID,
			_("No support for %s authentication"), mechanism);
		result = CAMEL_AUTHENTICATION_ERROR;
		goto exit;
	}

	string = g_strdup_printf ("AUTH %s\r\n", mechanism);
	ret = camel_stream_write_string (
		CAMEL_STREAM (pop3_stream), string, cancellable, error);
	g_free (string);

	if (ret == -1)
		goto ioerror;

	while (1) {
		GError *local_error = NULL;

		if (camel_pop3_stream_line (pop3_stream, &line, &len, cancellable, error) == -1)
			goto ioerror;

		if (strncmp ((gchar *) line, "+OK", 3) == 0) {
			result = CAMEL_AUTHENTICATION_ACCEPTED;
			break;
		}

		if (strncmp ((gchar *) line, "-ERR", 4) == 0) {
			result = CAMEL_AUTHENTICATION_REJECTED;
			break;
		}

		/* If we dont get continuation, or the sasl object's run out
		 * of work, or we dont get a challenge, its a protocol error,
		 * so fail, and try reset the server. */
		if (strncmp ((gchar *) line, "+ ", 2) != 0
		    || camel_sasl_get_authenticated (sasl)
		    || (resp = (guchar *) camel_sasl_challenge_base64_sync (sasl, (const gchar *) line + 2, cancellable, &local_error)) == NULL) {
			camel_stream_write_string (
				CAMEL_STREAM (pop3_stream), "*\r\n", cancellable, NULL);
			camel_pop3_stream_line (pop3_stream, &line, &len, cancellable, NULL);

			if (local_error) {
				g_propagate_error (error, local_error);
				local_error = NULL;
				goto ioerror;
			}

			g_set_error (
				error, CAMEL_SERVICE_ERROR,
				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
				_("Cannot login to POP server %s: "
				"SASL Protocol error"), host);
			result = CAMEL_AUTHENTICATION_ERROR;
			goto exit;
		}

		string = g_strdup_printf ("%s\r\n", resp);
		ret = camel_stream_write_string (
			CAMEL_STREAM (pop3_stream), string, cancellable, error);
		g_free (string);

		g_free (resp);

		if (ret == -1)
			goto ioerror;

	}

	goto exit;

ioerror:
	g_prefix_error (
		error, _("Failed to authenticate on POP server %s: "), host);
	result = CAMEL_AUTHENTICATION_ERROR;

exit:
	if (sasl != NULL)
		g_object_unref (sasl);

	g_free (host);

	g_clear_object (&pop3_engine);

	return result;
}
コード例 #3
0
static gboolean
smtp_transport_connect_sync (CamelService *service,
                             GCancellable *cancellable,
                             GError **error)
{
	CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
	CamelNetworkSettings *network_settings;
	CamelSettings *settings;
	gchar *host;
	gchar *mechanism;
	gboolean auth_required;
	gboolean success = TRUE;

	/* Chain up to parent's method. */
	if (!CAMEL_SERVICE_CLASS (camel_smtp_transport_parent_class)->connect_sync (service, cancellable, error))
		return FALSE;

	smtp_debug_print_server_name (service, "Connecting to");

	settings = camel_service_ref_settings (service);

	network_settings = CAMEL_NETWORK_SETTINGS (settings);
	host = camel_network_settings_dup_host (network_settings);
	mechanism = camel_network_settings_dup_auth_mechanism (network_settings);

	g_object_unref (settings);

	/* We (probably) need to check popb4smtp before we connect ... */
	if (g_strcmp0 (mechanism, "POPB4SMTP") == 0) {
		GByteArray *chal;
		CamelSasl *sasl;

		sasl = camel_sasl_new ("smtp", "POPB4SMTP", service);
		chal = camel_sasl_challenge_sync (sasl, NULL, cancellable, error);
		if (chal != NULL)
			g_byte_array_free (chal, TRUE);

		if (camel_sasl_get_authenticated (sasl))
			success = connect_to_server (
				service, cancellable, error);
		else
			success = FALSE;

		g_object_unref (sasl);

		goto exit;
	}

	success = connect_to_server (service, cancellable, error);

	if (!success)
		return FALSE;

	/* check to see if AUTH is required, if so...then AUTH ourselves */
	auth_required =
		(mechanism != NULL) &&
		(transport->authtypes != NULL) &&
		(g_hash_table_size (transport->authtypes) > 0) &&
		(transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP);

	if (auth_required) {
		CamelSession *session;

		session = camel_service_ref_session (service);

		if (g_hash_table_lookup (transport->authtypes, mechanism)) {
			success = camel_session_authenticate_sync (
				session, service, mechanism,
				cancellable, error);
		} else {
			g_set_error (
				error, CAMEL_SERVICE_ERROR,
				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
				_("SMTP server %s does not support %s "
				"authentication"), host, mechanism);
			success = FALSE;
		}

		g_object_unref (session);

		if (!success)
			transport->connected = FALSE;
	}

exit:
	g_free (host);
	g_free (mechanism);

	return success;
}