Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-test
[kai/samba.git] / source / heimdal / lib / gssapi / mech / gss_import_name.c
1 /*-
2  * Copyright (c) 2005 Doug Rabson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *      $FreeBSD: src/lib/libgssapi/gss_import_name.c,v 1.1 2005/12/29 14:40:20 dfr Exp $
27  */
28
29 #include "mech_locl.h"
30 RCSID("$Id$");
31
32 static OM_uint32
33 _gss_import_export_name(OM_uint32 *minor_status,
34     const gss_buffer_t input_name_buffer,
35     gss_name_t *output_name)
36 {
37         OM_uint32 major_status;
38         unsigned char *p = input_name_buffer->value;
39         size_t len = input_name_buffer->length;
40         size_t t;
41         gss_OID_desc mech_oid;
42         gssapi_mech_interface m;
43         struct _gss_name *name;
44         gss_name_t new_canonical_name;
45
46         *minor_status = 0;
47         *output_name = 0;
48
49         /*
50          * Make sure that TOK_ID is {4, 1}.
51          */
52         if (len < 2)
53                 return (GSS_S_BAD_NAME);
54         if (p[0] != 4 || p[1] != 1)
55                 return (GSS_S_BAD_NAME);
56         p += 2;
57         len -= 2;
58
59         /*
60          * Get the mech length and the name length and sanity
61          * check the size of of the buffer.
62          */
63         if (len < 2)
64                 return (GSS_S_BAD_NAME);
65         t = (p[0] << 8) + p[1];
66         p += 2;
67         len -= 2;
68
69         /*
70          * Check the DER encoded OID to make sure it agrees with the
71          * length we just decoded.
72          */
73         if (p[0] != 6)          /* 6=OID */
74                 return (GSS_S_BAD_NAME);
75         p++;
76         len--;
77         t--;
78         if (p[0] & 0x80) {
79                 int digits = p[0];
80                 p++;
81                 len--;
82                 t--;
83                 mech_oid.length = 0;
84                 while (digits--) {
85                         mech_oid.length = (mech_oid.length << 8) | p[0];
86                         p++;
87                         len--;
88                         t--;
89                 }
90         } else {
91                 mech_oid.length = p[0];
92                 p++;
93                 len--;
94                 t--;
95         }
96         if (mech_oid.length != t)
97                 return (GSS_S_BAD_NAME);
98
99         mech_oid.elements = p;
100
101         if (len < t + 4)
102                 return (GSS_S_BAD_NAME);
103         p += t;
104         len -= t;
105
106         t = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
107         p += 4;
108         len -= 4;
109
110         if (len != t)
111                 return (GSS_S_BAD_NAME);
112
113         m = __gss_get_mechanism(&mech_oid);
114         if (!m)
115                 return (GSS_S_BAD_MECH);
116
117         /*
118          * Ask the mechanism to import the name.
119          */
120         major_status = m->gm_import_name(minor_status,
121             input_name_buffer, GSS_C_NT_EXPORT_NAME, &new_canonical_name);
122         if (major_status != GSS_S_COMPLETE) {
123                 _gss_mg_error(m, major_status, *minor_status);
124                 return major_status;
125         }
126
127         /*
128          * Now we make a new name and mark it as an MN.
129          */
130         name = _gss_make_name(m, new_canonical_name);
131         if (!name) {
132                 m->gm_release_name(minor_status, &new_canonical_name);
133                 return (GSS_S_FAILURE);
134         }
135
136         *output_name = (gss_name_t) name;
137
138         *minor_status = 0;
139         return (GSS_S_COMPLETE);
140 }
141
142 OM_uint32 GSSAPI_LIB_FUNCTION
143 gss_import_name(OM_uint32 *minor_status,
144     const gss_buffer_t input_name_buffer,
145     const gss_OID input_name_type,
146     gss_name_t *output_name)
147 {
148         gss_OID                 name_type = input_name_type;
149         OM_uint32               major_status;
150         struct _gss_name        *name;
151
152         *output_name = GSS_C_NO_NAME;
153
154         if (input_name_buffer->length == 0) {
155                 *minor_status = 0;
156                 return (GSS_S_BAD_NAME);
157         }
158
159         /*
160          * Use GSS_NT_USER_NAME as default name type.
161          */
162         if (name_type == GSS_C_NO_OID)
163                 name_type = GSS_C_NT_USER_NAME;
164
165         /*
166          * If this is an exported name, we need to parse it to find
167          * the mechanism and then import it as an MN. See RFC 2743
168          * section 3.2 for a description of the format.
169          */
170         if (gss_oid_equal(name_type, GSS_C_NT_EXPORT_NAME)) {
171                 return _gss_import_export_name(minor_status,
172                     input_name_buffer, output_name);
173         }
174
175         /*
176          * Only allow certain name types. This is pretty bogus - we
177          * should figure out the list of supported name types using
178          * gss_inquire_names_for_mech.
179          */
180         if (!gss_oid_equal(name_type, GSS_C_NT_USER_NAME)
181             && !gss_oid_equal(name_type, GSS_C_NT_MACHINE_UID_NAME)
182             && !gss_oid_equal(name_type, GSS_C_NT_STRING_UID_NAME)
183             && !gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE_X)
184             && !gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE)
185             && !gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)
186             && !gss_oid_equal(name_type, GSS_KRB5_NT_PRINCIPAL_NAME)) {
187                 *minor_status = 0;
188                 return (GSS_S_BAD_NAMETYPE);
189         }
190
191         *minor_status = 0;
192         name = malloc(sizeof(struct _gss_name));
193         if (!name) {
194                 *minor_status = ENOMEM;
195                 return (GSS_S_FAILURE);
196         }
197         memset(name, 0, sizeof(struct _gss_name));
198
199         major_status = _gss_copy_oid(minor_status,
200             name_type, &name->gn_type);
201         if (major_status) {
202                 free(name);
203                 return (GSS_S_FAILURE);
204         }
205
206         major_status = _gss_copy_buffer(minor_status,
207             input_name_buffer, &name->gn_value);
208         if (major_status) {
209                 gss_name_t rname = (gss_name_t)name;
210                 gss_release_name(minor_status, &rname);
211                 return (GSS_S_FAILURE);
212         }
213
214         SLIST_INIT(&name->gn_mn);
215
216         *output_name = (gss_name_t) name;
217         return (GSS_S_COMPLETE);
218 }