Contents
Camel.SASL
CamelSasl is an abstract base class for representing Secure Authentication and Security Layer objects.
In CamelSasl, only the secure authentication part of SASL is implemented.
It allows for various 'pluggable' authentication mechanisms to be added to connection-based sessions. It works by providing a challenge-response sequence through a controlling object, which may be invoked multiple times until it has authenticated. Other non-SASL authentication mechanisms which fit the same challenge-response design are also wrapped inside CamelSasl objects to simplify their use.
CamelSasl is used by Evolution/Camel.Store and Evolution/Camel.Transport implementations where appropriate.
Base class
This object will always be sub-classed for use, but it provides a few publically readable fields for each implementation to use, and each user to access if they wish.
struct _CamelSasl { CamelObject parent_object; char *service_name; char *mech; CamelService *service; gboolean authenticated; };
The class itself only has a single virtual method which implementors must override. The challenge and response data is passed as raw binary using GByteArrays.
struct _CamelSaslClass { CamelObjectClass parent_class; GByteArray *(*challenge)(CamelSasl *sasl, GByteArray *token, CamelException *ex); };
A factory method is used to create each instance of a SASL object. This way, each user of a SASL authentication mechanism only needs to access the base camel-sasl class. This has a hard-coded list of 'plugins' for each SASL type (i.e. they are not pluggable, but could be with a little bit of effort). It will initialise the public fields as appropriate, also see the API documentation.
CamelSasl *camel_sasl_new(const char *service_name, const char *mechanism, CamelService *service);
The normal client interfaces to the SASL object are then the challenge call and authenticated accessor. As a convenience to most backends in which the challenge-response is passed as base64 encoded data rather than raw binary, challenge_base64 will perform this conversion automatically.
GByteArray *camel_sasl_challenge(CamelSasl *sasl, GByteArray *token, CamelException *ex); char *camel_sasl_challenge_base64(CamelSasl *sasl, const char *token, CamelException *ex); gboolean camel_sasl_authenticated(CamelSasl *sasl);
And finally, there are a couple of static methods which are used to build the authtype-list for Evolution/Camel.Service objects and Evolution/Camel.Provider descriptions. They can also be used by client code to query display information about the auth types.
GList *camel_sasl_authtype_list(gboolean include_plain); CamelServiceAuthType *camel_sasl_authtype(const char *mechanism);
Camel.SASLAnonymous
The Anonymous SASL mechanism isn't handled by the camel_sasl_new sasl method, because it needs some other special arguments.
typedef enum { CAMEL_SASL_ANON_TRACE_EMAIL, CAMEL_SASL_ANON_TRACE_OPAQUE, CAMEL_SASL_ANON_TRACE_EMPTY } CamelSaslAnonTraceType; CamelSasl *camel_sasl_anonymous_new(CamelSaslAnonTraceType type, const char *trace_info);
Refer to the #RFCs for more information.
Example: IMAP SASL authentication loop
The full details of the implementation depends a lot on the driving code, but the following is how a SASL authentication mechanism might be implemented in a hypothetical synchronous IMAP implementation.
static gboolean try_auth(CamelImapStore *store, const char *mech, CamelException *ex) { CamelSasl *sasl; CamelImapResponse *response; int ok = FALSE; sasl = camel_sasl_new("imap", mech, (CamelService *)store); if (sasl == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Uknown authentication mechanism: %s"), mech); return FALSE; } response = camel_imap_command(store, NULL, ex, "AUTHENTICATE %s", mech); if (camel_exception_is_set(ex)) goto fail; while (!camel_sasl_authenticated(sasl)) { char *sasl_resp; sasl_resp = camel_sasl_challenge_base64(sasl, imap_parse_word(response), ex); if (camel_exception_is_set(ex)) goto fail; response = camel_imap_command_continuation(store, sasl_resp, strlen(sasl_resp), ex); g_free (sasl_resp); if (camel_exception_is_set(ex)) goto fail; } if (imap_parse_word(response)) /* Oops. SASL claims we're done, but the IMAP server is asking for more data */ goto fail; ok = TRUE; fail: camel_object_unref(sasl); return ok; }
See camel/providers/imap/camel-imap-store.c:try_auth for another working example.
But basically the process is:
# Create an appropriate CamelSasl object. # Feed it the response from an AUTHENTICATE or AUTH command. # Take the challange generated and send it to the server. # Repeat until authenticated.
Camel.SASLCRAMMD5
- mechanism: "CRAM-MD5"
This implements the CRAM-MD5 SASL mechanism, Challenge-Response Authentication Mechanism. This is a hash-based authentication mechanism using a MD5 sum of processed password and challenge data.
See #RFCs RFC-2195.
Camel.SASLDigestMD5
- mechanism: "DIGEST-MD5"
Another challenge-response SASL mechanism.
See #RFCs RFC-2831.
Camel.SASLGSSAPI
- mechamism: "GSSAPI"
A "Generic Security Service Application Program Interface" authentication mechanism.
See #RFCs RFC-2222 & RFC-2078.
Camel.SASLLogin
- mechamism: "LOGIN"
This is similar to the PLAIN authentication type, but the username and password are sent instead as two separate responses with no challenge data.
I can't find any relevent RFC for this; but it appears to be used by the SMTP backend.
Camel.SASLNTLM
- mechamism: "NTLM"
This implements a New Technology Lan Manager based challenge-response authentication mechanism/Secure Password Authentication mechanism.
This is used by some Windoze based servers. It is not specified in any internet standard.
Camel.SASLPlain
- mechanism: "PLAIN"
This implements the PLAIN authentication type. It issues a clear-text username and password response to an empty challenge, and so should only be used within authenticated sessions (TLS/SSL).
Note that this is not the same as a simple username/password IMAP or POP login, although it is just as insecure.
See #RFCs
Camel.SASLPOPB4SMTP
- mechanism: "POPB4SMTP"
This is not a proper challenge-response authentication mechanism. It is used to implement the old and fairly messy POP before SMTP authentication mechanism used by some SMTP servers to authenticate their users. These days SMTP supports proper mechanisms, so this isn't required.
The way it works is when asked for a challenge, it asks for a special 'password' against the source service of popb4smtp_uri. It is then up to the Evolution/Camel.Session implementation to intepret this password request appropriately and find the matching POP account details for this SMTP transport. It then makes a dummy connection to the POP server, returns an empty challenge response and sets the state to authenticated if it worked.
There are a few annoying ISPs out there that still use this hack, and what's worse they tried to improve on it by enforcing that the POP session remain active while the SMTP is made. Camel.SASLPOPB4SMTP does not work terribly well with such services.
Camel.SASLKerberos4
- mechamism: "KERBEROS_V4"
A Kerberos Versin 4 authentication mechanism.
See #RFCs RFC-1731.
RFCs
RFC-1731 IMAP4 Authentication Mechanisms
RFC-1734 POP3 AUTHentication command
RFC-2078 Generic Security Service Application Program Interface, Version 2
RFC-2195 IMAP/POP AUTHorise Extension for Simple Challenge/Response
RFC-2222 Simple Authentication and Security Layer (SASL)
RFC-2245 Anonymous SASL Mechanism
RFC-2554 SMTP Service Extension for Authentication
RFC-2595 Using TLS with IMAP, POP3 and ACAP
RFC-2831 Using Digest Authentication as a SASL Mechanism
RFC-3501/RFC-2060 INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1