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 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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_ 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 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_ 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