xref: /illumos-gate/usr/src/lib/libsasl/lib/client.c (revision 694c35fa)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate /* SASL server API implementation
7*7c478bd9Sstevel@tonic-gate  * Rob Siemborski
8*7c478bd9Sstevel@tonic-gate  * Tim Martin
9*7c478bd9Sstevel@tonic-gate  * $Id: client.c,v 1.61 2003/04/16 19:36:00 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 #include <stdio.h>
53*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
54*7c478bd9Sstevel@tonic-gate #include <limits.h>
55*7c478bd9Sstevel@tonic-gate #include <ctype.h>
56*7c478bd9Sstevel@tonic-gate #include <string.h>
57*7c478bd9Sstevel@tonic-gate #ifdef HAVE_UNISTD_H
58*7c478bd9Sstevel@tonic-gate #include <unistd.h>
59*7c478bd9Sstevel@tonic-gate #endif
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate /* SASL Headers */
62*7c478bd9Sstevel@tonic-gate #include "sasl.h"
63*7c478bd9Sstevel@tonic-gate #include "saslplug.h"
64*7c478bd9Sstevel@tonic-gate #include "saslutil.h"
65*7c478bd9Sstevel@tonic-gate #include "saslint.h"
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
68*7c478bd9Sstevel@tonic-gate DEFINE_STATIC_MUTEX(init_client_mutex);
69*7c478bd9Sstevel@tonic-gate DEFINE_STATIC_MUTEX(client_active_mutex);
70*7c478bd9Sstevel@tonic-gate /*
71*7c478bd9Sstevel@tonic-gate  * client_plug_mutex ensures only one client plugin is init'ed at a time
72*7c478bd9Sstevel@tonic-gate  * If a plugin is loaded more than once, the glob_context may be overwritten
73*7c478bd9Sstevel@tonic-gate  * which may lead to a memory leak. We keep glob_context with each mech
74*7c478bd9Sstevel@tonic-gate  * to avoid this problem.
75*7c478bd9Sstevel@tonic-gate  */
76*7c478bd9Sstevel@tonic-gate DEFINE_STATIC_MUTEX(client_plug_mutex);
77*7c478bd9Sstevel@tonic-gate #else
78*7c478bd9Sstevel@tonic-gate static cmech_list_t *cmechlist; /* global var which holds the list */
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate static sasl_global_callbacks_t global_callbacks;
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate static int _sasl_client_active = 0;
83*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
init_mechlist(_sasl_global_context_t * gctx)86*7c478bd9Sstevel@tonic-gate static int init_mechlist(_sasl_global_context_t *gctx)
87*7c478bd9Sstevel@tonic-gate {
88*7c478bd9Sstevel@tonic-gate   cmech_list_t *cmechlist = gctx->cmechlist;
89*7c478bd9Sstevel@tonic-gate #else
90*7c478bd9Sstevel@tonic-gate static int init_mechlist()
91*7c478bd9Sstevel@tonic-gate {
92*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate   cmechlist->mutex = sasl_MUTEX_ALLOC();
95*7c478bd9Sstevel@tonic-gate   if(!cmechlist->mutex) return SASL_FAIL;
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
98*7c478bd9Sstevel@tonic-gate   cmechlist->utils=
99*7c478bd9Sstevel@tonic-gate 	_sasl_alloc_utils(gctx, NULL, &gctx->client_global_callbacks);
100*7c478bd9Sstevel@tonic-gate #else
101*7c478bd9Sstevel@tonic-gate   cmechlist->utils=_sasl_alloc_utils(NULL, &global_callbacks);
102*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
103*7c478bd9Sstevel@tonic-gate   if (cmechlist->utils==NULL)
104*7c478bd9Sstevel@tonic-gate     return SASL_NOMEM;
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate   cmechlist->mech_list=NULL;
107*7c478bd9Sstevel@tonic-gate   cmechlist->mech_length=0;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate   return SASL_OK;
110*7c478bd9Sstevel@tonic-gate }
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
113*7c478bd9Sstevel@tonic-gate static int client_done(_sasl_global_context_t *gctx) {
114*7c478bd9Sstevel@tonic-gate   cmech_list_t *cmechlist = gctx->cmechlist;
115*7c478bd9Sstevel@tonic-gate   _sasl_path_info_t *path_info, *p;
116*7c478bd9Sstevel@tonic-gate #else
117*7c478bd9Sstevel@tonic-gate static int client_done(void) {
118*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
119*7c478bd9Sstevel@tonic-gate   cmechanism_t *cm;
120*7c478bd9Sstevel@tonic-gate   cmechanism_t *cprevm;
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
123*7c478bd9Sstevel@tonic-gate   if(!gctx->sasl_client_active)
124*7c478bd9Sstevel@tonic-gate       return SASL_NOTINIT;
125*7c478bd9Sstevel@tonic-gate   if (LOCK_MUTEX(&client_active_mutex) < 0) {
126*7c478bd9Sstevel@tonic-gate 	return (SASL_FAIL);
127*7c478bd9Sstevel@tonic-gate   }
128*7c478bd9Sstevel@tonic-gate   gctx->sasl_client_active--;
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate   if(gctx->sasl_client_active) {
131*7c478bd9Sstevel@tonic-gate       /* Don't de-init yet! Our refcount is nonzero. */
132*7c478bd9Sstevel@tonic-gate       UNLOCK_MUTEX(&client_active_mutex);
133*7c478bd9Sstevel@tonic-gate       return SASL_CONTINUE;
134*7c478bd9Sstevel@tonic-gate   }
135*7c478bd9Sstevel@tonic-gate #else
136*7c478bd9Sstevel@tonic-gate   if(!_sasl_client_active)
137*7c478bd9Sstevel@tonic-gate       return SASL_NOTINIT;
138*7c478bd9Sstevel@tonic-gate   else
139*7c478bd9Sstevel@tonic-gate       _sasl_client_active--;
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate   if(_sasl_client_active) {
142*7c478bd9Sstevel@tonic-gate       /* Don't de-init yet! Our refcount is nonzero. */
143*7c478bd9Sstevel@tonic-gate       return SASL_CONTINUE;
144*7c478bd9Sstevel@tonic-gate   }
145*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate   cm=cmechlist->mech_list; /* m point to begging of the list */
148*7c478bd9Sstevel@tonic-gate   while (cm!=NULL)
149*7c478bd9Sstevel@tonic-gate   {
150*7c478bd9Sstevel@tonic-gate     cprevm=cm;
151*7c478bd9Sstevel@tonic-gate     cm=cm->next;
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate     if (cprevm->plug->mech_free) {
154*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
155*7c478bd9Sstevel@tonic-gate 	cprevm->plug->mech_free(cprevm->glob_context, cmechlist->utils);
156*7c478bd9Sstevel@tonic-gate #else
157*7c478bd9Sstevel@tonic-gate 	cprevm->plug->mech_free(cprevm->plug->glob_context,
158*7c478bd9Sstevel@tonic-gate 				cmechlist->utils);
159*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
160*7c478bd9Sstevel@tonic-gate     }
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate     sasl_FREE(cprevm->plugname);
163*7c478bd9Sstevel@tonic-gate     sasl_FREE(cprevm);
164*7c478bd9Sstevel@tonic-gate   }
165*7c478bd9Sstevel@tonic-gate   sasl_MUTEX_FREE(cmechlist->mutex);
166*7c478bd9Sstevel@tonic-gate   _sasl_free_utils(&cmechlist->utils);
167*7c478bd9Sstevel@tonic-gate   sasl_FREE(cmechlist);
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
170*7c478bd9Sstevel@tonic-gate   gctx->cmechlist = NULL;
171*7c478bd9Sstevel@tonic-gate   p = gctx->cplug_path_info;
172*7c478bd9Sstevel@tonic-gate   while((path_info = p) != NULL) {
173*7c478bd9Sstevel@tonic-gate     sasl_FREE(path_info->path);
174*7c478bd9Sstevel@tonic-gate     p = path_info->next;
175*7c478bd9Sstevel@tonic-gate     sasl_FREE(path_info);
176*7c478bd9Sstevel@tonic-gate   }
177*7c478bd9Sstevel@tonic-gate   gctx->cplug_path_info = NULL;
178*7c478bd9Sstevel@tonic-gate   UNLOCK_MUTEX(&client_active_mutex);
179*7c478bd9Sstevel@tonic-gate #else
180*7c478bd9Sstevel@tonic-gate   cmechlist = NULL;
181*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate   return SASL_OK;
184*7c478bd9Sstevel@tonic-gate }
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate int sasl_client_add_plugin(const char *plugname,
187*7c478bd9Sstevel@tonic-gate 			   sasl_client_plug_init_t *entry_point)
188*7c478bd9Sstevel@tonic-gate {
189*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
190*7c478bd9Sstevel@tonic-gate     return (_sasl_client_add_plugin(_sasl_gbl_ctx(), plugname, entry_point));
191*7c478bd9Sstevel@tonic-gate }
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate int _sasl_client_add_plugin(void *ctx,
194*7c478bd9Sstevel@tonic-gate                             const char *plugname,
195*7c478bd9Sstevel@tonic-gate                             sasl_client_plug_init_t *entry_point)
196*7c478bd9Sstevel@tonic-gate {
197*7c478bd9Sstevel@tonic-gate   cmech_list_t *cmechlist;
198*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
199*7c478bd9Sstevel@tonic-gate   _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx;
200*7c478bd9Sstevel@tonic-gate   int sun_reg;
201*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
202*7c478bd9Sstevel@tonic-gate   int i;
203*7c478bd9Sstevel@tonic-gate   cmechanism_t *m;
204*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
205*7c478bd9Sstevel@tonic-gate   int plugcount;
206*7c478bd9Sstevel@tonic-gate   sasl_client_plug_t *pluglist;
207*7c478bd9Sstevel@tonic-gate   cmechanism_t *mech;
208*7c478bd9Sstevel@tonic-gate   int result;
209*7c478bd9Sstevel@tonic-gate   int version;
210*7c478bd9Sstevel@tonic-gate   int lupe;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate   if(!plugname || !entry_point) return SASL_BADPARAM;
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
215*7c478bd9Sstevel@tonic-gate   cmechlist = gctx->cmechlist;
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate   if (cmechlist == NULL) return SASL_BADPARAM;
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate   /* Check to see if this plugin has already been registered */
220*7c478bd9Sstevel@tonic-gate   m = cmechlist->mech_list;
221*7c478bd9Sstevel@tonic-gate   for (i = 0; i < cmechlist->mech_length; i++) {
222*7c478bd9Sstevel@tonic-gate     if (strcmp(plugname, m->plugname) == 0) {
223*7c478bd9Sstevel@tonic-gate 	return SASL_OK;
224*7c478bd9Sstevel@tonic-gate     }
225*7c478bd9Sstevel@tonic-gate     m = m->next;
226*7c478bd9Sstevel@tonic-gate   }
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate   result = LOCK_MUTEX(&client_plug_mutex);
229*7c478bd9Sstevel@tonic-gate   if (result != SASL_OK)
230*7c478bd9Sstevel@tonic-gate 	return result;
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate   result = entry_point(cmechlist->utils, SASL_CLIENT_PLUG_VERSION, &version,
235*7c478bd9Sstevel@tonic-gate 		       &pluglist, &plugcount);
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
238*7c478bd9Sstevel@tonic-gate   sun_reg = _is_sun_reg(pluglist);
239*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
240*7c478bd9Sstevel@tonic-gate   if (result != SASL_OK)
241*7c478bd9Sstevel@tonic-gate   {
242*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
243*7c478bd9Sstevel@tonic-gate     UNLOCK_MUTEX(&client_plug_mutex);
244*7c478bd9Sstevel@tonic-gate     __sasl_log(gctx, gctx->client_global_callbacks.callbacks, SASL_LOG_WARN,
245*7c478bd9Sstevel@tonic-gate 	      "entry_point failed in sasl_client_add_plugin for %s",
246*7c478bd9Sstevel@tonic-gate 	      plugname);
247*7c478bd9Sstevel@tonic-gate #else
248*7c478bd9Sstevel@tonic-gate     _sasl_log(NULL, SASL_LOG_WARN,
249*7c478bd9Sstevel@tonic-gate 	      "entry_point failed in sasl_client_add_plugin for %s",
250*7c478bd9Sstevel@tonic-gate 	      plugname);
251*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
252*7c478bd9Sstevel@tonic-gate     return result;
253*7c478bd9Sstevel@tonic-gate   }
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate   if (version != SASL_CLIENT_PLUG_VERSION)
256*7c478bd9Sstevel@tonic-gate   {
257*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
258*7c478bd9Sstevel@tonic-gate     UNLOCK_MUTEX(&client_plug_mutex);
259*7c478bd9Sstevel@tonic-gate     __sasl_log(gctx, gctx->client_global_callbacks.callbacks, SASL_LOG_WARN,
260*7c478bd9Sstevel@tonic-gate 	      "version conflict in sasl_client_add_plugin for %s", plugname);
261*7c478bd9Sstevel@tonic-gate #else
262*7c478bd9Sstevel@tonic-gate     _sasl_log(NULL, SASL_LOG_WARN,
263*7c478bd9Sstevel@tonic-gate 	      "version conflict in sasl_client_add_plugin for %s", plugname);
264*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
265*7c478bd9Sstevel@tonic-gate     return SASL_BADVERS;
266*7c478bd9Sstevel@tonic-gate   }
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
269*7c478bd9Sstevel@tonic-gate     /* Check plugins to make sure mech_name is non-NULL */
270*7c478bd9Sstevel@tonic-gate     for (lupe=0;lupe < plugcount ;lupe++) {
271*7c478bd9Sstevel@tonic-gate 	if (pluglist[lupe].mech_name == NULL)
272*7c478bd9Sstevel@tonic-gate 	     break;
273*7c478bd9Sstevel@tonic-gate     }
274*7c478bd9Sstevel@tonic-gate     if (lupe < plugcount) {
275*7c478bd9Sstevel@tonic-gate 	UNLOCK_MUTEX(&client_plug_mutex);
276*7c478bd9Sstevel@tonic-gate 	__sasl_log(gctx, gctx->client_global_callbacks.callbacks,
277*7c478bd9Sstevel@tonic-gate 		SASL_LOG_ERR, "invalid client plugin %s", plugname);
278*7c478bd9Sstevel@tonic-gate 	return SASL_BADPROT;
279*7c478bd9Sstevel@tonic-gate     }
280*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate   for (lupe=0;lupe< plugcount ;lupe++)
283*7c478bd9Sstevel@tonic-gate     {
284*7c478bd9Sstevel@tonic-gate       mech = sasl_ALLOC(sizeof(cmechanism_t));
285*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
286*7c478bd9Sstevel@tonic-gate       if (! mech) {
287*7c478bd9Sstevel@tonic-gate 	UNLOCK_MUTEX(&client_plug_mutex);
288*7c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
289*7c478bd9Sstevel@tonic-gate       }
290*7c478bd9Sstevel@tonic-gate       mech->glob_context = pluglist->glob_context;
291*7c478bd9Sstevel@tonic-gate #else
292*7c478bd9Sstevel@tonic-gate       if (! mech) return SASL_NOMEM;
293*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate       mech->plug=pluglist++;
296*7c478bd9Sstevel@tonic-gate       if(_sasl_strdup(plugname, &mech->plugname, NULL) != SASL_OK) {
297*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
298*7c478bd9Sstevel@tonic-gate 	UNLOCK_MUTEX(&client_plug_mutex);
299*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
300*7c478bd9Sstevel@tonic-gate 	sasl_FREE(mech);
301*7c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
302*7c478bd9Sstevel@tonic-gate       }
303*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
304*7c478bd9Sstevel@tonic-gate       mech->sun_reg = sun_reg;
305*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
306*7c478bd9Sstevel@tonic-gate       mech->version = version;
307*7c478bd9Sstevel@tonic-gate       mech->next = cmechlist->mech_list;
308*7c478bd9Sstevel@tonic-gate       cmechlist->mech_list = mech;
309*7c478bd9Sstevel@tonic-gate       cmechlist->mech_length++;
310*7c478bd9Sstevel@tonic-gate     }
311*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
312*7c478bd9Sstevel@tonic-gate     UNLOCK_MUTEX(&client_plug_mutex);
313*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate   return SASL_OK;
316*7c478bd9Sstevel@tonic-gate }
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate static int
319*7c478bd9Sstevel@tonic-gate client_idle(sasl_conn_t *conn)
320*7c478bd9Sstevel@tonic-gate {
321*7c478bd9Sstevel@tonic-gate   cmechanism_t *m;
322*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
323*7c478bd9Sstevel@tonic-gate   _sasl_global_context_t *gctx = conn == NULL ? _sasl_gbl_ctx() : conn->gctx;
324*7c478bd9Sstevel@tonic-gate    cmech_list_t *cmechlist = gctx->cmechlist;
325*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate   if (! cmechlist)
328*7c478bd9Sstevel@tonic-gate     return 0;
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate   for (m = cmechlist->mech_list;
331*7c478bd9Sstevel@tonic-gate        m;
332*7c478bd9Sstevel@tonic-gate        m = m->next)
333*7c478bd9Sstevel@tonic-gate     if (m->plug->idle
334*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
335*7c478bd9Sstevel@tonic-gate 	&&  m->plug->idle(m->glob_context,
336*7c478bd9Sstevel@tonic-gate #else
337*7c478bd9Sstevel@tonic-gate 	&&  m->plug->idle(m->plug->glob_context,
338*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
339*7c478bd9Sstevel@tonic-gate 			  conn,
340*7c478bd9Sstevel@tonic-gate 			  conn ? ((sasl_client_conn_t *)conn)->cparams : NULL))
341*7c478bd9Sstevel@tonic-gate       return 1;
342*7c478bd9Sstevel@tonic-gate   return 0;
343*7c478bd9Sstevel@tonic-gate }
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
346*7c478bd9Sstevel@tonic-gate static int _load_client_plugins(_sasl_global_context_t *gctx)
347*7c478bd9Sstevel@tonic-gate {
348*7c478bd9Sstevel@tonic-gate     int ret;
349*7c478bd9Sstevel@tonic-gate     const add_plugin_list_t _ep_list[] = {
350*7c478bd9Sstevel@tonic-gate       { "sasl_client_plug_init", (add_plugin_t *)_sasl_client_add_plugin },
351*7c478bd9Sstevel@tonic-gate       { "sasl_canonuser_init", (add_plugin_t *)_sasl_canonuser_add_plugin },
352*7c478bd9Sstevel@tonic-gate       { NULL, NULL }
353*7c478bd9Sstevel@tonic-gate     };
354*7c478bd9Sstevel@tonic-gate     const sasl_callback_t *callbacks = gctx->client_global_callbacks.callbacks;
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate     ret = _sasl_load_plugins(gctx, 0, _ep_list,
357*7c478bd9Sstevel@tonic-gate 			     _sasl_find_getpath_callback(callbacks),
358*7c478bd9Sstevel@tonic-gate 			     _sasl_find_verifyfile_callback(callbacks));
359*7c478bd9Sstevel@tonic-gate     return (ret);
360*7c478bd9Sstevel@tonic-gate }
361*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate /* initialize the SASL client drivers
364*7c478bd9Sstevel@tonic-gate  *  callbacks      -- base callbacks for all client connections
365*7c478bd9Sstevel@tonic-gate  * returns:
366*7c478bd9Sstevel@tonic-gate  *  SASL_OK        -- Success
367*7c478bd9Sstevel@tonic-gate  *  SASL_NOMEM     -- Not enough memory
368*7c478bd9Sstevel@tonic-gate  *  SASL_BADVERS   -- Mechanism version mismatch
369*7c478bd9Sstevel@tonic-gate  *  SASL_BADPARAM  -- error in config file
370*7c478bd9Sstevel@tonic-gate  *  SASL_NOMECH    -- No mechanisms available
371*7c478bd9Sstevel@tonic-gate  *  ...
372*7c478bd9Sstevel@tonic-gate  */
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate int sasl_client_init(const sasl_callback_t *callbacks)
375*7c478bd9Sstevel@tonic-gate {
376*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
377*7c478bd9Sstevel@tonic-gate 	return _sasl_client_init(NULL, callbacks);
378*7c478bd9Sstevel@tonic-gate }
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate int _sasl_client_init(void *ctx,
381*7c478bd9Sstevel@tonic-gate 		      const sasl_callback_t *callbacks)
382*7c478bd9Sstevel@tonic-gate {
383*7c478bd9Sstevel@tonic-gate   int ret;
384*7c478bd9Sstevel@tonic-gate   _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate   if (gctx == NULL)
387*7c478bd9Sstevel@tonic-gate 	gctx = _sasl_gbl_ctx();
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate   ret = LOCK_MUTEX(&init_client_mutex);
390*7c478bd9Sstevel@tonic-gate   if (ret < 0) {
391*7c478bd9Sstevel@tonic-gate 	return (SASL_FAIL);
392*7c478bd9Sstevel@tonic-gate   }
393*7c478bd9Sstevel@tonic-gate   ret = LOCK_MUTEX(&client_active_mutex);
394*7c478bd9Sstevel@tonic-gate   if (ret < 0) {
395*7c478bd9Sstevel@tonic-gate 	UNLOCK_MUTEX(&init_client_mutex);
396*7c478bd9Sstevel@tonic-gate 	return (SASL_FAIL);
397*7c478bd9Sstevel@tonic-gate   }
398*7c478bd9Sstevel@tonic-gate   if(gctx->sasl_client_active) {
399*7c478bd9Sstevel@tonic-gate       /* We're already active, just increase our refcount */
400*7c478bd9Sstevel@tonic-gate       /* xxx do something with the callback structure? */
401*7c478bd9Sstevel@tonic-gate       gctx->sasl_client_active++;
402*7c478bd9Sstevel@tonic-gate       UNLOCK_MUTEX(&client_active_mutex);
403*7c478bd9Sstevel@tonic-gate       UNLOCK_MUTEX(&init_client_mutex);
404*7c478bd9Sstevel@tonic-gate       return SASL_OK;
405*7c478bd9Sstevel@tonic-gate   }
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate   gctx->client_global_callbacks.callbacks = callbacks;
408*7c478bd9Sstevel@tonic-gate   gctx->client_global_callbacks.appname = NULL;
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate   gctx->cmechlist=sasl_ALLOC(sizeof(cmech_list_t));
411*7c478bd9Sstevel@tonic-gate   if (gctx->cmechlist==NULL) {
412*7c478bd9Sstevel@tonic-gate       UNLOCK_MUTEX(&init_client_mutex);
413*7c478bd9Sstevel@tonic-gate       UNLOCK_MUTEX(&client_active_mutex);
414*7c478bd9Sstevel@tonic-gate       return SASL_NOMEM;
415*7c478bd9Sstevel@tonic-gate   }
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate   gctx->sasl_client_active = 1;
418*7c478bd9Sstevel@tonic-gate   UNLOCK_MUTEX(&client_active_mutex);
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate   /* load plugins */
421*7c478bd9Sstevel@tonic-gate   ret=init_mechlist(gctx);
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate   if (ret!=SASL_OK) {
424*7c478bd9Sstevel@tonic-gate     client_done(gctx);
425*7c478bd9Sstevel@tonic-gate     UNLOCK_MUTEX(&init_client_mutex);
426*7c478bd9Sstevel@tonic-gate     return ret;
427*7c478bd9Sstevel@tonic-gate   }
428*7c478bd9Sstevel@tonic-gate   _sasl_client_add_plugin(gctx, "EXTERNAL", &external_client_plug_init);
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate   ret = _sasl_common_init(gctx, &gctx->client_global_callbacks, 0);
431*7c478bd9Sstevel@tonic-gate #else
432*7c478bd9Sstevel@tonic-gate int sasl_client_init(const sasl_callback_t *callbacks)
433*7c478bd9Sstevel@tonic-gate {
434*7c478bd9Sstevel@tonic-gate   int ret;
435*7c478bd9Sstevel@tonic-gate   const add_plugin_list_t ep_list[] = {
436*7c478bd9Sstevel@tonic-gate       { "sasl_client_plug_init", (add_plugin_t *)sasl_client_add_plugin },
437*7c478bd9Sstevel@tonic-gate       { "sasl_canonuser_init", (add_plugin_t *)sasl_canonuser_add_plugin },
438*7c478bd9Sstevel@tonic-gate       { NULL, NULL }
439*7c478bd9Sstevel@tonic-gate   };
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate   if(_sasl_client_active) {
442*7c478bd9Sstevel@tonic-gate       /* We're already active, just increase our refcount */
443*7c478bd9Sstevel@tonic-gate       /* xxx do something with the callback structure? */
444*7c478bd9Sstevel@tonic-gate       _sasl_client_active++;
445*7c478bd9Sstevel@tonic-gate       return SASL_OK;
446*7c478bd9Sstevel@tonic-gate   }
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate   global_callbacks.callbacks = callbacks;
449*7c478bd9Sstevel@tonic-gate   global_callbacks.appname = NULL;
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate   cmechlist=sasl_ALLOC(sizeof(cmech_list_t));
452*7c478bd9Sstevel@tonic-gate   if (cmechlist==NULL) return SASL_NOMEM;
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate   /* We need to call client_done if we fail now */
455*7c478bd9Sstevel@tonic-gate   _sasl_client_active = 1;
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate   /* load plugins */
458*7c478bd9Sstevel@tonic-gate   ret=init_mechlist();
459*7c478bd9Sstevel@tonic-gate   if (ret!=SASL_OK) {
460*7c478bd9Sstevel@tonic-gate       client_done();
461*7c478bd9Sstevel@tonic-gate       return ret;
462*7c478bd9Sstevel@tonic-gate   }
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate   sasl_client_add_plugin("EXTERNAL", &external_client_plug_init);
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate   ret = _sasl_common_init(&global_callbacks);
467*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate   if (ret == SASL_OK)
470*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
471*7c478bd9Sstevel@tonic-gate       ret = _load_client_plugins(gctx);
472*7c478bd9Sstevel@tonic-gate #else
473*7c478bd9Sstevel@tonic-gate       ret = _sasl_load_plugins(ep_list,
474*7c478bd9Sstevel@tonic-gate 			       _sasl_find_getpath_callback(callbacks),
475*7c478bd9Sstevel@tonic-gate 			       _sasl_find_verifyfile_callback(callbacks));
476*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
479*7c478bd9Sstevel@tonic-gate   if (ret == SASL_OK)
480*7c478bd9Sstevel@tonic-gate 	/* If sasl_client_init returns error, sasl_done() need not be called */
481*7c478bd9Sstevel@tonic-gate       ret = _sasl_build_mechlist(gctx);
482*7c478bd9Sstevel@tonic-gate   if (ret == SASL_OK) {
483*7c478bd9Sstevel@tonic-gate       gctx->sasl_client_cleanup_hook = &client_done;
484*7c478bd9Sstevel@tonic-gate       gctx->sasl_client_idle_hook = &client_idle;
485*7c478bd9Sstevel@tonic-gate   } else {
486*7c478bd9Sstevel@tonic-gate       client_done(gctx);
487*7c478bd9Sstevel@tonic-gate   }
488*7c478bd9Sstevel@tonic-gate   UNLOCK_MUTEX(&init_client_mutex);
489*7c478bd9Sstevel@tonic-gate #else
490*7c478bd9Sstevel@tonic-gate   if (ret == SASL_OK) {
491*7c478bd9Sstevel@tonic-gate       _sasl_client_cleanup_hook = &client_done;
492*7c478bd9Sstevel@tonic-gate       _sasl_client_idle_hook = &client_idle;
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate       ret = _sasl_build_mechlist();
495*7c478bd9Sstevel@tonic-gate   } else {
496*7c478bd9Sstevel@tonic-gate       client_done();
497*7c478bd9Sstevel@tonic-gate   }
498*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate   return ret;
501*7c478bd9Sstevel@tonic-gate }
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate static void client_dispose(sasl_conn_t *pconn)
504*7c478bd9Sstevel@tonic-gate {
505*7c478bd9Sstevel@tonic-gate   sasl_client_conn_t *c_conn=(sasl_client_conn_t *) pconn;
506*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
507*7c478bd9Sstevel@tonic-gate   sasl_free_t *free_func = c_conn->cparams->utils->free;
508*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate   if (c_conn->mech && c_conn->mech->plug->mech_dispose) {
511*7c478bd9Sstevel@tonic-gate     c_conn->mech->plug->mech_dispose(pconn->context,
512*7c478bd9Sstevel@tonic-gate 				     c_conn->cparams->utils);
513*7c478bd9Sstevel@tonic-gate   }
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate   pconn->context = NULL;
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate   if (c_conn->clientFQDN)
518*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
519*7c478bd9Sstevel@tonic-gate       free_func(c_conn->clientFQDN);
520*7c478bd9Sstevel@tonic-gate #else
521*7c478bd9Sstevel@tonic-gate       sasl_FREE(c_conn->clientFQDN);
522*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate   if (c_conn->cparams) {
525*7c478bd9Sstevel@tonic-gate       _sasl_free_utils(&(c_conn->cparams->utils));
526*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
527*7c478bd9Sstevel@tonic-gate       free_func(c_conn->cparams);
528*7c478bd9Sstevel@tonic-gate #else
529*7c478bd9Sstevel@tonic-gate       sasl_FREE(c_conn->cparams);
530*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
531*7c478bd9Sstevel@tonic-gate   }
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate   _sasl_conn_dispose(pconn);
534*7c478bd9Sstevel@tonic-gate }
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate /* initialize a client exchange based on the specified mechanism
537*7c478bd9Sstevel@tonic-gate  *  service       -- registered name of the service using SASL (e.g. "imap")
538*7c478bd9Sstevel@tonic-gate  *  serverFQDN    -- the fully qualified domain name of the server
539*7c478bd9Sstevel@tonic-gate  *  iplocalport   -- client IPv4/IPv6 domain literal string with port
540*7c478bd9Sstevel@tonic-gate  *                    (if NULL, then mechanisms requiring IPaddr are disabled)
541*7c478bd9Sstevel@tonic-gate  *  ipremoteport  -- server IPv4/IPv6 domain literal string with port
542*7c478bd9Sstevel@tonic-gate  *                    (if NULL, then mechanisms requiring IPaddr are disabled)
543*7c478bd9Sstevel@tonic-gate  *  prompt_supp   -- list of client interactions supported
544*7c478bd9Sstevel@tonic-gate  *                   may also include sasl_getopt_t context & call
545*7c478bd9Sstevel@tonic-gate  *                   NULL prompt_supp = user/pass via SASL_INTERACT only
546*7c478bd9Sstevel@tonic-gate  *                   NULL proc = interaction supported via SASL_INTERACT
547*7c478bd9Sstevel@tonic-gate  *  secflags      -- security flags (see above)
548*7c478bd9Sstevel@tonic-gate  * in/out:
549*7c478bd9Sstevel@tonic-gate  *  pconn         -- connection negotiation structure
550*7c478bd9Sstevel@tonic-gate  *                   pointer to NULL => allocate new
551*7c478bd9Sstevel@tonic-gate  *                   non-NULL => recycle storage and go for next available mech
552*7c478bd9Sstevel@tonic-gate  *
553*7c478bd9Sstevel@tonic-gate  * Returns:
554*7c478bd9Sstevel@tonic-gate  *  SASL_OK       -- success
555*7c478bd9Sstevel@tonic-gate  *  SASL_NOMECH   -- no mechanism meets requested properties
556*7c478bd9Sstevel@tonic-gate  *  SASL_NOMEM    -- not enough memory
557*7c478bd9Sstevel@tonic-gate  */
558*7c478bd9Sstevel@tonic-gate int sasl_client_new(const char *service,
559*7c478bd9Sstevel@tonic-gate 		    const char *serverFQDN,
560*7c478bd9Sstevel@tonic-gate 		    const char *iplocalport,
561*7c478bd9Sstevel@tonic-gate 		    const char *ipremoteport,
562*7c478bd9Sstevel@tonic-gate 		    const sasl_callback_t *prompt_supp,
563*7c478bd9Sstevel@tonic-gate 		    unsigned flags,
564*7c478bd9Sstevel@tonic-gate 		    sasl_conn_t **pconn)
565*7c478bd9Sstevel@tonic-gate {
566*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
567*7c478bd9Sstevel@tonic-gate     return _sasl_client_new(NULL, service, serverFQDN, iplocalport,
568*7c478bd9Sstevel@tonic-gate 			    ipremoteport, prompt_supp, flags, pconn);
569*7c478bd9Sstevel@tonic-gate }
570*7c478bd9Sstevel@tonic-gate int _sasl_client_new(void *ctx,
571*7c478bd9Sstevel@tonic-gate 		     const char *service,
572*7c478bd9Sstevel@tonic-gate 		     const char *serverFQDN,
573*7c478bd9Sstevel@tonic-gate 		     const char *iplocalport,
574*7c478bd9Sstevel@tonic-gate 		     const char *ipremoteport,
575*7c478bd9Sstevel@tonic-gate 		     const sasl_callback_t *prompt_supp,
576*7c478bd9Sstevel@tonic-gate 		     unsigned flags,
577*7c478bd9Sstevel@tonic-gate 		     sasl_conn_t **pconn)
578*7c478bd9Sstevel@tonic-gate {
579*7c478bd9Sstevel@tonic-gate   _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx;
580*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
581*7c478bd9Sstevel@tonic-gate   int result;
582*7c478bd9Sstevel@tonic-gate   char name[MAXHOSTNAMELEN];
583*7c478bd9Sstevel@tonic-gate   sasl_client_conn_t *conn;
584*7c478bd9Sstevel@tonic-gate   sasl_utils_t *utils;
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
587*7c478bd9Sstevel@tonic-gate   if (gctx == NULL)
588*7c478bd9Sstevel@tonic-gate 	gctx = _sasl_gbl_ctx();
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate   if(gctx->sasl_client_active==0) return SASL_NOTINIT;
591*7c478bd9Sstevel@tonic-gate #else
592*7c478bd9Sstevel@tonic-gate   if(_sasl_client_active==0) return SASL_NOTINIT;
593*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate   /* Remember, iplocalport and ipremoteport can be NULL and be valid! */
596*7c478bd9Sstevel@tonic-gate   if (!pconn || !service || !serverFQDN)
597*7c478bd9Sstevel@tonic-gate     return SASL_BADPARAM;
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate   *pconn=sasl_ALLOC(sizeof(sasl_client_conn_t));
600*7c478bd9Sstevel@tonic-gate   if (*pconn==NULL) {
601*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
602*7c478bd9Sstevel@tonic-gate       __sasl_log(gctx, gctx->client_global_callbacks.callbacks, SASL_LOG_ERR,
603*7c478bd9Sstevel@tonic-gate 		"Out of memory allocating connection context");
604*7c478bd9Sstevel@tonic-gate #else
605*7c478bd9Sstevel@tonic-gate       _sasl_log(NULL, SASL_LOG_ERR,
606*7c478bd9Sstevel@tonic-gate 		"Out of memory allocating connection context");
607*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
608*7c478bd9Sstevel@tonic-gate       return SASL_NOMEM;
609*7c478bd9Sstevel@tonic-gate   }
610*7c478bd9Sstevel@tonic-gate   memset(*pconn, 0, sizeof(sasl_client_conn_t));
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
613*7c478bd9Sstevel@tonic-gate   (*pconn)->gctx = gctx;
614*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate   (*pconn)->destroy_conn = &client_dispose;
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate   conn = (sasl_client_conn_t *)*pconn;
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate   conn->mech = NULL;
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate   conn->cparams=sasl_ALLOC(sizeof(sasl_client_params_t));
623*7c478bd9Sstevel@tonic-gate   if (conn->cparams==NULL)
624*7c478bd9Sstevel@tonic-gate       MEMERROR(*pconn);
625*7c478bd9Sstevel@tonic-gate   memset(conn->cparams,0,sizeof(sasl_client_params_t));
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate   result = _sasl_conn_init(*pconn, service, flags, SASL_CONN_CLIENT,
628*7c478bd9Sstevel@tonic-gate 			   &client_idle, serverFQDN,
629*7c478bd9Sstevel@tonic-gate 			   iplocalport, ipremoteport,
630*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
631*7c478bd9Sstevel@tonic-gate 			   prompt_supp, &gctx->client_global_callbacks);
632*7c478bd9Sstevel@tonic-gate #else
633*7c478bd9Sstevel@tonic-gate 			   prompt_supp, &global_callbacks);
634*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate   if (result != SASL_OK) RETURN(*pconn, result);
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
639*7c478bd9Sstevel@tonic-gate   utils=_sasl_alloc_utils(gctx, *pconn, &gctx->client_global_callbacks);
640*7c478bd9Sstevel@tonic-gate #else
641*7c478bd9Sstevel@tonic-gate   utils=_sasl_alloc_utils(*pconn, &global_callbacks);
642*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
643*7c478bd9Sstevel@tonic-gate   if (utils==NULL)
644*7c478bd9Sstevel@tonic-gate       MEMERROR(*pconn);
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate   utils->conn= *pconn;
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate   /* Setup the non-lazy parts of cparams, the rest is done in
649*7c478bd9Sstevel@tonic-gate    * sasl_client_start */
650*7c478bd9Sstevel@tonic-gate   conn->cparams->utils = utils;
651*7c478bd9Sstevel@tonic-gate   conn->cparams->canon_user = &_sasl_canon_user;
652*7c478bd9Sstevel@tonic-gate   conn->cparams->flags = flags;
653*7c478bd9Sstevel@tonic-gate   conn->cparams->prompt_supp = (*pconn)->callbacks;
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate   /* get the clientFQDN (serverFQDN was set in _sasl_conn_init) */
656*7c478bd9Sstevel@tonic-gate   memset(name, 0, sizeof(name));
657*7c478bd9Sstevel@tonic-gate   gethostname(name, MAXHOSTNAMELEN);
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate   result = _sasl_strdup(name, &conn->clientFQDN, NULL);
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate   if(result == SASL_OK) return SASL_OK;
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
664*7c478bd9Sstevel@tonic-gate   conn->cparams->iplocalport = (*pconn)->iplocalport;
665*7c478bd9Sstevel@tonic-gate   conn->cparams->iploclen = strlen((*pconn)->iplocalport);
666*7c478bd9Sstevel@tonic-gate   conn->cparams->ipremoteport = (*pconn)->ipremoteport;
667*7c478bd9Sstevel@tonic-gate   conn->cparams->ipremlen = strlen((*pconn)->ipremoteport);
668*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate   /* result isn't SASL_OK */
671*7c478bd9Sstevel@tonic-gate   _sasl_conn_dispose(*pconn);
672*7c478bd9Sstevel@tonic-gate   sasl_FREE(*pconn);
673*7c478bd9Sstevel@tonic-gate   *pconn = NULL;
674*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
675*7c478bd9Sstevel@tonic-gate   __sasl_log(gctx, gctx->client_global_callbacks.callbacks, SASL_LOG_ERR,
676*7c478bd9Sstevel@tonic-gate 	"Out of memory in sasl_client_new");
677*7c478bd9Sstevel@tonic-gate #else
678*7c478bd9Sstevel@tonic-gate   _sasl_log(NULL, SASL_LOG_ERR, "Out of memory in sasl_client_new");
679*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
680*7c478bd9Sstevel@tonic-gate   return result;
681*7c478bd9Sstevel@tonic-gate }
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate static int have_prompts(sasl_conn_t *conn,
684*7c478bd9Sstevel@tonic-gate 			const sasl_client_plug_t *mech)
685*7c478bd9Sstevel@tonic-gate {
686*7c478bd9Sstevel@tonic-gate   static const unsigned long default_prompts[] = {
687*7c478bd9Sstevel@tonic-gate     SASL_CB_AUTHNAME,
688*7c478bd9Sstevel@tonic-gate     SASL_CB_PASS,
689*7c478bd9Sstevel@tonic-gate     SASL_CB_LIST_END
690*7c478bd9Sstevel@tonic-gate   };
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate   const unsigned long *prompt;
693*7c478bd9Sstevel@tonic-gate   int (*pproc)();
694*7c478bd9Sstevel@tonic-gate   void *pcontext;
695*7c478bd9Sstevel@tonic-gate   int result;
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate   for (prompt = (mech->required_prompts
698*7c478bd9Sstevel@tonic-gate 		 ? mech->required_prompts :
699*7c478bd9Sstevel@tonic-gate 		 default_prompts);
700*7c478bd9Sstevel@tonic-gate        *prompt != SASL_CB_LIST_END;
701*7c478bd9Sstevel@tonic-gate        prompt++) {
702*7c478bd9Sstevel@tonic-gate     result = _sasl_getcallback(conn, *prompt, &pproc, &pcontext);
703*7c478bd9Sstevel@tonic-gate     if (result != SASL_OK && result != SASL_INTERACT)
704*7c478bd9Sstevel@tonic-gate       return 0;			/* we don't have this required prompt */
705*7c478bd9Sstevel@tonic-gate   }
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate   return 1; /* we have all the prompts */
708*7c478bd9Sstevel@tonic-gate }
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate /* select a mechanism for a connection
711*7c478bd9Sstevel@tonic-gate  *  mechlist      -- mechanisms server has available (punctuation ignored)
712*7c478bd9Sstevel@tonic-gate  *  secret        -- optional secret from previous session
713*7c478bd9Sstevel@tonic-gate  * output:
714*7c478bd9Sstevel@tonic-gate  *  prompt_need   -- on SASL_INTERACT, list of prompts needed to continue
715*7c478bd9Sstevel@tonic-gate  *  clientout     -- the initial client response to send to the server
716*7c478bd9Sstevel@tonic-gate  *  mech          -- set to mechanism name
717*7c478bd9Sstevel@tonic-gate  *
718*7c478bd9Sstevel@tonic-gate  * Returns:
719*7c478bd9Sstevel@tonic-gate  *  SASL_OK       -- success
720*7c478bd9Sstevel@tonic-gate  *  SASL_NOMEM    -- not enough memory
721*7c478bd9Sstevel@tonic-gate  *  SASL_NOMECH   -- no mechanism meets requested properties
722*7c478bd9Sstevel@tonic-gate  *  SASL_INTERACT -- user interaction needed to fill in prompt_need list
723*7c478bd9Sstevel@tonic-gate  */
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate /* xxx confirm this with rfc 2222
726*7c478bd9Sstevel@tonic-gate  * SASL mechanism allowable characters are "AZaz-_"
727*7c478bd9Sstevel@tonic-gate  * seperators can be any other characters and of any length
728*7c478bd9Sstevel@tonic-gate  * even variable lengths between
729*7c478bd9Sstevel@tonic-gate  *
730*7c478bd9Sstevel@tonic-gate  * Apps should be encouraged to simply use space or comma space
731*7c478bd9Sstevel@tonic-gate  * though
732*7c478bd9Sstevel@tonic-gate  */
733*7c478bd9Sstevel@tonic-gate int sasl_client_start(sasl_conn_t *conn,
734*7c478bd9Sstevel@tonic-gate 		      const char *mechlist,
735*7c478bd9Sstevel@tonic-gate 		      sasl_interact_t **prompt_need,
736*7c478bd9Sstevel@tonic-gate 		      const char **clientout,
737*7c478bd9Sstevel@tonic-gate 		      unsigned *clientoutlen,
738*7c478bd9Sstevel@tonic-gate 		      const char **mech)
739*7c478bd9Sstevel@tonic-gate {
740*7c478bd9Sstevel@tonic-gate     sasl_client_conn_t *c_conn= (sasl_client_conn_t *) conn;
741*7c478bd9Sstevel@tonic-gate     char name[SASL_MECHNAMEMAX + 1];
742*7c478bd9Sstevel@tonic-gate     cmechanism_t *m=NULL,*bestm=NULL;
743*7c478bd9Sstevel@tonic-gate     size_t pos=0,place;
744*7c478bd9Sstevel@tonic-gate     size_t list_len;
745*7c478bd9Sstevel@tonic-gate     sasl_ssf_t bestssf = 0, minssf = 0;
746*7c478bd9Sstevel@tonic-gate     int result;
747*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
748*7c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx = (conn == NULL) ?
749*7c478bd9Sstevel@tonic-gate 		_sasl_gbl_ctx() : conn->gctx;
750*7c478bd9Sstevel@tonic-gate     cmech_list_t *cmechlist;
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate     if(gctx->sasl_client_active==0) return SASL_NOTINIT;
753*7c478bd9Sstevel@tonic-gate     cmechlist = gctx->cmechlist;
754*7c478bd9Sstevel@tonic-gate #else
755*7c478bd9Sstevel@tonic-gate     if(_sasl_client_active==0) return SASL_NOTINIT;
756*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate     if (!conn) return SASL_BADPARAM;
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate     /* verify parameters */
761*7c478bd9Sstevel@tonic-gate     if (mechlist == NULL)
762*7c478bd9Sstevel@tonic-gate 	PARAMERROR(conn);
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate     /* if prompt_need != NULL we've already been here
765*7c478bd9Sstevel@tonic-gate        and just need to do the continue step again */
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate     /* do a step */
768*7c478bd9Sstevel@tonic-gate     /* FIXME: Hopefully they only give us our own prompt_need back */
769*7c478bd9Sstevel@tonic-gate     if (prompt_need && *prompt_need != NULL) {
770*7c478bd9Sstevel@tonic-gate 	goto dostep;
771*7c478bd9Sstevel@tonic-gate     }
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
774*7c478bd9Sstevel@tonic-gate     if (c_conn->mech != NULL) {
775*7c478bd9Sstevel@tonic-gate 	if (c_conn->mech->plug->mech_dispose != NULL) {
776*7c478bd9Sstevel@tonic-gate 	    c_conn->mech->plug->mech_dispose(conn->context,
777*7c478bd9Sstevel@tonic-gate 		c_conn->cparams->utils);
778*7c478bd9Sstevel@tonic-gate 	    c_conn->mech = NULL;
779*7c478bd9Sstevel@tonic-gate 	}
780*7c478bd9Sstevel@tonic-gate     }
781*7c478bd9Sstevel@tonic-gate     memset(&conn->oparams, 0, sizeof(sasl_out_params_t));
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate     (void) _load_client_plugins(gctx);
784*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate     if(conn->props.min_ssf < conn->external.ssf) {
787*7c478bd9Sstevel@tonic-gate 	minssf = 0;
788*7c478bd9Sstevel@tonic-gate     } else {
789*7c478bd9Sstevel@tonic-gate 	minssf = conn->props.min_ssf - conn->external.ssf;
790*7c478bd9Sstevel@tonic-gate     }
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate     /* parse mechlist */
793*7c478bd9Sstevel@tonic-gate     list_len = strlen(mechlist);
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate     while (pos<list_len)
796*7c478bd9Sstevel@tonic-gate     {
797*7c478bd9Sstevel@tonic-gate 	place=0;
798*7c478bd9Sstevel@tonic-gate 	while ((pos<list_len) && (isalnum((unsigned char)mechlist[pos])
799*7c478bd9Sstevel@tonic-gate 				  || mechlist[pos] == '_'
800*7c478bd9Sstevel@tonic-gate 				  || mechlist[pos] == '-')) {
801*7c478bd9Sstevel@tonic-gate 	    name[place]=mechlist[pos];
802*7c478bd9Sstevel@tonic-gate 	    pos++;
803*7c478bd9Sstevel@tonic-gate 	    place++;
804*7c478bd9Sstevel@tonic-gate 	    if (SASL_MECHNAMEMAX < place) {
805*7c478bd9Sstevel@tonic-gate 		place--;
806*7c478bd9Sstevel@tonic-gate 		while(pos<list_len && (isalnum((unsigned char)mechlist[pos])
807*7c478bd9Sstevel@tonic-gate 				       || mechlist[pos] == '_'
808*7c478bd9Sstevel@tonic-gate 				       || mechlist[pos] == '-'))
809*7c478bd9Sstevel@tonic-gate 		    pos++;
810*7c478bd9Sstevel@tonic-gate 	    }
811*7c478bd9Sstevel@tonic-gate 	}
812*7c478bd9Sstevel@tonic-gate 	pos++;
813*7c478bd9Sstevel@tonic-gate 	name[place]=0;
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 	if (! place) continue;
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 	/* foreach in server list */
818*7c478bd9Sstevel@tonic-gate 	for (m = cmechlist->mech_list; m != NULL; m = m->next) {
819*7c478bd9Sstevel@tonic-gate 	    int myflags;
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate 	    /* Is this the mechanism the server is suggesting? */
822*7c478bd9Sstevel@tonic-gate 	    if (strcasecmp(m->plug->mech_name, name))
823*7c478bd9Sstevel@tonic-gate 		continue; /* no */
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 	    /* Do we have the prompts for it? */
826*7c478bd9Sstevel@tonic-gate 	    if (!have_prompts(conn, m->plug))
827*7c478bd9Sstevel@tonic-gate 		break;
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	    /* Is it strong enough? */
830*7c478bd9Sstevel@tonic-gate 	    if (minssf > m->plug->max_ssf)
831*7c478bd9Sstevel@tonic-gate 		break;
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
834*7c478bd9Sstevel@tonic-gate 	    /* If not SUN supplied mech, it has no strength */
835*7c478bd9Sstevel@tonic-gate 	    if (minssf > 0 && !m->sun_reg)
836*7c478bd9Sstevel@tonic-gate 		break;
837*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	    /* Does it meet our security properties? */
840*7c478bd9Sstevel@tonic-gate 	    myflags = conn->props.security_flags;
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	    /* if there's an external layer this is no longer plaintext */
843*7c478bd9Sstevel@tonic-gate 	    if ((conn->props.min_ssf <= conn->external.ssf) &&
844*7c478bd9Sstevel@tonic-gate 		(conn->external.ssf > 1)) {
845*7c478bd9Sstevel@tonic-gate 		myflags &= ~SASL_SEC_NOPLAINTEXT;
846*7c478bd9Sstevel@tonic-gate 	    }
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate 	    if (((myflags ^ m->plug->security_flags) & myflags) != 0) {
849*7c478bd9Sstevel@tonic-gate 		break;
850*7c478bd9Sstevel@tonic-gate 	    }
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate 	    /* Can we meet it's features? */
853*7c478bd9Sstevel@tonic-gate 	    if ((m->plug->features & SASL_FEAT_NEEDSERVERFQDN)
854*7c478bd9Sstevel@tonic-gate 		&& !conn->serverFQDN) {
855*7c478bd9Sstevel@tonic-gate 		break;
856*7c478bd9Sstevel@tonic-gate 	    }
857*7c478bd9Sstevel@tonic-gate 
858*7c478bd9Sstevel@tonic-gate 	    /* Can it meet our features? */
859*7c478bd9Sstevel@tonic-gate 	    if ((conn->flags & SASL_NEED_PROXY) &&
860*7c478bd9Sstevel@tonic-gate 		!(m->plug->features & SASL_FEAT_ALLOWS_PROXY)) {
861*7c478bd9Sstevel@tonic-gate 		break;
862*7c478bd9Sstevel@tonic-gate 	    }
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate #ifdef PREFER_MECH
865*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
866*7c478bd9Sstevel@tonic-gate 	    if (strcasecmp(m->plug->mech_name, PREFER_MECH) &&
867*7c478bd9Sstevel@tonic-gate 		bestm && (m->sun_reg && m->plug->max_ssf <= bestssf) ||
868*7c478bd9Sstevel@tonic-gate 		(m->plug->max_ssf == 0)) {
869*7c478bd9Sstevel@tonic-gate #else
870*7c478bd9Sstevel@tonic-gate 	    if (strcasecmp(m->plug->mech_name, PREFER_MECH) &&
871*7c478bd9Sstevel@tonic-gate 		bestm && m->plug->max_ssf <= bestssf) {
872*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate 		/* this mechanism isn't our favorite, and it's no better
875*7c478bd9Sstevel@tonic-gate 		   than what we already have! */
876*7c478bd9Sstevel@tonic-gate 		break;
877*7c478bd9Sstevel@tonic-gate 	    }
878*7c478bd9Sstevel@tonic-gate #else
879*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
880*7c478bd9Sstevel@tonic-gate 	    if (bestm && m->sun_reg && m->plug->max_ssf <= bestssf) {
881*7c478bd9Sstevel@tonic-gate #else
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate 	    if (bestm && m->plug->max_ssf <= bestssf) {
884*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 		/* this mechanism is no better than what we already have! */
887*7c478bd9Sstevel@tonic-gate 		break;
888*7c478bd9Sstevel@tonic-gate 	    }
889*7c478bd9Sstevel@tonic-gate #endif
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate 	    /* compare security flags, only take new mechanism if it has
892*7c478bd9Sstevel@tonic-gate 	     * all the security flags of the previous one.
893*7c478bd9Sstevel@tonic-gate 	     *
894*7c478bd9Sstevel@tonic-gate 	     * From the mechanisms we ship with, this yields the order:
895*7c478bd9Sstevel@tonic-gate 	     *
896*7c478bd9Sstevel@tonic-gate 	     * SRP
897*7c478bd9Sstevel@tonic-gate 	     * GSSAPI + KERBEROS_V4
898*7c478bd9Sstevel@tonic-gate 	     * DIGEST + OTP
899*7c478bd9Sstevel@tonic-gate 	     * CRAM + EXTERNAL
900*7c478bd9Sstevel@tonic-gate 	     * PLAIN + LOGIN + ANONYMOUS
901*7c478bd9Sstevel@tonic-gate 	     *
902*7c478bd9Sstevel@tonic-gate 	     * This might be improved on by comparing the numeric value of
903*7c478bd9Sstevel@tonic-gate 	     * the bitwise-or'd security flags, which splits DIGEST/OTP,
904*7c478bd9Sstevel@tonic-gate 	     * CRAM/EXTERNAL, and PLAIN/LOGIN from ANONYMOUS, but then we
905*7c478bd9Sstevel@tonic-gate 	     * are depending on the numeric values of the flags (which may
906*7c478bd9Sstevel@tonic-gate 	     * change, and their ordering could be considered dumb luck.
907*7c478bd9Sstevel@tonic-gate 	     */
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate 	    if (bestm &&
910*7c478bd9Sstevel@tonic-gate 		((m->plug->security_flags ^ bestm->plug->security_flags) &
911*7c478bd9Sstevel@tonic-gate 		 bestm->plug->security_flags)) {
912*7c478bd9Sstevel@tonic-gate 		break;
913*7c478bd9Sstevel@tonic-gate 	    }
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate 	    if (mech) {
916*7c478bd9Sstevel@tonic-gate 		*mech = m->plug->mech_name;
917*7c478bd9Sstevel@tonic-gate 	    }
918*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
919*7c478bd9Sstevel@tonic-gate 	    bestssf = m->sun_reg ? m->plug->max_ssf : 0;
920*7c478bd9Sstevel@tonic-gate #else
921*7c478bd9Sstevel@tonic-gate 	    bestssf = m->plug->max_ssf;
922*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
923*7c478bd9Sstevel@tonic-gate 	    bestm = m;
924*7c478bd9Sstevel@tonic-gate 	    break;
925*7c478bd9Sstevel@tonic-gate 	}
926*7c478bd9Sstevel@tonic-gate     }
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate     if (bestm == NULL) {
929*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
930*7c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0, gettext("No worthy mechs found"));
931*7c478bd9Sstevel@tonic-gate #else
932*7c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0, "No worthy mechs found");
933*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
934*7c478bd9Sstevel@tonic-gate 	result = SASL_NOMECH;
935*7c478bd9Sstevel@tonic-gate 	goto done;
936*7c478bd9Sstevel@tonic-gate     }
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate     /* make (the rest of) cparams */
939*7c478bd9Sstevel@tonic-gate     c_conn->cparams->service = conn->service;
940*7c478bd9Sstevel@tonic-gate     c_conn->cparams->servicelen = strlen(conn->service);
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate     c_conn->cparams->serverFQDN = conn->serverFQDN;
943*7c478bd9Sstevel@tonic-gate     c_conn->cparams->slen = strlen(conn->serverFQDN);
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate     c_conn->cparams->clientFQDN = c_conn->clientFQDN;
946*7c478bd9Sstevel@tonic-gate     c_conn->cparams->clen = strlen(c_conn->clientFQDN);
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate     c_conn->cparams->external_ssf = conn->external.ssf;
949*7c478bd9Sstevel@tonic-gate     c_conn->cparams->props = conn->props;
950*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
951*7c478bd9Sstevel@tonic-gate     if (!bestm->sun_reg) {
952*7c478bd9Sstevel@tonic-gate 	c_conn->cparams->props.min_ssf = 0;
953*7c478bd9Sstevel@tonic-gate 	c_conn->cparams->props.max_ssf = 0;
954*7c478bd9Sstevel@tonic-gate     }
955*7c478bd9Sstevel@tonic-gate     c_conn->base.sun_reg = bestm->sun_reg;
956*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
957*7c478bd9Sstevel@tonic-gate     c_conn->mech = bestm;
958*7c478bd9Sstevel@tonic-gate 
959*7c478bd9Sstevel@tonic-gate     /* init that plugin */
960*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
961*7c478bd9Sstevel@tonic-gate     result = c_conn->mech->plug->mech_new(c_conn->mech->glob_context,
962*7c478bd9Sstevel@tonic-gate #else
963*7c478bd9Sstevel@tonic-gate     result = c_conn->mech->plug->mech_new(c_conn->mech->plug->glob_context,
964*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
965*7c478bd9Sstevel@tonic-gate 					  c_conn->cparams,
966*7c478bd9Sstevel@tonic-gate 					  &(conn->context));
967*7c478bd9Sstevel@tonic-gate     if(result != SASL_OK) goto done;
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate     /* do a step -- but only if we can do a client-send-first */
970*7c478bd9Sstevel@tonic-gate  dostep:
971*7c478bd9Sstevel@tonic-gate     if(clientout) {
972*7c478bd9Sstevel@tonic-gate         if(c_conn->mech->plug->features & SASL_FEAT_SERVER_FIRST) {
973*7c478bd9Sstevel@tonic-gate             *clientout = NULL;
974*7c478bd9Sstevel@tonic-gate             *clientoutlen = 0;
975*7c478bd9Sstevel@tonic-gate             result = SASL_CONTINUE;
976*7c478bd9Sstevel@tonic-gate         } else {
977*7c478bd9Sstevel@tonic-gate             result = sasl_client_step(conn, NULL, 0, prompt_need,
978*7c478bd9Sstevel@tonic-gate                                       clientout, clientoutlen);
979*7c478bd9Sstevel@tonic-gate         }
980*7c478bd9Sstevel@tonic-gate     }
981*7c478bd9Sstevel@tonic-gate     else
982*7c478bd9Sstevel@tonic-gate 	result = SASL_CONTINUE;
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate  done:
985*7c478bd9Sstevel@tonic-gate     RETURN(conn, result);
986*7c478bd9Sstevel@tonic-gate }
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate /* do a single authentication step.
989*7c478bd9Sstevel@tonic-gate  *  serverin    -- the server message received by the client, MUST have a NUL
990*7c478bd9Sstevel@tonic-gate  *                 sentinel, not counted by serverinlen
991*7c478bd9Sstevel@tonic-gate  * output:
992*7c478bd9Sstevel@tonic-gate  *  prompt_need -- on SASL_INTERACT, list of prompts needed to continue
993*7c478bd9Sstevel@tonic-gate  *  clientout   -- the client response to send to the server
994*7c478bd9Sstevel@tonic-gate  *
995*7c478bd9Sstevel@tonic-gate  * returns:
996*7c478bd9Sstevel@tonic-gate  *  SASL_OK        -- success
997*7c478bd9Sstevel@tonic-gate  *  SASL_INTERACT  -- user interaction needed to fill in prompt_need list
998*7c478bd9Sstevel@tonic-gate  *  SASL_BADPROT   -- server protocol incorrect/cancelled
999*7c478bd9Sstevel@tonic-gate  *  SASL_BADSERV   -- server failed mutual auth
1000*7c478bd9Sstevel@tonic-gate  */
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate int sasl_client_step(sasl_conn_t *conn,
1003*7c478bd9Sstevel@tonic-gate 		     const char *serverin,
1004*7c478bd9Sstevel@tonic-gate 		     unsigned serverinlen,
1005*7c478bd9Sstevel@tonic-gate 		     sasl_interact_t **prompt_need,
1006*7c478bd9Sstevel@tonic-gate 		     const char **clientout,
1007*7c478bd9Sstevel@tonic-gate 		     unsigned *clientoutlen)
1008*7c478bd9Sstevel@tonic-gate {
1009*7c478bd9Sstevel@tonic-gate   sasl_client_conn_t *c_conn= (sasl_client_conn_t *) conn;
1010*7c478bd9Sstevel@tonic-gate   int result;
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
1013*7c478bd9Sstevel@tonic-gate   _sasl_global_context_t *gctx = (conn == NULL) ?
1014*7c478bd9Sstevel@tonic-gate 		_sasl_gbl_ctx() : conn->gctx;
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate   if(gctx->sasl_client_active==0) return SASL_NOTINIT;
1017*7c478bd9Sstevel@tonic-gate #else
1018*7c478bd9Sstevel@tonic-gate   if(_sasl_client_active==0) return SASL_NOTINIT;
1019*7c478bd9Sstevel@tonic-gate #endif	/* _SUN_SDK_ */
1020*7c478bd9Sstevel@tonic-gate   if(!conn) return SASL_BADPARAM;
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate   /* check parameters */
1023*7c478bd9Sstevel@tonic-gate   if ((serverin==NULL) && (serverinlen>0))
1024*7c478bd9Sstevel@tonic-gate       PARAMERROR(conn);
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate   /* Don't do another step if the plugin told us that we're done */
1027*7c478bd9Sstevel@tonic-gate   if (conn->oparams.doneflag) {
1028*7c478bd9Sstevel@tonic-gate       _sasl_log(conn, SASL_LOG_ERR, "attempting client step after doneflag");
1029*7c478bd9Sstevel@tonic-gate       return SASL_FAIL;
1030*7c478bd9Sstevel@tonic-gate   }
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate   if(clientout) *clientout = NULL;
1033*7c478bd9Sstevel@tonic-gate   if(clientoutlen) *clientoutlen = 0;
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate   /* do a step */
1036*7c478bd9Sstevel@tonic-gate   result = c_conn->mech->plug->mech_step(conn->context,
1037*7c478bd9Sstevel@tonic-gate 					 c_conn->cparams,
1038*7c478bd9Sstevel@tonic-gate 					 serverin,
1039*7c478bd9Sstevel@tonic-gate 					 serverinlen,
1040*7c478bd9Sstevel@tonic-gate 					 prompt_need,
1041*7c478bd9Sstevel@tonic-gate 					 clientout, clientoutlen,
1042*7c478bd9Sstevel@tonic-gate 					 &conn->oparams);
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate   if (result == SASL_OK) {
1045*7c478bd9Sstevel@tonic-gate       /* So we're done on this end, but if both
1046*7c478bd9Sstevel@tonic-gate        * 1. the mech does server-send-last
1047*7c478bd9Sstevel@tonic-gate        * 2. the protocol does not
1048*7c478bd9Sstevel@tonic-gate        * we need to return no data */
1049*7c478bd9Sstevel@tonic-gate       if(!*clientout && !(conn->flags & SASL_SUCCESS_DATA)) {
1050*7c478bd9Sstevel@tonic-gate 	  *clientout = "";
1051*7c478bd9Sstevel@tonic-gate 	  *clientoutlen = 0;
1052*7c478bd9Sstevel@tonic-gate       }
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate       if(!conn->oparams.maxoutbuf) {
1055*7c478bd9Sstevel@tonic-gate 	  conn->oparams.maxoutbuf = conn->props.maxbufsize;
1056*7c478bd9Sstevel@tonic-gate       }
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate       if(conn->oparams.user == NULL || conn->oparams.authid == NULL) {
1059*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
1060*7c478bd9Sstevel@tonic-gate 	_sasl_log(conn, SASL_LOG_ERR,
1061*7c478bd9Sstevel@tonic-gate 		  "mech did not call canon_user for both authzid and authid");
1062*7c478bd9Sstevel@tonic-gate #else
1063*7c478bd9Sstevel@tonic-gate 	  sasl_seterror(conn, 0,
1064*7c478bd9Sstevel@tonic-gate 			"mech did not call canon_user for both authzid and authid");
1065*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
1066*7c478bd9Sstevel@tonic-gate 	  result = SASL_BADPROT;
1067*7c478bd9Sstevel@tonic-gate       }
1068*7c478bd9Sstevel@tonic-gate   }
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate   RETURN(conn,result);
1071*7c478bd9Sstevel@tonic-gate }
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate /* returns the length of all the mechanisms
1074*7c478bd9Sstevel@tonic-gate  * added up
1075*7c478bd9Sstevel@tonic-gate  */
1076*7c478bd9Sstevel@tonic-gate 
1077*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
1078*7c478bd9Sstevel@tonic-gate static unsigned mech_names_len(_sasl_global_context_t *gctx)
1079*7c478bd9Sstevel@tonic-gate {
1080*7c478bd9Sstevel@tonic-gate   cmech_list_t *cmechlist = gctx->cmechlist;
1081*7c478bd9Sstevel@tonic-gate #else
1082*7c478bd9Sstevel@tonic-gate static unsigned mech_names_len()
1083*7c478bd9Sstevel@tonic-gate {
1084*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
1085*7c478bd9Sstevel@tonic-gate   cmechanism_t *listptr;
1086*7c478bd9Sstevel@tonic-gate   unsigned result = 0;
1087*7c478bd9Sstevel@tonic-gate 
1088*7c478bd9Sstevel@tonic-gate   for (listptr = cmechlist->mech_list;
1089*7c478bd9Sstevel@tonic-gate        listptr;
1090*7c478bd9Sstevel@tonic-gate        listptr = listptr->next)
1091*7c478bd9Sstevel@tonic-gate     result += strlen(listptr->plug->mech_name);
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate   return result;
1094*7c478bd9Sstevel@tonic-gate }
1095*7c478bd9Sstevel@tonic-gate 
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate int _sasl_client_listmech(sasl_conn_t *conn,
1098*7c478bd9Sstevel@tonic-gate 			  const char *prefix,
1099*7c478bd9Sstevel@tonic-gate 			  const char *sep,
1100*7c478bd9Sstevel@tonic-gate 			  const char *suffix,
1101*7c478bd9Sstevel@tonic-gate 			  const char **result,
1102*7c478bd9Sstevel@tonic-gate 			  unsigned *plen,
1103*7c478bd9Sstevel@tonic-gate 			  int *pcount)
1104*7c478bd9Sstevel@tonic-gate {
1105*7c478bd9Sstevel@tonic-gate     cmechanism_t *m=NULL;
1106*7c478bd9Sstevel@tonic-gate     sasl_ssf_t minssf = 0;
1107*7c478bd9Sstevel@tonic-gate     int ret;
1108*7c478bd9Sstevel@tonic-gate     unsigned int resultlen;
1109*7c478bd9Sstevel@tonic-gate     int flag;
1110*7c478bd9Sstevel@tonic-gate     const char *mysep;
1111*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
1112*7c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx = conn == NULL ? _sasl_gbl_ctx() : conn->gctx;
1113*7c478bd9Sstevel@tonic-gate     cmech_list_t *cmechlist;
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate     if(gctx->sasl_client_active==0) return SASL_NOTINIT;
1116*7c478bd9Sstevel@tonic-gate     cmechlist = gctx->cmechlist;
1117*7c478bd9Sstevel@tonic-gate #else
1118*7c478bd9Sstevel@tonic-gate     if(_sasl_client_active == 0) return SASL_NOTINIT;
1119*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
1120*7c478bd9Sstevel@tonic-gate     if (!conn) return SASL_BADPARAM;
1121*7c478bd9Sstevel@tonic-gate     if(conn->type != SASL_CONN_CLIENT) PARAMERROR(conn);
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate     if (! result)
1124*7c478bd9Sstevel@tonic-gate 	PARAMERROR(conn);
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
1127*7c478bd9Sstevel@tonic-gate      (void) _load_client_plugins(gctx);
1128*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate     if (plen != NULL)
1131*7c478bd9Sstevel@tonic-gate 	*plen = 0;
1132*7c478bd9Sstevel@tonic-gate     if (pcount != NULL)
1133*7c478bd9Sstevel@tonic-gate 	*pcount = 0;
1134*7c478bd9