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