1/* Anonymous SASL plugin 2 * Rob Siemborski 3 * Tim Martin 4 * $Id: anonymous.c,v 1.8 2006/02/03 22:33:14 snsimon Exp $ 5 */ 6/* 7 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 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 19 * distribution. 20 * 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 27 * 5000 Forbes Avenue 28 * Pittsburgh, PA 15213-3890 29 * (412) 268-4387, fax: (412) 268-7395 30 * tech-transfer@andrew.cmu.edu 31 * 32 * 4. Redistributions of any form whatsoever must retain the following 33 * acknowledgment: 34 * "This product includes software developed by Computing Services 35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 36 * 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. 44 */ 45 46#include <config.h> 47#include <stdio.h> 48#include <string.h> 49#ifdef HAVE_UNISTD_H 50#include <unistd.h> 51#endif 52#include <sasl.h> 53#include <saslplug.h> 54 55#include "plugin_common.h" 56 57#ifdef macintosh 58#include <sasl_anonymous_plugin_decl.h> 59#endif 60 61/***************************** Common Section *****************************/ 62 63//static const char plugin_id[] = "$Id: anonymous.c,v 1.8 2006/02/03 22:33:14 snsimon Exp $"; 64 65static const char anonymous_id[] = "anonymous"; 66 67/***************************** Server Section *****************************/ 68 69static int 70anonymous_server_mech_new(void *glob_context __attribute__((unused)), 71 sasl_server_params_t *sparams, 72 const char *challenge __attribute__((unused)), 73 unsigned challen __attribute__((unused)), 74 void **conn_context) 75{ 76 /* holds state are in */ 77 if (!conn_context) { 78 PARAMERROR( sparams->utils ); 79 return SASL_BADPARAM; 80 } 81 82 *conn_context = NULL; 83 84 return SASL_OK; 85} 86 87static int 88anonymous_server_mech_step(void *conn_context __attribute__((unused)), 89 sasl_server_params_t *sparams, 90 const char *clientin, 91 unsigned clientinlen, 92 const char **serverout, 93 unsigned *serveroutlen, 94 sasl_out_params_t *oparams) 95{ 96 char *clientdata; 97 int result; 98 99 if (!sparams 100 || !serverout 101 || !serveroutlen 102 || !oparams) { 103 PARAMERROR( sparams->utils ); 104 return SASL_BADPARAM; 105 } 106 107 *serverout = NULL; 108 *serveroutlen = 0; 109 110 if (!clientin) { 111 return SASL_CONTINUE; 112 } 113 114 /* We force a truncation 255 characters (specified by RFC 2245) */ 115 if (clientinlen > 255) clientinlen = 255; 116 117 /* NULL-terminate the clientin... */ 118 clientdata = sparams->utils->malloc(clientinlen + 1); 119 if (!clientdata) { 120 MEMERROR(sparams->utils); 121 return SASL_NOMEM; 122 } 123 124 strncpy(clientdata, clientin, clientinlen); 125 clientdata[clientinlen] = '\0'; 126 127 sparams->utils->log(sparams->utils->conn, 128 SASL_LOG_NOTE, 129 "ANONYMOUS login: \"%s\"", 130 clientdata); 131 132 if (clientdata != clientin) 133 sparams->utils->free(clientdata); 134 135 result = sparams->canon_user(sparams->utils->conn, 136 anonymous_id, 0, 137 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); 138 139 if (result != SASL_OK) return result; 140 141 /* set oparams */ 142 oparams->doneflag = 1; 143 oparams->mech_ssf = 0; 144 oparams->maxoutbuf = 0; 145 oparams->encode_context = NULL; 146 oparams->encode = NULL; 147 oparams->decode_context = NULL; 148 oparams->decode = NULL; 149 oparams->param_version = 0; 150 151 return SASL_OK; 152} 153 154static sasl_server_plug_t anonymous_server_plugins[] = 155{ 156 { 157 "ANONYMOUS", /* mech_name */ 158 0, /* max_ssf */ 159 SASL_SEC_NOPLAINTEXT, /* security_flags */ 160 SASL_FEAT_WANT_CLIENT_FIRST 161 | SASL_FEAT_DONTUSE_USERPASSWD, /* features */ 162 NULL, /* glob_context */ 163 &anonymous_server_mech_new, /* mech_new */ 164 &anonymous_server_mech_step, /* mech_step */ 165 NULL, /* mech_dispose */ 166 NULL, /* mech_free */ 167 NULL, /* setpass */ 168 NULL, /* user_query */ 169 NULL, /* idle */ 170 NULL, /* mech_avail */ 171 NULL /* spare */ 172 } 173}; 174 175int anonymous_server_plug_init(const sasl_utils_t *utils, 176 int maxversion, 177 int *out_version, 178 sasl_server_plug_t **pluglist, 179 int *plugcount) 180{ 181 if (maxversion < SASL_SERVER_PLUG_VERSION) { 182 SETERROR( utils, "ANONYMOUS version mismatch" ); 183 return SASL_BADVERS; 184 } 185 186 *out_version = SASL_SERVER_PLUG_VERSION; 187 *pluglist = anonymous_server_plugins; 188 *plugcount = 1; 189 190 return SASL_OK; 191} 192 193/***************************** Client Section *****************************/ 194 195typedef struct client_context { 196 char *out_buf; 197 unsigned out_buf_len; 198} client_context_t; 199 200static int 201anonymous_client_mech_new(void *glob_context __attribute__((unused)), 202 sasl_client_params_t *cparams, 203 void **conn_context) 204{ 205 client_context_t *text; 206 207 if (!conn_context) { 208 PARAMERROR(cparams->utils); 209 return SASL_BADPARAM; 210 } 211 212 /* holds state are in */ 213 text = cparams->utils->malloc(sizeof(client_context_t)); 214 if (text == NULL) { 215 MEMERROR(cparams->utils); 216 return SASL_NOMEM; 217 } 218 219 memset(text, 0, sizeof(client_context_t)); 220 221 *conn_context = text; 222 223 return SASL_OK; 224} 225 226static int 227anonymous_client_mech_step(void *conn_context, 228 sasl_client_params_t *cparams, 229 const char *serverin __attribute__((unused)), 230 unsigned serverinlen, 231 sasl_interact_t **prompt_need, 232 const char **clientout, 233 unsigned *clientoutlen, 234 sasl_out_params_t *oparams) 235{ 236 client_context_t *text = (client_context_t *) conn_context; 237 size_t userlen; 238 char hostname[256]; 239 const char *user = NULL; 240 int user_result = SASL_OK; 241 int result; 242 243 if (!cparams 244 || !clientout 245 || !clientoutlen 246 || !oparams) { 247 PARAMERROR( cparams->utils ); 248 return SASL_BADPARAM; 249 } 250 251 *clientout = NULL; 252 *clientoutlen = 0; 253 254 if (serverinlen != 0) { 255 SETERROR( cparams->utils, 256 "Nonzero serverinlen in ANONYMOUS continue_step" ); 257 return SASL_BADPROT; 258 } 259 260 /* check if sec layer strong enough */ 261 if (cparams->props.min_ssf > cparams->external_ssf) { 262 SETERROR( cparams->utils, "SSF requested of ANONYMOUS plugin"); 263 return SASL_TOOWEAK; 264 } 265 266 /* try to get the trace info */ 267 if (user == NULL) { 268 user_result = _plug_get_userid(cparams->utils, &user, prompt_need); 269 270 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) { 271 return user_result; 272 } 273 } 274 275 /* free prompts we got */ 276 if (prompt_need && *prompt_need) { 277 cparams->utils->free(*prompt_need); 278 *prompt_need = NULL; 279 } 280 281 /* if there are prompts not filled in */ 282 if (user_result == SASL_INTERACT) { 283 /* make the prompt list */ 284 result = 285 _plug_make_prompts(cparams->utils, prompt_need, 286 user_result == SASL_INTERACT ? 287 "Please enter anonymous identification" : NULL, 288 "", 289 NULL, NULL, 290 NULL, NULL, 291 NULL, NULL, NULL, 292 NULL, NULL, NULL); 293 if (result != SASL_OK) return result; 294 295 return SASL_INTERACT; 296 } 297 298 if (!user || !*user) { 299 user = anonymous_id; 300 } 301 userlen = strlen(user); 302 303 result = cparams->canon_user(cparams->utils->conn, 304 anonymous_id, 0, 305 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); 306 if (result != SASL_OK) return result; 307 308 memset(hostname, 0, sizeof(hostname)); 309 gethostname(hostname, sizeof(hostname)); 310 hostname[sizeof(hostname)-1] = '\0'; 311 312 *clientoutlen = (unsigned) (userlen + strlen(hostname) + 1); 313 314 result = _plug_buf_alloc(cparams->utils, &text->out_buf, 315 &text->out_buf_len, *clientoutlen); 316 317 if (result != SASL_OK) return result; 318 319 strcpy(text->out_buf, user); 320 text->out_buf[userlen] = '@'; 321 /* use memcpy() instead of strcpy() so we don't add the NUL */ 322 memcpy(text->out_buf + userlen + 1, hostname, strlen(hostname)); 323 324 *clientout = text->out_buf; 325 326 /* set oparams */ 327 oparams->doneflag = 1; 328 oparams->mech_ssf = 0; 329 oparams->maxoutbuf = 0; 330 oparams->encode_context = NULL; 331 oparams->encode = NULL; 332 oparams->decode_context = NULL; 333 oparams->decode = NULL; 334 oparams->param_version = 0; 335 336 return SASL_OK; 337} 338 339static void anonymous_client_dispose(void *conn_context, 340 const sasl_utils_t *utils) 341{ 342 client_context_t *text = (client_context_t *) conn_context; 343 344 if(!text) return; 345 346 if (text->out_buf) utils->free(text->out_buf); 347 348 utils->free(text); 349} 350 351static const unsigned long anonymous_required_prompts[] = { 352 SASL_CB_LIST_END 353}; 354 355static sasl_client_plug_t anonymous_client_plugins[] = 356{ 357 { 358 "ANONYMOUS", /* mech_name */ 359 0, /* max_ssf */ 360 SASL_SEC_NOPLAINTEXT, /* security_flags */ 361 SASL_FEAT_WANT_CLIENT_FIRST, /* features */ 362 anonymous_required_prompts, /* required_prompts */ 363 NULL, /* glob_context */ 364 &anonymous_client_mech_new, /* mech_new */ 365 &anonymous_client_mech_step, /* mech_step */ 366 &anonymous_client_dispose, /* mech_dispose */ 367 NULL, /* mech_free */ 368 NULL, /* idle */ 369 NULL, /* spare */ 370 NULL /* spare */ 371 } 372}; 373 374int anonymous_client_plug_init(const sasl_utils_t *utils, 375 int maxversion, 376 int *out_version, 377 sasl_client_plug_t **pluglist, 378 int *plugcount) 379{ 380 if (maxversion < SASL_CLIENT_PLUG_VERSION) { 381 SETERROR( utils, "ANONYMOUS version mismatch" ); 382 return SASL_BADVERS; 383 } 384 385 *out_version = SASL_CLIENT_PLUG_VERSION; 386 *pluglist = anonymous_client_plugins; 387 *plugcount = 1; 388 389 return SASL_OK; 390} 391