/* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* auxprop.c - auxilliary property support * Rob Siemborski * $Id: auxprop.c,v 1.10 2003/03/19 18:25:27 rjs3 Exp $ */ /* * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any other legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@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 #include #include #include #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; #ifdef _SUN_SDK_ char *plugname; #endif /* _SUN_SDK_ */ } auxprop_plug_list_t; #ifndef _SUN_SDK_ static auxprop_plug_list_t *auxprop_head = NULL; #endif /* !_SUN_SDK_ */ 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; #ifdef _SUN_SDK_ ret = sasl_sun_ALLOC(total_size); #else ret = sasl_ALLOC(total_size); #endif /* _SUN_SDK_*/ 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; #ifdef _SUN_SDK_ ret = sasl_sun_REALLOC(pool, sizeof(struct proppool) + size); #else ret = sasl_REALLOC(pool, sizeof(struct proppool) + size); #endif /* _SUN_SDK_*/ 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; #ifdef _SUN_SDK_ new_ctx = sasl_sun_ALLOC(sizeof(struct propctx)); #else new_ctx = sasl_ALLOC(sizeof(struct propctx)); #endif /* _SUN_SDK_*/ 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; size_t total_size = 0, 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 += 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; iused_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; #ifdef _SUN_SDK_ sasl_sun_FREE(tmp); #else sasl_FREE(tmp); #endif /* _SUN_SDK_*/ } #ifdef _SUN_SDK_ sasl_sun_FREE(*ctx); #else sasl_FREE(*ctx); #endif /* _SUN_SDK_*/ *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 atleast on 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 = 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;iused_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; #ifdef _SUN_SDK_ if(!ctx) return; #endif /* _SUN_SDK_ */ /* 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(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; iused_values; i++) { new_values[i].name = ctx->values[i].name; } } while(ctx->mem_base) { tmp = ctx->mem_base; ctx->mem_base = tmp->next; #ifdef _SUN_SDK_ sasl_sun_FREE(tmp); #else sasl_FREE(tmp); #endif /* _SUN_SDK_ */ } /* 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 = strlen(sep); needed = seplen * (ctx->used_values - 1); for(val = ctx->values; val->name; val++) { needed += 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 += (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 += (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 */ #ifdef _SUN_SDK_ int sasl_auxprop_add_plugin(const char *plugname, sasl_auxprop_init_t *auxpropfunc) { return (_sasl_auxprop_add_plugin(_sasl_gbl_ctx(), plugname, auxpropfunc)); } int _sasl_auxprop_add_plugin(void *ctx, const char *plugname, sasl_auxprop_init_t *auxpropfunc) #else int sasl_auxprop_add_plugin(const char *plugname, sasl_auxprop_init_t *auxpropfunc) #endif /* _SUN_SDK_ */ { int result, out_version; auxprop_plug_list_t *new_item; sasl_auxprop_plug_t *plug; #ifdef _SUN_SDK_ _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx; auxprop_plug_list_t *auxprop_head; const sasl_utils_t *sasl_global_utils; auxprop_plug_list_t *l; auxprop_head = gctx->auxprop_head; sasl_global_utils = gctx->sasl_server_global_utils; /* Check to see if this plugin has already been registered */ for (l = auxprop_head; l != NULL; l = l->next) { if (strcmp(plugname, l->plugname) == 0) { return SASL_OK; } } #endif /* _SUN_SDK_ */ result = auxpropfunc(sasl_global_utils, SASL_AUXPROP_PLUG_VERSION, &out_version, &plug, plugname); if(result != SASL_OK) { #ifdef _SUN_SDK_ __sasl_log(gctx, gctx->server_global_callbacks.callbacks, SASL_LOG_ERR, "auxpropfunc error %i\n",result); #else _sasl_log(NULL, SASL_LOG_ERR, "auxpropfunc error %i\n",result); #endif /* _SUN_SDK_ */ return result; } /* We require that this function is implemented */ if(!plug->auxprop_lookup) return SASL_BADPROT; #ifdef _SUN_SDK_ /* Check plugin to make sure name is non-NULL */ if (plug->name == NULL) { __sasl_log(gctx, gctx->server_global_callbacks.callbacks, SASL_LOG_ERR, "invalid auxprop plugin %s", plugname); return SASL_BADPROT; } #endif /* _SUN_SDK_ */ new_item = sasl_ALLOC(sizeof(auxprop_plug_list_t)); if(!new_item) return SASL_NOMEM; #ifdef _SUN_SDK_ if(_sasl_strdup(plugname, &new_item->plugname, NULL) != SASL_OK) { sasl_FREE(new_item); return SASL_NOMEM; } #endif /* _SUN_SDK_ */ /* These will load from least-important to most important */ new_item->plug = plug; new_item->next = auxprop_head; #ifdef _SUN_SDK_ gctx->auxprop_head = new_item; #else auxprop_head = new_item; #endif /* _SUN_SDK_ */ return SASL_OK; } #ifdef _SUN_SDK_ void _sasl_auxprop_free(_sasl_global_context_t *gctx) #else void _sasl_auxprop_free() #endif /* _SUN_SDK_ */ { auxprop_plug_list_t *ptr, *ptr_next; #ifdef _SUN_SDK_ const sasl_utils_t *sasl_global_utils = gctx->sasl_server_global_utils; for(ptr = (auxprop_plug_list_t *)gctx->auxprop_head; ptr; ptr = ptr_next) { #else for(ptr = auxprop_head; ptr; ptr = ptr_next) { #endif /* _SUN_SDK_ */ ptr_next = ptr->next; if(ptr->plug->auxprop_free) ptr->plug->auxprop_free(ptr->plug->glob_context, sasl_global_utils); #ifdef _SUN_SDK_ sasl_FREE(ptr->plugname); #endif /* _SUN_SDK_ */ sasl_FREE(ptr); } #ifdef _SUN_SDK_ gctx->auxprop_head = NULL; #else auxprop_head = NULL; #endif /* _SUN_SDK_ */ } /* Do the callbacks for auxprop lookups */ void _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; #ifdef _SUN_SDK_ _sasl_global_context_t *gctx = sparams->utils->conn->gctx; auxprop_plug_list_t *auxprop_head = gctx->auxprop_head; #endif /* _SUN_SDK_ */ if(_sasl_getcallback(sparams->utils->conn, SASL_CB_GETOPT, &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 */ for(ptr = auxprop_head; ptr; ptr = ptr->next) { found=1; ptr->plug->auxprop_lookup(ptr->plug->glob_context, sparams, flags, user, ulen); } } else { char *pluginlist = NULL, *freeptr = NULL, *thisplugin = NULL; if(_sasl_strdup(plist, &pluginlist, NULL) != SASL_OK) return; 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; ptr->plug->auxprop_lookup(ptr->plug->glob_context, sparams, flags, user, ulen); } 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]"); }