Initial release, version 0.0.0.
[gsasl.git] / lib / plain.c
blob970c83c8b5bc8783f69241d30ef0d89fdffe7276
1 /* plain.c implementation of SASL mechanism PLAIN as defined in RFC 2595
2 * Copyright (C) 2002 Simon Josefsson
4 * This file is part of libgsasl.
6 * Libgsasl is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * Libgsasl 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 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with libgsasl; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "internal.h"
24 #ifdef USE_PLAIN
26 int
27 _gsasl_plain_client_init (Gsasl_ctx *ctx)
29 return GSASL_OK;
32 void
33 _gsasl_plain_client_done (Gsasl_ctx *ctx)
35 return;
38 int
39 _gsasl_plain_client_start (Gsasl_session_ctx *cctx,
40 void **mech_data)
42 Gsasl_ctx *ctx;
43 int *step;
45 ctx = gsasl_client_ctx_get (cctx);
46 if (ctx == NULL)
47 return GSASL_CANNOT_GET_CTX;
49 if (gsasl_client_callback_authorization_id_get (ctx) == NULL)
50 return GSASL_NEED_CLIENT_AUTHORIZATION_ID_CALLBACK;
52 if (gsasl_client_callback_authentication_id_get (ctx) == NULL)
53 return GSASL_NEED_CLIENT_AUTHENTICATION_ID_CALLBACK;
55 if (gsasl_client_callback_password_get (ctx) == NULL)
56 return GSASL_NEED_CLIENT_PASSWORD_CALLBACK;
58 step = (int*) malloc(sizeof(*step));
59 if (step == NULL)
60 return GSASL_MALLOC_ERROR;
62 *step = 0;
64 *mech_data = step;
66 return GSASL_OK;
69 int
70 _gsasl_plain_client_step (Gsasl_session_ctx *cctx,
71 void *mech_data,
72 const char *input,
73 size_t input_len,
74 char *output,
75 size_t *output_len)
77 int *step = mech_data;
78 Gsasl_client_callback_authentication_id cb_authentication_id;
79 Gsasl_client_callback_authorization_id cb_authorization_id;
80 Gsasl_client_callback_password cb_password;
81 Gsasl_ctx *ctx;
82 char *tmp, *tmp2;
83 size_t len;
84 int res;
86 if (*step > 0)
87 return GSASL_OK;
89 ctx = gsasl_client_ctx_get (cctx);
90 if (ctx == NULL)
91 return GSASL_CANNOT_GET_CTX;
93 cb_authorization_id = gsasl_client_callback_authorization_id_get (ctx);
94 if (cb_authorization_id == NULL)
95 return GSASL_NEED_CLIENT_AUTHORIZATION_ID_CALLBACK;
97 cb_authentication_id = gsasl_client_callback_authentication_id_get (ctx);
98 if (cb_authentication_id == NULL)
99 return GSASL_NEED_CLIENT_AUTHENTICATION_ID_CALLBACK;
101 cb_password = gsasl_client_callback_password_get (ctx);
102 if (cb_password == NULL)
103 return GSASL_NEED_CLIENT_PASSWORD_CALLBACK;
105 tmp = output;
107 len = *output_len - (tmp - output);
108 res = cb_authorization_id (cctx, tmp, &len);
109 if (res != GSASL_OK)
110 return res;
111 tmp2 = gsasl_utf8_nfkc_normalize (tmp, len);
112 if (tmp2 == NULL)
113 return GSASL_UNICODE_NORMALIZATION_ERROR;
114 if (*output_len <= tmp - output + strlen(tmp2))
115 return GSASL_TOO_SMALL_BUFFER;
116 memcpy(tmp, tmp2, strlen(tmp2));
117 tmp += strlen(tmp2);
118 free(tmp2);
119 *tmp++ = '\0';
121 len = *output_len - (tmp - output);
122 res = cb_authentication_id (cctx, tmp, &len);
123 if (res != GSASL_OK)
124 return res;
125 tmp2 = gsasl_utf8_nfkc_normalize (tmp, len);
126 if (tmp2 == NULL)
127 return GSASL_UNICODE_NORMALIZATION_ERROR;
128 if (*output_len <= tmp - output + strlen(tmp2))
129 return GSASL_TOO_SMALL_BUFFER;
130 memcpy(tmp, tmp2, strlen(tmp2));
131 tmp += strlen(tmp2);
132 free(tmp2);
133 *tmp++ = '\0';
135 len = *output_len - (tmp - output);
136 res = cb_password (cctx, tmp, &len);
137 if (res != GSASL_OK)
138 return res;
139 tmp2 = gsasl_utf8_nfkc_normalize (tmp, len);
140 if (tmp2 == NULL)
141 return GSASL_UNICODE_NORMALIZATION_ERROR;
142 if (*output_len <= tmp - output + strlen(tmp2))
143 return GSASL_TOO_SMALL_BUFFER;
144 memcpy(tmp, tmp2, strlen(tmp2));
145 tmp += strlen(tmp2);
146 free(tmp2);
148 *output_len = tmp - output;
150 (*step)++;
152 return GSASL_NEEDS_MORE;
156 _gsasl_plain_client_finish (Gsasl_session_ctx *cctx,
157 void *mech_data)
159 int *step = mech_data;
161 free(step);
163 return GSASL_OK;
166 /* Server */
169 _gsasl_plain_server_init (Gsasl_ctx *ctx)
171 return GSASL_OK;
174 void
175 _gsasl_plain_server_done (Gsasl_ctx *ctx)
177 return;
181 _gsasl_plain_server_start (Gsasl_session_ctx *sctx,
182 void **mech_data)
184 Gsasl_ctx *ctx;
186 ctx = gsasl_server_ctx_get (sctx);
187 if (ctx == NULL)
188 return GSASL_CANNOT_GET_CTX;
190 if (gsasl_server_callback_validate_get (ctx) == NULL &&
191 gsasl_server_callback_retrieve_get (ctx) == NULL)
192 return GSASL_NEED_SERVER_VALIDATE_CALLBACK;
194 return GSASL_OK;
198 _gsasl_plain_server_step (Gsasl_session_ctx *sctx,
199 void *mech_data,
200 const char *input,
201 size_t input_len,
202 char *output,
203 size_t *output_len)
205 Gsasl_server_callback_validate cb_validate;
206 Gsasl_server_callback_retrieve cb_retrieve;
207 char *authorization_id = NULL;
208 char *authentication_id = NULL;
209 char *passwordptr = NULL;
210 char *password = NULL;
211 Gsasl_ctx *ctx;
212 int res;
214 if (input_len == 0)
216 *output_len = 0;
217 return GSASL_NEEDS_MORE;
220 authorization_id = input;
221 authentication_id = memchr(input, 0, input_len);
222 if (authentication_id)
224 authentication_id++;
225 passwordptr = memchr(authentication_id, 0,
226 input_len - strlen(authorization_id) - 1);
227 if (passwordptr != NULL)
228 passwordptr++;
231 if (passwordptr == NULL)
232 return GSASL_MECHANISM_PARSE_ERROR;
234 password = malloc(input_len - (passwordptr - input) + 1);
235 if (password == NULL)
236 return GSASL_MALLOC_ERROR;
237 memcpy(password, passwordptr, input_len - (passwordptr - input));
238 password[input_len - (passwordptr - input)] = '\0';
240 ctx = gsasl_server_ctx_get (sctx);
241 if (ctx == NULL)
242 return GSASL_CANNOT_GET_CTX;
244 cb_validate = gsasl_server_callback_validate_get (ctx);
245 cb_retrieve = gsasl_server_callback_retrieve_get (ctx);
246 if (cb_validate == NULL && cb_retrieve == NULL)
247 return GSASL_NEED_SERVER_VALIDATE_CALLBACK;
249 if (cb_validate)
251 res = cb_validate(sctx, authorization_id, authentication_id, password);
253 else
255 size_t keylen;
256 char *key;
257 char *normkey;
259 res = cb_retrieve(sctx, authentication_id, authorization_id, NULL,
260 NULL, &keylen);
261 if (res != GSASL_OK)
262 return res;
263 key = malloc(keylen);
264 if (key == NULL)
265 return GSASL_MALLOC_ERROR;
266 res = cb_retrieve(sctx, authentication_id, authorization_id, NULL,
267 key, &keylen);
268 if (res != GSASL_OK)
270 free(key);
271 return res;
273 normkey = gsasl_utf8_nfkc_normalize (key, keylen);
274 free(key);
275 if (normkey == NULL)
277 free(normkey);
278 return GSASL_UNICODE_NORMALIZATION_ERROR;
280 if (strlen(password) == strlen(normkey) &&
281 memcmp(normkey, password, strlen(normkey)) == 0)
282 res = GSASL_OK;
283 else
284 res = GSASL_AUTHENTICATION_ERROR;
285 free(normkey);
288 return res;
292 _gsasl_plain_server_finish (Gsasl_session_ctx *sctx,
293 void *mech_data)
295 return GSASL_OK;
298 #endif /* USE_PLAIN */