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