2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
5 #pragma ident "%Z%%M% %I% %E% SMI"
10 * $Id: plain.c,v 1.61 2003/03/26 17:18: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 "saslPLAIN.h"
66 #endif /* !_SUN_SDK_ */
69 #include <sasl_plain_plugin_decl.h>
72 /***************************** Common Section *****************************/
75 static const char plugin_id
[] = "$Id: plain.c,v 1.61 2003/03/26 17:18:04 rjs3 Exp $";
76 #endif /* !_SUN_SDK_ */
78 /***************************** Server Section *****************************/
80 static int plain_server_mech_new(void *glob_context
__attribute__((unused
)),
81 sasl_server_params_t
*sparams
,
82 const char *challenge
__attribute__((unused
)),
83 unsigned challen
__attribute__((unused
)),
86 /* holds state are in */
88 PARAMERROR( sparams
->utils
);
97 static int plain_server_mech_step(void *conn_context
__attribute__((unused
)),
98 sasl_server_params_t
*params
,
100 unsigned clientinlen
,
101 const char **serverout
,
102 unsigned *serveroutlen
,
103 sasl_out_params_t
*oparams
)
107 const char *password
;
116 /* should have received author-id NUL authen-id NUL password */
120 while ((lup
< clientinlen
) && (clientin
[lup
] != 0)) ++lup
;
122 if (lup
>= clientinlen
) {
124 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
125 "Can only find author (no password)");
127 SETERROR(params
->utils
, "Can only find author (no password)");
128 #endif /* _SUN_SDK_ */
134 authen
= clientin
+ lup
;
135 while ((lup
< clientinlen
) && (clientin
[lup
] != 0)) ++lup
;
137 if (lup
>= clientinlen
) {
139 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
140 "Can only find author/en (no password)");
142 params
->utils
->seterror(params
->utils
->conn
, 0,
143 "Can only find author/en (no password)");
144 #endif /* _SUN_SDK_ */
150 password
= clientin
+ lup
;
151 while ((lup
< clientinlen
) && (clientin
[lup
] != 0)) ++lup
;
153 password_len
= clientin
+ lup
- password
;
155 if (lup
!= clientinlen
) {
157 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
158 "Got more data than we were expecting in the PLAIN plugin");
160 SETERROR(params
->utils
,
161 "Got more data than we were expecting in the PLAIN plugin\n");
162 #endif /* _SUN_SDK_ */
166 /* this kinda sucks. we need password to be null terminated
167 but we can't assume there is an allocated byte at the end
168 of password so we have to copy it */
169 passcopy
= params
->utils
->malloc(password_len
+ 1);
170 if (passcopy
== NULL
) {
171 MEMERROR(params
->utils
);
175 strncpy(passcopy
, password
, password_len
);
176 passcopy
[password_len
] = '\0';
178 /* Canonicalize userid first, so that password verification is only
179 * against the canonical id */
180 if (!author
|| !*author
)
183 result
= params
->canon_user(params
->utils
->conn
,
184 authen
, 0, SASL_CU_AUTHID
, oparams
);
185 if (result
!= SASL_OK
) {
186 _plug_free_string(params
->utils
, &passcopy
);
190 /* verify password - return sasl_ok on success*/
191 result
= params
->utils
->checkpass(params
->utils
->conn
,
192 oparams
->authid
, oparams
->alen
,
193 passcopy
, password_len
);
195 _plug_free_string(params
->utils
, &passcopy
);
197 if (result
!= SASL_OK
) {
198 #ifdef _INTEGRATED_SOLARIS_
199 params
->utils
->seterror(params
->utils
->conn
, 0,
200 gettext("Password verification failed"));
202 params
->utils
->seterror(params
->utils
->conn
, 0,
203 "Password verification failed");
204 #endif /* _INTEGRATED_SOLARIS_ */
208 /* Canonicalize and store the authorization ID */
209 /* We need to do this after calling verify_user just in case verify_user
210 * needed to get auxprops itself */
211 result
= params
->canon_user(params
->utils
->conn
,
212 author
, 0, SASL_CU_AUTHZID
, oparams
);
213 if (result
!= SASL_OK
) return result
;
216 if (params
->transition
) {
217 params
->transition(params
->utils
->conn
, password
, password_len
);
221 oparams
->doneflag
= 1;
222 oparams
->mech_ssf
= 0;
223 oparams
->maxoutbuf
= 0;
224 oparams
->encode_context
= NULL
;
225 oparams
->encode
= NULL
;
226 oparams
->decode_context
= NULL
;
227 oparams
->decode
= NULL
;
228 oparams
->param_version
= 0;
233 static sasl_server_plug_t plain_server_plugins
[] =
236 "PLAIN", /* mech_name */
238 SASL_SEC_NOANONYMOUS
, /* security_flags */
239 SASL_FEAT_WANT_CLIENT_FIRST
240 | SASL_FEAT_ALLOWS_PROXY
, /* features */
241 NULL
, /* glob_context */
242 &plain_server_mech_new
, /* mech_new */
243 &plain_server_mech_step
, /* mech_step */
244 NULL
, /* mech_dispose */
245 NULL
, /* mech_free */
247 NULL
, /* user_query */
249 NULL
, /* mech_avail */
254 int plain_server_plug_init(const sasl_utils_t
*utils
,
257 sasl_server_plug_t
**pluglist
,
260 if (maxversion
< SASL_SERVER_PLUG_VERSION
) {
261 SETERROR(utils
, "PLAIN version mismatch");
265 *out_version
= SASL_SERVER_PLUG_VERSION
;
266 *pluglist
= plain_server_plugins
;
272 /***************************** Client Section *****************************/
274 typedef struct client_context
{
276 unsigned out_buf_len
;
277 #ifdef _INTEGRATED_SOLARIS_
279 #endif /* _INTEGRATED_SOLARIS_ */
282 static int plain_client_mech_new(void *glob_context
__attribute__((unused
)),
283 sasl_client_params_t
*params
,
286 client_context_t
*text
;
288 /* holds state are in */
289 text
= params
->utils
->malloc(sizeof(client_context_t
));
291 MEMERROR( params
->utils
);
295 memset(text
, 0, sizeof(client_context_t
));
297 *conn_context
= text
;
302 static int plain_client_mech_step(void *conn_context
,
303 sasl_client_params_t
*params
,
304 const char *serverin
__attribute__((unused
)),
305 unsigned serverinlen
__attribute__((unused
)),
306 sasl_interact_t
**prompt_need
,
307 const char **clientout
,
308 unsigned *clientoutlen
,
309 sasl_out_params_t
*oparams
)
311 client_context_t
*text
= (client_context_t
*) conn_context
;
312 const char *user
= NULL
, *authid
= NULL
;
313 sasl_secret_t
*password
= NULL
;
314 unsigned int free_password
= 0; /* set if we need to free password */
315 int user_result
= SASL_OK
;
316 int auth_result
= SASL_OK
;
317 int pass_result
= SASL_OK
;
323 /* doesn't really matter how the server responds */
325 /* check if sec layer strong enough */
326 if (params
->props
.min_ssf
> params
->external_ssf
) {
327 #ifdef _INTEGRATED_SOLARIS_
328 SETERROR( params
->utils
, gettext("SSF requested of PLAIN plugin"));
330 SETERROR( params
->utils
, "SSF requested of PLAIN plugin");
331 #endif /* _INTEGRATED_SOLARIS_ */
335 /* try to get the authid */
336 if (oparams
->authid
== NULL
) {
337 auth_result
= _plug_get_authid(params
->utils
, &authid
, prompt_need
);
339 if ((auth_result
!= SASL_OK
) && (auth_result
!= SASL_INTERACT
))
343 /* try to get the userid */
344 if (oparams
->user
== NULL
) {
345 user_result
= _plug_get_userid(params
->utils
, &user
, prompt_need
);
347 if ((user_result
!= SASL_OK
) && (user_result
!= SASL_INTERACT
))
351 /* try to get the password */
352 if (password
== NULL
) {
353 pass_result
= _plug_get_password(params
->utils
, &password
,
354 &free_password
, prompt_need
);
356 if ((pass_result
!= SASL_OK
) && (pass_result
!= SASL_INTERACT
))
360 /* free prompts we got */
361 if (prompt_need
&& *prompt_need
) {
362 params
->utils
->free(*prompt_need
);
366 /* if there are prompts not filled in */
367 if ((user_result
== SASL_INTERACT
) || (auth_result
== SASL_INTERACT
) ||
368 (pass_result
== SASL_INTERACT
)) {
369 /* make the prompt list */
371 #ifdef _INTEGRATED_SOLARIS_
372 _plug_make_prompts(params
->utils
, &text
->h
, prompt_need
,
373 user_result
== SASL_INTERACT
?
374 convert_prompt(params
->utils
, &text
->h
,
375 gettext("Please enter your authorization name"))
378 auth_result
== SASL_INTERACT
?
379 convert_prompt(params
->utils
, &text
->h
,
380 gettext("Please enter your authentication name"))
383 pass_result
== SASL_INTERACT
?
384 convert_prompt(params
->utils
, &text
->h
,
385 gettext("Please enter your password")) : NULL
,
390 _plug_make_prompts(params
->utils
, prompt_need
,
391 user_result
== SASL_INTERACT
?
392 "Please enter your authorization name" : NULL
,
394 auth_result
== SASL_INTERACT
?
395 "Please enter your authentication name" : NULL
,
397 pass_result
== SASL_INTERACT
?
398 "Please enter your password" : NULL
, NULL
,
401 #endif /* _INTEGRATED_SOLARIS_ */
402 if (result
!= SASL_OK
) goto cleanup
;
404 return SASL_INTERACT
;
408 PARAMERROR(params
->utils
);
409 return SASL_BADPARAM
;
412 if (!user
|| !*user
) {
413 result
= params
->canon_user(params
->utils
->conn
, authid
, 0,
414 SASL_CU_AUTHID
| SASL_CU_AUTHZID
, oparams
);
417 result
= params
->canon_user(params
->utils
->conn
, user
, 0,
418 SASL_CU_AUTHZID
, oparams
);
419 if (result
!= SASL_OK
) goto cleanup
;
421 result
= params
->canon_user(params
->utils
->conn
, authid
, 0,
422 SASL_CU_AUTHID
, oparams
);
424 if (result
!= SASL_OK
) goto cleanup
;
426 /* send authorized id NUL authentication id NUL password */
427 *clientoutlen
= (oparams
->ulen
+ 1
431 /* remember the extra NUL on the end for stupid clients */
432 result
= _plug_buf_alloc(params
->utils
, &(text
->out_buf
),
433 &(text
->out_buf_len
), *clientoutlen
+ 1);
434 if (result
!= SASL_OK
) goto cleanup
;
436 memset(text
->out_buf
, 0, *clientoutlen
+ 1);
437 memcpy(text
->out_buf
, oparams
->user
, oparams
->ulen
);
438 memcpy(text
->out_buf
+ oparams
->ulen
+ 1, oparams
->authid
, oparams
->alen
);
439 memcpy(text
->out_buf
+ oparams
->ulen
+ oparams
->alen
+ 2,
440 password
->data
, password
->len
);
442 *clientout
= text
->out_buf
;
445 oparams
->doneflag
= 1;
446 oparams
->mech_ssf
= 0;
447 oparams
->maxoutbuf
= 0;
448 oparams
->encode_context
= NULL
;
449 oparams
->encode
= NULL
;
450 oparams
->decode_context
= NULL
;
451 oparams
->decode
= NULL
;
452 oparams
->param_version
= 0;
457 /* free sensitive info */
458 if (free_password
) _plug_free_secret(params
->utils
, &password
);
463 static void plain_client_mech_dispose(void *conn_context
,
464 const sasl_utils_t
*utils
)
466 client_context_t
*text
= (client_context_t
*) conn_context
;
470 if (text
->out_buf
) utils
->free(text
->out_buf
);
471 #ifdef _INTEGRATED_SOLARIS_
472 convert_prompt(utils
, &text
->h
, NULL
);
473 #endif /* _INTEGRATED_SOLARIS_ */
478 static sasl_client_plug_t plain_client_plugins
[] =
481 "PLAIN", /* mech_name */
483 SASL_SEC_NOANONYMOUS
, /* security_flags */
484 SASL_FEAT_WANT_CLIENT_FIRST
485 | SASL_FEAT_ALLOWS_PROXY
, /* features */
486 NULL
, /* required_prompts */
487 NULL
, /* glob_context */
488 &plain_client_mech_new
, /* mech_new */
489 &plain_client_mech_step
, /* mech_step */
490 &plain_client_mech_dispose
, /* mech_dispose */
491 NULL
, /* mech_free */
498 int plain_client_plug_init(sasl_utils_t
*utils
,
501 sasl_client_plug_t
**pluglist
,
504 if (maxversion
< SASL_CLIENT_PLUG_VERSION
) {
505 SETERROR(utils
, "PLAIN version mismatch");
509 *out_version
= SASL_CLIENT_PLUG_VERSION
;
510 *pluglist
= plain_client_plugins
;