From 2eb3d680625286431a3a60e37b75f47e0738f253 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 24 Mar 2005 04:14:06 +0000 Subject: [PATCH] r6028: A MAJOR update to intergrate the new credentails system fully with GENSEC, and to pull SCHANNEL into GENSEC, by making it less 'special'. GENSEC now no longer has it's own handling of 'set username' etc, instead it uses cli_credentials calls. In order to link the credentails code right though Samba, a lot of interfaces have changed to remove 'username, domain, password' arguments, and these have been replaced with a single 'struct cli_credentials'. In the session setup code, a new parameter 'workgroup' contains the client/server current workgroup, which seems unrelated to the authentication exchange (it was being filled in from the auth info). This allows in particular kerberos to only call back for passwords when it actually needs to perform the kinit. The kerberos code has been modified not to use the SPNEGO provided 'principal name' (in the mechListMIC), but to instead use the name the host was connected to as. This better matches Microsoft behaviour, is more secure and allows better use of standard kerberos functions. To achieve this, I made changes to our socket code so that the hostname (before name resolution) is now recorded on the socket. In schannel, most of the code from librpc/rpc/dcerpc_schannel.c is now in libcli/auth/schannel.c, and it looks much more like a standard GENSEC module. The actual sign/seal code moved to libcli/auth/schannel_sign.c in a previous commit. The schannel credentails structure is now merged with the rest of the credentails, as many of the values (username, workstation, domain) where already present there. This makes handling this in a generic manner much easier, as there is no longer a custom entry-point. The auth_domain module continues to be developed, but is now just as functional as auth_winbind. The changes here are consequential to the schannel changes. The only removed function at this point is the RPC-LOGIN test (simulating the load of a WinXP login), which needs much more work to clean it up (it contains copies of too much code from all over the torture suite, and I havn't been able to penetrate its 'structure'). Andrew Bartlett (This used to be commit 2301a4b38a21aa60917973451687063d83d18d66) --- source4/auth/auth_domain.c | 10 +- source4/client/client.c | 2 +- source4/include/smb_interfaces.h | 4 +- source4/libcli/auth/config.mk | 3 +- source4/libcli/auth/credentials.c | 6 - source4/libcli/auth/gensec.c | 210 +------------- source4/libcli/auth/gensec.h | 12 +- source4/libcli/auth/gensec.mk | 12 + source4/libcli/auth/gensec_krb5.c | 57 ++-- source4/libcli/auth/gensec_ntlmssp.c | 21 +- source4/libcli/auth/kerberos.h | 1 + source4/libcli/auth/ntlmssp_sign.c | 2 +- source4/libcli/auth/schannel.c | 268 +++++++++++++++++ source4/libcli/auth/schannel_sign.c | 67 ++--- source4/libcli/auth/spnego.c | 10 +- source4/libcli/cliconnect.c | 16 +- source4/libcli/composite/composite.h | 17 +- source4/libcli/composite/connect.c | 9 +- source4/libcli/composite/fetchfile.c | 6 +- source4/libcli/composite/sesssetup.c | 58 ++-- source4/libcli/ldap/ldap.h | 4 +- source4/libcli/ldap/ldap_client.c | 27 +- source4/libcli/raw/clisession.c | 4 +- source4/libcli/raw/clisocket.c | 28 +- source4/libcli/raw/clitree.c | 7 +- source4/librpc/config.mk | 2 +- source4/librpc/rpc/dcerpc_auth.c | 32 +-- source4/librpc/rpc/dcerpc_schannel.c | 413 ++------------------------- source4/librpc/rpc/dcerpc_util.c | 12 +- source4/ntvfs/cifs/vfs_cifs.c | 14 +- source4/smb_server/reply.c | 12 +- source4/smb_server/sesssetup.c | 2 +- source4/torture/basic/secleak.c | 10 +- source4/torture/gentest.c | 4 +- source4/torture/ldap/basic.c | 9 +- source4/torture/ldap/common.c | 5 +- source4/torture/locktest.c | 3 +- source4/torture/masktest.c | 4 +- source4/torture/raw/composite.c | 6 +- source4/torture/raw/context.c | 20 +- source4/torture/rpc/netlogon.c | 9 - source4/torture/rpc/schannel.c | 9 +- source4/torture/rpc/xplogin.c | 23 +- source4/torture/torture.c | 6 +- source4/utils/ntlm_auth.c | 112 ++++---- 45 files changed, 601 insertions(+), 967 deletions(-) create mode 100644 source4/libcli/auth/schannel.c diff --git a/source4/auth/auth_domain.c b/source4/auth/auth_domain.c index 6a968592bdc..a6950445cbc 100644 --- a/source4/auth/auth_domain.c +++ b/source4/auth/auth_domain.c @@ -51,7 +51,15 @@ static NTSTATUS domain_check_password(struct auth_method_context *ctx, binding = bindings[0]; } + if (!user_info->account_name) { + return NT_STATUS_INVALID_PARAMETER; + } + if (!user_info->workstation_name) { + return NT_STATUS_INVALID_PARAMETER; + } + credentials = cli_credentials_init(mem_ctx); + cli_credentials_set_conf(credentials); status = cli_credentials_set_machine_account(credentials); if (!NT_STATUS_IS_OK(status)) { @@ -101,7 +109,7 @@ static NTSTATUS domain_check_password(struct auth_method_context *ctx, ninfo.lm.data = user_info->lm_resp.data; r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p)); - r.in.workstation = creds->computer_name; + r.in.workstation = cli_credentials_get_workstation(credentials); r.in.credential = &auth; r.in.return_authenticator = &auth2; r.in.logon_level = 2; diff --git a/source4/client/client.c b/source4/client/client.c index 4ce686cdcfd..9738292f037 100644 --- a/source4/client/client.c +++ b/source4/client/client.c @@ -3043,7 +3043,7 @@ static struct smbcli_state *do_connect(const char *server, const char *share, st smbcli_parse_unc(share, NULL, &server, &share); } - status = smbcli_full_connection(NULL, &c, lp_netbios_name(), server, + status = smbcli_full_connection(NULL, &c, server, share, NULL, cred); if (!NT_STATUS_IS_OK(status)) { d_printf("Connection to \\\\%s\\%s failed - %s\n", diff --git a/source4/include/smb_interfaces.h b/source4/include/smb_interfaces.h index 1052a6297d5..af9f6efd7a2 100644 --- a/source4/include/smb_interfaces.h +++ b/source4/include/smb_interfaces.h @@ -269,14 +269,14 @@ union smb_sesssetup { DATA_BLOB secblob; const char *os; const char *lanman; - const char *domain; + const char *workgroup; } in; struct { uint16_t action; DATA_BLOB secblob; char *os; char *lanman; - char *domain; + char *workgroup; uint16_t vuid; } out; } spnego; diff --git a/source4/libcli/auth/config.mk b/source4/libcli/auth/config.mk index b37e2143605..0c013ce0ef8 100644 --- a/source4/libcli/auth/config.mk +++ b/source4/libcli/auth/config.mk @@ -1,8 +1,7 @@ ################################# # Start SUBSYSTEM GENSEC [SUBSYSTEM::LIBCLI_AUTH] -ADD_OBJ_FILES = libcli/auth/schannel_sign.o \ - libcli/auth/credentials.o \ +ADD_OBJ_FILES = libcli/auth/credentials.o \ libcli/auth/session.o \ libcli/auth/smbencrypt.o REQUIRED_SUBSYSTEMS = \ diff --git a/source4/libcli/auth/credentials.c b/source4/libcli/auth/credentials.c index 90b8313c9d8..bcb462ae9da 100644 --- a/source4/libcli/auth/credentials.c +++ b/source4/libcli/auth/credentials.c @@ -192,18 +192,12 @@ next comes the client specific functions void creds_client_init(struct creds_CredentialState *creds, const struct netr_Credential *client_challenge, const struct netr_Credential *server_challenge, - const char *computer_name, - const char *domain, - const char *account_name, const struct samr_Password *machine_password, struct netr_Credential *initial_credential, uint32_t negotiate_flags) { creds->sequence = time(NULL); creds->negotiate_flags = negotiate_flags; - creds->computer_name = talloc_strdup(creds, computer_name); - creds->domain = talloc_strdup(creds, domain); - creds->account_name = talloc_strdup(creds, account_name); dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data)); dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data)); diff --git a/source4/libcli/auth/gensec.c b/source4/libcli/auth/gensec.c index 69de0161567..cc7327187cb 100644 --- a/source4/libcli/auth/gensec.c +++ b/source4/libcli/auth/gensec.c @@ -4,7 +4,7 @@ Generic Authentication Interface Copyright (C) Andrew Tridgell 2003 - Copyright (C) Andrew Bartlett 2004 + Copyright (C) Andrew Bartlett 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 @@ -130,13 +130,7 @@ static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, struct gensec_security **gense (*gensec_security)->ops = NULL; - ZERO_STRUCT((*gensec_security)->user); ZERO_STRUCT((*gensec_security)->target); - ZERO_STRUCT((*gensec_security)->default_user); - - (*gensec_security)->default_user.name = ""; - (*gensec_security)->default_user.domain = talloc_strdup(*gensec_security, lp_workgroup()); - (*gensec_security)->default_user.realm = talloc_strdup(*gensec_security, lp_realm()); (*gensec_security)->subcontext = False; (*gensec_security)->want_features = 0; @@ -185,8 +179,6 @@ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gense (*gensec_security)->gensec_role = GENSEC_CLIENT; (*gensec_security)->password_callback = NULL; - ZERO_STRUCT((*gensec_security)->user); - return status; } @@ -507,163 +499,24 @@ BOOL gensec_have_feature(struct gensec_security *gensec_security, } /** - * Set a username on a GENSEC context - ensures it is talloc()ed + * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context * */ -NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user) +NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) { - gensec_security->user.name = talloc_strdup(gensec_security, user); - if (user && !gensec_security->user.name) { - return NT_STATUS_NO_MEMORY; - } + gensec_security->credentials = talloc_reference(gensec_security, credentials); return NT_STATUS_OK; } /** - * Set a username on a GENSEC context - ensures it is talloc()ed + * Return the credentails structure associated with a GENSEC context * */ -const char *gensec_get_username(struct gensec_security *gensec_security) +struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security) { - if (gensec_security->user.name) { - return gensec_security->user.name; - } - return gensec_security->default_user.name; -} - -/** - * Set a domain on a GENSEC context - ensures it is talloc()ed - * - */ - -NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain) -{ - gensec_security->user.domain = talloc_strdup(gensec_security, domain); - if (domain && !gensec_security->user.domain) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Return the NT domain for this GENSEC context - * - */ - -const char *gensec_get_domain(struct gensec_security *gensec_security) -{ - if (gensec_security->user.domain) { - return gensec_security->user.domain; - } else if (gensec_security->user.realm) { - return gensec_security->user.realm; - } - return gensec_security->default_user.domain; -} - -/** - * Set the client workstation on a GENSEC context - ensures it is talloc()ed - * - */ - -NTSTATUS gensec_set_workstation(struct gensec_security *gensec_security, const char *workstation) -{ - gensec_security->user.workstation = talloc_strdup(gensec_security, workstation); - if (workstation && !gensec_security->user.workstation) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Return the client workstation on a GENSEC context - ensures it is talloc()ed - * - */ - -const char *gensec_get_workstation(struct gensec_security *gensec_security) -{ - if (gensec_security->user.workstation) { - return gensec_security->user.workstation; - } else { - return lp_netbios_name(); - } -} - -/** - * Set a kerberos realm on a GENSEC context - ensures it is talloc()ed - * - */ - -NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm) -{ - gensec_security->user.realm = talloc_strdup(gensec_security, realm); - if (realm && !gensec_security->user.realm) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Return the Krb5 realm for this context - * - */ - -const char *gensec_get_realm(struct gensec_security *gensec_security) -{ - if (gensec_security->user.realm) { - return gensec_security->user.realm; - } else if (gensec_security->user.domain) { - return gensec_security->user.domain; - } - return gensec_security->default_user.realm; -} - -/** - * Return a kerberos principal for this context, if one has been set - * - */ - -char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx) -{ - const char *realm = gensec_get_realm(gensec_security); - if (realm) { - return talloc_asprintf(mem_ctx, "%s@%s", - gensec_get_username(gensec_security), - gensec_get_realm(gensec_security)); - } else { - return talloc_strdup(mem_ctx, gensec_get_username(gensec_security)); - } -} - -/** - * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will - * not do a callback - * - */ - -NTSTATUS gensec_set_password(struct gensec_security *gensec_security, - const char *password) -{ - gensec_security->user.password = talloc_strdup(gensec_security, password); - if (password && !gensec_security->user.password) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed - * - */ - -NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal) -{ - gensec_security->target.principal = talloc_strdup(gensec_security, principal); - if (!gensec_security->target.principal) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; + return gensec_security->credentials; } /** @@ -713,54 +566,6 @@ const char *gensec_get_target_service(struct gensec_security *gensec_security) return "host"; } -const char *gensec_get_target_principal(struct gensec_security *gensec_security) -{ - const char *mechListMIC; - - if (gensec_security->target.principal) { - return gensec_security->target.principal; - } - - mechListMIC = talloc_asprintf(gensec_security,"%s$@%s", - lp_netbios_name(), - lp_realm()); - return mechListMIC; -} - -/** - * Set a password callback, if the gensec module we use demands a password - */ - -void gensec_set_password_callback(struct gensec_security *gensec_security, - gensec_password_callback callback, void *callback_private_data) -{ - gensec_security->password_callback = callback; - gensec_security->password_callback_private = callback_private_data; -} - -/** - * Get (or call back for) a password. - */ - -NTSTATUS gensec_get_password(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - char **password) -{ - if (gensec_security->user.password) { - *password = talloc_strdup(mem_ctx, gensec_security->user.password); - if (!*password) { - return NT_STATUS_NO_MEMORY; - } else { - return NT_STATUS_OK; - } - } - if (!gensec_security->password_callback) { - *password = NULL; - return NT_STATUS_OK; - } - return gensec_security->password_callback(gensec_security, mem_ctx, password); -} - /* register a GENSEC backend. @@ -821,6 +626,5 @@ const struct gensec_critical_sizes *gensec_interface_version(void) */ NTSTATUS gensec_init(void) { - gensec_dcerpc_schannel_init(); return NT_STATUS_OK; } diff --git a/source4/libcli/auth/gensec.h b/source4/libcli/auth/gensec.h index a4383d852c5..91c817d48a8 100644 --- a/source4/libcli/auth/gensec.h +++ b/source4/libcli/auth/gensec.h @@ -4,7 +4,7 @@ Generic Authentication Interface Copyright (C) Andrew Tridgell 2003 - Copyright (C) Andrew Bartlett 2004 + Copyright (C) Andrew Bartlett 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 @@ -28,13 +28,6 @@ #define GENSEC_OID_KERBEROS5_USER2USER "1 2 840 113554 1 2 2 3" struct gensec_security; -struct gensec_user { - const char *workstation; - const char *domain; - const char *realm; - const char *name; - const char *password; -}; struct gensec_target { const char *principal; const char *hostname; @@ -105,8 +98,7 @@ struct gensec_security { void *password_callback_private; const struct gensec_security_ops *ops; void *private_data; - struct gensec_user user; - struct gensec_user default_user; + struct cli_credentials *credentials; struct gensec_target target; enum gensec_role gensec_role; BOOL subcontext; diff --git a/source4/libcli/auth/gensec.mk b/source4/libcli/auth/gensec.mk index 7e2e34081d3..b4c612da14e 100644 --- a/source4/libcli/auth/gensec.mk +++ b/source4/libcli/auth/gensec.mk @@ -68,6 +68,18 @@ 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] diff --git a/source4/libcli/auth/gensec_krb5.c b/source4/libcli/auth/gensec_krb5.c index 71670632b94..453485d8160 100644 --- a/source4/libcli/auth/gensec_krb5.c +++ b/source4/libcli/auth/gensec_krb5.c @@ -320,7 +320,12 @@ 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; @@ -341,22 +346,8 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security } while (1) { - if (gensec_security->target.principal) { - DEBUG(5, ("Finding ticket for target [%s]\n", gensec_security->target.principal)); - ret = ads_krb5_mk_req(gensec_krb5_state->context, - &gensec_krb5_state->auth_context, - AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED, - gensec_security->target.principal, - gensec_krb5_state->ccache, - &gensec_krb5_state->ticket); - } else { + { krb5_data in_data; - 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; - } - in_data.length = 0; ret = krb5_mk_req(gensec_krb5_state->context, @@ -372,36 +363,40 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security case 0: return NT_STATUS_OK; case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: - DEBUG(3, ("Server is not registered with our KDC: %s\n", - error_message(ret))); + 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: + { - char *password; + const char *password; char *ccache_string; time_t kdc_time = 0; - nt_status = gensec_get_password(gensec_security, - gensec_security, - &password); + 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", - gensec_get_client_principal(gensec_security, gensec_krb5_state), - gensec_get_target_principal(gensec_security), + 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); @@ -413,8 +408,8 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security } ret = kerberos_kinit_password_cc(gensec_krb5_state->context, gensec_krb5_state->ccache, - gensec_get_client_principal(gensec_security, gensec_krb5_state), - password, NULL, &kdc_time); + 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)) { @@ -422,10 +417,18 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security 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 failed (%s)\n", + 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; } diff --git a/source4/libcli/auth/gensec_ntlmssp.c b/source4/libcli/auth/gensec_ntlmssp.c index 51456d91070..59559048866 100644 --- a/source4/libcli/auth/gensec_ntlmssp.c +++ b/source4/libcli/auth/gensec_ntlmssp.c @@ -109,7 +109,7 @@ static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, 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); + user_info, &gensec_ntlmssp_state->server_info); talloc_free(user_info); NT_STATUS_NOT_OK_RETURN(nt_status); @@ -197,7 +197,7 @@ static NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_secur static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security) { struct gensec_ntlmssp_state *gensec_ntlmssp_state; - char *password = NULL; + const char *password = NULL; NTSTATUS nt_status; nt_status = gensec_ntlmssp_start(gensec_security); @@ -228,25 +228,20 @@ static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_secur } nt_status = ntlmssp_set_domain(gensec_ntlmssp_state->ntlmssp_state, - gensec_security->user.domain); + cli_credentials_get_domain(gensec_security->credentials)); NT_STATUS_NOT_OK_RETURN(nt_status); nt_status = ntlmssp_set_username(gensec_ntlmssp_state->ntlmssp_state, - gensec_security->user.name); + cli_credentials_get_username(gensec_security->credentials)); NT_STATUS_NOT_OK_RETURN(nt_status); - if (gensec_security->user.name) { - nt_status = gensec_get_password(gensec_security, gensec_ntlmssp_state, &password); - NT_STATUS_NOT_OK_RETURN(nt_status); - } + password = cli_credentials_get_password(gensec_security->credentials); - if (password) { - nt_status = ntlmssp_set_password(gensec_ntlmssp_state->ntlmssp_state, password); - NT_STATUS_NOT_OK_RETURN(nt_status); - } + 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, - gensec_get_workstation(gensec_security)); + cli_credentials_get_workstation(gensec_security->credentials)); gensec_security->private_data = gensec_ntlmssp_state; diff --git a/source4/libcli/auth/kerberos.h b/source4/libcli/auth/kerberos.h index 9bb6d22eb6b..c9b2eae55cb 100644 --- a/source4/libcli/auth/kerberos.h +++ b/source4/libcli/auth/kerberos.h @@ -93,5 +93,6 @@ krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context, 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); #endif /* HAVE_KRB5 */ diff --git a/source4/libcli/auth/ntlmssp_sign.c b/source4/libcli/auth/ntlmssp_sign.c index 1b391306bce..347a85da77a 100644 --- a/source4/libcli/auth/ntlmssp_sign.c +++ b/source4/libcli/auth/ntlmssp_sign.c @@ -3,7 +3,7 @@ * Version 3.0 * NTLMSSP Signing routines * Copyright (C) Luke Kenneth Casson Leighton 1996-2001 - * Copyright (C) Andrew Bartlett 2003 + * Copyright (C) Andrew Bartlett 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 diff --git a/source4/libcli/auth/schannel.c b/source4/libcli/auth/schannel.c new file mode 100644 index 00000000000..3dbf10580bb --- /dev/null +++ b/source4/libcli/auth/schannel.c @@ -0,0 +1,268 @@ +/* + Unix SMB/CIFS implementation. + + dcerpc schannel operations + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Andrew Bartlett 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_sign.c b/source4/libcli/auth/schannel_sign.c index d582ff2dd0e..3b493bd0d38 100644 --- a/source4/libcli/auth/schannel_sign.c +++ b/source4/libcli/auth/schannel_sign.c @@ -4,6 +4,7 @@ schannel library code Copyright (C) Andrew Tridgell 2004 + Copyright (C) Andrew Bartlett 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 @@ -22,12 +23,9 @@ #include "includes.h" #include "lib/crypto/crypto.h" - -struct schannel_state { - uint8_t session_key[16]; - uint32_t seq_num; - BOOL initiator; -}; +#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 } @@ -43,7 +41,7 @@ static void netsec_deal_with_seq_num(struct schannel_state *state, uint8_t sequence_key[16]; uint8_t digest1[16]; - hmac_md5(state->session_key, zeros, sizeof(zeros), digest1); + 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); @@ -102,11 +100,14 @@ static void schannel_digest(const uint8_t sess_key[16], /* unseal a packet */ -NTSTATUS schannel_unseal_packet(struct schannel_state *state, +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]; @@ -122,11 +123,11 @@ NTSTATUS schannel_unseal_packet(struct schannel_state *state, RSIVAL(seq_num, 0, state->seq_num); SIVAL(seq_num, 4, state->initiator?0:0x80); - netsec_get_sealing_key(state->session_key, seq_num, sealing_key); + 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->session_key, + schannel_digest(state->creds->session_key, netsec_sig, confounder, data, length, digest_final); @@ -150,10 +151,14 @@ NTSTATUS schannel_unseal_packet(struct schannel_state *state, /* check the signature on a packet */ -NTSTATUS schannel_check_packet(struct schannel_state *state, +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; @@ -167,9 +172,9 @@ NTSTATUS schannel_check_packet(struct schannel_state *state, SIVAL(seq_num, 4, state->initiator?0:0x80); dump_data_pw("seq_num:\n", seq_num, 8); - dump_data_pw("sess_key:\n", state->session_key, 16); + dump_data_pw("sess_key:\n", state->creds->session_key, 16); - schannel_digest(state->session_key, + schannel_digest(state->creds->session_key, netsec_sig, NULL, data, length, digest_final); @@ -194,11 +199,14 @@ NTSTATUS schannel_check_packet(struct schannel_state *state, /* seal a packet */ -NTSTATUS schannel_seal_packet(struct schannel_state *state, +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]; @@ -210,11 +218,11 @@ NTSTATUS schannel_seal_packet(struct schannel_state *state, RSIVAL(seq_num, 0, state->seq_num); SIVAL(seq_num, 4, state->initiator?0x80:0); - schannel_digest(state->session_key, + schannel_digest(state->creds->session_key, netsec_sig, confounder, data, length, digest_final); - netsec_get_sealing_key(state->session_key, seq_num, sealing_key); + netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key); arcfour_crypt(confounder, sealing_key, 8); arcfour_crypt(data, sealing_key, length); @@ -239,11 +247,14 @@ NTSTATUS schannel_seal_packet(struct schannel_state *state, /* sign a packet */ -NTSTATUS schannel_sign_packet(struct schannel_state *state, +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; @@ -251,7 +262,7 @@ NTSTATUS schannel_sign_packet(struct schannel_state *state, RSIVAL(seq_num, 0, state->seq_num); SIVAL(seq_num, 4, state->initiator?0x80:0); - schannel_digest(state->session_key, + schannel_digest(state->creds->session_key, netsec_sig, NULL, data, length, digest_final); @@ -271,23 +282,3 @@ NTSTATUS schannel_sign_packet(struct schannel_state *state, return NT_STATUS_OK; } - -/* - create an schannel context state -*/ -NTSTATUS schannel_start(TALLOC_CTX *mem_ctx, - struct schannel_state **state, - const uint8_t session_key[16], - BOOL initiator) -{ - (*state) = talloc(mem_ctx, struct schannel_state); - if (!(*state)) { - return NT_STATUS_NO_MEMORY; - } - - memcpy((*state)->session_key, session_key, 16); - (*state)->initiator = initiator; - (*state)->seq_num = 0; - - return NT_STATUS_OK; -} diff --git a/source4/libcli/auth/spnego.c b/source4/libcli/auth/spnego.c index 39807671656..f5a091cd784 100644 --- a/source4/libcli/auth/spnego.c +++ b/source4/libcli/auth/spnego.c @@ -610,7 +610,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA spnego_out.negTokenInit.mechTypes = mechlist; spnego_out.negTokenInit.reqFlags = 0; spnego_out.negTokenInit.mechListMIC - = data_blob_string_const(gensec_get_target_principal(gensec_security)); + = 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) { @@ -657,13 +657,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA } if (spnego.negTokenInit.targetPrincipal) { - DEBUG(5, ("Server claims it's principal name is %s\n", spnego.negTokenInit.targetPrincipal)); - nt_status = gensec_set_target_principal(gensec_security, - spnego.negTokenInit.targetPrincipal); - if (!NT_STATUS_IS_OK(nt_status)) { - spnego_free_data(&spnego); - return nt_status; - } + DEBUG(5, ("Server claims it's principal name is %s (ignored)\n", spnego.negTokenInit.targetPrincipal)); } nt_status = gensec_spnego_client_parse_negTokenInit(gensec_security, diff --git a/source4/libcli/cliconnect.c b/source4/libcli/cliconnect.c index 7459460137a..53a97da168e 100644 --- a/source4/libcli/cliconnect.c +++ b/source4/libcli/cliconnect.c @@ -63,7 +63,7 @@ NTSTATUS smbcli_negprot(struct smbcli_state *cli) /* wrapper around smb_raw_session_setup() */ NTSTATUS smbcli_session_setup(struct smbcli_state *cli, - struct cli_credentials *credentials) + struct cli_credentials *credentials) { struct smb_composite_sesssetup setup; NTSTATUS status; @@ -77,15 +77,8 @@ NTSTATUS smbcli_session_setup(struct smbcli_state *cli, setup.in.sesskey = cli->transport->negotiate.sesskey; setup.in.capabilities = cli->transport->negotiate.capabilities; - if (cli_credentials_is_anonymous(credentials)) { - if (cli->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) { - setup.in.password = cli_credentials_get_password(credentials); - } else { - setup.in.password = NULL; - } - setup.in.user = cli_credentials_get_username(credentials); - setup.in.domain = cli_credentials_get_domain(credentials); - } + setup.in.credentials = credentials; + setup.in.workgroup = lp_workgroup(); status = smb_composite_sesssetup(cli->session, &setup); @@ -144,7 +137,6 @@ NTSTATUS smbcli_send_tconX(struct smbcli_state *cli, const char *sharename, */ NTSTATUS smbcli_full_connection(TALLOC_CTX *parent_ctx, struct smbcli_state **ret_cli, - const char *myname, const char *host, const char *sharename, const char *devtype, @@ -159,7 +151,7 @@ NTSTATUS smbcli_full_connection(TALLOC_CTX *parent_ctx, *ret_cli = NULL; status = smbcli_tree_full_connection(parent_ctx, - &tree, myname, host, 0, sharename, devtype, + &tree, host, 0, sharename, devtype, credentials); if (!NT_STATUS_IS_OK(status)) { goto done; diff --git a/source4/libcli/composite/composite.h b/source4/libcli/composite/composite.h index bf0fb9ed48a..18922127ee7 100644 --- a/source4/libcli/composite/composite.h +++ b/source4/libcli/composite/composite.h @@ -70,12 +70,10 @@ struct smb_composite_fetchfile { const char *dest_host; int port; const char *called_name; - const char *calling_name; const char *service; const char *service_type; - const char *user; - const char *domain; - const char *password; + struct cli_credentials *credentials; + const char *workgroup; const char *filename; } in; struct { @@ -111,12 +109,10 @@ struct smb_composite_connect { const char *dest_host; int port; const char *called_name; - const char *calling_name; const char *service; const char *service_type; - const char *user; - const char *domain; - const char *password; + struct cli_credentials *credentials; + const char *workgroup; } in; struct { struct smbcli_tree *tree; @@ -132,9 +128,8 @@ struct smb_composite_sesssetup { struct { uint32_t sesskey; uint32_t capabilities; - const char *password; - const char *user; - const char *domain; + struct cli_credentials *credentials; + const char *workgroup; } in; struct { uint16_t vuid; diff --git a/source4/libcli/composite/connect.c b/source4/libcli/composite/connect.c index 5f5275f7e64..0da71df9928 100644 --- a/source4/libcli/composite/connect.c +++ b/source4/libcli/composite/connect.c @@ -166,9 +166,8 @@ static NTSTATUS connect_negprot(struct composite_context *c, /* prepare a session setup to establish a security context */ state->io_setup->in.sesskey = state->transport->negotiate.sesskey; state->io_setup->in.capabilities = state->transport->negotiate.capabilities; - state->io_setup->in.domain = io->in.domain; - state->io_setup->in.user = io->in.user; - state->io_setup->in.password = io->in.password; + state->io_setup->in.credentials = io->in.credentials; + state->io_setup->in.workgroup = io->in.workgroup; state->creq = smb_composite_sesssetup_send(state->session, state->io_setup); NT_STATUS_HAVE_NO_MEMORY(state->creq); @@ -214,7 +213,7 @@ static NTSTATUS connect_socket(struct composite_context *c, state->transport = smbcli_transport_init(state->sock, state, True); NT_STATUS_HAVE_NO_MEMORY(state->transport); - calling.name = io->in.calling_name; + calling.name = cli_credentials_get_workstation(io->in.credentials); calling.type = NBT_NAME_CLIENT; calling.scope = NULL; @@ -254,7 +253,7 @@ static NTSTATUS connect_resolve(struct composite_context *c, status = resolve_name_recv(state->creq, state, &address); NT_STATUS_NOT_OK_RETURN(status); - state->creq = smbcli_sock_connect_send(state->sock, address, state->io->in.port); + state->creq = smbcli_sock_connect_send(state->sock, address, state->io->in.port, io->in.dest_host); NT_STATUS_HAVE_NO_MEMORY(state->creq); state->stage = CONNECT_SOCKET; diff --git a/source4/libcli/composite/fetchfile.c b/source4/libcli/composite/fetchfile.c index 2bf6ef90232..fb9226985e9 100644 --- a/source4/libcli/composite/fetchfile.c +++ b/source4/libcli/composite/fetchfile.c @@ -140,12 +140,10 @@ struct composite_context *smb_composite_fetchfile_send(struct smb_composite_fetc state->connect->in.dest_host = io->in.dest_host; state->connect->in.port = io->in.port; state->connect->in.called_name = io->in.called_name; - state->connect->in.calling_name = io->in.calling_name; state->connect->in.service = io->in.service; state->connect->in.service_type = io->in.service_type; - state->connect->in.user = io->in.user; - state->connect->in.domain = io->in.domain; - state->connect->in.password = io->in.password; + state->connect->in.credentials = io->in.credentials; + state->connect->in.workgroup = io->in.workgroup; state->req = smb_composite_connect_send(state->connect, event_ctx); if (state->req == NULL) goto failed; diff --git a/source4/libcli/composite/sesssetup.c b/source4/libcli/composite/sesssetup.c index 07c718b05b6..31ca5caed79 100644 --- a/source4/libcli/composite/sesssetup.c +++ b/source4/libcli/composite/sesssetup.c @@ -142,7 +142,7 @@ static void request_handler(struct smbcli_request *req) } /* enforce the local signing required flag */ - if (NT_STATUS_IS_OK(c->status) && state->io->in.user && state->io->in.user[0]) { + if (NT_STATUS_IS_OK(c->status) && !cli_credentials_is_anonymous(state->io->in.credentials)) { if (!session->transport->negotiate.sign_info.doing_signing && session->transport->negotiate.sign_info.mandatory_signing) { DEBUG(0, ("SMB signing required, but server does not support it\n")); @@ -169,6 +169,7 @@ static struct smbcli_request *session_setup_nt1(struct composite_context *c, struct smb_composite_sesssetup *io) { struct sesssetup_state *state = talloc_get_type(c->private, struct sesssetup_state); + const char *password = cli_credentials_get_password(io->in.credentials); state->setup.nt1.level = RAW_SESSSETUP_NT1; state->setup.nt1.in.bufsize = session->transport->options.max_xmit; @@ -176,23 +177,23 @@ static struct smbcli_request *session_setup_nt1(struct composite_context *c, state->setup.nt1.in.vc_num = 1; state->setup.nt1.in.sesskey = io->in.sesskey; state->setup.nt1.in.capabilities = io->in.capabilities; - state->setup.nt1.in.domain = io->in.domain; - state->setup.nt1.in.user = io->in.user; state->setup.nt1.in.os = "Unix"; state->setup.nt1.in.lanman = "Samba"; - if (!io->in.password) { + state->setup.old.in.domain = cli_credentials_get_domain(io->in.credentials); + state->setup.old.in.user = cli_credentials_get_username(io->in.credentials); + if (!password) { state->setup.nt1.in.password1 = data_blob(NULL, 0); state->setup.nt1.in.password2 = data_blob(NULL, 0); } else if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) { - state->setup.nt1.in.password1 = lanman_blob(state, io->in.password, + state->setup.nt1.in.password1 = lanman_blob(state, password, session->transport->negotiate.secblob); - state->setup.nt1.in.password2 = nt_blob(state, io->in.password, + state->setup.nt1.in.password2 = nt_blob(state, password, session->transport->negotiate.secblob); - use_nt1_session_keys(session, io->in.password, &state->setup.nt1.in.password2); + use_nt1_session_keys(session, password, &state->setup.nt1.in.password2); } else { - state->setup.nt1.in.password1 = data_blob_talloc(state, io->in.password, strlen(io->in.password)); + state->setup.nt1.in.password1 = data_blob_talloc(state, password, strlen(password)); state->setup.nt1.in.password2 = data_blob(NULL, 0); } @@ -208,26 +209,27 @@ static struct smbcli_request *session_setup_old(struct composite_context *c, struct smb_composite_sesssetup *io) { struct sesssetup_state *state = talloc_get_type(c->private, struct sesssetup_state); + const char *password = cli_credentials_get_password(io->in.credentials); state->setup.old.level = RAW_SESSSETUP_OLD; state->setup.old.in.bufsize = session->transport->options.max_xmit; state->setup.old.in.mpx_max = session->transport->options.max_mux; state->setup.old.in.vc_num = 1; state->setup.old.in.sesskey = io->in.sesskey; - state->setup.old.in.domain = io->in.domain; - state->setup.old.in.user = io->in.user; + state->setup.old.in.domain = cli_credentials_get_domain(io->in.credentials); + state->setup.old.in.user = cli_credentials_get_username(io->in.credentials); state->setup.old.in.os = "Unix"; state->setup.old.in.lanman = "Samba"; - if (!io->in.password) { + if (!password) { state->setup.old.in.password = data_blob(NULL, 0); } else if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) { - state->setup.old.in.password = lanman_blob(state, io->in.password, + state->setup.old.in.password = lanman_blob(state, password, session->transport->negotiate.secblob); } else { state->setup.old.in.password = data_blob_talloc(state, - io->in.password, - strlen(io->in.password)); + password, + strlen(password)); } return smb_raw_session_setup_send(session, &state->setup); @@ -253,9 +255,10 @@ static struct smbcli_request *session_setup_spnego(struct composite_context *c, state->setup.spnego.in.vc_num = 1; state->setup.spnego.in.sesskey = io->in.sesskey; state->setup.spnego.in.capabilities = io->in.capabilities; - state->setup.spnego.in.domain = io->in.domain; state->setup.spnego.in.os = "Unix"; state->setup.spnego.in.lanman = "Samba"; + state->setup.spnego.in.workgroup = io->in.workgroup; + state->setup.spnego.out.vuid = session->vuid; smbcli_temp_set_signing(session->transport); @@ -268,23 +271,9 @@ static struct smbcli_request *session_setup_spnego(struct composite_context *c, gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY); - status = gensec_set_domain(session->gensec, io->in.domain); + status = gensec_set_credentials(session->gensec, io->in.credentials); if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n", - io->in.domain, nt_errstr(status))); - return NULL; - } - - status = gensec_set_username(session->gensec, io->in.user); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n", - io->in.user, nt_errstr(status))); - return NULL; - } - - status = gensec_set_password(session->gensec, io->in.password); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client password: %s\n", + DEBUG(1, ("Failed to start set GENSEC client credentails: %s\n", nt_errstr(status))); return NULL; } @@ -296,6 +285,13 @@ static struct smbcli_request *session_setup_spnego(struct composite_context *c, return NULL; } + status = gensec_set_target_service(session->gensec, "cifs"); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to start set GENSEC target service: %s\n", + nt_errstr(status))); + return NULL; + } + if (session->transport->negotiate.secblob.length) { chosen_oid = GENSEC_OID_SPNEGO; } else { diff --git a/source4/libcli/ldap/ldap.h b/source4/libcli/ldap/ldap.h index 3e51e4f60f4..710c022a3c0 100644 --- a/source4/libcli/ldap/ldap.h +++ b/source4/libcli/ldap/ldap.h @@ -337,11 +337,11 @@ struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid, struct ldap_message *ldap_transaction(struct ldap_connection *conn, struct ldap_message *request); int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password); -int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password); +int ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *creds); struct ldap_connection *ldap_setup_connection(TALLOC_CTX *mem_ctx, const char *url, const char *userdn, const char *password); struct ldap_connection *ldap_setup_connection_with_sasl(TALLOC_CTX *mem_ctx, const char *url, - const char *username, const char *domain, const char *password); + struct cli_credentials *creds); BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid, const struct timeval *endtime); BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg, diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c index e3904c7a6b4..71b57e116e6 100644 --- a/source4/libcli/ldap/ldap_client.c +++ b/source4/libcli/ldap/ldap_client.c @@ -605,7 +605,7 @@ int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const cha return result; } -int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password) +int ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *creds) { NTSTATUS status; TALLOC_CTX *mem_ctx = NULL; @@ -626,23 +626,9 @@ int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const cha gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL); - status = gensec_set_domain(conn->gensec, domain); + status = gensec_set_credentials(conn->gensec, creds); if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n", - domain, nt_errstr(status))); - goto done; - } - - status = gensec_set_username(conn->gensec, username); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n", - username, nt_errstr(status))); - goto done; - } - - status = gensec_set_password(conn->gensec, password); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client password: %s\n", + DEBUG(1, ("Failed to start set GENSEC creds: %s\n", nt_errstr(status))); goto done; } @@ -739,8 +725,9 @@ struct ldap_connection *ldap_setup_connection(TALLOC_CTX *mem_ctx, const char *u return conn; } -struct ldap_connection *ldap_setup_connection_with_sasl(TALLOC_CTX *mem_ctx, const char *url, - const char *username, const char *domain, const char *password) +struct ldap_connection *ldap_setup_connection_with_sasl(TALLOC_CTX *mem_ctx, + const char *url, + struct cli_credentials *creds) { struct ldap_connection *conn; int result; @@ -750,7 +737,7 @@ struct ldap_connection *ldap_setup_connection_with_sasl(TALLOC_CTX *mem_ctx, con return NULL; } - result = ldap_bind_sasl(conn, username, domain, password); + result = ldap_bind_sasl(conn, creds); if (result != LDAP_SUCCESS) { talloc_free(conn); return NULL; diff --git a/source4/libcli/raw/clisession.c b/source4/libcli/raw/clisession.c index 5f757018713..31566245896 100644 --- a/source4/libcli/raw/clisession.c +++ b/source4/libcli/raw/clisession.c @@ -134,7 +134,7 @@ struct smbcli_request *smb_raw_session_setup_send(struct smbcli_session *session smbcli_req_append_blob(req, &parms->spnego.in.secblob); smbcli_req_append_string(req, parms->spnego.in.os, STR_TERMINATE); smbcli_req_append_string(req, parms->spnego.in.lanman, STR_TERMINATE); - smbcli_req_append_string(req, parms->spnego.in.domain, STR_TERMINATE); + smbcli_req_append_string(req, parms->spnego.in.workgroup, STR_TERMINATE); break; } @@ -210,7 +210,7 @@ NTSTATUS smb_raw_session_setup_recv(struct smbcli_request *req, p += parms->spnego.out.secblob.length; p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.os, p, -1, STR_TERMINATE); p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.lanman, p, -1, STR_TERMINATE); - p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.domain, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.workgroup, p, -1, STR_TERMINATE); break; } diff --git a/source4/libcli/raw/clisocket.c b/source4/libcli/raw/clisocket.c index cbb479ca1a1..7cb70401310 100644 --- a/source4/libcli/raw/clisocket.c +++ b/source4/libcli/raw/clisocket.c @@ -34,7 +34,8 @@ struct clisocket_connect { int port_num; int *iports; struct smbcli_socket *sock; - const char *dest_host; + const char *dest_host_addr; + const char *dest_hostname; }; @@ -83,7 +84,7 @@ static void smbcli_sock_connect_handler(struct event_context *ev, struct fd_even c->status = socket_connect_complete(conn->sock->sock, 0); if (NT_STATUS_IS_OK(c->status)) { socket_set_option(conn->sock->sock, lp_socket_options(), NULL); - conn->sock->hostname = talloc_strdup(conn->sock, conn->dest_host); + conn->sock->hostname = talloc_strdup(conn->sock, conn->dest_hostname); c->state = SMBCLI_REQUEST_DONE; if (c->async.fn) { c->async.fn(c); @@ -95,7 +96,7 @@ static void smbcli_sock_connect_handler(struct event_context *ev, struct fd_even for (i=conn->port_num+1;conn->iports[i];i++) { conn->port_num = i; c->status = smbcli_sock_connect_one(conn->sock, - conn->dest_host, + conn->dest_host_addr, conn->iports[i], c); if (NT_STATUS_IS_OK(c->status) || NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { @@ -151,7 +152,8 @@ static NTSTATUS smbcli_sock_connect_one(struct smbcli_socket *sock, this is the async send side of the interface */ struct composite_context *smbcli_sock_connect_send(struct smbcli_socket *sock, - const char *host_addr, int port) + const char *host_addr, int port, + const char *host_name) { struct composite_context *c; struct clisocket_connect *conn; @@ -184,8 +186,11 @@ struct composite_context *smbcli_sock_connect_send(struct smbcli_socket *sock, conn->iports[1] = 0; } - conn->dest_host = talloc_strdup(c, host_addr); - if (conn->dest_host == NULL) goto failed; + conn->dest_host_addr = talloc_strdup(c, host_addr); + if (conn->dest_host_addr == NULL) goto failed; + + conn->dest_hostname = talloc_strdup(c, host_name); + if (conn->dest_hostname == NULL) goto failed; c->private = conn; c->state = SMBCLI_REQUEST_SEND; @@ -196,7 +201,7 @@ struct composite_context *smbcli_sock_connect_send(struct smbcli_socket *sock, conn->port_num = i; conn->sock->port = conn->iports[i]; c->status = smbcli_sock_connect_one(sock, - conn->dest_host, + conn->dest_host_addr, conn->iports[i], c); if (NT_STATUS_IS_OK(c->status) || NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { @@ -229,11 +234,12 @@ NTSTATUS smbcli_sock_connect_recv(struct composite_context *c) sync version of the function */ -NTSTATUS smbcli_sock_connect(struct smbcli_socket *sock, const char *host_addr, int port) +NTSTATUS smbcli_sock_connect(struct smbcli_socket *sock, const char *host_addr, int port, + const char *host_name) { struct composite_context *c; - c = smbcli_sock_connect_send(sock, host_addr, port); + c = smbcli_sock_connect_send(sock, host_addr, port, host_name); if (c == NULL) { return NT_STATUS_NO_MEMORY; } @@ -337,9 +343,7 @@ BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, in return False; } - sock->hostname = name; - - status = smbcli_sock_connect(sock, address, port); + status = smbcli_sock_connect(sock, address, port, name); return NT_STATUS_IS_OK(status); } diff --git a/source4/libcli/raw/clitree.c b/source4/libcli/raw/clitree.c index f333cf7a98d..87c2dbba7c0 100644 --- a/source4/libcli/raw/clitree.c +++ b/source4/libcli/raw/clitree.c @@ -164,7 +164,6 @@ NTSTATUS smb_tree_disconnect(struct smbcli_tree *tree) */ NTSTATUS smbcli_tree_full_connection(TALLOC_CTX *parent_ctx, struct smbcli_tree **ret_tree, - const char *my_name, const char *dest_host, int port, const char *service, const char *service_type, struct cli_credentials *credentials) @@ -175,12 +174,10 @@ NTSTATUS smbcli_tree_full_connection(TALLOC_CTX *parent_ctx, io.in.dest_host = dest_host; io.in.port = port; io.in.called_name = strupper_talloc(parent_ctx, dest_host); - io.in.calling_name = strupper_talloc(parent_ctx, my_name); io.in.service = service; io.in.service_type = service_type; - io.in.domain = cli_credentials_get_domain(credentials); - io.in.user = cli_credentials_get_username(credentials); - io.in.password = cli_credentials_get_password(credentials); + io.in.credentials = credentials; + io.in.workgroup = lp_workgroup(); status = smb_composite_connect(&io, parent_ctx); if (NT_STATUS_IS_OK(status)) { diff --git a/source4/librpc/config.mk b/source4/librpc/config.mk index 70fafdaf3be..f6b05a41b51 100644 --- a/source4/librpc/config.mk +++ b/source4/librpc/config.mk @@ -20,9 +20,9 @@ INIT_OBJ_FILES = \ librpc/rpc/dcerpc.o ADD_OBJ_FILES = \ librpc/rpc/dcerpc_auth.o \ + librpc/rpc/dcerpc_schannel.o \ librpc/rpc/dcerpc_util.o \ librpc/rpc/dcerpc_error.o \ - librpc/rpc/dcerpc_schannel.o \ librpc/rpc/dcerpc_smb.o \ librpc/rpc/dcerpc_sock.o REQUIRED_SUBSYSTEMS = SOCKET diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c index c5bfe150bd2..ae0a89910ea 100644 --- a/source4/librpc/rpc/dcerpc_auth.c +++ b/source4/librpc/rpc/dcerpc_auth.c @@ -4,7 +4,7 @@ Generic Authentication Interface Copyright (C) Andrew Tridgell 2003 - Copyright (C) Andrew Bartlett 2004 + Copyright (C) Andrew Bartlett 2004-2005 Copyright (C) Stefan Metzmacher 2004 This program is free software; you can redistribute it and/or modify @@ -159,34 +159,10 @@ NTSTATUS dcerpc_bind_auth_password(struct dcerpc_pipe *p, return status; } - status = gensec_set_workstation(p->conn->security_state.generic_state, - cli_credentials_get_workstation(credentials)); + status = gensec_set_credentials(p->conn->security_state.generic_state, + credentials); if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client workstation name to %s: %s\n", - cli_credentials_get_workstation(credentials), nt_errstr(status))); - return status; - } - - status = gensec_set_domain(p->conn->security_state.generic_state, - cli_credentials_get_domain(credentials)); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n", - cli_credentials_get_domain(credentials), nt_errstr(status))); - return status; - } - - status = gensec_set_username(p->conn->security_state.generic_state, - cli_credentials_get_username(credentials)); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n", - cli_credentials_get_username(credentials), nt_errstr(status))); - return status; - } - - status = gensec_set_password(p->conn->security_state.generic_state, - cli_credentials_get_password(credentials)); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client password: %s\n", + DEBUG(1, ("Failed to start set GENSEC client credentails: %s\n", nt_errstr(status))); return status; } diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c index 77453cf4768..3ae2624ff9d 100644 --- a/source4/librpc/rpc/dcerpc_schannel.c +++ b/source4/librpc/rpc/dcerpc_schannel.c @@ -4,7 +4,8 @@ dcerpc schannel operations Copyright (C) Andrew Tridgell 2004 - + Copyright (C) Andrew Bartlett 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 @@ -24,281 +25,13 @@ #include "librpc/gen_ndr/ndr_schannel.h" #include "auth/auth.h" -enum schannel_position { - DCERPC_SCHANNEL_STATE_START = 0, - DCERPC_SCHANNEL_STATE_UPDATE_1 -}; - -struct dcerpc_schannel_state { - enum schannel_position state; - struct schannel_state *schannel_state; - struct creds_CredentialState *creds; -}; - -/* - wrappers for the schannel_*() functions - - These will become static again, when we get dynamic registration, and - decrpc_schannel_security_ops come back here. -*/ -static NTSTATUS dcerpc_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 dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; - - return schannel_unseal_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig); -} - -static NTSTATUS dcerpc_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 dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; - - return schannel_check_packet(dce_schan_state->schannel_state, data, length, sig); -} - -static NTSTATUS dcerpc_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 dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; - - return schannel_seal_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig); -} - -static NTSTATUS dcerpc_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 dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; - - return schannel_sign_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig); -} - -static size_t dcerpc_schannel_sig_size(struct gensec_security *gensec_security) -{ - return 32; -} - -static NTSTATUS dcerpc_schannel_session_key(struct gensec_security *gensec_security, - DATA_BLOB *session_key) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - -static NTSTATUS dcerpc_schannel_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; - NTSTATUS status; - struct schannel_bind bind_schannel; - struct schannel_bind_ack bind_schannel_ack; - const char *workstation; - const char *domain; - *out = data_blob(NULL, 0); - - switch (gensec_security->gensec_role) { - case GENSEC_CLIENT: - if (dce_schan_state->state != DCERPC_SCHANNEL_STATE_START) { - /* we could parse the bind ack, but we don't know what it is yet */ - return NT_STATUS_OK; - } - - status = schannel_start(dce_schan_state, - &dce_schan_state->schannel_state, - dce_schan_state->creds->session_key, - True); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start schannel client\n")); - return status; - } - talloc_steal(dce_schan_state, dce_schan_state->schannel_state); - - 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 = gensec_security->user.domain; - bind_schannel.u.info23.account_name = gensec_security->user.name; - 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, gensec_get_workstation(gensec_security)); -#else - bind_schannel.bind_type = 3; - bind_schannel.u.info3.domain = gensec_security->user.domain; - bind_schannel.u.info3.workstation = gensec_get_workstation(gensec_security); -#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; - } - - dce_schan_state->state = DCERPC_SCHANNEL_STATE_UPDATE_1; - - return NT_STATUS_MORE_PROCESSING_REQUIRED; - case GENSEC_SERVER: - - if (dce_schan_state->state != DCERPC_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, &dce_schan_state->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; - } - - /* start up the schannel server code */ - status = schannel_start(dce_schan_state, - &dce_schan_state->schannel_state, - dce_schan_state->creds->session_key, False); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("Could not initialise schannel state from client %s: %s\n", - workstation, nt_errstr(status))); - return status; - } - talloc_steal(dce_schan_state, dce_schan_state->schannel_state); - - 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; - } - - dce_schan_state->state = DCERPC_SCHANNEL_STATE_UPDATE_1; - - return NT_STATUS_OK; - } - return NT_STATUS_INVALID_PARAMETER; -} - -/** - * 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 dcerpc_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; -} - -/** - * 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 dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; - - *creds = talloc_reference(mem_ctx, dce_schan_state->creds); - if (!*creds) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - - -static NTSTATUS dcerpc_schannel_start(struct gensec_security *gensec_security) -{ - struct dcerpc_schannel_state *dce_schan_state; - - dce_schan_state = talloc(gensec_security, struct dcerpc_schannel_state); - if (!dce_schan_state) { - return NT_STATUS_NO_MEMORY; - } - - dce_schan_state->state = DCERPC_SCHANNEL_STATE_START; - gensec_security->private_data = dce_schan_state; - - return NT_STATUS_OK; -} - -static NTSTATUS dcerpc_schannel_server_start(struct gensec_security *gensec_security) -{ - NTSTATUS status; - - status = dcerpc_schannel_start(gensec_security); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - return NT_STATUS_OK; -} - -static NTSTATUS dcerpc_schannel_client_start(struct gensec_security *gensec_security) -{ - NTSTATUS status; - - status = dcerpc_schannel_start(gensec_security); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - return NT_STATUS_OK; -} - - /* get a schannel key using a netlogon challenge on a secondary pipe */ static NTSTATUS dcerpc_schannel_key(TALLOC_CTX *tmp_ctx, struct dcerpc_pipe *p, struct cli_credentials *credentials, - int chan_type, - struct creds_CredentialState *creds) + int chan_type) { NTSTATUS status; struct dcerpc_binding *b; @@ -307,8 +40,12 @@ static NTSTATUS dcerpc_schannel_key(TALLOC_CTX *tmp_ctx, struct netr_ServerAuthenticate2 a; struct netr_Credential credentials1, credentials2, credentials3; struct samr_Password mach_pwd; - const char *workgroup; uint32_t negotiate_flags; + struct creds_CredentialState *creds; + creds = talloc(tmp_ctx, struct creds_CredentialState); + if (!creds) { + return NT_STATUS_NO_MEMORY; + } if (p->conn->flags & DCERPC_SCHANNEL_128) { negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; @@ -316,8 +53,6 @@ static NTSTATUS dcerpc_schannel_key(TALLOC_CTX *tmp_ctx, negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS; } - workgroup = cli_credentials_get_domain(credentials); - /* step 1 - establish a netlogon connection, with no authentication */ @@ -369,9 +104,6 @@ static NTSTATUS dcerpc_schannel_key(TALLOC_CTX *tmp_ctx, */ E_md4hash(cli_credentials_get_password(credentials), mach_pwd.hash); creds_client_init(creds, &credentials1, &credentials2, - cli_credentials_get_workstation(credentials), - cli_credentials_get_domain(credentials), - cli_credentials_get_username(credentials), &mach_pwd, &credentials3, negotiate_flags); @@ -393,6 +125,8 @@ static NTSTATUS dcerpc_schannel_key(TALLOC_CTX *tmp_ctx, return NT_STATUS_UNSUCCESSFUL; } + cli_credentials_set_netlogon_creds(credentials, creds); + /* the schannel session key is now in creds.session_key @@ -403,76 +137,6 @@ static NTSTATUS dcerpc_schannel_key(TALLOC_CTX *tmp_ctx, return NT_STATUS_OK; } -/* - do a schannel style bind on a dcerpc pipe. The username is usually - of the form HOSTNAME$ and the password is the domain trust password -*/ -NTSTATUS dcerpc_bind_auth_schannel_withkey(struct dcerpc_pipe *p, - const char *uuid, uint_t version, - struct creds_CredentialState *creds) -{ - NTSTATUS status; - struct dcerpc_schannel_state *dce_schan_state; - - status = gensec_client_start(p, &p->conn->security_state.generic_state); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = gensec_set_workstation(p->conn->security_state.generic_state, creds->computer_name); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to set schannel workstation to %s: %s\n", - creds->computer_name, nt_errstr(status))); - talloc_free(p->conn->security_state.generic_state); - p->conn->security_state.generic_state = NULL; - return status; - } - - status = gensec_set_username(p->conn->security_state.generic_state, creds->account_name); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to set schannel username to %s: %s\n", - creds->account_name, nt_errstr(status))); - talloc_free(p->conn->security_state.generic_state); - p->conn->security_state.generic_state = NULL; - return status; - } - - status = gensec_set_domain(p->conn->security_state.generic_state, creds->domain); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to set schannel domain to %s: %s\n", - creds->domain, nt_errstr(status))); - talloc_free(p->conn->security_state.generic_state); - p->conn->security_state.generic_state = NULL; - return status; - } - - status = gensec_start_mech_by_authtype(p->conn->security_state.generic_state, - DCERPC_AUTH_TYPE_SCHANNEL, - dcerpc_auth_level(p->conn)); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start SCHANNEL GENSEC backend: %s\n", nt_errstr(status))); - talloc_free(p->conn->security_state.generic_state); - p->conn->security_state.generic_state = NULL; - return status; - } - - dce_schan_state = p->conn->security_state.generic_state->private_data; - dce_schan_state->creds = talloc_reference(dce_schan_state, creds); - - status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_SCHANNEL, dcerpc_auth_level(p->conn), - uuid, version); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to bind to pipe with SCHANNEL: %s\n", nt_errstr(status))); - talloc_free(p->conn->security_state.generic_state); - p->conn->security_state.generic_state = NULL; - return status; - } - - return NT_STATUS_OK; -} - NTSTATUS dcerpc_bind_auth_schannel(TALLOC_CTX *tmp_ctx, struct dcerpc_pipe *p, const char *uuid, uint_t version, @@ -480,11 +144,6 @@ NTSTATUS dcerpc_bind_auth_schannel(TALLOC_CTX *tmp_ctx, { NTSTATUS status; int chan_type = 0; - struct creds_CredentialState *creds; - creds = talloc(tmp_ctx, struct creds_CredentialState); - if (!creds) { - return NT_STATUS_NO_MEMORY; - } if (p->conn->flags & DCERPC_SCHANNEL_BDC) { chan_type = SEC_CHAN_BDC; @@ -494,58 +153,20 @@ NTSTATUS dcerpc_bind_auth_schannel(TALLOC_CTX *tmp_ctx, chan_type = SEC_CHAN_DOMAIN; } + /* Fills in NETLOGON credentials */ status = dcerpc_schannel_key(tmp_ctx, p, credentials, - chan_type, - creds); + chan_type); if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to fetch schannel session key: %s\n", + DEBUG(1, ("Failed to setup credentials for account %s: %s\n", + cli_credentials_get_username(credentials), nt_errstr(status))); return status; } - return dcerpc_bind_auth_schannel_withkey(p, uuid, version, creds); + return dcerpc_bind_auth_password(p, uuid, version, + credentials, DCERPC_AUTH_TYPE_SCHANNEL, + NULL); } -static BOOL dcerpc_schannel_have_feature(struct gensec_security *gensec_security, - uint32_t feature) -{ - if (feature & (GENSEC_FEATURE_SESSION_KEY | - GENSEC_FEATURE_SIGN | - GENSEC_FEATURE_SEAL)) { - return True; - } - return False; -} - - -static const struct gensec_security_ops gensec_dcerpc_schannel_security_ops = { - .name = "dcerpc_schannel", - .auth_type = DCERPC_AUTH_TYPE_SCHANNEL, - .client_start = dcerpc_schannel_client_start, - .server_start = dcerpc_schannel_server_start, - .update = dcerpc_schannel_update, - .seal_packet = dcerpc_schannel_seal_packet, - .sign_packet = dcerpc_schannel_sign_packet, - .check_packet = dcerpc_schannel_check_packet, - .unseal_packet = dcerpc_schannel_unseal_packet, - .session_key = dcerpc_schannel_session_key, - .session_info = dcerpc_schannel_session_info, - .sig_size = dcerpc_schannel_sig_size, - .have_feature = dcerpc_schannel_have_feature, - .enabled = True -}; - -NTSTATUS gensec_dcerpc_schannel_init(void) -{ - NTSTATUS ret; - ret = gensec_register(&gensec_dcerpc_schannel_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_dcerpc_schannel_security_ops.name)); - return ret; - } - - return ret; -} diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index 88b1c54cefd..ffefd5111ca 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -5,6 +5,7 @@ Copyright (C) Andrew Tridgell 2003 Copyright (C) Jelmer Vernooij 2004 + Copyright (C) Andrew Bartlett 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 @@ -926,7 +927,12 @@ NTSTATUS dcerpc_pipe_auth(struct dcerpc_pipe *p, p->conn->binding_string = dcerpc_binding_string(p, binding); if (!cli_credentials_is_anonymous(credentials) && - (binding->flags & DCERPC_SCHANNEL_ANY)) { + (binding->flags & DCERPC_SCHANNEL_ANY) && + !cli_credentials_get_netlogon_creds(credentials)) { + + /* If we don't already have netlogon credentials for + * the schannel bind, then we have to get these + * first */ status = dcerpc_bind_auth_schannel(tmp_ctx, p, pipe_uuid, pipe_version, credentials); @@ -936,6 +942,8 @@ NTSTATUS dcerpc_pipe_auth(struct dcerpc_pipe *p, auth_type = DCERPC_AUTH_TYPE_SPNEGO; } else if (binding->flags & DCERPC_AUTH_KRB5) { auth_type = DCERPC_AUTH_TYPE_KRB5; + } else if (binding->flags & DCERPC_SCHANNEL_ANY) { + auth_type = DCERPC_AUTH_TYPE_SCHANNEL; } else { auth_type = DCERPC_AUTH_TYPE_NTLMSSP; } @@ -974,13 +982,11 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(TALLOC_CTX *tmp_ctx, cli_credentials_set_anonymous(anon_creds); cli_credentials_guess(anon_creds); status = smbcli_full_connection(p->conn, &cli, - cli_credentials_get_workstation(credentials), binding->host, "IPC$", NULL, anon_creds); } else { status = smbcli_full_connection(p->conn, &cli, - cli_credentials_get_workstation(credentials), binding->host, "IPC$", NULL, credentials); diff --git a/source4/ntvfs/cifs/vfs_cifs.c b/source4/ntvfs/cifs/vfs_cifs.c index 0bb47bab2aa..e283e12f247 100644 --- a/source4/ntvfs/cifs/vfs_cifs.c +++ b/source4/ntvfs/cifs/vfs_cifs.c @@ -90,6 +90,8 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, struct composite_context *creq; struct fd_event *fde; + struct cli_credentials *credentials; + /* Here we need to determine which server to connect to. * For now we use parametric options, type cifs. * Later we will use security=server and auth_server.c. @@ -116,16 +118,20 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, ntvfs->private_data = private; + credentials = cli_credentials_init(private); + cli_credentials_set_username(credentials, user, CRED_SPECIFIED); + cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED); + cli_credentials_set_password(credentials, pass, CRED_SPECIFIED); + cli_credentials_set_workstation(credentials, "vfs_cifs", CRED_SPECIFIED); + /* connect to the server, using the smbd event context */ io.in.dest_host = host; io.in.port = 0; io.in.called_name = host; - io.in.calling_name = "vfs_cifs"; + io.in.credentials = credentials; + io.in.workgroup = lp_workgroup(); io.in.service = remote_share; io.in.service_type = "?????"; - io.in.domain = domain; - io.in.user = user; - io.in.password = pass; creq = smb_composite_connect_send(&io, tcon->smb_conn->connection->event.ctx); status = smb_composite_connect_recv(creq, private); diff --git a/source4/smb_server/reply.c b/source4/smb_server/reply.c index 17dcb8623a9..9c8478d6d31 100644 --- a/source4/smb_server/reply.c +++ b/source4/smb_server/reply.c @@ -2106,9 +2106,9 @@ static void reply_sesssetup_spnego(struct smbsrv_request *req) } p += blob_len; - p += req_pull_string(req, &sess.spnego.in.os, p, -1, STR_TERMINATE); - p += req_pull_string(req, &sess.spnego.in.lanman, p, -1, STR_TERMINATE); - p += req_pull_string(req, &sess.spnego.in.domain, p, -1, STR_TERMINATE); + p += req_pull_string(req, &sess.spnego.in.os, p, -1, STR_TERMINATE); + p += req_pull_string(req, &sess.spnego.in.lanman, p, -1, STR_TERMINATE); + p += req_pull_string(req, &sess.spnego.in.workgroup, p, -1, STR_TERMINATE); /* call the generic handler */ status = sesssetup_backend(req, &sess); @@ -2134,9 +2134,9 @@ static void reply_sesssetup_spnego(struct smbsrv_request *req) SSVAL(req->out.hdr, HDR_UID, sess.spnego.out.vuid); memcpy(req->out.data, sess.spnego.out.secblob.data, sess.spnego.out.secblob.length); - req_push_str(req, NULL, sess.spnego.out.os, -1, STR_TERMINATE); - req_push_str(req, NULL, sess.spnego.out.lanman, -1, STR_TERMINATE); - req_push_str(req, NULL, sess.spnego.out.domain, -1, STR_TERMINATE); + req_push_str(req, NULL, sess.spnego.out.os, -1, STR_TERMINATE); + req_push_str(req, NULL, sess.spnego.out.lanman, -1, STR_TERMINATE); + req_push_str(req, NULL, sess.spnego.out.workgroup, -1, STR_TERMINATE); chain_reply(req); } diff --git a/source4/smb_server/sesssetup.c b/source4/smb_server/sesssetup.c index dc3a60874a0..0f0dcb837e5 100644 --- a/source4/smb_server/sesssetup.c +++ b/source4/smb_server/sesssetup.c @@ -296,7 +296,7 @@ static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup sesssetup_common_strings(req, &sess->spnego.out.os, &sess->spnego.out.lanman, - &sess->spnego.out.domain); + &sess->spnego.out.workgroup); return status; } diff --git a/source4/torture/basic/secleak.c b/source4/torture/basic/secleak.c index 31c23ff5f7d..50d5c40d078 100644 --- a/source4/torture/basic/secleak.c +++ b/source4/torture/basic/secleak.c @@ -34,9 +34,13 @@ static BOOL try_failed_login(struct smbcli_state *cli) session = smbcli_session_init(cli->transport, cli, False); setup.in.sesskey = cli->transport->negotiate.sesskey; setup.in.capabilities = cli->transport->negotiate.capabilities; - setup.in.password = "INVALID-PASSWORD"; - setup.in.user = "INVALID-USERNAME"; - setup.in.domain = "INVALID-DOMAIN"; + setup.in.workgroup = lp_workgroup(); + + setup.in.credentials = cli_credentials_init(NULL); + cli_credentials_set_conf(setup.in.credentials); + cli_credentials_set_domain(setup.in.credentials, "INVALID-DOMAIN", CRED_SPECIFIED); + cli_credentials_set_username(setup.in.credentials, "INVALID-USERNAME", CRED_SPECIFIED); + cli_credentials_set_password(setup.in.credentials, "INVALID-PASSWORD", CRED_SPECIFIED); status = smb_composite_sesssetup(session, &setup); talloc_free(session); diff --git a/source4/torture/gentest.c b/source4/torture/gentest.c index 5f036910b60..3e13bf12c05 100644 --- a/source4/torture/gentest.c +++ b/source4/torture/gentest.c @@ -177,8 +177,10 @@ static BOOL connect_servers(void) servers[i].server_name, servers[i].share_name, servers[i].credentials->username, j); + cli_credentials_set_workstation(servers[i].credentials, + "gentest", CRED_SPECIFIED); + status = smbcli_full_connection(NULL, &servers[i].cli[j], - "gentest", servers[i].server_name, servers[i].share_name, NULL, servers[i].credentials); diff --git a/source4/torture/ldap/basic.c b/source4/torture/ldap/basic.c index d0255abe01d..b53515fdbc6 100644 --- a/source4/torture/ldap/basic.c +++ b/source4/torture/ldap/basic.c @@ -38,14 +38,14 @@ BOOL test_bind_simple(struct ldap_connection *conn, const char *userdn, const ch return ret; } -BOOL test_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password) +BOOL test_bind_sasl(struct ldap_connection *conn, struct cli_credentials *creds) { NTSTATUS status; BOOL ret = True; printf("Testing sasl bind as user\n"); - status = torture_ldap_bind_sasl(conn, username, domain, password); + status = torture_ldap_bind_sasl(conn, creds); if (!NT_STATUS_IS_OK(status)) { ret = False; } @@ -189,9 +189,6 @@ BOOL torture_ldap_basic(void) TALLOC_CTX *mem_ctx; BOOL ret = True; const char *host = lp_parm_string(-1, "torture", "host"); - const char *username = cli_credentials_get_username(cmdline_credentials); - const char *domain = cli_credentials_get_domain(cmdline_credentials); - const char *password = cli_credentials_get_password(cmdline_credentials); const char *userdn = lp_parm_string(-1, "torture", "ldap_userdn"); /*const char *basedn = lp_parm_string(-1, "torture", "ldap_basedn");*/ const char *secret = lp_parm_string(-1, "torture", "ldap_secret"); @@ -217,7 +214,7 @@ BOOL torture_ldap_basic(void) ret = False; } - if (!test_bind_sasl(conn, username, domain, password)) { + if (!test_bind_sasl(conn, cmdline_credentials)) { ret = False; } diff --git a/source4/torture/ldap/common.c b/source4/torture/ldap/common.c index f421565cbd9..9dbe2557eba 100644 --- a/source4/torture/ldap/common.c +++ b/source4/torture/ldap/common.c @@ -46,7 +46,8 @@ NTSTATUS torture_ldap_bind(struct ldap_connection *conn, const char *userdn, con return NT_STATUS_OK; } -NTSTATUS torture_ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password) +NTSTATUS torture_ldap_bind_sasl(struct ldap_connection *conn, + struct cli_credentials *creds) { NTSTATUS status = NT_STATUS_UNSUCCESSFUL; int result; @@ -56,7 +57,7 @@ NTSTATUS torture_ldap_bind_sasl(struct ldap_connection *conn, const char *userna return status; } - result = ldap_bind_sasl(conn, username, domain, password); + result = ldap_bind_sasl(conn, creds); if (result != LDAP_SUCCESS) { printf("Failed to bind with provided credentials and SASL mechanism\n"); /* FIXME: what abut actually implementing an ldap_connection_free() function ? diff --git a/source4/torture/locktest.c b/source4/torture/locktest.c index 4051f9c4114..fe5dfe51787 100644 --- a/source4/torture/locktest.c +++ b/source4/torture/locktest.c @@ -116,9 +116,10 @@ static struct smbcli_state *connect_one(char *share, int snum) share++; slprintf(myname,sizeof(myname), "lock-%u-%u", getpid(), snum); + cli_credentials_set_workstation(servers[snum], myname, CRED_SPECIFIED); do { - status = smbcli_full_connection(NULL, &c, myname, + status = smbcli_full_connection(NULL, &c, server, share, NULL, servers[snum]); diff --git a/source4/torture/masktest.c b/source4/torture/masktest.c index d760934334b..21e22e91d8b 100644 --- a/source4/torture/masktest.c +++ b/source4/torture/masktest.c @@ -77,7 +77,9 @@ static struct smbcli_state *connect_one(char *share) *share = 0; share++; - status = smbcli_full_connection(NULL, &c, "masktest", + cli_credentials_set_workstation(credentials, "masktest", CRED_SPECIFIED); + + status = smbcli_full_connection(NULL, &c, server, share, NULL, credentials); diff --git a/source4/torture/raw/composite.c b/source4/torture/raw/composite.c index b9c7609b5fd..f836e1eb4b8 100644 --- a/source4/torture/raw/composite.c +++ b/source4/torture/raw/composite.c @@ -147,13 +147,11 @@ static BOOL test_fetchfile(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) io2.in.dest_host = lp_parm_string(-1, "torture", "host"); io2.in.port = 0; io2.in.called_name = lp_parm_string(-1, "torture", "host"); - io2.in.calling_name = lp_netbios_name(); io2.in.service = lp_parm_string(-1, "torture", "share"); io2.in.service_type = "A:"; - io2.in.user = cli_credentials_get_username(cmdline_credentials); - io2.in.domain = cli_credentials_get_domain(cmdline_credentials); - io2.in.password = cli_credentials_get_password(cmdline_credentials); + io2.in.credentials = cmdline_credentials; + io2.in.workgroup = lp_workgroup(); io2.in.filename = fname; printf("testing parallel fetchfile with %d ops\n", torture_numops); diff --git a/source4/torture/raw/context.c b/source4/torture/raw/context.c index 3eb848eebd8..a610eaa79ea 100644 --- a/source4/torture/raw/context.c +++ b/source4/torture/raw/context.c @@ -81,9 +81,9 @@ static BOOL test_session(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) setup.in.sesskey = cli->transport->negotiate.sesskey; setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */ - setup.in.password = cli_credentials_get_password(cmdline_credentials); - setup.in.user = cli_credentials_get_username(cmdline_credentials); - setup.in.domain = cli_credentials_get_domain(cmdline_credentials); + setup.in.workgroup = lp_workgroup(); + + setup.in.credentials = cmdline_credentials; status = smb_composite_sesssetup(session, &setup); CHECK_STATUS(status, NT_STATUS_OK); @@ -96,10 +96,9 @@ static BOOL test_session(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) session2->vuid = session->vuid; setup.in.sesskey = cli->transport->negotiate.sesskey; setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */ + setup.in.workgroup = lp_workgroup(); - setup.in.password = cli_credentials_get_password(cmdline_credentials); - setup.in.user = cli_credentials_get_username(cmdline_credentials); - setup.in.domain = cli_credentials_get_domain(cmdline_credentials); + setup.in.credentials = cmdline_credentials; status = smb_composite_sesssetup(session2, &setup); CHECK_STATUS(status, NT_STATUS_OK); @@ -117,11 +116,10 @@ static BOOL test_session(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) session3->vuid = session->vuid; setup.in.sesskey = cli->transport->negotiate.sesskey; setup.in.capabilities = 0; /* force a non extended security login (should fail) */ - - - setup.in.password = cli_credentials_get_password(cmdline_credentials); - setup.in.user = cli_credentials_get_username(cmdline_credentials); - setup.in.domain = cli_credentials_get_domain(cmdline_credentials); + setup.in.workgroup = lp_workgroup(); + + setup.in.credentials = cmdline_credentials; + status = smb_composite_sesssetup(session3, &setup); CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index d9ce350428b..c12560ad531 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -116,9 +116,6 @@ BOOL test_SetupCredentials(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, a.out.credentials = &credentials3; creds_client_init(creds, &credentials1, &credentials2, - machine_name, - lp_workgroup(), - a.in.account_name, &mach_password, &credentials3, 0); @@ -185,9 +182,6 @@ BOOL test_SetupCredentials2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, a.out.credentials = &credentials3; creds_client_init(creds, &credentials1, &credentials2, - machine_name, - lp_workgroup(), - a.in.account_name, &mach_password, &credentials3, negotiate_flags); @@ -258,9 +252,6 @@ BOOL test_SetupCredentials3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, a.out.rid = &rid; creds_client_init(creds, &credentials1, &credentials2, - machine_name, - lp_workgroup(), - a.in.account_name, &mach_password, &credentials3, negotiate_flags); diff --git a/source4/torture/rpc/schannel.c b/source4/torture/rpc/schannel.c index d60a8bb60b7..7bc184f42eb 100644 --- a/source4/torture/rpc/schannel.c +++ b/source4/torture/rpc/schannel.c @@ -194,10 +194,11 @@ static BOOL test_schannel(TALLOC_CTX *mem_ctx, goto failed; } - status = dcerpc_bind_auth_schannel_withkey(p_netlogon, - DCERPC_NETLOGON_UUID, - DCERPC_NETLOGON_VERSION, - creds); + status = dcerpc_bind_auth_password(p_netlogon, + DCERPC_NETLOGON_UUID, + DCERPC_NETLOGON_VERSION, + credentials, DCERPC_AUTH_TYPE_SCHANNEL, + NULL); if (!NT_STATUS_IS_OK(status)) { goto failed; diff --git a/source4/torture/rpc/xplogin.c b/source4/torture/rpc/xplogin.c index cf42f938c1d..f55f6684bc0 100644 --- a/source4/torture/rpc/xplogin.c +++ b/source4/torture/rpc/xplogin.c @@ -118,11 +118,11 @@ static NTSTATUS anon_ipc(struct smbcli_transport *transport, /* prepare a session setup to establish a security context */ setup.in.sesskey = transport->negotiate.sesskey; setup.in.capabilities = transport->negotiate.capabilities; - setup.in.password = NULL; - setup.in.user = ""; - setup.in.domain = ""; setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; + setup.in.credentials = cli_credentials_init(mem_ctx); + cli_credentials_set_anonymous(setup.in.credentials); + status = smb_composite_sesssetup(session, &setup); if (!NT_STATUS_IS_OK(status)) { talloc_free(session); @@ -479,9 +479,6 @@ static NTSTATUS setup_netlogon_creds(struct smbcli_transport *transport, a.out.credentials = &credentials3; creds_client_init(creds, &credentials1, &credentials2, - machine_name, - domain, - a.in.account_name, &mach_password, &credentials3, negotiate_flags); @@ -978,6 +975,7 @@ static NTSTATUS test_remoteTOD(struct smbcli_transport *transport) return status; } +#if 0 static BOOL xp_login(const char *dcname, const char *wksname, const char *domain, const char *wkspwd, const char *user1name, const char *user1pw, @@ -1033,10 +1031,10 @@ static BOOL xp_login(const char *dcname, const char *wksname, netlogon_schannel_pipe->conn->flags |= DCERPC_SEAL; - status = dcerpc_bind_auth_schannel_withkey(netlogon_schannel_pipe, - DCERPC_NETLOGON_UUID, - DCERPC_NETLOGON_VERSION, - netlogon_creds); + status = dcerpc_bind_auth_password(netlogon_schannel_pipe, + DCERPC_NETLOGON_UUID, + DCERPC_NETLOGON_VERSION, + creds, NULL); if (!NT_STATUS_IS_OK(status)) return False; @@ -1096,6 +1094,8 @@ static BOOL xp_login(const char *dcname, const char *wksname, return True; } +#endif + struct user_pw { const char *username; const char *password; @@ -1124,10 +1124,13 @@ BOOL torture_rpc_login(void) users[useridx1].username, users[useridx2].username); +#if 0 return xp_login(pdcname, machines[machidx].username, domainname, machines[machidx].password, users[useridx1].username, users[useridx1].password, users[useridx2].username, users[useridx2].password); +#endif + return False; } diff --git a/source4/torture/torture.c b/source4/torture/torture.c index 4fca36a9aee..eb4dd0b84ad 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -82,8 +82,7 @@ BOOL torture_open_connection_share(struct smbcli_state **c, NTSTATUS status; status = smbcli_full_connection(NULL, - c, lp_netbios_name(), - hostname, + c, hostname, sharename, NULL, cmdline_credentials); if (!NT_STATUS_IS_OK(status)) { @@ -725,8 +724,7 @@ static BOOL run_tcon_devtype_test(void) const char *share = lp_parm_string(-1, "torture", "share"); status = smbcli_full_connection(NULL, - &cli1, lp_netbios_name(), - host, + &cli1, host, share, NULL, cmdline_credentials); diff --git a/source4/utils/ntlm_auth.c b/source4/utils/ntlm_auth.c index 81c7f90c9b9..3bc479e0613 100644 --- a/source4/utils/ntlm_auth.c +++ b/source4/utils/ntlm_auth.c @@ -52,22 +52,22 @@ enum stdio_helper_mode { typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode, char *buf, int length, void **private, - unsigned int mux_id); + unsigned int mux_id, void **private2); static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode, char *buf, int length, void **private, - unsigned int mux_id); + unsigned int mux_id, void **private2); static void manage_gensec_request (enum stdio_helper_mode stdio_helper_mode, char *buf, int length, void **private, - unsigned int mux_id); + unsigned int mux_id, void **private2); static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode, char *buf, int length, void **private, - unsigned int mux_id); + unsigned int mux_id, void **private2); static void manage_squid_request(enum stdio_helper_mode helper_mode, - stdio_helper_function fn); + stdio_helper_function fn, void **private2); static const struct { enum stdio_helper_mode mode; @@ -203,7 +203,7 @@ static NTSTATUS local_pw_check_specified(const char *username, static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, char *buf, int length, void **private, - unsigned int mux_id) + unsigned int mux_id, void **private2) { char *user, *pass; user=buf; @@ -234,10 +234,9 @@ static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode, char *buf, int length, void **private, - unsigned int mux_id) + unsigned int mux_id, void **password) { DATA_BLOB in; - struct gensec_security **gensec_state = (struct gensec_security **)private; if (strlen(buf) < 2) { DEBUG(1, ("query [%s] invalid", buf)); mux_printf(mux_id, "BH\n"); @@ -252,10 +251,10 @@ static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mod if (strncmp(buf, "PW ", 3) == 0) { - (*gensec_state)->password_callback_private = talloc_strndup((*gensec_state), - (const char *)in.data, in.length); + *password = talloc_strndup(*private /* hopefully the right gensec context, useful to use for talloc */, + (const char *)in.data, in.length); - if ((*gensec_state)->password_callback_private == NULL) { + if (*password == NULL) { DEBUG(1, ("Out of memory\n")); mux_printf(mux_id, "BH\n"); data_blob_free(&in); @@ -271,33 +270,27 @@ static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mod data_blob_free(&in); } -/* - * Callback for gensec, to ask the calling application for a password. Uses the above function - * for the stdio part of this. +/** + * Callback for password credentails. This is not async, and when + * GENSEC and the credentails code is made async, it will look rather + * different. */ -static NTSTATUS get_password(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - char **password) +static const char *get_password(struct cli_credentials *credentials) { - *password = NULL; + char *password = NULL; /* Ask for a password */ - mux_printf((unsigned int)gensec_security->password_callback_private, "PW\n"); - gensec_security->password_callback_private = NULL; + mux_printf((unsigned int)credentials->priv_data, "PW\n"); + credentials->priv_data = NULL; - manage_squid_request(NUM_HELPER_MODES /* bogus */, manage_gensec_get_pw_request); - *password = (char *)gensec_security->password_callback_private; - if (*password) { - return NT_STATUS_OK; - } else { - return NT_STATUS_INVALID_PARAMETER; - } + manage_squid_request(NUM_HELPER_MODES /* bogus */, manage_gensec_get_pw_request, (void **)&password); + return password; } static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, char *buf, int length, void **private, - unsigned int mux_id) + unsigned int mux_id, void **private2) { DATA_BLOB in; DATA_BLOB out = data_blob(NULL, 0); @@ -307,6 +300,7 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, NTSTATUS nt_status; BOOL first = False; const char *reply_code; + struct cli_credentials *creds; if (strlen(buf) < 2) { DEBUG(1, ("query [%s] invalid", buf)); @@ -351,19 +345,25 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, if (!NT_STATUS_IS_OK(gensec_client_start(NULL, gensec_state))) { exit(1); } - gensec_set_username(*gensec_state, opt_username); - gensec_set_domain(*gensec_state, opt_domain); - if (opt_password) { - if (!NT_STATUS_IS_OK(gensec_set_password(*gensec_state, opt_password))) { - DEBUG(1, ("Out of memory\n")); - mux_printf(mux_id, "BH\n"); - data_blob_free(&in); - return; - } - } else { - gensec_set_password_callback(*gensec_state, get_password, (void*)mux_id); + + creds = cli_credentials_init(*gensec_state); + cli_credentials_set_conf(creds); + if (opt_username) { + cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED); + } + if (opt_domain) { + cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED); } - + if (opt_password) { + cli_credentials_set_password(creds, opt_password, CRED_SPECIFIED); + } else { + creds->password_obtained = CRED_CALLBACK; + creds->password_cb = get_password; + creds->priv_data = (void*)mux_id; + } + + gensec_set_credentials(*gensec_state, creds); + break; case GSS_SPNEGO_SERVER: case SQUID_2_5_NTLMSSP: @@ -395,7 +395,7 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, } if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("SPNEGO login failed to initialise: %s\n", nt_errstr(nt_status))); + DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status))); mux_printf(mux_id, "BH\n"); return; } @@ -403,16 +403,11 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, if (strncmp(buf, "PW ", 3) == 0) { - if (!NT_STATUS_IS_OK(gensec_set_password(*gensec_state, - talloc_strndup((*gensec_state), - (const char *)in.data, - in.length)))) { - DEBUG(1, ("gensec_set_password failed: %s\n", nt_errstr(nt_status))); - mux_printf(mux_id, "BH %s\n", nt_errstr(nt_status)); - data_blob_free(&in); - return; - } - + cli_credentials_set_password((*gensec_state)->credentials, + talloc_strndup((*gensec_state), + (const char *)in.data, + in.length), + CRED_SPECIFIED); mux_printf(mux_id, "OK\n"); data_blob_free(&in); return; @@ -528,7 +523,7 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode, char *buf, int length, void **private, - unsigned int mux_id) + unsigned int mux_id, void **private2) { char *request, *parameter; static DATA_BLOB challenge; @@ -723,7 +718,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod } static void manage_squid_request(enum stdio_helper_mode helper_mode, - stdio_helper_function fn) + stdio_helper_function fn, void **private2) { char buf[SQUID_BUFFER_SIZE+1]; unsigned int mux_id; @@ -785,7 +780,12 @@ static void manage_squid_request(enum stdio_helper_mode helper_mode, mux_private->private_pointers = NULL; } - c=memchr(buf,' ',sizeof(buf)-1); + c=strchr(buf,' '); + if (!c) { + DEBUG(0, ("Invalid Request - no data after multiplex id\n")); + x_fprintf(x_stdout, "ERR\n"); + return; + } c++; if (mux_id >= mux_private->max_mux) { unsigned int prev_max = mux_private->max_mux; @@ -804,7 +804,7 @@ static void manage_squid_request(enum stdio_helper_mode helper_mode, private = &normal_private; } - fn(helper_mode, c, length, private, mux_id); + fn(helper_mode, c, length, private, mux_id, private2); } static void squid_stream(enum stdio_helper_mode stdio_mode, @@ -813,7 +813,7 @@ static void squid_stream(enum stdio_helper_mode stdio_mode, x_setbuf(x_stdout, NULL); x_setbuf(x_stderr, NULL); while(1) { - manage_squid_request(stdio_mode, fn); + manage_squid_request(stdio_mode, fn, NULL); } }