return NT_STATUS_OK;
}
+/* The Heimdal OID for getting the PAC */
+#define GSE_EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH 8
+/* EXTRACTION OID AUTHZ ID */
+#define GSE_EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID "\x2a\x85\x70\x2b\x0d\x03" "\x81\x00"
+
+static gss_OID_desc gse_pac_data_oid = {
+ GSE_EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH,
+ (void *)GSE_EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID
+};
+
+NTSTATUS gssapi_obtain_pac_blob(TALLOC_CTX *mem_ctx,
+ gss_ctx_id_t gssapi_context,
+ gss_name_t gss_client_name,
+ DATA_BLOB *pac_blob)
+{
+ OM_uint32 gss_maj, gss_min;
+ gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
+ gss_buffer_desc pac_buffer;
+ gss_buffer_desc pac_display_buffer;
+ gss_buffer_desc pac_name = {
+ .value = "urn:mspac:",
+ .length = sizeof("urn:mspac:")-1
+ };
+ NTSTATUS status;
+ int more = -1;
+ int authenticated = false;
+ int complete = false;
+
+#ifdef HAVE_GSS_GET_NAME_ATTRIBUTE
+ gss_maj = gss_get_name_attribute(
+ &gss_min, gss_client_name, &pac_name,
+ &authenticated, &complete,
+ &pac_buffer, &pac_display_buffer, &more);
+
+ if (gss_maj != 0) {
+ DEBUG(0, ("obtaining PAC via GSSAPI gss_get_name_attribute failed: %s\n",
+ gssapi_krb5_errstr(mem_ctx, gss_maj, gss_min)));
+ return NT_STATUS_ACCESS_DENIED;
+ } else if (authenticated && complete) {
+ /* The PAC blob is returned directly */
+ *pac_blob = data_blob_talloc(mem_ctx, pac_buffer.value,
+ pac_buffer.length);
+
+ if (!pac_blob->data) {
+ status = NT_STATUS_NO_MEMORY;
+ } else {
+ status = NT_STATUS_OK;
+ }
+
+ gss_maj = gss_release_buffer(&gss_min, &pac_buffer);
+ gss_maj = gss_release_buffer(&gss_min, &pac_display_buffer);
+ return status;
+ } else {
+ DEBUG(0, ("obtaining PAC via GSSAPI failed: authenticated: %s, complete: %s, more: %s\n",
+ authenticated ? "true" : "false",
+ complete ? "true" : "false",
+ more ? "true" : "false"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+#endif
+ /* If we didn't have the routine to get a verified, validated
+ * PAC (supplied only by MIT at the time of writing), then try
+ * with the Heimdal OID (fetches the PAC directly and always
+ * validates) */
+ gss_maj = gss_inquire_sec_context_by_oid(
+ &gss_min, gssapi_context,
+ &gse_pac_data_oid, &set);
+
+ /* First check for the error MIT gives for an unknown OID */
+ if (gss_maj == GSS_S_UNAVAILABLE) {
+ DEBUG(1, ("unable to obtain a PAC against this GSSAPI library. "
+ "GSSAPI secured connections are available only with Heimdal or MIT Kerberos >= 1.8\n"));
+ } else if (gss_maj != 0) {
+ DEBUG(2, ("obtaining PAC via GSSAPI gss_inqiure_sec_context_by_oid (Heimdal OID) failed: %s\n",
+ gssapi_krb5_errstr(mem_ctx, gss_maj, gss_min)));
+ } else {
+ if (set == GSS_C_NO_BUFFER_SET) {
+ DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
+ "data in results.\n"));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /* The PAC blob is returned directly */
+ *pac_blob = data_blob_talloc(mem_ctx, set->elements[0].value,
+ set->elements[0].length);
+ if (!pac_blob->data) {
+ status = NT_STATUS_NO_MEMORY;
+ } else {
+ status = NT_STATUS_OK;
+ }
+
+ gss_maj = gss_release_buffer_set(&gss_min, &set);
+ return status;
+ }
+ return NT_STATUS_ACCESS_DENIED;
+}
#endif
krb5_const_principal client_principal,
time_t tgs_authtime,
struct PAC_DATA **pac_data_out);
+
+NTSTATUS gssapi_obtain_pac_blob(TALLOC_CTX *mem_ctx,
+ gss_ctx_id_t gssapi_context,
+ gss_name_t gss_client_name,
+ DATA_BLOB *pac_data);
bld.SAMBA_SUBSYSTEM('KRB5_WRAP',
source='krb5_wrap.c kerberos_pac.c',
- deps='gssapi krb5 ndr-krb5pac')
+ deps='gssapi_krb5 krb5 ndr-krb5pac')
libads/disp_sec.o libads/ldap_utils.o \
libads/ldap_schema.o libads/util.o libads/ndr.o
-LIBADS_SERVER_OBJ = libads/kerberos_verify.o libads/authdata.o ../libcli/auth/kerberos_pac.o \
+LIBADS_SERVER_OBJ = libads/kerberos_verify.o libads/authdata.o \
+ ../libcli/auth/kerberos_pac.o \
../librpc/ndr/ndr_krb5pac.o \
librpc/gen_ndr/ndr_krb5pac.o
../librpc/rpc/dcerpc_util.o \
../librpc/rpc/binding_handle.o \
librpc/rpc/dcerpc_helpers.o \
- $(LIBCLI_EPMAPPER_OBJ)
+ $(LIBCLI_EPMAPPER_OBJ) \
+ $(LIBADS_SERVER_OBJ)
LIBMSRPC_GEN_OBJ = $(LIBNDR_GEN_OBJ)
$(LIB_OBJ) $(PRINTBACKEND_OBJ) $(OPLOCK_OBJ) \
$(NOTIFY_OBJ) $(FNAME_UTIL_OBJ) $(GROUPDB_OBJ) $(AUTH_OBJ) \
$(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(AVAHI_OBJ) \
- $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(LIBADS_SERVER_OBJ) $(LIBADS_PRINTER_OBJ) \
+ $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(LIBADS_PRINTER_OBJ) \
$(REG_FULL_OBJ) $(POPT_LIB_OBJ) $(BUILDOPT_OBJ) \
$(SMBLDAP_OBJ) $(LIBNET_OBJ) \
$(LIBSMBCONF_OBJ) \
$(PASSDB_OBJ) $(GROUPDB_OBJ) \
$(KRBCLIENT_OBJ) $(LIB_NONSMBD_OBJ) $(LIBADDNS_OBJ0) \
$(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) \
- $(LIBADS_OBJ) $(LIBADS_SERVER_OBJ) $(LIBADS_PRINTER_OBJ) $(POPT_LIB_OBJ) \
+ $(LIBADS_OBJ) $(LIBADS_PRINTER_OBJ) $(POPT_LIB_OBJ) \
$(SMBLDAP_OBJ) $(DCUTIL_OBJ) \
$(AFS_OBJ) $(AFS_SETTOKEN_OBJ) $(READLINE_OBJ) \
$(LIBGPO_OBJ) @BUILD_INIPARSER@ $(DISPLAY_SEC_OBJ) \
@LIBWBCLIENT_STATIC@ \
torture/wbc_async.o \
../nsswitch/wb_reqtrans.o \
- $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(LIBCLI_ECHO_OBJ)
+ $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(LIBCLI_ECHO_OBJ) $(SERVER_MUTEX_OBJ)
MASKTEST_OBJ = torture/masktest.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
$(LIB_NONSMBD_OBJ) \
$(RPC_NCACN_NP) $(RPC_SAMR_OBJ) $(RPC_LSARPC_OBJ) \
$(NPA_TSTREAM_OBJ) \
$(AFS_OBJ) $(AFS_SETTOKEN_OBJ) \
- $(LIBADS_SERVER_OBJ) \
$(TDB_VALIDATE_OBJ) \
$(LIBCLI_DSSETUP_OBJ) \
$(LIBCLI_LSA_OBJ) \
AC_CHECK_FUNC_EXT(krb5_get_host_realm, $KRB5_LIBS)
AC_CHECK_FUNC_EXT(krb5_free_host_realm, $KRB5_LIBS)
AC_CHECK_FUNC_EXT(gss_krb5_import_cred, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(gss_get_name_attribute, $KRB5_LIBS)
# MIT krb5 1.8 does not expose this call (yet)
AC_CHECK_DECLS(krb5_get_credentials_for_user, [], [], [#include <krb5.h>])
(void *)GSS_KRB5_SESSION_KEY_ENCTYPE_OID
};
-#define GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID_LENGTH 12
-/* EXTRACTION OID AUTHZ ID */
-#define GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0a" "\x01"
-
-gss_OID_desc gse_authz_data_oid = {
- GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID_LENGTH,
- (void *)GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID
-};
-
-#ifndef GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID
-#define GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH 11
-#define GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0c"
-#endif
-
-gss_OID_desc gse_authtime_oid = {
- GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH,
- (void *)GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID
-};
-
-static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
-
struct gse_context {
krb5_context k5ctx;
krb5_ccache ccache;
return NT_STATUS_OK;
}
-NTSTATUS gse_get_authz_data(struct gse_context *gse_ctx,
- TALLOC_CTX *mem_ctx, DATA_BLOB *pac)
-{
- OM_uint32 gss_min, gss_maj;
- gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
-
- if (!gse_ctx->authenticated) {
- return NT_STATUS_ACCESS_DENIED;
- }
-
- gss_maj = gss_inquire_sec_context_by_oid(
- &gss_min, gse_ctx->gss_ctx,
- &gse_authz_data_oid, &set);
- if (gss_maj) {
- DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
- gse_errstr(talloc_tos(), gss_maj, gss_min)));
- return NT_STATUS_NOT_FOUND;
- }
-
- if (set == GSS_C_NO_BUFFER_SET) {
- DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
- "data in results.\n"));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- /* for now we just hope it is the first value */
- *pac = data_blob_talloc(mem_ctx,
- set->elements[0].value,
- set->elements[0].length);
-
- gss_maj = gss_release_buffer_set(&gss_min, &set);
-
- return NT_STATUS_OK;
-}
-
-NTSTATUS gse_get_authtime(struct gse_context *gse_ctx, time_t *authtime)
+NTSTATUS gse_get_pac_data(struct gse_context *gse_ctx,
+ TALLOC_CTX *mem_ctx, struct PAC_DATA **pac)
{
OM_uint32 gss_min, gss_maj;
gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
- int32_t tkttime;
+ NTSTATUS status;
+ DATA_BLOB pac_blob;
if (!gse_ctx->authenticated) {
return NT_STATUS_ACCESS_DENIED;
}
- gss_maj = gss_inquire_sec_context_by_oid(
- &gss_min, gse_ctx->gss_ctx,
- &gse_authtime_oid, &set);
- if (gss_maj) {
- DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
- gse_errstr(talloc_tos(), gss_maj, gss_min)));
- return NT_STATUS_NOT_FOUND;
+ status = gssapi_obtain_pac_blob(mem_ctx, gse_ctx->gss_ctx,
+ gse_ctx->client_name, &pac_blob);
+ if (NT_STATUS_IS_OK(status)) {
+ status = kerberos_decode_pac(mem_ctx,
+ pac_blob,
+ NULL, NULL, NULL, NULL, 0, pac);
+ data_blob_free(&pac_blob);
}
-
- if ((set == GSS_C_NO_BUFFER_SET) || (set->count != 1) != 0) {
- DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
- "data in results.\n"));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- if (set->elements[0].length != sizeof(int32_t)) {
- DEBUG(0, ("Invalid authtime size!\n"));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- tkttime = *((int32_t *)set->elements[0].value);
-
- gss_maj = gss_release_buffer_set(&gss_min, &set);
-
- *authtime = (time_t)tkttime;
- return NT_STATUS_OK;
+ return status;
}
size_t gse_get_signature_length(struct gse_context *gse_ctx,
return NT_STATUS_NOT_IMPLEMENTED;
}
-NTSTATUS gse_get_authz_data(struct gse_context *gse_ctx,
- TALLOC_CTX *mem_ctx, DATA_BLOB *pac)
-{
- return NT_STATUS_NOT_IMPLEMENTED;
-}
-
-NTSTATUS gse_get_authtime(struct gse_context *gse_ctx, time_t *authtime)
+NTSTATUS gse_get_pac_data(struct gse_context *gse_ctx,
+ TALLOC_CTX *mem_ctx, struct PAC_DATA **pac)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
return NT_STATUS_NOT_IMPLEMENTED;
}
-#endif /* HAVE_KRB5 && HAVE_GSSAPI_EXT_H && HAVE_GSS_WRAP_IOV */
+#endif /* HAVE_KRB5 && HAVE_GSS_WRAP_IOV */
#define _GSE_H_
struct gse_context;
+struct PAC_DATA;
#ifndef GSS_C_DCE_STYLE
#define GSS_C_DCE_STYLE 0x1000
struct gse_context *gse_ctx);
NTSTATUS gse_get_client_name(struct gse_context *gse_ctx,
TALLOC_CTX *mem_ctx, char **client_name);
-NTSTATUS gse_get_authz_data(struct gse_context *gse_ctx,
- TALLOC_CTX *mem_ctx, DATA_BLOB *pac);
-NTSTATUS gse_get_authtime(struct gse_context *gse_ctx, time_t *authtime);
+NTSTATUS gse_get_pac_data(struct gse_context *gse_ctx,
+ TALLOC_CTX *mem_ctx, struct PAC_DATA **pac);
size_t gse_get_signature_length(struct gse_context *gse_ctx,
int seal, size_t payload_size);
struct auth_serversupplied_info **server_info)
{
TALLOC_CTX *tmp_ctx;
- DATA_BLOB auth_data;
- time_t tgs_authtime;
- NTTIME tgs_authtime_nttime;
- DATA_BLOB pac;
struct PAC_DATA *pac_data;
- struct PAC_LOGON_NAME *logon_name = NULL;
struct PAC_LOGON_INFO *logon_info = NULL;
- enum ndr_err_code ndr_err;
unsigned int i;
bool is_mapped;
bool is_guest;
char *username;
struct passwd *pw;
NTSTATUS status;
- bool bret;
tmp_ctx = talloc_new(mem_ctx);
if (!tmp_ctx) {
return NT_STATUS_NO_MEMORY;
}
- status = gse_get_authz_data(gse_ctx, tmp_ctx, &auth_data);
+ status = gse_get_pac_data(gse_ctx, tmp_ctx, &pac_data);
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
/* TODO: Fetch user by principal name ? */
status = NT_STATUS_ACCESS_DENIED;
goto done;
}
- bret = unwrap_pac(tmp_ctx, &auth_data, &pac);
- if (!bret) {
- DEBUG(1, ("Failed to unwrap PAC\n"));
- status = NT_STATUS_ACCESS_DENIED;
- goto done;
- }
-
status = gse_get_client_name(gse_ctx, tmp_ctx, &princ_name);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
- status = gse_get_authtime(gse_ctx, &tgs_authtime);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
- unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime);
-
- pac_data = talloc_zero(tmp_ctx, struct PAC_DATA);
- if (!pac_data) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
- ndr_err = ndr_pull_struct_blob(&pac, pac_data, pac_data,
- (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- DEBUG(1, ("Failed to parse the PAC for %s\n", princ_name));
- status = ndr_map_error2ntstatus(ndr_err);
- goto done;
- }
-
/* get logon name and logon info */
for (i = 0; i < pac_data->num_buffers; i++) {
struct PAC_BUFFER *data_buf = &pac_data->buffers[i];
}
logon_info = data_buf->info->logon_info.info;
break;
- case PAC_TYPE_LOGON_NAME:
- logon_name = &data_buf->info->logon_name;
- break;
default:
break;
}
status = NT_STATUS_NOT_FOUND;
goto done;
}
- if (!logon_name) {
- DEBUG(1, ("Invalid PAC data, missing logon info!\n"));
- status = NT_STATUS_NOT_FOUND;
- goto done;
- }
-
- /* check time */
- if (tgs_authtime_nttime != logon_name->logon_time) {
- DEBUG(1, ("Logon time mismatch between ticket and PAC!\n"
- "PAC Time = %s | Ticket Time = %s\n",
- nt_time_string(tmp_ctx, logon_name->logon_time),
- nt_time_string(tmp_ctx, tgs_authtime_nttime)));
- status = NT_STATUS_ACCESS_DENIED;
- goto done;
- }
-
- /* TODO: Should we check princ_name against account_name in
- * logon_name ? Are they supposed to be identical, or can an
- * account_name be different from the UPN ? */
status = get_user_from_kerberos_info(tmp_ctx, client_id->name,
princ_name, logon_info,
if conf.CHECK_FUNCS_IN('gss_display_status', 'gssapi') or \
conf.CHECK_FUNCS_IN('gss_display_status', 'gssapi_krb5'):
have_gssapi=True
- conf.CHECK_FUNCS_IN('gss_wrap_iov gss_krb5_import_cred', 'gssapi gssapi_krb5 krb5')
+ conf.CHECK_FUNCS_IN('gss_wrap_iov gss_krb5_import_cred gss_get_name_attribute', 'gssapi gssapi_krb5 krb5')
conf.CHECK_FUNCS_IN('krb5_mk_req_extended krb5_kt_compare', 'krb5')
conf.CHECK_FUNCS('''
krb5_set_real_time krb5_set_default_in_tkt_etypes krb5_set_default_tgs_enctypes