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; }
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; }
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; }