source: trunk/third/cyrus-sasl/lib/client.c @ 19512

Revision 19512, 21.5 KB checked in by rbasch, 22 years ago (diff)
Set SASL_NOLOG for the "No worthy mechs found" error, so that the user does not see this message.
Line 
1/* SASL server API implementation
2 * Rob Siemborski
3 * Tim Martin
4 * $Id: client.c,v 1.2 2003-07-07 20:26:35 rbasch Exp $
5 */
6/*
7 * Copyright (c) 2001 Carnegie Mellon University.  All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in
18 *    the documentation and/or other materials provided with the
19 *    distribution.
20 *
21 * 3. The name "Carnegie Mellon University" must not be used to
22 *    endorse or promote products derived from this software without
23 *    prior written permission. For permission or any other legal
24 *    details, please contact 
25 *      Office of Technology Transfer
26 *      Carnegie Mellon University
27 *      5000 Forbes Avenue
28 *      Pittsburgh, PA  15213-3890
29 *      (412) 268-4387, fax: (412) 268-7395
30 *      tech-transfer@andrew.cmu.edu
31 *
32 * 4. Redistributions of any form whatsoever must retain the following
33 *    acknowledgment:
34 *    "This product includes software developed by Computing Services
35 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
36 *
37 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
38 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
40 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
42 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
43 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44 */
45
46#include <config.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <limits.h>
50#include <ctype.h>
51#include <string.h>
52#ifdef HAVE_UNISTD_H
53#include <unistd.h>
54#endif
55
56/* SASL Headers */
57#include "sasl.h"
58#include "saslplug.h"
59#include "saslutil.h"
60#include "saslint.h"
61
62static cmech_list_t *cmechlist; /* global var which holds the list */
63
64static sasl_global_callbacks_t global_callbacks;
65
66static int _sasl_client_active = 0;
67
68static int init_mechlist()
69{
70  cmechlist->mutex = sasl_MUTEX_ALLOC();
71  if(!cmechlist->mutex) return SASL_FAIL;
72 
73  cmechlist->utils=_sasl_alloc_utils(NULL, &global_callbacks);
74  if (cmechlist->utils==NULL)
75    return SASL_NOMEM;
76
77  cmechlist->mech_list=NULL;
78  cmechlist->mech_length=0;
79
80  return SASL_OK;
81}
82
83static void client_done(void) {
84  cmechanism_t *cm;
85  cmechanism_t *cprevm;
86
87  cm=cmechlist->mech_list; /* m point to begging of the list */
88  while (cm!=NULL)
89  {
90    cprevm=cm;
91    cm=cm->next;
92
93    if (cprevm->plug->mech_free) {
94        cprevm->plug->mech_free(cprevm->plug->glob_context,
95                                cmechlist->utils);
96    }
97
98    sasl_FREE(cprevm->plugname);
99    sasl_FREE(cprevm);   
100  }
101  sasl_MUTEX_FREE(cmechlist->mutex);
102  _sasl_free_utils(&cmechlist->utils);
103  sasl_FREE(cmechlist);
104
105  cmechlist = NULL;
106
107  _sasl_client_active = 0;
108}
109
110int sasl_client_add_plugin(const char *plugname,
111                           sasl_client_plug_init_t *entry_point)
112{
113  int plugcount;
114  sasl_client_plug_t *pluglist;
115  cmechanism_t *mech;
116  int result;
117  int version;
118  int lupe;
119
120  if(!plugname || !entry_point) return SASL_BADPARAM;
121 
122  result = entry_point(cmechlist->utils, SASL_CLIENT_PLUG_VERSION, &version,
123                       &pluglist, &plugcount);
124
125  if (result != SASL_OK)
126  {
127    _sasl_log(NULL, SASL_LOG_WARN,
128              "entry_point failed in sasl_client_add_plugin for %s",
129              plugname);
130    return result;
131  }
132
133  if (version != SASL_CLIENT_PLUG_VERSION)
134  {
135    _sasl_log(NULL, SASL_LOG_WARN,
136              "version conflict in sasl_client_add_plugin for %s", plugname);
137    return SASL_BADVERS;
138  }
139
140  for (lupe=0;lupe< plugcount ;lupe++)
141    {
142      mech = sasl_ALLOC(sizeof(cmechanism_t));
143      if (! mech) return SASL_NOMEM;
144
145      mech->plug=pluglist++;
146      if(_sasl_strdup(plugname, &mech->plugname, NULL) != SASL_OK) {
147        sasl_FREE(mech);
148        return SASL_NOMEM;
149      }
150      mech->version = version;
151      mech->next = cmechlist->mech_list;
152      cmechlist->mech_list = mech;
153      cmechlist->mech_length++;
154    }
155
156  return SASL_OK;
157}
158
159static int
160client_idle(sasl_conn_t *conn)
161{
162  cmechanism_t *m;
163  if (! cmechlist)
164    return 0;
165
166  for (m = cmechlist->mech_list;
167       m;
168       m = m->next)
169    if (m->plug->idle
170        &&  m->plug->idle(m->plug->glob_context,
171                          conn,
172                          conn ? ((sasl_client_conn_t *)conn)->cparams : NULL))
173      return 1;
174  return 0;
175}
176
177/* initialize the SASL client drivers
178 *  callbacks      -- base callbacks for all client connections
179 * returns:
180 *  SASL_OK        -- Success
181 *  SASL_NOMEM     -- Not enough memory
182 *  SASL_BADVERS   -- Mechanism version mismatch
183 *  SASL_BADPARAM  -- error in config file
184 *  SASL_NOMECH    -- No mechanisms available
185 *  ...
186 */
187
188int sasl_client_init(const sasl_callback_t *callbacks)
189{
190  int ret;
191  const add_plugin_list_t ep_list[] = {
192      { "sasl_client_plug_init", (add_plugin_t *)sasl_client_add_plugin },
193      { "sasl_canonuser_init", (add_plugin_t *)sasl_canonuser_add_plugin },
194      { NULL, NULL }
195  };
196
197  _sasl_client_cleanup_hook = &client_done;
198  _sasl_client_idle_hook = &client_idle;
199
200  global_callbacks.callbacks = callbacks;
201  global_callbacks.appname = NULL;
202
203  cmechlist=sasl_ALLOC(sizeof(cmech_list_t));
204  if (cmechlist==NULL) return SASL_NOMEM;
205
206  /* load plugins */
207  ret=init_mechlist(); 
208  if (ret!=SASL_OK)
209    return ret;
210
211  sasl_client_add_plugin("EXTERNAL", &external_client_plug_init);
212
213  ret = _sasl_common_init();
214
215  if (ret == SASL_OK)
216      ret = _sasl_load_plugins(ep_list,
217                               _sasl_find_getpath_callback(callbacks),
218                               _sasl_find_verifyfile_callback(callbacks));
219 
220  if (ret == SASL_OK) {
221      _sasl_client_active = 1;
222      ret = _sasl_build_mechlist();
223  }
224
225  return ret;
226}
227
228static void client_dispose(sasl_conn_t *pconn)
229{
230  sasl_client_conn_t *c_conn=(sasl_client_conn_t *) pconn;
231
232  if (c_conn->mech && c_conn->mech->plug->mech_dispose) {
233    c_conn->mech->plug->mech_dispose(pconn->context,
234                                     c_conn->cparams->utils);
235  }
236
237  pconn->context = NULL;
238
239  if (c_conn->clientFQDN)
240      sasl_FREE(c_conn->clientFQDN);
241
242  if (c_conn->cparams) {
243      _sasl_free_utils(&(c_conn->cparams->utils));
244      sasl_FREE(c_conn->cparams);
245  }
246
247  _sasl_conn_dispose(pconn);
248}
249
250/* initialize a client exchange based on the specified mechanism
251 *  service       -- registered name of the service using SASL (e.g. "imap")
252 *  serverFQDN    -- the fully qualified domain name of the server
253 *  iplocalport   -- client IPv4/IPv6 domain literal string with port
254 *                    (if NULL, then mechanisms requiring IPaddr are disabled)
255 *  ipremoteport  -- server IPv4/IPv6 domain literal string with port
256 *                    (if NULL, then mechanisms requiring IPaddr are disabled)
257 *  prompt_supp   -- list of client interactions supported
258 *                   may also include sasl_getopt_t context & call
259 *                   NULL prompt_supp = user/pass via SASL_INTERACT only
260 *                   NULL proc = interaction supported via SASL_INTERACT
261 *  secflags      -- security flags (see above)
262 * in/out:
263 *  pconn         -- connection negotiation structure
264 *                   pointer to NULL => allocate new
265 *                   non-NULL => recycle storage and go for next available mech
266 *
267 * Returns:
268 *  SASL_OK       -- success
269 *  SASL_NOMECH   -- no mechanism meets requested properties
270 *  SASL_NOMEM    -- not enough memory
271 */
272int sasl_client_new(const char *service,
273                    const char *serverFQDN,
274                    const char *iplocalport,
275                    const char *ipremoteport,
276                    const sasl_callback_t *prompt_supp,
277                    unsigned flags,
278                    sasl_conn_t **pconn)
279{
280  int result;
281  char name[MAXHOSTNAMELEN];
282  sasl_client_conn_t *conn;
283  sasl_utils_t *utils;
284
285  if(_sasl_client_active==0) return SASL_NOTINIT;
286 
287  /* Remember, iplocalport and ipremoteport can be NULL and be valid! */
288  if (!pconn || !service || !serverFQDN)
289    return SASL_BADPARAM;
290
291  *pconn=sasl_ALLOC(sizeof(sasl_client_conn_t));
292  if (*pconn==NULL) {
293      _sasl_log(NULL, SASL_LOG_ERR,
294                "Out of memory allocating connection context");
295      return SASL_NOMEM;
296  }
297  memset(*pconn, 0, sizeof(sasl_client_conn_t));
298
299  (*pconn)->destroy_conn = &client_dispose;
300
301  conn = (sasl_client_conn_t *)*pconn;
302 
303  conn->mech = NULL;
304
305  conn->cparams=sasl_ALLOC(sizeof(sasl_client_params_t));
306  if (conn->cparams==NULL)
307      MEMERROR(*pconn);
308  memset(conn->cparams,0,sizeof(sasl_client_params_t));
309
310  result = _sasl_conn_init(*pconn, service, flags, SASL_CONN_CLIENT,
311                           &client_idle, serverFQDN,
312                           iplocalport, ipremoteport,
313                           prompt_supp, &global_callbacks);
314  if (result != SASL_OK) RETURN(*pconn, result);
315 
316  utils=_sasl_alloc_utils(*pconn, &global_callbacks);
317  if (utils==NULL)
318      MEMERROR(*pconn);
319 
320  utils->conn= *pconn;
321
322  /* Setup the non-lazy parts of cparams, the rest is done in
323   * sasl_client_start */
324  conn->cparams->utils = utils;
325  conn->cparams->canon_user = &_sasl_canon_user;
326  conn->cparams->flags = flags;
327 
328  /* get the clientFQDN (serverFQDN was set in _sasl_conn_init) */
329  memset(name, 0, sizeof(name));
330  gethostname(name, MAXHOSTNAMELEN);
331
332  result = _sasl_strdup(name, &conn->clientFQDN, NULL);
333
334  if(result == SASL_OK) return SASL_OK;
335
336  /* result isn't SASL_OK */
337  _sasl_conn_dispose(*pconn);
338  sasl_FREE(*pconn);
339  *pconn = NULL;
340  _sasl_log(NULL, SASL_LOG_ERR, "Out of memory in sasl_client_new");
341  return result;
342}
343
344static int have_prompts(sasl_conn_t *conn,
345                        const sasl_client_plug_t *mech)
346{
347  static const unsigned long default_prompts[] = {
348    SASL_CB_AUTHNAME,
349    SASL_CB_PASS,
350    SASL_CB_LIST_END
351  };
352
353  const unsigned long *prompt;
354  int (*pproc)();
355  void *pcontext;
356  int result;
357
358  for (prompt = (mech->required_prompts
359                 ? mech->required_prompts :
360                 default_prompts);
361       *prompt != SASL_CB_LIST_END;
362       prompt++) {
363    result = _sasl_getcallback(conn, *prompt, &pproc, &pcontext);
364    if (result != SASL_OK && result != SASL_INTERACT)
365      return 0;                 /* we don't have this required prompt */
366  }
367
368  return 1; /* we have all the prompts */
369}
370
371/* select a mechanism for a connection
372 *  mechlist      -- mechanisms server has available (punctuation ignored)
373 *  secret        -- optional secret from previous session
374 * output:
375 *  prompt_need   -- on SASL_INTERACT, list of prompts needed to continue
376 *  clientout     -- the initial client response to send to the server
377 *  mech          -- set to mechanism name
378 *
379 * Returns:
380 *  SASL_OK       -- success
381 *  SASL_NOMEM    -- not enough memory
382 *  SASL_NOMECH   -- no mechanism meets requested properties
383 *  SASL_INTERACT -- user interaction needed to fill in prompt_need list
384 */
385
386/* xxx confirm this with rfc 2222
387 * SASL mechanism allowable characters are "AZaz-_"
388 * seperators can be any other characters and of any length
389 * even variable lengths between
390 *
391 * Apps should be encouraged to simply use space or comma space
392 * though
393 */
394int sasl_client_start(sasl_conn_t *conn,
395                      const char *mechlist,
396                      sasl_interact_t **prompt_need,
397                      const char **clientout,
398                      unsigned *clientoutlen,
399                      const char **mech)
400{
401    sasl_client_conn_t *c_conn= (sasl_client_conn_t *) conn;
402    char name[SASL_MECHNAMEMAX + 1];
403    cmechanism_t *m=NULL,*bestm=NULL;
404    size_t pos=0,place;
405    size_t list_len;
406    sasl_ssf_t bestssf = 0, minssf = 0;
407    int result;
408
409    if(_sasl_client_active==0) return SASL_NOTINIT;
410
411    if (!conn) return SASL_BADPARAM;
412
413    /* verify parameters */
414    if (mechlist == NULL)
415        PARAMERROR(conn);
416
417    /* if prompt_need != NULL we've already been here
418       and just need to do the continue step again */
419
420    /* do a step */
421    /* FIXME: Hopefully they only give us our own prompt_need back */
422    if (prompt_need && *prompt_need != NULL) {
423        goto dostep;
424    }
425
426    if(conn->props.min_ssf < conn->external.ssf) {
427        minssf = 0;
428    } else {
429        minssf = conn->props.min_ssf - conn->external.ssf;
430    }
431
432    /* parse mechlist */
433    list_len = strlen(mechlist);
434
435    while (pos<list_len)
436    {
437        place=0;
438        while ((pos<list_len) && (isalnum((unsigned char)mechlist[pos])
439                                  || mechlist[pos] == '_'
440                                  || mechlist[pos] == '-')) {
441            name[place]=mechlist[pos];
442            pos++;
443            place++;
444            if (SASL_MECHNAMEMAX < place) {
445                place--;
446                while(pos<list_len && (isalnum((unsigned char)mechlist[pos])
447                                       || mechlist[pos] == '_'
448                                       || mechlist[pos] == '-'))
449                    pos++;
450            }
451        }
452        pos++;
453        name[place]=0;
454
455        if (! place) continue;
456
457        /* foreach in server list */
458        for (m = cmechlist->mech_list; m != NULL; m = m->next) {
459            int myflags;
460           
461            /* Is this the mechanism the server is suggesting? */
462            if (strcasecmp(m->plug->mech_name, name))
463                continue; /* no */
464
465            /* Do we have the prompts for it? */
466            if (!have_prompts(conn, m->plug))
467                break;
468
469            /* Is it strong enough? */
470            if (minssf > m->plug->max_ssf)
471                break;
472
473            /* Does it meet our security properties? */
474            myflags = conn->props.security_flags;
475           
476            /* if there's an external layer this is no longer plaintext */
477            if ((conn->props.min_ssf <= conn->external.ssf) &&
478                (conn->external.ssf > 1)) {
479                myflags &= ~SASL_SEC_NOPLAINTEXT;
480            }
481
482            if (((myflags ^ m->plug->security_flags) & myflags) != 0) {
483                break;
484            }
485
486            /* Can we meet it's features? */
487            if ((m->plug->features & SASL_FEAT_NEEDSERVERFQDN)
488                && !conn->serverFQDN) {
489                break;
490            }
491
492            /* Can it meet our features? */
493            if ((conn->flags & SASL_NEED_PROXY) &&
494                !(m->plug->features & SASL_FEAT_ALLOWS_PROXY)) {
495                break;
496            }
497           
498#ifdef PREFER_MECH
499            if (strcasecmp(m->plug->mech_name, PREFER_MECH) &&
500                bestm && m->plug->max_ssf <= bestssf) {
501                /* this mechanism isn't our favorite, and it's no better
502                   than what we already have! */
503                break;
504            }
505#else
506            if (bestm && m->plug->max_ssf <= bestssf) {
507                /* this mechanism is no better than what we already have! */
508                break;
509            }
510#endif
511
512            /* compare security flags, only take new mechanism if it has
513             * all the security flags of the previous one.
514             *
515             * From the mechanisms we ship with, this yields the order:
516             *
517             * SRP
518             * GSSAPI + KERBEROS_V4
519             * DIGEST + OTP
520             * CRAM + EXTERNAL
521             * PLAIN + LOGIN + ANONYMOUS
522             *
523             * This might be improved on by comparing the numeric value of
524             * the bitwise-or'd security flags, which splits DIGEST/OTP,
525             * CRAM/EXTERNAL, and PLAIN/LOGIN from ANONYMOUS, but then we
526             * are depending on the numeric values of the flags (which may
527             * change, and their ordering could be considered dumb luck.
528             */
529
530            if (bestm &&
531                ((m->plug->security_flags ^ bestm->plug->security_flags) &
532                 bestm->plug->security_flags)) {
533                break;
534            }
535
536            if (mech) {
537                *mech = m->plug->mech_name;
538            }
539            bestssf = m->plug->max_ssf;
540            bestm = m;
541            break;
542        }
543    }
544
545    if (bestm == NULL) {
546        sasl_seterror(conn, SASL_NOLOG, "No worthy mechs found");
547        result = SASL_NOMECH;
548        goto done;
549    }
550
551    /* make (the rest of) cparams */
552    c_conn->cparams->service = conn->service;
553    c_conn->cparams->servicelen = strlen(conn->service);
554   
555    c_conn->cparams->serverFQDN = conn->serverFQDN;
556    c_conn->cparams->slen = strlen(conn->serverFQDN);
557
558    c_conn->cparams->clientFQDN = c_conn->clientFQDN;
559    c_conn->cparams->clen = strlen(c_conn->clientFQDN);
560
561    c_conn->cparams->external_ssf = conn->external.ssf;
562    c_conn->cparams->props = conn->props;
563    c_conn->mech = bestm;
564
565    /* init that plugin */
566    result = c_conn->mech->plug->mech_new(c_conn->mech->plug->glob_context,
567                                          c_conn->cparams,
568                                          &(conn->context));
569    if(result != SASL_OK) goto done;
570
571    /* do a step -- but only if we can do a client-send-first */
572 dostep:
573    if(clientout) {
574        if(c_conn->mech->plug->features & SASL_FEAT_SERVER_FIRST) {
575            *clientout = NULL;
576            *clientoutlen = 0;
577            result = SASL_CONTINUE;
578        } else {
579            result = sasl_client_step(conn, NULL, 0, prompt_need,
580                                      clientout, clientoutlen);
581        }
582    }
583    else
584        result = SASL_CONTINUE;
585
586 done:
587    RETURN(conn, result);
588}
589
590/* do a single authentication step.
591 *  serverin    -- the server message received by the client, MUST have a NUL
592 *                 sentinel, not counted by serverinlen
593 * output:
594 *  prompt_need -- on SASL_INTERACT, list of prompts needed to continue
595 *  clientout   -- the client response to send to the server
596 *
597 * returns:
598 *  SASL_OK        -- success
599 *  SASL_INTERACT  -- user interaction needed to fill in prompt_need list
600 *  SASL_BADPROT   -- server protocol incorrect/cancelled
601 *  SASL_BADSERV   -- server failed mutual auth
602 */
603
604int sasl_client_step(sasl_conn_t *conn,
605                     const char *serverin,
606                     unsigned serverinlen,
607                     sasl_interact_t **prompt_need,
608                     const char **clientout,
609                     unsigned *clientoutlen)
610{
611  sasl_client_conn_t *c_conn= (sasl_client_conn_t *) conn;
612  int result;
613
614  if(_sasl_client_active==0) return SASL_NOTINIT;
615  if(!conn) return SASL_BADPARAM;
616
617  /* check parameters */
618  if ((serverin==NULL) && (serverinlen>0))
619      PARAMERROR(conn);
620
621  /* Don't do another step if the plugin told us that we're done */
622  if (conn->oparams.doneflag) {
623      _sasl_log(conn, SASL_LOG_ERR, "attempting client step after doneflag");
624      return SASL_FAIL;
625  }
626
627  if(clientout) *clientout = NULL;
628  if(clientoutlen) *clientoutlen = 0;
629
630  /* do a step */
631  result = c_conn->mech->plug->mech_step(conn->context,
632                                         c_conn->cparams,
633                                         serverin,
634                                         serverinlen,
635                                         prompt_need,
636                                         clientout, (int *)clientoutlen,
637                                         &conn->oparams);
638
639  if (result == SASL_OK) {
640      /* So we're done on this end, but if both
641       * 1. the mech does server-send-last
642       * 2. the protocol does not
643       * we need to return no data */
644      if(!*clientout && !(conn->flags & SASL_SUCCESS_DATA)) {
645          *clientout = "";
646          *clientoutlen = 0;
647      }
648     
649      if(!conn->oparams.maxoutbuf) {
650          conn->oparams.maxoutbuf = conn->props.maxbufsize;
651      }
652
653      if(conn->oparams.user == NULL || conn->oparams.authid == NULL) {
654          sasl_seterror(conn, 0,
655                        "mech did not call canon_user for both authzid and authid");
656          result = SASL_BADPROT;
657      }
658  } 
659
660  RETURN(conn,result);
661}
662
663/* returns the length of all the mechanisms
664 * added up
665 */
666
667static unsigned mech_names_len()
668{
669  cmechanism_t *listptr;
670  unsigned result = 0;
671
672  for (listptr = cmechlist->mech_list;
673       listptr;
674       listptr = listptr->next)
675    result += strlen(listptr->plug->mech_name);
676
677  return result;
678}
679
680
681int _sasl_client_listmech(sasl_conn_t *conn,
682                          const char *prefix,
683                          const char *sep,
684                          const char *suffix,
685                          const char **result,
686                          unsigned *plen,
687                          int *pcount)
688{
689    cmechanism_t *m=NULL;
690    sasl_ssf_t minssf = 0;
691    int ret;
692    unsigned int resultlen;
693    int flag;
694    const char *mysep;
695
696    if(_sasl_client_active == 0) return SASL_NOTINIT;
697    if (!conn) return SASL_BADPARAM;
698    if(conn->type != SASL_CONN_CLIENT) PARAMERROR(conn);
699   
700    if (! result)
701        PARAMERROR(conn);
702   
703    if (plen != NULL)
704        *plen = 0;
705    if (pcount != NULL)
706        *pcount = 0;
707
708    if (sep) {
709        mysep = sep;
710    } else {
711        mysep = " ";
712    }
713
714    if(conn->props.min_ssf < conn->external.ssf) {
715        minssf = 0;
716    } else {
717        minssf = conn->props.min_ssf - conn->external.ssf;
718    }
719
720    if (! cmechlist || cmechlist->mech_length <= 0)
721        INTERROR(conn, SASL_NOMECH);
722
723    resultlen = (prefix ? strlen(prefix) : 0)
724        + (strlen(mysep) * (cmechlist->mech_length - 1))
725        + mech_names_len()
726        + (suffix ? strlen(suffix) : 0)
727        + 1;
728    ret = _buf_alloc(&conn->mechlist_buf,
729                     &conn->mechlist_buf_len, resultlen);
730    if(ret != SASL_OK) MEMERROR(conn);
731
732    if (prefix)
733        strcpy (conn->mechlist_buf,prefix);
734    else
735        *(conn->mechlist_buf) = '\0';
736
737    flag = 0;
738    for (m = cmechlist->mech_list; m != NULL; m = m->next) {
739            /* do we have the prompts for it? */
740            if (!have_prompts(conn, m->plug))
741                continue;
742
743            /* is it strong enough? */
744            if (minssf > m->plug->max_ssf)
745                continue;
746
747            /* does it meet our security properties? */
748            if (((conn->props.security_flags ^ m->plug->security_flags)
749                 & conn->props.security_flags) != 0) {
750                continue;
751            }
752
753            /* Can we meet it's features? */
754            if ((m->plug->features & SASL_FEAT_NEEDSERVERFQDN)
755                && !conn->serverFQDN) {
756                continue;
757            }
758
759            /* Can it meet our features? */
760            if ((conn->flags & SASL_NEED_PROXY) &&
761                !(m->plug->features & SASL_FEAT_ALLOWS_PROXY)) {
762                break;
763            }
764
765            /* Okay, we like it, add it to the list! */
766
767            if (pcount != NULL)
768                (*pcount)++;
769
770            /* print seperator */
771            if (flag) {
772                strcat(conn->mechlist_buf, mysep);
773            } else {
774                flag = 1;
775            }
776           
777            /* now print the mechanism name */
778            strcat(conn->mechlist_buf, m->plug->mech_name);
779    }
780   
781  if (suffix)
782      strcat(conn->mechlist_buf,suffix);
783
784  if (plen!=NULL)
785      *plen=strlen(conn->mechlist_buf);
786
787  *result = conn->mechlist_buf;
788
789  return SASL_OK;
790}
791
792sasl_string_list_t *_sasl_client_mechs(void)
793{
794  cmechanism_t *listptr;
795  sasl_string_list_t *retval = NULL, *next=NULL;
796
797  if(!_sasl_client_active) return NULL;
798
799  /* make list */
800  for (listptr = cmechlist->mech_list; listptr; listptr = listptr->next) {
801      next = sasl_ALLOC(sizeof(sasl_string_list_t));
802
803      if(!next && !retval) return NULL;
804      else if(!next) {
805          next = retval->next;
806          do {
807              sasl_FREE(retval);
808              retval = next;
809              next = retval->next;
810          } while(next);
811          return NULL;
812      }
813     
814      next->d = listptr->plug->mech_name;
815
816      if(!retval) {
817          next->next = NULL;
818          retval = next;
819      } else {
820          next->next = retval;
821          retval = next;
822      }
823  }
824
825  return retval;
826}
Note: See TracBrowser for help on using the repository browser.