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 /* Generic SASL plugin utility functions 8 * Rob Siemborski 9 * $Id: plugin_common.c,v 1.13 2003/02/13 19:56:05 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 #ifndef macintosh 53 #ifdef WIN32 54 # include <winsock.h> 55 #else 56 # include <sys/socket.h> 57 # include <netinet/in.h> 58 # include <arpa/inet.h> 59 # include <netdb.h> 60 #endif /* WIN32 */ 61 #endif /* macintosh */ 62 #ifdef HAVE_UNISTD_H 63 #include <unistd.h> 64 #endif 65 #include <fcntl.h> 66 #include <sasl.h> 67 #include <saslutil.h> 68 #include <saslplug.h> 69 70 #include <errno.h> 71 #include <ctype.h> 72 73 #ifdef HAVE_INTTYPES_H 74 #include <inttypes.h> 75 #endif 76 77 #include "plugin_common.h" 78 79 /* translate IPv4 mapped IPv6 address to IPv4 address */ 80 static void sockaddr_unmapped( 81 #ifdef IN6_IS_ADDR_V4MAPPED 82 struct sockaddr *sa, socklen_t *len 83 #else 84 struct sockaddr *sa __attribute__((unused)), 85 socklen_t *len __attribute__((unused)) 86 #endif 87 ) 88 { 89 #ifdef IN6_IS_ADDR_V4MAPPED 90 struct sockaddr_in6 *sin6; 91 struct sockaddr_in *sin4; 92 uint32_t addr; 93 #ifdef _SUN_SDK_ 94 in_port_t port; 95 #else 96 int port; 97 #endif /* _SUN_SDK_ */ 98 99 if (sa->sa_family != AF_INET6) 100 return; 101 /* LINTED pointer alignment */ 102 sin6 = (struct sockaddr_in6 *)sa; 103 if (!IN6_IS_ADDR_V4MAPPED((&sin6->sin6_addr))) 104 return; 105 /* LINTED pointer alignment */ 106 sin4 = (struct sockaddr_in *)sa; 107 /* LINTED pointer alignment */ 108 addr = *(uint32_t *)&sin6->sin6_addr.s6_addr[12]; 109 port = sin6->sin6_port; 110 memset(sin4, 0, sizeof(struct sockaddr_in)); 111 sin4->sin_addr.s_addr = addr; 112 sin4->sin_port = port; 113 sin4->sin_family = AF_INET; 114 #ifdef HAVE_SOCKADDR_SA_LEN 115 sin4->sin_len = sizeof(struct sockaddr_in); 116 #endif 117 *len = sizeof(struct sockaddr_in); 118 #else 119 return; 120 #endif 121 } 122 123 int _plug_ipfromstring(const sasl_utils_t *utils, const char *addr, 124 struct sockaddr *out, socklen_t outlen) 125 { 126 int i, j; 127 socklen_t len; 128 #ifdef WINNT /* _SUN_SDK_ */ 129 struct sockaddr_in ss; 130 #else 131 struct sockaddr_storage ss; 132 #endif /* _SUN_SDK_ */ 133 struct addrinfo hints, *ai = NULL; 134 char hbuf[NI_MAXHOST]; 135 #ifdef _SUN_SDK_ 136 const char *start, *end, *p; 137 #endif /* _SUN_SDK_ */ 138 139 if(!utils || !addr || !out) { 140 if(utils) PARAMERROR( utils ); 141 return SASL_BADPARAM; 142 } 143 144 #ifdef _SUN_SDK_ 145 end = strchr(addr, ']'); 146 if (end != NULL) { 147 /* This an rfc 2732 ipv6 address */ 148 start = strchr(addr, '['); 149 if (start >= end || start == NULL) { 150 if(utils) PARAMERROR( utils ); 151 return SASL_BADPARAM; 152 } 153 for (i = 0, p = start + 1; p < end; p++) { 154 hbuf[i++] = *p; 155 if (i >= NI_MAXHOST) 156 break; 157 } 158 p = strchr(end, ':'); 159 if (p == NULL) 160 p = end + 1; 161 else 162 p = p + 1; 163 } else { 164 for (i = 0; addr[i] != '\0' && addr[i] != ';'; ) { 165 hbuf[i] = addr[i]; 166 if (++i >= NI_MAXHOST) 167 break; 168 } 169 if (addr[i] == ';') 170 p = &addr[i+1]; 171 else 172 p = &addr[i]; 173 } 174 if (i >= NI_MAXHOST) { 175 if(utils) PARAMERROR( utils ); 176 return SASL_BADPARAM; 177 } 178 hbuf[i] = '\0'; 179 for (j = 0; p[j] != '\0'; j++) 180 if (!isdigit((int)(p[j]))) { 181 PARAMERROR( utils ); 182 return SASL_BADPARAM; 183 } 184 #else 185 /* Parse the address */ 186 for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) { 187 if (i >= NI_MAXHOST) { 188 if(utils) PARAMERROR( utils ); 189 return SASL_BADPARAM; 190 } 191 hbuf[i] = addr[i]; 192 } 193 hbuf[i] = '\0'; 194 195 if (addr[i] == ';') 196 i++; 197 /* XXX/FIXME: Do we need this check? */ 198 for (j = i; addr[j] != '\0'; j++) 199 if (!isdigit((int)(addr[j]))) { 200 PARAMERROR( utils ); 201 return SASL_BADPARAM; 202 } 203 #endif /* _SUN_SDK_ */ 204 205 memset(&hints, 0, sizeof(hints)); 206 hints.ai_family = PF_UNSPEC; 207 hints.ai_socktype = SOCK_STREAM; 208 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 209 210 #ifdef _SUN_SDK_ 211 if (getaddrinfo(hbuf, p, &hints, &ai) != 0) { 212 #else 213 if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0) { 214 #endif /* _SUN_SDK_ */ 215 PARAMERROR( utils ); 216 return SASL_BADPARAM; 217 } 218 219 len = ai->ai_addrlen; 220 #ifdef _SUN_SDK_ 221 if (len > sizeof(ss)) 222 return (SASL_BUFOVER); 223 #endif /* _SUN_SDK_ */ 224 memcpy(&ss, ai->ai_addr, len); 225 freeaddrinfo(ai); 226 sockaddr_unmapped((struct sockaddr *)&ss, &len); 227 if (outlen < len) { 228 PARAMERROR( utils ); 229 return SASL_BUFOVER; 230 } 231 232 memcpy(out, &ss, len); 233 234 return SASL_OK; 235 } 236 237 int _plug_iovec_to_buf(const sasl_utils_t *utils, const struct iovec *vec, 238 unsigned numiov, buffer_info_t **output) 239 { 240 unsigned i; 241 int ret; 242 buffer_info_t *out; 243 char *pos; 244 245 if(!utils || !vec || !output) { 246 if(utils) PARAMERROR( utils ); 247 return SASL_BADPARAM; 248 } 249 250 if(!(*output)) { 251 *output = utils->malloc(sizeof(buffer_info_t)); 252 if(!*output) { 253 MEMERROR(utils); 254 return SASL_NOMEM; 255 } 256 memset(*output,0,sizeof(buffer_info_t)); 257 } 258 259 out = *output; 260 261 out->curlen = 0; 262 for(i=0; i<numiov; i++) 263 out->curlen += vec[i].iov_len; 264 265 ret = _plug_buf_alloc(utils, &out->data, &out->reallen, out->curlen); 266 267 if(ret != SASL_OK) { 268 MEMERROR(utils); 269 return SASL_NOMEM; 270 } 271 272 memset(out->data, 0, out->reallen); 273 pos = out->data; 274 275 for(i=0; i<numiov; i++) { 276 memcpy(pos, vec[i].iov_base, vec[i].iov_len); 277 pos += vec[i].iov_len; 278 } 279 280 return SASL_OK; 281 } 282 283 /* Basically a conditional call to realloc(), if we need more */ 284 int _plug_buf_alloc(const sasl_utils_t *utils, char **rwbuf, 285 unsigned *curlen, unsigned newlen) 286 { 287 if(!utils || !rwbuf || !curlen) { 288 PARAMERROR(utils); 289 return SASL_BADPARAM; 290 } 291 292 if(!(*rwbuf)) { 293 *rwbuf = utils->malloc(newlen); 294 if (*rwbuf == NULL) { 295 *curlen = 0; 296 MEMERROR(utils); 297 return SASL_NOMEM; 298 } 299 *curlen = newlen; 300 } else if(*rwbuf && *curlen < newlen) { 301 #ifdef _SUN_SDK_ 302 unsigned needed = 2*(*curlen); 303 #else 304 size_t needed = 2*(*curlen); 305 #endif /* _SUN_SDK_ */ 306 307 while(needed < newlen) 308 needed *= 2; 309 310 *rwbuf = utils->realloc(*rwbuf, needed); 311 if (*rwbuf == NULL) { 312 *curlen = 0; 313 MEMERROR(utils); 314 return SASL_NOMEM; 315 } 316 *curlen = needed; 317 } 318 319 return SASL_OK; 320 } 321 322 /* copy a string */ 323 int _plug_strdup(const sasl_utils_t * utils, const char *in, 324 char **out, int *outlen) 325 { 326 #ifdef _SUN_SDK_ 327 int len; 328 #else 329 size_t len = strlen(in); 330 #endif /* _SUN_SDK_ */ 331 332 if(!utils || !in || !out) { 333 if(utils) PARAMERROR(utils); 334 return SASL_BADPARAM; 335 } 336 337 #ifdef _SUN_SDK_ 338 len = strlen(in); 339 #endif /* _SUN_SDK_ */ 340 *out = utils->malloc(len + 1); 341 if (!*out) { 342 MEMERROR(utils); 343 return SASL_NOMEM; 344 } 345 346 strcpy((char *) *out, in); 347 348 if (outlen) 349 *outlen = len; 350 351 return SASL_OK; 352 } 353 354 void _plug_free_string(const sasl_utils_t *utils, char **str) 355 { 356 size_t len; 357 358 if (!utils || !str || !(*str)) return; 359 360 len = strlen(*str); 361 362 utils->erasebuffer(*str, len); 363 utils->free(*str); 364 365 *str=NULL; 366 } 367 368 void _plug_free_secret(const sasl_utils_t *utils, sasl_secret_t **secret) 369 { 370 if(!utils || !secret || !(*secret)) return; 371 372 #ifdef _SUN_SDK_ 373 utils->erasebuffer((char *)(*secret)->data, (*secret)->len); 374 #else 375 utils->erasebuffer((*secret)->data, (*secret)->len); 376 #endif /* _SUN_SDK_ */ 377 utils->free(*secret); 378 *secret = NULL; 379 } 380 381 /* 382 * Trys to find the prompt with the lookingfor id in the prompt list 383 * Returns it if found. NULL otherwise 384 */ 385 sasl_interact_t *_plug_find_prompt(sasl_interact_t **promptlist, 386 unsigned int lookingfor) 387 { 388 sasl_interact_t *prompt; 389 390 if (promptlist && *promptlist) { 391 for (prompt = *promptlist; prompt->id != SASL_CB_LIST_END; ++prompt) { 392 if (prompt->id==lookingfor) 393 return prompt; 394 } 395 } 396 397 return NULL; 398 } 399 400 /* 401 * Retrieve the simple string given by the callback id. 402 */ 403 int _plug_get_simple(const sasl_utils_t *utils, unsigned int id, int required, 404 const char **result, sasl_interact_t **prompt_need) 405 { 406 407 int ret = SASL_FAIL; 408 sasl_getsimple_t *simple_cb; 409 void *simple_context; 410 sasl_interact_t *prompt; 411 412 *result = NULL; 413 414 /* see if we were given the result in the prompt */ 415 prompt = _plug_find_prompt(prompt_need, id); 416 if (prompt != NULL) { 417 /* We prompted, and got.*/ 418 419 if (required && !prompt->result) { 420 SETERROR(utils, "Unexpectedly missing a prompt result"); 421 return SASL_BADPARAM; 422 } 423 424 *result = prompt->result; 425 return SASL_OK; 426 } 427 428 /* Try to get the callback... */ 429 ret = utils->getcallback(utils->conn, id, &simple_cb, &simple_context); 430 431 if (ret == SASL_FAIL && !required) 432 return SASL_OK; 433 434 if (ret == SASL_OK && simple_cb) { 435 ret = simple_cb(simple_context, id, result, NULL); 436 if (ret != SASL_OK) 437 return ret; 438 439 if (required && !*result) { 440 PARAMERROR(utils); 441 return SASL_BADPARAM; 442 } 443 } 444 445 return ret; 446 } 447 448 /* 449 * Retrieve the user password. 450 */ 451 int _plug_get_password(const sasl_utils_t *utils, sasl_secret_t **password, 452 unsigned int *iscopy, sasl_interact_t **prompt_need) 453 { 454 int ret = SASL_FAIL; 455 sasl_getsecret_t *pass_cb; 456 void *pass_context; 457 sasl_interact_t *prompt; 458 459 *password = NULL; 460 *iscopy = 0; 461 462 /* see if we were given the password in the prompt */ 463 prompt = _plug_find_prompt(prompt_need, SASL_CB_PASS); 464 if (prompt != NULL) { 465 /* We prompted, and got.*/ 466 467 if (!prompt->result) { 468 SETERROR(utils, "Unexpectedly missing a prompt result"); 469 return SASL_BADPARAM; 470 } 471 472 /* copy what we got into a secret_t */ 473 *password = (sasl_secret_t *) utils->malloc(sizeof(sasl_secret_t) + 474 prompt->len + 1); 475 if (!*password) { 476 MEMERROR(utils); 477 return SASL_NOMEM; 478 } 479 480 (*password)->len=prompt->len; 481 memcpy((*password)->data, prompt->result, prompt->len); 482 (*password)->data[(*password)->len]=0; 483 484 *iscopy = 1; 485 486 return SASL_OK; 487 } 488 489 /* Try to get the callback... */ 490 ret = utils->getcallback(utils->conn, SASL_CB_PASS, 491 &pass_cb, &pass_context); 492 493 if (ret == SASL_OK && pass_cb) { 494 ret = pass_cb(utils->conn, pass_context, SASL_CB_PASS, password); 495 if (ret != SASL_OK) 496 return ret; 497 498 if (!*password) { 499 PARAMERROR(utils); 500 return SASL_BADPARAM; 501 } 502 } 503 504 return ret; 505 } 506 507 /* 508 * Retrieve the string given by the challenge prompt id. 509 */ 510 int _plug_challenge_prompt(const sasl_utils_t *utils, unsigned int id, 511 const char *challenge, const char *promptstr, 512 const char **result, sasl_interact_t **prompt_need) 513 { 514 int ret = SASL_FAIL; 515 sasl_chalprompt_t *chalprompt_cb; 516 void *chalprompt_context; 517 sasl_interact_t *prompt; 518 519 *result = NULL; 520 521 /* see if we were given the password in the prompt */ 522 prompt = _plug_find_prompt(prompt_need, id); 523 if (prompt != NULL) { 524 /* We prompted, and got.*/ 525 526 if (!prompt->result) { 527 SETERROR(utils, "Unexpectedly missing a prompt result"); 528 return SASL_BADPARAM; 529 } 530 531 *result = prompt->result; 532 return SASL_OK; 533 } 534 535 /* Try to get the callback... */ 536 ret = utils->getcallback(utils->conn, id, 537 &chalprompt_cb, &chalprompt_context); 538 539 if (ret == SASL_OK && chalprompt_cb) { 540 ret = chalprompt_cb(chalprompt_context, id, 541 challenge, promptstr, NULL, result, NULL); 542 if (ret != SASL_OK) 543 return ret; 544 545 if (!*result) { 546 PARAMERROR(utils); 547 return SASL_BADPARAM; 548 } 549 } 550 551 return ret; 552 } 553 554 /* 555 * Retrieve the client realm. 556 */ 557 int _plug_get_realm(const sasl_utils_t *utils, const char **availrealms, 558 const char **realm, sasl_interact_t **prompt_need) 559 { 560 int ret = SASL_FAIL; 561 sasl_getrealm_t *realm_cb; 562 void *realm_context; 563 sasl_interact_t *prompt; 564 565 *realm = NULL; 566 567 /* see if we were given the result in the prompt */ 568 prompt = _plug_find_prompt(prompt_need, SASL_CB_GETREALM); 569 if (prompt != NULL) { 570 /* We prompted, and got.*/ 571 572 if (!prompt->result) { 573 SETERROR(utils, "Unexpectedly missing a prompt result"); 574 return SASL_BADPARAM; 575 } 576 577 *realm = prompt->result; 578 return SASL_OK; 579 } 580 581 /* Try to get the callback... */ 582 ret = utils->getcallback(utils->conn, SASL_CB_GETREALM, 583 &realm_cb, &realm_context); 584 585 if (ret == SASL_OK && realm_cb) { 586 ret = realm_cb(realm_context, SASL_CB_GETREALM, availrealms, realm); 587 if (ret != SASL_OK) 588 return ret; 589 590 if (!*realm) { 591 PARAMERROR(utils); 592 return SASL_BADPARAM; 593 } 594 } 595 596 return ret; 597 } 598 599 /* 600 * Make the requested prompts. (prompt==NULL means we don't want it) 601 */ 602 int _plug_make_prompts(const sasl_utils_t *utils, 603 #ifdef _INTEGRATED_SOLARIS_ 604 void **h, 605 #endif /* _INTEGRATED_SOLARIS_ */ 606 sasl_interact_t **prompts_res, 607 const char *user_prompt, const char *user_def, 608 const char *auth_prompt, const char *auth_def, 609 const char *pass_prompt, const char *pass_def, 610 const char *echo_chal, 611 const char *echo_prompt, const char *echo_def, 612 const char *realm_chal, 613 const char *realm_prompt, const char *realm_def) 614 { 615 int num = 1; 616 int alloc_size; 617 sasl_interact_t *prompts; 618 619 if (user_prompt) num++; 620 if (auth_prompt) num++; 621 if (pass_prompt) num++; 622 if (echo_prompt) num++; 623 if (realm_prompt) num++; 624 625 if (num == 1) { 626 SETERROR( utils, "make_prompts() called with no actual prompts" ); 627 return SASL_FAIL; 628 } 629 630 alloc_size = sizeof(sasl_interact_t)*num; 631 prompts = utils->malloc(alloc_size); 632 if (!prompts) { 633 MEMERROR( utils ); 634 return SASL_NOMEM; 635 } 636 memset(prompts, 0, alloc_size); 637 638 *prompts_res = prompts; 639 640 if (user_prompt) { 641 (prompts)->id = SASL_CB_USER; 642 #ifdef _INTEGRATED_SOLARIS_ 643 (prompts)->challenge = convert_prompt(utils, h, 644 gettext("Authorization Name")); 645 #else 646 (prompts)->challenge = "Authorization Name"; 647 #endif /* _INTEGRATED_SOLARIS_ */ 648 (prompts)->prompt = user_prompt; 649 (prompts)->defresult = user_def; 650 651 prompts++; 652 } 653 654 if (auth_prompt) { 655 (prompts)->id = SASL_CB_AUTHNAME; 656 #ifdef _INTEGRATED_SOLARIS_ 657 (prompts)->challenge = convert_prompt(utils, h, 658 gettext( "Authentication Name")); 659 #else 660 (prompts)->challenge = "Authentication Name"; 661 #endif /* _INTEGRATED_SOLARIS_ */ 662 (prompts)->prompt = auth_prompt; 663 (prompts)->defresult = auth_def; 664 665 prompts++; 666 } 667 668 if (pass_prompt) { 669 (prompts)->id = SASL_CB_PASS; 670 #ifdef _INTEGRATED_SOLARIS_ 671 (prompts)->challenge = convert_prompt(utils, h, gettext("Password")); 672 #else 673 (prompts)->challenge = "Password"; 674 #endif /* _INTEGRATED_SOLARIS_ */ 675 (prompts)->prompt = pass_prompt; 676 (prompts)->defresult = pass_def; 677 678 prompts++; 679 } 680 681 if (echo_prompt) { 682 (prompts)->id = SASL_CB_ECHOPROMPT; 683 (prompts)->challenge = echo_chal; 684 (prompts)->prompt = echo_prompt; 685 (prompts)->defresult = echo_def; 686 687 prompts++; 688 } 689 690 if (realm_prompt) { 691 (prompts)->id = SASL_CB_GETREALM; 692 (prompts)->challenge = realm_chal; 693 (prompts)->prompt = realm_prompt; 694 (prompts)->defresult = realm_def; 695 696 prompts++; 697 } 698 699 /* add the ending one */ 700 (prompts)->id = SASL_CB_LIST_END; 701 (prompts)->challenge = NULL; 702 (prompts)->prompt = NULL; 703 (prompts)->defresult = NULL; 704 705 return SASL_OK; 706 } 707 708 /* 709 * Decode and concatenate multiple packets using the given function 710 * to decode each packet. 711 */ 712 int _plug_decode(const sasl_utils_t *utils, 713 void *context, 714 const char *input, unsigned inputlen, 715 char **output, /* output buffer */ 716 unsigned *outputsize, /* current size of output buffer */ 717 unsigned *outputlen, /* length of data in output buffer */ 718 int (*decode_pkt)(void *context, 719 const char **input, unsigned *inputlen, 720 char **output, unsigned *outputlen)) 721 { 722 char *tmp = NULL; 723 unsigned tmplen = 0; 724 int ret; 725 726 *outputlen = 0; 727 728 while (inputlen!=0) 729 { 730 /* no need to free tmp */ 731 ret = decode_pkt(context, &input, &inputlen, &tmp, &tmplen); 732 733 if(ret != SASL_OK) return ret; 734 735 if (tmp!=NULL) /* if received 2 packets merge them together */ 736 { 737 ret = _plug_buf_alloc(utils, output, outputsize, 738 *outputlen + tmplen + 1); 739 if(ret != SASL_OK) return ret; 740 741 memcpy(*output + *outputlen, tmp, tmplen); 742 743 /* Protect stupid clients */ 744 *(*output + *outputlen + tmplen) = '\0'; 745 746 *outputlen+=tmplen; 747 } 748 } 749 750 return SASL_OK; 751 } 752 753 /* returns the realm we should pretend to be in */ 754 int _plug_parseuser(const sasl_utils_t *utils, 755 char **user, char **realm, const char *user_realm, 756 const char *serverFQDN, const char *input) 757 { 758 int ret; 759 #ifdef _SUN_SDK_ 760 const char *r; 761 #else 762 char *r; 763 #endif /* _SUN_SDK_ */ 764 765 if(!user || !serverFQDN) { 766 PARAMERROR( utils ); 767 return SASL_BADPARAM; 768 } 769 770 r = strchr(input, '@'); 771 if (!r) { 772 /* hmmm, the user didn't specify a realm */ 773 if(user_realm && user_realm[0]) { 774 ret = _plug_strdup(utils, user_realm, realm, NULL); 775 } else { 776 /* Default to serverFQDN */ 777 ret = _plug_strdup(utils, serverFQDN, realm, NULL); 778 } 779 780 if (ret == SASL_OK) { 781 ret = _plug_strdup(utils, input, user, NULL); 782 } 783 } else { 784 r++; 785 ret = _plug_strdup(utils, r, realm, NULL); 786 #ifdef _SUN_SDK_ 787 if (ret == SASL_OK) { 788 *user = utils->malloc(r - input); 789 if (*user) { 790 memcpy(*user, input, r - input - 1); 791 (*user)[r - input - 1] = '\0'; 792 } else { 793 MEMERROR( utils ); 794 ret = SASL_NOMEM; 795 } 796 } 797 #else 798 *--r = '\0'; 799 *user = utils->malloc(r - input + 1); 800 if (*user) { 801 strncpy(*user, input, r - input +1); 802 } else { 803 MEMERROR( utils ); 804 ret = SASL_NOMEM; 805 } 806 *r = '@'; 807 #endif /* _SUN_SDK_ */ 808 } 809 810 return ret; 811 } 812 813 #ifdef _INTEGRATED_SOLARIS_ 814 int 815 use_locale(const char *lang_list, int is_client) 816 { 817 const char *s; 818 const char *begin; 819 const char *end; 820 const char *i_default = "i-default"; 821 const int i_default_len = 9; 822 823 if (lang_list == NULL) 824 return is_client; 825 826 begin = lang_list; 827 828 for (;;) { 829 /* skip over leading whitespace and commas */ 830 while (isspace(*begin) || *begin == ',') 831 begin++; 832 if (*begin == '\0') 833 break; 834 835 /* Find the end of the language tag */ 836 for (end = begin; end[1] != ',' && end[1] != '\0'; end++) {} 837 838 for (s = end; isspace(*s); s--) {} 839 840 if (s == begin && *begin == '*') 841 return 1; 842 843 if (s - begin == (i_default_len - 1) && 844 strncasecmp(begin, i_default, i_default_len) == 0) 845 return 0; 846 847 begin = end + 1; 848 } 849 850 return is_client; 851 } 852 853 typedef struct prompt_list { 854 char *prompt; 855 struct prompt_list *next; 856 } prompt_list; 857 858 const char * 859 convert_prompt(const sasl_utils_t *utils, void **h, const char *s) 860 { 861 sasl_getsimple_t *simple_cb; 862 void *simple_context; 863 const char *result = NULL; 864 const char *s_locale; 865 int ret; 866 char *buf; 867 const char *ret_buf; 868 prompt_list *list; 869 prompt_list *next; 870 871 if (utils == NULL || utils->conn == NULL) 872 return s; 873 874 if (s == NULL) { 875 for (list = (prompt_list *)*h; list != NULL; list = next) { 876 if (list->prompt) 877 utils->free(list->prompt); 878 next = list->next; 879 utils->free(list); 880 } 881 *h = NULL; 882 return NULL; 883 } 884 885 ret = utils->getcallback(utils->conn, SASL_CB_LANGUAGE, &simple_cb, 886 &simple_context); 887 888 if (ret == SASL_OK && simple_cb) { 889 ret = simple_cb(simple_context, SASL_CB_LANGUAGE, &result, NULL); 890 } else 891 ret = SASL_FAIL; 892 if (ret == SASL_OK && !use_locale(result, 1)) 893 return s; 894 895 s_locale = dgettext(TEXT_DOMAIN, s); 896 if (s == s_locale) { 897 return s; 898 } 899 900 buf = local_to_utf(utils, s_locale); 901 902 if (buf != NULL) { 903 list = utils->malloc(sizeof (prompt_list)); 904 if (list == NULL) { 905 utils->free(buf); 906 buf = NULL; 907 } else { 908 list->prompt = buf; 909 list->next = *h; 910 *h = list; 911 } 912 } 913 914 ret_buf = (buf == NULL) ? s : buf; 915 916 return ret_buf; 917 } 918 919 #include <iconv.h> 920 #include <langinfo.h> 921 922 /* 923 * local_to_utf converts a string in the current codeset to utf-8. 924 * If no codeset is specified, then codeset 646 will be used. 925 * Upon successful completion, this function will return a non-NULL buffer 926 * that is allocated by local_to_utf. 927 * 928 * If utils is NULL, local_to_utf will use the standard memory allocation 929 * functions, otherwise the memory functions defined in sasl_utils_t will 930 * be used. 931 * 932 * local_to_utf will return NULL in the case of any error 933 */ 934 char * 935 local_to_utf(const sasl_utils_t *utils, const char *s) 936 { 937 const char *code_set = nl_langinfo(CODESET); 938 iconv_t cd; 939 char *buf, *tmp; 940 size_t in_len; 941 size_t buf_size; 942 size_t ileft, oleft; 943 const char *inptr; 944 char *outptr; 945 size_t ret; 946 947 if (s == NULL) 948 return NULL; 949 950 if (code_set == NULL) 951 code_set = "646"; 952 953 if (strcasecmp(code_set, "UTF-8") == 0) { 954 if (utils == NULL) 955 buf = strdup(s); 956 else { 957 if (_plug_strdup(utils, s, &buf, NULL) != SASL_OK) 958 buf = NULL; 959 } 960 return buf; 961 } 962 cd = iconv_open("UTF-8", code_set); 963 if (cd == (iconv_t)-1) 964 return NULL; 965 966 in_len = strlen(s); 967 buf_size = 4 * (in_len + 1); /* guess */ 968 969 if (utils == NULL) 970 buf = malloc(buf_size); 971 else 972 buf = utils->malloc(buf_size); 973 974 if (buf == NULL) { 975 (void) iconv_close(cd); 976 return NULL; 977 } 978 inptr = s; 979 ileft = in_len; 980 outptr = buf; 981 oleft = buf_size; 982 for (;;) { 983 ret = iconv(cd, &inptr, &ileft, &outptr, &oleft); 984 if (ret == (size_t)(-1)) { 985 if (errno == E2BIG) { 986 oleft += buf_size; 987 buf_size *= 2; 988 if (utils == NULL) 989 tmp = realloc(buf, buf_size); 990 else 991 tmp = utils->realloc(buf, buf_size); 992 if (tmp == NULL) { 993 oleft = (size_t)(-1); 994 break; 995 } 996 outptr = tmp + (outptr-buf); 997 buf = tmp; 998 continue; 999 } 1000 oleft = (size_t)(-1); 1001 break; 1002 } 1003 if (inptr == NULL) 1004 break; 1005 inptr = NULL; 1006 ileft = 0; 1007 } 1008 if (oleft > 0) { 1009 *outptr = '\0'; 1010 } else if (oleft != (size_t)(-1)) { 1011 if (utils == NULL) 1012 tmp = realloc(buf, buf_size + 1); 1013 else 1014 tmp = utils->realloc(buf, buf_size + 1); 1015 if (tmp == NULL) { 1016 oleft = (size_t)(-1); 1017 } else { 1018 buf = tmp; 1019 buf[buf_size] = '\0'; 1020 } 1021 } 1022 if (oleft == (size_t)(-1)) { 1023 if (utils == NULL) 1024 free(buf); 1025 else 1026 utils->free(buf); 1027 buf = NULL; 1028 } 1029 1030 (void) iconv_close(cd); 1031 return buf; 1032 } 1033 #endif /* _INTEGRATED_SOLARIS_ */ 1034