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