diff options
321 files changed, 17822 insertions, 7115 deletions
@@ -25,7 +25,7 @@ ######################################################## SAMBA_VERSION_MAJOR=4 SAMBA_VERSION_MINOR=2 -SAMBA_VERSION_RELEASE=10 +SAMBA_VERSION_RELEASE=11 ######################################################## # If a official release has a serious bug # diff --git a/WHATSNEW.txt b/WHATSNEW.txt index f03be3afc4b..ecb5fe6e2c3 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,3 +1,580 @@ + ============================== + Release Notes for Samba 4.2.11 + April 12, 2016 + ============================== + +This is a security release containing one additional +regression fix for the security release 4.2.10. + +This fixes a regression that prevents things like 'net ads join' +from working against a Windows 2003 domain. + +Changes since 4.2.10: +===================== + +o Stefan Metzmacher <metze@samba.org> + * Bug 11804 - prerequisite backports for the security release on + April 12th, 2016 + +Release notes for the original 4.2.10 release follows: +------------------------------------------------------ + + ============================== + Release Notes for Samba 4.2.10 + April 12, 2016 + ============================== + + +This is a security release in order to address the following CVEs: + +o CVE-2015-5370 (Multiple errors in DCE-RPC code) + +o CVE-2016-2110 (Man in the middle attacks possible with NTLMSSP) + +o CVE-2016-2111 (NETLOGON Spoofing Vulnerability) + +o CVE-2016-2112 (LDAP client and server don't enforce integrity) + +o CVE-2016-2113 (Missing TLS certificate validation) + +o CVE-2016-2114 ("server signing = mandatory" not enforced) + +o CVE-2016-2115 (SMB IPC traffic is not integrity protected) + +o CVE-2016-2118 (SAMR and LSA man in the middle attacks possible) + +The number of changes are rather huge for a security release, +compared to typical security releases. + +Given the number of problems and the fact that they are all related +to man in the middle attacks we decided to fix them all at once +instead of splitting them. + +In order to prevent the man in the middle attacks it was required +to change the (default) behavior for some protocols. Please see the +"New smb.conf options" and "Behavior changes" sections below. + +======= +Details +======= + +o CVE-2015-5370 + + Versions of Samba from 3.6.0 to 4.4.0 inclusive are vulnerable to + denial of service attacks (crashes and high cpu consumption) + in the DCE-RPC client and server implementations. In addition, + errors in validation of the DCE-RPC packets can lead to a downgrade + of a secure connection to an insecure one. + + While we think it is unlikely, there's a nonzero chance for + a remote code execution attack against the client components, + which are used by smbd, winbindd and tools like net, rpcclient and + others. This may gain root access to the attacker. + + The above applies all possible server roles Samba can operate in. + + Note that versions before 3.6.0 had completely different marshalling + functions for the generic DCE-RPC layer. It's quite possible that + that code has similar problems! + + The downgrade of a secure connection to an insecure one may + allow an attacker to take control of Active Directory object + handles created on a connection created from an Administrator + account and re-use them on the now non-privileged connection, + compromising the security of the Samba AD-DC. + +o CVE-2016-2110: + + There are several man in the middle attacks possible with + NTLMSSP authentication. + + E.g. NTLMSSP_NEGOTIATE_SIGN and NTLMSSP_NEGOTIATE_SEAL + can be cleared by a man in the middle. + + This was by protocol design in earlier Windows versions. + + Windows Server 2003 RTM and Vista RTM introduced a way + to protect against the trivial downgrade. + + See MsvAvFlags and flag 0x00000002 in + https://msdn.microsoft.com/en-us/library/cc236646.aspx + + This new feature also implies support for a mechlistMIC + when used within SPNEGO, which may prevent downgrades + from other SPNEGO mechs, e.g. Kerberos, if sign or + seal is finally negotiated. + + The Samba implementation doesn't enforce the existence of + required flags, which were requested by the application layer, + e.g. LDAP or SMB1 encryption (via the unix extensions). + As a result a man in the middle can take over the connection. + It is also possible to misguide client and/or + server to send unencrypted traffic even if encryption + was explicitly requested. + + LDAP (with NTLMSSP authentication) is used as a client + by various admin tools of the Samba project, + e.g. "net", "samba-tool", "ldbsearch", "ldbedit", ... + + As an active directory member server LDAP is also used + by the winbindd service when connecting to domain controllers. + + Samba also offers an LDAP server when running as + active directory domain controller. + + The NTLMSSP authentication used by the SMB1 encryption + is protected by smb signing, see CVE-2015-5296. + +o CVE-2016-2111: + + It's basically the same as CVE-2015-0005 for Windows: + + The NETLOGON service in Microsoft Windows Server 2003 SP2, + Windows Server 2008 SP2 and R2 SP1, and Windows Server 2012 Gold + and R2, when a Domain Controller is configured, allows remote + attackers to spoof the computer name of a secure channel's + endpoint, and obtain sensitive session information, by running a + crafted application and leveraging the ability to sniff network + traffic, aka "NETLOGON Spoofing Vulnerability". + + The vulnerability in Samba is worse as it doesn't require + credentials of a computer account in the domain. + + This only applies to Samba running as classic primary domain controller, + classic backup domain controller or active directory domain controller. + + The security patches introduce a new option called "raw NTLMv2 auth" + ("yes" or "no") for the [global] section in smb.conf. + Samba (the smbd process) will reject client using raw NTLMv2 + without using NTLMSSP. + + Note that this option also applies to Samba running as + standalone server and member server. + + You should also consider using "lanman auth = no" (which is already the default) + and "ntlm auth = no". Have a look at the smb.conf manpage for further details, + as they might impact compatibility with older clients. These also + apply for all server roles. + +o CVE-2016-2112: + + Samba uses various LDAP client libraries, a builtin one and/or the system + ldap libraries (typically openldap). + + As active directory domain controller Samba also provides an LDAP server. + + Samba takes care of doing SASL (GSS-SPNEGO) authentication with Kerberos or NTLMSSP + for LDAP connections, including possible integrity (sign) and privacy (seal) + protection. + + Samba has support for an option called "client ldap sasl wrapping" since version + 3.2.0. Its default value has changed from "plain" to "sign" with version 4.2.0. + + Tools using the builtin LDAP client library do not obey the + "client ldap sasl wrapping" option. This applies to tools like: + "samba-tool", "ldbsearch", "ldbedit" and more. Some of them have command line + options like "--sign" and "--encrypt". With the security update they will + also obey the "client ldap sasl wrapping" option as default. + + In all cases, even if explicitly request via "client ldap sasl wrapping", + "--sign" or "--encrypt", the protection can be downgraded by a man in the + middle. + + The LDAP server doesn't have an option to enforce strong authentication + yet. The security patches will introduce a new option called + "ldap server require strong auth", possible values are "no", + "allow_sasl_over_tls" and "yes". + + As the default behavior was as "no" before, you may + have to explicitly change this option until all clients have + been adjusted to handle LDAP_STRONG_AUTH_REQUIRED errors. + Windows clients and Samba member servers already use + integrity protection. + +o CVE-2016-2113: + + Samba has support for TLS/SSL for some protocols: + ldap and http, but currently certificates are not + validated at all. While we have a "tls cafile" option, + the configured certificate is not used to validate + the server certificate. + + This applies to ldaps:// connections triggered by tools like: + "ldbsearch", "ldbedit" and more. Note that it only applies + to the ldb tools when they are built as part of Samba or with Samba + extensions installed, which means the Samba builtin LDAP client library is + used. + + It also applies to dcerpc client connections using ncacn_http (with https://), + which are only used by the openchange project. Support for ncacn_http + was introduced in version 4.2.0. + + The security patches will introduce a new option called + "tls verify peer". Possible values are "no_check", "ca_only", + "ca_and_name_if_available", "ca_and_name" and "as_strict_as_possible". + + If you use the self-signed certificates which are auto-generated + by Samba, you won't have a crl file and need to explicitly + set "tls verify peer = ca_and_name". + +o CVE-2016-2114 + + Due to a regression introduced in Samba 4.0.0, + an explicit "server signing = mandatory" in the [global] section + of the smb.conf was not enforced for clients using the SMB1 protocol. + + As a result it does not enforce smb signing and allows man in the middle attacks. + + This problem applies to all possible server roles: + standalone server, member server, classic primary domain controller, + classic backup domain controller and active directory domain controller. + + In addition, when Samba is configured with "server role = active directory domain controller" + the effective default for the "server signing" option should be "mandatory". + + During the early development of Samba 4 we had a new experimental + file server located under source4/smb_server. But before + the final 4.0.0 release we switched back to the file server + under source3/smbd. + + But the logic for the correct default of "server signing" was not + ported correctly ported. + + Note that the default for server roles other than active directory domain + controller, is "off" because of performance reasons. + +o CVE-2016-2115: + + Samba has an option called "client signing", this is turned off by default + for performance reasons on file transfers. + + This option is also used when using DCERPC with ncacn_np. + + In order to get integrity protection for ipc related communication + by default the "client ipc signing" option is introduced. + The effective default for this new option is "mandatory". + + In order to be compatible with more SMB server implementations, + the following additional options are introduced: + "client ipc min protocol" ("NT1" by default) and + "client ipc max protocol" (the highest support SMB2/3 dialect by default). + These options overwrite the "client min protocol" and "client max protocol" + options, because the default for "client max protocol" is still "NT1". + The reason for this is the fact that all SMB2/3 support SMB signing, + while there are still SMB1 implementations which don't offer SMB signing + by default (this includes Samba versions before 4.0.0). + + Note that winbindd (in versions 4.2.0 and higher) enforces SMB signing + against active directory domain controllers despite of the + "client signing" and "client ipc signing" options. + +o CVE-2016-2118 (a.k.a. BADLOCK): + + The Security Account Manager Remote Protocol [MS-SAMR] and the + Local Security Authority (Domain Policy) Remote Protocol [MS-LSAD] + are both vulnerable to man in the middle attacks. Both are application level + protocols based on the generic DCE 1.1 Remote Procedure Call (DCERPC) protocol. + + These protocols are typically available on all Windows installations + as well as every Samba server. They are used to maintain + the Security Account Manager Database. This applies to all + roles, e.g. standalone, domain member, domain controller. + + Any authenticated DCERPC connection a client initiates against a server + can be used by a man in the middle to impersonate the authenticated user + against the SAMR or LSAD service on the server. + + The client chosen application protocol, auth type (e.g. Kerberos or NTLMSSP) + and auth level (NONE, CONNECT, PKT_INTEGRITY, PKT_PRIVACY) do not matter + in this case. A man in the middle can change auth level to CONNECT + (which means authentication without message protection) and take over + the connection. + + As a result, a man in the middle is able to get read/write access to the + Security Account Manager Database, which reveals all passwords + and any other potential sensitive information. + + Samba running as an active directory domain controller is additionally + missing checks to enforce PKT_PRIVACY for the + Directory Replication Service Remote Protocol [MS-DRSR] (drsuapi) + and the BackupKey Remote Protocol [MS-BKRP] (backupkey). + The Domain Name Service Server Management Protocol [MS-DNSP] (dnsserver) + is not enforcing at least PKT_INTEGRITY. + +==================== +New smb.conf options +==================== + + allow dcerpc auth level connect (G) + + This option controls whether DCERPC services are allowed to be used with + DCERPC_AUTH_LEVEL_CONNECT, which provides authentication, but no per + message integrity nor privacy protection. + + Some interfaces like samr, lsarpc and netlogon have a hard-coded default + of no and epmapper, mgmt and rpcecho have a hard-coded default of yes. + + The behavior can be overwritten per interface name (e.g. lsarpc, + netlogon, samr, srvsvc, winreg, wkssvc ...) by using + 'allow dcerpc auth level connect:interface = yes' as option. + + This option yields precedence to the implementation specific restrictions. + E.g. the drsuapi and backupkey protocols require DCERPC_AUTH_LEVEL_PRIVACY. + The dnsserver protocol requires DCERPC_AUTH_LEVEL_INTEGRITY. + + Default: allow dcerpc auth level connect = no + + Example: allow dcerpc auth level connect = yes + + client ipc signing (G) + + This controls whether the client is allowed or required to use + SMB signing for IPC$ connections as DCERPC transport. Possible + values are auto, mandatory and disabled. + + When set to mandatory or default, SMB signing is required. + + When set to auto, SMB signing is offered, but not enforced and + if set to disabled, SMB signing is not offered either. + + Connections from winbindd to Active Directory Domain Controllers + always enforce signing. + + Default: client ipc signing = default + + client ipc max protocol (G) + + The value of the parameter (a string) is the highest protocol level that will + be supported for IPC$ connections as DCERPC transport. + + Normally this option should not be set as the automatic negotiation phase + in the SMB protocol takes care of choosing the appropriate protocol. + + The value default refers to the latest supported protocol, currently SMB3_11. + + See client max protocol for a full list of available protocols. + The values CORE, COREPLUS, LANMAN1, LANMAN2 are silently upgraded to NT1. + + Default: client ipc max protocol = default + + Example: client ipc max protocol = SMB2_10 + + client ipc min protocol (G) + + This setting controls the minimum protocol version that the will be + attempted to use for IPC$ connections as DCERPC transport. + + Normally this option should not be set as the automatic negotiation phase + in the SMB protocol takes care of choosing the appropriate protocol. + + The value default refers to the higher value of NT1 and the + effective value of "client min protocol". + + See client max protocol for a full list of available protocols. + The values CORE, COREPLUS, LANMAN1, LANMAN2 are silently upgraded to NT1. + + Default: client ipc min protocol = default + + Example: client ipc min protocol = SMB3_11 + + ldap server require strong auth (G) + + The ldap server require strong auth defines whether the + ldap server requires ldap traffic to be signed or + signed and encrypted (sealed). Possible values are no, + allow_sasl_over_tls and yes. + + A value of no allows simple and sasl binds over all transports. + + A value of allow_sasl_over_tls allows simple and sasl binds (without sign or seal) + over TLS encrypted connections. Unencrypted connections only + allow sasl binds with sign or seal. + + A value of yes allows only simple binds over TLS encrypted connections. + Unencrypted connections only allow sasl binds with sign or seal. + + Default: ldap server require strong auth = yes + + raw NTLMv2 auth (G) + + This parameter determines whether or not smbd(8) will allow SMB1 clients + without extended security (without SPNEGO) to use NTLMv2 authentication. + + If this option, lanman auth and ntlm auth are all disabled, then only + clients with SPNEGO support will be permitted. That means NTLMv2 is only + supported within NTLMSSP. + + Default: raw NTLMv2 auth = no + + tls verify peer (G) + + This controls if and how strict the client will verify the peer's + certificate and name. Possible values are (in increasing order): no_check, + ca_only, ca_and_name_if_available, ca_and_name and as_strict_as_possible. + + When set to no_check the certificate is not verified at all, + which allows trivial man in the middle attacks. + + When set to ca_only the certificate is verified to be signed from a ca + specified in the "tls ca file" option. Setting "tls ca file" to a valid file + is required. The certificate lifetime is also verified. If the "tls crl file" + option is configured, the certificate is also verified against + the ca crl. + + When set to ca_and_name_if_available all checks from ca_only are performed. + In addition, the peer hostname is verified against the certificate's + name, if it is provided by the application layer and not given as + an ip address string. + + When set to ca_and_name all checks from ca_and_name_if_available are performed. + In addition the peer hostname needs to be provided and even an ip + address is checked against the certificate's name. + + When set to as_strict_as_possible all checks from ca_and_name are performed. + In addition the "tls crl file" needs to be configured. Future versions + of Samba may implement additional checks. + + Default: tls verify peer = as_strict_as_possible + + tls priority (G) (backported from Samba 4.3 to Samba 4.2) + + This option can be set to a string describing the TLS protocols to be + supported in the parts of Samba that use GnuTLS, specifically the AD DC. + + The default turns off SSLv3, as this protocol is no longer considered + secure after CVE-2014-3566 (otherwise known as POODLE) impacted SSLv3 use + in HTTPS applications. + + The valid options are described in the GNUTLS Priority-Strings + documentation at http://gnutls.org/manual/html_node/Priority-Strings.html + + Default: tls priority = NORMAL:-VERS-SSL3.0 + +================ +Behavior changes +================ + +o The default auth level for authenticated binds has changed from + DCERPC_AUTH_LEVEL_CONNECT to DCERPC_AUTH_LEVEL_INTEGRITY. + That means ncacn_ip_tcp:server is now implicitly the same + as ncacn_ip_tcp:server[sign] and offers a similar protection + as ncacn_np:server, which relies on smb signing. + +o The following constraints are applied to SMB1 connections: + + - "client lanman auth = yes" is now consistently + required for authenticated connections using the + SMB1 LANMAN2 dialect. + - "client ntlmv2 auth = yes" and "client use spnego = yes" + (both the default values), require extended security (SPNEGO) + support from the server. That means NTLMv2 is only used within + NTLMSSP. + +o Tools like "samba-tool", "ldbsearch", "ldbedit" and more obey the + default of "client ldap sasl wrapping = sign". Even with + "client ldap sasl wrapping = plain" they will automatically upgrade + to "sign" when getting LDAP_STRONG_AUTH_REQUIRED from the LDAP + server. + +Changes since 4.2.9: +==================== + +o Jeremy Allison <jra@samba.org> + * Bug 11344 - CVE-2015-5370: Multiple errors in DCE-RPC code. + + * Bug 11804 - prerequisite backports for the security release on + April 12th, 2016. + +o Christian Ambach <ambi@samba.org> + * Bug 11804 - prerequisite backports for the security release on + April 12th, 2016. + +o Andrew Bartlett <abartlet@samba.org> + * Bug 11804 - prerequisite backports for the security release on + April 12th, 2016. + +o Ralph Boehme <slow@samba.org> + * Bug 11644 - CVE-2016-2112: The LDAP client and server don't enforce + integrity protection. + +o Günther Deschner <gd@samba.org> + * Bug 11749 - CVE-2016-2111: NETLOGON Spoofing Vulnerability. + + * Bug 11804 - prerequisite backports for the security release on + April 12th, 2016. + +o Björn Jacke <bj@sernet.de> + * Bug 11804 - prerequisite backports for the security release on + April 12th, 2016. + +o Volker Lendecke <vl@samba.org> + * Bug 11804 - prerequisite backports for the security release on + April 12th, 2016. + +o Kamen Mazdrashki <kamenim@samba.org> + * Bug 11804 - prerequisite backports for the security release on + April 12th, 2016. + +o Stefan Metzmacher <metze@samba.org> + * Bug 11344 - CVE-2015-5370: Multiple errors in DCE-RPC code. + + * Bug 11616 - CVE-2016-2118: SAMR and LSA man in the middle attacks possible. + + * Bug 11644 - CVE-2016-2112: The LDAP client and server doesn't enforce + integrity protection. + + * Bug 11687 - CVE-2016-2114: "server signing = mandatory" not enforced. + + * Bug 11688 - CVE-2016-2110: Man in the middle attacks possible with NTLMSSP. + + * Bug 11749 - CVE-2016-2111: NETLOGON Spoofing Vulnerability. + + * Bug 11752 - CVE-2016-2113: Missing TLS certificate validation allows man in + the middle attacks. + + * Bug 11756 - CVE-2016-2115: SMB client connections for IPC traffic are not + integrity protected. + + * Bug 11804 - prerequisite backports for the security release on + April 12th, 2016. + +o Richard Sharpe <rsharpe@samba.org> + * Bug 11804 - prerequisite backports for the security release on + April 12th, 2016. + +o Andreas Schneider <asn@samba.org> + * Bug 11804 - prerequisite backports for the security release on + April 12th, 2016. + +o Jelmer Vernooij <jelmer@samba.org> + * Bug 11804 - prerequisite backports for the security release on + April 12th, 2016. + + +####################################### +Reporting bugs & Development Discussion +####################################### + +Please discuss this release on the samba-technical mailing list or by +joining the #samba-technical IRC channel on irc.freenode.net. + +If you do report problems then please try to send high quality +feedback. If you don't provide vital information to help us track down +the problem then you will probably be ignored. All bug reports should +be filed under the "Samba 4.1 and newer" product in the project's Bugzilla +database (https://bugzilla.samba.org/). + + +====================================================================== +== Our Code, Our Bugs, Our Responsibility. +== The Samba Team +====================================================================== + + +Release notes for older releases follow: +---------------------------------------- + + ============================= Release Notes for Samba 4.2.9 March 8, 2016 @@ -78,8 +655,8 @@ database (https://bugzilla.samba.org/). ====================================================================== -Release notes for older releases follow: ----------------------------------------- +---------------------------------------------------------------------- + ============================= Release Notes for Samba 4.2.8 diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c index e988d2d3c79..7c7e4d5748b 100644 --- a/auth/credentials/credentials.c +++ b/auth/credentials/credentials.c @@ -900,6 +900,7 @@ _PUBLIC_ void cli_credentials_set_anonymous(struct cli_credentials *cred) cli_credentials_set_password(cred, NULL, CRED_SPECIFIED); cli_credentials_set_realm(cred, NULL, CRED_SPECIFIED); cli_credentials_set_workstation(cred, "", CRED_UNINITIALISED); + cli_credentials_set_kerberos_state(cred, CRED_DONT_USE_KERBEROS); } /** diff --git a/auth/credentials/credentials.h b/auth/credentials/credentials.h index 2da47d2cac3..6c5c2c88f58 100644 --- a/auth/credentials/credentials.h +++ b/auth/credentials/credentials.h @@ -22,6 +22,7 @@ #ifndef __CREDENTIALS_H__ #define __CREDENTIALS_H__ +#include "../lib/util/time.h" #include "../lib/util/data_blob.h" #include "librpc/gen_ndr/misc.h" @@ -80,7 +81,9 @@ void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALL const char **domain); NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, int *flags, - DATA_BLOB challenge, DATA_BLOB target_info, + DATA_BLOB challenge, + const NTTIME *server_timestamp, + DATA_BLOB target_info, DATA_BLOB *_lm_response, DATA_BLOB *_nt_response, DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key); const char *cli_credentials_get_realm(struct cli_credentials *cred); diff --git a/auth/credentials/credentials_krb5.c b/auth/credentials/credentials_krb5.c index d968e200e77..a340ed97c59 100644 --- a/auth/credentials/credentials_krb5.c +++ b/auth/credentials/credentials_krb5.c @@ -516,7 +516,7 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, OM_uint32 maj_stat, min_stat; struct gssapi_creds_container *gcc; struct ccache_container *ccache; -#ifdef SAMBA4_USES_HEIMDAL +#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; #endif krb5_enctype *etypes = NULL; @@ -632,8 +632,7 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, } } -#ifdef SAMBA4_USES_HEIMDAL /* MIT lacks GSS_KRB5_CRED_NO_CI_FLAGS_X */ - +#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */ maj_stat = gss_set_cred_option(&min_stat, &gcc->creds, GSS_KRB5_CRED_NO_CI_FLAGS_X, diff --git a/auth/credentials/credentials_ntlm.c b/auth/credentials/credentials_ntlm.c index 8c6be395226..c1d0c00de59 100644 --- a/auth/credentials/credentials_ntlm.c +++ b/auth/credentials/credentials_ntlm.c @@ -30,7 +30,9 @@ _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, int *flags, - DATA_BLOB challenge, DATA_BLOB target_info, + DATA_BLOB challenge, + const NTTIME *server_timestamp, + DATA_BLOB target_info, DATA_BLOB *_lm_response, DATA_BLOB *_nt_response, DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key) { @@ -102,7 +104,7 @@ _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred user, domain, nt_hash->hash, &challenge, - &target_info, + server_timestamp, &target_info, &lm_response, &nt_response, NULL, &session_key)) { return NT_STATUS_NO_MEMORY; @@ -110,6 +112,12 @@ _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred /* LM Key is incompatible... */ *flags &= ~CLI_CRED_LANMAN_AUTH; + if (lm_response.length != 0) { + /* + * We should not expose the lm key. + */ + memset(lm_response.data, 0, lm_response.length); + } } else if (*flags & CLI_CRED_NTLM2) { MD5_CTX md5_session_nonce_ctx; uint8_t session_nonce[16]; diff --git a/auth/gensec/gensec.c b/auth/gensec/gensec.c index 01cceaf912f..4d0968b298f 100644 --- a/auth/gensec/gensec.c +++ b/auth/gensec/gensec.c @@ -30,6 +30,16 @@ #include "auth/gensec/gensec_internal.h" #include "librpc/gen_ndr/dcerpc.h" +_PRIVATE_ NTSTATUS gensec_may_reset_crypto(struct gensec_security *gensec_security, + bool full_reset) +{ + if (!gensec_security->ops->may_reset_crypto) { + return NT_STATUS_OK; + } + + return gensec_security->ops->may_reset_crypto(gensec_security, full_reset); +} + /* wrappers for the gensec function pointers */ @@ -217,6 +227,50 @@ _PUBLIC_ size_t gensec_max_update_size(struct gensec_security *gensec_security) return gensec_security->max_update_size; } +static NTSTATUS gensec_verify_dcerpc_auth_level(struct gensec_security *gensec_security) +{ + if (gensec_security->dcerpc_auth_level == 0) { + return NT_STATUS_OK; + } + + /* + * Because callers using the + * gensec_start_mech_by_auth_type() never call + * gensec_want_feature(), it isn't sensible for them + * to have to call gensec_have_feature() manually, and + * these are not points of negotiation, but are + * asserted by the client + */ + switch (gensec_security->dcerpc_auth_level) { + case DCERPC_AUTH_LEVEL_INTEGRITY: + if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { + DEBUG(0,("Did not manage to negotiate mandetory feature " + "SIGN for dcerpc auth_level %u\n", + gensec_security->dcerpc_auth_level)); + return NT_STATUS_ACCESS_DENIED; + } + break; + case DCERPC_AUTH_LEVEL_PRIVACY: + if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { + DEBUG(0,("Did not manage to negotiate mandetory feature " + "SIGN for dcerpc auth_level %u\n", + gensec_security->dcerpc_auth_level)); + return NT_STATUS_ACCESS_DENIED; + } + if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { + DEBUG(0,("Did not manage to negotiate mandetory feature " + "SEAL for dcerpc auth_level %u\n", + gensec_security->dcerpc_auth_level)); + return NT_STATUS_ACCESS_DENIED; + } + break; + default: + break; + } + + return NT_STATUS_OK; +} + _PUBLIC_ NTSTATUS gensec_update_ev(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, struct tevent_context *ev, @@ -261,31 +315,9 @@ _PUBLIC_ NTSTATUS gensec_update_ev(struct gensec_security *gensec_security, * these are not points of negotiation, but are * asserted by the client */ - switch (gensec_security->dcerpc_auth_level) { - case DCERPC_AUTH_LEVEL_INTEGRITY: - if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - DEBUG(0,("Did not manage to negotiate mandetory feature " - "SIGN for dcerpc auth_level %u\n", - gensec_security->dcerpc_auth_level)); - return NT_STATUS_ACCESS_DENIED; - } - break; - case DCERPC_AUTH_LEVEL_PRIVACY: - if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - DEBUG(0,("Did not manage to negotiate mandetory feature " - "SIGN for dcerpc auth_level %u\n", - gensec_security->dcerpc_auth_level)); - return NT_STATUS_ACCESS_DENIED; - } - if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { - DEBUG(0,("Did not manage to negotiate mandetory feature " - "SEAL for dcerpc auth_level %u\n", - gensec_security->dcerpc_auth_level)); - return NT_STATUS_ACCESS_DENIED; - } - break; - default: - break; + status = gensec_verify_dcerpc_auth_level(gensec_security); + if (!NT_STATUS_IS_OK(status)) { + return status; } return NT_STATUS_OK; @@ -458,34 +490,9 @@ static void gensec_update_subreq_done(struct tevent_req *subreq) * these are not points of negotiation, but are * asserted by the client */ - switch (state->gensec_security->dcerpc_auth_level) { - case DCERPC_AUTH_LEVEL_INTEGRITY: - if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SIGN)) { - DEBUG(0,("Did not manage to negotiate mandetory feature " - "SIGN for dcerpc auth_level %u\n", - state->gensec_security->dcerpc_auth_level)); - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - break; - case DCERPC_AUTH_LEVEL_PRIVACY: - if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SIGN)) { - DEBUG(0,("Did not manage to negotiate mandetory feature " - "SIGN for dcerpc auth_level %u\n", - state->gensec_security->dcerpc_auth_level)); - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SEAL)) { - DEBUG(0,("Did not manage to negotiate mandetory feature " - "SEAL for dcerpc auth_level %u\n", - state->gensec_security->dcerpc_auth_level)); - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - break; - default: - break; + status = gensec_verify_dcerpc_auth_level(state->gensec_security); + if (tevent_req_nterror(req, status)) { + return; } tevent_req_done(req); diff --git a/auth/gensec/gensec.h b/auth/gensec/gensec.h index 0d3a29ca831..e8bd7b1f22a 100644 --- a/auth/gensec/gensec.h +++ b/auth/gensec/gensec.h @@ -61,6 +61,8 @@ struct gensec_target { #define GENSEC_FEATURE_SIGN_PKT_HEADER 0x00000040 #define GENSEC_FEATURE_NEW_SPNEGO 0x00000080 #define GENSEC_FEATURE_UNIX_TOKEN 0x00000100 +#define GENSEC_FEATURE_NTLM_CCACHE 0x00000200 +#define GENSEC_FEATURE_LDAP_STYLE 0x00000400 #define GENSEC_EXPIRE_TIME_INFINITY (NTTIME)0x8000000000000000LL @@ -107,30 +109,9 @@ const struct gensec_critical_sizes *gensec_interface_version(void); /* Socket wrapper */ struct gensec_security; -struct socket_context; struct auth4_context; struct auth_user_info_dc; -/* These functions are for use here only (public because SPNEGO must - * use them for recursion) */ -NTSTATUS gensec_wrap_packets(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out, - size_t *len_processed); -/* These functions are for use here only (public because SPNEGO must - * use them for recursion) */ -NTSTATUS gensec_unwrap_packets(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out, - size_t *len_processed); - -/* These functions are for use here only (public because SPNEGO must - * use them for recursion) */ -NTSTATUS gensec_packet_full_request(struct gensec_security *gensec_security, - DATA_BLOB blob, size_t *size); - struct loadparm_context; NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx, @@ -184,6 +165,8 @@ const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_sec const struct gensec_security_ops *gensec_security_by_auth_type( struct gensec_security *gensec_security, uint32_t auth_type); +const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security, + const char *name); const struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx); const struct gensec_security_ops_wrapper *gensec_security_by_oid_list( diff --git a/auth/gensec/gensec_internal.h b/auth/gensec/gensec_internal.h index c04164a3dbd..55352417e99 100644 --- a/auth/gensec/gensec_internal.h +++ b/auth/gensec/gensec_internal.h @@ -47,6 +47,8 @@ struct gensec_security_ops { NTSTATUS (*update_recv)(struct tevent_req *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out); + NTSTATUS (*may_reset_crypto)(struct gensec_security *gensec_security, + bool full_reset); NTSTATUS (*seal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx, uint8_t *data, size_t length, const uint8_t *whole_pdu, size_t pdu_length, @@ -74,18 +76,6 @@ struct gensec_security_ops { TALLOC_CTX *mem_ctx, const DATA_BLOB *in, DATA_BLOB *out); - NTSTATUS (*wrap_packets)(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out, - size_t *len_processed); - NTSTATUS (*unwrap_packets)(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out, - size_t *len_processed); - NTSTATUS (*packet_full_request)(struct gensec_security *gensec_security, - DATA_BLOB blob, size_t *size); NTSTATUS (*session_key)(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, DATA_BLOB *session_key); NTSTATUS (*session_info)(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, @@ -122,6 +112,8 @@ struct gensec_security { * NTLM authentication backend, and user lookup (such as if no * PAC is found) */ struct auth4_context *auth_context; + + struct gensec_security *child_security; }; /* this structure is used by backends to determine the size of some critical types */ @@ -131,4 +123,7 @@ struct gensec_critical_sizes { int sizeof_gensec_security; }; +NTSTATUS gensec_may_reset_crypto(struct gensec_security *gensec_security, + bool full_reset); + #endif /* __GENSEC_H__ */ diff --git a/auth/gensec/gensec_start.c b/auth/gensec/gensec_start.c index b1bc1b93223..cb836f47ac3 100644 --- a/auth/gensec/gensec_start.c +++ b/auth/gensec/gensec_start.c @@ -203,8 +203,10 @@ _PUBLIC_ const struct gensec_security_ops *gensec_security_by_sasl_name( } backends = gensec_security_mechs(gensec_security, mem_ctx); for (i=0; backends && backends[i]; i++) { - if (!gensec_security_ops_enabled(backends[i], gensec_security)) - continue; + if (gensec_security != NULL && + !gensec_security_ops_enabled(backends[i], gensec_security)) { + continue; + } if (backends[i]->sasl_name && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) { backend = backends[i]; @@ -224,7 +226,13 @@ _PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type( int i; const struct gensec_security_ops **backends; const struct gensec_security_ops *backend; - TALLOC_CTX *mem_ctx = talloc_new(gensec_security); + TALLOC_CTX *mem_ctx; + + if (auth_type == DCERPC_AUTH_TYPE_NONE) { + return NULL; + } + + mem_ctx = talloc_new(gensec_security); if (!mem_ctx) { return NULL; } @@ -245,8 +253,8 @@ _PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type( return NULL; } -static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security, - const char *name) +const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security, + const char *name) { int i; const struct gensec_security_ops **backends; diff --git a/auth/gensec/gensec_util.c b/auth/gensec/gensec_util.c index b8e38b7f7c9..64fffb1efc9 100644 --- a/auth/gensec/gensec_util.c +++ b/auth/gensec/gensec_util.c @@ -68,122 +68,6 @@ NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx, } /* - * These functions are for use in the deprecated - * gensec_socket code (public because SPNEGO must - * use them for recursion) - */ -_PUBLIC_ NTSTATUS gensec_wrap_packets(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out, - size_t *len_processed) -{ - if (!gensec_security->ops->wrap_packets) { - NTSTATUS nt_status; - size_t max_input_size; - DATA_BLOB unwrapped, wrapped; - max_input_size = gensec_max_input_size(gensec_security); - unwrapped = data_blob_const(in->data, MIN(max_input_size, (size_t)in->length)); - - nt_status = gensec_wrap(gensec_security, - mem_ctx, - &unwrapped, &wrapped); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - *out = data_blob_talloc(mem_ctx, NULL, 4); - if (!out->data) { - return NT_STATUS_NO_MEMORY; - } - RSIVAL(out->data, 0, wrapped.length); - - if (!data_blob_append(mem_ctx, out, wrapped.data, wrapped.length)) { - return NT_STATUS_NO_MEMORY; - } - *len_processed = unwrapped.length; - return NT_STATUS_OK; - } - return gensec_security->ops->wrap_packets(gensec_security, mem_ctx, in, out, - len_processed); -} - -/* - * These functions are for use in the deprecated - * gensec_socket code (public because SPNEGO must - * use them for recursion) - */ -NTSTATUS gensec_unwrap_packets(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out, - size_t *len_processed) -{ - if (!gensec_security->ops->unwrap_packets) { - DATA_BLOB wrapped; - NTSTATUS nt_status; - size_t packet_size; - if (in->length < 4) { - /* Missing the header we already had! */ - DEBUG(0, ("Asked to unwrap packet of bogus length! How did we get the short packet?!\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - packet_size = RIVAL(in->data, 0); - - wrapped = data_blob_const(in->data + 4, packet_size); - - if (wrapped.length > (in->length - 4)) { - DEBUG(0, ("Asked to unwrap packed of bogus length %d > %d! How did we get this?!\n", - (int)wrapped.length, (int)(in->length - 4))); - return NT_STATUS_INTERNAL_ERROR; - } - - nt_status = gensec_unwrap(gensec_security, - mem_ctx, - &wrapped, out); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - *len_processed = packet_size + 4; - return nt_status; - } - return gensec_security->ops->unwrap_packets(gensec_security, mem_ctx, in, out, - len_processed); -} - -/* - * These functions are for use in the deprecated - * gensec_socket code (public because SPNEGO must - * use them for recursion) - */ -NTSTATUS gensec_packet_full_request(struct gensec_security *gensec_security, - DATA_BLOB blob, size_t *size) -{ - if (gensec_security->ops->packet_full_request) { - return gensec_security->ops->packet_full_request(gensec_security, - blob, size); - } - if (gensec_security->ops->unwrap_packets) { - if (blob.length) { - *size = blob.length; - return NT_STATUS_OK; - } - return STATUS_MORE_ENTRIES; - } - - if (blob.length < 4) { - return STATUS_MORE_ENTRIES; - } - *size = 4 + RIVAL(blob.data, 0); - if (*size > blob.length) { - return STATUS_MORE_ENTRIES; - } - return NT_STATUS_OK; -} - -/* magic check a GSS-API wrapper packet for an Kerberos OID */ static bool gensec_gssapi_check_oid(const DATA_BLOB *blob, const char *oid) @@ -197,7 +81,7 @@ static bool gensec_gssapi_check_oid(const DATA_BLOB *blob, const char *oid) if (!asn1_start_tag(data, ASN1_APPLICATION(0))) goto err; if (!asn1_check_OID(data, oid)) goto err; - ret = !data->has_error; + ret = !asn1_has_error(data); err: diff --git a/auth/gensec/schannel.c b/auth/gensec/schannel.c index ee23e77ace4..1acf7fefb73 100644 --- a/auth/gensec/schannel.c +++ b/auth/gensec/schannel.c @@ -467,6 +467,16 @@ static NTSTATUS schannel_update(struct gensec_security *gensec_security, TALLOC_ *out = data_blob(NULL, 0); + if (gensec_security->dcerpc_auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) { + switch (gensec_security->gensec_role) { + case GENSEC_CLIENT: + return NT_STATUS_INVALID_PARAMETER_MIX; + case GENSEC_SERVER: + return NT_STATUS_INVALID_PARAMETER; + } + return NT_STATUS_INTERNAL_ERROR; + } + switch (gensec_security->gensec_role) { case GENSEC_CLIENT: if (state != NULL) { @@ -669,9 +679,15 @@ static NTSTATUS schannel_client_start(struct gensec_security *gensec_security) static bool schannel_have_feature(struct gensec_security *gensec_security, uint32_t feature) { - if (feature & (GENSEC_FEATURE_SIGN | - GENSEC_FEATURE_SEAL)) { - return true; + if (gensec_security->dcerpc_auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) { + if (feature & GENSEC_FEATURE_SIGN) { + return true; + } + } + if (gensec_security->dcerpc_auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + if (feature & GENSEC_FEATURE_SEAL) { + return true; + } } if (feature & GENSEC_FEATURE_DCE_STYLE) { return true; diff --git a/auth/gensec/spnego.c b/auth/gensec/spnego.c index 8fd11e90527..1d4b172e476 100644 --- a/auth/gensec/spnego.c +++ b/auth/gensec/spnego.c @@ -53,6 +53,11 @@ struct spnego_state { const char *neg_oid; DATA_BLOB mech_types; + size_t num_targs; + bool mic_requested; + bool needs_mic_sign; + bool needs_mic_check; + bool done_mic_check; /* * The following is used to implement @@ -221,59 +226,6 @@ static NTSTATUS gensec_spnego_unwrap(struct gensec_security *gensec_security, mem_ctx, in, out); } -static NTSTATUS gensec_spnego_wrap_packets(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out, - size_t *len_processed) -{ - struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - DEBUG(1, ("gensec_spnego_wrap: wrong state for wrap\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_wrap_packets(spnego_state->sub_sec_security, - mem_ctx, in, out, - len_processed); -} - -static NTSTATUS gensec_spnego_packet_full_request(struct gensec_security *gensec_security, - DATA_BLOB blob, size_t *size) -{ - struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_packet_full_request(spnego_state->sub_sec_security, - blob, size); -} - -static NTSTATUS gensec_spnego_unwrap_packets(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out, - size_t *len_processed) -{ - struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_unwrap_packets(spnego_state->sub_sec_security, - mem_ctx, in, out, - len_processed); -} - static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security, size_t data_size) { struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; @@ -469,6 +421,11 @@ static NTSTATUS gensec_spnego_parse_negTokenInit(struct gensec_security *gensec_ spnego_state->neg_oid = all_sec[i].oid; *unwrapped_out = data_blob_null; nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; + /* + * Indicate the downgrade and request a + * mic. + */ + spnego_state->mic_requested = true; break; } @@ -727,22 +684,27 @@ static NTSTATUS gensec_spnego_server_negTokenTarg(struct spnego_state *spnego_st /* compose reply */ spnego_out.type = SPNEGO_NEG_TOKEN_TARG; spnego_out.negTokenTarg.responseToken = unwrapped_out; - spnego_out.negTokenTarg.mechListMIC = null_data_blob; + spnego_out.negTokenTarg.mechListMIC = mech_list_mic; spnego_out.negTokenTarg.supportedMech = NULL; if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid; - spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE; + if (spnego_state->mic_requested) { + spnego_out.negTokenTarg.negResult = SPNEGO_REQUEST_MIC; + spnego_state->mic_requested = false; + } else { + spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE; + } spnego_state->state_position = SPNEGO_SERVER_TARG; } else if (NT_STATUS_IS_OK(nt_status)) { if (unwrapped_out.data) { spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid; } spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED; - spnego_out.negTokenTarg.mechListMIC = mech_list_mic; spnego_state->state_position = SPNEGO_DONE; } else { spnego_out.negTokenTarg.negResult = SPNEGO_REJECT; + spnego_out.negTokenTarg.mechListMIC = null_data_blob; DEBUG(2, ("SPNEGO login failed: %s\n", nt_errstr(nt_status))); spnego_state->state_position = SPNEGO_DONE; } @@ -753,6 +715,7 @@ static NTSTATUS gensec_spnego_server_negTokenTarg(struct spnego_state *spnego_st } spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; + spnego_state->num_targs++; return nt_status; } @@ -837,6 +800,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA const char *my_mechs[] = {NULL, NULL}; NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; + bool ok; if (!in.length) { /* client to produce negTokenInit */ @@ -899,6 +863,14 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA return NT_STATUS_INVALID_PARAMETER; } + ok = spnego_write_mech_types(spnego_state, + my_mechs, + &spnego_state->mech_types); + if (!ok) { + DEBUG(1, ("SPNEGO: Failed to write mechTypes\n")); + return NT_STATUS_NO_MEMORY; + } + /* set next state */ spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; spnego_state->state_position = SPNEGO_CLIENT_TARG; @@ -936,18 +908,57 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA return NT_STATUS_INVALID_PARAMETER; } + spnego_state->num_targs++; + if (!spnego_state->sub_sec_security) { DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n")); spnego_free_data(&spnego); return NT_STATUS_INVALID_PARAMETER; } + if (spnego_state->needs_mic_check) { + if (spnego.negTokenTarg.responseToken.length != 0) { + DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n")); + spnego_free_data(&spnego); + return NT_STATUS_INVALID_PARAMETER; + } + + nt_status = gensec_check_packet(spnego_state->sub_sec_security, + spnego_state->mech_types.data, + spnego_state->mech_types.length, + spnego_state->mech_types.data, + spnego_state->mech_types.length, + &spnego.negTokenTarg.mechListMIC); + if (NT_STATUS_IS_OK(nt_status)) { + spnego_state->needs_mic_check = false; + spnego_state->done_mic_check = true; + } else { + DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n", + nt_errstr(nt_status))); + } + goto server_response; + } + nt_status = gensec_update_ev(spnego_state->sub_sec_security, - out_mem_ctx, ev, - spnego.negTokenTarg.responseToken, - &unwrapped_out); - if (NT_STATUS_IS_OK(nt_status) && spnego.negTokenTarg.mechListMIC.length > 0) { + out_mem_ctx, ev, + spnego.negTokenTarg.responseToken, + &unwrapped_out); + if (!NT_STATUS_IS_OK(nt_status)) { + goto server_response; + } + + new_spnego = gensec_have_feature(spnego_state->sub_sec_security, + GENSEC_FEATURE_NEW_SPNEGO); + if (spnego.negTokenTarg.mechListMIC.length > 0) { new_spnego = true; + } + + if (new_spnego) { + spnego_state->needs_mic_check = true; + spnego_state->needs_mic_sign = true; + } + + if (spnego.negTokenTarg.mechListMIC.length > 0) { nt_status = gensec_check_packet(spnego_state->sub_sec_security, spnego_state->mech_types.data, spnego_state->mech_types.length, @@ -957,9 +968,14 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n", nt_errstr(nt_status))); + goto server_response; } + + spnego_state->needs_mic_check = false; + spnego_state->done_mic_check = true; } - if (NT_STATUS_IS_OK(nt_status) && new_spnego) { + + if (spnego_state->needs_mic_sign) { nt_status = gensec_sign_packet(spnego_state->sub_sec_security, out_mem_ctx, spnego_state->mech_types.data, @@ -970,9 +986,16 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n", nt_errstr(nt_status))); + goto server_response; } + spnego_state->needs_mic_sign = false; } + if (spnego_state->needs_mic_check) { + nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; + } + + server_response: nt_status = gensec_spnego_server_negTokenTarg(spnego_state, out_mem_ctx, nt_status, @@ -986,7 +1009,8 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA } case SPNEGO_CLIENT_TARG: { - NTSTATUS nt_status; + NTSTATUS nt_status = NT_STATUS_INTERNAL_ERROR; + if (!in.length) { return NT_STATUS_INVALID_PARAMETER; } @@ -1008,19 +1032,27 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA return NT_STATUS_INVALID_PARAMETER; } + spnego_state->num_targs++; + if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) { spnego_free_data(&spnego); return NT_STATUS_LOGON_FAILURE; } + if (spnego.negTokenTarg.negResult == SPNEGO_REQUEST_MIC) { + spnego_state->mic_requested = true; + } + /* Server didn't like our choice of mech, and chose something else */ - if ((spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_INCOMPLETE) && + if (((spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_INCOMPLETE) || + (spnego.negTokenTarg.negResult == SPNEGO_REQUEST_MIC)) && spnego.negTokenTarg.supportedMech && strcmp(spnego.negTokenTarg.supportedMech, spnego_state->neg_oid) != 0) { DEBUG(3,("GENSEC SPNEGO: client preferred mech (%s) not accepted, server wants: %s\n", - gensec_get_name_by_oid(gensec_security, spnego.negTokenTarg.supportedMech), - gensec_get_name_by_oid(gensec_security, spnego_state->neg_oid))); + gensec_get_name_by_oid(gensec_security, spnego_state->neg_oid), + gensec_get_name_by_oid(gensec_security, spnego.negTokenTarg.supportedMech))); + spnego_state->no_response_expected = false; talloc_free(spnego_state->sub_sec_security); nt_status = gensec_subcontext_start(spnego_state, gensec_security, @@ -1037,64 +1069,143 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA return nt_status; } - nt_status = gensec_update_ev(spnego_state->sub_sec_security, - out_mem_ctx, ev, - spnego.negTokenTarg.responseToken, - &unwrapped_out); - spnego_state->neg_oid = talloc_strdup(spnego_state, spnego.negTokenTarg.supportedMech); - } else if (spnego_state->no_response_expected) { - if (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) { - DEBUG(3,("GENSEC SPNEGO: client GENSEC accepted, but server rejected (bad password?)\n")); - nt_status = NT_STATUS_INVALID_PARAMETER; - } else if (spnego.negTokenTarg.responseToken.length) { - DEBUG(2,("GENSEC SPNEGO: client GENSEC accepted, but server continued negotiation!\n")); - nt_status = NT_STATUS_INVALID_PARAMETER; - } else { - nt_status = NT_STATUS_OK; + spnego_state->neg_oid = talloc_strdup(spnego_state, + spnego.negTokenTarg.supportedMech); + if (spnego_state->neg_oid == NULL) { + spnego_free_data(&spnego); + return NT_STATUS_NO_MEMORY; + }; + } + + if (spnego.negTokenTarg.mechListMIC.length > 0) { + if (spnego_state->no_response_expected) { + spnego_state->needs_mic_check = true; } - if (NT_STATUS_IS_OK(nt_status) && spnego.negTokenTarg.mechListMIC.length > 0) { - nt_status = gensec_check_packet(spnego_state->sub_sec_security, - spnego_state->mech_types.data, - spnego_state->mech_types.length, - spnego_state->mech_types.data, - spnego_state->mech_types.length, - &spnego.negTokenTarg.mechListMIC); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n", - nt_errstr(nt_status))); - } + } + + if (spnego_state->needs_mic_check) { + if (spnego.negTokenTarg.responseToken.length != 0) { + DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n")); + spnego_free_data(&spnego); + return NT_STATUS_INVALID_PARAMETER; } - } else { - bool new_spnego = false; + nt_status = gensec_check_packet(spnego_state->sub_sec_security, + spnego_state->mech_types.data, + spnego_state->mech_types.length, + spnego_state->mech_types.data, + spnego_state->mech_types.length, + &spnego.negTokenTarg.mechListMIC); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n", + nt_errstr(nt_status))); + spnego_free_data(&spnego); + return nt_status; + } + spnego_state->needs_mic_check = false; + spnego_state->done_mic_check = true; + goto client_response; + } + + if (!spnego_state->no_response_expected) { nt_status = gensec_update_ev(spnego_state->sub_sec_security, out_mem_ctx, ev, spnego.negTokenTarg.responseToken, &unwrapped_out); + if (!NT_STATUS_IS_OK(nt_status)) { + goto client_response; + } + + spnego_state->no_response_expected = true; + } else { + nt_status = NT_STATUS_OK; + } - if (NT_STATUS_IS_OK(nt_status) - && spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) { - new_spnego = gensec_have_feature(spnego_state->sub_sec_security, - GENSEC_FEATURE_NEW_SPNEGO); + if (spnego_state->no_response_expected && + !spnego_state->done_mic_check) + { + bool new_spnego = false; + + new_spnego = gensec_have_feature(spnego_state->sub_sec_security, + GENSEC_FEATURE_NEW_SPNEGO); + + switch (spnego.negTokenTarg.negResult) { + case SPNEGO_ACCEPT_COMPLETED: + case SPNEGO_NONE_RESULT: + if (spnego_state->num_targs == 1) { + /* + * the first exchange doesn't require + * verification + */ + new_spnego = false; + } + break; + + case SPNEGO_ACCEPT_INCOMPLETE: + case SPNEGO_REQUEST_MIC: + if (spnego.negTokenTarg.mechListMIC.length > 0) { + new_spnego = true; + } + break; + default: + break; } - if (NT_STATUS_IS_OK(nt_status) && new_spnego) { - nt_status = gensec_sign_packet(spnego_state->sub_sec_security, - out_mem_ctx, - spnego_state->mech_types.data, - spnego_state->mech_types.length, - spnego_state->mech_types.data, - spnego_state->mech_types.length, - &mech_list_mic); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n", - nt_errstr(nt_status))); + + if (spnego_state->mic_requested) { + bool sign; + + sign = gensec_have_feature(spnego_state->sub_sec_security, + GENSEC_FEATURE_SIGN); + if (sign) { + new_spnego = true; } } - if (NT_STATUS_IS_OK(nt_status)) { - spnego_state->no_response_expected = true; + + if (new_spnego) { + spnego_state->needs_mic_check = true; + spnego_state->needs_mic_sign = true; } - } + } + if (spnego.negTokenTarg.mechListMIC.length > 0) { + nt_status = gensec_check_packet(spnego_state->sub_sec_security, + spnego_state->mech_types.data, + spnego_state->mech_types.length, + spnego_state->mech_types.data, + spnego_state->mech_types.length, + &spnego.negTokenTarg.mechListMIC); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n", + nt_errstr(nt_status))); + spnego_free_data(&spnego); + return nt_status; + } + spnego_state->needs_mic_check = false; + spnego_state->done_mic_check = true; + } + + if (spnego_state->needs_mic_sign) { + nt_status = gensec_sign_packet(spnego_state->sub_sec_security, + out_mem_ctx, + spnego_state->mech_types.data, + spnego_state->mech_types.length, + spnego_state->mech_types.data, + spnego_state->mech_types.length, + &mech_list_mic); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n", + nt_errstr(nt_status))); + spnego_free_data(&spnego); + return nt_status; + } + spnego_state->needs_mic_sign = false; + } + + if (spnego_state->needs_mic_check) { + nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; + } + + client_response: spnego_free_data(&spnego); if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) @@ -1118,6 +1229,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA return NT_STATUS_INVALID_PARAMETER; } + spnego_state->num_targs++; spnego_state->state_position = SPNEGO_CLIENT_TARG; nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; } else { @@ -1148,26 +1260,24 @@ static NTSTATUS gensec_spnego_update_in(struct gensec_security *gensec_security, { struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; size_t expected; - NTSTATUS status; bool ok; *full_in = data_blob_null; if (spnego_state->in_needed == 0) { size_t size = 0; + int ret; /* * try to work out the size of the full * input token, it might be fragmented */ - status = asn1_peek_full_tag(in, ASN1_APPLICATION(0), &size); - if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) { - status = asn1_peek_full_tag(in, ASN1_CONTEXT(1), &size); + ret = asn1_peek_full_tag(in, ASN1_APPLICATION(0), &size); + if ((ret != 0) && (ret != EAGAIN)) { + ret = asn1_peek_full_tag(in, ASN1_CONTEXT(1), &size); } - if (NT_STATUS_IS_OK(status) || - NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) { + if ((ret == 0) || (ret == EAGAIN)) { spnego_state->in_needed = size; } else { /* @@ -1315,6 +1425,16 @@ static NTSTATUS gensec_spnego_update_wrapper(struct gensec_security *gensec_secu &spnego_state->out_frag); data_blob_free(&spnego_state->in_frag); spnego_state->in_needed = 0; + if (NT_STATUS_IS_OK(status)) { + bool reset_full = true; + + gensec_security->child_security = spnego_state->sub_sec_security; + + reset_full = !spnego_state->done_mic_check; + + status = gensec_may_reset_crypto(spnego_state->sub_sec_security, + reset_full); + } if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { return status; @@ -1384,11 +1504,8 @@ static const struct gensec_security_ops gensec_spnego_security_ops = { .max_input_size = gensec_spnego_max_input_size, .check_packet = gensec_spnego_check_packet, .unseal_packet = gensec_spnego_unseal_packet, - .packet_full_request = gensec_spnego_packet_full_request, .wrap = gensec_spnego_wrap, .unwrap = gensec_spnego_unwrap, - .wrap_packets = gensec_spnego_wrap_packets, - .unwrap_packets = gensec_spnego_unwrap_packets, .session_key = gensec_spnego_session_key, .session_info = gensec_spnego_session_info, .want_feature = gensec_spnego_want_feature, diff --git a/auth/gensec/wscript_build b/auth/gensec/wscript_build index b2f6033ed00..413c60672ae 100755 --- a/auth/gensec/wscript_build +++ b/auth/gensec/wscript_build @@ -3,7 +3,7 @@ bld.SAMBA_LIBRARY('gensec', source='gensec.c gensec_start.c gensec_util.c', pc_files='gensec.pc', autoproto='gensec_toplevel_proto.h', - public_deps='tevent-util samba-util errors LIBPACKET auth_system_session samba-modules gensec_util asn1util', + public_deps='tevent-util samba-util errors auth_system_session samba-modules gensec_util asn1util', public_headers='gensec.h', deps='com_err', vnum='0.0.1' diff --git a/auth/kerberos/gssapi_helper.c b/auth/kerberos/gssapi_helper.c new file mode 100644 index 00000000000..b7ffb6ca9ff --- /dev/null +++ b/auth/kerberos/gssapi_helper.c @@ -0,0 +1,395 @@ +/* + Unix SMB/CIFS implementation. + GSSAPI helper functions + + Copyright (C) Stefan Metzmacher 2008,2015 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "system/gssapi.h" +#include "auth/kerberos/pac_utils.h" +#include "auth/kerberos/gssapi_helper.h" + +size_t gssapi_get_sig_size(gss_ctx_id_t gssapi_context, + const gss_OID mech, + uint32_t gss_want_flags, + size_t data_size) +{ + TALLOC_CTX *frame = talloc_stackframe(); + size_t sig_size = 0; + + if (gss_want_flags & GSS_C_CONF_FLAG) { + OM_uint32 min_stat, maj_stat; + bool want_sealing = true; + int sealed = 0; + gss_iov_buffer_desc iov[2]; + + if (!(gss_want_flags & GSS_C_DCE_STYLE)) { + TALLOC_FREE(frame); + return 0; + } + + /* + * gss_wrap_iov_length() only needs the type and length + */ + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; + iov[0].buffer.value = NULL; + iov[0].buffer.length = 0; + iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[1].buffer.value = NULL; + iov[1].buffer.length = data_size; + + maj_stat = gss_wrap_iov_length(&min_stat, + gssapi_context, + want_sealing, + GSS_C_QOP_DEFAULT, + &sealed, + iov, ARRAY_SIZE(iov)); + if (maj_stat) { + DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n", + gssapi_error_string(frame, + maj_stat, + min_stat, + mech))); + TALLOC_FREE(frame); + return 0; + } + + sig_size = iov[0].buffer.length; + } else if (gss_want_flags & GSS_C_INTEG_FLAG) { + NTSTATUS status; + uint32_t keytype; + + status = gssapi_get_session_key(frame, + gssapi_context, + NULL, &keytype); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return 0; + } + + switch (keytype) { + case ENCTYPE_DES_CBC_MD5: + case ENCTYPE_DES_CBC_CRC: + case ENCTYPE_ARCFOUR_HMAC: + case ENCTYPE_ARCFOUR_HMAC_EXP: + sig_size = 37; + break; + default: + sig_size = 28; + break; + } + } + + TALLOC_FREE(frame); + return sig_size; +} + +NTSTATUS gssapi_seal_packet(gss_ctx_id_t gssapi_context, + const gss_OID mech, + bool hdr_signing, size_t sig_size, + uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + TALLOC_CTX *mem_ctx, + DATA_BLOB *sig) +{ + OM_uint32 maj_stat, min_stat; + gss_iov_buffer_desc iov[4]; + int req_seal = 1; + int sealed = 0; + const uint8_t *pre_sign_ptr = NULL; + size_t pre_sign_len = 0; + const uint8_t *post_sign_ptr = NULL; + size_t post_sign_len = 0; + + if (hdr_signing) { + const uint8_t *de = data + length; + const uint8_t *we = whole_pdu + pdu_length; + + if (data < whole_pdu) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (de > we) { + return NT_STATUS_INVALID_PARAMETER; + } + + pre_sign_len = data - whole_pdu; + if (pre_sign_len > 0) { + pre_sign_ptr = whole_pdu; + } + post_sign_len = we - de; + if (post_sign_len > 0) { + post_sign_ptr = de; + } + } + + sig->length = sig_size; + if (sig->length == 0) { + return NT_STATUS_ACCESS_DENIED; + } + + sig->data = talloc_zero_array(mem_ctx, uint8_t, sig->length); + if (sig->data == NULL) { + return NT_STATUS_NO_MEMORY; + } + + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; + iov[0].buffer.length = sig->length; + iov[0].buffer.value = sig->data; + + if (pre_sign_ptr != NULL) { + iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov[1].buffer.length = pre_sign_len; + iov[1].buffer.value = discard_const(pre_sign_ptr); + } else { + iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY; + iov[1].buffer.length = 0; + iov[1].buffer.value = NULL; + } + + /* data is encrypted in place, which is ok */ + iov[2].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[2].buffer.length = length; + iov[2].buffer.value = data; + + if (post_sign_ptr != NULL) { + iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov[3].buffer.length = post_sign_len; + iov[3].buffer.value = discard_const(post_sign_ptr); + } else { + iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY; + iov[3].buffer.length = 0; + iov[3].buffer.value = NULL; + } + + maj_stat = gss_wrap_iov(&min_stat, + gssapi_context, + req_seal, + GSS_C_QOP_DEFAULT, + &sealed, + iov, ARRAY_SIZE(iov)); + if (GSS_ERROR(maj_stat)) { + char *error_string = gssapi_error_string(mem_ctx, + maj_stat, + min_stat, + mech); + DEBUG(1, ("gss_wrap_iov failed: %s\n", error_string)); + talloc_free(error_string); + data_blob_free(sig); + return NT_STATUS_ACCESS_DENIED; + } + + if (req_seal == 1 && sealed == 0) { + DEBUG(0, ("gss_wrap_iov says data was not sealed!\n")); + data_blob_free(sig); + return NT_STATUS_ACCESS_DENIED; + } + + dump_data_pw("gssapi_seal_packet: sig\n", sig->data, sig->length); + dump_data_pw("gssapi_seal_packet: sealed\n", data, length); + + DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n", + (int)iov[2].buffer.length, (int)iov[0].buffer.length)); + + return NT_STATUS_OK; +} + +NTSTATUS gssapi_unseal_packet(gss_ctx_id_t gssapi_context, + const gss_OID mech, + bool hdr_signing, + uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + const DATA_BLOB *sig) +{ + OM_uint32 maj_stat, min_stat; + gss_iov_buffer_desc iov[4]; + gss_qop_t qop_state; + int sealed = 0; + const uint8_t *pre_sign_ptr = NULL; + size_t pre_sign_len = 0; + const uint8_t *post_sign_ptr = NULL; + size_t post_sign_len = 0; + + if (hdr_signing) { + const uint8_t *de = data + length; + const uint8_t *we = whole_pdu + pdu_length; + + if (data < whole_pdu) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (de > we) { + return NT_STATUS_INVALID_PARAMETER; + } + + pre_sign_len = data - whole_pdu; + if (pre_sign_len > 0) { + pre_sign_ptr = whole_pdu; + } + post_sign_len = we - de; + if (post_sign_len > 0) { + post_sign_ptr = de; + } + } + + dump_data_pw("gssapi_unseal_packet: sig\n", sig->data, sig->length); + dump_data_pw("gssapi_unseal_packet: sealed\n", data, length); + + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; + iov[0].buffer.length = sig->length; + iov[0].buffer.value = sig->data; + + if (pre_sign_ptr != NULL) { + iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov[1].buffer.length = pre_sign_len; + iov[1].buffer.value = discard_const(pre_sign_ptr); + } else { + iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY; + iov[1].buffer.length = 0; + iov[1].buffer.value = NULL; + } + + /* data is encrypted in place, which is ok */ + iov[2].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[2].buffer.length = length; + iov[2].buffer.value = data; + + if (post_sign_ptr != NULL) { + iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov[3].buffer.length = post_sign_len; + iov[3].buffer.value = discard_const(post_sign_ptr); + } else { + iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY; + iov[3].buffer.length = 0; + iov[3].buffer.value = NULL; + } + + maj_stat = gss_unwrap_iov(&min_stat, + gssapi_context, + &sealed, + &qop_state, + iov, ARRAY_SIZE(iov)); + if (GSS_ERROR(maj_stat)) { + char *error_string = gssapi_error_string(NULL, + maj_stat, + min_stat, + mech); + DEBUG(1, ("gss_unwrap_iov failed: %s\n", error_string)); + talloc_free(error_string); + + return NT_STATUS_ACCESS_DENIED; + } + + if (sealed == 0) { + DEBUG(0, ("gss_unwrap_iov says data was not sealed!\n")); + return NT_STATUS_ACCESS_DENIED; + } + + DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n", + (int)iov[2].buffer.length, (int)iov[0].buffer.length)); + + return NT_STATUS_OK; +} + +NTSTATUS gssapi_sign_packet(gss_ctx_id_t gssapi_context, + const gss_OID mech, + bool hdr_signing, + const uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + TALLOC_CTX *mem_ctx, + DATA_BLOB *sig) +{ + OM_uint32 maj_stat, min_stat; + gss_buffer_desc input_token, output_token; + + if (hdr_signing) { + input_token.length = pdu_length; + input_token.value = discard_const_p(uint8_t *, whole_pdu); + } else { + input_token.length = length; + input_token.value = discard_const_p(uint8_t *, data); + } + + maj_stat = gss_get_mic(&min_stat, + gssapi_context, + GSS_C_QOP_DEFAULT, + &input_token, + &output_token); + if (GSS_ERROR(maj_stat)) { + char *error_string = gssapi_error_string(mem_ctx, + maj_stat, + min_stat, + mech); + DEBUG(1, ("GSS GetMic failed: %s\n", error_string)); + talloc_free(error_string); + return NT_STATUS_ACCESS_DENIED; + } + + *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, output_token.length); + gss_release_buffer(&min_stat, &output_token); + if (sig->data == NULL) { + return NT_STATUS_NO_MEMORY; + } + + dump_data_pw("gssapi_sign_packet: sig\n", sig->data, sig->length); + + return NT_STATUS_OK; +} + +NTSTATUS gssapi_check_packet(gss_ctx_id_t gssapi_context, + const gss_OID mech, + bool hdr_signing, + const uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + const DATA_BLOB *sig) +{ + OM_uint32 maj_stat, min_stat; + gss_buffer_desc input_token; + gss_buffer_desc input_message; + gss_qop_t qop_state; + + dump_data_pw("gssapi_check_packet: sig\n", sig->data, sig->length); + + if (hdr_signing) { + input_message.length = pdu_length; + input_message.value = discard_const(whole_pdu); + } else { + input_message.length = length; + input_message.value = discard_const(data); + } + + input_token.length = sig->length; + input_token.value = sig->data; + + maj_stat = gss_verify_mic(&min_stat, + gssapi_context, + &input_message, + &input_token, + &qop_state); + if (GSS_ERROR(maj_stat)) { + char *error_string = gssapi_error_string(NULL, + maj_stat, + min_stat, + mech); + DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string)); + talloc_free(error_string); + + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; +} diff --git a/auth/kerberos/gssapi_helper.h b/auth/kerberos/gssapi_helper.h new file mode 100644 index 00000000000..f40adf1540c --- /dev/null +++ b/auth/kerberos/gssapi_helper.h @@ -0,0 +1,55 @@ +/* + Unix SMB/CIFS implementation. + GSSAPI helper functions + + Copyright (C) Stefan Metzmacher 2008,2015 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef AUTH_KERBEROS_GSSAPI_HELPER_H +#define AUTH_KERBEROS_GSSAPI_HELPER_H 1 + +size_t gssapi_get_sig_size(gss_ctx_id_t gssapi_context, + const gss_OID mech, + uint32_t gss_want_flags, + size_t data_size); +NTSTATUS gssapi_seal_packet(gss_ctx_id_t gssapi_context, + const gss_OID mech, + bool hdr_signing, size_t sig_size, + uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + TALLOC_CTX *mem_ctx, + DATA_BLOB *sig); +NTSTATUS gssapi_unseal_packet(gss_ctx_id_t gssapi_context, + const gss_OID mech, + bool hdr_signing, + uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + const DATA_BLOB *sig); +NTSTATUS gssapi_sign_packet(gss_ctx_id_t gssapi_context, + const gss_OID mech, + bool hdr_signing, + const uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + TALLOC_CTX *mem_ctx, + DATA_BLOB *sig); +NTSTATUS gssapi_check_packet(gss_ctx_id_t gssapi_context, + const gss_OID mech, + bool hdr_signing, + const uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + const DATA_BLOB *sig); + +#endif /* AUTH_KERBEROS_GSSAPI_HELPER_H */ diff --git a/auth/kerberos/gssapi_pac.c b/auth/kerberos/gssapi_pac.c index 99181a13091..c6fa9092080 100644 --- a/auth/kerberos/gssapi_pac.c +++ b/auth/kerberos/gssapi_pac.c @@ -54,7 +54,7 @@ const gss_OID_desc * const gss_mech_krb5_wrong = krb5_gss_oid_array+2; gss_OID_desc gse_sesskey_inq_oid = { GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH, - (void *)GSS_KRB5_INQ_SSPI_SESSION_KEY_OID + discard_const(GSS_KRB5_INQ_SSPI_SESSION_KEY_OID) }; #ifndef GSS_KRB5_SESSION_KEY_ENCTYPE_OID @@ -64,7 +64,7 @@ gss_OID_desc gse_sesskey_inq_oid = { gss_OID_desc gse_sesskeytype_oid = { GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH, - (void *)GSS_KRB5_SESSION_KEY_ENCTYPE_OID + discard_const(GSS_KRB5_SESSION_KEY_ENCTYPE_OID) }; /* The Heimdal OID for getting the PAC */ @@ -236,7 +236,7 @@ NTSTATUS gssapi_get_session_key(TALLOC_CTX *mem_ctx, if (keytype) { int diflen, i; - const char *p; + const uint8_t *p; if (set->count < 2) { @@ -266,7 +266,7 @@ NTSTATUS gssapi_get_session_key(TALLOC_CTX *mem_ctx, gss_maj = gss_release_buffer_set(&gss_min, &set); return NT_STATUS_OK; } - p = (uint8_t *)set->elements[1].value + gse_sesskeytype_oid.length; + p = (const uint8_t *)set->elements[1].value + gse_sesskeytype_oid.length; diflen = set->elements[1].length - gse_sesskeytype_oid.length; if (diflen <= 0) { gss_maj = gss_release_buffer_set(&gss_min, &set); @@ -307,9 +307,17 @@ char *gssapi_error_string(TALLOC_CTX *mem_ctx, disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE, mech, &msg_ctx, &maj_error_message); + if (disp_maj_stat != 0) { + maj_error_message.value = NULL; + maj_error_message.length = 0; + } disp_maj_stat = gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE, mech, &msg_ctx, &min_error_message); + if (disp_maj_stat != 0) { + min_error_message.value = NULL; + min_error_message.length = 0; + } maj_error_string = talloc_strndup(mem_ctx, (char *)maj_error_message.value, diff --git a/auth/kerberos/wscript_build b/auth/kerberos/wscript_build index 15b48894770..1fa1b51138d 100755 --- a/auth/kerberos/wscript_build +++ b/auth/kerberos/wscript_build @@ -1,5 +1,4 @@ #!/usr/bin/env python bld.SAMBA_SUBSYSTEM('KRB5_PAC', - source='gssapi_pac.c kerberos_pac.c', - allow_warnings=True, + source='gssapi_pac.c kerberos_pac.c gssapi_helper.c', deps='gssapi_krb5 ndr-krb5pac krb5samba') diff --git a/auth/ntlmssp/gensec_ntlmssp.c b/auth/ntlmssp/gensec_ntlmssp.c index 567258914af..329d8eb4751 100644 --- a/auth/ntlmssp/gensec_ntlmssp.c +++ b/auth/ntlmssp/gensec_ntlmssp.c @@ -105,6 +105,15 @@ bool gensec_ntlmssp_have_feature(struct gensec_security *gensec_security, if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) { return true; } + if (feature & GENSEC_FEATURE_NEW_SPNEGO) { + if (!ntlmssp_state->session_key.length) { + return false; + } + if (!(ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) { + return false; + } + return ntlmssp_state->new_spnego; + } return false; } diff --git a/auth/ntlmssp/gensec_ntlmssp_server.c b/auth/ntlmssp/gensec_ntlmssp_server.c index 69c56fbbfbb..6147b140fa5 100644 --- a/auth/ntlmssp/gensec_ntlmssp_server.c +++ b/auth/ntlmssp/gensec_ntlmssp_server.c @@ -34,7 +34,7 @@ #include "auth/gensec/gensec_internal.h" #include "auth/common_auth.h" #include "param/param.h" - +#include "param/loadparm.h" /** * Return the credentials of a logged on user, including session keys @@ -98,6 +98,9 @@ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security) const char *netbios_domain; const char *dns_name; const char *dns_domain; + enum server_role role; + + role = lpcfg_server_role(gensec_security->settings->lp_ctx); nt_status = gensec_ntlmssp_start(gensec_security); NT_STATUS_NOT_OK_RETURN(nt_status); @@ -117,13 +120,32 @@ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security) ntlmssp_state->expected_state = NTLMSSP_NEGOTIATE; - if (lpcfg_lanman_auth(gensec_security->settings->lp_ctx) && + ntlmssp_state->allow_lm_response = + lpcfg_lanman_auth(gensec_security->settings->lp_ctx); + + if (ntlmssp_state->allow_lm_response && gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "allow_lm_key", false)) { ntlmssp_state->allow_lm_key = true; } + if (lpcfg_map_to_guest(gensec_security->settings->lp_ctx) != NEVER_MAP_TO_GUEST) { + /* + * map to guest is not secure anyway, so + * try to make it work and don't try to + * negotiate new_spnego and MIC checking + */ + ntlmssp_state->force_old_spnego = true; + } + + if (role == ROLE_ACTIVE_DIRECTORY_DC) { + /* + * map to guest is not supported on an AD DC. + */ + ntlmssp_state->force_old_spnego = false; + } + ntlmssp_state->neg_flags = NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_VERSION; @@ -147,18 +169,31 @@ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security) ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; } + if (ntlmssp_state->allow_lm_key) { + ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY; + } + if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; + + if (gensec_security->want_features & GENSEC_FEATURE_LDAP_STYLE) { + /* + * We need to handle NTLMSSP_NEGOTIATE_SIGN as + * NTLMSSP_NEGOTIATE_SEAL if GENSEC_FEATURE_LDAP_STYLE + * is requested. + */ + ntlmssp_state->force_wrap_seal = true; + } } if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; } - if (lpcfg_server_role(gensec_security->settings->lp_ctx) == ROLE_STANDALONE) { + if (role == ROLE_STANDALONE) { ntlmssp_state->server.is_standalone = true; } else { ntlmssp_state->server.is_standalone = false; @@ -215,6 +250,9 @@ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security) ntlmssp_state->server.dns_domain = talloc_strdup(ntlmssp_state, dns_domain); NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.dns_domain); + ntlmssp_state->neg_flags |= ntlmssp_state->required_flags; + ntlmssp_state->conf_flags = ntlmssp_state->neg_flags; + return NT_STATUS_OK; } diff --git a/auth/ntlmssp/ntlmssp.c b/auth/ntlmssp/ntlmssp.c index 916b376b111..4abab88627a 100644 --- a/auth/ntlmssp/ntlmssp.c +++ b/auth/ntlmssp/ntlmssp.c @@ -48,6 +48,10 @@ static const struct ntlmssp_callbacks { .command = NTLMSSP_INITIAL, .sync_fn = ntlmssp_client_initial, },{ + .role = NTLMSSP_CLIENT, + .command = NTLMSSP_NEGOTIATE, + .sync_fn = gensec_ntlmssp_resume_ccache, + },{ .role = NTLMSSP_SERVER, .command = NTLMSSP_NEGOTIATE, .sync_fn = gensec_ntlmssp_server_negotiate, @@ -82,6 +86,15 @@ static NTSTATUS gensec_ntlmssp_update_find(struct gensec_security *gensec_securi if (!input.length) { switch (gensec_ntlmssp->ntlmssp_state->role) { case NTLMSSP_CLIENT: + if (gensec_ntlmssp->ntlmssp_state->resume_ccache) { + /* + * make sure gensec_ntlmssp_resume_ccache() + * will be called + */ + ntlmssp_command = NTLMSSP_NEGOTIATE; + break; + } + ntlmssp_command = NTLMSSP_INITIAL; break; case NTLMSSP_SERVER: @@ -166,6 +179,30 @@ NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, return NT_STATUS_OK; } +static NTSTATUS gensec_ntlmssp_may_reset_crypto(struct gensec_security *gensec_security, + bool full_reset) +{ + struct gensec_ntlmssp_context *gensec_ntlmssp = + talloc_get_type_abort(gensec_security->private_data, + struct gensec_ntlmssp_context); + struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state; + NTSTATUS status; + bool reset_seqnums = full_reset; + + if (!gensec_ntlmssp_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { + return NT_STATUS_OK; + } + + status = ntlmssp_sign_reset(ntlmssp_state, reset_seqnums); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Could not reset NTLMSSP signing/sealing system (error was: %s)\n", + nt_errstr(status))); + return status; + } + + return NT_STATUS_OK; +} + static const char *gensec_ntlmssp_oids[] = { GENSEC_OID_NTLMSSP, NULL @@ -180,6 +217,7 @@ static const struct gensec_security_ops gensec_ntlmssp_security_ops = { .server_start = gensec_ntlmssp_server_start, .magic = gensec_ntlmssp_magic, .update = gensec_ntlmssp_update, + .may_reset_crypto= gensec_ntlmssp_may_reset_crypto, .sig_size = gensec_ntlmssp_sig_size, .sign_packet = gensec_ntlmssp_sign_packet, .check_packet = gensec_ntlmssp_check_packet, @@ -194,6 +232,15 @@ static const struct gensec_security_ops gensec_ntlmssp_security_ops = { .priority = GENSEC_NTLMSSP }; +static const struct gensec_security_ops gensec_ntlmssp_resume_ccache_ops = { + .name = "ntlmssp_resume_ccache", + .client_start = gensec_ntlmssp_resume_ccache_start, + .update = gensec_ntlmssp_update, + .session_key = gensec_ntlmssp_session_key, + .have_feature = gensec_ntlmssp_have_feature, + .enabled = true, + .priority = GENSEC_NTLMSSP +}; _PUBLIC_ NTSTATUS gensec_ntlmssp_init(void) { @@ -206,16 +253,58 @@ _PUBLIC_ NTSTATUS gensec_ntlmssp_init(void) return ret; } + ret = gensec_register(&gensec_ntlmssp_resume_ccache_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register '%s' gensec backend!\n", + gensec_ntlmssp_resume_ccache_ops.name)); + return ret; + } + return ret; } +static struct gensec_security *gensec_find_child_by_ops(struct gensec_security *gensec_security, + const struct gensec_security_ops *ops) +{ + struct gensec_security *current = gensec_security; + + while (current != NULL) { + if (current->ops == ops) { + return current; + } + + current = current->child_security; + } + + return NULL; +} + uint32_t gensec_ntlmssp_neg_flags(struct gensec_security *gensec_security) { struct gensec_ntlmssp_context *gensec_ntlmssp; - if (gensec_security->ops != &gensec_ntlmssp_security_ops) { + + gensec_security = gensec_find_child_by_ops(gensec_security, + &gensec_ntlmssp_security_ops); + if (gensec_security == NULL) { return 0; } + gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data, struct gensec_ntlmssp_context); return gensec_ntlmssp->ntlmssp_state->neg_flags; } + +const char *gensec_ntlmssp_server_domain(struct gensec_security *gensec_security) +{ + struct gensec_ntlmssp_context *gensec_ntlmssp; + + gensec_security = gensec_find_child_by_ops(gensec_security, + &gensec_ntlmssp_security_ops); + if (gensec_security == NULL) { + return NULL; + } + + gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data, + struct gensec_ntlmssp_context); + return gensec_ntlmssp->ntlmssp_state->server.netbios_domain; +} diff --git a/auth/ntlmssp/ntlmssp.h b/auth/ntlmssp/ntlmssp.h index 6061cd0951c..24127686312 100644 --- a/auth/ntlmssp/ntlmssp.h +++ b/auth/ntlmssp/ntlmssp.h @@ -62,7 +62,9 @@ struct ntlmssp_state bool unicode; bool use_ntlmv2; bool use_ccache; + bool resume_ccache; bool use_nt_response; /* Set to 'False' to debug what happens when the NT response is omited */ + bool allow_lm_response;/* The LM_RESPONSE code is not very secure... */ bool allow_lm_key; /* The LM_KEY code is not very secure... */ const char *user; @@ -70,9 +72,15 @@ struct ntlmssp_state uint8_t *nt_hash; uint8_t *lm_hash; + DATA_BLOB negotiate_blob; + DATA_BLOB challenge_blob; + bool new_spnego; + bool force_old_spnego; + struct { const char *netbios_name; const char *netbios_domain; + struct AV_PAIR_LIST av_pair_list; } client; struct { @@ -81,6 +89,8 @@ struct ntlmssp_state const char *netbios_domain; const char *dns_name; const char *dns_domain; + NTTIME challenge_endtime; + struct AV_PAIR_LIST av_pair_list; } server; DATA_BLOB internal_chal; /* Random challenge as supplied to the client for NTLM authentication */ @@ -90,8 +100,12 @@ struct ntlmssp_state DATA_BLOB nt_resp; DATA_BLOB session_key; + uint32_t conf_flags; + uint32_t required_flags; uint32_t neg_flags; /* the current state of negotiation with the NTLMSSP partner */ + bool force_wrap_seal; + union ntlmssp_crypt_state *crypt; }; @@ -123,6 +137,8 @@ NTSTATUS ntlmssp_unwrap(struct ntlmssp_state *ntlmssp_stae, TALLOC_CTX *out_mem_ctx, const DATA_BLOB *in, DATA_BLOB *out); +NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state, + bool reset_seqnums); NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state); bool ntlmssp_blob_matches_magic(const DATA_BLOB *blob); @@ -132,3 +148,4 @@ bool ntlmssp_blob_matches_magic(const DATA_BLOB *blob); NTSTATUS gensec_ntlmssp_init(void); uint32_t gensec_ntlmssp_neg_flags(struct gensec_security *gensec_security); +const char *gensec_ntlmssp_server_domain(struct gensec_security *gensec_security); diff --git a/auth/ntlmssp/ntlmssp_client.c b/auth/ntlmssp/ntlmssp_client.c index d8531e4c2e9..b4196157c81 100644 --- a/auth/ntlmssp/ntlmssp_client.c +++ b/auth/ntlmssp/ntlmssp_client.c @@ -34,6 +34,7 @@ struct auth_session_info; #include "auth/ntlmssp/ntlmssp_private.h" #include "../librpc/gen_ndr/ndr_ntlmssp.h" #include "../auth/ntlmssp/ntlmssp_ndr.h" +#include "../nsswitch/libwbclient/wbclient.h" /********************************************************************* Client side NTLMSSP @@ -57,38 +58,18 @@ NTSTATUS ntlmssp_client_initial(struct gensec_security *gensec_security, talloc_get_type_abort(gensec_security->private_data, struct gensec_ntlmssp_context); struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state; - const char *domain = ntlmssp_state->client.netbios_domain; - const char *workstation = ntlmssp_state->client.netbios_name; NTSTATUS status; - - /* These don't really matter in the initial packet, so don't panic if they are not set */ - if (!domain) { - domain = ""; - } - - if (!workstation) { - workstation = ""; - } - - if (ntlmssp_state->unicode) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE; - } else { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM; - } - - if (ntlmssp_state->use_ntlmv2) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; - } + const DATA_BLOB version_blob = ntlmssp_version_blob(); /* generate the ntlmssp negotiate packet */ status = msrpc_gen(out_mem_ctx, - out, "CddAA", + out, "CddAAb", "NTLMSSP", NTLMSSP_NEGOTIATE, ntlmssp_state->neg_flags, - domain, - workstation); - + "", /* domain */ + "", /* workstation */ + version_blob.data, version_blob.length); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("ntlmssp_client_initial: failed to generate " "ntlmssp negotiate packet\n")); @@ -109,6 +90,122 @@ NTSTATUS ntlmssp_client_initial(struct gensec_security *gensec_security, } } + ntlmssp_state->negotiate_blob = data_blob_dup_talloc(ntlmssp_state, + *out); + if (ntlmssp_state->negotiate_blob.length != out->length) { + return NT_STATUS_NO_MEMORY; + } + + ntlmssp_state->expected_state = NTLMSSP_CHALLENGE; + + return NT_STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS gensec_ntlmssp_resume_ccache(struct gensec_security *gensec_security, + TALLOC_CTX *out_mem_ctx, + DATA_BLOB in, DATA_BLOB *out) +{ + struct gensec_ntlmssp_context *gensec_ntlmssp = + talloc_get_type_abort(gensec_security->private_data, + struct gensec_ntlmssp_context); + struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state; + uint32_t neg_flags = 0; + uint32_t ntlmssp_command; + NTSTATUS status; + bool ok; + + *out = data_blob_null; + + if (in.length == 0) { + /* + * This is compat code for older callers + * which were missing the "initial_blob"/"negotiate_blob". + * + * That means we can't calculate the NTLMSSP_MIC + * field correctly and need to force the + * old_spnego behaviour. + */ + DEBUG(10, ("%s: in.length==%u force_old_spnego!\n", + __func__, (unsigned int)in.length)); + ntlmssp_state->force_old_spnego = true; + ntlmssp_state->neg_flags |= ntlmssp_state->required_flags; + ntlmssp_state->required_flags = 0; + ntlmssp_state->expected_state = NTLMSSP_CHALLENGE; + return NT_STATUS_MORE_PROCESSING_REQUIRED; + } + + /* parse the NTLMSSP packet */ + + if (in.length > UINT16_MAX) { + DEBUG(1, ("%s: reject large request of length %u\n", + __func__, (unsigned int)in.length)); + return NT_STATUS_INVALID_PARAMETER; + } + + ok = msrpc_parse(ntlmssp_state, &in, "Cdd", + "NTLMSSP", + &ntlmssp_command, + &neg_flags); + if (!ok) { + DEBUG(1, ("%s: failed to parse NTLMSSP Negotiate of length %u\n", + __func__, (unsigned int)in.length)); + dump_data(2, in.data, in.length); + return NT_STATUS_INVALID_PARAMETER; + } + + if (ntlmssp_command != NTLMSSP_NEGOTIATE) { + DEBUG(1, ("%s: no NTLMSSP Negotiate message (length %u)\n", + __func__, (unsigned int)in.length)); + dump_data(2, in.data, in.length); + return NT_STATUS_INVALID_PARAMETER; + } + + ntlmssp_state->neg_flags = neg_flags; + DEBUG(3, ("Imported Negotiate flags:\n")); + debug_ntlmssp_flags(neg_flags); + + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_UNICODE) { + ntlmssp_state->unicode = true; + } else { + ntlmssp_state->unicode = false; + } + + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) { + gensec_security->want_features |= GENSEC_FEATURE_SIGN; + + ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN; + } + + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) { + gensec_security->want_features |= GENSEC_FEATURE_SEAL; + + ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN; + ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL; + } + + ntlmssp_state->neg_flags |= ntlmssp_state->required_flags; + ntlmssp_state->conf_flags = ntlmssp_state->neg_flags; + + if (DEBUGLEVEL >= 10) { + struct NEGOTIATE_MESSAGE *negotiate = talloc( + ntlmssp_state, struct NEGOTIATE_MESSAGE); + if (negotiate != NULL) { + status = ntlmssp_pull_NEGOTIATE_MESSAGE( + &in, negotiate, negotiate); + if (NT_STATUS_IS_OK(status)) { + NDR_PRINT_DEBUG(NEGOTIATE_MESSAGE, + negotiate); + } + TALLOC_FREE(negotiate); + } + } + + ntlmssp_state->negotiate_blob = data_blob_dup_talloc(ntlmssp_state, + in); + if (ntlmssp_state->negotiate_blob.length != in.length) { + return NT_STATUS_NO_MEMORY; + } + ntlmssp_state->expected_state = NTLMSSP_CHALLENGE; return NT_STATUS_MORE_PROCESSING_REQUIRED; @@ -147,7 +244,13 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, DATA_BLOB encrypted_session_key = data_blob(NULL, 0); NTSTATUS nt_status; int flags = 0; - const char *user, *domain; + const char *user = NULL, *domain = NULL, *workstation = NULL; + bool is_anonymous = false; + const DATA_BLOB version_blob = ntlmssp_version_blob(); + const NTTIME *server_timestamp = NULL; + uint8_t mic_buffer[NTLMSSP_MIC_SIZE] = { 0, }; + DATA_BLOB mic_blob = data_blob_const(mic_buffer, sizeof(mic_buffer)); + HMACMD5Context ctx; TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx); if (!mem_ctx) { @@ -172,7 +275,11 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, DEBUG(3, ("Got challenge flags:\n")); debug_ntlmssp_flags(chal_flags); - ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, ntlmssp_state->allow_lm_key); + nt_status = ntlmssp_handle_neg_flags(ntlmssp_state, + chal_flags, "challenge"); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } if (ntlmssp_state->unicode) { if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) { @@ -181,7 +288,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, chal_parse_string = "CdUdbdd"; chal_parse_string_short = "CdUdb"; } - auth_gen_string = "CdBBUUUBd"; + auth_gen_string = "CdBBUUUBdbb"; } else { if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) { chal_parse_string = "CdAdbddB"; @@ -190,7 +297,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, chal_parse_string_short = "CdAdb"; } - auth_gen_string = "CdBBAAABd"; + auth_gen_string = "CdBBAAABdbb"; } if (!msrpc_parse(mem_ctx, @@ -244,7 +351,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, } /* TODO: parse struct_blob and fill in the rest */ ntlmssp_state->server.netbios_name = ""; - ntlmssp_state->server.netbios_domain = server_domain; + ntlmssp_state->server.netbios_domain = talloc_move(ntlmssp_state, &server_domain); ntlmssp_state->server.dns_name = ""; ntlmssp_state->server.dns_domain = ""; @@ -253,9 +360,118 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, return NT_STATUS_INVALID_PARAMETER; } + is_anonymous = cli_credentials_is_anonymous(gensec_security->credentials); cli_credentials_get_ntlm_username_domain(gensec_security->credentials, mem_ctx, &user, &domain); + workstation = cli_credentials_get_workstation(gensec_security->credentials); + + if (user == NULL) { + DEBUG(10, ("User is NULL, returning INVALID_PARAMETER\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + if (domain == NULL) { + DEBUG(10, ("Domain is NULL, returning INVALID_PARAMETER\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + if (workstation == NULL) { + DEBUG(10, ("Workstation is NULL, returning INVALID_PARAMETER\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + if (is_anonymous) { + ntlmssp_state->neg_flags |= NTLMSSP_ANONYMOUS; + /* + * don't use the ccache for anonymous auth + */ + ntlmssp_state->use_ccache = false; + } + if (ntlmssp_state->use_ccache) { + struct samr_Password *nt_hash = NULL; + + /* + * If we have a password given we don't + * use the ccache + */ + nt_hash = cli_credentials_get_nt_hash(gensec_security->credentials, + mem_ctx); + if (nt_hash != NULL) { + ZERO_STRUCTP(nt_hash); + TALLOC_FREE(nt_hash); + ntlmssp_state->use_ccache = false; + } + } + + if (ntlmssp_state->use_ccache) { + struct wbcCredentialCacheParams params; + struct wbcCredentialCacheInfo *info = NULL; + struct wbcAuthErrorInfo *error = NULL; + struct wbcNamedBlob auth_blobs[2]; + const struct wbcBlob *wbc_auth_blob = NULL; + const struct wbcBlob *wbc_session_key = NULL; + wbcErr wbc_status; + int i; + bool new_spnego = false; + + params.account_name = user; + params.domain_name = domain; + params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP; + + auth_blobs[0].name = "challenge_blob"; + auth_blobs[0].flags = 0; + auth_blobs[0].blob.data = in.data; + auth_blobs[0].blob.length = in.length; + auth_blobs[1].name = "negotiate_blob"; + auth_blobs[1].flags = 0; + auth_blobs[1].blob.data = ntlmssp_state->negotiate_blob.data; + auth_blobs[1].blob.length = ntlmssp_state->negotiate_blob.length; + params.num_blobs = ARRAY_SIZE(auth_blobs); + params.blobs = auth_blobs; + + wbc_status = wbcCredentialCache(¶ms, &info, &error); + wbcFreeMemory(error); + if (!WBC_ERROR_IS_OK(wbc_status)) { + return NT_STATUS_WRONG_CREDENTIAL_HANDLE; + } + + for (i=0; i<info->num_blobs; i++) { + if (strequal(info->blobs[i].name, "auth_blob")) { + wbc_auth_blob = &info->blobs[i].blob; + } + if (strequal(info->blobs[i].name, "session_key")) { + wbc_session_key = &info->blobs[i].blob; + } + if (strequal(info->blobs[i].name, "new_spnego")) { + new_spnego = true; + } + } + if ((wbc_auth_blob == NULL) || (wbc_session_key == NULL)) { + wbcFreeMemory(info); + return NT_STATUS_WRONG_CREDENTIAL_HANDLE; + } + + session_key = data_blob_talloc(mem_ctx, + wbc_session_key->data, + wbc_session_key->length); + if (session_key.length != wbc_session_key->length) { + wbcFreeMemory(info); + return NT_STATUS_NO_MEMORY; + } + *out = data_blob_talloc(mem_ctx, + wbc_auth_blob->data, + wbc_auth_blob->length); + if (out->length != wbc_auth_blob->length) { + wbcFreeMemory(info); + return NT_STATUS_NO_MEMORY; + } + ntlmssp_state->new_spnego = new_spnego; + + wbcFreeMemory(info); + goto done; + } + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { flags |= CLI_CRED_NTLM2; } @@ -265,15 +481,159 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, if (ntlmssp_state->use_nt_response) { flags |= CLI_CRED_NTLM_AUTH; } - if (lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx)) { + if (ntlmssp_state->allow_lm_response) { flags |= CLI_CRED_LANMAN_AUTH; } + if (target_info.length != 0 && !is_anonymous) { + struct AV_PAIR *pairs = NULL; + uint32_t count = 0; + enum ndr_err_code err; + struct AV_PAIR *timestamp = NULL; + struct AV_PAIR *eol = NULL; + uint32_t i = 0; + const char *service = NULL; + const char *hostname = NULL; + + err = ndr_pull_struct_blob(&target_info, + ntlmssp_state, + &ntlmssp_state->server.av_pair_list, + (ndr_pull_flags_fn_t)ndr_pull_AV_PAIR_LIST); + if (!NDR_ERR_CODE_IS_SUCCESS(err)) { + return ndr_map_error2ntstatus(err); + } + + count = ntlmssp_state->server.av_pair_list.count; + /* + * We need room for Flags, SingleHost, + * ChannelBindings and Target + */ + pairs = talloc_zero_array(ntlmssp_state, struct AV_PAIR, + count + 4); + if (pairs == NULL) { + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < count; i++) { + pairs[i] = ntlmssp_state->server.av_pair_list.pair[i]; + } + + ntlmssp_state->client.av_pair_list.count = count; + ntlmssp_state->client.av_pair_list.pair = pairs; + + eol = ndr_ntlmssp_find_av(&ntlmssp_state->client.av_pair_list, + MsvAvEOL); + if (eol == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + timestamp = ndr_ntlmssp_find_av(&ntlmssp_state->client.av_pair_list, + MsvAvTimestamp); + if (timestamp != NULL) { + uint32_t sign_features = + GENSEC_FEATURE_SESSION_KEY | + GENSEC_FEATURE_SIGN | + GENSEC_FEATURE_SEAL; + + server_timestamp = ×tamp->Value.AvTimestamp; + + if (ntlmssp_state->force_old_spnego) { + sign_features = 0; + } + + if (gensec_security->want_features & sign_features) { + struct AV_PAIR *av_flags = NULL; + + av_flags = ndr_ntlmssp_find_av(&ntlmssp_state->client.av_pair_list, + MsvAvFlags); + if (av_flags == NULL) { + av_flags = eol; + eol++; + count++; + *eol = *av_flags; + av_flags->AvId = MsvAvFlags; + av_flags->Value.AvFlags = 0; + } + + av_flags->Value.AvFlags |= NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE; + ntlmssp_state->new_spnego = true; + } + } + + { + struct AV_PAIR *SingleHost = NULL; + + SingleHost = eol; + eol++; + count++; + *eol = *SingleHost; + + /* + * This is not really used, but we want to + * add some more random bytes and match + * Windows. + */ + SingleHost->AvId = MsvAvSingleHost; + SingleHost->Value.AvSingleHost.token_info.Flags = 0; + SingleHost->Value.AvSingleHost.token_info.TokenIL = 0; + generate_random_buffer(SingleHost->Value.AvSingleHost.token_info.MachineId, + sizeof(SingleHost->Value.AvSingleHost.token_info.MachineId)); + SingleHost->Value.AvSingleHost.remaining = data_blob_null; + } + + { + struct AV_PAIR *ChannelBindings = NULL; + + ChannelBindings = eol; + eol++; + count++; + *eol = *ChannelBindings; + + /* + * gensec doesn't support channel bindings yet, + * but we want to match Windows on the wire + */ + ChannelBindings->AvId = MsvChannelBindings; + memset(ChannelBindings->Value.ChannelBindings, 0, + sizeof(ChannelBindings->Value.ChannelBindings)); + } + + service = gensec_get_target_service(gensec_security); + hostname = gensec_get_target_hostname(gensec_security); + if (service != NULL && hostname != NULL) { + struct AV_PAIR *target = NULL; + + target = eol; + eol++; + count++; + *eol = *target; + + target->AvId = MsvAvTargetName; + target->Value.AvTargetName = talloc_asprintf(pairs, "%s/%s", + service, + hostname); + if (target->Value.AvTargetName == NULL) { + return NT_STATUS_NO_MEMORY; + } + } + + ntlmssp_state->client.av_pair_list.count = count; + ntlmssp_state->client.av_pair_list.pair = pairs; + + err = ndr_push_struct_blob(&target_info, + ntlmssp_state, + &ntlmssp_state->client.av_pair_list, + (ndr_push_flags_fn_t)ndr_push_AV_PAIR_LIST); + if (!NDR_ERR_CODE_IS_SUCCESS(err)) { + return NT_STATUS_NO_MEMORY; + } + } + nt_status = cli_credentials_get_ntlm_response(gensec_security->credentials, mem_ctx, - &flags, challenge_blob, target_info, + &flags, challenge_blob, + server_timestamp, target_info, &lm_response, &nt_response, &lm_session_key, &session_key); - if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } @@ -292,7 +652,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, } if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) - && lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx) && lm_session_key.length == 16) { + && ntlmssp_state->allow_lm_key && lm_session_key.length == 16) { DATA_BLOB new_session_key = data_blob_talloc(mem_ctx, NULL, 16); if (lm_response.length == 24) { SMBsesskeygen_lm_sess_key(lm_session_key.data, lm_response.data, @@ -325,9 +685,6 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, session_key = data_blob_talloc(mem_ctx, client_session_key, sizeof(client_session_key)); } - DEBUG(3, ("NTLMSSP: Set final flags:\n")); - debug_ntlmssp_flags(ntlmssp_state->neg_flags); - /* this generates the actual auth packet */ nt_status = msrpc_gen(mem_ctx, out, auth_gen_string, @@ -337,22 +694,48 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, nt_response.data, nt_response.length, domain, user, - cli_credentials_get_workstation(gensec_security->credentials), + workstation, encrypted_session_key.data, encrypted_session_key.length, - ntlmssp_state->neg_flags); + ntlmssp_state->neg_flags, + version_blob.data, version_blob.length, + mic_blob.data, mic_blob.length); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); return nt_status; } + /* + * We always include the MIC, even without: + * av_flags->Value.AvFlags |= NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE; + * ntlmssp_state->new_spnego = true; + * + * This matches a Windows client. + */ + hmac_md5_init_limK_to_64(session_key.data, + session_key.length, + &ctx); + hmac_md5_update(ntlmssp_state->negotiate_blob.data, + ntlmssp_state->negotiate_blob.length, + &ctx); + hmac_md5_update(in.data, in.length, &ctx); + hmac_md5_update(out->data, out->length, &ctx); + hmac_md5_final(mic_buffer, &ctx); + memcpy(out->data + NTLMSSP_MIC_OFFSET, mic_buffer, NTLMSSP_MIC_SIZE); + +done: + data_blob_free(&ntlmssp_state->negotiate_blob); + ntlmssp_state->session_key = session_key; talloc_steal(ntlmssp_state, session_key.data); + DEBUG(3, ("NTLMSSP: Set final flags:\n")); + debug_ntlmssp_flags(ntlmssp_state->neg_flags); + talloc_steal(out_mem_ctx, out->data); ntlmssp_state->expected_state = NTLMSSP_DONE; - if (gensec_security->want_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL)) { + if (gensec_ntlmssp_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { nt_status = ntlmssp_sign_init(ntlmssp_state); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", @@ -398,7 +781,9 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security) ntlmssp_state->use_nt_response = gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "send_nt_reponse", true); - ntlmssp_state->allow_lm_key = (lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx) + ntlmssp_state->allow_lm_response = lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx); + + ntlmssp_state->allow_lm_key = (ntlmssp_state->allow_lm_response && (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "allow_lm_key", false) || gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "lm_key", false))); @@ -408,8 +793,15 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security) ntlmssp_state->neg_flags = NTLMSSP_NEGOTIATE_NTLM | + NTLMSSP_NEGOTIATE_VERSION | NTLMSSP_REQUEST_TARGET; + if (ntlmssp_state->unicode) { + ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE; + } else { + ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM; + } + if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "128bit", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_128; } @@ -437,6 +829,16 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security) ntlmssp_state->use_ntlmv2 = false; } + if (ntlmssp_state->use_ntlmv2) { + ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_NTLM2; + ntlmssp_state->allow_lm_response = false; + ntlmssp_state->allow_lm_key = false; + } + + if (ntlmssp_state->allow_lm_key) { + ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY; + } + if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { /* * We need to set this to allow a later SetPassword @@ -447,15 +849,57 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security) * that it thinks is only used for NTLMSSP signing and * sealing. (It is actually pulled out and used directly) */ - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; + ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; + ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN; + + if (gensec_security->want_features & GENSEC_FEATURE_LDAP_STYLE) { + /* + * We need to handle NTLMSSP_NEGOTIATE_SIGN as + * NTLMSSP_NEGOTIATE_SEAL if GENSEC_FEATURE_LDAP_STYLE + * is requested. + */ + ntlmssp_state->force_wrap_seal = true; + /* + * We want also work against old Samba servers + * which didn't had GENSEC_FEATURE_LDAP_STYLE + * we negotiate SEAL too. We may remove this + * in a few years. As all servers should have + * GENSEC_FEATURE_LDAP_STYLE by then. + */ + ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL; + } } if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; + ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN; + ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL; + } + if (gensec_security->want_features & GENSEC_FEATURE_NTLM_CCACHE) { + ntlmssp_state->use_ccache = true; } + ntlmssp_state->neg_flags |= ntlmssp_state->required_flags; + ntlmssp_state->conf_flags = ntlmssp_state->neg_flags; + + return NT_STATUS_OK; +} + +NTSTATUS gensec_ntlmssp_resume_ccache_start(struct gensec_security *gensec_security) +{ + struct gensec_ntlmssp_context *gensec_ntlmssp = NULL; + NTSTATUS status; + + status = gensec_ntlmssp_client_start(gensec_security); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data, + struct gensec_ntlmssp_context); + gensec_ntlmssp->ntlmssp_state->use_ccache = false; + gensec_ntlmssp->ntlmssp_state->resume_ccache = true; + gensec_ntlmssp->ntlmssp_state->expected_state = NTLMSSP_NEGOTIATE; + return NT_STATUS_OK; } diff --git a/auth/ntlmssp/ntlmssp_ndr.c b/auth/ntlmssp/ntlmssp_ndr.c index af24be9dc22..c8b16ccd413 100644 --- a/auth/ntlmssp/ntlmssp_ndr.c +++ b/auth/ntlmssp/ntlmssp_ndr.c @@ -25,6 +25,7 @@ #define NTLMSSP_PULL_MESSAGE(type, blob, mem_ctx, r) \ do { \ enum ndr_err_code __ndr_err; \ + ZERO_STRUCTP(r); /* in order to deal with unset neg flags */\ __ndr_err = ndr_pull_struct_blob(blob, mem_ctx, r, \ (ndr_pull_flags_fn_t)ndr_pull_ ##type); \ if (!NDR_ERR_CODE_IS_SUCCESS(__ndr_err)) { \ diff --git a/auth/ntlmssp/ntlmssp_private.h b/auth/ntlmssp/ntlmssp_private.h index 778d638b2ad..e938e5cad8f 100644 --- a/auth/ntlmssp/ntlmssp_private.h +++ b/auth/ntlmssp/ntlmssp_private.h @@ -59,8 +59,9 @@ NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, /* The following definitions come from auth/ntlmssp_util.c */ void debug_ntlmssp_flags(uint32_t neg_flags); -void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, - uint32_t neg_flags, bool allow_lm); +NTSTATUS ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, + uint32_t neg_flags, const char *name); +const DATA_BLOB ntlmssp_version_blob(void); /* The following definitions come from auth/ntlmssp_server.c */ @@ -88,6 +89,10 @@ NTSTATUS ntlmssp_client_initial(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, DATA_BLOB in, DATA_BLOB *out) ; +NTSTATUS gensec_ntlmssp_resume_ccache(struct gensec_security *gensec_security, + TALLOC_CTX *out_mem_ctx, + DATA_BLOB in, DATA_BLOB *out); + /** * Next state function for the Challenge Packet. Generate an auth packet. * @@ -101,6 +106,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, const DATA_BLOB in, DATA_BLOB *out) ; NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security); +NTSTATUS gensec_ntlmssp_resume_ccache_start(struct gensec_security *gensec_security); /* The following definitions come from auth/ntlmssp/gensec_ntlmssp_server.c */ diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c index 2f3f0bb723f..954964196d1 100644 --- a/auth/ntlmssp/ntlmssp_server.c +++ b/auth/ntlmssp/ntlmssp_server.c @@ -21,6 +21,7 @@ */ #include "includes.h" +#include "lib/util/time_basic.h" #include "auth/ntlmssp/ntlmssp.h" #include "auth/ntlmssp/ntlmssp_private.h" #include "../librpc/gen_ndr/ndr_ntlmssp.h" @@ -84,6 +85,27 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security uint8_t cryptkey[8]; const char *target_name; NTSTATUS status; + struct timeval tv_now = timeval_current(); + /* + * See [MS-NLMP] + * + * Windows NT 4.0, windows_2000: use 30 minutes, + * Windows XP, Windows Server 2003, Windows Vista, + * Windows Server 2008, Windows 7, and Windows Server 2008 R2 + * use 36 hours. + * + * Newer systems doesn't check this, likely because the + * connectionless NTLMSSP is no longer supported. + * + * As we expect the AUTHENTICATION_MESSAGE to arrive + * directly after the NEGOTIATE_MESSAGE (typically less than + * as 1 second later). We use a hard timeout of 30 Minutes. + * + * We don't look at AUTHENTICATE_MESSAGE.NtChallengeResponse.TimeStamp + * instead we just remember our own time. + */ + uint32_t max_lifetime = 30 * 60; + struct timeval tv_end = timeval_add(&tv_now, max_lifetime, 0); /* parse the NTLMSSP packet */ #if 0 @@ -91,6 +113,12 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security #endif if (request.length) { + if (request.length > UINT16_MAX) { + DEBUG(1, ("ntlmssp_server_negotiate: reject large request of length %u\n", + (unsigned int)request.length)); + return NT_STATUS_INVALID_PARAMETER; + } + if ((request.length < 16) || !msrpc_parse(ntlmssp_state, &request, "Cdd", "NTLMSSP", &ntlmssp_command, @@ -117,7 +145,10 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security } } - ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, ntlmssp_state->allow_lm_key); + status = ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, "negotiate"); + if (!NT_STATUS_IS_OK(status)){ + return status; + } /* Ask our caller what challenge they would like in the packet */ if (auth_context->get_ntlm_challenge) { @@ -138,6 +169,7 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security */ chal_flags = ntlmssp_state->neg_flags; + ntlmssp_state->server.challenge_endtime = timeval_to_nttime(&tv_end); /* get the right name to fill in as 'target' */ target_name = ntlmssp_target_name(ntlmssp_state, @@ -150,16 +182,48 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security cryptkey, 8); /* This creates the 'blob' of names that appears at the end of the packet */ - if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) - { - status = msrpc_gen(ntlmssp_state, &struct_blob, "aaaaa", - MsvAvNbDomainName, target_name, - MsvAvNbComputerName, ntlmssp_state->server.netbios_name, - MsvAvDnsDomainName, ntlmssp_state->server.dns_domain, - MsvAvDnsComputerName, ntlmssp_state->server.dns_name, - MsvAvEOL, ""); - if (!NT_STATUS_IS_OK(status)) { - return status; + if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) { + enum ndr_err_code err; + struct AV_PAIR *pairs = NULL; + uint32_t count = 5; + + pairs = talloc_zero_array(ntlmssp_state, struct AV_PAIR, count + 1); + if (pairs == NULL) { + return NT_STATUS_NO_MEMORY; + } + + pairs[0].AvId = MsvAvNbDomainName; + pairs[0].Value.AvNbDomainName = target_name; + + pairs[1].AvId = MsvAvNbComputerName; + pairs[1].Value.AvNbComputerName = ntlmssp_state->server.netbios_name; + + pairs[2].AvId = MsvAvDnsDomainName; + pairs[2].Value.AvDnsDomainName = ntlmssp_state->server.dns_domain; + + pairs[3].AvId = MsvAvDnsComputerName; + pairs[3].Value.AvDnsComputerName= ntlmssp_state->server.dns_name; + + if (!ntlmssp_state->force_old_spnego) { + pairs[4].AvId = MsvAvTimestamp; + pairs[4].Value.AvTimestamp = + timeval_to_nttime(&tv_now); + count += 1; + + pairs[5].AvId = MsvAvEOL; + } else { + pairs[4].AvId = MsvAvEOL; + } + + ntlmssp_state->server.av_pair_list.count = count; + ntlmssp_state->server.av_pair_list.pair = pairs; + + err = ndr_push_struct_blob(&struct_blob, + ntlmssp_state, + &ntlmssp_state->server.av_pair_list, + (ndr_push_flags_fn_t)ndr_push_AV_PAIR_LIST); + if (!NDR_ERR_CODE_IS_SUCCESS(err)) { + return NT_STATUS_NO_MEMORY; } } else { struct_blob = data_blob_null; @@ -168,29 +232,7 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security { /* Marshal the packet in the right format, be it unicode or ASCII */ const char *gen_string; - DATA_BLOB version_blob = data_blob_null; - - if (chal_flags & NTLMSSP_NEGOTIATE_VERSION) { - enum ndr_err_code err; - struct ntlmssp_VERSION vers; - - /* "What Windows returns" as a version number. */ - ZERO_STRUCT(vers); - vers.ProductMajorVersion = NTLMSSP_WINDOWS_MAJOR_VERSION_6; - vers.ProductMinorVersion = NTLMSSP_WINDOWS_MINOR_VERSION_1; - vers.ProductBuild = 0; - vers.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3; - - err = ndr_push_struct_blob(&version_blob, - ntlmssp_state, - &vers, - (ndr_push_flags_fn_t)ndr_push_ntlmssp_VERSION); - - if (!NDR_ERR_CODE_IS_SUCCESS(err)) { - data_blob_free(&struct_blob); - return NT_STATUS_NO_MEMORY; - } - } + const DATA_BLOB version_blob = ntlmssp_version_blob(); if (ntlmssp_state->unicode) { gen_string = "CdUdbddBb"; @@ -209,13 +251,10 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security version_blob.data, version_blob.length); if (!NT_STATUS_IS_OK(status)) { - data_blob_free(&version_blob); data_blob_free(&struct_blob); return status; } - data_blob_free(&version_blob); - if (DEBUGLEVEL >= 10) { struct CHALLENGE_MESSAGE *challenge = talloc( ntlmssp_state, struct CHALLENGE_MESSAGE); @@ -234,6 +273,18 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security data_blob_free(&struct_blob); + ntlmssp_state->negotiate_blob = data_blob_dup_talloc(ntlmssp_state, + request); + if (ntlmssp_state->negotiate_blob.length != request.length) { + return NT_STATUS_NO_MEMORY; + } + + ntlmssp_state->challenge_blob = data_blob_dup_talloc(ntlmssp_state, + *reply); + if (ntlmssp_state->challenge_blob.length != reply->length) { + return NT_STATUS_NO_MEMORY; + } + ntlmssp_state->expected_state = NTLMSSP_AUTH; return NT_STATUS_MORE_PROCESSING_REQUIRED; @@ -266,19 +317,24 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security, struct auth4_context *auth_context = gensec_security->auth_context; uint32_t ntlmssp_command, auth_flags; NTSTATUS nt_status; - + const unsigned int version_len = 8; + DATA_BLOB version_blob = data_blob_null; + const unsigned int mic_len = NTLMSSP_MIC_SIZE; + DATA_BLOB mic_blob = data_blob_null; uint8_t session_nonce_hash[16]; - const char *parse_string; + bool ok; + struct timeval endtime; + bool expired = false; #if 0 file_save("ntlmssp_auth.dat", request.data, request.length); #endif if (ntlmssp_state->unicode) { - parse_string = "CdBBUUUBd"; + parse_string = "CdBBUUUBdbb"; } else { - parse_string = "CdBBAAABd"; + parse_string = "CdBBAAABdbb"; } /* zero these out */ @@ -291,7 +347,7 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security, ntlmssp_state->client.netbios_name = NULL; /* now the NTLMSSP encoded auth hashes */ - if (!msrpc_parse(ntlmssp_state, &request, parse_string, + ok = msrpc_parse(ntlmssp_state, &request, parse_string, "NTLMSSP", &ntlmssp_command, &ntlmssp_state->lm_resp, @@ -300,7 +356,35 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security, &ntlmssp_state->user, &ntlmssp_state->client.netbios_name, &state->encrypted_session_key, - &auth_flags)) { + &auth_flags, + &version_blob, version_len, + &mic_blob, mic_len); + if (!ok) { + DEBUG(10, ("ntlmssp_server_auth: failed to parse NTLMSSP (nonfatal):\n")); + dump_data(10, request.data, request.length); + + data_blob_free(&version_blob); + data_blob_free(&mic_blob); + + if (ntlmssp_state->unicode) { + parse_string = "CdBBUUUBd"; + } else { + parse_string = "CdBBAAABd"; + } + + ok = msrpc_parse(ntlmssp_state, &request, parse_string, + "NTLMSSP", + &ntlmssp_command, + &ntlmssp_state->lm_resp, + &ntlmssp_state->nt_resp, + &ntlmssp_state->domain, + &ntlmssp_state->user, + &ntlmssp_state->client.netbios_name, + &state->encrypted_session_key, + &auth_flags); + } + + if (!ok) { DEBUG(10, ("ntlmssp_server_auth: failed to parse NTLMSSP (nonfatal):\n")); dump_data(10, request.data, request.length); @@ -333,8 +417,14 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security, talloc_steal(state, state->encrypted_session_key.data); - if (auth_flags) - ntlmssp_handle_neg_flags(ntlmssp_state, auth_flags, ntlmssp_state->allow_lm_key); + if (auth_flags != 0) { + nt_status = ntlmssp_handle_neg_flags(ntlmssp_state, + auth_flags, + "authenticate"); + if (!NT_STATUS_IS_OK(nt_status)){ + return nt_status; + } + } if (DEBUGLEVEL >= 10) { struct AUTHENTICATE_MESSAGE *authenticate = talloc( @@ -363,6 +453,192 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security, file_save("lmhash1.dat", &ntlmssp_state->lm_resp.data, &ntlmssp_state->lm_resp.length); #endif + if (ntlmssp_state->nt_resp.length > 24) { + struct NTLMv2_RESPONSE v2_resp; + enum ndr_err_code err; + uint32_t i = 0; + uint32_t count = 0; + const struct AV_PAIR *flags = NULL; + const struct AV_PAIR *eol = NULL; + uint32_t av_flags = 0; + + err = ndr_pull_struct_blob(&ntlmssp_state->nt_resp, + ntlmssp_state, + &v2_resp, + (ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE); + if (!NDR_ERR_CODE_IS_SUCCESS(err)) { + nt_status = ndr_map_error2ntstatus(err); + DEBUG(1,("%s: failed to parse NTLMv2_RESPONSE of length %zu for " + "user=[%s] domain=[%s] workstation=[%s] - %s %s\n", + __func__, ntlmssp_state->nt_resp.length, + ntlmssp_state->user, ntlmssp_state->domain, + ntlmssp_state->client.netbios_name, + ndr_errstr(err), nt_errstr(nt_status))); + return nt_status; + } + + if (DEBUGLVL(10)) { + NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &v2_resp); + } + + eol = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs, + MsvAvEOL); + if (eol == NULL) { + DEBUG(1,("%s: missing MsvAvEOL for " + "user=[%s] domain=[%s] workstation=[%s]\n", + __func__, ntlmssp_state->user, ntlmssp_state->domain, + ntlmssp_state->client.netbios_name)); + return NT_STATUS_INVALID_PARAMETER; + } + + flags = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs, + MsvAvFlags); + if (flags != NULL) { + av_flags = flags->Value.AvFlags; + } + + if (av_flags & NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE) { + if (mic_blob.length != NTLMSSP_MIC_SIZE) { + DEBUG(1,("%s: mic_blob.length[%u] for " + "user=[%s] domain=[%s] workstation=[%s]\n", + __func__, + (unsigned)mic_blob.length, + ntlmssp_state->user, + ntlmssp_state->domain, + ntlmssp_state->client.netbios_name)); + return NT_STATUS_INVALID_PARAMETER; + } + + if (request.length < + (NTLMSSP_MIC_OFFSET + NTLMSSP_MIC_SIZE)) + { + DEBUG(1,("%s: missing MIC " + "request.length[%u] for " + "user=[%s] domain=[%s] workstation=[%s]\n", + __func__, + (unsigned)request.length, + ntlmssp_state->user, + ntlmssp_state->domain, + ntlmssp_state->client.netbios_name)); + return NT_STATUS_INVALID_PARAMETER; + } + + ntlmssp_state->new_spnego = true; + } + + count = ntlmssp_state->server.av_pair_list.count; + if (v2_resp.Challenge.AvPairs.count < count) { + return NT_STATUS_INVALID_PARAMETER; + } + + for (i = 0; i < count; i++) { + const struct AV_PAIR *sp = + &ntlmssp_state->server.av_pair_list.pair[i]; + const struct AV_PAIR *cp = NULL; + + if (sp->AvId == MsvAvEOL) { + continue; + } + + cp = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs, + sp->AvId); + if (cp == NULL) { + DEBUG(1,("%s: AvId 0x%x missing for" + "user=[%s] domain=[%s] " + "workstation=[%s]\n", + __func__, + (unsigned)sp->AvId, + ntlmssp_state->user, + ntlmssp_state->domain, + ntlmssp_state->client.netbios_name)); + return NT_STATUS_INVALID_PARAMETER; + } + + switch (cp->AvId) { +#define CASE_STRING(v) case Msv ## v: do { \ + int cmp; \ + if (sp->Value.v == NULL) { \ + return NT_STATUS_INTERNAL_ERROR; \ + } \ + if (cp->Value.v == NULL) { \ + DEBUG(1,("%s: invalid %s " \ + "got[%s] expect[%s] for " \ + "user=[%s] domain=[%s] workstation=[%s]\n", \ + __func__, #v, \ + cp->Value.v, \ + sp->Value.v, \ + ntlmssp_state->user, \ + ntlmssp_state->domain, \ + ntlmssp_state->client.netbios_name)); \ + return NT_STATUS_INVALID_PARAMETER; \ + } \ + cmp = strcmp(cp->Value.v, sp->Value.v); \ + if (cmp != 0) { \ + DEBUG(1,("%s: invalid %s " \ + "got[%s] expect[%s] for " \ + "user=[%s] domain=[%s] workstation=[%s]\n", \ + __func__, #v, \ + cp->Value.v, \ + sp->Value.v, \ + ntlmssp_state->user, \ + ntlmssp_state->domain, \ + ntlmssp_state->client.netbios_name)); \ + return NT_STATUS_INVALID_PARAMETER; \ + } \ +} while(0); break + CASE_STRING(AvNbComputerName); + CASE_STRING(AvNbDomainName); + CASE_STRING(AvDnsComputerName); + CASE_STRING(AvDnsDomainName); + CASE_STRING(AvDnsTreeName); + case MsvAvTimestamp: + if (cp->Value.AvTimestamp != sp->Value.AvTimestamp) { + struct timeval ct; + struct timeval st; + struct timeval_buf tmp1; + struct timeval_buf tmp2; + + nttime_to_timeval(&ct, + cp->Value.AvTimestamp); + nttime_to_timeval(&st, + sp->Value.AvTimestamp); + + DEBUG(1,("%s: invalid AvTimestamp " + "got[%s] expect[%s] for " + "user=[%s] domain=[%s] " + "workstation=[%s]\n", + __func__, + timeval_str_buf(&ct, true, &tmp1), + timeval_str_buf(&st, true, &tmp2), + ntlmssp_state->user, + ntlmssp_state->domain, + ntlmssp_state->client.netbios_name)); + return NT_STATUS_INVALID_PARAMETER; + } + break; + default: + /* + * This can't happen as we control + * ntlmssp_state->server.av_pair_list + */ + return NT_STATUS_INTERNAL_ERROR; + } + } + } + + nttime_to_timeval(&endtime, ntlmssp_state->server.challenge_endtime); + expired = timeval_expired(&endtime); + if (expired) { + struct timeval_buf tmp; + DEBUG(1,("%s: challenge invalid (expired %s) for " + "user=[%s] domain=[%s] workstation=[%s]\n", + __func__, + timeval_str_buf(&endtime, true, &tmp), + ntlmssp_state->user, ntlmssp_state->domain, + ntlmssp_state->client.netbios_name)); + return NT_STATUS_INVALID_PARAMETER; + } + /* NTLM2 uses a 'challenge' that is made of up both the server challenge, and a client challenge @@ -474,7 +750,8 @@ static NTSTATUS ntlmssp_server_check_password(struct gensec_security *gensec_sec static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security, struct gensec_ntlmssp_context *gensec_ntlmssp, - struct ntlmssp_server_auth_state *state) + struct ntlmssp_server_auth_state *state, + DATA_BLOB request) { struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state; DATA_BLOB user_session_key = state->user_session_key; @@ -591,7 +868,56 @@ static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security, talloc_steal(ntlmssp_state, session_key.data); } - if (ntlmssp_state->session_key.length) { + if (ntlmssp_state->new_spnego) { + HMACMD5Context ctx; + uint8_t mic_buffer[NTLMSSP_MIC_SIZE] = { 0, }; + int cmp; + + hmac_md5_init_limK_to_64(ntlmssp_state->session_key.data, + ntlmssp_state->session_key.length, + &ctx); + + hmac_md5_update(ntlmssp_state->negotiate_blob.data, + ntlmssp_state->negotiate_blob.length, + &ctx); + hmac_md5_update(ntlmssp_state->challenge_blob.data, + ntlmssp_state->challenge_blob.length, + &ctx); + + /* checked were we set ntlmssp_state->new_spnego */ + SMB_ASSERT(request.length > + (NTLMSSP_MIC_OFFSET + NTLMSSP_MIC_SIZE)); + + hmac_md5_update(request.data, NTLMSSP_MIC_OFFSET, &ctx); + hmac_md5_update(mic_buffer, NTLMSSP_MIC_SIZE, &ctx); + hmac_md5_update(request.data + + (NTLMSSP_MIC_OFFSET + NTLMSSP_MIC_SIZE), + request.length - + (NTLMSSP_MIC_OFFSET + NTLMSSP_MIC_SIZE), + &ctx); + hmac_md5_final(mic_buffer, &ctx); + + cmp = memcmp(request.data + NTLMSSP_MIC_OFFSET, + mic_buffer, NTLMSSP_MIC_SIZE); + if (cmp != 0) { + DEBUG(1,("%s: invalid NTLMSSP_MIC for " + "user=[%s] domain=[%s] workstation=[%s]\n", + __func__, + ntlmssp_state->user, + ntlmssp_state->domain, + ntlmssp_state->client.netbios_name)); + dump_data(1, request.data + NTLMSSP_MIC_OFFSET, + NTLMSSP_MIC_SIZE); + dump_data(1, mic_buffer, + NTLMSSP_MIC_SIZE); + return NT_STATUS_INVALID_PARAMETER; + } + } + + data_blob_free(&ntlmssp_state->negotiate_blob); + data_blob_free(&ntlmssp_state->challenge_blob); + + if (gensec_ntlmssp_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { nt_status = ntlmssp_sign_init(ntlmssp_state); } @@ -656,7 +982,7 @@ NTSTATUS gensec_ntlmssp_server_auth(struct gensec_security *gensec_security, ntlmssp_state->check_password, the ntlmssp_server_postpath can be done in a callback */ - nt_status = ntlmssp_server_postauth(gensec_security, gensec_ntlmssp, state); + nt_status = ntlmssp_server_postauth(gensec_security, gensec_ntlmssp, state, in); TALLOC_FREE(state); return nt_status; } diff --git a/auth/ntlmssp/ntlmssp_sign.c b/auth/ntlmssp/ntlmssp_sign.c index c0be91465b3..a9757258803 100644 --- a/auth/ntlmssp/ntlmssp_sign.c +++ b/auth/ntlmssp/ntlmssp_sign.c @@ -479,57 +479,18 @@ NTSTATUS ntlmssp_unwrap(struct ntlmssp_state *ntlmssp_state, &sig); } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) { - NTSTATUS status; - struct ntlmssp_crypt_direction save_direction; - if (in->length < NTLMSSP_SIG_SIZE) { return NT_STATUS_INVALID_PARAMETER; } sig.data = in->data; sig.length = NTLMSSP_SIG_SIZE; - *out = data_blob_talloc(out_mem_ctx, in->data + NTLMSSP_SIG_SIZE, in->length - NTLMSSP_SIG_SIZE); - - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - save_direction = ntlmssp_state->crypt->ntlm2.receiving; - } else { - save_direction = ntlmssp_state->crypt->ntlm; - } - - status = ntlmssp_check_packet(ntlmssp_state, - out->data, out->length, - out->data, out->length, - &sig); - if (!NT_STATUS_IS_OK(status)) { - NTSTATUS check_status = status; - /* - * The Windows LDAP libraries seems to have a bug - * and always use sealing even if only signing was - * negotiated. So we need to fallback. - */ - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - ntlmssp_state->crypt->ntlm2.receiving = save_direction; - } else { - ntlmssp_state->crypt->ntlm = save_direction; - } - - status = ntlmssp_unseal_packet(ntlmssp_state, - out->data, - out->length, - out->data, - out->length, - &sig); - if (NT_STATUS_IS_OK(status)) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; - } else { - status = check_status; - } - } + *out = data_blob_talloc(out_mem_ctx, in->data + NTLMSSP_SIG_SIZE, in->length - NTLMSSP_SIG_SIZE); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("NTLMSSP packet check for unwrap failed due to invalid signature\n")); - } - return status; + return ntlmssp_check_packet(ntlmssp_state, + out->data, out->length, + out->data, out->length, + &sig); } else { *out = data_blob_talloc(out_mem_ctx, in->data, in->length); if (!out->data) { @@ -542,20 +503,30 @@ NTSTATUS ntlmssp_unwrap(struct ntlmssp_state *ntlmssp_state, /** Initialise the state for NTLMSSP signing. */ -NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state) +NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state, + bool reset_seqnums) { DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n")); debug_ntlmssp_flags(ntlmssp_state->neg_flags); - if (ntlmssp_state->session_key.length < 8) { - DEBUG(3, ("NO session key, cannot intialise signing\n")); - return NT_STATUS_NO_USER_SESSION_KEY; + if (ntlmssp_state->crypt == NULL) { + return NT_STATUS_INVALID_PARAMETER_MIX; } - ntlmssp_state->crypt = talloc_zero(ntlmssp_state, - union ntlmssp_crypt_state); - if (ntlmssp_state->crypt == NULL) { - return NT_STATUS_NO_MEMORY; + if (ntlmssp_state->force_wrap_seal && + (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) + { + /* + * We need to handle NTLMSSP_NEGOTIATE_SIGN as + * NTLMSSP_NEGOTIATE_SEAL if GENSEC_FEATURE_LDAP_STYLE + * is requested. + * + * The negotiation of flags (and authentication) + * is completed when ntlmssp_sign_init() is called + * so we can safely pretent NTLMSSP_NEGOTIATE_SEAL + * was negotiated. + */ + ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; } if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { @@ -629,7 +600,9 @@ NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state) &ntlmssp_state->crypt->ntlm2.sending.seal_state); /* SEND: seq num */ - ntlmssp_state->crypt->ntlm2.sending.seq_num = 0; + if (reset_seqnums) { + ntlmssp_state->crypt->ntlm2.sending.seq_num = 0; + } /* RECV: sign key */ calc_ntlmv2_key(ntlmssp_state->crypt->ntlm2.receiving.sign_key, @@ -649,7 +622,9 @@ NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state) &ntlmssp_state->crypt->ntlm2.receiving.seal_state); /* RECV: seq num */ - ntlmssp_state->crypt->ntlm2.receiving.seq_num = 0; + if (reset_seqnums) { + ntlmssp_state->crypt->ntlm2.receiving.seq_num = 0; + } } else { uint8_t weak_session_key[8]; DATA_BLOB seal_session_key = ntlmssp_state->session_key; @@ -699,8 +674,26 @@ NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state) dump_arc4_state("NTLMv1 arc4 state:\n", &ntlmssp_state->crypt->ntlm.seal_state); - ntlmssp_state->crypt->ntlm.seq_num = 0; + if (reset_seqnums) { + ntlmssp_state->crypt->ntlm.seq_num = 0; + } } return NT_STATUS_OK; } + +NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state) +{ + if (ntlmssp_state->session_key.length < 8) { + DEBUG(3, ("NO session key, cannot intialise signing\n")); + return NT_STATUS_NO_USER_SESSION_KEY; + } + + ntlmssp_state->crypt = talloc_zero(ntlmssp_state, + union ntlmssp_crypt_state); + if (ntlmssp_state->crypt == NULL) { + return NT_STATUS_NO_MEMORY; + } + + return ntlmssp_sign_reset(ntlmssp_state, true); +} diff --git a/auth/ntlmssp/ntlmssp_util.c b/auth/ntlmssp/ntlmssp_util.c index 96793abfda1..4ae6101f025 100644 --- a/auth/ntlmssp/ntlmssp_util.c +++ b/auth/ntlmssp/ntlmssp_util.c @@ -25,6 +25,41 @@ #include "../auth/ntlmssp/ntlmssp.h" #include "../auth/ntlmssp/ntlmssp_private.h" +static void debug_ntlmssp_flags_raw(int level, uint32_t flags) +{ +#define _PRINT_FLAG_LINE(v) do { \ + if (flags & (v)) { \ + DEBUGADD(level, (" " #v "\n")); \ + } \ +} while (0) + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_UNICODE); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_OEM); + _PRINT_FLAG_LINE(NTLMSSP_REQUEST_TARGET); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_SIGN); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_SEAL); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_DATAGRAM); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_LM_KEY); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_NETWARE); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_NTLM); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_NT_ONLY); + _PRINT_FLAG_LINE(NTLMSSP_ANONYMOUS); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_ALWAYS_SIGN); + _PRINT_FLAG_LINE(NTLMSSP_TARGET_TYPE_DOMAIN); + _PRINT_FLAG_LINE(NTLMSSP_TARGET_TYPE_SERVER); + _PRINT_FLAG_LINE(NTLMSSP_TARGET_TYPE_SHARE); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_IDENTIFY); + _PRINT_FLAG_LINE(NTLMSSP_REQUEST_NON_NT_SESSION_KEY); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_TARGET_INFO); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_VERSION); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_128); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_KEY_EXCH); + _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_56); +} + /** * Print out the NTLMSSP flags for debugging * @param neg_flags The flags from the packet @@ -32,53 +67,15 @@ void debug_ntlmssp_flags(uint32_t neg_flags) { DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags)); - - if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_UNICODE\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_OEM) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM\n")); - if (neg_flags & NTLMSSP_REQUEST_TARGET) - DEBUGADD(4, (" NTLMSSP_REQUEST_TARGET\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_SIGN) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SIGN\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_SEAL) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SEAL\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_DATAGRAM) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DATAGRAM\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_LM_KEY\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NETWARE\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_NTLM) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n")); - if (neg_flags & NTLMSSP_REQUEST_NON_NT_SESSION_KEY) - DEBUGADD(4, (" NTLMSSP_REQUEST_NON_NT_SESSION_KEY\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM2\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_TARGET_INFO\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_VERSION) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_VERSION\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_128) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_128\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_KEY_EXCH\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_56) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_56\n")); + debug_ntlmssp_flags_raw(4, neg_flags); } -void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, - uint32_t neg_flags, bool allow_lm) +NTSTATUS ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, + uint32_t flags, const char *name) { - if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) { + uint32_t missing_flags = ntlmssp_state->required_flags; + + if (flags & NTLMSSP_NEGOTIATE_UNICODE) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE; ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM; ntlmssp_state->unicode = true; @@ -88,49 +85,69 @@ void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, ntlmssp_state->unicode = false; } - if ((neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) && allow_lm) { - /* other end forcing us to use LM */ - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY; - ntlmssp_state->use_ntlmv2 = false; - } else { + /* + * NTLMSSP_NEGOTIATE_NTLM2 (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) + * has priority over NTLMSSP_NEGOTIATE_LM_KEY + */ + if (!(flags & NTLMSSP_NEGOTIATE_NTLM2)) { + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; + } + + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; } - if (!(neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN; + if (!(flags & NTLMSSP_NEGOTIATE_LM_KEY)) { + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; } - if (!(neg_flags & NTLMSSP_NEGOTIATE_NTLM2)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; + if (!(flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) { + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN; } - if (!(neg_flags & NTLMSSP_NEGOTIATE_128)) { + if (!(flags & NTLMSSP_NEGOTIATE_128)) { ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128; } - if (!(neg_flags & NTLMSSP_NEGOTIATE_56)) { + if (!(flags & NTLMSSP_NEGOTIATE_56)) { ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56; } - if (!(neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) { + if (!(flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) { ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH; } - if (!(neg_flags & NTLMSSP_NEGOTIATE_SIGN)) { + if (!(flags & NTLMSSP_NEGOTIATE_SIGN)) { ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN; } - if (!(neg_flags & NTLMSSP_NEGOTIATE_SEAL)) { + if (!(flags & NTLMSSP_NEGOTIATE_SEAL)) { ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SEAL; } - if (!(neg_flags & NTLMSSP_NEGOTIATE_VERSION)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_VERSION; + if ((flags & NTLMSSP_REQUEST_TARGET)) { + ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET; } - if ((neg_flags & NTLMSSP_REQUEST_TARGET)) { - ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET; + missing_flags &= ~ntlmssp_state->neg_flags; + if (missing_flags != 0) { + HRESULT hres = HRES_SEC_E_UNSUPPORTED_FUNCTION; + NTSTATUS status = NT_STATUS(HRES_ERROR_V(hres)); + DEBUG(1, ("%s: Got %s flags[0x%08x] " + "- possible downgrade detected! " + "missing_flags[0x%08x] - %s\n", + __func__, name, + (unsigned)flags, + (unsigned)missing_flags, + nt_errstr(status))); + debug_ntlmssp_flags_raw(1, missing_flags); + DEBUGADD(4, ("neg_flags[0x%08x]\n", + (unsigned)ntlmssp_state->neg_flags)); + debug_ntlmssp_flags_raw(4, ntlmssp_state->neg_flags); + return status; } + + return NT_STATUS_OK; } /* Does this blob looks like it could be NTLMSSP? */ @@ -142,3 +159,38 @@ bool ntlmssp_blob_matches_magic(const DATA_BLOB *blob) return false; } } + +const DATA_BLOB ntlmssp_version_blob(void) +{ + /* + * This is a simplified version of + * + * enum ndr_err_code err; + * struct ntlmssp_VERSION vers; + * + * ZERO_STRUCT(vers); + * vers.ProductMajorVersion = NTLMSSP_WINDOWS_MAJOR_VERSION_6; + * vers.ProductMinorVersion = NTLMSSP_WINDOWS_MINOR_VERSION_1; + * vers.ProductBuild = 0; + * vers.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3; + * + * err = ndr_push_struct_blob(&version_blob, + * ntlmssp_state, + * &vers, + * (ndr_push_flags_fn_t)ndr_push_ntlmssp_VERSION); + * + * if (!NDR_ERR_CODE_IS_SUCCESS(err)) { + * data_blob_free(&struct_blob); + * return NT_STATUS_NO_MEMORY; + * } + */ + static const uint8_t version_buffer[8] = { + NTLMSSP_WINDOWS_MAJOR_VERSION_6, + NTLMSSP_WINDOWS_MINOR_VERSION_1, + 0x00, 0x00, /* product build */ + 0x00, 0x00, 0x00, /* reserved */ + NTLMSSP_REVISION_W2K3 + }; + + return data_blob_const(version_buffer, ARRAY_SIZE(version_buffer)); +} diff --git a/auth/ntlmssp/wscript_build b/auth/ntlmssp/wscript_build index 8725a8077d9..e28d4eb9dd8 100644 --- a/auth/ntlmssp/wscript_build +++ b/auth/ntlmssp/wscript_build @@ -7,7 +7,7 @@ bld.SAMBA_SUBSYSTEM('NTLMSSP_COMMON', ntlmssp_server.c ntlmssp_sign.c gensec_ntlmssp_server.c''', - deps='samba-util NDR_NTLMSSP MSRPC_PARSE NTLM_CHECK samba-credentials') + deps='samba-util NDR_NTLMSSP MSRPC_PARSE NTLM_CHECK samba-credentials wbclient') bld.SAMBA_MODULE('gensec_ntlmssp', source='''''', diff --git a/docs-xml/smbdotconf/ldap/ldapserverrequirestrongauth.xml b/docs-xml/smbdotconf/ldap/ldapserverrequirestrongauth.xml new file mode 100644 index 00000000000..02bdd811491 --- /dev/null +++ b/docs-xml/smbdotconf/ldap/ldapserverrequirestrongauth.xml @@ -0,0 +1,26 @@ +<samba:parameter name="ldap server require strong auth" + context="G" + type="enum" + enumlist="enum_ldap_server_require_strong_auth_vals" + xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> +<description> + <para> + The <smbconfoption name="ldap server require strong auth"/> defines whether + the ldap server requires ldap traffic to be signed or signed and encrypted (sealed). + Possible values are <emphasis>no</emphasis>, <emphasis>allow_sasl_over_tls</emphasis> + and <emphasis>yes</emphasis>. + </para> + + <para>A value of <emphasis>no</emphasis> allows simple and sasl binds over + all transports.</para> + + <para>A value of <emphasis>allow_sasl_over_tls</emphasis> allows simple and sasl binds + (without sign or seal) over TLS encrypted connections. Unencrypted connections only + allow sasl binds with sign or seal.</para> + + <para>A value of <emphasis>yes</emphasis> allows only simple binds + over TLS encrypted connections. Unencrypted connections only + allow sasl binds with sign or seal.</para> +</description> +<value type="default">yes</value> +</samba:parameter> diff --git a/docs-xml/smbdotconf/protocol/clientipcmaxprotocol.xml b/docs-xml/smbdotconf/protocol/clientipcmaxprotocol.xml new file mode 100644 index 00000000000..408af50940f --- /dev/null +++ b/docs-xml/smbdotconf/protocol/clientipcmaxprotocol.xml @@ -0,0 +1,29 @@ +<samba:parameter name="client ipc max protocol" + context="G" + type="enum" + function="_client_ipc_max_protocol" + enumlist="enum_protocol" + xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> +<description> + <para>The value of the parameter (a string) is the highest + protocol level that will be supported for IPC$ connections as DCERPC transport.</para> + + <para>Normally this option should not be set as the automatic + negotiation phase in the SMB protocol takes care of choosing + the appropriate protocol.</para> + + <para>The value <constant>default</constant> refers to the latest + supported protocol, currently <constant>SMB3_11</constant>.</para> + + <para>See <smbconfoption name="client max protocol"/> for a full list + of available protocols. The values CORE, COREPLUS, LANMAN1, LANMAN2 + are silently upgraded to NT1.</para> +</description> + +<related>client ipc min protocol</related> +<related>client min protocol</related> +<related>client max protocol</related> + +<value type="default">default</value> +<value type="example">SMB2_10</value> +</samba:parameter> diff --git a/docs-xml/smbdotconf/protocol/clientipcminprotocol.xml b/docs-xml/smbdotconf/protocol/clientipcminprotocol.xml new file mode 100644 index 00000000000..fc04b780b15 --- /dev/null +++ b/docs-xml/smbdotconf/protocol/clientipcminprotocol.xml @@ -0,0 +1,29 @@ +<samba:parameter name="client ipc min protocol" + context="G" + type="enum" + function="_client_ipc_min_protocol" + enumlist="enum_protocol" + xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> +<description> + <para>This setting controls the minimum protocol version that the + will be attempted to use for IPC$ connections as DCERPC transport.</para> + + <para>Normally this option should not be set as the automatic + negotiation phase in the SMB protocol takes care of choosing + the appropriate protocol.</para> + + <para>The value <constant>default</constant> refers to the higher value + of <constant>NT1</constant> and the effective value of + <smbconfoption name="client min protocol"/>.</para> + + <para>See <smbconfoption name="client max protocol"/> for a full list + of available protocols. The values CORE, COREPLUS, LANMAN1, LANMAN2 + are silently upgraded to NT1.</para> +</description> + +<related>client ipc max protocol</related> +<related>client min protocol</related> +<related>client max protocol</related> +<value type="default">default</value> +<value type="example">SMB3_11</value> +</samba:parameter> diff --git a/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml b/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml index 121eeb8e717..5a6c9af0a9a 100644 --- a/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml +++ b/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml @@ -73,13 +73,16 @@ negotiation phase in the SMB protocol takes care of choosing the appropriate protocol.</para> - <para>The value <constant>default</constant> refers to the default protocol in each - part of the code, currently <constant>NT1</constant> in the client tools and - <constant>SMB3_02</constant> in winbindd.</para> + <para>The value <constant>default</constant> refers to <constant>NT1</constant>.</para> + + <para>IPC$ connections for DCERPC e.g. in winbindd, are handled by the + <smbconfoption name="client ipc max protocol"/> option.</para> </description> <related>server max protocol</related> <related>client min protocol</related> +<related>client ipc min protocol</related> +<related>client ipc max protocol</related> <value type="default">default</value> <value type="example">LANMAN1</value> diff --git a/docs-xml/smbdotconf/protocol/clientminprotocol.xml b/docs-xml/smbdotconf/protocol/clientminprotocol.xml index 84e03eac902..052a42c7e40 100644 --- a/docs-xml/smbdotconf/protocol/clientminprotocol.xml +++ b/docs-xml/smbdotconf/protocol/clientminprotocol.xml @@ -13,10 +13,16 @@ <para>See <related>client max protocol</related> for a full list of available protocols.</para> + + <para>IPC$ connections for DCERPC e.g. in winbindd, are handled by the + <smbconfoption name="client ipc min protocol"/> option.</para> </description> <related>client max protocol</related> <related>server min protocol</related> +<related>client ipc min protocol</related> +<related>client ipc max protocol</related> + <value type="default">CORE</value> <value type="example">NT1</value> </samba:parameter> diff --git a/docs-xml/smbdotconf/protocol/clientusespnego.xml b/docs-xml/smbdotconf/protocol/clientusespnego.xml index c688a656f4f..e53874583b0 100644 --- a/docs-xml/smbdotconf/protocol/clientusespnego.xml +++ b/docs-xml/smbdotconf/protocol/clientusespnego.xml @@ -9,6 +9,11 @@ supporting servers (including WindowsXP, Windows2000 and Samba 3.0) to agree upon an authentication mechanism. This enables Kerberos authentication in particular.</para> + + <para>When <smbconfoption name="client NTLMv2 auth"/> is also set to + <constant>yes</constant> extended security (SPNEGO) is required + in order to use NTLMv2 only within NTLMSSP. This behavior was + introduced with the patches for CVE-2016-2111.</para> </description> <value type="default">yes</value> diff --git a/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml b/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml new file mode 100644 index 00000000000..03531adbfb3 --- /dev/null +++ b/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml @@ -0,0 +1,27 @@ +<samba:parameter name="allow dcerpc auth level connect" + context="G" + type="boolean" + xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> +<description> + <para>This option controls whether DCERPC services are allowed to + be used with DCERPC_AUTH_LEVEL_CONNECT, which provides authentication, + but no per message integrity nor privacy protection.</para> + + <para>Some interfaces like samr, lsarpc and netlogon have a hard-coded default of + <constant>no</constant> and epmapper, mgmt and rpcecho have a hard-coded default of + <constant>yes</constant>. + </para> + + <para>The behavior can be overwritten per interface name (e.g. lsarpc, netlogon, samr, srvsvc, + winreg, wkssvc ...) by using 'allow dcerpc auth level connect:interface = yes' as option.</para> + + <para>This option yields precedence to the implementation specific restrictions. + E.g. the drsuapi and backupkey protocols require DCERPC_AUTH_LEVEL_PRIVACY. + The dnsserver protocol requires DCERPC_AUTH_LEVEL_INTEGRITY. + </para> +</description> + +<value type="default">no</value> +<value type="example">yes</value> + +</samba:parameter> diff --git a/docs-xml/smbdotconf/security/clientipcsigning.xml b/docs-xml/smbdotconf/security/clientipcsigning.xml new file mode 100644 index 00000000000..0881c6c020e --- /dev/null +++ b/docs-xml/smbdotconf/security/clientipcsigning.xml @@ -0,0 +1,26 @@ +<samba:parameter name="client ipc signing" + context="G" + type="enum" + function="_client_ipc_signing" + enumlist="enum_smb_signing_vals" + xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> +<description> + <para>This controls whether the client is allowed or required to use SMB signing for IPC$ + connections as DCERPC transport. Possible values + are <emphasis>auto</emphasis>, <emphasis>mandatory</emphasis> + and <emphasis>disabled</emphasis>. + </para> + + <para>When set to mandatory or default, SMB signing is required.</para> + + <para>When set to auto, SMB signing is offered, but not enforced and if set + to disabled, SMB signing is not offered either.</para> + + <para>Connections from winbindd to Active Directory Domain Controllers + always enforce signing.</para> +</description> + +<related>client signing</related> + +<value type="default">default</value> +</samba:parameter> diff --git a/docs-xml/smbdotconf/security/clientntlmv2auth.xml b/docs-xml/smbdotconf/security/clientntlmv2auth.xml index 7f303565ba5..451e1803c75 100644 --- a/docs-xml/smbdotconf/security/clientntlmv2auth.xml +++ b/docs-xml/smbdotconf/security/clientntlmv2auth.xml @@ -28,6 +28,11 @@ NTLMv2 by default, and some sites (particularly those following 'best practice' security polices) only allow NTLMv2 responses, and not the weaker LM or NTLM.</para> + + <para>When <smbconfoption name="client use spnego"/> is also set to + <constant>yes</constant> extended security (SPNEGO) is required + in order to use NTLMv2 only within NTLMSSP. This behavior was + introduced with the patches for CVE-2016-2111.</para> </description> <value type="default">yes</value> </samba:parameter> diff --git a/docs-xml/smbdotconf/security/clientsigning.xml b/docs-xml/smbdotconf/security/clientsigning.xml index 34fce3e857c..354cc535248 100644 --- a/docs-xml/smbdotconf/security/clientsigning.xml +++ b/docs-xml/smbdotconf/security/clientsigning.xml @@ -9,11 +9,16 @@ and <emphasis>disabled</emphasis>. </para> - <para>When set to auto or default, SMB signing is offered, but not enforced. - When set to mandatory, SMB signing is required and if set - to disabled, SMB signing is not offered either. -</para> + <para>When set to auto or default, SMB signing is offered, but not enforced.</para> + + <para>When set to mandatory, SMB signing is required and if set + to disabled, SMB signing is not offered either.</para> + + <para>IPC$ connections for DCERPC e.g. in winbindd, are handled by the + <smbconfoption name="client ipc signing"/> option.</para> </description> +<related>client ipc signing</related> + <value type="default">default</value> </samba:parameter> diff --git a/docs-xml/smbdotconf/security/rawntlmv2auth.xml b/docs-xml/smbdotconf/security/rawntlmv2auth.xml new file mode 100644 index 00000000000..30e7280bc5d --- /dev/null +++ b/docs-xml/smbdotconf/security/rawntlmv2auth.xml @@ -0,0 +1,19 @@ +<samba:parameter name="raw NTLMv2 auth" + context="G" + type="boolean" + xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> +<description> + <para>This parameter determines whether or not <citerefentry><refentrytitle>smbd</refentrytitle> + <manvolnum>8</manvolnum></citerefentry> will allow SMB1 clients without + extended security (without SPNEGO) to use NTLMv2 authentication.</para> + + <para>If this option, <command moreinfo="none">lanman auth</command> + and <command moreinfo="none">ntlm auth</command> are all disabled, + then only clients with SPNEGO support will be permitted. + That means NTLMv2 is only supported within NTLMSSP.</para> +</description> + +<related>lanman auth</related> +<related>ntlm auth</related> +<value type="default">no</value> +</samba:parameter> diff --git a/docs-xml/smbdotconf/security/serversigning.xml b/docs-xml/smbdotconf/security/serversigning.xml index c94a3ee6ba2..1eb7c41952b 100644 --- a/docs-xml/smbdotconf/security/serversigning.xml +++ b/docs-xml/smbdotconf/security/serversigning.xml @@ -11,7 +11,7 @@ </para> <para>By default, and when smb signing is set to - <emphasis>default</emphasis>, smb signing enabled when + <emphasis>default</emphasis>, smb signing is required when <smbconfoption name="server role"/> is <emphasis>active directory domain controller</emphasis> and disabled otherwise.</para> diff --git a/docs-xml/smbdotconf/security/tlspriority.xml b/docs-xml/smbdotconf/security/tlspriority.xml new file mode 100644 index 00000000000..d399eef8eef --- /dev/null +++ b/docs-xml/smbdotconf/security/tlspriority.xml @@ -0,0 +1,22 @@ +<samba:parameter name="tls priority" + type="string" + context="G" + constant="1" + xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> + <description> + <para>This option can be set to a string describing the TLS protocols + to be supported in the parts of Samba that use GnuTLS, specifically + the AD DC. + </para> + <para>The default turns off SSLv3, as this protocol is no longer considered + secure after CVE-2014-3566 (otherwise known as POODLE) impacted SSLv3 use + in HTTPS applications. + </para> + <para>The valid options are described in the + <ulink url="http://gnutls.org/manual/html_node/Priority-Strings.html">GNUTLS + Priority-Strings documentation at http://gnutls.org/manual/html_node/Priority-Strings.html</ulink> + </para> + </description> + + <value type="default">NORMAL:-VERS-SSL3.0</value> +</samba:parameter> diff --git a/docs-xml/smbdotconf/security/tlsverifypeer.xml b/docs-xml/smbdotconf/security/tlsverifypeer.xml new file mode 100644 index 00000000000..4f47dd4db0d --- /dev/null +++ b/docs-xml/smbdotconf/security/tlsverifypeer.xml @@ -0,0 +1,47 @@ +<samba:parameter name="tls verify peer" + context="G" + type="enum" + enumlist="enum_tls_verify_peer_vals" + xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> +<description> + <para>This controls if and how strict the client will verify the peer's certificate and name. + Possible values are (in increasing order): + <constant>no_check</constant>, + <constant>ca_only</constant>, + <constant>ca_and_name_if_available</constant>, + <constant>ca_and_name</constant> + and + <constant>as_strict_as_possible</constant>.</para> + + <para>When set to <constant>no_check</constant> the certificate is not verified at + all, which allows trivial man in the middle attacks. + </para> + + <para>When set to <constant>ca_only</constant> the certificate is verified to + be signed from a ca specified in the <smbconfoption name="tls ca file"/> option. + Setting <smbconfoption name="tls ca file"/> to a valid file is required. + The certificate lifetime is also verified. If the <smbconfoption name="tls crl file"/> + option is configured, the certificate is also verified against the ca crl. + </para> + + <para>When set to <constant>ca_and_name_if_available</constant> all checks from + <constant>ca_only</constant> are performed. In addition, the peer hostname is verified + against the certificate's name, if it is provided by the application layer and + not given as an ip address string. + </para> + + <para>When set to <constant>ca_and_name</constant> all checks from + <constant>ca_and_name_if_available</constant> are performed. + In addition the peer hostname needs to be provided and even an ip + address is checked against the certificate's name. + </para> + + <para>When set to <constant>as_strict_as_possible</constant> all checks from + <constant>ca_and_name</constant> are performed. In addition the + <smbconfoption name="tls crl file"/> needs to be configured. + Future versions of Samba may implement additional checks. + </para> +</description> + +<value type="default">as_strict_as_possible</value> +</samba:parameter> diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index 2cc145d600d..4857c199cc5 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -2494,6 +2494,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "server max protocol", "SMB3"); lpcfg_do_global_parameter(lp_ctx, "client min protocol", "CORE"); lpcfg_do_global_parameter(lp_ctx, "client max protocol", "default"); + lpcfg_do_global_parameter(lp_ctx, "client ipc min protocol", "default"); + lpcfg_do_global_parameter(lp_ctx, "client ipc max protocol", "default"); lpcfg_do_global_parameter(lp_ctx, "security", "AUTO"); lpcfg_do_global_parameter(lp_ctx, "EncryptPasswords", "True"); lpcfg_do_global_parameter(lp_ctx, "ReadRaw", "True"); @@ -2509,8 +2511,11 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "ClientNTLMv2Auth", "True"); lpcfg_do_global_parameter(lp_ctx, "LanmanAuth", "False"); lpcfg_do_global_parameter(lp_ctx, "NTLMAuth", "True"); + lpcfg_do_global_parameter(lp_ctx, "RawNTLMv2Auth", "False"); lpcfg_do_global_parameter(lp_ctx, "client use spnego principal", "False"); + lpcfg_do_global_parameter(lp_ctx, "allow dcerpc auth level connect", "False"); + lpcfg_do_global_parameter(lp_ctx, "UnixExtensions", "True"); lpcfg_do_global_parameter(lp_ctx, "PreferredMaster", "Auto"); @@ -2533,6 +2538,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "template homedir", "/home/%D/%U"); lpcfg_do_global_parameter(lp_ctx, "client signing", "default"); + lpcfg_do_global_parameter(lp_ctx, "client ipc signing", "default"); lpcfg_do_global_parameter(lp_ctx, "server signing", "default"); lpcfg_do_global_parameter(lp_ctx, "use spnego", "True"); @@ -2553,9 +2559,11 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "min wins ttl", "21600"); lpcfg_do_global_parameter(lp_ctx, "tls enabled", "True"); + lpcfg_do_global_parameter(lp_ctx, "tls verify peer", "as_strict_as_possible"); lpcfg_do_global_parameter(lp_ctx, "tls keyfile", "tls/key.pem"); lpcfg_do_global_parameter(lp_ctx, "tls certfile", "tls/cert.pem"); lpcfg_do_global_parameter(lp_ctx, "tls cafile", "tls/ca.pem"); + lpcfg_do_global_parameter(lp_ctx, "tls priority", "NORMAL:-VERS-SSL3.0"); lpcfg_do_global_parameter(lp_ctx, "prefork children:smb", "4"); lpcfg_do_global_parameter(lp_ctx, "rndc command", "/usr/sbin/rndc"); @@ -2686,6 +2694,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "client ldap sasl wrapping", "sign"); + lpcfg_do_global_parameter(lp_ctx, "ldap server require strong auth", "yes"); + lpcfg_do_global_parameter(lp_ctx, "follow symlinks", "yes"); lpcfg_do_global_parameter(lp_ctx, "machine password timeout", "604800"); @@ -3176,6 +3186,39 @@ int lpcfg_client_max_protocol(struct loadparm_context *lp_ctx) return client_max_protocol; } +int lpcfg_client_ipc_min_protocol(struct loadparm_context *lp_ctx) +{ + int client_ipc_min_protocol = lpcfg__client_ipc_min_protocol(lp_ctx); + if (client_ipc_min_protocol == PROTOCOL_DEFAULT) { + client_ipc_min_protocol = lpcfg_client_min_protocol(lp_ctx); + } + if (client_ipc_min_protocol < PROTOCOL_NT1) { + return PROTOCOL_NT1; + } + return client_ipc_min_protocol; +} + +int lpcfg_client_ipc_max_protocol(struct loadparm_context *lp_ctx) +{ + int client_ipc_max_protocol = lpcfg__client_ipc_max_protocol(lp_ctx); + if (client_ipc_max_protocol == PROTOCOL_DEFAULT) { + return PROTOCOL_LATEST; + } + if (client_ipc_max_protocol < PROTOCOL_NT1) { + return PROTOCOL_NT1; + } + return client_ipc_max_protocol; +} + +int lpcfg_client_ipc_signing(struct loadparm_context *lp_ctx) +{ + int client_ipc_signing = lpcfg__client_ipc_signing(lp_ctx); + if (client_ipc_signing == SMB_SIGNING_DEFAULT) { + return SMB_SIGNING_REQUIRED; + } + return client_ipc_signing; +} + bool lpcfg_server_signing_allowed(struct loadparm_context *lp_ctx, bool *mandatory) { bool allowed = true; @@ -3210,10 +3253,13 @@ bool lpcfg_server_signing_allowed(struct loadparm_context *lp_ctx, bool *mandato case SMB_SIGNING_DESIRED: case SMB_SIGNING_IF_REQUIRED: break; - case SMB_SIGNING_DEFAULT: case SMB_SIGNING_OFF: allowed = false; break; + case SMB_SIGNING_DEFAULT: + case SMB_SIGNING_IPC_DEFAULT: + smb_panic(__location__); + break; } return allowed; diff --git a/lib/param/loadparm.h b/lib/param/loadparm.h index 11632de65cc..2d460dc3394 100644 --- a/lib/param/loadparm.h +++ b/lib/param/loadparm.h @@ -201,6 +201,12 @@ enum printing_types {PRINT_BSD,PRINT_SYSV,PRINT_AIX,PRINT_HPUX, #define ADS_AUTH_SASL_FORCE 0x0080 #define ADS_AUTH_USER_CREDS 0x0100 +enum ldap_server_require_strong_auth { + LDAP_SERVER_REQUIRE_STRONG_AUTH_NO, + LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS, + LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, +}; + /* DNS update settings */ enum dns_update_settings {DNS_UPDATE_OFF, DNS_UPDATE_ON, DNS_UPDATE_SIGNED}; diff --git a/lib/param/param_table.c b/lib/param/param_table.c index 530d8589578..4bc9198bf92 100644 --- a/lib/param/param_table.c +++ b/lib/param/param_table.c @@ -32,6 +32,7 @@ #include "lib/param/loadparm.h" #include "lib/param/param_global.h" #include "libcli/smb/smb_constants.h" +#include "source4/lib/tls/tls.h" #ifndef N_ #define N_(x) x @@ -122,6 +123,20 @@ static const struct enum_list enum_smb_signing_vals[] = { {-1, NULL} }; +static const struct enum_list enum_tls_verify_peer_vals[] = { + {TLS_VERIFY_PEER_NO_CHECK, + TLS_VERIFY_PEER_NO_CHECK_STRING}, + {TLS_VERIFY_PEER_CA_ONLY, + TLS_VERIFY_PEER_CA_ONLY_STRING}, + {TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE, + TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE_STRING}, + {TLS_VERIFY_PEER_CA_AND_NAME, + TLS_VERIFY_PEER_CA_AND_NAME_STRING}, + {TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE, + TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE_STRING}, + {-1, NULL} +}; + /* DNS update options. */ static const struct enum_list enum_dns_update_settings[] = { {DNS_UPDATE_OFF, "disabled"}, @@ -216,6 +231,18 @@ static const struct enum_list enum_ldap_sasl_wrapping[] = { {-1, NULL} }; +static const struct enum_list enum_ldap_server_require_strong_auth_vals[] = { + { LDAP_SERVER_REQUIRE_STRONG_AUTH_NO, "No" }, + { LDAP_SERVER_REQUIRE_STRONG_AUTH_NO, "False" }, + { LDAP_SERVER_REQUIRE_STRONG_AUTH_NO, "0" }, + { LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS, + "allow_sasl_over_tls" }, + { LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, "Yes" }, + { LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, "True" }, + { LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, "1" }, + {-1, NULL} +}; + static const struct enum_list enum_ldap_ssl[] = { {LDAP_SSL_OFF, "no"}, {LDAP_SSL_OFF, "off"}, @@ -728,6 +755,14 @@ struct parm_struct parm_table[] = { .flags = FLAG_ADVANCED, }, { + .label = "raw NTLMv2 auth", + .type = P_BOOL, + .p_class = P_GLOBAL, + .offset = GLOBAL_VAR(raw_ntlmv2_auth), + .special = NULL, + .enum_list = NULL, + }, + { .label = "client NTLMv2 auth", .type = P_BOOL, .p_class = P_GLOBAL, @@ -1663,6 +1698,14 @@ struct parm_struct parm_table[] = { .flags = FLAG_ADVANCED, }, { + .label = "ldap server require strong auth", + .type = P_ENUM, + .p_class = P_GLOBAL, + .offset = GLOBAL_VAR(ldap_server_require_strong_auth), + .special = NULL, + .enum_list = enum_ldap_server_require_strong_auth_vals + }, + { .label = "enable asu support", .type = P_BOOL, .p_class = P_GLOBAL, @@ -4433,6 +4476,54 @@ struct parm_struct parm_table[] = { .special = NULL, .enum_list = NULL }, + { + .label = "tls priority", + .type = P_STRING, + .p_class = P_GLOBAL, + .offset = GLOBAL_VAR(tls_priority), + .special = NULL, + .enum_list = NULL + }, + { + .label = "tls verify peer", + .type = P_ENUM, + .p_class = P_GLOBAL, + .offset = GLOBAL_VAR(tls_verify_peer), + .special = NULL, + .enum_list = enum_tls_verify_peer_vals, + }, + { + .label = "client ipc max protocol", + .type = P_ENUM, + .p_class = P_GLOBAL, + .offset = GLOBAL_VAR(_client_ipc_max_protocol), + .special = NULL, + .enum_list = enum_protocol, + }, + { + .label = "client ipc min protocol", + .type = P_ENUM, + .p_class = P_GLOBAL, + .offset = GLOBAL_VAR(_client_ipc_min_protocol), + .special = NULL, + .enum_list = enum_protocol, + }, + { + .label = "client ipc signing", + .type = P_ENUM, + .p_class = P_GLOBAL, + .offset = GLOBAL_VAR(_client_ipc_signing), + .special = NULL, + .enum_list = enum_smb_signing_vals, + }, + { + .label = "allow dcerpc auth level connect", + .type = P_BOOL, + .p_class = P_GLOBAL, + .offset = GLOBAL_VAR(allow_dcerpc_auth_level_connect), + .special = NULL, + .enum_list = NULL + }, {NULL, P_BOOL, P_NONE, 0, NULL, NULL, 0} }; diff --git a/lib/util/asn1.c b/lib/util/asn1.c index 90f950a1491..4778da498e2 100644 --- a/lib/util/asn1.c +++ b/lib/util/asn1.c @@ -20,6 +20,21 @@ #include "includes.h" #include "../lib/util/asn1.h" +struct nesting { + off_t start; + size_t taglen; /* for parsing */ + struct nesting *next; +}; + + +struct asn1_data { + uint8_t *data; + size_t length; + off_t ofs; + struct nesting *nesting; + bool has_error; +}; + /* allocate an asn1 structure */ struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx) { @@ -36,10 +51,36 @@ void asn1_free(struct asn1_data *data) talloc_free(data); } +bool asn1_has_error(const struct asn1_data *data) +{ + return data->has_error; +} + +void asn1_set_error(struct asn1_data *data) +{ + data->has_error = true; +} + +bool asn1_has_nesting(const struct asn1_data *data) +{ + return data->nesting != NULL; +} + +off_t asn1_current_ofs(const struct asn1_data *data) +{ + return data->ofs; +} + /* write to the ASN1 buffer, advancing the buffer pointer */ bool asn1_write(struct asn1_data *data, const void *p, int len) { if (data->has_error) return false; + + if ((len < 0) || (data->ofs + (size_t)len < data->ofs)) { + data->has_error = true; + return false; + } + if (data->length < data->ofs+len) { uint8_t *newp; newp = talloc_realloc(data, data->data, uint8_t, data->ofs+len); @@ -66,7 +107,9 @@ bool asn1_push_tag(struct asn1_data *data, uint8_t tag) { struct nesting *nesting; - asn1_write_uint8(data, tag); + if (!asn1_write_uint8(data, tag)) { + return false; + } nesting = talloc(data, struct nesting); if (!nesting) { data->has_error = true; @@ -85,6 +128,10 @@ bool asn1_pop_tag(struct asn1_data *data) struct nesting *nesting; size_t len; + if (data->has_error) { + return false; + } + nesting = data->nesting; if (!nesting) { @@ -184,6 +231,10 @@ static bool push_int_bigendian(struct asn1_data *data, unsigned int i, bool nega bool asn1_write_implicit_Integer(struct asn1_data *data, int i) { + if (data->has_error) { + return false; + } + if (i == -1) { /* -1 is special as it consists of all-0xff bytes. In push_int_bigendian this is the only case that is not @@ -984,6 +1035,26 @@ bool asn1_blob(const struct asn1_data *asn1, DATA_BLOB *blob) return true; } +bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, + DATA_BLOB *pblob) +{ + DATA_BLOB blob; + + if (!asn1_blob(asn1, &blob)) { + return false; + } + + *pblob = (DATA_BLOB) { .length = blob.length }; + pblob->data = talloc_move(mem_ctx, &blob.data); + + /* + * Stop access from here on + */ + asn1->has_error = true; + + return true; +} + /* Fill in an asn1 struct without making a copy */ @@ -994,35 +1065,7 @@ void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len) data->length = len; } -/* - check if a ASN.1 blob is a full tag -*/ -NTSTATUS asn1_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size) -{ - struct asn1_data *asn1 = asn1_init(NULL); - int size; - - NT_STATUS_HAVE_NO_MEMORY(asn1); - - asn1->data = blob.data; - asn1->length = blob.length; - if (!asn1_start_tag(asn1, tag)) { - talloc_free(asn1); - return STATUS_MORE_ENTRIES; - } - size = asn1_tag_remaining(asn1) + asn1->ofs; - - talloc_free(asn1); - - if (size > blob.length) { - return STATUS_MORE_ENTRIES; - } - - *packet_size = size; - return NT_STATUS_OK; -} - -NTSTATUS asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size) +int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size) { struct asn1_data asn1; size_t size; @@ -1034,14 +1077,14 @@ NTSTATUS asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size) ok = asn1_peek_tag_needed_size(&asn1, tag, &size); if (!ok) { - return NT_STATUS_INVALID_BUFFER_SIZE; + return EMSGSIZE; } if (size > blob.length) { *packet_size = size; - return STATUS_MORE_ENTRIES; + return EAGAIN; } *packet_size = size; - return NT_STATUS_OK; + return 0; } diff --git a/lib/util/asn1.h b/lib/util/asn1.h index 568b4e4cc8b..4eb8506d092 100644 --- a/lib/util/asn1.h +++ b/lib/util/asn1.h @@ -20,20 +20,8 @@ #ifndef _ASN_1_H #define _ASN_1_H -struct nesting { - off_t start; - size_t taglen; /* for parsing */ - struct nesting *next; -}; - -struct asn1_data { - uint8_t *data; - size_t length; - off_t ofs; - struct nesting *nesting; - bool has_error; -}; - +struct nesting; +struct asn1_data; typedef struct asn1_data ASN1_DATA; #define ASN1_APPLICATION(x) ((x)+0x60) @@ -54,6 +42,10 @@ typedef struct asn1_data ASN1_DATA; struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx); void asn1_free(struct asn1_data *data); +bool asn1_has_error(const struct asn1_data *data); +void asn1_set_error(struct asn1_data *data); +bool asn1_has_nesting(const struct asn1_data *data); +off_t asn1_current_ofs(const struct asn1_data *data); bool asn1_write(struct asn1_data *data, const void *p, int len); bool asn1_write_uint8(struct asn1_data *data, uint8_t v); bool asn1_push_tag(struct asn1_data *data, uint8_t tag); @@ -99,8 +91,9 @@ bool asn1_read_enumerated(struct asn1_data *data, int *v); bool asn1_check_enumerated(struct asn1_data *data, int v); bool asn1_write_enumerated(struct asn1_data *data, uint8_t v); bool asn1_blob(const struct asn1_data *asn1, DATA_BLOB *blob); +bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, + DATA_BLOB *pblob); void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len); -NTSTATUS asn1_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size); -NTSTATUS asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size); +int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size); #endif /* _ASN_1_H */ diff --git a/lib/util/tests/asn1_tests.c b/lib/util/tests/asn1_tests.c index 2c68cb435de..a91d7a7389a 100644 --- a/lib/util/tests/asn1_tests.c +++ b/lib/util/tests/asn1_tests.c @@ -337,8 +337,10 @@ static bool test_asn1_Integer(struct torture_context *tctx) if (!asn1_write_Integer(data, integer_tests[i].value)) goto err; - blob.data = data->data; - blob.length = data->length; + if (!asn1_blob(data, &blob)) { + goto err; + } + torture_assert_data_blob_equal(tctx, blob, integer_tests[i].blob, "asn1_write_Integer gave incorrect result"); if (!asn1_load(data, blob)) goto err; diff --git a/lib/util/util.c b/lib/util/util.c index 21d55c6af27..e21c3641f7e 100644 --- a/lib/util/util.c +++ b/lib/util/util.c @@ -530,7 +530,7 @@ void dump_data_cb(const uint8_t *buf, int len, if (i%16) { int n; n = 16 - (i%16); - cb(" ", private_data); + cb(" ", private_data); if (n>8) { cb(" ", private_data); } diff --git a/lib/util/util_net.c b/lib/util/util_net.c index d58855da5b2..e5b33aa0a7e 100644 --- a/lib/util/util_net.c +++ b/lib/util/util_net.c @@ -41,6 +41,115 @@ void zero_sockaddr(struct sockaddr_storage *pss) pss->ss_family = AF_INET; } +static char *normalize_ipv6_literal(const char *str, char *buf, size_t *_len) +{ +#define IPv6_LITERAL_NET ".ipv6-literal.net" + static const size_t llen = sizeof(IPv6_LITERAL_NET) - 1; + size_t len = *_len; + int cmp; + size_t i; + size_t idx_chars = 0; + size_t cnt_delimiter = 0; + size_t cnt_chars = 0; + + if (len <= llen) { + return false; + } + + /* ignore a trailing '.' */ + if (str[len - 1] == '.') { + len -= 1; + } + + len -= llen; + if (len >= INET6_ADDRSTRLEN) { + return NULL; + } + if (len < 2) { + return NULL; + } + + cmp = strncasecmp(&str[len], IPv6_LITERAL_NET, llen); + if (cmp != 0) { + return NULL; + } + + for (i = 0; i < len; i++) { + if (idx_chars != 0) { + break; + } + + switch (str[i]) { + case '-': + buf[i] = ':'; + cnt_chars = 0; + cnt_delimiter += 1; + break; + case 's': + buf[i] = '%'; + idx_chars += 1; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'a': + case 'A': + case 'b': + case 'B': + case 'c': + case 'C': + case 'd': + case 'D': + case 'e': + case 'E': + case 'f': + case 'F': + buf[i] = str[i]; + cnt_chars += 1; + break; + default: + return NULL; + } + if (cnt_chars > 4) { + return NULL; + } + if (cnt_delimiter > 7) { + return NULL; + } + } + + if (cnt_delimiter < 2) { + return NULL; + } + + for (; idx_chars != 0 && i < len; i++) { + switch (str[i]) { + case '%': + case ':': + return NULL; + default: + buf[i] = str[i]; + idx_chars += 1; + break; + } + } + + if (idx_chars == 1) { + return NULL; + } + + buf[i] = '\0'; + *_len = len; + return buf; +} + /** * Wrap getaddrinfo... */ @@ -49,6 +158,11 @@ bool interpret_string_addr_internal(struct addrinfo **ppres, { int ret; struct addrinfo hints; +#if defined(HAVE_IPV6) + char addr[INET6_ADDRSTRLEN*2] = { 0, }; + unsigned int scope_id = 0; + size_t len = strlen(str); +#endif ZERO_STRUCT(hints); @@ -58,8 +172,72 @@ bool interpret_string_addr_internal(struct addrinfo **ppres, /* always try as a numeric host first. This prevents unnecessary name * lookups, and also ensures we accept IPv6 addresses */ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + +#if defined(HAVE_IPV6) + if (len < sizeof(addr)) { + char *p = NULL; + + p = normalize_ipv6_literal(str, addr, &len); + if (p != NULL) { + hints.ai_family = AF_INET6; + str = p; + } + } + + if (strchr_m(str, ':')) { + char *p = strchr_m(str, '%'); + + /* + * Cope with link-local. + * This is IP:v6:addr%ifname. + */ + + if (p && (p > str) && ((scope_id = if_nametoindex(p+1)) != 0)) { + /* Length of string we want to copy. + This is IP:v6:addr (removing the %ifname). + */ + len = PTR_DIFF(p,str); + + if (len+1 > sizeof(addr)) { + /* string+nul too long for array. */ + return false; + } + if (str != addr) { + memcpy(addr, str, len); + } + addr[len] = '\0'; + + str = addr; + } + } +#endif + ret = getaddrinfo(str, NULL, &hints, ppres); if (ret == 0) { +#if defined(HAVE_IPV6) + struct sockaddr_in6 *ps6 = NULL; + + if (scope_id == 0) { + return true; + } + if (ppres == NULL) { + return true; + } + if ((*ppres) == NULL) { + return true; + } + if ((*ppres)->ai_addr->sa_family != AF_INET6) { + return true; + } + + ps6 = (struct sockaddr_in6 *)(*ppres)->ai_addr; + + if (IN6_IS_ADDR_LINKLOCAL(&ps6->sin6_addr) && + ps6->sin6_scope_id == 0) { + ps6->sin6_scope_id = scope_id; + } +#endif + return true; } @@ -94,35 +272,6 @@ static bool interpret_string_addr_pref(struct sockaddr_storage *pss, { struct addrinfo *res = NULL; int int_flags; -#if defined(HAVE_IPV6) - char addr[INET6_ADDRSTRLEN]; - unsigned int scope_id = 0; - - if (strchr_m(str, ':')) { - char *p = strchr_m(str, '%'); - - /* - * Cope with link-local. - * This is IP:v6:addr%ifname. - */ - - if (p && (p > str) && ((scope_id = if_nametoindex(p+1)) != 0)) { - /* Length of string we want to copy. - This is IP:v6:addr (removing the %ifname). - */ - size_t len = PTR_DIFF(p,str); - - if (len+1 > sizeof(addr)) { - /* string+nul too long for array. */ - return false; - } - memcpy(addr, str, len); - addr[len] = '\0'; - - str = addr; - } - } -#endif zero_sockaddr(pss); @@ -157,16 +306,6 @@ static bool interpret_string_addr_pref(struct sockaddr_storage *pss, memcpy(pss, res->ai_addr, res->ai_addrlen); } -#if defined(HAVE_IPV6) - if (pss->ss_family == AF_INET6 && scope_id) { - struct sockaddr_in6 *ps6 = (struct sockaddr_in6 *)pss; - if (IN6_IS_ADDR_LINKLOCAL(&ps6->sin6_addr) && - ps6->sin6_scope_id == 0) { - ps6->sin6_scope_id = scope_id; - } - } -#endif - freeaddrinfo(res); return true; } @@ -320,6 +459,28 @@ bool is_ipaddress_v4(const char *str) return false; } +bool is_ipv6_literal(const char *str) +{ +#if defined(HAVE_IPV6) + char buf[INET6_ADDRSTRLEN*2] = { 0, }; + size_t len = strlen(str); + char *p = NULL; + + if (len >= sizeof(buf)) { + return false; + } + + p = normalize_ipv6_literal(str, buf, &len); + if (p == NULL) { + return false; + } + + return true; +#else + return false; +#endif +} + /** * Return true if a string could be a IPv6 address. */ @@ -328,16 +489,20 @@ bool is_ipaddress_v6(const char *str) { #if defined(HAVE_IPV6) int ret = -1; + char *p = NULL; - if (strchr_m(str, ':')) { + p = strchr_m(str, ':'); + if (p == NULL) { + return is_ipv6_literal(str); + } else { char buf[INET6_ADDRSTRLEN] = { 0, }; size_t len; const char *addr = str; const char *idxs = NULL; unsigned int idx = 0; struct in6_addr ip6; - char *p = strchr_m(str, '%'); + p = strchr_m(str, '%'); if (p && (p > str)) { len = PTR_DIFF(p, str); idxs = p + 1; diff --git a/lib/util/util_net.h b/lib/util/util_net.h index 2f1beffb168..29468b4263d 100644 --- a/lib/util/util_net.h +++ b/lib/util/util_net.h @@ -86,6 +86,7 @@ _PUBLIC_ uint32_t interpret_addr(const char *str); _PUBLIC_ struct in_addr interpret_addr2(const char *str); _PUBLIC_ bool is_ipaddress_v4(const char *str); +_PUBLIC_ bool is_ipv6_literal(const char *str); _PUBLIC_ bool is_ipaddress_v6(const char *str); bool is_address_any(const struct sockaddr *psa); diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h index 0c319d32e7b..a4949d09a46 100644 --- a/libcli/auth/proto.h +++ b/libcli/auth/proto.h @@ -144,6 +144,7 @@ DATA_BLOB NTLMv2_generate_names_blob(TALLOC_CTX *mem_ctx, bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx, const char *user, const char *domain, const uint8_t nt_hash[16], const DATA_BLOB *server_chal, + const NTTIME *server_timestamp, const DATA_BLOB *names_blob, DATA_BLOB *lm_response, DATA_BLOB *nt_response, DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) ; @@ -154,6 +155,11 @@ bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ctx, const DATA_BLOB *names_blob, DATA_BLOB *lm_response, DATA_BLOB *nt_response, DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) ; +NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name, + const char *account_domain, + const DATA_BLOB response, + const struct netlogon_creds_CredentialState *creds, + const char *workgroup); /*********************************************************** encode a password buffer with a unicode password. The buffer diff --git a/libcli/auth/smbencrypt.c b/libcli/auth/smbencrypt.c index ec819cd4db3..c88fbd6e28c 100644 --- a/libcli/auth/smbencrypt.c +++ b/libcli/auth/smbencrypt.c @@ -26,7 +26,7 @@ #include "../libcli/auth/msrpc_parse.h" #include "../lib/crypto/crypto.h" #include "../libcli/auth/libcli_auth.h" -#include "../librpc/gen_ndr/ntlmssp.h" +#include "../librpc/gen_ndr/ndr_ntlmssp.h" void SMBencrypt_hash(const uint8_t lm_hash[16], const uint8_t *c8, uint8_t p24[24]) { @@ -387,14 +387,13 @@ DATA_BLOB NTLMv2_generate_names_blob(TALLOC_CTX *mem_ctx, return names_blob; } -static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx, const DATA_BLOB *names_blob) +static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx, + NTTIME nttime, + const DATA_BLOB *names_blob) { uint8_t client_chal[8]; DATA_BLOB response = data_blob(NULL, 0); uint8_t long_date[8]; - NTTIME nttime; - - unix_to_nt_time(&nttime, time(NULL)); generate_random_buffer(client_chal, sizeof(client_chal)); @@ -417,6 +416,7 @@ static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx, const DATA_BLO static DATA_BLOB NTLMv2_generate_response(TALLOC_CTX *out_mem_ctx, const uint8_t ntlm_v2_hash[16], const DATA_BLOB *server_chal, + NTTIME nttime, const DATA_BLOB *names_blob) { uint8_t ntlmv2_response[16]; @@ -433,7 +433,7 @@ static DATA_BLOB NTLMv2_generate_response(TALLOC_CTX *out_mem_ctx, /* NTLMv2 */ /* generate some data to pass into the response function - including the hostname and domain name of the server */ - ntlmv2_client_data = NTLMv2_generate_client_data(mem_ctx, names_blob); + ntlmv2_client_data = NTLMv2_generate_client_data(mem_ctx, nttime, names_blob); /* Given that data, and the challenge from the server, generate a response */ SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &ntlmv2_client_data, ntlmv2_response); @@ -479,6 +479,7 @@ static DATA_BLOB LMv2_generate_response(TALLOC_CTX *mem_ctx, bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx, const char *user, const char *domain, const uint8_t nt_hash[16], const DATA_BLOB *server_chal, + const NTTIME *server_timestamp, const DATA_BLOB *names_blob, DATA_BLOB *lm_response, DATA_BLOB *nt_response, DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) @@ -494,8 +495,19 @@ bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx, } if (nt_response) { + const NTTIME *nttime = server_timestamp; + NTTIME _now = 0; + + if (nttime == NULL) { + struct timeval tv_now = timeval_current(); + _now = timeval_to_nttime(&tv_now); + nttime = &_now; + } + *nt_response = NTLMv2_generate_response(mem_ctx, - ntlm_v2_hash, server_chal, + ntlm_v2_hash, + server_chal, + *nttime, names_blob); if (user_session_key) { *user_session_key = data_blob_talloc(mem_ctx, NULL, 16); @@ -509,8 +521,13 @@ bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx, /* LMv2 */ if (lm_response) { - *lm_response = LMv2_generate_response(mem_ctx, - ntlm_v2_hash, server_chal); + if (server_timestamp != NULL) { + *lm_response = data_blob_talloc_zero(mem_ctx, 24); + } else { + *lm_response = LMv2_generate_response(mem_ctx, + ntlm_v2_hash, + server_chal); + } if (lm_session_key) { *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16); @@ -535,10 +552,143 @@ bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ctx, E_md4hash(password, nt_hash); return SMBNTLMv2encrypt_hash(mem_ctx, - user, domain, nt_hash, server_chal, names_blob, + user, domain, nt_hash, + server_chal, NULL, names_blob, lm_response, nt_response, lm_session_key, user_session_key); } +NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name, + const char *account_domain, + const DATA_BLOB response, + const struct netlogon_creds_CredentialState *creds, + const char *workgroup) +{ + TALLOC_CTX *frame = NULL; + /* RespType + HiRespType */ + static const char *magic = "\x01\x01"; + int cmp; + struct NTLMv2_RESPONSE v2_resp; + enum ndr_err_code err; + const struct AV_PAIR *av_nb_cn = NULL; + const struct AV_PAIR *av_nb_dn = NULL; + + if (response.length < 48) { + /* + * NTLMv2_RESPONSE has at least 48 bytes. + */ + return NT_STATUS_OK; + } + + cmp = memcmp(response.data + 16, magic, 2); + if (cmp != 0) { + /* + * It doesn't look like a valid NTLMv2_RESPONSE + */ + return NT_STATUS_OK; + } + + frame = talloc_stackframe(); + + err = ndr_pull_struct_blob(&response, frame, &v2_resp, + (ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE); + if (!NDR_ERR_CODE_IS_SUCCESS(err)) { + NTSTATUS status; + status = ndr_map_error2ntstatus(err); + DEBUG(2,("Failed to parse NTLMv2_RESPONSE " + "length %u - %s - %s\n", + (unsigned)response.length, + ndr_map_error2string(err), + nt_errstr(status))); + dump_data(2, response.data, response.length); + TALLOC_FREE(frame); + return status; + } + + if (DEBUGLVL(10)) { + NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &v2_resp); + } + + /* + * Make sure the netbios computer name in the + * NTLMv2_RESPONSE matches the computer name + * in the secure channel credentials for workstation + * trusts. + * + * And the netbios domain name matches our + * workgroup. + * + * This prevents workstations from requesting + * the session key of NTLMSSP sessions of clients + * to other hosts. + */ + if (creds->secure_channel_type == SEC_CHAN_WKSTA) { + av_nb_cn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs, + MsvAvNbComputerName); + av_nb_dn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs, + MsvAvNbDomainName); + } + + if (av_nb_cn != NULL) { + const char *v = NULL; + char *a = NULL; + size_t len; + + v = av_nb_cn->Value.AvNbComputerName; + + a = talloc_strdup(frame, creds->account_name); + if (a == NULL) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + len = strlen(a); + if (len > 0 && a[len - 1] == '$') { + a[len - 1] = '\0'; + } + + cmp = strcasecmp_m(a, v); + if (cmp != 0) { + DEBUG(2,("%s: NTLMv2_RESPONSE with " + "NbComputerName[%s] rejected " + "for user[%s\\%s] " + "against SEC_CHAN_WKSTA[%s/%s] " + "in workgroup[%s]\n", + __func__, v, + account_domain, + account_name, + creds->computer_name, + creds->account_name, + workgroup)); + TALLOC_FREE(frame); + return NT_STATUS_LOGON_FAILURE; + } + } + if (av_nb_dn != NULL) { + const char *v = NULL; + + v = av_nb_dn->Value.AvNbDomainName; + + cmp = strcasecmp_m(workgroup, v); + if (cmp != 0) { + DEBUG(2,("%s: NTLMv2_RESPONSE with " + "NbDomainName[%s] rejected " + "for user[%s\\%s] " + "against SEC_CHAN_WKSTA[%s/%s] " + "in workgroup[%s]\n", + __func__, v, + account_domain, + account_name, + creds->computer_name, + creds->account_name, + workgroup)); + TALLOC_FREE(frame); + return NT_STATUS_LOGON_FAILURE; + } + } + + TALLOC_FREE(frame); + return NT_STATUS_OK; +} + /*********************************************************** encode a password buffer with a unicode password. The buffer is filled with random data to make it harder to attack. diff --git a/libcli/auth/spnego.h b/libcli/auth/spnego.h index 539b90336f0..49645e06bff 100644 --- a/libcli/auth/spnego.h +++ b/libcli/auth/spnego.h @@ -45,7 +45,11 @@ enum spnego_negResult { SPNEGO_ACCEPT_COMPLETED = 0, SPNEGO_ACCEPT_INCOMPLETE = 1, SPNEGO_REJECT = 2, - SPNEGO_NONE_RESULT = 3 + SPNEGO_REQUEST_MIC = 3, + /* + * The max value is 0xff (255) on the wire + */ + SPNEGO_NONE_RESULT = 256 }; struct spnego_negTokenInit { @@ -58,7 +62,7 @@ struct spnego_negTokenInit { }; struct spnego_negTokenTarg { - uint8_t negResult; + enum spnego_negResult negResult; const char *supportedMech; DATA_BLOB responseToken; DATA_BLOB mechListMIC; diff --git a/libcli/auth/spnego_parse.c b/libcli/auth/spnego_parse.c index d4c5bdcfa5c..12303766a59 100644 --- a/libcli/auth/spnego_parse.c +++ b/libcli/auth/spnego_parse.c @@ -32,12 +32,12 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false; if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false; - while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) { + while (!asn1_has_error(asn1) && 0 < asn1_tag_remaining(asn1)) { int i; uint8_t context; if (!asn1_peek_uint8(asn1, &context)) { - asn1->has_error = true; + asn1_set_error(asn1); break; } @@ -51,10 +51,10 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, mechTypes = talloc(mem_ctx, const char *); if (mechTypes == NULL) { - asn1->has_error = true; + asn1_set_error(asn1); return false; } - for (i = 0; !asn1->has_error && + for (i = 0; !asn1_has_error(asn1) && 0 < asn1_tag_remaining(asn1); i++) { char *oid; const char **p; @@ -63,7 +63,7 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, const char *, i+2); if (p == NULL) { talloc_free(mechTypes); - asn1->has_error = true; + asn1_set_error(asn1); return false; } mechTypes = p; @@ -97,7 +97,7 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, uint8_t type_peek; if (!asn1_start_tag(asn1, ASN1_CONTEXT(3))) return false; if (!asn1_peek_uint8(asn1, &type_peek)) { - asn1->has_error = true; + asn1_set_error(asn1); break; } if (type_peek == ASN1_OCTET_STRING) { @@ -119,7 +119,7 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, break; } default: - asn1->has_error = true; + asn1_set_error(asn1); break; } } @@ -127,7 +127,7 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, if (!asn1_end_tag(asn1)) return false; if (!asn1_end_tag(asn1)) return false; - return !asn1->has_error; + return !asn1_has_error(asn1); } static bool write_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenInit *token) @@ -190,7 +190,7 @@ static bool write_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenIni if (!asn1_pop_tag(asn1)) return false; if (!asn1_pop_tag(asn1)) return false; - return !asn1->has_error; + return !asn1_has_error(asn1); } static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, @@ -201,11 +201,13 @@ static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false; if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false; - while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) { + while (!asn1_has_error(asn1) && 0 < asn1_tag_remaining(asn1)) { uint8_t context; + uint8_t neg_result; char *oid; + if (!asn1_peek_uint8(asn1, &context)) { - asn1->has_error = true; + asn1_set_error(asn1); break; } @@ -213,7 +215,8 @@ static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, case ASN1_CONTEXT(0): if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false; if (!asn1_start_tag(asn1, ASN1_ENUMERATED)) return false; - if (!asn1_read_uint8(asn1, &token->negResult)) return false; + if (!asn1_read_uint8(asn1, &neg_result)) return false; + token->negResult = neg_result; if (!asn1_end_tag(asn1)) return false; if (!asn1_end_tag(asn1)) return false; break; @@ -234,7 +237,7 @@ static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, if (!asn1_end_tag(asn1)) return false; break; default: - asn1->has_error = true; + asn1_set_error(asn1); break; } } @@ -242,7 +245,7 @@ static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, if (!asn1_end_tag(asn1)) return false; if (!asn1_end_tag(asn1)) return false; - return !asn1->has_error; + return !asn1_has_error(asn1); } static bool write_negTokenTarg(struct asn1_data *asn1, struct spnego_negTokenTarg *token) @@ -279,7 +282,7 @@ static bool write_negTokenTarg(struct asn1_data *asn1, struct spnego_negTokenTar if (!asn1_pop_tag(asn1)) return false; if (!asn1_pop_tag(asn1)) return false; - return !asn1->has_error; + return !asn1_has_error(asn1); } ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data *token) @@ -302,7 +305,7 @@ ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data if (!asn1_load(asn1, data)) goto err; if (!asn1_peek_uint8(asn1, &context)) { - asn1->has_error = true; + asn1_set_error(asn1); } else { switch (context) { case ASN1_APPLICATION(0): @@ -319,12 +322,14 @@ ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data } break; default: - asn1->has_error = true; + asn1_set_error(asn1); break; } } - if (!asn1->has_error) ret = asn1->ofs; + if (!asn1_has_error(asn1)) { + ret = asn1_current_ofs(asn1); + } err: @@ -353,15 +358,16 @@ ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_da write_negTokenTarg(asn1, &spnego->negTokenTarg); break; default: - asn1->has_error = true; + asn1_set_error(asn1); break; } - if (!asn1->has_error) { - *blob = data_blob_talloc(mem_ctx, asn1->data, asn1->length); - ret = asn1->ofs; + if (!asn1_extract_blob(asn1, mem_ctx, blob)) { + goto err; } + ret = asn1_current_ofs(asn1); + err: asn1_free(asn1); @@ -423,12 +429,11 @@ bool spnego_write_mech_types(TALLOC_CTX *mem_ctx, if (!asn1_pop_tag(asn1)) goto err; } - if (asn1->has_error) { + if (asn1_has_error(asn1)) { goto err; } - *blob = data_blob_talloc(mem_ctx, asn1->data, asn1->length); - if (blob->length != asn1->length) { + if (!asn1_extract_blob(asn1, mem_ctx, blob)) { goto err; } diff --git a/libcli/cldap/cldap.c b/libcli/cldap/cldap.c index df81767a760..2d34337338a 100644 --- a/libcli/cldap/cldap.c +++ b/libcli/cldap/cldap.c @@ -220,7 +220,6 @@ nomem: static bool cldap_socket_recv_dgram(struct cldap_socket *c, struct cldap_incoming *in) { - DATA_BLOB blob; struct asn1_data *asn1; void *p; struct cldap_search_state *search; @@ -230,16 +229,12 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c, goto error; } - blob = data_blob_const(in->buf, in->len); - asn1 = asn1_init(in); if (!asn1) { goto nomem; } - if (!asn1_load(asn1, blob)) { - goto nomem; - } + asn1_load_nocopy(asn1, in->buf, in->len); in->ldap_msg = talloc(in, struct ldap_message); if (in->ldap_msg == NULL) { @@ -267,8 +262,11 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c, search = talloc_get_type_abort(p, struct cldap_search_state); search->response.in = talloc_move(search, &in); + search->response.asn1 = asn1; - search->response.asn1->ofs = 0; + + asn1_load_nocopy(search->response.asn1, + search->response.in->buf, search->response.in->len); DLIST_REMOVE(c->searches.list, search); diff --git a/libcli/ldap/ldap_message.c b/libcli/ldap/ldap_message.c index ba94f4ccfac..a4e702a1917 100644 --- a/libcli/ldap/ldap_message.c +++ b/libcli/ldap/ldap_message.c @@ -322,7 +322,7 @@ static bool ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(7))) return false; if (!asn1_write_LDAPString(data, tree->u.present.attr)) return false; if (!asn1_pop_tag(data)) return false; - return !data->has_error; + return !asn1_has_error(data); case LDB_OP_APPROX: /* approx test */ @@ -366,7 +366,7 @@ static bool ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree default: return false; } - return !data->has_error; + return !asn1_has_error(data); } static bool ldap_encode_response(struct asn1_data *data, struct ldap_Result *result) @@ -691,7 +691,10 @@ _PUBLIC_ bool ldap_encode(struct ldap_message *msg, if (!asn1_pop_tag(data)) goto err; - *result = data_blob_talloc(mem_ctx, data->data, data->length); + if (!asn1_extract_blob(data, mem_ctx, result)) { + goto err; + } + asn1_free(data); return true; @@ -842,7 +845,8 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx, if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed; if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed; if (!asn1_end_tag(data)) goto failed; - if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) { + if (asn1_has_error(data) || (attrib == NULL) || + (value.data == NULL)) { goto failed; } @@ -954,7 +958,8 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx, if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed; if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed; if (!asn1_end_tag(data)) goto failed; - if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) { + if (asn1_has_error(data) || (attrib == NULL) || + (value.data == NULL)) { goto failed; } @@ -973,7 +978,8 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx, if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed; if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed; if (!asn1_end_tag(data)) goto failed; - if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) { + if (asn1_has_error(data) || (attrib == NULL) || + (value.data == NULL)) { goto failed; } @@ -1011,7 +1017,8 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx, if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed; if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed; if (!asn1_end_tag(data)) goto failed; - if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) { + if (asn1_has_error(data) || (attrib == NULL) || + (value.data == NULL)) { goto failed; } @@ -1609,7 +1616,7 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data, } if (!asn1_end_tag(data)) goto prot_err; - if ((data->has_error) || (data->nesting != NULL)) { + if (asn1_has_error(data) || asn1_has_nesting(data)) { return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR); } return NT_STATUS_OK; @@ -1626,6 +1633,8 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data, */ NTSTATUS ldap_full_packet(void *private_data, DATA_BLOB blob, size_t *packet_size) { + int ret; + if (blob.length < 6) { /* * We need at least 6 bytes to workout the length @@ -1633,5 +1642,10 @@ NTSTATUS ldap_full_packet(void *private_data, DATA_BLOB blob, size_t *packet_siz */ return STATUS_MORE_ENTRIES; } - return asn1_peek_full_tag(blob, ASN1_SEQUENCE(0), packet_size); + + ret = asn1_peek_full_tag(blob, ASN1_SEQUENCE(0), packet_size); + if (ret != 0) { + return map_nt_error_from_unix_common(ret); + } + return NT_STATUS_OK; } diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index b00afbc2d5a..7bf48c80437 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -363,6 +363,7 @@ struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx, conn->desire_signing = true; conn->mandatory_signing = false; break; + case SMB_SIGNING_IPC_DEFAULT: case SMB_SIGNING_REQUIRED: /* always */ conn->allow_signing = true; diff --git a/libcli/smb/smb_constants.h b/libcli/smb/smb_constants.h index 60588769025..9b1de5048d0 100644 --- a/libcli/smb/smb_constants.h +++ b/libcli/smb/smb_constants.h @@ -93,6 +93,7 @@ enum protocol_types { #define PROTOCOL_LATEST PROTOCOL_SMB3_02 enum smb_signing_setting { + SMB_SIGNING_IPC_DEFAULT = -2, /* Only used in C code */ SMB_SIGNING_DEFAULT = -1, SMB_SIGNING_OFF = 0, SMB_SIGNING_IF_REQUIRED = 1, diff --git a/libcli/smb/smb_signing.c b/libcli/smb/smb_signing.c index e128e8f8a0b..a7bc819f489 100644 --- a/libcli/smb/smb_signing.c +++ b/libcli/smb/smb_signing.c @@ -424,6 +424,10 @@ bool smb_signing_set_negotiated(struct smb_signing_state *si, return true; } + if (mandatory) { + allowed = true; + } + if (!si->allowed && mandatory) { return false; } diff --git a/libcli/smb/tstream_smbXcli_np.c b/libcli/smb/tstream_smbXcli_np.c index 77a326b012d..248bfb02cfc 100644 --- a/libcli/smb/tstream_smbXcli_np.c +++ b/libcli/smb/tstream_smbXcli_np.c @@ -111,7 +111,11 @@ static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np *cli_nps) * Once we've fixed all callers to call * tstream_disconnect_send()/_recv(), this will * never be called. + * + * We use a maximun timeout of 1 second == 1000 msec. */ + cli_nps->timeout = MIN(cli_nps->timeout, 1000); + if (cli_nps->is_smb1) { status = smb1cli_close(cli_nps->conn, cli_nps->timeout, @@ -632,7 +636,7 @@ static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq) } TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__); + tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__); return; } @@ -980,7 +984,7 @@ static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq) status = NT_STATUS_OK; } if (!NT_STATUS_IS_OK(status)) { - tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__); + tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__); return; } @@ -1064,7 +1068,7 @@ static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq) } if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(subreq); - tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__); + tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__); return; } @@ -1290,7 +1294,7 @@ static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq) } TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - tevent_req_error(req, EIO); + tevent_req_error(req, EPIPE); return; } diff --git a/libcli/util/error.h b/libcli/util/error.h index 0972601afb1..14614458473 100644 --- a/libcli/util/error.h +++ b/libcli/util/error.h @@ -22,6 +22,7 @@ #include "libcli/util/werror.h" #include "libcli/util/doserr.h" #include "libcli/util/ntstatus.h" +#include "libcli/util/hresult.h" /***************************************************************************** convert a NT status code to a dos class/code diff --git a/librpc/idl/dcerpc.idl b/librpc/idl/dcerpc.idl index cb7f5b85430..015eb3d1815 100644 --- a/librpc/idl/dcerpc.idl +++ b/librpc/idl/dcerpc.idl @@ -106,7 +106,7 @@ interface dcerpc uint16 max_xmit_frag; uint16 max_recv_frag; uint32 assoc_group_id; - [value(strlen(secondary_address)+1)] uint16 secondary_address_size; + [value(strlen_m_term_null(secondary_address))] uint16 secondary_address_size; [charset(DOS)] uint8 secondary_address[secondary_address_size]; [flag(NDR_ALIGN4)] DATA_BLOB _pad1; uint8 num_results; @@ -197,18 +197,21 @@ interface dcerpc DCERPC_NCA_S_FAULT_TX_OPEN_FAILED = 0x1C000022, DCERPC_NCA_S_FAULT_CODESET_CONV_ERROR = 0x1C000023, DCERPC_NCA_S_FAULT_OBJECT_NOT_FOUND = 0x1C000024, - DCERPC_NCA_S_FAULT_NO_CLIENT_STUB = 0x1C000025 + DCERPC_NCA_S_FAULT_NO_CLIENT_STUB = 0x1C000025, + DCERPC_FAULT_ACCESS_DENIED = 0x00000005, + DCERPC_FAULT_NO_CALL_ACTIVE = 0x000006bd, + DCERPC_FAULT_CANT_PERFORM = 0x000006d8, + DCERPC_FAULT_OUT_OF_RESOURCES = 0x000006d9, + DCERPC_FAULT_BAD_STUB_DATA = 0x000006f7, + DCERPC_FAULT_SEC_PKG_ERROR = 0x00000721 } dcerpc_nca_status; const int DCERPC_FAULT_OP_RNG_ERROR = DCERPC_NCA_S_OP_RNG_ERROR; const int DCERPC_FAULT_UNK_IF = DCERPC_NCA_S_UNKNOWN_IF; - const int DCERPC_FAULT_NDR = 0x000006f7; + const int DCERPC_FAULT_NDR = DCERPC_FAULT_BAD_STUB_DATA; const int DCERPC_FAULT_INVALID_TAG = DCERPC_NCA_S_FAULT_INVALID_TAG; const int DCERPC_FAULT_CONTEXT_MISMATCH = DCERPC_NCA_S_FAULT_CONTEXT_MISMATCH; const int DCERPC_FAULT_OTHER = 0x00000001; - const int DCERPC_FAULT_ACCESS_DENIED = 0x00000005; - const int DCERPC_FAULT_CANT_PERFORM = 0x000006d8; - const int DCERPC_FAULT_SEC_PKG_ERROR = 0x00000721; /* we return this fault when we haven't yet run the test to see what fault w2k3 returns in this case */ @@ -529,8 +532,10 @@ interface dcerpc const uint8 DCERPC_PFC_OFFSET = 3; const uint8 DCERPC_DREP_OFFSET = 4; const uint8 DCERPC_FRAG_LEN_OFFSET = 8; + const uint32 DCERPC_FRAG_MAX_SIZE = 5840; const uint8 DCERPC_AUTH_LEN_OFFSET = 10; const uint8 DCERPC_NCACN_PAYLOAD_OFFSET = 16; + const uint32 DCERPC_NCACN_PAYLOAD_MAX_SIZE = 0x400000; /* 4 MByte */ /* little-endian flag */ const uint8 DCERPC_DREP_LE = 0x10; diff --git a/librpc/idl/epmapper.idl b/librpc/idl/epmapper.idl index 5f3d653961d..fd8eeb4c475 100644 --- a/librpc/idl/epmapper.idl +++ b/librpc/idl/epmapper.idl @@ -214,7 +214,7 @@ interface epmapper epm_floor floors[num_floors]; } epm_tower; - typedef struct { + typedef [public] struct { [value(ndr_size_epm_tower(&tower, ndr->flags))] uint32 tower_length; [subcontext(4)] epm_tower tower; } epm_twr_t; diff --git a/librpc/idl/ntlmssp.idl b/librpc/idl/ntlmssp.idl index 7c3b8fe63ba..95b4f1186f8 100644 --- a/librpc/idl/ntlmssp.idl +++ b/librpc/idl/ntlmssp.idl @@ -1,5 +1,7 @@ #include "idl_types.h" +import "security.idl"; + /* ntlmssp interface definition */ @@ -54,18 +56,21 @@ interface ntlmssp /* NTLMSSP_WINDOWS_MAJOR_VERSION_5: Windows XP SP2 and Server 2003 - NTLMSSP_WINDOWS_MAJOR_VERSION_6: Windows Vista, Server 2008, 7 and Server 2008 R2 + NTLMSSP_WINDOWS_MAJOR_VERSION_6: Windows Vista, Server 2008, 7, Server 2008 R2, 8, Server 2012, 8.1, Server 2012 R2 + NTLMSSP_WINDOWS_MAJOR_VERSION_10: Windows 10, Windows Server 2016 Technical Preview */ typedef [enum8bit] enum { NTLMSSP_WINDOWS_MAJOR_VERSION_5 = 0x05, - NTLMSSP_WINDOWS_MAJOR_VERSION_6 = 0x06 + NTLMSSP_WINDOWS_MAJOR_VERSION_6 = 0x06, + NTLMSSP_WINDOWS_MAJOR_VERSION_10 = 0x0A } ntlmssp_WindowsMajorVersion; /* - NTLMSSP_WINDOWS_MINOR_VERSION_0: Windows Vista, Server 2008, 7, Server 2008 R2 - NTLMSSP_WINDOWS_MINOR_VERSION_1: Windows XP SP2 - NTLMSSP_WINDOWS_MINOR_VERSION_2: Windows Server 2003 + NTLMSSP_WINDOWS_MINOR_VERSION_0: Windows Vista, 10, Server 2016 Technical Preview + NTLMSSP_WINDOWS_MINOR_VERSION_1: Windows XP SP2, 7, Server 2008 R2 + NTLMSSP_WINDOWS_MINOR_VERSION_2: Windows Server 2003, 8, Server 2012 + NTLMSSP_WINDOWS_MINOR_VERSION_3: Windows 8.1, Server 2012 R2 */ typedef [enum8bit] enum { @@ -123,24 +128,24 @@ interface ntlmssp MsvAvDnsTreeName = 5, MsvAvFlags = 6, MsvAvTimestamp = 7, - MsAvRestrictions = 8, + MsvAvSingleHost = 8, MsvAvTargetName = 9, MsvChannelBindings = 10 } ntlmssp_AvId; - /* [MS-NLMP] 2.2.2.2 Restriction_Encoding */ + /* [MS-NLMP] 2.2.2.2 SingleHostData */ - typedef struct { - uint32 Size; + typedef [flag(NDR_PAHEX)] struct { + [value(8+ndr_size_LSAP_TOKEN_INFO_INTEGRITY(&r->token_info, 0)+r->remaining.length)] uint32 Size; [value(0)] uint32 Z4; - boolean32 IntegrityLevel; - uint32 SubjectIntegrityLevel; - uint8 MachineId[32]; - } Restriction_Encoding; + LSAP_TOKEN_INFO_INTEGRITY token_info; + [flag(NDR_REMAINING)] DATA_BLOB remaining; + } ntlmssp_SingleHostData; typedef [bitmap32bit] bitmap { NTLMSSP_AVFLAG_CONSTRAINTED_ACCOUNT = 0x00000001, - NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE = 0x00000002 + NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE = 0x00000002, + NTLMSSP_AVFLAG_TARGET_SPN_FROM_UNTRUSTED_SOURCE = 0x00000004 } ntlmssp_AvFlags; typedef [gensize,nodiscriminant,flag(NDR_NOALIGN)] union { @@ -152,7 +157,7 @@ interface ntlmssp [case(MsvAvDnsTreeName)] [flag(ndr_ntlmssp_negotiated_string_flags(NTLMSSP_NEGOTIATE_UNICODE))] string AvDnsTreeName; [case(MsvAvFlags)] ntlmssp_AvFlags AvFlags; [case(MsvAvTimestamp)] NTTIME AvTimestamp; - [case(MsAvRestrictions)] Restriction_Encoding AvRestrictions; + [case(MsvAvSingleHost)] ntlmssp_SingleHostData AvSingleHost; [case(MsvAvTargetName)] [flag(ndr_ntlmssp_negotiated_string_flags(NTLMSSP_NEGOTIATE_UNICODE))] string AvTargetName; [case(MsvChannelBindings)] uint8 ChannelBindings[16]; [default] [flag(NDR_REMAINING)] DATA_BLOB blob; @@ -166,7 +171,7 @@ interface ntlmssp [subcontext(0),subcontext_size(AvLen),switch_is(AvId)] ntlmssp_AvValue Value; } AV_PAIR; - typedef [gensize,nopush,nopull,flag(NDR_NOALIGN)] struct { + typedef [public,gensize,nopush,nopull,flag(NDR_NOALIGN)] struct { uint32 count; AV_PAIR pair[count]; } AV_PAIR_LIST; @@ -183,7 +188,7 @@ interface ntlmssp uint8 ServerChallenge[8]; uint8 Reserved[8]; [value(ndr_size_AV_PAIR_LIST(TargetInfo, ndr->flags))] uint16 TargetInfoLen; - [value(TargetInfoLen)] uint16 TargetNameInfoMaxLen; + [value(TargetInfoLen)] uint16 TargetInfoMaxLen; [relative] [subcontext(0),subcontext_size(TargetInfoLen)] AV_PAIR_LIST *TargetInfo; [switch_is(NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)] ntlmssp_Version Version; } CHALLENGE_MESSAGE; @@ -238,9 +243,12 @@ interface ntlmssp [default] NTLMv2_RESPONSE v2; } ntlmssp_NTLM_RESPONSE; + const int NTLMSSP_MIC_OFFSET = 72; + const int NTLMSSP_MIC_SIZE = 16; + typedef [flag(NDR_PAHEX)] struct { - uint8 MIC[16]; - } MIC; + uint8 MIC[NTLMSSP_MIC_SIZE]; + } ntlmssp_MIC; /* [MS-NLMP] 2.2.1.3 AUTHENTICATE_MESSAGE */ @@ -269,7 +277,7 @@ interface ntlmssp [switch_is(NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)] ntlmssp_Version Version; /* MIC (Message Integrity) is only included when the client has * sent a timestap Av struct in the CHALLENGE_MESSAGE AvPair */ - /* [flag(NDR_REMAINING)] MIC mic; */ + /* [flag(NDR_REMAINING)] ntlmssp_MIC mic; */ } AUTHENTICATE_MESSAGE; /* NTLMSSP signature version */ diff --git a/librpc/idl/security.idl b/librpc/idl/security.idl index 78c13c99504..88d8936ab78 100644 --- a/librpc/idl/security.idl +++ b/librpc/idl/security.idl @@ -648,12 +648,28 @@ interface security SECINFO_BACKUP | 0); + /* + * See [MS-KILE] 2.2.5 LSAP_TOKEN_INFO_INTEGRITY + */ + typedef [public,gensize,flag(NDR_PAHEX)] struct { + uint32 Flags; + uint32 TokenIL; + uint8 MachineId[32]; + } LSAP_TOKEN_INFO_INTEGRITY; + + /* + * See [MS-KILE] 2.2.6 Supported Encryption Types Bit Flags + */ typedef [public,bitmap32bit] bitmap { KERB_ENCTYPE_DES_CBC_CRC = 0x00000001, KERB_ENCTYPE_DES_CBC_MD5 = 0x00000002, KERB_ENCTYPE_RC4_HMAC_MD5 = 0x00000004, KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 = 0x00000008, - KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96 = 0x00000010 + KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96 = 0x00000010, + KERB_ENCTYPE_FAST_SUPPORTED = 0x00010000, + KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED = 0x00020000, + KERB_ENCTYPE_CLAIMS_SUPPORTED = 0x00040000, + KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED = 0x00080000 } kerb_EncTypes; typedef [public,bitmap32bit] bitmap { diff --git a/librpc/ndr/ndr_basic.c b/librpc/ndr/ndr_basic.c index a6cf607f3eb..ea3a2d43613 100644 --- a/librpc/ndr/ndr_basic.c +++ b/librpc/ndr/ndr_basic.c @@ -1204,11 +1204,11 @@ _PUBLIC_ void ndr_print_array_uint8(struct ndr_print *ndr, const char *name, #undef _ONELINE_LIMIT } -static void ndr_print_asc(struct ndr_print *ndr, const uint8_t *buf, int len) +static void ndr_print_dump_data_cb(const char *buf, void *private_data) { - int i; - for (i=0;i<len;i++) - ndr->print(ndr, "%c", isprint(buf[i])?buf[i]:'.'); + struct ndr_print *ndr = (struct ndr_print *)private_data; + + ndr->print(ndr, "%s", buf); } /* @@ -1216,37 +1216,8 @@ static void ndr_print_asc(struct ndr_print *ndr, const uint8_t *buf, int len) */ static void ndr_dump_data(struct ndr_print *ndr, const uint8_t *buf, int len) { - int i=0; - ndr->no_newline = true; - - for (i=0;i<len;) { - if (i%16 == 0 && i<len) { - ndr->print(ndr, "[%04X] ",i); - } - - ndr->print(ndr, "%02X ",(int)buf[i]); - i++; - if (i%8 == 0) ndr->print(ndr," "); - if (i%16 == 0) { - ndr_print_asc(ndr,&buf[i-16],8); ndr->print(ndr," "); - ndr_print_asc(ndr,&buf[i-8],8); ndr->print(ndr, "\n"); - } - } - - if (i%16) { - int n; - n = 16 - (i%16); - ndr->print(ndr, " "); - if (n>8) ndr->print(ndr," "); - while (n--) ndr->print(ndr," "); - n = MIN(8,i%16); - ndr_print_asc(ndr,&buf[i-(i%16)],n); ndr->print(ndr, " "); - n = (i%16) - n; - if (n>0) ndr_print_asc(ndr,&buf[i-n],n); - ndr->print(ndr,"\n"); - } - + dump_data_cb(buf, len, true, ndr_print_dump_data_cb, ndr); ndr->no_newline = false; } diff --git a/librpc/ndr/ndr_ntlmssp.c b/librpc/ndr/ndr_ntlmssp.c index d024da5ed8e..7027ac0b13d 100644 --- a/librpc/ndr/ndr_ntlmssp.c +++ b/librpc/ndr/ndr_ntlmssp.c @@ -176,4 +176,20 @@ _PUBLIC_ void ndr_print_ntlmssp_Version(struct ndr_print *ndr, const char *name, } } +_PUBLIC_ struct AV_PAIR *ndr_ntlmssp_find_av(const struct AV_PAIR_LIST *av_list, + enum ntlmssp_AvId AvId) +{ + struct AV_PAIR *res = NULL; + uint32_t i = 0; + + for (i = 0; i < av_list->count; i++) { + if (av_list->pair[i].AvId != AvId) { + continue; + } + res = discard_const_p(struct AV_PAIR, &av_list->pair[i]); + break; + } + + return res; +} diff --git a/librpc/ndr/ndr_ntlmssp.h b/librpc/ndr/ndr_ntlmssp.h index e07ff15cf6f..5c979ffa4f7 100644 --- a/librpc/ndr/ndr_ntlmssp.h +++ b/librpc/ndr/ndr_ntlmssp.h @@ -31,3 +31,5 @@ _PUBLIC_ void ndr_print_ntlmssp_lm_response(TALLOC_CTX *mem_ctx, bool ntlmv2); _PUBLIC_ void ndr_print_ntlmssp_Version(struct ndr_print *ndr, const char *name, const union ntlmssp_Version *r); +_PUBLIC_ struct AV_PAIR *ndr_ntlmssp_find_av(const struct AV_PAIR_LIST *av_list, + enum ntlmssp_AvId AvId); diff --git a/librpc/rpc/binding.c b/librpc/rpc/binding.c index 37e0c4f54f6..6407a8d4ee1 100644 --- a/librpc/rpc/binding.c +++ b/librpc/rpc/binding.c @@ -591,7 +591,7 @@ _PUBLIC_ void dcerpc_binding_get_auth_info(const struct dcerpc_binding *b, } else if (b->flags & DCERPC_CONNECT) { auth_level = DCERPC_AUTH_LEVEL_CONNECT; } else if (auth_type != DCERPC_AUTH_TYPE_NONE) { - auth_level = DCERPC_AUTH_LEVEL_CONNECT; + auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; } else { auth_level = DCERPC_AUTH_LEVEL_NONE; } diff --git a/librpc/rpc/dcerpc_error.c b/librpc/rpc/dcerpc_error.c index 4f0ed6e5dfa..f38602528d6 100644 --- a/librpc/rpc/dcerpc_error.c +++ b/librpc/rpc/dcerpc_error.c @@ -26,58 +26,74 @@ struct dcerpc_fault_table { const char *errstr; uint32_t faultcode; + NTSTATUS nt_status; }; static const struct dcerpc_fault_table dcerpc_faults[] = { -#define _FAULT_STR(x) { #x , x } - _FAULT_STR(DCERPC_NCA_S_COMM_FAILURE), - _FAULT_STR(DCERPC_NCA_S_OP_RNG_ERROR), - _FAULT_STR(DCERPC_NCA_S_UNKNOWN_IF), - _FAULT_STR(DCERPC_NCA_S_WRONG_BOOT_TIME), - _FAULT_STR(DCERPC_NCA_S_YOU_CRASHED), - _FAULT_STR(DCERPC_NCA_S_PROTO_ERROR), - _FAULT_STR(DCERPC_NCA_S_OUT_ARGS_TOO_BIG), - _FAULT_STR(DCERPC_NCA_S_SERVER_TOO_BUSY), - _FAULT_STR(DCERPC_NCA_S_FAULT_STRING_TOO_LARGE), - _FAULT_STR(DCERPC_NCA_S_UNSUPPORTED_TYPE), - _FAULT_STR(DCERPC_NCA_S_FAULT_INT_DIV_BY_ZERO), - _FAULT_STR(DCERPC_NCA_S_FAULT_ADDR_ERROR), - _FAULT_STR(DCERPC_NCA_S_FAULT_FP_DIV_BY_ZERO), - _FAULT_STR(DCERPC_NCA_S_FAULT_FP_UNDERFLOW), - _FAULT_STR(DCERPC_NCA_S_FAULT_FP_OVERRFLOW), - _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_TAG), - _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_BOUND), - _FAULT_STR(DCERPC_NCA_S_FAULT_RPC_VERSION_MISMATCH), - _FAULT_STR(DCERPC_NCA_S_FAULT_UNSPEC_REJECT), - _FAULT_STR(DCERPC_NCA_S_FAULT_BAD_ACTID), - _FAULT_STR(DCERPC_NCA_S_FAULT_WHO_ARE_YOU_FAILED), - _FAULT_STR(DCERPC_NCA_S_FAULT_MANAGER_NOT_ENTERED), - _FAULT_STR(DCERPC_NCA_S_FAULT_CANCEL), - _FAULT_STR(DCERPC_NCA_S_FAULT_ILL_INST), - _FAULT_STR(DCERPC_NCA_S_FAULT_FP_ERROR), - _FAULT_STR(DCERPC_NCA_S_FAULT_INT_OVERFLOW), - _FAULT_STR(DCERPC_NCA_S_UNUSED_1C000011), - _FAULT_STR(DCERPC_NCA_S_FAULT_UNSPEC), - _FAULT_STR(DCERPC_NCA_S_FAULT_REMOTE_COMM_FAILURE), - _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_EMPTY), - _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_CLOSED), - _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_ORDER), - _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_DISCIPLINE), - _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_COMM_ERROR), - _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_MEMORY), - _FAULT_STR(DCERPC_NCA_S_FAULT_CONTEXT_MISMATCH), - _FAULT_STR(DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY), - _FAULT_STR(DCERPC_NCA_S_INVALID_PRES_CONTEXT_ID), - _FAULT_STR(DCERPC_NCA_S_UNSUPPORTED_AUTHN_LEVEL), - _FAULT_STR(DCERPC_NCA_S_UNUSED_1C00001E), - _FAULT_STR(DCERPC_NCA_S_INVALID_CHECKSUM), - _FAULT_STR(DCERPC_NCA_S_INVALID_CRC), - _FAULT_STR(DCERPC_NCA_S_FAULT_USER_DEFINED), - _FAULT_STR(DCERPC_NCA_S_FAULT_TX_OPEN_FAILED), - _FAULT_STR(DCERPC_NCA_S_FAULT_CODESET_CONV_ERROR), - _FAULT_STR(DCERPC_NCA_S_FAULT_OBJECT_NOT_FOUND), - _FAULT_STR(DCERPC_NCA_S_FAULT_NO_CLIENT_STUB), +#define _FAULT_STR(x, s) { .errstr = #x , .faultcode = x, .nt_status = s } +#define _FAULT_STR_NO_NT_MAPPING(x) _FAULT_STR(x, NT_STATUS_RPC_NOT_RPC_ERROR) + _FAULT_STR(DCERPC_NCA_S_COMM_FAILURE, NT_STATUS_RPC_COMM_FAILURE), + _FAULT_STR(DCERPC_NCA_S_OP_RNG_ERROR, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE), + _FAULT_STR(DCERPC_NCA_S_UNKNOWN_IF, NT_STATUS_RPC_UNKNOWN_IF), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_WRONG_BOOT_TIME), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_YOU_CRASHED), + _FAULT_STR(DCERPC_NCA_S_PROTO_ERROR, NT_STATUS_RPC_PROTOCOL_ERROR), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_OUT_ARGS_TOO_BIG), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_SERVER_TOO_BUSY), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_STRING_TOO_LARGE), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_UNSUPPORTED_TYPE), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_ADDR_ERROR), + _FAULT_STR(DCERPC_NCA_S_FAULT_FP_DIV_BY_ZERO, NT_STATUS_RPC_FP_DIV_ZERO), + _FAULT_STR(DCERPC_NCA_S_FAULT_FP_UNDERFLOW, NT_STATUS_RPC_FP_UNDERFLOW), + _FAULT_STR(DCERPC_NCA_S_FAULT_FP_OVERRFLOW, NT_STATUS_RPC_FP_OVERFLOW), + _FAULT_STR(DCERPC_NCA_S_FAULT_INT_DIV_BY_ZERO, NT_STATUS_RPC_FP_DIV_ZERO), + _FAULT_STR(DCERPC_NCA_S_FAULT_INT_OVERFLOW, NT_STATUS_RPC_FP_OVERFLOW), + /* + * What's the difference between NT_STATUS_RPC_INVALID_TAG + * and NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE ??? + * + * Our callers expect NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE. + */ + _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_TAG, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE), + _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_TAG, NT_STATUS_RPC_INVALID_TAG), + _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_BOUND, NT_STATUS_RPC_INVALID_BOUND), + _FAULT_STR(DCERPC_NCA_S_FAULT_RPC_VERSION_MISMATCH, NT_STATUS_RPC_PROTOCOL_ERROR), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_UNSPEC_REJECT), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_BAD_ACTID), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_WHO_ARE_YOU_FAILED), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_MANAGER_NOT_ENTERED), + _FAULT_STR(DCERPC_NCA_S_FAULT_CANCEL, NT_STATUS_RPC_CALL_CANCELLED), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_ILL_INST), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_FP_ERROR), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_UNUSED_1C000011), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_UNSPEC), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_REMOTE_COMM_FAILURE), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_PIPE_EMPTY), + _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_CLOSED, NT_STATUS_RPC_PIPE_CLOSED), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_PIPE_ORDER), + _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_DISCIPLINE, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_PIPE_COMM_ERROR), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_PIPE_MEMORY), + _FAULT_STR(DCERPC_NCA_S_FAULT_CONTEXT_MISMATCH, NT_STATUS_RPC_SS_CONTEXT_MISMATCH), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_INVALID_PRES_CONTEXT_ID), + _FAULT_STR(DCERPC_NCA_S_UNSUPPORTED_AUTHN_LEVEL, NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_UNUSED_1C00001E), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_INVALID_CHECKSUM), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_INVALID_CRC), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_USER_DEFINED), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_TX_OPEN_FAILED), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_CODESET_CONV_ERROR), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_OBJECT_NOT_FOUND), + _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_NO_CLIENT_STUB), + _FAULT_STR(DCERPC_FAULT_OTHER, NT_STATUS_RPC_CALL_FAILED), + _FAULT_STR(DCERPC_FAULT_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED), + _FAULT_STR(DCERPC_FAULT_NO_CALL_ACTIVE, NT_STATUS_RPC_NO_CALL_ACTIVE), + _FAULT_STR(DCERPC_FAULT_CANT_PERFORM, NT_STATUS_EPT_CANT_PERFORM_OP), + _FAULT_STR(DCERPC_FAULT_OUT_OF_RESOURCES, NT_STATUS_RPC_OUT_OF_RESOURCES), + _FAULT_STR(DCERPC_FAULT_BAD_STUB_DATA, NT_STATUS_RPC_BAD_STUB_DATA), + _FAULT_STR(DCERPC_FAULT_SEC_PKG_ERROR, NT_STATUS_RPC_SEC_PKG_ERROR), { NULL, 0 } #undef _FAULT_STR }; @@ -99,26 +115,40 @@ _PUBLIC_ const char *dcerpc_errstr(TALLOC_CTX *mem_ctx, uint32_t fault_code) _PUBLIC_ NTSTATUS dcerpc_fault_to_nt_status(uint32_t fault_code) { - /* TODO: add more mappings */ - switch (fault_code) { - case DCERPC_NCA_S_OP_RNG_ERROR: - return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE; - case DCERPC_NCA_S_UNKNOWN_IF: - return NT_STATUS_RPC_UNKNOWN_IF; - case DCERPC_FAULT_NDR: - return NT_STATUS_RPC_BAD_STUB_DATA; - case DCERPC_NCA_S_FAULT_INVALID_TAG: - return NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE; - case DCERPC_NCA_S_FAULT_CONTEXT_MISMATCH: - return NT_STATUS_RPC_SS_CONTEXT_MISMATCH; - case DCERPC_FAULT_OTHER: - return NT_STATUS_RPC_CALL_FAILED; - case DCERPC_FAULT_ACCESS_DENIED: - return NT_STATUS_ACCESS_DENIED; - case DCERPC_FAULT_SEC_PKG_ERROR: - return NT_STATUS_RPC_SEC_PKG_ERROR; + int idx = 0; + WERROR werr = W_ERROR(fault_code); + + if (fault_code == 0) { + return NT_STATUS_RPC_PROTOCOL_ERROR; } - return NT_STATUS_RPC_PROTOCOL_ERROR; + while (dcerpc_faults[idx].errstr != NULL) { + if (dcerpc_faults[idx].faultcode == fault_code) { + return dcerpc_faults[idx].nt_status; + } + idx++; + } + + return werror_to_ntstatus(werr); } +_PUBLIC_ uint32_t dcerpc_fault_from_nt_status(NTSTATUS nt_status) +{ + int idx = 0; + WERROR werr; + + if (NT_STATUS_IS_OK(nt_status)) { + return DCERPC_NCA_S_PROTO_ERROR; + } + + while (dcerpc_faults[idx].errstr != NULL) { + if (NT_STATUS_EQUAL(dcerpc_faults[idx].nt_status, nt_status)) { + return dcerpc_faults[idx].faultcode; + } + idx++; + } + + werr = ntstatus_to_werror(nt_status); + + return W_ERROR_V(werr); +} diff --git a/librpc/rpc/dcerpc_util.c b/librpc/rpc/dcerpc_util.c index a4dd56986ae..43e1b7f426f 100644 --- a/librpc/rpc/dcerpc_util.c +++ b/librpc/rpc/dcerpc_util.c @@ -83,31 +83,49 @@ uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob) * * @return - A NTSTATUS error code. */ -NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt, +NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt, TALLOC_CTX *mem_ctx, - DATA_BLOB *pkt_trailer, + const DATA_BLOB *pkt_trailer, struct dcerpc_auth *auth, - uint32_t *auth_length, + uint32_t *_auth_length, bool auth_data_only) { struct ndr_pull *ndr; enum ndr_err_code ndr_err; - uint32_t data_and_pad; + uint16_t data_and_pad; + uint16_t auth_length; + uint32_t tmp_length; - data_and_pad = pkt_trailer->length - - (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length); + ZERO_STRUCTP(auth); + if (_auth_length != NULL) { + *_auth_length = 0; + } - /* paranoia check for pad size. This would be caught anyway by - the ndr_pull_advance() a few lines down, but it scared - Jeremy enough for him to call me, so we might as well check - it now, just to prevent someone posting a bogus YouTube - video in the future. - */ - if (data_and_pad > pkt_trailer->length) { - return NT_STATUS_INFO_LENGTH_MISMATCH; + /* Paranoia checks for auth_length. The caller should check this... */ + if (pkt->auth_length == 0) { + return NT_STATUS_INTERNAL_ERROR; } - *auth_length = pkt_trailer->length - data_and_pad; + /* Paranoia checks for auth_length. The caller should check this... */ + if (pkt->auth_length > pkt->frag_length) { + return NT_STATUS_INTERNAL_ERROR; + } + tmp_length = DCERPC_NCACN_PAYLOAD_OFFSET; + tmp_length += DCERPC_AUTH_TRAILER_LENGTH; + tmp_length += pkt->auth_length; + if (tmp_length > pkt->frag_length) { + return NT_STATUS_INTERNAL_ERROR; + } + if (pkt_trailer->length > UINT16_MAX) { + return NT_STATUS_INTERNAL_ERROR; + } + + auth_length = DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length; + if (pkt_trailer->length < auth_length) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + + data_and_pad = pkt_trailer->length - auth_length; ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx); if (!ndr) { @@ -127,14 +145,28 @@ NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt, ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { talloc_free(ndr); + ZERO_STRUCTP(auth); return ndr_map_error2ntstatus(ndr_err); } + if (data_and_pad < auth->auth_pad_length) { + DEBUG(1, (__location__ ": ERROR: pad length mismatch. " + "Calculated %u got %u\n", + (unsigned)data_and_pad, + (unsigned)auth->auth_pad_length)); + talloc_free(ndr); + ZERO_STRUCTP(auth); + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + if (auth_data_only && data_and_pad != auth->auth_pad_length) { - DEBUG(1, (__location__ ": WARNING: pad length mismatch. " + DEBUG(1, (__location__ ": ERROR: pad length mismatch. " "Calculated %u got %u\n", (unsigned)data_and_pad, (unsigned)auth->auth_pad_length)); + talloc_free(ndr); + ZERO_STRUCTP(auth); + return NT_STATUS_RPC_PROTOCOL_ERROR; } DEBUG(6,(__location__ ": auth_pad_length %u\n", @@ -143,6 +175,83 @@ NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt, talloc_steal(mem_ctx, auth->credentials.data); talloc_free(ndr); + if (_auth_length != NULL) { + *_auth_length = auth_length; + } + + return NT_STATUS_OK; +} + +/** +* @brief Verify the fields in ncacn_packet header. +* +* @param pkt - The ncacn_packet strcuture +* @param ptype - The expected PDU type +* @param max_auth_info - The maximum size of a possible auth trailer +* @param required_flags - The required flags for the pdu. +* @param optional_flags - The possible optional flags for the pdu. +* +* @return - A NTSTATUS error code. +*/ +NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt, + enum dcerpc_pkt_type ptype, + size_t max_auth_info, + uint8_t required_flags, + uint8_t optional_flags) +{ + if (pkt->rpc_vers != 5) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + + if (pkt->rpc_vers_minor != 0) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + + if (pkt->auth_length > pkt->frag_length) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + + if (pkt->ptype != ptype) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + + if (max_auth_info > UINT16_MAX) { + return NT_STATUS_INTERNAL_ERROR; + } + + if (pkt->auth_length > 0) { + size_t max_auth_length; + + if (max_auth_info <= DCERPC_AUTH_TRAILER_LENGTH) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + max_auth_length = max_auth_info - DCERPC_AUTH_TRAILER_LENGTH; + + if (pkt->auth_length > max_auth_length) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + } + + if ((pkt->pfc_flags & required_flags) != required_flags) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + if (pkt->pfc_flags & ~(optional_flags|required_flags)) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + + if (pkt->drep[0] & ~DCERPC_DREP_LE) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + if (pkt->drep[1] != 0) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + if (pkt->drep[2] != 0) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + if (pkt->drep[3] != 0) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + return NT_STATUS_OK; } @@ -652,3 +761,66 @@ bool dcerpc_sec_verification_trailer_check( return true; } + +static const struct ndr_syntax_id dcerpc_bind_time_features_prefix = { + .uuid = { + .time_low = 0x6cb71c2c, + .time_mid = 0x9812, + .time_hi_and_version = 0x4540, + .clock_seq = {0x00, 0x00}, + .node = {0x00,0x00,0x00,0x00,0x00,0x00} + }, + .if_version = 1, +}; + +bool dcerpc_extract_bind_time_features(struct ndr_syntax_id s, uint64_t *_features) +{ + uint8_t values[8]; + uint64_t features = 0; + + values[0] = s.uuid.clock_seq[0]; + values[1] = s.uuid.clock_seq[1]; + values[2] = s.uuid.node[0]; + values[3] = s.uuid.node[1]; + values[4] = s.uuid.node[2]; + values[5] = s.uuid.node[3]; + values[6] = s.uuid.node[4]; + values[7] = s.uuid.node[5]; + + ZERO_STRUCT(s.uuid.clock_seq); + ZERO_STRUCT(s.uuid.node); + + if (!ndr_syntax_id_equal(&s, &dcerpc_bind_time_features_prefix)) { + if (_features != NULL) { + *_features = 0; + } + return false; + } + + features = BVAL(values, 0); + + if (_features != NULL) { + *_features = features; + } + + return true; +} + +struct ndr_syntax_id dcerpc_construct_bind_time_features(uint64_t features) +{ + struct ndr_syntax_id s = dcerpc_bind_time_features_prefix; + uint8_t values[8]; + + SBVAL(values, 0, features); + + s.uuid.clock_seq[0] = values[0]; + s.uuid.clock_seq[1] = values[1]; + s.uuid.node[0] = values[2]; + s.uuid.node[1] = values[3]; + s.uuid.node[2] = values[4]; + s.uuid.node[3] = values[5]; + s.uuid.node[4] = values[6]; + s.uuid.node[5] = values[7]; + + return s; +} diff --git a/librpc/rpc/rpc_common.h b/librpc/rpc/rpc_common.h index 45d36912030..da6c2a28ea6 100644 --- a/librpc/rpc/rpc_common.h +++ b/librpc/rpc/rpc_common.h @@ -106,6 +106,7 @@ struct dcerpc_binding; const char *dcerpc_errstr(TALLOC_CTX *mem_ctx, uint32_t fault_code); NTSTATUS dcerpc_fault_to_nt_status(uint32_t fault_code); +uint32_t dcerpc_fault_from_nt_status(NTSTATUS nt_status); /* The following definitions come from ../librpc/rpc/binding.c */ @@ -183,12 +184,17 @@ const char *dcerpc_default_transport_endpoint(TALLOC_CTX *mem_ctx, * * @return - A NTSTATUS error code. */ -NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt, +NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt, TALLOC_CTX *mem_ctx, - DATA_BLOB *pkt_trailer, + const DATA_BLOB *pkt_trailer, struct dcerpc_auth *auth, uint32_t *auth_length, bool auth_data_only); +NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt, + enum dcerpc_pkt_type ptype, + size_t max_auth_info, + uint8_t required_flags, + uint8_t optional_flags); struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct tstream_context *stream); @@ -370,6 +376,36 @@ bool dcerpc_sec_verification_trailer_check( const struct dcerpc_sec_vt_pcontext *pcontext, const struct dcerpc_sec_vt_header2 *header2); +/** + * @brief check and optionally extract the Bind Time Features from + * the given ndr_syntax_id. + * + * <a href="http://msdn.microsoft.com/en-us/library/cc243715.aspx">MS-RPCE 3.3.1.5.3 Bind Time Feature Negotiation</a>. + * + * @param[in] s the syntax that should be checked. + * + * @param[out] features This is optional, it will be filled with the extracted + * features the on success, otherwise it's filled with 0. + * + * @return true if the syntax matches the 6CB71C2C-9812-4540 prefix with version 1, false otherwise. + * + * @see dcerpc_construct_bind_time_features + */ +bool dcerpc_extract_bind_time_features(struct ndr_syntax_id syntax, uint64_t *features); + +/** + * @brief Construct a ndr_syntax_id used for Bind Time Features Negotiation. + * + * <a href="http://msdn.microsoft.com/en-us/library/cc243715.aspx">MS-RPCE 3.3.1.5.3 Bind Time Feature Negotiation</a>. + * + * @param[in] features The supported features. + * + * @return The ndr_syntax_id with the given features. + * + * @see dcerpc_extract_bind_time_features + */ +struct ndr_syntax_id dcerpc_construct_bind_time_features(uint64_t features); + #define DCERPC_AUTH_PAD_LENGTH(stub_length) (\ (((stub_length) % DCERPC_AUTH_PAD_ALIGNMENT) > 0)?\ (DCERPC_AUTH_PAD_ALIGNMENT - (stub_length) % DCERPC_AUTH_PAD_ALIGNMENT):\ diff --git a/nsswitch/libwbclient/wbc_pam.c b/nsswitch/libwbclient/wbc_pam.c index 390d73ef278..4ae2de1f810 100644 --- a/nsswitch/libwbclient/wbc_pam.c +++ b/nsswitch/libwbclient/wbc_pam.c @@ -1290,7 +1290,17 @@ wbcErr wbcCtxCredentialCache(struct wbcContext *ctx, } for (i=0; i<params->num_blobs; i++) { - if (strcasecmp(params->blobs[i].name, "initial_blob") == 0) { + /* + * Older callers may used to provide the NEGOTIATE request + * as "initial_blob", but it was completely ignored by winbindd. + * + * So we keep ignoring it. + * + * A new callers that is capable to support "new_spnego", + * will provide the NEGOTIATE request as "negotiate_blob" + * instead. + */ + if (strcasecmp(params->blobs[i].name, "negotiate_blob") == 0) { if (initial_blob != NULL) { status = WBC_ERR_INVALID_PARAM; goto fail; @@ -1388,6 +1398,15 @@ wbcErr wbcCtxCredentialCache(struct wbcContext *ctx, if (!WBC_ERROR_IS_OK(status)) { goto fail; } + if (response.data.ccache_ntlm_auth.new_spnego) { + status = wbcAddNamedBlob( + &result->num_blobs, &result->blobs, "new_spnego", 0, + &response.data.ccache_ntlm_auth.new_spnego, + sizeof(response.data.ccache_ntlm_auth.new_spnego)); + if (!WBC_ERROR_IS_OK(status)) { + goto fail; + } + } *info = result; result = NULL; diff --git a/nsswitch/winbind_struct_protocol.h b/nsswitch/winbind_struct_protocol.h index 0dffa4be528..245162d2ad6 100644 --- a/nsswitch/winbind_struct_protocol.h +++ b/nsswitch/winbind_struct_protocol.h @@ -486,6 +486,7 @@ struct winbindd_response { struct { uint8_t session_key[16]; uint32_t auth_blob_len; /* blob in extra_data */ + uint8_t new_spnego; } ccache_ntlm_auth; struct { fstring dc_unc; diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py index 8d3b4dd152d..0499b4e0fc3 100644 --- a/python/samba/tests/__init__.py +++ b/python/samba/tests/__init__.py @@ -1,5 +1,6 @@ # Unix SMB/CIFS implementation. # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2010 +# Copyright (C) Stefan Metzmacher 2014,2015 # # 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 @@ -23,19 +24,27 @@ import samba import samba.auth from samba import param from samba.samdb import SamDB +from samba import credentials +import samba.ndr +import samba.dcerpc.dcerpc +import samba.dcerpc.base +import samba.dcerpc.epmapper +import socket +import struct import subprocess +import sys import tempfile +import unittest -samba.ensure_external_module("testtools", "testtools") +try: + from unittest import SkipTest +except ImportError: + class SkipTest(Exception): + """Test skipped.""" -# Other modules import these two classes from here, for convenience: -from testtools.testcase import ( - TestCase as TesttoolsTestCase, - TestSkipped, - ) +HEXDUMP_FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)]) - -class TestCase(TesttoolsTestCase): +class TestCase(unittest.TestCase): """A Samba test case.""" def setUp(self): @@ -53,8 +62,119 @@ class TestCase(TesttoolsTestCase): def get_credentials(self): return cmdline_credentials - -class LdbTestCase(TesttoolsTestCase): + def hexdump(self, src): + N = 0 + result = '' + while src: + ll = src[:8] + lr = src[8:16] + src = src[16:] + hl = ' '.join(["%02X" % ord(x) for x in ll]) + hr = ' '.join(["%02X" % ord(x) for x in lr]) + ll = ll.translate(HEXDUMP_FILTER) + lr = lr.translate(HEXDUMP_FILTER) + result += "[%04X] %-*s %-*s %s %s\n" % (N, 8*3, hl, 8*3, hr, ll, lr) + N += 16 + return result + + # These functions didn't exist before Python2.7: + if sys.version_info < (2, 7): + import warnings + + def skipTest(self, reason): + raise SkipTest(reason) + + def assertIn(self, member, container, msg=None): + self.assertTrue(member in container, msg) + + def assertIs(self, a, b, msg=None): + self.assertTrue(a is b, msg) + + def assertIsNot(self, a, b, msg=None): + self.assertTrue(a is not b, msg) + + def assertIsNotNone(self, a, msg=None): + self.assertTrue(a is not None) + + def assertIsInstance(self, a, b, msg=None): + self.assertTrue(isinstance(a, b), msg) + + def assertIsNone(self, a, msg=None): + self.assertTrue(a is None, msg) + + def assertGreater(self, a, b, msg=None): + self.assertTrue(a > b, msg) + + def assertGreaterEqual(self, a, b, msg=None): + self.assertTrue(a >= b, msg) + + def assertLess(self, a, b, msg=None): + self.assertTrue(a < b, msg) + + def assertLessEqual(self, a, b, msg=None): + self.assertTrue(a <= b, msg) + + def addCleanup(self, fn, *args, **kwargs): + self._cleanups = getattr(self, "_cleanups", []) + [ + (fn, args, kwargs)] + + def _addSkip(self, result, reason): + addSkip = getattr(result, 'addSkip', None) + if addSkip is not None: + addSkip(self, reason) + else: + warnings.warn("TestResult has no addSkip method, skips not reported", + RuntimeWarning, 2) + result.addSuccess(self) + + def run(self, result=None): + if result is None: result = self.defaultTestResult() + result.startTest(self) + testMethod = getattr(self, self._testMethodName) + try: + try: + self.setUp() + except SkipTest, e: + self._addSkip(result, str(e)) + return + except KeyboardInterrupt: + raise + except: + result.addError(self, self._exc_info()) + return + + ok = False + try: + testMethod() + ok = True + except SkipTest, e: + self._addSkip(result, str(e)) + return + except self.failureException: + result.addFailure(self, self._exc_info()) + except KeyboardInterrupt: + raise + except: + result.addError(self, self._exc_info()) + + try: + self.tearDown() + except SkipTest, e: + self._addSkip(result, str(e)) + except KeyboardInterrupt: + raise + except: + result.addError(self, self._exc_info()) + ok = False + + for (fn, args, kwargs) in reversed(getattr(self, "_cleanups", [])): + fn(*args, **kwargs) + if ok: result.addSuccess(self) + finally: + result.stopTest(self) + + +class LdbTestCase(TestCase): """Trivial test case for running tests against a LDB.""" def setUp(self): @@ -89,7 +209,7 @@ def env_loadparm(): try: lp.load(os.environ["SMB_CONF_PATH"]) except KeyError: - raise Exception("SMB_CONF_PATH not set") + raise KeyError("SMB_CONF_PATH not set") return lp @@ -109,6 +229,524 @@ cmdline_credentials = None class RpcInterfaceTestCase(TestCase): """DCE/RPC Test case.""" +class RawDCERPCTest(TestCase): + """A raw DCE/RPC Test case.""" + + def _disconnect(self, reason): + if self.s is None: + return + self.s.close() + self.s = None + if self.do_hexdump: + sys.stderr.write("disconnect[%s]\n" % reason) + + def connect(self): + try: + self.a = socket.getaddrinfo(self.host, self.tcp_port, socket.AF_UNSPEC, + socket.SOCK_STREAM, socket.SOL_TCP, + 0) + self.s = socket.socket(self.a[0][0], self.a[0][1], self.a[0][2]) + self.s.settimeout(10) + self.s.connect(self.a[0][4]) + except socket.error as e: + self.s.close() + raise + except IOError as e: + self.s.close() + raise + except Exception as e: + raise + finally: + pass + + def setUp(self): + super(RawDCERPCTest, self).setUp() + self.do_ndr_print = False + self.do_hexdump = False + + self.host = samba.tests.env_get_var_value('SERVER') + self.tcp_port = 135 + + self.settings = {} + self.settings["lp_ctx"] = self.lp_ctx = samba.tests.env_loadparm() + self.settings["target_hostname"] = self.host + + self.connect() + + def epmap_reconnect(self, abstract): + ndr32 = samba.dcerpc.base.transfer_syntax_ndr() + + tsf0_list = [ndr32] + ctx0 = samba.dcerpc.dcerpc.ctx_list() + ctx0.context_id = 1 + ctx0.num_transfer_syntaxes = len(tsf0_list) + ctx0.abstract_syntax = samba.dcerpc.epmapper.abstract_syntax() + ctx0.transfer_syntaxes = tsf0_list + + req = self.generate_bind(call_id=0, ctx_list=[ctx0]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_BIND_ACK, + req.call_id, auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEqual(len(rep.u._pad1), 2) + self.assertEqual(rep.u._pad1, '\0' * 2) + self.assertEqual(rep.u.num_results, 1) + self.assertEqual(rep.u.ctx_list[0].result, + samba.dcerpc.dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEqual(rep.u.ctx_list[0].reason, + samba.dcerpc.dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertEqual(rep.u.auth_info, '\0' * 0) + + # And now try a request + data1 = samba.ndr.ndr_pack(abstract) + lhs1 = samba.dcerpc.epmapper.epm_lhs() + lhs1.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_UUID + lhs1.lhs_data = data1[:18] + rhs1 = samba.dcerpc.epmapper.epm_rhs_uuid() + rhs1.unknown = data1[18:] + floor1 = samba.dcerpc.epmapper.epm_floor() + floor1.lhs = lhs1 + floor1.rhs = rhs1 + data2 = samba.ndr.ndr_pack(ndr32) + lhs2 = samba.dcerpc.epmapper.epm_lhs() + lhs2.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_UUID + lhs2.lhs_data = data2[:18] + rhs2 = samba.dcerpc.epmapper.epm_rhs_uuid() + rhs2.unknown = data1[18:] + floor2 = samba.dcerpc.epmapper.epm_floor() + floor2.lhs = lhs2 + floor2.rhs = rhs2 + lhs3 = samba.dcerpc.epmapper.epm_lhs() + lhs3.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_NCACN + lhs3.lhs_data = "" + floor3 = samba.dcerpc.epmapper.epm_floor() + floor3.lhs = lhs3 + floor3.rhs.minor_version = 0 + lhs4 = samba.dcerpc.epmapper.epm_lhs() + lhs4.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_TCP + lhs4.lhs_data = "" + floor4 = samba.dcerpc.epmapper.epm_floor() + floor4.lhs = lhs4 + floor4.rhs.port = self.tcp_port + lhs5 = samba.dcerpc.epmapper.epm_lhs() + lhs5.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_IP + lhs5.lhs_data = "" + floor5 = samba.dcerpc.epmapper.epm_floor() + floor5.lhs = lhs5 + floor5.rhs.ipaddr = "0.0.0.0" + + floors = [floor1,floor2,floor3,floor4,floor5] + req_tower = samba.dcerpc.epmapper.epm_tower() + req_tower.num_floors = len(floors) + req_tower.floors = floors + req_twr = samba.dcerpc.epmapper.epm_twr_t() + req_twr.tower = req_tower + + pack_twr = samba.ndr.ndr_pack(req_twr) + + # object + stub = "\x01\x00\x00\x00" + stub += "\x00" * 16 + # tower + stub += "\x02\x00\x00\x00" + stub += pack_twr + # padding? + stub += "\x00" * 1 + # handle + stub += "\x00" * 20 + # max_towers + stub += "\x04\x00\x00\x00" + + # we do an epm_Map() request + req = self.generate_request(call_id = 1, + context_id=ctx0.context_id, + opnum=3, + stub=stub) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_RESPONSE, + req.call_id, auth_length=0) + self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + num_towers = struct.unpack_from("<I", rep.u.stub_and_verifier, 20) + (array_max, array_ofs, array_cnt) = struct.unpack_from("<III", rep.u.stub_and_verifier, 24) + status = struct.unpack_from("<I", rep.u.stub_and_verifier, len(rep.u.stub_and_verifier) - 4) + self.assertEqual(status[0], 0) + self.assertGreaterEqual(num_towers[0], 1) + self.assertEqual(array_max, 4) + self.assertEqual(array_ofs, 0) + self.assertGreaterEqual(array_cnt, 1) + + unpack_twr = rep.u.stub_and_verifier[(36 + 4 * array_cnt):-4] + rep_twr = samba.ndr.ndr_unpack(samba.dcerpc.epmapper.epm_twr_t, unpack_twr, allow_remaining=True) + self.assertEqual(rep_twr.tower_length, 75) + self.assertEqual(rep_twr.tower.num_floors, 5) + self.assertEqual(len(rep_twr.tower.floors), 5) + self.assertEqual(rep_twr.tower.floors[3].lhs.protocol, + samba.dcerpc.epmapper.EPM_PROTOCOL_TCP) + self.assertEqual(rep_twr.tower.floors[3].lhs.protocol, + samba.dcerpc.epmapper.EPM_PROTOCOL_TCP) + + # reconnect to the given port + self._disconnect("epmap_reconnect") + self.tcp_port = rep_twr.tower.floors[3].rhs.port + self.connect() + + def send_pdu(self, req, ndr_print=None, hexdump=None): + if ndr_print is None: + ndr_print = self.do_ndr_print + if hexdump is None: + hexdump = self.do_hexdump + try: + req_pdu = samba.ndr.ndr_pack(req) + if ndr_print: + sys.stderr.write("send_pdu: %s" % samba.ndr.ndr_print(req)) + if hexdump: + sys.stderr.write("send_pdu: %d\n%s" % (len(req_pdu), self.hexdump(req_pdu))) + while True: + sent = self.s.send(req_pdu, 0) + if sent == len(req_pdu): + break + req_pdu = req_pdu[sent:] + except socket.error as e: + self._disconnect("send_pdu: %s" % e) + raise + except IOError as e: + self._disconnect("send_pdu: %s" % e) + raise + finally: + pass + + def recv_raw(self, hexdump=None, timeout=None): + rep_pdu = None + if hexdump is None: + hexdump = self.do_hexdump + try: + if timeout is not None: + self.s.settimeout(timeout) + rep_pdu = self.s.recv(0xffff, 0) + self.s.settimeout(10) + if len(rep_pdu) == 0: + self._disconnect("recv_raw: EOF") + return None + if hexdump: + sys.stderr.write("recv_raw: %d\n%s" % (len(rep_pdu), self.hexdump(rep_pdu))) + except socket.timeout as e: + self.s.settimeout(10) + sys.stderr.write("recv_raw: TIMEOUT\n") + pass + except socket.error as e: + self._disconnect("recv_raw: %s" % e) + raise + except IOError as e: + self._disconnect("recv_raw: %s" % e) + raise + finally: + pass + return rep_pdu + + def recv_pdu(self, ndr_print=None, hexdump=None, timeout=None): + rep = None + if ndr_print is None: + ndr_print = self.do_ndr_print + if hexdump is None: + hexdump = self.do_hexdump + try: + rep_pdu = self.recv_raw(hexdump=hexdump, timeout=timeout) + if rep_pdu is None: + return None + rep = samba.ndr.ndr_unpack(samba.dcerpc.dcerpc.ncacn_packet, rep_pdu, allow_remaining=True) + if ndr_print: + sys.stderr.write("recv_pdu: %s" % samba.ndr.ndr_print(rep)) + self.assertEqual(rep.frag_length, len(rep_pdu)) + finally: + pass + return rep + + def generate_auth(self, + auth_type=None, + auth_level=None, + auth_pad_length=0, + auth_context_id=None, + auth_blob=None, + ndr_print=None, hexdump=None): + if ndr_print is None: + ndr_print = self.do_ndr_print + if hexdump is None: + hexdump = self.do_hexdump + + if auth_type is not None: + a = samba.dcerpc.dcerpc.auth() + a.auth_type = auth_type + a.auth_level = auth_level + a.auth_pad_length = auth_pad_length + a.auth_context_id= auth_context_id + a.credentials = auth_blob + + ai = samba.ndr.ndr_pack(a) + if ndr_print: + sys.stderr.write("generate_auth: %s" % samba.ndr.ndr_print(a)) + if hexdump: + sys.stderr.write("generate_auth: %d\n%s" % (len(ai), self.hexdump(ai))) + else: + ai = "" + + return ai + + def parse_auth(self, auth_info, ndr_print=None, hexdump=None): + if ndr_print is None: + ndr_print = self.do_ndr_print + if hexdump is None: + hexdump = self.do_hexdump + + if (len(auth_info) <= samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH): + return None + + if hexdump: + sys.stderr.write("parse_auth: %d\n%s" % (len(auth_info), self.hexdump(auth_info))) + a = samba.ndr.ndr_unpack(samba.dcerpc.dcerpc.auth, auth_info, allow_remaining=True) + if ndr_print: + sys.stderr.write("parse_auth: %s" % samba.ndr.ndr_print(a)) + + return a + + def generate_pdu(self, ptype, call_id, payload, + rpc_vers=5, + rpc_vers_minor=0, + pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST | + samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST, + drep = [samba.dcerpc.dcerpc.DCERPC_DREP_LE, 0, 0, 0], + ndr_print=None, hexdump=None): + + if getattr(payload, 'auth_info', None): + ai = payload.auth_info + else: + ai = "" + + p = samba.dcerpc.dcerpc.ncacn_packet() + p.rpc_vers = rpc_vers + p.rpc_vers_minor = rpc_vers_minor + p.ptype = ptype + p.pfc_flags = pfc_flags + p.drep = drep + p.frag_length = 0 + if len(ai) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH: + p.auth_length = len(ai) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH + else: + p.auth_length = 0 + p.call_id = call_id + p.u = payload + + pdu = samba.ndr.ndr_pack(p) + p.frag_length = len(pdu) + + return p + + def verify_pdu(self, p, ptype, call_id, + rpc_vers=5, + rpc_vers_minor=0, + pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST | + samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST, + drep = [samba.dcerpc.dcerpc.DCERPC_DREP_LE, 0, 0, 0], + auth_length=None): + + self.assertIsNotNone(p, "No valid pdu") + + if getattr(p.u, 'auth_info', None): + ai = p.u.auth_info + else: + ai = "" + + self.assertEqual(p.rpc_vers, rpc_vers) + self.assertEqual(p.rpc_vers_minor, rpc_vers_minor) + self.assertEqual(p.ptype, ptype) + self.assertEqual(p.pfc_flags, pfc_flags) + self.assertEqual(p.drep, drep) + self.assertGreaterEqual(p.frag_length, + samba.dcerpc.dcerpc.DCERPC_NCACN_PAYLOAD_OFFSET) + if len(ai) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH: + self.assertEqual(p.auth_length, + len(ai) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH) + elif auth_length is not None: + self.assertEqual(p.auth_length, auth_length) + else: + self.assertEqual(p.auth_length, 0) + self.assertEqual(p.call_id, call_id) + + return + + def generate_bind(self, call_id, + pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST | + samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST, + max_xmit_frag=5840, + max_recv_frag=5840, + assoc_group_id=0, + ctx_list=[], + auth_info="", + ndr_print=None, hexdump=None): + + b = samba.dcerpc.dcerpc.bind() + b.max_xmit_frag = max_xmit_frag + b.max_recv_frag = max_recv_frag + b.assoc_group_id = assoc_group_id + b.num_contexts = len(ctx_list) + b.ctx_list = ctx_list + b.auth_info = auth_info + + p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_BIND, + pfc_flags=pfc_flags, + call_id=call_id, + payload=b, + ndr_print=ndr_print, hexdump=hexdump) + + return p + + def generate_alter(self, call_id, + pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST | + samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST, + max_xmit_frag=5840, + max_recv_frag=5840, + assoc_group_id=0, + ctx_list=[], + auth_info="", + ndr_print=None, hexdump=None): + + a = samba.dcerpc.dcerpc.bind() + a.max_xmit_frag = max_xmit_frag + a.max_recv_frag = max_recv_frag + a.assoc_group_id = assoc_group_id + a.num_contexts = len(ctx_list) + a.ctx_list = ctx_list + a.auth_info = auth_info + + p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_ALTER, + pfc_flags=pfc_flags, + call_id=call_id, + payload=a, + ndr_print=ndr_print, hexdump=hexdump) + + return p + + def generate_auth3(self, call_id, + pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST | + samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST, + auth_info="", + ndr_print=None, hexdump=None): + + a = samba.dcerpc.dcerpc.auth3() + a.auth_info = auth_info + + p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_AUTH3, + pfc_flags=pfc_flags, + call_id=call_id, + payload=a, + ndr_print=ndr_print, hexdump=hexdump) + + return p + + def generate_request(self, call_id, + pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST | + samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST, + alloc_hint=None, + context_id=None, + opnum=None, + object=None, + stub=None, + auth_info="", + ndr_print=None, hexdump=None): + + if alloc_hint is None: + alloc_hint = len(stub) + + r = samba.dcerpc.dcerpc.request() + r.alloc_hint = alloc_hint + r.context_id = context_id + r.opnum = opnum + if object is not None: + r.object = object + r.stub_and_verifier = stub + auth_info + + p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_REQUEST, + pfc_flags=pfc_flags, + call_id=call_id, + payload=r, + ndr_print=ndr_print, hexdump=hexdump) + + if len(auth_info) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH: + p.auth_length = len(auth_info) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH + + return p + + def generate_co_cancel(self, call_id, + pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST | + samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST, + auth_info="", + ndr_print=None, hexdump=None): + + c = samba.dcerpc.dcerpc.co_cancel() + c.auth_info = auth_info + + p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_CO_CANCEL, + pfc_flags=pfc_flags, + call_id=call_id, + payload=c, + ndr_print=ndr_print, hexdump=hexdump) + + return p + + def generate_orphaned(self, call_id, + pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST | + samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST, + auth_info="", + ndr_print=None, hexdump=None): + + o = samba.dcerpc.dcerpc.orphaned() + o.auth_info = auth_info + + p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_ORPHANED, + pfc_flags=pfc_flags, + call_id=call_id, + payload=o, + ndr_print=ndr_print, hexdump=hexdump) + + return p + + def generate_shutdown(self, call_id, + pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST | + samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST, + ndr_print=None, hexdump=None): + + s = samba.dcerpc.dcerpc.shutdown() + + p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_SHUTDOWN, + pfc_flags=pfc_flags, + call_id=call_id, + payload=s, + ndr_print=ndr_print, hexdump=hexdump) + + return p + + def assertIsConnected(self): + self.assertIsNotNone(self.s, msg="Not connected") + return + + def assertNotConnected(self): + self.assertIsNone(self.s, msg="Is connected") + return + + def assertNDRSyntaxEquals(self, s1, s2): + self.assertEqual(s1.uuid, s2.uuid) + self.assertEqual(s1.if_version, s2.if_version) + return class ValidNetbiosNameTests(TestCase): @@ -183,7 +821,6 @@ def connect_samdb(samdb_url, lp=None, session_info=None, credentials=None, to make proper URL for ldb.connect() while using default parameters for connection based on test environment """ - samdb_url = samdb_url.lower() if not "://" in samdb_url: if not ldap_only and os.path.isfile(samdb_url): samdb_url = "tdb://%s" % samdb_url @@ -233,8 +870,28 @@ def connect_samdb_ex(samdb_url, lp=None, session_info=None, credentials=None, return (sam_db, res[0]) +def connect_samdb_env(env_url, env_username, env_password, lp=None): + """Connect to SamDB by getting URL and Credentials from environment + + :param env_url: Environment variable name to get lsb url from + :param env_username: Username environment variable + :param env_password: Password environment variable + :return: sam_db_connection + """ + samdb_url = env_get_var_value(env_url) + creds = credentials.Credentials() + if lp is None: + # guess Credentials parameters here. Otherwise workstation + # and domain fields are NULL and gencache code segfalts + lp = param.LoadParm() + creds.guess(lp) + creds.set_username(env_get_var_value(env_username)) + creds.set_password(env_get_var_value(env_password)) + return connect_samdb(samdb_url, credentials=creds, lp=lp) + + def delete_force(samdb, dn): try: samdb.delete(dn) - except ldb.LdbError, (num, _): - assert(num == ldb.ERR_NO_SUCH_OBJECT) + except ldb.LdbError, (num, errstr): + assert num == ldb.ERR_NO_SUCH_OBJECT, "ldb.delete() failed: %s" % errstr diff --git a/python/samba/tests/dcerpc/bare.py b/python/samba/tests/dcerpc/bare.py index 3efbf9d4cf3..e101c5bcfcf 100644 --- a/python/samba/tests/dcerpc/bare.py +++ b/python/samba/tests/dcerpc/bare.py @@ -31,21 +31,12 @@ class BareTestCase(samba.tests.TestCase): lp_ctx=samba.tests.env_loadparm()) self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) - def test_alter_context(self): + def test_two_contexts(self): x = ClientConnection("ncalrpc:localhost[DEFAULT]", ("12345778-1234-abcd-ef00-0123456789ac", 1), lp_ctx=samba.tests.env_loadparm()) y = ClientConnection("ncalrpc:localhost", ("60a15ec5-4de8-11d7-a637-005056a20182", 1), basis_connection=x, lp_ctx=samba.tests.env_loadparm()) - x.alter_context(("60a15ec5-4de8-11d7-a637-005056a20182", 1)) - # FIXME: self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) - - def test_two_connections(self): - x = ClientConnection("ncalrpc:localhost[DEFAULT]", - ("60a15ec5-4de8-11d7-a637-005056a20182", 1), - lp_ctx=samba.tests.env_loadparm()) - y = ClientConnection("ncalrpc:localhost", - ("60a15ec5-4de8-11d7-a637-005056a20182", 1), - basis_connection=x, lp_ctx=samba.tests.env_loadparm()) + self.assertEquals(24, len(x.request(0, chr(0) * 8))) self.assertEquals("\x01\x00\x00\x00", y.request(0, chr(0) * 4)) diff --git a/python/samba/tests/dcerpc/dnsserver.py b/python/samba/tests/dcerpc/dnsserver.py index 2b421d07bab..7229877a313 100644 --- a/python/samba/tests/dcerpc/dnsserver.py +++ b/python/samba/tests/dcerpc/dnsserver.py @@ -27,7 +27,7 @@ class DnsserverTests(RpcInterfaceTestCase): super(DnsserverTests, self).setUp() self.server = env_get_var_value("SERVER_IP") self.zone = env_get_var_value("REALM").lower() - self.conn = dnsserver.dnsserver("ncacn_ip_tcp:%s" % (self.server), + self.conn = dnsserver.dnsserver("ncacn_ip_tcp:%s[sign]" % (self.server), self.get_loadparm(), self.get_credentials()) diff --git a/python/samba/tests/dcerpc/raw_protocol.py b/python/samba/tests/dcerpc/raw_protocol.py new file mode 100755 index 00000000000..ccd0f6bd210 --- /dev/null +++ b/python/samba/tests/dcerpc/raw_protocol.py @@ -0,0 +1,2623 @@ +#!/usr/bin/env python +# Unix SMB/CIFS implementation. +# Copyright (C) Stefan Metzmacher 2014,2015 +# +# 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 3 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, see <http://www.gnu.org/licenses/>. +# + +import sys +import os + +sys.path.insert(0, "bin/python") +os.environ["PYTHONUNBUFFERED"] = "1" + +import samba.dcerpc.dcerpc as dcerpc +import samba.dcerpc.base as base +import samba.dcerpc.epmapper +import samba.dcerpc.mgmt +import samba.dcerpc.netlogon +import struct +from samba.credentials import Credentials +from samba import gensec +from samba.tests import RawDCERPCTest + +global_ndr_print = False +global_hexdump = False + +class TestDCERPC_BIND(RawDCERPCTest): + + def setUp(self): + super(TestDCERPC_BIND, self).setUp() + self.do_ndr_print = global_ndr_print + self.do_hexdump = global_hexdump + + def _test_no_auth_request_bind_pfc_flags(self, req_pfc_flags, rep_pfc_flags): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + req = self.generate_bind(call_id=0, pfc_flags=req_pfc_flags, ctx_list=[ctx1]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id, + pfc_flags=rep_pfc_flags, auth_length=0) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + # sometimes windows sends random bytes + # self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertEquals(rep.u.auth_info, '\0' * 0) + + # And now try a request + req = self.generate_request(call_id = 1, + context_id=ctx1.context_id, + opnum=0, + stub="") + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + def _test_no_auth_request_alter_pfc_flags(self, req_pfc_flags, rep_pfc_flags): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + req = self.generate_bind(call_id=0, ctx_list=[ctx1]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id, + auth_length=0) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + # sometimes windows sends random bytes + # self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertEquals(rep.u.auth_info, '\0' * 0) + + # And now try a alter context + req = self.generate_alter(call_id=0, pfc_flags=req_pfc_flags, ctx_list=[ctx1]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id, + pfc_flags=rep_pfc_flags, auth_length=0) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 0) + self.assertEquals(rep.u.secondary_address, "") + self.assertEquals(len(rep.u._pad1), 2) + # sometimes windows sends random bytes + # self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertEquals(rep.u.auth_info, '\0' * 0) + + # And now try a request + req = self.generate_request(call_id = 1, + context_id=ctx1.context_id, + opnum=0, + stub="") + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + def test_no_auth_request(self): + return self._test_no_auth_request_bind_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + def test_no_auth_request_bind_pfc_00(self): + return self._test_no_auth_request_bind_pfc_flags( + req_pfc_flags=0 | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + def test_no_auth_request_bind_pfc_FIRST(self): + return self._test_no_auth_request_bind_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + def test_no_auth_request_bind_pfc_LAST(self): + return self._test_no_auth_request_bind_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_LAST | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + # TODO: doesn't announce DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN + # without authentication + def _test_no_auth_request_bind_pfc_HDR_SIGNING(self): + return self._test_no_auth_request_bind_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST | + dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) + + def test_no_auth_request_bind_pfc_08(self): + return self._test_no_auth_request_bind_pfc_flags( + req_pfc_flags=0 | + 8 | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + # TODO: doesn't announce DCERPC_PFC_FLAG_CONC_MPX + # by default + def _test_no_auth_request_bind_pfc_CONC_MPX(self): + return self._test_no_auth_request_bind_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_CONC_MPX | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST | + dcerpc.DCERPC_PFC_FLAG_CONC_MPX) + + def test_no_auth_request_bind_pfc_DID_NOT_EXECUTE(self): + return self._test_no_auth_request_bind_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + def test_no_auth_request_bind_pfc_MAYBE(self): + return self._test_no_auth_request_bind_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_MAYBE | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + def test_no_auth_request_bind_pfc_OBJECT_UUID(self): + return self._test_no_auth_request_bind_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_OBJECT_UUID | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + # TODO: doesn't announce DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN + # without authentication + # TODO: doesn't announce DCERPC_PFC_FLAG_CONC_MPX + # by default + def _test_no_auth_request_bind_pfc_ff(self): + return self._test_no_auth_request_bind_pfc_flags( + req_pfc_flags=0 | + 0xff | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST | + dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN | + dcerpc.DCERPC_PFC_FLAG_CONC_MPX) + + def test_no_auth_request_alter_pfc_00(self): + return self._test_no_auth_request_alter_pfc_flags( + req_pfc_flags=0 | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + def test_no_auth_request_alter_pfc_FIRST(self): + return self._test_no_auth_request_alter_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + def test_no_auth_request_alter_pfc_LAST(self): + return self._test_no_auth_request_alter_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_LAST | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + # TODO: doesn't announce DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN + # without authentication + def _test_no_auth_request_alter_pfc_HDR_SIGNING(self): + return self._test_no_auth_request_alter_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST | + dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) + + def test_no_auth_request_alter_pfc_08(self): + return self._test_no_auth_request_alter_pfc_flags( + req_pfc_flags=0 | + 8 | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + def test_no_auth_request_alter_pfc_CONC_MPX(self): + return self._test_no_auth_request_alter_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_CONC_MPX | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + def test_no_auth_request_alter_pfc_DID_NOT_EXECUTE(self): + return self._test_no_auth_request_alter_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + def test_no_auth_request_alter_pfc_MAYBE(self): + return self._test_no_auth_request_alter_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_MAYBE | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + def test_no_auth_request_alter_pfc_OBJECT_UUID(self): + return self._test_no_auth_request_alter_pfc_flags( + req_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_OBJECT_UUID | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST) + + # TODO: doesn't announce DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN + # without authentication + def _test_no_auth_request_alter_pfc_ff(self): + return self._test_no_auth_request_alter_pfc_flags( + req_pfc_flags=0 | + 0xff | + 0, + rep_pfc_flags=0 | + dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST | + dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) + + def test_no_auth_no_ctx(self): + # send an useless bind + req = self.generate_bind(call_id=0) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id, + auth_length=0) + self.assertEquals(rep.u.reject_reason, + dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED) + self.assertEquals(rep.u.num_versions, 1) + self.assertEquals(rep.u.versions[0].rpc_vers, req.rpc_vers) + self.assertEquals(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor) + self.assertEquals(len(rep.u._pad), 3) + self.assertEquals(rep.u._pad, '\0' * 3) + + def test_invalid_auth_noctx(self): + req = self.generate_bind(call_id=0) + req.auth_length = dcerpc.DCERPC_AUTH_TRAILER_LENGTH + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id, + auth_length=0) + self.assertEquals(rep.u.reject_reason, + dcerpc.DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED) + self.assertEquals(rep.u.num_versions, 1) + self.assertEquals(rep.u.versions[0].rpc_vers, req.rpc_vers) + self.assertEquals(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor) + self.assertEquals(len(rep.u._pad), 3) + self.assertEquals(rep.u._pad, '\0' * 3) + + def test_no_auth_valid_valid_request(self): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + req = self.generate_bind(call_id=0, ctx_list=[ctx1]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id, + auth_length=0) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertEquals(rep.u.auth_info, '\0' * 0) + + # Send a bind again + tsf2_list = [ndr32] + ctx2 = dcerpc.ctx_list() + ctx2.context_id = 2 + ctx2.num_transfer_syntaxes = len(tsf2_list) + ctx2.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx2.transfer_syntaxes = tsf2_list + + req = self.generate_bind(call_id=1, ctx_list=[ctx2]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id, + auth_length=0) + self.assertEquals(rep.u.reject_reason, + dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED) + self.assertEquals(rep.u.num_versions, 1) + self.assertEquals(rep.u.versions[0].rpc_vers, req.rpc_vers) + self.assertEquals(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor) + self.assertEquals(len(rep.u._pad), 3) + self.assertEquals(rep.u._pad, '\0' * 3) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_no_auth_invalid_valid_request(self): + # send an useless bind + req = self.generate_bind(call_id=0) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id, + auth_length=0) + self.assertEquals(rep.u.reject_reason, + dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED) + self.assertEquals(rep.u.num_versions, 1) + self.assertEquals(rep.u.versions[0].rpc_vers, req.rpc_vers) + self.assertEquals(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor) + self.assertEquals(len(rep.u._pad), 3) + self.assertEquals(rep.u._pad, '\0' * 3) + + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_alter_no_auth_no_ctx(self): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + req = self.generate_bind(call_id=0, ctx_list=[ctx1]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id, + auth_length=0) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertEquals(rep.u.auth_info, '\0' * 0) + + # Send a alter + req = self.generate_alter(call_id=1, ctx_list=[]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, 0) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def _test_auth_none_level_bind(self, auth_level, + reason=dcerpc.DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + ctx_list = [ctx1] + + auth_type = dcerpc.DCERPC_AUTH_TYPE_NONE + auth_context_id = 0 + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob="none") + + req = self.generate_bind(call_id=0, + ctx_list=ctx_list, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id, + auth_length=0) + self.assertEquals(rep.u.reject_reason, reason) + self.assertEquals(rep.u.num_versions, 1) + self.assertEquals(rep.u.versions[0].rpc_vers, req.rpc_vers) + self.assertEquals(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor) + self.assertEquals(len(rep.u._pad), 3) + self.assertEquals(rep.u._pad, '\0' * 3) + + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_auth_none_none_bind(self): + return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_NONE, + reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED) + + def test_auth_none_connect_bind(self): + return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_CONNECT) + + def test_auth_none_call_bind(self): + return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_CALL) + + def test_auth_none_packet_bind(self): + return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_PACKET) + + def test_auth_none_integrity_bind(self): + return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY) + + def test_auth_none_privacy_bind(self): + return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_PRIVACY) + + def test_auth_none_0_bind(self): + return self._test_auth_none_level_bind(0, + reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED) + + def test_auth_none_7_bind(self): + return self._test_auth_none_level_bind(7, + reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED) + + def test_auth_none_255_bind(self): + return self._test_auth_none_level_bind(255, + reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED) + + def _test_auth_none_level_request(self, auth_level): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + ctx_list = [ctx1] + + auth_type = dcerpc.DCERPC_AUTH_TYPE_NONE + auth_context_id = 0 + + req = self.generate_bind(call_id=0, + ctx_list=ctx_list) + + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertEquals(len(rep.u.auth_info), 0) + + # And now try a request without auth_info + req = self.generate_request(call_id = 2, + context_id=ctx1.context_id, + opnum=0, + stub="") + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob="none") + + req = self.generate_request(call_id = 3, + context_id=ctx1.context_id, + opnum=0, + stub="", + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_auth_none_none_request(self): + return self._test_auth_none_level_request(dcerpc.DCERPC_AUTH_LEVEL_NONE) + + def test_auth_none_connect_request(self): + return self._test_auth_none_level_request(dcerpc.DCERPC_AUTH_LEVEL_CONNECT) + + def test_auth_none_call_request(self): + return self._test_auth_none_level_request(dcerpc.DCERPC_AUTH_LEVEL_CALL) + + def _test_neg_xmit_check_values(self, + req_xmit=None, + req_recv=None, + rep_both=None, + alter_xmit=None, + alter_recv=None): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + req = self.generate_bind(call_id=0, + max_xmit_frag=req_xmit, + max_recv_frag=req_recv, + ctx_list=[ctx1]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id, + auth_length=0) + self.assertEquals(rep.u.max_xmit_frag, rep_both) + self.assertEquals(rep.u.max_recv_frag, rep_both) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertEquals(rep.u.auth_info, '\0' * 0) + + assoc_group_id = rep.u.assoc_group_id + if alter_xmit is None: + alter_xmit = rep_both - 8 + if alter_recv is None: + alter_recv = rep_both - 8 + + # max_{xmit,recv}_frag and assoc_group_id are completely + # ignored in alter_context requests + req = self.generate_alter(call_id=1, + max_xmit_frag=alter_xmit, + max_recv_frag=alter_recv, + assoc_group_id=0xffffffff-rep.u.assoc_group_id, + ctx_list=[ctx1]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id, + auth_length=0) + self.assertEquals(rep.u.max_xmit_frag, rep_both) + self.assertEquals(rep.u.max_recv_frag, rep_both) + self.assertEquals(rep.u.assoc_group_id, rep.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 0) + self.assertEquals(len(rep.u._pad1), 2) + #self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertEquals(rep.u.auth_info, '\0' * 0) + + chunk_size = rep_both - dcerpc.DCERPC_REQUEST_LENGTH + req = self.generate_request(call_id = 2, + context_id=ctx1.context_id, + opnum=0, + alloc_hint=0xffffffff, + stub="\00" * chunk_size) + self.send_pdu(req,ndr_print=True,hexdump=True) + rep = self.recv_pdu(ndr_print=True,hexdump=True) + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + chunk_size = 5840 - dcerpc.DCERPC_REQUEST_LENGTH + req = self.generate_request(call_id = 2, + context_id=ctx1.context_id, + opnum=0, + alloc_hint=0xffffffff, + stub="\00" * chunk_size) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + chunk_size += 1 + req = self.generate_request(call_id = 3, + context_id=ctx1.context_id, + opnum=0, + alloc_hint=0xffffffff, + stub="\00" * chunk_size) + self.send_pdu(req) + rep = self.recv_pdu() + # We get a fault + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, 0) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_neg_xmit_ffff_ffff(self): + return self._test_neg_xmit_check_values(req_xmit=0xffff, + req_recv=0xffff, + rep_both=5840) + + def test_neg_xmit_0_ffff(self): + return self._test_neg_xmit_check_values(req_xmit=0, + req_recv=0xffff, + rep_both=2048, + alter_xmit=0xffff, + alter_recv=0xffff) + + def test_neg_xmit_ffff_0(self): + return self._test_neg_xmit_check_values(req_xmit=0xffff, + req_recv=0, + rep_both=2048) + + def test_neg_xmit_0_0(self): + return self._test_neg_xmit_check_values(req_xmit=0, + req_recv=0, + rep_both=2048, + alter_xmit=0xffff, + alter_recv=0xffff) + + def test_neg_xmit_3199_0(self): + return self._test_neg_xmit_check_values(req_xmit=3199, + req_recv=0, + rep_both=2048) + def test_neg_xmit_0_3199(self): + return self._test_neg_xmit_check_values(req_xmit=0, + req_recv=3199, + rep_both=2048) + + def test_neg_xmit_3199_ffff(self): + return self._test_neg_xmit_check_values(req_xmit=3199, + req_recv=0xffff, + rep_both=3192) + def test_neg_xmit_ffff_3199(self): + return self._test_neg_xmit_check_values(req_xmit=0xffff, + req_recv=3199, + rep_both=3192) + + def test_alloc_hint(self): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx = dcerpc.ctx_list() + ctx.context_id = 0 + ctx.num_transfer_syntaxes = len(tsf1_list) + ctx.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx.transfer_syntaxes = tsf1_list + + req = self.generate_bind(call_id=0, + ctx_list=[ctx]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id, + auth_length=0) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertEquals(rep.u.auth_info, '\0' * 0) + + # And now try a request without auth_info + req = self.generate_request(call_id = 2, + context_id=ctx.context_id, + opnum=0, + alloc_hint=0xffffffff, + stub="") + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + req = self.generate_request(call_id = 3, + context_id=ctx.context_id, + opnum=1, + alloc_hint=0xffffffff, + stub="\04\00\00\00\00\00\00\00") + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + req = self.generate_request(call_id = 4, + context_id=ctx.context_id, + opnum=1, + alloc_hint=1, + stub="\04\00\00\00\00\00\00\00") + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + def _get_netlogon_ctx(self): + abstract = samba.dcerpc.netlogon.abstract_syntax() + self.epmap_reconnect(abstract) + + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx = dcerpc.ctx_list() + ctx.context_id = 0 + ctx.num_transfer_syntaxes = len(tsf1_list) + ctx.abstract_syntax = abstract + ctx.transfer_syntaxes = tsf1_list + + req = self.generate_bind(call_id=0, + ctx_list=[ctx]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id, + auth_length=0) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + port_str = "%d" % self.tcp_port + port_len = len(port_str) + 1 + mod_len = (2 + port_len) % 4 + if mod_len != 0: + port_pad = 4 - mod_len + else: + port_pad = 0 + self.assertEquals(rep.u.secondary_address_size, port_len) + self.assertEquals(rep.u.secondary_address, port_str) + self.assertEquals(len(rep.u._pad1), port_pad) + self.assertEquals(rep.u._pad1, '\0' * port_pad) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertEquals(rep.u.auth_info, '\0' * 0) + + server = '\\\\' + self.host + server_utf16 = unicode(server, 'utf-8').encode('utf-16-le') + computer = 'UNKNOWNCOMPUTER' + computer_utf16 = unicode(computer, 'utf-8').encode('utf-16-le') + + real_stub = struct.pack('<IIII', 0x00200000, + len(server)+1, 0, len(server)+1) + real_stub += server_utf16 + '\x00\x00' + mod_len = len(real_stub) % 4 + if mod_len != 0: + real_stub += '\x00' * (4 - mod_len) + real_stub += struct.pack('<III', + len(computer)+1, 0, len(computer)+1) + real_stub += computer_utf16 + '\x00\x00' + real_stub += '\x11\x22\x33\x44\x55\x66\x77\x88' + + return (ctx, rep, real_stub) + + def _test_fragmented_requests(self, remaining=None, alloc_hint=None, + fault_first=None, fault_last=None): + (ctx, rep, real_stub) = self._get_netlogon_ctx() + + chunk = rep.u.max_recv_frag - dcerpc.DCERPC_REQUEST_LENGTH + + total = 0 + first = True + while remaining > 0: + thistime = min(remaining, chunk) + remaining -= thistime + total += thistime + + pfc_flags = 0 + if first: + pfc_flags |= dcerpc.DCERPC_PFC_FLAG_FIRST + first = False + stub = real_stub + '\x00' * (thistime - len(real_stub)) + else: + stub = "\x00" * thistime + + if remaining == 0: + pfc_flags |= dcerpc.DCERPC_PFC_FLAG_LAST + + # And now try a request without auth_info + # netr_ServerReqChallenge() + req = self.generate_request(call_id = 2, + pfc_flags=pfc_flags, + context_id=ctx.context_id, + opnum=4, + alloc_hint=alloc_hint, + stub=stub) + if alloc_hint >= thistime: + alloc_hint -= thistime + else: + alloc_hint = 0 + self.send_pdu(req,hexdump=False) + if fault_first is not None: + rep = self.recv_pdu() + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, fault_first) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + return + if remaining == 0: + break + if total >= 0x400000 and fault_last is not None: + rep = self.recv_pdu() + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, fault_last) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + return + rep = self.recv_pdu(timeout=0.01) + self.assertIsNone(rep) + self.assertIsConnected() + + if total >= 0x400000 and fault_last is not None: + rep = self.recv_pdu() + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, fault_last) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + return + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + self.assertEquals(len(rep.u.stub_and_verifier), 12) + status = struct.unpack_from("<I", rep.u.stub_and_verifier, len(rep.u.stub_and_verifier) - 4) + self.assertEquals(status[0], 0) + + def test_fragmented_requests01(self): + return self._test_fragmented_requests(remaining=0x400000, + alloc_hint=0x400000) + + def test_fragmented_requests02(self): + return self._test_fragmented_requests(remaining=0x400000, + alloc_hint=0x100000) + + def test_fragmented_requests03(self): + return self._test_fragmented_requests(remaining=0x400000, + alloc_hint=0) + + def test_fragmented_requests04(self): + return self._test_fragmented_requests(remaining=0x400000, + alloc_hint=0x400001, + fault_first=dcerpc.DCERPC_FAULT_ACCESS_DENIED) + + def test_fragmented_requests05(self): + return self._test_fragmented_requests(remaining=0x500001, + alloc_hint=0, + fault_last=dcerpc.DCERPC_FAULT_ACCESS_DENIED) + + def _test_same_requests(self, pfc_flags, fault_1st=False, fault_2nd=False): + (ctx, rep, real_stub) = self._get_netlogon_ctx() + + # netr_ServerReqChallenge with given flags + req = self.generate_request(call_id = 2, + pfc_flags=pfc_flags, + context_id=ctx.context_id, + opnum=4, + stub=real_stub) + self.send_pdu(req) + if fault_1st: + rep = self.recv_pdu() + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + return + rep = self.recv_pdu(timeout=0.1) + self.assertIsNone(rep) + self.assertIsConnected() + + # netr_ServerReqChallenge without DCERPC_PFC_FLAG_LAST + # with the same call_id + req = self.generate_request(call_id = 2, + pfc_flags=pfc_flags, + context_id=ctx.context_id, + opnum=4, + stub=real_stub) + self.send_pdu(req) + if fault_2nd: + rep = self.recv_pdu() + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + return + + rep = self.recv_pdu(timeout=0.1) + self.assertIsNone(rep) + self.assertIsConnected() + + def test_first_only_requests(self): + return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST, + fault_2nd=True) + + def test_none_only_requests(self): + return self._test_same_requests(pfc_flags=0, fault_1st=True) + + def test_last_only_requests(self): + return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_LAST, + fault_1st=True) + + def test_first_maybe_requests(self): + return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_MAYBE, + fault_2nd=True) + + def test_first_didnot_requests(self): + return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + fault_2nd=True) + + def test_first_cmpx_requests(self): + return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_CONC_MPX, + fault_2nd=True) + + def test_first_08_requests(self): + return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST | + 0x08, + fault_2nd=True) + + def test_first_cancel_requests(self): + (ctx, rep, real_stub) = self._get_netlogon_ctx() + + # netr_ServerReqChallenge with given flags + req = self.generate_request(call_id = 2, + pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_PENDING_CANCEL, + context_id=ctx.context_id, + opnum=4, + stub=real_stub) + self.send_pdu(req) + rep = self.recv_pdu() + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_NO_CALL_ACTIVE) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_2nd_cancel_requests(self): + (ctx, rep, real_stub) = self._get_netlogon_ctx() + + # netr_ServerReqChallenge with given flags + req = self.generate_request(call_id = 2, + pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST, + context_id=ctx.context_id, + opnum=4, + stub=real_stub) + self.send_pdu(req) + rep = self.recv_pdu(timeout=0.1) + self.assertIsNone(rep) + self.assertIsConnected() + + # netr_ServerReqChallenge with given flags + req = self.generate_request(call_id = 2, + pfc_flags=dcerpc.DCERPC_PFC_FLAG_PENDING_CANCEL, + context_id=ctx.context_id, + opnum=4, + stub=real_stub) + self.send_pdu(req) + rep = self.recv_pdu(timeout=0.1) + self.assertIsNone(rep) + self.assertIsConnected() + + # netr_ServerReqChallenge with given flags + req = self.generate_request(call_id = 2, + pfc_flags=dcerpc.DCERPC_PFC_FLAG_LAST, + context_id=ctx.context_id, + opnum=4, + stub=real_stub) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + self.assertEquals(len(rep.u.stub_and_verifier), 12) + status = struct.unpack_from("<I", rep.u.stub_and_verifier, len(rep.u.stub_and_verifier) - 4) + self.assertEquals(status[0], 0) + + def test_last_cancel_requests(self): + (ctx, rep, real_stub) = self._get_netlogon_ctx() + + # netr_ServerReqChallenge with given flags + req = self.generate_request(call_id = 2, + pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST, + context_id=ctx.context_id, + opnum=4, + stub=real_stub[:4]) + self.send_pdu(req) + rep = self.recv_pdu(timeout=0.1) + self.assertIsNone(rep) + self.assertIsConnected() + + # netr_ServerReqChallenge with given flags + req = self.generate_request(call_id = 2, + pfc_flags=dcerpc.DCERPC_PFC_FLAG_LAST | + dcerpc.DCERPC_PFC_FLAG_PENDING_CANCEL, + context_id=ctx.context_id, + opnum=4, + stub=real_stub[4:]) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + self.assertEquals(len(rep.u.stub_and_verifier), 12) + status = struct.unpack_from("<I", rep.u.stub_and_verifier, len(rep.u.stub_and_verifier) - 4) + self.assertEquals(status[0], 0) + + def test_mix_requests(self): + (ctx, rep, real_stub) = self._get_netlogon_ctx() + + # netr_ServerReqChallenge with given flags + req = self.generate_request(call_id = 50, + pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST, + context_id=ctx.context_id, + opnum=4, + stub=real_stub) + self.send_pdu(req) + rep = self.recv_pdu(timeout=0.1) + self.assertIsNone(rep) + self.assertIsConnected() + + # netr_ServerReqChallenge with given flags + req = self.generate_request(call_id = 51, + pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST, + context_id=ctx.context_id, + opnum=4, + stub=real_stub) + self.send_pdu(req) + rep = self.recv_pdu() + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, 50, + pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + def test_spnego_connect_request(self): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + ctx_list = [ctx1] + + c = Credentials() + c.set_anonymous() + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + + req = self.generate_bind(call_id=0, + ctx_list=ctx_list, + auth_info=auth_info) + + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + + req = self.generate_alter(call_id=0, + ctx_list=ctx_list, + assoc_group_id=rep.u.assoc_group_id, + auth_info=auth_info) + + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 0) + self.assertEquals(len(rep.u._pad1), 2) + # Windows sends garbage + #self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertTrue(finished) + + # And now try a request without auth_info + req = self.generate_request(call_id = 2, + context_id=ctx1.context_id, + opnum=0, + stub="") + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob="\x01"+"\x00"*15) + req = self.generate_request(call_id = 3, + context_id=ctx1.context_id, + opnum=0, + stub="", + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + # We don't get an auth_info back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + # Now a request with auth_info DCERPC_AUTH_LEVEL_INTEGRITY + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY, + auth_context_id=auth_context_id, + auth_blob="\x01"+"\x00"*15) + req = self.generate_request(call_id = 4, + context_id=ctx1.context_id, + opnum=0, + stub="", + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_spnego_integrity_request(self): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + ctx_list = [ctx1] + + c = Credentials() + c.set_anonymous() + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + + req = self.generate_bind(call_id=0, + ctx_list=ctx_list, + auth_info=auth_info) + + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + + req = self.generate_alter(call_id=0, + ctx_list=ctx_list, + assoc_group_id=rep.u.assoc_group_id, + auth_info=auth_info) + + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 0) + self.assertEquals(len(rep.u._pad1), 2) + # Windows sends garbage + #self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertTrue(finished) + + # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=dcerpc.DCERPC_AUTH_LEVEL_CONNECT, + auth_context_id=auth_context_id, + auth_blob="\x01"+"\x00"*15) + req = self.generate_request(call_id = 3, + context_id=ctx1.context_id, + opnum=0, + stub="", + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_spnego_unfinished_request(self): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + ctx_list = [ctx1] + + c = Credentials() + c.set_anonymous() + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + + req = self.generate_bind(call_id=0, + ctx_list=ctx_list, + auth_info=auth_info) + + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + assoc_group_id = rep.u.assoc_group_id + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob="\x01"+"\x00"*15) + req = self.generate_request(call_id = 1, + context_id=ctx1.context_id, + opnum=0, + stub="", + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + # We get a fault + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, 0) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_spnego_auth3(self): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + ctx_list = [ctx1] + + c = Credentials() + c.set_anonymous() + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_bind(call_id=0, + ctx_list=ctx_list, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + #self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_auth3(call_id=0, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertIsConnected() + + # And now try a request without auth_info + req = self.generate_request(call_id = 2, + context_id=ctx1.context_id, + opnum=0, + stub="") + self.send_pdu(req) + rep = self.recv_pdu() + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_spnego_connect_reauth_alter(self): + ndr32 = base.transfer_syntax_ndr() + ndr64 = base.transfer_syntax_ndr64() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + ctx_list = [ctx1] + + c = Credentials() + c.set_anonymous() + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + + req = self.generate_bind(call_id=0, + ctx_list=ctx_list, + auth_info=auth_info) + + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_alter(call_id=0, + ctx_list=[ctx1], + assoc_group_id=rep.u.assoc_group_id, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 0) + self.assertEquals(len(rep.u._pad1), 2) + # Windows sends garbage + #self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertTrue(finished) + + # And now try a request without auth_info + req = self.generate_request(call_id = 2, + context_id=ctx1.context_id, + opnum=0, + stub="") + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob="\x01"+"\x00"*15) + req = self.generate_request(call_id = 3, + context_id=ctx1.context_id, + opnum=0, + stub="", + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + # We don't get an auth_info back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + # Now a reauth + + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_alter(call_id=0, + ctx_list=ctx_list, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + # We get a fault + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, 0) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_spnego_connect_reauth_auth3(self): + ndr32 = base.transfer_syntax_ndr() + ndr64 = base.transfer_syntax_ndr64() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + ctx_list = [ctx1] + + c = Credentials() + c.set_anonymous() + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + + req = self.generate_bind(call_id=0, + ctx_list=ctx_list, + auth_info=auth_info) + + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_alter(call_id=0, + ctx_list=[ctx1], + assoc_group_id=rep.u.assoc_group_id, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 0) + self.assertEquals(len(rep.u._pad1), 2) + # Windows sends garbage + #self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertTrue(finished) + + # And now try a request without auth_info + req = self.generate_request(call_id = 2, + context_id=ctx1.context_id, + opnum=0, + stub="") + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob="\x01"+"\x00"*15) + req = self.generate_request(call_id = 3, + context_id=ctx1.context_id, + opnum=0, + stub="", + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + # We don't get an auth_info back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, req.u.context_id) + self.assertEquals(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + + # Now a reauth + + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_auth3(call_id=0, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + # We get a fault + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, 0) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_spnego_change_auth_level(self): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + c = Credentials() + c.set_anonymous() + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_bind(call_id=0, + ctx_list=[ctx1], + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_alter(call_id=0, + ctx_list=[ctx1], + assoc_group_id=rep.u.assoc_group_id, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, 0) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_spnego_change_abstract(self): + ndr32 = base.transfer_syntax_ndr() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + ctx1b = dcerpc.ctx_list() + ctx1b.context_id = 1 + ctx1b.num_transfer_syntaxes = len(tsf1_list) + ctx1b.abstract_syntax = samba.dcerpc.epmapper.abstract_syntax() + ctx1b.transfer_syntaxes = tsf1_list + + c = Credentials() + c.set_anonymous() + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_bind(call_id=0, + ctx_list=[ctx1], + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + #self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_alter(call_id=0, + ctx_list=[ctx1b], + assoc_group_id=rep.u.assoc_group_id, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, 0) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_spnego_change_transfer(self): + ndr32 = base.transfer_syntax_ndr() + ndr64 = base.transfer_syntax_ndr64() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + tsf1b_list = [ndr32,ndr64] + ctx1b = dcerpc.ctx_list() + ctx1b.context_id = 1 + ctx1b.num_transfer_syntaxes = len(tsf1b_list) + ctx1b.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1b.transfer_syntaxes = tsf1b_list + + c = Credentials() + c.set_anonymous() + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_bind(call_id=0, + ctx_list=[ctx1], + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + #self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + # We change ctx_list and auth_level + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_alter(call_id=0, + ctx_list=[ctx1b], + assoc_group_id=rep.u.assoc_group_id, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, 0) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_spnego_change_auth_type1(self): + ndr32 = base.transfer_syntax_ndr() + ndr64 = base.transfer_syntax_ndr64() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + c = Credentials() + c.set_anonymous() + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_bind(call_id=0, + ctx_list=[ctx1], + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + #self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + # We change ctx_list and auth_level + auth_info = self.generate_auth(auth_type=dcerpc.DCERPC_AUTH_TYPE_KRB5, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_alter(call_id=0, + ctx_list=[ctx1], + assoc_group_id=rep.u.assoc_group_id, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, 0) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_SEC_PKG_ERROR) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_spnego_change_auth_type2(self): + ndr32 = base.transfer_syntax_ndr() + ndr64 = base.transfer_syntax_ndr64() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + tsf1b_list = [ndr32,ndr64] + ctx1b = dcerpc.ctx_list() + ctx1b.context_id = 1 + ctx1b.num_transfer_syntaxes = len(tsf1b_list) + ctx1b.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1b.transfer_syntaxes = tsf1b_list + + c = Credentials() + c.set_anonymous() + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_bind(call_id=0, + ctx_list=[ctx1], + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + #self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + # We change ctx_list and auth_level + auth_info = self.generate_auth(auth_type=dcerpc.DCERPC_AUTH_TYPE_KRB5, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_alter(call_id=0, + ctx_list=[ctx1b], + assoc_group_id=rep.u.assoc_group_id, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, 0) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + + def test_spnego_change_auth_type3(self): + ndr32 = base.transfer_syntax_ndr() + ndr64 = base.transfer_syntax_ndr64() + + tsf1_list = [ndr32] + ctx1 = dcerpc.ctx_list() + ctx1.context_id = 1 + ctx1.num_transfer_syntaxes = len(tsf1_list) + ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1.transfer_syntaxes = tsf1_list + + tsf1b_list = [ndr32,ndr64] + ctx1b = dcerpc.ctx_list() + ctx1b.context_id = 1 + ctx1b.num_transfer_syntaxes = len(tsf1b_list) + ctx1b.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax() + ctx1b.transfer_syntaxes = tsf1b_list + + c = Credentials() + c.set_anonymous() + g = gensec.Security.start_client(self.settings) + g.set_credentials(c) + g.want_feature(gensec.FEATURE_DCE_STYLE) + auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO + auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY + auth_context_id = 2 + g.start_mech_by_authtype(auth_type, auth_level) + from_server = "" + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + auth_info = self.generate_auth(auth_type=auth_type, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_bind(call_id=0, + ctx_list=[ctx1], + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag) + self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEquals(rep.u.secondary_address_size, 4) + self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertEquals(len(rep.u._pad1), 2) + #self.assertEquals(rep.u._pad1, '\0' * 2) + self.assertEquals(rep.u.num_results, 1) + self.assertEquals(rep.u.ctx_list[0].result, + dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE) + self.assertEquals(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) + self.assertNotEquals(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials + (finished, to_server) = g.update(from_server) + self.assertFalse(finished) + + # We change ctx_list and auth_level + auth_info = self.generate_auth(auth_type=dcerpc.DCERPC_AUTH_TYPE_NONE, + auth_level=auth_level, + auth_context_id=auth_context_id, + auth_blob=to_server) + req = self.generate_alter(call_id=0, + ctx_list=[ctx1b], + assoc_group_id=rep.u.assoc_group_id, + auth_info=auth_info) + self.send_pdu(req) + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) + self.assertNotEquals(rep.u.alloc_hint, 0) + self.assertEquals(rep.u.context_id, 0) + self.assertEquals(rep.u.cancel_count, 0) + self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED) + self.assertEquals(len(rep.u._pad), 4) + self.assertEquals(rep.u._pad, '\0' * 4) + + # wait for a disconnect + rep = self.recv_pdu() + self.assertIsNone(rep) + self.assertNotConnected() + +if __name__ == "__main__": + global_ndr_print = True + global_hexdump = True + import unittest + unittest.main() diff --git a/python/samba/tests/dcerpc/srvsvc.py b/python/samba/tests/dcerpc/srvsvc.py index 3206a27e678..407a9d52a73 100644 --- a/python/samba/tests/dcerpc/srvsvc.py +++ b/python/samba/tests/dcerpc/srvsvc.py @@ -45,12 +45,12 @@ class SrvsvcTests(RpcInterfaceTestCase): return share def test_NetShareAdd(self): - self.skip("Dangerous test") + self.skipTest("Dangerous test") share = self.getDummyShareObject() self.conn.NetShareAdd(self.server_unc, 2, share, None) def test_NetShareSetInfo(self): - self.skip("Dangerous test") + self.skipTest("Dangerous test") share = self.getDummyShareObject() parm_error = 0x00000000 self.conn.NetShareAdd(self.server_unc, 502, share, parm_error) @@ -60,7 +60,7 @@ class SrvsvcTests(RpcInterfaceTestCase): 502, share, parm_error) def test_NetShareDel(self): - self.skip("Dangerous test") + self.skipTest("Dangerous test") share = self.getDummyShareObject() parm_error = 0x00000000 self.expectFailure("NetShareAdd doesn't work properly from Python", diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py index f7f56a3696b..a0d93abbda8 100644 --- a/python/samba/tests/dns.py +++ b/python/samba/tests/dns.py @@ -33,8 +33,6 @@ parser = optparse.OptionParser("dns.py <server name> <server ip> [options]") sambaopts = options.SambaOptions(parser) parser.add_option_group(sambaopts) -FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)]) - # This timeout only has relevance when testing against Windows # Format errors tend to return patchy responses, so a timeout is needed. parser.add_option("--timeout", type="int", dest="timeout", @@ -178,16 +176,6 @@ class DNSTest(TestCase): if s is not None: s.close() - def hexdump(self, src, length=8): - N=0; result='' - while src: - s,src = src[:length],src[length:] - hexa = ' '.join(["%02X"%ord(x) for x in s]) - s = s.translate(FILTER) - result += "%04X %-*s %s\n" % (N, length*3, hexa, s) - N+=length - return result - def make_txt_update(self, prefix, txt_array): p = self.make_name_packet(dns.DNS_OPCODE_UPDATE) updates = [] diff --git a/python/samba/tests/docs.py b/python/samba/tests/docs.py index 0d71e685ab7..561628f901d 100644 --- a/python/samba/tests/docs.py +++ b/python/samba/tests/docs.py @@ -21,9 +21,7 @@ import samba import samba.tests -from samba.tests import TestSkipped, TestCaseInTempDir -import errno import os import re import subprocess @@ -36,6 +34,7 @@ class TestCase(samba.tests.TestCaseInTempDir): parameters.sort() return message + '\n\n %s' % ('\n '.join(parameters)) + def get_documented_parameters(sourcedir): path = os.path.join(sourcedir, "bin", "default", "docs-xml", "smbdotconf") if not os.path.exists(os.path.join(path, "parameters.all.xml")): diff --git a/python/samba/tests/ntacls.py b/python/samba/tests/ntacls.py index aa9ef6852ba..8cd09fbcc54 100644 --- a/python/samba/tests/ntacls.py +++ b/python/samba/tests/ntacls.py @@ -19,10 +19,9 @@ """Tests for samba.ntacls.""" from samba.ntacls import setntacl, getntacl, XattrBackendError -from samba.dcerpc import xattr, security from samba.param import LoadParm -from samba.tests import TestCaseInTempDir, TestSkipped -import random +from samba.dcerpc import security +from samba.tests import TestCaseInTempDir, SkipTest import os class NtaclsTests(TestCaseInTempDir): @@ -64,7 +63,7 @@ class NtaclsTests(TestCaseInTempDir): def test_setntacl_forcenative(self): if os.getuid() == 0: - raise TestSkipped("Running test as root, test skipped") + raise SkipTest("Running test as root, test skipped") lp = LoadParm() acl = "O:S-1-5-21-2212615479-2695158682-2101375467-512G:S-1-5-21-2212615479-2695158682-2101375467-513D:(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375467-512)" open(self.tempf, 'w').write("empty") diff --git a/python/samba/tests/subunitrun.py b/python/samba/tests/subunitrun.py index d45467607e6..291e7ab461a 100755 --- a/python/samba/tests/subunitrun.py +++ b/python/samba/tests/subunitrun.py @@ -37,9 +37,7 @@ signal.signal(signal.SIGINT, signal.SIG_DFL) import optparse import samba import sys -samba.ensure_external_module("mimeparse", "mimeparse") -samba.ensure_external_module("extras", "extras") -samba.ensure_external_module("testtools", "testtools") +import samba.tests samba.ensure_external_module("subunit", "subunit/python") import subunit.run diff --git a/python/samba/tests/xattr.py b/python/samba/tests/xattr.py index 89add284566..63874523f00 100644 --- a/python/samba/tests/xattr.py +++ b/python/samba/tests/xattr.py @@ -22,9 +22,9 @@ from samba.xattr import copytree_with_xattrs from samba.dcerpc import xattr from samba.ndr import ndr_pack from samba.tests import ( + SkipTest, TestCase, TestCaseInTempDir, - TestSkipped, ) import random import shutil @@ -42,7 +42,7 @@ class XattrTests(TestCase): def test_set_xattr_native(self): if not samba.xattr_native.is_xattr_supported(): - raise TestSkipped() + raise SkipTest() ntacl = xattr.NTACL() ntacl.version = 1 tempf = self._tmpfilename() @@ -51,12 +51,12 @@ class XattrTests(TestCase): samba.xattr_native.wrap_setxattr(tempf, "user.unittests", ndr_pack(ntacl)) except IOError: - raise TestSkipped("the filesystem where the tests are runned do not support XATTR") + raise SkipTest("the filesystem where the tests are runned do not support XATTR") os.unlink(tempf) def test_set_and_get_native(self): if not samba.xattr_native.is_xattr_supported(): - raise TestSkipped() + raise SkipTest() tempf = self._tmpfilename() reftxt = "this is a test" open(tempf, 'w').write("empty") @@ -65,7 +65,7 @@ class XattrTests(TestCase): text = samba.xattr_native.wrap_getxattr(tempf, "user.unittests") self.assertEquals(text, reftxt) except IOError: - raise TestSkipped("the filesystem where the tests are runned do not support XATTR") + raise SkipTest("the filesystem where the tests are runned do not support XATTR") os.unlink(tempf) def test_set_xattr_tdb(self): diff --git a/selftest/filter-subunit b/selftest/filter-subunit index 2ce9584c2a5..4f95546794a 100755 --- a/selftest/filter-subunit +++ b/selftest/filter-subunit @@ -19,14 +19,15 @@ # to upstream subunit's filtering tools. import optparse -import os import sys import signal -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/subunit/python")) -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/testtools")) -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/mimeparse")) -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/extras")) +sys.path.insert(0, "bin/python") +import samba +samba.ensure_external_module("mimeparse", "mimeparse") +samba.ensure_external_module("extras", "extras") +samba.ensure_external_module("testtools", "testtools") +samba.ensure_external_module("subunit", "subunit/python") import subunithelper diff --git a/selftest/format-subunit b/selftest/format-subunit index 5da56beb090..dc44842c15a 100755 --- a/selftest/format-subunit +++ b/selftest/format-subunit @@ -9,10 +9,12 @@ import os import signal import sys -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/subunit/python")) -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/testtools")) -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/mimeparse")) -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/extras")) +sys.path.insert(0, "bin/python") +import samba +samba.ensure_external_module("mimeparse", "mimeparse") +samba.ensure_external_module("extras", "extras") +samba.ensure_external_module("testtools", "testtools") +samba.ensure_external_module("subunit", "subunit/python") import subunithelper diff --git a/selftest/knownfail b/selftest/knownfail index c919a6a92d8..f8a52cf91e3 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -86,6 +86,9 @@ ^samba4.rpc.lsalookup with seal,padcheck ^samba4.rpc.lsalookup with validate ^samba4.rpc.lsalookup with bigendian +^samba4.rpc.lsa on ncacn_np with seal # This gives NT_STATUS_LOCAL_USER_SESSION_KEY +^samba4.rpc.lsa with seal # This gives NT_STATUS_LOCAL_USER_SESSION_KEY +^samba4.rpc.lsa.secrets.*seal # This gives NT_STATUS_LOCAL_USER_SESSION_KEY ^samba4.rpc.netlogon.*.LogonUasLogon ^samba4.rpc.netlogon.*.LogonUasLogoff ^samba4.rpc.netlogon.*.DatabaseSync @@ -98,6 +101,10 @@ ^samba4.rpc.netlogon.*.GetTrustPasswords ^samba4.rpc.netlogon.*.DatabaseRedo ^samba4.rpc.netlogon.*.ServerGetTrustInfo +^samba4.rpc.drsuapi.*ncacn_ip_tcp.*validate # should only work with seal +^samba4.rpc.drsuapi.*ncacn_ip_tcp.*bigendian # should only work with seal +^samba4.rpc.samr.passwords.validate.*ncacn_ip_tcp.*with.validate # should only work with seal +^samba4.rpc.samr.passwords.validate.*ncacn_ip_tcp.*with.bigendian # should only work with seal ^samba4.base.charset.*.Testing partial surrogate ^samba4.*.base.maximum_allowed # broken until we implement NTCREATEX_OPTIONS_BACKUP_INTENT .*net.api.delshare.* # DelShare isn't implemented yet @@ -215,6 +222,7 @@ ^samba3.smb2.replay.replay4 ^samba3.smb2.lock.*replay ^samba3.raw.session.*reauth2 # maybe fix this? +^samba3.rpc.lsa.secrets.seal # This gives NT_STATUS_LOCAL_USER_SESSION_KEY ^samba3.rpc.samr.passwords.badpwdcount.samr.badPwdCount\(s3dc\) # We fail this test currently ^samba3.rpc.samr.passwords.lockout.*\(s3dc\)$ # We fail this test currently ^samba3.rpc.spoolss.printer.addprinter.driver_info_winreg # knownfail or flapping? @@ -302,3 +310,25 @@ ^samba.blackbox.wbinfo\(s3member:local\).wbinfo -G check for sane mapping\(s3member:local\) ^samba.ntlm_auth.\(dc:local\).ntlm_auth against winbindd with failed require-membership-of ^samba.ntlm_auth.\(dc:local\).ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server against winbind with failed require-membership-of +^samba.ntlm_auth.\(dc:local\).wbinfo store cached credentials +^samba.ntlm_auth.\(dc:local\).ntlm_auth ccached credentials with NTLMSSP client and gss-spnego server +# +## We assert all "ldap server require strong auth" combinations +# +^samba4.ldb.simple.ldap with SIMPLE-BIND.*ad_dc_ntvfs # ldap server require strong auth = allow_sasl_over_tls +^samba4.ldb.simple.ldap with SIMPLE-BIND.*fl2003dc # ldap server require strong auth = yes +^samba4.ldb.simple.ldaps with SASL-BIND.*fl2003dc # ldap server require strong auth = yes +# These are supposed to fail as we want to verify the "tls verify peer" +# restrictions. Note that fl2008r2dc uses a self-signed certificate +# with does not have a crl file. +# +^samba4.ldb.simple.ldaps.*SERVER_NAME.*tlsverifypeer=ca_and_name_if_available\( +^samba4.ldb.simple.ldaps.*SERVER_NAME.*tlsverifypeer=ca_and_name\( +^samba4.ldb.simple.ldaps.*SERVER_NAME.*tlsverifypeer=as_strict_as_possible\( +^samba4.ldb.simple.ldaps.*SERVER_IP.*tlsverifypeer=ca_and_name\( +^samba4.ldb.simple.ldaps.*SERVER_IP.*tlsverifypeer=as_strict_as_possible\( +^samba4.ldb.simple.ldaps.*SERVER.REALM.*tlsverifypeer=as_strict_as_possible.*fl2008r2dc +# +# we don't allow auth_level_connect anymore... +# +^samba3.blackbox.rpcclient.*ncacn_np.*with.*connect.*rpcclient # we don't allow auth_level_connect anymore diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-cert.pem b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-cert.pem new file mode 100644 index 00000000000..2a1f36f063f --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-cert.pem @@ -0,0 +1,190 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com + Validity + Not Before: Mar 18 11:44:51 2016 GMT + Not After : Mar 13 11:44:51 2036 GMT + Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Domain Controllers, CN=localdc.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:e6:5f:4f:b7:ba:64:00:94:b2:0b:a0:29:3b:66: + 1f:28:85:cd:fa:bb:d7:de:18:8e:e2:4b:14:ab:33: + 17:4c:5f:8b:84:0e:b2:19:cd:32:ae:2a:8e:fc:8c: + 4b:51:c0:d9:2e:de:7f:d2:d3:7a:83:9d:95:66:6d: + e0:08:1a:25:10:2f:d3:27:bf:c7:ae:3a:f9:33:e4: + 65:87:af:a2:80:87:cc:f7:69:a3:4d:8d:65:30:81: + b3:20:ca:3f:54:28:b7:d9:1f:fe:90:92:8f:34:0b: + 0c:44:eb:48:b1:54:3e:66:29:c3:aa:e8:f4:f7:2d: + 6a:0c:cc:c2:31:f5:35:76:48:ba:82:c8:d0:06:42: + 2f:cd:4e:3f:20:b5:fc:f6:72:fc:0e:fe:92:a3:97: + 16:c7:9b:40:e4:ca:5c:47:39:bd:b1:4c:09:e3:a7: + 42:c2:0d:a8:b5:3e:f9:dc:7d:39:05:4d:c8:5f:c8: + 69:dc:85:5c:3c:9a:23:07:bc:30:33:38:a6:c4:03: + 07:59:e3:97:55:84:61:65:52:80:60:fa:77:b6:76: + 5a:31:32:51:a6:22:98:b5:ab:dc:67:51:23:76:08: + 09:8e:38:1c:75:0b:9c:59:43:1f:41:04:dd:60:69: + d9:fa:31:b8:16:5e:b8:f8:27:82:16:8e:c6:ce:d9: + 56:01:68:e4:5f:f8:2d:0f:31:85:27:37:92:fa:4d: + 0b:b3:f3:6a:f4:be:30:15:0d:8e:00:b5:87:f8:67: + 5c:ae:6a:25:59:23:8c:bf:a5:02:eb:b7:cc:0c:fc: + bc:3b:bd:80:08:fc:a3:86:5f:2d:ec:79:05:8e:e4: + d2:d2:c4:a6:ab:84:e3:da:aa:58:c3:db:8b:28:4b: + 15:49:79:7e:58:19:8b:7d:3e:87:9e:79:28:15:e1: + 8a:ad:75:10:0b:71:1e:8f:e8:1f:cd:d4:9b:11:e1: + 47:26:1a:f8:d4:a3:0b:7d:08:de:a6:f1:7a:93:26: + fb:bd:78:a3:60:8a:8b:29:fe:f8:9f:7b:5e:d7:64: + 03:e1:58:23:ac:23:35:3f:4f:b9:f7:3d:d6:d7:64: + 1f:0b:6b:11:9b:10:1f:2b:49:b2:f9:63:e8:cf:bf: + ac:da:9e:b7:f7:12:91:e4:01:77:9a:7f:31:c8:b6: + af:7d:5e:4e:55:ee:3d:2a:f9:0d:56:11:49:e3:f6: + 09:8c:2f:d0:06:eb:f4:f7:65:9f:db:85:0a:57:7e: + 9a:b8:1a:60:11:18:d1:3d:1c:c0:53:65:9b:e8:00: + 93:e4:91:61:b6:e8:7b:63:d3:d8:ec:70:8d:92:54: + 12:8b:56:1f:cf:83:34:d5:44:86:cd:b6:0b:fc:95: + 8f:f9:11 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + + Netscape Cert Type: + SSL Server + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + Netscape Comment: + Domain Controller Certificate localdc.samba.example.com + X509v3 Subject Key Identifier: + CD:25:BC:9E:49:98:02:88:4F:A7:5C:4F:2D:68:B9:E3:61:9F:AE:2E + X509v3 Authority Key Identifier: + keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42 + + X509v3 Subject Alternative Name: + DNS:localdc.samba.example.com, othername:<unsupported> + X509v3 Issuer Alternative Name: + email:ca-samba.example.com@samba.example.com + Netscape CA Revocation Url: + http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication, msKDC + Signature Algorithm: sha256WithRSAEncryption + 15:c0:31:31:7f:65:7c:7c:a4:db:1c:23:1b:81:bf:e8:c8:ad: + c0:2e:ce:c6:8e:3a:a2:d7:8f:ad:19:9a:e9:ea:72:bd:25:bc: + 26:3c:57:a7:53:4e:c5:24:a2:3c:70:59:48:9d:f5:df:2c:bd: + b5:b4:71:fe:a6:58:15:eb:31:86:83:c9:7a:39:47:80:f1:9d: + 31:ed:e1:5a:26:3f:9c:be:06:45:93:96:d9:3b:7d:d1:9c:b2: + ea:7b:a3:71:f0:9d:c7:a1:29:ba:38:eb:e4:be:bc:e9:9d:e8: + e1:be:eb:57:5a:1e:d1:09:58:dc:77:04:85:48:ba:94:19:73: + 8f:3a:31:6d:3c:ec:37:a6:d7:94:25:e3:98:e9:3c:f6:85:c6: + 6a:8e:d5:cd:32:05:1f:76:b7:b0:5a:c5:45:c0:81:20:16:4f: + e0:bb:e7:42:06:5c:6c:ff:e6:8a:73:7b:8c:1c:98:fe:2d:47: + 8a:e0:06:38:53:77:5b:6b:13:82:f4:a6:0b:c3:b2:88:2a:05: + 96:c8:04:66:cb:59:19:08:d4:9b:0f:1f:e3:3a:48:65:32:07: + 69:39:34:d4:a3:2e:d5:19:09:c7:07:d9:71:4d:62:81:fc:5a: + be:f1:da:65:3a:24:1e:2c:40:c8:78:4a:bb:0a:4f:a4:3d:ab: + 3c:b9:22:fb:0b:5c:9f:09:95:76:6f:6b:53:3d:1f:ee:fd:3f: + cd:be:7a:61:3e:08:3b:99:69:68:91:a9:9f:b8:4f:b8:c9:1f: + d4:ed:86:61:aa:6f:4f:a8:6a:4d:b6:79:e9:af:37:d2:83:9b: + f7:61:6a:65:f6:8c:f7:f9:3b:23:b6:cc:78:bf:16:ee:a0:50: + 1f:7e:38:7b:72:1b:62:ef:17:60:db:6f:c9:29:c1:c2:53:f7: + e8:27:de:3e:22:da:f0:5f:ba:55:9f:57:6f:b9:8f:c4:7a:c5: + 72:9a:a3:95:cc:ac:fd:f3:a6:a9:da:d6:57:d3:28:7f:72:60: + a8:5b:2f:c3:b1:07:c4:c7:af:d9:3c:a9:e9:78:e1:5a:0f:da: + c9:d0:e6:5d:9a:bd:61:ef:1d:25:7f:54:08:aa:f2:6c:11:1e: + a4:46:8e:9e:e2:79:c8:c2:dd:09:1b:62:27:e6:70:7a:e4:f3: + 66:db:57:30:ce:3f:27:f5:c6:c8:f2:3f:a1:bc:dd:ec:fe:3a: + c4:b9:ad:21:73:d8:83:a5:9f:02:ba:d0:52:8a:f2:d5:25:63: + 15:82:38:25:e2:74:ce:a6:a5:32:9a:6c:52:33:ba:45:ba:01: + 16:14:5f:ce:66:89:9e:03:ed:8a:95:80:c4:cf:20:24:d4:c5: + 5b:e5:c3:51:62:57:1e:45:be:0a:47:24:b7:cb:a4:dd:6e:54: + 2c:f4:25:80:a3:85:a9:74:0c:c0:65:c9:f8:2f:9a:22:bc:85: + c9:63:8a:08:f3:c9:1c:77:9b:a8:42:5a:45:dd:be:21:be:9d: + e7:15:9b:67:19:6c:d3:da:9b:67:a8:1d:22:35:d4:16:89:ad: + 4c:c3:17:bb:9e:f5:e5:3b:a2:a6:81:34:e0:4c:36:be:bb:e5: + a3:60:7d:28:30:82:db:99:ef:c6:19:43:d1:73:24:f0:8e:d1: + 6c:3b:cc:f8:cb:1a:14:79:67:07:ea:b5:47:08:bf:11:33:29: + 01:2e:fd:44:14:33:f6:36:65:8b:a8:f8:e6:0b:84:6d:a1:91: + 08:56:c1:5d:ca:12:b6:00:ba:9c:7e:7e:9b:26:3f:d3:dd:e1: + 2f:ae:f5:76:45:ed:a2:9b:b4:a1:a9:d6:b6:f5:7e:68:80:17: + 81:fb:ef:24:dc:84:de:38:20:45:34:6c:72:e5:d6:08:61:e7: + dd:45:43:d2:06:2b:ae:d9:73:a1:fb:bb:04:3c:61:45:d3:9e: + fc:45:c0:e3:db:02:ae:45:e3:de:d1:34:00:b0:1b:0f:ce:f8: + 33:0f:87:9c:9b:5d:49:11:7a:30:15:e3:9f:76:02:82:18:c2: + a6:dd:25:a6:e0:84:1f:1d:0d:db:81:7c:df:a1:65:9b:5b:08: + e0:4e:6d:4c:76:8a:0b:09:14:7c:e1:23:ad:18:4c:02:6b:e3: + f4:e0:22:26:e1:30:7e:a5:59:22:5b:a5:73:5a:23:24:1f:1a: + 7b:e5:46:f7:0c:14:00:53:72:33:4d:c4:c4:59:3e:04:17:33: + 34:04:67:1e:cd:a0:e5:9f:85:87:77:f6:dd:03:f0:74:cf:56: + e9:99:a8:95:3a:52:db:d1:61:72:91:60:9f:80:bf:22:26:da: + d7:09:4e:df:81:30:dc:9b:b4:c1:c7:cb:97:93:bc:b7:93:a3: + db:88:cc:5e:9f:39:94:57:a5:57:d6:cd:1b:12:a4:86:62:4f: + b2:08:22:4e:d9:07:8e:27:06:82:d9:f1:ec:70:30:82:56:0c: + f7:d9:56:bf:f1:7f:fd:65:90:8d:5e:d5:13:b3:31:89:5d:e8: + df:35:2f:77:6b:b7:c7:e8:7d:89:f8:cf:9e:a5:1c:60:be:7c: + 6c:b7:0f:fa:8e:62:8e:b0:72:10:8a:04:6a:50:83:3a:38:dc: + 13:8b:89:8f:6c:0f:fc:3e:c7:36:15:37:78:5f:24:87:8a:70: + cc:3e:5a:fc:88:78:19:70:89:65:a0:c7:47:67:f2:bc:1e:f5: + 04:e7:94:ba:74:ea:2a:a7:c1:26:b1:2e:ac:64:0b:fa +-----BEGIN CERTIFICATE----- +MIIJ6zCCBdOgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx +EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE +CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x +IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB +FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz +MTgxMTQ0NTFaFw0zNjAzMTMxMTQ0NTFaMIG1MQswCQYDVQQGEwJVUzETMBEGA1UE +CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEbMBkGA1UE +CwwSRG9tYWluIENvbnRyb2xsZXJzMSIwIAYDVQQDDBlsb2NhbGRjLnNhbWJhLmV4 +YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkBFiZjYS1zYW1iYS5leGFtcGxlLmNvbUBz +YW1iYS5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AOZfT7e6ZACUsgugKTtmHyiFzfq7194YjuJLFKszF0xfi4QOshnNMq4qjvyMS1HA +2S7ef9LTeoOdlWZt4AgaJRAv0ye/x646+TPkZYevooCHzPdpo02NZTCBsyDKP1Qo +t9kf/pCSjzQLDETrSLFUPmYpw6ro9PctagzMwjH1NXZIuoLI0AZCL81OPyC1/PZy +/A7+kqOXFsebQOTKXEc5vbFMCeOnQsINqLU++dx9OQVNyF/IadyFXDyaIwe8MDM4 +psQDB1njl1WEYWVSgGD6d7Z2WjEyUaYimLWr3GdRI3YICY44HHULnFlDH0EE3WBp +2foxuBZeuPgnghaOxs7ZVgFo5F/4LQ8xhSc3kvpNC7PzavS+MBUNjgC1h/hnXK5q +JVkjjL+lAuu3zAz8vDu9gAj8o4ZfLex5BY7k0tLEpquE49qqWMPbiyhLFUl5flgZ +i30+h555KBXhiq11EAtxHo/oH83UmxHhRyYa+NSjC30I3qbxepMm+714o2CKiyn+ ++J97XtdkA+FYI6wjNT9Pufc91tdkHwtrEZsQHytJsvlj6M+/rNqet/cSkeQBd5p/ +Mci2r31eTlXuPSr5DVYRSeP2CYwv0Abr9Pdln9uFCld+mrgaYBEY0T0cwFNlm+gA +k+SRYbboe2PT2OxwjZJUEotWH8+DNNVEhs22C/yVj/kRAgMBAAGjggHxMIIB7TAJ +BgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly93d3cuc2FtYmEuZXhh +bXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMBEGCWCG +SAGG+EIBAQQEAwIGQDALBgNVHQ8EBAMCBeAwRgYJYIZIAYb4QgENBDkWN0RvbWFp +biBDb250cm9sbGVyIENlcnRpZmljYXRlIGxvY2FsZGMuc2FtYmEuZXhhbXBsZS5j +b20wHQYDVR0OBBYEFM0lvJ5JmAKIT6dcTy1oueNhn64uMB8GA1UdIwQYMBaAFEaH +hsLnGc8WTAxiy3N//Y8Z5LVCMD0GA1UdEQQ2MDSCGWxvY2FsZGMuc2FtYmEuZXhh +bXBsZS5jb22gFwYJKwYBBAGCNxkBoAoECAEjRWeJq83vMDEGA1UdEgQqMCiBJmNh +LXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0GCWCGSAGG+EIB +BARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMvQ0Etc2FtYmEu +ZXhhbXBsZS5jb20tY3JsLmNybDAmBgNVHSUEHzAdBggrBgEFBQcDAgYIKwYBBQUH +AwEGBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggQBABXAMTF/ZXx8pNscIxuBv+jI +rcAuzsaOOqLXj60Zmunqcr0lvCY8V6dTTsUkojxwWUid9d8svbW0cf6mWBXrMYaD +yXo5R4DxnTHt4VomP5y+BkWTltk7fdGcsup7o3HwncehKbo46+S+vOmd6OG+61da +HtEJWNx3BIVIupQZc486MW087Dem15Ql45jpPPaFxmqO1c0yBR92t7BaxUXAgSAW +T+C750IGXGz/5opze4wcmP4tR4rgBjhTd1trE4L0pgvDsogqBZbIBGbLWRkI1JsP +H+M6SGUyB2k5NNSjLtUZCccH2XFNYoH8Wr7x2mU6JB4sQMh4SrsKT6Q9qzy5IvsL +XJ8JlXZva1M9H+79P82+emE+CDuZaWiRqZ+4T7jJH9TthmGqb0+oak22eemvN9KD +m/dhamX2jPf5OyO2zHi/Fu6gUB9+OHtyG2LvF2Dbb8kpwcJT9+gn3j4i2vBfulWf +V2+5j8R6xXKao5XMrP3zpqna1lfTKH9yYKhbL8OxB8THr9k8qel44VoP2snQ5l2a +vWHvHSV/VAiq8mwRHqRGjp7iecjC3QkbYifmcHrk82bbVzDOPyf1xsjyP6G83ez+ +OsS5rSFz2IOlnwK60FKK8tUlYxWCOCXidM6mpTKabFIzukW6ARYUX85miZ4D7YqV +gMTPICTUxVvlw1FiVx5FvgpHJLfLpN1uVCz0JYCjhal0DMBlyfgvmiK8hcljigjz +yRx3m6hCWkXdviG+necVm2cZbNPam2eoHSI11BaJrUzDF7ue9eU7oqaBNOBMNr67 +5aNgfSgwgtuZ78YZQ9FzJPCO0Ww7zPjLGhR5ZwfqtUcIvxEzKQEu/UQUM/Y2ZYuo ++OYLhG2hkQhWwV3KErYAupx+fpsmP9Pd4S+u9XZF7aKbtKGp1rb1fmiAF4H77yTc +hN44IEU0bHLl1ghh591FQ9IGK67Zc6H7uwQ8YUXTnvxFwOPbAq5F497RNACwGw/O ++DMPh5ybXUkRejAV4592AoIYwqbdJabghB8dDduBfN+hZZtbCOBObUx2igsJFHzh +I60YTAJr4/TgIibhMH6lWSJbpXNaIyQfGnvlRvcMFABTcjNNxMRZPgQXMzQEZx7N +oOWfhYd39t0D8HTPVumZqJU6UtvRYXKRYJ+AvyIm2tcJTt+BMNybtMHHy5eTvLeT +o9uIzF6fOZRXpVfWzRsSpIZiT7IIIk7ZB44nBoLZ8exwMIJWDPfZVr/xf/1lkI1e +1ROzMYld6N81L3drt8fofYn4z56lHGC+fGy3D/qOYo6wchCKBGpQgzo43BOLiY9s +D/w+xzYVN3hfJIeKcMw+WvyIeBlwiWWgx0dn8rwe9QTnlLp06iqnwSaxLqxkC/o= +-----END CERTIFICATE----- diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-key.pem new file mode 100644 index 00000000000..0dec9845d18 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-key.pem @@ -0,0 +1,54 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIJljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI/ffRVypD9HkCAggA +MBQGCCqGSIb3DQMHBAjv05OkfOwFaQSCCVCbev4X3oUISTe03sWAz0bzijH5Wg7w +Vc9+SnYwt0pFZTaUw6MkvhFNUD+BEw0fePpCeBzf2DTVqCQ4RVY7ps3/DmTZQlWa +KDLbermsiT5n1dc22iYeA1zsHc/h020djrm+Eem5rcNGsxlfln3fRMVwSPEEBBnK +7k/8tM1SeXe/QmFtm3CRJ02dNzvr11xcYLDN9i2bVskqIFME/+Vi57/rdEAhyaBB +osJBhv+vvfoyTbZ8buRIxN2rUxkPp27jPqckyZoC9IWE6MXoyyaKYIvkscIIU6Xf +hj4K/FdozbD6TkCC84KfHqXgMy+CFN04yTt9fORl0L/3NHHJoMjXQsg26wSfbCFY +t9FK5QQlm0MqimsOaxCTEd1LivRw16KYLOva20t2/1aMpc8nBP4ROheugGhEOsCB +RwbvANTmg4E/uBWORDsDRu4OQN3XE/nzW3R7uokv4aGON8Ob6M7DExDIQCdsbGvB +8DdziETmvXAj6yGH0LfqaZhNXpj5uyuNVVt7ROoKYFIOdkUXPC1DFOcLRiClaM87 +8XU8Zy2l/tFh56jgWMzMcqoIlLxIpMMCZl5P533+5nQ2tQtdRynTpKuipdDIFu/r +JjMsTYgh8knG8C5qSXqNT0hu0yRleGNRVslTBnc7JqjMdqcZBS1Ut4asU7aVn6Fv +egGmgPXTsC8tnYy6lT+lam+jjdk65SHP+/HUNuyhVzmDKPXaUG/bdh4NmCHaxE4y +WjLTKMkEs/NBkGDxbqgw3HtatSBiK+JG1zUeaDomxbROjv8VYGGF1RXrp38KOqao +Tg6gEUzcktbEdcvm+q1Pkau2vPxRcnnOQSSmnqr+w0+kh9OawaZ5B+VMr5eV9mdZ +oj2yT0nw7+BFJq3zeaIt1ksSkqUaXLVspeJkBC/DbC/MyoOLdMgzHfkxc1/hq0WV +UoQtHI4lTk+3aWu4ZD47BrigLbeDOvvW/oMF6CdVZBghhsyhvmpWASQ1kiVN7k18 +A19iX5W33x9bjD+0392mSPo525BR24z5x8bTklLng0Kro84sXfRPHMXqIoCEDXz0 +z8QGJtdVdUi9wVLqcCyW+8U51ACTWnrxv0oTlRy7ESbj229Cj29o3qGdCXaU7XVz +g5WGtziVR1Lquql+hzCckwPLjm6olLyxZwk6d83KwMUckhvLeYXJ65/ZRRaE2R91 +2X0ir7Csk802NPjaV21No3/EJVuw57dZ9xxUUW8Q+OfCQAxKxdKfWcK3JjdNvZn4 +778E/kWg+KdhcQ1yb6MHZafrjnkwAp4qm3Kp936zL5a/nsTT2e0661pC/8FBxfNQ +H+CFLylW77vpVo/iFSeHzGmOEuUC7hsbqjX8y4x8czuY1sCNA0Ty3tf5gOVhemuP +xgfJRQF/bUAnlWnCb83peSYq5SUQq1LTtkKGghXCgV1d3MzryAoOr6znZTcE0CSG +GDUk7vzaZmzKp8TySAFUcuo6Ve297yi9A+dGNsuOyqmFwS7pjrwYI9HPj2BKu7Gw +Ns/aPs9lJhGR7tjpqyX2Ok4OQBBcwdP3OfjdCQdwdjAjVXlj5BeNiSQ7HiRECYza +kGzvwuO+10DXTSwcLhakNZZtONFpuMU5JoSCcICUaJ+4AAqJdfO13TiOYHRLN9VC +2h2/4wGPcvLdYg9ByiE5wt5bysGl0jOtmTA5boK6TD1qF5fD8+WNd7VPDmFS/uUo +65JXn63Q8A8MC7sQNLOsyoFkXOVr5uLNdZMzbcOqre9h3y1GCucXRAhQ4eOefJPA +2u/vFk0opk8dMq0FA9LH4zbvhpTBytHdcnkwlsCmv8XO7j544gSbrUNKMqSkY2DT +R37qxq6iCzaSkNnpxLH8kY5KydCnxqxLhbECbNqdIIajxPgctCbzKJrOe/I9CUzu +qsXY8+ZVRD2wBOnP8p9oWq0pbilmgNquQD5/maO0Rm09A6Eg4vvki/PJxBC9KRfv +VXmgk4LsmAPxh/anJFJlK36LRUNosmBFSOZ+NnCMAhEGjH+5VER4hWmWxr4znLfD +QsIh+uui2fZWr8dBmpArzGyq7C3sB4sIXqacaExu+ed8f/tvU414Y1b75XaIMGX/ +CcSDf/NgGw1+Ucf0hp7nHU6/u7dhuwvrw8LLhXhuGU9al7vVP8n8aEwzNPo1OAnd +0DcPWGFaFGQlSWL6oOXDsE2KVkI82+2XJZopLL2Envh5ntct0a49DHIi4TP+aVbT +Q37EU2SvNYvJk0h8dUibrM/hd5UZ8PKWgIamOjhhi+0mTON2sW9Jitr3NSFRw6sn +NOC9p5kH2R5TGH8r34RbfEU6Zy3bSukuW/63FknS8VLWu0AWfzqNRTIZj8xfoaGd +MsNTsgTdXHt/9pgbtMRU/EDs9ZfNmbLM1uw5Kfp7garX4TuZefgPAWHzoZM4zD71 +xe6aVOTiPatdDceFuynFdijK3RljO25CgOURQe0OYNNOJIrXGtkmC2szD3LTqW/x +wn51DiIijGQLrFIzrflw/V7is5VpujyU5dn8/Wk6OTbhoVctmlhOyKVvM/fo2m/g +q4pSD4TvLWgJW+aU3XZTw55P0hV9zYzienmWc6Ny1zen+829pm6gbYW9N/qsU5CB +W5h4+rBgp9htUVeeu2mKiaZW9V5Y2IN7frKwZxUQPe3FMS3TEfEjBAqcdJHGPZEZ +tqFB4CiW7F0w0Tt30ATdoPIbnK/RQa025JhAWjSCLZg88Busik2uEvoZLe8Z+6bc +hTQnKcHY63LbkqqpYBKvsE/MjYUts7K7QKYQPmFvxoQpgpmqdfQ53ibvDnGeWnxj +j+5qXgx73cUaKPU14ObiLrhieVCnhEqSRot2aUx2hllbJn7CXj4OUkznFL6k2GGg +HzOe7PsZUhXWdUaBvSjbr6Whg8erCumJq2b346deoiGl3o/RsgFu4V3tZHN+v1Lj +gorQXOmnqXOhUbquM+2p5TRiKRfn6ARLf7Ja4UZhmk0w8e1vw+u0WKScMaNQ+BVT +91lBpJcHqWZiMAVDvgyZk3oM954xEgyr6guG/8eoTUXECUUn0HPbMOqmoLsMH6Ok +bFR2t1mtan8Qp9zYW8wIMAAdnkOMoYrUgB9KImr8Mr/DCa6ouqybNcO6xuVnVwq3 +vCmSqd5+XPORqnDF1wPZUbKh825VMXENa6RIX4rkiZwG+j4ALtzOqt5u6k3MZNIe +fmluaS0MnFk2mw== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-openssl.cnf new file mode 100644 index 00000000000..bf4131fecf8 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-openssl.cnf @@ -0,0 +1,250 @@ +# +# Based on the OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +#CRLDISTPT = [CRL Distribution Point; e.g., http://crl-list.base/w4edom-l4.base.crl] +CRLDISTPT = http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + +# Extra OBJECT IDENTIFIER info: +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] +# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used as a login credential +scardLogin=1.3.6.1.4.1.311.20.2.2 +# Used in a smart card login certificate's subject alternative name +msUPN=1.3.6.1.4.1.311.20.2.3 +# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used to identify a domain controller +msKDC=1.3.6.1.5.2.3.5 +# Identifies the AD GUID +msADGUID=1.3.6.1.4.1.311.25.1 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = CA-samba.example.com # Where everything is kept +certs = $dir/_none_certs # Where the issued certs are kept +crl_dir = $dir/_none_crl # Where the issued crl are kept +database = $dir/Private/CA-samba.example.com-index.txt # database index file. +unique_subject = yes # Set to 'no' to allow creation of + # several certificates with same subject. +new_certs_dir = $dir/NewCerts # default place for new certs. + +certificate = $dir/Public/CA-samba.example.com-cert.pem # The CA certificate +serial = $dir/Private/CA-samba.example.com-serial.txt # The current serial number +crlnumber = $dir/Private/CA-samba.example.com-crlnumber.txt # the current crl number + # must be commented out to leave a V1 CRL + +#crl = $dir/Public/CA-samba.example.com-crl.pem # The current CRL +crl = $dir/Public/CA-samba.example.com-crl.crl # The current CRL +private_key = $dir/Private/CA-samba.example.com-private-key.pem # The private key +RANDFILE = $dir/Private/CA-samba.example.com.rand # private random number file + +#x509_extensions = # The extensions to add to the cert +x509_extensions = template_x509_extensions + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +crl_extensions = crl_ext + +default_days = 7300 # how long to certify for +default_crl_days= 7300 # how long before next CRL +default_md = sha256 # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = match +stateOrProvinceName = match +localityName = match +organizationName = match +organizationalUnitName = match +commonName = supplied +emailAddress = supplied + +#################################################################### +[ req ] +default_bits = 4096 +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extensions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = US +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = SambaState + +localityName = Locality Name (eg, city) +localityName_default = SambaCity + +organizationName = Organization Name (eg, company) +organizationName_default = SambaSelfTesting + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = Domain Controllers + +commonName = Common Name (eg, YOUR name) +commonName_default = localdc.samba.example.com +commonName_max = 64 + +emailAddress = Email Address +emailAddress_default = ca-samba.example.com@samba.example.com +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +#challengePassword = A challenge password +#challengePassword_min = 4 +#challengePassword_max = 20 +# +#unstructuredName = An optional company name + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] +# Extensions for a typical CA +# PKIX recommendation. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. +keyUsage = cRLSign, keyCertSign + +crlDistributionPoints=URI:$CRLDISTPT + +# Some might want this also +nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +subjectAltName=email:copy +# Copy issuer details +issuerAltName=issuer:copy + +[ crl_ext ] +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +#[ usr_cert_mskdc ] +[ template_x509_extensions ] + +# These extensions are added when 'ca' signs a request for a domain controller certificate. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE +crlDistributionPoints=URI:$CRLDISTPT + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +nsCertType = server + +# This is typical in keyUsage for a client certificate. +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "Domain Controller Certificate localdc.samba.example.com" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. + +subjectAltName=@dc_subjalt + +# Copy subject details +issuerAltName=issuer:copy + +nsCaRevocationUrl = $CRLDISTPT +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +#Extended Key requirements for our domain controller certs +# serverAuth - says cert can be used to identify an ssl/tls server +# msKDC - says cert can be used to identify a Kerberos Domain Controller. +extendedKeyUsage = clientAuth,serverAuth,msKDC + +[dc_subjalt] +DNS=localdc.samba.example.com +otherName=msADGUID;FORMAT:HEX,OCTETSTRING:0123456789ABCDEF diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-private-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-private-key.pem new file mode 100644 index 00000000000..f8c3c4070b1 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-private-key.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKgIBAAKCAgEA5l9Pt7pkAJSyC6ApO2YfKIXN+rvX3hiO4ksUqzMXTF+LhA6y +Gc0yriqO/IxLUcDZLt5/0tN6g52VZm3gCBolEC/TJ7/Hrjr5M+Rlh6+igIfM92mj +TY1lMIGzIMo/VCi32R/+kJKPNAsMROtIsVQ+ZinDquj09y1qDMzCMfU1dki6gsjQ +BkIvzU4/ILX89nL8Dv6So5cWx5tA5MpcRzm9sUwJ46dCwg2otT753H05BU3IX8hp +3IVcPJojB7wwMzimxAMHWeOXVYRhZVKAYPp3tnZaMTJRpiKYtavcZ1EjdggJjjgc +dQucWUMfQQTdYGnZ+jG4Fl64+CeCFo7GztlWAWjkX/gtDzGFJzeS+k0Ls/Nq9L4w +FQ2OALWH+GdcrmolWSOMv6UC67fMDPy8O72ACPyjhl8t7HkFjuTS0sSmq4Tj2qpY +w9uLKEsVSXl+WBmLfT6HnnkoFeGKrXUQC3Eej+gfzdSbEeFHJhr41KMLfQjepvF6 +kyb7vXijYIqLKf74n3te12QD4VgjrCM1P0+59z3W12QfC2sRmxAfK0my+WPoz7+s +2p639xKR5AF3mn8xyLavfV5OVe49KvkNVhFJ4/YJjC/QBuv092Wf24UKV36auBpg +ERjRPRzAU2Wb6ACT5JFhtuh7Y9PY7HCNklQSi1Yfz4M01USGzbYL/JWP+RECAwEA +AQKCAgEA1iZfupFACPIxGHGIIrlp2YeY1K3tm34ExQO6cPMLg2mGDfqDQUzpAdJ6 +HPZlxdeZjOI0vMzuJI9GpHMbQSzcq1Fp3pd+jc4wfjag0yNH0mdq98txjNQV7qOC +2sZnXFqFnQcK42X6TQzAGQkHCCEh6GKGi8gGgAftf3yQQVSKoCw3hQAbsNWyDg3g +zQ2f25FEEsQ/mGcJPABssMIUSfm5BqmCv+dqPW3pGKM0Le0SJoYJ8FAjaGVoOsWm +LriXreXJ0IhoOv1AXrSyvTeWM5Bh3HHkobr+/4tFngvm1PwuFLif+V7bxUpHywqE +cTKOf+OmR9gUImdnVveTDFkpInwSX3UH88lKwg2t9rANuSgrfnhX9MgLxWT52qFw +hRwtLHamnKZw9IrYq002O00NPAoS2AFApFzAbPBxTy5cOKVzOzBr27w5Qxam+GoH +LVk/1qePWI0CwP68DN2jFM5TWd9zGUpXnSHcsX0j/qs6UKamUbmszbRenskOtn0b +d3Et/gKQt6168aBDSkCxFsdkeWMKI9xcnfSi97i/dRCvqIfEGRqoQLwknk2DMoE6 +2Z23hs+tRVRHu49CWABPnMBf5FqN2rocjr15wKAphgbbMIA3tw2wo03wmaMYNzxJ +M57ejJc+6MNfRyb0nLRaClsveU30qpfWhd36eKdKLZtrfj0Be2ECggEBAP90L6gM +83MA4hIOvLO5zhMMPdbm0+hOLlKpKUqBsNaCeJWutF9TcnqajoaYy9p+gKlASO5s +BgQiwMy3JlHc2KrbMXruksUER3d4Oprv/DKS+XfRciRZ0//+jCrNHrBvMB5VQHYs +wTB9Sdbdgfc1YiPdkF4JRBqmUrMS9b7iv8BLzAxbcdXz2xoXhkmbwgTJghdQAigq +GnoeXoc8qbA8IYKQefFevd6TzBL6UR+ZFHOjz2A2gX/1G31i6z5cjZc2XRjvI9aC +rBorjzYg2M7KBusbKhr8zYDqn/Rl0e/vK9NhZEz7Vg2FXUT25WZPlktQV1b3TVtY +yoWhJj2vy4ffqz0CggEBAObdZdE2I3UY/TTk/jK6LKg+uTB7/AjjaTga4T770IoV +pdAYEiGAFO1Y22gK14FAzq1CY7/SGtPtie3fBDCDcbv+K/qw7sVZvkXWKKSpvYCq +pB0xkmTWJGReAYh8QeI9KHuNhfEX2OO6fW2Tx9rt6ZzGxAZrQL7f1gKLjICEtYKp +dG6OjHHHVZprsFt/czFkfY+cVFvuTOSD8MmCjO5ErM48lCWAVXhJnfDR+rSMjiq7 +2SSqN120vp6Bdm6jatoxsUV4KUIp0kkO8UPA5vJsn+wwX+gXfDjZnqBSTbkia9Mw +xQ3mCSgYfhyxK8UCVoH466SXCqM7StqV3G04TqJVsmUCggEBALJOtikWCSQ//Izg +LoVA73/KLqv/aPChCaJ3IzQ3fGjunx7T2GEljSXZFh0LMFetrz70eTO6wSRH4c3D +FYNUpQP1hf8p4daVWxEgIcAePSpL/sfMsWCANwNb+RizHnXG1o6FsT4LlTm0akMJ +UHtujrc8I1YQH7J+YAFQ/amk+nVOMvp5JedSlKAMxZZBm1beFOkS1r6UTPDqm87H +4CX8guNw1z1MhTmEbpDcmp10q5rgP5MH2LKpMuv9jPh1f/uJXchWu+wyP9DwkMEW +gl8tE1EuH+DAju0qWEYugDB7AFtGgs1dLj631VebApq8eMrPJHe2nQ9i1dIanue1 ++lo4HH0CggEAQuU4UYzsbUvWYvNPrQdBVWcHZkMm3rR2kqlHR2bUII7xQwEWj9p7 +NeMfgGBT3cIXoSCxoq2Q1IPqCaErp5sO47hcqgGGzmyYs8fAcyY0IQpRD5yDnPBo +DyUmMJRAyvuJtXNmsluEn0g0fAHsUUXLAYCe4HVHh4d4jbg9+Cd8KOZNNJPdokJu +TZaSvZCKom9J6skTsKe2ZCjPJrTLfWcs432uN8ed/ILoXxWZHaP0tfFElFk2PdLX +wTomRRzZI2xuv4B4BBH2OvE3e7hzsx9Cn7/MqoXTmu2EB1SR7OlKcSGal9JmKNYg +BNRZqHZq9rJYJZMWpAHUSM5P1t4P+v31+QKCAQEAvkx6xN6DubYIgzHlaBW38iM3 +4pMUOA9DXIxQzDuYX1XCpxTv0d/9Y+nEWGJ9UeVAfRnyThYVoALAcI8xF/YLU9S9 +DiKgG89G6S8ZyVvYSWuJZWi1Y/Dup/SDcGXWuVO0fWS9UaDqzib4zFEtVtjjvkep +xRZYetMM/v0xTKFCLU9hvsy/Ngb485ChPLgr12ajldubfkHZrmfqbBfqGAsUsmXA +AP2BKkaopnNY/x8TYFcuYLiypYufXk8Hh/cUhWT0GiuAsPNmB4KwJjkXdktMbkpM +6enkjxXX4TPfbxe4ftV2GpCdfR7sWFgcJTn+C45Lsl7QT+P65Onr1QNGyKIp7g== +-----END RSA PRIVATE KEY----- diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-req.pem b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-req.pem new file mode 100644 index 00000000000..d0fe335f405 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-req.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIFDzCCAvcCAQAwgckxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTYW1iYVN0YXRl +MRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNhbWJhU2VsZlRlc3Rpbmcx +GzAZBgNVBAsMEkRvbWFpbiBDb250cm9sbGVyczEiMCAGA1UEAwwZbG9jYWxkYy5z +YW1iYS5leGFtcGxlLmNvbTE1MDMGCSqGSIb3DQEJARYmY2Etc2FtYmEuZXhhbXBs +ZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDmX0+3umQAlLILoCk7Zh8ohc36u9feGI7iSxSrMxdMX4uEDrIZzTKu +Ko78jEtRwNku3n/S03qDnZVmbeAIGiUQL9Mnv8euOvkz5GWHr6KAh8z3aaNNjWUw +gbMgyj9UKLfZH/6Qko80CwxE60ixVD5mKcOq6PT3LWoMzMIx9TV2SLqCyNAGQi/N +Tj8gtfz2cvwO/pKjlxbHm0DkylxHOb2xTAnjp0LCDai1PvncfTkFTchfyGnchVw8 +miMHvDAzOKbEAwdZ45dVhGFlUoBg+ne2dloxMlGmIpi1q9xnUSN2CAmOOBx1C5xZ +Qx9BBN1gadn6MbgWXrj4J4IWjsbO2VYBaORf+C0PMYUnN5L6TQuz82r0vjAVDY4A +tYf4Z1yuaiVZI4y/pQLrt8wM/Lw7vYAI/KOGXy3seQWO5NLSxKarhOPaqljD24so +SxVJeX5YGYt9PoeeeSgV4YqtdRALcR6P6B/N1JsR4UcmGvjUowt9CN6m8XqTJvu9 +eKNgiosp/vife17XZAPhWCOsIzU/T7n3PdbXZB8LaxGbEB8rSbL5Y+jPv6zanrf3 +EpHkAXeafzHItq99Xk5V7j0q+Q1WEUnj9gmML9AG6/T3ZZ/bhQpXfpq4GmARGNE9 +HMBTZZvoAJPkkWG26Htj09jscI2SVBKLVh/PgzTVRIbNtgv8lY/5EQIDAQABoAAw +DQYJKoZIhvcNAQELBQADggIBAEO4n5lMOyBsZBuVKOyYYC2uFUCnIXepxLwpTN16 ++8wNjXG25B0nm0dgmPpsq4zvYLAMY32vyxo81LKX2fh0f6xyovN7VOmXBUcwHVtl +6GZIIFDOm8uMQutqX0HV25S9Q5nxqoX1K4stBNmHxAFmyp0vZgz5CcoOn36bWIr1 +CRLKt0RF0unUlzXKdQIdlmugxnfitKg6gkr2MN2ae2wQmZB2Z7Q6edfda82xw2l7 +yE2qwwpstjlgPSrM/W53byiXO5w+5UI1U4mbF8J5eB5xlaLaaoPwuDteOlw0TN+9 +FOgFp0MZq2Mu4YdO8Bcl7k+rTXyviyzNG9MiABYsMwZQ9XSClF6OUIxQFqXBgY7Z +Xo2wp8ggCsWHgA5uofVXxbnkxquI4pEH9ZzI1jJT7nZIw7Dyb0RJcbMlLArPEbZ6 +pRQapv8vK4Sc3DVxLwu5bnxwzllTjGPQH9Z/uRjft7EK3cByO6x7jZJXpUOKK+0C +eF8nvmsoqnPfx92tfNZ4tYXga/1hq5warOl++nDSpIPVNlLEhyATuFakxYj9qiag +fn2qIrXEyoOmjKlTdUJehKIFviUVD+2o/9bBsS3x+fZLPxs8BbWHeq5BuZM5o9qV +F5A1BrytjQwDWWznU9E/SSiWh0JqQeQaGWLBr1XAejSb7Xk5ecqsO+6aaWvYL9JD +vI4t +-----END CERTIFICATE REQUEST----- diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-cert.pem new file mode 120000 index 00000000000..b7549bb7690 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-cert.pem @@ -0,0 +1 @@ +DC-localdc.samba.example.com-S00-cert.pem
\ No newline at end of file diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-private-key.pem new file mode 120000 index 00000000000..21601b4df86 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-private-key.pem @@ -0,0 +1 @@ +DC-localdc.samba.example.com-S00-private-key.pem
\ No newline at end of file diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-cert.pem b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-cert.pem new file mode 100644 index 00000000000..4cc42aafc9c --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-cert.pem @@ -0,0 +1,191 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com + Validity + Not Before: Mar 18 11:45:30 2016 GMT + Not After : Mar 13 11:45:30 2036 GMT + Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Domain Controllers, CN=plugindc.plugindom.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:aa:a3:74:2b:4b:6d:29:43:67:03:dc:c0:be:ce: + a6:e3:43:99:e5:87:34:34:42:70:4b:bb:50:87:6d: + e8:65:2b:5e:1a:b3:68:0d:9f:27:eb:dc:b8:84:bb: + 3d:f4:40:28:c0:c7:aa:e5:8d:a1:d5:7f:c7:6b:36: + 96:6b:3e:65:72:37:0e:d4:2c:03:4d:ee:e6:f8:41: + 5c:27:bf:32:53:6c:13:28:1f:be:78:9c:7c:80:53: + eb:4d:0a:19:1a:88:49:95:a9:c6:65:23:5b:3e:24: + 27:06:eb:7c:58:24:c6:e7:a4:d9:98:02:c4:ce:b3: + 1e:01:34:4c:bd:9c:28:da:10:4d:36:e9:7d:a8:68: + 04:75:18:eb:f0:58:94:05:b1:61:97:d5:9a:b3:db: + 09:71:74:90:05:87:d4:1c:ff:06:2b:c0:51:b6:26: + ca:28:8b:c2:08:3a:93:62:f8:69:b4:3b:c3:6d:9b: + 0f:80:1d:f8:c3:51:93:78:64:83:63:c7:d0:21:e8: + 05:cd:22:3e:3e:e2:c2:66:af:46:6c:c6:7d:d8:ed: + 53:b9:cc:42:e9:a2:43:94:31:f4:9e:45:fa:45:35: + ab:7f:32:93:95:a5:1b:4a:9d:27:c0:5f:bf:03:7f: + ca:37:c3:c2:c9:6f:b6:6e:5f:05:55:56:f5:2f:40: + c2:41:12:17:ee:23:1b:3a:9c:39:74:d5:cc:b1:47: + 6a:24:85:95:f5:aa:e6:35:40:0c:d3:8f:1e:d3:df: + b5:1b:7c:ff:3f:df:7e:7a:d3:f8:e1:92:b0:41:14: + f6:aa:1d:8c:36:3d:5c:c5:c5:b7:2f:b8:f8:09:47: + c2:51:58:de:80:41:c2:a5:18:c6:a9:16:39:d4:8e: + ef:f3:a9:c6:13:db:1e:f5:8a:e7:37:16:7c:df:28: + fe:19:44:7b:58:98:ee:72:fa:41:a2:f5:e0:77:c2: + 5e:fa:e1:94:87:96:17:66:75:07:45:c8:df:6a:40: + 19:3b:da:4d:48:e8:51:a3:1f:ba:41:62:0a:48:f5: + 62:42:9e:69:49:aa:ac:36:bd:6f:41:32:bb:62:8a: + 96:6b:01:aa:de:14:05:3a:43:e9:45:f2:00:9a:dc: + 71:20:b7:65:f2:f0:7d:b3:74:a0:43:1c:3f:5e:22: + 47:df:47:8d:5e:cb:93:1a:14:6e:b4:29:0f:af:1c: + 07:9c:11:74:24:38:09:23:76:0e:ca:fc:60:8f:1a: + e2:dc:d4:fd:fe:cb:12:f8:a7:83:c4:ae:db:a4:c7: + 74:b3:a5:76:90:93:9d:a3:78:01:97:e0:ec:09:78: + b9:98:ff:b7:2a:9d:05:03:5e:cf:b2:01:80:79:6b: + f9:5d:f5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + + Netscape Cert Type: + SSL Server + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + Netscape Comment: + Domain Controller Certificate plugindc.plugindom.samba.example.com + X509v3 Subject Key Identifier: + DB:4F:D4:70:C3:38:E6:26:37:6F:1B:50:5E:7D:E5:80:7D:B4:08:0D + X509v3 Authority Key Identifier: + keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42 + + X509v3 Subject Alternative Name: + DNS:plugindc.plugindom.samba.example.com, othername:<unsupported> + X509v3 Issuer Alternative Name: + email:ca-samba.example.com@samba.example.com + Netscape CA Revocation Url: + http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication, msKDC + Signature Algorithm: sha256WithRSAEncryption + ab:ed:44:9c:0d:f9:df:d6:8d:f2:98:05:cb:97:0c:14:9d:0c: + b3:2b:49:6c:4f:d6:8f:81:dd:c7:d9:67:be:ad:5b:f6:08:34: + 44:09:88:3a:9d:e9:fe:0b:91:89:f8:32:92:43:43:af:cf:04: + 5c:35:a4:d2:04:77:04:bf:37:45:57:2b:70:94:d0:7a:5f:b9: + d6:9c:47:ac:46:e4:4c:c2:87:5d:78:b7:3c:be:80:42:dc:3c: + 36:3b:c0:57:fb:ec:95:3a:bb:58:7e:09:ff:57:4e:4f:59:73: + 2a:65:0e:6e:a8:b3:8e:22:6b:40:0c:b5:5b:96:f3:a1:35:92: + 17:12:24:f3:43:fe:54:1d:ac:f9:f1:72:cb:97:b8:43:2f:e1: + ac:9c:a6:e7:78:98:38:ad:83:eb:c9:77:0b:ea:5a:21:6a:76: + f7:b2:4c:d7:7b:d4:57:eb:4c:a4:6e:be:eb:be:60:99:ae:ce: + 13:1c:6a:9f:58:e5:64:a2:b6:4e:2a:2e:62:99:d8:fa:af:11: + 5c:7e:51:d3:cf:7e:84:1c:f4:8b:a5:df:c8:b2:39:4c:c3:40: + 48:2e:b6:9d:3d:bf:b1:7b:58:39:f0:38:60:72:42:f4:8c:2a: + b3:66:c1:e9:12:bc:2a:51:75:55:1e:56:2a:bc:6e:40:1c:2b: + 16:25:90:97:18:4e:b4:63:dc:ff:7a:31:5e:b2:38:c4:17:65: + 3d:1a:31:47:04:75:3a:b7:83:c3:59:09:d5:99:56:45:4d:a0: + c8:6f:3e:87:61:17:4f:2e:7b:5c:34:76:45:e1:b5:bf:c4:fe: + 32:31:ff:2c:95:52:9c:12:2a:c3:b8:04:f9:25:a3:11:64:35: + c8:5d:92:f9:fc:2c:ba:45:18:d0:dc:95:1c:dd:30:16:3f:56: + a4:15:45:85:9b:52:55:3f:f6:a8:dd:54:53:d2:84:1b:d3:1a: + 97:61:8a:60:d6:fb:a1:75:f3:15:8f:b7:f3:f4:41:dc:7d:24: + 90:9a:62:23:a1:ef:c1:01:69:d4:a1:69:82:58:5f:35:b4:83: + b1:7c:cf:dc:f2:ca:23:af:5a:ac:e9:53:53:bd:33:8e:22:2a: + 1b:cf:ea:e7:e0:24:b2:f5:f7:ff:f6:99:6c:34:13:e9:f2:50: + 70:a1:0f:ec:f9:12:22:99:58:08:5d:f0:49:86:f8:14:3b:1b: + e6:49:eb:9b:fb:b1:07:60:e0:05:e6:4f:13:39:d1:ea:07:6b: + e8:85:33:eb:4f:b7:d3:7f:bd:9b:f4:a4:40:f4:a4:4a:f6:5f: + db:04:f5:f8:04:fa:1a:13:1b:cc:75:6f:c2:df:9d:89:12:5b: + f1:fa:cf:df:b6:32:3c:3c:5e:e0:26:9a:c7:e7:87:e7:5b:9a: + 76:b3:41:a3:0f:e1:f2:12:69:db:1b:32:57:a4:ad:5b:52:32: + 8d:7e:ec:34:c4:ce:d2:ee:6b:96:56:0e:ef:97:9a:26:a3:b5: + a0:4c:9a:e0:4f:9b:8d:07:df:92:46:1b:53:53:eb:96:62:74: + a8:13:03:e3:1f:13:0e:48:22:ca:ba:94:7f:86:80:c0:76:ab: + 08:36:e4:02:f3:ad:31:2f:97:00:06:57:09:12:66:d5:4e:8f: + 5b:88:67:7c:e3:0f:df:1c:97:17:85:9f:b9:08:4c:6e:88:e3: + e7:b9:53:06:87:98:e8:a3:9f:7c:7d:c9:07:d8:69:74:d1:e7: + c1:e6:46:e9:0f:2d:4f:04:6d:41:e8:b8:a7:87:d4:5b:1f:89: + e4:b1:c0:ba:78:2e:7d:cf:84:56:25:56:95:f7:93:dd:4a:47: + 88:b5:ac:d7:da:a7:b3:c9:8c:c5:41:34:8c:31:24:84:d4:51: + bb:46:4a:3c:db:72:e6:1b:c1:c2:15:6e:1a:ac:61:bd:ce:f1: + a3:ff:60:d9:a7:90:5a:3a:3e:1c:28:13:ed:cf:ef:ed:f1:fb: + 79:3a:57:ac:41:de:e6:17:d0:92:c6:fc:bd:6a:1c:e0:44:c7: + d7:ce:80:b4:c2:59:75:a8:bc:8b:32:4e:ea:2a:ff:89:fb:f9: + 98:6b:04:1a:fd:9e:2e:b9:bf:60:d5:84:80:f8:5b:03:0d:d9: + 1e:30:cf:4e:78:2c:a1:88:6d:ee:80:a2:ec:d9:96:00:c9:82: + a2:81:c0:6e:74:4b:69:9f:fd:c2:ed:0a:f7:31:a9:dc:89:f7: + c5:83:83:51:bf:f0:f6:8f:22:72:8e:f6:0b:54:d0:b8:7a:39: + 62:d1:d8:76:bd:c3:85:be:18:41:e9:42:c2:80:21:1c:86:20: + f9:4b:55:5f:e3:e1:6e:ae:ab:0a:4a:0c:05:1f:0d:b5:1f:a0: + d6:92:dd:20:71:56:74:e8:13:83:2f:4f:d0:72:98:b8:57:b5: + cc:06:63:3b:29:5b:f7:be:fc:e1:0e:24:94:da:1c:d1:ba:9f: + 7b:af:0d:d9:80:ed:18:85:74:73:62:2f:cb:37:e2:8c:85:90: + e9:86:dc:2b:78:b5:2a:47:fb:a1:41:f1:d4:2f:66:87:17:a5: + 24:20:54:61:99:03:72:56:5f:96:92:bf:25:4e:d0:20:a0:26: + 85:ac:b1:d2:7b:b9:b9:e9:9c:9d:01:52:a7:29:32:bd:94:65: + fb:bc:41:d2:9e:6c:59:c7:9a:b6:92:38:ba:fa:08:fc:1f:c7: + 72:9a:a3:a2:cb:02:e3:fc:29:20:20:b7:15:76:73:ab +-----BEGIN CERTIFICATE----- +MIIKDDCCBfSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx +EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE +CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x +IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB +FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz +MTgxMTQ1MzBaFw0zNjAzMTMxMTQ1MzBaMIHAMQswCQYDVQQGEwJVUzETMBEGA1UE +CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEbMBkGA1UE +CwwSRG9tYWluIENvbnRyb2xsZXJzMS0wKwYDVQQDDCRwbHVnaW5kYy5wbHVnaW5k +b20uc2FtYmEuZXhhbXBsZS5jb20xNTAzBgkqhkiG9w0BCQEWJmNhLXNhbWJhLmV4 +YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOC +Ag8AMIICCgKCAgEAqqN0K0ttKUNnA9zAvs6m40OZ5Yc0NEJwS7tQh23oZSteGrNo +DZ8n69y4hLs99EAowMeq5Y2h1X/HazaWaz5lcjcO1CwDTe7m+EFcJ78yU2wTKB++ +eJx8gFPrTQoZGohJlanGZSNbPiQnBut8WCTG56TZmALEzrMeATRMvZwo2hBNNul9 +qGgEdRjr8FiUBbFhl9Was9sJcXSQBYfUHP8GK8BRtibKKIvCCDqTYvhptDvDbZsP +gB34w1GTeGSDY8fQIegFzSI+PuLCZq9GbMZ92O1TucxC6aJDlDH0nkX6RTWrfzKT +laUbSp0nwF+/A3/KN8PCyW+2bl8FVVb1L0DCQRIX7iMbOpw5dNXMsUdqJIWV9arm +NUAM048e09+1G3z/P99+etP44ZKwQRT2qh2MNj1cxcW3L7j4CUfCUVjegEHCpRjG +qRY51I7v86nGE9se9YrnNxZ83yj+GUR7WJjucvpBovXgd8Je+uGUh5YXZnUHRcjf +akAZO9pNSOhRox+6QWIKSPViQp5pSaqsNr1vQTK7YoqWawGq3hQFOkPpRfIAmtxx +ILdl8vB9s3SgQxw/XiJH30eNXsuTGhRutCkPrxwHnBF0JDgJI3YOyvxgjxri3NT9 +/ssS+KeDxK7bpMd0s6V2kJOdo3gBl+DsCXi5mP+3Kp0FA17PsgGAeWv5XfUCAwEA +AaOCAgcwggIDMAkGA1UdEwQCMAAwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3 +dy5zYW1iYS5leGFtcGxlLmNvbS9jcmxzL0NBLXNhbWJhLmV4YW1wbGUuY29tLWNy +bC5jcmwwEQYJYIZIAYb4QgEBBAQDAgZAMAsGA1UdDwQEAwIF4DBRBglghkgBhvhC +AQ0ERBZCRG9tYWluIENvbnRyb2xsZXIgQ2VydGlmaWNhdGUgcGx1Z2luZGMucGx1 +Z2luZG9tLnNhbWJhLmV4YW1wbGUuY29tMB0GA1UdDgQWBBTbT9RwwzjmJjdvG1Be +feWAfbQIDTAfBgNVHSMEGDAWgBRGh4bC5xnPFkwMYstzf/2PGeS1QjBIBgNVHREE +QTA/giRwbHVnaW5kYy5wbHVnaW5kb20uc2FtYmEuZXhhbXBsZS5jb22gFwYJKwYB +BAGCNxkBoAoECAEjRWeJq83vMDEGA1UdEgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUu +Y29tQHNhbWJhLmV4YW1wbGUuY29tME0GCWCGSAGG+EIBBARAFj5odHRwOi8vd3d3 +LnNhbWJhLmV4YW1wbGUuY29tL2NybHMvQ0Etc2FtYmEuZXhhbXBsZS5jb20tY3Js +LmNybDAmBgNVHSUEHzAdBggrBgEFBQcDAgYIKwYBBQUHAwEGBysGAQUCAwUwDQYJ +KoZIhvcNAQELBQADggQBAKvtRJwN+d/WjfKYBcuXDBSdDLMrSWxP1o+B3cfZZ76t +W/YINEQJiDqd6f4LkYn4MpJDQ6/PBFw1pNIEdwS/N0VXK3CU0HpfudacR6xG5EzC +h114tzy+gELcPDY7wFf77JU6u1h+Cf9XTk9ZcyplDm6os44ia0AMtVuW86E1khcS +JPND/lQdrPnxcsuXuEMv4aycpud4mDitg+vJdwvqWiFqdveyTNd71FfrTKRuvuu+ +YJmuzhMcap9Y5WSitk4qLmKZ2PqvEVx+UdPPfoQc9Iul38iyOUzDQEgutp09v7F7 +WDnwOGByQvSMKrNmwekSvCpRdVUeViq8bkAcKxYlkJcYTrRj3P96MV6yOMQXZT0a +MUcEdTq3g8NZCdWZVkVNoMhvPodhF08ue1w0dkXhtb/E/jIx/yyVUpwSKsO4BPkl +oxFkNchdkvn8LLpFGNDclRzdMBY/VqQVRYWbUlU/9qjdVFPShBvTGpdhimDW+6F1 +8xWPt/P0Qdx9JJCaYiOh78EBadShaYJYXzW0g7F8z9zyyiOvWqzpU1O9M44iKhvP +6ufgJLL19//2mWw0E+nyUHChD+z5EiKZWAhd8EmG+BQ7G+ZJ65v7sQdg4AXmTxM5 +0eoHa+iFM+tPt9N/vZv0pED0pEr2X9sE9fgE+hoTG8x1b8LfnYkSW/H6z9+2Mjw8 +XuAmmsfnh+dbmnazQaMP4fISadsbMlekrVtSMo1+7DTEztLua5ZWDu+XmiajtaBM +muBPm40H35JGG1NT65ZidKgTA+MfEw5IIsq6lH+GgMB2qwg25ALzrTEvlwAGVwkS +ZtVOj1uIZ3zjD98clxeFn7kITG6I4+e5UwaHmOijn3x9yQfYaXTR58HmRukPLU8E +bUHouKeH1FsfieSxwLp4Ln3PhFYlVpX3k91KR4i1rNfap7PJjMVBNIwxJITUUbtG +SjzbcuYbwcIVbhqsYb3O8aP/YNmnkFo6PhwoE+3P7+3x+3k6V6xB3uYX0JLG/L1q +HOBEx9fOgLTCWXWovIsyTuoq/4n7+ZhrBBr9ni65v2DVhID4WwMN2R4wz054LKGI +be6AouzZlgDJgqKBwG50S2mf/cLtCvcxqdyJ98WDg1G/8PaPInKO9gtU0Lh6OWLR +2Ha9w4W+GEHpQsKAIRyGIPlLVV/j4W6uqwpKDAUfDbUfoNaS3SBxVnToE4MvT9By +mLhXtcwGYzspW/e+/OEOJJTaHNG6n3uvDdmA7RiFdHNiL8s34oyFkOmG3Ct4tSpH ++6FB8dQvZocXpSQgVGGZA3JWX5aSvyVO0CCgJoWssdJ7ubnpnJ0BUqcpMr2UZfu8 +QdKebFnHmraSOLr6CPwfx3Kao6LLAuP8KSAgtxV2c6s= +-----END CERTIFICATE----- diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-key.pem new file mode 100644 index 00000000000..21de683bd19 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-key.pem @@ -0,0 +1,54 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIJjjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI8qLXeXVBnvQCAggA +MBQGCCqGSIb3DQMHBAgbmdRIPfia2ASCCUi97VRXS5hQ6b+T8cv5YOs0CdVw+XBd +3ZiBBM1FF4lFjGMpA+YRLkcC2ksn+dW4Obyimqi6ODk3jhikXJ8LhgCa4uo22ghU +Pmqsgs3xScwJEM6VHZSGQ0ULJ+wce6mgIPCVzNRkpkREZ+jT9NAPTxSQoBJDYggV +WERdMf+3us7i2uyn4l+mAbuggEMWgJgXcz5QVCDmMilYW3CHeuT/6VW04ma0dyGa +d6O4y5DHZiO9u+oCPiHzPWrR9VCD6uq3Yr7JU5B0Aee3Fj/5NXAFsPq5a9VCP76R +oF7maYitgl1RtPYmD60bGA4yJI1hEsq+xiq/VM0ZHkvKOQJp7Jvp4xR2QPnr71IF +gmx4GAekWd02sFd3cjt7MV/nRm4W8TWGtQfm8c8Ino5T8zs74EGViNnAMg8wdzqL +tlmwkOgN94VFXl/taY4qLlmskTD/sdsfwuF6Q+4tef8iDQfxko8dWr8nT3Vj9VWD +5lQMiolcdJ96CfCitxZXkPL9lPr1LNBOFhTEZ71mhjcXFx7fPdbhTekKAMm060uV +6ycl+iLWjsJngA4SJZoeBNB+aMCWq/HT9yMWQOQHx80f65AsygGUJlZFkVBO8oQh +GLIZzZ425ZGwGF235GrQ7gKHYvZcFL+rmhPJAO/xPS0oM87fS760kVfriOwP9JPV +S7VlmLbdZ3jmz5XWggD2M1Stl0A9+Mwiss6/5IxHgcvew2VCYRQnxss5KCS52UOB +6ZMG7QlAhLMds/0dEPW5tvupojXMQj2GD1kC1LAWUGrhN2QkJ0efIs4I7sRvYyr0 +5QHBlQACNT8J/W9DiTXAbgMernAgrCGw0RN9Ibnlf2Uf8KWB1HPv7LWnjjyeU6Sj +8WdAOHPZUkYj71WhAy/UqO9gZ1RbbYtmQ4PnU0tWdzABJbRQQCnXbP0C/b3QNA5Q +ocTzBg0IUYN2SVw4ApVz8prSHiXNlNxMAnVKGdIbBB3t+a3vXCkHden01MemoP6m +ybUFPlQ479TvSNut7v7ZwQjtTliiU3plPUuT6fwvXlJfnn+QzKCh0CEbgadQvYam +lZ8bzkVOTtX+eLG3ZOGUrY6yFf+jFuPx94kE4BJU/DtK9mP/gPWrD6dm476X5xRX +J2+zPWYogBxkHhANoNI18B3VszEzB9MYzngIUJDJU+5gC8lYtT3O4ZZNlDbj1n/e +NOEZWxXUaGbGZ84RTbCJxWcZoEVQ0YUWAG7ALNPVBweLcxtx+wH1ctxsv1jNz8uP +poUMKGbX6EYkE8Ytvq5a3/hlwXcxxX+ynII6X5UJ8jssD3vmMJdHQyY0QhgIoRgJ +fV0DIqP42bwsEe03F5VFqjBbeGT5Db2RLenoPeYRiBCGjnJvWD20T+mqepBy2Ugj +I0/+SpELZhID7Ltpfdg5CKqN4/YCaO+gxY3A9Spw2iSmaVCwNXEmlbzh6gv/fRuD +J3rad27S302caZunZkw6yIjYAcvtT694Wd7mUMFQtjiB6QJPfeNBo1XnSvstWv4b +yEsKK1gJGTyiYn3/+zUGfuky7TRaKkNyA1baHlQdz42fzX8OHQwausFOjy3HgICM +pgkirbylxyS9b0utYO1utqOButyfd0P8Y5WKyBZtYV9vY0WlJKwDSRxZBpv9tL6K +LANEpcSmWZ9gKjpFtmaAIvN03GoLc2aYOwKL3vVOnbkyuUXN7XQDWpMX+xy7AlVR +IdR2Po2xTH/Hk3kFJW7MxrURNuSGKuHj7HVdWy5pTem/g6RL/OjPbiS3ys76XcoM +44h71IPOCGTxIGqMpPUAnJk59pOSJFaJLU3Gh87dBAk/amwbPfjRc2VI/d1hVpdB +jyIFhLOSKOQlIey/29ueDXWVxKbeOSVVPv2QxrI9EvpC7Uayq+ADd4kNDHfz/Jz8 +MknA/T9VmstCyjTQ4mgpwyvoAZCRa+V8nrLWm3Di6fIg8QUv7SZ+qWYKAhgG363t +5IRnnfoFD3ikCeBKYtiqhvtXoCQIm/rbOvTuLMOx43nF6Vw/nOBHG46ZZUzdwC8u +2EZnRjKOnxCtAGMkbHf6yMgG8zgM+obAHiD41CpBgDogpzS6zphTQEfDRAiqRNVQ +XrAaME5bn8aXozGEudPLJD0A0jqaXQiO8UXhToTBefGRqttXSE7XpuweUJ+34j0J +StpyjL/rXYBb0lfBV+jyOwNB4PCuGcKdEQWiX3usQH1NTJvhRt1iJx17E/GOBGMR +ygZIMK8vPKSLVfUOuwaXtJBQyH3BfNzwNyBFB2UvZ0xxrlVpi8ro3/6VUDPNNA4F +ld1bLhG0+M9LNuhset/qvYN41Y8fsQm+bHkIC9IDyCJ5I3bKfPEKFVBDDMKHT3R2 +NVKsCzQSmqLfmhGxgubdjt4fUVDK0BAfQDYsEp9DK9miD6igAy7IM+RkYfK2TqSW +bOFaf+1YN3W3WMllBYTHuaz+NwgjS6L4z9fgm/f10rEp1HY/Qqvkj9hdw7W5r8IK +vcCdXa5jM4tuXIpF/GdvwXskFQl8aGGTflU8GNjV7TJ/7SACWdHillQlkkq3VljI +hqo17cJgHC4NWFhR1X/gnpTOe80Ljkg4QIC7Nam/6rm77+acnfYtJKxOaxv3W6i2 +NCAjBeMRaKrKTIa+YCRQnAYrq8Cx2vWspb/kM7rDMiHaIbDvh0sST6MWXWYqudNs +Oxdal0PIZx5D1KvtHrX4PhomnTzYcQ81Jz/ufqg9DrpmYZGOm2mVVgRuxjHtBBpk +97t8sq3kpxXwcDAc1QeQyNekq+mG+qIevkyI5T/lPJEKEJkcpNYqkLoThegtNgzD +l+lyL5sC9VYcgDhpKH8UoalSFWFVNBu71yXF0lYorRRBFcCFEiEKQOgOvJyB3ire +f9aRNfo4ukS74BjBu5rqPoQe5JUlO8QGCQjk8y9t6Iz+WoBSZFUGVOeXWSPaWif2 +3y/zTwfvWW7FQB3hqUkqEQg3G2pJbK2a9jspy8vC2nQdr7Lip6FRBQk4Gt8Dp9rq +EancUwVeMfMRT58jgEH90yJfZk/f8VF1MQh+ByIl2YWfVZjydFOVetG/iHAH4cZs +/Y/XEG0L79XHlJu+Ccl2T4V6hhRJl6bD234FEsGPO5XFa7oueoy4w0ejdC3D8Ayu +mwYpvmsfsGJm4C3dbiQLZ8568OkOy32Dq1CSiE/lz6YgcqBlj+T7H6ZWpHN9dkMo +5zs= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-openssl.cnf new file mode 100644 index 00000000000..56b18390c03 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-openssl.cnf @@ -0,0 +1,250 @@ +# +# Based on the OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +#CRLDISTPT = [CRL Distribution Point; e.g., http://crl-list.base/w4edom-l4.base.crl] +CRLDISTPT = http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + +# Extra OBJECT IDENTIFIER info: +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] +# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used as a login credential +scardLogin=1.3.6.1.4.1.311.20.2.2 +# Used in a smart card login certificate's subject alternative name +msUPN=1.3.6.1.4.1.311.20.2.3 +# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used to identify a domain controller +msKDC=1.3.6.1.5.2.3.5 +# Identifies the AD GUID +msADGUID=1.3.6.1.4.1.311.25.1 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = CA-samba.example.com # Where everything is kept +certs = $dir/_none_certs # Where the issued certs are kept +crl_dir = $dir/_none_crl # Where the issued crl are kept +database = $dir/Private/CA-samba.example.com-index.txt # database index file. +unique_subject = yes # Set to 'no' to allow creation of + # several certificates with same subject. +new_certs_dir = $dir/NewCerts # default place for new certs. + +certificate = $dir/Public/CA-samba.example.com-cert.pem # The CA certificate +serial = $dir/Private/CA-samba.example.com-serial.txt # The current serial number +crlnumber = $dir/Private/CA-samba.example.com-crlnumber.txt # the current crl number + # must be commented out to leave a V1 CRL + +#crl = $dir/Public/CA-samba.example.com-crl.pem # The current CRL +crl = $dir/Public/CA-samba.example.com-crl.crl # The current CRL +private_key = $dir/Private/CA-samba.example.com-private-key.pem # The private key +RANDFILE = $dir/Private/CA-samba.example.com.rand # private random number file + +#x509_extensions = # The extensions to add to the cert +x509_extensions = template_x509_extensions + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +crl_extensions = crl_ext + +default_days = 7300 # how long to certify for +default_crl_days= 7300 # how long before next CRL +default_md = sha256 # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = match +stateOrProvinceName = match +localityName = match +organizationName = match +organizationalUnitName = match +commonName = supplied +emailAddress = supplied + +#################################################################### +[ req ] +default_bits = 4096 +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extensions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = US +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = SambaState + +localityName = Locality Name (eg, city) +localityName_default = SambaCity + +organizationName = Organization Name (eg, company) +organizationName_default = SambaSelfTesting + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = Domain Controllers + +commonName = Common Name (eg, YOUR name) +commonName_default = plugindc.plugindom.samba.example.com +commonName_max = 64 + +emailAddress = Email Address +emailAddress_default = ca-samba.example.com@samba.example.com +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +#challengePassword = A challenge password +#challengePassword_min = 4 +#challengePassword_max = 20 +# +#unstructuredName = An optional company name + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] +# Extensions for a typical CA +# PKIX recommendation. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. +keyUsage = cRLSign, keyCertSign + +crlDistributionPoints=URI:$CRLDISTPT + +# Some might want this also +nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +subjectAltName=email:copy +# Copy issuer details +issuerAltName=issuer:copy + +[ crl_ext ] +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +#[ usr_cert_mskdc ] +[ template_x509_extensions ] + +# These extensions are added when 'ca' signs a request for a domain controller certificate. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE +crlDistributionPoints=URI:$CRLDISTPT + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +nsCertType = server + +# This is typical in keyUsage for a client certificate. +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "Domain Controller Certificate plugindc.plugindom.samba.example.com" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. + +subjectAltName=@dc_subjalt + +# Copy subject details +issuerAltName=issuer:copy + +nsCaRevocationUrl = $CRLDISTPT +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +#Extended Key requirements for our domain controller certs +# serverAuth - says cert can be used to identify an ssl/tls server +# msKDC - says cert can be used to identify a Kerberos Domain Controller. +extendedKeyUsage = clientAuth,serverAuth,msKDC + +[dc_subjalt] +DNS=plugindc.plugindom.samba.example.com +otherName=msADGUID;FORMAT:HEX,OCTETSTRING:0123456789ABCDEF diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-private-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-private-key.pem new file mode 100644 index 00000000000..c436d7d5429 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-private-key.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKAIBAAKCAgEAqqN0K0ttKUNnA9zAvs6m40OZ5Yc0NEJwS7tQh23oZSteGrNo +DZ8n69y4hLs99EAowMeq5Y2h1X/HazaWaz5lcjcO1CwDTe7m+EFcJ78yU2wTKB++ +eJx8gFPrTQoZGohJlanGZSNbPiQnBut8WCTG56TZmALEzrMeATRMvZwo2hBNNul9 +qGgEdRjr8FiUBbFhl9Was9sJcXSQBYfUHP8GK8BRtibKKIvCCDqTYvhptDvDbZsP +gB34w1GTeGSDY8fQIegFzSI+PuLCZq9GbMZ92O1TucxC6aJDlDH0nkX6RTWrfzKT +laUbSp0nwF+/A3/KN8PCyW+2bl8FVVb1L0DCQRIX7iMbOpw5dNXMsUdqJIWV9arm +NUAM048e09+1G3z/P99+etP44ZKwQRT2qh2MNj1cxcW3L7j4CUfCUVjegEHCpRjG +qRY51I7v86nGE9se9YrnNxZ83yj+GUR7WJjucvpBovXgd8Je+uGUh5YXZnUHRcjf +akAZO9pNSOhRox+6QWIKSPViQp5pSaqsNr1vQTK7YoqWawGq3hQFOkPpRfIAmtxx +ILdl8vB9s3SgQxw/XiJH30eNXsuTGhRutCkPrxwHnBF0JDgJI3YOyvxgjxri3NT9 +/ssS+KeDxK7bpMd0s6V2kJOdo3gBl+DsCXi5mP+3Kp0FA17PsgGAeWv5XfUCAwEA +AQKCAgBgQ44Jzqdqm+fFugfSnOpxU3XCkx/US5bmYmnvvQVZ7blM/uE4rgzrdr1x +w+ATpw5Wk03J6rjdpRRvW4BISA8a/AyVja7fjGMosla25ZoSjenQvPfLOxzRmIYq +FARNf41jrT+LVwLmb6bEtJyVbUn47HsE0qsMoOfQbhzM6wfw3TlyPQ7yrpu1I7YX +BSGchJE2Av8fb/ZH1yZYuGPlZ8mnbPur8v4hGZcA5Wq4bsPTNdPuRYfdEwt/xMmZ +Jbsp01OLjUWYkDTlbS+WllL4kpH0iw6sxpsJCs1tETGbCIdD/B8fxvyTc22ODlKa +qGkuJC2EgB+nXCpi4aA0oLX5TmNHPnzIAb1d5OEqw20Iwr/tV39RYC7xuLV1FidU +3qj0jNCJkf+v7TIB0E1CoEbPIRj7plQJWWgTj+EEHtTz/b1lyPLnRUYxfTm1Pcje +SbYjDd/GxKmUhNQyxIGuNR1B2JA6qZiaYfjFCp4h54NwHWvt0yMR5xUglG7+IGof +jcLPHlsZtnCit/bGUz35JdbirQFbBWIAHpqLlPf7dqVzaTwI/nw6jdQ/bUxq24kz +p8f3V7OEzKdemXfGBV9bk9hD+zeCQwm3EqILmPU3Be+sF2xWlkWwR2Xygy8xQ0q5 +2/BnLkY2dXZQMEEJJi5gZRN+irvpC33G4X1qXGZfDjvkeqOeAQKCAQEA1QoWw3Xi +qyxoSf7F/KZefo1IsXsIsuXYG25fLWExDHncpxEpXl+IqQx1icfMeM0EP/jUFjWu +Ti9V09u9FcP5Dl+uHfHqc3zFBJfAGhlPH+7YhVcjAzBx5LA7J65GqO3CHSUVk74G +4nvAr51R1ba85VfgCavllaS6oJcEOZxECBT+1DicaD4Ir6QSDH0+d19t4LUDw1G8 +ARlOpC9rP/eSGL5LqOTiZ8LjjruGI55GG0vpgoG3bEli/Or8uqZzqZjYR5dD9Wfo +MIjqdDjmojOiZMh9m/coZlphQaGl3Rqb3e2RZkZ2n+wyyo8g5DknyPKyiN0qu9nt +86m/B3bE0RaFIQKCAQEAzQx3hpsD5PtTXL/K43OXVb4/r9OTwF55TuCnne4xBqgv +jHMtMsgF481gCtrIbbZ+TH6B5FdYNHBui2hfrN4R1XZoAjAuCRxgHQn8UPd9G415 +aieSIj/wPUQgl8AIOygxDw28FvjDqf7khKF9z+pDsxNDqkTxFl04zYb2cLUBW9/r +xQ68sb8BxxQ7qbR94gyOnSGO0+9Vy3MQNUAfLbbqMyBKbFym4gPGkVdGCvAaMsHn +Hu2Z0oZSEwe3hAVL6ZnrqvMOxDbJ7RKZev1YfZGdno8YemAXKwRk3LOxXxodAF4x +bUUOaY/AVqYvLGu7SJ4h4LBFn/DPnEbpceN3IO/qVQKCAQBH3NZe6rYiXaF0TG/G +0OwRLmF2FPWTOzsRzcJnUWC1P6ox5PUac4lq1NwVNQOBQE8NsUcBkuwQTaFbDMWU +wP2TXq0iRsd6W30uFm5jn2P0dqItIH6cBcx1gwkBUqVdOI6BPFAx/SjfXzVZR+0h +9Tl095aITKbuOpoFr8tqD49XVpW7Srlf5IUTknnQIrNemx86bHUvfrO3fyzq71/z +PPTYSeDFwSeqLrCKJjGSdEJb1NiZAF66NWshu7ay05EyhW93fswazQkizhygRc1u +q5I9AvB0GwRSumwSMo/7rI0laIzifiRnv8pGT8+djLYh79RPnKNcqJ++0OSyhNrR +WRJhAoIBAQCjzjjSNJY44DopVyJ68AXOvqxcBzb6r75TMA9XkEhkHAnYNs69yaNC +5/e41CzX0Lk23L1hsBFL2yHEhr4f+Evg7rWKQfkU2DFEIY0LFZtBXpTHJBOO/usp +1nn/IK6yq5n9f6hp5ZNSA8mE1woOBgTNUy90H51Fk3VkY1QOl9sdDVZpVyuRB5kg +893x5bnG0uc/SeazEnjEjgg9shr2RzDzZPFvfdjnp8KCq2jOJh+XuuWrBH8k+p8o +irqlYiHR3V+ycneycl5/4KLx6OA/eAul9oTEhm0btWfqFDc3VUIj4Bu2QjuQQwGR +dzMqVmoISiOgPtFwQ01neBLYI7Iwgtj9AoIBAApZsr/9mYNwzPamSGc1zyDF/9j5 +EM6MXgFAQxpxzQlC36EDliZ8RvrQSJ5HjWxIihcZP/iR0rUBn71kitj5B88iURbF +lsKyjbX4ZfrmClWiFkmJv0Js4n8+H3YdqFeUPgD3gQ1UfcViJgEt0iOv6N6qN32Q ++ofcWP6cdMEzXmfK+q53U6C38d2WD3QFoc/5qB0NnDYMr7Al4LHcfNwOmxIHDd7q +C/0ang9tkbjVehX6S1DozFEgmMxYU8ZrB/KwYRMEXTUNSjyn2PXgTNqMch9OZpsD +c9jmUdN9x7Pi7pyaxiREBpRDp9Cj0RZEcASeUKH2lpuEl7dT9YZaShBeY20= +-----END RSA PRIVATE KEY----- diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-req.pem b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-req.pem new file mode 100644 index 00000000000..4fc6722945f --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-req.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIFGjCCAwICAQAwgdQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTYW1iYVN0YXRl +MRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNhbWJhU2VsZlRlc3Rpbmcx +GzAZBgNVBAsMEkRvbWFpbiBDb250cm9sbGVyczEtMCsGA1UEAwwkcGx1Z2luZGMu +cGx1Z2luZG9tLnNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkBFiZjYS1z +YW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAKqjdCtLbSlDZwPcwL7OpuNDmeWHNDRCcEu7UIdt +6GUrXhqzaA2fJ+vcuIS7PfRAKMDHquWNodV/x2s2lms+ZXI3DtQsA03u5vhBXCe/ +MlNsEygfvnicfIBT600KGRqISZWpxmUjWz4kJwbrfFgkxuek2ZgCxM6zHgE0TL2c +KNoQTTbpfahoBHUY6/BYlAWxYZfVmrPbCXF0kAWH1Bz/BivAUbYmyiiLwgg6k2L4 +abQ7w22bD4Ad+MNRk3hkg2PH0CHoBc0iPj7iwmavRmzGfdjtU7nMQumiQ5Qx9J5F ++kU1q38yk5WlG0qdJ8BfvwN/yjfDwslvtm5fBVVW9S9AwkESF+4jGzqcOXTVzLFH +aiSFlfWq5jVADNOPHtPftRt8/z/ffnrT+OGSsEEU9qodjDY9XMXFty+4+AlHwlFY +3oBBwqUYxqkWOdSO7/OpxhPbHvWK5zcWfN8o/hlEe1iY7nL6QaL14HfCXvrhlIeW +F2Z1B0XI32pAGTvaTUjoUaMfukFiCkj1YkKeaUmqrDa9b0Eyu2KKlmsBqt4UBTpD +6UXyAJrccSC3ZfLwfbN0oEMcP14iR99HjV7LkxoUbrQpD68cB5wRdCQ4CSN2Dsr8 +YI8a4tzU/f7LEving8Su26THdLOldpCTnaN4AZfg7Al4uZj/tyqdBQNez7IBgHlr ++V31AgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAgEAXdU/NQs8tIc2BsjClwmdZYXo +HRV/QyyrtxwZyDhIt8jG/DE/rggGXPLOaQQwbPgax7JCYbeyolCLQtOIP/sWwpje +0rADXkdvwdUyEmEUl6ARmxJNm9j4DTKttAQCFquww70di9X1C7IHXrb5VR2HrvgI +JChexYX3Nt2Aj01Y1vc7Wn1EStWJ5CUZg3yHe4x5aZ9t0/8J7fXLzmhyNO96S2dy +BiPz3S7SNv8kRLqHDsKEZq6gzY54lQaCIpj4gCyd573YBm3YogMak9Su58+/AWE5 +lrwAJLSb6nfN0YZhVsq3kAhhD2yT/x1vH3JG/0LcaGqW/zOa0ZLWU2qPk4y5UIKo +EdC0/FGvmHBDLmb7YPKsjBnrtZ0pGlyxu8vempDG3qa7elsVBW9VvI3R6fPcNfZe +WJhNuS8RnnANRQJkavZEpPcM/IwBvje5toOH9uHIw9SzG3i8XHuelQ9g49zbpz0h +JoGalDcQDk1vriIivNPsEo17T2jXxNiZY+BFF2hGNmxjDjenbdFu1N/TQU5ouUag +SO/h/AqO6ONCXUaPnqcYXYcaC5kY/4Ea4Vp+DcbzKu25FrQLQDcDc4Iq1RpAdHPS +WJNnR1/IKkTGBvhPHGmp8ZRohynJXPJ6AbLChhpJrJjb+fLsboLNTjIjoOsesxe9 +jzOfD9FSF9kL1esrz70= +-----END CERTIFICATE REQUEST----- diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-cert.pem new file mode 120000 index 00000000000..cf090b32d90 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-cert.pem @@ -0,0 +1 @@ +DC-plugindc.plugindom.samba.example.com-S02-cert.pem
\ No newline at end of file diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-private-key.pem new file mode 120000 index 00000000000..64ddc9628f1 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-private-key.pem @@ -0,0 +1 @@ +DC-plugindc.plugindom.samba.example.com-S02-private-key.pem
\ No newline at end of file diff --git a/selftest/manage-ca/CA-samba.example.com/NewCerts/00.pem b/selftest/manage-ca/CA-samba.example.com/NewCerts/00.pem new file mode 100644 index 00000000000..2a1f36f063f --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/NewCerts/00.pem @@ -0,0 +1,190 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com + Validity + Not Before: Mar 18 11:44:51 2016 GMT + Not After : Mar 13 11:44:51 2036 GMT + Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Domain Controllers, CN=localdc.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:e6:5f:4f:b7:ba:64:00:94:b2:0b:a0:29:3b:66: + 1f:28:85:cd:fa:bb:d7:de:18:8e:e2:4b:14:ab:33: + 17:4c:5f:8b:84:0e:b2:19:cd:32:ae:2a:8e:fc:8c: + 4b:51:c0:d9:2e:de:7f:d2:d3:7a:83:9d:95:66:6d: + e0:08:1a:25:10:2f:d3:27:bf:c7:ae:3a:f9:33:e4: + 65:87:af:a2:80:87:cc:f7:69:a3:4d:8d:65:30:81: + b3:20:ca:3f:54:28:b7:d9:1f:fe:90:92:8f:34:0b: + 0c:44:eb:48:b1:54:3e:66:29:c3:aa:e8:f4:f7:2d: + 6a:0c:cc:c2:31:f5:35:76:48:ba:82:c8:d0:06:42: + 2f:cd:4e:3f:20:b5:fc:f6:72:fc:0e:fe:92:a3:97: + 16:c7:9b:40:e4:ca:5c:47:39:bd:b1:4c:09:e3:a7: + 42:c2:0d:a8:b5:3e:f9:dc:7d:39:05:4d:c8:5f:c8: + 69:dc:85:5c:3c:9a:23:07:bc:30:33:38:a6:c4:03: + 07:59:e3:97:55:84:61:65:52:80:60:fa:77:b6:76: + 5a:31:32:51:a6:22:98:b5:ab:dc:67:51:23:76:08: + 09:8e:38:1c:75:0b:9c:59:43:1f:41:04:dd:60:69: + d9:fa:31:b8:16:5e:b8:f8:27:82:16:8e:c6:ce:d9: + 56:01:68:e4:5f:f8:2d:0f:31:85:27:37:92:fa:4d: + 0b:b3:f3:6a:f4:be:30:15:0d:8e:00:b5:87:f8:67: + 5c:ae:6a:25:59:23:8c:bf:a5:02:eb:b7:cc:0c:fc: + bc:3b:bd:80:08:fc:a3:86:5f:2d:ec:79:05:8e:e4: + d2:d2:c4:a6:ab:84:e3:da:aa:58:c3:db:8b:28:4b: + 15:49:79:7e:58:19:8b:7d:3e:87:9e:79:28:15:e1: + 8a:ad:75:10:0b:71:1e:8f:e8:1f:cd:d4:9b:11:e1: + 47:26:1a:f8:d4:a3:0b:7d:08:de:a6:f1:7a:93:26: + fb:bd:78:a3:60:8a:8b:29:fe:f8:9f:7b:5e:d7:64: + 03:e1:58:23:ac:23:35:3f:4f:b9:f7:3d:d6:d7:64: + 1f:0b:6b:11:9b:10:1f:2b:49:b2:f9:63:e8:cf:bf: + ac:da:9e:b7:f7:12:91:e4:01:77:9a:7f:31:c8:b6: + af:7d:5e:4e:55:ee:3d:2a:f9:0d:56:11:49:e3:f6: + 09:8c:2f:d0:06:eb:f4:f7:65:9f:db:85:0a:57:7e: + 9a:b8:1a:60:11:18:d1:3d:1c:c0:53:65:9b:e8:00: + 93:e4:91:61:b6:e8:7b:63:d3:d8:ec:70:8d:92:54: + 12:8b:56:1f:cf:83:34:d5:44:86:cd:b6:0b:fc:95: + 8f:f9:11 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + + Netscape Cert Type: + SSL Server + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + Netscape Comment: + Domain Controller Certificate localdc.samba.example.com + X509v3 Subject Key Identifier: + CD:25:BC:9E:49:98:02:88:4F:A7:5C:4F:2D:68:B9:E3:61:9F:AE:2E + X509v3 Authority Key Identifier: + keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42 + + X509v3 Subject Alternative Name: + DNS:localdc.samba.example.com, othername:<unsupported> + X509v3 Issuer Alternative Name: + email:ca-samba.example.com@samba.example.com + Netscape CA Revocation Url: + http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication, msKDC + Signature Algorithm: sha256WithRSAEncryption + 15:c0:31:31:7f:65:7c:7c:a4:db:1c:23:1b:81:bf:e8:c8:ad: + c0:2e:ce:c6:8e:3a:a2:d7:8f:ad:19:9a:e9:ea:72:bd:25:bc: + 26:3c:57:a7:53:4e:c5:24:a2:3c:70:59:48:9d:f5:df:2c:bd: + b5:b4:71:fe:a6:58:15:eb:31:86:83:c9:7a:39:47:80:f1:9d: + 31:ed:e1:5a:26:3f:9c:be:06:45:93:96:d9:3b:7d:d1:9c:b2: + ea:7b:a3:71:f0:9d:c7:a1:29:ba:38:eb:e4:be:bc:e9:9d:e8: + e1:be:eb:57:5a:1e:d1:09:58:dc:77:04:85:48:ba:94:19:73: + 8f:3a:31:6d:3c:ec:37:a6:d7:94:25:e3:98:e9:3c:f6:85:c6: + 6a:8e:d5:cd:32:05:1f:76:b7:b0:5a:c5:45:c0:81:20:16:4f: + e0:bb:e7:42:06:5c:6c:ff:e6:8a:73:7b:8c:1c:98:fe:2d:47: + 8a:e0:06:38:53:77:5b:6b:13:82:f4:a6:0b:c3:b2:88:2a:05: + 96:c8:04:66:cb:59:19:08:d4:9b:0f:1f:e3:3a:48:65:32:07: + 69:39:34:d4:a3:2e:d5:19:09:c7:07:d9:71:4d:62:81:fc:5a: + be:f1:da:65:3a:24:1e:2c:40:c8:78:4a:bb:0a:4f:a4:3d:ab: + 3c:b9:22:fb:0b:5c:9f:09:95:76:6f:6b:53:3d:1f:ee:fd:3f: + cd:be:7a:61:3e:08:3b:99:69:68:91:a9:9f:b8:4f:b8:c9:1f: + d4:ed:86:61:aa:6f:4f:a8:6a:4d:b6:79:e9:af:37:d2:83:9b: + f7:61:6a:65:f6:8c:f7:f9:3b:23:b6:cc:78:bf:16:ee:a0:50: + 1f:7e:38:7b:72:1b:62:ef:17:60:db:6f:c9:29:c1:c2:53:f7: + e8:27:de:3e:22:da:f0:5f:ba:55:9f:57:6f:b9:8f:c4:7a:c5: + 72:9a:a3:95:cc:ac:fd:f3:a6:a9:da:d6:57:d3:28:7f:72:60: + a8:5b:2f:c3:b1:07:c4:c7:af:d9:3c:a9:e9:78:e1:5a:0f:da: + c9:d0:e6:5d:9a:bd:61:ef:1d:25:7f:54:08:aa:f2:6c:11:1e: + a4:46:8e:9e:e2:79:c8:c2:dd:09:1b:62:27:e6:70:7a:e4:f3: + 66:db:57:30:ce:3f:27:f5:c6:c8:f2:3f:a1:bc:dd:ec:fe:3a: + c4:b9:ad:21:73:d8:83:a5:9f:02:ba:d0:52:8a:f2:d5:25:63: + 15:82:38:25:e2:74:ce:a6:a5:32:9a:6c:52:33:ba:45:ba:01: + 16:14:5f:ce:66:89:9e:03:ed:8a:95:80:c4:cf:20:24:d4:c5: + 5b:e5:c3:51:62:57:1e:45:be:0a:47:24:b7:cb:a4:dd:6e:54: + 2c:f4:25:80:a3:85:a9:74:0c:c0:65:c9:f8:2f:9a:22:bc:85: + c9:63:8a:08:f3:c9:1c:77:9b:a8:42:5a:45:dd:be:21:be:9d: + e7:15:9b:67:19:6c:d3:da:9b:67:a8:1d:22:35:d4:16:89:ad: + 4c:c3:17:bb:9e:f5:e5:3b:a2:a6:81:34:e0:4c:36:be:bb:e5: + a3:60:7d:28:30:82:db:99:ef:c6:19:43:d1:73:24:f0:8e:d1: + 6c:3b:cc:f8:cb:1a:14:79:67:07:ea:b5:47:08:bf:11:33:29: + 01:2e:fd:44:14:33:f6:36:65:8b:a8:f8:e6:0b:84:6d:a1:91: + 08:56:c1:5d:ca:12:b6:00:ba:9c:7e:7e:9b:26:3f:d3:dd:e1: + 2f:ae:f5:76:45:ed:a2:9b:b4:a1:a9:d6:b6:f5:7e:68:80:17: + 81:fb:ef:24:dc:84:de:38:20:45:34:6c:72:e5:d6:08:61:e7: + dd:45:43:d2:06:2b:ae:d9:73:a1:fb:bb:04:3c:61:45:d3:9e: + fc:45:c0:e3:db:02:ae:45:e3:de:d1:34:00:b0:1b:0f:ce:f8: + 33:0f:87:9c:9b:5d:49:11:7a:30:15:e3:9f:76:02:82:18:c2: + a6:dd:25:a6:e0:84:1f:1d:0d:db:81:7c:df:a1:65:9b:5b:08: + e0:4e:6d:4c:76:8a:0b:09:14:7c:e1:23:ad:18:4c:02:6b:e3: + f4:e0:22:26:e1:30:7e:a5:59:22:5b:a5:73:5a:23:24:1f:1a: + 7b:e5:46:f7:0c:14:00:53:72:33:4d:c4:c4:59:3e:04:17:33: + 34:04:67:1e:cd:a0:e5:9f:85:87:77:f6:dd:03:f0:74:cf:56: + e9:99:a8:95:3a:52:db:d1:61:72:91:60:9f:80:bf:22:26:da: + d7:09:4e:df:81:30:dc:9b:b4:c1:c7:cb:97:93:bc:b7:93:a3: + db:88:cc:5e:9f:39:94:57:a5:57:d6:cd:1b:12:a4:86:62:4f: + b2:08:22:4e:d9:07:8e:27:06:82:d9:f1:ec:70:30:82:56:0c: + f7:d9:56:bf:f1:7f:fd:65:90:8d:5e:d5:13:b3:31:89:5d:e8: + df:35:2f:77:6b:b7:c7:e8:7d:89:f8:cf:9e:a5:1c:60:be:7c: + 6c:b7:0f:fa:8e:62:8e:b0:72:10:8a:04:6a:50:83:3a:38:dc: + 13:8b:89:8f:6c:0f:fc:3e:c7:36:15:37:78:5f:24:87:8a:70: + cc:3e:5a:fc:88:78:19:70:89:65:a0:c7:47:67:f2:bc:1e:f5: + 04:e7:94:ba:74:ea:2a:a7:c1:26:b1:2e:ac:64:0b:fa +-----BEGIN CERTIFICATE----- +MIIJ6zCCBdOgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx +EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE +CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x +IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB +FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz +MTgxMTQ0NTFaFw0zNjAzMTMxMTQ0NTFaMIG1MQswCQYDVQQGEwJVUzETMBEGA1UE +CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEbMBkGA1UE +CwwSRG9tYWluIENvbnRyb2xsZXJzMSIwIAYDVQQDDBlsb2NhbGRjLnNhbWJhLmV4 +YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkBFiZjYS1zYW1iYS5leGFtcGxlLmNvbUBz +YW1iYS5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AOZfT7e6ZACUsgugKTtmHyiFzfq7194YjuJLFKszF0xfi4QOshnNMq4qjvyMS1HA +2S7ef9LTeoOdlWZt4AgaJRAv0ye/x646+TPkZYevooCHzPdpo02NZTCBsyDKP1Qo +t9kf/pCSjzQLDETrSLFUPmYpw6ro9PctagzMwjH1NXZIuoLI0AZCL81OPyC1/PZy +/A7+kqOXFsebQOTKXEc5vbFMCeOnQsINqLU++dx9OQVNyF/IadyFXDyaIwe8MDM4 +psQDB1njl1WEYWVSgGD6d7Z2WjEyUaYimLWr3GdRI3YICY44HHULnFlDH0EE3WBp +2foxuBZeuPgnghaOxs7ZVgFo5F/4LQ8xhSc3kvpNC7PzavS+MBUNjgC1h/hnXK5q +JVkjjL+lAuu3zAz8vDu9gAj8o4ZfLex5BY7k0tLEpquE49qqWMPbiyhLFUl5flgZ +i30+h555KBXhiq11EAtxHo/oH83UmxHhRyYa+NSjC30I3qbxepMm+714o2CKiyn+ ++J97XtdkA+FYI6wjNT9Pufc91tdkHwtrEZsQHytJsvlj6M+/rNqet/cSkeQBd5p/ +Mci2r31eTlXuPSr5DVYRSeP2CYwv0Abr9Pdln9uFCld+mrgaYBEY0T0cwFNlm+gA +k+SRYbboe2PT2OxwjZJUEotWH8+DNNVEhs22C/yVj/kRAgMBAAGjggHxMIIB7TAJ +BgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly93d3cuc2FtYmEuZXhh +bXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMBEGCWCG +SAGG+EIBAQQEAwIGQDALBgNVHQ8EBAMCBeAwRgYJYIZIAYb4QgENBDkWN0RvbWFp +biBDb250cm9sbGVyIENlcnRpZmljYXRlIGxvY2FsZGMuc2FtYmEuZXhhbXBsZS5j +b20wHQYDVR0OBBYEFM0lvJ5JmAKIT6dcTy1oueNhn64uMB8GA1UdIwQYMBaAFEaH +hsLnGc8WTAxiy3N//Y8Z5LVCMD0GA1UdEQQ2MDSCGWxvY2FsZGMuc2FtYmEuZXhh +bXBsZS5jb22gFwYJKwYBBAGCNxkBoAoECAEjRWeJq83vMDEGA1UdEgQqMCiBJmNh +LXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0GCWCGSAGG+EIB +BARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMvQ0Etc2FtYmEu +ZXhhbXBsZS5jb20tY3JsLmNybDAmBgNVHSUEHzAdBggrBgEFBQcDAgYIKwYBBQUH +AwEGBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggQBABXAMTF/ZXx8pNscIxuBv+jI +rcAuzsaOOqLXj60Zmunqcr0lvCY8V6dTTsUkojxwWUid9d8svbW0cf6mWBXrMYaD +yXo5R4DxnTHt4VomP5y+BkWTltk7fdGcsup7o3HwncehKbo46+S+vOmd6OG+61da +HtEJWNx3BIVIupQZc486MW087Dem15Ql45jpPPaFxmqO1c0yBR92t7BaxUXAgSAW +T+C750IGXGz/5opze4wcmP4tR4rgBjhTd1trE4L0pgvDsogqBZbIBGbLWRkI1JsP +H+M6SGUyB2k5NNSjLtUZCccH2XFNYoH8Wr7x2mU6JB4sQMh4SrsKT6Q9qzy5IvsL +XJ8JlXZva1M9H+79P82+emE+CDuZaWiRqZ+4T7jJH9TthmGqb0+oak22eemvN9KD +m/dhamX2jPf5OyO2zHi/Fu6gUB9+OHtyG2LvF2Dbb8kpwcJT9+gn3j4i2vBfulWf +V2+5j8R6xXKao5XMrP3zpqna1lfTKH9yYKhbL8OxB8THr9k8qel44VoP2snQ5l2a +vWHvHSV/VAiq8mwRHqRGjp7iecjC3QkbYifmcHrk82bbVzDOPyf1xsjyP6G83ez+ +OsS5rSFz2IOlnwK60FKK8tUlYxWCOCXidM6mpTKabFIzukW6ARYUX85miZ4D7YqV +gMTPICTUxVvlw1FiVx5FvgpHJLfLpN1uVCz0JYCjhal0DMBlyfgvmiK8hcljigjz +yRx3m6hCWkXdviG+necVm2cZbNPam2eoHSI11BaJrUzDF7ue9eU7oqaBNOBMNr67 +5aNgfSgwgtuZ78YZQ9FzJPCO0Ww7zPjLGhR5ZwfqtUcIvxEzKQEu/UQUM/Y2ZYuo ++OYLhG2hkQhWwV3KErYAupx+fpsmP9Pd4S+u9XZF7aKbtKGp1rb1fmiAF4H77yTc +hN44IEU0bHLl1ghh591FQ9IGK67Zc6H7uwQ8YUXTnvxFwOPbAq5F497RNACwGw/O ++DMPh5ybXUkRejAV4592AoIYwqbdJabghB8dDduBfN+hZZtbCOBObUx2igsJFHzh +I60YTAJr4/TgIibhMH6lWSJbpXNaIyQfGnvlRvcMFABTcjNNxMRZPgQXMzQEZx7N +oOWfhYd39t0D8HTPVumZqJU6UtvRYXKRYJ+AvyIm2tcJTt+BMNybtMHHy5eTvLeT +o9uIzF6fOZRXpVfWzRsSpIZiT7IIIk7ZB44nBoLZ8exwMIJWDPfZVr/xf/1lkI1e +1ROzMYld6N81L3drt8fofYn4z56lHGC+fGy3D/qOYo6wchCKBGpQgzo43BOLiY9s +D/w+xzYVN3hfJIeKcMw+WvyIeBlwiWWgx0dn8rwe9QTnlLp06iqnwSaxLqxkC/o= +-----END CERTIFICATE----- diff --git a/selftest/manage-ca/CA-samba.example.com/NewCerts/01.pem b/selftest/manage-ca/CA-samba.example.com/NewCerts/01.pem new file mode 100644 index 00000000000..deb2b73f312 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/NewCerts/01.pem @@ -0,0 +1,169 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com + Validity + Not Before: Mar 18 11:45:11 2016 GMT + Not After : Mar 13 11:45:11 2036 GMT + Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Users, CN=administrator@samba.example.com/emailAddress=administrator@samba.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c9:07:44:3a:5f:f6:34:5f:27:8a:7a:6e:2f:fb: + 45:1f:c3:3d:dd:2c:43:65:f1:7a:29:3f:42:26:bd: + ff:4f:5d:91:c0:bb:75:e3:81:14:7d:59:72:78:96: + 1a:5e:8d:95:93:f4:5d:92:79:0e:24:77:4f:8b:08: + 4e:72:b1:99:88:63:06:74:b2:dc:f7:82:62:e9:dd: + 6f:e5:a7:b4:c9:44:0c:e4:43:41:f8:57:a9:20:b1: + 70:c1:76:a1:48:5b:e9:54:b6:4f:22:50:93:90:f0: + 62:32:50:9a:6e:22:6b:37:a0:f7:1f:fc:b1:5f:ae: + e2:0b:88:6d:ea:29:b6:01:27:b2:84:ef:10:4d:6c: + 0a:df:ea:a9:8a:82:98:60:a7:52:73:a4:f7:7c:b2: + 4a:b9:f0:9b:c4:f8:19:5a:c0:84:54:52:35:c8:92: + 4f:16:af:d6:36:a6:78:57:55:e5:5e:6b:62:00:fa: + 48:c2:7a:e7:17:38:b5:23:d5:a8:fb:7d:df:42:5c: + 03:f4:7c:ef:ff:f1:a0:e6:d8:27:93:06:b3:a3:21: + 68:0e:c4:60:20:02:46:2f:2b:d8:88:e4:2b:01:c2: + 31:5a:55:28:be:55:03:f2:06:2b:e4:ec:48:60:e4: + b6:db:a1:f0:c5:24:ba:e1:a8:e2:6a:fb:0b:40:6c: + 3d:f5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + + Netscape Cert Type: + SSL Client, S/MIME + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + Netscape Comment: + Smart Card Login Certificate for administrator@samba.example.com + X509v3 Subject Key Identifier: + 70:86:EC:68:B4:51:8A:1C:12:65:A0:2A:B3:43:33:12:65:83:8D:40 + X509v3 Authority Key Identifier: + keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42 + + X509v3 Subject Alternative Name: + email:administrator@samba.example.com, othername:<unsupported> + X509v3 Issuer Alternative Name: + email:ca-samba.example.com@samba.example.com + Netscape CA Revocation Url: + http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + X509v3 Extended Key Usage: + TLS Web Client Authentication, scardLogin + Signature Algorithm: sha256WithRSAEncryption + 5d:b1:10:f8:36:dd:a9:fd:8d:be:31:53:1d:cf:b5:ea:33:1a: + 85:0f:13:8d:cc:67:91:41:97:e4:e9:67:6a:0c:ce:a4:9a:06: + b3:53:bf:e6:6d:f1:d1:32:7d:54:5d:6a:a8:94:fe:d4:f6:62: + 85:0f:e0:73:f8:ce:51:32:18:65:50:34:f9:f2:66:f8:ec:fd: + 94:c2:1d:28:6f:ce:3c:b3:0a:0a:cc:8b:fb:2c:e8:44:d2:d8: + 64:d7:19:1c:a4:25:5f:75:63:bc:44:56:64:cb:ca:8c:43:75: + 1e:95:36:98:a1:c6:49:e6:14:60:ad:87:91:af:d8:3c:d2:63: + 52:82:02:0a:42:c0:e3:7b:50:51:37:d5:c0:a5:0c:09:ac:2d: + a0:b3:29:e4:9e:bf:d3:df:01:82:00:a5:ad:fb:35:e8:f6:1c: + d7:cb:d1:3c:54:1f:d2:73:38:ce:a6:0a:e2:77:0a:fc:e5:ff: + 7e:68:a6:c7:57:fd:c7:cf:95:48:9f:97:6f:fe:2e:9f:e3:d6: + b0:a5:b5:33:9f:12:c1:e6:12:15:77:33:8f:1e:35:b5:88:f8: + 6b:47:88:e4:cb:49:f7:11:ba:19:39:55:5e:4a:5a:65:76:7e: + cc:3a:a7:fa:91:9a:ef:b5:c1:bf:f0:e7:a2:c6:9f:08:17:fc: + 4c:a4:ef:0b:d8:c7:a4:f9:74:36:b3:67:90:5e:84:26:83:bd: + 36:89:0d:c6:8c:1d:03:ce:8f:80:c9:0c:c6:c0:1e:eb:42:e7: + 97:7f:21:ac:b1:64:06:f6:1d:6d:0c:87:ff:c9:30:23:d3:21: + 1f:53:05:69:21:d5:26:ca:7f:ce:3a:4e:8d:d1:40:16:7e:a2: + c0:0f:95:0c:67:90:47:d2:e2:cf:87:ef:dc:35:18:2a:a2:21: + cd:67:b0:b2:14:9f:75:94:93:ba:8c:4d:45:71:cb:e9:df:cd: + f5:e3:f0:ff:c3:38:77:c2:41:55:d6:60:96:d8:bd:5f:09:22: + 97:44:8d:4d:b1:dd:68:39:04:1b:7a:57:3b:ca:56:27:87:31: + 55:84:6c:f0:65:af:ec:0b:52:87:28:0b:2d:52:c0:ce:a3:7d: + 7b:47:07:df:8a:65:e9:6f:da:e7:b6:94:06:69:b8:55:3d:11: + 01:c6:bf:0b:61:1b:cc:30:47:ab:cf:fb:72:62:f3:eb:66:11: + cd:1c:ab:4e:29:bf:b7:78:d6:09:ec:d7:67:5b:17:b9:34:cc: + af:5e:d9:02:0b:33:fc:a1:f2:64:33:c4:af:11:5b:08:f7:af: + ba:0d:68:d7:cf:d2:40:2f:56:20:34:da:82:18:7c:0e:71:61: + a6:58:60:00:30:a6:c7:25:3a:90:70:a0:14:e6:da:d8:12:e9: + b3:6a:c4:96:85:41:80:a6:71:17:b5:cf:4f:a2:2d:51:93:fd: + 26:eb:44:3c:2a:84:6a:da:18:10:d6:48:e3:8e:0f:c9:69:05: + 96:8c:96:f9:74:06:ab:11:d2:e4:e5:d7:22:db:13:93:d6:f9: + 24:84:56:7c:6a:43:a9:b8:30:33:2c:a4:42:9f:ec:f6:56:2d: + 46:cf:ec:26:49:5e:da:53:21:6b:8c:05:0d:b7:12:26:29:43: + 32:b2:6c:ed:07:47:75:2b:0b:7e:5d:28:1b:5b:7b:b5:63:13: + 55:4d:f7:a3:f6:fd:2d:f5:6d:43:83:40:46:b3:0d:d6:28:99: + d4:fb:89:fb:41:c6:15:35:a5:ee:1a:08:33:b3:0b:75:0a:d0: + fc:31:ec:77:80:e2:f0:ab:20:cc:43:24:67:42:a5:d7:e6:b0: + b9:84:fd:43:a0:5e:d9:78:10:97:d3:d1:b7:d9:33:70:0f:4d: + f0:a1:ac:22:d7:36:53:68:6d:39:e0:14:dc:d7:ea:1e:c2:92: + 1b:f8:2a:99:97:14:76:2c:89:3f:b7:89:c7:69:6e:5b:dd:8e: + 47:7a:f0:0e:a4:d0:18:c6:c4:34:f0:b8:84:3a:6e:ee:1e:7b: + 84:58:d2:10:a6:a2:0c:14:a8:55:e9:c5:7e:ab:97:e4:9d:b5: + f0:9f:2e:36:ac:2f:73:30:c8:b1:fc:b4:ce:b4:39:bd:59:75: + b8:24:5a:b1:67:de:34:3f:4e:17:5d:d3:bc:bb:6a:6a:b7:3e: + 0b:e8:4d:3b:08:d6:de:a7:9a:d7:8d:60:56:bb:3e:6c:d0:a7: + f8:45:a2:52:a3:b5:1e:ef:56:df:14:62:52:ed:36:ab:cc:7a: + a1:96:14:9a:e9:de:4a:28:68:bd:21:2d:60:d5:06:8a:e9:5e: + b6:ce:e1:b4:ed:56:9f:99:87:fe:20:bb:d5:8d:0d:72:1d:7e: + 88:27:9c:66:d5:26:aa:32:0a:ad:64:de:b8:13:2d:51:cc:8b: + e2:f4:c1:63:a6:64:e8:03:08:42:38:bf:f4:fe:b3:25:03:1b: + 14:b9:68:81:14:b9:5d:b9:6a:eb:f0:a9:24:41:8e:49:03:be: + 0b:55:cf:ac:77:68:ed:54:ae:55:40:dd:31:c4:3a:e2:d7:86: + d5:d5:e4:5e:5b:ce:9e:da:a1:90:58:e1:b3:7c:a6:87:15:bd: + 3a:67:b9:ab:29:de:4f:af:08:98:89:45:62:8f:db:5b:2e:2b: + e8:97:35:a2:fc:4f:cf:63:7d:56:a0:51:dd:3f:b2:90:a6:9b: + a0:9b:9e:93:8d:9d:92:b2:ed:36:d5:e1:f1:e3:97:dc +-----BEGIN CERTIFICATE----- +MIII/TCCBOWgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx +EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE +CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x +IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB +FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz +MTgxMTQ1MTFaFw0zNjAzMTMxMTQ1MTFaMIGnMQswCQYDVQQGEwJVUzETMBEGA1UE +CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEOMAwGA1UE +CwwFVXNlcnMxKDAmBgNVBAMMH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5j +b20xLjAsBgkqhkiG9w0BCQEWH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5j +b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJB0Q6X/Y0XyeKem4v ++0Ufwz3dLENl8XopP0Imvf9PXZHAu3XjgRR9WXJ4lhpejZWT9F2SeQ4kd0+LCE5y +sZmIYwZ0stz3gmLp3W/lp7TJRAzkQ0H4V6kgsXDBdqFIW+lUtk8iUJOQ8GIyUJpu +Ims3oPcf/LFfruILiG3qKbYBJ7KE7xBNbArf6qmKgphgp1JzpPd8skq58JvE+Bla +wIRUUjXIkk8Wr9Y2pnhXVeVea2IA+kjCeucXOLUj1aj7fd9CXAP0fO//8aDm2CeT +BrOjIWgOxGAgAkYvK9iI5CsBwjFaVSi+VQPyBivk7Ehg5LbbofDFJLrhqOJq+wtA +bD31AgMBAAGjggIRMIICDTAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0 +dHA6Ly93d3cuc2FtYmEuZXhhbXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxl +LmNvbS1jcmwuY3JsMBEGCWCGSAGG+EIBAQQEAwIFoDALBgNVHQ8EBAMCBeAwTwYJ +YIZIAYb4QgENBEIWQFNtYXJ0IENhcmQgTG9naW4gQ2VydGlmaWNhdGUgZm9yIGFk +bWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5jb20wHQYDVR0OBBYEFHCG7Gi0UYoc +EmWgKrNDMxJlg41AMB8GA1UdIwQYMBaAFEaHhsLnGc8WTAxiy3N//Y8Z5LVCMFsG +A1UdEQRUMFKBH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5jb22gLwYKKwYB +BAGCNxQCA6AhDB9hZG1pbmlzdHJhdG9yQHNhbWJhLmV4YW1wbGUuY29tMDEGA1Ud +EgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0G +CWCGSAGG+EIBBARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMv +Q0Etc2FtYmEuZXhhbXBsZS5jb20tY3JsLmNybDAfBgNVHSUEGDAWBggrBgEFBQcD +AgYKKwYBBAGCNxQCAjANBgkqhkiG9w0BAQsFAAOCBAEAXbEQ+Dbdqf2NvjFTHc+1 +6jMahQ8TjcxnkUGX5OlnagzOpJoGs1O/5m3x0TJ9VF1qqJT+1PZihQ/gc/jOUTIY +ZVA0+fJm+Oz9lMIdKG/OPLMKCsyL+yzoRNLYZNcZHKQlX3VjvERWZMvKjEN1HpU2 +mKHGSeYUYK2Hka/YPNJjUoICCkLA43tQUTfVwKUMCawtoLMp5J6/098BggClrfs1 +6PYc18vRPFQf0nM4zqYK4ncK/OX/fmimx1f9x8+VSJ+Xb/4un+PWsKW1M58SweYS +FXczjx41tYj4a0eI5MtJ9xG6GTlVXkpaZXZ+zDqn+pGa77XBv/DnosafCBf8TKTv +C9jHpPl0NrNnkF6EJoO9NokNxowdA86PgMkMxsAe60Lnl38hrLFkBvYdbQyH/8kw +I9MhH1MFaSHVJsp/zjpOjdFAFn6iwA+VDGeQR9Liz4fv3DUYKqIhzWewshSfdZST +uoxNRXHL6d/N9ePw/8M4d8JBVdZglti9Xwkil0SNTbHdaDkEG3pXO8pWJ4cxVYRs +8GWv7AtShygLLVLAzqN9e0cH34pl6W/a57aUBmm4VT0RAca/C2EbzDBHq8/7cmLz +62YRzRyrTim/t3jWCezXZ1sXuTTMr17ZAgsz/KHyZDPErxFbCPevug1o18/SQC9W +IDTaghh8DnFhplhgADCmxyU6kHCgFOba2BLps2rEloVBgKZxF7XPT6ItUZP9JutE +PCqEatoYENZI444PyWkFloyW+XQGqxHS5OXXItsTk9b5JIRWfGpDqbgwMyykQp/s +9lYtRs/sJkle2lMha4wFDbcSJilDMrJs7QdHdSsLfl0oG1t7tWMTVU33o/b9LfVt +Q4NARrMN1iiZ1PuJ+0HGFTWl7hoIM7MLdQrQ/DHsd4Di8KsgzEMkZ0Kl1+awuYT9 +Q6Be2XgQl9PRt9kzcA9N8KGsItc2U2htOeAU3NfqHsKSG/gqmZcUdiyJP7eJx2lu +W92OR3rwDqTQGMbENPC4hDpu7h57hFjSEKaiDBSoVenFfquX5J218J8uNqwvczDI +sfy0zrQ5vVl1uCRasWfeND9OF13TvLtqarc+C+hNOwjW3qea141gVrs+bNCn+EWi +UqO1Hu9W3xRiUu02q8x6oZYUmuneSihovSEtYNUGiulets7htO1Wn5mH/iC71Y0N +ch1+iCecZtUmqjIKrWTeuBMtUcyL4vTBY6Zk6AMIQji/9P6zJQMbFLlogRS5Xblq +6/CpJEGOSQO+C1XPrHdo7VSuVUDdMcQ64teG1dXkXlvOntqhkFjhs3ymhxW9Ome5 +qyneT68ImIlFYo/bWy4r6Jc1ovxPz2N9VqBR3T+ykKaboJuek42dkrLtNtXh8eOX +3A== +-----END CERTIFICATE----- diff --git a/selftest/manage-ca/CA-samba.example.com/NewCerts/02.pem b/selftest/manage-ca/CA-samba.example.com/NewCerts/02.pem new file mode 100644 index 00000000000..4cc42aafc9c --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/NewCerts/02.pem @@ -0,0 +1,191 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com + Validity + Not Before: Mar 18 11:45:30 2016 GMT + Not After : Mar 13 11:45:30 2036 GMT + Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Domain Controllers, CN=plugindc.plugindom.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:aa:a3:74:2b:4b:6d:29:43:67:03:dc:c0:be:ce: + a6:e3:43:99:e5:87:34:34:42:70:4b:bb:50:87:6d: + e8:65:2b:5e:1a:b3:68:0d:9f:27:eb:dc:b8:84:bb: + 3d:f4:40:28:c0:c7:aa:e5:8d:a1:d5:7f:c7:6b:36: + 96:6b:3e:65:72:37:0e:d4:2c:03:4d:ee:e6:f8:41: + 5c:27:bf:32:53:6c:13:28:1f:be:78:9c:7c:80:53: + eb:4d:0a:19:1a:88:49:95:a9:c6:65:23:5b:3e:24: + 27:06:eb:7c:58:24:c6:e7:a4:d9:98:02:c4:ce:b3: + 1e:01:34:4c:bd:9c:28:da:10:4d:36:e9:7d:a8:68: + 04:75:18:eb:f0:58:94:05:b1:61:97:d5:9a:b3:db: + 09:71:74:90:05:87:d4:1c:ff:06:2b:c0:51:b6:26: + ca:28:8b:c2:08:3a:93:62:f8:69:b4:3b:c3:6d:9b: + 0f:80:1d:f8:c3:51:93:78:64:83:63:c7:d0:21:e8: + 05:cd:22:3e:3e:e2:c2:66:af:46:6c:c6:7d:d8:ed: + 53:b9:cc:42:e9:a2:43:94:31:f4:9e:45:fa:45:35: + ab:7f:32:93:95:a5:1b:4a:9d:27:c0:5f:bf:03:7f: + ca:37:c3:c2:c9:6f:b6:6e:5f:05:55:56:f5:2f:40: + c2:41:12:17:ee:23:1b:3a:9c:39:74:d5:cc:b1:47: + 6a:24:85:95:f5:aa:e6:35:40:0c:d3:8f:1e:d3:df: + b5:1b:7c:ff:3f:df:7e:7a:d3:f8:e1:92:b0:41:14: + f6:aa:1d:8c:36:3d:5c:c5:c5:b7:2f:b8:f8:09:47: + c2:51:58:de:80:41:c2:a5:18:c6:a9:16:39:d4:8e: + ef:f3:a9:c6:13:db:1e:f5:8a:e7:37:16:7c:df:28: + fe:19:44:7b:58:98:ee:72:fa:41:a2:f5:e0:77:c2: + 5e:fa:e1:94:87:96:17:66:75:07:45:c8:df:6a:40: + 19:3b:da:4d:48:e8:51:a3:1f:ba:41:62:0a:48:f5: + 62:42:9e:69:49:aa:ac:36:bd:6f:41:32:bb:62:8a: + 96:6b:01:aa:de:14:05:3a:43:e9:45:f2:00:9a:dc: + 71:20:b7:65:f2:f0:7d:b3:74:a0:43:1c:3f:5e:22: + 47:df:47:8d:5e:cb:93:1a:14:6e:b4:29:0f:af:1c: + 07:9c:11:74:24:38:09:23:76:0e:ca:fc:60:8f:1a: + e2:dc:d4:fd:fe:cb:12:f8:a7:83:c4:ae:db:a4:c7: + 74:b3:a5:76:90:93:9d:a3:78:01:97:e0:ec:09:78: + b9:98:ff:b7:2a:9d:05:03:5e:cf:b2:01:80:79:6b: + f9:5d:f5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + + Netscape Cert Type: + SSL Server + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + Netscape Comment: + Domain Controller Certificate plugindc.plugindom.samba.example.com + X509v3 Subject Key Identifier: + DB:4F:D4:70:C3:38:E6:26:37:6F:1B:50:5E:7D:E5:80:7D:B4:08:0D + X509v3 Authority Key Identifier: + keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42 + + X509v3 Subject Alternative Name: + DNS:plugindc.plugindom.samba.example.com, othername:<unsupported> + X509v3 Issuer Alternative Name: + email:ca-samba.example.com@samba.example.com + Netscape CA Revocation Url: + http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication, msKDC + Signature Algorithm: sha256WithRSAEncryption + ab:ed:44:9c:0d:f9:df:d6:8d:f2:98:05:cb:97:0c:14:9d:0c: + b3:2b:49:6c:4f:d6:8f:81:dd:c7:d9:67:be:ad:5b:f6:08:34: + 44:09:88:3a:9d:e9:fe:0b:91:89:f8:32:92:43:43:af:cf:04: + 5c:35:a4:d2:04:77:04:bf:37:45:57:2b:70:94:d0:7a:5f:b9: + d6:9c:47:ac:46:e4:4c:c2:87:5d:78:b7:3c:be:80:42:dc:3c: + 36:3b:c0:57:fb:ec:95:3a:bb:58:7e:09:ff:57:4e:4f:59:73: + 2a:65:0e:6e:a8:b3:8e:22:6b:40:0c:b5:5b:96:f3:a1:35:92: + 17:12:24:f3:43:fe:54:1d:ac:f9:f1:72:cb:97:b8:43:2f:e1: + ac:9c:a6:e7:78:98:38:ad:83:eb:c9:77:0b:ea:5a:21:6a:76: + f7:b2:4c:d7:7b:d4:57:eb:4c:a4:6e:be:eb:be:60:99:ae:ce: + 13:1c:6a:9f:58:e5:64:a2:b6:4e:2a:2e:62:99:d8:fa:af:11: + 5c:7e:51:d3:cf:7e:84:1c:f4:8b:a5:df:c8:b2:39:4c:c3:40: + 48:2e:b6:9d:3d:bf:b1:7b:58:39:f0:38:60:72:42:f4:8c:2a: + b3:66:c1:e9:12:bc:2a:51:75:55:1e:56:2a:bc:6e:40:1c:2b: + 16:25:90:97:18:4e:b4:63:dc:ff:7a:31:5e:b2:38:c4:17:65: + 3d:1a:31:47:04:75:3a:b7:83:c3:59:09:d5:99:56:45:4d:a0: + c8:6f:3e:87:61:17:4f:2e:7b:5c:34:76:45:e1:b5:bf:c4:fe: + 32:31:ff:2c:95:52:9c:12:2a:c3:b8:04:f9:25:a3:11:64:35: + c8:5d:92:f9:fc:2c:ba:45:18:d0:dc:95:1c:dd:30:16:3f:56: + a4:15:45:85:9b:52:55:3f:f6:a8:dd:54:53:d2:84:1b:d3:1a: + 97:61:8a:60:d6:fb:a1:75:f3:15:8f:b7:f3:f4:41:dc:7d:24: + 90:9a:62:23:a1:ef:c1:01:69:d4:a1:69:82:58:5f:35:b4:83: + b1:7c:cf:dc:f2:ca:23:af:5a:ac:e9:53:53:bd:33:8e:22:2a: + 1b:cf:ea:e7:e0:24:b2:f5:f7:ff:f6:99:6c:34:13:e9:f2:50: + 70:a1:0f:ec:f9:12:22:99:58:08:5d:f0:49:86:f8:14:3b:1b: + e6:49:eb:9b:fb:b1:07:60:e0:05:e6:4f:13:39:d1:ea:07:6b: + e8:85:33:eb:4f:b7:d3:7f:bd:9b:f4:a4:40:f4:a4:4a:f6:5f: + db:04:f5:f8:04:fa:1a:13:1b:cc:75:6f:c2:df:9d:89:12:5b: + f1:fa:cf:df:b6:32:3c:3c:5e:e0:26:9a:c7:e7:87:e7:5b:9a: + 76:b3:41:a3:0f:e1:f2:12:69:db:1b:32:57:a4:ad:5b:52:32: + 8d:7e:ec:34:c4:ce:d2:ee:6b:96:56:0e:ef:97:9a:26:a3:b5: + a0:4c:9a:e0:4f:9b:8d:07:df:92:46:1b:53:53:eb:96:62:74: + a8:13:03:e3:1f:13:0e:48:22:ca:ba:94:7f:86:80:c0:76:ab: + 08:36:e4:02:f3:ad:31:2f:97:00:06:57:09:12:66:d5:4e:8f: + 5b:88:67:7c:e3:0f:df:1c:97:17:85:9f:b9:08:4c:6e:88:e3: + e7:b9:53:06:87:98:e8:a3:9f:7c:7d:c9:07:d8:69:74:d1:e7: + c1:e6:46:e9:0f:2d:4f:04:6d:41:e8:b8:a7:87:d4:5b:1f:89: + e4:b1:c0:ba:78:2e:7d:cf:84:56:25:56:95:f7:93:dd:4a:47: + 88:b5:ac:d7:da:a7:b3:c9:8c:c5:41:34:8c:31:24:84:d4:51: + bb:46:4a:3c:db:72:e6:1b:c1:c2:15:6e:1a:ac:61:bd:ce:f1: + a3:ff:60:d9:a7:90:5a:3a:3e:1c:28:13:ed:cf:ef:ed:f1:fb: + 79:3a:57:ac:41:de:e6:17:d0:92:c6:fc:bd:6a:1c:e0:44:c7: + d7:ce:80:b4:c2:59:75:a8:bc:8b:32:4e:ea:2a:ff:89:fb:f9: + 98:6b:04:1a:fd:9e:2e:b9:bf:60:d5:84:80:f8:5b:03:0d:d9: + 1e:30:cf:4e:78:2c:a1:88:6d:ee:80:a2:ec:d9:96:00:c9:82: + a2:81:c0:6e:74:4b:69:9f:fd:c2:ed:0a:f7:31:a9:dc:89:f7: + c5:83:83:51:bf:f0:f6:8f:22:72:8e:f6:0b:54:d0:b8:7a:39: + 62:d1:d8:76:bd:c3:85:be:18:41:e9:42:c2:80:21:1c:86:20: + f9:4b:55:5f:e3:e1:6e:ae:ab:0a:4a:0c:05:1f:0d:b5:1f:a0: + d6:92:dd:20:71:56:74:e8:13:83:2f:4f:d0:72:98:b8:57:b5: + cc:06:63:3b:29:5b:f7:be:fc:e1:0e:24:94:da:1c:d1:ba:9f: + 7b:af:0d:d9:80:ed:18:85:74:73:62:2f:cb:37:e2:8c:85:90: + e9:86:dc:2b:78:b5:2a:47:fb:a1:41:f1:d4:2f:66:87:17:a5: + 24:20:54:61:99:03:72:56:5f:96:92:bf:25:4e:d0:20:a0:26: + 85:ac:b1:d2:7b:b9:b9:e9:9c:9d:01:52:a7:29:32:bd:94:65: + fb:bc:41:d2:9e:6c:59:c7:9a:b6:92:38:ba:fa:08:fc:1f:c7: + 72:9a:a3:a2:cb:02:e3:fc:29:20:20:b7:15:76:73:ab +-----BEGIN CERTIFICATE----- +MIIKDDCCBfSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx +EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE +CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x +IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB +FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz +MTgxMTQ1MzBaFw0zNjAzMTMxMTQ1MzBaMIHAMQswCQYDVQQGEwJVUzETMBEGA1UE +CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEbMBkGA1UE +CwwSRG9tYWluIENvbnRyb2xsZXJzMS0wKwYDVQQDDCRwbHVnaW5kYy5wbHVnaW5k +b20uc2FtYmEuZXhhbXBsZS5jb20xNTAzBgkqhkiG9w0BCQEWJmNhLXNhbWJhLmV4 +YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOC +Ag8AMIICCgKCAgEAqqN0K0ttKUNnA9zAvs6m40OZ5Yc0NEJwS7tQh23oZSteGrNo +DZ8n69y4hLs99EAowMeq5Y2h1X/HazaWaz5lcjcO1CwDTe7m+EFcJ78yU2wTKB++ +eJx8gFPrTQoZGohJlanGZSNbPiQnBut8WCTG56TZmALEzrMeATRMvZwo2hBNNul9 +qGgEdRjr8FiUBbFhl9Was9sJcXSQBYfUHP8GK8BRtibKKIvCCDqTYvhptDvDbZsP +gB34w1GTeGSDY8fQIegFzSI+PuLCZq9GbMZ92O1TucxC6aJDlDH0nkX6RTWrfzKT +laUbSp0nwF+/A3/KN8PCyW+2bl8FVVb1L0DCQRIX7iMbOpw5dNXMsUdqJIWV9arm +NUAM048e09+1G3z/P99+etP44ZKwQRT2qh2MNj1cxcW3L7j4CUfCUVjegEHCpRjG +qRY51I7v86nGE9se9YrnNxZ83yj+GUR7WJjucvpBovXgd8Je+uGUh5YXZnUHRcjf +akAZO9pNSOhRox+6QWIKSPViQp5pSaqsNr1vQTK7YoqWawGq3hQFOkPpRfIAmtxx +ILdl8vB9s3SgQxw/XiJH30eNXsuTGhRutCkPrxwHnBF0JDgJI3YOyvxgjxri3NT9 +/ssS+KeDxK7bpMd0s6V2kJOdo3gBl+DsCXi5mP+3Kp0FA17PsgGAeWv5XfUCAwEA +AaOCAgcwggIDMAkGA1UdEwQCMAAwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3 +dy5zYW1iYS5leGFtcGxlLmNvbS9jcmxzL0NBLXNhbWJhLmV4YW1wbGUuY29tLWNy +bC5jcmwwEQYJYIZIAYb4QgEBBAQDAgZAMAsGA1UdDwQEAwIF4DBRBglghkgBhvhC +AQ0ERBZCRG9tYWluIENvbnRyb2xsZXIgQ2VydGlmaWNhdGUgcGx1Z2luZGMucGx1 +Z2luZG9tLnNhbWJhLmV4YW1wbGUuY29tMB0GA1UdDgQWBBTbT9RwwzjmJjdvG1Be +feWAfbQIDTAfBgNVHSMEGDAWgBRGh4bC5xnPFkwMYstzf/2PGeS1QjBIBgNVHREE +QTA/giRwbHVnaW5kYy5wbHVnaW5kb20uc2FtYmEuZXhhbXBsZS5jb22gFwYJKwYB +BAGCNxkBoAoECAEjRWeJq83vMDEGA1UdEgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUu +Y29tQHNhbWJhLmV4YW1wbGUuY29tME0GCWCGSAGG+EIBBARAFj5odHRwOi8vd3d3 +LnNhbWJhLmV4YW1wbGUuY29tL2NybHMvQ0Etc2FtYmEuZXhhbXBsZS5jb20tY3Js +LmNybDAmBgNVHSUEHzAdBggrBgEFBQcDAgYIKwYBBQUHAwEGBysGAQUCAwUwDQYJ +KoZIhvcNAQELBQADggQBAKvtRJwN+d/WjfKYBcuXDBSdDLMrSWxP1o+B3cfZZ76t +W/YINEQJiDqd6f4LkYn4MpJDQ6/PBFw1pNIEdwS/N0VXK3CU0HpfudacR6xG5EzC +h114tzy+gELcPDY7wFf77JU6u1h+Cf9XTk9ZcyplDm6os44ia0AMtVuW86E1khcS +JPND/lQdrPnxcsuXuEMv4aycpud4mDitg+vJdwvqWiFqdveyTNd71FfrTKRuvuu+ +YJmuzhMcap9Y5WSitk4qLmKZ2PqvEVx+UdPPfoQc9Iul38iyOUzDQEgutp09v7F7 +WDnwOGByQvSMKrNmwekSvCpRdVUeViq8bkAcKxYlkJcYTrRj3P96MV6yOMQXZT0a +MUcEdTq3g8NZCdWZVkVNoMhvPodhF08ue1w0dkXhtb/E/jIx/yyVUpwSKsO4BPkl +oxFkNchdkvn8LLpFGNDclRzdMBY/VqQVRYWbUlU/9qjdVFPShBvTGpdhimDW+6F1 +8xWPt/P0Qdx9JJCaYiOh78EBadShaYJYXzW0g7F8z9zyyiOvWqzpU1O9M44iKhvP +6ufgJLL19//2mWw0E+nyUHChD+z5EiKZWAhd8EmG+BQ7G+ZJ65v7sQdg4AXmTxM5 +0eoHa+iFM+tPt9N/vZv0pED0pEr2X9sE9fgE+hoTG8x1b8LfnYkSW/H6z9+2Mjw8 +XuAmmsfnh+dbmnazQaMP4fISadsbMlekrVtSMo1+7DTEztLua5ZWDu+XmiajtaBM +muBPm40H35JGG1NT65ZidKgTA+MfEw5IIsq6lH+GgMB2qwg25ALzrTEvlwAGVwkS +ZtVOj1uIZ3zjD98clxeFn7kITG6I4+e5UwaHmOijn3x9yQfYaXTR58HmRukPLU8E +bUHouKeH1FsfieSxwLp4Ln3PhFYlVpX3k91KR4i1rNfap7PJjMVBNIwxJITUUbtG +SjzbcuYbwcIVbhqsYb3O8aP/YNmnkFo6PhwoE+3P7+3x+3k6V6xB3uYX0JLG/L1q +HOBEx9fOgLTCWXWovIsyTuoq/4n7+ZhrBBr9ni65v2DVhID4WwMN2R4wz054LKGI +be6AouzZlgDJgqKBwG50S2mf/cLtCvcxqdyJ98WDg1G/8PaPInKO9gtU0Lh6OWLR +2Ha9w4W+GEHpQsKAIRyGIPlLVV/j4W6uqwpKDAUfDbUfoNaS3SBxVnToE4MvT9By +mLhXtcwGYzspW/e+/OEOJJTaHNG6n3uvDdmA7RiFdHNiL8s34oyFkOmG3Ct4tSpH ++6FB8dQvZocXpSQgVGGZA3JWX5aSvyVO0CCgJoWssdJ7ubnpnJ0BUqcpMr2UZfu8 +QdKebFnHmraSOLr6CPwfx3Kao6LLAuP8KSAgtxV2c6s= +-----END CERTIFICATE----- diff --git a/selftest/manage-ca/CA-samba.example.com/NewCerts/03.pem b/selftest/manage-ca/CA-samba.example.com/NewCerts/03.pem new file mode 100644 index 00000000000..223d4072ce4 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/NewCerts/03.pem @@ -0,0 +1,170 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com + Validity + Not Before: Mar 18 11:46:04 2016 GMT + Not After : Mar 13 11:46:04 2036 GMT + Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Users, CN=administrator@plugindom.samba.example.com/emailAddress=administrator@plugindom.samba.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bc:1c:03:de:e6:1e:17:1a:85:5b:13:b8:a9:b1: + 26:36:b2:7c:4e:d2:8a:3f:20:37:ea:57:f6:46:38: + 9e:86:26:cd:73:cc:6d:a6:a1:4e:21:29:89:f0:7e: + 75:a5:8d:5f:92:42:9d:88:81:21:66:8c:2f:1b:f5: + 14:54:6b:ed:18:c9:a7:a6:a7:16:07:10:27:77:31: + d4:90:a5:cd:a2:9c:96:c0:18:92:76:f9:12:40:ec: + 51:54:12:36:ce:c5:02:fd:9e:b9:80:4c:81:e9:7e: + 5b:59:2d:4a:7c:0a:35:0c:0f:85:a0:b9:93:23:77: + 35:8b:de:18:e7:5d:3e:25:27:cc:0e:f0:0f:ab:40: + a5:08:02:84:f1:cf:9b:66:37:12:37:02:4c:03:43: + 04:d5:a9:ad:6e:d2:88:c4:85:fa:f3:9f:f2:5d:6d: + 1f:f4:54:a1:d7:4a:93:c5:42:e9:cb:da:ff:bd:70: + 8b:27:75:4d:77:b0:ea:97:f1:80:75:84:57:5e:1e: + e5:a5:d9:89:28:e8:44:a0:77:66:08:64:51:c0:4a: + d0:06:c7:b1:b4:1e:6b:0a:94:a0:61:5a:9e:7b:5b: + d6:48:ab:1e:7e:65:43:d9:e0:91:51:f5:2b:43:99: + a1:94:bb:7f:aa:2b:e9:54:69:c4:e3:f1:e0:38:77: + 9f:f9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + + Netscape Cert Type: + SSL Client, S/MIME + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + Netscape Comment: + Smart Card Login Certificate for administrator@plugindom.samba.example.com + X509v3 Subject Key Identifier: + 1D:D6:74:30:69:F7:2D:5F:81:E4:83:F1:7E:B0:08:F3:9C:06:41:E4 + X509v3 Authority Key Identifier: + keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42 + + X509v3 Subject Alternative Name: + email:administrator@plugindom.samba.example.com, othername:<unsupported> + X509v3 Issuer Alternative Name: + email:ca-samba.example.com@samba.example.com + Netscape CA Revocation Url: + http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + X509v3 Extended Key Usage: + TLS Web Client Authentication, scardLogin + Signature Algorithm: sha256WithRSAEncryption + 2c:23:ad:2f:a2:83:57:e8:42:b3:27:43:7f:aa:9d:99:ae:9d: + 20:7f:0a:b0:f4:32:33:ad:ee:fe:33:aa:20:09:8e:4b:4b:0d: + 12:b1:d5:0c:29:bc:13:aa:04:49:ce:2c:b7:01:e7:68:e9:ef: + 77:a9:dd:b6:9a:0a:11:bf:88:46:0c:09:7b:ac:6b:ed:6a:8e: + 72:fc:d8:28:46:21:48:8f:27:04:67:2c:17:2b:33:f7:8c:18: + ca:c6:3d:0e:76:36:fe:6b:03:77:eb:97:28:a9:64:4b:46:32: + 38:23:f5:6f:d9:43:b6:4e:c6:b5:14:0c:c5:09:0c:55:94:06: + 92:26:10:66:44:90:64:fa:e8:ae:75:43:a0:bd:14:9a:31:37: + 87:30:b7:61:87:65:40:b7:c1:2e:94:4c:0a:ed:4c:c2:75:2d: + 60:57:f9:b3:cf:b2:ef:19:c3:96:a6:25:d3:1d:92:16:9e:af: + e4:e4:ca:87:77:4b:13:31:48:de:99:1a:9c:ea:9a:27:96:bc: + 16:48:af:83:41:8c:56:d4:9c:6f:c5:9a:31:c9:35:3a:a5:c9: + cc:7f:9f:3d:c2:56:03:6b:df:b3:ac:c0:47:ce:53:5c:bd:38: + 7d:57:d4:c3:59:c9:b7:0a:89:ac:c2:15:a4:4d:50:84:67:91: + 59:6d:28:a1:78:0c:2e:20:39:06:9d:0c:2d:a7:c4:dc:98:eb: + 4f:b4:58:6d:6a:ba:b0:5a:e9:87:7f:c9:11:a5:7c:b7:91:49: + f5:0a:e7:f9:c9:7c:ba:30:3d:95:a7:8a:66:47:ed:49:53:74: + 85:e3:63:d5:38:34:76:e7:3e:2c:74:b6:58:23:5b:93:be:eb: + b2:98:9c:7e:bd:0e:5f:fa:98:4d:76:13:b7:5d:22:bc:76:5b: + 13:88:8d:84:8b:fc:a4:25:99:82:3b:1e:2e:58:2a:8f:d7:36: + ec:fb:d6:1e:76:b8:0a:31:fa:56:18:38:96:d5:0e:d7:dd:ac: + 70:a6:c1:80:0e:9c:9b:44:e7:e8:b6:8a:64:8d:7c:9c:57:6a: + 90:ce:2b:c1:c6:da:f5:68:1d:c4:37:58:70:f7:ba:3d:4f:2e: + 6c:a6:a2:3b:12:1e:1c:ea:99:bb:ac:54:57:18:c0:d3:7f:8a: + c8:7e:73:8e:b1:06:6b:55:57:e3:4f:46:9e:db:50:55:1d:c9: + 61:99:de:31:79:75:bc:b1:d6:fe:17:b2:fd:cb:36:3a:12:6b: + 0f:c8:b0:a6:be:e1:a4:de:5b:76:02:bc:e4:9b:f9:df:e1:ed: + bb:dc:40:62:1b:05:34:c0:53:10:47:ac:c7:18:6e:7c:17:37: + 86:f3:84:91:17:00:f3:69:45:3f:fe:fe:3c:c6:b2:13:82:70: + fa:fc:1b:51:d0:56:19:b0:9e:9f:1d:27:75:27:81:f1:85:b2: + 15:7f:ac:f1:8d:de:fe:3a:57:0f:13:4f:d8:7c:9d:f3:49:a2: + fe:5a:e8:91:8c:38:c2:4b:9a:f3:49:0c:92:70:62:8e:ed:91: + 8a:3e:da:ab:96:d6:46:5f:25:e6:82:cd:29:03:20:83:3b:63: + c2:5b:34:92:12:98:13:b4:56:2d:1d:cf:4b:22:f8:40:fb:7f: + ae:3e:49:52:54:de:02:95:0a:f2:22:6f:e1:2c:bd:a4:08:8d: + ec:83:79:4a:a8:ee:27:0e:b8:6a:65:4f:ba:be:8a:94:02:ad: + ef:72:3e:07:52:52:51:58:6c:e7:20:e4:81:49:da:7f:f1:dd: + ea:2b:56:f4:29:75:16:df:b8:19:da:63:b2:a0:d3:93:5d:a6: + 81:f4:2d:d3:fb:cb:7c:e3:04:8e:38:9d:66:9d:29:57:28:22: + e3:7a:5b:48:cf:6e:79:32:24:6e:e4:dc:7a:05:22:2c:a4:0e: + 30:74:41:cd:34:ef:3d:33:4e:01:3e:65:25:01:cc:5d:73:5a: + 10:d6:df:45:24:93:69:fa:d3:ab:7f:c8:b7:5a:86:1c:88:be: + 32:05:2f:f8:2a:26:02:f5:cc:30:4a:dd:97:0a:3a:db:c0:0c: + 67:36:90:9b:f9:2c:e3:d0:04:26:46:c1:a3:4e:a0:46:be:f3: + 8b:91:9c:d5:f0:32:09:c5:f0:a3:51:bf:05:70:83:51:25:ba: + 6f:8c:25:ea:30:96:52:e6:53:64:38:ac:0e:de:54:e7:5f:da: + 30:e0:39:9b:d8:64:d5:3b:70:4f:9a:27:96:36:98:9b:f5:07: + 0b:4a:89:40:06:18:9d:6d:e2:6c:40:51:af:83:66:73:87:56: + 5c:fa:38:96:a8:dd:4a:28:4a:82:d2:09:0f:e4:77:db:09:ff: + 50:34:c9:dc:0e:27:fe:94:1d:65:71:56:59:19:1d:62:a2:1a: + 93:bc:25:7b:be:6e:06:2a:e6:ce:ef:fa:cf:30:a2:e6:ce:26: + 28:e5:eb:6e:03:64:3c:8f:65:ce:32:33:08:ab:dc:45:69:78: + 4e:d3:b5:87:4f:03:48:e0:c3:24:48:cf:74:79:62:1e:b1:e0: + 39:12:02:08:db:fe:f8:78:a7:43:7f:e1:e8:86:b4:04:3c:e1: + fe:26:71:75:9d:32:4c:3a:ad:84:cb:e6:be:f5:7f:20:9d:04: + 4f:ba:41:d1:78:4d:f7:3a:93:89:ef:a4:4e:b4:83:4c:92:70: + 39:1d:21:de:c8:4c:9b:5d:26:55:1b:ad:93:48:79:19 +-----BEGIN CERTIFICATE----- +MIIJLzCCBRegAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx +EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE +CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x +IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB +FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz +MTgxMTQ2MDRaFw0zNjAzMTMxMTQ2MDRaMIG7MQswCQYDVQQGEwJVUzETMBEGA1UE +CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEOMAwGA1UE +CwwFVXNlcnMxMjAwBgNVBAMMKWFkbWluaXN0cmF0b3JAcGx1Z2luZG9tLnNhbWJh +LmV4YW1wbGUuY29tMTgwNgYJKoZIhvcNAQkBFilhZG1pbmlzdHJhdG9yQHBsdWdp +bmRvbS5zYW1iYS5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALwcA97mHhcahVsTuKmxJjayfE7Sij8gN+pX9kY4noYmzXPMbaahTiEp +ifB+daWNX5JCnYiBIWaMLxv1FFRr7RjJp6anFgcQJ3cx1JClzaKclsAYknb5EkDs +UVQSNs7FAv2euYBMgel+W1ktSnwKNQwPhaC5kyN3NYveGOddPiUnzA7wD6tApQgC +hPHPm2Y3EjcCTANDBNWprW7SiMSF+vOf8l1tH/RUoddKk8VC6cva/71wiyd1TXew +6pfxgHWEV14e5aXZiSjoRKB3ZghkUcBK0AbHsbQeawqUoGFanntb1kirHn5lQ9ng +kVH1K0OZoZS7f6or6VRpxOPx4Dh3n/kCAwEAAaOCAi8wggIrMAkGA1UdEwQCMAAw +TwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3dy5zYW1iYS5leGFtcGxlLmNvbS9j +cmxzL0NBLXNhbWJhLmV4YW1wbGUuY29tLWNybC5jcmwwEQYJYIZIAYb4QgEBBAQD +AgWgMAsGA1UdDwQEAwIF4DBZBglghkgBhvhCAQ0ETBZKU21hcnQgQ2FyZCBMb2dp +biBDZXJ0aWZpY2F0ZSBmb3IgYWRtaW5pc3RyYXRvckBwbHVnaW5kb20uc2FtYmEu +ZXhhbXBsZS5jb20wHQYDVR0OBBYEFB3WdDBp9y1fgeSD8X6wCPOcBkHkMB8GA1Ud +IwQYMBaAFEaHhsLnGc8WTAxiy3N//Y8Z5LVCMG8GA1UdEQRoMGaBKWFkbWluaXN0 +cmF0b3JAcGx1Z2luZG9tLnNhbWJhLmV4YW1wbGUuY29toDkGCisGAQQBgjcUAgOg +KwwpYWRtaW5pc3RyYXRvckBwbHVnaW5kb20uc2FtYmEuZXhhbXBsZS5jb20wMQYD +VR0SBCowKIEmY2Etc2FtYmEuZXhhbXBsZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20w +TQYJYIZIAYb4QgEEBEAWPmh0dHA6Ly93d3cuc2FtYmEuZXhhbXBsZS5jb20vY3Js +cy9DQS1zYW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMB8GA1UdJQQYMBYGCCsGAQUF +BwMCBgorBgEEAYI3FAICMA0GCSqGSIb3DQEBCwUAA4IEAQAsI60vooNX6EKzJ0N/ +qp2Zrp0gfwqw9DIzre7+M6ogCY5LSw0SsdUMKbwTqgRJziy3Aedo6e93qd22mgoR +v4hGDAl7rGvtao5y/NgoRiFIjycEZywXKzP3jBjKxj0Odjb+awN365coqWRLRjI4 +I/Vv2UO2Tsa1FAzFCQxVlAaSJhBmRJBk+uiudUOgvRSaMTeHMLdhh2VAt8EulEwK +7UzCdS1gV/mzz7LvGcOWpiXTHZIWnq/k5MqHd0sTMUjemRqc6ponlrwWSK+DQYxW +1JxvxZoxyTU6pcnMf589wlYDa9+zrMBHzlNcvTh9V9TDWcm3ComswhWkTVCEZ5FZ +bSiheAwuIDkGnQwtp8TcmOtPtFhtarqwWumHf8kRpXy3kUn1Cuf5yXy6MD2Vp4pm +R+1JU3SF42PVODR25z4sdLZYI1uTvuuymJx+vQ5f+phNdhO3XSK8dlsTiI2Ei/yk +JZmCOx4uWCqP1zbs+9YedrgKMfpWGDiW1Q7X3axwpsGADpybROfotopkjXycV2qQ +zivBxtr1aB3EN1hw97o9Ty5spqI7Eh4c6pm7rFRXGMDTf4rIfnOOsQZrVVfjT0ae +21BVHclhmd4xeXW8sdb+F7L9yzY6EmsPyLCmvuGk3lt2Arzkm/nf4e273EBiGwU0 +wFMQR6zHGG58FzeG84SRFwDzaUU//v48xrITgnD6/BtR0FYZsJ6fHSd1J4HxhbIV +f6zxjd7+OlcPE0/YfJ3zSaL+WuiRjDjCS5rzSQyScGKO7ZGKPtqrltZGXyXmgs0p +AyCDO2PCWzSSEpgTtFYtHc9LIvhA+3+uPklSVN4ClQryIm/hLL2kCI3sg3lKqO4n +DrhqZU+6voqUAq3vcj4HUlJRWGznIOSBSdp/8d3qK1b0KXUW37gZ2mOyoNOTXaaB +9C3T+8t84wSOOJ1mnSlXKCLjeltIz255MiRu5Nx6BSIspA4wdEHNNO89M04BPmUl +Acxdc1oQ1t9FJJNp+tOrf8i3WoYciL4yBS/4KiYC9cwwSt2XCjrbwAxnNpCb+Szj +0AQmRsGjTqBGvvOLkZzV8DIJxfCjUb8FcINRJbpvjCXqMJZS5lNkOKwO3lTnX9ow +4Dmb2GTVO3BPmieWNpib9QcLSolABhidbeJsQFGvg2Zzh1Zc+jiWqN1KKEqC0gkP +5HfbCf9QNMncDif+lB1lcVZZGR1iohqTvCV7vm4GKubO7/rPMKLmziYo5etuA2Q8 +j2XOMjMIq9xFaXhO07WHTwNI4MMkSM90eWIeseA5EgII2/74eKdDf+HohrQEPOH+ +JnF1nTJMOq2Ey+a+9X8gnQRPukHReE33OpOJ76ROtINMknA5HSHeyEybXSZVG62T +SHkZ +-----END CERTIFICATE----- diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt new file mode 100644 index 00000000000..8a0f05e166a --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt @@ -0,0 +1 @@ +01 diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt.old b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt.old new file mode 100644 index 00000000000..4daddb72ffc --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt.old @@ -0,0 +1 @@ +00 diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt new file mode 100644 index 00000000000..27e6ac3ff60 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt @@ -0,0 +1,4 @@ +V 360313114451Z 00 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Domain Controllers/CN=localdc.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com +V 360313114511Z 01 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Users/CN=administrator@samba.example.com/emailAddress=administrator@samba.example.com +V 360313114530Z 02 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Domain Controllers/CN=plugindc.plugindom.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com +V 360313114604Z 03 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Users/CN=administrator@plugindom.samba.example.com/emailAddress=administrator@plugindom.samba.example.com diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr new file mode 100644 index 00000000000..8f7e63a3475 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr @@ -0,0 +1 @@ +unique_subject = yes diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr.old b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr.old new file mode 100644 index 00000000000..8f7e63a3475 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr.old @@ -0,0 +1 @@ +unique_subject = yes diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.old b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.old new file mode 100644 index 00000000000..04d6e6beabc --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.old @@ -0,0 +1,3 @@ +V 360313114451Z 00 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Domain Controllers/CN=localdc.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com +V 360313114511Z 01 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Users/CN=administrator@samba.example.com/emailAddress=administrator@samba.example.com +V 360313114530Z 02 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Domain Controllers/CN=plugindc.plugindom.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-openssl.cnf new file mode 100644 index 00000000000..17a55717f06 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-openssl.cnf @@ -0,0 +1,203 @@ +# +# Based on the OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +#CRLDISTPT = [CRL Distribution Point; e.g., http://crl-list.base/w4edom-l4.base.crl] +CRLDISTPT = http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + +# Extra OBJECT IDENTIFIER info: +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] +# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used as a login credential +scardLogin=1.3.6.1.4.1.311.20.2.2 +# Used in a smart card login certificate's subject alternative name +msUPN=1.3.6.1.4.1.311.20.2.3 +# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used to identify a domain controller +msKDC=1.3.6.1.5.2.3.5 +# Identifies the AD GUID +msADGUID=1.3.6.1.4.1.311.25.1 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = CA-samba.example.com # Where everything is kept +certs = $dir/_none_certs # Where the issued certs are kept +crl_dir = $dir/_none_crl # Where the issued crl are kept +database = $dir/Private/CA-samba.example.com-index.txt # database index file. +unique_subject = yes # Set to 'no' to allow creation of + # several certificates with same subject. +new_certs_dir = $dir/NewCerts # default place for new certs. + +certificate = $dir/Public/CA-samba.example.com-cert.pem # The CA certificate +serial = $dir/Private/CA-samba.example.com-serial.txt # The current serial number +crlnumber = $dir/Private/CA-samba.example.com-crlnumber.txt # the current crl number + # must be commented out to leave a V1 CRL + +#crl = $dir/Public/CA-samba.example.com-crl.pem # The current CRL +crl = $dir/Public/CA-samba.example.com-crl.crl # The current CRL +private_key = $dir/Private/CA-samba.example.com-private-key.pem # The private key +RANDFILE = $dir/Private/CA-samba.example.com.rand # private random number file + +#x509_extensions = # The extensions to add to the cert +x509_extensions = template_x509_extensions + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +crl_extensions = crl_ext + +default_days = 1 # how long to certify for +default_crl_days= 7300 # how long before next CRL +default_md = sha256 # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = match +stateOrProvinceName = match +localityName = match +organizationName = match +organizationalUnitName = match +commonName = supplied +emailAddress = supplied + +#################################################################### +[ req ] +default_bits = 8192 +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extensions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = US +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = SambaState + +localityName = Locality Name (eg, city) +localityName_default = SambaCity + +organizationName = Organization Name (eg, company) +organizationName_default = SambaSelfTesting + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = CA Administration + +commonName = Common Name (eg, YOUR name) +commonName_default = CA of samba.example.com +commonName_max = 64 + +emailAddress = Email Address +emailAddress_default = ca-samba.example.com@samba.example.com +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +#challengePassword = A challenge password +#challengePassword_min = 4 +#challengePassword_max = 20 +# +#unstructuredName = An optional company name + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] +# Extensions for a typical CA +# PKIX recommendation. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. +keyUsage = cRLSign, keyCertSign + +crlDistributionPoints=URI:$CRLDISTPT + +# Some might want this also +nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +subjectAltName=email:copy +# Copy issuer details +issuerAltName=issuer:copy + +[ crl_ext ] +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ template_x509_extensions ] + diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-private-key.pem new file mode 100644 index 00000000000..852b53d9c78 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-private-key.pem @@ -0,0 +1,102 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIISjjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI8K/V4PKOJq0CAggA +MBQGCCqGSIb3DQMHBAj0N1BCFJkjIQSCEki8nJ5Sf4sV5cwTX0t2wqkXcZkP0L8f +wc/F/B9+EmqsJiTpH6wnH1ztcEqTBVfOsln6TYeF9oUgQrEZgYDQE4Hwxq7QKreK +vOvJlSX5Grk727s32msLjqiH+ccQOFiFme8SiTJqfCeyJyYOWoBMwmney3Ao7+Ab +1CtJtw6zOHKOeiBM6gNu9hM362ESUSPPiwgfx90koHuilOy3vxHPuGSWtaCt1cGB +Vuvp/rPY04vUgs4lSXacWB61Jy0qnFu0dGmzeBRP5P4TGzvdAOJY54lAwNxaEZg6 +okVQ32JdNxze708N+uObWE9LYgQpMriEww8f/anKE9yMRD+K8cvMkvMph4qRJuVj +W9OKJxOpfnRopbVYbh0O+gK3zA9RWQmfvrZ7O30sGqbKQhZWneU1Pa8WfEflfrBs +TDLQdJ7J9Jdar41faSFDg4jSzqhk8FGtSP7hkmJRII4ltPoXjHUEmpSeGsOtT9Ey +25QcVcizyHl0ckJ0efib6pUWmhpOF05uf/RTTY7seBv+NY0XPFpMtH5PS6p0dNTt +bg+MgJqewwfWCcv577MMAdyXHV7aOTUJ+g4V6YME/20tL6sMyQafMfWq4yLMHtmL +MC/RU8hKnTHT0uh2QHkxFiUWZL7yLwKgXKRU3y00dDJ3QvwnrOdVSXod//H64dyZ +BYwc/st24DswlAs/xclapNzKm2BjRJxsaeGuEmUpSOQn4iV6r54CEwEgcNB6rKMT +mYefJ2pKlswCDtZz744LeVqYFb/Tp6bV1Jq3of90GgIf53Ziq5eWILuubWw9ZMJ5 +2ex6A2Lb/+GiXaKdITeJmUvxme6ZxH6efvGE2yciTLki0oPDmPFywcsdJK/FzVNv +F3gOqD558Oo/uUf2aw/VwUZeFIA465RQbIEXj06F1KnA3JwMlRNJy2Jz10sLcyJR +vVykjjRZVb36coOrnMt/rGpiXXci77a2hUX/nNrEXL8A2wobS2kGVOPz4klD0Rfh +/B4kqa3pnPXjUKn0xNe3CHwOd/qOPgzlUYkGDZP+GnuMpaFWfz4tWmLaOElKnWwi +MbzDAt6Fh+nddHMusxtQv/iyADq5CC7XcZsFfnQQBR9yyrdoMwJxiEbF1oyB2LvS +iQqWxtoT6Y2PjfBS+zmbLEVQfwxL0UiQ/TrdgWumsIVi02AlEvyj4aIhc52aSevk +M5rWkKqrJqec9bLeXYlIpS57VYwxd+8FZjkxM/bIrGh7Bas7t1BQ3anh7+t7H6xr +XU8rwuGDtw0LawkGUC+0OgcmM+45WQdR1LtTP2xrwH1MdIoX0BrVtqW4ZpOBjjyD +UpG1bv/CGQwRXtZ/pVrWMfohYZOiNqyyiTEgmHjCuoon161mLRnRb6vVKp6eRUH4 +GMW8UM/k1spF/zMUfkuymdyFwkGrdhuDuaiaW3A3sgECqSKY4p4VXa1Awm8v2t0J +tHTuOAlbuhgtZXE6P1dtas+sc2WbsKC6X6ul+dhzvaBJo31Dz16ly74h+U/UUS9u +iS6p+UMCdg33R96AITJJ83RNQBIFG6sEZDTEy9fvH31uBVbeuW5GOhT5cMBf9b24 +o9B/gl5CVEmEAdwQ8BY6W7Ujk/GN7q44kmATT8C0zW5vJIbK1SRrYyfhiPjN+uv1 +bVrQDajrmP94MdpPB1YW1q0fZwRsz4836SN0uMSvC++rHzqgT9nhcJM7eHbvXtkY +u/57OnCTNtSIxzgcnS8TfMJTrHF/f4o/RuBbVBMFZFWHUIN4+OKwf7qzmNYHleMR +WN+2nTxACLL58RPOzCrQWLsbPFdOE81XSTQjp9YXF7H1MeMVaUhkXZDHShk8SOMX +oewF6ZvcM6sxgdYz8Ib/5dBDOLxBESc8ctvBgbmDGRopwTdCfDY9+TwZUE4n9Lj3 +EkcNh4282btr1MosBnH/udb5QZhlsXQCwrpvdxNTEsmpLpV5t390B+3Rt6wMxTLG +j4nNQuK2rj9D3to+S4wyfmg3QOmiUMrVCuW3anmoEcwlHsQN+BSkCF1PleGklCET +DI4DuQdv5CTg61nN8zIIqqVtCAXiSHX/FM4KAQHD1oLEozoOiS3AH6mx6cJ9rEP6 +iWylQzI2Ppv7hYTKpheboVlL8UsMbr982rUXeIUsGqvM2dSEuX8EjKQKqfDmo+1C +AA1puZvpGsVgvgEb9cDgklBKFOHRUhV3KP4oe7Zx4SsyTIuNYBG1U1ykIPiTLpQd +jzu/PwO94AIMiqF3NwEfOU+NBdG3cADdIau2cJucQTzfvBgQz0YkcnQq8dTTUaf/ +P76bviKsNqzy3fawbRziHkPk6VBsNwOkOSz9T9TYrmFlOSC9hJp/7k92TUy6vPxM +UbsUEZmS2dwmSjtGzjLyTv9yF50qHq5u03LpaKU5IHZHHoi2RnDvwblhtZlm8w9s +mRrbXiZkYAXg2BKDS7rTWIR3RBptG2iYPuQaUQ4XgMFvDIsGmEgm29GJOpLmIKy2 +NXBL2hRgmDGvUkMdRTKMm2sh+/ml6iW58kXgXyeIp/Z450zq2q2oa2Vd+LCoM+2a +zEa6ykn6gRIMFIu7VbGNtYrVDixZLqsqGDZc8O1Ob/fGzMiNL8cM+N9GCLRmIV+E +EqhwyrmF2gKj3mP1D4y1hdcgJvQpYdaPdpTe8cUaDpYtptl/TwS7s9YWjFnPXzfs +hU4TquWDthGpuIT4D3N6rd3gWHb8wmT67FEjYt7pC8IIkquIaerlkLN5Z5bX+MhH +1yiZBTmJ7vx+EWG5UMDW4khYNR5ggH1kN3pYbmwQW84GIAiJ6GJcp658QIT8/WKv +H3kHl+3m5Oduncy6HpuN37Fbzbak0AAevOPtjwTHTyyb7dgbMzp7Z3yApZ9h4ENz +0tk+2bRG0TPsBBmHYyGx66r9s23yQV+7ewmBY07Z2YkJGJ1ezzwYypseQIFWWxY8 +zmuehkT2sXycF89zGoVWL1Bcrpdg5Bi20rUOtKlkFWzcVNdOXdbcMu8u5RVxeLEj +ftBInNO8gY9tjvzPKMv7KOj3RE6sPNiVZS/UIicAIEuvgt3Pu8WooG7y32hBE66H +vITJWK+RvDN6BPfmFMQAAUXLpBTsqkmferPWrgxSd2T3cgbjS5JvAquxt0Mad3TH +ERPHOoDi62x4jX7UiElNQUGArcVw7MNuo2txkRvCnb8GZK8JiWcBVzuka8Fs1JBe +kw6tqoauNM+uNRaVgY7o1NPfW3uA53B5N2OHl+t5jmXi+llTmQz5VXE+UiCacxE8 +Vlhtos6w3E7CfCXDfwlvaZHniPM4PZic/jpDZEE+XBWvtcXkgstG3Ufs9MpCIqCj +ktjiiVBNE+QLaCpw7sNZGq1QOxmdMw97/HRwVGWtzvx63B7a44JBfnVbPAp2e30k +vTPI2v/4b0+7AvKMnnON7VZHmifngEr6Ok+m7+O1yn2KyigOANPPdzTkGV69tv9c +XoIkvCXYXDrEpi0n7z4SSze09qAZ12jDAOY+H+/ag1nOar/bP68WSISL1uE3wYWX +kbdp3xdES5BPXZK/EldVGlHvvqwYBKHI9XmG361+/b/mxLVIcfBwtiiFIaJvnRcc +pzefHJo01aW34//OYGs1lc7s39Ox2094Xj4uqorNBu4f3hKna5cnzBLqDK/zZUA+ +RV4CutR/OZTw30xv2ho7FKb7uHg7o3jk2cRQgBy3ep2DwxhBZ1HrtozDOLZs2nFL +9/+GdKahJS+ZOmfSOVKUpyWw2OtlnGYIp3NxsWdGtrK8/aLrFgY9wOHJ7A19Lb2Z +wTMn+wqrGv7rp4TBdND5eAj5+P+1027GHn20fHtF3yqDsIjwd9Qaoh6JRnB7f0KS +cQI7X3J7uv6uRT9uNdxk8BV9cliz0OHIvxPdov43QSRetpVMZez1nDwJRx2hkh1X +tl+qLG9tZvB69Wwh+bFQ5vwtH9YJHHBlg8rdCFMj4IHY1dEPvzpmvd0xxj7lVX1/ +CzN232aaYblfn2SCFUbsnxhAMrb762FIp37VOXw8Uu1ylF0hput46oJhqeheI95X +0/eLTjE5ZYPYXD6tiGx5JC2R3jSUZ9JDC50YFOYEALyagBc1vzcmMUxbi8SHEGd8 +sgCpWVmCcZfWA6yJRTiuip7pDkXW8E1sm63moYsSZ9DdNboYM500z7Swm6TsOejf +2m8axEhXJorasZKMw6nLUEO6fyMbbp6ZZRjRd0dBjEdCF9oPKhK5vx+A9e8eiwJ1 +io15AMh94DOVUBtZpMl/oLurGsPyMzbPY3D9FtACDQ5fZ/T1gM3CBQj0YhaoZ8vK +Zj1F/CdQMhm4GoTaFeZAjOLQb03h7PuDYDBGMk43SIt2ogCYfmQWWQy3TfHZqcFV +IdT3eYMi/j9cmCrxBJwoftBYVg+qPtGyRisD+CPVJKVGA6Q6T2Fcr5AQdzwtvFjj +7OTEPEo9cDvS+Y7sTKHULBmHAZAAYQr2CsNZ1G9e0xXvp3+++S4EZ/Xp2xE1iImX +Uup72cVMZPcm9s7s6u/rS0pEtgf20US7Ct9B77Govevcp5xeNVQHQFehF6Ksd4b0 +dnQCfNZ5bCBjC2D9S2rnPL+N5mkKSMwk+zFjc7owno/INs7za/TGU7wosnS4+nuT +6J1ya0RrTjPU6eh453R5QKfYof8C1qpHvAhNhLqI/dJK5XSDeBVEcdCj+pEekTC4 +3fFJ2ZNxXIoE7Folwc/VAmlI1lsq/ZimNwL2UQ/Yh06dxm1G9W98F+8m1vNdwudG +moMbwmrPLnnxTwAOhAQkdtpYKKaiXkH9xkJXNRew/Jaer3YvPF87yyu78eU83ZP/ +3ua/5Aq6L+6FK78nfGfv1FhtYCdsMNZv/xGQS6LVAdOON5A4+0C8A97mAQUYen2F +34j5TY9iuqeLvXFxSZ/s+hafuRbN682PQ3Mdrd7CINjQmtGHSLoRp+6gTQ844bl4 +kaJhsawxBE8rE63I58w0E715u/o/460N1bYaLBY4n2wbv3pDRVNtJcJRSOeLUSZJ +2slbE8Ok7jmAexFNlj/cjFwcdMPSjk5J5hVXhRiQgbpVVEpvUPgGuULwXpfot6o5 +uREHPjf/PP9Oneny69Eoijtee8f9SIYEkLsiMpUrdm+3JXc8ohI8DqjmDsr+YUUl +yJJ5yXyUQjG3YZU5S+3lH0G9VQsIPpIUuqOtllOPLZjZe+7g35GUASeh3TLoO2l7 +Jeub0I5apqXwNSf/Xw+fIbiunMKGGOFotKCYDn7w6HT2HLsFFGu2NJigeBzBsl2N +Ngms0Ur1r+8EUsmIP2Fox02saKbCyiaTvpMUMTrXPsZ1L83galem8QWr6AiHCk06 +heOu0leO77baMA8hgPjpY1RnVYl4/ZX+fTGkq1rNAmNHt7x46FQEK/yuFtMt1sNh +DgA+HJpNLh8FTDesiIymfaesoXk79FSD7amsPfT4oNzjo1aqsrQ6qteKD0XqLjOA +juvUF3O/MhD2frSDT6yHs8Pd5aPDb7DwX8gRaQ68kFwyUXPijpU9rFAylIT15WNb +xXfwYgq1g5V0eqtEVlLisQj70wRJOADYCRAAcEUYiaf86pN6SUxH3a48XrqZqcVi +vPteMicbitpcJjmVHAKiKlwqwmFmnwzb57J2xYijG9Y2TKE9HBCDkaKIx3BUQRdq +VcZJ+wm7rBtScBXhECkyzFbJVOLCSYX/ziKf33BBZKhRY6cCr0UuH1G5nj8wxiin +fod7Go8slrBS0pnPRWczxH3LqbvpRBA1lfTaKNyBSAjDuVJF5QifiIjRqk5AziCU +Bk3F3pVIoA72OnXlmdDa2HkG85iH9NyiWEfOkou5goAuQvILu94cX0+gw3bGYNPc +Uc+LprTR5cXT2aA5D7uRMMWJ+Znrw3/4pnKtVmRGkbMsuFej/gKXvl+UCmYkywXa +RyE1BeThrRgA4/QeU9x2aqCnZyTmszFW43PtzzZqfks48qpBxYq47NbrfLV5w9av +1XzVj8NIechjFlB/KUIY6jylY+fAdx8Za8I/RyCFWwlhsDQ4Ef3aWtumlevYu0d6 +1Z63Of+ySvOdlvsoV2fOHAJGa2aeAh+ibXe8h8myNOrzVDx4blParf0F28ikaVOj +IzH8Rk/UEsCElY+Cb/KVPoPtk1zxtFhAElqq18LGrRbQBT7Ntd/FYf84POZ5ItKu +B1z8hmq2EIb0FUKV7Hx4coFE6cb8y1NcMs5T0z09nfCiDZJl5Vr0NR6bWDRBWm3L +seXEEGHblpFl4UTVMZ3szBHGveDSoKujIiqbHC8o4GshhmQBhyIhw0lnxmh40FPk +R1Y= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt new file mode 100644 index 00000000000..64969239d5f --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt @@ -0,0 +1 @@ +04 diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt.old b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt.old new file mode 100644 index 00000000000..75016ea3625 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt.old @@ -0,0 +1 @@ +03 diff --git a/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-cert.pem new file mode 100644 index 00000000000..2b3d7fb1487 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-cert.pem @@ -0,0 +1,62 @@ +-----BEGIN CERTIFICATE----- +MIILPDCCBySgAwIBAgIJAMjuQLBy0LOvMA0GCSqGSIb3DQEBCwUAMIHGMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKU2FtYmFTdGF0ZTESMBAGA1UEBwwJU2FtYmFDaXR5 +MRkwFwYDVQQKDBBTYW1iYVNlbGZUZXN0aW5nMRowGAYDVQQLDBFDQSBBZG1pbmlz +dHJhdGlvbjEgMB4GA1UEAwwXQ0Egb2Ygc2FtYmEuZXhhbXBsZS5jb20xNTAzBgkq +hkiG9w0BCQEWJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29t +MB4XDTE2MDMxODExNDQzNVoXDTM2MDMxMzExNDQzNVowgcYxCzAJBgNVBAYTAlVT +MRMwEQYDVQQIDApTYW1iYVN0YXRlMRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNV +BAoMEFNhbWJhU2VsZlRlc3RpbmcxGjAYBgNVBAsMEUNBIEFkbWluaXN0cmF0aW9u +MSAwHgYDVQQDDBdDQSBvZiBzYW1iYS5leGFtcGxlLmNvbTE1MDMGCSqGSIb3DQEJ +ARYmY2Etc2FtYmEuZXhhbXBsZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20wggQiMA0G +CSqGSIb3DQEBAQUAA4IEDwAwggQKAoIEAQDRaY4kvh518y/goY9ZM+e7Z2ihJ0fB +dC7vMPyl+5GjcatbL4pqe/FQWDPVKZrTQzLEjDjoTjfFIaZDE8WGeShDS1Z0vaNf +u4NPCPyTwYpzH76E5a/gvQVt6c0tJC74pD3Z2u7JdCEkL5ywv/RggMPqVz4SmHZn +Ul53Y+/GgNoqb3Cbd2IAbD8QxNgbwKoYbP2+31DZALlL3pR4yUYSvf7OxPuY4nRY +npYpr/C77Zi5nx5nSmplYN15ab2swx2qMMF6LGrxyKK7yfLoDJn2iZa9JswL/gTx +3Tc+gkEvQQby3wzffWKSA2m7wFGxd1mytsFFnsohloueVj4b/FdTHuJM2SKD5JXf +l9Jh6ECMcYolcKNpWRZPsv5eAJNiwfy0f2+fuz9x0sB6F5hP0ttEdvYto2ZkMNT/ +hRsBGsAI1NP6AGNgDuGbi9ZLML7kWD0ZH+8ceFl5QKcvDw3QCBiwkc/LtGcnMyRV +5Fkjiptu7jlNsjYi+h/N8n/sFawjcERYrnaevD0J4qgekq0VuzdcYLZnW7j7L/+A +klQlJsyP8OD7VRvAbRDmRWRqVKa6wvuOC/zb/QCn10WcabsD6IsbjP5AS8DEosW3 +ld71mCeskTG50TK2+fFoofHTjqJl2g3JCwmBJ/OWj+i986+JG9MaXxqajLGkd0rZ +AroMHllkSB3STiybQb9uLyJG1hrVeVeYz9uFhCSjQvcYLZ+weIt2C/43BYLp06Ss +ZHjMy96kiGnUnw6PIMsPW+sZOzfby183kZjdKOWw6TIlDEznlWwFLa43mZqPRLhx +xsLd6wZAXXYBK2k0fcSMLIGnzLyvzcS6XVD93G136IvZpGgmryZkVBmzkGyoigMy +h2dzVpj99qu6JNig92YkS5nVRXgt5V63vS4cavwWgxZbMr6q1nOPmphCa8pTJ68u +PeRS71B9TTF6Wx5T/qeQ/Qzx9aa35eNO3LpogxFRWWJP48yFmjEZ4fKtLYlted1f +ZfFRlnkYmfuaqCaDUQKnxI1TWaLUMIWxZRNSen471p/x5+M7Vn5q7RLiu+UprFYM +j1swJ/EBw00KqEtlb6QNHuegqOqwUat1D2F9w/BIq/krR7lhM9UyB9FXttXFwJLS +WaBXL/S5ZrIXeHvIObOM6ovhza7dtRQuAJSs8DwBfhcNn1JxUGGHkAkg2xSr9Pl8 +wBigczSjGw35YxO+Ne++mF6dlHcoexrm3ZVI84kr1jB4dyFKuVCZ+6TabxeCNytp +s2+6YoCcu7b1ie2ljt0jhCcw0oEY3OTv0lAdOS4mst4rwgPr8kB3IqlLGnTPUFGg +g2clRN1JzWE9auTElWA0j4ECRbq4/HXrJB/L2TGi4kfqSGmCzLXgYCe/AgMBAAGj +ggEpMIIBJTAdBgNVHQ4EFgQURoeGwucZzxZMDGLLc3/9jxnktUIwHwYDVR0jBBgw +FoAURoeGwucZzxZMDGLLc3/9jxnktUIwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMC +AQYwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3dy5zYW1iYS5leGFtcGxlLmNv +bS9jcmxzL0NBLXNhbWJhLmV4YW1wbGUuY29tLWNybC5jcmwwEQYJYIZIAYb4QgEB +BAQDAgEGMDEGA1UdEQQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4 +YW1wbGUuY29tMDEGA1UdEgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJh +LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IEAQBeOC+ekA3OZ2DRFN6VQED2 +87IsASYi8kfZhRe/vA6Cx42jqbmJcbdDtc8v2GqMXbuO6nFZCOmhxvShL6ScQI+j +Scx6pNZYi8s4tg/2KGsTNRhhNXYzQ1hbEpQuDi8cHvft95cKlBTZrZHXyBTJbOZJ +jy3jbHmzsE+RiuMvBM+QVvo/ykQ2ySc6O8rzOhRwmSvrW+zZEjrOZEjQVFMisq/S +LkJ8Y8SkxH9F95EBexVztpOzfY20hkc8UDaqDP7OQhoY95mjJ0j90/7TjNTFT1bi +GmOVMr+K+3RWqUcCvAY0tIG9cPDvRFT5frEcV87W/R1ffG0FnNaq+Y8AGI24UO4s +TDll92OOX5KDbVunVerw/CII3+9k+tB9lbDYsdfDaoFJaIWLV0kXV9uUS/Ninp8T +M6smq594Hbjuy8hcse3USKrnMP1lLkb9s3I3U+UV098wf5qFx/sFjeXsPhZcD6Gt +oL9uGY2M6ZWxgkvOUDtdzfyhplWi7Ps+n+qR6JuCp5cemb8WGarqekeZNuJfve/f +eWXgpwac5CgJTSOI37LqzYKQehaBD9vJnS9RUMacSxOiH3puXGrxgPye88Yh6YOY +bkdsDQY17JLdLw6zHObJ1MrywCVLYa9aZlzrISJ2oka4qza+rfl6QVoYNcKUK/oh +hKcWpcfJOrDlxHneow4iA9uYY2MrKDKuTEgNS+lWYD3EO5iq9cC56anBO581xBXM +6ZBEijuIHOETlu6Hyks2iVkEEeSDT4JGVn720WXuMuZYMWh+TOTJz9Sq1M4orlsE +BszVqrfcOV6eb1n1ZeZ8mjxqyTtuuxIbpccNm4kEwH8EDPQvDTF0lnM4qjAYXJxp +uBEgHVyQY2Y4s6aDtbvoZiTQ4+0YcS/2db4puesXO9UzlBuVgKh4ta8MrYFIhl5t +V/U8t6/lXC82hyYuX5dNPhKQeScfZiW2VJZYyrVX+gRXyRuP0s9dB7q6G3o0kDCu +a/H6Hqf59dLppWIJE6aJClCaxhI9B95UeDMg1+eL8nKjrWkgIt6bdNpXGF6CPHeP +zVB+syvGwNdsYQBb313IpkkADoKtPb0PAK+3tC0Mm06fV/7ORq1/zLU2P8T5adxh +iXQ7ZkkxO+UVSdIveppG+uCzQrL0n0UmtQLP8euVaXe36vbjq6qECB89r0YFon90 +BHCIuegU2PUFL8sBs8ln3BAG+2sdDslIoQCT1k0Ce7kGoRDubIH7mK+t7ahvZHlu +jHaSopM+TIQYnwftvb4RVdwHhErHMovIoIirAZ50WALRNIUvMyWNi2uBwBLCyONY +3DVIyudGERIDT7RXvryvBXplH4Aj3ubu+KSB7WAceHyFpP5GVPULR5m1tAuHAR+K +-----END CERTIFICATE----- diff --git a/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-crl.pem b/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-crl.pem new file mode 100644 index 00000000000..df9445fbd13 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-crl.pem @@ -0,0 +1,32 @@ +-----BEGIN X509 CRL----- +MIIFdTCCAV0CAQEwDQYJKoZIhvcNAQELBQAwgcYxCzAJBgNVBAYTAlVTMRMwEQYD +VQQIDApTYW1iYVN0YXRlMRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNh +bWJhU2VsZlRlc3RpbmcxGjAYBgNVBAsMEUNBIEFkbWluaXN0cmF0aW9uMSAwHgYD +VQQDDBdDQSBvZiBzYW1iYS5leGFtcGxlLmNvbTE1MDMGCSqGSIb3DQEJARYmY2Et +c2FtYmEuZXhhbXBsZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20XDTE2MDMxODExNDQz +OFoXDTM2MDMxMzExNDQzOFqgYjBgMDEGA1UdEgQqMCiBJmNhLXNhbWJhLmV4YW1w +bGUuY29tQHNhbWJhLmV4YW1wbGUuY29tMB8GA1UdIwQYMBaAFEaHhsLnGc8WTAxi +y3N//Y8Z5LVCMAoGA1UdFAQDAgEAMA0GCSqGSIb3DQEBCwUAA4IEAQDCY6ioFWXc +znAwARBrMTLSu0eqm2gIK4luXEDM7w8875kGKfp6Xf+SVMpagQwNIWApDsVU59FO +zGn7GSD6sRaV0FSNiio/XBxIuCLGUrOss6tcClrtpwt8Y/GLv3SMpMwtH0GRsP4w +INrsUGxC/gh0njEcE6YXZH9QL+p4UBWwPvkFfAT3WijF2WLMCsI18ZPZ/q1ONkNt +sb3Kr+lowxVbLb5B+YDqP6ncRe1U49l6A1Q/8s0SDDmBnhiMtwSy0rdAxJ5eD2Wn +HlAkd/JS6xSR68XvG7fD6NrwHVZtGBNBZQvXJth/xS67ym2m36oGffO8w1z1/uxb +Zmr9HQAomubfc5rKCMQV1fREgnJGtY0VsWpiBqHxIXMK/A4DGVWrcg4GB5h5DHZi +bb62HjXrm8pQDMkRLS3smmnMbFrfuJ/2jH8hyfoSesQKcHGUJfF2UJh6yuGp8ud4 +uX4YTmb84u5UvrF848etp/Ij4l/qOJjj+C4rCt0CiPHetuMLhfLQuLt5JD220E38 +ESVi9cuj2cjPkpNoPOqqP8p5wOiJ7JZgrBLtZ/ha4gYyDiYqaX63Krp8uBJM2Kqa +BGgI5aKNzb9aXZhuZaXoiF2hXu+pD0XzmQ3B11hXa7DRwXdQiUcW0K28o/Kfvvzk +2jubHMiWt+NS8Jw7WeJjNB8rSNjWYGTgf/i8LNi8569AZH7q32wvm/KVUsB2MGAH +HRXk/yiPW2l4nIKD6/kxHEViVVG0k14IxohhPa8XMqHSt5/sOdZoaD4/7MJ4ci3L +DXAh/AoNTBhx0PSXGgfb0m8/pDykcdp6m6Ggf6Gzptu4iZroXC3rDMIkkvhKNX5c +ZanlSgpwcqSr18SEyPjOAWGBoTDStmoVVH1pWgdyL/u6kB4/pEpypQfXJrIV+pjg +EY6EQEZYtv1h2doJ2K9XkFDE0nPyw0QvdgAWqDTdOCaUhmTL2QbDdcjViV65cXwk +XyDq8C6aGYLz6Qqi2wzJRyGYfKBC7kDNvB5DIHC4ByFy5oEwm5fDWTkQcJ6hOHeh +of3zYCts39/dBD90jFFlM3dmSzUNCKJDaO6sudF1BuT1OfjnH6ABSkMfklNbqvKc +iAnDkmRt1edr3SUyA7RiBsJ4bTjs3YPbvN+zBEOIuRRi0OC8iO9zGG+2nFKtjTzd +Kz4JdSiGkcNTWoYBDqdiwUvPDDLT5nqO4XDC+1fHST0cy1IP1ggSRh1+YsBZbUnF +11gHE6WuMoRIQelLqiGjZhXrO8nB2dwu1uR70z2S1zI/Om5B7z/vREDZqewkht9U +YLmlkGMdhTdMmon9yVkXGEi6va/kyi24O81nJE7cyUnySoKp43zvpr5dZjbtUP0a +qcBp6pW4976r +-----END X509 CRL----- diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-cert.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-cert.pem new file mode 100644 index 00000000000..223d4072ce4 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-cert.pem @@ -0,0 +1,170 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com + Validity + Not Before: Mar 18 11:46:04 2016 GMT + Not After : Mar 13 11:46:04 2036 GMT + Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Users, CN=administrator@plugindom.samba.example.com/emailAddress=administrator@plugindom.samba.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bc:1c:03:de:e6:1e:17:1a:85:5b:13:b8:a9:b1: + 26:36:b2:7c:4e:d2:8a:3f:20:37:ea:57:f6:46:38: + 9e:86:26:cd:73:cc:6d:a6:a1:4e:21:29:89:f0:7e: + 75:a5:8d:5f:92:42:9d:88:81:21:66:8c:2f:1b:f5: + 14:54:6b:ed:18:c9:a7:a6:a7:16:07:10:27:77:31: + d4:90:a5:cd:a2:9c:96:c0:18:92:76:f9:12:40:ec: + 51:54:12:36:ce:c5:02:fd:9e:b9:80:4c:81:e9:7e: + 5b:59:2d:4a:7c:0a:35:0c:0f:85:a0:b9:93:23:77: + 35:8b:de:18:e7:5d:3e:25:27:cc:0e:f0:0f:ab:40: + a5:08:02:84:f1:cf:9b:66:37:12:37:02:4c:03:43: + 04:d5:a9:ad:6e:d2:88:c4:85:fa:f3:9f:f2:5d:6d: + 1f:f4:54:a1:d7:4a:93:c5:42:e9:cb:da:ff:bd:70: + 8b:27:75:4d:77:b0:ea:97:f1:80:75:84:57:5e:1e: + e5:a5:d9:89:28:e8:44:a0:77:66:08:64:51:c0:4a: + d0:06:c7:b1:b4:1e:6b:0a:94:a0:61:5a:9e:7b:5b: + d6:48:ab:1e:7e:65:43:d9:e0:91:51:f5:2b:43:99: + a1:94:bb:7f:aa:2b:e9:54:69:c4:e3:f1:e0:38:77: + 9f:f9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + + Netscape Cert Type: + SSL Client, S/MIME + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + Netscape Comment: + Smart Card Login Certificate for administrator@plugindom.samba.example.com + X509v3 Subject Key Identifier: + 1D:D6:74:30:69:F7:2D:5F:81:E4:83:F1:7E:B0:08:F3:9C:06:41:E4 + X509v3 Authority Key Identifier: + keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42 + + X509v3 Subject Alternative Name: + email:administrator@plugindom.samba.example.com, othername:<unsupported> + X509v3 Issuer Alternative Name: + email:ca-samba.example.com@samba.example.com + Netscape CA Revocation Url: + http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + X509v3 Extended Key Usage: + TLS Web Client Authentication, scardLogin + Signature Algorithm: sha256WithRSAEncryption + 2c:23:ad:2f:a2:83:57:e8:42:b3:27:43:7f:aa:9d:99:ae:9d: + 20:7f:0a:b0:f4:32:33:ad:ee:fe:33:aa:20:09:8e:4b:4b:0d: + 12:b1:d5:0c:29:bc:13:aa:04:49:ce:2c:b7:01:e7:68:e9:ef: + 77:a9:dd:b6:9a:0a:11:bf:88:46:0c:09:7b:ac:6b:ed:6a:8e: + 72:fc:d8:28:46:21:48:8f:27:04:67:2c:17:2b:33:f7:8c:18: + ca:c6:3d:0e:76:36:fe:6b:03:77:eb:97:28:a9:64:4b:46:32: + 38:23:f5:6f:d9:43:b6:4e:c6:b5:14:0c:c5:09:0c:55:94:06: + 92:26:10:66:44:90:64:fa:e8:ae:75:43:a0:bd:14:9a:31:37: + 87:30:b7:61:87:65:40:b7:c1:2e:94:4c:0a:ed:4c:c2:75:2d: + 60:57:f9:b3:cf:b2:ef:19:c3:96:a6:25:d3:1d:92:16:9e:af: + e4:e4:ca:87:77:4b:13:31:48:de:99:1a:9c:ea:9a:27:96:bc: + 16:48:af:83:41:8c:56:d4:9c:6f:c5:9a:31:c9:35:3a:a5:c9: + cc:7f:9f:3d:c2:56:03:6b:df:b3:ac:c0:47:ce:53:5c:bd:38: + 7d:57:d4:c3:59:c9:b7:0a:89:ac:c2:15:a4:4d:50:84:67:91: + 59:6d:28:a1:78:0c:2e:20:39:06:9d:0c:2d:a7:c4:dc:98:eb: + 4f:b4:58:6d:6a:ba:b0:5a:e9:87:7f:c9:11:a5:7c:b7:91:49: + f5:0a:e7:f9:c9:7c:ba:30:3d:95:a7:8a:66:47:ed:49:53:74: + 85:e3:63:d5:38:34:76:e7:3e:2c:74:b6:58:23:5b:93:be:eb: + b2:98:9c:7e:bd:0e:5f:fa:98:4d:76:13:b7:5d:22:bc:76:5b: + 13:88:8d:84:8b:fc:a4:25:99:82:3b:1e:2e:58:2a:8f:d7:36: + ec:fb:d6:1e:76:b8:0a:31:fa:56:18:38:96:d5:0e:d7:dd:ac: + 70:a6:c1:80:0e:9c:9b:44:e7:e8:b6:8a:64:8d:7c:9c:57:6a: + 90:ce:2b:c1:c6:da:f5:68:1d:c4:37:58:70:f7:ba:3d:4f:2e: + 6c:a6:a2:3b:12:1e:1c:ea:99:bb:ac:54:57:18:c0:d3:7f:8a: + c8:7e:73:8e:b1:06:6b:55:57:e3:4f:46:9e:db:50:55:1d:c9: + 61:99:de:31:79:75:bc:b1:d6:fe:17:b2:fd:cb:36:3a:12:6b: + 0f:c8:b0:a6:be:e1:a4:de:5b:76:02:bc:e4:9b:f9:df:e1:ed: + bb:dc:40:62:1b:05:34:c0:53:10:47:ac:c7:18:6e:7c:17:37: + 86:f3:84:91:17:00:f3:69:45:3f:fe:fe:3c:c6:b2:13:82:70: + fa:fc:1b:51:d0:56:19:b0:9e:9f:1d:27:75:27:81:f1:85:b2: + 15:7f:ac:f1:8d:de:fe:3a:57:0f:13:4f:d8:7c:9d:f3:49:a2: + fe:5a:e8:91:8c:38:c2:4b:9a:f3:49:0c:92:70:62:8e:ed:91: + 8a:3e:da:ab:96:d6:46:5f:25:e6:82:cd:29:03:20:83:3b:63: + c2:5b:34:92:12:98:13:b4:56:2d:1d:cf:4b:22:f8:40:fb:7f: + ae:3e:49:52:54:de:02:95:0a:f2:22:6f:e1:2c:bd:a4:08:8d: + ec:83:79:4a:a8:ee:27:0e:b8:6a:65:4f:ba:be:8a:94:02:ad: + ef:72:3e:07:52:52:51:58:6c:e7:20:e4:81:49:da:7f:f1:dd: + ea:2b:56:f4:29:75:16:df:b8:19:da:63:b2:a0:d3:93:5d:a6: + 81:f4:2d:d3:fb:cb:7c:e3:04:8e:38:9d:66:9d:29:57:28:22: + e3:7a:5b:48:cf:6e:79:32:24:6e:e4:dc:7a:05:22:2c:a4:0e: + 30:74:41:cd:34:ef:3d:33:4e:01:3e:65:25:01:cc:5d:73:5a: + 10:d6:df:45:24:93:69:fa:d3:ab:7f:c8:b7:5a:86:1c:88:be: + 32:05:2f:f8:2a:26:02:f5:cc:30:4a:dd:97:0a:3a:db:c0:0c: + 67:36:90:9b:f9:2c:e3:d0:04:26:46:c1:a3:4e:a0:46:be:f3: + 8b:91:9c:d5:f0:32:09:c5:f0:a3:51:bf:05:70:83:51:25:ba: + 6f:8c:25:ea:30:96:52:e6:53:64:38:ac:0e:de:54:e7:5f:da: + 30:e0:39:9b:d8:64:d5:3b:70:4f:9a:27:96:36:98:9b:f5:07: + 0b:4a:89:40:06:18:9d:6d:e2:6c:40:51:af:83:66:73:87:56: + 5c:fa:38:96:a8:dd:4a:28:4a:82:d2:09:0f:e4:77:db:09:ff: + 50:34:c9:dc:0e:27:fe:94:1d:65:71:56:59:19:1d:62:a2:1a: + 93:bc:25:7b:be:6e:06:2a:e6:ce:ef:fa:cf:30:a2:e6:ce:26: + 28:e5:eb:6e:03:64:3c:8f:65:ce:32:33:08:ab:dc:45:69:78: + 4e:d3:b5:87:4f:03:48:e0:c3:24:48:cf:74:79:62:1e:b1:e0: + 39:12:02:08:db:fe:f8:78:a7:43:7f:e1:e8:86:b4:04:3c:e1: + fe:26:71:75:9d:32:4c:3a:ad:84:cb:e6:be:f5:7f:20:9d:04: + 4f:ba:41:d1:78:4d:f7:3a:93:89:ef:a4:4e:b4:83:4c:92:70: + 39:1d:21:de:c8:4c:9b:5d:26:55:1b:ad:93:48:79:19 +-----BEGIN CERTIFICATE----- +MIIJLzCCBRegAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx +EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE +CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x +IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB +FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz +MTgxMTQ2MDRaFw0zNjAzMTMxMTQ2MDRaMIG7MQswCQYDVQQGEwJVUzETMBEGA1UE +CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEOMAwGA1UE +CwwFVXNlcnMxMjAwBgNVBAMMKWFkbWluaXN0cmF0b3JAcGx1Z2luZG9tLnNhbWJh +LmV4YW1wbGUuY29tMTgwNgYJKoZIhvcNAQkBFilhZG1pbmlzdHJhdG9yQHBsdWdp +bmRvbS5zYW1iYS5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALwcA97mHhcahVsTuKmxJjayfE7Sij8gN+pX9kY4noYmzXPMbaahTiEp +ifB+daWNX5JCnYiBIWaMLxv1FFRr7RjJp6anFgcQJ3cx1JClzaKclsAYknb5EkDs +UVQSNs7FAv2euYBMgel+W1ktSnwKNQwPhaC5kyN3NYveGOddPiUnzA7wD6tApQgC +hPHPm2Y3EjcCTANDBNWprW7SiMSF+vOf8l1tH/RUoddKk8VC6cva/71wiyd1TXew +6pfxgHWEV14e5aXZiSjoRKB3ZghkUcBK0AbHsbQeawqUoGFanntb1kirHn5lQ9ng +kVH1K0OZoZS7f6or6VRpxOPx4Dh3n/kCAwEAAaOCAi8wggIrMAkGA1UdEwQCMAAw +TwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3dy5zYW1iYS5leGFtcGxlLmNvbS9j +cmxzL0NBLXNhbWJhLmV4YW1wbGUuY29tLWNybC5jcmwwEQYJYIZIAYb4QgEBBAQD +AgWgMAsGA1UdDwQEAwIF4DBZBglghkgBhvhCAQ0ETBZKU21hcnQgQ2FyZCBMb2dp +biBDZXJ0aWZpY2F0ZSBmb3IgYWRtaW5pc3RyYXRvckBwbHVnaW5kb20uc2FtYmEu +ZXhhbXBsZS5jb20wHQYDVR0OBBYEFB3WdDBp9y1fgeSD8X6wCPOcBkHkMB8GA1Ud +IwQYMBaAFEaHhsLnGc8WTAxiy3N//Y8Z5LVCMG8GA1UdEQRoMGaBKWFkbWluaXN0 +cmF0b3JAcGx1Z2luZG9tLnNhbWJhLmV4YW1wbGUuY29toDkGCisGAQQBgjcUAgOg +KwwpYWRtaW5pc3RyYXRvckBwbHVnaW5kb20uc2FtYmEuZXhhbXBsZS5jb20wMQYD +VR0SBCowKIEmY2Etc2FtYmEuZXhhbXBsZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20w +TQYJYIZIAYb4QgEEBEAWPmh0dHA6Ly93d3cuc2FtYmEuZXhhbXBsZS5jb20vY3Js +cy9DQS1zYW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMB8GA1UdJQQYMBYGCCsGAQUF +BwMCBgorBgEEAYI3FAICMA0GCSqGSIb3DQEBCwUAA4IEAQAsI60vooNX6EKzJ0N/ +qp2Zrp0gfwqw9DIzre7+M6ogCY5LSw0SsdUMKbwTqgRJziy3Aedo6e93qd22mgoR +v4hGDAl7rGvtao5y/NgoRiFIjycEZywXKzP3jBjKxj0Odjb+awN365coqWRLRjI4 +I/Vv2UO2Tsa1FAzFCQxVlAaSJhBmRJBk+uiudUOgvRSaMTeHMLdhh2VAt8EulEwK +7UzCdS1gV/mzz7LvGcOWpiXTHZIWnq/k5MqHd0sTMUjemRqc6ponlrwWSK+DQYxW +1JxvxZoxyTU6pcnMf589wlYDa9+zrMBHzlNcvTh9V9TDWcm3ComswhWkTVCEZ5FZ +bSiheAwuIDkGnQwtp8TcmOtPtFhtarqwWumHf8kRpXy3kUn1Cuf5yXy6MD2Vp4pm +R+1JU3SF42PVODR25z4sdLZYI1uTvuuymJx+vQ5f+phNdhO3XSK8dlsTiI2Ei/yk +JZmCOx4uWCqP1zbs+9YedrgKMfpWGDiW1Q7X3axwpsGADpybROfotopkjXycV2qQ +zivBxtr1aB3EN1hw97o9Ty5spqI7Eh4c6pm7rFRXGMDTf4rIfnOOsQZrVVfjT0ae +21BVHclhmd4xeXW8sdb+F7L9yzY6EmsPyLCmvuGk3lt2Arzkm/nf4e273EBiGwU0 +wFMQR6zHGG58FzeG84SRFwDzaUU//v48xrITgnD6/BtR0FYZsJ6fHSd1J4HxhbIV +f6zxjd7+OlcPE0/YfJ3zSaL+WuiRjDjCS5rzSQyScGKO7ZGKPtqrltZGXyXmgs0p +AyCDO2PCWzSSEpgTtFYtHc9LIvhA+3+uPklSVN4ClQryIm/hLL2kCI3sg3lKqO4n +DrhqZU+6voqUAq3vcj4HUlJRWGznIOSBSdp/8d3qK1b0KXUW37gZ2mOyoNOTXaaB +9C3T+8t84wSOOJ1mnSlXKCLjeltIz255MiRu5Nx6BSIspA4wdEHNNO89M04BPmUl +Acxdc1oQ1t9FJJNp+tOrf8i3WoYciL4yBS/4KiYC9cwwSt2XCjrbwAxnNpCb+Szj +0AQmRsGjTqBGvvOLkZzV8DIJxfCjUb8FcINRJbpvjCXqMJZS5lNkOKwO3lTnX9ow +4Dmb2GTVO3BPmieWNpib9QcLSolABhidbeJsQFGvg2Zzh1Zc+jiWqN1KKEqC0gkP +5HfbCf9QNMncDif+lB1lcVZZGR1iohqTvCV7vm4GKubO7/rPMKLmziYo5etuA2Q8 +j2XOMjMIq9xFaXhO07WHTwNI4MMkSM90eWIeseA5EgII2/74eKdDf+HohrQEPOH+ +JnF1nTJMOq2Ey+a+9X8gnQRPukHReE33OpOJ76ROtINMknA5HSHeyEybXSZVG62T +SHkZ +-----END CERTIFICATE----- diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-key.pem new file mode 100644 index 00000000000..f0c97b7cc7f --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-key.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIywzM9NUqYIYCAggA +MBQGCCqGSIb3DQMHBAg/PHGo9J8k2ASCBMgInucWaWmW19O/FNVi2NqcCenKvxfb +rM1b9KigeRKo1GABmMVen0Ugy5A4YxIF9nrjCYjI+eDfsZjLaP5Fzn3Nt7/eX1bV +dvKK3N4Zwks0SuMtksyYs2wshT86dVjnHbIXC5p9cJFjPEyxSp/M77ypQnmqTwDM +2GhYQywPoOQ8b3JwhAREevJnbA6bQw79E/9NzmtrhXJkvahqLWkNGR0yPx9iH0tN +9qfPP5Svz8un8cHlulb2VoY9BgsoxG0AO9V62slwX3WRv7BKtkyM8E0HXD3sBSNB +fpt1FhqFW2nQM9F0gikA6LIh4QYBd5c5zMDF1FW5kbFp5OTQaUEvIKw3TTHXQdhs +bnXfiJ6DxdIdeSubOGP3RxRv9gLmSYMq9UqyVQM4jHKsDMA2RLSj5yc6DTUGYe3a +OHNk4v0mNLLvW9VJTkoQrnSpr2Px1ZIB2uTBY4+1VV3eALtZTTvW9cJmV7uaPirJ +gEAQMY2uWHJTOPqzDdB1RwAB3P46b208nPgWuW/DG2+NFhnkGxQGceITRSIc9StF +icJtVeYPTgOuVsV01V1SrdpgtUg2sEXCfJKWxHROXkFnf0lxibC1m1gRiaLMDHkZ +sFDPgBpNuGNcf5wtqDxBTwiRhsgwqtMRtXLTzNxh7VDUIXnu4CrwD4Pcmeul/qnd +5hrHyz7MF0ZUep0IkcR0O3ullo09Ayptsaxv8xcSjKPP7Kt8U1h7YQie/hVQ5roi +Uhjf1PeaNtIsZtrf0nJnrbj4yY/ZdIXP8uVDWT0+GCDW055cEw6XfTdsRdMzMQqc +ZfpR7kh2quAuvTzVVzrHve+bVB/AmHXJr1MKPLS7wfyaqESCbVmP+9k7bybjwCKU +LlPuQVFFtE7ZBSgzkORTfjIMSY0XwISzZY8clowrkHU/ATj6MTZo5mWq18ddEBl3 +3dbUHqM8g9BnSd0oOXORQqInZY1G0U2+O/AJB6haaQAI2LBeSqf0GH+5BU9Ty7wH +QEfQaQLnwTG3gwugluYTSjn1K9SiHptDHfNxBnCPOflm2PriDAvkylgnHHIRjbsn +PnC/Wn0QiVUvP4WuVb+p0cfR7s0f6diBuaWaWY6acd0vbrXqs1qp78sqKZ1qVCMA +FJ+S8IJmu4q9Up92XiyWgMQWi/oa2u9HoNh1K9+LMrXiEnson0VJlCy+SQ+QxTpK +rOp0bThlqaZF9VYSoawfGiLjbwr2rh8fJ/1bIENy0sIyWvPyRFyl63ku9nI46Ze+ +qQFiG9GRURzRCjyhDZIWJT4F6m65o5LoKFeFTi2WwAV9UK744F06SxsIGHNMm5EV +iXLIkipWqGJZ/UUEv3vleirud0STQFpp2NYBIGNtEH1LbhjIeF0rALx8+lnPx54F +atNh52qKkiz/VMBnZ/q/z3+qK9G4ou4b/AB4xzPOQUMLUQ3/aiJciFGRpBCm5QTn +bnO0IiCpLIgQu6rmEJ59iF5pbujMFXgF5W9DdxvSSvWhsRgu1+V9vUVfR7h9HXc3 +hIglijRDwVSzlvuVslMLtmy+fkzzezFvsmgRPy6t5dGpqmvfGel/wC6m3kQ+0IHt +t/GUTgPoVS52YhB4xurMsGLYQbjuLnnZ8rc/2O7ciqHhW0tB40D04L6Ap7rCLuqK +oRY= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-openssl.cnf new file mode 100644 index 00000000000..8016fb3535b --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-openssl.cnf @@ -0,0 +1,242 @@ +# +# Based on the OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +#CRLDISTPT = [CRL Distribution Point; e.g., http://crl-list.base/w4edom-l4.base.crl] +CRLDISTPT = http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + +# Extra OBJECT IDENTIFIER info: +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] +# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used as a login credential +scardLogin=1.3.6.1.4.1.311.20.2.2 +# Used in a smart card login certificate's subject alternative name +msUPN=1.3.6.1.4.1.311.20.2.3 +# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used to identify a domain controller +msKDC=1.3.6.1.5.2.3.5 +# Identifies the AD GUID +msADGUID=1.3.6.1.4.1.311.25.1 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = CA-samba.example.com # Where everything is kept +certs = $dir/_none_certs # Where the issued certs are kept +crl_dir = $dir/_none_crl # Where the issued crl are kept +database = $dir/Private/CA-samba.example.com-index.txt # database index file. +unique_subject = yes # Set to 'no' to allow creation of + # several certificates with same subject. +new_certs_dir = $dir/NewCerts # default place for new certs. + +certificate = $dir/Public/CA-samba.example.com-cert.pem # The CA certificate +serial = $dir/Private/CA-samba.example.com-serial.txt # The current serial number +crlnumber = $dir/Private/CA-samba.example.com-crlnumber.txt # the current crl number + # must be commented out to leave a V1 CRL + +#crl = $dir/Public/CA-samba.example.com-crl.pem # The current CRL +crl = $dir/Public/CA-samba.example.com-crl.crl # The current CRL +private_key = $dir/Private/CA-samba.example.com-private-key.pem # The private key +RANDFILE = $dir/Private/CA-samba.example.com.rand # private random number file + +#x509_extensions = # The extensions to add to the cert +x509_extensions = template_x509_extensions + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +crl_extensions = crl_ext + +default_days = 7300 # how long to certify for +default_crl_days= 7300 # how long before next CRL +default_md = sha256 # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = match +stateOrProvinceName = match +localityName = match +organizationName = match +organizationalUnitName = match +commonName = supplied +emailAddress = supplied + +#################################################################### +[ req ] +default_bits = 2048 +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extensions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = US +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = SambaState + +localityName = Locality Name (eg, city) +localityName_default = SambaCity + +organizationName = Organization Name (eg, company) +organizationName_default = SambaSelfTesting + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = Users + +commonName = Common Name (eg, YOUR name) +commonName_default = administrator@plugindom.samba.example.com +commonName_max = 64 + +emailAddress = Email Address +emailAddress_default = administrator@plugindom.samba.example.com +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +#challengePassword = A challenge password +#challengePassword_min = 4 +#challengePassword_max = 20 +# +#unstructuredName = An optional company name + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] +# Extensions for a typical CA +# PKIX recommendation. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. +keyUsage = cRLSign, keyCertSign + +crlDistributionPoints=URI:$CRLDISTPT + +# Some might want this also +nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +subjectAltName=email:copy +# Copy issuer details +issuerAltName=issuer:copy + +[ crl_ext ] +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +#[ usr_cert_scarduser ] +[ template_x509_extensions ] + +# These extensions are added when 'ca' signs a request for a certificate that will be used to login from a smart card + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE +crlDistributionPoints=URI:$CRLDISTPT + +# For normal client use this is typical +nsCertType = client, email + +# This is typical in keyUsage for a client certificate. +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "Smart Card Login Certificate for administrator@plugindom.samba.example.com" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. + +subjectAltName=email:copy,otherName:msUPN;UTF8:administrator@plugindom.samba.example.com + +# Copy subject details +issuerAltName=issuer:copy + +nsCaRevocationUrl = $CRLDISTPT +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +#Extended Key requirements for client certs +extendedKeyUsage = clientAuth,scardLogin + diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-private-key.pem new file mode 100644 index 00000000000..a68aaac7bee --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-private-key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAvBwD3uYeFxqFWxO4qbEmNrJ8TtKKPyA36lf2RjiehibNc8xt +pqFOISmJ8H51pY1fkkKdiIEhZowvG/UUVGvtGMmnpqcWBxAndzHUkKXNopyWwBiS +dvkSQOxRVBI2zsUC/Z65gEyB6X5bWS1KfAo1DA+FoLmTI3c1i94Y510+JSfMDvAP +q0ClCAKE8c+bZjcSNwJMA0ME1amtbtKIxIX685/yXW0f9FSh10qTxULpy9r/vXCL +J3VNd7Dql/GAdYRXXh7lpdmJKOhEoHdmCGRRwErQBsextB5rCpSgYVqee1vWSKse +fmVD2eCRUfUrQ5mhlLt/qivpVGnE4/HgOHef+QIDAQABAoIBABUKwTgW37jP46j7 +fMWmplKqBpO+o25KSVbyff7+6GSzRHo2nPFty9KT1fVMABcDyHQQ9ZRGdZkGB2MG +OD71T7FdJV7UA/fIS9HehhukIGuXPpnAZenfFLakeLiBzRW2Hg6GydNbO5EF7Gv+ +T/2uGp79wYHoIFhwRlIeBwUifggjyWuLFproK+JGLtzNLEWnn12k/5oSbXTYOcvJ +mPKGe0XmBMtY8IqlH6BLi04XFWBFT+DE+U0Yx9OzrRi51srq4+acpX06GiaH2Q3E +J61gr4e2EcDf6AJiz+jihLLBrVgTFda+eldoRyS2eG8EPsD/O7jakiBbKuCIDWwo +YZnOrYECgYEA3gxYEohP1P/B9D8cSOBYOhwZL3aZBXnWMACup0ppJBWlDkUvNUJa +ScVZJuj7s6zPp1boWMjfQvfX8q4M7gC3mccotnYGR4zRm1iDbYuUUBmM1ChQ6Cks +nZRcvYskTOl+ja+aULEde/I6/kYIQFUWyYR6UmKHxXcV0Co9I0DcnVECgYEA2N8z +qGuVHpZOJPhCod4eFXxKUh1WYUzkMcH4RlJ/h+Y2BYkUDSQb26KBur7KvVHmJm1G +28zBqLS76/3nha8XuHlLmHnD+6R4LEe8d4sm7RHJWgQMzvrnqle30Db2hBK0dwNI +JkI9zzQZv7FIqT0DHZ8aWKc+D2luJdDdbboIDikCgYEAh5b8FNz9+q/ubMo46Ftu +JJXR30TJbimW3Bsei3MJvwokjxE6IYiR/6gtp2/veykUaDfOi6CljIwxZrRXmuH/ +Ozz9JGXvsbNQr06eer8X4s2nTEoOFaZG4zacZvXXRcvzBmvrjEiLG4uv8GMtWLNc +xdNKqpIWHEN6o3GXgbZywPECgYEAuWbfh70pR3PhrHNcq3rzJxURiG+yOA5/Cxaz +RJMkma6yQjs1HCLhefvMgjS3p/ALHJDRQfkjGjIgcZinxD6yva9cdCas6EVrwxc0 +xNH+Xi+VflH2DUCsqpDBAMzsJG7FPvVcSfDZXHlDBgDuiFgzgLBS2rVnNc/BLa0I +j9S5LDkCgYA8Cz5qcVfTU8QoS2ZrYxzLJM7m2h+BwLTaFtV8Gu0nkPQXT/Wa9QJj +h6eFGIYRvImNe0ASurTqDqQBmmWsFK9SofuPOGW8T+nBm+3ApjtTxev1zugV9YXO +cc2Opy84+OYqE4prg+qxg8/zgNtUF6IQ+LDB7AXS3FJGCyeCSMmILg== +-----END RSA PRIVATE KEY----- diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-req.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-req.pem new file mode 100644 index 00000000000..0e58e9aa66f --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-req.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIDFTCCAf0CAQAwgc8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTYW1iYVN0YXRl +MRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNhbWJhU2VsZlRlc3Rpbmcx +DjAMBgNVBAsMBVVzZXJzMTIwMAYDVQQDDClhZG1pbmlzdHJhdG9yQHBsdWdpbmRv +bS5zYW1iYS5leGFtcGxlLmNvbTE4MDYGCSqGSIb3DQEJARYpYWRtaW5pc3RyYXRv +ckBwbHVnaW5kb20uc2FtYmEuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQC8HAPe5h4XGoVbE7ipsSY2snxO0oo/IDfqV/ZGOJ6GJs1z +zG2moU4hKYnwfnWljV+SQp2IgSFmjC8b9RRUa+0YyaempxYHECd3MdSQpc2inJbA +GJJ2+RJA7FFUEjbOxQL9nrmATIHpfltZLUp8CjUMD4WguZMjdzWL3hjnXT4lJ8wO +8A+rQKUIAoTxz5tmNxI3AkwDQwTVqa1u0ojEhfrzn/JdbR/0VKHXSpPFQunL2v+9 +cIsndU13sOqX8YB1hFdeHuWl2Yko6ESgd2YIZFHAStAGx7G0HmsKlKBhWp57W9ZI +qx5+ZUPZ4JFR9StDmaGUu3+qK+lUacTj8eA4d5/5AgMBAAGgADANBgkqhkiG9w0B +AQsFAAOCAQEADZFjHLUC/AZU07Ax6GmjmSvP4OIxFm3NWS6OSD3a1MrPN/v6IGBl +joVTlMpIrVFg2/iXZnLSJechq9HFDJ7wyeIX+QgFwuTDG1cfH7Ji5Xk3HgN2oVyD +Eea02tTbTOLVGJk27yFJaKCmpGJ3mKiOBFmfZRXitE15hEvOMXVkJVR2FtxxW0fk +PLYDX74e4fLFZUCgmOh47Seuc0bZk4pLROAaUhxFPOuLiLs//YbdkY8LLz6MYXdv +ia08JhcEq6zbrPPvTxRtGTFHWSJUhpOkEroRfeT/8vgirwnGLlkeLXIL5l7iyUi+ +3Z01Qrv/frJxsAgMaXdBB4YZES+Z/qoiNA== +-----END CERTIFICATE REQUEST----- diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-cert.pem new file mode 120000 index 00000000000..282971d3f6e --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-cert.pem @@ -0,0 +1 @@ +USER-administrator@plugindom.samba.example.com-S03-cert.pem
\ No newline at end of file diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-private-key.pem new file mode 120000 index 00000000000..b3fec415305 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-private-key.pem @@ -0,0 +1 @@ +USER-administrator@plugindom.samba.example.com-S03-private-key.pem
\ No newline at end of file diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-cert.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-cert.pem new file mode 100644 index 00000000000..deb2b73f312 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-cert.pem @@ -0,0 +1,169 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com + Validity + Not Before: Mar 18 11:45:11 2016 GMT + Not After : Mar 13 11:45:11 2036 GMT + Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Users, CN=administrator@samba.example.com/emailAddress=administrator@samba.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c9:07:44:3a:5f:f6:34:5f:27:8a:7a:6e:2f:fb: + 45:1f:c3:3d:dd:2c:43:65:f1:7a:29:3f:42:26:bd: + ff:4f:5d:91:c0:bb:75:e3:81:14:7d:59:72:78:96: + 1a:5e:8d:95:93:f4:5d:92:79:0e:24:77:4f:8b:08: + 4e:72:b1:99:88:63:06:74:b2:dc:f7:82:62:e9:dd: + 6f:e5:a7:b4:c9:44:0c:e4:43:41:f8:57:a9:20:b1: + 70:c1:76:a1:48:5b:e9:54:b6:4f:22:50:93:90:f0: + 62:32:50:9a:6e:22:6b:37:a0:f7:1f:fc:b1:5f:ae: + e2:0b:88:6d:ea:29:b6:01:27:b2:84:ef:10:4d:6c: + 0a:df:ea:a9:8a:82:98:60:a7:52:73:a4:f7:7c:b2: + 4a:b9:f0:9b:c4:f8:19:5a:c0:84:54:52:35:c8:92: + 4f:16:af:d6:36:a6:78:57:55:e5:5e:6b:62:00:fa: + 48:c2:7a:e7:17:38:b5:23:d5:a8:fb:7d:df:42:5c: + 03:f4:7c:ef:ff:f1:a0:e6:d8:27:93:06:b3:a3:21: + 68:0e:c4:60:20:02:46:2f:2b:d8:88:e4:2b:01:c2: + 31:5a:55:28:be:55:03:f2:06:2b:e4:ec:48:60:e4: + b6:db:a1:f0:c5:24:ba:e1:a8:e2:6a:fb:0b:40:6c: + 3d:f5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + + Netscape Cert Type: + SSL Client, S/MIME + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + Netscape Comment: + Smart Card Login Certificate for administrator@samba.example.com + X509v3 Subject Key Identifier: + 70:86:EC:68:B4:51:8A:1C:12:65:A0:2A:B3:43:33:12:65:83:8D:40 + X509v3 Authority Key Identifier: + keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42 + + X509v3 Subject Alternative Name: + email:administrator@samba.example.com, othername:<unsupported> + X509v3 Issuer Alternative Name: + email:ca-samba.example.com@samba.example.com + Netscape CA Revocation Url: + http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + X509v3 Extended Key Usage: + TLS Web Client Authentication, scardLogin + Signature Algorithm: sha256WithRSAEncryption + 5d:b1:10:f8:36:dd:a9:fd:8d:be:31:53:1d:cf:b5:ea:33:1a: + 85:0f:13:8d:cc:67:91:41:97:e4:e9:67:6a:0c:ce:a4:9a:06: + b3:53:bf:e6:6d:f1:d1:32:7d:54:5d:6a:a8:94:fe:d4:f6:62: + 85:0f:e0:73:f8:ce:51:32:18:65:50:34:f9:f2:66:f8:ec:fd: + 94:c2:1d:28:6f:ce:3c:b3:0a:0a:cc:8b:fb:2c:e8:44:d2:d8: + 64:d7:19:1c:a4:25:5f:75:63:bc:44:56:64:cb:ca:8c:43:75: + 1e:95:36:98:a1:c6:49:e6:14:60:ad:87:91:af:d8:3c:d2:63: + 52:82:02:0a:42:c0:e3:7b:50:51:37:d5:c0:a5:0c:09:ac:2d: + a0:b3:29:e4:9e:bf:d3:df:01:82:00:a5:ad:fb:35:e8:f6:1c: + d7:cb:d1:3c:54:1f:d2:73:38:ce:a6:0a:e2:77:0a:fc:e5:ff: + 7e:68:a6:c7:57:fd:c7:cf:95:48:9f:97:6f:fe:2e:9f:e3:d6: + b0:a5:b5:33:9f:12:c1:e6:12:15:77:33:8f:1e:35:b5:88:f8: + 6b:47:88:e4:cb:49:f7:11:ba:19:39:55:5e:4a:5a:65:76:7e: + cc:3a:a7:fa:91:9a:ef:b5:c1:bf:f0:e7:a2:c6:9f:08:17:fc: + 4c:a4:ef:0b:d8:c7:a4:f9:74:36:b3:67:90:5e:84:26:83:bd: + 36:89:0d:c6:8c:1d:03:ce:8f:80:c9:0c:c6:c0:1e:eb:42:e7: + 97:7f:21:ac:b1:64:06:f6:1d:6d:0c:87:ff:c9:30:23:d3:21: + 1f:53:05:69:21:d5:26:ca:7f:ce:3a:4e:8d:d1:40:16:7e:a2: + c0:0f:95:0c:67:90:47:d2:e2:cf:87:ef:dc:35:18:2a:a2:21: + cd:67:b0:b2:14:9f:75:94:93:ba:8c:4d:45:71:cb:e9:df:cd: + f5:e3:f0:ff:c3:38:77:c2:41:55:d6:60:96:d8:bd:5f:09:22: + 97:44:8d:4d:b1:dd:68:39:04:1b:7a:57:3b:ca:56:27:87:31: + 55:84:6c:f0:65:af:ec:0b:52:87:28:0b:2d:52:c0:ce:a3:7d: + 7b:47:07:df:8a:65:e9:6f:da:e7:b6:94:06:69:b8:55:3d:11: + 01:c6:bf:0b:61:1b:cc:30:47:ab:cf:fb:72:62:f3:eb:66:11: + cd:1c:ab:4e:29:bf:b7:78:d6:09:ec:d7:67:5b:17:b9:34:cc: + af:5e:d9:02:0b:33:fc:a1:f2:64:33:c4:af:11:5b:08:f7:af: + ba:0d:68:d7:cf:d2:40:2f:56:20:34:da:82:18:7c:0e:71:61: + a6:58:60:00:30:a6:c7:25:3a:90:70:a0:14:e6:da:d8:12:e9: + b3:6a:c4:96:85:41:80:a6:71:17:b5:cf:4f:a2:2d:51:93:fd: + 26:eb:44:3c:2a:84:6a:da:18:10:d6:48:e3:8e:0f:c9:69:05: + 96:8c:96:f9:74:06:ab:11:d2:e4:e5:d7:22:db:13:93:d6:f9: + 24:84:56:7c:6a:43:a9:b8:30:33:2c:a4:42:9f:ec:f6:56:2d: + 46:cf:ec:26:49:5e:da:53:21:6b:8c:05:0d:b7:12:26:29:43: + 32:b2:6c:ed:07:47:75:2b:0b:7e:5d:28:1b:5b:7b:b5:63:13: + 55:4d:f7:a3:f6:fd:2d:f5:6d:43:83:40:46:b3:0d:d6:28:99: + d4:fb:89:fb:41:c6:15:35:a5:ee:1a:08:33:b3:0b:75:0a:d0: + fc:31:ec:77:80:e2:f0:ab:20:cc:43:24:67:42:a5:d7:e6:b0: + b9:84:fd:43:a0:5e:d9:78:10:97:d3:d1:b7:d9:33:70:0f:4d: + f0:a1:ac:22:d7:36:53:68:6d:39:e0:14:dc:d7:ea:1e:c2:92: + 1b:f8:2a:99:97:14:76:2c:89:3f:b7:89:c7:69:6e:5b:dd:8e: + 47:7a:f0:0e:a4:d0:18:c6:c4:34:f0:b8:84:3a:6e:ee:1e:7b: + 84:58:d2:10:a6:a2:0c:14:a8:55:e9:c5:7e:ab:97:e4:9d:b5: + f0:9f:2e:36:ac:2f:73:30:c8:b1:fc:b4:ce:b4:39:bd:59:75: + b8:24:5a:b1:67:de:34:3f:4e:17:5d:d3:bc:bb:6a:6a:b7:3e: + 0b:e8:4d:3b:08:d6:de:a7:9a:d7:8d:60:56:bb:3e:6c:d0:a7: + f8:45:a2:52:a3:b5:1e:ef:56:df:14:62:52:ed:36:ab:cc:7a: + a1:96:14:9a:e9:de:4a:28:68:bd:21:2d:60:d5:06:8a:e9:5e: + b6:ce:e1:b4:ed:56:9f:99:87:fe:20:bb:d5:8d:0d:72:1d:7e: + 88:27:9c:66:d5:26:aa:32:0a:ad:64:de:b8:13:2d:51:cc:8b: + e2:f4:c1:63:a6:64:e8:03:08:42:38:bf:f4:fe:b3:25:03:1b: + 14:b9:68:81:14:b9:5d:b9:6a:eb:f0:a9:24:41:8e:49:03:be: + 0b:55:cf:ac:77:68:ed:54:ae:55:40:dd:31:c4:3a:e2:d7:86: + d5:d5:e4:5e:5b:ce:9e:da:a1:90:58:e1:b3:7c:a6:87:15:bd: + 3a:67:b9:ab:29:de:4f:af:08:98:89:45:62:8f:db:5b:2e:2b: + e8:97:35:a2:fc:4f:cf:63:7d:56:a0:51:dd:3f:b2:90:a6:9b: + a0:9b:9e:93:8d:9d:92:b2:ed:36:d5:e1:f1:e3:97:dc +-----BEGIN CERTIFICATE----- +MIII/TCCBOWgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx +EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE +CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x +IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB +FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz +MTgxMTQ1MTFaFw0zNjAzMTMxMTQ1MTFaMIGnMQswCQYDVQQGEwJVUzETMBEGA1UE +CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEOMAwGA1UE +CwwFVXNlcnMxKDAmBgNVBAMMH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5j +b20xLjAsBgkqhkiG9w0BCQEWH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5j +b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJB0Q6X/Y0XyeKem4v ++0Ufwz3dLENl8XopP0Imvf9PXZHAu3XjgRR9WXJ4lhpejZWT9F2SeQ4kd0+LCE5y +sZmIYwZ0stz3gmLp3W/lp7TJRAzkQ0H4V6kgsXDBdqFIW+lUtk8iUJOQ8GIyUJpu +Ims3oPcf/LFfruILiG3qKbYBJ7KE7xBNbArf6qmKgphgp1JzpPd8skq58JvE+Bla +wIRUUjXIkk8Wr9Y2pnhXVeVea2IA+kjCeucXOLUj1aj7fd9CXAP0fO//8aDm2CeT +BrOjIWgOxGAgAkYvK9iI5CsBwjFaVSi+VQPyBivk7Ehg5LbbofDFJLrhqOJq+wtA +bD31AgMBAAGjggIRMIICDTAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0 +dHA6Ly93d3cuc2FtYmEuZXhhbXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxl +LmNvbS1jcmwuY3JsMBEGCWCGSAGG+EIBAQQEAwIFoDALBgNVHQ8EBAMCBeAwTwYJ +YIZIAYb4QgENBEIWQFNtYXJ0IENhcmQgTG9naW4gQ2VydGlmaWNhdGUgZm9yIGFk +bWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5jb20wHQYDVR0OBBYEFHCG7Gi0UYoc +EmWgKrNDMxJlg41AMB8GA1UdIwQYMBaAFEaHhsLnGc8WTAxiy3N//Y8Z5LVCMFsG +A1UdEQRUMFKBH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5jb22gLwYKKwYB +BAGCNxQCA6AhDB9hZG1pbmlzdHJhdG9yQHNhbWJhLmV4YW1wbGUuY29tMDEGA1Ud +EgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0G +CWCGSAGG+EIBBARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMv +Q0Etc2FtYmEuZXhhbXBsZS5jb20tY3JsLmNybDAfBgNVHSUEGDAWBggrBgEFBQcD +AgYKKwYBBAGCNxQCAjANBgkqhkiG9w0BAQsFAAOCBAEAXbEQ+Dbdqf2NvjFTHc+1 +6jMahQ8TjcxnkUGX5OlnagzOpJoGs1O/5m3x0TJ9VF1qqJT+1PZihQ/gc/jOUTIY +ZVA0+fJm+Oz9lMIdKG/OPLMKCsyL+yzoRNLYZNcZHKQlX3VjvERWZMvKjEN1HpU2 +mKHGSeYUYK2Hka/YPNJjUoICCkLA43tQUTfVwKUMCawtoLMp5J6/098BggClrfs1 +6PYc18vRPFQf0nM4zqYK4ncK/OX/fmimx1f9x8+VSJ+Xb/4un+PWsKW1M58SweYS +FXczjx41tYj4a0eI5MtJ9xG6GTlVXkpaZXZ+zDqn+pGa77XBv/DnosafCBf8TKTv +C9jHpPl0NrNnkF6EJoO9NokNxowdA86PgMkMxsAe60Lnl38hrLFkBvYdbQyH/8kw +I9MhH1MFaSHVJsp/zjpOjdFAFn6iwA+VDGeQR9Liz4fv3DUYKqIhzWewshSfdZST +uoxNRXHL6d/N9ePw/8M4d8JBVdZglti9Xwkil0SNTbHdaDkEG3pXO8pWJ4cxVYRs +8GWv7AtShygLLVLAzqN9e0cH34pl6W/a57aUBmm4VT0RAca/C2EbzDBHq8/7cmLz +62YRzRyrTim/t3jWCezXZ1sXuTTMr17ZAgsz/KHyZDPErxFbCPevug1o18/SQC9W +IDTaghh8DnFhplhgADCmxyU6kHCgFOba2BLps2rEloVBgKZxF7XPT6ItUZP9JutE +PCqEatoYENZI444PyWkFloyW+XQGqxHS5OXXItsTk9b5JIRWfGpDqbgwMyykQp/s +9lYtRs/sJkle2lMha4wFDbcSJilDMrJs7QdHdSsLfl0oG1t7tWMTVU33o/b9LfVt +Q4NARrMN1iiZ1PuJ+0HGFTWl7hoIM7MLdQrQ/DHsd4Di8KsgzEMkZ0Kl1+awuYT9 +Q6Be2XgQl9PRt9kzcA9N8KGsItc2U2htOeAU3NfqHsKSG/gqmZcUdiyJP7eJx2lu +W92OR3rwDqTQGMbENPC4hDpu7h57hFjSEKaiDBSoVenFfquX5J218J8uNqwvczDI +sfy0zrQ5vVl1uCRasWfeND9OF13TvLtqarc+C+hNOwjW3qea141gVrs+bNCn+EWi +UqO1Hu9W3xRiUu02q8x6oZYUmuneSihovSEtYNUGiulets7htO1Wn5mH/iC71Y0N +ch1+iCecZtUmqjIKrWTeuBMtUcyL4vTBY6Zk6AMIQji/9P6zJQMbFLlogRS5Xblq +6/CpJEGOSQO+C1XPrHdo7VSuVUDdMcQ64teG1dXkXlvOntqhkFjhs3ymhxW9Ome5 +qyneT68ImIlFYo/bWy4r6Jc1ovxPz2N9VqBR3T+ykKaboJuek42dkrLtNtXh8eOX +3A== +-----END CERTIFICATE----- diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-key.pem new file mode 100644 index 00000000000..8fd071e0e49 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-key.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIoZ6d4mqaZJgCAggA +MBQGCCqGSIb3DQMHBAjIgOrp5hZNzwSCBMjN+4OCjg+nTVC3WPMEHePoX4Utg7nv +KymusJKn1Uh6tuVjP3JJtxQUtFblEeeeNtFGH7voDbW/BUFWJMgwleNdH6yeB4jw +8AaSFNB325sUKTK4jzzVJPPbV2zf59ZnJN334RqlcJIMc4ptd/L2kvZhkEhQmAXW +z70lz1ufz498vdeFu1FvyC2TQInHglCVbJBBde+hxVe66O2/ztjzpYhYEvPrPaGm +TWjEdBsd1bpcspsbXhGd+gyA23S+Tg3VHXooLFW8C5AFFBVyEn8f7dv3ThGLCrG8 +/bkBr+WegR6r/etNwIGeXerdGzS+NMZZ2t0x7eoAAJetUtj4YJHWcaInvRlB8bJ/ +dJ64q6iOjACecIk17+DOksqjnxX8d2xTRxVd41wMMPoJ0rw/Se6fPty2Iyz+z+pK +XahP6Nj/TpXwnqvB44tMiWHENTN6+HbWecFyCVHcx1NOsWex50JZbsufsmwffi6H +Sk8tDuz+NseFnkbT1dDJirO/PkMaGk9+YqC9Hi/+prXFowcSKC0xrzuoz3PghxD9 +XoAdDhU3OGEfegwWT4GMQM4bOhiT2TOMmpoPuyi2bhtb/0v2pj3OaDxqUku9GBfK ++W7KSmRVLbHJkTZoLPaFtXvk0qOP6b6LH/bevMuPEz2YKiyhb8JDrIIspn/CfjJA +DbIINBH0d3HNUduX4+GhIKAKDJenciTQXAwA6wjsxIpEwb7jvgup+o+7cAW2GcWu +mQCrpRQDwM0jU/ATFx/aAJoTJjwEESn0h2AhZfnTbx4d0Re9tjzm2CwOvr6ZPc3H +eQzuC5Z+fksITab2ZG+s++qV09cUqlwjCm73ISVyqkajv774YjDSYTDw77wB6Xu7 +7i7mKDXGqGdUgaIry6wMmJI+dumMArzBtcG0AGI8f/WvpK5R50q5Msx0fS4aBva7 +QDcqWfz89yIjJvxW6R+56PsZDV4uOSwFfSMqizNVc1fwoGmgLmPx2ACqxksIetX1 +7rvd1OZG2Q5Mmbs2VX9+LPWgXQkOvW2OL7Ywr6oWdlsOyNWzUaZFkhmKLnTqT9kG +hzt64fR4XZMrSpCHNFhECve2GCMqQDzUaoNwOFM5t6G9xSbHfZlA6AvE4fS1so7r +NiEycl/JBwatJyYHw8OpN4Honry/OHJONj95Hl3LUL4s1YXuXyOFsovPDH1ot5t6 +tLSiK1ggdpi8nxQY7j86beu1JGOMVoZF15RGPbam8HoGJM93iCe6yI+pEa9rytfy +PFg6QscmaAe5oA2Aw3HTjTcyz4sKOct8mYkbWdSgoRLhN4fXM+5/lgTolBpsrFVZ +4bxkFmkRlc5CDBpGkY/4j4AsXiKZSsB+iX3abQvXL4f1YFqggFLBLVEtaECcarfN +dINQJCQvfK79ZBuMYZAieAoiuF7CEPDQCfwRJ8H/35JdcnXg3vEusKhapEfJg+Dg +xbNJc9Vlzta/ABTaj4nxKFXGWJEY/IYcWwM2NN+SdrEwzoykrOUGkwIrCVqshXZx +bgN8qnt6D9OPlm5xos12RGwmlDIenmQMt+aG7RXGOWVa0nmv/VTVkLmRfrBcEJ6F +XYsKJ6oz2vgItlKoZLDpjiRB+ENbRwfJy1Hd6lPTi/a8bw9izyEQXef3X3pT9YfM +Tow= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-openssl.cnf new file mode 100644 index 00000000000..db7236074bd --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-openssl.cnf @@ -0,0 +1,242 @@ +# +# Based on the OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +#CRLDISTPT = [CRL Distribution Point; e.g., http://crl-list.base/w4edom-l4.base.crl] +CRLDISTPT = http://www.samba.example.com/crls/CA-samba.example.com-crl.crl + +# Extra OBJECT IDENTIFIER info: +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] +# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used as a login credential +scardLogin=1.3.6.1.4.1.311.20.2.2 +# Used in a smart card login certificate's subject alternative name +msUPN=1.3.6.1.4.1.311.20.2.3 +# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used to identify a domain controller +msKDC=1.3.6.1.5.2.3.5 +# Identifies the AD GUID +msADGUID=1.3.6.1.4.1.311.25.1 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = CA-samba.example.com # Where everything is kept +certs = $dir/_none_certs # Where the issued certs are kept +crl_dir = $dir/_none_crl # Where the issued crl are kept +database = $dir/Private/CA-samba.example.com-index.txt # database index file. +unique_subject = yes # Set to 'no' to allow creation of + # several certificates with same subject. +new_certs_dir = $dir/NewCerts # default place for new certs. + +certificate = $dir/Public/CA-samba.example.com-cert.pem # The CA certificate +serial = $dir/Private/CA-samba.example.com-serial.txt # The current serial number +crlnumber = $dir/Private/CA-samba.example.com-crlnumber.txt # the current crl number + # must be commented out to leave a V1 CRL + +#crl = $dir/Public/CA-samba.example.com-crl.pem # The current CRL +crl = $dir/Public/CA-samba.example.com-crl.crl # The current CRL +private_key = $dir/Private/CA-samba.example.com-private-key.pem # The private key +RANDFILE = $dir/Private/CA-samba.example.com.rand # private random number file + +#x509_extensions = # The extensions to add to the cert +x509_extensions = template_x509_extensions + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +crl_extensions = crl_ext + +default_days = 7300 # how long to certify for +default_crl_days= 7300 # how long before next CRL +default_md = sha256 # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = match +stateOrProvinceName = match +localityName = match +organizationName = match +organizationalUnitName = match +commonName = supplied +emailAddress = supplied + +#################################################################### +[ req ] +default_bits = 2048 +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extensions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = US +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = SambaState + +localityName = Locality Name (eg, city) +localityName_default = SambaCity + +organizationName = Organization Name (eg, company) +organizationName_default = SambaSelfTesting + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = Users + +commonName = Common Name (eg, YOUR name) +commonName_default = administrator@samba.example.com +commonName_max = 64 + +emailAddress = Email Address +emailAddress_default = administrator@samba.example.com +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +#challengePassword = A challenge password +#challengePassword_min = 4 +#challengePassword_max = 20 +# +#unstructuredName = An optional company name + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] +# Extensions for a typical CA +# PKIX recommendation. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. +keyUsage = cRLSign, keyCertSign + +crlDistributionPoints=URI:$CRLDISTPT + +# Some might want this also +nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +subjectAltName=email:copy +# Copy issuer details +issuerAltName=issuer:copy + +[ crl_ext ] +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +#[ usr_cert_scarduser ] +[ template_x509_extensions ] + +# These extensions are added when 'ca' signs a request for a certificate that will be used to login from a smart card + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE +crlDistributionPoints=URI:$CRLDISTPT + +# For normal client use this is typical +nsCertType = client, email + +# This is typical in keyUsage for a client certificate. +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "Smart Card Login Certificate for administrator@samba.example.com" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. + +subjectAltName=email:copy,otherName:msUPN;UTF8:administrator@samba.example.com + +# Copy subject details +issuerAltName=issuer:copy + +nsCaRevocationUrl = $CRLDISTPT +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +#Extended Key requirements for client certs +extendedKeyUsage = clientAuth,scardLogin + diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-private-key.pem new file mode 100644 index 00000000000..1d5ceeb2e14 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-private-key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAyQdEOl/2NF8ninpuL/tFH8M93SxDZfF6KT9CJr3/T12RwLt1 +44EUfVlyeJYaXo2Vk/RdknkOJHdPiwhOcrGZiGMGdLLc94Ji6d1v5ae0yUQM5ENB ++FepILFwwXahSFvpVLZPIlCTkPBiMlCabiJrN6D3H/yxX67iC4ht6im2ASeyhO8Q +TWwK3+qpioKYYKdSc6T3fLJKufCbxPgZWsCEVFI1yJJPFq/WNqZ4V1XlXmtiAPpI +wnrnFzi1I9Wo+33fQlwD9Hzv//Gg5tgnkwazoyFoDsRgIAJGLyvYiOQrAcIxWlUo +vlUD8gYr5OxIYOS226HwxSS64ajiavsLQGw99QIDAQABAoIBAFcGeUfYEQpdAw4U +sCy/Vw5IBDkCF29DWUIP64BAEg12kUlhHcjOMWOOXFrNiD7UhiNVz0hAdZnduKaU +gvlt3uxHCh1s7PGNFWrufKlrr3zNo9MRNrbepA3OIuTtiSZ8+4a7oYhWX3uIRMpJ +UIFLDyU23qSPTO4CFEMv3X1Ybz0SALtUxZr5fwtAOn/EdiqSQzF65tBe0OzMWzfc +Jm1Uvv3H/Dm8intOUMDQk+8KmQSp/Mj1Fwi4jU77WbZWXmAuDE1bQ6TSUHUBYBdp +FgmRPk8gcOOHNjvEa62hZ2KIyKixjXoRKm9Sxr3jeZWG9QZcJFyVRMH37wa9vU8U +d9lszkUCgYEA7ZkeFNO7ISqi4G5VeaTiZFMtGwHBUHYU30ccPg5T1gNNb0rOo17Y +BOuqPE3HbqsfRiN1jTIkEE68ngP1VCE9H7WQ1pxMZSqBIotgGqZLFBkvbKTnlCNL +dAtgTFQbZuBP/M/JN8g934kgjn33LOfPKoCzCnO9XZwEKVyRivQBV48CgYEA2JkT +wVvLxB6NgshStjLBcLbeIPADT24xcH7Wyr7WoSx+F/J0q3nT5qHAFmVDttFMujc2 +EVBeJclMxmC529O+SPid8X3/Y9BqOwSzBdFIEBw0xbv0ntgCr0qYNHkkqqvvDNCm +4VsIOeNi4YvNwHFuUB4+7upAkG/khGORJnIJ8DsCgYEAiG9Rb8I5hY0XJGsXGBgP +jG6ayxRR7qMvzxrlY9kUWSNiVtMNH5D52LF++svrBmirN7pq6R5uyRJ9ivtY5+uC +TvAS8LmlwL4Mk0qXcBYnrK3dprR26oDt9gAGVy5A4e1S4ShsMmUA6piyokBBLH8c +XhqzNQBLMDLDzQCD7te44Y8CgYEAnVYlCZIa5G2lMdk+a+dWqP/NP3PZk7th4mvg +rwoNcqqVNeQDaARpLuFUXXBVzdkfuS0d81nD6gLd6ESe/dZEJVGjuaZi/CiK4jA5 +swIhLMKweupbeX9EA/1VrthJEEkwrshqUM0FnrdUPq6FWUOMdFpkMLytBb6h6qFA +8QJpwb0CgYEA11acodjgxuuLPOOxUG7sl++ZNT8/2Upx02QbPknJ/Hmu63CHv2qL +HxGvsynw3ardm9flgbpxSuU5K2ntQjo64SfZxgTC5z5Oqr0m6oIoMutQTNvTnbtm +AhQ9V9Z795DcLaDDNAQB3LmEvQWT5FSDSdi2lLXzQWlHf//VGDIipjE= +-----END RSA PRIVATE KEY----- diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-req.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-req.pem new file mode 100644 index 00000000000..7c2f1630908 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-req.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIDATCCAekCAQAwgbsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTYW1iYVN0YXRl +MRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNhbWJhU2VsZlRlc3Rpbmcx +DjAMBgNVBAsMBVVzZXJzMSgwJgYDVQQDDB9hZG1pbmlzdHJhdG9yQHNhbWJhLmV4 +YW1wbGUuY29tMS4wLAYJKoZIhvcNAQkBFh9hZG1pbmlzdHJhdG9yQHNhbWJhLmV4 +YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyQdEOl/2 +NF8ninpuL/tFH8M93SxDZfF6KT9CJr3/T12RwLt144EUfVlyeJYaXo2Vk/RdknkO +JHdPiwhOcrGZiGMGdLLc94Ji6d1v5ae0yUQM5ENB+FepILFwwXahSFvpVLZPIlCT +kPBiMlCabiJrN6D3H/yxX67iC4ht6im2ASeyhO8QTWwK3+qpioKYYKdSc6T3fLJK +ufCbxPgZWsCEVFI1yJJPFq/WNqZ4V1XlXmtiAPpIwnrnFzi1I9Wo+33fQlwD9Hzv +//Gg5tgnkwazoyFoDsRgIAJGLyvYiOQrAcIxWlUovlUD8gYr5OxIYOS226HwxSS6 +4ajiavsLQGw99QIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAGx2x4siii0Z5wAL +u/UPPTQqqKvOdtAGpQzeT/pBw1ttXq8G3tgSJ4H0KAcqFfUFdjTVqMbzSGFF3InX +uop0fkZIG4A5uMKNget2atlP6BUejlVoHWA2Tyuioo+iYDAosN9fI3RkgOgEl4T2 +fwcOkae2uTVTUloDaBfzQNPRd86RCHVEYc+PSjVfNUoTjRug/BhR+7ZOTcDRFQ4N +61LeMll9j/ooFEYgpfXBygoDpx44mEH69c/7aLjydq/nLMKbCtNG7NYDAEUbruB4 +D48JYBDHB/1XqzvIYwmXLAdlZ3prNaF+c/O7KHqa+R2kilZ+YvhUuyuHLEMecNsD +owjRHmw= +-----END CERTIFICATE REQUEST----- diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-cert.pem new file mode 120000 index 00000000000..3b134b6f698 --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-cert.pem @@ -0,0 +1 @@ +USER-administrator@samba.example.com-S01-cert.pem
\ No newline at end of file diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-private-key.pem new file mode 120000 index 00000000000..964892eba9c --- /dev/null +++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-private-key.pem @@ -0,0 +1 @@ +USER-administrator@samba.example.com-S01-private-key.pem
\ No newline at end of file diff --git a/selftest/manage-ca/manage-CA-samba.example.com.cnf b/selftest/manage-ca/manage-CA-samba.example.com.cnf new file mode 100644 index 00000000000..65c9b95ecbe --- /dev/null +++ b/selftest/manage-ca/manage-CA-samba.example.com.cnf @@ -0,0 +1,21 @@ +# +# All passwords are "1234" +# + +CRL_HTTP_BASE="http://www.samba.example.com/crls" +CRL_SSH_BASE="none@samba.example.com:/none/crls" +DNS_DOMAIN="samba.example.com" + +CA_BITS="8192" +DC_BITS="4096" +USER_BITS="2048" +# 20 years should be enough +CA_DAYS="7300" +CRL_DAYS="7300" +DC_DAYS="7300" +USER_DAYS="7300" + +COUNTRY_NAME="US" +STATE_NAME="SambaState" +LOCALITY_NAME="SambaCity" +ORGANIZATION_NAME="SambaSelfTesting" diff --git a/selftest/manage-ca/manage-CA-samba.example.com.sh b/selftest/manage-ca/manage-CA-samba.example.com.sh new file mode 100644 index 00000000000..449a58a4bcf --- /dev/null +++ b/selftest/manage-ca/manage-CA-samba.example.com.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# + +set -e +set -u +set -x + +# +# All passwords are "1234" +# + +# DONE # ./manage-ca.sh manage-CA-samba.example.com.cnf init_ca +# DONE # +# DONE # ./manage-ca.sh manage-CA-samba.example.com.cnf create_dc localdc.samba.example.com 0123456789ABCDEF +# DONE # ./manage-ca.sh manage-CA-samba.example.com.cnf create_user administrator@samba.example.com +# DONE # +# DONE # ./manage-ca.sh manage-CA-samba.example.com.cnf create_dc plugindc.plugindom.samba.example.com 0123456789ABCDEF +# DONE # ./manage-ca.sh manage-CA-samba.example.com.cnf create_user administrator@plugindom.samba.example.com diff --git a/selftest/manage-ca/manage-ca.sh b/selftest/manage-ca/manage-ca.sh new file mode 100755 index 00000000000..ab796b718af --- /dev/null +++ b/selftest/manage-ca/manage-ca.sh @@ -0,0 +1,387 @@ +#!/bin/bash +# + +set -e +set -u +#set -x + +umask 022 + +function print_usage() +{ + echo "Usage:" + echo "" + echo "${0} <CNF_FILE> <CMD> [<ARG1> [<ARG2>]]" + echo "" + echo "${0} <CNF_FILE> init_ca" + echo "${0} <CNF_FILE> update_crl" + echo "${0} <CNF_FILE> publish_crl" + echo "${0} <CNF_FILE> create_dc <DC_DNS_NAME> <DC_OBJECTGUID_HEX>" + echo "${0} <CNF_FILE> revoke_dc <DC_DNS_NAME> <REVOKE_RESON>" + echo "${0} <CNF_FILE> create_user <USER_PRINCIPAL_NAME>" + echo "${0} <CNF_FILE> revoke_user <USER_PRINCIPAL_NAME> <REVOKE_RESON>" + echo "" +} + +function check_arg() +{ + local k="${1}" + local v="${2}" + + test -n "${v}" || { + print_usage + echo "ERROR: CMD[${CMD}] argument <${k}> missing" + return 1 + } + + return 0 +} +CNF="${1-}" +test -n "${CNF}" || { + print_usage + echo "ERROR: speficy <CNF_FILE> see manage-ca.templates.d/manage-CA-example.com.cnf" + exit 1 +} +test -e "${CNF}" || { + print_usage + echo "ERROR: CNF_FILE[${CNF}] does not exist" + exit 1 +} +CMD="${2-}" +CMDARG1="${3-}" +CMDARG2="${4-}" + +TEMPLATE_DIR="manage-ca.templates.d" +DEFAULT_VARS="" +DEFAULT_VARS="${DEFAULT_VARS} CRL_HTTP_BASE DNS_DOMAIN DEFAULT_BITS" +DEFAULT_VARS="${DEFAULT_VARS} DEFAULT_BITS DEFAULT_DAYS DEFAULT_CRL_DAYS" +DEFAULT_VARS="${DEFAULT_VARS} COUNTRY_NAME STATE_NAME LOCALITY_NAME ORGANIZATION_NAME" +DEFAULT_VARS="${DEFAULT_VARS} ORGANIZATIONAL_UNIT_NAME COMMON_NAME EMAIL_ADDRESS" + +source "${CNF}" + +DEFAULT_BITS=${DEFAULT_BITS:=8192} +CA_BITS=${CA_BITS:=${DEFAULT_BITS}} +DC_BITS=${DC_BITS:=${DEFAULT_BITS}} +USER_BITS=${USER_BITS:=${DEFAULT_BITS}} + +CA_DAYS=${CA_DAYS:=3650} +CRL_DAYS=${CRL_DAYS:=30} +DC_DAYS=${DC_DAYS:=730} +USER_DAYS=${USER_DAYS:=730} + +CA_DIR="CA-${DNS_DOMAIN}" +DEFAULT_VARS="${DEFAULT_VARS} CA_DIR" + +CACERT_PEM="${CA_DIR}/Public/CA-${DNS_DOMAIN}-cert.pem" +CACERT_CER="${CA_DIR}/Public/CA-${DNS_DOMAIN}-cert.cer" +CACRL_PEM="${CA_DIR}/Public/CA-${DNS_DOMAIN}-crl.pem" +CACRL_CRL="${CA_DIR}/Public/CA-${DNS_DOMAIN}-crl.crl" +CA_SERIAL="${CA_DIR}/Private/CA-${DNS_DOMAIN}-serial.txt" + +function generate_from_template() +{ + local base_template="${TEMPLATE_DIR}/$1" + local cmd_template="${TEMPLATE_DIR}/$2" + local cnf_file="$3" + shift 3 + local vars="$@" + + test -f "${base_template}" || { + echo "base_template[${base_template}] does not exists" + return 1 + } + test -f "${cmd_template}" || { + echo "cmd_template[${cmd_template}] does not exists" + return 1 + } + test -e "${cnf_file}" && { + echo "cnf_file[${cnf_file}] already exists" + return 1 + } + + local sedargs="" + for k in $vars; do + v=$(eval echo "\${${k}}") + sedargs="${sedargs} -e 's!@@${k}@@!${v}!g'" + done + + #echo "sedargs[${sedargs}]" + cat "${base_template}" "${cmd_template}" | eval sed ${sedargs} > "${cnf_file}" + grep '@@' "${cnf_file}" | wc -l | grep -q '^0' || { + echo "invalid context in cnf_file[${cnf_file}]" + grep '@@' "${cnf_file}" + return 1 + } + + return 0 +} + +case "${CMD}" in +init_ca) + test -e "${CA_DIR}" && { + echo "CA with CA_DIR[${CA_DIR}] already exists" + exit 1 + } + + OPENSSLCNF="${CA_DIR}/Private/CA-${DNS_DOMAIN}-openssl.cnf" + CA_INDEX="${CA_DIR}/Private/CA-${DNS_DOMAIN}-index.txt" + CA_CRLNUMBER="${CA_DIR}/Private/CA-${DNS_DOMAIN}-crlnumber.txt" + PRIVATEKEY="${CA_DIR}/Private/CA-${DNS_DOMAIN}-private-key.pem" + + ORGANIZATIONAL_UNIT_NAME="CA Administration" + COMMON_NAME="CA of ${DNS_DOMAIN}" + EMAIL_ADDRESS="ca-${DNS_DOMAIN}@${DNS_DOMAIN}" + + DEFAULT_BITS="${CA_BITS}" + DEFAULT_DAYS="1" + DEFAULT_CRL_DAYS="${CRL_DAYS}" + + mkdir -p "${CA_DIR}/"{,Public} + umask 077 + mkdir -p "${CA_DIR}/"{,Private,NewCerts,DCs,Users} + umask 022 + touch "${CA_INDEX}" + echo "00" > "${CA_SERIAL}" + echo "00" > "${CA_CRLNUMBER}" + + generate_from_template \ + "openssl-BASE-template.cnf" \ + "openssl-CA-template.cnf" \ + "${OPENSSLCNF}" \ + ${DEFAULT_VARS} + openssl req -new -x509 -sha256 -extensions v3_ca -days "${CA_DAYS}" -keyout "${PRIVATEKEY}" -out "${CACERT_PEM}" -config "${OPENSSLCNF}" + openssl x509 -in "${CACERT_PEM}" -inform PEM -out "${CACERT_CER}" -outform DER + echo -n "Generate CRL [ENTER] to continue" + read + openssl ca -config "${OPENSSLCNF}" -gencrl -out "${CACRL_PEM}" + openssl crl -in "${CACRL_PEM}" -inform PEM -out "${CACRL_CRL}" -outform DER + ls -la "${CA_DIR}"/Public/CA-* + echo "Please run: '${0} ${CNF} publish_crl'" + exit 0 + ;; +update_crl) + test -e "${CA_DIR}" || { + echo "CA with CA_DIR[${CA_DIR}] does not exists" + exit 1 + } + + OPENSSLCNF="${CA_DIR}/Private/CA-${DNS_DOMAIN}-openssl.cnf" + openssl ca -config "${OPENSSLCNF}" -gencrl -out "${CACRL_PEM}" + openssl crl -in "${CACRL_PEM}" -inform PEM -out "${CACRL_CRL}" -outform DER + ls -la "${CACRL_PEM}" "${CACRL_CRL}" + echo "Please run: '${0} ${CNF} publish_crl'" + exit 0 + ;; +publish_crl) + test -e "${CA_DIR}" || { + echo "CA with CA_DIR[${CA_DIR}] does not exists" + exit 1 + } + + echo "Upload ${CACRL_CRL} to ${CRL_SSH_BASE}/" + rsync -a -P "${CACRL_CRL}" "${CRL_SSH_BASE}/" + echo "Check ${CRL_HTTP_BASE}/CA-${DNS_DOMAIN}-crl.crl" + exit 0 + ;; +create_dc) + test -e "${CA_DIR}" || { + echo "CA with CA_DIR[${CA_DIR}] does not exists" + exit 1 + } + # + # + # ldbsearch -H ldap://DC_DNS_NAME '(dnsHostName=DC_DNS_NAME)' distinguishedName --controls=search_options:1:1 --controls=extended_dn:1:0 + DC_DNS_NAME="${CMDARG1}" + check_arg "DC_DNS_NAME" "${DC_DNS_NAME}" + DC_OBJECTGUID_HEX=$(echo "${CMDARG2}" | tr a-z A-Z) + check_arg "DC_OBJECTGUID_HEX" "${DC_OBJECTGUID_HEX}" + + DC_DIR="${CA_DIR}/DCs/${DC_DNS_NAME}" + test -e "${DC_DIR}" && { + echo "DC with DC_DIR[${DC_DIR}] already exists" + exit 1 + } + + NEXT_SERIAL=$(cat "${CA_SERIAL}" | xargs) + DCFILE_BASE="DC-${DC_DNS_NAME}-S${NEXT_SERIAL}" + OPENSSLCNF="${DC_DIR}/${DCFILE_BASE}-openssl.cnf" + DCKEY_PEM="${DC_DIR}/${DCFILE_BASE}-key.pem" + DCKEY_PRIVATE_PEM="${DC_DIR}/${DCFILE_BASE}-private-key.pem" + DCKEY_PRIVATE_PEM_BASE="${DCFILE_BASE}-private-key.pem" + DCKEY_PRIVATE_PEM_LINK="${DC_DIR}/DC-${DC_DNS_NAME}-private-key.pem" + DCREQ_PEM="${DC_DIR}/${DCFILE_BASE}-req.pem" + DCCERT_PEM="${DC_DIR}/${DCFILE_BASE}-cert.pem" + DCCERT_PEM_BASE="${DCFILE_BASE}-cert.pem" + DCCERT_PEM_LINK="${DC_DIR}/DC-${DC_DNS_NAME}-cert.pem" + DCCERT_CER="${DC_DIR}/${DCFILE_BASE}-cert.cer" + DCCERT_P12="${DC_DIR}/${DCFILE_BASE}-private.p12" + + ORGANIZATIONAL_UNIT_NAME="Domain Controllers" + COMMON_NAME="${DC_DNS_NAME}" + EMAIL_ADDRESS="ca-${DNS_DOMAIN}@${DNS_DOMAIN}" + + DEFAULT_BITS="${DC_BITS}" + DEFAULT_DAYS="${DC_DAYS}" + DEFAULT_CRL_DAYS="${CRL_DAYS}" + + umask 077 + mkdir -p "${DC_DIR}/" + + generate_from_template \ + "openssl-BASE-template.cnf" \ + "openssl-DC-template.cnf" \ + "${OPENSSLCNF}" \ + ${DEFAULT_VARS} DC_DNS_NAME DC_OBJECTGUID_HEX + + openssl req -new -newkey rsa -keyout "${DCKEY_PEM}" -out "${DCREQ_PEM}" -config "${OPENSSLCNF}" + openssl rsa -in "${DCKEY_PEM}" -inform PEM -out "${DCKEY_PRIVATE_PEM}" -outform PEM + openssl ca -config "${OPENSSLCNF}" -in "${DCREQ_PEM}" -out "${DCCERT_PEM}" + ln -s "${DCKEY_PRIVATE_PEM_BASE}" "${DCKEY_PRIVATE_PEM_LINK}" + ln -s "${DCCERT_PEM_BASE}" "${DCCERT_PEM_LINK}" + openssl x509 -in "${DCCERT_PEM}" -inform PEM -out "${DCCERT_CER}" -outform DER + echo "Generate ${DCCERT_P12}" + openssl pkcs12 -in "${DCCERT_PEM}" -inkey "${DCKEY_PRIVATE_PEM}" -export -out "${DCCERT_P12}" + ls -la "${DC_DIR}"/*.* + exit 0 + ;; +revoke_dc) + test -e "${CA_DIR}" || { + echo "CA with CA_DIR[${CA_DIR}] does not exists" + exit 1 + } + DC_DNS_NAME="${CMDARG1}" + check_arg "DC_DNS_NAME" "${DC_DNS_NAME}" + REVOKE_REASON="${CMDARG2}" + check_arg "REVOKE_REASON" "${REVOKE_REASON}" + + DC_DIR="${CA_DIR}/DCs/${DC_DNS_NAME}" + test -e "${DC_DIR}" || { + echo "DC with DC_DIR[${DC_DIR}] does not exists" + exit 1 + } + + OPENSSLCNF="${CA_DIR}/Private/CA-${DNS_DOMAIN}-openssl.cnf" + DCKEY_PRIVATE_PEM_LINK="${DC_DIR}/DC-${DC_DNS_NAME}-private-key.pem" + DCCERT_PEM_LINK="${DC_DIR}/DC-${DC_DNS_NAME}-cert.pem" + + REVOKE_DATE=$(date +%Y%m%d-%H%M%S) + REVOKE_DC_DIR="${DC_DIR}.${REVOKE_DATE}.revoked-${REVOKE_REASON}" + + openssl ca -config "${OPENSSLCNF}" -revoke "${DCCERT_PEM_LINK}" -crl_reason "${REVOKE_REASON}" + + mv "${DCKEY_PRIVATE_PEM_LINK}" "${DCKEY_PRIVATE_PEM_LINK}.revoked" + mv "${DCCERT_PEM_LINK}" "${DCCERT_PEM_LINK}.revoked" + mv "${DC_DIR}" "${REVOKE_DC_DIR}" + echo "${REVOKE_DC_DIR}" + + openssl ca -config "${OPENSSLCNF}" -gencrl -out "${CACRL_PEM}" + openssl crl -in "${CACRL_PEM}" -inform PEM -out "${CACRL_CRL}" -outform DER + ls -la "${CACRL_PEM}" "${CACRL_CRL}" + echo "Please run: '${0} ${CNF} publish_crl'" + exit 0 + ;; +create_user) + test -e "${CA_DIR}" || { + echo "CA with CA_DIR[${CA_DIR}] does not exists" + exit 1 + } + USER_PRINCIPAL_NAME="${CMDARG1}" + check_arg "USER_PRINCIPAL_NAME" "${USER_PRINCIPAL_NAME}" + + USER_DIR="${CA_DIR}/Users/${USER_PRINCIPAL_NAME}" + test -e "${USER_DIR}" && { + echo "USER with USER_DIR[${USER_DIR}] already exists" + exit 1 + } + + NEXT_SERIAL=$(cat "${CA_SERIAL}" | xargs) + USERFILE_BASE="USER-${USER_PRINCIPAL_NAME}-S${NEXT_SERIAL}" + OPENSSLCNF="${USER_DIR}/${USERFILE_BASE}-openssl.cnf" + USERKEY_PEM="${USER_DIR}/${USERFILE_BASE}-key.pem" + USERKEY_PRIVATE_PEM="${USER_DIR}/${USERFILE_BASE}-private-key.pem" + USERKEY_PRIVATE_PEM_BASE="${USERFILE_BASE}-private-key.pem" + USERKEY_PRIVATE_PEM_LINK="${USER_DIR}/USER-${USER_PRINCIPAL_NAME}-private-key.pem" + USERREQ_PEM="${USER_DIR}/${USERFILE_BASE}-req.pem" + USERCERT_PEM="${USER_DIR}/${USERFILE_BASE}-cert.pem" + USERCERT_PEM_BASE="${USERFILE_BASE}-cert.pem" + USERCERT_PEM_LINK="${USER_DIR}/USER-${USER_PRINCIPAL_NAME}-cert.pem" + USERCERT_CER="${USER_DIR}/${USERFILE_BASE}-cert.cer" + USERCERT_P12="${USER_DIR}/${USERFILE_BASE}-private.p12" + + ORGANIZATIONAL_UNIT_NAME="Users" + COMMON_NAME="${USER_PRINCIPAL_NAME}" + EMAIL_ADDRESS="${USER_PRINCIPAL_NAME}" + + DEFAULT_BITS="${USER_BITS}" + DEFAULT_DAYS="${USER_DAYS}" + DEFAULT_CRL_DAYS="${CRL_DAYS}" + + umask 077 + mkdir -p "${USER_DIR}/" + + generate_from_template \ + "openssl-BASE-template.cnf" \ + "openssl-USER-template.cnf" \ + "${OPENSSLCNF}" \ + ${DEFAULT_VARS} USER_PRINCIPAL_NAME + + openssl req -new -newkey rsa -keyout "${USERKEY_PEM}" -out "${USERREQ_PEM}" -config "${OPENSSLCNF}" + openssl rsa -in "${USERKEY_PEM}" -inform PEM -out "${USERKEY_PRIVATE_PEM}" -outform PEM + openssl ca -config "${OPENSSLCNF}" -in "${USERREQ_PEM}" -out "${USERCERT_PEM}" + ln -s "${USERKEY_PRIVATE_PEM_BASE}" "${USERKEY_PRIVATE_PEM_LINK}" + ln -s "${USERCERT_PEM_BASE}" "${USERCERT_PEM_LINK}" + openssl x509 -in "${USERCERT_PEM}" -inform PEM -out "${USERCERT_CER}" -outform DER + echo "Generate ${USERCERT_P12}" + openssl pkcs12 -in "${USERCERT_PEM}" -inkey "${USERKEY_PRIVATE_PEM}" -export -out "${USERCERT_P12}" + ls -la "${USER_DIR}"/*.* + exit 0 + ;; +revoke_user) + test -e "${CA_DIR}" || { + echo "CA with CA_DIR[${CA_DIR}] does not exists" + exit 1 + } + USER_PRINCIPAL_NAME="${CMDARG1}" + check_arg "USER_PRINCIPAL_NAME" "${USER_PRINCIPAL_NAME}" + REVOKE_REASON="${CMDARG2}" + check_arg "REVOKE_REASON" "${REVOKE_REASON}" + + USER_DIR="${CA_DIR}/Users/${USER_PRINCIPAL_NAME}" + test -e "${USER_DIR}" || { + echo "USER with USER_DIR[${USER_DIR}] does not exists" + exit 1 + } + + OPENSSLCNF="${CA_DIR}/Private/CA-${DNS_DOMAIN}-openssl.cnf" + USERKEY_PRIVATE_PEM_LINK="${USER_DIR}/USER-${USER_PRINCIPAL_NAME}-private-key.pem" + USERCERT_PEM_LINK="${USER_DIR}/USER-${USER_PRINCIPAL_NAME}-cert.pem" + + REVOKE_DATE=$(date +%Y%m%d-%H%M%S) + REVOKE_USER_DIR="${USER_DIR}.${REVOKE_DATE}.revoked-${REVOKE_REASON}" + + openssl ca -config "${OPENSSLCNF}" -revoke "${USERCERT_PEM_LINK}" -crl_reason "${REVOKE_REASON}" + + mv "${USERKEY_PRIVATE_PEM_LINK}" "${USERKEY_PRIVATE_PEM_LINK}.revoked" + mv "${USERCERT_PEM_LINK}" "${USERCERT_PEM_LINK}.revoked" + mv "${USER_DIR}" "${REVOKE_USER_DIR}.revoked" + echo "${REVOKE_USER_DIR}" + + openssl ca -config "${OPENSSLCNF}" -gencrl -out "${CACRL_PEM}" + openssl crl -in "${CACRL_PEM}" -inform PEM -out "${CACRL_CRL}" -outform DER + ls -la "${CACRL_PEM}" "${CACRL_CRL}" + echo "Please run: '${0} ${CNF} publish_crl'" + exit 0 + ;; +usage) + print_usage + exit 1 + ;; +*) + print_usage + echo "ERROR: CMD[${CMD}] - unknown" + exit 1 + ;; +esac + +exit 1 diff --git a/selftest/manage-ca/manage-ca.templates.d/manage-CA-example.com.cnf b/selftest/manage-ca/manage-ca.templates.d/manage-CA-example.com.cnf new file mode 100644 index 00000000000..1f3d24ef29b --- /dev/null +++ b/selftest/manage-ca/manage-ca.templates.d/manage-CA-example.com.cnf @@ -0,0 +1,17 @@ + +CRL_HTTP_BASE="http://www.example.com/crls" +CRL_SSH_BASE="www.example.com:/path/to/crls" +DNS_DOMAIN="example.com" + +#CA_BITS="8192" +#DC_BITS="8192" +#USER_BITS="8192" +#CA_DAYS="3650" +#CRL_DAYS="30" +#DC_DAYS="730" +#USER_DAYS="730" + +COUNTRY_NAME="US" +STATE_NAME="ExampleState" +LOCALITY_NAME="ExampleCity" +ORGANIZATION_NAME="ExampleOrganization" diff --git a/selftest/manage-ca/manage-ca.templates.d/openssl-BASE-template.cnf b/selftest/manage-ca/manage-ca.templates.d/openssl-BASE-template.cnf new file mode 100644 index 00000000000..ca8415b67d0 --- /dev/null +++ b/selftest/manage-ca/manage-ca.templates.d/openssl-BASE-template.cnf @@ -0,0 +1,201 @@ +# +# Based on the OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +#CRLDISTPT = [CRL Distribution Point; e.g., http://crl-list.base/w4edom-l4.base.crl] +CRLDISTPT = @@CRL_HTTP_BASE@@/CA-@@DNS_DOMAIN@@-crl.crl + +# Extra OBJECT IDENTIFIER info: +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] +# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used as a login credential +scardLogin=1.3.6.1.4.1.311.20.2.2 +# Used in a smart card login certificate's subject alternative name +msUPN=1.3.6.1.4.1.311.20.2.3 +# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used to identify a domain controller +msKDC=1.3.6.1.5.2.3.5 +# Identifies the AD GUID +msADGUID=1.3.6.1.4.1.311.25.1 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = @@CA_DIR@@ # Where everything is kept +certs = $dir/_none_certs # Where the issued certs are kept +crl_dir = $dir/_none_crl # Where the issued crl are kept +database = $dir/Private/CA-@@DNS_DOMAIN@@-index.txt # database index file. +unique_subject = yes # Set to 'no' to allow creation of + # several certificates with same subject. +new_certs_dir = $dir/NewCerts # default place for new certs. + +certificate = $dir/Public/CA-@@DNS_DOMAIN@@-cert.pem # The CA certificate +serial = $dir/Private/CA-@@DNS_DOMAIN@@-serial.txt # The current serial number +crlnumber = $dir/Private/CA-@@DNS_DOMAIN@@-crlnumber.txt # the current crl number + # must be commented out to leave a V1 CRL + +#crl = $dir/Public/CA-@@DNS_DOMAIN@@-crl.pem # The current CRL +crl = $dir/Public/CA-@@DNS_DOMAIN@@-crl.crl # The current CRL +private_key = $dir/Private/CA-@@DNS_DOMAIN@@-private-key.pem # The private key +RANDFILE = $dir/Private/CA-@@DNS_DOMAIN@@.rand # private random number file + +#x509_extensions = # The extensions to add to the cert +x509_extensions = template_x509_extensions + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +crl_extensions = crl_ext + +default_days = @@DEFAULT_DAYS@@ # how long to certify for +default_crl_days= @@DEFAULT_CRL_DAYS@@ # how long before next CRL +default_md = sha256 # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = match +stateOrProvinceName = match +localityName = match +organizationName = match +organizationalUnitName = match +commonName = supplied +emailAddress = supplied + +#################################################################### +[ req ] +default_bits = @@DEFAULT_BITS@@ +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extensions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = @@COUNTRY_NAME@@ +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = @@STATE_NAME@@ + +localityName = Locality Name (eg, city) +localityName_default = @@LOCALITY_NAME@@ + +organizationName = Organization Name (eg, company) +organizationName_default = @@ORGANIZATION_NAME@@ + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = @@ORGANIZATIONAL_UNIT_NAME@@ + +commonName = Common Name (eg, YOUR name) +commonName_default = @@COMMON_NAME@@ +commonName_max = 64 + +emailAddress = Email Address +emailAddress_default = @@EMAIL_ADDRESS@@ +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +#challengePassword = A challenge password +#challengePassword_min = 4 +#challengePassword_max = 20 +# +#unstructuredName = An optional company name + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] +# Extensions for a typical CA +# PKIX recommendation. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. +keyUsage = cRLSign, keyCertSign + +crlDistributionPoints=URI:$CRLDISTPT + +# Some might want this also +nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +subjectAltName=email:copy +# Copy issuer details +issuerAltName=issuer:copy + +[ crl_ext ] +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + diff --git a/selftest/manage-ca/manage-ca.templates.d/openssl-CA-template.cnf b/selftest/manage-ca/manage-ca.templates.d/openssl-CA-template.cnf new file mode 100644 index 00000000000..4c6bb4a8836 --- /dev/null +++ b/selftest/manage-ca/manage-ca.templates.d/openssl-CA-template.cnf @@ -0,0 +1,2 @@ +[ template_x509_extensions ] + diff --git a/selftest/manage-ca/manage-ca.templates.d/openssl-DC-template.cnf b/selftest/manage-ca/manage-ca.templates.d/openssl-DC-template.cnf new file mode 100644 index 00000000000..0b0424da27f --- /dev/null +++ b/selftest/manage-ca/manage-ca.templates.d/openssl-DC-template.cnf @@ -0,0 +1,49 @@ +#[ usr_cert_mskdc ] +[ template_x509_extensions ] + +# These extensions are added when 'ca' signs a request for a domain controller certificate. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE +crlDistributionPoints=URI:$CRLDISTPT + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +nsCertType = server + +# This is typical in keyUsage for a client certificate. +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "Domain Controller Certificate @@DC_DNS_NAME@@" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. + +subjectAltName=@dc_subjalt + +# Copy subject details +issuerAltName=issuer:copy + +nsCaRevocationUrl = $CRLDISTPT +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +#Extended Key requirements for our domain controller certs +# serverAuth - says cert can be used to identify an ssl/tls server +# msKDC - says cert can be used to identify a Kerberos Domain Controller. +extendedKeyUsage = clientAuth,serverAuth,msKDC + +[dc_subjalt] +DNS=@@DC_DNS_NAME@@ +otherName=msADGUID;FORMAT:HEX,OCTETSTRING:@@DC_OBJECTGUID_HEX@@ diff --git a/selftest/manage-ca/manage-ca.templates.d/openssl-USER-template.cnf b/selftest/manage-ca/manage-ca.templates.d/openssl-USER-template.cnf new file mode 100644 index 00000000000..71674b9c07c --- /dev/null +++ b/selftest/manage-ca/manage-ca.templates.d/openssl-USER-template.cnf @@ -0,0 +1,41 @@ +#[ usr_cert_scarduser ] +[ template_x509_extensions ] + +# These extensions are added when 'ca' signs a request for a certificate that will be used to login from a smart card + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE +crlDistributionPoints=URI:$CRLDISTPT + +# For normal client use this is typical +nsCertType = client, email + +# This is typical in keyUsage for a client certificate. +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "Smart Card Login Certificate for @@USER_PRINCIPAL_NAME@@" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. + +subjectAltName=email:copy,otherName:msUPN;UTF8:@@USER_PRINCIPAL_NAME@@ + +# Copy subject details +issuerAltName=issuer:copy + +nsCaRevocationUrl = $CRLDISTPT +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +#Extended Key requirements for client certs +extendedKeyUsage = clientAuth,scardLogin + diff --git a/selftest/selftest.pl b/selftest/selftest.pl index 1d5826da5ea..4d82b31487b 100755 --- a/selftest/selftest.pl +++ b/selftest/selftest.pl @@ -27,6 +27,7 @@ use Cwd qw(abs_path); use lib "$RealBin"; use Subunit; use SocketWrapper; +use target::Samba; eval { require Time::HiRes; @@ -505,6 +506,42 @@ sub write_clientconf($$$) mkdir("$clientdir/ncalrpcdir", 0755); umask $mask; + my $cadir = "$ENV{SRCDIR_ABS}/selftest/manage-ca/CA-samba.example.com"; + my $cacert = "$cadir/Public/CA-samba.example.com-cert.pem"; + my $cacrl_pem = "$cadir/Public/CA-samba.example.com-crl.pem"; + my $ca_users_dir = "$cadir/Users"; + + if ( -d "$clientdir/pkinit" ) { + unlink <$clientdir/pkinit/*>; + } else { + mkdir("$clientdir/pkinit", 0700); + } + + # each user has a USER-${USER_PRINCIPAL_NAME}-cert.pem and + # USER-${USER_PRINCIPAL_NAME}-private-key.pem symlink + # We make a copy here and make the certificated easily + # accessable in the client environment. + my $mask = umask; + umask 0077; + opendir USERS, "${ca_users_dir}" or die "Could not open dir '${ca_users_dir}': $!"; + for my $d (readdir USERS) { + my $user_dir = "${ca_users_dir}/${d}"; + next if ${d} =~ /^\./; + next if (! -d "${user_dir}"); + opendir USER, "${user_dir}" or die "Could not open dir '${user_dir}': $!"; + for my $l (readdir USER) { + my $user_link = "${user_dir}/${l}"; + next if ${l} =~ /^\./; + next if (! -l "${user_link}"); + + my $dest = "${clientdir}/pkinit/${l}"; + Samba::copy_file_content(${user_link}, ${dest}); + } + closedir USER; + } + closedir USERS; + umask $mask; + open(CF, ">$conffile"); print CF "[global]\n"; print CF "\tnetbios name = client\n"; @@ -538,6 +575,9 @@ sub write_clientconf($$$) #We don't want to run 'speed' tests for very long torture:timelimit = 1 winbind separator = / + tls cafile = ${cacert} + tls crlfile = ${cacrl_pem} + tls verify peer = no_check "; close(CF); } diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm index ccc63f3713d..dabe442c142 100644 --- a/selftest/target/Samba.pm +++ b/selftest/target/Samba.pm @@ -75,6 +75,111 @@ sub nss_wrapper_winbind_so_path($) { return $ret; } +sub copy_file_content($$) +{ + my ($in, $out) = @_; + open(IN, "${in}") or die("failed to open in[${in}] for reading: $!"); + open(OUT, ">${out}") or die("failed to open out[${out}] for writing: $!"); + while(<IN>) { + print OUT $_; + } + close(OUT); + close(IN); +} + +sub prepare_keyblobs($) +{ + my ($ctx) = @_; + + my $cadir = "$ENV{SRCDIR_ABS}/selftest/manage-ca/CA-samba.example.com"; + my $cacert = "$cadir/Public/CA-samba.example.com-cert.pem"; + my $cacrl_pem = "$cadir/Public/CA-samba.example.com-crl.pem"; + my $dcdnsname = "$ctx->{hostname}.$ctx->{dnsname}"; + my $dcdir = "$cadir/DCs/$dcdnsname"; + my $dccert = "$dcdir/DC-$dcdnsname-cert.pem"; + my $dckey_private = "$dcdir/DC-$dcdnsname-private-key.pem"; + my $userprincipalname = "administrator\@$ctx->{dnsname}"; + my $userdir = "$cadir/Users/$userprincipalname"; + my $usercert = "$userdir/USER-$userprincipalname-cert.pem"; + my $userkey_private = "$userdir/USER-$userprincipalname-private-key.pem"; + + my $tlsdir = "$ctx->{tlsdir}"; + my $pkinitdir = "$ctx->{prefix_abs}/pkinit"; + #TLS and PKINIT crypto blobs + my $dhfile = "$tlsdir/dhparms.pem"; + my $cafile = "$tlsdir/ca.pem"; + my $crlfile = "$tlsdir/crl.pem"; + my $certfile = "$tlsdir/cert.pem"; + my $keyfile = "$tlsdir/key.pem"; + my $usercertfile = "$pkinitdir/USER-$userprincipalname-cert.pem"; + my $userkeyfile = "$pkinitdir/USER-$userprincipalname-private-key.pem"; + + mkdir($tlsdir, 0700); + mkdir($pkinitdir, 0700); + my $oldumask = umask; + umask 0077; + + # This is specified here to avoid draining entropy on every run + # generate by + # openssl dhparam -out dhparms.pem -text -2 8192 + open(DHFILE, ">$dhfile"); + print DHFILE <<EOF; +-----BEGIN DH PARAMETERS----- +MIIECAKCBAEAlcpjuJptCzC2bIIApLuyFLw2nODQUztqs/peysY9e3LgWh/xrc87 +SWJNSUrqFJFh2m357WH0XGcTdTk0b/8aIYIWjbwEhWR/5hZ+1x2TDrX1awkYayAe +pr0arycmWHaAmhw+m+dBdj2O2jRMe7gn0ha85JALNl+Z3wv2q2eys8TIiQ2dbHPx +XvpMmlAv7QHZnpSpX/XgueQr6T3EYggljppZwk1fe4W2cxBjCv9w/Q83pJXMEVVB +WESEQPZC38v6hVIXIlF4J7jXjV3+NtCLL4nvsy0jrLEntyKz5OB8sNPRzJr0Ju2Y +yXORCSMMXMygP+dxJtQ6txzQYWyaCYN1HqHDZy3cFL9Qy8kTFqIcW56Lti2GsW/p +jSMzEOa1NevhKNFL3dSZJx5m+5ZeMvWXlCqXSptmVdbs5wz5jkMUm/E6pVfM5lyb +Ttlcq2iYPqnJz1jcL5xwhoufID8zSJCPJ7C0jb0Ngy5wLIUZfjXJUXxUyxTnNR9i +N9Sc+UkDvLxnCW+qzjyPXGlQU1SsJwMLWa2ZecL/uYE4bOdcN3g+5WHkevyDnXqR ++yy9x7sGXjBT3bRWK5tVHJWOi6eBu1hp39U6aK8oOJWiUt3vmC2qEdIsT6JaLNNi +YKrSfRGBf19IJBaagen1S19bb3dnmwoU1RaWM0EeJQW1oXOBg7zLisB2yuu5azBn +tse00+0nc+GbH2y+jP0sE7xil1QeilZl+aQ3tX9vL0cnCa+8602kXxU7P5HaX2+d +05pvoHmeZbDV85io36oF976gBYeYN+qAkTUMsIZhuLQDuyn0963XOLyn1Pm6SBrU +OkIZXW7WoKEuO/YSfizUIqXwmAMJjnEMJCWG51MZZKx//9Hsdp1RXSm/bRSbvXB7 +MscjvQYWmfCFnIk8LYnEt3Yey40srEiS9xyZqdrvobxz+sU1XcqR38kpVf4gKASL +xURia64s4emuJF+YHIObyydazQ+6/wX/C+m+nyfhuxSO6j1janPwtYbU+Uj3TzeM +04K1mpPQpZcaMdZZiNiu7i8VJlOPKAz7aJT8TnMMF5GMyzyLpSMpc+NF9L/BSocV +/cUM4wQT2PTHrcyYzmTVH7c9bzBkuxqrwVB1BY1jitDV9LIYIVBglKcX88qrfHIM +XiXPAIwGclD59qm2cG8OdM9NA5pNMI119KuUAIJsUdgPbR1LkT2XTT15YVoHmFSQ +DlaWOXn4td031jr0EisX8QtFR7+/0Nfoni6ydFGs5fNH/L1ckq6FEO4OhgucJw9H +YRmiFlsQBQNny78vNchwZne3ZixkShtGW0hWDdi2n+h7St1peNJCNJjMbEhRsPRx +RmNGWh4AL8rho4RO9OBao0MnUdjbbffD+wIBAg== +-----END DH PARAMETERS----- +EOF + close(DHFILE); + + if (! -e ${dckey_private}) { + umask $oldumask; + return; + } + + copy_file_content(${cacert}, ${cafile}); + copy_file_content(${cacrl_pem}, ${crlfile}); + copy_file_content(${dccert}, ${certfile}); + copy_file_content(${dckey_private}, ${keyfile}); + if (-e ${userkey_private}) { + copy_file_content(${usercert}, ${usercertfile}); + copy_file_content(${userkey_private}, ${userkeyfile}); + } + + # COMPAT stuff to be removed in a later commit + my $kdccertfile = "$tlsdir/kdc.pem"; + copy_file_content(${dccert}, ${kdccertfile}); + if (-e ${userkey_private}) { + my $adminkeyfile = "$tlsdir/adminkey.pem"; + my $admincertfile = "$tlsdir/admincert.pem"; + my $admincertupnfile = "$tlsdir/admincertupn.pem"; + copy_file_content(${userkey_private}, ${adminkeyfile}); + copy_file_content(${usercert}, ${admincertfile}); + copy_file_content(${usercert}, ${admincertupnfile}); + } + + umask $oldumask; +} + sub mk_krb5_conf($$) { my ($ctx, $other_realms_stanza) = @_; diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index ac8bfb7c606..bb1fd5b08cb 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -210,6 +210,7 @@ sub setup_s3dc($$) domain master = yes domain logons = yes lanman auth = yes + raw NTLMv2 auth = yes rpc_server:epmapper = external rpc_server:spoolss = external diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index ab3124858c9..7ea154407c9 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -247,219 +247,6 @@ sub mk_openldap($$) return ($slapd_conf_d, $pidfile); } -sub mk_keyblobs($$) -{ - my ($self, $tlsdir) = @_; - - #TLS and PKINIT crypto blobs - my $dhfile = "$tlsdir/dhparms.pem"; - my $cafile = "$tlsdir/ca.pem"; - my $certfile = "$tlsdir/cert.pem"; - my $reqkdc = "$tlsdir/req-kdc.der"; - my $kdccertfile = "$tlsdir/kdc.pem"; - my $keyfile = "$tlsdir/key.pem"; - my $adminkeyfile = "$tlsdir/adminkey.pem"; - my $reqadmin = "$tlsdir/req-admin.der"; - my $admincertfile = "$tlsdir/admincert.pem"; - my $admincertupnfile = "$tlsdir/admincertupn.pem"; - - mkdir($tlsdir, 0700); - my $oldumask = umask; - umask 0077; - - #This is specified here to avoid draining entropy on every run - open(DHFILE, ">$dhfile"); - print DHFILE <<EOF; ------BEGIN DH PARAMETERS----- -MGYCYQC/eWD2xkb7uELmqLi+ygPMKyVcpHUo2yCluwnbPutEueuxrG/Cys8j8wLO -svCN/jYNyR2NszOmg7ZWcOC/4z/4pWDVPUZr8qrkhj5MRKJc52MncfaDglvEdJrv -YX70obsCAQI= ------END DH PARAMETERS----- -EOF - close(DHFILE); - - #Likewise, we pregenerate the key material. This allows the - #other certificates to be pre-generated - open(KEYFILE, ">$keyfile"); - print KEYFILE <<EOF; ------BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQDKg6pAwCHUMA1DfHDmWhZfd+F0C+9Jxcqvpw9ii9En3E1uflpc -ol3+S9/6I/uaTmJHZre+DF3dTzb/UOZo0Zem8N+IzzkgoGkFafjXuT3BL5UPY2/H -6H+pPqVIRLOmrWImai359YyoKhFyo37Y6HPeU8QcZ+u2rS9geapIWfeuowIDAQAB -AoGAAqDLzFRR/BF1kpsiUfL4WFvTarCe9duhwj7ORc6fs785qAXuwUYAJ0Uvzmy6 -HqoGv3t3RfmeHDmjcpPHsbOKnsOQn2MgmthidQlPBMWtQMff5zdoYNUFiPS0XQBq -szNW4PRjaA9KkLQVTwnzdXGkBSkn/nGxkaVu7OR3vJOBoo0CQQDO4upypesnbe6p -9/xqfZ2uim8IwV1fLlFClV7WlCaER8tsQF4lEi0XSzRdXGUD/dilpY88Nb+xok/X -8Z8OvgAXAkEA+pcLsx1gN7kxnARxv54jdzQjC31uesJgMKQXjJ0h75aUZwTNHmZQ -vPxi6u62YiObrN5oivkixwFNncT9MxTxVQJBAMaWUm2SjlLe10UX4Zdm1MEB6OsC -kVoX37CGKO7YbtBzCfTzJGt5Mwc1DSLA2cYnGJqIfSFShptALlwedot0HikCQAJu -jNKEKnbf+TdGY8Q0SKvTebOW2Aeg80YFkaTvsXCdyXrmdQcifw4WdO9KucJiDhSz -Y9hVapz7ykEJtFtWjLECQQDIlfc63I5ZpXfg4/nN4IJXUW6AmPVOYIA5215itgki -cSlMYli1H9MEXH0pQMGv5Qyd0OYIx2DDg96mZ+aFvqSG ------END RSA PRIVATE KEY----- -EOF - close(KEYFILE); - - open(ADMINKEYFILE, ">$adminkeyfile"); - - print ADMINKEYFILE <<EOF; ------BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQD0+OL7TQBj0RejbIH1+g5GeRaWaM9xF43uE5y7jUHEsi5owhZF -5iIoHZeeL6cpDF5y1BZRs0JlA1VqMry1jjKlzFYVEMMFxB6esnXhl0Jpip1JkUMM -XLOP1m/0dqayuHBWozj9f/cdyCJr0wJIX1Z8Pr+EjYRGPn/MF0xdl3JRlwIDAQAB -AoGAP8mjCP628Ebc2eACQzOWjgEvwYCPK4qPmYOf1zJkArzG2t5XAGJ5WGrENRuB -cm3XFh1lpmaADl982UdW3gul4gXUy6w4XjKK4vVfhyHj0kZ/LgaXUK9BAGhroJ2L -osIOUsaC6jdx9EwSRctwdlF3wWJ8NK0g28AkvIk+FlolW4ECQQD7w5ouCDnf58CN -u4nARx4xv5XJXekBvOomkCQAmuOsdOb6b9wn3mm2E3au9fueITjb3soMR31AF6O4 -eAY126rXAkEA+RgHzybzZEP8jCuznMqoN2fq/Vrs6+W3M8/G9mzGEMgLLpaf2Jiz -I9tLZ0+OFk9tkRaoCHPfUOCrVWJZ7Y53QQJBAMhoA6rw0WDyUcyApD5yXg6rusf4 -ASpo/tqDkqUIpoL464Qe1tjFqtBM3gSXuhs9xsz+o0bzATirmJ+WqxrkKTECQHt2 -OLCpKqwAspU7N+w32kaUADoRLisCEdrhWklbwpQgwsIVsCaoEOpt0CLloJRYTANE -yoZeAErTALjyZYZEPcECQQDlUi0N8DFxQ/lOwWyR3Hailft+mPqoPCa8QHlQZnlG -+cfgNl57YHMTZFwgUVFRdJNpjH/WdZ5QxDcIVli0q+Ko ------END RSA PRIVATE KEY----- -EOF - - #generated with - # hxtool issue-certificate --self-signed --issue-ca \ - # --ca-private-key="FILE:$KEYFILE" \ - # --subject="CN=CA,DC=samba,DC=example,DC=com" \ - # --certificate="FILE:$CAFILE" --lifetime="25 years" - - open(CAFILE, ">$cafile"); - print CAFILE <<EOF; ------BEGIN CERTIFICATE----- -MIICcTCCAdqgAwIBAgIUaBPmjnPVqyFqR5foICmLmikJTzgwCwYJKoZIhvcNAQEFMFIxEzAR -BgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMRUwEwYKCZImiZPy -LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDgwMzAxMTIyMzEyWhgPMjAzMzAyMjQx -MjIzMTJaMFIxEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl -MRUwEwYKCZImiZPyLGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDKg6pAwCHUMA1DfHDmWhZfd+F0C+9Jxcqvpw9ii9En3E1uflpcol3+S9/6 -I/uaTmJHZre+DF3dTzb/UOZo0Zem8N+IzzkgoGkFafjXuT3BL5UPY2/H6H+pPqVIRLOmrWIm -ai359YyoKhFyo37Y6HPeU8QcZ+u2rS9geapIWfeuowIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC -AaYwHQYDVR0OBBYEFMLZufegDKLZs0VOyFXYK1L6M8oyMA8GA1UdEwEB/wQFMAMBAf8wDQYJ -KoZIhvcNAQEFBQADgYEAAZJbCAAkaqgFJ0xgNovn8Ydd0KswQPjicwiODPgw9ZPoD2HiOUVO -yYDRg/dhFF9y656OpcHk4N7qZ2sl3RlHkzDu+dseETW+CnKvQIoXNyeARRJSsSlwrwcoD4JR -HTLk2sGigsWwrJ2N99sG/cqSJLJ1MFwLrs6koweBnYU0f/g= ------END CERTIFICATE----- -EOF - - #generated with GNUTLS internally in Samba. - - open(CERTFILE, ">$certfile"); - print CERTFILE <<EOF; ------BEGIN CERTIFICATE----- -MIICYTCCAcygAwIBAgIE5M7SRDALBgkqhkiG9w0BAQUwZTEdMBsGA1UEChMUU2Ft -YmEgQWRtaW5pc3RyYXRpb24xNDAyBgNVBAsTK1NhbWJhIC0gdGVtcG9yYXJ5IGF1 -dG9nZW5lcmF0ZWQgY2VydGlmaWNhdGUxDjAMBgNVBAMTBVNhbWJhMB4XDTA2MDgw -NDA0MzY1MloXDTA4MDcwNDA0MzY1MlowZTEdMBsGA1UEChMUU2FtYmEgQWRtaW5p -c3RyYXRpb24xNDAyBgNVBAsTK1NhbWJhIC0gdGVtcG9yYXJ5IGF1dG9nZW5lcmF0 -ZWQgY2VydGlmaWNhdGUxDjAMBgNVBAMTBVNhbWJhMIGcMAsGCSqGSIb3DQEBAQOB -jAAwgYgCgYDKg6pAwCHUMA1DfHDmWhZfd+F0C+9Jxcqvpw9ii9En3E1uflpcol3+ -S9/6I/uaTmJHZre+DF3dTzb/UOZo0Zem8N+IzzkgoGkFafjXuT3BL5UPY2/H6H+p -PqVIRLOmrWImai359YyoKhFyo37Y6HPeU8QcZ+u2rS9geapIWfeuowIDAQABoyUw -IzAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAsGCSqGSIb3DQEB -BQOBgQAmkN6XxvDnoMkGcWLCTwzxGfNNSVcYr7TtL2aJh285Xw9zaxcm/SAZBFyG -LYOChvh6hPU7joMdDwGfbiLrBnMag+BtGlmPLWwp/Kt1wNmrRhduyTQFhN3PP6fz -nBr9vVny2FewB2gHmelaPS//tXdxivSXKz3NFqqXLDJjq7P8wA== ------END CERTIFICATE----- -EOF - close(CERTFILE); - - #KDC certificate - # hxtool request-create \ - # --subject="CN=krbtgt,CN=users,DC=samba,DC=example,DC=com" \ - # --key="FILE:$KEYFILE" $KDCREQ - - # hxtool issue-certificate --ca-certificate=FILE:$CAFILE,$KEYFILE \ - # --type="pkinit-kdc" \ - # --pk-init-principal="krbtgt/SAMBA.EXAMPLE.COM@SAMBA.EXAMPLE.COM" \ - # --req="PKCS10:$KDCREQ" --certificate="FILE:$KDCCERTFILE" \ - # --lifetime="25 years" - - open(KDCCERTFILE, ">$kdccertfile"); - print KDCCERTFILE <<EOF; ------BEGIN CERTIFICATE----- -MIIDDDCCAnWgAwIBAgIUI2Tzj+JnMzMcdeabcNo30rovzFAwCwYJKoZIhvcNAQEFMFIxEzAR -BgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMRUwEwYKCZImiZPy -LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDgwMzAxMTMxOTIzWhgPMjAzMzAyMjQx -MzE5MjNaMGYxEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl -MRUwEwYKCZImiZPyLGQBGQwFc2FtYmExDjAMBgNVBAMMBXVzZXJzMQ8wDQYDVQQDDAZrcmJ0 -Z3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMqDqkDAIdQwDUN8cOZaFl934XQL70nF -yq+nD2KL0SfcTW5+WlyiXf5L3/oj+5pOYkdmt74MXd1PNv9Q5mjRl6bw34jPOSCgaQVp+Ne5 -PcEvlQ9jb8fof6k+pUhEs6atYiZqLfn1jKgqEXKjftjoc95TxBxn67atL2B5qkhZ966jAgMB -AAGjgcgwgcUwDgYDVR0PAQH/BAQDAgWgMBIGA1UdJQQLMAkGBysGAQUCAwUwVAYDVR0RBE0w -S6BJBgYrBgEFAgKgPzA9oBMbEVNBTUJBLkVYQU1QTEUuQ09NoSYwJKADAgEBoR0wGxsGa3Ji -dGd0GxFTQU1CQS5FWEFNUExFLkNPTTAfBgNVHSMEGDAWgBTC2bn3oAyi2bNFTshV2CtS+jPK -MjAdBgNVHQ4EFgQUwtm596AMotmzRU7IVdgrUvozyjIwCQYDVR0TBAIwADANBgkqhkiG9w0B -AQUFAAOBgQBmrVD5MCmZjfHp1nEnHqTIh8r7lSmVtDx4s9MMjxm9oNrzbKXynvdhwQYFVarc -ge4yRRDXtSebErOl71zVJI9CVeQQpwcH+tA85oGA7oeFtO/S7ls581RUU6tGgyxV4veD+lJv -KPH5LevUtgD+q9H4LU4Sq5N3iFwBaeryB0g2wg== ------END CERTIFICATE----- -EOF - - # hxtool request-create \ - # --subject="CN=Administrator,CN=users,DC=samba,DC=example,DC=com" \ - # --key="FILE:$ADMINKEYFILE" $ADMINREQFILE - - # hxtool issue-certificate --ca-certificate=FILE:$CAFILE,$KEYFILE \ - # --type="pkinit-client" \ - # --pk-init-principal="administrator@SAMBA.EXAMPLE.COM" \ - # --req="PKCS10:$ADMINREQFILE" --certificate="FILE:$ADMINCERTFILE" \ - # --lifetime="25 years" - - open(ADMINCERTFILE, ">$admincertfile"); - print ADMINCERTFILE <<EOF; ------BEGIN CERTIFICATE----- -MIIDHTCCAoagAwIBAgIUUggzW4lLRkMKe1DAR2NKatkMDYwwCwYJKoZIhvcNAQELMFIxEzAR -BgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMRUwEwYKCZImiZPy -LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDkwNzI3MDMzMjE1WhgPMjAzNDA3MjIw -MzMyMTVaMG0xEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl -MRUwEwYKCZImiZPyLGQBGQwFc2FtYmExDjAMBgNVBAMMBXVzZXJzMRYwFAYDVQQDDA1BZG1p -bmlzdHJhdG9yMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0+OL7TQBj0RejbIH1+g5G -eRaWaM9xF43uE5y7jUHEsi5owhZF5iIoHZeeL6cpDF5y1BZRs0JlA1VqMry1jjKlzFYVEMMF -xB6esnXhl0Jpip1JkUMMXLOP1m/0dqayuHBWozj9f/cdyCJr0wJIX1Z8Pr+EjYRGPn/MF0xd -l3JRlwIDAQABo4HSMIHPMA4GA1UdDwEB/wQEAwIFoDAoBgNVHSUEITAfBgcrBgEFAgMEBggr -BgEFBQcDAgYKKwYBBAGCNxQCAjBIBgNVHREEQTA/oD0GBisGAQUCAqAzMDGgExsRU0FNQkEu -RVhBTVBMRS5DT02hGjAYoAMCAQGhETAPGw1BZG1pbmlzdHJhdG9yMB8GA1UdIwQYMBaAFMLZ -ufegDKLZs0VOyFXYK1L6M8oyMB0GA1UdDgQWBBQg81bLyfCA88C2B/BDjXlGuaFaxjAJBgNV -HRMEAjAAMA0GCSqGSIb3DQEBCwUAA4GBAEf/OSHUDJaGdtWGNuJeqcVYVMwrfBAc0OSwVhz1 -7/xqKHWo8wIMPkYRtaRHKLNDsF8GkhQPCpVsa6mX/Nt7YQnNvwd+1SBP5E8GvwWw9ZzLJvma -nk2n89emuayLpVtp00PymrDLRBcNaRjFReQU8f0o509kiVPHduAp3jOiy13l ------END CERTIFICATE----- -EOF - close(ADMINCERTFILE); - - # hxtool issue-certificate --ca-certificate=FILE:$CAFILE,$KEYFILE \ - # --type="pkinit-client" \ - # --ms-upn="administrator@samba.example.com" \ - # --req="PKCS10:$ADMINREQFILE" --certificate="FILE:$ADMINCERTUPNFILE" \ - # --lifetime="25 years" - - open(ADMINCERTUPNFILE, ">$admincertupnfile"); - print ADMINCERTUPNFILE <<EOF; ------BEGIN CERTIFICATE----- -MIIDDzCCAnigAwIBAgIUUp3CJMuNaEaAdPKp3QdNIwG7a4wwCwYJKoZIhvcNAQELMFIxEzAR -BgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMRUwEwYKCZImiZPy -LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDkwNzI3MDMzMzA1WhgPMjAzNDA3MjIw -MzMzMDVaMG0xEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl -MRUwEwYKCZImiZPyLGQBGQwFc2FtYmExDjAMBgNVBAMMBXVzZXJzMRYwFAYDVQQDDA1BZG1p -bmlzdHJhdG9yMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0+OL7TQBj0RejbIH1+g5G -eRaWaM9xF43uE5y7jUHEsi5owhZF5iIoHZeeL6cpDF5y1BZRs0JlA1VqMry1jjKlzFYVEMMF -xB6esnXhl0Jpip1JkUMMXLOP1m/0dqayuHBWozj9f/cdyCJr0wJIX1Z8Pr+EjYRGPn/MF0xd -l3JRlwIDAQABo4HEMIHBMA4GA1UdDwEB/wQEAwIFoDAoBgNVHSUEITAfBgcrBgEFAgMEBggr -BgEFBQcDAgYKKwYBBAGCNxQCAjA6BgNVHREEMzAxoC8GCisGAQQBgjcUAgOgIQwfYWRtaW5p -c3RyYXRvckBzYW1iYS5leGFtcGxlLmNvbTAfBgNVHSMEGDAWgBTC2bn3oAyi2bNFTshV2CtS -+jPKMjAdBgNVHQ4EFgQUIPNWy8nwgPPAtgfwQ415RrmhWsYwCQYDVR0TBAIwADANBgkqhkiG -9w0BAQsFAAOBgQBk42+egeUB3Ji2PC55fbt3FNKxvmm2xUUFkV9POK/YR9rajKOwk5jtYSeS -Zd7J9s//rNFNa7waklFkDaY56+QWTFtdvxfE+KoHaqt6X8u6pqi7p3M4wDKQox+9Dx8yWFyq -Wfz/8alZ5aMezCQzXJyIaJsCLeKABosSwHcpAFmxlQ== ------END CERTIFICATE----- -EOF - - umask $oldumask; -} - sub provision_raw_prepare($$$$$$$$$$) { my ($self, $prefix, $server_role, $hostname, @@ -611,6 +398,11 @@ sub provision_raw_step1($$) warn("can't open $ctx->{smb_conf}$?"); return undef; } + + Samba::prepare_keyblobs($ctx); + my $crlfile = "$ctx->{tlsdir}/crl.pem"; + $crlfile = "" unless -e ${crlfile}; + print CONFFILE " [global] netbios name = $ctx->{netbiosname} @@ -630,6 +422,8 @@ sub provision_raw_step1($$) name resolve order = file bcast interfaces = $ctx->{interfaces} tls dh params file = $ctx->{tlsdir}/dhparms.pem + tls crlfile = ${crlfile} + tls verify peer = no_check panic action = $RealBin/gdb_backtrace \%d wins support = yes server role = $ctx->{server_role} @@ -637,6 +431,7 @@ sub provision_raw_step1($$) dcerpc endpoint servers = +winreg +srvsvc notify:inotify = false ldb:nosync = true + ldap server require strong auth = yes #We don't want to pass our self-tests if the PAC code is wrong gensec:require_pac = true log file = $ctx->{logdir}/log.\%m @@ -668,8 +463,6 @@ sub provision_raw_step1($$) "; close(CONFFILE); - $self->mk_keyblobs($ctx->{tlsdir}); - #Default the KDC IP to the server's IP if (not defined($ctx->{kdc_ipv4})) { $ctx->{kdc_ipv4} = $ctx->{ipv4}; @@ -1314,7 +1107,9 @@ sub provision_dc($$) print "PROVISIONING DC..."; my $extra_conf_options = "netbios aliases = localDC1-a - server services = +winbind -winbindd"; + server services = +winbind -winbindd + ldap server require strong auth = allow_sasl_over_tls + "; my $ret = $self->provision($prefix, "domain controller", "localdc", @@ -1420,6 +1215,7 @@ sub provision_fl2008r2dc($$) my ($self, $prefix) = @_; print "PROVISIONING DC..."; + my $extra_conf_options = "ldap server require strong auth = no"; my $ret = $self->provision($prefix, "domain controller", "dc7", @@ -1427,7 +1223,8 @@ sub provision_fl2008r2dc($$) "samba2008R2.example.com", "2008_R2", "locDCpass7", - undef, "", "", undef); + undef, $extra_conf_options, + "", undef); unless ($self->add_wins_config("$prefix/private")) { warn("Unable to add wins configuration"); @@ -1615,7 +1412,7 @@ sub provision_plugin_s4_dc($$) "domain controller", "plugindc", "PLUGINDOMAIN", - "plugindc.samba.example.com", + "plugindom.samba.example.com", "2008", "locDCpass1", undef, $extra_smbconf_options, diff --git a/selftest/tests/__init__.py b/selftest/tests/__init__.py index 85d0316b464..ee536630ce1 100644 --- a/selftest/tests/__init__.py +++ b/selftest/tests/__init__.py @@ -19,8 +19,6 @@ """Tests for selftest.""" -from testtools import TestCase - import unittest def test_suite(): diff --git a/selftest/tests/test_run.py b/selftest/tests/test_run.py index de5f4b121bc..9b77516adb0 100644 --- a/selftest/tests/test_run.py +++ b/selftest/tests/test_run.py @@ -22,6 +22,7 @@ import datetime import os import subunit +from samba.tests import TestCase import tempfile from selftest.run import ( @@ -33,7 +34,6 @@ from selftest.run import ( run_testsuite_command, ) -from selftest.tests import TestCase class ExpandEnvironmentStringsTests(TestCase): diff --git a/selftest/tests/test_samba.py b/selftest/tests/test_samba.py index b49463eabb9..23de0d34c73 100644 --- a/selftest/tests/test_samba.py +++ b/selftest/tests/test_samba.py @@ -21,7 +21,7 @@ from cStringIO import StringIO -from selftest.tests import TestCase +from samba.tests import TestCase from selftest.target.samba import ( bindir_path, diff --git a/selftest/tests/test_socket_wrapper.py b/selftest/tests/test_socket_wrapper.py index 81fe5b603cf..e278fdddfa6 100644 --- a/selftest/tests/test_socket_wrapper.py +++ b/selftest/tests/test_socket_wrapper.py @@ -19,7 +19,7 @@ """Tests for selftest/socket_wrapper.""" -from selftest.tests import TestCase +from samba.tests import TestCase from selftest import socket_wrapper diff --git a/selftest/tests/test_target.py b/selftest/tests/test_target.py index 00b7126a073..ed9b064961e 100644 --- a/selftest/tests/test_target.py +++ b/selftest/tests/test_target.py @@ -29,7 +29,7 @@ from selftest.target import ( UnsupportedEnvironment, ) -from selftest.tests import TestCase +from samba.tests import TestCase class DummyEnvironment(Environment): diff --git a/selftest/tests/test_testlist.py b/selftest/tests/test_testlist.py index 7007d6d35a2..d82b00cefdb 100644 --- a/selftest/tests/test_testlist.py +++ b/selftest/tests/test_testlist.py @@ -22,7 +22,7 @@ import os import tempfile -from selftest.tests import TestCase +from samba.tests import TestCase from selftest.testlist import ( RestrictedTestManager, diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c index c3c54f343dd..b10162547eb 100644 --- a/source3/auth/auth_domain.c +++ b/source3/auth/auth_domain.c @@ -98,7 +98,7 @@ static NTSTATUS connect_to_domain_password_server(struct cli_state **cli_ret, /* Attempt connection */ result = cli_full_connection(&cli, lp_netbios_name(), dc_name, dc_ss, 0, - "IPC$", "IPC", "", "", "", 0, SMB_SIGNING_DEFAULT); + "IPC$", "IPC", "", "", "", 0, SMB_SIGNING_IPC_DEFAULT); if (!NT_STATUS_IS_OK(result)) { /* map to something more useful */ diff --git a/source3/auth/auth_samba4.c b/source3/auth/auth_samba4.c index 0a80d173355..4f37fea7ac6 100644 --- a/source3/auth/auth_samba4.c +++ b/source3/auth/auth_samba4.c @@ -245,8 +245,8 @@ static NTSTATUS prepare_gensec(const struct auth_context *auth_context, status = cli_credentials_set_machine_account(server_credentials, lp_ctx); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status))); - talloc_free(server_credentials); - server_credentials = NULL; + TALLOC_FREE(frame); + return status; } status = samba_server_gensec_start(mem_ctx, diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index 2b355e45565..c1aa9978553 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -34,6 +34,7 @@ #include "../auth/auth_sam_reply.h" #include "../librpc/gen_ndr/idmap.h" #include "lib/param/loadparm.h" +#include "../lib/tsocket/tsocket.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_AUTH @@ -353,6 +354,20 @@ NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx, const struct tsocket_address *remote_address, DATA_BLOB lm_resp, DATA_BLOB nt_resp) { + bool allow_raw = lp_raw_ntlmv2_auth(); + + if (!allow_raw && nt_resp.length >= 48) { + /* + * NTLMv2_RESPONSE has at least 48 bytes + * and should only be supported via NTLMSSP. + */ + DEBUG(2,("Rejecting raw NTLMv2 authentication with " + "user [%s\\%s] from[%s]\n", + client_domain, smb_name, + tsocket_address_string(remote_address, mem_ctx))); + return NT_STATUS_INVALID_PARAMETER; + } + return make_user_info(mem_ctx, user_info, smb_name, smb_name, client_domain, client_domain, diff --git a/source3/include/ads.h b/source3/include/ads.h index 3de1d8b199e..daea56d58ee 100644 --- a/source3/include/ads.h +++ b/source3/include/ads.h @@ -13,7 +13,7 @@ struct ads_struct; struct ads_saslwrap_ops { const char *name; - ADS_STATUS (*wrap)(struct ads_struct *, uint8 *buf, uint32 len); + ADS_STATUS (*wrap)(struct ads_struct *, uint8_t *buf, uint32_t len); ADS_STATUS (*unwrap)(struct ads_struct *); void (*disconnect)(struct ads_struct *); }; @@ -53,7 +53,7 @@ typedef struct ads_struct { /* info derived from the servers config */ struct { - uint32 flags; /* cldap flags identifying the services. */ + uint32_t flags; /* cldap flags identifying the services. */ char *realm; char *bind_path; char *ldap_server_name; @@ -82,23 +82,23 @@ typedef struct ads_struct { const struct ads_saslwrap_ops *wrap_ops; void *wrap_private_data; struct { - uint32 ofs; - uint32 needed; - uint32 left; + uint32_t ofs; + uint32_t needed; + uint32_t left; #define ADS_SASL_WRAPPING_IN_MAX_WRAPPED 0x0FFFFFFF - uint32 max_wrapped; - uint32 min_wrapped; - uint32 size; - uint8 *buf; + uint32_t max_wrapped; + uint32_t min_wrapped; + uint32_t size; + uint8_t *buf; } in; struct { - uint32 ofs; - uint32 left; + uint32_t ofs; + uint32_t left; #define ADS_SASL_WRAPPING_OUT_MAX_WRAPPED 0x00A00000 - uint32 max_unwrapped; - uint32 sig_size; - uint32 size; - uint8 *buf; + uint32_t max_unwrapped; + uint32_t sig_size; + uint32_t size; + uint8_t *buf; } out; } ldap; #endif /* HAVE_LDAP */ diff --git a/source3/include/auth_generic.h b/source3/include/auth_generic.h index 96b07cd8f77..a1558ea2e31 100644 --- a/source3/include/auth_generic.h +++ b/source3/include/auth_generic.h @@ -40,11 +40,12 @@ NTSTATUS auth_generic_set_password(struct auth_generic_state *ans, NTSTATUS auth_generic_client_prepare(TALLOC_CTX *mem_ctx, struct auth_generic_state **_ans); NTSTATUS auth_generic_client_start(struct auth_generic_state *ans, const char *oid); - +NTSTATUS auth_generic_client_start_by_name(struct auth_generic_state *ans, + const char *name); NTSTATUS auth_generic_client_start_by_authtype(struct auth_generic_state *ans, uint8_t auth_type, uint8_t auth_level); - -extern const struct gensec_security_ops gensec_ntlmssp3_client_ops; +NTSTATUS auth_generic_client_start_by_sasl(struct auth_generic_state *ans, + const char **sasl_list); #endif /* _AUTH_GENERIC_ */ diff --git a/source3/include/proto.h b/source3/include/proto.h index ce23289bab4..be900246da4 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -732,13 +732,6 @@ bool wins_server_tag_ips(const char *tag, TALLOC_CTX *mem_ctx, struct in_addr **pservers, int *pnum_servers); unsigned wins_srv_count_tag(const char *tag); -/* The following definitions come from libsmb/clispnego.c */ - -DATA_BLOB spnego_gen_negTokenInit(TALLOC_CTX *ctx, - const char *OIDs[], - DATA_BLOB *psecblob, - const char *principal); - #ifndef ASN1_MAX_OIDS #define ASN1_MAX_OIDS 20 #endif @@ -748,18 +741,6 @@ bool spnego_parse_negTokenInit(TALLOC_CTX *ctx, char **principal, DATA_BLOB *secblob); DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const uint8 tok_id[2]); -int spnego_gen_krb5_negTokenInit(TALLOC_CTX *ctx, - const char *principal, int time_offset, - DATA_BLOB *targ, - DATA_BLOB *session_key_krb5, uint32 extra_ap_opts, - const char *ccname, time_t *expire_time); -bool spnego_parse_challenge(TALLOC_CTX *ctx, const DATA_BLOB blob, - DATA_BLOB *chal1, DATA_BLOB *chal2); -DATA_BLOB spnego_gen_auth(TALLOC_CTX *ctx, DATA_BLOB blob); -bool spnego_parse_auth_response(TALLOC_CTX *ctx, - DATA_BLOB blob, NTSTATUS nt_status, - const char *mechOID, - DATA_BLOB *auth); /* The following definitions come from libsmb/conncache.c */ @@ -903,31 +884,6 @@ bool get_dc_name(const char *domain, fstring srv_name, struct sockaddr_storage *ss_out); -/* The following definitions come from libsmb/ntlmssp.c */ -struct ntlmssp_state; -NTSTATUS ntlmssp_set_username(struct ntlmssp_state *ntlmssp_state, const char *user) ; -NTSTATUS ntlmssp_set_password(struct ntlmssp_state *ntlmssp_state, const char *password) ; -NTSTATUS ntlmssp_set_password_hash(struct ntlmssp_state *ntlmssp_state, - const char *hash); -NTSTATUS ntlmssp_set_domain(struct ntlmssp_state *ntlmssp_state, const char *domain) ; -void ntlmssp_want_feature_list(struct ntlmssp_state *ntlmssp_state, char *feature_list); -void ntlmssp_want_feature(struct ntlmssp_state *ntlmssp_state, uint32_t feature); -NTSTATUS ntlmssp_update(struct ntlmssp_state *ntlmssp_state, - const DATA_BLOB in, DATA_BLOB *out) ; -bool ntlmssp_is_anonymous(struct ntlmssp_state *ntlmssp_state); -NTSTATUS ntlmssp_server_start(TALLOC_CTX *mem_ctx, - bool is_standalone, - const char *netbios_name, - const char *netbios_domain, - const char *dns_name, - const char *dns_domain, - struct ntlmssp_state **ntlmssp_state); -NTSTATUS ntlmssp_client_start(TALLOC_CTX *mem_ctx, - const char *netbios_name, - const char *netbios_domain, - bool use_ntlmv2, - struct ntlmssp_state **_ntlmssp_state); - /* The following definitions come from libsmb/passchange.c */ NTSTATUS remote_password_change(const char *remote_machine, const char *user_name, @@ -988,7 +944,9 @@ const char *lp_idmap_backend(const char *domain_name); const char *lp_idmap_default_backend (void); int lp_security(void); int lp_client_max_protocol(void); -int lp_winbindd_max_protocol(void); +int lp_client_ipc_min_protocol(void); +int lp_client_ipc_max_protocol(void); +int lp_client_ipc_signing(void); int lp_smb2_max_credits(void); int lp_cups_encrypt(void); bool lp_widelinks(int ); diff --git a/source3/lib/netapi/cm.c b/source3/lib/netapi/cm.c index 801e61f4a45..e9f2863952f 100644 --- a/source3/lib/netapi/cm.c +++ b/source3/lib/netapi/cm.c @@ -88,7 +88,7 @@ static WERROR libnetapi_open_ipc_connection(struct libnetapi_ctx *ctx, if (!auth_info) { return WERR_NOMEM; } - auth_info->signing_state = SMB_SIGNING_DEFAULT; + auth_info->signing_state = SMB_SIGNING_IPC_DEFAULT; set_cmdline_auth_info_use_kerberos(auth_info, ctx->use_kerberos); set_cmdline_auth_info_username(auth_info, ctx->username); if (ctx->password) { diff --git a/source3/lib/tldap.c b/source3/lib/tldap.c index 5d3773e4c7c..17238a547e0 100644 --- a/source3/lib/tldap.c +++ b/source3/lib/tldap.c @@ -1315,7 +1315,7 @@ done: } s++; - if (data->has_error) { + if (asn1_has_error(data)) { return false; } @@ -1529,7 +1529,7 @@ static bool tldap_push_filter_basic(struct tldap_context *ld, if (!asn1_write_OctetString(data, uval, uval_len)) return false; } - if (data->has_error) { + if (asn1_has_error(data)) { return false; } return asn1_pop_tag(data); @@ -2019,7 +2019,7 @@ static bool tldap_decode_controls(struct tldap_req_state *state) if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto out; if (!asn1_read_OctetString_talloc(msg, data, &oid)) goto out; - if ((data->has_error) || (oid == NULL)) { + if (asn1_has_error(data) || (oid == NULL)) { goto out; } c->oid = oid; diff --git a/source3/libads/ads_ldap_protos.h b/source3/libads/ads_ldap_protos.h index 3024ae2ea65..b063815678a 100644 --- a/source3/libads/ads_ldap_protos.h +++ b/source3/libads/ads_ldap_protos.h @@ -51,7 +51,7 @@ char **ads_pull_strings_range(ADS_STRUCT *ads, size_t *num_strings, bool *more_strings); bool ads_pull_uint32(ADS_STRUCT *ads, LDAPMessage *msg, const char *field, - uint32 *v); + uint32_t *v); bool ads_pull_guid(ADS_STRUCT *ads, LDAPMessage *msg, struct GUID *guid); bool ads_pull_sid(ADS_STRUCT *ads, LDAPMessage *msg, const char *field, struct dom_sid *sid); @@ -120,12 +120,12 @@ ADS_STATUS ads_parse_gpo(ADS_STRUCT *ads, const char *gpo_dn, struct GROUP_POLICY_OBJECT *gpo); ADS_STATUS ads_search_retry_dn_sd_flags(ADS_STRUCT *ads, LDAPMessage **res, - uint32 sd_flags, + uint32_t sd_flags, const char *dn, const char **attrs); ADS_STATUS ads_do_search_all_sd_flags(ADS_STRUCT *ads, const char *bind_path, int scope, const char *expr, - const char **attrs, uint32 sd_flags, + const char **attrs, uint32_t sd_flags, LDAPMessage **res); ADS_STATUS ads_get_tokensids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, diff --git a/source3/libads/ads_proto.h b/source3/libads/ads_proto.h index 1e34247e2fe..1399f41fbf7 100644 --- a/source3/libads/ads_proto.h +++ b/source3/libads/ads_proto.h @@ -66,7 +66,6 @@ bool ads_sitename_match(ADS_STRUCT *ads); bool ads_closest_dc(ADS_STRUCT *ads); ADS_STATUS ads_connect(ADS_STRUCT *ads); ADS_STATUS ads_connect_user_creds(ADS_STRUCT *ads); -ADS_STATUS ads_connect_gc(ADS_STRUCT *ads); void ads_disconnect(ADS_STRUCT *ads); ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path, int scope, const char *expr, const char **attrs, @@ -85,7 +84,7 @@ char *ads_ou_string(ADS_STRUCT *ads, const char *org_unit); char *ads_default_ou_string(ADS_STRUCT *ads, const char *wknguid); ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods, const char *name, const char **vals); -uint32 ads_get_kvno(ADS_STRUCT *ads, const char *account_name); +uint32_t ads_get_kvno(ADS_STRUCT *ads, const char *account_name); uint32_t ads_get_machine_kvno(ADS_STRUCT *ads, const char *machine_name); bool ads_element_in_array(const char **el_array, size_t num_el, const char *el); @@ -103,9 +102,9 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, ADS_STATUS ads_move_machine_acct(ADS_STRUCT *ads, const char *machine_name, const char *org_unit, bool *moved); int ads_count_replies(ADS_STRUCT *ads, void *res); -ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn); +ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32_t *usn); ADS_STATUS ads_current_time(ADS_STRUCT *ads); -ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32 *val); +ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32_t *val); ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, struct dom_sid *sid); ADS_STATUS ads_site_dn(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char **site_name); ADS_STATUS ads_site_dn_for_machine(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char *computer_name, const char **site_dn); @@ -122,12 +121,12 @@ char* ads_get_dnshostname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine char* ads_get_upn( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name ); char* ads_get_samaccountname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name ); ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name, - uint32 account_type, const char *org_unit); + uint32_t account_type, const char *org_unit); ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname); ADS_STATUS ads_find_samaccount(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char *samaccountname, - uint32 *uac_ret, + uint32_t *uac_ret, const char **dn_ret); ADS_STATUS ads_config_path(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, diff --git a/source3/libads/ads_status.c b/source3/libads/ads_status.c index 7465531404d..70569949aeb 100644 --- a/source3/libads/ads_status.c +++ b/source3/libads/ads_status.c @@ -119,8 +119,8 @@ const char *ads_errstr(ADS_STATUS status) case ENUM_ADS_ERROR_GSS: { char *ret; - uint32 msg_ctx; - uint32 minor; + uint32_t msg_ctx; + uint32_t minor; gss_buffer_desc msg1, msg2; msg_ctx = 0; @@ -147,7 +147,7 @@ const char *ads_errstr(ADS_STATUS status) } #ifdef HAVE_KRB5 -NTSTATUS gss_err_to_ntstatus(uint32 maj, uint32 min) +NTSTATUS gss_err_to_ntstatus(uint32_t maj, uint32_t min) { ADS_STATUS adss = ADS_ERROR_GSS(maj, min); DEBUG(10,("gss_err_to_ntstatus: Error %s\n", diff --git a/source3/libads/ads_status.h b/source3/libads/ads_status.h index ff7c1036380..2ff4ef003b1 100644 --- a/source3/libads/ads_status.h +++ b/source3/libads/ads_status.h @@ -63,6 +63,6 @@ ADS_STATUS ads_build_nt_error(enum ads_error_type etype, NTSTATUS nt_status); NTSTATUS ads_ntstatus(ADS_STATUS status); const char *ads_errstr(ADS_STATUS status); -NTSTATUS gss_err_to_ntstatus(uint32 maj, uint32 min); +NTSTATUS gss_err_to_ntstatus(uint32_t maj, uint32_t min); #endif /* _LIBADS_ADS_STATUS_H_ */ diff --git a/source3/libads/disp_sec.c b/source3/libads/disp_sec.c index 7dcdc95901e..472741fa1b6 100644 --- a/source3/libads/disp_sec.c +++ b/source3/libads/disp_sec.c @@ -29,7 +29,7 @@ #ifdef HAVE_LDAP static struct perm_mask_str { - uint32 mask; + uint32_t mask; const char *str; } perms[] = { {SEC_RIGHTS_FULL_CTRL, "[Full Control]"}, @@ -59,7 +59,7 @@ static struct perm_mask_str { }; /* convert a security permissions into a string */ -static void ads_disp_perms(uint32 type) +static void ads_disp_perms(uint32_t type) { int i = 0; int j = 0; diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 6031b421e98..121ba08d0c0 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -476,139 +476,6 @@ static NTSTATUS ads_find_dc(ADS_STRUCT *ads) return NT_STATUS_NO_LOGON_SERVERS; } -/********************************************************************* - *********************************************************************/ - -static NTSTATUS ads_lookup_site(void) -{ - ADS_STRUCT *ads = NULL; - ADS_STATUS ads_status; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - - ads = ads_init(lp_realm(), NULL, NULL); - if (!ads) { - return NT_STATUS_NO_MEMORY; - } - - /* The NO_BIND here will find a DC and set the client site - but not establish the TCP connection */ - - ads->auth.flags = ADS_AUTH_NO_BIND; - ads_status = ads_connect(ads); - if (!ADS_ERR_OK(ads_status)) { - DEBUG(4, ("ads_lookup_site: ads_connect to our realm failed! (%s)\n", - ads_errstr(ads_status))); - } - nt_status = ads_ntstatus(ads_status); - - if (ads) { - ads_destroy(&ads); - } - - return nt_status; -} - -/********************************************************************* - *********************************************************************/ - -static const char* host_dns_domain(const char *fqdn) -{ - const char *p = fqdn; - - /* go to next char following '.' */ - - if ((p = strchr_m(fqdn, '.')) != NULL) { - p++; - } - - return p; -} - - -/** - * Connect to the Global Catalog server - * @param ads Pointer to an existing ADS_STRUCT - * @return status of connection - * - * Simple wrapper around ads_connect() that fills in the - * GC ldap server information - **/ - -ADS_STATUS ads_connect_gc(ADS_STRUCT *ads) -{ - TALLOC_CTX *frame = talloc_stackframe(); - struct dns_rr_srv *gcs_list; - int num_gcs; - const char *realm = ads->server.realm; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); - int i; - bool done = false; - char *sitename = NULL; - const char *dns_hosts_file; - - if (!realm) - realm = lp_realm(); - - if ((sitename = sitename_fetch(frame, realm)) == NULL) { - ads_lookup_site(); - sitename = sitename_fetch(frame, realm); - } - - dns_hosts_file = lp_parm_const_string(-1, "resolv", "host file", NULL); - do { - /* We try once with a sitename and once without - (unless we don't have a sitename and then we're - done */ - - if (sitename == NULL) - done = true; - - nt_status = ads_dns_query_gcs(frame, dns_hosts_file, - realm, sitename, - &gcs_list, &num_gcs); - - if (!NT_STATUS_IS_OK(nt_status)) { - ads_status = ADS_ERROR_NT(nt_status); - goto done; - } - - /* Loop until we get a successful connection or have gone - through them all. When connecting a GC server, make sure that - the realm is the server's DNS name and not the forest root */ - - for (i=0; i<num_gcs; i++) { - ads->server.gc = true; - ads->server.ldap_server = SMB_STRDUP(gcs_list[i].hostname); - ads->server.realm = SMB_STRDUP(host_dns_domain(ads->server.ldap_server)); - ads_status = ads_connect(ads); - if (ADS_ERR_OK(ads_status)) { - /* Reset the bind_dn to "". A Global Catalog server - may host multiple domain trees in a forest. - Windows 2003 GC server will accept "" as the search - path to imply search all domain trees in the forest */ - - SAFE_FREE(ads->config.bind_path); - ads->config.bind_path = SMB_STRDUP(""); - - - goto done; - } - SAFE_FREE(ads->server.ldap_server); - SAFE_FREE(ads->server.realm); - } - - TALLOC_FREE(gcs_list); - num_gcs = 0; - } while (!done); - -done: - talloc_destroy(frame); - - return ads_status; -} - - /** * Connect to the LDAP server * @param ads Pointer to an existing ADS_STRUCT @@ -1174,7 +1041,7 @@ static ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path, ADS_STATUS ads_do_search_all_sd_flags(ADS_STRUCT *ads, const char *bind_path, int scope, const char *expr, - const char **attrs, uint32 sd_flags, + const char **attrs, uint32_t sd_flags, LDAPMessage **res) { ads_control args; @@ -1783,10 +1650,10 @@ ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods, * @return the kvno for the account, or -1 in case of a failure. **/ -uint32 ads_get_kvno(ADS_STRUCT *ads, const char *account_name) +uint32_t ads_get_kvno(ADS_STRUCT *ads, const char *account_name) { LDAPMessage *res = NULL; - uint32 kvno = (uint32)-1; /* -1 indicates a failure */ + uint32_t kvno = (uint32)-1; /* -1 indicates a failure */ char *filter; const char *attrs[] = {"msDS-KeyVersionNumber", NULL}; char *dn_string = NULL; @@ -2136,7 +2003,7 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, const char *objectClass[] = {"top", "person", "organizationalPerson", "user", "computer", NULL}; LDAPMessage *res = NULL; - uint32 acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\ + uint32_t acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\ UF_DONT_EXPIRE_PASSWD |\ UF_ACCOUNTDISABLE ); @@ -2312,7 +2179,7 @@ static void dump_sd(ADS_STRUCT *ads, const char *filed, struct berval **values) struct security_descriptor *psd; NTSTATUS status; - status = unmarshall_sec_desc(talloc_tos(), (uint8 *)values[0]->bv_val, + status = unmarshall_sec_desc(talloc_tos(), (uint8_t *)values[0]->bv_val, values[0]->bv_len, &psd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("unmarshall_sec_desc failed: %s\n", @@ -2725,7 +2592,7 @@ int ads_count_replies(ADS_STRUCT *ads, void *res) } /** - * pull a single uint32 from a ADS result + * pull a single uint32_t from a ADS result * @param ads connection to ads server * @param msg Results of search * @param field Attribute to retrieve @@ -2733,7 +2600,7 @@ int ads_count_replies(ADS_STRUCT *ads, void *res) * @return boolean inidicating success */ bool ads_pull_uint32(ADS_STRUCT *ads, LDAPMessage *msg, const char *field, - uint32 *v) + uint32_t *v) { char **values; @@ -2858,7 +2725,7 @@ int ads_count_replies(ADS_STRUCT *ads, void *res) if (values[0]) { NTSTATUS status; status = unmarshall_sec_desc(mem_ctx, - (uint8 *)values[0]->bv_val, + (uint8_t *)values[0]->bv_val, values[0]->bv_len, sd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("unmarshall_sec_desc failed: %s\n", @@ -2908,7 +2775,7 @@ int ads_count_replies(ADS_STRUCT *ads, void *res) * @param usn Pointer to retrieved update serial number * @return status of search **/ -ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn) +ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32_t *usn) { const char *attrs[] = {"highestCommittedUSN", NULL}; ADS_STATUS status; @@ -3020,7 +2887,7 @@ done: /******************************************************************** ********************************************************************/ -ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32 *val) +ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32_t *val) { const char *attrs[] = {"domainFunctionality", NULL}; ADS_STATUS status; @@ -3512,7 +3379,7 @@ out: * @return status of join **/ ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name, - uint32 account_type, const char *org_unit) + uint32_t account_type, const char *org_unit) { ADS_STATUS status; LDAPMessage *res = NULL; @@ -3708,7 +3575,7 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname) struct dom_sid *tmp_sids; struct dom_sid tmp_user_sid; struct dom_sid tmp_primary_group_sid; - uint32 pgid; + uint32_t pgid; const char *attrs[] = { "objectSid", "tokenGroups", @@ -3790,14 +3657,14 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname) * @param ads connection to ads server * @param mem_ctx TALLOC_CTX for allocating sid array * @param samaccountname to search - * @param uac_ret uint32 pointer userAccountControl attribute value + * @param uac_ret uint32_t pointer userAccountControl attribute value * @param dn_ret pointer to dn * @return status of token query **/ ADS_STATUS ads_find_samaccount(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char *samaccountname, - uint32 *uac_ret, + uint32_t *uac_ret, const char **dn_ret) { ADS_STATUS status; @@ -3805,7 +3672,7 @@ ADS_STATUS ads_find_samaccount(ADS_STRUCT *ads, const char *filter; LDAPMessage *res = NULL; char *dn = NULL; - uint32 uac = 0; + uint32_t uac = 0; filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)(sAMAccountName=%s))", samaccountname); diff --git a/source3/libads/ldap_printer.c b/source3/libads/ldap_printer.c index e9eb41967f2..82c131104b9 100644 --- a/source3/libads/ldap_printer.c +++ b/source3/libads/ldap_printer.c @@ -146,7 +146,7 @@ static bool map_dword(TALLOC_CTX *ctx, ADS_MODLIST *mods, if (value->type != REG_DWORD) { return false; } - if (value->data.length != sizeof(uint32)) { + if (value->data.length != sizeof(uint32_t)) { return false; } str_value = talloc_asprintf(ctx, "%d", IVAL(value->data.data, 0)); @@ -292,7 +292,7 @@ WERROR get_remote_printer_publishing_data(struct rpc_pipe_client *cli, char *printername; struct spoolss_PrinterEnumValues *info; uint32_t count; - uint32 i; + uint32_t i; struct policy_handle pol; WERROR werr; diff --git a/source3/libads/ldap_utils.c b/source3/libads/ldap_utils.c index 88db3a3ab73..117dc557e25 100644 --- a/source3/libads/ldap_utils.c +++ b/source3/libads/ldap_utils.c @@ -36,7 +36,7 @@ static ADS_STATUS ads_ranged_search_internal(ADS_STRUCT *ads, const char *range_attr, char ***strings, size_t *num_strings, - uint32 *first_usn, + uint32_t *first_usn, int *num_retries, bool *more_values); @@ -169,7 +169,7 @@ static ADS_STATUS ads_do_search_retry_args(ADS_STRUCT *ads, const char *bind_pat } ADS_STATUS ads_search_retry_dn_sd_flags(ADS_STRUCT *ads, LDAPMessage **res, - uint32 sd_flags, + uint32_t sd_flags, const char *dn, const char **attrs) { @@ -242,7 +242,7 @@ ADS_STATUS ads_ranged_search(ADS_STRUCT *ads, size_t *num_strings) { ADS_STATUS status; - uint32 first_usn; + uint32_t first_usn; int num_retries = 0; const char **attrs; bool more_values = False; @@ -296,14 +296,14 @@ static ADS_STATUS ads_ranged_search_internal(ADS_STRUCT *ads, const char *range_attr, char ***strings, size_t *num_strings, - uint32 *first_usn, + uint32_t *first_usn, int *num_retries, bool *more_values) { LDAPMessage *res = NULL; ADS_STATUS status; int count; - uint32 current_usn; + uint32_t current_usn; DEBUG(10, ("Searching for attrs[0] = %s, attrs[1] = %s\n", attrs[0], attrs[1])); diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c index ea0b821294e..22aa9cf4bb7 100644 --- a/source3/libads/sasl.c +++ b/source3/libads/sasl.c @@ -19,6 +19,7 @@ #include "includes.h" #include "../libcli/auth/spnego.h" +#include "auth/credentials/credentials.h" #include "auth/gensec/gensec.h" #include "auth_generic.h" #include "ads.h" @@ -28,7 +29,7 @@ #ifdef HAVE_LDAP -static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len) +static ADS_STATUS ads_sasl_gensec_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len) { struct gensec_security *gensec_security = talloc_get_type_abort(ads->ldap.wrap_private_data, @@ -46,6 +47,7 @@ static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len) } if ((ads->ldap.out.size - 4) < wrapped.length) { + TALLOC_FREE(frame); return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR); } @@ -60,7 +62,7 @@ static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len) return ADS_SUCCESS; } -static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads) +static ADS_STATUS ads_sasl_gensec_unwrap(ADS_STRUCT *ads) { struct gensec_security *gensec_security = talloc_get_type_abort(ads->ldap.wrap_private_data, @@ -94,7 +96,7 @@ static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads) return ADS_SUCCESS; } -static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads) +static void ads_sasl_gensec_disconnect(ADS_STRUCT *ads) { struct gensec_security *gensec_security = talloc_get_type_abort(ads->ldap.wrap_private_data, @@ -106,30 +108,32 @@ static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads) ads->ldap.wrap_private_data = NULL; } -static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = { - .name = "ntlmssp", - .wrap = ads_sasl_ntlmssp_wrap, - .unwrap = ads_sasl_ntlmssp_unwrap, - .disconnect = ads_sasl_ntlmssp_disconnect +static const struct ads_saslwrap_ops ads_sasl_gensec_ops = { + .name = "gensec", + .wrap = ads_sasl_gensec_wrap, + .unwrap = ads_sasl_gensec_unwrap, + .disconnect = ads_sasl_gensec_disconnect }; /* - perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can + perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can we fit on one socket??) */ -static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads) +static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads, + const char *sasl, + enum credentials_use_kerberos krb5_state, + const char *target_service, + const char *target_hostname, + const DATA_BLOB server_blob) { - DATA_BLOB msg1 = data_blob_null; - DATA_BLOB blob = data_blob_null; DATA_BLOB blob_in = data_blob_null; DATA_BLOB blob_out = data_blob_null; - struct berval cred, *scred = NULL; int rc; NTSTATUS nt_status; ADS_STATUS status; - int turn = 1; - struct auth_generic_state *auth_generic_state; + bool use_spnego_principal = lp_client_use_spnego_principal(); + const char *sasl_list[] = { sasl, NULL }; nt_status = auth_generic_client_prepare(NULL, &auth_generic_state); if (!NT_STATUS_IS_OK(nt_status)) { @@ -146,6 +150,39 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads) return ADS_ERROR_NT(nt_status); } + if (server_blob.length == 0) { + use_spnego_principal = false; + } + + if (krb5_state == CRED_DONT_USE_KERBEROS) { + use_spnego_principal = false; + } + + cli_credentials_set_kerberos_state(auth_generic_state->credentials, + krb5_state); + + if (target_service != NULL) { + nt_status = gensec_set_target_service( + auth_generic_state->gensec_security, + target_service); + if (!NT_STATUS_IS_OK(nt_status)) { + return ADS_ERROR_NT(nt_status); + } + } + + if (target_hostname != NULL) { + nt_status = gensec_set_target_hostname( + auth_generic_state->gensec_security, + target_hostname); + if (!NT_STATUS_IS_OK(nt_status)) { + return ADS_ERROR_NT(nt_status); + } + } + + if (target_service != NULL && target_hostname != NULL) { + use_spnego_principal = false; + } + switch (ads->ldap.wrap_type) { case ADS_SASLWRAP_TYPE_SEAL: gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); @@ -157,105 +194,133 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads) } else { /* * windows servers are broken with sign only, - * so we need to use seal here too + * so we let the NTLMSSP backend to seal here, + * via GENSEC_FEATURE_LDAP_STYLE. */ gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); - gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL); - ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL; + gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE); } break; case ADS_SASLWRAP_TYPE_PLAIN: break; } - nt_status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP); + nt_status = auth_generic_client_start_by_sasl(auth_generic_state, + sasl_list); if (!NT_STATUS_IS_OK(nt_status)) { return ADS_ERROR_NT(nt_status); } - blob_in = data_blob_null; + rc = LDAP_SASL_BIND_IN_PROGRESS; + nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; + if (use_spnego_principal) { + blob_in = data_blob_dup_talloc(talloc_tos(), server_blob); + if (blob_in.length == 0) { + TALLOC_FREE(auth_generic_state); + return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + } + } else { + blob_in = data_blob_null; + } + blob_out = data_blob_null; + + while (true) { + struct berval cred, *scred = NULL; - do { nt_status = gensec_update(auth_generic_state->gensec_security, talloc_tos(), blob_in, &blob_out); data_blob_free(&blob_in); - if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) - || NT_STATUS_IS_OK(nt_status)) - && blob_out.length) { - if (turn == 1) { - const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL}; - /* and wrap it in a SPNEGO wrapper */ - msg1 = spnego_gen_negTokenInit(talloc_tos(), - OIDs_ntlm, &blob_out, NULL); - } else { - /* wrap it in SPNEGO */ - msg1 = spnego_gen_auth(talloc_tos(), blob_out); - } - + if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) + && !NT_STATUS_IS_OK(nt_status)) + { + TALLOC_FREE(auth_generic_state); data_blob_free(&blob_out); + return ADS_ERROR_NT(nt_status); + } - cred.bv_val = (char *)msg1.data; - cred.bv_len = msg1.length; - scred = NULL; - rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred); - data_blob_free(&msg1); - if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) { - if (scred) { - ber_bvfree(scred); - } + if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) { + break; + } - TALLOC_FREE(auth_generic_state); - return ADS_ERROR(rc); - } + cred.bv_val = (char *)blob_out.data; + cred.bv_len = blob_out.length; + scred = NULL; + rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred); + data_blob_free(&blob_out); + if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) { if (scred) { - blob = data_blob(scred->bv_val, scred->bv_len); ber_bvfree(scred); - } else { - blob = data_blob_null; } + TALLOC_FREE(auth_generic_state); + return ADS_ERROR(rc); + } + if (scred) { + blob_in = data_blob_talloc(talloc_tos(), + scred->bv_val, + scred->bv_len); + if (blob_in.length != scred->bv_len) { + ber_bvfree(scred); + TALLOC_FREE(auth_generic_state); + return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + } + ber_bvfree(scred); } else { + blob_in = data_blob_null; + } + if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) { + break; + } + } + data_blob_free(&blob_in); + data_blob_free(&blob_out); + + if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SEAL) { + bool ok; + + ok = gensec_have_feature(auth_generic_state->gensec_security, + GENSEC_FEATURE_SEAL); + if (!ok) { + DEBUG(0,("The gensec feature sealing request, but unavailable\n")); TALLOC_FREE(auth_generic_state); - data_blob_free(&blob_out); - return ADS_ERROR_NT(nt_status); + return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); } - - if ((turn == 1) && - (rc == LDAP_SASL_BIND_IN_PROGRESS)) { - DATA_BLOB tmp_blob = data_blob_null; - /* the server might give us back two challenges */ - if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in, - &tmp_blob)) { - TALLOC_FREE(auth_generic_state); - data_blob_free(&blob); - DEBUG(3,("Failed to parse challenges\n")); - return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - data_blob_free(&tmp_blob); - } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) { - if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP, - &blob_in)) { + ok = gensec_have_feature(auth_generic_state->gensec_security, + GENSEC_FEATURE_SIGN); + if (!ok) { + DEBUG(0,("The gensec feature signing request, but unavailable\n")); + TALLOC_FREE(auth_generic_state); + return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); + } - TALLOC_FREE(auth_generic_state); - data_blob_free(&blob); - DEBUG(3,("Failed to parse auth response\n")); - return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } + } else if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SIGN) { + bool ok; + + ok = gensec_have_feature(auth_generic_state->gensec_security, + GENSEC_FEATURE_SIGN); + if (!ok) { + DEBUG(0,("The gensec feature signing request, but unavailable\n")); + TALLOC_FREE(auth_generic_state); + return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); } - data_blob_free(&blob); - data_blob_free(&blob_out); - turn++; - } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status)); - + } + if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { - uint32_t sig_size = gensec_sig_size(auth_generic_state->gensec_security, 0); - ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - sig_size; - ads->ldap.out.sig_size = sig_size; - ads->ldap.in.min_wrapped = ads->ldap.out.sig_size; - ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED; - status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, auth_generic_state->gensec_security); + size_t max_wrapped = gensec_max_wrapped_size(auth_generic_state->gensec_security); + ads->ldap.out.max_unwrapped = gensec_max_input_size(auth_generic_state->gensec_security); + + ads->ldap.out.sig_size = max_wrapped - ads->ldap.out.max_unwrapped; + /* + * Note that we have to truncate this to 0x2C + * (taken from a capture with LDAP unbind), as the + * signature size is not constant for Kerberos with + * arcfour-hmac-md5. + */ + ads->ldap.in.min_wrapped = MIN(ads->ldap.out.sig_size, 0x2C); + ads->ldap.in.max_wrapped = max_wrapped; + status = ads_setup_sasl_wrapping(ads, &ads_sasl_gensec_ops, auth_generic_state->gensec_security); if (!ADS_ERR_OK(status)) { DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n", ads_errstr(status))); @@ -339,12 +404,12 @@ done: return status; } -static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len) +static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len) { gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data; ADS_STATUS status; int gss_rc; - uint32 minor_status; + uint32_t minor_status; gss_buffer_desc unwrapped, wrapped; int conf_req_flag, conf_state; @@ -385,7 +450,7 @@ static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads) gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data; ADS_STATUS status; int gss_rc; - uint32 minor_status; + uint32_t minor_status; gss_buffer_desc unwrapped, wrapped; int conf_state; @@ -421,7 +486,7 @@ static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads) static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads) { gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data; - uint32 minor_status; + uint32_t minor_status; gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER); @@ -436,306 +501,37 @@ static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = { .disconnect = ads_sasl_gssapi_disconnect }; -/* - perform a LDAP/SASL/SPNEGO/GSSKRB5 bind -*/ -static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name) -{ - ADS_STATUS status; - bool ok; - uint32 minor_status; - int gss_rc, rc; - gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL; - gss_OID_desc krb5_mech_type = - {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") }; - gss_OID mech_type = &krb5_mech_type; - gss_OID actual_mech_type = GSS_C_NULL_OID; - const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL}; - gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; - gss_buffer_desc input_token, output_token; - uint32 req_flags, ret_flags; - uint32 req_tmp, ret_tmp; - DATA_BLOB unwrapped; - DATA_BLOB wrapped; - struct berval cred, *scred = NULL; - uint32_t context_validity = 0; - time_t context_endtime = 0; - - status = ads_init_gssapi_cred(ads, &gss_cred); - if (!ADS_ERR_OK(status)) { - goto failed; - } - - input_token.value = NULL; - input_token.length = 0; - - req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; - switch (ads->ldap.wrap_type) { - case ADS_SASLWRAP_TYPE_SEAL: - req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG; - break; - case ADS_SASLWRAP_TYPE_SIGN: - req_flags |= GSS_C_INTEG_FLAG; - break; - case ADS_SASLWRAP_TYPE_PLAIN: - break; - } - - /* Note: here we explicit ask for the krb5 mech_type */ - gss_rc = gss_init_sec_context(&minor_status, - gss_cred, - &context_handle, - serv_name, - mech_type, - req_flags, - 0, - NULL, - &input_token, - &actual_mech_type, - &output_token, - &ret_flags, - NULL); - if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) { - status = ADS_ERROR_GSS(gss_rc, minor_status); - goto failed; - } - - /* - * As some gssapi krb5 mech implementations - * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG - * to req_flags internaly, it's not possible to - * use plain or signing only connection via - * the gssapi interface. - * - * Because of this we need to check it the ret_flags - * has more flags as req_flags and correct the value - * of ads->ldap.wrap_type. - * - * I ads->auth.flags has ADS_AUTH_SASL_FORCE - * we need to give an error. - */ - req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); - ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); - - if (req_tmp == ret_tmp) { - /* everythings fine... */ - - } else if (req_flags & GSS_C_CONF_FLAG) { - /* - * here we wanted sealing but didn't got it - * from the gssapi library - */ - status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); - goto failed; - - } else if ((req_flags & GSS_C_INTEG_FLAG) && - !(ret_flags & GSS_C_INTEG_FLAG)) { - /* - * here we wanted siging but didn't got it - * from the gssapi library - */ - status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); - goto failed; - - } else if (ret_flags & GSS_C_CONF_FLAG) { - /* - * here we didn't want sealing - * but the gssapi library forces it - * so correct the needed wrap_type if - * the caller didn't forced siging only - */ - if (ads->auth.flags & ADS_AUTH_SASL_FORCE) { - status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); - goto failed; - } - - ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL; - req_flags = ret_flags; - - } else if (ret_flags & GSS_C_INTEG_FLAG) { - /* - * here we didn't want signing - * but the gssapi library forces it - * so correct the needed wrap_type if - * the caller didn't forced plain - */ - if (ads->auth.flags & ADS_AUTH_SASL_FORCE) { - status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); - goto failed; - } - - ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN; - req_flags = ret_flags; - } else { - /* - * This could (should?) not happen - */ - status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR); - goto failed; - - } - - /* and wrap that in a shiny SPNEGO wrapper */ - unwrapped = data_blob_const(output_token.value, output_token.length); - wrapped = spnego_gen_negTokenInit(talloc_tos(), - spnego_mechs, &unwrapped, NULL); - gss_release_buffer(&minor_status, &output_token); - if (unwrapped.length > wrapped.length) { - status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); - goto failed; - } - - cred.bv_val = (char *)wrapped.data; - cred.bv_len = wrapped.length; - - rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, - &scred); - data_blob_free(&wrapped); - if (rc != LDAP_SUCCESS) { - status = ADS_ERROR(rc); - goto failed; - } - - if (scred) { - wrapped = data_blob_const(scred->bv_val, scred->bv_len); - } else { - wrapped = data_blob_null; - } - - ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK, - OID_KERBEROS5_OLD, - &unwrapped); - if (scred) ber_bvfree(scred); - if (!ok) { - status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); - goto failed; - } - - input_token.value = unwrapped.data; - input_token.length = unwrapped.length; - - /* - * As we asked for mutal authentication - * we need to pass the servers response - * to gssapi - */ - gss_rc = gss_init_sec_context(&minor_status, - gss_cred, - &context_handle, - serv_name, - mech_type, - req_flags, - 0, - NULL, - &input_token, - &actual_mech_type, - &output_token, - &ret_flags, - NULL); - data_blob_free(&unwrapped); - if (gss_rc) { - status = ADS_ERROR_GSS(gss_rc, minor_status); - goto failed; - } - - gss_release_buffer(&minor_status, &output_token); - - /* - * If we the sign and seal options - * doesn't match after getting the response - * from the server, we don't want to use the connection - */ - req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); - ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); - - if (req_tmp != ret_tmp) { - /* everythings fine... */ - status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); - goto failed; - } - - gss_rc = - gss_context_time(&minor_status, context_handle, &context_validity); - if (gss_rc == GSS_S_COMPLETE) { - if (context_validity != 0) { - context_endtime = time(NULL) + context_validity; - DEBUG(10, ("context (service ticket) valid for " - "%u seconds\n", - context_validity)); - } else { - DEBUG(10, ("context (service ticket) expired\n")); - } - } else { - DEBUG(1, ("gss_context_time failed (%d,%u) -" - " this will be a one-time context\n", - gss_rc, minor_status)); - if (gss_rc == GSS_S_CONTEXT_EXPIRED) { - DEBUG(10, ("context (service ticket) expired\n")); - } - } - - if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { - uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED; - - gss_rc = gss_wrap_size_limit(&minor_status, context_handle, - (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL), - GSS_C_QOP_DEFAULT, - max_msg_size, &ads->ldap.out.max_unwrapped); - if (gss_rc) { - status = ADS_ERROR_GSS(gss_rc, minor_status); - goto failed; - } - - ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped; - ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */ - ads->ldap.in.max_wrapped = max_msg_size; - status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle); - if (!ADS_ERR_OK(status)) { - DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n", - ads_errstr(status))); - goto failed; - } - /* make sure we don't free context_handle */ - context_handle = GSS_C_NO_CONTEXT; - } - - ads->auth.tgs_expire = context_endtime; - status = ADS_SUCCESS; - -failed: - if (gss_cred != GSS_C_NO_CREDENTIAL) - gss_release_cred(&minor_status, &gss_cred); - if (context_handle != GSS_C_NO_CONTEXT) - gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER); - return status; -} - #endif /* HAVE_KRB5 */ #ifdef HAVE_KRB5 struct ads_service_principal { - char *string; + char *service; + char *hostname; + char *string; #ifdef HAVE_KRB5 - gss_name_t name; + gss_name_t name; #endif }; static void ads_free_service_principal(struct ads_service_principal *p) { + SAFE_FREE(p->service); + SAFE_FREE(p->hostname); SAFE_FREE(p->string); #ifdef HAVE_KRB5 if (p->name) { - uint32 minor_status; + uint32_t minor_status; gss_release_name(&minor_status, &p->name); } #endif ZERO_STRUCTP(p); } - -static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads, - char **returned_principal) +static ADS_STATUS ads_guess_target(ADS_STRUCT *ads, + char **service, + char **hostname, + char **principal) { ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY); char *princ = NULL; @@ -815,13 +611,26 @@ static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads, goto out; } + *service = SMB_STRDUP("ldap"); + if (*service == NULL) { + status = ADS_ERROR(LDAP_PARAM_ERROR); + goto out; + } + *hostname = SMB_STRDUP(server); + if (*hostname == NULL) { + SAFE_FREE(*service); + status = ADS_ERROR(LDAP_PARAM_ERROR); + goto out; + } rc = asprintf(&princ, "ldap/%s@%s", server, realm); if (rc == -1 || princ == NULL) { + SAFE_FREE(*service); + SAFE_FREE(*hostname); status = ADS_ERROR(LDAP_PARAM_ERROR); goto out; } - *returned_principal = princ; + *principal = princ; status = ADS_SUCCESS; out: @@ -830,7 +639,6 @@ out: } static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads, - const char *given_principal, struct ads_service_principal *p) { ADS_STATUS status; @@ -839,33 +647,18 @@ static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads, /* GSS_KRB5_NT_PRINCIPAL_NAME */ gss_OID_desc nt_principal = {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")}; - uint32 minor_status; + uint32_t minor_status; int gss_rc; #endif ZERO_STRUCTP(p); - /* I've seen a child Windows 2000 domain not send - the principal name back in the first round of - the SASL bind reply. So we guess based on server - name and realm. --jerry */ - /* Also try best guess when we get the w2k8 ignore principal - back, or when we are configured to ignore it - gd, - abartlet */ - - if (!lp_client_use_spnego_principal() || - !given_principal || - strequal(given_principal, ADS_IGNORE_PRINCIPAL)) { - - status = ads_guess_service_principal(ads, &p->string); - if (!ADS_ERR_OK(status)) { - return status; - } - } else { - p->string = SMB_STRDUP(given_principal); - if (!p->string) { - return ADS_ERROR(LDAP_NO_MEMORY); - } + status = ads_guess_target(ads, + &p->service, + &p->hostname, + &p->string); + if (!ADS_ERR_OK(status)) { + return status; } #ifdef HAVE_KRB5 @@ -882,63 +675,6 @@ static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads, return ADS_SUCCESS; } -/* - perform a LDAP/SASL/SPNEGO/KRB5 bind -*/ -static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal) -{ - DATA_BLOB blob = data_blob_null; - struct berval cred, *scred = NULL; - DATA_BLOB session_key = data_blob_null; - int rc; - - if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { - return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); - } - - rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal, - ads->auth.time_offset, &blob, &session_key, 0, - ads->auth.ccache_name, - &ads->auth.tgs_expire); - - if (rc) { - return ADS_ERROR_KRB5(rc); - } - - /* now send the auth packet and we should be done */ - cred.bv_val = (char *)blob.data; - cred.bv_len = blob.length; - - rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred); - - data_blob_free(&blob); - data_blob_free(&session_key); - if(scred) - ber_bvfree(scred); - - return ADS_ERROR(rc); -} - -static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, - struct ads_service_principal *p) -{ -#ifdef HAVE_KRB5 - /* - * we only use the gsskrb5 based implementation - * when sasl sign or seal is requested. - * - * This has the following reasons: - * - it's likely that the gssapi krb5 mech implementation - * doesn't support to negotiate plain connections - * - the ads_sasl_spnego_rawkrb5_bind is more robust - * against clock skew errors - */ - if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { - return ads_sasl_spnego_gsskrb5_bind(ads, p->name); - } -#endif - return ads_sasl_spnego_rawkrb5_bind(ads, p->string); -} #endif /* HAVE_KRB5 */ /* @@ -946,6 +682,8 @@ static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, */ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) { + TALLOC_CTX *frame = talloc_stackframe(); + struct ads_service_principal p = {0}; struct berval *scred=NULL; int rc, i; ADS_STATUS status; @@ -960,7 +698,7 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) if (rc != LDAP_SASL_BIND_IN_PROGRESS) { status = ADS_ERROR(rc); - goto failed; + goto done; } blob = data_blob(scred->bv_val, scred->bv_len); @@ -975,11 +713,10 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) reply */ if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) || OIDs[0] == NULL) { - data_blob_free(&blob); status = ADS_ERROR(LDAP_OPERATIONS_ERROR); - goto failed; + goto done; } - data_blob_free(&blob); + TALLOC_FREE(given_principal); /* make sure the server understands kerberos */ for (i=0;OIDs[i];i++) { @@ -992,59 +729,60 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) #endif talloc_free(OIDs[i]); } - DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal)); + + status = ads_generate_service_principal(ads, &p); + if (!ADS_ERR_OK(status)) { + goto done; + } #ifdef HAVE_KRB5 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) && got_kerberos_mechanism) { - struct ads_service_principal p; - - status = ads_generate_service_principal(ads, given_principal, &p); - TALLOC_FREE(given_principal); - if (!ADS_ERR_OK(status)) { - return status; - } - - status = ads_sasl_spnego_krb5_bind(ads, &p); + status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO", + CRED_MUST_USE_KERBEROS, + p.service, p.hostname, + blob); if (ADS_ERR_OK(status)) { ads_free_service_principal(&p); - return status; + goto done; } - DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, " + DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, " "calling kinit\n", ads_errstr(status))); status = ADS_ERROR_KRB5(ads_kinit_password(ads)); if (ADS_ERR_OK(status)) { - status = ads_sasl_spnego_krb5_bind(ads, &p); + status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO", + CRED_MUST_USE_KERBEROS, + p.service, p.hostname, + blob); if (!ADS_ERR_OK(status)) { DEBUG(0,("kinit succeeded but " - "ads_sasl_spnego_krb5_bind failed: %s\n", + "ads_sasl_spnego_gensec_bind(KRB5) failed: %s\n", ads_errstr(status))); } } - ads_free_service_principal(&p); - /* only fallback to NTLMSSP if allowed */ if (ADS_ERR_OK(status) || !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) { - return status; + goto done; } - } else -#endif - { - TALLOC_FREE(given_principal); } +#endif /* lets do NTLMSSP ... this has the big advantage that we don't need to sync clocks, and we don't rely on special versions of the krb5 library for HMAC_MD4 encryption */ - return ads_sasl_spnego_ntlmssp_bind(ads); - -failed: + status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO", + CRED_DONT_USE_KERBEROS, + p.service, p.hostname, + data_blob_null); +done: + ads_free_service_principal(&p); + TALLOC_FREE(frame); return status; } @@ -1059,20 +797,20 @@ failed: */ static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name) { - uint32 minor_status; + uint32_t minor_status; gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; gss_OID mech_type = GSS_C_NULL_OID; gss_buffer_desc output_token, input_token; - uint32 req_flags, ret_flags; + uint32_t req_flags, ret_flags; int conf_state; struct berval cred; struct berval *scred = NULL; int i=0; int gss_rc, rc; - uint8 *p; - uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED; - uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN; + uint8_t *p; + uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED; + uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN; ADS_STATUS status; input_token.value = NULL; @@ -1149,7 +887,7 @@ static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv goto failed; } - p = (uint8 *)output_token.value; + p = (uint8_t *)output_token.value; #if 0 file_save("sasl_gssapi.dat", output_token.value, output_token.length); @@ -1187,7 +925,7 @@ static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); goto failed; } - p = (uint8 *)output_token.value; + p = (uint8_t *)output_token.value; RSIVAL(p,0,max_msg_size); SCVAL(p,0,ads->ldap.wrap_type); @@ -1266,7 +1004,7 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) ADS_STATUS status; struct ads_service_principal p; - status = ads_generate_service_principal(ads, NULL, &p); + status = ads_generate_service_principal(ads, &p); if (!ADS_ERR_OK(status)) { return status; } diff --git a/source3/libads/sasl_wrapping.c b/source3/libads/sasl_wrapping.c index d7353ac79c9..9296d60ba9d 100644 --- a/source3/libads/sasl_wrapping.c +++ b/source3/libads/sasl_wrapping.c @@ -171,7 +171,7 @@ eagain: return -1; } -static ber_slen_t ads_saslwrap_prepare_outbuf(ADS_STRUCT *ads, uint32 len) +static ber_slen_t ads_saslwrap_prepare_outbuf(ADS_STRUCT *ads, uint32_t len) { ads->ldap.out.ofs = 0; ads->ldap.out.left = 0; diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index 187e524606c..d7c7679d26e 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -846,7 +846,7 @@ static NTSTATUS libnet_join_connect_dc_ipc(const char *dc, domain, pass, flags, - SMB_SIGNING_DEFAULT); + SMB_SIGNING_IPC_DEFAULT); } /**************************************************************** @@ -1407,7 +1407,7 @@ NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx, netbios_domain_name, machine_password, flags, - SMB_SIGNING_DEFAULT); + SMB_SIGNING_IPC_DEFAULT); E_md4hash(machine_password, current_nt_hash.hash); SAFE_FREE(machine_password); @@ -1421,7 +1421,7 @@ NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx, NULL, "", 0, - SMB_SIGNING_DEFAULT); + SMB_SIGNING_IPC_DEFAULT); } if (!NT_STATUS_IS_OK(status)) { diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c index 8db3cdd227a..fc31064ea1d 100644 --- a/source3/librpc/crypto/gse.c +++ b/source3/librpc/crypto/gse.c @@ -33,15 +33,20 @@ #if defined(HAVE_KRB5) #include "auth/kerberos/pac_utils.h" +#include "auth/kerberos/gssapi_helper.h" #include "gse_krb5.h" static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min); +static size_t gensec_gse_sig_size(struct gensec_security *gensec_security, + size_t data_size); struct gse_context { gss_ctx_id_t gssapi_context; gss_name_t server_name; gss_name_t client_name; OM_uint32 gss_want_flags, gss_got_flags; + size_t max_wrap_buf_size; + size_t sig_size; gss_cred_id_t delegated_cred_handle; @@ -132,6 +137,7 @@ static NTSTATUS gse_context_init(TALLOC_CTX *mem_ctx, talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor); gse_ctx->expire_time = GENSEC_EXPIRE_TIME_INFINITY; + gse_ctx->max_wrap_buf_size = UINT16_MAX; memcpy(&gse_ctx->gss_mech, gss_mech_krb5, sizeof(gss_OID_desc)); @@ -197,8 +203,11 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx, { struct gse_context *gse_ctx; OM_uint32 gss_maj, gss_min; - gss_buffer_desc name_buffer = {0, NULL}; + gss_buffer_desc name_buffer = GSS_C_EMPTY_BUFFER; gss_OID_set_desc mech_set; +#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X + gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; +#endif NTSTATUS status; if (!server || !service) { @@ -251,12 +260,34 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx, &gse_ctx->creds, NULL, NULL); if (gss_maj) { - DEBUG(0, ("gss_acquire_creds failed for %s, with [%s]\n", - (char *)name_buffer.value, + DEBUG(5, ("gss_acquire_creds failed for GSS_C_NO_NAME with [%s] -" + "the caller may retry after a kinit.\n", + gse_errstr(gse_ctx, gss_maj, gss_min))); + status = NT_STATUS_INTERNAL_ERROR; + goto err_out; + } + +#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X + /* + * Don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG. + * + * This allows us to disable SIGN and SEAL for + * AUTH_LEVEL_CONNECT and AUTH_LEVEL_INTEGRITY. + * + * https://groups.yahoo.com/neo/groups/cat-ietf/conversations/topics/575 + * http://krbdev.mit.edu/rt/Ticket/Display.html?id=6938 + */ + gss_maj = gss_set_cred_option(&gss_min, &gse_ctx->creds, + GSS_KRB5_CRED_NO_CI_FLAGS_X, + &empty_buffer); + if (gss_maj) { + DEBUG(0, ("gss_set_cred_option(GSS_KRB5_CRED_NO_CI_FLAGS_X), " + "failed with [%s]\n", gse_errstr(gse_ctx, gss_maj, gss_min))); status = NT_STATUS_INTERNAL_ERROR; goto err_out; } +#endif *_gse_ctx = gse_ctx; TALLOC_FREE(name_buffer.value); @@ -541,193 +572,6 @@ done: return errstr; } -static size_t gse_get_signature_length(struct gse_context *gse_ctx, - bool seal, size_t payload_size) -{ - OM_uint32 gss_min, gss_maj; - gss_iov_buffer_desc iov[2]; - int sealed; - - /* - * gss_wrap_iov_length() only needs the type and length - */ - iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; - iov[0].buffer.value = NULL; - iov[0].buffer.length = 0; - iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; - iov[1].buffer.value = NULL; - iov[1].buffer.length = payload_size; - - gss_maj = gss_wrap_iov_length(&gss_min, gse_ctx->gssapi_context, - seal, GSS_C_QOP_DEFAULT, - &sealed, iov, 2); - if (gss_maj) { - DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n", - gse_errstr(talloc_tos(), gss_maj, gss_min))); - return 0; - } - - return iov[0].buffer.length; -} - -static NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx, - DATA_BLOB *data, DATA_BLOB *signature) -{ - OM_uint32 gss_min, gss_maj; - gss_iov_buffer_desc iov[2]; - int req_seal = 1; /* setting to 1 means we request sign+seal */ - int sealed = 1; - NTSTATUS status; - - /* allocate the memory ourselves so we do not need to talloc_memdup */ - signature->length = gse_get_signature_length(gse_ctx, true, data->length); - if (!signature->length) { - return NT_STATUS_INTERNAL_ERROR; - } - signature->data = (uint8_t *)talloc_size(mem_ctx, signature->length); - if (!signature->data) { - return NT_STATUS_NO_MEMORY; - } - iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; - iov[0].buffer.value = signature->data; - iov[0].buffer.length = signature->length; - - /* data is encrypted in place, which is ok */ - iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; - iov[1].buffer.value = data->data; - iov[1].buffer.length = data->length; - - gss_maj = gss_wrap_iov(&gss_min, gse_ctx->gssapi_context, - req_seal, GSS_C_QOP_DEFAULT, - &sealed, iov, 2); - if (gss_maj) { - DEBUG(0, ("gss_wrap_iov failed with [%s]\n", - gse_errstr(talloc_tos(), gss_maj, gss_min))); - status = NT_STATUS_ACCESS_DENIED; - goto done; - } - - if (!sealed) { - DEBUG(0, ("gss_wrap_iov says data was not sealed!\n")); - status = NT_STATUS_ACCESS_DENIED; - goto done; - } - - status = NT_STATUS_OK; - - DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n", - (int)iov[1].buffer.length, (int)iov[0].buffer.length)); - -done: - return status; -} - -static NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx, - DATA_BLOB *data, const DATA_BLOB *signature) -{ - OM_uint32 gss_min, gss_maj; - gss_iov_buffer_desc iov[2]; - int sealed; - NTSTATUS status; - - iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; - iov[0].buffer.value = signature->data; - iov[0].buffer.length = signature->length; - - /* data is decrypted in place, which is ok */ - iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; - iov[1].buffer.value = data->data; - iov[1].buffer.length = data->length; - - gss_maj = gss_unwrap_iov(&gss_min, gse_ctx->gssapi_context, - &sealed, NULL, iov, 2); - if (gss_maj) { - DEBUG(0, ("gss_unwrap_iov failed with [%s]\n", - gse_errstr(talloc_tos(), gss_maj, gss_min))); - status = NT_STATUS_ACCESS_DENIED; - goto done; - } - - if (!sealed) { - DEBUG(0, ("gss_unwrap_iov says data is not sealed!\n")); - status = NT_STATUS_ACCESS_DENIED; - goto done; - } - - status = NT_STATUS_OK; - - DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n", - (int)iov[1].buffer.length, (int)iov[0].buffer.length)); - -done: - return status; -} - -static NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx, - DATA_BLOB *data, DATA_BLOB *signature) -{ - OM_uint32 gss_min, gss_maj; - gss_buffer_desc in_data = { 0, NULL }; - gss_buffer_desc out_data = { 0, NULL}; - NTSTATUS status; - - in_data.value = data->data; - in_data.length = data->length; - - gss_maj = gss_get_mic(&gss_min, gse_ctx->gssapi_context, - GSS_C_QOP_DEFAULT, - &in_data, &out_data); - if (gss_maj) { - DEBUG(0, ("gss_get_mic failed with [%s]\n", - gse_errstr(talloc_tos(), gss_maj, gss_min))); - status = NT_STATUS_ACCESS_DENIED; - goto done; - } - - *signature = data_blob_talloc(mem_ctx, - out_data.value, out_data.length); - if (!signature->data) { - status = NT_STATUS_NO_MEMORY; - goto done; - } - - status = NT_STATUS_OK; - -done: - if (out_data.value) { - gss_maj = gss_release_buffer(&gss_min, &out_data); - } - return status; -} - -static NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx, - const DATA_BLOB *data, const DATA_BLOB *signature) -{ - OM_uint32 gss_min, gss_maj; - gss_buffer_desc in_data = { 0, NULL }; - gss_buffer_desc in_token = { 0, NULL}; - NTSTATUS status; - - in_data.value = data->data; - in_data.length = data->length; - in_token.value = signature->data; - in_token.length = signature->length; - - gss_maj = gss_verify_mic(&gss_min, gse_ctx->gssapi_context, - &in_data, &in_token, NULL); - if (gss_maj) { - DEBUG(0, ("gss_verify_mic failed with [%s]\n", - gse_errstr(talloc_tos(), gss_maj, gss_min))); - status = NT_STATUS_ACCESS_DENIED; - goto done; - } - - status = NT_STATUS_OK; - -done: - return status; -} - static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security) { struct gse_context *gse_ctx; @@ -753,6 +597,9 @@ static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security) return NT_STATUS_INVALID_PARAMETER; } + if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { + do_sign = true; + } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { do_sign = true; } @@ -921,8 +768,31 @@ static NTSTATUS gensec_gse_seal_packet(struct gensec_security *gensec_security, struct gse_context *gse_ctx = talloc_get_type_abort(gensec_security->private_data, struct gse_context); - DATA_BLOB payload = data_blob_const(data, length); - return gse_seal(mem_ctx, gse_ctx, &payload, sig); + bool hdr_signing = false; + size_t sig_size = 0; + NTSTATUS status; + + if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) { + hdr_signing = true; + } + + sig_size = gensec_gse_sig_size(gensec_security, length); + + status = gssapi_seal_packet(gse_ctx->gssapi_context, + &gse_ctx->gss_mech, + hdr_signing, sig_size, + data, length, + whole_pdu, pdu_length, + mem_ctx, sig); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%ju," + "data=%ju,pdu=%ju) failed: %s\n", + hdr_signing, sig_size, length, pdu_length, + nt_errstr(status))); + return status; + } + + return NT_STATUS_OK; } static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security, @@ -933,8 +803,28 @@ static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security struct gse_context *gse_ctx = talloc_get_type_abort(gensec_security->private_data, struct gse_context); - DATA_BLOB payload = data_blob_const(data, length); - return gse_unseal(talloc_tos() /* unused */, gse_ctx, &payload, sig); + bool hdr_signing = false; + NTSTATUS status; + + if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) { + hdr_signing = true; + } + + status = gssapi_unseal_packet(gse_ctx->gssapi_context, + &gse_ctx->gss_mech, + hdr_signing, + data, length, + whole_pdu, pdu_length, + sig); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%ju," + "data=%ju,pdu=%ju) failed: %s\n", + hdr_signing, sig->length, length, pdu_length, + nt_errstr(status))); + return status; + } + + return NT_STATUS_OK; } static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security, @@ -946,8 +836,28 @@ static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security, struct gse_context *gse_ctx = talloc_get_type_abort(gensec_security->private_data, struct gse_context); - DATA_BLOB payload = data_blob_const(data, length); - return gse_sign(mem_ctx, gse_ctx, &payload, sig); + bool hdr_signing = false; + NTSTATUS status; + + if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) { + hdr_signing = true; + } + + status = gssapi_sign_packet(gse_ctx->gssapi_context, + &gse_ctx->gss_mech, + hdr_signing, + data, length, + whole_pdu, pdu_length, + mem_ctx, sig); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u," + "data=%ju,pdu=%ju) failed: %s\n", + hdr_signing, length, pdu_length, + nt_errstr(status))); + return status; + } + + return NT_STATUS_OK; } static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security, @@ -958,8 +868,28 @@ static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security, struct gse_context *gse_ctx = talloc_get_type_abort(gensec_security->private_data, struct gse_context); - DATA_BLOB payload = data_blob_const(data, length); - return gse_sigcheck(NULL, gse_ctx, &payload, sig); + bool hdr_signing = false; + NTSTATUS status; + + if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) { + hdr_signing = true; + } + + status = gssapi_check_packet(gse_ctx->gssapi_context, + &gse_ctx->gss_mech, + hdr_signing, + data, length, + whole_pdu, pdu_length, + sig); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%ju" + "data=%ju,pdu=%ju) failed: %s\n", + hdr_signing, sig->length, length, pdu_length, + nt_errstr(status))); + return status; + } + + return NT_STATUS_OK; } /* Try to figure out what features we actually got on the connection */ @@ -970,18 +900,15 @@ static bool gensec_gse_have_feature(struct gensec_security *gensec_security, talloc_get_type_abort(gensec_security->private_data, struct gse_context); + if (feature & GENSEC_FEATURE_SESSION_KEY) { + return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG; + } if (feature & GENSEC_FEATURE_SIGN) { return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG; } if (feature & GENSEC_FEATURE_SEAL) { return gse_ctx->gss_got_flags & GSS_C_CONF_FLAG; } - if (feature & GENSEC_FEATURE_SESSION_KEY) { - /* Only for GSE/Krb5 */ - if (smb_gss_oid_equal(gse_ctx->ret_mech, gss_mech_krb5)) { - return true; - } - } if (feature & GENSEC_FEATURE_DCE_STYLE) { return gse_ctx->gss_got_flags & GSS_C_DCE_STYLE; } @@ -1019,6 +946,17 @@ static bool gensec_gse_have_feature(struct gensec_security *gensec_security, if (feature & GENSEC_FEATURE_ASYNC_REPLIES) { return true; } + if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) { + if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { + return true; + } + + if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { + return true; + } + + return false; + } return false; } @@ -1126,6 +1064,40 @@ static NTSTATUS gensec_gse_session_info(struct gensec_security *gensec_security, return NT_STATUS_OK; } +static size_t gensec_gse_max_input_size(struct gensec_security *gensec_security) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + OM_uint32 maj_stat, min_stat; + OM_uint32 max_input_size; + + maj_stat = gss_wrap_size_limit(&min_stat, + gse_ctx->gssapi_context, + gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL), + GSS_C_QOP_DEFAULT, + gse_ctx->max_wrap_buf_size, + &max_input_size); + if (GSS_ERROR(maj_stat)) { + TALLOC_CTX *mem_ctx = talloc_new(NULL); + DEBUG(1, ("gensec_gssapi_max_input_size: determining signature size with gss_wrap_size_limit failed: %s\n", + gse_errstr(mem_ctx, maj_stat, min_stat))); + talloc_free(mem_ctx); + return 0; + } + + return max_input_size; +} + +/* Find out the maximum output size negotiated on this connection */ +static size_t gensec_gse_max_wrapped_size(struct gensec_security *gensec_security) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + return gse_ctx->max_wrap_buf_size; +} + static size_t gensec_gse_sig_size(struct gensec_security *gensec_security, size_t data_size) { @@ -1133,9 +1105,15 @@ static size_t gensec_gse_sig_size(struct gensec_security *gensec_security, talloc_get_type_abort(gensec_security->private_data, struct gse_context); - return gse_get_signature_length(gse_ctx, - gensec_security->want_features & GENSEC_FEATURE_SEAL, - data_size); + if (gse_ctx->sig_size > 0) { + return gse_ctx->sig_size; + } + + gse_ctx->sig_size = gssapi_get_sig_size(gse_ctx->gssapi_context, + &gse_ctx->gss_mech, + gse_ctx->gss_want_flags, + data_size); + return gse_ctx->sig_size; } static const char *gensec_gse_krb5_oids[] = { @@ -1159,6 +1137,8 @@ const struct gensec_security_ops gensec_gse_krb5_security_ops = { .check_packet = gensec_gse_check_packet, .seal_packet = gensec_gse_seal_packet, .unseal_packet = gensec_gse_unseal_packet, + .max_input_size = gensec_gse_max_input_size, + .max_wrapped_size = gensec_gse_max_wrapped_size, .wrap = gensec_gse_wrap, .unwrap = gensec_gse_unwrap, .have_feature = gensec_gse_have_feature, diff --git a/source3/librpc/rpc/dcerpc.h b/source3/librpc/rpc/dcerpc.h index e7d66b7252b..183801228f5 100644 --- a/source3/librpc/rpc/dcerpc.h +++ b/source3/librpc/rpc/dcerpc.h @@ -40,6 +40,7 @@ struct gensec_security; struct pipe_auth_data { enum dcerpc_AuthType auth_type; enum dcerpc_AuthLevel auth_level; + uint32_t auth_context_id; bool client_hdr_signing; bool hdr_signing; bool verified_bitmask1; @@ -69,10 +70,6 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx, uint32_t auth_context_id, const DATA_BLOB *credentials, DATA_BLOB *blob); -NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx, - const DATA_BLOB *blob, - struct dcerpc_auth *r, - bool bigendian); NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth, size_t header_len, size_t data_left, size_t max_xmit_frag, @@ -83,8 +80,7 @@ NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth, NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, struct ncacn_packet *pkt, DATA_BLOB *pkt_trailer, - size_t header_size, - DATA_BLOB *raw_pkt, - size_t *pad_len); + uint8_t header_size, + DATA_BLOB *raw_pkt); #endif /* __S3_DCERPC_H__ */ diff --git a/source3/librpc/rpc/dcerpc_helpers.c b/source3/librpc/rpc/dcerpc_helpers.c index 1193baa7983..aab43a1abd4 100644 --- a/source3/librpc/rpc/dcerpc_helpers.c +++ b/source3/librpc/rpc/dcerpc_helpers.c @@ -177,47 +177,6 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx, } /** -* @brief Decodes a dcerpc_auth blob -* -* @param mem_ctx The memory context on which to allocate the packet -* elements -* @param blob The blob of data to decode -* @param r An empty dcerpc_auth structure, must not be NULL -* -* @return a NTSTATUS error code -*/ -NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx, - const DATA_BLOB *blob, - struct dcerpc_auth *r, - bool bigendian) -{ - enum ndr_err_code ndr_err; - struct ndr_pull *ndr; - - ndr = ndr_pull_init_blob(blob, mem_ctx); - if (!ndr) { - return NT_STATUS_NO_MEMORY; - } - if (bigendian) { - ndr->flags |= LIBNDR_FLAG_BIGENDIAN; - } - - ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, r); - - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - talloc_free(ndr); - return ndr_map_error2ntstatus(ndr_err); - } - talloc_free(ndr); - - if (DEBUGLEVEL >= 10) { - NDR_PRINT_DEBUG(dcerpc_auth, r); - } - - return NT_STATUS_OK; -} - -/** * @brief Calculate how much data we can in a packet, including calculating * auth token and pad lengths. * @@ -444,7 +403,7 @@ NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth, auth->auth_type, auth->auth_level, pad_len, - 1 /* context id. */, + auth->auth_context_id, &auth_blob, &auth_info); if (!NT_STATUS_IS_OK(status)) { @@ -481,19 +440,18 @@ NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth, * * @param auth The auth data for the connection * @param pkt The actual ncacn_packet -* @param pkt_trailer The stub_and_verifier part of the packet +* @param pkt_trailer [in][out] The stub_and_verifier part of the packet, +* the auth_trailer and padding will be removed. * @param header_size The header size * @param raw_pkt The whole raw packet data blob -* @param pad_len [out] The padding length used in the packet * * @return A NTSTATUS error code */ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, struct ncacn_packet *pkt, DATA_BLOB *pkt_trailer, - size_t header_size, - DATA_BLOB *raw_pkt, - size_t *pad_len) + uint8_t header_size, + DATA_BLOB *raw_pkt) { struct gensec_security *gensec_security; NTSTATUS status; @@ -502,6 +460,14 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, DATA_BLOB full_pkt; DATA_BLOB data; + /* + * These check should be done in the caller. + */ + SMB_ASSERT(raw_pkt->length == pkt->frag_length); + SMB_ASSERT(header_size <= pkt->frag_length); + SMB_ASSERT(pkt_trailer->length < pkt->frag_length); + SMB_ASSERT((pkt_trailer->length + header_size) <= pkt->frag_length); + switch (auth->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: DEBUG(10, ("Requested Privacy.\n")); @@ -515,7 +481,6 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, if (pkt->auth_length != 0) { break; } - *pad_len = 0; return NT_STATUS_OK; case DCERPC_AUTH_LEVEL_NONE: @@ -524,7 +489,6 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, "authenticated connection!\n")); return NT_STATUS_INVALID_PARAMETER; } - *pad_len = 0; return NT_STATUS_OK; default: @@ -533,16 +497,8 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, return NT_STATUS_INVALID_PARAMETER; } - /* Paranioa checks for auth_length. */ - if (pkt->auth_length > pkt->frag_length) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - if (((unsigned int)pkt->auth_length - + DCERPC_AUTH_TRAILER_LENGTH < (unsigned int)pkt->auth_length) || - ((unsigned int)pkt->auth_length - + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) { - /* Integer wrap attempt. */ - return NT_STATUS_INFO_LENGTH_MISMATCH; + if (pkt->auth_length == 0) { + return NT_STATUS_INVALID_PARAMETER; } status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer, @@ -551,10 +507,23 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, return status; } + if (auth_info.auth_type != auth->auth_type) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (auth_info.auth_level != auth->auth_level) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (auth_info.auth_context_id != auth->auth_context_id) { + return NT_STATUS_INVALID_PARAMETER; + } + + pkt_trailer->length -= auth_length; data = data_blob_const(raw_pkt->data + header_size, - pkt_trailer->length - auth_length); - full_pkt = data_blob_const(raw_pkt->data, - raw_pkt->length - auth_info.credentials.length); + pkt_trailer->length); + full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length); + full_pkt.length -= auth_info.credentials.length; switch (auth->auth_type) { case DCERPC_AUTH_TYPE_NONE: @@ -579,10 +548,13 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, * pkt_trailer actually has a copy of the raw data, and they * are still both used in later calls */ if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + if (pkt_trailer->length != data.length) { + return NT_STATUS_INVALID_PARAMETER; + } memcpy(pkt_trailer->data, data.data, data.length); } - *pad_len = auth_info.auth_pad_length; + pkt_trailer->length -= auth_info.auth_pad_length; data_blob_free(&auth_info.credentials); return NT_STATUS_OK; } diff --git a/source3/libsmb/auth_generic.c b/source3/libsmb/auth_generic.c index 1f6c681a6e5..2e45cdbc53e 100644 --- a/source3/libsmb/auth_generic.c +++ b/source3/libsmb/auth_generic.c @@ -78,7 +78,7 @@ NTSTATUS auth_generic_client_prepare(TALLOC_CTX *mem_ctx, struct auth_generic_st } backends = talloc_zero_array(gensec_settings, - const struct gensec_security_ops *, 6); + const struct gensec_security_ops *, 7); if (backends == NULL) { TALLOC_FREE(ans); return NT_STATUS_NO_MEMORY; @@ -92,7 +92,8 @@ NTSTATUS auth_generic_client_prepare(TALLOC_CTX *mem_ctx, struct auth_generic_st backends[idx++] = &gensec_gse_krb5_security_ops; #endif - backends[idx++] = &gensec_ntlmssp3_client_ops; + backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP); + backends[idx++] = gensec_security_by_name(NULL, "ntlmssp_resume_ccache"); backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO); backends[idx++] = gensec_security_by_auth_type(NULL, DCERPC_AUTH_TYPE_SCHANNEL); @@ -143,6 +144,29 @@ NTSTATUS auth_generic_client_start(struct auth_generic_state *ans, const char *o return NT_STATUS_OK; } +NTSTATUS auth_generic_client_start_by_name(struct auth_generic_state *ans, + const char *name) +{ + NTSTATUS status; + + /* Transfer the credentials to gensec */ + status = gensec_set_credentials(ans->gensec_security, ans->credentials); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to set GENSEC credentials: %s\n", + nt_errstr(status))); + return status; + } + talloc_unlink(ans, ans->credentials); + ans->credentials = NULL; + + status = gensec_start_mech_by_name(ans->gensec_security, name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + NTSTATUS auth_generic_client_start_by_authtype(struct auth_generic_state *ans, uint8_t auth_type, uint8_t auth_level) @@ -167,3 +191,26 @@ NTSTATUS auth_generic_client_start_by_authtype(struct auth_generic_state *ans, return NT_STATUS_OK; } + +NTSTATUS auth_generic_client_start_by_sasl(struct auth_generic_state *ans, + const char **sasl_list) +{ + NTSTATUS status; + + /* Transfer the credentials to gensec */ + status = gensec_set_credentials(ans->gensec_security, ans->credentials); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to set GENSEC credentials: %s\n", + nt_errstr(status))); + return status; + } + talloc_unlink(ans, ans->credentials); + ans->credentials = NULL; + + status = gensec_start_mech_by_sasl_list(ans->gensec_security, sasl_list); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 46d3da3fc45..039fba2c71b 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -26,7 +26,10 @@ #include "../libcli/auth/libcli_auth.h" #include "../libcli/auth/spnego.h" #include "smb_krb5.h" -#include "../auth/ntlmssp/ntlmssp.h" +#include "auth/credentials/credentials.h" +#include "auth/gensec/gensec.h" +#include "auth/ntlmssp/ntlmssp.h" +#include "auth_generic.h" #include "libads/kerberos_proto.h" #include "krb5_env.h" #include "../lib/util/tevent_ntstatus.h" @@ -1282,218 +1285,179 @@ static void use_in_memory_ccache(void) { setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1); } +#endif /* HAVE_KRB5 */ + /**************************************************************************** - Do a spnego/kerberos encrypted session setup. + Do a spnego/NTLMSSP encrypted session setup. ****************************************************************************/ -struct cli_session_setup_kerberos_state { +struct cli_session_setup_gensec_state { + struct tevent_context *ev; struct cli_state *cli; - DATA_BLOB negTokenTarg; - DATA_BLOB session_key_krb5; - ADS_STATUS ads_status; + struct auth_generic_state *auth_generic; + bool is_anonymous; + DATA_BLOB blob_in; + uint8_t *inbuf; + struct iovec *recv_iov; + DATA_BLOB blob_out; + bool local_ready; + bool remote_ready; + DATA_BLOB session_key; }; -static void cli_session_setup_kerberos_done(struct tevent_req *subreq); +static int cli_session_setup_gensec_state_destructor( + struct cli_session_setup_gensec_state *state) +{ + TALLOC_FREE(state->auth_generic); + data_blob_clear_free(&state->session_key); + return 0; +} -static struct tevent_req *cli_session_setup_kerberos_send( +static void cli_session_setup_gensec_local_next(struct tevent_req *req); +static void cli_session_setup_gensec_local_done(struct tevent_req *subreq); +static void cli_session_setup_gensec_remote_next(struct tevent_req *req); +static void cli_session_setup_gensec_remote_done(struct tevent_req *subreq); +static void cli_session_setup_gensec_ready(struct tevent_req *req); + +static struct tevent_req *cli_session_setup_gensec_send( TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, - const char *principal) + const char *user, const char *pass, const char *domain, + enum credentials_use_kerberos krb5_state, + const char *target_service, + const char *target_hostname, + const char *target_principal) { - struct tevent_req *req, *subreq; - struct cli_session_setup_kerberos_state *state; - int rc; - - DEBUG(2,("Doing kerberos session setup\n")); + struct tevent_req *req; + struct cli_session_setup_gensec_state *state; + NTSTATUS status; + bool use_spnego_principal = lp_client_use_spnego_principal(); req = tevent_req_create(mem_ctx, &state, - struct cli_session_setup_kerberos_state); + struct cli_session_setup_gensec_state); if (req == NULL) { return NULL; } + state->ev = ev; state->cli = cli; - state->ads_status = ADS_SUCCESS; - /* - * Ok, this is cheating: spnego_gen_krb5_negTokenInit can block if - * we have to acquire a ticket. To be fixed later :-) - */ - rc = spnego_gen_krb5_negTokenInit(state, principal, 0, &state->negTokenTarg, - &state->session_key_krb5, 0, NULL, NULL); - if (rc) { - DEBUG(1, ("cli_session_setup_kerberos: " - "spnego_gen_krb5_negTokenInit failed: %s\n", - error_message(rc))); - state->ads_status = ADS_ERROR_KRB5(rc); - tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL); + talloc_set_destructor( + state, cli_session_setup_gensec_state_destructor); + + status = auth_generic_client_prepare(state, &state->auth_generic); + if (tevent_req_nterror(req, status)) { return tevent_req_post(req, ev); } -#if 0 - file_save("negTokenTarg.dat", state->negTokenTarg.data, - state->negTokenTarg.length); -#endif - - if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { - state->cli->smb2.session = smbXcli_session_create(cli, - cli->conn); - if (tevent_req_nomem(state->cli->smb2.session, req)) { - return tevent_req_post(req, ev); + gensec_want_feature(state->auth_generic->gensec_security, + GENSEC_FEATURE_SESSION_KEY); + if (cli->use_ccache) { + gensec_want_feature(state->auth_generic->gensec_security, + GENSEC_FEATURE_NTLM_CCACHE); + if (pass != NULL && strlen(pass) == 0) { + /* + * some callers pass "" as no password + * + * GENSEC_FEATURE_NTLM_CCACHE only handles + * NULL as no password. + */ + pass = NULL; } } - subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg); - if (tevent_req_nomem(subreq, req)) { + status = auth_generic_set_username(state->auth_generic, user); + if (tevent_req_nterror(req, status)) { return tevent_req_post(req, ev); } - tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req); - return req; -} -static void cli_session_setup_kerberos_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct cli_session_setup_kerberos_state *state = tevent_req_data( - req, struct cli_session_setup_kerberos_state); - uint8_t *inbuf = NULL; - struct iovec *recv_iov = NULL; - NTSTATUS status; - - status = cli_sesssetup_blob_recv(subreq, state, - NULL, &inbuf, &recv_iov); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return; + status = auth_generic_set_domain(state->auth_generic, domain); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); } - if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { - struct smbXcli_session *session = state->cli->smb2.session; - status = smb2cli_session_set_session_key(session, - state->session_key_krb5, - recv_iov); - if (tevent_req_nterror(req, status)) { - return; + if (cli->pw_nt_hash) { + struct samr_Password nt_hash; + size_t converted; + bool ok; + + if (pass == NULL) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); + return tevent_req_post(req, ev); } - } else { - struct smbXcli_session *session = state->cli->smb1.session; - status = smb1cli_session_set_session_key(session, - state->session_key_krb5); - if (tevent_req_nterror(req, status)) { - return; + converted = strhex_to_str((char *)nt_hash.hash, + sizeof(nt_hash.hash), + pass, strlen(pass)); + if (converted != sizeof(nt_hash.hash)) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); + return tevent_req_post(req, ev); } - if (smb1cli_conn_activate_signing(state->cli->conn, state->session_key_krb5, - data_blob_null) - && !smb1cli_conn_check_signing(state->cli->conn, inbuf, 1)) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; + ok = cli_credentials_set_nt_hash(state->auth_generic->credentials, + &nt_hash, CRED_SPECIFIED); + if (!ok) { + tevent_req_oom(req); + return tevent_req_post(req, ev); + } + } else { + status = auth_generic_set_password(state->auth_generic, pass); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); } } - tevent_req_done(req); -} + cli_credentials_set_kerberos_state(state->auth_generic->credentials, + krb5_state); -static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req) -{ - struct cli_session_setup_kerberos_state *state = tevent_req_data( - req, struct cli_session_setup_kerberos_state); - NTSTATUS status; - - if (tevent_req_is_nterror(req, &status)) { - return ADS_ERROR_NT(status); + if (krb5_state == CRED_DONT_USE_KERBEROS) { + use_spnego_principal = false; } - return state->ads_status; -} - -#endif /* HAVE_KRB5 */ - -/**************************************************************************** - Do a spnego/NTLMSSP encrypted session setup. -****************************************************************************/ - -struct cli_session_setup_ntlmssp_state { - struct tevent_context *ev; - struct cli_state *cli; - struct ntlmssp_state *ntlmssp_state; - int turn; - DATA_BLOB blob_out; -}; -static int cli_session_setup_ntlmssp_state_destructor( - struct cli_session_setup_ntlmssp_state *state) -{ - if (state->ntlmssp_state != NULL) { - TALLOC_FREE(state->ntlmssp_state); + if (target_service != NULL) { + status = gensec_set_target_service( + state->auth_generic->gensec_security, + target_service); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } } - return 0; -} -static void cli_session_setup_ntlmssp_done(struct tevent_req *req); + if (target_hostname != NULL) { + status = gensec_set_target_hostname( + state->auth_generic->gensec_security, + target_hostname); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + } -static struct tevent_req *cli_session_setup_ntlmssp_send( - TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, - const char *user, const char *pass, const char *domain) -{ - struct tevent_req *req, *subreq; - struct cli_session_setup_ntlmssp_state *state; - NTSTATUS status; - DATA_BLOB blob_out; - const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL}; + if (target_principal != NULL) { + status = gensec_set_target_principal( + state->auth_generic->gensec_security, + target_principal); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + use_spnego_principal = false; + } else if (target_service != NULL && target_hostname != NULL) { + use_spnego_principal = false; + } - req = tevent_req_create(mem_ctx, &state, - struct cli_session_setup_ntlmssp_state); - if (req == NULL) { - return NULL; + if (use_spnego_principal) { + const DATA_BLOB *b; + b = smbXcli_conn_server_gss_blob(cli->conn); + if (b != NULL) { + state->blob_in = *b; + } } - state->ev = ev; - state->cli = cli; - state->turn = 1; - state->ntlmssp_state = NULL; - talloc_set_destructor( - state, cli_session_setup_ntlmssp_state_destructor); + state->is_anonymous = cli_credentials_is_anonymous(state->auth_generic->credentials); - status = ntlmssp_client_start(state, - lp_netbios_name(), - lp_workgroup(), - lp_client_ntlmv2_auth(), - &state->ntlmssp_state); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - ntlmssp_want_feature(state->ntlmssp_state, - NTLMSSP_FEATURE_SESSION_KEY); - if (cli->use_ccache) { - ntlmssp_want_feature(state->ntlmssp_state, - NTLMSSP_FEATURE_CCACHE); - } - status = ntlmssp_set_username(state->ntlmssp_state, user); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - status = ntlmssp_set_domain(state->ntlmssp_state, domain); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - if (cli->pw_nt_hash) { - status = ntlmssp_set_password_hash(state->ntlmssp_state, pass); - } else { - status = ntlmssp_set_password(state->ntlmssp_state, pass); - } - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - status = ntlmssp_update(state->ntlmssp_state, data_blob_null, - &blob_out); - if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - goto fail; + status = auth_generic_client_start(state->auth_generic, + GENSEC_OID_SPNEGO); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); } - state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL); - data_blob_free(&blob_out); - if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { state->cli->smb2.session = smbXcli_session_create(cli, cli->conn); @@ -1502,150 +1466,226 @@ static struct tevent_req *cli_session_setup_ntlmssp_send( } } - subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out); - if (tevent_req_nomem(subreq, req)) { + cli_session_setup_gensec_local_next(req); + if (!tevent_req_is_in_progress(req)) { return tevent_req_post(req, ev); } - tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req); + return req; -fail: - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); } -static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq) +static void cli_session_setup_gensec_local_next(struct tevent_req *req) { - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct cli_session_setup_ntlmssp_state *state = tevent_req_data( - req, struct cli_session_setup_ntlmssp_state); - DATA_BLOB blob_in, msg_in, blob_out; - uint8_t *inbuf = NULL; - struct iovec *recv_iov = NULL; - bool parse_ret; + struct cli_session_setup_gensec_state *state = + tevent_req_data(req, + struct cli_session_setup_gensec_state); + struct tevent_req *subreq = NULL; + + if (state->local_ready) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + subreq = gensec_update_send(state, state->ev, + state->auth_generic->gensec_security, + state->blob_in); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, cli_session_setup_gensec_local_done, req); +} + +static void cli_session_setup_gensec_local_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct cli_session_setup_gensec_state *state = + tevent_req_data(req, + struct cli_session_setup_gensec_state); NTSTATUS status; - status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in, - &inbuf, &recv_iov); + status = gensec_update_recv(subreq, state, &state->blob_out); TALLOC_FREE(subreq); - data_blob_free(&state->blob_out); + state->blob_in = data_blob_null; + if (!NT_STATUS_IS_OK(status) && + !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) + { + tevent_req_nterror(req, status); + return; + } if (NT_STATUS_IS_OK(status)) { - if (state->cli->server_domain[0] == '\0') { - TALLOC_FREE(state->cli->server_domain); - state->cli->server_domain = talloc_strdup(state->cli, - state->ntlmssp_state->server.netbios_domain); - if (state->cli->server_domain == NULL) { - tevent_req_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - } + state->local_ready = true; + } - if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { - struct smbXcli_session *session = state->cli->smb2.session; + if (state->local_ready && state->remote_ready) { + cli_session_setup_gensec_ready(req); + return; + } - if (ntlmssp_is_anonymous(state->ntlmssp_state)) { - /* - * Windows server does not set the - * SMB2_SESSION_FLAG_IS_GUEST nor - * SMB2_SESSION_FLAG_IS_NULL flag. - * - * This fix makes sure we do not try - * to verify a signature on the final - * session setup response. - */ - TALLOC_FREE(state->ntlmssp_state); - tevent_req_done(req); - return; - } + cli_session_setup_gensec_remote_next(req); +} - status = smb2cli_session_set_session_key(session, - state->ntlmssp_state->session_key, - recv_iov); - if (tevent_req_nterror(req, status)) { - return; - } - } else { - struct smbXcli_session *session = state->cli->smb1.session; +static void cli_session_setup_gensec_remote_next(struct tevent_req *req) +{ + struct cli_session_setup_gensec_state *state = + tevent_req_data(req, + struct cli_session_setup_gensec_state); + struct tevent_req *subreq = NULL; - status = smb1cli_session_set_session_key(session, - state->ntlmssp_state->session_key); - if (tevent_req_nterror(req, status)) { - return; - } + if (state->remote_ready) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } - if (smb1cli_conn_activate_signing( - state->cli->conn, state->ntlmssp_state->session_key, - data_blob_null) - && !smb1cli_conn_check_signing(state->cli->conn, inbuf, 1)) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - } - TALLOC_FREE(state->ntlmssp_state); - tevent_req_done(req); + subreq = cli_sesssetup_blob_send(state, state->ev, + state->cli, state->blob_out); + if (tevent_req_nomem(subreq, req)) { return; } - if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + tevent_req_set_callback(subreq, + cli_session_setup_gensec_remote_done, + req); +} + +static void cli_session_setup_gensec_remote_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct cli_session_setup_gensec_state *state = + tevent_req_data(req, + struct cli_session_setup_gensec_state); + NTSTATUS status; + + TALLOC_FREE(state->inbuf); + TALLOC_FREE(state->recv_iov); + + status = cli_sesssetup_blob_recv(subreq, state, &state->blob_in, + &state->inbuf, &state->recv_iov); + TALLOC_FREE(subreq); + data_blob_free(&state->blob_out); + if (!NT_STATUS_IS_OK(status) && + !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) + { tevent_req_nterror(req, status); return; } - if (blob_in.length == 0) { - tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL); - return; + if (NT_STATUS_IS_OK(status)) { + state->remote_ready = true; } - if ((state->turn == 1) - && NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - DATA_BLOB tmp_blob = data_blob_null; - /* the server might give us back two challenges */ - parse_ret = spnego_parse_challenge(state, blob_in, &msg_in, - &tmp_blob); - data_blob_free(&tmp_blob); - } else { - parse_ret = spnego_parse_auth_response(state, blob_in, status, - OID_NTLMSSP, &msg_in); - } - state->turn += 1; - - if (!parse_ret) { - DEBUG(3,("Failed to parse auth response\n")); - if (NT_STATUS_IS_OK(status) - || NT_STATUS_EQUAL(status, - NT_STATUS_MORE_PROCESSING_REQUIRED)) { - tevent_req_nterror( - req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } + if (state->local_ready && state->remote_ready) { + cli_session_setup_gensec_ready(req); + return; } - status = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out); + cli_session_setup_gensec_local_next(req); +} - if (!NT_STATUS_IS_OK(status) - && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - TALLOC_FREE(state->ntlmssp_state); - tevent_req_nterror(req, status); +static void cli_session_setup_gensec_ready(struct tevent_req *req) +{ + struct cli_session_setup_gensec_state *state = + tevent_req_data(req, + struct cli_session_setup_gensec_state); + const char *server_domain = NULL; + NTSTATUS status; + + if (state->blob_in.length != 0) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } - state->blob_out = spnego_gen_auth(state, blob_out); - if (tevent_req_nomem(state->blob_out.data, req)) { + if (state->blob_out.length != 0) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } - subreq = cli_sesssetup_blob_send(state, state->ev, state->cli, - state->blob_out); - if (tevent_req_nomem(subreq, req)) { + /* + * gensec_ntlmssp_server_domain() returns NULL + * if NTLMSSP is not used. + * + * We can remove this later + * and leave the server domain empty for SMB2 and above + * in future releases. + */ + server_domain = gensec_ntlmssp_server_domain( + state->auth_generic->gensec_security); + + if (state->cli->server_domain[0] == '\0' && server_domain != NULL) { + TALLOC_FREE(state->cli->server_domain); + state->cli->server_domain = talloc_strdup(state->cli, + server_domain); + if (state->cli->server_domain == NULL) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + } + + status = gensec_session_key(state->auth_generic->gensec_security, + state, &state->session_key); + if (tevent_req_nterror(req, status)) { return; } - tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req); + + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + struct smbXcli_session *session = state->cli->smb2.session; + + if (state->is_anonymous) { + /* + * Windows server does not set the + * SMB2_SESSION_FLAG_IS_GUEST nor + * SMB2_SESSION_FLAG_IS_NULL flag. + * + * This fix makes sure we do not try + * to verify a signature on the final + * session setup response. + */ + tevent_req_done(req); + return; + } + + status = smb2cli_session_set_session_key(session, + state->session_key, + state->recv_iov); + if (tevent_req_nterror(req, status)) { + return; + } + } else { + struct smbXcli_session *session = state->cli->smb1.session; + bool active; + + status = smb1cli_session_set_session_key(session, + state->session_key); + if (tevent_req_nterror(req, status)) { + return; + } + + active = smb1cli_conn_activate_signing(state->cli->conn, + state->session_key, + data_blob_null); + if (active) { + bool ok; + + ok = smb1cli_conn_check_signing(state->cli->conn, + state->inbuf, 1); + if (!ok) { + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return; + } + } + } + + tevent_req_done(req); } -static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req) +static NTSTATUS cli_session_setup_gensec_recv(struct tevent_req *req) { - struct cli_session_setup_ntlmssp_state *state = tevent_req_data( - req, struct cli_session_setup_ntlmssp_state); + struct cli_session_setup_gensec_state *state = + tevent_req_data(req, + struct cli_session_setup_gensec_state); NTSTATUS status; if (tevent_req_is_nterror(req, &status)) { @@ -1725,6 +1765,7 @@ static char *cli_session_setup_get_account(TALLOC_CTX *mem_ctx, struct cli_session_setup_spnego_state { struct tevent_context *ev; struct cli_state *cli; + const char *target_hostname; const char *user; const char *account; const char *pass; @@ -1741,14 +1782,14 @@ static void cli_session_setup_spnego_done_ntlmssp(struct tevent_req *subreq); static struct tevent_req *cli_session_setup_spnego_send( TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, - const char *user, const char *pass, const char *user_domain, - const char *dest_realm) + const char *user, const char *pass, const char *user_domain) { struct tevent_req *req, *subreq; struct cli_session_setup_spnego_state *state; char *principal = NULL; char *OIDs[ASN1_MAX_OIDS]; int i; + const char *dest_realm = cli_state_remote_realm(cli); const DATA_BLOB *server_blob; NTSTATUS status; @@ -1769,6 +1810,7 @@ static struct tevent_req *cli_session_setup_spnego_send( return tevent_req_post(req, ev); } + state->target_hostname = smbXcli_conn_remote_name(cli->conn); server_blob = smbXcli_conn_server_gss_blob(cli->conn); DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", @@ -1823,9 +1865,13 @@ static struct tevent_req *cli_session_setup_spnego_send( * and do not store results */ if (user && *user && cli->got_kerberos_mechanism && cli->use_kerberos) { - const char *remote_name = smbXcli_conn_remote_name(cli->conn); char *tmp; + tmp = cli_session_setup_get_principal( + talloc_tos(), principal, state->target_hostname, dest_realm); + TALLOC_FREE(principal); + principal = tmp; + if (pass && *pass) { int ret; @@ -1833,8 +1879,8 @@ static struct tevent_req *cli_session_setup_spnego_send( ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL); if (ret){ + DEBUG(0, ("Kinit for %s to access %s failed: %s\n", user, principal, error_message(ret))); TALLOC_FREE(principal); - DEBUG(0, ("Kinit failed: %s\n", error_message(ret))); if (cli->fallback_after_kerberos) goto ntlmssp; state->result = ADS_ERROR_KRB5(ret); @@ -1843,14 +1889,12 @@ static struct tevent_req *cli_session_setup_spnego_send( } } - tmp = cli_session_setup_get_principal( - talloc_tos(), principal, remote_name, dest_realm); - TALLOC_FREE(principal); - principal = tmp; - if (principal) { - subreq = cli_session_setup_kerberos_send( - state, ev, cli, principal); + subreq = cli_session_setup_gensec_send( + state, ev, cli, + state->account, pass, user_domain, + CRED_MUST_USE_KERBEROS, + "cifs", state->target_hostname, principal); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } @@ -1863,8 +1907,11 @@ static struct tevent_req *cli_session_setup_spnego_send( #endif ntlmssp: - subreq = cli_session_setup_ntlmssp_send( - state, ev, cli, state->account, pass, user_domain); + subreq = cli_session_setup_gensec_send( + state, state->ev, state->cli, + state->account, state->pass, state->user_domain, + CRED_DONT_USE_KERBEROS, + "cifs", state->target_hostname, NULL); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } @@ -1880,9 +1927,11 @@ static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq) subreq, struct tevent_req); struct cli_session_setup_spnego_state *state = tevent_req_data( req, struct cli_session_setup_spnego_state); + NTSTATUS status; - state->result = cli_session_setup_kerberos_recv(subreq); + status = cli_session_setup_gensec_recv(subreq); TALLOC_FREE(subreq); + state->result = ADS_ERROR_NT(status); if (ADS_ERR_OK(state->result) || !state->cli->fallback_after_kerberos) { @@ -1890,9 +1939,11 @@ static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq) return; } - subreq = cli_session_setup_ntlmssp_send( - state, state->ev, state->cli, state->account, state->pass, - state->user_domain); + subreq = cli_session_setup_gensec_send( + state, state->ev, state->cli, + state->account, state->pass, state->user_domain, + CRED_DONT_USE_KERBEROS, + "cifs", state->target_hostname, NULL); if (tevent_req_nomem(subreq, req)) { return; } @@ -1909,7 +1960,7 @@ static void cli_session_setup_spnego_done_ntlmssp(struct tevent_req *subreq) req, struct cli_session_setup_spnego_state); NTSTATUS status; - status = cli_session_setup_ntlmssp_recv(subreq); + status = cli_session_setup_gensec_recv(subreq); TALLOC_FREE(subreq); state->result = ADS_ERROR_NT(status); tevent_req_done(req); @@ -2023,10 +2074,8 @@ struct tevent_req *cli_session_setup_send(TALLOC_CTX *mem_ctx, } if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { - const char *remote_realm = cli_state_remote_realm(cli); - subreq = cli_session_setup_spnego_send( - state, ev, cli, user, pass, workgroup, remote_realm); + state, ev, cli, user, pass, workgroup); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } @@ -2086,10 +2135,8 @@ struct tevent_req *cli_session_setup_send(TALLOC_CTX *mem_ctx, /* if the server supports extended security then use SPNEGO */ if (smb1cli_conn_capabilities(cli->conn) & CAP_EXTENDED_SECURITY) { - const char *remote_realm = cli_state_remote_realm(cli); - subreq = cli_session_setup_spnego_send( - state, ev, cli, user, pass, workgroup, remote_realm); + state, ev, cli, user, pass, workgroup); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } @@ -2098,6 +2145,17 @@ struct tevent_req *cli_session_setup_send(TALLOC_CTX *mem_ctx, return req; } else { /* otherwise do a NT1 style session setup */ + if (lp_client_ntlmv2_auth() && lp_client_use_spnego()) { + /* + * Don't send an NTLMv2 response without NTLMSSP + * if we want to use spnego support + */ + DEBUG(1, ("Server does not support EXTENDED_SECURITY " + " but 'client use spnego = yes" + " and 'client ntlmv2 auth = yes'\n")); + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return tevent_req_post(req, ev); + } subreq = cli_session_setup_nt1_send( state, ev, cli, user, pass, passlen, ntpass, ntpasslen, @@ -2410,7 +2468,7 @@ struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx, * Non-encrypted passwords - convert to DOS codepage * before using. */ - tmp_pass = talloc_array(talloc_tos(), uint8, 0); + tmp_pass = talloc_array(talloc_tos(), uint8_t, 0); if (tevent_req_nomem(tmp_pass, req)) { return tevent_req_post(req, ev); } @@ -2637,7 +2695,7 @@ static struct tevent_req *cli_raw_tcon_send( TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, const char *service, const char *pass, const char *dev); static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req, - uint16 *max_xmit, uint16 *tid); + uint16_t *max_xmit, uint16_t *tid); static void cli_tree_connect_smb2_done(struct tevent_req *subreq); static void cli_tree_connect_andx_done(struct tevent_req *subreq); @@ -3120,6 +3178,8 @@ fail: struct cli_start_connection_state { struct tevent_context *ev; struct cli_state *cli; + int min_protocol; + int max_protocol; }; static void cli_start_connection_connected(struct tevent_req *subreq); @@ -3149,6 +3209,14 @@ static struct tevent_req *cli_start_connection_send( } state->ev = ev; + if (signing_state == SMB_SIGNING_IPC_DEFAULT) { + state->min_protocol = lp_client_ipc_min_protocol(); + state->max_protocol = lp_client_ipc_max_protocol(); + } else { + state->min_protocol = lp_client_min_protocol(); + state->max_protocol = lp_client_max_protocol(); + } + subreq = cli_connect_nb_send(state, ev, dest_host, dest_ss, port, 0x20, my_name, signing_state, flags); if (tevent_req_nomem(subreq, req)) { @@ -3174,8 +3242,8 @@ static void cli_start_connection_connected(struct tevent_req *subreq) subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn, state->cli->timeout, - lp_client_min_protocol(), - lp_client_max_protocol()); + state->min_protocol, + state->max_protocol); if (tevent_req_nomem(subreq, req)) { return; } @@ -3543,7 +3611,7 @@ static void cli_raw_tcon_done(struct tevent_req *subreq) } static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req, - uint16 *max_xmit, uint16 *tid) + uint16_t *max_xmit, uint16_t *tid) { struct cli_raw_tcon_state *state = tevent_req_data( req, struct cli_raw_tcon_state); @@ -3559,7 +3627,7 @@ static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req, NTSTATUS cli_raw_tcon(struct cli_state *cli, const char *service, const char *pass, const char *dev, - uint16 *max_xmit, uint16 *tid) + uint16_t *max_xmit, uint16_t *tid) { struct tevent_context *ev; struct tevent_req *req; diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c index be237540316..d8fa1c6b935 100644 --- a/source3/libsmb/clidgram.c +++ b/source3/libsmb/clidgram.c @@ -33,7 +33,7 @@ */ static bool cli_prep_mailslot(bool unique, const char *mailslot, - uint16 priority, + uint16_t priority, char *buf, int len, const char *srcname, int src_type, const char *dstname, int dest_type, diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 71ec1dcc99a..79e1392c5db 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -231,6 +231,15 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, use_level_II_oplocks = true; } + if (signing_state == SMB_SIGNING_IPC_DEFAULT) { + /* + * Ensure for IPC/RPC the default is to require + * signing unless explicitly turned off by the + * administrator. + */ + signing_state = lp_client_ipc_signing(); + } + if (signing_state == SMB_SIGNING_DEFAULT) { signing_state = lp_client_signing(); } @@ -379,7 +388,7 @@ uint16_t cli_state_get_vc_num(struct cli_state *cli) Set the PID to use for smb messages. Return the old pid. ****************************************************************************/ -uint16 cli_setpid(struct cli_state *cli, uint16 pid) +uint16_t cli_setpid(struct cli_state *cli, uint16 pid) { uint16_t ret = cli->smb1.pid; cli->smb1.pid = pid; diff --git a/source3/libsmb/clierror.c b/source3/libsmb/clierror.c index a53c9c4e1e8..f20980251f4 100644 --- a/source3/libsmb/clierror.c +++ b/source3/libsmb/clierror.c @@ -84,7 +84,7 @@ NTSTATUS cli_nt_error(struct cli_state *cli) code. ****************************************************************************/ -void cli_dos_error(struct cli_state *cli, uint8 *eclass, uint32 *ecode) +void cli_dos_error(struct cli_state *cli, uint8_t *eclass, uint32_t *ecode) { if (!cli_state_is_connected(cli)) { *eclass = ERRDOS; @@ -115,8 +115,8 @@ int cli_errno(struct cli_state *cli) } if (cli_is_dos_error(cli)) { - uint8 eclass; - uint32 ecode; + uint8_t eclass; + uint32_t ecode; cli_dos_error(cli, &eclass, &ecode); status = dos_to_ntstatus(eclass, ecode); diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c index 376c4f5d5b1..3fbfbbe67a6 100644 --- a/source3/libsmb/clifsinfo.c +++ b/source3/libsmb/clifsinfo.c @@ -120,9 +120,9 @@ NTSTATUS cli_unix_extensions_version_recv(struct tevent_req *req, return NT_STATUS_OK; } -NTSTATUS cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor, - uint16 *pminor, uint32 *pcaplow, - uint32 *pcaphigh) +NTSTATUS cli_unix_extensions_version(struct cli_state *cli, uint16_t *pmajor, + uint16_t *pminor, uint32_t *pcaplow, + uint32_t *pcaphigh) { TALLOC_CTX *frame = talloc_stackframe(); struct tevent_context *ev; @@ -235,8 +235,8 @@ NTSTATUS cli_set_unix_extensions_capabilities_recv(struct tevent_req *req) } NTSTATUS cli_set_unix_extensions_capabilities(struct cli_state *cli, - uint16 major, uint16 minor, - uint32 caplow, uint32 caphigh) + uint16_t major, uint16 minor, + uint32_t caplow, uint32 caphigh) { struct tevent_context *ev; struct tevent_req *req; @@ -432,7 +432,7 @@ NTSTATUS cli_get_fs_full_size_info(struct cli_state *cli, uint64_t *sectors_per_allocation_unit, uint64_t *bytes_per_sector) { - uint16 setup[1]; + uint16_t setup[1]; uint8_t param[2]; uint8_t *rdata = NULL; uint32_t rdata_count; @@ -476,8 +476,8 @@ fail: } NTSTATUS cli_get_posix_fs_info(struct cli_state *cli, - uint32 *optimal_transfer_size, - uint32 *block_size, + uint32_t *optimal_transfer_size, + uint32_t *block_size, uint64_t *total_blocks, uint64_t *blocks_available, uint64_t *user_blocks_available, @@ -485,7 +485,7 @@ NTSTATUS cli_get_posix_fs_info(struct cli_state *cli, uint64_t *free_file_nodes, uint64_t *fs_identifier) { - uint16 setup[1]; + uint16_t setup[1]; uint8_t param[2]; uint8_t *rdata = NULL; uint32_t rdata_count; @@ -748,8 +748,8 @@ NTSTATUS cli_force_encryption(struct cli_state *c, const char *password, const char *domain) { - uint16 major, minor; - uint32 caplow, caphigh; + uint16_t major, minor; + uint32_t caplow, caphigh; NTSTATUS status; if (!SERVER_HAS_UNIX_CIFS(c)) { diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c index 3080fb883dd..2e5023916e7 100644 --- a/source3/libsmb/clilist.c +++ b/source3/libsmb/clilist.c @@ -56,7 +56,7 @@ static size_t interpret_long_filename(TALLOC_CTX *ctx, const char *p, const char *pdata_end, struct file_info *finfo, - uint32 *p_resume_key, + uint32_t *p_resume_key, DATA_BLOB *p_last_name_raw) { int len; @@ -479,7 +479,7 @@ static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, } NTSTATUS cli_list_old(struct cli_state *cli, const char *mask, - uint16 attribute, + uint16_t attribute, NTSTATUS (*fn)(const char *, struct file_info *, const char *, void *), void *state) { @@ -929,7 +929,7 @@ NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } -NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16 attribute, +NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16_t attribute, NTSTATUS (*fn)(const char *, struct file_info *, const char *, void *), void *state) { diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 64e3767c129..c176fd6c45a 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -165,7 +165,7 @@ bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation) Call a NetShareEnum - try and browse available connections on a host. ****************************************************************************/ -int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state) +int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32_t, const char *, void *), void *state) { char *rparam = NULL; char *rdata = NULL; @@ -272,8 +272,8 @@ int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, co the comment and a state pointer. ****************************************************************************/ -bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, - void (*fn)(const char *, uint32, const char *, void *), +bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32_t stype, + void (*fn)(const char *, uint32_t, const char *, void *), void *state) { char *rparam = NULL; @@ -284,7 +284,7 @@ bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, char param[1024]; int uLevel = 1; size_t len; - uint32 func = RAP_NetServerEnum2; + uint32_t func = RAP_NetServerEnum2; char *last_entry = NULL; int total_cnt = 0; int return_cnt = 0; @@ -626,7 +626,7 @@ NTSTATUS cli_qpathinfo1_recv(struct tevent_req *req, time_t *access_time, time_t *write_time, off_t *size, - uint16 *mode) + uint16_t *mode) { struct cli_qpathinfo1_state *state = tevent_req_data( req, struct cli_qpathinfo1_state); @@ -668,7 +668,7 @@ NTSTATUS cli_qpathinfo1(struct cli_state *cli, time_t *access_time, time_t *write_time, off_t *size, - uint16 *mode) + uint16_t *mode) { TALLOC_CTX *frame = talloc_stackframe(); struct tevent_context *ev; @@ -709,7 +709,7 @@ NTSTATUS cli_setpathinfo_basic(struct cli_state *cli, const char *fname, time_t access_time, time_t write_time, time_t change_time, - uint16 mode) + uint16_t mode) { unsigned int data_len = 0; char data[40]; @@ -802,7 +802,7 @@ NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req, struct timespec *access_time, struct timespec *write_time, struct timespec *change_time, - off_t *size, uint16 *mode, + off_t *size, uint16_t *mode, SMB_INO_T *ino) { struct cli_qpathinfo2_state *state = tevent_req_data( @@ -842,7 +842,7 @@ NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname, struct timespec *access_time, struct timespec *write_time, struct timespec *change_time, - off_t *size, uint16 *mode, + off_t *size, uint16_t *mode, SMB_INO_T *ino) { TALLOC_CTX *frame = NULL; @@ -1138,7 +1138,7 @@ NTSTATUS cli_qfilename(struct cli_state *cli, uint16_t fnum, ****************************************************************************/ NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum, - uint16 *mode, off_t *size, + uint16_t *mode, off_t *size, struct timespec *create_time, struct timespec *access_time, struct timespec *write_time, @@ -1255,7 +1255,7 @@ static void cli_qpathinfo_basic_done(struct tevent_req *subreq) } NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req, - SMB_STRUCT_STAT *sbuf, uint32 *attributes) + SMB_STRUCT_STAT *sbuf, uint32_t *attributes) { struct cli_qpathinfo_basic_state *state = tevent_req_data( req, struct cli_qpathinfo_basic_state); @@ -1274,7 +1274,7 @@ NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req, } NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name, - SMB_STRUCT_STAT *sbuf, uint32 *attributes) + SMB_STRUCT_STAT *sbuf, uint32_t *attributes) { TALLOC_CTX *frame = NULL; struct tevent_context *ev; @@ -1420,7 +1420,7 @@ NTSTATUS cli_qpathinfo3(struct cli_state *cli, const char *fname, struct timespec *access_time, struct timespec *write_time, struct timespec *change_time, - off_t *size, uint16 *mode, + off_t *size, uint16_t *mode, SMB_INO_T *ino) { NTSTATUS status = NT_STATUS_OK; diff --git a/source3/libsmb/clirap.h b/source3/libsmb/clirap.h index 54f06b4e76c..a0d4d0609af 100644 --- a/source3/libsmb/clirap.h +++ b/source3/libsmb/clirap.h @@ -35,9 +35,9 @@ bool cli_api(struct cli_state *cli, char **rparam, unsigned int *rprcnt, char **rdata, unsigned int *rdrcnt); bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation); -int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state); -bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, - void (*fn)(const char *, uint32, const char *, void *), +int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32_t, const char *, void *), void *state); +bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32_t stype, + void (*fn)(const char *, uint32_t, const char *, void *), void *state); bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password, const char *old_password); @@ -50,20 +50,20 @@ NTSTATUS cli_qpathinfo1_recv(struct tevent_req *req, time_t *access_time, time_t *write_time, off_t *size, - uint16 *mode); + uint16_t *mode); NTSTATUS cli_qpathinfo1(struct cli_state *cli, const char *fname, time_t *change_time, time_t *access_time, time_t *write_time, off_t *size, - uint16 *mode); + uint16_t *mode); NTSTATUS cli_setpathinfo_basic(struct cli_state *cli, const char *fname, time_t create_time, time_t access_time, time_t write_time, time_t change_time, - uint16 mode); + uint16_t mode); struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, @@ -73,21 +73,21 @@ NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req, struct timespec *access_time, struct timespec *write_time, struct timespec *change_time, - off_t *size, uint16 *mode, + off_t *size, uint16_t *mode, SMB_INO_T *ino); NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname, struct timespec *create_time, struct timespec *access_time, struct timespec *write_time, struct timespec *change_time, - off_t *size, uint16 *mode, + off_t *size, uint16_t *mode, SMB_INO_T *ino); NTSTATUS cli_qpathinfo3(struct cli_state *cli, const char *fname, struct timespec *create_time, struct timespec *access_time, struct timespec *write_time, struct timespec *change_time, - off_t *size, uint16 *mode, + off_t *size, uint16_t *mode, SMB_INO_T *ino); struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -108,7 +108,7 @@ bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata, NTSTATUS cli_qfilename(struct cli_state *cli, uint16_t fnum, TALLOC_CTX *mem_ctx, char **name); NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum, - uint16 *mode, off_t *size, + uint16_t *mode, off_t *size, struct timespec *create_time, struct timespec *access_time, struct timespec *write_time, @@ -119,9 +119,9 @@ struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx, struct cli_state *cli, const char *fname); NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req, - SMB_STRUCT_STAT *sbuf, uint32 *attributes); + SMB_STRUCT_STAT *sbuf, uint32_t *attributes); NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name, - SMB_STRUCT_STAT *sbuf, uint32 *attributes); + SMB_STRUCT_STAT *sbuf, uint32_t *attributes); NTSTATUS cli_qpathinfo_standard(struct cli_state *cli, const char *fname, uint64_t *allocated, uint64_t *size, uint32_t *nlinks, @@ -191,31 +191,31 @@ int cli_RNetUserEnum(struct cli_state *cli, void (*fn)(const char *, const char int cli_RNetUserEnum0(struct cli_state *cli, void (*fn)(const char *, void *), void *state); -int cli_NetFileClose(struct cli_state *cli, uint32 file_id ); -int cli_NetFileGetInfo(struct cli_state *cli, uint32 file_id, void (*fn)(const char *, const char *, uint16, uint16, uint32)); +int cli_NetFileClose(struct cli_state *cli, uint32_t file_id ); +int cli_NetFileGetInfo(struct cli_state *cli, uint32_t file_id, void (*fn)(const char *, const char *, uint16_t, uint16_t, uint32_t)); int cli_NetFileEnum(struct cli_state *cli, const char * user, const char * base_path, - void (*fn)(const char *, const char *, uint16, uint16, - uint32)); + void (*fn)(const char *, const char *, uint16_t, uint16_t, + uint32_t)); int cli_NetShareAdd(struct cli_state *cli, struct rap_share_info_2 * sinfo ); int cli_NetShareDelete(struct cli_state *cli, const char * share_name ); bool cli_get_pdc_name(struct cli_state *cli, const char *workgroup, char **pdc_name); bool cli_get_server_domain(struct cli_state *cli); -bool cli_get_server_type(struct cli_state *cli, uint32 *pstype); +bool cli_get_server_type(struct cli_state *cli, uint32_t *pstype); bool cli_get_server_name(TALLOC_CTX *mem_ctx, struct cli_state *cli, char **servername); -bool cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32 stype); +bool cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32_t stype); bool cli_NetWkstaUserLogoff(struct cli_state *cli, const char *user, const char *workstation); int cli_NetPrintQEnum(struct cli_state *cli, - void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16), - void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,unsigned int,unsigned int,const char*)); + void (*qfn)(const char*,uint16_t,uint16_t,uint16_t,const char*,const char*,const char*,const char*,const char*,uint16_t,uint16_t), + void (*jfn)(uint16_t,const char*,const char*,const char*,const char*,uint16_t,uint16_t,const char*,unsigned int,unsigned int,const char*)); int cli_NetPrintQGetInfo(struct cli_state *cli, const char *printer, - void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16), - void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,unsigned int,unsigned int,const char*)); + void (*qfn)(const char*,uint16_t,uint16_t,uint16_t,const char*,const char*,const char*,const char*,const char*,uint16_t,uint16_t), + void (*jfn)(uint16_t,const char*,const char*,const char*,const char*,uint16_t,uint16_t,const char*,unsigned int,unsigned int,const char*)); int cli_RNetServiceEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state); -int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16, uint16, uint16, unsigned int, unsigned int, unsigned int, char *)); +int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16_t, uint16_t, uint16_t, unsigned int, unsigned int, unsigned int, char *)); int cli_NetSessionGetInfo(struct cli_state *cli, const char *workstation, - void (*fn)(const char *, const char *, uint16, uint16, uint16, unsigned int, unsigned int, unsigned int, const char *)); + void (*fn)(const char *, const char *, uint16_t, uint16_t, uint16_t, unsigned int, unsigned int, unsigned int, const char *)); int cli_NetSessionDel(struct cli_state *cli, const char *workstation); int cli_NetConnectionEnum(struct cli_state *cli, const char *qualifier, void (*fn)(uint16_t conid, uint16_t contype, diff --git a/source3/libsmb/clirap2.c b/source3/libsmb/clirap2.c index 457a82ee116..931bc237f9a 100644 --- a/source3/libsmb/clirap2.c +++ b/source3/libsmb/clirap2.c @@ -218,7 +218,7 @@ static size_t rap_getstringp(TALLOC_CTX *ctx, char *p, char **dest, char *r, uin return 4; } -static char *make_header(char *param, uint16 apinum, const char *reqfmt, const char *datafmt) +static char *make_header(char *param, uint16_t apinum, const char *reqfmt, const char *datafmt) { PUTWORD(param,apinum); if (reqfmt) @@ -1097,7 +1097,7 @@ int cli_RNetUserEnum0(struct cli_state *cli, Call a NetFileClose2 - close open file on another session to server. ****************************************************************************/ -int cli_NetFileClose(struct cli_state *cli, uint32 file_id ) +int cli_NetFileClose(struct cli_state *cli, uint32_t file_id ) { char *rparam = NULL; char *rdata = NULL; @@ -1145,7 +1145,7 @@ int cli_NetFileClose(struct cli_state *cli, uint32 file_id ) workstation. ****************************************************************************/ -int cli_NetFileGetInfo(struct cli_state *cli, uint32 file_id, void (*fn)(const char *, const char *, uint16, uint16, uint32)) +int cli_NetFileGetInfo(struct cli_state *cli, uint32_t file_id, void (*fn)(const char *, const char *, uint16_t, uint16_t, uint32_t)) { char *rparam = NULL; char *rdata = NULL; @@ -1245,8 +1245,8 @@ int cli_NetFileGetInfo(struct cli_state *cli, uint32 file_id, void (*fn)(const c int cli_NetFileEnum(struct cli_state *cli, const char * user, const char * base_path, - void (*fn)(const char *, const char *, uint16, uint16, - uint32)) + void (*fn)(const char *, const char *, uint16_t, uint16_t, + uint32_t)) { char *rparam = NULL; char *rdata = NULL; @@ -1636,7 +1636,7 @@ bool cli_get_server_domain(struct cli_state *cli) * * Parameters: * cli - pointer to cli_state structure -* pstype - pointer to uint32 to contain returned server type +* pstype - pointer to uint32_t to contain returned server type * * Returns: * True - success @@ -1646,7 +1646,7 @@ bool cli_get_server_domain(struct cli_state *cli) * ************************************************************************/ -bool cli_get_server_type(struct cli_state *cli, uint32 *pstype) +bool cli_get_server_type(struct cli_state *cli, uint32_t *pstype) { char *rparam = NULL; char *rdata = NULL; @@ -1775,7 +1775,7 @@ bool cli_get_server_name(TALLOC_CTX *mem_ctx, struct cli_state *cli, * ************************************************************************/ -bool cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32 stype) +bool cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32_t stype) { char *rparam = NULL; char *rdata = NULL; @@ -1910,8 +1910,8 @@ bool cli_NetWkstaUserLogoff(struct cli_state *cli, const char *user, const char } int cli_NetPrintQEnum(struct cli_state *cli, - void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16), - void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,unsigned int,unsigned int,const char*)) + void (*qfn)(const char*,uint16_t,uint16_t,uint16_t,const char*,const char*,const char*,const char*,const char*,uint16_t,uint16_t), + void (*jfn)(uint16_t,const char*,const char*,const char*,const char*,uint16_t,uint16_t,const char*,unsigned int,unsigned int,const char*)) { char param[WORDSIZE /* api number */ +sizeof(RAP_NetPrintQEnum_REQ) /* req string */ @@ -2018,7 +2018,7 @@ int cli_NetPrintQEnum(struct cli_state *cli, if (jobcount) { int j; for (j=0;j<jobcount;j++) { - uint16 jid = 0, pos = 0, fsstatus = 0; + uint16_t jid = 0, pos = 0, fsstatus = 0; char ownername[RAP_USERNAME_LEN]; char notifyname[RAP_MACHNAME_LEN]; char datatype[RAP_DATATYPE_LEN]; @@ -2086,8 +2086,8 @@ int cli_NetPrintQEnum(struct cli_state *cli, } int cli_NetPrintQGetInfo(struct cli_state *cli, const char *printer, - void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16), - void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,unsigned int,unsigned int,const char*)) + void (*qfn)(const char*,uint16_t,uint16_t,uint16_t,const char*,const char*,const char*,const char*,const char*,uint16_t,uint16_t), + void (*jfn)(uint16_t,const char*,const char*,const char*,const char*,uint16_t,uint16_t,const char*,unsigned int,unsigned int,const char*)) { char param[WORDSIZE /* api number */ +sizeof(RAP_NetPrintQGetInfo_REQ) /* req string */ @@ -2347,7 +2347,7 @@ int cli_RNetServiceEnum(struct cli_state *cli, void (*fn)(const char *, const ch Call a NetSessionEnum - list workstations with sessions to an SMB server. ****************************************************************************/ -int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16, uint16, uint16, unsigned int, unsigned int, unsigned int, char *)) +int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16_t, uint16_t, uint16_t, unsigned int, unsigned int, unsigned int, char *)) { char param[WORDSIZE /* api number */ +sizeof(RAP_NetSessionEnum_REQ) /* parm string */ @@ -2447,7 +2447,7 @@ int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16, ****************************************************************************/ int cli_NetSessionGetInfo(struct cli_state *cli, const char *workstation, - void (*fn)(const char *, const char *, uint16, uint16, uint16, unsigned int, unsigned int, unsigned int, const char *)) + void (*fn)(const char *, const char *, uint16_t, uint16_t, uint16_t, unsigned int, unsigned int, unsigned int, const char *)) { char param[WORDSIZE /* api number */ +sizeof(RAP_NetSessionGetInfo_REQ) /* req string */ diff --git a/source3/libsmb/clisecdesc.c b/source3/libsmb/clisecdesc.c index 986610fb785..c11e4b322ef 100644 --- a/source3/libsmb/clisecdesc.c +++ b/source3/libsmb/clisecdesc.c @@ -62,7 +62,7 @@ NTSTATUS cli_query_security_descriptor(struct cli_state *cli, goto cleanup; } - status = unmarshall_sec_desc(mem_ctx, (uint8 *)rdata, rdata_count, + status = unmarshall_sec_desc(mem_ctx, (uint8_t *)rdata, rdata_count, &lsd); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("unmarshall_sec_desc failed: %s\n", @@ -100,7 +100,7 @@ NTSTATUS cli_set_security_descriptor(struct cli_state *cli, const struct security_descriptor *sd) { uint8_t param[8]; - uint8 *data; + uint8_t *data; size_t len; NTSTATUS status; diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c index ec8d1ee7806..959eaa433d6 100644 --- a/source3/libsmb/clispnego.c +++ b/source3/libsmb/clispnego.c @@ -26,73 +26,6 @@ #include "../lib/util/asn1.h" /* - generate a negTokenInit packet given a list of supported - OIDs (the mechanisms) a blob, and a principal name string -*/ - -DATA_BLOB spnego_gen_negTokenInit(TALLOC_CTX *ctx, - const char *OIDs[], - DATA_BLOB *psecblob, - const char *principal) -{ - int i; - ASN1_DATA *data; - DATA_BLOB ret = data_blob_null; - - data = asn1_init(talloc_tos()); - if (data == NULL) { - return data_blob_null; - } - - if (!asn1_push_tag(data,ASN1_APPLICATION(0))) goto err; - if (!asn1_write_OID(data,OID_SPNEGO)) goto err; - if (!asn1_push_tag(data,ASN1_CONTEXT(0))) goto err; - if (!asn1_push_tag(data,ASN1_SEQUENCE(0))) goto err; - - if (!asn1_push_tag(data,ASN1_CONTEXT(0))) goto err; - if (!asn1_push_tag(data,ASN1_SEQUENCE(0))) goto err; - for (i=0; OIDs[i]; i++) { - if (!asn1_write_OID(data,OIDs[i])) goto err; - } - if (!asn1_pop_tag(data)) goto err; - if (!asn1_pop_tag(data)) goto err; - - if (psecblob && psecblob->length && psecblob->data) { - if (!asn1_push_tag(data, ASN1_CONTEXT(2))) goto err; - if (!asn1_write_OctetString(data,psecblob->data, - psecblob->length)) goto err; - if (!asn1_pop_tag(data)) goto err; - } - - if (principal) { - if (!asn1_push_tag(data, ASN1_CONTEXT(3))) goto err; - if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err; - if (!asn1_push_tag(data, ASN1_CONTEXT(0))) goto err; - if (!asn1_write_GeneralString(data,principal)) goto err; - if (!asn1_pop_tag(data)) goto err; - if (!asn1_pop_tag(data)) goto err; - if (!asn1_pop_tag(data)) goto err; - } - - if (!asn1_pop_tag(data)) goto err; - if (!asn1_pop_tag(data)) goto err; - - if (!asn1_pop_tag(data)) goto err; - - ret = data_blob_talloc(ctx, data->data, data->length); - - err: - - if (data->has_error) { - DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data->ofs)); - } - - asn1_free(data); - - return ret; -} - -/* parse a negTokenInit packet giving a GUID, a list of supported OIDs (the mechanisms) and a principal name string */ @@ -143,7 +76,7 @@ bool spnego_parse_negTokenInit(TALLOC_CTX *ctx, if (!asn1_read_OID(data,ctx, &OIDs[i])) { goto err; } - if (data->has_error) { + if (asn1_has_error(data)) { goto err; } } @@ -209,11 +142,11 @@ bool spnego_parse_negTokenInit(TALLOC_CTX *ctx, if (!asn1_end_tag(data)) goto err; - ret = !data->has_error; + ret = !asn1_has_error(data); err: - if (data->has_error) { + if (asn1_has_error(data)) { int j; if (principal) { TALLOC_FREE(*principal); @@ -250,219 +183,23 @@ DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const ui if (!asn1_write(data, ticket.data, ticket.length)) goto err; if (!asn1_pop_tag(data)) goto err; - ret = data_blob_talloc(ctx, data->data, data->length); - - err: - - if (data->has_error) { - DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data->ofs)); + if (!asn1_extract_blob(data, ctx, &ret)) { + goto err; } asn1_free(data); - - return ret; -} - -/* - generate a SPNEGO krb5 negTokenInit packet, ready for a EXTENDED_SECURITY - kerberos session setup -*/ -int spnego_gen_krb5_negTokenInit(TALLOC_CTX *ctx, - const char *principal, int time_offset, - DATA_BLOB *targ, - DATA_BLOB *session_key_krb5, uint32 extra_ap_opts, - const char *ccname, time_t *expire_time) -{ - int retval; - DATA_BLOB tkt, tkt_wrapped; - const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL}; - - /* get a kerberos ticket for the service and extract the session key */ - retval = cli_krb5_get_ticket(ctx, principal, time_offset, - &tkt, session_key_krb5, - extra_ap_opts, ccname, - expire_time, NULL); - if (retval) { - return retval; - } - - /* wrap that up in a nice GSS-API wrapping */ - tkt_wrapped = spnego_gen_krb5_wrap(ctx, tkt, TOK_ID_KRB_AP_REQ); - - /* and wrap that in a shiny SPNEGO wrapper */ - *targ = spnego_gen_negTokenInit(ctx, krb_mechs, &tkt_wrapped, NULL); - - data_blob_free(&tkt_wrapped); - data_blob_free(&tkt); - - return retval; -} - - -/* - parse a spnego NTLMSSP challenge packet giving two security blobs -*/ -bool spnego_parse_challenge(TALLOC_CTX *ctx, const DATA_BLOB blob, - DATA_BLOB *chal1, DATA_BLOB *chal2) -{ - bool ret = false; - ASN1_DATA *data; - - ZERO_STRUCTP(chal1); - ZERO_STRUCTP(chal2); - - data = asn1_init(talloc_tos()); - if (data == NULL) { - return false; - } - - if (!asn1_load(data, blob)) goto err; - if (!asn1_start_tag(data,ASN1_CONTEXT(1))) goto err; - if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err; - - if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err; - if (!asn1_check_enumerated(data,1)) goto err; - if (!asn1_end_tag(data)) goto err; - - if (!asn1_start_tag(data,ASN1_CONTEXT(1))) goto err; - if (!asn1_check_OID(data, OID_NTLMSSP)) goto err; - if (!asn1_end_tag(data)) goto err; - - if (!asn1_start_tag(data,ASN1_CONTEXT(2))) goto err; - if (!asn1_read_OctetString(data, ctx, chal1)) goto err; - if (!asn1_end_tag(data)) goto err; - - /* the second challenge is optional (XP doesn't send it) */ - if (asn1_tag_remaining(data)) { - if (!asn1_start_tag(data,ASN1_CONTEXT(3))) goto err; - if (!asn1_read_OctetString(data, ctx, chal2)) goto err; - if (!asn1_end_tag(data)) goto err; - } - - if (!asn1_end_tag(data)) goto err; - if (!asn1_end_tag(data)) goto err; - - ret = !data->has_error; + data = NULL; err: - if (data->has_error) { - data_blob_free(chal1); - data_blob_free(chal2); - } - - asn1_free(data); - return ret; -} - - -/* - generate a SPNEGO auth packet. This will contain the encrypted passwords -*/ -DATA_BLOB spnego_gen_auth(TALLOC_CTX *ctx, DATA_BLOB blob) -{ - ASN1_DATA *data; - DATA_BLOB ret = data_blob_null; - - data = asn1_init(talloc_tos()); - if (data == NULL) { - return data_blob_null; - } - - if (!asn1_push_tag(data, ASN1_CONTEXT(1))) goto err; - if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err; - if (!asn1_push_tag(data, ASN1_CONTEXT(2))) goto err; - if (!asn1_write_OctetString(data,blob.data,blob.length)) goto err; - if (!asn1_pop_tag(data)) goto err; - if (!asn1_pop_tag(data)) goto err; - if (!asn1_pop_tag(data)) goto err; - - ret = data_blob_talloc(ctx, data->data, data->length); - - err: - - asn1_free(data); - - return ret; -} - -/* - parse a SPNEGO auth packet. This contains the encrypted passwords -*/ -bool spnego_parse_auth_response(TALLOC_CTX *ctx, - DATA_BLOB blob, NTSTATUS nt_status, - const char *mechOID, - DATA_BLOB *auth) -{ - ASN1_DATA *data; - uint8 negResult; - bool ret = false; - - if (NT_STATUS_IS_OK(nt_status)) { - negResult = SPNEGO_ACCEPT_COMPLETED; - } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - negResult = SPNEGO_ACCEPT_INCOMPLETE; - } else { - negResult = SPNEGO_REJECT; - } - - data = asn1_init(talloc_tos()); - if (data == NULL) { - return false; - } - - *auth = data_blob_null; - - if (!asn1_load(data, blob)) goto err; - if (!asn1_start_tag(data, ASN1_CONTEXT(1))) goto err; - if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto err; - if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto err; - if (!asn1_check_enumerated(data, negResult)) goto err; - if (!asn1_end_tag(data)) goto err; - - if (asn1_tag_remaining(data)) { - if (!asn1_start_tag(data,ASN1_CONTEXT(1))) goto err; - if (!asn1_check_OID(data, mechOID)) goto err; - if (!asn1_end_tag(data)) goto err; - - if (asn1_tag_remaining(data)) { - if (!asn1_start_tag(data,ASN1_CONTEXT(2))) goto err; - if (!asn1_read_OctetString(data, ctx, auth)) goto err; - if (!asn1_end_tag(data)) goto err; + if (data != NULL) { + if (asn1_has_error(data)) { + DEBUG(1, ("Failed to build krb5 wrapper at offset %d\n", + (int)asn1_current_ofs(data))); } - } else if (negResult == SPNEGO_ACCEPT_INCOMPLETE) { - data->has_error = 1; - goto err; - } - - /* Binding against Win2K DC returns a duplicate of the responseToken in - * the optional mechListMIC field. This is a bug in Win2K. We ignore - * this field if it exists. Win2K8 may return a proper mechListMIC at - * which point we need to implement the integrity checking. */ - if (asn1_tag_remaining(data)) { - DATA_BLOB mechList = data_blob_null; - if (!asn1_start_tag(data, ASN1_CONTEXT(3))) goto err; - if (!asn1_read_OctetString(data, ctx, &mechList)) goto err; - data_blob_free(&mechList); - if (!asn1_end_tag(data)) goto err; - DEBUG(5,("spnego_parse_auth_response received mechListMIC, " - "ignoring.\n")); - } - - if (!asn1_end_tag(data)) goto err; - if (!asn1_end_tag(data)) goto err; - - ret = !data->has_error; - err: - - if (data->has_error) { - DEBUG(3,("spnego_parse_auth_response failed at %d\n", (int)data->ofs)); asn1_free(data); - data_blob_free(auth); - return false; } - asn1_free(data); return ret; } diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c index 3a07f118b0c..d131c30c772 100644 --- a/source3/libsmb/libsmb_dir.c +++ b/source3/libsmb/libsmb_dir.c @@ -60,7 +60,7 @@ static int add_dirent(SMBCFILE *dir, const char *name, const char *comment, - uint32 type) + uint32_t type) { struct smbc_dirent *dirent; int size; @@ -138,7 +138,7 @@ add_dirent(SMBCFILE *dir, static void list_unique_wg_fn(const char *name, - uint32 type, + uint32_t type, const char *comment, void *state) { @@ -183,7 +183,7 @@ list_unique_wg_fn(const char *name, static void list_fn(const char *name, - uint32 type, + uint32_t type, const char *comment, void *state) { @@ -257,15 +257,15 @@ dir_list_fn(const char *mnt, static int net_share_enum_rpc(struct cli_state *cli, void (*fn)(const char *name, - uint32 type, + uint32_t type, const char *comment, void *state), void *state) { int i; WERROR result; - uint32 preferred_len = 0xffffffff; - uint32 type; + uint32_t preferred_len = 0xffffffff; + uint32_t type; struct srvsvc_NetShareInfoCtr info_ctr; struct srvsvc_NetShareCtr1 ctr1; fstring name = ""; @@ -377,7 +377,7 @@ SMBC_opendir_ctx(SMBCCTX *context, char *options = NULL; char *workgroup = NULL; char *path = NULL; - uint16 mode; + uint16_t mode; uint16_t port = 0; char *p = NULL; SMBCSRV *srv = NULL; @@ -1562,7 +1562,7 @@ SMBC_chmod_ctx(SMBCCTX *context, char *targetpath = NULL; struct cli_state *targetcli = NULL; char *path = NULL; - uint16 mode; + uint16_t mode; uint16_t port = 0; TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; @@ -1832,7 +1832,7 @@ SMBC_unlink_ctx(SMBCCTX *context, int saverr = errno; off_t size = 0; - uint16 mode = 0; + uint16_t mode = 0; struct timespec write_time_ts; struct timespec access_time_ts; struct timespec change_time_ts; diff --git a/source3/libsmb/libsmb_file.c b/source3/libsmb/libsmb_file.c index c8beafce65e..916364920f3 100644 --- a/source3/libsmb/libsmb_file.c +++ b/source3/libsmb/libsmb_file.c @@ -401,7 +401,7 @@ bool SMBC_getatr(SMBCCTX * context, SMBCSRV *srv, const char *path, - uint16 *mode, + uint16_t *mode, off_t *size, struct timespec *create_time_ts, struct timespec *access_time_ts, @@ -531,7 +531,7 @@ SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, time_t access_time, time_t write_time, time_t change_time, - uint16 mode) + uint16_t mode) { uint16_t fd; int ret; @@ -586,7 +586,7 @@ SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, * cli_setatr() for that, and with only this parameter, it * seems to work on win98. */ - if (ret && mode != (uint16) -1) { + if (ret && mode != (uint16_t) -1) { ret = NT_STATUS_IS_OK(cli_setatr(srv->cli, path, mode, 0)); } diff --git a/source3/libsmb/libsmb_misc.c b/source3/libsmb/libsmb_misc.c index 98739c69ef4..1d874c74cd8 100644 --- a/source3/libsmb/libsmb_misc.c +++ b/source3/libsmb/libsmb_misc.c @@ -53,8 +53,8 @@ SMBC_errno(SMBCCTX *context, int ret = cli_errno(c); if (cli_is_dos_error(c)) { - uint8 eclass; - uint32 ecode; + uint8_t eclass; + uint32_t ecode; cli_dos_error(c, &eclass, &ecode); diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c index 6e8e3c37d32..39a0b470769 100644 --- a/source3/libsmb/libsmb_server.c +++ b/source3/libsmb/libsmb_server.c @@ -267,7 +267,7 @@ SMBC_server_internal(TALLOC_CTX *ctx, struct cli_state *c = NULL; const char *server_n = server; int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0); - uint32 fs_attrs = 0; + uint32_t fs_attrs = 0; const char *username_used; NTSTATUS status; char *newserver, *newshare; diff --git a/source3/libsmb/libsmb_stat.c b/source3/libsmb/libsmb_stat.c index 3c895cefd3e..4191ad6d215 100644 --- a/source3/libsmb/libsmb_stat.c +++ b/source3/libsmb/libsmb_stat.c @@ -119,7 +119,7 @@ SMBC_stat_ctx(SMBCCTX *context, struct timespec access_time_ts; struct timespec change_time_ts; off_t size = 0; - uint16 mode = 0; + uint16_t mode = 0; uint16_t port = 0; SMB_INO_T ino = 0; TALLOC_CTX *frame = talloc_stackframe(); @@ -207,7 +207,7 @@ SMBC_fstat_ctx(SMBCCTX *context, struct timespec access_time_ts; struct timespec write_time_ts; off_t size; - uint16 mode; + uint16_t mode; char *server = NULL; char *share = NULL; char *user = NULL; @@ -368,7 +368,7 @@ SMBC_fstatvfs_ctx(SMBCCTX *context, struct statvfs *st) { unsigned long flags = 0; - uint32 fs_attrs = 0; + uint32_t fs_attrs = 0; struct cli_state *cli = file->srv->cli; struct smbXcli_tcon *tcon; TALLOC_CTX *frame = talloc_stackframe(); @@ -424,8 +424,8 @@ SMBC_fstatvfs_ctx(SMBCCTX *context, flags |= SMBC_VFS_FEATURE_NO_UNIXCIFS; } else { - uint32 optimal_transfer_size; - uint32 block_size; + uint32_t optimal_transfer_size; + uint32_t block_size; uint64_t total_blocks; uint64_t blocks_available; uint64_t user_blocks_available; diff --git a/source3/libsmb/libsmb_xattr.c b/source3/libsmb/libsmb_xattr.c index 9f7bea8da11..8c23a8f87a6 100644 --- a/source3/libsmb/libsmb_xattr.c +++ b/source3/libsmb/libsmb_xattr.c @@ -146,7 +146,7 @@ ace_compare(struct security_ace *ace1, static void sort_acl(struct security_acl *the_acl) { - uint32 i; + uint32_t i; if (!the_acl) return; TYPESAFE_QSORT(the_acl->aces, the_acl->num_aces, ace_compare); @@ -272,7 +272,7 @@ parse_ace(struct cli_state *ipc_cli, const struct perm_value *v; struct perm_value { const char perm[7]; - uint32 mask; + uint32_t mask; }; TALLOC_CTX *frame = talloc_stackframe(); @@ -558,7 +558,7 @@ dos_attr_query(SMBCCTX *context, struct timespec access_time_ts; struct timespec change_time_ts; off_t size = 0; - uint16 mode = 0; + uint16_t mode = 0; SMB_INO_T inode = 0; DOS_ATTR_DESC *ret; @@ -708,7 +708,7 @@ cacl_get(SMBCCTX *context, char *buf, int bufsize) { - uint32 i; + uint32_t i; int n = 0; int n_used; bool all; @@ -746,7 +746,7 @@ cacl_get(SMBCCTX *context, time_t access_time = (time_t)0; time_t change_time = (time_t)0; off_t size = 0; - uint16 mode = 0; + uint16_t mode = 0; SMB_INO_T ino = 0; struct cli_state *cli = srv->cli; struct { @@ -1515,7 +1515,7 @@ cacl_set(SMBCCTX *context, struct security_acl *dacl = NULL; struct dom_sid *owner_sid = NULL; struct dom_sid *group_sid = NULL; - uint32 i, j; + uint32_t i, j; size_t sd_size; int ret = 0; char *p; @@ -1595,7 +1595,7 @@ cacl_set(SMBCCTX *context, for (j=0;old->dacl && j<old->dacl->num_aces;j++) { if (security_ace_equal(&sd->dacl->aces[i], &old->dacl->aces[j])) { - uint32 k; + uint32_t k; for (k=j; k<old->dacl->num_aces-1;k++) { old->dacl->aces[k] = old->dacl->aces[k+1]; diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index 6f056be54a6..544c5086c55 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -241,9 +241,9 @@ static struct in_addr my_socket_addr_v4(void) static int generate_trn_id(void) { - uint16 id; + uint16_t id; - generate_random_buffer((uint8 *)&id, sizeof(id)); + generate_random_buffer((uint8_t *)&id, sizeof(id)); return id % (unsigned)0x7FFF; } diff --git a/source3/libsmb/nmblib.c b/source3/libsmb/nmblib.c index 4adc3da5fab..8feb029b05e 100644 --- a/source3/libsmb/nmblib.c +++ b/source3/libsmb/nmblib.c @@ -1334,7 +1334,7 @@ static unsigned char *name_ptr(unsigned char *buf, size_t buf_len, unsigned int c = *(unsigned char *)(buf+ofs); if ((c & 0xC0) == 0xC0) { - uint16 l = 0; + uint16_t l = 0; if (ofs > buf_len - 1) { return NULL; diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c deleted file mode 100644 index e661aebba12..00000000000 --- a/source3/libsmb/ntlmssp.c +++ /dev/null @@ -1,765 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 3.0 - handle NLTMSSP, server side - - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Andrew Bartlett 2001-2010 - Copyright (C) Stefan Metzmacher 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "../auth/ntlmssp/ntlmssp.h" -#include "../auth/ntlmssp/ntlmssp_private.h" -#include "../libcli/auth/libcli_auth.h" -#include "../librpc/gen_ndr/ndr_ntlmssp.h" -#include "../auth/ntlmssp/ntlmssp_ndr.h" -#include "../lib/crypto/md5.h" -#include "../lib/crypto/arcfour.h" -#include "../lib/crypto/hmacmd5.h" -#include "../nsswitch/libwbclient/wbclient.h" - -static NTSTATUS ntlmssp3_client_initial(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - DATA_BLOB reply, DATA_BLOB *next_request); -static NTSTATUS ntlmssp3_client_challenge(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, /* Unused at this time */ - const DATA_BLOB reply, DATA_BLOB *next_request); -/** - * Callbacks for NTLMSSP - for both client and server operating modes - * - */ - -static const struct ntlmssp_callbacks { - enum ntlmssp_role role; - enum ntlmssp_message_type ntlmssp_command; - NTSTATUS (*fn)(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - DATA_BLOB in, DATA_BLOB *out); -} ntlmssp_callbacks[] = { - {NTLMSSP_CLIENT, NTLMSSP_INITIAL, ntlmssp3_client_initial}, - {NTLMSSP_CLIENT, NTLMSSP_CHALLENGE, ntlmssp3_client_challenge}, - {NTLMSSP_CLIENT, NTLMSSP_UNKNOWN, NULL}, - {NTLMSSP_SERVER, NTLMSSP_UNKNOWN, NULL} -}; - -/** - * Set a username on an NTLMSSP context - ensures it is talloc()ed - * - */ - -NTSTATUS ntlmssp_set_username(struct ntlmssp_state *ntlmssp_state, const char *user) -{ - ntlmssp_state->user = talloc_strdup(ntlmssp_state, user ? user : "" ); - if (!ntlmssp_state->user) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Converts a password to the hashes on an NTLMSSP context. - * - */ -NTSTATUS ntlmssp_set_password(struct ntlmssp_state *ntlmssp_state, const char *password) -{ - uint8_t lm_hash[16]; - uint8_t nt_hash[16]; - - TALLOC_FREE(ntlmssp_state->lm_hash); - TALLOC_FREE(ntlmssp_state->nt_hash); - - if (password == NULL) { - return NT_STATUS_OK; - } - - if (E_deshash(password, lm_hash)) { - ntlmssp_state->lm_hash = (uint8_t *) - talloc_memdup(ntlmssp_state, lm_hash, 16); - if (!ntlmssp_state->lm_hash) { - return NT_STATUS_NO_MEMORY; - } - } - - E_md4hash(password, nt_hash); - - ntlmssp_state->nt_hash = (uint8_t *) - talloc_memdup(ntlmssp_state, nt_hash, 16); - if (!ntlmssp_state->nt_hash) { - TALLOC_FREE(ntlmssp_state->lm_hash); - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - -NTSTATUS ntlmssp_set_password_hash(struct ntlmssp_state *state, - const char *pwhash) -{ - char nt_hash[16]; - size_t converted; - - converted = strhex_to_str( - nt_hash, sizeof(nt_hash), pwhash, strlen(pwhash)); - if (converted != sizeof(nt_hash)) { - return NT_STATUS_INVALID_PARAMETER; - } - - TALLOC_FREE(state->lm_hash); - TALLOC_FREE(state->nt_hash); - - state->nt_hash = (uint8_t *)talloc_memdup(state, nt_hash, 16); - if (!state->nt_hash) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Set a domain on an NTLMSSP context - ensures it is talloc()ed - * - */ -NTSTATUS ntlmssp_set_domain(struct ntlmssp_state *ntlmssp_state, const char *domain) -{ - ntlmssp_state->domain = talloc_strdup(ntlmssp_state, - domain ? domain : "" ); - if (!ntlmssp_state->domain) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Request features for the NTLMSSP negotiation - * - * @param ntlmssp_state NTLMSSP state - * @param feature_list List of space separated features requested from NTLMSSP. - */ -void ntlmssp_want_feature_list(struct ntlmssp_state *ntlmssp_state, char *feature_list) -{ - /* - * We need to set this to allow a later SetPassword - * via the SAMR pipe to succeed. Strange.... We could - * also add NTLMSSP_NEGOTIATE_SEAL here. JRA. - */ - if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, True)) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } - if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, True)) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } - if(in_list("NTLMSSP_FEATURE_SEAL", feature_list, True)) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; - } - if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list, true)) { - ntlmssp_state->use_ccache = true; - } -} - -/** - * Request a feature for the NTLMSSP negotiation - * - * @param ntlmssp_state NTLMSSP state - * @param feature Bit flag specifying the requested feature - */ -void ntlmssp_want_feature(struct ntlmssp_state *ntlmssp_state, uint32_t feature) -{ - /* As per JRA's comment above */ - if (feature & NTLMSSP_FEATURE_SESSION_KEY) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } - if (feature & NTLMSSP_FEATURE_SIGN) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } - if (feature & NTLMSSP_FEATURE_SEAL) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; - } - if (feature & NTLMSSP_FEATURE_CCACHE) { - ntlmssp_state->use_ccache = true; - } -} - -/** - * Next state function for the NTLMSSP state machine - * - * @param ntlmssp_state NTLMSSP State - * @param in The packet in from the NTLMSSP partner, as a DATA_BLOB - * @param out The reply, as an allocated DATA_BLOB, caller to free. - * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK. - */ - -NTSTATUS ntlmssp_update(struct ntlmssp_state *ntlmssp_state, - const DATA_BLOB input, DATA_BLOB *out) -{ - uint32_t ntlmssp_command; - int i; - - if (ntlmssp_state->expected_state == NTLMSSP_DONE) { - /* Called update after negotiations finished. */ - DEBUG(1, ("Called NTLMSSP after state machine was 'done'\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - *out = data_blob_null; - - if (!input.length) { - switch (ntlmssp_state->role) { - case NTLMSSP_CLIENT: - ntlmssp_command = NTLMSSP_INITIAL; - break; - case NTLMSSP_SERVER: - /* 'datagram' mode - no neg packet */ - ntlmssp_command = NTLMSSP_NEGOTIATE; - break; - default: - DEBUG(1, ("Invalid role: %d\n", ntlmssp_state->role)); - return NT_STATUS_INVALID_PARAMETER; - } - } else { - if (!msrpc_parse(ntlmssp_state, &input, "Cd", - "NTLMSSP", - &ntlmssp_command)) { - DEBUG(1, ("Failed to parse NTLMSSP packet, could not extract NTLMSSP command\n")); - dump_data(2, input.data, input.length); - return NT_STATUS_INVALID_PARAMETER; - } - } - - if (ntlmssp_command != ntlmssp_state->expected_state) { - DEBUG(1, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command, ntlmssp_state->expected_state)); - return NT_STATUS_INVALID_PARAMETER; - } - - for (i=0; ntlmssp_callbacks[i].fn; i++) { - if (ntlmssp_callbacks[i].role == ntlmssp_state->role - && ntlmssp_callbacks[i].ntlmssp_command == ntlmssp_command) { - return ntlmssp_callbacks[i].fn(ntlmssp_state, ntlmssp_state, input, out); - } - } - - DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n", - ntlmssp_state->role, ntlmssp_command)); - - return NT_STATUS_INVALID_PARAMETER; -} - -/********************************************************************* - Client side NTLMSSP -*********************************************************************/ - -/** - * Next state function for the Initial packet - * - * @param ntlmssp_state NTLMSSP State - * @param request The request, as a DATA_BLOB. reply.data must be NULL - * @param request The reply, as an allocated DATA_BLOB, caller to free. - * @return Errors or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp3_client_initial(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - DATA_BLOB in, DATA_BLOB *out) -{ - const char *domain = ntlmssp_state->client.netbios_domain; - const char *workstation = ntlmssp_state->client.netbios_name; - NTSTATUS status; - - /* These don't really matter in the initial packet, so don't panic if they are not set */ - if (!domain) { - domain = ""; - } - - if (!workstation) { - workstation = ""; - } - - if (ntlmssp_state->unicode) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE; - } else { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM; - } - - if (ntlmssp_state->use_ntlmv2) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; - } - - /* generate the ntlmssp negotiate packet */ - status = msrpc_gen(out_mem_ctx, - out, "CddAA", - "NTLMSSP", - NTLMSSP_NEGOTIATE, - ntlmssp_state->neg_flags, - domain, - workstation); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("ntlmssp_client_initial: failed to generate " - "ntlmssp negotiate packet\n")); - return status; - } - - if (DEBUGLEVEL >= 10) { - struct NEGOTIATE_MESSAGE *negotiate = talloc( - talloc_tos(), struct NEGOTIATE_MESSAGE); - if (negotiate != NULL) { - status = ntlmssp_pull_NEGOTIATE_MESSAGE( - out, negotiate, negotiate); - if (NT_STATUS_IS_OK(status)) { - NDR_PRINT_DEBUG(NEGOTIATE_MESSAGE, - negotiate); - } - TALLOC_FREE(negotiate); - } - } - - ntlmssp_state->expected_state = NTLMSSP_CHALLENGE; - - return NT_STATUS_MORE_PROCESSING_REQUIRED; -} - -bool ntlmssp_is_anonymous(struct ntlmssp_state *ntlmssp_state) -{ - const char *user = ntlmssp_state->user; - - if (user == NULL) { - return true; - } - - if (strlen(user) == 0) { - return true; - } - - return false; -} - -/** - * Next state function for the Challenge Packet. Generate an auth packet. - * - * @param ntlmssp_state NTLMSSP State - * @param request The request, as a DATA_BLOB. reply.data must be NULL - * @param request The reply, as an allocated DATA_BLOB, caller to free. - * @return Errors or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp3_client_challenge(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, /* Unused at this time */ - const DATA_BLOB reply, DATA_BLOB *next_request) -{ - uint32_t chal_flags, ntlmssp_command, unkn1 = 0, unkn2 = 0; - DATA_BLOB server_domain_blob; - DATA_BLOB challenge_blob; - DATA_BLOB struct_blob = data_blob_null; - char *server_domain; - const char *chal_parse_string; - const char *chal_parse_string_short = NULL; - const char *auth_gen_string; - DATA_BLOB lm_response = data_blob_null; - DATA_BLOB nt_response = data_blob_null; - DATA_BLOB session_key = data_blob_null; - DATA_BLOB encrypted_session_key = data_blob_null; - NTSTATUS nt_status = NT_STATUS_OK; - bool anon = ntlmssp_is_anonymous(ntlmssp_state); - - if (!anon && ntlmssp_state->use_ccache) { - struct wbcCredentialCacheParams params; - struct wbcCredentialCacheInfo *info = NULL; - struct wbcAuthErrorInfo *error = NULL; - struct wbcNamedBlob auth_blob; - struct wbcBlob *wbc_next = NULL; - struct wbcBlob *wbc_session_key = NULL; - wbcErr wbc_status; - int i; - - /* - * We need to set the netbios name or we are not able to connect - * a Windows DC. - */ - if (ntlmssp_state->server.netbios_domain == NULL || - ntlmssp_state->server.netbios_domain[0] == '\0') { - ntlmssp_state->server.netbios_domain = ntlmssp_state->domain; - } - - params.account_name = ntlmssp_state->user; - params.domain_name = ntlmssp_state->domain; - params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP; - - auth_blob.name = "challenge_blob"; - auth_blob.flags = 0; - auth_blob.blob.data = reply.data; - auth_blob.blob.length = reply.length; - params.num_blobs = 1; - params.blobs = &auth_blob; - - wbc_status = wbcCredentialCache(¶ms, &info, &error); - wbcFreeMemory(error); - if (!WBC_ERROR_IS_OK(wbc_status)) { - goto noccache; - } - - for (i=0; i<info->num_blobs; i++) { - if (strequal(info->blobs[i].name, "auth_blob")) { - wbc_next = &info->blobs[i].blob; - } - if (strequal(info->blobs[i].name, "session_key")) { - wbc_session_key = &info->blobs[i].blob; - } - } - if ((wbc_next == NULL) || (wbc_session_key == NULL)) { - wbcFreeMemory(info); - goto noccache; - } - - *next_request = data_blob_talloc(ntlmssp_state, - wbc_next->data, - wbc_next->length); - ntlmssp_state->session_key = data_blob_talloc(ntlmssp_state, - wbc_session_key->data, - wbc_session_key->length); - - wbcFreeMemory(info); - goto done; - } - -noccache: - - if (!msrpc_parse(ntlmssp_state, &reply, "CdBd", - "NTLMSSP", - &ntlmssp_command, - &server_domain_blob, - &chal_flags)) { - DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n")); - dump_data(2, reply.data, reply.length); - - return NT_STATUS_INVALID_PARAMETER; - } - - if (DEBUGLEVEL >= 10) { - struct CHALLENGE_MESSAGE *challenge = talloc( - talloc_tos(), struct CHALLENGE_MESSAGE); - if (challenge != NULL) { - NTSTATUS status; - challenge->NegotiateFlags = chal_flags; - status = ntlmssp_pull_CHALLENGE_MESSAGE( - &reply, challenge, challenge); - if (NT_STATUS_IS_OK(status)) { - NDR_PRINT_DEBUG(CHALLENGE_MESSAGE, - challenge); - } - TALLOC_FREE(challenge); - } - } - - data_blob_free(&server_domain_blob); - - DEBUG(3, ("Got challenge flags:\n")); - debug_ntlmssp_flags(chal_flags); - - ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth()); - - if (ntlmssp_state->unicode) { - if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) { - chal_parse_string = "CdUdbddB"; - } else { - chal_parse_string = "CdUdbdd"; - chal_parse_string_short = "CdUdb"; - } - auth_gen_string = "CdBBUUUBd"; - } else { - if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) { - chal_parse_string = "CdAdbddB"; - } else { - chal_parse_string = "CdAdbdd"; - chal_parse_string_short = "CdAdb"; - } - - auth_gen_string = "CdBBAAABd"; - } - - DEBUG(3, ("NTLMSSP: Set final flags:\n")); - debug_ntlmssp_flags(ntlmssp_state->neg_flags); - - if (!msrpc_parse(ntlmssp_state, &reply, chal_parse_string, - "NTLMSSP", - &ntlmssp_command, - &server_domain, - &chal_flags, - &challenge_blob, 8, - &unkn1, &unkn2, - &struct_blob)) { - - bool ok = false; - - DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n")); - - if (chal_parse_string_short != NULL) { - /* - * In the case where NTLMSSP_NEGOTIATE_TARGET_INFO - * is not used, some NTLMSSP servers don't return - * the unused unkn1 and unkn2 fields. - * See bug: - * https://bugzilla.samba.org/show_bug.cgi?id=10016 - * for packet traces. - * Try and parse again without them. - */ - ok = msrpc_parse(ntlmssp_state, &reply, - chal_parse_string_short, - "NTLMSSP", - &ntlmssp_command, - &server_domain, - &chal_flags, - &challenge_blob, 8); - if (!ok) { - DEBUG(1, ("Failed to short parse " - "the NTLMSSP Challenge: (#2)\n")); - } - } - - if (!ok) { - dump_data(2, reply.data, reply.length); - return NT_STATUS_INVALID_PARAMETER; - } - } - - if (chal_flags & NTLMSSP_TARGET_TYPE_SERVER) { - ntlmssp_state->server.is_standalone = true; - } else { - ntlmssp_state->server.is_standalone = false; - } - /* TODO: parse struct_blob and fill in the rest */ - ntlmssp_state->server.netbios_name = ""; - ntlmssp_state->server.netbios_domain = server_domain; - ntlmssp_state->server.dns_name = ""; - ntlmssp_state->server.dns_domain = ""; - - if (challenge_blob.length != 8) { - data_blob_free(&struct_blob); - return NT_STATUS_INVALID_PARAMETER; - } - - if (anon || !ntlmssp_state->nt_hash) { - static const uint8_t zeros[16] = {0, }; - /* do nothing - blobs are zero length */ - - /* session key is all zeros */ - session_key = data_blob_talloc(ntlmssp_state, zeros, 16); - - /* not doing NLTM2 without a password */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; - } else if (ntlmssp_state->use_ntlmv2) { - if (!struct_blob.length) { - /* be lazy, match win2k - we can't do NTLMv2 without it */ - DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - /* TODO: if the remote server is standalone, then we should replace 'domain' - with the server name as supplied above */ - - if (!SMBNTLMv2encrypt_hash(ntlmssp_state, - ntlmssp_state->user, - ntlmssp_state->domain, - ntlmssp_state->nt_hash, &challenge_blob, - &struct_blob, - &lm_response, &nt_response, NULL, - &session_key)) { - data_blob_free(&challenge_blob); - data_blob_free(&struct_blob); - return NT_STATUS_NO_MEMORY; - } - } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - MD5_CTX md5_session_nonce_ctx; - uint8_t session_nonce[16]; - uint8_t session_nonce_hash[16]; - uint8_t user_session_key[16]; - - lm_response = data_blob_talloc(ntlmssp_state, NULL, 24); - generate_random_buffer(lm_response.data, 8); - memset(lm_response.data+8, 0, 16); - - memcpy(session_nonce, challenge_blob.data, 8); - memcpy(&session_nonce[8], lm_response.data, 8); - - MD5Init(&md5_session_nonce_ctx); - MD5Update(&md5_session_nonce_ctx, challenge_blob.data, 8); - MD5Update(&md5_session_nonce_ctx, lm_response.data, 8); - MD5Final(session_nonce_hash, &md5_session_nonce_ctx); - - DEBUG(5, ("NTLMSSP challenge set by NTLM2\n")); - DEBUG(5, ("challenge is: \n")); - dump_data(5, session_nonce_hash, 8); - - nt_response = data_blob_talloc(ntlmssp_state, NULL, 24); - SMBNTencrypt_hash(ntlmssp_state->nt_hash, - session_nonce_hash, - nt_response.data); - - session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - - SMBsesskeygen_ntv1(ntlmssp_state->nt_hash, user_session_key); - hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data); - dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length); - } else { - /* lanman auth is insecure, it may be disabled */ - if (lp_client_lanman_auth() && ntlmssp_state->lm_hash) { - lm_response = data_blob_talloc(ntlmssp_state, - NULL, 24); - SMBencrypt_hash(ntlmssp_state->lm_hash,challenge_blob.data, - lm_response.data); - } - - nt_response = data_blob_talloc(ntlmssp_state, NULL, 24); - SMBNTencrypt_hash(ntlmssp_state->nt_hash,challenge_blob.data, - nt_response.data); - - session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) - && lp_client_lanman_auth() && ntlmssp_state->lm_hash) { - SMBsesskeygen_lm_sess_key(ntlmssp_state->lm_hash, lm_response.data, - session_key.data); - dump_data_pw("LM session key\n", session_key.data, session_key.length); - } else { - SMBsesskeygen_ntv1(ntlmssp_state->nt_hash, session_key.data); - dump_data_pw("NT session key:\n", session_key.data, session_key.length); - } - } - data_blob_free(&struct_blob); - - /* Key exchange encryptes a new client-generated session key with - the password-derived key */ - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { - /* Make up a new session key */ - uint8_t client_session_key[16]; - generate_random_buffer(client_session_key, sizeof(client_session_key)); - - /* Encrypt the new session key with the old one */ - encrypted_session_key = data_blob(client_session_key, sizeof(client_session_key)); - dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length); - arcfour_crypt_blob(encrypted_session_key.data, encrypted_session_key.length, &session_key); - dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length); - - /* Mark the new session key as the 'real' session key */ - data_blob_free(&session_key); - session_key = data_blob_talloc(ntlmssp_state, - client_session_key, - sizeof(client_session_key)); - } - - /* this generates the actual auth packet */ - nt_status = msrpc_gen(ntlmssp_state, next_request, auth_gen_string, - "NTLMSSP", - NTLMSSP_AUTH, - lm_response.data, lm_response.length, - nt_response.data, nt_response.length, - ntlmssp_state->domain, - ntlmssp_state->user, - ntlmssp_state->client.netbios_name, - encrypted_session_key.data, encrypted_session_key.length, - ntlmssp_state->neg_flags); - - if (!NT_STATUS_IS_OK(nt_status)) { - return NT_STATUS_NO_MEMORY; - } - - if (DEBUGLEVEL >= 10) { - struct AUTHENTICATE_MESSAGE *authenticate = talloc( - talloc_tos(), struct AUTHENTICATE_MESSAGE); - if (authenticate != NULL) { - NTSTATUS status; - authenticate->NegotiateFlags = - ntlmssp_state->neg_flags; - status = ntlmssp_pull_AUTHENTICATE_MESSAGE( - next_request, authenticate, authenticate); - if (NT_STATUS_IS_OK(status)) { - NDR_PRINT_DEBUG(AUTHENTICATE_MESSAGE, - authenticate); - } - TALLOC_FREE(authenticate); - } - } - - data_blob_free(&encrypted_session_key); - - data_blob_free(&ntlmssp_state->chal); - - ntlmssp_state->session_key = session_key; - - ntlmssp_state->chal = challenge_blob; - ntlmssp_state->lm_resp = lm_response; - ntlmssp_state->nt_resp = nt_response; - -done: - - ntlmssp_state->expected_state = NTLMSSP_DONE; - - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_sign_init(ntlmssp_state))) { - DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", nt_errstr(nt_status))); - } - - return nt_status; -} - -NTSTATUS ntlmssp_client_start(TALLOC_CTX *mem_ctx, - const char *netbios_name, - const char *netbios_domain, - bool use_ntlmv2, - struct ntlmssp_state **_ntlmssp_state) -{ - struct ntlmssp_state *ntlmssp_state; - - if (!netbios_name) { - netbios_name = ""; - } - - if (!netbios_domain) { - netbios_domain = ""; - } - - ntlmssp_state = talloc_zero(mem_ctx, struct ntlmssp_state); - if (!ntlmssp_state) { - return NT_STATUS_NO_MEMORY; - } - - ntlmssp_state->role = NTLMSSP_CLIENT; - - ntlmssp_state->unicode = True; - - ntlmssp_state->use_ntlmv2 = use_ntlmv2; - - ntlmssp_state->expected_state = NTLMSSP_INITIAL; - - ntlmssp_state->neg_flags = - NTLMSSP_NEGOTIATE_128 | - NTLMSSP_NEGOTIATE_ALWAYS_SIGN | - NTLMSSP_NEGOTIATE_NTLM | - NTLMSSP_NEGOTIATE_NTLM2 | - NTLMSSP_NEGOTIATE_KEY_EXCH | - NTLMSSP_REQUEST_TARGET; - - ntlmssp_state->client.netbios_name = talloc_strdup(ntlmssp_state, netbios_name); - if (!ntlmssp_state->client.netbios_name) { - talloc_free(ntlmssp_state); - return NT_STATUS_NO_MEMORY; - } - ntlmssp_state->client.netbios_domain = talloc_strdup(ntlmssp_state, netbios_domain); - if (!ntlmssp_state->client.netbios_domain) { - talloc_free(ntlmssp_state); - return NT_STATUS_NO_MEMORY; - } - - *_ntlmssp_state = ntlmssp_state; - return NT_STATUS_OK; -} diff --git a/source3/libsmb/ntlmssp_wrap.c b/source3/libsmb/ntlmssp_wrap.c deleted file mode 100644 index 46f68aede79..00000000000 --- a/source3/libsmb/ntlmssp_wrap.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - NLTMSSP wrappers - - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Andrew Bartlett 2001-2003,2011 - - 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 3 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "auth/ntlmssp/ntlmssp.h" -#include "auth/ntlmssp/ntlmssp_private.h" -#include "auth_generic.h" -#include "auth/gensec/gensec.h" -#include "auth/gensec/gensec_internal.h" -#include "auth/credentials/credentials.h" -#include "librpc/rpc/dcerpc.h" -#include "lib/param/param.h" - -static NTSTATUS gensec_ntlmssp3_client_update(struct gensec_security *gensec_security, - TALLOC_CTX *out_mem_ctx, - struct tevent_context *ev, - const DATA_BLOB request, - DATA_BLOB *reply) -{ - NTSTATUS status; - struct gensec_ntlmssp_context *gensec_ntlmssp = - talloc_get_type_abort(gensec_security->private_data, - struct gensec_ntlmssp_context); - - status = ntlmssp_update(gensec_ntlmssp->ntlmssp_state, request, reply); - if (NT_STATUS_IS_OK(status) || - NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - talloc_steal(out_mem_ctx, reply->data); - } - - return status; -} - -static NTSTATUS gensec_ntlmssp3_client_start(struct gensec_security *gensec_security) -{ - NTSTATUS nt_status; - struct gensec_ntlmssp_context *gensec_ntlmssp; - const char *user, *domain; - const char *password; - - nt_status = gensec_ntlmssp_start(gensec_security); - NT_STATUS_NOT_OK_RETURN(nt_status); - - gensec_ntlmssp = - talloc_get_type_abort(gensec_security->private_data, - struct gensec_ntlmssp_context); - - nt_status = ntlmssp_client_start(gensec_ntlmssp, - lp_netbios_name(), lp_workgroup(), - lp_client_ntlmv2_auth(), &gensec_ntlmssp->ntlmssp_state); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - cli_credentials_get_ntlm_username_domain(gensec_security->credentials, gensec_ntlmssp, &user, &domain); - if (!user || !domain) { - return NT_STATUS_NO_MEMORY; - } - - nt_status = ntlmssp_set_username(gensec_ntlmssp->ntlmssp_state, user); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - nt_status = ntlmssp_set_domain(gensec_ntlmssp->ntlmssp_state, domain); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - password = cli_credentials_get_password(gensec_security->credentials); - if (!password) { - return NT_STATUS_NO_MEMORY; - } - - nt_status = ntlmssp_set_password(gensec_ntlmssp->ntlmssp_state, password); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { - gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } - if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { - gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } - if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { - gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; - } - - return NT_STATUS_OK; -} - -static const char *gensec_ntlmssp3_client_oids[] = { - GENSEC_OID_NTLMSSP, - NULL -}; - -const struct gensec_security_ops gensec_ntlmssp3_client_ops = { - .name = "ntlmssp3_client", - .sasl_name = GENSEC_SASL_NAME_NTLMSSP, /* "NTLM" */ - .auth_type = DCERPC_AUTH_TYPE_NTLMSSP, - .oid = gensec_ntlmssp3_client_oids, - .client_start = gensec_ntlmssp3_client_start, - .magic = gensec_ntlmssp_magic, - .update = gensec_ntlmssp3_client_update, - .sig_size = gensec_ntlmssp_sig_size, - .sign_packet = gensec_ntlmssp_sign_packet, - .check_packet = gensec_ntlmssp_check_packet, - .seal_packet = gensec_ntlmssp_seal_packet, - .unseal_packet = gensec_ntlmssp_unseal_packet, - .wrap = gensec_ntlmssp_wrap, - .unwrap = gensec_ntlmssp_unwrap, - .session_key = gensec_ntlmssp_session_key, - .have_feature = gensec_ntlmssp_have_feature, - .enabled = true, - .priority = GENSEC_NTLMSSP -}; diff --git a/source3/libsmb/passchange.c b/source3/libsmb/passchange.c index 9736adab9f6..3b8767672e3 100644 --- a/source3/libsmb/passchange.c +++ b/source3/libsmb/passchange.c @@ -57,7 +57,7 @@ NTSTATUS remote_password_change(const char *remote_machine, const char *user_nam *err_str = NULL; result = cli_connect_nb(remote_machine, NULL, 0, 0x20, NULL, - SMB_SIGNING_DEFAULT, 0, &cli); + SMB_SIGNING_IPC_DEFAULT, 0, &cli); if (!NT_STATUS_IS_OK(result)) { if (asprintf(err_str, "Unable to connect to SMB server on " "machine %s. Error was : %s.\n", @@ -67,8 +67,9 @@ NTSTATUS remote_password_change(const char *remote_machine, const char *user_nam return result; } - result = smbXcli_negprot(cli->conn, cli->timeout, PROTOCOL_CORE, - PROTOCOL_NT1); + result = smbXcli_negprot(cli->conn, cli->timeout, + lp_client_ipc_min_protocol(), + lp_client_ipc_max_protocol()); if (!NT_STATUS_IS_OK(result)) { if (asprintf(err_str, "machine %s rejected the negotiate " diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index 08dda9685fc..a4b3c7423ab 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -99,7 +99,7 @@ NTSTATUS cli_full_connection(struct cli_state **output_cli, int signing_state); NTSTATUS cli_raw_tcon(struct cli_state *cli, const char *service, const char *pass, const char *dev, - uint16 *max_xmit, uint16 *tid); + uint16_t *max_xmit, uint16_t *tid); struct cli_state *get_ipc_connect(char *server, struct sockaddr_storage *server_ss, const struct user_auth_info *user_info); @@ -176,7 +176,7 @@ void cli_nt_pipes_close(struct cli_state *cli); void cli_shutdown(struct cli_state *cli); const char *cli_state_remote_realm(struct cli_state *cli); uint16_t cli_state_get_vc_num(struct cli_state *cli); -uint16 cli_setpid(struct cli_state *cli, uint16 pid); +uint16_t cli_setpid(struct cli_state *cli, uint16_t pid); uint16_t cli_getpid(struct cli_state *cli); bool cli_state_has_tcon(struct cli_state *cli); uint16_t cli_state_get_tid(struct cli_state *cli); @@ -204,7 +204,7 @@ NTSTATUS cli_smb(TALLOC_CTX *mem_ctx, struct cli_state *cli, const char *cli_errstr(struct cli_state *cli); NTSTATUS cli_nt_error(struct cli_state *cli); -void cli_dos_error(struct cli_state *cli, uint8 *eclass, uint32 *ecode); +void cli_dos_error(struct cli_state *cli, uint8_t *eclass, uint32_t *ecode); int cli_errno(struct cli_state *cli); bool cli_is_error(struct cli_state *cli); bool cli_is_nt_error(struct cli_state *cli); @@ -643,16 +643,16 @@ NTSTATUS cli_unix_extensions_version_recv(struct tevent_req *req, uint16_t *pmajor, uint16_t *pminor, uint32_t *pcaplow, uint32_t *pcaphigh); -NTSTATUS cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor, - uint16 *pminor, uint32 *pcaplow, - uint32 *pcaphigh); +NTSTATUS cli_unix_extensions_version(struct cli_state *cli, uint16_t *pmajor, + uint16_t *pminor, uint32_t *pcaplow, + uint32_t *pcaphigh); struct tevent_req *cli_set_unix_extensions_capabilities_send( TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, uint16_t major, uint16_t minor, uint32_t caplow, uint32_t caphigh); NTSTATUS cli_set_unix_extensions_capabilities_recv(struct tevent_req *req); NTSTATUS cli_set_unix_extensions_capabilities(struct cli_state *cli, - uint16 major, uint16 minor, - uint32 caplow, uint32 caphigh); + uint16_t major, uint16_t minor, + uint32_t caplow, uint32 caphigh); struct tevent_req *cli_get_fs_attr_info_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli); @@ -660,7 +660,7 @@ NTSTATUS cli_get_fs_attr_info_recv(struct tevent_req *req, uint32_t *fs_attr); NTSTATUS cli_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr); NTSTATUS cli_get_fs_volume_info(struct cli_state *cli, TALLOC_CTX *mem_ctx, char **volume_name, - uint32 *pserial_number, time_t *pdate); + uint32_t *pserial_number, time_t *pdate); NTSTATUS cli_get_fs_full_size_info(struct cli_state *cli, uint64_t *total_allocation_units, uint64_t *caller_allocation_units, @@ -668,8 +668,8 @@ NTSTATUS cli_get_fs_full_size_info(struct cli_state *cli, uint64_t *sectors_per_allocation_unit, uint64_t *bytes_per_sector); NTSTATUS cli_get_posix_fs_info(struct cli_state *cli, - uint32 *optimal_transfer_size, - uint32 *block_size, + uint32_t *optimal_transfer_size, + uint32_t *block_size, uint64_t *total_blocks, uint64_t *blocks_available, uint64_t *user_blocks_available, @@ -688,7 +688,7 @@ NTSTATUS cli_force_encryption(struct cli_state *c, /* The following definitions come from libsmb/clilist.c */ -NTSTATUS cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute, +NTSTATUS cli_list_old(struct cli_state *cli,const char *Mask,uint16_t attribute, NTSTATUS (*fn)(const char *, struct file_info *, const char *, void *), void *state); NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask, @@ -704,7 +704,7 @@ struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx, uint16_t info_level); NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct file_info **finfo, size_t *num_finfo); -NTSTATUS cli_list(struct cli_state *cli,const char *Mask,uint16 attribute, +NTSTATUS cli_list(struct cli_state *cli,const char *Mask,uint16_t attribute, NTSTATUS (*fn)(const char *, struct file_info *, const char *, void *), void *state); diff --git a/source3/libsmb/samlogon_cache.c b/source3/libsmb/samlogon_cache.c index 0a157d48463..a91ef6e4214 100644 --- a/source3/libsmb/samlogon_cache.c +++ b/source3/libsmb/samlogon_cache.c @@ -261,7 +261,7 @@ struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const struct do --jerry */ { time_t now = time(NULL); - uint32 time_diff; + uint32_t time_diff; /* is the entry expired? */ time_diff = now - t; diff --git a/source3/libsmb/smb_share_modes.c b/source3/libsmb/smb_share_modes.c index bf21bf5a593..325078d0875 100644 --- a/source3/libsmb/smb_share_modes.c +++ b/source3/libsmb/smb_share_modes.c @@ -60,7 +60,7 @@ struct locking_data { int num_share_mode_entries; struct timespec old_write_time; struct timespec changed_write_time; - uint32 num_delete_token_entries; + uint32_t num_delete_token_entries; } s; struct share_mode_entry dummy; /* Needed for alignment. */ } u; @@ -146,7 +146,7 @@ static TDB_DATA get_locking_key(struct locking_key *lk, uint64_t dev, lk->dev = (SMB_DEV_T)dev; lk->inode = (SMB_INO_T)ino; lk->extid = extid; - ld.dptr = (uint8 *)lk; + ld.dptr = (uint8_t *)lk; ld.dsize = sizeof(*lk); return ld; } @@ -213,7 +213,7 @@ static void create_share_mode_entry(struct share_mode_entry *out, out->id.devid = in->dev; out->id.inode = in->ino; out->id.extid = in->extid; - out->uid = (uint32)geteuid(); + out->uid = (uint32_t)geteuid(); out->flags = 0; out->name_hash = name_hash; } @@ -342,7 +342,7 @@ int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx, int orig_num_share_modes = 0; struct locking_data *ld = NULL; /* internal samba db state. */ struct share_mode_entry *shares = NULL; - uint8 *new_data_p = NULL; + uint8_t *new_data_p = NULL; size_t new_data_size = 0; int err = 0; uint32_t name_hash = smb_name_hash(sharepath, filename, &err); @@ -354,7 +354,7 @@ int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx, db_data = tdb_fetch_compat(db_ctx->smb_tdb, locking_key); if (!db_data.dptr) { /* We must create the entry. */ - db_data.dptr = (uint8 *)malloc( + db_data.dptr = (uint8_t *)malloc( sizeof(struct locking_data) + sizeof(struct share_mode_entry) + strlen(sharepath) + 1 + @@ -389,7 +389,7 @@ int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx, } /* Entry exists, we must add a new entry. */ - new_data_p = (uint8 *)malloc( + new_data_p = (uint8_t *)malloc( db_data.dsize + sizeof(struct share_mode_entry)); if (!new_data_p) { free(db_data.dptr); @@ -463,10 +463,10 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx, int orig_num_share_modes = 0; struct locking_data *ld = NULL; /* internal samba db state. */ struct share_mode_entry *shares = NULL; - uint8 *new_data_p = NULL; + uint8_t *new_data_p = NULL; size_t remaining_size = 0; size_t i, num_share_modes; - const uint8 *remaining_ptr = NULL; + const uint8_t *remaining_ptr = NULL; db_data = tdb_fetch_compat(db_ctx->smb_tdb, locking_key); if (!db_data.dptr) { @@ -490,7 +490,7 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx, } /* More than one - allocate a new record minus the one we'll delete. */ - new_data_p = (uint8 *)malloc( + new_data_p = (uint8_t *)malloc( db_data.dsize - sizeof(struct share_mode_entry)); if (!new_data_p) { free(db_data.dptr); diff --git a/source3/libsmb/smbsock_connect.c b/source3/libsmb/smbsock_connect.c index dc04b6a966e..9f915e1bb42 100644 --- a/source3/libsmb/smbsock_connect.c +++ b/source3/libsmb/smbsock_connect.c @@ -29,7 +29,7 @@ struct cli_session_request_state { struct tevent_context *ev; int sock; - uint32 len_hdr; + uint32_t len_hdr; struct iovec iov[3]; uint8_t nb_session_response; }; diff --git a/source3/pam_smbpass/wscript_build b/source3/pam_smbpass/wscript_build index a4eaa6c2972..fb760b431d1 100644 --- a/source3/pam_smbpass/wscript_build +++ b/source3/pam_smbpass/wscript_build @@ -8,7 +8,7 @@ if bld.CONFIG_SET('WITH_PAM_MODULES'): support.c''', allow_warnings=True, deps='''tdb talloc pam PAM_ERRORS wbclient cap asn1util param pdb - LIBNTLMSSP LIBTSOCKET''', + LIBTSOCKET''', cflags='-DLOCALEDIR=\"%s/locale\"' % bld.env.DATADIR, realname='pam_smbpass.so', install_path='${PAMMODULESDIR}', diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index d15d7fc5e8a..e805fa420a1 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -69,6 +69,7 @@ #include "dbwrap/dbwrap.h" #include "dbwrap/dbwrap_rbt.h" #include "../lib/util/bitmap.h" +#include "source4/lib/tls/tls.h" #ifdef HAVE_SYS_SYSCTL_H #include <sys/sysctl.h> @@ -612,6 +613,8 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.server_min_protocol = PROTOCOL_LANMAN1; Globals._client_max_protocol = PROTOCOL_DEFAULT; Globals.client_min_protocol = PROTOCOL_CORE; + Globals._client_ipc_max_protocol = PROTOCOL_DEFAULT; + Globals._client_ipc_min_protocol = PROTOCOL_DEFAULT; Globals._security = SEC_AUTO; Globals.encrypt_passwords = true; Globals.client_schannel = Auto; @@ -663,9 +666,12 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.client_plaintext_auth = false; /* Do NOT use a plaintext password even if is requested by the server */ Globals.lanman_auth = false; /* Do NOT use the LanMan hash, even if it is supplied */ Globals.ntlm_auth = true; /* Do use NTLMv1 if it is supplied by the client (otherwise NTLMv2) */ + Globals.raw_ntlmv2_auth = false; /* Reject NTLMv2 without NTLMSSP */ Globals.client_ntlmv2_auth = true; /* Client should always use use NTLMv2, as we can't tell that the server supports it, but most modern servers do */ /* Note, that we will also use NTLM2 session security (which is different), if it is available */ + Globals.allow_dcerpc_auth_level_connect = false; /* we don't allow this by default */ + Globals.map_to_guest = 0; /* By Default, "Never" */ Globals.oplock_break_wait_time = 0; /* By Default, 0 msecs. */ Globals.enhanced_browsing = true; @@ -710,6 +716,9 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.client_ldap_sasl_wrapping = ADS_AUTH_SASL_SIGN; + Globals.ldap_server_require_strong_auth = + LDAP_SERVER_REQUIRE_STRONG_AUTH_YES; + /* This is what we tell the afs client. in reality we set the token * to never expire, though, when this runs out the afs client will * forget the token. Set to 0 to get NEVERDATE.*/ @@ -785,6 +794,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.client_use_spnego = true; Globals.client_signing = SMB_SIGNING_DEFAULT; + Globals._client_ipc_signing = SMB_SIGNING_DEFAULT; Globals.server_signing = SMB_SIGNING_DEFAULT; Globals.defer_sharing_violations = true; @@ -832,10 +842,12 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.dcerpc_endpoint_servers = (const char **)str_list_make_v3(NULL, "epmapper wkssvc rpcecho samr netlogon lsarpc spoolss drsuapi dssetup unixinfo browser eventlog6 backupkey dnsserver", NULL); Globals.tls_enabled = true; + Globals.tls_verify_peer = TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE; lpcfg_string_set(Globals.ctx, &Globals._tls_keyfile, "tls/key.pem"); lpcfg_string_set(Globals.ctx, &Globals._tls_certfile, "tls/cert.pem"); lpcfg_string_set(Globals.ctx, &Globals._tls_cafile, "tls/ca.pem"); + lpcfg_string_set(Globals.ctx, &Globals.tls_priority, "NORMAL:-VERS-SSL3.0"); lpcfg_string_set(Globals.ctx, &Globals.share_backend, "classic"); @@ -4338,13 +4350,37 @@ int lp_client_max_protocol(void) return client_max_protocol; } -int lp_winbindd_max_protocol(void) +int lp_client_ipc_min_protocol(void) { - int client_max_protocol = lp__client_max_protocol(); - if (client_max_protocol == PROTOCOL_DEFAULT) { + int client_ipc_min_protocol = lp__client_ipc_min_protocol(); + if (client_ipc_min_protocol == PROTOCOL_DEFAULT) { + client_ipc_min_protocol = lp_client_min_protocol(); + } + if (client_ipc_min_protocol < PROTOCOL_NT1) { + return PROTOCOL_NT1; + } + return client_ipc_min_protocol; +} + +int lp_client_ipc_max_protocol(void) +{ + int client_ipc_max_protocol = lp__client_ipc_max_protocol(); + if (client_ipc_max_protocol == PROTOCOL_DEFAULT) { return PROTOCOL_LATEST; } - return client_max_protocol; + if (client_ipc_max_protocol < PROTOCOL_NT1) { + return PROTOCOL_NT1; + } + return client_ipc_max_protocol; +} + +int lp_client_ipc_signing(void) +{ + int client_ipc_signing = lp__client_ipc_signing(); + if (client_ipc_signing == SMB_SIGNING_DEFAULT) { + return SMB_SIGNING_REQUIRED; + } + return client_ipc_signing; } struct loadparm_global * get_globals(void) diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c index 974538b87bd..f50a5e92d03 100644 --- a/source3/rpc_client/cli_lsarpc.c +++ b/source3/rpc_client/cli_lsarpc.c @@ -81,7 +81,7 @@ NTSTATUS dcerpc_lsa_open_policy(struct dcerpc_binding_handle *h, NTSTATUS rpccli_lsa_open_policy(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, - bool sec_qos, uint32 des_access, + bool sec_qos, uint32_t des_access, struct policy_handle *pol) { NTSTATUS status; @@ -140,7 +140,7 @@ NTSTATUS dcerpc_lsa_open_policy2(struct dcerpc_binding_handle *h, NTSTATUS rpccli_lsa_open_policy2(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, bool sec_qos, - uint32 des_access, struct policy_handle *pol) + uint32_t des_access, struct policy_handle *pol) { NTSTATUS status; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; diff --git a/source3/rpc_client/cli_lsarpc.h b/source3/rpc_client/cli_lsarpc.h index 36afe0bdfb0..4f9464d5b05 100644 --- a/source3/rpc_client/cli_lsarpc.h +++ b/source3/rpc_client/cli_lsarpc.h @@ -54,7 +54,7 @@ NTSTATUS dcerpc_lsa_open_policy(struct dcerpc_binding_handle *h, NTSTATUS *result); NTSTATUS rpccli_lsa_open_policy(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, - bool sec_qos, uint32 des_access, + bool sec_qos, uint32_t des_access, struct policy_handle *pol); /** @@ -83,7 +83,7 @@ NTSTATUS dcerpc_lsa_open_policy2(struct dcerpc_binding_handle *h, NTSTATUS *result); NTSTATUS rpccli_lsa_open_policy2(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, bool sec_qos, - uint32 des_access, struct policy_handle *pol); + uint32_t des_access, struct policy_handle *pol); /** * @brief Look up the names that correspond to an array of sids. diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c index 7063351ef8a..9c727f7da31 100644 --- a/source3/rpc_client/cli_netlogon.c +++ b/source3/rpc_client/cli_netlogon.c @@ -312,7 +312,7 @@ NTSTATUS rpccli_netlogon_password_logon(struct netlogon_creds_cli_context *creds } case NetlogonNetworkInformation: { struct netr_NetworkInfo *network_info; - uint8 chal[8]; + uint8_t chal[8]; unsigned char local_lm_response[24]; unsigned char local_nt_response[24]; struct netr_ChallengeResponse lm; @@ -400,7 +400,7 @@ NTSTATUS rpccli_netlogon_network_logon(struct netlogon_creds_cli_context *creds, const char *username, const char *domain, const char *workstation, - const uint8 chal[8], + const uint8_t chal[8], DATA_BLOB lm_response, DATA_BLOB nt_response, uint8_t *authoritative, diff --git a/source3/rpc_client/cli_netlogon.h b/source3/rpc_client/cli_netlogon.h index fee08016d5d..0765dfac618 100644 --- a/source3/rpc_client/cli_netlogon.h +++ b/source3/rpc_client/cli_netlogon.h @@ -60,7 +60,7 @@ NTSTATUS rpccli_netlogon_network_logon(struct netlogon_creds_cli_context *creds, const char *username, const char *domain, const char *workstation, - const uint8 chal[8], + const uint8_t chal[8], DATA_BLOB lm_response, DATA_BLOB nt_response, uint8_t *authoritative, diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index 652a773ab51..cb01338c01e 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -56,9 +56,9 @@ static const char *rpccli_pipe_txt(TALLOC_CTX *mem_ctx, Rpc pipe call id. ********************************************************************/ -static uint32 get_rpc_call_id(void) +static uint32_t get_rpc_call_id(void) { - static uint32 call_id = 0; + static uint32_t call_id = 0; return ++call_id; } @@ -391,9 +391,9 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx, DATA_BLOB *rdata, DATA_BLOB *reply_pdu) { - struct dcerpc_response *r; + const struct dcerpc_response *r = NULL; + DATA_BLOB tmp_stub = data_blob_null; NTSTATUS ret = NT_STATUS_OK; - size_t pad_len = 0; /* * Point the return values at the real data including the RPC @@ -401,50 +401,128 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx, */ *rdata = *pdu; + if ((pkt->ptype == DCERPC_PKT_BIND_ACK) && + !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) { + /* + * TODO: do we still need this hack which was introduced + * in commit a42afcdcc7ab9aa9ed193ae36d3dbb10843447f0. + * + * I don't even know what AS/U might be... + */ + DEBUG(5, (__location__ ": bug in server (AS/U?), setting " + "fragment first/last ON.\n")); + pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; + } + /* Ensure we have the correct type. */ switch (pkt->ptype) { - case DCERPC_PKT_ALTER_RESP: + case DCERPC_PKT_BIND_NAK: + DEBUG(1, (__location__ ": Bind NACK received from %s!\n", + rpccli_pipe_txt(talloc_tos(), cli))); + + ret = dcerpc_verify_ncacn_packet_header(pkt, + DCERPC_PKT_BIND_NAK, + 0, /* max_auth_info */ + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST, + 0); /* optional flags */ + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(1, (__location__ ": Connection to %s got an unexpected " + "RPC packet type - %u, expected %u: %s\n", + rpccli_pipe_txt(talloc_tos(), cli), + pkt->ptype, expected_pkt_type, + nt_errstr(ret))); + NDR_PRINT_DEBUG(ncacn_packet, pkt); + return ret; + } + + /* Use this for now... */ + return NT_STATUS_NETWORK_ACCESS_DENIED; + case DCERPC_PKT_BIND_ACK: + ret = dcerpc_verify_ncacn_packet_header(pkt, + expected_pkt_type, + pkt->u.bind_ack.auth_info.length, + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST, + DCERPC_PFC_FLAG_CONC_MPX | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(1, (__location__ ": Connection to %s got an unexpected " + "RPC packet type - %u, expected %u: %s\n", + rpccli_pipe_txt(talloc_tos(), cli), + pkt->ptype, expected_pkt_type, + nt_errstr(ret))); + NDR_PRINT_DEBUG(ncacn_packet, pkt); + return ret; + } - /* Client code never receives this kind of packets */ break; + case DCERPC_PKT_ALTER_RESP: + ret = dcerpc_verify_ncacn_packet_header(pkt, + expected_pkt_type, + pkt->u.alter_resp.auth_info.length, + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST, + DCERPC_PFC_FLAG_CONC_MPX | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(1, (__location__ ": Connection to %s got an unexpected " + "RPC packet type - %u, expected %u: %s\n", + rpccli_pipe_txt(talloc_tos(), cli), + pkt->ptype, expected_pkt_type, + nt_errstr(ret))); + NDR_PRINT_DEBUG(ncacn_packet, pkt); + return ret; + } + + break; case DCERPC_PKT_RESPONSE: r = &pkt->u.response; + ret = dcerpc_verify_ncacn_packet_header(pkt, + expected_pkt_type, + r->stub_and_verifier.length, + 0, /* required_flags */ + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(1, (__location__ ": Connection to %s got an unexpected " + "RPC packet type - %u, expected %u: %s\n", + rpccli_pipe_txt(talloc_tos(), cli), + pkt->ptype, expected_pkt_type, + nt_errstr(ret))); + NDR_PRINT_DEBUG(ncacn_packet, pkt); + return ret; + } + + tmp_stub.data = r->stub_and_verifier.data; + tmp_stub.length = r->stub_and_verifier.length; + /* Here's where we deal with incoming sign/seal. */ ret = dcerpc_check_auth(cli->auth, pkt, - &r->stub_and_verifier, + &tmp_stub, DCERPC_RESPONSE_LENGTH, - pdu, &pad_len); + pdu); if (!NT_STATUS_IS_OK(ret)) { + DEBUG(1, (__location__ ": Connection to %s got an unexpected " + "RPC packet type - %u, expected %u: %s\n", + rpccli_pipe_txt(talloc_tos(), cli), + pkt->ptype, expected_pkt_type, + nt_errstr(ret))); + NDR_PRINT_DEBUG(ncacn_packet, pkt); return ret; } - if (pkt->frag_length < DCERPC_RESPONSE_LENGTH + pad_len) { - return NT_STATUS_BUFFER_TOO_SMALL; - } - /* Point the return values at the NDR data. */ - rdata->data = r->stub_and_verifier.data; - - if (pkt->auth_length) { - /* We've already done integer wrap tests in - * dcerpc_check_auth(). */ - rdata->length = r->stub_and_verifier.length - - pad_len - - DCERPC_AUTH_TRAILER_LENGTH - - pkt->auth_length; - } else { - rdata->length = r->stub_and_verifier.length; - } + *rdata = tmp_stub; - DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n", + DEBUG(10, ("Got pdu len %lu, data_len %lu\n", (long unsigned int)pdu->length, - (long unsigned int)rdata->length, - (unsigned int)pad_len)); + (long unsigned int)rdata->length)); /* * If this is the first reply, and the allocation hint is @@ -465,14 +543,24 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx, break; - case DCERPC_PKT_BIND_NAK: - DEBUG(1, (__location__ ": Bind NACK received from %s!\n", - rpccli_pipe_txt(talloc_tos(), cli))); - /* Use this for now... */ - return NT_STATUS_NETWORK_ACCESS_DENIED; - case DCERPC_PKT_FAULT: + ret = dcerpc_verify_ncacn_packet_header(pkt, + DCERPC_PKT_FAULT, + 0, /* max_auth_info */ + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST, + DCERPC_PFC_FLAG_DID_NOT_EXECUTE); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(1, (__location__ ": Connection to %s got an unexpected " + "RPC packet type - %u, expected %u: %s\n", + rpccli_pipe_txt(talloc_tos(), cli), + pkt->ptype, expected_pkt_type, + nt_errstr(ret))); + NDR_PRINT_DEBUG(ncacn_packet, pkt); + return ret; + } + DEBUG(1, (__location__ ": RPC fault code %s received " "from %s!\n", dcerpc_errstr(talloc_tos(), @@ -489,13 +577,6 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx, return NT_STATUS_RPC_PROTOCOL_ERROR; } - if (pkt->ptype != expected_pkt_type) { - DEBUG(3, (__location__ ": Connection to %s got an unexpected " - "RPC packet type - %u, not %u\n", - rpccli_pipe_txt(talloc_tos(), cli), - pkt->ptype, expected_pkt_type)); - return NT_STATUS_RPC_PROTOCOL_ERROR; - } if (pkt->call_id != call_id) { DEBUG(3, (__location__ ": Connection to %s got an unexpected " @@ -505,17 +586,6 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx, return NT_STATUS_RPC_PROTOCOL_ERROR; } - /* Do this just before return - we don't want to modify any rpc header - data before now as we may have needed to do cryptographic actions on - it before. */ - - if ((pkt->ptype == DCERPC_PKT_BIND_ACK) && - !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) { - DEBUG(5, (__location__ ": bug in server (AS/U?), setting " - "fragment first/last ON.\n")); - pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; - } - return NT_STATUS_OK; } @@ -866,6 +936,12 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq) state->pkt = talloc(state, struct ncacn_packet); if (!state->pkt) { + /* + * TODO: do a real async disconnect ... + * + * For now do it sync... + */ + TALLOC_FREE(state->cli->transport); tevent_req_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -875,18 +951,16 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq) state->pkt, !state->endianess); if (!NT_STATUS_IS_OK(status)) { + /* + * TODO: do a real async disconnect ... + * + * For now do it sync... + */ + TALLOC_FREE(state->cli->transport); tevent_req_nterror(req, status); return; } - if (state->incoming_frag.length != state->pkt->frag_length) { - DEBUG(5, ("Incorrect pdu length %u, expected %u\n", - (unsigned int)state->incoming_frag.length, - (unsigned int)state->pkt->frag_length)); - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - status = cli_pipe_validate_current_pdu(state, state->cli, state->pkt, &state->incoming_frag, @@ -900,6 +974,28 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq) (unsigned)state->reply_pdu_offset, nt_errstr(status))); + if (state->pkt->ptype != DCERPC_PKT_FAULT && !NT_STATUS_IS_OK(status)) { + /* + * TODO: do a real async disconnect ... + * + * For now do it sync... + */ + TALLOC_FREE(state->cli->transport); + } else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) { + /* + * TODO: do a real async disconnect ... + * + * For now do it sync... + */ + TALLOC_FREE(state->cli->transport); + } else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) { + /* + * TODO: do a real async disconnect ... + * + * For now do it sync... + */ + TALLOC_FREE(state->cli->transport); + } if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return; @@ -924,7 +1020,24 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq) "%s\n", state->endianess?"little":"big", state->pkt->drep[0]?"little":"big")); - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + /* + * TODO: do a real async disconnect ... + * + * For now do it sync... + */ + TALLOC_FREE(state->cli->transport); + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); + return; + } + + if (state->reply_pdu_offset + rdata.length > MAX_RPC_DATA_SIZE) { + /* + * TODO: do a real async disconnect ... + * + * For now do it sync... + */ + TALLOC_FREE(state->cli->transport); + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); return; } @@ -932,6 +1045,12 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq) if (state->reply_pdu.length < state->reply_pdu_offset + rdata.length) { if (!data_blob_realloc(NULL, &state->reply_pdu, state->reply_pdu_offset + rdata.length)) { + /* + * TODO: do a real async disconnect ... + * + * For now do it sync... + */ + TALLOC_FREE(state->cli->transport); tevent_req_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -960,6 +1079,14 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq) subreq = get_complete_frag_send(state, state->ev, state->cli, &state->incoming_frag); + if (subreq == NULL) { + /* + * TODO: do a real async disconnect ... + * + * For now do it sync... + */ + TALLOC_FREE(state->cli->transport); + } if (tevent_req_nomem(subreq, req)) { return; } @@ -1039,14 +1166,14 @@ static NTSTATUS create_generic_auth_rpc_bind_req(struct rpc_pipe_client *cli, static NTSTATUS create_bind_or_alt_ctx_internal(TALLOC_CTX *mem_ctx, enum dcerpc_pkt_type ptype, - uint32 rpc_call_id, + uint32_t rpc_call_id, const struct ndr_syntax_id *abstract, const struct ndr_syntax_id *transfer, const DATA_BLOB *auth_info, bool client_hdr_signing, DATA_BLOB *blob) { - uint16 auth_len = auth_info->length; + uint16_t auth_len = auth_info->length; NTSTATUS status; union dcerpc_payload u; struct dcerpc_ctx_list ctx_list; @@ -1093,7 +1220,7 @@ static NTSTATUS create_bind_or_alt_ctx_internal(TALLOC_CTX *mem_ctx, static NTSTATUS create_rpc_bind_req(TALLOC_CTX *mem_ctx, struct rpc_pipe_client *cli, struct pipe_auth_data *auth, - uint32 rpc_call_id, + uint32_t rpc_call_id, const struct ndr_syntax_id *abstract, const struct ndr_syntax_id *transfer, DATA_BLOB *rpc_out) @@ -1123,7 +1250,7 @@ static NTSTATUS create_rpc_bind_req(TALLOC_CTX *mem_ctx, auth->auth_type, auth->auth_level, 0, /* auth_pad_length */ - 1, /* auth_context_id */ + auth->auth_context_id, &auth_token, &auth_info); if (!NT_STATUS_IS_OK(ret)) { @@ -1628,9 +1755,8 @@ static bool check_bind_response(const struct dcerpc_bind_ack *r, static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx, struct rpc_pipe_client *cli, - uint32 rpc_call_id, - enum dcerpc_AuthType auth_type, - enum dcerpc_AuthLevel auth_level, + struct pipe_auth_data *auth, + uint32_t rpc_call_id, DATA_BLOB *pauth_blob, DATA_BLOB *rpc_out) { @@ -1640,10 +1766,10 @@ static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx, u.auth3._pad = 0; status = dcerpc_push_dcerpc_auth(mem_ctx, - auth_type, - auth_level, + auth->auth_type, + auth->auth_level, 0, /* auth_pad_length */ - 1, /* auth_context_id */ + auth->auth_context_id, pauth_blob, &u.auth3.auth_info); if (!NT_STATUS_IS_OK(status)) { @@ -1673,9 +1799,8 @@ static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx, ********************************************************************/ static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx, - enum dcerpc_AuthType auth_type, - enum dcerpc_AuthLevel auth_level, - uint32 rpc_call_id, + struct pipe_auth_data *auth, + uint32_t rpc_call_id, const struct ndr_syntax_id *abstract, const struct ndr_syntax_id *transfer, const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */ @@ -1685,10 +1810,10 @@ static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx, NTSTATUS status; status = dcerpc_push_dcerpc_auth(mem_ctx, - auth_type, - auth_level, + auth->auth_type, + auth->auth_level, 0, /* auth_pad_length */ - 1, /* auth_context_id */ + auth->auth_context_id, pauth_blob, &auth_info); if (!NT_STATUS_IS_OK(status)) { @@ -1826,23 +1951,44 @@ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq) return; default: - /* Paranoid lenght checks */ - if (pkt->frag_length < DCERPC_AUTH_TRAILER_LENGTH - + pkt->auth_length) { - tevent_req_nterror(req, - NT_STATUS_INFO_LENGTH_MISMATCH); + if (pkt->auth_length == 0) { + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); return; } + /* get auth credentials */ - status = dcerpc_pull_dcerpc_auth(talloc_tos(), - &pkt->u.bind_ack.auth_info, - &auth, false); + status = dcerpc_pull_auth_trailer(pkt, talloc_tos(), + &pkt->u.bind_ack.auth_info, + &auth, NULL, true); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to pull dcerpc auth: %s.\n", nt_errstr(status))); tevent_req_nterror(req, status); return; } + + if (auth.auth_type != pauth->auth_type) { + DEBUG(0, (__location__ " Auth type %u mismatch expected %u.\n", + auth.auth_type, pauth->auth_type)); + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); + return; + } + + if (auth.auth_level != pauth->auth_level) { + DEBUG(0, (__location__ " Auth level %u mismatch expected %u.\n", + auth.auth_level, pauth->auth_level)); + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); + return; + } + + if (auth.auth_context_id != pauth->auth_context_id) { + DEBUG(0, (__location__ " Auth context id %u mismatch expected %u.\n", + (unsigned)auth.auth_context_id, + (unsigned)pauth->auth_context_id)); + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); + return; + } + break; } @@ -1903,9 +2049,7 @@ static NTSTATUS rpc_bind_next_send(struct tevent_req *req, /* Now prepare the alter context pdu. */ data_blob_free(&state->rpc_out); - status = create_rpc_alter_context(state, - auth->auth_type, - auth->auth_level, + status = create_rpc_alter_context(state, auth, state->rpc_call_id, &state->cli->abstract_syntax, &state->cli->transfer_syntax, @@ -1938,10 +2082,8 @@ static NTSTATUS rpc_bind_finish_send(struct tevent_req *req, /* Now prepare the auth3 context pdu. */ data_blob_free(&state->rpc_out); - status = create_rpc_bind_auth3(state, state->cli, + status = create_rpc_bind_auth3(state, state->cli, auth, state->rpc_call_id, - auth->auth_type, - auth->auth_level, auth_token, &state->rpc_out); if (!NT_STATUS_IS_OK(status)) { @@ -2194,8 +2336,9 @@ static struct tevent_req *rpccli_bh_disconnect_send(TALLOC_CTX *mem_ctx, /* * TODO: do a real async disconnect ... * - * For now the caller needs to free rpc_cli + * For now we do it sync... */ + TALLOC_FREE(hs->rpc_cli->transport); hs->rpc_cli = NULL; tevent_req_done(req); @@ -2296,6 +2439,7 @@ NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx, result->auth_type = DCERPC_AUTH_TYPE_NONE; result->auth_level = DCERPC_AUTH_LEVEL_NONE; + result->auth_context_id = 0; status = auth_generic_client_prepare(result, &auth_generic_ctx); @@ -2356,6 +2500,7 @@ static NTSTATUS rpccli_generic_bind_data(TALLOC_CTX *mem_ctx, result->auth_type = auth_type; result->auth_level = auth_level; + result->auth_context_id = 1; status = auth_generic_client_prepare(result, &auth_generic_ctx); diff --git a/source3/rpc_client/rpc_client.h b/source3/rpc_client/rpc_client.h index 7c5ff0e8181..b033da6c3d7 100644 --- a/source3/rpc_client/rpc_client.h +++ b/source3/rpc_client/rpc_client.h @@ -44,8 +44,8 @@ struct rpc_pipe_client { char *desthost; char *srv_name_slash; - uint16 max_xmit_frag; - uint16 max_recv_frag; + uint16_t max_xmit_frag; + uint16_t max_recv_frag; struct pipe_auth_data *auth; }; diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index b487c31e872..932df1de7d6 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1573,6 +1573,7 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, case NetlogonNetworkTransitiveInformation: { const char *wksname = nt_workstation; + const char *workgroup = lp_workgroup(); status = make_auth_context_fixed(talloc_tos(), &auth_context, logon->network->challenge); @@ -1599,6 +1600,14 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, logon->network->nt.length)) { status = NT_STATUS_NO_MEMORY; } + + if (NT_STATUS_IS_OK(status)) { + status = NTLMv2_RESPONSE_verify_netlogon_creds( + user_info->client.account_name, + user_info->client.domain_name, + user_info->password.response.nt, + creds, workgroup); + } break; } case NetlogonInteractiveInformation: @@ -1707,6 +1716,14 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, r->out.validation->sam3); break; case 6: + /* Only allow this if the pipe is protected. */ + if (p->auth.auth_level < DCERPC_AUTH_LEVEL_PRIVACY) { + DEBUG(0,("netr_Validation6: client %s not using privacy for netlogon\n", + get_remote_machine_name())); + status = NT_STATUS_INVALID_PARAMETER; + break; + } + status = serverinfo_to_SamInfo6(server_info, r->out.validation->sam6); break; @@ -2456,22 +2473,16 @@ NTSTATUS _netr_GetForestTrustInformation(struct pipes_struct *p, NTSTATUS status; struct netlogon_creds_CredentialState *creds; struct lsa_ForestTrustInformation *info, **info_ptr; - struct loadparm_context *lp_ctx; /* TODO: check server name */ - lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers()); - if (lp_ctx == NULL) { - DEBUG(0, ("loadparm_init_s3 failed\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - status = schannel_check_creds_state(p->mem_ctx, lp_ctx, - r->in.computer_name, - r->in.credential, - r->out.return_authenticator, - &creds); - talloc_unlink(p->mem_ctx, lp_ctx); + become_root(); + status = netr_creds_server_step_check(p, p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); + unbecome_root(); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -2558,22 +2569,16 @@ NTSTATUS _netr_ServerGetTrustInfo(struct pipes_struct *p, bool trusted; struct netr_TrustInfo *trust_info; struct pdb_trusted_domain *td; - struct loadparm_context *lp_ctx; - - lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers()); - if (lp_ctx == NULL) { - DEBUG(0, ("loadparm_init_s3 failed\n")); - return NT_STATUS_INTERNAL_ERROR; - } /* TODO: check server name */ - status = schannel_check_creds_state(p->mem_ctx, lp_ctx, - r->in.computer_name, - r->in.credential, - r->out.return_authenticator, - &creds); - talloc_unlink(p->mem_ctx, lp_ctx); + become_root(); + status = netr_creds_server_step_check(p, p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); + unbecome_root(); if (!NT_STATUS_IS_OK(status)) { return status; } diff --git a/source3/rpc_server/rpc_handles.c b/source3/rpc_server/rpc_handles.c index 3542acca106..62b545c55c9 100644 --- a/source3/rpc_server/rpc_handles.c +++ b/source3/rpc_server/rpc_handles.c @@ -69,6 +69,7 @@ int make_base_pipes_struct(TALLOC_CTX *mem_ctx, p->msg_ctx = msg_ctx; p->transport = transport; p->endian = endian; + p->allow_bind = true; p->remote_address = tsocket_address_copy(remote_address, p); if (p->remote_address == NULL) { @@ -253,8 +254,8 @@ static struct dcesrv_handle *create_rpc_handle_internal(struct pipes_struct *p, struct policy_handle *hnd, void *data_ptr) { struct dcesrv_handle *rpc_hnd; - static uint32 pol_hnd_low = 0; - static uint32 pol_hnd_high = 0; + static uint32_t pol_hnd_low = 0; + static uint32_t pol_hnd_high = 0; time_t t = time(NULL); if (p->pipe_handles->count > MAX_OPEN_POLS) { @@ -336,7 +337,7 @@ static struct dcesrv_handle *find_policy_by_hnd_internal(struct pipes_struct *p, for (h = p->pipe_handles->handles; h != NULL; h = h->next) { if (memcmp(&h->wire_handle, hnd, sizeof(*hnd)) == 0) { DEBUG(6,("Found policy hnd[%u] ", count)); - dump_data(6, (const uint8 *)hnd, sizeof(*hnd)); + dump_data(6, (const uint8_t *)hnd, sizeof(*hnd)); if (data_p) { *data_p = h->data; } diff --git a/source3/rpc_server/rpc_ncacn_np.c b/source3/rpc_server/rpc_ncacn_np.c index d504847b434..5647596f559 100644 --- a/source3/rpc_server/rpc_ncacn_np.c +++ b/source3/rpc_server/rpc_ncacn_np.c @@ -224,7 +224,7 @@ struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx, return NULL; } - context_fns = talloc(p, struct pipe_rpc_fns); + context_fns = talloc_zero(p, struct pipe_rpc_fns); if (context_fns == NULL) { DEBUG(0,("talloc() failed!\n")); TALLOC_FREE(p); @@ -977,6 +977,7 @@ static NTSTATUS rpc_pipe_open_external(TALLOC_CTX *mem_ctx, } result->auth->auth_type = DCERPC_AUTH_TYPE_NONE; result->auth->auth_level = DCERPC_AUTH_LEVEL_NONE; + result->auth->auth_context_id = 0; status = rpccli_anon_bind_data(result, &auth); if (!NT_STATUS_IS_OK(status)) { diff --git a/source3/rpc_server/rpc_pipes.h b/source3/rpc_server/rpc_pipes.h index e65209aefc0..d44ee92bd5c 100644 --- a/source3/rpc_server/rpc_pipes.h +++ b/source3/rpc_server/rpc_pipes.h @@ -94,6 +94,10 @@ struct pipe_rpc_fns { uint32_t context_id; struct ndr_syntax_id syntax; + /* + * shall we allow "connect" auth level for this interface ? + */ + bool allow_connect; }; /* @@ -127,6 +131,13 @@ struct pipes_struct { bool pipe_bound; /* + * States we can be in. + */ + bool allow_alter; + bool allow_bind; + bool allow_auth3; + + /* * Set the DCERPC_FAULT to return. */ int fault_state; diff --git a/source3/rpc_server/rpc_server.c b/source3/rpc_server/rpc_server.c index 01a854ccafa..5effe66d9bb 100644 --- a/source3/rpc_server/rpc_server.c +++ b/source3/rpc_server/rpc_server.c @@ -558,6 +558,12 @@ static void named_pipe_packet_done(struct tevent_req *subreq) return; } + if (npc->p->fault_state != 0) { + DEBUG(2, ("Disconnect after fault\n")); + sys_errno = EINVAL; + goto fail; + } + /* clear out any data that may have been left around */ npc->count = 0; TALLOC_FREE(npc->iov); @@ -1292,6 +1298,12 @@ static void dcerpc_ncacn_packet_done(struct tevent_req *subreq) goto fail; } + if (ncacn_conn->p->fault_state != 0) { + DEBUG(2, ("Disconnect after fault\n")); + sys_errno = EINVAL; + goto fail; + } + /* clear out any data that may have been left around */ ncacn_conn->count = 0; TALLOC_FREE(ncacn_conn->iov); diff --git a/source3/rpc_server/samr/srv_samr_nt.c b/source3/rpc_server/samr/srv_samr_nt.c index 76703d1389c..259b0dd1a9f 100644 --- a/source3/rpc_server/samr/srv_samr_nt.c +++ b/source3/rpc_server/samr/srv_samr_nt.c @@ -5097,7 +5097,7 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, case 18: status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); if(!NT_STATUS_IS_OK(status)) { - return status; + break; } /* Used by AS/U JRA. */ status = set_user_info_18(&info->info18, @@ -5114,7 +5114,7 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, case 21: status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); if(!NT_STATUS_IS_OK(status)) { - return status; + break; } status = set_user_info_21(&info->info21, p->mem_ctx, @@ -5124,6 +5124,9 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, case 23: status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); + if(!NT_STATUS_IS_OK(status)) { + break; + } arcfour_crypt_blob(info->info23.password.data, 516, &session_key); @@ -5137,6 +5140,9 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, case 24: status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); + if(!NT_STATUS_IS_OK(status)) { + break; + } arcfour_crypt_blob(info->info24.password.data, 516, &session_key); @@ -5150,6 +5156,9 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, case 25: status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); + if(!NT_STATUS_IS_OK(status)) { + break; + } encode_or_decode_arc4_passwd_buffer( info->info25.password.data, &session_key); @@ -5163,6 +5172,9 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, case 26: status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); + if(!NT_STATUS_IS_OK(status)) { + break; + } encode_or_decode_arc4_passwd_buffer( info->info26.password.data, &session_key); @@ -6734,6 +6746,11 @@ NTSTATUS _samr_ValidatePassword(struct pipes_struct *p, return NT_STATUS_ACCESS_DENIED; } + if (p->auth.auth_level != DCERPC_AUTH_LEVEL_PRIVACY) { + p->fault_state = DCERPC_FAULT_ACCESS_DENIED; + return NT_STATUS_ACCESS_DENIED; + } + if (r->in.level < 1 || r->in.level > 3) { return NT_STATUS_INVALID_INFO_CLASS; } diff --git a/source3/rpc_server/srv_access_check.c b/source3/rpc_server/srv_access_check.c index 878e38b1923..bb638251ba5 100644 --- a/source3/rpc_server/srv_access_check.c +++ b/source3/rpc_server/srv_access_check.c @@ -47,12 +47,12 @@ NTSTATUS access_check_object( struct security_descriptor *psd, struct security_token *token, enum sec_privilege needed_priv_1, enum sec_privilege needed_priv_2, - uint32 rights_mask, - uint32 des_access, uint32 *acc_granted, + uint32_t rights_mask, + uint32_t des_access, uint32 *acc_granted, const char *debug ) { NTSTATUS status = NT_STATUS_ACCESS_DENIED; - uint32 saved_mask = 0; + uint32_t saved_mask = 0; bool priv_granted = false; bool is_system = false; bool is_root = false; diff --git a/source3/rpc_server/srv_access_check.h b/source3/rpc_server/srv_access_check.h index 72ce539568e..0e161689a86 100644 --- a/source3/rpc_server/srv_access_check.h +++ b/source3/rpc_server/srv_access_check.h @@ -34,8 +34,8 @@ NTSTATUS access_check_object( struct security_descriptor *psd, struct security_token *token, enum sec_privilege needed_priv_1, enum sec_privilege needed_priv_2, - uint32 rights_mask, - uint32 des_access, uint32 *acc_granted, + uint32_t rights_mask, + uint32_t des_access, uint32 *acc_granted, const char *debug ); void map_max_allowed_access(const struct security_token *nt_token, const struct security_unix_token *unix_token, diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index 77200f8fed1..bcd7e5db6c2 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -30,7 +30,7 @@ #include "includes.h" #include "system/filesys.h" #include "srv_pipe_internal.h" -#include "../librpc/gen_ndr/dcerpc.h" +#include "../librpc/gen_ndr/ndr_dcerpc.h" #include "../librpc/rpc/rpc_common.h" #include "dcesrv_auth_generic.h" #include "rpc_server.h" @@ -44,6 +44,12 @@ #include "librpc/ndr/ndr_table.h" #include "auth/gensec/gensec.h" #include "librpc/ndr/ndr_dcerpc.h" +#include "lib/tsocket/tsocket.h" +#include "../librpc/gen_ndr/ndr_samr.h" +#include "../librpc/gen_ndr/ndr_lsa.h" +#include "../librpc/gen_ndr/ndr_netlogon.h" +#include "../librpc/gen_ndr/ndr_epmapper.h" +#include "../librpc/gen_ndr/ndr_echo.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_SRV @@ -272,10 +278,14 @@ static bool setup_bind_nak(struct pipes_struct *p, struct ncacn_packet *pkt) p->out_data.data_sent_length = 0; p->out_data.current_pdu_sent = 0; + set_incoming_fault(p); TALLOC_FREE(p->auth.auth_ctx); p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE; p->auth.auth_type = DCERPC_AUTH_TYPE_NONE; p->pipe_bound = False; + p->allow_bind = false; + p->allow_alter = false; + p->allow_auth3 = false; return True; } @@ -338,39 +348,118 @@ static bool check_bind_req(struct pipes_struct *p, { struct pipe_rpc_fns *context_fns; bool ok; + const char *interface_name = NULL; - DEBUG(3,("check_bind_req for %s\n", + DEBUG(3,("check_bind_req for %s context_id=%u\n", ndr_interface_name(&abstract->uuid, - abstract->if_version))); + abstract->if_version), + (unsigned)context_id)); + + ok = ndr_syntax_id_equal(transfer, &ndr_transfer_syntax_ndr); + if (!ok) { + DEBUG(1,("check_bind_req unknown transfer syntax for " + "%s context_id=%u\n", + ndr_interface_name(&abstract->uuid, + abstract->if_version), + (unsigned)context_id)); + return false; + } + + for (context_fns = p->contexts; + context_fns != NULL; + context_fns = context_fns->next) + { + if (context_fns->context_id != context_id) { + continue; + } + + ok = ndr_syntax_id_equal(&context_fns->syntax, + abstract); + if (ok) { + return true; + } + + DEBUG(1,("check_bind_req: changing abstract syntax for " + "%s context_id=%u into %s not supported\n", + ndr_interface_name(&context_fns->syntax.uuid, + context_fns->syntax.if_version), + (unsigned)context_id, + ndr_interface_name(&abstract->uuid, + abstract->if_version))); + return false; + } /* we have to check all now since win2k introduced a new UUID on the lsaprpc pipe */ - if (rpc_srv_pipe_exists_by_id(abstract) && - ndr_syntax_id_equal(transfer, &ndr_transfer_syntax_ndr)) { - DEBUG(3, ("check_bind_req: %s -> %s rpc service\n", - rpc_srv_get_pipe_cli_name(abstract), - rpc_srv_get_pipe_srv_name(abstract))); - } else { + if (!rpc_srv_pipe_exists_by_id(abstract)) { return false; } + DEBUG(3, ("check_bind_req: %s -> %s rpc service\n", + rpc_srv_get_pipe_cli_name(abstract), + rpc_srv_get_pipe_srv_name(abstract))); + ok = init_pipe_handles(p, abstract); if (!ok) { DEBUG(1, ("Failed to init pipe handles!\n")); return false; } - context_fns = talloc(p, struct pipe_rpc_fns); + context_fns = talloc_zero(p, struct pipe_rpc_fns); if (context_fns == NULL) { DEBUG(0,("check_bind_req: talloc() failed!\n")); return false; } + interface_name = ndr_interface_name(&abstract->uuid, + abstract->if_version); + SMB_ASSERT(interface_name != NULL); + context_fns->next = context_fns->prev = NULL; context_fns->n_cmds = rpc_srv_get_pipe_num_cmds(abstract); context_fns->cmds = rpc_srv_get_pipe_cmds(abstract); context_fns->context_id = context_id; context_fns->syntax = *abstract; + context_fns->allow_connect = lp_allow_dcerpc_auth_level_connect(); + /* + * for the samr, lsarpc and netlogon interfaces we don't allow "connect" + * auth_level by default. + */ + ok = ndr_syntax_id_equal(abstract, &ndr_table_samr.syntax_id); + if (ok) { + context_fns->allow_connect = false; + } + ok = ndr_syntax_id_equal(abstract, &ndr_table_lsarpc.syntax_id); + if (ok) { + context_fns->allow_connect = false; + } + ok = ndr_syntax_id_equal(abstract, &ndr_table_netlogon.syntax_id); + if (ok) { + context_fns->allow_connect = false; + } + /* + * for the epmapper and echo interfaces we allow "connect" + * auth_level by default. + */ + ok = ndr_syntax_id_equal(abstract, &ndr_table_epmapper.syntax_id); + if (ok) { + context_fns->allow_connect = true; + } + ok = ndr_syntax_id_equal(abstract, &ndr_table_rpcecho.syntax_id); + if (ok) { + context_fns->allow_connect = true; + } + /* + * every interface can be modified to allow "connect" auth_level by + * using a parametric option like: + * allow dcerpc auth level connect:<interface> + * e.g. + * allow dcerpc auth level connect:samr = yes + */ + context_fns->allow_connect = lp_parm_bool(-1, + "allow dcerpc auth level connect", + interface_name, context_fns->allow_connect); + /* add to the list of open contexts */ DLIST_ADD( p->contexts, context_fns ); @@ -449,6 +538,8 @@ static bool pipe_auth_generic_bind(struct pipes_struct *p, p->auth.auth_ctx = gensec_security; p->auth.auth_type = auth_info->auth_type; + p->auth.auth_level = auth_info->auth_level; + p->auth.auth_context_id = auth_info->auth_context_id; if (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) { p->auth.client_hdr_signing = true; @@ -573,9 +664,8 @@ static NTSTATUS pipe_auth_verify_final(struct pipes_struct *p) static bool api_pipe_bind_req(struct pipes_struct *p, struct ncacn_packet *pkt) { - struct dcerpc_auth auth_info; - uint16 assoc_gid; - unsigned int auth_type = DCERPC_AUTH_TYPE_NONE; + struct dcerpc_auth auth_info = {0}; + uint16_t assoc_gid; NTSTATUS status; struct ndr_syntax_id id; uint8_t pfc_flags = 0; @@ -585,14 +675,38 @@ static bool api_pipe_bind_req(struct pipes_struct *p, DATA_BLOB auth_blob = data_blob_null; const struct ndr_interface_table *table; - /* No rebinds on a bound pipe - use alter context. */ - if (p->pipe_bound) { - DEBUG(2,("Rejecting bind request on bound rpc connection\n")); + if (!p->allow_bind) { + DEBUG(2,("Pipe not in allow bind state\n")); return setup_bind_nak(p, pkt); } + p->allow_bind = false; + + status = dcerpc_verify_ncacn_packet_header(pkt, + DCERPC_PKT_BIND, + pkt->u.bind.auth_info.length, + 0, /* required flags */ + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN | + 0x08 | /* this is not defined, but should be ignored */ + DCERPC_PFC_FLAG_CONC_MPX | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE | + DCERPC_PFC_FLAG_MAYBE | + DCERPC_PFC_FLAG_OBJECT_UUID); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("api_pipe_bind_req: invalid pdu: %s\n", + nt_errstr(status))); + NDR_PRINT_DEBUG(ncacn_packet, pkt); + goto err_exit; + } if (pkt->u.bind.num_contexts == 0) { - DEBUG(0, ("api_pipe_bind_req: no rpc contexts around\n")); + DEBUG(1, ("api_pipe_bind_req: no rpc contexts around\n")); + goto err_exit; + } + + if (pkt->u.bind.ctx_list[0].num_transfer_syntaxes == 0) { + DEBUG(1, ("api_pipe_bind_req: no transfer syntaxes around\n")); goto err_exit; } @@ -671,7 +785,6 @@ static bool api_pipe_bind_req(struct pipes_struct *p, bind_ack_ctx.reason.value = 0; bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0]; } else { - p->pipe_bound = False; /* Rejection reason: abstract syntax not supported */ bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT; bind_ack_ctx.reason.value = DCERPC_BIND_REASON_ASYNTAX; @@ -682,71 +795,25 @@ static bool api_pipe_bind_req(struct pipes_struct *p, * Check if this is an authenticated bind request. */ if (pkt->auth_length) { - /* Quick length check. Won't catch a bad auth footer, - * prevents overrun. */ - - if (pkt->frag_length < RPC_HEADER_LEN + - DCERPC_AUTH_TRAILER_LENGTH + - pkt->auth_length) { - DEBUG(0,("api_pipe_bind_req: auth_len (%u) " - "too long for fragment %u.\n", - (unsigned int)pkt->auth_length, - (unsigned int)pkt->frag_length)); - goto err_exit; - } - /* * Decode the authentication verifier. */ - status = dcerpc_pull_dcerpc_auth(pkt, - &pkt->u.bind.auth_info, - &auth_info, p->endian); + status = dcerpc_pull_auth_trailer(pkt, pkt, + &pkt->u.bind.auth_info, + &auth_info, NULL, true); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n")); goto err_exit; } - auth_type = auth_info.auth_type; - - /* Work out if we have to sign or seal etc. */ - switch (auth_info.auth_level) { - case DCERPC_AUTH_LEVEL_INTEGRITY: - p->auth.auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; - break; - case DCERPC_AUTH_LEVEL_PRIVACY: - p->auth.auth_level = DCERPC_AUTH_LEVEL_PRIVACY; - break; - case DCERPC_AUTH_LEVEL_CONNECT: - p->auth.auth_level = DCERPC_AUTH_LEVEL_CONNECT; - break; - default: - DEBUG(0, ("Unexpected auth level (%u).\n", - (unsigned int)auth_info.auth_level )); + if (!pipe_auth_generic_bind(p, pkt, + &auth_info, &auth_resp)) { goto err_exit; } - - switch (auth_type) { - case DCERPC_AUTH_TYPE_NONE: - break; - - default: - if (!pipe_auth_generic_bind(p, pkt, - &auth_info, &auth_resp)) { - goto err_exit; - } - break; - } - } - - if (auth_type == DCERPC_AUTH_TYPE_NONE) { - /* Unauthenticated bind request. */ - /* We're finished - no more packets. */ + } else { p->auth.auth_type = DCERPC_AUTH_TYPE_NONE; - /* We must set the pipe auth_level here also. */ p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE; - p->pipe_bound = True; - /* The session key was initialized from the SMB - * session in make_internal_rpc_pipe_p */ + p->auth.auth_context_id = 0; } ZERO_STRUCT(u.bind_ack); @@ -793,15 +860,15 @@ static bool api_pipe_bind_req(struct pipes_struct *p, if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n", nt_errstr(status))); + goto err_exit; } if (auth_resp.length) { - status = dcerpc_push_dcerpc_auth(pkt, - auth_type, - auth_info.auth_level, - 0, - 1, /* auth_context_id */ + p->auth.auth_type, + p->auth.auth_level, + 0, /* pad_len */ + p->auth.auth_context_id, &auth_resp, &auth_blob); if (!NT_STATUS_IS_OK(status)) { @@ -832,6 +899,22 @@ static bool api_pipe_bind_req(struct pipes_struct *p, p->out_data.current_pdu_sent = 0; TALLOC_FREE(auth_blob.data); + + if (bind_ack_ctx.result == 0) { + p->allow_alter = true; + p->allow_auth3 = true; + if (p->auth.auth_type == DCERPC_AUTH_TYPE_NONE) { + status = pipe_auth_verify_final(p); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("pipe_auth_verify_final failed: %s\n", + nt_errstr(status))); + goto err_exit; + } + } + } else { + goto err_exit; + } + return True; err_exit: @@ -854,18 +937,39 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt) DEBUG(5, ("api_pipe_bind_auth3: decode request. %d\n", __LINE__)); - if (pkt->auth_length == 0) { - DEBUG(1, ("No auth field sent for bind request!\n")); + if (!p->allow_auth3) { + DEBUG(1, ("Pipe not in allow auth3 state.\n")); + goto err; + } + + status = dcerpc_verify_ncacn_packet_header(pkt, + DCERPC_PKT_AUTH3, + pkt->u.auth3.auth_info.length, + 0, /* required flags */ + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN | + 0x08 | /* this is not defined, but should be ignored */ + DCERPC_PFC_FLAG_CONC_MPX | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE | + DCERPC_PFC_FLAG_MAYBE | + DCERPC_PFC_FLAG_OBJECT_UUID); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("api_pipe_bind_auth3: invalid pdu: %s\n", + nt_errstr(status))); + NDR_PRINT_DEBUG(ncacn_packet, pkt); + goto err; + } + + /* We can only finish if the pipe is unbound for now */ + if (p->pipe_bound) { + DEBUG(0, (__location__ ": Pipe already bound, " + "AUTH3 not supported!\n")); goto err; } - /* Ensure there's enough data for an authenticated request. */ - if (pkt->frag_length < RPC_HEADER_LEN - + DCERPC_AUTH_TRAILER_LENGTH - + pkt->auth_length) { - DEBUG(1,("api_pipe_ntlmssp_auth_process: auth_len " - "%u is too large.\n", - (unsigned int)pkt->auth_length)); + if (pkt->auth_length == 0) { + DEBUG(1, ("No auth field sent for auth3 request!\n")); goto err; } @@ -873,9 +977,9 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt) * Decode the authentication verifier response. */ - status = dcerpc_pull_dcerpc_auth(pkt, - &pkt->u.auth3.auth_info, - &auth_info, p->endian); + status = dcerpc_pull_auth_trailer(pkt, pkt, + &pkt->u.auth3.auth_info, + &auth_info, NULL, true); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to unmarshall dcerpc_auth.\n")); goto err; @@ -893,6 +997,21 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt) goto err; } + if (auth_info.auth_level != p->auth.auth_level) { + DEBUG(1, ("Auth level mismatch! Client sent %d, " + "but auth was started as level %d!\n", + auth_info.auth_level, p->auth.auth_level)); + goto err; + } + + if (auth_info.auth_context_id != p->auth.auth_context_id) { + DEBUG(0, ("Auth context id mismatch! Client sent %u, " + "but auth was started as level %u!\n", + (unsigned)auth_info.auth_context_id, + (unsigned)p->auth.auth_context_id)); + goto err; + } + gensec_security = p->auth.auth_ctx; status = auth_generic_server_step(gensec_security, @@ -923,6 +1042,10 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt) return true; err: + p->pipe_bound = false; + p->allow_bind = false; + p->allow_alter = false; + p->allow_auth3 = false; TALLOC_FREE(p->auth.auth_ctx); return false; @@ -936,19 +1059,53 @@ err: static bool api_pipe_alter_context(struct pipes_struct *p, struct ncacn_packet *pkt) { - struct dcerpc_auth auth_info; - uint16 assoc_gid; + struct dcerpc_auth auth_info = {0}; + uint16_t assoc_gid; NTSTATUS status; union dcerpc_payload u; - struct dcerpc_ack_ctx bind_ack_ctx; + struct dcerpc_ack_ctx alter_ack_ctx; DATA_BLOB auth_resp = data_blob_null; DATA_BLOB auth_blob = data_blob_null; struct gensec_security *gensec_security; DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__)); - if (pkt->u.bind.assoc_group_id != 0) { - assoc_gid = pkt->u.bind.assoc_group_id; + if (!p->allow_alter) { + DEBUG(1, ("Pipe not in allow alter state.\n")); + goto err_exit; + } + + status = dcerpc_verify_ncacn_packet_header(pkt, + DCERPC_PKT_ALTER, + pkt->u.alter.auth_info.length, + 0, /* required flags */ + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN | + 0x08 | /* this is not defined, but should be ignored */ + DCERPC_PFC_FLAG_CONC_MPX | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE | + DCERPC_PFC_FLAG_MAYBE | + DCERPC_PFC_FLAG_OBJECT_UUID); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("api_pipe_alter_context: invalid pdu: %s\n", + nt_errstr(status))); + NDR_PRINT_DEBUG(ncacn_packet, pkt); + goto err_exit; + } + + if (pkt->u.alter.num_contexts == 0) { + DEBUG(1, ("api_pipe_alter_context: no rpc contexts around\n")); + goto err_exit; + } + + if (pkt->u.alter.ctx_list[0].num_transfer_syntaxes == 0) { + DEBUG(1, ("api_pipe_alter_context: no transfer syntaxes around\n")); + goto err_exit; + } + + if (pkt->u.alter.assoc_group_id != 0) { + assoc_gid = pkt->u.alter.assoc_group_id; } else { assoc_gid = 0x53f0; } @@ -958,59 +1115,45 @@ static bool api_pipe_alter_context(struct pipes_struct *p, */ /* If the requested abstract synt uuid doesn't match our client pipe, - reject the bind_ack & set the transfer interface synt to all 0's, + reject the alter_ack & set the transfer interface synt to all 0's, ver 0 (observed when NT5 attempts to bind to abstract interfaces unknown to NT4) Needed when adding entries to a DACL from NT5 - SK */ if (check_bind_req(p, - &pkt->u.bind.ctx_list[0].abstract_syntax, - &pkt->u.bind.ctx_list[0].transfer_syntaxes[0], - pkt->u.bind.ctx_list[0].context_id)) { + &pkt->u.alter.ctx_list[0].abstract_syntax, + &pkt->u.alter.ctx_list[0].transfer_syntaxes[0], + pkt->u.alter.ctx_list[0].context_id)) { - bind_ack_ctx.result = 0; - bind_ack_ctx.reason.value = 0; - bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0]; + alter_ack_ctx.result = 0; + alter_ack_ctx.reason.value = 0; + alter_ack_ctx.syntax = pkt->u.alter.ctx_list[0].transfer_syntaxes[0]; } else { - p->pipe_bound = False; /* Rejection reason: abstract syntax not supported */ - bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT; - bind_ack_ctx.reason.value = DCERPC_BIND_REASON_ASYNTAX; - bind_ack_ctx.syntax = ndr_syntax_id_null; + alter_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT; + alter_ack_ctx.reason.value = DCERPC_BIND_REASON_ASYNTAX; + alter_ack_ctx.syntax = ndr_syntax_id_null; } /* * Check if this is an authenticated alter context request. */ if (pkt->auth_length) { - /* Quick length check. Won't catch a bad auth footer, - * prevents overrun. */ - - if (pkt->frag_length < RPC_HEADER_LEN + - DCERPC_AUTH_TRAILER_LENGTH + - pkt->auth_length) { - DEBUG(0,("api_pipe_alter_context: auth_len (%u) " - "too long for fragment %u.\n", - (unsigned int)pkt->auth_length, - (unsigned int)pkt->frag_length )); + /* We can only finish if the pipe is unbound for now */ + if (p->pipe_bound) { + DEBUG(0, (__location__ ": Pipe already bound, " + "Altering Context not yet supported!\n")); goto err_exit; } - status = dcerpc_pull_dcerpc_auth(pkt, - &pkt->u.bind.auth_info, - &auth_info, p->endian); + status = dcerpc_pull_auth_trailer(pkt, pkt, + &pkt->u.alter.auth_info, + &auth_info, NULL, true); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n")); goto err_exit; } - /* We can only finish if the pipe is unbound for now */ - if (p->pipe_bound) { - DEBUG(0, (__location__ ": Pipe already bound, " - "Altering Context not yet supported!\n")); - goto err_exit; - } - if (auth_info.auth_type != p->auth.auth_type) { DEBUG(0, ("Auth type mismatch! Client sent %d, " "but auth was started as type %d!\n", @@ -1018,6 +1161,21 @@ static bool api_pipe_alter_context(struct pipes_struct *p, goto err_exit; } + if (auth_info.auth_level != p->auth.auth_level) { + DEBUG(0, ("Auth level mismatch! Client sent %d, " + "but auth was started as level %d!\n", + auth_info.auth_level, p->auth.auth_level)); + goto err_exit; + } + + if (auth_info.auth_context_id != p->auth.auth_context_id) { + DEBUG(0, ("Auth context id mismatch! Client sent %u, " + "but auth was started as level %u!\n", + (unsigned)auth_info.auth_context_id, + (unsigned)p->auth.auth_context_id)); + goto err_exit; + } + gensec_security = p->auth.auth_ctx; status = auth_generic_server_step(gensec_security, pkt, @@ -1054,7 +1212,7 @@ static bool api_pipe_alter_context(struct pipes_struct *p, u.alter_resp.secondary_address_size = 1; u.alter_resp.num_results = 1; - u.alter_resp.ctx_list = &bind_ack_ctx; + u.alter_resp.ctx_list = &alter_ack_ctx; /* NOTE: We leave the auth_info empty so we can calculate the padding * later and then append the auth_info --simo */ @@ -1074,16 +1232,17 @@ static bool api_pipe_alter_context(struct pipes_struct *p, &u, &p->out_data.frag); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n", + DEBUG(0, ("Failed to marshall alter_resp packet. (%s)\n", nt_errstr(status))); + goto err_exit; } if (auth_resp.length) { status = dcerpc_push_dcerpc_auth(pkt, - auth_info.auth_type, - auth_info.auth_level, + p->auth.auth_type, + p->auth.auth_level, 0, /* pad_len */ - 1, /* auth_context_id */ + p->auth.auth_context_id, &auth_resp, &auth_blob); if (!NT_STATUS_IS_OK(status)) { @@ -1174,6 +1333,7 @@ static bool api_pipe_request(struct pipes_struct *p, TALLOC_CTX *frame = talloc_stackframe(); bool ret = False; struct pipe_rpc_fns *pipe_fns; + const char *interface_name = NULL; if (!p->pipe_bound) { DEBUG(1, ("Pipe not bound!\n")); @@ -1194,8 +1354,40 @@ static bool api_pipe_request(struct pipes_struct *p, return false; } + interface_name = ndr_interface_name(&pipe_fns->syntax.uuid, + pipe_fns->syntax.if_version); + SMB_ASSERT(interface_name != NULL); + + switch (p->auth.auth_level) { + case DCERPC_AUTH_LEVEL_NONE: + case DCERPC_AUTH_LEVEL_INTEGRITY: + case DCERPC_AUTH_LEVEL_PRIVACY: + break; + default: + if (!pipe_fns->allow_connect) { + char *addr; + + addr = tsocket_address_string(p->remote_address, frame); + + DEBUG(1, ("%s: restrict auth_level_connect access " + "to [%s] with auth[type=0x%x,level=0x%x] " + "on [%s] from [%s]\n", + __func__, interface_name, + p->auth.auth_type, + p->auth.auth_level, + derpc_transport_string_by_transport(p->transport), + addr)); + + setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED)); + TALLOC_FREE(frame); + return true; + } + break; + } + if (!srv_pipe_check_verification_trailer(p, pkt, pipe_fns)) { DEBUG(1, ("srv_pipe_check_verification_trailer: failed\n")); + set_incoming_fault(p); setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED)); data_blob_free(&p->out_data.rdata); TALLOC_FREE(frame); @@ -1209,9 +1401,7 @@ static bool api_pipe_request(struct pipes_struct *p, return false; } - DEBUG(5, ("Requested %s rpc service\n", - ndr_interface_name(&pipe_fns->syntax.uuid, - pipe_fns->syntax.if_version))); + DEBUG(5, ("Requested %s rpc service\n", interface_name)); ret = api_rpcTNP(p, pkt, pipe_fns->cmds, pipe_fns->n_cmds, &pipe_fns->syntax); @@ -1345,7 +1535,11 @@ void set_incoming_fault(struct pipes_struct *p) data_blob_free(&p->in_data.data); p->in_data.pdu_needed_len = 0; p->in_data.pdu.length = 0; - p->fault_state = DCERPC_FAULT_CANT_PERFORM; + p->fault_state = DCERPC_NCA_S_PROTO_ERROR; + + p->allow_alter = false; + p->allow_auth3 = false; + p->pipe_bound = false; DEBUG(10, ("Setting fault state\n")); } @@ -1356,7 +1550,6 @@ static NTSTATUS dcesrv_auth_request(struct pipe_auth_data *auth, { NTSTATUS status; size_t hdr_size = DCERPC_REQUEST_LENGTH; - size_t pad_len; DEBUG(10, ("Checking request auth.\n")); @@ -1367,25 +1560,11 @@ static NTSTATUS dcesrv_auth_request(struct pipe_auth_data *auth, /* in case of sealing this function will unseal the data in place */ status = dcerpc_check_auth(auth, pkt, &pkt->u.request.stub_and_verifier, - hdr_size, raw_pkt, - &pad_len); + hdr_size, raw_pkt); if (!NT_STATUS_IS_OK(status)) { return status; } - - /* remove padding and auth trailer, - * this way the caller will get just the data */ - if (pkt->auth_length) { - size_t trail_len = pad_len - + DCERPC_AUTH_TRAILER_LENGTH - + pkt->auth_length; - if (pkt->u.request.stub_and_verifier.length < trail_len) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - pkt->u.request.stub_and_verifier.length -= trail_len; - } - return NT_STATUS_OK; } @@ -1406,6 +1585,29 @@ static bool process_request_pdu(struct pipes_struct *p, struct ncacn_packet *pkt return False; } + /* + * We don't ignore DCERPC_PFC_FLAG_PENDING_CANCEL. + * TODO: we can reject it with DCERPC_FAULT_NO_CALL_ACTIVE later. + */ + status = dcerpc_verify_ncacn_packet_header(pkt, + DCERPC_PKT_REQUEST, + pkt->u.request.stub_and_verifier.length, + 0, /* required_flags */ + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST | + 0x08 | /* this is not defined, but should be ignored */ + DCERPC_PFC_FLAG_CONC_MPX | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE | + DCERPC_PFC_FLAG_MAYBE | + DCERPC_PFC_FLAG_OBJECT_UUID); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("process_request_pdu: invalid pdu: %s\n", + nt_errstr(status))); + NDR_PRINT_DEBUG(ncacn_packet, pkt); + set_incoming_fault(p); + return false; + } + hdr2 = dcerpc_sec_vt_header2_from_ncacn_packet(pkt); if (pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST) { p->header2 = hdr2; @@ -1597,7 +1799,7 @@ done: if (!reply) { DEBUG(3,("DCE/RPC fault sent!")); set_incoming_fault(p); - setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR)); + setup_fault_pdu(p, NT_STATUS(DCERPC_NCA_S_PROTO_ERROR)); } /* pkt and p->in_data.pdu.data freed by caller */ } diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c index ac7576fc017..a35e4223327 100644 --- a/source3/rpcclient/rpcclient.c +++ b/source3/rpcclient/rpcclient.c @@ -1110,10 +1110,9 @@ out_free: } } if (pipe_default_auth_type != DCERPC_AUTH_TYPE_NONE) { - /* If neither Integrity or Privacy are requested then - * Use just Connect level */ + /* If nothing is requested then default to integrity */ if (pipe_default_auth_level == DCERPC_AUTH_LEVEL_NONE) { - pipe_default_auth_level = DCERPC_AUTH_LEVEL_CONNECT; + pipe_default_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; } } diff --git a/source3/script/tests/test_ntlm_auth_s3.sh b/source3/script/tests/test_ntlm_auth_s3.sh index 655556b692c..bd4ffa1ea1b 100755 --- a/source3/script/tests/test_ntlm_auth_s3.sh +++ b/source3/script/tests/test_ntlm_auth_s3.sh @@ -94,6 +94,8 @@ testit "ntlm_auth with NTLMSSP client and gss-spnego server" $PYTHON $SRC3DIR/to testit "ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH $ADDARGS --client-domain=fOo --server-domain=fOo --client-helper=gss-spnego-client --server-helper=gss-spnego || failed=`expr $failed + 1` testit "ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server against winbind" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH --client-username=$USERNAME --client-domain=$DOMAIN --client-password=$PASSWORD --server-use-winbindd --client-helper=gss-spnego-client --server-helper=gss-spnego $ADDARGS || failed=`expr $failed + 1` +testit "wbinfo store cached credentials" $BINDIR/wbinfo --ccache-save=$DOMAIN/$USERNAME%$PASSWORD || failed=`expr $failed + 1` +testit "ntlm_auth ccached credentials with NTLMSSP client and gss-spnego server" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH $ADDARGS --client-username=$USERNAME --client-domain=$DOMAIN --client-use-cached-creds --client-helper=ntlmssp-client-1 --server-helper=gss-spnego --server-use-winbindd || failed=`expr $failed + 1` testit "ntlm_auth against winbindd with require-membership-of" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH --client-username=$USERNAME --client-domain=$DOMAIN --client-password=$PASSWORD --server-use-winbindd $ADDARGS --require-membership-of=$SID || failed=`expr $failed + 1` testit "ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server against winbind with require-membership-of" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH --client-username=$USERNAME --client-domain=$DOMAIN --client-password=$PASSWORD --server-use-winbindd --client-helper=gss-spnego-client --server-helper=gss-spnego $ADDARGS --require-membership-of=$SID || failed=`expr $failed + 1` diff --git a/source3/script/tests/test_rpcclient_samlogon.sh b/source3/script/tests/test_rpcclient_samlogon.sh index 01af7f80a15..a41ae44d25f 100755 --- a/source3/script/tests/test_rpcclient_samlogon.sh +++ b/source3/script/tests/test_rpcclient_samlogon.sh @@ -12,16 +12,21 @@ PASSWORD="$2" shift 2 ADDARGS="$*" -rpcclient_samlogon() +rpcclient_samlogon_schannel_seal() { - $VALGRIND $BINDIR/rpcclient -U% -c "samlogon $USERNAME $PASSWORD;samlogon $USERNAME $PASSWORD" $@ + $VALGRIND $BINDIR/rpcclient -U% -c "schannel;samlogon $USERNAME $PASSWORD;samlogon $USERNAME $PASSWORD" $@ } +rpcclient_samlogon_schannel_sign() +{ + $VALGRIND $BINDIR/rpcclient -U% -c "schannelsign;samlogon $USERNAME $PASSWORD;samlogon $USERNAME $PASSWORD" $@ +} incdir=`dirname $0`/../../../testprogs/blackbox . $incdir/subunit.sh testit "rpcclient dsenumdomtrusts" $VALGRIND $BINDIR/rpcclient $ADDARGS -U% -c "dsenumdomtrusts" || failed=`expr $failed + 1` testit "rpcclient getdcsitecoverage" $VALGRIND $BINDIR/rpcclient $ADDARGS -U% -c "getdcsitecoverage" || failed=`expr $failed + 1` -testit "rpcclient samlogon" rpcclient_samlogon $ADDARGS || failed=`expr $failed +1` +testit "rpcclient samlogon schannel seal" rpcclient_samlogon_schannel_seal $ADDARGS || failed=`expr $failed +1` +testit "rpcclient samlogon schannel sign" rpcclient_samlogon_schannel_sign $ADDARGS || failed=`expr $failed +1` testok $0 $failed diff --git a/source3/script/tests/test_smbclient_auth.sh b/source3/script/tests/test_smbclient_auth.sh index 24e98b1f552..2402f737287 100755 --- a/source3/script/tests/test_smbclient_auth.sh +++ b/source3/script/tests/test_smbclient_auth.sh @@ -21,6 +21,17 @@ ADDARGS="$*" incdir=`dirname $0`/../../../testprogs/blackbox . $incdir/subunit.sh +echo "${SERVER_IP}" | grep -q ':.*:' && { + # If we have an ipv6 address e.g. + # fd00:0000:0000:0000:0000:0000:5357:5f03 + # we also try + # fd00-0000-0000-0000-0000-0000-5357-5f03.ipv6-literal.net + IPV6LITERAL=$(echo "${SERVER_IP}.ipv6-literal.net" | sed -e 's!:!-!g' -e 's!%!s!') + testit "smbclient //${IPV6LITERAL}/tmpguest" $SMBCLIENT //${IPV6LITERAL}/tmpguest $CONFIGURATION -U$USERNAME%$PASSWORD -c quit $ADDARGS + testit "smbclient //${IPV6LITERAL}./tmpguest" $SMBCLIENT //${IPV6LITERAL}./tmpguest $CONFIGURATION -U$USERNAME%$PASSWORD -c quit $ADDARGS +} +testit "smbclient //${SERVER_IP}/tmpguest" $SMBCLIENT //${SERVER_IP}/tmpguest $CONFIGURATION -U$USERNAME%$PASSWORD -p 139 -c quit $ADDARGS + testit "smbclient //$SERVER/guestonly" $SMBCLIENT //$SERVER/guestonly $CONFIGURATION -U$USERNAME%$PASSWORD -I $SERVER_IP -p 139 -c quit $ADDARGS testit "smbclient //$SERVER/guestonly as anon" $SMBCLIENT //$SERVER/guestonly $CONFIGURATION -U% -I $SERVER_IP -p 139 -c quit $ADDARGS testit "smbclient //$SERVER/tmpguest" $SMBCLIENT //$SERVER/tmpguest $CONFIGURATION -U$USERNAME%$PASSWORD -I $SERVER_IP -p 139 -c quit $ADDARGS diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 830753c12b4..8b929214af8 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -135,6 +135,9 @@ for env in ["s3dc", "member", "s3member"]: plantestsuite("samba3.blackbox.smbclient_auth.plain (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbclient_auth.sh"), '$SERVER', '$SERVER_IP', '$DC_USERNAME', '$DC_PASSWORD', smbclient3, configuration]) plantestsuite("samba3.blackbox.smbclient_auth.plain (%s) member creds" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbclient_auth.sh"), '$SERVER', '$SERVER_IP', '$SERVER/$USERNAME', '$PASSWORD', smbclient3, configuration]) +env="s3dc" +plantestsuite("samba3.blackbox.smbclient_auth.plain (%s) ipv6" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbclient_auth.sh"), '$SERVER', '$SERVER_IPV6', '$SERVER/$USERNAME', '$PASSWORD', smbclient3, configuration]) + for env in ["member", "s3member"]: plantestsuite("samba3.blackbox.net_cred_change.(%s:local)" % env, "%s:local" % env, [os.path.join(samba3srcdir, "script/tests/test_net_cred_change.sh"), configuration]) @@ -338,8 +341,8 @@ for t in tests: plansmbtorture4testsuite(t, "plugin_s4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD', 'over ncacn_np ') plansmbtorture4testsuite(t, "plugin_s4_dc", 'ncacn_ip_tcp:$SERVER_IP -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ') elif t == "rpc.samr.passwords.validate": - plansmbtorture4testsuite(t, "s3dc", 'ncacn_ip_tcp:$SERVER_IP -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ') - plansmbtorture4testsuite(t, "plugin_s4_dc", 'ncacn_ip_tcp:$SERVER_IP -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ') + plansmbtorture4testsuite(t, "s3dc", 'ncacn_ip_tcp:$SERVER_IP[seal] -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ') + plansmbtorture4testsuite(t, "plugin_s4_dc", 'ncacn_ip_tcp:$SERVER_IP[seal] -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ') elif t == "smb2.durable-open" or t == "smb2.durable-v2-open" or t == "smb2.replay": plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/durable -U$USERNAME%$PASSWORD') plansmbtorture4testsuite(t, "plugin_s4_dc", '//$SERVER_IP/durable -U$USERNAME%$PASSWORD') diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index 2ea74450732..ff7337c438c 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -544,6 +544,7 @@ void reply_negprot(struct smb_request *req) size_t converted_size; struct smbXsrv_connection *xconn = req->xconn; struct smbd_server_connection *sconn = req->sconn; + bool signing_required = true; START_PROFILE(SMBnegprot); @@ -717,8 +718,9 @@ void reply_negprot(struct smb_request *req) DEBUG( 5, ( "negprot index=%d\n", choice ) ); - if ((lp_server_signing() == SMB_SIGNING_REQUIRED) - && (chosen_level < PROTOCOL_NT1)) { + /* We always have xconn->smb1.signing_state also for >= SMB2_02 */ + signing_required = smb_signing_is_mandatory(xconn->smb1.signing_state); + if (signing_required && (chosen_level < PROTOCOL_NT1)) { exit_server_cleanly("SMB signing is required and " "client negotiated a downlevel protocol"); } diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index b2617041e52..33574f7c086 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -37,6 +37,7 @@ #include "../libcli/security/security.h" #include "auth/gensec/gensec.h" #include "lib/conn_tdb.h" +#include "../libcli/smb/smb_signing.h" /**************************************************************************** Add the standard 'Samba' signature to the end of the session setup. @@ -598,7 +599,8 @@ void reply_sesssetup_and_X(struct smb_request *req) struct smbd_server_connection *sconn = req->sconn; bool doencrypt = xconn->smb1.negprot.encrypted_passwords; bool signing_allowed = false; - bool signing_mandatory = false; + bool signing_mandatory = smb_signing_is_mandatory( + xconn->smb1.signing_state); START_PROFILE(SMBsesssetupX); diff --git a/source3/smbd/smb2_negprot.c b/source3/smbd/smb2_negprot.c index eb238d38b08..bb11f0613ad 100644 --- a/source3/smbd/smb2_negprot.c +++ b/source3/smbd/smb2_negprot.c @@ -24,6 +24,7 @@ #include "../libcli/smb/smb_common.h" #include "../lib/tsocket/tsocket.h" #include "../librpc/ndr/libndr.h" +#include "../libcli/smb/smb_signing.h" extern fstring remote_proto; @@ -149,6 +150,7 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req) uint32_t max_read = lp_smb2_max_read(); uint32_t max_write = lp_smb2_max_write(); NTTIME now = timeval_to_nttime(&req->request_time); + bool signing_required = true; status = smbd_smb2_request_verify_sizes(req, 0x24); if (!NT_STATUS_IS_OK(status)) { @@ -228,7 +230,13 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req) } security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; - if (lp_server_signing() == SMB_SIGNING_REQUIRED) { + /* + * We use xconn->smb1.signing_state as that's already present + * and used lpcfg_server_signing_allowed() to get the correct + * defaults, e.g. signing_required for an ad_dc. + */ + signing_required = smb_signing_is_mandatory(xconn->smb1.signing_state); + if (signing_required) { security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED; } diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index e255e46ba95..8b239c9b3b0 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -186,7 +186,8 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session, struct smbXsrv_connection *xconn = smb2req->xconn; if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || - lp_server_signing() == SMB_SIGNING_REQUIRED) { + (xconn->smb2.server.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED)) + { x->global->signing_required = true; } diff --git a/source3/torture/test_ntlm_auth.py b/source3/torture/test_ntlm_auth.py index d17af9b0bf9..fffeb2696b2 100755 --- a/source3/torture/test_ntlm_auth.py +++ b/source3/torture/test_ntlm_auth.py @@ -27,300 +27,305 @@ import sys from optparse import OptionParser class ReadChildError(Exception): - pass + pass class WriteChildError(Exception): - pass + pass def readLine(pipe): - """readLine(pipe) -> str - Read a line from the child's pipe, returns the string read. - Throws ReadChildError if the read fails. - """ - buf = os.read(pipe, 2047) - newline = buf.find('\n') - if newline == -1: - raise ReadChildError() - return buf[:newline] + """readLine(pipe) -> str + Read a line from the child's pipe, returns the string read. + Throws ReadChildError if the read fails. + """ + buf = os.read(pipe, 2047) + newline = buf.find('\n') + if newline == -1: + raise ReadChildError() + return buf[:newline] def writeLine(pipe, buf): - """writeLine(pipe, buf) -> nul - Write a line to the child's pipe. - Raises WriteChildError if the write fails. - """ - written = os.write(pipe, buf) - if written != len(buf): - raise WriteChildError() - os.write(pipe, "\n") + """writeLine(pipe, buf) -> nul + Write a line to the child's pipe. + Raises WriteChildError if the write fails. + """ + written = os.write(pipe, buf) + if written != len(buf): + raise WriteChildError() + os.write(pipe, "\n") def parseCommandLine(): - """parseCommandLine() -> (opts, ntlm_auth_path) - Parse the command line. - Return a tuple consisting of the options and the path to ntlm_auth. - """ - usage = "usage: %prog [options] path/to/ntlm_auth" - parser = OptionParser(usage) - - parser.set_defaults(client_username="foo") - parser.set_defaults(client_password="secret") - parser.set_defaults(client_domain="FOO") - parser.set_defaults(client_helper="ntlmssp-client-1") - - parser.set_defaults(server_username="foo") - parser.set_defaults(server_password="secret") - parser.set_defaults(server_domain="FOO") - parser.set_defaults(server_helper="squid-2.5-ntlmssp") - parser.set_defaults(config_file="/etc/samba/smb.conf") - - parser.add_option("--client-username", dest="client_username",\ - help="User name for the client. [default: foo]") - parser.add_option("--client-password", dest="client_password",\ - help="Password the client will send. [default: secret]") - parser.add_option("--client-domain", dest="client_domain",\ - help="Domain the client authenticates for. [default: FOO]") - parser.add_option("--client-helper", dest="client_helper",\ - help="Helper mode for the ntlm_auth client. [default: ntlmssp-client-1]") - - parser.add_option("--target-hostname", dest="target_hostname",\ - help="Target hostname for kerberos") - parser.add_option("--target-service", dest="target_service",\ - help="Target service for kerberos") - - - parser.add_option("--server-username", dest="server_username",\ - help="User name server uses for local auth. [default: foo]") - parser.add_option("--server-password", dest="server_password",\ - help="Password server uses for local auth. [default: secret]") - parser.add_option("--server-domain", dest="server_domain",\ - help="Domain server uses for local auth. [default: FOO]") - parser.add_option("--server-helper", dest="server_helper",\ - help="Helper mode for the ntlm_auth server. [default: squid-2.5-server]") - parser.add_option("--server-use-winbindd", dest="server_use_winbindd",\ - help="Use winbindd to check the password (rather than default username/pw)", action="store_true") - parser.add_option("--require-membership-of", dest="sid",\ - help="Require that the user is a member of this group to authenticate.") - - - parser.add_option("-s", "--configfile", dest="config_file",\ - help="Path to smb.conf file. [default:/etc/samba/smb.conf") - - (opts, args) = parser.parse_args() - if len(args) != 1: - parser.error("Invalid number of arguments.") - - if not os.access(args[0], os.X_OK): - parser.error("%s is not executable." % args[0]) - - return (opts, args[0]) + """parseCommandLine() -> (opts, ntlm_auth_path) + Parse the command line. + Return a tuple consisting of the options and the path to ntlm_auth. + """ + usage = "usage: %prog [options] path/to/ntlm_auth" + parser = OptionParser(usage) + + parser.set_defaults(client_username="foo") + parser.set_defaults(client_password="secret") + parser.set_defaults(client_domain="FOO") + parser.set_defaults(client_helper="ntlmssp-client-1") + + parser.set_defaults(server_username="foo") + parser.set_defaults(server_password="secret") + parser.set_defaults(server_domain="FOO") + parser.set_defaults(server_helper="squid-2.5-ntlmssp") + parser.set_defaults(config_file="/etc/samba/smb.conf") + + parser.add_option("--client-username", dest="client_username",\ + help="User name for the client. [default: foo]") + parser.add_option("--client-password", dest="client_password",\ + help="Password the client will send. [default: secret]") + parser.add_option("--client-domain", dest="client_domain",\ + help="Domain the client authenticates for. [default: FOO]") + parser.add_option("--client-helper", dest="client_helper",\ + help="Helper mode for the ntlm_auth client. [default: ntlmssp-client-1]") + parser.add_option("--client-use-cached-creds", dest="client_use_cached_creds",\ + help="Use winbindd credentials cache (rather than default username/pw)", action="store_true") + + parser.add_option("--target-hostname", dest="target_hostname",\ + help="Target hostname for kerberos") + parser.add_option("--target-service", dest="target_service",\ + help="Target service for kerberos") + + + parser.add_option("--server-username", dest="server_username",\ + help="User name server uses for local auth. [default: foo]") + parser.add_option("--server-password", dest="server_password",\ + help="Password server uses for local auth. [default: secret]") + parser.add_option("--server-domain", dest="server_domain",\ + help="Domain server uses for local auth. [default: FOO]") + parser.add_option("--server-helper", dest="server_helper",\ + help="Helper mode for the ntlm_auth server. [default: squid-2.5-server]") + parser.add_option("--server-use-winbindd", dest="server_use_winbindd",\ + help="Use winbindd to check the password (rather than default username/pw)", action="store_true") + parser.add_option("--require-membership-of", dest="sid",\ + help="Require that the user is a member of this group to authenticate.") + + + parser.add_option("-s", "--configfile", dest="config_file",\ + help="Path to smb.conf file. [default:/etc/samba/smb.conf") + + (opts, args) = parser.parse_args() + if len(args) != 1: + parser.error("Invalid number of arguments.") + + if not os.access(args[0], os.X_OK): + parser.error("%s is not executable." % args[0]) + + return (opts, args[0]) def main(): - """main() -> int - Run the test. - Returns 0 if test succeeded, <>0 otherwise. - """ - (opts, ntlm_auth_path) = parseCommandLine() + """main() -> int + Run the test. + Returns 0 if test succeeded, <>0 otherwise. + """ + (opts, ntlm_auth_path) = parseCommandLine() - (client_in_r, client_in_w) = os.pipe() - (client_out_r, client_out_w) = os.pipe() - - client_pid = os.fork() - - if not client_pid: - # We're in the client child - os.close(0) - os.close(1) - - os.dup2(client_out_r, 0) - os.close(client_out_r) - os.close(client_out_w) - - os.dup2(client_in_w, 1) - os.close(client_in_r) - os.close(client_in_w) - - client_args = [] - client_args.append("--helper-protocol=%s" % opts.client_helper) - client_args.append("--username=%s" % opts.client_username) - client_args.append("--password=%s" % opts.client_password) - client_args.append("--domain=%s" % opts.client_domain) - client_args.append("--configfile=%s" % opts.config_file) - if opts.target_service: - client_args.append("--target-service=%s" % opts.target_service) - if opts.target_hostname: - client_args.append("--target-hostname=%s" % opts.target_hostname) - - os.execv(ntlm_auth_path, client_args) - - client_in = client_in_r - os.close(client_in_w) - - client_out = client_out_w - os.close(client_out_r) - - (server_in_r, server_in_w) = os.pipe() - (server_out_r, server_out_w) = os.pipe() - - server_pid = os.fork() - - if not server_pid: - # We're in the server child - os.close(0) - os.close(1) - - os.dup2(server_out_r, 0) - os.close(server_out_r) - os.close(server_out_w) - - os.dup2(server_in_w, 1) - os.close(server_in_r) - os.close(server_in_w) - - server_args = [] - server_args.append("--helper-protocol=%s" % opts.server_helper) - if not opts.server_use_winbindd: - server_args.append("--username=%s" % opts.server_username) - server_args.append("--password=%s" % opts.server_password) - server_args.append("--domain=%s" % opts.server_domain) - if opts.sid: - raise Exception("Server must be using winbindd for require-membership-of.") - else: - if opts.sid: - server_args.append("--require-membership-of=%s" % opts.sid) - - server_args.append("--configfile=%s" % opts.config_file) - - os.execv(ntlm_auth_path, server_args) - - server_in = server_in_r - os.close(server_in_w) - - server_out = server_out_w - os.close(server_out_r) - - if opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "squid-2.5-ntlmssp": - - # We're in the parent - writeLine(client_out, "YR") - buf = readLine(client_in) - - if buf.count("YR ", 0, 3) != 1: - sys.exit(1) - - writeLine(server_out, buf) - buf = readLine(server_in) - - if buf.count("TT ", 0, 3) != 1: - sys.exit(2) - - writeLine(client_out, buf) - buf = readLine(client_in) - - if buf.count("AF ", 0, 3) != 1: - sys.exit(3) - - # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>' - buf = buf.replace("AF", "KK", 1) - - writeLine(server_out, buf) - buf = readLine(server_in) - - if buf.count("AF ", 0, 3) != 1: - sys.exit(4) - - - elif opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "gss-spnego": - # We're in the parent - writeLine(client_out, "YR") - buf = readLine(client_in) - - if buf.count("YR ", 0, 3) != 1: - sys.exit(1) - - writeLine(server_out, buf) - buf = readLine(server_in) - - if buf.count("TT ", 0, 3) != 1: - sys.exit(2) - - writeLine(client_out, buf) - buf = readLine(client_in) + (client_in_r, client_in_w) = os.pipe() + (client_out_r, client_out_w) = os.pipe() - if buf.count("AF ", 0, 3) != 1: - sys.exit(3) + client_pid = os.fork() - # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>' - buf = buf.replace("AF", "KK", 1) - - writeLine(server_out, buf) - buf = readLine(server_in) - - if buf.count("AF * ", 0, 5) != 1: - sys.exit(4) + if not client_pid: + # We're in the client child + os.close(0) + os.close(1) + os.dup2(client_out_r, 0) + os.close(client_out_r) + os.close(client_out_w) - elif opts.client_helper == "gss-spnego-client" and opts.server_helper == "gss-spnego": - # We're in the parent - writeLine(server_out, "YR") - buf = readLine(server_in) - - while True: - if buf.count("AF ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1: - sys.exit(1) - - writeLine(client_out, buf) - buf = readLine(client_in) - - if buf.count("AF", 0, 2) == 1: - break - - if buf.count("AF ", 0, 5) != 1 and buf.count("KK ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1: - sys.exit(2) - - writeLine(server_out, buf) - buf = readLine(server_in) - - if buf.count("AF * ", 0, 5) == 1: - break - - else: - sys.exit(5) + os.dup2(client_in_w, 1) + os.close(client_in_r) + os.close(client_in_w) - if opts.client_helper == "ntlmssp-client-1": - writeLine(client_out, "GK") - buf = readLine(client_in) + client_args = [] + client_args.append("--helper-protocol=%s" % opts.client_helper) + client_args.append("--username=%s" % opts.client_username) + if opts.client_use_cached_creds: + client_args.append("--use-cached-creds") + else: + client_args.append("--password=%s" % opts.client_password) + client_args.append("--domain=%s" % opts.client_domain) + client_args.append("--configfile=%s" % opts.config_file) + if opts.target_service: + client_args.append("--target-service=%s" % opts.target_service) + if opts.target_hostname: + client_args.append("--target-hostname=%s" % opts.target_hostname) - if buf.count("GK ", 0, 3) != 1: - sys.exit(4) - - writeLine(client_out, "GF") - buf = readLine(client_in) - - if buf.count("GF ", 0, 3) != 1: - sys.exit(4) - - if opts.server_helper == "squid-2.5-ntlmssp": - writeLine(server_out, "GK") - buf = readLine(server_in) - - if buf.count("GK ", 0, 3) != 1: - sys.exit(4) + os.execv(ntlm_auth_path, client_args) - writeLine(server_out, "GF") - buf = readLine(server_in) - - if buf.count("GF ", 0, 3) != 1: - sys.exit(4) - - os.close(server_in) - os.close(server_out) - os.close(client_in) - os.close(client_out) - os.waitpid(server_pid, 0) - os.waitpid(client_pid, 0) - sys.exit(0) + client_in = client_in_r + os.close(client_in_w) + + client_out = client_out_w + os.close(client_out_r) + + (server_in_r, server_in_w) = os.pipe() + (server_out_r, server_out_w) = os.pipe() + + server_pid = os.fork() + + if not server_pid: + # We're in the server child + os.close(0) + os.close(1) + + os.dup2(server_out_r, 0) + os.close(server_out_r) + os.close(server_out_w) + + os.dup2(server_in_w, 1) + os.close(server_in_r) + os.close(server_in_w) + + server_args = [] + server_args.append("--helper-protocol=%s" % opts.server_helper) + if not opts.server_use_winbindd: + server_args.append("--username=%s" % opts.server_username) + server_args.append("--password=%s" % opts.server_password) + server_args.append("--domain=%s" % opts.server_domain) + if opts.sid: + raise Exception("Server must be using winbindd for require-membership-of.") + else: + if opts.sid: + server_args.append("--require-membership-of=%s" % opts.sid) + + server_args.append("--configfile=%s" % opts.config_file) + + os.execv(ntlm_auth_path, server_args) + + server_in = server_in_r + os.close(server_in_w) + + server_out = server_out_w + os.close(server_out_r) + + if opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "squid-2.5-ntlmssp": + + # We're in the parent + writeLine(client_out, "YR") + buf = readLine(client_in) + + if buf.count("YR ", 0, 3) != 1: + sys.exit(1) + + writeLine(server_out, buf) + buf = readLine(server_in) + + if buf.count("TT ", 0, 3) != 1: + sys.exit(2) + + writeLine(client_out, buf) + buf = readLine(client_in) + + if buf.count("AF ", 0, 3) != 1: + sys.exit(3) + + # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>' + buf = buf.replace("AF", "KK", 1) + + writeLine(server_out, buf) + buf = readLine(server_in) + + if buf.count("AF ", 0, 3) != 1: + sys.exit(4) + + + elif opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "gss-spnego": + # We're in the parent + writeLine(client_out, "YR") + buf = readLine(client_in) + + if buf.count("YR ", 0, 3) != 1: + sys.exit(1) + + writeLine(server_out, buf) + buf = readLine(server_in) + + if buf.count("TT ", 0, 3) != 1: + sys.exit(2) + + writeLine(client_out, buf) + buf = readLine(client_in) + + if buf.count("AF ", 0, 3) != 1: + sys.exit(3) + + # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>' + buf = buf.replace("AF", "KK", 1) + + writeLine(server_out, buf) + buf = readLine(server_in) + + if buf.count("AF * ", 0, 5) != 1: + sys.exit(4) + + + elif opts.client_helper == "gss-spnego-client" and opts.server_helper == "gss-spnego": + # We're in the parent + writeLine(server_out, "YR") + buf = readLine(server_in) + + while True: + if buf.count("AF ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1: + sys.exit(1) + + writeLine(client_out, buf) + buf = readLine(client_in) + + if buf.count("AF", 0, 2) == 1: + break + + if buf.count("AF ", 0, 5) != 1 and buf.count("KK ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1: + sys.exit(2) + + writeLine(server_out, buf) + buf = readLine(server_in) + + if buf.count("AF * ", 0, 5) == 1: + break + + else: + sys.exit(5) + + if opts.client_helper == "ntlmssp-client-1": + writeLine(client_out, "GK") + buf = readLine(client_in) + + if buf.count("GK ", 0, 3) != 1: + sys.exit(4) + + writeLine(client_out, "GF") + buf = readLine(client_in) + + if buf.count("GF ", 0, 3) != 1: + sys.exit(4) + + if opts.server_helper == "squid-2.5-ntlmssp": + writeLine(server_out, "GK") + buf = readLine(server_in) + + if buf.count("GK ", 0, 3) != 1: + sys.exit(4) + + writeLine(server_out, "GF") + buf = readLine(server_in) + + if buf.count("GF ", 0, 3) != 1: + sys.exit(4) + + os.close(server_in) + os.close(server_out) + os.close(client_in) + os.close(client_out) + os.waitpid(server_pid, 0) + os.waitpid(client_pid, 0) + sys.exit(0) if __name__ == "__main__": - main() + main() diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 5f18bf4401a..3d7d8a15dce 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -1907,7 +1907,7 @@ static int net_ads_printer_publish(struct net_context *c, int argc, const char * c->opt_user_name, c->opt_workgroup, c->opt_password ? c->opt_password : "", CLI_FULL_CONNECTION_USE_KERBEROS, - SMB_SIGNING_DEFAULT); + SMB_SIGNING_IPC_DEFAULT); if (NT_STATUS_IS_ERR(nt_status)) { d_fprintf(stderr, _("Unable to open a connection to %s to " diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c index cd17b2cf1a2..8f65a73b396 100644 --- a/source3/utils/net_rpc.c +++ b/source3/utils/net_rpc.c @@ -7395,7 +7395,7 @@ bool net_rpc_check(struct net_context *c, unsigned flags) return false; status = cli_connect_nb(server_name, &server_ss, 0, 0x20, - lp_netbios_name(), SMB_SIGNING_DEFAULT, + lp_netbios_name(), SMB_SIGNING_IPC_DEFAULT, 0, &cli); if (!NT_STATUS_IS_OK(status)) { return false; diff --git a/source3/utils/net_util.c b/source3/utils/net_util.c index 13a0ef12d86..de929ffd75d 100644 --- a/source3/utils/net_util.c +++ b/source3/utils/net_util.c @@ -126,7 +126,7 @@ NTSTATUS connect_to_service(struct net_context *c, service_name, service_type, c->opt_user_name, c->opt_workgroup, c->opt_password, flags, - SMB_SIGNING_DEFAULT); + SMB_SIGNING_IPC_DEFAULT); if (!NT_STATUS_IS_OK(nt_status)) { d_fprintf(stderr, _("Could not connect to server %s\n"), server_name); diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 3906f3829df..d01c522dffd 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -29,7 +29,6 @@ #include "popt_common.h" #include "utils/ntlm_auth.h" #include "../libcli/auth/libcli_auth.h" -#include "../libcli/auth/spnego.h" #include "auth/ntlmssp/ntlmssp.h" #include "auth/gensec/gensec.h" #include "auth/gensec/gensec_internal.h" @@ -38,7 +37,6 @@ #include "smb_krb5.h" #include "lib/util/tiniparser.h" #include "../lib/crypto/arcfour.h" -#include "libads/kerberos_proto.h" #include "nsswitch/winbind_client.h" #include "librpc/gen_ndr/krb5pac.h" #include "../lib/util/asn1.h" @@ -100,6 +98,10 @@ typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode, struct ntlm_auth_state *state, char *buf, int length, void **private2); +static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private1); + static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, struct ntlm_auth_state *state, @@ -225,13 +227,25 @@ static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mod static const char *get_password(struct cli_credentials *credentials) { + TALLOC_CTX *frame = talloc_stackframe(); char *password = NULL; + struct ntlm_auth_state *state; + + state = talloc_zero(frame, struct ntlm_auth_state); + if (state == NULL) { + DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n")); + x_fprintf(x_stderr, "ERR\n"); + exit(1); + } + + state->mem_ctx = state; /* Ask for a password */ x_fprintf(x_stdout, "PW\n"); - manage_squid_request(NUM_HELPER_MODES /* bogus */, NULL, NULL, manage_gensec_get_pw_request, (void **)&password); + manage_squid_request(NUM_HELPER_MODES /* bogus */, NULL, state, manage_gensec_get_pw_request, (void **)&password); talloc_steal(credentials, password); + TALLOC_FREE(frame); return password; } @@ -254,6 +268,10 @@ static void gensec_want_feature_list(struct gensec_security *state, char* featur DEBUG(10, ("want GENSEC_FEATURE_SEAL\n")); gensec_want_feature(state, GENSEC_FEATURE_SEAL); } + if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list, true)) { + DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n")); + gensec_want_feature(state, GENSEC_FEATURE_NTLM_CCACHE); + } } static char winbind_separator(void) @@ -953,57 +971,75 @@ static NTSTATUS local_pw_check(struct auth4_context *auth4_context, return nt_status; } -static NTSTATUS ntlm_auth_start_ntlmssp_client(struct ntlmssp_state **client_ntlmssp_state) +static NTSTATUS ntlm_auth_prepare_gensec_client(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + struct gensec_security **gensec_security_out) { - NTSTATUS status; - if ( (opt_username == NULL) || (opt_domain == NULL) ) { - status = NT_STATUS_UNSUCCESSFUL; - DEBUG(1, ("Need username and domain for NTLMSSP\n")); - return NT_STATUS_INVALID_PARAMETER; - } + struct gensec_security *gensec_security = NULL; + NTSTATUS nt_status; + TALLOC_CTX *tmp_ctx; + const struct gensec_security_ops **backends = NULL; + struct gensec_settings *gensec_settings = NULL; + size_t idx = 0; - status = ntlmssp_client_start(NULL, - lp_netbios_name(), - lp_workgroup(), - lp_client_ntlmv2_auth(), - client_ntlmssp_state); + tmp_ctx = talloc_new(mem_ctx); + NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Could not start NTLMSSP client: %s\n", - nt_errstr(status))); - TALLOC_FREE(*client_ntlmssp_state); - return status; + gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx); + if (gensec_settings == NULL) { + DEBUG(10, ("lpcfg_gensec_settings failed\n")); + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; } - status = ntlmssp_set_username(*client_ntlmssp_state, opt_username); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Could not set username: %s\n", - nt_errstr(status))); - TALLOC_FREE(*client_ntlmssp_state); - return status; + backends = talloc_zero_array(gensec_settings, + const struct gensec_security_ops *, 4); + if (backends == NULL) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; } + gensec_settings->backends = backends; + + gensec_init(); + + /* These need to be in priority order, krb5 before NTLMSSP */ +#if defined(HAVE_KRB5) + backends[idx++] = &gensec_gse_krb5_security_ops; +#endif - status = ntlmssp_set_domain(*client_ntlmssp_state, opt_domain); + backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Could not set domain: %s\n", - nt_errstr(status))); - TALLOC_FREE(*client_ntlmssp_state); - return status; + backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO); + + nt_status = gensec_client_start(NULL, &gensec_security, + gensec_settings); + if (!NT_STATUS_IS_OK(nt_status)) { + TALLOC_FREE(tmp_ctx); + return nt_status; } - if (opt_password) { - status = ntlmssp_set_password(*client_ntlmssp_state, opt_password); + talloc_unlink(tmp_ctx, gensec_settings); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Could not set password: %s\n", - nt_errstr(status))); - TALLOC_FREE(*client_ntlmssp_state); - return status; + if (opt_target_service != NULL) { + nt_status = gensec_set_target_service(gensec_security, + opt_target_service); + if (!NT_STATUS_IS_OK(nt_status)) { + TALLOC_FREE(tmp_ctx); + return nt_status; + } + } + + if (opt_target_hostname != NULL) { + nt_status = gensec_set_target_hostname(gensec_security, + opt_target_hostname); + if (!NT_STATUS_IS_OK(nt_status)) { + TALLOC_FREE(tmp_ctx); + return nt_status; } } + *gensec_security_out = talloc_steal(mem_ctx, gensec_security); + TALLOC_FREE(tmp_ctx); return NT_STATUS_OK; } @@ -1027,9 +1063,9 @@ static struct auth4_context *make_auth4_context_ntlm_auth(TALLOC_CTX *mem_ctx, b return auth4_context; } -static NTSTATUS ntlm_auth_start_ntlmssp_server(TALLOC_CTX *mem_ctx, - struct loadparm_context *lp_ctx, - struct gensec_security **gensec_security_out) +static NTSTATUS ntlm_auth_prepare_gensec_server(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + struct gensec_security **gensec_security_out) { struct gensec_security *gensec_security; NTSTATUS nt_status; @@ -1135,260 +1171,18 @@ static NTSTATUS ntlm_auth_start_ntlmssp_server(TALLOC_CTX *mem_ctx, talloc_unlink(tmp_ctx, gensec_settings); talloc_unlink(tmp_ctx, auth4_context); - nt_status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_NTLMSSP); - if (!NT_STATUS_IS_OK(nt_status)) { - TALLOC_FREE(tmp_ctx); - return nt_status; - } - *gensec_security_out = talloc_steal(mem_ctx, gensec_security); TALLOC_FREE(tmp_ctx); return NT_STATUS_OK; } -/******************************************************************* - Used by firefox to drive NTLM auth to IIS servers. -*******************************************************************/ - -static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_msg, - DATA_BLOB *reply) -{ - struct winbindd_request wb_request; - struct winbindd_response wb_response; - int ctrl = 0; - NSS_STATUS result; - - /* get winbindd to do the ntlmssp step on our behalf */ - ZERO_STRUCT(wb_request); - ZERO_STRUCT(wb_response); - - /* - * This is tricky here. If we set krb5_auth in pam_winbind.conf - * creds for users in trusted domain will be stored the winbindd - * child of the trusted domain. If we ask the primary domain for - * ntlm_ccache_auth, it will fail. So, we have to ask the trusted - * domain's child for ccache_ntlm_auth. that is to say, we have to - * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags. - */ - ctrl = get_pam_winbind_config(); - - if (ctrl & WINBIND_KRB5_AUTH) { - wb_request.flags |= WBFLAG_PAM_CONTACT_TRUSTDOM; - } - - fstr_sprintf(wb_request.data.ccache_ntlm_auth.user, - "%s%c%s", opt_domain, winbind_separator(), opt_username); - wb_request.data.ccache_ntlm_auth.uid = geteuid(); - wb_request.data.ccache_ntlm_auth.initial_blob_len = initial_msg.length; - wb_request.data.ccache_ntlm_auth.challenge_blob_len = challenge_msg.length; - wb_request.extra_len = initial_msg.length + challenge_msg.length; - - if (wb_request.extra_len > 0) { - wb_request.extra_data.data = SMB_MALLOC_ARRAY(char, wb_request.extra_len); - if (wb_request.extra_data.data == NULL) { - return NT_STATUS_NO_MEMORY; - } - - memcpy(wb_request.extra_data.data, initial_msg.data, initial_msg.length); - memcpy(wb_request.extra_data.data + initial_msg.length, - challenge_msg.data, challenge_msg.length); - } - - result = winbindd_request_response(NULL, WINBINDD_CCACHE_NTLMAUTH, &wb_request, &wb_response); - SAFE_FREE(wb_request.extra_data.data); - - if (result != NSS_STATUS_SUCCESS) { - winbindd_free_response(&wb_response); - return NT_STATUS_UNSUCCESSFUL; - } - - if (reply) { - *reply = data_blob(wb_response.extra_data.data, - wb_response.data.ccache_ntlm_auth.auth_blob_len); - if (wb_response.data.ccache_ntlm_auth.auth_blob_len > 0 && - reply->data == NULL) { - winbindd_free_response(&wb_response); - return NT_STATUS_NO_MEMORY; - } - } - - winbindd_free_response(&wb_response); - return NT_STATUS_MORE_PROCESSING_REQUIRED; -} - static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, struct ntlm_auth_state *state, char *buf, int length, void **private2) { - DATA_BLOB request, reply; - NTSTATUS nt_status; - - if (!opt_username || !*opt_username) { - x_fprintf(x_stderr, "username must be specified!\n\n"); - exit(1); - } - - if (strlen(buf) < 2) { - DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf)); - x_fprintf(x_stdout, "BH NTLMSSP query invalid\n"); - return; - } - - if (strlen(buf) > 3) { - if(strncmp(buf, "SF ", 3) == 0) { - DEBUG(10, ("Looking for flags to negotiate\n")); - talloc_free(state->want_feature_list); - state->want_feature_list = talloc_strdup(state->mem_ctx, - buf+3); - x_fprintf(x_stdout, "OK\n"); - return; - } - request = base64_decode_data_blob(buf + 3); - } else { - request = data_blob_null; - } - - if (strncmp(buf, "PW ", 3) == 0) { - /* We asked for a password and obviously got it :-) */ - - opt_password = SMB_STRNDUP((const char *)request.data, - request.length); - - if (opt_password == NULL) { - DEBUG(1, ("Out of memory\n")); - x_fprintf(x_stdout, "BH Out of memory\n"); - data_blob_free(&request); - return; - } - - x_fprintf(x_stdout, "OK\n"); - data_blob_free(&request); - return; - } - - if (!state->ntlmssp_state && use_cached_creds) { - /* check whether cached credentials are usable. */ - DATA_BLOB empty_blob = data_blob_null; - - nt_status = do_ccache_ntlm_auth(empty_blob, empty_blob, NULL); - if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - /* failed to use cached creds */ - use_cached_creds = False; - } - } - - if (opt_password == NULL && !use_cached_creds) { - /* Request a password from the calling process. After - sending it, the calling process should retry asking for the - negotiate. */ - - DEBUG(10, ("Requesting password\n")); - x_fprintf(x_stdout, "PW\n"); - return; - } - - if (strncmp(buf, "YR", 2) == 0) { - TALLOC_FREE(state->ntlmssp_state); - state->cli_state = CLIENT_INITIAL; - } else if (strncmp(buf, "TT", 2) == 0) { - /* No special preprocessing required */ - } else if (strncmp(buf, "GF", 2) == 0) { - DEBUG(10, ("Requested negotiated NTLMSSP flags\n")); - - if(state->cli_state == CLIENT_FINISHED) { - x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags); - } - else { - x_fprintf(x_stdout, "BH\n"); - } - - data_blob_free(&request); - return; - } else if (strncmp(buf, "GK", 2) == 0 ) { - DEBUG(10, ("Requested session key\n")); - - if(state->cli_state == CLIENT_FINISHED) { - char *key64 = base64_encode_data_blob(state->mem_ctx, - state->session_key); - x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>"); - TALLOC_FREE(key64); - } - else { - x_fprintf(x_stdout, "BH\n"); - } - - data_blob_free(&request); - return; - } else { - DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf)); - x_fprintf(x_stdout, "BH NTLMSSP query invalid\n"); - return; - } - - if (!state->ntlmssp_state) { - nt_status = ntlm_auth_start_ntlmssp_client( - &state->ntlmssp_state); - if (!NT_STATUS_IS_OK(nt_status)) { - x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status)); - return; - } - ntlmssp_want_feature_list(state->ntlmssp_state, - state->want_feature_list); - state->initial_message = data_blob_null; - } - - DEBUG(10, ("got NTLMSSP packet:\n")); - dump_data(10, request.data, request.length); - - if (use_cached_creds && !opt_password && - (state->cli_state == CLIENT_RESPONSE)) { - nt_status = do_ccache_ntlm_auth(state->initial_message, request, - &reply); - } else { - nt_status = ntlmssp_update(state->ntlmssp_state, request, - &reply); - } - - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - char *reply_base64 = base64_encode_data_blob(state->mem_ctx, - reply); - if (state->cli_state == CLIENT_INITIAL) { - x_fprintf(x_stdout, "YR %s\n", reply_base64); - state->initial_message = reply; - state->cli_state = CLIENT_RESPONSE; - } else { - x_fprintf(x_stdout, "KK %s\n", reply_base64); - data_blob_free(&reply); - } - TALLOC_FREE(reply_base64); - DEBUG(10, ("NTLMSSP challenge\n")); - } else if (NT_STATUS_IS_OK(nt_status)) { - char *reply_base64 = base64_encode_data_blob(talloc_tos(), - reply); - x_fprintf(x_stdout, "AF %s\n", reply_base64); - TALLOC_FREE(reply_base64); - - if(state->have_session_key) - data_blob_free(&state->session_key); - - state->session_key = data_blob( - state->ntlmssp_state->session_key.data, - state->ntlmssp_state->session_key.length); - state->neg_flags = state->ntlmssp_state->neg_flags; - state->have_session_key = true; - - DEBUG(10, ("NTLMSSP OK!\n")); - state->cli_state = CLIENT_FINISHED; - TALLOC_FREE(state->ntlmssp_state); - } else { - x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status)); - DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status))); - state->cli_state = CLIENT_ERROR; - TALLOC_FREE(state->ntlmssp_state); - } - - data_blob_free(&request); + manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1); + return; } static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, @@ -1507,11 +1301,42 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, if (!(state->gensec_state)) { switch (stdio_helper_mode) { case GSS_SPNEGO_CLIENT: + /* + * cached credentials are only supported by + * NTLMSSP_CLIENT_1 for now. + */ + use_cached_creds = false; + /* fall through */ case NTLMSSP_CLIENT_1: /* setup the client side */ - nt_status = gensec_client_start(NULL, &state->gensec_state, - lpcfg_gensec_settings(NULL, lp_ctx)); + if (state->set_password != NULL) { + use_cached_creds = false; + } + + if (use_cached_creds) { + struct wbcCredentialCacheParams params; + struct wbcCredentialCacheInfo *info = NULL; + struct wbcAuthErrorInfo *error = NULL; + wbcErr wbc_status; + + params.account_name = opt_username; + params.domain_name = opt_domain; + params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP; + params.num_blobs = 0; + params.blobs = NULL; + + wbc_status = wbcCredentialCache(¶ms, &info, + &error); + wbcFreeMemory(error); + if (!WBC_ERROR_IS_OK(wbc_status)) { + use_cached_creds = false; + } + wbcFreeMemory(info); + } + + nt_status = ntlm_auth_prepare_gensec_client(state, lp_ctx, + &state->gensec_state); if (!NT_STATUS_IS_OK(nt_status)) { x_fprintf(x_stdout, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status)); talloc_free(mem_ctx); @@ -1526,7 +1351,10 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, if (opt_domain) { cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED); } - if (state->set_password) { + if (use_cached_creds) { + gensec_want_feature(state->gensec_state, + GENSEC_FEATURE_NTLM_CCACHE); + } else if (state->set_password) { cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED); } else { cli_credentials_set_password_callback(creds, get_password); @@ -1541,8 +1369,8 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, case GSS_SPNEGO_SERVER: case SQUID_2_5_NTLMSSP: { - nt_status = ntlm_auth_start_ntlmssp_server(state, lp_ctx, - &state->gensec_state); + nt_status = ntlm_auth_prepare_gensec_server(state, lp_ctx, + &state->gensec_state); if (!NT_STATUS_IS_OK(nt_status)) { x_fprintf(x_stdout, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status)); talloc_free(mem_ctx); @@ -1621,12 +1449,17 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, return; } - if (stdio_helper_mode == SQUID_2_5_NTLMSSP && strncmp(buf, "GF", 2) == 0) { + if (strncmp(buf, "GF", 2) == 0) { uint32_t neg_flags; + DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n")); + neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state); + if (neg_flags == 0) { + x_fprintf(x_stdout, "BH\n"); + return; + } - DEBUG(10, ("Requested negotiated feature flags\n")); x_fprintf(x_stdout, "GF 0x%08x\n", neg_flags); return; } @@ -1730,408 +1563,12 @@ static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mod return; } -static struct ntlmssp_state *client_ntlmssp_state = NULL; - -static bool manage_client_ntlmssp_init(struct spnego_data spnego) -{ - NTSTATUS status; - DATA_BLOB null_blob = data_blob_null; - DATA_BLOB to_server; - char *to_server_base64; - const char *my_mechs[] = {OID_NTLMSSP, NULL}; - TALLOC_CTX *ctx = talloc_tos(); - - DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n")); - - if (client_ntlmssp_state != NULL) { - DEBUG(1, ("Request for initial SPNEGO request where " - "we already have a state\n")); - return False; - } - - if (!client_ntlmssp_state) { - if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state))) { - x_fprintf(x_stdout, "BH %s\n", nt_errstr(status)); - return False; - } - } - - - if (opt_password == NULL) { - - /* Request a password from the calling process. After - sending it, the calling process should retry with - the negTokenInit. */ - - DEBUG(10, ("Requesting password\n")); - x_fprintf(x_stdout, "PW\n"); - return True; - } - - spnego.type = SPNEGO_NEG_TOKEN_INIT; - spnego.negTokenInit.mechTypes = my_mechs; - spnego.negTokenInit.reqFlags = data_blob_null; - spnego.negTokenInit.reqFlagsPadding = 0; - spnego.negTokenInit.mechListMIC = null_blob; - - status = ntlmssp_update(client_ntlmssp_state, null_blob, - &spnego.negTokenInit.mechToken); - - if ( !(NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || - NT_STATUS_IS_OK(status)) ) { - DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n", - nt_errstr(status))); - TALLOC_FREE(client_ntlmssp_state); - return False; - } - - spnego_write_data(ctx, &to_server, &spnego); - data_blob_free(&spnego.negTokenInit.mechToken); - - to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server); - data_blob_free(&to_server); - x_fprintf(x_stdout, "KK %s\n", to_server_base64); - TALLOC_FREE(to_server_base64); - return True; -} - -static void manage_client_ntlmssp_targ(struct spnego_data spnego) -{ - NTSTATUS status; - DATA_BLOB null_blob = data_blob_null; - DATA_BLOB request; - DATA_BLOB to_server; - char *to_server_base64; - TALLOC_CTX *ctx = talloc_tos(); - - DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n")); - - if (client_ntlmssp_state == NULL) { - DEBUG(1, ("Got NTLMSSP tArg without a client state\n")); - x_fprintf(x_stdout, "BH Got NTLMSSP tArg without a client state\n"); - return; - } - - if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) { - x_fprintf(x_stdout, "NA\n"); - TALLOC_FREE(client_ntlmssp_state); - return; - } - - if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) { - x_fprintf(x_stdout, "AF\n"); - TALLOC_FREE(client_ntlmssp_state); - return; - } - - status = ntlmssp_update(client_ntlmssp_state, - spnego.negTokenTarg.responseToken, - &request); - - if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED or OK from " - "ntlmssp_client_update, got: %s\n", - nt_errstr(status))); - x_fprintf(x_stdout, "BH Expected MORE_PROCESSING_REQUIRED from " - "ntlmssp_client_update\n"); - data_blob_free(&request); - TALLOC_FREE(client_ntlmssp_state); - return; - } - - spnego.type = SPNEGO_NEG_TOKEN_TARG; - spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE; - spnego.negTokenTarg.supportedMech = (const char *)OID_NTLMSSP; - spnego.negTokenTarg.responseToken = request; - spnego.negTokenTarg.mechListMIC = null_blob; - - spnego_write_data(ctx, &to_server, &spnego); - data_blob_free(&request); - - to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server); - data_blob_free(&to_server); - x_fprintf(x_stdout, "KK %s\n", to_server_base64); - TALLOC_FREE(to_server_base64); - return; -} - -#ifdef HAVE_KRB5 - -static bool manage_client_krb5_init(struct spnego_data spnego) -{ - char *principal; - DATA_BLOB tkt, tkt_wrapped, to_server; - DATA_BLOB session_key_krb5 = data_blob_null; - struct spnego_data reply; - char *reply_base64; - int retval; - - const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL}; - ssize_t len; - TALLOC_CTX *ctx = talloc_tos(); - - principal = spnego.negTokenInit.targetPrincipal; - - /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us - */ - if (!lp_client_use_spnego_principal() || strequal(principal, ADS_IGNORE_PRINCIPAL)) { - principal = NULL; - } - - if (principal == NULL && - opt_target_service && opt_target_hostname && !is_ipaddress(opt_target_hostname)) { - DEBUG(3,("manage_client_krb5_init: using target " - "hostname not SPNEGO principal\n")); - - principal = kerberos_get_principal_from_service_hostname(talloc_tos(), - opt_target_service, - opt_target_hostname, - lp_realm()); - - if (!principal) { - return false; - } - - DEBUG(3,("manage_client_krb5_init: guessed " - "server principal=%s\n", - principal ? principal : "<null>")); - } - - if (principal == NULL) { - DEBUG(3,("manage_client_krb5_init: could not guess server principal\n")); - return false; - } - - retval = cli_krb5_get_ticket(ctx, principal, 0, - &tkt, &session_key_krb5, - 0, NULL, NULL, NULL); - if (retval) { - char *user = NULL; - - /* Let's try to first get the TGT, for that we need a - password. */ - - if (opt_password == NULL) { - DEBUG(10, ("Requesting password\n")); - x_fprintf(x_stdout, "PW\n"); - return True; - } - - user = talloc_asprintf(talloc_tos(), "%s@%s", opt_username, opt_domain); - if (!user) { - return false; - } - - if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) { - DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval))); - return False; - } - - retval = cli_krb5_get_ticket(ctx, principal, 0, - &tkt, &session_key_krb5, - 0, NULL, NULL, NULL); - if (retval) { - DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval))); - return False; - } - - } - - /* wrap that up in a nice GSS-API wrapping */ - tkt_wrapped = spnego_gen_krb5_wrap(ctx, tkt, TOK_ID_KRB_AP_REQ); - - data_blob_free(&session_key_krb5); - - ZERO_STRUCT(reply); - - reply.type = SPNEGO_NEG_TOKEN_INIT; - reply.negTokenInit.mechTypes = my_mechs; - reply.negTokenInit.reqFlags = data_blob_null; - reply.negTokenInit.reqFlagsPadding = 0; - reply.negTokenInit.mechToken = tkt_wrapped; - reply.negTokenInit.mechListMIC = data_blob_null; - - len = spnego_write_data(ctx, &to_server, &reply); - data_blob_free(&tkt); - - if (len == -1) { - DEBUG(1, ("Could not write SPNEGO data blob\n")); - return False; - } - - reply_base64 = base64_encode_data_blob(talloc_tos(), to_server); - x_fprintf(x_stdout, "KK %s *\n", reply_base64); - - TALLOC_FREE(reply_base64); - data_blob_free(&to_server); - DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n")); - return True; -} - -static void manage_client_krb5_targ(struct spnego_data spnego) -{ - switch (spnego.negTokenTarg.negResult) { - case SPNEGO_ACCEPT_INCOMPLETE: - DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n")); - x_fprintf(x_stdout, "BH Got a Kerberos negTokenTarg with " - "ACCEPT_INCOMPLETE\n"); - break; - case SPNEGO_ACCEPT_COMPLETED: - DEBUG(10, ("Accept completed\n")); - x_fprintf(x_stdout, "AF\n"); - break; - case SPNEGO_REJECT: - DEBUG(10, ("Rejected\n")); - x_fprintf(x_stdout, "NA\n"); - break; - default: - DEBUG(1, ("Got an invalid negTokenTarg\n")); - x_fprintf(x_stdout, "AF\n"); - } -} - -#endif - static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, struct ntlm_auth_state *state, char *buf, int length, void **private2) { - DATA_BLOB request; - struct spnego_data spnego; - ssize_t len; - TALLOC_CTX *ctx = talloc_tos(); - - if (!opt_username || !*opt_username) { - x_fprintf(x_stderr, "username must be specified!\n\n"); - exit(1); - } - - if (strlen(buf) <= 3) { - DEBUG(1, ("SPNEGO query [%s] too short\n", buf)); - x_fprintf(x_stdout, "BH SPNEGO query too short\n"); - return; - } - - request = base64_decode_data_blob(buf+3); - - if (strncmp(buf, "PW ", 3) == 0) { - - /* We asked for a password and obviously got it :-) */ - - opt_password = SMB_STRNDUP((const char *)request.data, request.length); - - if (opt_password == NULL) { - DEBUG(1, ("Out of memory\n")); - x_fprintf(x_stdout, "BH Out of memory\n"); - data_blob_free(&request); - return; - } - - x_fprintf(x_stdout, "OK\n"); - data_blob_free(&request); - return; - } - - if ( (strncmp(buf, "TT ", 3) != 0) && - (strncmp(buf, "AF ", 3) != 0) && - (strncmp(buf, "NA ", 3) != 0) ) { - DEBUG(1, ("SPNEGO request [%s] invalid\n", buf)); - x_fprintf(x_stdout, "BH SPNEGO request invalid\n"); - data_blob_free(&request); - return; - } - - /* So we got a server challenge to generate a SPNEGO - client-to-server request... */ - - len = spnego_read_data(ctx, request, &spnego); - data_blob_free(&request); - - if (len == -1) { - DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf)); - x_fprintf(x_stdout, "BH Could not read SPNEGO data\n"); - return; - } - - if (spnego.type == SPNEGO_NEG_TOKEN_INIT) { - - /* The server offers a list of mechanisms */ - - const char *const *mechType = spnego.negTokenInit.mechTypes; - - while (*mechType != NULL) { - -#ifdef HAVE_KRB5 - if ( (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) || - (strcmp(*mechType, OID_KERBEROS5) == 0) ) { - if (manage_client_krb5_init(spnego)) - goto out; - } -#endif - - if (strcmp(*mechType, OID_NTLMSSP) == 0) { - if (manage_client_ntlmssp_init(spnego)) - goto out; - } - - mechType++; - } - - DEBUG(1, ("Server offered no compatible mechanism\n")); - x_fprintf(x_stdout, "BH Server offered no compatible mechanism\n"); - return; - } - - if (spnego.type == SPNEGO_NEG_TOKEN_TARG) { - - if (spnego.negTokenTarg.supportedMech == NULL) { - /* On accept/reject Windows does not send the - mechanism anymore. Handle that here and - shut down the mechanisms. */ - - switch (spnego.negTokenTarg.negResult) { - case SPNEGO_ACCEPT_COMPLETED: - x_fprintf(x_stdout, "AF\n"); - break; - case SPNEGO_REJECT: - x_fprintf(x_stdout, "NA\n"); - break; - default: - DEBUG(1, ("Got a negTokenTarg with no mech and an " - "unknown negResult: %d\n", - spnego.negTokenTarg.negResult)); - x_fprintf(x_stdout, "BH Got a negTokenTarg with" - " no mech and an unknown " - "negResult\n"); - } - - TALLOC_FREE(client_ntlmssp_state); - goto out; - } - - if (strcmp(spnego.negTokenTarg.supportedMech, - OID_NTLMSSP) == 0) { - manage_client_ntlmssp_targ(spnego); - goto out; - } - -#if HAVE_KRB5 - if (strcmp(spnego.negTokenTarg.supportedMech, - OID_KERBEROS5_OLD) == 0) { - manage_client_krb5_targ(spnego); - goto out; - } -#endif - - } - - DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf)); - x_fprintf(x_stdout, "BH Got an SPNEGO token I could not handle\n"); - return; - - out: - spnego_free_data(&spnego); + manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1); return; } diff --git a/source3/winbindd/winbindd_ccache_access.c b/source3/winbindd/winbindd_ccache_access.c index 7e300dbe92e..9bcbf0bb05a 100644 --- a/source3/winbindd/winbindd_ccache_access.c +++ b/source3/winbindd/winbindd_ccache_access.c @@ -48,14 +48,16 @@ static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username, const char *password, const DATA_BLOB initial_msg, const DATA_BLOB challenge_msg, + TALLOC_CTX *mem_ctx, DATA_BLOB *auth_msg, - uint8_t session_key[16]) + uint8_t session_key[16], + uint8_t *new_spnego) { NTSTATUS status; struct auth_generic_state *auth_generic_state = NULL; - DATA_BLOB dummy_msg, reply, session_key_blob; + DATA_BLOB reply, session_key_blob; - status = auth_generic_client_prepare(NULL, &auth_generic_state); + status = auth_generic_client_prepare(mem_ctx, &auth_generic_state); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Could not start NTLMSSP client: %s\n", @@ -87,29 +89,26 @@ static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username, goto done; } - gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SESSION_KEY); + if (initial_msg.length == 0) { + gensec_want_feature(auth_generic_state->gensec_security, + GENSEC_FEATURE_SESSION_KEY); + } - status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP); + status = auth_generic_client_start_by_name(auth_generic_state, + "ntlmssp_resume_ccache"); if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Could not start NTLMSSP mech: %s\n", + DEBUG(1, ("Could not start NTLMSSP resume mech: %s\n", nt_errstr(status))); goto done; } - /* We need to get our protocol handler into the right state. So first - we ask it to generate the initial message. Actually the client has already - sent its own initial message, so we're going to drop this one on the floor. - The client might have sent a different message, for example with different - negotiation options, but as far as I can tell this won't hurt us. (Unless - the client sent a different username or domain, in which case that's their - problem for telling us the wrong username or domain.) - Since we have a copy of the initial message that the client sent, we could - resolve any discrepancies if we had to. - */ - dummy_msg = data_blob_null; + /* + * We inject the inital NEGOTIATE message our caller used + * in order to get the state machine into the correct possition. + */ reply = data_blob_null; status = gensec_update(auth_generic_state->gensec_security, - talloc_tos(), dummy_msg, &reply); + talloc_tos(), initial_msg, &reply); data_blob_free(&reply); if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { @@ -120,7 +119,7 @@ static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username, /* Now we are ready to handle the server's actual response. */ status = gensec_update(auth_generic_state->gensec_security, - NULL, challenge_msg, &reply); + mem_ctx, challenge_msg, &reply); if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) { DEBUG(1, ("We didn't get a response to the challenge! [%s]\n", nt_errstr(status))); @@ -146,6 +145,8 @@ static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username, memcpy(session_key, session_key_blob.data, 16); data_blob_free(&session_key_blob); *auth_msg = reply; + *new_spnego = gensec_have_feature(auth_generic_state->gensec_security, + GENSEC_FEATURE_NEW_SPNEGO); status = NT_STATUS_OK; done: @@ -273,8 +274,9 @@ void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state) result = do_ntlm_auth_with_stored_pw( name_user, name_domain, entry->pass, - initial, challenge, &auth, - state->response->data.ccache_ntlm_auth.session_key); + initial, challenge, talloc_tos(), &auth, + state->response->data.ccache_ntlm_auth.session_key, + &state->response->data.ccache_ntlm_auth.new_spnego); if (!NT_STATUS_IS_OK(result)) { goto process_result; diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index cbce0c40c06..63175e54986 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -882,7 +882,7 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - enum smb_signing_setting smb_sign_client_connections = lp_client_signing(); + enum smb_signing_setting smb_sign_client_connections = lp_client_ipc_signing(); if (smb_sign_client_connections == SMB_SIGNING_DEFAULT) { /* @@ -935,8 +935,8 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, cli_set_timeout(*cli, 10000); /* 10 seconds */ result = smbXcli_negprot((*cli)->conn, (*cli)->timeout, - lp_client_min_protocol(), - lp_winbindd_max_protocol()); + lp_client_ipc_min_protocol(), + lp_client_ipc_max_protocol()); if (!NT_STATUS_IS_OK(result)) { DEBUG(1, ("cli_negprot failed: %s\n", nt_errstr(result))); diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c index bff310a6f13..cb85560500c 100644 --- a/source3/winbindd/winbindd_dual_srv.c +++ b/source3/winbindd/winbindd_dual_srv.c @@ -711,7 +711,7 @@ reconnect: logon_server, NETLOGON_CONTROL_QUERY, 2, &info, &werr); - if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) { + if (!dcerpc_binding_handle_is_connected(b) && !retry) { DEBUG(10, ("Session might have expired. " "Reconnect and retry once.\n")); invalidate_cm_connection(&domain->conn); diff --git a/source3/wscript_build b/source3/wscript_build index 58e1b9996d9..2c94ef31ffe 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -358,14 +358,9 @@ bld.SAMBA3_LIBRARY('smbd_shim', deps='talloc', private_library=True) -bld.SAMBA3_SUBSYSTEM('LIBNTLMSSP', - source='''libsmb/ntlmssp.c - libsmb/ntlmssp_wrap.c''', - deps='NDR_NTLMSSP NTLMSSP_COMMON wbclient') - bld.SAMBA3_SUBSYSTEM('auth_generic', source='libsmb/auth_generic.c', - deps='LIBNTLMSSP gse gensec') + deps='gse gensec') bld.SAMBA3_LIBRARY('libsmb', source='''libsmb/clientgen.c @@ -393,7 +388,6 @@ bld.SAMBA3_LIBRARY('libsmb', libsmb/smbsock_connect.c libsmb/cli_smb2_fnum.c''', deps=''' - LIBNTLMSSP auth_generic CLDAP LIBNMB @@ -1420,7 +1414,7 @@ bld.SAMBA3_BINARY('ntlm_auth', tiniparser libsmb popt_samba3 - LIBNTLMSSP gse gensec''') + gse gensec''') bld.SAMBA3_BINARY('timelimit', source='script/tests/timelimit.c', diff --git a/source4/auth/gensec/cyrus_sasl.c b/source4/auth/gensec/cyrus_sasl.c deleted file mode 100644 index 08dccd6f5d1..00000000000 --- a/source4/auth/gensec/cyrus_sasl.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Connect GENSEC to an external SASL lib - - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006 - - 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 3 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "lib/tsocket/tsocket.h" -#include "auth/credentials/credentials.h" -#include "auth/gensec/gensec.h" -#include "auth/gensec/gensec_internal.h" -#include "auth/gensec/gensec_proto.h" -#include "auth/gensec/gensec_toplevel_proto.h" -#include <sasl/sasl.h> - -NTSTATUS gensec_sasl_init(void); - -struct gensec_sasl_state { - sasl_conn_t *conn; - int step; - bool wrap; -}; - -static NTSTATUS sasl_nt_status(int sasl_ret) -{ - switch (sasl_ret) { - case SASL_CONTINUE: - return NT_STATUS_MORE_PROCESSING_REQUIRED; - case SASL_NOMEM: - return NT_STATUS_NO_MEMORY; - case SASL_BADPARAM: - case SASL_NOMECH: - return NT_STATUS_INVALID_PARAMETER; - case SASL_BADMAC: - return NT_STATUS_ACCESS_DENIED; - case SASL_OK: - return NT_STATUS_OK; - default: - return NT_STATUS_UNSUCCESSFUL; - } -} - -static int gensec_sasl_get_user(void *context, int id, - const char **result, unsigned *len) -{ - struct gensec_security *gensec_security = talloc_get_type(context, struct gensec_security); - const char *username = cli_credentials_get_username(gensec_get_credentials(gensec_security)); - if (id != SASL_CB_USER && id != SASL_CB_AUTHNAME) { - return SASL_FAIL; - } - - *result = username; - return SASL_OK; -} - -static int gensec_sasl_get_realm(void *context, int id, - const char **availrealms, - const char **result) -{ - struct gensec_security *gensec_security = talloc_get_type(context, struct gensec_security); - const char *realm = cli_credentials_get_realm(gensec_get_credentials(gensec_security)); - int i; - if (id != SASL_CB_GETREALM) { - return SASL_FAIL; - } - - for (i=0; availrealms && availrealms[i]; i++) { - if (strcasecmp_m(realm, availrealms[i]) == 0) { - result[i] = availrealms[i]; - return SASL_OK; - } - } - /* None of the realms match, so lets not specify one */ - *result = ""; - return SASL_OK; -} - -static int gensec_sasl_get_password(sasl_conn_t *conn, void *context, int id, - sasl_secret_t **psecret) -{ - struct gensec_security *gensec_security = talloc_get_type(context, struct gensec_security); - const char *password = cli_credentials_get_password(gensec_get_credentials(gensec_security)); - - sasl_secret_t *secret; - if (!password) { - *psecret = NULL; - return SASL_OK; - } - secret = talloc_size(gensec_security, sizeof(sasl_secret_t)+strlen(password)+1); - if (!secret) { - return SASL_NOMEM; - } - secret->len = strlen(password); - strlcpy((char*)secret->data, password, secret->len+1); - *psecret = secret; - return SASL_OK; -} - -static int gensec_sasl_dispose(struct gensec_sasl_state *gensec_sasl_state) -{ - sasl_dispose(&gensec_sasl_state->conn); - return SASL_OK; -} - -static NTSTATUS gensec_sasl_client_start(struct gensec_security *gensec_security) -{ - struct gensec_sasl_state *gensec_sasl_state; - const char *service = gensec_get_target_service(gensec_security); - const char *target_name = gensec_get_target_hostname(gensec_security); - const struct tsocket_address *tlocal_addr = gensec_get_local_address(gensec_security); - const struct tsocket_address *tremote_addr = gensec_get_remote_address(gensec_security); - char *local_addr = NULL; - char *remote_addr = NULL; - int sasl_ret; - - sasl_callback_t *callbacks; - - gensec_sasl_state = talloc_zero(gensec_security, struct gensec_sasl_state); - if (!gensec_sasl_state) { - return NT_STATUS_NO_MEMORY; - } - - callbacks = talloc_array(gensec_sasl_state, sasl_callback_t, 5); - callbacks[0].id = SASL_CB_USER; - callbacks[0].proc = gensec_sasl_get_user; - callbacks[0].context = gensec_security; - - callbacks[1].id = SASL_CB_AUTHNAME; - callbacks[1].proc = gensec_sasl_get_user; - callbacks[1].context = gensec_security; - - callbacks[2].id = SASL_CB_GETREALM; - callbacks[2].proc = gensec_sasl_get_realm; - callbacks[2].context = gensec_security; - - callbacks[3].id = SASL_CB_PASS; - callbacks[3].proc = gensec_sasl_get_password; - callbacks[3].context = gensec_security; - - callbacks[4].id = SASL_CB_LIST_END; - callbacks[4].proc = NULL; - callbacks[4].context = NULL; - - gensec_security->private_data = gensec_sasl_state; - - if (tlocal_addr) { - local_addr = talloc_asprintf(gensec_sasl_state, - "%s;%d", - tsocket_address_inet_addr_string(tlocal_addr, gensec_sasl_state), - tsocket_address_inet_port(tlocal_addr)); - } - - if (tremote_addr) { - remote_addr = talloc_asprintf(gensec_sasl_state, - "%s;%d", - tsocket_address_inet_addr_string(tremote_addr, gensec_sasl_state), - tsocket_address_inet_port(tremote_addr)); - } - gensec_sasl_state->step = 0; - - sasl_ret = sasl_client_new(service, - target_name, - local_addr, remote_addr, callbacks, 0, - &gensec_sasl_state->conn); - - if (sasl_ret == SASL_OK) { - sasl_security_properties_t props; - talloc_set_destructor(gensec_sasl_state, gensec_sasl_dispose); - - ZERO_STRUCT(props); - if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { - props.min_ssf = 1; - props.max_ssf = 1; - props.maxbufsize = 65536; - gensec_sasl_state->wrap = true; - } - if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { - props.min_ssf = 40; - props.max_ssf = UINT_MAX; - props.maxbufsize = 65536; - gensec_sasl_state->wrap = true; - } - - sasl_ret = sasl_setprop(gensec_sasl_state->conn, SASL_SEC_PROPS, &props); - } - if (sasl_ret != SASL_OK) { - DEBUG(1, ("GENSEC SASL: client_new failed: %s\n", sasl_errdetail(gensec_sasl_state->conn))); - } - return sasl_nt_status(sasl_ret); -} - -static NTSTATUS gensec_sasl_update(struct gensec_security *gensec_security, - TALLOC_CTX *out_mem_ctx, - struct tevent_context *ev, - const DATA_BLOB in, DATA_BLOB *out) -{ - struct gensec_sasl_state *gensec_sasl_state = talloc_get_type(gensec_security->private_data, - struct gensec_sasl_state); - int sasl_ret; - const char *out_data; - unsigned int out_len; - - if (gensec_sasl_state->step == 0) { - const char *mech; - sasl_ret = sasl_client_start(gensec_sasl_state->conn, gensec_security->ops->sasl_name, - NULL, &out_data, &out_len, &mech); - } else { - sasl_ret = sasl_client_step(gensec_sasl_state->conn, - (char*)in.data, in.length, NULL, - &out_data, &out_len); - } - if (sasl_ret == SASL_OK || sasl_ret == SASL_CONTINUE) { - *out = data_blob_talloc(out_mem_ctx, out_data, out_len); - } else { - DEBUG(1, ("GENSEC SASL: step %d update failed: %s\n", gensec_sasl_state->step, - sasl_errdetail(gensec_sasl_state->conn))); - } - gensec_sasl_state->step++; - return sasl_nt_status(sasl_ret); -} - -static NTSTATUS gensec_sasl_unwrap_packets(struct gensec_security *gensec_security, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out, - size_t *len_processed) -{ - struct gensec_sasl_state *gensec_sasl_state = talloc_get_type(gensec_security->private_data, - struct gensec_sasl_state); - const char *out_data; - unsigned int out_len; - - int sasl_ret = sasl_decode(gensec_sasl_state->conn, - (char*)in->data, in->length, &out_data, - &out_len); - if (sasl_ret == SASL_OK) { - *out = data_blob_talloc(out_mem_ctx, out_data, out_len); - *len_processed = in->length; - } else { - DEBUG(1, ("GENSEC SASL: unwrap failed: %s\n", sasl_errdetail(gensec_sasl_state->conn))); - } - return sasl_nt_status(sasl_ret); - -} - -static NTSTATUS gensec_sasl_wrap_packets(struct gensec_security *gensec_security, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out, - size_t *len_processed) -{ - struct gensec_sasl_state *gensec_sasl_state = talloc_get_type(gensec_security->private_data, - struct gensec_sasl_state); - const char *out_data; - unsigned int out_len; - unsigned len_permitted; - int sasl_ret = sasl_getprop(gensec_sasl_state->conn, SASL_SSF, - (const void**)&len_permitted); - if (sasl_ret != SASL_OK) { - return sasl_nt_status(sasl_ret); - } - len_permitted = MIN(len_permitted, in->length); - - sasl_ret = sasl_encode(gensec_sasl_state->conn, - (char*)in->data, len_permitted, &out_data, - &out_len); - if (sasl_ret == SASL_OK) { - *out = data_blob_talloc(out_mem_ctx, out_data, out_len); - *len_processed = in->length; - } else { - DEBUG(1, ("GENSEC SASL: wrap failed: %s\n", sasl_errdetail(gensec_sasl_state->conn))); - } - return sasl_nt_status(sasl_ret); -} - -/* Try to figure out what features we actually got on the connection */ -static bool gensec_sasl_have_feature(struct gensec_security *gensec_security, - uint32_t feature) -{ - struct gensec_sasl_state *gensec_sasl_state = talloc_get_type(gensec_security->private_data, - struct gensec_sasl_state); - sasl_ssf_t ssf; - int sasl_ret; - - /* If we did not elect to wrap, then we have neither sign nor seal, no matter what the SSF claims */ - if (!gensec_sasl_state->wrap) { - return false; - } - - sasl_ret = sasl_getprop(gensec_sasl_state->conn, SASL_SSF, - (const void**)&ssf); - if (sasl_ret != SASL_OK) { - return false; - } - if (feature & GENSEC_FEATURE_SIGN) { - if (ssf == 0) { - return false; - } - if (ssf >= 1) { - return true; - } - } - if (feature & GENSEC_FEATURE_SEAL) { - if (ssf <= 1) { - return false; - } - if (ssf > 1) { - return true; - } - } - return false; -} - -/* This could in theory work with any SASL mech */ -static const struct gensec_security_ops gensec_sasl_security_ops = { - .name = "sasl-DIGEST-MD5", - .sasl_name = "DIGEST-MD5", - .client_start = gensec_sasl_client_start, - .update = gensec_sasl_update, - .wrap_packets = gensec_sasl_wrap_packets, - .unwrap_packets = gensec_sasl_unwrap_packets, - .have_feature = gensec_sasl_have_feature, - .enabled = true, - .priority = GENSEC_SASL -}; - -static int gensec_sasl_log(void *context, - int sasl_log_level, - const char *message) -{ - int dl; - switch (sasl_log_level) { - case SASL_LOG_NONE: - dl = 0; - break; - case SASL_LOG_ERR: - dl = 1; - break; - case SASL_LOG_FAIL: - dl = 2; - break; - case SASL_LOG_WARN: - dl = 3; - break; - case SASL_LOG_NOTE: - dl = 5; - break; - case SASL_LOG_DEBUG: - dl = 10; - break; - case SASL_LOG_TRACE: - dl = 11; - break; -#if DEBUG_PASSWORD - case SASL_LOG_PASS: - dl = 100; - break; -#endif - default: - dl = 0; - break; - } - DEBUG(dl, ("gensec_sasl: %s\n", message)); - - return SASL_OK; -} - -NTSTATUS gensec_sasl_init(void) -{ - NTSTATUS ret; - int sasl_ret; -#if 0 - int i; - const char **sasl_mechs; -#endif - - static const sasl_callback_t callbacks[] = { - { - .id = SASL_CB_LOG, - .proc = gensec_sasl_log, - .context = NULL, - }, - { - .id = SASL_CB_LIST_END, - .proc = gensec_sasl_log, - .context = NULL, - } - }; - sasl_ret = sasl_client_init(callbacks); - - if (sasl_ret == SASL_NOMECH) { - /* Nothing to do here */ - return NT_STATUS_OK; - } - - if (sasl_ret != SASL_OK) { - return sasl_nt_status(sasl_ret); - } - - /* For now, we just register DIGEST-MD5 */ -#if 1 - ret = gensec_register(&gensec_sasl_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_sasl_security_ops.name)); - return ret; - } -#else - sasl_mechs = sasl_global_listmech(); - for (i = 0; sasl_mechs && sasl_mechs[i]; i++) { - const struct gensec_security_ops *oldmech; - struct gensec_security_ops *newmech; - oldmech = gensec_security_by_sasl_name(NULL, sasl_mechs[i]); - if (oldmech) { - continue; - } - newmech = talloc(talloc_autofree_context(), struct gensec_security_ops); - if (!newmech) { - return NT_STATUS_NO_MEMORY; - } - *newmech = gensec_sasl_security_ops; - newmech->sasl_name = talloc_strdup(newmech, sasl_mechs[i]); - newmech->name = talloc_asprintf(newmech, "sasl-%s", sasl_mechs[i]); - if (!newmech->sasl_name || !newmech->name) { - return NT_STATUS_NO_MEMORY; - } - - ret = gensec_register(newmech); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_sasl_security_ops.name)); - return ret; - } - } -#endif - return NT_STATUS_OK; -} diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index 514d4238d58..15685a88340 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -42,6 +42,7 @@ #include "gensec_gssapi.h" #include "lib/util/util_net.h" #include "auth/kerberos/pac_utils.h" +#include "auth/kerberos/gssapi_helper.h" #ifndef gss_mech_spnego gss_OID_desc spnego_mech_oid_desc = @@ -53,67 +54,35 @@ _PUBLIC_ NTSTATUS gensec_gssapi_init(void); static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security); static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security); +static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size); static int gensec_gssapi_destructor(struct gensec_gssapi_state *gensec_gssapi_state) { - OM_uint32 maj_stat, min_stat; - + OM_uint32 min_stat; + if (gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) { - maj_stat = gss_release_cred(&min_stat, - &gensec_gssapi_state->delegated_cred_handle); + gss_release_cred(&min_stat, + &gensec_gssapi_state->delegated_cred_handle); } if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) { - maj_stat = gss_delete_sec_context (&min_stat, - &gensec_gssapi_state->gssapi_context, - GSS_C_NO_BUFFER); + gss_delete_sec_context(&min_stat, + &gensec_gssapi_state->gssapi_context, + GSS_C_NO_BUFFER); } if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) { - maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name); + gss_release_name(&min_stat, + &gensec_gssapi_state->server_name); } if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) { - maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name); - } - - if (gensec_gssapi_state->lucid) { - gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid); + gss_release_name(&min_stat, + &gensec_gssapi_state->client_name); } return 0; } -static NTSTATUS gensec_gssapi_init_lucid(struct gensec_gssapi_state *gensec_gssapi_state) -{ - OM_uint32 maj_stat, min_stat; - - if (gensec_gssapi_state->lucid) { - return NT_STATUS_OK; - } - - maj_stat = gss_krb5_export_lucid_sec_context(&min_stat, - &gensec_gssapi_state->gssapi_context, - 1, - (void **)&gensec_gssapi_state->lucid); - if (maj_stat != GSS_S_COMPLETE) { - DEBUG(0,("gensec_gssapi_init_lucid: %s\n", - gssapi_error_string(gensec_gssapi_state, - maj_stat, min_stat, - gensec_gssapi_state->gss_oid))); - return NT_STATUS_INTERNAL_ERROR; - } - - if (gensec_gssapi_state->lucid->version != 1) { - DEBUG(0,("gensec_gssapi_init_lucid: lucid version[%d] != 1\n", - gensec_gssapi_state->lucid->version)); - gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid); - gensec_gssapi_state->lucid = NULL; - return NT_STATUS_INTERNAL_ERROR; - } - - return NT_STATUS_OK; -} - static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security) { struct gensec_gssapi_state *gensec_gssapi_state; @@ -191,8 +160,6 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security) gensec_gssapi_state->client_cred = NULL; gensec_gssapi_state->server_cred = NULL; - gensec_gssapi_state->lucid = NULL; - gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL; gensec_gssapi_state->sasl = false; @@ -303,6 +270,7 @@ static NTSTATUS gensec_gssapi_client_creds(struct gensec_security *gensec_securi return NT_STATUS_INVALID_PARAMETER; case KRB5KDC_ERR_PREAUTH_FAILED: case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: + case KRB5KRB_AP_ERR_BAD_INTEGRITY: DEBUG(1, ("Wrong username or password: %s\n", error_string)); return NT_STATUS_LOGON_FAILURE; case KRB5KDC_ERR_CLIENT_REVOKED: @@ -524,7 +492,8 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length); gss_release_buffer(&min_stat2, &output_token); - if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG) { + if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG && + gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) { DEBUG(5, ("gensec_gssapi: credentials were delegated\n")); } else { DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n")); @@ -1028,53 +997,30 @@ static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_securit { struct gensec_gssapi_state *gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state); - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token, output_token; - int conf_state; - ssize_t sig_length; + bool hdr_signing = false; + size_t sig_size = 0; + NTSTATUS status; if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) { - DEBUG(1, ("gensec_gssapi_seal_packet: " - "GENSEC_FEATURE_SIGN_PKT_HEADER not supported\n")); - return NT_STATUS_ACCESS_DENIED; + hdr_signing = true; } - input_token.length = length; - input_token.value = data; - - maj_stat = gss_wrap(&min_stat, - gensec_gssapi_state->gssapi_context, - gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL), - GSS_C_QOP_DEFAULT, - &input_token, - &conf_state, - &output_token); - if (GSS_ERROR(maj_stat)) { - DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n", - gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid))); - return NT_STATUS_ACCESS_DENIED; - } + sig_size = gensec_gssapi_sig_size(gensec_security, length); - if (output_token.length < input_token.length) { - DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%ld] *less* than caller length [%ld]\n", - (long)output_token.length, (long)length)); - return NT_STATUS_INTERNAL_ERROR; + status = gssapi_seal_packet(gensec_gssapi_state->gssapi_context, + gensec_gssapi_state->gss_oid, + hdr_signing, sig_size, + data, length, + whole_pdu, pdu_length, + mem_ctx, sig); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%ju," + "data=%ju,pdu=%ju) failed: %s\n", + hdr_signing, sig_size, length, pdu_length, + nt_errstr(status))); + return status; } - sig_length = output_token.length - input_token.length; - - memcpy(data, ((uint8_t *)output_token.value) + sig_length, length); - *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length); - dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length); - dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length); - dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length); - - gss_release_buffer(&min_stat, &output_token); - - if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) - && !conf_state) { - return NT_STATUS_ACCESS_DENIED; - } return NT_STATUS_OK; } @@ -1085,55 +1031,27 @@ static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_secur { struct gensec_gssapi_state *gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state); - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token, output_token; - int conf_state; - gss_qop_t qop_state; - DATA_BLOB in; - - dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length); + bool hdr_signing = false; + NTSTATUS status; if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) { - DEBUG(1, ("gensec_gssapi_unseal_packet: " - "GENSEC_FEATURE_SIGN_PKT_HEADER not supported\n")); - return NT_STATUS_ACCESS_DENIED; - } - - in = data_blob_talloc(gensec_security, NULL, sig->length + length); - - memcpy(in.data, sig->data, sig->length); - memcpy(in.data + sig->length, data, length); - - input_token.length = in.length; - input_token.value = in.data; - - maj_stat = gss_unwrap(&min_stat, - gensec_gssapi_state->gssapi_context, - &input_token, - &output_token, - &conf_state, - &qop_state); - talloc_free(in.data); - if (GSS_ERROR(maj_stat)) { - char *error_string = gssapi_error_string(NULL, maj_stat, min_stat, gensec_gssapi_state->gss_oid); - DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n", - error_string)); - talloc_free(error_string); - return NT_STATUS_ACCESS_DENIED; + hdr_signing = true; } - if (output_token.length != length) { - return NT_STATUS_INTERNAL_ERROR; + status = gssapi_unseal_packet(gensec_gssapi_state->gssapi_context, + gensec_gssapi_state->gss_oid, + hdr_signing, + data, length, + whole_pdu, pdu_length, + sig); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%ju," + "data=%ju,pdu=%ju) failed: %s\n", + hdr_signing, sig->length, length, pdu_length, + nt_errstr(status))); + return status; } - memcpy(data, output_token.value, length); - - gss_release_buffer(&min_stat, &output_token); - - if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) - && !conf_state) { - return NT_STATUS_ACCESS_DENIED; - } return NT_STATUS_OK; } @@ -1145,34 +1063,27 @@ static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_securit { struct gensec_gssapi_state *gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state); - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token, output_token; + bool hdr_signing = false; + NTSTATUS status; if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) { - input_token.length = pdu_length; - input_token.value = discard_const_p(uint8_t *, whole_pdu); - } else { - input_token.length = length; - input_token.value = discard_const_p(uint8_t *, data); + hdr_signing = true; } - maj_stat = gss_get_mic(&min_stat, - gensec_gssapi_state->gssapi_context, - GSS_C_QOP_DEFAULT, - &input_token, - &output_token); - if (GSS_ERROR(maj_stat)) { - DEBUG(1, ("GSS GetMic failed: %s\n", - gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid))); - return NT_STATUS_ACCESS_DENIED; + status = gssapi_sign_packet(gensec_gssapi_state->gssapi_context, + gensec_gssapi_state->gss_oid, + hdr_signing, + data, length, + whole_pdu, pdu_length, + mem_ctx, sig); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u," + "data=%ju,pdu=%ju) failed: %s\n", + hdr_signing, length, pdu_length, + nt_errstr(status))); + return status; } - *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, output_token.length); - - dump_data_pw("gensec_gssapi_sign_packet: sig\n", sig->data, sig->length); - - gss_release_buffer(&min_stat, &output_token); - return NT_STATUS_OK; } @@ -1183,35 +1094,25 @@ static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_securi { struct gensec_gssapi_state *gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state); - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token; - gss_buffer_desc input_message; - gss_qop_t qop_state; - - dump_data_pw("gensec_gssapi_check_packet: sig\n", sig->data, sig->length); + bool hdr_signing = false; + NTSTATUS status; if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) { - input_message.length = pdu_length; - input_message.value = discard_const(whole_pdu); - } else { - input_message.length = length; - input_message.value = discard_const(data); + hdr_signing = true; } - input_token.length = sig->length; - input_token.value = sig->data; - - maj_stat = gss_verify_mic(&min_stat, - gensec_gssapi_state->gssapi_context, - &input_message, - &input_token, - &qop_state); - if (GSS_ERROR(maj_stat)) { - char *error_string = gssapi_error_string(NULL, maj_stat, min_stat, gensec_gssapi_state->gss_oid); - DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string)); - talloc_free(error_string); - - return NT_STATUS_ACCESS_DENIED; + status = gssapi_check_packet(gensec_gssapi_state->gssapi_context, + gensec_gssapi_state->gss_oid, + hdr_signing, + data, length, + whole_pdu, pdu_length, + sig); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%ju," + "data=%ju,pdu=%ju) failed: %s\n", + hdr_signing, sig->length, length, pdu_length, + nt_errstr(status))); + return status; } return NT_STATUS_OK; @@ -1294,8 +1195,7 @@ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security, } if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) { if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { - /* TODO: implement this using gss_wrap_iov() */ - return false; + return true; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { @@ -1402,9 +1302,8 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi return nt_status; } - if (!(gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG)) { - DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n")); - } else { + if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG && + gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) { krb5_error_code ret; const char *error_string; @@ -1434,7 +1333,10 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi /* It has been taken from this place... */ gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL; + } else { + DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n")); } + *_session_info = talloc_steal(mem_ctx, session_info); talloc_free(tmp_ctx); @@ -1445,56 +1347,18 @@ static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, si { struct gensec_gssapi_state *gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state); - NTSTATUS status; - - if (gensec_gssapi_state->sig_size) { - return gensec_gssapi_state->sig_size; - } - - if (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG) { - gensec_gssapi_state->sig_size = 45; - } else { - gensec_gssapi_state->sig_size = 37; - } + size_t sig_size; - status = gensec_gssapi_init_lucid(gensec_gssapi_state); - if (!NT_STATUS_IS_OK(status)) { + if (gensec_gssapi_state->sig_size > 0) { return gensec_gssapi_state->sig_size; } - if (gensec_gssapi_state->lucid->protocol == 1) { - if (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG) { - /* - * TODO: windows uses 76 here, but we don't know - * gss_wrap works with aes keys yet - */ - gensec_gssapi_state->sig_size = 76; - } else { - gensec_gssapi_state->sig_size = 28; - } - } else if (gensec_gssapi_state->lucid->protocol == 0) { - switch (gensec_gssapi_state->lucid->rfc1964_kd.ctx_key.type) { - case ENCTYPE_DES_CBC_CRC: - case ENCTYPE_ARCFOUR_HMAC: - case ENCTYPE_ARCFOUR_HMAC_EXP: - if (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG) { - gensec_gssapi_state->sig_size = 45; - } else { - gensec_gssapi_state->sig_size = 37; - } - break; -#ifdef SAMBA4_USES_HEIMDAL - case ENCTYPE_OLD_DES3_CBC_SHA1: - if (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG) { - gensec_gssapi_state->sig_size = 57; - } else { - gensec_gssapi_state->sig_size = 49; - } - break; -#endif - } - } + sig_size = gssapi_get_sig_size(gensec_gssapi_state->gssapi_context, + gensec_gssapi_state->gss_oid, + gensec_gssapi_state->gss_want_flags, + data_size); + gensec_gssapi_state->sig_size = sig_size; return gensec_gssapi_state->sig_size; } @@ -1525,6 +1389,8 @@ static const struct gensec_security_ops gensec_gssapi_spnego_security_ops = { .check_packet = gensec_gssapi_check_packet, .seal_packet = gensec_gssapi_seal_packet, .unseal_packet = gensec_gssapi_unseal_packet, + .max_input_size = gensec_gssapi_max_input_size, + .max_wrapped_size = gensec_gssapi_max_wrapped_size, .wrap = gensec_gssapi_wrap, .unwrap = gensec_gssapi_unwrap, .have_feature = gensec_gssapi_have_feature, @@ -1550,6 +1416,8 @@ static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = { .check_packet = gensec_gssapi_check_packet, .seal_packet = gensec_gssapi_seal_packet, .unseal_packet = gensec_gssapi_unseal_packet, + .max_input_size = gensec_gssapi_max_input_size, + .max_wrapped_size = gensec_gssapi_max_wrapped_size, .wrap = gensec_gssapi_wrap, .unwrap = gensec_gssapi_unwrap, .have_feature = gensec_gssapi_have_feature, diff --git a/source4/auth/gensec/gensec_gssapi.h b/source4/auth/gensec/gensec_gssapi.h index b7429b5f48d..cf0e3a8d914 100644 --- a/source4/auth/gensec/gensec_gssapi.h +++ b/source4/auth/gensec/gensec_gssapi.h @@ -46,7 +46,6 @@ struct gensec_gssapi_state { NTTIME expire_time; /* gensec_gssapi only */ - gss_krb5_lucid_context_v1_t *lucid; gss_OID gss_oid; struct gss_channel_bindings_struct *input_chan_bindings; diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c index c34c43425e4..5d2f8b87ddc 100644 --- a/source4/auth/gensec/gensec_krb5.c +++ b/source4/auth/gensec/gensec_krb5.c @@ -27,7 +27,6 @@ #include "system/kerberos.h" #include "auth/kerberos/kerberos.h" #include "auth/auth.h" -#include "lib/socket/socket.h" #include "lib/tsocket/tsocket.h" #include "librpc/gen_ndr/dcerpc.h" #include "auth/credentials/credentials.h" @@ -418,14 +417,17 @@ static DATA_BLOB gensec_gssapi_gen_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLO if (!asn1_pop_tag(data)) goto err; - ret = data_blob_talloc(mem_ctx, data->data, data->length); + if (!asn1_extract_blob(data, mem_ctx, &ret)) { + goto err; + } asn1_free(data); return ret; err: - DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data->ofs)); + DEBUG(1, ("Failed to build krb5 wrapper at offset %d\n", + (int)asn1_current_ofs(data))); asn1_free(data); return ret; } @@ -450,7 +452,7 @@ static bool gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB * data_remaining = asn1_tag_remaining(data); if (data_remaining < 3) { - data->has_error = true; + asn1_set_error(data); } else { if (!asn1_read(data, tok_id, 2)) goto err; data_remaining -= 2; @@ -460,7 +462,7 @@ static bool gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB * if (!asn1_end_tag(data)) goto err; - ret = !data->has_error; + ret = !asn1_has_error(data); err: diff --git a/source4/auth/gensec/gensec_socket.h b/source4/auth/gensec/gensec_socket.h deleted file mode 100644 index bb12cc00ead..00000000000 --- a/source4/auth/gensec/gensec_socket.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - GENSEC socket interface - - Copyright (C) Andrew Bartlett 2006 - - 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 3 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, see <http://www.gnu.org/licenses/>. -*/ - -NTSTATUS gensec_socket_init(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - struct socket_context *current_socket, - struct tevent_context *ev, - void (*recv_handler)(void *, uint16_t), - void *recv_private, - struct socket_context **new_socket); diff --git a/source4/auth/gensec/pygensec.c b/source4/auth/gensec/pygensec.c index 83864e65af2..a6be0cbe25b 100644 --- a/source4/auth/gensec/pygensec.c +++ b/source4/auth/gensec/pygensec.c @@ -504,6 +504,83 @@ static PyObject *py_gensec_unwrap(PyObject *self, PyObject *args) return ret; } +static PyObject *py_gensec_sig_size(PyObject *self, PyObject *args) +{ + struct gensec_security *security = pytalloc_get_type(self, struct gensec_security); + Py_ssize_t data_size = 0; + size_t sig_size = 0; + + if (!PyArg_ParseTuple(args, "n", &data_size)) { + return NULL; + } + + sig_size = gensec_sig_size(security, data_size); + + return PyLong_FromSize_t(sig_size); +} + +static PyObject *py_gensec_sign_packet(PyObject *self, PyObject *args) +{ + NTSTATUS status; + TALLOC_CTX *mem_ctx = NULL; + Py_ssize_t data_length = 0; + Py_ssize_t pdu_length = 0; + DATA_BLOB data, pdu, sig; + PyObject *py_sig; + struct gensec_security *security = pytalloc_get_type(self, struct gensec_security); + + if (!PyArg_ParseTuple(args, "z#z#", &data.data, &data_length, &pdu.data, &pdu_length)) { + return NULL; + } + data.length = data_length; + pdu.length = pdu_length; + + mem_ctx = talloc_new(NULL); + + status = gensec_sign_packet(security, mem_ctx, + data.data, data.length, + pdu.data, pdu.length, &sig); + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetNTSTATUS(status); + talloc_free(mem_ctx); + return NULL; + } + + py_sig = PyBytes_FromStringAndSize((const char *)sig.data, sig.length); + talloc_free(mem_ctx); + return py_sig; +} + +static PyObject *py_gensec_check_packet(PyObject *self, PyObject *args) +{ + NTSTATUS status; + Py_ssize_t data_length = 0; + Py_ssize_t pdu_length = 0; + Py_ssize_t sig_length = 0; + DATA_BLOB data, pdu, sig; + struct gensec_security *security = pytalloc_get_type(self, struct gensec_security); + + if (!PyArg_ParseTuple(args, "z#z#z#", + &data.data, &data_length, + &pdu.data, &pdu_length, + &sig.data, &sig_length)) { + return NULL; + } + data.length = data_length; + pdu.length = pdu_length; + sig.length = sig_length; + + status = gensec_check_packet(security, + data.data, data.length, + pdu.data, pdu.length, &sig); + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetNTSTATUS(status); + return NULL; + } + + Py_RETURN_NONE; +} + static PyMethodDef py_gensec_security_methods[] = { { "start_client", (PyCFunction)py_gensec_start_client, METH_VARARGS|METH_KEYWORDS|METH_CLASS, "S.start_client(settings) -> gensec" }, @@ -537,6 +614,12 @@ static PyMethodDef py_gensec_security_methods[] = { "S.wrap(blob_in) -> blob_out\nPackage one clear packet into a wrapped GENSEC packet." }, { "unwrap", (PyCFunction)py_gensec_unwrap, METH_VARARGS, "S.unwrap(blob_in) -> blob_out\nPerform one wrapped GENSEC packet into a clear packet." }, + { "sig_size", (PyCFunction)py_gensec_sig_size, METH_VARARGS, + "S.sig_size(data_size) -> sig_size\nSize of the DCERPC packet signature" }, + { "sign_packet", (PyCFunction)py_gensec_sign_packet, METH_VARARGS, + "S.sign_packet(data, whole_pdu) -> sig\nSign a DCERPC packet." }, + { "check_packet", (PyCFunction)py_gensec_check_packet, METH_VARARGS, + "S.check_packet(data, whole_pdu, sig)\nCheck a DCERPC packet." }, { NULL } }; diff --git a/source4/auth/gensec/socket.c b/source4/auth/gensec/socket.c deleted file mode 100644 index c89e0802323..00000000000 --- a/source4/auth/gensec/socket.c +++ /dev/null @@ -1,435 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - GENSEC socket interface - - Copyright (C) Andrew Bartlett 2006 - - 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 3 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "lib/events/events.h" -#include "lib/socket/socket.h" -#include "lib/stream/packet.h" -#include "auth/gensec/gensec.h" -#include "auth/gensec/gensec_proto.h" -#include "auth/gensec/gensec_socket.h" - -static const struct socket_ops gensec_socket_ops; - -struct gensec_socket { - struct gensec_security *gensec_security; - struct socket_context *socket; - struct tevent_context *ev; - struct packet_context *packet; - DATA_BLOB read_buffer; /* SASL packets are turned into liniarlised data here, for reading */ - size_t orig_send_len; - bool eof; - NTSTATUS error; - bool interrupted; - void (*recv_handler)(void *, uint16_t); - void *recv_private; - int in_extra_read; - bool wrap; /* Should we be wrapping on this socket at all? */ -}; - -static NTSTATUS gensec_socket_init_fn(struct socket_context *sock) -{ - switch (sock->type) { - case SOCKET_TYPE_STREAM: - break; - default: - return NT_STATUS_INVALID_PARAMETER; - } - - sock->backend_name = "gensec"; - - return NT_STATUS_OK; -} - -static NTSTATUS gensec_socket_full_request(void *private_data, DATA_BLOB blob, size_t *size) -{ - struct gensec_socket *gensec_socket = talloc_get_type(private_data, struct gensec_socket); - struct gensec_security *gensec_security = gensec_socket->gensec_security; - return gensec_packet_full_request(gensec_security, blob, size); -} - -/* Try to figure out how much data is waiting to be read */ -static NTSTATUS gensec_socket_pending(struct socket_context *sock, size_t *npending) -{ - struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket); - if (!gensec_socket->wrap) { - return socket_pending(gensec_socket->socket, npending); - } - - if (gensec_socket->read_buffer.length > 0) { - *npending = gensec_socket->read_buffer.length; - return NT_STATUS_OK; - } - - /* This is a lie. We hope the decrypted data will always be - * less than this value, so the application just gets a short - * read. Without reading and decrypting it, we can't tell. - * If the SASL mech does compression, then we just need to - * manually trigger read events */ - return socket_pending(gensec_socket->socket, npending); -} - -/* Note if an error occours, so we can return it up the stack */ -static void gensec_socket_error_handler(void *private_data, NTSTATUS status) -{ - struct gensec_socket *gensec_socket = talloc_get_type(private_data, struct gensec_socket); - if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) { - gensec_socket->eof = true; - } else { - gensec_socket->error = status; - } -} - -static void gensec_socket_trigger_read(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval t, void *private_data) -{ - struct gensec_socket *gensec_socket = talloc_get_type(private_data, struct gensec_socket); - - gensec_socket->in_extra_read++; - gensec_socket->recv_handler(gensec_socket->recv_private, TEVENT_FD_READ); - gensec_socket->in_extra_read--; - - /* It may well be that, having run the recv handler, we still - * have even more data waiting for us! - */ - if (gensec_socket->read_buffer.length > 0) { - /* Schedule this funcion to run again */ - tevent_add_timer(gensec_socket->ev, gensec_socket, timeval_zero(), - gensec_socket_trigger_read, gensec_socket); - } -} - -/* These two routines could be changed to use a circular buffer of - * some kind, or linked lists, or ... */ -static NTSTATUS gensec_socket_recv(struct socket_context *sock, void *buf, - size_t wantlen, size_t *nread) -{ - struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket); - - if (!gensec_socket->wrap) { - return socket_recv(gensec_socket->socket, buf, wantlen, nread); - } - - gensec_socket->error = NT_STATUS_OK; - - if (gensec_socket->read_buffer.length == 0) { - /* Process any data on the socket, into the read buffer. At - * this point, the socket is not available for read any - * longer */ - packet_recv(gensec_socket->packet); - - if (gensec_socket->eof) { - *nread = 0; - return NT_STATUS_OK; - } - - if (!NT_STATUS_IS_OK(gensec_socket->error)) { - return gensec_socket->error; - } - - if (gensec_socket->read_buffer.length == 0) { - /* Clearly we don't have the entire SASL packet yet, - * so it has not been written into the buffer */ - *nread = 0; - return STATUS_MORE_ENTRIES; - } - } - - - *nread = MIN(wantlen, gensec_socket->read_buffer.length); - memcpy(buf, gensec_socket->read_buffer.data, *nread); - - if (gensec_socket->read_buffer.length > *nread) { - memmove(gensec_socket->read_buffer.data, - gensec_socket->read_buffer.data + *nread, - gensec_socket->read_buffer.length - *nread); - } - - gensec_socket->read_buffer.length -= *nread; - gensec_socket->read_buffer.data = talloc_realloc(gensec_socket, - gensec_socket->read_buffer.data, - uint8_t, - gensec_socket->read_buffer.length); - - if (gensec_socket->read_buffer.length && - gensec_socket->in_extra_read == 0 && - gensec_socket->recv_handler) { - /* Manually call a read event, to get this moving - * again (as the socket should be dry, so the normal - * event handler won't trigger) */ - tevent_add_timer(gensec_socket->ev, gensec_socket, timeval_zero(), - gensec_socket_trigger_read, gensec_socket); - } - - return NT_STATUS_OK; -} - -/* Completed SASL packet callback. When we have a 'whole' SASL - * packet, decrypt it, and add it to the read buffer - * - * This function (and anything under it) MUST NOT call the event system - */ -static NTSTATUS gensec_socket_unwrap(void *private_data, DATA_BLOB blob) -{ - struct gensec_socket *gensec_socket = talloc_get_type(private_data, struct gensec_socket); - DATA_BLOB unwrapped; - NTSTATUS nt_status; - TALLOC_CTX *mem_ctx; - size_t packet_size; - - mem_ctx = talloc_new(gensec_socket); - if (!mem_ctx) { - return NT_STATUS_NO_MEMORY; - } - nt_status = gensec_unwrap_packets(gensec_socket->gensec_security, - mem_ctx, - &blob, &unwrapped, - &packet_size); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(mem_ctx); - return nt_status; - } - - if (packet_size != blob.length) { - DEBUG(0, ("gensec_socket_unwrap: Did not consume entire packet!\n")); - talloc_free(mem_ctx); - return NT_STATUS_INTERNAL_ERROR; - } - - /* We could change this into a linked list, and have - * gensec_socket_recv() and gensec_socket_pending() walk the - * linked list */ - - if (!data_blob_append(gensec_socket, &gensec_socket->read_buffer, - unwrapped.data, unwrapped.length)) { - talloc_free(mem_ctx); - return NT_STATUS_NO_MEMORY; - } - - talloc_free(mem_ctx); - return NT_STATUS_OK; -} - -/* when the data is sent, we know we have not been interrupted */ -static void send_callback(void *private_data) -{ - struct gensec_socket *gensec_socket = talloc_get_type(private_data, struct gensec_socket); - gensec_socket->interrupted = false; -} - -/* - send data, but only as much as we allow in one packet. - - If this returns STATUS_MORE_ENTRIES, the caller must retry with - exactly the same data, or a NULL blob. -*/ -static NTSTATUS gensec_socket_send(struct socket_context *sock, - const DATA_BLOB *blob, size_t *sendlen) -{ - NTSTATUS nt_status; - struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket); - DATA_BLOB wrapped; - TALLOC_CTX *mem_ctx; - - if (!gensec_socket->wrap) { - return socket_send(gensec_socket->socket, blob, sendlen); - } - - *sendlen = 0; - - /* We have have been interupted, so the caller should be - * giving us the same data again. */ - if (gensec_socket->interrupted) { - packet_queue_run(gensec_socket->packet); - - if (!NT_STATUS_IS_OK(gensec_socket->error)) { - return gensec_socket->error; - } else if (gensec_socket->interrupted) { - return STATUS_MORE_ENTRIES; - } else { - *sendlen = gensec_socket->orig_send_len; - gensec_socket->orig_send_len = 0; - return NT_STATUS_OK; - } - } - - mem_ctx = talloc_new(gensec_socket); - if (!mem_ctx) { - return NT_STATUS_NO_MEMORY; - } - - nt_status = gensec_wrap_packets(gensec_socket->gensec_security, - mem_ctx, - blob, &wrapped, - &gensec_socket->orig_send_len); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(mem_ctx); - return nt_status; - } - - gensec_socket->interrupted = true; - gensec_socket->error = NT_STATUS_OK; - - nt_status = packet_send_callback(gensec_socket->packet, - wrapped, - send_callback, gensec_socket); - - talloc_free(mem_ctx); - - packet_queue_run(gensec_socket->packet); - - if (!NT_STATUS_IS_OK(gensec_socket->error)) { - return gensec_socket->error; - } else if (gensec_socket->interrupted) { - return STATUS_MORE_ENTRIES; - } else { - *sendlen = gensec_socket->orig_send_len; - gensec_socket->orig_send_len = 0; - return NT_STATUS_OK; - } -} - -/* Turn a normal socket into a potentially GENSEC wrapped socket */ -/* CAREFUL: this function will steal 'current_socket' */ - -NTSTATUS gensec_socket_init(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - struct socket_context *current_socket, - struct tevent_context *ev, - void (*recv_handler)(void *, uint16_t), - void *recv_private, - struct socket_context **new_socket) -{ - struct gensec_socket *gensec_socket; - struct socket_context *new_sock; - NTSTATUS nt_status; - - nt_status = socket_create_with_ops(mem_ctx, &gensec_socket_ops, &new_sock, - SOCKET_TYPE_STREAM, current_socket->flags | SOCKET_FLAG_ENCRYPT); - if (!NT_STATUS_IS_OK(nt_status)) { - *new_socket = NULL; - return nt_status; - } - - new_sock->state = current_socket->state; - - gensec_socket = talloc(new_sock, struct gensec_socket); - if (gensec_socket == NULL) { - *new_socket = NULL; - talloc_free(new_sock); - return NT_STATUS_NO_MEMORY; - } - - new_sock->private_data = gensec_socket; - gensec_socket->socket = current_socket; - - /* Nothing to do here, if we are not actually wrapping on this socket */ - if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) && - !gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - - gensec_socket->wrap = false; - talloc_steal(gensec_socket, current_socket); - *new_socket = new_sock; - return NT_STATUS_OK; - } - - gensec_socket->gensec_security = gensec_security; - - gensec_socket->wrap = true; - gensec_socket->eof = false; - gensec_socket->error = NT_STATUS_OK; - gensec_socket->interrupted = false; - gensec_socket->in_extra_read = 0; - - gensec_socket->read_buffer = data_blob(NULL, 0); - - gensec_socket->recv_handler = recv_handler; - gensec_socket->recv_private = recv_private; - gensec_socket->ev = ev; - - gensec_socket->packet = packet_init(gensec_socket); - if (gensec_socket->packet == NULL) { - *new_socket = NULL; - talloc_free(new_sock); - return NT_STATUS_NO_MEMORY; - } - - packet_set_private(gensec_socket->packet, gensec_socket); - packet_set_socket(gensec_socket->packet, gensec_socket->socket); - packet_set_callback(gensec_socket->packet, gensec_socket_unwrap); - packet_set_full_request(gensec_socket->packet, gensec_socket_full_request); - packet_set_error_handler(gensec_socket->packet, gensec_socket_error_handler); - packet_set_serialise(gensec_socket->packet); - - /* TODO: full-request that knows about maximum packet size */ - - talloc_steal(gensec_socket, current_socket); - *new_socket = new_sock; - return NT_STATUS_OK; -} - - -static NTSTATUS gensec_socket_set_option(struct socket_context *sock, const char *option, const char *val) -{ - set_socket_options(socket_get_fd(sock), option); - return NT_STATUS_OK; -} - -static char *gensec_socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx) -{ - struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket); - return socket_get_peer_name(gensec->socket, mem_ctx); -} - -static struct socket_address *gensec_socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) -{ - struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket); - return socket_get_peer_addr(gensec->socket, mem_ctx); -} - -static struct socket_address *gensec_socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) -{ - struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket); - return socket_get_my_addr(gensec->socket, mem_ctx); -} - -static int gensec_socket_get_fd(struct socket_context *sock) -{ - struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket); - return socket_get_fd(gensec->socket); -} - -static const struct socket_ops gensec_socket_ops = { - .name = "gensec", - .fn_init = gensec_socket_init_fn, - .fn_recv = gensec_socket_recv, - .fn_send = gensec_socket_send, - .fn_pending = gensec_socket_pending, - - .fn_set_option = gensec_socket_set_option, - - .fn_get_peer_name = gensec_socket_get_peer_name, - .fn_get_peer_addr = gensec_socket_get_peer_addr, - .fn_get_my_addr = gensec_socket_get_my_addr, - .fn_get_fd = gensec_socket_get_fd -}; - diff --git a/source4/auth/gensec/wscript_build b/source4/auth/gensec/wscript_build index 1a44a9072c3..3c7cc2e12b4 100755 --- a/source4/auth/gensec/wscript_build +++ b/source4/auth/gensec/wscript_build @@ -1,7 +1,7 @@ #!/usr/bin/env python bld.SAMBA_SUBSYSTEM('gensec_util', - source='socket.c gensec_tstream.c', + source='gensec_tstream.c', deps='tevent-util tevent samba-util LIBTSOCKET', autoproto='gensec_proto.h') @@ -19,21 +19,9 @@ bld.SAMBA_MODULE('gensec_gssapi', source='gensec_gssapi.c', subsystem='gensec', init_function='gensec_gssapi_init', - allow_warnings=True, deps='gssapi samba-credentials authkrb5 com_err gensec_util' ) - -bld.SAMBA_MODULE('cyrus_sasl', - source='cyrus_sasl.c', - subsystem='gensec', - init_function='gensec_sasl_init', - deps='samba-credentials sasl2', - allow_warnings=True, - enabled=bld.CONFIG_SET('HAVE_SASL') - ) - - bld.SAMBA_PYTHON('pygensec', source='pygensec.c', deps='gensec pytalloc-util pyparam_util', diff --git a/source4/auth/ntlm/auth_util.c b/source4/auth/ntlm/auth_util.c index 16977fa00a3..3e5a0da59c2 100644 --- a/source4/auth/ntlm/auth_util.c +++ b/source4/auth/ntlm/auth_util.c @@ -350,7 +350,9 @@ NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth4_context *auth_conte if (!SMBNTLMv2encrypt_hash(user_info_temp, user_info_in->client.account_name, user_info_in->client.domain_name, - user_info_in->password.hash.nt->hash, &chall_blob, + user_info_in->password.hash.nt->hash, + &chall_blob, + NULL, /* server_timestamp */ &names_blob, &lmv2_response, &ntlmv2_response, &lmv2_session_key, &ntlmv2_session_key)) { diff --git a/source4/auth/wscript_configure b/source4/auth/wscript_configure index 1d26cde1398..d25cc0b359d 100644 --- a/source4/auth/wscript_configure +++ b/source4/auth/wscript_configure @@ -2,7 +2,3 @@ conf.CHECK_HEADERS('security/pam_appl.h') conf.CHECK_FUNCS_IN('pam_start', 'pam', checklibc=True) - -if (conf.CHECK_HEADERS('sasl/sasl.h') and - conf.CHECK_FUNCS_IN('sasl_client_init', 'sasl2')): - conf.DEFINE('HAVE_SASL', 1) diff --git a/source4/dsdb/tests/python/dsdb_schema_info.py b/source4/dsdb/tests/python/dsdb_schema_info.py index 28fce1b00f4..8f64f1063c0 100755 --- a/source4/dsdb/tests/python/dsdb_schema_info.py +++ b/source4/dsdb/tests/python/dsdb_schema_info.py @@ -30,8 +30,7 @@ import time import random sys.path.insert(0, "bin/python") -import samba -samba.ensure_external_module("testtools", "testtools") +import samba.tests from ldb import SCOPE_BASE, LdbError diff --git a/source4/heimdal/lib/gssapi/krb5/aeap.c b/source4/heimdal/lib/gssapi/krb5/aeap.c index 47913e4aec0..fe95ecf0b9c 100644 --- a/source4/heimdal/lib/gssapi/krb5/aeap.c +++ b/source4/heimdal/lib/gssapi/krb5/aeap.c @@ -44,17 +44,43 @@ _gk_wrap_iov(OM_uint32 * minor_status, gss_iov_buffer_desc *iov, int iov_count) { - const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; - krb5_context context; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + krb5_context context; + OM_uint32 ret; + krb5_keyblock *key; + krb5_keytype keytype; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_cfx_iov(minor_status, ctx, context, + conf_req_flag, conf_state, + iov, iov_count); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype(context, key->keytype, &keytype); - GSSAPI_KRB5_INIT (&context); + switch (keytype) { + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = _gssapi_wrap_iov_arcfour(minor_status, ctx, context, + conf_req_flag, conf_state, + iov, iov_count, key); + break; - if (ctx->more_flags & IS_CFX) - return _gssapi_wrap_cfx_iov(minor_status, ctx, context, - conf_req_flag, conf_state, - iov, iov_count); + default: + ret = GSS_S_FAILURE; + break; + } - return GSS_S_FAILURE; + krb5_free_keyblock(context, key); + return ret; } OM_uint32 GSSAPI_CALLCONV @@ -67,6 +93,9 @@ _gk_unwrap_iov(OM_uint32 *minor_status, { const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; krb5_context context; + OM_uint32 ret; + krb5_keytype keytype; + krb5_keyblock *key; GSSAPI_KRB5_INIT (&context); @@ -74,7 +103,30 @@ _gk_unwrap_iov(OM_uint32 *minor_status, return _gssapi_unwrap_cfx_iov(minor_status, ctx, context, conf_state, qop_state, iov, iov_count); - return GSS_S_FAILURE; + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype(context, key->keytype, &keytype); + + switch (keytype) { + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = _gssapi_unwrap_iov_arcfour(minor_status, ctx, context, + conf_state, qop_state, + iov, iov_count, key); + break; + + default: + ret = GSS_S_FAILURE; + break; + } + + krb5_free_keyblock(context, key); + return ret; } OM_uint32 GSSAPI_CALLCONV @@ -88,6 +140,9 @@ _gk_wrap_iov_length(OM_uint32 * minor_status, { const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; krb5_context context; + OM_uint32 ret; + krb5_keytype keytype; + krb5_keyblock *key; GSSAPI_KRB5_INIT (&context); @@ -96,5 +151,28 @@ _gk_wrap_iov_length(OM_uint32 * minor_status, conf_req_flag, qop_req, conf_state, iov, iov_count); - return GSS_S_FAILURE; + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype(context, key->keytype, &keytype); + + switch (keytype) { + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = _gssapi_wrap_iov_length_arcfour(minor_status, ctx, context, + conf_req_flag, qop_req, conf_state, + iov, iov_count); + break; + + default: + ret = GSS_S_FAILURE; + break; + } + + krb5_free_keyblock(context, key); + return ret; } diff --git a/source4/heimdal/lib/gssapi/krb5/arcfour.c b/source4/heimdal/lib/gssapi/krb5/arcfour.c index f5e41e4056f..a61f7686e95 100644 --- a/source4/heimdal/lib/gssapi/krb5/arcfour.c +++ b/source4/heimdal/lib/gssapi/krb5/arcfour.c @@ -69,7 +69,7 @@ static krb5_error_code arcfour_mic_key(krb5_context context, krb5_keyblock *key, - void *cksum_data, size_t cksum_size, + const void *cksum_data, size_t cksum_size, void *key6_data, size_t key6_size) { krb5_error_code ret; @@ -112,30 +112,73 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key, static krb5_error_code -arcfour_mic_cksum(krb5_context context, - krb5_keyblock *key, unsigned usage, - u_char *sgn_cksum, size_t sgn_cksum_sz, - const u_char *v1, size_t l1, - const void *v2, size_t l2, - const void *v3, size_t l3) +arcfour_mic_cksum_iov(krb5_context context, + krb5_keyblock *key, unsigned usage, + u_char *sgn_cksum, size_t sgn_cksum_sz, + const u_char *v1, size_t l1, + const void *v2, size_t l2, + const gss_iov_buffer_desc *iov, + int iov_count, + const gss_iov_buffer_desc *padding) { Checksum CKSUM; u_char *ptr; size_t len; + size_t ofs = 0; + int i; krb5_crypto crypto; krb5_error_code ret; assert(sgn_cksum_sz == 8); - len = l1 + l2 + l3; + len = l1 + l2; + + for (i=0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + break; + default: + continue; + } + + len += iov[i].buffer.length; + } + + if (padding) { + len += padding->buffer.length; + } ptr = malloc(len); if (ptr == NULL) return ENOMEM; - memcpy(ptr, v1, l1); - memcpy(ptr + l1, v2, l2); - memcpy(ptr + l1 + l2, v3, l3); + memcpy(ptr + ofs, v1, l1); + ofs += l1; + memcpy(ptr + ofs, v2, l2); + ofs += l2; + + for (i=0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + break; + default: + continue; + } + + memcpy(ptr + ofs, + iov[i].buffer.value, + iov[i].buffer.length); + ofs += iov[i].buffer.length; + } + + if (padding) { + memcpy(ptr + ofs, + padding->buffer.value, + padding->buffer.length); + ofs += padding->buffer.length; + } ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) { @@ -149,6 +192,7 @@ arcfour_mic_cksum(krb5_context context, 0, ptr, len, &CKSUM); + memset(ptr, 0, len); free(ptr); if (ret == 0) { memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz); @@ -159,6 +203,26 @@ arcfour_mic_cksum(krb5_context context, return ret; } +static krb5_error_code +arcfour_mic_cksum(krb5_context context, + krb5_keyblock *key, unsigned usage, + u_char *sgn_cksum, size_t sgn_cksum_sz, + const u_char *v1, size_t l1, + const void *v2, size_t l2, + const void *v3, size_t l3) +{ + gss_iov_buffer_desc iov; + + iov.type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov.buffer.value = rk_UNCONST(v3); + iov.buffer.length = l3; + + return arcfour_mic_cksum_iov(context, key, usage, + sgn_cksum, sgn_cksum_sz, + v1, l1, v2, l2, + &iov, 1, NULL); +} + OM_uint32 _gssapi_get_mic_arcfour(OM_uint32 * minor_status, @@ -760,3 +824,562 @@ _gssapi_wrap_size_arcfour(OM_uint32 *minor_status, return GSS_S_COMPLETE; } + +OM_uint32 +_gssapi_wrap_iov_length_arcfour(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 major_status; + size_t data_len = 0; + int i; + gss_iov_buffer_desc *header = NULL; + gss_iov_buffer_desc *padding = NULL; + gss_iov_buffer_desc *trailer = NULL; + + *minor_status = 0; + + for (i = 0; i < iov_count; i++) { + switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_EMPTY: + break; + case GSS_IOV_BUFFER_TYPE_DATA: + data_len += iov[i].buffer.length; + break; + case GSS_IOV_BUFFER_TYPE_HEADER: + if (header != NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + header = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_TRAILER: + if (trailer != NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + trailer = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_PADDING: + if (padding != NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + padding = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + break; + default: + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + + major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + if (IS_DCE_STYLE(ctx)) { + size_t len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + size_t total_len; + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + header->buffer.length = total_len; + } else { + size_t len; + size_t total_len; + if (padding) { + data_len += 1; /* padding */ + } + len = data_len + GSS_ARCFOUR_WRAP_TOKEN_SIZE; + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + header->buffer.length = total_len - data_len; + } + + if (trailer) { + trailer->buffer.length = 0; + } + + if (padding) { + padding->buffer.length = 1; + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_wrap_iov_arcfour(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count, + krb5_keyblock *key) +{ + OM_uint32 major_status, junk; + gss_iov_buffer_desc *header, *padding, *trailer; + krb5_error_code kret; + int32_t seq_number; + u_char Klocaldata[16], k6_data[16], *p, *p0; + size_t make_len = 0; + size_t header_len = 0; + size_t data_len = 0; + krb5_keyblock Klocal; + int i; + + header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + break; + default: + continue; + } + + data_len += iov[i].buffer.length; + } + + if (padding) { + data_len += 1; + } + + if (IS_DCE_STYLE(ctx)) { + size_t unwrapped_len; + unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + _gssapi_encap_length(unwrapped_len, + &make_len, + &header_len, + GSS_KRB5_MECHANISM); + } else { + size_t unwrapped_len; + unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + data_len; + _gssapi_encap_length(unwrapped_len, + &make_len, + &header_len, + GSS_KRB5_MECHANISM); + header_len -= data_len; + } + + if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) { + major_status = _gk_allocate_buffer(minor_status, header, + header_len); + if (major_status != GSS_S_COMPLETE) + goto failure; + } else if (header->buffer.length < header_len) { + *minor_status = KRB5_BAD_MSIZE; + major_status = GSS_S_FAILURE; + goto failure; + } else { + header->buffer.length = header_len; + } + + if (padding) { + if (GSS_IOV_BUFFER_FLAGS(padding->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) { + major_status = _gk_allocate_buffer(minor_status, padding, 1); + if (major_status != GSS_S_COMPLETE) + goto failure; + } else if (padding->buffer.length < 1) { + *minor_status = KRB5_BAD_MSIZE; + major_status = GSS_S_FAILURE; + goto failure; + } else { + padding->buffer.length = 1; + } + memset(padding->buffer.value, 1, 1); + } + + if (trailer) { + trailer->buffer.length = 0; + trailer->buffer.value = NULL; + } + + p0 = _gssapi_make_mech_header(header->buffer.value, + make_len, + GSS_KRB5_MECHANISM); + p = p0; + + *p++ = 0x02; /* TOK_ID */ + *p++ = 0x01; + *p++ = 0x11; /* SGN_ALG */ + *p++ = 0x00; + if (conf_req_flag) { + *p++ = 0x10; /* SEAL_ALG */ + *p++ = 0x00; + } else { + *p++ = 0xff; /* SEAL_ALG */ + *p++ = 0xff; + } + *p++ = 0xff; /* Filler */ + *p++ = 0xff; + + p = NULL; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &seq_number); + _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8); + + krb5_auth_con_setlocalseqnumber(context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + memset(p0 + 8 + 4, + (ctx->more_flags & LOCAL) ? 0 : 0xff, + 4); + + krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */ + + /* Sign Data */ + kret = arcfour_mic_cksum_iov(context, + key, KRB5_KU_USAGE_SEAL, + p0 + 16, 8, /* SGN_CKSUM */ + p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */ + p0 + 24, 8, /* Confounder */ + iov, iov_count, /* Data + SignOnly */ + padding); /* padding */ + if (kret) { + *minor_status = kret; + major_status = GSS_S_FAILURE; + goto failure; + } + + Klocal.keytype = key->keytype; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) { + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + kret = arcfour_mic_key(context, &Klocal, + p0 + 8, 4, /* SND_SEQ */ + k6_data, sizeof(k6_data)); + memset(Klocaldata, 0, sizeof(Klocaldata)); + if (kret) { + *minor_status = kret; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (conf_req_flag) { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + + /* Confounder */ + EVP_Cipher(&rc4_key, p0 + 24, p0 + 24, 8); + + /* Seal Data */ + for (i=0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + break; + default: + continue; + } + + EVP_Cipher(&rc4_key, iov[i].buffer.value, + iov[i].buffer.value, iov[i].buffer.length); + } + + /* Padding */ + if (padding) { + EVP_Cipher(&rc4_key, padding->buffer.value, + padding->buffer.value, padding->buffer.length); + } + + EVP_CIPHER_CTX_cleanup(&rc4_key); + } + memset(k6_data, 0, sizeof(k6_data)); + + kret = arcfour_mic_key(context, key, + p0 + 16, 8, /* SGN_CKSUM */ + k6_data, sizeof(k6_data)); + if (kret) { + *minor_status = kret; + major_status = GSS_S_FAILURE; + } + + { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + EVP_Cipher(&rc4_key, p0 + 8, p0 + 8, 8); /* SND_SEQ */ + EVP_CIPHER_CTX_cleanup(&rc4_key); + + memset(k6_data, 0, sizeof(k6_data)); + } + + if (conf_state) + *conf_state = conf_req_flag; + + *minor_status = 0; + return GSS_S_COMPLETE; + +failure: + + gss_release_iov_buffer(&junk, iov, iov_count); + + return major_status; +} + +OM_uint32 +_gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int *pconf_state, + gss_qop_t *pqop_state, + gss_iov_buffer_desc *iov, + int iov_count, + krb5_keyblock *key) +{ + OM_uint32 major_status; + gss_iov_buffer_desc *header, *padding, *trailer; + krb5_keyblock Klocal; + uint8_t Klocaldata[16]; + uint8_t k6_data[16], snd_seq[8], Confounder[8]; + uint8_t cksum_data[8]; + uint8_t *_p = NULL; + const uint8_t *p, *p0; + size_t verify_len = 0; + uint32_t seq_number; + size_t hlen = 0; + int conf_state; + int cmp; + size_t i; + krb5_error_code kret; + OM_uint32 ret; + + if (pconf_state != NULL) { + *pconf_state = 0; + } + if (pqop_state != NULL) { + *pqop_state = 0; + } + + header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + /* Check if the packet is correct */ + major_status = _gk_verify_buffers(minor_status, + ctx, + header, + padding, + trailer); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + if (padding != NULL && padding->buffer.length != 1) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (IS_DCE_STYLE(context)) { + verify_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + + GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE; + if (header->buffer.length > verify_len) { + return GSS_S_BAD_MECH; + } + } else { + verify_len = header->buffer.length; + } + _p = header->buffer.value; + + ret = _gssapi_verify_mech_header(&_p, + verify_len, + GSS_KRB5_MECHANISM); + if (ret) { + return ret; + } + p0 = _p; + + /* length of mech header */ + hlen = (p0 - (uint8_t *)header->buffer.value); + hlen += GSS_ARCFOUR_WRAP_TOKEN_SIZE; + + if (hlen > header->buffer.length) { + return GSS_S_BAD_MECH; + } + + p = p0; + + if (memcmp(p, "\x02\x01", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ + return GSS_S_BAD_SIG; + p += 2; + + if (memcmp (p, "\x10\x00", 2) == 0) + conf_state = 1; + else if (memcmp (p, "\xff\xff", 2) == 0) + conf_state = 0; + else + return GSS_S_BAD_SIG; + + p += 2; + if (memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_BAD_MIC; + p = NULL; + + kret = arcfour_mic_key(context, + key, + p0 + 16, /* SGN_CKSUM */ + 8, /* SGN_CKSUM_LEN */ + k6_data, + sizeof(k6_data)); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + EVP_Cipher(&rc4_key, snd_seq, p0 + 8, 8); /* SND_SEQ */ + EVP_CIPHER_CTX_cleanup(&rc4_key); + + memset(k6_data, 0, sizeof(k6_data)); + } + + _gsskrb5_decode_be_om_uint32(snd_seq, &seq_number); + + if (ctx->more_flags & LOCAL) { + cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4); + } else { + cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4); + } + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + if (ctx->more_flags & LOCAL) { + cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4); + } else { + cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4); + } + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + /* keyblock */ + Klocal.keytype = key->keytype; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) { + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + + kret = arcfour_mic_key(context, + &Klocal, + snd_seq, + 4, + k6_data, sizeof(k6_data)); + memset(Klocaldata, 0, sizeof(Klocaldata)); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + if (conf_state == 1) { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + + /* Confounder */ + EVP_Cipher(&rc4_key, Confounder, p0 + 24, 8); + + /* Data */ + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + break; + default: + continue; + } + + EVP_Cipher(&rc4_key, iov[i].buffer.value, + iov[i].buffer.value, iov[i].buffer.length); + } + + /* Padding */ + if (padding) { + EVP_Cipher(&rc4_key, padding->buffer.value, + padding->buffer.value, padding->buffer.length); + } + + EVP_CIPHER_CTX_cleanup(&rc4_key); + } else { + /* Confounder */ + memcpy(Confounder, p0 + 24, 8); + } + memset(k6_data, 0, sizeof(k6_data)); + + /* Prepare the buffer for signing */ + kret = arcfour_mic_cksum_iov(context, + key, KRB5_KU_USAGE_SEAL, + cksum_data, sizeof(cksum_data), + p0, 8, + Confounder, sizeof(Confounder), + iov, iov_count, + padding); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */ + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + if (padding) { + size_t plen; + + ret = _gssapi_verify_pad(&padding->buffer, 1, &plen); + if (ret) { + *minor_status = 0; + return ret; + } + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gssapi_msg_order_check(ctx->order, seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret != 0) { + return ret; + } + + if (pconf_state) { + *pconf_state = conf_state; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/krb5/decapsulate.c b/source4/heimdal/lib/gssapi/krb5/decapsulate.c index 640c064d0bf..86085f56950 100644 --- a/source4/heimdal/lib/gssapi/krb5/decapsulate.c +++ b/source4/heimdal/lib/gssapi/krb5/decapsulate.c @@ -190,6 +190,9 @@ _gssapi_verify_pad(gss_buffer_t wrapped_token, size_t padlength; int i; + if (wrapped_token->length < 1) + return GSS_S_BAD_MECH; + pad = (u_char *)wrapped_token->value + wrapped_token->length - 1; padlength = *pad; diff --git a/source4/heimdal_build/wscript_configure b/source4/heimdal_build/wscript_configure index 90df14cdbbc..e49c9c99bb8 100755 --- a/source4/heimdal_build/wscript_configure +++ b/source4/heimdal_build/wscript_configure @@ -94,6 +94,7 @@ conf.define('HAVE_GSSKRB5_GET_SUBKEY', 1) conf.define('HAVE_GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT', 1) conf.define('HAVE_GSS_IMPORT_CRED', 1) conf.define('HAVE_GSS_EXPORT_CRED', 1) +conf.define('HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X', 1) conf.define('HAVE_GSSAPI', 1) conf.define('HAVE_ADDR_TYPE_IN_KRB5_ADDRESS', 1) conf.define('HAVE_CHECKSUM_IN_KRB5_CHECKSUM', 1) diff --git a/source4/ldap_server/ldap_bind.c b/source4/ldap_server/ldap_bind.c index 69a6b6153b0..99ca148547c 100644 --- a/source4/ldap_server/ldap_bind.c +++ b/source4/ldap_server/ldap_bind.c @@ -45,6 +45,23 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call) DEBUG(10, ("BindSimple dn: %s\n",req->dn)); + reply = ldapsrv_init_reply(call, LDAP_TAG_BindResponse); + if (!reply) { + return NT_STATUS_NO_MEMORY; + } + + if (req->dn != NULL && + strlen(req->dn) != 0 && + call->conn->require_strong_auth > LDAP_SERVER_REQUIRE_STRONG_AUTH_NO && + call->conn->sockets.active != call->conn->sockets.tls) + { + status = NT_STATUS_NETWORK_ACCESS_DENIED; + result = LDAP_STRONG_AUTH_REQUIRED; + errstr = talloc_asprintf(reply, + "BindSimple: Transport encryption required."); + goto do_reply; + } + status = crack_auto_name_to_nt4_name(call, call->conn->connection->event.ctx, call->conn->lp_ctx, req->dn, &nt4_domain, &nt4_account); if (NT_STATUS_IS_OK(status)) { status = authenticate_username_pw(call, @@ -58,11 +75,6 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call) &session_info); } - reply = ldapsrv_init_reply(call, LDAP_TAG_BindResponse); - if (!reply) { - return NT_STATUS_NO_MEMORY; - } - if (NT_STATUS_IS_OK(status)) { result = LDAP_SUCCESS; errstr = NULL; @@ -86,6 +98,7 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call) errstr = talloc_asprintf(reply, "Simple Bind Failed: %s", nt_errstr(status)); } +do_reply: resp = &reply->msg->r.BindResponse; resp->response.resultcode = result; resp->response.errormessage = errstr; @@ -181,6 +194,7 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call) gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN); gensec_want_feature(conn->gensec, GENSEC_FEATURE_SEAL); gensec_want_feature(conn->gensec, GENSEC_FEATURE_ASYNC_REPLIES); + gensec_want_feature(conn->gensec, GENSEC_FEATURE_LDAP_STYLE); status = gensec_start_mech_by_sasl_name(conn->gensec, req->creds.SASL.mechanism); @@ -217,7 +231,6 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call) result = LDAP_SASL_BIND_IN_PROGRESS; errstr = NULL; } else if (NT_STATUS_IS_OK(status)) { - struct auth_session_info *old_session_info=NULL; struct ldapsrv_sasl_postprocess_context *context = NULL; result = LDAP_SUCCESS; @@ -262,17 +275,38 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call) status = NT_STATUS_NO_MEMORY; } } + } else { + switch (call->conn->require_strong_auth) { + case LDAP_SERVER_REQUIRE_STRONG_AUTH_NO: + break; + case LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS: + if (call->conn->sockets.active == call->conn->sockets.tls) { + break; + } + status = NT_STATUS_NETWORK_ACCESS_DENIED; + result = LDAP_STRONG_AUTH_REQUIRED; + errstr = talloc_asprintf(reply, + "SASL:[%s]: not allowed if TLS is used.", + req->creds.SASL.mechanism); + break; + case LDAP_SERVER_REQUIRE_STRONG_AUTH_YES: + status = NT_STATUS_NETWORK_ACCESS_DENIED; + result = LDAP_STRONG_AUTH_REQUIRED; + errstr = talloc_asprintf(reply, + "SASL:[%s]: Sign or Seal are required.", + req->creds.SASL.mechanism); + break; + } } if (result != LDAP_SUCCESS) { - conn->session_info = old_session_info; } else if (!NT_STATUS_IS_OK(status)) { - conn->session_info = old_session_info; result = LDAP_OPERATIONS_ERROR; errstr = talloc_asprintf(reply, "SASL:[%s]: Failed to setup SASL socket: %s", req->creds.SASL.mechanism, nt_errstr(status)); } else { + struct auth_session_info *old_session_info=NULL; old_session_info = conn->session_info; conn->session_info = NULL; diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c index 691266cfabf..f4134d76bd6 100644 --- a/source4/ldap_server/ldap_server.c +++ b/source4/ldap_server/ldap_server.c @@ -334,6 +334,12 @@ static void ldapsrv_accept(struct stream_connection *c, conn->sockets.active = conn->sockets.raw; + if (conn->is_privileged) { + conn->require_strong_auth = LDAP_SERVER_REQUIRE_STRONG_AUTH_NO; + } else { + conn->require_strong_auth = lpcfg_ldap_server_require_strong_auth(conn->lp_ctx); + } + if (!NT_STATUS_IS_OK(ldapsrv_backend_Init(conn))) { ldapsrv_terminate_connection(conn, "backend Init failed"); return; @@ -934,6 +940,7 @@ static void ldapsrv_task_init(struct task_server *task) lpcfg_tls_cafile(ldap_service, task->lp_ctx), lpcfg_tls_crlfile(ldap_service, task->lp_ctx), lpcfg_tls_dhpfile(ldap_service, task->lp_ctx), + lpcfg_tls_priority(task->lp_ctx), &ldap_service->tls_params); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("ldapsrv failed tstream_tls_params_server - %s\n", diff --git a/source4/ldap_server/ldap_server.h b/source4/ldap_server/ldap_server.h index 6f8b433a1cd..87a71630881 100644 --- a/source4/ldap_server/ldap_server.h +++ b/source4/ldap_server/ldap_server.h @@ -22,6 +22,7 @@ #include "lib/socket/socket.h" #include "lib/stream/packet.h" #include "system/network.h" +#include "lib/param/loadparm.h" struct ldapsrv_connection { struct loadparm_context *lp_ctx; @@ -42,6 +43,7 @@ struct ldapsrv_connection { bool global_catalog; bool is_privileged; + enum ldap_server_require_strong_auth require_strong_auth; struct { int initial_timeout; diff --git a/source4/lib/tls/tls.c b/source4/lib/tls/tls.c index 2fe4ff7a3fc..f2197e6c3b5 100644 --- a/source4/lib/tls/tls.c +++ b/source4/lib/tls/tls.c @@ -31,7 +31,7 @@ #if ENABLE_GNUTLS #include <gnutls/gnutls.h> -#define DH_BITS 1024 +#define DH_BITS 2048 #if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T) typedef gnutls_datum gnutls_datum_t; diff --git a/source4/lib/tls/tls.h b/source4/lib/tls/tls.h index ed3c81ee2b4..e600c89cceb 100644 --- a/source4/lib/tls/tls.h +++ b/source4/lib/tls/tls.h @@ -45,6 +45,11 @@ struct socket_context *tls_init_server(struct tls_params *parms, struct tevent_fd *fde, const char *plain_chars); +void tls_cert_generate(TALLOC_CTX *mem_ctx, + const char *hostname, + const char *keyfile, const char *certfile, + const char *cafile); + /* call tls_init_client() on each new client connection */ @@ -63,9 +68,33 @@ const struct socket_ops *socket_tls_ops(enum socket_type type); struct tstream_context; struct tstream_tls_params; +enum tls_verify_peer_state { + TLS_VERIFY_PEER_NO_CHECK = 0, +#define TLS_VERIFY_PEER_NO_CHECK_STRING "no_check" + + TLS_VERIFY_PEER_CA_ONLY = 10, +#define TLS_VERIFY_PEER_CA_ONLY_STRING "ca_only" + + TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE = 20, +#define TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE_STRING \ + "ca_and_name_if_available" + + TLS_VERIFY_PEER_CA_AND_NAME = 30, +#define TLS_VERIFY_PEER_CA_AND_NAME_STRING "ca_and_name" + + TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE = 9999, +#define TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE_STRING \ + "as_strict_as_possible" +}; + +const char *tls_verify_peer_string(enum tls_verify_peer_state verify_peer); + NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx, const char *ca_file, const char *crl_file, + const char *tls_priority, + enum tls_verify_peer_state verify_peer, + const char *peer_name, struct tstream_tls_params **_tlsp); NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx, @@ -76,6 +105,7 @@ NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx, const char *ca_file, const char *crl_file, const char *dhp_file, + const char *tls_priority, struct tstream_tls_params **_params); bool tstream_tls_params_enabled(struct tstream_tls_params *params); @@ -85,7 +115,7 @@ struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx, struct tstream_context *plain_stream, struct tstream_tls_params *tls_params, const char *location); -#define tstream_tls_connect_send(mem_ctx, ev, plain_stream, tls_params); \ +#define tstream_tls_connect_send(mem_ctx, ev, plain_stream, tls_params) \ _tstream_tls_connect_send(mem_ctx, ev, plain_stream, tls_params, __location__) int tstream_tls_connect_recv(struct tevent_req *req, diff --git a/source4/lib/tls/tls_tstream.c b/source4/lib/tls/tls_tstream.c index b907d0a4d30..2ccb9090eba 100644 --- a/source4/lib/tls/tls_tstream.c +++ b/source4/lib/tls/tls_tstream.c @@ -20,22 +20,64 @@ #include "includes.h" #include "system/network.h" #include "system/filesys.h" +#include "system/time.h" #include "../util/tevent_unix.h" #include "../lib/tsocket/tsocket.h" #include "../lib/tsocket/tsocket_internal.h" +#include "../lib/util/util_net.h" #include "lib/tls/tls.h" #if ENABLE_GNUTLS #include <gnutls/gnutls.h> +#include <gnutls/x509.h> -#define DH_BITS 1024 +#define DH_BITS 2048 #if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T) typedef gnutls_datum gnutls_datum_t; #endif +/* + * define our own values in a high range + */ +#ifndef HAVE_DECL_GNUTLS_CERT_EXPIRED +#define GNUTLS_CERT_EXPIRED 0x10000000 +#define REQUIRE_CERT_TIME_CHECKS 1 +#endif +#ifndef HAVE_DECL_GNUTLS_CERT_NOT_ACTIVATED +#define GNUTLS_CERT_NOT_ACTIVATED 0x20000000 +#ifndef REQUIRE_CERT_TIME_CHECKS +#define REQUIRE_CERT_TIME_CHECKS 1 +#endif +#endif +#ifndef HAVE_DECL_GNUTLS_CERT_UNEXPECTED_OWNER +#define GNUTLS_CERT_UNEXPECTED_OWNER 0x40000000 +#endif + #endif /* ENABLE_GNUTLS */ +const char *tls_verify_peer_string(enum tls_verify_peer_state verify_peer) +{ + switch (verify_peer) { + case TLS_VERIFY_PEER_NO_CHECK: + return TLS_VERIFY_PEER_NO_CHECK_STRING; + + case TLS_VERIFY_PEER_CA_ONLY: + return TLS_VERIFY_PEER_CA_ONLY_STRING; + + case TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE: + return TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE_STRING; + + case TLS_VERIFY_PEER_CA_AND_NAME: + return TLS_VERIFY_PEER_CA_AND_NAME_STRING; + + case TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE: + return TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE_STRING; + } + + return "unknown tls_verify_peer_state"; +} + static const struct tstream_context_ops tstream_tls_ops; struct tstream_tls { @@ -46,6 +88,9 @@ struct tstream_tls { gnutls_session tls_session; #endif /* ENABLE_GNUTLS */ + enum tls_verify_peer_state verify_peer; + const char *peer_name; + struct tevent_context *current_ev; struct tevent_immediate *retry_im; @@ -868,8 +913,11 @@ struct tstream_tls_params { #if ENABLE_GNUTLS gnutls_certificate_credentials x509_cred; gnutls_dh_params dh_params; + const char *tls_priority; #endif /* ENABLE_GNUTLS */ bool tls_enabled; + enum tls_verify_peer_state verify_peer; + const char *peer_name; }; static int tstream_tls_params_destructor(struct tstream_tls_params *tlsp) @@ -895,6 +943,9 @@ bool tstream_tls_params_enabled(struct tstream_tls_params *tlsp) NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx, const char *ca_file, const char *crl_file, + const char *tls_priority, + enum tls_verify_peer_state verify_peer, + const char *peer_name, struct tstream_tls_params **_tlsp) { #if ENABLE_GNUTLS @@ -912,6 +963,21 @@ NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx, talloc_set_destructor(tlsp, tstream_tls_params_destructor); + tlsp->verify_peer = verify_peer; + if (peer_name != NULL) { + tlsp->peer_name = talloc_strdup(tlsp, peer_name); + if (tlsp->peer_name == NULL) { + talloc_free(tlsp); + return NT_STATUS_NO_MEMORY; + } + } else if (tlsp->verify_peer >= TLS_VERIFY_PEER_CA_AND_NAME) { + DEBUG(0,("TLS failed to missing peer_name - " + "with 'tls verify peer = %s'\n", + tls_verify_peer_string(tlsp->verify_peer))); + talloc_free(tlsp); + return NT_STATUS_INVALID_PARAMETER_MIX; + } + ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred); if (ret != GNUTLS_E_SUCCESS) { DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret))); @@ -919,7 +985,7 @@ NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx, return NT_STATUS_NO_MEMORY; } - if (ca_file && *ca_file) { + if (ca_file && *ca_file && file_exist(ca_file)) { ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred, ca_file, GNUTLS_X509_FMT_PEM); @@ -929,9 +995,16 @@ NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx, talloc_free(tlsp); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } + } else if (tlsp->verify_peer >= TLS_VERIFY_PEER_CA_ONLY) { + DEBUG(0,("TLS failed to missing cafile %s - " + "with 'tls verify peer = %s'\n", + ca_file, + tls_verify_peer_string(tlsp->verify_peer))); + talloc_free(tlsp); + return NT_STATUS_INVALID_PARAMETER_MIX; } - if (crl_file && *crl_file) { + if (crl_file && *crl_file && file_exist(crl_file)) { ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred, crl_file, GNUTLS_X509_FMT_PEM); @@ -941,6 +1014,19 @@ NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx, talloc_free(tlsp); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } + } else if (tlsp->verify_peer >= TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE) { + DEBUG(0,("TLS failed to missing crlfile %s - " + "with 'tls verify peer = %s'\n", + crl_file, + tls_verify_peer_string(tlsp->verify_peer))); + talloc_free(tlsp); + return NT_STATUS_INVALID_PARAMETER_MIX; + } + + tlsp->tls_priority = talloc_strdup(tlsp, tls_priority); + if (tlsp->tls_priority == NULL) { + talloc_free(tlsp); + return NT_STATUS_NO_MEMORY; } tlsp->tls_enabled = true; @@ -964,6 +1050,7 @@ struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx, { struct tevent_req *req; struct tstream_tls_connect_state *state; + const char *error_pos; #if ENABLE_GNUTLS struct tstream_tls *tlss; int ret; @@ -988,6 +1075,13 @@ struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx, talloc_set_destructor(tlss, tstream_tls_destructor); tlss->plain_stream = plain_stream; + tlss->verify_peer = tls_params->verify_peer; + if (tls_params->peer_name != NULL) { + tlss->peer_name = talloc_strdup(tlss, tls_params->peer_name); + if (tevent_req_nomem(tlss->peer_name, req)) { + return tevent_req_post(req, ev); + } + } tlss->current_ev = ev; tlss->retry_im = tevent_create_immediate(tlss); @@ -1002,9 +1096,12 @@ struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - ret = gnutls_set_default_priority(tlss->tls_session); + ret = gnutls_priority_set_direct(tlss->tls_session, + tls_params->tls_priority, + &error_pos); if (ret != GNUTLS_E_SUCCESS) { - DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret))); + DEBUG(0,("TLS %s - %s. Check 'tls priority' option at '%s'\n", + __location__, gnutls_strerror(ret), error_pos)); tevent_req_error(req, EINVAL); return tevent_req_post(req, ev); } @@ -1061,8 +1158,6 @@ int tstream_tls_connect_recv(struct tevent_req *req, return 0; } -extern void tls_cert_generate(TALLOC_CTX *, const char *, const char *, const char *, const char *); - /* initialise global tls state */ @@ -1074,6 +1169,7 @@ NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx, const char *ca_file, const char *crl_file, const char *dhp_file, + const char *tls_priority, struct tstream_tls_params **_tlsp) { struct tstream_tls_params *tlsp; @@ -1204,6 +1300,12 @@ NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx, gnutls_certificate_set_dh_params(tlsp->x509_cred, tlsp->dh_params); + tlsp->tls_priority = talloc_strdup(tlsp, tls_priority); + if (tlsp->tls_priority == NULL) { + talloc_free(tlsp); + return NT_STATUS_NO_MEMORY; + } + tlsp->tls_enabled = true; #else /* ENABLE_GNUTLS */ @@ -1230,6 +1332,7 @@ struct tevent_req *_tstream_tls_accept_send(TALLOC_CTX *mem_ctx, struct tevent_req *req; struct tstream_tls_accept_state *state; struct tstream_tls *tlss; + const char *error_pos; #if ENABLE_GNUTLS int ret; #endif /* ENABLE_GNUTLS */ @@ -1267,9 +1370,12 @@ struct tevent_req *_tstream_tls_accept_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - ret = gnutls_set_default_priority(tlss->tls_session); + ret = gnutls_priority_set_direct(tlss->tls_session, + tlsp->tls_priority, + &error_pos); if (ret != GNUTLS_E_SUCCESS) { - DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret))); + DEBUG(0,("TLS %s - %s. Check 'tls priority' option at '%s'\n", + __location__, gnutls_strerror(ret), error_pos)); tevent_req_error(req, EINVAL); return tevent_req_post(req, ev); } @@ -1343,6 +1449,170 @@ static void tstream_tls_retry_handshake(struct tstream_context *stream) return; } + if (tlss->verify_peer >= TLS_VERIFY_PEER_CA_ONLY) { + unsigned int status = UINT32_MAX; + bool ip = true; + const char *hostname = NULL; +#ifndef HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3 + bool need_crt_checks = false; +#endif + + if (tlss->peer_name != NULL) { + ip = is_ipaddress(tlss->peer_name); + } + + if (!ip) { + hostname = tlss->peer_name; + } + + if (tlss->verify_peer == TLS_VERIFY_PEER_CA_ONLY) { + hostname = NULL; + } + + if (tlss->verify_peer >= TLS_VERIFY_PEER_CA_AND_NAME) { + if (hostname == NULL) { + DEBUG(1,("TLS %s - no hostname available for " + "verify_peer[%s] and peer_name[%s]\n", + __location__, + tls_verify_peer_string(tlss->verify_peer), + tlss->peer_name)); + tlss->error = EINVAL; + tevent_req_error(req, tlss->error); + return; + } + } + +#ifdef HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3 + ret = gnutls_certificate_verify_peers3(tlss->tls_session, + hostname, + &status); + if (ret != GNUTLS_E_SUCCESS) { + DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret))); + tlss->error = EIO; + tevent_req_error(req, tlss->error); + return; + } +#else /* not HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3 */ + ret = gnutls_certificate_verify_peers2(tlss->tls_session, &status); + if (ret != GNUTLS_E_SUCCESS) { + DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret))); + tlss->error = EIO; + tevent_req_error(req, tlss->error); + return; + } + + if (status == 0) { + if (hostname != NULL) { + need_crt_checks = true; + } +#ifdef REQUIRE_CERT_TIME_CHECKS + need_crt_checks = true; +#endif + } + + if (need_crt_checks) { + gnutls_x509_crt crt; + const gnutls_datum *cert_list; + unsigned int cert_list_size = 0; +#ifdef REQUIRE_CERT_TIME_CHECKS + time_t now = time(NULL); + time_t tret = -1; +#endif + + cert_list = gnutls_certificate_get_peers(tlss->tls_session, + &cert_list_size); + if (cert_list == NULL) { + cert_list_size = 0; + } + if (cert_list_size == 0) { + DEBUG(1,("TLS %s - cert_list_size == 0\n", + __location__)); + tlss->error = EIO; + tevent_req_error(req, tlss->error); + return; + } + + ret = gnutls_x509_crt_init(&crt); + if (ret != GNUTLS_E_SUCCESS) { + DEBUG(1,("TLS %s - %s\n", __location__, + gnutls_strerror(ret))); + tlss->error = EIO; + tevent_req_error(req, tlss->error); + return; + } + ret = gnutls_x509_crt_import(crt, + &cert_list[0], + GNUTLS_X509_FMT_DER); + if (ret != GNUTLS_E_SUCCESS) { + DEBUG(1,("TLS %s - %s\n", __location__, + gnutls_strerror(ret))); + gnutls_x509_crt_deinit(crt); + tlss->error = EIO; + tevent_req_error(req, tlss->error); + return; + } + + if (hostname != NULL) { + ret = gnutls_x509_crt_check_hostname(crt, + hostname); + if (ret == 0) { + status |= GNUTLS_CERT_INVALID; + status |= GNUTLS_CERT_UNEXPECTED_OWNER; + } + } + +#ifndef HAVE_DECL_GNUTLS_CERT_NOT_ACTIVATED + /* + * GNUTLS_CERT_NOT_ACTIVATED is defined by ourself + */ + tret = gnutls_x509_crt_get_activation_time(crt); + if ((tret == -1) || (now > tret)) { + status |= GNUTLS_CERT_INVALID; + status |= GNUTLS_CERT_NOT_ACTIVATED; + } +#endif +#ifndef HAVE_DECL_GNUTLS_CERT_EXPIRED + /* + * GNUTLS_CERT_EXPIRED is defined by ourself + */ + tret = gnutls_certificate_expiration_time_peers(tlss->tls_session); + if ((tret == -1) || (now > tret)) { + status |= GNUTLS_CERT_INVALID; + status |= GNUTLS_CERT_EXPIRED; + } +#endif + gnutls_x509_crt_deinit(crt); + } +#endif + + if (status != 0) { + DEBUG(1,("TLS %s - check failed for " + "verify_peer[%s] and peer_name[%s] " + "status 0x%x (%s%s%s%s%s%s%s%s)\n", + __location__, + tls_verify_peer_string(tlss->verify_peer), + tlss->peer_name, + status, + status & GNUTLS_CERT_INVALID ? "invalid " : "", + status & GNUTLS_CERT_REVOKED ? "revoked " : "", + status & GNUTLS_CERT_SIGNER_NOT_FOUND ? + "signer_not_found " : "", + status & GNUTLS_CERT_SIGNER_NOT_CA ? + "signer_not_ca " : "", + status & GNUTLS_CERT_INSECURE_ALGORITHM ? + "insecure_algorithm " : "", + status & GNUTLS_CERT_NOT_ACTIVATED ? + "not_activated " : "", + status & GNUTLS_CERT_EXPIRED ? + "expired " : "", + status & GNUTLS_CERT_UNEXPECTED_OWNER ? + "unexptected_owner " : "")); + tlss->error = EINVAL; + tevent_req_error(req, tlss->error); + return; + } + } + tevent_req_done(req); #else /* ENABLE_GNUTLS */ tevent_req_error(req, ENOSYS); diff --git a/source4/lib/tls/tlscert.c b/source4/lib/tls/tlscert.c index b44d46b0f1b..f1808d7cfd9 100644 --- a/source4/lib/tls/tlscert.c +++ b/source4/lib/tls/tlscert.c @@ -20,6 +20,7 @@ */ #include "includes.h" +#include "lib/tls/tls.h" #if ENABLE_GNUTLS #include <gnutls/gnutls.h> @@ -29,9 +30,10 @@ #endif #define ORGANISATION_NAME "Samba Administration" -#define UNIT_NAME "Samba - temporary autogenerated certificate" +#define CA_NAME "Samba - temporary autogenerated CA certificate" +#define UNIT_NAME "Samba - temporary autogenerated HOST certificate" #define LIFETIME 700*24*60*60 -#define DH_BITS 1024 +#define RSA_BITS 4096 /* auto-generate a set of self signed certificates @@ -76,11 +78,11 @@ void tls_cert_generate(TALLOC_CTX *mem_ctx, DEBUG(3,("Generating private key\n")); TLSCHECK(gnutls_x509_privkey_init(&key)); - TLSCHECK(gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, DH_BITS, 0)); + TLSCHECK(gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, RSA_BITS, 0)); DEBUG(3,("Generating CA private key\n")); TLSCHECK(gnutls_x509_privkey_init(&cakey)); - TLSCHECK(gnutls_x509_privkey_generate(cakey, GNUTLS_PK_RSA, DH_BITS, 0)); + TLSCHECK(gnutls_x509_privkey_generate(cakey, GNUTLS_PK_RSA, RSA_BITS, 0)); DEBUG(3,("Generating CA certificate\n")); TLSCHECK(gnutls_x509_crt_init(&cacrt)); @@ -89,7 +91,7 @@ void tls_cert_generate(TALLOC_CTX *mem_ctx, ORGANISATION_NAME, strlen(ORGANISATION_NAME))); TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, - UNIT_NAME, strlen(UNIT_NAME))); + CA_NAME, strlen(CA_NAME))); TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt, GNUTLS_OID_X520_COMMON_NAME, 0, hostname, strlen(hostname))); @@ -97,10 +99,8 @@ void tls_cert_generate(TALLOC_CTX *mem_ctx, TLSCHECK(gnutls_x509_crt_set_serial(cacrt, &serial, sizeof(serial))); TLSCHECK(gnutls_x509_crt_set_activation_time(cacrt, activation)); TLSCHECK(gnutls_x509_crt_set_expiration_time(cacrt, expiry)); - TLSCHECK(gnutls_x509_crt_set_ca_status(cacrt, 0)); -#ifdef GNUTLS_KP_TLS_WWW_SERVER - TLSCHECK(gnutls_x509_crt_set_key_purpose_oid(cacrt, GNUTLS_KP_TLS_WWW_SERVER, 0)); -#endif + TLSCHECK(gnutls_x509_crt_set_ca_status(cacrt, 1)); + TLSCHECK(gnutls_x509_crt_set_key_usage(cacrt, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN)); TLSCHECK(gnutls_x509_crt_set_version(cacrt, 3)); TLSCHECK(gnutls_x509_crt_get_key_id(cacrt, 0, keyid, &keyidsize)); #if HAVE_GNUTLS_X509_CRT_SET_SUBJECT_KEY_ID @@ -133,6 +133,7 @@ void tls_cert_generate(TALLOC_CTX *mem_ctx, TLSCHECK(gnutls_x509_crt_set_subject_key_id(crt, keyid, keyidsize)); #endif TLSCHECK(gnutls_x509_crt_sign(crt, crt, key)); + TLSCHECK(gnutls_x509_crt_sign(crt, cacrt, cakey)); DEBUG(3,("Exporting TLS keys\n")); diff --git a/source4/lib/tls/wscript b/source4/lib/tls/wscript index cbba87d5804..3fd8acaff18 100644 --- a/source4/lib/tls/wscript +++ b/source4/lib/tls/wscript @@ -39,6 +39,11 @@ def configure(conf): conf.CHECK_FUNCS_IN('gnutls_global_init', 'gnutls', headers='gnutls/gnutls.h') + conf.CHECK_FUNCS_IN('gnutls_certificate_verify_peers3', 'gnutls', + headers='gnutls/gnutls.h') + conf.CHECK_DECLS('GNUTLS_CERT_EXPIRED GNUTLS_CERT_NOT_ACTIVATED GNUTLS_CERT_UNEXPECTED_OWNER', + headers='gnutls/gnutls.h gnutls/x509.h') + conf.CHECK_VARIABLE('gnutls_x509_crt_set_version', headers='gnutls/gnutls.h gnutls/x509.h', define='HAVE_GNUTLS_X509_CRT_SET_VERSION', @@ -64,6 +69,5 @@ def configure(conf): def build(bld): bld.SAMBA_SUBSYSTEM('LIBTLS', source='tls.c tlscert.c tls_tstream.c', - allow_warnings=True, public_deps='talloc gnutls gcrypt samba-hostconfig samba_socket LIBTSOCKET tevent tevent-util' ) diff --git a/source4/libcli/cliconnect.c b/source4/libcli/cliconnect.c index 17151923d5b..35d963eebf8 100644 --- a/source4/libcli/cliconnect.c +++ b/source4/libcli/cliconnect.c @@ -77,7 +77,7 @@ NTSTATUS smbcli_negprot(struct smbcli_state *cli, bool unicode, int maxprotocol) return NT_STATUS_NO_MEMORY; } - return smb_raw_negotiate(cli->transport, unicode, maxprotocol); + return smb_raw_negotiate(cli->transport, unicode, PROTOCOL_CORE, maxprotocol); } /* wrapper around smb_raw_sesssetup() */ diff --git a/source4/libcli/ldap/ldap_bind.c b/source4/libcli/ldap/ldap_bind.c index a96ea9f6aee..397b4cb3e44 100644 --- a/source4/libcli/ldap/ldap_bind.c +++ b/source4/libcli/ldap/ldap_bind.c @@ -28,10 +28,11 @@ #include "lib/tls/tls.h" #include "auth/gensec/gensec.h" #include "auth/gensec/gensec_internal.h" /* TODO: remove this */ -#include "auth/gensec/gensec_socket.h" +#include "source4/auth/gensec/gensec_tstream.h" #include "auth/credentials/credentials.h" #include "lib/stream/packet.h" #include "param/param.h" +#include "param/loadparm.h" struct ldap_simple_creds { const char *dn; @@ -216,7 +217,7 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, struct ldap_SearchResEntry *search; int count, i; bool first = true; - + int wrap_flags = 0; const char **sasl_names; uint32_t old_gensec_features; static const char *supported_sasl_mech_attrs[] = { @@ -224,6 +225,27 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, NULL }; unsigned int logon_retries = 0; + size_t queue_length; + + if (conn->sockets.active == NULL) { + status = NT_STATUS_CONNECTION_DISCONNECTED; + goto failed; + } + + queue_length = tevent_queue_length(conn->sockets.send_queue); + if (queue_length != 0) { + status = NT_STATUS_INVALID_PARAMETER_MIX; + DEBUG(1, ("SASL bind triggered with non empty send_queue[%ju]: %s\n", + queue_length, nt_errstr(status))); + goto failed; + } + + if (conn->pending != NULL) { + status = NT_STATUS_INVALID_PARAMETER_MIX; + DEBUG(1, ("SASL bind triggered with pending requests: %s\n", + nt_errstr(status))); + goto failed; + } status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs, false, NULL, NULL, &sasl_mechs_msgs); @@ -264,12 +286,29 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, gensec_init(); + if (conn->sockets.active == conn->sockets.tls) { + /* + * require Kerberos SIGN/SEAL only if we don't use SSL + * Windows seem not to like double encryption + */ + wrap_flags = 0; + } else if (cli_credentials_is_anonymous(creds)) { + /* + * anonymous isn't protected + */ + wrap_flags = 0; + } else { + wrap_flags = lpcfg_client_ldap_sasl_wrapping(lp_ctx); + } + try_logon_again: /* we loop back here on a logon failure, and re-create the gensec session. The logon_retries counter ensures we don't loop forever. */ + data_blob_free(&input); + TALLOC_FREE(conn->gensec); status = gensec_client_start(conn, &conn->gensec, lpcfg_gensec_settings(conn, lp_ctx)); @@ -278,10 +317,8 @@ try_logon_again: goto failed; } - /* require Kerberos SIGN/SEAL only if we don't use SSL - * Windows seem not to like double encryption */ old_gensec_features = cli_credentials_get_gensec_features(creds); - if (tls_enabled(conn->sock)) { + if (wrap_flags == 0) { cli_credentials_set_gensec_features(creds, old_gensec_features & ~(GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL)); } @@ -297,6 +334,21 @@ try_logon_again: * context, so we don't tatoo it ) */ cli_credentials_set_gensec_features(creds, old_gensec_features); + if (wrap_flags & ADS_AUTH_SASL_SEAL) { + gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN); + gensec_want_feature(conn->gensec, GENSEC_FEATURE_SEAL); + } + if (wrap_flags & ADS_AUTH_SASL_SIGN) { + gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN); + } + + /* + * This is an indication for the NTLMSSP backend to + * also encrypt when only GENSEC_FEATURE_SIGN is requested + * in gensec_[un]wrap(). + */ + gensec_want_feature(conn->gensec, GENSEC_FEATURE_LDAP_STYLE); + if (conn->host) { status = gensec_set_target_hostname(conn->gensec, conn->host); if (!NT_STATUS_IS_OK(status)) { @@ -385,6 +437,13 @@ try_logon_again: result = response->r.BindResponse.response.resultcode; + if (result == LDAP_STRONG_AUTH_REQUIRED) { + if (wrap_flags == 0) { + wrap_flags = ADS_AUTH_SASL_SIGN; + goto try_logon_again; + } + } + if (result == LDAP_INVALID_CREDENTIALS) { /* try a second time on invalid credentials, to @@ -413,8 +472,6 @@ try_logon_again: new credentials, or get a new ticket if using kerberos */ - talloc_free(conn->gensec); - conn->gensec = NULL; goto try_logon_again; } } @@ -436,27 +493,45 @@ try_logon_again: } } - talloc_free(tmp_ctx); + TALLOC_FREE(tmp_ctx); - if (NT_STATUS_IS_OK(status)) { - struct socket_context *sasl_socket; - status = gensec_socket_init(conn->gensec, - conn, - conn->sock, - conn->event.event_ctx, - ldap_read_io_handler, - conn, - &sasl_socket); - if (!NT_STATUS_IS_OK(status)) goto failed; - - conn->sock = sasl_socket; - packet_set_socket(conn->packet, conn->sock); - - conn->bind.type = LDAP_BIND_SASL; - conn->bind.creds = creds; + if (!NT_STATUS_IS_OK(status)) { + goto failed; } - return status; + conn->bind.type = LDAP_BIND_SASL; + conn->bind.creds = creds; + + if (wrap_flags & ADS_AUTH_SASL_SEAL) { + if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN)) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SEAL)) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + } else if (wrap_flags & ADS_AUTH_SASL_SIGN) { + if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN)) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + } + + if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN) && + !gensec_have_feature(conn->gensec, GENSEC_FEATURE_SEAL)) { + return NT_STATUS_OK; + } + + status = gensec_create_tstream(conn->sockets.raw, + conn->gensec, + conn->sockets.raw, + &conn->sockets.sasl); + if (!NT_STATUS_IS_OK(status)) { + goto failed; + } + + conn->sockets.active = conn->sockets.sasl; + + return NT_STATUS_OK; failed: talloc_free(tmp_ctx); diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c index 7c8bb0304c9..817863a3449 100644 --- a/source4/libcli/ldap/ldap_client.c +++ b/source4/libcli/ldap/ldap_client.c @@ -25,22 +25,36 @@ #include "includes.h" #include <tevent.h> #include "lib/socket/socket.h" +#include "lib/tsocket/tsocket.h" +#include "libcli/util/tstream.h" #include "../lib/util/asn1.h" #include "../lib/util/dlinklist.h" #include "libcli/ldap/libcli_ldap.h" #include "libcli/ldap/ldap_proto.h" #include "libcli/ldap/ldap_client.h" #include "libcli/composite/composite.h" -#include "lib/stream/packet.h" #include "lib/tls/tls.h" #include "auth/gensec/gensec.h" #include "system/time.h" #include "param/param.h" #include "libcli/resolve/resolve.h" +static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status); + +static int ldap_connection_destructor(struct ldap_connection *conn) +{ + /* + * NT_STATUS_OK means that callbacks of pending requests are not + * triggered + */ + ldap_connection_dead(conn, NT_STATUS_OK); + return 0; +} + /** create a new ldap_connection stucture. The event context is optional */ + _PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct tevent_context *ev) @@ -59,6 +73,13 @@ _PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx, conn->next_messageid = 1; conn->event.event_ctx = ev; + conn->sockets.send_queue = tevent_queue_create(conn, + "ldap_connection send_queue"); + if (conn->sockets.send_queue == NULL) { + TALLOC_FREE(conn); + return NULL; + } + conn->lp_ctx = lp_ctx; /* set a reasonable request timeout */ @@ -66,29 +87,35 @@ _PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx, /* explicitly avoid reconnections by default */ conn->reconnect.max_retries = 0; - + + talloc_set_destructor(conn, ldap_connection_destructor); return conn; } /* the connection is dead */ -static void ldap_connection_dead(struct ldap_connection *conn) +static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status) { struct ldap_request *req; - talloc_free(conn->sock); /* this will also free event.fde */ - talloc_free(conn->packet); - conn->sock = NULL; - conn->event.fde = NULL; - conn->packet = NULL; + tevent_queue_stop(conn->sockets.send_queue); + TALLOC_FREE(conn->sockets.recv_subreq); + conn->sockets.active = NULL; + TALLOC_FREE(conn->sockets.sasl); + TALLOC_FREE(conn->sockets.tls); + TALLOC_FREE(conn->sockets.raw); /* return an error for any pending request ... */ while (conn->pending) { req = conn->pending; DLIST_REMOVE(req->conn->pending, req); + req->conn = NULL; req->state = LDAP_REQUEST_DONE; - req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; + if (NT_STATUS_IS_OK(status)) { + continue; + } + req->status = status; if (req->async.fn) { req->async.fn(req); } @@ -100,11 +127,9 @@ static void ldap_reconnect(struct ldap_connection *conn); /* handle packet errors */ -static void ldap_error_handler(void *private_data, NTSTATUS status) +static void ldap_error_handler(struct ldap_connection *conn, NTSTATUS status) { - struct ldap_connection *conn = talloc_get_type(private_data, - struct ldap_connection); - ldap_connection_dead(conn); + ldap_connection_dead(conn, status); /* but try to reconnect so that the ldb client can go on */ ldap_reconnect(conn); @@ -130,7 +155,7 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message if (req == NULL) { DEBUG(0,("ldap: no matching message id for %u\n", msg->messageid)); - talloc_free(msg); + TALLOC_FREE(msg); return; } @@ -138,6 +163,7 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message for (i=0; msg->controls && msg->controls[i]; i++) { if (!msg->controls_decoded[i] && msg->controls[i]->critical) { + TALLOC_FREE(msg); req->status = NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION); req->state = LDAP_REQUEST_DONE; DLIST_REMOVE(conn->pending, req); @@ -149,10 +175,10 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message } /* add to the list of replies received */ - talloc_steal(req, msg); req->replies = talloc_realloc(req, req->replies, struct ldap_message *, req->num_replies+1); if (req->replies == NULL) { + TALLOC_FREE(msg); req->status = NT_STATUS_NO_MEMORY; req->state = LDAP_REQUEST_DONE; DLIST_REMOVE(conn->pending, req); @@ -178,64 +204,120 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message } } +static void ldap_connection_recv_done(struct tevent_req *subreq); + +static void ldap_connection_recv_next(struct ldap_connection *conn) +{ + struct tevent_req *subreq = NULL; + + if (conn->sockets.recv_subreq != NULL) { + return; + } + + if (conn->sockets.active == NULL) { + return; + } + + if (conn->pending == NULL) { + return; + } + + /* + * The minimun size of a LDAP pdu is 7 bytes + * + * dumpasn1 -hh ldap-unbind-min.dat + * + * <30 05 02 01 09 42 00> + * 0 5: SEQUENCE { + * <02 01 09> + * 2 1: INTEGER 9 + * <42 00> + * 5 0: [APPLICATION 2] + * : Error: Object has zero length. + * : } + * + * dumpasn1 -hh ldap-unbind-windows.dat + * + * <30 84 00 00 00 05 02 01 09 42 00> + * 0 5: SEQUENCE { + * <02 01 09> + * 6 1: INTEGER 9 + * <42 00> + * 9 0: [APPLICATION 2] + * : Error: Object has zero length. + * : } + * + * This means using an initial read size + * of 7 is ok. + */ + subreq = tstream_read_pdu_blob_send(conn, + conn->event.event_ctx, + conn->sockets.active, + 7, /* initial_read_size */ + ldap_full_packet, + conn); + if (subreq == NULL) { + ldap_error_handler(conn, NT_STATUS_NO_MEMORY); + return; + } + tevent_req_set_callback(subreq, ldap_connection_recv_done, conn); + conn->sockets.recv_subreq = subreq; + return; +} /* decode/process LDAP data */ -static NTSTATUS ldap_recv_handler(void *private_data, DATA_BLOB blob) +static void ldap_connection_recv_done(struct tevent_req *subreq) { NTSTATUS status; - struct ldap_connection *conn = talloc_get_type(private_data, - struct ldap_connection); - struct ldap_message *msg = talloc(conn, struct ldap_message); - struct asn1_data *asn1 = asn1_init(conn); - - if (asn1 == NULL || msg == NULL) { - return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR); + struct ldap_connection *conn = + tevent_req_callback_data(subreq, + struct ldap_connection); + struct ldap_message *msg; + struct asn1_data *asn1; + DATA_BLOB blob; + + msg = talloc_zero(conn, struct ldap_message); + if (msg == NULL) { + ldap_error_handler(conn, NT_STATUS_NO_MEMORY); + return; } - if (!asn1_load(asn1, blob)) { - talloc_free(msg); - talloc_free(asn1); - return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR); + asn1 = asn1_init(conn); + if (asn1 == NULL) { + TALLOC_FREE(msg); + ldap_error_handler(conn, NT_STATUS_NO_MEMORY); + return; } - - status = ldap_decode(asn1, samba_ldap_control_handlers(), msg); + + conn->sockets.recv_subreq = NULL; + + status = tstream_read_pdu_blob_recv(subreq, + asn1, + &blob); + TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(msg); asn1_free(asn1); - return status; + ldap_error_handler(conn, status); + return; } - ldap_match_message(conn, msg); + asn1_load_nocopy(asn1, blob.data, blob.length); - data_blob_free(&blob); + status = ldap_decode(asn1, samba_ldap_control_handlers(), msg); asn1_free(asn1); - return NT_STATUS_OK; -} + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(msg); + ldap_error_handler(conn, status); + return; + } -/* Handle read events, from the GENSEC socket callback, or real events */ -void ldap_read_io_handler(void *private_data, uint16_t flags) -{ - struct ldap_connection *conn = talloc_get_type(private_data, - struct ldap_connection); - packet_recv(conn->packet); -} + ldap_match_message(conn, msg); + ldap_connection_recv_next(conn); -/* - handle ldap socket events -*/ -static void ldap_io_handler(struct tevent_context *ev, struct tevent_fd *fde, - uint16_t flags, void *private_data) -{ - struct ldap_connection *conn = talloc_get_type(private_data, - struct ldap_connection); - if (flags & TEVENT_FD_WRITE) { - packet_queue_run(conn->packet); - if (!tls_enabled(conn->sock)) return; - } - if (flags & TEVENT_FD_READ) { - ldap_read_io_handler(private_data, flags); - } + return; } /* @@ -284,6 +366,10 @@ static NTSTATUS ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url, struct ldap_connect_state { struct composite_context *ctx; struct ldap_connection *conn; + struct socket_context *sock; + struct tstream_context *raw; + struct tstream_tls_params *tls_params; + struct tstream_context *tls; }; static void ldap_connect_recv_unix_conn(struct composite_context *ctx); @@ -327,11 +413,11 @@ _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *con struct socket_address *unix_addr; char path[1025]; - NTSTATUS status = socket_create("unix", SOCKET_TYPE_STREAM, &conn->sock, 0); + NTSTATUS status = socket_create("unix", SOCKET_TYPE_STREAM, &state->sock, 0); if (!NT_STATUS_IS_OK(status)) { return NULL; } - talloc_steal(conn, conn->sock); + talloc_steal(state, state->sock); SMB_ASSERT(sizeof(protocol)>10); SMB_ASSERT(sizeof(path)>1024); @@ -354,29 +440,53 @@ _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *con } rfc1738_unescape(path); - - unix_addr = socket_address_from_strings(conn, conn->sock->backend_name, + + unix_addr = socket_address_from_strings(state, state->sock->backend_name, path, 0); - if (!unix_addr) { - return NULL; + if (composite_nomem(unix_addr, result)) { + return result; } - ctx = socket_connect_send(conn->sock, NULL, unix_addr, - 0, conn->event.event_ctx); + + ctx = socket_connect_send(state->sock, NULL, unix_addr, + 0, result->event_ctx); ctx->async.fn = ldap_connect_recv_unix_conn; ctx->async.private_data = state; return result; } else { NTSTATUS status = ldap_parse_basic_url(conn, url, &conn->host, &conn->port, &conn->ldaps); - if (!NT_STATUS_IS_OK(state->ctx->status)) { - composite_error(state->ctx, status); + if (!NT_STATUS_IS_OK(status)) { + composite_error(result, status); return result; } - + + if (conn->ldaps) { + char *ca_file = lpcfg_tls_cafile(state, conn->lp_ctx); + char *crl_file = lpcfg_tls_crlfile(state, conn->lp_ctx); + const char *tls_priority = lpcfg_tls_priority(conn->lp_ctx); + enum tls_verify_peer_state verify_peer = + lpcfg_tls_verify_peer(conn->lp_ctx); + + status = tstream_tls_params_client(state, + ca_file, + crl_file, + tls_priority, + verify_peer, + conn->host, + &state->tls_params); + if (!NT_STATUS_IS_OK(status)) { + composite_error(result, status); + return result; + } + } + ctx = socket_connect_multi_send(state, conn->host, 1, &conn->port, - lpcfg_resolve_context(conn->lp_ctx), conn->event.event_ctx); - if (ctx == NULL) goto failed; + lpcfg_resolve_context(conn->lp_ctx), + result->event_ctx); + if (composite_nomem(ctx, result)) { + return result; + } ctx->async.fn = ldap_connect_recv_tcp_conn; ctx->async.private_data = state; @@ -387,72 +497,80 @@ _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *con return NULL; } +static void ldap_connect_got_tls(struct tevent_req *subreq); + static void ldap_connect_got_sock(struct composite_context *ctx, - struct ldap_connection *conn) + struct ldap_connection *conn) { - /* setup a handler for events on this socket */ - conn->event.fde = tevent_add_fd(conn->event.event_ctx, conn->sock, - socket_get_fd(conn->sock), - TEVENT_FD_READ, ldap_io_handler, conn); - if (conn->event.fde == NULL) { - composite_error(ctx, NT_STATUS_INTERNAL_ERROR); - return; - } - - tevent_fd_set_close_fn(conn->event.fde, socket_tevent_fd_close_fn); - socket_set_flags(conn->sock, SOCKET_FLAG_NOCLOSE); + struct ldap_connect_state *state = + talloc_get_type_abort(ctx->private_data, + struct ldap_connect_state); + struct tevent_req *subreq = NULL; + int fd; + int ret; - talloc_steal(conn, conn->sock); - if (conn->ldaps) { - struct socket_context *tls_socket; - char *cafile = lpcfg_tls_cafile(conn->sock, conn->lp_ctx); + socket_set_flags(state->sock, SOCKET_FLAG_NOCLOSE); + fd = socket_get_fd(state->sock); + TALLOC_FREE(state->sock); - if (!cafile || !*cafile) { - talloc_free(conn->sock); - return; - } + smb_set_close_on_exec(fd); + set_blocking(fd, false); - tls_socket = tls_init_client(conn->sock, conn->event.fde, cafile); - talloc_free(cafile); - - if (tls_socket == NULL) { - talloc_free(conn->sock); - return; - } + ret = tstream_bsd_existing_socket(state, fd, &state->raw); + if (ret == -1) { + NTSTATUS status = map_nt_error_from_unix_common(errno); + composite_error(state->ctx, status); + return; + } - conn->sock = talloc_steal(conn, tls_socket); + if (!conn->ldaps) { + conn->sockets.raw = talloc_move(conn, &state->raw); + conn->sockets.active = conn->sockets.raw; + composite_done(state->ctx); + return; } - conn->packet = packet_init(conn); - if (conn->packet == NULL) { - talloc_free(conn->sock); + subreq = tstream_tls_connect_send(state, state->ctx->event_ctx, + state->raw, state->tls_params); + if (composite_nomem(subreq, state->ctx)) { return; } + tevent_req_set_callback(subreq, ldap_connect_got_tls, state); +} - packet_set_private(conn->packet, conn); - packet_set_socket(conn->packet, conn->sock); - packet_set_callback(conn->packet, ldap_recv_handler); - packet_set_full_request(conn->packet, ldap_full_packet); - packet_set_error_handler(conn->packet, ldap_error_handler); - packet_set_event_context(conn->packet, conn->event.event_ctx); - packet_set_fde(conn->packet, conn->event.fde); -/* packet_set_serialise(conn->packet); */ +static void ldap_connect_got_tls(struct tevent_req *subreq) +{ + struct ldap_connect_state *state = + tevent_req_callback_data(subreq, + struct ldap_connect_state); + int err; + int ret; - if (conn->ldaps) { - packet_set_unreliable_select(conn->packet); + ret = tstream_tls_connect_recv(subreq, &err, state, &state->tls); + TALLOC_FREE(subreq); + if (ret == -1) { + NTSTATUS status = map_nt_error_from_unix_common(err); + composite_error(state->ctx, status); + return; } - composite_done(ctx); + talloc_steal(state->tls, state->tls_params); + + state->conn->sockets.raw = talloc_move(state->conn, &state->raw); + state->conn->sockets.tls = talloc_move(state->conn->sockets.raw, + &state->tls); + state->conn->sockets.active = state->conn->sockets.tls; + composite_done(state->ctx); } static void ldap_connect_recv_tcp_conn(struct composite_context *ctx) { struct ldap_connect_state *state = - talloc_get_type(ctx->async.private_data, - struct ldap_connect_state); + talloc_get_type_abort(ctx->async.private_data, + struct ldap_connect_state); struct ldap_connection *conn = state->conn; uint16_t port; - NTSTATUS status = socket_connect_multi_recv(ctx, state, &conn->sock, + NTSTATUS status = socket_connect_multi_recv(ctx, state, &state->sock, &port); if (!NT_STATUS_IS_OK(status)) { composite_error(state->ctx, status); @@ -465,8 +583,8 @@ static void ldap_connect_recv_tcp_conn(struct composite_context *ctx) static void ldap_connect_recv_unix_conn(struct composite_context *ctx) { struct ldap_connect_state *state = - talloc_get_type(ctx->async.private_data, - struct ldap_connect_state); + talloc_get_type_abort(ctx->async.private_data, + struct ldap_connect_state); struct ldap_connection *conn = state->conn; NTSTATUS status = socket_connect_recv(ctx); @@ -533,7 +651,7 @@ static void ldap_reconnect(struct ldap_connection *conn) /* rebind */ status = ldap_rebind(conn); if ( ! NT_STATUS_IS_OK(status)) { - ldap_connection_dead(conn); + ldap_connection_dead(conn, status); } } @@ -552,7 +670,10 @@ static int ldap_request_destructor(struct ldap_request *req) static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer *te, struct timeval t, void *private_data) { - struct ldap_request *req = talloc_get_type(private_data, struct ldap_request); + struct ldap_request *req = + talloc_get_type_abort(private_data, + struct ldap_request); + req->status = NT_STATUS_IO_TIMEOUT; if (req->state == LDAP_REQUEST_PENDING) { DLIST_REMOVE(req->conn->pending, req); @@ -570,26 +691,17 @@ static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer static void ldap_request_failed_complete(struct tevent_context *ev, struct tevent_timer *te, struct timeval t, void *private_data) { - struct ldap_request *req = talloc_get_type(private_data, struct ldap_request); - if (req->async.fn) { - req->async.fn(req); - } -} + struct ldap_request *req = + talloc_get_type_abort(private_data, + struct ldap_request); -/* - called on completion of a one-way ldap request -*/ -static void ldap_request_oneway_complete(void *private_data) -{ - struct ldap_request *req = talloc_get_type(private_data, struct ldap_request); - if (req->state == LDAP_REQUEST_PENDING) { - DLIST_REMOVE(req->conn->pending, req); - } - req->state = LDAP_REQUEST_DONE; if (req->async.fn) { req->async.fn(req); } } + +static void ldap_request_written(struct tevent_req *subreq); + /* send a ldap message - async interface */ @@ -598,12 +710,12 @@ _PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn, { struct ldap_request *req; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; - packet_send_callback_fn_t send_callback = NULL; + struct tevent_req *subreq = NULL; req = talloc_zero(conn, struct ldap_request); if (req == NULL) return NULL; - if (conn->sock == NULL) { + if (conn->sockets.active == NULL) { status = NT_STATUS_INVALID_CONNECTION; goto failed; } @@ -628,25 +740,31 @@ _PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn, goto failed; } - if (req->type == LDAP_TAG_AbandonRequest || - req->type == LDAP_TAG_UnbindRequest) { - send_callback = ldap_request_oneway_complete; + /* put a timeout on the request */ + req->time_event = tevent_add_timer(conn->event.event_ctx, req, + timeval_current_ofs(conn->timeout, 0), + ldap_request_timeout, req); + if (req->time_event == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; } - status = packet_send_callback(conn->packet, req->data, - send_callback, req); - if (!NT_STATUS_IS_OK(status)) { + req->write_iov.iov_base = req->data.data; + req->write_iov.iov_len = req->data.length; + + subreq = tstream_writev_queue_send(req, conn->event.event_ctx, + conn->sockets.active, + conn->sockets.send_queue, + &req->write_iov, 1); + if (subreq == NULL) { + status = NT_STATUS_NO_MEMORY; goto failed; } + tevent_req_set_callback(subreq, ldap_request_written, req); req->state = LDAP_REQUEST_PENDING; DLIST_ADD(conn->pending, req); - /* put a timeout on the request */ - req->time_event = tevent_add_timer(conn->event.event_ctx, req, - timeval_current_ofs(conn->timeout, 0), - ldap_request_timeout, req); - return req; failed: @@ -658,6 +776,38 @@ failed: return req; } +static void ldap_request_written(struct tevent_req *subreq) +{ + struct ldap_request *req = + tevent_req_callback_data(subreq, + struct ldap_request); + int err; + ssize_t ret; + + ret = tstream_writev_queue_recv(subreq, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + NTSTATUS error = map_nt_error_from_unix_common(err); + ldap_error_handler(req->conn, error); + return; + } + + if (req->type == LDAP_TAG_AbandonRequest || + req->type == LDAP_TAG_UnbindRequest) + { + if (req->state == LDAP_REQUEST_PENDING) { + DLIST_REMOVE(req->conn->pending, req); + } + req->state = LDAP_REQUEST_DONE; + if (req->async.fn) { + req->async.fn(req); + } + return; + } + + ldap_connection_recv_next(req->conn); +} + /* wait for a request to complete @@ -667,6 +817,7 @@ _PUBLIC_ NTSTATUS ldap_request_wait(struct ldap_request *req) { while (req->state < LDAP_REQUEST_DONE) { if (tevent_loop_once(req->conn->event.event_ctx) != 0) { + req->state = LDAP_REQUEST_ERROR; req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; break; } diff --git a/source4/libcli/ldap/ldap_client.h b/source4/libcli/ldap/ldap_client.h index 3b4da6bcf23..e2b1b30e493 100644 --- a/source4/libcli/ldap/ldap_client.h +++ b/source4/libcli/ldap/ldap_client.h @@ -20,6 +20,7 @@ */ +#include "system/network.h" /* for struct iovec */ #include "libcli/ldap/libcli_ldap.h" enum ldap_request_state { LDAP_REQUEST_SEND=1, LDAP_REQUEST_PENDING=2, LDAP_REQUEST_DONE=3, LDAP_REQUEST_ERROR=4 }; @@ -39,6 +40,8 @@ struct ldap_request { NTSTATUS status; DATA_BLOB data; + struct iovec write_iov; + struct { void (*fn)(struct ldap_request *); void *private_data; @@ -50,7 +53,16 @@ struct ldap_request { /* main context for a ldap client connection */ struct ldap_connection { - struct socket_context *sock; + struct { + struct tstream_context *raw; + struct tstream_context *tls; + struct tstream_context *sasl; + struct tstream_context *active; + + struct tevent_queue *send_queue; + struct tevent_req *recv_subreq; + } sockets; + struct loadparm_context *lp_ctx; char *host; @@ -89,10 +101,7 @@ struct ldap_connection { struct { struct tevent_context *event_ctx; - struct tevent_fd *fde; } event; - - struct packet_context *packet; }; struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx, diff --git a/source4/libcli/ldap/ldap_controls.c b/source4/libcli/ldap/ldap_controls.c index f910acba383..448a2633c26 100644 --- a/source4/libcli/ldap/ldap_controls.c +++ b/source4/libcli/ldap/ldap_controls.c @@ -512,10 +512,10 @@ static bool encode_verify_name_request(void *mem_ctx, void *in, DATA_BLOB *out) return false; } - *out = data_blob_talloc(mem_ctx, data->data, data->length); - if (out->data == NULL) { + if (!asn1_extract_blob(data, mem_ctx, out)) { return false; } + talloc_free(data); return true; @@ -716,10 +716,10 @@ static bool encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out) return false; } - *out = data_blob_talloc(mem_ctx, data->data, data->length); - if (out->data == NULL) { + if (!asn1_extract_blob(data, mem_ctx, out)) { return false; } + talloc_free(data); return true; @@ -774,10 +774,10 @@ static bool encode_server_sort_request(void *mem_ctx, void *in, DATA_BLOB *out) return false; } - *out = data_blob_talloc(mem_ctx, data->data, data->length); - if (out->data == NULL) { + if (!asn1_extract_blob(data, mem_ctx, out)) { return false; } + talloc_free(data); return true; @@ -809,10 +809,10 @@ static bool encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out) return false; } - *out = data_blob_talloc(mem_ctx, data->data, data->length); - if (out->data == NULL) { + if (!asn1_extract_blob(data, mem_ctx, out)) { return false; } + talloc_free(data); return true; @@ -837,10 +837,10 @@ static bool encode_sd_flags_request(void *mem_ctx, void *in, DATA_BLOB *out) return false; } - *out = data_blob_talloc(mem_ctx, data->data, data->length); - if (out->data == NULL) { + if (!asn1_extract_blob(data, mem_ctx, out)) { return false; } + talloc_free(data); return true; @@ -865,10 +865,10 @@ static bool encode_search_options_request(void *mem_ctx, void *in, DATA_BLOB *ou return false; } - *out = data_blob_talloc(mem_ctx, data->data, data->length); - if (out->data == NULL) { + if (!asn1_extract_blob(data, mem_ctx, out)) { return false; } + talloc_free(data); return true; @@ -897,10 +897,10 @@ static bool encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out return false; } - *out = data_blob_talloc(mem_ctx, data->data, data->length); - if (out->data == NULL) { + if (!asn1_extract_blob(data, mem_ctx, out)) { return false; } + talloc_free(data); return true; @@ -935,10 +935,10 @@ static bool encode_asq_control(void *mem_ctx, void *in, DATA_BLOB *out) return false; } - *out = data_blob_talloc(mem_ctx, data->data, data->length); - if (out->data == NULL) { + if (!asn1_extract_blob(data, mem_ctx, out)) { return false; } + talloc_free(data); return true; @@ -971,10 +971,10 @@ static bool encode_dirsync_request(void *mem_ctx, void *in, DATA_BLOB *out) return false; } - *out = data_blob_talloc(mem_ctx, data->data, data->length); - if (out->data == NULL) { + if (!asn1_extract_blob(data, mem_ctx, out)) { return false; } + talloc_free(data); return true; @@ -1047,10 +1047,10 @@ static bool encode_vlv_request(void *mem_ctx, void *in, DATA_BLOB *out) return false; } - *out = data_blob_talloc(mem_ctx, data->data, data->length); - if (out->data == NULL) { + if (!asn1_extract_blob(data, mem_ctx, out)) { return false; } + talloc_free(data); return true; @@ -1089,10 +1089,10 @@ static bool encode_vlv_response(void *mem_ctx, void *in, DATA_BLOB *out) return false; } - *out = data_blob_talloc(mem_ctx, data->data, data->length); - if (out->data == NULL) { + if (!asn1_extract_blob(data, mem_ctx, out)) { return false; } + talloc_free(data); return true; @@ -1140,10 +1140,10 @@ static bool encode_openldap_dereference(void *mem_ctx, void *in, DATA_BLOB *out) return false; } - *out = data_blob_talloc(mem_ctx, data->data, data->length); - if (out->data == NULL) { + if (!asn1_extract_blob(data, mem_ctx, out)) { return false; } + talloc_free(data); return true; } diff --git a/source4/libcli/ldap/wscript_build b/source4/libcli/ldap/wscript_build index f7afec73f29..f79cc2b6149 100644 --- a/source4/libcli/ldap/wscript_build +++ b/source4/libcli/ldap/wscript_build @@ -3,9 +3,9 @@ bld.SAMBA_LIBRARY('cli-ldap', source='ldap_client.c ldap_bind.c ldap_ildap.c ldap_controls.c', autoproto='ldap_proto.h', - public_deps='errors tevent LIBPACKET', + public_deps='errors tevent', public_headers='libcli_ldap.h:ldap-util.h', - deps='cli_composite samba_socket NDR_SAMR LIBTLS ndr LP_RESOLVE gensec cli-ldap-common', + deps='cli_composite LIBSAMBA_TSOCKET samba_socket NDR_SAMR LIBTLS ndr LP_RESOLVE gensec cli-ldap-common', private_library=True ) diff --git a/source4/libcli/raw/libcliraw.h b/source4/libcli/raw/libcliraw.h index 95e69431c1e..8220cd7c563 100644 --- a/source4/libcli/raw/libcliraw.h +++ b/source4/libcli/raw/libcliraw.h @@ -95,6 +95,7 @@ struct smbcli_options { unsigned int use_spnego:1; unsigned int unicode:1; unsigned int ntstatus_support:1; + int min_protocol; int max_protocol; uint32_t max_xmit; uint16_t max_mux; diff --git a/source4/libcli/raw/rawnegotiate.c b/source4/libcli/raw/rawnegotiate.c index 9b0ed38cf0c..4b42c2662a0 100644 --- a/source4/libcli/raw/rawnegotiate.c +++ b/source4/libcli/raw/rawnegotiate.c @@ -37,6 +37,7 @@ static void smb_raw_negotiate_done(struct tevent_req *subreq); struct tevent_req *smb_raw_negotiate_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbcli_transport *transport, + int minprotocol, int maxprotocol) { struct tevent_req *req; @@ -51,10 +52,14 @@ struct tevent_req *smb_raw_negotiate_send(TALLOC_CTX *mem_ctx, } state->transport = transport; + if (maxprotocol > PROTOCOL_NT1) { + maxprotocol = PROTOCOL_NT1; + } + subreq = smbXcli_negprot_send(state, ev, transport->conn, timeout_msec, - PROTOCOL_CORE, + minprotocol, maxprotocol); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); @@ -127,7 +132,8 @@ NTSTATUS smb_raw_negotiate_recv(struct tevent_req *req) /* Send a negprot command (sync interface) */ -NTSTATUS smb_raw_negotiate(struct smbcli_transport *transport, bool unicode, int maxprotocol) +NTSTATUS smb_raw_negotiate(struct smbcli_transport *transport, bool unicode, + int minprotocol, int maxprotocol) { NTSTATUS status = NT_STATUS_INTERNAL_ERROR; struct tevent_req *subreq = NULL; @@ -136,6 +142,7 @@ NTSTATUS smb_raw_negotiate(struct smbcli_transport *transport, bool unicode, int subreq = smb_raw_negotiate_send(transport, transport->ev, transport, + minprotocol, maxprotocol); if (subreq == NULL) { return NT_STATUS_NO_MEMORY; diff --git a/source4/libcli/smb2/connect.c b/source4/libcli/smb2/connect.c index 9535380d646..1a6ae34d2cd 100644 --- a/source4/libcli/smb2/connect.c +++ b/source4/libcli/smb2/connect.c @@ -134,6 +134,7 @@ static void smb2_connect_socket_done(struct composite_context *creq) struct tevent_req *subreq; NTSTATUS status; uint32_t timeout_msec; + enum protocol_types min_protocol; status = smbcli_sock_connect_recv(creq, state, &sock); if (tevent_req_nterror(req, status)) { @@ -146,10 +147,14 @@ static void smb2_connect_socket_done(struct composite_context *creq) } timeout_msec = state->transport->options.request_timeout * 1000; + min_protocol = state->transport->options.min_protocol; + if (min_protocol < PROTOCOL_SMB2_02) { + min_protocol = PROTOCOL_SMB2_02; + } subreq = smbXcli_negprot_send(state, state->ev, state->transport->conn, timeout_msec, - PROTOCOL_SMB2_02, + min_protocol, state->transport->options.max_protocol); if (tevent_req_nomem(subreq, req)) { return; diff --git a/source4/libcli/smb_composite/connect.c b/source4/libcli/smb_composite/connect.c index d87d5ecae27..fffa768ac97 100644 --- a/source4/libcli/smb_composite/connect.c +++ b/source4/libcli/smb_composite/connect.c @@ -297,6 +297,7 @@ static NTSTATUS connect_send_negprot(struct composite_context *c, state->subreq = smb_raw_negotiate_send(state, state->transport->ev, state->transport, + state->transport->options.min_protocol, state->transport->options.max_protocol); NT_STATUS_HAVE_NO_MEMORY(state->subreq); tevent_req_set_callback(state->subreq, subreq_handler, c); diff --git a/source4/libcli/smb_composite/sesssetup.c b/source4/libcli/smb_composite/sesssetup.c index e4964c19b5d..9f989f21f2c 100644 --- a/source4/libcli/smb_composite/sesssetup.c +++ b/source4/libcli/smb_composite/sesssetup.c @@ -329,9 +329,21 @@ static NTSTATUS session_setup_nt1(struct composite_context *c, if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) { + if (!cli_credentials_is_anonymous(io->in.credentials) && + session->options.ntlmv2_auth && + session->transport->options.use_spnego) + { + /* + * Don't send an NTLMv2_RESPONSE without NTLMSSP + * if we want to use spnego + */ + return NT_STATUS_INVALID_PARAMETER; + } + nt_status = cli_credentials_get_ntlm_response(io->in.credentials, state, &flags, session->transport->negotiate.secblob, + NULL, /* server_timestamp */ names_blob, &state->setup.nt1.in.password1, &state->setup.nt1.in.password2, @@ -392,24 +404,13 @@ static NTSTATUS session_setup_old(struct composite_context *c, struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state); const char *password = cli_credentials_get_password(io->in.credentials); - const char *domain = cli_credentials_get_domain(io->in.credentials); /* * domain controllers tend to reject the NTLM v2 blob * if the netbiosname is not valid (e.g. IP address or FQDN) * so just leave it away (as Windows client do) */ - DATA_BLOB names_blob = NTLMv2_generate_names_blob(state, NULL, domain); - DATA_BLOB session_key; - int flags = 0; - if (session->options.lanman_auth) { - flags |= CLI_CRED_LANMAN_AUTH; - } - - if (session->options.ntlmv2_auth) { - flags |= CLI_CRED_NTLMv2_AUTH; - } state->setup.old.level = RAW_SESSSETUP_OLD; state->setup.old.in.bufsize = session->transport->options.max_xmit; @@ -423,9 +424,21 @@ static NTSTATUS session_setup_old(struct composite_context *c, &state->setup.old.in.domain); if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) { + DATA_BLOB names_blob = data_blob_null; + int flags = 0; + + if (!cli_credentials_is_anonymous(io->in.credentials) && + !session->options.lanman_auth) + { + return NT_STATUS_INVALID_PARAMETER; + } + + flags |= CLI_CRED_LANMAN_AUTH; + nt_status = cli_credentials_get_ntlm_response(io->in.credentials, state, &flags, session->transport->negotiate.secblob, + NULL, /* server_timestamp */ names_blob, &state->setup.old.in.password, NULL, diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 6e3410bd238..827499155f8 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -65,6 +65,8 @@ struct rpc_request { DATA_BLOB request_data; bool ignore_timeout; bool wait_for_sync; + bool verify_bitmask1; + bool verify_pcontext; struct { void (*callback)(struct rpc_request *); @@ -139,7 +141,9 @@ static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, } c->call_id = 1; - c->security_state.auth_info = NULL; + c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE; + c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE; + c->security_state.auth_context_id = 0; c->security_state.session_key = dcerpc_generic_session_key; c->security_state.generic_state = NULL; c->flags = 0; @@ -220,12 +224,8 @@ static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h, return; } - if (hs->p->conn->security_state.auth_info == NULL) { - return; - } - - *auth_type = hs->p->conn->security_state.auth_info->auth_type; - *auth_level = hs->p->conn->security_state.auth_info->auth_level; + *auth_type = hs->p->conn->security_state.auth_type; + *auth_level = hs->p->conn->security_state.auth_level; } struct dcerpc_bh_raw_call_state { @@ -741,12 +741,16 @@ static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX struct dcerpc_auth auth; uint32_t auth_length; - if (!c->security_state.auth_info || - !c->security_state.generic_state) { - return NT_STATUS_OK; + status = dcerpc_verify_ncacn_packet_header(pkt, DCERPC_PKT_RESPONSE, + pkt->u.response.stub_and_verifier.length, + 0, /* required_flags */ + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST); + if (!NT_STATUS_IS_OK(status)) { + return status; } - switch (c->security_state.auth_info->auth_level) { + switch (c->security_state.auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: case DCERPC_AUTH_LEVEL_INTEGRITY: break; @@ -766,6 +770,14 @@ static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX return NT_STATUS_INVALID_LEVEL; } + if (pkt->auth_length == 0) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + if (c->security_state.generic_state == NULL) { + return NT_STATUS_INTERNAL_ERROR; + } + status = dcerpc_pull_auth_trailer(pkt, mem_ctx, &pkt->u.response.stub_and_verifier, &auth, &auth_length, false); @@ -773,8 +785,20 @@ static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX pkt->u.response.stub_and_verifier.length -= auth_length; + if (auth.auth_type != c->security_state.auth_type) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + + if (auth.auth_level != c->security_state.auth_level) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + + if (auth.auth_context_id != c->security_state.auth_context_id) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + /* check signature or unseal the packet */ - switch (c->security_state.auth_info->auth_level) { + switch (c->security_state.auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: status = gensec_unseal_packet(c->security_state.generic_state, raw_packet->data + DCERPC_REQUEST_LENGTH, @@ -830,13 +854,13 @@ static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c, size_t payload_length; enum ndr_err_code ndr_err; size_t hdr_size = DCERPC_REQUEST_LENGTH; + struct dcerpc_auth auth_info = { + .auth_type = c->security_state.auth_type, + .auth_level = c->security_state.auth_level, + .auth_context_id = c->security_state.auth_context_id, + }; - /* non-signed packets are simpler */ - if (c->security_state.auth_info == NULL) { - return ncacn_push_auth(blob, mem_ctx, pkt, NULL); - } - - switch (c->security_state.auth_info->auth_level) { + switch (c->security_state.auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: case DCERPC_AUTH_LEVEL_INTEGRITY: if (sig_size == 0) { @@ -883,21 +907,18 @@ static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c, ndr_push_align() as that is relative to the start of the whole packet, whereas w2k8 wants it relative to the start of the stub */ - c->security_state.auth_info->auth_pad_length = + auth_info.auth_pad_length = DCERPC_AUTH_PAD_LENGTH(pkt->u.request.stub_and_verifier.length); - ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length); + ndr_err = ndr_push_zero(ndr, auth_info.auth_pad_length); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return ndr_map_error2ntstatus(ndr_err); } payload_length = pkt->u.request.stub_and_verifier.length + - c->security_state.auth_info->auth_pad_length; - - /* we start without signature, it will appended later */ - c->security_state.auth_info->credentials = data_blob(NULL,0); + auth_info.auth_pad_length; /* add the auth verifier */ - ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info); + ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth_info); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return ndr_map_error2ntstatus(ndr_err); } @@ -915,7 +936,7 @@ static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c, dcerpc_set_auth_length(blob, sig_size); /* sign or seal the packet */ - switch (c->security_state.auth_info->auth_level) { + switch (c->security_state.auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: status = gensec_seal_packet(c->security_state.generic_state, mem_ctx, @@ -955,7 +976,7 @@ static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c, DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n", (unsigned) creds2.length, (unsigned) sig_size, - (unsigned) c->security_state.auth_info->auth_pad_length, + (unsigned) auth_info.auth_pad_length, (unsigned) pkt->u.request.stub_and_verifier.length)); dcerpc_set_frag_length(blob, blob->length + creds2.length); dcerpc_set_auth_length(blob, creds2.length); @@ -1223,7 +1244,7 @@ struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx, /* construct the NDR form of the packet */ status = ncacn_push_auth(&blob, state, &pkt, - p->conn->security_state.auth_info); + p->conn->security_state.tmp_auth_info.out); if (tevent_req_nterror(req, status)) { return tevent_req_post(req, ev); } @@ -1296,6 +1317,7 @@ static void dcerpc_bind_recv_handler(struct rpc_request *subreq, tevent_req_data(req, struct dcerpc_bind_state); struct dcecli_connection *conn = state->p->conn; + struct dcecli_security *sec = &conn->security_state; struct dcerpc_binding *b = NULL; NTSTATUS status; uint32_t flags; @@ -1329,14 +1351,34 @@ static void dcerpc_bind_recv_handler(struct rpc_request *subreq, return; } - if ((pkt->ptype != DCERPC_PKT_BIND_ACK) || - (pkt->u.bind_ack.num_results == 0) || - (pkt->u.bind_ack.ctx_list[0].result != 0)) { + status = dcerpc_verify_ncacn_packet_header(pkt, + DCERPC_PKT_BIND_ACK, + pkt->u.bind_ack.auth_info.length, + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST, + DCERPC_PFC_FLAG_CONC_MPX | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN); + if (!NT_STATUS_IS_OK(status)) { state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR; tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT); return; } + if (pkt->u.bind_ack.num_results != 1) { + state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR; + tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT); + return; + } + + if (pkt->u.bind_ack.ctx_list[0].result != 0) { + status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]); + DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n", + pkt->u.bind_ack.ctx_list[0].reason.value, + nt_errstr(status))); + tevent_req_nterror(req, status); + return; + } + /* * DCE-RPC 1.1 (c706) specifies * CONST_MUST_RCV_FRAG_SIZE as 1432 @@ -1369,11 +1411,13 @@ static void dcerpc_bind_recv_handler(struct rpc_request *subreq, } /* the bind_ack might contain a reply set of credentials */ - if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) { + if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) { uint32_t auth_length; - status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info, - conn->security_state.auth_info, &auth_length, true); + status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem, + &pkt->u.bind_ack.auth_info, + sec->tmp_auth_info.in, + &auth_length, true); if (tevent_req_nterror(req, status)) { return; } @@ -1423,9 +1467,8 @@ NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p, } /* construct the NDR form of the packet */ - status = ncacn_push_auth(&blob, mem_ctx, - &pkt, - p->conn->security_state.auth_info); + status = ncacn_push_auth(&blob, mem_ctx, &pkt, + p->conn->security_state.tmp_auth_info.out); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -1461,8 +1504,7 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c, to run the auth routines so that we don't get the sign/seal info out of step with the server */ - if (c->security_state.auth_info && c->security_state.generic_state && - pkt->ptype == DCERPC_PKT_RESPONSE) { + if (pkt->ptype == DCERPC_PKT_RESPONSE) { status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt); } @@ -1502,7 +1544,16 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c, } if (pkt->ptype == DCERPC_PKT_FAULT) { + status = dcerpc_fault_to_nt_status(pkt->u.fault.status); DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status))); + if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) { + dcerpc_connection_dead(c, status); + return; + } + if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) { + dcerpc_connection_dead(c, status); + return; + } req->fault_code = pkt->u.fault.status; req->status = NT_STATUS_NET_WRITE_FAULT; goto req_done; @@ -1511,20 +1562,27 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c, if (pkt->ptype != DCERPC_PKT_RESPONSE) { DEBUG(2,("Unexpected packet type %d in dcerpc response\n", (int)pkt->ptype)); - req->fault_code = DCERPC_FAULT_OTHER; - req->status = NT_STATUS_NET_WRITE_FAULT; - goto req_done; + dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR); + return; } /* now check the status from the auth routines, and if it failed then fail this request accordingly */ if (!NT_STATUS_IS_OK(status)) { - req->status = status; - goto req_done; + dcerpc_connection_dead(c, status); + return; } length = pkt->u.response.stub_and_verifier.length; + if (req->payload.length + length > DCERPC_NCACN_PAYLOAD_MAX_SIZE) { + DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n", + (unsigned)req->payload.length + length, + DCERPC_NCACN_PAYLOAD_MAX_SIZE)); + dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR); + return; + } + if (length > 0) { req->payload.data = talloc_realloc(req, req->payload.data, @@ -1545,6 +1603,13 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c, return; } + if (req->verify_bitmask1) { + req->p->conn->security_state.verified_bitmask1 = true; + } + if (req->verify_pcontext) { + req->p->verified_pcontext = true; + } + if (!(pkt->drep[0] & DCERPC_DREP_LE)) { req->flags |= DCERPC_PULL_BIGENDIAN; } else { @@ -1569,6 +1634,8 @@ req_done: } } +static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req); + /* perform the send side of a async dcerpc request */ @@ -1579,6 +1646,7 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx, DATA_BLOB *stub_data) { struct rpc_request *req; + NTSTATUS status; req = talloc_zero(mem_ctx, struct rpc_request); if (req == NULL) { @@ -1601,6 +1669,12 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx, req->request_data.length = stub_data->length; req->request_data.data = stub_data->data; + status = dcerpc_request_prepare_vt(req); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(req); + return NULL; + } + DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *); talloc_set_destructor(req, dcerpc_req_dequeue); @@ -1615,6 +1689,120 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx, return req; } +static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req) +{ + struct dcecli_security *sec = &req->p->conn->security_state; + struct dcerpc_sec_verification_trailer *t; + struct dcerpc_sec_vt *c = NULL; + struct ndr_push *ndr = NULL; + enum ndr_err_code ndr_err; + + if (sec->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) { + return NT_STATUS_OK; + } + + t = talloc_zero(req, struct dcerpc_sec_verification_trailer); + if (t == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (!sec->verified_bitmask1) { + t->commands = talloc_realloc(t, t->commands, + struct dcerpc_sec_vt, + t->count.count + 1); + if (t->commands == NULL) { + return NT_STATUS_NO_MEMORY; + } + c = &t->commands[t->count.count++]; + ZERO_STRUCTP(c); + + c->command = DCERPC_SEC_VT_COMMAND_BITMASK1; + if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) { + c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING; + } + req->verify_bitmask1 = true; + } + + if (!req->p->verified_pcontext) { + t->commands = talloc_realloc(t, t->commands, + struct dcerpc_sec_vt, + t->count.count + 1); + if (t->commands == NULL) { + return NT_STATUS_NO_MEMORY; + } + c = &t->commands[t->count.count++]; + ZERO_STRUCTP(c); + + c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT; + c->u.pcontext.abstract_syntax = req->p->syntax; + c->u.pcontext.transfer_syntax = req->p->transfer_syntax; + + req->verify_pcontext = true; + } + + if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) { + t->commands = talloc_realloc(t, t->commands, + struct dcerpc_sec_vt, + t->count.count + 1); + if (t->commands == NULL) { + return NT_STATUS_NO_MEMORY; + } + c = &t->commands[t->count.count++]; + ZERO_STRUCTP(c); + + c->command = DCERPC_SEC_VT_COMMAND_HEADER2; + c->u.header2.ptype = DCERPC_PKT_REQUEST; + if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) { + c->u.header2.drep[0] = 0; + } else { + c->u.header2.drep[0] = DCERPC_DREP_LE; + } + c->u.header2.drep[1] = 0; + c->u.header2.drep[2] = 0; + c->u.header2.drep[3] = 0; + c->u.header2.call_id = req->call_id; + c->u.header2.context_id = req->p->context_id; + c->u.header2.opnum = req->opnum; + } + + if (t->count.count == 0) { + TALLOC_FREE(t); + return NT_STATUS_OK; + } + + c = &t->commands[t->count.count - 1]; + c->command |= DCERPC_SEC_VT_COMMAND_END; + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t); + } + + ndr = ndr_push_init_ctx(req); + if (ndr == NULL) { + return NT_STATUS_NO_MEMORY; + } + + /* + * for now we just copy and append + */ + + ndr_err = ndr_push_bytes(ndr, req->request_data.data, + req->request_data.length); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr, + NDR_SCALARS | NDR_BUFFERS, + t); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + req->request_data = ndr_push_blob(ndr); + + return NT_STATUS_OK; +} + /* Send a request using the transport */ @@ -1644,25 +1832,9 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c) need_async = true; } - if (c->security_state.auth_info && - c->security_state.generic_state) - { - struct gensec_security *gensec = c->security_state.generic_state; - - switch (c->security_state.auth_info->auth_level) { - case DCERPC_AUTH_LEVEL_PRIVACY: - case DCERPC_AUTH_LEVEL_INTEGRITY: - can_async = gensec_have_feature(gensec, + if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) { + can_async = gensec_have_feature(c->security_state.generic_state, GENSEC_FEATURE_ASYNC_REPLIES); - break; - case DCERPC_AUTH_LEVEL_CONNECT: - case DCERPC_AUTH_LEVEL_NONE: - can_async = true; - break; - default: - can_async = false; - break; - } } if (need_async && !can_async) { @@ -1682,8 +1854,7 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c) request header size */ chunk_size = p->conn->srv_max_recv_frag; chunk_size -= DCERPC_REQUEST_LENGTH; - if (c->security_state.auth_info && - c->security_state.generic_state) { + if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) { size_t max_payload = chunk_size; max_payload -= DCERPC_AUTH_TRAILER_LENGTH; @@ -2119,7 +2290,7 @@ struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx, /* construct the NDR form of the packet */ status = ncacn_push_auth(&blob, state, &pkt, - p->conn->security_state.auth_info); + p->conn->security_state.tmp_auth_info.out); if (tevent_req_nterror(req, status)) { return tevent_req_post(req, ev); } @@ -2192,6 +2363,7 @@ static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq, tevent_req_data(req, struct dcerpc_alter_context_state); struct dcecli_connection *conn = state->p->conn; + struct dcecli_security *sec = &conn->security_state; NTSTATUS status; /* @@ -2213,23 +2385,15 @@ static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq, */ tevent_req_defer_callback(req, state->ev); - if (pkt->ptype == DCERPC_PKT_ALTER_RESP && - pkt->u.alter_resp.num_results == 1 && - pkt->u.alter_resp.ctx_list[0].result != 0) { - status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]); - DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n", - pkt->u.alter_resp.ctx_list[0].reason.value, - nt_errstr(status))); - tevent_req_nterror(req, status); - return; - } - if (pkt->ptype == DCERPC_PKT_FAULT) { DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n", dcerpc_errstr(state, pkt->u.fault.status))); if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) { state->p->last_fault_code = pkt->u.fault.status; tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE); + } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) { + state->p->last_fault_code = pkt->u.fault.status; + tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE); } else { state->p->last_fault_code = pkt->u.fault.status; status = dcerpc_fault_to_nt_status(pkt->u.fault.status); @@ -2238,21 +2402,42 @@ static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq, return; } - if (pkt->ptype != DCERPC_PKT_ALTER_RESP || - pkt->u.alter_resp.num_results == 0 || - pkt->u.alter_resp.ctx_list[0].result != 0) { + status = dcerpc_verify_ncacn_packet_header(pkt, + DCERPC_PKT_ALTER_RESP, + pkt->u.alter_resp.auth_info.length, + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST, + DCERPC_PFC_FLAG_CONC_MPX | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN); + if (!NT_STATUS_IS_OK(status)) { + state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR; + tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT); + return; + } + + if (pkt->u.alter_resp.num_results != 1) { state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR; tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT); return; } + if (pkt->u.alter_resp.ctx_list[0].result != 0) { + status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]); + DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n", + pkt->u.alter_resp.ctx_list[0].reason.value, + nt_errstr(status))); + tevent_req_nterror(req, status); + return; + } + /* the alter_resp might contain a reply set of credentials */ - if (conn->security_state.auth_info && - pkt->u.alter_resp.auth_info.length) { + if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) { uint32_t auth_length; - status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info, - conn->security_state.auth_info, &auth_length, true); + status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem, + &pkt->u.alter_resp.auth_info, + sec->tmp_auth_info.in, + &auth_length, true); if (tevent_req_nterror(req, status)) { return; } diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h index a7d16947707..1b0eb7d9ba1 100644 --- a/source4/librpc/rpc/dcerpc.h +++ b/source4/librpc/rpc/dcerpc.h @@ -46,11 +46,21 @@ struct dcecli_connection; struct gensec_settings; struct cli_credentials; struct dcecli_security { - struct dcerpc_auth *auth_info; + enum dcerpc_AuthType auth_type; + enum dcerpc_AuthLevel auth_level; + uint32_t auth_context_id; + struct { + struct dcerpc_auth *out; + struct dcerpc_auth *in; + TALLOC_CTX *mem; + } tmp_auth_info; struct gensec_security *generic_state; /* get the session key */ NTSTATUS (*session_key)(struct dcecli_connection *, DATA_BLOB *); + + bool verified_bitmask1; + }; /* @@ -126,6 +136,8 @@ struct dcerpc_pipe { */ bool inhibit_timeout_processing; bool timed_out; + + bool verified_pcontext; }; /* default timeout for all rpc requests, in seconds */ diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c index 2d60d38732b..d617b07e07c 100644 --- a/source4/librpc/rpc/dcerpc_auth.c +++ b/source4/librpc/rpc/dcerpc_auth.c @@ -124,7 +124,8 @@ _PUBLIC_ NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p, struct bind_auth_state { struct dcerpc_pipe *pipe; - DATA_BLOB credentials; + struct dcerpc_auth out_auth_info; + struct dcerpc_auth in_auth_info; bool more_processing; /* Is there anything more to do after the * first bind itself received? */ }; @@ -141,6 +142,27 @@ static void bind_auth_next_step(struct composite_context *c) state = talloc_get_type(c->private_data, struct bind_auth_state); sec = &state->pipe->conn->security_state; + if (state->in_auth_info.auth_type != sec->auth_type) { + composite_error(c, NT_STATUS_RPC_PROTOCOL_ERROR); + return; + } + + if (state->in_auth_info.auth_level != sec->auth_level) { + composite_error(c, NT_STATUS_RPC_PROTOCOL_ERROR); + return; + } + + if (state->in_auth_info.auth_context_id != sec->auth_context_id) { + composite_error(c, NT_STATUS_RPC_PROTOCOL_ERROR); + return; + } + + state->out_auth_info = (struct dcerpc_auth) { + .auth_type = sec->auth_type, + .auth_level = sec->auth_level, + .auth_context_id = sec->auth_context_id, + }; + /* The status value here, from GENSEC is vital to the security * of the system. Even if the other end accepts, if GENSEC * claims 'MORE_PROCESSING_REQUIRED' then you must keep @@ -156,16 +178,14 @@ static void bind_auth_next_step(struct composite_context *c) c->status = gensec_update_ev(sec->generic_state, state, state->pipe->conn->event_ctx, - sec->auth_info->credentials, - &state->credentials); + state->in_auth_info.credentials, + &state->out_auth_info.credentials); if (state->pipe->timed_out) { composite_error(c, NT_STATUS_IO_TIMEOUT); return; } state->pipe->inhibit_timeout_processing = false; - data_blob_free(&sec->auth_info->credentials); - if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { more_processing = true; c->status = NT_STATUS_OK; @@ -173,18 +193,21 @@ static void bind_auth_next_step(struct composite_context *c) if (!composite_is_ok(c)) return; - if (state->credentials.length == 0) { + if (state->out_auth_info.credentials.length == 0) { composite_done(c); return; } - sec->auth_info->credentials = state->credentials; + state->in_auth_info = (struct dcerpc_auth) { + .auth_type = DCERPC_AUTH_TYPE_NONE, + }; + sec->tmp_auth_info.in = &state->in_auth_info; + sec->tmp_auth_info.mem = state; + sec->tmp_auth_info.out = &state->out_auth_info; if (!more_processing) { /* NO reply expected, so just send it */ c->status = dcerpc_auth3(state->pipe, state); - data_blob_free(&state->credentials); - sec->auth_info->credentials = data_blob(NULL, 0); if (!composite_is_ok(c)) return; composite_done(c); @@ -197,8 +220,6 @@ static void bind_auth_next_step(struct composite_context *c) state->pipe, &state->pipe->syntax, &state->pipe->transfer_syntax); - data_blob_free(&state->credentials); - sec->auth_info->credentials = data_blob(NULL, 0); if (composite_nomem(subreq, c)) return; tevent_req_set_callback(subreq, bind_auth_recv_alter, c); } @@ -209,6 +230,11 @@ static void bind_auth_recv_alter(struct tevent_req *subreq) struct composite_context *c = tevent_req_callback_data(subreq, struct composite_context); + struct bind_auth_state *state = talloc_get_type(c->private_data, + struct bind_auth_state); + struct dcecli_security *sec = &state->pipe->conn->security_state; + + ZERO_STRUCT(sec->tmp_auth_info); c->status = dcerpc_alter_context_recv(subreq); TALLOC_FREE(subreq); @@ -225,14 +251,15 @@ static void bind_auth_recv_bindreply(struct tevent_req *subreq) struct composite_context); struct bind_auth_state *state = talloc_get_type(c->private_data, struct bind_auth_state); + struct dcecli_security *sec = &state->pipe->conn->security_state; + + ZERO_STRUCT(sec->tmp_auth_info); c->status = dcerpc_bind_recv(subreq); TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; if (state->pipe->conn->flags & DCERPC_HEADER_SIGNING) { - struct dcecli_security *sec = &state->pipe->conn->security_state; - gensec_want_feature(sec->generic_state, GENSEC_FEATURE_SIGN_PKT_HEADER); } @@ -353,15 +380,20 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx, return c; } - sec->auth_info = talloc(p, struct dcerpc_auth); - if (composite_nomem(sec->auth_info, c)) return c; + sec->auth_type = auth_type; + sec->auth_level = auth_level, + /* + * We use auth_context_id = 1 as some older + * Samba versions (<= 4.2.3) use that value hardcoded + * in a response. + */ + sec->auth_context_id = 1; - sec->auth_info->auth_type = auth_type; - sec->auth_info->auth_level = auth_level, - sec->auth_info->auth_pad_length = 0; - sec->auth_info->auth_reserved = 0; - sec->auth_info->auth_context_id = random(); - sec->auth_info->credentials = data_blob(NULL, 0); + state->out_auth_info = (struct dcerpc_auth) { + .auth_type = sec->auth_type, + .auth_level = sec->auth_level, + .auth_context_id = sec->auth_context_id, + }; /* The status value here, from GENSEC is vital to the security * of the system. Even if the other end accepts, if GENSEC @@ -377,8 +409,8 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx, state->pipe->timed_out = false; c->status = gensec_update_ev(sec->generic_state, state, p->conn->event_ctx, - sec->auth_info->credentials, - &state->credentials); + data_blob_null, + &state->out_auth_info.credentials); if (state->pipe->timed_out) { composite_error(c, NT_STATUS_IO_TIMEOUT); return c; @@ -394,25 +426,28 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx, state->more_processing = NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED); - if (state->credentials.length == 0) { + if (state->out_auth_info.credentials.length == 0) { composite_done(c); return c; } - sec->auth_info->credentials = state->credentials; - if (gensec_have_feature(sec->generic_state, GENSEC_FEATURE_SIGN_PKT_HEADER)) { - if (auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) { + if (sec->auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) { state->pipe->conn->flags |= DCERPC_PROPOSE_HEADER_SIGNING; } } + state->in_auth_info = (struct dcerpc_auth) { + .auth_type = DCERPC_AUTH_TYPE_NONE, + }; + sec->tmp_auth_info.in = &state->in_auth_info; + sec->tmp_auth_info.mem = state; + sec->tmp_auth_info.out = &state->out_auth_info; + /* The first request always is a dcerpc_bind. The subsequent ones * depend on gensec results */ subreq = dcerpc_bind_send(state, p->conn->event_ctx, p, &syntax, &transfer_syntax); - data_blob_free(&state->credentials); - sec->auth_info->credentials = data_blob(NULL, 0); if (composite_nomem(subreq, c)) return c; tevent_req_set_callback(subreq, bind_auth_recv_bindreply, c); diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c index 9c5dbebcc1d..8ed12578e21 100644 --- a/source4/librpc/rpc/dcerpc_connect.c +++ b/source4/librpc/rpc/dcerpc_connect.c @@ -183,6 +183,11 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CT conn->in.fallback_to_anonymous = false; } + conn->in.options.min_protocol = PROTOCOL_NT1; + conn->in.options.max_protocol = PROTOCOL_NT1; + + conn->in.options.signing = lpcfg_client_ipc_signing(lp_ctx); + /* send smb connect request */ conn_req = smb_composite_connect_send(conn, s->io.conn, s->io.resolve_ctx, @@ -277,6 +282,17 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send( lpcfg_smbcli_options(lp_ctx, &options); + options.min_protocol = lpcfg_client_ipc_min_protocol(lp_ctx); + if (options.min_protocol < PROTOCOL_SMB2_02) { + options.min_protocol = PROTOCOL_SMB2_02; + } + options.max_protocol = lpcfg_client_ipc_max_protocol(lp_ctx); + if (options.max_protocol < PROTOCOL_SMB2_02) { + options.max_protocol = PROTOCOL_SMB2_02; + } + + options.signing = lpcfg_client_ipc_signing(lp_ctx); + /* send smb2 connect request */ subreq = smb2_connect_send(s, c->event_ctx, host, @@ -773,6 +789,7 @@ static void continue_connect(struct composite_context *c, struct pipe_connect_st struct composite_context *ncacn_unix_req; struct composite_context *ncalrpc_req; enum dcerpc_transport_t transport; + enum protocol_types min_ipc_protocol; uint32_t flags; /* dcerpc pipe connect input parameters */ @@ -786,6 +803,11 @@ static void continue_connect(struct composite_context *c, struct pipe_connect_st transport = dcerpc_binding_get_transport(s->binding); flags = dcerpc_binding_get_flags(s->binding); + min_ipc_protocol = lpcfg_client_ipc_min_protocol(s->lp_ctx); + if (min_ipc_protocol >= PROTOCOL_SMB2_02) { + flags |= DCERPC_SMB2; + } + /* connect dcerpc pipe depending on required transport */ switch (transport) { case NCACN_NP: diff --git a/source4/librpc/rpc/dcerpc_roh.c b/source4/librpc/rpc/dcerpc_roh.c index 09072940f90..6da29787fbe 100644 --- a/source4/librpc/rpc/dcerpc_roh.c +++ b/source4/librpc/rpc/dcerpc_roh.c @@ -31,6 +31,7 @@ #include "librpc/rpc/dcerpc.h" #include "librpc/rpc/dcerpc_roh.h" #include "librpc/rpc/dcerpc_proto.h" +#include "lib/param/param.h" static ssize_t tstream_roh_pending_bytes(struct tstream_context *stream); static struct tevent_req * tstream_roh_readv_send( @@ -184,7 +185,17 @@ struct tevent_req *dcerpc_pipe_open_roh_send(struct dcecli_connection *conn, /* Initialize TLS */ if (use_tls) { - status = tstream_tls_params_client(state->roh, NULL, NULL, + char *ca_file = lpcfg_tls_cafile(state, lp_ctx); + char *crl_file = lpcfg_tls_crlfile(state, lp_ctx); + const char *tls_priority = lpcfg_tls_priority(lp_ctx); + enum tls_verify_peer_state verify_peer = + lpcfg_tls_verify_peer(lp_ctx); + + status = tstream_tls_params_client(state->roh, + ca_file, crl_file, + tls_priority, + verify_peer, + state->rpc_proxy, &state->tls_params); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("%s: Failed tstream_tls_params_client - %s\n", diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index de960b246be..d7757503820 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -662,15 +662,15 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p, /* Perform an authenticated DCE-RPC bind */ - if (!(conn->flags & (DCERPC_SIGN|DCERPC_SEAL))) { + if (!(conn->flags & (DCERPC_CONNECT|DCERPC_SEAL))) { /* we are doing an authenticated connection, - but not using sign or seal. We must force - the CONNECT dcerpc auth type as a NONE auth - type doesn't allow authentication - information to be passed. + which needs to use [connect], [sign] or [seal]. + If nothing is specified, we default to [sign] now. + This give roughly the same protection as + ncacn_np with smb signing. */ - conn->flags |= DCERPC_CONNECT; + conn->flags |= DCERPC_SIGN; } if (conn->flags & DCERPC_AUTH_SPNEGO) { @@ -760,6 +760,16 @@ _PUBLIC_ NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx, NTSTATUS dcerpc_generic_session_key(struct dcecli_connection *c, DATA_BLOB *session_key) { + *session_key = data_blob_null; + + if (c != NULL) { + if (c->transport.transport != NCALRPC && + c->transport.transport != NCACN_UNIX_STREAM) + { + return NT_STATUS_LOCAL_USER_SESSION_KEY; + } + } + /* this took quite a few CPU cycles to find ... */ session_key->data = discard_const_p(unsigned char, "SystemLibraryDTC"); session_key->length = 16; diff --git a/source4/librpc/rpc/pyrpc.c b/source4/librpc/rpc/pyrpc.c index 09f663213b6..243e96b93ef 100644 --- a/source4/librpc/rpc/pyrpc.c +++ b/source4/librpc/rpc/pyrpc.c @@ -246,44 +246,8 @@ static PyObject *py_iface_request(PyObject *self, PyObject *args, PyObject *kwar return ret; } -static PyObject *py_iface_alter_context(PyObject *self, PyObject *args, PyObject *kwargs) -{ - dcerpc_InterfaceObject *iface = (dcerpc_InterfaceObject *)self; - NTSTATUS status; - const char *kwnames[] = { "abstract_syntax", "transfer_syntax", NULL }; - PyObject *py_abstract_syntax = Py_None, *py_transfer_syntax = Py_None; - struct ndr_syntax_id abstract_syntax, transfer_syntax; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:alter_context", - discard_const_p(char *, kwnames), &py_abstract_syntax, - &py_transfer_syntax)) { - return NULL; - } - - if (!ndr_syntax_from_py_object(py_abstract_syntax, &abstract_syntax)) - return NULL; - - if (py_transfer_syntax == Py_None) { - transfer_syntax = ndr_transfer_syntax_ndr; - } else { - if (!ndr_syntax_from_py_object(py_transfer_syntax, &transfer_syntax)) - return NULL; - } - - status = dcerpc_alter_context(iface->pipe, iface->pipe, &abstract_syntax, - &transfer_syntax); - - if (!NT_STATUS_IS_OK(status)) { - PyErr_SetDCERPCStatus(iface->pipe, status); - return NULL; - } - - Py_RETURN_NONE; -} - static PyMethodDef dcerpc_interface_methods[] = { { "request", (PyCFunction)py_iface_request, METH_VARARGS|METH_KEYWORDS, "S.request(opnum, data, object=None) -> data\nMake a raw request" }, - { "alter_context", (PyCFunction)py_iface_alter_context, METH_VARARGS|METH_KEYWORDS, "S.alter_context(syntax)\nChange to a different interface" }, { NULL, NULL, 0, NULL }, }; @@ -398,6 +362,45 @@ static PyTypeObject py_transfer_syntax_ndr64_SyntaxType = { .tp_new = py_transfer_syntax_ndr64_new, }; +static PyObject *py_bind_time_features_syntax_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + const char *kwnames[] = { + "features", NULL + }; + unsigned long long features = 0; + struct ndr_syntax_id syntax; + PyObject *args2 = Py_None; + PyObject *kwargs2 = Py_None; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "K:features", discard_const_p(char *, kwnames), &features)) { + return NULL; + } + + args2 = Py_BuildValue("()"); + if (args2 == NULL) { + return NULL; + } + + kwargs2 = Py_BuildValue("{}"); + if (kwargs2 == NULL) { + Py_DECREF(args2); + return NULL; + } + + syntax = dcerpc_construct_bind_time_features(features); + + return py_dcerpc_syntax_init_helper(type, args2, kwargs2, &syntax); +} + +static PyTypeObject py_bind_time_features_syntax_SyntaxType = { + PyObject_HEAD_INIT(NULL) 0, + .tp_name = "base.bind_time_features_syntax", + .tp_basicsize = sizeof(pytalloc_Object), + .tp_doc = "bind_time_features_syntax(features)\n", + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = py_bind_time_features_syntax_new, +}; + void initbase(void) { PyObject *m; @@ -413,6 +416,7 @@ void initbase(void) py_transfer_syntax_ndr_SyntaxType.tp_base = ndr_syntax_id_Type; py_transfer_syntax_ndr64_SyntaxType.tp_base = ndr_syntax_id_Type; + py_bind_time_features_syntax_SyntaxType.tp_base = ndr_syntax_id_Type; if (PyType_Ready(&dcerpc_InterfaceType) < 0) return; @@ -421,6 +425,8 @@ void initbase(void) return; if (PyType_Ready(&py_transfer_syntax_ndr64_SyntaxType) < 0) return; + if (PyType_Ready(&py_bind_time_features_syntax_SyntaxType) < 0) + return; m = Py_InitModule3("base", NULL, "DCE/RPC protocol implementation"); if (m == NULL) @@ -433,4 +439,6 @@ void initbase(void) PyModule_AddObject(m, "transfer_syntax_ndr", (PyObject *)(void *)&py_transfer_syntax_ndr_SyntaxType); Py_INCREF((PyObject *)(void *)&py_transfer_syntax_ndr64_SyntaxType); PyModule_AddObject(m, "transfer_syntax_ndr64", (PyObject *)(void *)&py_transfer_syntax_ndr64_SyntaxType); + Py_INCREF((PyObject *)(void *)&py_bind_time_features_syntax_SyntaxType); + PyModule_AddObject(m, "bind_time_features_syntax", (PyObject *)(void *)&py_bind_time_features_syntax_SyntaxType); } diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c index af3313f6dd8..f53b2dd1807 100644 --- a/source4/param/loadparm.c +++ b/source4/param/loadparm.c @@ -36,10 +36,11 @@ void lpcfg_smbcli_options(struct loadparm_context *lp_ctx, { options->max_xmit = lpcfg_max_xmit(lp_ctx); options->max_mux = lpcfg_max_mux(lp_ctx); - options->use_spnego = lpcfg_nt_status_support(lp_ctx) && lpcfg_use_spnego(lp_ctx); + options->use_spnego = lpcfg_nt_status_support(lp_ctx) && lpcfg_client_use_spnego(lp_ctx); options->signing = lpcfg_client_signing(lp_ctx); options->request_timeout = SMB_REQUEST_TIMEOUT; options->ntstatus_support = lpcfg_nt_status_support(lp_ctx); + options->min_protocol = lpcfg_client_min_protocol(lp_ctx); options->max_protocol = lpcfg__client_max_protocol(lp_ctx); options->unicode = lpcfg_unicode(lp_ctx); options->use_oplocks = true; diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c index 9dea3d6357e..4037d18edf0 100644 --- a/source4/rpc_server/backupkey/dcesrv_backupkey.c +++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c @@ -54,6 +54,14 @@ static const AlgorithmIdentifier _hx509_signature_rsa_with_var_num = { { 7, discard_const_p(unsigned, rsa_with_var_num) }, NULL }; +#define DCESRV_INTERFACE_BACKUPKEY_BIND(call, iface) \ + dcesrv_interface_backupkey_bind(call, iface) +static NTSTATUS dcesrv_interface_backupkey_bind(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + return dcesrv_interface_bind_require_privacy(dce_call, iface); +} + static NTSTATUS set_lsa_secret(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const char *name, @@ -1791,11 +1799,6 @@ static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call, return WERR_NOT_SUPPORTED; } - if (!dce_call->conn->auth_state.auth_info || - dce_call->conn->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) { - DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); - } - ldb_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx), 0); diff --git a/source4/rpc_server/common/reply.c b/source4/rpc_server/common/reply.c index 007b68083bf..8f0e3043ad0 100644 --- a/source4/rpc_server/common/reply.c +++ b/source4/rpc_server/common/reply.c @@ -97,28 +97,41 @@ void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian) /* return a dcerpc fault */ -NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code) +NTSTATUS dcesrv_fault_with_flags(struct dcesrv_call_state *call, + uint32_t fault_code, + uint8_t extra_flags) { struct ncacn_packet pkt; struct data_blob_list_item *rep; - uint8_t zeros[4]; + static const uint8_t zeros[4] = { 0, }; NTSTATUS status; - /* setup a bind_ack */ + /* setup a fault */ dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx)); pkt.auth_length = 0; pkt.call_id = call->pkt.call_id; pkt.ptype = DCERPC_PKT_FAULT; - pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; - pkt.u.fault.alloc_hint = 0; - pkt.u.fault.context_id = 0; + pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags; + pkt.u.fault.alloc_hint = 24; + switch (call->pkt.ptype) { + case DCERPC_PKT_REQUEST: + pkt.u.fault.context_id = call->pkt.u.request.context_id; + break; + default: + pkt.u.fault.context_id = 0; + break; + } + if (fault_code == DCERPC_NCA_S_PROTO_ERROR) { + /* + * context_id = 0 is forced on protocol errors. + */ + pkt.u.fault.context_id = 0; + } pkt.u.fault.cancel_count = 0; pkt.u.fault.status = fault_code; - - ZERO_STRUCT(zeros); pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros)); - rep = talloc(call, struct data_blob_list_item); + rep = talloc_zero(call, struct data_blob_list_item); if (!rep) { return NT_STATUS_NO_MEMORY; } @@ -142,7 +155,10 @@ NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code) return NT_STATUS_OK; } - +NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code) +{ + return dcesrv_fault_with_flags(call, fault_code, 0); +} _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call) { @@ -183,9 +199,9 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call) /* we can write a full max_recv_frag size, minus the dcerpc request header size */ - chunk_size = call->conn->cli_max_recv_frag; + chunk_size = call->conn->max_xmit_frag; chunk_size -= DCERPC_REQUEST_LENGTH; - if (call->conn->auth_state.auth_info && + if (call->conn->auth_state.auth_finished && call->conn->auth_state.gensec_security) { size_t max_payload = chunk_size; @@ -206,7 +222,7 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call) struct data_blob_list_item *rep; struct ncacn_packet pkt; - rep = talloc(call, struct data_blob_list_item); + rep = talloc_zero(call, struct data_blob_list_item); NT_STATUS_HAVE_NO_MEMORY(rep); length = MIN(chunk_size, stub.length); @@ -259,5 +275,12 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call) NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *c, DATA_BLOB *session_key) { + enum dcerpc_transport_t transport = + dcerpc_binding_get_transport(c->endpoint->ep_description); + + if (transport != NCALRPC && transport != NCACN_UNIX_STREAM) { + return NT_STATUS_NO_USER_SESSION_KEY; + } + return dcerpc_generic_session_key(NULL, session_key); } diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index b1c763b76f7..278e1af3eaa 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -42,9 +42,6 @@ #include "lib/util/samba_modules.h" #include "librpc/gen_ndr/ndr_dcerpc.h" -/* this is only used when the client asks for an unknown interface */ -#define DUMMY_ASSOC_GROUP 0x0FFFFFFF - extern const struct dcesrv_interface dcesrv_mgmt_interface; @@ -74,7 +71,7 @@ static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_c assoc_group = dcesrv_assoc_group_find(dce_ctx, id); if (assoc_group == NULL) { - DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id)); + DEBUG(2,(__location__ ": Failed to find assoc_group 0x%08x\n", id)); return NULL; } return talloc_reference(mem_ctx, assoc_group); @@ -269,7 +266,7 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx, /* check if this endpoint exists */ if ((ep=find_endpoint(dce_ctx, binding))==NULL) { - ep = talloc(dce_ctx, struct dcesrv_endpoint); + ep = talloc_zero(dce_ctx, struct dcesrv_endpoint); if (!ep) { return NT_STATUS_NO_MEMORY; } @@ -278,7 +275,7 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx, add_ep = true; /* add mgmt interface */ - ifl = talloc(ep, struct dcesrv_if_list); + ifl = talloc_zero(ep, struct dcesrv_if_list); if (!ifl) { return NT_STATUS_NO_MEMORY; } @@ -297,7 +294,7 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx, } /* talloc a new interface list element */ - ifl = talloc(ep, struct dcesrv_if_list); + ifl = talloc_zero(ep, struct dcesrv_if_list); if (!ifl) { return NT_STATUS_NO_MEMORY; } @@ -408,6 +405,9 @@ _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx, p->msg_ctx = msg_ctx; p->server_id = server_id; p->state_flags = state_flags; + p->allow_bind = true; + p->max_recv_frag = 5840; + p->max_xmit_frag = 5840; *_p = p; return NT_STATUS_OK; @@ -450,6 +450,23 @@ static void dcesrv_call_set_list(struct dcesrv_call_state *call, } } +static void dcesrv_call_disconnect_after(struct dcesrv_call_state *call, + const char *reason) +{ + if (call->conn->terminate != NULL) { + return; + } + + call->conn->allow_bind = false; + call->conn->allow_alter = false; + call->conn->allow_auth3 = false; + call->conn->allow_request = false; + + call->terminate_reason = talloc_strdup(call, reason); + if (call->terminate_reason == NULL) { + call->terminate_reason = __location__; + } +} /* return a dcerpc bind_nak @@ -460,6 +477,13 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason) struct dcerpc_bind_nak_version version; struct data_blob_list_item *rep; NTSTATUS status; + static const uint8_t _pad[3] = { 0, }; + + /* + * We add the call to the pending_call_list + * in order to defer the termination. + */ + dcesrv_call_disconnect_after(call, "dcesrv_bind_nak"); /* setup a bind_nak */ dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx)); @@ -472,9 +496,9 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason) version.rpc_vers_minor = 0; pkt.u.bind_nak.num_versions = 1; pkt.u.bind_nak.versions = &version; - pkt.u.bind_nak._pad = data_blob_null; + pkt.u.bind_nak._pad = data_blob_const(_pad, sizeof(_pad)); - rep = talloc(call, struct data_blob_list_item); + rep = talloc_zero(call, struct data_blob_list_item); if (!rep) { return NT_STATUS_NO_MEMORY; } @@ -498,6 +522,19 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason) return NT_STATUS_OK; } +static NTSTATUS dcesrv_fault_disconnect(struct dcesrv_call_state *call, + uint32_t fault_code) +{ + /* + * We add the call to the pending_call_list + * in order to defer the termination. + */ + dcesrv_call_disconnect_after(call, "dcesrv_fault_disconnect"); + + return dcesrv_fault_with_flags(call, fault_code, + DCERPC_PFC_FLAG_DID_NOT_EXECUTE); +} + static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c) { DLIST_REMOVE(c->conn->contexts, c); @@ -510,6 +547,115 @@ static int dcesrv_connection_context_destructor(struct dcesrv_connection_context return 0; } +static void dcesrv_prepare_context_auth(struct dcesrv_call_state *dce_call) +{ + struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint; + enum dcerpc_transport_t transport = + dcerpc_binding_get_transport(endpoint->ep_description); + struct dcesrv_connection_context *context = dce_call->context; + const struct dcesrv_interface *iface = context->iface; + + context->min_auth_level = DCERPC_AUTH_LEVEL_NONE; + + if (transport == NCALRPC) { + context->allow_connect = true; + return; + } + + /* + * allow overwrite per interface + * allow dcerpc auth level connect:<interface> + */ + context->allow_connect = lpcfg_allow_dcerpc_auth_level_connect(lp_ctx); + context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL, + "allow dcerpc auth level connect", + iface->name, + context->allow_connect); +} + +NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + if (dce_call->context == NULL) { + return NT_STATUS_INTERNAL_ERROR; + } + + dce_call->context->min_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; + return NT_STATUS_OK; +} + +NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + if (dce_call->context == NULL) { + return NT_STATUS_INTERNAL_ERROR; + } + + dce_call->context->min_auth_level = DCERPC_AUTH_LEVEL_PRIVACY; + return NT_STATUS_OK; +} + +_PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint; + enum dcerpc_transport_t transport = + dcerpc_binding_get_transport(endpoint->ep_description); + struct dcesrv_connection_context *context = dce_call->context; + + if (context == NULL) { + return NT_STATUS_INTERNAL_ERROR; + } + + if (transport == NCALRPC) { + context->allow_connect = true; + return NT_STATUS_OK; + } + + /* + * allow overwrite per interface + * allow dcerpc auth level connect:<interface> + */ + context->allow_connect = false; + context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL, + "allow dcerpc auth level connect", + iface->name, + context->allow_connect); + return NT_STATUS_OK; +} + +_PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint; + enum dcerpc_transport_t transport = + dcerpc_binding_get_transport(endpoint->ep_description); + struct dcesrv_connection_context *context = dce_call->context; + + if (context == NULL) { + return NT_STATUS_INTERNAL_ERROR; + } + + if (transport == NCALRPC) { + context->allow_connect = true; + return NT_STATUS_OK; + } + + /* + * allow overwrite per interface + * allow dcerpc auth level connect:<interface> + */ + context->allow_connect = true; + context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL, + "allow dcerpc auth level connect", + iface->name, + context->allow_connect); + return NT_STATUS_OK; +} + /* handle a bind request */ @@ -524,14 +670,57 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) uint32_t context_id; const struct dcesrv_interface *iface; uint32_t extra_flags = 0; + uint16_t max_req = 0; + uint16_t max_rep = 0; + const char *ep_prefix = ""; + const char *endpoint = NULL; + + status = dcerpc_verify_ncacn_packet_header(&call->pkt, + DCERPC_PKT_BIND, + call->pkt.u.bind.auth_info.length, + 0, /* required flags */ + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN | + 0x08 | /* this is not defined, but should be ignored */ + DCERPC_PFC_FLAG_CONC_MPX | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE | + DCERPC_PFC_FLAG_MAYBE | + DCERPC_PFC_FLAG_OBJECT_UUID); + if (!NT_STATUS_IS_OK(status)) { + return dcesrv_bind_nak(call, + DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED); + } + + /* max_recv_frag and max_xmit_frag result always in the same value! */ + max_req = MIN(call->pkt.u.bind.max_xmit_frag, + call->pkt.u.bind.max_recv_frag); + /* + * The values are between 2048 and 5840 tested against Windows 2012R2 + * via ncacn_ip_tcp on port 135. + */ + max_req = MAX(2048, max_req); + max_rep = MIN(max_req, call->conn->max_recv_frag); + /* They are truncated to an 8 byte boundary. */ + max_rep &= 0xFFF8; + + /* max_recv_frag and max_xmit_frag result always in the same value! */ + call->conn->max_recv_frag = max_rep; + call->conn->max_xmit_frag = max_rep; /* if provided, check the assoc_group is valid */ - if (call->pkt.u.bind.assoc_group_id != 0 && - lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) && - dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) { - return dcesrv_bind_nak(call, 0); + if (call->pkt.u.bind.assoc_group_id != 0) { + call->conn->assoc_group = dcesrv_assoc_group_reference(call->conn, + call->conn->dce_ctx, + call->pkt.u.bind.assoc_group_id); + } else { + call->conn->assoc_group = dcesrv_assoc_group_new(call->conn, + call->conn->dce_ctx); + } + if (call->conn->assoc_group == NULL) { + return dcesrv_bind_nak(call, 0); } if (call->pkt.u.bind.num_contexts < 1 || @@ -540,12 +729,6 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) } context_id = call->pkt.u.bind.ctx_list[0].context_id; - - /* you can't bind twice on one context */ - if (dcesrv_find_context(call->conn, context_id) != NULL) { - return dcesrv_bind_nak(call, 0); - } - if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version; uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid; @@ -573,7 +756,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) if (iface) { /* add this context to the list of available context_ids */ - struct dcesrv_connection_context *context = talloc(call->conn, + struct dcesrv_connection_context *context = talloc_zero(call->conn, struct dcesrv_connection_context); if (context == NULL) { return dcesrv_bind_nak(call, 0); @@ -581,22 +764,15 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) context->conn = call->conn; context->iface = iface; context->context_id = context_id; - if (call->pkt.u.bind.assoc_group_id != 0) { - context->assoc_group = dcesrv_assoc_group_reference(context, - call->conn->dce_ctx, - call->pkt.u.bind.assoc_group_id); - } else { - context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx); - } - if (context->assoc_group == NULL) { - talloc_free(context); - return dcesrv_bind_nak(call, 0); - } + /* legacy for openchange dcesrv_mapiproxy.c */ + context->assoc_group = call->conn->assoc_group; context->private_data = NULL; DLIST_ADD(call->conn->contexts, context); call->context = context; talloc_set_destructor(context, dcesrv_connection_context_destructor); + dcesrv_prepare_context_auth(call); + status = iface->bind(call, iface, if_version); if (!NT_STATUS_IS_OK(status)) { char *uuid_str = GUID_string(call, &uuid); @@ -611,10 +787,6 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) } } - if (call->conn->cli_max_recv_frag == 0) { - call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag); - } - if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) && (call->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) { call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED; @@ -627,9 +799,20 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) /* handle any authentication that is being requested */ if (!dcesrv_auth_bind(call)) { - talloc_free(call->context); - call->context = NULL; - return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE); + struct dcesrv_auth *auth = &call->conn->auth_state; + + TALLOC_FREE(call->context); + + if (auth->auth_level != DCERPC_AUTH_LEVEL_NONE) { + /* + * We only give INVALID_AUTH_TYPE if the auth_level was + * valid. + */ + return dcesrv_bind_nak(call, + DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE); + } + return dcesrv_bind_nak(call, + DCERPC_BIND_NAK_REASON_NOT_SPECIFIED); } /* setup a bind_ack */ @@ -638,29 +821,39 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) pkt.call_id = call->pkt.call_id; pkt.ptype = DCERPC_PKT_BIND_ACK; pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags; - pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag; - pkt.u.bind_ack.max_recv_frag = 0x2000; + pkt.u.bind_ack.max_xmit_frag = call->conn->max_xmit_frag; + pkt.u.bind_ack.max_recv_frag = call->conn->max_recv_frag; + pkt.u.bind_ack.assoc_group_id = call->conn->assoc_group->id; - /* - make it possible for iface->bind() to specify the assoc_group_id - This helps the openchange mapiproxy plugin to work correctly. - - metze - */ - if (call->context) { - pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id; - } else { - pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP; + if (iface) { + endpoint = dcerpc_binding_get_string_option( + call->conn->endpoint->ep_description, + "endpoint"); } - if (iface) { - /* FIXME: Use pipe name as specified by endpoint instead of interface name */ - pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name); - } else { - pkt.u.bind_ack.secondary_address = ""; + if (endpoint == NULL) { + endpoint = ""; + } + + if (strncasecmp(endpoint, "\\pipe\\", 6) == 0) { + /* + * TODO: check if this is really needed + * + * Or if we should fix this in our idl files. + */ + ep_prefix = "\\PIPE\\"; + endpoint += 6; + } + + pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "%s%s", + ep_prefix, + endpoint); + if (pkt.u.bind_ack.secondary_address == NULL) { + TALLOC_FREE(call->context); + return NT_STATUS_NO_MEMORY; } pkt.u.bind_ack.num_results = 1; - pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx); + pkt.u.bind_ack.ctx_list = talloc_zero(call, struct dcerpc_ack_ctx); if (!pkt.u.bind_ack.ctx_list) { talloc_free(call->context); call->context = NULL; @@ -678,7 +871,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) return dcesrv_bind_nak(call, 0); } - rep = talloc(call, struct data_blob_list_item); + rep = talloc_zero(call, struct data_blob_list_item); if (!rep) { talloc_free(call->context); call->context = NULL; @@ -686,7 +879,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) } status = ncacn_push_auth(&rep->blob, call, &pkt, - call->conn->auth_state.auth_info); + call->out_auth_info); if (!NT_STATUS_IS_OK(status)) { talloc_free(call->context); call->context = NULL; @@ -713,9 +906,35 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) */ static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call) { + NTSTATUS status; + + if (!call->conn->allow_auth3) { + return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); + } + + if (call->conn->auth_state.auth_finished) { + return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); + } + + status = dcerpc_verify_ncacn_packet_header(&call->pkt, + DCERPC_PKT_AUTH3, + call->pkt.u.auth3.auth_info.length, + 0, /* required flags */ + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN | + 0x08 | /* this is not defined, but should be ignored */ + DCERPC_PFC_FLAG_CONC_MPX | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE | + DCERPC_PFC_FLAG_MAYBE | + DCERPC_PFC_FLAG_OBJECT_UUID); + if (!NT_STATUS_IS_OK(status)) { + return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); + } + /* handle the auth3 in the auth code */ if (!dcesrv_auth_auth3(call)) { - return dcesrv_fault(call, DCERPC_FAULT_OTHER); + call->conn->auth_state.auth_invalid = true; } talloc_free(call); @@ -757,30 +976,22 @@ static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_ } /* add this context to the list of available context_ids */ - context = talloc(call->conn, struct dcesrv_connection_context); + context = talloc_zero(call->conn, struct dcesrv_connection_context); if (context == NULL) { return NT_STATUS_NO_MEMORY; } context->conn = call->conn; context->iface = iface; context->context_id = context_id; - if (call->pkt.u.alter.assoc_group_id != 0) { - context->assoc_group = dcesrv_assoc_group_reference(context, - call->conn->dce_ctx, - call->pkt.u.alter.assoc_group_id); - } else { - context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx); - } - if (context->assoc_group == NULL) { - talloc_free(context); - call->context = NULL; - return NT_STATUS_NO_MEMORY; - } + /* legacy for openchange dcesrv_mapiproxy.c */ + context->assoc_group = call->conn->assoc_group; context->private_data = NULL; DLIST_ADD(call->conn->contexts, context); call->context = context; talloc_set_destructor(context, dcesrv_connection_context_destructor); + dcesrv_prepare_context_auth(call); + status = iface->bind(call, iface, if_version); if (!NT_STATUS_IS_OK(status)) { /* we don't want to trigger the iface->unbind() hook */ @@ -819,15 +1030,11 @@ static NTSTATUS dcesrv_alter_resp(struct dcesrv_call_state *call, } } pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags; - pkt.u.alter_resp.max_xmit_frag = 0x2000; - pkt.u.alter_resp.max_recv_frag = 0x2000; - if (result == 0) { - pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id; - } else { - pkt.u.alter_resp.assoc_group_id = 0; - } + pkt.u.alter_resp.max_xmit_frag = call->conn->max_xmit_frag; + pkt.u.alter_resp.max_recv_frag = call->conn->max_recv_frag; + pkt.u.alter_resp.assoc_group_id = call->conn->assoc_group->id; pkt.u.alter_resp.num_results = 1; - pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1); + pkt.u.alter_resp.ctx_list = talloc_zero(call, struct dcerpc_ack_ctx); if (!pkt.u.alter_resp.ctx_list) { return NT_STATUS_NO_MEMORY; } @@ -839,21 +1046,15 @@ static NTSTATUS dcesrv_alter_resp(struct dcesrv_call_state *call, status = dcesrv_auth_alter_ack(call, &pkt); if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) - || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE) - || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER) - || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED); - } - return dcesrv_fault(call, 0); + return dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR); } - rep = talloc(call, struct data_blob_list_item); + rep = talloc_zero(call, struct data_blob_list_item); if (!rep) { return NT_STATUS_NO_MEMORY; } - status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info); + status = ncacn_push_auth(&rep->blob, call, &pkt, call->out_auth_info); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -878,38 +1079,86 @@ static NTSTATUS dcesrv_alter_resp(struct dcesrv_call_state *call, static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call) { NTSTATUS status; - uint32_t context_id; + const struct dcerpc_ctx_list *ctx = NULL; + bool auth_ok = false; + + if (!call->conn->allow_alter) { + return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); + } + + status = dcerpc_verify_ncacn_packet_header(&call->pkt, + DCERPC_PKT_ALTER, + call->pkt.u.alter.auth_info.length, + 0, /* required flags */ + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST | + DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN | + 0x08 | /* this is not defined, but should be ignored */ + DCERPC_PFC_FLAG_CONC_MPX | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE | + DCERPC_PFC_FLAG_MAYBE | + DCERPC_PFC_FLAG_OBJECT_UUID); + if (!NT_STATUS_IS_OK(status)) { + return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); + } - /* handle any authentication that is being requested */ - if (!dcesrv_auth_alter(call)) { - /* TODO: work out the right reject code */ - return dcesrv_alter_resp(call, - DCERPC_BIND_PROVIDER_REJECT, - DCERPC_BIND_REASON_ASYNTAX); + auth_ok = dcesrv_auth_alter(call); + if (!auth_ok) { + if (call->in_auth_info.auth_type == DCERPC_AUTH_TYPE_NONE) { + return dcesrv_fault_disconnect(call, + DCERPC_FAULT_ACCESS_DENIED); + } } - context_id = call->pkt.u.alter.ctx_list[0].context_id; + if (call->pkt.u.alter.num_contexts < 1) { + return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); + } + ctx = &call->pkt.u.alter.ctx_list[0]; + if (ctx->num_transfer_syntaxes < 1) { + return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); + } /* see if they are asking for a new interface */ - call->context = dcesrv_find_context(call->conn, context_id); + call->context = dcesrv_find_context(call->conn, ctx->context_id); if (!call->context) { - status = dcesrv_alter_new_context(call, context_id); + status = dcesrv_alter_new_context(call, ctx->context_id); if (!NT_STATUS_IS_OK(status)) { return dcesrv_alter_resp(call, DCERPC_BIND_PROVIDER_REJECT, DCERPC_BIND_REASON_ASYNTAX); } + } else { + bool ok; + + ok = ndr_syntax_id_equal(&ctx->abstract_syntax, + &call->context->iface->syntax_id); + if (!ok) { + return dcesrv_fault_disconnect(call, + DCERPC_NCA_S_PROTO_ERROR); + } + + if (ctx->num_transfer_syntaxes != 1) { + return dcesrv_fault_disconnect(call, + DCERPC_NCA_S_PROTO_ERROR); + } + + ok = ndr_syntax_id_equal(&ctx->transfer_syntaxes[0], + &ndr_transfer_syntax_ndr); + if (!ok) { + return dcesrv_fault_disconnect(call, + DCERPC_NCA_S_PROTO_ERROR); + } } - if (call->pkt.u.alter.assoc_group_id != 0 && - lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) && - call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) { - DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n", - call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id)); - /* TODO: can they ask for a new association group? */ - return dcesrv_alter_resp(call, - DCERPC_BIND_PROVIDER_REJECT, - DCERPC_BIND_REASON_ASYNTAX); + /* handle any authentication that is being requested */ + if (!auth_ok) { + if (call->in_auth_info.auth_type != + call->conn->auth_state.auth_type) + { + return dcesrv_fault_disconnect(call, + DCERPC_FAULT_SEC_PKG_ERROR); + } + return dcesrv_fault_disconnect(call, DCERPC_FAULT_ACCESS_DENIED); } return dcesrv_alter_resp(call, @@ -982,10 +1231,17 @@ done: */ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) { + const struct dcesrv_endpoint *endpoint = call->conn->endpoint; + enum dcerpc_transport_t transport = + dcerpc_binding_get_transport(endpoint->ep_description); struct ndr_pull *pull; NTSTATUS status; struct dcesrv_connection_context *context; + if (!call->conn->allow_request) { + return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); + } + /* if authenticated, and the mech we use can't do async replies, don't use them... */ if (call->conn->auth_state.gensec_security && !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) { @@ -997,6 +1253,49 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) return dcesrv_fault(call, DCERPC_FAULT_UNK_IF); } + switch (call->conn->auth_state.auth_level) { + case DCERPC_AUTH_LEVEL_NONE: + case DCERPC_AUTH_LEVEL_INTEGRITY: + case DCERPC_AUTH_LEVEL_PRIVACY: + break; + default: + if (!context->allow_connect) { + char *addr; + + addr = tsocket_address_string(call->conn->remote_address, + call); + + DEBUG(2, ("%s: restrict auth_level_connect access " + "to [%s] with auth[type=0x%x,level=0x%x] " + "on [%s] from [%s]\n", + __func__, context->iface->name, + call->conn->auth_state.auth_type, + call->conn->auth_state.auth_level, + derpc_transport_string_by_transport(transport), + addr)); + return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED); + } + break; + } + + if (call->conn->auth_state.auth_level < context->min_auth_level) { + char *addr; + + addr = tsocket_address_string(call->conn->remote_address, call); + + DEBUG(2, ("%s: restrict access by min_auth_level[0x%x] " + "to [%s] with auth[type=0x%x,level=0x%x] " + "on [%s] from [%s]\n", + __func__, + context->min_auth_level, + context->iface->name, + call->conn->auth_state.auth_type, + call->conn->auth_state.auth_level, + derpc_transport_string_by_transport(transport), + addr)); + return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED); + } + pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call); NT_STATUS_HAVE_NO_MEMORY(pull); @@ -1083,12 +1382,13 @@ _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(stru /* process some input to a dcerpc endpoint server. */ -NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, - struct ncacn_packet *pkt, - DATA_BLOB blob) +static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + struct ncacn_packet *pkt, + DATA_BLOB blob) { NTSTATUS status; struct dcesrv_call_state *call; + struct dcesrv_call_state *existing = NULL; call = talloc_zero(dce_conn, struct dcesrv_call_state); if (!call) { @@ -1109,77 +1409,187 @@ NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, talloc_set_destructor(call, dcesrv_call_dequeue); - /* we have to check the signing here, before combining the - pdus */ - if (call->pkt.ptype == DCERPC_PKT_REQUEST && - !dcesrv_auth_request(call, &blob)) { - return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED); + if (call->conn->allow_bind) { + /* + * Only one bind is possible per connection + */ + call->conn->allow_bind = false; + return dcesrv_bind(call); } - /* see if this is a continued packet */ - if (call->pkt.ptype == DCERPC_PKT_REQUEST && - !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) { - struct dcesrv_call_state *call2 = call; - uint32_t alloc_size; - - /* we only allow fragmented requests, no other packet types */ - if (call->pkt.ptype != DCERPC_PKT_REQUEST) { - return dcesrv_fault(call2, DCERPC_FAULT_OTHER); + /* we have to check the signing here, before combining the + pdus */ + if (call->pkt.ptype == DCERPC_PKT_REQUEST) { + if (!call->conn->allow_request) { + return dcesrv_fault_disconnect(call, + DCERPC_NCA_S_PROTO_ERROR); } - /* this is a continuation of an existing call - find the call - then tack it on the end */ - call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id); - if (!call) { - return dcesrv_fault(call2, DCERPC_FAULT_OTHER); + status = dcerpc_verify_ncacn_packet_header(&call->pkt, + DCERPC_PKT_REQUEST, + call->pkt.u.request.stub_and_verifier.length, + 0, /* required_flags */ + DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST | + DCERPC_PFC_FLAG_PENDING_CANCEL | + 0x08 | /* this is not defined, but should be ignored */ + DCERPC_PFC_FLAG_CONC_MPX | + DCERPC_PFC_FLAG_DID_NOT_EXECUTE | + DCERPC_PFC_FLAG_MAYBE | + DCERPC_PFC_FLAG_OBJECT_UUID); + if (!NT_STATUS_IS_OK(status)) { + return dcesrv_fault_disconnect(call, + DCERPC_NCA_S_PROTO_ERROR); } - if (call->pkt.ptype != call2->pkt.ptype) { - /* trying to play silly buggers are we? */ - return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR); + if (call->pkt.frag_length > DCERPC_FRAG_MAX_SIZE) { + /* + * We don't use dcesrv_fault_disconnect() + * here, because we don't want to set + * DCERPC_PFC_FLAG_DID_NOT_EXECUTE + * + * Note that we don't check against the negotiated + * max_recv_frag, but a hard coded value. + */ + dcesrv_call_disconnect_after(call, + "dcesrv_auth_request - frag_length too large"); + return dcesrv_fault(call, + DCERPC_NCA_S_PROTO_ERROR); } - if (memcmp(call->pkt.drep, call2->pkt.drep, sizeof(pkt->drep)) != 0) { - return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR); + + if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) { + /* only one request is possible in the fragmented list */ + if (dce_conn->incoming_fragmented_call_list != NULL) { + TALLOC_FREE(call); + call = dce_conn->incoming_fragmented_call_list; + dcesrv_call_disconnect_after(call, + "dcesrv_auth_request - " + "existing fragmented call"); + return dcesrv_fault(call, + DCERPC_NCA_S_PROTO_ERROR); + } + if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_PENDING_CANCEL) { + return dcesrv_fault_disconnect(call, + DCERPC_FAULT_NO_CALL_ACTIVE); + } + } else { + const struct dcerpc_request *nr = &call->pkt.u.request; + const struct dcerpc_request *er = NULL; + int cmp; + + existing = dcesrv_find_fragmented_call(dce_conn, + call->pkt.call_id); + if (existing == NULL) { + dcesrv_call_disconnect_after(call, + "dcesrv_auth_request - " + "no existing fragmented call"); + return dcesrv_fault(call, + DCERPC_NCA_S_PROTO_ERROR); + } + er = &existing->pkt.u.request; + + if (call->pkt.ptype != existing->pkt.ptype) { + /* trying to play silly buggers are we? */ + return dcesrv_fault_disconnect(existing, + DCERPC_NCA_S_PROTO_ERROR); + } + cmp = memcmp(call->pkt.drep, existing->pkt.drep, + sizeof(pkt->drep)); + if (cmp != 0) { + return dcesrv_fault_disconnect(existing, + DCERPC_NCA_S_PROTO_ERROR); + } + if (nr->context_id != er->context_id) { + return dcesrv_fault_disconnect(existing, + DCERPC_NCA_S_PROTO_ERROR); + } + if (nr->opnum != er->opnum) { + return dcesrv_fault_disconnect(existing, + DCERPC_NCA_S_PROTO_ERROR); + } } - if (call->pkt.call_id != call2->pkt.call_id) { - return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR); + + if (!dcesrv_auth_request(call, &blob)) { + /* + * We don't use dcesrv_fault_disconnect() + * here, because we don't want to set + * DCERPC_PFC_FLAG_DID_NOT_EXECUTE + */ + dcesrv_call_disconnect_after(call, + "dcesrv_auth_request - failed"); + return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED); } - if (call->pkt.u.request.context_id != call2->pkt.u.request.context_id) { - return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR); + } + + /* see if this is a continued packet */ + if (existing != NULL) { + struct dcerpc_request *er = &existing->pkt.u.request; + const struct dcerpc_request *nr = &call->pkt.u.request; + size_t available; + size_t alloc_size; + size_t alloc_hint; + + /* + * Up to 4 MByte are allowed by all fragments + */ + available = DCERPC_NCACN_PAYLOAD_MAX_SIZE; + if (er->stub_and_verifier.length > available) { + dcesrv_call_disconnect_after(existing, + "dcesrv_auth_request - existing payload too large"); + return dcesrv_fault(existing, DCERPC_FAULT_ACCESS_DENIED); } - if (call->pkt.u.request.opnum != call2->pkt.u.request.opnum) { - return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR); + available -= er->stub_and_verifier.length; + if (nr->alloc_hint > available) { + dcesrv_call_disconnect_after(existing, + "dcesrv_auth_request - alloc hint too large"); + return dcesrv_fault(existing, DCERPC_FAULT_ACCESS_DENIED); } - - alloc_size = call->pkt.u.request.stub_and_verifier.length + - call2->pkt.u.request.stub_and_verifier.length; - if (call->pkt.u.request.alloc_hint > alloc_size) { - alloc_size = call->pkt.u.request.alloc_hint; + if (nr->stub_and_verifier.length > available) { + dcesrv_call_disconnect_after(existing, + "dcesrv_auth_request - new payload too large"); + return dcesrv_fault(existing, DCERPC_FAULT_ACCESS_DENIED); } - - call->pkt.u.request.stub_and_verifier.data = - talloc_realloc(call, - call->pkt.u.request.stub_and_verifier.data, + alloc_hint = er->stub_and_verifier.length + nr->alloc_hint; + /* allocate at least 1 byte */ + alloc_hint = MAX(alloc_hint, 1); + alloc_size = er->stub_and_verifier.length + + nr->stub_and_verifier.length; + alloc_size = MAX(alloc_size, alloc_hint); + + er->stub_and_verifier.data = + talloc_realloc(existing, + er->stub_and_verifier.data, uint8_t, alloc_size); - if (!call->pkt.u.request.stub_and_verifier.data) { - return dcesrv_fault(call2, DCERPC_FAULT_OTHER); + if (er->stub_and_verifier.data == NULL) { + TALLOC_FREE(call); + return dcesrv_fault_with_flags(existing, + DCERPC_FAULT_OUT_OF_RESOURCES, + DCERPC_PFC_FLAG_DID_NOT_EXECUTE); } - memcpy(call->pkt.u.request.stub_and_verifier.data + - call->pkt.u.request.stub_and_verifier.length, - call2->pkt.u.request.stub_and_verifier.data, - call2->pkt.u.request.stub_and_verifier.length); - call->pkt.u.request.stub_and_verifier.length += - call2->pkt.u.request.stub_and_verifier.length; + memcpy(er->stub_and_verifier.data + + er->stub_and_verifier.length, + nr->stub_and_verifier.data, + nr->stub_and_verifier.length); + er->stub_and_verifier.length += nr->stub_and_verifier.length; - call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST); + existing->pkt.pfc_flags |= (call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST); - talloc_free(call2); + TALLOC_FREE(call); + call = existing; } /* this may not be the last pdu in the chain - if its isn't then just put it on the incoming_fragmented_call_list and wait for the rest */ if (call->pkt.ptype == DCERPC_PKT_REQUEST && !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) { + /* + * Up to 4 MByte are allowed by all fragments + */ + if (call->pkt.u.request.alloc_hint > DCERPC_NCACN_PAYLOAD_MAX_SIZE) { + dcesrv_call_disconnect_after(call, + "dcesrv_auth_request - initial alloc hint too large"); + return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED); + } dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST); return NT_STATUS_OK; } @@ -1189,7 +1599,8 @@ NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, switch (call->pkt.ptype) { case DCERPC_PKT_BIND: - status = dcesrv_bind(call); + status = dcesrv_bind_nak(call, + DCERPC_BIND_NAK_REASON_NOT_SPECIFIED); break; case DCERPC_PKT_AUTH3: status = dcesrv_auth3(call); @@ -1201,7 +1612,7 @@ NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, status = dcesrv_request(call); break; default: - status = NT_STATUS_INVALID_PARAMETER; + status = dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); break; } @@ -1228,7 +1639,7 @@ _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, return NT_STATUS_INTERNAL_ERROR; } - dce_ctx = talloc(mem_ctx, struct dcesrv_context); + dce_ctx = talloc_zero(mem_ctx, struct dcesrv_context); NT_STATUS_HAVE_NO_MEMORY(dce_ctx); dce_ctx->endpoint_list = NULL; dce_ctx->lp_ctx = lp_ctx; @@ -1366,6 +1777,11 @@ static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, cons srv_conn = talloc_get_type(dce_conn->transport.private_data, struct stream_connection); + dce_conn->allow_bind = false; + dce_conn->allow_auth3 = false; + dce_conn->allow_alter = false; + dce_conn->allow_request = false; + if (dce_conn->pending_call_list == NULL) { char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason); @@ -1429,6 +1845,7 @@ struct dcesrv_sock_reply_state { }; static void dcesrv_sock_reply_done(struct tevent_req *subreq); +static void dcesrv_call_terminate_step1(struct tevent_req *subreq); static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn) { @@ -1444,7 +1861,7 @@ static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn) struct dcesrv_sock_reply_state *substate; struct tevent_req *subreq; - substate = talloc(call, struct dcesrv_sock_reply_state); + substate = talloc_zero(call, struct dcesrv_sock_reply_state); if (!substate) { dcesrv_terminate_connection(dce_conn, "no memory"); return; @@ -1455,7 +1872,7 @@ static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn) DLIST_REMOVE(call->replies, rep); - if (call->replies == NULL) { + if (call->replies == NULL && call->terminate_reason == NULL) { substate->call = call; } @@ -1475,6 +1892,20 @@ static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn) substate); } + if (call->terminate_reason != NULL) { + struct tevent_req *subreq; + + subreq = tevent_queue_wait_send(call, + dce_conn->event_ctx, + dce_conn->send_queue); + if (!subreq) { + dcesrv_terminate_connection(dce_conn, __location__); + return; + } + tevent_req_set_callback(subreq, dcesrv_call_terminate_step1, + call); + } + DLIST_REMOVE(call->conn->call_list, call); call->list = DCESRV_LIST_NONE; } @@ -1502,8 +1933,51 @@ static void dcesrv_sock_reply_done(struct tevent_req *subreq) } } +static void dcesrv_call_terminate_step2(struct tevent_req *subreq); + +static void dcesrv_call_terminate_step1(struct tevent_req *subreq) +{ + struct dcesrv_call_state *call = tevent_req_callback_data(subreq, + struct dcesrv_call_state); + bool ok; + struct timeval tv; + + /* make sure we stop send queue before removing subreq */ + tevent_queue_stop(call->conn->send_queue); + + ok = tevent_queue_wait_recv(subreq); + TALLOC_FREE(subreq); + if (!ok) { + dcesrv_terminate_connection(call->conn, __location__); + return; + } + + /* disconnect after 200 usecs */ + tv = timeval_current_ofs_usec(200); + subreq = tevent_wakeup_send(call, call->conn->event_ctx, tv); + if (subreq == NULL) { + dcesrv_terminate_connection(call->conn, __location__); + return; + } + tevent_req_set_callback(subreq, dcesrv_call_terminate_step2, + call); +} + +static void dcesrv_call_terminate_step2(struct tevent_req *subreq) +{ + struct dcesrv_call_state *call = tevent_req_callback_data(subreq, + struct dcesrv_call_state); + bool ok; + ok = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (!ok) { + dcesrv_terminate_connection(call->conn, __location__); + return; + } + dcesrv_terminate_connection(call->conn, call->terminate_reason); +} struct dcesrv_socket_context { const struct dcesrv_endpoint *endpoint; @@ -1688,7 +2162,7 @@ static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx, NTSTATUS status; const char *endpoint; - dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); + dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context); NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); /* remember the endpoint of this socket */ @@ -1744,7 +2218,7 @@ static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx, full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx), endpoint); - dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); + dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context); NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); /* remember the endpoint of this socket */ @@ -1778,7 +2252,7 @@ static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx, return NT_STATUS_INVALID_PARAMETER; } - dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); + dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context); NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); /* remember the endpoint of this socket */ @@ -1816,7 +2290,7 @@ static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct port = atoi(endpoint); } - dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); + dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context); NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); /* remember the endpoint of this socket */ diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h index 8786cd83cc6..15b25ea8fda 100644 --- a/source4/rpc_server/dcerpc_server.h +++ b/source4/rpc_server/dcerpc_server.h @@ -130,6 +130,14 @@ struct dcesrv_call_state { /* this is used by the boilerplate code to generate DCERPC faults */ uint32_t fault_code; + + /* the reason why we terminate the connection after sending a response */ + const char *terminate_reason; + + /* temporary auth_info fields */ + struct dcerpc_auth in_auth_info; + struct dcerpc_auth _out_auth_info; + struct dcerpc_auth *out_auth_info; }; #define DCESRV_HANDLE_ANY 255 @@ -146,18 +154,23 @@ struct dcesrv_handle { /* hold the authentication state information */ struct dcesrv_auth { - struct dcerpc_auth *auth_info; + enum dcerpc_AuthType auth_type; + enum dcerpc_AuthLevel auth_level; + uint32_t auth_context_id; struct gensec_security *gensec_security; struct auth_session_info *session_info; NTSTATUS (*session_key)(struct dcesrv_connection *, DATA_BLOB *session_key); bool client_hdr_signing; bool hdr_signing; + bool auth_finished; + bool auth_invalid; }; struct dcesrv_connection_context { struct dcesrv_connection_context *next, *prev; uint32_t context_id; + /* TODO: remove this legacy (for openchange) in master */ struct dcesrv_assoc_group *assoc_group; /* the connection this is on */ @@ -168,6 +181,12 @@ struct dcesrv_connection_context { /* private data for the interface implementation */ void *private_data; + + /* + * the minimum required auth level for this interface + */ + enum dcerpc_AuthLevel min_auth_level; + bool allow_connect; }; @@ -195,12 +214,20 @@ struct dcesrv_connection { struct dcesrv_call_state *call_list; /* the maximum size the client wants to receive */ - uint32_t cli_max_recv_frag; + uint16_t max_recv_frag; + uint16_t max_xmit_frag; DATA_BLOB partial_input; - /* the current authentication state */ - struct dcesrv_auth auth_state; + /* This can be removed in master... */ + struct { + struct dcerpc_auth *auth_info; + struct gensec_security *gensec_security; + struct auth_session_info *session_info; + NTSTATUS (*session_key)(struct dcesrv_connection *, DATA_BLOB *session_key); + bool client_hdr_signing; + bool hdr_signing; + } _unused_auth_state; /* the event_context that will be used for this connection */ struct tevent_context *event_ctx; @@ -232,6 +259,20 @@ struct dcesrv_connection { const struct tsocket_address *local_address; const struct tsocket_address *remote_address; + + /* the current authentication state */ + struct dcesrv_auth auth_state; + + /* + * remember which pdu types are allowed + */ + bool allow_bind; + bool allow_auth3; + bool allow_alter; + bool allow_request; + + /* the association group the connection belongs to */ + struct dcesrv_assoc_group *assoc_group; }; @@ -407,5 +448,13 @@ _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call); */ _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call); +_PUBLIC_ NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface); +_PUBLIC_ NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface); +_PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface); +_PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface); #endif /* SAMBA_DCERPC_SERVER_H */ diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c index 51f299550bd..2b3f8b07710 100644 --- a/source4/rpc_server/dcesrv_auth.c +++ b/source4/rpc_server/dcesrv_auth.c @@ -39,26 +39,55 @@ */ bool dcesrv_auth_bind(struct dcesrv_call_state *call) { - struct cli_credentials *server_credentials; + struct cli_credentials *server_credentials = NULL; struct ncacn_packet *pkt = &call->pkt; struct dcesrv_connection *dce_conn = call->conn; struct dcesrv_auth *auth = &dce_conn->auth_state; NTSTATUS status; uint32_t auth_length; - if (pkt->u.bind.auth_info.length == 0) { - dce_conn->auth_state.auth_info = NULL; + if (pkt->auth_length == 0) { + auth->auth_type = DCERPC_AUTH_TYPE_NONE; + auth->auth_level = DCERPC_AUTH_LEVEL_NONE; + auth->auth_context_id = 0; return true; } - dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth); - if (!dce_conn->auth_state.auth_info) { + status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.bind.auth_info, + &call->in_auth_info, + &auth_length, false); + if (!NT_STATUS_IS_OK(status)) { return false; } - status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.bind.auth_info, - dce_conn->auth_state.auth_info, - &auth_length, false); + switch (call->in_auth_info.auth_level) { + case DCERPC_AUTH_LEVEL_CONNECT: + case DCERPC_AUTH_LEVEL_CALL: + case DCERPC_AUTH_LEVEL_PACKET: + case DCERPC_AUTH_LEVEL_INTEGRITY: + case DCERPC_AUTH_LEVEL_PRIVACY: + /* + * We evaluate auth_type only if auth_level was valid + */ + break; + default: + /* + * Setting DCERPC_AUTH_LEVEL_NONE, + * gives the caller a chance to decide what + * reject_reason to use + * + * Note: DCERPC_AUTH_LEVEL_NONE == 1 + */ + auth->auth_type = DCERPC_AUTH_TYPE_NONE; + auth->auth_level = DCERPC_AUTH_LEVEL_NONE; + auth->auth_context_id = 0; + return false; + } + + auth->auth_type = call->in_auth_info.auth_type; + auth->auth_level = call->in_auth_info.auth_level; + auth->auth_context_id = call->in_auth_info.auth_context_id; + server_credentials = cli_credentials_init(call); if (!server_credentials) { @@ -69,9 +98,9 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call) cli_credentials_set_conf(server_credentials, call->conn->dce_ctx->lp_ctx); status = cli_credentials_set_machine_account(server_credentials, call->conn->dce_ctx->lp_ctx); if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status))); - talloc_free(server_credentials); - server_credentials = NULL; + DEBUG(1, ("Failed to obtain server credentials: %s\n", + nt_errstr(status))); + return false; } status = samba_server_gensec_start(dce_conn, call->event_ctx, @@ -80,14 +109,28 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call) server_credentials, NULL, &auth->gensec_security); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to call samba_server_gensec_start %s\n", + nt_errstr(status))); + return false; + } - status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_info->auth_type, - auth->auth_info->auth_level); + if (call->conn->remote_address != NULL) { + status = gensec_set_remote_address(auth->gensec_security, + call->conn->remote_address); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to call gensec_set_remote_address() %s\n", + nt_errstr(status))); + return false; + } + } + status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_type, + auth->auth_level); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("Failed to start GENSEC mechanism for DCERPC server: auth_type=%d, auth_level=%d: %s\n", - (int)auth->auth_info->auth_type, - (int)auth->auth_info->auth_level, + (int)auth->auth_type, + (int)auth->auth_level, nt_errstr(status))); return false; } @@ -105,10 +148,20 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe NTSTATUS status; bool want_header_signing = false; - if (!call->conn->auth_state.gensec_security) { + dce_conn->allow_alter = true; + dce_conn->allow_auth3 = true; + + if (call->pkt.auth_length == 0) { + dce_conn->auth_state.auth_finished = true; + dce_conn->allow_request = true; return NT_STATUS_OK; } + /* We can't work without an existing gensec state */ + if (!call->conn->auth_state.gensec_security) { + return NT_STATUS_INTERNAL_ERROR; + } + if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) { dce_conn->auth_state.client_hdr_signing = true; want_header_signing = true; @@ -118,10 +171,17 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe want_header_signing = false; } + call->_out_auth_info = (struct dcerpc_auth) { + .auth_type = dce_conn->auth_state.auth_type, + .auth_level = dce_conn->auth_state.auth_level, + .auth_context_id = dce_conn->auth_state.auth_context_id, + }; + call->out_auth_info = &call->_out_auth_info; + status = gensec_update_ev(dce_conn->auth_state.gensec_security, call, call->event_ctx, - dce_conn->auth_state.auth_info->credentials, - &dce_conn->auth_state.auth_info->credentials); + call->in_auth_info.credentials, + &call->out_auth_info->credentials); if (NT_STATUS_IS_OK(status)) { status = gensec_session_info(dce_conn->auth_state.gensec_security, @@ -131,6 +191,8 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); return status; } + dce_conn->auth_state.auth_finished = true; + dce_conn->allow_request = true; if (!gensec_have_feature(dce_conn->auth_state.gensec_security, GENSEC_FEATURE_SIGN_PKT_HEADER)) @@ -149,9 +211,6 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe dce_conn->auth_state.session_key = dcesrv_generic_session_key; return NT_STATUS_OK; } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - dce_conn->auth_state.auth_info->auth_pad_length = 0; - dce_conn->auth_state.auth_info->auth_reserved = 0; - if (!gensec_have_feature(dce_conn->auth_state.gensec_security, GENSEC_FEATURE_SIGN_PKT_HEADER)) { @@ -184,24 +243,49 @@ bool dcesrv_auth_auth3(struct dcesrv_call_state *call) NTSTATUS status; uint32_t auth_length; - /* We can't work without an existing gensec state, and an new blob to feed it */ - if (!dce_conn->auth_state.auth_info || - !dce_conn->auth_state.gensec_security || - pkt->u.auth3.auth_info.length == 0) { + if (pkt->auth_length == 0) { + return false; + } + + if (dce_conn->auth_state.auth_finished) { + return false; + } + + /* We can't work without an existing gensec state */ + if (!dce_conn->auth_state.gensec_security) { return false; } status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.auth3.auth_info, - dce_conn->auth_state.auth_info, &auth_length, true); + &call->in_auth_info, &auth_length, true); if (!NT_STATUS_IS_OK(status)) { return false; } + if (call->in_auth_info.auth_type != dce_conn->auth_state.auth_type) { + return false; + } + + if (call->in_auth_info.auth_level != dce_conn->auth_state.auth_level) { + return false; + } + + if (call->in_auth_info.auth_context_id != dce_conn->auth_state.auth_context_id) { + return false; + } + + call->_out_auth_info = (struct dcerpc_auth) { + .auth_type = dce_conn->auth_state.auth_type, + .auth_level = dce_conn->auth_state.auth_level, + .auth_context_id = dce_conn->auth_state.auth_context_id, + }; + call->out_auth_info = &call->_out_auth_info; + /* Pass the extra data we got from the client down to gensec for processing */ status = gensec_update_ev(dce_conn->auth_state.gensec_security, call, call->event_ctx, - dce_conn->auth_state.auth_info->credentials, - &dce_conn->auth_state.auth_info->credentials); + call->in_auth_info.credentials, + &call->out_auth_info->credentials); if (NT_STATUS_IS_OK(status)) { status = gensec_session_info(dce_conn->auth_state.gensec_security, dce_conn, @@ -210,8 +294,18 @@ bool dcesrv_auth_auth3(struct dcesrv_call_state *call) DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); return false; } + dce_conn->auth_state.auth_finished = true; + dce_conn->allow_request = true; + /* Now that we are authenticated, go back to the generic session key... */ dce_conn->auth_state.session_key = dcesrv_generic_session_key; + + if (call->out_auth_info->credentials.length != 0) { + + DEBUG(4, ("GENSEC produced output token (len=%u) at bind_auth3\n", + (unsigned)call->out_auth_info->credentials.length)); + return false; + } return true; } else { DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_auth3: %s\n", @@ -233,27 +327,40 @@ bool dcesrv_auth_alter(struct dcesrv_call_state *call) uint32_t auth_length; /* on a pure interface change there is no auth blob */ - if (pkt->u.alter.auth_info.length == 0) { + if (pkt->auth_length == 0) { + if (!dce_conn->auth_state.auth_finished) { + return false; + } return true; } - /* We can't work without an existing gensec state */ - if (!dce_conn->auth_state.gensec_security) { + if (dce_conn->auth_state.auth_finished) { return false; } - dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth); - if (!dce_conn->auth_state.auth_info) { + /* We can't work without an existing gensec state */ + if (!dce_conn->auth_state.gensec_security) { return false; } status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.alter.auth_info, - dce_conn->auth_state.auth_info, - &auth_length, true); + &call->in_auth_info, &auth_length, true); if (!NT_STATUS_IS_OK(status)) { return false; } + if (call->in_auth_info.auth_type != dce_conn->auth_state.auth_type) { + return false; + } + + if (call->in_auth_info.auth_level != dce_conn->auth_state.auth_level) { + return false; + } + + if (call->in_auth_info.auth_context_id != dce_conn->auth_state.auth_context_id) { + return false; + } + return true; } @@ -268,19 +375,25 @@ NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_pack /* on a pure interface change there is no auth_info structure setup */ - if (!call->conn->auth_state.auth_info || - dce_conn->auth_state.auth_info->credentials.length == 0) { + if (call->pkt.auth_length == 0) { return NT_STATUS_OK; } if (!call->conn->auth_state.gensec_security) { - return NT_STATUS_INVALID_PARAMETER; + return NT_STATUS_INTERNAL_ERROR; } + call->_out_auth_info = (struct dcerpc_auth) { + .auth_type = dce_conn->auth_state.auth_type, + .auth_level = dce_conn->auth_state.auth_level, + .auth_context_id = dce_conn->auth_state.auth_context_id, + }; + call->out_auth_info = &call->_out_auth_info; + status = gensec_update_ev(dce_conn->auth_state.gensec_security, call, call->event_ctx, - dce_conn->auth_state.auth_info->credentials, - &dce_conn->auth_state.auth_info->credentials); + call->in_auth_info.credentials, + &call->out_auth_info->credentials); if (NT_STATUS_IS_OK(status)) { status = gensec_session_info(dce_conn->auth_state.gensec_security, @@ -290,13 +403,13 @@ NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_pack DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); return status; } + dce_conn->auth_state.auth_finished = true; + dce_conn->allow_request = true; /* Now that we are authenticated, got back to the generic session key... */ dce_conn->auth_state.session_key = dcesrv_generic_session_key; return NT_STATUS_OK; } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - dce_conn->auth_state.auth_info->auth_pad_length = 0; - dce_conn->auth_state.auth_info->auth_reserved = 0; return NT_STATUS_OK; } @@ -312,24 +425,23 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet) { struct ncacn_packet *pkt = &call->pkt; struct dcesrv_connection *dce_conn = call->conn; - struct dcerpc_auth auth; NTSTATUS status; uint32_t auth_length; size_t hdr_size = DCERPC_REQUEST_LENGTH; - if (!dce_conn->auth_state.auth_info || - !dce_conn->auth_state.gensec_security) { - if (pkt->auth_length != 0) { - return false; - } - return true; + if (!dce_conn->allow_request) { + return false; + } + + if (dce_conn->auth_state.auth_invalid) { + return false; } if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) { hdr_size += 16; } - switch (dce_conn->auth_state.auth_info->auth_level) { + switch (dce_conn->auth_state.auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: case DCERPC_AUTH_LEVEL_INTEGRITY: break; @@ -349,36 +461,41 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet) return false; } + if (!dce_conn->auth_state.gensec_security) { + return false; + } + status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.request.stub_and_verifier, - &auth, &auth_length, false); + &call->in_auth_info, &auth_length, false); if (!NT_STATUS_IS_OK(status)) { return false; } - if (auth.auth_type != dce_conn->auth_state.auth_info->auth_type) { + if (call->in_auth_info.auth_type != dce_conn->auth_state.auth_type) { return false; } - if (auth.auth_level != dce_conn->auth_state.auth_info->auth_level) { + if (call->in_auth_info.auth_level != dce_conn->auth_state.auth_level) { return false; } - if (auth.auth_context_id != dce_conn->auth_state.auth_info->auth_context_id) { + if (call->in_auth_info.auth_context_id != dce_conn->auth_state.auth_context_id) { return false; } pkt->u.request.stub_and_verifier.length -= auth_length; /* check signature or unseal the packet */ - switch (dce_conn->auth_state.auth_info->auth_level) { + switch (dce_conn->auth_state.auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: status = gensec_unseal_packet(dce_conn->auth_state.gensec_security, full_packet->data + hdr_size, pkt->u.request.stub_and_verifier.length, full_packet->data, - full_packet->length-auth.credentials.length, - &auth.credentials); + full_packet->length- + call->in_auth_info.credentials.length, + &call->in_auth_info.credentials); memcpy(pkt->u.request.stub_and_verifier.data, full_packet->data + hdr_size, pkt->u.request.stub_and_verifier.length); @@ -389,8 +506,9 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet) pkt->u.request.stub_and_verifier.data, pkt->u.request.stub_and_verifier.length, full_packet->data, - full_packet->length-auth.credentials.length, - &auth.credentials); + full_packet->length- + call->in_auth_info.credentials.length, + &call->in_auth_info.credentials); break; case DCERPC_AUTH_LEVEL_CONNECT: @@ -404,10 +522,10 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet) } /* remove the indicated amount of padding */ - if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) { + if (pkt->u.request.stub_and_verifier.length < call->in_auth_info.auth_pad_length) { return false; } - pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length; + pkt->u.request.stub_and_verifier.length -= call->in_auth_info.auth_pad_length; return NT_STATUS_IS_OK(status); } @@ -427,13 +545,7 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call, uint32_t payload_length; DATA_BLOB creds2; - /* non-signed packets are simple */ - if (dce_conn->auth_state.auth_info == NULL) { - status = ncacn_push_auth(blob, call, pkt, NULL); - return NT_STATUS_IS_OK(status); - } - - switch (dce_conn->auth_state.auth_info->auth_level) { + switch (dce_conn->auth_state.auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: case DCERPC_AUTH_LEVEL_INTEGRITY: if (sig_size == 0) { @@ -458,6 +570,10 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call, return false; } + if (!dce_conn->auth_state.gensec_security) { + return false; + } + ndr = ndr_push_init_ctx(call); if (!ndr) { return false; @@ -472,28 +588,31 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call, return false; } + call->_out_auth_info = (struct dcerpc_auth) { + .auth_type = dce_conn->auth_state.auth_type, + .auth_level = dce_conn->auth_state.auth_level, + .auth_context_id = dce_conn->auth_state.auth_context_id, + }; + call->out_auth_info = &call->_out_auth_info; + /* pad to 16 byte multiple in the payload portion of the packet. This matches what w2k3 does. Note that we can't use ndr_push_align() as that is relative to the start of the whole packet, whereas w2k8 wants it relative to the start of the stub */ - dce_conn->auth_state.auth_info->auth_pad_length = + call->out_auth_info->auth_pad_length = DCERPC_AUTH_PAD_LENGTH(pkt->u.response.stub_and_verifier.length); - ndr_err = ndr_push_zero(ndr, - dce_conn->auth_state.auth_info->auth_pad_length); + ndr_err = ndr_push_zero(ndr, call->out_auth_info->auth_pad_length); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return false; } payload_length = pkt->u.response.stub_and_verifier.length + - dce_conn->auth_state.auth_info->auth_pad_length; - - /* we start without signature, it will appended later */ - dce_conn->auth_state.auth_info->credentials = data_blob(NULL, 0); + call->out_auth_info->auth_pad_length; /* add the auth verifier */ ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, - dce_conn->auth_state.auth_info); + call->out_auth_info); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return false; } @@ -511,7 +630,7 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call, dcerpc_set_auth_length(blob, sig_size); /* sign or seal the packet */ - switch (dce_conn->auth_state.auth_info->auth_level) { + switch (dce_conn->auth_state.auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: status = gensec_seal_packet(dce_conn->auth_state.gensec_security, call, @@ -544,7 +663,7 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call, if (creds2.length != sig_size) { DEBUG(3,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n", (unsigned)creds2.length, (uint32_t)sig_size, - (unsigned)dce_conn->auth_state.auth_info->auth_pad_length, + (unsigned)call->out_auth_info->auth_pad_length, (unsigned)pkt->u.response.stub_and_verifier.length)); dcerpc_set_frag_length(blob, blob->length + creds2.length); dcerpc_set_auth_length(blob, creds2.length); diff --git a/source4/rpc_server/dcesrv_mgmt.c b/source4/rpc_server/dcesrv_mgmt.c index 8c4eb63ec30..4d3428d13cf 100644 --- a/source4/rpc_server/dcesrv_mgmt.c +++ b/source4/rpc_server/dcesrv_mgmt.c @@ -23,6 +23,14 @@ #include "rpc_server/dcerpc_server.h" #include "librpc/gen_ndr/ndr_mgmt.h" +#define DCESRV_INTERFACE_MGMT_BIND(call, iface) \ + dcesrv_interface_mgmt_bind(call, iface) +static NTSTATUS dcesrv_interface_mgmt_bind(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + return dcesrv_interface_bind_allow_connect(dce_call, iface); +} + /* mgmt_inq_if_ids */ diff --git a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c index be315001ee2..7571756845c 100644 --- a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c +++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c @@ -28,6 +28,14 @@ #include "dnsserver.h" #include "lib/ldb/include/ldb_private.h" +#define DCESRV_INTERFACE_DNSSERVER_BIND(call, iface) \ + dcesrv_interface_dnsserver_bind(call, iface) +static NTSTATUS dcesrv_interface_dnsserver_bind(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + return dcesrv_interface_bind_require_integrity(dce_call, iface); +} + struct dnsserver_state { struct loadparm_context *lp_ctx; struct ldb_context *samdb; diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c index 879f63f6df5..c28f557b545 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c @@ -39,6 +39,14 @@ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); \ } while (0) +#define DCESRV_INTERFACE_DRSUAPI_BIND(call, iface) \ + dcesrv_interface_drsuapi_bind(call, iface) +static NTSTATUS dcesrv_interface_drsuapi_bind(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + return dcesrv_interface_bind_require_privacy(dce_call, iface); +} + /* drsuapi_DsBind */ diff --git a/source4/rpc_server/echo/rpc_echo.c b/source4/rpc_server/echo/rpc_echo.c index 4863c779f4c..49c9e23c678 100644 --- a/source4/rpc_server/echo/rpc_echo.c +++ b/source4/rpc_server/echo/rpc_echo.c @@ -26,6 +26,13 @@ #include "librpc/gen_ndr/ndr_echo.h" #include "lib/events/events.h" +#define DCESRV_INTERFACE_RPCECHO_BIND(call, iface) \ + dcesrv_interface_rpcecho_bind(call, iface) +static NTSTATUS dcesrv_interface_rpcecho_bind(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + return dcesrv_interface_bind_allow_connect(dce_call, iface); +} static NTSTATUS dcesrv_echo_AddOne(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_AddOne *r) { diff --git a/source4/rpc_server/epmapper/rpc_epmapper.c b/source4/rpc_server/epmapper/rpc_epmapper.c index 62627ce3093..6b934d7d1b4 100644 --- a/source4/rpc_server/epmapper/rpc_epmapper.c +++ b/source4/rpc_server/epmapper/rpc_epmapper.c @@ -24,6 +24,14 @@ #include "librpc/gen_ndr/ndr_epmapper.h" #include "rpc_server/dcerpc_server.h" +#define DCESRV_INTERFACE_EPMAPPER_BIND(call, iface) \ + dcesrv_interface_epmapper_bind(call, iface) +static NTSTATUS dcesrv_interface_epmapper_bind(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + return dcesrv_interface_bind_allow_connect(dce_call, iface); +} + typedef uint32_t error_status_t; /* handle types for this module */ diff --git a/source4/rpc_server/handles.c b/source4/rpc_server/handles.c index be9f16ce733..820da49c02d 100644 --- a/source4/rpc_server/handles.c +++ b/source4/rpc_server/handles.c @@ -46,7 +46,7 @@ _PUBLIC_ struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_connection_contex sid = &context->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX]; - h = talloc(context->assoc_group, struct dcesrv_handle); + h = talloc_zero(context->conn->assoc_group, struct dcesrv_handle); if (!h) { return NULL; } @@ -56,12 +56,12 @@ _PUBLIC_ struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_connection_contex talloc_free(h); return NULL; } - h->assoc_group = context->assoc_group; + h->assoc_group = context->conn->assoc_group; h->iface = context->iface; h->wire_handle.handle_type = handle_type; h->wire_handle.uuid = GUID_random(); - DLIST_ADD(context->assoc_group->handles, h); + DLIST_ADD(context->conn->assoc_group->handles, h); talloc_set_destructor(h, dcesrv_handle_destructor); @@ -87,7 +87,7 @@ _PUBLIC_ struct dcesrv_handle *dcesrv_handle_fetch( return dcesrv_handle_new(context, handle_type); } - for (h=context->assoc_group->handles; h; h=h->next) { + for (h=context->conn->assoc_group->handles; h; h=h->next) { if (h->wire_handle.handle_type == p->handle_type && GUID_equal(&p->uuid, &h->wire_handle.uuid)) { if (handle_type != DCESRV_HANDLE_ANY && diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c index 53b937ef5d4..0218d9d6814 100644 --- a/source4/rpc_server/lsa/dcesrv_lsa.c +++ b/source4/rpc_server/lsa/dcesrv_lsa.c @@ -33,6 +33,14 @@ #include "libcli/security/session.h" #include "libcli/lsarpc/util_lsarpc.h" +#define DCESRV_INTERFACE_LSARPC_BIND(call, iface) \ + dcesrv_interface_lsarpc_bind(call, iface) +static NTSTATUS dcesrv_interface_lsarpc_bind(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + return dcesrv_interface_bind_reject_connect(dce_call, iface); +} + /* this type allows us to distinguish handle types */ diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index 8d92ba89d06..d90ca70c0c1 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -718,7 +718,7 @@ NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call, { enum dcerpc_transport_t transport = dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); - struct dcerpc_auth *auth_info = dce_call->conn->auth_state.auth_info; + const struct dcesrv_auth *auth = &dce_call->conn->auth_state; struct lsa_policy_state *policy_state; struct lsa_LookupSids2 q; NTSTATUS status; @@ -731,8 +731,8 @@ NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call, * We don't have policy handles on this call. So this must be restricted * to crypto connections only. */ - if (auth_info->auth_type != DCERPC_AUTH_TYPE_SCHANNEL || - auth_info->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) { + if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL || + auth->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) { DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } @@ -944,7 +944,7 @@ NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX { enum dcerpc_transport_t transport = dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); - struct dcerpc_auth *auth_info = dce_call->conn->auth_state.auth_info; + const struct dcesrv_auth *auth = &dce_call->conn->auth_state; struct lsa_policy_state *policy_state; struct lsa_LookupNames3 q; NTSTATUS status; @@ -957,8 +957,8 @@ NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX * We don't have policy handles on this call. So this must be restricted * to crypto connections only. */ - if (auth_info->auth_type != DCERPC_AUTH_TYPE_SCHANNEL || - auth_info->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) { + if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL || + auth->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) { DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index b2f0073d091..9ba28425ff2 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -41,6 +41,14 @@ #include "librpc/gen_ndr/ndr_irpc.h" #include "lib/socket/netif.h" +#define DCESRV_INTERFACE_NETLOGON_BIND(call, iface) \ + dcesrv_interface_netlogon_bind(call, iface) +static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + return dcesrv_interface_bind_reject_connect(dce_call, iface); +} + static struct memcache *global_challenge_table; struct netlogon_server_pipe_state { @@ -126,6 +134,8 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca bool allow_nt4_crypto = lpcfg_allow_nt4_crypto(dce_call->conn->dce_ctx->lp_ctx); bool reject_des_client = !allow_nt4_crypto; bool reject_md5_client = lpcfg_reject_md5_clients(dce_call->conn->dce_ctx->lp_ctx); + int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx); + bool reject_none_rpc = (schannel == true); ZERO_STRUCTP(r->out.return_credentials); *r->out.rid = 0; @@ -198,6 +208,10 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca negotiate_flags = *r->in.negotiate_flags & server_flags; + if (negotiate_flags & NETLOGON_NEG_AUTHENTICATED_RPC) { + reject_none_rpc = false; + } + if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) { reject_des_client = false; } @@ -234,6 +248,14 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca */ *r->out.negotiate_flags = negotiate_flags; + if (reject_none_rpc) { + /* schannel must be used, but client did not offer it. */ + DEBUG(0,("%s: schannel required but client failed " + "to offer it. Client was %s\n", + __func__, r->in.account_name)); + return NT_STATUS_ACCESS_DENIED; + } + switch (r->in.secure_channel_type) { case SEC_CHAN_WKSTA: case SEC_CHAN_DNS_DOMAIN: @@ -451,7 +473,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate2(struct dcesrv_call_state *dce_ca /* * If schannel is required for this call test that it actually is available. */ -static NTSTATUS schannel_check_required(struct dcerpc_auth *auth_info, +static NTSTATUS schannel_check_required(const struct dcesrv_auth *auth_info, const char *computer_name, bool integrity, bool privacy) { @@ -487,11 +509,11 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc struct netlogon_creds_CredentialState **creds_out) { NTSTATUS nt_status; - struct dcerpc_auth *auth_info = dce_call->conn->auth_state.auth_info; - bool schannel_global_required = false; /* Should be lpcfg_schannel_server() == true */ + int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx); + bool schannel_global_required = (schannel == true); if (schannel_global_required) { - nt_status = schannel_check_required(auth_info, + nt_status = schannel_check_required(&dce_call->conn->auth_state, computer_name, true, false); if (!NT_STATUS_IS_OK(nt_status)) { @@ -724,6 +746,8 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_check(const struct netr_LogonSamLogonE static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct netr_LogonSamLogonEx *r, struct netlogon_creds_CredentialState *creds) { + struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + const char *workgroup = lpcfg_workgroup(lp_ctx); struct auth4_context *auth_context; struct auth_usersupplied_info *user_info; struct auth_user_info_dc *user_info_dc; @@ -794,6 +818,13 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal user_info->password.response.lanman = data_blob_talloc(mem_ctx, r->in.logon->network->lm.data, r->in.logon->network->lm.length); user_info->password.response.nt = data_blob_talloc(mem_ctx, r->in.logon->network->nt.data, r->in.logon->network->nt.length); + nt_status = NTLMv2_RESPONSE_verify_netlogon_creds( + user_info->client.account_name, + user_info->client.domain_name, + user_info->password.response.nt, + creds, workgroup); + NT_STATUS_NOT_OK_RETURN(nt_status); + break; @@ -889,6 +920,10 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal break; case 6: + if (dce_call->conn->auth_state.auth_level < DCERPC_AUTH_LEVEL_PRIVACY) { + return NT_STATUS_INVALID_PARAMETER; + } + nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, user_info_dc, &sam3); @@ -945,8 +980,7 @@ static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, return nt_status; } - if (!dce_call->conn->auth_state.auth_info || - dce_call->conn->auth_state.auth_info->auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { + if (dce_call->conn->auth_state.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { return NT_STATUS_ACCESS_DENIED; } return dcesrv_netr_LogonSamLogon_base(dce_call, mem_ctx, r, creds); diff --git a/source4/rpc_server/remote/dcesrv_remote.c b/source4/rpc_server/remote/dcesrv_remote.c index be4bd1253e0..3eb0ad4b4a1 100644 --- a/source4/rpc_server/remote/dcesrv_remote.c +++ b/source4/rpc_server/remote/dcesrv_remote.c @@ -117,9 +117,9 @@ static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct } /* If we already have a remote association group ID, then use that */ - if (dce_call->context->assoc_group->proxied_id != 0) { + if (dce_call->conn->assoc_group->proxied_id != 0) { status = dcerpc_binding_set_assoc_group_id(b, - dce_call->context->assoc_group->proxied_id); + dce_call->conn->assoc_group->proxied_id); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("dcerpc_binding_set_assoc_group_id() - %s'\n", nt_errstr(status))); @@ -148,8 +148,8 @@ static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct return status; } - if (dce_call->context->assoc_group->proxied_id == 0) { - dce_call->context->assoc_group->proxied_id = + if (dce_call->conn->assoc_group->proxied_id == 0) { + dce_call->conn->assoc_group->proxied_id = dcerpc_binding_get_assoc_group_id(priv->c_pipe->binding); } diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index 8c34e305f15..55efdacf90a 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -41,6 +41,14 @@ #include "lib/util/tsort.h" #include "libds/common/flag_mapping.h" +#define DCESRV_INTERFACE_SAMR_BIND(call, iface) \ + dcesrv_interface_samr_bind(call, iface) +static NTSTATUS dcesrv_interface_samr_bind(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + return dcesrv_interface_bind_reject_connect(dce_call, iface); +} + /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */ #define QUERY_STRING(msg, field, attr) \ @@ -4318,6 +4326,10 @@ static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } + if (dce_call->conn->auth_state.auth_level != DCERPC_AUTH_LEVEL_PRIVACY) { + DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); + } + (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep); r2.in.domain_name = NULL; diff --git a/source4/rpc_server/samr/samr_password.c b/source4/rpc_server/samr/samr_password.c index 1466decc081..f053dad31ae 100644 --- a/source4/rpc_server/samr/samr_password.c +++ b/source4/rpc_server/samr/samr_password.c @@ -419,7 +419,10 @@ NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call, nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key); if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; + DEBUG(3,("samr: failed to get session key: %s " + "=> NT_STATUS_WRONG_PASSWORD\n", + nt_errstr(nt_status))); + return NT_STATUS_WRONG_PASSWORD; } arcfour_crypt_blob(pwbuf->data, 516, &session_key); @@ -458,7 +461,10 @@ NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call, nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key); if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; + DEBUG(3,("samr: failed to get session key: %s " + "=> NT_STATUS_WRONG_PASSWORD\n", + nt_errstr(nt_status))); + return NT_STATUS_WRONG_PASSWORD; } co_session_key = data_blob_talloc(mem_ctx, NULL, 16); @@ -500,11 +506,26 @@ NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call, const uint8_t *nt_pwd_hash) { struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL; + uint8_t random_session_key[16] = { 0, }; DATA_BLOB session_key = data_blob(NULL, 0); DATA_BLOB in, out; NTSTATUS nt_status = NT_STATUS_OK; nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key); + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) { + DEBUG(3,("samr: failed to get session key: %s " + "=> use a random session key\n", + nt_errstr(nt_status))); + + /* + * Windows just uses a random key + */ + generate_random_buffer(random_session_key, + sizeof(random_session_key)); + session_key = data_blob_const(random_session_key, + sizeof(random_session_key)); + nt_status = NT_STATUS_OK; + } if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index e044c80e59c..5d451e9b9ed 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -43,8 +43,11 @@ smbclient4 = binpath('smbclient4') bbdir = os.path.join(srcdir(), "testprogs/blackbox") # Simple tests for LDAP and CLDAP -for options in ['-U"$USERNAME%$PASSWORD" --option=socket:testnonblock=true', '-U"$USERNAME%$PASSWORD"', '-U"$USERNAME%$PASSWORD" -k yes', '-U"$USERNAME%$PASSWORD" -k no', '-U"$USERNAME%$PASSWORD" -k no --sign', '-U"$USERNAME%$PASSWORD" -k no --encrypt', '-U"$USERNAME%$PASSWORD" -k yes --encrypt', '-U"$USERNAME%$PASSWORD" -k yes --sign']: - plantestsuite("samba4.ldb.ldap with options %s(dc)" % options, "dc", "%s/test_ldb.sh ldap $SERVER %s" % (bbdir, options)) +for auth_type in ['', '-k no', '-k yes']: + for auth_level in ['--option=clientldapsaslwrapping=plain', '--sign', '--encrypt']: + creds = '-U"$USERNAME%$PASSWORD"' + options = creds + ' ' + auth_type + ' ' + auth_level + plantestsuite("samba4.ldb.ldap with options %r(dc)" % options, "dc", "%s/test_ldb.sh ldap $SERVER %s" % (bbdir, options)) # see if we support ADS on the Samba3 side try: @@ -64,6 +67,58 @@ if have_tls_support: plantestsuite("samba4.ldb.ldaps with options %s(dc)" % options, "dc", "%s/test_ldb.sh ldaps $SERVER_IP %s" % (bbdir, options)) + creds_options = [ + '--simple-bind-dn=$USERNAME@$REALM --password=$PASSWORD', + ] + peer_options = { + 'SERVER_IP': '$SERVER_IP', + 'SERVER_NAME': '$SERVER', + 'SERVER.REALM': '$SERVER.$REALM', + } + tls_verify_options = [ + '--option="tlsverifypeer=no_check"', + '--option="tlsverifypeer=ca_only"', + '--option="tlsverifypeer=ca_and_name_if_available"', + '--option="tlsverifypeer=ca_and_name"', + '--option="tlsverifypeer=as_strict_as_possible"', + ] + + # we use :local for fl2008r2dc because of the self-signed certificate + for env in ["ad_dc_ntvfs", "fl2008r2dc:local"]: + for peer_key in peer_options.keys(): + peer_val = peer_options[peer_key] + for creds in creds_options: + for tls_verify in tls_verify_options: + options = creds + ' ' + tls_verify + plantestsuite("samba4.ldb.simple.ldaps with options %s %s(%s)" % ( + peer_key, options, env), env, + "%s/test_ldb_simple.sh ldaps %s %s" % (bbdir, peer_val, options)) + +# test all "ldap server require strong auth" combinations +for env in ["ad_dc_ntvfs", "fl2008r2dc", "fl2003dc"]: + options = '--simple-bind-dn="$USERNAME@$REALM" --password="$PASSWORD"' + plantestsuite("samba4.ldb.simple.ldap with SIMPLE-BIND %s(%s)" % (options, env), + env, "%s/test_ldb_simple.sh ldap $SERVER %s" % (bbdir, options)) + if have_tls_support: + options += ' --option="tlsverifypeer=no_check"' + plantestsuite("samba4.ldb.simple.ldaps with SIMPLE-BIND %s(%s)" % (options, env), + env, "%s/test_ldb_simple.sh ldaps $SERVER %s" % (bbdir, options)) + + auth_options = [ + '--option=clientldapsaslwrapping=plain', + '--sign', + '--encrypt', + ] + + for auth_option in auth_options: + options = '-U"$USERNAME%$PASSWORD"' + ' ' + auth_option + plantestsuite("samba4.ldb.simple.ldap with SASL-BIND %s(%s)" % (options, env), + env, "%s/test_ldb_simple.sh ldap $SERVER %s" % (bbdir, options)) + if have_tls_support: + options = '-U"$USERNAME%$PASSWORD" --option="tlsverifypeer=no_check"' + plantestsuite("samba4.ldb.simple.ldaps with SASL-BIND %s(%s)" % (options, env), + env, "%s/test_ldb_simple.sh ldaps $SERVER %s" % (bbdir, options)) + for options in ['-U"$USERNAME%$PASSWORD"']: plantestsuite("samba4.ldb.ldapi with options %s(dc:local)" % options, "dc:local", "%s/test_ldb.sh ldapi $PREFIX_ABS/dc/private/ldapi %s" % (bbdir, options)) @@ -82,12 +137,12 @@ else: # add tests to this list as they start passing, so we test # that they stay passing -ncacn_np_tests = ["rpc.schannel", "rpc.join", "rpc.lsa", "rpc.dssetup", "rpc.altercontext", "rpc.netlogon", "rpc.handles", "rpc.samsync", "rpc.samba3-sessionkey", "rpc.samba3-getusername", "rpc.samba3-lsa", "rpc.samba3-bind", "rpc.samba3-netlogon", "rpc.asyncbind", "rpc.lsalookup", "rpc.lsa-getuser", "rpc.schannel2", "rpc.authcontext"] -ncalrpc_tests = ["rpc.schannel", "rpc.join", "rpc.lsa", "rpc.dssetup", "rpc.altercontext", "rpc.netlogon", "rpc.drsuapi", "rpc.asyncbind", "rpc.lsalookup", "rpc.lsa-getuser", "rpc.schannel2", "rpc.authcontext"] +ncacn_np_tests = ["rpc.schannel", "rpc.join", "rpc.lsa", "rpc.dssetup", "rpc.altercontext", "rpc.netlogon", "rpc.netlogon.admin", "rpc.handles", "rpc.samsync", "rpc.samba3-sessionkey", "rpc.samba3-getusername", "rpc.samba3-lsa", "rpc.samba3-bind", "rpc.samba3-netlogon", "rpc.asyncbind", "rpc.lsalookup", "rpc.lsa-getuser", "rpc.schannel2", "rpc.authcontext"] +ncalrpc_tests = ["rpc.schannel", "rpc.join", "rpc.lsa", "rpc.dssetup", "rpc.altercontext", "rpc.netlogon", "rpc.netlogon.admin", "rpc.asyncbind", "rpc.lsalookup", "rpc.lsa-getuser", "rpc.schannel2", "rpc.authcontext"] drs_rpc_tests = smbtorture4_testsuites("drs.rpc") -ncacn_ip_tcp_tests = ["rpc.schannel", "rpc.join", "rpc.lsa", "rpc.dssetup", "rpc.netlogon", "rpc.asyncbind", "rpc.lsalookup", "rpc.lsa-getuser", "rpc.schannel2", "rpc.authcontext", "rpc.samr.passwords.validate"] + drs_rpc_tests -slow_ncacn_np_tests = ["rpc.samlogon", "rpc.samr.users", "rpc.samr.large-dc", "rpc.samr.users.privileges", "rpc.samr.passwords", "rpc.samr.passwords.pwdlastset", "rpc.samr.passwords.lockout", "rpc.samr.passwords.badpwdcount"] -slow_ncacn_ip_tcp_tests = ["rpc.samr", "rpc.cracknames"] +ncacn_ip_tcp_tests = ["rpc.schannel", "rpc.join", "rpc.lsa", "rpc.dssetup", "rpc.drsuapi", "rpc.netlogon", "rpc.netlogon.admin", "rpc.asyncbind", "rpc.lsalookup", "rpc.lsa-getuser", "rpc.schannel2", "rpc.authcontext", "rpc.samr.passwords.validate"] + drs_rpc_tests +slow_ncacn_np_tests = ["rpc.samlogon", "rpc.samr", "rpc.samr.users", "rpc.samr.large-dc", "rpc.samr.users.privileges", "rpc.samr.passwords", "rpc.samr.passwords.pwdlastset", "rpc.samr.passwords.lockout", "rpc.samr.passwords.badpwdcount"] +slow_ncacn_ip_tcp_tests = ["rpc.cracknames"] all_rpc_tests = ncalrpc_tests + ncacn_np_tests + ncacn_ip_tcp_tests + slow_ncacn_np_tests + slow_ncacn_ip_tcp_tests + ["rpc.lsa.secrets", "rpc.pac", "rpc.samba3-sharesec", "rpc.countcalls"] @@ -135,7 +190,10 @@ for transport in ["ncacn_np", "ncacn_ip_tcp"]: else: raise AssertionError("Invalid transport %r" % transport) for t in tests: - plansmbtorture4testsuite(t, env, ["%s:$SERVER" % transport, '-U$USERNAME%$PASSWORD', '--workgroup=$DOMAIN'], "samba4.%s on %s" % (t, transport)) + bindoptions = '' + if t == 'rpc.cracknames': + bindoptions = 'seal' + plansmbtorture4testsuite(t, env, ["%s:$SERVER[%s]" % (transport,bindoptions), '-U$USERNAME%$PASSWORD', '--workgroup=$DOMAIN'], "samba4.%s on %s with %s" % (t, transport, bindoptions)) # Tests for the DFS referral calls implementation for t in smbtorture4_testsuites("dfs."): @@ -470,6 +528,7 @@ planpythontestsuite("dc:local", "samba.tests.dcerpc.rpcecho") planoldpythontestsuite("dc:local", "samba.tests.dcerpc.registry", extra_args=['-U"$USERNAME%$PASSWORD"']) planoldpythontestsuite("dc", "samba.tests.dcerpc.dnsserver", extra_args=['-U"$USERNAME%$PASSWORD"']) planoldpythontestsuite("plugin_s4_dc", "samba.tests.dcerpc.dnsserver", extra_args=['-U"$USERNAME%$PASSWORD"']) +planoldpythontestsuite("plugin_s4_dc", "samba.tests.dcerpc.raw_protocol", extra_args=['-U"$USERNAME%$PASSWORD"']) plantestsuite_loadlist("samba4.ldap.python(dc)", "dc", [python, os.path.join(samba4srcdir, "dsdb/tests/python/ldap.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) plantestsuite_loadlist("samba4.tokengroups.python(dc)", "dc:local", [python, os.path.join(samba4srcdir, "dsdb/tests/python/token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) plantestsuite("samba4.sam.python(dc)", "dc", [python, os.path.join(samba4srcdir, "dsdb/tests/python/sam.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN']) @@ -505,7 +564,7 @@ plantestsuite("samba4.blackbox.setpassword.py", "none", ["PYTHON=%s" % python, o plantestsuite("samba4.blackbox.newuser.py", "none", ["PYTHON=%s" % python, os.path.join(samba4srcdir, "setup/tests/blackbox_newuser.sh"), '$PREFIX/provision']) plantestsuite("samba4.blackbox.group.py", "none", ["PYTHON=%s" % python, os.path.join(samba4srcdir, "setup/tests/blackbox_group.sh"), '$PREFIX/provision']) plantestsuite("samba4.blackbox.spn.py(dc:local)", "dc:local", ["PYTHON=%s" % python, os.path.join(samba4srcdir, "setup/tests/blackbox_spn.sh"), '$PREFIX/dc']) -plantestsuite_loadlist("samba4.ldap.bind(dc)", "dc", [python, os.path.join(srcdir(), "auth/credentials/tests/bind.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '$LOADLIST', '$LISTOPT']) +plantestsuite_loadlist("samba4.ldap.bind(fl2008r2dc)", "fl2008r2dc", [python, os.path.join(srcdir(), "auth/credentials/tests/bind.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '$LOADLIST', '$LISTOPT']) # This makes sure we test the rid allocation code t = "rpc.samr.large-dc" diff --git a/source4/smb_server/smb/negprot.c b/source4/smb_server/smb/negprot.c index cdfa2b4046f..dfcc1a29bf2 100644 --- a/source4/smb_server/smb/negprot.c +++ b/source4/smb_server/smb/negprot.c @@ -387,8 +387,10 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice) nt_status = cli_credentials_set_machine_account(server_credentials, req->smb_conn->lp_ctx); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(nt_status))); - talloc_free(server_credentials); - server_credentials = NULL; + /* + * We keep the server_credentials as anonymous + * this is required for the spoolss.notify test + */ } nt_status = samba_server_gensec_start(req, diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c index 4ebc0c47718..e06853afcd4 100644 --- a/source4/smb_server/smb/sesssetup.c +++ b/source4/smb_server/smb/sesssetup.c @@ -263,6 +263,7 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess) const char *remote_machine = NULL; struct tevent_req *subreq; struct sesssetup_context *state; + bool allow_raw = lpcfg_raw_ntlmv2_auth(req->smb_conn->lp_ctx); sess->nt1.out.vuid = 0; sess->nt1.out.action = 0; @@ -338,6 +339,15 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess) user_info->password.response.nt = sess->nt1.in.password2; user_info->password.response.nt.data = talloc_steal(user_info, sess->nt1.in.password2.data); + if (!allow_raw && user_info->password.response.nt.length >= 48) { + /* + * NTLMv2_RESPONSE has at least 48 bytes + * and should only be supported via NTLMSSP. + */ + status = NT_STATUS_INVALID_PARAMETER; + goto failed; + } + subreq = auth_check_password_send(state, req->smb_conn->connection->event.ctx, state->auth_context, diff --git a/source4/smb_server/smb2/negprot.c b/source4/smb_server/smb2/negprot.c index b48b1700bf0..addd278eb4c 100644 --- a/source4/smb_server/smb2/negprot.c +++ b/source4/smb_server/smb2/negprot.c @@ -49,8 +49,10 @@ static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB * nt_status = cli_credentials_set_machine_account(server_credentials, req->smb_conn->lp_ctx); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(nt_status))); - talloc_free(server_credentials); - server_credentials = NULL; + /* + * We keep the server_credentials as anonymous + * this is required for the spoolss.notify test + */ } req->smb_conn->negotiate.server_credentials = talloc_steal(req->smb_conn, server_credentials); @@ -145,6 +147,7 @@ static NTSTATUS smb2srv_negprot_backend(struct smb2srv_request *req, struct smb2 switch (signing_setting) { case SMB_SIGNING_DEFAULT: + case SMB_SIGNING_IPC_DEFAULT: smb_panic(__location__); break; case SMB_SIGNING_OFF: diff --git a/source4/smb_server/smb2/sesssetup.c b/source4/smb_server/smb2/sesssetup.c index 35a14840300..36adafdb891 100644 --- a/source4/smb_server/smb2/sesssetup.c +++ b/source4/smb_server/smb2/sesssetup.c @@ -201,14 +201,6 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses set SMB2_NEGOTIATE_SIGNING_REQUIRED */ if (io->smb2.in.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) { smb_sess->smb2_signing.required = true; - } else if (req->smb_conn->smb2_signing_required) { - /* - * if required signing was negotiates in SMB2 Negotiate - * then the client made an error not using it here - */ - DEBUG(1, ("SMB2 signing required on the connection but not used on session\n")); - req->status = NT_STATUS_FOOBAR; - goto failed; } /* disable receipt of more packets on this socket until we've diff --git a/source4/torture/basic/base.c b/source4/torture/basic/base.c index 6a792b2781f..01ac170ea2f 100644 --- a/source4/torture/basic/base.c +++ b/source4/torture/basic/base.c @@ -371,6 +371,7 @@ static bool run_negprot_nowait(struct torture_context *tctx) struct tevent_req *req; req = smb_raw_negotiate_send(cli, tctx->ev, cli->transport, + PROTOCOL_CORE, PROTOCOL_NT1); tevent_loop_once(tctx->ev); if (!tevent_req_is_in_progress(req)) { @@ -1527,6 +1528,7 @@ static bool torture_chkpath_test(struct torture_context *tctx, static bool torture_samba3_errorpaths(struct torture_context *tctx) { bool nt_status_support; + bool client_ntlmv2_auth; struct smbcli_state *cli_nt = NULL, *cli_dos = NULL; bool result = false; int fnum; @@ -1536,18 +1538,27 @@ static bool torture_samba3_errorpaths(struct torture_context *tctx) NTSTATUS status; nt_status_support = lpcfg_nt_status_support(tctx->lp_ctx); + client_ntlmv2_auth = lpcfg_client_ntlmv2_auth(tctx->lp_ctx); if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", "yes")) { torture_result(tctx, TORTURE_FAIL, "Could not set 'nt status support = yes'\n"); goto fail; } + if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", "yes")) { + torture_result(tctx, TORTURE_FAIL, "Could not set 'client ntlmv2 auth = yes'\n"); + goto fail; + } if (!torture_open_connection(&cli_nt, tctx, 0)) { goto fail; } if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", "no")) { - torture_result(tctx, TORTURE_FAIL, "Could not set 'nt status support = yes'\n"); + torture_result(tctx, TORTURE_FAIL, "Could not set 'nt status support = no'\n"); + goto fail; + } + if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", "no")) { + torture_result(tctx, TORTURE_FAIL, "Could not set 'client ntlmv2 auth = no'\n"); goto fail; } @@ -1557,7 +1568,12 @@ static bool torture_samba3_errorpaths(struct torture_context *tctx) if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", nt_status_support ? "yes":"no")) { - torture_result(tctx, TORTURE_FAIL, "Could not reset 'nt status support = yes'"); + torture_result(tctx, TORTURE_FAIL, "Could not reset 'nt status support'"); + goto fail; + } + if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", + client_ntlmv2_auth ? "yes":"no")) { + torture_result(tctx, TORTURE_FAIL, "Could not reset 'client ntlmv2 auth'"); goto fail; } diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py index f692edc4f57..683987fdb6d 100644 --- a/source4/torture/drs/python/drs_base.py +++ b/source4/torture/drs/python/drs_base.py @@ -24,10 +24,8 @@ import time import os sys.path.insert(0, "bin/python") -import samba +import samba.tests from samba import dsdb -samba.ensure_external_module("testtools", "testtools") -samba.ensure_external_module("subunit", "subunit/python") from ldb import ( SCOPE_BASE, @@ -35,8 +33,6 @@ from ldb import ( FLAG_MOD_REPLACE, ) -import samba.tests - class DrsBaseTestCase(samba.tests.BlackboxTestCase): """Base class implementation for all DRS python tests. diff --git a/source4/torture/ndr/ntlmssp.c b/source4/torture/ndr/ntlmssp.c index a3cf7b8591d..aeac26ffe57 100644 --- a/source4/torture/ndr/ntlmssp.c +++ b/source4/torture/ndr/ntlmssp.c @@ -2,7 +2,7 @@ Unix SMB/CIFS implementation. test suite for ntlmssp ndr operations - Copyright (C) Guenther Deschner 2010 + Copyright (C) Guenther Deschner 2010,2015 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 @@ -33,6 +33,23 @@ static const uint8_t ntlmssp_NEGOTIATE_MESSAGE_data[] = { static bool ntlmssp_NEGOTIATE_MESSAGE_check(struct torture_context *tctx, struct NEGOTIATE_MESSAGE *r) { + torture_assert_str_equal(tctx, r->Signature, "NTLMSSP", "Signature"); + torture_assert_int_equal(tctx, r->MessageType, NtLmNegotiate, "MessageType"); + torture_assert_int_equal(tctx, r->NegotiateFlags, 0xe2088297, "NegotiateFlags"); + torture_assert_int_equal(tctx, r->DomainNameLen, 0, "DomainNameLen"); + torture_assert_int_equal(tctx, r->DomainNameMaxLen, 0, "DomainNameMaxLen"); + torture_assert(tctx, r->DomainName == NULL, "DomainName"); + torture_assert_int_equal(tctx, r->WorkstationLen, 0, "WorkstationLen"); + torture_assert_int_equal(tctx, r->WorkstationMaxLen, 0, "WorkstationMaxLen"); + torture_assert(tctx, r->Workstation == NULL, "Workstation"); + torture_assert_int_equal(tctx, r->Version.version.ProductMajorVersion, NTLMSSP_WINDOWS_MAJOR_VERSION_6, "ProductMajorVersion"); + torture_assert_int_equal(tctx, r->Version.version.ProductMinorVersion, NTLMSSP_WINDOWS_MINOR_VERSION_1, "ProductMinorVersion"); + torture_assert_int_equal(tctx, r->Version.version.ProductBuild, 0x1db0, "ProductBuild"); + torture_assert_int_equal(tctx, r->Version.version.Reserved[0], 0x00, "Reserved"); + torture_assert_int_equal(tctx, r->Version.version.Reserved[1], 0x00, "Reserved"); + torture_assert_int_equal(tctx, r->Version.version.Reserved[2], 0x00, "Reserved"); + torture_assert_int_equal(tctx, r->Version.version.NTLMRevisionCurrent, NTLMSSP_REVISION_W2K3, "NTLMRevisionCurrent"); + return true; } @@ -58,6 +75,48 @@ static const uint8_t ntlmssp_CHALLENGE_MESSAGE_data[] = { static bool ntlmssp_CHALLENGE_MESSAGE_check(struct torture_context *tctx, struct CHALLENGE_MESSAGE *r) { + uint8_t chal[8] = { 0xed, 0xc8, 0x2b, 0x7d, 0x2e, 0xd7, 0xd0, 0xd9 }; + uint8_t data[8] = { 0 }; + + torture_assert_str_equal(tctx, r->Signature, "NTLMSSP", "Signature"); + torture_assert_int_equal(tctx, r->MessageType, NtLmChallenge, "MessageType"); + torture_assert_int_equal(tctx, r->TargetNameLen, 10, "TargetNameLen"); + torture_assert_int_equal(tctx, r->TargetNameMaxLen, 10, "TargetNameMaxLen"); + torture_assert_str_equal(tctx, r->TargetName, "SAMBA", "TargetName"); + torture_assert_int_equal(tctx, r->NegotiateFlags, 0xe2898295, "NegotiateFlags"); + torture_assert_mem_equal(tctx, r->ServerChallenge, chal, 8, "ServerChallenge"); + torture_assert_mem_equal(tctx, r->Reserved, data, 8, "Reserved"); + torture_assert_int_equal(tctx, r->TargetInfoLen, 120, "TargetInfoLen"); + torture_assert_int_equal(tctx, r->TargetInfoMaxLen, 120, "TargetInfoMaxLen"); + torture_assert_int_equal(tctx, r->TargetInfo->count, 5, "TargetInfo->count"); + + torture_assert_int_equal(tctx, r->TargetInfo->pair[0].AvId, MsvAvNbDomainName, "AvId"); + torture_assert_int_equal(tctx, r->TargetInfo->pair[0].AvLen, 10, "AvLen"); + torture_assert_str_equal(tctx, r->TargetInfo->pair[0].Value.AvNbDomainName, "SAMBA", "AvNbDomainName"); + + torture_assert_int_equal(tctx, r->TargetInfo->pair[1].AvId, MsvAvNbComputerName, "AvId"); + torture_assert_int_equal(tctx, r->TargetInfo->pair[1].AvLen, 16, "AvLen"); + torture_assert_str_equal(tctx, r->TargetInfo->pair[1].Value.AvNbComputerName, "MTHELENA", "AvNbComputerName"); + + torture_assert_int_equal(tctx, r->TargetInfo->pair[2].AvId, MsvAvDnsDomainName, "AvId"); + torture_assert_int_equal(tctx, r->TargetInfo->pair[2].AvLen, 28, "AvLen"); + torture_assert_str_equal(tctx, r->TargetInfo->pair[2].Value.AvDnsDomainName, "ber.redhat.com", "AvDnsDomainName"); + + torture_assert_int_equal(tctx, r->TargetInfo->pair[3].AvId, MsvAvDnsComputerName, "AvId"); + torture_assert_int_equal(tctx, r->TargetInfo->pair[3].AvLen, 46, "AvLen"); + torture_assert_str_equal(tctx, r->TargetInfo->pair[3].Value.AvDnsComputerName, "mthelena.ber.redhat.com", "AvDnsComputerName"); + + torture_assert_int_equal(tctx, r->TargetInfo->pair[4].AvId, MsvAvEOL, "AvId"); + torture_assert_int_equal(tctx, r->TargetInfo->pair[4].AvLen, 0, "AvLen"); + + torture_assert_int_equal(tctx, r->Version.version.ProductMajorVersion, NTLMSSP_WINDOWS_MAJOR_VERSION_6, "ProductMajorVersion"); + torture_assert_int_equal(tctx, r->Version.version.ProductMinorVersion, NTLMSSP_WINDOWS_MINOR_VERSION_1, "ProductMinorVersion"); + torture_assert_int_equal(tctx, r->Version.version.ProductBuild, 0, "ProductBuild"); + torture_assert_int_equal(tctx, r->Version.version.Reserved[0], 0x00, "Reserved"); + torture_assert_int_equal(tctx, r->Version.version.Reserved[1], 0x00, "Reserved"); + torture_assert_int_equal(tctx, r->Version.version.Reserved[2], 0x00, "Reserved"); + torture_assert_int_equal(tctx, r->Version.version.NTLMRevisionCurrent, NTLMSSP_REVISION_W2K3, "NTLMRevisionCurrent"); + return true; } @@ -105,6 +164,113 @@ static const uint8_t ntlmssp_AUTHENTICATE_MESSAGE_data[] = { static bool ntlmssp_AUTHENTICATE_MESSAGE_check(struct torture_context *tctx, struct AUTHENTICATE_MESSAGE *r) { + uint8_t lm_challenge_response[24] = { 0 }; + struct NTLMv2_RESPONSE v2; + struct AV_PAIR_LIST AvPairs; + uint8_t Response[16] = { + 0x38, 0xcf, 0xfb, 0x39, 0x5a, 0xb3, 0x4c, 0x58, + 0x86, 0x35, 0xa3, 0xe7, 0x1e, 0x00, 0x98, 0x43 + }; + uint8_t ChallengeFromClient[8] = { + 0x3c, 0x21, 0x0a, 0xe9, 0xde, 0x61, 0xc0, 0x7e + }; + uint8_t MachineId[32] = { + 0x0a, 0xfd, 0x3b, 0x2c, 0xad, 0x43, 0x46, 0x8b, + 0x49, 0x01, 0x6c, 0xa5, 0xf3, 0xbc, 0xd2, 0x13, + 0xbb, 0x70, 0xe2, 0x65, 0x96, 0xba, 0x0d, 0x8d, + 0x5d, 0x31, 0xe6, 0x47, 0x94, 0x61, 0xed, 0x28 + }; + uint8_t EncryptedRandomSessionKey[16] = { + 0xA4, 0x23, 0xD4, 0x5C, 0x16, 0x52, 0x8D, 0x56, + 0x34, 0x2D, 0x1C, 0xFF, 0x86, 0x17, 0xC9, 0x4F + }; + + torture_assert_str_equal(tctx, r->Signature, "NTLMSSP", "Signature"); + torture_assert_int_equal(tctx, r->MessageType, NtLmAuthenticate, "MessageType"); + torture_assert_int_equal(tctx, r->LmChallengeResponseLen, 24, "LmChallengeResponseLen"); + torture_assert_int_equal(tctx, r->LmChallengeResponseMaxLen, 24, "LmChallengeResponseMaxLen"); + torture_assert_mem_equal(tctx, r->LmChallengeResponse->v1.Response, lm_challenge_response, 24, "LmChallengeResponse"); + + torture_assert_int_equal(tctx, r->NtChallengeResponseLen, 270, "NtChallengeResponseLen"); + torture_assert_int_equal(tctx, r->NtChallengeResponseMaxLen, 270, "NtChallengeResponseMaxLen"); + + v2 = r->NtChallengeResponse->v2; + + torture_assert_mem_equal(tctx, v2.Response, Response, 16, "v2.Response"); + torture_assert_int_equal(tctx, v2.Challenge.RespType, 1, "RespType"); + torture_assert_int_equal(tctx, v2.Challenge.HiRespType, 1, "HiRespType"); + torture_assert_int_equal(tctx, v2.Challenge.Reserved1, 0, "Reserved1"); + torture_assert_int_equal(tctx, v2.Challenge.Reserved2, 0, "Reserved2"); + /* TimeStamp : Tue Sep 14 17:06:53 2010 CEST */ + torture_assert_mem_equal(tctx, v2.Challenge.ChallengeFromClient, ChallengeFromClient, 8, "v2.Challenge.ChallengeFromClient"); + torture_assert_int_equal(tctx, v2.Challenge.Reserved3, 0, "Reserved3"); + + AvPairs = v2.Challenge.AvPairs; + + torture_assert_int_equal(tctx, AvPairs.count, 8, "AvPairs.count"); + + torture_assert_int_equal(tctx, AvPairs.pair[0].AvId, MsvAvNbDomainName, "AvId"); + torture_assert_int_equal(tctx, AvPairs.pair[0].AvLen, 10, "AvLen"); + torture_assert_str_equal(tctx, AvPairs.pair[0].Value.AvNbDomainName, "SAMBA", "Value.AvNbDomainName"); + + torture_assert_int_equal(tctx, AvPairs.pair[1].AvId, MsvAvNbComputerName, "AvId"); + torture_assert_int_equal(tctx, AvPairs.pair[1].AvLen, 16, "AvLen"); + torture_assert_str_equal(tctx, AvPairs.pair[1].Value.AvNbComputerName, "MTHELENA", "Value.AvNbComputerName"); + + torture_assert_int_equal(tctx, AvPairs.pair[2].AvId, MsvAvDnsDomainName, "AvId"); + torture_assert_int_equal(tctx, AvPairs.pair[2].AvLen, 28, "AvLen"); + torture_assert_str_equal(tctx, AvPairs.pair[2].Value.AvDnsDomainName, "ber.redhat.com", "Value.AvDnsDomainName"); + + torture_assert_int_equal(tctx, AvPairs.pair[3].AvId, MsvAvDnsComputerName, "AvId"); + torture_assert_int_equal(tctx, AvPairs.pair[3].AvLen, 46, "AvLen"); + torture_assert_str_equal(tctx, AvPairs.pair[3].Value.AvDnsComputerName, "mthelena.ber.redhat.com", "Value.AvDnsComputerName"); + + torture_assert_int_equal(tctx, AvPairs.pair[4].AvId, MsvAvSingleHost, "AvId"); + torture_assert_int_equal(tctx, AvPairs.pair[4].AvLen, 48, "AvLen"); + torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.Size, 48, "Value.AvSingleHost.Size"); + torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.Z4, 0, "Value.AvSingleHost.Z4"); + torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.token_info.Flags, 0, "Value.AvSingleHost.token_info.Flags"); + torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.token_info.TokenIL, 0x00003000, "Value.AvSingleHost.token_info.TokenIL"); + torture_assert_mem_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.token_info.MachineId, MachineId, 32, "Value.AvSingleHost.token_info.MachineId"); + torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.remaining.length, 0, "Value.AvSingleHost.remaining.length"); + + torture_assert_int_equal(tctx, AvPairs.pair[5].AvId, MsvChannelBindings, "AvId"); + torture_assert_int_equal(tctx, AvPairs.pair[5].AvLen, 16, "AvLen"); + torture_assert_mem_equal(tctx, AvPairs.pair[5].Value.ChannelBindings, lm_challenge_response, 16, "Value.ChannelBindings"); + + torture_assert_int_equal(tctx, AvPairs.pair[6].AvId, MsvAvTargetName, "AvId"); + torture_assert_int_equal(tctx, AvPairs.pair[6].AvLen, 26, "AvLen"); + torture_assert_str_equal(tctx, AvPairs.pair[6].Value.AvTargetName, "cifs/mthelena", "Value.AvTargetName"); + + torture_assert_int_equal(tctx, AvPairs.pair[7].AvId, MsvAvEOL, "AvId"); + torture_assert_int_equal(tctx, AvPairs.pair[7].AvLen, 0, "AvLen"); + + torture_assert_int_equal(tctx, r->DomainNameLen, 14, "DomainNameLen"); + torture_assert_int_equal(tctx, r->DomainNameMaxLen, 14, "DomainNameMaxLen"); + torture_assert_str_equal(tctx, r->DomainName, "W2K8DOM", "DomainName"); + + torture_assert_int_equal(tctx, r->UserNameLen, 26, "UserNameLen"); + torture_assert_int_equal(tctx, r->UserNameMaxLen, 26, "UserNameMaxLen"); + torture_assert_str_equal(tctx, r->UserName, "Administrator", "UserName"); + + torture_assert_int_equal(tctx, r->WorkstationLen, 12, "WorkstationLen"); + torture_assert_int_equal(tctx, r->WorkstationMaxLen, 12, "WorkstationMaxLen"); + torture_assert_str_equal(tctx, r->Workstation, "W2K8R2", "Workstation"); + + torture_assert_int_equal(tctx, r->EncryptedRandomSessionKeyLen, 16, "EncryptedRandomSessionKeyLen"); + torture_assert_int_equal(tctx, r->EncryptedRandomSessionKeyMaxLen, 16, "EncryptedRandomSessionKeyMaxLen"); + torture_assert_mem_equal(tctx, r->EncryptedRandomSessionKey->data, EncryptedRandomSessionKey, 16, "EncryptedRandomSessionKeyMaxLen"); + + torture_assert_int_equal(tctx, r->NegotiateFlags, 0xe2888215, "NegotiateFlags"); + + torture_assert_int_equal(tctx, r->Version.version.ProductMajorVersion, NTLMSSP_WINDOWS_MAJOR_VERSION_6, "ProductMajorVersion"); + torture_assert_int_equal(tctx, r->Version.version.ProductMinorVersion, NTLMSSP_WINDOWS_MINOR_VERSION_1, "ProductMinorVersion"); + torture_assert_int_equal(tctx, r->Version.version.ProductBuild, 0x1db0, "ProductBuild"); + torture_assert_int_equal(tctx, r->Version.version.Reserved[0], 0x00, "Reserved"); + torture_assert_int_equal(tctx, r->Version.version.Reserved[1], 0x00, "Reserved"); + torture_assert_int_equal(tctx, r->Version.version.Reserved[2], 0x00, "Reserved"); + torture_assert_int_equal(tctx, r->Version.version.NTLMRevisionCurrent, NTLMSSP_REVISION_W2K3, "NTLMRevisionCurrent"); + return true; } @@ -113,9 +279,18 @@ struct torture_suite *ndr_ntlmssp_suite(TALLOC_CTX *ctx) struct torture_suite *suite = torture_suite_create(ctx, "ntlmssp"); torture_suite_add_ndr_pull_test(suite, NEGOTIATE_MESSAGE, ntlmssp_NEGOTIATE_MESSAGE_data, ntlmssp_NEGOTIATE_MESSAGE_check); -#if 0 torture_suite_add_ndr_pull_test(suite, CHALLENGE_MESSAGE, ntlmssp_CHALLENGE_MESSAGE_data, ntlmssp_CHALLENGE_MESSAGE_check); torture_suite_add_ndr_pull_test(suite, AUTHENTICATE_MESSAGE, ntlmssp_AUTHENTICATE_MESSAGE_data, ntlmssp_AUTHENTICATE_MESSAGE_check); -#endif + + torture_suite_add_ndr_pullpush_test(suite, + NEGOTIATE_MESSAGE, + data_blob_const(ntlmssp_NEGOTIATE_MESSAGE_data, sizeof(ntlmssp_NEGOTIATE_MESSAGE_data)), + ntlmssp_NEGOTIATE_MESSAGE_check); + + torture_suite_add_ndr_pullpush_test(suite, + CHALLENGE_MESSAGE, + data_blob_const(ntlmssp_CHALLENGE_MESSAGE_data, sizeof(ntlmssp_CHALLENGE_MESSAGE_data)), + ntlmssp_CHALLENGE_MESSAGE_check); + return suite; } diff --git a/source4/torture/raw/samba3misc.c b/source4/torture/raw/samba3misc.c index a818c6bb484..97586538a45 100644 --- a/source4/torture/raw/samba3misc.c +++ b/source4/torture/raw/samba3misc.c @@ -440,22 +440,29 @@ bool torture_samba3_badpath(struct torture_context *torture) bool ret = true; TALLOC_CTX *mem_ctx; bool nt_status_support; + bool client_ntlmv2_auth; torture_assert(torture, mem_ctx = talloc_init("torture_samba3_badpath"), "talloc_init failed"); nt_status_support = lpcfg_nt_status_support(torture->lp_ctx); + client_ntlmv2_auth = lpcfg_client_ntlmv2_auth(torture->lp_ctx); torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "yes"), ret, fail, "Could not set 'nt status support = yes'\n"); + torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", "yes"), ret, fail, "Could not set 'client ntlmv2 auth = yes'\n"); torture_assert_goto(torture, torture_open_connection(&cli_nt, torture, 0), ret, fail, "Could not open NTSTATUS connection\n"); torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "no"), ret, fail, "Could not set 'nt status support = no'\n"); + torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", "no"), ret, fail, "Could not set 'client ntlmv2 auth = no'\n"); torture_assert_goto(torture, torture_open_connection(&cli_dos, torture, 1), ret, fail, "Could not open DOS connection\n"); torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", nt_status_support ? "yes":"no"), ret, fail, "Could not set 'nt status support' back to where it was\n"); + torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", + client_ntlmv2_auth ? "yes":"no"), + ret, fail, "Could not set 'client ntlmv2 auth' back to where it was\n"); torture_assert(torture, torture_setup_dir(cli_nt, dirname), "creating test directory"); diff --git a/source4/torture/rpc/alter_context.c b/source4/torture/rpc/alter_context.c index d14cabc3a09..60e03db2914 100644 --- a/source4/torture/rpc/alter_context.c +++ b/source4/torture/rpc/alter_context.c @@ -85,7 +85,7 @@ bool torture_rpc_alter_context(struct torture_context *torture) if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) { ret &= test_lsa_OpenPolicy2_ex(p->binding_handle, torture, &handle, - NT_STATUS_IO_DEVICE_ERROR); + NT_STATUS_CONNECTION_DISCONNECTED); torture_assert(torture, !dcerpc_binding_handle_is_connected(p->binding_handle), "dcerpc disonnected"); diff --git a/source4/torture/rpc/backupkey.c b/source4/torture/rpc/backupkey.c index 1a57bd2c687..119b1d68d9c 100644 --- a/source4/torture/rpc/backupkey.c +++ b/source4/torture/rpc/backupkey.c @@ -1542,8 +1542,10 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx, struct bkrp_server_side_wrapped *server_side_wrapped, enum test_wrong wrong) { - struct dcerpc_pipe *lsa_p; - struct dcerpc_binding_handle *lsa_b; + char *lsa_binding_string = NULL; + struct dcerpc_binding *lsa_binding = NULL; + struct dcerpc_pipe *lsa_p = NULL; + struct dcerpc_binding_handle *lsa_b = NULL; struct lsa_OpenSecret r_secret; struct lsa_QuerySecret r_query_secret; struct policy_handle *handle, sec_handle; @@ -1568,9 +1570,20 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx, ZERO_STRUCT(r_query_secret); /* Now read BCKUPKEY_P and prove we can do a matching decrypt and encrypt */ - + + /* lsa_OpenSecret only works with ncacn_np and AUTH_LEVEL_NONE */ + lsa_binding_string = talloc_asprintf(tctx, "ncacn_np:%s", + torture_setting_string(tctx, "host", NULL)); + torture_assert(tctx, lsa_binding_string != NULL, "lsa_binding_string"); + + torture_assert_ntstatus_ok(tctx, + dcerpc_parse_binding(tctx, lsa_binding_string, &lsa_binding), + "Failed to parse dcerpc binding"); + torture_assert_ntstatus_ok(tctx, - torture_rpc_connection(tctx, &lsa_p, &ndr_table_lsarpc), + dcerpc_pipe_connect_b(tctx, &lsa_p, + lsa_binding, &ndr_table_lsarpc, + cmdline_credentials, tctx->ev, tctx->lp_ctx), "Opening LSA pipe"); lsa_b = lsa_p->binding_handle; diff --git a/source4/torture/rpc/forest_trust.c b/source4/torture/rpc/forest_trust.c index 74a56ef639b..758befcc1e3 100644 --- a/source4/torture/rpc/forest_trust.c +++ b/source4/torture/rpc/forest_trust.c @@ -592,7 +592,8 @@ static bool test_validate_trust(struct torture_context *tctx, NTSTATUS status; struct cli_credentials *credentials; struct dcerpc_binding *b; - struct dcerpc_pipe *p; + struct dcerpc_pipe *p1 = NULL; + struct dcerpc_pipe *p = NULL; struct netr_GetForestTrustInformation fr; struct lsa_ForestTrustInformation *forest_trust_info; @@ -620,7 +621,7 @@ static bool test_validate_trust(struct torture_context *tctx, trusted_dom_name, CRED_SPECIFIED); cli_credentials_set_secure_channel_type(credentials, SEC_CHAN_DOMAIN); - status = dcerpc_pipe_connect_b(tctx, &p, b, + status = dcerpc_pipe_connect_b(tctx, &p1, b, &ndr_table_netlogon, credentials, tctx->ev, tctx->lp_ctx); @@ -632,11 +633,16 @@ static bool test_validate_trust(struct torture_context *tctx, return false; } - if (!test_SetupCredentials3(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, + if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, credentials, &creds)) { torture_comment(tctx, "test_SetupCredentials3 failed.\n"); return false; } + if (!test_SetupCredentialsPipe(p1, tctx, credentials, creds, + DCERPC_SIGN | DCERPC_SEAL, &p)) { + torture_comment(tctx, "test_SetupCredentialsPipe failed.\n"); + return false; + } netlogon_creds_client_authenticator(creds, &a); diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index a2450cf1c25..66f09a239c5 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -359,6 +359,35 @@ bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx, return true; } +bool test_SetupCredentialsPipe(const struct dcerpc_pipe *p1, + struct torture_context *tctx, + struct cli_credentials *machine_credentials, + struct netlogon_creds_CredentialState *creds, + uint32_t additional_flags, + struct dcerpc_pipe **_p2) +{ + NTSTATUS status; + struct dcerpc_binding *b2 = NULL; + struct dcerpc_pipe *p2 = NULL; + + b2 = dcerpc_binding_dup(tctx, p1->binding); + torture_assert(tctx, b2 != NULL, "dcerpc_binding_dup"); + dcerpc_binding_set_flags(b2, + DCERPC_SCHANNEL | additional_flags, + DCERPC_AUTH_OPTIONS); + + cli_credentials_set_netlogon_creds(machine_credentials, creds); + status = dcerpc_pipe_connect_b(tctx, &p2, b2, + &ndr_table_netlogon, + machine_credentials, + tctx->ev, tctx->lp_ctx); + cli_credentials_set_netlogon_creds(machine_credentials, NULL); + torture_assert_ntstatus_ok(tctx, status, "dcerpc_pipe_connect_b schannel"); + + *_p2 = p2; + return true; +} + /* try a change password for our machine account */ @@ -436,7 +465,7 @@ static bool test_SetPassword(struct torture_context *tctx, try a change password for our machine account */ static bool test_SetPassword_flags(struct torture_context *tctx, - struct dcerpc_pipe *p, + struct dcerpc_pipe *p1, struct cli_credentials *machine_credentials, uint32_t negotiate_flags) { @@ -445,14 +474,20 @@ static bool test_SetPassword_flags(struct torture_context *tctx, struct netlogon_creds_CredentialState *creds; struct netr_Authenticator credential, return_authenticator; struct samr_Password new_password; - struct dcerpc_binding_handle *b = p->binding_handle; + struct dcerpc_pipe *p = NULL; + struct dcerpc_binding_handle *b = NULL; - if (!test_SetupCredentials2(p, tctx, negotiate_flags, + if (!test_SetupCredentials2(p1, tctx, negotiate_flags, machine_credentials, cli_credentials_get_secure_channel_type(machine_credentials), &creds)) { return false; } + if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds, + DCERPC_SIGN | DCERPC_SEAL, &p)) { + return false; + } + b = p->binding_handle; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME); @@ -532,7 +567,7 @@ static DATA_BLOB netlogon_very_rand_pass(TALLOC_CTX *mem_ctx, int len) try a change password for our machine account */ static bool test_SetPassword2_with_flags(struct torture_context *tctx, - struct dcerpc_pipe *p, + struct dcerpc_pipe *p1, struct cli_credentials *machine_credentials, uint32_t flags) { @@ -544,11 +579,19 @@ static bool test_SetPassword2_with_flags(struct torture_context *tctx, struct samr_Password nt_hash; struct netr_Authenticator credential, return_authenticator; struct netr_CryptPassword new_password; - struct dcerpc_binding_handle *b = p->binding_handle; + struct dcerpc_pipe *p = NULL; + struct dcerpc_binding_handle *b = NULL; - if (!test_SetupCredentials2(p, tctx, flags, machine_credentials, cli_credentials_get_secure_channel_type(machine_credentials), &creds)) { + if (!test_SetupCredentials2(p1, tctx, flags, machine_credentials, + cli_credentials_get_secure_channel_type(machine_credentials), + &creds)) { + return false; + } + if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds, + DCERPC_SIGN | DCERPC_SEAL, &p)) { return false; } + b = p->binding_handle; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME); @@ -838,6 +881,7 @@ static bool test_netlogon_ops_args(struct dcerpc_pipe *p, struct torture_context status = cli_credentials_get_ntlm_response(cmdline_credentials, tctx, &flags, chal, + NULL, /* server_timestamp */ names_blob, &lm_resp, &nt_resp, NULL, NULL); @@ -2454,7 +2498,7 @@ static bool test_LogonControl2Ex(struct torture_context *tctx, } static bool test_netr_GetForestTrustInformation(struct torture_context *tctx, - struct dcerpc_pipe *p, + struct dcerpc_pipe *p1, struct cli_credentials *machine_credentials) { struct netr_GetForestTrustInformation r; @@ -2462,12 +2506,18 @@ static bool test_netr_GetForestTrustInformation(struct torture_context *tctx, struct netr_Authenticator a; struct netr_Authenticator return_authenticator; struct lsa_ForestTrustInformation *forest_trust_info; - struct dcerpc_binding_handle *b = p->binding_handle; + struct dcerpc_pipe *p = NULL; + struct dcerpc_binding_handle *b = NULL; - if (!test_SetupCredentials3(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, + if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, machine_credentials, &creds)) { return false; } + if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds, + DCERPC_SIGN | DCERPC_SEAL, &p)) { + return false; + } + b = p->binding_handle; netlogon_creds_client_authenticator(creds, &a); @@ -3290,7 +3340,7 @@ static bool test_netr_DsRAddressToSitenamesExW(struct torture_context *tctx, } static bool test_netr_ServerGetTrustInfo_flags(struct torture_context *tctx, - struct dcerpc_pipe *p, + struct dcerpc_pipe *p1, struct cli_credentials *machine_credentials, uint32_t negotiate_flags) { @@ -3303,14 +3353,20 @@ static bool test_netr_ServerGetTrustInfo_flags(struct torture_context *tctx, struct netr_TrustInfo *trust_info; struct netlogon_creds_CredentialState *creds; - struct dcerpc_binding_handle *b = p->binding_handle; + struct dcerpc_pipe *p = NULL; + struct dcerpc_binding_handle *b = NULL; struct samr_Password nt_hash; - if (!test_SetupCredentials3(p, tctx, negotiate_flags, + if (!test_SetupCredentials3(p1, tctx, negotiate_flags, machine_credentials, &creds)) { return false; } + if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds, + DCERPC_SIGN | DCERPC_SEAL, &p)) { + return false; + } + b = p->binding_handle; netlogon_creds_client_authenticator(creds, &a); @@ -3360,7 +3416,7 @@ static bool test_netr_ServerGetTrustInfo_AES(struct torture_context *tctx, } static bool test_GetDomainInfo(struct torture_context *tctx, - struct dcerpc_pipe *p, + struct dcerpc_pipe *p1, struct cli_credentials *machine_credentials) { struct netr_LogonGetDomainInfo r; @@ -3383,14 +3439,20 @@ static bool test_GetDomainInfo(struct torture_context *tctx, char **spns = NULL; int num_spns = 0; char *temp_str; - struct dcerpc_binding_handle *b = p->binding_handle; + struct dcerpc_pipe *p = NULL; + struct dcerpc_binding_handle *b = NULL; torture_comment(tctx, "Testing netr_LogonGetDomainInfo\n"); - if (!test_SetupCredentials3(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, + if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, machine_credentials, &creds)) { return false; } + if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds, + DCERPC_SIGN | DCERPC_SEAL, &p)) { + return false; + } + b = p->binding_handle; /* We won't double-check this when we are over 'local' transports */ if (dcerpc_server_name(p)) { @@ -3815,7 +3877,7 @@ static bool test_GetDomainInfo(struct torture_context *tctx, } static bool test_GetDomainInfo_async(struct torture_context *tctx, - struct dcerpc_pipe *p, + struct dcerpc_pipe *p1, struct cli_credentials *machine_credentials) { NTSTATUS status; @@ -3829,6 +3891,7 @@ static bool test_GetDomainInfo_async(struct torture_context *tctx, int i; union netr_WorkstationInfo query; union netr_DomainInfo info; + struct dcerpc_pipe *p = NULL; torture_comment(tctx, "Testing netr_LogonGetDomainInfo - async count %d\n", ASYNC_COUNT); @@ -3836,6 +3899,10 @@ static bool test_GetDomainInfo_async(struct torture_context *tctx, machine_credentials, &creds)) { return false; } + if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds, + DCERPC_SIGN | DCERPC_SEAL, &p)) { + return false; + } ZERO_STRUCT(r); r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); @@ -3907,7 +3974,7 @@ static bool test_ManyGetDCName(struct torture_context *tctx, int i; if (p->conn->transport.transport != NCACN_NP) { - return true; + torture_skip(tctx, "test_ManyGetDCName works only with NCACN_NP"); } torture_comment(tctx, "Torturing GetDCName\n"); diff --git a/source4/torture/rpc/netlogon.h b/source4/torture/rpc/netlogon.h index f2f2a6f9c95..a4ab8f00ce0 100644 --- a/source4/torture/rpc/netlogon.h +++ b/source4/torture/rpc/netlogon.h @@ -28,3 +28,10 @@ bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx, uint32_t negotiate_flags, struct cli_credentials *machine_credentials, struct netlogon_creds_CredentialState **creds_out); + +bool test_SetupCredentialsPipe(const struct dcerpc_pipe *p1, + struct torture_context *tctx, + struct cli_credentials *machine_credentials, + struct netlogon_creds_CredentialState *creds, + uint32_t additional_flags, + struct dcerpc_pipe **_p2); diff --git a/source4/torture/rpc/remote_pac.c b/source4/torture/rpc/remote_pac.c index 7ea123b8bda..aaf08e04713 100644 --- a/source4/torture/rpc/remote_pac.c +++ b/source4/torture/rpc/remote_pac.c @@ -118,7 +118,7 @@ static NTSTATUS test_generate_session_info_pac(struct auth4_context *auth_ctx, /* Also happens to be a really good one-step verfication of our Kerberos stack */ static bool test_PACVerify(struct torture_context *tctx, - struct dcerpc_pipe *p, + struct dcerpc_pipe *p1, struct cli_credentials *credentials, enum netr_SchannelType secure_channel_type, const char *test_machine_name, @@ -139,6 +139,8 @@ static bool test_PACVerify(struct torture_context *tctx, struct netlogon_creds_CredentialState *creds; struct gensec_security *gensec_client_context; struct gensec_security *gensec_server_context; + struct cli_credentials *client_creds; + struct cli_credentials *server_creds; DATA_BLOB client_to_server, server_to_client, pac_wrapped, payload; struct PAC_Validate pac_wrapped_struct; @@ -149,7 +151,8 @@ static bool test_PACVerify(struct torture_context *tctx, struct auth_session_info *session_info; struct pac_data *pac_data; - struct dcerpc_binding_handle *b = p->binding_handle; + struct dcerpc_pipe *p = NULL; + struct dcerpc_binding_handle *b = NULL; TALLOC_CTX *tmp_ctx = talloc_new(tctx); torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed"); @@ -157,11 +160,32 @@ static bool test_PACVerify(struct torture_context *tctx, "Testing PAC Verify (secure_channel_type: %d, machine: %s, negotiate_flags: 0x%08x\n", secure_channel_type, test_machine_name, negotiate_flags); - if (!test_SetupCredentials2(p, tctx, negotiate_flags, - credentials, secure_channel_type, + /* + * Copy the credentials in order to use a different MEMORY krb5 ccache + * for each client/server setup. The MEMORY cache identifier is a + * pointer to the creds container. If we copy it the pointer changes and + * we will get a new clean memory cache. + */ + client_creds = cli_credentials_shallow_copy(tmp_ctx, + cmdline_credentials); + torture_assert(tctx, client_creds, "Failed to copy of credentials"); + /* Invalidate the gss creds container to allocate a new MEMORY ccache */ + cli_credentials_invalidate_ccache(client_creds, CRED_SPECIFIED); + + server_creds = cli_credentials_shallow_copy(tmp_ctx, + credentials); + torture_assert(tctx, server_creds, "Failed to copy of credentials"); + + if (!test_SetupCredentials2(p1, tctx, negotiate_flags, + server_creds, secure_channel_type, &creds)) { return false; } + if (!test_SetupCredentialsPipe(p1, tctx, server_creds, creds, + DCERPC_SIGN | DCERPC_SEAL, &p)) { + return false; + } + b = p->binding_handle; auth_context = talloc_zero(tmp_ctx, struct auth4_context); torture_assert(tctx, auth_context != NULL, "talloc_new() failed"); @@ -174,7 +198,7 @@ static bool test_PACVerify(struct torture_context *tctx, status = gensec_set_target_hostname(gensec_client_context, test_machine_name); - status = gensec_set_credentials(gensec_client_context, cmdline_credentials); + status = gensec_set_credentials(gensec_client_context, client_creds); torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed"); status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI"); @@ -185,7 +209,7 @@ static bool test_PACVerify(struct torture_context *tctx, auth_context, &gensec_server_context); torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed"); - status = gensec_set_credentials(gensec_server_context, credentials); + status = gensec_set_credentials(gensec_server_context, server_creds); torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed"); status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI"); @@ -269,7 +293,7 @@ static bool test_PACVerify(struct torture_context *tctx, r.in.logon = &logon; r.in.logon_level = NetlogonGenericInformation; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); - r.in.computer_name = cli_credentials_get_workstation(credentials); + r.in.computer_name = cli_credentials_get_workstation(server_creds); r.in.validation_level = NetlogonValidationGenericInfo2; r.out.validation = &validation; r.out.authoritative = &authoritative; @@ -292,7 +316,7 @@ static bool test_PACVerify(struct torture_context *tctx, r.in.logon_level = NetlogonGenericInformation; r.in.logon = &logon; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); - r.in.computer_name = cli_credentials_get_workstation(credentials); + r.in.computer_name = cli_credentials_get_workstation(server_creds); r.in.validation_level = NetlogonValidationGenericInfo2; torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r), @@ -315,7 +339,7 @@ static bool test_PACVerify(struct torture_context *tctx, r.in.logon_level = NetlogonGenericInformation; r.in.logon = &logon; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); - r.in.computer_name = cli_credentials_get_workstation(credentials); + r.in.computer_name = cli_credentials_get_workstation(server_creds); r.in.validation_level = NetlogonValidationGenericInfo2; torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r), @@ -368,7 +392,7 @@ static bool test_PACVerify(struct torture_context *tctx, r.in.logon_level = NetlogonGenericInformation; r.in.logon = &logon; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); - r.in.computer_name = cli_credentials_get_workstation(credentials); + r.in.computer_name = cli_credentials_get_workstation(server_creds); r.in.validation_level = NetlogonValidationGenericInfo2; torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r), @@ -420,7 +444,7 @@ static bool test_PACVerify(struct torture_context *tctx, r.in.logon_level = NetlogonGenericInformation; r.in.logon = &logon; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); - r.in.computer_name = cli_credentials_get_workstation(credentials); + r.in.computer_name = cli_credentials_get_workstation(server_creds); r.in.validation_level = NetlogonValidationGenericInfo2; torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r), @@ -431,6 +455,8 @@ static bool test_PACVerify(struct torture_context *tctx, torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred), "Credential chaining failed"); + talloc_free(tmp_ctx); + return true; } @@ -505,14 +531,15 @@ static bool test_PACVerify_workstation_des(struct torture_context *tctx, /* Check various ways to get the PAC, in particular check the group membership and other details between the PAC from a normal kinit, S2U4Self and a SamLogon */ static bool test_S2U4Self(struct torture_context *tctx, - struct dcerpc_pipe *p, + struct dcerpc_pipe *p1, struct cli_credentials *credentials, enum netr_SchannelType secure_channel_type, const char *test_machine_name, uint32_t negotiate_flags) { NTSTATUS status; - struct dcerpc_binding_handle *b = p->binding_handle; + struct dcerpc_pipe *p = NULL; + struct dcerpc_binding_handle *b = NULL; struct netr_LogonSamLogon r; @@ -527,6 +554,8 @@ static bool test_S2U4Self(struct torture_context *tctx, struct netlogon_creds_CredentialState *creds; struct gensec_security *gensec_client_context; struct gensec_security *gensec_server_context; + struct cli_credentials *client_creds; + struct cli_credentials *server_creds; struct auth4_context *auth_context; struct auth_session_info *kinit_session_info; @@ -548,6 +577,31 @@ static bool test_S2U4Self(struct torture_context *tctx, "Testing S4U2SELF (secure_channel_type: %d, machine: %s, negotiate_flags: 0x%08x\n", secure_channel_type, test_machine_name, negotiate_flags); + /* + * Copy the credentials in order to use a different MEMORY krb5 ccache + * for each client/server setup. The MEMORY cache identifier is a + * pointer to the creds container. If we copy it the pointer changes and + * we will get a new clean memory cache. + */ + client_creds = cli_credentials_shallow_copy(tmp_ctx, + cmdline_credentials); + torture_assert(tctx, client_creds, "Failed to copy of credentials"); + + server_creds = cli_credentials_shallow_copy(tmp_ctx, + credentials); + torture_assert(tctx, server_creds, "Failed to copy of credentials"); + + if (!test_SetupCredentials2(p1, tctx, negotiate_flags, + server_creds, secure_channel_type, + &creds)) { + return false; + } + if (!test_SetupCredentialsPipe(p1, tctx, server_creds, creds, + DCERPC_SIGN | DCERPC_SEAL, &p)) { + return false; + } + b = p->binding_handle; + auth_context = talloc_zero(tmp_ctx, struct auth4_context); torture_assert(tctx, auth_context != NULL, "talloc_new() failed"); @@ -561,7 +615,7 @@ static bool test_S2U4Self(struct torture_context *tctx, status = gensec_set_target_hostname(gensec_client_context, test_machine_name); - status = gensec_set_credentials(gensec_client_context, cmdline_credentials); + status = gensec_set_credentials(gensec_client_context, client_creds); torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed"); status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI"); @@ -572,7 +626,7 @@ static bool test_S2U4Self(struct torture_context *tctx, auth_context, &gensec_server_context); torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed"); - status = gensec_set_credentials(gensec_server_context, credentials); + status = gensec_set_credentials(gensec_server_context, server_creds); torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed"); status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI"); @@ -606,9 +660,10 @@ static bool test_S2U4Self(struct torture_context *tctx, /* Now do the dance with S2U4Self */ /* Wipe out any existing ccache */ - cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); - cli_credentials_set_impersonate_principal(credentials, - cli_credentials_get_principal(cmdline_credentials, tmp_ctx), + cli_credentials_invalidate_ccache(client_creds, CRED_SPECIFIED); + cli_credentials_invalidate_ccache(server_creds, CRED_SPECIFIED); + cli_credentials_set_impersonate_principal(server_creds, + cli_credentials_get_principal(client_creds, tmp_ctx), talloc_asprintf(tmp_ctx, "host/%s", test_machine_name)); status = gensec_client_start(tctx, &gensec_client_context, @@ -618,7 +673,7 @@ static bool test_S2U4Self(struct torture_context *tctx, status = gensec_set_target_hostname(gensec_client_context, test_machine_name); /* We now set the same credentials on both client and server contexts */ - status = gensec_set_credentials(gensec_client_context, credentials); + status = gensec_set_credentials(gensec_client_context, server_creds); torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed"); status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI"); @@ -629,7 +684,7 @@ static bool test_S2U4Self(struct torture_context *tctx, auth_context, &gensec_server_context); torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed"); - status = gensec_set_credentials(gensec_server_context, credentials); + status = gensec_set_credentials(gensec_server_context, server_creds); torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed"); status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI"); @@ -655,16 +710,16 @@ static bool test_S2U4Self(struct torture_context *tctx, } while (1); /* Don't pollute the remaining tests with the changed credentials */ - cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); - cli_credentials_set_target_service(credentials, NULL); - cli_credentials_set_impersonate_principal(credentials, NULL, NULL); + cli_credentials_invalidate_ccache(server_creds, CRED_SPECIFIED); + cli_credentials_set_target_service(server_creds, NULL); + cli_credentials_set_impersonate_principal(server_creds, NULL, NULL); /* Extract the PAC using Samba's code */ status = gensec_session_info(gensec_server_context, gensec_server_context, &s2u4self_session_info); torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed"); - cli_credentials_get_ntlm_username_domain(cmdline_credentials, tctx, + cli_credentials_get_ntlm_username_domain(client_creds, tctx, &ninfo.identity_info.account_name.string, &ninfo.identity_info.domain_name.string); @@ -674,12 +729,13 @@ static bool test_S2U4Self(struct torture_context *tctx, chal = data_blob_const(ninfo.challenge, sizeof(ninfo.challenge)); - names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(credentials), - cli_credentials_get_domain(credentials)); + names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(server_creds), + cli_credentials_get_domain(server_creds)); - status = cli_credentials_get_ntlm_response(cmdline_credentials, tctx, + status = cli_credentials_get_ntlm_response(client_creds, tctx, &flags, chal, + NULL, /* server_timestamp */ names_blob, &lm_resp, &nt_resp, NULL, NULL); @@ -694,12 +750,12 @@ static bool test_S2U4Self(struct torture_context *tctx, ninfo.identity_info.parameter_control = 0; ninfo.identity_info.logon_id_low = 0; ninfo.identity_info.logon_id_high = 0; - ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials); + ninfo.identity_info.workstation.string = cli_credentials_get_workstation(server_creds); logon.network = &ninfo; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); - r.in.computer_name = cli_credentials_get_workstation(credentials); + r.in.computer_name = cli_credentials_get_workstation(server_creds); r.in.credential = &auth; r.in.return_authenticator = &auth2; r.in.logon_level = NetlogonNetworkInformation; @@ -707,12 +763,6 @@ static bool test_S2U4Self(struct torture_context *tctx, r.out.validation = &validation; r.out.authoritative = &authoritative; - if (!test_SetupCredentials2(p, tctx, negotiate_flags, - credentials, secure_channel_type, - &creds)) { - return false; - } - ZERO_STRUCT(auth2); netlogon_creds_client_authenticator(creds, &auth); @@ -797,7 +847,6 @@ struct torture_suite *torture_rpc_remote_pac(TALLOC_CTX *mem_ctx) struct torture_suite *suite = torture_suite_create(mem_ctx, "pac"); struct torture_rpc_tcase *tcase; - /* It is important to use different names, so that old entries in our credential cache are not used */ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netr-bdc-arcfour", &ndr_table_netlogon, TEST_MACHINE_NAME_BDC); torture_rpc_tcase_add_test_creds(tcase, "verify-sig-arcfour", test_PACVerify_bdc_arcfour); diff --git a/source4/torture/rpc/samba3rpc.c b/source4/torture/rpc/samba3rpc.c index ff1a53ca314..cec3aaad3ed 100644 --- a/source4/torture/rpc/samba3rpc.c +++ b/source4/torture/rpc/samba3rpc.c @@ -192,13 +192,19 @@ bool torture_bind_authcontext(struct torture_context *torture) if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { torture_comment(torture, "dcerpc_lsa_OpenPolicy2 with wrong vuid gave %s, " - "expected NT_STATUS_IO_DEVICE_ERROR\n", + "expected NT_STATUS_CONNECTION_DISCONNECTED\n", nt_errstr(status)); - status = NT_STATUS_IO_DEVICE_ERROR; + status = NT_STATUS_CONNECTION_DISCONNECTED; + } + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR)) { + torture_comment(torture, "dcerpc_lsa_OpenPolicy2 with wrong vuid gave %s, " + "expected NT_STATUS_CONNECTION_DISCONNECTED\n", + nt_errstr(status)); + status = NT_STATUS_CONNECTION_DISCONNECTED; } - torture_assert_ntstatus_equal(torture, status, NT_STATUS_IO_DEVICE_ERROR, - "lsa io device error"); + torture_assert_ntstatus_equal(torture, status, NT_STATUS_CONNECTION_DISCONNECTED, + "lsa connection disconnected"); smb1cli_session_set_id(tmp->smbXcli, tmp_vuid); cli->tree->session = tmp; @@ -1139,10 +1145,10 @@ static bool schan(struct torture_context *tctx, generate_random_buffer(chal.data, chal.length); names_blob = NTLMv2_generate_names_blob( mem_ctx, - cli_credentials_get_workstation(user_creds), - cli_credentials_get_domain(user_creds)); + cli_credentials_get_workstation(wks_creds), + cli_credentials_get_domain(wks_creds)); status = cli_credentials_get_ntlm_response( - user_creds, mem_ctx, &flags, chal, names_blob, + user_creds, mem_ctx, &flags, chal, NULL, names_blob, &lm_resp, &nt_resp, NULL, NULL); if (!NT_STATUS_IS_OK(status)) { torture_comment(tctx, "cli_credentials_get_ntlm_response failed:" @@ -1312,7 +1318,6 @@ static bool torture_netlogon_samba3(struct torture_context *torture) { NTSTATUS status; struct smbcli_state *cli; - struct cli_credentials *anon_creds; struct cli_credentials *wks_creds; const char *wks_name; int i; @@ -1324,10 +1329,6 @@ static bool torture_netlogon_samba3(struct torture_context *torture) wks_name = get_myname(torture); } - if (!(anon_creds = cli_credentials_init_anon(torture))) { - torture_fail(torture, "create_anon_creds failed\n"); - } - lpcfg_smbcli_options(torture->lp_ctx, &options); lpcfg_smbcli_session_options(torture->lp_ctx, &session_options); @@ -1336,7 +1337,7 @@ static bool torture_netlogon_samba3(struct torture_context *torture) lpcfg_smb_ports(torture->lp_ctx), "IPC$", NULL, lpcfg_socket_options(torture->lp_ctx), - anon_creds, + cmdline_credentials, lpcfg_resolve_context(torture->lp_ctx), torture->ev, &options, &session_options, lpcfg_gensec_settings(torture, torture->lp_ctx)); @@ -1356,7 +1357,7 @@ static bool torture_netlogon_samba3(struct torture_context *torture) CRED_SPECIFIED); torture_assert(torture, - join3(torture, cli, false, cmdline_credentials, wks_creds), + join3(torture, cli, false, NULL, wks_creds), "join failed"); cli_credentials_set_domain( @@ -1383,7 +1384,7 @@ static bool torture_netlogon_samba3(struct torture_context *torture) } torture_assert(torture, - leave(torture, cli, cmdline_credentials, wks_creds), + leave(torture, cli, NULL, wks_creds), "leave failed"); return true; @@ -1482,26 +1483,14 @@ static bool torture_samba3_sessionkey(struct torture_context *torture) } torture_assert(torture, - test_join3(torture, false, anon_creds, cmdline_credentials, wks_name), - "join using ntlmssp bind on an anonymous smb connection failed"); - - torture_assert(torture, test_join3(torture, false, cmdline_credentials, NULL, wks_name), "join using anonymous bind on an authenticated smb connection failed"); - torture_assert(torture, - test_join3(torture, false, cmdline_credentials, cmdline_credentials, wks_name), - "join using ntlmssp bind on an authenticated smb connection failed"); - /* * The following two are tests for setuserinfolevel 25 */ torture_assert(torture, - test_join3(torture, true, anon_creds, cmdline_credentials, wks_name), - "join using ntlmssp bind on an anonymous smb connection failed"); - - torture_assert(torture, test_join3(torture, true, cmdline_credentials, NULL, wks_name), "join using anonymous bind on an authenticated smb connection failed"); @@ -1786,20 +1775,6 @@ static bool torture_samba3_rpc_getusername(struct torture_context *torture) lpcfg_smbcli_options(torture->lp_ctx, &options); lpcfg_smbcli_session_options(torture->lp_ctx, &session_options); - status = smbcli_full_connection( - torture, &cli, torture_setting_string(torture, "host", NULL), - lpcfg_smb_ports(torture->lp_ctx), - "IPC$", NULL, lpcfg_socket_options(torture->lp_ctx), cmdline_credentials, - lpcfg_resolve_context(torture->lp_ctx), torture->ev, &options, - &session_options, lpcfg_gensec_settings(torture, torture->lp_ctx)); - torture_assert_ntstatus_ok(torture, status, "smbcli_full_connection failed\n"); - - if (!(user_sid = whoami(torture, torture, cli->tree))) { - torture_fail(torture, "whoami on auth'ed connection failed\n"); - } - - talloc_free(cli); - if (!(anon_creds = cli_credentials_init_anon(torture))) { torture_fail(torture, "create_anon_creds failed\n"); } @@ -1820,6 +1795,20 @@ static bool torture_samba3_rpc_getusername(struct torture_context *torture) torture_assert_sid_equal(torture, user_sid, dom_sid_parse_talloc(torture, "s-1-5-7"), "Anon lsa_GetUserName returned unexpected SID"); + talloc_free(cli); + + status = smbcli_full_connection( + torture, &cli, torture_setting_string(torture, "host", NULL), + lpcfg_smb_ports(torture->lp_ctx), + "IPC$", NULL, lpcfg_socket_options(torture->lp_ctx), cmdline_credentials, + lpcfg_resolve_context(torture->lp_ctx), torture->ev, &options, + &session_options, lpcfg_gensec_settings(torture, torture->lp_ctx)); + torture_assert_ntstatus_ok(torture, status, "smbcli_full_connection failed\n"); + + if (!(user_sid = whoami(torture, torture, cli->tree))) { + torture_fail(torture, "whoami on auth'ed connection failed\n"); + } + if (!(user_creds = cli_credentials_init(torture))) { torture_fail(torture, "cli_credentials_init failed\n"); } @@ -1831,7 +1820,7 @@ static bool torture_samba3_rpc_getusername(struct torture_context *torture) generate_random_password(user_creds, 8, 255), CRED_SPECIFIED); - if (!create_user(torture, torture, cli, cmdline_credentials, + if (!create_user(torture, torture, cli, NULL, cli_credentials_get_username(user_creds), cli_credentials_get_password(user_creds), &domain_name, &created_sid)) { @@ -1886,7 +1875,7 @@ static bool torture_samba3_rpc_getusername(struct torture_context *torture) del: if (!delete_user(torture, cli, - cmdline_credentials, + NULL, cli_credentials_get_username(user_creds))) { torture_fail(torture, "delete_user failed\n"); } diff --git a/source4/torture/rpc/samlogon.c b/source4/torture/rpc/samlogon.c index 3c5398d8c8e..bfa8b639c3d 100644 --- a/source4/torture/rpc/samlogon.c +++ b/source4/torture/rpc/samlogon.c @@ -1754,7 +1754,8 @@ bool torture_rpc_samlogon(struct torture_context *torture) * with INTERNAL_ERROR */ status = dcerpc_binding_set_flags(b, - DCERPC_SCHANNEL | DCERPC_SIGN | + DCERPC_SCHANNEL | + DCERPC_SIGN | DCERPC_SEAL | DCERPC_SCHANNEL_128, DCERPC_AUTH_OPTIONS); torture_assert_ntstatus_ok(torture, status, "set flags"); diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c index 293b6722cc2..dcdbb8ad550 100644 --- a/source4/torture/rpc/samr.c +++ b/source4/torture/rpc/samr.c @@ -3096,6 +3096,7 @@ static bool test_SamLogon(struct torture_context *tctx, status = cli_credentials_get_ntlm_response(test_credentials, tctx, &flags, chal, + NULL, /* server_timestamp */ names_blob, &lm_resp, &nt_resp, NULL, NULL); @@ -3257,7 +3258,8 @@ static bool setup_schannel_netlogon_pipe(struct torture_context *tctx, * with INTERNAL_ERROR */ status = dcerpc_binding_set_flags(b, - DCERPC_SCHANNEL | DCERPC_SIGN | + DCERPC_SCHANNEL | + DCERPC_SIGN | DCERPC_SEAL | DCERPC_SCHANNEL_AUTO, DCERPC_AUTH_OPTIONS); torture_assert_ntstatus_ok(tctx, status, "set flags"); diff --git a/source4/torture/rpc/schannel.c b/source4/torture/rpc/schannel.c index de93fcad1a6..d5de134dcce 100644 --- a/source4/torture/rpc/schannel.c +++ b/source4/torture/rpc/schannel.c @@ -62,6 +62,7 @@ bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx, struct netr_SamBaseInfo *base; const char *crypto_alg = ""; bool can_do_validation_6 = true; + enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; if (lpcfg_client_lanman_auth(tctx->lp_ctx)) { flags |= CLI_CRED_LANMAN_AUTH; @@ -86,6 +87,7 @@ bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx, status = cli_credentials_get_ntlm_response(cmdline_credentials, tctx, &flags, chal, + NULL, /* server_timestamp */ names_blob, &lm_resp, &nt_resp, NULL, NULL); @@ -131,16 +133,26 @@ bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx, } } - r.in.validation_level = 6; + dcerpc_binding_handle_auth_info(b, NULL, &auth_level); + if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + r.in.validation_level = 6; - torture_comment(tctx, - "Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n", - ninfo.identity_info.account_name.string, crypto_alg, - r.in.validation_level); + torture_comment(tctx, + "Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n", + ninfo.identity_info.account_name.string, crypto_alg, + r.in.validation_level); + + torture_assert_ntstatus_ok(tctx, + dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r), + "LogonSamLogonEx failed"); + } else { + torture_comment(tctx, + "Skip auth_level[%u] Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n", + auth_level, ninfo.identity_info.account_name.string, crypto_alg, + r.in.validation_level); + r.out.result = NT_STATUS_INVALID_INFO_CLASS; + } - torture_assert_ntstatus_ok(tctx, - dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r), - "LogonSamLogonEx failed"); if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_INFO_CLASS)) { can_do_validation_6 = false; } else { @@ -741,6 +753,7 @@ static bool torture_schannel_bench_start(struct torture_schannel_bench_conn *con status = cli_credentials_get_ntlm_response(user_creds, conn->tmp, &flags, chal, + NULL, /* server_timestamp */ names_blob, &lm_resp, &nt_resp, NULL, NULL); diff --git a/source4/torture/rpc/testjoin.c b/source4/torture/rpc/testjoin.c index 5ee2c2ac9f9..7fbf301b6ca 100644 --- a/source4/torture/rpc/testjoin.c +++ b/source4/torture/rpc/testjoin.c @@ -503,10 +503,36 @@ _PUBLIC_ struct test_join *torture_join_domain(struct torture_context *tctx, struct test_join *tj; struct samr_SetUserInfo s; union samr_UserInfo u; - + const char *binding_str = NULL; + struct dcerpc_binding *binding = NULL; + enum dcerpc_transport_t transport; + tj = talloc_zero(tctx, struct test_join); if (!tj) return NULL; + binding_str = torture_setting_string(tctx, "binding", NULL); + if (binding_str == NULL) { + const char *host = torture_setting_string(tctx, "host", NULL); + binding_str = talloc_asprintf(tj, "ncacn_np:%s", host); + } + status = dcerpc_parse_binding(tj, binding_str, &binding); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("dcerpc_parse_binding(%s) failed - %s\n", + binding_str, nt_errstr(status))); + talloc_free(tj); + return NULL; + } + transport = dcerpc_binding_get_transport(binding); + switch (transport) { + case NCALRPC: + case NCACN_UNIX_STREAM: + break; + default: + dcerpc_binding_set_transport(binding, NCACN_NP); + dcerpc_binding_set_flags(binding, 0, DCERPC_AUTH_OPTIONS); + break; + } + libnet_r = talloc_zero(tj, struct libnet_JoinDomain); if (!libnet_r) { talloc_free(tj); @@ -522,9 +548,10 @@ _PUBLIC_ struct test_join *torture_join_domain(struct torture_context *tctx, tj->libnet_r = libnet_r; libnet_ctx->cred = cmdline_credentials; - libnet_r->in.binding = torture_setting_string(tctx, "binding", NULL); - if (!libnet_r->in.binding) { - libnet_r->in.binding = talloc_asprintf(libnet_r, "ncacn_np:%s", torture_setting_string(tctx, "host", NULL)); + libnet_r->in.binding = dcerpc_binding_string(libnet_r, binding); + if (libnet_r->in.binding == NULL) { + talloc_free(tj); + return NULL; } libnet_r->in.level = LIBNET_JOINDOMAIN_SPECIFIED; libnet_r->in.netbios_name = machine_name; diff --git a/source4/winbind/wb_pam_auth.c b/source4/winbind/wb_pam_auth.c index c84b51f4fe9..bb9cf42d772 100644 --- a/source4/winbind/wb_pam_auth.c +++ b/source4/winbind/wb_pam_auth.c @@ -250,7 +250,9 @@ struct composite_context *wb_cmd_pam_auth_send(TALLOC_CTX *mem_ctx, cli_credentials_get_domain(credentials)); status = cli_credentials_get_ntlm_response( - credentials, mem_ctx, &flags, chal, names_blob, + credentials, mem_ctx, &flags, chal, + NULL, /* server_timestamp */ + names_blob, &lm_resp, &nt_resp, NULL, NULL); if (!NT_STATUS_IS_OK(status)) { return NULL; diff --git a/source4/winbind/wb_samba3_cmd.c b/source4/winbind/wb_samba3_cmd.c index 9ec3c4b0ccd..2e6a2601ce5 100644 --- a/source4/winbind/wb_samba3_cmd.c +++ b/source4/winbind/wb_samba3_cmd.c @@ -643,8 +643,13 @@ NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call) chal.data = s3call->request->data.auth_crap.chal; chal.length = sizeof(s3call->request->data.auth_crap.chal); - nt_resp.data = (uint8_t *)s3call->request->data.auth_crap.nt_resp; - nt_resp.length = s3call->request->data.auth_crap.nt_resp_len; + if (s3call->request->flags & WBFLAG_BIG_NTLMV2_BLOB) { + nt_resp.data = (uint8_t *)s3call->request->extra_data.data; + nt_resp.length = s3call->request->extra_len; + } else { + nt_resp.data = (uint8_t *)s3call->request->data.auth_crap.nt_resp; + nt_resp.length = s3call->request->data.auth_crap.nt_resp_len; + } lm_resp.data = (uint8_t *)s3call->request->data.auth_crap.lm_resp; lm_resp.length = s3call->request->data.auth_crap.lm_resp_len; diff --git a/testprogs/blackbox/test_ldb.sh b/testprogs/blackbox/test_ldb.sh index 60bad44ebb9..394a7e88bf5 100755 --- a/testprogs/blackbox/test_ldb.sh +++ b/testprogs/blackbox/test_ldb.sh @@ -39,6 +39,9 @@ ldbsearch="$VALGRIND ldbsearch" check "RootDSE" $ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base DUMMY=x dnsHostName highestCommittedUSN || failed=`expr $failed + 1` check "RootDSE (full)" $ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base '(objectClass=*)' || failed=`expr $failed + 1` check "RootDSE (extended)" $ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base '(objectClass=*)' --extended-dn || failed=`expr $failed + 1` +if [ x$p = x"ldaps" ]; then + testit_expect_failure "RootDSE over SSLv3 should fail" $ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base DUMMY=x dnsHostName highestCommittedUSN --option='tlspriority=NONE:+VERS-SSL3.0:+MAC-ALL:+CIPHER-ALL:+RSA:+SIGN-ALL:+COMP-NULL' && failed=`expr $failed + 1` +fi echo "Getting defaultNamingContext" BASEDN=`$ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base DUMMY=x defaultNamingContext | grep defaultNamingContext | awk '{print $2}'` diff --git a/testprogs/blackbox/test_ldb_simple.sh b/testprogs/blackbox/test_ldb_simple.sh new file mode 100755 index 00000000000..7375cbfd843 --- /dev/null +++ b/testprogs/blackbox/test_ldb_simple.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +if [ $# -lt 2 ]; then +cat <<EOF +Usage: test_ldb_simple.sh PROTOCOL SERVER [OPTIONS] +EOF +exit 1; +fi + + +p=$1 +SERVER=$2 +PREFIX=$3 +shift 2 +options="$*" + +. `dirname $0`/subunit.sh + +check() { + name="$1" + shift + cmdline="$*" + echo "test: $name" + $cmdline + status=$? + if [ x$status = x0 ]; then + echo "success: $name" + else + echo "failure: $name" + failed=`expr $failed + 1` + fi + return $status +} + +export PATH="$BINDIR:$PATH" + +ldbsearch="$VALGRIND ldbsearch" + +check "currentTime" $ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base currentTime || failed=`expr $failed + 1` + +exit $failed diff --git a/testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.idl b/testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.idl new file mode 100644 index 00000000000..73aeb16d379 --- /dev/null +++ b/testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.idl @@ -0,0 +1,64 @@ +#ifndef MIDLTESTS_C_CODE + +/* + * For midltests_tcp.exe you may want to + * redirect the traffic via rinetd + * with a /etc/rinetd.conf like this: + * + * 172.31.9.1 5032 172.31.9.8 5032 + * 172.31.9.1 5064 172.31.9.8 5064 + * + * This is useful to watch the traffic with + * a network sniffer. + */ +/* +cpp_quote("#define LISTEN_IP \"0.0.0.0\"") +cpp_quote("#define FORWARD_IP \"127.0.0.1\"") +cpp_quote("#define CONNECT_IP \"172.31.9.1\"") +*/ + +/* + * With midltests_tcp.exe NDR64 is enforced by default. + * For testing it might be needed to allow downgrades + * to NDR32. This is needed when you use 'pipe'. + */ +//cpp_quote("#define DONOT_FORCE_NDR64 1") + +[ + uuid("225b9fcb-eb3d-497b-8b0b-591f049a2507"), + pointer_default(unique) +] +interface midltests +{ + + typedef struct { + [range(1,10000)] long cb; + [size_is(cb)] char rcg[]; + } DRS_EXTENSIONS; + + long midltests_fn( + [out] DRS_EXTENSIONS **e + ); +} + +#elif MIDLTESTS_C_CODE + +static void midltests(void) +{ + DRS_EXTENSIONS *e = NULL; + cli_midltests_fn(&e); +} + +long srv_midltests_fn(DRS_EXTENSIONS **_e) +{ + DRS_EXTENSIONS *e; + printf("srv_midltests_fn: Start\n"); + e = (DRS_EXTENSIONS *)malloc(sizeof(DRS_EXTENSIONS) + 0x34); + e->cb = 0x34; + memset(e->rcg, 0xcd, e->cb); + *_e = e; + printf("srv_midltests_fn: End\n"); + return 0x65757254; +} + +#endif diff --git a/testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.out b/testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.out new file mode 100644 index 00000000000..e0b3a0ee338 --- /dev/null +++ b/testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.out @@ -0,0 +1,43 @@ +Wait for setup of server threads + +Test NDR32 + +ndr32: disable NDR64 + +ndr32:in => out: ptype[request] flen[24] plen[0] ahint[0] + + +srv_midltests_fn: Start +srv_midltests_fn: End + +ndr32:out => in: ptype[response] flen[92] plen[68] ahint[68] + +[000] 00 00 02 00 34 00 00 00 34 00 00 00 CD CD CD CD ....4... 4....... +[010] CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ +[020] CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ +[030] CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ +[040] 54 72 75 65 True + +NDRTcpThread[ndr32] stop + +Test NDR64 + +ndr64: got NDR64 + +ndr64:in => out: ptype[request] flen[24] plen[0] ahint[0] + + +srv_midltests_fn: Start +srv_midltests_fn: End + +ndr64:out => in: ptype[response] flen[100] plen[76] ahint[76] + +[000] 00 00 02 00 00 00 00 00 34 00 00 00 00 00 00 00 ........ 4....... +[010] 34 00 00 00 CD CD CD CD CD CD CD CD CD CD CD CD 4....... ........ +[020] CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ +[030] CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ +[040] CD CD CD CD CD CD CD CD 54 72 75 65 ........ True + +NDRTcpThread[ndr64] stop + +Test OK diff --git a/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5 index 0db55ce9ea4..4b50d60dd2d 100644 --- a/wscript_configure_system_mitkrb5 +++ b/wscript_configure_system_mitkrb5 @@ -55,7 +55,8 @@ conf.CHECK_FUNCS_IN('_et_list', 'com_err') conf.CHECK_HEADERS('com_err.h', lib='com_err') conf.CHECK_HEADERS('krb5.h krb5/locate_plugin.h', lib='krb5') -conf.CHECK_HEADERS('gssapi.h gssapi/gssapi_generic.h gssapi/gssapi.h gssapi/gssapi_ext.h gssapi/gssapi_krb5.h', lib='gssapi') +possible_gssapi_headers="gssapi.h gssapi/gssapi_generic.h gssapi/gssapi.h gssapi/gssapi_ext.h gssapi/gssapi_krb5.h gssapi/gssapi_oid.h" +conf.CHECK_HEADERS(possible_gssapi_headers, lib='gssapi') conf.CHECK_FUNCS_IN('krb5_encrypt_data', 'k5crypto') conf.CHECK_FUNCS_IN('des_set_key','crypto') @@ -83,6 +84,7 @@ conf.CHECK_FUNCS_IN(''' gss_krb5_export_lucid_sec_context gss_import_cred gss_export_cred ''', 'gssapi gssapi_krb5') +conf.CHECK_VARIABLE('GSS_KRB5_CRED_NO_CI_FLAGS_X', headers=possible_gssapi_headers) conf.CHECK_FUNCS_IN('krb5_mk_req_extended krb5_kt_compare', 'krb5') conf.CHECK_FUNCS(''' krb5_set_default_in_tkt_etypes krb5_set_default_tgs_enctypes |