4 * $Id: plain.c,v 1.64 2004/09/08 11:06:11 mel Exp $
7 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
21 * 3. The name "Carnegie Mellon University" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For permission or any other legal
24 * details, please contact
25 * Office of Technology Transfer
26 * Carnegie Mellon University
28 * Pittsburgh, PA 15213-3890
29 * (412) 268-4387, fax: (412) 268-7395
30 * tech-transfer@andrew.cmu.edu
32 * 4. Redistributions of any form whatsoever must retain the following
34 * "This product includes software developed by Computing Services
35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
37 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
38 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
40 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
42 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
43 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
52 #include "plugin_common.h"
55 #include <sasl_plain_plugin_decl.h>
58 /***************************** Common Section *****************************/
60 static const char plugin_id[] = "$Id: plain.c,v 1.64 2004/09/08 11:06:11 mel Exp $";
62 /***************************** Server Section *****************************/
64 static int plain_server_mech_new(void *glob_context __attribute__((unused)),
65 sasl_server_params_t *sparams,
66 const char *challenge __attribute__((unused)),
67 unsigned challen __attribute__((unused)),
70 /* holds state are in */
72 PARAMERROR( sparams->utils );
81 static int plain_server_mech_step(void *conn_context __attribute__((unused)),
82 sasl_server_params_t *params,
85 const char **serverout,
86 unsigned *serveroutlen,
87 sasl_out_params_t *oparams)
92 unsigned password_len;
100 /* should have received author-id NUL authen-id NUL password */
104 while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
106 if (lup >= clientinlen) {
107 SETERROR(params->utils, "Can only find author (no password)");
113 authen = clientin + lup;
114 while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
116 if (lup >= clientinlen) {
117 params->utils->seterror(params->utils->conn, 0,
118 "Can only find author/en (no password)");
124 password = clientin + lup;
125 while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
127 password_len = (unsigned) (clientin + lup - password);
129 if (lup != clientinlen) {
130 SETERROR(params->utils,
131 "Got more data than we were expecting in the PLAIN plugin\n");
135 /* this kinda sucks. we need password to be null terminated
136 but we can't assume there is an allocated byte at the end
137 of password so we have to copy it */
138 passcopy = params->utils->malloc(password_len + 1);
139 if (passcopy == NULL) {
140 MEMERROR(params->utils);
144 strncpy(passcopy, password, password_len);
145 passcopy[password_len] = '\0';
147 /* Canonicalize userid first, so that password verification is only
148 * against the canonical id */
149 if (!author || !*author)
152 result = params->canon_user(params->utils->conn,
153 authen, 0, SASL_CU_AUTHID, oparams);
154 if (result != SASL_OK) {
155 _plug_free_string(params->utils, &passcopy);
159 /* verify password - return sasl_ok on success*/
160 result = params->utils->checkpass(params->utils->conn,
161 oparams->authid, oparams->alen,
162 passcopy, password_len);
164 _plug_free_string(params->utils, &passcopy);
166 if (result != SASL_OK) {
167 params->utils->seterror(params->utils->conn, 0,
168 "Password verification failed");
172 /* Canonicalize and store the authorization ID */
173 /* We need to do this after calling verify_user just in case verify_user
174 * needed to get auxprops itself */
175 result = params->canon_user(params->utils->conn,
176 author, 0, SASL_CU_AUTHZID, oparams);
177 if (result != SASL_OK) return result;
180 oparams->doneflag = 1;
181 oparams->mech_ssf = 0;
182 oparams->maxoutbuf = 0;
183 oparams->encode_context = NULL;
184 oparams->encode = NULL;
185 oparams->decode_context = NULL;
186 oparams->decode = NULL;
187 oparams->param_version = 0;
192 static sasl_server_plug_t plain_server_plugins[] =
195 "PLAIN", /* mech_name */
197 SASL_SEC_NOANONYMOUS, /* security_flags */
198 SASL_FEAT_WANT_CLIENT_FIRST
199 | SASL_FEAT_ALLOWS_PROXY, /* features */
200 NULL, /* glob_context */
201 &plain_server_mech_new, /* mech_new */
202 &plain_server_mech_step, /* mech_step */
203 NULL, /* mech_dispose */
204 NULL, /* mech_free */
206 NULL, /* user_query */
208 NULL, /* mech_avail */
213 int plain_server_plug_init(const sasl_utils_t *utils,
216 sasl_server_plug_t **pluglist,
219 if (maxversion < SASL_SERVER_PLUG_VERSION) {
220 SETERROR(utils, "PLAIN version mismatch");
224 *out_version = SASL_SERVER_PLUG_VERSION;
225 *pluglist = plain_server_plugins;
231 /***************************** Client Section *****************************/
233 typedef struct client_context {
235 unsigned out_buf_len;
238 static int plain_client_mech_new(void *glob_context __attribute__((unused)),
239 sasl_client_params_t *params,
242 client_context_t *text;
244 /* holds state are in */
245 text = params->utils->malloc(sizeof(client_context_t));
247 MEMERROR( params->utils );
251 memset(text, 0, sizeof(client_context_t));
253 *conn_context = text;
258 static int plain_client_mech_step(void *conn_context,
259 sasl_client_params_t *params,
260 const char *serverin __attribute__((unused)),
261 unsigned serverinlen __attribute__((unused)),
262 sasl_interact_t **prompt_need,
263 const char **clientout,
264 unsigned *clientoutlen,
265 sasl_out_params_t *oparams)
267 client_context_t *text = (client_context_t *) conn_context;
268 const char *user = NULL, *authid = NULL;
269 sasl_secret_t *password = NULL;
270 unsigned int free_password = 0; /* set if we need to free password */
271 int user_result = SASL_OK;
272 int auth_result = SASL_OK;
273 int pass_result = SASL_OK;
280 /* doesn't really matter how the server responds */
282 /* check if sec layer strong enough */
283 if (params->props.min_ssf > params->external_ssf) {
284 SETERROR( params->utils, "SSF requested of PLAIN plugin");
288 /* try to get the authid */
289 if (oparams->authid == NULL) {
290 auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
292 if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
296 /* try to get the userid */
297 if (oparams->user == NULL) {
298 user_result = _plug_get_userid(params->utils, &user, prompt_need);
300 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
304 /* try to get the password */
305 if (password == NULL) {
306 pass_result = _plug_get_password(params->utils, &password,
307 &free_password, prompt_need);
309 if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
313 /* free prompts we got */
314 if (prompt_need && *prompt_need) {
315 params->utils->free(*prompt_need);
319 /* if there are prompts not filled in */
320 if ((user_result == SASL_INTERACT) || (auth_result == SASL_INTERACT) ||
321 (pass_result == SASL_INTERACT)) {
322 /* make the prompt list */
324 _plug_make_prompts(params->utils, prompt_need,
325 user_result == SASL_INTERACT ?
326 "Please enter your authorization name" : NULL,
328 auth_result == SASL_INTERACT ?
329 "Please enter your authentication name" : NULL,
331 pass_result == SASL_INTERACT ?
332 "Please enter your password" : NULL, NULL,
335 if (result != SASL_OK) goto cleanup;
337 return SASL_INTERACT;
341 PARAMERROR(params->utils);
342 return SASL_BADPARAM;
345 if (!user || !*user) {
346 result = params->canon_user(params->utils->conn, authid, 0,
347 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
350 result = params->canon_user(params->utils->conn, user, 0,
351 SASL_CU_AUTHZID, oparams);
352 if (result != SASL_OK) goto cleanup;
354 result = params->canon_user(params->utils->conn, authid, 0,
355 SASL_CU_AUTHID, oparams);
357 if (result != SASL_OK) goto cleanup;
359 /* send authorized id NUL authentication id NUL password */
360 *clientoutlen = ((user && *user ? oparams->ulen : 0) +
364 /* remember the extra NUL on the end for stupid clients */
365 result = _plug_buf_alloc(params->utils, &(text->out_buf),
366 &(text->out_buf_len), *clientoutlen + 1);
367 if (result != SASL_OK) goto cleanup;
369 memset(text->out_buf, 0, *clientoutlen + 1);
372 memcpy(p, oparams->user, oparams->ulen);
375 memcpy(++p, oparams->authid, oparams->alen);
377 memcpy(++p, password->data, password->len);
379 *clientout = text->out_buf;
382 oparams->doneflag = 1;
383 oparams->mech_ssf = 0;
384 oparams->maxoutbuf = 0;
385 oparams->encode_context = NULL;
386 oparams->encode = NULL;
387 oparams->decode_context = NULL;
388 oparams->decode = NULL;
389 oparams->param_version = 0;
394 /* free sensitive info */
395 if (free_password) _plug_free_secret(params->utils, &password);
400 static void plain_client_mech_dispose(void *conn_context,
401 const sasl_utils_t *utils)
403 client_context_t *text = (client_context_t *) conn_context;
407 if (text->out_buf) utils->free(text->out_buf);
412 static sasl_client_plug_t plain_client_plugins[] =
415 "PLAIN", /* mech_name */
417 SASL_SEC_NOANONYMOUS, /* security_flags */
418 SASL_FEAT_WANT_CLIENT_FIRST
419 | SASL_FEAT_ALLOWS_PROXY, /* features */
420 NULL, /* required_prompts */
421 NULL, /* glob_context */
422 &plain_client_mech_new, /* mech_new */
423 &plain_client_mech_step, /* mech_step */
424 &plain_client_mech_dispose, /* mech_dispose */
425 NULL, /* mech_free */
432 int plain_client_plug_init(sasl_utils_t *utils,
435 sasl_client_plug_t **pluglist,
438 if (maxversion < SASL_CLIENT_PLUG_VERSION) {
439 SETERROR(utils, "PLAIN version mismatch");
443 *out_version = SASL_CLIENT_PLUG_VERSION;
444 *pluglist = plain_client_plugins;