xref: /freebsd/crypto/heimdal/lib/krb5/principal.c (revision b528cefc6b8f9670b31a865051741d946cb37085)
1 /*
2  * Copyright (c) 1997-1999 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "krb5_locl.h"
35 #ifdef HAVE_RES_SEARCH
36 #define USE_RESOLVER
37 #endif
38 #ifdef HAVE_ARPA_NAMESER_H
39 #include <arpa/nameser.h>
40 #endif
41 #include "resolve.h"
42 
43 RCSID("$Id: principal.c,v 1.57 2000/01/08 08:08:03 assar Exp $");
44 
45 #define princ_num_comp(P) ((P)->name.name_string.len)
46 #define princ_type(P) ((P)->name.name_type)
47 #define princ_comp(P) ((P)->name.name_string.val)
48 #define princ_ncomp(P, N) ((P)->name.name_string.val[(N)])
49 #define princ_realm(P) ((P)->realm)
50 
51 void
52 krb5_free_principal(krb5_context context,
53 		    krb5_principal p)
54 {
55     if(p){
56 	free_Principal(p);
57 	free(p);
58     }
59 }
60 
61 krb5_error_code
62 krb5_parse_name(krb5_context context,
63 		const char *name,
64 		krb5_principal *principal)
65 {
66     krb5_error_code ret;
67     general_string *comp;
68     general_string realm;
69     int ncomp;
70 
71     char *p;
72     char *q;
73     char *s;
74     char *start;
75 
76     int n;
77     char c;
78     int got_realm = 0;
79 
80     /* count number of component */
81     ncomp = 1;
82     for(p = (char*)name; *p; p++){
83 	if(*p=='\\'){
84 	    if(!p[1])
85 		return KRB5_PARSE_MALFORMED;
86 	    p++;
87 	} else if(*p == '/')
88 	    ncomp++;
89     }
90     comp = calloc(ncomp, sizeof(*comp));
91     if (comp == NULL)
92 	return ENOMEM;
93 
94     n = 0;
95     start = q = p = s = strdup(name);
96     if (start == NULL) {
97 	free (comp);
98 	return ENOMEM;
99     }
100     while(*p){
101 	c = *p++;
102 	if(c == '\\'){
103 	    c = *p++;
104 	    if(c == 'n')
105 		c = '\n';
106 	    else if(c == 't')
107 		c = '\t';
108 	    else if(c == 'b')
109 		c = '\b';
110 	    else if(c == '0')
111 		c = '\0';
112 	}else if(c == '/' || c == '@'){
113 	    if(got_realm){
114 		ret = KRB5_PARSE_MALFORMED;
115 		goto exit;
116 	    }else{
117 		comp[n] = malloc(q - start + 1);
118 		if (comp[n] == NULL) {
119 		    ret = ENOMEM;
120 		    goto exit;
121 		}
122 		strncpy(comp[n], start, q - start);
123 		comp[n][q - start] = 0;
124 		n++;
125 	    }
126 	    if(c == '@')
127 		got_realm = 1;
128 	    start = q;
129 	    continue;
130 	}
131 	if(got_realm && (c == ':' || c == '/' || c == '\0')) {
132 	    ret = KRB5_PARSE_MALFORMED;
133 	    goto exit;
134 	}
135 	*q++ = c;
136     }
137     if(got_realm){
138 	realm = malloc(q - start + 1);
139 	if (realm == NULL) {
140 	    ret = ENOMEM;
141 	    goto exit;
142 	}
143 	strncpy(realm, start, q - start);
144 	realm[q - start] = 0;
145     }else{
146 	ret = krb5_get_default_realm (context, &realm);
147 	if (ret)
148 	    goto exit;
149 
150 	comp[n] = malloc(q - start + 1);
151 	if (comp[n] == NULL) {
152 	    ret = ENOMEM;
153 	    goto exit;
154 	}
155 	strncpy(comp[n], start, q - start);
156 	comp[n][q - start] = 0;
157 	n++;
158     }
159     *principal = malloc(sizeof(**principal));
160     if (*principal == NULL) {
161 	ret = ENOMEM;
162 	goto exit;
163     }
164     (*principal)->name.name_type = KRB5_NT_PRINCIPAL;
165     (*principal)->name.name_string.val = comp;
166     princ_num_comp(*principal) = n;
167     (*principal)->realm = realm;
168     free(s);
169     return 0;
170 exit:
171     while(n>0){
172 	free(comp[--n]);
173     }
174     free(comp);
175     free(s);
176     return ret;
177 }
178 
179 static const char quotable_chars[] = "\n\t\b\\/@";
180 static const char replace_chars[] = "ntb\\/@";
181 
182 #define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0);
183 
184 static size_t
185 quote_string(const char *s, char *out, size_t index, size_t len)
186 {
187     const char *p, *q;
188     for(p = s; *p && index < len; p++){
189 	if((q = strchr(quotable_chars, *p))){
190 	    add_char(out, index, len, '\\');
191 	    add_char(out, index, len, replace_chars[q - quotable_chars]);
192 	}else
193 	    add_char(out, index, len, *p);
194     }
195     if(index < len)
196 	out[index] = '\0';
197     return index;
198 }
199 
200 
201 static krb5_error_code
202 unparse_name_fixed(krb5_context context,
203 		   krb5_const_principal principal,
204 		   char *name,
205 		   size_t len,
206 		   krb5_boolean short_form)
207 {
208     size_t index = 0;
209     int i;
210     for(i = 0; i < princ_num_comp(principal); i++){
211 	if(i)
212 	    add_char(name, index, len, '/');
213 	index = quote_string(princ_ncomp(principal, i), name, index, len);
214 	if(index == len)
215 	    return ERANGE;
216     }
217     /* add realm if different from default realm */
218     if(short_form) {
219 	krb5_realm r;
220 	krb5_error_code ret;
221 	ret = krb5_get_default_realm(context, &r);
222 	if(ret)
223 	    return ret;
224 	if(strcmp(princ_realm(principal), r) != 0)
225 	    short_form = 0;
226 	free(r);
227     }
228     if(!short_form) {
229 	add_char(name, index, len, '@');
230 	index = quote_string(princ_realm(principal), name, index, len);
231 	if(index == len)
232 	    return ERANGE;
233     }
234     return 0;
235 }
236 
237 krb5_error_code
238 krb5_unparse_name_fixed(krb5_context context,
239 			krb5_const_principal principal,
240 			char *name,
241 			size_t len)
242 {
243     return unparse_name_fixed(context, principal, name, len, FALSE);
244 }
245 
246 krb5_error_code
247 krb5_unparse_name_fixed_short(krb5_context context,
248 			      krb5_const_principal principal,
249 			      char *name,
250 			      size_t len)
251 {
252     return unparse_name_fixed(context, principal, name, len, TRUE);
253 }
254 
255 static krb5_error_code
256 unparse_name(krb5_context context,
257 	     krb5_const_principal principal,
258 	     char **name,
259 	     krb5_boolean short_flag)
260 {
261     size_t len = 0, plen;
262     int i;
263     krb5_error_code ret;
264     /* count length */
265     plen = strlen(princ_realm(principal));
266     if(strcspn(princ_realm(principal), quotable_chars) == plen)
267 	len += plen;
268     else
269 	len += 2*plen;
270     len++;
271     for(i = 0; i < princ_num_comp(principal); i++){
272 	plen = strlen(princ_ncomp(principal, i));
273 	if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen)
274 	    len += plen;
275 	else
276 	    len += 2*plen;
277 	len++;
278     }
279     *name = malloc(len);
280     if(len != 0 && *name == NULL)
281 	return ENOMEM;
282     ret = unparse_name_fixed(context, principal, *name, len, short_flag);
283     if(ret)
284 	free(*name);
285     return ret;
286 }
287 
288 krb5_error_code
289 krb5_unparse_name(krb5_context context,
290 		  krb5_const_principal principal,
291 		  char **name)
292 {
293     return unparse_name(context, principal, name, FALSE);
294 }
295 
296 krb5_error_code
297 krb5_unparse_name_short(krb5_context context,
298 			krb5_const_principal principal,
299 			char **name)
300 {
301     return unparse_name(context, principal, name, TRUE);
302 }
303 
304 #if 0 /* not implemented */
305 
306 krb5_error_code
307 krb5_unparse_name_ext(krb5_context context,
308 		      krb5_const_principal principal,
309 		      char **name,
310 		      size_t *size)
311 {
312     krb5_abortx(context, "unimplemented krb5_unparse_name_ext called");
313 }
314 
315 #endif
316 
317 krb5_realm*
318 krb5_princ_realm(krb5_context context,
319 		 krb5_principal principal)
320 {
321     return &princ_realm(principal);
322 }
323 
324 
325 void
326 krb5_princ_set_realm(krb5_context context,
327 		     krb5_principal principal,
328 		     krb5_realm *realm)
329 {
330     princ_realm(principal) = *realm;
331 }
332 
333 
334 krb5_error_code
335 krb5_build_principal(krb5_context context,
336 		     krb5_principal *principal,
337 		     int rlen,
338 		     krb5_const_realm realm,
339 		     ...)
340 {
341     krb5_error_code ret;
342     va_list ap;
343     va_start(ap, realm);
344     ret = krb5_build_principal_va(context, principal, rlen, realm, ap);
345     va_end(ap);
346     return ret;
347 }
348 
349 static krb5_error_code
350 append_component(krb5_context context, krb5_principal p,
351 		 general_string comp,
352 		 size_t comp_len)
353 {
354     general_string *tmp;
355     size_t len = princ_num_comp(p);
356     tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp));
357     if(tmp == NULL)
358 	return ENOMEM;
359     princ_comp(p) = tmp;
360     princ_ncomp(p, len) = malloc(comp_len + 1);
361     memcpy (princ_ncomp(p, len), comp, comp_len);
362     princ_ncomp(p, len)[comp_len] = '\0';
363     princ_num_comp(p)++;
364     return 0;
365 }
366 
367 static void
368 va_ext_princ(krb5_context context, krb5_principal p, va_list ap)
369 {
370     while(1){
371 	char *s;
372 	int len;
373 	len = va_arg(ap, int);
374 	if(len == 0)
375 	    break;
376 	s = va_arg(ap, char*);
377 	append_component(context, p, s, len);
378     }
379 }
380 
381 static void
382 va_princ(krb5_context context, krb5_principal p, va_list ap)
383 {
384     while(1){
385 	char *s;
386 	s = va_arg(ap, char*);
387 	if(s == NULL)
388 	    break;
389 	append_component(context, p, s, strlen(s));
390     }
391 }
392 
393 
394 static krb5_error_code
395 build_principal(krb5_context context,
396 		krb5_principal *principal,
397 		int rlen,
398 		krb5_const_realm realm,
399 		void (*func)(krb5_context, krb5_principal, va_list),
400 		va_list ap)
401 {
402     krb5_principal p;
403 
404     p = calloc(1, sizeof(*p));
405     if (p == NULL)
406 	return ENOMEM;
407     princ_type(p) = KRB5_NT_PRINCIPAL;
408 
409     princ_realm(p) = strdup(realm);
410     if(p->realm == NULL){
411 	free(p);
412 	return ENOMEM;
413     }
414 
415     (*func)(context, p, ap);
416     *principal = p;
417     return 0;
418 }
419 
420 krb5_error_code
421 krb5_make_principal(krb5_context context,
422 		    krb5_principal *principal,
423 		    krb5_const_realm realm,
424 		    ...)
425 {
426     krb5_error_code ret;
427     krb5_realm r = NULL;
428     va_list ap;
429     if(realm == NULL) {
430 	ret = krb5_get_default_realm(context, &r);
431 	if(ret)
432 	    return ret;
433 	realm = r;
434     }
435     va_start(ap, realm);
436     ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap);
437     va_end(ap);
438     if(r)
439 	free(r);
440     return ret;
441 }
442 
443 krb5_error_code
444 krb5_build_principal_va(krb5_context context,
445 			krb5_principal *principal,
446 			int rlen,
447 			krb5_const_realm realm,
448 			va_list ap)
449 {
450     return build_principal(context, principal, rlen, realm, va_princ, ap);
451 }
452 
453 krb5_error_code
454 krb5_build_principal_va_ext(krb5_context context,
455 			    krb5_principal *principal,
456 			    int rlen,
457 			    krb5_const_realm realm,
458 			    va_list ap)
459 {
460     return build_principal(context, principal, rlen, realm, va_ext_princ, ap);
461 }
462 
463 
464 krb5_error_code
465 krb5_build_principal_ext(krb5_context context,
466 			 krb5_principal *principal,
467 			 int rlen,
468 			 krb5_const_realm realm,
469 			 ...)
470 {
471     krb5_error_code ret;
472     va_list ap;
473     va_start(ap, realm);
474     ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap);
475     va_end(ap);
476     return ret;
477 }
478 
479 
480 krb5_error_code
481 krb5_copy_principal(krb5_context context,
482 		    krb5_const_principal inprinc,
483 		    krb5_principal *outprinc)
484 {
485     krb5_principal p = malloc(sizeof(*p));
486     if (p == NULL)
487 	return ENOMEM;
488     if(copy_Principal(inprinc, p))
489 	return ENOMEM;
490     *outprinc = p;
491     return 0;
492 }
493 
494 
495 krb5_boolean
496 krb5_principal_compare_any_realm(krb5_context context,
497 				 krb5_const_principal princ1,
498 				 krb5_const_principal princ2)
499 {
500     int i;
501     if(princ_num_comp(princ1) != princ_num_comp(princ2))
502 	return FALSE;
503     for(i = 0; i < princ_num_comp(princ1); i++){
504 	if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0)
505 	    return FALSE;
506     }
507     return TRUE;
508 }
509 
510 krb5_boolean
511 krb5_principal_compare(krb5_context context,
512 		       krb5_const_principal princ1,
513 		       krb5_const_principal princ2)
514 {
515     if(!krb5_realm_compare(context, princ1, princ2))
516 	return FALSE;
517     return krb5_principal_compare_any_realm(context, princ1, princ2);
518 }
519 
520 
521 krb5_boolean
522 krb5_realm_compare(krb5_context context,
523 		   krb5_const_principal princ1,
524 		   krb5_const_principal princ2)
525 {
526     return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0;
527 }
528 
529 struct v4_name_convert {
530     const char *from;
531     const char *to;
532 } default_v4_name_convert[] = {
533     { "ftp", "ftp" },
534     { "hprop", "hprop" },
535     { "pop", "pop" },
536     { "rcmd", "host" },
537     { NULL, NULL }
538 };
539 
540 static const char*
541 get_name_conversion(krb5_context context, const char *realm, const char *name)
542 {
543     struct v4_name_convert *q;
544     const char *p;
545     p = krb5_config_get_string(context, NULL, "realms", realm,
546 			       "v4_name_convert", "host", name, NULL);
547     if(p == NULL)
548 	p = krb5_config_get_string(context, NULL, "libdefaults",
549 				   "v4_name_convert", "host", name, NULL);
550     if(p)
551 	return p;
552 
553     /* XXX should be possible to override default list */
554     p = krb5_config_get_string(context, NULL,
555 			       "realms",
556 			       realm,
557 			       "v4_name_convert",
558 			       "plain",
559 			       name,
560 			       NULL);
561     if(p)
562 	return NULL;
563     p = krb5_config_get_string(context, NULL,
564 			       "libdefaults",
565 			       "v4_name_convert",
566 			       "plain",
567 			       name,
568 			       NULL);
569     if(p)
570 	return NULL;
571     for(q = default_v4_name_convert; q->from; q++)
572 	if(strcmp(q->from, name) == 0)
573 	    return q->to;
574     return NULL;
575 }
576 
577 krb5_error_code
578 krb5_425_conv_principal_ext(krb5_context context,
579 			    const char *name,
580 			    const char *instance,
581 			    const char *realm,
582 			    krb5_boolean (*func)(krb5_context, krb5_principal),
583 			    krb5_boolean resolve,
584 			    krb5_principal *princ)
585 {
586     const char *p;
587     krb5_error_code ret;
588     krb5_principal pr;
589     char host[128];
590 
591     /* do the following: if the name is found in the
592        `v4_name_convert:host' part, is is assumed to be a `host' type
593        principal, and the instance is looked up in the
594        `v4_instance_convert' part. if not found there the name is
595        (optionally) looked up as a hostname, and if that doesn't yield
596        anything, the `default_domain' is appended to the instance
597        */
598 
599     if(instance == NULL)
600 	goto no_host;
601     if(instance[0] == 0){
602 	instance = NULL;
603 	goto no_host;
604     }
605     p = get_name_conversion(context, realm, name);
606     if(p == NULL)
607 	goto no_host;
608     name = p;
609     p = krb5_config_get_string(context, NULL, "realms", realm,
610 			       "v4_instance_convert", instance, NULL);
611     if(p){
612 	instance = p;
613 	ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
614 	if(func == NULL || (*func)(context, pr)){
615 	    *princ = pr;
616 	    return 0;
617 	}
618 	krb5_free_principal(context, pr);
619 	*princ = NULL;
620 	return HEIM_ERR_V4_PRINC_NO_CONV;
621     }
622     if(resolve){
623 	const char *inst = NULL;
624 #ifdef USE_RESOLVER
625 	struct dns_reply *r;
626 	r = dns_lookup(instance, "a");
627 	if(r && r->head && r->head->type == T_A)
628 	    inst = r->head->domain;
629 #else
630 	struct hostent *hp = roken_gethostbyname(instance);
631 	if(hp)
632 	    inst = hp->h_name;
633 #endif
634 	if(inst) {
635 	    ret = krb5_make_principal(context, &pr, realm, name, inst, NULL);
636 	    if(ret == 0) {
637 		if(func == NULL || (*func)(context, pr)){
638 		    *princ = pr;
639 #ifdef USE_RESOLVER
640 		    dns_free_data(r);
641 #endif
642 		    return 0;
643 		}
644 		krb5_free_principal(context, pr);
645 	    }
646 	}
647 #ifdef USE_RESOLVER
648 	if(r)
649 	    dns_free_data(r);
650 #endif
651     }
652     {
653 	char **domains, **d;
654 	domains = krb5_config_get_strings(context, NULL, "realms", realm,
655 					  "v4_domains", NULL);
656 	for(d = domains; d && *d; d++){
657 	    snprintf(host, sizeof(host), "%s.%s", instance, *d);
658 	    ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
659 	    if(func == NULL || (*func)(context, pr)){
660 		*princ = pr;
661 		krb5_config_free_strings(domains);
662 		return 0;
663 	    }
664 	    krb5_free_principal(context, pr);
665 	}
666 	krb5_config_free_strings(domains);
667     }
668 
669 
670     p = krb5_config_get_string(context, NULL, "realms", realm,
671 			       "default_domain", NULL);
672     if(p == NULL){
673 	/* should this be an error or should it silently
674 	   succeed? */
675 	return HEIM_ERR_V4_PRINC_NO_CONV;
676     }
677 
678     if (*p == '.')
679 	++p;
680     snprintf(host, sizeof(host), "%s.%s", instance, p);
681     ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
682     if(func == NULL || (*func)(context, pr)){
683 	*princ = pr;
684 	return 0;
685     }
686     krb5_free_principal(context, pr);
687     return HEIM_ERR_V4_PRINC_NO_CONV;
688 no_host:
689     p = krb5_config_get_string(context, NULL,
690 			       "realms",
691 			       realm,
692 			       "v4_name_convert",
693 			       "plain",
694 			       name,
695 			       NULL);
696     if(p == NULL)
697 	p = krb5_config_get_string(context, NULL,
698 				   "libdefaults",
699 				   "v4_name_convert",
700 				   "plain",
701 				   name,
702 				   NULL);
703     if(p)
704 	name = p;
705 
706     ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
707     if(func == NULL || (*func)(context, pr)){
708 	*princ = pr;
709 	return 0;
710     }
711     krb5_free_principal(context, pr);
712     return HEIM_ERR_V4_PRINC_NO_CONV;
713 }
714 
715 krb5_error_code
716 krb5_425_conv_principal(krb5_context context,
717 			const char *name,
718 			const char *instance,
719 			const char *realm,
720 			krb5_principal *princ)
721 {
722     krb5_boolean resolve = krb5_config_get_bool(context,
723 						NULL,
724 						"libdefaults",
725 						"v4_instance_resolve",
726 						NULL);
727 
728     return krb5_425_conv_principal_ext(context, name, instance, realm,
729 				       NULL, resolve, princ);
730 }
731 
732 
733 static int
734 check_list(const krb5_config_binding *l, const char *name, const char **out)
735 {
736     while(l){
737 	if (l->type != krb5_config_string)
738 	    continue;
739 	if(strcmp(name, l->u.string) == 0) {
740 	    *out = l->name;
741 	    return 1;
742 	}
743 	l = l->next;
744     }
745     return 0;
746 }
747 
748 static int
749 name_convert(krb5_context context, const char *name, const char *realm,
750 	     const char **out)
751 {
752     const krb5_config_binding *l;
753     l = krb5_config_get_list (context,
754 			      NULL,
755 			      "realms",
756 			      realm,
757 			      "v4_name_convert",
758 			      "host",
759 			      NULL);
760     if(l && check_list(l, name, out))
761 	return KRB5_NT_SRV_HST;
762     l = krb5_config_get_list (context,
763 			      NULL,
764 			      "libdefaults",
765 			      "v4_name_convert",
766 			      "host",
767 			      NULL);
768     if(l && check_list(l, name, out))
769 	return KRB5_NT_SRV_HST;
770     l = krb5_config_get_list (context,
771 			      NULL,
772 			      "realms",
773 			      realm,
774 			      "v4_name_convert",
775 			      "plain",
776 			      NULL);
777     if(l && check_list(l, name, out))
778 	return KRB5_NT_UNKNOWN;
779     l = krb5_config_get_list (context,
780 			      NULL,
781 			      "libdefaults",
782 			      "v4_name_convert",
783 			      "host",
784 			      NULL);
785     if(l && check_list(l, name, out))
786 	return KRB5_NT_UNKNOWN;
787 
788     /* didn't find it in config file, try built-in list */
789     {
790 	struct v4_name_convert *q;
791 	for(q = default_v4_name_convert; q->from; q++) {
792 	    if(strcmp(name, q->to) == 0) {
793 		*out = q->from;
794 		return KRB5_NT_SRV_HST;
795 	    }
796 	}
797     }
798     return -1;
799 }
800 
801 krb5_error_code
802 krb5_524_conv_principal(krb5_context context,
803 			const krb5_principal principal,
804 			char *name,
805 			char *instance,
806 			char *realm)
807 {
808     const char *n, *i, *r;
809     char tmpinst[40];
810     int type = princ_type(principal);
811 
812     r = principal->realm;
813 
814     switch(principal->name.name_string.len){
815     case 1:
816 	n = principal->name.name_string.val[0];
817 	i = "";
818 	break;
819     case 2:
820 	n = principal->name.name_string.val[0];
821 	i = principal->name.name_string.val[1];
822 	break;
823     default:
824 	return KRB5_PARSE_MALFORMED;
825     }
826 
827     {
828 	const char *tmp;
829 	int t = name_convert(context, n, r, &tmp);
830 	if(t >= 0) {
831 	    type = t;
832 	    n = tmp;
833 	}
834     }
835 
836     if(type == KRB5_NT_SRV_HST){
837 	char *p;
838 	strncpy(tmpinst, i, sizeof(tmpinst));
839 	tmpinst[sizeof(tmpinst) - 1] = 0;
840 	p = strchr(tmpinst, '.');
841 	if(p) *p = 0;
842 	i = tmpinst;
843     }
844 
845     if(strlen(r) >= 40)
846 	return KRB5_PARSE_MALFORMED;
847     if(strlen(n) >= 40)
848 	return KRB5_PARSE_MALFORMED;
849     if(strlen(i) >= 40)
850 	return KRB5_PARSE_MALFORMED;
851     strcpy(realm, r);
852     strcpy(name, n);
853     strcpy(instance, i);
854     return 0;
855 }
856 
857 /*
858  * Create a principal in `ret_princ' for the service `sname' running
859  * on host `hostname'.
860  */
861 
862 krb5_error_code
863 krb5_sname_to_principal (krb5_context context,
864 			 const char *hostname,
865 			 const char *sname,
866 			 int32_t type,
867 			 krb5_principal *ret_princ)
868 {
869     krb5_error_code ret;
870     char localhost[128];
871     char **realms, *host = NULL;
872 
873     if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN)
874 	return KRB5_SNAME_UNSUPP_NAMETYPE;
875     if(hostname == NULL) {
876 	gethostname(localhost, sizeof(localhost));
877 	hostname = localhost;
878     }
879     if(sname == NULL)
880 	sname = "host";
881     if(type == KRB5_NT_SRV_HST) {
882 	ret = krb5_expand_hostname (context, hostname, &host);
883 	if (ret)
884 	    return ret;
885 	strlwr(host);
886 	hostname = host;
887     }
888     ret = krb5_get_host_realm(context, hostname, &realms);
889     if(ret)
890 	return ret;
891 
892     ret = krb5_make_principal(context, ret_princ, realms[0], sname,
893 			      hostname, NULL);
894     if(host)
895 	free(host);
896     krb5_free_host_realm(context, realms);
897     return ret;
898 }
899