aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/sasl/lib
diff options
context:
space:
mode:
authormolotkov-and <molotkov-and@ydb.tech>2023-08-18 17:20:47 +0300
committermolotkov-and <molotkov-and@ydb.tech>2023-08-18 19:42:07 +0300
commit73215359bc33e76f5b94d1832a377072bf245cfc (patch)
tree9cb8ad61d8c3cd107353d42951560ff3cf1b966d /contrib/libs/sasl/lib
parent1cbfd34a55732f7b1d407986b45e40853f01f2c2 (diff)
downloadydb-73215359bc33e76f5b94d1832a377072bf245cfc.tar.gz
KIKIMR-18220: Enrich token with groups from LDAP
Add ldap functions wrapper and separate in different files for compatibility with different OS. Add user groups fetching from ldap server. Limitations: - Fixed 'memberOf' attribute - No tests to check how filter for search created - Fetched groups are returned in event as is.
Diffstat (limited to 'contrib/libs/sasl/lib')
-rw-r--r--contrib/libs/sasl/lib/auxprop.c1202
-rw-r--r--contrib/libs/sasl/lib/canonusr.c465
-rw-r--r--contrib/libs/sasl/lib/checkpw.c1110
-rw-r--r--contrib/libs/sasl/lib/client.c1317
-rw-r--r--contrib/libs/sasl/lib/common.c2674
-rw-r--r--contrib/libs/sasl/lib/config.c168
-rw-r--r--contrib/libs/sasl/lib/dlopen.c569
-rw-r--r--contrib/libs/sasl/lib/external.c407
-rw-r--r--contrib/libs/sasl/lib/md5.c527
-rw-r--r--contrib/libs/sasl/lib/saslint.h544
-rw-r--r--contrib/libs/sasl/lib/saslutil.c790
-rw-r--r--contrib/libs/sasl/lib/server.c2406
-rw-r--r--contrib/libs/sasl/lib/seterror.c263
-rw-r--r--contrib/libs/sasl/lib/staticopen.h188
14 files changed, 12630 insertions, 0 deletions
diff --git a/contrib/libs/sasl/lib/auxprop.c b/contrib/libs/sasl/lib/auxprop.c
new file mode 100644
index 0000000000..1b0162db74
--- /dev/null
+++ b/contrib/libs/sasl/lib/auxprop.c
@@ -0,0 +1,1202 @@
+/* auxprop.c - auxilliary property support
+ * Rob Siemborski
+ */
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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.
+ */
+
+#include <config.h>
+#include <sasl.h>
+#include <prop.h>
+#include <ctype.h>
+#include <stdio.h>
+#include "saslint.h"
+
+struct proppool
+{
+ struct proppool *next;
+
+ size_t size; /* Size of Block */
+ size_t unused; /* Space unused in this pool between end
+ * of char** area and beginning of char* area */
+
+ char data[1]; /* Variable Sized */
+};
+
+struct propctx {
+ struct propval *values;
+ struct propval *prev_val; /* Previous value used by set/setvalues */
+
+ unsigned used_values, allocated_values;
+
+ char *data_end; /* Bottom of string area in current pool */
+ char **list_end; /* Top of list area in current pool */
+
+ struct proppool *mem_base;
+ struct proppool *mem_cur;
+};
+
+typedef struct auxprop_plug_list
+{
+ struct auxprop_plug_list *next;
+ const sasl_auxprop_plug_t *plug;
+} auxprop_plug_list_t;
+
+static auxprop_plug_list_t *auxprop_head = NULL;
+
+static struct proppool *alloc_proppool(size_t size)
+{
+ struct proppool *ret;
+ /* minus 1 for the one that is already a part of the array
+ * in the struct */
+ size_t total_size = sizeof(struct proppool) + size - 1;
+ ret = sasl_ALLOC(total_size);
+ if(!ret) return NULL;
+
+ memset(ret, 0, total_size);
+
+ ret->size = ret->unused = size;
+
+ return ret;
+}
+
+/* Resize a proppool. Invalidates the unused value for this pool */
+static struct proppool *resize_proppool(struct proppool *pool, size_t size)
+{
+ struct proppool *ret;
+
+ if(pool->size >= size) return pool;
+ ret = sasl_REALLOC(pool, sizeof(struct proppool) + size);
+ if(!ret) return NULL;
+
+ ret->size = size;
+
+ return ret;
+}
+
+static int prop_init(struct propctx *ctx, unsigned estimate)
+{
+ const unsigned VALUES_SIZE = PROP_DEFAULT * sizeof(struct propval);
+
+ ctx->mem_base = alloc_proppool(VALUES_SIZE + estimate);
+ if(!ctx->mem_base) return SASL_NOMEM;
+
+ ctx->mem_cur = ctx->mem_base;
+
+ ctx->values = (struct propval *)ctx->mem_base->data;
+ ctx->mem_base->unused = ctx->mem_base->size - VALUES_SIZE;
+ ctx->allocated_values = PROP_DEFAULT;
+ ctx->used_values = 0;
+
+ ctx->data_end = ctx->mem_base->data + ctx->mem_base->size;
+ ctx->list_end = (char **)(ctx->mem_base->data + VALUES_SIZE);
+
+ ctx->prev_val = NULL;
+
+ return SASL_OK;
+}
+
+/* create a property context
+ * estimate -- an estimate of the storage needed for requests & responses
+ * 0 will use module default
+ * returns NULL on error
+ */
+struct propctx *prop_new(unsigned estimate)
+{
+ struct propctx *new_ctx;
+
+ if(!estimate) estimate = PROP_DEFAULT * 255;
+
+ new_ctx = sasl_ALLOC(sizeof(struct propctx));
+ if(!new_ctx) return NULL;
+
+ if(prop_init(new_ctx, estimate) != SASL_OK) {
+ prop_dispose(&new_ctx);
+ }
+
+ return new_ctx;
+}
+
+/* create new propctx which duplicates the contents of an existing propctx
+ * returns -1 on error
+ */
+int prop_dup(struct propctx *src_ctx, struct propctx **dst_ctx)
+{
+ struct proppool *pool;
+ struct propctx *retval = NULL;
+ unsigned i;
+ int result;
+ unsigned total_size = 0;
+ size_t values_size;
+
+ if(!src_ctx || !dst_ctx) return SASL_BADPARAM;
+
+ /* What is the total allocated size of src_ctx? */
+ pool = src_ctx->mem_base;
+ while(pool) {
+ total_size += (unsigned) pool->size;
+ pool = pool->next;
+ }
+
+ /* allocate the new context */
+ retval = prop_new(total_size);
+ if(!retval) return SASL_NOMEM;
+
+ retval->used_values = src_ctx->used_values;
+ retval->allocated_values = src_ctx->used_values + 1;
+
+ values_size = (retval->allocated_values * sizeof(struct propval));
+
+ retval->mem_base->unused = retval->mem_base->size - values_size;
+
+ retval->list_end = (char **)(retval->mem_base->data + values_size);
+ /* data_end should still be OK */
+
+ /* Now dup the values */
+ for(i=0; i<src_ctx->used_values; i++) {
+ retval->values[i].name = src_ctx->values[i].name;
+ result = prop_setvals(retval, retval->values[i].name,
+ src_ctx->values[i].values);
+ if(result != SASL_OK)
+ goto fail;
+ }
+
+ retval->prev_val = src_ctx->prev_val;
+
+ *dst_ctx = retval;
+ return SASL_OK;
+
+ fail:
+ if(retval) prop_dispose(&retval);
+ return result;
+}
+
+/*
+ * dispose of property context
+ * ctx -- is disposed and set to NULL; noop if ctx or *ctx is NULL
+ */
+void prop_dispose(struct propctx **ctx)
+{
+ struct proppool *tmp;
+
+ if(!ctx || !*ctx) return;
+
+ while((*ctx)->mem_base) {
+ tmp = (*ctx)->mem_base;
+ (*ctx)->mem_base = tmp->next;
+ sasl_FREE(tmp);
+ }
+
+ sasl_FREE(*ctx);
+ *ctx = NULL;
+
+ return;
+}
+
+/* Add property names to request
+ * ctx -- context from prop_new()
+ * names -- list of property names; must persist until context freed
+ * or requests cleared
+ *
+ * NOTE: may clear values from context as side-effect
+ * returns -1 on error
+ */
+int prop_request(struct propctx *ctx, const char **names)
+{
+ unsigned i, new_values, total_values;
+
+ if(!ctx || !names) return SASL_BADPARAM;
+
+ /* Count how many we need to add */
+ for(new_values=0; names[new_values]; new_values++);
+
+ /* Do we need to add ANY? */
+ if(!new_values) return SASL_OK;
+
+ /* We always want at least one extra to mark the end of the array */
+ total_values = new_values + ctx->used_values + 1;
+
+ /* Do we need to increase the size of our propval table? */
+ if(total_values > ctx->allocated_values) {
+ unsigned max_in_pool;
+
+ /* Do we need a larger base pool? */
+ max_in_pool = (unsigned) (ctx->mem_base->size / sizeof(struct propval));
+
+ if(total_values <= max_in_pool) {
+ /* Don't increase the size of the base pool, just use what
+ we need */
+ ctx->allocated_values = total_values;
+ ctx->mem_base->unused =
+ ctx->mem_base->size - (sizeof(struct propval)
+ * ctx->allocated_values);
+ } else {
+ /* We need to allocate more! */
+ unsigned new_alloc_length;
+ size_t new_size;
+
+ new_alloc_length = 2 * ctx->allocated_values;
+ while(total_values > new_alloc_length) {
+ new_alloc_length *= 2;
+ }
+
+ new_size = new_alloc_length * sizeof(struct propval);
+ ctx->mem_base = resize_proppool(ctx->mem_base, new_size);
+
+ if(!ctx->mem_base) {
+ ctx->values = NULL;
+ ctx->allocated_values = ctx->used_values = 0;
+ return SASL_NOMEM;
+ }
+
+ /* It worked! Update the structure! */
+ ctx->values = (struct propval *)ctx->mem_base->data;
+ ctx->allocated_values = new_alloc_length;
+ ctx->mem_base->unused = ctx->mem_base->size
+ - sizeof(struct propval) * ctx->allocated_values;
+ }
+
+ /* Clear out new propvals */
+ memset(&(ctx->values[ctx->used_values]), 0,
+ sizeof(struct propval) * (ctx->allocated_values - ctx->used_values));
+
+ /* Finish updating the context -- we've extended the list! */
+ /* ctx->list_end = (char **)(ctx->values + ctx->allocated_values); */
+ /* xxx test here */
+ ctx->list_end = (char **)(ctx->values + total_values);
+ }
+
+ /* Now do the copy, or referencing rather */
+ for(i=0;i<new_values;i++) {
+ unsigned j, flag;
+
+ flag = 0;
+
+ /* Check for dups */
+ for(j=0;j<ctx->used_values;j++) {
+ if(!strcmp(ctx->values[j].name, names[i])) {
+ flag = 1;
+ break;
+ }
+ }
+
+ /* We already have it... skip! */
+ if(flag) continue;
+
+ ctx->values[ctx->used_values++].name = names[i];
+ }
+
+ prop_clear(ctx, 0);
+
+ return SASL_OK;
+}
+
+/* return array of struct propval from the context
+ * return value persists until next call to
+ * prop_request, prop_clear or prop_dispose on context
+ */
+const struct propval *prop_get(struct propctx *ctx)
+{
+ if(!ctx) return NULL;
+
+ return ctx->values;
+}
+
+/* Fill in an array of struct propval based on a list of property names
+ * return value persists until next call to
+ * prop_request, prop_clear or prop_dispose on context
+ * returns -1 on error (no properties ever requested, ctx NULL, etc)
+ * returns number of matching properties which were found (values != NULL)
+ * if a name requested here was never requested by a prop_request, then
+ * the name field of the associated vals entry will be set to NULL
+ */
+int prop_getnames(struct propctx *ctx, const char **names,
+ struct propval *vals)
+{
+ int found_names = 0;
+
+ struct propval *cur = vals;
+ const char **curname;
+
+ if(!ctx || !names || !vals) return SASL_BADPARAM;
+
+ for(curname = names; *curname; curname++) {
+ struct propval *val;
+ for(val = ctx->values; val->name; val++) {
+ if(!strcmp(*curname,val->name)) {
+ found_names++;
+ memcpy(cur, val, sizeof(struct propval));
+ goto next;
+ }
+ }
+
+ /* If we are here, we didn't find it */
+ memset(cur, 0, sizeof(struct propval));
+
+ next:
+ cur++;
+ }
+
+ return found_names;
+}
+
+
+/* clear values and optionally requests from property context
+ * ctx -- property context
+ * requests -- 0 = don't clear requests, 1 = clear requests
+ */
+void prop_clear(struct propctx *ctx, int requests)
+{
+ struct proppool *new_pool, *tmp;
+ unsigned i;
+
+ /* We're going to need a new proppool once we reset things */
+ new_pool = alloc_proppool(ctx->mem_base->size +
+ (ctx->used_values+1) * sizeof(struct propval));
+ if (new_pool == NULL) {
+ _sasl_log(NULL, SASL_LOG_ERR, "failed to allocate memory\n");
+ exit(1);
+ }
+
+ if(requests) {
+ /* We're wiping the whole shebang */
+ ctx->used_values = 0;
+ } else {
+ /* Need to keep around old requets */
+ struct propval *new_values = (struct propval *)new_pool->data;
+ for(i=0; i<ctx->used_values; i++) {
+ new_values[i].name = ctx->values[i].name;
+ }
+ }
+
+ while(ctx->mem_base) {
+ tmp = ctx->mem_base;
+ ctx->mem_base = tmp->next;
+ sasl_FREE(tmp);
+ }
+
+ /* Update allocation-related metadata */
+ ctx->allocated_values = ctx->used_values+1;
+ new_pool->unused =
+ new_pool->size - (ctx->allocated_values * sizeof(struct propval));
+
+ /* Setup pointers for the values array */
+ ctx->values = (struct propval *)new_pool->data;
+ ctx->prev_val = NULL;
+
+ /* Setup the pools */
+ ctx->mem_base = ctx->mem_cur = new_pool;
+
+ /* Reset list_end and data_end for the new memory pool */
+ ctx->list_end =
+ (char **)((char *)ctx->mem_base->data + ctx->allocated_values * sizeof(struct propval));
+ ctx->data_end = (char *)ctx->mem_base->data + ctx->mem_base->size;
+
+ return;
+}
+
+/*
+ * erase the value of a property
+ */
+void prop_erase(struct propctx *ctx, const char *name)
+{
+ struct propval *val;
+ int i;
+
+ if(!ctx || !name) return;
+
+ for(val = ctx->values; val->name; val++) {
+ if(!strcmp(name,val->name)) {
+ if(!val->values) break;
+
+ /*
+ * Yes, this is casting away the const, but
+ * we should be okay because the only place this
+ * memory should be is in the proppool's
+ */
+ for(i=0;val->values[i];i++) {
+ memset((void *)(val->values[i]),0,strlen(val->values[i]));
+ val->values[i] = NULL;
+ }
+
+ val->values = NULL;
+ val->nvalues = 0;
+ val->valsize = 0;
+ break;
+ }
+ }
+
+ return;
+}
+
+/****fetcher interfaces****/
+
+/* format the requested property names into a string
+ * ctx -- context from prop_new()/prop_request()
+ * sep -- separator between property names (unused if none requested)
+ * seplen -- length of separator, if < 0 then strlen(sep) will be used
+ * outbuf -- output buffer
+ * outmax -- maximum length of output buffer including NUL terminator
+ * outlen -- set to length of output string excluding NUL terminator
+ * returns 0 on success and amount of additional space needed on failure
+ */
+int prop_format(struct propctx *ctx, const char *sep, int seplen,
+ char *outbuf, unsigned outmax, unsigned *outlen)
+{
+ unsigned needed, flag = 0;
+ struct propval *val;
+
+ if (!ctx || !outbuf) return SASL_BADPARAM;
+
+ if (!sep) seplen = 0;
+ if (seplen < 0) seplen = (int) strlen(sep);
+/* If seplen is negative now we have overflow.
+ But if you have a string longer than 2Gb, you are an idiot anyway */
+ if (seplen < 0) return SASL_BADPARAM;
+
+ needed = seplen * (ctx->used_values - 1);
+ for(val = ctx->values; val->name; val++) {
+ needed += (unsigned) strlen(val->name);
+ }
+
+ if(!outmax) return (needed + 1); /* Because of unsigned funkiness */
+ if(needed > (outmax - 1)) return (needed - (outmax - 1));
+
+ *outbuf = '\0';
+ if(outlen) *outlen = needed;
+
+ if(needed == 0) return SASL_OK;
+
+ for(val = ctx->values; val->name; val++) {
+ if(seplen && flag) {
+ strncat(outbuf, sep, seplen);
+ } else {
+ flag = 1;
+ }
+ strcat(outbuf, val->name);
+ }
+
+ return SASL_OK;
+}
+
+/* add a property value to the context
+ * ctx -- context from prop_new()/prop_request()
+ * name -- name of property to which value will be added
+ * if NULL, add to the same name as previous prop_set/setvals call
+ * value -- a value for the property; will be copied into context
+ * if NULL, remove existing values
+ * vallen -- length of value, if <= 0 then strlen(value) will be used
+ */
+int prop_set(struct propctx *ctx, const char *name,
+ const char *value, int vallen)
+{
+ struct propval *cur;
+
+ if(!ctx) return SASL_BADPARAM;
+ if(!name && !ctx->prev_val) return SASL_BADPARAM;
+
+ if(name) {
+ struct propval *val;
+
+ ctx->prev_val = NULL;
+
+ for(val = ctx->values; val->name; val++) {
+ if(!strcmp(name,val->name)){
+ ctx->prev_val = val;
+ break;
+ }
+ }
+
+ /* Couldn't find it! */
+ if(!ctx->prev_val) return SASL_BADPARAM;
+ }
+
+ cur = ctx->prev_val;
+
+ if(name) /* New Entry */ {
+ unsigned nvalues = 1; /* 1 for NULL entry */
+ const char **old_values = NULL;
+ char **tmp, **tmp2;
+ size_t size;
+
+ if(cur->values) {
+
+ if(!value) {
+ /* If we would be adding a null value, then we are done */
+ return SASL_OK;
+ }
+
+ old_values = cur->values;
+ tmp = (char **)cur->values;
+ while(*tmp) {
+ nvalues++;
+ tmp++;
+ }
+
+ }
+
+ if(value) {
+ nvalues++; /* for the new value */
+ }
+
+ size = nvalues * sizeof(char*);
+
+ if(size > ctx->mem_cur->unused) {
+ size_t needed;
+
+ for(needed = ctx->mem_cur->size * 2; needed < size; needed *= 2);
+
+ /* Allocate a new proppool */
+ ctx->mem_cur->next = alloc_proppool(needed);
+ if(!ctx->mem_cur->next) return SASL_NOMEM;
+
+ ctx->mem_cur = ctx->mem_cur->next;
+
+ ctx->list_end = (char **)ctx->mem_cur->data;
+ ctx->data_end = ctx->mem_cur->data + needed;
+ }
+
+ /* Grab the memory */
+ ctx->mem_cur->unused -= size;
+ cur->values = (const char **)ctx->list_end;
+ cur->values[nvalues - 1] = NULL;
+
+ /* Finish updating the context */
+ ctx->list_end = (char **)(cur->values + nvalues);
+
+ /* If we don't have an actual value to fill in, we are done */
+ if(!value)
+ return SASL_OK;
+
+ tmp2 = (char **)cur->values;
+ if(old_values) {
+ tmp = (char **)old_values;
+
+ while(*tmp) {
+ *tmp2 = *tmp;
+ tmp++; tmp2++;
+ }
+ }
+
+ /* Now allocate the last entry */
+ if(vallen <= 0)
+ size = (size_t)(strlen(value) + 1);
+ else
+ size = (size_t)(vallen + 1);
+
+ if(size > ctx->mem_cur->unused) {
+ size_t needed;
+
+ needed = ctx->mem_cur->size * 2;
+
+ while(needed < size) {
+ needed *= 2;
+ }
+
+ /* Allocate a new proppool */
+ ctx->mem_cur->next = alloc_proppool(needed);
+ if(!ctx->mem_cur->next) return SASL_NOMEM;
+
+ ctx->mem_cur = ctx->mem_cur->next;
+ ctx->list_end = (char **)ctx->mem_cur->data;
+ ctx->data_end = ctx->mem_cur->data + needed;
+ }
+
+ /* Update the data_end pointer */
+ ctx->data_end -= size;
+ ctx->mem_cur->unused -= size;
+
+ /* Copy and setup the new value! */
+ memcpy(ctx->data_end, value, size-1);
+ ctx->data_end[size - 1] = '\0';
+ cur->values[nvalues - 2] = ctx->data_end;
+
+ cur->nvalues++;
+ cur->valsize += ((unsigned) size - 1);
+ } else /* Appending an entry */ {
+ char **tmp;
+ size_t size;
+
+ /* If we are setting it to be NULL, we are done */
+ if(!value) return SASL_OK;
+
+ size = sizeof(char*);
+
+ /* Is it in the current pool, and will it fit in the unused space? */
+ if(size > ctx->mem_cur->unused &&
+ (void *)cur->values > (void *)(ctx->mem_cur->data) &&
+ (void *)cur->values < (void *)(ctx->mem_cur->data + ctx->mem_cur->size)) {
+ /* recursively call the not-fast way */
+ return prop_set(ctx, cur->name, value, vallen);
+ }
+
+ /* Note the invariant: the previous value list must be
+ at the top of the CURRENT pool at this point */
+
+ /* Grab the memory */
+ ctx->mem_cur->unused -= size;
+ ctx->list_end++;
+
+ *(ctx->list_end - 1) = NULL;
+ tmp = (ctx->list_end - 2);
+
+ /* Now allocate the last entry */
+ if(vallen <= 0)
+ size = strlen(value) + 1;
+ else
+ size = vallen + 1;
+
+ if(size > ctx->mem_cur->unused) {
+ size_t needed;
+
+ needed = ctx->mem_cur->size * 2;
+
+ while(needed < size) {
+ needed *= 2;
+ }
+
+ /* Allocate a new proppool */
+ ctx->mem_cur->next = alloc_proppool(needed);
+ if(!ctx->mem_cur->next) return SASL_NOMEM;
+
+ ctx->mem_cur = ctx->mem_cur->next;
+ ctx->list_end = (char **)ctx->mem_cur->data;
+ ctx->data_end = ctx->mem_cur->data + needed;
+ }
+
+ /* Update the data_end pointer */
+ ctx->data_end -= size;
+ ctx->mem_cur->unused -= size;
+
+ /* Copy and setup the new value! */
+ memcpy(ctx->data_end, value, size-1);
+ ctx->data_end[size - 1] = '\0';
+ *tmp = ctx->data_end;
+
+ cur->nvalues++;
+ cur->valsize += ((unsigned) size - 1);
+ }
+
+ return SASL_OK;
+}
+
+
+/* set the values for a property
+ * ctx -- context from prop_new()/prop_request()
+ * name -- name of property to which value will be added
+ * if NULL, add to the same name as previous prop_set/setvals call
+ * values -- array of values, ending in NULL. Each value is a NUL terminated
+ * string
+ */
+int prop_setvals(struct propctx *ctx, const char *name,
+ const char **values)
+{
+ const char **val = values;
+ int result = SASL_OK;
+
+ if(!ctx) return SASL_BADPARAM;
+
+ /* If they want us to add no values, we can do that */
+ if(!values) return SASL_OK;
+
+ /* Basically, use prop_set to do all our dirty work for us */
+ if(name) {
+ result = prop_set(ctx, name, *val, 0);
+ val++;
+ }
+
+ for(;*val;val++) {
+ if(result != SASL_OK) return result;
+ result = prop_set(ctx, NULL, *val,0);
+ }
+
+ return result;
+}
+
+/* Request a set of auxiliary properties
+ * conn connection context
+ * propnames list of auxiliary property names to request ending with
+ * NULL.
+ *
+ * Subsequent calls will add items to the request list. Call with NULL
+ * to clear the request list.
+ *
+ * errors
+ * SASL_OK -- success
+ * SASL_BADPARAM -- bad count/conn parameter
+ * SASL_NOMEM -- out of memory
+ */
+int sasl_auxprop_request(sasl_conn_t *conn, const char **propnames)
+{
+ int result;
+ sasl_server_conn_t *sconn;
+
+ if(!conn) return SASL_BADPARAM;
+ if(conn->type != SASL_CONN_SERVER)
+ PARAMERROR(conn);
+
+ sconn = (sasl_server_conn_t *)conn;
+
+ if(!propnames) {
+ prop_clear(sconn->sparams->propctx,1);
+ return SASL_OK;
+ }
+
+ result = prop_request(sconn->sparams->propctx, propnames);
+ RETURN(conn, result);
+}
+
+
+/* Returns current auxiliary property context.
+ * Use functions in prop.h to access content
+ *
+ * if authentication hasn't completed, property values may be empty/NULL
+ *
+ * properties not recognized by active plug-ins will be left empty/NULL
+ *
+ * returns NULL if conn is invalid.
+ */
+struct propctx *sasl_auxprop_getctx(sasl_conn_t *conn)
+{
+ sasl_server_conn_t *sconn;
+
+ if(!conn || conn->type != SASL_CONN_SERVER) return NULL;
+
+ sconn = (sasl_server_conn_t *)conn;
+
+ return sconn->sparams->propctx;
+}
+
+/* add an auxiliary property plugin */
+int sasl_auxprop_add_plugin(const char *plugname,
+ sasl_auxprop_init_t *auxpropfunc)
+{
+ int result, out_version;
+ auxprop_plug_list_t *new_item;
+ sasl_auxprop_plug_t *plug;
+
+ result = auxpropfunc(sasl_global_utils, SASL_AUXPROP_PLUG_VERSION,
+ &out_version, &plug, plugname);
+
+ /* Check if out_version is too old.
+ We only support the current at the moment */
+ if (result == SASL_OK && out_version < SASL_AUXPROP_PLUG_VERSION) {
+ result = SASL_BADVERS;
+ }
+
+ if(result != SASL_OK) {
+ _sasl_log(NULL, SASL_LOG_ERR, "auxpropfunc error %s\n",
+ sasl_errstring(result, NULL, NULL));
+ return result;
+ }
+
+ /* We require that this function is implemented */
+ if(!plug->auxprop_lookup) return SASL_BADPROT;
+
+ new_item = sasl_ALLOC(sizeof(auxprop_plug_list_t));
+ if(!new_item) return SASL_NOMEM;
+
+ /* These will load from least-important to most important */
+ new_item->plug = plug;
+ new_item->next = auxprop_head;
+ auxprop_head = new_item;
+
+ return SASL_OK;
+}
+
+void _sasl_auxprop_free()
+{
+ auxprop_plug_list_t *ptr, *ptr_next;
+
+ for(ptr = auxprop_head; ptr; ptr = ptr_next) {
+ ptr_next = ptr->next;
+ if(ptr->plug->auxprop_free)
+ ptr->plug->auxprop_free(ptr->plug->glob_context,
+ sasl_global_utils);
+ sasl_FREE(ptr);
+ }
+
+ auxprop_head = NULL;
+}
+
+/* Return the updated account status based on the current ("so far") and
+ the specific status returned by the latest auxprop call */
+static int
+_sasl_account_status (int current_status,
+ int specific_status)
+{
+ switch (specific_status) {
+ case SASL_NOVERIFY:
+ specific_status = SASL_OK;
+ /* fall through */
+ case SASL_OK:
+ if (current_status == SASL_NOMECH ||
+ current_status == SASL_NOUSER) {
+ current_status = specific_status;
+ }
+ break;
+
+ case SASL_NOUSER:
+ if (current_status == SASL_NOMECH) {
+ current_status = specific_status;
+ }
+ break;
+
+ /* NOTE: The disabled flag sticks, unless we hit an error */
+ case SASL_DISABLED:
+ if (current_status == SASL_NOMECH ||
+ current_status == SASL_NOUSER ||
+ current_status == SASL_OK) {
+ current_status = specific_status;
+ }
+ break;
+
+ case SASL_NOMECH:
+ /* ignore */
+ break;
+
+ /* SASL_UNAVAIL overrides everything */
+ case SASL_UNAVAIL:
+ current_status = specific_status;
+ break;
+
+ default:
+ current_status = specific_status;
+ break;
+ }
+ return (current_status);
+}
+
+/* Do the callbacks for auxprop lookups */
+int _sasl_auxprop_lookup(sasl_server_params_t *sparams,
+ unsigned flags,
+ const char *user, unsigned ulen)
+{
+ sasl_getopt_t *getopt;
+ int ret, found = 0;
+ void *context;
+ const char *plist = NULL;
+ auxprop_plug_list_t *ptr;
+ int result = SASL_NOMECH;
+
+ if(_sasl_getcallback(sparams->utils->conn,
+ SASL_CB_GETOPT,
+ (sasl_callback_ft *)&getopt,
+ &context) == SASL_OK) {
+ ret = getopt(context, NULL, "auxprop_plugin", &plist, NULL);
+ if(ret != SASL_OK) plist = NULL;
+ }
+
+ if(!plist) {
+ /* Do lookup in all plugins */
+
+ /* TODO: Ideally, each auxprop plugin should be marked if its failure
+ should be ignored or treated as a fatal error of the whole lookup. */
+ for(ptr = auxprop_head; ptr; ptr = ptr->next) {
+ found=1;
+ ret = ptr->plug->auxprop_lookup(ptr->plug->glob_context,
+ sparams, flags, user, ulen);
+ result = _sasl_account_status (result, ret);
+ }
+ } else {
+ char *pluginlist = NULL, *freeptr = NULL, *thisplugin = NULL;
+
+ if(_sasl_strdup(plist, &pluginlist, NULL) != SASL_OK) return SASL_NOMEM;
+ thisplugin = freeptr = pluginlist;
+
+ /* Do lookup in all *specified* plugins, in order */
+ while(*thisplugin) {
+ char *p;
+ int last=0;
+
+ while(*thisplugin && isspace((int)*thisplugin)) thisplugin++;
+ if(!(*thisplugin)) break;
+
+ for(p = thisplugin;*p != '\0' && !isspace((int)*p); p++);
+ if(*p == '\0') last = 1;
+ else *p='\0';
+
+ for(ptr = auxprop_head; ptr; ptr = ptr->next) {
+ /* Skip non-matching plugins */
+ if(!ptr->plug->name
+ || strcasecmp(ptr->plug->name, thisplugin))
+ continue;
+
+ found=1;
+ ret = ptr->plug->auxprop_lookup(ptr->plug->glob_context,
+ sparams, flags, user, ulen);
+ result = _sasl_account_status (result, ret);
+ }
+
+ if(last) break;
+
+ thisplugin = p+1;
+ }
+
+ sasl_FREE(freeptr);
+ }
+
+ if(!found) {
+ _sasl_log(sparams->utils->conn, SASL_LOG_DEBUG,
+ "could not find auxprop plugin, was searching for '%s'",
+ plist ? plist : "[all]");
+ }
+
+ return result;
+}
+
+/* Do the callbacks for auxprop stores */
+int sasl_auxprop_store(sasl_conn_t *conn,
+ struct propctx *ctx, const char *user)
+{
+ sasl_getopt_t *getopt;
+ int ret;
+ void *context;
+ const char *plist = NULL;
+ auxprop_plug_list_t *ptr;
+ sasl_server_params_t *sparams = NULL;
+ unsigned userlen = 0;
+ int num_constraint_violations = 0;
+ int total_plugins = 0;
+
+ if (ctx) {
+ if (!conn || !user)
+ return SASL_BADPARAM;
+
+ sparams = ((sasl_server_conn_t *) conn)->sparams;
+ userlen = (unsigned) strlen(user);
+ }
+
+ /* Pickup getopt callback from the connection, if conn is not NULL */
+ if(_sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+ ret = getopt(context, NULL, "auxprop_plugin", &plist, NULL);
+ if(ret != SASL_OK) plist = NULL;
+ }
+
+ ret = SASL_OK;
+ if(!plist) {
+ /* Do store in all plugins */
+ for(ptr = auxprop_head; ptr && ret == SASL_OK; ptr = ptr->next) {
+ total_plugins++;
+ if (ptr->plug->auxprop_store) {
+ ret = ptr->plug->auxprop_store(ptr->plug->glob_context,
+ sparams, ctx, user, userlen);
+ if (ret == SASL_CONSTRAINT_VIOLAT) {
+ ret = SASL_OK;
+ num_constraint_violations++;
+ }
+ }
+ }
+ } else {
+ char *pluginlist = NULL, *freeptr = NULL, *thisplugin = NULL;
+
+ if(_sasl_strdup(plist, &pluginlist, NULL) != SASL_OK) return SASL_FAIL;
+ thisplugin = freeptr = pluginlist;
+
+ /* Do store in all *specified* plugins, in order */
+ while(*thisplugin) {
+ char *p;
+ int last=0;
+
+ while(*thisplugin && isspace((int)*thisplugin)) thisplugin++;
+ if(!(*thisplugin)) break;
+
+ for(p = thisplugin;*p != '\0' && !isspace((int)*p); p++);
+ if(*p == '\0') last = 1;
+ else *p='\0';
+
+ for(ptr = auxprop_head; ptr && ret == SASL_OK; ptr = ptr->next) {
+ /* Skip non-matching plugins */
+ if((!ptr->plug->name
+ || strcasecmp(ptr->plug->name, thisplugin)))
+ continue;
+
+ total_plugins++;
+ if (ptr->plug->auxprop_store) {
+ ret = ptr->plug->auxprop_store(ptr->plug->glob_context,
+ sparams, ctx, user, userlen);
+ if (ret == SASL_CONSTRAINT_VIOLAT) {
+ ret = SASL_OK;
+ num_constraint_violations++;
+ }
+ }
+ }
+
+ if(last) break;
+
+ thisplugin = p+1;
+ }
+
+ sasl_FREE(freeptr);
+ }
+
+ if(total_plugins == 0) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "could not find auxprop plugin, was searching for %s",
+ plist ? plist : "[all]");
+ return SASL_FAIL;
+ } else if (total_plugins == num_constraint_violations) {
+ ret = SASL_CONSTRAINT_VIOLAT;
+ }
+
+ return ret;
+}
+
+/* It would be nice if we can show other information like Author, Company, Year, plugin version */
+static void
+_sasl_print_mechanism (sasl_auxprop_plug_t *m,
+ sasl_info_callback_stage_t stage,
+ void *rock __attribute__((unused))
+)
+{
+ if (stage == SASL_INFO_LIST_START) {
+ printf ("List of auxprop plugins follows\n");
+ return;
+ } else if (stage == SASL_INFO_LIST_END) {
+ return;
+ }
+
+ /* Process the mechanism */
+ printf ("Plugin \"%s\" ", m->name);
+
+#ifdef NOT_YET
+ 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;
+ }
+#endif
+
+ printf (", \tAPI version: %d\n", /* m->version */ SASL_AUXPROP_PLUG_VERSION);
+
+ /* TODO - Update for auxprop_export, etc. */
+ printf ("\tsupports store: %s\n",
+ (m->auxprop_store != NULL) ? "yes" : "no"
+ );
+
+ /* No features defined yet */
+#ifdef NOT_YET
+ printf ("\n\tfeatures:");
+#endif
+
+ printf ("\n");
+}
+
+/* Dump information about available auxprop plugins (separate functions are
+ used for canon and server authentication plugins) */
+int auxprop_plugin_info (
+ const char *c_mech_list, /* space separated mechanism list or NULL for ALL */
+ auxprop_info_callback_t *info_cb,
+ void *info_cb_rock
+)
+{
+ auxprop_plug_list_t *m;
+ sasl_auxprop_plug_t plug_data;
+ char * cur_mech;
+ char *mech_list = NULL;
+ char * p;
+
+ if (info_cb == NULL) {
+ info_cb = _sasl_print_mechanism;
+ }
+
+ if (auxprop_head != NULL) {
+ info_cb (NULL, SASL_INFO_LIST_START, info_cb_rock);
+
+ if (c_mech_list == NULL) {
+ m = auxprop_head; /* m point to beginning of the list */
+
+ while (m != NULL) {
+ /* TODO: Need to be careful when dealing with auxprop_export, etc. */
+ memcpy (&plug_data, m->plug, 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 = auxprop_head; /* m point to beginning of the list */
+
+ while (m != NULL) {
+ if (strcasecmp (cur_mech, m->plug->name) == 0) {
+ memcpy (&plug_data, m->plug, 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);
+}
diff --git a/contrib/libs/sasl/lib/canonusr.c b/contrib/libs/sasl/lib/canonusr.c
new file mode 100644
index 0000000000..66f7e112a6
--- /dev/null
+++ b/contrib/libs/sasl/lib/canonusr.c
@@ -0,0 +1,465 @@
+/* canonusr.c - user canonicalization support
+ * Rob Siemborski
+ */
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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.
+ */
+
+#include <config.h>
+#include <sasl.h>
+#include <string.h>
+#include <ctype.h>
+#include <prop.h>
+#include <stdio.h>
+
+#include "saslint.h"
+
+typedef struct canonuser_plug_list
+{
+ struct canonuser_plug_list *next;
+ char name[PATH_MAX];
+ const sasl_canonuser_plug_t *plug;
+} canonuser_plug_list_t;
+
+static canonuser_plug_list_t *canonuser_head = NULL;
+
+/* default behavior:
+ * eliminate leading & trailing whitespace,
+ * null-terminate, and get into the outparams
+ * (handled by INTERNAL plugin) */
+/* a zero ulen or alen indicates that it is strlen(value) */
+int _sasl_canon_user(sasl_conn_t *conn,
+ const char *user, unsigned ulen,
+ unsigned flags,
+ sasl_out_params_t *oparams)
+{
+ canonuser_plug_list_t *ptr;
+ sasl_server_conn_t *sconn = NULL;
+ sasl_client_conn_t *cconn = NULL;
+ sasl_canon_user_t *cuser_cb;
+ sasl_getopt_t *getopt;
+ void *context;
+ int result;
+ const char *plugin_name = NULL;
+ char *user_buf;
+ unsigned *lenp;
+
+ if(!conn) return SASL_BADPARAM;
+ if(!user || !oparams) return SASL_BADPARAM;
+
+ if(flags & SASL_CU_AUTHID) {
+ user_buf = conn->authid_buf;
+ lenp = &(oparams->alen);
+ } else if (flags & SASL_CU_AUTHZID) {
+ user_buf = conn->user_buf;
+ lenp = &(oparams->ulen);
+ } else {
+ return SASL_BADPARAM;
+ }
+
+ if (conn->type == SASL_CONN_SERVER)
+ sconn = (sasl_server_conn_t *)conn;
+ else if (conn->type == SASL_CONN_CLIENT)
+ cconn = (sasl_client_conn_t *)conn;
+ else return SASL_FAIL;
+
+ if(!ulen) ulen = (unsigned int)strlen(user);
+
+ /* check to see if we have a callback to make*/
+ result = _sasl_getcallback(conn,
+ SASL_CB_CANON_USER,
+ (sasl_callback_ft *)&cuser_cb,
+ &context);
+ if(result == SASL_OK && cuser_cb) {
+ result = cuser_cb(conn,
+ context,
+ user,
+ ulen,
+ flags,
+ (sconn ?
+ sconn->user_realm :
+ NULL),
+ user_buf,
+ CANON_BUF_SIZE,
+ lenp);
+
+
+ if (result != SASL_OK) return result;
+
+ /* Point the input copy at the stored buffer */
+ user = user_buf;
+ ulen = *lenp;
+ }
+
+ /* which plugin are we supposed to use? */
+ result = _sasl_getcallback(conn,
+ SASL_CB_GETOPT,
+ (sasl_callback_ft *)&getopt,
+ &context);
+ if (result == SASL_OK && getopt) {
+ getopt(context, NULL, "canon_user_plugin", &plugin_name, NULL);
+ }
+
+ if (!plugin_name) {
+ /* Use Default */
+ plugin_name = "INTERNAL";
+ }
+
+ for (ptr = canonuser_head; ptr; ptr = ptr->next) {
+ /* A match is if we match the internal name of the plugin, or if
+ * we match the filename (old-style) */
+ if ((ptr->plug->name && !strcmp(plugin_name, ptr->plug->name))
+ || !strcmp(plugin_name, ptr->name)) break;
+ }
+
+ /* We clearly don't have this one! */
+ if (!ptr) {
+ sasl_seterror(conn, 0, "desired canon_user plugin %s not found",
+ plugin_name);
+ return SASL_NOMECH;
+ }
+
+ if (sconn) {
+ /* we're a server */
+ result = ptr->plug->canon_user_server(ptr->plug->glob_context,
+ sconn->sparams,
+ user, ulen,
+ flags,
+ user_buf,
+ CANON_BUF_SIZE, lenp);
+ } else {
+ /* we're a client */
+ result = ptr->plug->canon_user_client(ptr->plug->glob_context,
+ cconn->cparams,
+ user, ulen,
+ flags,
+ user_buf,
+ CANON_BUF_SIZE, lenp);
+ }
+
+ if (result != SASL_OK) return result;
+
+ if ((flags & SASL_CU_AUTHID) && (flags & SASL_CU_AUTHZID)) {
+ /* We did both, so we need to copy the result into
+ * the buffer for the authzid from the buffer for the authid */
+ memcpy(conn->user_buf, conn->authid_buf, CANON_BUF_SIZE);
+ oparams->ulen = oparams->alen;
+ }
+
+ /* Set the appropriate oparams (lengths have already been set by lenp) */
+ if (flags & SASL_CU_AUTHID) {
+ oparams->authid = conn->authid_buf;
+ }
+
+ if (flags & SASL_CU_AUTHZID) {
+ oparams->user = conn->user_buf;
+ }
+
+ RETURN(conn, result);
+}
+
+/* Lookup all properties for authentication and/or authorization identity. */
+static int _sasl_auxprop_lookup_user_props (sasl_conn_t *conn,
+ unsigned flags,
+ sasl_out_params_t *oparams)
+{
+ sasl_server_conn_t *sconn = NULL;
+ int result = SASL_OK;
+
+ if (!conn) return SASL_BADPARAM;
+ if (!oparams) return SASL_BADPARAM;
+
+#ifndef macintosh
+ if (conn->type == SASL_CONN_SERVER) sconn = (sasl_server_conn_t *)conn;
+
+ /* do auxprop lookups (server only) */
+ if (sconn) {
+ int authz_result;
+ unsigned auxprop_lookup_flags = flags & SASL_CU_ASIS_MASK;
+
+ if (flags & SASL_CU_OVERRIDE) {
+ auxprop_lookup_flags |= SASL_AUXPROP_OVERRIDE;
+ }
+
+ if (flags & SASL_CU_AUTHID) {
+ result = _sasl_auxprop_lookup(sconn->sparams,
+ auxprop_lookup_flags,
+ oparams->authid,
+ oparams->alen);
+ } else {
+ result = SASL_CONTINUE;
+ }
+ if (flags & SASL_CU_AUTHZID) {
+ authz_result = _sasl_auxprop_lookup(sconn->sparams,
+ auxprop_lookup_flags | SASL_AUXPROP_AUTHZID,
+ oparams->user,
+ oparams->ulen);
+
+ if (result == SASL_CONTINUE) {
+ /* Only SASL_CU_AUTHZID was requested.
+ The authz_result value is authoritative. */
+ result = authz_result;
+ } else if (result == SASL_OK && authz_result != SASL_NOUSER) {
+ /* Use the authz_result value, unless "result"
+ already contains an error */
+ result = authz_result;
+ }
+ }
+
+ if ((flags & SASL_CU_EXTERNALLY_VERIFIED) && (result == SASL_NOUSER || result == SASL_NOMECH)) {
+ /* The called has explicitly told us that the authentication identity
+ was already verified or will be verified independently.
+ So a failure to retrieve any associated properties
+ is not an error. For example the caller is using Kerberos to verify user,
+ but the LDAPDB/SASLDB auxprop plugin doesn't contain any auxprops for
+ the user.
+ Another case is PLAIN/LOGIN not using auxprop to verify user passwords. */
+ result = SASL_OK;
+ }
+ }
+#endif
+
+ RETURN(conn, result);
+}
+
+/* default behavior:
+ * Eliminate leading & trailing whitespace,
+ * null-terminate, and get into the outparams
+ * (handled by INTERNAL plugin).
+ *
+ * Server only: Also does auxprop lookups once username
+ * is canonicalized. */
+int _sasl_canon_user_lookup (sasl_conn_t *conn,
+ const char *user,
+ unsigned ulen,
+ unsigned flags,
+ sasl_out_params_t *oparams)
+{
+ int result;
+
+ result = _sasl_canon_user (conn,
+ user,
+ ulen,
+ flags,
+ oparams);
+ if (result == SASL_OK) {
+ result = _sasl_auxprop_lookup_user_props (conn,
+ flags,
+ oparams);
+ }
+
+ RETURN(conn, result);
+}
+
+void _sasl_canonuser_free()
+{
+ canonuser_plug_list_t *ptr, *ptr_next;
+
+ for(ptr = canonuser_head; ptr; ptr = ptr_next) {
+ ptr_next = ptr->next;
+ if(ptr->plug->canon_user_free)
+ ptr->plug->canon_user_free(ptr->plug->glob_context,
+ sasl_global_utils);
+ sasl_FREE(ptr);
+ }
+
+ canonuser_head = NULL;
+}
+
+int sasl_canonuser_add_plugin(const char *plugname,
+ sasl_canonuser_init_t *canonuserfunc)
+{
+ int result, out_version;
+ canonuser_plug_list_t *new_item;
+ sasl_canonuser_plug_t *plug;
+
+ if(!plugname || strlen(plugname) > (PATH_MAX - 1)) {
+ sasl_seterror(NULL, 0,
+ "bad plugname passed to sasl_canonuser_add_plugin\n");
+ return SASL_BADPARAM;
+ }
+
+ result = canonuserfunc(sasl_global_utils, SASL_CANONUSER_PLUG_VERSION,
+ &out_version, &plug, plugname);
+
+ if(result != SASL_OK) {
+ _sasl_log(NULL, SASL_LOG_ERR, "%s_canonuser_plug_init() failed in sasl_canonuser_add_plugin(): %z\n",
+ plugname, result);
+ return result;
+ }
+
+ if(!plug->canon_user_server && !plug->canon_user_client) {
+ /* We need at least one of these implemented */
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "canonuser plugin '%s' without either client or server side", plugname);
+ return SASL_BADPROT;
+ }
+
+ new_item = sasl_ALLOC(sizeof(canonuser_plug_list_t));
+ if(!new_item) return SASL_NOMEM;
+
+ strncpy(new_item->name, plugname, PATH_MAX - 1);
+ new_item->name[strlen(plugname)] = '\0';
+
+ new_item->plug = plug;
+ new_item->next = canonuser_head;
+ canonuser_head = new_item;
+
+ return SASL_OK;
+}
+
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN(a,b) (((a) < (b))? (a):(b))
+
+static int _canonuser_internal(const sasl_utils_t *utils,
+ const char *user, unsigned ulen,
+ unsigned flags __attribute__((unused)),
+ char *out_user,
+ unsigned out_umax, unsigned *out_ulen)
+{
+ unsigned i;
+ char *in_buf, *userin;
+ const char *begin_u;
+ unsigned u_apprealm = 0;
+ sasl_server_conn_t *sconn = NULL;
+
+ if(!utils || !user) return SASL_BADPARAM;
+
+ in_buf = sasl_ALLOC((ulen + 2) * sizeof(char));
+ if(!in_buf) return SASL_NOMEM;
+
+ userin = in_buf;
+
+ memcpy(userin, user, ulen);
+ userin[ulen] = '\0';
+
+ /* Strip User ID */
+ for(i=0;isspace((int)userin[i]) && i<ulen;i++);
+ begin_u = &(userin[i]);
+ if(i>0) ulen -= i;
+
+ for(;ulen > 0 && isspace((int)begin_u[ulen-1]); ulen--);
+ if(begin_u == &(userin[ulen])) {
+ sasl_FREE(in_buf);
+ utils->seterror(utils->conn, 0, "All-whitespace username.");
+ return SASL_FAIL;
+ }
+
+ if(utils->conn && utils->conn->type == SASL_CONN_SERVER)
+ sconn = (sasl_server_conn_t *)utils->conn;
+
+ /* Need to append realm if necessary (see sasl.h) */
+ if(sconn && sconn->user_realm && !strchr(user, '@')) {
+ u_apprealm = (unsigned) strlen(sconn->user_realm) + 1;
+ }
+
+ /* Now Copy */
+ memcpy(out_user, begin_u, MIN(ulen, out_umax));
+ if(sconn && u_apprealm) {
+ if(ulen >= out_umax) return SASL_BUFOVER;
+ out_user[ulen] = '@';
+ memcpy(&(out_user[ulen+1]), sconn->user_realm,
+ MIN(u_apprealm-1, out_umax-ulen-1));
+ }
+ out_user[MIN(ulen + u_apprealm,out_umax)] = '\0';
+
+ if(ulen + u_apprealm > out_umax) return SASL_BUFOVER;
+
+ if(out_ulen) *out_ulen = MIN(ulen + u_apprealm,out_umax);
+
+ sasl_FREE(in_buf);
+ return SASL_OK;
+}
+
+static int _cu_internal_server(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *user, unsigned ulen,
+ unsigned flags,
+ char *out_user,
+ unsigned out_umax, unsigned *out_ulen)
+{
+ return _canonuser_internal(sparams->utils,
+ user, ulen,
+ flags, out_user, out_umax, out_ulen);
+}
+
+static int _cu_internal_client(void *glob_context __attribute__((unused)),
+ sasl_client_params_t *cparams,
+ const char *user, unsigned ulen,
+ unsigned flags,
+ char *out_user,
+ unsigned out_umax, unsigned *out_ulen)
+{
+ return _canonuser_internal(cparams->utils,
+ user, ulen,
+ flags, out_user, out_umax, out_ulen);
+}
+
+static sasl_canonuser_plug_t canonuser_internal_plugin = {
+ 0, /* features */
+ 0, /* spare */
+ NULL, /* glob_context */
+ "INTERNAL", /* name */
+ NULL, /* canon_user_free */
+ _cu_internal_server,
+ _cu_internal_client,
+ NULL,
+ NULL,
+ NULL
+};
+
+int internal_canonuser_init(const sasl_utils_t *utils __attribute__((unused)),
+ int max_version,
+ int *out_version,
+ sasl_canonuser_plug_t **plug,
+ const char *plugname __attribute__((unused)))
+{
+ if(!out_version || !plug) return SASL_BADPARAM;
+
+ if(max_version < SASL_CANONUSER_PLUG_VERSION) return SASL_BADVERS;
+
+ *out_version = SASL_CANONUSER_PLUG_VERSION;
+
+ *plug = &canonuser_internal_plugin;
+
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/lib/checkpw.c b/contrib/libs/sasl/lib/checkpw.c
new file mode 100644
index 0000000000..a13f526b7c
--- /dev/null
+++ b/contrib/libs/sasl/lib/checkpw.c
@@ -0,0 +1,1110 @@
+/* SASL server API implementation
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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.
+ */
+
+#include <config.h>
+
+/* checkpw stuff */
+
+#include <stdio.h>
+#include "sasl.h"
+#include "saslutil.h"
+#include "saslplug.h"
+#include "saslint.h"
+
+#include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#ifdef USE_DOORS
+#include <sys/mman.h>
+#error #include <door.h>
+#endif
+
+#include <stdlib.h>
+
+#ifndef WIN32
+#include <strings.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#else
+#include <string.h>
+#endif
+
+#include <limits.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif /* HAVE_PWD_H */
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif /* HAVE_SHADOW_H */
+
+#if defined(HAVE_PWCHECK) || defined(HAVE_SASLAUTHD) || defined(HAVE_AUTHDAEMON)
+# include <errno.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/un.h>
+# ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+#endif
+
+
+/* we store the following secret to check plaintext passwords:
+ *
+ * <salt> \0 <secret>
+ *
+ * where <secret> = MD5(<salt>, "sasldb", <pass>)
+ */
+static int _sasl_make_plain_secret(const char *salt,
+ const char *passwd, size_t passlen,
+ sasl_secret_t **secret)
+{
+ MD5_CTX ctx;
+ unsigned sec_len = 16 + 1 + 16; /* salt + "\0" + hash */
+
+ *secret = (sasl_secret_t *) sasl_ALLOC(sizeof(sasl_secret_t) +
+ sec_len * sizeof(char));
+ if (*secret == NULL) {
+ return SASL_NOMEM;
+ }
+
+ _sasl_MD5Init(&ctx);
+ _sasl_MD5Update(&ctx, (const unsigned char *) salt, 16);
+ _sasl_MD5Update(&ctx, (const unsigned char *) "sasldb", 6);
+ _sasl_MD5Update(&ctx, (const unsigned char *) passwd, (unsigned int) passlen);
+ memcpy((*secret)->data, salt, 16);
+ (*secret)->data[16] = '\0';
+ _sasl_MD5Final((*secret)->data + 17, &ctx);
+ (*secret)->len = sec_len;
+
+ return SASL_OK;
+}
+
+/* verify user password using auxprop plugins
+ */
+static int auxprop_verify_password(sasl_conn_t *conn,
+ const char *userstr,
+ const char *passwd,
+ const char *service __attribute__((unused)),
+ const char *user_realm __attribute__((unused)))
+{
+ int ret = SASL_FAIL;
+ int result = SASL_OK;
+ sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
+ const char *password_request[] = { SASL_AUX_PASSWORD,
+ "*cmusaslsecretPLAIN",
+ NULL };
+ struct propval auxprop_values[3];
+
+ if (!conn || !userstr)
+ return SASL_BADPARAM;
+
+ /* We need to clear any previous results and re-canonify to
+ * ensure correctness */
+
+ prop_clear (sconn->sparams->propctx, 0);
+
+ /* ensure its requested */
+ result = prop_request(sconn->sparams->propctx, password_request);
+
+ if(result != SASL_OK) return result;
+
+ result = _sasl_canon_user_lookup (conn,
+ userstr,
+ 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID,
+ &(conn->oparams));
+ if(result != SASL_OK) return result;
+
+ result = prop_getnames(sconn->sparams->propctx, password_request,
+ auxprop_values);
+ if (result < 0) {
+ return result;
+ }
+
+ /* Verify that the returned <name>s are correct.
+ But we defer checking for NULL values till after we verify
+ that a passwd is specified. */
+ if (!auxprop_values[0].name && !auxprop_values[1].name) {
+ return SASL_NOUSER;
+ }
+
+ /* It is possible for us to get useful information out of just
+ * the lookup, so we won't check that we have a password until now */
+ if(!passwd) {
+ ret = SASL_BADPARAM;
+ goto done;
+ }
+
+ if ((!auxprop_values[0].values || !auxprop_values[0].values[0])
+ && (!auxprop_values[1].values || !auxprop_values[1].values[0])) {
+ return SASL_NOUSER;
+ }
+
+ /* At the point this has been called, the username has been canonified
+ * and we've done the auxprop lookup. This should be easy. */
+ if(auxprop_values[0].name
+ && auxprop_values[0].values
+ && auxprop_values[0].values[0]
+ && !strcmp(auxprop_values[0].values[0], passwd)) {
+ /* We have a plaintext version and it matched! */
+ return SASL_OK;
+ } else if(auxprop_values[1].name
+ && auxprop_values[1].values
+ && auxprop_values[1].values[0]) {
+ const char *db_secret = auxprop_values[1].values[0];
+ sasl_secret_t *construct;
+
+ ret = _sasl_make_plain_secret(db_secret, passwd,
+ strlen(passwd),
+ &construct);
+ if (ret != SASL_OK) {
+ goto done;
+ }
+
+ if (!memcmp(db_secret, construct->data, construct->len)) {
+ /* password verified! */
+ ret = SASL_OK;
+ } else {
+ /* passwords do not match */
+ ret = SASL_BADAUTH;
+ }
+
+ sasl_FREE(construct);
+ } else {
+ /* passwords do not match */
+ ret = SASL_BADAUTH;
+ }
+
+ /* erase the plaintext password */
+ sconn->sparams->utils->prop_erase(sconn->sparams->propctx,
+ password_request[0]);
+
+ done:
+ /* We're not going to erase the property here because other people
+ * may want it */
+ return ret;
+}
+
+#if 0
+/* Verify user password using auxprop plugins. Allow verification against a hashed password,
+ * or non-retrievable password. Don't use cmusaslsecretPLAIN attribute.
+ *
+ * This function is similar to auxprop_verify_password().
+ */
+static int auxprop_verify_password_hashed(sasl_conn_t *conn,
+ const char *userstr,
+ const char *passwd,
+ const char *service __attribute__((unused)),
+ const char *user_realm __attribute__((unused)))
+{
+ int ret = SASL_FAIL;
+ int result = SASL_OK;
+ sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
+ const char *password_request[] = { SASL_AUX_PASSWORD,
+ NULL };
+ struct propval auxprop_values[2];
+ unsigned extra_cu_flags = 0;
+
+ if (!conn || !userstr)
+ return SASL_BADPARAM;
+
+ /* We need to clear any previous results and re-canonify to
+ * ensure correctness */
+
+ prop_clear(sconn->sparams->propctx, 0);
+
+ /* ensure its requested */
+ result = prop_request(sconn->sparams->propctx, password_request);
+
+ if (result != SASL_OK) return result;
+
+ /* We need to pass "password" down to the auxprop_lookup */
+ /* NB: We don't support binary passwords */
+ if (passwd != NULL) {
+ prop_set (sconn->sparams->propctx,
+ SASL_AUX_PASSWORD,
+ passwd,
+ -1);
+ extra_cu_flags = SASL_CU_VERIFY_AGAINST_HASH;
+ }
+
+ result = _sasl_canon_user_lookup (conn,
+ userstr,
+ 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID | extra_cu_flags,
+ &(conn->oparams));
+
+ if (result != SASL_OK) return result;
+
+ result = prop_getnames(sconn->sparams->propctx, password_request,
+ auxprop_values);
+ if (result < 0) {
+ return result;
+ }
+
+ /* Verify that the returned <name>s are correct.
+ But we defer checking for NULL values till after we verify
+ that a passwd is specified. */
+ if (!auxprop_values[0].name && !auxprop_values[1].name) {
+ return SASL_NOUSER;
+ }
+
+ /* It is possible for us to get useful information out of just
+ * the lookup, so we won't check that we have a password until now */
+ if (!passwd) {
+ ret = SASL_BADPARAM;
+ goto done;
+ }
+
+ if ((!auxprop_values[0].values || !auxprop_values[0].values[0])) {
+ return SASL_NOUSER;
+ }
+
+ /* At the point this has been called, the username has been canonified
+ * and we've done the auxprop lookup. This should be easy. */
+
+ /* NB: Note that if auxprop_lookup failed to verify the password,
+ then the userPassword property value would be NULL */
+ if (auxprop_values[0].name
+ && auxprop_values[0].values
+ && auxprop_values[0].values[0]
+ && !strcmp(auxprop_values[0].values[0], passwd)) {
+ /* We have a plaintext version and it matched! */
+ return SASL_OK;
+ } else {
+ /* passwords do not match */
+ ret = SASL_BADAUTH;
+ }
+
+ done:
+ /* We're not going to erase the property here because other people
+ * may want it */
+ return ret;
+}
+#endif
+
+#ifdef DO_SASL_CHECKAPOP
+int _sasl_auxprop_verify_apop(sasl_conn_t *conn,
+ const char *userstr,
+ const char *challenge,
+ const char *response,
+ const char *user_realm __attribute__((unused)))
+{
+ int ret = SASL_BADAUTH;
+ char *userid = NULL;
+ char *realm = NULL;
+ unsigned char digest[16];
+ char digeststr[33];
+ const char *password_request[] = { SASL_AUX_PASSWORD, NULL };
+ struct propval auxprop_values[2];
+ sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
+ MD5_CTX ctx;
+ int i;
+
+ if (!conn || !userstr || !challenge || !response)
+ PARAMERROR(conn)
+
+ /* We've done the auxprop lookup already (in our caller) */
+ /* sadly, APOP has no provision for storing secrets */
+ ret = prop_getnames(sconn->sparams->propctx, password_request,
+ auxprop_values);
+ if(ret < 0) {
+ sasl_seterror(conn, 0, "could not perform password lookup");
+ goto done;
+ }
+
+ if(!auxprop_values[0].name ||
+ !auxprop_values[0].values ||
+ !auxprop_values[0].values[0]) {
+ sasl_seterror(conn, 0, "could not find password");
+ ret = SASL_NOUSER;
+ goto done;
+ }
+
+ _sasl_MD5Init(&ctx);
+ _sasl_MD5Update(&ctx, (const unsigned char *) challenge, strlen(challenge));
+ _sasl_MD5Update(&ctx, (const unsigned char *) auxprop_values[0].values[0],
+ strlen(auxprop_values[0].values[0]));
+ _sasl_MD5Final(digest, &ctx);
+
+ /* erase the plaintext password */
+ sconn->sparams->utils->prop_erase(sconn->sparams->propctx,
+ password_request[0]);
+
+ /* convert digest from binary to ASCII hex */
+ for (i = 0; i < 16; i++)
+ sprintf(digeststr + (i*2), "%02x", digest[i]);
+
+ if (!strncasecmp(digeststr, response, 32)) {
+ /* password verified! */
+ ret = SASL_OK;
+ } else {
+ /* passwords do not match */
+ ret = SASL_BADAUTH;
+ }
+
+ done:
+ if (ret == SASL_BADAUTH) sasl_seterror(conn, SASL_NOLOG,
+ "login incorrect");
+ if (userid) sasl_FREE(userid);
+ if (realm) sasl_FREE(realm);
+
+ return ret;
+}
+#endif /* DO_SASL_CHECKAPOP */
+
+#if defined(HAVE_PWCHECK) || defined(HAVE_SASLAUTHD) || defined(HAVE_AUTHDAEMON)
+/*
+ * Wait for file descriptor to be writable. Return with error if timeout.
+ */
+static int write_wait(int fd, unsigned delta)
+{
+ fd_set wfds;
+ fd_set efds;
+ struct timeval tv;
+
+ /*
+ * Wait for file descriptor fd to be writable. Retry on
+ * interruptions. Return with error upon timeout.
+ */
+ while (1) {
+ FD_ZERO(&wfds);
+ FD_ZERO(&efds);
+ FD_SET(fd, &wfds);
+ FD_SET(fd, &efds);
+ tv.tv_sec = (long) delta;
+ tv.tv_usec = 0;
+ switch(select(fd + 1, 0, &wfds, &efds, &tv)) {
+ case 0:
+ /* Timeout. */
+ errno = ETIMEDOUT;
+ return -1;
+ case +1:
+ if (FD_ISSET(fd, &wfds)) {
+ /* Success, file descriptor is writable. */
+ return 0;
+ }
+ return -1;
+ case -1:
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ default:
+ /* Error catch-all. */
+ return -1;
+ }
+ }
+ /* Not reached. */
+ return -1;
+}
+
+/*
+ * Keep calling the writev() system call with 'fd', 'iov', and 'iovcnt'
+ * until all the data is written out or an error/timeout occurs.
+ */
+static int retry_writev(int fd, struct iovec *iov, int iovcnt, unsigned delta)
+{
+ int n;
+ int i;
+ int written = 0;
+ static int iov_max =
+#ifdef MAXIOV
+ MAXIOV
+#else
+#ifdef IOV_MAX
+ IOV_MAX
+#else
+ 8192
+#endif
+#endif
+ ;
+
+ for (;;) {
+ while (iovcnt && iov[0].iov_len == 0) {
+ iov++;
+ iovcnt--;
+ }
+
+ if (!iovcnt) return written;
+
+ if (delta > 0) {
+ if (write_wait(fd, delta))
+ return -1;
+ }
+ n = writev(fd, iov, iovcnt > iov_max ? iov_max : iovcnt);
+ if (n == -1) {
+ if (errno == EINVAL && iov_max > 10) {
+ iov_max /= 2;
+ continue;
+ }
+ if (errno == EINTR) continue;
+ return -1;
+ }
+
+ written += n;
+
+ for (i = 0; i < iovcnt; i++) {
+ if ((int) iov[i].iov_len > n) {
+ iov[i].iov_base = (char *)iov[i].iov_base + n;
+ iov[i].iov_len -= n;
+ break;
+ }
+ n -= iov[i].iov_len;
+ iov[i].iov_len = 0;
+ }
+
+ if (i == iovcnt) return written;
+ }
+}
+
+#endif
+
+#ifdef HAVE_PWCHECK
+/* pwcheck daemon-authenticated login */
+static int pwcheck_verify_password(sasl_conn_t *conn,
+ const char *userid,
+ const char *passwd,
+ const char *service __attribute__((unused)),
+ const char *user_realm
+ __attribute__((unused)))
+{
+ int s;
+ struct sockaddr_un srvaddr;
+ int r;
+ struct iovec iov[10];
+ static char response[1024];
+ unsigned start, n;
+ char pwpath[1024];
+
+ if (strlen(PWCHECKDIR)+8+1 > sizeof(pwpath)) return SASL_FAIL;
+
+ strcpy(pwpath, PWCHECKDIR);
+ strcat(pwpath, "/pwcheck");
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s == -1) return errno;
+
+ memset((char *)&srvaddr, 0, sizeof(srvaddr));
+ srvaddr.sun_family = AF_UNIX;
+ strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));
+ r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
+ if (r == -1) {
+ sasl_seterror(conn,0,"cannot connect to pwcheck server");
+ return SASL_FAIL;
+ }
+
+ iov[0].iov_base = (char *)userid;
+ iov[0].iov_len = strlen(userid)+1;
+ iov[1].iov_base = (char *)passwd;
+ iov[1].iov_len = strlen(passwd)+1;
+
+ retry_writev(s, iov, 2, 0);
+
+ start = 0;
+ while (start < sizeof(response) - 1) {
+ n = read(s, response+start, sizeof(response) - 1 - start);
+ if (n < 1) break;
+ start += n;
+ }
+
+ close(s);
+
+ if (start > 1 && !strncmp(response, "OK", 2)) {
+ return SASL_OK;
+ }
+
+ response[start] = '\0';
+ sasl_seterror(conn,0,response);
+ return SASL_BADAUTH;
+}
+
+#endif
+
+#if defined(HAVE_SASLAUTHD) || defined(HAVE_AUTHDAEMON)
+static int read_wait(int fd, unsigned delta)
+{
+ fd_set rfds;
+ fd_set efds;
+ struct timeval tv;
+ /*
+ * Wait for file descriptor fd to be readable. Retry on
+ * interruptions. Return with error upon timeout.
+ */
+ while (1) {
+ FD_ZERO(&rfds);
+ FD_ZERO(&efds);
+ FD_SET(fd, &rfds);
+ FD_SET(fd, &efds);
+ tv.tv_sec = (long) delta;
+ tv.tv_usec = 0;
+ switch(select(fd + 1, &rfds, 0, &efds, &tv)) {
+ case 0:
+ /* Timeout. */
+ errno = ETIMEDOUT;
+ return -1;
+ case +1:
+ case +2:
+ if (FD_ISSET(fd, &rfds)) {
+ /* Success, file descriptor is readable. */
+ return 0;
+ }
+ return -1;
+ case -1:
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ default:
+ /* Error catch-all. */
+ return -1;
+ }
+ }
+ /* Not reached. */
+ return -1;
+}
+
+/*
+ * Keep calling the read() system call until all the data is read in,
+ * timeout, EOF, or an error occurs. This function returns the number
+ * of useful bytes, or -1 if timeout/error.
+ */
+static int retry_read(int fd, void *buf0, unsigned nbyte, unsigned delta)
+{
+ int nr;
+ unsigned nleft = nbyte;
+ char *buf = (char*) buf0;
+
+ while (nleft >= 1) {
+ if (delta > 0) {
+ if (read_wait(fd, delta))
+ return -1;
+ }
+ nr = read(fd, buf, nleft);
+ if (nr < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ } else if (nr == 0) {
+ break;
+ }
+ buf += nr;
+ nleft -= nr;
+ }
+ return nbyte - nleft;
+}
+#endif
+
+#ifdef HAVE_SASLAUTHD
+/* saslauthd-authenticated login */
+static int saslauthd_verify_password(sasl_conn_t *conn,
+ const char *userid,
+ const char *passwd,
+ const char *service,
+ const char *user_realm)
+{
+ char response[1024];
+ char query[8192];
+ char *query_end = query;
+ int s;
+ struct sockaddr_un srvaddr;
+ sasl_getopt_t *getopt;
+ void *context;
+ char pwpath[sizeof(srvaddr.sun_path)];
+ const char *p = NULL;
+ char *freeme = NULL;
+#ifdef USE_DOORS
+ door_arg_t arg;
+#endif
+
+ /* check to see if the user configured a rundir */
+ if (_sasl_getcallback(conn, SASL_CB_GETOPT,
+ (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+ getopt(context, NULL, "saslauthd_path", &p, NULL);
+ }
+ if (p) {
+ if (strlen(p) >= sizeof(pwpath))
+ return SASL_FAIL;
+
+ strncpy(pwpath, p, sizeof(pwpath) - 1);
+ pwpath[strlen(p)] = '\0';
+ } else {
+ if (strlen(PATH_SASLAUTHD_RUNDIR) + 4 + 1 > sizeof(pwpath))
+ return SASL_FAIL;
+
+ strcpy(pwpath, PATH_SASLAUTHD_RUNDIR "/mux");
+ }
+
+ /* Split out username/realm if necessary */
+ if(strrchr(userid,'@') != NULL) {
+ char *rtmp;
+
+ if(_sasl_strdup(userid, &freeme, NULL) != SASL_OK)
+ goto fail;
+
+ userid = freeme;
+ rtmp = strrchr(userid,'@');
+ *rtmp = '\0';
+ user_realm = rtmp + 1;
+ }
+
+ /*
+ * build request of the form:
+ *
+ * count authid count password count service count realm
+ */
+ {
+ unsigned short max_len, req_len, u_len, p_len, s_len, r_len;
+
+ max_len = (unsigned short) sizeof(query);
+
+ /* prevent buffer overflow */
+ if ((strlen(userid) > USHRT_MAX) ||
+ (strlen(passwd) > USHRT_MAX) ||
+ (strlen(service) > USHRT_MAX) ||
+ (user_realm && (strlen(user_realm) > USHRT_MAX))) {
+ goto toobig;
+ }
+
+ u_len = (strlen(userid));
+ p_len = (strlen(passwd));
+ s_len = (strlen(service));
+ r_len = ((user_realm ? strlen(user_realm) : 0));
+
+ /* prevent buffer overflow */
+ req_len = 30;
+ if (max_len - req_len < u_len) goto toobig;
+ req_len += u_len;
+ if (max_len - req_len < p_len) goto toobig;
+ req_len += p_len;
+ if (max_len - req_len < s_len) goto toobig;
+ req_len += s_len;
+ if (max_len - req_len < r_len) goto toobig;
+
+ u_len = htons(u_len);
+ p_len = htons(p_len);
+ s_len = htons(s_len);
+ r_len = htons(r_len);
+
+ memcpy(query_end, &u_len, sizeof(unsigned short));
+ query_end += sizeof(unsigned short);
+ while (*userid) *query_end++ = *userid++;
+
+ memcpy(query_end, &p_len, sizeof(unsigned short));
+ query_end += sizeof(unsigned short);
+ while (*passwd) *query_end++ = *passwd++;
+
+ memcpy(query_end, &s_len, sizeof(unsigned short));
+ query_end += sizeof(unsigned short);
+ while (*service) *query_end++ = *service++;
+
+ memcpy(query_end, &r_len, sizeof(unsigned short));
+ query_end += sizeof(unsigned short);
+ if (user_realm) while (*user_realm) *query_end++ = *user_realm++;
+ }
+
+#ifdef USE_DOORS
+ s = open(pwpath, O_RDONLY);
+ if (s < 0) {
+ sasl_seterror(conn, 0, "cannot open door to saslauthd server: %m", errno);
+ goto fail;
+ }
+
+ arg.data_ptr = query;
+ arg.data_size = query_end - query;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = response;
+ arg.rsize = sizeof(response);
+
+ if (door_call(s, &arg) < 0) {
+ /* Parameters are undefined */
+ close(s);
+ sasl_seterror(conn, 0, "door call to saslauthd server failed: %m", errno);
+ goto fail;
+ }
+
+ if (arg.data_ptr != response || arg.data_size >= sizeof(response)) {
+ /* oh damn, we got back a really long response */
+ munmap(arg.rbuf, arg.rsize);
+ close(s);
+ sasl_seterror(conn, 0, "saslauthd sent an overly long response");
+ goto fail;
+ }
+ response[arg.data_size] = '\0';
+
+ close(s);
+#else
+ /* unix sockets */
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s == -1) {
+ sasl_seterror(conn, 0, "cannot create socket for saslauthd: %m", errno);
+ goto fail;
+ }
+
+ memset((char *)&srvaddr, 0, sizeof(srvaddr));
+ srvaddr.sun_family = AF_UNIX;
+ strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path) - 1);
+ srvaddr.sun_path[strlen(pwpath)] = '\0';
+
+ {
+ int r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
+ if (r == -1) {
+ close(s);
+ sasl_seterror(conn, 0, "cannot connect to saslauthd server: %m", errno);
+ goto fail;
+ }
+ }
+
+ {
+ struct iovec iov[8];
+
+ iov[0].iov_len = query_end - query;
+ iov[0].iov_base = query;
+
+ if (retry_writev(s, iov, 1, 0) == -1) {
+ close(s);
+ sasl_seterror(conn, 0, "write failed");
+ goto fail;
+ }
+ }
+
+ {
+ unsigned short count = 0;
+
+ /*
+ * read response of the form:
+ *
+ * count result
+ */
+ if (retry_read(s, &count, sizeof(count), 0) < (int) sizeof(count)) {
+ sasl_seterror(conn, 0, "size read failed");
+ goto fail;
+ }
+
+ count = ntohs(count);
+ if (count < 2) { /* MUST have at least "OK" or "NO" */
+ close(s);
+ sasl_seterror(conn, 0, "bad response from saslauthd");
+ goto fail;
+ }
+
+ count = (int)sizeof(response) <= count ? sizeof(response) - 1 : count;
+ if (retry_read(s, response, count, 0) < count) {
+ close(s);
+ sasl_seterror(conn, 0, "read failed");
+ goto fail;
+ }
+ response[count] = '\0';
+ }
+
+ close(s);
+#endif /* USE_DOORS */
+
+ if(freeme) free(freeme);
+
+ if (!strncmp(response, "OK", 2)) {
+ return SASL_OK;
+ }
+
+ sasl_seterror(conn, SASL_NOLOG, "authentication failed");
+ return SASL_BADAUTH;
+
+ toobig:
+ /* request just too damn big */
+ sasl_seterror(conn, 0, "saslauthd request too large");
+
+ fail:
+ if (freeme) free(freeme);
+ return SASL_FAIL;
+}
+
+#endif
+
+#ifdef HAVE_AUTHDAEMON
+/*
+ * Preliminary support for Courier's authdaemond.
+ */
+#define AUTHDAEMON_IO_TIMEOUT 30
+
+static int authdaemon_blocking(int fd, int block)
+{
+ int f, r;
+
+ /* Get the fd's blocking bit. */
+ f = fcntl(fd, F_GETFL, 0);
+ if (f == -1)
+ return -1;
+
+ /* Adjust the bitmap accordingly. */
+#ifndef O_NONBLOCK
+#define NB_BITMASK FNDELAY
+#else
+#define NB_BITMASK O_NONBLOCK
+#endif
+ if (block)
+ f &= ~NB_BITMASK;
+ else
+ f |= NB_BITMASK;
+#undef NB_BITMASK
+
+ /* Adjust the fd's blocking bit. */
+ r = fcntl(fd, F_SETFL, f);
+ if (r)
+ return -1;
+
+ /* Success. */
+ return 0;
+}
+
+static int authdaemon_connect(sasl_conn_t *conn, const char *path)
+{
+ int r, s = -1;
+ struct sockaddr_un srvaddr;
+
+ if (strlen(path) >= sizeof(srvaddr.sun_path)) {
+ sasl_seterror(conn, 0, "unix socket path too large", errno);
+ goto fail;
+ }
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s == -1) {
+ sasl_seterror(conn, 0, "cannot create socket for connection to Courier authdaemond: %m", errno);
+ goto fail;
+ }
+
+ memset((char *)&srvaddr, 0, sizeof(srvaddr));
+ srvaddr.sun_family = AF_UNIX;
+ strncpy(srvaddr.sun_path, path, sizeof(srvaddr.sun_path) - 1);
+
+ /* Use nonblocking unix socket connect(2). */
+ if (authdaemon_blocking(s, 0)) {
+ sasl_seterror(conn, 0, "cannot set nonblocking bit: %m", errno);
+ goto fail;
+ }
+
+ r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
+ if (r == -1) {
+ sasl_seterror(conn, 0, "cannot connect to Courier authdaemond: %m", errno);
+ goto fail;
+ }
+
+ if (authdaemon_blocking(s, 1)) {
+ sasl_seterror(conn, 0, "cannot clear nonblocking bit: %m", errno);
+ goto fail;
+ }
+
+ return s;
+fail:
+ if (s >= 0)
+ close(s);
+ return -1;
+}
+
+static char *authdaemon_build_query(const char *service,
+ const char *authtype,
+ const char *user,
+ const char *passwd)
+{
+ int sz;
+ int l = strlen(service)
+ + 1
+ + strlen(authtype)
+ + 1
+ + strlen(user)
+ + 1
+ + strlen(passwd)
+ + 1;
+ char *buf, n[5];
+ if (snprintf(n, sizeof(n), "%d", l) >= (int)sizeof(n))
+ return NULL;
+ sz = strlen(n) + l + 20;
+ if (!(buf = sasl_ALLOC(sz)))
+ return NULL;
+ snprintf(buf,
+ sz,
+ "AUTH %s\n%s\n%s\n%s\n%s\n\n",
+ n,
+ service,
+ authtype,
+ user,
+ passwd);
+ return buf;
+}
+
+static int authdaemon_read(int fd, void *buf0, unsigned sz)
+{
+ int nr;
+ char *buf = (char*) buf0;
+ if (sz <= 1)
+ return -1;
+ if ((nr = retry_read(fd, buf0, sz - 1, AUTHDAEMON_IO_TIMEOUT)) < 0)
+ return -1;
+ /* We need a null-terminated buffer. */
+ buf[nr] = 0;
+ /* Check for overflow condition. */
+ return nr + 1 < (int)sz ? 0 : -1;
+}
+
+static int authdaemon_write(int fd, void *buf0, unsigned sz)
+{
+ int nw;
+ struct iovec io;
+ io.iov_len = sz;
+ io.iov_base = buf0;
+ nw = retry_writev(fd, &io, 1, AUTHDAEMON_IO_TIMEOUT);
+ return nw == (int)sz ? 0 : -1;
+}
+
+static int authdaemon_talk(sasl_conn_t *conn, int sock, char *authreq)
+{
+ char *str;
+ char buf[8192];
+
+ if (authdaemon_write(sock, authreq, strlen(authreq)))
+ goto _err_out;
+ if (authdaemon_read(sock, buf, sizeof(buf)))
+ goto _err_out;
+ for (str = buf; *str; ) {
+ char *sub;
+
+ for (sub = str; *str; ++str) {
+ if (*str == '\n') {
+ *str++ = 0;
+ break;
+ }
+ }
+ if (strcmp(sub, ".") == 0) {
+ /* success */
+ return SASL_OK;
+ }
+ if (strcmp(sub, "FAIL") == 0) {
+ /* passwords do not match */
+ sasl_seterror(conn, SASL_NOLOG, "authentication failed");
+ return SASL_BADAUTH;
+ }
+ }
+_err_out:
+ /* catchall: authentication error */
+ sasl_seterror(conn, 0, "could not verify password");
+ return SASL_FAIL;
+}
+
+static int authdaemon_verify_password(sasl_conn_t *conn,
+ const char *userid,
+ const char *passwd,
+ const char *service,
+ const char *user_realm __attribute__((unused)))
+{
+ const char *p = NULL;
+ sasl_getopt_t *getopt;
+ void *context;
+ int result = SASL_FAIL;
+ char *query = NULL;
+ int sock = -1;
+
+ /* check to see if the user configured a rundir */
+ if (_sasl_getcallback(conn, SASL_CB_GETOPT,
+ (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+ getopt(context, NULL, "authdaemond_path", &p, NULL);
+ }
+ if (!p) {
+ /*
+ * XXX should we peek at Courier's build-time config ?
+ */
+ p = PATH_AUTHDAEMON_SOCKET;
+ }
+
+ if ((sock = authdaemon_connect(conn, p)) < 0)
+ goto out;
+ if (!(query = authdaemon_build_query(service, "login", userid, passwd)))
+ goto out;
+ result = authdaemon_talk(conn, sock, query);
+out:
+ if (sock >= 0)
+ close(sock), sock = -1;
+ if (query)
+ sasl_FREE(query), query = 0;
+ return result;
+}
+#endif
+
+#ifdef HAVE_ALWAYSTRUE
+static int always_true(sasl_conn_t *conn,
+ const char *userstr,
+ const char *passwd __attribute__((unused)),
+ const char *service __attribute__((unused)),
+ const char *user_realm __attribute__((unused)))
+{
+ _sasl_log(conn, SASL_LOG_WARN, "AlwaysTrue Password Verifier Verified: %s",
+ userstr);
+ return SASL_OK;
+}
+#endif
+
+struct sasl_verify_password_s _sasl_verify_password[] = {
+ { "auxprop", &auxprop_verify_password },
+#if 0 /* totally undocumented. wtf is this? */
+ { "auxprop-hashed", &auxprop_verify_password_hashed },
+#endif
+#ifdef HAVE_PWCHECK
+ { "pwcheck", &pwcheck_verify_password },
+#endif
+#ifdef HAVE_SASLAUTHD
+ { "saslauthd", &saslauthd_verify_password },
+#endif
+#ifdef HAVE_AUTHDAEMON
+ { "authdaemond", &authdaemon_verify_password },
+#endif
+#ifdef HAVE_ALWAYSTRUE
+ { "alwaystrue", &always_true },
+#endif
+ { NULL, NULL }
+};
diff --git a/contrib/libs/sasl/lib/client.c b/contrib/libs/sasl/lib/client.c
new file mode 100644
index 0000000000..3784bb0e42
--- /dev/null
+++ b/contrib/libs/sasl/lib/client.c
@@ -0,0 +1,1317 @@
+/* SASL client API implementation
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* SASL Headers */
+#include "sasl.h"
+#include "saslplug.h"
+#include "saslutil.h"
+#include "saslint.h"
+
+static cmech_list_t *cmechlist; /* global var which holds the list */
+static sasl_global_callbacks_t global_callbacks_client;
+static int _sasl_client_active = 0;
+
+static int init_mechlist()
+{
+ cmechlist->utils=_sasl_alloc_utils(NULL, &global_callbacks_client);
+ if (cmechlist->utils==NULL)
+ return SASL_NOMEM;
+
+ cmechlist->mech_list=NULL;
+ cmechlist->mech_length=0;
+
+ return SASL_OK;
+}
+
+int sasl_client_done(void)
+{
+ int result = SASL_CONTINUE;
+
+ if (_sasl_server_cleanup_hook == NULL && _sasl_client_cleanup_hook == NULL) {
+ return SASL_NOTINIT;
+ }
+
+ if (_sasl_client_cleanup_hook) {
+ result = _sasl_client_cleanup_hook();
+
+ if (result == SASL_OK) {
+ _sasl_client_idle_hook = NULL;
+ _sasl_client_cleanup_hook = NULL;
+ } else {
+ return result;
+ }
+ }
+
+ if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
+ return result;
+ }
+
+ sasl_common_done();
+
+ return SASL_OK;
+}
+
+static int client_done(void) {
+ cmechanism_t *cm;
+ cmechanism_t *cprevm;
+
+ if (!_sasl_client_active) {
+ return SASL_NOTINIT;
+ } else {
+ _sasl_client_active--;
+ }
+
+ if(_sasl_client_active) {
+ /* Don't de-init yet! Our refcount is nonzero. */
+ return SASL_CONTINUE;
+ }
+
+ cm = cmechlist->mech_list; /* m point to beginning of the list */
+ while (cm != NULL) {
+ cprevm = cm;
+ cm = cm->next;
+
+ if (cprevm->m.plug->mech_free) {
+ cprevm->m.plug->mech_free(cprevm->m.plug->glob_context,
+ cmechlist->utils);
+ }
+
+ sasl_FREE(cprevm->m.plugname);
+ sasl_FREE(cprevm);
+ }
+ _sasl_free_utils(&cmechlist->utils);
+ sasl_FREE(cmechlist);
+
+ cmechlist = NULL;
+
+ return SASL_OK;
+}
+
+/* This is nearly identical to the version in server.c.
+ Keep in sync. */
+static int mech_compare(const sasl_client_plug_t *a,
+ const sasl_client_plug_t *b)
+{
+ unsigned sec_diff;
+ unsigned features_diff;
+
+ /* XXX the following is fairly arbitrary, but its independent
+ of the order in which the plugins are loaded
+ */
+#ifdef PREFER_MECH
+ if (!strcasecmp(a->mech_name, PREFER_MECH)) return 1;
+ if (!strcasecmp(b->mech_name, PREFER_MECH)) return -1;
+#endif
+
+ sec_diff = a->security_flags ^ b->security_flags;
+ if (sec_diff & a->security_flags & SASL_SEC_NOANONYMOUS) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NOANONYMOUS) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_NOPLAINTEXT) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NOPLAINTEXT) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_MUTUAL_AUTH) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_MUTUAL_AUTH) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_NOACTIVE) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NOACTIVE) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_NODICTIONARY) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NODICTIONARY) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_FORWARD_SECRECY) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_FORWARD_SECRECY) return -1;
+
+ features_diff = a->features ^ b->features;
+ if (features_diff & a->features & SASL_FEAT_CHANNEL_BINDING) return 1;
+ if (features_diff & b->features & SASL_FEAT_CHANNEL_BINDING) return -1;
+
+ if (a->max_ssf > b->max_ssf) return 1;
+ if (a->max_ssf < b->max_ssf) return -1;
+
+ if (SASL_GET_HASH_STRENGTH(a->security_flags) > SASL_GET_HASH_STRENGTH(b->security_flags)) return 1;
+ if (SASL_GET_HASH_STRENGTH(a->security_flags) < SASL_GET_HASH_STRENGTH(b->security_flags)) return -1;
+
+ return 0;
+}
+
+int sasl_client_add_plugin(const char *plugname,
+ sasl_client_plug_init_t *entry_point)
+{
+ int plugcount;
+ sasl_client_plug_t *pluglist;
+ cmechanism_t *mech, *mp;
+ int result;
+ int version;
+ int lupe;
+
+ if (!plugname || !entry_point) return SASL_BADPARAM;
+
+ result = entry_point(cmechlist->utils,
+ SASL_CLIENT_PLUG_VERSION,
+ &version,
+ &pluglist,
+ &plugcount);
+
+ if (result != SASL_OK)
+ {
+ _sasl_log(NULL, SASL_LOG_WARN,
+ "sasl_client_add_plugin(): entry_point(): failed for plugname %s: %z",
+ plugname, result);
+ return result;
+ }
+
+ if (version != SASL_CLIENT_PLUG_VERSION)
+ {
+ _sasl_log(NULL, SASL_LOG_WARN,
+ "version conflict in sasl_client_add_plugin for %s", plugname);
+ return SASL_BADVERS;
+ }
+
+ for (lupe=0; lupe < plugcount; lupe++, pluglist++)
+ {
+ mech = sasl_ALLOC(sizeof(cmechanism_t));
+ if (!mech) return SASL_NOMEM;
+
+ mech->m.plug = pluglist;
+ if (_sasl_strdup(plugname, &mech->m.plugname, NULL) != SASL_OK) {
+ sasl_FREE(mech);
+ return SASL_NOMEM;
+ }
+ mech->m.version = version;
+
+ /* sort mech_list by relative "strength" */
+ mp = cmechlist->mech_list;
+ if (!mp || mech_compare(pluglist, mp->m.plug) >= 0) {
+ /* add mech to head of list */
+ mech->next = cmechlist->mech_list;
+ cmechlist->mech_list = mech;
+ } else {
+ /* find where to insert mech into list */
+ while (mp->next &&
+ mech_compare(pluglist, mp->next->m.plug) <= 0) mp = mp->next;
+ mech->next = mp->next;
+ mp->next = mech;
+ }
+
+ cmechlist->mech_length++;
+ }
+
+ return SASL_OK;
+}
+
+static int
+client_idle(sasl_conn_t *conn)
+{
+ cmechanism_t *m;
+ if (! cmechlist)
+ return 0;
+
+ for (m = cmechlist->mech_list;
+ m;
+ m = m->next)
+ if (m->m.plug->idle
+ && m->m.plug->idle(m->m.plug->glob_context,
+ conn,
+ conn ? ((sasl_client_conn_t *)conn)->cparams : NULL))
+ return 1;
+ return 0;
+}
+
+/* initialize the SASL client drivers
+ * callbacks -- base callbacks for all client connections
+ * returns:
+ * SASL_OK -- Success
+ * SASL_NOMEM -- Not enough memory
+ * SASL_BADVERS -- Mechanism version mismatch
+ * SASL_BADPARAM -- error in config file
+ * SASL_NOMECH -- No mechanisms available
+ * ...
+ */
+
+int sasl_client_init(const sasl_callback_t *callbacks)
+{
+ int ret;
+ const add_plugin_list_t ep_list[] = {
+ { "sasl_client_plug_init", (add_plugin_t *)sasl_client_add_plugin },
+ { "sasl_canonuser_init", (add_plugin_t *)sasl_canonuser_add_plugin },
+ { 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? */
+ _sasl_client_active++;
+ return SASL_OK;
+ }
+
+ global_callbacks_client.callbacks = callbacks;
+ global_callbacks_client.appname = NULL;
+
+ cmechlist=sasl_ALLOC(sizeof(cmech_list_t));
+ if (cmechlist==NULL) return SASL_NOMEM;
+
+ /* We need to call client_done if we fail now */
+ _sasl_client_active = 1;
+
+ /* load plugins */
+ ret=init_mechlist();
+ if (ret!=SASL_OK) {
+ client_done();
+ return ret;
+ }
+
+ sasl_client_add_plugin("EXTERNAL", &external_client_plug_init);
+
+ ret = _sasl_common_init(&global_callbacks_client);
+
+ if (ret == SASL_OK)
+ ret = _sasl_load_plugins(ep_list,
+ _sasl_find_getpath_callback(callbacks),
+ _sasl_find_verifyfile_callback(callbacks));
+
+ if (ret == SASL_OK) {
+ _sasl_client_cleanup_hook = &client_done;
+ _sasl_client_idle_hook = &client_idle;
+
+ ret = _sasl_build_mechlist();
+ } else {
+ client_done();
+ }
+
+ return ret;
+}
+
+static void client_dispose(sasl_conn_t *pconn)
+{
+ sasl_client_conn_t *c_conn=(sasl_client_conn_t *) pconn;
+
+ if (c_conn->mech && c_conn->mech->m.plug->mech_dispose) {
+ c_conn->mech->m.plug->mech_dispose(pconn->context,
+ c_conn->cparams->utils);
+ }
+
+ pconn->context = NULL;
+
+ if (c_conn->clientFQDN)
+ sasl_FREE(c_conn->clientFQDN);
+
+ if (c_conn->cparams) {
+ _sasl_free_utils(&(c_conn->cparams->utils));
+ sasl_FREE(c_conn->cparams);
+ }
+
+ if (c_conn->mech_list != cmechlist->mech_list) {
+ /* free connection-specific mech_list */
+ cmechanism_t *m, *prevm;
+
+ m = c_conn->mech_list; /* m point to beginning of the list */
+
+ while (m) {
+ prevm = m;
+ m = m->next;
+ sasl_FREE(prevm);
+ }
+ }
+
+ _sasl_conn_dispose(pconn);
+}
+
+/* initialize a client exchange based on the specified mechanism
+ * service -- registered name of the service using SASL (e.g. "imap")
+ * serverFQDN -- the fully qualified domain name of the server
+ * iplocalport -- client IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * ipremoteport -- server IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * prompt_supp -- list of client interactions supported
+ * may also include sasl_getopt_t context & call
+ * NULL prompt_supp = user/pass via SASL_INTERACT only
+ * NULL proc = interaction supported via SASL_INTERACT
+ * secflags -- security flags (see above)
+ * in/out:
+ * pconn -- connection negotiation structure
+ * pointer to NULL => allocate new
+ * non-NULL => recycle storage and go for next available mech
+ *
+ * Returns:
+ * SASL_OK -- success
+ * SASL_NOMECH -- no mechanism meets requested properties
+ * SASL_NOMEM -- not enough memory
+ */
+int sasl_client_new(const char *service,
+ const char *serverFQDN,
+ const char *iplocalport,
+ const char *ipremoteport,
+ const sasl_callback_t *prompt_supp,
+ unsigned flags,
+ sasl_conn_t **pconn)
+{
+ int result;
+ char name[MAXFQDNLEN];
+ sasl_client_conn_t *conn;
+ sasl_utils_t *utils;
+ sasl_getopt_t *getopt;
+ void *context;
+ const char *mlist = NULL;
+ int plus = 0;
+
+ if (_sasl_client_active == 0) return SASL_NOTINIT;
+
+ /* Remember, serverFQDN, iplocalport and ipremoteport can be NULL and be valid! */
+ if (!pconn || !service)
+ return SASL_BADPARAM;
+
+ *pconn=sasl_ALLOC(sizeof(sasl_client_conn_t));
+ if (*pconn==NULL) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "Out of memory allocating connection context");
+ return SASL_NOMEM;
+ }
+ memset(*pconn, 0, sizeof(sasl_client_conn_t));
+
+ (*pconn)->destroy_conn = &client_dispose;
+
+ conn = (sasl_client_conn_t *)*pconn;
+
+ conn->mech = NULL;
+
+ conn->cparams=sasl_ALLOC(sizeof(sasl_client_params_t));
+ if (conn->cparams==NULL)
+ MEMERROR(*pconn);
+ memset(conn->cparams,0,sizeof(sasl_client_params_t));
+
+ result = _sasl_conn_init(*pconn, service, flags, SASL_CONN_CLIENT,
+ &client_idle, serverFQDN,
+ iplocalport, ipremoteport,
+ prompt_supp, &global_callbacks_client);
+ if (result != SASL_OK) RETURN(*pconn, result);
+
+ utils = _sasl_alloc_utils(*pconn, &global_callbacks_client);
+ if (utils == NULL) {
+ MEMERROR(*pconn);
+ }
+
+ utils->conn= *pconn;
+ conn->cparams->utils = utils;
+
+ if(_sasl_getcallback(*pconn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+ getopt(context, NULL, "client_mech_list", &mlist, NULL);
+ }
+
+ /* if we have a client_mech_list, create ordered list of
+ available mechanisms for this conn */
+ if (mlist) {
+ const char *cp;
+ cmechanism_t *mptr, *tail = NULL;
+ cmechanism_t *new;
+
+ while (*mlist) {
+ /* find end of current mech name */
+ for (cp = mlist; *cp && !isspace((int) *cp); cp++);
+
+ /* search for mech name in loaded plugins */
+ for (mptr = cmechlist->mech_list; mptr; mptr = mptr->next) {
+ const sasl_client_plug_t *plug = mptr->m.plug;
+
+ if (_sasl_is_equal_mech(mlist, plug->mech_name, (size_t) (cp - mlist), &plus)) {
+ /* found a match */
+ break;
+ }
+ }
+ if (mptr) {
+ new = sasl_ALLOC(sizeof(cmechanism_t));
+ if (!new) {
+ result = SASL_NOMEM;
+ goto failed_client_new;
+ }
+ memcpy(&new->m, &mptr->m, sizeof(client_sasl_mechanism_t));
+ new->next = NULL;
+
+ if (!conn->mech_list) {
+ conn->mech_list = new;
+ tail = conn->mech_list;
+ } else {
+ if (tail)
+ tail->next = new;
+ tail = new;
+ }
+ conn->mech_length++;
+ }
+
+ /* find next mech name */
+ mlist = cp;
+ while (*mlist && isspace((int) *mlist)) mlist++;
+ }
+ } else {
+ conn->mech_list = cmechlist->mech_list;
+ conn->mech_length = cmechlist->mech_length;
+ }
+
+ if (conn->mech_list == NULL) {
+ sasl_seterror(*pconn, 0, "No worthy mechs found");
+ result = SASL_NOMECH;
+ goto failed_client_new;
+ }
+
+ /* Setup the non-lazy parts of cparams, the rest is done in
+ * sasl_client_start */
+ conn->cparams->canon_user = &_sasl_canon_user_lookup;
+ conn->cparams->flags = flags;
+ conn->cparams->prompt_supp = (*pconn)->callbacks;
+
+ /* get the clientFQDN (serverFQDN was set in _sasl_conn_init) */
+ memset(name, 0, sizeof(name));
+ if (get_fqhostname (name, MAXFQDNLEN, 0) != 0) {
+ return (SASL_FAIL);
+ }
+
+ result = _sasl_strdup(name, &conn->clientFQDN, NULL);
+
+ if (result == SASL_OK) return SASL_OK;
+
+failed_client_new:
+ /* result isn't SASL_OK */
+ _sasl_conn_dispose(*pconn);
+ sasl_FREE(*pconn);
+ *pconn = NULL;
+ _sasl_log(NULL, SASL_LOG_ERR, "Out of memory in sasl_client_new");
+ return result;
+}
+
+static int have_prompts(sasl_conn_t *conn,
+ const sasl_client_plug_t *mech)
+{
+ static const unsigned long default_prompts[] = {
+ SASL_CB_AUTHNAME,
+ SASL_CB_PASS,
+ SASL_CB_LIST_END
+ };
+
+ const unsigned long *prompt;
+ sasl_callback_ft pproc;
+ void *pcontext;
+ int result;
+
+ for (prompt = (mech->required_prompts
+ ? mech->required_prompts :
+ default_prompts);
+ *prompt != SASL_CB_LIST_END;
+ prompt++) {
+ result = _sasl_getcallback(conn, *prompt, &pproc, &pcontext);
+ if (result != SASL_OK && result != SASL_INTERACT)
+ return 0; /* we don't have this required prompt */
+ }
+
+ return 1; /* we have all the prompts */
+}
+
+static int
+_mech_plus_p(const char *mech, size_t len)
+{
+ return (len > 5 && strncasecmp(&mech[len - 5], "-PLUS", 5) == 0);
+}
+
+/*
+ * Order PLUS mechanisms first. Returns NUL separated list of
+ * *count items.
+ */
+static int
+_sasl_client_order_mechs(const sasl_utils_t *utils,
+ const char *mechs,
+ int has_cb_data,
+ char **ordered_mechs,
+ size_t *count,
+ int *server_can_cb)
+{
+ char *list, *listp;
+ size_t i, mechslen, start;
+
+ *count = 0;
+ *server_can_cb = 0;
+
+ if (mechs == NULL || mechs[0] == '\0')
+ return SASL_NOMECH;
+
+ mechslen = strlen(mechs);
+
+ listp = list = utils->malloc(mechslen + 1);
+ if (list == NULL)
+ return SASL_NOMEM;
+
+ /* As per RFC 4422:
+ * SASL mechanism allowable characters are "AZ-_"
+ * separators can be any other characters and of any length
+ * even variable lengths between.
+ *
+ * But for convenience we accept lowercase ASCII.
+ *
+ * Apps should be encouraged to simply use space or comma space
+ * though
+ */
+#define ismechchar(c) (isalnum((c)) || (c) == '_' || (c) == '-')
+ do {
+ for (i = start = 0; i <= mechslen; i++) {
+ if (!ismechchar(mechs[i])) {
+ const char *mechp = &mechs[start];
+ size_t len = i - start;
+
+ if (len != 0 &&
+ _mech_plus_p(mechp, len) == has_cb_data) {
+ memcpy(listp, mechp, len);
+ listp[len] = '\0';
+ listp += len + 1;
+ (*count)++;
+ if (*server_can_cb == 0 && has_cb_data)
+ *server_can_cb = 1;
+ }
+ start = i+1;
+ }
+ }
+ if (has_cb_data)
+ has_cb_data = 0;
+ else
+ break;
+ } while (1);
+
+ if (*count == 0) {
+ utils->free(list);
+ return SASL_NOMECH;
+ }
+
+ *ordered_mechs = list;
+
+ return SASL_OK;
+}
+
+static INLINE int
+_sasl_cbinding_disp(sasl_client_params_t *cparams,
+ int mech_nego,
+ int server_can_cb,
+ sasl_cbinding_disp_t *cbindingdisp)
+{
+ /*
+ * If negotiating mechanisms, then we fail immediately if the
+ * client requires channel binding and the server does not
+ * advertise support. Otherwise we send "y" (which later will
+ * become "p" if we select a supporting mechanism).
+ *
+ * If the client explicitly selected a mechanism, then we only
+ * send channel bindings if they're marked critical.
+ */
+
+ *cbindingdisp = SASL_CB_DISP_NONE;
+
+ if (SASL_CB_PRESENT(cparams)) {
+ if (mech_nego) {
+ if (!server_can_cb && SASL_CB_CRITICAL(cparams)) {
+ return SASL_NOMECH;
+ } else {
+ *cbindingdisp = SASL_CB_DISP_WANT;
+ }
+ } else if (SASL_CB_CRITICAL(cparams)) {
+ *cbindingdisp = SASL_CB_DISP_USED;
+ }
+ }
+
+ return SASL_OK;
+}
+
+/* select a mechanism for a connection
+ * mechlist -- mechanisms server has available (punctuation ignored)
+ * secret -- optional secret from previous session
+ * output:
+ * prompt_need -- on SASL_INTERACT, list of prompts needed to continue
+ * clientout -- the initial client response to send to the server
+ * mech -- set to mechanism name
+ *
+ * Returns:
+ * SASL_OK -- success
+ * SASL_NOMEM -- not enough memory
+ * SASL_NOMECH -- no mechanism meets requested properties
+ * SASL_INTERACT -- user interaction needed to fill in prompt_need list
+ */
+
+/*
+ * SASL mechanism allowable characters are "AZ-_"
+ * separators can be any other characters and of any length
+ * even variable lengths between.
+ *
+ * But for convenience we accept lowercase ASCII.
+ *
+ * Apps should be encouraged to simply use space or comma space
+ * though
+ */
+int sasl_client_start(sasl_conn_t *conn,
+ const char *mechlist,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ const char **mech)
+{
+ sasl_client_conn_t *c_conn = (sasl_client_conn_t *) conn;
+ char *ordered_mechs = NULL, *name;
+ cmechanism_t *m = NULL, *bestm = NULL;
+ size_t i, list_len, name_len;
+ sasl_ssf_t minssf = 0;
+ int result, server_can_cb = 0;
+ sasl_cbinding_disp_t cbindingdisp;
+ sasl_cbinding_disp_t cur_cbindingdisp;
+ sasl_cbinding_disp_t best_cbindingdisp = SASL_CB_DISP_NONE;
+
+ if (_sasl_client_active == 0) return SASL_NOTINIT;
+
+ if (!conn) return SASL_BADPARAM;
+
+ /* verify parameters */
+ if (mechlist == NULL) {
+ PARAMERROR(conn);
+ }
+
+ /* if prompt_need != NULL we've already been here
+ and just need to do the continue step again */
+
+ /* do a step */
+ /* FIXME: Hopefully they only give us our own prompt_need back */
+ if (prompt_need && *prompt_need != NULL) {
+ goto dostep;
+ }
+
+ if (conn->props.min_ssf < conn->external.ssf) {
+ minssf = 0;
+ } else {
+ minssf = conn->props.min_ssf - conn->external.ssf;
+ }
+
+ /* Order mechanisms so -PLUS are preferred */
+ result = _sasl_client_order_mechs(c_conn->cparams->utils,
+ mechlist,
+ SASL_CB_PRESENT(c_conn->cparams),
+ &ordered_mechs,
+ &list_len,
+ &server_can_cb);
+ if (result != 0)
+ goto done;
+
+ /*
+ * Determine channel binding disposition based on whether we
+ * are doing mechanism negotiation and whether server supports
+ * channel bindings.
+ */
+ result = _sasl_cbinding_disp(c_conn->cparams,
+ (list_len > 1),
+ server_can_cb,
+ &cbindingdisp);
+ if (result != 0)
+ goto done;
+
+ /* for each mechanism in client's list */
+ for (m = c_conn->mech_list; !bestm && m != NULL; m = m->next) {
+
+ for (i = 0, name = ordered_mechs; i < list_len; i++, name += name_len + 1) {
+ unsigned myflags;
+ int plus;
+
+ name_len = strlen(name);
+
+ if (!_sasl_is_equal_mech(name, m->m.plug->mech_name, name_len, &plus)) {
+ continue;
+ }
+
+ /* Do we have the prompts for it? */
+ if (!have_prompts(conn, m->m.plug))
+ break;
+
+ /* Is it strong enough? */
+ if (minssf > m->m.plug->max_ssf)
+ break;
+
+ myflags = conn->props.security_flags;
+
+ /* if there's an external layer with a better SSF then this is no
+ * longer considered a plaintext mechanism
+ */
+ if ((conn->props.min_ssf <= conn->external.ssf) &&
+ (conn->external.ssf > 1)) {
+ myflags &= ~SASL_SEC_NOPLAINTEXT;
+ }
+
+ /* Does it meet our security properties? */
+ if (((myflags ^ m->m.plug->security_flags) & myflags) != 0) {
+ break;
+ }
+
+ /* Can we meet it's features? */
+ if (cbindingdisp == SASL_CB_DISP_USED &&
+ !(m->m.plug->features & SASL_FEAT_CHANNEL_BINDING)) {
+ break;
+ }
+
+ if ((m->m.plug->features & SASL_FEAT_NEEDSERVERFQDN)
+ && !conn->serverFQDN) {
+ break;
+ }
+
+ /* Can it meet our features? */
+ if ((conn->flags & SASL_NEED_PROXY) &&
+ !(m->m.plug->features & SASL_FEAT_ALLOWS_PROXY)) {
+ break;
+ }
+
+ if ((conn->flags & SASL_NEED_HTTP) &&
+ !(m->m.plug->features & SASL_FEAT_SUPPORTS_HTTP)) {
+ break;
+ }
+
+ if (SASL_CB_PRESENT(c_conn->cparams) && plus) {
+ cur_cbindingdisp = SASL_CB_DISP_USED;
+ } else {
+ cur_cbindingdisp = cbindingdisp;
+ }
+
+ if (mech) {
+ *mech = m->m.plug->mech_name;
+ }
+
+ /* Since the list of client mechs is ordered by preference/strength,
+ the first mech in our list that is available on the server and
+ meets our security properties and features is the "best" */
+ best_cbindingdisp = cur_cbindingdisp;
+ bestm = m;
+ break;
+ }
+ }
+
+ if (bestm == NULL) {
+ sasl_seterror(conn, 0, "No worthy mechs found");
+ result = SASL_NOMECH;
+ goto done;
+ }
+
+ /* make (the rest of) cparams */
+ c_conn->cparams->service = conn->service;
+ c_conn->cparams->servicelen = (unsigned) strlen(conn->service);
+
+ if (conn->serverFQDN) {
+ c_conn->cparams->serverFQDN = conn->serverFQDN;
+ c_conn->cparams->slen = (unsigned) strlen(conn->serverFQDN);
+ }
+
+ c_conn->cparams->clientFQDN = c_conn->clientFQDN;
+ c_conn->cparams->clen = (unsigned) strlen(c_conn->clientFQDN);
+
+ c_conn->cparams->external_ssf = conn->external.ssf;
+ c_conn->cparams->props = conn->props;
+ c_conn->cparams->cbindingdisp = best_cbindingdisp;
+ c_conn->mech = bestm;
+
+ /* init that plugin */
+ result = c_conn->mech->m.plug->mech_new(c_conn->mech->m.plug->glob_context,
+ c_conn->cparams,
+ &(conn->context));
+ if (result != SASL_OK) goto done;
+
+ /* do a step -- but only if we can do a client-send-first */
+ dostep:
+ if(clientout) {
+ if(c_conn->mech->m.plug->features & SASL_FEAT_SERVER_FIRST) {
+ *clientout = NULL;
+ *clientoutlen = 0;
+ result = SASL_CONTINUE;
+ } else {
+ result = sasl_client_step(conn, NULL, 0, prompt_need,
+ clientout, clientoutlen);
+ }
+ }
+ else
+ result = SASL_CONTINUE;
+
+ done:
+ if (ordered_mechs != NULL)
+ c_conn->cparams->utils->free(ordered_mechs);
+ RETURN(conn, result);
+}
+
+/* do a single authentication step.
+ * serverin -- the server message received by the client, MUST have a NUL
+ * sentinel, not counted by serverinlen
+ * output:
+ * prompt_need -- on SASL_INTERACT, list of prompts needed to continue
+ * clientout -- the client response to send to the server
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_INTERACT -- user interaction needed to fill in prompt_need list
+ * SASL_BADPROT -- server protocol incorrect/cancelled
+ * SASL_BADSERV -- server failed mutual auth
+ */
+
+int sasl_client_step(sasl_conn_t *conn,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen)
+{
+ sasl_client_conn_t *c_conn= (sasl_client_conn_t *) conn;
+ int result;
+
+ if (_sasl_client_active == 0) return SASL_NOTINIT;
+ if (!conn) return SASL_BADPARAM;
+
+ /* check parameters */
+ if ((serverin==NULL) && (serverinlen>0))
+ PARAMERROR(conn);
+
+ /* 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 client step after doneflag");
+ return SASL_FAIL;
+ }
+
+ if(clientout) *clientout = NULL;
+ if(clientoutlen) *clientoutlen = 0;
+
+ /* do a step */
+ result = c_conn->mech->m.plug->mech_step(conn->context,
+ c_conn->cparams,
+ serverin,
+ serverinlen,
+ prompt_need,
+ clientout, clientoutlen,
+ &conn->oparams);
+
+ if (result == SASL_OK) {
+ /* So we're done on this end, but if both
+ * 1. the mech does server-send-last
+ * 2. the protocol does not
+ * we need to return no data */
+ if(!*clientout && !(conn->flags & SASL_SUCCESS_DATA)) {
+ *clientout = "";
+ *clientoutlen = 0;
+ }
+
+ 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");
+ result = SASL_BADPROT;
+ }
+ }
+
+ RETURN(conn,result);
+}
+
+/* returns the length of all the mechanisms
+ * added up
+ */
+
+static unsigned mech_names_len(cmechanism_t *mech_list)
+{
+ cmechanism_t *listptr;
+ unsigned result = 0;
+
+ for (listptr = mech_list;
+ listptr;
+ listptr = listptr->next)
+ result += (unsigned) strlen(listptr->m.plug->mech_name);
+
+ return result;
+}
+
+
+int _sasl_client_listmech(sasl_conn_t *conn,
+ const char *prefix,
+ const char *sep,
+ const char *suffix,
+ const char **result,
+ unsigned *plen,
+ int *pcount)
+{
+ sasl_client_conn_t *c_conn = (sasl_client_conn_t *)conn;
+ cmechanism_t *m = NULL;
+ sasl_ssf_t minssf = 0;
+ int ret;
+ size_t resultlen;
+ int flag;
+ const char *mysep;
+
+ if (_sasl_client_active == 0) return SASL_NOTINIT;
+ if (!conn) return SASL_BADPARAM;
+ if (conn->type != SASL_CONN_CLIENT) PARAMERROR(conn);
+
+ if (! result)
+ PARAMERROR(conn);
+
+ if (plen != NULL)
+ *plen = 0;
+ if (pcount != NULL)
+ *pcount = 0;
+
+ if (sep) {
+ mysep = sep;
+ } else {
+ mysep = " ";
+ }
+
+ if (conn->props.min_ssf < conn->external.ssf) {
+ minssf = 0;
+ } else {
+ minssf = conn->props.min_ssf - conn->external.ssf;
+ }
+
+ if (!c_conn->mech_list || c_conn->mech_length <= 0) {
+ INTERROR(conn, SASL_NOMECH);
+ }
+
+ resultlen = (prefix ? strlen(prefix) : 0)
+ + (strlen(mysep) * (c_conn->mech_length - 1))
+ + mech_names_len(c_conn->mech_list)
+ + (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';
+ }
+
+ flag = 0;
+ for (m = c_conn->mech_list; m != NULL; m = m->next) {
+ /* do we have the prompts for it? */
+ if (!have_prompts(conn, m->m.plug)) {
+ continue;
+ }
+
+ /* is it strong enough? */
+ if (minssf > m->m.plug->max_ssf) {
+ continue;
+ }
+
+ /* does it meet our security properties? */
+ if (((conn->props.security_flags ^ m->m.plug->security_flags)
+ & conn->props.security_flags) != 0) {
+ continue;
+ }
+
+ /* Can we meet it's features? */
+ if ((m->m.plug->features & SASL_FEAT_NEEDSERVERFQDN)
+ && !conn->serverFQDN) {
+ continue;
+ }
+
+ /* Can it meet our features? */
+ if ((conn->flags & SASL_NEED_PROXY) &&
+ !(m->m.plug->features & SASL_FEAT_ALLOWS_PROXY)) {
+ continue;
+ }
+
+ /* Okay, we like it, add it to the list! */
+
+ if (pcount != NULL)
+ (*pcount)++;
+
+ /* print seperator */
+ if (flag) {
+ strcat(conn->mechlist_buf, mysep);
+ } else {
+ flag = 1;
+ }
+
+ /* now print the mechanism name */
+ strcat(conn->mechlist_buf, m->m.plug->mech_name);
+ }
+
+ 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_client_mechs(void)
+{
+ cmechanism_t *listptr;
+ sasl_string_list_t *retval = NULL, *next=NULL;
+
+ if(!_sasl_client_active) return NULL;
+
+ /* make list */
+ for (listptr = cmechlist->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;
+}
+
+
+
+
+/* It would be nice if we can show other information like Author, Company, Year, plugin version */
+static void
+_sasl_print_mechanism (
+ client_sasl_mechanism_t *m,
+ sasl_info_callback_stage_t stage,
+ void *rock __attribute__((unused))
+)
+{
+ char delimiter;
+
+ if (stage == SASL_INFO_LIST_START) {
+ printf ("List of client plugins follows\n");
+ return;
+ } else if (stage == SASL_INFO_LIST_END) {
+ return;
+ }
+
+ /* Process the mechanism */
+ printf ("Plugin \"%s\" ", m->plugname);
+
+ /* There is no delay loading for client side plugins */
+ printf ("[loaded]");
+
+ printf (", \tAPI version: %d\n", m->version);
+
+ if (m->plug != NULL) {
+ printf ("\tSASL mechanism: %s, best SSF: %d\n",
+ m->plug->mech_name,
+ m->plug->max_ssf);
+
+ 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 = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_GSS_FRAMING) {
+ printf ("%cGSS_FRAMING", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_CHANNEL_BINDING) {
+ printf ("%cCHANNEL_BINDING", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_SUPPORTS_HTTP) {
+ printf ("%cSUPPORTS_HTTP", delimiter);
+ delimiter = '|';
+ }
+ }
+
+/* Delay loading is not supported for the client side plugins:
+ if (m->f) {
+ printf ("\n\twill be loaded from \"%s\"", m->f);
+ }
+ */
+
+ printf ("\n");
+}
+
+
+/* Dump information about available client plugins */
+int sasl_client_plugin_info (
+ const char *c_mech_list, /* space separated mechanism list or NULL for ALL */
+ sasl_client_info_callback_t *info_cb,
+ void *info_cb_rock
+)
+{
+ cmechanism_t *m;
+ client_sasl_mechanism_t plug_data;
+ char * cur_mech;
+ char * mech_list = NULL;
+ char * p;
+
+ if (info_cb == NULL) {
+ info_cb = _sasl_print_mechanism;
+ }
+
+ if (cmechlist != NULL) {
+ info_cb (NULL, SASL_INFO_LIST_START, info_cb_rock);
+
+ if (c_mech_list == NULL) {
+ m = cmechlist->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 = cmechlist->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);
+}
diff --git a/contrib/libs/sasl/lib/common.c b/contrib/libs/sasl/lib/common.c
new file mode 100644
index 0000000000..d9104c8956
--- /dev/null
+++ b/contrib/libs/sasl/lib/common.c
@@ -0,0 +1,2674 @@
+/* common.c - Functions that are common to server and clinet
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#ifdef HAVE_SYSLOG
+#include <syslog.h>
+#endif
+#include <stdarg.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslutil.h>
+#include <saslplug.h>
+#include "saslint.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+static const char *implementation_string = "Cyrus SASL";
+
+#define VSTR0(maj, min, step) #maj "." #min "." #step
+#define VSTR(maj, min, step) VSTR0(maj, min, step)
+#define SASL_VERSION_STRING VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \
+ SASL_VERSION_STEP)
+
+static int _sasl_getpath(void *context __attribute__((unused)), const char **path);
+static int _sasl_getpath_simple(void *context __attribute__((unused)), const char **path);
+static int _sasl_getconfpath(void *context __attribute__((unused)), char ** path);
+static int _sasl_getconfpath_simple(void *context __attribute__((unused)), const char **path);
+
+#if !defined(WIN32)
+static char * _sasl_get_default_unix_path(void *context __attribute__((unused)),
+ char * env_var_name, char * default_value);
+#else
+/* NB: Always returned allocated value */
+static char * _sasl_get_default_win_path(void *context __attribute__((unused)),
+ TCHAR * reg_attr_name, char * default_value);
+#endif
+
+
+/* It turns out to be convenient to have a shared sasl_utils_t */
+const sasl_utils_t *sasl_global_utils = NULL;
+
+/* Should be a null-terminated array that lists the available mechanisms */
+static char **global_mech_list = NULL;
+
+void *free_mutex = NULL;
+
+int (*_sasl_client_cleanup_hook)(void) = NULL;
+int (*_sasl_server_cleanup_hook)(void) = NULL;
+int (*_sasl_client_idle_hook)(sasl_conn_t *conn) = NULL;
+int (*_sasl_server_idle_hook)(sasl_conn_t *conn) = NULL;
+
+sasl_allocation_utils_t _sasl_allocation_utils={
+ (sasl_malloc_t *) &malloc,
+ (sasl_calloc_t *) &calloc,
+ (sasl_realloc_t *) &realloc,
+ (sasl_free_t *) &free
+};
+int _sasl_allocation_locked = 0;
+
+#define SASL_ENCODEV_EXTRA 4096
+
+/* Default getpath/getconfpath callbacks. These can be edited by sasl_set_path(). */
+static sasl_callback_t default_getpath_cb = {
+ SASL_CB_GETPATH, (sasl_callback_ft)&_sasl_getpath, NULL
+};
+static sasl_callback_t default_getconfpath_cb = {
+ SASL_CB_GETCONFPATH, (sasl_callback_ft)&_sasl_getconfpath, NULL
+};
+
+static char * default_plugin_path = NULL;
+static char * default_conf_path = NULL;
+
+static int _sasl_global_getopt(void *context,
+ const char *plugin_name,
+ const char *option,
+ const char ** result,
+ unsigned *len);
+
+/* Intenal mutex functions do as little as possible (no thread protection) */
+static void *sasl_mutex_alloc(void)
+{
+ return (void *)0x1;
+}
+
+static int sasl_mutex_lock(void *mutex __attribute__((unused)))
+{
+ return SASL_OK;
+}
+
+static int sasl_mutex_unlock(void *mutex __attribute__((unused)))
+{
+ return SASL_OK;
+}
+
+static void sasl_mutex_free(void *mutex __attribute__((unused)))
+{
+ return;
+}
+
+sasl_mutex_utils_t _sasl_mutex_utils={
+ &sasl_mutex_alloc,
+ &sasl_mutex_lock,
+ &sasl_mutex_unlock,
+ &sasl_mutex_free
+};
+
+void sasl_set_mutex(sasl_mutex_alloc_t *n,
+ sasl_mutex_lock_t *l,
+ sasl_mutex_unlock_t *u,
+ sasl_mutex_free_t *d)
+{
+ /* Disallow mutex function changes once sasl_client_init
+ and/or sasl_server_init is called */
+ if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
+ return;
+ }
+
+ _sasl_mutex_utils.alloc=n;
+ _sasl_mutex_utils.lock=l;
+ _sasl_mutex_utils.unlock=u;
+ _sasl_mutex_utils.free=d;
+}
+
+/* copy a string to malloced memory */
+int _sasl_strdup(const char *in, char **out, size_t *outlen)
+{
+ size_t len = strlen(in);
+ if (outlen) *outlen = len;
+ *out=sasl_ALLOC((unsigned) len + 1);
+ if (! *out) return SASL_NOMEM;
+ strcpy((char *) *out, in);
+ return SASL_OK;
+}
+
+/* adds a string to the buffer; reallocing if need be */
+int _sasl_add_string(char **out, size_t *alloclen,
+ size_t *outlen, const char *add)
+{
+ size_t addlen;
+
+ if (add==NULL) add = "(null)";
+
+ addlen=strlen(add); /* only compute once */
+ if (_buf_alloc(out, alloclen, (*outlen)+addlen+1)!=SASL_OK)
+ return SASL_NOMEM;
+
+ strcpy(*out + *outlen, add);
+ *outlen += addlen;
+
+ return SASL_OK;
+}
+
+/* a simpler way to set plugin path or configuration file path
+ * without the need to set sasl_getpath_t callback.
+ *
+ * This function can be called before sasl_server_init/sasl_client_init.
+ *
+ * Don't call this function without locking in a multithreaded application.
+ */
+int sasl_set_path (int path_type, char * path)
+{
+ int result;
+
+ if (path == NULL) {
+ return (SASL_FAIL);
+ }
+
+ switch (path_type) {
+ case SASL_PATH_TYPE_PLUGIN:
+ if (default_plugin_path != NULL) {
+ sasl_FREE (default_plugin_path);
+ default_plugin_path = NULL;
+ }
+ result = _sasl_strdup (path, &default_plugin_path, NULL);
+ if (result != SASL_OK) {
+ return (result);
+ }
+
+ /* Update the default getpath_t callback */
+ default_getpath_cb.proc = (sasl_callback_ft)&_sasl_getpath_simple;
+ break;
+
+ case SASL_PATH_TYPE_CONFIG:
+ if (default_conf_path != NULL) {
+ sasl_FREE (default_conf_path);
+ default_conf_path = NULL;
+ }
+ result = _sasl_strdup (path, &default_conf_path, NULL);
+ if (result != SASL_OK) {
+ return (result);
+ }
+
+ /* Update the default getpath_t callback */
+ default_getconfpath_cb.proc = (sasl_callback_ft)&_sasl_getconfpath_simple;
+ break;
+
+ default:
+ return (SASL_FAIL);
+ }
+
+ return (SASL_OK);
+}
+
+/* return the version of the cyrus sasl library as compiled,
+ * using 32 bits: high byte is major version, second byte is minor version,
+ * low 16 bits are step #.
+ * Patch version is not available using this function,
+ * use sasl_version_info() instead.
+ */
+void sasl_version(const char **implementation, int *version)
+{
+ if(implementation) *implementation = implementation_string;
+ /* NB: the format is not the same as in SASL_VERSION_FULL */
+ if(version) *version = (SASL_VERSION_MAJOR << 24) |
+ (SASL_VERSION_MINOR << 16) |
+ (SASL_VERSION_STEP);
+}
+
+/* Extended version of sasl_version above */
+void sasl_version_info (const char **implementation, const char **version_string,
+ int *version_major, int *version_minor, int *version_step,
+ int *version_patch)
+{
+ if (implementation) *implementation = implementation_string;
+ if (version_string) *version_string = SASL_VERSION_STRING;
+ if (version_major) *version_major = SASL_VERSION_MAJOR;
+ if (version_minor) *version_minor = SASL_VERSION_MINOR;
+ if (version_step) *version_step = SASL_VERSION_STEP;
+ /* Version patch is always 0 for CMU SASL */
+ if (version_patch) *version_patch = 0;
+}
+
+/* security-encode a regular string. Mostly a wrapper for sasl_encodev */
+/* output is only valid until next call to sasl_encode or sasl_encodev */
+int sasl_encode(sasl_conn_t *conn, const char *input,
+ unsigned inputlen,
+ const char **output, unsigned *outputlen)
+{
+ int result;
+ struct iovec tmp;
+
+ if(!conn) return SASL_BADPARAM;
+ if(!input || !inputlen || !output || !outputlen)
+ PARAMERROR(conn);
+
+ /* maxoutbuf checking is done in sasl_encodev */
+
+ /* Note: We are casting a const pointer here, but it's okay
+ * because we believe people downstream of us are well-behaved, and the
+ * alternative is an absolute mess, performance-wise. */
+ tmp.iov_base = (void *)input;
+ tmp.iov_len = inputlen;
+
+ result = sasl_encodev(conn, &tmp, 1, output, outputlen);
+
+ RETURN(conn, result);
+}
+
+/* Internal function that doesn't do any verification */
+static int
+_sasl_encodev (sasl_conn_t *conn,
+ const struct iovec *invec,
+ unsigned numiov,
+ int * p_num_packets, /* number of packets generated so far */
+ const char **output, /* previous output, if *p_num_packets > 0 */
+ unsigned *outputlen)
+{
+ int result;
+ char * new_buf;
+
+ assert (conn->oparams.encode != NULL);
+
+ if (*p_num_packets == 1) {
+ /* This is the second call to this function,
+ so we need to allocate a new output buffer
+ and copy existing data there. */
+ conn->multipacket_encoded_data.curlen = *outputlen;
+ if (conn->multipacket_encoded_data.data == NULL) {
+ conn->multipacket_encoded_data.reallen =
+ conn->multipacket_encoded_data.curlen + SASL_ENCODEV_EXTRA;
+ conn->multipacket_encoded_data.data =
+ sasl_ALLOC(conn->multipacket_encoded_data.reallen + 1);
+
+ if (conn->multipacket_encoded_data.data == NULL) {
+ MEMERROR(conn);
+ }
+ } else {
+ /* A buffer left from a previous sasl_encodev call.
+ Make sure it is big enough. */
+ if (conn->multipacket_encoded_data.curlen >
+ conn->multipacket_encoded_data.reallen) {
+ conn->multipacket_encoded_data.reallen =
+ conn->multipacket_encoded_data.curlen + SASL_ENCODEV_EXTRA;
+
+ new_buf = sasl_REALLOC(conn->multipacket_encoded_data.data,
+ conn->multipacket_encoded_data.reallen + 1);
+ if (new_buf == NULL) {
+ MEMERROR(conn);
+ }
+ conn->multipacket_encoded_data.data = new_buf;
+ }
+ }
+
+ memcpy (conn->multipacket_encoded_data.data,
+ *output,
+ *outputlen);
+ }
+
+ result = conn->oparams.encode(conn->context,
+ invec,
+ numiov,
+ output,
+ outputlen);
+
+ if (*p_num_packets > 0 && result == SASL_OK) {
+ /* Is the allocated buffer big enough? If not, grow it. */
+ if ((conn->multipacket_encoded_data.curlen + *outputlen) >
+ conn->multipacket_encoded_data.reallen) {
+ conn->multipacket_encoded_data.reallen =
+ conn->multipacket_encoded_data.curlen + *outputlen;
+ new_buf = sasl_REALLOC(conn->multipacket_encoded_data.data,
+ conn->multipacket_encoded_data.reallen + 1);
+ if (new_buf == NULL) {
+ MEMERROR(conn);
+ }
+ conn->multipacket_encoded_data.data = new_buf;
+ }
+
+ /* Append new data to the end of the buffer */
+ memcpy (conn->multipacket_encoded_data.data +
+ conn->multipacket_encoded_data.curlen,
+ *output,
+ *outputlen);
+ conn->multipacket_encoded_data.curlen += *outputlen;
+
+ *output = conn->multipacket_encoded_data.data;
+ *outputlen = (unsigned)conn->multipacket_encoded_data.curlen;
+ }
+
+ (*p_num_packets)++;
+
+ RETURN(conn, result);
+}
+
+/* security-encode an iovec */
+/* output is only valid until the next call to sasl_encode or sasl_encodev */
+int sasl_encodev(sasl_conn_t *conn,
+ const struct iovec *invec,
+ unsigned numiov,
+ const char **output,
+ unsigned *outputlen)
+{
+ int result = SASL_OK;
+ unsigned i;
+ unsigned j;
+ size_t total_size = 0;
+ struct iovec *cur_invec = NULL;
+ struct iovec last_invec;
+ unsigned cur_numiov;
+ char * next_buf = NULL;
+ size_t remainder_len;
+ unsigned index_offset;
+ unsigned allocated = 0;
+ /* Number of generated SASL packets */
+ int num_packets = 0;
+
+ if (!conn) return SASL_BADPARAM;
+ if (! invec || ! output || ! outputlen || numiov < 1) {
+ PARAMERROR(conn);
+ }
+
+ if (!conn->props.maxbufsize) {
+ sasl_seterror(conn, 0,
+ "called sasl_encode[v] with application that does not support security layers");
+ return SASL_TOOWEAK;
+ }
+
+ /* If oparams.encode is NULL, this means there is no SASL security
+ layer in effect, so no SASL framing is needed. */
+ if (conn->oparams.encode == NULL) {
+ result = _iovec_to_buf(invec, numiov, &conn->encode_buf);
+ if (result != SASL_OK) INTERROR(conn, result);
+
+ *output = conn->encode_buf->data;
+ *outputlen = (unsigned) conn->encode_buf->curlen;
+
+ RETURN(conn, result);
+ }
+
+ /* This might be better to check on a per-plugin basis, but I think
+ * it's cleaner and more effective here. It also encourages plugins
+ * to be honest about what they accept */
+
+ last_invec.iov_base = NULL;
+ remainder_len = 0;
+ next_buf = NULL;
+ i = 0;
+ while (i < numiov) {
+ if ((total_size + invec[i].iov_len) > conn->oparams.maxoutbuf) {
+
+ /* CLAIM: total_size < conn->oparams.maxoutbuf */
+
+ /* Fit as many bytes in last_invec, so that we have conn->oparams.maxoutbuf
+ bytes in total. */
+ last_invec.iov_len = conn->oparams.maxoutbuf - total_size;
+ /* Point to the first byte of the current record. */
+ last_invec.iov_base = invec[i].iov_base;
+
+ /* Note that total_size < conn->oparams.maxoutbuf */
+ /* The total size of the iov is bigger then the other end can accept.
+ So we allocate a new iov that contains just enough. */
+
+ /* +1 --- for the tail record */
+ cur_numiov = i + 1;
+
+ /* +1 --- just in case we need the head record */
+ if ((cur_numiov + 1) > allocated) {
+ struct iovec *new_invec;
+
+ allocated = cur_numiov + 1;
+ new_invec = sasl_REALLOC (cur_invec, sizeof(struct iovec) * allocated);
+ if (new_invec == NULL) {
+ if (cur_invec != NULL) {
+ sasl_FREE(cur_invec);
+ }
+ MEMERROR(conn);
+ }
+ cur_invec = new_invec;
+ }
+
+ if (next_buf != NULL) {
+ cur_invec[0].iov_base = next_buf;
+ cur_invec[0].iov_len = (long)remainder_len;
+ cur_numiov++;
+ index_offset = 1;
+ } else {
+ index_offset = 0;
+ }
+
+ if (i > 0) {
+ /* Copy all previous chunks */
+ /* NOTE - The starting index in invec is always 0 */
+ for (j = 0; j < i; j++) {
+ cur_invec[j + index_offset] = invec[j];
+ }
+ }
+
+ /* Initialize the last record */
+ cur_invec[i + index_offset] = last_invec;
+
+ result = _sasl_encodev (conn,
+ cur_invec,
+ cur_numiov,
+ &num_packets,
+ output,
+ outputlen);
+
+ if (result != SASL_OK) {
+ goto cleanup;
+ }
+
+ /* Point to the first byte that wouldn't fit into
+ the conn->oparams.maxoutbuf buffer. */
+ /* Note, if next_buf points to the very end of the IOV record,
+ it will be reset to NULL below */
+ /* Note, that some platforms define iov_base as "void *",
+ thus the typecase below */
+ next_buf = (char *) last_invec.iov_base + last_invec.iov_len;
+ /* Note - remainder_len is how many bytes left to be encoded in
+ the current IOV slot. */
+ remainder_len = (total_size + invec[i].iov_len) - conn->oparams.maxoutbuf;
+
+ /* Skip all consumed IOV records */
+ invec += i + 1;
+ numiov = numiov - (i + 1);
+ i = 0;
+
+ while (remainder_len > conn->oparams.maxoutbuf) {
+ last_invec.iov_base = next_buf;
+ last_invec.iov_len = conn->oparams.maxoutbuf;
+
+ /* Note, if next_buf points to the very end of the IOV record,
+ it will be reset to NULL below */
+ /* Note, that some platforms define iov_base as "void *",
+ thus the typecase below */
+ next_buf = (char *) last_invec.iov_base + last_invec.iov_len;
+ remainder_len = remainder_len - conn->oparams.maxoutbuf;
+
+ result = _sasl_encodev (conn,
+ &last_invec,
+ 1,
+ &num_packets,
+ output,
+ outputlen);
+ if (result != SASL_OK) {
+ goto cleanup;
+ }
+ }
+
+ total_size = remainder_len;
+
+ if (remainder_len == 0) {
+ /* Just clear next_buf */
+ next_buf = NULL;
+ }
+ } else {
+ total_size += invec[i].iov_len;
+ i++;
+ }
+ }
+
+ /* CLAIM - The remaining data is shorter then conn->oparams.maxoutbuf. */
+
+ /* Force encoding of any partial buffer. Might not be optimal on the wire. */
+ if (next_buf != NULL) {
+ last_invec.iov_base = next_buf;
+ last_invec.iov_len = (long)remainder_len;
+
+ result = _sasl_encodev (conn,
+ &last_invec,
+ 1,
+ &num_packets,
+ output,
+ outputlen);
+
+ if (result != SASL_OK) {
+ goto cleanup;
+ }
+ }
+
+ if (numiov > 0) {
+ result = _sasl_encodev (conn,
+ invec,
+ numiov,
+ &num_packets,
+ output,
+ outputlen);
+ }
+
+cleanup:
+ if (cur_invec != NULL) {
+ sasl_FREE(cur_invec);
+ }
+
+ RETURN(conn, result);
+}
+
+/* output is only valid until next call to sasl_decode */
+int sasl_decode(sasl_conn_t *conn,
+ const char *input, unsigned inputlen,
+ const char **output, unsigned *outputlen)
+{
+ int result;
+
+ if(!conn) return SASL_BADPARAM;
+ if(!input || !output || !outputlen)
+ PARAMERROR(conn);
+
+ if(!conn->props.maxbufsize) {
+ sasl_seterror(conn, 0,
+ "called sasl_decode with application that does not support security layers");
+ RETURN(conn, SASL_TOOWEAK);
+ }
+
+ if(conn->oparams.decode == NULL)
+ {
+ /* Since we know how long the output is maximally, we can
+ * just allocate it to begin with, and never need another
+ * allocation! */
+
+ /* However, if they pass us more than they actually can take,
+ * we cannot help them... */
+ if(inputlen > conn->props.maxbufsize) {
+ sasl_seterror(conn, 0,
+ "input too large for default sasl_decode");
+ RETURN(conn,SASL_BUFOVER);
+ }
+
+ if(!conn->decode_buf)
+ conn->decode_buf = sasl_ALLOC(conn->props.maxbufsize + 1);
+ if(!conn->decode_buf)
+ MEMERROR(conn);
+
+ memcpy(conn->decode_buf, input, inputlen);
+ conn->decode_buf[inputlen] = '\0';
+ *output = conn->decode_buf;
+ *outputlen = inputlen;
+
+ return SASL_OK;
+ } else {
+ result = conn->oparams.decode(conn->context, input, inputlen,
+ output, outputlen);
+
+ /* NULL an empty buffer (for misbehaved applications) */
+ if (*outputlen == 0) *output = NULL;
+
+ RETURN(conn, result);
+ }
+
+ INTERROR(conn, SASL_FAIL);
+}
+
+
+void
+sasl_set_alloc(sasl_malloc_t *m,
+ sasl_calloc_t *c,
+ 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;
+ _sasl_allocation_utils.free=f;
+}
+
+void sasl_common_done(void)
+{
+ /* NOTE - the caller will need to reinitialize the values,
+ if it is going to call sasl_client_init/sasl_server_init again. */
+ if (default_plugin_path != NULL) {
+ sasl_FREE (default_plugin_path);
+ default_plugin_path = NULL;
+ }
+ if (default_conf_path != NULL) {
+ sasl_FREE (default_conf_path);
+ default_conf_path = NULL;
+ }
+
+ _sasl_canonuser_free();
+ _sasl_done_with_plugins();
+
+ sasl_MUTEX_FREE(free_mutex);
+ free_mutex = NULL;
+
+ _sasl_free_utils(&sasl_global_utils);
+
+ if (global_mech_list) {
+ sasl_FREE(global_mech_list);
+ global_mech_list = NULL;
+ }
+}
+
+/* This function is for backward compatibility */
+void sasl_done(void)
+{
+ if (_sasl_server_cleanup_hook && _sasl_server_cleanup_hook() == SASL_OK) {
+ _sasl_server_idle_hook = NULL;
+ _sasl_server_cleanup_hook = NULL;
+ }
+
+ if (_sasl_client_cleanup_hook && _sasl_client_cleanup_hook() == SASL_OK) {
+ _sasl_client_idle_hook = NULL;
+ _sasl_client_cleanup_hook = NULL;
+ }
+
+ if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
+ return;
+ }
+
+ sasl_common_done();
+}
+
+/* fills in the base sasl_conn_t info */
+int _sasl_conn_init(sasl_conn_t *conn,
+ const char *service,
+ unsigned int flags,
+ enum Sasl_conn_type type,
+ int (*idle_hook)(sasl_conn_t *conn),
+ const char *serverFQDN,
+ const char *iplocalport,
+ const char *ipremoteport,
+ const sasl_callback_t *callbacks,
+ const sasl_global_callbacks_t *global_callbacks) {
+ int result = SASL_OK;
+
+ conn->type = type;
+
+ result = _sasl_strdup(service, &conn->service, NULL);
+ if (result != SASL_OK)
+ MEMERROR(conn);
+
+ memset(&conn->oparams, 0, sizeof(sasl_out_params_t));
+ memset(&conn->external, 0, sizeof(_sasl_external_properties_t));
+
+ conn->flags = flags;
+
+ result = sasl_setprop(conn, SASL_IPLOCALPORT, iplocalport);
+ if(result != SASL_OK)
+ RETURN(conn, result);
+
+ result = sasl_setprop(conn, SASL_IPREMOTEPORT, ipremoteport);
+ if(result != SASL_OK)
+ RETURN(conn, result);
+
+ conn->encode_buf = NULL;
+ conn->context = NULL;
+ conn->secret = NULL;
+ conn->idle_hook = idle_hook;
+ conn->callbacks = callbacks;
+ conn->global_callbacks = global_callbacks;
+
+ memset(&conn->props, 0, sizeof(conn->props));
+
+ /* Start this buffer out as an empty string */
+ conn->error_code = SASL_OK;
+ conn->errdetail_buf = conn->error_buf = NULL;
+ conn->errdetail_buf_len = conn->error_buf_len = 150;
+
+ result = _buf_alloc(&conn->error_buf, &conn->error_buf_len, 150);
+ if(result != SASL_OK) MEMERROR(conn);
+ result = _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, 150);
+ if(result != SASL_OK) MEMERROR(conn);
+
+ conn->error_buf[0] = '\0';
+ conn->errdetail_buf[0] = '\0';
+
+ conn->decode_buf = NULL;
+
+ if(serverFQDN) {
+ result = _sasl_strdup(serverFQDN, &conn->serverFQDN, NULL);
+ sasl_strlower (conn->serverFQDN);
+ } else if (conn->type == SASL_CONN_SERVER) {
+ /* We can fake it because we *are* the server */
+ char name[MAXFQDNLEN];
+ memset(name, 0, sizeof(name));
+ if (get_fqhostname (name, MAXFQDNLEN, 0) != 0) {
+ return (SASL_FAIL);
+ }
+
+ result = _sasl_strdup(name, &conn->serverFQDN, NULL);
+ } else {
+ conn->serverFQDN = NULL;
+ }
+
+
+ if(result != SASL_OK) MEMERROR( conn );
+
+ RETURN(conn, SASL_OK);
+}
+
+int _sasl_common_init(sasl_global_callbacks_t *global_callbacks)
+{
+ int result;
+
+ /* The last specified global callback always wins */
+ if (sasl_global_utils != NULL) {
+ sasl_utils_t * global_utils = (sasl_utils_t *)sasl_global_utils;
+ global_utils->getopt = &_sasl_global_getopt;
+ global_utils->getopt_context = global_callbacks;
+ }
+
+ /* Do nothing if we are already initialized */
+ if (free_mutex) {
+ return SASL_OK;
+ }
+
+ /* Setup the global utilities */
+ if(!sasl_global_utils) {
+ sasl_global_utils = _sasl_alloc_utils(NULL, global_callbacks);
+ if(sasl_global_utils == NULL) return SASL_NOMEM;
+ }
+
+ /* Init the canon_user plugin */
+ result = sasl_canonuser_add_plugin("INTERNAL", internal_canonuser_init);
+ if(result != SASL_OK) return result;
+
+ if (!free_mutex) {
+ free_mutex = sasl_MUTEX_ALLOC();
+ }
+ if (!free_mutex) return SASL_FAIL;
+
+ return SASL_OK;
+}
+
+/* dispose connection state, sets it to NULL
+ * checks for pointer to NULL
+ */
+void sasl_dispose(sasl_conn_t **pconn)
+{
+ int result;
+
+ if (! pconn) return;
+ if (! *pconn) return;
+
+ /* serialize disposes. this is necessary because we can't
+ dispose of conn->mutex if someone else is locked on it */
+ if (!free_mutex) {
+ free_mutex = sasl_MUTEX_ALLOC();
+ if (!free_mutex) return;
+ }
+
+ result = sasl_MUTEX_LOCK(free_mutex);
+ if (result!=SASL_OK) return;
+
+ /* *pconn might have become NULL by now */
+ if (*pconn) {
+ (*pconn)->destroy_conn(*pconn);
+ sasl_FREE(*pconn);
+ *pconn=NULL;
+ }
+
+ sasl_MUTEX_UNLOCK(free_mutex);
+}
+
+void _sasl_conn_dispose(sasl_conn_t *conn) {
+ if (conn->serverFQDN)
+ sasl_FREE(conn->serverFQDN);
+
+ if (conn->external.auth_id)
+ sasl_FREE(conn->external.auth_id);
+
+ if(conn->encode_buf) {
+ if(conn->encode_buf->data) sasl_FREE(conn->encode_buf->data);
+ sasl_FREE(conn->encode_buf);
+ }
+
+ if(conn->error_buf)
+ sasl_FREE(conn->error_buf);
+
+ if(conn->errdetail_buf)
+ sasl_FREE(conn->errdetail_buf);
+
+ if(conn->decode_buf)
+ sasl_FREE(conn->decode_buf);
+
+ if(conn->mechlist_buf)
+ sasl_FREE(conn->mechlist_buf);
+
+ if(conn->service)
+ sasl_FREE(conn->service);
+
+ if (conn->multipacket_encoded_data.data) {
+ sasl_FREE(conn->multipacket_encoded_data.data);
+ }
+
+ /* oparams sub-members should be freed by the plugin, in so much
+ * as they were allocated by the plugin */
+}
+
+
+/* get property from SASL connection state
+ * propnum -- property number
+ * pvalue -- pointer to value
+ * returns:
+ * SASL_OK -- no error
+ * SASL_NOTDONE -- property not available yet
+ * SASL_BADPARAM -- bad property number or SASL context is NULL
+ */
+int sasl_getprop(sasl_conn_t *conn, int propnum, const void **pvalue)
+{
+ int result = SASL_OK;
+ sasl_getopt_t *getopt;
+ void *context;
+
+ if (! conn) return SASL_BADPARAM;
+ if (! pvalue) PARAMERROR(conn);
+
+ switch(propnum)
+ {
+ case SASL_SSF:
+ *(sasl_ssf_t **)pvalue= &conn->oparams.mech_ssf;
+ break;
+ case SASL_MAXOUTBUF:
+ *(unsigned **)pvalue = &conn->oparams.maxoutbuf;
+ break;
+ case SASL_GETOPTCTX:
+ result = _sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context);
+ if(result != SASL_OK) break;
+
+ *(void **)pvalue = context;
+ break;
+ case SASL_CALLBACK:
+ *(const sasl_callback_t **)pvalue = conn->callbacks;
+ break;
+ case SASL_IPLOCALPORT:
+ if(conn->got_ip_local)
+ *(const char **)pvalue = conn->iplocalport;
+ else {
+ *(const char **)pvalue = NULL;
+ result = SASL_NOTDONE;
+ }
+ break;
+ case SASL_IPREMOTEPORT:
+ if(conn->got_ip_remote)
+ *(const char **)pvalue = conn->ipremoteport;
+ else {
+ *(const char **)pvalue = NULL;
+ result = SASL_NOTDONE;
+ }
+ break;
+ case SASL_USERNAME:
+ if(! conn->oparams.user)
+ result = SASL_NOTDONE;
+ else
+ *((const char **)pvalue) = conn->oparams.user;
+ break;
+ case SASL_AUTHUSER:
+ if(! conn->oparams.authid)
+ result = SASL_NOTDONE;
+ else
+ *((const char **)pvalue) = conn->oparams.authid;
+ break;
+ case SASL_APPNAME:
+ /* Currently we only support server side contexts, but we should
+ be able to extend this to support client side contexts as well */
+ if(conn->type != SASL_CONN_SERVER) result = SASL_BADPROT;
+ else
+ *((const char **)pvalue) = ((sasl_server_conn_t *)conn)->sparams->appname;
+ break;
+ case SASL_SERVERFQDN:
+ *((const char **)pvalue) = conn->serverFQDN;
+ break;
+ case SASL_DEFUSERREALM:
+ if(conn->type != SASL_CONN_SERVER) result = SASL_BADPROT;
+ else
+ *((const char **)pvalue) = ((sasl_server_conn_t *)conn)->user_realm;
+ break;
+ case SASL_SERVICE:
+ *((const char **)pvalue) = conn->service;
+ break;
+ case SASL_AUTHSOURCE: /* name of plugin (not name of mech) */
+ if(conn->type == SASL_CONN_CLIENT) {
+ if(!((sasl_client_conn_t *)conn)->mech) {
+ result = SASL_NOTDONE;
+ break;
+ }
+ *((const char **)pvalue) =
+ ((sasl_client_conn_t *)conn)->mech->m.plugname;
+ } else if (conn->type == SASL_CONN_SERVER) {
+ if(!((sasl_server_conn_t *)conn)->mech) {
+ result = SASL_NOTDONE;
+ break;
+ }
+ *((const char **)pvalue) =
+ ((sasl_server_conn_t *)conn)->mech->m.plugname;
+ } else {
+ result = SASL_BADPARAM;
+ }
+ break;
+ case SASL_MECHNAME: /* name of mech */
+ if(conn->type == SASL_CONN_CLIENT) {
+ if(!((sasl_client_conn_t *)conn)->mech) {
+ result = SASL_NOTDONE;
+ break;
+ }
+ *((const char **)pvalue) =
+ ((sasl_client_conn_t *)conn)->mech->m.plug->mech_name;
+ } else if (conn->type == SASL_CONN_SERVER) {
+ if(!((sasl_server_conn_t *)conn)->mech) {
+ result = SASL_NOTDONE;
+ break;
+ }
+ *((const char **)pvalue) =
+ ((sasl_server_conn_t *)conn)->mech->m.plug->mech_name;
+ } else {
+ result = SASL_BADPARAM;
+ }
+
+ if(!(*pvalue) && result == SASL_OK) result = SASL_NOTDONE;
+ break;
+ case SASL_PLUGERR:
+ *((const char **)pvalue) = conn->error_buf;
+ break;
+ case SASL_DELEGATEDCREDS:
+ /* We can't really distinguish between "no delegated credentials"
+ and "authentication not finished" */
+ if(! conn->oparams.client_creds)
+ result = SASL_NOTDONE;
+ else
+ *((const char **)pvalue) = conn->oparams.client_creds;
+ break;
+ case SASL_GSS_PEER_NAME:
+ if(! conn->oparams.gss_peer_name)
+ result = SASL_NOTDONE;
+ else
+ *((const char **)pvalue) = conn->oparams.gss_peer_name;
+ break;
+ case SASL_GSS_LOCAL_NAME:
+ if(! conn->oparams.gss_local_name)
+ result = SASL_NOTDONE;
+ else
+ *((const char **)pvalue) = conn->oparams.gss_local_name;
+ break;
+ case SASL_SSF_EXTERNAL:
+ *((const sasl_ssf_t **)pvalue) = &conn->external.ssf;
+ break;
+ case SASL_AUTH_EXTERNAL:
+ *((const char **)pvalue) = conn->external.auth_id;
+ break;
+ case SASL_SEC_PROPS:
+ *((const sasl_security_properties_t **)pvalue) = &conn->props;
+ break;
+ case SASL_GSS_CREDS:
+ if(conn->type == SASL_CONN_CLIENT)
+ *(const void **)pvalue =
+ ((sasl_client_conn_t *)conn)->cparams->gss_creds;
+ else
+ *(const void **)pvalue =
+ ((sasl_server_conn_t *)conn)->sparams->gss_creds;
+ break;
+ case SASL_HTTP_REQUEST: {
+ if (conn->type == SASL_CONN_SERVER)
+ *(const sasl_http_request_t **)pvalue =
+ ((sasl_server_conn_t *)conn)->sparams->http_request;
+ else
+ *(const sasl_http_request_t **)pvalue =
+ ((sasl_client_conn_t *)conn)->cparams->http_request;
+ break;
+ }
+ default:
+ result = SASL_BADPARAM;
+ }
+
+ if(result == SASL_BADPARAM) {
+ PARAMERROR(conn);
+ } else if(result == SASL_NOTDONE) {
+ sasl_seterror(conn, SASL_NOLOG,
+ "Information that was requested is not yet available.");
+ RETURN(conn, result);
+ } else if(result != SASL_OK) {
+ INTERROR(conn, result);
+ } else
+ RETURN(conn, result);
+}
+
+/* set property in SASL connection state
+ * returns:
+ * SASL_OK -- value set
+ * SASL_BADPARAM -- invalid property or value
+ */
+int sasl_setprop(sasl_conn_t *conn, int propnum, const void *value)
+{
+ int result = SASL_OK;
+ char *str;
+
+ /* make sure the sasl context is valid */
+ if (!conn)
+ return SASL_BADPARAM;
+
+ switch(propnum)
+ {
+ case SASL_SSF_EXTERNAL:
+ conn->external.ssf = *((sasl_ssf_t *)value);
+ if(conn->type == SASL_CONN_SERVER) {
+ ((sasl_server_conn_t*)conn)->sparams->external_ssf =
+ conn->external.ssf;
+ } else {
+ ((sasl_client_conn_t*)conn)->cparams->external_ssf =
+ conn->external.ssf;
+ }
+ break;
+
+ case SASL_AUTH_EXTERNAL:
+ if(value && strlen(value)) {
+ result = _sasl_strdup(value, &str, NULL);
+ if(result != SASL_OK) MEMERROR(conn);
+ } else {
+ str = NULL;
+ }
+
+ if(conn->external.auth_id)
+ sasl_FREE(conn->external.auth_id);
+
+ conn->external.auth_id = str;
+
+ break;
+
+ case SASL_DEFUSERREALM:
+ if(conn->type != SASL_CONN_SERVER) {
+ sasl_seterror(conn, 0, "Tried to set realm on non-server connection");
+ result = SASL_BADPROT;
+ break;
+ }
+
+ if(value && strlen(value)) {
+ result = _sasl_strdup(value, &str, NULL);
+ if(result != SASL_OK) MEMERROR(conn);
+ } else {
+ PARAMERROR(conn);
+ }
+
+ if(((sasl_server_conn_t *)conn)->user_realm)
+ sasl_FREE(((sasl_server_conn_t *)conn)->user_realm);
+
+ ((sasl_server_conn_t *)conn)->user_realm = str;
+ ((sasl_server_conn_t *)conn)->sparams->user_realm = str;
+
+ break;
+
+ case SASL_SEC_PROPS:
+ {
+ sasl_security_properties_t *props = (sasl_security_properties_t *)value;
+
+ if(props->maxbufsize == 0 && props->min_ssf != 0) {
+ sasl_seterror(conn, 0,
+ "Attempt to disable security layers (maxoutbuf == 0) with min_ssf > 0");
+ RETURN(conn, SASL_TOOWEAK);
+ }
+
+ conn->props = *props;
+
+ if(conn->type == SASL_CONN_SERVER) {
+ ((sasl_server_conn_t*)conn)->sparams->props = *props;
+ } else {
+ ((sasl_client_conn_t*)conn)->cparams->props = *props;
+ }
+
+ break;
+ }
+
+ case SASL_IPREMOTEPORT:
+ {
+ const char *ipremoteport = (const char *)value;
+ if(!value) {
+ conn->got_ip_remote = 0;
+ } else if (_sasl_ipfromstring(ipremoteport, NULL, 0)
+ != SASL_OK) {
+ sasl_seterror(conn, 0, "Bad IPREMOTEPORT value");
+ RETURN(conn, SASL_BADPARAM);
+ } else {
+ strcpy(conn->ipremoteport, ipremoteport);
+ conn->got_ip_remote = 1;
+ }
+
+ if(conn->got_ip_remote) {
+ if(conn->type == SASL_CONN_CLIENT) {
+ ((sasl_client_conn_t *)conn)->cparams->ipremoteport
+ = conn->ipremoteport;
+ ((sasl_client_conn_t *)conn)->cparams->ipremlen =
+ (unsigned) strlen(conn->ipremoteport);
+ } else if (conn->type == SASL_CONN_SERVER) {
+ ((sasl_server_conn_t *)conn)->sparams->ipremoteport
+ = conn->ipremoteport;
+ ((sasl_server_conn_t *)conn)->sparams->ipremlen =
+ (unsigned) strlen(conn->ipremoteport);
+ }
+ } else {
+ if(conn->type == SASL_CONN_CLIENT) {
+ ((sasl_client_conn_t *)conn)->cparams->ipremoteport
+ = NULL;
+ ((sasl_client_conn_t *)conn)->cparams->ipremlen = 0;
+ } else if (conn->type == SASL_CONN_SERVER) {
+ ((sasl_server_conn_t *)conn)->sparams->ipremoteport
+ = NULL;
+ ((sasl_server_conn_t *)conn)->sparams->ipremlen = 0;
+ }
+ }
+
+ break;
+ }
+
+ case SASL_IPLOCALPORT:
+ {
+ const char *iplocalport = (const char *)value;
+ if(!value) {
+ conn->got_ip_local = 0;
+ } else if (_sasl_ipfromstring(iplocalport, NULL, 0)
+ != SASL_OK) {
+ sasl_seterror(conn, 0, "Bad IPLOCALPORT value");
+ RETURN(conn, SASL_BADPARAM);
+ } else {
+ strcpy(conn->iplocalport, iplocalport);
+ conn->got_ip_local = 1;
+ }
+
+ if(conn->got_ip_local) {
+ if(conn->type == SASL_CONN_CLIENT) {
+ ((sasl_client_conn_t *)conn)->cparams->iplocalport
+ = conn->iplocalport;
+ ((sasl_client_conn_t *)conn)->cparams->iploclen
+ = (unsigned) strlen(conn->iplocalport);
+ } else if (conn->type == SASL_CONN_SERVER) {
+ ((sasl_server_conn_t *)conn)->sparams->iplocalport
+ = conn->iplocalport;
+ ((sasl_server_conn_t *)conn)->sparams->iploclen
+ = (unsigned) strlen(conn->iplocalport);
+ }
+ } else {
+ if(conn->type == SASL_CONN_CLIENT) {
+ ((sasl_client_conn_t *)conn)->cparams->iplocalport
+ = NULL;
+ ((sasl_client_conn_t *)conn)->cparams->iploclen = 0;
+ } else if (conn->type == SASL_CONN_SERVER) {
+ ((sasl_server_conn_t *)conn)->sparams->iplocalport
+ = NULL;
+ ((sasl_server_conn_t *)conn)->sparams->iploclen = 0;
+ }
+ }
+ break;
+ }
+
+ case SASL_APPNAME:
+ /* Currently we only support server side contexts, but we should
+ be able to extend this to support client side contexts as well */
+ if(conn->type != SASL_CONN_SERVER) {
+ sasl_seterror(conn, 0, "Tried to set application name on non-server connection");
+ result = SASL_BADPROT;
+ break;
+ }
+
+ if(((sasl_server_conn_t *)conn)->appname) {
+ sasl_FREE(((sasl_server_conn_t *)conn)->appname);
+ ((sasl_server_conn_t *)conn)->appname = NULL;
+ }
+
+ if(value && strlen(value)) {
+ result = _sasl_strdup(value,
+ &(((sasl_server_conn_t *)conn)->appname),
+ NULL);
+ if(result != SASL_OK) MEMERROR(conn);
+ ((sasl_server_conn_t *)conn)->sparams->appname =
+ ((sasl_server_conn_t *)conn)->appname;
+ ((sasl_server_conn_t *)conn)->sparams->applen =
+ (unsigned) strlen(((sasl_server_conn_t *)conn)->appname);
+ } else {
+ ((sasl_server_conn_t *)conn)->sparams->appname = NULL;
+ ((sasl_server_conn_t *)conn)->sparams->applen = 0;
+ }
+ break;
+
+ case SASL_GSS_CREDS:
+ if(conn->type == SASL_CONN_CLIENT)
+ ((sasl_client_conn_t *)conn)->cparams->gss_creds = value;
+ else
+ ((sasl_server_conn_t *)conn)->sparams->gss_creds = value;
+ break;
+
+ case SASL_CHANNEL_BINDING: {
+ const struct sasl_channel_binding *cb = (const struct sasl_channel_binding *)value;
+
+ if (conn->type == SASL_CONN_SERVER)
+ ((sasl_server_conn_t *)conn)->sparams->cbinding = cb;
+ else
+ ((sasl_client_conn_t *)conn)->cparams->cbinding = cb;
+ break;
+ }
+
+ case SASL_HTTP_REQUEST: {
+ const sasl_http_request_t *req = (const sasl_http_request_t *)value;
+
+ if (conn->type == SASL_CONN_SERVER)
+ ((sasl_server_conn_t *)conn)->sparams->http_request = req;
+ else
+ ((sasl_client_conn_t *)conn)->cparams->http_request = req;
+ break;
+ }
+
+ default:
+ sasl_seterror(conn, 0, "Unknown parameter type");
+ result = SASL_BADPARAM;
+ }
+
+ RETURN(conn, result);
+}
+
+/* this is apparently no longer a user function */
+static int sasl_usererr(int saslerr)
+{
+ /* Hide the difference in a username failure and a password failure */
+ if (saslerr == SASL_NOUSER)
+ return SASL_BADAUTH;
+
+ /* otherwise return the error given; no transform necessary */
+ return saslerr;
+}
+
+const char *sasl_errstring(int saslerr,
+ const char *langlist __attribute__((unused)),
+ const char **outlang)
+{
+ if (outlang) *outlang="en-us";
+
+ switch(saslerr)
+ {
+ case SASL_CONTINUE: return "another step is needed in authentication";
+ case SASL_OK: return "successful result";
+ case SASL_FAIL: return "generic failure";
+ case SASL_NOMEM: return "no memory available";
+ case SASL_BUFOVER: return "overflowed buffer";
+ case SASL_NOMECH: return "no mechanism available";
+ case SASL_BADPROT: return "bad protocol / cancel";
+ case SASL_NOTDONE: return "can't request information until later in exchange";
+ case SASL_BADPARAM: return "invalid parameter supplied";
+ case SASL_TRYAGAIN: return "transient failure (e.g., weak key)";
+ case SASL_BADMAC: return "integrity check failed";
+ case SASL_NOTINIT: return "SASL library is not initialized";
+ /* -- client only codes -- */
+ case SASL_INTERACT: return "needs user interaction";
+ case SASL_BADSERV: return "server failed mutual authentication step";
+ case SASL_WRONGMECH: return "mechanism doesn't support requested feature";
+ /* -- server only codes -- */
+ case SASL_BADAUTH: return "authentication failure";
+ case SASL_NOAUTHZ: return "authorization failure";
+ case SASL_TOOWEAK: return "mechanism too weak for this user";
+ case SASL_ENCRYPT: return "encryption needed to use mechanism";
+ case SASL_TRANS: return "One time use of a plaintext password will enable requested mechanism for user";
+ case SASL_EXPIRED: return "passphrase expired, has to be reset";
+ case SASL_DISABLED: return "account disabled";
+ case SASL_NOUSER: return "user not found";
+ case SASL_BADVERS: return "version mismatch with plug-in";
+ case SASL_UNAVAIL: return "remote authentication server unavailable";
+ case SASL_NOVERIFY: return "user exists, but no verifier for user";
+ case SASL_PWLOCK: return "passphrase locked";
+ case SASL_NOCHANGE: return "requested change was not needed";
+ case SASL_WEAKPASS: return "passphrase is too weak for security policy";
+ case SASL_NOUSERPASS: return "user supplied passwords are not permitted";
+ case SASL_NEED_OLD_PASSWD: return "sasl_setpass needs old password in order "
+ "to perform password change";
+ case SASL_CONSTRAINT_VIOLAT: return "sasl_setpass can't store a property because "
+ "of a constraint violation";
+ case SASL_BADBINDING: return "channel binding failure";
+ case SASL_CONFIGERR: return "error when parsing configuration file";
+
+ default: return "undefined error!";
+ }
+
+}
+
+/* Return the sanitized error detail about the last error that occured for
+ * a connection */
+const char *sasl_errdetail(sasl_conn_t *conn)
+{
+ unsigned need_len;
+ const char *errstr;
+ char leader[128];
+
+ if(!conn) return NULL;
+
+ errstr = sasl_errstring(conn->error_code, NULL, NULL);
+ snprintf(leader,128,"SASL(%d): %s: ",
+ sasl_usererr(conn->error_code), errstr);
+
+ need_len = (unsigned) (strlen(leader) + strlen(conn->error_buf) + 12);
+ if (_buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, need_len) != SASL_OK) {
+ return NULL;
+ }
+
+ snprintf(conn->errdetail_buf, need_len, "%s%s", leader, conn->error_buf);
+
+ return conn->errdetail_buf;
+}
+
+
+/* Note that this needs the global callbacks, so if you don't give getcallbacks
+ * a sasl_conn_t, you're going to need to pass it yourself (or else we couldn't
+ * have client and server at the same time */
+static int _sasl_global_getopt(void *context,
+ const char *plugin_name,
+ const char *option,
+ const char ** result,
+ unsigned *len)
+{
+ const sasl_global_callbacks_t * global_callbacks;
+ const sasl_callback_t *callback;
+
+ global_callbacks = (const sasl_global_callbacks_t *) context;
+
+ if (global_callbacks && global_callbacks->callbacks) {
+ for (callback = global_callbacks->callbacks;
+ callback->id != SASL_CB_LIST_END;
+ callback++) {
+ if (callback->id == SASL_CB_GETOPT) {
+ if (!callback->proc) return SASL_FAIL;
+ if (((sasl_getopt_t *)(callback->proc))(callback->context,
+ plugin_name,
+ option,
+ result,
+ len)
+ == SASL_OK)
+ return SASL_OK;
+ }
+ }
+ }
+
+ /* look it up in our configuration file */
+ *result = sasl_config_getstring(option, NULL);
+ if (*result != NULL) {
+ if (len) { *len = (unsigned) strlen(*result); }
+ return SASL_OK;
+ }
+
+ return SASL_FAIL;
+}
+
+static int
+_sasl_conn_getopt(void *context,
+ const char *plugin_name,
+ const char *option,
+ const char ** result,
+ unsigned *len)
+{
+ sasl_conn_t * conn;
+ const sasl_callback_t *callback;
+
+ if (! context)
+ return SASL_BADPARAM;
+
+ conn = (sasl_conn_t *) context;
+
+ if (conn->callbacks)
+ for (callback = conn->callbacks;
+ callback->id != SASL_CB_LIST_END;
+ callback++)
+ if (callback->id == SASL_CB_GETOPT
+ && (((sasl_getopt_t *)(callback->proc))(callback->context,
+ plugin_name,
+ option,
+ result,
+ len)
+ == SASL_OK))
+ return SASL_OK;
+
+ /* If we made it here, we didn't find an appropriate callback
+ * in the connection's callback list, or the callback we did
+ * find didn't return SASL_OK. So we attempt to use the
+ * global callback for this connection... */
+ return _sasl_global_getopt((void *)conn->global_callbacks,
+ plugin_name,
+ option,
+ result,
+ len);
+}
+
+#ifdef HAVE_SYSLOG
+/* this is the default logging */
+static int _sasl_syslog(void *context,
+ int priority,
+ const char *message)
+{
+ int syslog_priority;
+ sasl_server_conn_t *sconn;
+
+ if (context) {
+ if (((sasl_conn_t *)context)->type == SASL_CONN_SERVER) {
+ sconn = (sasl_server_conn_t *)context;
+ if (sconn->sparams->log_level < priority)
+ return SASL_OK;
+ }
+ }
+
+ /* set syslog priority */
+ switch(priority) {
+ case SASL_LOG_NONE:
+ return SASL_OK;
+ break;
+ case SASL_LOG_ERR:
+ syslog_priority = LOG_ERR;
+ break;
+ case SASL_LOG_WARN:
+ syslog_priority = LOG_WARNING;
+ break;
+ case SASL_LOG_NOTE:
+ case SASL_LOG_FAIL:
+ syslog_priority = LOG_NOTICE;
+ break;
+ case SASL_LOG_PASS:
+ case SASL_LOG_TRACE:
+ case SASL_LOG_DEBUG:
+ default:
+ syslog_priority = LOG_DEBUG;
+ break;
+ }
+
+ /* do the syslog call. Do not need to call openlog? */
+ syslog(syslog_priority | LOG_AUTH, "%s", message);
+
+ return SASL_OK;
+}
+#endif /* HAVE_SYSLOG */
+
+static int
+_sasl_getsimple(void *context,
+ int id,
+ const char ** result,
+ size_t *len)
+{
+ const char *userid;
+
+ if (! context || ! result) return SASL_BADPARAM;
+
+ switch(id) {
+ case SASL_CB_AUTHNAME:
+ userid = getenv("USER");
+ if (userid != NULL) {
+ *result = userid;
+ if (len) *len = strlen(userid);
+ return SASL_OK;
+ }
+ userid = getenv("USERNAME");
+ if (userid != NULL) {
+ *result = userid;
+ if (len) *len = strlen(userid);
+ return SASL_OK;
+ }
+#ifdef WIN32
+ /* for win32, try using the GetUserName standard call */
+ {
+ DWORD i;
+ BOOL rval;
+ static char sender[128];
+
+ TCHAR tsender[128];
+ i = sizeof(tsender) / sizeof(tsender[0]);
+ rval = GetUserName(tsender, &i);
+ if ( rval) { /* got a userid */
+ WideCharToMultiByte(CP_UTF8, 0, tsender, -1, sender, sizeof(sender), NULL, NULL); /* -1 ensures null-terminated utf8 */
+ *result = sender;
+ if (len) *len = strlen(sender);
+ return SASL_OK;
+ }
+ }
+#endif /* WIN32 */
+ return SASL_FAIL;
+ default:
+ return SASL_BADPARAM;
+ }
+}
+
+static int
+_sasl_getpath(void *context __attribute__((unused)),
+ const char ** path_dest)
+{
+#if !defined(WIN32)
+ char *path;
+#endif
+ int res = SASL_OK;
+
+ if (! path_dest) {
+ return SASL_BADPARAM;
+ }
+
+ /* Only calculate the path once. */
+ if (default_plugin_path == NULL) {
+
+#if defined(WIN32)
+ /* NB: On Windows platforms this value is always allocated */
+ default_plugin_path = _sasl_get_default_win_path(context,
+ SASL_PLUGIN_PATH_ATTR,
+ PLUGINDIR);
+#else
+ /* NB: On Unix platforms this value is never allocated */
+ path = _sasl_get_default_unix_path(context,
+ SASL_PATH_ENV_VAR,
+ PLUGINDIR);
+
+ res = _sasl_strdup(path, &default_plugin_path, NULL);
+#endif
+ }
+
+ if (res == SASL_OK) {
+ *path_dest = default_plugin_path;
+ }
+
+ return res;
+}
+
+static int
+_sasl_getpath_simple(void *context __attribute__((unused)),
+ const char **path)
+{
+ if (! path) {
+ return SASL_BADPARAM;
+ }
+
+ if (default_plugin_path == NULL) {
+ return SASL_FAIL;
+ }
+
+ *path = default_plugin_path;
+
+ return SASL_OK;
+}
+
+static int
+_sasl_getconfpath(void *context __attribute__((unused)),
+ char ** path_dest)
+{
+#if !defined(WIN32)
+ char *path;
+#endif
+ int res = SASL_OK;
+
+ if (! path_dest) {
+ return SASL_BADPARAM;
+ }
+
+ /* Only calculate the path once. */
+ if (default_conf_path == NULL) {
+
+#if defined(WIN32)
+ /* NB: On Windows platforms this value is always allocated */
+ default_conf_path = _sasl_get_default_win_path(context,
+ SASL_CONF_PATH_ATTR,
+ CONFIGDIR);
+#else
+ /* NB: On Unix platforms this value is never allocated */
+ path = _sasl_get_default_unix_path(context,
+ SASL_CONF_PATH_ENV_VAR,
+ CONFIGDIR);
+
+ res = _sasl_strdup(path, &default_conf_path, NULL);
+#endif
+ }
+
+ if (res == SASL_OK) {
+ *path_dest = default_conf_path;
+ }
+
+ return res;
+}
+
+static int
+_sasl_getconfpath_simple(void *context __attribute__((unused)),
+ const char **path)
+{
+ if (! path) {
+ return SASL_BADPARAM;
+ }
+
+ if (default_conf_path == NULL) {
+ return SASL_FAIL;
+ }
+
+ *path = default_conf_path;
+
+ return SASL_OK;
+}
+
+
+static int
+_sasl_verifyfile(void *context __attribute__((unused)),
+ char *file __attribute__((unused)),
+ int type __attribute__((unused)))
+{
+ /* always say ok */
+ return SASL_OK;
+}
+
+
+static int
+_sasl_proxy_policy(sasl_conn_t *conn,
+ void *context __attribute__((unused)),
+ const char *requested_user, unsigned rlen,
+ const char *auth_identity, unsigned alen,
+ const char *def_realm __attribute__((unused)),
+ unsigned urlen __attribute__((unused)),
+ struct propctx *propctx __attribute__((unused)))
+{
+ if (!conn)
+ return SASL_BADPARAM;
+
+ if (!requested_user || *requested_user == '\0')
+ return SASL_OK;
+
+ if (!auth_identity || !requested_user || rlen != alen ||
+ (memcmp(auth_identity, requested_user, rlen) != 0)) {
+ sasl_seterror(conn, 0,
+ "Requested identity not authenticated identity");
+ RETURN(conn, SASL_BADAUTH);
+ }
+
+ return SASL_OK;
+}
+
+int _sasl_getcallback(sasl_conn_t * conn,
+ unsigned long callbackid,
+ sasl_callback_ft *pproc,
+ void **pcontext)
+{
+ const sasl_callback_t *callback;
+
+ if (!pproc || !pcontext)
+ PARAMERROR(conn);
+
+ /* Some callbacks are always provided by the library */
+ switch (callbackid) {
+ case SASL_CB_LIST_END:
+ /* Nothing ever gets to provide this */
+ INTERROR(conn, SASL_FAIL);
+ case SASL_CB_GETOPT:
+ if (conn) {
+ *pproc = (sasl_callback_ft)&_sasl_conn_getopt;
+ *pcontext = conn;
+ } else {
+ *pproc = (sasl_callback_ft)&_sasl_global_getopt;
+ *pcontext = NULL;
+ }
+ return SASL_OK;
+ }
+
+ /* If it's not always provided by the library, see if there's
+ * a version provided by the application for this connection... */
+ if (conn && conn->callbacks) {
+ for (callback = conn->callbacks; callback->id != SASL_CB_LIST_END;
+ callback++) {
+ if (callback->id == callbackid) {
+ *pproc = callback->proc;
+ *pcontext = callback->context;
+ if (callback->proc) {
+ return SASL_OK;
+ } else {
+ return SASL_INTERACT;
+ }
+ }
+ }
+ }
+
+ /* And, if not for this connection, see if there's one
+ * for all {server,client} connections... */
+ if (conn && conn->global_callbacks && conn->global_callbacks->callbacks) {
+ for (callback = conn->global_callbacks->callbacks;
+ callback->id != SASL_CB_LIST_END;
+ callback++) {
+ if (callback->id == callbackid) {
+ *pproc = callback->proc;
+ *pcontext = callback->context;
+ if (callback->proc) {
+ return SASL_OK;
+ } else {
+ return SASL_INTERACT;
+ }
+ }
+ }
+ }
+
+ /* Otherwise, see if the library provides a default callback. */
+ switch (callbackid) {
+#ifdef HAVE_SYSLOG
+ case SASL_CB_LOG:
+ *pproc = (sasl_callback_ft)&_sasl_syslog;
+ *pcontext = conn;
+ return SASL_OK;
+#endif /* HAVE_SYSLOG */
+ case SASL_CB_GETPATH:
+ *pproc = default_getpath_cb.proc;
+ *pcontext = default_getpath_cb.context;
+ return SASL_OK;
+ case SASL_CB_GETCONFPATH:
+ *pproc = default_getconfpath_cb.proc;
+ *pcontext = default_getconfpath_cb.context;
+ return SASL_OK;
+ case SASL_CB_AUTHNAME:
+ *pproc = (sasl_callback_ft)&_sasl_getsimple;
+ *pcontext = conn;
+ return SASL_OK;
+ case SASL_CB_VERIFYFILE:
+ *pproc = (sasl_callback_ft)&_sasl_verifyfile;
+ *pcontext = NULL;
+ return SASL_OK;
+ case SASL_CB_PROXY_POLICY:
+ *pproc = (sasl_callback_ft)&_sasl_proxy_policy;
+ *pcontext = NULL;
+ return SASL_OK;
+ }
+
+ /* Unable to find a callback... */
+ *pproc = NULL;
+ *pcontext = NULL;
+ sasl_seterror(conn, SASL_NOLOG, "Unable to find a callback: %d", callbackid);
+ RETURN(conn,SASL_FAIL);
+}
+
+
+/*
+ * This function is typically called from a plugin.
+ * It creates a string from the formatting and varargs given
+ * and calls the logging callback (syslog by default)
+ *
+ * %m will parse the value in the next argument as an errno string
+ * %z will parse the next argument as a SASL error code.
+ */
+
+void
+_sasl_log (sasl_conn_t *conn,
+ int level,
+ const char *fmt,
+ ...)
+{
+ char *out = NULL;
+ size_t alloclen=100; /* current allocated length */
+ size_t outlen=0; /* current length of output buffer */
+ size_t formatlen;
+ size_t pos=0; /* current position in format string */
+ int result;
+ sasl_log_t *log_cb;
+ void *log_ctx;
+
+ int ival;
+ unsigned int uval;
+ char *cval;
+ va_list ap; /* varargs thing */
+
+ if(!fmt) return;
+
+ out = (char *) sasl_ALLOC(250);
+ if(!out) return;
+
+ formatlen = strlen(fmt);
+
+ /* See if we have a logging callback... */
+ result = _sasl_getcallback(conn, SASL_CB_LOG, (sasl_callback_ft *)&log_cb, &log_ctx);
+ if (result == SASL_OK && ! log_cb)
+ result = SASL_FAIL;
+ if (result != SASL_OK) goto done;
+
+ va_start(ap, fmt); /* start varargs */
+
+ while(pos<formatlen)
+ {
+ if (fmt[pos]!='%') /* regular character */
+ {
+ result = _buf_alloc(&out, &alloclen, outlen+1);
+ if (result != SASL_OK) goto done;
+ out[outlen]=fmt[pos];
+ outlen++;
+ pos++;
+
+ } else { /* formating thing */
+ int done=0;
+ char frmt[10];
+ int frmtpos=1;
+ char tempbuf[21];
+ frmt[0]='%';
+ pos++;
+
+ while (done==0)
+ {
+ switch(fmt[pos])
+ {
+ case 's': /* need to handle this */
+ cval = va_arg(ap, char *); /* get the next arg */
+ result = _sasl_add_string(&out, &alloclen,
+ &outlen, cval);
+
+ if (result != SASL_OK) /* add the string */
+ goto done;
+
+ done=1;
+ break;
+
+ case '%': /* double % output the '%' character */
+ result = _buf_alloc(&out,&alloclen,outlen+1);
+ if (result != SASL_OK)
+ goto done;
+
+ out[outlen]='%';
+ outlen++;
+ done=1;
+ break;
+
+ case 'm': /* insert the errno string */
+ result = _sasl_add_string(&out, &alloclen, &outlen,
+ strerror(va_arg(ap, int)));
+ if (result != SASL_OK)
+ goto done;
+
+ done=1;
+ break;
+
+ case 'z': /* insert the sasl error string */
+ result = _sasl_add_string(&out, &alloclen, &outlen,
+ (char *) sasl_errstring(va_arg(ap, int),NULL,NULL));
+ if (result != SASL_OK)
+ goto done;
+
+ done=1;
+ break;
+
+ case 'c':
+ frmt[frmtpos++]=fmt[pos];
+ frmt[frmtpos]=0;
+ tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
+ tempbuf[1]='\0';
+
+ /* now add the character */
+ result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
+ if (result != SASL_OK)
+ goto done;
+
+ done=1;
+ break;
+
+ case 'd':
+ case 'i':
+ frmt[frmtpos++]=fmt[pos];
+ frmt[frmtpos]=0;
+ ival = va_arg(ap, int); /* get the next arg */
+
+ snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
+ /* now add the string */
+ result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
+ if (result != SASL_OK)
+ goto done;
+
+ done=1;
+ break;
+
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ frmt[frmtpos++]=fmt[pos];
+ frmt[frmtpos]=0;
+ uval = va_arg(ap, unsigned int); /* get the next arg */
+
+ snprintf(tempbuf,20,frmt,uval); /* have snprintf do the work */
+ /* now add the string */
+ result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
+ if (result != SASL_OK)
+ goto done;
+
+ done=1;
+ break;
+
+ default:
+ frmt[frmtpos++]=fmt[pos]; /* add to the formating */
+ frmt[frmtpos]=0;
+ if (frmtpos>9)
+ done=1;
+ }
+ pos++;
+ if (pos>formatlen)
+ done=1;
+ }
+
+ }
+ }
+
+ /* put 0 at end */
+ result = _buf_alloc(&out, &alloclen, outlen+1);
+ if (result != SASL_OK) goto done;
+ out[outlen]=0;
+
+ /* send log message */
+ result = log_cb(log_ctx, level, out);
+
+ done:
+ va_end(ap);
+ if(out) sasl_FREE(out);
+}
+
+
+
+/* Allocate and Init a sasl_utils_t structure */
+sasl_utils_t *
+_sasl_alloc_utils(sasl_conn_t *conn,
+ sasl_global_callbacks_t *global_callbacks)
+{
+ sasl_utils_t *utils;
+ /* set util functions - need to do rest*/
+ utils=sasl_ALLOC(sizeof(sasl_utils_t));
+ if (utils==NULL)
+ return NULL;
+
+ utils->conn = conn;
+
+ sasl_randcreate(&utils->rpool);
+
+ if (conn) {
+ utils->getopt = &_sasl_conn_getopt;
+ utils->getopt_context = conn;
+ } else {
+ utils->getopt = &_sasl_global_getopt;
+ utils->getopt_context = global_callbacks;
+ }
+
+ utils->malloc=_sasl_allocation_utils.malloc;
+ utils->calloc=_sasl_allocation_utils.calloc;
+ utils->realloc=_sasl_allocation_utils.realloc;
+ utils->free=_sasl_allocation_utils.free;
+
+ utils->mutex_alloc = _sasl_mutex_utils.alloc;
+ utils->mutex_lock = _sasl_mutex_utils.lock;
+ utils->mutex_unlock = _sasl_mutex_utils.unlock;
+ utils->mutex_free = _sasl_mutex_utils.free;
+
+ utils->MD5Init = &_sasl_MD5Init;
+ utils->MD5Update= &_sasl_MD5Update;
+ utils->MD5Final = &_sasl_MD5Final;
+ utils->hmac_md5 = &_sasl_hmac_md5;
+ utils->hmac_md5_init = &_sasl_hmac_md5_init;
+ utils->hmac_md5_final = &_sasl_hmac_md5_final;
+ utils->hmac_md5_precalc = &_sasl_hmac_md5_precalc;
+ utils->hmac_md5_import = &_sasl_hmac_md5_import;
+ utils->mkchal = &sasl_mkchal;
+ utils->utf8verify = &sasl_utf8verify;
+ utils->rand=&sasl_rand;
+ utils->churn=&sasl_churn;
+ utils->checkpass=NULL;
+
+ utils->encode64=&sasl_encode64;
+ utils->decode64=&sasl_decode64;
+
+ utils->erasebuffer=&sasl_erasebuffer;
+
+ utils->getprop=&sasl_getprop;
+ utils->setprop=&sasl_setprop;
+
+ utils->getcallback=&_sasl_getcallback;
+
+ utils->log=&_sasl_log;
+
+ utils->seterror=&sasl_seterror;
+
+#ifndef macintosh
+ /* Aux Property Utilities */
+ utils->prop_new=&prop_new;
+ utils->prop_dup=&prop_dup;
+ utils->prop_request=&prop_request;
+ utils->prop_get=&prop_get;
+ utils->prop_getnames=&prop_getnames;
+ utils->prop_clear=&prop_clear;
+ utils->prop_dispose=&prop_dispose;
+ utils->prop_format=&prop_format;
+ utils->prop_set=&prop_set;
+ utils->prop_setvals=&prop_setvals;
+ utils->prop_erase=&prop_erase;
+ utils->auxprop_store=&sasl_auxprop_store;
+#endif
+
+ /* Spares */
+ utils->spare_fptr = NULL;
+ utils->spare_fptr1 = utils->spare_fptr2 = NULL;
+
+ return utils;
+}
+
+int
+_sasl_free_utils(const sasl_utils_t ** utils)
+{
+ sasl_utils_t *nonconst;
+
+ if(!utils) return SASL_BADPARAM;
+ if(!*utils) return SASL_OK;
+
+ /* I wish we could avoid this cast, it's pretty gratuitous but it
+ * does make life easier to have it const everywhere else. */
+ nonconst = (sasl_utils_t *)(*utils);
+
+ sasl_randfree(&(nonconst->rpool));
+ sasl_FREE(nonconst);
+
+ *utils = NULL;
+ return SASL_OK;
+}
+
+int sasl_idle(sasl_conn_t *conn)
+{
+ if (! conn) {
+ if (_sasl_server_idle_hook
+ && _sasl_server_idle_hook(NULL))
+ return 1;
+ if (_sasl_client_idle_hook
+ && _sasl_client_idle_hook(NULL))
+ return 1;
+ return 0;
+ }
+
+ if (conn->idle_hook)
+ return conn->idle_hook(conn);
+
+ return 0;
+}
+
+static const sasl_callback_t *
+_sasl_find_callback_by_type (const sasl_callback_t *callbacks,
+ unsigned long id)
+{
+ if (callbacks) {
+ while (callbacks->id != SASL_CB_LIST_END) {
+ if (callbacks->id == id) {
+ return callbacks;
+ } else {
+ ++callbacks;
+ }
+ }
+ }
+ return NULL;
+}
+
+const sasl_callback_t *
+_sasl_find_getpath_callback(const sasl_callback_t *callbacks)
+{
+ callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETPATH);
+ if (callbacks != NULL) {
+ return callbacks;
+ } else {
+ return &default_getpath_cb;
+ }
+}
+
+const sasl_callback_t *
+_sasl_find_getconfpath_callback(const sasl_callback_t *callbacks)
+{
+ callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETCONFPATH);
+ if (callbacks != NULL) {
+ return callbacks;
+ } else {
+ return &default_getconfpath_cb;
+ }
+}
+
+const sasl_callback_t *
+_sasl_find_verifyfile_callback(const sasl_callback_t *callbacks)
+{
+ static const sasl_callback_t default_verifyfile_cb = {
+ SASL_CB_VERIFYFILE,
+ (sasl_callback_ft)&_sasl_verifyfile,
+ NULL
+ };
+
+ callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_VERIFYFILE);
+ if (callbacks != NULL) {
+ return callbacks;
+ } else {
+ return &default_verifyfile_cb;
+ }
+}
+
+/* Basically a conditional call to realloc(), if we need more */
+int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen)
+{
+ if(!(*rwbuf)) {
+ *rwbuf = sasl_ALLOC((unsigned)newlen);
+ if (*rwbuf == NULL) {
+ *curlen = 0;
+ return SASL_NOMEM;
+ }
+ *curlen = newlen;
+ } else if(*rwbuf && *curlen < newlen) {
+ size_t needed = 2*(*curlen);
+
+ while(needed < newlen)
+ needed *= 2;
+
+ /* WARN - We will leak the old buffer on failure */
+ *rwbuf = sasl_REALLOC(*rwbuf, (unsigned)needed);
+
+ if (*rwbuf == NULL) {
+ *curlen = 0;
+ return SASL_NOMEM;
+ }
+ *curlen = needed;
+ }
+
+ return SASL_OK;
+}
+
+/* for the mac os x cfm glue: this lets the calling function
+ get pointers to the error buffer without having to touch the sasl_conn_t struct */
+void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl)
+{
+ *bufhdl = &conn->error_buf;
+ *lenhdl = &conn->error_buf_len;
+}
+
+/* convert an iovec to a single buffer */
+int _iovec_to_buf(const struct iovec *vec,
+ unsigned numiov, buffer_info_t **output)
+{
+ unsigned i;
+ int ret;
+ buffer_info_t *out;
+ char *pos;
+
+ if (!vec || !output) return SASL_BADPARAM;
+
+ if (!(*output)) {
+ *output = sasl_ALLOC(sizeof(buffer_info_t));
+ if (!*output) return SASL_NOMEM;
+ memset(*output,0,sizeof(buffer_info_t));
+ }
+
+ out = *output;
+
+ out->curlen = 0;
+ for (i = 0; i < numiov; i++) {
+ out->curlen += vec[i].iov_len;
+ }
+
+ ret = _buf_alloc(&out->data, &out->reallen, out->curlen);
+
+ if (ret != SASL_OK) return SASL_NOMEM;
+
+ memset(out->data, 0, out->reallen);
+ pos = out->data;
+
+ for (i = 0; i < numiov; i++) {
+ memcpy(pos, vec[i].iov_base, vec[i].iov_len);
+ pos += vec[i].iov_len;
+ }
+
+ return SASL_OK;
+}
+
+/* This code might be useful in the future, but it isn't now, so.... */
+#if 0
+int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
+ char *out, unsigned outlen) {
+ char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+ int niflags;
+
+ if(!addr || !out) return SASL_BADPARAM;
+
+ niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
+#ifdef NI_WITHSCOPEID
+ if (addr->sa_family == AF_INET6)
+ niflags |= NI_WITHSCOPEID;
+#endif
+ if (getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
+ niflags) != 0)
+ return SASL_BADPARAM;
+
+ if(outlen < strlen(hbuf) + strlen(pbuf) + 2)
+ return SASL_BUFOVER;
+
+ snprintf(out, outlen, "%s;%s", hbuf, pbuf);
+
+ return SASL_OK;
+}
+#endif
+
+int _sasl_ipfromstring(const char *addr,
+ struct sockaddr *out, socklen_t outlen)
+{
+ int i, j;
+ struct addrinfo hints, *ai = NULL;
+ char hbuf[NI_MAXHOST];
+
+ /* A NULL out pointer just implies we don't do a copy, just verify it */
+
+ if(!addr) return SASL_BADPARAM;
+
+ /* Parse the address */
+ for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
+ if (i >= NI_MAXHOST)
+ return SASL_BADPARAM;
+ hbuf[i] = addr[i];
+ }
+ hbuf[i] = '\0';
+
+ if (addr[i] == ';')
+ i++;
+ /* XXX: Do we need this check? */
+ for (j = i; addr[j] != '\0'; j++)
+ if (!isdigit((int)(addr[j])))
+ return SASL_BADPARAM;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+ if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0)
+ return SASL_BADPARAM;
+
+ if (out) {
+ if (outlen < (socklen_t)ai->ai_addrlen) {
+ freeaddrinfo(ai);
+ return SASL_BUFOVER;
+ }
+ memcpy(out, ai->ai_addr, ai->ai_addrlen);
+ }
+
+ freeaddrinfo(ai);
+
+ return SASL_OK;
+}
+
+int _sasl_build_mechlist(void)
+{
+ int count = 0;
+ sasl_string_list_t *clist = NULL, *slist = NULL, *olist = NULL;
+ sasl_string_list_t *p, *q, **last, *p_next;
+
+ clist = _sasl_client_mechs();
+ slist = _sasl_server_mechs();
+
+ if(!clist) {
+ olist = slist;
+ } else {
+ int flag;
+
+ /* append slist to clist, and set olist to clist */
+ for(p = slist; p; p = p_next) {
+ flag = 0;
+ p_next = p->next;
+
+ last = &clist;
+ for(q = clist; q; q = q->next) {
+ if(!strcmp(q->d, p->d)) {
+ /* They match, set the flag */
+ flag = 1;
+ break;
+ }
+ last = &(q->next);
+ }
+
+ if(!flag) {
+ *last = p;
+ p->next = NULL;
+ } else {
+ sasl_FREE(p);
+ }
+ }
+
+ olist = clist;
+ }
+
+ if(!olist) {
+ /* This is not going to be very useful */
+ printf ("no olist");
+ return SASL_FAIL;
+ }
+
+ for (p = olist; p; p = p->next) count++;
+
+ if(global_mech_list) {
+ sasl_FREE(global_mech_list);
+ global_mech_list = NULL;
+ }
+
+ global_mech_list = sasl_ALLOC((count + 1) * sizeof(char *));
+ if(!global_mech_list) return SASL_NOMEM;
+
+ memset(global_mech_list, 0, (count + 1) * sizeof(char *));
+
+ count = 0;
+ for (p = olist; p; p = p_next) {
+ p_next = p->next;
+
+ global_mech_list[count++] = (char *) p->d;
+
+ sasl_FREE(p);
+ }
+
+ return SASL_OK;
+}
+
+const char ** sasl_global_listmech(void)
+{
+ return (const char **)global_mech_list;
+}
+
+int sasl_listmech(sasl_conn_t *conn,
+ const char *user,
+ const char *prefix,
+ const char *sep,
+ const char *suffix,
+ const char **result,
+ unsigned *plen,
+ int *pcount)
+{
+ if(!conn) {
+ return SASL_BADPARAM;
+ } else if(conn->type == SASL_CONN_SERVER) {
+ RETURN(conn, _sasl_server_listmech(conn, user, prefix, sep, suffix,
+ result, plen, pcount));
+ } else if (conn->type == SASL_CONN_CLIENT) {
+ RETURN(conn, _sasl_client_listmech(conn, prefix, sep, suffix,
+ result, plen, pcount));
+ }
+
+ PARAMERROR(conn);
+}
+
+int _sasl_is_equal_mech(const char *req_mech,
+ const char *plug_mech,
+ size_t req_mech_len,
+ int *plus)
+{
+ size_t n;
+
+ if (req_mech_len > 5 &&
+ strcasecmp(&req_mech[req_mech_len - 5], "-PLUS") == 0) {
+ n = req_mech_len - 5;
+ *plus = 1;
+ } else {
+ n = req_mech_len;
+ *plus = 0;
+ }
+
+ if (n < strlen(plug_mech)) {
+ /* Don't allow arbitrary prefix match */
+ return 0;
+ }
+
+ return (strncasecmp(req_mech, plug_mech, n) == 0);
+}
+
+#ifndef WIN32
+static char *
+_sasl_get_default_unix_path(void *context __attribute__((unused)),
+ char * env_var_name,
+ char * default_value)
+{
+ char *path = NULL;
+
+ /* Honor external variable only in a safe environment */
+ if (getuid() == geteuid() && getgid() == getegid()) {
+ path = getenv(env_var_name);
+ }
+ if (! path) {
+ path = default_value;
+ }
+
+ return path;
+}
+
+#else /*WIN32*/
+/* Return NULL on failure */
+static char *
+_sasl_get_default_win_path(void *context __attribute__((unused)),
+ TCHAR * reg_attr_name,
+ char * default_value)
+{
+ /* Open registry entry, and find all registered SASL libraries.
+ *
+ * Registry location:
+ *
+ * SOFTWARE\\Carnegie Mellon\\Project Cyrus\\SASL Library
+ *
+ * Key - value:
+ *
+ * "SearchPath" - value: PATH like (';' delimited) list
+ * of directories where to search for plugins
+ * The list may contain references to environment
+ * variables (e.g. %PATH%).
+ *
+ */
+ HKEY hKey;
+ DWORD ret;
+ DWORD ValueType; /* value type */
+ DWORD cbData; /* value size in bytes and later number of wchars */
+ TCHAR * ValueData; /* value */
+ DWORD cbExpandedData; /* "expanded" value size in wchars */
+ TCHAR * ExpandedValueData; /* "expanded" value */
+ TCHAR * return_value; /* function return value */
+ TCHAR * tmp;
+
+ /* Initialization */
+ ExpandedValueData = NULL;
+ ValueData = NULL;
+ return_value = NULL;
+
+ /* Open the registry */
+ ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ SASL_ROOT_KEY,
+ 0,
+ KEY_READ,
+ &hKey);
+
+ if (ret != ERROR_SUCCESS) {
+ /* no registry entry */
+ char *ret;
+ (void) _sasl_strdup (default_value, &ret, NULL);
+ return ret;
+ }
+
+ /* figure out value type and required buffer size */
+ /* the size will include space for terminating NUL if required */
+ RegQueryValueEx (hKey,
+ reg_attr_name,
+ NULL, /* reserved */
+ &ValueType,
+ NULL,
+ &cbData);
+
+ /* Only accept string related types */
+ if (ValueType != REG_EXPAND_SZ &&
+ ValueType != REG_MULTI_SZ &&
+ ValueType != REG_SZ) {
+ return_value = NULL;
+ goto CLEANUP;
+ }
+
+ /* Any high water mark? */
+ ValueData = sasl_ALLOC(cbData + 2 * sizeof(TCHAR)); /* extra bytes to insert null-terminator if it's missed */
+ if (ValueData == NULL) {
+ return_value = NULL;
+ goto CLEANUP;
+ };
+
+ if (RegQueryValueEx(hKey,
+ reg_attr_name,
+ NULL, /* reserved */
+ &ValueType,
+ (LPBYTE)ValueData,
+ &cbData) != ERROR_SUCCESS) {
+ return_value = NULL;
+ goto CLEANUP;
+ }
+ cbData /= sizeof(TCHAR); /* covert to number of symbols */
+ ValueData[cbData] = '\0'; /* MS docs say we have to to that */
+ ValueData[cbData + 1] = '\0'; /* for MULTI */
+
+ switch (ValueType) {
+ case REG_EXPAND_SZ:
+ /* : A random starting guess */
+ cbExpandedData = cbData + 1024;
+ ExpandedValueData = (TCHAR*)sasl_ALLOC(cbExpandedData * sizeof(TCHAR));
+ if (ExpandedValueData == NULL) {
+ return_value = NULL;
+ goto CLEANUP;
+ };
+
+
+ cbExpandedData = ExpandEnvironmentStrings(
+ ValueData,
+ ExpandedValueData,
+ cbExpandedData);
+
+ if (cbExpandedData == 0) {
+ /* : GetLastError() contains the reason for failure */
+ return_value = NULL;
+ goto CLEANUP;
+ }
+
+ /* : Must retry expansion with the bigger buffer */
+ if (cbExpandedData > cbData + 1024) {
+ /* : Memory leak here if can't realloc */
+ ExpandedValueData = sasl_REALLOC(ExpandedValueData, cbExpandedData * sizeof(TCHAR));
+ if (ExpandedValueData == NULL) {
+ return_value = NULL;
+ goto CLEANUP;
+ };
+
+ cbExpandedData = ExpandEnvironmentStrings(
+ ValueData,
+ ExpandedValueData,
+ cbExpandedData);
+
+ /* : This should not happen */
+ if (cbExpandedData == 0) {
+ /* : GetLastError() contains the reason for failure */
+ return_value = NULL;
+ goto CLEANUP;
+ }
+ }
+
+ sasl_FREE(ValueData);
+ ValueData = ExpandedValueData;
+ /* : This is to prevent automatical freeing of this block on cleanup */
+ ExpandedValueData = NULL;
+
+ break;
+
+ case REG_MULTI_SZ:
+ tmp = ValueData;
+
+ /* : We shouldn't overflow here, as the buffer is guarantied
+ : to contain at least two consequent NULs */
+ while (1) {
+ if (tmp[0] == '\0') {
+ /* : Stop the process if we found the end of the string (two consequent NULs) */
+ if (tmp[1] == '\0') {
+ break;
+ }
+
+ /* : Replace delimiting NUL with our delimiter characted */
+ tmp[0] = PATHS_DELIMITER;
+ }
+ tmp += (_tcslen(tmp));
+ }
+ break;
+
+ case REG_SZ:
+ /* Do nothing, it is good as is */
+ break;
+
+ default:
+ return_value = NULL;
+ goto CLEANUP;
+ }
+
+ return_value = ValueData; /* just to flag we have a result */
+
+CLEANUP:
+ RegCloseKey(hKey);
+ if (ExpandedValueData != NULL) sasl_FREE(ExpandedValueData);
+ if (return_value == NULL) {
+ if (ValueData != NULL) sasl_FREE(ValueData);
+ return NULL;
+ }
+ if (sizeof(TCHAR) == sizeof(char)) {
+ return (char*)return_value;
+ }
+
+ /* convert to utf-8 for compatibility with other OS' */
+ {
+ char *tmp = _sasl_wchar_to_utf8(return_value);
+ sasl_FREE(return_value);
+ return tmp;
+ }
+}
+
+char* _sasl_wchar_to_utf8(WCHAR *str)
+{
+ size_t bufLen = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
+ char *buf = sasl_ALLOC(bufLen);
+ if (buf) {
+ if (WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, bufLen, NULL, NULL) == 0) { /* -1 ensures null-terminated utf8 */
+ sasl_FREE(buf);
+ buf = NULL;
+ }
+ }
+ return buf;
+}
+
+WCHAR* _sasl_utf8_to_wchar(const char *str)
+{
+ size_t bufLen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+ WCHAR *buf = sasl_ALLOC(bufLen * sizeof(WCHAR));
+ if (buf) {
+ if (MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, bufLen) == 0) { /* -1 ensures null-terminated utf8 */
+ sasl_FREE(buf);
+ buf = NULL;
+ }
+ }
+ return buf;
+}
+
+#endif /*WIN32*/
diff --git a/contrib/libs/sasl/lib/config.c b/contrib/libs/sasl/lib/config.c
new file mode 100644
index 0000000000..d1a5b973de
--- /dev/null
+++ b/contrib/libs/sasl/lib/config.c
@@ -0,0 +1,168 @@
+/* SASL Config file API
+ * Rob Siemborski
+ * Tim Martin (originally in Cyrus distribution)
+ */
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "sasl.h"
+#include "saslint.h"
+
+struct configlist {
+ char *key;
+ char *value;
+};
+
+static struct configlist *configlist = NULL;
+static int nconfiglist = 0;
+
+#define CONFIGLISTGROWSIZE 100
+
+int sasl_config_init(const char *filename)
+{
+ FILE *infile;
+ int lineno = 0;
+ int alloced = 0;
+ char buf[4096];
+ char *p, *key;
+ char *tail;
+ int result;
+
+ nconfiglist=0;
+
+ infile = fopen(filename, "r");
+ if (!infile) {
+ return SASL_CONTINUE;
+ }
+
+ while (fgets(buf, sizeof(buf), infile)) {
+ lineno++;
+
+ if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
+ for (p = buf; *p && isspace((int) *p); p++);
+ if (!*p || *p == '#') continue;
+
+ key = p;
+ while (*p && (isalnum((int) *p) || *p == '-' || *p == '_')) {
+ if (isupper((int) *p)) *p = (char) tolower(*p);
+ p++;
+ }
+ if (*p != ':') {
+ fclose(infile);
+ return SASL_CONFIGERR;
+ }
+ *p++ = '\0';
+
+ while (*p && isspace((int) *p)) p++;
+
+ if (!*p) {
+ fclose(infile);
+ return SASL_CONFIGERR;
+ }
+
+ /* Now strip trailing spaces, if any */
+ tail = p + strlen(p) - 1;
+ while (tail > p && isspace((int) *tail)) {
+ *tail = '\0';
+ tail--;
+ }
+
+ if (nconfiglist == alloced) {
+ alloced += CONFIGLISTGROWSIZE;
+ configlist=sasl_REALLOC((char *)configlist,
+ alloced * sizeof(struct configlist));
+ if (configlist == NULL) {
+ fclose(infile);
+ return SASL_NOMEM;
+ }
+ }
+
+ result = _sasl_strdup(key,
+ &(configlist[nconfiglist].key),
+ NULL);
+ if (result != SASL_OK) {
+ fclose(infile);
+ return result;
+ }
+ result = _sasl_strdup(p,
+ &(configlist[nconfiglist].value),
+ NULL);
+ if (result != SASL_OK) {
+ fclose(infile);
+ return result;
+ }
+
+ nconfiglist++;
+ }
+ fclose(infile);
+
+ return SASL_OK;
+}
+
+const char *sasl_config_getstring(const char *key,const char *def)
+{
+ int opt;
+
+ for (opt = 0; opt < nconfiglist; opt++) {
+ if (*key == configlist[opt].key[0] &&
+ !strcmp(key, configlist[opt].key))
+ return configlist[opt].value;
+ }
+ return def;
+}
+
+void sasl_config_done(void)
+{
+ int opt;
+
+ for (opt = 0; opt < nconfiglist; opt++) {
+ if (configlist[opt].key) sasl_FREE(configlist[opt].key);
+ if (configlist[opt].value) sasl_FREE(configlist[opt].value);
+ }
+
+ sasl_FREE(configlist);
+ configlist = NULL;
+ nconfiglist = 0;
+}
diff --git a/contrib/libs/sasl/lib/dlopen.c b/contrib/libs/sasl/lib/dlopen.c
new file mode 100644
index 0000000000..8284cd8700
--- /dev/null
+++ b/contrib/libs/sasl/lib/dlopen.c
@@ -0,0 +1,569 @@
+/* dlopen.c--Unix dlopen() dynamic loader interface
+ * Rob Siemborski
+ * Rob Earhart
+ */
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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.
+ */
+
+#include <config.h>
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include <sasl.h>
+#include "saslint.h"
+
+#ifndef PIC
+#include <saslplug.h>
+#include "staticopen.h"
+#endif
+
+#ifdef DO_DLOPEN
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else /* HAVE_DIRENT_H */
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif /* ! HAVE_DIRENT_H */
+
+#ifndef NAME_MAX
+# ifdef _POSIX_NAME_MAX
+# define NAME_MAX _POSIX_NAME_MAX
+# else
+# define NAME_MAX 16
+# endif
+#endif
+
+#if NAME_MAX < 8
+# define NAME_MAX 8
+#endif
+
+#ifdef __hpux
+#ifndef HAVE_DLFCN_H
+#include <dl.h>
+
+typedef shl_t * dll_handle;
+typedef void * dll_func;
+
+dll_handle
+dlopen(char *fname, int mode)
+{
+ shl_t h = shl_load(fname, BIND_DEFERRED, 0L);
+ shl_t *hp = NULL;
+
+ if (h) {
+ hp = (shl_t *)malloc(sizeof (shl_t));
+ if (!hp) {
+ shl_unload(h);
+ } else {
+ *hp = h;
+ }
+ }
+
+ return (dll_handle)hp;
+}
+
+int
+dlclose(dll_handle hp)
+{
+ shl_t h;
+
+ if (hp != NULL) {
+ h = *((shl_t *)hp);
+ free(hp);
+ return shl_unload(h);
+ } else {
+ /* Return error */
+ return -1;
+ }
+}
+
+dll_func
+dlsym(dll_handle h, char *n)
+{
+ dll_func handle;
+
+ if (shl_findsym ((shl_t *)h, n, TYPE_PROCEDURE, &handle))
+ return NULL;
+
+ return (dll_func)handle;
+}
+
+char *dlerror()
+{
+ if (errno != 0) {
+ return strerror(errno);
+ }
+ return "Generic shared library error";
+}
+
+#endif /* HAVE_DLFCN_H */
+
+#ifdef __ia64
+#define SO_SUFFIX ".so"
+#else
+#define SO_SUFFIX ".sl"
+#endif /* __ia64 */
+
+#else /* __hpux */
+#define SO_SUFFIX ".so"
+#endif
+
+#define LA_SUFFIX ".la"
+
+typedef struct lib_list
+{
+ struct lib_list *next;
+ void *library;
+} lib_list_t;
+
+static lib_list_t *lib_list_head = NULL;
+
+#endif /* DO_DLOPEN */
+
+int _sasl_locate_entry(void *library, const char *entryname,
+ void **entry_point)
+{
+#ifdef DO_DLOPEN
+/* note that we still check for known problem systems in
+ * case we are cross-compiling */
+#if defined(DLSYM_NEEDS_UNDERSCORE) || (defined(__OpenBSD__) && !defined(__ELF__))
+ char adj_entryname[1024];
+#else
+#define adj_entryname entryname
+#endif
+
+ if(!entryname) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "no entryname in _sasl_locate_entry");
+ return SASL_BADPARAM;
+ }
+
+ if(!library) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "no library in _sasl_locate_entry");
+ return SASL_BADPARAM;
+ }
+
+ if(!entry_point) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "no entrypoint output pointer in _sasl_locate_entry");
+ return SASL_BADPARAM;
+ }
+
+#if defined(DLSYM_NEEDS_UNDERSCORE) || (defined(__OpenBSD__) && !defined(__ELF__))
+ snprintf(adj_entryname, sizeof adj_entryname, "_%s", entryname);
+#endif
+
+ *entry_point = NULL;
+ *entry_point = dlsym(library, adj_entryname);
+ if (*entry_point == NULL) {
+#if 0 /* This message appears to confuse people */
+ _sasl_log(NULL, SASL_LOG_DEBUG,
+ "unable to get entry point %s: %s", adj_entryname,
+ dlerror());
+#endif
+ return SASL_FAIL;
+ }
+
+ return SASL_OK;
+#else
+ return SASL_FAIL;
+#endif /* DO_DLOPEN */
+}
+
+#ifdef DO_DLOPEN
+
+static int _sasl_plugin_load(char *plugin, void *library,
+ const char *entryname,
+ int (*add_plugin)(const char *, void *))
+{
+ void *entry_point;
+ int result;
+
+ result = _sasl_locate_entry(library, entryname, &entry_point);
+ if(result == SASL_OK) {
+ result = add_plugin(plugin, entry_point);
+ if(result != SASL_OK)
+ _sasl_log(NULL, SASL_LOG_DEBUG,
+ "_sasl_plugin_load failed on %s for plugin: %s\n",
+ entryname, plugin);
+ }
+
+ return result;
+}
+
+/* this returns the file to actually open.
+ * out should be a buffer of size PATH_MAX
+ * and may be the same as in. */
+
+/* We'll use a static buffer for speed unless someone complains */
+#define MAX_LINE 2048
+
+static int _parse_la(const char *prefix, const char *in, char *out)
+{
+ FILE *file;
+ size_t length;
+ char line[MAX_LINE];
+ char *ntmp = NULL;
+
+ if(!in || !out || !prefix || out == in) return SASL_BADPARAM;
+
+ /* Set this so we can detect failure */
+ *out = '\0';
+
+ length = strlen(in);
+
+ if (strcmp(in + (length - strlen(LA_SUFFIX)), LA_SUFFIX)) {
+ if(!strcmp(in + (length - strlen(SO_SUFFIX)),SO_SUFFIX)) {
+ /* check for a .la file */
+ if (strlen(prefix) + strlen(in) + strlen(LA_SUFFIX) + 1 >= MAX_LINE)
+ return SASL_BADPARAM;
+ strcpy(line, prefix);
+ strcat(line, in);
+ length = strlen(line);
+ *(line + (length - strlen(SO_SUFFIX))) = '\0';
+ strcat(line, LA_SUFFIX);
+ file = fopen(line, "r");
+ if(file) {
+ /* We'll get it on the .la open */
+ fclose(file);
+ return SASL_FAIL;
+ }
+ }
+ if (strlen(prefix) + strlen(in) + 1 >= PATH_MAX)
+ return SASL_BADPARAM;
+ strcpy(out, prefix);
+ strcat(out, in);
+ return SASL_OK;
+ }
+
+ if (strlen(prefix) + strlen(in) + 1 >= MAX_LINE)
+ return SASL_BADPARAM;
+ strcpy(line, prefix);
+ strcat(line, in);
+
+ file = fopen(line, "r");
+ if(!file) {
+ _sasl_log(NULL, SASL_LOG_WARN,
+ "unable to open LA file: %s", line);
+ return SASL_FAIL;
+ }
+
+ while(!feof(file)) {
+ if(!fgets(line, MAX_LINE, file)) break;
+ if(line[strlen(line) - 1] != '\n') {
+ _sasl_log(NULL, SASL_LOG_WARN,
+ "LA file has too long of a line: %s", in);
+ fclose(file);
+ return SASL_BUFOVER;
+ }
+ if(line[0] == '\n' || line[0] == '#') continue;
+ if(!strncmp(line, "dlname=", sizeof("dlname=") - 1)) {
+ /* We found the line with the name in it */
+ char *end;
+ char *start;
+ size_t len;
+ end = strrchr(line, '\'');
+ if(!end) continue;
+ start = &line[sizeof("dlname=")-1];
+ len = strlen(start);
+ if(len > 3 && start[0] == '\'') {
+ ntmp=&start[1];
+ *end='\0';
+ /* Do we have dlname="" ? */
+ if(ntmp == end) {
+ _sasl_log(NULL, SASL_LOG_DEBUG,
+ "dlname is empty in .la file: %s", in);
+ fclose(file);
+ return SASL_FAIL;
+ }
+ strcpy(out, prefix);
+ strcat(out, ntmp);
+ }
+ break;
+ }
+ }
+ if(ferror(file) || feof(file)) {
+ _sasl_log(NULL, SASL_LOG_WARN,
+ "Error reading .la: %s\n", in);
+ fclose(file);
+ return SASL_FAIL;
+ }
+ fclose(file);
+
+ if(!(*out)) {
+ _sasl_log(NULL, SASL_LOG_WARN,
+ "Could not find a dlname line in .la file: %s", in);
+ return SASL_FAIL;
+ }
+
+ return SASL_OK;
+}
+#endif /* DO_DLOPEN */
+
+/* loads a plugin library */
+int _sasl_get_plugin(const char *file,
+ const sasl_callback_t *verifyfile_cb,
+ void **libraryptr)
+{
+#ifdef DO_DLOPEN
+ int r = 0;
+ int flag;
+ void *library;
+ lib_list_t *newhead;
+
+ r = ((sasl_verifyfile_t *)(verifyfile_cb->proc))
+ (verifyfile_cb->context, file, SASL_VRFY_PLUGIN);
+ if (r != SASL_OK) return r;
+
+#ifdef RTLD_NOW
+ flag = RTLD_NOW;
+#else
+ flag = 0;
+#endif
+
+ newhead = sasl_ALLOC(sizeof(lib_list_t));
+ if(!newhead) return SASL_NOMEM;
+
+ if (!(library = dlopen(file, flag))) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "unable to dlopen %s: %s", file, dlerror());
+ sasl_FREE(newhead);
+ return SASL_FAIL;
+ }
+
+ newhead->library = library;
+ newhead->next = lib_list_head;
+ lib_list_head = newhead;
+
+ *libraryptr = library;
+ return SASL_OK;
+#else
+ return SASL_FAIL;
+#endif /* DO_DLOPEN */
+}
+
+/* gets the list of mechanisms */
+int _sasl_load_plugins(const add_plugin_list_t *entrypoints,
+ const sasl_callback_t *getpath_cb,
+ const sasl_callback_t *verifyfile_cb)
+{
+ int result;
+ const add_plugin_list_t *cur_ep;
+#ifdef DO_DLOPEN
+ char str[PATH_MAX], tmp[PATH_MAX+2], prefix[PATH_MAX+2];
+ /* 1 for '/' 1 for trailing '\0' */
+ char c;
+ int pos;
+ const char *path=NULL;
+ int position;
+ DIR *dp;
+ struct dirent *dir;
+#endif
+#ifndef PIC
+ add_plugin_t *add_plugin;
+ _sasl_plug_type type;
+ _sasl_plug_rec *p;
+#endif
+
+ if (! entrypoints
+ || ! getpath_cb
+ || getpath_cb->id != SASL_CB_GETPATH
+ || ! getpath_cb->proc
+ || ! verifyfile_cb
+ || verifyfile_cb->id != SASL_CB_VERIFYFILE
+ || ! verifyfile_cb->proc)
+ return SASL_BADPARAM;
+
+#ifndef PIC
+ /* do all the static plugins first */
+
+ for(cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
+
+ /* What type of plugin are we looking for? */
+ if(!strcmp(cur_ep->entryname, "sasl_server_plug_init")) {
+ type = SERVER;
+ add_plugin = (add_plugin_t *)sasl_server_add_plugin;
+ } else if (!strcmp(cur_ep->entryname, "sasl_client_plug_init")) {
+ type = CLIENT;
+ add_plugin = (add_plugin_t *)sasl_client_add_plugin;
+ } else if (!strcmp(cur_ep->entryname, "sasl_auxprop_plug_init")) {
+ type = AUXPROP;
+ add_plugin = (add_plugin_t *)sasl_auxprop_add_plugin;
+ } else if (!strcmp(cur_ep->entryname, "sasl_canonuser_init")) {
+ type = CANONUSER;
+ add_plugin = (add_plugin_t *)sasl_canonuser_add_plugin;
+ } else {
+ /* What are we looking for then? */
+ return SASL_FAIL;
+ }
+ for (p=_sasl_static_plugins; p->type; p++) {
+ if(type == p->type)
+ result = add_plugin(p->name, p->plug);
+ }
+ }
+#endif /* !PIC */
+
+/* only do the following if:
+ *
+ * we support dlopen()
+ * AND we are not staticly compiled
+ * OR we are staticly compiled and TRY_DLOPEN_WHEN_STATIC is defined
+ */
+#if defined(DO_DLOPEN) && (defined(PIC) || (!defined(PIC) && defined(TRY_DLOPEN_WHEN_STATIC)))
+ /* get the path to the plugins */
+ result = ((sasl_getpath_t *)(getpath_cb->proc))(getpath_cb->context,
+ &path);
+ if (result != SASL_OK) return result;
+ if (! path) return SASL_FAIL;
+
+ if (strlen(path) >= PATH_MAX) { /* no you can't buffer overrun */
+ return SASL_FAIL;
+ }
+
+ position=0;
+ do {
+ pos=0;
+ do {
+ c=path[position];
+ position++;
+ str[pos]=c;
+ pos++;
+ } while ((c!=':') && (c!='=') && (c!=0));
+ str[pos-1]='\0';
+
+ strcpy(prefix,str);
+ strcat(prefix,"/");
+
+ if ((dp=opendir(str)) !=NULL) /* ignore errors */
+ {
+ while ((dir=readdir(dp)) != NULL)
+ {
+ size_t length;
+ void *library;
+ char *c;
+ char plugname[PATH_MAX];
+ char name[PATH_MAX];
+
+ length = NAMLEN(dir);
+ if (length < 4)
+ continue; /* can not possibly be what we're looking for */
+
+ if (length + pos>=PATH_MAX) continue; /* too big */
+
+ if (strcmp(dir->d_name + (length - strlen(SO_SUFFIX)),
+ SO_SUFFIX)
+ && strcmp(dir->d_name + (length - strlen(LA_SUFFIX)),
+ LA_SUFFIX))
+ continue;
+
+ memcpy(name,dir->d_name,length);
+ name[length]='\0';
+
+ result = _parse_la(prefix, name, tmp);
+ if(result != SASL_OK)
+ continue;
+
+ /* skip "lib" and cut off suffix --
+ this only need be approximate */
+ strcpy(plugname, name + 3);
+ c = strchr(plugname, (int)'.');
+ if(c) *c = '\0';
+
+ result = _sasl_get_plugin(tmp, verifyfile_cb, &library);
+
+ if(result != SASL_OK)
+ continue;
+
+ for(cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
+ _sasl_plugin_load(plugname, library, cur_ep->entryname,
+ cur_ep->add_plugin);
+ /* If this fails, it's not the end of the world */
+ }
+ }
+
+ closedir(dp);
+ } else {
+ _sasl_log(NULL, SASL_LOG_DEBUG,
+ "looking for plugins in '%s', failed to open directory, error: %s",
+ str,
+ strerror(errno));
+ }
+
+ } while ((c!='=') && (c!=0));
+#endif /* defined(DO_DLOPEN) && (!defined(PIC) || (defined(PIC) && defined(TRY_DLOPEN_WHEN_STATIC))) */
+
+ return SASL_OK;
+}
+
+int
+_sasl_done_with_plugins(void)
+{
+#ifdef DO_DLOPEN
+ lib_list_t *libptr, *libptr_next;
+
+ for(libptr = lib_list_head; libptr; libptr = libptr_next) {
+ libptr_next = libptr->next;
+ if(libptr->library)
+ dlclose(libptr->library);
+ sasl_FREE(libptr);
+ }
+
+ lib_list_head = NULL;
+#endif /* DO_DLOPEN */
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/lib/external.c b/contrib/libs/sasl/lib/external.c
new file mode 100644
index 0000000000..4650838bf2
--- /dev/null
+++ b/contrib/libs/sasl/lib/external.c
@@ -0,0 +1,407 @@
+/* SASL server API implementation
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <string.h>
+#include <sasl.h>
+#include <saslplug.h>
+#include "saslint.h"
+
+#include "../common/plugin_common.h"
+
+/***************************** Common Section *****************************/
+
+/***************************** Server Section *****************************/
+
+static int
+external_server_mech_new(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ void **conn_context)
+{
+ if (!conn_context
+ || !sparams
+ || !sparams->utils
+ || !sparams->utils->conn)
+ return SASL_BADPARAM;
+
+ if (!sparams->utils->conn->external.auth_id)
+ return SASL_NOMECH;
+
+ *conn_context = NULL;
+
+ return SASL_OK;
+}
+
+static int
+external_server_mech_step(void *conn_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ int result;
+
+ if (!sparams
+ || !sparams->utils
+ || !sparams->utils->conn
+ || !sparams->utils->getcallback
+ || !serverout
+ || !serveroutlen
+ || !oparams)
+ return SASL_BADPARAM;
+
+ if (!sparams->utils->conn->external.auth_id)
+ return SASL_BADPROT;
+
+ /* xxx arbitrary limit here */
+ if (clientinlen > 16384) return SASL_BADPROT;
+
+ if ((sparams->props.security_flags & SASL_SEC_NOANONYMOUS) &&
+ (!strcmp(sparams->utils->conn->external.auth_id, "anonymous"))) {
+ sasl_seterror(sparams->utils->conn,0,"anonymous login not allowed");
+ return SASL_NOAUTHZ;
+ }
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ if (!clientin) {
+ /* No initial data; we're in a protocol which doesn't support it.
+ * So we let the server app know that we need some... */
+ return SASL_CONTINUE;
+ }
+
+ if (clientinlen) { /* if we have a non-zero authorization id */
+ /* The user's trying to authorize as someone they didn't
+ * authenticate as */
+ result = sparams->canon_user(sparams->utils->conn,
+ clientin, clientinlen,
+ SASL_CU_AUTHZID, oparams);
+ if(result != SASL_OK) return result;
+
+ result = sparams->canon_user(sparams->utils->conn,
+ sparams->utils->conn->external.auth_id, 0,
+ SASL_CU_AUTHID | SASL_CU_EXTERNALLY_VERIFIED, oparams);
+ } else {
+ result = sparams->canon_user(sparams->utils->conn,
+ sparams->utils->conn->external.auth_id, 0,
+ SASL_CU_AUTHID | SASL_CU_EXTERNALLY_VERIFIED | SASL_CU_AUTHZID, oparams);
+ }
+
+ if (result != SASL_OK) return result;
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ return SASL_OK;
+}
+
+static int
+external_server_mech_avail(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ void **conn_context __attribute__((unused)))
+{
+ if (!sparams->utils->conn->external.auth_id) {
+ /* Return Temporary Failure */
+ return SASL_NOTDONE;
+ }
+
+ return SASL_OK;
+}
+
+static sasl_server_plug_t external_server_plugins[] =
+{
+ {
+ "EXTERNAL", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_NODICTIONARY, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_ALLOWS_PROXY, /* features */
+ NULL, /* glob_context */
+ &external_server_mech_new, /* mech_new */
+ &external_server_mech_step, /* mech_step */
+ NULL, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ &external_server_mech_avail, /* mech_avail */
+ NULL /* spare */
+ }
+};
+
+int external_server_plug_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount)
+{
+ if (!out_version || !pluglist || !plugcount)
+ return SASL_BADPARAM;
+
+ if (max_version != SASL_SERVER_PLUG_VERSION) {
+ SETERROR( utils, "EXTERNAL version mismatch" );
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_SERVER_PLUG_VERSION;
+ *pluglist = external_server_plugins;
+ *plugcount = 1;
+ return SASL_OK;
+}
+
+/***************************** Client Section *****************************/
+
+typedef struct client_context
+{
+ char *out_buf;
+ size_t out_buf_len;
+} client_context_t;
+
+static int external_client_mech_new(void *glob_context __attribute__((unused)),
+ sasl_client_params_t *params,
+ void **conn_context)
+{
+ client_context_t *text;
+
+ if (!params
+ || !params->utils
+ || !params->utils->conn
+ || !conn_context)
+ return SASL_BADPARAM;
+
+ if (!params->utils->conn->external.auth_id)
+ return SASL_NOMECH;
+
+ text = sasl_ALLOC(sizeof(client_context_t));
+ if(!text) return SASL_NOMEM;
+
+ memset(text, 0, sizeof(client_context_t));
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static int
+external_client_mech_step(void *conn_context,
+ sasl_client_params_t *params,
+ const char *serverin __attribute__((unused)),
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ client_context_t *text = (client_context_t *)conn_context;
+ const char *user = NULL;
+ int user_result = SASL_OK;
+ int result;
+
+ if (!params
+ || !params->utils
+ || !params->utils->conn
+ || !params->utils->getcallback
+ || !clientout
+ || !clientoutlen
+ || !oparams)
+ return SASL_BADPARAM;
+
+ if (!params->utils->conn->external.auth_id)
+ return SASL_BADPROT;
+
+ if (serverinlen != 0)
+ return SASL_BADPROT;
+
+ *clientout = NULL;
+ *clientoutlen = 0;
+
+ /* try to get the userid */
+ if (user == NULL) {
+ user_result = _plug_get_userid(params->utils, &user, prompt_need);
+
+ if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
+ return user_result;
+ }
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ params->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+ if (user_result == SASL_INTERACT) {
+ /* make the prompt list */
+ int result =
+ _plug_make_prompts(params->utils, prompt_need,
+ "Please enter your authorization name",
+ "",
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if (result != SASL_OK) return result;
+
+ return SASL_INTERACT;
+ }
+
+ *clientoutlen = user ? (unsigned) strlen(user) : 0;
+
+ result = _buf_alloc(&text->out_buf, &text->out_buf_len, *clientoutlen + 1);
+
+ if (result != SASL_OK) return result;
+
+ if (user && *user) {
+ result = params->canon_user(params->utils->conn,
+ user, 0, SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) return result;
+
+ result = params->canon_user(params->utils->conn,
+ params->utils->conn->external.auth_id, 0,
+ SASL_CU_AUTHID, oparams);
+ if (result != SASL_OK) return result;
+
+ memcpy(text->out_buf, user, *clientoutlen);
+ } else {
+ result = params->canon_user(params->utils->conn,
+ params->utils->conn->external.auth_id, 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) return result;
+ }
+
+ text->out_buf[*clientoutlen] = '\0';
+
+ *clientout = text->out_buf;
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ return SASL_OK;
+}
+
+static void
+external_client_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils __attribute__((unused)))
+{
+ client_context_t *text = (client_context_t *) conn_context;
+
+ if (!text) return;
+
+ if(text->out_buf) sasl_FREE(text->out_buf);
+
+ sasl_FREE(text);
+}
+
+static const unsigned long external_required_prompts[] = {
+ SASL_CB_LIST_END
+};
+
+static sasl_client_plug_t external_client_plugins[] =
+{
+ {
+ "EXTERNAL", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_NODICTIONARY, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_ALLOWS_PROXY, /* features */
+ external_required_prompts, /* required_prompts */
+ NULL, /* glob_context */
+ &external_client_mech_new, /* mech_new */
+ &external_client_mech_step, /* mech_step */
+ &external_client_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ }
+};
+
+int external_client_plug_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount)
+{
+ if (!utils || !out_version || !pluglist || !plugcount)
+ return SASL_BADPARAM;
+
+ if (max_version != SASL_CLIENT_PLUG_VERSION) {
+ SETERROR( utils, "EXTERNAL version mismatch" );
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_CLIENT_PLUG_VERSION;
+ *pluglist = external_client_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/lib/md5.c b/contrib/libs/sasl/lib/md5.c
new file mode 100644
index 0000000000..c79f4f7d77
--- /dev/null
+++ b/contrib/libs/sasl/lib/md5.c
@@ -0,0 +1,527 @@
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Function names changed to avoid namespace collisions: Rob Siemborski */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+*/
+
+#include <config.h>
+#include "md5global.h"
+#include "md5.h"
+#include "hmac-md5.h"
+
+#ifndef WIN32
+# include <arpa/inet.h>
+#endif
+
+/* Constants for MD5Transform routine.
+*/
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((SASL_UINT4 [4], const unsigned char [64]));
+static void Encode PROTO_LIST
+ ((unsigned char *, SASL_UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((SASL_UINT4 *, const unsigned char *, unsigned int));
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+
+ */
+#ifdef I
+/* This might be defined via NANA */
+#undef I
+#endif
+
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+
+ */
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+*/
+
+#define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (SASL_UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+#define GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (SASL_UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+#define HH(a, b, c, d, x, s, ac) { (a) += H ((b), (c), (d)) + (x) + (SASL_UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+#define II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (SASL_UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+*/
+
+void _sasl_MD5Init (context)
+MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+
+ /* Load magic initialization constants. */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the context.
+*/
+
+void _sasl_MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+const unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((SASL_UINT4)inputLen << 3))
+ < ((SASL_UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((SASL_UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen); MD5Transform
+ (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+ inputLen-i);
+
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+*/
+
+void _sasl_MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64. */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ _sasl_MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ _sasl_MD5Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information. */
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+
+static void MD5Transform (state, block)
+SASL_UINT4 state[4];
+const unsigned char block[64];
+{
+ SASL_UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+ */
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (SASL_UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+
+ */
+
+static void Encode (output, input, len)
+unsigned char *output;
+SASL_UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (SASL_UINT4). Assumes len is
+ a multiple of 4.
+
+ */
+
+static void Decode (output, input, len)
+SASL_UINT4 *output;
+const unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((SASL_UINT4)input[j]) | (((SASL_UINT4)input[j+1]) << 8) | (((SASL_UINT4)input[j+2]) << 16)
+ | (((SASL_UINT4)input[j+3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+*/
+
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+
+void _sasl_hmac_md5_init(HMAC_MD5_CTX *hmac,
+ const unsigned char *key,
+ int key_len)
+{
+ unsigned char k_ipad[65]; /* inner padding -
+ * key XORd with ipad
+ */
+ unsigned char k_opad[65]; /* outer padding -
+ * key XORd with opad
+ */
+ unsigned char tk[16];
+ int i;
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64) {
+
+ MD5_CTX tctx;
+
+ _sasl_MD5Init(&tctx);
+ _sasl_MD5Update(&tctx, key, key_len);
+ _sasl_MD5Final(tk, &tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ MD5_memset((POINTER)k_ipad, '\0', sizeof k_ipad);
+ MD5_memset((POINTER)k_opad, '\0', sizeof k_opad);
+ MD5_memcpy( k_ipad, (POINTER)key, key_len);
+ MD5_memcpy( k_opad, (POINTER)key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ _sasl_MD5Init(&hmac->ictx); /* init inner context */
+ _sasl_MD5Update(&hmac->ictx, k_ipad, 64); /* apply inner pad */
+
+ _sasl_MD5Init(&hmac->octx); /* init outer context */
+ _sasl_MD5Update(&hmac->octx, k_opad, 64); /* apply outer pad */
+
+ /* scrub the pads and key context (if used) */
+ MD5_memset((POINTER)&k_ipad, 0, sizeof(k_ipad));
+ MD5_memset((POINTER)&k_opad, 0, sizeof(k_opad));
+ MD5_memset((POINTER)&tk, 0, sizeof(tk));
+
+ /* and we're done. */
+}
+
+/* The precalc and import routines here rely on the fact that we pad
+ * the key out to 64 bytes and use that to initialize the md5
+ * contexts, and that updating an md5 context with 64 bytes of data
+ * leaves nothing left over; all of the interesting state is contained
+ * in the state field, and none of it is left over in the count and
+ * buffer fields. So all we have to do is save the state field; we
+ * can zero the others when we reload it. Which is why the decision
+ * was made to pad the key out to 64 bytes in the first place. */
+void _sasl_hmac_md5_precalc(HMAC_MD5_STATE *state,
+ const unsigned char *key,
+ int key_len)
+{
+ HMAC_MD5_CTX hmac;
+ unsigned lupe;
+
+ _sasl_hmac_md5_init(&hmac, key, key_len);
+ for (lupe = 0; lupe < 4; lupe++) {
+ state->istate[lupe] = htonl(hmac.ictx.state[lupe]);
+ state->ostate[lupe] = htonl(hmac.octx.state[lupe]);
+ }
+ MD5_memset((POINTER)&hmac, 0, sizeof(hmac));
+}
+
+
+void _sasl_hmac_md5_import(HMAC_MD5_CTX *hmac,
+ HMAC_MD5_STATE *state)
+{
+ unsigned lupe;
+ MD5_memset((POINTER)hmac, 0, sizeof(HMAC_MD5_CTX));
+ for (lupe = 0; lupe < 4; lupe++) {
+ hmac->ictx.state[lupe] = ntohl(state->istate[lupe]);
+ hmac->octx.state[lupe] = ntohl(state->ostate[lupe]);
+ }
+ /* Init the counts to account for our having applied
+ * 64 bytes of key; this works out to 0x200 (64 << 3; see
+ * MD5Update above...) */
+ hmac->ictx.count[0] = hmac->octx.count[0] = 0x200;
+}
+
+void _sasl_hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
+ HMAC_MD5_CTX *hmac)
+{
+ _sasl_MD5Final(digest, &hmac->ictx); /* Finalize inner md5 */
+ _sasl_MD5Update(&hmac->octx, digest, 16); /* Update outer ctx */
+ _sasl_MD5Final(digest, &hmac->octx); /* Finalize outer md5 */
+}
+
+
+void _sasl_hmac_md5(text, text_len, key, key_len, digest)
+const unsigned char* text; /* pointer to data stream */
+int text_len; /* length of data stream */
+const unsigned char* key; /* pointer to authentication key */
+int key_len; /* length of authentication key */
+unsigned char *digest; /* caller digest to be filled in */
+{
+ MD5_CTX context;
+
+ unsigned char k_ipad[65]; /* inner padding -
+ * key XORd with ipad
+ */
+ unsigned char k_opad[65]; /* outer padding -
+ * key XORd with opad
+ */
+ unsigned char tk[16];
+ int i;
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64) {
+
+ MD5_CTX tctx;
+
+ _sasl_MD5Init(&tctx);
+ _sasl_MD5Update(&tctx, key, key_len);
+ _sasl_MD5Final(tk, &tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ MD5_memset(k_ipad, '\0', sizeof k_ipad);
+ MD5_memset(k_opad, '\0', sizeof k_opad);
+ MD5_memcpy( k_ipad, (POINTER)key, key_len);
+ MD5_memcpy( k_opad, (POINTER)key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+ /*
+ * perform inner MD5
+ */
+
+ _sasl_MD5Init(&context); /* init context for 1st
+ * pass */
+ _sasl_MD5Update(&context, k_ipad, 64); /* start with inner pad */
+ _sasl_MD5Update(&context, text, text_len); /* then text of datagram */
+ _sasl_MD5Final(digest, &context); /* finish up 1st pass */
+
+ /*
+ * perform outer MD5
+ */
+ _sasl_MD5Init(&context); /* init context for 2nd
+ * pass */
+ _sasl_MD5Update(&context, k_opad, 64); /* start with outer pad */
+ _sasl_MD5Update(&context, digest, 16); /* then results of 1st
+ * hash */
+ _sasl_MD5Final(digest, &context); /* finish up 2nd pass */
+
+}
diff --git a/contrib/libs/sasl/lib/saslint.h b/contrib/libs/sasl/lib/saslint.h
new file mode 100644
index 0000000000..ebade78f3a
--- /dev/null
+++ b/contrib/libs/sasl/lib/saslint.h
@@ -0,0 +1,544 @@
+/* saslint.h - internal SASL library definitions
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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.
+ */
+
+#ifndef SASLINT_H
+#define SASLINT_H
+
+#include <config.h>
+#include "sasl.h"
+#include "saslplug.h"
+#include "saslutil.h"
+#include "prop.h"
+
+#ifndef INLINE
+#if defined (WIN32)
+/* Visual Studio: "inline" keyword is not available in C, only in C++ */
+#define INLINE __inline
+#else
+#define INLINE inline
+#endif
+#endif
+
+/* #define'd constants */
+#define CANON_BUF_SIZE 1024
+
+/* Error Handling Foo */
+/* Helpful Hints:
+ * -Error strings are set as soon as possible (first function in stack trace
+ * with a pointer to the sasl_conn_t.
+ * -Error codes are set as late as possible (only in the sasl api functions),
+ * though "as often as possible" also comes to mind to ensure correctness
+ * -Errors from calls to _buf_alloc, _sasl_strdup, etc are assumed to be
+ * memory errors.
+ * -Only errors (error codes < SASL_OK) should be remembered
+ */
+#define RETURN(conn, val) { if(conn && (val) < SASL_OK) \
+ (conn)->error_code = (val); \
+ return (val); }
+#define MEMERROR(conn) {\
+ if(conn) sasl_seterror( (conn), 0, \
+ "Out of Memory in " __FILE__ " near line %d", __LINE__ ); \
+ RETURN(conn, SASL_NOMEM) }
+#define PARAMERROR(conn) {\
+ if(conn) sasl_seterror( (conn), SASL_NOLOG, \
+ "Parameter error in " __FILE__ " near line %d", __LINE__ ); \
+ RETURN(conn, SASL_BADPARAM) }
+#define INTERROR(conn, val) {\
+ if(conn) sasl_seterror( (conn), 0, \
+ "Internal Error %d in " __FILE__ " near line %d", (val),\
+ __LINE__ ); \
+ RETURN(conn, (val)) }
+
+#ifndef PATH_MAX
+# ifdef WIN32
+# define PATH_MAX MAX_PATH
+# else
+# ifdef _POSIX_PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+# else
+# define PATH_MAX 1024 /* arbitrary; probably big enough.
+ * will probably only be 256+64 on
+ * pre-posix machines */
+# endif /* _POSIX_PATH_MAX */
+# endif /* WIN32 */
+#endif
+
+/* : Define directory delimiter in SASL_PATH/SASL_CONF_PATH variables */
+#ifdef WIN32
+#define PATHS_DELIMITER ';'
+#else
+#define PATHS_DELIMITER ':'
+#endif
+
+/* A FQDN max len is 255 per RFC 1035,
+ * this means 253 chars max, we add one more for zero terminator */
+#define MAXFQDNLEN 254
+
+/* Datatype Definitions */
+typedef struct {
+ const sasl_callback_t *callbacks;
+ const char *appname;
+} sasl_global_callbacks_t;
+
+typedef struct _sasl_external_properties
+{
+ sasl_ssf_t ssf;
+ char *auth_id;
+} _sasl_external_properties_t;
+
+typedef struct sasl_string_list
+{
+ const char *d;
+ struct sasl_string_list *next;
+} sasl_string_list_t;
+
+typedef struct buffer_info
+{
+ char *data;
+ size_t curlen;
+ size_t reallen;
+} buffer_info_t;
+
+typedef int add_plugin_t(const char *, void *);
+
+typedef struct add_plugin_list
+{
+ const char *entryname;
+ add_plugin_t *add_plugin;
+} add_plugin_list_t;
+
+enum Sasl_conn_type { SASL_CONN_UNKNOWN = 0,
+ SASL_CONN_SERVER = 1,
+ SASL_CONN_CLIENT = 2 };
+
+struct sasl_conn {
+ enum Sasl_conn_type type;
+
+ void (*destroy_conn)(sasl_conn_t *); /* destroy function */
+
+ char *service;
+
+ unsigned int flags; /* flags passed to sasl_*_new */
+
+ /* IP information. A buffer of size 52 is adequate for this in its
+ longest format (see sasl.h) */
+ int got_ip_local, got_ip_remote;
+ char iplocalport[NI_MAXHOST + NI_MAXSERV];
+ char ipremoteport[NI_MAXHOST + NI_MAXSERV];
+
+ void *context;
+ sasl_out_params_t oparams;
+
+ sasl_security_properties_t props;
+ _sasl_external_properties_t external;
+
+ sasl_secret_t *secret;
+
+ int (*idle_hook)(sasl_conn_t *conn);
+ const sasl_callback_t *callbacks;
+ const sasl_global_callbacks_t *global_callbacks; /* global callbacks
+ * connection */
+ char *serverFQDN;
+
+ /* Pointers to memory that we are responsible for */
+ buffer_info_t *encode_buf;
+
+ int error_code;
+ char *error_buf, *errdetail_buf;
+ size_t error_buf_len, errdetail_buf_len;
+ char *mechlist_buf;
+ size_t mechlist_buf_len;
+
+ char *decode_buf;
+
+ char user_buf[CANON_BUF_SIZE+1], authid_buf[CANON_BUF_SIZE+1];
+
+ /* Allocated by sasl_encodev if the output contains multiple SASL packet. */
+ buffer_info_t multipacket_encoded_data;
+};
+
+/* Server Conn Type Information */
+
+typedef struct mechanism
+{
+ server_sasl_mechanism_t m;
+ struct mechanism *next;
+} mechanism_t;
+
+typedef struct mech_list {
+ const sasl_utils_t *utils; /* gotten from plug_init */
+
+ void *mutex; /* mutex for this data */
+ mechanism_t *mech_list; /* list of loaded mechanisms */
+ int mech_length; /* number of loaded mechanisms */
+} mech_list_t;
+
+typedef struct context_list
+{
+ mechanism_t *mech;
+ void *context; /* if NULL, this mech is disabled for this connection
+ * otherwise, use this context instead of a call
+ * to mech_new */
+ struct context_list *next;
+} context_list_t;
+
+typedef struct sasl_server_conn {
+ sasl_conn_t base; /* parts common to server + client */
+
+ char *appname; /* application name buffer (for sparams) */
+ char *user_realm; /* domain the user authenticating is in */
+ int sent_last; /* Have we already done the last send? */
+ int authenticated;
+ mechanism_t *mech; /* mechanism trying to use */
+ sasl_server_params_t *sparams;
+ context_list_t *mech_contexts;
+ mechanism_t *mech_list; /* list of available mechanisms */
+ int mech_length; /* number of available mechanisms */
+} sasl_server_conn_t;
+
+/* Client Conn Type Information */
+
+typedef struct cmechanism
+{
+ client_sasl_mechanism_t m;
+ struct cmechanism *next;
+} cmechanism_t;
+
+typedef struct cmech_list {
+ const sasl_utils_t *utils;
+
+ void *mutex; /* mutex for this data */
+ cmechanism_t *mech_list; /* list of mechanisms */
+ int mech_length; /* number of mechanisms */
+
+} cmech_list_t;
+
+typedef struct sasl_client_conn {
+ sasl_conn_t base; /* parts common to server + client */
+
+ cmechanism_t *mech;
+ sasl_client_params_t *cparams;
+
+ char *clientFQDN;
+
+ cmechanism_t *mech_list; /* list of available mechanisms */
+ int mech_length; /* number of available mechanisms */
+} sasl_client_conn_t;
+
+typedef struct sasl_allocation_utils {
+ sasl_malloc_t *malloc;
+ sasl_calloc_t *calloc;
+ sasl_realloc_t *realloc;
+ sasl_free_t *free;
+} sasl_allocation_utils_t;
+
+typedef struct sasl_mutex_utils {
+ sasl_mutex_alloc_t *alloc;
+ sasl_mutex_lock_t *lock;
+ sasl_mutex_unlock_t *unlock;
+ sasl_mutex_free_t *free;
+} sasl_mutex_utils_t;
+
+typedef struct sasl_log_utils_s {
+ sasl_log_t *log;
+} sasl_log_utils_t;
+
+typedef int sasl_plaintext_verifier(sasl_conn_t *conn,
+ const char *userid,
+ const char *passwd,
+ const char *service,
+ const char *user_realm);
+
+struct sasl_verify_password_s {
+ char *name;
+ sasl_plaintext_verifier *verify;
+};
+
+/*
+ * globals & constants
+ */
+/*
+ * common.c
+ */
+LIBSASL_API const sasl_utils_t *sasl_global_utils;
+
+extern int (*_sasl_client_idle_hook)(sasl_conn_t *conn);
+extern int (*_sasl_server_idle_hook)(sasl_conn_t *conn);
+
+/* These return SASL_OK if we've actually finished cleanup,
+ * SASL_NOTINIT if that part of the library isn't initialized, and
+ * SASL_CONTINUE if we need to call them again */
+extern int (*_sasl_client_cleanup_hook)(void);
+extern int (*_sasl_server_cleanup_hook)(void);
+
+extern sasl_allocation_utils_t _sasl_allocation_utils;
+extern sasl_mutex_utils_t _sasl_mutex_utils;
+extern int _sasl_allocation_locked;
+
+void sasl_common_done(void);
+
+extern int _sasl_is_equal_mech(const char *req_mech,
+ const char *plug_mech,
+ size_t req_mech_len,
+ int *plus);
+
+/*
+ * checkpw.c
+ */
+extern struct sasl_verify_password_s _sasl_verify_password[];
+
+/*
+ * server.c
+ */
+/* (this is a function call to ensure this is read-only to the outside) */
+extern int _is_sasl_server_active(void);
+
+/*
+ * Allocation and Mutex utility macros
+ */
+#define sasl_ALLOC(__size__) (_sasl_allocation_utils.malloc((__size__)))
+#define sasl_CALLOC(__nelem__, __size__) \
+ (_sasl_allocation_utils.calloc((__nelem__), (__size__)))
+#define sasl_REALLOC(__ptr__, __size__) \
+ (_sasl_allocation_utils.realloc((__ptr__), (__size__)))
+#define sasl_FREE(__ptr__) (_sasl_allocation_utils.free((__ptr__)))
+
+#define sasl_MUTEX_ALLOC() (_sasl_mutex_utils.alloc())
+#define sasl_MUTEX_LOCK(__mutex__) (_sasl_mutex_utils.lock((__mutex__)))
+#define sasl_MUTEX_UNLOCK(__mutex__) (_sasl_mutex_utils.unlock((__mutex__)))
+#define sasl_MUTEX_FREE(__mutex__) \
+ (_sasl_mutex_utils.free((__mutex__)))
+
+/* function prototypes */
+/*
+ * dlopen.c and staticopen.c
+ */
+/*
+ * The differences here are:
+ * _sasl_load_plugins loads all plugins from all files
+ * _sasl_get_plugin loads the LIBRARY for an individual file
+ * _sasl_done_with_plugins frees the LIBRARIES loaded by the above 2
+ * _sasl_locate_entry locates an entrypoint in a given library
+ */
+extern int _sasl_load_plugins(const add_plugin_list_t *entrypoints,
+ const sasl_callback_t *getpath_callback,
+ const sasl_callback_t *verifyfile_callback);
+extern int _sasl_get_plugin(const char *file,
+ const sasl_callback_t *verifyfile_cb,
+ void **libraryptr);
+extern int _sasl_locate_entry(void *library, const char *entryname,
+ void **entry_point);
+extern int _sasl_done_with_plugins();
+
+/*
+ * common.c
+ */
+extern const sasl_callback_t *
+_sasl_find_getpath_callback(const sasl_callback_t *callbacks);
+
+extern const sasl_callback_t *
+_sasl_find_getconfpath_callback(const sasl_callback_t *callbacks);
+
+extern const sasl_callback_t *
+_sasl_find_verifyfile_callback(const sasl_callback_t *callbacks);
+
+extern int _sasl_common_init(sasl_global_callbacks_t *global_callbacks);
+
+extern int _sasl_conn_init(sasl_conn_t *conn,
+ const char *service,
+ unsigned int flags,
+ enum Sasl_conn_type type,
+ int (*idle_hook)(sasl_conn_t *conn),
+ const char *serverFQDN,
+ const char *iplocalport,
+ const char *ipremoteport,
+ const sasl_callback_t *callbacks,
+ const sasl_global_callbacks_t *global_callbacks);
+extern void _sasl_conn_dispose(sasl_conn_t *conn);
+
+extern sasl_utils_t *
+_sasl_alloc_utils(sasl_conn_t *conn,
+ sasl_global_callbacks_t *global_callbacks);
+extern int _sasl_free_utils(const sasl_utils_t ** utils);
+
+extern int
+_sasl_getcallback(sasl_conn_t * conn,
+ unsigned long callbackid,
+ sasl_callback_ft * pproc,
+ void **pcontext);
+
+extern void
+_sasl_log(sasl_conn_t *conn,
+ int level,
+ const char *fmt,
+ ...);
+
+void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl);
+int _sasl_add_string(char **out, size_t *alloclen,
+ size_t *outlen, const char *add);
+
+/* More Generic Utilities in common.c */
+extern int _sasl_strdup(const char *in, char **out, size_t *outlen);
+
+/* Basically a conditional call to realloc(), if we need more */
+int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen);
+
+/* convert an iovec to a single buffer */
+int _iovec_to_buf(const struct iovec *vec,
+ unsigned numiov, buffer_info_t **output);
+
+/* Convert between string formats and sockaddr formats */
+int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
+ char *out, unsigned outlen);
+int _sasl_ipfromstring(const char *addr, struct sockaddr *out,
+ socklen_t outlen);
+
+/*
+ * external plugin (external.c)
+ */
+int external_client_plug_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount);
+int external_server_plug_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount);
+
+/* Mech Listing Functions */
+int _sasl_build_mechlist(void);
+int _sasl_server_listmech(sasl_conn_t *conn,
+ const char *user,
+ const char *prefix,
+ const char *sep,
+ const char *suffix,
+ const char **result,
+ unsigned *plen,
+ int *pcount);
+int _sasl_client_listmech(sasl_conn_t *conn,
+ const char *prefix,
+ const char *sep,
+ const char *suffix,
+ const char **result,
+ unsigned *plen,
+ int *pcount);
+/* Just create a straight list of them */
+sasl_string_list_t *_sasl_client_mechs(void);
+sasl_string_list_t *_sasl_server_mechs(void);
+
+/*
+ * config file declarations (config.c)
+ */
+extern const char *sasl_config_getstring(const char *key,const char *def);
+
+/* checkpw.c */
+#ifdef DO_SASL_CHECKAPOP
+extern int _sasl_auxprop_verify_apop(sasl_conn_t *conn,
+ const char *userstr,
+ const char *challenge,
+ const char *response,
+ const char *user_realm);
+#endif /* DO_SASL_CHECKAPOP */
+
+/* Auxprop Plugin (sasldb.c) */
+extern int sasldb_auxprop_plug_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_auxprop_plug_t **plug,
+ const char *plugname);
+
+/*
+ * auxprop.c
+ */
+extern int _sasl_auxprop_add_plugin(void *p, void *library);
+extern void _sasl_auxprop_free(void);
+extern int _sasl_auxprop_lookup(sasl_server_params_t *sparams,
+ unsigned flags,
+ const char *user, unsigned ulen);
+
+/*
+ * canonusr.c
+ */
+void _sasl_canonuser_free();
+extern int internal_canonuser_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_canonuser_plug_t **plug,
+ const char *plugname);
+extern int _sasl_canon_user(sasl_conn_t *conn,
+ const char *user,
+ unsigned ulen,
+ unsigned flags,
+ sasl_out_params_t *oparams);
+int _sasl_canon_user_lookup (sasl_conn_t *conn,
+ const char *user,
+ unsigned ulen,
+ unsigned flags,
+ sasl_out_params_t *oparams);
+
+/*
+ * saslutil.c
+ */
+int get_fqhostname(
+ char *name,
+ int namelen,
+ int abort_if_no_fqdn
+ );
+
+#ifndef HAVE_GETHOSTNAME
+#ifdef sun
+/* gotta define gethostname ourselves on suns */
+extern int gethostname(char *, int);
+#endif
+#endif /* HAVE_GETHOSTNAME */
+
+#ifdef WIN32
+char* _sasl_wchar_to_utf8(WCHAR *str);
+WCHAR* _sasl_utf8_to_wchar(const char *str);
+#endif
+
+#endif /* SASLINT_H */
diff --git a/contrib/libs/sasl/lib/saslutil.c b/contrib/libs/sasl/lib/saslutil.c
new file mode 100644
index 0000000000..46c628c7f5
--- /dev/null
+++ b/contrib/libs/sasl/lib/saslutil.c
@@ -0,0 +1,790 @@
+/* saslutil.c
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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.
+ */
+
+#if defined(WIN32)
+#define _CRT_RAND_S
+#endif
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#include "saslint.h"
+#include <saslutil.h>
+
+/* Contains:
+ *
+ * sasl_decode64
+ * sasl_encode64
+ * sasl_mkchal
+ * sasl_utf8verify
+ * sasl_randcreate
+ * sasl_randfree
+ * sasl_randseed
+ * sasl_rand
+ * sasl_churn
+ * sasl_erasebuffer
+ */
+
+char *encode_table;
+char *decode_table;
+
+#define RPOOL_SIZE 3
+struct sasl_rand_s {
+ unsigned short pool[RPOOL_SIZE];
+ /* since the init time might be really bad let's make this lazy */
+ int initialized;
+};
+
+#define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
+
+static char basis_64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????";
+
+static signed char index_64[128] = {
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+ 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
+ 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+ -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+ 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+};
+
+/* base64 encode
+ * in -- input data
+ * inlen -- input data length
+ * out -- output buffer (will be NUL terminated)
+ * outmax -- max size of output buffer
+ * result:
+ * outlen -- gets actual length of output buffer (optional)
+ *
+ * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
+ */
+
+int sasl_encode64(const char *_in,
+ unsigned inlen,
+ char *_out,
+ unsigned outmax,
+ unsigned *outlen)
+{
+ const unsigned char *in = (const unsigned char *)_in;
+ unsigned char *out = (unsigned char *)_out;
+ unsigned char oval;
+ unsigned olen;
+
+ /* check params */
+ if ((inlen > 0) && (in == NULL)) return SASL_BADPARAM;
+
+ /* Will it fit? */
+ olen = (inlen + 2) / 3 * 4;
+ if (outlen) {
+ *outlen = olen;
+ }
+ if (outmax <= olen) {
+ return SASL_BUFOVER;
+ }
+
+ /* Do the work... */
+ while (inlen >= 3) {
+ /* user provided max buffer size; make sure we don't go over it */
+ *out++ = basis_64[in[0] >> 2];
+ *out++ = basis_64[((in[0] << 4) & 0x30) | (in[1] >> 4)];
+ *out++ = basis_64[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
+ *out++ = basis_64[in[2] & 0x3f];
+ in += 3;
+ inlen -= 3;
+ }
+ if (inlen > 0) {
+ /* user provided max buffer size; make sure we don't go over it */
+ *out++ = basis_64[in[0] >> 2];
+ oval = (in[0] << 4) & 0x30;
+ if (inlen > 1) oval |= in[1] >> 4;
+ *out++ = basis_64[oval];
+ *out++ = (inlen < 2) ? '=' : basis_64[(in[1] << 2) & 0x3c];
+ *out++ = '=';
+ }
+
+ *out = '\0';
+
+ return SASL_OK;
+}
+
+/* base64 decode
+ * in -- input data
+ * inlen -- length of input data
+ * out -- output data (may be same as in, must have enough space)
+ * outmax -- max size of output buffer
+ * result:
+ * outlen -- actual output length
+ *
+ * returns:
+ * SASL_BADPROT on bad base64,
+ * SASL_BUFOVER if result won't fit,
+ * SASL_CONTINUE on a partial block,
+ * SASL_OK on success
+ */
+
+int sasl_decode64(const char *in,
+ unsigned inlen,
+ char *out,
+ unsigned outmax, /* size of the buffer, not counting the NUL */
+ unsigned *outlen)
+{
+ unsigned len = 0;
+ unsigned j;
+ int c[4];
+ int saw_equal = 0;
+
+ /* check parameters */
+ if (out == NULL) return SASL_FAIL;
+
+ if (inlen > 0 && *in == '\r') return SASL_FAIL;
+
+ while (inlen > 3) {
+ /* No data is valid after an '=' character */
+ if (saw_equal) {
+ return SASL_BADPROT;
+ }
+
+ for (j = 0; j < 4; j++) {
+ c[j] = in[0];
+ in++;
+ inlen--;
+ }
+
+ if (CHAR64(c[0]) == -1 || CHAR64(c[1]) == -1) return SASL_BADPROT;
+ if (c[2] != '=' && CHAR64(c[2]) == -1) return SASL_BADPROT;
+ if (c[3] != '=' && CHAR64(c[3]) == -1) return SASL_BADPROT;
+ /* No data is valid after a '=' character, unless it is another '=' */
+ if (c[2] == '=' && c[3] != '=') return SASL_BADPROT;
+ if (c[2] == '=' || c[3] == '=') {
+ saw_equal = 1;
+ }
+
+ *out++ = (CHAR64(c[0]) << 2) | (CHAR64(c[1]) >> 4);
+ if (++len >= outmax) return SASL_BUFOVER;
+ if (c[2] != '=') {
+ *out++ = ((CHAR64(c[1]) << 4) & 0xf0) | (CHAR64(c[2]) >> 2);
+ if (++len >= outmax) return SASL_BUFOVER;
+ if (c[3] != '=') {
+ *out++ = ((CHAR64(c[2]) << 6) & 0xc0) | CHAR64(c[3]);
+ if (++len >= outmax) return SASL_BUFOVER;
+ }
+ }
+ }
+
+ *out = '\0'; /* NUL terminate the output string */
+
+ if (outlen) *outlen = len;
+
+ if (inlen != 0) {
+ if (saw_equal) {
+ /* Unless there is CRLF at the end? */
+ return SASL_BADPROT;
+ } else {
+ return (SASL_CONTINUE);
+ }
+ }
+
+ return SASL_OK;
+}
+
+/* make a challenge string (NUL terminated)
+ * buf -- buffer for result
+ * maxlen -- max length of result
+ * hostflag -- 0 = don't include hostname, 1 = include hostname
+ * returns final length or 0 if not enough space
+ */
+
+int sasl_mkchal(sasl_conn_t *conn,
+ char *buf,
+ unsigned maxlen,
+ unsigned hostflag)
+{
+ sasl_rand_t *pool = NULL;
+ unsigned long randnum;
+ int ret;
+ time_t now;
+ unsigned len;
+
+ len = 4 /* <.>\0 */
+ + (2 * 20); /* 2 numbers, 20 => max size of 64bit
+ * ulong in base 10 */
+ if (hostflag && conn->serverFQDN)
+ len += (unsigned) strlen(conn->serverFQDN) + 1 /* for the @ */;
+
+ if (maxlen < len)
+ return 0;
+
+ ret = sasl_randcreate(&pool);
+ if(ret != SASL_OK) return 0; /* xxx sasl return code? */
+
+ sasl_rand(pool, (char *)&randnum, sizeof(randnum));
+ sasl_randfree(&pool);
+
+ time(&now);
+
+ if (hostflag && conn->serverFQDN)
+ snprintf(buf,maxlen, "<%lu.%lu@%s>", randnum, (unsigned long)now, conn->serverFQDN); /* don't care much about time 32bit overlap */
+ else
+ snprintf(buf,maxlen, "<%lu.%lu>", randnum, (unsigned long)now);
+
+ return (int) strlen(buf);
+}
+
+ /* borrowed from larry. probably works :)
+ * probably is also in acap server somewhere
+ */
+int sasl_utf8verify(const char *str, unsigned len)
+{
+ unsigned i;
+ for (i = 0; i < len; i++) {
+ /* how many octets? */
+ int seqlen = 0;
+ while (str[i] & (0x80 >> seqlen)) ++seqlen;
+ if (seqlen == 0) continue; /* this is a valid US-ASCII char */
+ if (seqlen == 1) return SASL_BADPROT; /* this shouldn't happen here */
+ if (seqlen > 6) return SASL_BADPROT; /* illegal */
+ while (--seqlen)
+ if ((str[++i] & 0xC0) != 0x80) return SASL_BADPROT; /* needed a 10 octet */
+ }
+ return SASL_OK;
+}
+
+/*
+ * To see why this is really bad see RFC 1750
+ *
+ * unfortunatly there currently is no way to make
+ * cryptographically secure pseudo random numbers
+ * without specialized hardware etc...
+ * thus, this is for nonce use only
+ */
+void getranddata(unsigned short ret[RPOOL_SIZE])
+{
+ long curtime;
+
+ memset(ret, 0, RPOOL_SIZE*sizeof(unsigned short));
+
+#ifdef DEV_RANDOM
+ {
+ int fd;
+
+ fd = open(DEV_RANDOM, O_RDONLY);
+ if(fd != -1) {
+ unsigned char *buf = (unsigned char *)ret;
+ ssize_t bytesread = 0;
+ size_t bytesleft = RPOOL_SIZE*sizeof(unsigned short);
+
+ do {
+ bytesread = read(fd, buf, bytesleft);
+ if(bytesread == -1 && errno == EINTR) continue;
+ else if(bytesread <= 0) break;
+ bytesleft -= bytesread;
+ buf += bytesread;
+ } while(bytesleft != 0);
+
+ close(fd);
+ }
+ }
+#endif
+
+#ifdef HAVE_GETPID
+ ret[0] ^= (unsigned short) getpid();
+#endif
+
+#ifdef HAVE_GETTIMEOFDAY
+ {
+ struct timeval tv;
+
+ /* xxx autoconf macro */
+#ifdef _SVID_GETTOD
+ if (!gettimeofday(&tv))
+#else
+ if (!gettimeofday(&tv, NULL))
+#endif
+ {
+ /* longs are guaranteed to be at least 32 bits; we need
+ 16 bits in each short */
+ ret[0] ^= (unsigned short) (tv.tv_sec & 0xFFFF);
+ ret[1] ^= (unsigned short) (clock() & 0xFFFF);
+ ret[1] ^= (unsigned short) (tv.tv_usec >> 16);
+ ret[2] ^= (unsigned short) (tv.tv_usec & 0xFFFF);
+ return;
+ }
+ }
+#endif /* HAVE_GETTIMEOFDAY */
+
+ /* if all else fails just use time() */
+ curtime = (long) time(NULL); /* better be at least 32 bits */
+
+ ret[0] ^= (unsigned short) (curtime >> 16);
+ ret[1] ^= (unsigned short) (curtime & 0xFFFF);
+ ret[2] ^= (unsigned short) (clock() & 0xFFFF);
+
+ return;
+}
+
+int sasl_randcreate(sasl_rand_t **rpool)
+{
+ (*rpool)=sasl_ALLOC(sizeof(sasl_rand_t));
+ if ((*rpool) == NULL) return SASL_NOMEM;
+
+ /* init is lazy */
+ (*rpool)->initialized = 0;
+
+ return SASL_OK;
+}
+
+void sasl_randfree(sasl_rand_t **rpool)
+{
+ sasl_FREE(*rpool);
+}
+
+void sasl_randseed (sasl_rand_t *rpool, const char *seed, unsigned len)
+{
+ /* is it acceptable to just use the 1st 3 char's given??? */
+ unsigned int lup;
+
+ /* check params */
+ if (seed == NULL) return;
+ if (rpool == NULL) return;
+
+ rpool->initialized = 1;
+
+ if (len > sizeof(unsigned short)*RPOOL_SIZE)
+ len = sizeof(unsigned short)*RPOOL_SIZE;
+
+ for (lup = 0; lup < len; lup += 2)
+ rpool->pool[lup/2] = (seed[lup] << 8) + seed[lup + 1];
+}
+
+static void randinit(sasl_rand_t *rpool)
+{
+ if (!rpool) return;
+
+ if (!rpool->initialized) {
+ getranddata(rpool->pool);
+ rpool->initialized = 1;
+#if !(defined(WIN32)||defined(macintosh))
+#ifndef HAVE_JRAND48
+ {
+ /* xxx varies by platform */
+ unsigned int *foo = (unsigned int *)rpool->pool;
+ srandom(*foo);
+ }
+#endif /* HAVE_JRAND48 */
+#elif defined(WIN32)
+ {
+ unsigned int *foo = (unsigned int *)rpool->pool;
+ srand(*foo);
+ }
+#endif /* WIN32 */
+ }
+
+}
+
+void sasl_rand (sasl_rand_t *rpool, char *buf, unsigned len)
+{
+ unsigned int lup;
+#if defined(WIN32) && !defined(__MINGW32__)
+ unsigned int randomValue;
+#endif
+
+ /* check params */
+ if (!rpool || !buf) return;
+
+ /* init if necessary */
+ randinit(rpool);
+
+ for (lup = 0; lup < len; lup++) {
+#if defined(__MINGW32__)
+ buf[lup] = (char) (rand() >> 8);
+#elif defined(WIN32)
+ if (rand_s(&randomValue) != 0) {
+ randomValue = rand();
+ }
+
+ buf[lup] = (char) (randomValue >> 8);
+#elif defined(macintosh)
+ buf[lup] = (char) (rand() >> 8);
+#else /* !WIN32 && !macintosh */
+#ifdef HAVE_JRAND48
+ buf[lup] = (char) (jrand48(rpool->pool) >> 8);
+#else
+ buf[lup] = (char) (random() >> 8);
+#endif /* HAVE_JRAND48 */
+#endif /* WIN32 */
+ }
+}
+
+/* this function is just a bad idea all around, since we're not trying to
+ implement a true random number generator */
+void sasl_churn (sasl_rand_t *rpool, const char *data, unsigned len)
+{
+ unsigned int lup;
+
+ /* check params */
+ if (!rpool || !data) return;
+
+ /* init if necessary */
+ randinit(rpool);
+
+ for (lup=0; lup<len; lup++)
+ rpool->pool[lup % RPOOL_SIZE] ^= data[lup];
+}
+
+void sasl_erasebuffer(char *buf, unsigned len) {
+ memset(buf, 0, len);
+}
+
+/* Lowercase string in place */
+char *sasl_strlower (
+ char *val
+)
+{
+ int i;
+
+ if (val == NULL) {
+ return (NULL);
+ }
+
+/* don't use tolower(), as it is locale dependent */
+
+ for (i = 0; val[i] != '\0'; i++) {
+ if (val[i] >= 'A' && val[i] <= 'Z') {
+ val[i] = val[i] - 'A' + 'a';
+ }
+ }
+
+ return (val);
+}
+
+/* A version of gethostname that tries hard to return a FQDN */
+int get_fqhostname(
+ char *name,
+ int namelen,
+ int abort_if_no_fqdn
+)
+{
+ int return_value;
+ struct addrinfo hints;
+ struct addrinfo *result;
+
+ return_value = gethostname (name, namelen);
+ name[namelen-1] = '\0'; /* insure string is always 0 terminated*/
+ if (return_value != 0) {
+ return (return_value);
+ }
+
+ if (strchr (name, '.') != NULL) {
+ goto LOWERCASE;
+ }
+
+/* gethostname hasn't returned a FQDN, we have to canonify it ourselves */
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_socktype = SOCK_STREAM; /* TCP only */
+/* A value of zero for ai_protocol indicates the caller will accept any protocol. or IPPROTO_TCP? */
+ hints.ai_protocol = 0; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ hints.ai_addrlen = 0;
+ hints.ai_canonname = NULL;
+ hints.ai_addr = NULL;
+ hints.ai_next = NULL;
+
+ if (getaddrinfo(name,
+ NULL, /* don't care abour service/port */
+ &hints,
+ &result) != 0) {
+ if (abort_if_no_fqdn) {
+ /* errno on Unix, WSASetLastError on Windows are already done by the function */
+ return (-1);
+ } else {
+ goto LOWERCASE;
+ }
+ }
+
+ if (result == NULL || result->ai_canonname == NULL
+ || strchr (result->ai_canonname, '.') == NULL
+ || strlen (result->ai_canonname) > namelen -1) {
+ freeaddrinfo (result);
+ if (abort_if_no_fqdn) {
+#ifdef WIN32
+ WSASetLastError (WSANO_DATA);
+#elif defined(ENODATA)
+ errno = ENODATA;
+#elif defined(EADDRNOTAVAIL)
+ errno = EADDRNOTAVAIL;
+#endif
+ return (-1);
+ } else {
+ goto LOWERCASE;
+ }
+ }
+
+ strncpy (name, result->ai_canonname, namelen);
+ name[namelen-1] = '\0'; /* insure string is always 0 terminated*/
+ freeaddrinfo (result);
+
+LOWERCASE:
+ sasl_strlower (name);
+ return (0);
+}
+
+#if defined(WIN32) && !defined(__MINGW64_VERSION_MAJOR)
+/*****************************************************************************
+ *
+ * MODULE NAME : GETOPT.C
+ *
+ * COPYRIGHTS:
+ * This module contains code made available by IBM
+ * Corporation on an AS IS basis. Any one receiving the
+ * module is considered to be licensed under IBM copyrights
+ * to use the IBM-provided source code in any way he or she
+ * deems fit, including copying it, compiling it, modifying
+ * it, and redistributing it, with or without
+ * modifications. No license under any IBM patents or
+ * patent applications is to be implied from this copyright
+ * license.
+ *
+ * A user of the module should understand that IBM cannot
+ * provide technical support for the module and will not be
+ * responsible for any consequences of use of the program.
+ *
+ * Any notices, including this one, are not to be removed
+ * from the module without the prior written consent of
+ * IBM.
+ *
+ * AUTHOR: Original author:
+ * G. R. Blair (BOBBLAIR at AUSVM1)
+ * Internet: bobblair@bobblair.austin.ibm.com
+ *
+ * Extensively revised by:
+ * John Q. Walker II, Ph.D. (JOHHQ at RALVM6)
+ * Internet: johnq@ralvm6.vnet.ibm.com
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ * getopt()
+ *
+ * The getopt() function is a command line parser. It returns the next
+ * option character in argv that matches an option character in opstring.
+ *
+ * The argv argument points to an array of argc+1 elements containing argc
+ * pointers to character strings followed by a null pointer.
+ *
+ * The opstring argument points to a string of option characters; if an
+ * option character is followed by a colon, the option is expected to have
+ * an argument that may or may not be separated from it by white space.
+ * The external variable optarg is set to point to the start of the option
+ * argument on return from getopt().
+ *
+ * The getopt() function places in optind the argv index of the next argument
+ * to be processed. The system initializes the external variable optind to
+ * 1 before the first call to getopt().
+ *
+ * When all options have been processed (that is, up to the first nonoption
+ * argument), getopt() returns EOF. The special option "--" may be used to
+ * delimit the end of the options; EOF will be returned, and "--" will be
+ * skipped.
+ *
+ * The getopt() function returns a question mark (?) when it encounters an
+ * option character not included in opstring. This error message can be
+ * disabled by setting opterr to zero. Otherwise, it returns the option
+ * character that was detected.
+ *
+ * If the special option "--" is detected, or all options have been
+ * processed, EOF is returned.
+ *
+ * Options are marked by either a minus sign (-) or a slash (/).
+ *
+ * No errors are defined.
+ *****************************************************************************/
+
+#include <string.h> /* for strchr() */
+
+/* static (global) variables that are specified as exported by getopt() */
+__declspec(dllexport) char *optarg = NULL; /* pointer to the start of the option argument */
+__declspec(dllexport) int optind = 1; /* number of the next argv[] to be evaluated */
+__declspec(dllexport) int opterr = 1; /* non-zero if a question mark should be returned */
+
+
+/* handle possible future character set concerns by putting this in a macro */
+#define _next_char(string) (char)(*(string+1))
+
+int getopt(int argc, char *argv[], char *opstring)
+{
+ static char *pIndexPosition = NULL; /* place inside current argv string */
+ char *pArgString = NULL; /* where to start from next */
+ char *pOptString; /* the string in our program */
+
+
+ if (pIndexPosition != NULL) {
+ /* we last left off inside an argv string */
+ if (*(++pIndexPosition)) {
+ /* there is more to come in the most recent argv */
+ pArgString = pIndexPosition;
+ }
+ }
+
+ if (pArgString == NULL) {
+ /* we didn't leave off in the middle of an argv string */
+ if (optind >= argc) {
+ /* more command-line arguments than the argument count */
+ pIndexPosition = NULL; /* not in the middle of anything */
+ return EOF; /* used up all command-line arguments */
+ }
+
+ /*---------------------------------------------------------------------
+ * If the next argv[] is not an option, there can be no more options.
+ *-------------------------------------------------------------------*/
+ pArgString = argv[optind++]; /* set this to the next argument ptr */
+
+ if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */
+ ('-' != *pArgString)) {
+ --optind; /* point to current arg once we're done */
+ optarg = NULL; /* no argument follows the option */
+ pIndexPosition = NULL; /* not in the middle of anything */
+ return EOF; /* used up all the command-line flags */
+ }
+
+ /* check for special end-of-flags markers */
+ if ((strcmp(pArgString, "-") == 0) ||
+ (strcmp(pArgString, "--") == 0)) {
+ optarg = NULL; /* no argument follows the option */
+ pIndexPosition = NULL; /* not in the middle of anything */
+ return EOF; /* encountered the special flag */
+ }
+
+ pArgString++; /* look past the / or - */
+ }
+
+ if (':' == *pArgString) { /* is it a colon? */
+ /*---------------------------------------------------------------------
+ * Rare case: if opterr is non-zero, return a question mark;
+ * otherwise, just return the colon we're on.
+ *-------------------------------------------------------------------*/
+ return (opterr ? (int)'?' : (int)':');
+ }
+ else if ((pOptString = strchr(opstring, *pArgString)) == 0) {
+ /*---------------------------------------------------------------------
+ * The letter on the command-line wasn't any good.
+ *-------------------------------------------------------------------*/
+ optarg = NULL; /* no argument follows the option */
+ pIndexPosition = NULL; /* not in the middle of anything */
+ return (opterr ? (int)'?' : (int)*pArgString);
+ }
+ else {
+ /*---------------------------------------------------------------------
+ * The letter on the command-line matches one we expect to see
+ *-------------------------------------------------------------------*/
+ if (':' == _next_char(pOptString)) { /* is the next letter a colon? */
+ /* It is a colon. Look for an argument string. */
+ if ('\0' != _next_char(pArgString)) { /* argument in this argv? */
+ optarg = &pArgString[1]; /* Yes, it is */
+ }
+ else {
+ /*-------------------------------------------------------------
+ * The argument string must be in the next argv.
+ * But, what if there is none (bad input from the user)?
+ * In that case, return the letter, and optarg as NULL.
+ *-----------------------------------------------------------*/
+ if (optind < argc)
+ optarg = argv[optind++];
+ else {
+ optarg = NULL;
+ return (opterr ? (int)'?' : (int)*pArgString);
+ }
+ }
+ pIndexPosition = NULL; /* not in the middle of anything */
+ }
+ else {
+ /* it's not a colon, so just return the letter */
+ optarg = NULL; /* no argument follows the option */
+ pIndexPosition = pArgString; /* point to the letter we're on */
+ }
+ return (int)*pArgString; /* return the letter that matched */
+ }
+}
+
+#ifndef PASSWORD_MAX
+# define PASSWORD_MAX 255
+#endif
+
+#include <conio.h>
+char *
+getpass(prompt)
+const char *prompt;
+{
+ register char *p;
+ register int c;
+ static char pbuf[PASSWORD_MAX];
+
+ fprintf(stderr, "%s", prompt); (void) fflush(stderr);
+ for (p=pbuf; (c = _getch())!=13 && c!=EOF;) {
+ if (p < &pbuf[sizeof(pbuf)-1])
+ *p++ = (char) c;
+ }
+ *p = '\0';
+ fprintf(stderr, "\n"); (void) fflush(stderr);
+ return(pbuf);
+}
+
+
+
+#endif /* WIN32 */
diff --git a/contrib/libs/sasl/lib/server.c b/contrib/libs/sasl/lib/server.c
new file mode 100644
index 0000000000..bff461f825
--- /dev/null
+++ b/contrib/libs/sasl/lib/server.c
@@ -0,0 +1,2406 @@
+/* SASL server API implementation
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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"
+
+#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 */
+
+static 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 };
+ const char *user_delete_request[] = { SASL_AUX_PASSWORD_PROP, SASL_AUX_ALL, NULL };
+ sasl_server_userdb_setpass_t *setpass_cb = NULL;
+ void *context = NULL;
+ int tried_setpass = 0;
+ int failed = 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 **) &current_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, user_delete_request);
+ } else {
+ result = prop_request(s_conn->sparams->propctx, password_request);
+ }
+ if (result == SASL_OK) {
+ /* NOTE: When deleting users, this will work in a backward compatible way */
+ result = prop_set(s_conn->sparams->propctx, SASL_AUX_PASSWORD_PROP,
+ pass, passlen);
+ }
+ if (result == SASL_OK && flags & SASL_SET_DISABLE) {
+ result = prop_set(s_conn->sparams->propctx, SASL_AUX_ALL,
+ NULL, 0);
+ }
+ 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);
+ failed++;
+ } 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,
+ (sasl_callback_ft *)&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) {
+ if (tmpresult == SASL_CONSTRAINT_VIOLAT) {
+ if (result == SASL_OK) {
+ result = tmpresult;
+ }
+ } else {
+ result = tmpresult;
+ }
+ _sasl_log(conn, SASL_LOG_ERR,
+ "setpass callback failed for %s: %z",
+ user, tmpresult);
+ failed++;
+ } else {
+ _sasl_log(conn, SASL_LOG_NOTE,
+ "setpass callback succeeded for %s", user);
+ }
+ }
+
+ /* now we let the mechanisms set their secrets */
+ for (sm = s_conn->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 if (tmpresult == SASL_CONSTRAINT_VIOLAT) {
+ _sasl_log(conn, SASL_LOG_ERR,
+ "%s: failed to set secret for %s: constrain violation",
+ m->plug->mech_name, user);
+ if (result == SASL_OK) {
+ result = tmpresult;
+ }
+ failed++;
+ } 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
+ );
+ failed++;
+ }
+ }
+
+ if (!tried_setpass) {
+ _sasl_log(conn, SASL_LOG_WARN,
+ "secret not changed for %s: "
+ "no writable auxprop plugin or setpass callback found",
+ user);
+ } else if (result == SASL_CONSTRAINT_VIOLAT) {
+ /* If not all setpass failed with SASL_CONSTRAINT_VIOLAT -
+ ignore SASL_CONSTRAINT_VIOLAT */
+ if (failed < tried_setpass) {
+ result = SASL_OK;
+ }
+ }
+
+ 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;
+
+ /* Just sanity check that sasl_server_done wasn't called yet */
+ if (_sasl_server_active != 0) {
+ if (s_conn->mech) {
+ void (*mech_dispose)(void *conn_context, const sasl_utils_t *utils);
+
+ mech_dispose = s_conn->mech->m.plug->mech_dispose;
+
+ if (mech_dispose) {
+ 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);
+ }
+
+ if (s_conn->mech_list != mechlist->mech_list) {
+ /* free connection-specific mech_list */
+ mechanism_t *m, *prevm;
+
+ m = s_conn->mech_list; /* m point to beginning of the list */
+
+ while (m) {
+ prevm = m;
+ m = m->next;
+ sasl_FREE(prevm);
+ }
+ }
+
+ _sasl_conn_dispose(pconn);
+}
+
+static int init_mechlist(void)
+{
+ sasl_utils_t *newutils = NULL;
+
+ /* 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;
+}
+
+static int mech_compare(const sasl_server_plug_t *a,
+ const sasl_server_plug_t *b)
+{
+ unsigned sec_diff;
+ unsigned features_diff;
+
+ /* XXX the following is fairly arbitrary, but its independent
+ of the order in which the plugins are loaded
+ */
+ sec_diff = a->security_flags ^ b->security_flags;
+ if (sec_diff & a->security_flags & SASL_SEC_NOANONYMOUS) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NOANONYMOUS) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_NOPLAINTEXT) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NOPLAINTEXT) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_MUTUAL_AUTH) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_MUTUAL_AUTH) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_NOACTIVE) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NOACTIVE) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_NODICTIONARY) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NODICTIONARY) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_FORWARD_SECRECY) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_FORWARD_SECRECY) return -1;
+
+ features_diff = a->features ^ b->features;
+ if (features_diff & a->features & SASL_FEAT_CHANNEL_BINDING) return 1;
+ if (features_diff & b->features & SASL_FEAT_CHANNEL_BINDING) return -1;
+
+ if (a->max_ssf > b->max_ssf) return 1;
+ if (a->max_ssf < b->max_ssf) return -1;
+
+ if (SASL_GET_HASH_STRENGTH(a->security_flags) > SASL_GET_HASH_STRENGTH(b->security_flags)) return 1;
+ if (SASL_GET_HASH_STRENGTH(a->security_flags) < SASL_GET_HASH_STRENGTH(b->security_flags)) return -1;
+
+ return 0;
+}
+
+/*
+ * 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 = NULL;
+ sasl_server_plug_init_t *entry_point = NULL;
+ 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,
+ "%s_client_plug_init() failed in sasl_server_add_plugin(): %z\n",
+ plugname, 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 sasl_server_add_plugin for '%s': %d expected, but %d reported",
+ plugname,
+ SASL_SERVER_PLUG_VERSION,
+ version);
+ return SASL_BADVERS;
+ }
+
+ for (lupe=0;lupe < plugcount ;lupe++, pluglist++)
+ {
+ mechanism_t *mech, *mp;
+
+ 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;
+
+ /* whether 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; */
+
+ /* sort mech_list by relative "strength" */
+ mp = mechlist->mech_list;
+ if (!mp || mech_compare(pluglist, mp->m.plug) >= 0) {
+ /* add mech to head of list */
+ mech->next = mechlist->mech_list;
+ mechlist->mech_list = mech;
+ } else {
+ /* find where to insert mech into list */
+ while (mp->next &&
+ mech_compare(pluglist, mp->next->m.plug) <= 0) mp = mp->next;
+ mech->next = mp->next;
+ mp->next = mech;
+ }
+ mechlist->mech_length++;
+ }
+
+ return SASL_OK;
+}
+
+int sasl_server_done(void)
+{
+ int result = SASL_CONTINUE;
+
+ if (_sasl_server_cleanup_hook == NULL && _sasl_client_cleanup_hook == NULL) {
+ return SASL_NOTINIT;
+ }
+
+ if (_sasl_server_cleanup_hook) {
+ result = _sasl_server_cleanup_hook();
+
+ if (result == SASL_OK) {
+ _sasl_server_idle_hook = NULL;
+ _sasl_server_cleanup_hook = NULL;
+ } else {
+ return result;
+ }
+ }
+
+ if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
+ return result;
+ }
+
+ sasl_common_done();
+
+ 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_FREE(mechlist);
+ mechlist = NULL;
+ }
+
+ /* Free the auxprop plugins */
+ _sasl_auxprop_free();
+
+ global_callbacks.callbacks = NULL;
+ global_callbacks.appname = NULL;
+
+ sasl_config_done();
+
+ return SASL_OK;
+}
+
+static int server_idle(sasl_conn_t *conn)
+{
+ sasl_server_conn_t *s_conn = NULL;
+ mechanism_t *m;
+
+ if (! mechlist) {
+ return 0;
+ }
+
+ if (!conn)
+ return 1;
+ s_conn = (sasl_server_conn_t *) conn;
+
+ for (m = s_conn->mech_list;
+ m != NULL;
+ m = m->next) {
+ if (m->m.plug->idle
+ && m->m.plug->idle(m->m.plug->glob_context,
+ conn,
+ s_conn->sparams)) {
+ 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,
+ (char **) &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", (int)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 }
+ };
+
+ /* 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;
+
+ 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, (sasl_callback_ft *)&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, (sasl_callback_ft *)&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;
+ const char *mlist = NULL;
+ int plus = 0;
+
+ 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, (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+ getopt(context, NULL, "log_level", &log_level, NULL);
+ getopt(context, NULL, "auto_transition", &auto_trans, NULL);
+ getopt(context, NULL, "mech_list", &mlist, 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;
+ }
+
+ /* if we have a mech_list, create ordered list of avail mechs for this conn */
+ if (mlist) {
+ const char *cp;
+ mechanism_t *mptr, *tail = NULL;
+
+ while (*mlist) {
+ /* find end of current mech name */
+ for (cp = mlist; *cp && !isspace((int) *cp); cp++);
+
+ /* search for mech name in loaded plugins */
+ for (mptr = mechlist->mech_list; mptr; mptr = mptr->next) {
+ const sasl_server_plug_t *plug = mptr->m.plug;
+
+ if (_sasl_is_equal_mech(mlist, plug->mech_name, (size_t) (cp - mlist), &plus)) {
+ /* found a match */
+ break;
+ }
+ }
+ if (mptr) {
+ mechanism_t *new = sasl_ALLOC(sizeof(mechanism_t));
+ if (!new) return SASL_NOMEM;
+
+ memcpy(&new->m, &mptr->m, sizeof(server_sasl_mechanism_t));
+ new->next = NULL;
+
+ if (!serverconn->mech_list) {
+ serverconn->mech_list = new;
+ tail = serverconn->mech_list;
+ }
+ else {
+ if (tail)
+ tail->next = new;
+ tail = new;
+ }
+ serverconn->mech_length++;
+ }
+
+ /* find next mech name */
+ mlist = cp;
+ while (*mlist && isspace((int) *mlist)) mlist++;
+ }
+ }
+ else {
+ serverconn->mech_list = mechlist->mech_list;
+ serverconn->mech_length = mechlist->mech_length;
+ }
+
+ serverconn->sparams->canon_user = &_sasl_canon_user_lookup;
+ 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;
+ context_list_t *mech_context_list_entry = NULL;
+ void *context = NULL;
+ sasl_ssf_t minssf = 0;
+
+ if(!conn) return SASL_NOMECH;
+
+ if(! mech || ! mech->m.plug) {
+ PARAMERROR(conn);
+ return SASL_NOMECH;
+ }
+
+ plug = mech->m.plug;
+
+ /* 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;
+ } else {
+ context = cur->context;
+ mech_context_list_entry = cur;
+ }
+ 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 */
+ }
+
+ 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) {
+ if (mech_context_list_entry != NULL) {
+ /* Update the context. It shouldn't have changed, but who knows */
+ mech_context_list_entry->context = context;
+ } else {
+ /* 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;
+ }
+ if ((conn->flags & SASL_NEED_HTTP) &&
+ !(plug->features & SASL_FEAT_SUPPORTS_HTTP)) {
+ 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,
+ (sasl_callback_ft *)&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;
+ size_t mech_len;
+ int plus = 0;
+
+ if (_sasl_server_active==0) return SASL_NOTINIT;
+
+ /* check parameters */
+ if(!conn) return SASL_BADPARAM;
+
+ if (!mech || ((clientin == NULL) && (clientinlen > 0)))
+ PARAMERROR(conn);
+
+ if (serverout) *serverout = NULL;
+ if (serveroutlen) *serveroutlen = 0;
+
+ /* make sure mech is valid mechanism
+ if not return appropriate error */
+ m = s_conn->mech_list;
+ mech_len = strlen(mech);
+
+ while (m != NULL) {
+ if (_sasl_is_equal_mech(mech, m->m.plug->mech_name, mech_len, &plus)) {
+ 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 = NULL;
+ void *library = NULL;
+ sasl_server_plug_t *pluglist = NULL;
+ 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);
+ }
+ }
+
+ if (conn->context) {
+ s_conn->mech->m.plug->mech_dispose(conn->context,
+ s_conn->sparams->utils);
+ conn->context = NULL;
+ }
+
+ /* 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 = cur->next;
+ conn->context = cur->context;
+ sasl_FREE(cur);
+ break;
+ }
+ }
+
+ 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 */
+ if (serverout) *serverout = "";
+ if (serveroutlen) *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;
+ }
+ conn->oparams.doneflag = 0;
+ }
+
+ RETURN(conn,result);
+}
+
+
+/* perform one step of the SASL exchange
+ * clientinlen & clientin -- client data
+ * NULL on first step if no optional client step
+ * serveroutlen & serverout -- 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;
+ }
+
+ /* Validate channel bindings */
+ switch (conn->oparams.cbindingdisp) {
+ case SASL_CB_DISP_NONE:
+ if (SASL_CB_CRITICAL(s_conn->sparams)) {
+ sasl_seterror(conn, 0,
+ "server requires channel binding but client provided none");
+ ret = SASL_BADBINDING;
+ }
+ break;
+ case SASL_CB_DISP_WANT:
+ if (SASL_CB_PRESENT(s_conn->sparams)) {
+ sasl_seterror(conn, 0,
+ "client incorrectly assumed server had no channel binding");
+ ret = SASL_BADAUTH;
+ }
+ break;
+ case SASL_CB_DISP_USED:
+ if (!SASL_CB_PRESENT(s_conn->sparams)) {
+ sasl_seterror(conn, 0,
+ "client provided channel binding but server had none");
+ ret = SASL_BADBINDING;
+ } else if (strcmp(conn->oparams.cbindingname,
+ s_conn->sparams->cbinding->name) != 0) {
+ sasl_seterror(conn, 0,
+ "client channel binding %s does not match server %s",
+ conn->oparams.cbindingname, s_conn->sparams->cbinding->name);
+ ret = SASL_BADBINDING;
+ }
+ break;
+ }
+
+ if (ret == SASL_OK &&
+ (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;
+ }
+ conn->oparams.doneflag = 0;
+ }
+
+ RETURN(conn, ret);
+}
+
+/* returns the length of all the mechanisms
+ * added up
+ */
+
+static unsigned mech_names_len(mechanism_t *mech_list)
+{
+ mechanism_t *listptr;
+ unsigned result = 0;
+
+ for (listptr = 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 separate 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)
+{
+ sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn; /* cast */
+ 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 (!s_conn->mech_list || s_conn->mech_length <= 0)
+ INTERROR(conn, SASL_NOMECH);
+
+ resultlen = (prefix ? strlen(prefix) : 0)
+ + (strlen(mysep) * (s_conn->mech_length - 1) * 2)
+ + (mech_names_len(s_conn->mech_list) * 2) /* including -PLUS variant */
+ + (s_conn->mech_length * (sizeof("-PLUS") - 1))
+ + (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 = s_conn->mech_list;
+
+ flag = 0;
+ /* make list */
+ for (lup = 0; lup < s_conn->mech_length; lup++) {
+ /* currently, we don't use the "user" parameter for anything */
+ if (mech_permitted(conn, listptr) == SASL_OK) {
+
+ /*
+ * If the server would never succeed in the authentication of
+ * the non-PLUS-variant due to policy reasons, it MUST advertise
+ * only the PLUS-variant.
+ */
+ if ((listptr->m.plug->features & SASL_FEAT_CHANNEL_BINDING) &&
+ SASL_CB_PRESENT(s_conn->sparams)) {
+ if (pcount != NULL) {
+ (*pcount)++;
+ }
+ if (flag) {
+ strcat(conn->mechlist_buf, mysep);
+ } else {
+ flag = 1;
+ }
+ strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
+ strcat(conn->mechlist_buf, "-PLUS");
+ }
+
+ /*
+ * If the server cannot support channel binding, it SHOULD
+ * advertise only the non-PLUS-variant. Here, supporting channel
+ * binding means the underlying SASL mechanism supports it and
+ * the application has set some channel binding data.
+ */
+ if (!SASL_CB_PRESENT(s_conn->sparams) ||
+ !SASL_CB_CRITICAL(s_conn->sparams)) {
+ if (pcount != NULL) {
+ (*pcount)++;
+ }
+ if (flag) {
+ strcat(conn->mechlist_buf, mysep);
+ } else {
+ flag = 1;
+ }
+ 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,
+ (sasl_callback_ft *)&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, (sasl_callback_ft *)&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) %s", mlist);
+ }
+
+ 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 and lookup additional properties */
+ 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
+ * SASL_UNAVAIL -- remote authentication server unavailable, try again later
+ */
+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, (sasl_callback_ft *)&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]);
+
+ /* canonicalize the username and lookup any associated properties */
+ result = _sasl_canon_user_lookup (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 __attribute__((unused))
+)
+{
+ 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_DONTUSE_USERPASSWD) {
+ printf ("%cDONTUSE_USERPASSWD", 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->plug->features & SASL_FEAT_GSS_FRAMING) {
+ printf ("%cGSS_FRAMING", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_CHANNEL_BINDING) {
+ printf ("%cCHANNEL_BINDING", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_SUPPORTS_HTTP) {
+ printf ("%cSUPPORTS_HTTP", 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);
+}
diff --git a/contrib/libs/sasl/lib/seterror.c b/contrib/libs/sasl/lib/seterror.c
new file mode 100644
index 0000000000..05eec9a8e2
--- /dev/null
+++ b/contrib/libs/sasl/lib/seterror.c
@@ -0,0 +1,263 @@
+/* seterror.c - sasl_seterror split out because glue libraries
+ * can't pass varargs lists
+ * Rob Siemborski
+ * Tim Martin
+ * split from common.c by Rolf Braun
+ */
+
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#ifdef HAVE_SYSLOG
+#include <syslog.h>
+#endif
+#include <stdarg.h>
+#include <ctype.h>
+
+#include <sasl.h>
+#include <saslutil.h>
+#include <saslplug.h>
+#include "saslint.h"
+
+#ifdef WIN32
+/* need to handle the fact that errno has been defined as a function
+ in a dll, not an extern int */
+# ifdef errno
+# undef errno
+# endif /* errno */
+#endif /* WIN32 */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* this is apparently no longer a user function */
+static int _sasl_seterror_usererr(int saslerr)
+{
+ /* Hide the difference in a username failure and a password failure */
+ if (saslerr == SASL_NOUSER)
+ return SASL_BADAUTH;
+
+ /* otherwise return the error given; no transform necessary */
+ return saslerr;
+}
+
+/* set the error string which will be returned by sasl_errdetail() using
+ * syslog()-style formatting (e.g. printf-style with %m as the string form
+ * of an errno error)
+ *
+ * primarily for use by server callbacks such as the sasl_authorize_t
+ * callback and internally to plug-ins
+ *
+ * This will also trigger a call to the SASL logging callback (if any)
+ * with a level of SASL_LOG_FAIL unless the SASL_NOLOG flag is set.
+ *
+ * Messages should be sensitive to the current language setting. If there
+ * is no SASL_CB_LANGUAGE callback messages MUST be US-ASCII otherwise UTF-8
+ * is used and use of RFC 2482 for mixed-language text is encouraged.
+ *
+ * if conn is NULL, function does nothing
+ */
+void sasl_seterror(sasl_conn_t *conn,
+ unsigned flags,
+ const char *fmt, ...)
+{
+ size_t outlen=0; /* current length of output buffer */
+ size_t pos = 0; /* current position in format string */
+ size_t formatlen;
+ int result;
+ sasl_log_t *log_cb = NULL;
+ void *log_ctx;
+ int ival;
+ char *cval;
+ va_list ap; /* varargs thing */
+ char **error_buf;
+ size_t *error_buf_len;
+
+ if(!conn) {
+#ifndef SASL_OSX_CFMGLUE
+ if(!(flags & SASL_NOLOG)) {
+ /* See if we have a logging callback... */
+ result = _sasl_getcallback(NULL, SASL_CB_LOG, (sasl_callback_ft *)&log_cb, &log_ctx);
+ if (result == SASL_OK && ! log_cb)
+ result = SASL_FAIL;
+ if (result != SASL_OK)
+ return;
+
+ log_cb(log_ctx, SASL_LOG_FAIL,
+ "No sasl_conn_t passed to sasl_seterror");
+ }
+#endif /* SASL_OSX_CFMGLUE */
+ return;
+ } else if(!fmt) return;
+
+/* we need to use a back end function to get the buffer because the
+ cfm glue can't be rooting around in the internal structs */
+ _sasl_get_errorbuf(conn, &error_buf, &error_buf_len);
+
+ formatlen = strlen(fmt);
+
+ va_start(ap, fmt); /* start varargs */
+
+ while(pos<formatlen)
+ {
+ if (fmt[pos]!='%') /* regular character */
+ {
+ result = _buf_alloc(error_buf, error_buf_len, outlen+1);
+ if (result != SASL_OK)
+ goto done;
+ (*error_buf)[outlen]=fmt[pos];
+ outlen++;
+ pos++;
+ } else { /* formating thing */
+ int done=0;
+ char frmt[10];
+ int frmtpos=1;
+ char tempbuf[21];
+ frmt[0]='%';
+ pos++;
+
+ while (done==0)
+ {
+ switch(fmt[pos])
+ {
+ case 's': /* need to handle this */
+ cval = va_arg(ap, char *); /* get the next arg */
+ result = _sasl_add_string(error_buf, error_buf_len,
+ &outlen, cval);
+
+ if (result != SASL_OK) /* add the string */
+ goto done;
+
+ done=1;
+ break;
+
+ case '%': /* double % output the '%' character */
+ result = _buf_alloc(error_buf, error_buf_len, outlen+1);
+ if (result != SASL_OK)
+ goto done;
+ (*error_buf)[outlen]='%';
+ outlen++;
+ done=1;
+ break;
+
+ case 'm': /* insert the errno string */
+ result = _sasl_add_string(error_buf, error_buf_len,
+ &outlen,
+ strerror(va_arg(ap, int)));
+ if (result != SASL_OK)
+ goto done;
+ done=1;
+ break;
+
+ case 'z': /* insert the sasl error string */
+ result = _sasl_add_string(error_buf, error_buf_len, &outlen,
+ (char *)sasl_errstring(_sasl_seterror_usererr(
+ va_arg(ap, int)),NULL,NULL));
+ if (result != SASL_OK)
+ goto done;
+ done=1;
+ break;
+
+ case 'c':
+ frmt[frmtpos++]=fmt[pos];
+ frmt[frmtpos]=0;
+ tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
+ tempbuf[1]='\0';
+
+ /* now add the character */
+ result = _sasl_add_string(error_buf, error_buf_len,
+ &outlen, tempbuf);
+ if (result != SASL_OK)
+ goto done;
+ done=1;
+ break;
+
+ case 'd':
+ case 'i':
+ frmt[frmtpos++]=fmt[pos];
+ frmt[frmtpos]=0;
+ ival = va_arg(ap, int); /* get the next arg */
+
+ snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
+ /* now add the string */
+ result = _sasl_add_string(error_buf, error_buf_len,
+ &outlen, tempbuf);
+ if (result != SASL_OK)
+ goto done;
+ done=1;
+
+ break;
+ default:
+ frmt[frmtpos++]=fmt[pos]; /* add to the formating */
+ frmt[frmtpos]=0;
+ if (frmtpos>9)
+ done=1;
+ }
+ pos++;
+ if (pos>formatlen)
+ done=1;
+ }
+
+ }
+ }
+
+ (*error_buf)[outlen]='\0'; /* put 0 at end */
+
+#ifndef SASL_OSX_CFMGLUE
+ if(!(flags & SASL_NOLOG)) {
+ /* See if we have a logging callback... */
+ result = _sasl_getcallback(conn, SASL_CB_LOG, (sasl_callback_ft *)&log_cb, &log_ctx);
+ if (result == SASL_OK && ! log_cb)
+ result = SASL_FAIL;
+ if (result != SASL_OK)
+ goto done;
+
+ result = log_cb(log_ctx, SASL_LOG_FAIL, conn->error_buf);
+ }
+#endif /* SASL_OSX_CFMGLUE */
+done:
+ va_end(ap);
+}
diff --git a/contrib/libs/sasl/lib/staticopen.h b/contrib/libs/sasl/lib/staticopen.h
new file mode 100644
index 0000000000..d1983163d9
--- /dev/null
+++ b/contrib/libs/sasl/lib/staticopen.h
@@ -0,0 +1,188 @@
+/* staticopen.h
+ * Rob Siemborski
+ * Howard Chu
+ */
+/*
+ * Copyright (c) 1998-2016 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
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@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.
+ */
+
+typedef enum {
+ UNKNOWN = 0, SERVER = 1, CLIENT = 2, AUXPROP = 3, CANONUSER = 4
+} _sasl_plug_type;
+
+typedef struct {
+ _sasl_plug_type type;
+ char *name;
+ sasl_client_plug_init_t *plug;
+} _sasl_plug_rec;
+
+/* For static linking */
+#define SPECIFIC_CLIENT_PLUG_INIT_PROTO( x ) \
+sasl_client_plug_init_t x##_client_plug_init
+
+#define SPECIFIC_SERVER_PLUG_INIT_PROTO( x ) \
+sasl_server_plug_init_t x##_server_plug_init
+
+#define SPECIFIC_AUXPROP_PLUG_INIT_PROTO( x ) \
+sasl_auxprop_init_t x##_auxprop_plug_init
+
+#define SPECIFIC_CANONUSER_PLUG_INIT_PROTO( x ) \
+sasl_canonuser_init_t x##_canonuser_plug_init
+
+/* Static Compillation Foo */
+#define SPECIFIC_CLIENT_PLUG_INIT( x, n )\
+ { CLIENT, n, x##_client_plug_init }
+#define SPECIFIC_SERVER_PLUG_INIT( x, n )\
+ { SERVER, n, (sasl_client_plug_init_t *)x##_server_plug_init }
+#define SPECIFIC_AUXPROP_PLUG_INIT( x, n )\
+ { AUXPROP, n, (sasl_client_plug_init_t *)x##_auxprop_plug_init }
+#define SPECIFIC_CANONUSER_PLUG_INIT( x, n )\
+ { CANONUSER, n, (sasl_client_plug_init_t *)x##_canonuser_plug_init }
+
+#ifdef STATIC_ANONYMOUS
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( anonymous );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( anonymous );
+#endif
+#ifdef STATIC_CRAMMD5
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( crammd5 );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( crammd5 );
+#endif
+#ifdef STATIC_DIGESTMD5
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( digestmd5 );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( digestmd5 );
+#endif
+#ifdef STATIC_SCRAM
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( scram );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( scram );
+#endif
+#ifdef STATIC_GSSAPIV2
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( gssapiv2 );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( gssapiv2 );
+#endif
+#ifdef STATIC_KERBEROS4
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( kerberos4 );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( kerberos4 );
+#endif
+#ifdef STATIC_LOGIN
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( login );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( login );
+#endif
+#ifdef STATIC_NTLM
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( ntlm );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( ntlm );
+#endif
+#ifdef STATIC_OTP
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( otp );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( otp );
+#endif
+#ifdef STATIC_PLAIN
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( plain );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( plain );
+#endif
+#ifdef STATIC_SRP
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( srp );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( srp );
+#endif
+#ifdef STATIC_SASLDB
+extern SPECIFIC_AUXPROP_PLUG_INIT_PROTO( sasldb );
+#endif
+#ifdef STATIC_SQL
+extern SPECIFIC_AUXPROP_PLUG_INIT_PROTO( sql );
+#endif
+#ifdef STATIC_LDAPDB
+extern SPECIFIC_AUXPROP_PLUG_INIT_PROTO( ldapdb );
+#endif
+
+_sasl_plug_rec _sasl_static_plugins[] = {
+#ifdef STATIC_ANONYMOUS
+ SPECIFIC_SERVER_PLUG_INIT( anonymous, "ANONYMOUS" ),
+ SPECIFIC_CLIENT_PLUG_INIT( anonymous, "ANONYMOUS" ),
+#endif
+#ifdef STATIC_CRAMMD5
+ SPECIFIC_SERVER_PLUG_INIT( crammd5, "CRAM-MD5" ),
+ SPECIFIC_CLIENT_PLUG_INIT( crammd5, "CRAM-MD5" ),
+#endif
+#ifdef STATIC_DIGESTMD5
+ SPECIFIC_SERVER_PLUG_INIT( digestmd5, "DIGEST-MD5" ),
+ SPECIFIC_CLIENT_PLUG_INIT( digestmd5, "DIGEST-MD5" ),
+#endif
+#ifdef STATIC_GSSAPIV2
+ SPECIFIC_SERVER_PLUG_INIT( gssapiv2, "GSSAPI" ),
+ SPECIFIC_CLIENT_PLUG_INIT( gssapiv2, "GSSAPI" ),
+#endif
+#ifdef STATIC_KERBEROS4
+ SPECIFIC_SERVER_PLUG_INIT( kerberos4, "KERBEROS_V4" ),
+ SPECIFIC_CLIENT_PLUG_INIT( kerberos4, "KERBEROS_V4" ),
+#endif
+#ifdef STATIC_LOGIN
+ SPECIFIC_SERVER_PLUG_INIT( login, "LOGIN" ),
+ SPECIFIC_CLIENT_PLUG_INIT( login, "LOGIN" ),
+#endif
+#ifdef STATIC_NTLM
+ SPECIFIC_SERVER_PLUG_INIT( ntlm, "NTLM" ),
+ SPECIFIC_CLIENT_PLUG_INIT( ntlm, "NTLM" ),
+#endif
+#ifdef STATIC_OTP
+ SPECIFIC_SERVER_PLUG_INIT( otp, "OTP" ),
+ SPECIFIC_CLIENT_PLUG_INIT( otp, "OTP" ),
+#endif
+#ifdef STATIC_PLAIN
+ SPECIFIC_SERVER_PLUG_INIT( plain, "PLAIN" ),
+ SPECIFIC_CLIENT_PLUG_INIT( plain, "PLAIN" ),
+#endif
+#ifdef STATIC_SCRAM
+ SPECIFIC_SERVER_PLUG_INIT( scram, "SCRAM" ),
+ SPECIFIC_CLIENT_PLUG_INIT( scram, "SCRAM" ),
+#endif
+#ifdef STATIC_SRP
+ SPECIFIC_SERVER_PLUG_INIT( srp, "SRP" ),
+ SPECIFIC_CLIENT_PLUG_INIT( srp, "SRP" ),
+#endif
+#ifdef STATIC_SASLDB
+ SPECIFIC_AUXPROP_PLUG_INIT( sasldb, "SASLDB" ),
+#endif
+#ifdef STATIC_SQL
+ SPECIFIC_AUXPROP_PLUG_INIT( sql, "SQL" ),
+#endif
+#ifdef STATIC_LDAPDB
+ SPECIFIC_AUXPROP_PLUG_INIT( ldapdb, "LDAPDB" ),
+#endif
+ { UNKNOWN, NULL, NULL }
+};