1 /* 2 * Copyright 2005 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 return KRB5_LNAME_NOTRANS; 727 } 728 else 729 /* no components or more than one component to non-realm part of name 730 --no translation. */ 731 return KRB5_LNAME_NOTRANS; 732 } 733 734 free(def_realm); 735 strncpy(lname, krb5_princ_component(context, aname,0)->data, 736 min(krb5_princ_component(context, aname,0)->length,lnsize)); 737 if (lnsize <= krb5_princ_component(context, aname,0)->length ) { 738 retval = KRB5_CONFIG_NOTENUFSPACE; 739 } else { 740 lname[krb5_princ_component(context, aname,0)->length] = '\0'; 741 retval = 0; 742 } 743 return retval; 744 } 745 746 /* 747 Converts an authentication name to a local name suitable for use by 748 programs wishing a translation to an environment-specific name (e.g. 749 user account name). 750 751 lnsize specifies the maximum length name that is to be filled into 752 lname. 753 The translation will be null terminated in all non-error returns. 754 755 returns system errors, NOT_ENOUGH_SPACE 756 */ 757 758 krb5_error_code 759 krb5_aname_to_localname(krb5_context context, 760 krb5_const_principal aname, const int lnsize_in, char *lname) 761 { 762 krb5_error_code kret; 763 char *realm; 764 char *pname; 765 char *mname; 766 const char *hierarchy[5]; 767 char **mapping_values; 768 int i, nvalid; 769 char *cp, *s; 770 char *typep, *argp; 771 unsigned int lnsize; 772 773 if (lnsize_in < 0) 774 return KRB5_CONFIG_NOTENUFSPACE; 775 776 lnsize = lnsize_in; /* Unsigned */ 777 778 /* 779 * First get the default realm. 780 */ 781 if (!(kret = krb5_get_default_realm(context, &realm))) { 782 /* Flatten the name */ 783 if (!(kret = krb5_unparse_name(context, aname, &pname))) { 784 if ((mname = aname_full_to_mapping_name(pname))) { 785 /* 786 * Search first for explicit mappings of the form: 787 * 788 * [realms]->realm->"auth_to_local_names"->mapping_name 789 */ 790 hierarchy[0] = "realms"; 791 hierarchy[1] = realm; 792 hierarchy[2] = "auth_to_local_names"; 793 hierarchy[3] = mname; 794 hierarchy[4] = (char *) NULL; 795 if (!(kret = profile_get_values(context->profile, 796 hierarchy, 797 &mapping_values))) { 798 /* We found one or more explicit mappings. */ 799 for (nvalid=0; mapping_values[nvalid]; nvalid++); 800 801 /* Just use the last one. */ 802 /* Trim the value. */ 803 s = mapping_values[nvalid-1]; 804 cp = s + strlen(s); 805 while (cp > s) { 806 cp--; 807 if (!isspace((int)(*cp))) 808 break; 809 *cp = '\0'; 810 } 811 812 /* Copy out the value if there's enough room */ 813 if (strlen(mapping_values[nvalid-1])+1 <= (size_t) lnsize) 814 strcpy(lname, mapping_values[nvalid-1]); 815 else 816 kret = KRB5_CONFIG_NOTENUFSPACE; 817 818 /* Free residue */ 819 profile_free_list(mapping_values); 820 } 821 else { 822 /* 823 * OK - There's no explicit mapping. Now check for 824 * general auth_to_local rules of the form: 825 * 826 * [realms]->realm->"auth_to_local" 827 * 828 * This can have one or more of the following kinds of 829 * values: 830 * DB:<filename> - Look up principal in aname database. 831 * RULE:<sed-exp> - Formulate lname from sed-exp. 832 * DEFAULT - Use default rule. 833 * The first rule to find a match is used. 834 */ 835 hierarchy[0] = "realms"; 836 hierarchy[1] = realm; 837 hierarchy[2] = "auth_to_local"; 838 hierarchy[3] = (char *) NULL; 839 if (!(kret = profile_get_values(context->profile, 840 hierarchy, 841 &mapping_values))) { 842 /* 843 * Loop through all the mapping values. 844 */ 845 for (i=0; mapping_values[i]; i++) { 846 typep = mapping_values[i]; 847 argp = strchr(typep, ':'); 848 if (argp) { 849 *argp = '\0'; 850 argp++; 851 } 852 #ifdef ANAME_DB 853 if (!strcmp(typep, "DB") && argp) { 854 kret = db_an_to_ln(context, 855 argp, 856 aname, 857 lnsize, 858 lname); 859 if (kret != KRB5_LNAME_NOTRANS) 860 break; 861 } 862 else 863 #endif 864 #ifdef AN_TO_LN_RULES 865 if (!strcmp(typep, "RULE") && argp) { 866 kret = rule_an_to_ln(context, 867 argp, 868 aname, 869 lnsize, 870 lname); 871 if (kret != KRB5_LNAME_NOTRANS) 872 break; 873 } 874 else 875 #endif /* AN_TO_LN_RULES */ 876 if (!strcmp(typep, "DEFAULT") && !argp) { 877 kret = default_an_to_ln(context, 878 aname, 879 lnsize, 880 lname); 881 if (kret != KRB5_LNAME_NOTRANS) 882 break; 883 } 884 else { 885 kret = KRB5_CONFIG_BADFORMAT; 886 break; 887 } 888 } 889 890 /* We're done, clean up the droppings. */ 891 profile_free_list(mapping_values); 892 } 893 else { 894 /* 895 * No profile relation found, try default mapping. 896 */ 897 kret = default_an_to_ln(context, 898 aname, 899 lnsize, 900 lname); 901 } 902 } 903 free(mname); 904 } 905 else 906 kret = ENOMEM; 907 krb5_xfree(pname); 908 } 909 krb5_xfree(realm); 910 } 911 return(kret); 912 } 913