xref: /illumos-gate/usr/src/lib/sasl_plugins/login/login.c (revision 7a7d534ff7d637c8673694e0ec835c590a6697e5)
12871f9cfSDan McDonald /*
22871f9cfSDan McDonald  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
32871f9cfSDan McDonald  */
42871f9cfSDan McDonald 
52871f9cfSDan McDonald /* LOGIN is a PLAIN-like authenticator, but for older deployments. */
62871f9cfSDan McDonald 
72871f9cfSDan McDonald /* Login SASL plugin
82871f9cfSDan McDonald  * Rob Siemborski (SASLv2 Conversion)
92871f9cfSDan McDonald  * contributed by Rainer Schoepf <schoepf@uni-mainz.de>
102871f9cfSDan McDonald  * based on PLAIN, by Tim Martin <tmartin@andrew.cmu.edu>
112871f9cfSDan McDonald  * $Id: login.c,v 1.25 2003/02/13 19:56:04 rjs3 Exp $
122871f9cfSDan McDonald  */
132871f9cfSDan McDonald /*
142871f9cfSDan McDonald  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
152871f9cfSDan McDonald  *
162871f9cfSDan McDonald  * Redistribution and use in source and binary forms, with or without
172871f9cfSDan McDonald  * modification, are permitted provided that the following conditions
182871f9cfSDan McDonald  * are met:
192871f9cfSDan McDonald  *
202871f9cfSDan McDonald  * 1. Redistributions of source code must retain the above copyright
212871f9cfSDan McDonald  *    notice, this list of conditions and the following disclaimer.
222871f9cfSDan McDonald  *
232871f9cfSDan McDonald  * 2. Redistributions in binary form must reproduce the above copyright
242871f9cfSDan McDonald  *    notice, this list of conditions and the following disclaimer in
252871f9cfSDan McDonald  *    the documentation and/or other materials provided with the
262871f9cfSDan McDonald  *    distribution.
272871f9cfSDan McDonald  *
282871f9cfSDan McDonald  * 3. The name "Carnegie Mellon University" must not be used to
292871f9cfSDan McDonald  *    endorse or promote products derived from this software without
302871f9cfSDan McDonald  *    prior written permission. For permission or any other legal
312871f9cfSDan McDonald  *    details, please contact
322871f9cfSDan McDonald  *      Office of Technology Transfer
332871f9cfSDan McDonald  *      Carnegie Mellon University
342871f9cfSDan McDonald  *      5000 Forbes Avenue
352871f9cfSDan McDonald  *      Pittsburgh, PA  15213-3890
362871f9cfSDan McDonald  *      (412) 268-4387, fax: (412) 268-7395
372871f9cfSDan McDonald  *      tech-transfer@andrew.cmu.edu
382871f9cfSDan McDonald  *
392871f9cfSDan McDonald  * 4. Redistributions of any form whatsoever must retain the following
402871f9cfSDan McDonald  *    acknowledgment:
412871f9cfSDan McDonald  *    "This product includes software developed by Computing Services
422871f9cfSDan McDonald  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
432871f9cfSDan McDonald  *
442871f9cfSDan McDonald  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
452871f9cfSDan McDonald  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
462871f9cfSDan McDonald  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
472871f9cfSDan McDonald  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
482871f9cfSDan McDonald  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
492871f9cfSDan McDonald  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
502871f9cfSDan McDonald  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
512871f9cfSDan McDonald  */
522871f9cfSDan McDonald 
532871f9cfSDan McDonald #include <config.h>
542871f9cfSDan McDonald #include <stdio.h>
552871f9cfSDan McDonald #include <ctype.h>
562871f9cfSDan McDonald #include <sasl.h>
572871f9cfSDan McDonald #include <saslplug.h>
582871f9cfSDan McDonald 
592871f9cfSDan McDonald #include "plugin_common.h"
602871f9cfSDan McDonald 
612871f9cfSDan McDonald #ifndef _SUN_SDK_
622871f9cfSDan McDonald #ifdef WIN32
632871f9cfSDan McDonald /* This must be after sasl.h */
642871f9cfSDan McDonald # include "saslLOGIN.h"
652871f9cfSDan McDonald #endif /* WIN32 */
662871f9cfSDan McDonald #endif /* !_SUN_SDK_ */
672871f9cfSDan McDonald 
682871f9cfSDan McDonald /*****************************  Common Section  *****************************/
692871f9cfSDan McDonald 
702871f9cfSDan McDonald #ifndef _SUN_SDK_
712871f9cfSDan McDonald static const char plugin_id[] = "$Id: login.c,v 1.25 2003/02/13 19:56:04 rjs3 Exp $";
722871f9cfSDan McDonald #endif /* !_SUN_SDK_ */
732871f9cfSDan McDonald 
742871f9cfSDan McDonald /*****************************  Server Section  *****************************/
752871f9cfSDan McDonald 
762871f9cfSDan McDonald typedef struct context {
772871f9cfSDan McDonald     int state;
782871f9cfSDan McDonald 
792871f9cfSDan McDonald     char *username;
802871f9cfSDan McDonald     size_t username_len;
812871f9cfSDan McDonald } server_context_t;
822871f9cfSDan McDonald 
login_server_mech_new(void * glob_context,sasl_server_params_t * sparams,const char * challenge,unsigned challen,void ** conn_context)832871f9cfSDan McDonald static int login_server_mech_new(void *glob_context __attribute__((unused)),
842871f9cfSDan McDonald 				 sasl_server_params_t *sparams,
852871f9cfSDan McDonald 				 const char *challenge __attribute__((unused)),
862871f9cfSDan McDonald 				 unsigned challen __attribute__((unused)),
872871f9cfSDan McDonald 				 void **conn_context)
882871f9cfSDan McDonald {
892871f9cfSDan McDonald     server_context_t *text;
902871f9cfSDan McDonald 
912871f9cfSDan McDonald     /* holds state are in */
922871f9cfSDan McDonald     text = sparams->utils->malloc(sizeof(server_context_t));
932871f9cfSDan McDonald     if (text == NULL) {
942871f9cfSDan McDonald 	MEMERROR( sparams->utils );
952871f9cfSDan McDonald 	return SASL_NOMEM;
962871f9cfSDan McDonald     }
972871f9cfSDan McDonald 
982871f9cfSDan McDonald     memset(text, 0, sizeof(server_context_t));
992871f9cfSDan McDonald 
1002871f9cfSDan McDonald     text->state = 1;
1012871f9cfSDan McDonald 
1022871f9cfSDan McDonald     *conn_context = text;
1032871f9cfSDan McDonald 
1042871f9cfSDan McDonald     return SASL_OK;
1052871f9cfSDan McDonald }
1062871f9cfSDan McDonald 
1072871f9cfSDan McDonald #define USERNAME_CHALLENGE "Username:"
1082871f9cfSDan McDonald #define PASSWORD_CHALLENGE "Password:"
1092871f9cfSDan McDonald 
login_server_mech_step(void * conn_context,sasl_server_params_t * params,const char * clientin,unsigned clientinlen,const char ** serverout,unsigned * serveroutlen,sasl_out_params_t * oparams)1102871f9cfSDan McDonald static int login_server_mech_step(void *conn_context,
1112871f9cfSDan McDonald 				  sasl_server_params_t *params,
1122871f9cfSDan McDonald 				  const char *clientin,
1132871f9cfSDan McDonald 				  unsigned clientinlen,
1142871f9cfSDan McDonald 				  const char **serverout,
1152871f9cfSDan McDonald 				  unsigned *serveroutlen,
1162871f9cfSDan McDonald 				  sasl_out_params_t *oparams)
1172871f9cfSDan McDonald {
1182871f9cfSDan McDonald     server_context_t *text = (server_context_t *) conn_context;
1192871f9cfSDan McDonald 
1202871f9cfSDan McDonald     *serverout = NULL;
1212871f9cfSDan McDonald     *serveroutlen = 0;
1222871f9cfSDan McDonald 
1232871f9cfSDan McDonald     switch (text->state) {
1242871f9cfSDan McDonald 
1252871f9cfSDan McDonald     case 1:
1262871f9cfSDan McDonald 	text->state = 2;
1272871f9cfSDan McDonald 
1282871f9cfSDan McDonald 	/* Check inlen, (possibly we have already the user name) */
1292871f9cfSDan McDonald 	/* In this case fall through to state 2 */
1302871f9cfSDan McDonald 	if (clientinlen == 0) {
1312871f9cfSDan McDonald 	    /* demand username */
1322871f9cfSDan McDonald 
1332871f9cfSDan McDonald 	    *serveroutlen = strlen(USERNAME_CHALLENGE);
1342871f9cfSDan McDonald 	    *serverout = USERNAME_CHALLENGE;
1352871f9cfSDan McDonald 
1362871f9cfSDan McDonald 	    return SASL_CONTINUE;
1372871f9cfSDan McDonald 	}
138*7a7d534fSToomas Soome 	/* FALLTHROUGH */
1392871f9cfSDan McDonald 
1402871f9cfSDan McDonald     case 2:
1412871f9cfSDan McDonald 	/* Catch really long usernames */
1422871f9cfSDan McDonald 	if (clientinlen > 1024) {
1432871f9cfSDan McDonald #ifdef _SUN_SDK_
1442871f9cfSDan McDonald 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
1452871f9cfSDan McDonald 		"username too long (>1024 characters)");
1462871f9cfSDan McDonald #else
1472871f9cfSDan McDonald 	    SETERROR(params->utils, "username too long (>1024 characters)");
1482871f9cfSDan McDonald #endif	/* _SUN_SDK_ */
1492871f9cfSDan McDonald 	    return SASL_BADPROT;
1502871f9cfSDan McDonald 	}
1512871f9cfSDan McDonald 
1522871f9cfSDan McDonald 	/* get username */
1532871f9cfSDan McDonald 	text->username =
1542871f9cfSDan McDonald 	    params->utils->malloc(sizeof(sasl_secret_t) + clientinlen + 1);
1552871f9cfSDan McDonald 	if (!text->username) {
1562871f9cfSDan McDonald 	    MEMERROR( params->utils );
1572871f9cfSDan McDonald 	    return SASL_NOMEM;
1582871f9cfSDan McDonald 	}
1592871f9cfSDan McDonald 
1602871f9cfSDan McDonald 	strncpy(text->username, clientin, clientinlen);
1612871f9cfSDan McDonald 	text->username_len = clientinlen;
1622871f9cfSDan McDonald 	text->username[clientinlen] = '\0';
1632871f9cfSDan McDonald 
1642871f9cfSDan McDonald 	/* demand password */
1652871f9cfSDan McDonald 	*serveroutlen = strlen(PASSWORD_CHALLENGE);
1662871f9cfSDan McDonald 	*serverout = PASSWORD_CHALLENGE;
1672871f9cfSDan McDonald 
1682871f9cfSDan McDonald 	text->state = 3;
1692871f9cfSDan McDonald 
1702871f9cfSDan McDonald 	return SASL_CONTINUE;
1712871f9cfSDan McDonald 
1722871f9cfSDan McDonald 
1732871f9cfSDan McDonald     case 3: {
1742871f9cfSDan McDonald 	sasl_secret_t *password;
1752871f9cfSDan McDonald 	int result;
1762871f9cfSDan McDonald 
1772871f9cfSDan McDonald 	/* Catch really long passwords */
1782871f9cfSDan McDonald 	if (clientinlen > 1024) {
1792871f9cfSDan McDonald #ifdef _SUN_SDK_
1802871f9cfSDan McDonald 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
1812871f9cfSDan McDonald 		     "clientinlen is > 1024 characters in LOGIN plugin");
1822871f9cfSDan McDonald #else
1832871f9cfSDan McDonald 	    SETERROR(params->utils,
1842871f9cfSDan McDonald 		     "clientinlen is > 1024 characters in LOGIN plugin");
1852871f9cfSDan McDonald #endif	/* _SUN_SDK_ */
1862871f9cfSDan McDonald 	    return SASL_BADPROT;
1872871f9cfSDan McDonald 	}
1882871f9cfSDan McDonald 
1892871f9cfSDan McDonald 	/* get password */
1902871f9cfSDan McDonald 	password =
1912871f9cfSDan McDonald 	    params->utils->malloc(sizeof(sasl_secret_t) + clientinlen + 1);
1922871f9cfSDan McDonald 	if (!password) {
1932871f9cfSDan McDonald 	    MEMERROR(params->utils);
1942871f9cfSDan McDonald 	    return SASL_NOMEM;
1952871f9cfSDan McDonald 	}
1962871f9cfSDan McDonald 
1972871f9cfSDan McDonald 	strncpy((char *)password->data, clientin, clientinlen);
1982871f9cfSDan McDonald 	password->data[clientinlen] = '\0';
1992871f9cfSDan McDonald 	password->len = clientinlen;
2002871f9cfSDan McDonald 
2012871f9cfSDan McDonald 	/* canonicalize username first, so that password verification is
2022871f9cfSDan McDonald 	 * done against the canonical id */
2032871f9cfSDan McDonald 	result = params->canon_user(params->utils->conn, text->username,
2042871f9cfSDan McDonald 				    text->username_len,
2052871f9cfSDan McDonald 				    SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
2062871f9cfSDan McDonald 	if (result != SASL_OK) {
2072871f9cfSDan McDonald 		_plug_free_secret(params->utils, &password);
2082871f9cfSDan McDonald 		return result;
2092871f9cfSDan McDonald 	}
2102871f9cfSDan McDonald 
2112871f9cfSDan McDonald 	/* verify_password - return sasl_ok on success */
2122871f9cfSDan McDonald 	result = params->utils->checkpass(params->utils->conn,
2132871f9cfSDan McDonald 					oparams->authid, oparams->alen,
2142871f9cfSDan McDonald 					(char *)password->data, password->len);
2152871f9cfSDan McDonald 
2162871f9cfSDan McDonald 	if (result != SASL_OK) {
2172871f9cfSDan McDonald 	    _plug_free_secret(params->utils, &password);
2182871f9cfSDan McDonald 	    return result;
2192871f9cfSDan McDonald 	}
2202871f9cfSDan McDonald 
2212871f9cfSDan McDonald 	if (params->transition) {
2222871f9cfSDan McDonald 	    params->transition(params->utils->conn,
2232871f9cfSDan McDonald 			       (char *)password->data, password->len);
2242871f9cfSDan McDonald 	}
2252871f9cfSDan McDonald 
2262871f9cfSDan McDonald 	_plug_free_secret(params->utils, &password);
2272871f9cfSDan McDonald 
2282871f9cfSDan McDonald 	*serverout = NULL;
2292871f9cfSDan McDonald 	*serveroutlen = 0;
2302871f9cfSDan McDonald 
2312871f9cfSDan McDonald 	oparams->doneflag = 1;
2322871f9cfSDan McDonald 	oparams->mech_ssf = 0;
2332871f9cfSDan McDonald 	oparams->maxoutbuf = 0;
2342871f9cfSDan McDonald 	oparams->encode_context = NULL;
2352871f9cfSDan McDonald 	oparams->encode = NULL;
2362871f9cfSDan McDonald 	oparams->decode_context = NULL;
2372871f9cfSDan McDonald 	oparams->decode = NULL;
2382871f9cfSDan McDonald 	oparams->param_version = 0;
2392871f9cfSDan McDonald 
2402871f9cfSDan McDonald 	return SASL_OK;
2412871f9cfSDan McDonald     }
2422871f9cfSDan McDonald 
2432871f9cfSDan McDonald 
2442871f9cfSDan McDonald     default:
2452871f9cfSDan McDonald 	params->utils->log(NULL, SASL_LOG_ERR,
2462871f9cfSDan McDonald 			   "Invalid LOGIN server step %d\n", text->state);
2472871f9cfSDan McDonald 	return SASL_FAIL;
2482871f9cfSDan McDonald     }
2492871f9cfSDan McDonald 
2502871f9cfSDan McDonald     return SASL_FAIL; /* should never get here */
2512871f9cfSDan McDonald }
2522871f9cfSDan McDonald 
login_server_mech_dispose(void * conn_context,const sasl_utils_t * utils)2532871f9cfSDan McDonald static void login_server_mech_dispose(void *conn_context,
2542871f9cfSDan McDonald 				      const sasl_utils_t *utils)
2552871f9cfSDan McDonald {
2562871f9cfSDan McDonald     server_context_t *text = (server_context_t *) conn_context;
2572871f9cfSDan McDonald 
2582871f9cfSDan McDonald     if (!text) return;
2592871f9cfSDan McDonald 
2602871f9cfSDan McDonald     if (text->username) utils->free(text->username);
2612871f9cfSDan McDonald 
2622871f9cfSDan McDonald     utils->free(text);
2632871f9cfSDan McDonald }
2642871f9cfSDan McDonald 
2652871f9cfSDan McDonald static sasl_server_plug_t login_server_plugins[] =
2662871f9cfSDan McDonald {
2672871f9cfSDan McDonald     {
2682871f9cfSDan McDonald 	"LOGIN",			/* mech_name */
2692871f9cfSDan McDonald 	0,				/* max_ssf */
2702871f9cfSDan McDonald 	SASL_SEC_NOANONYMOUS,		/* security_flags */
2712871f9cfSDan McDonald 	0,				/* features */
2722871f9cfSDan McDonald 	NULL,				/* glob_context */
2732871f9cfSDan McDonald 	&login_server_mech_new,		/* mech_new */
2742871f9cfSDan McDonald 	&login_server_mech_step,	/* mech_step */
2752871f9cfSDan McDonald 	&login_server_mech_dispose,	/* mech_dispose */
2762871f9cfSDan McDonald 	NULL,				/* mech_free */
2772871f9cfSDan McDonald 	NULL,				/* setpass */
2782871f9cfSDan McDonald 	NULL,				/* user_query */
2792871f9cfSDan McDonald 	NULL,				/* idle */
2802871f9cfSDan McDonald 	NULL,				/* mech_avail */
2812871f9cfSDan McDonald 	NULL				/* spare */
2822871f9cfSDan McDonald     }
2832871f9cfSDan McDonald };
2842871f9cfSDan McDonald 
login_server_plug_init(sasl_utils_t * utils,int maxversion,int * out_version,sasl_server_plug_t ** pluglist,int * plugcount)2852871f9cfSDan McDonald int login_server_plug_init(sasl_utils_t *utils,
2862871f9cfSDan McDonald 			   int maxversion,
2872871f9cfSDan McDonald 			   int *out_version,
2882871f9cfSDan McDonald 			   sasl_server_plug_t **pluglist,
2892871f9cfSDan McDonald 			   int *plugcount)
2902871f9cfSDan McDonald {
2912871f9cfSDan McDonald     if (maxversion < SASL_SERVER_PLUG_VERSION) {
2922871f9cfSDan McDonald 	SETERROR(utils, "LOGIN version mismatch");
2932871f9cfSDan McDonald 	return SASL_BADVERS;
2942871f9cfSDan McDonald     }
2952871f9cfSDan McDonald 
2962871f9cfSDan McDonald     *out_version = SASL_SERVER_PLUG_VERSION;
2972871f9cfSDan McDonald     *pluglist = login_server_plugins;
2982871f9cfSDan McDonald     *plugcount = 1;
2992871f9cfSDan McDonald 
3002871f9cfSDan McDonald     return SASL_OK;
3012871f9cfSDan McDonald }
3022871f9cfSDan McDonald 
3032871f9cfSDan McDonald /*****************************  Client Section  *****************************/
3042871f9cfSDan McDonald 
3052871f9cfSDan McDonald typedef struct client_context {
3062871f9cfSDan McDonald     int state;
3072871f9cfSDan McDonald 
3082871f9cfSDan McDonald #ifdef _INTEGRATED_SOLARIS_
3092871f9cfSDan McDonald     void *h;
3102871f9cfSDan McDonald #endif /* _INTEGRATED_SOLARIS_ */
3112871f9cfSDan McDonald     sasl_secret_t *password;
3122871f9cfSDan McDonald     unsigned int free_password; /* set if we need to free password */
3132871f9cfSDan McDonald } client_context_t;
3142871f9cfSDan McDonald 
login_client_mech_new(void * glob_context,sasl_client_params_t * params,void ** conn_context)3152871f9cfSDan McDonald static int login_client_mech_new(void *glob_context __attribute__((unused)),
3162871f9cfSDan McDonald 				 sasl_client_params_t *params,
3172871f9cfSDan McDonald 				 void **conn_context)
3182871f9cfSDan McDonald {
3192871f9cfSDan McDonald     client_context_t *text;
3202871f9cfSDan McDonald 
3212871f9cfSDan McDonald     /* holds state are in */
3222871f9cfSDan McDonald     text = params->utils->malloc(sizeof(client_context_t));
3232871f9cfSDan McDonald     if (text == NULL) {
3242871f9cfSDan McDonald 	MEMERROR(params->utils);
3252871f9cfSDan McDonald 	return SASL_NOMEM;
3262871f9cfSDan McDonald     }
3272871f9cfSDan McDonald 
3282871f9cfSDan McDonald     memset(text, 0, sizeof(client_context_t));
3292871f9cfSDan McDonald 
3302871f9cfSDan McDonald     text->state = 1;
3312871f9cfSDan McDonald 
3322871f9cfSDan McDonald     *conn_context = text;
3332871f9cfSDan McDonald 
3342871f9cfSDan McDonald     return SASL_OK;
3352871f9cfSDan McDonald }
3362871f9cfSDan McDonald 
login_client_mech_step(void * conn_context,sasl_client_params_t * params,const char * serverin,unsigned serverinlen,sasl_interact_t ** prompt_need,const char ** clientout,unsigned * clientoutlen,sasl_out_params_t * oparams)3372871f9cfSDan McDonald static int login_client_mech_step(void *conn_context,
3382871f9cfSDan McDonald 				  sasl_client_params_t *params,
3392871f9cfSDan McDonald 				  const char *serverin __attribute__((unused)),
3402871f9cfSDan McDonald 				  unsigned serverinlen __attribute__((unused)),
3412871f9cfSDan McDonald 				  sasl_interact_t **prompt_need,
3422871f9cfSDan McDonald 				  const char **clientout,
3432871f9cfSDan McDonald 				  unsigned *clientoutlen,
3442871f9cfSDan McDonald 				  sasl_out_params_t *oparams)
3452871f9cfSDan McDonald {
3462871f9cfSDan McDonald     client_context_t *text = (client_context_t *) conn_context;
3472871f9cfSDan McDonald 
3482871f9cfSDan McDonald     *clientout = NULL;
3492871f9cfSDan McDonald     *clientoutlen = 0;
3502871f9cfSDan McDonald 
3512871f9cfSDan McDonald     switch (text->state) {
3522871f9cfSDan McDonald 
3532871f9cfSDan McDonald     case 1: {
3542871f9cfSDan McDonald 	const char *user;
3552871f9cfSDan McDonald 	int auth_result = SASL_OK;
3562871f9cfSDan McDonald 	int pass_result = SASL_OK;
3572871f9cfSDan McDonald 	int result;
3582871f9cfSDan McDonald 
3592871f9cfSDan McDonald 	/* check if sec layer strong enough */
3602871f9cfSDan McDonald 	if (params->props.min_ssf > params->external_ssf) {
3612871f9cfSDan McDonald #ifdef _INTEGRATED_SOLARIS_
3622871f9cfSDan McDonald 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
3632871f9cfSDan McDonald 		gettext("SSF requested of LOGIN plugin"));
3642871f9cfSDan McDonald #else
3652871f9cfSDan McDonald 	    SETERROR( params->utils, "SSF requested of LOGIN plugin");
3662871f9cfSDan McDonald #endif /* _INTEGRATED_SOLARIS_ */
3672871f9cfSDan McDonald 	    return SASL_TOOWEAK;
3682871f9cfSDan McDonald 	}
3692871f9cfSDan McDonald 
3702871f9cfSDan McDonald 	/* try to get the userid */
3712871f9cfSDan McDonald 	/* Note: we want to grab the authname and not the userid, which is
3722871f9cfSDan McDonald 	 *       who we AUTHORIZE as, and will be the same as the authname
3732871f9cfSDan McDonald 	 *       for the LOGIN mech.
3742871f9cfSDan McDonald 	 */
3752871f9cfSDan McDonald 	if (oparams->user == NULL) {
3762871f9cfSDan McDonald 	    auth_result = _plug_get_authid(params->utils, &user, prompt_need);
3772871f9cfSDan McDonald 
3782871f9cfSDan McDonald 	    if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
3792871f9cfSDan McDonald 		return auth_result;
3802871f9cfSDan McDonald 	}
3812871f9cfSDan McDonald 
3822871f9cfSDan McDonald 	/* try to get the password */
3832871f9cfSDan McDonald 	if (text->password == NULL) {
3842871f9cfSDan McDonald 	    pass_result = _plug_get_password(params->utils, &text->password,
3852871f9cfSDan McDonald 					     &text->free_password, prompt_need);
3862871f9cfSDan McDonald 
3872871f9cfSDan McDonald 	    if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
3882871f9cfSDan McDonald 		return pass_result;
3892871f9cfSDan McDonald 	}
3902871f9cfSDan McDonald 
3912871f9cfSDan McDonald 	/* free prompts we got */
3922871f9cfSDan McDonald 	if (prompt_need && *prompt_need) {
3932871f9cfSDan McDonald 	    params->utils->free(*prompt_need);
3942871f9cfSDan McDonald 	    *prompt_need = NULL;
3952871f9cfSDan McDonald 	}
3962871f9cfSDan McDonald 
3972871f9cfSDan McDonald 	/* if there are prompts not filled in */
3982871f9cfSDan McDonald 	if ((auth_result == SASL_INTERACT) || (pass_result == SASL_INTERACT)) {
3992871f9cfSDan McDonald 	    /* make the prompt list */
4002871f9cfSDan McDonald 	    result =
4012871f9cfSDan McDonald #ifdef _INTEGRATED_SOLARIS_
4022871f9cfSDan McDonald 		_plug_make_prompts(params->utils, &text->h, prompt_need,
4032871f9cfSDan McDonald 		    NULL, NULL,
4042871f9cfSDan McDonald 		    auth_result == SASL_INTERACT ?
4052871f9cfSDan McDonald 		    gettext("Please enter your authentication name") : NULL,
4062871f9cfSDan McDonald 		    NULL,
4072871f9cfSDan McDonald 		    pass_result == SASL_INTERACT ?
4082871f9cfSDan McDonald 		    gettext("Please enter your password") : NULL, NULL,
4092871f9cfSDan McDonald 		    NULL, NULL, NULL,
4102871f9cfSDan McDonald 		    NULL, NULL, NULL);
4112871f9cfSDan McDonald #else
4122871f9cfSDan McDonald 		_plug_make_prompts(params->utils, prompt_need,
4132871f9cfSDan McDonald 				   NULL, NULL,
4142871f9cfSDan McDonald 				   auth_result == SASL_INTERACT ?
4152871f9cfSDan McDonald 				   "Please enter your authentication name" : NULL,
4162871f9cfSDan McDonald 				   NULL,
4172871f9cfSDan McDonald 				   pass_result == SASL_INTERACT ?
4182871f9cfSDan McDonald 				   "Please enter your password" : NULL, NULL,
4192871f9cfSDan McDonald 				   NULL, NULL, NULL,
4202871f9cfSDan McDonald 				   NULL, NULL, NULL);
4212871f9cfSDan McDonald #endif /* _INTEGRATED_SOLARIS_ */
4222871f9cfSDan McDonald 	    if (result != SASL_OK) return result;
4232871f9cfSDan McDonald 
4242871f9cfSDan McDonald 	    return SASL_INTERACT;
4252871f9cfSDan McDonald 	}
4262871f9cfSDan McDonald 
4272871f9cfSDan McDonald 	if (!text->password) {
4282871f9cfSDan McDonald 	    PARAMERROR(params->utils);
4292871f9cfSDan McDonald 	    return SASL_BADPARAM;
4302871f9cfSDan McDonald 	}
4312871f9cfSDan McDonald 
4322871f9cfSDan McDonald 	result = params->canon_user(params->utils->conn, user, 0,
4332871f9cfSDan McDonald 				    SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
4342871f9cfSDan McDonald 	if (result != SASL_OK) return result;
4352871f9cfSDan McDonald 
4362871f9cfSDan McDonald 	/* server should have sent request for username - we ignore it */
4372871f9cfSDan McDonald 	if (!serverin) {
4382871f9cfSDan McDonald #ifdef _SUN_SDK_
4392871f9cfSDan McDonald 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
4402871f9cfSDan McDonald 		      "Server didn't issue challenge for USERNAME");
4412871f9cfSDan McDonald #else
4422871f9cfSDan McDonald 	    SETERROR( params->utils,
4432871f9cfSDan McDonald 		      "Server didn't issue challenge for USERNAME");
4442871f9cfSDan McDonald #endif /* _SUN_SDK_ */
4452871f9cfSDan McDonald 	    return SASL_BADPROT;
4462871f9cfSDan McDonald 	}
4472871f9cfSDan McDonald 
4482871f9cfSDan McDonald 	if (!clientout) {
4492871f9cfSDan McDonald 	    PARAMERROR( params->utils );
4502871f9cfSDan McDonald 	    return SASL_BADPARAM;
4512871f9cfSDan McDonald 	}
4522871f9cfSDan McDonald 
4532871f9cfSDan McDonald 	if (clientoutlen) *clientoutlen = oparams->alen;
4542871f9cfSDan McDonald 	*clientout = oparams->authid;
4552871f9cfSDan McDonald 
4562871f9cfSDan McDonald 	text->state = 2;
4572871f9cfSDan McDonald 
4582871f9cfSDan McDonald 	return SASL_CONTINUE;
4592871f9cfSDan McDonald     }
4602871f9cfSDan McDonald 
4612871f9cfSDan McDonald     case 2:
4622871f9cfSDan McDonald 	/* server should have sent request for password - we ignore it */
4632871f9cfSDan McDonald 	if (!serverin) {
4642871f9cfSDan McDonald #ifdef _SUN_SDK_
4652871f9cfSDan McDonald 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
4662871f9cfSDan McDonald 		      "Server didn't issue challenge for PASSWORD");
4672871f9cfSDan McDonald #else
4682871f9cfSDan McDonald 	    SETERROR( params->utils,
4692871f9cfSDan McDonald 		      "Server didn't issue challenge for PASSWORD");
4702871f9cfSDan McDonald #endif /* _SUN_SDK_ */
4712871f9cfSDan McDonald 	    return SASL_BADPROT;
4722871f9cfSDan McDonald 	}
4732871f9cfSDan McDonald 
4742871f9cfSDan McDonald 	if (!clientout) {
4752871f9cfSDan McDonald 	    PARAMERROR(params->utils);
4762871f9cfSDan McDonald 	    return SASL_BADPARAM;
4772871f9cfSDan McDonald 	}
4782871f9cfSDan McDonald 
4792871f9cfSDan McDonald 	if (clientoutlen) *clientoutlen = text->password->len;
4802871f9cfSDan McDonald 	*clientout = (char *)text->password->data;
4812871f9cfSDan McDonald 
4822871f9cfSDan McDonald 	/* set oparams */
4832871f9cfSDan McDonald 	oparams->doneflag = 1;
4842871f9cfSDan McDonald 	oparams->mech_ssf = 0;
4852871f9cfSDan McDonald 	oparams->maxoutbuf = 0;
4862871f9cfSDan McDonald 	oparams->encode_context = NULL;
4872871f9cfSDan McDonald 	oparams->encode = NULL;
4882871f9cfSDan McDonald 	oparams->decode_context = NULL;
4892871f9cfSDan McDonald 	oparams->decode = NULL;
4902871f9cfSDan McDonald 	oparams->param_version = 0;
4912871f9cfSDan McDonald 
4922871f9cfSDan McDonald 	return SASL_OK;
4932871f9cfSDan McDonald 
4942871f9cfSDan McDonald     default:
4952871f9cfSDan McDonald 	params->utils->log(NULL, SASL_LOG_ERR,
4962871f9cfSDan McDonald 			   "Invalid LOGIN client step %d\n", text->state);
4972871f9cfSDan McDonald 	return SASL_FAIL;
4982871f9cfSDan McDonald     }
4992871f9cfSDan McDonald 
5002871f9cfSDan McDonald     return SASL_FAIL; /* should never get here */
5012871f9cfSDan McDonald }
5022871f9cfSDan McDonald 
login_client_mech_dispose(void * conn_context,const sasl_utils_t * utils)5032871f9cfSDan McDonald static void login_client_mech_dispose(void *conn_context,
5042871f9cfSDan McDonald 				      const sasl_utils_t *utils)
5052871f9cfSDan McDonald {
5062871f9cfSDan McDonald     client_context_t *text = (client_context_t *) conn_context;
5072871f9cfSDan McDonald 
5082871f9cfSDan McDonald     if (!text) return;
5092871f9cfSDan McDonald 
5102871f9cfSDan McDonald     /* free sensitive info */
5112871f9cfSDan McDonald     if (text->free_password) _plug_free_secret(utils, &(text->password));
5122871f9cfSDan McDonald #ifdef _INTEGRATED_SOLARIS_
5132871f9cfSDan McDonald     convert_prompt(utils, &text->h, NULL);
5142871f9cfSDan McDonald #endif /* _INTEGRATED_SOLARIS_ */
5152871f9cfSDan McDonald 
5162871f9cfSDan McDonald     utils->free(text);
5172871f9cfSDan McDonald }
5182871f9cfSDan McDonald 
5192871f9cfSDan McDonald static sasl_client_plug_t login_client_plugins[] =
5202871f9cfSDan McDonald {
5212871f9cfSDan McDonald     {
5222871f9cfSDan McDonald 	"LOGIN",			/* mech_name */
5232871f9cfSDan McDonald 	0,				/* max_ssf */
5242871f9cfSDan McDonald 	SASL_SEC_NOANONYMOUS,		/* security_flags */
5252871f9cfSDan McDonald 	SASL_FEAT_SERVER_FIRST,		/* features */
5262871f9cfSDan McDonald 	NULL,				/* required_prompts */
5272871f9cfSDan McDonald 	NULL,				/* glob_context */
5282871f9cfSDan McDonald 	&login_client_mech_new,		/* mech_new */
5292871f9cfSDan McDonald 	&login_client_mech_step,	/* mech_step */
5302871f9cfSDan McDonald 	&login_client_mech_dispose,	/* mech_dispose */
5312871f9cfSDan McDonald 	NULL,				/* mech_free */
5322871f9cfSDan McDonald 	NULL,				/* idle */
5332871f9cfSDan McDonald 	NULL,				/* spare */
5342871f9cfSDan McDonald 	NULL				/* spare */
5352871f9cfSDan McDonald     }
5362871f9cfSDan McDonald };
5372871f9cfSDan McDonald 
login_client_plug_init(sasl_utils_t * utils,int maxversion,int * out_version,sasl_client_plug_t ** pluglist,int * plugcount)5382871f9cfSDan McDonald int login_client_plug_init(sasl_utils_t *utils,
5392871f9cfSDan McDonald 			   int maxversion,
5402871f9cfSDan McDonald 			   int *out_version,
5412871f9cfSDan McDonald 			   sasl_client_plug_t **pluglist,
5422871f9cfSDan McDonald 			   int *plugcount)
5432871f9cfSDan McDonald {
5442871f9cfSDan McDonald     if (maxversion < SASL_CLIENT_PLUG_VERSION) {
5452871f9cfSDan McDonald 	SETERROR(utils, "Version mismatch in LOGIN");
5462871f9cfSDan McDonald 	return SASL_BADVERS;
5472871f9cfSDan McDonald     }
5482871f9cfSDan McDonald 
5492871f9cfSDan McDonald     *out_version = SASL_CLIENT_PLUG_VERSION;
5502871f9cfSDan McDonald     *pluglist = login_client_plugins;
5512871f9cfSDan McDonald     *plugcount = 1;
5522871f9cfSDan McDonald 
5532871f9cfSDan McDonald     return SASL_OK;
5542871f9cfSDan McDonald }
555