dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / sasl_plugins / plain / plain.c
blob97194dee5b0f275fe0d488ef910c3a043dcadd14
1 /*
2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5 #pragma ident "%Z%%M% %I% %E% SMI"
7 /* Plain SASL plugin
8 * Rob Siemborski
9 * Tim Martin
10 * $Id: plain.c,v 1.61 2003/03/26 17:18:04 rjs3 Exp $
13 /*
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
18 * are met:
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
26 * distribution.
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
34 * 5000 Forbes Avenue
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
40 * acknowledgment:
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.
53 #include <config.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <sasl.h>
57 #include <saslplug.h>
59 #include "plugin_common.h"
61 #ifndef _SUN_SDK_
62 #ifdef WIN32
63 /* This must be after sasl.h */
64 # include "saslPLAIN.h"
65 #endif /* WIN32 */
66 #endif /* !_SUN_SDK_ */
68 #ifdef macintosh
69 #include <sasl_plain_plugin_decl.h>
70 #endif
72 /***************************** Common Section *****************************/
74 #ifndef _SUN_SDK_
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)),
84 void **conn_context)
86 /* holds state are in */
87 if (!conn_context) {
88 PARAMERROR( sparams->utils );
89 return SASL_BADPARAM;
92 *conn_context = NULL;
94 return SASL_OK;
97 static int plain_server_mech_step(void *conn_context __attribute__((unused)),
98 sasl_server_params_t *params,
99 const char *clientin,
100 unsigned clientinlen,
101 const char **serverout,
102 unsigned *serveroutlen,
103 sasl_out_params_t *oparams)
105 const char *author;
106 const char *authen;
107 const char *password;
108 size_t password_len;
109 unsigned lup=0;
110 int result;
111 char *passcopy;
113 *serverout = NULL;
114 *serveroutlen = 0;
116 /* should have received author-id NUL authen-id NUL password */
118 /* get author */
119 author = clientin;
120 while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
122 if (lup >= clientinlen) {
123 #ifdef _SUN_SDK_
124 params->utils->log(params->utils->conn, SASL_LOG_ERR,
125 "Can only find author (no password)");
126 #else
127 SETERROR(params->utils, "Can only find author (no password)");
128 #endif /* _SUN_SDK_ */
129 return SASL_BADPROT;
132 /* get authen */
133 ++lup;
134 authen = clientin + lup;
135 while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
137 if (lup >= clientinlen) {
138 #ifdef _SUN_SDK_
139 params->utils->log(params->utils->conn, SASL_LOG_ERR,
140 "Can only find author/en (no password)");
141 #else
142 params->utils->seterror(params->utils->conn, 0,
143 "Can only find author/en (no password)");
144 #endif /* _SUN_SDK_ */
145 return SASL_BADPROT;
148 /* get password */
149 lup++;
150 password = clientin + lup;
151 while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
153 password_len = clientin + lup - password;
155 if (lup != clientinlen) {
156 #ifdef _SUN_SDK_
157 params->utils->log(params->utils->conn, SASL_LOG_ERR,
158 "Got more data than we were expecting in the PLAIN plugin");
159 #else
160 SETERROR(params->utils,
161 "Got more data than we were expecting in the PLAIN plugin\n");
162 #endif /* _SUN_SDK_ */
163 return SASL_BADPROT;
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);
172 return SASL_NOMEM;
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)
181 author = authen;
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);
187 return result;
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"));
201 #else
202 params->utils->seterror(params->utils->conn, 0,
203 "Password verification failed");
204 #endif /* _INTEGRATED_SOLARIS_ */
205 return result;
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;
215 /* Transition? */
216 if (params->transition) {
217 params->transition(params->utils->conn, password, password_len);
220 /* set oparams */
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;
230 return SASL_OK;
233 static sasl_server_plug_t plain_server_plugins[] =
236 "PLAIN", /* mech_name */
237 0, /* max_ssf */
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 */
246 NULL, /* setpass */
247 NULL, /* user_query */
248 NULL, /* idle */
249 NULL, /* mech_avail */
250 NULL /* spare */
254 int plain_server_plug_init(const sasl_utils_t *utils,
255 int maxversion,
256 int *out_version,
257 sasl_server_plug_t **pluglist,
258 int *plugcount)
260 if (maxversion < SASL_SERVER_PLUG_VERSION) {
261 SETERROR(utils, "PLAIN version mismatch");
262 return SASL_BADVERS;
265 *out_version = SASL_SERVER_PLUG_VERSION;
266 *pluglist = plain_server_plugins;
267 *plugcount = 1;
269 return SASL_OK;
272 /***************************** Client Section *****************************/
274 typedef struct client_context {
275 char *out_buf;
276 unsigned out_buf_len;
277 #ifdef _INTEGRATED_SOLARIS_
278 void *h;
279 #endif /* _INTEGRATED_SOLARIS_ */
280 } client_context_t;
282 static int plain_client_mech_new(void *glob_context __attribute__((unused)),
283 sasl_client_params_t *params,
284 void **conn_context)
286 client_context_t *text;
288 /* holds state are in */
289 text = params->utils->malloc(sizeof(client_context_t));
290 if (text == NULL) {
291 MEMERROR( params->utils );
292 return SASL_NOMEM;
295 memset(text, 0, sizeof(client_context_t));
297 *conn_context = text;
299 return SASL_OK;
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;
318 int result;
320 *clientout = NULL;
321 *clientoutlen = 0;
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"));
329 #else
330 SETERROR( params->utils, "SSF requested of PLAIN plugin");
331 #endif /* _INTEGRATED_SOLARIS_ */
332 return SASL_TOOWEAK;
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))
340 return auth_result;
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))
348 return user_result;
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))
357 return pass_result;
360 /* free prompts we got */
361 if (prompt_need && *prompt_need) {
362 params->utils->free(*prompt_need);
363 *prompt_need = NULL;
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 */
370 result =
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"))
376 : NULL,
377 NULL,
378 auth_result == SASL_INTERACT ?
379 convert_prompt(params->utils, &text->h,
380 gettext("Please enter your authentication name"))
381 : NULL,
382 NULL,
383 pass_result == SASL_INTERACT ?
384 convert_prompt(params->utils, &text->h,
385 gettext("Please enter your password")) : NULL,
386 NULL,
387 NULL, NULL, NULL,
388 NULL, NULL, NULL);
389 #else
390 _plug_make_prompts(params->utils, prompt_need,
391 user_result == SASL_INTERACT ?
392 "Please enter your authorization name" : NULL,
393 NULL,
394 auth_result == SASL_INTERACT ?
395 "Please enter your authentication name" : NULL,
396 NULL,
397 pass_result == SASL_INTERACT ?
398 "Please enter your password" : NULL, NULL,
399 NULL, NULL, NULL,
400 NULL, NULL, NULL);
401 #endif /* _INTEGRATED_SOLARIS_ */
402 if (result != SASL_OK) goto cleanup;
404 return SASL_INTERACT;
407 if (!password) {
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);
416 else {
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
428 + oparams->alen + 1
429 + password->len);
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;
444 /* set oparams */
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;
454 result = SASL_OK;
456 cleanup:
457 /* free sensitive info */
458 if (free_password) _plug_free_secret(params->utils, &password);
460 return result;
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;
468 if (!text) return;
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_ */
475 utils->free(text);
478 static sasl_client_plug_t plain_client_plugins[] =
481 "PLAIN", /* mech_name */
482 0, /* max_ssf */
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 */
492 NULL, /* idle */
493 NULL, /* spare */
494 NULL /* spare */
498 int plain_client_plug_init(sasl_utils_t *utils,
499 int maxversion,
500 int *out_version,
501 sasl_client_plug_t **pluglist,
502 int *plugcount)
504 if (maxversion < SASL_CLIENT_PLUG_VERSION) {
505 SETERROR(utils, "PLAIN version mismatch");
506 return SASL_BADVERS;
509 *out_version = SASL_CLIENT_PLUG_VERSION;
510 *pluglist = plain_client_plugins;
511 *plugcount = 1;
513 return SASL_OK;