summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auth/kerberos/gssapi_pac.c123
-rw-r--r--auth/kerberos/wscript_build3
-rw-r--r--libcli/auth/krb5_wrap.h5
-rw-r--r--libcli/auth/wscript_build2
-rw-r--r--source3/Makefile.in1
-rw-r--r--source3/configure.in1
-rw-r--r--source3/librpc/crypto/gse.c47
-rw-r--r--source3/librpc/crypto/gse.h3
-rw-r--r--source3/rpc_server/dcesrv_gssapi.c62
-rw-r--r--source3/wscript2
-rwxr-xr-xsource3/wscript_build1
-rw-r--r--wscript_build1
12 files changed, 152 insertions, 99 deletions
diff --git a/auth/kerberos/gssapi_pac.c b/auth/kerberos/gssapi_pac.c
new file mode 100644
index 0000000000..dd2fb7e0a7
--- /dev/null
+++ b/auth/kerberos/gssapi_pac.c
@@ -0,0 +1,123 @@
+/*
+ Unix SMB/CIFS implementation.
+ kerberos authorization data (PAC) utility library
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2011
+ Copyright (C) Simo Sorce 2010.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#ifdef HAVE_KRB5
+
+#include "libcli/auth/krb5_wrap.h"
+
+/* The Heimdal OID for getting the PAC */
+#define EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH 8
+/* EXTRACTION OID AUTHZ ID */
+#define EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID "\x2a\x85\x70\x2b\x0d\x03" "\x81\x00"
+
+static gss_OID_desc pac_data_oid = {
+ EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH,
+ (void *)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_error_string(mem_ctx, gss_maj, gss_min, gss_mech_krb5)));
+ 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,
+ &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_error_string(mem_ctx, gss_maj, gss_min, gss_mech_krb5)));
+ } 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
diff --git a/auth/kerberos/wscript_build b/auth/kerberos/wscript_build
new file mode 100644
index 0000000000..c289aab839
--- /dev/null
+++ b/auth/kerberos/wscript_build
@@ -0,0 +1,3 @@
+bld.SAMBA_SUBSYSTEM('KRB5_PAC',
+ source='gssapi_pac.c',
+ deps='gssapi_krb5 krb5 ndr-krb5pac')
diff --git a/libcli/auth/krb5_wrap.h b/libcli/auth/krb5_wrap.h
index 31bee352ab..82769aede9 100644
--- a/libcli/auth/krb5_wrap.h
+++ b/libcli/auth/krb5_wrap.h
@@ -72,3 +72,8 @@ NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
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);
diff --git a/libcli/auth/wscript_build b/libcli/auth/wscript_build
index 541eaf0434..262d483e06 100644
--- a/libcli/auth/wscript_build
+++ b/libcli/auth/wscript_build
@@ -41,4 +41,4 @@ bld.SAMBA_SUBSYSTEM('SPNEGO_PARSE',
bld.SAMBA_SUBSYSTEM('KRB5_WRAP',
source='krb5_wrap.c kerberos_pac.c',
- deps='gssapi krb5 ndr-krb5pac com_err')
+ deps='gssapi_krb5 krb5 ndr-krb5pac com_err KRB5_PAC')
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 3407dfd215..1e8b5bb994 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -598,6 +598,7 @@ LIBMSRPC_OBJ = $(SCHANNEL_OBJ) \
rpc_client/cli_pipe.o \
librpc/crypto/gse_krb5.o \
librpc/crypto/gse.o \
+ ../auth/kerberos/gssapi_pac.o \
librpc/crypto/cli_spnego.o \
librpc/rpc/rpc_common.o \
rpc_client/rpc_transport_np.o \
diff --git a/source3/configure.in b/source3/configure.in
index 556b8d3aee..883f0b1df0 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -3869,6 +3869,7 @@ if test x"$with_ads_support" != x"no"; then
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>])
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index 0d9eead082..42e9c942a9 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -62,16 +62,6 @@ gss_OID_desc gse_authz_data_oid = {
(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 {
@@ -692,42 +682,15 @@ NTSTATUS gse_get_authz_data(struct gse_context *gse_ctx,
return NT_STATUS_OK;
}
-NTSTATUS gse_get_authtime(struct gse_context *gse_ctx, time_t *authtime)
+NTSTATUS gse_get_pac_blob(struct gse_context *gse_ctx,
+ TALLOC_CTX *mem_ctx, DATA_BLOB *pac_blob)
{
- OM_uint32 gss_min, gss_maj;
- gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
- int32_t tkttime;
-
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;
- }
-
- 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 gssapi_obtain_pac_blob(mem_ctx, gse_ctx->gss_ctx,
+ gse_ctx->client_name, pac_blob);
}
size_t gse_get_signature_length(struct gse_context *gse_ctx,
@@ -1017,4 +980,4 @@ NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
return NT_STATUS_NOT_IMPLEMENTED;
}
-#endif /* HAVE_KRB5 && HAVE_GSSAPI_EXT_H && HAVE_GSS_WRAP_IOV */
+#endif /* HAVE_KRB5 && HAVE_GSS_WRAP_IOV */
diff --git a/source3/librpc/crypto/gse.h b/source3/librpc/crypto/gse.h
index fbcf5b6e10..27cc2e9255 100644
--- a/source3/librpc/crypto/gse.h
+++ b/source3/librpc/crypto/gse.h
@@ -56,7 +56,8 @@ 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_blob(struct gse_context *gse_ctx,
+ TALLOC_CTX *mem_ctx, DATA_BLOB *pac_blob);
size_t gse_get_signature_length(struct gse_context *gse_ctx,
int seal, size_t payload_size);
diff --git a/source3/rpc_server/dcesrv_gssapi.c b/source3/rpc_server/dcesrv_gssapi.c
index ec02459633..b63f4f129e 100644
--- a/source3/rpc_server/dcesrv_gssapi.c
+++ b/source3/rpc_server/dcesrv_gssapi.c
@@ -23,6 +23,7 @@
#include "../librpc/gen_ndr/ndr_krb5pac.h"
#include "librpc/crypto/gse.h"
#include "auth.h"
+#include "libcli/auth/krb5_wrap.h"
NTSTATUS gssapi_server_auth_start(TALLOC_CTX *mem_ctx,
bool do_sign,
@@ -105,14 +106,9 @@ NTSTATUS gssapi_server_get_user_info(struct gse_context *gse_ctx,
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;
+ DATA_BLOB pac_blob;
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;
@@ -122,14 +118,13 @@ NTSTATUS gssapi_server_get_user_info(struct gse_context *gse_ctx,
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_blob(gse_ctx, tmp_ctx, &pac_blob);
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
/* TODO: Fetch user by principal name ? */
status = NT_STATUS_ACCESS_DENIED;
@@ -139,37 +134,18 @@ NTSTATUS gssapi_server_get_user_info(struct gse_context *gse_ctx,
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);
+ status = kerberos_decode_pac(tmp_ctx,
+ pac_blob,
+ NULL, NULL, NULL, NULL, 0, &pac_data);
+ data_blob_free(&pac_blob);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
- status = gse_get_authtime(gse_ctx, &tgs_authtime);
+ status = gse_get_client_name(gse_ctx, tmp_ctx, &princ_name);
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++) {
@@ -182,9 +158,6 @@ NTSTATUS gssapi_server_get_user_info(struct gse_context *gse_ctx,
}
logon_info = data_buf->info->logon_info.info;
break;
- case PAC_TYPE_LOGON_NAME:
- logon_name = &data_buf->info->logon_name;
- break;
default:
break;
}
@@ -194,25 +167,6 @@ NTSTATUS gssapi_server_get_user_info(struct gse_context *gse_ctx,
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,
diff --git a/source3/wscript b/source3/wscript
index 49f11f2e5b..6081ac9d4d 100644
--- a/source3/wscript
+++ b/source3/wscript
@@ -632,7 +632,7 @@ msg.msg_acctrightslen = sizeof(fd);
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
diff --git a/source3/wscript_build b/source3/wscript_build
index dc01554c2e..8b337e6ccb 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -1327,6 +1327,7 @@ if not bld.env.toplevel_build:
bld.RECURSE('../lib/util/charset')
bld.RECURSE('../auth')
+bld.RECURSE('../auth/kerberos')
bld.RECURSE('../lib/addns')
bld.RECURSE('../lib/async_req')
bld.RECURSE('../libcli/auth')
diff --git a/wscript_build b/wscript_build
index d955f90dc2..174a25a282 100644
--- a/wscript_build
+++ b/wscript_build
@@ -49,6 +49,7 @@ bld.RECURSE('source4/smbd')
bld.RECURSE('source4/libnet')
bld.RECURSE('source4/auth')
bld.RECURSE('auth')
+bld.RECURSE('auth/kerberos')
bld.RECURSE('lib/iniparser/src')
bld.RECURSE('nsswitch')
bld.RECURSE('nsswitch/libwbclient')