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