xref: /titanic_51/usr/src/lib/sasl_plugins/login/login.c (revision 2871f9cf6725277c39b2ceffac261281ef256dac)
1*2871f9cfSDan McDonald /*
2*2871f9cfSDan McDonald  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
3*2871f9cfSDan McDonald  */
4*2871f9cfSDan McDonald 
5*2871f9cfSDan McDonald /* LOGIN is a PLAIN-like authenticator, but for older deployments. */
6*2871f9cfSDan McDonald 
7*2871f9cfSDan McDonald /* Login SASL plugin
8*2871f9cfSDan McDonald  * Rob Siemborski (SASLv2 Conversion)
9*2871f9cfSDan McDonald  * contributed by Rainer Schoepf <schoepf@uni-mainz.de>
10*2871f9cfSDan McDonald  * based on PLAIN, by Tim Martin <tmartin@andrew.cmu.edu>
11*2871f9cfSDan McDonald  * $Id: login.c,v 1.25 2003/02/13 19:56:04 rjs3 Exp $
12*2871f9cfSDan McDonald  */
13*2871f9cfSDan McDonald /*
14*2871f9cfSDan McDonald  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
15*2871f9cfSDan McDonald  *
16*2871f9cfSDan McDonald  * Redistribution and use in source and binary forms, with or without
17*2871f9cfSDan McDonald  * modification, are permitted provided that the following conditions
18*2871f9cfSDan McDonald  * are met:
19*2871f9cfSDan McDonald  *
20*2871f9cfSDan McDonald  * 1. Redistributions of source code must retain the above copyright
21*2871f9cfSDan McDonald  *    notice, this list of conditions and the following disclaimer.
22*2871f9cfSDan McDonald  *
23*2871f9cfSDan McDonald  * 2. Redistributions in binary form must reproduce the above copyright
24*2871f9cfSDan McDonald  *    notice, this list of conditions and the following disclaimer in
25*2871f9cfSDan McDonald  *    the documentation and/or other materials provided with the
26*2871f9cfSDan McDonald  *    distribution.
27*2871f9cfSDan McDonald  *
28*2871f9cfSDan McDonald  * 3. The name "Carnegie Mellon University" must not be used to
29*2871f9cfSDan McDonald  *    endorse or promote products derived from this software without
30*2871f9cfSDan McDonald  *    prior written permission. For permission or any other legal
31*2871f9cfSDan McDonald  *    details, please contact
32*2871f9cfSDan McDonald  *      Office of Technology Transfer
33*2871f9cfSDan McDonald  *      Carnegie Mellon University
34*2871f9cfSDan McDonald  *      5000 Forbes Avenue
35*2871f9cfSDan McDonald  *      Pittsburgh, PA  15213-3890
36*2871f9cfSDan McDonald  *      (412) 268-4387, fax: (412) 268-7395
37*2871f9cfSDan McDonald  *      tech-transfer@andrew.cmu.edu
38*2871f9cfSDan McDonald  *
39*2871f9cfSDan McDonald  * 4. Redistributions of any form whatsoever must retain the following
40*2871f9cfSDan McDonald  *    acknowledgment:
41*2871f9cfSDan McDonald  *    "This product includes software developed by Computing Services
42*2871f9cfSDan McDonald  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
43*2871f9cfSDan McDonald  *
44*2871f9cfSDan McDonald  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
45*2871f9cfSDan McDonald  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
46*2871f9cfSDan McDonald  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
47*2871f9cfSDan McDonald  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
48*2871f9cfSDan McDonald  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
49*2871f9cfSDan McDonald  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
50*2871f9cfSDan McDonald  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
51*2871f9cfSDan McDonald  */
52*2871f9cfSDan McDonald 
53*2871f9cfSDan McDonald #include <config.h>
54*2871f9cfSDan McDonald #include <stdio.h>
55*2871f9cfSDan McDonald #include <ctype.h>
56*2871f9cfSDan McDonald #include <sasl.h>
57*2871f9cfSDan McDonald #include <saslplug.h>
58*2871f9cfSDan McDonald 
59*2871f9cfSDan McDonald #include "plugin_common.h"
60*2871f9cfSDan McDonald 
61*2871f9cfSDan McDonald #ifndef _SUN_SDK_
62*2871f9cfSDan McDonald #ifdef WIN32
63*2871f9cfSDan McDonald /* This must be after sasl.h */
64*2871f9cfSDan McDonald # include "saslLOGIN.h"
65*2871f9cfSDan McDonald #endif /* WIN32 */
66*2871f9cfSDan McDonald #endif /* !_SUN_SDK_ */
67*2871f9cfSDan McDonald 
68*2871f9cfSDan McDonald /*****************************  Common Section  *****************************/
69*2871f9cfSDan McDonald 
70*2871f9cfSDan McDonald #ifndef _SUN_SDK_
71*2871f9cfSDan McDonald static const char plugin_id[] = "$Id: login.c,v 1.25 2003/02/13 19:56:04 rjs3 Exp $";
72*2871f9cfSDan McDonald #endif /* !_SUN_SDK_ */
73*2871f9cfSDan McDonald 
74*2871f9cfSDan McDonald /*****************************  Server Section  *****************************/
75*2871f9cfSDan McDonald 
76*2871f9cfSDan McDonald typedef struct context {
77*2871f9cfSDan McDonald     int state;
78*2871f9cfSDan McDonald 
79*2871f9cfSDan McDonald     char *username;
80*2871f9cfSDan McDonald     size_t username_len;
81*2871f9cfSDan McDonald } server_context_t;
82*2871f9cfSDan McDonald 
83*2871f9cfSDan McDonald static int login_server_mech_new(void *glob_context __attribute__((unused)),
84*2871f9cfSDan McDonald 				 sasl_server_params_t *sparams,
85*2871f9cfSDan McDonald 				 const char *challenge __attribute__((unused)),
86*2871f9cfSDan McDonald 				 unsigned challen __attribute__((unused)),
87*2871f9cfSDan McDonald 				 void **conn_context)
88*2871f9cfSDan McDonald {
89*2871f9cfSDan McDonald     server_context_t *text;
90*2871f9cfSDan McDonald 
91*2871f9cfSDan McDonald     /* holds state are in */
92*2871f9cfSDan McDonald     text = sparams->utils->malloc(sizeof(server_context_t));
93*2871f9cfSDan McDonald     if (text == NULL) {
94*2871f9cfSDan McDonald 	MEMERROR( sparams->utils );
95*2871f9cfSDan McDonald 	return SASL_NOMEM;
96*2871f9cfSDan McDonald     }
97*2871f9cfSDan McDonald 
98*2871f9cfSDan McDonald     memset(text, 0, sizeof(server_context_t));
99*2871f9cfSDan McDonald 
100*2871f9cfSDan McDonald     text->state = 1;
101*2871f9cfSDan McDonald 
102*2871f9cfSDan McDonald     *conn_context = text;
103*2871f9cfSDan McDonald 
104*2871f9cfSDan McDonald     return SASL_OK;
105*2871f9cfSDan McDonald }
106*2871f9cfSDan McDonald 
107*2871f9cfSDan McDonald #define USERNAME_CHALLENGE "Username:"
108*2871f9cfSDan McDonald #define PASSWORD_CHALLENGE "Password:"
109*2871f9cfSDan McDonald 
110*2871f9cfSDan McDonald static int login_server_mech_step(void *conn_context,
111*2871f9cfSDan McDonald 				  sasl_server_params_t *params,
112*2871f9cfSDan McDonald 				  const char *clientin,
113*2871f9cfSDan McDonald 				  unsigned clientinlen,
114*2871f9cfSDan McDonald 				  const char **serverout,
115*2871f9cfSDan McDonald 				  unsigned *serveroutlen,
116*2871f9cfSDan McDonald 				  sasl_out_params_t *oparams)
117*2871f9cfSDan McDonald {
118*2871f9cfSDan McDonald     server_context_t *text = (server_context_t *) conn_context;
119*2871f9cfSDan McDonald 
120*2871f9cfSDan McDonald     *serverout = NULL;
121*2871f9cfSDan McDonald     *serveroutlen = 0;
122*2871f9cfSDan McDonald 
123*2871f9cfSDan McDonald     switch (text->state) {
124*2871f9cfSDan McDonald 
125*2871f9cfSDan McDonald     case 1:
126*2871f9cfSDan McDonald 	text->state = 2;
127*2871f9cfSDan McDonald 
128*2871f9cfSDan McDonald 	/* Check inlen, (possibly we have already the user name) */
129*2871f9cfSDan McDonald 	/* In this case fall through to state 2 */
130*2871f9cfSDan McDonald 	if (clientinlen == 0) {
131*2871f9cfSDan McDonald 	    /* demand username */
132*2871f9cfSDan McDonald 
133*2871f9cfSDan McDonald 	    *serveroutlen = strlen(USERNAME_CHALLENGE);
134*2871f9cfSDan McDonald 	    *serverout = USERNAME_CHALLENGE;
135*2871f9cfSDan McDonald 
136*2871f9cfSDan McDonald 	    return SASL_CONTINUE;
137*2871f9cfSDan McDonald 	}
138*2871f9cfSDan McDonald 
139*2871f9cfSDan McDonald 
140*2871f9cfSDan McDonald     case 2:
141*2871f9cfSDan McDonald 	/* Catch really long usernames */
142*2871f9cfSDan McDonald 	if (clientinlen > 1024) {
143*2871f9cfSDan McDonald #ifdef _SUN_SDK_
144*2871f9cfSDan McDonald 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
145*2871f9cfSDan McDonald 		"username too long (>1024 characters)");
146*2871f9cfSDan McDonald #else
147*2871f9cfSDan McDonald 	    SETERROR(params->utils, "username too long (>1024 characters)");
148*2871f9cfSDan McDonald #endif	/* _SUN_SDK_ */
149*2871f9cfSDan McDonald 	    return SASL_BADPROT;
150*2871f9cfSDan McDonald 	}
151*2871f9cfSDan McDonald 
152*2871f9cfSDan McDonald 	/* get username */
153*2871f9cfSDan McDonald 	text->username =
154*2871f9cfSDan McDonald 	    params->utils->malloc(sizeof(sasl_secret_t) + clientinlen + 1);
155*2871f9cfSDan McDonald 	if (!text->username) {
156*2871f9cfSDan McDonald 	    MEMERROR( params->utils );
157*2871f9cfSDan McDonald 	    return SASL_NOMEM;
158*2871f9cfSDan McDonald 	}
159*2871f9cfSDan McDonald 
160*2871f9cfSDan McDonald 	strncpy(text->username, clientin, clientinlen);
161*2871f9cfSDan McDonald 	text->username_len = clientinlen;
162*2871f9cfSDan McDonald 	text->username[clientinlen] = '\0';
163*2871f9cfSDan McDonald 
164*2871f9cfSDan McDonald 	/* demand password */
165*2871f9cfSDan McDonald 	*serveroutlen = strlen(PASSWORD_CHALLENGE);
166*2871f9cfSDan McDonald 	*serverout = PASSWORD_CHALLENGE;
167*2871f9cfSDan McDonald 
168*2871f9cfSDan McDonald 	text->state = 3;
169*2871f9cfSDan McDonald 
170*2871f9cfSDan McDonald 	return SASL_CONTINUE;
171*2871f9cfSDan McDonald 
172*2871f9cfSDan McDonald 
173*2871f9cfSDan McDonald     case 3: {
174*2871f9cfSDan McDonald 	sasl_secret_t *password;
175*2871f9cfSDan McDonald 	int result;
176*2871f9cfSDan McDonald 
177*2871f9cfSDan McDonald 	/* Catch really long passwords */
178*2871f9cfSDan McDonald 	if (clientinlen > 1024) {
179*2871f9cfSDan McDonald #ifdef _SUN_SDK_
180*2871f9cfSDan McDonald 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
181*2871f9cfSDan McDonald 		     "clientinlen is > 1024 characters in LOGIN plugin");
182*2871f9cfSDan McDonald #else
183*2871f9cfSDan McDonald 	    SETERROR(params->utils,
184*2871f9cfSDan McDonald 		     "clientinlen is > 1024 characters in LOGIN plugin");
185*2871f9cfSDan McDonald #endif	/* _SUN_SDK_ */
186*2871f9cfSDan McDonald 	    return SASL_BADPROT;
187*2871f9cfSDan McDonald 	}
188*2871f9cfSDan McDonald 
189*2871f9cfSDan McDonald 	/* get password */
190*2871f9cfSDan McDonald 	password =
191*2871f9cfSDan McDonald 	    params->utils->malloc(sizeof(sasl_secret_t) + clientinlen + 1);
192*2871f9cfSDan McDonald 	if (!password) {
193*2871f9cfSDan McDonald 	    MEMERROR(params->utils);
194*2871f9cfSDan McDonald 	    return SASL_NOMEM;
195*2871f9cfSDan McDonald 	}
196*2871f9cfSDan McDonald 
197*2871f9cfSDan McDonald 	strncpy((char *)password->data, clientin, clientinlen);
198*2871f9cfSDan McDonald 	password->data[clientinlen] = '\0';
199*2871f9cfSDan McDonald 	password->len = clientinlen;
200*2871f9cfSDan McDonald 
201*2871f9cfSDan McDonald 	/* canonicalize username first, so that password verification is
202*2871f9cfSDan McDonald 	 * done against the canonical id */
203*2871f9cfSDan McDonald 	result = params->canon_user(params->utils->conn, text->username,
204*2871f9cfSDan McDonald 				    text->username_len,
205*2871f9cfSDan McDonald 				    SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
206*2871f9cfSDan McDonald 	if (result != SASL_OK) {
207*2871f9cfSDan McDonald 		_plug_free_secret(params->utils, &password);
208*2871f9cfSDan McDonald 		return result;
209*2871f9cfSDan McDonald 	}
210*2871f9cfSDan McDonald 
211*2871f9cfSDan McDonald 	/* verify_password - return sasl_ok on success */
212*2871f9cfSDan McDonald 	result = params->utils->checkpass(params->utils->conn,
213*2871f9cfSDan McDonald 					oparams->authid, oparams->alen,
214*2871f9cfSDan McDonald 					(char *)password->data, password->len);
215*2871f9cfSDan McDonald 
216*2871f9cfSDan McDonald 	if (result != SASL_OK) {
217*2871f9cfSDan McDonald 	    _plug_free_secret(params->utils, &password);
218*2871f9cfSDan McDonald 	    return result;
219*2871f9cfSDan McDonald 	}
220*2871f9cfSDan McDonald 
221*2871f9cfSDan McDonald 	if (params->transition) {
222*2871f9cfSDan McDonald 	    params->transition(params->utils->conn,
223*2871f9cfSDan McDonald 			       (char *)password->data, password->len);
224*2871f9cfSDan McDonald 	}
225*2871f9cfSDan McDonald 
226*2871f9cfSDan McDonald 	_plug_free_secret(params->utils, &password);
227*2871f9cfSDan McDonald 
228*2871f9cfSDan McDonald 	*serverout = NULL;
229*2871f9cfSDan McDonald 	*serveroutlen = 0;
230*2871f9cfSDan McDonald 
231*2871f9cfSDan McDonald 	oparams->doneflag = 1;
232*2871f9cfSDan McDonald 	oparams->mech_ssf = 0;
233*2871f9cfSDan McDonald 	oparams->maxoutbuf = 0;
234*2871f9cfSDan McDonald 	oparams->encode_context = NULL;
235*2871f9cfSDan McDonald 	oparams->encode = NULL;
236*2871f9cfSDan McDonald 	oparams->decode_context = NULL;
237*2871f9cfSDan McDonald 	oparams->decode = NULL;
238*2871f9cfSDan McDonald 	oparams->param_version = 0;
239*2871f9cfSDan McDonald 
240*2871f9cfSDan McDonald 	return SASL_OK;
241*2871f9cfSDan McDonald     }
242*2871f9cfSDan McDonald 
243*2871f9cfSDan McDonald 
244*2871f9cfSDan McDonald     default:
245*2871f9cfSDan McDonald 	params->utils->log(NULL, SASL_LOG_ERR,
246*2871f9cfSDan McDonald 			   "Invalid LOGIN server step %d\n", text->state);
247*2871f9cfSDan McDonald 	return SASL_FAIL;
248*2871f9cfSDan McDonald     }
249*2871f9cfSDan McDonald 
250*2871f9cfSDan McDonald     return SASL_FAIL; /* should never get here */
251*2871f9cfSDan McDonald }
252*2871f9cfSDan McDonald 
253*2871f9cfSDan McDonald static void login_server_mech_dispose(void *conn_context,
254*2871f9cfSDan McDonald 				      const sasl_utils_t *utils)
255*2871f9cfSDan McDonald {
256*2871f9cfSDan McDonald     server_context_t *text = (server_context_t *) conn_context;
257*2871f9cfSDan McDonald 
258*2871f9cfSDan McDonald     if (!text) return;
259*2871f9cfSDan McDonald 
260*2871f9cfSDan McDonald     if (text->username) utils->free(text->username);
261*2871f9cfSDan McDonald 
262*2871f9cfSDan McDonald     utils->free(text);
263*2871f9cfSDan McDonald }
264*2871f9cfSDan McDonald 
265*2871f9cfSDan McDonald static sasl_server_plug_t login_server_plugins[] =
266*2871f9cfSDan McDonald {
267*2871f9cfSDan McDonald     {
268*2871f9cfSDan McDonald 	"LOGIN",			/* mech_name */
269*2871f9cfSDan McDonald 	0,				/* max_ssf */
270*2871f9cfSDan McDonald 	SASL_SEC_NOANONYMOUS,		/* security_flags */
271*2871f9cfSDan McDonald 	0,				/* features */
272*2871f9cfSDan McDonald 	NULL,				/* glob_context */
273*2871f9cfSDan McDonald 	&login_server_mech_new,		/* mech_new */
274*2871f9cfSDan McDonald 	&login_server_mech_step,	/* mech_step */
275*2871f9cfSDan McDonald 	&login_server_mech_dispose,	/* mech_dispose */
276*2871f9cfSDan McDonald 	NULL,				/* mech_free */
277*2871f9cfSDan McDonald 	NULL,				/* setpass */
278*2871f9cfSDan McDonald 	NULL,				/* user_query */
279*2871f9cfSDan McDonald 	NULL,				/* idle */
280*2871f9cfSDan McDonald 	NULL,				/* mech_avail */
281*2871f9cfSDan McDonald 	NULL				/* spare */
282*2871f9cfSDan McDonald     }
283*2871f9cfSDan McDonald };
284*2871f9cfSDan McDonald 
285*2871f9cfSDan McDonald int login_server_plug_init(sasl_utils_t *utils,
286*2871f9cfSDan McDonald 			   int maxversion,
287*2871f9cfSDan McDonald 			   int *out_version,
288*2871f9cfSDan McDonald 			   sasl_server_plug_t **pluglist,
289*2871f9cfSDan McDonald 			   int *plugcount)
290*2871f9cfSDan McDonald {
291*2871f9cfSDan McDonald     if (maxversion < SASL_SERVER_PLUG_VERSION) {
292*2871f9cfSDan McDonald 	SETERROR(utils, "LOGIN version mismatch");
293*2871f9cfSDan McDonald 	return SASL_BADVERS;
294*2871f9cfSDan McDonald     }
295*2871f9cfSDan McDonald 
296*2871f9cfSDan McDonald     *out_version = SASL_SERVER_PLUG_VERSION;
297*2871f9cfSDan McDonald     *pluglist = login_server_plugins;
298*2871f9cfSDan McDonald     *plugcount = 1;
299*2871f9cfSDan McDonald 
300*2871f9cfSDan McDonald     return SASL_OK;
301*2871f9cfSDan McDonald }
302*2871f9cfSDan McDonald 
303*2871f9cfSDan McDonald /*****************************  Client Section  *****************************/
304*2871f9cfSDan McDonald 
305*2871f9cfSDan McDonald typedef struct client_context {
306*2871f9cfSDan McDonald     int state;
307*2871f9cfSDan McDonald 
308*2871f9cfSDan McDonald #ifdef _INTEGRATED_SOLARIS_
309*2871f9cfSDan McDonald     void *h;
310*2871f9cfSDan McDonald #endif /* _INTEGRATED_SOLARIS_ */
311*2871f9cfSDan McDonald     sasl_secret_t *password;
312*2871f9cfSDan McDonald     unsigned int free_password; /* set if we need to free password */
313*2871f9cfSDan McDonald } client_context_t;
314*2871f9cfSDan McDonald 
315*2871f9cfSDan McDonald static int login_client_mech_new(void *glob_context __attribute__((unused)),
316*2871f9cfSDan McDonald 				 sasl_client_params_t *params,
317*2871f9cfSDan McDonald 				 void **conn_context)
318*2871f9cfSDan McDonald {
319*2871f9cfSDan McDonald     client_context_t *text;
320*2871f9cfSDan McDonald 
321*2871f9cfSDan McDonald     /* holds state are in */
322*2871f9cfSDan McDonald     text = params->utils->malloc(sizeof(client_context_t));
323*2871f9cfSDan McDonald     if (text == NULL) {
324*2871f9cfSDan McDonald 	MEMERROR(params->utils);
325*2871f9cfSDan McDonald 	return SASL_NOMEM;
326*2871f9cfSDan McDonald     }
327*2871f9cfSDan McDonald 
328*2871f9cfSDan McDonald     memset(text, 0, sizeof(client_context_t));
329*2871f9cfSDan McDonald 
330*2871f9cfSDan McDonald     text->state = 1;
331*2871f9cfSDan McDonald 
332*2871f9cfSDan McDonald     *conn_context = text;
333*2871f9cfSDan McDonald 
334*2871f9cfSDan McDonald     return SASL_OK;
335*2871f9cfSDan McDonald }
336*2871f9cfSDan McDonald 
337*2871f9cfSDan McDonald static int login_client_mech_step(void *conn_context,
338*2871f9cfSDan McDonald 				  sasl_client_params_t *params,
339*2871f9cfSDan McDonald 				  const char *serverin __attribute__((unused)),
340*2871f9cfSDan McDonald 				  unsigned serverinlen __attribute__((unused)),
341*2871f9cfSDan McDonald 				  sasl_interact_t **prompt_need,
342*2871f9cfSDan McDonald 				  const char **clientout,
343*2871f9cfSDan McDonald 				  unsigned *clientoutlen,
344*2871f9cfSDan McDonald 				  sasl_out_params_t *oparams)
345*2871f9cfSDan McDonald {
346*2871f9cfSDan McDonald     client_context_t *text = (client_context_t *) conn_context;
347*2871f9cfSDan McDonald 
348*2871f9cfSDan McDonald     *clientout = NULL;
349*2871f9cfSDan McDonald     *clientoutlen = 0;
350*2871f9cfSDan McDonald 
351*2871f9cfSDan McDonald     switch (text->state) {
352*2871f9cfSDan McDonald 
353*2871f9cfSDan McDonald     case 1: {
354*2871f9cfSDan McDonald 	const char *user;
355*2871f9cfSDan McDonald 	int auth_result = SASL_OK;
356*2871f9cfSDan McDonald 	int pass_result = SASL_OK;
357*2871f9cfSDan McDonald 	int result;
358*2871f9cfSDan McDonald 
359*2871f9cfSDan McDonald 	/* check if sec layer strong enough */
360*2871f9cfSDan McDonald 	if (params->props.min_ssf > params->external_ssf) {
361*2871f9cfSDan McDonald #ifdef _INTEGRATED_SOLARIS_
362*2871f9cfSDan McDonald 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
363*2871f9cfSDan McDonald 		gettext("SSF requested of LOGIN plugin"));
364*2871f9cfSDan McDonald #else
365*2871f9cfSDan McDonald 	    SETERROR( params->utils, "SSF requested of LOGIN plugin");
366*2871f9cfSDan McDonald #endif /* _INTEGRATED_SOLARIS_ */
367*2871f9cfSDan McDonald 	    return SASL_TOOWEAK;
368*2871f9cfSDan McDonald 	}
369*2871f9cfSDan McDonald 
370*2871f9cfSDan McDonald 	/* try to get the userid */
371*2871f9cfSDan McDonald 	/* Note: we want to grab the authname and not the userid, which is
372*2871f9cfSDan McDonald 	 *       who we AUTHORIZE as, and will be the same as the authname
373*2871f9cfSDan McDonald 	 *       for the LOGIN mech.
374*2871f9cfSDan McDonald 	 */
375*2871f9cfSDan McDonald 	if (oparams->user == NULL) {
376*2871f9cfSDan McDonald 	    auth_result = _plug_get_authid(params->utils, &user, prompt_need);
377*2871f9cfSDan McDonald 
378*2871f9cfSDan McDonald 	    if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
379*2871f9cfSDan McDonald 		return auth_result;
380*2871f9cfSDan McDonald 	}
381*2871f9cfSDan McDonald 
382*2871f9cfSDan McDonald 	/* try to get the password */
383*2871f9cfSDan McDonald 	if (text->password == NULL) {
384*2871f9cfSDan McDonald 	    pass_result = _plug_get_password(params->utils, &text->password,
385*2871f9cfSDan McDonald 					     &text->free_password, prompt_need);
386*2871f9cfSDan McDonald 
387*2871f9cfSDan McDonald 	    if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
388*2871f9cfSDan McDonald 		return pass_result;
389*2871f9cfSDan McDonald 	}
390*2871f9cfSDan McDonald 
391*2871f9cfSDan McDonald 	/* free prompts we got */
392*2871f9cfSDan McDonald 	if (prompt_need && *prompt_need) {
393*2871f9cfSDan McDonald 	    params->utils->free(*prompt_need);
394*2871f9cfSDan McDonald 	    *prompt_need = NULL;
395*2871f9cfSDan McDonald 	}
396*2871f9cfSDan McDonald 
397*2871f9cfSDan McDonald 	/* if there are prompts not filled in */
398*2871f9cfSDan McDonald 	if ((auth_result == SASL_INTERACT) || (pass_result == SASL_INTERACT)) {
399*2871f9cfSDan McDonald 	    /* make the prompt list */
400*2871f9cfSDan McDonald 	    result =
401*2871f9cfSDan McDonald #ifdef _INTEGRATED_SOLARIS_
402*2871f9cfSDan McDonald 		_plug_make_prompts(params->utils, &text->h, prompt_need,
403*2871f9cfSDan McDonald 		    NULL, NULL,
404*2871f9cfSDan McDonald 		    auth_result == SASL_INTERACT ?
405*2871f9cfSDan McDonald 		    gettext("Please enter your authentication name") : NULL,
406*2871f9cfSDan McDonald 		    NULL,
407*2871f9cfSDan McDonald 		    pass_result == SASL_INTERACT ?
408*2871f9cfSDan McDonald 		    gettext("Please enter your password") : NULL, NULL,
409*2871f9cfSDan McDonald 		    NULL, NULL, NULL,
410*2871f9cfSDan McDonald 		    NULL, NULL, NULL);
411*2871f9cfSDan McDonald #else
412*2871f9cfSDan McDonald 		_plug_make_prompts(params->utils, prompt_need,
413*2871f9cfSDan McDonald 				   NULL, NULL,
414*2871f9cfSDan McDonald 				   auth_result == SASL_INTERACT ?
415*2871f9cfSDan McDonald 				   "Please enter your authentication name" : NULL,
416*2871f9cfSDan McDonald 				   NULL,
417*2871f9cfSDan McDonald 				   pass_result == SASL_INTERACT ?
418*2871f9cfSDan McDonald 				   "Please enter your password" : NULL, NULL,
419*2871f9cfSDan McDonald 				   NULL, NULL, NULL,
420*2871f9cfSDan McDonald 				   NULL, NULL, NULL);
421*2871f9cfSDan McDonald #endif /* _INTEGRATED_SOLARIS_ */
422*2871f9cfSDan McDonald 	    if (result != SASL_OK) return result;
423*2871f9cfSDan McDonald 
424*2871f9cfSDan McDonald 	    return SASL_INTERACT;
425*2871f9cfSDan McDonald 	}
426*2871f9cfSDan McDonald 
427*2871f9cfSDan McDonald 	if (!text->password) {
428*2871f9cfSDan McDonald 	    PARAMERROR(params->utils);
429*2871f9cfSDan McDonald 	    return SASL_BADPARAM;
430*2871f9cfSDan McDonald 	}
431*2871f9cfSDan McDonald 
432*2871f9cfSDan McDonald 	result = params->canon_user(params->utils->conn, user, 0,
433*2871f9cfSDan McDonald 				    SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
434*2871f9cfSDan McDonald 	if (result != SASL_OK) return result;
435*2871f9cfSDan McDonald 
436*2871f9cfSDan McDonald 	/* server should have sent request for username - we ignore it */
437*2871f9cfSDan McDonald 	if (!serverin) {
438*2871f9cfSDan McDonald #ifdef _SUN_SDK_
439*2871f9cfSDan McDonald 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
440*2871f9cfSDan McDonald 		      "Server didn't issue challenge for USERNAME");
441*2871f9cfSDan McDonald #else
442*2871f9cfSDan McDonald 	    SETERROR( params->utils,
443*2871f9cfSDan McDonald 		      "Server didn't issue challenge for USERNAME");
444*2871f9cfSDan McDonald #endif /* _SUN_SDK_ */
445*2871f9cfSDan McDonald 	    return SASL_BADPROT;
446*2871f9cfSDan McDonald 	}
447*2871f9cfSDan McDonald 
448*2871f9cfSDan McDonald 	if (!clientout) {
449*2871f9cfSDan McDonald 	    PARAMERROR( params->utils );
450*2871f9cfSDan McDonald 	    return SASL_BADPARAM;
451*2871f9cfSDan McDonald 	}
452*2871f9cfSDan McDonald 
453*2871f9cfSDan McDonald 	if (clientoutlen) *clientoutlen = oparams->alen;
454*2871f9cfSDan McDonald 	*clientout = oparams->authid;
455*2871f9cfSDan McDonald 
456*2871f9cfSDan McDonald 	text->state = 2;
457*2871f9cfSDan McDonald 
458*2871f9cfSDan McDonald 	return SASL_CONTINUE;
459*2871f9cfSDan McDonald     }
460*2871f9cfSDan McDonald 
461*2871f9cfSDan McDonald     case 2:
462*2871f9cfSDan McDonald 	/* server should have sent request for password - we ignore it */
463*2871f9cfSDan McDonald 	if (!serverin) {
464*2871f9cfSDan McDonald #ifdef _SUN_SDK_
465*2871f9cfSDan McDonald 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
466*2871f9cfSDan McDonald 		      "Server didn't issue challenge for PASSWORD");
467*2871f9cfSDan McDonald #else
468*2871f9cfSDan McDonald 	    SETERROR( params->utils,
469*2871f9cfSDan McDonald 		      "Server didn't issue challenge for PASSWORD");
470*2871f9cfSDan McDonald #endif /* _SUN_SDK_ */
471*2871f9cfSDan McDonald 	    return SASL_BADPROT;
472*2871f9cfSDan McDonald 	}
473*2871f9cfSDan McDonald 
474*2871f9cfSDan McDonald 	if (!clientout) {
475*2871f9cfSDan McDonald 	    PARAMERROR(params->utils);
476*2871f9cfSDan McDonald 	    return SASL_BADPARAM;
477*2871f9cfSDan McDonald 	}
478*2871f9cfSDan McDonald 
479*2871f9cfSDan McDonald 	if (clientoutlen) *clientoutlen = text->password->len;
480*2871f9cfSDan McDonald 	*clientout = (char *)text->password->data;
481*2871f9cfSDan McDonald 
482*2871f9cfSDan McDonald 	/* set oparams */
483*2871f9cfSDan McDonald 	oparams->doneflag = 1;
484*2871f9cfSDan McDonald 	oparams->mech_ssf = 0;
485*2871f9cfSDan McDonald 	oparams->maxoutbuf = 0;
486*2871f9cfSDan McDonald 	oparams->encode_context = NULL;
487*2871f9cfSDan McDonald 	oparams->encode = NULL;
488*2871f9cfSDan McDonald 	oparams->decode_context = NULL;
489*2871f9cfSDan McDonald 	oparams->decode = NULL;
490*2871f9cfSDan McDonald 	oparams->param_version = 0;
491*2871f9cfSDan McDonald 
492*2871f9cfSDan McDonald 	return SASL_OK;
493*2871f9cfSDan McDonald 
494*2871f9cfSDan McDonald     default:
495*2871f9cfSDan McDonald 	params->utils->log(NULL, SASL_LOG_ERR,
496*2871f9cfSDan McDonald 			   "Invalid LOGIN client step %d\n", text->state);
497*2871f9cfSDan McDonald 	return SASL_FAIL;
498*2871f9cfSDan McDonald     }
499*2871f9cfSDan McDonald 
500*2871f9cfSDan McDonald     return SASL_FAIL; /* should never get here */
501*2871f9cfSDan McDonald }
502*2871f9cfSDan McDonald 
503*2871f9cfSDan McDonald static void login_client_mech_dispose(void *conn_context,
504*2871f9cfSDan McDonald 				      const sasl_utils_t *utils)
505*2871f9cfSDan McDonald {
506*2871f9cfSDan McDonald     client_context_t *text = (client_context_t *) conn_context;
507*2871f9cfSDan McDonald 
508*2871f9cfSDan McDonald     if (!text) return;
509*2871f9cfSDan McDonald 
510*2871f9cfSDan McDonald     /* free sensitive info */
511*2871f9cfSDan McDonald     if (text->free_password) _plug_free_secret(utils, &(text->password));
512*2871f9cfSDan McDonald #ifdef _INTEGRATED_SOLARIS_
513*2871f9cfSDan McDonald     convert_prompt(utils, &text->h, NULL);
514*2871f9cfSDan McDonald #endif /* _INTEGRATED_SOLARIS_ */
515*2871f9cfSDan McDonald 
516*2871f9cfSDan McDonald     utils->free(text);
517*2871f9cfSDan McDonald }
518*2871f9cfSDan McDonald 
519*2871f9cfSDan McDonald static sasl_client_plug_t login_client_plugins[] =
520*2871f9cfSDan McDonald {
521*2871f9cfSDan McDonald     {
522*2871f9cfSDan McDonald 	"LOGIN",			/* mech_name */
523*2871f9cfSDan McDonald 	0,				/* max_ssf */
524*2871f9cfSDan McDonald 	SASL_SEC_NOANONYMOUS,		/* security_flags */
525*2871f9cfSDan McDonald 	SASL_FEAT_SERVER_FIRST,		/* features */
526*2871f9cfSDan McDonald 	NULL,				/* required_prompts */
527*2871f9cfSDan McDonald 	NULL,				/* glob_context */
528*2871f9cfSDan McDonald 	&login_client_mech_new,		/* mech_new */
529*2871f9cfSDan McDonald 	&login_client_mech_step,	/* mech_step */
530*2871f9cfSDan McDonald 	&login_client_mech_dispose,	/* mech_dispose */
531*2871f9cfSDan McDonald 	NULL,				/* mech_free */
532*2871f9cfSDan McDonald 	NULL,				/* idle */
533*2871f9cfSDan McDonald 	NULL,				/* spare */
534*2871f9cfSDan McDonald 	NULL				/* spare */
535*2871f9cfSDan McDonald     }
536*2871f9cfSDan McDonald };
537*2871f9cfSDan McDonald 
538*2871f9cfSDan McDonald int login_client_plug_init(sasl_utils_t *utils,
539*2871f9cfSDan McDonald 			   int maxversion,
540*2871f9cfSDan McDonald 			   int *out_version,
541*2871f9cfSDan McDonald 			   sasl_client_plug_t **pluglist,
542*2871f9cfSDan McDonald 			   int *plugcount)
543*2871f9cfSDan McDonald {
544*2871f9cfSDan McDonald     if (maxversion < SASL_CLIENT_PLUG_VERSION) {
545*2871f9cfSDan McDonald 	SETERROR(utils, "Version mismatch in LOGIN");
546*2871f9cfSDan McDonald 	return SASL_BADVERS;
547*2871f9cfSDan McDonald     }
548*2871f9cfSDan McDonald 
549*2871f9cfSDan McDonald     *out_version = SASL_CLIENT_PLUG_VERSION;
550*2871f9cfSDan McDonald     *pluglist = login_client_plugins;
551*2871f9cfSDan McDonald     *plugcount = 1;
552*2871f9cfSDan McDonald 
553*2871f9cfSDan McDonald     return SASL_OK;
554*2871f9cfSDan McDonald }
555