Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / camel-sasl.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Authors: Jeffrey Stedfast <fejj@ximian.com>
4  *
5  *  Copyright 2001-2003 Ximian, Inc. (www.ximian.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 2 of the GNU Lesser General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <string.h>
29
30 #include "camel-mime-utils.h"
31 #include "camel-sasl-cram-md5.h"
32 #include "camel-sasl-digest-md5.h"
33 #include "camel-sasl-gssapi.h"
34 #include "camel-sasl-kerberos4.h"
35 #include "camel-sasl-login.h"
36 #include "camel-sasl-ntlm.h"
37 #include "camel-sasl-plain.h"
38 #include "camel-sasl-popb4smtp.h"
39 #include "camel-sasl.h"
40 #include "camel-service.h"
41
42
43 #define w(x)
44
45 static CamelObjectClass *parent_class = NULL;
46
47 /* Returns the class for a CamelSasl */
48 #define CS_CLASS(so) CAMEL_SASL_CLASS (CAMEL_OBJECT_GET_CLASS (so))
49
50 static GByteArray *sasl_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex);
51
52 static void
53 camel_sasl_class_init (CamelSaslClass *camel_sasl_class)
54 {
55         parent_class = camel_type_get_global_classfuncs (CAMEL_OBJECT_TYPE);
56         
57         /* virtual method definition */
58         camel_sasl_class->challenge = sasl_challenge;
59 }
60
61 static void
62 camel_sasl_finalize (CamelSasl *sasl)
63 {
64         g_free (sasl->service_name);
65         g_free (sasl->mech);
66         camel_object_unref (sasl->service);
67 }
68
69 CamelType
70 camel_sasl_get_type (void)
71 {
72         static CamelType type = CAMEL_INVALID_TYPE;
73         
74         if (type == CAMEL_INVALID_TYPE) {
75                 type = camel_type_register (CAMEL_OBJECT_TYPE,
76                                             "CamelSasl",
77                                             sizeof (CamelSasl),
78                                             sizeof (CamelSaslClass),
79                                             (CamelObjectClassInitFunc) camel_sasl_class_init,
80                                             NULL,
81                                             NULL,
82                                             (CamelObjectFinalizeFunc) camel_sasl_finalize);
83         }
84         
85         return type;
86 }
87
88
89 static GByteArray *
90 sasl_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
91 {
92         w(g_warning ("sasl_challenge: Using default implementation!"));
93         return NULL;
94 }
95
96 /**
97  * camel_sasl_challenge:
98  * @sasl: a #CamelSasl object
99  * @token: a token, or %NULL
100  * @ex: a #CamelException
101  *
102  * If @token is %NULL, generate the initial SASL message to send to
103  * the server. (This will be %NULL if the client doesn't initiate the
104  * exchange.) Otherwise, @token is a challenge from the server, and
105  * the return value is the response.
106  *
107  * Returns the SASL response or %NULL. If an error occurred, @ex will
108  * also be set.
109  **/
110 GByteArray *
111 camel_sasl_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
112 {
113         g_return_val_if_fail (CAMEL_IS_SASL (sasl), NULL);
114         
115         return CS_CLASS (sasl)->challenge (sasl, token, ex);
116 }
117
118 /**
119  * camel_sasl_challenge_base64:
120  * @sasl: a #CamelSasl object
121  * @token: a base64-encoded token
122  * @ex: a #CamelException
123  *
124  * As with #camel_sasl_challenge, but the challenge @token and the
125  * response are both base64-encoded.
126  *
127  * Returns the base64 encoded challenge string
128  **/
129 char *
130 camel_sasl_challenge_base64 (CamelSasl *sasl, const char *token, CamelException *ex)
131 {
132         GByteArray *token_binary, *ret_binary;
133         char *ret;
134         int len;
135         
136         g_return_val_if_fail (CAMEL_IS_SASL (sasl), NULL);
137         
138         if (token) {
139                 token_binary = g_byte_array_new ();
140                 len = strlen (token);
141                 g_byte_array_append (token_binary, token, len);
142                 token_binary->len = camel_base64_decode_simple (token_binary->data, len);
143         } else
144                 token_binary = NULL;
145         
146         ret_binary = camel_sasl_challenge (sasl, token_binary, ex);
147         if (token_binary)
148                 g_byte_array_free (token_binary, TRUE);
149         if (!ret_binary)
150                 return NULL;
151         
152         ret = camel_base64_encode_simple (ret_binary->data, ret_binary->len);
153         g_byte_array_free (ret_binary, TRUE);
154
155         return ret;
156 }
157
158 /**
159  * camel_sasl_authenticated:
160  * @sasl: a #CamelSasl object
161  *
162  * Returns whether or not @sasl has successfully authenticated the
163  * user. This will be %TRUE after it returns the last needed response.
164  * The caller must still pass that information on to the server and
165  * verify that it has accepted it.
166  **/
167 gboolean
168 camel_sasl_authenticated (CamelSasl *sasl)
169 {
170         return sasl->authenticated;
171 }
172
173
174 /**
175  * camel_sasl_new:
176  * @service_name: the SASL service name
177  * @mechanism: the SASL mechanism
178  * @service: the CamelService that will be using this SASL
179  *
180  * Returns a new #CamelSasl object for the given @service_name,
181  * @mechanism, and @service, or %NULL if the mechanism is not
182  * supported.
183  **/
184 CamelSasl *
185 camel_sasl_new (const char *service_name, const char *mechanism, CamelService *service)
186 {
187         CamelSasl *sasl;
188         
189         g_return_val_if_fail (service_name != NULL, NULL);
190         g_return_val_if_fail (mechanism != NULL, NULL);
191         g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
192         
193         /* We don't do ANONYMOUS here, because it's a little bit weird. */
194         
195         if (!strcmp (mechanism, "CRAM-MD5"))
196                 sasl = (CamelSasl *) camel_object_new (CAMEL_SASL_CRAM_MD5_TYPE);
197         else if (!strcmp (mechanism, "DIGEST-MD5"))
198                 sasl = (CamelSasl *) camel_object_new (CAMEL_SASL_DIGEST_MD5_TYPE);
199 #ifdef HAVE_KRB5
200         else if (!strcmp (mechanism, "GSSAPI"))
201                 sasl = (CamelSasl *) camel_object_new (CAMEL_SASL_GSSAPI_TYPE);
202 #endif
203 #ifdef HAVE_KRB4
204         else if (!strcmp (mechanism, "KERBEROS_V4"))
205                 sasl = (CamelSasl *) camel_object_new (CAMEL_SASL_KERBEROS4_TYPE);
206 #endif
207         else if (!strcmp (mechanism, "PLAIN"))
208                 sasl = (CamelSasl *) camel_object_new (CAMEL_SASL_PLAIN_TYPE);
209         else if (!strcmp (mechanism, "LOGIN"))
210                 sasl = (CamelSasl *) camel_object_new (CAMEL_SASL_LOGIN_TYPE);
211         else if (!strcmp (mechanism, "POPB4SMTP"))
212                 sasl = (CamelSasl *) camel_object_new (CAMEL_SASL_POPB4SMTP_TYPE);
213         else if (!strcmp (mechanism, "NTLM"))
214                 sasl = (CamelSasl *) camel_object_new (CAMEL_SASL_NTLM_TYPE);
215         else
216                 return NULL;
217
218         sasl->mech = g_strdup (mechanism);
219         sasl->service_name = g_strdup (service_name);
220         sasl->service = service;
221         camel_object_ref (service);
222         
223         return sasl;
224 }
225
226 /**
227  * camel_sasl_authtype_list:
228  * @include_plain: whether or not to include the PLAIN mechanism
229  *
230  * Returns a #GList of SASL-supported authtypes. The caller must
231  * free the list, but not the contents.
232  **/
233 GList *
234 camel_sasl_authtype_list (gboolean include_plain)
235 {
236         GList *types = NULL;
237         
238         types = g_list_prepend (types, &camel_sasl_cram_md5_authtype);
239         types = g_list_prepend (types, &camel_sasl_digest_md5_authtype);
240 #ifdef HAVE_KRB5
241         types = g_list_prepend (types, &camel_sasl_gssapi_authtype);
242 #endif
243 #ifdef HAVE_KRB4
244         types = g_list_prepend (types, &camel_sasl_kerberos4_authtype);
245 #endif
246         types = g_list_prepend (types, &camel_sasl_ntlm_authtype);
247         if (include_plain)
248                 types = g_list_prepend (types, &camel_sasl_plain_authtype);
249         
250         return types;
251 }
252
253 /**
254  * camel_sasl_authtype:
255  * @mechanism: the SASL mechanism to get an authtype for
256  *
257  * Returns a #CamelServiceAuthType for the given mechanism, if
258  * it is supported.
259  **/
260 CamelServiceAuthType *
261 camel_sasl_authtype (const char *mechanism)
262 {
263         if (!strcmp (mechanism, "CRAM-MD5"))
264                 return &camel_sasl_cram_md5_authtype;
265         else if (!strcmp (mechanism, "DIGEST-MD5"))
266                 return &camel_sasl_digest_md5_authtype;
267 #ifdef HAVE_KRB5
268         else if (!strcmp (mechanism, "GSSAPI"))
269                 return &camel_sasl_gssapi_authtype;
270 #endif
271 #ifdef HAVE_KRB4
272         else if (!strcmp (mechanism, "KERBEROS_V4"))
273                 return &camel_sasl_kerberos4_authtype;
274 #endif
275         else if (!strcmp (mechanism, "PLAIN"))
276                 return &camel_sasl_plain_authtype;
277         else if (!strcmp (mechanism, "LOGIN"))
278                 return &camel_sasl_login_authtype;
279         else if (!strcmp(mechanism, "POPB4SMTP"))
280                 return &camel_sasl_popb4smtp_authtype;
281         else if (!strcmp (mechanism, "NTLM"))
282                 return &camel_sasl_ntlm_authtype;
283         else
284                 return NULL;
285 }