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