#include "includes.h"
#include "gse.h"
+#include "libads/kerberos_proto.h"
#if defined(HAVE_KRB5) && defined(HAVE_GSS_WRAP_IOV)
#include "smb_krb5.h"
#include "gse_krb5.h"
-#include <gssapi/gssapi.h>
-#include <gssapi/gssapi_krb5.h>
-#ifdef HAVE_GSSAPI_GSSAPI_EXT_H
-#include <gssapi/gssapi_ext.h>
-#endif
-
#ifndef GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
return NT_STATUS_NO_MEMORY;
}
- name_buffer.value = talloc_asprintf(gse_ctx,
- "%s@%s", service, server);
+ /* Guess the realm based on the supplied service, and avoid the GSS libs
+ doing DNS lookups which may fail.
+
+ TODO: Loop with the KDC on some more combinations (local
+ realm in particular), possibly falling back to
+ GSS_C_NT_HOSTBASED_SERVICE
+ */
+ name_buffer.value = kerberos_get_principal_from_service_hostname(gse_ctx,
+ service, server);
if (!name_buffer.value) {
status = NT_STATUS_NO_MEMORY;
goto err_out;
}
name_buffer.length = strlen((char *)name_buffer.value);
gss_maj = gss_import_name(&gss_min, &name_buffer,
- GSS_C_NT_HOSTBASED_SERVICE,
+ GSS_C_NT_USER_NAME,
&gse_ctx->server_name);
if (gss_maj) {
DEBUG(0, ("gss_import_name failed for %s, with [%s]\n",
gse_ctx->gss_c_flags,
0, GSS_C_NO_CHANNEL_BINDINGS,
&in_data, NULL, &out_data,
- NULL, NULL);
+ &gse_ctx->ret_flags, NULL);
switch (gss_maj) {
case GSS_S_COMPLETE:
/* we are done with it */
OM_uint32 gss_maj, gss_min;
krb5_error_code ret;
NTSTATUS status;
- const char *ktname;
- gss_OID_set_desc mech_set;
status = gse_context_init(mem_ctx, do_sign, do_seal,
NULL, add_gss_c_flags, &gse_ctx);
}
#ifdef HAVE_GSS_KRB5_IMPORT_CRED
- /* This creates a GSSAPI cred_id_t with the principal and keytab set */
+
+ /* This creates a GSSAPI cred_id_t with the keytab set */
gss_maj = gss_krb5_import_cred(&gss_min, NULL, NULL, gse_ctx->keytab,
- &gse_ctx->creds);
- if (gss_maj) {
+ &gse_ctx->creds);
+
+ if (gss_maj != 0
+ && gss_maj != (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
DEBUG(0, ("gss_krb5_import_cred failed with [%s]\n",
gse_errstr(gse_ctx, gss_maj, gss_min)));
status = NT_STATUS_INTERNAL_ERROR;
goto done;
- }
-#else
+
+ /* This is the error the MIT krb5 1.9 gives when it
+ * implements the function, but we do not specify the
+ * principal. However, when we specify the principal
+ * as host$@REALM the GSS acceptor fails with 'wrong
+ * principal in request'. Work around the issue by
+ * falling back to the alternate approach below. */
+ } else if (gss_maj == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME))
+#endif
/* FIXME!!!
* This call sets the default keytab for the whole server, not
* just for this context. Need to find a way that does not alter
* the state of the whole server ... */
+ {
+ const char *ktname;
+ gss_OID_set_desc mech_set;
- ret = smb_krb5_keytab_name(gse_ctx, gse_ctx->k5ctx,
+ ret = smb_krb5_keytab_name(gse_ctx, gse_ctx->k5ctx,
gse_ctx->keytab, &ktname);
- if (ret) {
- status = NT_STATUS_INTERNAL_ERROR;
- goto done;
- }
+ if (ret) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto done;
+ }
- ret = gsskrb5_register_acceptor_identity(ktname);
- if (ret) {
- status = NT_STATUS_INTERNAL_ERROR;
- goto done;
- }
+ ret = gsskrb5_register_acceptor_identity(ktname);
+ if (ret) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto done;
+ }
- mech_set.count = 1;
- mech_set.elements = &gse_ctx->gss_mech;
-
- gss_maj = gss_acquire_cred(&gss_min,
+ mech_set.count = 1;
+ mech_set.elements = &gse_ctx->gss_mech;
+
+ gss_maj = gss_acquire_cred(&gss_min,
GSS_C_NO_NAME,
GSS_C_INDEFINITE,
&mech_set,
&gse_ctx->creds,
NULL, NULL);
- if (gss_maj) {
- DEBUG(0, ("gss_acquire_creds failed with [%s]\n",
- gse_errstr(gse_ctx, gss_maj, gss_min)));
- status = NT_STATUS_INTERNAL_ERROR;
- goto done;
+ if (gss_maj) {
+ DEBUG(0, ("gss_acquire_creds failed with [%s]\n",
+ gse_errstr(gse_ctx, gss_maj, gss_min)));
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto done;
+ }
}
-#endif
+
status = NT_STATUS_OK;
done:
if (gss_maj) {
goto done;
}
+ errstr = talloc_strndup(mem_ctx,
+ (char *)msg_maj.value,
+ msg_maj.length);
+ if (!errstr) {
+ goto done;
+ }
gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE,
(gss_OID)discard_const(gss_mech_krb5),
&msg_ctx, &msg_min);
goto done;
}
- errstr = talloc_strndup(mem_ctx,
- (char *)msg_maj.value,
- msg_maj.length);
- if (!errstr) {
- goto done;
- }
errstr = talloc_strdup_append_buffer(errstr, ": ");
if (!errstr) {
goto done;
(memcmp(set->elements[1].value,
gse_sesskeytype_oid.elements,
gse_sesskeytype_oid.length) != 0)) {
+#ifdef HAVE_GSSKRB5_GET_SUBKEY
+ krb5_keyblock *subkey;
+ gss_maj = gsskrb5_get_subkey(&gss_min,
+ gse_ctx->gss_ctx,
+ &subkey);
+ if (gss_maj != 0) {
+ DEBUG(1, ("NO session key for this mech\n"));
+ return data_blob_null;
+ }
+ ret = data_blob_talloc(mem_ctx,
+ KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
+ krb5_free_keyblock(NULL /* should be krb5_context */, subkey);
+ return ret;
+#else
DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
"OID for data in results:\n"));
dump_data(1, (uint8_t *)set->elements[1].value,
set->elements[1].length);
return data_blob_null;
+#endif
}
ret = data_blob_talloc(mem_ctx, set->elements[0].value,
OM_uint32 gss_min, gss_maj;
gss_iov_buffer_desc iov[2];
int req_seal = 1; /* setting to 1 means we request sign+seal */
- int sealed;
+ int sealed = 1;
NTSTATUS status;
/* allocate the memory ourselves so we do not need to talloc_memdup */