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