#include "lib/tsocket/tsocket.h"
#include "librpc/rpc/dcerpc.h"
#include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_krb5.h"
+#include "auth/kerberos/kerberos_credentials.h"
#include "auth/gensec/gensec.h"
#include "auth/gensec/gensec_proto.h"
+#include "auth/gensec/gensec_toplevel_proto.h"
#include "param/param.h"
#include "auth/auth_sam_reply.h"
+#include "lib/util/util_net.h"
+
+_PUBLIC_ NTSTATUS gensec_krb5_init(void);
enum GENSEC_KRB5_STATE {
GENSEC_KRB5_SERVER_START,
};
struct gensec_krb5_state {
- DATA_BLOB session_key;
- DATA_BLOB pac;
enum GENSEC_KRB5_STATE state_position;
struct smb_krb5_context *smb_krb5_context;
krb5_auth_context auth_context;
krb5_error_code ret;
struct gensec_krb5_state *gensec_krb5_state;
struct cli_credentials *creds;
- const struct socket_address *peer_addr;
- const struct tsocket_address *tlocal_addr;
+ const struct tsocket_address *tlocal_addr, *tremote_addr;
krb5_address my_krb5_addr, peer_krb5_addr;
creds = gensec_get_credentials(gensec_security);
gensec_krb5_state->ticket = NULL;
ZERO_STRUCT(gensec_krb5_state->enc_ticket);
gensec_krb5_state->keyblock = NULL;
- gensec_krb5_state->session_key = data_blob(NULL, 0);
- gensec_krb5_state->pac = data_blob(NULL, 0);
gensec_krb5_state->gssapi = gssapi;
talloc_set_destructor(gensec_krb5_state, gensec_krb5_destroy);
if (cli_credentials_get_krb5_context(creds,
- gensec_security->event_ctx,
gensec_security->settings->lp_ctx, &gensec_krb5_state->smb_krb5_context)) {
talloc_free(gensec_krb5_state);
return NT_STATUS_INTERNAL_ERROR;
(struct sockaddr *) &ss,
sizeof(struct sockaddr_storage));
if (socklen < 0) {
+ talloc_free(gensec_krb5_state);
return NT_STATUS_INTERNAL_ERROR;
}
ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context,
}
}
- peer_addr = gensec_get_peer_addr(gensec_security);
- if (peer_addr && peer_addr->sockaddr) {
- ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context,
- peer_addr->sockaddr, &peer_krb5_addr);
+ tremote_addr = gensec_get_remote_address(gensec_security);
+ if (tremote_addr) {
+ ssize_t socklen;
+ struct sockaddr_storage ss;
+
+ socklen = tsocket_address_bsd_sockaddr(tremote_addr,
+ (struct sockaddr *) &ss,
+ sizeof(struct sockaddr_storage));
+ if (socklen < 0) {
+ talloc_free(gensec_krb5_state);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context,
+ (const struct sockaddr *) &ss, &peer_krb5_addr);
if (ret) {
DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n",
smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context,
ret = krb5_auth_con_setaddrs(gensec_krb5_state->smb_krb5_context->krb5_context,
gensec_krb5_state->auth_context,
tlocal_addr ? &my_krb5_addr : NULL,
- peer_addr ? &peer_krb5_addr : NULL);
+ tremote_addr ? &peer_krb5_addr : NULL);
if (ret) {
DEBUG(1,("gensec_krb5_start: krb5_auth_con_setaddrs failed (%s)\n",
smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context,
static NTSTATUS gensec_krb5_common_client_start(struct gensec_security *gensec_security, bool gssapi)
{
+ const char *hostname;
struct gensec_krb5_state *gensec_krb5_state;
- krb5_error_code ret;
NTSTATUS nt_status;
- struct ccache_container *ccache_container;
- const char *hostname;
-
- const char *principal;
- krb5_data in_data;
-
hostname = gensec_get_target_hostname(gensec_security);
if (!hostname) {
DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
gensec_krb5_state->ap_req_options |= AP_OPTS_MUTUAL_REQUIRED;
}
}
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS gensec_krb5_common_client_creds(struct gensec_security *gensec_security, bool gssapi)
+{
+ struct gensec_krb5_state *gensec_krb5_state;
+ krb5_error_code ret;
+ struct ccache_container *ccache_container;
+ const char *error_string;
+ const char *principal;
+ const char *hostname;
+ krb5_data in_data;
+ struct tevent_context *previous_ev;
+
+ gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
principal = gensec_get_target_principal(gensec_security);
+ hostname = gensec_get_target_hostname(gensec_security);
ret = cli_credentials_get_ccache(gensec_get_credentials(gensec_security),
gensec_security->event_ctx,
- gensec_security->settings->lp_ctx, &ccache_container);
+ gensec_security->settings->lp_ctx, &ccache_container, &error_string);
switch (ret) {
case 0:
break;
case KRB5KDC_ERR_PREAUTH_FAILED:
+ case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
return NT_STATUS_LOGON_FAILURE;
case KRB5_KDC_UNREACH:
- DEBUG(3, ("Cannot reach a KDC we require to contact %s\n", principal));
+ DEBUG(3, ("Cannot reach a KDC we require to contact %s: %s\n", principal, error_string));
+ return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
+ case KRB5_CC_NOTFOUND:
+ case KRB5_CC_END:
+ DEBUG(3, ("Error preparing credentials we require to contact %s : %s\n", principal, error_string));
return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
default:
- DEBUG(1, ("gensec_krb5_start: Aquiring initiator credentials failed: %s\n", error_message(ret)));
+ DEBUG(1, ("gensec_krb5_start: Aquiring initiator credentials failed: %s\n", error_string));
return NT_STATUS_UNSUCCESSFUL;
}
in_data.length = 0;
- if (principal && lp_client_use_spnego_principal(gensec_security->settings->lp_ctx)) {
+ /* Do this every time, in case we have weird recursive issues here */
+ ret = smb_krb5_context_set_event_ctx(gensec_krb5_state->smb_krb5_context, gensec_security->event_ctx, &previous_ev);
+ if (ret != 0) {
+ DEBUG(1, ("gensec_krb5_start: Setting event context failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (principal) {
krb5_principal target_principal;
ret = krb5_parse_name(gensec_krb5_state->smb_krb5_context->krb5_context, principal,
&target_principal);
&in_data, ccache_container->ccache,
&gensec_krb5_state->enc_ticket);
}
+
+ smb_krb5_context_remove_event_ctx(gensec_krb5_state->smb_krb5_context, previous_ev, gensec_security->event_ctx);
+
switch (ret) {
case 0:
return NT_STATUS_OK;
{
DATA_BLOB unwrapped_out;
+ nt_status = gensec_krb5_common_client_creds(gensec_security, gensec_krb5_state->gssapi);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
if (gensec_krb5_state->gssapi) {
unwrapped_out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->enc_ticket.data, gensec_krb5_state->enc_ticket.length);
uint8_t tok_id[2];
struct keytab_container *keytab;
krb5_principal server_in_keytab;
+ const char *error_string;
+ enum credentials_obtained obtained;
if (!in.data) {
return NT_STATUS_INVALID_PARAMETER;
/* Grab the keytab, however generated */
ret = cli_credentials_get_keytab(gensec_get_credentials(gensec_security),
- gensec_security->event_ctx,
gensec_security->settings->lp_ctx, &keytab);
if (ret) {
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
/* This ensures we lookup the correct entry in that keytab */
ret = principal_from_credentials(out_mem_ctx, gensec_get_credentials(gensec_security),
gensec_krb5_state->smb_krb5_context,
- &server_in_keytab);
+ &server_in_keytab, &obtained, &error_string);
if (ret) {
+ DEBUG(2,("Failed to make credentials from principal: %s\n", error_string));
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
}
static NTSTATUS gensec_krb5_session_key(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
DATA_BLOB *session_key)
{
struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
return NT_STATUS_NO_USER_SESSION_KEY;
}
- if (gensec_krb5_state->session_key.data) {
- *session_key = gensec_krb5_state->session_key;
- return NT_STATUS_OK;
- }
-
switch (gensec_security->gensec_role) {
case GENSEC_CLIENT:
err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey);
if (err == 0 && skey != NULL) {
DEBUG(10, ("Got KRB5 session key of length %d\n",
(int)KRB5_KEY_LENGTH(skey)));
- gensec_krb5_state->session_key = data_blob_talloc(gensec_krb5_state,
- KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
- *session_key = gensec_krb5_state->session_key;
+ *session_key = data_blob_talloc(mem_ctx,
+ KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
krb5_free_keyblock(context, skey);
}
static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx_out,
struct auth_session_info **_session_info)
{
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context;
- struct auth_serversupplied_info *server_info = NULL;
+ struct auth_user_info_dc *user_info_dc = NULL;
struct auth_session_info *session_info = NULL;
struct PAC_LOGON_INFO *logon_info;
krb5_error_code ret;
- TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
+ TALLOC_CTX *mem_ctx = talloc_new(mem_ctx_out);
if (!mem_ctx) {
return NT_STATUS_NO_MEMORY;
}
DEBUG(1, ("Unable to parse client principal: %s\n",
smb_get_krb5_error_message(context,
ret, mem_ctx)));
+ krb5_free_principal(context, client_principal);
talloc_free(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
principal_string,
smb_get_krb5_error_message(context,
ret, mem_ctx)));
- krb5_free_principal(context, client_principal);
free(principal_string);
+ krb5_free_principal(context, client_principal);
+ talloc_free(mem_ctx);
return NT_STATUS_ACCESS_DENIED;
} else if (ret) {
/* NO pac */
DEBUG(1, ("Unable to find PAC for %s, resorting to local user lookup: %s",
principal_string, smb_get_krb5_error_message(context,
ret, mem_ctx)));
- nt_status = gensec_security->auth_context->get_server_info_principal(mem_ctx,
+ nt_status = gensec_security->auth_context->get_user_info_dc_principal(mem_ctx,
gensec_security->auth_context,
principal_string,
- &server_info);
+ NULL, &user_info_dc);
if (!NT_STATUS_IS_OK(nt_status)) {
+ free(principal_string);
+ krb5_free_principal(context, client_principal);
talloc_free(mem_ctx);
return nt_status;
}
} else {
DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access\n",
principal_string));
- return NT_STATUS_ACCESS_DENIED;
- }
-
- krb5_free_principal(context, client_principal);
- free(principal_string);
-
- if (!NT_STATUS_IS_OK(nt_status)) {
+ free(principal_string);
+ krb5_free_principal(context, client_principal);
talloc_free(mem_ctx);
- return nt_status;
+ return NT_STATUS_ACCESS_DENIED;
}
} else {
/* Found pac */
union netr_Validation validation;
- free(principal_string);
pac = data_blob_talloc(mem_ctx, pac_data.data, pac_data.length);
if (!pac.data) {
+ free(principal_string);
krb5_free_principal(context, client_principal);
talloc_free(mem_ctx);
return NT_STATUS_NO_MEMORY;
/* decode and verify the pac */
nt_status = kerberos_pac_logon_info(gensec_krb5_state,
- gensec_security->settings->iconv_convenience,
- &logon_info, pac,
+ pac,
gensec_krb5_state->smb_krb5_context->krb5_context,
NULL, gensec_krb5_state->keyblock,
client_principal,
- gensec_krb5_state->ticket->ticket.authtime, NULL);
- krb5_free_principal(context, client_principal);
+ gensec_krb5_state->ticket->ticket.authtime, &logon_info);
if (!NT_STATUS_IS_OK(nt_status)) {
+ free(principal_string);
+ krb5_free_principal(context, client_principal);
talloc_free(mem_ctx);
return nt_status;
}
validation.sam3 = &logon_info->info3;
- nt_status = make_server_info_netlogon_validation(mem_ctx,
+ nt_status = make_user_info_dc_netlogon_validation(mem_ctx,
NULL,
3, &validation,
- &server_info);
+ true, /* This user was authenticated */
+ &user_info_dc);
if (!NT_STATUS_IS_OK(nt_status)) {
+ free(principal_string);
+ krb5_free_principal(context, client_principal);
talloc_free(mem_ctx);
return nt_status;
}
}
- /* references the server_info into the session_info */
- nt_status = auth_generate_session_info(mem_ctx, gensec_security->event_ctx, gensec_security->settings->lp_ctx, server_info, &session_info);
+ free(principal_string);
+ krb5_free_principal(context, client_principal);
+
+ /* references the user_info_dc into the session_info */
+ nt_status = gensec_generate_session_info(mem_ctx, gensec_security, user_info_dc, &session_info);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(mem_ctx);
return nt_status;
}
- nt_status = gensec_krb5_session_key(gensec_security, &session_info->session_key);
+ nt_status = gensec_krb5_session_key(gensec_security, session_info, &session_info->session_key);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(mem_ctx);
return nt_status;
}
- *_session_info = session_info;
+ *_session_info = talloc_steal(mem_ctx_out, session_info);
- talloc_steal(gensec_krb5_state, session_info);
talloc_free(mem_ctx);
return NT_STATUS_OK;
}