12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202 |
- /* 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);
- }
|