1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* SASL server API implementation 7 * Rob Siemborski 8 * Tim Martin 9 * $Id: external.c,v 1.19 2003/04/08 17:30:54 rjs3 Exp $ 10 */ 11 /* 12 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in 23 * the documentation and/or other materials provided with the 24 * distribution. 25 * 26 * 3. The name "Carnegie Mellon University" must not be used to 27 * endorse or promote products derived from this software without 28 * prior written permission. For permission or any other legal 29 * details, please contact 30 * Office of Technology Transfer 31 * Carnegie Mellon University 32 * 5000 Forbes Avenue 33 * Pittsburgh, PA 15213-3890 34 * (412) 268-4387, fax: (412) 268-7395 35 * tech-transfer@andrew.cmu.edu 36 * 37 * 4. Redistributions of any form whatsoever must retain the following 38 * acknowledgment: 39 * "This product includes software developed by Computing Services 40 * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 41 * 42 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 43 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 44 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 45 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 46 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 47 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 48 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 49 */ 50 51 #include <config.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <limits.h> 55 #include <ctype.h> 56 #include <string.h> 57 #include <sasl.h> 58 #include <saslplug.h> 59 #include "saslint.h" 60 61 #include <plugin_common.h> 62 63 /***************************** Common Section *****************************/ 64 65 #ifndef _SUN_SDK_ 66 static const char plugin_id[] = "$Id: external.c,v 1.19 2003/04/08 17:30:54 rjs3 Exp $"; 67 #endif /* !_SUN_SDK_ */ 68 69 /***************************** Server Section *****************************/ 70 71 static int 72 external_server_mech_new(void *glob_context __attribute__((unused)), 73 sasl_server_params_t *sparams, 74 const char *challenge __attribute__((unused)), 75 unsigned challen __attribute__((unused)), 76 void **conn_context) 77 { 78 if (!conn_context 79 || !sparams 80 || !sparams->utils 81 || !sparams->utils->conn) 82 return SASL_BADPARAM; 83 84 if (!sparams->utils->conn->external.auth_id) 85 return SASL_NOMECH; 86 87 *conn_context = NULL; 88 89 return SASL_OK; 90 } 91 92 static int 93 external_server_mech_step(void *conn_context __attribute__((unused)), 94 sasl_server_params_t *sparams, 95 const char *clientin, 96 unsigned clientinlen, 97 const char **serverout, 98 unsigned *serveroutlen, 99 sasl_out_params_t *oparams) 100 { 101 int result; 102 103 if (!sparams 104 || !sparams->utils 105 || !sparams->utils->conn 106 || !sparams->utils->getcallback 107 || !serverout 108 || !serveroutlen 109 || !oparams) 110 return SASL_BADPARAM; 111 112 if (!sparams->utils->conn->external.auth_id) 113 return SASL_BADPROT; 114 115 if ((sparams->props.security_flags & SASL_SEC_NOANONYMOUS) && 116 (!strcmp(sparams->utils->conn->external.auth_id, "anonymous"))) { 117 #ifdef _INTEGRATED_SOLARIS_ 118 sasl_seterror(sparams->utils->conn,0, 119 gettext("anonymous login not allowed")); 120 #else 121 sasl_seterror(sparams->utils->conn,0,"anonymous login not allowed"); 122 #endif /* _INTEGRATED_SOLARIS_ */ 123 return SASL_NOAUTHZ; 124 } 125 126 *serverout = NULL; 127 *serveroutlen = 0; 128 129 if (!clientin) { 130 /* No initial data; we're in a protocol which doesn't support it. 131 * So we let the server app know that we need some... */ 132 return SASL_CONTINUE; 133 } 134 135 if (clientinlen) { /* if we have a non-zero authorization id */ 136 /* The user's trying to authorize as someone they didn't 137 * authenticate as */ 138 result = sparams->canon_user(sparams->utils->conn, 139 clientin, 0, SASL_CU_AUTHZID, oparams); 140 if(result != SASL_OK) return result; 141 142 result = sparams->canon_user(sparams->utils->conn, 143 sparams->utils->conn->external.auth_id, 0, 144 SASL_CU_AUTHID, oparams); 145 } else { 146 result = sparams->canon_user(sparams->utils->conn, 147 sparams->utils->conn->external.auth_id, 0, 148 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); 149 } 150 151 if (result != SASL_OK) return result; 152 153 /* set oparams */ 154 oparams->doneflag = 1; 155 oparams->mech_ssf = 0; 156 oparams->maxoutbuf = 0; 157 oparams->encode_context = NULL; 158 oparams->encode = NULL; 159 oparams->decode_context = NULL; 160 oparams->decode = NULL; 161 oparams->param_version = 0; 162 163 return SASL_OK; 164 } 165 166 static int 167 external_server_mech_avail(void *glob_context __attribute__((unused)), 168 sasl_server_params_t *sparams, 169 void **conn_context __attribute__((unused))) 170 { 171 if (!sparams->utils->conn->external.auth_id) 172 return SASL_NOMECH; 173 return SASL_OK; 174 } 175 176 static sasl_server_plug_t external_server_plugins[] = 177 { 178 { 179 "EXTERNAL", /* mech_name */ 180 0, /* max_ssf */ 181 SASL_SEC_NOPLAINTEXT 182 | SASL_SEC_NOANONYMOUS 183 | SASL_SEC_NODICTIONARY, /* security_flags */ 184 SASL_FEAT_WANT_CLIENT_FIRST 185 | SASL_FEAT_ALLOWS_PROXY, /* features */ 186 NULL, /* glob_context */ 187 &external_server_mech_new, /* mech_new */ 188 &external_server_mech_step, /* mech_step */ 189 NULL, /* mech_dispose */ 190 NULL, /* mech_free */ 191 NULL, /* setpass */ 192 NULL, /* user_query */ 193 NULL, /* idle */ 194 &external_server_mech_avail, /* mech_avail */ 195 NULL /* spare */ 196 } 197 }; 198 199 int external_server_plug_init(const sasl_utils_t *utils, 200 int max_version, 201 int *out_version, 202 sasl_server_plug_t **pluglist, 203 int *plugcount) 204 { 205 if (!out_version || !pluglist || !plugcount) 206 return SASL_BADPARAM; 207 208 if (max_version != SASL_SERVER_PLUG_VERSION) { 209 #ifdef _SUN_SDK_ 210 utils->log(utils->conn, SASL_LOG_ERR, "EXTERNAL version mismatch"); 211 #else 212 SETERROR( utils, "EXTERNAL version mismatch" ); 213 #endif /* _SUN_SDK_ */ 214 return SASL_BADVERS; 215 } 216 217 *out_version = SASL_SERVER_PLUG_VERSION; 218 *pluglist = external_server_plugins; 219 *plugcount = 1; 220 return SASL_OK; 221 } 222 223 /***************************** Client Section *****************************/ 224 225 typedef struct client_context 226 { 227 char *out_buf; 228 #ifdef _SUN_SDK_ 229 unsigned out_buf_len; 230 #else 231 size_t out_buf_len; 232 #endif /* _SUN_SDK_ */ 233 #ifdef _INTEGRATED_SOLARIS_ 234 void *h; 235 #endif /* _INTEGRATED_SOLARIS_ */ 236 } client_context_t; 237 238 static int external_client_mech_new(void *glob_context __attribute__((unused)), 239 sasl_client_params_t *params, 240 void **conn_context) 241 { 242 client_context_t *text; 243 244 if (!params 245 || !params->utils 246 || !params->utils->conn 247 || !conn_context) 248 return SASL_BADPARAM; 249 250 if (!params->utils->conn->external.auth_id) 251 return SASL_NOMECH; 252 253 #ifdef _SUN_SDK_ 254 text = params->utils->malloc(sizeof(client_context_t)); 255 #else 256 text = sasl_ALLOC(sizeof(client_context_t)); 257 #endif /* _SUN_SDK_ */ 258 if(!text) return SASL_NOMEM; 259 260 memset(text, 0, sizeof(client_context_t)); 261 262 *conn_context = text; 263 264 return SASL_OK; 265 } 266 267 static int 268 external_client_mech_step(void *conn_context, 269 sasl_client_params_t *params, 270 const char *serverin __attribute__((unused)), 271 unsigned serverinlen, 272 sasl_interact_t **prompt_need, 273 const char **clientout, 274 unsigned *clientoutlen, 275 sasl_out_params_t *oparams) 276 { 277 client_context_t *text = (client_context_t *)conn_context; 278 const char *user = NULL; 279 int user_result = SASL_OK; 280 int result; 281 282 if (!params 283 || !params->utils 284 || !params->utils->conn 285 || !params->utils->getcallback 286 || !clientout 287 || !clientoutlen 288 || !oparams) 289 return SASL_BADPARAM; 290 291 if (!params->utils->conn->external.auth_id) 292 return SASL_BADPROT; 293 294 if (serverinlen != 0) 295 return SASL_BADPROT; 296 297 *clientout = NULL; 298 *clientoutlen = 0; 299 300 /* try to get the userid */ 301 if (user == NULL) { 302 user_result = _plug_get_userid(params->utils, &user, prompt_need); 303 304 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) 305 return user_result; 306 } 307 308 /* free prompts we got */ 309 if (prompt_need && *prompt_need) { 310 params->utils->free(*prompt_need); 311 *prompt_need = NULL; 312 } 313 314 /* if there are prompts not filled in */ 315 if (user_result == SASL_INTERACT) { 316 /* make the prompt list */ 317 int result = 318 #ifdef _INTEGRATED_SOLARIS_ 319 _plug_make_prompts(params->utils, &text->h, prompt_need, 320 user_result == SASL_INTERACT ? 321 convert_prompt(params->utils, &text->h, 322 gettext("Please enter your authorization name")) 323 : NULL, 324 #else 325 _plug_make_prompts(params->utils, prompt_need, 326 user_result == SASL_INTERACT ? 327 "Please enter your authorization name" : NULL, 328 #endif /* _INTEGRATED_SOLARIS_ */ 329 "", 330 NULL, NULL, 331 NULL, NULL, 332 NULL, NULL, NULL, 333 NULL, NULL, NULL); 334 if (result != SASL_OK) return result; 335 336 return SASL_INTERACT; 337 } 338 339 *clientoutlen = user ? strlen(user) : 0; 340 341 #ifdef _SUN_SDK_ 342 result = _plug_buf_alloc(params->utils, &text->out_buf, 343 &text->out_buf_len, *clientoutlen + 1); 344 #else 345 result = _buf_alloc(&text->out_buf, &text->out_buf_len, *clientoutlen + 1); 346 #endif /* _SUN_SDK_ */ 347 348 if (result != SASL_OK) return result; 349 350 if (user && *user) { 351 result = params->canon_user(params->utils->conn, 352 user, 0, SASL_CU_AUTHZID, oparams); 353 if (result != SASL_OK) return result; 354 355 result = params->canon_user(params->utils->conn, 356 params->utils->conn->external.auth_id, 0, 357 SASL_CU_AUTHID, oparams); 358 if (result != SASL_OK) return result; 359 360 memcpy(text->out_buf, user, *clientoutlen); 361 } else { 362 result = params->canon_user(params->utils->conn, 363 params->utils->conn->external.auth_id, 0, 364 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); 365 if (result != SASL_OK) return result; 366 } 367 368 text->out_buf[*clientoutlen] = '\0'; 369 370 *clientout = text->out_buf; 371 372 /* set oparams */ 373 oparams->doneflag = 1; 374 oparams->mech_ssf = 0; 375 oparams->maxoutbuf = 0; 376 oparams->encode_context = NULL; 377 oparams->encode = NULL; 378 oparams->decode_context = NULL; 379 oparams->decode = NULL; 380 oparams->param_version = 0; 381 382 return SASL_OK; 383 } 384 385 static void 386 external_client_mech_dispose(void *conn_context, 387 const sasl_utils_t *utils __attribute__((unused))) 388 { 389 client_context_t *text = (client_context_t *) conn_context; 390 391 if (!text) return; 392 393 #ifdef _INTEGRATED_SOLARIS_ 394 convert_prompt(utils, &text->h, NULL); 395 #endif /* _INTEGRATED_SOLARIS_ */ 396 397 #ifdef _SUN_SDK_ 398 if(text->out_buf) utils->free(text->out_buf); 399 400 utils->free(text); 401 #else 402 if(text->out_buf) sasl_FREE(text->out_buf); 403 404 sasl_FREE(text); 405 #endif /* _SUN_SDK_ */ 406 } 407 408 #ifdef _SUN_SDK_ 409 static const unsigned long external_required_prompts[] = { 410 #else 411 static const long external_required_prompts[] = { 412 #endif /* _SUN_SDK_ */ 413 SASL_CB_LIST_END 414 }; 415 416 static sasl_client_plug_t external_client_plugins[] = 417 { 418 { 419 "EXTERNAL", /* mech_name */ 420 0, /* max_ssf */ 421 SASL_SEC_NOPLAINTEXT 422 | SASL_SEC_NOANONYMOUS 423 | SASL_SEC_NODICTIONARY, /* security_flags */ 424 SASL_FEAT_WANT_CLIENT_FIRST 425 | SASL_FEAT_ALLOWS_PROXY, /* features */ 426 external_required_prompts, /* required_prompts */ 427 NULL, /* glob_context */ 428 &external_client_mech_new, /* mech_new */ 429 &external_client_mech_step, /* mech_step */ 430 &external_client_mech_dispose, /* mech_dispose */ 431 NULL, /* mech_free */ 432 NULL, /* idle */ 433 NULL, /* spare */ 434 NULL /* spare */ 435 } 436 }; 437 438 int external_client_plug_init(const sasl_utils_t *utils, 439 int max_version, 440 int *out_version, 441 sasl_client_plug_t **pluglist, 442 int *plugcount) 443 { 444 if (!utils || !out_version || !pluglist || !plugcount) 445 return SASL_BADPARAM; 446 447 if (max_version != SASL_CLIENT_PLUG_VERSION) { 448 #ifdef _SUN_SDK_ 449 utils->log(utils->conn, SASL_LOG_ERR, "EXTERNAL version mismatch"); 450 #else 451 SETERROR( utils, "EXTERNAL version mismatch" ); 452 #endif /* _SUN_SDK_ */ 453 return SASL_BADVERS; 454 } 455 456 *out_version = SASL_CLIENT_PLUG_VERSION; 457 *pluglist = external_client_plugins; 458 *plugcount = 1; 459 460 return SASL_OK; 461 } 462