1178825Sdfr/*
2233294Sstas * Copyright (c) 1997 - 2003 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34233294Sstas#include "gsskrb5_locl.h"
35178825Sdfr
36178825Sdfrstatic OM_uint32
37178825Sdfrparse_krb5_name (OM_uint32 *minor_status,
38178825Sdfr		 krb5_context context,
39178825Sdfr		 const char *name,
40178825Sdfr		 gss_name_t *output_name)
41178825Sdfr{
42178825Sdfr    krb5_principal princ;
43178825Sdfr    krb5_error_code kerr;
44178825Sdfr
45178825Sdfr    kerr = krb5_parse_name (context, name, &princ);
46178825Sdfr
47178825Sdfr    if (kerr == 0) {
48178825Sdfr	*output_name = (gss_name_t)princ;
49178825Sdfr	return GSS_S_COMPLETE;
50178825Sdfr    }
51178825Sdfr    *minor_status = kerr;
52178825Sdfr
53178825Sdfr    if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED)
54178825Sdfr	return GSS_S_BAD_NAME;
55178825Sdfr
56178825Sdfr    return GSS_S_FAILURE;
57178825Sdfr}
58178825Sdfr
59178825Sdfrstatic OM_uint32
60178825Sdfrimport_krb5_name (OM_uint32 *minor_status,
61178825Sdfr		  krb5_context context,
62178825Sdfr		  const gss_buffer_t input_name_buffer,
63178825Sdfr		  gss_name_t *output_name)
64178825Sdfr{
65178825Sdfr    OM_uint32 ret;
66178825Sdfr    char *tmp;
67178825Sdfr
68178825Sdfr    tmp = malloc (input_name_buffer->length + 1);
69178825Sdfr    if (tmp == NULL) {
70178825Sdfr	*minor_status = ENOMEM;
71178825Sdfr	return GSS_S_FAILURE;
72178825Sdfr    }
73178825Sdfr    memcpy (tmp,
74178825Sdfr	    input_name_buffer->value,
75178825Sdfr	    input_name_buffer->length);
76178825Sdfr    tmp[input_name_buffer->length] = '\0';
77178825Sdfr
78178825Sdfr    ret = parse_krb5_name(minor_status, context, tmp, output_name);
79178825Sdfr    free(tmp);
80178825Sdfr
81178825Sdfr    return ret;
82178825Sdfr}
83178825Sdfr
84233294SstasOM_uint32
85233294Sstas_gsskrb5_canon_name(OM_uint32 *minor_status, krb5_context context,
86233294Sstas		    int use_dns, krb5_const_principal sourcename, gss_name_t targetname,
87233294Sstas		    krb5_principal *out)
88233294Sstas{
89233294Sstas    krb5_principal p = (krb5_principal)targetname;
90233294Sstas    krb5_error_code ret;
91233294Sstas    char *hostname = NULL, *service;
92233294Sstas
93233294Sstas    *minor_status = 0;
94233294Sstas
95233294Sstas    /* If its not a hostname */
96233294Sstas    if (krb5_principal_get_type(context, p) != MAGIC_HOSTBASED_NAME_TYPE) {
97233294Sstas	ret = krb5_copy_principal(context, p, out);
98233294Sstas    } else if (!use_dns) {
99233294Sstas	ret = krb5_copy_principal(context, p, out);
100233294Sstas	if (ret)
101233294Sstas	    goto out;
102233294Sstas	krb5_principal_set_type(context, *out, KRB5_NT_SRV_HST);
103233294Sstas	if (sourcename)
104233294Sstas	    ret = krb5_principal_set_realm(context, *out, sourcename->realm);
105233294Sstas    } else {
106233294Sstas	if (p->name.name_string.len == 0)
107233294Sstas	    return GSS_S_BAD_NAME;
108233294Sstas	else if (p->name.name_string.len > 1)
109233294Sstas	    hostname = p->name.name_string.val[1];
110233294Sstas
111233294Sstas	service = p->name.name_string.val[0];
112233294Sstas
113233294Sstas	ret = krb5_sname_to_principal(context,
114233294Sstas				      hostname,
115233294Sstas				      service,
116233294Sstas				      KRB5_NT_SRV_HST,
117233294Sstas				      out);
118233294Sstas    }
119233294Sstas
120233294Sstas out:
121233294Sstas    if (ret) {
122233294Sstas	*minor_status = ret;
123233294Sstas	return GSS_S_FAILURE;
124233294Sstas    }
125233294Sstas
126233294Sstas    return 0;
127233294Sstas}
128233294Sstas
129233294Sstas
130178825Sdfrstatic OM_uint32
131178825Sdfrimport_hostbased_name (OM_uint32 *minor_status,
132178825Sdfr		       krb5_context context,
133178825Sdfr		       const gss_buffer_t input_name_buffer,
134178825Sdfr		       gss_name_t *output_name)
135178825Sdfr{
136233294Sstas    krb5_principal princ = NULL;
137178825Sdfr    krb5_error_code kerr;
138233294Sstas    char *tmp, *p, *host = NULL;
139178825Sdfr
140178825Sdfr    tmp = malloc (input_name_buffer->length + 1);
141178825Sdfr    if (tmp == NULL) {
142178825Sdfr	*minor_status = ENOMEM;
143178825Sdfr	return GSS_S_FAILURE;
144178825Sdfr    }
145178825Sdfr    memcpy (tmp,
146178825Sdfr	    input_name_buffer->value,
147178825Sdfr	    input_name_buffer->length);
148178825Sdfr    tmp[input_name_buffer->length] = '\0';
149178825Sdfr
150178825Sdfr    p = strchr (tmp, '@');
151178825Sdfr    if (p != NULL) {
152178825Sdfr	*p = '\0';
153178825Sdfr	host = p + 1;
154178825Sdfr    }
155178825Sdfr
156233294Sstas    kerr = krb5_make_principal(context, &princ, NULL, tmp, host, NULL);
157178825Sdfr    free (tmp);
158178825Sdfr    *minor_status = kerr;
159178825Sdfr    if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED)
160178825Sdfr	return GSS_S_BAD_NAME;
161233294Sstas    else if (kerr)
162233294Sstas	return GSS_S_FAILURE;
163178825Sdfr
164233294Sstas    krb5_principal_set_type(context, princ, MAGIC_HOSTBASED_NAME_TYPE);
165233294Sstas    *output_name = (gss_name_t)princ;
166233294Sstas
167233294Sstas    return 0;
168178825Sdfr}
169178825Sdfr
170178825Sdfrstatic OM_uint32
171178825Sdfrimport_export_name (OM_uint32 *minor_status,
172178825Sdfr		    krb5_context context,
173178825Sdfr		    const gss_buffer_t input_name_buffer,
174178825Sdfr		    gss_name_t *output_name)
175178825Sdfr{
176178825Sdfr    unsigned char *p;
177178825Sdfr    uint32_t length;
178178825Sdfr    OM_uint32 ret;
179178825Sdfr    char *name;
180178825Sdfr
181178825Sdfr    if (input_name_buffer->length < 10 + GSS_KRB5_MECHANISM->length)
182178825Sdfr	return GSS_S_BAD_NAME;
183178825Sdfr
184178825Sdfr    /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */
185178825Sdfr
186178825Sdfr    p = input_name_buffer->value;
187178825Sdfr
188178825Sdfr    if (memcmp(&p[0], "\x04\x01\x00", 3) != 0 ||
189178825Sdfr	p[3] != GSS_KRB5_MECHANISM->length + 2 ||
190178825Sdfr	p[4] != 0x06 ||
191178825Sdfr	p[5] != GSS_KRB5_MECHANISM->length ||
192233294Sstas	memcmp(&p[6], GSS_KRB5_MECHANISM->elements,
193178825Sdfr	       GSS_KRB5_MECHANISM->length) != 0)
194178825Sdfr	return GSS_S_BAD_NAME;
195178825Sdfr
196178825Sdfr    p += 6 + GSS_KRB5_MECHANISM->length;
197178825Sdfr
198178825Sdfr    length = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
199178825Sdfr    p += 4;
200178825Sdfr
201178825Sdfr    if (length > input_name_buffer->length - 10 - GSS_KRB5_MECHANISM->length)
202178825Sdfr	return GSS_S_BAD_NAME;
203178825Sdfr
204178825Sdfr    name = malloc(length + 1);
205178825Sdfr    if (name == NULL) {
206178825Sdfr	*minor_status = ENOMEM;
207178825Sdfr	return GSS_S_FAILURE;
208178825Sdfr    }
209178825Sdfr    memcpy(name, p, length);
210178825Sdfr    name[length] = '\0';
211178825Sdfr
212178825Sdfr    ret = parse_krb5_name(minor_status, context, name, output_name);
213178825Sdfr    free(name);
214178825Sdfr
215178825Sdfr    return ret;
216178825Sdfr}
217178825Sdfr
218233294SstasOM_uint32 GSSAPI_CALLCONV _gsskrb5_import_name
219178825Sdfr           (OM_uint32 * minor_status,
220178825Sdfr            const gss_buffer_t input_name_buffer,
221178825Sdfr            const gss_OID input_name_type,
222178825Sdfr            gss_name_t * output_name
223178825Sdfr           )
224178825Sdfr{
225178825Sdfr    krb5_context context;
226178825Sdfr
227178825Sdfr    *minor_status = 0;
228178825Sdfr    *output_name = GSS_C_NO_NAME;
229233294Sstas
230178825Sdfr    GSSAPI_KRB5_INIT (&context);
231178825Sdfr
232178825Sdfr    if (gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE) ||
233178825Sdfr	gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE_X))
234178825Sdfr	return import_hostbased_name (minor_status,
235178825Sdfr				      context,
236178825Sdfr				      input_name_buffer,
237178825Sdfr				      output_name);
238233294Sstas    else if (input_name_type == GSS_C_NO_OID
239178825Sdfr	     || gss_oid_equal(input_name_type, GSS_C_NT_USER_NAME)
240178825Sdfr	     || gss_oid_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME))
241178825Sdfr 	/* default printable syntax */
242178825Sdfr	return import_krb5_name (minor_status,
243178825Sdfr				 context,
244178825Sdfr				 input_name_buffer,
245178825Sdfr				 output_name);
246178825Sdfr    else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) {
247178825Sdfr	return import_export_name(minor_status,
248178825Sdfr				  context,
249233294Sstas				  input_name_buffer,
250178825Sdfr				  output_name);
251178825Sdfr    } else {
252178825Sdfr	*minor_status = 0;
253178825Sdfr	return GSS_S_BAD_NAMETYPE;
254178825Sdfr    }
255178825Sdfr}
256