1 /* 2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* CRAM-MD5 SASL plugin 7 * Rob Siemborski 8 * Tim Martin 9 * $Id: cram.c,v 1.79 2003/02/18 18:27:37 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 53 #include <string.h> 54 #include <stdlib.h> 55 #include <stdio.h> 56 #ifndef macintosh 57 #include <sys/stat.h> 58 #endif 59 #include <fcntl.h> 60 61 #include <sasl.h> 62 #include <saslplug.h> 63 #include <saslutil.h> 64 65 #ifdef _SUN_SDK_ 66 #include <unistd.h> 67 #endif /* _SUN_SDK_ */ 68 69 #include "plugin_common.h" 70 71 #ifdef macintosh 72 #include <sasl_cram_plugin_decl.h> 73 #endif 74 75 /***************************** Common Section *****************************/ 76 77 #ifndef _SUN_SDK_ 78 static const char plugin_id[] = "$Id: cram.c,v 1.79 2003/02/18 18:27:37 rjs3 Exp $"; 79 #endif /* !_SUN_SDK_ */ 80 81 /* convert a string of 8bit chars to it's representation in hex 82 * using lowercase letters 83 */ 84 static char *convert16(unsigned char *in, int inlen, const sasl_utils_t *utils) 85 { 86 static char hex[]="0123456789abcdef"; 87 int lup; 88 char *out; 89 90 out = utils->malloc(inlen*2+1); 91 if (out == NULL) return NULL; 92 93 for (lup=0; lup < inlen; lup++) { 94 out[lup*2] = hex[in[lup] >> 4]; 95 out[lup*2+1] = hex[in[lup] & 15]; 96 } 97 98 out[lup*2] = 0; 99 return out; 100 } 101 102 103 /***************************** Server Section *****************************/ 104 105 typedef struct server_context { 106 int state; 107 108 char *challenge; 109 } server_context_t; 110 111 static int 112 crammd5_server_mech_new(void *glob_context __attribute__((unused)), 113 sasl_server_params_t *sparams, 114 const char *challenge __attribute__((unused)), 115 unsigned challen __attribute__((unused)), 116 void **conn_context) 117 { 118 server_context_t *text; 119 120 /* holds state are in */ 121 text = sparams->utils->malloc(sizeof(server_context_t)); 122 if (text == NULL) { 123 MEMERROR( sparams->utils ); 124 return SASL_NOMEM; 125 } 126 127 memset(text, 0, sizeof(server_context_t)); 128 129 text->state = 1; 130 131 *conn_context = text; 132 133 return SASL_OK; 134 } 135 136 /* 137 * Returns the current time (or part of it) in string form 138 * maximum length=15 139 */ 140 static char *gettime(sasl_server_params_t *sparams) 141 { 142 char *ret; 143 time_t t; 144 145 t=time(NULL); 146 ret= sparams->utils->malloc(15); 147 if (ret==NULL) return NULL; 148 149 /* the bottom bits are really the only random ones so if 150 we overflow we don't want to loose them */ 151 snprintf(ret,15,"%lu",t%(0xFFFFFF)); 152 153 return ret; 154 } 155 156 static char *randomdigits(sasl_server_params_t *sparams) 157 { 158 unsigned int num; 159 char *ret; 160 unsigned char temp[5]; /* random 32-bit number */ 161 162 #if defined _DEV_URANDOM && defined _SUN_SDK_ 163 { 164 int fd = open(_DEV_URANDOM, O_RDONLY); 165 int nread = 0; 166 167 if (fd != -1) { 168 nread = read(fd, temp, 4); 169 close(fd); 170 } 171 if (nread != 4) 172 sparams->utils->rand(sparams->utils->rpool, 173 (char *) temp, 4); 174 } 175 #else 176 sparams->utils->rand(sparams->utils->rpool,(char *) temp,4); 177 #endif /* _DEV_URANDOM && _SUN_SDK_ */ 178 num=(temp[0] * 256 * 256 * 256) + 179 (temp[1] * 256 * 256) + 180 (temp[2] * 256) + 181 (temp[3] ); 182 183 ret = sparams->utils->malloc(15); /* there's no way an unsigned can be longer than this right? */ 184 if (ret == NULL) return NULL; 185 sprintf(ret, "%u", num); 186 187 return ret; 188 } 189 190 static int 191 crammd5_server_mech_step1(server_context_t *text, 192 sasl_server_params_t *sparams, 193 const char *clientin __attribute__((unused)), 194 unsigned clientinlen, 195 const char **serverout, 196 unsigned *serveroutlen, 197 sasl_out_params_t *oparams __attribute__((unused))) 198 { 199 char *time, *randdigits; 200 201 /* we shouldn't have received anything */ 202 if (clientinlen != 0) { 203 #ifdef _SUN_SDK_ 204 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR, 205 "CRAM-MD5 does not accept inital data"); 206 #else 207 SETERROR(sparams->utils, "CRAM-MD5 does not accpet inital data"); 208 #endif /* _SUN_SDK_ */ 209 return SASL_BADPROT; 210 } 211 212 /* get time and a random number for the nonce */ 213 time = gettime(sparams); 214 randdigits = randomdigits(sparams); 215 if ((time == NULL) || (randdigits == NULL)) { 216 MEMERROR( sparams->utils ); 217 return SASL_NOMEM; 218 } 219 220 /* allocate some space for the challenge */ 221 text->challenge = sparams->utils->malloc(200 + 1); 222 if (text->challenge == NULL) { 223 MEMERROR(sparams->utils); 224 return SASL_NOMEM; 225 } 226 227 /* create the challenge */ 228 snprintf(text->challenge, 200, "<%s.%s@%s>", randdigits, time, 229 sparams->serverFQDN); 230 231 *serverout = text->challenge; 232 *serveroutlen = strlen(text->challenge); 233 234 /* free stuff */ 235 sparams->utils->free(time); 236 sparams->utils->free(randdigits); 237 238 text->state = 2; 239 240 return SASL_CONTINUE; 241 } 242 243 static int 244 crammd5_server_mech_step2(server_context_t *text, 245 sasl_server_params_t *sparams, 246 const char *clientin, 247 unsigned clientinlen, 248 const char **serverout __attribute__((unused)), 249 unsigned *serveroutlen __attribute__((unused)), 250 sasl_out_params_t *oparams) 251 { 252 char *userid = NULL; 253 sasl_secret_t *sec = NULL; 254 int pos, len; 255 int result = SASL_FAIL; 256 const char *password_request[] = { SASL_AUX_PASSWORD, 257 "*cmusaslsecretCRAM-MD5", 258 NULL }; 259 struct propval auxprop_values[3]; 260 HMAC_MD5_CTX tmphmac; 261 HMAC_MD5_STATE md5state; 262 int clear_md5state = 0; 263 char *digest_str = NULL; 264 UINT4 digest[4]; 265 266 /* extract userid; everything before last space */ 267 pos = clientinlen-1; 268 while ((pos > 0) && (clientin[pos] != ' ')) pos--; 269 270 if (pos <= 0) { 271 #ifdef _SUN_SDK_ 272 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR, 273 "need authentication name"); 274 #else 275 SETERROR( sparams->utils,"need authentication name"); 276 #endif /* _SUN_SDK_ */ 277 return SASL_BADPROT; 278 } 279 280 userid = (char *) sparams->utils->malloc(pos+1); 281 if (userid == NULL) { 282 MEMERROR( sparams->utils); 283 return SASL_NOMEM; 284 } 285 286 /* copy authstr out */ 287 memcpy(userid, clientin, pos); 288 userid[pos] = '\0'; 289 290 result = sparams->utils->prop_request(sparams->propctx, password_request); 291 if (result != SASL_OK) goto done; 292 293 /* this will trigger the getting of the aux properties */ 294 result = sparams->canon_user(sparams->utils->conn, 295 userid, 0, SASL_CU_AUTHID | SASL_CU_AUTHZID, 296 oparams); 297 if (result != SASL_OK) goto done; 298 299 result = sparams->utils->prop_getnames(sparams->propctx, 300 password_request, 301 auxprop_values); 302 if (result < 0 || 303 ((!auxprop_values[0].name || !auxprop_values[0].values) && 304 (!auxprop_values[1].name || !auxprop_values[1].values))) { 305 /* We didn't find this username */ 306 #ifdef _INTEGRATED_SOLARIS_ 307 sparams->utils->seterror(sparams->utils->conn,0, 308 gettext("no secret in database")); 309 #else 310 sparams->utils->seterror(sparams->utils->conn,0, 311 "no secret in database"); 312 #endif /* _INTEGRATED_SOLARIS_ */ 313 result = SASL_NOUSER; 314 goto done; 315 } 316 317 if (auxprop_values[0].name && auxprop_values[0].values) { 318 len = strlen(auxprop_values[0].values[0]); 319 if (len == 0) { 320 #ifdef _INTEGRATED_SOLARIS_ 321 sparams->utils->seterror(sparams->utils->conn,0, 322 gettext("empty secret")); 323 #else 324 sparams->utils->seterror(sparams->utils->conn,0, 325 "empty secret"); 326 #endif /* _INTEGRATED_SOLARIS_ */ 327 result = SASL_FAIL; 328 goto done; 329 } 330 331 sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len); 332 if (!sec) goto done; 333 334 sec->len = len; 335 #ifdef _SUN_SDK_ 336 strncpy((char *)sec->data, auxprop_values[0].values[0], len + 1); 337 #else 338 strncpy(sec->data, auxprop_values[0].values[0], len + 1); 339 #endif /* _SUN_SDK_ */ 340 341 clear_md5state = 1; 342 /* Do precalculation on plaintext secret */ 343 sparams->utils->hmac_md5_precalc(&md5state, /* OUT */ 344 sec->data, 345 sec->len); 346 } else if (auxprop_values[1].name && auxprop_values[1].values) { 347 /* We have a precomputed secret */ 348 memcpy(&md5state, auxprop_values[1].values[0], 349 sizeof(HMAC_MD5_STATE)); 350 } else { 351 #ifdef _SUN_SDK_ 352 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR, 353 "Have neither type of secret"); 354 #else 355 sparams->utils->seterror(sparams->utils->conn, 0, 356 "Have neither type of secret"); 357 #endif /* _SUN_SDK_ */ 358 return SASL_FAIL; 359 } 360 361 /* ok this is annoying: 362 so we have this half-way hmac transform instead of the plaintext 363 that means we half to: 364 -import it back into a md5 context 365 -do an md5update with the nonce 366 -finalize it 367 */ 368 sparams->utils->hmac_md5_import(&tmphmac, (HMAC_MD5_STATE *) &md5state); 369 sparams->utils->MD5Update(&(tmphmac.ictx), 370 (const unsigned char *) text->challenge, 371 strlen(text->challenge)); 372 sparams->utils->hmac_md5_final((unsigned char *) &digest, &tmphmac); 373 374 /* convert to base 16 with lower case letters */ 375 digest_str = convert16((unsigned char *) digest, 16, sparams->utils); 376 377 /* if same then verified 378 * - we know digest_str is null terminated but clientin might not be 379 */ 380 if (strncmp(digest_str, clientin+pos+1, strlen(digest_str)) != 0) { 381 #ifdef _INTEGRATED_SOLARIS_ 382 sparams->utils->seterror(sparams->utils->conn, 0, 383 gettext("incorrect digest response")); 384 #else 385 sparams->utils->seterror(sparams->utils->conn, 0, 386 "incorrect digest response"); 387 #endif /* _INTEGRATED_SOLARIS_ */ 388 result = SASL_BADAUTH; 389 goto done; 390 } 391 392 /* set oparams */ 393 oparams->doneflag = 1; 394 oparams->mech_ssf = 0; 395 oparams->maxoutbuf = 0; 396 oparams->encode_context = NULL; 397 oparams->encode = NULL; 398 oparams->decode_context = NULL; 399 oparams->decode = NULL; 400 oparams->param_version = 0; 401 402 result = SASL_OK; 403 404 done: 405 if (userid) sparams->utils->free(userid); 406 if (sec) _plug_free_secret(sparams->utils, &sec); 407 408 if (digest_str) sparams->utils->free(digest_str); 409 if (clear_md5state) memset(&md5state, 0, sizeof(md5state)); 410 411 return result; 412 } 413 414 static int crammd5_server_mech_step(void *conn_context, 415 sasl_server_params_t *sparams, 416 const char *clientin, 417 unsigned clientinlen, 418 const char **serverout, 419 unsigned *serveroutlen, 420 sasl_out_params_t *oparams) 421 { 422 server_context_t *text = (server_context_t *) conn_context; 423 424 *serverout = NULL; 425 *serveroutlen = 0; 426 427 /* this should be well more than is ever needed */ 428 if (clientinlen > 1024) { 429 #ifdef _SUN_SDK_ 430 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR, 431 "CRAM-MD5 input longer than 1024 bytes"); 432 #else 433 SETERROR(sparams->utils, "CRAM-MD5 input longer than 1024 bytes"); 434 #endif /* _SUN_SDK_ */ 435 return SASL_BADPROT; 436 } 437 438 switch (text->state) { 439 440 case 1: 441 return crammd5_server_mech_step1(text, sparams, 442 clientin, clientinlen, 443 serverout, serveroutlen, 444 oparams); 445 446 case 2: 447 return crammd5_server_mech_step2(text, sparams, 448 clientin, clientinlen, 449 serverout, serveroutlen, 450 oparams); 451 452 default: /* should never get here */ 453 #ifdef _SUN_SDK_ 454 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR, 455 "Invalid CRAM-MD5 server step %d", text->state); 456 #else 457 sparams->utils->log(NULL, SASL_LOG_ERR, 458 "Invalid CRAM-MD5 server step %d\n", text->state); 459 #endif /* _SUN_SDK_ */ 460 return SASL_FAIL; 461 } 462 463 #ifndef _SUN_SDK_ 464 return SASL_FAIL; /* should never get here */ 465 #endif /* !_SUN_SDK_ */ 466 } 467 468 static void crammd5_server_mech_dispose(void *conn_context, 469 const sasl_utils_t *utils) 470 { 471 server_context_t *text = (server_context_t *) conn_context; 472 473 if (!text) return; 474 475 if (text->challenge) _plug_free_string(utils,&(text->challenge)); 476 477 utils->free(text); 478 } 479 480 static sasl_server_plug_t crammd5_server_plugins[] = 481 { 482 { 483 "CRAM-MD5", /* mech_name */ 484 0, /* max_ssf */ 485 SASL_SEC_NOPLAINTEXT 486 | SASL_SEC_NOANONYMOUS, /* security_flags */ 487 SASL_FEAT_SERVER_FIRST, /* features */ 488 NULL, /* glob_context */ 489 &crammd5_server_mech_new, /* mech_new */ 490 &crammd5_server_mech_step, /* mech_step */ 491 &crammd5_server_mech_dispose, /* mech_dispose */ 492 NULL, /* mech_free */ 493 NULL, /* setpass */ 494 NULL, /* user_query */ 495 NULL, /* idle */ 496 NULL, /* mech avail */ 497 NULL /* spare */ 498 } 499 }; 500 501 int crammd5_server_plug_init(const sasl_utils_t *utils, 502 int maxversion, 503 int *out_version, 504 sasl_server_plug_t **pluglist, 505 int *plugcount) 506 { 507 if (maxversion < SASL_SERVER_PLUG_VERSION) { 508 #ifdef _SUN_SDK_ 509 utils->log(NULL, SASL_LOG_ERR, "CRAM version mismatch"); 510 #else 511 SETERROR( utils, "CRAM version mismatch"); 512 #endif /* _SUN_SDK_ */ 513 return SASL_BADVERS; 514 } 515 516 *out_version = SASL_SERVER_PLUG_VERSION; 517 *pluglist = crammd5_server_plugins; 518 *plugcount = 1; 519 520 return SASL_OK; 521 } 522 523 /***************************** Client Section *****************************/ 524 525 typedef struct client_context { 526 char *out_buf; 527 unsigned out_buf_len; 528 #ifdef _INTEGRATED_SOLARIS_ 529 void *h; 530 #endif /* _INTEGRATED_SOLARIS_ */ 531 } client_context_t; 532 533 static int crammd5_client_mech_new(void *glob_context __attribute__((unused)), 534 sasl_client_params_t *params, 535 void **conn_context) 536 { 537 client_context_t *text; 538 539 /* holds state are in */ 540 text = params->utils->malloc(sizeof(client_context_t)); 541 if (text == NULL) { 542 MEMERROR(params->utils); 543 return SASL_NOMEM; 544 } 545 546 memset(text, 0, sizeof(client_context_t)); 547 548 *conn_context = text; 549 550 return SASL_OK; 551 } 552 553 static char *make_hashed(sasl_secret_t *sec, char *nonce, int noncelen, 554 const sasl_utils_t *utils) 555 { 556 char secret[65]; 557 unsigned char digest[24]; 558 int lup; 559 char *in16; 560 561 if (sec == NULL) return NULL; 562 563 if (sec->len < 64) { 564 memcpy(secret, sec->data, sec->len); 565 566 /* fill in rest with 0's */ 567 for (lup= sec->len; lup < 64; lup++) 568 secret[lup]='\0'; 569 570 } else { 571 memcpy(secret, sec->data, 64); 572 } 573 574 /* do the hmac md5 hash output 128 bits */ 575 utils->hmac_md5((unsigned char *) nonce, noncelen, 576 (unsigned char *) secret, 64, digest); 577 578 /* convert that to hex form */ 579 in16 = convert16(digest, 16, utils); 580 if (in16 == NULL) return NULL; 581 582 return in16; 583 } 584 585 static int crammd5_client_mech_step(void *conn_context, 586 sasl_client_params_t *params, 587 const char *serverin, 588 unsigned serverinlen, 589 sasl_interact_t **prompt_need, 590 const char **clientout, 591 unsigned *clientoutlen, 592 sasl_out_params_t *oparams) 593 { 594 client_context_t *text = (client_context_t *) conn_context; 595 const char *authid; 596 sasl_secret_t *password = NULL; 597 unsigned int free_password = 0; /* set if we need to free password */ 598 int auth_result = SASL_OK; 599 int pass_result = SASL_OK; 600 int result; 601 int maxsize; 602 char *in16 = NULL; 603 604 *clientout = NULL; 605 *clientoutlen = 0; 606 607 /* First check for absurd lengths */ 608 if (serverinlen > 1024) { 609 #ifdef _SUN_SDK_ 610 params->utils->log(params->utils->conn, SASL_LOG_ERR, 611 "CRAM-MD5 input longer than 1024 bytes"); 612 #else 613 params->utils->seterror(params->utils->conn, 0, 614 "CRAM-MD5 input longer than 1024 bytes"); 615 #endif /* _SUN_SDK_ */ 616 return SASL_BADPROT; 617 } 618 619 /* check if sec layer strong enough */ 620 if (params->props.min_ssf > params->external_ssf) { 621 #ifdef _SUN_SDK_ 622 params->utils->log(params->utils->conn, SASL_LOG_ERR, 623 "SSF requested of CRAM-MD5 plugin"); 624 #else 625 SETERROR( params->utils, "SSF requested of CRAM-MD5 plugin"); 626 #endif /* _SUN_SDK_ */ 627 return SASL_TOOWEAK; 628 } 629 630 /* try to get the userid */ 631 if (oparams->authid == NULL) { 632 auth_result=_plug_get_authid(params->utils, &authid, prompt_need); 633 634 if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT)) 635 return auth_result; 636 } 637 638 /* try to get the password */ 639 if (password == NULL) { 640 pass_result=_plug_get_password(params->utils, &password, 641 &free_password, prompt_need); 642 643 if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT)) 644 return pass_result; 645 } 646 647 /* free prompts we got */ 648 if (prompt_need && *prompt_need) { 649 params->utils->free(*prompt_need); 650 *prompt_need = NULL; 651 } 652 653 /* if there are prompts not filled in */ 654 if ((auth_result == SASL_INTERACT) || (pass_result == SASL_INTERACT)) { 655 /* make the prompt list */ 656 result = 657 #ifdef _INTEGRATED_SOLARIS_ 658 _plug_make_prompts(params->utils, &text->h, prompt_need, 659 NULL, NULL, 660 auth_result == SASL_INTERACT ? 661 convert_prompt(params->utils, &text->h, 662 gettext("Please enter your authentication name")) 663 : NULL, NULL, 664 pass_result == SASL_INTERACT ? 665 convert_prompt(params->utils, &text->h, 666 gettext("Please enter your password")) 667 : NULL, NULL, 668 NULL, NULL, NULL, 669 NULL, NULL, NULL); 670 #else 671 _plug_make_prompts(params->utils, prompt_need, 672 NULL, NULL, 673 auth_result == SASL_INTERACT ? 674 "Please enter your authentication name" : NULL, 675 NULL, 676 pass_result == SASL_INTERACT ? 677 "Please enter your password" : NULL, NULL, 678 NULL, NULL, NULL, 679 NULL, NULL, NULL); 680 #endif /* _INTEGRATED_SOLARIS_ */ 681 if (result != SASL_OK) goto cleanup; 682 683 return SASL_INTERACT; 684 } 685 686 if (!password) { 687 PARAMERROR(params->utils); 688 return SASL_BADPARAM; 689 } 690 691 result = params->canon_user(params->utils->conn, authid, 0, 692 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); 693 if (result != SASL_OK) goto cleanup; 694 695 /* 696 * username SP digest (keyed md5 where key is passwd) 697 */ 698 699 in16 = make_hashed(password, (char *) serverin, serverinlen, 700 params->utils); 701 702 if (in16 == NULL) { 703 #ifdef _SUN_SDK_ 704 params->utils->log(params->utils->conn, SASL_LOG_ERR, 705 "make_hashed failed"); 706 #else 707 SETERROR(params->utils, "whoops, make_hashed failed us this time"); 708 #endif /* _SUN_SDK_ */ 709 result = SASL_FAIL; 710 goto cleanup; 711 } 712 713 maxsize = 32+1+strlen(oparams->authid)+30; 714 result = _plug_buf_alloc(params->utils, &(text->out_buf), 715 &(text->out_buf_len), maxsize); 716 if (result != SASL_OK) goto cleanup; 717 718 snprintf(text->out_buf, maxsize, "%s %s", oparams->authid, in16); 719 720 *clientout = text->out_buf; 721 *clientoutlen = strlen(*clientout); 722 723 /* set oparams */ 724 oparams->doneflag = 1; 725 oparams->mech_ssf = 0; 726 oparams->maxoutbuf = 0; 727 oparams->encode_context = NULL; 728 oparams->encode = NULL; 729 oparams->decode_context = NULL; 730 oparams->decode = NULL; 731 oparams->param_version = 0; 732 733 result = SASL_OK; 734 735 cleanup: 736 /* get rid of private information */ 737 if (in16) _plug_free_string(params->utils, &in16); 738 739 /* get rid of all sensitive info */ 740 if (free_password) _plug_free_secret(params-> utils, &password); 741 742 return result; 743 } 744 745 static void crammd5_client_mech_dispose(void *conn_context, 746 const sasl_utils_t *utils) 747 { 748 client_context_t *text = (client_context_t *) conn_context; 749 750 if (!text) return; 751 752 #ifdef _INTEGRATED_SOLARIS_ 753 convert_prompt(utils, &text->h, NULL); 754 #endif /* _INTEGRATED_SOLARIS_ */ 755 if (text->out_buf) utils->free(text->out_buf); 756 757 utils->free(text); 758 } 759 760 static sasl_client_plug_t crammd5_client_plugins[] = 761 { 762 { 763 "CRAM-MD5", /* mech_name */ 764 0, /* max_ssf */ 765 SASL_SEC_NOPLAINTEXT 766 | SASL_SEC_NOANONYMOUS, /* security_flags */ 767 SASL_FEAT_SERVER_FIRST, /* features */ 768 NULL, /* required_prompts */ 769 NULL, /* glob_context */ 770 &crammd5_client_mech_new, /* mech_new */ 771 &crammd5_client_mech_step, /* mech_step */ 772 &crammd5_client_mech_dispose, /* mech_dispose */ 773 NULL, /* mech_free */ 774 NULL, /* idle */ 775 NULL, /* spare */ 776 NULL /* spare */ 777 } 778 }; 779 780 int crammd5_client_plug_init(const sasl_utils_t *utils, 781 int maxversion, 782 int *out_version, 783 sasl_client_plug_t **pluglist, 784 int *plugcount) 785 { 786 if (maxversion < SASL_CLIENT_PLUG_VERSION) { 787 #ifdef _SUN_SDK_ 788 utils->log(NULL, SASL_LOG_ERR, "CRAM version mismatch"); 789 #else 790 SETERROR( utils, "CRAM version mismatch"); 791 #endif /* _SUN_SDK_ */ 792 return SASL_BADVERS; 793 } 794 795 *out_version = SASL_CLIENT_PLUG_VERSION; 796 *pluglist = crammd5_client_plugins; 797 *plugcount = 1; 798 799 return SASL_OK; 800 } 801