diff options
Diffstat (limited to 'source4/libcli/auth')
24 files changed, 0 insertions, 9464 deletions
diff --git a/source4/libcli/auth/clikrb5.c b/source4/libcli/auth/clikrb5.c deleted file mode 100644 index b7bd710304..0000000000 --- a/source4/libcli/auth/clikrb5.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - Unix SMB/CIFS implementation. - simple kerberos5 routines for active directory - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Luke Howard 2002-2003 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "system/network.h" -#include "system/kerberos.h" -#include "system/time.h" -#include "libcli/auth/kerberos.h" - -#ifdef HAVE_KRB5 - -#ifndef HAVE_KRB5_SET_REAL_TIME -/* - * This function is not in the Heimdal mainline. - */ - krb5_error_code krb5_set_real_time(krb5_context context, int32_t seconds, int32_t microseconds) -{ - krb5_error_code ret; - int32_t sec, usec; - - ret = krb5_us_timeofday(context, &sec, &usec); - if (ret) - return ret; - - context->kdc_sec_offset = seconds - sec; - context->kdc_usec_offset = microseconds - usec; - - return 0; -} -#endif - -#if defined(HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES) && !defined(HAVE_KRB5_SET_DEFAULT_TGS_KTYPES) - krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc) -{ - return krb5_set_default_in_tkt_etypes(ctx, enc); -} -#endif - -#if defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) -/* HEIMDAL */ - void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr) -{ - pkaddr->addr_type = KRB5_ADDRESS_INET; - pkaddr->address.length = sizeof(((struct sockaddr_in *)paddr)->sin_addr); - pkaddr->address.data = (char *)&(((struct sockaddr_in *)paddr)->sin_addr); -} -#elif defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) -/* MIT */ - void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr) -{ - pkaddr->addrtype = ADDRTYPE_INET; - pkaddr->length = sizeof(((struct sockaddr_in *)paddr)->sin_addr); - pkaddr->contents = (krb5_octet *)&(((struct sockaddr_in *)paddr)->sin_addr); -} -#else -#error UNKNOWN_ADDRTYPE -#endif - -#if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_USE_ENCTYPE) && defined(HAVE_KRB5_STRING_TO_KEY) && defined(HAVE_KRB5_ENCRYPT_BLOCK) - int create_kerberos_key_from_string_direct(krb5_context context, - krb5_principal host_princ, - krb5_data *password, - krb5_keyblock *key, - krb5_enctype enctype) -{ - int ret; - krb5_data salt; - krb5_encrypt_block eblock; - - ret = krb5_principal2salt(context, host_princ, &salt); - if (ret) { - DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret))); - return ret; - } - krb5_use_enctype(context, &eblock, enctype); - ret = krb5_string_to_key(context, &eblock, key, password, &salt); - SAFE_FREE(salt.data); - return ret; -} -#elif defined(HAVE_KRB5_GET_PW_SALT) && defined(HAVE_KRB5_STRING_TO_KEY_SALT) - int create_kerberos_key_from_string_direct(krb5_context context, - krb5_principal host_princ, - krb5_data *password, - krb5_keyblock *key, - krb5_enctype enctype) -{ - int ret; - krb5_salt salt; - - ret = krb5_get_pw_salt(context, host_princ, &salt); - if (ret) { - DEBUG(1,("krb5_get_pw_salt failed (%s)\n", error_message(ret))); - return ret; - } - return krb5_string_to_key_salt(context, enctype, password->data, - salt, key); -} -#else -#error UNKNOWN_CREATE_KEY_FUNCTIONS -#endif - - int create_kerberos_key_from_string(krb5_context context, - krb5_principal host_princ, - krb5_data *password, - krb5_keyblock *key, - krb5_enctype enctype) -{ - krb5_principal salt_princ = NULL; - int ret; - /* - * Check if we've determined that the KDC is salting keys for this - * principal/enctype in a non-obvious way. If it is, try to match - * its behavior. - */ - salt_princ = kerberos_fetch_salt_princ_for_host_princ(context, host_princ, enctype); - ret = create_kerberos_key_from_string_direct(context, salt_princ ? salt_princ : host_princ, password, key, enctype); - if (salt_princ) { - krb5_free_principal(context, salt_princ); - } - return ret; -} - -#if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES) - krb5_error_code get_kerberos_allowed_etypes(krb5_context context, - krb5_enctype **enctypes) -{ - return krb5_get_permitted_enctypes(context, enctypes); -} -#elif defined(HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES) - krb5_error_code get_kerberos_allowed_etypes(krb5_context context, - krb5_enctype **enctypes) -{ - return krb5_get_default_in_tkt_etypes(context, enctypes); -} -#else -#error UNKNOWN_GET_ENCTYPES_FUNCTIONS -#endif - - void free_kerberos_etypes(krb5_context context, - krb5_enctype *enctypes) -{ -#if defined(HAVE_KRB5_FREE_KTYPES) - krb5_free_ktypes(context, enctypes); - return; -#else - SAFE_FREE(enctypes); - return; -#endif -} - -#if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY) - krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context, - krb5_auth_context auth_context, - krb5_keyblock *keyblock) -{ - return krb5_auth_con_setkey(context, auth_context, keyblock); -} -#endif - - DATA_BLOB get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, - krb5_ticket *tkt) -{ - DATA_BLOB auth_data = data_blob(NULL, 0); -#if defined(HAVE_KRB5_TKT_ENC_PART2) - if (tkt && tkt->enc_part2 - && tkt->enc_part2->authorization_data - && tkt->enc_part2->authorization_data[0] - && tkt->enc_part2->authorization_data[0]->length) - auth_data = data_blob(tkt->enc_part2->authorization_data[0]->contents, - tkt->enc_part2->authorization_data[0]->length); -#else - if (tkt && tkt->ticket.authorization_data && tkt->ticket.authorization_data->len) - auth_data = data_blob(tkt->ticket.authorization_data->val->ad_data.data, - tkt->ticket.authorization_data->val->ad_data.length); -#endif - return auth_data; -} - - krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt) -{ -#if defined(HAVE_KRB5_TKT_ENC_PART2) - return tkt->enc_part2->client; -#else - return tkt->client; -#endif -} - -#if !defined(HAVE_KRB5_LOCATE_KDC) - krb5_error_code krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters) -{ - krb5_krbhst_handle hnd; - krb5_krbhst_info *hinfo; - krb5_error_code rc; - int num_kdcs, i; - struct sockaddr *sa; - struct addrinfo *ai; - - *addr_pp = NULL; - *naddrs = 0; - - rc = krb5_krbhst_init(ctx, realm->data, KRB5_KRBHST_KDC, &hnd); - if (rc) { - DEBUG(0, ("krb5_locate_kdc: krb5_krbhst_init failed (%s)\n", error_message(rc))); - return rc; - } - - for ( num_kdcs = 0; (rc = krb5_krbhst_next(ctx, hnd, &hinfo) == 0); num_kdcs++) - ; - - krb5_krbhst_reset(ctx, hnd); - - if (!num_kdcs) { - DEBUG(0, ("krb5_locate_kdc: zero kdcs found !\n")); - krb5_krbhst_free(ctx, hnd); - return -1; - } - - sa = malloc_array_p(struct sockaddr, num_kdcs); - if (!sa) { - DEBUG(0, ("krb5_locate_kdc: malloc failed\n")); - krb5_krbhst_free(ctx, hnd); - naddrs = 0; - return -1; - } - - memset(sa, '\0', sizeof(struct sockaddr) * num_kdcs ); - - for (i = 0; i < num_kdcs && (rc = krb5_krbhst_next(ctx, hnd, &hinfo) == 0); i++) { - -#if defined(HAVE_KRB5_KRBHST_GET_ADDRINFO) - rc = krb5_krbhst_get_addrinfo(ctx, hinfo, &ai); - if (rc) { - DEBUG(0,("krb5_krbhst_get_addrinfo failed: %s\n", error_message(rc))); - continue; - } -#endif - if (hinfo->ai && hinfo->ai->ai_family == AF_INET) - memcpy(&sa[i], hinfo->ai->ai_addr, sizeof(struct sockaddr)); - } - - krb5_krbhst_free(ctx, hnd); - - *naddrs = num_kdcs; - *addr_pp = sa; - return 0; -} -#endif - -#if !defined(HAVE_KRB5_FREE_UNPARSED_NAME) - void krb5_free_unparsed_name(krb5_context context, char *val) -{ - SAFE_FREE(val); -} -#endif - - void kerberos_free_data_contents(krb5_context context, krb5_data *pdata) -{ -#if defined(HAVE_KRB5_FREE_DATA_CONTENTS) - if (pdata->data) { - krb5_free_data_contents(context, pdata); - } -#else - SAFE_FREE(pdata->data); -#endif -} - - void kerberos_set_creds_enctype(krb5_creds *pcreds, int enctype) -{ -#if defined(HAVE_KRB5_KEYBLOCK_IN_CREDS) - KRB5_KEY_TYPE((&pcreds->keyblock)) = enctype; -#elif defined(HAVE_KRB5_SESSION_IN_CREDS) - KRB5_KEY_TYPE((&pcreds->session)) = enctype; -#else -#error UNKNOWN_KEYBLOCK_MEMBER_IN_KRB5_CREDS_STRUCT -#endif -} - - BOOL kerberos_compatible_enctypes(krb5_context context, - krb5_enctype enctype1, - krb5_enctype enctype2) -{ -#if defined(HAVE_KRB5_C_ENCTYPE_COMPARE) - krb5_boolean similar = 0; - - krb5_c_enctype_compare(context, enctype1, enctype2, &similar); - return similar ? True : False; -#elif defined(HAVE_KRB5_ENCTYPES_COMPATIBLE_KEYS) - return krb5_enctypes_compatible_keys(context, enctype1, enctype2) ? True : False; -#endif -} - -static BOOL ads_cleanup_expired_creds(krb5_context context, - krb5_ccache ccache, - krb5_creds *credsp) -{ - krb5_error_code retval; - TALLOC_CTX *mem_ctx = talloc_init("ticket expied time"); - if (!mem_ctx) { - return False; - } - - DEBUG(3, ("Ticket in ccache[%s] expiration %s\n", - krb5_cc_default_name(context), - http_timestring(mem_ctx, credsp->times.endtime))); - - talloc_free(mem_ctx); - - /* we will probably need new tickets if the current ones - will expire within 10 seconds. - */ - if (credsp->times.endtime >= (time(NULL) + 10)) - return False; - - /* heimdal won't remove creds from a file ccache, and - perhaps we shouldn't anyway, since internally we - use memory ccaches, and a FILE one probably means that - we're using creds obtained outside of our exectuable - */ - if (StrCaseCmp(krb5_cc_get_type(context, ccache), "FILE") == 0) { - DEBUG(5, ("ads_cleanup_expired_creds: We do not remove creds from a FILE ccache\n")); - return False; - } - - retval = krb5_cc_remove_cred(context, ccache, 0, credsp); - if (retval) { - DEBUG(1, ("ads_cleanup_expired_creds: krb5_cc_remove_cred failed, err %s\n", - error_message(retval))); - /* If we have an error in this, we want to display it, - but continue as though we deleted it */ - } - return True; -} - -/* - we can't use krb5_mk_req because w2k wants the service to be in a particular format -*/ -krb5_error_code ads_krb5_mk_req(krb5_context context, - krb5_auth_context *auth_context, - const krb5_flags ap_req_options, - const char *principal, - krb5_ccache ccache, - krb5_data *outbuf) -{ - krb5_error_code retval; - krb5_principal server; - krb5_creds * credsp; - krb5_creds creds; - krb5_data in_data; - BOOL creds_ready = False; - - TALLOC_CTX *mem_ctx = NULL; - - retval = krb5_parse_name(context, principal, &server); - if (retval) { - DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal)); - return retval; - } - - /* obtain ticket & session key */ - ZERO_STRUCT(creds); - if ((retval = krb5_copy_principal(context, server, &creds.server))) { - DEBUG(1,("krb5_copy_principal failed (%s)\n", - error_message(retval))); - goto cleanup_princ; - } - - if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) { - /* This can commonly fail on smbd startup with no ticket in the cache. - * Report at higher level than 1. */ - DEBUG(3,("ads_krb5_mk_req: krb5_cc_get_principal failed (%s)\n", - error_message(retval))); - goto cleanup_creds; - } - - while(!creds_ready) { - if ((retval = krb5_get_credentials(context, 0, ccache, - &creds, &credsp))) { - DEBUG(1,("ads_krb5_mk_req: krb5_get_credentials failed for %s (%s)\n", - principal, error_message(retval))); - goto cleanup_creds; - } - - /* cope with ticket being in the future due to clock skew */ - if ((unsigned)credsp->times.starttime > time(NULL)) { - time_t t = time(NULL); - int time_offset =(unsigned)credsp->times.starttime-t; - DEBUG(4,("ads_krb5_mk_req: Advancing clock by %d seconds to cope with clock skew\n", time_offset)); - krb5_set_real_time(context, t + time_offset + 1, 0); - } - - if (!ads_cleanup_expired_creds(context, ccache, credsp)) - creds_ready = True; - } - - mem_ctx = talloc_init("ticket expied time"); - if (!mem_ctx) { - retval = ENOMEM; - goto cleanup_creds; - } - DEBUG(10,("Ticket (%s) in ccache (%s) is valid until: (%s - %d)\n", - principal, krb5_cc_default_name(context), - http_timestring(mem_ctx, (unsigned)credsp->times.endtime), - (unsigned)credsp->times.endtime)); - - in_data.length = 0; - retval = krb5_mk_req_extended(context, auth_context, ap_req_options, - &in_data, credsp, outbuf); - if (retval) { - DEBUG(1,("ads_krb5_mk_req: krb5_mk_req_extended failed (%s)\n", - error_message(retval))); - } - - krb5_free_creds(context, credsp); - -cleanup_creds: - krb5_free_cred_contents(context, &creds); - -cleanup_princ: - krb5_free_principal(context, server); - - return retval; -} - -#if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING) && !defined(HAVE_KRB5_PRINC_COMPONENT) - const krb5_data *krb5_princ_component(krb5_context context, krb5_principal principal, int i ) -{ - static krb5_data kdata; - - kdata.data = discard_const(krb5_principal_get_comp_string(context, principal, i)); - kdata.length = strlen(kdata.data); - return &kdata; -} -#endif - - krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry) -{ -#if defined(HAVE_KRB5_KT_FREE_ENTRY) - return krb5_kt_free_entry(context, kt_entry); -#elif defined(HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS) - return krb5_free_keytab_entry_contents(context, kt_entry); -#else -#error UNKNOWN_KT_FREE_FUNCTION -#endif -} - - char *smb_get_krb5_error_message(krb5_context context, krb5_error_code code, TALLOC_CTX *mem_ctx) -{ - char *ret; - -#if defined(HAVE_KRB5_GET_ERROR_STRING) && defined(HAVE_KRB5_FREE_ERROR_STRING) - char *context_error = krb5_get_error_string(context); - ret = talloc_asprintf(mem_ctx, "%s: %s", error_message(code), context_error); - krb5_free_error_string(context, context_error); -#else - ret = talloc_strdup(mem_ctx, error_message(code)); -#endif - return ret; -} - -#endif diff --git a/source4/libcli/auth/gensec.c b/source4/libcli/auth/gensec.c deleted file mode 100644 index cc7327187c..0000000000 --- a/source4/libcli/auth/gensec.c +++ /dev/null @@ -1,630 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Generic Authentication Interface - - Copyright (C) Andrew Tridgell 2003 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "auth/auth.h" - -/* the list of currently registered GENSEC backends */ -const static struct gensec_security_ops **generic_security_ops; -static int gensec_num_backends; - -static const struct gensec_security_ops *gensec_security_by_authtype(uint8_t auth_type) -{ - int i; - for (i=0; i < gensec_num_backends; i++) { - if (generic_security_ops[i]->auth_type == auth_type) { - return generic_security_ops[i]; - } - } - - return NULL; -} - -static const struct gensec_security_ops *gensec_security_by_oid(const char *oid_string) -{ - int i; - for (i=0; i < gensec_num_backends; i++) { - if (generic_security_ops[i]->oid && - (strcmp(generic_security_ops[i]->oid, oid_string) == 0)) { - return generic_security_ops[i]; - } - } - - return NULL; -} - -static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name) -{ - int i; - for (i=0; i < gensec_num_backends; i++) { - if (generic_security_ops[i]->sasl_name - && (strcmp(generic_security_ops[i]->sasl_name, sasl_name) == 0)) { - return generic_security_ops[i]; - } - } - - return NULL; -} - -static const struct gensec_security_ops *gensec_security_by_name(const char *name) -{ - int i; - for (i=0; i < gensec_num_backends; i++) { - if (generic_security_ops[i]->name - && (strcmp(generic_security_ops[i]->name, name) == 0)) { - return generic_security_ops[i]; - } - } - - return NULL; -} - -const struct gensec_security_ops **gensec_security_all(int *num_backends_out) -{ - *num_backends_out = gensec_num_backends; - return generic_security_ops; -} - -const char **gensec_security_oids(TALLOC_CTX *mem_ctx, const char *skip) -{ - int i, j = 0; - const char **oid_list; - int num_backends; - const struct gensec_security_ops **ops = gensec_security_all(&num_backends); - if (!ops) { - return NULL; - } - oid_list = talloc_array(mem_ctx, const char *, num_backends + 1); - if (!oid_list) { - return NULL; - } - - for (i=0; i<num_backends; i++) { - if (!ops[i]->oid) { - continue; - } - - if (skip && strcmp(skip, ops[i]->oid)==0) { - continue; - } - - oid_list[j] = ops[i]->oid; - j++; - } - oid_list[j] = NULL; - return oid_list; -} - -/** - Start the GENSEC system, returning a context pointer. - @param mem_ctx The parent TALLOC memory context. - @param gensec_security Returned GENSEC context pointer. - @note The mem_ctx is only a parent and may be NULL. -*/ -static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security) -{ - (*gensec_security) = talloc(mem_ctx, struct gensec_security); - if (!(*gensec_security)) { - return NT_STATUS_NO_MEMORY; - } - - (*gensec_security)->ops = NULL; - - ZERO_STRUCT((*gensec_security)->target); - - (*gensec_security)->subcontext = False; - (*gensec_security)->want_features = 0; - return NT_STATUS_OK; -} - -/** - * Start a GENSEC subcontext, with a copy of the properties of the parent - * @param mem_ctx The parent TALLOC memory context. - * @param parent The parent GENSEC context - * @param gensec_security Returned GENSEC context pointer. - * @note Used by SPNEGO in particular, for the actual implementation mechanism - */ - -NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx, - struct gensec_security *parent, - struct gensec_security **gensec_security) -{ - (*gensec_security) = talloc(mem_ctx, struct gensec_security); - if (!(*gensec_security)) { - return NT_STATUS_NO_MEMORY; - } - - (**gensec_security) = *parent; - (*gensec_security)->ops = NULL; - (*gensec_security)->private_data = NULL; - - (*gensec_security)->subcontext = True; - - return NT_STATUS_OK; -} - -/** - Start the GENSEC system, in client mode, returning a context pointer. - @param mem_ctx The parent TALLOC memory context. - @param gensec_security Returned GENSEC context pointer. - @note The mem_ctx is only a parent and may be NULL. -*/ -NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security) -{ - NTSTATUS status; - status = gensec_start(mem_ctx, gensec_security); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - (*gensec_security)->gensec_role = GENSEC_CLIENT; - (*gensec_security)->password_callback = NULL; - - return status; -} - -/** - Start the GENSEC system, in server mode, returning a context pointer. - @param mem_ctx The parent TALLOC memory context. - @param gensec_security Returned GENSEC context pointer. - @note The mem_ctx is only a parent and may be NULL. -*/ -NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security) -{ - NTSTATUS status; - status = gensec_start(mem_ctx, gensec_security); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - (*gensec_security)->gensec_role = GENSEC_SERVER; - - return status; -} - -static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security) -{ - NTSTATUS status; - DEBUG(5, ("Starting GENSEC %smechanism %s\n", - gensec_security->subcontext ? "sub" : "", - gensec_security->ops->name)); - switch (gensec_security->gensec_role) { - case GENSEC_CLIENT: - if (gensec_security->ops->client_start) { - status = gensec_security->ops->client_start(gensec_security); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start GENSEC client mech %s: %s\n", - gensec_security->ops->name, nt_errstr(status))); - } - return status; - } - case GENSEC_SERVER: - if (gensec_security->ops->server_start) { - status = gensec_security->ops->server_start(gensec_security); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n", - gensec_security->ops->name, nt_errstr(status))); - } - return status; - } - } - return NT_STATUS_INVALID_PARAMETER; -} - -/** - * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number - * @param gensec_security GENSEC context pointer. - * @param auth_type DCERPC auth type - * @param auth_level DCERPC auth level - */ - -NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security, - uint8_t auth_type, uint8_t auth_level) -{ - gensec_security->ops = gensec_security_by_authtype(auth_type); - if (!gensec_security->ops) { - DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type)); - return NT_STATUS_INVALID_PARAMETER; - } - gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE); - if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { - gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN); - } - if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { - gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN); - gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL); - } - - return gensec_start_mech(gensec_security); -} - -const char *gensec_get_name_by_authtype(uint8_t authtype) -{ - const struct gensec_security_ops *ops; - ops = gensec_security_by_authtype(authtype); - if (ops) { - return ops->name; - } - return NULL; -} - - -const char *gensec_get_name_by_oid(const char *oid_string) -{ - const struct gensec_security_ops *ops; - ops = gensec_security_by_oid(oid_string); - if (ops) { - return ops->name; - } - return NULL; -} - - -/** - * Start a GENSEC sub-mechanism by OID, used in SPNEGO - * - * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a - * well-known #define to hook it in. - */ - -NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security, - const char *mech_oid) -{ - gensec_security->ops = gensec_security_by_oid(mech_oid); - if (!gensec_security->ops) { - DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid)); - return NT_STATUS_INVALID_PARAMETER; - } - return gensec_start_mech(gensec_security); -} - -/** - * Start a GENSEC sub-mechanism by a well know SASL name - * - */ - -NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, - const char *sasl_name) -{ - gensec_security->ops = gensec_security_by_sasl_name(sasl_name); - if (!gensec_security->ops) { - DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name)); - return NT_STATUS_INVALID_PARAMETER; - } - return gensec_start_mech(gensec_security); -} - -/* - wrappers for the gensec function pointers -*/ -NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - if (!gensec_security->ops->unseal_packet) { - return NT_STATUS_NOT_IMPLEMENTED; - } - if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { - if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - return gensec_check_packet(gensec_security, mem_ctx, - data, length, - whole_pdu, pdu_length, - sig); - } - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, - data, length, - whole_pdu, pdu_length, - sig); -} - -NTSTATUS gensec_check_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - const DATA_BLOB *sig) -{ - if (!gensec_security->ops->check_packet) { - return NT_STATUS_NOT_IMPLEMENTED; - } - if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig); -} - -NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - if (!gensec_security->ops->seal_packet) { - return NT_STATUS_NOT_IMPLEMENTED; - } - if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { - if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - return gensec_sign_packet(gensec_security, mem_ctx, - data, length, - whole_pdu, pdu_length, - sig); - } - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig); -} - -NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - if (!gensec_security->ops->sign_packet) { - return NT_STATUS_NOT_IMPLEMENTED; - } - if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig); -} - -size_t gensec_sig_size(struct gensec_security *gensec_security) -{ - if (!gensec_security->ops->sig_size) { - return 0; - } - if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - return 0; - } - - return gensec_security->ops->sig_size(gensec_security); -} - -NTSTATUS gensec_wrap(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - if (!gensec_security->ops->wrap) { - return NT_STATUS_NOT_IMPLEMENTED; - } - return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out); -} - -NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - if (!gensec_security->ops->unwrap) { - return NT_STATUS_NOT_IMPLEMENTED; - } - return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out); -} - -NTSTATUS gensec_session_key(struct gensec_security *gensec_security, - DATA_BLOB *session_key) -{ - if (!gensec_security->ops->session_key) { - return NT_STATUS_NOT_IMPLEMENTED; - } - return gensec_security->ops->session_key(gensec_security, session_key); -} - -/** - * Return the credentials of a logged on user, including session keys - * etc. - * - * Only valid after a successful authentication - * - * May only be called once per authentication. - * - */ - -NTSTATUS gensec_session_info(struct gensec_security *gensec_security, - struct auth_session_info **session_info) -{ - if (!gensec_security->ops->session_info) { - return NT_STATUS_NOT_IMPLEMENTED; - } - return gensec_security->ops->session_info(gensec_security, session_info); -} - -/** - * Next state function for the GENSEC state machine - * - * @param gensec_security GENSEC State - * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on - * @param in The request, as a DATA_BLOB - * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx - * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, - * or NT_STATUS_OK if the user is authenticated. - */ - -NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out); -} - -/** - * Set the requirement for a certain feature on the connection - * - */ - -void gensec_want_feature(struct gensec_security *gensec_security, - uint32_t feature) -{ - gensec_security->want_features |= feature; -} - -/** - * Check the requirement for a certain feature on the connection - * - */ - -BOOL gensec_have_feature(struct gensec_security *gensec_security, - uint32_t feature) -{ - if (!gensec_security->ops->have_feature) { - return False; - } - return gensec_security->ops->have_feature(gensec_security, feature); -} - -/** - * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context - * - */ - -NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) -{ - gensec_security->credentials = talloc_reference(gensec_security, credentials); - return NT_STATUS_OK; -} - -/** - * Return the credentails structure associated with a GENSEC context - * - */ - -struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security) -{ - return gensec_security->credentials; -} - -/** - * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed - * - */ - -NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) -{ - gensec_security->target.service = talloc_strdup(gensec_security, service); - if (!gensec_security->target.service) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed - * - */ - -NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) -{ - gensec_security->target.hostname = talloc_strdup(gensec_security, hostname); - if (!gensec_security->target.hostname) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -const char *gensec_get_target_hostname(struct gensec_security *gensec_security) -{ - if (gensec_security->target.hostname) { - return gensec_security->target.hostname; - } - - /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */ - return NULL; -} - -const char *gensec_get_target_service(struct gensec_security *gensec_security) -{ - if (gensec_security->target.service) { - return gensec_security->target.service; - } - - return "host"; -} - -/* - register a GENSEC backend. - - The 'name' can be later used by other backends to find the operations - structure for this backend. -*/ -NTSTATUS gensec_register(const void *_ops) -{ - const struct gensec_security_ops *ops = _ops; - - if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) { - DEBUG(2,("gensec subsystem %s is disabled\n", ops->name)); - return NT_STATUS_OK; - } - - if (gensec_security_by_name(ops->name) != NULL) { - /* its already registered! */ - DEBUG(0,("GENSEC backend '%s' already registered\n", - ops->name)); - return NT_STATUS_OBJECT_NAME_COLLISION; - } - - generic_security_ops = realloc_p(generic_security_ops, - const struct gensec_security_ops *, - gensec_num_backends+1); - if (!generic_security_ops) { - smb_panic("out of memory in gensec_register"); - } - - generic_security_ops[gensec_num_backends] = ops; - - gensec_num_backends++; - - DEBUG(3,("GENSEC backend '%s' registered\n", - ops->name)); - - return NT_STATUS_OK; -} - -/* - return the GENSEC interface version, and the size of some critical types - This can be used by backends to either detect compilation errors, or provide - multiple implementations for different smbd compilation options in one module -*/ -const struct gensec_critical_sizes *gensec_interface_version(void) -{ - static const struct gensec_critical_sizes critical_sizes = { - GENSEC_INTERFACE_VERSION, - sizeof(struct gensec_security_ops), - sizeof(struct gensec_security), - }; - - return &critical_sizes; -} - -/* - initialise the GENSEC subsystem -*/ -NTSTATUS gensec_init(void) -{ - return NT_STATUS_OK; -} diff --git a/source4/libcli/auth/gensec.h b/source4/libcli/auth/gensec.h deleted file mode 100644 index 91c817d48a..0000000000 --- a/source4/libcli/auth/gensec.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Generic Authentication Interface - - Copyright (C) Andrew Tridgell 2003 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#define GENSEC_OID_NTLMSSP "1 3 6 1 4 1 311 2 2 10" -#define GENSEC_OID_SPNEGO "1 3 6 1 5 5 2" -#define GENSEC_OID_KERBEROS5 "1 2 840 113554 1 2 2" -#define GENSEC_OID_KERBEROS5_OLD "1 2 840 48018 1 2 2" -#define GENSEC_OID_KERBEROS5_USER2USER "1 2 840 113554 1 2 2 3" - -struct gensec_security; -struct gensec_target { - const char *principal; - const char *hostname; - const struct sock_addr *addr; - const char *service; -}; - -#define GENSEC_FEATURE_SESSION_KEY 0x00000001 -#define GENSEC_FEATURE_SIGN 0x00000002 -#define GENSEC_FEATURE_SEAL 0x00000004 -#define GENSEC_FEATURE_DCE_STYLE 0x00000008 - -/* GENSEC mode */ -enum gensec_role -{ - GENSEC_SERVER, - GENSEC_CLIENT -}; - -struct auth_session_info; - -struct gensec_security_ops { - const char *name; - const char *sasl_name; - uint8_t auth_type; /* 0 if not offered on DCE-RPC */ - const char *oid; /* NULL if not offered by SPNEGO */ - NTSTATUS (*client_start)(struct gensec_security *gensec_security); - NTSTATUS (*server_start)(struct gensec_security *gensec_security); - NTSTATUS (*update)(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out); - NTSTATUS (*seal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig); - NTSTATUS (*sign_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig); - size_t (*sig_size)(struct gensec_security *gensec_security); - NTSTATUS (*check_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - const DATA_BLOB *sig); - NTSTATUS (*unseal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig); - NTSTATUS (*wrap)(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out); - NTSTATUS (*unwrap)(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out); - NTSTATUS (*session_key)(struct gensec_security *gensec_security, DATA_BLOB *session_key); - NTSTATUS (*session_info)(struct gensec_security *gensec_security, - struct auth_session_info **session_info); - BOOL (*have_feature)(struct gensec_security *gensec_security, - uint32_t feature); - BOOL enabled; -}; - -#define GENSEC_INTERFACE_VERSION 0 - -struct gensec_security { - gensec_password_callback password_callback; - void *password_callback_private; - const struct gensec_security_ops *ops; - void *private_data; - struct cli_credentials *credentials; - struct gensec_target target; - enum gensec_role gensec_role; - BOOL subcontext; - uint32_t want_features; -}; - -/* this structure is used by backends to determine the size of some critical types */ -struct gensec_critical_sizes { - int interface_version; - int sizeof_gensec_security_ops; - int sizeof_gensec_security; -}; - - -/* pre-declare schannel structure for schannel backend */ -struct schannel_state; diff --git a/source4/libcli/auth/gensec.m4 b/source4/libcli/auth/gensec.m4 deleted file mode 100644 index 6ccf45ad7e..0000000000 --- a/source4/libcli/auth/gensec.m4 +++ /dev/null @@ -1,12 +0,0 @@ -SMB_MODULE_DEFAULT(gensec_krb5, NOT) -SMB_MODULE_DEFAULT(gensec_gssapi, NOT) -SMB_MODULE_DEFAULT(gensec_gsskrb5, NOT) - -if test x"$SMB_EXT_LIB_ENABLE_KRB5" = x"YES"; then - # enable this when krb5 is fully working - SMB_MODULE_DEFAULT(gensec_krb5, STATIC) - SMB_MODULE_DEFAULT(gensec_gssapi, STATIC) - if test x"$samba_cv_GSS_C_DCE_STYLE" = x"yes"; then - SMB_MODULE_DEFAULT(gensec_gsskrb5, STATIC) - fi -fi diff --git a/source4/libcli/auth/gensec.mk b/source4/libcli/auth/gensec.mk deleted file mode 100644 index b4c612da14..0000000000 --- a/source4/libcli/auth/gensec.mk +++ /dev/null @@ -1,91 +0,0 @@ -################################# -# Start SUBSYSTEM GENSEC -[SUBSYSTEM::GENSEC] -INIT_FUNCTION = gensec_init -INIT_OBJ_FILES = libcli/auth/gensec.o -REQUIRED_SUBSYSTEMS = \ - SCHANNELDB -# End SUBSYSTEM GENSEC -################################# - -################################################ -# Start MODULE gensec_krb5 -[MODULE::gensec_krb5] -SUBSYSTEM = GENSEC -INIT_FUNCTION = gensec_krb5_init -INIT_OBJ_FILES = libcli/auth/gensec_krb5.o -ADD_OBJ_FILES = \ - libcli/auth/clikrb5.o \ - libcli/auth/kerberos.o \ - libcli/auth/kerberos_verify.o \ - libcli/auth/gssapi_parse.o -REQUIRED_SUBSYSTEMS = NDR_KRB5PAC EXT_LIB_KRB5 -# End MODULE gensec_krb5 -################################################ - -################################################ -# Start MODULE gensec_gssapi -[MODULE::gensec_gssapi] -SUBSYSTEM = GENSEC -INIT_FUNCTION = gensec_gssapi_init -INIT_OBJ_FILES = libcli/auth/gensec_gssapi.o -REQUIRED_SUBSYSTEMS = EXT_LIB_KRB5 -# End MODULE gensec_gssapi -################################################ - -################################################ -# Start MODULE gensec_gsskrb5 -[MODULE::gensec_gsskrb5] -SUBSYSTEM = GENSEC -INIT_FUNCTION = gensec_gsskrb5_init -INIT_OBJ_FILES = libcli/auth/gensec_gsskrb5.o -REQUIRED_SUBSYSTEMS = EXT_LIB_KRB5 -# End MODULE gensec_gsskrb5 -################################################ - -################################################ -# Start MODULE gensec_spnego -[MODULE::gensec_spnego] -SUBSYSTEM = GENSEC -INIT_FUNCTION = gensec_spnego_init -INIT_OBJ_FILES = libcli/auth/spnego.o -ADD_OBJ_FILES = \ - libcli/auth/spnego_parse.o -# End MODULE gensec_spnego -################################################ - -################################################ -# Start MODULE gensec_ntlmssp -[MODULE::gensec_ntlmssp] -SUBSYSTEM = GENSEC -INIT_FUNCTION = gensec_ntlmssp_init -INIT_OBJ_FILES = libcli/auth/gensec_ntlmssp.o -ADD_OBJ_FILES = \ - libcli/auth/ntlmssp.o \ - libcli/auth/ntlmssp_parse.o \ - libcli/auth/ntlmssp_sign.o -REQUIRED_SUBSYSTEMS = AUTH -# End MODULE gensec_ntlmssp -################################################ - -################################################ -# Start MODULE gensec_schannel -[MODULE::gensec_schannel] -SUBSYSTEM = GENSEC -INIT_FUNCTION = gensec_schannel_init -INIT_OBJ_FILES = libcli/auth/schannel.o -ADD_OBJ_FILES = \ - libcli/auth/schannel_sign.o -REQUIRED_SUBSYSTEMS = AUTH SCHANNELDB -# End MODULE gensec_ntlmssp -################################################ - -################################################ -# Start SUBSYSTEM SCHANNELDB -[SUBSYSTEM::SCHANNELDB] -INIT_OBJ_FILES = \ - libcli/auth/schannel_state.o -# -# End SUBSYSTEM SCHANNELDB -################################################ - diff --git a/source4/libcli/auth/gensec_gssapi.c b/source4/libcli/auth/gensec_gssapi.c deleted file mode 100644 index c974b93952..0000000000 --- a/source4/libcli/auth/gensec_gssapi.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Kerberos backend for GENSEC - - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "system/kerberos.h" -#include "auth/auth.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_AUTH - -struct gensec_gssapi_state { - gss_ctx_id_t gssapi_context; - struct gss_channel_bindings_struct *input_chan_bindings; - gss_name_t server_name; - gss_name_t client_name; - OM_uint32 want_flags, got_flags; - const gss_OID_desc *gss_oid; -}; -static int gensec_gssapi_destory(void *ptr) -{ - struct gensec_gssapi_state *gensec_gssapi_state = ptr; - OM_uint32 maj_stat, min_stat; - - if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) { - maj_stat = gss_delete_sec_context (&min_stat, - &gensec_gssapi_state->gssapi_context, - GSS_C_NO_BUFFER); - } - - if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) { - maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name); - } - if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) { - maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name); - } - return 0; -} - -static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security) -{ - struct gensec_gssapi_state *gensec_gssapi_state; - - gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state); - if (!gensec_gssapi_state) { - return NT_STATUS_NO_MEMORY; - } - - gensec_security->private_data = gensec_gssapi_state; - - gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT; - gensec_gssapi_state->server_name = GSS_C_NO_NAME; - gensec_gssapi_state->client_name = GSS_C_NO_NAME; - - talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory); - - /* TODO: Fill in channel bindings */ - gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS; - - gensec_gssapi_state->want_flags = 0; - gensec_gssapi_state->got_flags = 0; - - if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { - /* GSSAPI won't give us the session keys */ - return NT_STATUS_INVALID_PARAMETER; - } - if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { - gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG; - } - if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { - gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG; - } - - if (strcmp(gensec_security->ops->oid, GENSEC_OID_KERBEROS5) == 0) { - static const gss_OID_desc gensec_gss_krb5_mechanism_oid_desc = - {9, (void *)discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")}; - - gensec_gssapi_state->gss_oid = &gensec_gss_krb5_mechanism_oid_desc; - } else if (strcmp(gensec_security->ops->oid, GENSEC_OID_SPNEGO) == 0) { - static const gss_OID_desc gensec_gss_spnego_mechanism_oid_desc = - {6, (void *)discard_const_p(char, "\x2b\x06\x01\x05\x05\x02")}; - gensec_gssapi_state->gss_oid = &gensec_gss_spnego_mechanism_oid_desc; - } else { - return NT_STATUS_INVALID_PARAMETER; - } - - return NT_STATUS_OK; -} - -static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security) -{ - NTSTATUS nt_status; - struct gensec_gssapi_state *gensec_gssapi_state; - - nt_status = gensec_gssapi_start(gensec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - gensec_gssapi_state = gensec_security->private_data; - - return NT_STATUS_OK; -} - -static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security) -{ - struct gensec_gssapi_state *gensec_gssapi_state; - NTSTATUS nt_status; - gss_buffer_desc name_token; - OM_uint32 maj_stat, min_stat; - - gss_OID_desc hostbased = {10, - (void *)discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12" - "\x01\x02\x01\x04")}; - - nt_status = gensec_gssapi_start(gensec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - gensec_gssapi_state = gensec_security->private_data; - - name_token.value = talloc_asprintf(gensec_gssapi_state, "%s@%s", gensec_get_target_service(gensec_security), - gensec_get_target_hostname(gensec_security)); - DEBUG(0, ("name: %s\n", (char *)name_token.value)); - name_token.length = strlen(name_token.value); - - maj_stat = gss_import_name (&min_stat, - &name_token, - &hostbased, - &gensec_gssapi_state->server_name); - - - if (maj_stat) { - return NT_STATUS_UNSUCCESSFUL; - } - return NT_STATUS_OK; -} - - - -/** - * Next state function for the GSSAPI GENSEC mechanism - * - * @param gensec_gssapi_state GSSAPI State - * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on - * @param in The request, as a DATA_BLOB - * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx - * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, - * or NT_STATUS_OK if the user is authenticated. - */ - -static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - OM_uint32 maj_stat, min_stat; - OM_uint32 min_stat2; - gss_buffer_desc input_token, output_token; - gss_OID gss_oid_p; - input_token.length = in.length; - input_token.value = in.data; - - switch (gensec_security->gensec_role) { - case GENSEC_CLIENT: - { - maj_stat = gss_init_sec_context(&min_stat, - GSS_C_NO_CREDENTIAL, - &gensec_gssapi_state->gssapi_context, - gensec_gssapi_state->server_name, - discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid), - gensec_gssapi_state->want_flags, - 0, - gensec_gssapi_state->input_chan_bindings, - &input_token, - NULL, - &output_token, - &gensec_gssapi_state->got_flags, /* ret flags */ - NULL); - break; - } - case GENSEC_SERVER: - { - maj_stat = gss_accept_sec_context(&min_stat, - &gensec_gssapi_state->gssapi_context, - GSS_C_NO_CREDENTIAL, - &input_token, - gensec_gssapi_state->input_chan_bindings, - &gensec_gssapi_state->client_name, - &gss_oid_p, - &output_token, - &gensec_gssapi_state->got_flags, - NULL, - NULL); - gensec_gssapi_state->gss_oid = gss_oid_p; - break; - } - default: - return NT_STATUS_INVALID_PARAMETER; - - } - - *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length); - gss_release_buffer(&min_stat2, &output_token); - - if (maj_stat == GSS_S_COMPLETE) { - return NT_STATUS_OK; - } else if (maj_stat == GSS_S_CONTINUE_NEEDED) { - return NT_STATUS_MORE_PROCESSING_REQUIRED; - } else { - gss_buffer_desc msg1, msg2; - OM_uint32 msg_ctx = 0; - - msg1.value = NULL; - msg2.value = NULL; - gss_display_status(&min_stat2, maj_stat, GSS_C_GSS_CODE, - GSS_C_NULL_OID, &msg_ctx, &msg1); - gss_display_status(&min_stat2, min_stat, GSS_C_MECH_CODE, - GSS_C_NULL_OID, &msg_ctx, &msg2); - DEBUG(1, ("gensec_gssapi_update: %s : %s\n", (char *)msg1.value, (char *)msg2.value)); - gss_release_buffer(&min_stat2, &msg1); - gss_release_buffer(&min_stat2, &msg2); - - return nt_status; - } - -} - -static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data; - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token, output_token; - int conf_state; - input_token.length = in->length; - input_token.value = in->data; - - maj_stat = gss_wrap(&min_stat, - gensec_gssapi_state->gssapi_context, - gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL), - GSS_C_QOP_DEFAULT, - &input_token, - &conf_state, - &output_token); - if (GSS_ERROR(maj_stat)) { - return NT_STATUS_ACCESS_DENIED; - } - *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length); - - gss_release_buffer(&min_stat, &output_token); - - if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) - && !conf_state) { - return NT_STATUS_ACCESS_DENIED; - } - return NT_STATUS_OK; -} - -static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data; - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token, output_token; - int conf_state; - gss_qop_t qop_state; - input_token.length = in->length; - input_token.value = in->data; - - maj_stat = gss_unwrap(&min_stat, - gensec_gssapi_state->gssapi_context, - &input_token, - &output_token, - &conf_state, - &qop_state); - if (GSS_ERROR(maj_stat)) { - return NT_STATUS_ACCESS_DENIED; - } - *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length); - - gss_release_buffer(&min_stat, &output_token); - - if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) - && !conf_state) { - return NT_STATUS_ACCESS_DENIED; - } - return NT_STATUS_OK; -} - -static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security, - uint32_t feature) -{ - struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data; - if (feature & GENSEC_FEATURE_SIGN) { - return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG; - } - if (feature & GENSEC_FEATURE_SEAL) { - return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG; - } - return False; -} - -/* As a server, this could in theory accept any GSSAPI mech */ -static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = { - .name = "gssapi_krb5", - .sasl_name = "GSSAPI", - .oid = GENSEC_OID_KERBEROS5, - .client_start = gensec_gssapi_client_start, - .server_start = gensec_gssapi_server_start, - .update = gensec_gssapi_update, - .wrap = gensec_gssapi_wrap, - .unwrap = gensec_gssapi_unwrap, - .have_feature = gensec_gssapi_have_feature, - .enabled = False - -}; - -static const struct gensec_security_ops gensec_gssapi_spnego_security_ops = { - .name = "gssapi_spnego", - .sasl_name = "GSS-SPNEGO", - .oid = GENSEC_OID_SPNEGO, - .client_start = gensec_gssapi_client_start, - .server_start = gensec_gssapi_server_start, - .update = gensec_gssapi_update, - .wrap = gensec_gssapi_wrap, - .unwrap = gensec_gssapi_unwrap, - .have_feature = gensec_gssapi_have_feature, - .enabled = False -}; - -NTSTATUS gensec_gssapi_init(void) -{ - NTSTATUS ret; - - ret = gensec_register(&gensec_gssapi_krb5_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_gssapi_krb5_security_ops.name)); - return ret; - } - - ret = gensec_register(&gensec_gssapi_spnego_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_gssapi_spnego_security_ops.name)); - return ret; - } - - return ret; -} diff --git a/source4/libcli/auth/gensec_gsskrb5.c b/source4/libcli/auth/gensec_gsskrb5.c deleted file mode 100644 index 77e077276b..0000000000 --- a/source4/libcli/auth/gensec_gsskrb5.c +++ /dev/null @@ -1,584 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - GSSAPI KRB5 backend for GENSEC - - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004 - Copyright (C) Stefan Metzmacher <metze@samba.org> 2005 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "system/kerberos.h" -#include "system/time.h" -#include "libcli/auth/kerberos.h" -#include "auth/auth.h" - -static const gss_OID_desc gensec_gss_krb5_mechanism_oid_desc = - {9, (void *)discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")}; - -enum GENSEC_GSSKRB5_STATE { - GENSEC_GSSKRB5_CLIENT_START, - GENSEC_GSSKRB5_CLIENT_MUTUAL_AUTH, - GENSEC_GSSKRB5_CLIENT_DCE_STYLE, - GENSEC_GSSKRB5_DONE -}; - -struct gensec_gsskrb5_state { - enum GENSEC_GSSKRB5_STATE state_position; - gss_ctx_id_t gssapi_context; - struct gss_channel_bindings_struct *input_chan_bindings; - gss_name_t server_name; - gss_name_t client_name; - OM_uint32 want_flags, got_flags; -}; - -static int gensec_gsskrb5_destory(void *ptr) -{ - struct gensec_gsskrb5_state *gensec_gsskrb5_state = ptr; - OM_uint32 maj_stat, min_stat; - - if (gensec_gsskrb5_state->gssapi_context != GSS_C_NO_CONTEXT) { - maj_stat = gss_delete_sec_context (&min_stat, - &gensec_gsskrb5_state->gssapi_context, - GSS_C_NO_BUFFER); - } - - if (gensec_gsskrb5_state->server_name != GSS_C_NO_NAME) { - maj_stat = gss_release_name(&min_stat, &gensec_gsskrb5_state->server_name); - } - if (gensec_gsskrb5_state->client_name != GSS_C_NO_NAME) { - maj_stat = gss_release_name(&min_stat, &gensec_gsskrb5_state->client_name); - } - return 0; -} - -static NTSTATUS gensec_gsskrb5_start(struct gensec_security *gensec_security) -{ - struct gensec_gsskrb5_state *gensec_gsskrb5_state; - - gensec_gsskrb5_state = talloc(gensec_security, struct gensec_gsskrb5_state); - if (!gensec_gsskrb5_state) { - return NT_STATUS_NO_MEMORY; - } - - gensec_security->private_data = gensec_gsskrb5_state; - - gensec_gsskrb5_state->gssapi_context = GSS_C_NO_CONTEXT; - gensec_gsskrb5_state->server_name = GSS_C_NO_NAME; - gensec_gsskrb5_state->client_name = GSS_C_NO_NAME; - - talloc_set_destructor(gensec_gsskrb5_state, gensec_gsskrb5_destory); - - /* TODO: Fill in channel bindings */ - gensec_gsskrb5_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS; - - gensec_gsskrb5_state->want_flags = GSS_C_MUTUAL_FLAG; - gensec_gsskrb5_state->got_flags = 0; - - if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { - /* GSSAPI won't give us the session keys */ - return NT_STATUS_INVALID_PARAMETER; - } - if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { - gensec_gsskrb5_state->want_flags |= GSS_C_INTEG_FLAG; - } - if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { - gensec_gsskrb5_state->want_flags |= GSS_C_CONF_FLAG; - } - if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) { - gensec_gsskrb5_state->want_flags |= GSS_C_DCE_STYLE; - } - - return NT_STATUS_OK; -} - -static NTSTATUS gensec_gsskrb5_client_start(struct gensec_security *gensec_security) -{ - struct gensec_gsskrb5_state *gensec_gsskrb5_state; - NTSTATUS nt_status; - gss_buffer_desc name_token; - OM_uint32 maj_stat, min_stat; - - gss_OID_desc hostbased = {10, - (void *)discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12" - "\x01\x02\x01\x04")}; - - nt_status = gensec_gsskrb5_start(gensec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - gensec_gsskrb5_state = gensec_security->private_data; - - gensec_gsskrb5_state->state_position = GENSEC_GSSKRB5_CLIENT_START; - - name_token.value = talloc_asprintf(gensec_gsskrb5_state, "%s@%s", gensec_get_target_service(gensec_security), - gensec_get_target_hostname(gensec_security)); - DEBUG(0, ("name: %s\n", (char *)name_token.value)); - name_token.length = strlen(name_token.value); - - maj_stat = gss_import_name (&min_stat, - &name_token, - &hostbased, - &gensec_gsskrb5_state->server_name); - if (maj_stat) { - return NT_STATUS_UNSUCCESSFUL; - } - - return NT_STATUS_OK; -} - -/** - * Next state function for the GSSKRB5 GENSEC mechanism - * - * @param gensec_gsskrb5_state GSSAPI State - * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on - * @param in The request, as a DATA_BLOB - * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx - * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, - * or NT_STATUS_OK if the user is authenticated. - */ - -static NTSTATUS gensec_gsskrb5_update(struct gensec_security *gensec_security, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - struct gensec_gsskrb5_state *gensec_gsskrb5_state = gensec_security->private_data; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - OM_uint32 maj_stat, min_stat; - OM_uint32 min_stat2; - gss_buffer_desc input_token, output_token; - - *out = data_blob(NULL, 0); - - input_token.length = in.length; - input_token.value = in.data; - - switch (gensec_gsskrb5_state->state_position) { - case GENSEC_GSSKRB5_CLIENT_START: - { - maj_stat = gss_init_sec_context(&min_stat, - GSS_C_NO_CREDENTIAL, - &gensec_gsskrb5_state->gssapi_context, - gensec_gsskrb5_state->server_name, - discard_const_p(gss_OID_desc, &gensec_gss_krb5_mechanism_oid_desc), - gensec_gsskrb5_state->want_flags, - 0, - gensec_gsskrb5_state->input_chan_bindings, - &input_token, - NULL, - &output_token, - &gensec_gsskrb5_state->got_flags, /* ret flags */ - NULL); - *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length); - if (out->length != output_token.length) { - gss_release_buffer(&min_stat2, &output_token); - return NT_STATUS_NO_MEMORY; - } - gss_release_buffer(&min_stat2, &output_token); - - if (maj_stat == GSS_S_COMPLETE) { - gensec_gsskrb5_state->state_position = GENSEC_GSSKRB5_DONE; - return NT_STATUS_OK; - } else if (maj_stat == GSS_S_CONTINUE_NEEDED) { - gensec_gsskrb5_state->state_position = GENSEC_GSSKRB5_CLIENT_MUTUAL_AUTH; - return NT_STATUS_MORE_PROCESSING_REQUIRED; - } else { - gss_buffer_desc msg1, msg2; - OM_uint32 msg_ctx = 0; - - msg1.value = NULL; - msg2.value = NULL; - gss_display_status(&min_stat2, maj_stat, GSS_C_GSS_CODE, - GSS_C_NULL_OID, &msg_ctx, &msg1); - gss_display_status(&min_stat2, min_stat, GSS_C_MECH_CODE, - GSS_C_NULL_OID, &msg_ctx, &msg2); - DEBUG(1, ("gensec_gsskrb5_update: %s : %s\n", (char *)msg1.value, (char *)msg2.value)); - gss_release_buffer(&min_stat2, &msg1); - gss_release_buffer(&min_stat2, &msg2); - - return nt_status; - } - break; - } - case GENSEC_GSSKRB5_CLIENT_MUTUAL_AUTH: - { - maj_stat = gss_init_sec_context(&min_stat, - GSS_C_NO_CREDENTIAL, - &gensec_gsskrb5_state->gssapi_context, - gensec_gsskrb5_state->server_name, - discard_const_p(gss_OID_desc, &gensec_gss_krb5_mechanism_oid_desc), - gensec_gsskrb5_state->want_flags, - 0, - gensec_gsskrb5_state->input_chan_bindings, - &input_token, - NULL, - &output_token, - &gensec_gsskrb5_state->got_flags, /* ret flags */ - NULL); - *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length); - if (out->length != output_token.length) { - gss_release_buffer(&min_stat2, &output_token); - return NT_STATUS_NO_MEMORY; - } - gss_release_buffer(&min_stat2, &output_token); - - if (maj_stat == GSS_S_COMPLETE) { - if (gensec_gsskrb5_state->got_flags & GSS_C_DCE_STYLE) { - gensec_gsskrb5_state->state_position = GENSEC_GSSKRB5_CLIENT_DCE_STYLE; - return NT_STATUS_MORE_PROCESSING_REQUIRED; - } - gensec_gsskrb5_state->state_position = GENSEC_GSSKRB5_DONE; - return NT_STATUS_OK; - } else if (maj_stat == GSS_S_CONTINUE_NEEDED) { - gensec_gsskrb5_state->state_position = GENSEC_GSSKRB5_CLIENT_DCE_STYLE; - return NT_STATUS_MORE_PROCESSING_REQUIRED; - } else { - gss_buffer_desc msg1, msg2; - OM_uint32 msg_ctx = 0; - - msg1.value = NULL; - msg2.value = NULL; - gss_display_status(&min_stat2, maj_stat, GSS_C_GSS_CODE, - GSS_C_NULL_OID, &msg_ctx, &msg1); - gss_display_status(&min_stat2, min_stat, GSS_C_MECH_CODE, - GSS_C_NULL_OID, &msg_ctx, &msg2); - DEBUG(1, ("gensec_gsskrb5_update: %s : %s\n", (char *)msg1.value, (char *)msg2.value)); - gss_release_buffer(&min_stat2, &msg1); - gss_release_buffer(&min_stat2, &msg2); - - return nt_status; - } - break; - } - case GENSEC_GSSKRB5_CLIENT_DCE_STYLE: - { - gensec_gsskrb5_state->state_position = GENSEC_GSSKRB5_DONE; - return NT_STATUS_OK; - } - case GENSEC_GSSKRB5_DONE: - { - return NT_STATUS_OK; - } - default: - return NT_STATUS_INVALID_PARAMETER; - } - - return NT_STATUS_INVALID_PARAMETER; -} - -static NTSTATUS gensec_gsskrb5_wrap(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - struct gensec_gsskrb5_state *gensec_gsskrb5_state = gensec_security->private_data; - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token, output_token; - int conf_state; - input_token.length = in->length; - input_token.value = in->data; - - maj_stat = gss_wrap(&min_stat, - gensec_gsskrb5_state->gssapi_context, - gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL), - GSS_C_QOP_DEFAULT, - &input_token, - &conf_state, - &output_token); - if (GSS_ERROR(maj_stat)) { - return NT_STATUS_ACCESS_DENIED; - } - *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length); - - gss_release_buffer(&min_stat, &output_token); - - if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) - && !conf_state) { - return NT_STATUS_ACCESS_DENIED; - } - return NT_STATUS_OK; -} - -static NTSTATUS gensec_gsskrb5_unwrap(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - struct gensec_gsskrb5_state *gensec_gsskrb5_state = gensec_security->private_data; - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token, output_token; - int conf_state; - gss_qop_t qop_state; - input_token.length = in->length; - input_token.value = in->data; - - maj_stat = gss_unwrap(&min_stat, - gensec_gsskrb5_state->gssapi_context, - &input_token, - &output_token, - &conf_state, - &qop_state); - if (GSS_ERROR(maj_stat)) { - return NT_STATUS_ACCESS_DENIED; - } - *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length); - - gss_release_buffer(&min_stat, &output_token); - - if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) - && !conf_state) { - return NT_STATUS_ACCESS_DENIED; - } - return NT_STATUS_OK; -} - -static size_t gensec_gsskrb5_sig_size(struct gensec_security *gensec_security) -{ - /* not const but work for DCERPC packets and arcfour */ - return 45; -} - -static NTSTATUS gensec_gsskrb5_seal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct gensec_gsskrb5_state *gensec_gsskrb5_state = gensec_security->private_data; - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token, output_token; - int conf_state; - ssize_t sig_length = 0; - - input_token.length = length; - input_token.value = data; - - maj_stat = gss_wrap(&min_stat, - gensec_gsskrb5_state->gssapi_context, - gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL), - GSS_C_QOP_DEFAULT, - &input_token, - &conf_state, - &output_token); - if (GSS_ERROR(maj_stat)) { - return NT_STATUS_ACCESS_DENIED; - } - - if (output_token.length < length) { - return NT_STATUS_INTERNAL_ERROR; - } - - sig_length = 45; - - memcpy(data, ((uint8_t *)output_token.value) + sig_length, length); - *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length); - -DEBUG(0,("gensec_gsskrb5_seal_packet: siglen: %d inlen: %d, wrap_len: %d\n", sig->length, length, output_token.length - sig_length)); -dump_data(0,sig->data, sig->length); -dump_data(0,data, length); -dump_data(0,((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length); - - gss_release_buffer(&min_stat, &output_token); - - if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) - && !conf_state) { - return NT_STATUS_ACCESS_DENIED; - } - return NT_STATUS_OK; -} - -static NTSTATUS gensec_gsskrb5_unseal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct gensec_gsskrb5_state *gensec_gsskrb5_state = gensec_security->private_data; - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token, output_token; - int conf_state; - gss_qop_t qop_state; - DATA_BLOB in; - -DEBUG(0,("gensec_gsskrb5_unseal_packet: siglen: %d\n", sig->length)); -dump_data(0,sig->data, sig->length); - - in = data_blob_talloc(mem_ctx, NULL, sig->length + length); - - memcpy(in.data, sig->data, sig->length); - memcpy(in.data + sig->length, data, length); - - input_token.length = in.length; - input_token.value = in.data; - - maj_stat = gss_unwrap(&min_stat, - gensec_gsskrb5_state->gssapi_context, - &input_token, - &output_token, - &conf_state, - &qop_state); - if (GSS_ERROR(maj_stat)) { - return NT_STATUS_ACCESS_DENIED; - } - - if (output_token.length != length) { - return NT_STATUS_INTERNAL_ERROR; - } - - memcpy(data, output_token.value, length); - - gss_release_buffer(&min_stat, &output_token); - - if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) - && !conf_state) { - return NT_STATUS_ACCESS_DENIED; - } - return NT_STATUS_OK; -} - -static NTSTATUS gensec_gsskrb5_sign_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct gensec_gsskrb5_state *gensec_gsskrb5_state = gensec_security->private_data; - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token, output_token; - int conf_state; - ssize_t sig_length = 0; - - input_token.length = length; - input_token.value = data; - - maj_stat = gss_wrap(&min_stat, - gensec_gsskrb5_state->gssapi_context, - 0, - GSS_C_QOP_DEFAULT, - &input_token, - &conf_state, - &output_token); - if (GSS_ERROR(maj_stat)) { - return NT_STATUS_ACCESS_DENIED; - } - - if (output_token.length < length) { - return NT_STATUS_INTERNAL_ERROR; - } - - sig_length = 45; - - /*memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);*/ - *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length); - -DEBUG(0,("gensec_gsskrb5_sign_packet: siglen: %d\n", sig->length)); -dump_data(0,sig->data, sig->length); - - gss_release_buffer(&min_stat, &output_token); - - return NT_STATUS_OK; -} - -static NTSTATUS gensec_gsskrb5_check_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - const DATA_BLOB *sig) -{ - struct gensec_gsskrb5_state *gensec_gsskrb5_state = gensec_security->private_data; - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token, output_token; - int conf_state; - gss_qop_t qop_state; - DATA_BLOB in; - -DEBUG(0,("gensec_gsskrb5_check_packet: siglen: %d\n", sig->length)); -dump_data(0,sig->data, sig->length); - - in = data_blob_talloc(mem_ctx, NULL, sig->length + length); - - memcpy(in.data, sig->data, sig->length); - memcpy(in.data + sig->length, data, length); - - input_token.length = in.length; - input_token.value = in.data; - - maj_stat = gss_unwrap(&min_stat, - gensec_gsskrb5_state->gssapi_context, - &input_token, - &output_token, - &conf_state, - &qop_state); - if (GSS_ERROR(maj_stat)) { - return NT_STATUS_ACCESS_DENIED; - } - - if (output_token.length != length) { - return NT_STATUS_INTERNAL_ERROR; - } - - /*memcpy(data, output_token.value, length);*/ - - gss_release_buffer(&min_stat, &output_token); - - return NT_STATUS_OK; -} - -static BOOL gensec_gsskrb5_have_feature(struct gensec_security *gensec_security, - uint32_t feature) -{ - struct gensec_gsskrb5_state *gensec_gsskrb5_state = gensec_security->private_data; - if (feature & GENSEC_FEATURE_SIGN) { - return gensec_gsskrb5_state->got_flags & GSS_C_INTEG_FLAG; - } - if (feature & GENSEC_FEATURE_SEAL) { - return gensec_gsskrb5_state->got_flags & GSS_C_CONF_FLAG; - } - return False; -} - -static const struct gensec_security_ops gensec_gsskrb5_security_ops = { - .name = "gsskrb5", - .auth_type = DCERPC_AUTH_TYPE_KRB5, - .oid = GENSEC_OID_KERBEROS5, - .client_start = gensec_gsskrb5_client_start, - .update = gensec_gsskrb5_update, - .sig_size = gensec_gsskrb5_sig_size, - .sign_packet = gensec_gsskrb5_sign_packet, - .check_packet = gensec_gsskrb5_check_packet, - .seal_packet = gensec_gsskrb5_seal_packet, - .unseal_packet = gensec_gsskrb5_unseal_packet, - .wrap = gensec_gsskrb5_wrap, - .unwrap = gensec_gsskrb5_unwrap, - .have_feature = gensec_gsskrb5_have_feature, - .enabled = False -}; - -NTSTATUS gensec_gsskrb5_init(void) -{ - NTSTATUS ret; - - ret = gensec_register(&gensec_gsskrb5_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_gsskrb5_security_ops.name)); - return ret; - } - - return ret; -} diff --git a/source4/libcli/auth/gensec_krb5.c b/source4/libcli/auth/gensec_krb5.c deleted file mode 100644 index 453485d816..0000000000 --- a/source4/libcli/auth/gensec_krb5.c +++ /dev/null @@ -1,751 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Kerberos backend for GENSEC - - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004 - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Luke Howard 2002-2003 - Copyright (C) Stefan Metzmacher 2004-2005 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "system/kerberos.h" -#include "system/time.h" -#include "libcli/auth/kerberos.h" -#include "librpc/gen_ndr/ndr_krb5pac.h" -#include "auth/auth.h" - -enum GENSEC_KRB5_STATE { - GENSEC_KRB5_SERVER_START, - GENSEC_KRB5_CLIENT_START, - GENSEC_KRB5_CLIENT_MUTUAL_AUTH, - GENSEC_KRB5_DONE -}; - -struct gensec_krb5_state { - DATA_BLOB session_key; - DATA_BLOB pac; - enum GENSEC_KRB5_STATE state_position; - krb5_context context; - krb5_auth_context auth_context; - krb5_ccache ccache; - krb5_data ticket; - krb5_keyblock keyblock; - char *peer_principal; -}; - -#ifdef KRB5_DO_VERIFY_PAC -static NTSTATUS gensec_krb5_pac_checksum(DATA_BLOB pac_data, - struct PAC_SIGNATURE_DATA *sig, - struct gensec_krb5_state *gensec_krb5_state, - uint32 keyusage) -{ - krb5_error_code ret; - krb5_crypto crypto; - Checksum cksum; - int i; - - cksum.cksumtype = (CKSUMTYPE)sig->type; - cksum.checksum.length = sizeof(sig->signature); - cksum.checksum.data = sig->signature; - - - ret = krb5_crypto_init(gensec_krb5_state->context, - &gensec_krb5_state->keyblock, - 0, - &crypto); - if (ret) { - DEBUG(0,("krb5_crypto_init() failed\n")); - return NT_STATUS_FOOBAR; - } - for (i=0; i < 40; i++) { - keyusage = i; - ret = krb5_verify_checksum(gensec_krb5_state->context, - crypto, - keyusage, - pac_data.data, - pac_data.length, - &cksum); - if (!ret) { - DEBUG(0,("PAC Verified: keyusage: %d\n", keyusage)); - break; - } - } - krb5_crypto_destroy(gensec_krb5_state->context, crypto); - - if (ret) { - DEBUG(0,("NOT verifying PAC checksums yet!\n")); - //return NT_STATUS_LOGON_FAILURE; - } else { - DEBUG(0,("PAC checksums verified!\n")); - } - - return NT_STATUS_OK; -} -#endif - -static NTSTATUS gensec_krb5_decode_pac(TALLOC_CTX *mem_ctx, - struct PAC_LOGON_INFO **logon_info_out, - DATA_BLOB blob, - struct gensec_krb5_state *gensec_krb5_state) -{ - NTSTATUS status; - struct PAC_SIGNATURE_DATA srv_sig; - struct PAC_SIGNATURE_DATA *srv_sig_ptr; - struct PAC_SIGNATURE_DATA kdc_sig; - struct PAC_SIGNATURE_DATA *kdc_sig_ptr; - struct PAC_LOGON_INFO *logon_info = NULL; - struct PAC_DATA pac_data; -#ifdef KRB5_DO_VERIFY_PAC - DATA_BLOB tmp_blob = data_blob(NULL, 0); -#endif - int i; - - status = ndr_pull_struct_blob(&blob, mem_ctx, &pac_data, - (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("can't parse the PAC\n")); - return status; - } - NDR_PRINT_DEBUG(PAC_DATA, &pac_data); - - if (pac_data.num_buffers < 3) { - /* we need logon_ingo, service_key and kdc_key */ - DEBUG(0,("less than 3 PAC buffers\n")); - return NT_STATUS_FOOBAR; - } - - for (i=0; i < pac_data.num_buffers; i++) { - switch (pac_data.buffers[i].type) { - case PAC_TYPE_LOGON_INFO: - if (!pac_data.buffers[i].info) { - break; - } - logon_info = &pac_data.buffers[i].info->logon_info; - break; - case PAC_TYPE_SRV_CHECKSUM: - if (!pac_data.buffers[i].info) { - break; - } - srv_sig_ptr = &pac_data.buffers[i].info->srv_cksum; - srv_sig = pac_data.buffers[i].info->srv_cksum; - break; - case PAC_TYPE_KDC_CHECKSUM: - if (!pac_data.buffers[i].info) { - break; - } - kdc_sig_ptr = &pac_data.buffers[i].info->kdc_cksum; - kdc_sig = pac_data.buffers[i].info->kdc_cksum; - break; - case PAC_TYPE_UNKNOWN_10: - break; - default: - break; - } - } - - if (!logon_info) { - DEBUG(0,("PAC no logon_info\n")); - return NT_STATUS_FOOBAR; - } - - if (!srv_sig_ptr) { - DEBUG(0,("PAC no srv_key\n")); - return NT_STATUS_FOOBAR; - } - - if (!kdc_sig_ptr) { - DEBUG(0,("PAC no kdc_key\n")); - return NT_STATUS_FOOBAR; - } -#ifdef KRB5_DO_VERIFY_PAC - /* clear the kdc_key */ -/* memset((void *)kdc_sig_ptr , '\0', sizeof(*kdc_sig_ptr));*/ - - status = ndr_push_struct_blob(&tmp_blob, mem_ctx, &pac_data, - (ndr_push_flags_fn_t)ndr_push_PAC_DATA); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - status = ndr_pull_struct_blob(&tmp_blob, mem_ctx, &pac_data, - (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("can't parse the PAC\n")); - return status; - } - /*NDR_PRINT_DEBUG(PAC_DATA, &pac_data);*/ - - /* verify by kdc_key */ - status = gensec_krb5_pac_checksum(tmp_blob, &kdc_sig, gensec_krb5_state, 0); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* clear the service_key */ -/* memset((void *)srv_sig_ptr , '\0', sizeof(*srv_sig_ptr));*/ - - status = ndr_push_struct_blob(&tmp_blob, mem_ctx, &pac_data, - (ndr_push_flags_fn_t)ndr_push_PAC_DATA); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - status = ndr_pull_struct_blob(&tmp_blob, mem_ctx, &pac_data, - (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("can't parse the PAC\n")); - return status; - } - NDR_PRINT_DEBUG(PAC_DATA, &pac_data); - - /* verify by servie_key */ - status = gensec_krb5_pac_checksum(tmp_blob, &srv_sig, gensec_krb5_state, 0); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } -#endif - DEBUG(0,("account_name: %s [%s]\n",logon_info->info3.base.account_name.string, logon_info->info3.base.full_name.string)); - *logon_info_out = logon_info; - - return status; -} - -static int gensec_krb5_destory(void *ptr) -{ - struct gensec_krb5_state *gensec_krb5_state = ptr; - - if (gensec_krb5_state->ticket.length) { - kerberos_free_data_contents(gensec_krb5_state->context, &gensec_krb5_state->ticket); - } - if (gensec_krb5_state->ccache) { - /* current heimdal - 0.6.3, which we need anyway, fixes segfaults here */ - krb5_cc_close(gensec_krb5_state->context, gensec_krb5_state->ccache); - } - - krb5_free_keyblock_contents(gensec_krb5_state->context, - &gensec_krb5_state->keyblock); - - if (gensec_krb5_state->auth_context) { - krb5_auth_con_free(gensec_krb5_state->context, - gensec_krb5_state->auth_context); - } - - if (gensec_krb5_state->context) { - krb5_free_context(gensec_krb5_state->context); - } - return 0; -} - -static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security) -{ - struct gensec_krb5_state *gensec_krb5_state; - krb5_error_code ret = 0; - - gensec_krb5_state = talloc(gensec_security, struct gensec_krb5_state); - if (!gensec_krb5_state) { - return NT_STATUS_NO_MEMORY; - } - - gensec_security->private_data = gensec_krb5_state; - - initialize_krb5_error_table(); - gensec_krb5_state->context = NULL; - gensec_krb5_state->auth_context = NULL; - gensec_krb5_state->ccache = NULL; - ZERO_STRUCT(gensec_krb5_state->ticket); - ZERO_STRUCT(gensec_krb5_state->keyblock); - gensec_krb5_state->session_key = data_blob(NULL, 0); - gensec_krb5_state->pac = data_blob(NULL, 0); - - talloc_set_destructor(gensec_krb5_state, gensec_krb5_destory); - - ret = krb5_init_context(&gensec_krb5_state->context); - if (ret) { - DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n", error_message(ret))); - return NT_STATUS_INTERNAL_ERROR; - } - - if (lp_realm() && *lp_realm()) { - ret = krb5_set_default_realm(gensec_krb5_state->context, lp_realm()); - if (ret) { - DEBUG(1,("gensec_krb5_start: krb5_set_default_realm failed (%s)\n", error_message(ret))); - return NT_STATUS_INTERNAL_ERROR; - } - } - - ret = krb5_auth_con_init(gensec_krb5_state->context, &gensec_krb5_state->auth_context); - if (ret) { - DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", error_message(ret))); - return NT_STATUS_INTERNAL_ERROR; - } - - return NT_STATUS_OK; -} - -static NTSTATUS gensec_krb5_server_start(struct gensec_security *gensec_security) -{ - NTSTATUS nt_status; - struct gensec_krb5_state *gensec_krb5_state; - - nt_status = gensec_krb5_start(gensec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - gensec_krb5_state = gensec_security->private_data; - gensec_krb5_state->state_position = GENSEC_KRB5_SERVER_START; - - return NT_STATUS_OK; -} - -static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security) -{ - struct gensec_krb5_state *gensec_krb5_state; - krb5_error_code ret; - NTSTATUS nt_status; - const char *hostname = gensec_get_target_hostname(gensec_security); - if (!hostname) { - DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n")); - return NT_STATUS_ACCESS_DENIED; - } - - nt_status = gensec_krb5_start(gensec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - gensec_krb5_state = gensec_security->private_data; - gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_START; - - /* TODO: This is effecivly a static/global variable... - - TODO: If the user set a username, we should use an in-memory CCACHE (see below) - */ - ret = krb5_cc_default(gensec_krb5_state->context, &gensec_krb5_state->ccache); - if (ret) { - DEBUG(1,("krb5_cc_default failed (%s)\n", - error_message(ret))); - return NT_STATUS_INTERNAL_ERROR; - } - - while (1) { - { - krb5_data in_data; - in_data.length = 0; - - ret = krb5_mk_req(gensec_krb5_state->context, - &gensec_krb5_state->auth_context, - AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED, - gensec_get_target_service(gensec_security), - hostname, - &in_data, gensec_krb5_state->ccache, - &gensec_krb5_state->ticket); - - } - switch (ret) { - case 0: - return NT_STATUS_OK; - case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: - DEBUG(3, ("Server [%s] is not registered with our KDC: %s\n", - hostname, error_message(ret))); - return NT_STATUS_ACCESS_DENIED; - case KRB5KDC_ERR_PREAUTH_FAILED: - case KRB5KRB_AP_ERR_TKT_EXPIRED: - case KRB5_CC_END: - /* Too much clock skew - we will need to kinit to re-skew the clock */ - case KRB5KRB_AP_ERR_SKEW: - case KRB5_KDCREP_SKEW: - { - DEBUG(3, ("kerberos (mk_req) failed: %s\n", - error_message(ret))); - /* fall down to remaining code */ - } - - - /* just don't print a message for these really ordinary messages */ - case KRB5_FCC_NOFILE: - case KRB5_CC_NOTFOUND: - case ENOENT: - - { - const char *password; - char *ccache_string; - time_t kdc_time = 0; - password = cli_credentials_get_password(gensec_security->credentials); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - /* this string should be unique */ - ccache_string = talloc_asprintf(gensec_krb5_state, "MEMORY:%s:%s:%s", - cli_credentials_get_principal(gensec_security->credentials, gensec_krb5_state), - gensec_get_target_hostname(gensec_security), - generate_random_str(gensec_krb5_state, 16)); - - ret = krb5_cc_resolve(gensec_krb5_state->context, ccache_string, &gensec_krb5_state->ccache); - if (ret) { - DEBUG(1,("failed to generate a new krb5 keytab (%s): %s\n", - ccache_string, - error_message(ret))); - return NT_STATUS_INTERNAL_ERROR; - } - - ret = kerberos_kinit_password_cc(gensec_krb5_state->context, gensec_krb5_state->ccache, - cli_credentials_get_principal(gensec_security->credentials, gensec_krb5_state), - password, NULL, &kdc_time); - - /* cope with ticket being in the future due to clock skew */ - if ((unsigned)kdc_time > time(NULL)) { - time_t t = time(NULL); - int time_offset =(unsigned)kdc_time-t; - DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset)); - krb5_set_real_time(gensec_krb5_state->context, t + time_offset + 1, 0); - break; - } - - if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) { - DEBUG(1,("kinit for %s failed (%s)\n", - cli_credentials_get_principal(gensec_security->credentials, gensec_krb5_state), - error_message(ret))); - return NT_STATUS_TIME_DIFFERENCE_AT_DC; - } - if (ret) { - DEBUG(1,("kinit for %s failed (%s)\n", - cli_credentials_get_principal(gensec_security->credentials, gensec_krb5_state), - error_message(ret))); - return NT_STATUS_WRONG_PASSWORD; - } - break; - } - default: - DEBUG(0, ("kerberos: %s\n", - error_message(ret))); - return NT_STATUS_UNSUCCESSFUL; - } - } -} - - -/** - * Next state function for the Krb5 GENSEC mechanism - * - * @param gensec_krb5_state KRB5 State - * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on - * @param in The request, as a DATA_BLOB - * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx - * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, - * or NT_STATUS_OK if the user is authenticated. - */ - -static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data; - krb5_error_code ret = 0; - DATA_BLOB pac; - NTSTATUS nt_status; - - switch (gensec_krb5_state->state_position) { - case GENSEC_KRB5_CLIENT_START: - { - if (ret) { - DEBUG(1,("ads_krb5_mk_req (request ticket) failed (%s)\n", - error_message(ret))); - nt_status = NT_STATUS_LOGON_FAILURE; - } else { - DATA_BLOB unwrapped_out; - -#ifndef GENSEC_SEND_UNWRAPPED_KRB5 /* This should be a switch for the torture code to set */ - unwrapped_out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->ticket.data, gensec_krb5_state->ticket.length); - - /* wrap that up in a nice GSS-API wrapping */ - *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REQ); -#else - *out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->ticket.data, gensec_krb5_state->ticket.length); -#endif - gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_MUTUAL_AUTH; - nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; - } - - return nt_status; - } - - case GENSEC_KRB5_CLIENT_MUTUAL_AUTH: - { - krb5_data inbuf; - krb5_ap_rep_enc_part *repl = NULL; - uint8_t tok_id[2]; - DATA_BLOB unwrapped_in; - - if (!gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) { - DEBUG(1,("gensec_gssapi_parse_krb5_wrap(mutual authentication) failed to parse\n")); - dump_data_pw("Mutual authentication message:\n", in.data, in.length); - return NT_STATUS_INVALID_PARAMETER; - } - /* TODO: check the tok_id */ - - inbuf.data = unwrapped_in.data; - inbuf.length = unwrapped_in.length; - ret = krb5_rd_rep(gensec_krb5_state->context, - gensec_krb5_state->auth_context, - &inbuf, &repl); - if (ret) { - DEBUG(1,("krb5_rd_rep (mutual authentication) failed (%s)\n", - error_message(ret))); - dump_data_pw("Mutual authentication message:\n", inbuf.data, inbuf.length); - nt_status = NT_STATUS_ACCESS_DENIED; - } else { - *out = data_blob(NULL, 0); - nt_status = NT_STATUS_OK; - gensec_krb5_state->state_position = GENSEC_KRB5_DONE; - } - if (repl) { - krb5_free_ap_rep_enc_part(gensec_krb5_state->context, repl); - } - return nt_status; - } - - case GENSEC_KRB5_SERVER_START: - { - char *principal; - DATA_BLOB unwrapped_in; - DATA_BLOB unwrapped_out = data_blob(NULL, 0); - uint8_t tok_id[2]; - - if (!in.data) { - *out = unwrapped_out; - return NT_STATUS_MORE_PROCESSING_REQUIRED; - } - - /* Parse the GSSAPI wrapping, if it's there... (win2k3 allows it to be omited) */ - if (!gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) { - nt_status = ads_verify_ticket(out_mem_ctx, - gensec_krb5_state->context, - gensec_krb5_state->auth_context, - lp_realm(), - gensec_get_target_service(gensec_security), &in, - &principal, &pac, &unwrapped_out, - &gensec_krb5_state->keyblock); - } else { - /* TODO: check the tok_id */ - nt_status = ads_verify_ticket(out_mem_ctx, - gensec_krb5_state->context, - gensec_krb5_state->auth_context, - lp_realm(), - gensec_get_target_service(gensec_security), - &unwrapped_in, - &principal, &pac, &unwrapped_out, - &gensec_krb5_state->keyblock); - } - - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - if (pac.data) { - gensec_krb5_state->pac = data_blob_talloc_reference(gensec_krb5_state, &pac); - } - - if (NT_STATUS_IS_OK(nt_status)) { - gensec_krb5_state->state_position = GENSEC_KRB5_DONE; - /* wrap that up in a nice GSS-API wrapping */ -#ifndef GENSEC_SEND_UNWRAPPED_KRB5 - *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REP); -#else - *out = unwrapped_out; -#endif - gensec_krb5_state->peer_principal = talloc_steal(gensec_krb5_state, principal); - } - return nt_status; - } - case GENSEC_KRB5_DONE: - return NT_STATUS_OK; - } - - return NT_STATUS_INVALID_PARAMETER; -} - -static NTSTATUS gensec_krb5_session_key(struct gensec_security *gensec_security, - DATA_BLOB *session_key) -{ - struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data; - krb5_context context = gensec_krb5_state->context; - krb5_auth_context auth_context = gensec_krb5_state->auth_context; - krb5_keyblock *skey; - krb5_error_code err; - - 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); - break; - case GENSEC_SERVER: - err = krb5_auth_con_getremotesubkey(context, auth_context, &skey); - break; - } - if (err == 0 && skey != NULL) { - DEBUG(10, ("Got KRB5 session key of length %d\n", 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; - dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length); - - krb5_free_keyblock(context, skey); - return NT_STATUS_OK; - } else { - DEBUG(10, ("KRB5 error getting session key %d\n", err)); - return NT_STATUS_NO_USER_SESSION_KEY; - } -} - -static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security, - struct auth_session_info **_session_info) -{ - NTSTATUS nt_status; - struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data; - struct auth_serversupplied_info *server_info = NULL; - struct auth_session_info *session_info = NULL; - struct PAC_LOGON_INFO *logon_info; - char *p; - char *principal; - const char *account_name; - const char *realm; - - principal = talloc_strdup(gensec_krb5_state, gensec_krb5_state->peer_principal); - NT_STATUS_HAVE_NO_MEMORY(principal); - - p = strchr(principal, '@'); - if (p) { - *p = '\0'; - p++; - realm = p; - } else { - realm = lp_realm(); - } - account_name = principal; - - /* decode and verify the pac */ - nt_status = gensec_krb5_decode_pac(gensec_krb5_state, &logon_info, gensec_krb5_state->pac, - gensec_krb5_state); - - /* IF we have the PAC - otherwise we need to get this - * data from elsewere - local ldb, or (TODO) lookup of some - * kind... - * - * when heimdal can generate the PAC, we should fail if there's - * no PAC present - */ - - if (NT_STATUS_IS_OK(nt_status)) { - union netr_Validation validation; - validation.sam3 = &logon_info->info3; - nt_status = make_server_info_netlogon_validation(gensec_krb5_state, - account_name, - 3, &validation, - &server_info); - talloc_free(principal); - NT_STATUS_NOT_OK_RETURN(nt_status); - } else { - DATA_BLOB user_sess_key = data_blob(NULL, 0); - DATA_BLOB lm_sess_key = data_blob(NULL, 0); - /* TODO: should we pass the krb5 session key in here? */ - nt_status = sam_get_server_info(gensec_krb5_state, account_name, realm, - user_sess_key, lm_sess_key, - &server_info); - talloc_free(principal); - NT_STATUS_NOT_OK_RETURN(nt_status); - } - - /* references the server_info into the session_info */ - nt_status = auth_generate_session_info(gensec_krb5_state, server_info, &session_info); - talloc_free(server_info); - NT_STATUS_NOT_OK_RETURN(nt_status); - - nt_status = gensec_krb5_session_key(gensec_security, &session_info->session_key); - NT_STATUS_NOT_OK_RETURN(nt_status); - - *_session_info = session_info; - - return NT_STATUS_OK; -} - -static BOOL gensec_krb5_have_feature(struct gensec_security *gensec_security, - uint32_t feature) -{ - if (feature & GENSEC_FEATURE_SESSION_KEY) { - return True; - } - - return False; -} - - -static const struct gensec_security_ops gensec_krb5_security_ops = { - .name = "krb5", - .auth_type = DCERPC_AUTH_TYPE_KRB5, - .oid = GENSEC_OID_KERBEROS5, - .client_start = gensec_krb5_client_start, - .server_start = gensec_krb5_server_start, - .update = gensec_krb5_update, - .session_key = gensec_krb5_session_key, - .session_info = gensec_krb5_session_info, - .have_feature = gensec_krb5_have_feature, - .enabled = False -}; - -static const struct gensec_security_ops gensec_ms_krb5_security_ops = { - .name = "ms_krb5", - .auth_type = DCERPC_AUTH_TYPE_KRB5, - .oid = GENSEC_OID_KERBEROS5_OLD, - .client_start = gensec_krb5_client_start, - .server_start = gensec_krb5_server_start, - .update = gensec_krb5_update, - .session_key = gensec_krb5_session_key, - .session_info = gensec_krb5_session_info, - .have_feature = gensec_krb5_have_feature, - .enabled = False -}; - - -NTSTATUS gensec_krb5_init(void) -{ - NTSTATUS ret; - - ret = gensec_register(&gensec_krb5_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_krb5_security_ops.name)); - return ret; - } - - ret = gensec_register(&gensec_ms_krb5_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_krb5_security_ops.name)); - return ret; - } - - return ret; -} diff --git a/source4/libcli/auth/gensec_ntlmssp.c b/source4/libcli/auth/gensec_ntlmssp.c deleted file mode 100644 index 5955904886..0000000000 --- a/source4/libcli/auth/gensec_ntlmssp.c +++ /dev/null @@ -1,514 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - dcerpc authentication operations - - Copyright (C) Andrew Tridgell 2003 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004 - Copyright (C) Stefan Metzmacher 2005 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "auth/auth.h" - -struct gensec_ntlmssp_state { - struct auth_context *auth_context; - struct auth_serversupplied_info *server_info; - struct ntlmssp_state *ntlmssp_state; - uint32_t have_features; -}; - - -/** - * Return the challenge as determined by the authentication subsystem - * @return an 8 byte random challenge - */ - -static const uint8_t *auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context; - NTSTATUS status; - const uint8_t *chal; - - status = auth_get_challenge(gensec_ntlmssp_state->auth_context, &chal); - if (!NT_STATUS_IS_OK(status)) { - return NULL; - } - - return chal; -} - -/** - * Some authentication methods 'fix' the challenge, so we may not be able to set it - * - * @return If the effective challenge used by the auth subsystem may be modified - */ -static BOOL auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_state) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context; - - return auth_challenge_may_be_modified(gensec_ntlmssp_state->auth_context); -} - -/** - * NTLM2 authentication modifies the effective challenge, - * @param challenge The new challenge value - */ -static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge) -{ - NTSTATUS nt_status; - struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context; - struct auth_context *auth_context = gensec_ntlmssp_state->auth_context; - const uint8_t *chal; - - if (challenge->length != 8) { - return NT_STATUS_INVALID_PARAMETER; - } - - chal = challenge->data; - - nt_status = auth_context_set_challenge(auth_context, chal, "NTLMSSP callback (NTLM2)"); - - return nt_status; -} - -/** - * Check the password on an NTLMSSP login. - * - * Return the session keys used on the connection. - */ - -static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context; - struct auth_usersupplied_info *user_info = NULL; - NTSTATUS nt_status; - - nt_status = make_user_info_map(ntlmssp_state, - gensec_ntlmssp_state->ntlmssp_state->user, - gensec_ntlmssp_state->ntlmssp_state->domain, - gensec_ntlmssp_state->ntlmssp_state->workstation, - gensec_ntlmssp_state->ntlmssp_state->lm_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->lm_resp : NULL, - gensec_ntlmssp_state->ntlmssp_state->nt_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->nt_resp : NULL, - NULL, NULL, NULL, True, - &user_info); - NT_STATUS_NOT_OK_RETURN(nt_status); - - nt_status = auth_check_password(gensec_ntlmssp_state->auth_context, gensec_ntlmssp_state, - user_info, &gensec_ntlmssp_state->server_info); - talloc_free(user_info); - NT_STATUS_NOT_OK_RETURN(nt_status); - - if (gensec_ntlmssp_state->server_info->user_session_key.length) { - DEBUG(10, ("Got NT session key of length %u\n", gensec_ntlmssp_state->server_info->user_session_key.length)); - *user_session_key = data_blob_talloc(ntlmssp_state, - gensec_ntlmssp_state->server_info->user_session_key.data, - gensec_ntlmssp_state->server_info->user_session_key.length); - } - if (gensec_ntlmssp_state->server_info->lm_session_key.length) { - DEBUG(10, ("Got LM session key of length %u\n", gensec_ntlmssp_state->server_info->lm_session_key.length)); - *lm_session_key = data_blob_talloc(ntlmssp_state, - gensec_ntlmssp_state->server_info->lm_session_key.data, - gensec_ntlmssp_state->server_info->lm_session_key.length); - } - return nt_status; -} - -static int gensec_ntlmssp_destroy(void *ptr) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = ptr; - - if (gensec_ntlmssp_state->ntlmssp_state) { - ntlmssp_end(&gensec_ntlmssp_state->ntlmssp_state); - } - - return 0; -} - -static NTSTATUS gensec_ntlmssp_start(struct gensec_security *gensec_security) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state; - - gensec_ntlmssp_state = talloc(gensec_security, struct gensec_ntlmssp_state); - if (!gensec_ntlmssp_state) { - return NT_STATUS_NO_MEMORY; - } - - gensec_ntlmssp_state->ntlmssp_state = NULL; - gensec_ntlmssp_state->auth_context = NULL; - gensec_ntlmssp_state->server_info = NULL; - gensec_ntlmssp_state->have_features = 0; - - talloc_set_destructor(gensec_ntlmssp_state, gensec_ntlmssp_destroy); - - gensec_security->private_data = gensec_ntlmssp_state; - return NT_STATUS_OK; -} - -static NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security) -{ - NTSTATUS nt_status; - struct ntlmssp_state *ntlmssp_state; - struct gensec_ntlmssp_state *gensec_ntlmssp_state; - - nt_status = gensec_ntlmssp_start(gensec_security); - NT_STATUS_NOT_OK_RETURN(nt_status); - - gensec_ntlmssp_state = gensec_security->private_data; - - nt_status = ntlmssp_server_start(gensec_ntlmssp_state, &gensec_ntlmssp_state->ntlmssp_state); - NT_STATUS_NOT_OK_RETURN(nt_status); - - if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { - gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } - if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { - gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; - } - - nt_status = auth_context_create(gensec_ntlmssp_state, lp_auth_methods(), &gensec_ntlmssp_state->auth_context); - NT_STATUS_NOT_OK_RETURN(nt_status); - - ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state; - ntlmssp_state->auth_context = gensec_ntlmssp_state; - ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge; - ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge; - ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge; - ntlmssp_state->check_password = auth_ntlmssp_check_password; - ntlmssp_state->server_role = lp_server_role(); - - return NT_STATUS_OK; -} - -static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state; - const char *password = NULL; - NTSTATUS nt_status; - - nt_status = gensec_ntlmssp_start(gensec_security); - NT_STATUS_NOT_OK_RETURN(nt_status); - - gensec_ntlmssp_state = gensec_security->private_data; - nt_status = ntlmssp_client_start(gensec_ntlmssp_state, - &gensec_ntlmssp_state->ntlmssp_state); - NT_STATUS_NOT_OK_RETURN(nt_status); - - if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { - /* - * We need to set this to allow a later SetPassword - * via the SAMR pipe to succeed. Strange.... We could - * also add NTLMSSP_NEGOTIATE_SEAL here. JRA. - * - * Without this, Windows will not create the master key - * that it thinks is only used for NTLMSSP signing and - * sealing. (It is actually pulled out and used directly) - */ - gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } - if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { - gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } - if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { - gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; - } - - nt_status = ntlmssp_set_domain(gensec_ntlmssp_state->ntlmssp_state, - cli_credentials_get_domain(gensec_security->credentials)); - NT_STATUS_NOT_OK_RETURN(nt_status); - - nt_status = ntlmssp_set_username(gensec_ntlmssp_state->ntlmssp_state, - cli_credentials_get_username(gensec_security->credentials)); - NT_STATUS_NOT_OK_RETURN(nt_status); - - password = cli_credentials_get_password(gensec_security->credentials); - - nt_status = ntlmssp_set_password(gensec_ntlmssp_state->ntlmssp_state, password); - NT_STATUS_NOT_OK_RETURN(nt_status); - - nt_status = ntlmssp_set_workstation(gensec_ntlmssp_state->ntlmssp_state, - cli_credentials_get_workstation(gensec_security->credentials)); - - gensec_security->private_data = gensec_ntlmssp_state; - - return NT_STATUS_OK; -} - -/* - wrappers for the ntlmssp_*() functions -*/ -static NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - - return ntlmssp_unseal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig); -} - -static NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - const DATA_BLOB *sig) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - - return ntlmssp_check_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig); -} - -static NTSTATUS gensec_ntlmssp_seal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - - return ntlmssp_seal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig); -} - -static NTSTATUS gensec_ntlmssp_sign_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - - return ntlmssp_sign_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig); -} - -static size_t gensec_ntlmssp_sig_size(struct gensec_security *gensec_security) -{ - return NTLMSSP_SIG_SIZE; -} - -static NTSTATUS gensec_ntlmssp_wrap(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - DATA_BLOB sig; - NTSTATUS nt_status; - - if (gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) { - - *out = data_blob_talloc(mem_ctx, NULL, in->length + NTLMSSP_SIG_SIZE); - memcpy(out->data + NTLMSSP_SIG_SIZE, in->data, in->length); - - nt_status = ntlmssp_seal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, - out->data + NTLMSSP_SIG_SIZE, - out->length - NTLMSSP_SIG_SIZE, - out->data + NTLMSSP_SIG_SIZE, - out->length - NTLMSSP_SIG_SIZE, - &sig); - - if (NT_STATUS_IS_OK(nt_status)) { - memcpy(out->data, sig.data, NTLMSSP_SIG_SIZE); - } - return nt_status; - - } else if ((gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) - || (gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) { - - *out = data_blob_talloc(mem_ctx, NULL, in->length + NTLMSSP_SIG_SIZE); - memcpy(out->data + NTLMSSP_SIG_SIZE, in->data, in->length); - - nt_status = ntlmssp_sign_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, - out->data + NTLMSSP_SIG_SIZE, - out->length - NTLMSSP_SIG_SIZE, - out->data + NTLMSSP_SIG_SIZE, - out->length - NTLMSSP_SIG_SIZE, - &sig); - - if (NT_STATUS_IS_OK(nt_status)) { - memcpy(out->data, sig.data, NTLMSSP_SIG_SIZE); - } - return nt_status; - - } else { - *out = *in; - return NT_STATUS_OK; - } -} - - -static NTSTATUS gensec_ntlmssp_unwrap(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - DATA_BLOB sig; - - if (gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) { - if (in->length < NTLMSSP_SIG_SIZE) { - return NT_STATUS_INVALID_PARAMETER; - } - sig.data = in->data; - sig.length = NTLMSSP_SIG_SIZE; - - *out = data_blob_talloc(mem_ctx, in->data + NTLMSSP_SIG_SIZE, in->length - NTLMSSP_SIG_SIZE); - - return ntlmssp_unseal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, - out->data, out->length, - out->data, out->length, - &sig); - - } else if ((gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) - || (gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) { - if (in->length < NTLMSSP_SIG_SIZE) { - return NT_STATUS_INVALID_PARAMETER; - } - sig.data = in->data; - sig.length = NTLMSSP_SIG_SIZE; - - *out = data_blob_talloc(mem_ctx, in->data + NTLMSSP_SIG_SIZE, in->length - NTLMSSP_SIG_SIZE); - - return ntlmssp_check_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, - out->data, out->length, - out->data, out->length, - &sig); - } else { - *out = *in; - return NT_STATUS_OK; - } -} - -static NTSTATUS gensec_ntlmssp_session_key(struct gensec_security *gensec_security, - DATA_BLOB *session_key) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - - return ntlmssp_session_key(gensec_ntlmssp_state->ntlmssp_state, session_key); -} - -/** - * Next state function for the wrapped NTLMSSP state machine - * - * @param gensec_security GENSEC state, initialised to NTLMSSP - * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on - * @param in The request, as a DATA_BLOB - * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx - * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, - * or NT_STATUS_OK if the user is authenticated. - */ - -static NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - NTSTATUS status; - - status = ntlmssp_update(gensec_ntlmssp_state->ntlmssp_state, out_mem_ctx, in, out); - - if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) { - return status; - } - - gensec_ntlmssp_state->have_features = 0; - - if (gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) { - gensec_ntlmssp_state->have_features |= GENSEC_FEATURE_SIGN; - } - - if (gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) { - gensec_ntlmssp_state->have_features |= GENSEC_FEATURE_SEAL; - } - - if (gensec_ntlmssp_state->ntlmssp_state->session_key.data) { - gensec_ntlmssp_state->have_features |= GENSEC_FEATURE_SESSION_KEY; - } - - return status; -} - -/** - * Return the credentials of a logged on user, including session keys - * etc. - * - * Only valid after a successful authentication - * - * May only be called once per authentication. - * - */ - -static NTSTATUS gensec_ntlmssp_session_info(struct gensec_security *gensec_security, - struct auth_session_info **session_info) -{ - NTSTATUS nt_status; - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - - nt_status = auth_generate_session_info(gensec_ntlmssp_state, gensec_ntlmssp_state->server_info, session_info); - NT_STATUS_NOT_OK_RETURN(nt_status); - - (*session_info)->session_key = data_blob_talloc(*session_info, - gensec_ntlmssp_state->ntlmssp_state->session_key.data, - gensec_ntlmssp_state->ntlmssp_state->session_key.length); - - return NT_STATUS_OK; -} - -static BOOL gensec_ntlmssp_have_feature(struct gensec_security *gensec_security, - uint32_t feature) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - if (gensec_ntlmssp_state->have_features & feature) { - return True; - } - - return False; -} - -static const struct gensec_security_ops gensec_ntlmssp_security_ops = { - .name = "ntlmssp", - .sasl_name = "NTLM", - .auth_type = DCERPC_AUTH_TYPE_NTLMSSP, - .oid = GENSEC_OID_NTLMSSP, - .client_start = gensec_ntlmssp_client_start, - .server_start = gensec_ntlmssp_server_start, - .update = gensec_ntlmssp_update, - .sig_size = gensec_ntlmssp_sig_size, - .sign_packet = gensec_ntlmssp_sign_packet, - .check_packet = gensec_ntlmssp_check_packet, - .seal_packet = gensec_ntlmssp_seal_packet, - .unseal_packet = gensec_ntlmssp_unseal_packet, - .wrap = gensec_ntlmssp_wrap, - .unwrap = gensec_ntlmssp_unwrap, - .session_key = gensec_ntlmssp_session_key, - .session_info = gensec_ntlmssp_session_info, - .have_feature = gensec_ntlmssp_have_feature, - .enabled = True -}; - - -NTSTATUS gensec_ntlmssp_init(void) -{ - NTSTATUS ret; - ret = gensec_register(&gensec_ntlmssp_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_ntlmssp_security_ops.name)); - return ret; - } - - return ret; -} diff --git a/source4/libcli/auth/gssapi_parse.c b/source4/libcli/auth/gssapi_parse.c deleted file mode 100644 index 89929c8c6d..0000000000 --- a/source4/libcli/auth/gssapi_parse.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - simple GSSAPI wrappers - - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002 - Copyright (C) Luke Howard 2003 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "asn_1.h" -#include "system/kerberos.h" -#include "libcli/auth/gensec.h" - -/* - generate a krb5 GSS-API wrapper packet given a ticket -*/ -DATA_BLOB gensec_gssapi_gen_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *ticket, const uint8_t tok_id[2]) -{ - struct asn1_data data; - DATA_BLOB ret = data_blob(NULL,0); - - if (!ticket->data) { - return ret; - } - - ZERO_STRUCT(data); - - asn1_push_tag(&data, ASN1_APPLICATION(0)); - asn1_write_OID(&data, GENSEC_OID_KERBEROS5); - - asn1_write(&data, tok_id, 2); - asn1_write(&data, ticket->data, ticket->length); - asn1_pop_tag(&data); - - if (data.has_error) { - DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data.ofs)); - asn1_free(&data); - } - - ret = data_blob_talloc(mem_ctx, data.data, data.length); - asn1_free(&data); - - return ret; -} - -/* - parse a krb5 GSS-API wrapper packet giving a ticket -*/ -BOOL gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, DATA_BLOB *ticket, uint8_t tok_id[2]) -{ - BOOL ret; - struct asn1_data data; - int data_remaining; - - asn1_load(&data, *blob); - asn1_start_tag(&data, ASN1_APPLICATION(0)); - asn1_check_OID(&data, GENSEC_OID_KERBEROS5); - - data_remaining = asn1_tag_remaining(&data); - - if (data_remaining < 3) { - data.has_error = True; - } else { - asn1_read(&data, tok_id, 2); - data_remaining -= 2; - *ticket = data_blob_talloc(mem_ctx, NULL, data_remaining); - asn1_read(&data, ticket->data, ticket->length); - } - - asn1_end_tag(&data); - - ret = !data.has_error; - - asn1_free(&data); - - return ret; -} - - diff --git a/source4/libcli/auth/kerberos.c b/source4/libcli/auth/kerberos.c deleted file mode 100644 index 89b4108280..0000000000 --- a/source4/libcli/auth/kerberos.c +++ /dev/null @@ -1,788 +0,0 @@ -/* - Unix SMB/CIFS implementation. - kerberos utility library - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Remus Koos 2001 - Copyright (C) Nalin Dahyabhai 2004. - Copyright (C) Jeremy Allison 2004. - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "system/kerberos.h" -#include "system/time.h" -#include "libcli/auth/kerberos.h" -#include "secrets.h" -#include "pstring.h" -#include "ads.h" - -#ifdef HAVE_KRB5 - -#define LIBADS_CCACHE_NAME "MEMORY:libads" - -/* - we use a prompter to avoid a crash bug in the kerberos libs when - dealing with empty passwords - this prompter is just a string copy ... -*/ -static krb5_error_code -kerb_prompter(krb5_context ctx, void *data, - const char *name, - const char *banner, - int num_prompts, - krb5_prompt prompts[]) -{ - if (num_prompts == 0) return 0; - - memset(prompts[0].reply->data, '\0', prompts[0].reply->length); - if (prompts[0].reply->length > 0) { - if (data) { - strncpy(prompts[0].reply->data, data, prompts[0].reply->length-1); - prompts[0].reply->length = strlen(prompts[0].reply->data); - } else { - prompts[0].reply->length = 0; - } - } - return 0; -} - -/* - simulate a kinit, putting the tgt in the given credentials cache. - Orignally by remus@snapserver.com -*/ - int kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc, - const char *principal, const char *password, - time_t *expire_time, time_t *kdc_time) -{ - krb5_error_code code = 0; - krb5_principal me; - krb5_creds my_creds; - krb5_get_init_creds_opt options; - - if ((code = krb5_parse_name(ctx, principal, &me))) { - return code; - } - - krb5_get_init_creds_opt_init(&options); - - if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, password, - kerb_prompter, - NULL, 0, NULL, &options))) { - krb5_free_principal(ctx, me); - return code; - } - - if ((code = krb5_cc_initialize(ctx, cc, me))) { - krb5_free_cred_contents(ctx, &my_creds); - krb5_free_principal(ctx, me); - return code; - } - - if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) { - krb5_free_cred_contents(ctx, &my_creds); - krb5_free_principal(ctx, me); - return code; - } - - if (expire_time) { - *expire_time = (time_t) my_creds.times.endtime; - } - - if (kdc_time) { - *kdc_time = (time_t) my_creds.times.starttime; - } - - krb5_free_cred_contents(ctx, &my_creds); - krb5_free_principal(ctx, me); - - return 0; -} - -/* - simulate a kinit, putting the tgt in the given credentials cache. - If cache_name == NULL place in default cache location. - - Orignally by remus@snapserver.com -*/ -int kerberos_kinit_password(const char *principal, - const char *password, - int time_offset, - time_t *expire_time, - const char *cache_name, - time_t *kdc_time) -{ - int code; - krb5_context ctx = NULL; - krb5_ccache cc = NULL; - - if ((code = krb5_init_context(&ctx))) - return code; - - if (time_offset != 0) { - krb5_set_real_time(ctx, time(NULL) + time_offset, 0); - } - - if ((code = krb5_cc_resolve(ctx, cache_name ? - cache_name : krb5_cc_default_name(ctx), &cc))) { - krb5_free_context(ctx); - return code; - } - - code = kerberos_kinit_password_cc(ctx, cc, principal, password, expire_time, kdc_time); - - krb5_cc_close(ctx, cc); - krb5_free_context(ctx); - - return code; -} - -/* run kinit to setup our ccache */ -int ads_kinit_password(struct ads_struct *ads) -{ - char *s; - int ret; - - if (asprintf(&s, "%s@%s", ads->auth.user_name, ads->auth.realm) == -1) { - return KRB5_CC_NOMEM; - } - - if (!ads->auth.password) { - return KRB5_LIBOS_CANTREADPWD; - } - - ret = kerberos_kinit_password(s, ads->auth.password, ads->auth.time_offset, - &ads->auth.expire, NULL, NULL); - - if (ret) { - DEBUG(0,("kerberos_kinit_password %s failed: %s\n", - s, error_message(ret))); - } - free(s); - return ret; -} - -int ads_kdestroy(const char *cc_name) -{ - krb5_error_code code; - krb5_context ctx = NULL; - krb5_ccache cc = NULL; - - if ((code = krb5_init_context (&ctx))) { - DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", - error_message(code))); - return code; - } - - if (!cc_name) { - if ((code = krb5_cc_default(ctx, &cc))) { - krb5_free_context(ctx); - return code; - } - } else { - if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) { - DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n", - error_message(code))); - krb5_free_context(ctx); - return code; - } - } - - if ((code = krb5_cc_destroy (ctx, cc))) { - DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", - error_message(code))); - } - - krb5_free_context (ctx); - return code; -} - -/************************************************************************ - Routine to fetch the salting principal for a service. Active - Directory may use a non-obvious principal name to generate the salt - when it determines the key to use for encrypting tickets for a service, - and hopefully we detected that when we joined the domain. - ************************************************************************/ - -static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype) -{ - char *ret = NULL; - -#if 0 - asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype); - if (!key) { - return NULL; - } - ret = (char *)secrets_fetch(key, NULL); - SAFE_FREE(key); -#endif - return ret; -} - -/************************************************************************ - Routine to get the salting principal for this service. Active - Directory may use a non-obvious principal name to generate the salt - when it determines the key to use for encrypting tickets for a service, - and hopefully we detected that when we joined the domain. - Caller must free if return is not null. - ************************************************************************/ - -krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context, - krb5_principal host_princ, - int enctype) -{ - char *unparsed_name = NULL, *salt_princ_s = NULL; - krb5_principal ret_princ = NULL; - - if (krb5_unparse_name(context, host_princ, &unparsed_name) != 0) { - return (krb5_principal)NULL; - } - - if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) { - krb5_free_unparsed_name(context, unparsed_name); - return (krb5_principal)NULL; - } - - if (krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) { - krb5_free_unparsed_name(context, unparsed_name); - SAFE_FREE(salt_princ_s); - return (krb5_principal)NULL; - } - krb5_free_unparsed_name(context, unparsed_name); - SAFE_FREE(salt_princ_s); - return ret_princ; -} - -/************************************************************************ - Routine to set the salting principal for this service. Active - Directory may use a non-obvious principal name to generate the salt - when it determines the key to use for encrypting tickets for a service, - and hopefully we detected that when we joined the domain. - Setting principal to NULL deletes this entry. - ************************************************************************/ - - BOOL kerberos_secrets_store_salting_principal(const char *service, - int enctype, - const char *principal) -{ - char *key = NULL; - BOOL ret = False; - krb5_context context = NULL; - krb5_principal princ = NULL; - char *princ_s = NULL; - char *unparsed_name = NULL; - - krb5_init_context(&context); - if (!context) { - return False; - } - if (strchr_m(service, '@')) { - asprintf(&princ_s, "%s", service); - } else { - asprintf(&princ_s, "%s@%s", service, lp_realm()); - } - - if (krb5_parse_name(context, princ_s, &princ) != 0) { - goto out; - - } - if (krb5_unparse_name(context, princ, &unparsed_name) != 0) { - goto out; - } - - asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype); - if (!key) { - goto out; - } - -#if 0 - if ((principal != NULL) && (strlen(principal) > 0)) { - ret = secrets_store(key, principal, strlen(principal) + 1); - } else { - ret = secrets_delete(key); - } -#endif - - out: - - SAFE_FREE(key); - SAFE_FREE(princ_s); - - if (unparsed_name) { - krb5_free_unparsed_name(context, unparsed_name); - } - if (context) { - krb5_free_context(context); - } - - return ret; -} - -/************************************************************************ - Routine to get initial credentials as a service ticket for the local machine. - Returns a buffer initialized with krb5_mk_req_extended. - ************************************************************************/ - -static krb5_error_code get_service_ticket(krb5_context ctx, - krb5_ccache ccache, - const char *service_principal, - int enctype, - krb5_data *p_outbuf) -{ - krb5_creds creds, *new_creds = NULL; - char *service_s = NULL; - char *machine_account = NULL, *password = NULL; - krb5_data in_data; - krb5_auth_context auth_context = NULL; - krb5_error_code err = 0; - - ZERO_STRUCT(creds); - - asprintf(&machine_account, "%s$@%s", lp_netbios_name(), lp_realm()); - if (machine_account == NULL) { - goto out; - } - password = secrets_fetch_machine_password(lp_workgroup()); - if (password == NULL) { - goto out; - } - if ((err = kerberos_kinit_password(machine_account, password, 0, NULL, LIBADS_CCACHE_NAME, NULL)) != 0) { - DEBUG(0,("get_service_ticket: kerberos_kinit_password %s@%s failed: %s\n", - machine_account, - lp_realm(), - error_message(err))); - goto out; - } - - /* Ok - the above call has gotten a TGT. Now we need to get a service - ticket to ourselves. */ - - /* Set up the enctype and client and server principal fields for krb5_get_credentials. */ - kerberos_set_creds_enctype(&creds, enctype); - - if ((err = krb5_cc_get_principal(ctx, ccache, &creds.client))) { - DEBUG(3, ("get_service_ticket: krb5_cc_get_principal failed: %s\n", - error_message(err))); - goto out; - } - - if (strchr_m(service_principal, '@')) { - asprintf(&service_s, "%s", service_principal); - } else { - asprintf(&service_s, "%s@%s", service_principal, lp_realm()); - } - - if ((err = krb5_parse_name(ctx, service_s, &creds.server))) { - DEBUG(0,("get_service_ticket: krb5_parse_name %s failed: %s\n", - service_s, error_message(err))); - goto out; - } - - if ((err = krb5_get_credentials(ctx, 0, ccache, &creds, &new_creds))) { - DEBUG(5,("get_service_ticket: krb5_get_credentials for %s enctype %d failed: %s\n", - service_s, enctype, error_message(err))); - goto out; - } - - memset(&in_data, '\0', sizeof(in_data)); - if ((err = krb5_mk_req_extended(ctx, &auth_context, 0, &in_data, - new_creds, p_outbuf)) != 0) { - DEBUG(0,("get_service_ticket: krb5_mk_req_extended failed: %s\n", - error_message(err))); - goto out; - } - - out: - - if (auth_context) { - krb5_auth_con_free(ctx, auth_context); - } - if (new_creds) { - krb5_free_creds(ctx, new_creds); - } - if (creds.server) { - krb5_free_principal(ctx, creds.server); - } - if (creds.client) { - krb5_free_principal(ctx, creds.client); - } - - SAFE_FREE(service_s); - SAFE_FREE(password); - SAFE_FREE(machine_account); - return err; -} - -/************************************************************************ - Check if the machine password can be used in conjunction with the salting_principal - to generate a key which will successfully decrypt the AP_REQ already - gotten as a message to the local machine. - ************************************************************************/ - -static BOOL verify_service_password(krb5_context ctx, - int enctype, - const char *salting_principal, - krb5_data *in_data) -{ - BOOL ret = False; - krb5_principal salting_kprinc = NULL; - krb5_ticket *ticket = NULL; - krb5_keyblock key; - krb5_data passdata; - char *salting_s = NULL; - char *password = NULL; - krb5_auth_context auth_context = NULL; - krb5_error_code err; - - memset(&passdata, '\0', sizeof(passdata)); - memset(&key, '\0', sizeof(key)); - - password = secrets_fetch_machine_password(lp_workgroup()); - if (password == NULL) { - goto out; - } - - if (strchr_m(salting_principal, '@')) { - asprintf(&salting_s, "%s", salting_principal); - } else { - asprintf(&salting_s, "%s@%s", salting_principal, lp_realm()); - } - - if ((err = krb5_parse_name(ctx, salting_s, &salting_kprinc))) { - DEBUG(0,("verify_service_password: krb5_parse_name %s failed: %s\n", - salting_s, error_message(err))); - goto out; - } - - passdata.length = strlen(password); - passdata.data = (char*)password; - if ((err = create_kerberos_key_from_string_direct(ctx, salting_kprinc, &passdata, &key, enctype))) { - DEBUG(0,("verify_service_password: create_kerberos_key_from_string %d failed: %s\n", - enctype, error_message(err))); - goto out; - } - - if ((err = krb5_auth_con_init(ctx, &auth_context)) != 0) { - DEBUG(0,("verify_service_password: krb5_auth_con_init failed %s\n", error_message(err))); - goto out; - } - - if ((err = krb5_auth_con_setuseruserkey(ctx, auth_context, &key)) != 0) { - DEBUG(0,("verify_service_password: krb5_auth_con_setuseruserkey failed %s\n", error_message(err))); - goto out; - } - - if (!(err = krb5_rd_req(ctx, &auth_context, in_data, NULL, NULL, NULL, &ticket))) { - DEBUG(10,("verify_service_password: decrypted message with enctype %u salt %s!\n", - (unsigned int)enctype, salting_s)); - ret = True; - } - - out: - - memset(&passdata, 0, sizeof(passdata)); - krb5_free_keyblock_contents(ctx, &key); - if (ticket != NULL) { - krb5_free_ticket(ctx, ticket); - } - if (salting_kprinc) { - krb5_free_principal(ctx, salting_kprinc); - } - SAFE_FREE(salting_s); - SAFE_FREE(password); - return ret; -} - -/************************************************************************ - * - * From the current draft of kerberos-clarifications: - * - * It is not possible to reliably generate a user's key given a pass - * phrase without contacting the KDC, since it will not be known - * whether alternate salt or parameter values are required. - * - * And because our server has a password, we have this exact problem. We - * make multiple guesses as to which principal name provides the salt which - * the KDC is using. - * - ************************************************************************/ - -static void kerberos_derive_salting_principal_for_enctype(const char *service_principal, - krb5_context ctx, - krb5_ccache ccache, - krb5_enctype enctype, - krb5_enctype *enctypes) -{ - char *salting_principals[3] = {NULL, NULL, NULL}, *second_principal = NULL; - krb5_error_code err = 0; - krb5_data outbuf; - int i, j; - - memset(&outbuf, '\0', sizeof(outbuf)); - - /* Check that the service_principal is useful. */ - if ((service_principal == NULL) || (strlen(service_principal) == 0)) { - return; - } - - /* Generate our first guess -- the principal as-given. */ - asprintf(&salting_principals[0], "%s", service_principal); - if ((salting_principals[0] == NULL) || (strlen(salting_principals[0]) == 0)) { - return; - } - - /* Generate our second guess -- the computer's principal, as Win2k3. */ - asprintf(&second_principal, "host/%s.%s", lp_netbios_name(), lp_realm()); - if (second_principal != NULL) { - strlower_m(second_principal); - asprintf(&salting_principals[1], "%s@%s", second_principal, lp_realm()); - SAFE_FREE(second_principal); - } - if ((salting_principals[1] == NULL) || (strlen(salting_principals[1]) == 0)) { - goto out; - } - - /* Generate our third guess -- the computer's principal, as Win2k. */ - asprintf(&second_principal, "HOST/%s", lp_netbios_name()); - if (second_principal != NULL) { - strlower_m(second_principal + 5); - asprintf(&salting_principals[2], "%s@%s", - second_principal, lp_realm()); - SAFE_FREE(second_principal); - } - if ((salting_principals[2] == NULL) || (strlen(salting_principals[2]) == 0)) { - goto out; - } - - /* Get a service ticket for ourselves into our memory ccache. */ - /* This will commonly fail if there is no principal by that name (and we're trying - many names). So don't print a debug 0 error. */ - - if ((err = get_service_ticket(ctx, ccache, service_principal, enctype, &outbuf)) != 0) { - DEBUG(3, ("verify_service_password: get_service_ticket failed: %s\n", - error_message(err))); - goto out; - } - - /* At this point we have a message to ourselves, salted only the KDC knows how. We - have to work out what that salting is. */ - - /* Try and find the correct salting principal. */ - for (i = 0; i < sizeof(salting_principals) / sizeof(salting_principals[i]); i++) { - if (verify_service_password(ctx, enctype, salting_principals[i], &outbuf)) { - break; - } - } - - /* If we failed to get a match, return. */ - if (i >= sizeof(salting_principals) / sizeof(salting_principals[i])) { - goto out; - } - - /* If we succeeded, store the principal for use for all enctypes which - * share the same cipher and string-to-key function. Doing this here - * allows servers which just pass a keytab to krb5_rd_req() to work - * correctly. */ - for (j = 0; enctypes[j] != 0; j++) { - if (enctype != enctypes[j]) { - /* If this enctype isn't compatible with the one which - * we used, skip it. */ - - if (!kerberos_compatible_enctypes(ctx, enctypes[j], enctype)) - continue; - } - /* If the principal which gives us the proper salt is the one - * which we would normally guess, don't bother noting anything - * in the secrets tdb. */ - if (strcmp(service_principal, salting_principals[i]) != 0) { - kerberos_secrets_store_salting_principal(service_principal, - enctypes[j], - salting_principals[i]); - } - } - - out : - - kerberos_free_data_contents(ctx, &outbuf); - SAFE_FREE(salting_principals[0]); - SAFE_FREE(salting_principals[1]); - SAFE_FREE(salting_principals[2]); - SAFE_FREE(second_principal); -} - -/************************************************************************ - Go through all the possible enctypes for this principal. - ************************************************************************/ - -static void kerberos_derive_salting_principal_direct(krb5_context context, - krb5_ccache ccache, - krb5_enctype *enctypes, - char *service_principal) -{ - int i; - - /* Try for each enctype separately, because the rules are - * different for different enctypes. */ - for (i = 0; enctypes[i] != 0; i++) { - /* Delete secrets entry first. */ - kerberos_secrets_store_salting_principal(service_principal, 0, NULL); -#ifdef ENCTYPE_ARCFOUR_HMAC - if (enctypes[i] == ENCTYPE_ARCFOUR_HMAC) { - /* Of course this'll always work, so just save - * ourselves the effort. */ - continue; - } -#endif - /* Try to figure out what's going on with this - * principal. */ - kerberos_derive_salting_principal_for_enctype(service_principal, - context, - ccache, - enctypes[i], - enctypes); - } -} - -/************************************************************************ - Wrapper function for the above. - ************************************************************************/ - -BOOL kerberos_derive_salting_principal(char *service_principal) -{ - krb5_context context = NULL; - krb5_enctype *enctypes = NULL; - krb5_ccache ccache = NULL; - krb5_error_code ret = 0; - - initialize_krb5_error_table(); - if ((ret = krb5_init_context(&context)) != 0) { - DEBUG(1,("kerberos_derive_cifs_salting_principals: krb5_init_context failed. %s\n", - error_message(ret))); - return False; - } - if ((ret = get_kerberos_allowed_etypes(context, &enctypes)) != 0) { - DEBUG(1,("kerberos_derive_cifs_salting_principals: get_kerberos_allowed_etypes failed. %s\n", - error_message(ret))); - goto out; - } - - if ((ret = krb5_cc_resolve(context, LIBADS_CCACHE_NAME, &ccache)) != 0) { - DEBUG(3, ("get_service_ticket: krb5_cc_resolve for %s failed: %s\n", - LIBADS_CCACHE_NAME, error_message(ret))); - goto out; - } - - kerberos_derive_salting_principal_direct(context, ccache, enctypes, service_principal); - - out: - if (enctypes) { - free_kerberos_etypes(context, enctypes); - } - if (ccache) { - krb5_cc_destroy(context, ccache); - } - if (context) { - krb5_free_context(context); - } - - return ret ? False : True; -} - -/************************************************************************ - Core function to try and determine what salt is being used for any keytab - keys. - ************************************************************************/ - -BOOL kerberos_derive_cifs_salting_principals(void) -{ - fstring my_fqdn; - char *service = NULL; - krb5_context context = NULL; - krb5_enctype *enctypes = NULL; - krb5_ccache ccache = NULL; - krb5_error_code ret = 0; - BOOL retval = False; - - initialize_krb5_error_table(); - if ((ret = krb5_init_context(&context)) != 0) { - DEBUG(1,("kerberos_derive_cifs_salting_principals: krb5_init_context failed. %s\n", - error_message(ret))); - return False; - } - if ((ret = get_kerberos_allowed_etypes(context, &enctypes)) != 0) { - DEBUG(1,("kerberos_derive_cifs_salting_principals: get_kerberos_allowed_etypes failed. %s\n", - error_message(ret))); - goto out; - } - - if ((ret = krb5_cc_resolve(context, LIBADS_CCACHE_NAME, &ccache)) != 0) { - DEBUG(3, ("get_service_ticket: krb5_cc_resolve for %s failed: %s\n", - LIBADS_CCACHE_NAME, error_message(ret))); - goto out; - } - - if (asprintf(&service, "%s$", lp_netbios_name()) != -1) { - strlower_m(service); - kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); - SAFE_FREE(service); - } - if (asprintf(&service, "cifs/%s", lp_netbios_name()) != -1) { - strlower_m(service); - kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); - SAFE_FREE(service); - } - if (asprintf(&service, "host/%s", lp_netbios_name()) != -1) { - strlower_m(service); - kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); - SAFE_FREE(service); - } - if (asprintf(&service, "cifs/%s.%s", lp_netbios_name(), lp_realm()) != -1) { - strlower_m(service); - kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); - SAFE_FREE(service); - } - if (asprintf(&service, "host/%s.%s", lp_netbios_name(), lp_realm()) != -1) { - strlower_m(service); - kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); - SAFE_FREE(service); - } - name_to_fqdn(my_fqdn, lp_netbios_name()); - if (asprintf(&service, "cifs/%s", my_fqdn) != -1) { - strlower_m(service); - kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); - SAFE_FREE(service); - } - if (asprintf(&service, "host/%s", my_fqdn) != -1) { - strlower_m(service); - kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); - SAFE_FREE(service); - } - - retval = True; - - out: - if (enctypes) { - free_kerberos_etypes(context, enctypes); - } - if (ccache) { - krb5_cc_destroy(context, ccache); - } - if (context) { - krb5_free_context(context); - } - return retval; -} -#endif diff --git a/source4/libcli/auth/kerberos.h b/source4/libcli/auth/kerberos.h deleted file mode 100644 index 4daf0ea07a..0000000000 --- a/source4/libcli/auth/kerberos.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - Unix SMB/CIFS implementation. - simple kerberos5 routines for active directory - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Luke Howard 2002-2003 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#if defined(HAVE_KRB5) - -/* not really ASN.1, but RFC 1964 */ -#define TOK_ID_KRB_AP_REQ "\x01\x00" -#define TOK_ID_KRB_AP_REP "\x02\x00" -#define TOK_ID_KRB_ERROR "\x03\x00" -#define TOK_ID_GSS_GETMIC "\x01\x01" -#define TOK_ID_GSS_WRAP "\x02\x01" - -#ifdef HAVE_KRB5_KEYBLOCK_KEYVALUE -#define KRB5_KEY_TYPE(k) ((k)->keytype) -#define KRB5_KEY_LENGTH(k) ((k)->keyvalue.length) -#define KRB5_KEY_DATA(k) ((k)->keyvalue.data) -#else -#define KRB5_KEY_TYPE(k) ((k)->enctype) -#define KRB5_KEY_LENGTH(k) ((k)->length) -#define KRB5_KEY_DATA(k) ((k)->contents) -#endif /* HAVE_KRB5_KEYBLOCK_KEYVALUE */ - -#ifndef HAVE_KRB5_SET_REAL_TIME -krb5_error_code krb5_set_real_time(krb5_context context, int32_t seconds, int32_t microseconds); -#endif - -#ifndef HAVE_KRB5_SET_DEFAULT_TGS_KTYPES -krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc); -#endif - -#if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY) -krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock); -#endif - -#ifndef HAVE_KRB5_FREE_UNPARSED_NAME -void krb5_free_unparsed_name(krb5_context ctx, char *val); -#endif - -#if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING) && !defined(HAVE_KRB5_PRINC_COMPONENT) -const krb5_data *krb5_princ_component(krb5_context context, krb5_principal principal, int i ); -#endif - -/* Samba wrapper function for krb5 functionality. */ -void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr); -int create_kerberos_key_from_string(krb5_context context, krb5_principal host_princ, krb5_data *password, krb5_keyblock *key, krb5_enctype enctype); -int create_kerberos_key_from_string_direct(krb5_context context, krb5_principal host_princ, krb5_data *password, krb5_keyblock *key, krb5_enctype enctype); -krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt); -krb5_error_code krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters); -krb5_error_code get_kerberos_allowed_etypes(krb5_context context, krb5_enctype **enctypes); -void free_kerberos_etypes(krb5_context context, krb5_enctype *enctypes); -BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, BOOL remote); -krb5_error_code ads_krb5_mk_req(krb5_context context, - krb5_auth_context *auth_context, - const krb5_flags ap_req_options, - const char *principal, - krb5_ccache ccache, - krb5_data *outbuf); -DATA_BLOB get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, - krb5_ticket *tkt); - -NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, - krb5_context context, - krb5_auth_context auth_context, - const char *realm, const char *service, - const DATA_BLOB *ticket, - char **principal, DATA_BLOB *auth_data, - DATA_BLOB *ap_rep, - krb5_keyblock *keyblock); -int kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc, - const char *principal, const char *password, - time_t *expire_time, time_t *kdc_time); -krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context, - krb5_principal host_princ, - int enctype); -void kerberos_set_creds_enctype(krb5_creds *pcreds, int enctype); -BOOL kerberos_compatible_enctypes(krb5_context context, krb5_enctype enctype1, krb5_enctype enctype2); -void kerberos_free_data_contents(krb5_context context, krb5_data *pdata); -krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry); -char *smb_get_krb5_error_message(krb5_context context, krb5_error_code code, TALLOC_CTX *mem_ctx); -#endif /* HAVE_KRB5 */ - diff --git a/source4/libcli/auth/kerberos_verify.c b/source4/libcli/auth/kerberos_verify.c deleted file mode 100644 index a1dfe1056e..0000000000 --- a/source4/libcli/auth/kerberos_verify.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - Unix SMB/CIFS implementation. - kerberos utility library - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Remus Koos 2001 - Copyright (C) Luke Howard 2003 - Copyright (C) Guenther Deschner 2003 - Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "system/kerberos.h" -#include "libcli/auth/kerberos.h" -#include "asn_1.h" -#include "lib/ldb/include/ldb.h" -#include "secrets.h" -#include "pstring.h" - -#ifdef HAVE_KRB5 - -#if !defined(HAVE_KRB5_PRINC_COMPONENT) -const krb5_data *krb5_princ_component(krb5_context, krb5_principal, int ); -#endif -static DATA_BLOB unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data) -{ - DATA_BLOB out; - DATA_BLOB pac_contents = data_blob(NULL, 0); - struct asn1_data data; - int data_type; - if (!auth_data->length) { - return data_blob(NULL, 0); - } - - asn1_load(&data, *auth_data); - asn1_start_tag(&data, ASN1_SEQUENCE(0)); - asn1_start_tag(&data, ASN1_SEQUENCE(0)); - asn1_start_tag(&data, ASN1_CONTEXT(0)); - asn1_read_Integer(&data, &data_type); - asn1_end_tag(&data); - asn1_start_tag(&data, ASN1_CONTEXT(1)); - asn1_read_OctetString(&data, &pac_contents); - asn1_end_tag(&data); - asn1_end_tag(&data); - asn1_end_tag(&data); - asn1_free(&data); - - out = data_blob_talloc(mem_ctx, pac_contents.data, pac_contents.length); - - data_blob_free(&pac_contents); - - return out; -} - -/********************************************************************************** - Try to verify a ticket using the system keytab... the system keytab has kvno -1 entries, so - it's more like what microsoft does... see comment in utils/net_ads.c in the - ads_keytab_add_entry function for details. -***********************************************************************************/ - -static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_context context, - krb5_auth_context auth_context, - const char *service, - const DATA_BLOB *ticket, krb5_data *p_packet, - krb5_ticket **pp_tkt, - krb5_keyblock *keyblock) -{ - krb5_error_code ret = 0; - krb5_keytab keytab = NULL; - krb5_kt_cursor kt_cursor; - krb5_keytab_entry kt_entry; - char *valid_princ_formats[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; - char *entry_princ_s = NULL; - const char *my_name, *my_fqdn; - int i; - int number_matched_principals = 0; - const char *last_error_message; - - /* Generate the list of principal names which we expect - * clients might want to use for authenticating to the file - * service. We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */ - - my_name = lp_netbios_name(); - - my_fqdn = name_to_fqdn(mem_ctx, my_name); - - asprintf(&valid_princ_formats[0], "%s$@%s", my_name, lp_realm()); - asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm()); - asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm()); - asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm()); - asprintf(&valid_princ_formats[4], "cifs/%s@%s", my_name, lp_realm()); - asprintf(&valid_princ_formats[5], "cifs/%s@%s", my_fqdn, lp_realm()); - asprintf(&valid_princ_formats[6], "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm()); - - ZERO_STRUCT(kt_entry); - ZERO_STRUCT(kt_cursor); - - ret = krb5_kt_default(context, &keytab); - if (ret) { - DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_default failed (%s)\n", - smb_get_krb5_error_message(context, ret, mem_ctx))); - goto out; - } - - /* Iterate through the keytab. For each key, if the principal - * name case-insensitively matches one of the allowed formats, - * try verifying the ticket using that principal. */ - - ret = krb5_kt_start_seq_get(context, keytab, &kt_cursor); - if (ret) { - last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx); - DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n", - last_error_message)); - goto out; - } - - ret = krb5_kt_start_seq_get(context, keytab, &kt_cursor); - if (ret != KRB5_KT_END && ret != ENOENT ) { - ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; /* Pick an error... */ - while (ret && (krb5_kt_next_entry(context, keytab, &kt_entry, &kt_cursor) == 0)) { - krb5_error_code upn_ret; - upn_ret = krb5_unparse_name(context, kt_entry.principal, &entry_princ_s); - if (upn_ret) { - last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx); - DEBUG(1, ("ads_keytab_verify_ticket: krb5_unparse_name failed (%s)\n", - last_error_message)); - ret = upn_ret; - break; - } - for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) { - if (!strequal(entry_princ_s, valid_princ_formats[i])) { - continue; - } - - number_matched_principals++; - p_packet->length = ticket->length; - p_packet->data = (krb5_pointer)ticket->data; - *pp_tkt = NULL; - ret = krb5_rd_req(context, &auth_context, p_packet, kt_entry.principal, keytab, NULL, pp_tkt); - if (ret) { - last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx); - DEBUG(10, ("ads_keytab_verify_ticket: krb5_rd_req(%s) failed: %s\n", - entry_princ_s, last_error_message)); - } else { - DEBUG(3,("ads_keytab_verify_ticket: krb5_rd_req succeeded for principal %s\n", - entry_princ_s)); - break; - } - } - - /* Free the name we parsed. */ - krb5_free_unparsed_name(context, entry_princ_s); - entry_princ_s = NULL; - - /* Free the entry we just read. */ - smb_krb5_kt_free_entry(context, &kt_entry); - ZERO_STRUCT(kt_entry); - } - krb5_kt_end_seq_get(context, keytab, &kt_cursor); - } - - ZERO_STRUCT(kt_cursor); - - out: - - if (ret) { - if (!number_matched_principals) { - DEBUG(3, ("ads_keytab_verify_ticket: no keytab principals matched expected file service name.\n")); - } else { - DEBUG(3, ("ads_keytab_verify_ticket: krb5_rd_req failed for all %d matched keytab principals\n", - number_matched_principals)); - } - DEBUG(3, ("ads_keytab_verify_ticket: last error: %s\n", last_error_message)); - } - - if (entry_princ_s) { - krb5_free_unparsed_name(context, entry_princ_s); - } - - { - krb5_keytab_entry zero_kt_entry; - ZERO_STRUCT(zero_kt_entry); - if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) { - smb_krb5_kt_free_entry(context, &kt_entry); - } - } - - { - krb5_kt_cursor zero_csr; - ZERO_STRUCT(zero_csr); - if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) { - krb5_kt_end_seq_get(context, keytab, &kt_cursor); - } - } - - if (keytab) { - krb5_kt_close(context, keytab); - } - - return ret; -} - -/********************************************************************************** - Try to verify a ticket using the secrets.tdb. -***********************************************************************************/ - -static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx, krb5_context context, - krb5_auth_context auth_context, - krb5_principal host_princ, - const DATA_BLOB *ticket, krb5_data *p_packet, - krb5_ticket **pp_tkt, - krb5_keyblock *keyblock) -{ - krb5_error_code ret = 0; - krb5_error_code our_ret; - krb5_data password; - krb5_enctype *enctypes = NULL; - int i; - const struct ldb_val *password_v; - struct ldb_context *ldb; - int ldb_ret; - struct ldb_message **msgs; - const char *base_dn = SECRETS_PRIMARY_DOMAIN_DN; - const char *attrs[] = { - "secret", - NULL - }; - - ZERO_STRUCTP(keyblock); - - /* Local secrets are stored in secrets.ldb */ - ldb = secrets_db_connect(mem_ctx); - if (!ldb) { - return ENOENT; - } - - /* search for the secret record */ - ldb_ret = gendb_search(ldb, - mem_ctx, base_dn, &msgs, attrs, - SECRETS_PRIMARY_REALM_FILTER, - lp_realm()); - if (ldb_ret == 0) { - DEBUG(1, ("Could not find domain join record for %s\n", - lp_realm())); - return ENOENT; - } else if (ldb_ret != 1) { - DEBUG(1, ("Found %d records matching cn=%s under DN %s\n", ldb_ret, - lp_realm(), base_dn)); - return ENOENT; - } - - password_v = ldb_msg_find_ldb_val(msgs[0], "secret"); - - password.data = password_v->data; - password.length = password_v->length; - - /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */ - - if ((ret = get_kerberos_allowed_etypes(context, &enctypes))) { - DEBUG(1,("ads_secrets_verify_ticket: krb5_get_permitted_enctypes failed (%s)\n", - error_message(ret))); - return ret; - } - - p_packet->length = ticket->length; - p_packet->data = (krb5_pointer)ticket->data; - - /* We need to setup a auth context with each possible encoding type in turn. */ - - ret = KRB5_BAD_ENCTYPE; - for (i=0;enctypes[i];i++) { - krb5_keyblock *key = NULL; - - if (!(key = malloc_p(krb5_keyblock))) { - break; - } - - if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i])) { - SAFE_FREE(key); - continue; - } - - krb5_auth_con_setuseruserkey(context, auth_context, key); - - krb5_free_keyblock(context, key); - - our_ret = krb5_rd_req(context, &auth_context, p_packet, - NULL, - NULL, NULL, pp_tkt); - if (!our_ret) { - - DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n", - (unsigned int)enctypes[i] )); - ret = our_ret; - break; - } - - DEBUG((our_ret != KRB5_BAD_ENCTYPE) ? 3 : 10, - ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n", - (unsigned int)enctypes[i], smb_get_krb5_error_message(context, our_ret, mem_ctx))); - - if (our_ret != KRB5_BAD_ENCTYPE) { - ret = our_ret; - } - } - - free_kerberos_etypes(context, enctypes); - - return ret; -} - -/********************************************************************************** - Verify an incoming ticket and parse out the principal name and - authorization_data if available. -***********************************************************************************/ - - NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, - krb5_context context, - krb5_auth_context auth_context, - const char *realm, const char *service, - const DATA_BLOB *ticket, - char **principal, DATA_BLOB *auth_data, - DATA_BLOB *ap_rep, - krb5_keyblock *keyblock) -{ - NTSTATUS sret = NT_STATUS_LOGON_FAILURE; - krb5_data packet; - krb5_ticket *tkt = NULL; - krb5_rcache rcache = NULL; - int ret; - - krb5_principal host_princ = NULL; - char *host_princ_s = NULL; - BOOL got_replay_mutex = False; - - char *malloc_principal; - - ZERO_STRUCT(packet); - ZERO_STRUCTP(auth_data); - ZERO_STRUCTP(ap_rep); - - /* This whole process is far more complex than I would - like. We have to go through all this to allow us to store - the secret internally, instead of using /etc/krb5.keytab */ - - asprintf(&host_princ_s, "%s$", lp_netbios_name()); - strlower_m(host_princ_s); - ret = krb5_parse_name(context, host_princ_s, &host_princ); - if (ret) { - DEBUG(1,("ads_verify_ticket: krb5_parse_name(%s) failed (%s)\n", - host_princ_s, error_message(ret))); - goto out; - } - - - /* Lock a mutex surrounding the replay as there is no locking in the MIT krb5 - * code surrounding the replay cache... */ - - if (!grab_server_mutex("replay cache mutex")) { - DEBUG(1,("ads_verify_ticket: unable to protect replay cache with mutex.\n")); - goto out; - } - - got_replay_mutex = True; - - /* - * JRA. We must set the rcache here. This will prevent replay attacks. - */ - - ret = krb5_get_server_rcache(context, krb5_princ_component(context, host_princ, 0), &rcache); - if (ret) { - DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache failed (%s)\n", error_message(ret))); - goto out; - } - - ret = krb5_auth_con_setrcache(context, auth_context, rcache); - if (ret) { - DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache failed (%s)\n", error_message(ret))); - goto out; - } - - ret = ads_keytab_verify_ticket(mem_ctx, context, auth_context, - service, ticket, &packet, &tkt, keyblock); - if (ret) { - DEBUG(10, ("ads_secrets_verify_ticket: using host principal: [%s]\n", host_princ_s)); - ret = ads_secrets_verify_ticket(mem_ctx, context, auth_context, - host_princ, ticket, - &packet, &tkt, keyblock); - } - - release_server_mutex(); - got_replay_mutex = False; - - if (ret) { - DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", - smb_get_krb5_error_message(context, ret, mem_ctx))); - goto out; - } - - ret = krb5_mk_rep(context, auth_context, &packet); - if (ret) { - DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n", - smb_get_krb5_error_message(context, ret, mem_ctx))); - goto out; - } - - *ap_rep = data_blob_talloc(mem_ctx, packet.data, packet.length); - SAFE_FREE(packet.data); - packet.length = 0; - -#if 0 - file_save("/tmp/ticket.dat", ticket->data, ticket->length); -#endif - - *auth_data = get_auth_data_from_tkt(mem_ctx, tkt); - - *auth_data = unwrap_pac(mem_ctx, auth_data); - -#if 0 - if (tkt->enc_part2) { - file_save("/tmp/authdata.dat", - tkt->enc_part2->authorization_data[0]->contents, - tkt->enc_part2->authorization_data[0]->length); - } -#endif - - if ((ret = krb5_unparse_name(context, get_principal_from_tkt(tkt), - &malloc_principal))) { - DEBUG(3,("ads_verify_ticket: krb5_unparse_name failed (%s)\n", - smb_get_krb5_error_message(context, ret, mem_ctx))); - sret = NT_STATUS_LOGON_FAILURE; - goto out; - } - - *principal = talloc_strdup(mem_ctx, malloc_principal); - SAFE_FREE(malloc_principal); - if (!principal) { - DEBUG(3,("ads_verify_ticket: talloc_strdup() failed\n")); - sret = NT_STATUS_NO_MEMORY; - goto out; - } - - sret = NT_STATUS_OK; - - out: - - if (got_replay_mutex) { - release_server_mutex(); - } - - if (!NT_STATUS_IS_OK(sret)) { - data_blob_free(auth_data); - } - - if (!NT_STATUS_IS_OK(sret)) { - data_blob_free(ap_rep); - } - - if (host_princ) { - krb5_free_principal(context, host_princ); - } - - if (tkt != NULL) { - krb5_free_ticket(context, tkt); - } - - SAFE_FREE(host_princ_s); - - return sret; -} - -#endif /* HAVE_KRB5 */ diff --git a/source4/libcli/auth/ntlmssp.c b/source4/libcli/auth/ntlmssp.c deleted file mode 100644 index 37374d9d39..0000000000 --- a/source4/libcli/auth/ntlmssp.c +++ /dev/null @@ -1,1322 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 3.0 - handle NLTMSSP, client server side parsing - - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "lib/crypto/crypto.h" -#include "pstring.h" - -static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - DATA_BLOB in, DATA_BLOB *out); -static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out); -static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out); -static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out); - -/** - * Callbacks for NTLMSSP - for both client and server operating modes - * - */ - -static const struct ntlmssp_callbacks { - enum ntlmssp_role role; - enum ntlmssp_message_type ntlmssp_command; - NTSTATUS (*fn)(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - DATA_BLOB in, DATA_BLOB *out); -} ntlmssp_callbacks[] = { - {NTLMSSP_CLIENT, NTLMSSP_INITIAL, ntlmssp_client_initial}, - {NTLMSSP_SERVER, NTLMSSP_NEGOTIATE, ntlmssp_server_negotiate}, - {NTLMSSP_CLIENT, NTLMSSP_CHALLENGE, ntlmssp_client_challenge}, - {NTLMSSP_SERVER, NTLMSSP_AUTH, ntlmssp_server_auth}, - {NTLMSSP_CLIENT, NTLMSSP_UNKNOWN, NULL}, - {NTLMSSP_SERVER, NTLMSSP_UNKNOWN, NULL} -}; - - -/** - * Print out the NTLMSSP flags for debugging - * @param neg_flags The flags from the packet - */ - -void debug_ntlmssp_flags(uint32_t neg_flags) -{ - DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags)); - - if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_UNICODE\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_OEM) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM\n")); - if (neg_flags & NTLMSSP_REQUEST_TARGET) - DEBUGADD(4, (" NTLMSSP_REQUEST_TARGET\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_SIGN) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SIGN\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_SEAL) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SEAL\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_LM_KEY\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NETWARE\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_NTLM) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM2\n")); - if (neg_flags & NTLMSSP_CHAL_TARGET_INFO) - DEBUGADD(4, (" NTLMSSP_CHAL_TARGET_INFO\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_128) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_128\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_KEY_EXCH\n")); -} - -/** - * Default challenge generation code. - * - */ - -static const uint8_t *get_challenge(const struct ntlmssp_state *ntlmssp_state) -{ - uint8_t *chal = talloc_size(ntlmssp_state, 8); - generate_random_buffer(chal, 8); - - return chal; -} - -/** - * Default 'we can set the challenge to anything we like' implementation - * - */ - -static BOOL may_set_challenge(const struct ntlmssp_state *ntlmssp_state) -{ - return True; -} - -/** - * Default 'we can set the challenge to anything we like' implementation - * - * Does not actually do anything, as the value is always in the structure anyway. - * - */ - -static NTSTATUS set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge) -{ - SMB_ASSERT(challenge->length == 8); - return NT_STATUS_OK; -} - -/** - * Set a username on an NTLMSSP context - ensures it is talloc()ed - * - */ - -NTSTATUS ntlmssp_set_username(struct ntlmssp_state *ntlmssp_state, const char *user) -{ - if (!user) { - /* it should be at least "" */ - DEBUG(1, ("NTLMSSP failed to set username - cannot accept NULL username\n")); - return NT_STATUS_INVALID_PARAMETER; - } - ntlmssp_state->user = talloc_strdup(ntlmssp_state, user); - if (!ntlmssp_state->user) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Set a password on an NTLMSSP context - ensures it is talloc()ed - * - */ -NTSTATUS ntlmssp_set_password(struct ntlmssp_state *ntlmssp_state, const char *password) -{ - if (!password) { - ntlmssp_state->password = NULL; - } else { - ntlmssp_state->password = talloc_strdup(ntlmssp_state, password); - if (!ntlmssp_state->password) { - return NT_STATUS_NO_MEMORY; - } - } - return NT_STATUS_OK; -} - -/** - * Set a domain on an NTLMSSP context - ensures it is talloc()ed - * - */ -NTSTATUS ntlmssp_set_domain(struct ntlmssp_state *ntlmssp_state, const char *domain) -{ - ntlmssp_state->domain = talloc_strdup(ntlmssp_state, domain); - if (!ntlmssp_state->domain) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Set a workstation on an NTLMSSP context - ensures it is talloc()ed - * - */ -NTSTATUS ntlmssp_set_workstation(struct ntlmssp_state *ntlmssp_state, const char *workstation) -{ - ntlmssp_state->workstation = talloc_strdup(ntlmssp_state, workstation); - if (!ntlmssp_state->workstation) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Store a DATA_BLOB containing an NTLMSSP response, for use later. - * This copies the data blob - */ - -NTSTATUS ntlmssp_store_response(struct ntlmssp_state *ntlmssp_state, - DATA_BLOB response) -{ - ntlmssp_state->stored_response = data_blob_talloc(ntlmssp_state, - response.data, response.length); - return NT_STATUS_OK; -} - -/** - * Next state function for the NTLMSSP state machine - * - * @param ntlmssp_state NTLMSSP State - * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on - * @param in The request, as a DATA_BLOB - * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx - * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, - * or NT_STATUS_OK if the user is authenticated. - */ - -NTSTATUS ntlmssp_update(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - DATA_BLOB input; - uint32_t ntlmssp_command; - int i; - - *out = data_blob(NULL, 0); - - if (ntlmssp_state->expected_state == NTLMSSP_DONE) { - return NT_STATUS_OK; - } - - if (!out_mem_ctx) { - /* if the caller doesn't want to manage/own the memory, - we can put it on our context */ - out_mem_ctx = ntlmssp_state; - } - - if (!in.length && ntlmssp_state->stored_response.length) { - input = ntlmssp_state->stored_response; - - /* we only want to read the stored response once - overwrite it */ - ntlmssp_state->stored_response = data_blob(NULL, 0); - } else { - input = in; - } - - if (!input.length) { - switch (ntlmssp_state->role) { - case NTLMSSP_CLIENT: - ntlmssp_command = NTLMSSP_INITIAL; - break; - case NTLMSSP_SERVER: - /* 'datagram' mode - no neg packet */ - ntlmssp_command = NTLMSSP_NEGOTIATE; - break; - } - } else { - if (!msrpc_parse(ntlmssp_state, - &input, "Cd", - "NTLMSSP", - &ntlmssp_command)) { - DEBUG(1, ("Failed to parse NTLMSSP packet, could not extract NTLMSSP command\n")); - dump_data(2, input.data, input.length); - return NT_STATUS_INVALID_PARAMETER; - } - } - - if (ntlmssp_command != ntlmssp_state->expected_state) { - DEBUG(1, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command, ntlmssp_state->expected_state)); - return NT_STATUS_INVALID_PARAMETER; - } - - for (i=0; ntlmssp_callbacks[i].fn; i++) { - if (ntlmssp_callbacks[i].role == ntlmssp_state->role - && ntlmssp_callbacks[i].ntlmssp_command == ntlmssp_command - && ntlmssp_callbacks[i].fn) { - return ntlmssp_callbacks[i].fn(ntlmssp_state, out_mem_ctx, input, out); - } - } - - DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n", - ntlmssp_state->role, ntlmssp_command)); - - return NT_STATUS_INVALID_PARAMETER; -} - -/** - * Return the NTLMSSP master session key - * - * @param ntlmssp_state NTLMSSP State - */ - -NTSTATUS ntlmssp_session_key(struct ntlmssp_state *ntlmssp_state, - DATA_BLOB *session_key) -{ - if (!ntlmssp_state->session_key.data) { - return NT_STATUS_NO_USER_SESSION_KEY; - } - *session_key = ntlmssp_state->session_key; - - return NT_STATUS_OK; -} - -/** - * End an NTLMSSP state machine - * - * @param ntlmssp_state NTLMSSP State, free()ed by this function - */ - -void ntlmssp_end(struct ntlmssp_state **ntlmssp_state) -{ - (*ntlmssp_state)->ref_count--; - - if ((*ntlmssp_state)->ref_count == 0) { - talloc_free(*ntlmssp_state); - } - - *ntlmssp_state = NULL; - return; -} - -/** - * Determine correct target name flags for reply, given server role - * and negotiated flags - * - * @param ntlmssp_state NTLMSSP State - * @param neg_flags The flags from the packet - * @param chal_flags The flags to be set in the reply packet - * @return The 'target name' string. - */ - -static const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state, - uint32_t neg_flags, uint32_t *chal_flags) -{ - if (neg_flags & NTLMSSP_REQUEST_TARGET) { - *chal_flags |= NTLMSSP_CHAL_TARGET_INFO; - *chal_flags |= NTLMSSP_REQUEST_TARGET; - if (ntlmssp_state->server_role == ROLE_STANDALONE) { - *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER; - return ntlmssp_state->server_name; - } else { - *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN; - return ntlmssp_state->get_domain(); - }; - } else { - return ""; - } -} - -static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, - uint32_t neg_flags, BOOL allow_lm) { - if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE; - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM; - ntlmssp_state->unicode = True; - } else { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE; - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM; - ntlmssp_state->unicode = False; - } - - if ((neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) && allow_lm && !ntlmssp_state->use_ntlmv2) { - /* other end forcing us to use LM */ - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY; - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; - } else { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - } - - if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; - } - - if (!(neg_flags & NTLMSSP_NEGOTIATE_SIGN)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN; - } - - if (!(neg_flags & NTLMSSP_NEGOTIATE_SEAL)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SEAL; - } - - if (!(neg_flags & NTLMSSP_NEGOTIATE_NTLM2)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; - } - - if (!(neg_flags & NTLMSSP_NEGOTIATE_128)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128; - if (neg_flags & NTLMSSP_NEGOTIATE_56) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56; - } - } - - if (!(neg_flags & NTLMSSP_NEGOTIATE_56)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56; - } - - if (!(neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH; - } - - if ((neg_flags & NTLMSSP_REQUEST_TARGET)) { - ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET; - } - -} - -/** - Weaken NTLMSSP keys to cope with down-level clients and servers. - - We probably should have some parameters to control this, but as - it only occours for LM_KEY connections, and this is controlled - by the client lanman auth/lanman auth parameters, it isn't too bad. -*/ - -static void ntlmssp_weaken_keys(struct ntlmssp_state *ntlmssp_state) { - /* Key weakening not performed on the master key for NTLM2 - and does not occour for NTLM1. Therefore we only need - to do this for the LM_KEY. - */ - - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) { - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) { - - } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) { - ntlmssp_state->session_key.data[7] = 0xa0; - } else { /* forty bits */ - ntlmssp_state->session_key.data[5] = 0xe5; - ntlmssp_state->session_key.data[6] = 0x38; - ntlmssp_state->session_key.data[7] = 0xb0; - } - ntlmssp_state->session_key.length = 8; - } -} - -/** - * Next state function for the Negotiate packet - * - * @param ntlmssp_state NTLMSSP State - * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on - * @param in The request, as a DATA_BLOB - * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx - * @return Errors or MORE_PROCESSING_REQUIRED if a reply is sent. - */ - -static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - DATA_BLOB struct_blob; - fstring dnsname, dnsdomname; - uint32_t neg_flags = 0; - uint32_t ntlmssp_command, chal_flags; - char *cliname=NULL, *domname=NULL; - const uint8_t *cryptkey; - const char *target_name; - - /* parse the NTLMSSP packet */ -#if 0 - file_save("ntlmssp_negotiate.dat", request.data, request.length); -#endif - - if (in.length) { - if (!msrpc_parse(ntlmssp_state, - &in, "CddAA", - "NTLMSSP", - &ntlmssp_command, - &neg_flags, - &cliname, - &domname)) { - DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP:\n")); - dump_data(2, in.data, in.length); - return NT_STATUS_INVALID_PARAMETER; - } - - debug_ntlmssp_flags(neg_flags); - } - - ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, ntlmssp_state->allow_lm_key); - - /* Ask our caller what challenge they would like in the packet */ - cryptkey = ntlmssp_state->get_challenge(ntlmssp_state); - - /* Check if we may set the challenge */ - if (!ntlmssp_state->may_set_challenge(ntlmssp_state)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; - } - - /* The flags we send back are not just the negotiated flags, - * they are also 'what is in this packet'. Therfore, we - * operate on 'chal_flags' from here on - */ - - chal_flags = ntlmssp_state->neg_flags; - - /* get the right name to fill in as 'target' */ - target_name = ntlmssp_target_name(ntlmssp_state, - neg_flags, &chal_flags); - if (target_name == NULL) - return NT_STATUS_INVALID_PARAMETER; - - ntlmssp_state->chal = data_blob_talloc(ntlmssp_state, cryptkey, 8); - ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state, cryptkey, 8); - - /* This should be a 'netbios domain -> DNS domain' mapping */ - dnsdomname[0] = '\0'; - get_mydomname(dnsdomname); - strlower_m(dnsdomname); - - dnsname[0] = '\0'; - get_myfullname(dnsname); - - /* This creates the 'blob' of names that appears at the end of the packet */ - if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) - { - const char *target_name_dns = ""; - if (chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN) { - target_name_dns = dnsdomname; - } else if (chal_flags |= NTLMSSP_TARGET_TYPE_SERVER) { - target_name_dns = dnsname; - } - - msrpc_gen(out_mem_ctx, - &struct_blob, "aaaaa", - NTLMSSP_NAME_TYPE_DOMAIN, target_name, - NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->server_name, - NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsdomname, - NTLMSSP_NAME_TYPE_SERVER_DNS, dnsname, - 0, ""); - } else { - struct_blob = data_blob(NULL, 0); - } - - { - /* Marshel the packet in the right format, be it unicode or ASCII */ - const char *gen_string; - if (ntlmssp_state->unicode) { - gen_string = "CdUdbddB"; - } else { - gen_string = "CdAdbddB"; - } - - msrpc_gen(out_mem_ctx, - out, gen_string, - "NTLMSSP", - NTLMSSP_CHALLENGE, - target_name, - chal_flags, - cryptkey, 8, - 0, 0, - struct_blob.data, struct_blob.length); - } - - ntlmssp_state->expected_state = NTLMSSP_AUTH; - - return NT_STATUS_MORE_PROCESSING_REQUIRED; -} - -/** - * Next state function for the Authenticate packet - * - * @param ntlmssp_state NTLMSSP State - * @param request The request, as a DATA_BLOB - * @return Errors or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp_server_preauth(struct ntlmssp_state *ntlmssp_state, - const DATA_BLOB request) -{ - uint32_t ntlmssp_command, auth_flags; - NTSTATUS nt_status; - - uint8_t session_nonce_hash[16]; - - const char *parse_string; - char *domain = NULL; - char *user = NULL; - char *workstation = NULL; - -#if 0 - file_save("ntlmssp_auth.dat", request.data, request.length); -#endif - - if (ntlmssp_state->unicode) { - parse_string = "CdBBUUUBd"; - } else { - parse_string = "CdBBAAABd"; - } - - /* zero these out */ - data_blob_free(&ntlmssp_state->lm_resp); - data_blob_free(&ntlmssp_state->nt_resp); - - ntlmssp_state->user = NULL; - ntlmssp_state->domain = NULL; - ntlmssp_state->workstation = NULL; - - /* now the NTLMSSP encoded auth hashes */ - if (!msrpc_parse(ntlmssp_state, - &request, parse_string, - "NTLMSSP", - &ntlmssp_command, - &ntlmssp_state->lm_resp, - &ntlmssp_state->nt_resp, - &domain, - &user, - &workstation, - &ntlmssp_state->encrypted_session_key, - &auth_flags)) { - DEBUG(10, ("ntlmssp_server_auth: failed to parse NTLMSSP (nonfatal):\n")); - dump_data(10, request.data, request.length); - - /* zero this out */ - data_blob_free(&ntlmssp_state->encrypted_session_key); - auth_flags = 0; - - /* Try again with a shorter string (Win9X truncates this packet) */ - if (ntlmssp_state->unicode) { - parse_string = "CdBBUUU"; - } else { - parse_string = "CdBBAAA"; - } - - /* now the NTLMSSP encoded auth hashes */ - if (!msrpc_parse(ntlmssp_state, - &request, parse_string, - "NTLMSSP", - &ntlmssp_command, - &ntlmssp_state->lm_resp, - &ntlmssp_state->nt_resp, - &domain, - &user, - &workstation)) { - DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP:\n")); - dump_data(2, request.data, request.length); - - return NT_STATUS_INVALID_PARAMETER; - } - } - - if (auth_flags) - ntlmssp_handle_neg_flags(ntlmssp_state, auth_flags, ntlmssp_state->allow_lm_key); - - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) { - /* zero this out */ - data_blob_free(&ntlmssp_state->encrypted_session_key); - return nt_status; - } - - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) { - /* zero this out */ - data_blob_free(&ntlmssp_state->encrypted_session_key); - return nt_status; - } - - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_workstation(ntlmssp_state, workstation))) { - /* zero this out */ - data_blob_free(&ntlmssp_state->encrypted_session_key); - return nt_status; - } - - DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%lu len2=%lu\n", - ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, (unsigned long)ntlmssp_state->lm_resp.length, (unsigned long)ntlmssp_state->nt_resp.length)); - -#if 0 - file_save("nthash1.dat", &ntlmssp_state->nt_resp.data, &ntlmssp_state->nt_resp.length); - file_save("lmhash1.dat", &ntlmssp_state->lm_resp.data, &ntlmssp_state->lm_resp.length); -#endif - - /* NTLM2 uses a 'challenge' that is made of up both the server challenge, and a - client challenge - - However, the NTLM2 flag may still be set for the real NTLMv2 logins, be careful. - */ - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - if (ntlmssp_state->nt_resp.length == 24 && ntlmssp_state->lm_resp.length == 24) { - struct MD5Context md5_session_nonce_ctx; - SMB_ASSERT(ntlmssp_state->internal_chal.data - && ntlmssp_state->internal_chal.length == 8); - - ntlmssp_state->doing_ntlm2 = True; - - memcpy(ntlmssp_state->session_nonce, ntlmssp_state->internal_chal.data, 8); - memcpy(&ntlmssp_state->session_nonce[8], ntlmssp_state->lm_resp.data, 8); - - MD5Init(&md5_session_nonce_ctx); - MD5Update(&md5_session_nonce_ctx, ntlmssp_state->session_nonce, 16); - MD5Final(session_nonce_hash, &md5_session_nonce_ctx); - - ntlmssp_state->chal = data_blob_talloc(ntlmssp_state, - session_nonce_hash, 8); - - /* LM response is no longer useful, zero it out */ - data_blob_free(&ntlmssp_state->lm_resp); - - /* We changed the effective challenge - set it */ - if (!NT_STATUS_IS_OK(nt_status = - ntlmssp_state->set_challenge(ntlmssp_state, - &ntlmssp_state->chal))) { - /* zero this out */ - data_blob_free(&ntlmssp_state->encrypted_session_key); - return nt_status; - } - - /* LM Key is incompatible... */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - } - } - return NT_STATUS_OK; -} - -/** - * Next state function for the Authenticate packet - * (after authentication - figures out the session keys etc) - * - * @param ntlmssp_state NTLMSSP State - * @return Errors or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp_server_postauth(struct ntlmssp_state *ntlmssp_state, - DATA_BLOB *user_session_key, - DATA_BLOB *lm_session_key) -{ - NTSTATUS nt_status; - DATA_BLOB session_key = data_blob(NULL, 0); - - if (user_session_key) - dump_data_pw("USER session key:\n", user_session_key->data, user_session_key->length); - - if (lm_session_key) - dump_data_pw("LM first-8:\n", lm_session_key->data, lm_session_key->length); - - /* Handle the different session key derivation for NTLM2 */ - if (ntlmssp_state->doing_ntlm2) { - if (user_session_key && user_session_key->data && user_session_key->length == 16) { - session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - hmac_md5(user_session_key->data, ntlmssp_state->session_nonce, - sizeof(ntlmssp_state->session_nonce), session_key.data); - DEBUG(10,("ntlmssp_server_auth: Created NTLM2 session key.\n")); - dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length); - - } else { - DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM2 session key.\n")); - session_key = data_blob(NULL, 0); - } - } else if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) - /* Ensure we can never get here on NTLMv2 */ - && (ntlmssp_state->nt_resp.length == 0 || ntlmssp_state->nt_resp.length == 24)) { - - if (lm_session_key && lm_session_key->data && lm_session_key->length >= 8) { - if (ntlmssp_state->lm_resp.data && ntlmssp_state->lm_resp.length == 24) { - session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - SMBsesskeygen_lm_sess_key(lm_session_key->data, ntlmssp_state->lm_resp.data, - session_key.data); - DEBUG(10,("ntlmssp_server_auth: Created NTLM session key.\n")); - dump_data_pw("LM session key:\n", session_key.data, session_key.length); - } else { - - /* When there is no LM response, just use zeros */ - static const uint8_t zeros[24]; - session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - SMBsesskeygen_lm_sess_key(zeros, zeros, - session_key.data); - DEBUG(10,("ntlmssp_server_auth: Created NTLM session key.\n")); - dump_data_pw("LM session key:\n", session_key.data, session_key.length); - } - } else { - /* LM Key not selected */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - - DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM session key.\n")); - session_key = data_blob(NULL, 0); - } - - } else if (user_session_key && user_session_key->data) { - session_key = *user_session_key; - DEBUG(10,("ntlmssp_server_auth: Using unmodified nt session key.\n")); - dump_data_pw("unmodified session key:\n", session_key.data, session_key.length); - - /* LM Key not selected */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - - } else if (lm_session_key && lm_session_key->data) { - /* Very weird to have LM key, but no user session key, but anyway.. */ - session_key = *lm_session_key; - DEBUG(10,("ntlmssp_server_auth: Using unmodified lm session key.\n")); - dump_data_pw("unmodified session key:\n", session_key.data, session_key.length); - - /* LM Key not selected */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - - } else { - DEBUG(10,("ntlmssp_server_auth: Failed to create unmodified session key.\n")); - session_key = data_blob(NULL, 0); - - /* LM Key not selected */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - } - - /* With KEY_EXCH, the client supplies the proposed session key, - but encrypts it with the long-term key */ - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { - if (!ntlmssp_state->encrypted_session_key.data - || ntlmssp_state->encrypted_session_key.length != 16) { - data_blob_free(&ntlmssp_state->encrypted_session_key); - DEBUG(1, ("Client-supplied KEY_EXCH session key was of invalid length (%u)!\n", - ntlmssp_state->encrypted_session_key.length)); - return NT_STATUS_INVALID_PARAMETER; - } else if (!session_key.data || session_key.length != 16) { - DEBUG(5, ("server session key is invalid (len == %u), cannot do KEY_EXCH!\n", - session_key.length)); - ntlmssp_state->session_key = session_key; - } else { - dump_data_pw("KEY_EXCH session key (enc):\n", - ntlmssp_state->encrypted_session_key.data, - ntlmssp_state->encrypted_session_key.length); - arcfour_crypt(ntlmssp_state->encrypted_session_key.data, - session_key.data, - ntlmssp_state->encrypted_session_key.length); - ntlmssp_state->session_key = data_blob_talloc(ntlmssp_state, - ntlmssp_state->encrypted_session_key.data, - ntlmssp_state->encrypted_session_key.length); - dump_data_pw("KEY_EXCH session key:\n", ntlmssp_state->encrypted_session_key.data, - ntlmssp_state->encrypted_session_key.length); - } - } else { - ntlmssp_state->session_key = session_key; - } - - /* The server might need us to use a partial-strength session key */ - ntlmssp_weaken_keys(ntlmssp_state); - - nt_status = ntlmssp_sign_init(ntlmssp_state); - - data_blob_free(&ntlmssp_state->encrypted_session_key); - - /* allow arbitarily many authentications, but watch that this will cause a - memory leak, until the ntlmssp_state is shutdown - */ - - if (ntlmssp_state->server_multiple_authentications) { - ntlmssp_state->expected_state = NTLMSSP_AUTH; - } else { - ntlmssp_state->expected_state = NTLMSSP_DONE; - } - - return nt_status; -} - - -/** - * Next state function for the Authenticate packet - * - * @param ntlmssp_state NTLMSSP State - * @param in The packet in from the NTLMSSP partner, as a DATA_BLOB - * @param out The reply, as an allocated DATA_BLOB, caller to free. - * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - DATA_BLOB user_session_key = data_blob(NULL, 0); - DATA_BLOB lm_session_key = data_blob(NULL, 0); - NTSTATUS nt_status; - - /* zero the outbound NTLMSSP packet */ - *out = data_blob_talloc(out_mem_ctx, NULL, 0); - - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_preauth(ntlmssp_state, in))) { - return nt_status; - } - - /* - * Note we don't check here for NTLMv2 auth settings. If NTLMv2 auth - * is required (by "ntlm auth = no" and "lm auth = no" being set in the - * smb.conf file) and no NTLMv2 response was sent then the password check - * will fail here. JRA. - */ - - /* Finally, actually ask if the password is OK */ - - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->check_password(ntlmssp_state, - &user_session_key, &lm_session_key))) { - return nt_status; - } - - if (ntlmssp_state->server_use_session_keys) { - return ntlmssp_server_postauth(ntlmssp_state, &user_session_key, &lm_session_key); - } else { - ntlmssp_state->session_key = data_blob(NULL, 0); - return NT_STATUS_OK; - } -} - -/** - * Create an NTLMSSP state machine - * - * @param ntlmssp_state NTLMSSP State, allocated by this function - */ - -NTSTATUS ntlmssp_server_start(TALLOC_CTX *mem_ctx, struct ntlmssp_state **ntlmssp_state) -{ - *ntlmssp_state = talloc(mem_ctx, struct ntlmssp_state); - if (!*ntlmssp_state) { - DEBUG(0,("ntlmssp_server_start: talloc failed!\n")); - return NT_STATUS_NO_MEMORY; - } - ZERO_STRUCTP(*ntlmssp_state); - - (*ntlmssp_state)->role = NTLMSSP_SERVER; - - (*ntlmssp_state)->get_challenge = get_challenge; - (*ntlmssp_state)->set_challenge = set_challenge; - (*ntlmssp_state)->may_set_challenge = may_set_challenge; - - (*ntlmssp_state)->workstation = NULL; - (*ntlmssp_state)->server_name = lp_netbios_name(); - - (*ntlmssp_state)->get_domain = lp_workgroup; - (*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */ - - (*ntlmssp_state)->expected_state = NTLMSSP_NEGOTIATE; - - (*ntlmssp_state)->allow_lm_key = (lp_lanman_auth() - && lp_parm_bool(-1, "ntlmssp_server", "allow_lm_key", False)); - - (*ntlmssp_state)->server_use_session_keys = True; - (*ntlmssp_state)->server_multiple_authentications = False; - - (*ntlmssp_state)->ref_count = 1; - - (*ntlmssp_state)->neg_flags = - NTLMSSP_NEGOTIATE_NTLM; - - if (lp_parm_bool(-1, "ntlmssp_server", "128bit", True)) { - (*ntlmssp_state)->neg_flags |= NTLMSSP_NEGOTIATE_128; - } - - if (lp_parm_bool(-1, "ntlmssp_server", "keyexchange", True)) { - (*ntlmssp_state)->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH; - } - - if (lp_parm_bool(-1, "ntlmssp_server", "ntlm2", True)) { - (*ntlmssp_state)->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; - } - - return NT_STATUS_OK; -} - -/********************************************************************* - Client side NTLMSSP -*********************************************************************/ - -/** - * Next state function for the Initial packet - * - * @param ntlmssp_state NTLMSSP State - * @param out_mem_ctx The DATA_BLOB *out will be allocated on this context - * @param in The request, as a DATA_BLOB. reply.data must be NULL - * @param out The reply, as an talloc()ed DATA_BLOB, on out_mem_ctx - * @return Errors or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - DATA_BLOB in, DATA_BLOB *out) -{ - if (ntlmssp_state->unicode) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE; - } else { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM; - } - - if (ntlmssp_state->use_ntlmv2) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; - } - - /* generate the ntlmssp negotiate packet */ - msrpc_gen(out_mem_ctx, - out, "CddAA", - "NTLMSSP", - NTLMSSP_NEGOTIATE, - ntlmssp_state->neg_flags, - ntlmssp_state->get_domain(), - ntlmssp_state->workstation); - - ntlmssp_state->expected_state = NTLMSSP_CHALLENGE; - - return NT_STATUS_MORE_PROCESSING_REQUIRED; -} - -/** - * Next state function for the Challenge Packet. Generate an auth packet. - * - * @param ntlmssp_state NTLMSSP State - * @param request The request, as a DATA_BLOB. reply.data must be NULL - * @param request The reply, as an allocated DATA_BLOB, caller to free. - * @return Errors or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - uint32_t chal_flags, ntlmssp_command, unkn1, unkn2; - DATA_BLOB server_domain_blob; - DATA_BLOB challenge_blob; - DATA_BLOB struct_blob = data_blob(NULL, 0); - char *server_domain; - const char *chal_parse_string; - const char *auth_gen_string; - uint8_t lm_hash[16]; - DATA_BLOB lm_response = data_blob(NULL, 0); - DATA_BLOB nt_response = data_blob(NULL, 0); - DATA_BLOB session_key = data_blob(NULL, 0); - DATA_BLOB lm_session_key = data_blob(NULL, 0); - DATA_BLOB encrypted_session_key = data_blob(NULL, 0); - NTSTATUS nt_status; - - if (!msrpc_parse(ntlmssp_state, - &in, "CdBd", - "NTLMSSP", - &ntlmssp_command, - &server_domain_blob, - &chal_flags)) { - DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n")); - dump_data(2, in.data, in.length); - - return NT_STATUS_INVALID_PARAMETER; - } - - data_blob_free(&server_domain_blob); - - DEBUG(3, ("Got challenge flags:\n")); - debug_ntlmssp_flags(chal_flags); - - ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, ntlmssp_state->allow_lm_key); - - if (ntlmssp_state->unicode) { - if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) { - chal_parse_string = "CdUdbddB"; - } else { - chal_parse_string = "CdUdbdd"; - } - auth_gen_string = "CdBBUUUBd"; - } else { - if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) { - chal_parse_string = "CdAdbddB"; - } else { - chal_parse_string = "CdAdbdd"; - } - - auth_gen_string = "CdBBAAABd"; - } - - DEBUG(3, ("NTLMSSP: Set final flags:\n")); - debug_ntlmssp_flags(ntlmssp_state->neg_flags); - - if (!msrpc_parse(ntlmssp_state, - &in, chal_parse_string, - "NTLMSSP", - &ntlmssp_command, - &server_domain, - &chal_flags, - &challenge_blob, 8, - &unkn1, &unkn2, - &struct_blob)) { - DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n")); - dump_data(2, in.data, in.length); - return NT_STATUS_INVALID_PARAMETER; - } - - ntlmssp_state->server_domain = server_domain; - - if (challenge_blob.length != 8) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (!ntlmssp_state->password) { - static const uint8_t zeros[16]; - /* do nothing - blobs are zero length */ - - /* session key is all zeros */ - session_key = data_blob_talloc(ntlmssp_state, zeros, 16); - lm_session_key = data_blob_talloc(ntlmssp_state, zeros, 16); - - /* not doing NLTM2 without a password */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; - } else if (ntlmssp_state->use_ntlmv2) { - - if (!struct_blob.length) { - /* be lazy, match win2k - we can't do NTLMv2 without it */ - DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - /* TODO: if the remote server is standalone, then we should replace 'domain' - with the server name as supplied above */ - - if (!SMBNTLMv2encrypt(ntlmssp_state->user, - ntlmssp_state->domain, - ntlmssp_state->password, &challenge_blob, - &struct_blob, - &lm_response, &nt_response, - NULL, &session_key)) { - data_blob_free(&challenge_blob); - data_blob_free(&struct_blob); - return NT_STATUS_NO_MEMORY; - } - - /* LM Key is incompatible... */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - - } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - struct MD5Context md5_session_nonce_ctx; - uint8_t nt_hash[16]; - uint8_t session_nonce[16]; - uint8_t session_nonce_hash[16]; - uint8_t user_session_key[16]; - E_md4hash(ntlmssp_state->password, nt_hash); - - lm_response = data_blob_talloc(ntlmssp_state, NULL, 24); - generate_random_buffer(lm_response.data, 8); - memset(lm_response.data+8, 0, 16); - - memcpy(session_nonce, challenge_blob.data, 8); - memcpy(&session_nonce[8], lm_response.data, 8); - - MD5Init(&md5_session_nonce_ctx); - MD5Update(&md5_session_nonce_ctx, challenge_blob.data, 8); - MD5Update(&md5_session_nonce_ctx, lm_response.data, 8); - MD5Final(session_nonce_hash, &md5_session_nonce_ctx); - - DEBUG(5, ("NTLMSSP challenge set by NTLM2\n")); - DEBUG(5, ("challenge is: \n")); - dump_data(5, session_nonce_hash, 8); - - nt_response = data_blob_talloc(ntlmssp_state, NULL, 24); - SMBNTencrypt(ntlmssp_state->password, - session_nonce_hash, - nt_response.data); - - session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - - SMBsesskeygen_ntv1(nt_hash, user_session_key); - hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data); - dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length); - - /* LM Key is incompatible... */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - } else { - uint8_t nt_hash[16]; - - if (ntlmssp_state->use_nt_response) { - nt_response = data_blob_talloc(ntlmssp_state, NULL, 24); - SMBNTencrypt(ntlmssp_state->password,challenge_blob.data, - nt_response.data); - E_md4hash(ntlmssp_state->password, nt_hash); - session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - SMBsesskeygen_ntv1(nt_hash, session_key.data); - dump_data_pw("NT session key:\n", session_key.data, session_key.length); - } - - /* lanman auth is insecure, it may be disabled */ - if (lp_client_lanman_auth()) { - lm_response = data_blob_talloc(ntlmssp_state, NULL, 24); - if (!SMBencrypt(ntlmssp_state->password,challenge_blob.data, - lm_response.data)) { - /* If the LM password was too long (and therefore the LM hash being - of the first 14 chars only), don't send it */ - data_blob_free(&lm_response); - - /* LM Key is incompatible with 'long' passwords */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - } else { - E_deshash(ntlmssp_state->password, lm_hash); - lm_session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - memcpy(lm_session_key.data, lm_hash, 8); - memset(&lm_session_key.data[8], '\0', 8); - - if (!ntlmssp_state->use_nt_response) { - session_key = lm_session_key; - } - } - } else { - /* LM Key is incompatible... */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - } - } - - if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) - && lp_client_lanman_auth() && lm_session_key.length == 16) { - DATA_BLOB new_session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - if (lm_response.length == 24) { - SMBsesskeygen_lm_sess_key(lm_session_key.data, lm_response.data, - new_session_key.data); - } else { - static const uint8_t zeros[24]; - SMBsesskeygen_lm_sess_key(lm_session_key.data, zeros, - new_session_key.data); - } - new_session_key.length = 16; - session_key = new_session_key; - dump_data_pw("LM session key\n", session_key.data, session_key.length); - } - - - /* Key exchange encryptes a new client-generated session key with - the password-derived key */ - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { - /* Make up a new session key */ - uint8_t client_session_key[16]; - generate_random_buffer(client_session_key, sizeof(client_session_key)); - - /* Encrypt the new session key with the old one */ - encrypted_session_key = data_blob_talloc(ntlmssp_state, - client_session_key, sizeof(client_session_key)); - dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length); - arcfour_crypt(encrypted_session_key.data, session_key.data, encrypted_session_key.length); - dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length); - - /* Mark the new session key as the 'real' session key */ - session_key = data_blob_talloc(ntlmssp_state, client_session_key, sizeof(client_session_key)); - } - - /* this generates the actual auth packet */ - if (!msrpc_gen(out_mem_ctx, - out, auth_gen_string, - "NTLMSSP", - NTLMSSP_AUTH, - lm_response.data, lm_response.length, - nt_response.data, nt_response.length, - ntlmssp_state->domain, - ntlmssp_state->user, - ntlmssp_state->workstation, - encrypted_session_key.data, encrypted_session_key.length, - ntlmssp_state->neg_flags)) { - - return NT_STATUS_NO_MEMORY; - } - - ntlmssp_state->session_key = session_key; - - /* The client might be using 56 or 40 bit weakened keys */ - ntlmssp_weaken_keys(ntlmssp_state); - - ntlmssp_state->chal = challenge_blob; - ntlmssp_state->lm_resp = lm_response; - ntlmssp_state->nt_resp = nt_response; - - ntlmssp_state->expected_state = NTLMSSP_DONE; - - nt_status = ntlmssp_sign_init(ntlmssp_state); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", - nt_errstr(nt_status))); - return nt_status; - } - - return nt_status; -} - -NTSTATUS ntlmssp_client_start(TALLOC_CTX *mem_ctx, struct ntlmssp_state **ntlmssp_state) -{ - *ntlmssp_state = talloc(mem_ctx, struct ntlmssp_state); - if (!*ntlmssp_state) { - DEBUG(0,("ntlmssp_client_start: talloc failed!\n")); - return NT_STATUS_NO_MEMORY; - } - ZERO_STRUCTP(*ntlmssp_state); - - (*ntlmssp_state)->role = NTLMSSP_CLIENT; - - (*ntlmssp_state)->workstation = lp_netbios_name(); - (*ntlmssp_state)->get_domain = lp_workgroup; - - (*ntlmssp_state)->unicode = lp_parm_bool(-1, "ntlmssp_client", "unicode", True); - - (*ntlmssp_state)->use_nt_response = lp_parm_bool(-1, "ntlmssp_client", "send_nt_reponse", True); - - (*ntlmssp_state)->allow_lm_key = (lp_lanman_auth() - && lp_parm_bool(-1, "ntlmssp_client", "allow_lm_key", False)); - - (*ntlmssp_state)->use_ntlmv2 = lp_client_ntlmv2_auth(); - - (*ntlmssp_state)->expected_state = NTLMSSP_INITIAL; - - (*ntlmssp_state)->ref_count = 1; - - (*ntlmssp_state)->neg_flags = - NTLMSSP_NEGOTIATE_NTLM | - NTLMSSP_REQUEST_TARGET; - - if (lp_parm_bool(-1, "ntlmssp_client", "128bit", True)) { - (*ntlmssp_state)->neg_flags |= NTLMSSP_NEGOTIATE_128; - } - - if (lp_parm_bool(-1, "ntlmssp_client", "keyexchange", True)) { - (*ntlmssp_state)->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH; - } - - if (lp_parm_bool(-1, "ntlmssp_client", "ntlm2", True)) { - (*ntlmssp_state)->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; - } else { - /* apparently we can't do ntlmv2 if we don't do ntlm2 */ - (*ntlmssp_state)->use_ntlmv2 = False; - } - - return NT_STATUS_OK; -} - diff --git a/source4/libcli/auth/ntlmssp.h b/source4/libcli/auth/ntlmssp.h deleted file mode 100644 index e17c133c8b..0000000000 --- a/source4/libcli/auth/ntlmssp.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB parameters and setup - Copyright (C) Andrew Tridgell 1992-1997 - Copyright (C) Luke Kenneth Casson Leighton 1996-1997 - Copyright (C) Paul Ashton 1997 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "librpc/gen_ndr/ndr_samr.h" - -/* NTLMSSP mode */ -enum ntlmssp_role -{ - NTLMSSP_SERVER, - NTLMSSP_CLIENT -}; - -/* NTLMSSP message types */ -enum ntlmssp_message_type -{ - NTLMSSP_INITIAL = 0 /* samba internal state */, - NTLMSSP_NEGOTIATE = 1, - NTLMSSP_CHALLENGE = 2, - NTLMSSP_AUTH = 3, - NTLMSSP_UNKNOWN = 4, - NTLMSSP_DONE = 5 /* samba final state */ -}; - -/* NTLMSSP negotiation flags */ -#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 -#define NTLMSSP_NEGOTIATE_OEM 0x00000002 -#define NTLMSSP_REQUEST_TARGET 0x00000004 -#define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* Message integrity */ -#define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* Message confidentiality */ -#define NTLMSSP_NEGOTIATE_DATAGRAM_STYLE 0x00000040 -#define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 -#define NTLMSSP_NEGOTIATE_NETWARE 0x00000100 -#define NTLMSSP_NEGOTIATE_NTLM 0x00000200 -#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000 -#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000 -#define NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL 0x00004000 -#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 -#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 -#define NTLMSSP_TARGET_TYPE_SERVER 0x20000 -#define NTLMSSP_CHAL_INIT_RESPONSE 0x00010000 - -#define NTLMSSP_CHAL_ACCEPT_RESPONSE 0x00020000 -#define NTLMSSP_CHAL_NON_NT_SESSION_KEY 0x00040000 -#define NTLMSSP_NEGOTIATE_NTLM2 0x00080000 -#define NTLMSSP_CHAL_TARGET_INFO 0x00800000 -#define NTLMSSP_NEGOTIATE_128 0x20000000 /* 128-bit encryption */ -#define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 -#define NTLMSSP_NEGOTIATE_56 0x80000000 - -#define NTLMSSP_NAME_TYPE_SERVER 0x01 -#define NTLMSSP_NAME_TYPE_DOMAIN 0x02 -#define NTLMSSP_NAME_TYPE_SERVER_DNS 0x03 -#define NTLMSSP_NAME_TYPE_DOMAIN_DNS 0x04 - -#define NTLMSSP_SIGN_VERSION 1 - -#define NTLMSSP_SIG_SIZE 16 - -struct ntlmssp_state -{ - uint_t ref_count; - enum ntlmssp_role role; - enum samr_Role server_role; - uint32_t expected_state; - - BOOL unicode; - BOOL use_ntlmv2; - BOOL use_nt_response; /* Set to 'False' to debug what happens when the NT response is omited */ - BOOL allow_lm_key; /* The LM_KEY code is not functional at this point, and it's not - very secure anyway */ - - BOOL server_use_session_keys; /* Set to 'False' for authentication only, - that will never return a session key */ - BOOL server_multiple_authentications; /* Set to 'True' to allow squid 2.5 - style 'challenge caching' */ - - char *user; - char *domain; - const char *workstation; - char *password; - char *server_domain; - - DATA_BLOB internal_chal; /* Random challenge as supplied to the client for NTLM authentication */ - - DATA_BLOB chal; /* Random challenge as input into the actual NTLM (or NTLM2) authentication */ - DATA_BLOB lm_resp; - DATA_BLOB nt_resp; - DATA_BLOB session_key; - - uint32_t neg_flags; /* the current state of negotiation with the NTLMSSP partner */ - - /* internal variables used by NTLM2 */ - BOOL doing_ntlm2; - uint8_t session_nonce[16]; - - /* internal variables used by KEY_EXCH (client-supplied user session key */ - DATA_BLOB encrypted_session_key; - - void *auth_context; - - /** - * Callback to get the 'challenge' used for NTLM authentication. - * - * @param ntlmssp_state This structure - * @return 8 bytes of challenge data, determined by the server to be the challenge for NTLM authentication - * - */ - const uint8_t *(*get_challenge)(const struct ntlmssp_state *ntlmssp_state); - - /** - * Callback to find if the challenge used by NTLM authentication may be modified - * - * The NTLM2 authentication scheme modifies the effective challenge, but this is not compatiable with the - * current 'security=server' implementation.. - * - * @param ntlmssp_state This structure - * @return Can the challenge be set to arbitary values? - * - */ - BOOL (*may_set_challenge)(const struct ntlmssp_state *ntlmssp_state); - - /** - * Callback to set the 'challenge' used for NTLM authentication. - * - * The callback may use the void *auth_context to store state information, but the same value is always available - * from the DATA_BLOB chal on this structure. - * - * @param ntlmssp_state This structure - * @param challange 8 bytes of data, agreed by the client and server to be the effective challenge for NTLM2 authentication - * - */ - NTSTATUS (*set_challenge)(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge); - - /** - * Callback to check the user's password. - * - * The callback must reads the feilds of this structure for the information it needs on the user - * @param ntlmssp_state This structure - * @param nt_session_key If an NT session key is returned by the authentication process, return it here - * @param lm_session_key If an LM session key is returned by the authentication process, return it here - * - */ - NTSTATUS (*check_password)(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key); - - const char *server_name; - const char *(*get_domain)(void); - - /* SMB Signing */ - uint32_t ntlm_seq_num; - uint32_t ntlm2_send_seq_num; - uint32_t ntlm2_recv_seq_num; - - /* ntlmv2 */ - DATA_BLOB send_sign_key; - DATA_BLOB send_seal_key; - DATA_BLOB recv_sign_key; - DATA_BLOB recv_seal_key; - - uint8_t send_seal_hash[258]; - uint8_t recv_seal_hash[258]; - - /* ntlmv1 */ - uint8_t ntlmssp_hash[258]; - - /* it turns out that we don't always get the - response in at the time we want to process it. - Store it here, until we need it */ - DATA_BLOB stored_response; - -}; - diff --git a/source4/libcli/auth/ntlmssp_parse.c b/source4/libcli/auth/ntlmssp_parse.c deleted file mode 100644 index 42546cb130..0000000000 --- a/source4/libcli/auth/ntlmssp_parse.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - Unix SMB/CIFS implementation. - simple kerberos5/SPNEGO routines - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002 - Copyright (C) Andrew Bartlett 2002-2003 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "pstring.h" - -/* - this is a tiny msrpc packet generator. I am only using this to - avoid tying this code to a particular varient of our rpc code. This - generator is not general enough for all our rpc needs, its just - enough for the spnego/ntlmssp code - - format specifiers are: - - U = unicode string (input is unix string) - a = address (input is char *unix_string) - (1 byte type, 1 byte length, unicode/ASCII string, all inline) - A = ASCII string (input is unix string) - B = data blob (pointer + length) - b = data blob in header (pointer + length) - D - d = word (4 bytes) - C = constant ascii string - */ -BOOL msrpc_gen(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, - const char *format, ...) -{ - int i; - ssize_t n; - va_list ap; - char *s; - uint8_t *b; - int head_size=0, data_size=0; - int head_ofs, data_ofs; - int *intargs; - - DATA_BLOB *pointers; - - pointers = talloc_array(mem_ctx, DATA_BLOB, strlen(format)); - intargs = talloc_array(pointers, int, strlen(format)); - - /* first scan the format to work out the header and body size */ - va_start(ap, format); - for (i=0; format[i]; i++) { - switch (format[i]) { - case 'U': - s = va_arg(ap, char *); - head_size += 8; - n = push_ucs2_talloc(pointers, (void **)&pointers[i].data, s); - if (n == -1) { - return False; - } - pointers[i].length = n; - pointers[i].length -= 2; - data_size += pointers[i].length; - break; - case 'A': - s = va_arg(ap, char *); - head_size += 8; - n = push_ascii_talloc(pointers, (char **)&pointers[i].data, s); - if (n == -1) { - return False; - } - pointers[i].length = n; - pointers[i].length -= 1; - data_size += pointers[i].length; - break; - case 'a': - n = va_arg(ap, int); - intargs[i] = n; - s = va_arg(ap, char *); - n = push_ucs2_talloc(pointers, (void **)&pointers[i].data, s); - if (n == -1) { - return False; - } - pointers[i].length = n; - pointers[i].length -= 2; - data_size += pointers[i].length + 4; - break; - case 'B': - b = va_arg(ap, uint8_t *); - head_size += 8; - pointers[i].data = b; - pointers[i].length = va_arg(ap, int); - data_size += pointers[i].length; - break; - case 'b': - b = va_arg(ap, uint8_t *); - pointers[i].data = b; - pointers[i].length = va_arg(ap, int); - head_size += pointers[i].length; - break; - case 'd': - n = va_arg(ap, int); - intargs[i] = n; - head_size += 4; - break; - case 'C': - s = va_arg(ap, char *); - pointers[i].data = (uint8_t *)s; - pointers[i].length = strlen(s)+1; - head_size += pointers[i].length; - break; - } - } - va_end(ap); - - /* allocate the space, then scan the format again to fill in the values */ - *blob = data_blob_talloc(mem_ctx, NULL, head_size + data_size); - - head_ofs = 0; - data_ofs = head_size; - - va_start(ap, format); - for (i=0; format[i]; i++) { - switch (format[i]) { - case 'U': - case 'A': - case 'B': - n = pointers[i].length; - SSVAL(blob->data, head_ofs, n); head_ofs += 2; - SSVAL(blob->data, head_ofs, n); head_ofs += 2; - SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4; - if (pointers[i].data && n) /* don't follow null pointers... */ - memcpy(blob->data+data_ofs, pointers[i].data, n); - data_ofs += n; - break; - case 'a': - n = intargs[i]; - SSVAL(blob->data, data_ofs, n); data_ofs += 2; - - n = pointers[i].length; - SSVAL(blob->data, data_ofs, n); data_ofs += 2; - if (n >= 0) { - memcpy(blob->data+data_ofs, pointers[i].data, n); - } - data_ofs += n; - break; - case 'd': - n = intargs[i]; - SIVAL(blob->data, head_ofs, n); - head_ofs += 4; - break; - case 'b': - n = pointers[i].length; - memcpy(blob->data + head_ofs, pointers[i].data, n); - head_ofs += n; - break; - case 'C': - n = pointers[i].length; - memcpy(blob->data + head_ofs, pointers[i].data, n); - head_ofs += n; - break; - } - } - va_end(ap); - - talloc_free(pointers); - - return True; -} - - -/* a helpful macro to avoid running over the end of our blob */ -#define NEED_DATA(amount) \ -if ((head_ofs + amount) > blob->length) { \ - return False; \ -} - -/* - this is a tiny msrpc packet parser. This the the partner of msrpc_gen - - format specifiers are: - - U = unicode string (output is unix string) - A = ascii string - B = data blob - b = data blob in header - d = word (4 bytes) - C = constant ascii string - */ - -BOOL msrpc_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, - const char *format, ...) -{ - int i; - va_list ap; - const char **ps, *s; - DATA_BLOB *b; - size_t head_ofs = 0; - uint16_t len1, len2; - uint32_t ptr; - uint32_t *v; - pstring p; - - va_start(ap, format); - for (i=0; format[i]; i++) { - switch (format[i]) { - case 'U': - NEED_DATA(8); - len1 = SVAL(blob->data, head_ofs); head_ofs += 2; - len2 = SVAL(blob->data, head_ofs); head_ofs += 2; - ptr = IVAL(blob->data, head_ofs); head_ofs += 4; - - ps = (const char **)va_arg(ap, char **); - if (len1 == 0 && len2 == 0) { - *ps = ""; - } else { - /* make sure its in the right format - be strict */ - if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) { - return False; - } - if (len1 & 1) { - /* if odd length and unicode */ - return False; - } - if (blob->data + ptr < (uint8_t *)ptr || blob->data + ptr < blob->data) - return False; - - if (0 < len1) { - pull_string(p, blob->data + ptr, sizeof(p), - len1, - STR_UNICODE|STR_NOALIGN); - (*ps) = talloc_strdup(mem_ctx, p); - if (!(*ps)) { - return False; - } - } else { - (*ps) = ""; - } - } - break; - case 'A': - NEED_DATA(8); - len1 = SVAL(blob->data, head_ofs); head_ofs += 2; - len2 = SVAL(blob->data, head_ofs); head_ofs += 2; - ptr = IVAL(blob->data, head_ofs); head_ofs += 4; - - ps = (const char **)va_arg(ap, char **); - /* make sure its in the right format - be strict */ - if (len1 == 0 && len2 == 0) { - *ps = ""; - } else { - if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) { - return False; - } - - if (blob->data + ptr < (uint8_t *)ptr || blob->data + ptr < blob->data) - return False; - - if (0 < len1) { - pull_string(p, blob->data + ptr, sizeof(p), - len1, - STR_ASCII|STR_NOALIGN); - (*ps) = talloc_strdup(mem_ctx, p); - if (!(*ps)) { - return False; - } - } else { - (*ps) = ""; - } - } - break; - case 'B': - NEED_DATA(8); - len1 = SVAL(blob->data, head_ofs); head_ofs += 2; - len2 = SVAL(blob->data, head_ofs); head_ofs += 2; - ptr = IVAL(blob->data, head_ofs); head_ofs += 4; - - b = (DATA_BLOB *)va_arg(ap, void *); - if (len1 == 0 && len2 == 0) { - *b = data_blob_talloc(mem_ctx, NULL, 0); - } else { - /* make sure its in the right format - be strict */ - if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) { - return False; - } - - if (blob->data + ptr < (uint8_t *)ptr || blob->data + ptr < blob->data) - return False; - - *b = data_blob_talloc(mem_ctx, blob->data + ptr, len1); - } - break; - case 'b': - b = (DATA_BLOB *)va_arg(ap, void *); - len1 = va_arg(ap, uint_t); - /* make sure its in the right format - be strict */ - NEED_DATA(len1); - if (blob->data + head_ofs < (uint8_t *)head_ofs || blob->data + head_ofs < blob->data) - return False; - - *b = data_blob_talloc(mem_ctx, blob->data + head_ofs, len1); - head_ofs += len1; - break; - case 'd': - v = va_arg(ap, uint32_t *); - NEED_DATA(4); - *v = IVAL(blob->data, head_ofs); head_ofs += 4; - break; - case 'C': - s = va_arg(ap, char *); - - if (blob->data + head_ofs < (uint8_t *)head_ofs || blob->data + head_ofs < blob->data) - return False; - - head_ofs += pull_string(p, blob->data+head_ofs, sizeof(p), - blob->length - head_ofs, - STR_ASCII|STR_TERMINATE); - if (strcmp(s, p) != 0) { - return False; - } - break; - } - } - va_end(ap); - - return True; -} diff --git a/source4/libcli/auth/ntlmssp_sign.c b/source4/libcli/auth/ntlmssp_sign.c deleted file mode 100644 index 347a85da77..0000000000 --- a/source4/libcli/auth/ntlmssp_sign.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Version 3.0 - * NTLMSSP Signing routines - * Copyright (C) Luke Kenneth Casson Leighton 1996-2001 - * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004 - * - * 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 2 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, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include "includes.h" -#include "auth/auth.h" -#include "lib/crypto/crypto.h" - -#define CLI_SIGN "session key to client-to-server signing key magic constant" -#define CLI_SEAL "session key to client-to-server sealing key magic constant" -#define SRV_SIGN "session key to server-to-client signing key magic constant" -#define SRV_SEAL "session key to server-to-client sealing key magic constant" - -/** - * Some notes on then NTLM2 code: - * - * This code works correctly for the sealing part of the problem. If - * we disable the check for valid client signatures, then we see that - * the output of a rpcecho 'sinkdata' at smbd is correct. We get the - * valid data, and it is validly decrypted. - * - * This means that the quantity of data passing though the RC4 sealing - * pad is correct. - * - * This code also correctly matches test values that I have obtained, - * claiming to be the correct output of NTLM2 signature generation. - * - */ - -static void calc_ntlmv2_key(TALLOC_CTX *mem_ctx, - DATA_BLOB *subkey, - DATA_BLOB session_key, - const char *constant) -{ - struct MD5Context ctx3; - *subkey = data_blob_talloc(mem_ctx, NULL, 16); - MD5Init(&ctx3); - MD5Update(&ctx3, session_key.data, session_key.length); - MD5Update(&ctx3, constant, strlen(constant)+1); - MD5Final(subkey->data, &ctx3); -} - -enum ntlmssp_direction { - NTLMSSP_SEND, - NTLMSSP_RECEIVE -}; - -static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *sig_mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - enum ntlmssp_direction direction, - DATA_BLOB *sig, BOOL encrypt_sig) -{ - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - - HMACMD5Context ctx; - uint8_t digest[16]; - uint8_t seq_num[4]; - - *sig = data_blob_talloc(sig_mem_ctx, NULL, NTLMSSP_SIG_SIZE); - if (!sig->data) { - return NT_STATUS_NO_MEMORY; - } - - switch (direction) { - case NTLMSSP_SEND: - SIVAL(seq_num, 0, ntlmssp_state->ntlm2_send_seq_num); - ntlmssp_state->ntlm2_send_seq_num++; - hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key.data, - ntlmssp_state->send_sign_key.length, &ctx); - break; - case NTLMSSP_RECEIVE: - SIVAL(seq_num, 0, ntlmssp_state->ntlm2_recv_seq_num); - ntlmssp_state->ntlm2_recv_seq_num++; - hmac_md5_init_limK_to_64(ntlmssp_state->recv_sign_key.data, - ntlmssp_state->recv_sign_key.length, &ctx); - break; - } - hmac_md5_update(seq_num, sizeof(seq_num), &ctx); - hmac_md5_update(whole_pdu, pdu_length, &ctx); - hmac_md5_final(digest, &ctx); - - if (encrypt_sig && ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { - switch (direction) { - case NTLMSSP_SEND: - arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, digest, 8); - break; - case NTLMSSP_RECEIVE: - arcfour_crypt_sbox(ntlmssp_state->recv_seal_hash, digest, 8); - break; - } - } - - SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION); - memcpy(sig->data + 4, digest, 8); - memcpy(sig->data + 12, seq_num, 4); - - } else { - uint32_t crc; - crc = crc32_calc_buffer(data, length); - if (!msrpc_gen(sig_mem_ctx, sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlm_seq_num)) { - return NT_STATUS_NO_MEMORY; - } - ntlmssp_state->ntlm_seq_num++; - - arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4); - } - dump_data_pw("calculated ntlmssp signature\n", sig->data, sig->length); - return NT_STATUS_OK; -} - -NTSTATUS ntlmssp_sign_packet(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *sig_mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - if (!ntlmssp_state->session_key.length) { - DEBUG(3, ("NO session key, cannot check sign packet\n")); - return NT_STATUS_NO_USER_SESSION_KEY; - } - - if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) { - DEBUG(3, ("NTLMSSP Signing not negotiated - cannot sign packet!\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - return ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx, - data, length, - whole_pdu, pdu_length, - NTLMSSP_SEND, sig, True); -} - -/** - * Check the signature of an incoming packet - * - */ - -NTSTATUS ntlmssp_check_packet(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *sig_mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - const DATA_BLOB *sig) -{ - DATA_BLOB local_sig; - NTSTATUS nt_status; - - if (!ntlmssp_state->session_key.length) { - DEBUG(3, ("NO session key, cannot check packet signature\n")); - return NT_STATUS_NO_USER_SESSION_KEY; - } - - if (sig->length < 8) { - DEBUG(0, ("NTLMSSP packet check failed due to short signature (%lu bytes)!\n", - (unsigned long)sig->length)); - } - - nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx, - data, length, - whole_pdu, pdu_length, - NTLMSSP_RECEIVE, &local_sig, True); - - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status))); - return nt_status; - } - - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - if (local_sig.length != sig->length || - memcmp(local_sig.data, - sig->data, sig->length) != 0) { - DEBUG(5, ("BAD SIG NTLM2: wanted signature of\n")); - dump_data(5, local_sig.data, local_sig.length); - - DEBUG(5, ("BAD SIG: got signature of\n")); - dump_data(5, sig->data, sig->length); - - DEBUG(0, ("NTLMSSP NTLM2 packet check failed due to invalid signature!\n")); - return NT_STATUS_ACCESS_DENIED; - } - } else { - if (local_sig.length != sig->length || - memcmp(local_sig.data + 8, - sig->data + 8, sig->length - 8) != 0) { - DEBUG(5, ("BAD SIG NTLM1: wanted signature of\n")); - dump_data(5, local_sig.data, local_sig.length); - - DEBUG(5, ("BAD SIG: got signature of\n")); - dump_data(5, sig->data, sig->length); - - DEBUG(0, ("NTLMSSP NTLM1 packet check failed due to invalid signature!\n")); - return NT_STATUS_ACCESS_DENIED; - } - } - dump_data_pw("checked ntlmssp signature\n", sig->data, sig->length); - - return NT_STATUS_OK; -} - - -/** - * Seal data with the NTLMSSP algorithm - * - */ - -NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *sig_mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - NTSTATUS nt_status; - if (!ntlmssp_state->session_key.length) { - DEBUG(3, ("NO session key, cannot seal packet\n")); - return NT_STATUS_NO_USER_SESSION_KEY; - } - - if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) { - DEBUG(3, ("NTLMSSP Sealing not negotiated - cannot seal packet!\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - DEBUG(10,("ntlmssp_seal_data: seal\n")); - dump_data_pw("ntlmssp clear data\n", data, length); - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - /* The order of these two operations matters - we must first seal the packet, - then seal the sequence number - this is becouse the send_seal_hash is not - constant, but is is rather updated with each iteration */ - nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx, - data, length, - whole_pdu, pdu_length, - NTLMSSP_SEND, sig, False); - arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, data, length); - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { - arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, sig->data+4, 8); - } - } else { - uint32_t crc; - crc = crc32_calc_buffer(data, length); - if (!msrpc_gen(sig_mem_ctx, sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlm_seq_num)) { - return NT_STATUS_NO_MEMORY; - } - - /* The order of these two operations matters - we must - first seal the packet, then seal the sequence - number - this is becouse the ntlmssp_hash is not - constant, but is is rather updated with each - iteration */ - - arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, data, length); - arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4); - /* increment counter on send */ - ntlmssp_state->ntlm_seq_num++; - nt_status = NT_STATUS_OK; - } - dump_data_pw("ntlmssp signature\n", sig->data, sig->length); - dump_data_pw("ntlmssp sealed data\n", data, length); - - - return nt_status; -} - -/** - * Unseal data with the NTLMSSP algorithm - * - */ - -NTSTATUS ntlmssp_unseal_packet(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *sig_mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - DATA_BLOB local_sig; - NTSTATUS nt_status; - if (!ntlmssp_state->session_key.length) { - DEBUG(3, ("NO session key, cannot unseal packet\n")); - return NT_STATUS_NO_USER_SESSION_KEY; - } - - dump_data_pw("ntlmssp sealed data\n", data, length); - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - arcfour_crypt_sbox(ntlmssp_state->recv_seal_hash, data, length); - - nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx, - data, length, - whole_pdu, pdu_length, - NTLMSSP_RECEIVE, &local_sig, True); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - if (local_sig.length != sig->length || - memcmp(local_sig.data, - sig->data, sig->length) != 0) { - DEBUG(5, ("BAD SIG NTLM2: wanted signature of\n")); - dump_data(5, local_sig.data, local_sig.length); - - DEBUG(5, ("BAD SIG: got signature of\n")); - dump_data(5, sig->data, sig->length); - - DEBUG(0, ("NTLMSSP NTLM2 packet check failed due to invalid signature!\n")); - return NT_STATUS_ACCESS_DENIED; - } - - dump_data_pw("ntlmssp clear data\n", data, length); - return NT_STATUS_OK; - } else { - arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, data, length); - dump_data_pw("ntlmssp clear data\n", data, length); - return ntlmssp_check_packet(ntlmssp_state, sig_mem_ctx, data, length, whole_pdu, pdu_length, sig); - } -} - -/** - Initialise the state for NTLMSSP signing. -*/ -NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state) -{ - uint8_t p24[24]; - ZERO_STRUCT(p24); - - DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n")); - debug_ntlmssp_flags(ntlmssp_state->neg_flags); - - if (!ntlmssp_state->session_key.length) { - DEBUG(3, ("NO session key, cannot intialise signing\n")); - return NT_STATUS_NO_USER_SESSION_KEY; - } - - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) - { - DATA_BLOB weak_session_key = ntlmssp_state->session_key; - const char *send_sign_const; - const char *send_seal_const; - const char *recv_sign_const; - const char *recv_seal_const; - - switch (ntlmssp_state->role) { - case NTLMSSP_CLIENT: - send_sign_const = CLI_SIGN; - send_seal_const = CLI_SEAL; - recv_sign_const = SRV_SIGN; - recv_seal_const = SRV_SEAL; - break; - case NTLMSSP_SERVER: - send_sign_const = SRV_SIGN; - send_seal_const = SRV_SEAL; - recv_sign_const = CLI_SIGN; - recv_seal_const = CLI_SEAL; - break; - default: - return NT_STATUS_INTERNAL_ERROR; - } - - /** - Weaken NTLMSSP keys to cope with down-level clients, servers and export restrictions. - - We probably should have some parameters to control this, once we get NTLM2 working. - */ - - - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) { - - } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) { - weak_session_key.length = 6; - } else { /* forty bits */ - weak_session_key.length = 5; - } - dump_data_pw("NTLMSSP weakend master key:\n", - weak_session_key.data, - weak_session_key.length); - - /* SEND */ - calc_ntlmv2_key(ntlmssp_state, - &ntlmssp_state->send_sign_key, - ntlmssp_state->session_key, send_sign_const); - dump_data_pw("NTLMSSP send sign key:\n", - ntlmssp_state->send_sign_key.data, - ntlmssp_state->send_sign_key.length); - - calc_ntlmv2_key(ntlmssp_state, - &ntlmssp_state->send_seal_key, - weak_session_key, send_seal_const); - dump_data_pw("NTLMSSP send seal key:\n", - ntlmssp_state->send_seal_key.data, - ntlmssp_state->send_seal_key.length); - - arcfour_init(ntlmssp_state->send_seal_hash, - &ntlmssp_state->send_seal_key); - - dump_data_pw("NTLMSSP send sesl hash:\n", - ntlmssp_state->send_seal_hash, - sizeof(ntlmssp_state->send_seal_hash)); - - /* RECV */ - calc_ntlmv2_key(ntlmssp_state, - &ntlmssp_state->recv_sign_key, - ntlmssp_state->session_key, recv_sign_const); - dump_data_pw("NTLMSSP recv sign key:\n", - ntlmssp_state->recv_sign_key.data, - ntlmssp_state->recv_sign_key.length); - - calc_ntlmv2_key(ntlmssp_state, - &ntlmssp_state->recv_seal_key, - weak_session_key, recv_seal_const); - dump_data_pw("NTLMSSP recv seal key:\n", - ntlmssp_state->recv_seal_key.data, - ntlmssp_state->recv_seal_key.length); - arcfour_init(ntlmssp_state->recv_seal_hash, - &ntlmssp_state->recv_seal_key); - - dump_data_pw("NTLMSSP receive seal hash:\n", - ntlmssp_state->recv_seal_hash, - sizeof(ntlmssp_state->recv_seal_hash)); - } else { - DEBUG(5, ("NTLMSSP Sign/Seal - using NTLM1\n")); - - arcfour_init(ntlmssp_state->ntlmssp_hash, - &ntlmssp_state->session_key); - dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash, - sizeof(ntlmssp_state->ntlmssp_hash)); - } - - ntlmssp_state->ntlm_seq_num = 0; - ntlmssp_state->ntlm2_send_seq_num = 0; - ntlmssp_state->ntlm2_recv_seq_num = 0; - - return NT_STATUS_OK; -} diff --git a/source4/libcli/auth/schannel.c b/source4/libcli/auth/schannel.c deleted file mode 100644 index 3dbf10580b..0000000000 --- a/source4/libcli/auth/schannel.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - dcerpc schannel operations - - Copyright (C) Andrew Tridgell 2004 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "librpc/gen_ndr/ndr_schannel.h" -#include "auth/auth.h" -#include "libcli/auth/schannel.h" - -static size_t schannel_sig_size(struct gensec_security *gensec_security) -{ - return 32; -} - -static NTSTATUS schannel_session_key(struct gensec_security *gensec_security, - DATA_BLOB *session_key) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - -static NTSTATUS schannel_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - struct schannel_state *state = gensec_security->private_data; - NTSTATUS status; - struct schannel_bind bind_schannel; - struct schannel_bind_ack bind_schannel_ack; - struct creds_CredentialState *creds; - - const char *workstation; - const char *domain; - *out = data_blob(NULL, 0); - - switch (gensec_security->gensec_role) { - case GENSEC_CLIENT: - if (state->state != SCHANNEL_STATE_START) { - /* we could parse the bind ack, but we don't know what it is yet */ - return NT_STATUS_OK; - } - - state->creds = talloc_reference(state, cli_credentials_get_netlogon_creds(gensec_security->credentials)); - - bind_schannel.unknown1 = 0; -#if 0 - /* to support this we'd need to have access to the full domain name */ - bind_schannel.bind_type = 23; - bind_schannel.u.info23.domain = cli_credentials_get_domain(gensec_security->credentials); - bind_schannel.u.info23.account_name = cli_credentials_get_username(gensec_security->credentials); - bind_schannel.u.info23.dnsdomain = str_format_nbt_domain(out_mem_ctx, fulldomainname); - bind_schannel.u.info23.workstation = str_format_nbt_domain(out_mem_ctx, cli_credentials_get_workstation(gensec_security->credentials)); -#else - bind_schannel.bind_type = 3; - bind_schannel.u.info3.domain = cli_credentials_get_domain(gensec_security->credentials); - bind_schannel.u.info3.workstation = cli_credentials_get_workstation(gensec_security->credentials); -#endif - - status = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel, - (ndr_push_flags_fn_t)ndr_push_schannel_bind); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("Could not create schannel bind: %s\n", - nt_errstr(status))); - return status; - } - - state->state = SCHANNEL_STATE_UPDATE_1; - - return NT_STATUS_MORE_PROCESSING_REQUIRED; - case GENSEC_SERVER: - - if (state->state != SCHANNEL_STATE_START) { - /* no third leg on this protocol */ - return NT_STATUS_INVALID_PARAMETER; - } - - /* parse the schannel startup blob */ - status = ndr_pull_struct_blob(&in, out_mem_ctx, &bind_schannel, - (ndr_pull_flags_fn_t)ndr_pull_schannel_bind); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (bind_schannel.bind_type == 23) { - workstation = bind_schannel.u.info23.workstation; - domain = bind_schannel.u.info23.domain; - } else { - workstation = bind_schannel.u.info3.workstation; - domain = bind_schannel.u.info3.domain; - } - - /* pull the session key for this client */ - status = schannel_fetch_session_key(out_mem_ctx, workstation, - domain, &creds); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("Could not find session key for attempted schannel connection from %s: %s\n", - workstation, nt_errstr(status))); - return status; - } - - state->creds = talloc_reference(state, creds); - - bind_schannel_ack.unknown1 = 1; - bind_schannel_ack.unknown2 = 0; - bind_schannel_ack.unknown3 = 0x6c0000; - - status = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel_ack, - (ndr_push_flags_fn_t)ndr_push_schannel_bind_ack); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("Could not return schannel bind ack for client %s: %s\n", - workstation, nt_errstr(status))); - return status; - } - - state->state = SCHANNEL_STATE_UPDATE_1; - - return NT_STATUS_OK; - } - return NT_STATUS_INVALID_PARAMETER; -} - -/** - * Return the struct creds_CredentialState. - * - * Make sure not to call this unless gensec is using schannel... - */ - -NTSTATUS dcerpc_schannel_creds(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - struct creds_CredentialState **creds) -{ - struct schannel_state *state = gensec_security->private_data; - - *creds = talloc_reference(mem_ctx, state->creds); - if (!*creds) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - - -/** - * Return the credentials of a logged on user, including session keys - * etc. - * - * Only valid after a successful authentication - * - * May only be called once per authentication. - * - */ - -static NTSTATUS schannel_session_info(struct gensec_security *gensec_security, - struct auth_session_info **session_info) -{ - (*session_info) = talloc(gensec_security, struct auth_session_info); - NT_STATUS_HAVE_NO_MEMORY(*session_info); - - ZERO_STRUCTP(*session_info); - - return NT_STATUS_OK; -} - -static NTSTATUS schannel_start(struct gensec_security *gensec_security) -{ - struct schannel_state *state; - - state = talloc(gensec_security, struct schannel_state); - if (!state) { - return NT_STATUS_NO_MEMORY; - } - - state->state = SCHANNEL_STATE_START; - state->seq_num = 0; - gensec_security->private_data = state; - - return NT_STATUS_OK; -} - -static NTSTATUS schannel_server_start(struct gensec_security *gensec_security) -{ - NTSTATUS status; - struct schannel_state *state; - - status = schannel_start(gensec_security); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - state = gensec_security->private_data; - state->initiator = False; - - return NT_STATUS_OK; -} - -static NTSTATUS schannel_client_start(struct gensec_security *gensec_security) -{ - NTSTATUS status; - struct schannel_state *state; - - status = schannel_start(gensec_security); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - state = gensec_security->private_data; - state->initiator = True; - - return NT_STATUS_OK; -} - - -static BOOL schannel_have_feature(struct gensec_security *gensec_security, - uint32_t feature) -{ - if (feature & (GENSEC_FEATURE_SIGN | - GENSEC_FEATURE_SEAL)) { - return True; - } - return False; -} - - -static const struct gensec_security_ops gensec_schannel_security_ops = { - .name = "schannel", - .auth_type = DCERPC_AUTH_TYPE_SCHANNEL, - .client_start = schannel_client_start, - .server_start = schannel_server_start, - .update = schannel_update, - .seal_packet = schannel_seal_packet, - .sign_packet = schannel_sign_packet, - .check_packet = schannel_check_packet, - .unseal_packet = schannel_unseal_packet, - .session_key = schannel_session_key, - .session_info = schannel_session_info, - .sig_size = schannel_sig_size, - .have_feature = schannel_have_feature, - .enabled = True -}; - -NTSTATUS gensec_schannel_init(void) -{ - NTSTATUS ret; - ret = gensec_register(&gensec_schannel_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_schannel_security_ops.name)); - return ret; - } - - return ret; -} diff --git a/source4/libcli/auth/schannel.h b/source4/libcli/auth/schannel.h deleted file mode 100644 index c109387c7c..0000000000 --- a/source4/libcli/auth/schannel.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - dcerpc schannel operations - - Copyright (C) Andrew Tridgell 2004 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -enum schannel_position { - SCHANNEL_STATE_START = 0, - SCHANNEL_STATE_UPDATE_1 -}; - -struct schannel_state { - enum schannel_position state; - uint32_t seq_num; - BOOL initiator; - struct creds_CredentialState *creds; -}; - diff --git a/source4/libcli/auth/schannel_sign.c b/source4/libcli/auth/schannel_sign.c deleted file mode 100644 index 3b493bd0d3..0000000000 --- a/source4/libcli/auth/schannel_sign.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - schannel library code - - Copyright (C) Andrew Tridgell 2004 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "lib/crypto/crypto.h" -#include "libcli/auth/schannel.h" -#include "libcli/auth/gensec.h" -#include "libcli/auth/credentials.h" - -#define NETSEC_SIGN_SIGNATURE { 0x77, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } -#define NETSEC_SEAL_SIGNATURE { 0x77, 0x00, 0x7a, 0x00, 0xff, 0xff, 0x00, 0x00 } - -/******************************************************************* - Encode or Decode the sequence number (which is symmetric) - ********************************************************************/ -static void netsec_deal_with_seq_num(struct schannel_state *state, - const uint8_t packet_digest[8], - uint8_t seq_num[8]) -{ - static const uint8_t zeros[4]; - uint8_t sequence_key[16]; - uint8_t digest1[16]; - - hmac_md5(state->creds->session_key, zeros, sizeof(zeros), digest1); - hmac_md5(digest1, packet_digest, 8, sequence_key); - arcfour_crypt(seq_num, sequence_key, 8); - - state->seq_num++; -} - - -/******************************************************************* - Calculate the key with which to encode the data payload - ********************************************************************/ -static void netsec_get_sealing_key(const uint8_t session_key[16], - const uint8_t seq_num[8], - uint8_t sealing_key[16]) -{ - static const uint8_t zeros[4]; - uint8_t digest2[16]; - uint8_t sess_kf0[16]; - int i; - - for (i = 0; i < 16; i++) { - sess_kf0[i] = session_key[i] ^ 0xf0; - } - - hmac_md5(sess_kf0, zeros, 4, digest2); - hmac_md5(digest2, seq_num, 8, sealing_key); -} - - -/******************************************************************* - Create a digest over the entire packet (including the data), and - MD5 it with the session key. - ********************************************************************/ -static void schannel_digest(const uint8_t sess_key[16], - const uint8_t netsec_sig[8], - const uint8_t *confounder, - const uint8_t *data, size_t data_len, - uint8_t digest_final[16]) -{ - uint8_t packet_digest[16]; - static const uint8_t zeros[4]; - struct MD5Context ctx; - - MD5Init(&ctx); - MD5Update(&ctx, zeros, 4); - MD5Update(&ctx, netsec_sig, 8); - if (confounder) { - MD5Update(&ctx, confounder, 8); - } - MD5Update(&ctx, data, data_len); - MD5Final(packet_digest, &ctx); - - hmac_md5(sess_key, packet_digest, sizeof(packet_digest), digest_final); -} - - -/* - unseal a packet -*/ -NTSTATUS schannel_unseal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct schannel_state *state = gensec_security->private_data; - - uint8_t digest_final[16]; - uint8_t confounder[8]; - uint8_t seq_num[8]; - uint8_t sealing_key[16]; - static const uint8_t netsec_sig[8] = NETSEC_SEAL_SIGNATURE; - - if (sig->length != 32) { - return NT_STATUS_ACCESS_DENIED; - } - - memcpy(confounder, sig->data+24, 8); - - RSIVAL(seq_num, 0, state->seq_num); - SIVAL(seq_num, 4, state->initiator?0:0x80); - - netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key); - arcfour_crypt(confounder, sealing_key, 8); - arcfour_crypt(data, sealing_key, length); - - schannel_digest(state->creds->session_key, - netsec_sig, confounder, - data, length, digest_final); - - if (memcmp(digest_final, sig->data+16, 8) != 0) { - dump_data_pw("calc digest:", digest_final, 8); - dump_data_pw("wire digest:", sig->data+16, 8); - return NT_STATUS_ACCESS_DENIED; - } - - netsec_deal_with_seq_num(state, digest_final, seq_num); - - if (memcmp(seq_num, sig->data+8, 8) != 0) { - dump_data_pw("calc seq num:", seq_num, 8); - dump_data_pw("wire seq num:", sig->data+8, 8); - return NT_STATUS_ACCESS_DENIED; - } - - return NT_STATUS_OK; -} - -/* - check the signature on a packet -*/ -NTSTATUS schannel_check_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - const DATA_BLOB *sig) -{ - struct schannel_state *state = gensec_security->private_data; - - uint8_t digest_final[16]; - uint8_t seq_num[8]; - static const uint8_t netsec_sig[8] = NETSEC_SIGN_SIGNATURE; - - /* w2k sends just 24 bytes and skip the confounder */ - if (sig->length != 32 && sig->length != 24) { - return NT_STATUS_ACCESS_DENIED; - } - - RSIVAL(seq_num, 0, state->seq_num); - SIVAL(seq_num, 4, state->initiator?0:0x80); - - dump_data_pw("seq_num:\n", seq_num, 8); - dump_data_pw("sess_key:\n", state->creds->session_key, 16); - - schannel_digest(state->creds->session_key, - netsec_sig, NULL, - data, length, digest_final); - - netsec_deal_with_seq_num(state, digest_final, seq_num); - - if (memcmp(seq_num, sig->data+8, 8) != 0) { - dump_data_pw("calc seq num:", seq_num, 8); - dump_data_pw("wire seq num:", sig->data+8, 8); - return NT_STATUS_ACCESS_DENIED; - } - - if (memcmp(digest_final, sig->data+16, 8) != 0) { - dump_data_pw("calc digest:", digest_final, 8); - dump_data_pw("wire digest:", sig->data+16, 8); - return NT_STATUS_ACCESS_DENIED; - } - - return NT_STATUS_OK; -} - - -/* - seal a packet -*/ -NTSTATUS schannel_seal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct schannel_state *state = gensec_security->private_data; - - uint8_t digest_final[16]; - uint8_t confounder[8]; - uint8_t seq_num[8]; - uint8_t sealing_key[16]; - static const uint8_t netsec_sig[8] = NETSEC_SEAL_SIGNATURE; - - generate_random_buffer(confounder, 8); - - RSIVAL(seq_num, 0, state->seq_num); - SIVAL(seq_num, 4, state->initiator?0x80:0); - - schannel_digest(state->creds->session_key, - netsec_sig, confounder, - data, length, digest_final); - - netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key); - arcfour_crypt(confounder, sealing_key, 8); - arcfour_crypt(data, sealing_key, length); - - netsec_deal_with_seq_num(state, digest_final, seq_num); - - (*sig) = data_blob_talloc(mem_ctx, NULL, 32); - - memcpy(sig->data, netsec_sig, 8); - memcpy(sig->data+8, seq_num, 8); - memcpy(sig->data+16, digest_final, 8); - memcpy(sig->data+24, confounder, 8); - - dump_data_pw("signature:", sig->data+ 0, 8); - dump_data_pw("seq_num :", sig->data+ 8, 8); - dump_data_pw("digest :", sig->data+16, 8); - dump_data_pw("confound :", sig->data+24, 8); - - return NT_STATUS_OK; -} - - -/* - sign a packet -*/ -NTSTATUS schannel_sign_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct schannel_state *state = gensec_security->private_data; - - uint8_t digest_final[16]; - uint8_t seq_num[8]; - static const uint8_t netsec_sig[8] = NETSEC_SIGN_SIGNATURE; - - RSIVAL(seq_num, 0, state->seq_num); - SIVAL(seq_num, 4, state->initiator?0x80:0); - - schannel_digest(state->creds->session_key, - netsec_sig, NULL, - data, length, digest_final); - - netsec_deal_with_seq_num(state, digest_final, seq_num); - - (*sig) = data_blob_talloc(mem_ctx, NULL, 32); - - memcpy(sig->data, netsec_sig, 8); - memcpy(sig->data+8, seq_num, 8); - memcpy(sig->data+16, digest_final, 8); - memset(sig->data+24, 0, 8); - - dump_data_pw("signature:", sig->data+ 0, 8); - dump_data_pw("seq_num :", sig->data+ 8, 8); - dump_data_pw("digest :", sig->data+16, 8); - dump_data_pw("confound :", sig->data+24, 8); - - return NT_STATUS_OK; -} diff --git a/source4/libcli/auth/schannel_state.c b/source4/libcli/auth/schannel_state.c deleted file mode 100644 index b2d632a1f0..0000000000 --- a/source4/libcli/auth/schannel_state.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - module to store/fetch session keys for the schannel server - - Copyright (C) Andrew Tridgell 2004 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "system/time.h" -#include "auth/auth.h" -#include "lib/ldb/include/ldb.h" -#include "db_wrap.h" - -/* a reasonable amount of time to keep credentials live */ -#define SCHANNEL_CREDENTIALS_EXPIRY 600 - -/* - connect to the schannel ldb -*/ -static struct ldb_context *schannel_db_connect(TALLOC_CTX *mem_ctx) -{ - char *path; - struct ldb_context *ldb; - - path = smbd_tmp_path(mem_ctx, "schannel.ldb"); - if (!path) { - return NULL; - } - - ldb = ldb_wrap_connect(mem_ctx, path, 0, NULL); - talloc_free(path); - if (!ldb) { - return NULL; - } - - return ldb; -} - -/* - remember an established session key for a netr server authentication - use a simple ldb structure -*/ -NTSTATUS schannel_store_session_key(TALLOC_CTX *mem_ctx, - struct creds_CredentialState *creds) -{ - struct ldb_context *ldb; - struct ldb_message *msg; - struct ldb_val val, seed; - char *s; - char *f; - char *sct; - char *rid; - time_t expiry = time(NULL) + SCHANNEL_CREDENTIALS_EXPIRY; - int ret; - - ldb = schannel_db_connect(mem_ctx); - if (ldb == NULL) { - return NT_STATUS_NO_MEMORY; - } - - s = talloc_asprintf(mem_ctx, "%u", (unsigned int)expiry); - - if (s == NULL) { - talloc_free(ldb); - return NT_STATUS_NO_MEMORY; - } - - f = talloc_asprintf(mem_ctx, "%u", (unsigned int)creds->negotiate_flags); - - if (f == NULL) { - talloc_free(ldb); - return NT_STATUS_NO_MEMORY; - } - - sct = talloc_asprintf(mem_ctx, "%u", (unsigned int)creds->secure_channel_type); - - if (sct == NULL) { - talloc_free(ldb); - return NT_STATUS_NO_MEMORY; - } - - rid = talloc_asprintf(mem_ctx, "%u", (unsigned int)creds->rid); - - if (rid == NULL) { - talloc_free(ldb); - return NT_STATUS_NO_MEMORY; - } - - msg = ldb_msg_new(mem_ctx); - if (msg == NULL) { - talloc_free(ldb); - return NT_STATUS_NO_MEMORY; - } - - msg->dn = talloc_asprintf(msg, "computerName=%s", creds->computer_name); - if (msg->dn == NULL) { - talloc_free(ldb); - talloc_free(msg); - return NT_STATUS_NO_MEMORY; - } - - val.data = creds->session_key; - val.length = sizeof(creds->session_key); - - seed.data = creds->seed.data; - seed.length = sizeof(creds->seed.data); - - ldb_msg_add_value(ldb, msg, "sessionKey", &val); - ldb_msg_add_value(ldb, msg, "seed", &seed); - ldb_msg_add_string(ldb, msg, "expiry", s); - ldb_msg_add_string(ldb, msg, "negotiateFlags", f); - ldb_msg_add_string(ldb, msg, "secureChannelType", sct); - ldb_msg_add_string(ldb, msg, "accountName", creds->account_name); - ldb_msg_add_string(ldb, msg, "computerName", creds->computer_name); - ldb_msg_add_string(ldb, msg, "flatname", creds->domain); - ldb_msg_add_string(ldb, msg, "rid", rid); - - ldb_delete(ldb, msg->dn); - - ret = ldb_add(ldb, msg); - - talloc_free(s); - - if (ret != 0) { - DEBUG(0,("Unable to add %s to session key db - %s\n", - msg->dn, ldb_errstring(ldb))); - talloc_free(ldb); - talloc_free(msg); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - talloc_free(msg); - talloc_free(ldb); - - return NT_STATUS_OK; -} - - -/* - read back a credentials back for a computer -*/ -NTSTATUS schannel_fetch_session_key(TALLOC_CTX *mem_ctx, - const char *computer_name, - const char *domain, - struct creds_CredentialState **creds) -{ - struct ldb_context *ldb; - time_t expiry; - struct ldb_message **res; - int ret; - const struct ldb_val *val; - char *expr=NULL; - - *creds = talloc_zero(mem_ctx, struct creds_CredentialState); - if (!*creds) { - return NT_STATUS_NO_MEMORY; - } - - ldb = schannel_db_connect(mem_ctx); - if (ldb == NULL) { - return NT_STATUS_NO_MEMORY; - } - - expr = talloc_asprintf(mem_ctx, "(&(computerName=%s)(flatname=%s))", computer_name, domain); - if (expr == NULL) { - talloc_free(ldb); - return NT_STATUS_NO_MEMORY; - } - - ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, expr, NULL, &res); - if (ret != 1) { - talloc_free(ldb); - return NT_STATUS_INVALID_HANDLE; - } - - expiry = ldb_msg_find_uint(res[0], "expiry", 0); - if (expiry < time(NULL)) { - DEBUG(1,("schannel: attempt to use expired session key for %s\n", computer_name)); - talloc_free(ldb); - return NT_STATUS_INVALID_HANDLE; - } - - val = ldb_msg_find_ldb_val(res[0], "sessionKey"); - if (val == NULL || val->length != 16) { - talloc_free(ldb); - return NT_STATUS_INVALID_HANDLE; - } - - memcpy((*creds)->session_key, val->data, 16); - - val = ldb_msg_find_ldb_val(res[0], "seed"); - if (val == NULL || val->length != 8) { - talloc_free(ldb); - return NT_STATUS_INVALID_HANDLE; - } - - memcpy((*creds)->seed.data, val->data, 8); - - (*creds)->negotiate_flags = ldb_msg_find_int(res[0], "negotiateFlags", 0); - - (*creds)->secure_channel_type = ldb_msg_find_int(res[0], "secureChannelType", 0); - - (*creds)->account_name = talloc_reference(*creds, ldb_msg_find_string(res[0], "accountName", NULL)); - - (*creds)->computer_name = talloc_reference(*creds, ldb_msg_find_string(res[0], "computerName", NULL)); - - (*creds)->domain = talloc_reference(*creds, ldb_msg_find_string(res[0], "flatname", NULL)); - - (*creds)->rid = ldb_msg_find_uint(res[0], "rid", 0); - - talloc_free(ldb); - - return NT_STATUS_OK; -} diff --git a/source4/libcli/auth/spnego.c b/source4/libcli/auth/spnego.c deleted file mode 100644 index f5a091cd78..0000000000 --- a/source4/libcli/auth/spnego.c +++ /dev/null @@ -1,884 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - RFC2478 Compliant SPNEGO implementation - - Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "auth/auth.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_AUTH - -enum spnego_state_position { - SPNEGO_SERVER_START, - SPNEGO_CLIENT_START, - SPNEGO_SERVER_TARG, - SPNEGO_CLIENT_TARG, - SPNEGO_FALLBACK, - SPNEGO_DONE -}; - -struct spnego_state { - uint_t ref_count; - enum spnego_message_type expected_packet; - enum spnego_state_position state_position; - struct gensec_security *sub_sec_security; - BOOL no_response_expected; -}; - - -static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security) -{ - struct spnego_state *spnego_state; - - spnego_state = talloc(gensec_security, struct spnego_state); - if (!spnego_state) { - return NT_STATUS_NO_MEMORY; - } - - spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT; - spnego_state->state_position = SPNEGO_CLIENT_START; - spnego_state->sub_sec_security = NULL; - spnego_state->no_response_expected = False; - - gensec_security->private_data = spnego_state; - return NT_STATUS_OK; -} - -static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_security) -{ - struct spnego_state *spnego_state; - - spnego_state = talloc(gensec_security, struct spnego_state); - if (!spnego_state) { - return NT_STATUS_NO_MEMORY; - } - - spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT; - spnego_state->state_position = SPNEGO_SERVER_START; - spnego_state->sub_sec_security = NULL; - spnego_state->no_response_expected = False; - - gensec_security->private_data = spnego_state; - return NT_STATUS_OK; -} - -/* - wrappers for the spnego_*() functions -*/ -static NTSTATUS gensec_spnego_unseal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_unseal_packet(spnego_state->sub_sec_security, - mem_ctx, - data, length, - whole_pdu, pdu_length, - sig); -} - -static NTSTATUS gensec_spnego_check_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - const DATA_BLOB *sig) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_check_packet(spnego_state->sub_sec_security, - mem_ctx, - data, length, - whole_pdu, pdu_length, - sig); -} - -static NTSTATUS gensec_spnego_seal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_seal_packet(spnego_state->sub_sec_security, - mem_ctx, - data, length, - whole_pdu, pdu_length, - sig); -} - -static NTSTATUS gensec_spnego_sign_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_sign_packet(spnego_state->sub_sec_security, - mem_ctx, - data, length, - whole_pdu, pdu_length, - sig); -} - -static NTSTATUS gensec_spnego_wrap(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - DEBUG(1, ("gensec_spnego_wrap: wrong state for wrap\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_wrap(spnego_state->sub_sec_security, - mem_ctx, in, out); -} - -static NTSTATUS gensec_spnego_unwrap(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_unwrap(spnego_state->sub_sec_security, - mem_ctx, in, out); -} - -static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - return 0; - } - - return gensec_sig_size(spnego_state->sub_sec_security); -} - -static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security, - DATA_BLOB *session_key) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - if (!spnego_state->sub_sec_security) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_session_key(spnego_state->sub_sec_security, - session_key); -} - -static NTSTATUS gensec_spnego_session_info(struct gensec_security *gensec_security, - struct auth_session_info **session_info) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - if (!spnego_state->sub_sec_security) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_session_info(spnego_state->sub_sec_security, - session_info); -} - -/** Fallback to another GENSEC mechanism, based on magic strings - * - * This is the 'fallback' case, where we don't get SPNEGO, and have to - * try all the other options (and hope they all have a magic string - * they check) -*/ - -static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec_security, - struct spnego_state *spnego_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - int i; - int num_ops; - const struct gensec_security_ops **all_ops = gensec_security_all(&num_ops); - for (i=0; i < num_ops; i++) { - NTSTATUS nt_status; - if (!all_ops[i]->oid) { - continue; - } - if (strcasecmp(GENSEC_OID_SPNEGO,all_ops[i]->oid) == 0) { - continue; - } - - nt_status = gensec_subcontext_start(spnego_state, - gensec_security, - &spnego_state->sub_sec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - /* select the sub context */ - nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, - all_ops[i]->oid); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - continue; - } - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, in, out); - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - spnego_state->state_position = SPNEGO_FALLBACK; - return nt_status; - } - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - } - DEBUG(1, ("Failed to parse SPNEGO request\n")); - return NT_STATUS_INVALID_PARAMETER; - -} - -/* - Parse the netTokenInit from the client, to the server. - - -*/ - -static NTSTATUS gensec_spnego_server_parse_negTokenInit(struct gensec_security *gensec_security, - struct spnego_state *spnego_state, - TALLOC_CTX *out_mem_ctx, - const char **mechType, - const DATA_BLOB unwrapped_in, DATA_BLOB *unwrapped_out) -{ - NTSTATUS nt_status; - - if (!mechType || !mechType[0]) { - DEBUG(1, ("SPNEGO: Could not find a suitable mechtype in NEG_TOKEN_INIT\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - nt_status = gensec_subcontext_start(spnego_state, - gensec_security, - &spnego_state->sub_sec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - /* select the sub context */ - nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, - mechType[0]); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - return nt_status; - } - - if (!unwrapped_in.length) { - return NT_STATUS_INVALID_PARAMETER; - } - - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, - unwrapped_in, - unwrapped_out); - - if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed: %s\n", - spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - } - return nt_status; -} - -static NTSTATUS gensec_spnego_client_parse_negTokenInit(struct gensec_security *gensec_security, - struct spnego_state *spnego_state, - TALLOC_CTX *out_mem_ctx, - const char **mechType, - const DATA_BLOB unwrapped_in, DATA_BLOB *unwrapped_out) -{ - int i; - NTSTATUS nt_status; - DATA_BLOB null_data_blob = data_blob(NULL,0); - - for (i=0; mechType && mechType[i]; i++) { - nt_status = gensec_subcontext_start(spnego_state, - gensec_security, - &spnego_state->sub_sec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - break; - } - /* select the sub context */ - nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, - mechType[i]); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - continue; - } - - if (i == 0) { - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, - unwrapped_in, - unwrapped_out); - } else { - /* only get the helping start blob for the first OID */ - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, - null_data_blob, - unwrapped_out); - } - if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed: %s\n", - spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - } - return nt_status; - } - if (!mechType || !mechType[i]) { - DEBUG(1, ("SPNEGO: Could not find a suitable mechtype in NEG_TOKEN_INIT\n")); - } - return NT_STATUS_INVALID_PARAMETER; -} - -/** create a client negTokenInit - * - * This is the case, where the client is the first one who sends data -*/ - -static NTSTATUS gensec_spnego_client_negTokenInit(struct gensec_security *gensec_security, - struct spnego_state *spnego_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - DATA_BLOB null_data_blob = data_blob(NULL,0); - NTSTATUS nt_status; - const char **mechTypes = NULL; - DATA_BLOB unwrapped_out = data_blob(NULL,0); - - mechTypes = gensec_security_oids(out_mem_ctx, GENSEC_OID_SPNEGO); - - if (!mechTypes) { - DEBUG(1, ("no GENSEC OID backends available\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - nt_status = gensec_subcontext_start(spnego_state, - gensec_security, - &spnego_state->sub_sec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - /* select our preferred mech */ - nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, - mechTypes[0]); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - return nt_status; - } - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, in, &unwrapped_out); - if (NT_STATUS_IS_OK(nt_status) || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - struct spnego_data spnego_out; - spnego_out.type = SPNEGO_NEG_TOKEN_INIT; - spnego_out.negTokenInit.mechTypes = mechTypes; - spnego_out.negTokenInit.reqFlags = 0; - spnego_out.negTokenInit.mechListMIC = null_data_blob; - spnego_out.negTokenInit.mechToken = unwrapped_out; - - if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { - DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - /* set next state */ - spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; - spnego_state->state_position = SPNEGO_CLIENT_TARG; - - if (NT_STATUS_IS_OK(nt_status)) { - spnego_state->no_response_expected = True; - } - - return NT_STATUS_MORE_PROCESSING_REQUIRED; - } - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - - DEBUG(1, ("Failed to setup SPNEGO negTokenInit request: %s\n", nt_errstr(nt_status))); - return NT_STATUS_INVALID_PARAMETER; -} - - -/** create a client negTokenTarg - * - * This is the case, where the client is the first one who sends data -*/ - -static NTSTATUS gensec_spnego_server_negTokenTarg(struct gensec_security *gensec_security, - struct spnego_state *spnego_state, - TALLOC_CTX *out_mem_ctx, - NTSTATUS nt_status, - const DATA_BLOB unwrapped_out, DATA_BLOB *out) -{ - struct spnego_data spnego_out; - DATA_BLOB null_data_blob = data_blob(NULL, 0); - - /* compose reply */ - spnego_out.type = SPNEGO_NEG_TOKEN_TARG; - spnego_out.negTokenTarg.responseToken = unwrapped_out; - spnego_out.negTokenTarg.mechListMIC = null_data_blob; - spnego_out.negTokenTarg.supportedMech = NULL; - - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - spnego_out.negTokenTarg.supportedMech - = spnego_state->sub_sec_security->ops->oid; - spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE; - spnego_state->state_position = SPNEGO_SERVER_TARG; - } else if (NT_STATUS_IS_OK(nt_status)) { - if (unwrapped_out.data) { - spnego_out.negTokenTarg.supportedMech - = spnego_state->sub_sec_security->ops->oid; - } - spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED; - spnego_state->state_position = SPNEGO_DONE; - } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) { - if (spnego_state->sub_sec_security) { - /* we have a mech, but we just didn't get the input parameter */ - spnego_out.negTokenTarg.supportedMech - = spnego_state->sub_sec_security->ops->oid; - } else { - const char **mechTypes = gensec_security_oids(out_mem_ctx, GENSEC_OID_SPNEGO); - if (!mechTypes) { - DEBUG(1, ("no GENSEC OID backends available\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - nt_status = gensec_subcontext_start(spnego_state, - gensec_security, - &spnego_state->sub_sec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - /* select our preferred mech */ - nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, - mechTypes[0]); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - return nt_status; - } - - /* we should be sending the whole list here */ - spnego_out.negTokenTarg.supportedMech = mechTypes[0]; - } - - spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE; - spnego_state->state_position = SPNEGO_SERVER_TARG; - nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; - } else { - spnego_out.negTokenTarg.negResult = SPNEGO_REJECT; - DEBUG(2, ("SPNEGO login failed: %s\n", nt_errstr(nt_status))); - spnego_state->state_position = SPNEGO_DONE; - } - - if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { - DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; - - return nt_status; -} - - -static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - DATA_BLOB null_data_blob = data_blob(NULL, 0); - DATA_BLOB unwrapped_out = data_blob(NULL, 0); - struct spnego_data spnego_out; - struct spnego_data spnego; - - ssize_t len; - - *out = data_blob(NULL, 0); - - if (!out_mem_ctx) { - out_mem_ctx = spnego_state; - } - - /* and switch into the state machine */ - - switch (spnego_state->state_position) { - case SPNEGO_FALLBACK: - return gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, in, out); - case SPNEGO_SERVER_START: - { - if (in.length) { - NTSTATUS nt_status; - - len = spnego_read_data(in, &spnego); - if (len == -1) { - return gensec_spnego_server_try_fallback(gensec_security, spnego_state, out_mem_ctx, in, out); - } - /* client sent NegTargetInit, we send NegTokenTarg */ - - /* OK, so it's real SPNEGO, check the packet's the one we expect */ - if (spnego.type != spnego_state->expected_packet) { - DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, - spnego_state->expected_packet)); - dump_data(1, in.data, in.length); - spnego_free_data(&spnego); - return NT_STATUS_INVALID_PARAMETER; - } - - nt_status = gensec_spnego_server_parse_negTokenInit(gensec_security, - spnego_state, - out_mem_ctx, - spnego.negTokenInit.mechTypes, - spnego.negTokenInit.mechToken, - &unwrapped_out); - - nt_status = gensec_spnego_server_negTokenTarg(gensec_security, - spnego_state, - out_mem_ctx, - nt_status, - unwrapped_out, - out); - - spnego_free_data(&spnego); - - return nt_status; - } else { - const char **mechlist = gensec_security_oids(out_mem_ctx, GENSEC_OID_SPNEGO); - - spnego_out.type = SPNEGO_NEG_TOKEN_INIT; - spnego_out.negTokenInit.mechTypes = mechlist; - spnego_out.negTokenInit.reqFlags = 0; - spnego_out.negTokenInit.mechListMIC - = data_blob_string_const(talloc_asprintf(out_mem_ctx, "%s$@%s", lp_netbios_name(), lp_realm())); - spnego_out.negTokenInit.mechToken = unwrapped_out; - - if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { - DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - /* set next state */ - spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; - spnego_state->state_position = SPNEGO_SERVER_TARG; - - return NT_STATUS_MORE_PROCESSING_REQUIRED; - } - } - - case SPNEGO_CLIENT_START: - { - /* The server offers a list of mechanisms */ - - const char *my_mechs[] = {NULL, NULL}; - NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; - - if (!in.length) { - /* client to produce negTokenInit */ - return gensec_spnego_client_negTokenInit(gensec_security, spnego_state, - out_mem_ctx, in, out); - } - - len = spnego_read_data(in, &spnego); - - if (len == -1) { - DEBUG(1, ("Invalid SPNEGO request:\n")); - dump_data(1, in.data, in.length); - return NT_STATUS_INVALID_PARAMETER; - } - - /* OK, so it's real SPNEGO, check the packet's the one we expect */ - if (spnego.type != spnego_state->expected_packet) { - DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, - spnego_state->expected_packet)); - dump_data(1, in.data, in.length); - spnego_free_data(&spnego); - return NT_STATUS_INVALID_PARAMETER; - } - - if (spnego.negTokenInit.targetPrincipal) { - DEBUG(5, ("Server claims it's principal name is %s (ignored)\n", spnego.negTokenInit.targetPrincipal)); - } - - nt_status = gensec_spnego_client_parse_negTokenInit(gensec_security, - spnego_state, - out_mem_ctx, - spnego.negTokenInit.mechTypes, - spnego.negTokenInit.mechToken, - &unwrapped_out); - - if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { - spnego_free_data(&spnego); - return nt_status; - } - - /* compose reply */ - my_mechs[0] = spnego_state->sub_sec_security->ops->oid; - - spnego_out.type = SPNEGO_NEG_TOKEN_INIT; - spnego_out.negTokenInit.mechTypes = my_mechs; - spnego_out.negTokenInit.reqFlags = 0; - spnego_out.negTokenInit.mechListMIC = null_data_blob; - spnego_out.negTokenInit.mechToken = unwrapped_out; - - if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { - DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - /* set next state */ - spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; - spnego_state->state_position = SPNEGO_CLIENT_TARG; - - if (NT_STATUS_IS_OK(nt_status)) { - spnego_state->no_response_expected = True; - } - - return NT_STATUS_MORE_PROCESSING_REQUIRED; - } - case SPNEGO_SERVER_TARG: - { - NTSTATUS nt_status; - if (!in.length) { - return NT_STATUS_INVALID_PARAMETER; - } - - len = spnego_read_data(in, &spnego); - - if (len == -1) { - DEBUG(1, ("Invalid SPNEGO request:\n")); - dump_data(1, in.data, in.length); - return NT_STATUS_INVALID_PARAMETER; - } - - /* OK, so it's real SPNEGO, check the packet's the one we expect */ - if (spnego.type != spnego_state->expected_packet) { - DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, - spnego_state->expected_packet)); - dump_data(1, in.data, in.length); - spnego_free_data(&spnego); - return NT_STATUS_INVALID_PARAMETER; - } - - if (!spnego_state->sub_sec_security) { - DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, - spnego.negTokenTarg.responseToken, - &unwrapped_out); - - nt_status = gensec_spnego_server_negTokenTarg(gensec_security, - spnego_state, - out_mem_ctx, - nt_status, - unwrapped_out, - out); - - spnego_free_data(&spnego); - - return nt_status; - } - case SPNEGO_CLIENT_TARG: - { - NTSTATUS nt_status; - if (!in.length) { - return NT_STATUS_INVALID_PARAMETER; - } - - len = spnego_read_data(in, &spnego); - - if (len == -1) { - DEBUG(1, ("Invalid SPNEGO request:\n")); - dump_data(1, in.data, in.length); - return NT_STATUS_INVALID_PARAMETER; - } - - /* OK, so it's real SPNEGO, check the packet's the one we expect */ - if (spnego.type != spnego_state->expected_packet) { - DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, - spnego_state->expected_packet)); - dump_data(1, in.data, in.length); - spnego_free_data(&spnego); - return NT_STATUS_INVALID_PARAMETER; - } - - if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) { - return NT_STATUS_ACCESS_DENIED; - } - - if (spnego_state->no_response_expected) { - if (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) { - DEBUG(3,("GENSEC SPNEGO: client GENSEC accepted, but server rejected (bad password?)\n")); - nt_status = NT_STATUS_INVALID_PARAMETER; - } else if (spnego.negTokenTarg.responseToken.length) { - DEBUG(2,("GENSEC SPNEGO: client GENSEC accepted, but server continued negotiation!\n")); - nt_status = NT_STATUS_INVALID_PARAMETER; - } else { - nt_status = NT_STATUS_OK; - } - } else { - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, - spnego.negTokenTarg.responseToken, - &unwrapped_out); - - if (NT_STATUS_IS_OK(nt_status)) { - spnego_state->no_response_expected = True; - } - } - - spnego_free_data(&spnego); - - if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) - && !NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("SPNEGO(%s) login failed: %s\n", - spnego_state->sub_sec_security->ops->name, - nt_errstr(nt_status))); - return nt_status; - } - - if (unwrapped_out.length) { - /* compose reply */ - spnego_out.type = SPNEGO_NEG_TOKEN_TARG; - spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT; - spnego_out.negTokenTarg.supportedMech = NULL; - spnego_out.negTokenTarg.responseToken = unwrapped_out; - spnego_out.negTokenTarg.mechListMIC = null_data_blob; - - if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { - DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - spnego_state->state_position = SPNEGO_CLIENT_TARG; - nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; - } else { - - /* all done - server has accepted, and we agree */ - *out = null_data_blob; - - if (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) { - /* unless of course it did not accept */ - DEBUG(1,("gensec_update ok but not accepted\n")); - nt_status = NT_STATUS_INVALID_PARAMETER; - } - } - - spnego_state->state_position = SPNEGO_DONE; - - return nt_status; - } - case SPNEGO_DONE: - return NT_STATUS_OK; - } - return NT_STATUS_INVALID_PARAMETER; -} - -static BOOL gensec_spnego_have_feature(struct gensec_security *gensec_security, - uint32_t feature) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - if (!spnego_state->sub_sec_security) { - return False; - } - - return gensec_have_feature(spnego_state->sub_sec_security, - feature); -} - -static const struct gensec_security_ops gensec_spnego_security_ops = { - .name = "spnego", - .sasl_name = "GSS-SPNEGO", - .auth_type = DCERPC_AUTH_TYPE_SPNEGO, - .oid = GENSEC_OID_SPNEGO, - .client_start = gensec_spnego_client_start, - .server_start = gensec_spnego_server_start, - .update = gensec_spnego_update, - .seal_packet = gensec_spnego_seal_packet, - .sign_packet = gensec_spnego_sign_packet, - .sig_size = gensec_spnego_sig_size, - .check_packet = gensec_spnego_check_packet, - .unseal_packet = gensec_spnego_unseal_packet, - .wrap = gensec_spnego_wrap, - .unwrap = gensec_spnego_unwrap, - .session_key = gensec_spnego_session_key, - .session_info = gensec_spnego_session_info, - .have_feature = gensec_spnego_have_feature, - .enabled = True -}; - -NTSTATUS gensec_spnego_init(void) -{ - NTSTATUS ret; - ret = gensec_register(&gensec_spnego_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_spnego_security_ops.name)); - return ret; - } - - return ret; -} diff --git a/source4/libcli/auth/spnego.h b/source4/libcli/auth/spnego.h deleted file mode 100644 index 1064370146..0000000000 --- a/source4/libcli/auth/spnego.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - RFC2478 Compliant SPNEGO implementation - - Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef SAMBA_SPNEGO_H -#define SAMBA_SPNEGO_H - -#define SPNEGO_DELEG_FLAG 0x01 -#define SPNEGO_MUTUAL_FLAG 0x02 -#define SPNEGO_REPLAY_FLAG 0x04 -#define SPNEGO_SEQUENCE_FLAG 0x08 -#define SPNEGO_ANON_FLAG 0x10 -#define SPNEGO_CONF_FLAG 0x20 -#define SPNEGO_INTEG_FLAG 0x40 -#define SPNEGO_REQ_FLAG 0x80 - -enum spnego_negResult { - SPNEGO_ACCEPT_COMPLETED = 0, - SPNEGO_ACCEPT_INCOMPLETE = 1, - SPNEGO_REJECT = 2, - SPNEGO_NONE_RESULT = 3 -}; - -struct spnego_negTokenInit { - const char **mechTypes; - int reqFlags; - DATA_BLOB mechToken; - DATA_BLOB mechListMIC; - char *targetPrincipal; -}; - -struct spnego_negTokenTarg { - uint8_t negResult; - const char *supportedMech; - DATA_BLOB responseToken; - DATA_BLOB mechListMIC; -}; - -struct spnego_data { - int type; - struct spnego_negTokenInit negTokenInit; - struct spnego_negTokenTarg negTokenTarg; -}; - -enum spnego_message_type { - SPNEGO_NEG_TOKEN_INIT = 0, - SPNEGO_NEG_TOKEN_TARG = 1, -}; - -#endif diff --git a/source4/libcli/auth/spnego_parse.c b/source4/libcli/auth/spnego_parse.c deleted file mode 100644 index e48c32f0da..0000000000 --- a/source4/libcli/auth/spnego_parse.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - RFC2478 Compliant SPNEGO implementation - - Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "asn_1.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_AUTH - -static BOOL read_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenInit *token) -{ - ZERO_STRUCTP(token); - - asn1_start_tag(asn1, ASN1_CONTEXT(0)); - asn1_start_tag(asn1, ASN1_SEQUENCE(0)); - - while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) { - int i; - uint8_t context; - if (!asn1_peek_uint8(asn1, &context)) { - asn1->has_error = True; - break; - } - - switch (context) { - /* Read mechTypes */ - case ASN1_CONTEXT(0): - asn1_start_tag(asn1, ASN1_CONTEXT(0)); - asn1_start_tag(asn1, ASN1_SEQUENCE(0)); - - token->mechTypes = talloc(NULL, const char *); - for (i = 0; !asn1->has_error && - 0 < asn1_tag_remaining(asn1); i++) { - token->mechTypes = talloc_realloc(NULL, - token->mechTypes, - const char *, i+2); - asn1_read_OID(asn1, token->mechTypes + i); - if (token->mechTypes[i]) { - talloc_steal(token->mechTypes, - token->mechTypes[i]); - } - } - token->mechTypes[i] = NULL; - - asn1_end_tag(asn1); - asn1_end_tag(asn1); - break; - /* Read reqFlags */ - case ASN1_CONTEXT(1): - asn1_start_tag(asn1, ASN1_CONTEXT(1)); - asn1_read_Integer(asn1, &token->reqFlags); - token->reqFlags |= SPNEGO_REQ_FLAG; - asn1_end_tag(asn1); - break; - /* Read mechToken */ - case ASN1_CONTEXT(2): - asn1_start_tag(asn1, ASN1_CONTEXT(2)); - asn1_read_OctetString(asn1, &token->mechToken); - asn1_end_tag(asn1); - break; - /* Read mecListMIC */ - case ASN1_CONTEXT(3): - { - uint8_t type_peek; - asn1_start_tag(asn1, ASN1_CONTEXT(3)); - if (!asn1_peek_uint8(asn1, &type_peek)) { - asn1->has_error = True; - break; - } - if (type_peek == ASN1_OCTET_STRING) { - asn1_read_OctetString(asn1, - &token->mechListMIC); - } else { - /* RFC 2478 says we have an Octet String here, - but W2k sends something different... */ - char *mechListMIC; - asn1_push_tag(asn1, ASN1_SEQUENCE(0)); - asn1_push_tag(asn1, ASN1_CONTEXT(0)); - asn1_read_GeneralString(asn1, &mechListMIC); - asn1_pop_tag(asn1); - asn1_pop_tag(asn1); - - token->targetPrincipal = mechListMIC; - } - asn1_end_tag(asn1); - break; - } - default: - asn1->has_error = True; - break; - } - } - - asn1_end_tag(asn1); - asn1_end_tag(asn1); - - return !asn1->has_error; -} - -static BOOL write_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenInit *token) -{ - asn1_push_tag(asn1, ASN1_CONTEXT(0)); - asn1_push_tag(asn1, ASN1_SEQUENCE(0)); - - /* Write mechTypes */ - if (token->mechTypes && *token->mechTypes) { - int i; - - asn1_push_tag(asn1, ASN1_CONTEXT(0)); - asn1_push_tag(asn1, ASN1_SEQUENCE(0)); - for (i = 0; token->mechTypes[i]; i++) { - asn1_write_OID(asn1, token->mechTypes[i]); - } - asn1_pop_tag(asn1); - asn1_pop_tag(asn1); - } - - /* write reqFlags */ - if (token->reqFlags & SPNEGO_REQ_FLAG) { - int flags = token->reqFlags & ~SPNEGO_REQ_FLAG; - - asn1_push_tag(asn1, ASN1_CONTEXT(1)); - asn1_write_Integer(asn1, flags); - asn1_pop_tag(asn1); - } - - /* write mechToken */ - if (token->mechToken.data) { - asn1_push_tag(asn1, ASN1_CONTEXT(2)); - asn1_write_OctetString(asn1, token->mechToken.data, - token->mechToken.length); - asn1_pop_tag(asn1); - } - - /* write mechListMIC */ - if (token->mechListMIC.data) { - asn1_push_tag(asn1, ASN1_CONTEXT(3)); -#if 0 - /* This is what RFC 2478 says ... */ - asn1_write_OctetString(asn1, token->mechListMIC.data, - token->mechListMIC.length); -#else - /* ... but unfortunately this is what Windows - sends/expects */ - asn1_push_tag(asn1, ASN1_SEQUENCE(0)); - asn1_push_tag(asn1, ASN1_CONTEXT(0)); - asn1_push_tag(asn1, ASN1_GENERAL_STRING); - asn1_write(asn1, token->mechListMIC.data, - token->mechListMIC.length); - asn1_pop_tag(asn1); - asn1_pop_tag(asn1); - asn1_pop_tag(asn1); -#endif - asn1_pop_tag(asn1); - } - - asn1_pop_tag(asn1); - asn1_pop_tag(asn1); - - return !asn1->has_error; -} - -static BOOL read_negTokenTarg(struct asn1_data *asn1, struct spnego_negTokenTarg *token) -{ - ZERO_STRUCTP(token); - - asn1_start_tag(asn1, ASN1_CONTEXT(1)); - asn1_start_tag(asn1, ASN1_SEQUENCE(0)); - - while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) { - uint8_t context; - if (!asn1_peek_uint8(asn1, &context)) { - asn1->has_error = True; - break; - } - - switch (context) { - case ASN1_CONTEXT(0): - asn1_start_tag(asn1, ASN1_CONTEXT(0)); - asn1_start_tag(asn1, ASN1_ENUMERATED); - asn1_read_uint8(asn1, &token->negResult); - asn1_end_tag(asn1); - asn1_end_tag(asn1); - break; - case ASN1_CONTEXT(1): - asn1_start_tag(asn1, ASN1_CONTEXT(1)); - asn1_read_OID(asn1, &token->supportedMech); - asn1_end_tag(asn1); - break; - case ASN1_CONTEXT(2): - asn1_start_tag(asn1, ASN1_CONTEXT(2)); - asn1_read_OctetString(asn1, &token->responseToken); - asn1_end_tag(asn1); - break; - case ASN1_CONTEXT(3): - asn1_start_tag(asn1, ASN1_CONTEXT(3)); - asn1_read_OctetString(asn1, &token->mechListMIC); - asn1_end_tag(asn1); - break; - default: - asn1->has_error = True; - break; - } - } - - asn1_end_tag(asn1); - asn1_end_tag(asn1); - - return !asn1->has_error; -} - -static BOOL write_negTokenTarg(struct asn1_data *asn1, struct spnego_negTokenTarg *token) -{ - asn1_push_tag(asn1, ASN1_CONTEXT(1)); - asn1_push_tag(asn1, ASN1_SEQUENCE(0)); - - if (token->negResult != SPNEGO_NONE_RESULT) { - asn1_push_tag(asn1, ASN1_CONTEXT(0)); - asn1_write_enumerated(asn1, token->negResult); - asn1_pop_tag(asn1); - } - - if (token->supportedMech) { - asn1_push_tag(asn1, ASN1_CONTEXT(1)); - asn1_write_OID(asn1, token->supportedMech); - asn1_pop_tag(asn1); - } - - if (token->responseToken.data) { - asn1_push_tag(asn1, ASN1_CONTEXT(2)); - asn1_write_OctetString(asn1, token->responseToken.data, - token->responseToken.length); - asn1_pop_tag(asn1); - } - - if (token->mechListMIC.data) { - asn1_push_tag(asn1, ASN1_CONTEXT(3)); - asn1_write_OctetString(asn1, token->mechListMIC.data, - token->mechListMIC.length); - asn1_pop_tag(asn1); - } - - asn1_pop_tag(asn1); - asn1_pop_tag(asn1); - - return !asn1->has_error; -} - -ssize_t spnego_read_data(DATA_BLOB data, struct spnego_data *token) -{ - struct asn1_data asn1; - ssize_t ret = -1; - uint8_t context; - - ZERO_STRUCTP(token); - ZERO_STRUCT(asn1); - - if (data.length == 0) { - return ret; - } - - asn1_load(&asn1, data); - - if (!asn1_peek_uint8(&asn1, &context)) { - asn1.has_error = True; - } else { - switch (context) { - case ASN1_APPLICATION(0): - asn1_start_tag(&asn1, ASN1_APPLICATION(0)); - asn1_check_OID(&asn1, GENSEC_OID_SPNEGO); - if (read_negTokenInit(&asn1, &token->negTokenInit)) { - token->type = SPNEGO_NEG_TOKEN_INIT; - } - asn1_end_tag(&asn1); - break; - case ASN1_CONTEXT(1): - if (read_negTokenTarg(&asn1, &token->negTokenTarg)) { - token->type = SPNEGO_NEG_TOKEN_TARG; - } - break; - default: - asn1.has_error = True; - break; - } - } - - if (!asn1.has_error) ret = asn1.ofs; - asn1_free(&asn1); - - return ret; -} - -ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_data *spnego) -{ - struct asn1_data asn1; - ssize_t ret = -1; - - ZERO_STRUCT(asn1); - - switch (spnego->type) { - case SPNEGO_NEG_TOKEN_INIT: - asn1_push_tag(&asn1, ASN1_APPLICATION(0)); - asn1_write_OID(&asn1, GENSEC_OID_SPNEGO); - write_negTokenInit(&asn1, &spnego->negTokenInit); - asn1_pop_tag(&asn1); - break; - case SPNEGO_NEG_TOKEN_TARG: - write_negTokenTarg(&asn1, &spnego->negTokenTarg); - break; - default: - asn1.has_error = True; - break; - } - - if (!asn1.has_error) { - *blob = data_blob_talloc(mem_ctx, asn1.data, asn1.length); - ret = asn1.ofs; - } - asn1_free(&asn1); - - return ret; -} - -BOOL spnego_free_data(struct spnego_data *spnego) -{ - BOOL ret = True; - - if (!spnego) goto out; - - switch(spnego->type) { - case SPNEGO_NEG_TOKEN_INIT: - if (spnego->negTokenInit.mechTypes) { - talloc_free(spnego->negTokenInit.mechTypes); - } - data_blob_free(&spnego->negTokenInit.mechToken); - data_blob_free(&spnego->negTokenInit.mechListMIC); - talloc_free(spnego->negTokenInit.targetPrincipal); - break; - case SPNEGO_NEG_TOKEN_TARG: - if (spnego->negTokenTarg.supportedMech) { - talloc_free(discard_const(spnego->negTokenTarg.supportedMech)); - } - data_blob_free(&spnego->negTokenTarg.responseToken); - data_blob_free(&spnego->negTokenTarg.mechListMIC); - break; - default: - ret = False; - break; - } - ZERO_STRUCTP(spnego); -out: - return ret; -} - |