summaryrefslogtreecommitdiff
path: root/source4/auth
diff options
context:
space:
mode:
Diffstat (limited to 'source4/auth')
-rw-r--r--source4/auth/gensec/gensec.c69
-rw-r--r--source4/auth/gensec/gensec.h7
-rw-r--r--source4/auth/gensec/gensec_krb5.c78
3 files changed, 146 insertions, 8 deletions
diff --git a/source4/auth/gensec/gensec.c b/source4/auth/gensec/gensec.c
index e9a304133c..65bc5d2450 100644
--- a/source4/auth/gensec/gensec.c
+++ b/source4/auth/gensec/gensec.c
@@ -377,6 +377,8 @@ static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
(*gensec_security)->ops = NULL;
ZERO_STRUCT((*gensec_security)->target);
+ ZERO_STRUCT((*gensec_security)->peer_addr);
+ ZERO_STRUCT((*gensec_security)->my_addr);
(*gensec_security)->subcontext = False;
(*gensec_security)->want_features = 0;
@@ -789,7 +791,7 @@ BOOL gensec_have_feature(struct gensec_security *gensec_security,
}
/**
- * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context
+ * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
*
*/
@@ -800,7 +802,7 @@ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct
}
/**
- * Return the credentails structure associated with a GENSEC context
+ * Return the credentials structure associated with a GENSEC context
*
*/
@@ -855,11 +857,72 @@ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
return gensec_security->target.hostname;
}
- /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
+ /* We could add use the 'set sockaddr' call, and do a reverse
+ * lookup, but this would be both insecure (compromising the
+ * way kerberos works) and add DNS timeouts */
return NULL;
}
/**
+ * Set local and peer socket addresses onto a socket context on the GENSEC context
+ *
+ * This is so that kerberos can include these addresses in
+ * cryptographic tokens, to avoid certain attacks.
+ */
+
+NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, const char *my_addr, int port)
+{
+ gensec_security->my_addr.addr = talloc_strdup(gensec_security, my_addr);
+ if (my_addr && !gensec_security->my_addr.addr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ gensec_security->my_addr.port = port;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, const char *peer_addr, int port)
+{
+ gensec_security->peer_addr.addr = talloc_strdup(gensec_security, peer_addr);
+ if (peer_addr && !gensec_security->peer_addr.addr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ gensec_security->peer_addr.port = port;
+ return NT_STATUS_OK;
+}
+
+const char *gensec_get_my_addr(struct gensec_security *gensec_security, int *port)
+{
+ if (gensec_security->my_addr.addr) {
+ if (port) {
+ *port = gensec_security->my_addr.port;
+ }
+ return gensec_security->my_addr.addr;
+ }
+
+ /* We could add a 'set sockaddr' call, and do a lookup. This
+ * would avoid needing to do system calls if nothing asks. */
+ return NULL;
+}
+
+const char *gensec_get_peer_addr(struct gensec_security *gensec_security, int *port)
+{
+ if (gensec_security->peer_addr.addr) {
+ if (port) {
+ *port = gensec_security->peer_addr.port;
+ }
+ return gensec_security->peer_addr.addr;
+ }
+
+ /* We could add a 'set sockaddr' call, and do a lookup. This
+ * would avoid needing to do system calls if nothing asks.
+ * However, this is not appropriate for the peer addres on
+ * datagram sockets */
+ return NULL;
+}
+
+
+
+/**
* Set the target principal (assuming it it known, say from the SPNEGO reply)
* - ensures it is talloc()ed
*
diff --git a/source4/auth/gensec/gensec.h b/source4/auth/gensec/gensec.h
index ae85bf8f5e..67bec3a0f5 100644
--- a/source4/auth/gensec/gensec.h
+++ b/source4/auth/gensec/gensec.h
@@ -31,10 +31,14 @@ struct gensec_security;
struct gensec_target {
const char *principal;
const char *hostname;
- const struct sock_addr *addr;
const char *service;
};
+struct gensec_addr {
+ const char *addr;
+ int port;
+};
+
#define GENSEC_FEATURE_SESSION_KEY 0x00000001
#define GENSEC_FEATURE_SIGN 0x00000002
#define GENSEC_FEATURE_SEAL 0x00000004
@@ -114,6 +118,7 @@ struct gensec_security {
BOOL subcontext;
uint32_t want_features;
struct event_context *event_ctx;
+ struct gensec_addr my_addr, peer_addr;
};
/* this structure is used by backends to determine the size of some critical types */
diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c
index 161690f665..478ebcfbf0 100644
--- a/source4/auth/gensec/gensec_krb5.c
+++ b/source4/auth/gensec/gensec_krb5.c
@@ -29,6 +29,8 @@
#include "auth/kerberos/kerberos.h"
#include "librpc/gen_ndr/ndr_krb5pac.h"
#include "auth/auth.h"
+#include "system/network.h"
+#include "lib/socket/socket.h"
enum GENSEC_KRB5_STATE {
GENSEC_KRB5_SERVER_START,
@@ -85,7 +87,10 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security)
krb5_error_code ret;
struct gensec_krb5_state *gensec_krb5_state;
struct cli_credentials *creds;
-
+ const char *my_addr, *peer_addr;
+ int my_port, peer_port;
+ krb5_address my_krb5_addr, peer_krb5_addr;
+
creds = gensec_get_credentials(gensec_security);
if (!creds) {
return NT_STATUS_INVALID_PARAMETER;
@@ -133,6 +138,70 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security)
return NT_STATUS_INTERNAL_ERROR;
}
+ my_addr = gensec_get_my_addr(gensec_security, &my_port);
+ if (my_addr) {
+ struct sockaddr_in sock_addr;
+ struct ipv4_addr addr;
+
+ /* TODO: This really should be in a utility function somewhere */
+ ZERO_STRUCT(sock_addr);
+#ifdef HAVE_SOCK_SIN_LEN
+ sock_addr.sin_len = sizeof(sock_addr);
+#endif
+ addr = interpret_addr2(my_addr);
+ sock_addr.sin_addr.s_addr = addr.addr;
+ sock_addr.sin_port = htons(my_port);
+ sock_addr.sin_family = PF_INET;
+
+ ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context,
+ (struct sockaddr *)&sock_addr, &my_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, gensec_krb5_state)));
+ talloc_free(gensec_krb5_state);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ }
+
+ peer_addr = gensec_get_my_addr(gensec_security, &peer_port);
+ if (peer_addr) {
+ struct sockaddr_in sock_addr;
+ struct ipv4_addr addr;
+
+ /* TODO: This really should be in a utility function somewhere */
+ ZERO_STRUCT(sock_addr);
+#ifdef HAVE_SOCK_SIN_LEN
+ sock_addr.sin_len = sizeof(sock_addr);
+#endif
+ addr = interpret_addr2(peer_addr);
+ sock_addr.sin_addr.s_addr = addr.addr;
+ sock_addr.sin_port = htons(peer_port);
+ sock_addr.sin_family = PF_INET;
+
+ ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context,
+ (struct sockaddr *)&sock_addr, &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, gensec_krb5_state)));
+ talloc_free(gensec_krb5_state);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ }
+
+ ret = krb5_auth_con_setaddrs(gensec_krb5_state->smb_krb5_context->krb5_context,
+ gensec_krb5_state->auth_context,
+ my_addr ? &my_krb5_addr : NULL,
+ peer_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,
+ ret, gensec_krb5_state)));
+ talloc_free(gensec_krb5_state);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
return NT_STATUS_OK;
}
@@ -425,11 +494,12 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security,
}
return nt_status;
}
+
case GENSEC_KRB5_DONE:
- return NT_STATUS_OK;
+ default:
+ /* Asking too many times... */
+ return NT_STATUS_INVALID_PARAMETER;
}
-
- return NT_STATUS_INVALID_PARAMETER;
}
static NTSTATUS gensec_krb5_session_key(struct gensec_security *gensec_security,