1 /* 2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * lib/krb5/os/an_to_ln.c 10 * 11 * Copyright 1990,1991 by the Massachusetts Institute of Technology. 12 * All Rights Reserved. 13 * 14 * Export of this software from the United States of America may 15 * require a specific license from the United States Government. 16 * It is the responsibility of any person or organization contemplating 17 * export to obtain such a license before exporting. 18 * 19 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 20 * distribute this software and its documentation for any purpose and 21 * without fee is hereby granted, provided that the above copyright 22 * notice appear in all copies and that both that copyright notice and 23 * this permission notice appear in supporting documentation, and that 24 * the name of M.I.T. not be used in advertising or publicity pertaining 25 * to distribution of the software without specific, written prior 26 * permission. Furthermore if you modify this software you must label 27 * your software as modified software and not distribute it in such a 28 * fashion that it might be confused with the original M.I.T. software. 29 * M.I.T. makes no representations about the suitability of 30 * this software for any purpose. It is provided "as is" without express 31 * or implied warranty. 32 * 33 * 34 * krb5_aname_to_localname() 35 */ 36 37 38 /* 39 * We're only to AN_TO_LN rules at this point, and not doing the 40 * database lookup (moved from configure script) 41 */ 42 #ifndef AN_TO_LN_RULES 43 #define AN_TO_LN_RULES 44 #endif 45 46 #include <k5-int.h> 47 #include <ctype.h> 48 #if HAVE_REGEX_H 49 #include <regex.h> 50 #endif /* HAVE_REGEX_H */ 51 #include <string.h> 52 /* 53 * Use compile(3) if no regcomp present. 54 */ 55 #if !defined(HAVE_REGCOMP) && defined(HAVE_REGEXPR_H) && defined(HAVE_COMPILE) 56 #define RE_BUF_SIZE 1024 57 #include <regexpr.h> 58 #endif /* !HAVE_REGCOMP && HAVE_REGEXP_H && HAVE_COMPILE */ 59 60 #define MAX_FORMAT_BUFFER 1024 61 #ifndef min 62 #define min(a,b) ((a>b) ? b : a) 63 #endif /* min */ 64 #ifdef ANAME_DB 65 /* 66 * Use standard DBM code. 67 */ 68 #define KDBM_OPEN(db, fl, mo) dbm_open(db, fl, mo) 69 #define KDBM_CLOSE(db) dbm_close(db) 70 #define KDBM_FETCH(db, key) dbm_fetch(db, key) 71 #else /*ANAME_DB*/ 72 extern DBM *db_dbm_open (char *, int, int); 73 extern void db_dbm_close (DBM *); 74 extern datum db_dbm_fetch (DBM *, datum); 75 #define KDBM_OPEN(db, fl, mo) db_dbm_open(db, fl, mo) 76 #define KDBM_CLOSE(db) db_dbm_close(db) 77 #define KDBM_FETCH(db, key) db_dbm_fetch(db, key) 78 #endif /*ANAME_DB*/ 79 80 /* 81 * Find the portion of the flattened principal name that we use for mapping. 82 */ 83 static char * 84 aname_full_to_mapping_name(char *fprincname) 85 { 86 char *atp; 87 size_t mlen; 88 char *mname; 89 90 mname = (char *) NULL; 91 if (fprincname) { 92 atp = strrchr(fprincname, '@'); 93 if (!atp) 94 atp = &fprincname[strlen(fprincname)]; 95 mlen = (size_t) (atp - fprincname); 96 97 if ((mname = (char *) malloc(mlen+1))) { 98 strncpy(mname, fprincname, mlen); 99 mname[mlen] = '\0'; 100 } 101 } 102 return(mname); 103 } 104 105 #ifdef ANAME_DB 106 /* 107 * Implementation: This version uses a DBM database, indexed by aname, 108 * to generate a lname. 109 * 110 * The entries in the database are normal C strings, and include the trailing 111 * null in the DBM datum.size. 112 */ 113 static krb5_error_code 114 db_an_to_ln(context, dbname, aname, lnsize, lname) 115 krb5_context context; 116 char *dbname; 117 krb5_const_principal aname; 118 const unsigned int lnsize; 119 char *lname; 120 { 121 #if !defined(_WIN32) 122 DBM *db; 123 krb5_error_code retval; 124 datum key, contents; 125 char *princ_name; 126 127 if ((retval = krb5_unparse_name(context, aname, &princ_name))) 128 return(retval); 129 key.dptr = princ_name; 130 key.dsize = strlen(princ_name)+1; /* need to store the NULL for 131 decoding */ 132 133 db = KDBM_OPEN(dbname, O_RDONLY, 0600); 134 if (!db) { 135 krb5_xfree(princ_name); 136 return KRB5_LNAME_CANTOPEN; 137 } 138 139 contents = KDBM_FETCH(db, key); 140 141 krb5_xfree(princ_name); 142 143 if (contents.dptr == NULL) { 144 retval = KRB5_LNAME_NOTRANS; 145 } else { 146 strncpy(lname, contents.dptr, lnsize); 147 if (lnsize < contents.dsize) 148 retval = KRB5_CONFIG_NOTENUFSPACE; 149 else if (lname[contents.dsize-1] != '\0') 150 retval = KRB5_LNAME_BADFORMAT; 151 else 152 retval = 0; 153 } 154 /* can't close until we copy the contents. */ 155 (void) KDBM_CLOSE(db); 156 return retval; 157 #else /* !_WIN32 && !MACINTOSH */ 158 /* 159 * If we don't have support for a database mechanism, then we can't 160 * translate this now, can we? 161 */ 162 return KRB5_LNAME_NOTRANS; 163 #endif /* !_WIN32 && !MACINTOSH */ 164 } 165 #endif /*ANAME_DB*/ 166 167 #ifdef AN_TO_LN_RULES 168 /* 169 * Format and transform a principal name to a local name. This is particularly 170 * useful when Kerberos principals and local user names are formatted to 171 * some particular convention. 172 * 173 * There are three parts to each rule: 174 * First part - formulate the string to perform operations on: If not present 175 * then the string defaults to the fully flattened principal minus the realm 176 * name. Otherwise the syntax is as follows: 177 * "[" <ncomps> ":" <format> "]" 178 * Where: 179 * <ncomps> is the number of expected components for this 180 * rule. If the particular principal does not have this 181 * many components, then this rule does not apply. 182 * 183 * <format> is a string of <component> or verbatim 184 * characters to be inserted. 185 * 186 * <component> is of the form "$"<number> to select the 187 * <number>th component. <number> begins from 1. 188 * 189 * Second part - select rule validity: If not present, then this rule may 190 * apply to all selections. Otherwise the syntax is as follows: 191 * "(" <regexp> ")" 192 * Where: <regexp> is a selector regular expression. If this 193 * regular expression matches the whole pattern generated 194 * from the first part, then this rule still applies. 195 * 196 * Last part - Transform rule: If not present, then the selection string 197 * is passed verbatim and is matched. Otherwise, the syntax is as follows: 198 * <rule> ... 199 * Where: <rule> is of the form: 200 * "s/" <regexp> "/" <text> "/" ["g"] 201 * 202 * In order to be able to select rule validity, the native system must support 203 * one of compile(3), re_comp(3) or regcomp(3). In order to be able to 204 * transform (e.g. substitute), the native system must support regcomp(3) or 205 * compile(3). 206 */ 207 208 /* 209 * aname_do_match() - Does our name match the parenthesized regular 210 * expression? 211 * 212 * Chew up the match portion of the regular expression and update *contextp. 213 * If no re_comp() or regcomp(), then always return a match. 214 */ 215 static krb5_error_code 216 aname_do_match(char *string, char **contextp) 217 { 218 krb5_error_code kret; 219 char *regexp, *startp, *endp = 0; 220 size_t regexlen; 221 #if HAVE_REGCOMP 222 regex_t match_exp; 223 regmatch_t match_match; 224 #elif HAVE_REGEXPR_H 225 char regexp_buffer[RE_BUF_SIZE]; 226 #endif /* HAVE_REGEXP_H */ 227 228 kret = 0; 229 /* 230 * Is this a match expression? 231 */ 232 if (**contextp == '(') { 233 kret = KRB5_CONFIG_BADFORMAT; 234 startp = (*contextp) + 1; 235 endp = strchr(startp, ')'); 236 /* Find the end of the match expression. */ 237 if (endp) { 238 regexlen = (size_t) (endp - startp); 239 regexp = (char *) malloc((size_t) regexlen+1); 240 kret = ENOMEM; 241 if (regexp) { 242 strncpy(regexp, startp, regexlen); 243 regexp[regexlen] = '\0'; 244 kret = KRB5_LNAME_NOTRANS; 245 /* 246 * Perform the match. 247 */ 248 #if HAVE_REGCOMP 249 if (!regcomp(&match_exp, regexp, REG_EXTENDED) && 250 !regexec(&match_exp, string, 1, &match_match, 0)) { 251 if ((match_match.rm_so == 0) && 252 (match_match.rm_eo == strlen(string))) 253 kret = 0; 254 } 255 regfree(&match_exp); 256 #elif HAVE_REGEXPR_H 257 compile(regexp, 258 regexp_buffer, 259 ®exp_buffer[RE_BUF_SIZE], 260 '\0'); 261 if (step(string, regexp_buffer)) { 262 if ((loc1 == string) && 263 (loc2 == &string[strlen(string)])) 264 kret = 0; 265 } 266 #elif HAVE_RE_COMP 267 if (!re_comp(regexp) && re_exec(string)) 268 kret = 0; 269 #else /* HAVE_RE_COMP */ 270 kret = 0; 271 #endif /* HAVE_RE_COMP */ 272 free(regexp); 273 } 274 endp++; 275 } 276 else 277 endp = startp; 278 } 279 *contextp = endp; 280 return(kret); 281 } 282 283 /* 284 * do_replacement() - Replace the regular expression with the specified 285 * replacement. 286 * 287 * If "doall" is set, it's a global replacement, otherwise, just a oneshot 288 * deal. 289 * If no regcomp() then just return the input string verbatim in the output 290 * string. 291 */ 292 #define use_bytes(x) \ 293 out_used += (x); \ 294 if (out_used > MAX_FORMAT_BUFFER) goto mem_err 295 296 static int 297 do_replacement(char *regexp, char *repl, int doall, char *in, char *out) 298 { 299 size_t out_used = 0; 300 #if HAVE_REGCOMP 301 regex_t match_exp; 302 regmatch_t match_match; 303 int matched; 304 char *cp; 305 char *op; 306 307 if (!regcomp(&match_exp, regexp, REG_EXTENDED)) { 308 cp = in; 309 op = out; 310 matched = 0; 311 do { 312 if (!regexec(&match_exp, cp, 1, &match_match, 0)) { 313 if (match_match.rm_so) { 314 use_bytes(match_match.rm_so); 315 strncpy(op, cp, match_match.rm_so); 316 op += match_match.rm_so; 317 } 318 use_bytes(strlen(repl)); 319 strncpy(op, repl, MAX_FORMAT_BUFFER - 1 - (op - out)); 320 op += strlen(op); 321 cp += match_match.rm_eo; 322 if (!doall) { 323 use_bytes(strlen(cp)); 324 strncpy(op, cp, MAX_FORMAT_BUFFER - 1 - (op - out)); 325 } 326 matched = 1; 327 } 328 else { 329 use_bytes(strlen(cp)); 330 strncpy(op, cp, MAX_FORMAT_BUFFER - 1 - (op - out)); 331 matched = 0; 332 } 333 } while (doall && matched); 334 regfree(&match_exp); 335 } 336 #elif HAVE_REGEXPR_H 337 int matched; 338 char *cp; 339 char *op; 340 char regexp_buffer[RE_BUF_SIZE]; 341 size_t sdispl, edispl; 342 343 compile(regexp, 344 regexp_buffer, 345 ®exp_buffer[RE_BUF_SIZE], 346 '\0'); 347 cp = in; 348 op = out; 349 matched = 0; 350 do { 351 if (step(cp, regexp_buffer)) { 352 sdispl = (size_t) (loc1 - cp); 353 edispl = (size_t) (loc2 - cp); 354 if (sdispl) { 355 use_bytes(sdispl); 356 strncpy(op, cp, sdispl); 357 op += sdispl; 358 } 359 use_bytes(strlen(repl)); 360 strncpy(op, repl, MAX_FORMAT_BUFFER - 1 - (op - out)); 361 op += strlen(repl); 362 cp += edispl; 363 if (!doall) { 364 use_bytes(strlen(cp)); 365 strncpy(op, cp, MAX_FORMAT_BUFFER - 1 - (op - out)); 366 } 367 matched = 1; 368 } 369 else { 370 use_bytes(strlen(cp)); 371 strncpy(op, cp, MAX_FORMAT_BUFFER - 1 - (op - out)); 372 matched = 0; 373 } 374 } while (doall && matched); 375 #else /* HAVE_REGEXP_H */ 376 memcpy(out, in, MAX_FORMAT_BUFFER); 377 #endif /* HAVE_REGCOMP */ 378 return 1; 379 mem_err: 380 #ifdef HAVE_REGCMP 381 regfree(&match_exp); 382 #endif 383 return 0; 384 385 } 386 #undef use_bytes 387 388 /* 389 * aname_replacer() - Perform the specified substitutions on the input 390 * string and return the result. 391 * 392 * This routine enforces the "s/<pattern>/<replacement>/[g]" syntax. 393 */ 394 static krb5_error_code 395 aname_replacer(char *string, char **contextp, char **result) 396 { 397 krb5_error_code kret; 398 char *in; 399 char *out; 400 char *cp, *ep, *tp; 401 char *rule, *repl; 402 size_t rule_size, repl_size; 403 int doglobal; 404 char sep; 405 406 kret = ENOMEM; 407 *result = (char *) NULL; 408 /* Allocate the formatting buffers */ 409 if (((in = (char *) malloc(MAX_FORMAT_BUFFER)) != NULL) && 410 ((out = (char *) malloc(MAX_FORMAT_BUFFER)) != NULL)) { 411 /* 412 * Prime the buffers. Copy input string to "out" to simulate it 413 * being the result of an initial iteration. 414 */ 415 strncpy(out, string, MAX_FORMAT_BUFFER - 1); 416 out[MAX_FORMAT_BUFFER - 1] = '\0'; 417 in[0] = '\0'; 418 kret = 0; 419 /* 420 * Pound through the expression until we're done. 421 */ 422 for (cp = *contextp; *cp; ) { 423 /* Skip leading whitespace */ 424 while (isspace(*cp)) 425 cp++; 426 427 /* 428 * Find our separators. First two characters must be "s<sep>" 429 * We must also find another "<sep>" followed by another * "<sep>". 430 */ 431 if (cp[0] != 's') { 432 /* Bad syntax */ 433 kret = KRB5_CONFIG_BADFORMAT; 434 break; 435 } 436 if (strspn(cp + 1, ",/;|!%") < 1) { 437 /* Bad syntax */ 438 kret = KRB5_CONFIG_BADFORMAT; 439 break; 440 } 441 sep = cp[1]; 442 443 if (((ep = strchr(&cp[2], sep)) != NULL) && 444 ((tp = strchr(&ep[1], sep)) != NULL)) { 445 446 /* Figure out sizes of strings and allocate them */ 447 rule_size = (size_t) (ep - &cp[2]); 448 repl_size = (size_t) (tp - &ep[1]); 449 if (((rule = (char *) malloc(rule_size+1)) != NULL) && 450 ((repl = (char *) malloc(repl_size+1)) != NULL)) { 451 452 /* Copy the strings */ 453 strncpy(rule, &cp[2], rule_size); 454 strncpy(repl, &ep[1], repl_size); 455 rule[rule_size] = repl[repl_size] = '\0'; 456 457 /* Check for trailing "g" */ 458 doglobal = (tp[1] == 'g') ? 1 : 0; 459 if (doglobal) 460 tp++; 461 462 /* Swap previous in and out buffers */ 463 ep = in; 464 in = out; 465 out = ep; 466 467 /* Do the replacemenbt */ 468 memset(out, '\0', MAX_FORMAT_BUFFER); 469 if (!do_replacement(rule, repl, doglobal, in, out)) { 470 free(rule); 471 free(repl); 472 kret = KRB5_LNAME_NOTRANS; 473 break; 474 } 475 free(rule); 476 free(repl); 477 478 /* If we have no output buffer left, this can't be good */ 479 if (strlen(out) == 0) { 480 kret = KRB5_LNAME_NOTRANS; 481 break; 482 } 483 } 484 else { 485 /* No memory for copies */ 486 kret = ENOMEM; 487 break; 488 } 489 } 490 else { 491 /* Bad syntax */ 492 kret = KRB5_CONFIG_BADFORMAT; 493 break; 494 } 495 /* Advance past trailer */ 496 cp = &tp[1]; 497 } 498 free(in); 499 if (!kret) 500 *result = out; 501 else 502 free(out); 503 } 504 return(kret); 505 } 506 507 /* 508 * rule_an_to_ln() - Handle aname to lname translations for RULE rules. 509 * 510 * The initial part of this routine handles the formulation of the strings from 511 * the principal name. 512 */ 513 static krb5_error_code 514 rule_an_to_ln(krb5_context context, char *rule, 515 krb5_const_principal aname, const int lnsize, char *lname) 516 { 517 krb5_error_code kret; 518 char *current; 519 char *fprincname; 520 char *selstring = 0; 521 int num_comps, compind; 522 size_t selstring_used; 523 char *cout; 524 krb5_const krb5_data *datap; 525 char *outstring; 526 527 /* 528 * First flatten the name. 529 */ 530 current = rule; 531 if (!(kret = krb5_unparse_name(context, aname, &fprincname))) { 532 /* 533 * First part. 534 */ 535 if (*current == '[') { 536 if (sscanf(current+1,"%d:", &num_comps) == 1) { 537 if (num_comps == aname->length) { 538 /* 539 * We have a match based on the number of components. 540 */ 541 current = strchr(current, ':'); 542 selstring = (char *) malloc(MAX_FORMAT_BUFFER); 543 selstring_used = 0; 544 if (current && selstring) { 545 current++; 546 cout = selstring; 547 /* 548 * Plow through the string. 549 */ 550 while ((*current != ']') && 551 (*current != '\0')) { 552 /* 553 * Expand to a component. 554 */ 555 if (*current == '$') { 556 if ((sscanf(current+1, "%d", &compind) == 1) && 557 (compind <= num_comps) && 558 (datap = (compind > 0) ? 559 krb5_princ_component(context, aname, compind-1) : 560 krb5_princ_realm(context, aname))) { 561 if ((datap->length < MAX_FORMAT_BUFFER) 562 && (selstring_used+datap->length 563 < MAX_FORMAT_BUFFER)) { 564 selstring_used += datap->length; 565 } else { 566 kret = ENOMEM; 567 goto errout; 568 } 569 strncpy(cout, 570 datap->data, 571 (unsigned) datap->length); 572 cout += datap->length; 573 *cout = '\0'; 574 current++; 575 /* Point past number */ 576 while (isdigit((int) *current)) 577 current++; 578 } 579 else 580 kret = KRB5_CONFIG_BADFORMAT; 581 } 582 else { 583 /* Copy in verbatim. */ 584 *cout = *current; 585 cout++; 586 *cout = '\0'; 587 current++; 588 } 589 } 590 591 /* 592 * Advance past separator if appropriate. 593 */ 594 if (*current == ']') 595 current++; 596 else 597 kret = KRB5_CONFIG_BADFORMAT; 598 599 errout: if (kret) 600 free(selstring); 601 } 602 } 603 else 604 kret = KRB5_LNAME_NOTRANS; 605 } 606 else 607 kret = KRB5_CONFIG_BADFORMAT; 608 } 609 else { 610 if (!(selstring = aname_full_to_mapping_name(fprincname))) 611 kret = ENOMEM; 612 } 613 krb5_xfree(fprincname); 614 } 615 if (!kret) { 616 /* 617 * Second part 618 */ 619 if (*current == '(') 620 kret = aname_do_match(selstring, ¤t); 621 622 /* 623 * Third part. 624 */ 625 if (!kret) { 626 outstring = (char *) NULL; 627 kret = aname_replacer(selstring, ¤t, &outstring); 628 if (outstring) { 629 /* Copy out the value if there's enough room */ 630 if (strlen(outstring)+1 <= (size_t) lnsize) 631 strcpy(lname, outstring); 632 else 633 kret = KRB5_CONFIG_NOTENUFSPACE; 634 free(outstring); 635 } 636 } 637 free(selstring); 638 } 639 640 return(kret); 641 } 642 #endif /* AN_TO_LN_RULES */ 643 644 /* 645 * Solaris Kerberos 646 * Return true (1) if the princ's realm matches any of the 647 * 'auth_to_local_realm' relations in the default realm section. 648 */ 649 static int 650 an_to_ln_realm_chk( 651 krb5_context context, 652 krb5_const_principal aname, 653 char *def_realm, 654 int realm_length) 655 { 656 char **values, **cpp; 657 const char *realm_names[4]; 658 krb5_error_code retval; 659 660 realm_names[0] = "realms"; 661 realm_names[1] = def_realm; 662 realm_names[2] = "auth_to_local_realm"; 663 realm_names[3] = 0; 664 665 if (context->profile == 0) 666 return (0); 667 668 retval = profile_get_values(context->profile, realm_names, 669 &values); 670 if (retval) 671 return (0); 672 673 for (cpp = values; *cpp; cpp++) { 674 675 if (((size_t) realm_length == strlen(*cpp)) && 676 (memcmp(*cpp, krb5_princ_realm(context, aname)->data, 677 realm_length) == 0)) { 678 679 profile_free_list(values); 680 return (1); /* success */ 681 } 682 } 683 684 profile_free_list(values); 685 return (0); 686 } 687 688 /* 689 * Implementation: This version checks the realm to see if it is the local 690 * realm; if so, and there is exactly one non-realm component to the name, 691 * that name is returned as the lname. 692 */ 693 static krb5_error_code 694 default_an_to_ln(krb5_context context, krb5_const_principal aname, 695 const int lnsize, char *lname) 696 { 697 krb5_error_code retval; 698 char *def_realm; 699 unsigned int realm_length; 700 701 realm_length = krb5_princ_realm(context, aname)->length; 702 703 704 if ((retval = krb5_get_default_realm(context, &def_realm))) { 705 return(retval); 706 } 707 708 /* compare against default realm and auth_to_local_realm(s) */ 709 if ((((size_t) realm_length != strlen(def_realm)) || 710 (memcmp(def_realm, krb5_princ_realm(context, aname)->data, 711 realm_length))) && 712 !an_to_ln_realm_chk(context, aname, def_realm, 713 realm_length)) { 714 free(def_realm); 715 return KRB5_LNAME_NOTRANS; 716 } 717 718 if (krb5_princ_size(context, aname) != 1) { 719 if (krb5_princ_size(context, aname) == 2 ) { 720 /* Check to see if 2nd component is the local realm. */ 721 if (strncmp(krb5_princ_component(context, aname, 1)->data, 722 def_realm, realm_length) || 723 realm_length != 724 krb5_princ_component(context, aname, 1)->length) { 725 /* XXX an_to_ln_realm_chk ? */ 726 free(def_realm); 727 return KRB5_LNAME_NOTRANS; 728 } 729 } 730 else { 731 /* no components or more than one component to non-realm part of name 732 --no translation. */ 733 free(def_realm); 734 return KRB5_LNAME_NOTRANS; 735 } 736 } 737 738 free(def_realm); 739 strncpy(lname, krb5_princ_component(context, aname,0)->data, 740 min(krb5_princ_component(context, aname,0)->length,lnsize)); 741 if (lnsize <= krb5_princ_component(context, aname,0)->length ) { 742 retval = KRB5_CONFIG_NOTENUFSPACE; 743 } else { 744 lname[krb5_princ_component(context, aname,0)->length] = '\0'; 745 retval = 0; 746 } 747 return retval; 748 } 749 750 /* 751 Converts an authentication name to a local name suitable for use by 752 programs wishing a translation to an environment-specific name (e.g. 753 user account name). 754 755 lnsize specifies the maximum length name that is to be filled into 756 lname. 757 The translation will be null terminated in all non-error returns. 758 759 returns system errors, NOT_ENOUGH_SPACE 760 */ 761 762 krb5_error_code 763 krb5_aname_to_localname(krb5_context context, 764 krb5_const_principal aname, const int lnsize_in, char *lname) 765 { 766 krb5_error_code kret; 767 char *realm; 768 char *pname; 769 char *mname; 770 const char *hierarchy[5]; 771 char **mapping_values; 772 int i, nvalid; 773 char *cp, *s; 774 char *typep, *argp; 775 unsigned int lnsize; 776 777 if (lnsize_in < 0) 778 return KRB5_CONFIG_NOTENUFSPACE; 779 780 lnsize = lnsize_in; /* Unsigned */ 781 782 /* 783 * First get the default realm. 784 */ 785 if (!(kret = krb5_get_default_realm(context, &realm))) { 786 /* Flatten the name */ 787 if (!(kret = krb5_unparse_name(context, aname, &pname))) { 788 if ((mname = aname_full_to_mapping_name(pname))) { 789 /* 790 * Search first for explicit mappings of the form: 791 * 792 * [realms]->realm->"auth_to_local_names"->mapping_name 793 */ 794 hierarchy[0] = "realms"; 795 hierarchy[1] = realm; 796 hierarchy[2] = "auth_to_local_names"; 797 hierarchy[3] = mname; 798 hierarchy[4] = (char *) NULL; 799 if (!(kret = profile_get_values(context->profile, 800 hierarchy, 801 &mapping_values))) { 802 /* We found one or more explicit mappings. */ 803 for (nvalid=0; mapping_values[nvalid]; nvalid++); 804 805 /* Just use the last one. */ 806 /* Trim the value. */ 807 s = mapping_values[nvalid-1]; 808 cp = s + strlen(s); 809 while (cp > s) { 810 cp--; 811 if (!isspace((int)(*cp))) 812 break; 813 *cp = '\0'; 814 } 815 816 /* Copy out the value if there's enough room */ 817 if (strlen(mapping_values[nvalid-1])+1 <= (size_t) lnsize) 818 strcpy(lname, mapping_values[nvalid-1]); 819 else 820 kret = KRB5_CONFIG_NOTENUFSPACE; 821 822 /* Free residue */ 823 profile_free_list(mapping_values); 824 } 825 else { 826 /* 827 * OK - There's no explicit mapping. Now check for 828 * general auth_to_local rules of the form: 829 * 830 * [realms]->realm->"auth_to_local" 831 * 832 * This can have one or more of the following kinds of 833 * values: 834 * DB:<filename> - Look up principal in aname database. 835 * RULE:<sed-exp> - Formulate lname from sed-exp. 836 * DEFAULT - Use default rule. 837 * The first rule to find a match is used. 838 */ 839 hierarchy[0] = "realms"; 840 hierarchy[1] = realm; 841 hierarchy[2] = "auth_to_local"; 842 hierarchy[3] = (char *) NULL; 843 if (!(kret = profile_get_values(context->profile, 844 hierarchy, 845 &mapping_values))) { 846 /* 847 * Loop through all the mapping values. 848 */ 849 for (i=0; mapping_values[i]; i++) { 850 typep = mapping_values[i]; 851 argp = strchr(typep, ':'); 852 if (argp) { 853 *argp = '\0'; 854 argp++; 855 } 856 #ifdef ANAME_DB 857 if (!strcmp(typep, "DB") && argp) { 858 kret = db_an_to_ln(context, 859 argp, 860 aname, 861 lnsize, 862 lname); 863 if (kret != KRB5_LNAME_NOTRANS) 864 break; 865 } 866 else 867 #endif 868 #ifdef AN_TO_LN_RULES 869 if (!strcmp(typep, "RULE") && argp) { 870 kret = rule_an_to_ln(context, 871 argp, 872 aname, 873 lnsize, 874 lname); 875 if (kret != KRB5_LNAME_NOTRANS) 876 break; 877 } 878 else 879 #endif /* AN_TO_LN_RULES */ 880 if (!strcmp(typep, "DEFAULT") && !argp) { 881 kret = default_an_to_ln(context, 882 aname, 883 lnsize, 884 lname); 885 if (kret != KRB5_LNAME_NOTRANS) 886 break; 887 } 888 else { 889 kret = KRB5_CONFIG_BADFORMAT; 890 break; 891 } 892 } 893 894 /* We're done, clean up the droppings. */ 895 profile_free_list(mapping_values); 896 } 897 else { 898 /* 899 * No profile relation found, try default mapping. 900 */ 901 kret = default_an_to_ln(context, 902 aname, 903 lnsize, 904 lname); 905 } 906 } 907 free(mname); 908 } 909 else 910 kret = ENOMEM; 911 krb5_xfree(pname); 912 } 913 krb5_xfree(realm); 914 } 915 return(kret); 916 } 917