[Pkg-cyrus-sasl2-commits] r29 - in
/cyrus-sasl-2.1/trunk/debian/patches:
0008_one_time_sasl_set_alloc.dpatch 00list
fabbe at users.alioth.debian.org
fabbe at users.alioth.debian.org
Fri Oct 20 06:56:40 UTC 2006
Author: fabbe
Date: Mon Jul 31 15:54:50 2006
New Revision: 29
URL: http://svn.debian.org/wsvn/pkg-cyrus-sasl2/?sc=1&rev=29
Log:
Patch: make sasl_set_alloc a one-time function.
Added:
cyrus-sasl-2.1/trunk/debian/patches/0008_one_time_sasl_set_alloc.dpatch (with props)
Modified:
cyrus-sasl-2.1/trunk/debian/patches/00list
Added: cyrus-sasl-2.1/trunk/debian/patches/0008_one_time_sasl_set_alloc.dpatch
URL: http://svn.debian.org/wsvn/pkg-cyrus-sasl2/cyrus-sasl-2.1/trunk/debian/patches/0008_one_time_sasl_set_alloc.dpatch?rev=29&op=file
==============================================================================
--- cyrus-sasl-2.1/trunk/debian/patches/0008_one_time_sasl_set_alloc.dpatch (added)
+++ cyrus-sasl-2.1/trunk/debian/patches/0008_one_time_sasl_set_alloc.dpatch Mon Jul 31 15:54:50 2006
@@ -1,0 +1,2206 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 0008_one_time_sasl_set_alloc.dpatch by <fabbe at debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Make sasl_set_alloc a one-time function.
+## DP: This patch will divert all allocations to whomever called
+## DP: sasl_set_alloc first, hopefully that will be the application. If
+## DP: not, we sure *hope* the library doing stupid things has sane
+## DP: sasl_set_alloc semantics...
+## DP: It will also deny any futher tries to sasl_set_alloc after one
+## DP: of the _init functions are called.
+## DP: This patch was introduced and works fine in SASL 1.5, and no
+## DP: applications started behaving in insane ways, so chances are it
+## DP: will also work with SASL 2.1
+## DP: Reference: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=139568
+## DP: Reference: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=274087
+## DP: Reference: https://bugzilla.andrew.cmu.edu/show_bug.cgi?id=2525
+
+
+ at DPATCH@
+diff -urNad trunk~/lib/client.c trunk/lib/client.c
+--- trunk~/lib/client.c 2006-05-29 22:52:46.000000000 +0300
++++ trunk/lib/client.c 2006-07-31 18:48:58.000000000 +0300
+@@ -202,6 +202,9 @@
+ { NULL, NULL }
+ };
+
++ /* lock allocation type */
++ _sasl_allocation_locked++;
++
+ if(_sasl_client_active) {
+ /* We're already active, just increase our refcount */
+ /* xxx do something with the callback structure? */
+diff -urNad trunk~/lib/common.c trunk/lib/common.c
+--- trunk~/lib/common.c 2006-05-29 22:52:46.000000000 +0300
++++ trunk/lib/common.c 2006-07-31 18:48:58.000000000 +0300
+@@ -107,6 +107,7 @@
+ (sasl_realloc_t *) &realloc,
+ (sasl_free_t *) &free
+ };
++int _sasl_allocation_locked = 0;
+
+ #define SASL_ENCODEV_EXTRA 4096
+
+@@ -637,6 +638,8 @@
+ sasl_realloc_t *r,
+ sasl_free_t *f)
+ {
++ if (_sasl_allocation_locked++) return;
++
+ _sasl_allocation_utils.malloc=m;
+ _sasl_allocation_utils.calloc=c;
+ _sasl_allocation_utils.realloc=r;
+diff -urNad trunk~/lib/saslint.h trunk/lib/saslint.h
+--- trunk~/lib/saslint.h 2006-05-29 22:52:46.000000000 +0300
++++ trunk/lib/saslint.h 2006-07-31 18:48:58.000000000 +0300
+@@ -300,6 +300,7 @@
+
+ extern sasl_allocation_utils_t _sasl_allocation_utils;
+ extern sasl_mutex_utils_t _sasl_mutex_utils;
++extern int _sasl_allocation_locked;
+
+ /*
+ * checkpw.c
+diff -urNad trunk~/lib/server.c trunk/lib/server.c
+--- trunk~/lib/server.c 2006-05-29 22:52:46.000000000 +0300
++++ trunk/lib/server.c 2006-07-31 18:48:58.000000000 +0300
+@@ -698,6 +698,9 @@
+ { NULL, NULL }
+ };
+
++ /* lock allocation type */
++ _sasl_allocation_locked++;
++
+ /* we require the appname (if present) to be short enough to be a path */
+ if (appname != NULL && strlen(appname) >= PATH_MAX)
+ return SASL_BADPARAM;
+diff -urNad trunk~/lib/server.c.orig trunk/lib/server.c.orig
+--- trunk~/lib/server.c.orig 1970-01-01 02:00:00.000000000 +0200
++++ trunk/lib/server.c.orig 2006-05-29 22:52:46.000000000 +0300
+@@ -0,0 +1,2125 @@
++/* SASL server API implementation
++ * Rob Siemborski
++ * Tim Martin
++ * $Id: server.c,v 1.146 2006/04/26 17:45:53 murch Exp $
++ */
++/*
++ * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ *
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ *
++ * 3. The name "Carnegie Mellon University" must not be used to
++ * endorse or promote products derived from this software without
++ * prior written permission. For permission or any other legal
++ * details, please contact
++ * Office of Technology Transfer
++ * Carnegie Mellon University
++ * 5000 Forbes Avenue
++ * Pittsburgh, PA 15213-3890
++ * (412) 268-4387, fax: (412) 268-7395
++ * tech-transfer at andrew.cmu.edu
++ *
++ * 4. Redistributions of any form whatsoever must retain the following
++ * acknowledgment:
++ * "This product includes software developed by Computing Services
++ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
++ *
++ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
++ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
++ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
++ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
++ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* local functions/structs don't start with sasl
++ */
++#include <config.h>
++#include <errno.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <limits.h>
++#ifndef macintosh
++#include <sys/types.h>
++#include <sys/stat.h>
++#endif
++#include <fcntl.h>
++#include <string.h>
++#include <ctype.h>
++
++#include "sasl.h"
++#include "saslint.h"
++#include "saslplug.h"
++#include "saslutil.h"
++
++#ifdef sun
++/* gotta define gethostname ourselves on suns */
++extern int gethostname(char *, int);
++#endif
++
++#define DEFAULT_CHECKPASS_MECH "auxprop"
++
++/* Contains functions:
++ *
++ * sasl_server_init
++ * sasl_server_new
++ * sasl_listmech
++ * sasl_server_start
++ * sasl_server_step
++ * sasl_checkpass
++ * sasl_checkapop
++ * sasl_user_exists
++ * sasl_setpass
++ */
++
++/* if we've initialized the server sucessfully */
++static int _sasl_server_active = 0;
++
++/* For access by other modules */
++int _is_sasl_server_active(void) { return _sasl_server_active; }
++
++static int _sasl_checkpass(sasl_conn_t *conn,
++ const char *user, unsigned userlen,
++ const char *pass, unsigned passlen);
++
++static mech_list_t *mechlist = NULL; /* global var which holds the list */
++
++sasl_global_callbacks_t global_callbacks;
++
++/* set the password for a user
++ * conn -- SASL connection
++ * user -- user name
++ * pass -- plaintext password, may be NULL to remove user
++ * passlen -- length of password, 0 = strlen(pass)
++ * oldpass -- NULL will sometimes work
++ * oldpasslen -- length of password, 0 = strlen(oldpass)
++ * flags -- see flags below
++ *
++ * returns:
++ * SASL_NOCHANGE -- proper entry already exists
++ * SASL_NOMECH -- no authdb supports password setting as configured
++ * SASL_NOVERIFY -- user exists, but no settable password present
++ * SASL_DISABLED -- account disabled
++ * SASL_PWLOCK -- password locked
++ * SASL_WEAKPASS -- password too weak for security policy
++ * SASL_NOUSERPASS -- user-supplied passwords not permitted
++ * SASL_FAIL -- OS error
++ * SASL_BADPARAM -- password too long
++ * SASL_OK -- successful
++ */
++
++int sasl_setpass(sasl_conn_t *conn,
++ const char *user,
++ const char *pass, unsigned passlen,
++ const char *oldpass,
++ unsigned oldpasslen,
++ unsigned flags)
++{
++ int result = SASL_OK, tmpresult;
++ sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
++ const char *password_request[] = { SASL_AUX_PASSWORD_PROP, NULL };
++ sasl_server_userdb_setpass_t *setpass_cb = NULL;
++ void *context = NULL;
++ int tried_setpass = 0;
++ mechanism_t *sm;
++ server_sasl_mechanism_t *m;
++ char *current_mech;
++
++ if (!_sasl_server_active || !mechlist) return SASL_NOTINIT;
++
++ /* check params */
++ if (!conn) return SASL_BADPARAM;
++ if (conn->type != SASL_CONN_SERVER) PARAMERROR(conn);
++
++ if ((!(flags & SASL_SET_DISABLE) && passlen == 0)
++ || ((flags & SASL_SET_CREATE) && (flags & SASL_SET_DISABLE)))
++ PARAMERROR(conn);
++
++ /* Check that we have an active SASL mechanism */
++ if (sasl_getprop (conn,
++ SASL_MECHNAME,
++ (const void **) ¤t_mech) != SASL_OK) {
++ current_mech = NULL;
++ }
++
++ if ( (flags & SASL_SET_CURMECH_ONLY) &&
++ (current_mech == NULL) ) {
++ sasl_seterror( conn, SASL_NOLOG,
++ "No current SASL mechanism available");
++ RETURN(conn, SASL_BADPARAM);
++ }
++
++ /* Do we want to store SASL_AUX_PASSWORD_PROP (plain text)? and
++ * Do we have an auxprop backend that can store properties?
++ */
++ if ((flags & SASL_SET_DISABLE || !(flags & SASL_SET_NOPLAIN)) &&
++ sasl_auxprop_store(NULL, NULL, NULL) == SASL_OK) {
++
++ tried_setpass++;
++
++ if (flags & SASL_SET_DISABLE) {
++ pass = NULL;
++ passlen = 0;
++ }
++
++ result = prop_request(s_conn->sparams->propctx, password_request);
++ if (result == SASL_OK) {
++ result = prop_set(s_conn->sparams->propctx, SASL_AUX_PASSWORD_PROP,
++ pass, passlen);
++ }
++ if (result == SASL_OK) {
++ result = sasl_auxprop_store(conn, s_conn->sparams->propctx, user);
++ }
++ if (result != SASL_OK) {
++ _sasl_log(conn, SASL_LOG_ERR,
++ "setpass failed for %s: %z",
++ user, result);
++ } else {
++ _sasl_log(conn, SASL_LOG_NOTE,
++ "setpass succeeded for %s", user);
++ }
++ }
++
++ /* We want to preserve the current value of result, so we use tmpresult below */
++
++ /* call userdb callback function */
++ tmpresult = _sasl_getcallback(conn, SASL_CB_SERVER_USERDB_SETPASS,
++ &setpass_cb, &context);
++ if (tmpresult == SASL_OK && setpass_cb) {
++
++ tried_setpass++;
++
++ tmpresult = setpass_cb(conn, context, user, pass, passlen,
++ s_conn->sparams->propctx, flags);
++ if(tmpresult != SASL_OK) {
++ result = tmpresult;
++ _sasl_log(conn, SASL_LOG_ERR,
++ "setpass callback failed for %s: %z",
++ user, tmpresult);
++ } else {
++ _sasl_log(conn, SASL_LOG_NOTE,
++ "setpass callback succeeded for %s", user);
++ }
++ }
++
++ /* now we let the mechanisms set their secrets */
++ for (sm = mechlist->mech_list; sm; sm = sm->next) {
++ m = &sm->m;
++
++ if (!m->plug->setpass) {
++ /* can't set pass for this mech */
++ continue;
++ }
++
++ /* Invoke only one setpass for the currently selected mechanism,
++ if SASL_SET_CURMECH_ONLY is specified */
++ if ((flags & SASL_SET_CURMECH_ONLY) &&
++ (strcmp(current_mech, m->plug->mech_name) != 0)) {
++ continue;
++ }
++
++ tried_setpass++;
++
++ tmpresult = m->plug->setpass(m->plug->glob_context,
++ ((sasl_server_conn_t *)conn)->sparams,
++ user,
++ pass,
++ passlen,
++ oldpass, oldpasslen,
++ flags);
++ if (tmpresult == SASL_OK) {
++ _sasl_log(conn, SASL_LOG_NOTE,
++ "%s: set secret for %s", m->plug->mech_name, user);
++
++ m->condition = SASL_OK; /* if we previously thought the
++ mechanism didn't have any user secrets
++ we now think it does */
++
++ } else if (tmpresult == SASL_NOCHANGE) {
++ _sasl_log(conn, SASL_LOG_NOTE,
++ "%s: secret not changed for %s", m->plug->mech_name, user);
++ } else {
++ result = tmpresult;
++ _sasl_log(conn, SASL_LOG_ERR,
++ "%s: failed to set secret for %s: %z (%m)",
++ m->plug->mech_name, user, tmpresult,
++#ifndef WIN32
++ errno
++#else
++ GetLastError()
++#endif
++ );
++ }
++ }
++
++ if (!tried_setpass) {
++ _sasl_log(conn, SASL_LOG_WARN,
++ "secret not changed for %s: "
++ "no writable auxprop plugin or setpass callback found",
++ user);
++ }
++
++ RETURN(conn, result);
++}
++
++/* local mechanism which disposes of server */
++static void server_dispose(sasl_conn_t *pconn)
++{
++ sasl_server_conn_t *s_conn= (sasl_server_conn_t *) pconn;
++ context_list_t *cur, *cur_next;
++
++ if (s_conn->mech
++ && s_conn->mech->m.plug->mech_dispose) {
++ s_conn->mech->m.plug->mech_dispose(pconn->context,
++ s_conn->sparams->utils);
++ }
++ pconn->context = NULL;
++
++ for(cur = s_conn->mech_contexts; cur; cur=cur_next) {
++ cur_next = cur->next;
++ if(cur->context)
++ cur->mech->m.plug->mech_dispose(cur->context, s_conn->sparams->utils);
++ sasl_FREE(cur);
++ }
++ s_conn->mech_contexts = NULL;
++
++ _sasl_free_utils(&s_conn->sparams->utils);
++
++ if (s_conn->sparams->propctx)
++ prop_dispose(&s_conn->sparams->propctx);
++
++ if (s_conn->appname)
++ sasl_FREE(s_conn->appname);
++
++ if (s_conn->user_realm)
++ sasl_FREE(s_conn->user_realm);
++
++ if (s_conn->sparams)
++ sasl_FREE(s_conn->sparams);
++
++ _sasl_conn_dispose(pconn);
++}
++
++static int init_mechlist(void)
++{
++ sasl_utils_t *newutils = NULL;
++
++ mechlist->mutex = sasl_MUTEX_ALLOC();
++ if(!mechlist->mutex) return SASL_FAIL;
++
++ /* set util functions - need to do rest */
++ newutils = _sasl_alloc_utils(NULL, &global_callbacks);
++ if (newutils == NULL)
++ return SASL_NOMEM;
++
++ newutils->checkpass = &_sasl_checkpass;
++
++ mechlist->utils = newutils;
++ mechlist->mech_list=NULL;
++ mechlist->mech_length=0;
++
++ return SASL_OK;
++}
++
++/*
++ * parameters:
++ * p - entry point
++ */
++int sasl_server_add_plugin(const char *plugname,
++ sasl_server_plug_init_t *p)
++{
++ int plugcount;
++ sasl_server_plug_t *pluglist;
++ mechanism_t *mech;
++ sasl_server_plug_init_t *entry_point;
++ int result;
++ int version;
++ int lupe;
++
++ if(!plugname || !p) return SASL_BADPARAM;
++
++ entry_point = (sasl_server_plug_init_t *)p;
++
++ /* call into the shared library asking for information about it */
++ /* version is filled in with the version of the plugin */
++ result = entry_point(mechlist->utils, SASL_SERVER_PLUG_VERSION, &version,
++ &pluglist, &plugcount);
++
++ if ((result != SASL_OK) && (result != SASL_NOUSER)
++ && (result != SASL_CONTINUE)) {
++ _sasl_log(NULL, SASL_LOG_DEBUG,
++ "server add_plugin entry_point error %z\n", result);
++ return result;
++ }
++
++ /* Make sure plugin is using the same SASL version as us */
++ if (version != SASL_SERVER_PLUG_VERSION)
++ {
++ _sasl_log(NULL, SASL_LOG_ERR,
++ "version mismatch on plugin");
++ return SASL_BADVERS;
++ }
++
++ for (lupe=0;lupe < plugcount ;lupe++)
++ {
++ mech = sasl_ALLOC(sizeof(mechanism_t));
++ if (! mech) return SASL_NOMEM;
++ memset (mech, 0, sizeof(mechanism_t));
++
++ mech->m.plug = pluglist++;
++ if(_sasl_strdup(plugname, &mech->m.plugname, NULL) != SASL_OK) {
++ sasl_FREE(mech);
++ return SASL_NOMEM;
++ }
++ mech->m.version = version;
++
++ /* wheather this mech actually has any users in it's db */
++ mech->m.condition = result; /* SASL_OK, SASL_CONTINUE or SASL_NOUSER */
++
++ /* mech->m.f = NULL; */
++
++ mech->next = mechlist->mech_list;
++ mechlist->mech_list = mech;
++ mechlist->mech_length++;
++ }
++
++ return SASL_OK;
++}
++
++static int server_done(void) {
++ mechanism_t *m;
++ mechanism_t *prevm;
++
++ if(_sasl_server_active == 0)
++ return SASL_NOTINIT;
++ else
++ _sasl_server_active--;
++
++ if(_sasl_server_active) {
++ /* Don't de-init yet! Our refcount is nonzero. */
++ return SASL_CONTINUE;
++ }
++
++ if (mechlist != NULL)
++ {
++ m=mechlist->mech_list; /* m point to beginning of the list */
++
++ while (m!=NULL)
++ {
++ prevm=m;
++ m=m->next;
++
++ if (prevm->m.plug->mech_free) {
++ prevm->m.plug->mech_free(prevm->m.plug->glob_context,
++ mechlist->utils);
++ }
++
++ sasl_FREE(prevm->m.plugname);
++ sasl_FREE(prevm);
++ }
++ _sasl_free_utils(&mechlist->utils);
++ sasl_MUTEX_FREE(mechlist->mutex);
++ sasl_FREE(mechlist);
++ mechlist = NULL;
++ }
++
++ /* Free the auxprop plugins */
++ _sasl_auxprop_free();
++
++ global_callbacks.callbacks = NULL;
++ global_callbacks.appname = NULL;
++
++ return SASL_OK;
++}
++
++static int server_idle(sasl_conn_t *conn)
++{
++ mechanism_t *m;
++ if (! mechlist)
++ return 0;
++
++ for (m = mechlist->mech_list;
++ m != NULL;
++ m = m->next)
++ if (m->m.plug->idle
++ && m->m.plug->idle(m->m.plug->glob_context,
++ conn,
++ conn ? ((sasl_server_conn_t *)conn)->sparams : NULL))
++ return 1;
++
++ return 0;
++}
++
++static int load_config(const sasl_callback_t *verifyfile_cb)
++{
++ int result;
++ const char *path_to_config = NULL;
++ size_t path_len;
++ char *config_filename = NULL;
++ size_t len;
++ const sasl_callback_t *getconfpath_cb = NULL;
++ const char * next;
++
++ /* If appname was not provided, behave as if there is no config file
++ (see also sasl_config_init() */
++ if (global_callbacks.appname == NULL) {
++ return SASL_CONTINUE;
++ }
++
++ /* get the path to the config file */
++ getconfpath_cb = _sasl_find_getconfpath_callback( global_callbacks.callbacks );
++ if (getconfpath_cb == NULL) return SASL_BADPARAM;
++
++ /* getconfpath_cb->proc MUST be a sasl_getconfpath_t; if only C had a type
++ system */
++ result = ((sasl_getconfpath_t *)(getconfpath_cb->proc))(getconfpath_cb->context,
++ &path_to_config);
++ if (result != SASL_OK) goto done;
++ if (path_to_config == NULL) path_to_config = "";
++
++ next = path_to_config;
++
++ while (next != NULL) {
++ next = strchr(path_to_config, PATHS_DELIMITER);
++
++ /* length = length of path + '/' + length of appname + ".conf" + 1
++ for '\0' */
++
++ if (next != NULL) {
++ path_len = next - path_to_config;
++ next++; /* Skip to the next path */
++ } else {
++ path_len = strlen(path_to_config);
++ }
++
++ len = path_len + 2 + strlen(global_callbacks.appname) + 5 + 1;
++
++ if (len > PATH_MAX ) {
++ result = SASL_FAIL;
++ goto done;
++ }
++
++ /* construct the filename for the config file */
++ config_filename = sasl_ALLOC((unsigned)len);
++ if (! config_filename) {
++ result = SASL_NOMEM;
++ goto done;
++ }
++
++ snprintf(config_filename, len, "%.*s%c%s.conf", path_len, path_to_config,
++ HIER_DELIMITER, global_callbacks.appname);
++
++ /* Ask the application if it's safe to use this file */
++ result = ((sasl_verifyfile_t *)(verifyfile_cb->proc))(verifyfile_cb->context,
++ config_filename, SASL_VRFY_CONF);
++
++ /* returns SASL_CONTINUE if the config file doesn't exist */
++ if (result == SASL_OK) {
++ result = sasl_config_init(config_filename);
++
++ if (result != SASL_CONTINUE) {
++ /* We are done */
++ break;
++ }
++ }
++
++ if (config_filename) {
++ sasl_FREE(config_filename);
++ config_filename = NULL;
++ }
++
++ path_to_config = next;
++ }
++
++ done:
++ if (config_filename) sasl_FREE(config_filename);
++
++ return result;
++}
++
++/*
++ * Verify that all the callbacks are valid
++ */
++static int verify_server_callbacks(const sasl_callback_t *callbacks)
++{
++ if (callbacks == NULL) return SASL_OK;
++
++ while (callbacks->id != SASL_CB_LIST_END) {
++ if (callbacks->proc==NULL) return SASL_FAIL;
++
++ callbacks++;
++ }
++
++ return SASL_OK;
++}
++
++static char *grab_field(char *line, char **eofield)
++{
++ int d = 0;
++ char *field;
++
++ while (isspace((int) *line)) line++;
++
++ /* find end of field */
++ while (line[d] && !isspace(((int) line[d]))) d++;
++ field = sasl_ALLOC(d + 1);
++ if (!field) { return NULL; }
++ memcpy(field, line, d);
++ field[d] = '\0';
++ *eofield = line + d;
++
++ return field;
++}
++
++struct secflag_map_s {
++ char *name;
++ int value;
++};
++
++struct secflag_map_s secflag_map[] = {
++ { "noplaintext", SASL_SEC_NOPLAINTEXT },
++ { "noactive", SASL_SEC_NOACTIVE },
++ { "nodictionary", SASL_SEC_NODICTIONARY },
++ { "forward_secrecy", SASL_SEC_FORWARD_SECRECY },
++ { "noanonymous", SASL_SEC_NOANONYMOUS },
++ { "pass_credentials", SASL_SEC_PASS_CREDENTIALS },
++ { "mutual_auth", SASL_SEC_MUTUAL_AUTH },
++ { NULL, 0x0 }
++};
++
++static int parse_mechlist_file(const char *mechlistfile)
++{
++ FILE *f;
++ char buf[1024];
++ char *t, *ptr;
++ int r = 0;
++
++ f = fopen(mechlistfile, "r");
++ if (!f) return SASL_FAIL;
++
++ r = SASL_OK;
++ while (fgets(buf, sizeof(buf), f) != NULL) {
++ mechanism_t *n = sasl_ALLOC(sizeof(mechanism_t));
++ sasl_server_plug_t *nplug;
++
++ if (n == NULL) { r = SASL_NOMEM; break; }
++ n->m.version = SASL_SERVER_PLUG_VERSION;
++ n->m.condition = SASL_CONTINUE;
++ nplug = sasl_ALLOC(sizeof(sasl_server_plug_t));
++ if (nplug == NULL) { r = SASL_NOMEM; break; }
++ memset(nplug, 0, sizeof(sasl_server_plug_t));
++
++ /* each line is:
++ plugin-file WS mech_name WS max_ssf *(WS security_flag) RET
++ */
++
++ /* grab file */
++ n->m.f = grab_field(buf, &ptr);
++
++ /* grab mech_name */
++ nplug->mech_name = grab_field(ptr, &ptr);
++
++ /* grab max_ssf */
++ nplug->max_ssf = strtol(ptr, &ptr, 10);
++
++ /* grab security flags */
++ while (*ptr != '\n') {
++ struct secflag_map_s *map;
++
++ /* read security flag */
++ t = grab_field(ptr, &ptr);
++ map = secflag_map;
++ while (map->name) {
++ if (!strcasecmp(t, map->name)) {
++ nplug->security_flags |= map->value;
++ break;
++ }
++ map++;
++ }
++ if (!map->name) {
++ _sasl_log(NULL, SASL_LOG_ERR,
++ "%s: couldn't identify flag '%s'",
++ nplug->mech_name, t);
++ }
++ free(t);
++ }
++
++ /* insert mechanism into mechlist */
++ n->m.plug = nplug;
++ n->next = mechlist->mech_list;
++ mechlist->mech_list = n;
++ mechlist->mech_length++;
++ }
++
++ fclose(f);
++ return r;
++}
++
++/* initialize server drivers, done once per process
++ * callbacks -- callbacks for all server connections; must include
++ * getopt callback
++ * appname -- name of calling application
++ * (for lower level logging and reading of the configuration file)
++ * results:
++ * state -- server state
++ * returns:
++ * SASL_OK -- success
++ * SASL_BADPARAM -- error in config file
++ * SASL_NOMEM -- memory failure
++ * SASL_BADVERS -- Mechanism version mismatch
++ */
++
++int sasl_server_init(const sasl_callback_t *callbacks,
++ const char *appname)
++{
++ int ret;
++ const sasl_callback_t *vf;
++ const char *pluginfile = NULL;
++#ifdef PIC
++ sasl_getopt_t *getopt;
++ void *context;
++#endif
++
++ const add_plugin_list_t ep_list[] = {
++ { "sasl_server_plug_init", (add_plugin_t *)sasl_server_add_plugin },
++ { "sasl_auxprop_plug_init", (add_plugin_t *)sasl_auxprop_add_plugin },
++ { "sasl_canonuser_init", (add_plugin_t *)sasl_canonuser_add_plugin },
++ { NULL, NULL }
++ };
++
++ /* we require the appname (if present) to be short enough to be a path */
++ if (appname != NULL && strlen(appname) >= PATH_MAX)
++ return SASL_BADPARAM;
++
++ if (_sasl_server_active) {
++ /* We're already active, just increase our refcount */
++ /* xxx do something with the callback structure? */
++ _sasl_server_active++;
++ return SASL_OK;
++ }
++
++ ret = _sasl_common_init(&global_callbacks);
++ if (ret != SASL_OK)
++ return ret;
++
++ /* verify that the callbacks look ok */
++ ret = verify_server_callbacks(callbacks);
++ if (ret != SASL_OK)
++ return ret;
++
++ global_callbacks.callbacks = callbacks;
++
++ /* A shared library calling sasl_server_init will pass NULL as appname.
++ This should retain the original appname. */
++ if (appname != NULL) {
++ global_callbacks.appname = appname;
++ }
++
++ /* If we fail now, we have to call server_done */
++ _sasl_server_active = 1;
++
++ /* allocate mechlist and set it to empty */
++ mechlist = sasl_ALLOC(sizeof(mech_list_t));
++ if (mechlist == NULL) {
++ server_done();
++ return SASL_NOMEM;
++ }
++
++ ret = init_mechlist();
++ if (ret != SASL_OK) {
++ server_done();
++ return ret;
++ }
++
++ vf = _sasl_find_verifyfile_callback(callbacks);
++
++ /* load config file if applicable */
++ ret = load_config(vf);
++ if ((ret != SASL_OK) && (ret != SASL_CONTINUE)) {
++ server_done();
++ return ret;
++ }
++
++ /* load internal plugins */
++ sasl_server_add_plugin("EXTERNAL", &external_server_plug_init);
++
++#ifdef PIC
++ /* delayed loading of plugins? (DSO only, as it doesn't
++ * make much [any] sense to delay in the static library case) */
++ if (_sasl_getcallback(NULL, SASL_CB_GETOPT, &getopt, &context)
++ == SASL_OK) {
++ /* No sasl_conn_t was given to getcallback, so we provide the
++ * global callbacks structure */
++ ret = getopt(&global_callbacks, NULL, "plugin_list", &pluginfile, NULL);
++ }
++#endif
++
++ if (pluginfile != NULL) {
++ /* this file should contain a list of plugins available.
++ we'll load on demand. */
++
++ /* Ask the application if it's safe to use this file */
++ ret = ((sasl_verifyfile_t *)(vf->proc))(vf->context,
++ pluginfile,
++ SASL_VRFY_CONF);
++ if (ret != SASL_OK) {
++ _sasl_log(NULL, SASL_LOG_ERR,
++ "unable to load plugin list %s: %z", pluginfile, ret);
++ }
++
++ if (ret == SASL_OK) {
++ ret = parse_mechlist_file(pluginfile);
++ }
++ } else {
++ /* load all plugins now */
++ ret = _sasl_load_plugins(ep_list,
++ _sasl_find_getpath_callback(callbacks),
++ _sasl_find_verifyfile_callback(callbacks));
++ }
++
++ if (ret == SASL_OK) {
++ _sasl_server_cleanup_hook = &server_done;
++ _sasl_server_idle_hook = &server_idle;
++
++ ret = _sasl_build_mechlist();
++ } else {
++ server_done();
++ }
++
++ return ret;
++}
++
++/*
++ * Once we have the users plaintext password we
++ * may want to transition them. That is put entries
++ * for them in the passwd database for other
++ * stronger mechanism
++ *
++ * for example PLAIN -> CRAM-MD5
++ */
++static int
++_sasl_transition(sasl_conn_t * conn,
++ const char * pass,
++ unsigned passlen)
++{
++ const char *dotrans = "n";
++ sasl_getopt_t *getopt;
++ int result = SASL_OK;
++ void *context;
++ unsigned flags = 0;
++
++ if (! conn)
++ return SASL_BADPARAM;
++
++ if (! conn->oparams.authid)
++ PARAMERROR(conn);
++
++ /* check if this is enabled: default to false */
++ if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK)
++ {
++ getopt(context, NULL, "auto_transition", &dotrans, NULL);
++ if (dotrans == NULL) dotrans = "n";
++ }
++
++
++ if (!strcmp(dotrans, "noplain")) flags |= SASL_SET_NOPLAIN;
++
++ if (flags || *dotrans == '1' || *dotrans == 'y' ||
++ (*dotrans == 'o' && dotrans[1] == 'n') || *dotrans == 't') {
++ /* ok, it's on! */
++ _sasl_log(conn, SASL_LOG_NOTE,
++ "transitioning user %s to auxprop database",
++ conn->oparams.authid);
++ result = sasl_setpass(conn,
++ conn->oparams.authid,
++ pass,
++ passlen,
++ NULL, 0, SASL_SET_CREATE | flags);
++ }
++
++ RETURN(conn,result);
++}
++
++
++/* create context for a single SASL connection
++ * service -- registered name of the service using SASL (e.g. "imap")
++ * serverFQDN -- Fully qualified domain name of server. NULL means use
++ * gethostname() or equivalent.
++ * Useful for multi-homed servers.
++ * user_realm -- permits multiple user realms on server, NULL = default
++ * iplocalport -- server IPv4/IPv6 domain literal string with port
++ * (if NULL, then mechanisms requiring IPaddr are disabled)
++ * ipremoteport -- client IPv4/IPv6 domain literal string with port
++ * (if NULL, then mechanisms requiring IPaddr are disabled)
++ * callbacks -- callbacks (e.g., authorization, lang, new getopt context)
++ * flags -- usage flags (see above)
++ * returns:
++ * pconn -- new connection context
++ *
++ * returns:
++ * SASL_OK -- success
++ * SASL_NOMEM -- not enough memory
++ */
++
++int sasl_server_new(const char *service,
++ const char *serverFQDN,
++ const char *user_realm,
++ const char *iplocalport,
++ const char *ipremoteport,
++ const sasl_callback_t *callbacks,
++ unsigned flags,
++ sasl_conn_t **pconn)
++{
++ int result;
++ sasl_server_conn_t *serverconn;
++ sasl_utils_t *utils;
++ sasl_getopt_t *getopt;
++ void *context;
++ const char *log_level, *auto_trans;
++
++ if (_sasl_server_active==0) return SASL_NOTINIT;
++ if (! pconn) return SASL_FAIL;
++ if (! service) return SASL_FAIL;
++
++ *pconn=sasl_ALLOC(sizeof(sasl_server_conn_t));
++ if (*pconn==NULL) return SASL_NOMEM;
++
++ memset(*pconn, 0, sizeof(sasl_server_conn_t));
++
++ serverconn = (sasl_server_conn_t *)*pconn;
++
++ /* make sparams */
++ serverconn->sparams=sasl_ALLOC(sizeof(sasl_server_params_t));
++ if (serverconn->sparams==NULL)
++ MEMERROR(*pconn);
++
++ memset(serverconn->sparams, 0, sizeof(sasl_server_params_t));
++
++ (*pconn)->destroy_conn = &server_dispose;
++ result = _sasl_conn_init(*pconn, service, flags, SASL_CONN_SERVER,
++ &server_idle, serverFQDN,
++ iplocalport, ipremoteport,
++ callbacks, &global_callbacks);
++ if (result != SASL_OK)
++ goto done_error;
++
++
++ /* set util functions - need to do rest */
++ utils=_sasl_alloc_utils(*pconn, &global_callbacks);
++ if (!utils) {
++ result = SASL_NOMEM;
++ goto done_error;
++ }
++
++ utils->checkpass = &_sasl_checkpass;
++
++ /* Setup the propctx -> We'll assume the default size */
++ serverconn->sparams->propctx=prop_new(0);
++ if(!serverconn->sparams->propctx) {
++ result = SASL_NOMEM;
++ goto done_error;
++ }
++
++ serverconn->sparams->service = (*pconn)->service;
++ serverconn->sparams->servicelen = (unsigned) strlen((*pconn)->service);
++
++ if (global_callbacks.appname && global_callbacks.appname[0] != '\0') {
++ result = _sasl_strdup (global_callbacks.appname,
++ &serverconn->appname,
++ NULL);
++ if (result != SASL_OK) {
++ result = SASL_NOMEM;
++ goto done_error;
++ }
++ serverconn->sparams->appname = serverconn->appname;
++ serverconn->sparams->applen = (unsigned) strlen(serverconn->sparams->appname);
++ } else {
++ serverconn->appname = NULL;
++ serverconn->sparams->appname = NULL;
++ serverconn->sparams->applen = 0;
++ }
++
++ serverconn->sparams->serverFQDN = (*pconn)->serverFQDN;
++ serverconn->sparams->slen = (unsigned) strlen((*pconn)->serverFQDN);
++
++ if (user_realm) {
++ result = _sasl_strdup(user_realm, &serverconn->user_realm, NULL);
++ serverconn->sparams->urlen = (unsigned) strlen(user_realm);
++ serverconn->sparams->user_realm = serverconn->user_realm;
++ } else {
++ serverconn->user_realm = NULL;
++ /* the sparams is already zeroed */
++ }
++
++ serverconn->sparams->callbacks = callbacks;
++
++ log_level = auto_trans = NULL;
++ if(_sasl_getcallback(*pconn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK) {
++ getopt(context, NULL, "log_level", &log_level, NULL);
++ getopt(context, NULL, "auto_transition", &auto_trans, NULL);
++ }
++ serverconn->sparams->log_level = log_level ? atoi(log_level) : SASL_LOG_ERR;
++
++ serverconn->sparams->utils = utils;
++
++ if (auto_trans &&
++ (*auto_trans == '1' || *auto_trans == 'y' || *auto_trans == 't' ||
++ (*auto_trans == 'o' && auto_trans[1] == 'n') ||
++ !strcmp(auto_trans, "noplain")) &&
++ sasl_auxprop_store(NULL, NULL, NULL) == SASL_OK) {
++ serverconn->sparams->transition = &_sasl_transition;
++ }
++
++ serverconn->sparams->canon_user = &_sasl_canon_user;
++ serverconn->sparams->props = serverconn->base.props;
++ serverconn->sparams->flags = flags;
++
++ if(result == SASL_OK) return SASL_OK;
++
++ done_error:
++ _sasl_conn_dispose(*pconn);
++ sasl_FREE(*pconn);
++ *pconn = NULL;
++ return result;
++}
++
++/*
++ * The rule is:
++ * IF mech strength + external strength < min ssf THEN FAIL
++ * We also have to look at the security properties and make sure
++ * that this mechanism has everything we want
++ */
++static int mech_permitted(sasl_conn_t *conn,
++ mechanism_t *mech)
++{
++ sasl_server_conn_t *s_conn = (sasl_server_conn_t *)conn;
++ const sasl_server_plug_t *plug;
++ int ret;
++ int myflags;
++ context_list_t *cur;
++ sasl_getopt_t *getopt;
++ void *context;
++ sasl_ssf_t minssf = 0;
++
++ if(!conn) return SASL_NOMECH;
++
++ if(! mech || ! mech->m.plug) {
++ PARAMERROR(conn);
++ return SASL_NOMECH;
++ }
++
++ plug = mech->m.plug;
++
++ /* get the list of allowed mechanisms (default = all) */
++ if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context)
++ == SASL_OK) {
++ const char *mlist = NULL;
++
++ getopt(context, NULL, "mech_list", &mlist, NULL);
++
++ /* if we have a list, check the plugin against it */
++ if (mlist) {
++ const char *cp;
++
++ while (*mlist) {
++ for (cp = mlist; *cp && !isspace((int) *cp); cp++);
++ if (((size_t) (cp - mlist) == strlen(plug->mech_name)) &&
++ !strncasecmp(mlist, plug->mech_name,
++ strlen(plug->mech_name))) {
++ break;
++ }
++ mlist = cp;
++ while (*mlist && isspace((int) *mlist)) mlist++;
++ }
++
++ if (!*mlist) return SASL_NOMECH; /* reached EOS -> not in our list */
++ }
++ }
++
++ /* setup parameters for the call to mech_avail */
++ s_conn->sparams->serverFQDN=conn->serverFQDN;
++ s_conn->sparams->service=conn->service;
++ s_conn->sparams->user_realm=s_conn->user_realm;
++ s_conn->sparams->props=conn->props;
++ s_conn->sparams->external_ssf=conn->external.ssf;
++
++ /* Check if we have banished this one already */
++ for(cur = s_conn->mech_contexts; cur; cur=cur->next) {
++ if(cur->mech == mech) {
++ /* If it's not mech_avail'd, then stop now */
++ if(!cur->context) return SASL_NOMECH;
++ break;
++ }
++ }
++
++ if (conn->props.min_ssf < conn->external.ssf) {
++ minssf = 0;
++ } else {
++ minssf = conn->props.min_ssf - conn->external.ssf;
++ }
++
++ /* Generic mechanism */
++ if (plug->max_ssf < minssf) {
++ sasl_seterror(conn, SASL_NOLOG,
++ "mech %s is too weak", plug->mech_name);
++ return SASL_TOOWEAK; /* too weak */
++ }
++
++ context = NULL;
++ if(plug->mech_avail
++ && (ret = plug->mech_avail(plug->glob_context,
++ s_conn->sparams, (void **)&context)) != SASL_OK ) {
++ if(ret == SASL_NOMECH) {
++ /* Mark this mech as no good for this connection */
++ cur = sasl_ALLOC(sizeof(context_list_t));
++ if(!cur) {
++ MEMERROR(conn);
++ return SASL_NOMECH;
++ }
++ cur->context = NULL;
++ cur->mech = mech;
++ cur->next = s_conn->mech_contexts;
++ s_conn->mech_contexts = cur;
++ }
++
++ /* SASL_NOTDONE might also get us here */
++
++ /* Error should be set by mech_avail call */
++ return SASL_NOMECH;
++ } else if(context) {
++ /* Save this context */
++ cur = sasl_ALLOC(sizeof(context_list_t));
++ if(!cur) {
++ MEMERROR(conn);
++ return SASL_NOMECH;
++ }
++ cur->context = context;
++ cur->mech = mech;
++ cur->next = s_conn->mech_contexts;
++ s_conn->mech_contexts = cur;
++ }
++
++ /* Generic mechanism */
++ if (plug->max_ssf < minssf) {
++ sasl_seterror(conn, SASL_NOLOG, "too weak");
++ return SASL_TOOWEAK; /* too weak */
++ }
++
++ /* if there are no users in the secrets database we can't use this
++ mechanism */
++ if (mech->m.condition == SASL_NOUSER) {
++ sasl_seterror(conn, 0, "no users in secrets db");
++ return SASL_NOMECH;
++ }
++
++ /* Can it meet our features? */
++ if ((conn->flags & SASL_NEED_PROXY) &&
++ !(plug->features & SASL_FEAT_ALLOWS_PROXY)) {
++ return SASL_NOMECH;
++ }
++
++ /* security properties---if there are any flags that differ and are
++ in what the connection are requesting, then fail */
++
++ /* special case plaintext */
++ myflags = conn->props.security_flags;
++
++ /* if there's an external layer this is no longer plaintext */
++ if ((conn->props.min_ssf <= conn->external.ssf) &&
++ (conn->external.ssf > 1)) {
++ myflags &= ~SASL_SEC_NOPLAINTEXT;
++ }
++
++ /* do we want to special case SASL_SEC_PASS_CREDENTIALS? nah.. */
++ if ((myflags &= (myflags ^ plug->security_flags)) != 0) {
++ sasl_seterror(conn, SASL_NOLOG,
++ "security flags do not match required");
++ return (myflags & SASL_SEC_NOPLAINTEXT) ? SASL_ENCRYPT : SASL_NOMECH;
++ }
++
++ /* Check Features */
++ if(plug->features & SASL_FEAT_GETSECRET) {
++ /* We no longer support sasl_server_{get,put}secret */
++ sasl_seterror(conn, 0,
++ "mech %s requires unprovided secret facility",
++ plug->mech_name);
++ return SASL_NOMECH;
++ }
++
++ return SASL_OK;
++}
++
++/*
++ * make the authorization
++ *
++ */
++
++static int do_authorization(sasl_server_conn_t *s_conn)
++{
++ int ret;
++ sasl_authorize_t *authproc;
++ void *auth_context;
++
++ /* now let's see if authname is allowed to proxy for username! */
++
++ /* check the proxy callback */
++ if (_sasl_getcallback(&s_conn->base, SASL_CB_PROXY_POLICY,
++ &authproc, &auth_context) != SASL_OK) {
++ INTERROR(&s_conn->base, SASL_NOAUTHZ);
++ }
++
++ ret = authproc(&(s_conn->base), auth_context,
++ s_conn->base.oparams.user, s_conn->base.oparams.ulen,
++ s_conn->base.oparams.authid, s_conn->base.oparams.alen,
++ s_conn->user_realm,
++ (s_conn->user_realm ? (unsigned) strlen(s_conn->user_realm) : 0),
++ s_conn->sparams->propctx);
++
++ RETURN(&s_conn->base, ret);
++}
++
++
++/* start a mechanism exchange within a connection context
++ * mech -- the mechanism name client requested
++ * clientin -- client initial response (NUL terminated), NULL if empty
++ * clientinlen -- length of initial response
++ * serverout -- initial server challenge, NULL if done
++ * (library handles freeing this string)
++ * serveroutlen -- length of initial server challenge
++ * output:
++ * pconn -- the connection negotiation state on success
++ *
++ * Same returns as sasl_server_step() or
++ * SASL_NOMECH if mechanism not available.
++ */
++int sasl_server_start(sasl_conn_t *conn,
++ const char *mech,
++ const char *clientin,
++ unsigned clientinlen,
++ const char **serverout,
++ unsigned *serveroutlen)
++{
++ sasl_server_conn_t *s_conn=(sasl_server_conn_t *) conn;
++ int result;
++ context_list_t *cur, **prev;
++ mechanism_t *m;
++
++ if (_sasl_server_active==0) return SASL_NOTINIT;
++
++ /* make sure mech is valid mechanism
++ if not return appropriate error */
++ m=mechlist->mech_list;
++
++ /* check parameters */
++ if(!conn) return SASL_BADPARAM;
++
++ if (!mech || ((clientin==NULL) && (clientinlen>0)))
++ PARAMERROR(conn);
++
++ if(serverout) *serverout = NULL;
++ if(serveroutlen) *serveroutlen = 0;
++
++ while (m!=NULL)
++ {
++ if ( strcasecmp(mech, m->m.plug->mech_name)==0)
++ {
++ break;
++ }
++ m=m->next;
++ }
++
++ if (m==NULL) {
++ sasl_seterror(conn, 0, "Couldn't find mech %s", mech);
++ result = SASL_NOMECH;
++ goto done;
++ }
++
++ /* Make sure that we're willing to use this mech */
++ if ((result = mech_permitted(conn, m)) != SASL_OK) {
++ goto done;
++ }
++
++ if (m->m.condition == SASL_CONTINUE) {
++ sasl_server_plug_init_t *entry_point;
++ void *library = NULL;
++ sasl_server_plug_t *pluglist;
++ int version, plugcount;
++ int l = 0;
++
++ /* need to load this plugin */
++ result = _sasl_get_plugin(m->m.f,
++ _sasl_find_verifyfile_callback(global_callbacks.callbacks),
++ &library);
++
++ if (result == SASL_OK) {
++ result = _sasl_locate_entry(library, "sasl_server_plug_init",
++ (void **)&entry_point);
++ }
++
++ if (result == SASL_OK) {
++ result = entry_point(mechlist->utils, SASL_SERVER_PLUG_VERSION,
++ &version, &pluglist, &plugcount);
++ }
++
++ if (result == SASL_OK) {
++ /* find the correct mechanism in this plugin */
++ for (l = 0; l < plugcount; l++) {
++ if (!strcasecmp(pluglist[l].mech_name,
++ m->m.plug->mech_name)) break;
++ }
++ if (l == plugcount) {
++ result = SASL_NOMECH;
++ }
++ }
++ if (result == SASL_OK) {
++ /* check that the parameters are the same */
++ if ((pluglist[l].max_ssf != m->m.plug->max_ssf) ||
++ (pluglist[l].security_flags != m->m.plug->security_flags)) {
++ _sasl_log(conn, SASL_LOG_ERR,
++ "%s: security parameters don't match mechlist file",
++ pluglist[l].mech_name);
++ result = SASL_NOMECH;
++ }
++ }
++ if (result == SASL_OK) {
++ /* copy mechlist over */
++ sasl_FREE((sasl_server_plug_t *) m->m.plug);
++ m->m.plug = &pluglist[l];
++ m->m.condition = SASL_OK;
++ }
++
++ if (result != SASL_OK) {
++ /* The library will eventually be freed, don't sweat it */
++ RETURN(conn, result);
++ }
++ }
++
++ /* We used to setup sparams HERE, but now it's done
++ inside of mech_permitted (which is called above) */
++ prev = &s_conn->mech_contexts;
++ for(cur = *prev; cur; prev=&cur->next,cur=cur->next) {
++ if(cur->mech == m) {
++ if(!cur->context) {
++ sasl_seterror(conn, 0,
++ "Got past mech_permitted with a disallowed mech!");
++ return SASL_NOMECH;
++ }
++ /* If we find it, we need to pull cur out of the
++ list so it won't be freed later! */
++ (*prev)->next = cur->next;
++ conn->context = cur->context;
++ sasl_FREE(cur);
++ }
++ }
++
++ s_conn->mech = m;
++
++ if(!conn->context) {
++ /* Note that we don't hand over a new challenge */
++ result = s_conn->mech->m.plug->mech_new(s_conn->mech->m.plug->glob_context,
++ s_conn->sparams,
++ NULL,
++ 0,
++ &(conn->context));
++ } else {
++ /* the work was already done by mech_avail! */
++ result = SASL_OK;
++ }
++
++ if (result == SASL_OK) {
++ if(clientin) {
++ if(s_conn->mech->m.plug->features & SASL_FEAT_SERVER_FIRST) {
++ /* Remote sent first, but mechanism does not support it.
++ * RFC 2222 says we fail at this point. */
++ sasl_seterror(conn, 0,
++ "Remote sent first but mech does not allow it.");
++ result = SASL_BADPROT;
++ } else {
++ /* Mech wants client-first, so let them have it */
++ result = sasl_server_step(conn,
++ clientin, clientinlen,
++ serverout, serveroutlen);
++ }
++ } else {
++ if(s_conn->mech->m.plug->features & SASL_FEAT_WANT_CLIENT_FIRST) {
++ /* Mech wants client first anyway, so we should do that */
++ *serverout = "";
++ *serveroutlen = 0;
++ result = SASL_CONTINUE;
++ } else {
++ /* Mech wants server-first, so let them have it */
++ result = sasl_server_step(conn,
++ clientin, clientinlen,
++ serverout, serveroutlen);
++ }
++ }
++ }
++
++ done:
++ if( result != SASL_OK
++ && result != SASL_CONTINUE
++ && result != SASL_INTERACT) {
++ if(conn->context) {
++ s_conn->mech->m.plug->mech_dispose(conn->context,
++ s_conn->sparams->utils);
++ conn->context = NULL;
++ }
++ }
++
++ RETURN(conn,result);
++}
++
++
++/* perform one step of the SASL exchange
++ * inputlen & input -- client data
++ * NULL on first step if no optional client step
++ * outputlen & output -- set to the server data to transmit
++ * to the client in the next step
++ * (library handles freeing this)
++ *
++ * returns:
++ * SASL_OK -- exchange is complete.
++ * SASL_CONTINUE -- indicates another step is necessary.
++ * SASL_TRANS -- entry for user exists, but not for mechanism
++ * and transition is possible
++ * SASL_BADPARAM -- service name needed
++ * SASL_BADPROT -- invalid input from client
++ * ...
++ */
++
++int sasl_server_step(sasl_conn_t *conn,
++ const char *clientin,
++ unsigned clientinlen,
++ const char **serverout,
++ unsigned *serveroutlen)
++{
++ int ret;
++ sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn; /* cast */
++
++ /* check parameters */
++ if (_sasl_server_active==0) return SASL_NOTINIT;
++ if (!conn) return SASL_BADPARAM;
++ if ((clientin==NULL) && (clientinlen>0))
++ PARAMERROR(conn);
++
++ /* If we've already done the last send, return! */
++ if(s_conn->sent_last == 1) {
++ return SASL_OK;
++ }
++
++ /* Don't do another step if the plugin told us that we're done */
++ if (conn->oparams.doneflag) {
++ _sasl_log(conn, SASL_LOG_ERR, "attempting server step after doneflag");
++ return SASL_FAIL;
++ }
++
++ if(serverout) *serverout = NULL;
++ if(serveroutlen) *serveroutlen = 0;
++
++ ret = s_conn->mech->m.plug->mech_step(conn->context,
++ s_conn->sparams,
++ clientin,
++ clientinlen,
++ serverout,
++ serveroutlen,
++ &conn->oparams);
++
++ if (ret == SASL_OK) {
++ ret = do_authorization(s_conn);
++ }
++
++ if (ret == SASL_OK) {
++ /* if we're done, we need to watch out for the following:
++ * 1. the mech does server-send-last
++ * 2. the protocol does not
++ *
++ * in this case, return SASL_CONTINUE and remember we are done.
++ */
++ if(*serverout && !(conn->flags & SASL_SUCCESS_DATA)) {
++ s_conn->sent_last = 1;
++ ret = SASL_CONTINUE;
++ }
++ if(!conn->oparams.maxoutbuf) {
++ conn->oparams.maxoutbuf = conn->props.maxbufsize;
++ }
++
++ if(conn->oparams.user == NULL || conn->oparams.authid == NULL) {
++ sasl_seterror(conn, 0,
++ "mech did not call canon_user for both authzid " \
++ "and authid");
++ ret = SASL_BADPROT;
++ }
++ }
++
++ if( ret != SASL_OK
++ && ret != SASL_CONTINUE
++ && ret != SASL_INTERACT) {
++ if(conn->context) {
++ s_conn->mech->m.plug->mech_dispose(conn->context,
++ s_conn->sparams->utils);
++ conn->context = NULL;
++ }
++ }
++
++ RETURN(conn, ret);
++}
++
++/* returns the length of all the mechanisms
++ * added up
++ */
++
++static unsigned mech_names_len()
++{
++ mechanism_t *listptr;
++ unsigned result = 0;
++
++ for (listptr = mechlist->mech_list;
++ listptr;
++ listptr = listptr->next)
++ result += (unsigned) strlen(listptr->m.plug->mech_name);
++
++ return result;
++}
++
++/* This returns a list of mechanisms in a NUL-terminated string
++ *
++ * The default behavior is to seperate with spaces if sep==NULL
++ */
++int _sasl_server_listmech(sasl_conn_t *conn,
++ const char *user __attribute__((unused)),
++ const char *prefix,
++ const char *sep,
++ const char *suffix,
++ const char **result,
++ unsigned *plen,
++ int *pcount)
++{
++ int lup;
++ mechanism_t *listptr;
++ int ret;
++ size_t resultlen;
++ int flag;
++ const char *mysep;
++
++ /* if there hasn't been a sasl_sever_init() fail */
++ if (_sasl_server_active==0) return SASL_NOTINIT;
++ if (!conn) return SASL_BADPARAM;
++ if (conn->type != SASL_CONN_SERVER) PARAMERROR(conn);
++
++ if (! result)
++ PARAMERROR(conn);
++
++ if (plen != NULL)
++ *plen = 0;
++ if (pcount != NULL)
++ *pcount = 0;
++
++ if (sep) {
++ mysep = sep;
++ } else {
++ mysep = " ";
++ }
++
++ if (! mechlist || mechlist->mech_length <= 0)
++ INTERROR(conn, SASL_NOMECH);
++
++ resultlen = (prefix ? strlen(prefix) : 0)
++ + (strlen(mysep) * (mechlist->mech_length - 1))
++ + mech_names_len()
++ + (suffix ? strlen(suffix) : 0)
++ + 1;
++ ret = _buf_alloc(&conn->mechlist_buf,
++ &conn->mechlist_buf_len, resultlen);
++ if(ret != SASL_OK) MEMERROR(conn);
++
++ if (prefix)
++ strcpy (conn->mechlist_buf,prefix);
++ else
++ *(conn->mechlist_buf) = '\0';
++
++ listptr = mechlist->mech_list;
++
++ flag = 0;
++ /* make list */
++ for (lup = 0; lup < mechlist->mech_length; lup++) {
++ /* currently, we don't use the "user" parameter for anything */
++ if (mech_permitted(conn, listptr) == SASL_OK) {
++ if (pcount != NULL)
++ (*pcount)++;
++
++ /* print separator */
++ if (flag) {
++ strcat(conn->mechlist_buf, mysep);
++ } else {
++ flag = 1;
++ }
++
++ /* now print the mechanism name */
++ strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
++ }
++
++ listptr = listptr->next;
++ }
++
++ if (suffix)
++ strcat(conn->mechlist_buf,suffix);
++
++ if (plen!=NULL)
++ *plen = (unsigned) strlen(conn->mechlist_buf);
++
++ *result = conn->mechlist_buf;
++
++ return SASL_OK;
++}
++
++sasl_string_list_t *_sasl_server_mechs(void)
++{
++ mechanism_t *listptr;
++ sasl_string_list_t *retval = NULL, *next=NULL;
++
++ if(!_sasl_server_active) return NULL;
++
++ /* make list */
++ for (listptr = mechlist->mech_list; listptr; listptr = listptr->next) {
++ next = sasl_ALLOC(sizeof(sasl_string_list_t));
++
++ if(!next && !retval) return NULL;
++ else if(!next) {
++ next = retval->next;
++ do {
++ sasl_FREE(retval);
++ retval = next;
++ next = retval->next;
++ } while(next);
++ return NULL;
++ }
++
++ next->d = listptr->m.plug->mech_name;
++
++ if(!retval) {
++ next->next = NULL;
++ retval = next;
++ } else {
++ next->next = retval;
++ retval = next;
++ }
++ }
++
++ return retval;
++}
++
++#define EOSTR(s,n) (((s)[n] == '\0') || ((s)[n] == ' ') || ((s)[n] == '\t'))
++static int is_mech(const char *t, const char *m)
++{
++ size_t sl = strlen(m);
++ return ((!strncasecmp(m, t, sl)) && EOSTR(t, sl));
++}
++
++/* returns OK if it's valid */
++static int _sasl_checkpass(sasl_conn_t *conn,
++ const char *user,
++ unsigned userlen,
++ const char *pass,
++ unsigned passlen)
++{
++ sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
++ int result;
++ sasl_getopt_t *getopt;
++ sasl_server_userdb_checkpass_t *checkpass_cb;
++ void *context;
++ const char *mlist = NULL, *mech = NULL;
++ struct sasl_verify_password_s *v;
++ const char *service = conn->service;
++
++ if (!userlen) userlen = (unsigned) strlen(user);
++ if (!passlen) passlen = (unsigned) strlen(pass);
++
++ /* call userdb callback function, if available */
++ result = _sasl_getcallback(conn, SASL_CB_SERVER_USERDB_CHECKPASS,
++ &checkpass_cb, &context);
++ if(result == SASL_OK && checkpass_cb) {
++ result = checkpass_cb(conn, context, user, pass, passlen,
++ s_conn->sparams->propctx);
++ if(result == SASL_OK)
++ return SASL_OK;
++ }
++
++ /* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */
++ if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context)
++ == SASL_OK) {
++ getopt(context, NULL, "pwcheck_method", &mlist, NULL);
++ }
++
++ if(!mlist) mlist = DEFAULT_CHECKPASS_MECH;
++
++ result = SASL_NOMECH;
++
++ mech = mlist;
++ while (*mech && result != SASL_OK) {
++ for (v = _sasl_verify_password; v->name; v++) {
++ if(is_mech(mech, v->name)) {
++ result = v->verify(conn, user, pass, service,
++ s_conn->user_realm);
++ break;
++ }
++ }
++ if (result != SASL_OK) {
++ /* skip to next mech in list */
++ while (*mech && !isspace((int) *mech)) mech++;
++ while (*mech && isspace((int) *mech)) mech++;
++ }
++ else if (!is_mech(mech, "auxprop") && s_conn->sparams->transition) {
++ s_conn->sparams->transition(conn, pass, passlen);
++ }
++ }
++
++ if (result == SASL_NOMECH) {
++ /* no mechanism available ?!? */
++ _sasl_log(conn, SASL_LOG_ERR, "unknown password verifier %s", mech);
++ }
++
++ if (result != SASL_OK)
++ sasl_seterror(conn, SASL_NOLOG, "checkpass failed");
++
++ RETURN(conn, result);
++}
++
++/* check if a plaintext password is valid
++ * if user is NULL, check if plaintext passwords are enabled
++ * inputs:
++ * user -- user to query in current user_domain
++ * userlen -- length of username, 0 = strlen(user)
++ * pass -- plaintext password to check
++ * passlen -- length of password, 0 = strlen(pass)
++ * returns
++ * SASL_OK -- success
++ * SASL_NOMECH -- mechanism not supported
++ * SASL_NOVERIFY -- user found, but no verifier
++ * SASL_NOUSER -- user not found
++ */
++int sasl_checkpass(sasl_conn_t *conn,
++ const char *user,
++ unsigned userlen,
++ const char *pass,
++ unsigned passlen)
++{
++ int result;
++
++ if (_sasl_server_active==0) return SASL_NOTINIT;
++
++ /* check if it's just a query if we are enabled */
++ if (!user)
++ return SASL_OK;
++
++ if (!conn) return SASL_BADPARAM;
++
++ /* check params */
++ if (pass == NULL)
++ PARAMERROR(conn);
++
++ /* canonicalize the username */
++ result = _sasl_canon_user(conn, user, userlen,
++ SASL_CU_AUTHID | SASL_CU_AUTHZID,
++ &(conn->oparams));
++ if(result != SASL_OK) RETURN(conn, result);
++ user = conn->oparams.user;
++
++ /* Check the password */
++ result = _sasl_checkpass(conn, user, userlen, pass, passlen);
++
++ /* Do authorization */
++ if(result == SASL_OK) {
++ result = do_authorization((sasl_server_conn_t *)conn);
++ }
++
++ RETURN(conn,result);
++}
++
++/* check if a user exists on server
++ * conn -- connection context (may be NULL, used to hold last error)
++ * service -- registered name of the service using SASL (e.g. "imap")
++ * user_realm -- permits multiple user realms on server, NULL = default
++ * user -- NUL terminated user name
++ *
++ * returns:
++ * SASL_OK -- success
++ * SASL_DISABLED -- account disabled [FIXME: currently not detected]
++ * SASL_NOUSER -- user not found
++ * SASL_NOVERIFY -- user found, but no usable mechanism [FIXME: not supported]
++ * SASL_NOMECH -- no mechanisms enabled
++ */
++int sasl_user_exists(sasl_conn_t *conn,
++ const char *service,
++ const char *user_realm,
++ const char *user)
++{
++ int result=SASL_NOMECH;
++ const char *mlist = NULL, *mech = NULL;
++ void *context;
++ sasl_getopt_t *getopt;
++ struct sasl_verify_password_s *v;
++
++ /* check params */
++ if (_sasl_server_active==0) return SASL_NOTINIT;
++ if (!conn) return SASL_BADPARAM;
++ if (!user || conn->type != SASL_CONN_SERVER)
++ PARAMERROR(conn);
++
++ if(!service) service = conn->service;
++
++ /* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */
++ if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context)
++ == SASL_OK) {
++ getopt(context, NULL, "pwcheck_method", &mlist, NULL);
++ }
++
++ if(!mlist) mlist = DEFAULT_CHECKPASS_MECH;
++
++ result = SASL_NOMECH;
++
++ mech = mlist;
++ while (*mech && result != SASL_OK) {
++ for (v = _sasl_verify_password; v->name; v++) {
++ if(is_mech(mech, v->name)) {
++ result = v->verify(conn, user, NULL, service, user_realm);
++ break;
++ }
++ }
++ if (result != SASL_OK) {
++ /* skip to next mech in list */
++ while (*mech && !isspace((int) *mech)) mech++;
++ while (*mech && isspace((int) *mech)) mech++;
++ }
++ }
++
++ /* Screen out the SASL_BADPARAM response
++ * we'll get from not giving a password */
++ if(result == SASL_BADPARAM) {
++ result = SASL_OK;
++ }
++
++ if (result == SASL_NOMECH) {
++ /* no mechanism available ?!? */
++ _sasl_log(conn, SASL_LOG_ERR, "no plaintext password verifier?");
++ sasl_seterror(conn, SASL_NOLOG, "no plaintext password verifier?");
++ }
++
++ RETURN(conn, result);
++}
++
++/* check if an apop exchange is valid
++ * (note this is an optional part of the SASL API)
++ * if challenge is NULL, just check if APOP is enabled
++ * inputs:
++ * challenge -- challenge which was sent to client
++ * challen -- length of challenge, 0 = strlen(challenge)
++ * response -- client response, "<user> <digest>" (RFC 1939)
++ * resplen -- length of response, 0 = strlen(response)
++ * returns
++ * SASL_OK -- success
++ * SASL_BADAUTH -- authentication failed
++ * SASL_BADPARAM -- missing challenge
++ * SASL_BADPROT -- protocol error (e.g., response in wrong format)
++ * SASL_NOVERIFY -- user found, but no verifier
++ * SASL_NOMECH -- mechanism not supported
++ * SASL_NOUSER -- user not found
++ */
++int sasl_checkapop(sasl_conn_t *conn,
++#ifdef DO_SASL_CHECKAPOP
++ const char *challenge,
++ unsigned challen __attribute__((unused)),
++ const char *response,
++ unsigned resplen __attribute__((unused)))
++#else
++ const char *challenge __attribute__((unused)),
++ unsigned challen __attribute__((unused)),
++ const char *response __attribute__((unused)),
++ unsigned resplen __attribute__((unused)))
++#endif
++{
++#ifdef DO_SASL_CHECKAPOP
++ sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
++ char *user, *user_end;
++ const char *password_request[] = { SASL_AUX_PASSWORD, NULL };
++ size_t user_len;
++ int result;
++
++ if (_sasl_server_active==0)
++ return SASL_NOTINIT;
++
++ /* check if it's just a query if we are enabled */
++ if(!challenge)
++ return SASL_OK;
++
++ /* check params */
++ if (!conn) return SASL_BADPARAM;
++ if (!response)
++ PARAMERROR(conn);
++
++ /* Parse out username and digest.
++ *
++ * Per RFC 1939, response must be "<user> <digest>", where
++ * <digest> is a 16-octet value which is sent in hexadecimal
++ * format, using lower-case ASCII characters.
++ */
++ user_end = strrchr(response, ' ');
++ if (!user_end || strspn(user_end + 1, "0123456789abcdef") != 32)
++ {
++ sasl_seterror(conn, 0, "Bad Digest");
++ RETURN(conn,SASL_BADPROT);
++ }
++
++ user_len = (size_t)(user_end - response);
++ user = sasl_ALLOC(user_len + 1);
++ memcpy(user, response, user_len);
++ user[user_len] = '\0';
++
++ result = prop_request(s_conn->sparams->propctx, password_request);
++ if(result != SASL_OK)
++ {
++ sasl_FREE(user);
++ RETURN(conn, result);
++ }
++
++ /* erase the plaintext password */
++ s_conn->sparams->utils->prop_erase(s_conn->sparams->propctx,
++ password_request[0]);
++
++ /* Cannonify it */
++ result = _sasl_canon_user(conn, user, user_len,
++ SASL_CU_AUTHID | SASL_CU_AUTHZID,
++ &(conn->oparams));
++ sasl_FREE(user);
++
++ if(result != SASL_OK) RETURN(conn, result);
++
++ /* Do APOP verification */
++ result = _sasl_auxprop_verify_apop(conn, conn->oparams.authid,
++ challenge, user_end + 1, s_conn->user_realm);
++
++ /* Do authorization */
++ if(result == SASL_OK) {
++ result = do_authorization((sasl_server_conn_t *)conn);
++ } else {
++ /* If verification failed, we don't want to encourage getprop to work */
++ conn->oparams.user = NULL;
++ conn->oparams.authid = NULL;
++ }
++
++ RETURN(conn, result);
++#else /* sasl_checkapop was disabled at compile time */
++ sasl_seterror(conn, SASL_NOLOG,
++ "sasl_checkapop called, but was disabled at compile time");
++ RETURN(conn, SASL_NOMECH);
++#endif /* DO_SASL_CHECKAPOP */
++}
++
++/* It would be nice if we can show other information like Author, Company, Year, plugin version */
++static void
++_sasl_print_mechanism (
++ server_sasl_mechanism_t *m,
++ sasl_info_callback_stage_t stage,
++ void *rock
++)
++{
++ char delimiter;
++
++ if (stage == SASL_INFO_LIST_START) {
++ printf ("List of server plugins follows\n");
++ return;
++ } else if (stage == SASL_INFO_LIST_END) {
++ return;
++ }
++
++ /* Process the mechanism */
++ printf ("Plugin \"%s\" ", m->plugname);
++
++ switch (m->condition) {
++ case SASL_OK:
++ printf ("[loaded]");
++ break;
++
++ case SASL_CONTINUE:
++ printf ("[delayed]");
++ break;
++
++ case SASL_NOUSER:
++ printf ("[no users]");
++ break;
++
++ default:
++ printf ("[unknown]");
++ break;
++ }
++
++ printf (", \tAPI version: %d\n", m->version);
++
++ if (m->plug != NULL) {
++ printf ("\tSASL mechanism: %s, best SSF: %d, supports setpass: %s\n",
++ m->plug->mech_name,
++ m->plug->max_ssf,
++ (m->plug->setpass != NULL) ? "yes" : "no"
++ );
++
++
++ printf ("\tsecurity flags:");
++
++ delimiter = ' ';
++ if (m->plug->security_flags & SASL_SEC_NOANONYMOUS) {
++ printf ("%cNO_ANONYMOUS", delimiter);
++ delimiter = '|';
++ }
++
++ if (m->plug->security_flags & SASL_SEC_NOPLAINTEXT) {
++ printf ("%cNO_PLAINTEXT", delimiter);
++ delimiter = '|';
++ }
++
++ if (m->plug->security_flags & SASL_SEC_NOACTIVE) {
++ printf ("%cNO_ACTIVE", delimiter);
++ delimiter = '|';
++ }
++
++ if (m->plug->security_flags & SASL_SEC_NODICTIONARY) {
++ printf ("%cNO_DICTIONARY", delimiter);
++ delimiter = '|';
++ }
++
++ if (m->plug->security_flags & SASL_SEC_FORWARD_SECRECY) {
++ printf ("%cFORWARD_SECRECY", delimiter);
++ delimiter = '|';
++ }
++
++ if (m->plug->security_flags & SASL_SEC_PASS_CREDENTIALS) {
++ printf ("%cPASS_CREDENTIALS", delimiter);
++ delimiter = '|';
++ }
++
++ if (m->plug->security_flags & SASL_SEC_MUTUAL_AUTH) {
++ printf ("%cMUTUAL_AUTH", delimiter);
++ delimiter = '|';
++ }
++
++
++
++ printf ("\n\tfeatures:");
++
++ delimiter = ' ';
++ if (m->plug->features & SASL_FEAT_WANT_CLIENT_FIRST) {
++ printf ("%cWANT_CLIENT_FIRST", delimiter);
++ delimiter = '|';
++ }
++
++ if (m->plug->features & SASL_FEAT_SERVER_FIRST) {
++ printf ("%cSERVER_FIRST", delimiter);
++ delimiter = '|';
++ }
++
++ if (m->plug->features & SASL_FEAT_ALLOWS_PROXY) {
++ printf ("%cPROXY_AUTHENTICATION", delimiter);
++ delimiter = '|';
++ }
++
++ if (m->plug->features & SASL_FEAT_NEEDSERVERFQDN) {
++ printf ("%cNEED_SERVER_FQDN", delimiter);
++ delimiter = '|';
++ }
++
++ /* Is this one used? */
++ if (m->plug->features & SASL_FEAT_SERVICE) {
++ printf ("%cSERVICE", delimiter);
++ delimiter = '|';
++ }
++
++ if (m->plug->features & SASL_FEAT_GETSECRET) {
++ printf ("%cNEED_GETSECRET", delimiter);
++ delimiter = '|';
++ }
++ }
++
++ if (m->f) {
++ printf ("\n\twill be loaded from \"%s\"", m->f);
++ }
++
++ printf ("\n");
++}
++
++/* Dump information about available server plugins (separate functions should be
++ used for canon and auxprop plugins */
++int sasl_server_plugin_info (
++ const char *c_mech_list, /* space separated mechanism list or NULL for ALL */
++ sasl_server_info_callback_t *info_cb,
++ void *info_cb_rock
++)
++{
++ mechanism_t *m;
++ server_sasl_mechanism_t plug_data;
++ char * cur_mech;
++ char *mech_list = NULL;
++ char * p;
++
++ if (info_cb == NULL) {
++ info_cb = _sasl_print_mechanism;
++ }
++
++ if (mechlist != NULL) {
++ info_cb (NULL, SASL_INFO_LIST_START, info_cb_rock);
++
++ if (c_mech_list == NULL) {
++ m = mechlist->mech_list; /* m point to beginning of the list */
++
++ while (m != NULL) {
++ memcpy (&plug_data, &m->m, sizeof(plug_data));
++
++ info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
++
++ m = m->next;
++ }
++ } else {
++ mech_list = strdup(c_mech_list);
++
++ cur_mech = mech_list;
++
++ while (cur_mech != NULL) {
++ p = strchr (cur_mech, ' ');
++ if (p != NULL) {
++ *p = '\0';
++ p++;
++ }
++
++ m = mechlist->mech_list; /* m point to beginning of the list */
++
++ while (m != NULL) {
++ if (strcasecmp (cur_mech, m->m.plug->mech_name) == 0) {
++ memcpy (&plug_data, &m->m, sizeof(plug_data));
++
++ info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
++ }
++
++ m = m->next;
++ }
++
++ cur_mech = p;
++ }
++
++ free (mech_list);
++ }
++
++ info_cb (NULL, SASL_INFO_LIST_END, info_cb_rock);
++
++ return (SASL_OK);
++ }
++
++ return (SASL_NOTINIT);
++}
Propchange: cyrus-sasl-2.1/trunk/debian/patches/0008_one_time_sasl_set_alloc.dpatch
------------------------------------------------------------------------------
svn:executable = *
Modified: cyrus-sasl-2.1/trunk/debian/patches/00list
URL: http://svn.debian.org/wsvn/pkg-cyrus-sasl2/cyrus-sasl-2.1/trunk/debian/patches/00list?rev=29&op=diff
==============================================================================
--- cyrus-sasl-2.1/trunk/debian/patches/00list (original)
+++ cyrus-sasl-2.1/trunk/debian/patches/00list Mon Jul 31 15:54:50 2006
@@ -5,3 +5,4 @@
0005_dbconverter
0006_library_mutexes
0007_manpages_section
+0008_one_time_sasl_set_alloc
More information about the Pkg-cyrus-sasl2-commits
mailing list