2 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
5 /* LOGIN is a PLAIN-like authenticator, but for older deployments. */
8 * Rob Siemborski (SASLv2 Conversion)
9 * contributed by Rainer Schoepf <schoepf@uni-mainz.de>
10 * based on PLAIN, by Tim Martin <tmartin@andrew.cmu.edu>
11 * $Id: login.c,v 1.25 2003/02/13 19:56:04 rjs3 Exp $
14 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in
25 * the documentation and/or other materials provided with the
28 * 3. The name "Carnegie Mellon University" must not be used to
29 * endorse or promote products derived from this software without
30 * prior written permission. For permission or any other legal
31 * details, please contact
32 * Office of Technology Transfer
33 * Carnegie Mellon University
35 * Pittsburgh, PA 15213-3890
36 * (412) 268-4387, fax: (412) 268-7395
37 * tech-transfer@andrew.cmu.edu
39 * 4. Redistributions of any form whatsoever must retain the following
41 * "This product includes software developed by Computing Services
42 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
44 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
45 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
46 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
47 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
48 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
49 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
50 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
59 #include "plugin_common.h"
63 /* This must be after sasl.h */
64 # include "saslLOGIN.h"
66 #endif /* !_SUN_SDK_ */
68 /***************************** Common Section *****************************/
71 static const char plugin_id
[] = "$Id: login.c,v 1.25 2003/02/13 19:56:04 rjs3 Exp $";
72 #endif /* !_SUN_SDK_ */
74 /***************************** Server Section *****************************/
76 typedef struct context
{
83 static int login_server_mech_new(void *glob_context
__attribute__((unused
)),
84 sasl_server_params_t
*sparams
,
85 const char *challenge
__attribute__((unused
)),
86 unsigned challen
__attribute__((unused
)),
89 server_context_t
*text
;
91 /* holds state are in */
92 text
= sparams
->utils
->malloc(sizeof(server_context_t
));
94 MEMERROR( sparams
->utils
);
98 memset(text
, 0, sizeof(server_context_t
));
102 *conn_context
= text
;
107 #define USERNAME_CHALLENGE "Username:"
108 #define PASSWORD_CHALLENGE "Password:"
110 static int login_server_mech_step(void *conn_context
,
111 sasl_server_params_t
*params
,
112 const char *clientin
,
113 unsigned clientinlen
,
114 const char **serverout
,
115 unsigned *serveroutlen
,
116 sasl_out_params_t
*oparams
)
118 server_context_t
*text
= (server_context_t
*) conn_context
;
123 switch (text
->state
) {
128 /* Check inlen, (possibly we have already the user name) */
129 /* In this case fall through to state 2 */
130 if (clientinlen
== 0) {
131 /* demand username */
133 *serveroutlen
= strlen(USERNAME_CHALLENGE
);
134 *serverout
= USERNAME_CHALLENGE
;
136 return SASL_CONTINUE
;
141 /* Catch really long usernames */
142 if (clientinlen
> 1024) {
144 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
145 "username too long (>1024 characters)");
147 SETERROR(params
->utils
, "username too long (>1024 characters)");
148 #endif /* _SUN_SDK_ */
154 params
->utils
->malloc(sizeof(sasl_secret_t
) + clientinlen
+ 1);
155 if (!text
->username
) {
156 MEMERROR( params
->utils
);
160 strncpy(text
->username
, clientin
, clientinlen
);
161 text
->username_len
= clientinlen
;
162 text
->username
[clientinlen
] = '\0';
164 /* demand password */
165 *serveroutlen
= strlen(PASSWORD_CHALLENGE
);
166 *serverout
= PASSWORD_CHALLENGE
;
170 return SASL_CONTINUE
;
174 sasl_secret_t
*password
;
177 /* Catch really long passwords */
178 if (clientinlen
> 1024) {
180 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
181 "clientinlen is > 1024 characters in LOGIN plugin");
183 SETERROR(params
->utils
,
184 "clientinlen is > 1024 characters in LOGIN plugin");
185 #endif /* _SUN_SDK_ */
191 params
->utils
->malloc(sizeof(sasl_secret_t
) + clientinlen
+ 1);
193 MEMERROR(params
->utils
);
197 strncpy((char *)password
->data
, clientin
, clientinlen
);
198 password
->data
[clientinlen
] = '\0';
199 password
->len
= clientinlen
;
201 /* canonicalize username first, so that password verification is
202 * done against the canonical id */
203 result
= params
->canon_user(params
->utils
->conn
, text
->username
,
205 SASL_CU_AUTHID
| SASL_CU_AUTHZID
, oparams
);
206 if (result
!= SASL_OK
) {
207 _plug_free_secret(params
->utils
, &password
);
211 /* verify_password - return sasl_ok on success */
212 result
= params
->utils
->checkpass(params
->utils
->conn
,
213 oparams
->authid
, oparams
->alen
,
214 (char *)password
->data
, password
->len
);
216 if (result
!= SASL_OK
) {
217 _plug_free_secret(params
->utils
, &password
);
221 if (params
->transition
) {
222 params
->transition(params
->utils
->conn
,
223 (char *)password
->data
, password
->len
);
226 _plug_free_secret(params
->utils
, &password
);
231 oparams
->doneflag
= 1;
232 oparams
->mech_ssf
= 0;
233 oparams
->maxoutbuf
= 0;
234 oparams
->encode_context
= NULL
;
235 oparams
->encode
= NULL
;
236 oparams
->decode_context
= NULL
;
237 oparams
->decode
= NULL
;
238 oparams
->param_version
= 0;
245 params
->utils
->log(NULL
, SASL_LOG_ERR
,
246 "Invalid LOGIN server step %d\n", text
->state
);
250 return SASL_FAIL
; /* should never get here */
253 static void login_server_mech_dispose(void *conn_context
,
254 const sasl_utils_t
*utils
)
256 server_context_t
*text
= (server_context_t
*) conn_context
;
260 if (text
->username
) utils
->free(text
->username
);
265 static sasl_server_plug_t login_server_plugins
[] =
268 "LOGIN", /* mech_name */
270 SASL_SEC_NOANONYMOUS
, /* security_flags */
272 NULL
, /* glob_context */
273 &login_server_mech_new
, /* mech_new */
274 &login_server_mech_step
, /* mech_step */
275 &login_server_mech_dispose
, /* mech_dispose */
276 NULL
, /* mech_free */
278 NULL
, /* user_query */
280 NULL
, /* mech_avail */
285 int login_server_plug_init(sasl_utils_t
*utils
,
288 sasl_server_plug_t
**pluglist
,
291 if (maxversion
< SASL_SERVER_PLUG_VERSION
) {
292 SETERROR(utils
, "LOGIN version mismatch");
296 *out_version
= SASL_SERVER_PLUG_VERSION
;
297 *pluglist
= login_server_plugins
;
303 /***************************** Client Section *****************************/
305 typedef struct client_context
{
308 #ifdef _INTEGRATED_SOLARIS_
310 #endif /* _INTEGRATED_SOLARIS_ */
311 sasl_secret_t
*password
;
312 unsigned int free_password
; /* set if we need to free password */
315 static int login_client_mech_new(void *glob_context
__attribute__((unused
)),
316 sasl_client_params_t
*params
,
319 client_context_t
*text
;
321 /* holds state are in */
322 text
= params
->utils
->malloc(sizeof(client_context_t
));
324 MEMERROR(params
->utils
);
328 memset(text
, 0, sizeof(client_context_t
));
332 *conn_context
= text
;
337 static int login_client_mech_step(void *conn_context
,
338 sasl_client_params_t
*params
,
339 const char *serverin
__attribute__((unused
)),
340 unsigned serverinlen
__attribute__((unused
)),
341 sasl_interact_t
**prompt_need
,
342 const char **clientout
,
343 unsigned *clientoutlen
,
344 sasl_out_params_t
*oparams
)
346 client_context_t
*text
= (client_context_t
*) conn_context
;
351 switch (text
->state
) {
355 int auth_result
= SASL_OK
;
356 int pass_result
= SASL_OK
;
359 /* check if sec layer strong enough */
360 if (params
->props
.min_ssf
> params
->external_ssf
) {
361 #ifdef _INTEGRATED_SOLARIS_
362 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
363 gettext("SSF requested of LOGIN plugin"));
365 SETERROR( params
->utils
, "SSF requested of LOGIN plugin");
366 #endif /* _INTEGRATED_SOLARIS_ */
370 /* try to get the userid */
371 /* Note: we want to grab the authname and not the userid, which is
372 * who we AUTHORIZE as, and will be the same as the authname
373 * for the LOGIN mech.
375 if (oparams
->user
== NULL
) {
376 auth_result
= _plug_get_authid(params
->utils
, &user
, prompt_need
);
378 if ((auth_result
!= SASL_OK
) && (auth_result
!= SASL_INTERACT
))
382 /* try to get the password */
383 if (text
->password
== NULL
) {
384 pass_result
= _plug_get_password(params
->utils
, &text
->password
,
385 &text
->free_password
, prompt_need
);
387 if ((pass_result
!= SASL_OK
) && (pass_result
!= SASL_INTERACT
))
391 /* free prompts we got */
392 if (prompt_need
&& *prompt_need
) {
393 params
->utils
->free(*prompt_need
);
397 /* if there are prompts not filled in */
398 if ((auth_result
== SASL_INTERACT
) || (pass_result
== SASL_INTERACT
)) {
399 /* make the prompt list */
401 #ifdef _INTEGRATED_SOLARIS_
402 _plug_make_prompts(params
->utils
, &text
->h
, prompt_need
,
404 auth_result
== SASL_INTERACT
?
405 gettext("Please enter your authentication name") : NULL
,
407 pass_result
== SASL_INTERACT
?
408 gettext("Please enter your password") : NULL
, NULL
,
412 _plug_make_prompts(params
->utils
, prompt_need
,
414 auth_result
== SASL_INTERACT
?
415 "Please enter your authentication name" : NULL
,
417 pass_result
== SASL_INTERACT
?
418 "Please enter your password" : NULL
, NULL
,
421 #endif /* _INTEGRATED_SOLARIS_ */
422 if (result
!= SASL_OK
) return result
;
424 return SASL_INTERACT
;
427 if (!text
->password
) {
428 PARAMERROR(params
->utils
);
429 return SASL_BADPARAM
;
432 result
= params
->canon_user(params
->utils
->conn
, user
, 0,
433 SASL_CU_AUTHID
| SASL_CU_AUTHZID
, oparams
);
434 if (result
!= SASL_OK
) return result
;
436 /* server should have sent request for username - we ignore it */
439 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
440 "Server didn't issue challenge for USERNAME");
442 SETERROR( params
->utils
,
443 "Server didn't issue challenge for USERNAME");
444 #endif /* _SUN_SDK_ */
449 PARAMERROR( params
->utils
);
450 return SASL_BADPARAM
;
453 if (clientoutlen
) *clientoutlen
= oparams
->alen
;
454 *clientout
= oparams
->authid
;
458 return SASL_CONTINUE
;
462 /* server should have sent request for password - we ignore it */
465 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
466 "Server didn't issue challenge for PASSWORD");
468 SETERROR( params
->utils
,
469 "Server didn't issue challenge for PASSWORD");
470 #endif /* _SUN_SDK_ */
475 PARAMERROR(params
->utils
);
476 return SASL_BADPARAM
;
479 if (clientoutlen
) *clientoutlen
= text
->password
->len
;
480 *clientout
= (char *)text
->password
->data
;
483 oparams
->doneflag
= 1;
484 oparams
->mech_ssf
= 0;
485 oparams
->maxoutbuf
= 0;
486 oparams
->encode_context
= NULL
;
487 oparams
->encode
= NULL
;
488 oparams
->decode_context
= NULL
;
489 oparams
->decode
= NULL
;
490 oparams
->param_version
= 0;
495 params
->utils
->log(NULL
, SASL_LOG_ERR
,
496 "Invalid LOGIN client step %d\n", text
->state
);
500 return SASL_FAIL
; /* should never get here */
503 static void login_client_mech_dispose(void *conn_context
,
504 const sasl_utils_t
*utils
)
506 client_context_t
*text
= (client_context_t
*) conn_context
;
510 /* free sensitive info */
511 if (text
->free_password
) _plug_free_secret(utils
, &(text
->password
));
512 #ifdef _INTEGRATED_SOLARIS_
513 convert_prompt(utils
, &text
->h
, NULL
);
514 #endif /* _INTEGRATED_SOLARIS_ */
519 static sasl_client_plug_t login_client_plugins
[] =
522 "LOGIN", /* mech_name */
524 SASL_SEC_NOANONYMOUS
, /* security_flags */
525 SASL_FEAT_SERVER_FIRST
, /* features */
526 NULL
, /* required_prompts */
527 NULL
, /* glob_context */
528 &login_client_mech_new
, /* mech_new */
529 &login_client_mech_step
, /* mech_step */
530 &login_client_mech_dispose
, /* mech_dispose */
531 NULL
, /* mech_free */
538 int login_client_plug_init(sasl_utils_t
*utils
,
541 sasl_client_plug_t
**pluglist
,
544 if (maxversion
< SASL_CLIENT_PLUG_VERSION
) {
545 SETERROR(utils
, "Version mismatch in LOGIN");
549 *out_version
= SASL_CLIENT_PLUG_VERSION
;
550 *pluglist
= login_client_plugins
;