1 /*	$NetBSD: import_name.c,v 1.1.1.2 2014/04/24 12:45:29 pettai Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include "gsskrb5_locl.h"
37 
38 static OM_uint32
parse_krb5_name(OM_uint32 * minor_status,krb5_context context,const char * name,gss_name_t * output_name)39 parse_krb5_name (OM_uint32 *minor_status,
40 		 krb5_context context,
41 		 const char *name,
42 		 gss_name_t *output_name)
43 {
44     krb5_principal princ;
45     krb5_error_code kerr;
46 
47     kerr = krb5_parse_name (context, name, &princ);
48 
49     if (kerr == 0) {
50 	*output_name = (gss_name_t)princ;
51 	return GSS_S_COMPLETE;
52     }
53     *minor_status = kerr;
54 
55     if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED)
56 	return GSS_S_BAD_NAME;
57 
58     return GSS_S_FAILURE;
59 }
60 
61 static OM_uint32
import_krb5_name(OM_uint32 * minor_status,krb5_context context,const gss_buffer_t input_name_buffer,gss_name_t * output_name)62 import_krb5_name (OM_uint32 *minor_status,
63 		  krb5_context context,
64 		  const gss_buffer_t input_name_buffer,
65 		  gss_name_t *output_name)
66 {
67     OM_uint32 ret;
68     char *tmp;
69 
70     tmp = malloc (input_name_buffer->length + 1);
71     if (tmp == NULL) {
72 	*minor_status = ENOMEM;
73 	return GSS_S_FAILURE;
74     }
75     memcpy (tmp,
76 	    input_name_buffer->value,
77 	    input_name_buffer->length);
78     tmp[input_name_buffer->length] = '\0';
79 
80     ret = parse_krb5_name(minor_status, context, tmp, output_name);
81     free(tmp);
82 
83     return ret;
84 }
85 
86 OM_uint32
_gsskrb5_canon_name(OM_uint32 * minor_status,krb5_context context,int use_dns,krb5_const_principal sourcename,gss_name_t targetname,krb5_principal * out)87 _gsskrb5_canon_name(OM_uint32 *minor_status, krb5_context context,
88 		    int use_dns, krb5_const_principal sourcename, gss_name_t targetname,
89 		    krb5_principal *out)
90 {
91     krb5_principal p = (krb5_principal)targetname;
92     krb5_error_code ret;
93     char *hostname = NULL, *service;
94 
95     *minor_status = 0;
96 
97     /* If its not a hostname */
98     if (krb5_principal_get_type(context, p) != MAGIC_HOSTBASED_NAME_TYPE) {
99 	ret = krb5_copy_principal(context, p, out);
100     } else if (!use_dns) {
101 	ret = krb5_copy_principal(context, p, out);
102 	if (ret)
103 	    goto out;
104 	krb5_principal_set_type(context, *out, KRB5_NT_SRV_HST);
105 	if (sourcename)
106 	    ret = krb5_principal_set_realm(context, *out, sourcename->realm);
107     } else {
108 	if (p->name.name_string.len == 0)
109 	    return GSS_S_BAD_NAME;
110 	else if (p->name.name_string.len > 1)
111 	    hostname = p->name.name_string.val[1];
112 
113 	service = p->name.name_string.val[0];
114 
115 	ret = krb5_sname_to_principal(context,
116 				      hostname,
117 				      service,
118 				      KRB5_NT_SRV_HST,
119 				      out);
120     }
121 
122  out:
123     if (ret) {
124 	*minor_status = ret;
125 	return GSS_S_FAILURE;
126     }
127 
128     return 0;
129 }
130 
131 
132 static OM_uint32
import_hostbased_name(OM_uint32 * minor_status,krb5_context context,const gss_buffer_t input_name_buffer,gss_name_t * output_name)133 import_hostbased_name (OM_uint32 *minor_status,
134 		       krb5_context context,
135 		       const gss_buffer_t input_name_buffer,
136 		       gss_name_t *output_name)
137 {
138     krb5_principal princ = NULL;
139     krb5_error_code kerr;
140     char *tmp, *p, *host = NULL;
141 
142     tmp = malloc (input_name_buffer->length + 1);
143     if (tmp == NULL) {
144 	*minor_status = ENOMEM;
145 	return GSS_S_FAILURE;
146     }
147     memcpy (tmp,
148 	    input_name_buffer->value,
149 	    input_name_buffer->length);
150     tmp[input_name_buffer->length] = '\0';
151 
152     p = strchr (tmp, '@');
153     if (p != NULL) {
154 	*p = '\0';
155 	host = p + 1;
156     }
157 
158     kerr = krb5_make_principal(context, &princ, NULL, tmp, host, NULL);
159     free (tmp);
160     *minor_status = kerr;
161     if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED)
162 	return GSS_S_BAD_NAME;
163     else if (kerr)
164 	return GSS_S_FAILURE;
165 
166     krb5_principal_set_type(context, princ, MAGIC_HOSTBASED_NAME_TYPE);
167     *output_name = (gss_name_t)princ;
168 
169     return 0;
170 }
171 
172 static OM_uint32
import_export_name(OM_uint32 * minor_status,krb5_context context,const gss_buffer_t input_name_buffer,gss_name_t * output_name)173 import_export_name (OM_uint32 *minor_status,
174 		    krb5_context context,
175 		    const gss_buffer_t input_name_buffer,
176 		    gss_name_t *output_name)
177 {
178     unsigned char *p;
179     uint32_t length;
180     OM_uint32 ret;
181     char *name;
182 
183     if (input_name_buffer->length < 10 + GSS_KRB5_MECHANISM->length)
184 	return GSS_S_BAD_NAME;
185 
186     /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */
187 
188     p = input_name_buffer->value;
189 
190     if (memcmp(&p[0], "\x04\x01\x00", 3) != 0 ||
191 	p[3] != GSS_KRB5_MECHANISM->length + 2 ||
192 	p[4] != 0x06 ||
193 	p[5] != GSS_KRB5_MECHANISM->length ||
194 	memcmp(&p[6], GSS_KRB5_MECHANISM->elements,
195 	       GSS_KRB5_MECHANISM->length) != 0)
196 	return GSS_S_BAD_NAME;
197 
198     p += 6 + GSS_KRB5_MECHANISM->length;
199 
200     length = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
201     p += 4;
202 
203     if (length > input_name_buffer->length - 10 - GSS_KRB5_MECHANISM->length)
204 	return GSS_S_BAD_NAME;
205 
206     name = malloc(length + 1);
207     if (name == NULL) {
208 	*minor_status = ENOMEM;
209 	return GSS_S_FAILURE;
210     }
211     memcpy(name, p, length);
212     name[length] = '\0';
213 
214     ret = parse_krb5_name(minor_status, context, name, output_name);
215     free(name);
216 
217     return ret;
218 }
219 
_gsskrb5_import_name(OM_uint32 * minor_status,const gss_buffer_t input_name_buffer,const gss_OID input_name_type,gss_name_t * output_name)220 OM_uint32 GSSAPI_CALLCONV _gsskrb5_import_name
221            (OM_uint32 * minor_status,
222             const gss_buffer_t input_name_buffer,
223             const gss_OID input_name_type,
224             gss_name_t * output_name
225            )
226 {
227     krb5_context context;
228 
229     *minor_status = 0;
230     *output_name = GSS_C_NO_NAME;
231 
232     GSSAPI_KRB5_INIT (&context);
233 
234     if (gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE) ||
235 	gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE_X))
236 	return import_hostbased_name (minor_status,
237 				      context,
238 				      input_name_buffer,
239 				      output_name);
240     else if (input_name_type == GSS_C_NO_OID
241 	     || gss_oid_equal(input_name_type, GSS_C_NT_USER_NAME)
242 	     || gss_oid_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME))
243  	/* default printable syntax */
244 	return import_krb5_name (minor_status,
245 				 context,
246 				 input_name_buffer,
247 				 output_name);
248     else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) {
249 	return import_export_name(minor_status,
250 				  context,
251 				  input_name_buffer,
252 				  output_name);
253     } else {
254 	*minor_status = 0;
255 	return GSS_S_BAD_NAMETYPE;
256     }
257 }
258