From 61a496ffcad857b0dac176861206c4a98edc1620 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 1 Mar 2001 22:23:23 +0000 Subject: Take a GByteArray as input as well. Comment that you can pass %NULL for * camel-sasl.c (camel_sasl_challenge): Take a GByteArray as input as well. Comment that you can pass %NULL for @token to get the initial auth data for mechanisms that are client-initiated. (camel_sasl_challenge_base64): Convenience function for protocols that use base64-encoded SASL. (camel_sasl_authenticated): Implement this... (it was prototyped already) (camel_sasl_new): Function to take a service name, a mechanism name, and a CamelService, and return a CamelSasl for it. (camel_sasl_authtype, camel_sasl_authtype_list): Functions to return CamelServiceAuthType information about SASL mechanisms, to allow providers to deal with them generically. * camel-sasl-anonymous.c, camel-sasl-plain.c: Update/simplify for CamelSasl changes. Both of these are single-round (client-initiated) mechanisms, so they don't need to keep state. (camel_sasl_plain_new): Removed; use camel_sasl_new instead. (Can't get rid of camel_sasl_anonymous_new though...) * camel-sasl-cram-md5.c: Update/simplify for CamelSasl changes. (camel_sasl_cram_md5_new): Removed; use camel_sasl_new instead. (cram_md5_challenge): Use md5_get_digest where possible, and various other minor simplifications. CRAM-MD5 only has a single round, so there's no need to keep track of state. This code is now tested (against Cyrus IMAPd) and known to work. * camel-sasl-kerberos4.h: Update/simplify for CamelSasl changes. Make only a single #ifdef HAVE_KRB4. Remove stuff from priv that isn't needed between rounds. (camel_sasl_kerberos4_new): Removed; use camel_sasl_new instead (krb4_challenge): Fix up the logic I broke in my previous "at least make it compile" fixes, update to match other changes, and remove IMAP-isms that shouldn't be in the generic code. This still isn't tested, because we're stuck behind a NAT right now... svn path=/trunk/; revision=8462 --- camel/camel-sasl.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 164 insertions(+), 11 deletions(-) (limited to 'camel/camel-sasl.c') diff --git a/camel/camel-sasl.c b/camel/camel-sasl.c index a5aebe737c..1e7fc9108c 100644 --- a/camel/camel-sasl.c +++ b/camel/camel-sasl.c @@ -22,13 +22,19 @@ #include #include "camel-sasl.h" +#include "camel-mime-utils.h" +#include "camel-service.h" + +#include "camel-sasl-cram-md5.h" +#include "camel-sasl-kerberos4.h" +#include "camel-sasl-plain.h" static CamelObjectClass *parent_class = NULL; /* Returns the class for a CamelSasl */ #define CS_CLASS(so) CAMEL_SASL_CLASS (CAMEL_OBJECT_GET_CLASS (so)) -static GByteArray *sasl_challenge (CamelSasl *sasl, const char *token, CamelException *ex); +static GByteArray *sasl_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex); static void camel_sasl_class_init (CamelSaslClass *camel_sasl_class) @@ -39,6 +45,13 @@ camel_sasl_class_init (CamelSaslClass *camel_sasl_class) camel_sasl_class->challenge = sasl_challenge; } +static void +camel_sasl_finalize (CamelSasl *sasl) +{ + g_free (sasl->service_name); + camel_object_unref (CAMEL_OBJECT (sasl->service)); +} + CamelType camel_sasl_get_type (void) { @@ -52,7 +65,7 @@ camel_sasl_get_type (void) (CamelObjectClassInitFunc) camel_sasl_class_init, NULL, NULL, - NULL ); + (CamelObjectFinalizeFunc) camel_sasl_finalize); } return type; @@ -60,7 +73,7 @@ camel_sasl_get_type (void) static GByteArray * -sasl_challenge (CamelSasl *sasl, const char *token, CamelException *ex) +sasl_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex) { g_warning ("sasl_challenge: Using default implementation!"); return NULL; @@ -68,20 +81,160 @@ sasl_challenge (CamelSasl *sasl, const char *token, CamelException *ex) /** * camel_sasl_challenge: - * @sasl: a sasl object - * @token: a token + * @sasl: a SASL object + * @token: a token, or %NULL * @ex: exception * - * Generate the next sasl challenge to send to the server. + * If @token is %NULL, generate the initial SASL message to send to + * the server. (This will be %NULL if the client doesn't initiate the + * exchange.) Otherwise, @token is a challenge from the server, and + * the return value is the response. * - * Return value: a string containing the base64 encoded sasl challenge - * or NULL on either an error or if the negotiation is complete. If an - * error has occured, @ex will also be set. + * Return value: The SASL response or %NULL. If an error occurred, @ex + * will also be set. **/ GByteArray * -camel_sasl_challenge (CamelSasl *sasl, const char *token, CamelException *ex) +camel_sasl_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex) { g_return_val_if_fail (CAMEL_IS_SASL (sasl), NULL); - + return CS_CLASS (sasl)->challenge (sasl, token, ex); } + +/** + * camel_sasl_challenge_base64: + * @sasl: a SASL object + * @token: a base64-encoded token + * @ex: exception + * + * As with camel_sasl_challenge(), but the challenge @token and the + * response are both base64-encoded. + * + * Return value: As with camel_sasl_challenge(), but base64-encoded. + **/ +char * +camel_sasl_challenge_base64 (CamelSasl *sasl, const char *token, CamelException *ex) +{ + GByteArray *token_binary, *ret_binary; + char *ret; + int len; + + g_return_val_if_fail (CAMEL_IS_SASL (sasl), NULL); + + if (token) { + token_binary = g_byte_array_new (); + len = strlen (token); + g_byte_array_append (token_binary, token, len); + token_binary->len = base64_decode_simple (token_binary->data, len); + } else + token_binary = NULL; + + ret_binary = camel_sasl_challenge (sasl, token_binary, ex); + if (token_binary) + g_byte_array_free (token_binary, TRUE); + if (!ret_binary) + return NULL; + + ret = base64_encode_simple (ret_binary->data, ret_binary->len); + g_byte_array_free (ret_binary, TRUE); + + return ret; +} + +/** + * camel_sasl_authenticated: + * @sasl: a SASL object + * + * Return value: whether or not @sasl has successfully authenticated + * the user. This will be %TRUE after it returns the last needed response. + * The caller must still pass that information on to the server and verify + * that it has accepted it. + **/ +gboolean +camel_sasl_authenticated (CamelSasl *sasl) +{ + return sasl->authenticated; +} + + +/** + * camel_sasl_new: + * @service_name: the SASL service name + * @mechanism: the SASL mechanism + * @service: the CamelService that will be using this SASL + * + * Return value: a new CamelSasl for the given @service_name, + * @mechanism, and @service, or %NULL if the mechanism is not + * supported. + **/ +CamelSasl * +camel_sasl_new (const char *service_name, const char *mechanism, CamelService *service) +{ + CamelSasl *sasl; + + g_return_val_if_fail (service_name != NULL, NULL); + g_return_val_if_fail (mechanism != NULL, NULL); + g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL); + + /* We don't do ANONYMOUS here, because it's a little bit weird. */ + + if (!strcmp (mechanism, "CRAM-MD5")) + sasl = (CamelSasl *)camel_object_new (CAMEL_SASL_CRAM_MD5_TYPE); +#ifdef HAVE_KRB4 + else if (!strcmp (mechanism, "KERBEROS_V4")) + sasl = (CamelSasl *)camel_object_new (CAMEL_SASL_KERBEROS4_TYPE); +#endif + else if (!strcmp (mechanism, "PLAIN")) + sasl = (CamelSasl *)camel_object_new (CAMEL_SASL_PLAIN_TYPE); + else + return NULL; + + sasl->service_name = g_strdup (service_name); + sasl->service = service; + camel_object_ref (CAMEL_OBJECT (service)); + + return sasl; +} + +/** + * camel_sasl_authtype_list: + * + * Return value: a GList of SASL-supported authtypes. The caller must + * free the list, but not the contents. + **/ +GList * +camel_sasl_authtype_list (void) +{ + GList *types = NULL; + + /* We don't do PLAIN here, because it's considered to be + * normal password authentication, just behind SSL. + */ + + types = g_list_prepend (types, &camel_sasl_cram_md5_authtype); +#ifdef HAVE_KRB4 + types = g_list_prepend (types, &camel_sasl_kerberos4_authtype); +#endif + + return types; +} + +/** + * camel_sasl_authtype: + * @mechanism: the SASL mechanism to get an authtype for + * + * Return value: a CamelServiceAuthType for the given mechanism, if + * it is supported. + **/ +CamelServiceAuthType * +camel_sasl_authtype (const char *mechanism) +{ + if (!strcmp (mechanism, "CRAM-MD5")) + return &camel_sasl_cram_md5_authtype; +#ifdef HAVE_KRB4 + else if (!strcmp (mechanism, "KERBEROS_V4")) + return &camel_sasl_kerberos4_authtype; +#endif + else + return NULL; +} -- cgit v1.2.3