2 * Rob Siemborski (SASLv2 Conversion)
3 * contributed by Rainer Schoepf <schoepf@uni-mainz.de>
4 * based on PLAIN, by Tim Martin <tmartin@andrew.cmu.edu>
5 * $Id: login.c,v 1.27 2004/09/08 11:09:10 mel Exp $
8 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
22 * 3. The name "Carnegie Mellon University" must not be used to
23 * endorse or promote products derived from this software without
24 * prior written permission. For permission or any other legal
25 * details, please contact
26 * Office of Technology Transfer
27 * Carnegie Mellon University
29 * Pittsburgh, PA 15213-3890
30 * (412) 268-4387, fax: (412) 268-7395
31 * tech-transfer@andrew.cmu.edu
33 * 4. Redistributions of any form whatsoever must retain the following
35 * "This product includes software developed by Computing Services
36 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
38 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
39 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
40 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
41 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
42 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
43 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
44 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
53 #include "plugin_common.h"
55 /***************************** Common Section *****************************/
57 static const char plugin_id[] = "$Id: login.c,v 1.27 2004/09/08 11:09:10 mel Exp $";
59 /***************************** Server Section *****************************/
61 typedef struct context {
65 unsigned username_len;
68 static int login_server_mech_new(void *glob_context __attribute__((unused)),
69 sasl_server_params_t *sparams,
70 const char *challenge __attribute__((unused)),
71 unsigned challen __attribute__((unused)),
74 server_context_t *text;
76 /* holds state are in */
77 text = sparams->utils->malloc(sizeof(server_context_t));
79 MEMERROR( sparams->utils );
83 memset(text, 0, sizeof(server_context_t));
92 #define USERNAME_CHALLENGE "Username:"
93 #define PASSWORD_CHALLENGE "Password:"
95 static int login_server_mech_step(void *conn_context,
96 sasl_server_params_t *params,
99 const char **serverout,
100 unsigned *serveroutlen,
101 sasl_out_params_t *oparams)
103 server_context_t *text = (server_context_t *) conn_context;
108 switch (text->state) {
113 /* Check inlen, (possibly we have already the user name) */
114 /* In this case fall through to state 2 */
115 if (clientinlen == 0) {
116 /* demand username */
118 *serveroutlen = (unsigned) strlen(USERNAME_CHALLENGE);
119 *serverout = USERNAME_CHALLENGE;
121 return SASL_CONTINUE;
126 /* Catch really long usernames */
127 if (clientinlen > 1024) {
128 SETERROR(params->utils, "username too long (>1024 characters)");
134 params->utils->malloc(sizeof(sasl_secret_t) + clientinlen + 1);
135 if (!text->username) {
136 MEMERROR( params->utils );
140 strncpy(text->username, clientin, clientinlen);
141 text->username_len = clientinlen;
142 text->username[clientinlen] = '\0';
144 /* demand password */
145 *serveroutlen = (unsigned) strlen(PASSWORD_CHALLENGE);
146 *serverout = PASSWORD_CHALLENGE;
150 return SASL_CONTINUE;
154 sasl_secret_t *password;
157 /* Catch really long passwords */
158 if (clientinlen > 1024) {
159 SETERROR(params->utils,
160 "clientinlen is > 1024 characters in LOGIN plugin");
166 params->utils->malloc(sizeof(sasl_secret_t) + clientinlen + 1);
168 MEMERROR(params->utils);
172 strncpy(password->data, clientin, clientinlen);
173 password->data[clientinlen] = '\0';
174 password->len = clientinlen;
176 /* canonicalize username first, so that password verification is
177 * done against the canonical id */
178 result = params->canon_user(params->utils->conn, text->username,
180 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
181 if (result != SASL_OK) return result;
183 /* verify_password - return sasl_ok on success */
184 result = params->utils->checkpass(params->utils->conn,
185 oparams->authid, oparams->alen,
186 password->data, password->len);
188 if (result != SASL_OK) {
189 _plug_free_secret(params->utils, &password);
193 _plug_free_secret(params->utils, &password);
198 oparams->doneflag = 1;
199 oparams->mech_ssf = 0;
200 oparams->maxoutbuf = 0;
201 oparams->encode_context = NULL;
202 oparams->encode = NULL;
203 oparams->decode_context = NULL;
204 oparams->decode = NULL;
205 oparams->param_version = 0;
212 params->utils->log(NULL, SASL_LOG_ERR,
213 "Invalid LOGIN server step %d\n", text->state);
217 return SASL_FAIL; /* should never get here */
220 static void login_server_mech_dispose(void *conn_context,
221 const sasl_utils_t *utils)
223 server_context_t *text = (server_context_t *) conn_context;
227 if (text->username) utils->free(text->username);
232 static sasl_server_plug_t login_server_plugins[] =
235 "LOGIN", /* mech_name */
237 SASL_SEC_NOANONYMOUS, /* security_flags */
239 NULL, /* glob_context */
240 &login_server_mech_new, /* mech_new */
241 &login_server_mech_step, /* mech_step */
242 &login_server_mech_dispose, /* mech_dispose */
243 NULL, /* mech_free */
245 NULL, /* user_query */
247 NULL, /* mech_avail */
252 int login_server_plug_init(sasl_utils_t *utils,
255 sasl_server_plug_t **pluglist,
258 if (maxversion < SASL_SERVER_PLUG_VERSION) {
259 SETERROR(utils, "LOGIN version mismatch");
263 *out_version = SASL_SERVER_PLUG_VERSION;
264 *pluglist = login_server_plugins;
270 /***************************** Client Section *****************************/
272 typedef struct client_context {
275 sasl_secret_t *password;
276 unsigned int free_password; /* set if we need to free password */
279 static int login_client_mech_new(void *glob_context __attribute__((unused)),
280 sasl_client_params_t *params,
283 client_context_t *text;
285 /* holds state are in */
286 text = params->utils->malloc(sizeof(client_context_t));
288 MEMERROR(params->utils);
292 memset(text, 0, sizeof(client_context_t));
296 *conn_context = text;
301 static int login_client_mech_step(void *conn_context,
302 sasl_client_params_t *params,
303 const char *serverin __attribute__((unused)),
304 unsigned serverinlen __attribute__((unused)),
305 sasl_interact_t **prompt_need,
306 const char **clientout,
307 unsigned *clientoutlen,
308 sasl_out_params_t *oparams)
310 client_context_t *text = (client_context_t *) conn_context;
315 switch (text->state) {
319 int auth_result = SASL_OK;
320 int pass_result = SASL_OK;
323 /* check if sec layer strong enough */
324 if (params->props.min_ssf > params->external_ssf) {
325 SETERROR( params->utils, "SSF requested of LOGIN plugin");
329 /* try to get the userid */
330 /* Note: we want to grab the authname and not the userid, which is
331 * who we AUTHORIZE as, and will be the same as the authname
332 * for the LOGIN mech.
334 if (oparams->user == NULL) {
335 auth_result = _plug_get_authid(params->utils, &user, prompt_need);
337 if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
341 /* try to get the password */
342 if (text->password == NULL) {
343 pass_result = _plug_get_password(params->utils, &text->password,
344 &text->free_password, prompt_need);
346 if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
350 /* free prompts we got */
351 if (prompt_need && *prompt_need) {
352 params->utils->free(*prompt_need);
356 /* if there are prompts not filled in */
357 if ((auth_result == SASL_INTERACT) || (pass_result == SASL_INTERACT)) {
358 /* make the prompt list */
360 _plug_make_prompts(params->utils, prompt_need,
362 auth_result == SASL_INTERACT ?
363 "Please enter your authentication name" : NULL,
365 pass_result == SASL_INTERACT ?
366 "Please enter your password" : NULL, NULL,
369 if (result != SASL_OK) return result;
371 return SASL_INTERACT;
374 if (!text->password) {
375 PARAMERROR(params->utils);
376 return SASL_BADPARAM;
379 result = params->canon_user(params->utils->conn, user, 0,
380 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
381 if (result != SASL_OK) return result;
383 /* server should have sent request for username - we ignore it */
385 SETERROR( params->utils,
386 "Server didn't issue challenge for USERNAME");
391 PARAMERROR( params->utils );
392 return SASL_BADPARAM;
395 if (clientoutlen) *clientoutlen = oparams->alen;
396 *clientout = oparams->authid;
400 return SASL_CONTINUE;
404 /* server should have sent request for password - we ignore it */
406 SETERROR( params->utils,
407 "Server didn't issue challenge for PASSWORD");
412 PARAMERROR(params->utils);
413 return SASL_BADPARAM;
416 if (clientoutlen) *clientoutlen = text->password->len;
417 *clientout = text->password->data;
420 oparams->doneflag = 1;
421 oparams->mech_ssf = 0;
422 oparams->maxoutbuf = 0;
423 oparams->encode_context = NULL;
424 oparams->encode = NULL;
425 oparams->decode_context = NULL;
426 oparams->decode = NULL;
427 oparams->param_version = 0;
432 params->utils->log(NULL, SASL_LOG_ERR,
433 "Invalid LOGIN client step %d\n", text->state);
437 return SASL_FAIL; /* should never get here */
440 static void login_client_mech_dispose(void *conn_context,
441 const sasl_utils_t *utils)
443 client_context_t *text = (client_context_t *) conn_context;
447 /* free sensitive info */
448 if (text->free_password) _plug_free_secret(utils, &(text->password));
453 static sasl_client_plug_t login_client_plugins[] =
456 "LOGIN", /* mech_name */
458 SASL_SEC_NOANONYMOUS, /* security_flags */
459 SASL_FEAT_SERVER_FIRST, /* features */
460 NULL, /* required_prompts */
461 NULL, /* glob_context */
462 &login_client_mech_new, /* mech_new */
463 &login_client_mech_step, /* mech_step */
464 &login_client_mech_dispose, /* mech_dispose */
465 NULL, /* mech_free */
472 int login_client_plug_init(sasl_utils_t *utils,
475 sasl_client_plug_t **pluglist,
478 if (maxversion < SASL_CLIENT_PLUG_VERSION) {
479 SETERROR(utils, "Version mismatch in LOGIN");
483 *out_version = SASL_CLIENT_PLUG_VERSION;
484 *pluglist = login_client_plugins;