diff options
Diffstat (limited to 'source4/auth')
-rw-r--r-- | source4/auth/gensec/gensec.c | 69 | ||||
-rw-r--r-- | source4/auth/gensec/gensec.h | 7 | ||||
-rw-r--r-- | source4/auth/gensec/gensec_krb5.c | 78 |
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, |