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 */
sockaddr_unmapped(struct sockaddr * sa,socklen_t * len)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
_plug_ipfromstring(const sasl_utils_t * utils,const char * addr,struct sockaddr * out,socklen_t outlen)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