155682Smarkm/*
2178825Sdfr * Copyright (c) 1997-2007 Kungliga Tekniska H�gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
555682Smarkm *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "krb5_locl.h"
3555682Smarkm#ifdef HAVE_RES_SEARCH
3655682Smarkm#define USE_RESOLVER
3755682Smarkm#endif
3855682Smarkm#ifdef HAVE_ARPA_NAMESER_H
3955682Smarkm#include <arpa/nameser.h>
4055682Smarkm#endif
4172445Sassar#include <fnmatch.h>
4255682Smarkm#include "resolve.h"
4355682Smarkm
44178825SdfrRCSID("$Id: principal.c 21741 2007-07-31 16:00:37Z lha $");
4555682Smarkm
4655682Smarkm#define princ_num_comp(P) ((P)->name.name_string.len)
4755682Smarkm#define princ_type(P) ((P)->name.name_type)
4855682Smarkm#define princ_comp(P) ((P)->name.name_string.val)
4955682Smarkm#define princ_ncomp(P, N) ((P)->name.name_string.val[(N)])
5055682Smarkm#define princ_realm(P) ((P)->realm)
5155682Smarkm
52178825Sdfrvoid KRB5_LIB_FUNCTION
5355682Smarkmkrb5_free_principal(krb5_context context,
5455682Smarkm		    krb5_principal p)
5555682Smarkm{
5655682Smarkm    if(p){
5755682Smarkm	free_Principal(p);
5855682Smarkm	free(p);
5955682Smarkm    }
6055682Smarkm}
6155682Smarkm
62178825Sdfrvoid KRB5_LIB_FUNCTION
63178825Sdfrkrb5_principal_set_type(krb5_context context,
64178825Sdfr			krb5_principal principal,
65178825Sdfr			int type)
66178825Sdfr{
67178825Sdfr    princ_type(principal) = type;
68178825Sdfr}
69178825Sdfr
70178825Sdfrint KRB5_LIB_FUNCTION
7190926Snectarkrb5_principal_get_type(krb5_context context,
72178825Sdfr			krb5_const_principal principal)
7390926Snectar{
7490926Snectar    return princ_type(principal);
7590926Snectar}
7690926Snectar
77178825Sdfrconst char* KRB5_LIB_FUNCTION
7890926Snectarkrb5_principal_get_realm(krb5_context context,
79178825Sdfr			 krb5_const_principal principal)
8090926Snectar{
8190926Snectar    return princ_realm(principal);
8290926Snectar}
8390926Snectar
84178825Sdfrconst char* KRB5_LIB_FUNCTION
8590926Snectarkrb5_principal_get_comp_string(krb5_context context,
86178825Sdfr			       krb5_const_principal principal,
8790926Snectar			       unsigned int component)
8890926Snectar{
8990926Snectar    if(component >= princ_num_comp(principal))
9090926Snectar       return NULL;
9190926Snectar    return princ_ncomp(principal, component);
9290926Snectar}
9390926Snectar
94178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
95178825Sdfrkrb5_parse_name_flags(krb5_context context,
96178825Sdfr		      const char *name,
97178825Sdfr		      int flags,
98178825Sdfr		      krb5_principal *principal)
9955682Smarkm{
10055682Smarkm    krb5_error_code ret;
101178825Sdfr    heim_general_string *comp;
102178825Sdfr    heim_general_string realm = NULL;
10355682Smarkm    int ncomp;
10455682Smarkm
105102644Snectar    const char *p;
10655682Smarkm    char *q;
10755682Smarkm    char *s;
10855682Smarkm    char *start;
10955682Smarkm
11055682Smarkm    int n;
11155682Smarkm    char c;
11255682Smarkm    int got_realm = 0;
113178825Sdfr    int first_at = 1;
114178825Sdfr    int enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE);
11555682Smarkm
116178825Sdfr    *principal = NULL;
117178825Sdfr
118178825Sdfr#define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_MUST_REALM)
119178825Sdfr
120178825Sdfr    if ((flags & RFLAGS) == RFLAGS) {
121178825Sdfr	krb5_set_error_string(context, "Can't require both realm and "
122178825Sdfr			      "no realm at the same time");
123178825Sdfr	return KRB5_ERR_NO_SERVICE;
124178825Sdfr    }
125178825Sdfr#undef RFLAGS
126178825Sdfr
127178825Sdfr    /* count number of component,
128178825Sdfr     * enterprise names only have one component
129178825Sdfr     */
13055682Smarkm    ncomp = 1;
131178825Sdfr    if (!enterprise) {
132178825Sdfr	for(p = name; *p; p++){
133178825Sdfr	    if(*p=='\\'){
134178825Sdfr		if(!p[1]) {
135178825Sdfr		    krb5_set_error_string (context,
136178825Sdfr					   "trailing \\ in principal name");
137178825Sdfr		    return KRB5_PARSE_MALFORMED;
138178825Sdfr		}
139178825Sdfr		p++;
140178825Sdfr	    } else if(*p == '/')
141178825Sdfr		ncomp++;
142178825Sdfr	    else if(*p == '@')
143178825Sdfr		break;
144178825Sdfr	}
14555682Smarkm    }
14655682Smarkm    comp = calloc(ncomp, sizeof(*comp));
14778527Sassar    if (comp == NULL) {
14878527Sassar	krb5_set_error_string (context, "malloc: out of memory");
14955682Smarkm	return ENOMEM;
15078527Sassar    }
15155682Smarkm
15255682Smarkm    n = 0;
153102644Snectar    p = start = q = s = strdup(name);
15455682Smarkm    if (start == NULL) {
15555682Smarkm	free (comp);
15678527Sassar	krb5_set_error_string (context, "malloc: out of memory");
15755682Smarkm	return ENOMEM;
15855682Smarkm    }
15955682Smarkm    while(*p){
16055682Smarkm	c = *p++;
16155682Smarkm	if(c == '\\'){
16255682Smarkm	    c = *p++;
16355682Smarkm	    if(c == 'n')
16455682Smarkm		c = '\n';
16555682Smarkm	    else if(c == 't')
16655682Smarkm		c = '\t';
16755682Smarkm	    else if(c == 'b')
16855682Smarkm		c = '\b';
16955682Smarkm	    else if(c == '0')
17055682Smarkm		c = '\0';
171107207Snectar	    else if(c == '\0') {
172107207Snectar		krb5_set_error_string (context,
173107207Snectar				       "trailing \\ in principal name");
174107207Snectar		ret = KRB5_PARSE_MALFORMED;
175107207Snectar		goto exit;
176107207Snectar	    }
177178825Sdfr	}else if(enterprise && first_at) {
178178825Sdfr	    if (c == '@')
179178825Sdfr		first_at = 0;
180178825Sdfr	}else if((c == '/' && !enterprise) || c == '@'){
18155682Smarkm	    if(got_realm){
18278527Sassar		krb5_set_error_string (context,
18378527Sassar				       "part after realm in principal name");
18455682Smarkm		ret = KRB5_PARSE_MALFORMED;
18555682Smarkm		goto exit;
18655682Smarkm	    }else{
18755682Smarkm		comp[n] = malloc(q - start + 1);
18855682Smarkm		if (comp[n] == NULL) {
18978527Sassar		    krb5_set_error_string (context, "malloc: out of memory");
19055682Smarkm		    ret = ENOMEM;
19155682Smarkm		    goto exit;
19255682Smarkm		}
19357416Smarkm		memcpy(comp[n], start, q - start);
19455682Smarkm		comp[n][q - start] = 0;
19555682Smarkm		n++;
19655682Smarkm	    }
19755682Smarkm	    if(c == '@')
19855682Smarkm		got_realm = 1;
19955682Smarkm	    start = q;
20055682Smarkm	    continue;
20155682Smarkm	}
20255682Smarkm	if(got_realm && (c == ':' || c == '/' || c == '\0')) {
20378527Sassar	    krb5_set_error_string (context,
20478527Sassar				   "part after realm in principal name");
20555682Smarkm	    ret = KRB5_PARSE_MALFORMED;
20655682Smarkm	    goto exit;
20755682Smarkm	}
20855682Smarkm	*q++ = c;
20955682Smarkm    }
21055682Smarkm    if(got_realm){
211178825Sdfr	if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
212178825Sdfr	    krb5_set_error_string (context, "realm found in 'short' principal "
213178825Sdfr				   "expected to be without one");
214178825Sdfr	    ret = KRB5_PARSE_MALFORMED;
215178825Sdfr	    goto exit;
216178825Sdfr	}
21755682Smarkm	realm = malloc(q - start + 1);
21855682Smarkm	if (realm == NULL) {
21978527Sassar	    krb5_set_error_string (context, "malloc: out of memory");
22055682Smarkm	    ret = ENOMEM;
22155682Smarkm	    goto exit;
22255682Smarkm	}
22357416Smarkm	memcpy(realm, start, q - start);
22455682Smarkm	realm[q - start] = 0;
22555682Smarkm    }else{
226178825Sdfr	if (flags & KRB5_PRINCIPAL_PARSE_MUST_REALM) {
227178825Sdfr	    krb5_set_error_string (context, "realm NOT found in principal "
228178825Sdfr				   "expected to be with one");
229178825Sdfr	    ret = KRB5_PARSE_MALFORMED;
23055682Smarkm	    goto exit;
231178825Sdfr	} else if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
232178825Sdfr	    realm = NULL;
233178825Sdfr	} else {
234178825Sdfr	    ret = krb5_get_default_realm (context, &realm);
235178825Sdfr	    if (ret)
236178825Sdfr		goto exit;
237178825Sdfr	}
23855682Smarkm
23955682Smarkm	comp[n] = malloc(q - start + 1);
24055682Smarkm	if (comp[n] == NULL) {
24178527Sassar	    krb5_set_error_string (context, "malloc: out of memory");
24255682Smarkm	    ret = ENOMEM;
24355682Smarkm	    goto exit;
24455682Smarkm	}
24557416Smarkm	memcpy(comp[n], start, q - start);
24655682Smarkm	comp[n][q - start] = 0;
24755682Smarkm	n++;
24855682Smarkm    }
24955682Smarkm    *principal = malloc(sizeof(**principal));
25055682Smarkm    if (*principal == NULL) {
25178527Sassar	krb5_set_error_string (context, "malloc: out of memory");
25255682Smarkm	ret = ENOMEM;
25355682Smarkm	goto exit;
25455682Smarkm    }
255178825Sdfr    if (enterprise)
256178825Sdfr	(*principal)->name.name_type = KRB5_NT_ENTERPRISE_PRINCIPAL;
257178825Sdfr    else
258178825Sdfr	(*principal)->name.name_type = KRB5_NT_PRINCIPAL;
25955682Smarkm    (*principal)->name.name_string.val = comp;
26055682Smarkm    princ_num_comp(*principal) = n;
26155682Smarkm    (*principal)->realm = realm;
26255682Smarkm    free(s);
26355682Smarkm    return 0;
26455682Smarkmexit:
26555682Smarkm    while(n>0){
26655682Smarkm	free(comp[--n]);
26755682Smarkm    }
26855682Smarkm    free(comp);
269178825Sdfr    free(realm);
27055682Smarkm    free(s);
27155682Smarkm    return ret;
27255682Smarkm}
27355682Smarkm
274178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
275178825Sdfrkrb5_parse_name(krb5_context context,
276178825Sdfr		const char *name,
277178825Sdfr		krb5_principal *principal)
278178825Sdfr{
279178825Sdfr    return krb5_parse_name_flags(context, name, 0, principal);
280178825Sdfr}
281178825Sdfr
28257416Smarkmstatic const char quotable_chars[] = " \n\t\b\\/@";
28357416Smarkmstatic const char replace_chars[] = " ntb\\/@";
284178825Sdfrstatic const char nq_chars[] = "    \\/@";
28555682Smarkm
28655682Smarkm#define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0);
28755682Smarkm
28855682Smarkmstatic size_t
289178825Sdfrquote_string(const char *s, char *out, size_t idx, size_t len, int display)
29055682Smarkm{
29155682Smarkm    const char *p, *q;
292178825Sdfr    for(p = s; *p && idx < len; p++){
293178825Sdfr	q = strchr(quotable_chars, *p);
294178825Sdfr	if (q && display) {
295178825Sdfr	    add_char(out, idx, len, replace_chars[q - quotable_chars]);
296178825Sdfr	} else if (q) {
297178825Sdfr	    add_char(out, idx, len, '\\');
298178825Sdfr	    add_char(out, idx, len, replace_chars[q - quotable_chars]);
29955682Smarkm	}else
300178825Sdfr	    add_char(out, idx, len, *p);
30155682Smarkm    }
302178825Sdfr    if(idx < len)
303178825Sdfr	out[idx] = '\0';
304178825Sdfr    return idx;
30555682Smarkm}
30655682Smarkm
30755682Smarkm
30855682Smarkmstatic krb5_error_code
30955682Smarkmunparse_name_fixed(krb5_context context,
31055682Smarkm		   krb5_const_principal principal,
31155682Smarkm		   char *name,
31255682Smarkm		   size_t len,
313178825Sdfr		   int flags)
31455682Smarkm{
315178825Sdfr    size_t idx = 0;
31655682Smarkm    int i;
317178825Sdfr    int short_form = (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) != 0;
318178825Sdfr    int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) != 0;
319178825Sdfr    int display = (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) != 0;
320178825Sdfr
321178825Sdfr    if (!no_realm && princ_realm(principal) == NULL) {
322178825Sdfr	krb5_set_error_string(context, "Realm missing from principal, "
323178825Sdfr			      "can't unparse");
324178825Sdfr	return ERANGE;
325178825Sdfr    }
326178825Sdfr
32755682Smarkm    for(i = 0; i < princ_num_comp(principal); i++){
32855682Smarkm	if(i)
329178825Sdfr	    add_char(name, idx, len, '/');
330178825Sdfr	idx = quote_string(princ_ncomp(principal, i), name, idx, len, display);
331178825Sdfr	if(idx == len) {
332178825Sdfr	    krb5_set_error_string(context, "Out of space printing principal");
33355682Smarkm	    return ERANGE;
334178825Sdfr	}
33555682Smarkm    }
33655682Smarkm    /* add realm if different from default realm */
337178825Sdfr    if(short_form && !no_realm) {
33855682Smarkm	krb5_realm r;
33955682Smarkm	krb5_error_code ret;
34055682Smarkm	ret = krb5_get_default_realm(context, &r);
34155682Smarkm	if(ret)
34255682Smarkm	    return ret;
34355682Smarkm	if(strcmp(princ_realm(principal), r) != 0)
34455682Smarkm	    short_form = 0;
34555682Smarkm	free(r);
34655682Smarkm    }
347178825Sdfr    if(!short_form && !no_realm) {
348178825Sdfr	add_char(name, idx, len, '@');
349178825Sdfr	idx = quote_string(princ_realm(principal), name, idx, len, display);
350178825Sdfr	if(idx == len) {
351178825Sdfr	    krb5_set_error_string(context,
352178825Sdfr				  "Out of space printing realm of principal");
35355682Smarkm	    return ERANGE;
354178825Sdfr	}
35555682Smarkm    }
35655682Smarkm    return 0;
35755682Smarkm}
35855682Smarkm
359178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
36055682Smarkmkrb5_unparse_name_fixed(krb5_context context,
36155682Smarkm			krb5_const_principal principal,
36255682Smarkm			char *name,
36355682Smarkm			size_t len)
36455682Smarkm{
365178825Sdfr    return unparse_name_fixed(context, principal, name, len, 0);
36655682Smarkm}
36755682Smarkm
368178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
36955682Smarkmkrb5_unparse_name_fixed_short(krb5_context context,
37055682Smarkm			      krb5_const_principal principal,
37155682Smarkm			      char *name,
37255682Smarkm			      size_t len)
37355682Smarkm{
374178825Sdfr    return unparse_name_fixed(context, principal, name, len,
375178825Sdfr			      KRB5_PRINCIPAL_UNPARSE_SHORT);
37655682Smarkm}
37755682Smarkm
378178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
379178825Sdfrkrb5_unparse_name_fixed_flags(krb5_context context,
380178825Sdfr			      krb5_const_principal principal,
381178825Sdfr			      int flags,
382178825Sdfr			      char *name,
383178825Sdfr			      size_t len)
384178825Sdfr{
385178825Sdfr    return unparse_name_fixed(context, principal, name, len, flags);
386178825Sdfr}
387178825Sdfr
38855682Smarkmstatic krb5_error_code
38955682Smarkmunparse_name(krb5_context context,
39055682Smarkm	     krb5_const_principal principal,
39155682Smarkm	     char **name,
392178825Sdfr	     int flags)
39355682Smarkm{
39455682Smarkm    size_t len = 0, plen;
39555682Smarkm    int i;
39655682Smarkm    krb5_error_code ret;
39755682Smarkm    /* count length */
398178825Sdfr    if (princ_realm(principal)) {
399178825Sdfr	plen = strlen(princ_realm(principal));
400178825Sdfr
401178825Sdfr	if(strcspn(princ_realm(principal), quotable_chars) == plen)
402178825Sdfr	    len += plen;
403178825Sdfr	else
404178825Sdfr	    len += 2*plen;
405178825Sdfr	len++; /* '@' */
406178825Sdfr    }
40755682Smarkm    for(i = 0; i < princ_num_comp(principal); i++){
40855682Smarkm	plen = strlen(princ_ncomp(principal, i));
40955682Smarkm	if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen)
41055682Smarkm	    len += plen;
41155682Smarkm	else
41255682Smarkm	    len += 2*plen;
41355682Smarkm	len++;
41455682Smarkm    }
415178825Sdfr    len++; /* '\0' */
41655682Smarkm    *name = malloc(len);
417127808Snectar    if(*name == NULL) {
41878527Sassar	krb5_set_error_string (context, "malloc: out of memory");
41955682Smarkm	return ENOMEM;
42078527Sassar    }
421178825Sdfr    ret = unparse_name_fixed(context, principal, *name, len, flags);
422127808Snectar    if(ret) {
42355682Smarkm	free(*name);
424127808Snectar	*name = NULL;
425127808Snectar    }
42655682Smarkm    return ret;
42755682Smarkm}
42855682Smarkm
429178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
43055682Smarkmkrb5_unparse_name(krb5_context context,
43155682Smarkm		  krb5_const_principal principal,
43255682Smarkm		  char **name)
43355682Smarkm{
434178825Sdfr    return unparse_name(context, principal, name, 0);
43555682Smarkm}
43655682Smarkm
437178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
438178825Sdfrkrb5_unparse_name_flags(krb5_context context,
439178825Sdfr			krb5_const_principal principal,
440178825Sdfr			int flags,
441178825Sdfr			char **name)
442178825Sdfr{
443178825Sdfr    return unparse_name(context, principal, name, flags);
444178825Sdfr}
445178825Sdfr
446178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
44755682Smarkmkrb5_unparse_name_short(krb5_context context,
44855682Smarkm			krb5_const_principal principal,
44955682Smarkm			char **name)
45055682Smarkm{
451178825Sdfr    return unparse_name(context, principal, name, KRB5_PRINCIPAL_UNPARSE_SHORT);
45255682Smarkm}
45355682Smarkm
45455682Smarkm#if 0 /* not implemented */
45555682Smarkm
456178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
45755682Smarkmkrb5_unparse_name_ext(krb5_context context,
45855682Smarkm		      krb5_const_principal principal,
45955682Smarkm		      char **name,
46055682Smarkm		      size_t *size)
46155682Smarkm{
46255682Smarkm    krb5_abortx(context, "unimplemented krb5_unparse_name_ext called");
46355682Smarkm}
46455682Smarkm
46555682Smarkm#endif
46655682Smarkm
467178825Sdfrkrb5_realm * KRB5_LIB_FUNCTION
46855682Smarkmkrb5_princ_realm(krb5_context context,
46955682Smarkm		 krb5_principal principal)
47055682Smarkm{
47155682Smarkm    return &princ_realm(principal);
47255682Smarkm}
47355682Smarkm
47455682Smarkm
475178825Sdfrvoid KRB5_LIB_FUNCTION
47655682Smarkmkrb5_princ_set_realm(krb5_context context,
47755682Smarkm		     krb5_principal principal,
47855682Smarkm		     krb5_realm *realm)
47955682Smarkm{
48055682Smarkm    princ_realm(principal) = *realm;
48155682Smarkm}
48255682Smarkm
48355682Smarkm
484178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
48555682Smarkmkrb5_build_principal(krb5_context context,
48655682Smarkm		     krb5_principal *principal,
48755682Smarkm		     int rlen,
48855682Smarkm		     krb5_const_realm realm,
48955682Smarkm		     ...)
49055682Smarkm{
49155682Smarkm    krb5_error_code ret;
49255682Smarkm    va_list ap;
49355682Smarkm    va_start(ap, realm);
49455682Smarkm    ret = krb5_build_principal_va(context, principal, rlen, realm, ap);
49555682Smarkm    va_end(ap);
49655682Smarkm    return ret;
49755682Smarkm}
49855682Smarkm
49955682Smarkmstatic krb5_error_code
50055682Smarkmappend_component(krb5_context context, krb5_principal p,
50157416Smarkm		 const char *comp,
50255682Smarkm		 size_t comp_len)
50355682Smarkm{
504178825Sdfr    heim_general_string *tmp;
50555682Smarkm    size_t len = princ_num_comp(p);
50657416Smarkm
50755682Smarkm    tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp));
50878527Sassar    if(tmp == NULL) {
50978527Sassar	krb5_set_error_string (context, "malloc: out of memory");
51055682Smarkm	return ENOMEM;
51178527Sassar    }
51255682Smarkm    princ_comp(p) = tmp;
51355682Smarkm    princ_ncomp(p, len) = malloc(comp_len + 1);
51478527Sassar    if (princ_ncomp(p, len) == NULL) {
51578527Sassar	krb5_set_error_string (context, "malloc: out of memory");
51657416Smarkm	return ENOMEM;
51778527Sassar    }
51855682Smarkm    memcpy (princ_ncomp(p, len), comp, comp_len);
51955682Smarkm    princ_ncomp(p, len)[comp_len] = '\0';
52055682Smarkm    princ_num_comp(p)++;
52155682Smarkm    return 0;
52255682Smarkm}
52355682Smarkm
52455682Smarkmstatic void
52555682Smarkmva_ext_princ(krb5_context context, krb5_principal p, va_list ap)
52655682Smarkm{
52755682Smarkm    while(1){
52857416Smarkm	const char *s;
52955682Smarkm	int len;
53055682Smarkm	len = va_arg(ap, int);
53155682Smarkm	if(len == 0)
53255682Smarkm	    break;
53357416Smarkm	s = va_arg(ap, const char*);
53455682Smarkm	append_component(context, p, s, len);
53555682Smarkm    }
53655682Smarkm}
53755682Smarkm
53855682Smarkmstatic void
53955682Smarkmva_princ(krb5_context context, krb5_principal p, va_list ap)
54055682Smarkm{
54155682Smarkm    while(1){
54257416Smarkm	const char *s;
54357416Smarkm	s = va_arg(ap, const char*);
54455682Smarkm	if(s == NULL)
54555682Smarkm	    break;
54655682Smarkm	append_component(context, p, s, strlen(s));
54755682Smarkm    }
54855682Smarkm}
54955682Smarkm
55055682Smarkm
55155682Smarkmstatic krb5_error_code
55255682Smarkmbuild_principal(krb5_context context,
55355682Smarkm		krb5_principal *principal,
55455682Smarkm		int rlen,
55555682Smarkm		krb5_const_realm realm,
55655682Smarkm		void (*func)(krb5_context, krb5_principal, va_list),
55755682Smarkm		va_list ap)
55855682Smarkm{
55955682Smarkm    krb5_principal p;
56055682Smarkm
56155682Smarkm    p = calloc(1, sizeof(*p));
56278527Sassar    if (p == NULL) {
56378527Sassar	krb5_set_error_string (context, "malloc: out of memory");
56455682Smarkm	return ENOMEM;
56578527Sassar    }
56655682Smarkm    princ_type(p) = KRB5_NT_PRINCIPAL;
56755682Smarkm
56855682Smarkm    princ_realm(p) = strdup(realm);
56955682Smarkm    if(p->realm == NULL){
57055682Smarkm	free(p);
57178527Sassar	krb5_set_error_string (context, "malloc: out of memory");
57255682Smarkm	return ENOMEM;
57355682Smarkm    }
57455682Smarkm
57555682Smarkm    (*func)(context, p, ap);
57655682Smarkm    *principal = p;
57755682Smarkm    return 0;
57855682Smarkm}
57955682Smarkm
580178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
58155682Smarkmkrb5_make_principal(krb5_context context,
58255682Smarkm		    krb5_principal *principal,
58355682Smarkm		    krb5_const_realm realm,
58455682Smarkm		    ...)
58555682Smarkm{
58655682Smarkm    krb5_error_code ret;
58755682Smarkm    krb5_realm r = NULL;
58855682Smarkm    va_list ap;
58955682Smarkm    if(realm == NULL) {
59055682Smarkm	ret = krb5_get_default_realm(context, &r);
59155682Smarkm	if(ret)
59255682Smarkm	    return ret;
59355682Smarkm	realm = r;
59455682Smarkm    }
59555682Smarkm    va_start(ap, realm);
59655682Smarkm    ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap);
59755682Smarkm    va_end(ap);
59855682Smarkm    if(r)
59955682Smarkm	free(r);
60055682Smarkm    return ret;
60155682Smarkm}
60255682Smarkm
603178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
60455682Smarkmkrb5_build_principal_va(krb5_context context,
60555682Smarkm			krb5_principal *principal,
60655682Smarkm			int rlen,
60755682Smarkm			krb5_const_realm realm,
60855682Smarkm			va_list ap)
60955682Smarkm{
61055682Smarkm    return build_principal(context, principal, rlen, realm, va_princ, ap);
61155682Smarkm}
61255682Smarkm
613178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
61455682Smarkmkrb5_build_principal_va_ext(krb5_context context,
61555682Smarkm			    krb5_principal *principal,
61655682Smarkm			    int rlen,
61755682Smarkm			    krb5_const_realm realm,
61855682Smarkm			    va_list ap)
61955682Smarkm{
62055682Smarkm    return build_principal(context, principal, rlen, realm, va_ext_princ, ap);
62155682Smarkm}
62255682Smarkm
62355682Smarkm
624178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
62555682Smarkmkrb5_build_principal_ext(krb5_context context,
62655682Smarkm			 krb5_principal *principal,
62755682Smarkm			 int rlen,
62855682Smarkm			 krb5_const_realm realm,
62955682Smarkm			 ...)
63055682Smarkm{
63155682Smarkm    krb5_error_code ret;
63255682Smarkm    va_list ap;
63355682Smarkm    va_start(ap, realm);
63455682Smarkm    ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap);
63555682Smarkm    va_end(ap);
63655682Smarkm    return ret;
63755682Smarkm}
63855682Smarkm
63955682Smarkm
640178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
64155682Smarkmkrb5_copy_principal(krb5_context context,
64255682Smarkm		    krb5_const_principal inprinc,
64355682Smarkm		    krb5_principal *outprinc)
64455682Smarkm{
64555682Smarkm    krb5_principal p = malloc(sizeof(*p));
64678527Sassar    if (p == NULL) {
64778527Sassar	krb5_set_error_string (context, "malloc: out of memory");
64855682Smarkm	return ENOMEM;
64978527Sassar    }
65078527Sassar    if(copy_Principal(inprinc, p)) {
65178527Sassar	free(p);
65278527Sassar	krb5_set_error_string (context, "malloc: out of memory");
65355682Smarkm	return ENOMEM;
65478527Sassar    }
65555682Smarkm    *outprinc = p;
65655682Smarkm    return 0;
65755682Smarkm}
65855682Smarkm
65972445Sassar/*
66072445Sassar * return TRUE iff princ1 == princ2 (without considering the realm)
66172445Sassar */
66255682Smarkm
663178825Sdfrkrb5_boolean KRB5_LIB_FUNCTION
66455682Smarkmkrb5_principal_compare_any_realm(krb5_context context,
66555682Smarkm				 krb5_const_principal princ1,
66655682Smarkm				 krb5_const_principal princ2)
66755682Smarkm{
66855682Smarkm    int i;
66955682Smarkm    if(princ_num_comp(princ1) != princ_num_comp(princ2))
67055682Smarkm	return FALSE;
67155682Smarkm    for(i = 0; i < princ_num_comp(princ1); i++){
67255682Smarkm	if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0)
67355682Smarkm	    return FALSE;
67455682Smarkm    }
67555682Smarkm    return TRUE;
67655682Smarkm}
67755682Smarkm
67872445Sassar/*
67972445Sassar * return TRUE iff princ1 == princ2
68072445Sassar */
68172445Sassar
682178825Sdfrkrb5_boolean KRB5_LIB_FUNCTION
68355682Smarkmkrb5_principal_compare(krb5_context context,
68455682Smarkm		       krb5_const_principal princ1,
68555682Smarkm		       krb5_const_principal princ2)
68655682Smarkm{
68755682Smarkm    if(!krb5_realm_compare(context, princ1, princ2))
68855682Smarkm	return FALSE;
68955682Smarkm    return krb5_principal_compare_any_realm(context, princ1, princ2);
69055682Smarkm}
69155682Smarkm
69272445Sassar/*
69372445Sassar * return TRUE iff realm(princ1) == realm(princ2)
69472445Sassar */
69555682Smarkm
696178825Sdfrkrb5_boolean KRB5_LIB_FUNCTION
69755682Smarkmkrb5_realm_compare(krb5_context context,
69855682Smarkm		   krb5_const_principal princ1,
69955682Smarkm		   krb5_const_principal princ2)
70055682Smarkm{
70155682Smarkm    return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0;
70255682Smarkm}
70355682Smarkm
70472445Sassar/*
70572445Sassar * return TRUE iff princ matches pattern
70672445Sassar */
70772445Sassar
708178825Sdfrkrb5_boolean KRB5_LIB_FUNCTION
70972445Sassarkrb5_principal_match(krb5_context context,
71072445Sassar		     krb5_const_principal princ,
71172445Sassar		     krb5_const_principal pattern)
71272445Sassar{
71372445Sassar    int i;
71472445Sassar    if(princ_num_comp(princ) != princ_num_comp(pattern))
71572445Sassar	return FALSE;
71672445Sassar    if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0)
71772445Sassar	return FALSE;
71872445Sassar    for(i = 0; i < princ_num_comp(princ); i++){
71972445Sassar	if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0)
72072445Sassar	    return FALSE;
72172445Sassar    }
72272445Sassar    return TRUE;
72372445Sassar}
72472445Sassar
72572445Sassar
726178825Sdfrstatic struct v4_name_convert {
72755682Smarkm    const char *from;
72855682Smarkm    const char *to;
72955682Smarkm} default_v4_name_convert[] = {
73072445Sassar    { "ftp",	"ftp" },
73172445Sassar    { "hprop",	"hprop" },
73272445Sassar    { "pop",	"pop" },
73372445Sassar    { "imap",	"imap" },
73472445Sassar    { "rcmd",	"host" },
73590926Snectar    { "smtp",	"smtp" },
73655682Smarkm    { NULL, NULL }
73755682Smarkm};
73855682Smarkm
73972445Sassar/*
74072445Sassar * return the converted instance name of `name' in `realm'.
74172445Sassar * look in the configuration file and then in the default set above.
74272445Sassar * return NULL if no conversion is appropriate.
74372445Sassar */
74472445Sassar
74555682Smarkmstatic const char*
74655682Smarkmget_name_conversion(krb5_context context, const char *realm, const char *name)
74755682Smarkm{
74855682Smarkm    struct v4_name_convert *q;
74955682Smarkm    const char *p;
75072445Sassar
75155682Smarkm    p = krb5_config_get_string(context, NULL, "realms", realm,
75255682Smarkm			       "v4_name_convert", "host", name, NULL);
75355682Smarkm    if(p == NULL)
75455682Smarkm	p = krb5_config_get_string(context, NULL, "libdefaults",
75555682Smarkm				   "v4_name_convert", "host", name, NULL);
75655682Smarkm    if(p)
75755682Smarkm	return p;
75855682Smarkm
75955682Smarkm    /* XXX should be possible to override default list */
76055682Smarkm    p = krb5_config_get_string(context, NULL,
76155682Smarkm			       "realms",
76255682Smarkm			       realm,
76355682Smarkm			       "v4_name_convert",
76455682Smarkm			       "plain",
76555682Smarkm			       name,
76655682Smarkm			       NULL);
76755682Smarkm    if(p)
76855682Smarkm	return NULL;
76955682Smarkm    p = krb5_config_get_string(context, NULL,
77055682Smarkm			       "libdefaults",
77155682Smarkm			       "v4_name_convert",
77255682Smarkm			       "plain",
77355682Smarkm			       name,
77455682Smarkm			       NULL);
77555682Smarkm    if(p)
77655682Smarkm	return NULL;
77755682Smarkm    for(q = default_v4_name_convert; q->from; q++)
77855682Smarkm	if(strcmp(q->from, name) == 0)
77955682Smarkm	    return q->to;
78055682Smarkm    return NULL;
78155682Smarkm}
78255682Smarkm
78372445Sassar/*
78472445Sassar * convert the v4 principal `name.instance@realm' to a v5 principal in `princ'.
78572445Sassar * if `resolve', use DNS.
78672445Sassar * if `func', use that function for validating the conversion
78772445Sassar */
78872445Sassar
789178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
790178825Sdfrkrb5_425_conv_principal_ext2(krb5_context context,
791178825Sdfr			     const char *name,
792178825Sdfr			     const char *instance,
793178825Sdfr			     const char *realm,
794178825Sdfr			     krb5_boolean (*func)(krb5_context,
795178825Sdfr						  void *, krb5_principal),
796178825Sdfr			     void *funcctx,
797178825Sdfr			     krb5_boolean resolve,
798178825Sdfr			     krb5_principal *princ)
79955682Smarkm{
80055682Smarkm    const char *p;
80155682Smarkm    krb5_error_code ret;
80255682Smarkm    krb5_principal pr;
80372445Sassar    char host[MAXHOSTNAMELEN];
80490926Snectar    char local_hostname[MAXHOSTNAMELEN];
80555682Smarkm
80655682Smarkm    /* do the following: if the name is found in the
807178825Sdfr       `v4_name_convert:host' part, is assumed to be a `host' type
80855682Smarkm       principal, and the instance is looked up in the
80955682Smarkm       `v4_instance_convert' part. if not found there the name is
81055682Smarkm       (optionally) looked up as a hostname, and if that doesn't yield
81155682Smarkm       anything, the `default_domain' is appended to the instance
81255682Smarkm       */
81355682Smarkm
81455682Smarkm    if(instance == NULL)
81555682Smarkm	goto no_host;
81655682Smarkm    if(instance[0] == 0){
81755682Smarkm	instance = NULL;
81855682Smarkm	goto no_host;
81955682Smarkm    }
82055682Smarkm    p = get_name_conversion(context, realm, name);
82155682Smarkm    if(p == NULL)
82255682Smarkm	goto no_host;
82355682Smarkm    name = p;
82455682Smarkm    p = krb5_config_get_string(context, NULL, "realms", realm,
82555682Smarkm			       "v4_instance_convert", instance, NULL);
82655682Smarkm    if(p){
82755682Smarkm	instance = p;
82855682Smarkm	ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
829178825Sdfr	if(func == NULL || (*func)(context, funcctx, pr)){
83055682Smarkm	    *princ = pr;
83155682Smarkm	    return 0;
83255682Smarkm	}
83355682Smarkm	krb5_free_principal(context, pr);
83455682Smarkm	*princ = NULL;
83578527Sassar	krb5_clear_error_string (context);
83655682Smarkm	return HEIM_ERR_V4_PRINC_NO_CONV;
83755682Smarkm    }
83855682Smarkm    if(resolve){
839102644Snectar	krb5_boolean passed = FALSE;
840102644Snectar	char *inst = NULL;
84155682Smarkm#ifdef USE_RESOLVER
84255682Smarkm	struct dns_reply *r;
84372445Sassar
844102644Snectar	r = dns_lookup(instance, "aaaa");
845178825Sdfr	if (r) {
846178825Sdfr	    if (r->head && r->head->type == T_AAAA) {
847178825Sdfr		inst = strdup(r->head->domain);
848178825Sdfr		passed = TRUE;
849178825Sdfr	    }
850102644Snectar	    dns_free_data(r);
851102644Snectar	} else {
852102644Snectar	    r = dns_lookup(instance, "a");
853178825Sdfr	    if (r) {
854178825Sdfr		if(r->head && r->head->type == T_A) {
855178825Sdfr		    inst = strdup(r->head->domain);
856178825Sdfr		    passed = TRUE;
857178825Sdfr		}
85872445Sassar		dns_free_data(r);
859102644Snectar	    }
860102644Snectar	}
861102644Snectar#else
862102644Snectar	struct addrinfo hints, *ai;
863102644Snectar
864102644Snectar	memset (&hints, 0, sizeof(hints));
865102644Snectar	hints.ai_flags = AI_CANONNAME;
866102644Snectar	ret = getaddrinfo(instance, NULL, &hints, &ai);
867102644Snectar	if (ret == 0) {
868102644Snectar	    const struct addrinfo *a;
869102644Snectar	    for (a = ai; a != NULL; a = a->ai_next) {
870102644Snectar		if (a->ai_canonname != NULL) {
871102644Snectar		    inst = strdup (a->ai_canonname);
872102644Snectar		    passed = TRUE;
873102644Snectar		    break;
874102644Snectar		}
875102644Snectar	    }
876102644Snectar	    freeaddrinfo (ai);
877102644Snectar	}
87872445Sassar#endif
879102644Snectar	if (passed) {
880102644Snectar	    if (inst == NULL) {
88178527Sassar		krb5_set_error_string (context, "malloc: out of memory");
88272445Sassar		return ENOMEM;
88372445Sassar	    }
884102644Snectar	    strlwr(inst);
885102644Snectar	    ret = krb5_make_principal(context, &pr, realm, name, inst,
88672445Sassar				      NULL);
887102644Snectar	    free (inst);
88855682Smarkm	    if(ret == 0) {
889178825Sdfr		if(func == NULL || (*func)(context, funcctx, pr)){
89055682Smarkm		    *princ = pr;
89155682Smarkm		    return 0;
89255682Smarkm		}
89355682Smarkm		krb5_free_principal(context, pr);
89455682Smarkm	    }
89555682Smarkm	}
89655682Smarkm    }
89790926Snectar    if(func != NULL) {
89890926Snectar	snprintf(host, sizeof(host), "%s.%s", instance, realm);
89990926Snectar	strlwr(host);
90090926Snectar	ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
901178825Sdfr	if((*func)(context, funcctx, pr)){
90290926Snectar	    *princ = pr;
90390926Snectar	    return 0;
90490926Snectar	}
90590926Snectar	krb5_free_principal(context, pr);
90690926Snectar    }
90790926Snectar
90890926Snectar    /*
90990926Snectar     * if the instance is the first component of the local hostname,
91090926Snectar     * the converted host should be the long hostname.
91190926Snectar     */
91290926Snectar
91390926Snectar    if (func == NULL &&
91490926Snectar        gethostname (local_hostname, sizeof(local_hostname)) == 0 &&
91590926Snectar        strncmp(instance, local_hostname, strlen(instance)) == 0 &&
91690926Snectar	local_hostname[strlen(instance)] == '.') {
91790926Snectar	strlcpy(host, local_hostname, sizeof(host));
91890926Snectar	goto local_host;
91990926Snectar    }
92090926Snectar
92155682Smarkm    {
92255682Smarkm	char **domains, **d;
92355682Smarkm	domains = krb5_config_get_strings(context, NULL, "realms", realm,
92455682Smarkm					  "v4_domains", NULL);
92555682Smarkm	for(d = domains; d && *d; d++){
92655682Smarkm	    snprintf(host, sizeof(host), "%s.%s", instance, *d);
92755682Smarkm	    ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
928178825Sdfr	    if(func == NULL || (*func)(context, funcctx, pr)){
92955682Smarkm		*princ = pr;
93055682Smarkm		krb5_config_free_strings(domains);
93155682Smarkm		return 0;
93255682Smarkm	    }
93355682Smarkm	    krb5_free_principal(context, pr);
93455682Smarkm	}
93555682Smarkm	krb5_config_free_strings(domains);
93655682Smarkm    }
93790926Snectar
93855682Smarkm
93955682Smarkm    p = krb5_config_get_string(context, NULL, "realms", realm,
94055682Smarkm			       "default_domain", NULL);
94155682Smarkm    if(p == NULL){
94272445Sassar	/* this should be an error, just faking a name is not good */
94378527Sassar	krb5_clear_error_string (context);
94455682Smarkm	return HEIM_ERR_V4_PRINC_NO_CONV;
94555682Smarkm    }
94655682Smarkm
94755682Smarkm    if (*p == '.')
94855682Smarkm	++p;
94955682Smarkm    snprintf(host, sizeof(host), "%s.%s", instance, p);
95090926Snectarlocal_host:
95155682Smarkm    ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
952178825Sdfr    if(func == NULL || (*func)(context, funcctx, pr)){
95355682Smarkm	*princ = pr;
95455682Smarkm	return 0;
95555682Smarkm    }
95655682Smarkm    krb5_free_principal(context, pr);
95778527Sassar    krb5_clear_error_string (context);
95855682Smarkm    return HEIM_ERR_V4_PRINC_NO_CONV;
95955682Smarkmno_host:
96055682Smarkm    p = krb5_config_get_string(context, NULL,
96155682Smarkm			       "realms",
96255682Smarkm			       realm,
96355682Smarkm			       "v4_name_convert",
96455682Smarkm			       "plain",
96555682Smarkm			       name,
96655682Smarkm			       NULL);
96755682Smarkm    if(p == NULL)
96855682Smarkm	p = krb5_config_get_string(context, NULL,
96955682Smarkm				   "libdefaults",
97055682Smarkm				   "v4_name_convert",
97155682Smarkm				   "plain",
97255682Smarkm				   name,
97355682Smarkm				   NULL);
97455682Smarkm    if(p)
97555682Smarkm	name = p;
97655682Smarkm
97755682Smarkm    ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
978178825Sdfr    if(func == NULL || (*func)(context, funcctx, pr)){
97955682Smarkm	*princ = pr;
98055682Smarkm	return 0;
98155682Smarkm    }
98255682Smarkm    krb5_free_principal(context, pr);
98378527Sassar    krb5_clear_error_string (context);
98455682Smarkm    return HEIM_ERR_V4_PRINC_NO_CONV;
98555682Smarkm}
98655682Smarkm
987178825Sdfrstatic krb5_boolean
988178825Sdfrconvert_func(krb5_context conxtext, void *funcctx, krb5_principal principal)
989178825Sdfr{
990178825Sdfr    krb5_boolean (*func)(krb5_context, krb5_principal) = funcctx;
991178825Sdfr    return (*func)(conxtext, principal);
992178825Sdfr}
993178825Sdfr
994178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
995178825Sdfrkrb5_425_conv_principal_ext(krb5_context context,
996178825Sdfr			    const char *name,
997178825Sdfr			    const char *instance,
998178825Sdfr			    const char *realm,
999178825Sdfr			    krb5_boolean (*func)(krb5_context, krb5_principal),
1000178825Sdfr			    krb5_boolean resolve,
1001178825Sdfr			    krb5_principal *principal)
1002178825Sdfr{
1003178825Sdfr    return krb5_425_conv_principal_ext2(context,
1004178825Sdfr					name,
1005178825Sdfr					instance,
1006178825Sdfr					realm,
1007178825Sdfr					func ? convert_func : NULL,
1008178825Sdfr					func,
1009178825Sdfr					resolve,
1010178825Sdfr					principal);
1011178825Sdfr}
1012178825Sdfr
1013178825Sdfr
1014178825Sdfr
1015178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
101655682Smarkmkrb5_425_conv_principal(krb5_context context,
101755682Smarkm			const char *name,
101855682Smarkm			const char *instance,
101955682Smarkm			const char *realm,
102055682Smarkm			krb5_principal *princ)
102155682Smarkm{
102255682Smarkm    krb5_boolean resolve = krb5_config_get_bool(context,
102355682Smarkm						NULL,
102455682Smarkm						"libdefaults",
102555682Smarkm						"v4_instance_resolve",
102655682Smarkm						NULL);
102755682Smarkm
102855682Smarkm    return krb5_425_conv_principal_ext(context, name, instance, realm,
102955682Smarkm				       NULL, resolve, princ);
103055682Smarkm}
103155682Smarkm
103255682Smarkm
103355682Smarkmstatic int
103455682Smarkmcheck_list(const krb5_config_binding *l, const char *name, const char **out)
103555682Smarkm{
103655682Smarkm    while(l){
103755682Smarkm	if (l->type != krb5_config_string)
103855682Smarkm	    continue;
103955682Smarkm	if(strcmp(name, l->u.string) == 0) {
104055682Smarkm	    *out = l->name;
104155682Smarkm	    return 1;
104255682Smarkm	}
104355682Smarkm	l = l->next;
104455682Smarkm    }
104555682Smarkm    return 0;
104655682Smarkm}
104755682Smarkm
104855682Smarkmstatic int
104955682Smarkmname_convert(krb5_context context, const char *name, const char *realm,
105055682Smarkm	     const char **out)
105155682Smarkm{
105255682Smarkm    const krb5_config_binding *l;
105355682Smarkm    l = krb5_config_get_list (context,
105455682Smarkm			      NULL,
105555682Smarkm			      "realms",
105655682Smarkm			      realm,
105755682Smarkm			      "v4_name_convert",
105855682Smarkm			      "host",
105955682Smarkm			      NULL);
106055682Smarkm    if(l && check_list(l, name, out))
106155682Smarkm	return KRB5_NT_SRV_HST;
106255682Smarkm    l = krb5_config_get_list (context,
106355682Smarkm			      NULL,
106455682Smarkm			      "libdefaults",
106555682Smarkm			      "v4_name_convert",
106655682Smarkm			      "host",
106755682Smarkm			      NULL);
106855682Smarkm    if(l && check_list(l, name, out))
106955682Smarkm	return KRB5_NT_SRV_HST;
107055682Smarkm    l = krb5_config_get_list (context,
107155682Smarkm			      NULL,
107255682Smarkm			      "realms",
107355682Smarkm			      realm,
107455682Smarkm			      "v4_name_convert",
107555682Smarkm			      "plain",
107655682Smarkm			      NULL);
107755682Smarkm    if(l && check_list(l, name, out))
107855682Smarkm	return KRB5_NT_UNKNOWN;
107955682Smarkm    l = krb5_config_get_list (context,
108055682Smarkm			      NULL,
108155682Smarkm			      "libdefaults",
108255682Smarkm			      "v4_name_convert",
108355682Smarkm			      "host",
108455682Smarkm			      NULL);
108555682Smarkm    if(l && check_list(l, name, out))
108655682Smarkm	return KRB5_NT_UNKNOWN;
108755682Smarkm
108855682Smarkm    /* didn't find it in config file, try built-in list */
108955682Smarkm    {
109055682Smarkm	struct v4_name_convert *q;
109155682Smarkm	for(q = default_v4_name_convert; q->from; q++) {
109255682Smarkm	    if(strcmp(name, q->to) == 0) {
109355682Smarkm		*out = q->from;
109455682Smarkm		return KRB5_NT_SRV_HST;
109555682Smarkm	    }
109655682Smarkm	}
109755682Smarkm    }
109855682Smarkm    return -1;
109955682Smarkm}
110055682Smarkm
110172445Sassar/*
110272445Sassar * convert the v5 principal in `principal' into a v4 corresponding one
110372445Sassar * in `name, instance, realm'
110472445Sassar * this is limited interface since there's no length given for these
110572445Sassar * three parameters.  They have to be 40 bytes each (ANAME_SZ).
110672445Sassar */
110772445Sassar
1108178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
110955682Smarkmkrb5_524_conv_principal(krb5_context context,
111055682Smarkm			const krb5_principal principal,
111155682Smarkm			char *name,
111255682Smarkm			char *instance,
111355682Smarkm			char *realm)
111455682Smarkm{
111555682Smarkm    const char *n, *i, *r;
111655682Smarkm    char tmpinst[40];
111755682Smarkm    int type = princ_type(principal);
111872445Sassar    const int aname_sz = 40;
111955682Smarkm
112055682Smarkm    r = principal->realm;
112155682Smarkm
112255682Smarkm    switch(principal->name.name_string.len){
112355682Smarkm    case 1:
112455682Smarkm	n = principal->name.name_string.val[0];
112555682Smarkm	i = "";
112655682Smarkm	break;
112755682Smarkm    case 2:
112855682Smarkm	n = principal->name.name_string.val[0];
112955682Smarkm	i = principal->name.name_string.val[1];
113055682Smarkm	break;
113155682Smarkm    default:
113278527Sassar	krb5_set_error_string (context,
113378527Sassar			       "cannot convert a %d component principal",
113478527Sassar			       principal->name.name_string.len);
113555682Smarkm	return KRB5_PARSE_MALFORMED;
113655682Smarkm    }
113755682Smarkm
113855682Smarkm    {
113955682Smarkm	const char *tmp;
114055682Smarkm	int t = name_convert(context, n, r, &tmp);
114155682Smarkm	if(t >= 0) {
114255682Smarkm	    type = t;
114355682Smarkm	    n = tmp;
114455682Smarkm	}
114555682Smarkm    }
114655682Smarkm
114755682Smarkm    if(type == KRB5_NT_SRV_HST){
114855682Smarkm	char *p;
114957416Smarkm
115057416Smarkm	strlcpy (tmpinst, i, sizeof(tmpinst));
115155682Smarkm	p = strchr(tmpinst, '.');
115257416Smarkm	if(p)
115357416Smarkm	    *p = 0;
115455682Smarkm	i = tmpinst;
115555682Smarkm    }
115655682Smarkm
115778527Sassar    if (strlcpy (name, n, aname_sz) >= aname_sz) {
115878527Sassar	krb5_set_error_string (context,
115978527Sassar			       "too long name component to convert");
116055682Smarkm	return KRB5_PARSE_MALFORMED;
116178527Sassar    }
116278527Sassar    if (strlcpy (instance, i, aname_sz) >= aname_sz) {
116378527Sassar	krb5_set_error_string (context,
116478527Sassar			       "too long instance component to convert");
116555682Smarkm	return KRB5_PARSE_MALFORMED;
116678527Sassar    }
116778527Sassar    if (strlcpy (realm, r, aname_sz) >= aname_sz) {
116878527Sassar	krb5_set_error_string (context,
116978527Sassar			       "too long realm component to convert");
117055682Smarkm	return KRB5_PARSE_MALFORMED;
117178527Sassar    }
117255682Smarkm    return 0;
117355682Smarkm}
117455682Smarkm
117555682Smarkm/*
117655682Smarkm * Create a principal in `ret_princ' for the service `sname' running
117757416Smarkm * on host `hostname'.  */
117855682Smarkm
1179178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
118055682Smarkmkrb5_sname_to_principal (krb5_context context,
118155682Smarkm			 const char *hostname,
118255682Smarkm			 const char *sname,
118355682Smarkm			 int32_t type,
118455682Smarkm			 krb5_principal *ret_princ)
118555682Smarkm{
118655682Smarkm    krb5_error_code ret;
118772445Sassar    char localhost[MAXHOSTNAMELEN];
118855682Smarkm    char **realms, *host = NULL;
118955682Smarkm
119078527Sassar    if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) {
119178527Sassar	krb5_set_error_string (context, "unsupported name type %d",
119278527Sassar			       type);
119355682Smarkm	return KRB5_SNAME_UNSUPP_NAMETYPE;
119478527Sassar    }
119555682Smarkm    if(hostname == NULL) {
119655682Smarkm	gethostname(localhost, sizeof(localhost));
119755682Smarkm	hostname = localhost;
119855682Smarkm    }
119955682Smarkm    if(sname == NULL)
120055682Smarkm	sname = "host";
120155682Smarkm    if(type == KRB5_NT_SRV_HST) {
120257416Smarkm	ret = krb5_expand_hostname_realms (context, hostname,
120357416Smarkm					   &host, &realms);
120455682Smarkm	if (ret)
120555682Smarkm	    return ret;
120655682Smarkm	strlwr(host);
120755682Smarkm	hostname = host;
120857416Smarkm    } else {
120957416Smarkm	ret = krb5_get_host_realm(context, hostname, &realms);
121057416Smarkm	if(ret)
121157416Smarkm	    return ret;
121255682Smarkm    }
121355682Smarkm
121455682Smarkm    ret = krb5_make_principal(context, ret_princ, realms[0], sname,
121555682Smarkm			      hostname, NULL);
121655682Smarkm    if(host)
121755682Smarkm	free(host);
121855682Smarkm    krb5_free_host_realm(context, realms);
121955682Smarkm    return ret;
122055682Smarkm}
1221178825Sdfr
1222178825Sdfrstatic const struct {
1223178825Sdfr    const char *type;
1224178825Sdfr    int32_t value;
1225178825Sdfr} nametypes[] = {
1226178825Sdfr    { "UNKNOWN", KRB5_NT_UNKNOWN },
1227178825Sdfr    { "PRINCIPAL", KRB5_NT_PRINCIPAL },
1228178825Sdfr    { "SRV_INST", KRB5_NT_SRV_INST },
1229178825Sdfr    { "SRV_HST", KRB5_NT_SRV_HST },
1230178825Sdfr    { "SRV_XHST", KRB5_NT_SRV_XHST },
1231178825Sdfr    { "UID", KRB5_NT_UID },
1232178825Sdfr    { "X500_PRINCIPAL", KRB5_NT_X500_PRINCIPAL },
1233178825Sdfr    { "SMTP_NAME", KRB5_NT_SMTP_NAME },
1234178825Sdfr    { "ENTERPRISE_PRINCIPAL", KRB5_NT_ENTERPRISE_PRINCIPAL },
1235178825Sdfr    { "ENT_PRINCIPAL_AND_ID", KRB5_NT_ENT_PRINCIPAL_AND_ID },
1236178825Sdfr    { "MS_PRINCIPAL", KRB5_NT_MS_PRINCIPAL },
1237178825Sdfr    { "MS_PRINCIPAL_AND_ID", KRB5_NT_MS_PRINCIPAL_AND_ID },
1238178825Sdfr    { NULL }
1239178825Sdfr};
1240178825Sdfr
1241178825Sdfrkrb5_error_code
1242178825Sdfrkrb5_parse_nametype(krb5_context context, const char *str, int32_t *nametype)
1243178825Sdfr{
1244178825Sdfr    size_t i;
1245178825Sdfr
1246178825Sdfr    for(i = 0; nametypes[i].type; i++) {
1247178825Sdfr	if (strcasecmp(nametypes[i].type, str) == 0) {
1248178825Sdfr	    *nametype = nametypes[i].value;
1249178825Sdfr	    return 0;
1250178825Sdfr	}
1251178825Sdfr    }
1252178825Sdfr    krb5_set_error_string(context, "Failed to find name type %s", str);
1253178825Sdfr    return KRB5_PARSE_MALFORMED;
1254178825Sdfr}
1255