1 /*
2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /* auxprop.c - auxilliary property support
7 * Rob Siemborski
8 * $Id: auxprop.c,v 1.10 2003/03/19 18:25:27 rjs3 Exp $
9 */
10 /*
11 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 *
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 *
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in
22 * the documentation and/or other materials provided with the
23 * distribution.
24 *
25 * 3. The name "Carnegie Mellon University" must not be used to
26 * endorse or promote products derived from this software without
27 * prior written permission. For permission or any other legal
28 * details, please contact
29 * Office of Technology Transfer
30 * Carnegie Mellon University
31 * 5000 Forbes Avenue
32 * Pittsburgh, PA 15213-3890
33 * (412) 268-4387, fax: (412) 268-7395
34 * tech-transfer@andrew.cmu.edu
35 *
36 * 4. Redistributions of any form whatsoever must retain the following
37 * acknowledgment:
38 * "This product includes software developed by Computing Services
39 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
40 *
41 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
42 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
43 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
44 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
45 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
46 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
47 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
48 */
49
50 #include <config.h>
51 #include <sasl.h>
52 #include <prop.h>
53 #include <ctype.h>
54 #include "saslint.h"
55
56 struct proppool
57 {
58 struct proppool *next;
59
60 size_t size; /* Size of Block */
61 size_t unused; /* Space unused in this pool between end
62 * of char** area and beginning of char* area */
63
64 char data[1]; /* Variable Sized */
65 };
66
67 struct propctx {
68 struct propval *values;
69 struct propval *prev_val; /* Previous value used by set/setvalues */
70
71 unsigned used_values, allocated_values;
72
73 char *data_end; /* Bottom of string area in current pool */
74 char **list_end; /* Top of list area in current pool */
75
76 struct proppool *mem_base;
77 struct proppool *mem_cur;
78 };
79
80 typedef struct auxprop_plug_list
81 {
82 struct auxprop_plug_list *next;
83 const sasl_auxprop_plug_t *plug;
84 #ifdef _SUN_SDK_
85 char *plugname;
86 #endif /* _SUN_SDK_ */
87 } auxprop_plug_list_t;
88
89 #ifndef _SUN_SDK_
90 static auxprop_plug_list_t *auxprop_head = NULL;
91 #endif /* !_SUN_SDK_ */
92
alloc_proppool(size_t size)93 static struct proppool *alloc_proppool(size_t size)
94 {
95 struct proppool *ret;
96 /* minus 1 for the one that is already a part of the array
97 * in the struct */
98 size_t total_size = sizeof(struct proppool) + size - 1;
99 #ifdef _SUN_SDK_
100 ret = sasl_sun_ALLOC(total_size);
101 #else
102 ret = sasl_ALLOC(total_size);
103 #endif /* _SUN_SDK_*/
104 if(!ret) return NULL;
105
106 memset(ret, 0, total_size);
107
108 ret->size = ret->unused = size;
109
110 return ret;
111 }
112
113 /* Resize a proppool. Invalidates the unused value for this pool */
resize_proppool(struct proppool * pool,size_t size)114 static struct proppool *resize_proppool(struct proppool *pool, size_t size)
115 {
116 struct proppool *ret;
117
118 if(pool->size >= size) return pool;
119 #ifdef _SUN_SDK_
120 ret = sasl_sun_REALLOC(pool, sizeof(struct proppool) + size);
121 #else
122 ret = sasl_REALLOC(pool, sizeof(struct proppool) + size);
123 #endif /* _SUN_SDK_*/
124 if(!ret) return NULL;
125
126 ret->size = size;
127
128 return ret;
129 }
130
prop_init(struct propctx * ctx,unsigned estimate)131 static int prop_init(struct propctx *ctx, unsigned estimate)
132 {
133 const unsigned VALUES_SIZE = PROP_DEFAULT * sizeof(struct propval);
134
135 ctx->mem_base = alloc_proppool(VALUES_SIZE + estimate);
136 if(!ctx->mem_base) return SASL_NOMEM;
137
138 ctx->mem_cur = ctx->mem_base;
139
140 ctx->values = (struct propval *)ctx->mem_base->data;
141 ctx->mem_base->unused = ctx->mem_base->size - VALUES_SIZE;
142 ctx->allocated_values = PROP_DEFAULT;
143 ctx->used_values = 0;
144
145 ctx->data_end = ctx->mem_base->data + ctx->mem_base->size;
146 ctx->list_end = (char **)(ctx->mem_base->data + VALUES_SIZE);
147
148 ctx->prev_val = NULL;
149
150 return SASL_OK;
151 }
152
153 /* create a property context
154 * estimate -- an estimate of the storage needed for requests & responses
155 * 0 will use module default
156 * returns NULL on error
157 */
prop_new(unsigned estimate)158 struct propctx *prop_new(unsigned estimate)
159 {
160 struct propctx *new_ctx;
161
162 if(!estimate) estimate = PROP_DEFAULT * 255;
163
164 #ifdef _SUN_SDK_
165 new_ctx = sasl_sun_ALLOC(sizeof(struct propctx));
166 #else
167 new_ctx = sasl_ALLOC(sizeof(struct propctx));
168 #endif /* _SUN_SDK_*/
169 if(!new_ctx) return NULL;
170
171 if(prop_init(new_ctx, estimate) != SASL_OK) {
172 prop_dispose(&new_ctx);
173 }
174
175 return new_ctx;
176 }
177
178 /* create new propctx which duplicates the contents of an existing propctx
179 * returns -1 on error
180 */
prop_dup(struct propctx * src_ctx,struct propctx ** dst_ctx)181 int prop_dup(struct propctx *src_ctx, struct propctx **dst_ctx)
182 {
183 struct proppool *pool;
184 struct propctx *retval = NULL;
185 unsigned i;
186 int result;
187 size_t total_size = 0, values_size;
188
189 if(!src_ctx || !dst_ctx) return SASL_BADPARAM;
190
191 /* What is the total allocated size of src_ctx? */
192 pool = src_ctx->mem_base;
193 while(pool) {
194 total_size += pool->size;
195 pool = pool->next;
196 }
197
198 /* allocate the new context */
199 retval = prop_new(total_size);
200 if(!retval) return SASL_NOMEM;
201
202 retval->used_values = src_ctx->used_values;
203 retval->allocated_values = src_ctx->used_values + 1;
204
205 values_size = (retval->allocated_values * sizeof(struct propval));
206
207 retval->mem_base->unused = retval->mem_base->size - values_size;
208
209 retval->list_end = (char **)(retval->mem_base->data + values_size);
210 /* data_end should still be OK */
211
212 /* Now dup the values */
213 for(i=0; i<src_ctx->used_values; i++) {
214 retval->values[i].name = src_ctx->values[i].name;
215 result = prop_setvals(retval, retval->values[i].name,
216 src_ctx->values[i].values);
217 if(result != SASL_OK)
218 goto fail;
219 }
220
221 retval->prev_val = src_ctx->prev_val;
222
223 *dst_ctx = retval;
224 return SASL_OK;
225
226 fail:
227 if(retval) prop_dispose(&retval);
228 return result;
229 }
230
231 /*
232 * dispose of property context
233 * ctx -- is disposed and set to NULL; noop if ctx or *ctx is NULL
234 */
prop_dispose(struct propctx ** ctx)235 void prop_dispose(struct propctx **ctx)
236 {
237 struct proppool *tmp;
238
239 if(!ctx || !*ctx) return;
240
241 while((*ctx)->mem_base) {
242 tmp = (*ctx)->mem_base;
243 (*ctx)->mem_base = tmp->next;
244 #ifdef _SUN_SDK_
245 sasl_sun_FREE(tmp);
246 #else
247 sasl_FREE(tmp);
248 #endif /* _SUN_SDK_*/
249 }
250
251 #ifdef _SUN_SDK_
252 sasl_sun_FREE(*ctx);
253 #else
254 sasl_FREE(*ctx);
255 #endif /* _SUN_SDK_*/
256 *ctx = NULL;
257
258 return;
259 }
260
261 /* Add property names to request
262 * ctx -- context from prop_new()
263 * names -- list of property names; must persist until context freed
264 * or requests cleared
265 *
266 * NOTE: may clear values from context as side-effect
267 * returns -1 on error
268 */
prop_request(struct propctx * ctx,const char ** names)269 int prop_request(struct propctx *ctx, const char **names)
270 {
271 unsigned i, new_values, total_values;
272
273 if(!ctx || !names) return SASL_BADPARAM;
274
275 /* Count how many we need to add */
276 for(new_values=0; names[new_values]; new_values++);
277
278 /* Do we need to add ANY? */
279 if(!new_values) return SASL_OK;
280
281 /* We always want atleast on extra to mark the end of the array */
282 total_values = new_values + ctx->used_values + 1;
283
284 /* Do we need to increase the size of our propval table? */
285 if(total_values > ctx->allocated_values) {
286 unsigned max_in_pool;
287
288 /* Do we need a larger base pool? */
289 max_in_pool = ctx->mem_base->size / sizeof(struct propval);
290
291 if(total_values <= max_in_pool) {
292 /* Don't increase the size of the base pool, just use what
293 we need */
294 ctx->allocated_values = total_values;
295 ctx->mem_base->unused =
296 ctx->mem_base->size - (sizeof(struct propval)
297 * ctx->allocated_values);
298 } else {
299 /* We need to allocate more! */
300 unsigned new_alloc_length;
301 size_t new_size;
302
303 new_alloc_length = 2 * ctx->allocated_values;
304 while(total_values > new_alloc_length) {
305 new_alloc_length *= 2;
306 }
307
308 new_size = new_alloc_length * sizeof(struct propval);
309 ctx->mem_base = resize_proppool(ctx->mem_base, new_size);
310
311 if(!ctx->mem_base) {
312 ctx->values = NULL;
313 ctx->allocated_values = ctx->used_values = 0;
314 return SASL_NOMEM;
315 }
316
317 /* It worked! Update the structure! */
318 ctx->values = (struct propval *)ctx->mem_base->data;
319 ctx->allocated_values = new_alloc_length;
320 ctx->mem_base->unused = ctx->mem_base->size
321 - sizeof(struct propval) * ctx->allocated_values;
322 }
323
324 /* Clear out new propvals */
325 memset(&(ctx->values[ctx->used_values]), 0,
326 sizeof(struct propval) * (ctx->allocated_values - ctx->used_values));
327
328 /* Finish updating the context -- we've extended the list! */
329 /* ctx->list_end = (char **)(ctx->values + ctx->allocated_values); */
330 /* xxx test here */
331 ctx->list_end = (char **)(ctx->values + total_values);
332 }
333
334 /* Now do the copy, or referencing rather */
335 for(i=0;i<new_values;i++) {
336 unsigned j, flag;
337
338 flag = 0;
339
340 /* Check for dups */
341 for(j=0;j<ctx->used_values;j++) {
342 if(!strcmp(ctx->values[j].name, names[i])) {
343 flag = 1;
344 break;
345 }
346 }
347
348 /* We already have it... skip! */
349 if(flag) continue;
350
351 ctx->values[ctx->used_values++].name = names[i];
352 }
353
354 prop_clear(ctx, 0);
355
356 return SASL_OK;
357 }
358
359 /* return array of struct propval from the context
360 * return value persists until next call to
361 * prop_request, prop_clear or prop_dispose on context
362 */
prop_get(struct propctx * ctx)363 const struct propval *prop_get(struct propctx *ctx)
364 {
365 if(!ctx) return NULL;
366
367 return ctx->values;
368 }
369
370 /* Fill in an array of struct propval based on a list of property names
371 * return value persists until next call to
372 * prop_request, prop_clear or prop_dispose on context
373 * returns -1 on error (no properties ever requested, ctx NULL, etc)
374 * returns number of matching properties which were found (values != NULL)
375 * if a name requested here was never requested by a prop_request, then
376 * the name field of the associated vals entry will be set to NULL
377 */
prop_getnames(struct propctx * ctx,const char ** names,struct propval * vals)378 int prop_getnames(struct propctx *ctx, const char **names,
379 struct propval *vals)
380 {
381 int found_names = 0;
382
383 struct propval *cur = vals;
384 const char **curname;
385
386 if(!ctx || !names || !vals) return SASL_BADPARAM;
387
388 for(curname = names; *curname; curname++) {
389 struct propval *val;
390 for(val = ctx->values; val->name; val++) {
391 if(!strcmp(*curname,val->name)) {
392 found_names++;
393 memcpy(cur, val, sizeof(struct propval));
394 goto next;
395 }
396 }
397
398 /* If we are here, we didn't find it */
399 memset(cur, 0, sizeof(struct propval));
400
401 next:
402 cur++;
403 }
404
405 return found_names;
406 }
407
408
409 /* clear values and optionally requests from property context
410 * ctx -- property context
411 * requests -- 0 = don't clear requests, 1 = clear requests
412 */
prop_clear(struct propctx * ctx,int requests)413 void prop_clear(struct propctx *ctx, int requests)
414 {
415 struct proppool *new_pool, *tmp;
416 unsigned i;
417
418 #ifdef _SUN_SDK_
419 if(!ctx) return;
420 #endif /* _SUN_SDK_ */
421
422 /* We're going to need a new proppool once we reset things */
423 new_pool = alloc_proppool(ctx->mem_base->size +
424 (ctx->used_values+1) * sizeof(struct propval));
425
426 if(requests) {
427 /* We're wiping the whole shebang */
428 ctx->used_values = 0;
429 } else {
430 /* Need to keep around old requets */
431 struct propval *new_values = (struct propval *)new_pool->data;
432 for(i=0; i<ctx->used_values; i++) {
433 new_values[i].name = ctx->values[i].name;
434 }
435 }
436
437 while(ctx->mem_base) {
438 tmp = ctx->mem_base;
439 ctx->mem_base = tmp->next;
440 #ifdef _SUN_SDK_
441 sasl_sun_FREE(tmp);
442 #else
443 sasl_FREE(tmp);
444 #endif /* _SUN_SDK_ */
445 }
446
447 /* Update allocation-related metadata */
448 ctx->allocated_values = ctx->used_values+1;
449 new_pool->unused =
450 new_pool->size - (ctx->allocated_values * sizeof(struct propval));
451
452 /* Setup pointers for the values array */
453 ctx->values = (struct propval *)new_pool->data;
454 ctx->prev_val = NULL;
455
456 /* Setup the pools */
457 ctx->mem_base = ctx->mem_cur = new_pool;
458
459 /* Reset list_end and data_end for the new memory pool */
460 ctx->list_end =
461 (char **)((char *)ctx->mem_base->data + ctx->allocated_values * sizeof(struct propval));
462 ctx->data_end = (char *)ctx->mem_base->data + ctx->mem_base->size;
463
464 return;
465 }
466
467 /*
468 * erase the value of a property
469 */
prop_erase(struct propctx * ctx,const char * name)470 void prop_erase(struct propctx *ctx, const char *name)
471 {
472 struct propval *val;
473 int i;
474
475 if(!ctx || !name) return;
476
477 for(val = ctx->values; val->name; val++) {
478 if(!strcmp(name,val->name)) {
479 if(!val->values) break;
480
481 /*
482 * Yes, this is casting away the const, but
483 * we should be okay because the only place this
484 * memory should be is in the proppool's
485 */
486 for(i=0;val->values[i];i++) {
487 memset((void *)(val->values[i]),0,strlen(val->values[i]));
488 val->values[i] = NULL;
489 }
490
491 val->values = NULL;
492 val->nvalues = 0;
493 val->valsize = 0;
494 break;
495 }
496 }
497
498 return;
499 }
500
501 /****fetcher interfaces****/
502
503 /* format the requested property names into a string
504 * ctx -- context from prop_new()/prop_request()
505 * sep -- separator between property names (unused if none requested)
506 * seplen -- length of separator, if < 0 then strlen(sep) will be used
507 * outbuf -- output buffer
508 * outmax -- maximum length of output buffer including NUL terminator
509 * outlen -- set to length of output string excluding NUL terminator
510 * returns 0 on success and amount of additional space needed on failure
511 */
prop_format(struct propctx * ctx,const char * sep,int seplen,char * outbuf,unsigned outmax,unsigned * outlen)512 int prop_format(struct propctx *ctx, const char *sep, int seplen,
513 char *outbuf, unsigned outmax, unsigned *outlen)
514 {
515 unsigned needed, flag = 0;
516 struct propval *val;
517
518 if(!ctx || !outbuf) return SASL_BADPARAM;
519
520 if(!sep) seplen = 0;
521 if(seplen < 0) seplen = strlen(sep);
522
523 needed = seplen * (ctx->used_values - 1);
524 for(val = ctx->values; val->name; val++) {
525 needed += strlen(val->name);
526 }
527
528 if(!outmax) return (needed + 1); /* Because of unsigned funkiness */
529 if(needed > (outmax - 1)) return (needed - (outmax - 1));
530
531 *outbuf = '\0';
532 if(outlen) *outlen = needed;
533
534 if(needed == 0) return SASL_OK;
535
536 for(val = ctx->values; val->name; val++) {
537 if(seplen && flag) {
538 strncat(outbuf, sep, seplen);
539 } else {
540 flag = 1;
541 }
542 strcat(outbuf, val->name);
543 }
544
545 return SASL_OK;
546 }
547
548 /* add a property value to the context
549 * ctx -- context from prop_new()/prop_request()
550 * name -- name of property to which value will be added
551 * if NULL, add to the same name as previous prop_set/setvals call
552 * value -- a value for the property; will be copied into context
553 * if NULL, remove existing values
554 * vallen -- length of value, if <= 0 then strlen(value) will be used
555 */
prop_set(struct propctx * ctx,const char * name,const char * value,int vallen)556 int prop_set(struct propctx *ctx, const char *name,
557 const char *value, int vallen)
558 {
559 struct propval *cur;
560
561 if(!ctx) return SASL_BADPARAM;
562 if(!name && !ctx->prev_val) return SASL_BADPARAM;
563
564 if(name) {
565 struct propval *val;
566
567 ctx->prev_val = NULL;
568
569 for(val = ctx->values; val->name; val++) {
570 if(!strcmp(name,val->name)){
571 ctx->prev_val = val;
572 break;
573 }
574 }
575
576 /* Couldn't find it! */
577 if(!ctx->prev_val) return SASL_BADPARAM;
578 }
579
580 cur = ctx->prev_val;
581
582 if(name) /* New Entry */ {
583 unsigned nvalues = 1; /* 1 for NULL entry */
584 const char **old_values = NULL;
585 char **tmp, **tmp2;
586 size_t size;
587
588 if(cur->values) {
589
590 if(!value) {
591 /* If we would be adding a null value, then we are done */
592 return SASL_OK;
593 }
594
595 old_values = cur->values;
596 tmp = (char **)cur->values;
597 while(*tmp) {
598 nvalues++;
599 tmp++;
600 }
601
602 }
603
604 if(value) {
605 nvalues++; /* for the new value */
606 }
607
608 size = nvalues * sizeof(char*);
609
610 if(size > ctx->mem_cur->unused) {
611 size_t needed;
612
613 for(needed = ctx->mem_cur->size * 2; needed < size; needed *= 2);
614
615 /* Allocate a new proppool */
616 ctx->mem_cur->next = alloc_proppool(needed);
617 if(!ctx->mem_cur->next) return SASL_NOMEM;
618
619 ctx->mem_cur = ctx->mem_cur->next;
620
621 ctx->list_end = (char **)ctx->mem_cur->data;
622 ctx->data_end = ctx->mem_cur->data + needed;
623 }
624
625 /* Grab the memory */
626 ctx->mem_cur->unused -= size;
627 cur->values = (const char **)ctx->list_end;
628 cur->values[nvalues - 1] = NULL;
629
630 /* Finish updating the context */
631 ctx->list_end = (char **)(cur->values + nvalues);
632
633 /* If we don't have an actual value to fill in, we are done */
634 if(!value)
635 return SASL_OK;
636
637 tmp2 = (char **)cur->values;
638 if(old_values) {
639 tmp = (char **)old_values;
640
641 while(*tmp) {
642 *tmp2 = *tmp;
643 tmp++; tmp2++;
644 }
645 }
646
647 /* Now allocate the last entry */
648 if(vallen <= 0)
649 size = (size_t)(strlen(value) + 1);
650 else
651 size = (size_t)(vallen + 1);
652
653 if(size > ctx->mem_cur->unused) {
654 size_t needed;
655
656 needed = ctx->mem_cur->size * 2;
657
658 while(needed < size) {
659 needed *= 2;
660 }
661
662 /* Allocate a new proppool */
663 ctx->mem_cur->next = alloc_proppool(needed);
664 if(!ctx->mem_cur->next) return SASL_NOMEM;
665
666 ctx->mem_cur = ctx->mem_cur->next;
667 ctx->list_end = (char **)ctx->mem_cur->data;
668 ctx->data_end = ctx->mem_cur->data + needed;
669 }
670
671 /* Update the data_end pointer */
672 ctx->data_end -= size;
673 ctx->mem_cur->unused -= size;
674
675 /* Copy and setup the new value! */
676 memcpy(ctx->data_end, value, size-1);
677 ctx->data_end[size - 1] = '\0';
678 cur->values[nvalues - 2] = ctx->data_end;
679
680 cur->nvalues++;
681 cur->valsize += (size - 1);
682 } else /* Appending an entry */ {
683 char **tmp;
684 size_t size;
685
686 /* If we are setting it to be NULL, we are done */
687 if(!value) return SASL_OK;
688
689 size = sizeof(char*);
690
691 /* Is it in the current pool, and will it fit in the unused space? */
692 if(size > ctx->mem_cur->unused &&
693 (void *)cur->values > (void *)(ctx->mem_cur->data) &&
694 (void *)cur->values < (void *)(ctx->mem_cur->data + ctx->mem_cur->size)) {
695 /* recursively call the not-fast way */
696 return prop_set(ctx, cur->name, value, vallen);
697 }
698
699 /* Note the invariant: the previous value list must be
700 at the top of the CURRENT pool at this point */
701
702 /* Grab the memory */
703 ctx->mem_cur->unused -= size;
704 ctx->list_end++;
705
706 *(ctx->list_end - 1) = NULL;
707 tmp = (ctx->list_end - 2);
708
709 /* Now allocate the last entry */
710 if(vallen <= 0)
711 size = strlen(value) + 1;
712 else
713 size = vallen + 1;
714
715 if(size > ctx->mem_cur->unused) {
716 size_t needed;
717
718 needed = ctx->mem_cur->size * 2;
719
720 while(needed < size) {
721 needed *= 2;
722 }
723
724 /* Allocate a new proppool */
725 ctx->mem_cur->next = alloc_proppool(needed);
726 if(!ctx->mem_cur->next) return SASL_NOMEM;
727
728 ctx->mem_cur = ctx->mem_cur->next;
729 ctx->list_end = (char **)ctx->mem_cur->data;
730 ctx->data_end = ctx->mem_cur->data + needed;
731 }
732
733 /* Update the data_end pointer */
734 ctx->data_end -= size;
735 ctx->mem_cur->unused -= size;
736
737 /* Copy and setup the new value! */
738 memcpy(ctx->data_end, value, size-1);
739 ctx->data_end[size - 1] = '\0';
740 *tmp = ctx->data_end;
741
742 cur->nvalues++;
743 cur->valsize += (size - 1);
744 }
745
746 return SASL_OK;
747 }
748
749
750 /* set the values for a property
751 * ctx -- context from prop_new()/prop_request()
752 * name -- name of property to which value will be added
753 * if NULL, add to the same name as previous prop_set/setvals call
754 * values -- array of values, ending in NULL. Each value is a NUL terminated
755 * string
756 */
prop_setvals(struct propctx * ctx,const char * name,const char ** values)757 int prop_setvals(struct propctx *ctx, const char *name,
758 const char **values)
759 {
760 const char **val = values;
761 int result = SASL_OK;
762
763 if(!ctx) return SASL_BADPARAM;
764
765 /* If they want us to add no values, we can do that */
766 if(!values) return SASL_OK;
767
768 /* Basically, use prop_set to do all our dirty work for us */
769 if(name) {
770 result = prop_set(ctx, name, *val, 0);
771 val++;
772 }
773
774 for(;*val;val++) {
775 if(result != SASL_OK) return result;
776 result = prop_set(ctx, NULL, *val,0);
777 }
778
779 return result;
780 }
781
782 /* Request a set of auxiliary properties
783 * conn connection context
784 * propnames list of auxiliary property names to request ending with
785 * NULL.
786 *
787 * Subsequent calls will add items to the request list. Call with NULL
788 * to clear the request list.
789 *
790 * errors
791 * SASL_OK -- success
792 * SASL_BADPARAM -- bad count/conn parameter
793 * SASL_NOMEM -- out of memory
794 */
sasl_auxprop_request(sasl_conn_t * conn,const char ** propnames)795 int sasl_auxprop_request(sasl_conn_t *conn, const char **propnames)
796 {
797 int result;
798 sasl_server_conn_t *sconn;
799
800 if(!conn) return SASL_BADPARAM;
801 if(conn->type != SASL_CONN_SERVER)
802 PARAMERROR(conn);
803
804 sconn = (sasl_server_conn_t *)conn;
805
806 if(!propnames) {
807 prop_clear(sconn->sparams->propctx,1);
808 return SASL_OK;
809 }
810
811 result = prop_request(sconn->sparams->propctx, propnames);
812 RETURN(conn, result);
813 }
814
815
816 /* Returns current auxiliary property context.
817 * Use functions in prop.h to access content
818 *
819 * if authentication hasn't completed, property values may be empty/NULL
820 *
821 * properties not recognized by active plug-ins will be left empty/NULL
822 *
823 * returns NULL if conn is invalid.
824 */
sasl_auxprop_getctx(sasl_conn_t * conn)825 struct propctx *sasl_auxprop_getctx(sasl_conn_t *conn)
826 {
827 sasl_server_conn_t *sconn;
828
829 if(!conn || conn->type != SASL_CONN_SERVER) return NULL;
830
831 sconn = (sasl_server_conn_t *)conn;
832
833 return sconn->sparams->propctx;
834 }
835
836 /* add an auxiliary property plugin */
837 #ifdef _SUN_SDK_
sasl_auxprop_add_plugin(const char * plugname,sasl_auxprop_init_t * auxpropfunc)838 int sasl_auxprop_add_plugin(const char *plugname,
839 sasl_auxprop_init_t *auxpropfunc)
840 {
841 return (_sasl_auxprop_add_plugin(_sasl_gbl_ctx(), plugname, auxpropfunc));
842 }
843
_sasl_auxprop_add_plugin(void * ctx,const char * plugname,sasl_auxprop_init_t * auxpropfunc)844 int _sasl_auxprop_add_plugin(void *ctx,
845 const char *plugname,
846 sasl_auxprop_init_t *auxpropfunc)
847 #else
848 int sasl_auxprop_add_plugin(const char *plugname,
849 sasl_auxprop_init_t *auxpropfunc)
850 #endif /* _SUN_SDK_ */
851 {
852 int result, out_version;
853 auxprop_plug_list_t *new_item;
854 sasl_auxprop_plug_t *plug;
855 #ifdef _SUN_SDK_
856 _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx;
857 auxprop_plug_list_t *auxprop_head;
858 const sasl_utils_t *sasl_global_utils;
859 auxprop_plug_list_t *l;
860
861 auxprop_head = gctx->auxprop_head;
862 sasl_global_utils = gctx->sasl_server_global_utils;
863
864 /* Check to see if this plugin has already been registered */
865 for (l = auxprop_head; l != NULL; l = l->next) {
866 if (strcmp(plugname, l->plugname) == 0) {
867 return SASL_OK;
868 }
869 }
870 #endif /* _SUN_SDK_ */
871
872 result = auxpropfunc(sasl_global_utils, SASL_AUXPROP_PLUG_VERSION,
873 &out_version, &plug, plugname);
874
875 if(result != SASL_OK) {
876 #ifdef _SUN_SDK_
877 __sasl_log(gctx, gctx->server_global_callbacks.callbacks,
878 SASL_LOG_ERR, "auxpropfunc error %i\n",result);
879 #else
880 _sasl_log(NULL, SASL_LOG_ERR, "auxpropfunc error %i\n",result);
881 #endif /* _SUN_SDK_ */
882 return result;
883 }
884
885 /* We require that this function is implemented */
886 if(!plug->auxprop_lookup) return SASL_BADPROT;
887
888 #ifdef _SUN_SDK_
889 /* Check plugin to make sure name is non-NULL */
890 if (plug->name == NULL) {
891 __sasl_log(gctx, gctx->server_global_callbacks.callbacks,
892 SASL_LOG_ERR, "invalid auxprop plugin %s", plugname);
893 return SASL_BADPROT;
894 }
895 #endif /* _SUN_SDK_ */
896
897 new_item = sasl_ALLOC(sizeof(auxprop_plug_list_t));
898 if(!new_item) return SASL_NOMEM;
899
900 #ifdef _SUN_SDK_
901 if(_sasl_strdup(plugname, &new_item->plugname, NULL) != SASL_OK) {
902 sasl_FREE(new_item);
903 return SASL_NOMEM;
904 }
905 #endif /* _SUN_SDK_ */
906 /* These will load from least-important to most important */
907 new_item->plug = plug;
908 new_item->next = auxprop_head;
909 #ifdef _SUN_SDK_
910 gctx->auxprop_head = new_item;
911 #else
912 auxprop_head = new_item;
913 #endif /* _SUN_SDK_ */
914
915 return SASL_OK;
916 }
917
918 #ifdef _SUN_SDK_
_sasl_auxprop_free(_sasl_global_context_t * gctx)919 void _sasl_auxprop_free(_sasl_global_context_t *gctx)
920 #else
921 void _sasl_auxprop_free()
922 #endif /* _SUN_SDK_ */
923 {
924 auxprop_plug_list_t *ptr, *ptr_next;
925 #ifdef _SUN_SDK_
926 const sasl_utils_t *sasl_global_utils = gctx->sasl_server_global_utils;
927
928 for(ptr = (auxprop_plug_list_t *)gctx->auxprop_head; ptr; ptr = ptr_next) {
929 #else
930
931 for(ptr = auxprop_head; ptr; ptr = ptr_next) {
932 #endif /* _SUN_SDK_ */
933 ptr_next = ptr->next;
934 if(ptr->plug->auxprop_free)
935 ptr->plug->auxprop_free(ptr->plug->glob_context,
936 sasl_global_utils);
937 #ifdef _SUN_SDK_
938 sasl_FREE(ptr->plugname);
939 #endif /* _SUN_SDK_ */
940 sasl_FREE(ptr);
941 }
942
943 #ifdef _SUN_SDK_
944 gctx->auxprop_head = NULL;
945 #else
946 auxprop_head = NULL;
947 #endif /* _SUN_SDK_ */
948 }
949
950
951 /* Do the callbacks for auxprop lookups */
952 void _sasl_auxprop_lookup(sasl_server_params_t *sparams,
953 unsigned flags,
954 const char *user, unsigned ulen)
955 {
956 sasl_getopt_t *getopt;
957 int ret, found = 0;
958 void *context;
959 const char *plist = NULL;
960 auxprop_plug_list_t *ptr;
961 #ifdef _SUN_SDK_
962 _sasl_global_context_t *gctx = sparams->utils->conn->gctx;
963 auxprop_plug_list_t *auxprop_head = gctx->auxprop_head;
964 #endif /* _SUN_SDK_ */
965
966 if(_sasl_getcallback(sparams->utils->conn,
967 SASL_CB_GETOPT, &getopt, &context) == SASL_OK) {
968 ret = getopt(context, NULL, "auxprop_plugin", &plist, NULL);
969 if(ret != SASL_OK) plist = NULL;
970 }
971
972 if(!plist) {
973 /* Do lookup in all plugins */
974 for(ptr = auxprop_head; ptr; ptr = ptr->next) {
975 found=1;
976 ptr->plug->auxprop_lookup(ptr->plug->glob_context,
977 sparams, flags, user, ulen);
978 }
979 } else {
980 char *pluginlist = NULL, *freeptr = NULL, *thisplugin = NULL;
981
982 if(_sasl_strdup(plist, &pluginlist, NULL) != SASL_OK) return;
983 thisplugin = freeptr = pluginlist;
984
985 /* Do lookup in all *specified* plugins, in order */
986 while(*thisplugin) {
987 char *p;
988 int last=0;
989
990 while(*thisplugin && isspace((int)*thisplugin)) thisplugin++;
991 if(!(*thisplugin)) break;
992
993 for(p = thisplugin;*p != '\0' && !isspace((int)*p); p++);
994 if(*p == '\0') last = 1;
995 else *p='\0';
996
997 for(ptr = auxprop_head; ptr; ptr = ptr->next) {
998 /* Skip non-matching plugins */
999 if(!ptr->plug->name
1000 || strcasecmp(ptr->plug->name, thisplugin))
1001 continue;
1002
1003 found=1;
1004 ptr->plug->auxprop_lookup(ptr->plug->glob_context,
1005 sparams, flags, user, ulen);
1006 }
1007
1008 if(last) break;
1009
1010 thisplugin = p+1;
1011 }
1012
1013 sasl_FREE(freeptr);
1014 }
1015
1016 if(!found)
1017 _sasl_log(sparams->utils->conn, SASL_LOG_DEBUG,
1018 "could not find auxprop plugin, was searching for '%s'",
1019 plist ? plist : "[all]");
1020 }
1021