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