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