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.
53 struct proppool *next;
55 size_t size; /* Size of Block */
56 size_t unused; /* Space unused in this pool between end
57 * of char** area and beginning of char* area */
59 char data[1]; /* Variable Sized */
63 struct propval *values;
64 struct propval *prev_val; /* Previous value used by set/setvalues */
66 unsigned used_values, allocated_values;
68 char *data_end; /* Bottom of string area in current pool */
69 char **list_end; /* Top of list area in current pool */
71 struct proppool *mem_base;
72 struct proppool *mem_cur;
75 typedef struct auxprop_plug_list
77 struct auxprop_plug_list *next;
78 const sasl_auxprop_plug_t *plug;
79 } auxprop_plug_list_t;
81 static auxprop_plug_list_t *auxprop_head = NULL;
83 static struct proppool *alloc_proppool(size_t size)
86 /* minus 1 for the one that is already a part of the array
88 size_t total_size = sizeof(struct proppool) + size - 1;
89 ret = sasl_ALLOC(total_size);
92 memset(ret, 0, total_size);
94 ret->size = ret->unused = size;
99 /* Resize a proppool. Invalidates the unused value for this pool */
100 static struct proppool *resize_proppool(struct proppool *pool, size_t size)
102 struct proppool *ret;
104 if(pool->size >= size) return pool;
105 ret = sasl_REALLOC(pool, sizeof(struct proppool) + size);
106 if(!ret) return NULL;
113 static int prop_init(struct propctx *ctx, unsigned estimate)
115 const unsigned VALUES_SIZE = PROP_DEFAULT * sizeof(struct propval);
117 ctx->mem_base = alloc_proppool(VALUES_SIZE + estimate);
118 if(!ctx->mem_base) return SASL_NOMEM;
120 ctx->mem_cur = ctx->mem_base;
122 ctx->values = (struct propval *)ctx->mem_base->data;
123 ctx->mem_base->unused = ctx->mem_base->size - VALUES_SIZE;
124 ctx->allocated_values = PROP_DEFAULT;
125 ctx->used_values = 0;
127 ctx->data_end = ctx->mem_base->data + ctx->mem_base->size;
128 ctx->list_end = (char **)(ctx->mem_base->data + VALUES_SIZE);
130 ctx->prev_val = NULL;
135 /* create a property context
136 * estimate -- an estimate of the storage needed for requests & responses
137 * 0 will use module default
138 * returns NULL on error
140 struct propctx *prop_new(unsigned estimate)
142 struct propctx *new_ctx;
144 if(!estimate) estimate = PROP_DEFAULT * 255;
146 new_ctx = sasl_ALLOC(sizeof(struct propctx));
147 if(!new_ctx) return NULL;
149 if(prop_init(new_ctx, estimate) != SASL_OK) {
150 prop_dispose(&new_ctx);
156 /* create new propctx which duplicates the contents of an existing propctx
157 * returns -1 on error
159 int prop_dup(struct propctx *src_ctx, struct propctx **dst_ctx)
161 struct proppool *pool;
162 struct propctx *retval = NULL;
165 unsigned total_size = 0;
168 if(!src_ctx || !dst_ctx) return SASL_BADPARAM;
170 /* What is the total allocated size of src_ctx? */
171 pool = src_ctx->mem_base;
173 total_size += (unsigned) pool->size;
177 /* allocate the new context */
178 retval = prop_new(total_size);
179 if(!retval) return SASL_NOMEM;
181 retval->used_values = src_ctx->used_values;
182 retval->allocated_values = src_ctx->used_values + 1;
184 values_size = (retval->allocated_values * sizeof(struct propval));
186 retval->mem_base->unused = retval->mem_base->size - values_size;
188 retval->list_end = (char **)(retval->mem_base->data + values_size);
189 /* data_end should still be OK */
191 /* Now dup the values */
192 for(i=0; i<src_ctx->used_values; i++) {
193 retval->values[i].name = src_ctx->values[i].name;
194 result = prop_setvals(retval, retval->values[i].name,
195 src_ctx->values[i].values);
196 if(result != SASL_OK)
200 retval->prev_val = src_ctx->prev_val;
206 if(retval) prop_dispose(&retval);
211 * dispose of property context
212 * ctx -- is disposed and set to NULL; noop if ctx or *ctx is NULL
214 void prop_dispose(struct propctx **ctx)
216 struct proppool *tmp;
218 if(!ctx || !*ctx) return;
220 while((*ctx)->mem_base) {
221 tmp = (*ctx)->mem_base;
222 (*ctx)->mem_base = tmp->next;
232 /* Add property names to request
233 * ctx -- context from prop_new()
234 * names -- list of property names; must persist until context freed
235 * or requests cleared
237 * NOTE: may clear values from context as side-effect
238 * returns -1 on error
240 int prop_request(struct propctx *ctx, const char **names)
242 unsigned i, new_values, total_values;
244 if(!ctx || !names) return SASL_BADPARAM;
246 /* Count how many we need to add */
247 for(new_values=0; names[new_values]; new_values++);
249 /* Do we need to add ANY? */
250 if(!new_values) return SASL_OK;
252 /* We always want at least one extra to mark the end of the array */
253 total_values = new_values + ctx->used_values + 1;
255 /* Do we need to increase the size of our propval table? */
256 if(total_values > ctx->allocated_values) {
257 unsigned max_in_pool;
259 /* Do we need a larger base pool? */
260 max_in_pool = (unsigned) (ctx->mem_base->size / sizeof(struct propval));
262 if(total_values <= max_in_pool) {
263 /* Don't increase the size of the base pool, just use what
265 ctx->allocated_values = total_values;
266 ctx->mem_base->unused =
267 ctx->mem_base->size - (sizeof(struct propval)
268 * ctx->allocated_values);
270 /* We need to allocate more! */
271 unsigned new_alloc_length;
274 new_alloc_length = 2 * ctx->allocated_values;
275 while(total_values > new_alloc_length) {
276 new_alloc_length *= 2;
279 new_size = new_alloc_length * sizeof(struct propval);
280 ctx->mem_base = resize_proppool(ctx->mem_base, new_size);
284 ctx->allocated_values = ctx->used_values = 0;
288 /* It worked! Update the structure! */
289 ctx->values = (struct propval *)ctx->mem_base->data;
290 ctx->allocated_values = new_alloc_length;
291 ctx->mem_base->unused = ctx->mem_base->size
292 - sizeof(struct propval) * ctx->allocated_values;
295 /* Clear out new propvals */
296 memset(&(ctx->values[ctx->used_values]), 0,
297 sizeof(struct propval) * (ctx->allocated_values - ctx->used_values));
299 /* Finish updating the context -- we've extended the list! */
300 /* ctx->list_end = (char **)(ctx->values + ctx->allocated_values); */
302 ctx->list_end = (char **)(ctx->values + total_values);
305 /* Now do the copy, or referencing rather */
306 for(i=0;i<new_values;i++) {
312 for(j=0;j<ctx->used_values;j++) {
313 if(!strcmp(ctx->values[j].name, names[i])) {
319 /* We already have it... skip! */
322 ctx->values[ctx->used_values++].name = names[i];
330 /* return array of struct propval from the context
331 * return value persists until next call to
332 * prop_request, prop_clear or prop_dispose on context
334 const struct propval *prop_get(struct propctx *ctx)
336 if(!ctx) return NULL;
341 /* Fill in an array of struct propval based on a list of property names
342 * return value persists until next call to
343 * prop_request, prop_clear or prop_dispose on context
344 * returns -1 on error (no properties ever requested, ctx NULL, etc)
345 * returns number of matching properties which were found (values != NULL)
346 * if a name requested here was never requested by a prop_request, then
347 * the name field of the associated vals entry will be set to NULL
349 int prop_getnames(struct propctx *ctx, const char **names,
350 struct propval *vals)
354 struct propval *cur = vals;
355 const char **curname;
357 if(!ctx || !names || !vals) return SASL_BADPARAM;
359 for(curname = names; *curname; curname++) {
361 for(val = ctx->values; val->name; val++) {
362 if(!strcmp(*curname,val->name)) {
364 memcpy(cur, val, sizeof(struct propval));
369 /* If we are here, we didn't find it */
370 memset(cur, 0, sizeof(struct propval));
380 /* clear values and optionally requests from property context
381 * ctx -- property context
382 * requests -- 0 = don't clear requests, 1 = clear requests
384 void prop_clear(struct propctx *ctx, int requests)
386 struct proppool *new_pool, *tmp;
389 /* We're going to need a new proppool once we reset things */
390 new_pool = alloc_proppool(ctx->mem_base->size +
391 (ctx->used_values+1) * sizeof(struct propval));
394 /* We're wiping the whole shebang */
395 ctx->used_values = 0;
397 /* Need to keep around old requets */
398 struct propval *new_values = (struct propval *)new_pool->data;
399 for(i=0; i<ctx->used_values; i++) {
400 new_values[i].name = ctx->values[i].name;
404 while(ctx->mem_base) {
406 ctx->mem_base = tmp->next;
410 /* Update allocation-related metadata */
411 ctx->allocated_values = ctx->used_values+1;
413 new_pool->size - (ctx->allocated_values * sizeof(struct propval));
415 /* Setup pointers for the values array */
416 ctx->values = (struct propval *)new_pool->data;
417 ctx->prev_val = NULL;
419 /* Setup the pools */
420 ctx->mem_base = ctx->mem_cur = new_pool;
422 /* Reset list_end and data_end for the new memory pool */
424 (char **)((char *)ctx->mem_base->data + ctx->allocated_values * sizeof(struct propval));
425 ctx->data_end = (char *)ctx->mem_base->data + ctx->mem_base->size;
431 * erase the value of a property
433 void prop_erase(struct propctx *ctx, const char *name)
438 if(!ctx || !name) return;
440 for(val = ctx->values; val->name; val++) {
441 if(!strcmp(name,val->name)) {
442 if(!val->values) break;
445 * Yes, this is casting away the const, but
446 * we should be okay because the only place this
447 * memory should be is in the proppool's
449 for(i=0;val->values[i];i++) {
450 memset((void *)(val->values[i]),0,strlen(val->values[i]));
451 val->values[i] = NULL;
464 /****fetcher interfaces****/
466 /* format the requested property names into a string
467 * ctx -- context from prop_new()/prop_request()
468 * sep -- separator between property names (unused if none requested)
469 * seplen -- length of separator, if < 0 then strlen(sep) will be used
470 * outbuf -- output buffer
471 * outmax -- maximum length of output buffer including NUL terminator
472 * outlen -- set to length of output string excluding NUL terminator
473 * returns 0 on success and amount of additional space needed on failure
475 int prop_format(struct propctx *ctx, const char *sep, int seplen,
476 char *outbuf, unsigned outmax, unsigned *outlen)
478 unsigned needed, flag = 0;
481 if (!ctx || !outbuf) return SASL_BADPARAM;
483 if (!sep) seplen = 0;
484 if (seplen < 0) seplen = (int) strlen(sep);
485 /* If seplen is negative now we have overflow.
486 But if you have a string longer than 2Gb, you are an idiot anyway */
487 if (seplen < 0) return SASL_BADPARAM;
489 needed = seplen * (ctx->used_values - 1);
490 for(val = ctx->values; val->name; val++) {
491 needed += (unsigned) strlen(val->name);
494 if(!outmax) return (needed + 1); /* Because of unsigned funkiness */
495 if(needed > (outmax - 1)) return (needed - (outmax - 1));
498 if(outlen) *outlen = needed;
500 if(needed == 0) return SASL_OK;
502 for(val = ctx->values; val->name; val++) {
504 strncat(outbuf, sep, seplen);
508 strcat(outbuf, val->name);
514 /* add a property value to the context
515 * ctx -- context from prop_new()/prop_request()
516 * name -- name of property to which value will be added
517 * if NULL, add to the same name as previous prop_set/setvals call
518 * value -- a value for the property; will be copied into context
519 * if NULL, remove existing values
520 * vallen -- length of value, if <= 0 then strlen(value) will be used
522 int prop_set(struct propctx *ctx, const char *name,
523 const char *value, int vallen)
527 if(!ctx) return SASL_BADPARAM;
528 if(!name && !ctx->prev_val) return SASL_BADPARAM;
533 ctx->prev_val = NULL;
535 for(val = ctx->values; val->name; val++) {
536 if(!strcmp(name,val->name)){
542 /* Couldn't find it! */
543 if(!ctx->prev_val) return SASL_BADPARAM;
548 if(name) /* New Entry */ {
549 unsigned nvalues = 1; /* 1 for NULL entry */
550 const char **old_values = NULL;
557 /* If we would be adding a null value, then we are done */
561 old_values = cur->values;
562 tmp = (char **)cur->values;
571 nvalues++; /* for the new value */
574 size = nvalues * sizeof(char*);
576 if(size > ctx->mem_cur->unused) {
579 for(needed = ctx->mem_cur->size * 2; needed < size; needed *= 2);
581 /* Allocate a new proppool */
582 ctx->mem_cur->next = alloc_proppool(needed);
583 if(!ctx->mem_cur->next) return SASL_NOMEM;
585 ctx->mem_cur = ctx->mem_cur->next;
587 ctx->list_end = (char **)ctx->mem_cur->data;
588 ctx->data_end = ctx->mem_cur->data + needed;
591 /* Grab the memory */
592 ctx->mem_cur->unused -= size;
593 cur->values = (const char **)ctx->list_end;
594 cur->values[nvalues - 1] = NULL;
596 /* Finish updating the context */
597 ctx->list_end = (char **)(cur->values + nvalues);
599 /* If we don't have an actual value to fill in, we are done */
603 tmp2 = (char **)cur->values;
605 tmp = (char **)old_values;
613 /* Now allocate the last entry */
615 size = (size_t)(strlen(value) + 1);
617 size = (size_t)(vallen + 1);
619 if(size > ctx->mem_cur->unused) {
622 needed = ctx->mem_cur->size * 2;
624 while(needed < size) {
628 /* Allocate a new proppool */
629 ctx->mem_cur->next = alloc_proppool(needed);
630 if(!ctx->mem_cur->next) return SASL_NOMEM;
632 ctx->mem_cur = ctx->mem_cur->next;
633 ctx->list_end = (char **)ctx->mem_cur->data;
634 ctx->data_end = ctx->mem_cur->data + needed;
637 /* Update the data_end pointer */
638 ctx->data_end -= size;
639 ctx->mem_cur->unused -= size;
641 /* Copy and setup the new value! */
642 memcpy(ctx->data_end, value, size-1);
643 ctx->data_end[size - 1] = '\0';
644 cur->values[nvalues - 2] = ctx->data_end;
647 cur->valsize += ((unsigned) size - 1);
648 } else /* Appending an entry */ {
652 /* If we are setting it to be NULL, we are done */
653 if(!value) return SASL_OK;
655 size = sizeof(char*);
657 /* Is it in the current pool, and will it fit in the unused space? */
658 if(size > ctx->mem_cur->unused &&
659 (void *)cur->values > (void *)(ctx->mem_cur->data) &&
660 (void *)cur->values < (void *)(ctx->mem_cur->data + ctx->mem_cur->size)) {
661 /* recursively call the not-fast way */
662 return prop_set(ctx, cur->name, value, vallen);
665 /* Note the invariant: the previous value list must be
666 at the top of the CURRENT pool at this point */
668 /* Grab the memory */
669 ctx->mem_cur->unused -= size;
672 *(ctx->list_end - 1) = NULL;
673 tmp = (ctx->list_end - 2);
675 /* Now allocate the last entry */
677 size = strlen(value) + 1;
681 if(size > ctx->mem_cur->unused) {
684 needed = ctx->mem_cur->size * 2;
686 while(needed < size) {
690 /* Allocate a new proppool */
691 ctx->mem_cur->next = alloc_proppool(needed);
692 if(!ctx->mem_cur->next) return SASL_NOMEM;
694 ctx->mem_cur = ctx->mem_cur->next;
695 ctx->list_end = (char **)ctx->mem_cur->data;
696 ctx->data_end = ctx->mem_cur->data + needed;
699 /* Update the data_end pointer */
700 ctx->data_end -= size;
701 ctx->mem_cur->unused -= size;
703 /* Copy and setup the new value! */
704 memcpy(ctx->data_end, value, size-1);
705 ctx->data_end[size - 1] = '\0';
706 *tmp = ctx->data_end;
709 cur->valsize += ((unsigned) size - 1);
716 /* set the values for a property
717 * ctx -- context from prop_new()/prop_request()
718 * name -- name of property to which value will be added
719 * if NULL, add to the same name as previous prop_set/setvals call
720 * values -- array of values, ending in NULL. Each value is a NUL terminated
723 int prop_setvals(struct propctx *ctx, const char *name,
726 const char **val = values;
727 int result = SASL_OK;
729 if(!ctx) return SASL_BADPARAM;
731 /* If they want us to add no values, we can do that */
732 if(!values) return SASL_OK;
734 /* Basically, use prop_set to do all our dirty work for us */
736 result = prop_set(ctx, name, *val, 0);
741 if(result != SASL_OK) return result;
742 result = prop_set(ctx, NULL, *val,0);
748 /* Request a set of auxiliary properties
749 * conn connection context
750 * propnames list of auxiliary property names to request ending with
753 * Subsequent calls will add items to the request list. Call with NULL
754 * to clear the request list.
758 * SASL_BADPARAM -- bad count/conn parameter
759 * SASL_NOMEM -- out of memory
761 int sasl_auxprop_request(sasl_conn_t *conn, const char **propnames)
764 sasl_server_conn_t *sconn;
766 if(!conn) return SASL_BADPARAM;
767 if(conn->type != SASL_CONN_SERVER)
770 sconn = (sasl_server_conn_t *)conn;
773 prop_clear(sconn->sparams->propctx,1);
777 result = prop_request(sconn->sparams->propctx, propnames);
778 RETURN(conn, result);
782 /* Returns current auxiliary property context.
783 * Use functions in prop.h to access content
785 * if authentication hasn't completed, property values may be empty/NULL
787 * properties not recognized by active plug-ins will be left empty/NULL
789 * returns NULL if conn is invalid.
791 struct propctx *sasl_auxprop_getctx(sasl_conn_t *conn)
793 sasl_server_conn_t *sconn;
795 if(!conn || conn->type != SASL_CONN_SERVER) return NULL;
797 sconn = (sasl_server_conn_t *)conn;
799 return sconn->sparams->propctx;
802 /* add an auxiliary property plugin */
803 int sasl_auxprop_add_plugin(const char *plugname,
804 sasl_auxprop_init_t *auxpropfunc)
806 int result, out_version;
807 auxprop_plug_list_t *new_item;
808 sasl_auxprop_plug_t *plug;
810 result = auxpropfunc(sasl_global_utils, SASL_AUXPROP_PLUG_VERSION,
811 &out_version, &plug, plugname);
813 if(result != SASL_OK) {
814 _sasl_log(NULL, SASL_LOG_ERR, "auxpropfunc error %s\n",
815 sasl_errstring(result, NULL, NULL));
819 /* We require that this function is implemented */
820 if(!plug->auxprop_lookup) return SASL_BADPROT;
822 new_item = sasl_ALLOC(sizeof(auxprop_plug_list_t));
823 if(!new_item) return SASL_NOMEM;
825 /* These will load from least-important to most important */
826 new_item->plug = plug;
827 new_item->next = auxprop_head;
828 auxprop_head = new_item;
833 void _sasl_auxprop_free()
835 auxprop_plug_list_t *ptr, *ptr_next;
837 for(ptr = auxprop_head; ptr; ptr = ptr_next) {
838 ptr_next = ptr->next;
839 if(ptr->plug->auxprop_free)
840 ptr->plug->auxprop_free(ptr->plug->glob_context,
849 /* Do the callbacks for auxprop lookups */
850 void _sasl_auxprop_lookup(sasl_server_params_t *sparams,
852 const char *user, unsigned ulen)
854 sasl_getopt_t *getopt;
857 const char *plist = NULL;
858 auxprop_plug_list_t *ptr;
860 if(_sasl_getcallback(sparams->utils->conn,
861 SASL_CB_GETOPT, &getopt, &context) == SASL_OK) {
862 ret = getopt(context, NULL, "auxprop_plugin", &plist, NULL);
863 if(ret != SASL_OK) plist = NULL;
867 /* Do lookup in all plugins */
868 for(ptr = auxprop_head; ptr; ptr = ptr->next) {
870 ptr->plug->auxprop_lookup(ptr->plug->glob_context,
871 sparams, flags, user, ulen);
874 char *pluginlist = NULL, *freeptr = NULL, *thisplugin = NULL;
876 if(_sasl_strdup(plist, &pluginlist, NULL) != SASL_OK) return;
877 thisplugin = freeptr = pluginlist;
879 /* Do lookup in all *specified* plugins, in order */
884 while(*thisplugin && isspace((int)*thisplugin)) thisplugin++;
885 if(!(*thisplugin)) break;
887 for(p = thisplugin;*p != '\0' && !isspace((int)*p); p++);
888 if(*p == '\0') last = 1;
891 for(ptr = auxprop_head; ptr; ptr = ptr->next) {
892 /* Skip non-matching plugins */
894 || strcasecmp(ptr->plug->name, thisplugin))
898 ptr->plug->auxprop_lookup(ptr->plug->glob_context,
899 sparams, flags, user, ulen);
911 _sasl_log(sparams->utils->conn, SASL_LOG_DEBUG,
912 "could not find auxprop plugin, was searching for '%s'",
913 plist ? plist : "[all]");
916 /* Do the callbacks for auxprop stores */
917 int sasl_auxprop_store(sasl_conn_t *conn,
918 struct propctx *ctx, const char *user)
920 sasl_getopt_t *getopt;
923 const char *plist = NULL;
924 auxprop_plug_list_t *ptr;
925 sasl_server_params_t *sparams = NULL;
926 unsigned userlen = 0;
930 return SASL_BADPARAM;
932 sparams = ((sasl_server_conn_t *) conn)->sparams;
933 userlen = (unsigned) strlen(user);
936 /* Pickup getopt callback from the connection, if conn is not NULL */
937 if(_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK) {
938 ret = getopt(context, NULL, "auxprop_plugin", &plist, NULL);
939 if(ret != SASL_OK) plist = NULL;
944 /* Do store in all plugins */
945 for(ptr = auxprop_head; ptr && ret == SASL_OK; ptr = ptr->next) {
947 if (ptr->plug->auxprop_store)
948 ret = ptr->plug->auxprop_store(ptr->plug->glob_context,
949 sparams, ctx, user, userlen);
952 char *pluginlist = NULL, *freeptr = NULL, *thisplugin = NULL;
954 if(_sasl_strdup(plist, &pluginlist, NULL) != SASL_OK) return SASL_FAIL;
955 thisplugin = freeptr = pluginlist;
957 /* Do store in all *specified* plugins, in order */
962 while(*thisplugin && isspace((int)*thisplugin)) thisplugin++;
963 if(!(*thisplugin)) break;
965 for(p = thisplugin;*p != '\0' && !isspace((int)*p); p++);
966 if(*p == '\0') last = 1;
969 for(ptr = auxprop_head; ptr && ret == SASL_OK; ptr = ptr->next) {
970 /* Skip non-matching plugins */
972 || strcasecmp(ptr->plug->name, thisplugin)))
976 if (ptr->plug->auxprop_store)
977 ret = ptr->plug->auxprop_store(ptr->plug->glob_context,
978 sparams, ctx, user, userlen);
990 _sasl_log(NULL, SASL_LOG_ERR,
991 "could not find auxprop plugin, was searching for %s",
992 plist ? plist : "[all]");
999 /* It would be nice if we can show other information like Author, Company, Year, plugin version */
1001 _sasl_print_mechanism (
1002 sasl_auxprop_plug_t *m,
1003 sasl_info_callback_stage_t stage,
1009 if (stage == SASL_INFO_LIST_START) {
1010 printf ("List of auxprop plugins follows\n");
1012 } else if (stage == SASL_INFO_LIST_END) {
1016 /* Process the mechanism */
1017 printf ("Plugin \"%s\" ", m->name);
1020 switch (m->condition) {
1022 printf ("[loaded]");
1026 printf ("[delayed]");
1030 printf ("[no users]");
1034 printf ("[unknown]");
1039 printf (", \tAPI version: %d\n", /* m->version */ SASL_AUXPROP_PLUG_VERSION);
1041 /* TODO - Update for auxprop_export, etc. */
1042 printf ("\tsupports store: %s\n",
1043 (m->auxprop_store != NULL) ? "yes" : "no"
1046 /* No features defined yet */
1048 printf ("\n\tfeatures:");
1054 /* Dump information about available auxprop plugins (separate functions are
1055 used for canon and server authentication plugins) */
1056 int auxprop_plugin_info (
1057 const char *c_mech_list, /* space separated mechanism list or NULL for ALL */
1058 auxprop_info_callback_t *info_cb,
1062 auxprop_plug_list_t *m;
1063 sasl_auxprop_plug_t plug_data;
1065 char *mech_list = NULL;
1068 if (info_cb == NULL) {
1069 info_cb = _sasl_print_mechanism;
1072 if (auxprop_head != NULL) {
1073 info_cb (NULL, SASL_INFO_LIST_START, info_cb_rock);
1075 if (c_mech_list == NULL) {
1076 m = auxprop_head; /* m point to beginning of the list */
1079 /* TODO: Need to be careful when dealing with auxprop_export, etc. */
1080 memcpy (&plug_data, m->plug, sizeof(plug_data));
1082 info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
1087 mech_list = strdup(c_mech_list);
1089 cur_mech = mech_list;
1091 while (cur_mech != NULL) {
1092 p = strchr (cur_mech, ' ');
1098 m = auxprop_head; /* m point to beginning of the list */
1101 if (strcasecmp (cur_mech, m->plug->name) == 0) {
1102 memcpy (&plug_data, m->plug, sizeof(plug_data));
1104 info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
1116 info_cb (NULL, SASL_INFO_LIST_END, info_cb_rock);
1121 return (SASL_NOTINIT);