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