2N/A/*
2N/A * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/* SASL server API implementation
2N/A * Rob Siemborski
2N/A * Tim Martin
2N/A * $Id: client.c,v 1.61 2003/04/16 19:36:00 rjs3 Exp $
2N/A */
2N/A/*
2N/A * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
2N/A *
2N/A * Redistribution and use in source and binary forms, with or without
2N/A * modification, are permitted provided that the following conditions
2N/A * are met:
2N/A *
2N/A * 1. Redistributions of source code must retain the above copyright
2N/A * notice, this list of conditions and the following disclaimer.
2N/A *
2N/A * 2. Redistributions in binary form must reproduce the above copyright
2N/A * notice, this list of conditions and the following disclaimer in
2N/A * the documentation and/or other materials provided with the
2N/A * distribution.
2N/A *
2N/A * 3. The name "Carnegie Mellon University" must not be used to
2N/A * endorse or promote products derived from this software without
2N/A * prior written permission. For permission or any other legal
2N/A * details, please contact
2N/A * Office of Technology Transfer
2N/A * Carnegie Mellon University
2N/A * 5000 Forbes Avenue
2N/A * Pittsburgh, PA 15213-3890
2N/A * (412) 268-4387, fax: (412) 268-7395
2N/A * tech-transfer@andrew.cmu.edu
2N/A *
2N/A * 4. Redistributions of any form whatsoever must retain the following
2N/A * acknowledgment:
2N/A * "This product includes software developed by Computing Services
2N/A * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
2N/A *
2N/A * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
2N/A * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
2N/A * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
2N/A * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2N/A * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
2N/A * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
2N/A * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2N/A */
2N/A
2N/A#include <config.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <limits.h>
2N/A#include <ctype.h>
2N/A#include <string.h>
2N/A#ifdef HAVE_UNISTD_H
2N/A#include <unistd.h>
2N/A#endif
2N/A
2N/A/* SASL Headers */
2N/A#include "sasl.h"
2N/A#include "saslplug.h"
2N/A#include "saslutil.h"
2N/A#include "saslint.h"
2N/A
2N/A#ifdef _SUN_SDK_
2N/ADEFINE_STATIC_MUTEX(init_client_mutex);
2N/ADEFINE_STATIC_MUTEX(client_active_mutex);
2N/A/*
2N/A * client_plug_mutex ensures only one client plugin is init'ed at a time
2N/A * If a plugin is loaded more than once, the glob_context may be overwritten
2N/A * which may lead to a memory leak. We keep glob_context with each mech
2N/A * to avoid this problem.
2N/A */
2N/ADEFINE_STATIC_MUTEX(client_plug_mutex);
2N/A#else
2N/Astatic cmech_list_t *cmechlist; /* global var which holds the list */
2N/A
2N/Astatic sasl_global_callbacks_t global_callbacks;
2N/A
2N/Astatic int _sasl_client_active = 0;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A#ifdef _SUN_SDK_
2N/Astatic int init_mechlist(_sasl_global_context_t *gctx)
2N/A{
2N/A cmech_list_t *cmechlist = gctx->cmechlist;
2N/A#else
2N/Astatic int init_mechlist()
2N/A{
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A cmechlist->mutex = sasl_MUTEX_ALLOC();
2N/A if(!cmechlist->mutex) return SASL_FAIL;
2N/A
2N/A#ifdef _SUN_SDK_
2N/A cmechlist->utils=
2N/A _sasl_alloc_utils(gctx, NULL, &gctx->client_global_callbacks);
2N/A#else
2N/A cmechlist->utils=_sasl_alloc_utils(NULL, &global_callbacks);
2N/A#endif /* _SUN_SDK_ */
2N/A if (cmechlist->utils==NULL)
2N/A return SASL_NOMEM;
2N/A
2N/A cmechlist->mech_list=NULL;
2N/A cmechlist->mech_length=0;
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/A#ifdef _SUN_SDK_
2N/Astatic int client_done(_sasl_global_context_t *gctx) {
2N/A cmech_list_t *cmechlist = gctx->cmechlist;
2N/A _sasl_path_info_t *path_info, *p;
2N/A#else
2N/Astatic int client_done(void) {
2N/A#endif /* _SUN_SDK_ */
2N/A cmechanism_t *cm;
2N/A cmechanism_t *cprevm;
2N/A
2N/A#ifdef _SUN_SDK_
2N/A if(!gctx->sasl_client_active)
2N/A return SASL_NOTINIT;
2N/A if (LOCK_MUTEX(&client_active_mutex) < 0) {
2N/A return (SASL_FAIL);
2N/A }
2N/A gctx->sasl_client_active--;
2N/A
2N/A if(gctx->sasl_client_active) {
2N/A /* Don't de-init yet! Our refcount is nonzero. */
2N/A UNLOCK_MUTEX(&client_active_mutex);
2N/A return SASL_CONTINUE;
2N/A }
2N/A#else
2N/A if(!_sasl_client_active)
2N/A return SASL_NOTINIT;
2N/A else
2N/A _sasl_client_active--;
2N/A
2N/A if(_sasl_client_active) {
2N/A /* Don't de-init yet! Our refcount is nonzero. */
2N/A return SASL_CONTINUE;
2N/A }
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A cm=cmechlist->mech_list; /* m point to begging of the list */
2N/A while (cm!=NULL)
2N/A {
2N/A cprevm=cm;
2N/A cm=cm->next;
2N/A
2N/A if (cprevm->plug->mech_free) {
2N/A#ifdef _SUN_SDK_
2N/A cprevm->plug->mech_free(cprevm->glob_context, cmechlist->utils);
2N/A#else
2N/A cprevm->plug->mech_free(cprevm->plug->glob_context,
2N/A cmechlist->utils);
2N/A#endif /* _SUN_SDK_ */
2N/A }
2N/A
2N/A sasl_FREE(cprevm->plugname);
2N/A sasl_FREE(cprevm);
2N/A }
2N/A sasl_MUTEX_FREE(cmechlist->mutex);
2N/A _sasl_free_utils(&cmechlist->utils);
2N/A sasl_FREE(cmechlist);
2N/A
2N/A#ifdef _SUN_SDK_
2N/A gctx->cmechlist = NULL;
2N/A p = gctx->cplug_path_info;
2N/A while((path_info = p) != NULL) {
2N/A sasl_FREE(path_info->path);
2N/A p = path_info->next;
2N/A sasl_FREE(path_info);
2N/A }
2N/A gctx->cplug_path_info = NULL;
2N/A UNLOCK_MUTEX(&client_active_mutex);
2N/A#else
2N/A cmechlist = NULL;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/Aint sasl_client_add_plugin(const char *plugname,
2N/A sasl_client_plug_init_t *entry_point)
2N/A{
2N/A#ifdef _SUN_SDK_
2N/A return (_sasl_client_add_plugin(_sasl_gbl_ctx(), plugname, entry_point));
2N/A}
2N/A
2N/Aint _sasl_client_add_plugin(void *ctx,
2N/A const char *plugname,
2N/A sasl_client_plug_init_t *entry_point)
2N/A{
2N/A cmech_list_t *cmechlist;
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx;
2N/A /* EXPORT DELETE START */
2N/A /* CRYPT DELETE START */
2N/A int sun_reg;
2N/A /* CRYPT DELETE END */
2N/A /* EXPORT DELETE END */
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A int i;
2N/A cmechanism_t *m;
2N/A#endif /* _SUN_SDK_ */
2N/A int plugcount;
2N/A sasl_client_plug_t *pluglist;
2N/A cmechanism_t *mech;
2N/A int result;
2N/A int version;
2N/A int lupe;
2N/A
2N/A if(!plugname || !entry_point) return SASL_BADPARAM;
2N/A
2N/A#ifdef _SUN_SDK_
2N/A cmechlist = gctx->cmechlist;
2N/A
2N/A if (cmechlist == NULL) return SASL_BADPARAM;
2N/A
2N/A /* Check to see if this plugin has already been registered */
2N/A m = cmechlist->mech_list;
2N/A for (i = 0; i < cmechlist->mech_length; i++) {
2N/A if (strcmp(plugname, m->plugname) == 0) {
2N/A return SASL_OK;
2N/A }
2N/A m = m->next;
2N/A }
2N/A
2N/A result = LOCK_MUTEX(&client_plug_mutex);
2N/A if (result != SASL_OK)
2N/A return result;
2N/A
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A result = entry_point(cmechlist->utils, SASL_CLIENT_PLUG_VERSION, &version,
2N/A &pluglist, &plugcount);
2N/A
2N/A /* EXPORT DELETE START */
2N/A /* CRYPT DELETE START */
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A sun_reg = _is_sun_reg(pluglist);
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A /* CRYPT DELETE END */
2N/A /* EXPORT DELETE END */
2N/A if (result != SASL_OK)
2N/A {
2N/A#ifdef _SUN_SDK_
2N/A UNLOCK_MUTEX(&client_plug_mutex);
2N/A __sasl_log(gctx, gctx->client_global_callbacks.callbacks, SASL_LOG_WARN,
2N/A "entry_point failed in sasl_client_add_plugin for %s",
2N/A plugname);
2N/A#else
2N/A _sasl_log(NULL, SASL_LOG_WARN,
2N/A "entry_point failed in sasl_client_add_plugin for %s",
2N/A plugname);
2N/A#endif /* _SUN_SDK_ */
2N/A return result;
2N/A }
2N/A
2N/A if (version != SASL_CLIENT_PLUG_VERSION)
2N/A {
2N/A#ifdef _SUN_SDK_
2N/A UNLOCK_MUTEX(&client_plug_mutex);
2N/A __sasl_log(gctx, gctx->client_global_callbacks.callbacks, SASL_LOG_WARN,
2N/A "version conflict in sasl_client_add_plugin for %s", plugname);
2N/A#else
2N/A _sasl_log(NULL, SASL_LOG_WARN,
2N/A "version conflict in sasl_client_add_plugin for %s", plugname);
2N/A#endif /* _SUN_SDK_ */
2N/A return SASL_BADVERS;
2N/A }
2N/A
2N/A#ifdef _SUN_SDK_
2N/A /* Check plugins to make sure mech_name is non-NULL */
2N/A for (lupe=0;lupe < plugcount ;lupe++) {
2N/A if (pluglist[lupe].mech_name == NULL)
2N/A break;
2N/A }
2N/A if (lupe < plugcount) {
2N/A UNLOCK_MUTEX(&client_plug_mutex);
2N/A __sasl_log(gctx, gctx->client_global_callbacks.callbacks,
2N/A SASL_LOG_ERR, "invalid client plugin %s", plugname);
2N/A return SASL_BADPROT;
2N/A }
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A for (lupe=0;lupe< plugcount ;lupe++)
2N/A {
2N/A mech = sasl_ALLOC(sizeof(cmechanism_t));
2N/A#ifdef _SUN_SDK_
2N/A if (! mech) {
2N/A UNLOCK_MUTEX(&client_plug_mutex);
2N/A return SASL_NOMEM;
2N/A }
2N/A mech->glob_context = pluglist->glob_context;
2N/A#else
2N/A if (! mech) return SASL_NOMEM;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A mech->plug=pluglist++;
2N/A if(_sasl_strdup(plugname, &mech->plugname, NULL) != SASL_OK) {
2N/A#ifdef _SUN_SDK_
2N/A UNLOCK_MUTEX(&client_plug_mutex);
2N/A#endif /* _SUN_SDK_ */
2N/A sasl_FREE(mech);
2N/A return SASL_NOMEM;
2N/A }
2N/A /* EXPORT DELETE START */
2N/A /* CRYPT DELETE START */
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A mech->sun_reg = sun_reg;
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A /* CRYPT DELETE END */
2N/A /* EXPORT DELETE END */
2N/A mech->version = version;
2N/A mech->next = cmechlist->mech_list;
2N/A cmechlist->mech_list = mech;
2N/A cmechlist->mech_length++;
2N/A }
2N/A#ifdef _SUN_SDK_
2N/A UNLOCK_MUTEX(&client_plug_mutex);
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/Astatic int
2N/Aclient_idle(sasl_conn_t *conn)
2N/A{
2N/A cmechanism_t *m;
2N/A#ifdef _SUN_SDK_
2N/A _sasl_global_context_t *gctx = conn == NULL ? _sasl_gbl_ctx() : conn->gctx;
2N/A cmech_list_t *cmechlist = gctx->cmechlist;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A if (! cmechlist)
2N/A return 0;
2N/A
2N/A for (m = cmechlist->mech_list;
2N/A m;
2N/A m = m->next)
2N/A if (m->plug->idle
2N/A#ifdef _SUN_SDK_
2N/A && m->plug->idle(m->glob_context,
2N/A#else
2N/A && m->plug->idle(m->plug->glob_context,
2N/A#endif /* _SUN_SDK_ */
2N/A conn,
2N/A conn ? ((sasl_client_conn_t *)conn)->cparams : NULL))
2N/A return 1;
2N/A return 0;
2N/A}
2N/A
2N/A#ifdef _SUN_SDK_
2N/Astatic int _load_client_plugins(_sasl_global_context_t *gctx)
2N/A{
2N/A int ret;
2N/A const add_plugin_list_t _ep_list[] = {
2N/A { "sasl_client_plug_init", (add_plugin_t *)_sasl_client_add_plugin },
2N/A { "sasl_canonuser_init", (add_plugin_t *)_sasl_canonuser_add_plugin },
2N/A { NULL, NULL }
2N/A };
2N/A const sasl_callback_t *callbacks = gctx->client_global_callbacks.callbacks;
2N/A
2N/A ret = _sasl_load_plugins(gctx, 0, _ep_list,
2N/A _sasl_find_getpath_callback(callbacks),
2N/A _sasl_find_verifyfile_callback(callbacks));
2N/A return (ret);
2N/A}
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A/* initialize the SASL client drivers
2N/A * callbacks -- base callbacks for all client connections
2N/A * returns:
2N/A * SASL_OK -- Success
2N/A * SASL_NOMEM -- Not enough memory
2N/A * SASL_BADVERS -- Mechanism version mismatch
2N/A * SASL_BADPARAM -- error in config file
2N/A * SASL_NOMECH -- No mechanisms available
2N/A * ...
2N/A */
2N/A
2N/Aint sasl_client_init(const sasl_callback_t *callbacks)
2N/A{
2N/A#ifdef _SUN_SDK_
2N/A return _sasl_client_init(NULL, callbacks);
2N/A}
2N/A
2N/Aint _sasl_client_init(void *ctx,
2N/A const sasl_callback_t *callbacks)
2N/A{
2N/A int ret;
2N/A _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx;
2N/A
2N/A if (gctx == NULL)
2N/A gctx = _sasl_gbl_ctx();
2N/A
2N/A ret = LOCK_MUTEX(&init_client_mutex);
2N/A if (ret < 0) {
2N/A return (SASL_FAIL);
2N/A }
2N/A ret = LOCK_MUTEX(&client_active_mutex);
2N/A if (ret < 0) {
2N/A UNLOCK_MUTEX(&init_client_mutex);
2N/A return (SASL_FAIL);
2N/A }
2N/A if(gctx->sasl_client_active) {
2N/A /* We're already active, just increase our refcount */
2N/A /* xxx do something with the callback structure? */
2N/A gctx->sasl_client_active++;
2N/A UNLOCK_MUTEX(&client_active_mutex);
2N/A UNLOCK_MUTEX(&init_client_mutex);
2N/A return SASL_OK;
2N/A }
2N/A
2N/A gctx->client_global_callbacks.callbacks = callbacks;
2N/A gctx->client_global_callbacks.appname = NULL;
2N/A
2N/A gctx->cmechlist=sasl_ALLOC(sizeof(cmech_list_t));
2N/A if (gctx->cmechlist==NULL) {
2N/A UNLOCK_MUTEX(&init_client_mutex);
2N/A UNLOCK_MUTEX(&client_active_mutex);
2N/A return SASL_NOMEM;
2N/A }
2N/A
2N/A gctx->sasl_client_active = 1;
2N/A UNLOCK_MUTEX(&client_active_mutex);
2N/A
2N/A /* load plugins */
2N/A ret=init_mechlist(gctx);
2N/A
2N/A if (ret!=SASL_OK) {
2N/A client_done(gctx);
2N/A UNLOCK_MUTEX(&init_client_mutex);
2N/A return ret;
2N/A }
2N/A _sasl_client_add_plugin(gctx, "EXTERNAL", &external_client_plug_init);
2N/A
2N/A ret = _sasl_common_init(gctx, &gctx->client_global_callbacks, 0);
2N/A#else
2N/Aint sasl_client_init(const sasl_callback_t *callbacks)
2N/A{
2N/A int ret;
2N/A const add_plugin_list_t ep_list[] = {
2N/A { "sasl_client_plug_init", (add_plugin_t *)sasl_client_add_plugin },
2N/A { "sasl_canonuser_init", (add_plugin_t *)sasl_canonuser_add_plugin },
2N/A { NULL, NULL }
2N/A };
2N/A
2N/A if(_sasl_client_active) {
2N/A /* We're already active, just increase our refcount */
2N/A /* xxx do something with the callback structure? */
2N/A _sasl_client_active++;
2N/A return SASL_OK;
2N/A }
2N/A
2N/A global_callbacks.callbacks = callbacks;
2N/A global_callbacks.appname = NULL;
2N/A
2N/A cmechlist=sasl_ALLOC(sizeof(cmech_list_t));
2N/A if (cmechlist==NULL) return SASL_NOMEM;
2N/A
2N/A /* We need to call client_done if we fail now */
2N/A _sasl_client_active = 1;
2N/A
2N/A /* load plugins */
2N/A ret=init_mechlist();
2N/A if (ret!=SASL_OK) {
2N/A client_done();
2N/A return ret;
2N/A }
2N/A
2N/A sasl_client_add_plugin("EXTERNAL", &external_client_plug_init);
2N/A
2N/A ret = _sasl_common_init(&global_callbacks);
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A if (ret == SASL_OK)
2N/A#ifdef _SUN_SDK_
2N/A ret = _load_client_plugins(gctx);
2N/A#else
2N/A ret = _sasl_load_plugins(ep_list,
2N/A _sasl_find_getpath_callback(callbacks),
2N/A _sasl_find_verifyfile_callback(callbacks));
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A#ifdef _SUN_SDK_
2N/A if (ret == SASL_OK)
2N/A /* If sasl_client_init returns error, sasl_done() need not be called */
2N/A ret = _sasl_build_mechlist(gctx);
2N/A if (ret == SASL_OK) {
2N/A gctx->sasl_client_cleanup_hook = &client_done;
2N/A gctx->sasl_client_idle_hook = &client_idle;
2N/A } else {
2N/A client_done(gctx);
2N/A }
2N/A UNLOCK_MUTEX(&init_client_mutex);
2N/A#else
2N/A if (ret == SASL_OK) {
2N/A _sasl_client_cleanup_hook = &client_done;
2N/A _sasl_client_idle_hook = &client_idle;
2N/A
2N/A ret = _sasl_build_mechlist();
2N/A } else {
2N/A client_done();
2N/A }
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A return ret;
2N/A}
2N/A
2N/Astatic void client_dispose(sasl_conn_t *pconn)
2N/A{
2N/A sasl_client_conn_t *c_conn=(sasl_client_conn_t *) pconn;
2N/A#ifdef _SUN_SDK_
2N/A sasl_free_t *free_func = c_conn->cparams->utils->free;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A if (c_conn->mech && c_conn->mech->plug->mech_dispose) {
2N/A c_conn->mech->plug->mech_dispose(pconn->context,
2N/A c_conn->cparams->utils);
2N/A }
2N/A
2N/A pconn->context = NULL;
2N/A
2N/A if (c_conn->clientFQDN)
2N/A#ifdef _SUN_SDK_
2N/A free_func(c_conn->clientFQDN);
2N/A#else
2N/A sasl_FREE(c_conn->clientFQDN);
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A if (c_conn->cparams) {
2N/A _sasl_free_utils(&(c_conn->cparams->utils));
2N/A#ifdef _SUN_SDK_
2N/A free_func(c_conn->cparams);
2N/A#else
2N/A sasl_FREE(c_conn->cparams);
2N/A#endif /* _SUN_SDK_ */
2N/A }
2N/A
2N/A _sasl_conn_dispose(pconn);
2N/A}
2N/A
2N/A/* initialize a client exchange based on the specified mechanism
2N/A * service -- registered name of the service using SASL (e.g. "imap")
2N/A * serverFQDN -- the fully qualified domain name of the server
2N/A * iplocalport -- client IPv4/IPv6 domain literal string with port
2N/A * (if NULL, then mechanisms requiring IPaddr are disabled)
2N/A * ipremoteport -- server IPv4/IPv6 domain literal string with port
2N/A * (if NULL, then mechanisms requiring IPaddr are disabled)
2N/A * prompt_supp -- list of client interactions supported
2N/A * may also include sasl_getopt_t context & call
2N/A * NULL prompt_supp = user/pass via SASL_INTERACT only
2N/A * NULL proc = interaction supported via SASL_INTERACT
2N/A * secflags -- security flags (see above)
2N/A * in/out:
2N/A * pconn -- connection negotiation structure
2N/A * pointer to NULL => allocate new
2N/A * non-NULL => recycle storage and go for next available mech
2N/A *
2N/A * Returns:
2N/A * SASL_OK -- success
2N/A * SASL_NOMECH -- no mechanism meets requested properties
2N/A * SASL_NOMEM -- not enough memory
2N/A */
2N/Aint sasl_client_new(const char *service,
2N/A const char *serverFQDN,
2N/A const char *iplocalport,
2N/A const char *ipremoteport,
2N/A const sasl_callback_t *prompt_supp,
2N/A unsigned flags,
2N/A sasl_conn_t **pconn)
2N/A{
2N/A#ifdef _SUN_SDK_
2N/A return _sasl_client_new(NULL, service, serverFQDN, iplocalport,
2N/A ipremoteport, prompt_supp, flags, pconn);
2N/A}
2N/Aint _sasl_client_new(void *ctx,
2N/A const char *service,
2N/A const char *serverFQDN,
2N/A const char *iplocalport,
2N/A const char *ipremoteport,
2N/A const sasl_callback_t *prompt_supp,
2N/A unsigned flags,
2N/A sasl_conn_t **pconn)
2N/A{
2N/A _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx;
2N/A#endif /* _SUN_SDK_ */
2N/A int result;
2N/A char name[MAXHOSTNAMELEN];
2N/A sasl_client_conn_t *conn;
2N/A sasl_utils_t *utils;
2N/A
2N/A#ifdef _SUN_SDK_
2N/A if (gctx == NULL)
2N/A gctx = _sasl_gbl_ctx();
2N/A
2N/A if(gctx->sasl_client_active==0) return SASL_NOTINIT;
2N/A#else
2N/A if(_sasl_client_active==0) return SASL_NOTINIT;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A /* Remember, iplocalport and ipremoteport can be NULL and be valid! */
2N/A if (!pconn || !service || !serverFQDN)
2N/A return SASL_BADPARAM;
2N/A
2N/A *pconn=sasl_ALLOC(sizeof(sasl_client_conn_t));
2N/A if (*pconn==NULL) {
2N/A#ifdef _SUN_SDK_
2N/A __sasl_log(gctx, gctx->client_global_callbacks.callbacks, SASL_LOG_ERR,
2N/A "Out of memory allocating connection context");
2N/A#else
2N/A _sasl_log(NULL, SASL_LOG_ERR,
2N/A "Out of memory allocating connection context");
2N/A#endif /* _SUN_SDK_ */
2N/A return SASL_NOMEM;
2N/A }
2N/A memset(*pconn, 0, sizeof(sasl_client_conn_t));
2N/A
2N/A#ifdef _SUN_SDK_
2N/A (*pconn)->gctx = gctx;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A (*pconn)->destroy_conn = &client_dispose;
2N/A
2N/A conn = (sasl_client_conn_t *)*pconn;
2N/A
2N/A conn->mech = NULL;
2N/A
2N/A conn->cparams=sasl_ALLOC(sizeof(sasl_client_params_t));
2N/A if (conn->cparams==NULL)
2N/A MEMERROR(*pconn);
2N/A memset(conn->cparams,0,sizeof(sasl_client_params_t));
2N/A
2N/A result = _sasl_conn_init(*pconn, service, flags, SASL_CONN_CLIENT,
2N/A &client_idle, serverFQDN,
2N/A iplocalport, ipremoteport,
2N/A#ifdef _SUN_SDK_
2N/A prompt_supp, &gctx->client_global_callbacks);
2N/A#else
2N/A prompt_supp, &global_callbacks);
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A if (result != SASL_OK) RETURN(*pconn, result);
2N/A
2N/A#ifdef _SUN_SDK_
2N/A utils=_sasl_alloc_utils(gctx, *pconn, &gctx->client_global_callbacks);
2N/A#else
2N/A utils=_sasl_alloc_utils(*pconn, &global_callbacks);
2N/A#endif /* _SUN_SDK_ */
2N/A if (utils==NULL)
2N/A MEMERROR(*pconn);
2N/A
2N/A utils->conn= *pconn;
2N/A
2N/A /* Setup the non-lazy parts of cparams, the rest is done in
2N/A * sasl_client_start */
2N/A conn->cparams->utils = utils;
2N/A conn->cparams->canon_user = &_sasl_canon_user;
2N/A conn->cparams->flags = flags;
2N/A conn->cparams->prompt_supp = (*pconn)->callbacks;
2N/A
2N/A /* get the clientFQDN (serverFQDN was set in _sasl_conn_init) */
2N/A memset(name, 0, sizeof(name));
2N/A gethostname(name, MAXHOSTNAMELEN);
2N/A
2N/A result = _sasl_strdup(name, &conn->clientFQDN, NULL);
2N/A
2N/A if(result == SASL_OK) return SASL_OK;
2N/A
2N/A#ifdef _SUN_SDK_
2N/A conn->cparams->iplocalport = (*pconn)->iplocalport;
2N/A conn->cparams->iploclen = strlen((*pconn)->iplocalport);
2N/A conn->cparams->ipremoteport = (*pconn)->ipremoteport;
2N/A conn->cparams->ipremlen = strlen((*pconn)->ipremoteport);
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A /* result isn't SASL_OK */
2N/A _sasl_conn_dispose(*pconn);
2N/A sasl_FREE(*pconn);
2N/A *pconn = NULL;
2N/A#ifdef _SUN_SDK_
2N/A __sasl_log(gctx, gctx->client_global_callbacks.callbacks, SASL_LOG_ERR,
2N/A "Out of memory in sasl_client_new");
2N/A#else
2N/A _sasl_log(NULL, SASL_LOG_ERR, "Out of memory in sasl_client_new");
2N/A#endif /* _SUN_SDK_ */
2N/A return result;
2N/A}
2N/A
2N/Astatic int have_prompts(sasl_conn_t *conn,
2N/A const sasl_client_plug_t *mech)
2N/A{
2N/A static const unsigned long default_prompts[] = {
2N/A SASL_CB_AUTHNAME,
2N/A SASL_CB_PASS,
2N/A SASL_CB_LIST_END
2N/A };
2N/A
2N/A const unsigned long *prompt;
2N/A int (*pproc)();
2N/A void *pcontext;
2N/A int result;
2N/A
2N/A for (prompt = (mech->required_prompts
2N/A ? mech->required_prompts :
2N/A default_prompts);
2N/A *prompt != SASL_CB_LIST_END;
2N/A prompt++) {
2N/A result = _sasl_getcallback(conn, *prompt, &pproc, &pcontext);
2N/A if (result != SASL_OK && result != SASL_INTERACT)
2N/A return 0; /* we don't have this required prompt */
2N/A }
2N/A
2N/A return 1; /* we have all the prompts */
2N/A}
2N/A
2N/A/* select a mechanism for a connection
2N/A * mechlist -- mechanisms server has available (punctuation ignored)
2N/A * secret -- optional secret from previous session
2N/A * output:
2N/A * prompt_need -- on SASL_INTERACT, list of prompts needed to continue
2N/A * clientout -- the initial client response to send to the server
2N/A * mech -- set to mechanism name
2N/A *
2N/A * Returns:
2N/A * SASL_OK -- success
2N/A * SASL_NOMEM -- not enough memory
2N/A * SASL_NOMECH -- no mechanism meets requested properties
2N/A * SASL_INTERACT -- user interaction needed to fill in prompt_need list
2N/A */
2N/A
2N/A/* xxx confirm this with rfc 2222
2N/A * SASL mechanism allowable characters are "AZaz-_"
2N/A * separators can be any other characters and of any length
2N/A * even variable lengths between
2N/A *
2N/A * Apps should be encouraged to simply use space or comma space
2N/A * though
2N/A */
2N/Aint sasl_client_start(sasl_conn_t *conn,
2N/A const char *mechlist,
2N/A sasl_interact_t **prompt_need,
2N/A const char **clientout,
2N/A unsigned *clientoutlen,
2N/A const char **mech)
2N/A{
2N/A sasl_client_conn_t *c_conn= (sasl_client_conn_t *) conn;
2N/A char name[SASL_MECHNAMEMAX + 1];
2N/A cmechanism_t *m=NULL,*bestm=NULL;
2N/A size_t pos=0,place;
2N/A size_t list_len;
2N/A sasl_ssf_t bestssf = 0, minssf = 0;
2N/A int result;
2N/A#ifdef _SUN_SDK_
2N/A _sasl_global_context_t *gctx = (conn == NULL) ?
2N/A _sasl_gbl_ctx() : conn->gctx;
2N/A cmech_list_t *cmechlist;
2N/A
2N/A if(gctx->sasl_client_active==0) return SASL_NOTINIT;
2N/A cmechlist = gctx->cmechlist;
2N/A#else
2N/A if(_sasl_client_active==0) return SASL_NOTINIT;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A if (!conn) return SASL_BADPARAM;
2N/A
2N/A /* verify parameters */
2N/A if (mechlist == NULL)
2N/A PARAMERROR(conn);
2N/A
2N/A /* if prompt_need != NULL we've already been here
2N/A and just need to do the continue step again */
2N/A
2N/A /* do a step */
2N/A /* FIXME: Hopefully they only give us our own prompt_need back */
2N/A if (prompt_need && *prompt_need != NULL) {
2N/A goto dostep;
2N/A }
2N/A
2N/A#ifdef _SUN_SDK_
2N/A if (c_conn->mech != NULL) {
2N/A if (c_conn->mech->plug->mech_dispose != NULL) {
2N/A c_conn->mech->plug->mech_dispose(conn->context,
2N/A c_conn->cparams->utils);
2N/A c_conn->mech = NULL;
2N/A }
2N/A }
2N/A memset(&conn->oparams, 0, sizeof(sasl_out_params_t));
2N/A
2N/A (void) _load_client_plugins(gctx);
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A if(conn->props.min_ssf < conn->external.ssf) {
2N/A minssf = 0;
2N/A } else {
2N/A minssf = conn->props.min_ssf - conn->external.ssf;
2N/A }
2N/A
2N/A /* parse mechlist */
2N/A list_len = strlen(mechlist);
2N/A
2N/A while (pos<list_len)
2N/A {
2N/A place=0;
2N/A while ((pos<list_len) && (isalnum((unsigned char)mechlist[pos])
2N/A || mechlist[pos] == '_'
2N/A || mechlist[pos] == '-')) {
2N/A name[place]=mechlist[pos];
2N/A pos++;
2N/A place++;
2N/A if (SASL_MECHNAMEMAX < place) {
2N/A place--;
2N/A while(pos<list_len && (isalnum((unsigned char)mechlist[pos])
2N/A || mechlist[pos] == '_'
2N/A || mechlist[pos] == '-'))
2N/A pos++;
2N/A }
2N/A }
2N/A pos++;
2N/A name[place]=0;
2N/A
2N/A if (! place) continue;
2N/A
2N/A /* foreach in server list */
2N/A for (m = cmechlist->mech_list; m != NULL; m = m->next) {
2N/A int myflags;
2N/A
2N/A /* Is this the mechanism the server is suggesting? */
2N/A if (strcasecmp(m->plug->mech_name, name))
2N/A continue; /* no */
2N/A
2N/A /* Do we have the prompts for it? */
2N/A if (!have_prompts(conn, m->plug))
2N/A break;
2N/A
2N/A /* Is it strong enough? */
2N/A if (minssf > m->plug->max_ssf)
2N/A break;
2N/A
2N/A /* EXPORT DELETE START */
2N/A /* CRYPT DELETE START */
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A /* If not SUN supplied mech, it has no strength */
2N/A if (minssf > 0 && !m->sun_reg)
2N/A break;
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A /* CRYPT DELETE END */
2N/A /* EXPORT DELETE END */
2N/A
2N/A /* Does it meet our security properties? */
2N/A myflags = conn->props.security_flags;
2N/A
2N/A /* if there's an external layer this is no longer plaintext */
2N/A if ((conn->props.min_ssf <= conn->external.ssf) &&
2N/A (conn->external.ssf > 1)) {
2N/A myflags &= ~SASL_SEC_NOPLAINTEXT;
2N/A }
2N/A
2N/A if (((myflags ^ m->plug->security_flags) & myflags) != 0) {
2N/A break;
2N/A }
2N/A
2N/A /* Can we meet it's features? */
2N/A if ((m->plug->features & SASL_FEAT_NEEDSERVERFQDN)
2N/A && !conn->serverFQDN) {
2N/A break;
2N/A }
2N/A
2N/A /* Can it meet our features? */
2N/A if ((conn->flags & SASL_NEED_PROXY) &&
2N/A !(m->plug->features & SASL_FEAT_ALLOWS_PROXY)) {
2N/A break;
2N/A }
2N/A
2N/A#ifdef PREFER_MECH
2N/A /* EXPORT DELETE START */
2N/A /* CRYPT DELETE START */
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A if (strcasecmp(m->plug->mech_name, PREFER_MECH) &&
2N/A bestm && (m->sun_reg && m->plug->max_ssf <= bestssf) ||
2N/A (m->plug->max_ssf == 0)) {
2N/A#else
2N/A /* CRYPT DELETE END */
2N/A /* EXPORT DELETE END */
2N/A if (strcasecmp(m->plug->mech_name, PREFER_MECH) &&
2N/A bestm && m->plug->max_ssf <= bestssf) {
2N/A
2N/A /* EXPORT DELETE START */
2N/A /* CRYPT DELETE START */
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A /* CRYPT DELETE END */
2N/A /* EXPORT DELETE END */
2N/A
2N/A /* this mechanism isn't our favorite, and it's no better
2N/A than what we already have! */
2N/A break;
2N/A }
2N/A#else
2N/A /* EXPORT DELETE START */
2N/A /* CRYPT DELETE START */
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A if (bestm && m->sun_reg && m->plug->max_ssf <= bestssf) {
2N/A#else
2N/A /* CRYPT DELETE END */
2N/A /* EXPORT DELETE END */
2N/A
2N/A if (bestm && m->plug->max_ssf <= bestssf) {
2N/A /* EXPORT DELETE START */
2N/A /* CRYPT DELETE START */
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A /* CRYPT DELETE END */
2N/A /* EXPORT DELETE END */
2N/A
2N/A /* this mechanism is no better than what we already have! */
2N/A break;
2N/A }
2N/A#endif
2N/A
2N/A /* compare security flags, only take new mechanism if it has
2N/A * all the security flags of the previous one.
2N/A *
2N/A * From the mechanisms we ship with, this yields the order:
2N/A *
2N/A * SRP
2N/A * GSSAPI + KERBEROS_V4
2N/A * DIGEST + OTP
2N/A * CRAM + EXTERNAL
2N/A * PLAIN + LOGIN + ANONYMOUS
2N/A *
2N/A * This might be improved on by comparing the numeric value of
2N/A * the bitwise-or'd security flags, which splits DIGEST/OTP,
2N/A * CRAM/EXTERNAL, and PLAIN/LOGIN from ANONYMOUS, but then we
2N/A * are depending on the numeric values of the flags (which may
2N/A * change, and their ordering could be considered dumb luck.
2N/A */
2N/A
2N/A if (bestm &&
2N/A ((m->plug->security_flags ^ bestm->plug->security_flags) &
2N/A bestm->plug->security_flags)) {
2N/A break;
2N/A }
2N/A
2N/A if (mech) {
2N/A *mech = m->plug->mech_name;
2N/A }
2N/A /* EXPORT DELETE START */
2N/A /* CRYPT DELETE START */
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A bestssf = m->sun_reg ? m->plug->max_ssf : 0;
2N/A#else
2N/A /* CRYPT DELETE END */
2N/A /* EXPORT DELETE END */
2N/A bestssf = m->plug->max_ssf;
2N/A /* EXPORT DELETE START */
2N/A /* CRYPT DELETE START */
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A /* CRYPT DELETE END */
2N/A /* EXPORT DELETE END */
2N/A bestm = m;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (bestm == NULL) {
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A sasl_seterror(conn, 0, gettext("No worthy mechs found"));
2N/A#else
2N/A sasl_seterror(conn, 0, "No worthy mechs found");
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A result = SASL_NOMECH;
2N/A goto done;
2N/A }
2N/A
2N/A /* make (the rest of) cparams */
2N/A c_conn->cparams->service = conn->service;
2N/A c_conn->cparams->servicelen = strlen(conn->service);
2N/A
2N/A c_conn->cparams->serverFQDN = conn->serverFQDN;
2N/A c_conn->cparams->slen = strlen(conn->serverFQDN);
2N/A
2N/A c_conn->cparams->clientFQDN = c_conn->clientFQDN;
2N/A c_conn->cparams->clen = strlen(c_conn->clientFQDN);
2N/A
2N/A c_conn->cparams->external_ssf = conn->external.ssf;
2N/A c_conn->cparams->props = conn->props;
2N/A /* EXPORT DELETE START */
2N/A /* CRYPT DELETE START */
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A if (!bestm->sun_reg) {
2N/A c_conn->cparams->props.min_ssf = 0;
2N/A c_conn->cparams->props.max_ssf = 0;
2N/A }
2N/A c_conn->base.sun_reg = bestm->sun_reg;
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A /* CRYPT DELETE END */
2N/A /* EXPORT DELETE END */
2N/A c_conn->mech = bestm;
2N/A
2N/A /* init that plugin */
2N/A#ifdef _SUN_SDK_
2N/A result = c_conn->mech->plug->mech_new(c_conn->mech->glob_context,
2N/A#else
2N/A result = c_conn->mech->plug->mech_new(c_conn->mech->plug->glob_context,
2N/A#endif /* _SUN_SDK_ */
2N/A c_conn->cparams,
2N/A &(conn->context));
2N/A if(result != SASL_OK) goto done;
2N/A
2N/A /* do a step -- but only if we can do a client-send-first */
2N/A dostep:
2N/A if(clientout) {
2N/A if(c_conn->mech->plug->features & SASL_FEAT_SERVER_FIRST) {
2N/A *clientout = NULL;
2N/A *clientoutlen = 0;
2N/A result = SASL_CONTINUE;
2N/A } else {
2N/A result = sasl_client_step(conn, NULL, 0, prompt_need,
2N/A clientout, clientoutlen);
2N/A }
2N/A }
2N/A else
2N/A result = SASL_CONTINUE;
2N/A
2N/A done:
2N/A RETURN(conn, result);
2N/A}
2N/A
2N/A/* do a single authentication step.
2N/A * serverin -- the server message received by the client, MUST have a NUL
2N/A * sentinel, not counted by serverinlen
2N/A * output:
2N/A * prompt_need -- on SASL_INTERACT, list of prompts needed to continue
2N/A * clientout -- the client response to send to the server
2N/A *
2N/A * returns:
2N/A * SASL_OK -- success
2N/A * SASL_INTERACT -- user interaction needed to fill in prompt_need list
2N/A * SASL_BADPROT -- server protocol incorrect/cancelled
2N/A * SASL_BADSERV -- server failed mutual auth
2N/A */
2N/A
2N/Aint sasl_client_step(sasl_conn_t *conn,
2N/A const char *serverin,
2N/A unsigned serverinlen,
2N/A sasl_interact_t **prompt_need,
2N/A const char **clientout,
2N/A unsigned *clientoutlen)
2N/A{
2N/A sasl_client_conn_t *c_conn= (sasl_client_conn_t *) conn;
2N/A int result;
2N/A
2N/A#ifdef _SUN_SDK_
2N/A _sasl_global_context_t *gctx = (conn == NULL) ?
2N/A _sasl_gbl_ctx() : conn->gctx;
2N/A
2N/A if(gctx->sasl_client_active==0) return SASL_NOTINIT;
2N/A#else
2N/A if(_sasl_client_active==0) return SASL_NOTINIT;
2N/A#endif /* _SUN_SDK_ */
2N/A if(!conn) return SASL_BADPARAM;
2N/A
2N/A /* check parameters */
2N/A if ((serverin==NULL) && (serverinlen>0))
2N/A PARAMERROR(conn);
2N/A
2N/A /* Don't do another step if the plugin told us that we're done */
2N/A if (conn->oparams.doneflag) {
2N/A _sasl_log(conn, SASL_LOG_ERR, "attempting client step after doneflag");
2N/A return SASL_FAIL;
2N/A }
2N/A
2N/A if(clientout) *clientout = NULL;
2N/A if(clientoutlen) *clientoutlen = 0;
2N/A
2N/A /* do a step */
2N/A result = c_conn->mech->plug->mech_step(conn->context,
2N/A c_conn->cparams,
2N/A serverin,
2N/A serverinlen,
2N/A prompt_need,
2N/A clientout, clientoutlen,
2N/A &conn->oparams);
2N/A
2N/A if (result == SASL_OK) {
2N/A /* So we're done on this end, but if both
2N/A * 1. the mech does server-send-last
2N/A * 2. the protocol does not
2N/A * we need to return no data */
2N/A if(!*clientout && !(conn->flags & SASL_SUCCESS_DATA)) {
2N/A *clientout = "";
2N/A *clientoutlen = 0;
2N/A }
2N/A
2N/A if(!conn->oparams.maxoutbuf) {
2N/A conn->oparams.maxoutbuf = conn->props.maxbufsize;
2N/A }
2N/A
2N/A if(conn->oparams.user == NULL || conn->oparams.authid == NULL) {
2N/A#ifdef _SUN_SDK_
2N/A _sasl_log(conn, SASL_LOG_ERR,
2N/A "mech did not call canon_user for both authzid and authid");
2N/A#else
2N/A sasl_seterror(conn, 0,
2N/A "mech did not call canon_user for both authzid and authid");
2N/A#endif /* _SUN_SDK_ */
2N/A result = SASL_BADPROT;
2N/A }
2N/A }
2N/A
2N/A RETURN(conn,result);
2N/A}
2N/A
2N/A/* returns the length of all the mechanisms
2N/A * added up
2N/A */
2N/A
2N/A#ifdef _SUN_SDK_
2N/Astatic unsigned mech_names_len(_sasl_global_context_t *gctx)
2N/A{
2N/A cmech_list_t *cmechlist = gctx->cmechlist;
2N/A#else
2N/Astatic unsigned mech_names_len()
2N/A{
2N/A#endif /* _SUN_SDK_ */
2N/A cmechanism_t *listptr;
2N/A unsigned result = 0;
2N/A
2N/A for (listptr = cmechlist->mech_list;
2N/A listptr;
2N/A listptr = listptr->next)
2N/A result += strlen(listptr->plug->mech_name);
2N/A
2N/A return result;
2N/A}
2N/A
2N/A
2N/Aint _sasl_client_listmech(sasl_conn_t *conn,
2N/A const char *prefix,
2N/A const char *sep,
2N/A const char *suffix,
2N/A const char **result,
2N/A unsigned *plen,
2N/A int *pcount)
2N/A{
2N/A cmechanism_t *m=NULL;
2N/A sasl_ssf_t minssf = 0;
2N/A int ret;
2N/A unsigned int resultlen;
2N/A int flag;
2N/A const char *mysep;
2N/A#ifdef _SUN_SDK_
2N/A _sasl_global_context_t *gctx = conn == NULL ? _sasl_gbl_ctx() : conn->gctx;
2N/A cmech_list_t *cmechlist;
2N/A
2N/A if(gctx->sasl_client_active==0) return SASL_NOTINIT;
2N/A cmechlist = gctx->cmechlist;
2N/A#else
2N/A if(_sasl_client_active == 0) return SASL_NOTINIT;
2N/A#endif /* _SUN_SDK_ */
2N/A if (!conn) return SASL_BADPARAM;
2N/A if(conn->type != SASL_CONN_CLIENT) PARAMERROR(conn);
2N/A
2N/A if (! result)
2N/A PARAMERROR(conn);
2N/A
2N/A#ifdef _SUN_SDK_
2N/A (void) _load_client_plugins(gctx);
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A if (plen != NULL)
2N/A *plen = 0;
2N/A if (pcount != NULL)
2N/A *pcount = 0;
2N/A
2N/A if (sep) {
2N/A mysep = sep;
2N/A } else {
2N/A mysep = " ";
2N/A }
2N/A
2N/A if(conn->props.min_ssf < conn->external.ssf) {
2N/A minssf = 0;
2N/A } else {
2N/A minssf = conn->props.min_ssf - conn->external.ssf;
2N/A }
2N/A
2N/A if (! cmechlist || cmechlist->mech_length <= 0)
2N/A INTERROR(conn, SASL_NOMECH);
2N/A
2N/A resultlen = (prefix ? strlen(prefix) : 0)
2N/A + (strlen(mysep) * (cmechlist->mech_length - 1))
2N/A#ifdef _SUN_SDK_
2N/A + mech_names_len(gctx)
2N/A#else
2N/A + mech_names_len()
2N/A#endif /* _SUN_SDK_ */
2N/A + (suffix ? strlen(suffix) : 0)
2N/A + 1;
2N/A ret = _buf_alloc(&conn->mechlist_buf,
2N/A &conn->mechlist_buf_len, resultlen);
2N/A if(ret != SASL_OK) MEMERROR(conn);
2N/A
2N/A if (prefix)
2N/A strcpy (conn->mechlist_buf,prefix);
2N/A else
2N/A *(conn->mechlist_buf) = '\0';
2N/A
2N/A flag = 0;
2N/A for (m = cmechlist->mech_list; m != NULL; m = m->next) {
2N/A /* do we have the prompts for it? */
2N/A if (!have_prompts(conn, m->plug))
2N/A continue;
2N/A
2N/A /* is it strong enough? */
2N/A if (minssf > m->plug->max_ssf)
2N/A continue;
2N/A
2N/A /* EXPORT DELETE START */
2N/A /* CRYPT DELETE START */
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A /* If not SUN supplied mech, it has no strength */
2N/A if (minssf > 0 && !m->sun_reg)
2N/A continue;
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A /* CRYPT DELETE END */
2N/A /* EXPORT DELETE END */
2N/A
2N/A /* does it meet our security properties? */
2N/A if (((conn->props.security_flags ^ m->plug->security_flags)
2N/A & conn->props.security_flags) != 0) {
2N/A continue;
2N/A }
2N/A
2N/A /* Can we meet it's features? */
2N/A if ((m->plug->features & SASL_FEAT_NEEDSERVERFQDN)
2N/A && !conn->serverFQDN) {
2N/A continue;
2N/A }
2N/A
2N/A /* Can it meet our features? */
2N/A if ((conn->flags & SASL_NEED_PROXY) &&
2N/A !(m->plug->features & SASL_FEAT_ALLOWS_PROXY)) {
2N/A break;
2N/A }
2N/A
2N/A /* Okay, we like it, add it to the list! */
2N/A
2N/A if (pcount != NULL)
2N/A (*pcount)++;
2N/A
2N/A /* print separator */
2N/A if (flag) {
2N/A strcat(conn->mechlist_buf, mysep);
2N/A } else {
2N/A flag = 1;
2N/A }
2N/A
2N/A /* now print the mechanism name */
2N/A strcat(conn->mechlist_buf, m->plug->mech_name);
2N/A }
2N/A
2N/A if (suffix)
2N/A strcat(conn->mechlist_buf,suffix);
2N/A
2N/A if (plen!=NULL)
2N/A *plen=strlen(conn->mechlist_buf);
2N/A
2N/A *result = conn->mechlist_buf;
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/A#ifdef _SUN_SDK_
2N/Asasl_string_list_t *_sasl_client_mechs(_sasl_global_context_t *gctx)
2N/A{
2N/A cmech_list_t *cmechlist = gctx->cmechlist;
2N/A#else
2N/Asasl_string_list_t *_sasl_client_mechs(void)
2N/A{
2N/A#endif /* _SUN_SDK_ */
2N/A cmechanism_t *listptr;
2N/A sasl_string_list_t *retval = NULL, *next=NULL;
2N/A
2N/A#ifdef _SUN_SDK_
2N/A if(!gctx->sasl_client_active) return NULL;
2N/A#else
2N/A if(!_sasl_client_active) return NULL;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A /* make list */
2N/A for (listptr = cmechlist->mech_list; listptr; listptr = listptr->next) {
2N/A next = sasl_ALLOC(sizeof(sasl_string_list_t));
2N/A
2N/A if(!next && !retval) return NULL;
2N/A else if(!next) {
2N/A next = retval->next;
2N/A do {
2N/A sasl_FREE(retval);
2N/A retval = next;
2N/A next = retval->next;
2N/A } while(next);
2N/A return NULL;
2N/A }
2N/A
2N/A next->d = listptr->plug->mech_name;
2N/A
2N/A if(!retval) {
2N/A next->next = NULL;
2N/A retval = next;
2N/A } else {
2N/A next->next = retval;
2N/A retval = next;
2N/A }
2N/A }
2N/A
2N/A return retval;
2N/A}