1 /* auxprop.c - auxilliary property support
3 * $Id: auxprop.c,v 1.16 2006/03/14 14:23:55 mel Exp $
6 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
20 * 3. The name "Carnegie Mellon University" must not be used to
21 * endorse or promote products derived from this software without
22 * prior written permission. For permission or any other legal
23 * details, please contact
24 * Office of Technology Transfer
25 * Carnegie Mellon University
27 * Pittsburgh, PA 15213-3890
28 * (412) 268-4387, fax: (412) 268-7395
29 * tech-transfer@andrew.cmu.edu
31 * 4. Redistributions of any form whatsoever must retain the following
33 * "This product includes software developed by Computing Services
34 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
36 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
37 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
38 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
39 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
41 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
42 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
54 struct proppool *next;
56 size_t size; /* Size of Block */
57 size_t unused; /* Space unused in this pool between end
58 * of char** area and beginning of char* area */
60 char data[1]; /* Variable Sized */
64 struct propval *values;
65 struct propval *prev_val; /* Previous value used by set/setvalues */
67 unsigned used_values, allocated_values;
69 char *data_end; /* Bottom of string area in current pool */
70 char **list_end; /* Top of list area in current pool */
72 struct proppool *mem_base;
73 struct proppool *mem_cur;
76 typedef struct auxprop_plug_list
78 struct auxprop_plug_list *next;
79 const sasl_auxprop_plug_t *plug;
80 } auxprop_plug_list_t;
82 static auxprop_plug_list_t *auxprop_head = NULL;
84 static struct proppool *alloc_proppool(size_t size)
87 /* minus 1 for the one that is already a part of the array
89 size_t total_size = sizeof(struct proppool) + size - 1;
90 ret = sasl_ALLOC(total_size);
93 memset(ret, 0, total_size);
95 ret->size = ret->unused = size;
100 /* Resize a proppool. Invalidates the unused value for this pool */
101 static struct proppool *resize_proppool(struct proppool *pool, size_t size)
103 struct proppool *ret;
105 if(pool->size >= size) return pool;
106 ret = sasl_REALLOC(pool, sizeof(struct proppool) + size);
107 if(!ret) return NULL;
114 static int prop_init(struct propctx *ctx, unsigned estimate)
116 const unsigned VALUES_SIZE = PROP_DEFAULT * sizeof(struct propval);
118 ctx->mem_base = alloc_proppool(VALUES_SIZE + estimate);
119 if(!ctx->mem_base) return SASL_NOMEM;
121 ctx->mem_cur = ctx->mem_base;
123 ctx->values = (struct propval *)ctx->mem_base->data;
124 ctx->mem_base->unused = ctx->mem_base->size - VALUES_SIZE;
125 ctx->allocated_values = PROP_DEFAULT;
126 ctx->used_values = 0;
128 ctx->data_end = ctx->mem_base->data + ctx->mem_base->size;
129 ctx->list_end = (char **)(ctx->mem_base->data + VALUES_SIZE);
131 ctx->prev_val = NULL;
136 /* create a property context
137 * estimate -- an estimate of the storage needed for requests & responses
138 * 0 will use module default
139 * returns NULL on error
141 struct propctx *prop_new(unsigned estimate)
143 struct propctx *new_ctx;
145 if(!estimate) estimate = PROP_DEFAULT * 255;
147 new_ctx = sasl_ALLOC(sizeof(struct propctx));
148 if(!new_ctx) return NULL;
150 if(prop_init(new_ctx, estimate) != SASL_OK) {
151 prop_dispose(&new_ctx);
157 /* create new propctx which duplicates the contents of an existing propctx
158 * returns -1 on error
160 int prop_dup(struct propctx *src_ctx, struct propctx **dst_ctx)
162 struct proppool *pool;
163 struct propctx *retval = NULL;
166 unsigned total_size = 0;
169 if(!src_ctx || !dst_ctx) return SASL_BADPARAM;
171 /* What is the total allocated size of src_ctx? */
172 pool = src_ctx->mem_base;
174 total_size += (unsigned) pool->size;
178 /* allocate the new context */
179 retval = prop_new(total_size);
180 if(!retval) return SASL_NOMEM;
182 retval->used_values = src_ctx->used_values;
183 retval->allocated_values = src_ctx->used_values + 1;
185 values_size = (retval->allocated_values * sizeof(struct propval));
187 retval->mem_base->unused = retval->mem_base->size - values_size;
189 retval->list_end = (char **)(retval->mem_base->data + values_size);
190 /* data_end should still be OK */
192 /* Now dup the values */
193 for(i=0; i<src_ctx->used_values; i++) {
194 retval->values[i].name = src_ctx->values[i].name;
195 result = prop_setvals(retval, retval->values[i].name,
196 src_ctx->values[i].values);
197 if(result != SASL_OK)
201 retval->prev_val = src_ctx->prev_val;
207 if(retval) prop_dispose(&retval);
212 * dispose of property context
213 * ctx -- is disposed and set to NULL; noop if ctx or *ctx is NULL
215 void prop_dispose(struct propctx **ctx)
217 struct proppool *tmp;
219 if(!ctx || !*ctx) return;
221 while((*ctx)->mem_base) {
222 tmp = (*ctx)->mem_base;
223 (*ctx)->mem_base = tmp->next;
233 /* Add property names to request
234 * ctx -- context from prop_new()
235 * names -- list of property names; must persist until context freed
236 * or requests cleared
238 * NOTE: may clear values from context as side-effect
239 * returns -1 on error
241 int prop_request(struct propctx *ctx, const char **names)
243 unsigned i, new_values, total_values;
245 if(!ctx || !names) return SASL_BADPARAM;
247 /* Count how many we need to add */
248 for(new_values=0; names[new_values]; new_values++);
250 /* Do we need to add ANY? */
251 if(!new_values) return SASL_OK;
253 /* We always want at least one extra to mark the end of the array */
254 total_values = new_values + ctx->used_values + 1;
256 /* Do we need to increase the size of our propval table? */
257 if(total_values > ctx->allocated_values) {
258 unsigned max_in_pool;
260 /* Do we need a larger base pool? */
261 max_in_pool = (unsigned) (ctx->mem_base->size / sizeof(struct propval));
263 if(total_values <= max_in_pool) {
264 /* Don't increase the size of the base pool, just use what
266 ctx->allocated_values = total_values;
267 ctx->mem_base->unused =
268 ctx->mem_base->size - (sizeof(struct propval)
269 * ctx->allocated_values);
271 /* We need to allocate more! */
272 unsigned new_alloc_length;
275 new_alloc_length = 2 * ctx->allocated_values;
276 while(total_values > new_alloc_length) {
277 new_alloc_length *= 2;
280 new_size = new_alloc_length * sizeof(struct propval);
281 ctx->mem_base = resize_proppool(ctx->mem_base, new_size);
285 ctx->allocated_values = ctx->used_values = 0;
289 /* It worked! Update the structure! */
290 ctx->values = (struct propval *)ctx->mem_base->data;
291 ctx->allocated_values = new_alloc_length;
292 ctx->mem_base->unused = ctx->mem_base->size
293 - sizeof(struct propval) * ctx->allocated_values;
296 /* Clear out new propvals */
297 memset(&(ctx->values[ctx->used_values]), 0,
298 sizeof(struct propval) * (ctx->allocated_values - ctx->used_values));
300 /* Finish updating the context -- we've extended the list! */
301 /* ctx->list_end = (char **)(ctx->values + ctx->allocated_values); */
303 ctx->list_end = (char **)(ctx->values + total_values);
306 /* Now do the copy, or referencing rather */
307 for(i=0;i<new_values;i++) {
313 for(j=0;j<ctx->used_values;j++) {
314 if(!strcmp(ctx->values[j].name, names[i])) {
320 /* We already have it... skip! */
323 ctx->values[ctx->used_values++].name = names[i];
331 /* return array of struct propval from the context
332 * return value persists until next call to
333 * prop_request, prop_clear or prop_dispose on context
335 const struct propval *prop_get(struct propctx *ctx)
337 if(!ctx) return NULL;
342 /* Fill in an array of struct propval based on a list of property names
343 * return value persists until next call to
344 * prop_request, prop_clear or prop_dispose on context
345 * returns -1 on error (no properties ever requested, ctx NULL, etc)
346 * returns number of matching properties which were found (values != NULL)
347 * if a name requested here was never requested by a prop_request, then
348 * the name field of the associated vals entry will be set to NULL
350 int prop_getnames(struct propctx *ctx, const char **names,
351 struct propval *vals)
355 struct propval *cur = vals;
356 const char **curname;
358 if(!ctx || !names || !vals) return SASL_BADPARAM;
360 for(curname = names; *curname; curname++) {
362 for(val = ctx->values; val->name; val++) {
363 if(!strcmp(*curname,val->name)) {
365 memcpy(cur, val, sizeof(struct propval));
370 /* If we are here, we didn't find it */
371 memset(cur, 0, sizeof(struct propval));
381 /* clear values and optionally requests from property context
382 * ctx -- property context
383 * requests -- 0 = don't clear requests, 1 = clear requests
385 void prop_clear(struct propctx *ctx, int requests)
387 struct proppool *new_pool, *tmp;
390 /* We're going to need a new proppool once we reset things */
391 new_pool = alloc_proppool(ctx->mem_base->size +
392 (ctx->used_values+1) * sizeof(struct propval));
395 /* We're wiping the whole shebang */
396 ctx->used_values = 0;
398 /* Need to keep around old requets */
399 struct propval *new_values = (struct propval *)new_pool->data;
400 for(i=0; i<ctx->used_values; i++) {
401 new_values[i].name = ctx->values[i].name;
405 while(ctx->mem_base) {
407 ctx->mem_base = tmp->next;
411 /* Update allocation-related metadata */
412 ctx->allocated_values = ctx->used_values+1;
414 new_pool->size - (ctx->allocated_values * sizeof(struct propval));
416 /* Setup pointers for the values array */
417 ctx->values = (struct propval *)new_pool->data;
418 ctx->prev_val = NULL;
420 /* Setup the pools */
421 ctx->mem_base = ctx->mem_cur = new_pool;
423 /* Reset list_end and data_end for the new memory pool */
425 (char **)((char *)ctx->mem_base->data + ctx->allocated_values * sizeof(struct propval));
426 ctx->data_end = (char *)ctx->mem_base->data + ctx->mem_base->size;
432 * erase the value of a property
434 void prop_erase(struct propctx *ctx, const char *name)
439 if(!ctx || !name) return;
441 for(val = ctx->values; val->name; val++) {
442 if(!strcmp(name,val->name)) {
443 if(!val->values) break;
446 * Yes, this is casting away the const, but
447 * we should be okay because the only place this
448 * memory should be is in the proppool's
450 for(i=0;val->values[i];i++) {
451 memset((void *)(val->values[i]),0,strlen(val->values[i]));
452 val->values[i] = NULL;
465 /****fetcher interfaces****/
467 /* format the requested property names into a string
468 * ctx -- context from prop_new()/prop_request()
469 * sep -- separator between property names (unused if none requested)
470 * seplen -- length of separator, if < 0 then strlen(sep) will be used
471 * outbuf -- output buffer
472 * outmax -- maximum length of output buffer including NUL terminator
473 * outlen -- set to length of output string excluding NUL terminator
474 * returns 0 on success and amount of additional space needed on failure
476 int prop_format(struct propctx *ctx, const char *sep, int seplen,
477 char *outbuf, unsigned outmax, unsigned *outlen)
479 unsigned needed, flag = 0;
482 if (!ctx || !outbuf) return SASL_BADPARAM;
484 if (!sep) seplen = 0;
485 if (seplen < 0) seplen = (int) strlen(sep);
486 /* If seplen is negative now we have overflow.
487 But if you have a string longer than 2Gb, you are an idiot anyway */
488 if (seplen < 0) return SASL_BADPARAM;
490 needed = seplen * (ctx->used_values - 1);
491 for(val = ctx->values; val->name; val++) {
492 needed += (unsigned) strlen(val->name);
495 if(!outmax) return (needed + 1); /* Because of unsigned funkiness */
496 if(needed > (outmax - 1)) return (needed - (outmax - 1));
499 if(outlen) *outlen = needed;
501 if(needed == 0) return SASL_OK;
503 for(val = ctx->values; val->name; val++) {
505 strncat(outbuf, sep, seplen);
509 strcat(outbuf, val->name);
515 /* add a property value to the context
516 * ctx -- context from prop_new()/prop_request()
517 * name -- name of property to which value will be added
518 * if NULL, add to the same name as previous prop_set/setvals call
519 * value -- a value for the property; will be copied into context
520 * if NULL, remove existing values
521 * vallen -- length of value, if <= 0 then strlen(value) will be used
523 int prop_set(struct propctx *ctx, const char *name,
524 const char *value, int vallen)
528 if(!ctx) return SASL_BADPARAM;
529 if(!name && !ctx->prev_val) return SASL_BADPARAM;
534 ctx->prev_val = NULL;
536 for(val = ctx->values; val->name; val++) {
537 if(!strcmp(name,val->name)){
543 /* Couldn't find it! */
544 if(!ctx->prev_val) return SASL_BADPARAM;
549 if(name) /* New Entry */ {
550 unsigned nvalues = 1; /* 1 for NULL entry */
551 const char **old_values = NULL;
558 /* If we would be adding a null value, then we are done */
562 old_values = cur->values;
563 tmp = (char **)cur->values;
572 nvalues++; /* for the new value */
575 size = nvalues * sizeof(char*);
577 if(size > ctx->mem_cur->unused) {
580 for(needed = ctx->mem_cur->size * 2; needed < size; needed *= 2);
582 /* Allocate a new proppool */
583 ctx->mem_cur->next = alloc_proppool(needed);
584 if(!ctx->mem_cur->next) return SASL_NOMEM;
586 ctx->mem_cur = ctx->mem_cur->next;
588 ctx->list_end = (char **)ctx->mem_cur->data;
589 ctx->data_end = ctx->mem_cur->data + needed;
592 /* Grab the memory */
593 ctx->mem_cur->unused -= size;
594 cur->values = (const char **)ctx->list_end;
595 cur->values[nvalues - 1] = NULL;
597 /* Finish updating the context */
598 ctx->list_end = (char **)(cur->values + nvalues);
600 /* If we don't have an actual value to fill in, we are done */
604 tmp2 = (char **)cur->values;
606 tmp = (char **)old_values;
614 /* Now allocate the last entry */
616 size = (size_t)(strlen(value) + 1);
618 size = (size_t)(vallen + 1);
620 if(size > ctx->mem_cur->unused) {
623 needed = ctx->mem_cur->size * 2;
625 while(needed < size) {
629 /* Allocate a new proppool */
630 ctx->mem_cur->next = alloc_proppool(needed);
631 if(!ctx->mem_cur->next) return SASL_NOMEM;
633 ctx->mem_cur = ctx->mem_cur->next;
634 ctx->list_end = (char **)ctx->mem_cur->data;
635 ctx->data_end = ctx->mem_cur->data + needed;
638 /* Update the data_end pointer */
639 ctx->data_end -= size;
640 ctx->mem_cur->unused -= size;
642 /* Copy and setup the new value! */
643 memcpy(ctx->data_end, value, size-1);
644 ctx->data_end[size - 1] = '\0';
645 cur->values[nvalues - 2] = ctx->data_end;
648 cur->valsize += ((unsigned) size - 1);
649 } else /* Appending an entry */ {
653 /* If we are setting it to be NULL, we are done */
654 if(!value) return SASL_OK;
656 size = sizeof(char*);
658 /* Is it in the current pool, and will it fit in the unused space? */
659 if(size > ctx->mem_cur->unused &&
660 (void *)cur->values > (void *)(ctx->mem_cur->data) &&
661 (void *)cur->values < (void *)(ctx->mem_cur->data + ctx->mem_cur->size)) {
662 /* recursively call the not-fast way */
663 return prop_set(ctx, cur->name, value, vallen);
666 /* Note the invariant: the previous value list must be
667 at the top of the CURRENT pool at this point */
669 /* Grab the memory */
670 ctx->mem_cur->unused -= size;
673 *(ctx->list_end - 1) = NULL;
674 tmp = (ctx->list_end - 2);
676 /* Now allocate the last entry */
678 size = strlen(value) + 1;
682 if(size > ctx->mem_cur->unused) {
685 needed = ctx->mem_cur->size * 2;
687 while(needed < size) {
691 /* Allocate a new proppool */
692 ctx->mem_cur->next = alloc_proppool(needed);
693 if(!ctx->mem_cur->next) return SASL_NOMEM;
695 ctx->mem_cur = ctx->mem_cur->next;
696 ctx->list_end = (char **)ctx->mem_cur->data;
697 ctx->data_end = ctx->mem_cur->data + needed;
700 /* Update the data_end pointer */
701 ctx->data_end -= size;
702 ctx->mem_cur->unused -= size;
704 /* Copy and setup the new value! */
705 memcpy(ctx->data_end, value, size-1);
706 ctx->data_end[size - 1] = '\0';
707 *tmp = ctx->data_end;
710 cur->valsize += ((unsigned) size - 1);
717 /* set the values for a property
718 * ctx -- context from prop_new()/prop_request()
719 * name -- name of property to which value will be added
720 * if NULL, add to the same name as previous prop_set/setvals call
721 * values -- array of values, ending in NULL. Each value is a NUL terminated
724 int prop_setvals(struct propctx *ctx, const char *name,
727 const char **val = values;
728 int result = SASL_OK;
730 if(!ctx) return SASL_BADPARAM;
732 /* If they want us to add no values, we can do that */
733 if(!values) return SASL_OK;
735 /* Basically, use prop_set to do all our dirty work for us */
737 result = prop_set(ctx, name, *val, 0);
742 if(result != SASL_OK) return result;
743 result = prop_set(ctx, NULL, *val,0);
749 /* Request a set of auxiliary properties
750 * conn connection context
751 * propnames list of auxiliary property names to request ending with
754 * Subsequent calls will add items to the request list. Call with NULL
755 * to clear the request list.
759 * SASL_BADPARAM -- bad count/conn parameter
760 * SASL_NOMEM -- out of memory
762 int sasl_auxprop_request(sasl_conn_t *conn, const char **propnames)
765 sasl_server_conn_t *sconn;
767 if(!conn) return SASL_BADPARAM;
768 if(conn->type != SASL_CONN_SERVER)
771 sconn = (sasl_server_conn_t *)conn;
774 prop_clear(sconn->sparams->propctx,1);
778 result = prop_request(sconn->sparams->propctx, propnames);
779 RETURN(conn, result);
783 /* Returns current auxiliary property context.
784 * Use functions in prop.h to access content
786 * if authentication hasn't completed, property values may be empty/NULL
788 * properties not recognized by active plug-ins will be left empty/NULL
790 * returns NULL if conn is invalid.
792 struct propctx *sasl_auxprop_getctx(sasl_conn_t *conn)
794 sasl_server_conn_t *sconn;
796 if(!conn || conn->type != SASL_CONN_SERVER) return NULL;
798 sconn = (sasl_server_conn_t *)conn;
800 return sconn->sparams->propctx;
803 /* add an auxiliary property plugin */
804 int sasl_auxprop_add_plugin(const char *plugname,
805 sasl_auxprop_init_t *auxpropfunc)
807 int result, out_version;
808 auxprop_plug_list_t *new_item;
809 sasl_auxprop_plug_t *plug;
811 result = auxpropfunc(sasl_global_utils, SASL_AUXPROP_PLUG_VERSION,
812 &out_version, &plug, plugname);
814 if(result != SASL_OK) {
815 _sasl_log(NULL, SASL_LOG_ERR, "auxpropfunc error %s\n",
816 sasl_errstring(result, NULL, NULL));
820 /* We require that this function is implemented */
821 if(!plug->auxprop_lookup) return SASL_BADPROT;
823 new_item = sasl_ALLOC(sizeof(auxprop_plug_list_t));
824 if(!new_item) return SASL_NOMEM;
826 /* These will load from least-important to most important */
827 new_item->plug = plug;
828 new_item->next = auxprop_head;
829 auxprop_head = new_item;
834 void _sasl_auxprop_free()
836 auxprop_plug_list_t *ptr, *ptr_next;
838 for(ptr = auxprop_head; ptr; ptr = ptr_next) {
839 ptr_next = ptr->next;
840 if(ptr->plug->auxprop_free)
841 ptr->plug->auxprop_free(ptr->plug->glob_context,
850 /* Do the callbacks for auxprop lookups */
851 void _sasl_auxprop_lookup(sasl_server_params_t *sparams,
853 const char *user, unsigned ulen)
855 sasl_getopt_t *getopt;
858 const char *plist = NULL;
859 auxprop_plug_list_t *ptr;
861 if(_sasl_getcallback(sparams->utils->conn,
862 SASL_CB_GETOPT, &getopt, &context) == SASL_OK) {
863 ret = getopt(context, NULL, "auxprop_plugin", &plist, NULL);
864 if(ret != SASL_OK) plist = NULL;
868 /* Do lookup in all plugins */
869 for(ptr = auxprop_head; ptr; ptr = ptr->next) {
871 ptr->plug->auxprop_lookup(ptr->plug->glob_context,
872 sparams, flags, user, ulen);
875 char *pluginlist = NULL, *freeptr = NULL, *thisplugin = NULL;
877 if(_sasl_strdup(plist, &pluginlist, NULL) != SASL_OK) return;
878 thisplugin = freeptr = pluginlist;
880 /* Do lookup in all *specified* plugins, in order */
885 while(*thisplugin && isspace((int)*thisplugin)) thisplugin++;
886 if(!(*thisplugin)) break;
888 for(p = thisplugin;*p != '\0' && !isspace((int)*p); p++);
889 if(*p == '\0') last = 1;
892 for(ptr = auxprop_head; ptr; ptr = ptr->next) {
893 /* Skip non-matching plugins */
895 || strcasecmp(ptr->plug->name, thisplugin))
899 ptr->plug->auxprop_lookup(ptr->plug->glob_context,
900 sparams, flags, user, ulen);
912 _sasl_log(sparams->utils->conn, SASL_LOG_DEBUG,
913 "could not find auxprop plugin, was searching for '%s'",
914 plist ? plist : "[all]");
917 /* Do the callbacks for auxprop stores */
918 int sasl_auxprop_store(sasl_conn_t *conn,
919 struct propctx *ctx, const char *user)
921 sasl_getopt_t *getopt;
924 const char *plist = NULL;
925 auxprop_plug_list_t *ptr;
926 sasl_server_params_t *sparams = NULL;
927 unsigned userlen = 0;
931 return SASL_BADPARAM;
933 sparams = ((sasl_server_conn_t *) conn)->sparams;
934 userlen = (unsigned) strlen(user);
937 /* Pickup getopt callback from the connection, if conn is not NULL */
938 if(_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK) {
939 ret = getopt(context, NULL, "auxprop_plugin", &plist, NULL);
940 if(ret != SASL_OK) plist = NULL;
945 /* Do store in all plugins */
946 for(ptr = auxprop_head; ptr && ret == SASL_OK; ptr = ptr->next) {
948 if (ptr->plug->auxprop_store)
949 ret = ptr->plug->auxprop_store(ptr->plug->glob_context,
950 sparams, ctx, user, userlen);
953 char *pluginlist = NULL, *freeptr = NULL, *thisplugin = NULL;
955 if(_sasl_strdup(plist, &pluginlist, NULL) != SASL_OK) return SASL_FAIL;
956 thisplugin = freeptr = pluginlist;
958 /* Do store in all *specified* plugins, in order */
963 while(*thisplugin && isspace((int)*thisplugin)) thisplugin++;
964 if(!(*thisplugin)) break;
966 for(p = thisplugin;*p != '\0' && !isspace((int)*p); p++);
967 if(*p == '\0') last = 1;
970 for(ptr = auxprop_head; ptr && ret == SASL_OK; ptr = ptr->next) {
971 /* Skip non-matching plugins */
973 || strcasecmp(ptr->plug->name, thisplugin)))
977 if (ptr->plug->auxprop_store)
978 ret = ptr->plug->auxprop_store(ptr->plug->glob_context,
979 sparams, ctx, user, userlen);
991 _sasl_log(NULL, SASL_LOG_ERR,
992 "could not find auxprop plugin, was searching for %s",
993 plist ? plist : "[all]");
1000 /* It would be nice if we can show other information like Author, Company, Year, plugin version */
1002 _sasl_print_mechanism (
1003 sasl_auxprop_plug_t *m,
1004 sasl_info_callback_stage_t stage,
1010 if (stage == SASL_INFO_LIST_START) {
1011 printf ("List of auxprop plugins follows\n");
1013 } else if (stage == SASL_INFO_LIST_END) {
1017 /* Process the mechanism */
1018 printf ("Plugin \"%s\" ", m->name);
1021 switch (m->condition) {
1023 printf ("[loaded]");
1027 printf ("[delayed]");
1031 printf ("[no users]");
1035 printf ("[unknown]");
1040 printf (", \tAPI version: %d\n", /* m->version */ SASL_AUXPROP_PLUG_VERSION);
1042 /* TODO - Update for auxprop_export, etc. */
1043 printf ("\tsupports store: %s\n",
1044 (m->auxprop_store != NULL) ? "yes" : "no"
1047 /* No features defined yet */
1049 printf ("\n\tfeatures:");
1055 /* Dump information about available auxprop plugins (separate functions are
1056 used for canon and server authentication plugins) */
1057 int auxprop_plugin_info (
1058 const char *c_mech_list, /* space separated mechanism list or NULL for ALL */
1059 auxprop_info_callback_t *info_cb,
1063 auxprop_plug_list_t *m;
1064 sasl_auxprop_plug_t plug_data;
1066 char *mech_list = NULL;
1069 if (info_cb == NULL) {
1070 info_cb = _sasl_print_mechanism;
1073 if (auxprop_head != NULL) {
1074 info_cb (NULL, SASL_INFO_LIST_START, info_cb_rock);
1076 if (c_mech_list == NULL) {
1077 m = auxprop_head; /* m point to beginning of the list */
1080 /* TODO: Need to be careful when dealing with auxprop_export, etc. */
1081 memcpy (&plug_data, m->plug, sizeof(plug_data));
1083 info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
1088 mech_list = strdup(c_mech_list);
1090 cur_mech = mech_list;
1092 while (cur_mech != NULL) {
1093 p = strchr (cur_mech, ' ');
1099 m = auxprop_head; /* m point to beginning of the list */
1102 if (strcasecmp (cur_mech, m->plug->name) == 0) {
1103 memcpy (&plug_data, m->plug, sizeof(plug_data));
1105 info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
1117 info_cb (NULL, SASL_INFO_LIST_END, info_cb_rock);
1122 return (SASL_NOTINIT);