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