summaryrefslogtreecommitdiffstats
path: root/third_party/heimdal/lib/gss_preauth/pa_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/heimdal/lib/gss_preauth/pa_common.c')
-rw-r--r--third_party/heimdal/lib/gss_preauth/pa_common.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/gss_preauth/pa_common.c b/third_party/heimdal/lib/gss_preauth/pa_common.c
new file mode 100644
index 0000000..00efde7
--- /dev/null
+++ b/third_party/heimdal/lib/gss_preauth/pa_common.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2021, PADL Software Pty Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of PADL Software nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <krb5_locl.h>
+#include <mech_locl.h>
+#include <heimntlm.h>
+
+#include "gss-preauth-protos.h"
+#include "gss-preauth-private.h"
+
+krb5_error_code
+_krb5_gss_map_error(OM_uint32 major, OM_uint32 minor)
+{
+ krb5_error_code ret;
+
+ if (minor != 0)
+ return (krb5_error_code)minor;
+
+ switch (major) {
+ case GSS_S_COMPLETE:
+ ret = 0;
+ break;
+ case GSS_S_CONTINUE_NEEDED:
+ ret = HEIM_ERR_PA_CONTINUE_NEEDED;
+ break;
+ case GSS_S_BAD_NAME:
+ case GSS_S_BAD_NAMETYPE:
+ ret = KRB5_PRINC_NOMATCH;
+ break;
+ case GSS_S_NO_CRED:
+ ret = KRB5_CC_NOTFOUND;
+ break;
+ case GSS_S_BAD_MIC:
+ case GSS_S_DEFECTIVE_CREDENTIAL:
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ break;
+ case GSS_S_FAILURE:
+ default:
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ break;
+ }
+
+ return ret;
+}
+
+krb5_error_code
+_krb5_gss_pa_derive_key(krb5_context context,
+ gss_ctx_id_t ctx,
+ krb5int32 nonce,
+ krb5_enctype enctype,
+ krb5_keyblock **keyblock)
+{
+ krb5_error_code ret;
+ u_char saltdata[12] = "KRB-GSS";
+ krb5_keyblock kdkey;
+ size_t keysize;
+
+ OM_uint32 major, minor;
+ gss_buffer_desc salt, dkey = GSS_C_EMPTY_BUFFER;
+
+ *keyblock = NULL;
+
+ ret = krb5_enctype_keysize(context, enctype, &keysize);
+ if (ret)
+ return ret;
+
+ saltdata[ 8] = (nonce >> 0 ) & 0xFF;
+ saltdata[ 9] = (nonce >> 8 ) & 0xFF;
+ saltdata[10] = (nonce >> 16) & 0xFF;
+ saltdata[11] = (nonce >> 24) & 0xFF;
+
+ salt.value = saltdata;
+ salt.length = sizeof(saltdata);
+
+ major = gss_pseudo_random(&minor, ctx, GSS_C_PRF_KEY_FULL,
+ &salt, keysize, &dkey);
+ if (GSS_ERROR(major))
+ return KRB5_PREAUTH_NO_KEY;
+
+ kdkey.keytype = enctype;
+ kdkey.keyvalue.data = dkey.value;
+ kdkey.keyvalue.length = dkey.length;
+
+ ret = krb5_copy_keyblock(context, &kdkey, keyblock);
+
+ if (dkey.value) {
+ memset_s(dkey.value, dkey.length, 0, dkey.length);
+ gss_release_buffer(&minor, &dkey);
+ }
+
+ return ret;
+}
+
+krb5_error_code
+_krb5_gss_pa_unparse_name(krb5_context context,
+ krb5_const_principal principal,
+ gss_name_t *namep)
+{
+ krb5_error_code ret;
+ char *name = NULL;
+
+ OM_uint32 major, minor;
+ gss_buffer_desc name_buf;
+
+ *namep = GSS_C_NO_NAME;
+
+ if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
+ if (principal->name.name_string.len != 1)
+ return EINVAL;
+
+ name = principal->name.name_string.val[0];
+ } else {
+ ret = krb5_unparse_name(context, principal, &name);
+ if (ret)
+ return ret;
+ }
+
+ name_buf.length = strlen(name);
+ name_buf.value = name;
+
+ major = gss_import_name(&minor, &name_buf,
+ GSS_KRB5_NT_PRINCIPAL_NAME, namep);
+ if (major == GSS_S_BAD_NAMETYPE) {
+ gss_OID name_type = GSS_C_NO_OID;
+ int flags = 0;
+
+ if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
+ name_type = GSS_C_NT_USER_NAME;
+ } else if (principal->name.name_type == KRB5_NT_PRINCIPAL) {
+ flags = KRB5_PRINCIPAL_UNPARSE_SHORT;
+ name_type = GSS_C_NT_USER_NAME;
+ } else if ((principal->name.name_type == KRB5_NT_SRV_HST ||
+ principal->name.name_type == KRB5_NT_SRV_INST) &&
+ principal->name.name_string.len == 2) {
+ flags = KRB5_PRINCIPAL_UNPARSE_NO_REALM;
+ name_type = GSS_C_NT_HOSTBASED_SERVICE;
+ }
+
+ if (flags) {
+ krb5_xfree(name);
+
+ ret = krb5_unparse_name_flags(context, principal, flags, &name);
+ if (ret)
+ return ret;
+
+ if (gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE)) {
+ char *inst = strchr(name, '/');
+ if (inst)
+ *inst = '@';
+ }
+
+ name_buf.length = strlen(name);
+ name_buf.value = name;
+ }
+
+ if (name_type)
+ major = gss_import_name(&minor, &name_buf, name_type, namep);
+ }
+
+ if (name != principal->name.name_string.val[0])
+ krb5_xfree(name);
+
+ return _krb5_gss_map_error(major, minor);
+}
+
+krb5_error_code
+_krb5_gss_pa_parse_name(krb5_context context,
+ gss_const_name_t name,
+ int flags,
+ krb5_principal *principal)
+{
+ krb5_error_code ret;
+ char *displayed_name0;
+
+ OM_uint32 major, minor;
+ gss_OID name_type = GSS_C_NO_OID;
+ gss_buffer_desc displayed_name = GSS_C_EMPTY_BUFFER;
+
+ major = gss_display_name(&minor, name, &displayed_name, &name_type);
+ if (GSS_ERROR(major))
+ return _krb5_gss_map_error(major, minor);
+
+ if (gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)) {
+ ret = krb5_make_principal(context, principal, KRB5_ANON_REALM,
+ KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL);
+ if (ret == 0)
+ (*principal)->name.name_type = KRB5_NT_WELLKNOWN;
+ } else {
+ displayed_name0 = malloc(displayed_name.length + 1);
+ if (displayed_name0 == NULL)
+ return krb5_enomem(context);
+
+ memcpy(displayed_name0, displayed_name.value, displayed_name.length);
+ displayed_name0[displayed_name.length] = '\0';
+
+ ret = krb5_parse_name_flags(context, displayed_name0, flags, principal);
+ gss_release_buffer(&minor, &displayed_name);
+ free(displayed_name0);
+ }
+
+ gss_release_buffer(&minor, &displayed_name);
+
+ return ret;
+}
+
+void
+_krb5_gss_data_to_buffer(const krb5_data *data, gss_buffer_t buffer)
+{
+ if (data) {
+ buffer->length = data->length;
+ buffer->value = data->data;
+ } else {
+ _mg_buffer_zero(buffer);
+ }
+}
+
+void
+_krb5_gss_buffer_to_data(gss_const_buffer_t buffer, krb5_data *data)
+{
+ if (buffer) {
+ data->length = buffer->length;
+ data->data = buffer->value;
+ } else {
+ krb5_data_zero(data);
+ }
+}