Initial release, version 0.0.0.
[gsasl.git] / lib / login.c
blobd5a3cd16d74c49447a9c060ffbacb65c39a493b0
1 /* login.c implementation of non-standard SASL mechanism LOGIN
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_LOGIN
26 int
27 _gsasl_login_client_init (Gsasl_ctx *ctx)
29 return GSASL_OK;
32 void
33 _gsasl_login_client_done (Gsasl_ctx *ctx)
35 return;
38 int
39 _gsasl_login_client_start (Gsasl_session_ctx *cctx,
40 void **mech_data)
42 int *step;
43 Gsasl_ctx *ctx;
45 ctx = gsasl_client_ctx_get (cctx);
46 if (ctx == NULL)
47 return GSASL_CANNOT_GET_CTX;
49 if (gsasl_client_callback_authentication_id_get (ctx) == NULL)
50 return GSASL_NEED_CLIENT_AUTHENTICATION_ID_CALLBACK;
52 if (gsasl_client_callback_password_get (ctx) == NULL)
53 return GSASL_NEED_CLIENT_PASSWORD_CALLBACK;
55 step = (int*) malloc(sizeof(*step));
56 if (step == NULL)
57 return GSASL_MALLOC_ERROR;
59 *step = 0;
61 *mech_data = step;
63 return GSASL_OK;
66 int
67 _gsasl_login_client_step (Gsasl_session_ctx *cctx,
68 void *mech_data,
69 const char *input,
70 size_t input_len,
71 char *output,
72 size_t *output_len)
74 int *step = mech_data;
75 Gsasl_client_callback_authentication_id cb_authentication_id;
76 Gsasl_client_callback_password cb_password;
77 Gsasl_ctx *ctx;
78 char *tmp;
79 int res;
81 ctx = gsasl_client_ctx_get (cctx);
82 if (ctx == NULL)
83 return GSASL_CANNOT_GET_CTX;
85 cb_authentication_id = gsasl_client_callback_authentication_id_get (ctx);
86 if (cb_authentication_id == NULL)
87 return GSASL_NEED_CLIENT_AUTHENTICATION_ID_CALLBACK;
89 cb_password = gsasl_client_callback_password_get (ctx);
90 if (cb_password == NULL)
91 return GSASL_NEED_CLIENT_PASSWORD_CALLBACK;
93 switch (*step)
95 case 0:
96 if (input_len == 0)
98 *output_len = 0;
99 return GSASL_NEEDS_MORE;
101 res = cb_authentication_id (cctx, output, output_len);
102 if (res != GSASL_OK)
103 return res;
104 tmp = gsasl_utf8_nfkc_normalize (output, *output_len);
105 if (tmp == NULL)
106 return GSASL_UNICODE_NORMALIZATION_ERROR;
107 if (*output_len < strlen(tmp))
108 return GSASL_TOO_SMALL_BUFFER;
109 memcpy(output, tmp, strlen(tmp));
110 *output_len += strlen(tmp);
111 free(tmp);
112 (*step)++;
113 res = GSASL_NEEDS_MORE;
114 break;
116 case 1:
117 res = cb_password (cctx, output, output_len);
118 if (res != GSASL_OK)
119 return res;
120 tmp = gsasl_utf8_nfkc_normalize (output, *output_len);
121 if (tmp == NULL)
122 return GSASL_UNICODE_NORMALIZATION_ERROR;
123 if (*output_len < strlen(tmp))
124 return GSASL_TOO_SMALL_BUFFER;
125 memcpy(output, tmp, strlen(tmp));
126 *output_len += strlen(tmp);
127 free(tmp);
128 (*step)++;
129 res = GSASL_NEEDS_MORE;
130 break;
132 case 2:
133 res = GSASL_OK;
134 (*step)++;
135 break;
137 default:
138 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
139 break;
142 return res;
146 _gsasl_login_client_finish (Gsasl_session_ctx *cctx,
147 void *mech_data)
149 int *step = mech_data;
151 free(step);
153 return GSASL_OK;
156 /* Server */
158 struct _Gsasl_login_state {
159 int step;
160 char *username;
162 typedef struct _Gsasl_login_state _Gsasl_login_state;
164 #define CHALLENGE_USERNAME "User Name"
165 #define CHALLENGE_PASSWORD "Password"
168 _gsasl_login_server_init (Gsasl_ctx *ctx)
170 return GSASL_OK;
173 void
174 _gsasl_login_server_done (Gsasl_ctx *ctx)
176 return;
180 _gsasl_login_server_start (Gsasl_session_ctx *sctx,
181 void **mech_data)
183 _Gsasl_login_state *state;
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 state = (_Gsasl_login_state*) malloc(sizeof(*state));
195 if (state == NULL)
196 return GSASL_MALLOC_ERROR;
198 state->step = 0;
199 state->username = NULL;
201 *mech_data = state;
203 return GSASL_OK;
207 _gsasl_login_server_step (Gsasl_session_ctx *sctx,
208 void *mech_data,
209 const char *input,
210 size_t input_len,
211 char *output,
212 size_t *output_len)
214 _Gsasl_login_state *state = mech_data;
215 Gsasl_server_callback_validate cb_validate;
216 Gsasl_server_callback_retrieve cb_retrieve;
217 Gsasl_ctx *ctx;
218 char *password;
219 int res;
221 ctx = gsasl_server_ctx_get (sctx);
222 if (ctx == NULL)
223 return GSASL_CANNOT_GET_CTX;
225 cb_validate = gsasl_server_callback_validate_get (ctx);
226 cb_retrieve = gsasl_server_callback_retrieve_get (ctx);
227 if (cb_validate == NULL && cb_retrieve == NULL)
228 return GSASL_NEED_SERVER_VALIDATE_CALLBACK;
230 switch (state->step)
232 case 0:
233 if (*output_len < strlen(CHALLENGE_USERNAME))
234 return GSASL_TOO_SMALL_BUFFER;
236 memcpy(output, CHALLENGE_USERNAME, strlen(CHALLENGE_USERNAME));
237 *output_len = strlen(CHALLENGE_USERNAME);
239 state->step++;
240 res = GSASL_NEEDS_MORE;
241 break;
243 case 1:
244 if (input_len == 0)
245 return GSASL_MECHANISM_PARSE_ERROR;
247 if (*output_len < strlen(CHALLENGE_PASSWORD))
248 return GSASL_TOO_SMALL_BUFFER;
250 state->username = malloc(input_len + 1);
251 if (state->username == NULL)
252 return GSASL_MALLOC_ERROR;
254 memcpy(state->username, input, input_len);
255 state->username[input_len] = '\0';
257 memcpy(output, CHALLENGE_PASSWORD, strlen(CHALLENGE_PASSWORD));
258 *output_len = strlen(CHALLENGE_PASSWORD);
260 state->step++;
261 res = GSASL_NEEDS_MORE;
262 break;
264 case 2:
265 if (input_len == 0)
266 return GSASL_MECHANISM_PARSE_ERROR;
268 password = malloc(input_len + 1);
269 if (password == NULL)
270 return GSASL_MALLOC_ERROR;
272 memcpy(password, input, input_len);
273 password[input_len] = '\0';
275 if (cb_validate)
277 res = cb_validate(sctx, state->username, NULL, password);
279 else
281 size_t keylen;
282 char *key;
283 char *normkey;
285 res = cb_retrieve(sctx, state->username, NULL, NULL, NULL, &keylen);
286 if (res != GSASL_OK)
287 return res;
288 key = malloc(keylen);
289 if (key == NULL)
290 return GSASL_MALLOC_ERROR;
291 res = cb_retrieve(sctx, state->username, NULL, NULL, key, &keylen);
292 if (res != GSASL_OK)
294 free(key);
295 return res;
297 normkey = gsasl_utf8_nfkc_normalize (key, keylen);
298 free(key);
299 if (normkey == NULL)
300 return GSASL_UNICODE_NORMALIZATION_ERROR;
301 if (strlen(password) == strlen(normkey) &&
302 memcmp(normkey, password, strlen(normkey)) == 0)
303 res = GSASL_OK;
304 else
305 res = GSASL_AUTHENTICATION_ERROR;
306 free(normkey);
309 free(password);
311 state->step++;
312 break;
314 default:
315 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
316 break;
319 return res;
323 _gsasl_login_server_finish (Gsasl_session_ctx *sctx,
324 void *mech_data)
326 _Gsasl_login_state *state = mech_data;
328 if (state->username)
329 free(state->username);
330 free(state);
332 return GSASL_OK;
335 #endif /* USE_LOGIN */