HEIMDAL: move code from source4/heimdal* to third_party/heimdal*
[samba.git] / third_party / heimdal / lib / gssapi / sanon / import_name.c
1 /*
2  * Copyright (c) 2019-2020, AuriStor, Inc.
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  *
9  * - Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in
14  *   the documentation and/or other materials provided with the
15  *   distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31
32 #include "sanon_locl.h"
33
34 static int
35 is_anonymous_identity_p(gss_buffer_t name_string, gss_OID name_type)
36 {
37     if (gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS))
38         return TRUE;
39     else if ((gss_oid_equal(name_type, GSS_C_NT_USER_NAME) ||
40               gss_oid_equal(name_type, GSS_KRB5_NT_PRINCIPAL_NAME)) &&
41         buffer_equal_p(name_string, _gss_sanon_wellknown_user_name))
42         return TRUE;
43     else if (gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE) &&
44         buffer_equal_p(name_string, _gss_sanon_wellknown_service_name))
45         return TRUE;
46
47     return FALSE;
48 }
49
50 static krb5_error_code
51 storage_ret_der_oid(krb5_storage *sp, gss_OID_desc *oid)
52 {
53     krb5_error_code ret;
54     uint16_t der_oid_len;
55     uint8_t oid_len, tag;
56
57     oid->length = 0;
58     oid->elements = NULL;
59
60     ret = krb5_ret_uint16(sp, &der_oid_len);
61     if (ret != 0)
62         return ret;
63
64     ret = krb5_ret_uint8(sp, &tag);
65     if (tag != 0x06)
66         return EINVAL;
67
68     ret = krb5_ret_uint8(sp, &oid_len);
69     if (ret != 0)
70         return ret;
71
72     if (der_oid_len != 2 + oid_len)
73         return EINVAL;
74
75     oid->elements = malloc(oid_len);
76     if (oid->elements == NULL)
77         return ENOMEM;
78
79     if (krb5_storage_read(sp, oid->elements, oid_len) != oid_len) {
80         free(oid->elements);
81         oid->elements = NULL;
82         oid->length = 0;
83         return EINVAL;
84     }
85
86     oid->length = oid_len;
87
88     return 0;
89 }
90
91 static OM_uint32
92 import_export_name(OM_uint32 *minor,
93                    const gss_buffer_t input_name_buffer,
94                    gss_name_t *output_name)
95 {
96     OM_uint32 major;
97     krb5_error_code ret;
98     krb5_storage *sp;
99     uint32_t name_len = 0;
100     uint16_t tok_id;
101     gss_OID_desc oid_buf = { 0, NULL };
102     uint8_t is_anonymous;
103
104     sp = krb5_storage_from_readonly_mem(input_name_buffer->value,
105                                         input_name_buffer->length);
106     if (sp == NULL) {
107         *minor = ENOMEM;
108         return GSS_S_FAILURE;
109     }
110
111     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
112
113     major = GSS_S_BAD_NAME;
114     *minor = 0;
115
116     ret = krb5_ret_uint16(sp, &tok_id);
117     if (ret == 0 && tok_id != 0x0401)
118         ret = EINVAL;
119     if (ret == 0)
120         ret = storage_ret_der_oid(sp, &oid_buf);
121     if (ret == 0) {
122         if (!gss_oid_equal(&oid_buf, GSS_SANON_X25519_MECHANISM))
123             ret = EINVAL;
124         free(oid_buf.elements);
125     }
126     if (ret == 0)
127         ret = krb5_ret_uint32(sp, &name_len);
128     if (name_len != 1)
129         ret = EINVAL;
130     ret = krb5_ret_uint8(sp, &is_anonymous);
131     if (ret == 0) {
132         if (is_anonymous == 1) {
133             *output_name = _gss_sanon_anonymous_identity;
134             major = GSS_S_COMPLETE;
135         } else {
136             major = GSS_S_BAD_NAME;
137         }
138     }
139
140     krb5_storage_free(sp);
141
142     if (*minor == 0)
143         *minor = ret;
144
145     return major;
146 }
147
148 OM_uint32 GSSAPI_CALLCONV
149 _gss_sanon_import_name(OM_uint32 *minor,
150                        const gss_buffer_t input_name_buffer,
151                        const gss_OID input_name_type,
152                        gss_name_t *output_name)
153 {
154     heim_assert(input_name_type != GSS_C_NO_OID,
155                 "Mechglue passed null OID to _gss_sanon_import_name");
156
157     if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME))
158         return import_export_name(minor, input_name_buffer, output_name);
159
160     *minor = 0;
161     *output_name =
162         is_anonymous_identity_p(input_name_buffer, input_name_type) ?
163             _gss_sanon_anonymous_identity : _gss_sanon_non_anonymous_identity;
164
165     return GSS_S_COMPLETE;
166 }