[Pkg-samba-maint] [samba] 02/08: Imported Upstream version 4.4.1+dfsg
Andrew Bartlett
abartlet-guest at moszumanska.debian.org
Tue Apr 12 22:03:51 UTC 2016
This is an automated email from the git hooks/post-receive script.
abartlet-guest pushed a commit to branch experimental
in repository samba.
commit 8dc2e9118e24b80a3dee8ccd20b0980ddf54df3a
Author: Andrew Bartlett <abartlet at samba.org>
Date: Wed Apr 6 17:48:18 2016 +1200
Imported Upstream version 4.4.1+dfsg
---
VERSION | 2 +-
WHATSNEW.txt | 524 ++++
auth/credentials/credentials.h | 5 +-
auth/credentials/credentials_ntlm.c | 12 +-
auth/gensec/gensec.c | 113 +-
auth/gensec/gensec.h | 4 +
auth/gensec/gensec_internal.h | 7 +
auth/gensec/gensec_start.c | 18 +-
auth/gensec/schannel.c | 22 +-
auth/gensec/spnego.c | 289 ++-
auth/ntlmssp/gensec_ntlmssp.c | 9 +
auth/ntlmssp/gensec_ntlmssp_server.c | 44 +-
auth/ntlmssp/ntlmssp.c | 91 +-
auth/ntlmssp/ntlmssp.h | 17 +
auth/ntlmssp/ntlmssp_client.c | 513 +++-
auth/ntlmssp/ntlmssp_ndr.c | 1 +
auth/ntlmssp/ntlmssp_private.h | 10 +-
auth/ntlmssp/ntlmssp_server.c | 424 +++-
auth/ntlmssp/ntlmssp_sign.c | 103 +-
auth/ntlmssp/ntlmssp_util.c | 176 +-
auth/ntlmssp/wscript_build | 2 +-
.../ldap/ldapserverrequirestrongauth.xml | 26 +
.../smbdotconf/protocol/clientipcmaxprotocol.xml | 29 +
.../smbdotconf/protocol/clientipcminprotocol.xml | 29 +
docs-xml/smbdotconf/protocol/clientmaxprotocol.xml | 9 +-
docs-xml/smbdotconf/protocol/clientminprotocol.xml | 6 +
docs-xml/smbdotconf/protocol/clientusespnego.xml | 5 +
.../security/allowdcerpcauthlevelconnect.xml | 27 +
docs-xml/smbdotconf/security/clientipcsigning.xml | 26 +
docs-xml/smbdotconf/security/clientntlmv2auth.xml | 5 +
docs-xml/smbdotconf/security/clientsigning.xml | 12 +-
docs-xml/smbdotconf/security/rawntlmv2auth.xml | 19 +
docs-xml/smbdotconf/security/serversigning.xml | 2 +-
docs-xml/smbdotconf/security/tlsverifypeer.xml | 47 +
docs/manpages/cifsdd.8 | 4 +-
docs/manpages/dbwrap_tool.1 | 4 +-
docs/manpages/eventlogadm.8 | 4 +-
docs/manpages/findsmb.1 | 4 +-
docs/manpages/idmap_ad.8 | 4 +-
docs/manpages/idmap_autorid.8 | 4 +-
docs/manpages/idmap_hash.8 | 4 +-
docs/manpages/idmap_ldap.8 | 4 +-
docs/manpages/idmap_nss.8 | 4 +-
docs/manpages/idmap_rfc2307.8 | 4 +-
docs/manpages/idmap_rid.8 | 4 +-
docs/manpages/idmap_script.8 | 4 +-
docs/manpages/idmap_tdb.8 | 4 +-
docs/manpages/idmap_tdb2.8 | 4 +-
docs/manpages/libsmbclient.7 | 4 +-
docs/manpages/lmhosts.5 | 4 +-
docs/manpages/log2pcap.1 | 4 +-
docs/manpages/net.8 | 4 +-
docs/manpages/nmbd.8 | 4 +-
docs/manpages/nmblookup.1 | 4 +-
docs/manpages/ntlm_auth.1 | 4 +-
docs/manpages/pam_winbind.8 | 4 +-
docs/manpages/pam_winbind.conf.5 | 4 +-
docs/manpages/pdbedit.8 | 4 +-
docs/manpages/profiles.1 | 4 +-
docs/manpages/rpcclient.1 | 4 +-
docs/manpages/samba-regedit.8 | 4 +-
docs/manpages/samba-tool.8 | 4 +-
docs/manpages/samba.7 | 4 +-
docs/manpages/samba.8 | 4 +-
docs/manpages/sharesec.1 | 4 +-
docs/manpages/smb.conf.5 | 227 +-
docs/manpages/smbcacls.1 | 4 +-
docs/manpages/smbclient.1 | 4 +-
docs/manpages/smbcontrol.1 | 4 +-
docs/manpages/smbcquotas.1 | 4 +-
docs/manpages/smbd.8 | 4 +-
docs/manpages/smbget.1 | 4 +-
docs/manpages/smbgetrc.5 | 4 +-
docs/manpages/smbpasswd.5 | 4 +-
docs/manpages/smbpasswd.8 | 4 +-
docs/manpages/smbspool.8 | 4 +-
docs/manpages/smbspool_krb5_wrapper.8 | 4 +-
docs/manpages/smbstatus.1 | 4 +-
docs/manpages/smbtar.1 | 4 +-
docs/manpages/smbtree.1 | 4 +-
docs/manpages/testparm.1 | 4 +-
docs/manpages/vfs_acl_tdb.8 | 4 +-
docs/manpages/vfs_acl_xattr.8 | 4 +-
docs/manpages/vfs_aio_fork.8 | 4 +-
docs/manpages/vfs_aio_linux.8 | 4 +-
docs/manpages/vfs_aio_pthread.8 | 4 +-
docs/manpages/vfs_audit.8 | 4 +-
docs/manpages/vfs_btrfs.8 | 4 +-
docs/manpages/vfs_cacheprime.8 | 4 +-
docs/manpages/vfs_cap.8 | 4 +-
docs/manpages/vfs_catia.8 | 4 +-
docs/manpages/vfs_ceph.8 | 4 +-
docs/manpages/vfs_commit.8 | 4 +-
docs/manpages/vfs_crossrename.8 | 4 +-
docs/manpages/vfs_default_quota.8 | 4 +-
docs/manpages/vfs_dirsort.8 | 4 +-
docs/manpages/vfs_extd_audit.8 | 4 +-
docs/manpages/vfs_fake_perms.8 | 4 +-
docs/manpages/vfs_fileid.8 | 4 +-
docs/manpages/vfs_fruit.8 | 4 +-
docs/manpages/vfs_full_audit.8 | 4 +-
docs/manpages/vfs_glusterfs.8 | 4 +-
docs/manpages/vfs_gpfs.8 | 4 +-
docs/manpages/vfs_linux_xfs_sgid.8 | 4 +-
docs/manpages/vfs_media_harmony.8 | 4 +-
docs/manpages/vfs_netatalk.8 | 4 +-
docs/manpages/vfs_offline.8 | 4 +-
docs/manpages/vfs_prealloc.8 | 4 +-
docs/manpages/vfs_preopen.8 | 4 +-
docs/manpages/vfs_readahead.8 | 4 +-
docs/manpages/vfs_readonly.8 | 4 +-
docs/manpages/vfs_recycle.8 | 4 +-
docs/manpages/vfs_shadow_copy.8 | 4 +-
docs/manpages/vfs_shadow_copy2.8 | 4 +-
docs/manpages/vfs_shell_snap.8 | 4 +-
docs/manpages/vfs_snapper.8 | 4 +-
docs/manpages/vfs_streams_depot.8 | 4 +-
docs/manpages/vfs_streams_xattr.8 | 4 +-
docs/manpages/vfs_syncops.8 | 4 +-
docs/manpages/vfs_time_audit.8 | 4 +-
docs/manpages/vfs_tsmsm.8 | 4 +-
docs/manpages/vfs_unityed_media.8 | 4 +-
docs/manpages/vfs_worm.8 | 4 +-
docs/manpages/vfs_xattr_tdb.8 | 4 +-
docs/manpages/vfs_zfsacl.8 | 4 +-
docs/manpages/vfstest.1 | 4 +-
docs/manpages/wbinfo.1 | 4 +-
docs/manpages/winbind_krb5_locator.7 | 4 +-
docs/manpages/winbindd.8 | 4 +-
lib/param/loadparm.c | 47 +-
lib/param/loadparm.h | 6 +
lib/param/param_table.c | 27 +
lib/util/util_net.c | 247 +-
lib/util/util_net.h | 1 +
libcli/auth/proto.h | 6 +
libcli/auth/smbencrypt.c | 170 +-
libcli/auth/spnego.h | 8 +-
libcli/auth/spnego_parse.c | 5 +-
libcli/smb/smbXcli_base.c | 1 +
libcli/smb/smb_constants.h | 1 +
libcli/smb/smb_signing.c | 4 +
libcli/smb/tstream_smbXcli_np.c | 4 +
librpc/idl/dcerpc.idl | 15 +-
librpc/idl/epmapper.idl | 2 +-
librpc/idl/ntlmssp.idl | 48 +-
librpc/idl/security.idl | 9 +
librpc/ndr/ndr_ntlmssp.c | 16 +
librpc/ndr/ndr_ntlmssp.h | 2 +
librpc/rpc/binding.c | 2 +-
librpc/rpc/dcerpc_error.c | 6 +-
librpc/rpc/dcerpc_util.c | 141 +-
librpc/rpc/rpc_common.h | 9 +-
nsswitch/libwbclient/wbc_pam.c | 21 +-
nsswitch/winbind_struct_protocol.h | 1 +
python/samba/tests/__init__.py | 525 ++++
python/samba/tests/dcerpc/dnsserver.py | 2 +-
python/samba/tests/dcerpc/raw_protocol.py | 2623 ++++++++++++++++++++
selftest/knownfail | 28 +
.../DC-addc.addom.samba.example.com-S02-cert.pem | 191 ++
.../DC-addc.addom.samba.example.com-S02-key.pem | 54 +
...DC-addc.addom.samba.example.com-S02-openssl.cnf | 250 ++
...ddc.addom.samba.example.com-S02-private-key.pem | 51 +
.../DC-addc.addom.samba.example.com-S02-req.pem | 30 +
.../DC-addc.addom.samba.example.com-cert.pem | 1 +
...DC-addc.addom.samba.example.com-private-key.pem | 1 +
.../DC-localdc.samba.example.com-S00-cert.pem | 190 ++
.../DC-localdc.samba.example.com-S00-key.pem | 54 +
.../DC-localdc.samba.example.com-S00-openssl.cnf | 250 ++
...C-localdc.samba.example.com-S00-private-key.pem | 51 +
.../DC-localdc.samba.example.com-S00-req.pem | 30 +
.../DC-localdc.samba.example.com-cert.pem | 1 +
.../DC-localdc.samba.example.com-private-key.pem | 1 +
.../manage-ca/CA-samba.example.com/NewCerts/00.pem | 190 ++
.../manage-ca/CA-samba.example.com/NewCerts/01.pem | 169 ++
.../manage-ca/CA-samba.example.com/NewCerts/02.pem | 191 ++
.../manage-ca/CA-samba.example.com/NewCerts/03.pem | 169 ++
.../Private/CA-samba.example.com-crlnumber.txt | 1 +
.../Private/CA-samba.example.com-crlnumber.txt.old | 1 +
.../Private/CA-samba.example.com-index.txt | 4 +
.../Private/CA-samba.example.com-index.txt.attr | 1 +
.../CA-samba.example.com-index.txt.attr.old | 1 +
.../Private/CA-samba.example.com-index.txt.old | 3 +
.../Private/CA-samba.example.com-openssl.cnf | 203 ++
.../Private/CA-samba.example.com-private-key.pem | 102 +
.../Private/CA-samba.example.com-serial.txt | 1 +
.../Private/CA-samba.example.com-serial.txt.old | 1 +
.../Public/CA-samba.example.com-cert.pem | 62 +
.../Public/CA-samba.example.com-crl.pem | 32 +
...inistrator at addom.samba.example.com-S03-cert.pem | 169 ++
...ministrator at addom.samba.example.com-S03-key.pem | 30 +
...strator at addom.samba.example.com-S03-openssl.cnf | 242 ++
...tor at addom.samba.example.com-S03-private-key.pem | 27 +
...ministrator at addom.samba.example.com-S03-req.pem | 19 +
...-administrator at addom.samba.example.com-cert.pem | 1 +
...strator at addom.samba.example.com-private-key.pem | 1 +
...ER-administrator at samba.example.com-S01-cert.pem | 169 ++
...SER-administrator at samba.example.com-S01-key.pem | 30 +
...administrator at samba.example.com-S01-openssl.cnf | 242 ++
...nistrator at samba.example.com-S01-private-key.pem | 27 +
...SER-administrator at samba.example.com-S01-req.pem | 19 +
.../USER-administrator at samba.example.com-cert.pem | 1 +
...administrator at samba.example.com-private-key.pem | 1 +
selftest/manage-ca/manage-CA-samba.example.com.cnf | 21 +
selftest/manage-ca/manage-CA-samba.example.com.sh | 18 +
selftest/manage-ca/manage-ca.sh | 387 +++
.../manage-CA-example.com.cnf | 17 +
.../openssl-BASE-template.cnf | 201 ++
.../manage-ca.templates.d/openssl-CA-template.cnf | 2 +
.../manage-ca.templates.d/openssl-DC-template.cnf | 49 +
.../openssl-USER-template.cnf | 41 +
selftest/selftest.pl | 40 +
selftest/target/Samba.pm | 105 +
selftest/target/Samba3.pm | 1 +
selftest/target/Samba4.pm | 232 +-
source3/auth/auth_domain.c | 2 +-
source3/auth/auth_samba4.c | 4 +-
source3/auth/auth_util.c | 15 +
source3/include/auth_generic.h | 7 +-
source3/include/proto.h | 48 +-
source3/lib/netapi/cm.c | 2 +-
source3/libads/ads_proto.h | 1 -
source3/libads/ldap.c | 134 -
source3/libads/sasl.c | 663 ++---
source3/libnet/libnet_join.c | 6 +-
source3/librpc/crypto/gse.c | 81 +-
source3/librpc/rpc/dcerpc.h | 10 +-
source3/librpc/rpc/dcerpc_helpers.c | 98 +-
source3/libsmb/auth_generic.c | 51 +-
source3/libsmb/cliconnect.c | 669 ++---
source3/libsmb/clientgen.c | 9 +
source3/libsmb/clispnego.c | 282 ---
source3/libsmb/ntlmssp.c | 765 ------
source3/libsmb/ntlmssp_wrap.c | 135 -
source3/libsmb/passchange.c | 7 +-
source3/param/loadparm.c | 43 +-
source3/rpc_client/cli_pipe.c | 314 ++-
source3/rpc_server/netlogon/srv_netlog_nt.c | 57 +-
source3/rpc_server/rpc_handles.c | 1 +
source3/rpc_server/rpc_ncacn_np.c | 3 +-
source3/rpc_server/rpc_pipes.h | 11 +
source3/rpc_server/rpc_server.c | 12 +
source3/rpc_server/samr/srv_samr_nt.c | 21 +-
source3/rpc_server/srv_pipe.c | 494 ++--
source3/rpcclient/rpcclient.c | 5 +-
source3/script/tests/test_ntlm_auth_s3.sh | 2 +
source3/script/tests/test_rpcclient_samlogon.sh | 11 +-
source3/script/tests/test_smbclient_auth.sh | 11 +
source3/selftest/tests.py | 7 +-
source3/smbd/negprot.c | 6 +-
source3/smbd/sesssetup.c | 4 +-
source3/smbd/smb2_negprot.c | 10 +-
source3/smbd/smb2_sesssetup.c | 3 +-
source3/torture/test_ntlm_auth.py | 553 +++--
source3/utils/net_ads.c | 2 +-
source3/utils/net_rpc.c | 2 +-
source3/utils/net_util.c | 2 +-
source3/utils/ntlm_auth.c | 803 +-----
source3/winbindd/winbindd_ccache_access.c | 44 +-
source3/winbindd/winbindd_cm.c | 6 +-
source3/wscript_build | 10 +-
source4/auth/gensec/pygensec.c | 83 +
source4/auth/ntlm/auth_util.c | 4 +-
source4/ldap_server/ldap_bind.c | 50 +-
source4/ldap_server/ldap_server.c | 6 +
source4/ldap_server/ldap_server.h | 2 +
source4/lib/tls/tls.h | 23 +
source4/lib/tls/tls_tstream.c | 249 ++
source4/lib/tls/tlscert.c | 18 +-
source4/lib/tls/wscript | 5 +
source4/libcli/cliconnect.c | 2 +-
source4/libcli/ldap/ldap_bind.c | 62 +-
source4/libcli/ldap/ldap_client.c | 9 +-
source4/libcli/raw/libcliraw.h | 1 +
source4/libcli/raw/rawnegotiate.c | 11 +-
source4/libcli/smb2/connect.c | 7 +-
source4/libcli/smb_composite/connect.c | 1 +
source4/libcli/smb_composite/sesssetup.c | 35 +-
source4/librpc/rpc/dcerpc.c | 351 ++-
source4/librpc/rpc/dcerpc.h | 14 +-
source4/librpc/rpc/dcerpc_auth.c | 93 +-
source4/librpc/rpc/dcerpc_connect.c | 22 +
source4/librpc/rpc/dcerpc_roh.c | 13 +-
source4/librpc/rpc/dcerpc_util.c | 22 +-
source4/param/loadparm.c | 3 +-
source4/rpc_server/backupkey/dcesrv_backupkey.c | 13 +-
.../backupkey/dcesrv_backupkey_heimdal.c | 12 +-
source4/rpc_server/common/reply.c | 49 +-
source4/rpc_server/dcerpc_server.c | 812 ++++--
source4/rpc_server/dcerpc_server.h | 57 +-
source4/rpc_server/dcesrv_auth.c | 261 +-
source4/rpc_server/dcesrv_mgmt.c | 8 +
source4/rpc_server/dnsserver/dcerpc_dnsserver.c | 8 +
source4/rpc_server/drsuapi/dcesrv_drsuapi.c | 8 +
source4/rpc_server/echo/rpc_echo.c | 7 +
source4/rpc_server/epmapper/rpc_epmapper.c | 8 +
source4/rpc_server/handles.c | 8 +-
source4/rpc_server/lsa/dcesrv_lsa.c | 8 +
source4/rpc_server/lsa/lsa_lookup.c | 12 +-
source4/rpc_server/netlogon/dcerpc_netlogon.c | 46 +-
source4/rpc_server/remote/dcesrv_remote.c | 8 +-
source4/rpc_server/samr/dcesrv_samr.c | 12 +
source4/rpc_server/samr/samr_password.c | 25 +-
source4/selftest/tests.py | 75 +-
source4/smb_server/smb/negprot.c | 6 +-
source4/smb_server/smb/sesssetup.c | 10 +
source4/smb_server/smb2/negprot.c | 7 +-
source4/smb_server/smb2/sesssetup.c | 8 -
source4/torture/basic/base.c | 20 +-
source4/torture/ndr/ntlmssp.c | 183 +-
source4/torture/raw/samba3misc.c | 7 +
source4/torture/rpc/backupkey.c | 19 +-
source4/torture/rpc/backupkey_heimdal.c | 19 +-
source4/torture/rpc/forest_trust.c | 12 +-
source4/torture/rpc/lsa.c | 14 +-
source4/torture/rpc/netlogon.c | 101 +-
source4/torture/rpc/netlogon.h | 7 +
source4/torture/rpc/remote_pac.c | 39 +-
source4/torture/rpc/samba3rpc.c | 61 +-
source4/torture/rpc/samlogon.c | 3 +-
source4/torture/rpc/samr.c | 4 +-
source4/torture/rpc/schannel.c | 29 +-
source4/torture/rpc/testjoin.c | 35 +-
testprogs/blackbox/test_ldb_simple.sh | 41 +
wscript_configure_system_mitkrb5 | 4 +-
324 files changed, 15218 insertions(+), 4946 deletions(-)
diff --git a/VERSION b/VERSION
index 437e544..417145e 100644
--- a/VERSION
+++ b/VERSION
@@ -25,7 +25,7 @@
########################################################
SAMBA_VERSION_MAJOR=4
SAMBA_VERSION_MINOR=4
-SAMBA_VERSION_RELEASE=0
+SAMBA_VERSION_RELEASE=1
########################################################
# If a official release has a serious bug #
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 396ce6e..a5ca748 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,3 +1,527 @@
+ =============================
+ Release Notes for Samba 4.4.1
+ 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.
+
+ 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.4.0:
+--------------------
+
+o Jeremy Allison <jra at samba.org>
+ * Bug 11344 - CVE-2015-5370: Multiple errors in DCE-RPC code.
+
+o Christian Ambach <ambi at samba.org>
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Ralph Boehme <slow at samba.org>
+ * Bug 11644 - CVE-2016-2112: The LDAP client and server don't enforce
+ integrity protection.
+
+o Günther Deschner <gd at samba.org>
+ * Bug 11749 - CVE-2016-2111: NETLOGON Spoofing Vulnerability.
+
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Volker Lendecke <vl at samba.org>
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Stefan Metzmacher <metze at 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.
+
+
+#######################################
+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 Announcements
=====================
diff --git a/auth/credentials/credentials.h b/auth/credentials/credentials.h
index fdedd63..3779ec0 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_ntlm.c b/auth/credentials/credentials_ntlm.c
index 4e12277..0abbb5c 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 9fd5f25..2a8bba8 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 d09813e..e8bd7b1 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
@@ -163,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 45a66f8..5535241 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,
@@ -110,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 */
@@ -119,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 be31697..4c43519 100644
--- a/auth/gensec/gensec_start.c
+++ b/auth/gensec/gensec_start.c
@@ -211,8 +211,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];
@@ -232,7 +234,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;
}
@@ -253,8 +261,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/schannel.c b/auth/gensec/schannel.c
index 9b28c45..8baf803 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) {
@@ -662,9 +672,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 079a2bc..2922478 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
@@ -416,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;
}
@@ -674,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;
}
@@ -700,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;
}
@@ -784,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 */
@@ -846,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;
@@ -883,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,
@@ -904,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,
@@ -917,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,
@@ -933,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;
}
@@ -955,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,
@@ -984,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)
@@ -1065,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 {
@@ -1265,6 +1430,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;
diff --git a/auth/ntlmssp/gensec_ntlmssp.c b/auth/ntlmssp/gensec_ntlmssp.c
index 5672589..329d8eb 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 03d539b..ca19863 100644
--- a/auth/ntlmssp/gensec_ntlmssp_server.c
+++ b/auth/ntlmssp/gensec_ntlmssp_server.c
@@ -34,9 +34,9 @@
#include "auth/gensec/gensec_internal.h"
#include "auth/common_auth.h"
#include "param/param.h"
+#include "param/loadparm.h"
#include "libds/common/roles.h"
-
/**
* Return the credentials of a logged on user, including session keys
* etc.
@@ -99,6 +99,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);
@@ -118,13 +121,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;
@@ -148,18 +170,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;
@@ -216,6 +251,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 916b376..4abab88 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 6061cd0..2412768 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 b22619b..b419615 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;
@@ -148,6 +245,12 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
NTSTATUS nt_status;
int flags = 0;
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,6 +360,7 @@ 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);
@@ -273,6 +381,97 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
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;
}
@@ -282,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;
}
@@ -309,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,
@@ -342,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,
@@ -356,20 +696,46 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
user,
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",
@@ -415,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)));
@@ -425,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;
}
@@ -454,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
@@ -464,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 af24be9..c8b16cc 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 778d638..e938e5c 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 2f3f0bb..17d5ade 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,194 @@ 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, false,
+ true, &tmp1),
+ timeval_str_buf(&st, false,
+ 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, false, 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 +752,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 +870,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 +984,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 c0be914..a975725 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 96793ab..4ae6101 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 8725a80..e28d4eb 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 0000000..02bdd81
--- /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 0000000..408af50
--- /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 0000000..fc04b78
--- /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 240ba1a..0131331 100644
--- a/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml
+++ b/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml
@@ -79,13 +79,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 ac0d460..fb8f87e 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 f5a3512..b2f3b12 100644
--- a/docs-xml/smbdotconf/protocol/clientusespnego.xml
+++ b/docs-xml/smbdotconf/protocol/clientusespnego.xml
@@ -8,6 +8,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 0000000..03531ad
--- /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 0000000..0881c6c
--- /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 531c8fc..f42f627 100644
--- a/docs-xml/smbdotconf/security/clientntlmv2auth.xml
+++ b/docs-xml/smbdotconf/security/clientntlmv2auth.xml
@@ -27,6 +27,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 2af5ada..8addf8a 100644
--- a/docs-xml/smbdotconf/security/clientsigning.xml
+++ b/docs-xml/smbdotconf/security/clientsigning.xml
@@ -9,14 +9,16 @@
and <emphasis>disabled</emphasis>.
</para>
- <para>When set to auto or default, SMB signing is offered, but not
- enforced, except in winbindd, where it is enforced to Active
- Directory Domain Controllers. </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>
+ 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 0000000..30e7280
--- /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 21b79f0..0b7755a 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/tlsverifypeer.xml b/docs-xml/smbdotconf/security/tlsverifypeer.xml
new file mode 100644
index 0000000..4f47dd4
--- /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/docs/manpages/cifsdd.8 b/docs/manpages/cifsdd.8
index c73ff28..85676e3 100644
--- a/docs/manpages/cifsdd.8
+++ b/docs/manpages/cifsdd.8
@@ -2,12 +2,12 @@
.\" Title: cifsdd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "CIFSDD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "CIFSDD" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/dbwrap_tool.1 b/docs/manpages/dbwrap_tool.1
index 1322c44..e9a86a0 100644
--- a/docs/manpages/dbwrap_tool.1
+++ b/docs/manpages/dbwrap_tool.1
@@ -2,12 +2,12 @@
.\" Title: dbwrap_tool
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "DBWRAP_TOOL" "1" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "DBWRAP_TOOL" "1" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/eventlogadm.8 b/docs/manpages/eventlogadm.8
index 98948e2..3e9cd6c 100644
--- a/docs/manpages/eventlogadm.8
+++ b/docs/manpages/eventlogadm.8
@@ -2,12 +2,12 @@
.\" Title: eventlogadm
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "EVENTLOGADM" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "EVENTLOGADM" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/findsmb.1 b/docs/manpages/findsmb.1
index 1503981..f0bc54d 100644
--- a/docs/manpages/findsmb.1
+++ b/docs/manpages/findsmb.1
@@ -2,12 +2,12 @@
.\" Title: findsmb
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "FINDSMB" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "FINDSMB" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_ad.8 b/docs/manpages/idmap_ad.8
index 65dab87..100f1f3 100644
--- a/docs/manpages/idmap_ad.8
+++ b/docs/manpages/idmap_ad.8
@@ -2,12 +2,12 @@
.\" Title: idmap_ad
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "IDMAP_AD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "IDMAP_AD" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_autorid.8 b/docs/manpages/idmap_autorid.8
index 53407e1..645a52d 100644
--- a/docs/manpages/idmap_autorid.8
+++ b/docs/manpages/idmap_autorid.8
@@ -2,12 +2,12 @@
.\" Title: idmap_autorid
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "IDMAP_AUTORID" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "IDMAP_AUTORID" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_hash.8 b/docs/manpages/idmap_hash.8
index 5ab8594..011dd1a 100644
--- a/docs/manpages/idmap_hash.8
+++ b/docs/manpages/idmap_hash.8
@@ -2,12 +2,12 @@
.\" Title: idmap_hash
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "IDMAP_HASH" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "IDMAP_HASH" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_ldap.8 b/docs/manpages/idmap_ldap.8
index 18f176f..e8e942b 100644
--- a/docs/manpages/idmap_ldap.8
+++ b/docs/manpages/idmap_ldap.8
@@ -2,12 +2,12 @@
.\" Title: idmap_ldap
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "IDMAP_LDAP" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "IDMAP_LDAP" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_nss.8 b/docs/manpages/idmap_nss.8
index 805133d..5812000 100644
--- a/docs/manpages/idmap_nss.8
+++ b/docs/manpages/idmap_nss.8
@@ -2,12 +2,12 @@
.\" Title: idmap_nss
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "IDMAP_NSS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "IDMAP_NSS" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_rfc2307.8 b/docs/manpages/idmap_rfc2307.8
index 7e194bf..3b11a41 100644
--- a/docs/manpages/idmap_rfc2307.8
+++ b/docs/manpages/idmap_rfc2307.8
@@ -2,12 +2,12 @@
.\" Title: idmap_rfc2307
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "IDMAP_RFC2307" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "IDMAP_RFC2307" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_rid.8 b/docs/manpages/idmap_rid.8
index 3768b1d..32f8941 100644
--- a/docs/manpages/idmap_rid.8
+++ b/docs/manpages/idmap_rid.8
@@ -2,12 +2,12 @@
.\" Title: idmap_rid
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "IDMAP_RID" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "IDMAP_RID" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_script.8 b/docs/manpages/idmap_script.8
index 7d8f152..c0d8d11 100644
--- a/docs/manpages/idmap_script.8
+++ b/docs/manpages/idmap_script.8
@@ -2,12 +2,12 @@
.\" Title: idmap_script
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "IDMAP_SCRIPT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "IDMAP_SCRIPT" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_tdb.8 b/docs/manpages/idmap_tdb.8
index bb84117..c70d484 100644
--- a/docs/manpages/idmap_tdb.8
+++ b/docs/manpages/idmap_tdb.8
@@ -2,12 +2,12 @@
.\" Title: idmap_tdb
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "IDMAP_TDB" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "IDMAP_TDB" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/idmap_tdb2.8 b/docs/manpages/idmap_tdb2.8
index 11db10c..e1e3d18 100644
--- a/docs/manpages/idmap_tdb2.8
+++ b/docs/manpages/idmap_tdb2.8
@@ -2,12 +2,12 @@
.\" Title: idmap_tdb2
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "IDMAP_TDB2" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "IDMAP_TDB2" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/libsmbclient.7 b/docs/manpages/libsmbclient.7
index fc07386..187383e 100644
--- a/docs/manpages/libsmbclient.7
+++ b/docs/manpages/libsmbclient.7
@@ -2,12 +2,12 @@
.\" Title: libsmbclient
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: 7
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "LIBSMBCLIENT" "7" "03/22/2016" "Samba 4\&.4" "7"
+.TH "LIBSMBCLIENT" "7" "03/30/2016" "Samba 4\&.4" "7"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/lmhosts.5 b/docs/manpages/lmhosts.5
index baf2c5e..e04830d 100644
--- a/docs/manpages/lmhosts.5
+++ b/docs/manpages/lmhosts.5
@@ -2,12 +2,12 @@
.\" Title: lmhosts
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: File Formats and Conventions
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "LMHOSTS" "5" "03/22/2016" "Samba 4\&.4" "File Formats and Conventions"
+.TH "LMHOSTS" "5" "03/30/2016" "Samba 4\&.4" "File Formats and Conventions"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/log2pcap.1 b/docs/manpages/log2pcap.1
index eef069b..26dfd40 100644
--- a/docs/manpages/log2pcap.1
+++ b/docs/manpages/log2pcap.1
@@ -2,12 +2,12 @@
.\" Title: log2pcap
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "LOG2PCAP" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "LOG2PCAP" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/net.8 b/docs/manpages/net.8
index 2ee68ed..3c92872 100644
--- a/docs/manpages/net.8
+++ b/docs/manpages/net.8
@@ -2,12 +2,12 @@
.\" Title: net
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "NET" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "NET" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/nmbd.8 b/docs/manpages/nmbd.8
index 6543ee9..626c424 100644
--- a/docs/manpages/nmbd.8
+++ b/docs/manpages/nmbd.8
@@ -2,12 +2,12 @@
.\" Title: nmbd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "NMBD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "NMBD" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/nmblookup.1 b/docs/manpages/nmblookup.1
index 12e1d4f..b3855b2 100644
--- a/docs/manpages/nmblookup.1
+++ b/docs/manpages/nmblookup.1
@@ -2,12 +2,12 @@
.\" Title: nmblookup
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "NMBLOOKUP" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "NMBLOOKUP" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/ntlm_auth.1 b/docs/manpages/ntlm_auth.1
index 6d996e0..3b36ab2 100644
--- a/docs/manpages/ntlm_auth.1
+++ b/docs/manpages/ntlm_auth.1
@@ -2,12 +2,12 @@
.\" Title: ntlm_auth
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "NTLM_AUTH" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "NTLM_AUTH" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/pam_winbind.8 b/docs/manpages/pam_winbind.8
index 2da1b1f..b8b55449 100644
--- a/docs/manpages/pam_winbind.8
+++ b/docs/manpages/pam_winbind.8
@@ -2,12 +2,12 @@
.\" Title: pam_winbind
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: 8
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "PAM_WINBIND" "8" "03/22/2016" "Samba 4\&.4" "8"
+.TH "PAM_WINBIND" "8" "03/30/2016" "Samba 4\&.4" "8"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/pam_winbind.conf.5 b/docs/manpages/pam_winbind.conf.5
index 68b1fe0..b92bca1 100644
--- a/docs/manpages/pam_winbind.conf.5
+++ b/docs/manpages/pam_winbind.conf.5
@@ -2,12 +2,12 @@
.\" Title: pam_winbind.conf
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: 5
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "PAM_WINBIND\&.CONF" "5" "03/22/2016" "Samba 4\&.4" "5"
+.TH "PAM_WINBIND\&.CONF" "5" "03/30/2016" "Samba 4\&.4" "5"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/pdbedit.8 b/docs/manpages/pdbedit.8
index edecd5b..84b35e5 100644
--- a/docs/manpages/pdbedit.8
+++ b/docs/manpages/pdbedit.8
@@ -2,12 +2,12 @@
.\" Title: pdbedit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "PDBEDIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "PDBEDIT" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/profiles.1 b/docs/manpages/profiles.1
index 9216459..34f738c 100644
--- a/docs/manpages/profiles.1
+++ b/docs/manpages/profiles.1
@@ -2,12 +2,12 @@
.\" Title: profiles
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "PROFILES" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "PROFILES" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/rpcclient.1 b/docs/manpages/rpcclient.1
index c7394eb..27cdf1f 100644
--- a/docs/manpages/rpcclient.1
+++ b/docs/manpages/rpcclient.1
@@ -2,12 +2,12 @@
.\" Title: rpcclient
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "RPCCLIENT" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "RPCCLIENT" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/samba-regedit.8 b/docs/manpages/samba-regedit.8
index b734dd9..2d6aead 100644
--- a/docs/manpages/samba-regedit.8
+++ b/docs/manpages/samba-regedit.8
@@ -2,12 +2,12 @@
.\" Title: samba-regedit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SAMBA\-REGEDIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "SAMBA\-REGEDIT" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/samba-tool.8 b/docs/manpages/samba-tool.8
index 31aa073..0165614 100644
--- a/docs/manpages/samba-tool.8
+++ b/docs/manpages/samba-tool.8
@@ -2,12 +2,12 @@
.\" Title: samba-tool
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SAMBA\-TOOL" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "SAMBA\-TOOL" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/samba.7 b/docs/manpages/samba.7
index d47ce9e..d2fea34 100644
--- a/docs/manpages/samba.7
+++ b/docs/manpages/samba.7
@@ -2,12 +2,12 @@
.\" Title: samba
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: Miscellanea
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SAMBA" "7" "03/22/2016" "Samba 4\&.4" "Miscellanea"
+.TH "SAMBA" "7" "03/30/2016" "Samba 4\&.4" "Miscellanea"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/samba.8 b/docs/manpages/samba.8
index d4cf53e..04454c5 100644
--- a/docs/manpages/samba.8
+++ b/docs/manpages/samba.8
@@ -2,12 +2,12 @@
.\" Title: samba
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SAMBA" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "SAMBA" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/sharesec.1 b/docs/manpages/sharesec.1
index 5e86ba3..3167ac7 100644
--- a/docs/manpages/sharesec.1
+++ b/docs/manpages/sharesec.1
@@ -2,12 +2,12 @@
.\" Title: sharesec
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SHARESEC" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "SHARESEC" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smb.conf.5 b/docs/manpages/smb.conf.5
index 1705bfe..467ff2d 100644
--- a/docs/manpages/smb.conf.5
+++ b/docs/manpages/smb.conf.5
@@ -2,12 +2,12 @@
.\" Title: smb.conf
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: File Formats and Conventions
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMB\&.CONF" "5" "03/22/2016" "Samba 4\&.4" "File Formats and Conventions"
+.TH "SMB\&.CONF" "5" "03/30/2016" "Samba 4\&.4" "File Formats and Conventions"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -1291,6 +1291,28 @@ Example:
\fI\fIallocation roundup size\fR\fR\fI = \fR\fI0 # (to disable roundups)\fR\fI \fR
.RE
+allow dcerpc auth level connect (G)
+.\" allow dcerpc auth level connect
+.PP
+.RS 4
+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\&.
+.sp
+Some interfaces like samr, lsarpc and netlogon have a hard\-coded default of
+\fBno\fR
+and epmapper, mgmt and rpcecho have a hard\-coded default of
+\fByes\fR\&.
+.sp
+The behavior can be overwritten per interface name (e\&.g\&. lsarpc, netlogon, samr, srvsvc, winreg, wkssvc \&.\&.\&.) by using \*(Aqallow dcerpc auth level connect:interface = yes\*(Aq as option\&.
+.sp
+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\&.
+.sp
+Default:
+\fI\fIallow dcerpc auth level connect\fR\fR\fI = \fR\fIno\fR\fI \fR
+.sp
+Example:
+\fI\fIallow dcerpc auth level connect\fR\fR\fI = \fR\fIyes\fR\fI \fR
+.RE
+
allow dns updates (G)
.\" allow dns updates
.PP
@@ -1782,6 +1804,76 @@ Example:
\fI\fIcldap port\fR\fR\fI = \fR\fI3389\fR\fI \fR
.RE
+client ipc max protocol (G)
+.\" client ipc max protocol
+.PP
+.RS 4
+The value of the parameter (a string) is the highest protocol level that will be supported for IPC$ connections as DCERPC transport\&.
+.sp
+Normally this option should not be set as the automatic negotiation phase in the SMB protocol takes care of choosing the appropriate protocol\&.
+.sp
+The value
+\fBdefault\fR
+refers to the latest supported protocol, currently
+\fBSMB3_11\fR\&.
+.sp
+See
+\m[blue]\fBclient max protocol\fR\m[]
+for a full list of available protocols\&. The values CORE, COREPLUS, LANMAN1, LANMAN2 are silently upgraded to NT1\&.
+.sp
+Default:
+\fI\fIclient ipc max protocol\fR\fR\fI = \fR\fIdefault\fR\fI \fR
+.sp
+Example:
+\fI\fIclient ipc max protocol\fR\fR\fI = \fR\fISMB2_10\fR\fI \fR
+.RE
+
+client ipc min protocol (G)
+.\" client ipc min protocol
+.PP
+.RS 4
+This setting controls the minimum protocol version that the will be attempted to use for IPC$ connections as DCERPC transport\&.
+.sp
+Normally this option should not be set as the automatic negotiation phase in the SMB protocol takes care of choosing the appropriate protocol\&.
+.sp
+The value
+\fBdefault\fR
+refers to the higher value of
+\fBNT1\fR
+and the effective value of
+\m[blue]\fBclient min protocol\fR\m[]\&.
+.sp
+See
+\m[blue]\fBclient max protocol\fR\m[]
+for a full list of available protocols\&. The values CORE, COREPLUS, LANMAN1, LANMAN2 are silently upgraded to NT1\&.
+.sp
+Default:
+\fI\fIclient ipc min protocol\fR\fR\fI = \fR\fIdefault\fR\fI \fR
+.sp
+Example:
+\fI\fIclient ipc min protocol\fR\fR\fI = \fR\fISMB3_11\fR\fI \fR
+.RE
+
+client ipc signing (G)
+.\" client ipc signing
+.PP
+.RS 4
+This controls whether the client is allowed or required to use SMB signing for IPC$ connections as DCERPC transport\&. Possible values are
+\fIauto\fR,
+\fImandatory\fR
+and
+\fIdisabled\fR\&.
+.sp
+When set to mandatory or default, SMB signing is required\&.
+.sp
+When set to auto, SMB signing is offered, but not enforced and if set to disabled, SMB signing is not offered either\&.
+.sp
+Connections from winbindd to Active Directory Domain Controllers always enforce signing\&.
+.sp
+Default:
+\fI\fIclient ipc signing\fR\fR\fI = \fR\fIdefault\fR\fI \fR
+.RE
+
client lanman auth (G)
.\" client lanman auth
.PP
@@ -2023,11 +2115,12 @@ Normally this option should not be set as the automatic negotiation phase in the
.sp
The value
\fBdefault\fR
-refers to the default protocol in each part of the code, currently
-\fBNT1\fR
-in the client tools and
-\fBSMB3_02\fR
-in winbindd\&.
+refers to
+\fBNT1\fR\&.
+.sp
+IPC$ connections for DCERPC e\&.g\&. in winbindd, are handled by the
+\m[blue]\fBclient ipc max protocol\fR\m[]
+option\&.
.sp
Default:
\fI\fIclient max protocol\fR\fR\fI = \fR\fIdefault\fR\fI \fR
@@ -2048,6 +2141,10 @@ See
Related command: \m[blue]\fBclient max protocol\fR\m[]
for a full list of available protocols\&.
.sp
+IPC$ connections for DCERPC e\&.g\&. in winbindd, are handled by the
+\m[blue]\fBclient ipc min protocol\fR\m[]
+option\&.
+.sp
Default:
\fI\fIclient min protocol\fR\fR\fI = \fR\fICORE\fR\fI \fR
.sp
@@ -2076,6 +2173,12 @@ client lanman auth\&.
.sp
Note that Windows Vista and later versions already use NTLMv2 by default, and some sites (particularly those following \*(Aqbest practice\*(Aq security polices) only allow NTLMv2 responses, and not the weaker LM or NTLM\&.
.sp
+When
+\m[blue]\fBclient use spnego\fR\m[]
+is also set to
+\fByes\fR
+extended security (SPNEGO) is required in order to use NTLMv2 only within NTLMSSP\&. This behavior was introduced with the patches for CVE\-2016\-2111\&.
+.sp
Default:
\fI\fIclient NTLMv2 auth\fR\fR\fI = \fR\fIyes\fR\fI \fR
.RE
@@ -2126,10 +2229,14 @@ This controls whether the client is allowed or required to use SMB signing\&. Po
and
\fIdisabled\fR\&.
.sp
-When set to auto or default, SMB signing is offered, but not enforced, except in winbindd, where it is enforced to Active Directory Domain Controllers\&.
+When set to auto or default, SMB signing is offered, but not enforced\&.
.sp
When set to mandatory, SMB signing is required and if set to disabled, SMB signing is not offered either\&.
.sp
+IPC$ connections for DCERPC e\&.g\&. in winbindd, are handled by the
+\m[blue]\fBclient ipc signing\fR\m[]
+option\&.
+.sp
Default:
\fI\fIclient signing\fR\fR\fI = \fR\fIdefault\fR\fI \fR
.RE
@@ -2162,6 +2269,12 @@ client use spnego (G)
.RS 4
This variable controls whether Samba clients will try to use Simple and Protected NEGOciation (as specified by rfc2478) with supporting servers (including WindowsXP, Windows2000 and Samba 3\&.0) to agree upon an authentication mechanism\&. This enables Kerberos authentication in particular\&.
.sp
+When
+\m[blue]\fBclient NTLMv2 auth\fR\m[]
+is also set to
+\fByes\fR
+extended security (SPNEGO) is required in order to use NTLMv2 only within NTLMSSP\&. This behavior was introduced with the patches for CVE\-2016\-2111\&.
+.sp
Default:
\fI\fIclient use spnego\fR\fR\fI = \fR\fIyes\fR\fI \fR
.RE
@@ -5098,6 +5211,34 @@ Default:
\fI\fIldapsam:trusted\fR\fR\fI = \fR\fIno\fR\fI \fR
.RE
+ldap server require strong auth (G)
+.\" ldap server require strong auth
+.PP
+.RS 4
+The
+\m[blue]\fBldap server require strong auth\fR\m[]
+defines whether the ldap server requires ldap traffic to be signed or signed and encrypted (sealed)\&. Possible values are
+\fIno\fR,
+\fIallow_sasl_over_tls\fR
+and
+\fIyes\fR\&.
+.sp
+A value of
+\fIno\fR
+allows simple and sasl binds over all transports\&.
+.sp
+A value of
+\fIallow_sasl_over_tls\fR
+allows simple and sasl binds (without sign or seal) over TLS encrypted connections\&. Unencrypted connections only allow sasl binds with sign or seal\&.
+.sp
+A value of
+\fIyes\fR
+allows only simple binds over TLS encrypted connections\&. Unencrypted connections only allow sasl binds with sign or seal\&.
+.sp
+Default:
+\fI\fIldap server require strong auth\fR\fR\fI = \fR\fIyes\fR\fI \fR
+.RE
+
ldap ssl (G)
.\" ldap ssl
.PP
@@ -8352,6 +8493,24 @@ Example:
\fI\fIqueueresume command\fR\fR\fI = \fR\fIenable %p\fR\fI \fR
.RE
+raw NTLMv2 auth (G)
+.\" raw NTLMv2 auth
+.PP
+.RS 4
+This parameter determines whether or not
+\fBsmbd\fR(8)
+will allow SMB1 clients without extended security (without SPNEGO) to use NTLMv2 authentication\&.
+.sp
+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\&.
+.sp
+Default:
+\fI\fIraw NTLMv2 auth\fR\fR\fI = \fR\fIno\fR\fI \fR
+.RE
+
read list (S)
.\" read list
.PP
@@ -9595,7 +9754,7 @@ and
\fIdisabled\fR\&.
.sp
By default, and when smb signing is set to
-\fIdefault\fR, smb signing enabled when
+\fIdefault\fR, smb signing is required when
\m[blue]\fBserver role\fR\m[]
is
\fIactive directory domain controller\fR
@@ -11174,6 +11333,56 @@ Default:
\fI\fItls priority\fR\fR\fI = \fR\fINORMAL:\-VERS\-SSL3\&.0\fR\fI \fR
.RE
+tls verify peer (G)
+.\" tls verify peer
+.PP
+.RS 4
+This controls if and how strict the client will verify the peer\*(Aqs certificate and name\&. Possible values are (in increasing order):
+\fBno_check\fR,
+\fBca_only\fR,
+\fBca_and_name_if_available\fR,
+\fBca_and_name\fR
+and
+\fBas_strict_as_possible\fR\&.
+.sp
+When set to
+\fBno_check\fR
+the certificate is not verified at all, which allows trivial man in the middle attacks\&.
+.sp
+When set to
+\fBca_only\fR
+the certificate is verified to be signed from a ca specified in the
+\m[blue]\fBtls ca file\fR\m[]
+option\&. Setting
+\m[blue]\fBtls ca file\fR\m[]
+to a valid file is required\&. The certificate lifetime is also verified\&. If the
+\m[blue]\fBtls crl file\fR\m[]
+option is configured, the certificate is also verified against the ca crl\&.
+.sp
+When set to
+\fBca_and_name_if_available\fR
+all checks from
+\fBca_only\fR
+are performed\&. In addition, the peer hostname is verified against the certificate\*(Aqs name, if it is provided by the application layer and not given as an ip address string\&.
+.sp
+When set to
+\fBca_and_name\fR
+all checks from
+\fBca_and_name_if_available\fR
+are performed\&. In addition the peer hostname needs to be provided and even an ip address is checked against the certificate\*(Aqs name\&.
+.sp
+When set to
+\fBas_strict_as_possible\fR
+all checks from
+\fBca_and_name\fR
+are performed\&. In addition the
+\m[blue]\fBtls crl file\fR\m[]
+needs to be configured\&. Future versions of Samba may implement additional checks\&.
+.sp
+Default:
+\fI\fItls verify peer\fR\fR\fI = \fR\fIas_strict_as_possible\fR\fI \fR
+.RE
+
unicode (G)
.\" unicode
.PP
diff --git a/docs/manpages/smbcacls.1 b/docs/manpages/smbcacls.1
index 3a1f3fb..aa8219b 100644
--- a/docs/manpages/smbcacls.1
+++ b/docs/manpages/smbcacls.1
@@ -2,12 +2,12 @@
.\" Title: smbcacls
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBCACLS" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "SMBCACLS" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbclient.1 b/docs/manpages/smbclient.1
index d8964e8..29bac01 100644
--- a/docs/manpages/smbclient.1
+++ b/docs/manpages/smbclient.1
@@ -2,12 +2,12 @@
.\" Title: smbclient
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBCLIENT" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "SMBCLIENT" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbcontrol.1 b/docs/manpages/smbcontrol.1
index b42c86f..869db88 100644
--- a/docs/manpages/smbcontrol.1
+++ b/docs/manpages/smbcontrol.1
@@ -2,12 +2,12 @@
.\" Title: smbcontrol
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBCONTROL" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "SMBCONTROL" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbcquotas.1 b/docs/manpages/smbcquotas.1
index 146b110..15f67ad 100644
--- a/docs/manpages/smbcquotas.1
+++ b/docs/manpages/smbcquotas.1
@@ -2,12 +2,12 @@
.\" Title: smbcquotas
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBCQUOTAS" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "SMBCQUOTAS" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbd.8 b/docs/manpages/smbd.8
index 0f4f1ee..6daf510 100644
--- a/docs/manpages/smbd.8
+++ b/docs/manpages/smbd.8
@@ -2,12 +2,12 @@
.\" Title: smbd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "SMBD" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbget.1 b/docs/manpages/smbget.1
index 12a0374..01bc92f 100644
--- a/docs/manpages/smbget.1
+++ b/docs/manpages/smbget.1
@@ -2,12 +2,12 @@
.\" Title: smbget
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBGET" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "SMBGET" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbgetrc.5 b/docs/manpages/smbgetrc.5
index d1962b2..78c6acc 100644
--- a/docs/manpages/smbgetrc.5
+++ b/docs/manpages/smbgetrc.5
@@ -2,12 +2,12 @@
.\" Title: smbgetrc
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: File Formats and Conventions
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBGETRC" "5" "03/22/2016" "Samba 4\&.4" "File Formats and Conventions"
+.TH "SMBGETRC" "5" "03/30/2016" "Samba 4\&.4" "File Formats and Conventions"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbpasswd.5 b/docs/manpages/smbpasswd.5
index 71740b8..1305ec7 100644
--- a/docs/manpages/smbpasswd.5
+++ b/docs/manpages/smbpasswd.5
@@ -2,12 +2,12 @@
.\" Title: smbpasswd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: File Formats and Conventions
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBPASSWD" "5" "03/22/2016" "Samba 4\&.4" "File Formats and Conventions"
+.TH "SMBPASSWD" "5" "03/30/2016" "Samba 4\&.4" "File Formats and Conventions"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbpasswd.8 b/docs/manpages/smbpasswd.8
index 2f233e9..04d45f4 100644
--- a/docs/manpages/smbpasswd.8
+++ b/docs/manpages/smbpasswd.8
@@ -2,12 +2,12 @@
.\" Title: smbpasswd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBPASSWD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "SMBPASSWD" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbspool.8 b/docs/manpages/smbspool.8
index 975a6d6..a73d1b2 100644
--- a/docs/manpages/smbspool.8
+++ b/docs/manpages/smbspool.8
@@ -2,12 +2,12 @@
.\" Title: smbspool
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBSPOOL" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "SMBSPOOL" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbspool_krb5_wrapper.8 b/docs/manpages/smbspool_krb5_wrapper.8
index ccd20b9..c7447e5 100644
--- a/docs/manpages/smbspool_krb5_wrapper.8
+++ b/docs/manpages/smbspool_krb5_wrapper.8
@@ -2,12 +2,12 @@
.\" Title: smbspool_krb5_wrapper
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBSPOOL_KRB5_WRAPPE" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "SMBSPOOL_KRB5_WRAPPE" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbstatus.1 b/docs/manpages/smbstatus.1
index 1dcd876..9876413 100644
--- a/docs/manpages/smbstatus.1
+++ b/docs/manpages/smbstatus.1
@@ -2,12 +2,12 @@
.\" Title: smbstatus
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBSTATUS" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "SMBSTATUS" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbtar.1 b/docs/manpages/smbtar.1
index 8cf2265..ac027af 100644
--- a/docs/manpages/smbtar.1
+++ b/docs/manpages/smbtar.1
@@ -2,12 +2,12 @@
.\" Title: smbtar
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBTAR" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "SMBTAR" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/smbtree.1 b/docs/manpages/smbtree.1
index 0eea499..db25017 100644
--- a/docs/manpages/smbtree.1
+++ b/docs/manpages/smbtree.1
@@ -2,12 +2,12 @@
.\" Title: smbtree
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "SMBTREE" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "SMBTREE" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/testparm.1 b/docs/manpages/testparm.1
index dd29266..278bc5c 100644
--- a/docs/manpages/testparm.1
+++ b/docs/manpages/testparm.1
@@ -2,12 +2,12 @@
.\" Title: testparm
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "TESTPARM" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "TESTPARM" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_acl_tdb.8 b/docs/manpages/vfs_acl_tdb.8
index 2903303..7943680 100644
--- a/docs/manpages/vfs_acl_tdb.8
+++ b/docs/manpages/vfs_acl_tdb.8
@@ -2,12 +2,12 @@
.\" Title: vfs_acl_tdb
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_ACL_TDB" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_ACL_TDB" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_acl_xattr.8 b/docs/manpages/vfs_acl_xattr.8
index 0c80ba2..343d9ca 100644
--- a/docs/manpages/vfs_acl_xattr.8
+++ b/docs/manpages/vfs_acl_xattr.8
@@ -2,12 +2,12 @@
.\" Title: vfs_acl_xattr
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_ACL_XATTR" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_ACL_XATTR" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_aio_fork.8 b/docs/manpages/vfs_aio_fork.8
index 43e9d21..51ff01e 100644
--- a/docs/manpages/vfs_aio_fork.8
+++ b/docs/manpages/vfs_aio_fork.8
@@ -2,12 +2,12 @@
.\" Title: vfs_aio_fork
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_AIO_FORK" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_AIO_FORK" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_aio_linux.8 b/docs/manpages/vfs_aio_linux.8
index e962a26..009f63e 100644
--- a/docs/manpages/vfs_aio_linux.8
+++ b/docs/manpages/vfs_aio_linux.8
@@ -2,12 +2,12 @@
.\" Title: vfs_aio_linux
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_AIO_LINUX" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_AIO_LINUX" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_aio_pthread.8 b/docs/manpages/vfs_aio_pthread.8
index d96564e..b491773 100644
--- a/docs/manpages/vfs_aio_pthread.8
+++ b/docs/manpages/vfs_aio_pthread.8
@@ -2,12 +2,12 @@
.\" Title: vfs_aio_pthread
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_AIO_PTHREAD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_AIO_PTHREAD" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_audit.8 b/docs/manpages/vfs_audit.8
index 1316baa..299c724 100644
--- a/docs/manpages/vfs_audit.8
+++ b/docs/manpages/vfs_audit.8
@@ -2,12 +2,12 @@
.\" Title: vfs_audit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_AUDIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_AUDIT" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_btrfs.8 b/docs/manpages/vfs_btrfs.8
index 33c2245..db73105 100644
--- a/docs/manpages/vfs_btrfs.8
+++ b/docs/manpages/vfs_btrfs.8
@@ -2,12 +2,12 @@
.\" Title: vfs_btrfs
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_BTRFS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_BTRFS" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_cacheprime.8 b/docs/manpages/vfs_cacheprime.8
index 17ed828..a4ad59c 100644
--- a/docs/manpages/vfs_cacheprime.8
+++ b/docs/manpages/vfs_cacheprime.8
@@ -2,12 +2,12 @@
.\" Title: vfs_cacheprime
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_CACHEPRIME" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_CACHEPRIME" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_cap.8 b/docs/manpages/vfs_cap.8
index d278883..d616dee 100644
--- a/docs/manpages/vfs_cap.8
+++ b/docs/manpages/vfs_cap.8
@@ -2,12 +2,12 @@
.\" Title: vfs_cap
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_CAP" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_CAP" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_catia.8 b/docs/manpages/vfs_catia.8
index f48b650..3d67dcf 100644
--- a/docs/manpages/vfs_catia.8
+++ b/docs/manpages/vfs_catia.8
@@ -2,12 +2,12 @@
.\" Title: vfs_catia
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_CATIA" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_CATIA" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_ceph.8 b/docs/manpages/vfs_ceph.8
index 8c28386..90f165a 100644
--- a/docs/manpages/vfs_ceph.8
+++ b/docs/manpages/vfs_ceph.8
@@ -2,12 +2,12 @@
.\" Title: vfs_ceph
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_CEPH" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_CEPH" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_commit.8 b/docs/manpages/vfs_commit.8
index 36d357c..a73c93b 100644
--- a/docs/manpages/vfs_commit.8
+++ b/docs/manpages/vfs_commit.8
@@ -2,12 +2,12 @@
.\" Title: vfs_commit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_COMMIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_COMMIT" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_crossrename.8 b/docs/manpages/vfs_crossrename.8
index 4fab9e7..e76a495 100644
--- a/docs/manpages/vfs_crossrename.8
+++ b/docs/manpages/vfs_crossrename.8
@@ -2,12 +2,12 @@
.\" Title: vfs_crossrename
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_CROSSRENAME" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_CROSSRENAME" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_default_quota.8 b/docs/manpages/vfs_default_quota.8
index 9628808..faa423b 100644
--- a/docs/manpages/vfs_default_quota.8
+++ b/docs/manpages/vfs_default_quota.8
@@ -2,12 +2,12 @@
.\" Title: vfs_default_quota
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_DEFAULT_QUOTA" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_DEFAULT_QUOTA" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_dirsort.8 b/docs/manpages/vfs_dirsort.8
index ebc8bde..caa86e3 100644
--- a/docs/manpages/vfs_dirsort.8
+++ b/docs/manpages/vfs_dirsort.8
@@ -2,12 +2,12 @@
.\" Title: vfs_dirsort
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_DIRSORT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_DIRSORT" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_extd_audit.8 b/docs/manpages/vfs_extd_audit.8
index 66e5945..9b67508 100644
--- a/docs/manpages/vfs_extd_audit.8
+++ b/docs/manpages/vfs_extd_audit.8
@@ -2,12 +2,12 @@
.\" Title: vfs_extd_audit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_EXTD_AUDIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_EXTD_AUDIT" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_fake_perms.8 b/docs/manpages/vfs_fake_perms.8
index d7fbbb8..6b769f8 100644
--- a/docs/manpages/vfs_fake_perms.8
+++ b/docs/manpages/vfs_fake_perms.8
@@ -2,12 +2,12 @@
.\" Title: vfs_fake_perms
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_FAKE_PERMS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_FAKE_PERMS" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_fileid.8 b/docs/manpages/vfs_fileid.8
index aa13ef5..be3f75c 100644
--- a/docs/manpages/vfs_fileid.8
+++ b/docs/manpages/vfs_fileid.8
@@ -2,12 +2,12 @@
.\" Title: vfs_fileid
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_FILEID" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_FILEID" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_fruit.8 b/docs/manpages/vfs_fruit.8
index a2ac437..4f6bff3 100644
--- a/docs/manpages/vfs_fruit.8
+++ b/docs/manpages/vfs_fruit.8
@@ -2,12 +2,12 @@
.\" Title: vfs_fruit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_FRUIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_FRUIT" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_full_audit.8 b/docs/manpages/vfs_full_audit.8
index 8c2f996..a87b123 100644
--- a/docs/manpages/vfs_full_audit.8
+++ b/docs/manpages/vfs_full_audit.8
@@ -2,12 +2,12 @@
.\" Title: vfs_full_audit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_FULL_AUDIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_FULL_AUDIT" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_glusterfs.8 b/docs/manpages/vfs_glusterfs.8
index 0de3b97..6a87004 100644
--- a/docs/manpages/vfs_glusterfs.8
+++ b/docs/manpages/vfs_glusterfs.8
@@ -2,12 +2,12 @@
.\" Title: vfs_glusterfs
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_GLUSTERFS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_GLUSTERFS" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_gpfs.8 b/docs/manpages/vfs_gpfs.8
index 7f0a43d..0b3c553 100644
--- a/docs/manpages/vfs_gpfs.8
+++ b/docs/manpages/vfs_gpfs.8
@@ -2,12 +2,12 @@
.\" Title: vfs_gpfs
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_GPFS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_GPFS" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_linux_xfs_sgid.8 b/docs/manpages/vfs_linux_xfs_sgid.8
index 7621b0f..6a410aa 100644
--- a/docs/manpages/vfs_linux_xfs_sgid.8
+++ b/docs/manpages/vfs_linux_xfs_sgid.8
@@ -2,12 +2,12 @@
.\" Title: vfs_syncops
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_SYNCOPS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_SYNCOPS" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_media_harmony.8 b/docs/manpages/vfs_media_harmony.8
index f16553e..76e5f92 100644
--- a/docs/manpages/vfs_media_harmony.8
+++ b/docs/manpages/vfs_media_harmony.8
@@ -2,12 +2,12 @@
.\" Title: vfs_media_harmony
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_MEDIA_HARMONY" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_MEDIA_HARMONY" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_netatalk.8 b/docs/manpages/vfs_netatalk.8
index ab74ab6..9f82dd7 100644
--- a/docs/manpages/vfs_netatalk.8
+++ b/docs/manpages/vfs_netatalk.8
@@ -2,12 +2,12 @@
.\" Title: vfs_netatalk
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_NETATALK" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_NETATALK" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_offline.8 b/docs/manpages/vfs_offline.8
index e9ad9bc..c7a0102 100644
--- a/docs/manpages/vfs_offline.8
+++ b/docs/manpages/vfs_offline.8
@@ -2,12 +2,12 @@
.\" Title: vfs_offline
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_OFFLINE" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_OFFLINE" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_prealloc.8 b/docs/manpages/vfs_prealloc.8
index dee51e4..146f952 100644
--- a/docs/manpages/vfs_prealloc.8
+++ b/docs/manpages/vfs_prealloc.8
@@ -2,12 +2,12 @@
.\" Title: vfs_prealloc
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_PREALLOC" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_PREALLOC" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_preopen.8 b/docs/manpages/vfs_preopen.8
index 79a6c0b..432c17d 100644
--- a/docs/manpages/vfs_preopen.8
+++ b/docs/manpages/vfs_preopen.8
@@ -2,12 +2,12 @@
.\" Title: vfs_preopen
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_PREOPEN" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_PREOPEN" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_readahead.8 b/docs/manpages/vfs_readahead.8
index 8619a55..917c857 100644
--- a/docs/manpages/vfs_readahead.8
+++ b/docs/manpages/vfs_readahead.8
@@ -2,12 +2,12 @@
.\" Title: vfs_readahead
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_READAHEAD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_READAHEAD" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_readonly.8 b/docs/manpages/vfs_readonly.8
index 2f4a306..1778854 100644
--- a/docs/manpages/vfs_readonly.8
+++ b/docs/manpages/vfs_readonly.8
@@ -2,12 +2,12 @@
.\" Title: vfs_readonly
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_READONLY" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_READONLY" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_recycle.8 b/docs/manpages/vfs_recycle.8
index 414483a..28579f1 100644
--- a/docs/manpages/vfs_recycle.8
+++ b/docs/manpages/vfs_recycle.8
@@ -2,12 +2,12 @@
.\" Title: vfs_recycle
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_RECYCLE" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_RECYCLE" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_shadow_copy.8 b/docs/manpages/vfs_shadow_copy.8
index 00b2f62..79daca5 100644
--- a/docs/manpages/vfs_shadow_copy.8
+++ b/docs/manpages/vfs_shadow_copy.8
@@ -2,12 +2,12 @@
.\" Title: vfs_shadow_copy
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_SHADOW_COPY" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_SHADOW_COPY" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_shadow_copy2.8 b/docs/manpages/vfs_shadow_copy2.8
index 884f173..52f0122 100644
--- a/docs/manpages/vfs_shadow_copy2.8
+++ b/docs/manpages/vfs_shadow_copy2.8
@@ -2,12 +2,12 @@
.\" Title: vfs_shadow_copy2
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_SHADOW_COPY2" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_SHADOW_COPY2" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_shell_snap.8 b/docs/manpages/vfs_shell_snap.8
index 402d591..4411121 100644
--- a/docs/manpages/vfs_shell_snap.8
+++ b/docs/manpages/vfs_shell_snap.8
@@ -2,12 +2,12 @@
.\" Title: vfs_shell_snap
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_SHELL_SNAP" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_SHELL_SNAP" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_snapper.8 b/docs/manpages/vfs_snapper.8
index b3352a8..bd70cd5 100644
--- a/docs/manpages/vfs_snapper.8
+++ b/docs/manpages/vfs_snapper.8
@@ -2,12 +2,12 @@
.\" Title: vfs_snapper
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_SNAPPER" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_SNAPPER" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_streams_depot.8 b/docs/manpages/vfs_streams_depot.8
index 6e28159..eb59fe7 100644
--- a/docs/manpages/vfs_streams_depot.8
+++ b/docs/manpages/vfs_streams_depot.8
@@ -2,12 +2,12 @@
.\" Title: vfs_streams_depot
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_STREAMS_DEPOT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_STREAMS_DEPOT" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_streams_xattr.8 b/docs/manpages/vfs_streams_xattr.8
index d23f971..6d1f656 100644
--- a/docs/manpages/vfs_streams_xattr.8
+++ b/docs/manpages/vfs_streams_xattr.8
@@ -2,12 +2,12 @@
.\" Title: vfs_streams_xattr
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_STREAMS_XATTR" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_STREAMS_XATTR" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_syncops.8 b/docs/manpages/vfs_syncops.8
index 1c532d4..e54810e 100644
--- a/docs/manpages/vfs_syncops.8
+++ b/docs/manpages/vfs_syncops.8
@@ -2,12 +2,12 @@
.\" Title: vfs_syncops
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_SYNCOPS" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_SYNCOPS" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_time_audit.8 b/docs/manpages/vfs_time_audit.8
index 2e837aa..ba4071f 100644
--- a/docs/manpages/vfs_time_audit.8
+++ b/docs/manpages/vfs_time_audit.8
@@ -2,12 +2,12 @@
.\" Title: vfs_time_audit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_TIME_AUDIT" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_TIME_AUDIT" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_tsmsm.8 b/docs/manpages/vfs_tsmsm.8
index d4593cc..86bbd89 100644
--- a/docs/manpages/vfs_tsmsm.8
+++ b/docs/manpages/vfs_tsmsm.8
@@ -2,12 +2,12 @@
.\" Title: vfs_tsmsm
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_TSMSM" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_TSMSM" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_unityed_media.8 b/docs/manpages/vfs_unityed_media.8
index c429ac7..92e5647 100644
--- a/docs/manpages/vfs_unityed_media.8
+++ b/docs/manpages/vfs_unityed_media.8
@@ -2,12 +2,12 @@
.\" Title: vfs_unityed_media
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_UNITYED_MEDIA" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_UNITYED_MEDIA" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_worm.8 b/docs/manpages/vfs_worm.8
index 342f43f..d5ad1d3 100644
--- a/docs/manpages/vfs_worm.8
+++ b/docs/manpages/vfs_worm.8
@@ -2,12 +2,12 @@
.\" Title: vfs_worm
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_WORM" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_WORM" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_xattr_tdb.8 b/docs/manpages/vfs_xattr_tdb.8
index 6bb8d76..d480c62 100644
--- a/docs/manpages/vfs_xattr_tdb.8
+++ b/docs/manpages/vfs_xattr_tdb.8
@@ -2,12 +2,12 @@
.\" Title: vfs_xattr_tdb
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_XATTR_TDB" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_XATTR_TDB" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfs_zfsacl.8 b/docs/manpages/vfs_zfsacl.8
index 967d85e..cbc35a8 100644
--- a/docs/manpages/vfs_zfsacl.8
+++ b/docs/manpages/vfs_zfsacl.8
@@ -2,12 +2,12 @@
.\" Title: vfs_zfsacl
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFS_ZFSACL" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "VFS_ZFSACL" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/vfstest.1 b/docs/manpages/vfstest.1
index 918ec7c..8b38fb7 100644
--- a/docs/manpages/vfstest.1
+++ b/docs/manpages/vfstest.1
@@ -2,12 +2,12 @@
.\" Title: vfstest
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "VFSTEST" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "VFSTEST" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/wbinfo.1 b/docs/manpages/wbinfo.1
index 470e7b2..f2b96bf 100644
--- a/docs/manpages/wbinfo.1
+++ b/docs/manpages/wbinfo.1
@@ -2,12 +2,12 @@
.\" Title: wbinfo
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: User Commands
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "WBINFO" "1" "03/22/2016" "Samba 4\&.4" "User Commands"
+.TH "WBINFO" "1" "03/30/2016" "Samba 4\&.4" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/winbind_krb5_locator.7 b/docs/manpages/winbind_krb5_locator.7
index 49bc3d8..8ef27fe 100644
--- a/docs/manpages/winbind_krb5_locator.7
+++ b/docs/manpages/winbind_krb5_locator.7
@@ -2,12 +2,12 @@
.\" Title: winbind_krb5_locator
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: 7
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "WINBIND_KRB5_LOCATOR" "7" "03/22/2016" "Samba 4\&.4" "7"
+.TH "WINBIND_KRB5_LOCATOR" "7" "03/30/2016" "Samba 4\&.4" "7"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/docs/manpages/winbindd.8 b/docs/manpages/winbindd.8
index 9aef6bb..8ca6749 100644
--- a/docs/manpages/winbindd.8
+++ b/docs/manpages/winbindd.8
@@ -2,12 +2,12 @@
.\" Title: winbindd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 03/22/2016
+.\" Date: 03/30/2016
.\" Manual: System Administration tools
.\" Source: Samba 4.4
.\" Language: English
.\"
-.TH "WINBINDD" "8" "03/22/2016" "Samba 4\&.4" "System Administration tools"
+.TH "WINBINDD" "8" "03/30/2016" "Samba 4\&.4" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
index 9a3451f..73d4204 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -2614,6 +2614,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");
@@ -2629,8 +2631,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");
@@ -2653,6 +2658,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");
@@ -2673,6 +2679,7 @@ 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");
@@ -2809,6 +2816,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");
@@ -3315,6 +3324,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;
@@ -3349,10 +3391,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 b453aca..aa256c1 100644
--- a/lib/param/loadparm.h
+++ b/lib/param/loadparm.h
@@ -204,6 +204,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 1ebb2f8..d8d9144 100644
--- a/lib/param/param_table.c
+++ b/lib/param/param_table.c
@@ -33,6 +33,7 @@
#include "lib/param/param_global.h"
#include "libcli/smb/smb_constants.h"
#include "libds/common/roles.h"
+#include "source4/lib/tls/tls.h"
#ifndef N_
#define N_(x) x
@@ -125,6 +126,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"},
@@ -223,6 +238,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"},
diff --git a/lib/util/util_net.c b/lib/util/util_net.c
index d58855d..e5b33aa 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 2f1beff..29468b4 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 c58a23f..cc9ae33 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 e9eaadf..ebf6812 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 539b903..49645e0 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 1b294df..1230376 100644
--- a/libcli/auth/spnego_parse.c
+++ b/libcli/auth/spnego_parse.c
@@ -203,7 +203,9 @@ static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
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_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;
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index ad6a254..b635c14 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -382,6 +382,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 563a574..57915d9 100644
--- a/libcli/smb/smb_constants.h
+++ b/libcli/smb/smb_constants.h
@@ -95,6 +95,7 @@ enum protocol_types {
#define PROTOCOL_LATEST PROTOCOL_SMB3_11
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 e128e8f..a7bc819 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 af0863e..a59db13 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,
diff --git a/librpc/idl/dcerpc.idl b/librpc/idl/dcerpc.idl
index 1036693..015eb3d 100644
--- a/librpc/idl/dcerpc.idl
+++ b/librpc/idl/dcerpc.idl
@@ -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 5f3d653..fd8eeb4 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 4a9e7c2..f041e32 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 {
@@ -124,24 +129,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 {
@@ -153,7 +158,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;
@@ -167,7 +172,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;
@@ -184,7 +189,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;
@@ -239,9 +244,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 */
@@ -270,7 +278,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 f412ffe..f706efd 100644
--- a/librpc/idl/security.idl
+++ b/librpc/idl/security.idl
@@ -652,6 +652,15 @@ interface security
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 {
diff --git a/librpc/ndr/ndr_ntlmssp.c b/librpc/ndr/ndr_ntlmssp.c
index d024da5..7027ac0 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 e07ff15..5c979ff 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 d0acd6e..b9ccecd 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 2b90334..f386025 100644
--- a/librpc/rpc/dcerpc_error.c
+++ b/librpc/rpc/dcerpc_error.c
@@ -88,9 +88,11 @@ static const struct dcerpc_fault_table dcerpc_faults[] =
_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_CANT_PERFORM, NT_STATUS_EPT_CANT_PERFORM_OP),
- _FAULT_STR(DCERPC_FAULT_NDR, NT_STATUS_RPC_BAD_STUB_DATA),
_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
diff --git a/librpc/rpc/dcerpc_util.c b/librpc/rpc/dcerpc_util.c
index 696bcda..43e1b7f 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 checks for auth_length. The caller should check this... */
+ if (pkt->auth_length == 0) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /* 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;
+ }
- /* 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;
+ auth_length = DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length;
+ if (pkt_trailer->length < auth_length) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
}
- *auth_length = pkt_trailer->length - data_and_pad;
+ 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;
}
diff --git a/librpc/rpc/rpc_common.h b/librpc/rpc/rpc_common.h
index b03b9ff..bd0985a 100644
--- a/librpc/rpc/rpc_common.h
+++ b/librpc/rpc/rpc_common.h
@@ -187,12 +187,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);
diff --git a/nsswitch/libwbclient/wbc_pam.c b/nsswitch/libwbclient/wbc_pam.c
index 672cf37..0d1b90c 100644
--- a/nsswitch/libwbclient/wbc_pam.c
+++ b/nsswitch/libwbclient/wbc_pam.c
@@ -1286,7 +1286,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;
@@ -1384,6 +1394,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 0dffa4b..245162d 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 87b6943..1c5f678 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 at 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
@@ -24,6 +25,12 @@ 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
@@ -222,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):
diff --git a/python/samba/tests/dcerpc/dnsserver.py b/python/samba/tests/dcerpc/dnsserver.py
index 2b421d0..7229877 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 0000000..ccd0f6b
--- /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/selftest/knownfail b/selftest/knownfail
index 77d186c..1678cd0 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
@@ -94,6 +97,10 @@
^samba4.rpc.netlogon.*.NetrEnumerateTrustedDomainsEx
^samba4.rpc.netlogon.*.GetPassword
^samba4.rpc.netlogon.*.DatabaseRedo
+^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
@@ -208,6 +215,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\(nt4_dc\) # We fail this test currently
^samba3.rpc.samr.passwords.lockout.*\(nt4_dc\)$ # We fail this test currently
^samba3.rpc.spoolss.printer.addprinter.driver_info_winreg # knownfail or flapping?
@@ -296,3 +304,23 @@
# we can watch for set methods on.
#
^samba.tests.dcerpc.integer.samba.tests.dcerpc.integer.IntegerTests.test_.*_into_uint8_list
+#
+## 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/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-cert.pem b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-cert.pem
new file mode 100644
index 0000000..2e2a8b9
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.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 at samba.example.com
+ Validity
+ Not Before: Mar 16 23:29:25 2016 GMT
+ Not After : Mar 11 23:29:25 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Domain Controllers, CN=addc.addom.samba.example.com/emailAddress=ca-samba.example.com at samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:a6:c4:a9:bf:75:ea:4c:8d:3b:fd:8a:0f:b0:a2:
+ b6:c7:a8:1f:e4:0e:3e:41:ef:d6:10:48:77:7b:4e:
+ 4c:59:e1:bf:6d:c7:18:7b:a8:01:a7:d5:d2:2c:21:
+ 3e:d0:1a:da:58:03:e8:42:f1:53:0e:a7:91:b9:2c:
+ b9:e7:7a:c9:de:5e:ed:4c:93:6b:cc:dd:17:d0:c7:
+ d1:f1:7c:3d:0d:6f:df:5d:53:5a:b1:1f:a3:7b:5b:
+ 41:65:0c:7c:ea:53:df:bb:da:41:15:da:49:e3:b9:
+ 2d:bb:b5:af:ef:8c:b8:84:74:d0:18:16:8e:5c:e4:
+ c2:e7:a1:87:8f:e3:87:8b:0b:bb:90:30:e8:e0:f3:
+ eb:c0:50:5f:b5:7f:54:9a:1b:34:43:fd:be:5a:80:
+ 6e:0f:63:a2:b3:79:42:4a:85:c8:07:c7:82:55:23:
+ 88:d4:4e:03:2f:f1:95:bd:ed:15:2d:3e:16:cd:ff:
+ c7:9b:03:29:36:a6:5d:c9:1a:1e:89:a5:ba:66:83:
+ 0f:96:a8:07:9f:24:b9:1b:8f:02:9a:b8:50:29:8b:
+ be:63:45:fa:45:c3:38:23:a0:98:3a:b4:6b:42:99:
+ 13:36:4b:84:ef:27:89:39:34:79:f8:67:16:7b:9c:
+ 2a:03:41:15:63:46:e4:db:2f:f2:3e:6d:fe:7c:20:
+ 1e:9f:02:48:a4:bc:15:42:a6:f8:38:86:dc:6b:7c:
+ 4e:67:a3:31:81:8e:b6:30:1a:eb:3d:08:25:19:5f:
+ 42:dc:39:ec:79:1d:30:0a:fb:16:8f:3d:19:14:cc:
+ f5:af:d7:c6:75:cf:b3:96:a2:b2:9b:d9:03:01:a3:
+ ca:88:1d:72:ed:6f:d1:bf:57:56:8e:b9:07:9b:b9:
+ 04:13:1e:0b:5a:06:6b:2b:43:a2:dc:d5:b7:f4:ba:
+ d3:ae:9d:ad:fd:d3:8a:7c:2f:87:32:fa:89:88:58:
+ 00:ae:16:2b:9c:1d:58:82:4d:e5:21:da:d5:6c:f7:
+ a8:40:8b:c7:02:d5:36:30:ef:3f:09:9b:a6:d2:31:
+ a3:bf:20:d4:a2:9e:26:c4:b4:c3:0f:0b:6c:00:d1:
+ 2c:16:b1:2a:eb:06:d9:d5:98:c3:cd:cb:20:68:ad:
+ 0a:2c:a1:2f:27:41:5c:91:de:49:62:ed:d8:3a:ef:
+ 68:1c:6d:fe:94:c3:28:68:32:60:08:65:cd:02:9f:
+ 97:96:2f:0f:87:27:3d:b9:0f:85:62:e8:2b:9a:b4:
+ f4:d3:d7:c1:93:96:27:23:29:88:b1:39:99:53:3a:
+ 20:aa:88:44:3b:4a:24:2a:8b:e0:b4:8d:dd:66:30:
+ df:a6:6e:b7:fc:21:43:16:9e:3e:12:20:c8:7a:30:
+ c1:3d:ab
+ 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 addc.addom.samba.example.com
+ X509v3 Subject Key Identifier:
+ 3D:BC:70:0C:74:D4:B8:85:49:1D:08:84:C4:1B:27:F2:AF:72:37:D3
+ X509v3 Authority Key Identifier:
+ keyid:A2:3E:02:2A:A3:A7:4D:39:B4:08:4D:99:CC:0C:75:36:EA:27:C3:3E
+
+ X509v3 Subject Alternative Name:
+ DNS:addc.addom.samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com at 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
+ 9e:8b:bb:0a:7a:dc:c0:94:33:bc:18:a5:e6:4a:1f:ff:8e:21:
+ b1:8f:33:f0:3e:8b:6c:72:55:c4:47:71:5f:ce:e7:31:ef:5b:
+ 62:04:b7:57:8f:a8:27:9f:ed:69:d2:ec:a8:0d:e2:76:33:8d:
+ 41:3a:67:61:5c:53:60:c7:53:ed:d7:99:72:29:1d:ae:d3:ee:
+ c9:76:1c:6d:18:47:e9:94:dd:2e:97:3f:99:af:b5:f4:a1:7c:
+ 92:f6:4d:b5:c1:7a:0c:38:ba:d1:b6:19:9a:9f:e2:02:84:d4:
+ 54:01:38:7b:55:86:4a:ee:3d:85:48:01:da:34:09:69:43:25:
+ 7e:6e:06:73:e0:b9:7c:b5:9c:4e:9c:b5:52:85:32:62:62:25:
+ 39:fa:02:4b:51:2e:df:8e:52:17:02:50:f4:99:29:bf:7e:97:
+ 53:91:12:85:9a:69:62:45:59:c4:5b:3f:af:18:e6:7b:e4:86:
+ 5d:f1:9e:5a:2b:3e:14:6e:7e:d4:47:24:ef:d9:a8:ec:d9:a6:
+ cb:b8:4f:1a:86:d9:43:20:41:16:15:5f:81:0d:fe:6b:31:53:
+ c1:f6:84:4c:f3:03:64:d2:e6:44:3d:7a:60:79:d7:37:6f:33:
+ de:c0:a8:b9:6e:fe:b2:79:ac:b4:53:92:b8:0a:59:2b:cc:6b:
+ 37:c4:6f:c6:44:02:f7:7c:c5:c6:a6:6f:c2:ad:de:78:1e:48:
+ 96:cc:fe:59:2e:53:ce:34:d6:e8:f0:56:43:30:32:90:6f:f9:
+ 47:76:ab:99:63:e3:e8:a3:f3:83:98:e9:05:2b:ea:f9:f9:9d:
+ 66:70:c7:2c:00:c2:9e:57:3e:31:43:50:50:c8:db:a8:2d:21:
+ 4e:6f:39:c2:bd:ef:d8:47:99:27:0d:48:b2:58:f1:be:45:bd:
+ fe:c4:a2:56:fc:06:02:dc:19:33:85:53:ed:38:59:01:16:bc:
+ aa:c5:d3:4b:37:54:83:1b:e5:c1:4b:dd:34:6b:e5:d8:35:86:
+ 95:e6:9f:d2:22:84:b1:e2:4f:a7:2e:4d:e6:9c:eb:db:df:42:
+ e1:b4:66:e6:58:d3:28:10:34:97:f3:9c:6b:5f:05:2c:47:2c:
+ e3:75:eb:6f:74:0a:ec:d7:1d:30:80:56:44:12:26:f6:4e:5f:
+ ff:92:f4:62:02:36:9c:62:eb:39:98:53:68:68:95:fb:94:68:
+ 69:b8:3c:66:1a:ce:78:c4:cf:c4:6f:21:ac:a8:a6:f4:ab:69:
+ 2a:2e:00:5d:f7:67:06:b1:4f:97:58:88:55:d8:6e:eb:a5:98:
+ 50:36:21:70:3d:b0:a4:f5:3b:21:b3:1c:f5:a9:dd:c6:4a:c2:
+ 89:b8:5a:b3:bc:1f:21:ce:4c:68:5f:98:d8:39:70:d2:7e:a0:
+ 90:df:ad:a3:13:eb:3c:93:f6:b8:f4:d9:a7:51:b3:0d:ea:ee:
+ d4:57:aa:db:ca:7c:8a:a0:08:c3:98:9a:3a:b7:ba:2a:50:92:
+ 26:c2:e3:11:ba:12:60:24:b9:59:df:62:a8:d7:4d:a3:cb:ea:
+ 46:e8:39:f9:83:14:a8:5c:44:75:71:6b:7f:99:bd:68:58:d9:
+ 6b:d1:cd:c7:45:95:9e:44:1e:85:35:c0:30:2b:18:aa:eb:2f:
+ 93:d5:be:66:5d:70:ed:1d:04:f2:c1:1e:b5:ec:45:0c:04:f6:
+ 9d:88:d3:0c:20:5e:5b:23:df:34:a1:f5:ea:b4:a1:44:c0:da:
+ d5:ea:89:e8:b5:cb:dc:f8:92:ee:ac:8d:61:ed:bf:74:2b:28:
+ 79:1f:f4:9a:ff:63:bd:e6:aa:79:1d:2c:26:4a:b2:26:53:57:
+ ba:88:0e:eb:19:57:c0:10:a0:1e:81:2a:c0:56:2e:c3:2a:81:
+ bf:c1:5a:e7:48:ce:c1:6a:b9:6c:41:cc:44:a6:b8:70:e2:57:
+ 0e:6d:41:d6:61:da:bf:ac:20:2c:a7:2a:67:23:98:00:ba:ce:
+ 8b:a8:c2:45:66:a7:08:eb:7f:0a:b5:e7:9b:d6:f4:07:d5:b3:
+ 43:cd:27:d4:fa:c9:40:8f:af:b2:36:1c:e7:44:b4:4e:cc:5a:
+ 2b:73:ad:8f:c4:d9:47:a6:fb:2c:7d:1a:80:2a:55:b3:80:34:
+ 6f:8e:17:27:93:05:21:40:e9:8f:bf:47:6a:52:f5:2e:b5:18:
+ d1:8c:1d:83:04:80:55:fd:21:28:dc:7c:be:c8:c1:5f:e4:40:
+ d3:13:e4:66:bf:ad:92:4e:9b:db:c1:be:a3:42:74:da:c3:2c:
+ 0a:da:3f:94:14:ad:7e:de:81:c6:01:6a:f7:7a:b4:25:51:b0:
+ ab:cd:b3:3a:77:bf:c3:6b:04:44:30:73:41:ad:93:49:67:ee:
+ 43:d1:96:8e:36:83:2b:1b:6c:e7:cc:3e:d6:16:b9:88:4a:ab:
+ 56:c0:76:00:f6:9a:6a:8a:e3:e0:41:75:9d:3b:47:0f:c9:0a:
+ 8e:9f:9c:00:92:bb:ae:d8:42:56:35:64:eb:59:13:da:2c:63:
+ 83:c3:ec:68:91:b5:f3:71:85:48:54:c3:9d:a1:c8:63:f3:de:
+ 5d:a5:34:a9:1e:85:2c:2c:b5:d8:a9:62:8d:26:1f:b2:9e:a7:
+ 83:4d:df:69:63:b5:b7:e5:dd:e7:3b:18:e5:b3:77:df:c5:47:
+ b3:f7:8c:e7:5e:87:2e:46:e3:8f:b1:2b:9b:c6:26:2d:1a:28:
+ 30:13:10:86:5b:46:87:b1:2d:12:ce:b6:fe:1c:4e:44
+-----BEGIN CERTIFICATE-----
+MIIJ9DCCBdygAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTYyMzI5MjVaFw0zNjAzMTEyMzI5MjVaMIG4MQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEbMBkGA1UE
+CwwSRG9tYWluIENvbnRyb2xsZXJzMSUwIwYDVQQDDBxhZGRjLmFkZG9tLnNhbWJh
+LmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkBFiZjYS1zYW1iYS5leGFtcGxlLmNv
+bUBzYW1iYS5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAKbEqb916kyNO/2KD7CitseoH+QOPkHv1hBId3tOTFnhv23HGHuoAafV0iwh
+PtAa2lgD6ELxUw6nkbksued6yd5e7UyTa8zdF9DH0fF8PQ1v311TWrEfo3tbQWUM
+fOpT37vaQRXaSeO5Lbu1r++MuIR00BgWjlzkwuehh4/jh4sLu5Aw6ODz68BQX7V/
+VJobNEP9vlqAbg9jorN5QkqFyAfHglUjiNROAy/xlb3tFS0+Fs3/x5sDKTamXcka
+HomlumaDD5aoB58kuRuPApq4UCmLvmNF+kXDOCOgmDq0a0KZEzZLhO8niTk0efhn
+FnucKgNBFWNG5Nsv8j5t/nwgHp8CSKS8FUKm+DiG3Gt8TmejMYGOtjAa6z0IJRlf
+Qtw57HkdMAr7Fo89GRTM9a/XxnXPs5aispvZAwGjyogdcu1v0b9XVo65B5u5BBMe
+C1oGaytDotzVt/S6066drf3TinwvhzL6iYhYAK4WK5wdWIJN5SHa1Wz3qECLxwLV
+NjDvPwmbptIxo78g1KKeJsS0ww8LbADRLBaxKusG2dWYw83LIGitCiyhLydBXJHe
+SWLt2DrvaBxt/pTDKGgyYAhlzQKfl5YvD4cnPbkPhWLoK5q09NPXwZOWJyMpiLE5
+mVM6IKqIRDtKJCqL4LSN3WYw36Zut/whQxaePhIgyHowwT2rAgMBAAGjggH3MIIB
+8zAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly93d3cuc2FtYmEu
+ZXhhbXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMBEG
+CWCGSAGG+EIBAQQEAwIGQDALBgNVHQ8EBAMCBeAwSQYJYIZIAYb4QgENBDwWOkRv
+bWFpbiBDb250cm9sbGVyIENlcnRpZmljYXRlIGFkZGMuYWRkb20uc2FtYmEuZXhh
+bXBsZS5jb20wHQYDVR0OBBYEFD28cAx01LiFSR0IhMQbJ/KvcjfTMB8GA1UdIwQY
+MBaAFKI+Aiqjp005tAhNmcwMdTbqJ8M+MEAGA1UdEQQ5MDeCHGFkZGMuYWRkb20u
+c2FtYmEuZXhhbXBsZS5jb22gFwYJKwYBBAGCNxkBoAoECAEjRWeJq83vMDEGA1Ud
+EgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0G
+CWCGSAGG+EIBBARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMv
+Q0Etc2FtYmEuZXhhbXBsZS5jb20tY3JsLmNybDAmBgNVHSUEHzAdBggrBgEFBQcD
+AgYIKwYBBQUHAwEGBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggQBAJ6Luwp63MCU
+M7wYpeZKH/+OIbGPM/A+i2xyVcRHcV/O5zHvW2IEt1ePqCef7WnS7KgN4nYzjUE6
+Z2FcU2DHU+3XmXIpHa7T7sl2HG0YR+mU3S6XP5mvtfShfJL2TbXBegw4utG2GZqf
+4gKE1FQBOHtVhkruPYVIAdo0CWlDJX5uBnPguXy1nE6ctVKFMmJiJTn6AktRLt+O
+UhcCUPSZKb9+l1OREoWaaWJFWcRbP68Y5nvkhl3xnlorPhRuftRHJO/ZqOzZpsu4
+TxqG2UMgQRYVX4EN/msxU8H2hEzzA2TS5kQ9emB51zdvM97AqLlu/rJ5rLRTkrgK
+WSvMazfEb8ZEAvd8xcamb8Kt3ngeSJbM/lkuU8401ujwVkMwMpBv+Ud2q5lj4+ij
+84OY6QUr6vn5nWZwxywAwp5XPjFDUFDI26gtIU5vOcK979hHmScNSLJY8b5Fvf7E
+olb8BgLcGTOFU+04WQEWvKrF00s3VIMb5cFL3TRr5dg1hpXmn9IihLHiT6cuTeac
+69vfQuG0ZuZY0ygQNJfznGtfBSxHLON16290CuzXHTCAVkQSJvZOX/+S9GICNpxi
+6zmYU2holfuUaGm4PGYaznjEz8RvIayopvSraSouAF33ZwaxT5dYiFXYbuulmFA2
+IXA9sKT1OyGzHPWp3cZKwom4WrO8HyHOTGhfmNg5cNJ+oJDfraMT6zyT9rj02adR
+sw3q7tRXqtvKfIqgCMOYmjq3uipQkibC4xG6EmAkuVnfYqjXTaPL6kboOfmDFKhc
+RHVxa3+ZvWhY2WvRzcdFlZ5EHoU1wDArGKrrL5PVvmZdcO0dBPLBHrXsRQwE9p2I
+0wwgXlsj3zSh9eq0oUTA2tXqiei1y9z4ku6sjWHtv3QrKHkf9Jr/Y73mqnkdLCZK
+siZTV7qIDusZV8AQoB6BKsBWLsMqgb/BWudIzsFquWxBzESmuHDiVw5tQdZh2r+s
+ICynKmcjmAC6zouowkVmpwjrfwq155vW9AfVs0PNJ9T6yUCPr7I2HOdEtE7MWitz
+rY/E2Uem+yx9GoAqVbOANG+OFyeTBSFA6Y+/R2pS9S61GNGMHYMEgFX9ISjcfL7I
+wV/kQNMT5Ga/rZJOm9vBvqNCdNrDLAraP5QUrX7egcYBavd6tCVRsKvNszp3v8Nr
+BEQwc0Gtk0ln7kPRlo42gysbbOfMPtYWuYhKq1bAdgD2mmqK4+BBdZ07Rw/JCo6f
+nACSu67YQlY1ZOtZE9osY4PD7GiRtfNxhUhUw52hyGPz3l2lNKkehSwstdipYo0m
+H7Kep4NN32ljtbfl3ec7GOWzd9/FR7P3jOdehy5G44+xK5vGJi0aKDATEIZbRoex
+LRLOtv4cTkQ=
+-----END CERTIFICATE-----
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-key.pem
new file mode 100644
index 0000000..6f11ced
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-key.pem
@@ -0,0 +1,54 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIJjjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIpUlK4cdzu/UCAggA
+MBQGCCqGSIb3DQMHBAju3WkqK++BQgSCCUit3hNjGErKHafSn7CLnhKlNTzvtaAv
+PwTStReWMNULMJ6Z1Rhm0jO8x5BBStEHy3A4h1GmWNSyIzOhZqGi3K2SqpBa9+TP
+SSYzeNKCsv/06QeQ3GTJJF2GTKLw8I2tZOJnNy5wYprGDuz92AAncj645C8xBYb/
+RgN1YyHh3B2tkPlOVZZU8z8hH9iaDwKiXfY0+EgVDSCj1pHWKEzGzhx4UtyKhCc5
+1J4fyPA+8SzJ0tRAohLHdrm9KIn/tawbbS6Ce8iwLBad6A4k73WgYW4ZawMA+n1X
+OIhyCR/dfIlPRPcojyN4c2O5uPmGCDErt6awUY7LyctZPRAUBbk83i69HbRvK/kq
+JuyhTIWUbhVpvt6HZxCC0cFBy7tlSeOL3LXlu1JoWAEqCVm8vHQPs3WTwTTrShHP
+kauortTdLstddxqPwWKmUcSLcviK+IfD54y3fJGYMr5goLdXCGfb7XZQoXANIYKP
+di/jXOn6PTjKdC7/J8G0UZmRmjEvxp5CBPiNqr07YJUfu7IN4KxEKRf/aDyJ1npw
+JEaMFiBvFx0Vr5nm7trQ43TdkuHbn7MY6nkPMbzC8a8KcKFGbnU/n6TIyeGYo2o5
+2ICW3QmXjzhrWiDzU+cEbSEs77UAQJNrSxRVuKKuwLEnuy6/pRhlxex6Hp6nNCOd
+dTZKDeqHsntRa6zTuOleh+XOMHeSuHjhJdThxEszHPFsYzH/EtE8TaKiBQE9kecy
+M+nbxfMqRTYitsl8wTPiuoTgrzDjUJcAAsS/jDNYUA63NCG2BT9Gq9qY48DwfWGM
+YPMYj6CfRwsyAPSeC7hV31olnGAp15kBhM2TpxE6KqUnGuxL0ET9LJsHjaRsP+r1
+KMjNmibQSy948LIvHhEtdfg5/Jn5jv6JHmmSBktma4C+MUfQKBinzy6MM1IAaZlZ
+hUdL14VnERFh9OGLjZGBOBlk/9FU2Yf4lfAtLgT95GezlYQIOqpG/Pkm04wH71+W
+bfW+53gBQqcaSexM5QFsqRspq7yyLX0mElG6z5gOmEJN3rV+DZ2d+84dxKQ5rX++
++mLYlfQKe1K/1F8HVXH/1ZMeAkzvxk1Odlm6fhwcTHciX3CSESAtJeLSD3PNgSE1
+f0Lep/CteZecOnM63T454jC4V49qXYgQBD32WuOHIbFhHd/lQ5Zj+3T5LgKlE5H3
+5oTUU/+DFgqFrwHlM5f1Ha9G8rjuHucjHyQ7ix7jNjEIoG82It8ESisIOoOwb3bc
+Jjkfj3v7f5Axi0wyD94KLFntBCI64uhyTk+JuvagA2KnLQ5uWEFRgqhMXRNg3kbI
+STOAopjoB2bnIvQZxQ8hxOT67EjKd7iJJXh2zfBAQ7dvnVKznvdSamTcB/Uh3IQR
+RjOZE3ej3lEb4XCM2NCyqZvFgoU+Og4yg+4yainCE+6Jt1jYNvms2iabxC+ZQZ3t
+/vCgVDvnULX5FJvphGK/Idua5FFIeSNLOoK9qjfrBNL9kdFVMWCyMyK0cIdsZFRp
+2at32a9n8OU1rRYgFn8kaWK4JQqKelm1qVCixcHLUtI/cyp+t7vvjOGRnDrbfoK0
+ae+pt0De0aBsOMKmUetn3CXFXIyQa/FJ3W8X7yl82ctS3ZZmWcND0Lqhoa1JADdj
+vbxxGzh1rJPsuPePwIXAVqtbVJD84i+dP0+i1oR/e5jNgRKj0tJcfZnnsvmSIldY
+FvxDpIX2h/tDrTKfwQzFHBBuPA00ZuGfftGc4LD7SOVjVb6CF2GMX/0+zmKlPf56
+FvxvGl+GwLPz/BaSGlT/4DApF0HJEZ1AeSvzHGhdgWecbk4s/lMAnv17vH2YWql1
+uJ54FgDAT0ufzAb0aHAl3YO8pYDOOXGqHaqWRMJvtuh15FB52HYvt+Ojo2mzPu4j
+lvUcOBRMzgPl8zcs0L/WgE0SggC6DpXGU+rK1/J91qlNRBJ664R6j0iyskPvdzYN
+aJ8ZZSJ+yQPralfSD/Sd+RcRviP2draINoyVbFHSH2zvvhcZc0ETL24tNI/tSXpR
+Cw86CajiN7T691pC3eZyQLSQJnMSY/0F0i12KU3J+1kq6eeMSoPc5EKItfH5wxjw
+RPnJAU84HGIQEAhEn6Ht1XaZcMfo9xyr9WMpmyH4OoTLt1+gFGgSCfbjsusl9aNl
+EDhcYmav8OFHE48qvEoYyHD7S3fwsxKFSCJpYTRweBRQaEzpq1z90tVxzhLZFpJe
+A7sw/HpiOuty0hDHQ5JaiRBsQ+CiOsVdWZXzaI/H0aoaPbLbpursuTPPPG5OFqvL
+WIIDfFYZ9rhy8t/YaAeTyFoLx1VU7m88ZZndyaVXhnqp7iaU14NXlelPeyKJ3ZXc
+pd6gZ4l1XAJHbeyiBx+6khtZb6JTLbYpwfbjTqPmDtNw2PVb5rwF0ZSeP6LXKOEM
++WntayDMbWK67yUCBlkPTpY4k+8nV8pJ+th9sR8LlL7d9rZgbSjmxG8XgjC7HHg+
+4I2O7poGQMVgtMeIsGZRIS0cTpm1dpCRfFQPR0DOB6+wjDRPIRNNiTZQYdkpfHQ1
+QSpCskaWG9HzJQGSu+meN4LdaKEoXwNMMz77fCTWhXXkvy6Ujm44EpOOfaHXpg7T
+AQagXzyII0xXj+rAFkqmnyygWgxpou6f3MkoWxIC/qYocC4Ci3oWMAZVssWfnhoP
+T/ZormTZN3uQCZYtfwTjbjh5efFQc4I9THxkHV6eyhGE7MQO/D/5zjBzkwmNsU6b
+GttZyyHto+oKlXMF9dNKxLkQbtVO8ZDIDuNP+sb/m7wj3GG2MNoklp6Cd7lckimv
+PqkQP7PQa8h6EeFXmTKqi7vfgsQAEIzTfOLJDvfHhLC54pjbFPR8vY0T5Y2Dwe8w
+rMPwFenW1ae6DjeGDHij3+QbQmTYZeu8Hblhs5DNhy7wtZX05IUsioVfJLC9QngN
+Y5u7OuMGQLPdcPjWHBuZsl/lMdii1lOB/PrExrEIsybSGPQonDfK6x1pOeyIJsbr
+fDnevcamxLpG6BU8U7AqE1QHa/sJGNO/lgsHGLrb5A2id1J+VttSxSG09sML49uw
+T+vmgdVbVjsYRvMSjMfwRrVp4NARlXph5FUA2DxAKXvr1reicAleVgQDcokAHhLi
+vGZ34XFIZHB+YZvHxd3tZxLcKvAMZQJTPlO6RdD9cx+84DEfevaJilUjyu6Ga4ty
+HjA=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-openssl.cnf
new file mode 100644
index 0000000..bdd0364
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.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 = addc.addom.samba.example.com
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_default = ca-samba.example.com at 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 addc.addom.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=addc.addom.samba.example.com
+otherName=msADGUID;FORMAT:HEX,OCTETSTRING:0123456789ABCDEF
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-private-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-private-key.pem
new file mode 100644
index 0000000..eec21e4
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-private-key.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJJwIBAAKCAgEApsSpv3XqTI07/YoPsKK2x6gf5A4+Qe/WEEh3e05MWeG/bccY
+e6gBp9XSLCE+0BraWAPoQvFTDqeRuSy553rJ3l7tTJNrzN0X0MfR8Xw9DW/fXVNa
+sR+je1tBZQx86lPfu9pBFdpJ47ktu7Wv74y4hHTQGBaOXOTC56GHj+OHiwu7kDDo
+4PPrwFBftX9Umhs0Q/2+WoBuD2Ois3lCSoXIB8eCVSOI1E4DL/GVve0VLT4Wzf/H
+mwMpNqZdyRoeiaW6ZoMPlqgHnyS5G48CmrhQKYu+Y0X6RcM4I6CYOrRrQpkTNkuE
+7yeJOTR5+GcWe5wqA0EVY0bk2y/yPm3+fCAenwJIpLwVQqb4OIbca3xOZ6MxgY62
+MBrrPQglGV9C3DnseR0wCvsWjz0ZFMz1r9fGdc+zlqKym9kDAaPKiB1y7W/Rv1dW
+jrkHm7kEEx4LWgZrK0Oi3NW39LrTrp2t/dOKfC+HMvqJiFgArhYrnB1Ygk3lIdrV
+bPeoQIvHAtU2MO8/CZum0jGjvyDUop4mxLTDDwtsANEsFrEq6wbZ1ZjDzcsgaK0K
+LKEvJ0Fckd5JYu3YOu9oHG3+lMMoaDJgCGXNAp+Xli8Phyc9uQ+FYugrmrT009fB
+k5YnIymIsTmZUzogqohEO0okKovgtI3dZjDfpm63/CFDFp4+EiDIejDBPasCAwEA
+AQKCAgAloAU0PyRHdS3tu/JiRbO7RAE98MC3G6dOMStT1IyBUt9foyWw8Gy/Mwyi
+DDYhuY09glQqlkvI6KGGB8NBqIBW/U/IkRInPFKdNhf1xbP4jh707VNu1taJhEMy
+yyh7rcSym0FH7uHw0NyylwFEqJkQuVIhvSUNbEdU/yqYmhsAkfsVQxOnfSDZWMjf
+KAUsZ6rZFCyYOpWaPz58A4WjTp+csbSEBOpgC+HINVc1bIH0nSeD/otIO+RWgh5y
+usPdBlkRu8wOj4Z4r05cG13ZDnB3jyG7QBSBHNRTpW3zALWaZvLgsxUg5+ib0W0b
+UBbQeKE57rsmlN4ZXa3ny+U4l/6QQDSMtrWPNBCMrkt1Q/52gQk1IGeONUAQdLQT
+uBx0Vdn5ZvIFRBnkQl2KWOBWTdD2v0qxIHhXlsWX7tGVU7eh3GIAPoFzQZFHpPhA
+RObE8fNg/3HMVGDUwXnd4k+6c1t+Ioa17FuLJE4lr5c55Klq2lJ4Oq2Jd6AfoGjv
+anA45ChI6lrg2Kt7OhUEHIIHyZmm7eNmBHoGA3r+YJyiQQIGSiNjH+Up54KWa88z
+p+ZY1u3VdOiNuKVlRn79q85Th4HyMlx7wuY+t8HAj42Vt03Uy7iDaaTfuPxehMyS
+MqcRWR5MhavR5ShTtsIXwvUgWj/YcqaOb9Zfe2Y1RgFURKN3YQKCAQEA0I1hTnGs
+KE5l9dGowKm2io6pZr8J2B8ITjp8pdAaY46Ws1tfcTkbbpBUvyrflCIgLIP9KTP3
+6cc4HrK11mf8rPD1pHNWJd7CjPTLQFMYu+h8YlBqKwrgA8owLzUWG4omS0vehCnG
+6OIPi8ceUc2u6XW+TGKP4n8GXJrrKaw9hw83u6h9YQCpgfwF4QpwX8LzTMKnI7te
+HxUQFlhKX3vci+dP4n29c6yGl57830E7LeQGRfjo/NAV3pAAcHk79cEzOJQCN1Wy
+bNU2kcoOA3tGTI8tCfBdwpN11Sz2/tu4ytJE2weP5S7r9xOTq8t+iKQ9+NLhAvJU
+8S2mIkyFAi8tWQKCAQEAzLWsJ3qxyaLHv4tOFTqenSj0CbB25OIzDQNLT++L4fYn
+YAqL6/G83bRVbdYvfJ3ZdZdnseluGrR8ZcxdqioLCws66+O1vC8GkHI5aBKZt4MD
+Um+SzD6ZnARYcTbtRmPUJHxIdny2dbYLe5dDlqTFIV+olWDR+1YMSzXt/VW+jx9I
+tHhw8LJAxhMhDt0Gh+CxNFHQYdkdK/OuNTBufT/rxeT3E5t3TbSG29pU/F2Rce1G
+CCy0nbFsTMjPusSzwFJILWHdvBAYJceOajvqZhlaTV11u/qrj9gb+nJkH+rKvJnA
+pK2YyFWqomnGCZB61Y5LOfjk2b1BfVGCdqpRrBCOowKCAQBun3/NB1jlbGiDEvor
+cBpmtrO+z3jeTd+u9zElFxTYWEsxyjb/LOaTKDX7zTcZMVzVoBGKaImJVOY8yljP
+6QrLhWkXGSLKJbYW5MZnUWyeR/yqfbNDL5qSCA61C7i1VPtpF05p1msvHrJWV4GK
+rMqqBY2yoNlnsC9ksbwpt7ZPTNAoV4BiEuLXEyLfMxVWhmdeASZ9Oqb7X8XPxHd2
+3JGpGEJ0hnQWxp4CERBbMBO/DOQS+6xCZfIjw0ioYHZgrmGIEmJ2jZt+RT6T6JS0
+XhB1DcE7M2fYjTWEpTxDBbOoyg5CDGnUjKYXwiejieaNfmls8hbu5DIQWEF2khY/
+iVzJAoIBAENOiGgCo2oUp3CHMQkx2Oz7hiGZb74Z0Yc5yg1iSa/l61Rco1zUgrCy
+llQi1EI49EMBoQqSIa2OIkimRTWp1S+wZZMhr6NMIvBjXhSl6Py5iuIT5URaYM83
+bozq7mDyedH1Oy4aGzPgwy3DsmlZi6dJeHiE+QWWaTxhYvqksp8EPjd4UkoRkdKO
+f5QPgBI1Ao6dR9KkPD8zQ9ghMHLmDXNnsQU1XKij7qNiygagDS5UQW52pHwk1eL5
+M7PI8QEPDMQ/JVSsRgRF9MFhKdSgCVzemdNQvA/zkl9qNRl5bWdNdlWu7kkQQaZc
++Mw0QO7udjV9bGFbJKk7n5W8slXMq9kCggEAJ2yzyZKdQZtuXpf6WN6sNqRJ6CHo
+k9en+acEg9Y+5lVt2CRblprQxhdUV2KyN7G8GxV0hMwmHtMTeB4j6jhdZrAAZGVW
+upqCfY2vSYQ/svCeB0Fs5DMEI4iCS5Drn8gKKi/zWAbox9sb+zaYT/Ot5p2Ki/HH
+YIh+p8EE6IFWE3jChabPQieXVOC7tg/qaxWVHTv7Qe2fdZTY3XifTcN7hVghf/bH
+Vn+VdU2u/7hE7X3y9YNETNSin5U3F0BSm1tUQimUzU50+9Nl2UGPBI39e+15qRz7
+JHocpq9h9+k3T7qWwJxX74YhcTqdb1pGsKUEmo7r6rPR4L5h5nCF3OgR9g==
+-----END RSA PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-req.pem b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-req.pem
new file mode 100644
index 0000000..5b356fa
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-S02-req.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIFEjCCAvoCAQAwgcwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTYW1iYVN0YXRl
+MRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNhbWJhU2VsZlRlc3Rpbmcx
+GzAZBgNVBAsMEkRvbWFpbiBDb250cm9sbGVyczElMCMGA1UEAwwcYWRkYy5hZGRv
+bS5zYW1iYS5leGFtcGxlLmNvbTE1MDMGCSqGSIb3DQEJARYmY2Etc2FtYmEuZXhh
+bXBsZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQCmxKm/depMjTv9ig+worbHqB/kDj5B79YQSHd7TkxZ4b9txxh7
+qAGn1dIsIT7QGtpYA+hC8VMOp5G5LLnnesneXu1Mk2vM3RfQx9HxfD0Nb99dU1qx
+H6N7W0FlDHzqU9+72kEV2knjuS27ta/vjLiEdNAYFo5c5MLnoYeP44eLC7uQMOjg
+8+vAUF+1f1SaGzRD/b5agG4PY6KzeUJKhcgHx4JVI4jUTgMv8ZW97RUtPhbN/8eb
+Ayk2pl3JGh6Jpbpmgw+WqAefJLkbjwKauFApi75jRfpFwzgjoJg6tGtCmRM2S4Tv
+J4k5NHn4ZxZ7nCoDQRVjRuTbL/I+bf58IB6fAkikvBVCpvg4htxrfE5nozGBjrYw
+Gus9CCUZX0LcOex5HTAK+xaPPRkUzPWv18Z1z7OWorKb2QMBo8qIHXLtb9G/V1aO
+uQebuQQTHgtaBmsrQ6Lc1bf0utOuna3904p8L4cy+omIWACuFiucHViCTeUh2tVs
+96hAi8cC1TYw7z8Jm6bSMaO/INSinibEtMMPC2wA0SwWsSrrBtnVmMPNyyBorQos
+oS8nQVyR3kli7dg672gcbf6UwyhoMmAIZc0Cn5eWLw+HJz25D4Vi6CuatPTT18GT
+licjKYixOZlTOiCqiEQ7SiQqi+C0jd1mMN+mbrf8IUMWnj4SIMh6MME9qwIDAQAB
+oAAwDQYJKoZIhvcNAQELBQADggIBADLgdZz1gvzpnZPwd5KCxjwKgiotlUGBh6t6
+cLhyomCN02adMr0PPJP/n3r1Zsaq2db/zktP8J5fUYqA9vJZzYukzkKRHbl+rdHS
+JVEvHmbsG3729V9cy40kuL0EAM0weBbfQZaeFxfcLxl5v14QOxvldrmYSK5GaLh8
+WSEz4uljrI8ee3q8Cn08xlZ2Dr3MoHI9unEcLJFXkpCwVBALFhw5dG8od3jl8AyS
+WeMVbdD9fm4jnHE/RDSPDqUqMCGIYmrB5amGO5rSLDTWxDxrcHFRM7sa359nW2IA
+GoZd+r8Vf2AZ8i/KRgH7uIFB2BJm4L0QiVlajy3odW3zhQIVXNh9p58aGzOFQGkq
+Gsld4WI3gZZeSvGgGIjoB2+AYRjxTzUn5qSFVev5sFLK3cNdPZo66xltuPBhfXB/
+v/+/TQC80oZ8oZGdgYvBBT1IEg4pwB5Myqeps9J7kbJVmtxR2EGlq/aGN0yE/fy9
+S8ners0iXBJP18suSwbjj2unZQMBYLIgHLkzztxAMGYBlfEljSAvDfFCsK5Rkmya
+soxd1qHHMG8Ap+WZagpkK9tv42HwmbYKVeDArGAHr53aC4ripgrSBnzpmkiSyi4p
+mb3L5K/ZSOxo3xrS0wERq3p6FalF8/AhctgzWOgMvikVoTUy0xPsG/hulXPyk2UG
+rYn+WPQz
+-----END CERTIFICATE REQUEST-----
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-cert.pem
new file mode 120000
index 0000000..43b4b51
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-cert.pem
@@ -0,0 +1 @@
+DC-addc.addom.samba.example.com-S02-cert.pem
\ No newline at end of file
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-private-key.pem
new file mode 120000
index 0000000..3170fe7
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/addc.addom.samba.example.com/DC-addc.addom.samba.example.com-private-key.pem
@@ -0,0 +1 @@
+DC-addc.addom.samba.example.com-S02-private-key.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-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 0000000..7b1b6a1
--- /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 at samba.example.com
+ Validity
+ Not Before: Mar 16 23:28:44 2016 GMT
+ Not After : Mar 11 23:28:44 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Domain Controllers, CN=localdc.samba.example.com/emailAddress=ca-samba.example.com at samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:e6:a4:76:ce:e8:63:fe:57:f9:a3:ae:e0:ad:4d:
+ e2:15:8e:d8:27:c8:7d:7f:2b:b1:e8:aa:50:8f:94:
+ f9:c7:71:3f:52:32:91:d1:6d:52:22:5f:cd:8d:cc:
+ 62:16:7a:8b:58:65:ed:07:f7:ea:24:d3:88:d8:26:
+ ca:eb:ec:16:a7:84:1c:7e:15:46:64:09:22:46:b9:
+ dd:5c:07:84:50:a7:4e:31:3f:01:23:d1:f8:36:04:
+ 1a:bb:d4:e5:b6:d4:1b:5c:16:c9:9e:37:8a:3e:a9:
+ 7d:30:24:40:b2:b5:44:40:fa:5c:6f:d5:3e:ff:32:
+ c2:e7:24:0a:e4:e4:aa:9f:ff:4c:ac:be:37:58:22:
+ 08:16:0e:f6:a7:2f:b5:6c:4f:ac:7b:a4:82:a8:9f:
+ 38:64:17:6e:72:b6:7c:4c:c5:44:2a:0a:b4:25:0d:
+ b0:0c:ab:98:4a:f9:1a:1a:c9:a6:59:f4:00:a5:0a:
+ 6f:0a:d0:a5:34:ca:0f:f4:0e:fb:ba:d7:bb:3e:2c:
+ 7c:0c:68:6b:26:ff:1c:29:fe:77:f9:30:85:0d:44:
+ 8c:af:90:8a:70:93:5d:3a:b6:18:8b:a5:85:11:5c:
+ a3:5d:57:16:dd:c7:c8:00:f1:05:71:c2:6e:07:3c:
+ 37:69:36:7c:12:c5:9e:1b:69:11:45:44:1e:eb:b9:
+ b2:96:b1:89:cd:4d:fa:89:eb:92:49:f2:46:35:f3:
+ 9d:87:3c:be:e4:f8:b7:31:a7:36:4b:81:76:9b:b2:
+ 04:d5:80:7d:4f:e6:02:ed:24:4c:a0:03:c4:9d:00:
+ 9f:9d:71:93:0d:a5:b8:37:62:2b:03:c3:bd:24:25:
+ 2c:c3:43:d4:c8:27:b0:6d:05:d4:c6:c5:d8:5b:09:
+ 94:e8:27:6b:d9:6d:b7:bc:de:76:bf:d5:9c:36:26:
+ 04:b9:97:1d:f0:c9:8d:91:93:82:32:0d:b7:16:97:
+ 41:31:9a:22:0b:2e:ba:99:51:28:6b:f5:04:ba:c9:
+ 3d:57:0c:72:e8:e1:24:1a:d4:2a:6a:e7:e3:b6:b9:
+ 94:61:e3:4e:42:81:e5:43:e4:1e:ef:6d:c4:5d:a4:
+ f9:b4:ec:3a:8a:34:fe:b5:c7:a8:fe:19:8d:cf:7d:
+ 1b:60:21:ba:25:6f:35:cd:4f:72:28:42:7d:87:08:
+ aa:da:33:7e:63:e6:5b:5f:e7:01:a8:e3:0b:d3:08:
+ 5a:a6:df:ea:e7:2b:13:48:a7:83:32:96:c4:ba:d1:
+ ff:15:66:52:33:86:46:5f:c2:9f:59:4a:00:98:b7:
+ 1b:a1:87:25:df:ad:68:5b:f7:26:17:2b:eb:84:62:
+ 9d:c3:bd:99:67:6a:02:5d:70:72:3e:18:92:99:8c:
+ bd:d9:4f
+ 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:
+ E1:DF:73:0B:F1:3E:86:43:A4:B3:E9:8D:44:7D:3C:B2:19:C1:BC:F2
+ X509v3 Authority Key Identifier:
+ keyid:A2:3E:02:2A:A3:A7:4D:39:B4:08:4D:99:CC:0C:75:36:EA:27:C3:3E
+
+ X509v3 Subject Alternative Name:
+ DNS:localdc.samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com at 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
+ 89:2c:57:98:17:c1:73:a6:10:02:6f:a6:ac:47:1c:37:2d:1d:
+ a1:3c:c5:29:b6:3a:e6:e8:14:ec:3b:74:ee:da:db:2d:97:3e:
+ d3:8c:9d:42:7e:b0:46:e9:54:74:4f:34:df:9e:34:7f:9e:8a:
+ 9d:4d:b2:cf:fb:71:3f:cb:32:e6:45:e7:b4:d3:9e:e8:ca:a5:
+ cf:16:7b:76:b5:4e:e0:b9:bb:79:b1:82:a7:d3:23:cb:3c:46:
+ 63:63:96:b3:5b:62:9e:99:dc:02:17:f9:07:63:86:76:06:1a:
+ 02:1b:9a:df:1d:cd:e7:46:fe:9a:13:87:47:dd:e2:77:58:50:
+ a2:6c:c9:a0:f8:14:1f:3b:d7:59:9c:89:bd:2e:2d:ce:60:f4:
+ c6:2c:e3:63:cf:34:84:61:d9:90:2e:90:fc:5b:4f:a2:00:87:
+ e7:40:e0:fc:d1:24:8b:d0:28:01:d3:53:ac:b1:58:7f:87:29:
+ 38:56:93:dd:a2:14:4a:9a:94:b9:f8:94:b2:04:47:db:b8:38:
+ e6:85:2b:cf:d4:72:88:8b:0d:8e:a0:69:f9:9f:10:22:82:9c:
+ c5:ec:01:e3:07:a1:69:37:94:25:3a:cd:17:29:37:8d:24:d3:
+ 27:0f:4d:bf:b0:31:36:b8:c6:a8:69:0b:df:28:f8:e2:dc:da:
+ 95:3e:7f:d7:3f:a5:8f:92:6a:7d:ad:3a:ac:af:73:2b:5f:f1:
+ b3:22:92:ef:da:71:84:9e:4b:23:7b:69:b7:29:fc:c5:05:84:
+ 4b:ff:06:92:ee:f5:9b:14:2a:af:be:ef:02:e1:e7:d0:e8:d0:
+ 29:7c:48:40:f1:95:bb:08:b2:30:c5:81:80:a8:91:5b:2e:08:
+ 3b:30:44:07:b5:c4:0b:07:74:ca:5d:37:3d:75:f9:bc:6d:21:
+ a6:e0:91:d8:f9:27:88:05:58:a7:f4:36:eb:ba:40:63:36:15:
+ 42:98:0b:e2:d1:c9:11:0b:29:81:e1:c7:02:7e:fa:05:65:51:
+ 7b:d6:1a:33:46:fc:a5:d4:fd:64:e8:c8:11:d4:d1:41:d9:39:
+ 18:08:a3:ed:15:70:d9:14:f5:ba:c9:bb:3e:96:8d:5d:cc:c3:
+ 5c:b6:c8:79:02:2e:e2:a1:06:ba:a5:21:1c:bf:16:7f:2d:d9:
+ 93:07:92:b1:fa:ee:3f:e3:56:35:f3:30:aa:11:54:d3:71:cb:
+ 29:d4:60:e1:6c:ae:c4:24:e3:00:4f:5f:52:b0:3f:f4:76:f3:
+ 6d:db:bc:d8:65:c4:37:be:1a:87:9b:65:c4:20:dd:da:a9:4c:
+ 9f:86:33:2b:49:a6:f7:aa:ce:da:98:3b:e3:5f:ac:b8:1b:45:
+ 0e:56:59:fb:49:38:0f:b7:d4:49:f8:7b:ac:fa:d8:b8:1d:16:
+ db:b2:4c:15:d8:e7:eb:6b:38:ff:d2:69:26:a6:f6:50:15:45:
+ 2f:12:b2:05:d4:bf:6f:53:79:64:9b:d5:8b:a1:08:3e:43:ee:
+ 08:fe:9b:ea:83:89:8a:6a:53:98:1e:c5:91:4c:7a:99:2b:6d:
+ 97:dc:96:1b:de:27:c5:af:0f:dd:42:5c:23:7d:bc:6b:5b:ab:
+ 47:29:98:35:8f:9e:e6:e1:5f:96:6a:bd:cf:3c:47:89:8b:ad:
+ 21:de:20:da:99:82:c1:0e:9b:7c:38:21:d8:b1:1c:34:c5:4e:
+ f7:fe:7d:5e:a4:2f:f8:7d:5c:30:2c:9e:e6:5a:4f:d3:15:90:
+ e6:6f:69:ea:51:93:8f:2c:dd:a7:c3:3c:50:a8:d1:ba:0b:5c:
+ cc:2e:4e:57:71:21:08:a1:2c:bd:a7:20:4b:ae:5c:02:7a:cd:
+ 9a:fe:1e:db:ec:ce:3b:12:37:cb:96:20:7b:3b:b1:5a:2e:84:
+ 03:f9:0b:32:43:c0:4e:e3:ea:79:e7:9a:13:54:e5:a8:1a:17:
+ c4:79:78:25:63:ab:67:39:39:a0:6c:c4:c5:94:ac:16:92:3d:
+ f0:1a:1a:9e:ca:7a:84:1b:c1:5a:5f:4c:65:8a:30:a6:5e:6c:
+ 0e:ae:bf:ac:09:97:0f:83:5c:92:ce:e4:43:de:06:4b:96:f5:
+ 46:3b:7d:a8:e3:0f:d3:fe:00:c7:d4:79:4e:5f:bd:ec:59:12:
+ f9:65:23:fa:e7:97:a2:a6:39:3b:a3:1e:da:47:c5:18:5b:8d:
+ a7:7b:29:1c:5a:7a:06:c6:92:9e:b7:3b:f0:c5:56:e8:cf:84:
+ cd:dd:61:0f:21:25:f4:1e:2b:40:b6:74:28:8d:41:f6:2c:1d:
+ ce:b4:39:d1:e1:be:15:78:c9:d7:99:a1:9d:50:43:da:ec:40:
+ 69:6a:3b:17:af:28:22:09:e0:7d:38:9e:a7:ca:b7:f7:94:8a:
+ 2a:1b:32:4e:28:6d:18:95:ca:42:67:c8:bb:13:24:31:43:84:
+ 3e:95:66:08:5c:15:7f:6b:93:cc:8f:b8:76:7a:fd:74:4a:d6:
+ 6f:64:74:df:72:f7:34:a3:50:f0:db:bf:0a:2b:1b:48:b7:c9:
+ c0:97:23:27:b1:56:5b:9e:10:12:5a:bf:ff:38:61:da:41:75:
+ 15:c5:03:c2:20:fd:7f:84:c0:94:8e:11:ed:01:ba:f1:19:b5:
+ 05:1d:bf:89:ea:c9:38:4e:d2:cf:5b:24:c6:37:a1:8e:60:89:
+ 5c:52:ff:7d:5e:2d:c9:f8:b1:79:07:4c:2f:18:85:e8:ba:bf:
+ 3e:da:59:43:df:29:79:7e:00:38:d2:fc:a9:8e:3b:9d
+-----BEGIN CERTIFICATE-----
+MIIJ6zCCBdOgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTYyMzI4NDRaFw0zNjAzMTEyMzI4NDRaMIG1MQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEbMBkGA1UE
+CwwSRG9tYWluIENvbnRyb2xsZXJzMSIwIAYDVQQDDBlsb2NhbGRjLnNhbWJhLmV4
+YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkBFiZjYS1zYW1iYS5leGFtcGxlLmNvbUBz
+YW1iYS5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+AOakds7oY/5X+aOu4K1N4hWO2CfIfX8rseiqUI+U+cdxP1IykdFtUiJfzY3MYhZ6
+i1hl7Qf36iTTiNgmyuvsFqeEHH4VRmQJIka53VwHhFCnTjE/ASPR+DYEGrvU5bbU
+G1wWyZ43ij6pfTAkQLK1RED6XG/VPv8ywuckCuTkqp//TKy+N1giCBYO9qcvtWxP
+rHukgqifOGQXbnK2fEzFRCoKtCUNsAyrmEr5GhrJpln0AKUKbwrQpTTKD/QO+7rX
+uz4sfAxoayb/HCn+d/kwhQ1EjK+QinCTXTq2GIulhRFco11XFt3HyADxBXHCbgc8
+N2k2fBLFnhtpEUVEHuu5spaxic1N+onrkknyRjXznYc8vuT4tzGnNkuBdpuyBNWA
+fU/mAu0kTKADxJ0An51xkw2luDdiKwPDvSQlLMND1MgnsG0F1MbF2FsJlOgna9lt
+t7zedr/VnDYmBLmXHfDJjZGTgjINtxaXQTGaIgsuuplRKGv1BLrJPVcMcujhJBrU
+Kmrn47a5lGHjTkKB5UPkHu9txF2k+bTsOoo0/rXHqP4Zjc99G2AhuiVvNc1PcihC
+fYcIqtozfmPmW1/nAajjC9MIWqbf6ucrE0ingzKWxLrR/xVmUjOGRl/Cn1lKAJi3
+G6GHJd+taFv3Jhcr64RincO9mWdqAl1wcj4YkpmMvdlPAgMBAAGjggHxMIIB7TAJ
+BgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly93d3cuc2FtYmEuZXhh
+bXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMBEGCWCG
+SAGG+EIBAQQEAwIGQDALBgNVHQ8EBAMCBeAwRgYJYIZIAYb4QgENBDkWN0RvbWFp
+biBDb250cm9sbGVyIENlcnRpZmljYXRlIGxvY2FsZGMuc2FtYmEuZXhhbXBsZS5j
+b20wHQYDVR0OBBYEFOHfcwvxPoZDpLPpjUR9PLIZwbzyMB8GA1UdIwQYMBaAFKI+
+Aiqjp005tAhNmcwMdTbqJ8M+MD0GA1UdEQQ2MDSCGWxvY2FsZGMuc2FtYmEuZXhh
+bXBsZS5jb22gFwYJKwYBBAGCNxkBoAoECAEjRWeJq83vMDEGA1UdEgQqMCiBJmNh
+LXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0GCWCGSAGG+EIB
+BARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMvQ0Etc2FtYmEu
+ZXhhbXBsZS5jb20tY3JsLmNybDAmBgNVHSUEHzAdBggrBgEFBQcDAgYIKwYBBQUH
+AwEGBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggQBAIksV5gXwXOmEAJvpqxHHDct
+HaE8xSm2OuboFOw7dO7a2y2XPtOMnUJ+sEbpVHRPNN+eNH+eip1Nss/7cT/LMuZF
+57TTnujKpc8We3a1TuC5u3mxgqfTI8s8RmNjlrNbYp6Z3AIX+QdjhnYGGgIbmt8d
+zedG/poTh0fd4ndYUKJsyaD4FB8711mcib0uLc5g9MYs42PPNIRh2ZAukPxbT6IA
+h+dA4PzRJIvQKAHTU6yxWH+HKThWk92iFEqalLn4lLIER9u4OOaFK8/UcoiLDY6g
+afmfECKCnMXsAeMHoWk3lCU6zRcpN40k0ycPTb+wMTa4xqhpC98o+OLc2pU+f9c/
+pY+San2tOqyvcytf8bMiku/acYSeSyN7abcp/MUFhEv/BpLu9ZsUKq++7wLh59Do
+0Cl8SEDxlbsIsjDFgYCokVsuCDswRAe1xAsHdMpdNz11+bxtIabgkdj5J4gFWKf0
+Nuu6QGM2FUKYC+LRyRELKYHhxwJ++gVlUXvWGjNG/KXU/WToyBHU0UHZORgIo+0V
+cNkU9brJuz6WjV3Mw1y2yHkCLuKhBrqlIRy/Fn8t2ZMHkrH67j/jVjXzMKoRVNNx
+yynUYOFsrsQk4wBPX1KwP/R2823bvNhlxDe+GoebZcQg3dqpTJ+GMytJpveqztqY
+O+NfrLgbRQ5WWftJOA+31En4e6z62LgdFtuyTBXY5+trOP/SaSam9lAVRS8SsgXU
+v29TeWSb1YuhCD5D7gj+m+qDiYpqU5gexZFMepkrbZfclhveJ8WvD91CXCN9vGtb
+q0cpmDWPnubhX5Zqvc88R4mLrSHeINqZgsEOm3w4IdixHDTFTvf+fV6kL/h9XDAs
+nuZaT9MVkOZvaepRk48s3afDPFCo0boLXMwuTldxIQihLL2nIEuuXAJ6zZr+Htvs
+zjsSN8uWIHs7sVouhAP5CzJDwE7j6nnnmhNU5agaF8R5eCVjq2c5OaBsxMWUrBaS
+PfAaGp7KeoQbwVpfTGWKMKZebA6uv6wJlw+DXJLO5EPeBkuW9UY7fajjD9P+AMfU
+eU5fvexZEvllI/rnl6KmOTujHtpHxRhbjad7KRxaegbGkp63O/DFVujPhM3dYQ8h
+JfQeK0C2dCiNQfYsHc60OdHhvhV4ydeZoZ1QQ9rsQGlqOxevKCIJ4H04nqfKt/eU
+iiobMk4obRiVykJnyLsTJDFDhD6VZghcFX9rk8yPuHZ6/XRK1m9kdN9y9zSjUPDb
+vworG0i3ycCXIyexVlueEBJav/84YdpBdRXFA8Ig/X+EwJSOEe0BuvEZtQUdv4nq
+yThO0s9bJMY3oY5giVxS/31eLcn4sXkHTC8Yhei6vz7aWUPfKXl+ADjS/KmOO50=
+-----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 0000000..3443a50
--- /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-----
+MIIJjjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIc8U9D3UAcEQCAggA
+MBQGCCqGSIb3DQMHBAiv8rBzGS//TQSCCUieV5YQyWsn3FFhKYI425pOXfnTsSUb
+VEe7wO2H7D/S0RFfT5gILYv57TTH8Z9uAeX/wU5msKA4PZt16aMutNl2NWell8hy
+IX5R4n6IzSP6IobZKsyFR5u/h683Eli1pBd4BbLJuYu94sxelB4HQdRp0QJIvIvO
+TWqTyD7UmqqG/IVhTMQpzcepY/S4SGI6GODJtDLPRgv3x5/Z0/NsxiMKrXMi7HKc
+Rzg8jm2mausukN+sSyPcvlEufQjRJgJXtCIX98FMLp0pkOq1rsVUSNg8Qza6tbyE
+XhweHWbV9YZCVfmnhUalLt7CIoA7QeOQZbwTNpTo/4mSEA7lv1knvFSdMc9JvR6J
+bZQOk5rPzuX2W84UQ3CkIwaRB2iFUv0gJy5Z2xbhWgAR5KZIhGTKupHBYOmD29QU
+whgjXq4McdYWKquxELzSW5jXVPNwvREhEuKR1mt6g0NqXCbCeQHw7DWH1OGPz7jM
+HXsCGVWpXqeWvRHhdF+NRfHa41hqGS3Onq29UJtgcMpNYpGQYY6Exq6hVVsmddwt
+QU4COPfozJzeAlkUEem5AKnuh1JUxo/RieNP99sv1/8g8icc+oPXOIu/6HI3JGYB
+4WTVBp1OccEcNlnUYhxcL3ODYXcLUhiLZh2DS+IDLS3Pbp0v1qz/JuzDxiYBnEYt
+4Q5NWdhPF/TSS7wQHRl35LAyHHhBIu1kuDhnXjdq87h7ioNiffZ0DgSW4HFUzslk
+4UZGFTKaDpepBfIp1qnYGPKCMv+MLaMWU3LOfVGT3ecntkMxUtntNMZ6qGaXhzda
+65LD9xYJUrbo+qQSBiTNAhMOy6lHlwIulmML0j1YEcVc2EwgqdfbBeT9v9gh6If4
+85ba1Wvy4W/FN/xo/ECflLAvozjyYND8LMcZ73eJs4ncZkMZAkjfP3sg/qvTAtbf
+D6c+SRQbxRJv0ZUb9NN7wx4flsyypscKNqk78mytUN7gGf2xJIOvMS/zH/Zf9EpD
+bEY+lOY2llYtXhoEj95tnRPFhKaQeGZdkISsmoU5olLsw/tRkquGdAokh+fl+NtZ
+WxgJF8Ft8NT4iXhEBRfgFO5ubGq565c66ayA6R6K00pg/IvS8OXPuxT+/e8EKqUO
+R9RyWR5n+W8hWw5+pQWGNvwhLFLJFfCxHw2ucSyNCvtcb6ijV5yvi4cI+UuVnh3s
+WW3mMaMOYIcbh/thp8wBs/dpAOGUWX7XBfaGsQ0D+ff0ufcUobhXVZgtC0LhgfrN
+ZeHQF4bUXycyaAGWvstNb6Xj2QFVDG98eNDGmYDTD+0XwpPc/6/Ge4BLPAVcBpQw
+DMCKUqSkPPWCqfipbQmpBxswhYmzx+DjdfRxHExWeGk1pwyfH4GBhO5fkcpYVtU+
+RyruFu0YNnQ+2Y4eg8+3IyJndxkUHmwsB1DB0P8XvJ0n/NnAnZ0sIpE0x3dOFhb+
+SK0dj8fo2aEHOimrTHc2EJ2ZscpSCVNQ1BsScM36FCWxRWbTr8rBFsdUJ5CMZ2hN
+qHBtf38SgNkD3qBUmiPetsYt6qTKY9Rv25D4zL5IR2ZnV99oW6MTDhc49cxYn8Dy
+MKlyzV3upykqGBMSKBKbafDI3sO8gB3upUetnogi1TMaNyu4qNzq8oNRfdf+RD1R
+Rg4++U14UbYNvWRQnCqjJGUXDnVc8Gp9K8Z6p5eXihsFfpol1OGu0td1e0FRi3AH
+INW9UEpfRbmbEPHhYQRNAyRlcQXJ1FBnxUCk6qgfkD0ziJk2VD4oFoaSlqy7l21z
+zoH0Vp6PZGZEIs/mAODvtH5jsTEMUE8uuRmPqgnFqbi/gfQ5FJLR6dfCb8MJ2iJM
+Hw4791wi7tS1aCYoHneDtxNFeWuuEmw1uMoA+C5euGNv86XAH5AV2OrTIt8SLFPN
+mLBLQ3J9Kkitsy1JFz9IdJ5uY3K2CvpOaP+sx3l1Q4YVuSza8r7zRfTC1wPfbsvk
+64zZQzA57WvRvpaZU49HbMV9/zDOlQfLtL7TdAbqLYjlVRpO5pHHEqLRR9eGQ2UY
+zhfMFfcJahH4lDbgHf6EVjHnEuoW9fU8hLRVzUcQCVDsf36Et+g5G1JMhFnlVzdv
+MaKiN9tzKeIqxUSlXMHYm+oIb849pshNo+KRzZ0K+r+wExnpIfCfVOjAvSQU+6y9
+1uIIQlJfk6uPFVriaooyUDrW9/83AgzJDrkpSMTnVmo/MTS8cAe8Ox5cr+mHqJko
+cnHzBNI9Q0z59SpJdXucPVyk5MYPUdfyI2ouicm+nKidNvlp36O7UHMw0pJdeqDg
+03vhaVif5uN8FNjBLp6xIipX6lor6XCOnkGR/zkis602sTAkE4nemOw9zy3rIBr+
+hYnSY7vMFCVYIERjqSOLE0k0d5RyOsGjSYr8yQMvpTGusla34qVPjrrpJ+OuczK/
+6KJeHV+WUw42g8JSs67j8YJ2ejc9gr9AVSRiES99QL+tlFnOTY28N40OjXqFJjYK
+A0x0By1O6h4PMKtYchTuJAoEOB2KOP1Ta+NlL80zM4nWwv7NdO0AR/ATfUfix1GS
+NiMC10C7eurYdAfxly3p9NgjQq+vaKsnSy0TbXPCgW8YTegnxKTUWJm+BEiYaE4M
+A0c1CySusV+JO1catlXSeCB6ajddi/SKXsW26lJ3Q+8QqhA3EMivCE3Zh2Q5c1yp
+gCV7IXtdryPdK16qmirO9LKkm6sCfBdhgBgi+IcyUhqxwHCwxrPqzEs75Sa3U/6k
+kV3AqFwhHYtUj2fBNlfJ1efV8fW+WLboJkHbi2LXmL4NBvHTNjK3NprffFrQ/QJU
+oYsMQdeWQZD+3p8w1fPb0sXEDL6LQgjAjyDaqOiX8XrQ8nr3n4FpTI38/OIIfS69
+IHtgo5yv0CMfN+C6LAHOE0aDHRoY6+TVVgr1Z/X2VqJQJONii0dQ5ttDHYnUpzu0
+vWsdvVjsyhkLa2yhUB7UyWusZo0HZRSAcf1pNlpp5rCtJad9to7OvOL3qb5GluAK
+/5eZE6RzgyGOjtOx0IgQ+l4ThQCTbkoVEtB59IEeP/+Sq2RmFfdGiGgC3Wnrga8b
+gkuXXbjZboptSku6N1ZO1r99wd0qIHzrtVCONGLGfVBy7X6nDO2pC9IUOXycMji7
+B5J0toyDWt6UzlLQasmz8Be7NZJCkDd2jlSKorZtdynsXbRkX1H4by9kI8kEcgK7
+ICE=
+-----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 0000000..bf4131f
--- /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 at 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 0000000..546b292
--- /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-----
+MIIJJwIBAAKCAgEA5qR2zuhj/lf5o67grU3iFY7YJ8h9fyux6KpQj5T5x3E/UjKR
+0W1SIl/NjcxiFnqLWGXtB/fqJNOI2CbK6+wWp4QcfhVGZAkiRrndXAeEUKdOMT8B
+I9H4NgQau9TlttQbXBbJnjeKPql9MCRAsrVEQPpcb9U+/zLC5yQK5OSqn/9MrL43
+WCIIFg72py+1bE+se6SCqJ84ZBducrZ8TMVEKgq0JQ2wDKuYSvkaGsmmWfQApQpv
+CtClNMoP9A77ute7Pix8DGhrJv8cKf53+TCFDUSMr5CKcJNdOrYYi6WFEVyjXVcW
+3cfIAPEFccJuBzw3aTZ8EsWeG2kRRUQe67mylrGJzU36ieuSSfJGNfOdhzy+5Pi3
+Mac2S4F2m7IE1YB9T+YC7SRMoAPEnQCfnXGTDaW4N2IrA8O9JCUsw0PUyCewbQXU
+xsXYWwmU6Cdr2W23vN52v9WcNiYEuZcd8MmNkZOCMg23FpdBMZoiCy66mVEoa/UE
+usk9Vwxy6OEkGtQqaufjtrmUYeNOQoHlQ+Qe723EXaT5tOw6ijT+tceo/hmNz30b
+YCG6JW81zU9yKEJ9hwiq2jN+Y+ZbX+cBqOML0whapt/q5ysTSKeDMpbEutH/FWZS
+M4ZGX8KfWUoAmLcboYcl361oW/cmFyvrhGKdw72ZZ2oCXXByPhiSmYy92U8CAwEA
+AQKCAgBqVMxJW64t5lU69zax70QZ+D8DKFVjObvNridx6pa1MiqlNJcxXBsPqedU
+RjO6dUikumjq0Yrq63MdY9UNq0xOcoPIRPqsx+E7hhjdgsGnhVpxLcDSyMyL6pyA
+mAhHn8X1ULQm8ygS94S1myEQwqzy3/mZvVBLyxU8BsvW9u0K0mKBCTjustHTiZaB
+QWd8xcaZQiDSqIUQ8BSFYkgwBIoGb+TZaFQPo1SUy/8S9oBw3CMn84V6EPL5QWbV
+d8rqOuciJNQTzFgKJHbRjXW2Nn5Avae2kQaiG+5RUP5D801D0denAq2SFbbJaFTA
+O4kKYOKS6QGOjfj0Xh4ONveiaXxBSPpIJSvbjAV+Nq92NVkZ35jiPqGZzebhzzoD
+mU6mMvRoL/FHs9PKNZF1Cd4EP1SdLhiImj+1eajfYvHAlz6kIJxTue0BFkh13uwp
+amx48wB7e/W8t8lqixICf1HlCv+EQGN6aka5dHMqJobXhkt9npz53+AYdpc8Sjs9
+QlFplYoOgkaHvzLv9yeZPOT5Xr32weE6KpM+SwvpVxfttbkvqrWoOoEcDARuVqiS
+TRzS/ZDiEn+Kcgm7pJ3i2nTAIBzwC4z91HJbeVXNpptkZJEgjXM8XjSArHjDrkl1
+EGKARlkTn576XMGWSkF/bmEBiG0KIhTu+DmwsQvR+564tjV98QKCAQEA+aS7ygjL
+aRj5JZKMt3VWZRntK20m04iY0wGDNs+p+nFRJjCDAUhTTOl9++vlJYe8HO9iXzUv
+O51tGnzrck9+gUVlFghrw0dJ+mY0+1bSt2aLNUmlfvv1uRpm9Pd3xbQ6e3Kpf/r1
+ew6IpG8I6pvpVJXJ3FQZpSOlTP9dyRxMNzdILGzzPrb+2r0j6Oc/y3+adBiXB3Yg
+QPfFJRJZA4k2Wk/qSi9NR/yWHaY0krO68l8l2zn1AKaIoVVqtxVTQ7qUBWNXzVMe
+ULtAvO1Bonh+C+zYcNJjSBeYWeJ7pbp/ozDe6M2DuJMv4aW6oV6tGcMF9NOd1pFx
+qiC8vIVPZ3rJ9QKCAQEA7IPf9CAaDUScu2/Ry9z1RaISU4BMi/30poc80Zy2hC18
+vP8aiHVlQdkdzdKYGweaYNQpszGeBcHK51y6V11vwCNQRrCoUp9VbICp7ok2O4y8
+w9r+q4GcYthHeMhEnHDo4R/uHKEJCYS012RLlLSXMa0Dfl1sOv8mVuIEaZoRJrAq
+Xzxz9KX7MFv5Zb8TvVL6fHEXmdMmmoiZnyNplH+3LMj6duoNaxjtsoixCkuRTXE7
+Cav118q+QWae+yhIonF+HRIa/G0doqHa+P9rl18FUnxfAf91Z70SSJ2oOtuWjd1J
+37eG4d7skpAoWWdXNpCqpJnsPLlSlBqKmYrN5CM3swKCAQBAfV/Np0v00HC8Vgln
+8zXoVDRCfaYEC0t/ZuqgpDDC87cE6I9PK4HpYoAbLis58MCVsPl2ouSav+ZJa2/f
+Tc3eUzDz6iT8g1QHDZQuQZWZrzHTCD1qemhV8w4Zxjv4pMBe15YV65yyt2RxJgXl
+pXU3VqKY+ljNolG3fFib9WVy9iL85wBHeTqJA0ddiS+fwE0EJL4PPWLDpb4V/5Fj
+KnUSC4b4txN9vzCAZEk8hJWMuyuqYGR8UIkHNGum9ClYW8CVS76I2ioArP7iT2Af
+OoVFS1/2dUMUgpPm1G0guPb0D1HmTgDzE4LRBeEagryw5QKK5oflwBje3ColgUKr
+9rppAoIBAH9t9gXkHeU0KHXco16BaCziS5ltsNBkPaJTjvMoyjWhBGoX0EXhanL1
+9dblNkqp6AVviiAgBZH4fcf17/gOQZ116VSM7cPGURIqqGP6zZt8EmA756akKIwh
+FzD+Rek79F0HBRWrteDI/V5njUlLm4KKQy2cTCnlOtTo5ZO4DLGZjNrPCXKw0wuV
+ImQtdQc2Y/sUO7EHUO9F1e8l90apIRoiFsBnDl+7iKX+e9SeLmVZMoPdgJGJjMRT
+9ChB5hCPsXEcRinm6GataftqMp/V9Foi5FWBO9JuziENwIwlr5Izvg+pJCUiJLg6
+r2KsCRM/EpGo1N1KxDFDs5VScegPCX0CggEAWCJ0+KmHbA4F+vDjYW1wNE1MBKee
+4Q+nnX45oEHDM+J5da2Ov2IhblzVX/vJaVtI2rwSXCkM3x7ByAXwewNa4BA/eGG/
+v2MPs21f9GcLkpLv0xz+pILkeeNk+e0yIYE4jWQGFMlYh7cNLStDSw6XNU/9IKeO
+r2gQjAqS/pMGBMS3FOcd2S+/gMjJom2GaWLhGdJAGdmtGh2EbFku5+WDL76pyAaN
+BHEGD91PSER5nEGS9ho81IPDrIm0LVcp6xMRD6PWput/0gcC3Zun1ZDo9oJA1AsS
+NMnm6c14ASh/1KQUx9XkC1hUmBVhb4UA4EshT4oXffTHpDMlA6yWqlkReg==
+-----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 0000000..d2647cc
--- /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
+ggIKAoICAQDmpHbO6GP+V/mjruCtTeIVjtgnyH1/K7HoqlCPlPnHcT9SMpHRbVIi
+X82NzGIWeotYZe0H9+ok04jYJsrr7BanhBx+FUZkCSJGud1cB4RQp04xPwEj0fg2
+BBq71OW21BtcFsmeN4o+qX0wJECytURA+lxv1T7/MsLnJArk5Kqf/0ysvjdYIggW
+DvanL7VsT6x7pIKonzhkF25ytnxMxUQqCrQlDbAMq5hK+RoayaZZ9AClCm8K0KU0
+yg/0Dvu617s+LHwMaGsm/xwp/nf5MIUNRIyvkIpwk106thiLpYURXKNdVxbdx8gA
+8QVxwm4HPDdpNnwSxZ4baRFFRB7rubKWsYnNTfqJ65JJ8kY1852HPL7k+LcxpzZL
+gXabsgTVgH1P5gLtJEygA8SdAJ+dcZMNpbg3YisDw70kJSzDQ9TIJ7BtBdTGxdhb
+CZToJ2vZbbe83na/1Zw2JgS5lx3wyY2Rk4IyDbcWl0ExmiILLrqZUShr9QS6yT1X
+DHLo4SQa1Cpq5+O2uZRh405CgeVD5B7vbcRdpPm07DqKNP61x6j+GY3PfRtgIbol
+bzXNT3IoQn2HCKraM35j5ltf5wGo4wvTCFqm3+rnKxNIp4MylsS60f8VZlIzhkZf
+wp9ZSgCYtxuhhyXfrWhb9yYXK+uEYp3DvZlnagJdcHI+GJKZjL3ZTwIDAQABoAAw
+DQYJKoZIhvcNAQELBQADggIBAFRI0PRZO7XlWIpWUC0wc3KjVvTGxieaalJdPC/j
+dxT7lBkSTHGjbeLIkqjVAuhONziKT2RP9QxzK2sa9jxIi5zR1byZv500suTez+96
+KkqSnFTgM4nwJdv2S8x0uBPmlREL4K1I0FGZX29wd0bqFhBQqSzVQvQqGSiqSJfU
+KkIys1tAIrC7DfNvfhogIrupuN8clluLe0T25qxGeaqXN+EYB7U/O+4FZccpGoeP
+dHO2zYeRib0oGTlnk1noRmlqgXPEKfzoWMJ2cUkexlRy1ajW0r1rvcIgc1rPnB8h
+6c6YhFGwbYW54/I6tLxJc5pyWCQNH/uYEeFnGs/w85lPKvLM0RXsQ7rfnDRv3LOj
+Mex+3whmIs5dAVdQQMy0ngsbPpaR+5Ry8eWAPmwnRXwVaysGgmTysVCzFGqSO3ul
+7FgbKEEM1cNe4+Gvl2LEl+aJ5CB1DBslDjXMQVwLMpAU2sthJurhujx3/j598IUp
+why48F4056Uf33CncLSEriykIEFXUionXUxtDsCaS13+CfKw+gUJJRsg4ZWqrY6M
+b0KHAtzq4g7lFZ+XaXpGdxntqGOrgxfcgWBRhJnp35ILoMFNV2OHjySnF6SWDJvP
+AY9IQsUDiMruNjCS9s5zaH7KqmJJ+pgcjVSholozUEI2J3hUpq3KFsE20Cyi+YbO
+kTlo
+-----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 0000000..b7549bb
--- /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 0000000..21601b4
--- /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/NewCerts/00.pem b/selftest/manage-ca/CA-samba.example.com/NewCerts/00.pem
new file mode 100644
index 0000000..7b1b6a1
--- /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 at samba.example.com
+ Validity
+ Not Before: Mar 16 23:28:44 2016 GMT
+ Not After : Mar 11 23:28:44 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Domain Controllers, CN=localdc.samba.example.com/emailAddress=ca-samba.example.com at samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:e6:a4:76:ce:e8:63:fe:57:f9:a3:ae:e0:ad:4d:
+ e2:15:8e:d8:27:c8:7d:7f:2b:b1:e8:aa:50:8f:94:
+ f9:c7:71:3f:52:32:91:d1:6d:52:22:5f:cd:8d:cc:
+ 62:16:7a:8b:58:65:ed:07:f7:ea:24:d3:88:d8:26:
+ ca:eb:ec:16:a7:84:1c:7e:15:46:64:09:22:46:b9:
+ dd:5c:07:84:50:a7:4e:31:3f:01:23:d1:f8:36:04:
+ 1a:bb:d4:e5:b6:d4:1b:5c:16:c9:9e:37:8a:3e:a9:
+ 7d:30:24:40:b2:b5:44:40:fa:5c:6f:d5:3e:ff:32:
+ c2:e7:24:0a:e4:e4:aa:9f:ff:4c:ac:be:37:58:22:
+ 08:16:0e:f6:a7:2f:b5:6c:4f:ac:7b:a4:82:a8:9f:
+ 38:64:17:6e:72:b6:7c:4c:c5:44:2a:0a:b4:25:0d:
+ b0:0c:ab:98:4a:f9:1a:1a:c9:a6:59:f4:00:a5:0a:
+ 6f:0a:d0:a5:34:ca:0f:f4:0e:fb:ba:d7:bb:3e:2c:
+ 7c:0c:68:6b:26:ff:1c:29:fe:77:f9:30:85:0d:44:
+ 8c:af:90:8a:70:93:5d:3a:b6:18:8b:a5:85:11:5c:
+ a3:5d:57:16:dd:c7:c8:00:f1:05:71:c2:6e:07:3c:
+ 37:69:36:7c:12:c5:9e:1b:69:11:45:44:1e:eb:b9:
+ b2:96:b1:89:cd:4d:fa:89:eb:92:49:f2:46:35:f3:
+ 9d:87:3c:be:e4:f8:b7:31:a7:36:4b:81:76:9b:b2:
+ 04:d5:80:7d:4f:e6:02:ed:24:4c:a0:03:c4:9d:00:
+ 9f:9d:71:93:0d:a5:b8:37:62:2b:03:c3:bd:24:25:
+ 2c:c3:43:d4:c8:27:b0:6d:05:d4:c6:c5:d8:5b:09:
+ 94:e8:27:6b:d9:6d:b7:bc:de:76:bf:d5:9c:36:26:
+ 04:b9:97:1d:f0:c9:8d:91:93:82:32:0d:b7:16:97:
+ 41:31:9a:22:0b:2e:ba:99:51:28:6b:f5:04:ba:c9:
+ 3d:57:0c:72:e8:e1:24:1a:d4:2a:6a:e7:e3:b6:b9:
+ 94:61:e3:4e:42:81:e5:43:e4:1e:ef:6d:c4:5d:a4:
+ f9:b4:ec:3a:8a:34:fe:b5:c7:a8:fe:19:8d:cf:7d:
+ 1b:60:21:ba:25:6f:35:cd:4f:72:28:42:7d:87:08:
+ aa:da:33:7e:63:e6:5b:5f:e7:01:a8:e3:0b:d3:08:
+ 5a:a6:df:ea:e7:2b:13:48:a7:83:32:96:c4:ba:d1:
+ ff:15:66:52:33:86:46:5f:c2:9f:59:4a:00:98:b7:
+ 1b:a1:87:25:df:ad:68:5b:f7:26:17:2b:eb:84:62:
+ 9d:c3:bd:99:67:6a:02:5d:70:72:3e:18:92:99:8c:
+ bd:d9:4f
+ 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:
+ E1:DF:73:0B:F1:3E:86:43:A4:B3:E9:8D:44:7D:3C:B2:19:C1:BC:F2
+ X509v3 Authority Key Identifier:
+ keyid:A2:3E:02:2A:A3:A7:4D:39:B4:08:4D:99:CC:0C:75:36:EA:27:C3:3E
+
+ X509v3 Subject Alternative Name:
+ DNS:localdc.samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com at 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
+ 89:2c:57:98:17:c1:73:a6:10:02:6f:a6:ac:47:1c:37:2d:1d:
+ a1:3c:c5:29:b6:3a:e6:e8:14:ec:3b:74:ee:da:db:2d:97:3e:
+ d3:8c:9d:42:7e:b0:46:e9:54:74:4f:34:df:9e:34:7f:9e:8a:
+ 9d:4d:b2:cf:fb:71:3f:cb:32:e6:45:e7:b4:d3:9e:e8:ca:a5:
+ cf:16:7b:76:b5:4e:e0:b9:bb:79:b1:82:a7:d3:23:cb:3c:46:
+ 63:63:96:b3:5b:62:9e:99:dc:02:17:f9:07:63:86:76:06:1a:
+ 02:1b:9a:df:1d:cd:e7:46:fe:9a:13:87:47:dd:e2:77:58:50:
+ a2:6c:c9:a0:f8:14:1f:3b:d7:59:9c:89:bd:2e:2d:ce:60:f4:
+ c6:2c:e3:63:cf:34:84:61:d9:90:2e:90:fc:5b:4f:a2:00:87:
+ e7:40:e0:fc:d1:24:8b:d0:28:01:d3:53:ac:b1:58:7f:87:29:
+ 38:56:93:dd:a2:14:4a:9a:94:b9:f8:94:b2:04:47:db:b8:38:
+ e6:85:2b:cf:d4:72:88:8b:0d:8e:a0:69:f9:9f:10:22:82:9c:
+ c5:ec:01:e3:07:a1:69:37:94:25:3a:cd:17:29:37:8d:24:d3:
+ 27:0f:4d:bf:b0:31:36:b8:c6:a8:69:0b:df:28:f8:e2:dc:da:
+ 95:3e:7f:d7:3f:a5:8f:92:6a:7d:ad:3a:ac:af:73:2b:5f:f1:
+ b3:22:92:ef:da:71:84:9e:4b:23:7b:69:b7:29:fc:c5:05:84:
+ 4b:ff:06:92:ee:f5:9b:14:2a:af:be:ef:02:e1:e7:d0:e8:d0:
+ 29:7c:48:40:f1:95:bb:08:b2:30:c5:81:80:a8:91:5b:2e:08:
+ 3b:30:44:07:b5:c4:0b:07:74:ca:5d:37:3d:75:f9:bc:6d:21:
+ a6:e0:91:d8:f9:27:88:05:58:a7:f4:36:eb:ba:40:63:36:15:
+ 42:98:0b:e2:d1:c9:11:0b:29:81:e1:c7:02:7e:fa:05:65:51:
+ 7b:d6:1a:33:46:fc:a5:d4:fd:64:e8:c8:11:d4:d1:41:d9:39:
+ 18:08:a3:ed:15:70:d9:14:f5:ba:c9:bb:3e:96:8d:5d:cc:c3:
+ 5c:b6:c8:79:02:2e:e2:a1:06:ba:a5:21:1c:bf:16:7f:2d:d9:
+ 93:07:92:b1:fa:ee:3f:e3:56:35:f3:30:aa:11:54:d3:71:cb:
+ 29:d4:60:e1:6c:ae:c4:24:e3:00:4f:5f:52:b0:3f:f4:76:f3:
+ 6d:db:bc:d8:65:c4:37:be:1a:87:9b:65:c4:20:dd:da:a9:4c:
+ 9f:86:33:2b:49:a6:f7:aa:ce:da:98:3b:e3:5f:ac:b8:1b:45:
+ 0e:56:59:fb:49:38:0f:b7:d4:49:f8:7b:ac:fa:d8:b8:1d:16:
+ db:b2:4c:15:d8:e7:eb:6b:38:ff:d2:69:26:a6:f6:50:15:45:
+ 2f:12:b2:05:d4:bf:6f:53:79:64:9b:d5:8b:a1:08:3e:43:ee:
+ 08:fe:9b:ea:83:89:8a:6a:53:98:1e:c5:91:4c:7a:99:2b:6d:
+ 97:dc:96:1b:de:27:c5:af:0f:dd:42:5c:23:7d:bc:6b:5b:ab:
+ 47:29:98:35:8f:9e:e6:e1:5f:96:6a:bd:cf:3c:47:89:8b:ad:
+ 21:de:20:da:99:82:c1:0e:9b:7c:38:21:d8:b1:1c:34:c5:4e:
+ f7:fe:7d:5e:a4:2f:f8:7d:5c:30:2c:9e:e6:5a:4f:d3:15:90:
+ e6:6f:69:ea:51:93:8f:2c:dd:a7:c3:3c:50:a8:d1:ba:0b:5c:
+ cc:2e:4e:57:71:21:08:a1:2c:bd:a7:20:4b:ae:5c:02:7a:cd:
+ 9a:fe:1e:db:ec:ce:3b:12:37:cb:96:20:7b:3b:b1:5a:2e:84:
+ 03:f9:0b:32:43:c0:4e:e3:ea:79:e7:9a:13:54:e5:a8:1a:17:
+ c4:79:78:25:63:ab:67:39:39:a0:6c:c4:c5:94:ac:16:92:3d:
+ f0:1a:1a:9e:ca:7a:84:1b:c1:5a:5f:4c:65:8a:30:a6:5e:6c:
+ 0e:ae:bf:ac:09:97:0f:83:5c:92:ce:e4:43:de:06:4b:96:f5:
+ 46:3b:7d:a8:e3:0f:d3:fe:00:c7:d4:79:4e:5f:bd:ec:59:12:
+ f9:65:23:fa:e7:97:a2:a6:39:3b:a3:1e:da:47:c5:18:5b:8d:
+ a7:7b:29:1c:5a:7a:06:c6:92:9e:b7:3b:f0:c5:56:e8:cf:84:
+ cd:dd:61:0f:21:25:f4:1e:2b:40:b6:74:28:8d:41:f6:2c:1d:
+ ce:b4:39:d1:e1:be:15:78:c9:d7:99:a1:9d:50:43:da:ec:40:
+ 69:6a:3b:17:af:28:22:09:e0:7d:38:9e:a7:ca:b7:f7:94:8a:
+ 2a:1b:32:4e:28:6d:18:95:ca:42:67:c8:bb:13:24:31:43:84:
+ 3e:95:66:08:5c:15:7f:6b:93:cc:8f:b8:76:7a:fd:74:4a:d6:
+ 6f:64:74:df:72:f7:34:a3:50:f0:db:bf:0a:2b:1b:48:b7:c9:
+ c0:97:23:27:b1:56:5b:9e:10:12:5a:bf:ff:38:61:da:41:75:
+ 15:c5:03:c2:20:fd:7f:84:c0:94:8e:11:ed:01:ba:f1:19:b5:
+ 05:1d:bf:89:ea:c9:38:4e:d2:cf:5b:24:c6:37:a1:8e:60:89:
+ 5c:52:ff:7d:5e:2d:c9:f8:b1:79:07:4c:2f:18:85:e8:ba:bf:
+ 3e:da:59:43:df:29:79:7e:00:38:d2:fc:a9:8e:3b:9d
+-----BEGIN CERTIFICATE-----
+MIIJ6zCCBdOgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTYyMzI4NDRaFw0zNjAzMTEyMzI4NDRaMIG1MQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEbMBkGA1UE
+CwwSRG9tYWluIENvbnRyb2xsZXJzMSIwIAYDVQQDDBlsb2NhbGRjLnNhbWJhLmV4
+YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkBFiZjYS1zYW1iYS5leGFtcGxlLmNvbUBz
+YW1iYS5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+AOakds7oY/5X+aOu4K1N4hWO2CfIfX8rseiqUI+U+cdxP1IykdFtUiJfzY3MYhZ6
+i1hl7Qf36iTTiNgmyuvsFqeEHH4VRmQJIka53VwHhFCnTjE/ASPR+DYEGrvU5bbU
+G1wWyZ43ij6pfTAkQLK1RED6XG/VPv8ywuckCuTkqp//TKy+N1giCBYO9qcvtWxP
+rHukgqifOGQXbnK2fEzFRCoKtCUNsAyrmEr5GhrJpln0AKUKbwrQpTTKD/QO+7rX
+uz4sfAxoayb/HCn+d/kwhQ1EjK+QinCTXTq2GIulhRFco11XFt3HyADxBXHCbgc8
+N2k2fBLFnhtpEUVEHuu5spaxic1N+onrkknyRjXznYc8vuT4tzGnNkuBdpuyBNWA
+fU/mAu0kTKADxJ0An51xkw2luDdiKwPDvSQlLMND1MgnsG0F1MbF2FsJlOgna9lt
+t7zedr/VnDYmBLmXHfDJjZGTgjINtxaXQTGaIgsuuplRKGv1BLrJPVcMcujhJBrU
+Kmrn47a5lGHjTkKB5UPkHu9txF2k+bTsOoo0/rXHqP4Zjc99G2AhuiVvNc1PcihC
+fYcIqtozfmPmW1/nAajjC9MIWqbf6ucrE0ingzKWxLrR/xVmUjOGRl/Cn1lKAJi3
+G6GHJd+taFv3Jhcr64RincO9mWdqAl1wcj4YkpmMvdlPAgMBAAGjggHxMIIB7TAJ
+BgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly93d3cuc2FtYmEuZXhh
+bXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMBEGCWCG
+SAGG+EIBAQQEAwIGQDALBgNVHQ8EBAMCBeAwRgYJYIZIAYb4QgENBDkWN0RvbWFp
+biBDb250cm9sbGVyIENlcnRpZmljYXRlIGxvY2FsZGMuc2FtYmEuZXhhbXBsZS5j
+b20wHQYDVR0OBBYEFOHfcwvxPoZDpLPpjUR9PLIZwbzyMB8GA1UdIwQYMBaAFKI+
+Aiqjp005tAhNmcwMdTbqJ8M+MD0GA1UdEQQ2MDSCGWxvY2FsZGMuc2FtYmEuZXhh
+bXBsZS5jb22gFwYJKwYBBAGCNxkBoAoECAEjRWeJq83vMDEGA1UdEgQqMCiBJmNh
+LXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0GCWCGSAGG+EIB
+BARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMvQ0Etc2FtYmEu
+ZXhhbXBsZS5jb20tY3JsLmNybDAmBgNVHSUEHzAdBggrBgEFBQcDAgYIKwYBBQUH
+AwEGBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggQBAIksV5gXwXOmEAJvpqxHHDct
+HaE8xSm2OuboFOw7dO7a2y2XPtOMnUJ+sEbpVHRPNN+eNH+eip1Nss/7cT/LMuZF
+57TTnujKpc8We3a1TuC5u3mxgqfTI8s8RmNjlrNbYp6Z3AIX+QdjhnYGGgIbmt8d
+zedG/poTh0fd4ndYUKJsyaD4FB8711mcib0uLc5g9MYs42PPNIRh2ZAukPxbT6IA
+h+dA4PzRJIvQKAHTU6yxWH+HKThWk92iFEqalLn4lLIER9u4OOaFK8/UcoiLDY6g
+afmfECKCnMXsAeMHoWk3lCU6zRcpN40k0ycPTb+wMTa4xqhpC98o+OLc2pU+f9c/
+pY+San2tOqyvcytf8bMiku/acYSeSyN7abcp/MUFhEv/BpLu9ZsUKq++7wLh59Do
+0Cl8SEDxlbsIsjDFgYCokVsuCDswRAe1xAsHdMpdNz11+bxtIabgkdj5J4gFWKf0
+Nuu6QGM2FUKYC+LRyRELKYHhxwJ++gVlUXvWGjNG/KXU/WToyBHU0UHZORgIo+0V
+cNkU9brJuz6WjV3Mw1y2yHkCLuKhBrqlIRy/Fn8t2ZMHkrH67j/jVjXzMKoRVNNx
+yynUYOFsrsQk4wBPX1KwP/R2823bvNhlxDe+GoebZcQg3dqpTJ+GMytJpveqztqY
+O+NfrLgbRQ5WWftJOA+31En4e6z62LgdFtuyTBXY5+trOP/SaSam9lAVRS8SsgXU
+v29TeWSb1YuhCD5D7gj+m+qDiYpqU5gexZFMepkrbZfclhveJ8WvD91CXCN9vGtb
+q0cpmDWPnubhX5Zqvc88R4mLrSHeINqZgsEOm3w4IdixHDTFTvf+fV6kL/h9XDAs
+nuZaT9MVkOZvaepRk48s3afDPFCo0boLXMwuTldxIQihLL2nIEuuXAJ6zZr+Htvs
+zjsSN8uWIHs7sVouhAP5CzJDwE7j6nnnmhNU5agaF8R5eCVjq2c5OaBsxMWUrBaS
+PfAaGp7KeoQbwVpfTGWKMKZebA6uv6wJlw+DXJLO5EPeBkuW9UY7fajjD9P+AMfU
+eU5fvexZEvllI/rnl6KmOTujHtpHxRhbjad7KRxaegbGkp63O/DFVujPhM3dYQ8h
+JfQeK0C2dCiNQfYsHc60OdHhvhV4ydeZoZ1QQ9rsQGlqOxevKCIJ4H04nqfKt/eU
+iiobMk4obRiVykJnyLsTJDFDhD6VZghcFX9rk8yPuHZ6/XRK1m9kdN9y9zSjUPDb
+vworG0i3ycCXIyexVlueEBJav/84YdpBdRXFA8Ig/X+EwJSOEe0BuvEZtQUdv4nq
+yThO0s9bJMY3oY5giVxS/31eLcn4sXkHTC8Yhei6vz7aWUPfKXl+ADjS/KmOO50=
+-----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 0000000..4ab5d5a
--- /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 at samba.example.com
+ Validity
+ Not Before: Mar 16 23:29:04 2016 GMT
+ Not After : Mar 11 23:29:04 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Users, CN=administrator at samba.example.com/emailAddress=administrator at samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:af:87:9e:1e:7f:c0:ab:da:47:22:74:d0:df:01:
+ f1:67:6c:ac:c4:b7:d9:18:97:e5:7a:62:76:33:b6:
+ 52:f2:92:90:75:ac:a3:94:7e:0c:29:75:c9:83:2f:
+ 19:66:60:84:45:ff:d5:a9:bd:c5:3a:a2:d8:25:cf:
+ 15:8a:23:3e:09:73:2f:99:1d:24:1f:e6:96:7e:7b:
+ c4:1e:8d:55:5b:c1:18:69:cd:1d:b4:22:d5:7b:db:
+ 5e:7c:91:f2:8e:c1:03:30:ee:63:46:5a:54:d5:40:
+ ac:79:55:00:71:07:8d:3e:0e:ed:ff:93:6c:f1:2d:
+ 84:c1:51:a3:7c:49:cf:ff:85:7b:c0:64:c1:ba:c8:
+ 66:7a:ff:17:2a:74:ea:16:6a:1d:97:c0:27:57:10:
+ be:76:f5:9a:63:56:c7:25:c6:fc:a7:5e:00:a6:1a:
+ 3d:21:bd:7a:f9:e3:03:60:ce:df:16:06:fc:05:bc:
+ d1:c8:5d:e7:33:ed:52:8b:60:5b:60:c5:70:13:1d:
+ c1:b3:08:13:09:3b:05:e8:02:40:12:45:89:af:87:
+ 1f:6a:8f:62:ce:1e:17:13:34:82:81:86:e9:bb:85:
+ 5b:75:1d:f4:3a:02:b4:a6:58:23:fe:c3:3a:35:09:
+ 95:bb:f7:79:bc:e3:97:e6:6d:77:24:aa:2d:51:50:
+ 37:69
+ 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 at samba.example.com
+ X509v3 Subject Key Identifier:
+ 45:DA:4B:8D:05:9C:62:4E:62:C3:D7:5C:5F:D3:D9:85:B4:9B:F2:2C
+ X509v3 Authority Key Identifier:
+ keyid:A2:3E:02:2A:A3:A7:4D:39:B4:08:4D:99:CC:0C:75:36:EA:27:C3:3E
+
+ X509v3 Subject Alternative Name:
+ email:administrator at samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com at 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
+ a2:bb:e6:97:67:3c:b6:6e:6e:dd:34:99:16:c6:80:91:08:bf:
+ 91:ba:51:62:5d:76:2f:e5:53:91:3d:99:03:18:a9:84:69:73:
+ 76:66:c3:eb:56:d7:c5:40:91:15:da:de:b2:76:48:7d:8a:8c:
+ 80:79:3c:e6:da:0e:a6:c3:53:d6:74:ee:5f:29:b7:03:46:de:
+ 89:32:14:22:03:30:68:2e:7e:06:d4:ac:9e:82:c0:02:16:7f:
+ 81:ba:ee:7a:e7:8b:f7:fb:99:7f:8c:eb:78:54:97:4e:28:44:
+ da:f4:e2:1b:f8:3e:ac:ca:cc:e3:e3:71:90:91:47:9c:78:ed:
+ 6f:bc:b7:98:12:ea:75:e5:15:f7:26:56:a7:5c:d6:74:a8:13:
+ 7b:23:35:4e:6a:01:f6:a9:f5:5b:9b:d0:ea:ba:0f:c3:c4:1a:
+ e0:b9:a3:ed:5d:28:cb:7f:1d:3e:8a:9a:af:4c:88:00:3c:10:
+ f0:49:85:24:60:e6:cb:d6:9e:00:46:78:4d:90:22:68:4f:10:
+ 39:84:3b:e2:7c:3d:ed:23:41:19:7e:6f:45:59:89:a9:9f:26:
+ c1:f9:7d:4d:0a:b4:10:f9:31:7d:cc:87:d0:4b:62:14:70:86:
+ c8:7d:14:ff:e4:68:e2:de:42:ca:01:c7:aa:2d:5a:a5:72:64:
+ f1:4c:fa:6e:60:15:22:08:68:e6:c6:6a:75:63:24:b5:54:76:
+ d1:97:4f:e0:e8:bc:eb:d0:62:84:4a:b4:3a:07:38:5f:b9:a6:
+ 6a:31:14:47:33:81:bd:d0:a4:a2:da:2b:92:0d:dc:42:c4:0f:
+ 28:0d:b6:1b:33:b5:88:df:1b:a8:d8:90:9a:11:ce:df:d4:14:
+ e9:ac:94:94:95:bb:bc:6e:f1:be:85:29:3f:17:ab:41:14:d8:
+ 20:ba:e0:a2:a3:d3:d4:8b:1e:4b:32:22:8d:0d:c1:e6:39:1a:
+ ce:cd:f3:1d:f1:82:85:d5:e7:80:34:90:a4:0e:d4:af:32:c8:
+ 79:4e:25:32:b6:1e:06:3a:26:42:38:47:1a:32:96:71:5b:fe:
+ 5b:b0:ef:7d:fe:58:ca:eb:b5:c9:4b:2f:12:cb:89:36:22:7c:
+ a6:39:ab:20:c1:2d:cd:6b:34:e1:cd:bc:ed:45:45:12:4a:65:
+ 4b:ab:45:f2:6d:7a:9d:f8:b5:52:78:1b:da:2f:e0:ce:f7:e2:
+ b0:fa:6f:40:3d:dd:e9:39:c3:63:68:ab:77:53:be:3b:dd:9a:
+ bc:d7:d7:fa:6a:bf:bf:74:f7:11:80:87:f9:d3:45:eb:1e:8e:
+ d1:a9:a0:2e:66:e7:20:67:1c:4c:22:43:77:85:ff:1a:23:37:
+ cc:49:de:51:ee:f2:04:2f:a8:98:88:0f:b6:18:53:eb:e2:49:
+ 15:5e:02:8b:1e:7b:e6:c5:d1:0c:df:84:4e:d9:bd:fe:21:48:
+ d4:a4:11:01:27:57:51:d6:c1:b2:a1:1c:11:9a:a7:d1:ab:f0:
+ 99:16:b2:c8:3f:74:25:68:0b:1a:cf:58:0d:cd:cc:1a:6d:8b:
+ ec:1f:70:82:02:40:97:0f:75:2c:53:87:c1:42:5c:d1:7e:19:
+ 78:2c:2c:88:73:33:81:63:38:84:07:0f:16:bb:7c:54:59:03:
+ 94:e7:b8:85:d7:f8:5e:53:35:65:2e:e5:27:65:be:f0:89:65:
+ f6:ab:3f:6e:a5:bd:c1:1a:9e:31:30:68:6e:50:af:54:4c:33:
+ f8:73:2f:41:60:4f:4c:85:1b:ad:7d:db:62:42:dc:87:96:b4:
+ cf:ce:12:50:ed:6c:01:5f:e2:f9:03:f5:f7:4c:6c:8f:2b:5b:
+ 7a:64:7d:19:e8:20:f2:e9:10:58:f3:71:0e:1e:58:68:f2:59:
+ 3c:06:53:7a:f3:60:62:5b:c7:b7:83:58:1d:3d:a6:17:db:33:
+ cc:91:14:af:d6:b9:08:bf:60:af:ac:3e:fe:8b:74:71:20:c7:
+ e7:31:5e:26:6c:28:52:67:12:1e:c3:9b:89:23:5d:88:ee:b0:
+ 6b:db:cc:94:8b:9b:1b:40:b7:66:bc:7d:1d:e1:08:00:20:ba:
+ 41:cd:17:d6:4c:7b:c4:5a:fd:cf:6b:20:e2:b8:86:9c:31:17:
+ c2:d7:7f:1c:3a:d0:fc:1d:f5:7f:c9:96:04:27:de:b8:ef:8d:
+ 38:9a:b3:56:60:ac:c2:07:38:64:19:39:9e:73:6f:ba:59:15:
+ ac:45:42:4d:bb:79:60:7f:ae:c3:8d:63:4a:27:16:0a:ca:92:
+ 7f:f7:a2:02:76:f5:e6:7c:ec:ba:ea:18:cd:9c:3b:ee:37:2c:
+ 9d:78:4e:c9:40:6d:94:cc:ce:ca:f4:33:fc:a4:dd:05:62:d6:
+ 0f:1e:19:63:af:10:c3:ff:02:1a:0a:48:fd:af:f2:a4:0e:64:
+ dd:90:f4:4f:14:1b:90:1f:9e:29:b0:0b:94:a4:d1:2a:87:b9:
+ 3a:76:c2:b6:af:c3:d4:84:6e:85:1c:64:73:46:d0:df:72:c0:
+ 3c:42:91:c4:30:10:11:18:36:bc:e5:17:36:22:5f:c2:3f:ac:
+ 1d:2e:9d:87:11:be:a7:ac:b2:62:35:74:b9:27:27:95:bc:c1:
+ 11:44:f8:64:36:60:74:06:a2:e7:e9:76:be:a7:86:5e:18:1e:
+ bd:dc:b0:aa:ae:92:d6:dd:d6:25:80:d6:c1:be:c1:21:1c:01:
+ 6f:83:20:ae:b7:54:4f:3d:2d:12:fc:a2:cc:49:fd:59
+-----BEGIN CERTIFICATE-----
+MIII/TCCBOWgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTYyMzI5MDRaFw0zNjAzMTEyMzI5MDRaMIGnMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEOMAwGA1UE
+CwwFVXNlcnMxKDAmBgNVBAMMH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5j
+b20xLjAsBgkqhkiG9w0BCQEWH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5j
+b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvh54ef8Cr2kcidNDf
+AfFnbKzEt9kYl+V6YnYztlLykpB1rKOUfgwpdcmDLxlmYIRF/9WpvcU6otglzxWK
+Iz4Jcy+ZHSQf5pZ+e8QejVVbwRhpzR20ItV72158kfKOwQMw7mNGWlTVQKx5VQBx
+B40+Du3/k2zxLYTBUaN8Sc//hXvAZMG6yGZ6/xcqdOoWah2XwCdXEL529ZpjVscl
+xvynXgCmGj0hvXr54wNgzt8WBvwFvNHIXecz7VKLYFtgxXATHcGzCBMJOwXoAkAS
+RYmvhx9qj2LOHhcTNIKBhum7hVt1HfQ6ArSmWCP+wzo1CZW793m845fmbXckqi1R
+UDdpAgMBAAGjggIRMIICDTAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0
+dHA6Ly93d3cuc2FtYmEuZXhhbXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxl
+LmNvbS1jcmwuY3JsMBEGCWCGSAGG+EIBAQQEAwIFoDALBgNVHQ8EBAMCBeAwTwYJ
+YIZIAYb4QgENBEIWQFNtYXJ0IENhcmQgTG9naW4gQ2VydGlmaWNhdGUgZm9yIGFk
+bWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5jb20wHQYDVR0OBBYEFEXaS40FnGJO
+YsPXXF/T2YW0m/IsMB8GA1UdIwQYMBaAFKI+Aiqjp005tAhNmcwMdTbqJ8M+MFsG
+A1UdEQRUMFKBH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5jb22gLwYKKwYB
+BAGCNxQCA6AhDB9hZG1pbmlzdHJhdG9yQHNhbWJhLmV4YW1wbGUuY29tMDEGA1Ud
+EgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0G
+CWCGSAGG+EIBBARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMv
+Q0Etc2FtYmEuZXhhbXBsZS5jb20tY3JsLmNybDAfBgNVHSUEGDAWBggrBgEFBQcD
+AgYKKwYBBAGCNxQCAjANBgkqhkiG9w0BAQsFAAOCBAEAorvml2c8tm5u3TSZFsaA
+kQi/kbpRYl12L+VTkT2ZAxiphGlzdmbD61bXxUCRFdresnZIfYqMgHk85toOpsNT
+1nTuXym3A0beiTIUIgMwaC5+BtSsnoLAAhZ/gbrueueL9/uZf4zreFSXTihE2vTi
+G/g+rMrM4+NxkJFHnHjtb7y3mBLqdeUV9yZWp1zWdKgTeyM1TmoB9qn1W5vQ6roP
+w8Qa4Lmj7V0oy38dPoqar0yIADwQ8EmFJGDmy9aeAEZ4TZAiaE8QOYQ74nw97SNB
+GX5vRVmJqZ8mwfl9TQq0EPkxfcyH0EtiFHCGyH0U/+Ro4t5CygHHqi1apXJk8Uz6
+bmAVIgho5sZqdWMktVR20ZdP4Oi869BihEq0Ogc4X7mmajEURzOBvdCkotorkg3c
+QsQPKA22GzO1iN8bqNiQmhHO39QU6ayUlJW7vG7xvoUpPxerQRTYILrgoqPT1Ise
+SzIijQ3B5jkazs3zHfGChdXngDSQpA7UrzLIeU4lMrYeBjomQjhHGjKWcVv+W7Dv
+ff5Yyuu1yUsvEsuJNiJ8pjmrIMEtzWs04c287UVFEkplS6tF8m16nfi1Ungb2i/g
+zvfisPpvQD3d6TnDY2ird1O+O92avNfX+mq/v3T3EYCH+dNF6x6O0amgLmbnIGcc
+TCJDd4X/GiM3zEneUe7yBC+omIgPthhT6+JJFV4Cix575sXRDN+ETtm9/iFI1KQR
+ASdXUdbBsqEcEZqn0avwmRayyD90JWgLGs9YDc3MGm2L7B9wggJAlw91LFOHwUJc
+0X4ZeCwsiHMzgWM4hAcPFrt8VFkDlOe4hdf4XlM1ZS7lJ2W+8Ill9qs/bqW9wRqe
+MTBoblCvVEwz+HMvQWBPTIUbrX3bYkLch5a0z84SUO1sAV/i+QP190xsjytbemR9
+Gegg8ukQWPNxDh5YaPJZPAZTevNgYlvHt4NYHT2mF9szzJEUr9a5CL9gr6w+/ot0
+cSDH5zFeJmwoUmcSHsObiSNdiO6wa9vMlIubG0C3Zrx9HeEIACC6Qc0X1kx7xFr9
+z2sg4riGnDEXwtd/HDrQ/B31f8mWBCfeuO+NOJqzVmCswgc4ZBk5nnNvulkVrEVC
+Tbt5YH+uw41jSicWCsqSf/eiAnb15nzsuuoYzZw77jcsnXhOyUBtlMzOyvQz/KTd
+BWLWDx4ZY68Qw/8CGgpI/a/ypA5k3ZD0TxQbkB+eKbALlKTRKoe5OnbCtq/D1IRu
+hRxkc0bQ33LAPEKRxDAQERg2vOUXNiJfwj+sHS6dhxG+p6yyYjV0uScnlbzBEUT4
+ZDZgdAai5+l2vqeGXhgevdywqq6S1t3WJYDWwb7BIRwBb4MgrrdUTz0tEvyizEn9
+WQ==
+-----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 0000000..2e2a8b9
--- /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 at samba.example.com
+ Validity
+ Not Before: Mar 16 23:29:25 2016 GMT
+ Not After : Mar 11 23:29:25 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Domain Controllers, CN=addc.addom.samba.example.com/emailAddress=ca-samba.example.com at samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:a6:c4:a9:bf:75:ea:4c:8d:3b:fd:8a:0f:b0:a2:
+ b6:c7:a8:1f:e4:0e:3e:41:ef:d6:10:48:77:7b:4e:
+ 4c:59:e1:bf:6d:c7:18:7b:a8:01:a7:d5:d2:2c:21:
+ 3e:d0:1a:da:58:03:e8:42:f1:53:0e:a7:91:b9:2c:
+ b9:e7:7a:c9:de:5e:ed:4c:93:6b:cc:dd:17:d0:c7:
+ d1:f1:7c:3d:0d:6f:df:5d:53:5a:b1:1f:a3:7b:5b:
+ 41:65:0c:7c:ea:53:df:bb:da:41:15:da:49:e3:b9:
+ 2d:bb:b5:af:ef:8c:b8:84:74:d0:18:16:8e:5c:e4:
+ c2:e7:a1:87:8f:e3:87:8b:0b:bb:90:30:e8:e0:f3:
+ eb:c0:50:5f:b5:7f:54:9a:1b:34:43:fd:be:5a:80:
+ 6e:0f:63:a2:b3:79:42:4a:85:c8:07:c7:82:55:23:
+ 88:d4:4e:03:2f:f1:95:bd:ed:15:2d:3e:16:cd:ff:
+ c7:9b:03:29:36:a6:5d:c9:1a:1e:89:a5:ba:66:83:
+ 0f:96:a8:07:9f:24:b9:1b:8f:02:9a:b8:50:29:8b:
+ be:63:45:fa:45:c3:38:23:a0:98:3a:b4:6b:42:99:
+ 13:36:4b:84:ef:27:89:39:34:79:f8:67:16:7b:9c:
+ 2a:03:41:15:63:46:e4:db:2f:f2:3e:6d:fe:7c:20:
+ 1e:9f:02:48:a4:bc:15:42:a6:f8:38:86:dc:6b:7c:
+ 4e:67:a3:31:81:8e:b6:30:1a:eb:3d:08:25:19:5f:
+ 42:dc:39:ec:79:1d:30:0a:fb:16:8f:3d:19:14:cc:
+ f5:af:d7:c6:75:cf:b3:96:a2:b2:9b:d9:03:01:a3:
+ ca:88:1d:72:ed:6f:d1:bf:57:56:8e:b9:07:9b:b9:
+ 04:13:1e:0b:5a:06:6b:2b:43:a2:dc:d5:b7:f4:ba:
+ d3:ae:9d:ad:fd:d3:8a:7c:2f:87:32:fa:89:88:58:
+ 00:ae:16:2b:9c:1d:58:82:4d:e5:21:da:d5:6c:f7:
+ a8:40:8b:c7:02:d5:36:30:ef:3f:09:9b:a6:d2:31:
+ a3:bf:20:d4:a2:9e:26:c4:b4:c3:0f:0b:6c:00:d1:
+ 2c:16:b1:2a:eb:06:d9:d5:98:c3:cd:cb:20:68:ad:
+ 0a:2c:a1:2f:27:41:5c:91:de:49:62:ed:d8:3a:ef:
+ 68:1c:6d:fe:94:c3:28:68:32:60:08:65:cd:02:9f:
+ 97:96:2f:0f:87:27:3d:b9:0f:85:62:e8:2b:9a:b4:
+ f4:d3:d7:c1:93:96:27:23:29:88:b1:39:99:53:3a:
+ 20:aa:88:44:3b:4a:24:2a:8b:e0:b4:8d:dd:66:30:
+ df:a6:6e:b7:fc:21:43:16:9e:3e:12:20:c8:7a:30:
+ c1:3d:ab
+ 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 addc.addom.samba.example.com
+ X509v3 Subject Key Identifier:
+ 3D:BC:70:0C:74:D4:B8:85:49:1D:08:84:C4:1B:27:F2:AF:72:37:D3
+ X509v3 Authority Key Identifier:
+ keyid:A2:3E:02:2A:A3:A7:4D:39:B4:08:4D:99:CC:0C:75:36:EA:27:C3:3E
+
+ X509v3 Subject Alternative Name:
+ DNS:addc.addom.samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com at 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
+ 9e:8b:bb:0a:7a:dc:c0:94:33:bc:18:a5:e6:4a:1f:ff:8e:21:
+ b1:8f:33:f0:3e:8b:6c:72:55:c4:47:71:5f:ce:e7:31:ef:5b:
+ 62:04:b7:57:8f:a8:27:9f:ed:69:d2:ec:a8:0d:e2:76:33:8d:
+ 41:3a:67:61:5c:53:60:c7:53:ed:d7:99:72:29:1d:ae:d3:ee:
+ c9:76:1c:6d:18:47:e9:94:dd:2e:97:3f:99:af:b5:f4:a1:7c:
+ 92:f6:4d:b5:c1:7a:0c:38:ba:d1:b6:19:9a:9f:e2:02:84:d4:
+ 54:01:38:7b:55:86:4a:ee:3d:85:48:01:da:34:09:69:43:25:
+ 7e:6e:06:73:e0:b9:7c:b5:9c:4e:9c:b5:52:85:32:62:62:25:
+ 39:fa:02:4b:51:2e:df:8e:52:17:02:50:f4:99:29:bf:7e:97:
+ 53:91:12:85:9a:69:62:45:59:c4:5b:3f:af:18:e6:7b:e4:86:
+ 5d:f1:9e:5a:2b:3e:14:6e:7e:d4:47:24:ef:d9:a8:ec:d9:a6:
+ cb:b8:4f:1a:86:d9:43:20:41:16:15:5f:81:0d:fe:6b:31:53:
+ c1:f6:84:4c:f3:03:64:d2:e6:44:3d:7a:60:79:d7:37:6f:33:
+ de:c0:a8:b9:6e:fe:b2:79:ac:b4:53:92:b8:0a:59:2b:cc:6b:
+ 37:c4:6f:c6:44:02:f7:7c:c5:c6:a6:6f:c2:ad:de:78:1e:48:
+ 96:cc:fe:59:2e:53:ce:34:d6:e8:f0:56:43:30:32:90:6f:f9:
+ 47:76:ab:99:63:e3:e8:a3:f3:83:98:e9:05:2b:ea:f9:f9:9d:
+ 66:70:c7:2c:00:c2:9e:57:3e:31:43:50:50:c8:db:a8:2d:21:
+ 4e:6f:39:c2:bd:ef:d8:47:99:27:0d:48:b2:58:f1:be:45:bd:
+ fe:c4:a2:56:fc:06:02:dc:19:33:85:53:ed:38:59:01:16:bc:
+ aa:c5:d3:4b:37:54:83:1b:e5:c1:4b:dd:34:6b:e5:d8:35:86:
+ 95:e6:9f:d2:22:84:b1:e2:4f:a7:2e:4d:e6:9c:eb:db:df:42:
+ e1:b4:66:e6:58:d3:28:10:34:97:f3:9c:6b:5f:05:2c:47:2c:
+ e3:75:eb:6f:74:0a:ec:d7:1d:30:80:56:44:12:26:f6:4e:5f:
+ ff:92:f4:62:02:36:9c:62:eb:39:98:53:68:68:95:fb:94:68:
+ 69:b8:3c:66:1a:ce:78:c4:cf:c4:6f:21:ac:a8:a6:f4:ab:69:
+ 2a:2e:00:5d:f7:67:06:b1:4f:97:58:88:55:d8:6e:eb:a5:98:
+ 50:36:21:70:3d:b0:a4:f5:3b:21:b3:1c:f5:a9:dd:c6:4a:c2:
+ 89:b8:5a:b3:bc:1f:21:ce:4c:68:5f:98:d8:39:70:d2:7e:a0:
+ 90:df:ad:a3:13:eb:3c:93:f6:b8:f4:d9:a7:51:b3:0d:ea:ee:
+ d4:57:aa:db:ca:7c:8a:a0:08:c3:98:9a:3a:b7:ba:2a:50:92:
+ 26:c2:e3:11:ba:12:60:24:b9:59:df:62:a8:d7:4d:a3:cb:ea:
+ 46:e8:39:f9:83:14:a8:5c:44:75:71:6b:7f:99:bd:68:58:d9:
+ 6b:d1:cd:c7:45:95:9e:44:1e:85:35:c0:30:2b:18:aa:eb:2f:
+ 93:d5:be:66:5d:70:ed:1d:04:f2:c1:1e:b5:ec:45:0c:04:f6:
+ 9d:88:d3:0c:20:5e:5b:23:df:34:a1:f5:ea:b4:a1:44:c0:da:
+ d5:ea:89:e8:b5:cb:dc:f8:92:ee:ac:8d:61:ed:bf:74:2b:28:
+ 79:1f:f4:9a:ff:63:bd:e6:aa:79:1d:2c:26:4a:b2:26:53:57:
+ ba:88:0e:eb:19:57:c0:10:a0:1e:81:2a:c0:56:2e:c3:2a:81:
+ bf:c1:5a:e7:48:ce:c1:6a:b9:6c:41:cc:44:a6:b8:70:e2:57:
+ 0e:6d:41:d6:61:da:bf:ac:20:2c:a7:2a:67:23:98:00:ba:ce:
+ 8b:a8:c2:45:66:a7:08:eb:7f:0a:b5:e7:9b:d6:f4:07:d5:b3:
+ 43:cd:27:d4:fa:c9:40:8f:af:b2:36:1c:e7:44:b4:4e:cc:5a:
+ 2b:73:ad:8f:c4:d9:47:a6:fb:2c:7d:1a:80:2a:55:b3:80:34:
+ 6f:8e:17:27:93:05:21:40:e9:8f:bf:47:6a:52:f5:2e:b5:18:
+ d1:8c:1d:83:04:80:55:fd:21:28:dc:7c:be:c8:c1:5f:e4:40:
+ d3:13:e4:66:bf:ad:92:4e:9b:db:c1:be:a3:42:74:da:c3:2c:
+ 0a:da:3f:94:14:ad:7e:de:81:c6:01:6a:f7:7a:b4:25:51:b0:
+ ab:cd:b3:3a:77:bf:c3:6b:04:44:30:73:41:ad:93:49:67:ee:
+ 43:d1:96:8e:36:83:2b:1b:6c:e7:cc:3e:d6:16:b9:88:4a:ab:
+ 56:c0:76:00:f6:9a:6a:8a:e3:e0:41:75:9d:3b:47:0f:c9:0a:
+ 8e:9f:9c:00:92:bb:ae:d8:42:56:35:64:eb:59:13:da:2c:63:
+ 83:c3:ec:68:91:b5:f3:71:85:48:54:c3:9d:a1:c8:63:f3:de:
+ 5d:a5:34:a9:1e:85:2c:2c:b5:d8:a9:62:8d:26:1f:b2:9e:a7:
+ 83:4d:df:69:63:b5:b7:e5:dd:e7:3b:18:e5:b3:77:df:c5:47:
+ b3:f7:8c:e7:5e:87:2e:46:e3:8f:b1:2b:9b:c6:26:2d:1a:28:
+ 30:13:10:86:5b:46:87:b1:2d:12:ce:b6:fe:1c:4e:44
+-----BEGIN CERTIFICATE-----
+MIIJ9DCCBdygAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTYyMzI5MjVaFw0zNjAzMTEyMzI5MjVaMIG4MQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEbMBkGA1UE
+CwwSRG9tYWluIENvbnRyb2xsZXJzMSUwIwYDVQQDDBxhZGRjLmFkZG9tLnNhbWJh
+LmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkBFiZjYS1zYW1iYS5leGFtcGxlLmNv
+bUBzYW1iYS5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAKbEqb916kyNO/2KD7CitseoH+QOPkHv1hBId3tOTFnhv23HGHuoAafV0iwh
+PtAa2lgD6ELxUw6nkbksued6yd5e7UyTa8zdF9DH0fF8PQ1v311TWrEfo3tbQWUM
+fOpT37vaQRXaSeO5Lbu1r++MuIR00BgWjlzkwuehh4/jh4sLu5Aw6ODz68BQX7V/
+VJobNEP9vlqAbg9jorN5QkqFyAfHglUjiNROAy/xlb3tFS0+Fs3/x5sDKTamXcka
+HomlumaDD5aoB58kuRuPApq4UCmLvmNF+kXDOCOgmDq0a0KZEzZLhO8niTk0efhn
+FnucKgNBFWNG5Nsv8j5t/nwgHp8CSKS8FUKm+DiG3Gt8TmejMYGOtjAa6z0IJRlf
+Qtw57HkdMAr7Fo89GRTM9a/XxnXPs5aispvZAwGjyogdcu1v0b9XVo65B5u5BBMe
+C1oGaytDotzVt/S6066drf3TinwvhzL6iYhYAK4WK5wdWIJN5SHa1Wz3qECLxwLV
+NjDvPwmbptIxo78g1KKeJsS0ww8LbADRLBaxKusG2dWYw83LIGitCiyhLydBXJHe
+SWLt2DrvaBxt/pTDKGgyYAhlzQKfl5YvD4cnPbkPhWLoK5q09NPXwZOWJyMpiLE5
+mVM6IKqIRDtKJCqL4LSN3WYw36Zut/whQxaePhIgyHowwT2rAgMBAAGjggH3MIIB
+8zAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly93d3cuc2FtYmEu
+ZXhhbXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMBEG
+CWCGSAGG+EIBAQQEAwIGQDALBgNVHQ8EBAMCBeAwSQYJYIZIAYb4QgENBDwWOkRv
+bWFpbiBDb250cm9sbGVyIENlcnRpZmljYXRlIGFkZGMuYWRkb20uc2FtYmEuZXhh
+bXBsZS5jb20wHQYDVR0OBBYEFD28cAx01LiFSR0IhMQbJ/KvcjfTMB8GA1UdIwQY
+MBaAFKI+Aiqjp005tAhNmcwMdTbqJ8M+MEAGA1UdEQQ5MDeCHGFkZGMuYWRkb20u
+c2FtYmEuZXhhbXBsZS5jb22gFwYJKwYBBAGCNxkBoAoECAEjRWeJq83vMDEGA1Ud
+EgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0G
+CWCGSAGG+EIBBARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMv
+Q0Etc2FtYmEuZXhhbXBsZS5jb20tY3JsLmNybDAmBgNVHSUEHzAdBggrBgEFBQcD
+AgYIKwYBBQUHAwEGBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggQBAJ6Luwp63MCU
+M7wYpeZKH/+OIbGPM/A+i2xyVcRHcV/O5zHvW2IEt1ePqCef7WnS7KgN4nYzjUE6
+Z2FcU2DHU+3XmXIpHa7T7sl2HG0YR+mU3S6XP5mvtfShfJL2TbXBegw4utG2GZqf
+4gKE1FQBOHtVhkruPYVIAdo0CWlDJX5uBnPguXy1nE6ctVKFMmJiJTn6AktRLt+O
+UhcCUPSZKb9+l1OREoWaaWJFWcRbP68Y5nvkhl3xnlorPhRuftRHJO/ZqOzZpsu4
+TxqG2UMgQRYVX4EN/msxU8H2hEzzA2TS5kQ9emB51zdvM97AqLlu/rJ5rLRTkrgK
+WSvMazfEb8ZEAvd8xcamb8Kt3ngeSJbM/lkuU8401ujwVkMwMpBv+Ud2q5lj4+ij
+84OY6QUr6vn5nWZwxywAwp5XPjFDUFDI26gtIU5vOcK979hHmScNSLJY8b5Fvf7E
+olb8BgLcGTOFU+04WQEWvKrF00s3VIMb5cFL3TRr5dg1hpXmn9IihLHiT6cuTeac
+69vfQuG0ZuZY0ygQNJfznGtfBSxHLON16290CuzXHTCAVkQSJvZOX/+S9GICNpxi
+6zmYU2holfuUaGm4PGYaznjEz8RvIayopvSraSouAF33ZwaxT5dYiFXYbuulmFA2
+IXA9sKT1OyGzHPWp3cZKwom4WrO8HyHOTGhfmNg5cNJ+oJDfraMT6zyT9rj02adR
+sw3q7tRXqtvKfIqgCMOYmjq3uipQkibC4xG6EmAkuVnfYqjXTaPL6kboOfmDFKhc
+RHVxa3+ZvWhY2WvRzcdFlZ5EHoU1wDArGKrrL5PVvmZdcO0dBPLBHrXsRQwE9p2I
+0wwgXlsj3zSh9eq0oUTA2tXqiei1y9z4ku6sjWHtv3QrKHkf9Jr/Y73mqnkdLCZK
+siZTV7qIDusZV8AQoB6BKsBWLsMqgb/BWudIzsFquWxBzESmuHDiVw5tQdZh2r+s
+ICynKmcjmAC6zouowkVmpwjrfwq155vW9AfVs0PNJ9T6yUCPr7I2HOdEtE7MWitz
+rY/E2Uem+yx9GoAqVbOANG+OFyeTBSFA6Y+/R2pS9S61GNGMHYMEgFX9ISjcfL7I
+wV/kQNMT5Ga/rZJOm9vBvqNCdNrDLAraP5QUrX7egcYBavd6tCVRsKvNszp3v8Nr
+BEQwc0Gtk0ln7kPRlo42gysbbOfMPtYWuYhKq1bAdgD2mmqK4+BBdZ07Rw/JCo6f
+nACSu67YQlY1ZOtZE9osY4PD7GiRtfNxhUhUw52hyGPz3l2lNKkehSwstdipYo0m
+H7Kep4NN32ljtbfl3ec7GOWzd9/FR7P3jOdehy5G44+xK5vGJi0aKDATEIZbRoex
+LRLOtv4cTkQ=
+-----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 0000000..7486a63
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/NewCerts/03.pem
@@ -0,0 +1,169 @@
+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 at samba.example.com
+ Validity
+ Not Before: Mar 16 23:29:41 2016 GMT
+ Not After : Mar 11 23:29:41 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Users, CN=administrator at addom.samba.example.com/emailAddress=administrator at addom.samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:be:91:64:f2:1b:2b:ed:9b:40:bc:0d:46:23:49:
+ 77:32:74:fe:cb:9a:46:86:33:1e:56:bd:c8:da:dd:
+ e6:2a:07:34:61:1c:f0:b8:71:29:24:2b:90:f3:43:
+ 99:6f:69:f6:ff:8d:b9:b7:3f:f3:36:6a:99:90:90:
+ d6:95:63:4e:88:5a:d7:41:89:7f:73:13:64:49:c7:
+ de:42:65:08:5d:ca:04:b2:68:3a:40:7f:6a:05:df:
+ 56:30:2f:ac:1b:8b:0f:c3:15:3c:38:0f:90:50:44:
+ 00:bb:59:40:f6:d2:e8:5b:73:03:0d:f6:7d:38:5d:
+ 2f:99:c3:0d:13:0f:74:d0:9e:ef:1e:92:42:c4:46:
+ 7c:dc:85:7e:e9:af:91:4e:9d:5f:82:af:58:60:18:
+ a5:ac:91:6e:dd:cf:a7:32:3c:d2:f4:e9:81:be:80:
+ 9e:0c:ca:1f:1a:be:98:c4:fe:e6:25:c1:89:fe:16:
+ 0a:30:90:d3:d4:e5:af:89:24:64:12:d0:4f:19:e2:
+ 1b:86:fb:06:a9:63:d1:47:10:89:dc:2b:52:24:dc:
+ 66:a9:56:c2:cb:f4:ec:35:12:f4:ad:5e:fc:ff:86:
+ e9:b1:f9:1f:b3:ce:44:fb:be:04:af:8d:42:9b:56:
+ a5:02:7f:c5:cf:5f:23:41:1c:69:ee:33:97:7a:81:
+ 50:8b
+ 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 at addom.samba.example.com
+ X509v3 Subject Key Identifier:
+ 30:10:6E:1F:7E:52:33:8C:C8:85:E5:92:74:5D:76:7E:E9:33:5B:36
+ X509v3 Authority Key Identifier:
+ keyid:A2:3E:02:2A:A3:A7:4D:39:B4:08:4D:99:CC:0C:75:36:EA:27:C3:3E
+
+ X509v3 Subject Alternative Name:
+ email:administrator at addom.samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com at 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
+ 53:3e:51:d2:5d:2c:69:23:5b:dd:05:1a:23:ff:39:5d:54:63:
+ e5:da:e1:4b:60:8c:09:7c:4e:8e:da:8a:bb:63:5d:bc:2d:a0:
+ d4:ce:9e:d2:ce:38:d7:32:67:ba:4a:a6:d1:1d:c4:c7:50:e8:
+ 9a:9e:44:56:1a:9c:f4:8f:b9:8e:39:84:21:db:0f:60:8a:60:
+ b4:0f:4f:3c:35:a0:d2:37:3d:88:e8:0a:18:a7:a7:2d:19:e3:
+ aa:d3:8e:18:8f:35:ef:3e:4a:95:c4:d3:9b:f4:cf:89:c2:70:
+ b9:8c:5c:ef:8a:9e:7a:56:73:13:eb:8b:b7:d9:e1:88:5b:c4:
+ 62:47:42:45:8d:7b:2d:cf:71:83:1b:48:9d:84:8f:65:66:97:
+ 61:fc:f6:30:34:e8:88:2a:34:91:48:dc:7a:b7:65:bc:9c:98:
+ 00:4c:e7:49:fe:4d:a9:56:ea:87:d6:6c:46:39:f2:98:5b:56:
+ 14:82:f2:9e:b8:ad:fd:89:36:48:87:4e:5c:ef:3f:e0:35:ff:
+ 72:5f:5b:e1:c2:fd:d9:6e:40:2b:35:ad:50:08:74:94:87:89:
+ c4:cd:c7:ab:a7:19:4e:ba:f2:1d:83:0f:b0:cf:9c:e6:df:73:
+ 36:88:cf:42:9c:a3:72:27:0f:f7:bf:5b:cc:6b:e5:20:03:b5:
+ 4a:1c:f3:7d:ae:92:43:aa:bb:13:07:a4:3a:77:3d:34:01:00:
+ f1:89:aa:e8:1b:09:7b:b8:b0:e1:54:03:ff:3d:8d:be:35:b9:
+ 13:b2:59:58:32:48:93:f8:e7:d7:3d:49:70:01:44:e6:2b:21:
+ b3:75:49:ae:44:7a:50:15:b8:65:f3:c3:48:96:df:c8:d9:2a:
+ f7:c5:2a:7e:2c:68:77:af:2d:78:1b:fc:1a:d8:f4:8b:a6:86:
+ 35:d2:f0:87:e9:d6:30:0a:76:65:f8:71:e9:80:0d:1f:16:86:
+ 89:92:81:34:d9:be:9b:41:25:ec:65:a9:0a:56:b2:03:91:54:
+ 02:21:97:99:74:61:8c:4a:2e:f4:d0:b1:8b:f1:e6:26:52:bc:
+ f6:f2:e0:bd:96:66:22:c3:4e:51:2f:c3:c4:65:65:c7:97:b5:
+ 1b:29:23:7a:c0:7b:fb:49:33:a0:a9:6a:b7:2f:f3:44:6b:5b:
+ 0c:2c:0d:75:f2:50:d5:82:ba:9a:ab:e0:89:0a:b6:b5:8a:5e:
+ 1a:67:ab:d9:a7:21:22:75:61:1e:d7:21:36:15:6a:da:a8:39:
+ 4d:95:50:2b:e6:ac:c4:f6:38:74:c9:c5:ac:ce:2f:b3:c8:d4:
+ ad:18:a7:93:d4:1a:be:c2:be:9e:39:e6:a7:b1:0e:93:d0:9e:
+ cf:b0:ac:53:7d:08:1f:9d:a5:98:2b:4e:f6:80:e4:df:ea:43:
+ a2:f9:64:bf:84:b2:ff:1c:93:36:60:74:08:4e:5b:d6:24:9a:
+ f8:ac:c7:81:f9:2a:a9:00:28:44:15:6a:31:b9:b5:08:89:c8:
+ 31:15:1e:8f:9d:2c:d0:e3:a8:32:2c:68:42:41:19:6c:43:8e:
+ 69:c0:44:01:ba:1c:c4:ea:f4:ff:c8:57:03:ba:df:3f:5e:a5:
+ 03:da:75:31:2e:07:67:a7:5c:02:55:c3:6f:8f:11:f5:8c:56:
+ a1:f7:4b:bb:46:d0:e5:ff:68:c1:77:3d:0d:35:12:f5:40:af:
+ cd:05:5c:53:74:ff:54:e0:c0:c6:10:5c:e8:33:06:0a:50:47:
+ 7e:71:3a:36:66:aa:f8:de:97:2a:ae:bf:8d:6d:d4:39:c4:fd:
+ b3:03:1d:a5:9c:47:39:8c:c0:b3:73:f8:3a:d6:34:ac:49:4f:
+ b3:87:74:11:20:8f:c0:aa:24:a7:30:20:0c:c0:d9:1c:44:ee:
+ ae:c8:b8:13:63:e5:f8:5e:8f:b0:5a:46:c5:83:3d:41:62:06:
+ e4:62:a6:0a:40:cc:8e:59:ad:8a:36:4e:20:e6:f2:32:04:6e:
+ ee:4e:7d:97:88:dc:ea:74:90:c4:ab:a8:b5:bc:6c:81:b1:64:
+ 77:a6:93:34:44:e4:60:38:b1:0c:2b:29:3a:4a:f7:17:d7:3a:
+ c8:42:7e:db:4d:5f:09:92:ae:6c:90:e1:7d:9f:96:9c:1a:82:
+ bd:45:02:76:29:62:e5:b9:14:53:01:53:c0:5a:d5:34:53:7a:
+ 25:49:3e:3d:db:19:7e:29:57:80:78:67:ea:21:3e:3d:59:36:
+ e0:8b:da:75:57:9b:c8:9d:a1:18:18:e2:5c:35:35:9e:62:2c:
+ f5:0f:c0:8f:55:16:a5:d4:9e:cd:0e:78:87:9d:53:d3:01:e1:
+ 18:61:36:1c:06:c3:3a:43:f3:8a:13:e6:4e:52:32:fd:46:21:
+ cd:62:18:1f:ae:f5:f2:1a:ea:7a:01:3b:a1:3f:1d:16:00:91:
+ 5e:94:78:f4:60:33:54:a9:fc:1c:0a:75:f9:17:aa:dd:12:91:
+ 66:4b:f0:d1:60:25:d4:06:d1:99:9c:c5:64:01:4b:ba:d9:66:
+ ba:9c:f7:68:75:fd:11:3a:eb:6e:fb:8f:a6:17:8a:cd:bc:1a:
+ 59:f9:a9:cd:33:db:7d:71:26:7d:c7:be:de:eb:2e:c0:7e:db:
+ 29:08:0e:82:63:1e:8c:8f:e6:21:1c:b1:49:13:9e:df:78:3b:
+ 68:01:17:0f:df:97:96:58:32:48:1e:5c:ff:fa:db:90:b5:05:
+ 84:68:fd:7c:c0:a5:35:d9:75:1e:ea:cc:25:25:3f:6e
+-----BEGIN CERTIFICATE-----
+MIIJGzCCBQOgAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTYyMzI5NDFaFw0zNjAzMTEyMzI5NDFaMIGzMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEOMAwGA1UE
+CwwFVXNlcnMxLjAsBgNVBAMMJWFkbWluaXN0cmF0b3JAYWRkb20uc2FtYmEuZXhh
+bXBsZS5jb20xNDAyBgkqhkiG9w0BCQEWJWFkbWluaXN0cmF0b3JAYWRkb20uc2Ft
+YmEuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+
+kWTyGyvtm0C8DUYjSXcydP7LmkaGMx5Wvcja3eYqBzRhHPC4cSkkK5DzQ5lvafb/
+jbm3P/M2apmQkNaVY06IWtdBiX9zE2RJx95CZQhdygSyaDpAf2oF31YwL6wbiw/D
+FTw4D5BQRAC7WUD20uhbcwMN9n04XS+Zww0TD3TQnu8ekkLERnzchX7pr5FOnV+C
+r1hgGKWskW7dz6cyPNL06YG+gJ4Myh8avpjE/uYlwYn+FgowkNPU5a+JJGQS0E8Z
+4huG+wapY9FHEIncK1Ik3GapVsLL9Ow1EvStXvz/humx+R+zzkT7vgSvjUKbVqUC
+f8XPXyNBHGnuM5d6gVCLAgMBAAGjggIjMIICHzAJBgNVHRMEAjAAME8GA1UdHwRI
+MEYwRKBCoECGPmh0dHA6Ly93d3cuc2FtYmEuZXhhbXBsZS5jb20vY3Jscy9DQS1z
+YW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMBEGCWCGSAGG+EIBAQQEAwIFoDALBgNV
+HQ8EBAMCBeAwVQYJYIZIAYb4QgENBEgWRlNtYXJ0IENhcmQgTG9naW4gQ2VydGlm
+aWNhdGUgZm9yIGFkbWluaXN0cmF0b3JAYWRkb20uc2FtYmEuZXhhbXBsZS5jb20w
+HQYDVR0OBBYEFDAQbh9+UjOMyIXlknRddn7pM1s2MB8GA1UdIwQYMBaAFKI+Aiqj
+p005tAhNmcwMdTbqJ8M+MGcGA1UdEQRgMF6BJWFkbWluaXN0cmF0b3JAYWRkb20u
+c2FtYmEuZXhhbXBsZS5jb22gNQYKKwYBBAGCNxQCA6AnDCVhZG1pbmlzdHJhdG9y
+QGFkZG9tLnNhbWJhLmV4YW1wbGUuY29tMDEGA1UdEgQqMCiBJmNhLXNhbWJhLmV4
+YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0GCWCGSAGG+EIBBARAFj5odHRw
+Oi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMvQ0Etc2FtYmEuZXhhbXBsZS5j
+b20tY3JsLmNybDAfBgNVHSUEGDAWBggrBgEFBQcDAgYKKwYBBAGCNxQCAjANBgkq
+hkiG9w0BAQsFAAOCBAEAUz5R0l0saSNb3QUaI/85XVRj5drhS2CMCXxOjtqKu2Nd
+vC2g1M6e0s441zJnukqm0R3Ex1Domp5EVhqc9I+5jjmEIdsPYIpgtA9PPDWg0jc9
+iOgKGKenLRnjqtOOGI817z5KlcTTm/TPicJwuYxc74qeelZzE+uLt9nhiFvEYkdC
+RY17Lc9xgxtInYSPZWaXYfz2MDToiCo0kUjcerdlvJyYAEznSf5NqVbqh9ZsRjny
+mFtWFILynrit/Yk2SIdOXO8/4DX/cl9b4cL92W5AKzWtUAh0lIeJxM3Hq6cZTrry
+HYMPsM+c5t9zNojPQpyjcicP979bzGvlIAO1Shzzfa6SQ6q7EwekOnc9NAEA8Ymq
+6BsJe7iw4VQD/z2NvjW5E7JZWDJIk/jn1z1JcAFE5ishs3VJrkR6UBW4ZfPDSJbf
+yNkq98Uqfixod68teBv8Gtj0i6aGNdLwh+nWMAp2Zfhx6YANHxaGiZKBNNm+m0El
+7GWpClayA5FUAiGXmXRhjEou9NCxi/HmJlK89vLgvZZmIsNOUS/DxGVlx5e1Gykj
+esB7+0kzoKlqty/zRGtbDCwNdfJQ1YK6mqvgiQq2tYpeGmer2achInVhHtchNhVq
+2qg5TZVQK+asxPY4dMnFrM4vs8jUrRink9QavsK+njnmp7EOk9Cez7CsU30IH52l
+mCtO9oDk3+pDovlkv4Sy/xyTNmB0CE5b1iSa+KzHgfkqqQAoRBVqMbm1CInIMRUe
+j50s0OOoMixoQkEZbEOOacBEAbocxOr0/8hXA7rfP16lA9p1MS4HZ6dcAlXDb48R
+9YxWofdLu0bQ5f9owXc9DTUS9UCvzQVcU3T/VODAxhBc6DMGClBHfnE6Nmaq+N6X
+Kq6/jW3UOcT9swMdpZxHOYzAs3P4OtY0rElPs4d0ESCPwKokpzAgDMDZHETursi4
+E2Pl+F6PsFpGxYM9QWIG5GKmCkDMjlmtijZOIObyMgRu7k59l4jc6nSQxKuotbxs
+gbFkd6aTNETkYDixDCspOkr3F9c6yEJ+201fCZKubJDhfZ+WnBqCvUUCdili5bkU
+UwFTwFrVNFN6JUk+PdsZfilXgHhn6iE+PVk24IvadVebyJ2hGBjiXDU1nmIs9Q/A
+j1UWpdSezQ54h51T0wHhGGE2HAbDOkPzihPmTlIy/UYhzWIYH6718hrqegE7oT8d
+FgCRXpR49GAzVKn8HAp1+Req3RKRZkvw0WAl1AbRmZzFZAFLutlmupz3aHX9ETrr
+bvuPpheKzbwaWfmpzTPbfXEmfce+3usuwH7bKQgOgmMejI/mIRyxSROe33g7aAEX
+D9+XllgySB5c//rbkLUFhGj9fMClNdl1HurMJSU/bg==
+-----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 0000000..8a0f05e
--- /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 0000000..4daddb7
--- /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 0000000..fb3c34a
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt
@@ -0,0 +1,4 @@
+V 360311232844Z 00 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Domain Controllers/CN=localdc.samba.example.com/emailAddress=ca-samba.example.com at samba.example.com
+V 360311232904Z 01 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Users/CN=administrator at samba.example.com/emailAddress=administrator at samba.example.com
+V 360311232925Z 02 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Domain Controllers/CN=addc.addom.samba.example.com/emailAddress=ca-samba.example.com at samba.example.com
+V 360311232941Z 03 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Users/CN=administrator at addom.samba.example.com/emailAddress=administrator at addom.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 0000000..8f7e63a
--- /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 0000000..8f7e63a
--- /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 0000000..9b973d4
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.old
@@ -0,0 +1,3 @@
+V 360311232844Z 00 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Domain Controllers/CN=localdc.samba.example.com/emailAddress=ca-samba.example.com at samba.example.com
+V 360311232904Z 01 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Users/CN=administrator at samba.example.com/emailAddress=administrator at samba.example.com
+V 360311232925Z 02 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Domain Controllers/CN=addc.addom.samba.example.com/emailAddress=ca-samba.example.com at 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 0000000..17a5571
--- /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 at 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 0000000..930b870
--- /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-----
+MIISljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI8gnWGjK+GVYCAggA
+MBQGCCqGSIb3DQMHBAjV6Im8e0V05wSCElCDz2WaJB4sMLy3WQI/JoMnq+DDjyNC
+7+9th9jeu0Nzcax9NqQ2pKWav2eIwhjS61AM7Zw4+SIqV6mJmuv1IVohHgxAx+nN
+1Poq6bAbgbxk0uwS4nSYXQWOA6xhmjLuZcQcl8bZ6c50Vvc1GLkKiJ7T2x0xr2qt
+pkw86WzbBtrUDbg5IHR3AsgTpyg1Lhs/E1ZCJ3Kd5qXpJwoejvjMCeCqroEzEfo0
+TzIRQS3R/hbnsAzwP03p4HyNs7rY8qGY0K+xv6fTHHiiw+0KbJK0w8KLi7ru0pp8
+YPTTSWBLd96ws0nlhY0aVQzDhlbXSXtqMSQNgZYln7CcH2R8dycwcjDhX0JsPAql
+tIzvkl2goYU7jNI5QnpGPA9VH2U2ipMaEhiaY4yfDolnRaueo3YdmigFz7I4Tanx
+kB3BaF0WrUkIk9oXXH2yIbRm6UAgYhGvNkTcifu6Iv+xfxn2JPulNGWcsJlVsRof
+Hrdy3ZzcDp3bYDoA7gVWQgQKoz3ngIhrgH98zSiNCpKvjWXYx+oWYKHtxVFtFwij
+Pc6+AUdTTjVfQsfNBkE9B2sjmvif6lnKWaMS349zodVCjWQrjsUITJV9Hbqv/8lw
+GrCTFS4R1Wt+ABQDZXZDj4qXQ3Y8NhNI4Z/rkGN9rdaNJuDoyDYzm0tGvoRBP2uV
+GJrAWKt6amx0oSI18L1cqm2hoY7wiZSYFqdXbZm5fbhoELfeak0tMPkHEXx1HtCu
+cVQjcbHTakHcc1cW5TFRlmWZwar4RC//6YO5PENhMacPuW1ld0qF5AbwH303Gw1/
+k4+sYBe0IxiFQWnIFyfCoZI9swTojuUU/p+wxHjwCoxLoiYDN8EOCkHvgcgu7ddQ
+WVHpWyhcNeKcYH71PvyPXjJufbaBouMHrGAodAQXYuRZCwpXvfRG6rqs3yPYkFYn
+dBRdUKDIj2KBLg5n2ssy7ENpRcygUwfgK4H7Qn1yHmDMuq9VjgWNSn1ufCQa+M2L
+CAOMrzX6uRuzw04K2vvv9xhC/Vrr+ISbOL9CDJyvyD4Xzk09JXV9CL8zTDzlJf6s
+DnGhd4F/ejKn8MiOTOYuKugqoFDIw0D3WtbiAHYkXyB1Q13JXjc+N5E74xtGPVUW
+IezrC9yEnQWrrtCBFbAtAKehphfZrvseAB4tBSyToio9wXBVKupa/ghoKEuBIQtE
+OAsBY5Vd8JwZyaLFLBzkPfDqZE6mNSQuSm/x4HjciToQBYicNoGApRH0qneHXdUU
+YUA5QeRp/HRL+yawNPq47HgvmbJh1cpyOsBOGjwqo0Tf0Q6WcqhrZmceHJbpxFeR
+ySDEsuqdSp0prk5CCJ6HO3gsrE6DFLmLNNkZACycIndKO/I98ORY4dmR+zGUoMTS
+Y5Gqpxhuh2LleiquFv3c/mrXVRA4Vl6F43H8isv+7/avhoSkBdoVi17wCR3pdk9F
+naPHRqv6O+VT82S8BqYLR0xk3or+0wzFuaGkh6zPjlYr+DGrTr9qSW34+hJAUsSh
+pcmePlS4A08sM2aZ/z4NSBzGrtSAI0KaeZOZMEyHL7MwZGHvQYz4WbekZJMZR33L
+51ia/VkA2rMw6fgV/HYA3Zwd3NSTQ9jvwP8oAYmjrIbkApQTZQdbGQIh+8kcA4QE
+3seLJAQQ3/reJvkc4jzwbF+A6K53iu23s/FhP89fK93xz+2zxt4bfMb0RQYWSb4u
+aMsTHMC+Aenx93KrVYHvBi/O3PRxPUZQaPPQ+GQVerpmqhnrAtPh8xMjtxRpF3mI
+Hff9RJTCi9jAQWDYAuuWNo1nFi4q6tQU8vCX2T5o+AsvwIrRDxz9E3ELqwPD1Zl8
+YRSBVgQPpy9xS/eHCgBOa7Lch2/gmew0pE6JgHmGSAZbZGVa7QxIsWvrgvNwuDmQ
+pV9xVWttK5dup1un9Z9fiuozO+Iu6a8x0ECCxsUEO2C9bh+Qt1EzjirVy+1WWnKc
+fW2XrFHwQMqIMTjM8JOuWgL2R+YjhFFge0h8CGiXk4f6mnuuGfHhP858Mmxuw0rZ
+bdwwyBq1eiXPrkxm88yo8FYmLXCQExlyFsLbFZ+kJVhZbxeP9siedP14Tgqy2FC0
+2A+tcmypVLu5Vthu66I3wUvmgi9hucwe/s8qCRQwYciN1wzHH6f+uDz//kQIgA75
+AuNAHJYV3uWCKUESpnDL/9W2O6FvWY/j24QG0AkXsl+peovo8CucGUZxphLfsua6
+4x2WrTLehObG+G54CHdOLTrFQDIDRL9Kvmrw8/TGkXEles+WNnB8HxiUQKokA3ld
+fhXy+e/yjaGzwoNY84CV1WXowWJ2vA1Z9gdr1mFpl2uJm1s+RRquuyRI/yXBvGQ4
+x0pPSe8vbQ2OlCzuVMjFpG4dx4oqBwXUR69YigpsVi1A3n23qAPUSjJBflgPLWdG
+x/T+NiQ9TVhFKHqkgiL7e5s5VWaYREXjfDeiVowst/7vJdX3RugJTlVfnmPJ/pJZ
+JnObpWxm7jmJu72fek0bmNaOMvMf4YVB5G/z2gQ0bpwSbl91kxJvTJ6DG9Kb10h9
+ekfffdFdiZHD5V7BUibmt3aYAZSPRG3Scurrv/kKzkH1/cEMnMDb2ppxsfT+LrLu
+92P/7sCxqGJtk6JNiV9MhY3c9gBHsWTIbcJG/wZHzXhwZphoPyFf21I3x11jzQ86
+D3WTC4UQ8ez+PgMvl1ifP0wC0e7ANs8GsDZg9GEI+tBxx4GsAP1dcpr8c+v/wEDF
+/a2fXqtymxWUDc4qCcrE5Az/U7k4tMSIvOiH/QVBsYOybcuvHd4E+Yrx7bXapk0V
+KIgFQm8kVftR32h7KDx55Vcv5a11dEp4TUF1k1MH36GVxMzfqQnnTnwDs67Q2FCs
+YAGt9jF0imAU3KZUwHbJvPYpjNEV9g3pkd4shyB7ZqNXjOFG+rU7F6xOVcf33lBu
+yP653eMJjLR7hKrQ1UiWhgosc9zSUhl+Er6EqV0OoNtXzDI0uHsCzJ4BuLeKzOga
+wXS8JjzHR9Qb+Nf0OljkNgmfCUBk7BDGuvt6ZQwP4pift9+YKJQ9dTLz0QZxeEoA
+Ky9BOkhF4Q9cYACZiSnZGWq5Y+5I+zIPr1LxGfu8gOqhkvne5wAHmC97YbSXaHXI
+rHvFhAzbwdsX2Crgvgd+feIP3LU5T7YhGW3nZMbigaDsBOTUQQW0f8tXygc1QjzT
+dV/mbpoIDz/39PIYKC0BlQQ2S3clfr8SoRWR0bKEypPd7CZXAH4zAdPjKJih3yV/
+SqWxvMKuZFpSu3BJTcrXvN7nvKBzW17VGI0eSE9+SwrsMHZVUjXUolarSYczdC6v
+QKkNV7+Uu04GCNivnE6sYs3M0n5ZSvvBha1/8kUDIi1k6QhvtEauA3WuoMp8/iU2
+mlvT5Kev96glUo1SdCQRLZFh1HXtvKgYiqEZ8FVW3kHMrvDF3Nxh4XDGvuQ6nO8O
+w8TfE56kZVot8KTcYkOBDiyVX/qGLYNNvW2WHm+zygHKVQRkxnL5Y1/GOU10Wr2i
+7ynFFYyjHwj5vkKsqLytQmuIxig2L8eW2WSx74WyWJPLbeHUSVweHjO9DTh9TgUZ
+QEqPRuhTJMXq6VYpMWq9CUYAF/nal1vTab3Q7BbKcDFma89d4m+yv6FTnOnswS5q
+r22NvQwl+09grdVYaL14a+BtkkCYH+SL30B54Vws5W7JS+34OSkMzDZtwwuGUqC3
+P61oG3jsGyJt6knWTgnp83GHKo1jsrP6IooatP4BaPf7PmKcftPuzies10G7MGHm
+h7gAAYVrAW9lDvKKYc7UC/rgf4kJpkqcM6d3eU+9+ccVfmCIbHN4dEE/+VGKMHAA
+qKQS9j5dyoCZH14PXAotyHCmvst08pkKG9Oj7VPG/+rX6tBD3y1LOlMbMKet9Owy
+WA0yTBYXHxr22zcJD6k/7AgkBKbdkJPMR+X9IyINQojpvXJZIKZkVhoSCa4d9DYF
+2xLKo3W3Mqoi3U7sQ42mQsdaozlql+CBYqd3wq1bkGyyqZ4zgm+D9VI+mZ6hZGt/
+77Qlp2j8JeCdsPDy+igzCpz6fkVaQum5fZlg1II5uYR+4EOvn33LbCT+kcqp+YC8
+m32umo2Eg1In2xgfqCpPTEDIjLSxgvC+NtJ/CmGVo6gYebyFLXZlnDbzAhxaOIDO
+p59Tm9K3+wL31FnQOlXtkO9VihN9k5W1qR/MjPH3LaWCFSgMjed3LlOPEFBYmzeV
+oz1oBZcJGVA0aEMA/Oh8hqMjVjz3vaIQfCuJ6eTLob7RDfmnhVaCPHMT9sJDCqKU
+j4r1P0SRj+SRt+tO3kPD3dz8ejXRUb/lTLTSx3fQK0sB7XWu/LJpP3jGgoES6W/t
+Fj6Eai8LXjqr+1rMnc0NKCLlWZakYp8snikOI5b/+t4WsOwhKVFiMbMdtkf5u7J8
+yKLPpkUS/YBxk4Uhv7srkITCzGpE9keV9umQImwPKAtb25DcAXPp5IXuJViHtu6Y
+rKYYlmWgjobgCDvP7NFGKv+7hszZpWmSg/AS13QtPUZ9Fn9mM/Af8Swu5pp2HGUp
+Zme8CjltYjtAk5ChNL+9C5AlVEZoD0x1ag16Gp09ODzEjQ0JebojJuw1X4+q3syD
+BodCMFhwiO2nsnHrr5PALdoAy4YYmQop31HwjhsDShCuSc+8kWnvWRlzyVSI8/vV
+jD8TV68QBeKyU8PDhC2Bmogy/xVYAJthgfK9LYD619Xz8+0h0cTFSwK/WAO4C38l
+WV9SASyAj0O+JMUWheq/Qh4gP2NRDL2fyMFpf8uflwTjmg3Mu39oqcI3SQYk6ViI
+Mq+ClfbU1hYZrakAN8pt8HUM1XbXJRDXnE3hmrTiU+jdNucuunHDjkf9ZaRNgBWW
+yV309Ua9O91EEG0iGjkQ9Sy3ChscBolfvMpayzGtQRFDYWDX6UZnV5zI4ir21ikQ
+A04zphPlCdOWelU8Qs8GuYX8HeXCzc1hUKffARtY2DQqiQ6lmh4YXHM0ILK/kDYo
+ftmcBWpAZEntVRlnrCbPz29cwltn6DHQC6HWKGQyRxafp8fINUOINNMui+W4UR5f
+tNn9IederuOpDvgYDMAzEt59BT8QgRggJl+hlXjRxOXANLTOHWqWKejk8+LAAH3+
+DjBFTX84cfrbbLgrK57E9afEN84KM2EJCCGFXYvc5qBPgrS9oYQwIErvpy89k8fW
+bR7pU41CrHYZG2am774H80FCfofzzAFoJ2pZdPF2Lo95cLxNENy8RjYfePJR2tcf
+vlqNynUvBjabCW6XhtmRK8/fsakfqfaQkZfpHqtA+qAweLh1bcirz3rBeNvwsO3G
+JBxUgNkMel2F78Lg/EfMQL/hxeajDV+LilJkeZeRbHNL18M8dzzJaZkBm2oGylc5
+AS5r4r1EvSINjf1uXDA9CMBNydf6n62VPnDKrk1WK2R+pzFeeVvRayx7PVWacP3N
+JnKPY+t2eIq5JlNCfIHcL8MDHaau4ck/f2lnUJm1OfqhdfAf6wsf+XuEhfkzqsV/
+gRjrumWsuMs7B15eIZNoyP+x9XPfTXvKXtNpWaUbq2iC/rxgMzqzDN0XvHSr8eTL
+I5sg9nlAiezZYcDsGcjpK5EUY3/3zmZtO+OvXg2kA0dQx8QWg51B8MI/f9EprAAp
+O4ypSjvH+Hthnq4Cr1dXtJzOJru3wz0N37Hy/EhMrDYP3XJUjkYJqTrxM8dsT7TD
+RwvRjbJaZYi1mmIakXbHAhEAcIg/Z7hueIYHrOzYaW6akPdxy0yS252mZ83KtUC9
+oxNzYQdMi43bxbWgcTu5RxGPZ99IYUdKziBJiJlOpWFSzPwKcD0bkHeDAbWZ4Aex
+msyzLubI3nPnuszVWgG8cUP1w1HbCC5KAWIOSoRYS6SzcirAZAXuqvoBGGSCiKdJ
+kMIXRjSHgTfNPE0zSkuoYognqtPBQB+tCmEYUwmIidzp7iVe3muLJj1qHRcUNx1g
+XzbpRMOGRUSgMJJlcba5BRNmFnSEjgnFx+v/NEiMhjacOiDDypi58eYPvgLZ0v8I
+UlI0napiKxX1XS9XZE7SI8xXn5zte2de36xAfZTm1gMEYG/sOUndKUUrmsG4ag+u
+ttyW6veD/LMXzYX/vP6zBe8l2RkZp15xMPMSTovij4ELLOAsWmAB8MAQ7p2TThOa
+gmFx0AnWZ55GAXcM6/2dK54ZQjm12KgRz2uZD6RpHgxDlErzHBVY8VFWPHx4b60M
++BVqk94uAsprvWczcuowZwF41MsJ7wm3a1Jtd104mx1/0GokF6EG+NjpSFvHiDN8
+JVlZ24lBIBv/7Q==
+-----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 0000000..6496923
--- /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 0000000..75016ea
--- /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 0000000..d6a1577
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-cert.pem
@@ -0,0 +1,62 @@
+-----BEGIN CERTIFICATE-----
+MIILPDCCBySgAwIBAgIJAM6BrnFPnFmXMA0GCSqGSIb3DQEBCwUAMIHGMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKU2FtYmFTdGF0ZTESMBAGA1UEBwwJU2FtYmFDaXR5
+MRkwFwYDVQQKDBBTYW1iYVNlbGZUZXN0aW5nMRowGAYDVQQLDBFDQSBBZG1pbmlz
+dHJhdGlvbjEgMB4GA1UEAwwXQ0Egb2Ygc2FtYmEuZXhhbXBsZS5jb20xNTAzBgkq
+hkiG9w0BCQEWJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29t
+MB4XDTE2MDMxNjIzMjgzMVoXDTM2MDMxMTIzMjgzMVowgcYxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIDApTYW1iYVN0YXRlMRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNV
+BAoMEFNhbWJhU2VsZlRlc3RpbmcxGjAYBgNVBAsMEUNBIEFkbWluaXN0cmF0aW9u
+MSAwHgYDVQQDDBdDQSBvZiBzYW1iYS5leGFtcGxlLmNvbTE1MDMGCSqGSIb3DQEJ
+ARYmY2Etc2FtYmEuZXhhbXBsZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20wggQiMA0G
+CSqGSIb3DQEBAQUAA4IEDwAwggQKAoIEAQC3qPlXMRW0bS5QonEW4MMRiZlgWRc3
+DLtA1hSg0a0POKXIBTTb26kVWwJkdLdLPf9POdAWa+PtEDcgiTKeNeh3hdCaKQiR
+LGtmR2Ncy5jcLyAaJPHL3ZrYCzKPyfhVLtZqrS+5CmJRs1Ar1zEpRPIcT0Qdb6Jp
+gu43msIQnULTZPatF4Oi847jb/JIXnTYxto7cuk1I/2VFJ8OD2cYypNbCkthwAga
+ftJ0GNsM2Ii0q5aFnrHpCh/UhvQ1XGZfGVgBRrFjQQ75GlSCFXuwLLiyXwpj6c/p
+QPTQuWLe+21rnizpxmXBvP6d2LaX2Vsq/XP9iVN/jVigY4swgk61Z6XFkmsVJErB
++JEOrjdcO0kkkqlSY0aqqpoXgtV8lNxTeKrNllRmW/i/Wz174PPdvR6QQFMG0X/W
+NOtqwBGZqiafHlu1xrtC/RnzC2S3ygKssP9463bO8IDvhv2I3QnbsuQdKhQSE5rr
+VDJcSI1DHe+tGsko4QA2RBFvgO8+877K9qnBXpnVdYrnEk4UlZVk8L7TIngbA7RR
+bZ7j1mE28PIzcGN2ps1IY80CbO6V+60YegT2F7smjRAS9YJyfqM0fs4yoRuT5Day
+BHN9asy//gEVfebXytzfvZvh0Y+XTlxsXbZ24IsaW1IhsLNvny9BX2Ygrv5wnf7i
+zvEGf4rnO4v+d4mn2HrkkYLfIJe/iQAY3c8uABbEZgzrTHqC+oyRE4MQUtjQR+10
+8IOvbVeU716Q3SxyiGlq0Dici84J2izArVuZBGVoS2pytwbNFU7eL5SeirL1Xy/E
+3siV+y6Oxr3sigrAmMQbzr0YQT7yDjVaP61ct8krc5N4Z95SciIlvmEIzKkV8kql
+Uiom+XWP8aRnZmiuvfGnvEyB67MmggEkG1LGIhsp+ZsnTfo4nU716Djlq5pOZHY2
+VTiOLET7Omo/a+RmHwrog4hRm2BYifyt3RGmzoWF77klbow13ov0UrsTF7Sw6Uft
+EnaklsZU9cfFyNLsDjEwRTWQ4QMdq3dI6WSOYN9EWFtxLGY8FypH2QkTOOPsqgXY
+/SxZUBqa3r+MrGRJ2NCF6kr1/yanLicVzNSR4tymEFDfF2FJVOtQqbO370JGIrJE
+3kq89zUUMH9xNP6IJu+N11Xe63028KlJomWq6my8AUk7a0sk8z75FIa5PvUSYhQ8
+gbTYXM2AyYLTYxkLt+OzLLyvQI1l6KX3PWLaa94lqxkjGQWIt/ViL1OTineiTbYJ
+YR2SB4R3S3Y6N3AAT6l7D1/lxThrqzmWAAkbElBTZZrXGybjL3I9q8lzVt98X9HY
+LrVClydpw42drOIX5PQ68+s8lYNBA1/uYim3IgTjDPIqsNIkBOjreYnPAgMBAAGj
+ggEpMIIBJTAdBgNVHQ4EFgQUoj4CKqOnTTm0CE2ZzAx1Nuonwz4wHwYDVR0jBBgw
+FoAUoj4CKqOnTTm0CE2ZzAx1Nuonwz4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMC
+AQYwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3dy5zYW1iYS5leGFtcGxlLmNv
+bS9jcmxzL0NBLXNhbWJhLmV4YW1wbGUuY29tLWNybC5jcmwwEQYJYIZIAYb4QgEB
+BAQDAgEGMDEGA1UdEQQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4
+YW1wbGUuY29tMDEGA1UdEgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJh
+LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IEAQCa8zKgFnArq4GM+OJfiK95
+fYuTgbO+PaH19GWCyNkNCrtasxt6BIdxKYW+rC6VxXBRXSvaPLbiRCDhD9hL03IR
+daQ+R9JanYzoloN7m5q+mSdJpfsIfdlvqKr4hyti6sfC3jnQC1Tp696KrW1P1Ymi
+kOOxksmngZzTYr2q+JhydYsNAdpxeAIAILDZI0F4VzOVPXRy2+Gop+lwWYvtRjjn
+Z8HemYJ8jIGUlldMVInd5+XmS4/+kFLB6Ly+JAoqC9PBUfWiwXIFIPOIM5ia4sNH
+ZeViTG5Kw7MO/esPs7J8VKB6La4v+CYCT4ngT0ekRLXhRi/Dwa8Ok+hFmRtrikvU
+TEqZPOQT3sRqGdlongAZ1kmCkU4n4RhwbMh6WitDKJf7YToMsyrm6LQvGo4Bf1Ns
+mqnY93OSTyOblNGYwq45BMQbGhW21uW93SQg938ojuw4366KeGnHCD3zvyfWh6Yh
+duAWNQb8TNDqhik0lLNVMyrEPpk0f24XrVC2LBia3Z4hQvep/pI8tg1656XbI6/J
+GubM9KW6o0ndZLnMzFFga3JqztzL/Ooqu+yVaA9q89GlN2zv3hafXaC/AChG1b8k
+Esx37mA68jVaTh/1hX8T2hz14EV3LUB2N21W228HuUhZ33PEcR10XMJNJsOOwHUn
+5I902kznpUs3VTVvbWBsEfhZAD9uns07Z5b0b8UN3fZyNmXeE7gObt10obSFzoPt
+yhnTCULNJ0K3cwuQDAC4Y6HQK5hvLBazdvnYT5rZqGneG9ALdQqr9if2gZFeUPQv
+a63VZFwfyx5wQlFwLVbaH3tTl1dweJkZYjUC3BL1rngHNNvD1t//ERXqL2ngOe4C
+1xNNOBAC2Q4upBYAuH+zoT8KMRCxEh22SPNGrlmN+9MwY+ceP1Dxa97vY9FtSMIB
+dYEvoI8TyFhAjC6t4HOUxT4lvpc7Hma+1AlG5x/aSCY2A9ONdLLo5DyXSuLFHgtc
+gh0dJygZ85sd90k8hl+73muHHofG6HuzMNaQhN8sFoaiedhIHa5+Lv6FVyd7Y0dy
+QVHiPVcf5KG3o0y6OnXdfsGNUsak01fqQhIewVghdTU9liGW8PH1UVWO310q1K46
+U46Hp/JBamvvW5B2ZSg8Dj4arS7/TxxNqbIPAtNxtN7Hwg1dubGWMatCv2A8Cx29
+oWIeUG2HKY4XvbdOnpWvCGx+sUqBiK6Sf5zvJF+UigmZPKrZgbrFWSC1tf0RYn9d
+IyH4JGo4uP5OCxBWFvtj2d51qJJvdnlegKkPd9E0vzIZRHJsSoAx54MmqRZQkPzV
+56iQXA4iTfhv2sF7Uer379OV//ML5xIjsV+IkJepTUtAgimqkKKRktCPfFT6mOtw
+-----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 0000000..73b10cb
--- /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
+c2FtYmEuZXhhbXBsZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20XDTE2MDMxNjIzMjgz
+NFoXDTM2MDMxMTIzMjgzNFqgYjBgMDEGA1UdEgQqMCiBJmNhLXNhbWJhLmV4YW1w
+bGUuY29tQHNhbWJhLmV4YW1wbGUuY29tMB8GA1UdIwQYMBaAFKI+Aiqjp005tAhN
+mcwMdTbqJ8M+MAoGA1UdFAQDAgEAMA0GCSqGSIb3DQEBCwUAA4IEAQA13bwPRi4+
+CaG7MSTVA4Z4JZIU1CQagBJCah0XPXl+xIs/aWCxS3jdFnCUNLOxrKk5Onrsv0z7
+YWQJHsH2Lu0I38SPyWhftmhrqn74QQyfbGMGblDufbfJsHNyeME2z0ZtCoHUgaz2
+kMatR7ys6uvOY4Moghr/xNK2QYSzCFsetF/5ua2h547GK+VMqb4wH14WIx0ljVO0
+knpqT+uX5b+3KX2QcUFDIzRJZWBj0gDWzNxL5PSbZbcxtpUpUIgbFHD8HGRAu3R3
+MCJE3mKuKyaRKqLaF/qOWnskkHnIV3gObeKIgWFNLiyQKUAvu0m3QO7b5zqUeOep
+JMy/3dwixIoDU5QU1O7TAvJQhVscjt0baQaklqlI7jKwdd1xk6brIXKqLa55ALd2
+RIs7I01X/ZyukrY+NbvQOGh/Weqnxe2IM91DkVQGYNxaa52Fqlrop3U4qdZRgtuL
+Ye8RP3IPcVEoH/t/fW6IBTEN1uG9vVvyUUW2H4lI44yeNt2Pd+6qXXFyKZ9pfctx
+7zCOdo9/ikSzCddLFKL6bgJ4vxNuSt+4csq79BytK+69SrsGP/R87154uqA8nMPm
+TXpFhL3YBqOklphc1JVCccTp/824vkrgrEOSB7uIZOtdTpTuRabo6R5yv2pjC5GR
+om3sI8c7xKeUUsfxDF2jt4vJHlKgYEx8YgbAdKq3As0fkpsY0IcMSNR1KMq8H4ia
+0eNWy1YmkvcZzZTL1GBtL1XNPHkvmuBHV2rglBg7PAklr/9WX7IM6AZh2WKP0Spe
+ih1C7YlVzCgQgOaGEe28jegtgkr3I84j34GJmK5WO5fa7/au8wzUDEyGTJE1wZxv
+k1s4TKiNuCSiH26qVUKfwpzrqhiW/ElAeKsXxjg/V7anhPbQsd+sz4RNFi9RldlY
+tdXkPmKBTvupJkVa3ZUxl8gyXNW8t8bSpW2kYFOorxnEkvhwIxMhwSC9pyEyNFXa
+sxsMZ/BcvFBcJYORhxMYVNksCriyWRuYsNORC8s9wnygbQ2n3TuoloZ9rR8mc6XK
+3EgLwhOyENWToRurBdN7Vq6BuNtnl5P/Rd2WBTy62EcXkrnJCCUK4ouP3o0MRt/V
+LdQiCVf9nnHdkiWMQMH4pkgrEJb70IvS/MAAee3SFuMNa72zgD9Pgk4NX6upqt8s
+3+wo0gqmg1gJ9RQUyk/TuYMgdBVg68B6G1C8RifxffhZMj/rOm1xdXXwRfmDyrHZ
+aaNZv3VHTEIJjSCHMkDV7SD9d36gdX0F1lLP5HIu0QTWJeyE/fFTD+hQMY5Ryk+c
+nzW2ZYuTp14xWD3NTQzq/NS+BPpOcAtL3hSpyvP4UkIFGZc7OUPPBBwR2xTVLQfZ
+YqKrAHJKgPXZ
+-----END X509 CRL-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-cert.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-cert.pem
new file mode 100644
index 0000000..7486a63
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-cert.pem
@@ -0,0 +1,169 @@
+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 at samba.example.com
+ Validity
+ Not Before: Mar 16 23:29:41 2016 GMT
+ Not After : Mar 11 23:29:41 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Users, CN=administrator at addom.samba.example.com/emailAddress=administrator at addom.samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:be:91:64:f2:1b:2b:ed:9b:40:bc:0d:46:23:49:
+ 77:32:74:fe:cb:9a:46:86:33:1e:56:bd:c8:da:dd:
+ e6:2a:07:34:61:1c:f0:b8:71:29:24:2b:90:f3:43:
+ 99:6f:69:f6:ff:8d:b9:b7:3f:f3:36:6a:99:90:90:
+ d6:95:63:4e:88:5a:d7:41:89:7f:73:13:64:49:c7:
+ de:42:65:08:5d:ca:04:b2:68:3a:40:7f:6a:05:df:
+ 56:30:2f:ac:1b:8b:0f:c3:15:3c:38:0f:90:50:44:
+ 00:bb:59:40:f6:d2:e8:5b:73:03:0d:f6:7d:38:5d:
+ 2f:99:c3:0d:13:0f:74:d0:9e:ef:1e:92:42:c4:46:
+ 7c:dc:85:7e:e9:af:91:4e:9d:5f:82:af:58:60:18:
+ a5:ac:91:6e:dd:cf:a7:32:3c:d2:f4:e9:81:be:80:
+ 9e:0c:ca:1f:1a:be:98:c4:fe:e6:25:c1:89:fe:16:
+ 0a:30:90:d3:d4:e5:af:89:24:64:12:d0:4f:19:e2:
+ 1b:86:fb:06:a9:63:d1:47:10:89:dc:2b:52:24:dc:
+ 66:a9:56:c2:cb:f4:ec:35:12:f4:ad:5e:fc:ff:86:
+ e9:b1:f9:1f:b3:ce:44:fb:be:04:af:8d:42:9b:56:
+ a5:02:7f:c5:cf:5f:23:41:1c:69:ee:33:97:7a:81:
+ 50:8b
+ 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 at addom.samba.example.com
+ X509v3 Subject Key Identifier:
+ 30:10:6E:1F:7E:52:33:8C:C8:85:E5:92:74:5D:76:7E:E9:33:5B:36
+ X509v3 Authority Key Identifier:
+ keyid:A2:3E:02:2A:A3:A7:4D:39:B4:08:4D:99:CC:0C:75:36:EA:27:C3:3E
+
+ X509v3 Subject Alternative Name:
+ email:administrator at addom.samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com at 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
+ 53:3e:51:d2:5d:2c:69:23:5b:dd:05:1a:23:ff:39:5d:54:63:
+ e5:da:e1:4b:60:8c:09:7c:4e:8e:da:8a:bb:63:5d:bc:2d:a0:
+ d4:ce:9e:d2:ce:38:d7:32:67:ba:4a:a6:d1:1d:c4:c7:50:e8:
+ 9a:9e:44:56:1a:9c:f4:8f:b9:8e:39:84:21:db:0f:60:8a:60:
+ b4:0f:4f:3c:35:a0:d2:37:3d:88:e8:0a:18:a7:a7:2d:19:e3:
+ aa:d3:8e:18:8f:35:ef:3e:4a:95:c4:d3:9b:f4:cf:89:c2:70:
+ b9:8c:5c:ef:8a:9e:7a:56:73:13:eb:8b:b7:d9:e1:88:5b:c4:
+ 62:47:42:45:8d:7b:2d:cf:71:83:1b:48:9d:84:8f:65:66:97:
+ 61:fc:f6:30:34:e8:88:2a:34:91:48:dc:7a:b7:65:bc:9c:98:
+ 00:4c:e7:49:fe:4d:a9:56:ea:87:d6:6c:46:39:f2:98:5b:56:
+ 14:82:f2:9e:b8:ad:fd:89:36:48:87:4e:5c:ef:3f:e0:35:ff:
+ 72:5f:5b:e1:c2:fd:d9:6e:40:2b:35:ad:50:08:74:94:87:89:
+ c4:cd:c7:ab:a7:19:4e:ba:f2:1d:83:0f:b0:cf:9c:e6:df:73:
+ 36:88:cf:42:9c:a3:72:27:0f:f7:bf:5b:cc:6b:e5:20:03:b5:
+ 4a:1c:f3:7d:ae:92:43:aa:bb:13:07:a4:3a:77:3d:34:01:00:
+ f1:89:aa:e8:1b:09:7b:b8:b0:e1:54:03:ff:3d:8d:be:35:b9:
+ 13:b2:59:58:32:48:93:f8:e7:d7:3d:49:70:01:44:e6:2b:21:
+ b3:75:49:ae:44:7a:50:15:b8:65:f3:c3:48:96:df:c8:d9:2a:
+ f7:c5:2a:7e:2c:68:77:af:2d:78:1b:fc:1a:d8:f4:8b:a6:86:
+ 35:d2:f0:87:e9:d6:30:0a:76:65:f8:71:e9:80:0d:1f:16:86:
+ 89:92:81:34:d9:be:9b:41:25:ec:65:a9:0a:56:b2:03:91:54:
+ 02:21:97:99:74:61:8c:4a:2e:f4:d0:b1:8b:f1:e6:26:52:bc:
+ f6:f2:e0:bd:96:66:22:c3:4e:51:2f:c3:c4:65:65:c7:97:b5:
+ 1b:29:23:7a:c0:7b:fb:49:33:a0:a9:6a:b7:2f:f3:44:6b:5b:
+ 0c:2c:0d:75:f2:50:d5:82:ba:9a:ab:e0:89:0a:b6:b5:8a:5e:
+ 1a:67:ab:d9:a7:21:22:75:61:1e:d7:21:36:15:6a:da:a8:39:
+ 4d:95:50:2b:e6:ac:c4:f6:38:74:c9:c5:ac:ce:2f:b3:c8:d4:
+ ad:18:a7:93:d4:1a:be:c2:be:9e:39:e6:a7:b1:0e:93:d0:9e:
+ cf:b0:ac:53:7d:08:1f:9d:a5:98:2b:4e:f6:80:e4:df:ea:43:
+ a2:f9:64:bf:84:b2:ff:1c:93:36:60:74:08:4e:5b:d6:24:9a:
+ f8:ac:c7:81:f9:2a:a9:00:28:44:15:6a:31:b9:b5:08:89:c8:
+ 31:15:1e:8f:9d:2c:d0:e3:a8:32:2c:68:42:41:19:6c:43:8e:
+ 69:c0:44:01:ba:1c:c4:ea:f4:ff:c8:57:03:ba:df:3f:5e:a5:
+ 03:da:75:31:2e:07:67:a7:5c:02:55:c3:6f:8f:11:f5:8c:56:
+ a1:f7:4b:bb:46:d0:e5:ff:68:c1:77:3d:0d:35:12:f5:40:af:
+ cd:05:5c:53:74:ff:54:e0:c0:c6:10:5c:e8:33:06:0a:50:47:
+ 7e:71:3a:36:66:aa:f8:de:97:2a:ae:bf:8d:6d:d4:39:c4:fd:
+ b3:03:1d:a5:9c:47:39:8c:c0:b3:73:f8:3a:d6:34:ac:49:4f:
+ b3:87:74:11:20:8f:c0:aa:24:a7:30:20:0c:c0:d9:1c:44:ee:
+ ae:c8:b8:13:63:e5:f8:5e:8f:b0:5a:46:c5:83:3d:41:62:06:
+ e4:62:a6:0a:40:cc:8e:59:ad:8a:36:4e:20:e6:f2:32:04:6e:
+ ee:4e:7d:97:88:dc:ea:74:90:c4:ab:a8:b5:bc:6c:81:b1:64:
+ 77:a6:93:34:44:e4:60:38:b1:0c:2b:29:3a:4a:f7:17:d7:3a:
+ c8:42:7e:db:4d:5f:09:92:ae:6c:90:e1:7d:9f:96:9c:1a:82:
+ bd:45:02:76:29:62:e5:b9:14:53:01:53:c0:5a:d5:34:53:7a:
+ 25:49:3e:3d:db:19:7e:29:57:80:78:67:ea:21:3e:3d:59:36:
+ e0:8b:da:75:57:9b:c8:9d:a1:18:18:e2:5c:35:35:9e:62:2c:
+ f5:0f:c0:8f:55:16:a5:d4:9e:cd:0e:78:87:9d:53:d3:01:e1:
+ 18:61:36:1c:06:c3:3a:43:f3:8a:13:e6:4e:52:32:fd:46:21:
+ cd:62:18:1f:ae:f5:f2:1a:ea:7a:01:3b:a1:3f:1d:16:00:91:
+ 5e:94:78:f4:60:33:54:a9:fc:1c:0a:75:f9:17:aa:dd:12:91:
+ 66:4b:f0:d1:60:25:d4:06:d1:99:9c:c5:64:01:4b:ba:d9:66:
+ ba:9c:f7:68:75:fd:11:3a:eb:6e:fb:8f:a6:17:8a:cd:bc:1a:
+ 59:f9:a9:cd:33:db:7d:71:26:7d:c7:be:de:eb:2e:c0:7e:db:
+ 29:08:0e:82:63:1e:8c:8f:e6:21:1c:b1:49:13:9e:df:78:3b:
+ 68:01:17:0f:df:97:96:58:32:48:1e:5c:ff:fa:db:90:b5:05:
+ 84:68:fd:7c:c0:a5:35:d9:75:1e:ea:cc:25:25:3f:6e
+-----BEGIN CERTIFICATE-----
+MIIJGzCCBQOgAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTYyMzI5NDFaFw0zNjAzMTEyMzI5NDFaMIGzMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEOMAwGA1UE
+CwwFVXNlcnMxLjAsBgNVBAMMJWFkbWluaXN0cmF0b3JAYWRkb20uc2FtYmEuZXhh
+bXBsZS5jb20xNDAyBgkqhkiG9w0BCQEWJWFkbWluaXN0cmF0b3JAYWRkb20uc2Ft
+YmEuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+
+kWTyGyvtm0C8DUYjSXcydP7LmkaGMx5Wvcja3eYqBzRhHPC4cSkkK5DzQ5lvafb/
+jbm3P/M2apmQkNaVY06IWtdBiX9zE2RJx95CZQhdygSyaDpAf2oF31YwL6wbiw/D
+FTw4D5BQRAC7WUD20uhbcwMN9n04XS+Zww0TD3TQnu8ekkLERnzchX7pr5FOnV+C
+r1hgGKWskW7dz6cyPNL06YG+gJ4Myh8avpjE/uYlwYn+FgowkNPU5a+JJGQS0E8Z
+4huG+wapY9FHEIncK1Ik3GapVsLL9Ow1EvStXvz/humx+R+zzkT7vgSvjUKbVqUC
+f8XPXyNBHGnuM5d6gVCLAgMBAAGjggIjMIICHzAJBgNVHRMEAjAAME8GA1UdHwRI
+MEYwRKBCoECGPmh0dHA6Ly93d3cuc2FtYmEuZXhhbXBsZS5jb20vY3Jscy9DQS1z
+YW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMBEGCWCGSAGG+EIBAQQEAwIFoDALBgNV
+HQ8EBAMCBeAwVQYJYIZIAYb4QgENBEgWRlNtYXJ0IENhcmQgTG9naW4gQ2VydGlm
+aWNhdGUgZm9yIGFkbWluaXN0cmF0b3JAYWRkb20uc2FtYmEuZXhhbXBsZS5jb20w
+HQYDVR0OBBYEFDAQbh9+UjOMyIXlknRddn7pM1s2MB8GA1UdIwQYMBaAFKI+Aiqj
+p005tAhNmcwMdTbqJ8M+MGcGA1UdEQRgMF6BJWFkbWluaXN0cmF0b3JAYWRkb20u
+c2FtYmEuZXhhbXBsZS5jb22gNQYKKwYBBAGCNxQCA6AnDCVhZG1pbmlzdHJhdG9y
+QGFkZG9tLnNhbWJhLmV4YW1wbGUuY29tMDEGA1UdEgQqMCiBJmNhLXNhbWJhLmV4
+YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0GCWCGSAGG+EIBBARAFj5odHRw
+Oi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMvQ0Etc2FtYmEuZXhhbXBsZS5j
+b20tY3JsLmNybDAfBgNVHSUEGDAWBggrBgEFBQcDAgYKKwYBBAGCNxQCAjANBgkq
+hkiG9w0BAQsFAAOCBAEAUz5R0l0saSNb3QUaI/85XVRj5drhS2CMCXxOjtqKu2Nd
+vC2g1M6e0s441zJnukqm0R3Ex1Domp5EVhqc9I+5jjmEIdsPYIpgtA9PPDWg0jc9
+iOgKGKenLRnjqtOOGI817z5KlcTTm/TPicJwuYxc74qeelZzE+uLt9nhiFvEYkdC
+RY17Lc9xgxtInYSPZWaXYfz2MDToiCo0kUjcerdlvJyYAEznSf5NqVbqh9ZsRjny
+mFtWFILynrit/Yk2SIdOXO8/4DX/cl9b4cL92W5AKzWtUAh0lIeJxM3Hq6cZTrry
+HYMPsM+c5t9zNojPQpyjcicP979bzGvlIAO1Shzzfa6SQ6q7EwekOnc9NAEA8Ymq
+6BsJe7iw4VQD/z2NvjW5E7JZWDJIk/jn1z1JcAFE5ishs3VJrkR6UBW4ZfPDSJbf
+yNkq98Uqfixod68teBv8Gtj0i6aGNdLwh+nWMAp2Zfhx6YANHxaGiZKBNNm+m0El
+7GWpClayA5FUAiGXmXRhjEou9NCxi/HmJlK89vLgvZZmIsNOUS/DxGVlx5e1Gykj
+esB7+0kzoKlqty/zRGtbDCwNdfJQ1YK6mqvgiQq2tYpeGmer2achInVhHtchNhVq
+2qg5TZVQK+asxPY4dMnFrM4vs8jUrRink9QavsK+njnmp7EOk9Cez7CsU30IH52l
+mCtO9oDk3+pDovlkv4Sy/xyTNmB0CE5b1iSa+KzHgfkqqQAoRBVqMbm1CInIMRUe
+j50s0OOoMixoQkEZbEOOacBEAbocxOr0/8hXA7rfP16lA9p1MS4HZ6dcAlXDb48R
+9YxWofdLu0bQ5f9owXc9DTUS9UCvzQVcU3T/VODAxhBc6DMGClBHfnE6Nmaq+N6X
+Kq6/jW3UOcT9swMdpZxHOYzAs3P4OtY0rElPs4d0ESCPwKokpzAgDMDZHETursi4
+E2Pl+F6PsFpGxYM9QWIG5GKmCkDMjlmtijZOIObyMgRu7k59l4jc6nSQxKuotbxs
+gbFkd6aTNETkYDixDCspOkr3F9c6yEJ+201fCZKubJDhfZ+WnBqCvUUCdili5bkU
+UwFTwFrVNFN6JUk+PdsZfilXgHhn6iE+PVk24IvadVebyJ2hGBjiXDU1nmIs9Q/A
+j1UWpdSezQ54h51T0wHhGGE2HAbDOkPzihPmTlIy/UYhzWIYH6718hrqegE7oT8d
+FgCRXpR49GAzVKn8HAp1+Req3RKRZkvw0WAl1AbRmZzFZAFLutlmupz3aHX9ETrr
+bvuPpheKzbwaWfmpzTPbfXEmfce+3usuwH7bKQgOgmMejI/mIRyxSROe33g7aAEX
+D9+XllgySB5c//rbkLUFhGj9fMClNdl1HurMJSU/bg==
+-----END CERTIFICATE-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-key.pem
new file mode 100644
index 0000000..0d33211
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI06+E0Qn55PYCAggA
+MBQGCCqGSIb3DQMHBAgRIdE1BfEflgSCBMgjWcKNk0gmS+OepxYA2tMjMir2YwFb
+ht/PFx0llj4Zt2U2TgvSFhm7JcsNPXqqqElIvEeNrY5BTB6Jbkd5pt1EpKcBlgHQ
+cPtjslAxo5C5FgvLuzaFd1tRhHm7UWygTRcI+79zRmypOm0v57ZdS6Z218sJc0gk
+re7tBT+lF+S5uCRAUmWBgdVjEFjW+1r0dhVJWYftB8JoE4zW+B0wEz6PIv0cTt7K
+cnjHVMFKWPJStAbJ98RWchF0KWeu+cuWAWt/rJ2QrM+q1bBP4Mgn6XfRnKbcJofk
+BG5v4oo8B/TSe3woBMtf2BheaeXDa96D7lxF7gELTkdodNfJd9s66GLSRKCk6amk
+eJKO8fLZbXpiT0/TGeFvrihWa/ZpVG4I94KDn2a+U8Agq+B1WA6MqCt6txK6GFIN
+okCRyRUYb6TFDI2JA+jeEX+0tStVGp+qNyk4PT4tZOG2BJ2dq5F6+KF0VzE8I7V0
+zIFWQvvwO8N+osvmJgQgxI6JOq0ubiHEEiSrd4lKVO7NJ223I9GXao/z+0l5ywYn
+SL0LEsw2adblRDgzBnsLCqWEeC3Oczg790AaNkqWPolGKBEpOXlCPCjILJfG/7Ii
+GGvuAQaXOOM3fnxb2oTOpFMn6BQDmX77hiCKGTB4VCgTIhwBOpwLDeDxjyUjCp2C
+PPtped8Dne+kK9iGuHyu45sXrVtxfigfKh9+ncCsFVQfpmcYXDiUhn/RUP4qezco
+jkKeC+S4lM9mG/KzWeDUtMlYkEqFA6yxs05VzpxR3h7sizV0YAE2evSxn3w4aYWY
+GGKtVG4h30f7YbxI1N9+2iBTToAejF5gF5/WDPn8N+voohQCIQ6iAZ48vUDuQGme
+mzi73xu774u7M/BnmgtTr1ZG9gvT+F6q6rnJFAqj3k8j+mv2w4XCqytZJ4OGTijo
+j/s/eZDWmo4t/WXUMjePDzXl96hjBq4bZOpqNwKDLsqbVwQrhFzXTkGLhGQAyKb4
+wZywUkYfTdWa9f+A2NmWqry9Ef5KcOJTSHt6FeY5kwcY56iZT+cD4V2pgxTqQBGt
+YUy/j0V35l41OTKZ6x5P3ZSk45w6RPY3/BqcnfvhSFxON3jFivg1DKIcB8WaWjss
+40vP+TthOR2X4FQ/OHKwjs+tC6JpwDuSNCVwj9VBGSgjeXK/aV9BG1A0m4R7qxTV
+aT4tjSSfPfkOf16hTW2ncHTr9rvY3XcYm8eC5E/IEQ7gxpG/JI0+xK2tel0bochs
+aSBP+qGP85Sib3pcnepG6Zhkx4KgTvhbWRAfNS5rB1jLGSpeWQkMZmun91tTuVLK
+fRyfQZ2gkr2ixX/zlPb1bhIXHUBgnoUyUHwZ2lNCDp/dm+nGYqXeeg9lZfD3dYpQ
+Yd1zdR7Faj8aOsC9T4DRUDzgUIUCdvd2wdmnXF1YB43VgXjsAkfZkEVve1ltv4iG
+OAtp0n9aUz+4yS4kBLWEQfNsK7Tz5zjN2BJmm5qQWARxVbR/shhYKqXuY9HbmB95
+sGc1d37pK+n4HvXqQ701zEuvtwyP/P4gg7HjBI2pauuKfT+eVK+xpTBx4W8imY7j
+8IhJ4IBBUWzoMoADD132fVW7f3vpp1XGjvbq5fgDlU6beVsWS9KXBD2Wsl7FDkJ5
+49U=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-openssl.cnf
new file mode 100644
index 0000000..da136b8
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.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 at addom.samba.example.com
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_default = administrator at addom.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 at addom.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 at addom.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 at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-private-key.pem
new file mode 100644
index 0000000..1510760
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-private-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAvpFk8hsr7ZtAvA1GI0l3MnT+y5pGhjMeVr3I2t3mKgc0YRzw
+uHEpJCuQ80OZb2n2/425tz/zNmqZkJDWlWNOiFrXQYl/cxNkScfeQmUIXcoEsmg6
+QH9qBd9WMC+sG4sPwxU8OA+QUEQAu1lA9tLoW3MDDfZ9OF0vmcMNEw900J7vHpJC
+xEZ83IV+6a+RTp1fgq9YYBilrJFu3c+nMjzS9OmBvoCeDMofGr6YxP7mJcGJ/hYK
+MJDT1OWviSRkEtBPGeIbhvsGqWPRRxCJ3CtSJNxmqVbCy/TsNRL0rV78/4bpsfkf
+s85E+74Er41Cm1alAn/Fz18jQRxp7jOXeoFQiwIDAQABAoIBADkGUvmrrdJ1IcLk
+CffnNPbxUYllifMAevSj5+WufwBWlZL10QawPgpnywEwWkqfn9zK8SbnyQSgk4FS
+BhQ/2jEtVbpzxaKOy/TUDSs7BmziVdN5Iu1H81b8hNL4gPzg+P98bD+uUJXkM3/c
+bnctl4A+A0z7VG84W1Ucq93nQyJl18E64i57JMb3tI+423FM3sJBk2FUj64Mwg8r
+0p88gccSieB3GusffHazlJDKrlHdFyClLBnW3OQHegv42JOKZErIMHwlaV8fhF21
+GAARx/pDgnvIYUaGhLrf2pCyIkOZIdUedA84rLwAZT9akOtxpNCAxlVUn4xcpAC1
+EAKzGbECgYEA99Hzh3vDNGINYJjqsw01E71DelNTeUmBOuJKqdOG0YLHiG0tERcx
+9KLv+7Uo/qtuRzpkMHao7+zC4spQBk1yYkjVtPkXhWdgVUOztkkza72jlwtVu0eK
+VYfB7eubOMnSsPtVeYyyM6DFKBRUxo0VKsvvjD/84WdCGsgy+jDRDUkCgYEAxNur
+XMStYOnxdebOGFs5U8jc+/HNNuaCpSkk98uQ0/VfWp8TXA508FYnT6/BcoH+3hHy
+7W/7aMv//0IWgNQk8m1w33svDdq7jRJXrIpyb7QaX2OW8IfTfIMKVXOgxPvD/4IK
+lvmvf8T7K0W7rDYdcfy9bsDb0RQcH0Z3cp4lUzMCgYEAmLjmX6RB1FJo9BLI8Lc+
+8n88ynH3i1NlNKioYqhc+VijJsxBbbrhqmWPh4tJTEjRmUu+2q8FxXYfVCxhzMCF
+sVQ5f2HSwP/IOkOSyM+rxMYFvtvZZaTc94DGXp1H92NJWJBLSLEQUQjO97gv1nyz
+gsBTTBdS/IXqEx81a0ISUyECgYA80saClj4fmIjDbfm1qtHuojwtGAvY76XkE+9Z
+JKtt4f2BSW843TqiW2wwAdTaZXHy+Ua+t//M5GMHYksDqQh1Yv0h/7SNKk0SjF1M
+cUZkXxha6rFjRgRBD1ftCRneYw+u7WYKOcFQz/Lu7s/KqLm2U2nQQ4RneDgsLaCQ
+aG6N4wKBgArI0d3MlNFXLU7bT+q/2BaZ5VBwaF/6DlI4m1hDT8dKtOTja+y6vAm/
+aH82uJyoom8R/w2H/ICe3NuwYgTo/7Vy6xMt1TnskGOc0yjTZBMMU1nN8zrxlgD1
+1Xr8TzGOf//mK4H54B/POSq6WZ0PSXDVGToVWMdif+2Rq16+CcKp
+-----END RSA PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-req.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-req.pem
new file mode 100644
index 0000000..fbaf0fc
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-S03-req.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIDDTCCAfUCAQAwgccxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTYW1iYVN0YXRl
+MRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNhbWJhU2VsZlRlc3Rpbmcx
+DjAMBgNVBAsMBVVzZXJzMS4wLAYDVQQDDCVhZG1pbmlzdHJhdG9yQGFkZG9tLnNh
+bWJhLmV4YW1wbGUuY29tMTQwMgYJKoZIhvcNAQkBFiVhZG1pbmlzdHJhdG9yQGFk
+ZG9tLnNhbWJhLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvpFk8hsr7ZtAvA1GI0l3MnT+y5pGhjMeVr3I2t3mKgc0YRzwuHEpJCuQ
+80OZb2n2/425tz/zNmqZkJDWlWNOiFrXQYl/cxNkScfeQmUIXcoEsmg6QH9qBd9W
+MC+sG4sPwxU8OA+QUEQAu1lA9tLoW3MDDfZ9OF0vmcMNEw900J7vHpJCxEZ83IV+
+6a+RTp1fgq9YYBilrJFu3c+nMjzS9OmBvoCeDMofGr6YxP7mJcGJ/hYKMJDT1OWv
+iSRkEtBPGeIbhvsGqWPRRxCJ3CtSJNxmqVbCy/TsNRL0rV78/4bpsfkfs85E+74E
+r41Cm1alAn/Fz18jQRxp7jOXeoFQiwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEB
+ALQr9rGYIkhd/AXeVoFHs/66rwaq3GccdnJpi023/5LhOlRmMa2BWTuQm3jW/3Oc
+HgQOx9G0GTDpaBtAjOCGDCygw/k23oekVTQtDPiGigMnpuY2vnrjAeUFJo3us5pA
+9eVPzKTzJf5ftc/aoVC39t/1Uks103M8t5vJCcexBTYQONe56XC1krY50PHZNI/u
+stjOmleHZclLBU/BplId43nRlvvdkXihPiEbdV4XvhHRs/6w52DkQst6NH6jzeWk
+anYEP2Oo1ROX5v201414ZaWm7oDxtNuL8NzDt+DUGISwC/9ZcqadzlaoI9XVhOb2
+AfbQMY1Q/3OeR8uRROpnHjE=
+-----END CERTIFICATE REQUEST-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-cert.pem
new file mode 120000
index 0000000..a2eb210
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-cert.pem
@@ -0,0 +1 @@
+USER-administrator at addom.samba.example.com-S03-cert.pem
\ No newline at end of file
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-private-key.pem
new file mode 120000
index 0000000..afbf12e
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at addom.samba.example.com/USER-administrator at addom.samba.example.com-private-key.pem
@@ -0,0 +1 @@
+USER-administrator at addom.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 at samba.example.com/USER-administrator at samba.example.com-S01-cert.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-S01-cert.pem
new file mode 100644
index 0000000..4ab5d5a
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at 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 at samba.example.com
+ Validity
+ Not Before: Mar 16 23:29:04 2016 GMT
+ Not After : Mar 11 23:29:04 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Users, CN=administrator at samba.example.com/emailAddress=administrator at samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:af:87:9e:1e:7f:c0:ab:da:47:22:74:d0:df:01:
+ f1:67:6c:ac:c4:b7:d9:18:97:e5:7a:62:76:33:b6:
+ 52:f2:92:90:75:ac:a3:94:7e:0c:29:75:c9:83:2f:
+ 19:66:60:84:45:ff:d5:a9:bd:c5:3a:a2:d8:25:cf:
+ 15:8a:23:3e:09:73:2f:99:1d:24:1f:e6:96:7e:7b:
+ c4:1e:8d:55:5b:c1:18:69:cd:1d:b4:22:d5:7b:db:
+ 5e:7c:91:f2:8e:c1:03:30:ee:63:46:5a:54:d5:40:
+ ac:79:55:00:71:07:8d:3e:0e:ed:ff:93:6c:f1:2d:
+ 84:c1:51:a3:7c:49:cf:ff:85:7b:c0:64:c1:ba:c8:
+ 66:7a:ff:17:2a:74:ea:16:6a:1d:97:c0:27:57:10:
+ be:76:f5:9a:63:56:c7:25:c6:fc:a7:5e:00:a6:1a:
+ 3d:21:bd:7a:f9:e3:03:60:ce:df:16:06:fc:05:bc:
+ d1:c8:5d:e7:33:ed:52:8b:60:5b:60:c5:70:13:1d:
+ c1:b3:08:13:09:3b:05:e8:02:40:12:45:89:af:87:
+ 1f:6a:8f:62:ce:1e:17:13:34:82:81:86:e9:bb:85:
+ 5b:75:1d:f4:3a:02:b4:a6:58:23:fe:c3:3a:35:09:
+ 95:bb:f7:79:bc:e3:97:e6:6d:77:24:aa:2d:51:50:
+ 37:69
+ 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 at samba.example.com
+ X509v3 Subject Key Identifier:
+ 45:DA:4B:8D:05:9C:62:4E:62:C3:D7:5C:5F:D3:D9:85:B4:9B:F2:2C
+ X509v3 Authority Key Identifier:
+ keyid:A2:3E:02:2A:A3:A7:4D:39:B4:08:4D:99:CC:0C:75:36:EA:27:C3:3E
+
+ X509v3 Subject Alternative Name:
+ email:administrator at samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com at 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
+ a2:bb:e6:97:67:3c:b6:6e:6e:dd:34:99:16:c6:80:91:08:bf:
+ 91:ba:51:62:5d:76:2f:e5:53:91:3d:99:03:18:a9:84:69:73:
+ 76:66:c3:eb:56:d7:c5:40:91:15:da:de:b2:76:48:7d:8a:8c:
+ 80:79:3c:e6:da:0e:a6:c3:53:d6:74:ee:5f:29:b7:03:46:de:
+ 89:32:14:22:03:30:68:2e:7e:06:d4:ac:9e:82:c0:02:16:7f:
+ 81:ba:ee:7a:e7:8b:f7:fb:99:7f:8c:eb:78:54:97:4e:28:44:
+ da:f4:e2:1b:f8:3e:ac:ca:cc:e3:e3:71:90:91:47:9c:78:ed:
+ 6f:bc:b7:98:12:ea:75:e5:15:f7:26:56:a7:5c:d6:74:a8:13:
+ 7b:23:35:4e:6a:01:f6:a9:f5:5b:9b:d0:ea:ba:0f:c3:c4:1a:
+ e0:b9:a3:ed:5d:28:cb:7f:1d:3e:8a:9a:af:4c:88:00:3c:10:
+ f0:49:85:24:60:e6:cb:d6:9e:00:46:78:4d:90:22:68:4f:10:
+ 39:84:3b:e2:7c:3d:ed:23:41:19:7e:6f:45:59:89:a9:9f:26:
+ c1:f9:7d:4d:0a:b4:10:f9:31:7d:cc:87:d0:4b:62:14:70:86:
+ c8:7d:14:ff:e4:68:e2:de:42:ca:01:c7:aa:2d:5a:a5:72:64:
+ f1:4c:fa:6e:60:15:22:08:68:e6:c6:6a:75:63:24:b5:54:76:
+ d1:97:4f:e0:e8:bc:eb:d0:62:84:4a:b4:3a:07:38:5f:b9:a6:
+ 6a:31:14:47:33:81:bd:d0:a4:a2:da:2b:92:0d:dc:42:c4:0f:
+ 28:0d:b6:1b:33:b5:88:df:1b:a8:d8:90:9a:11:ce:df:d4:14:
+ e9:ac:94:94:95:bb:bc:6e:f1:be:85:29:3f:17:ab:41:14:d8:
+ 20:ba:e0:a2:a3:d3:d4:8b:1e:4b:32:22:8d:0d:c1:e6:39:1a:
+ ce:cd:f3:1d:f1:82:85:d5:e7:80:34:90:a4:0e:d4:af:32:c8:
+ 79:4e:25:32:b6:1e:06:3a:26:42:38:47:1a:32:96:71:5b:fe:
+ 5b:b0:ef:7d:fe:58:ca:eb:b5:c9:4b:2f:12:cb:89:36:22:7c:
+ a6:39:ab:20:c1:2d:cd:6b:34:e1:cd:bc:ed:45:45:12:4a:65:
+ 4b:ab:45:f2:6d:7a:9d:f8:b5:52:78:1b:da:2f:e0:ce:f7:e2:
+ b0:fa:6f:40:3d:dd:e9:39:c3:63:68:ab:77:53:be:3b:dd:9a:
+ bc:d7:d7:fa:6a:bf:bf:74:f7:11:80:87:f9:d3:45:eb:1e:8e:
+ d1:a9:a0:2e:66:e7:20:67:1c:4c:22:43:77:85:ff:1a:23:37:
+ cc:49:de:51:ee:f2:04:2f:a8:98:88:0f:b6:18:53:eb:e2:49:
+ 15:5e:02:8b:1e:7b:e6:c5:d1:0c:df:84:4e:d9:bd:fe:21:48:
+ d4:a4:11:01:27:57:51:d6:c1:b2:a1:1c:11:9a:a7:d1:ab:f0:
+ 99:16:b2:c8:3f:74:25:68:0b:1a:cf:58:0d:cd:cc:1a:6d:8b:
+ ec:1f:70:82:02:40:97:0f:75:2c:53:87:c1:42:5c:d1:7e:19:
+ 78:2c:2c:88:73:33:81:63:38:84:07:0f:16:bb:7c:54:59:03:
+ 94:e7:b8:85:d7:f8:5e:53:35:65:2e:e5:27:65:be:f0:89:65:
+ f6:ab:3f:6e:a5:bd:c1:1a:9e:31:30:68:6e:50:af:54:4c:33:
+ f8:73:2f:41:60:4f:4c:85:1b:ad:7d:db:62:42:dc:87:96:b4:
+ cf:ce:12:50:ed:6c:01:5f:e2:f9:03:f5:f7:4c:6c:8f:2b:5b:
+ 7a:64:7d:19:e8:20:f2:e9:10:58:f3:71:0e:1e:58:68:f2:59:
+ 3c:06:53:7a:f3:60:62:5b:c7:b7:83:58:1d:3d:a6:17:db:33:
+ cc:91:14:af:d6:b9:08:bf:60:af:ac:3e:fe:8b:74:71:20:c7:
+ e7:31:5e:26:6c:28:52:67:12:1e:c3:9b:89:23:5d:88:ee:b0:
+ 6b:db:cc:94:8b:9b:1b:40:b7:66:bc:7d:1d:e1:08:00:20:ba:
+ 41:cd:17:d6:4c:7b:c4:5a:fd:cf:6b:20:e2:b8:86:9c:31:17:
+ c2:d7:7f:1c:3a:d0:fc:1d:f5:7f:c9:96:04:27:de:b8:ef:8d:
+ 38:9a:b3:56:60:ac:c2:07:38:64:19:39:9e:73:6f:ba:59:15:
+ ac:45:42:4d:bb:79:60:7f:ae:c3:8d:63:4a:27:16:0a:ca:92:
+ 7f:f7:a2:02:76:f5:e6:7c:ec:ba:ea:18:cd:9c:3b:ee:37:2c:
+ 9d:78:4e:c9:40:6d:94:cc:ce:ca:f4:33:fc:a4:dd:05:62:d6:
+ 0f:1e:19:63:af:10:c3:ff:02:1a:0a:48:fd:af:f2:a4:0e:64:
+ dd:90:f4:4f:14:1b:90:1f:9e:29:b0:0b:94:a4:d1:2a:87:b9:
+ 3a:76:c2:b6:af:c3:d4:84:6e:85:1c:64:73:46:d0:df:72:c0:
+ 3c:42:91:c4:30:10:11:18:36:bc:e5:17:36:22:5f:c2:3f:ac:
+ 1d:2e:9d:87:11:be:a7:ac:b2:62:35:74:b9:27:27:95:bc:c1:
+ 11:44:f8:64:36:60:74:06:a2:e7:e9:76:be:a7:86:5e:18:1e:
+ bd:dc:b0:aa:ae:92:d6:dd:d6:25:80:d6:c1:be:c1:21:1c:01:
+ 6f:83:20:ae:b7:54:4f:3d:2d:12:fc:a2:cc:49:fd:59
+-----BEGIN CERTIFICATE-----
+MIII/TCCBOWgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTYyMzI5MDRaFw0zNjAzMTEyMzI5MDRaMIGnMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEOMAwGA1UE
+CwwFVXNlcnMxKDAmBgNVBAMMH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5j
+b20xLjAsBgkqhkiG9w0BCQEWH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5j
+b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvh54ef8Cr2kcidNDf
+AfFnbKzEt9kYl+V6YnYztlLykpB1rKOUfgwpdcmDLxlmYIRF/9WpvcU6otglzxWK
+Iz4Jcy+ZHSQf5pZ+e8QejVVbwRhpzR20ItV72158kfKOwQMw7mNGWlTVQKx5VQBx
+B40+Du3/k2zxLYTBUaN8Sc//hXvAZMG6yGZ6/xcqdOoWah2XwCdXEL529ZpjVscl
+xvynXgCmGj0hvXr54wNgzt8WBvwFvNHIXecz7VKLYFtgxXATHcGzCBMJOwXoAkAS
+RYmvhx9qj2LOHhcTNIKBhum7hVt1HfQ6ArSmWCP+wzo1CZW793m845fmbXckqi1R
+UDdpAgMBAAGjggIRMIICDTAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0
+dHA6Ly93d3cuc2FtYmEuZXhhbXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxl
+LmNvbS1jcmwuY3JsMBEGCWCGSAGG+EIBAQQEAwIFoDALBgNVHQ8EBAMCBeAwTwYJ
+YIZIAYb4QgENBEIWQFNtYXJ0IENhcmQgTG9naW4gQ2VydGlmaWNhdGUgZm9yIGFk
+bWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5jb20wHQYDVR0OBBYEFEXaS40FnGJO
+YsPXXF/T2YW0m/IsMB8GA1UdIwQYMBaAFKI+Aiqjp005tAhNmcwMdTbqJ8M+MFsG
+A1UdEQRUMFKBH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5jb22gLwYKKwYB
+BAGCNxQCA6AhDB9hZG1pbmlzdHJhdG9yQHNhbWJhLmV4YW1wbGUuY29tMDEGA1Ud
+EgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0G
+CWCGSAGG+EIBBARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMv
+Q0Etc2FtYmEuZXhhbXBsZS5jb20tY3JsLmNybDAfBgNVHSUEGDAWBggrBgEFBQcD
+AgYKKwYBBAGCNxQCAjANBgkqhkiG9w0BAQsFAAOCBAEAorvml2c8tm5u3TSZFsaA
+kQi/kbpRYl12L+VTkT2ZAxiphGlzdmbD61bXxUCRFdresnZIfYqMgHk85toOpsNT
+1nTuXym3A0beiTIUIgMwaC5+BtSsnoLAAhZ/gbrueueL9/uZf4zreFSXTihE2vTi
+G/g+rMrM4+NxkJFHnHjtb7y3mBLqdeUV9yZWp1zWdKgTeyM1TmoB9qn1W5vQ6roP
+w8Qa4Lmj7V0oy38dPoqar0yIADwQ8EmFJGDmy9aeAEZ4TZAiaE8QOYQ74nw97SNB
+GX5vRVmJqZ8mwfl9TQq0EPkxfcyH0EtiFHCGyH0U/+Ro4t5CygHHqi1apXJk8Uz6
+bmAVIgho5sZqdWMktVR20ZdP4Oi869BihEq0Ogc4X7mmajEURzOBvdCkotorkg3c
+QsQPKA22GzO1iN8bqNiQmhHO39QU6ayUlJW7vG7xvoUpPxerQRTYILrgoqPT1Ise
+SzIijQ3B5jkazs3zHfGChdXngDSQpA7UrzLIeU4lMrYeBjomQjhHGjKWcVv+W7Dv
+ff5Yyuu1yUsvEsuJNiJ8pjmrIMEtzWs04c287UVFEkplS6tF8m16nfi1Ungb2i/g
+zvfisPpvQD3d6TnDY2ird1O+O92avNfX+mq/v3T3EYCH+dNF6x6O0amgLmbnIGcc
+TCJDd4X/GiM3zEneUe7yBC+omIgPthhT6+JJFV4Cix575sXRDN+ETtm9/iFI1KQR
+ASdXUdbBsqEcEZqn0avwmRayyD90JWgLGs9YDc3MGm2L7B9wggJAlw91LFOHwUJc
+0X4ZeCwsiHMzgWM4hAcPFrt8VFkDlOe4hdf4XlM1ZS7lJ2W+8Ill9qs/bqW9wRqe
+MTBoblCvVEwz+HMvQWBPTIUbrX3bYkLch5a0z84SUO1sAV/i+QP190xsjytbemR9
+Gegg8ukQWPNxDh5YaPJZPAZTevNgYlvHt4NYHT2mF9szzJEUr9a5CL9gr6w+/ot0
+cSDH5zFeJmwoUmcSHsObiSNdiO6wa9vMlIubG0C3Zrx9HeEIACC6Qc0X1kx7xFr9
+z2sg4riGnDEXwtd/HDrQ/B31f8mWBCfeuO+NOJqzVmCswgc4ZBk5nnNvulkVrEVC
+Tbt5YH+uw41jSicWCsqSf/eiAnb15nzsuuoYzZw77jcsnXhOyUBtlMzOyvQz/KTd
+BWLWDx4ZY68Qw/8CGgpI/a/ypA5k3ZD0TxQbkB+eKbALlKTRKoe5OnbCtq/D1IRu
+hRxkc0bQ33LAPEKRxDAQERg2vOUXNiJfwj+sHS6dhxG+p6yyYjV0uScnlbzBEUT4
+ZDZgdAai5+l2vqeGXhgevdywqq6S1t3WJYDWwb7BIRwBb4MgrrdUTz0tEvyizEn9
+WQ==
+-----END CERTIFICATE-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-S01-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-S01-key.pem
new file mode 100644
index 0000000..652e3bd
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-S01-key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI7Afo/WihRO4CAggA
+MBQGCCqGSIb3DQMHBAiyzMez8ikVKgSCBMikJkx4Qhm0cLRQXJfIPsHX0YQfinoJ
+qLGWMQ5KWTpwFZHoeqarmCVLJwReF75E8nD5tJdKt5J+lN0gBQMbppAzlSOJvMne
+1E5sDoBHY3jYUViF3p+ZZt4YoDxaGFYxcGL9M6Uo/Yb1791riMisQjgn7inpRe0i
+JuHngJH9Dblg0+vGM3JkMKdizWHSW4RyeYXa8d3rh62Y5RD7exUHKkz3pPucSsyy
+dnkhvbhdXSYzPxcUarrjx3pNMzWhamLWP3V6UwupCB8dygLm4QV+Fc3Jw7wR3Efj
+cewWjmXHuHzAGfDhr1r6yeWaAQCYezSp18UwMRv9AWgiTAayxDI+IroBigvU3PfA
+KE0RlWBnvoy2ggNEsCvk2QXYpQiIJMTS9u1oi2aOdvXaaVxuKBPJGgzAFGSnM44k
+gE1Pe+snVxzRuzHCNXnWoCxSa9xAvRt/dnQ9n1p2m3lwlt+kP0kO4ieMhT+SnBNh
+QY/WRfJ8E5ldYyfJ0y2eRd1hCu+42tj72rAuQkhPEUJzWuU6N1xzChXPwXVnhIh4
+HS4bpd9uL1wA5sNw2zfXdanagmSrXC5EFVdj4rJzHWzkalg0GTMhYd4QsbqI5d8O
+lO5ECnZUJwIcYa5Hy7OVDymRh3BxPMDGYqiO1+6QHUrqRm/XiSDUSaBfLat9ckHY
+0JT5nbBMg0TJ3VIhUbsZaQ4fwZNr9zgeS+yoFuLcPYPCHBz2fDNq6MFb0BqbHcYY
+qmf++nxF/jW21UKTryBeiLdkq1TjExOEXdmjSL4vwmUjyx+ycM4w8GvdU4xkdkQl
+1jNlx20WSocZ0hzreCMXglUb1q7tzZvaVJrSS9TX2PV38Fcz6jpmOeKtnkRBMUis
+Ge20QO7D8zCJM0jL+mNAnuZCA7zHc8aenbR6hK8i3Kd8G0XhWLNVWI5KfFtgrRaW
+UCM8mSdEIvWZfPrdvxo/kYEXBBA8i+3oO0nSUTyHpqmsIH3nYvaWnVmibnKMigO3
++3d+6Db5R117EbXDdRWm85jiN7PQ1SdNVxtKN4Wu188r/KfchXAeBQcBy9Kh1vVY
+qYTqP4Mp7dbm864iiZQZwTLJeq346+xUze5NY7nFHWl0ps7ujk+i9WA9I+M2TAj9
+Zmywy4Xvjwpj7PO5zA9O5TRxnnBbz7VrTcxBLK+6T/2yZZceJ29Bv7wy61eK9LNk
+AYy+MFXlY64L6HauTk9Ne/VnNnTvYYqrqPNy6CehQc0+LKvmYLCHUZabhWi7P1rj
+gUkkypfBH0j8k1lDnjnYu5bml32GK7eBix9C+5kNDadnvCEVDiYFT59SDyKCUHMZ
+19EKywqkWVPu5ez+60zSEJACpvIqDxlamusN3O9tQZD/t2c2lJiBeBPszXgj8Gin
+++tuCwkz/3KNy+u3SCZg9SUk5+XVZDOQOMh9EmUT5oqoPUTm9pblU2B8lRZaw/wl
+B97E4q4TUOtXZXHJdCkU8Sxr8/l8fOFYqIeiFx8PhSHaFgpEKgs89G9AefIb+l1u
+Z36bqMs0y4rIiSHR++0ZO5NJIi33zhPHvifmPzBTDXRn9cWdfqwetq1ts9ZD27oE
+4UhJyRU0gprmtpQWoVnd6ghiM1zk7lZmRQEDDXy4+puztzgZNLKJbSeXbufe49nX
+DcU=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-S01-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-S01-openssl.cnf
new file mode 100644
index 0000000..db72360
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at 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 at samba.example.com
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_default = administrator at 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 at 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 at 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 at samba.example.com/USER-administrator at samba.example.com-S01-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-S01-private-key.pem
new file mode 100644
index 0000000..cc8f150
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-S01-private-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAr4eeHn/Aq9pHInTQ3wHxZ2ysxLfZGJflemJ2M7ZS8pKQdayj
+lH4MKXXJgy8ZZmCERf/Vqb3FOqLYJc8ViiM+CXMvmR0kH+aWfnvEHo1VW8EYac0d
+tCLVe9tefJHyjsEDMO5jRlpU1UCseVUAcQeNPg7t/5Ns8S2EwVGjfEnP/4V7wGTB
+ushmev8XKnTqFmodl8AnVxC+dvWaY1bHJcb8p14Apho9Ib16+eMDYM7fFgb8BbzR
+yF3nM+1Si2BbYMVwEx3BswgTCTsF6AJAEkWJr4cfao9izh4XEzSCgYbpu4VbdR30
+OgK0plgj/sM6NQmVu/d5vOOX5m13JKotUVA3aQIDAQABAoIBAQCEj7E0a1rA7ooG
+VZ5grQD5ELOxpP7Jef2OXcnS6ADgvRtoI0cun7rjnNbgwbM3A/EhRELCfFT1IYKH
+m0szFcaGMH1j7wQXK3fAcgv83tP2BXBAhu3F2wDLFzLWdQpwEQgt7fr/aLzkiIE4
+6J76va9HjNLkzxvZUH0P2m3TMZNp7s2NLjxNQwivNXSgKXcT9fPX7IaBd063W41I
+iYQZ7M8Q3C1vk34uC9V1LxjFxOAe42G/ITkjt3CJbg0CjMXG3P3TKIXG94ufpFQO
+mkEzUSGxTCkwlqHKcxsa+7f72TocuhLuwpFBSeRmiIsa5ZHxJiC6XOkz2CAboNkI
+UMSVjoxZAoGBAOlOGjiF7ChheDLhtj3/VcxfyHkcNoUFAtKuoT/FD8JMQiEUTifr
+V7eA8pfAQubVVRNLmZEA40gsJsTPbCRQymwcYDFRATlTd6nZ1s53z99E/v/1QjIa
+ZpQXRD+Nt1xmID/MuX34qpIA6ZEE2zTFoMo1STeNf4eC9mESW9DkA05rAoGBAMCa
+wrvLa5whtXbhdoWfCMYKtSQuGTEKslb4Ec97sKIdZXloGnH0eyiwnynCDhX2wPJt
+gnQtVxNXb9+MFxh+6bnX5rMyB+myXszpPNBCbLO0FU3+vfIEmOoULqU1Xn7Eu97m
+LGoR6G9cN7p8RuX7zp5ROKGfDg77oW8XhVah2x57AoGAY1BmBQ2tW/sx6ab/pyCc
+a2WSt0t1QebCLuE7ryO586H2vJIiOwgJzQnNOyAS2qSRlKcn9fwExGJXFoydok/p
++1+Q6y1qcfbAB8O9lyKVkJuUWW0UArQOWpgU62DuXxzyOXZyt9c09PYCd0Mz9SDz
+s2A/jLBlS1BKhUQFZcTKS4UCgYBaT7cD66x3t26pYar7mMi6ZAbwAhWZ41QgZ42i
+ZnM6cOJF/UR5LpQZTkgzgmSsc9mhUywaYbA0x4kTn1KtD8V0eQIaAFmpgRPmrW7w
+kFT8JnLe8ZYLR5CUIgaFPPMkKgeVywQEcIU2wlz3OpLcACiwH5GYZ0ZmTCM0Pikt
+qBNgxQKBgEVgpIHZi2xdfvwtCrEfomnlImj94HySKIFenCRoc/d34+KO4jKho1zN
+dqbSDqz/lB/7GWFjRszTMZMVJkl8TbE050UEe8EDPt93BSeGHNCUXUesZQVddGhn
+iH8OLIkoW3xIlNgflwi4+7gLjWrAHHPwEG3Iys83DVCA5D/4C02m
+-----END RSA PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-S01-req.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-S01-req.pem
new file mode 100644
index 0000000..72cd979
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-S01-req.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIDATCCAekCAQAwgbsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTYW1iYVN0YXRl
+MRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNhbWJhU2VsZlRlc3Rpbmcx
+DjAMBgNVBAsMBVVzZXJzMSgwJgYDVQQDDB9hZG1pbmlzdHJhdG9yQHNhbWJhLmV4
+YW1wbGUuY29tMS4wLAYJKoZIhvcNAQkBFh9hZG1pbmlzdHJhdG9yQHNhbWJhLmV4
+YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr4eeHn/A
+q9pHInTQ3wHxZ2ysxLfZGJflemJ2M7ZS8pKQdayjlH4MKXXJgy8ZZmCERf/Vqb3F
+OqLYJc8ViiM+CXMvmR0kH+aWfnvEHo1VW8EYac0dtCLVe9tefJHyjsEDMO5jRlpU
+1UCseVUAcQeNPg7t/5Ns8S2EwVGjfEnP/4V7wGTBushmev8XKnTqFmodl8AnVxC+
+dvWaY1bHJcb8p14Apho9Ib16+eMDYM7fFgb8BbzRyF3nM+1Si2BbYMVwEx3BswgT
+CTsF6AJAEkWJr4cfao9izh4XEzSCgYbpu4VbdR30OgK0plgj/sM6NQmVu/d5vOOX
+5m13JKotUVA3aQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAGrgBV0TkeQ3fHEJ
+vTabQG/aKSgzkkzaiBdY5GBX3FGtmKl0E9DNImc3bcw4QBC8GDObGoqct31QpHnT
+H51MN/Vix3YAUsKbGtvopGygn22sLtm21Iy1lOS2QsEikPxrDedmKjGzsyi8fWFF
+fWOEW1+mhS7L6oiNDm18MbAaYN6wdgkPVW0Uc+P/ftRZ1y2T2mli+99IgNQQW9Rb
+7ZrHBTyCq9IK73UniVCA3yEN2ibHxaZQsvl3DpUfkKdPV1FOsvj33nTMtcubY7/P
+c4n3w2M0HVSu6Ch+cJj0dy3FzYU76eInzT6B+hs2lGCIm6H4pUH8Vjx9dNMjcC4d
+vctx/Mw=
+-----END CERTIFICATE REQUEST-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-cert.pem
new file mode 120000
index 0000000..3b134b6
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-cert.pem
@@ -0,0 +1 @@
+USER-administrator at samba.example.com-S01-cert.pem
\ No newline at end of file
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-private-key.pem
new file mode 120000
index 0000000..964892e
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator at samba.example.com/USER-administrator at samba.example.com-private-key.pem
@@ -0,0 +1 @@
+USER-administrator at 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 0000000..65c9b95
--- /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 at 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 0000000..187ea4b
--- /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 at samba.example.com
+# DONE #
+# DONE # ./manage-ca.sh manage-CA-samba.example.com.cnf create_dc addc.addom.samba.example.com 0123456789ABCDEF
+# DONE # ./manage-ca.sh manage-CA-samba.example.com.cnf create_user administrator at addom.samba.example.com
diff --git a/selftest/manage-ca/manage-ca.sh b/selftest/manage-ca/manage-ca.sh
new file mode 100755
index 0000000..ab796b7
--- /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 0000000..1f3d24e
--- /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 0000000..ca8415b
--- /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 0000000..4c6bb4a
--- /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 0000000..0b0424d
--- /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 0000000..71674b9
--- /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 db70246..ff5f27d 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;
@@ -524,6 +525,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";
@@ -555,6 +592,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 f1c4055..6ca1036 100644
--- a/selftest/target/Samba.pm
+++ b/selftest/target/Samba.pm
@@ -71,6 +71,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) = @_;
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 6f7407a..8ff1e7c 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -213,6 +213,7 @@ sub setup_nt4_dc($$)
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 fbefda7..be6c47c 100755
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -272,219 +272,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 at 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 at 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 at 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 setup_namespaces($$:$$)
{
my ($self, $localenv, $upn_array, $spn_array) = @_;
@@ -727,6 +514,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}
@@ -745,6 +537,8 @@ sub provision_raw_step1($$)
winbind separator = /
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}
@@ -752,6 +546,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
@@ -782,8 +577,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};
@@ -1543,7 +1336,9 @@ sub provision_ad_dc_ntvfs($$)
print "PROVISIONING AD DC (NTVFS)...";
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",
@@ -1661,6 +1456,7 @@ sub provision_fl2008r2dc($$$)
my ($self, $prefix, $dcvars) = @_;
print "PROVISIONING DC WITH FOREST LEVEL 2008r2...";
+ my $extra_conf_options = "ldap server require strong auth = no";
my $ret = $self->provision($prefix,
"domain controller",
"dc7",
@@ -1670,7 +1466,7 @@ sub provision_fl2008r2dc($$$)
"locDCpass7",
undef,
undef,
- "",
+ $extra_conf_options,
"",
undef);
@@ -1879,7 +1675,7 @@ sub provision_ad_dc($$)
"domain controller",
"addc",
"ADDOMAIN",
- "addc.samba.example.com",
+ "addom.samba.example.com",
"2008",
"locDCpass1",
undef,
diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c
index 0dc6657..1a8cd91 100644
--- a/source3/auth/auth_domain.c
+++ b/source3/auth/auth_domain.c
@@ -89,7 +89,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 e68c702..8ea05c6 100644
--- a/source3/auth/auth_samba4.c
+++ b/source3/auth/auth_samba4.c
@@ -252,8 +252,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 b079d04..c23de7e 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/auth_generic.h b/source3/include/auth_generic.h
index 07df62a..0911182 100644
--- a/source3/include/auth_generic.h
+++ b/source3/include/auth_generic.h
@@ -42,11 +42,12 @@ NTSTATUS auth_generic_set_creds(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 e18aaf4..0bd0c80 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -693,13 +693,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
@@ -709,18 +702,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_t 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_t 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 */
@@ -862,31 +843,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,
@@ -947,7 +903,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 0e05af8..37632af 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/libads/ads_proto.h b/source3/libads/ads_proto.h
index eb0dea9..425c352 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,
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index 6735072..f1e7d21 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -553,140 +553,6 @@ static NTSTATUS ads_find_dc(ADS_STRUCT *ads)
c_realm, c_domain, nt_errstr(status)));
return status;
}
-
-/*********************************************************************
- *********************************************************************/
-
-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;
-
- if (!realm)
- realm = lp_realm();
-
- if ((sitename = sitename_fetch(frame, realm)) == NULL) {
- ads_lookup_site();
- sitename = sitename_fetch(frame, realm);
- }
-
- 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,
- 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
diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c
index 720ee78..4fcd733 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_t *buf, uint32_t 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_t *buf, uint32_t
}
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_t *buf, uint32_t
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,98 +194,119 @@ 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) {
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);
@@ -256,7 +314,7 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
ads->ldap.out.sig_size = max_wrapped - ads->ldap.out.max_unwrapped;
ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
ads->ldap.in.max_wrapped = max_wrapped;
- status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, auth_generic_state->gensec_security);
+ 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)));
@@ -437,292 +495,22 @@ 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_t 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_t req_flags, ret_flags;
- uint32_t 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_t 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
@@ -734,9 +522,10 @@ static void ads_free_service_principal(struct ads_service_principal *p)
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;
@@ -816,13 +605,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:
@@ -831,7 +633,6 @@ out:
}
static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
- const char *given_principal,
struct ads_service_principal *p)
{
ADS_STATUS status;
@@ -846,27 +647,12 @@ static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
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
@@ -883,63 +669,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 */
/*
@@ -947,6 +676,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;
@@ -961,7 +692,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);
@@ -976,11 +707,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++) {
@@ -993,59 +723,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;
}
@@ -1267,7 +998,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/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 235592c..ef6c995 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -962,7 +962,7 @@ static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
domain,
pass,
flags,
- SMB_SIGNING_DEFAULT);
+ SMB_SIGNING_IPC_DEFAULT);
}
/****************************************************************
@@ -1517,7 +1517,7 @@ NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
machine_domain,
machine_password,
flags,
- SMB_SIGNING_DEFAULT);
+ SMB_SIGNING_IPC_DEFAULT);
if (!NT_STATUS_IS_OK(status)) {
status = cli_full_connection(&cli, NULL,
@@ -1528,7 +1528,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 9c4cce2..ffdfde1 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -45,6 +45,7 @@ struct gse_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;
@@ -136,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));
@@ -201,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) {
@@ -255,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);
@@ -579,6 +606,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;
}
@@ -879,18 +909,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;
}
@@ -1046,6 +1073,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)
{
@@ -1085,6 +1146,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 e7d66b7..1838012 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 1193baa..aab43a1 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 68d1451..59560d6 100644
--- a/source3/libsmb/auth_generic.c
+++ b/source3/libsmb/auth_generic.c
@@ -86,7 +86,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;
@@ -100,7 +100,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);
@@ -151,6 +152,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)
@@ -175,3 +199,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 530f5c3..2c351dd 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"
@@ -1264,386 +1267,407 @@ 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) {
- NTSTATUS status;
-
- state->ads_status = ADS_ERROR_KRB5(rc);
- status = ads_ntstatus(state->ads_status);
- if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
- status = NT_STATUS_LOGON_FAILURE;
- state->ads_status = ADS_ERROR_NT(status);
+ 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);
+ }
+
+ 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;
}
- DEBUG(1, ("cli_session_setup_kerberos: "
- "spnego_gen_krb5_negTokenInit failed: %s - %s\n",
- error_message(rc), nt_errstr(status)));
- tevent_req_nterror(req, status);
+ }
+
+ status = auth_generic_set_username(state->auth_generic, user);
+ 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
+ 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(cli->conn) >= PROTOCOL_SMB2_02) {
- state->cli->smb2.session = smbXcli_session_create(cli,
- cli->conn);
- if (tevent_req_nomem(state->cli->smb2.session, req)) {
+ 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);
}
- }
- subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
+ 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);
+ }
+
+ 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_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;
+ cli_credentials_set_kerberos_state(state->auth_generic->credentials,
+ krb5_state);
- 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;
+ if (krb5_state == CRED_DONT_USE_KERBEROS) {
+ use_spnego_principal = false;
}
- 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 (target_service != NULL) {
+ status = gensec_set_target_service(
+ state->auth_generic->gensec_security,
+ target_service);
if (tevent_req_nterror(req, status)) {
- return;
+ 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 (target_hostname != NULL) {
+ status = gensec_set_target_hostname(
+ state->auth_generic->gensec_security,
+ target_hostname);
if (tevent_req_nterror(req, status)) {
- return;
+ 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;
+ 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;
}
- tevent_req_done(req);
-}
+ if (use_spnego_principal) {
+ const DATA_BLOB *b;
+ b = smbXcli_conn_server_gss_blob(cli->conn);
+ if (b != NULL) {
+ state->blob_in = *b;
+ }
+ }
-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;
+ state->is_anonymous = cli_credentials_is_anonymous(state->auth_generic->credentials);
- if (tevent_req_is_nterror(req, &status)) {
- ADS_STATUS ads = state->ads_status;
+ status = auth_generic_client_start(state->auth_generic,
+ GENSEC_OID_SPNEGO);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
- if (!ADS_ERR_OK(state->ads_status)) {
- ads = state->ads_status;
- } else {
- ads = ADS_ERROR_NT(status);
+ 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);
}
- tevent_req_received(req);
- return ads;
}
- tevent_req_received(req);
- return ADS_SUCCESS;
-}
-
-#endif /* HAVE_KRB5 */
-/****************************************************************************
- Do a spnego/NTLMSSP encrypted session setup.
-****************************************************************************/
+ cli_session_setup_gensec_local_next(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
-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;
-};
+ return req;
+}
-static int cli_session_setup_ntlmssp_state_destructor(
- struct cli_session_setup_ntlmssp_state *state)
+static void cli_session_setup_gensec_local_next(struct tevent_req *req)
{
- if (state->ntlmssp_state != NULL) {
- TALLOC_FREE(state->ntlmssp_state);
+ 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;
}
- return 0;
-}
-static void cli_session_setup_ntlmssp_done(struct tevent_req *req);
+ 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 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)
+static void cli_session_setup_gensec_local_done(struct tevent_req *subreq)
{
- struct tevent_req *req, *subreq;
- struct cli_session_setup_ntlmssp_state *state;
+ 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;
- DATA_BLOB blob_out;
- const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
- req = tevent_req_create(mem_ctx, &state,
- struct cli_session_setup_ntlmssp_state);
- if (req == NULL) {
- return NULL;
+ status = gensec_update_recv(subreq, state, &state->blob_out);
+ TALLOC_FREE(subreq);
+ 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;
}
- state->ev = ev;
- state->cli = cli;
- state->turn = 1;
- state->ntlmssp_state = NULL;
- talloc_set_destructor(
- state, cli_session_setup_ntlmssp_state_destructor);
-
- 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;
+ if (NT_STATUS_IS_OK(status)) {
+ state->local_ready = true;
}
- status = ntlmssp_update(state->ntlmssp_state, data_blob_null,
- &blob_out);
- if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- goto fail;
+
+ if (state->local_ready && state->remote_ready) {
+ cli_session_setup_gensec_ready(req);
+ return;
}
- state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
- data_blob_free(&blob_out);
+ cli_session_setup_gensec_remote_next(req);
+}
- 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);
- }
+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;
+
+ if (state->remote_ready) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
}
- subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
+ subreq = cli_sesssetup_blob_send(state, state->ev,
+ state->cli, state->blob_out);
if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
+ return;
}
- 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);
+ tevent_req_set_callback(subreq,
+ cli_session_setup_gensec_remote_done,
+ req);
}
-static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
+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_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 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);
+ 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 (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;
- }
- }
-
- if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
- struct smbXcli_session *session = state->cli->smb2.session;
+ state->remote_ready = true;
+ }
- 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;
- }
+ if (state->local_ready && state->remote_ready) {
+ cli_session_setup_gensec_ready(req);
+ return;
+ }
- 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;
+ cli_session_setup_gensec_local_next(req);
+}
- status = smb1cli_session_set_session_key(session,
- state->ntlmssp_state->session_key);
- if (tevent_req_nterror(req, status)) {
- return;
- }
+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 (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);
- return;
- }
- if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- tevent_req_nterror(req, status);
+ if (state->blob_in.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
- if (blob_in.length == 0) {
- tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ if (state->blob_out.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
- 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);
+ /*
+ * 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 = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out);
-
- 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);
+ status = gensec_session_key(state->auth_generic->gensec_security,
+ state, &state->session_key);
+ if (tevent_req_nterror(req, status)) {
return;
}
- state->blob_out = spnego_gen_auth(state, blob_out);
- if (tevent_req_nomem(state->blob_out.data, req)) {
- return;
- }
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ struct smbXcli_session *session = state->cli->smb2.session;
- subreq = cli_sesssetup_blob_send(state, state->ev, state->cli,
- state->blob_out);
- if (tevent_req_nomem(subreq, req)) {
- return;
+ 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_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
+
+ 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)) {
@@ -1723,6 +1747,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;
@@ -1739,14 +1764,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;
req = tevent_req_create(mem_ctx, &state,
@@ -1766,6 +1791,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",
@@ -1813,12 +1839,10 @@ 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, remote_name, dest_realm);
+ talloc_tos(), principal, state->target_hostname, dest_realm);
TALLOC_FREE(principal);
principal = tmp;
@@ -1840,8 +1864,11 @@ static struct tevent_req *cli_session_setup_spnego_send(
}
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);
}
@@ -1854,8 +1881,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);
}
@@ -1871,9 +1901,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) {
@@ -1881,9 +1913,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;
}
@@ -1900,7 +1934,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);
@@ -2014,10 +2048,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);
}
@@ -2077,10 +2109,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);
}
@@ -2089,6 +2119,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,
@@ -3111,6 +3152,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);
@@ -3140,6 +3183,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)) {
@@ -3165,8 +3216,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;
}
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index 6f28dfa..cfb3b16 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -170,6 +170,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();
}
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
index 82f13b7..4a0fbcd 100644
--- a/source3/libsmb/clispnego.c
+++ b/source3/libsmb/clispnego.c
@@ -26,81 +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;
-
- if (!asn1_extract_blob(data, ctx, &ret)) {
- goto err;
- }
-
- asn1_free(data);
- data = NULL;
-
- err:
-
- if (data != NULL) {
- if (asn1_has_error(data)) {
- DEBUG(1, ("Failed to build negTokenInit at offset %d\n",
- (int)asn1_current_ofs(data)));
- }
-
- asn1_free(data);
- }
-
- return ret;
-}
-
-/*
parse a negTokenInit packet giving a GUID, a list of supported
OIDs (the mechanisms) and a principal name string
*/
@@ -278,210 +203,3 @@ DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const ui
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_t 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 = !asn1_has_error(data);
-
- err:
-
- if (asn1_has_error(data)) {
- 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;
-
- if (!asn1_extract_blob(data, ctx, &ret)) {
- goto err;
- }
-
- 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_t 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;
- }
- } else if (negResult == SPNEGO_ACCEPT_INCOMPLETE) {
- asn1_set_error(data);
- 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 = !asn1_has_error(data);
-
- err:
-
- if (asn1_has_error(data)) {
- DEBUG(3, ("spnego_parse_auth_response failed at %d\n",
- (int)asn1_current_ofs(data)));
- asn1_free(data);
- data_blob_free(auth);
- return false;
- }
-
- asn1_free(data);
- return ret;
-}
diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c
deleted file mode 100644
index e661aeb..0000000
--- 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 46f68ae..0000000
--- 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 4676b72..49b9ad6 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/param/loadparm.c b/source3/param/loadparm.c
index 50b29e3..2ad1c6f 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -70,6 +70,7 @@
#include "dbwrap/dbwrap_rbt.h"
#include "../lib/util/bitmap.h"
#include "librpc/gen_ndr/nbt.h"
+#include "source4/lib/tls/tls.h"
#ifdef HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>
@@ -638,6 +639,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;
@@ -690,9 +693,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;
@@ -740,6 +746,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.*/
@@ -817,6 +826,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;
@@ -864,6 +874,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
Globals.dcerpc_endpoint_servers = str_list_make_v3_const(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");
@@ -4430,13 +4441,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_pipe.c b/source3/rpc_client/cli_pipe.c
index f642d30..97f4944 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -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;
}
@@ -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,
+ struct pipe_auth_data *auth,
uint32_t rpc_call_id,
- enum dcerpc_AuthType auth_type,
- enum dcerpc_AuthLevel auth_level,
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,8 +1799,7 @@ 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,
+ struct pipe_auth_data *auth,
uint32_t rpc_call_id,
const struct ndr_syntax_id *abstract,
const struct ndr_syntax_id *transfer,
@@ -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)) {
@@ -2193,8 +2335,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);
@@ -2295,6 +2438,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);
@@ -2355,6 +2499,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);
@@ -2425,6 +2570,7 @@ static NTSTATUS rpccli_generic_bind_data_from_creds(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_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index e0c1b85..176769f 100644
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -1585,6 +1585,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);
@@ -1611,6 +1612,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:
@@ -1719,6 +1728,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;
@@ -2468,22 +2485,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;
}
@@ -2570,22 +2581,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 4e2edc6..62b545c 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) {
diff --git a/source3/rpc_server/rpc_ncacn_np.c b/source3/rpc_server/rpc_ncacn_np.c
index d504847..5647596 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 e65209a..d44ee92 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 01a854c..5effe66 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 4b4b77a..2f6f020 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_pipe.c b/source3/rpc_server/srv_pipe.c
index 4ffaa0d..bcd7e5d 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;
@@ -575,7 +666,6 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
{
struct dcerpc_auth auth_info = {0};
uint16_t assoc_gid;
- unsigned int auth_type = DCERPC_AUTH_TYPE_NONE;
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;
@@ -940,15 +1063,49 @@ static bool api_pipe_alter_context(struct pipes_struct *p,
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 b4108d9..c32fbc7 100644
--- a/source3/rpcclient/rpcclient.c
+++ b/source3/rpcclient/rpcclient.c
@@ -1071,10 +1071,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 a6f20ed..2b5e435 100755
--- a/source3/script/tests/test_ntlm_auth_s3.sh
+++ b/source3/script/tests/test_ntlm_auth_s3.sh
@@ -276,6 +276,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 01af7f8..a41ae44 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 057414c..cc075b9 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 71b4e21..03345c6 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -136,6 +136,9 @@ for env in ["nt4_dc", "nt4_member", "ad_member"]:
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="nt4_dc"
+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 ["nt4_member", "ad_member"]:
plantestsuite("samba3.blackbox.net_cred_change.(%s:local)" % env, "%s:local" % env, [os.path.join(samba3srcdir, "script/tests/test_net_cred_change.sh"), configuration])
@@ -351,8 +354,8 @@ for t in tests:
plansmbtorture4testsuite(t, "ad_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD', 'over ncacn_np ')
plansmbtorture4testsuite(t, "ad_dc", 'ncacn_ip_tcp:$SERVER_IP -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ')
elif t == "rpc.samr.passwords.validate":
- plansmbtorture4testsuite(t, "nt4_dc", 'ncacn_ip_tcp:$SERVER_IP -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ')
- plansmbtorture4testsuite(t, "ad_dc", 'ncacn_ip_tcp:$SERVER_IP -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ')
+ plansmbtorture4testsuite(t, "nt4_dc", 'ncacn_ip_tcp:$SERVER_IP[seal] -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ')
+ plansmbtorture4testsuite(t, "ad_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, "nt4_dc", '//$SERVER_IP/durable -U$USERNAME%$PASSWORD')
plansmbtorture4testsuite(t, "ad_dc", '//$SERVER_IP/durable -U$USERNAME%$PASSWORD')
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
index 7590421..d2e5e2e 100644
--- a/source3/smbd/negprot.c
+++ b/source3/smbd/negprot.c
@@ -543,6 +543,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);
@@ -716,8 +717,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 fbc4013..b7fdd00 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -32,6 +32,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.
@@ -607,7 +608,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 e48d2b8..9c03b2c 100644
--- a/source3/smbd/smb2_negprot.c
+++ b/source3/smbd/smb2_negprot.c
@@ -25,6 +25,7 @@
#include "../libcli/smb/smb2_negotiate_context.h"
#include "../lib/tsocket/tsocket.h"
#include "../librpc/ndr/libndr.h"
+#include "../libcli/smb/smb_signing.h"
extern fstring remote_proto;
@@ -160,6 +161,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)) {
@@ -294,7 +296,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 a95f8a1..78bda7b 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -262,7 +262,8 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
}
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_flags = SMBXSRV_SIGNING_REQUIRED;
}
diff --git a/source3/torture/test_ntlm_auth.py b/source3/torture/test_ntlm_auth.py
index d17af9b..fffeb26 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 ace5b27..90af09e 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -1953,7 +1953,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 1de08c4..93caf04 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -7396,7 +7396,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 13a0ef1..de929ff 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 b90f927..27cb416 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,
@@ -226,13 +228,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;
}
@@ -255,6 +269,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)
@@ -958,57 +976,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();
- status = ntlmssp_set_domain(*client_ntlmssp_state, opt_domain);
+ /* These need to be in priority order, krb5 before NTLMSSP */
+#if defined(HAVE_KRB5)
+ backends[idx++] = &gensec_gse_krb5_security_ops;
+#endif
- 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_NTLMSSP);
+
+ 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;
}
@@ -1145,249 +1181,13 @@ static NTSTATUS ntlm_auth_prepare_gensec_server(TALLOC_CTX *mem_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,
@@ -1506,11 +1306,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);
@@ -1525,7 +1356,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);
@@ -1620,12 +1454,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;
}
@@ -1729,408 +1568,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 939da9b..039e653 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 f593d24..45e3fad 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -996,7 +996,7 @@ static NTSTATUS cm_prepare_connection(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) {
/*
@@ -1049,8 +1049,8 @@ static NTSTATUS cm_prepare_connection(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/wscript_build b/source3/wscript_build
index 7c9723a..3f6a43e 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -369,14 +369,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
@@ -404,7 +399,6 @@ bld.SAMBA3_LIBRARY('libsmb',
libsmb/smbsock_connect.c
libsmb/cli_smb2_fnum.c''',
deps='''
- LIBNTLMSSP
auth_generic
CLDAP
LIBNMB
@@ -1448,7 +1442,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/pygensec.c b/source4/auth/gensec/pygensec.c
index 3399869..eba84f0 100644
--- a/source4/auth/gensec/pygensec.c
+++ b/source4/auth/gensec/pygensec.c
@@ -530,6 +530,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" },
@@ -567,6 +644,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/ntlm/auth_util.c b/source4/auth/ntlm/auth_util.c
index 16977fa..3e5a0da 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/ldap_server/ldap_bind.c b/source4/ldap_server/ldap_bind.c
index 69a6b61..99ca148 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 3afbcdb..1f31627 100644
--- a/source4/ldap_server/ldap_server.c
+++ b/source4/ldap_server/ldap_server.c
@@ -335,6 +335,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;
diff --git a/source4/ldap_server/ldap_server.h b/source4/ldap_server/ldap_server.h
index 6f8b433..87a7163 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.h b/source4/lib/tls/tls.h
index 71e6cfb..91eeaae 100644
--- a/source4/lib/tls/tls.h
+++ b/source4/lib/tls/tls.h
@@ -61,10 +61,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,
diff --git a/source4/lib/tls/tls_tstream.c b/source4/lib/tls/tls_tstream.c
index 5c3e9f1..5045e88 100644
--- a/source4/lib/tls/tls_tstream.c
+++ b/source4/lib/tls/tls_tstream.c
@@ -20,13 +20,16 @@
#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 2048
@@ -34,8 +37,47 @@
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;
@@ -871,6 +916,8 @@ struct tstream_tls_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)
@@ -897,6 +944,8 @@ 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
@@ -914,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)));
@@ -931,6 +995,13 @@ 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 && file_exist(crl_file)) {
@@ -943,6 +1014,13 @@ 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);
@@ -997,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);
@@ -1362,6 +1447,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 8eab04a..f1808d7 100644
--- a/source4/lib/tls/tlscert.c
+++ b/source4/lib/tls/tlscert.c
@@ -30,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
@@ -77,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));
@@ -90,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)));
@@ -98,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
@@ -134,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 2083409..ecde360 100644
--- a/source4/lib/tls/wscript
+++ b/source4/lib/tls/wscript
@@ -53,6 +53,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',
diff --git a/source4/libcli/cliconnect.c b/source4/libcli/cliconnect.c
index 1715192..35d963e 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 0da49f3..c5d8219 100644
--- a/source4/libcli/ldap/ldap_bind.c
+++ b/source4/libcli/ldap/ldap_bind.c
@@ -32,6 +32,7 @@
#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[] = {
@@ -285,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));
@@ -299,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 (conn->sockets.active == conn->sockets.tls) {
+ if (wrap_flags == 0) {
cli_credentials_set_gensec_features(creds, old_gensec_features & ~(GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL));
}
@@ -318,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)) {
@@ -406,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
@@ -434,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;
}
}
@@ -466,6 +502,20 @@ try_logon_again:
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;
diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c
index 97a83ce..f362560 100644
--- a/source4/libcli/ldap/ldap_client.c
+++ b/source4/libcli/ldap/ldap_client.c
@@ -465,16 +465,15 @@ _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *con
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);
- if (!ca_file || !*ca_file) {
- composite_error(result,
- NT_STATUS_INVALID_PARAMETER_MIX);
- return result;
- }
+ 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);
diff --git a/source4/libcli/raw/libcliraw.h b/source4/libcli/raw/libcliraw.h
index 95e6943..8220cd7 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 9b0ed38..4b42c26 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 9535380..1a6ae34 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 d87d5ec..fffa768 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 e4964c1..9f989f2 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 33c3706..464ae95 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 {
@@ -743,12 +743,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;
@@ -768,6 +772,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);
@@ -775,8 +787,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,
@@ -832,13 +856,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) {
@@ -885,21 +909,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);
}
@@ -917,7 +938,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,
@@ -957,7 +978,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);
@@ -1225,7 +1246,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);
}
@@ -1298,6 +1319,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;
@@ -1331,14 +1353,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
@@ -1371,11 +1413,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;
}
@@ -1425,9 +1469,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;
}
@@ -1463,8 +1506,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);
}
@@ -1504,7 +1546,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;
@@ -1513,20 +1564,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,
@@ -1547,6 +1605,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 {
@@ -1571,6 +1636,8 @@ req_done:
}
}
+static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
+
/*
perform the send side of a async dcerpc request
*/
@@ -1581,6 +1648,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) {
@@ -1603,6 +1671,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);
talloc_set_destructor(req, dcerpc_req_dequeue);
@@ -1617,6 +1691,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
*/
@@ -1646,25 +1834,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) {
@@ -1684,8 +1856,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;
@@ -2121,7 +2292,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);
}
@@ -2194,6 +2365,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;
/*
@@ -2215,23 +2387,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);
@@ -2240,21 +2404,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 6385dd0..39d28a6 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 2d60d38..d617b07 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 9c5dbeb..8ed1257 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 61a22a7..6da2978 100644
--- a/source4/librpc/rpc/dcerpc_roh.c
+++ b/source4/librpc/rpc/dcerpc_roh.c
@@ -185,8 +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,
- lpcfg_tls_priority(lp_ctx),
+ 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 ff3e60e..e2e4a64 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -678,15 +678,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) {
@@ -776,6 +776,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/param/loadparm.c b/source4/param/loadparm.c
index af3313f..f53b2dd 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 5fb49b0..63b9ee9 100644
--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c
+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c
@@ -41,6 +41,14 @@
#include <gnutls/crypto.h>
#include <gnutls/abstract.h>
+#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,
@@ -1766,11 +1774,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/backupkey/dcesrv_backupkey_heimdal.c b/source4/rpc_server/backupkey/dcesrv_backupkey_heimdal.c
index 90cc4fb..ac12c64 100644
--- a/source4/rpc_server/backupkey/dcesrv_backupkey_heimdal.c
+++ b/source4/rpc_server/backupkey/dcesrv_backupkey_heimdal.c
@@ -48,6 +48,13 @@
#include <gcrypt.h>
#endif
+#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 const unsigned rsa_with_var_num[] = { 1, 2, 840, 113549, 1, 1, 1 };
/* Equivalent to asn1_oid_id_pkcs1_rsaEncryption*/
@@ -1803,11 +1810,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 59c289c..f8b8d5d 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 df0ffc8..8c69351 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);
if (uid_wrapper_enabled()) {
@@ -1375,6 +1786,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);
@@ -1438,6 +1854,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)
{
@@ -1453,7 +1870,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;
@@ -1464,7 +1881,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;
}
@@ -1484,6 +1901,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;
}
@@ -1511,8 +1942,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;
@@ -1728,7 +2202,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 */
@@ -1784,7 +2258,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 */
@@ -1818,7 +2292,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 */
@@ -1856,7 +2330,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 9a697ce..7e8b18a 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;
};
@@ -414,5 +455,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 374c2e0..2b3f8b0 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,
@@ -96,12 +125,12 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call)
}
}
- status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_info->auth_type,
- auth->auth_info->auth_level);
+ 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;
}
@@ -119,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;
@@ -132,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,
@@ -145,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))
@@ -163,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))
{
@@ -198,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,
@@ -224,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",
@@ -247,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;
}
@@ -282,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,
@@ -304,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;
}
@@ -326,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;
@@ -363,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);
@@ -403,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:
@@ -418,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);
}
@@ -441,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) {
@@ -472,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;
@@ -486,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;
}
@@ -525,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,
@@ -558,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 8c4eb63..4d3428d 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 a4b82e5..286da18 100644
--- a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
+++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
@@ -27,6 +27,14 @@
#include "librpc/gen_ndr/ndr_dnsserver.h"
#include "dnsserver.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 d331313..3fe6c13 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 4863c77..49c9e23 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 62627ce..6b934d7 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 be9f16c..820da49 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 c55f679..41311ed 100644
--- a/source4/rpc_server/lsa/dcesrv_lsa.c
+++ b/source4/rpc_server/lsa/dcesrv_lsa.c
@@ -35,6 +35,14 @@
#include "lib/messaging/irpc.h"
#include "libds/common/roles.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 9a8fdfb..f4da0b4 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);
}
@@ -946,7 +946,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;
@@ -959,8 +959,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 49b5b2f..7a92a6d 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -44,6 +44,14 @@
#include "librpc/gen_ndr/ndr_winbind_c.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 {
@@ -128,6 +136,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;
@@ -200,6 +210,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;
}
@@ -236,6 +250,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:
@@ -514,7 +536,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)
{
@@ -550,11 +572,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)) {
@@ -813,6 +835,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;
@@ -883,6 +907,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;
@@ -978,6 +1009,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);
@@ -1034,8 +1069,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 be4bd12..3eb0ad4 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 9f3bd10..423fcf0 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 1466dec..f053dad 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 3edfcbd..a2f2203 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(ad_dc_ntvfs)" % options, "ad_dc_ntvfs", "%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(ad_dc_ntvfs)" % options, "ad_dc_ntvfs", "%s/test_ldb.sh ldap $SERVER %s" % (bbdir, options))
# see if we support ADS on the Samba3 side
try:
@@ -71,6 +74,58 @@ if have_tls_support:
plantestsuite("samba4.ldb.ldaps with options %s(ad_dc_ntvfs)" % options, "ad_dc_ntvfs",
"%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(ad_dc_ntvfs:local)" % options, "ad_dc_ntvfs:local",
"%s/test_ldb.sh ldapi $PREFIX_ABS/ad_dc_ntvfs/private/ldapi %s" % (bbdir, options))
@@ -90,11 +145,11 @@ 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.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.drsuapi", "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"]
@@ -142,7 +197,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."):
@@ -496,6 +554,7 @@ planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.dcerpc.rpcecho")
planoldpythontestsuite("ad_dc_ntvfs:local", "samba.tests.dcerpc.registry", extra_args=['-U"$USERNAME%$PASSWORD"'])
planoldpythontestsuite("ad_dc_ntvfs", "samba.tests.dcerpc.dnsserver", extra_args=['-U"$USERNAME%$PASSWORD"'])
planoldpythontestsuite("ad_dc", "samba.tests.dcerpc.dnsserver", extra_args=['-U"$USERNAME%$PASSWORD"'])
+planoldpythontestsuite("ad_dc", "samba.tests.dcerpc.raw_protocol", extra_args=['-U"$USERNAME%$PASSWORD"'])
plantestsuite_loadlist("samba4.ldap.python(ad_dc_ntvfs)", "ad_dc_ntvfs", [python, os.path.join(samba4srcdir, "dsdb/tests/python/ldap.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
plantestsuite_loadlist("samba4.tokengroups.python(ad_dc_ntvfs)", "ad_dc_ntvfs:local", [python, os.path.join(samba4srcdir, "dsdb/tests/python/token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
plantestsuite("samba4.sam.python(ad_dc_ntvfs)", "ad_dc_ntvfs", [python, os.path.join(samba4srcdir, "dsdb/tests/python/sam.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
@@ -533,7 +592,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(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", ["PYTHON=%s" % python, os.path.join(samba4srcdir, "setup/tests/blackbox_spn.sh"), '$PREFIX/ad_dc_ntvfs'])
-plantestsuite_loadlist("samba4.ldap.bind(ad_dc_ntvfs)", "ad_dc_ntvfs", [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 cdfa2b4..dfcc1a2 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 4ebc0c4..e06853a 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 b48b170..addd278 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 d4b8de6..5e261a2 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 e8ae4b6..8f51253 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)) {
@@ -1526,6 +1527,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;
@@ -1535,18 +1537,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;
}
@@ -1556,7 +1567,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/ndr/ntlmssp.c b/source4/torture/ndr/ntlmssp.c
index 36127ce..aeac26f 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,10 +33,26 @@ 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;
}
-#if 0
static const uint8_t ntlmssp_CHALLENGE_MESSAGE_data[] = {
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x0a, 0x00, 0x38, 0x00, 0x00, 0x00, 0x95, 0x82, 0x89, 0xe2,
@@ -59,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;
}
@@ -106,18 +164,133 @@ 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;
}
-#endif
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 f40a4f1..dc460b9 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/backupkey.c b/source4/torture/rpc/backupkey.c
index aaff59f..ca981c2 100644
--- a/source4/torture/rpc/backupkey.c
+++ b/source4/torture/rpc/backupkey.c
@@ -1770,8 +1770,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;
@@ -1800,8 +1802,19 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
/* 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/backupkey_heimdal.c b/source4/torture/rpc/backupkey_heimdal.c
index 9c388c0..042cd23 100644
--- a/source4/torture/rpc/backupkey_heimdal.c
+++ b/source4/torture/rpc/backupkey_heimdal.c
@@ -1544,8 +1544,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;
@@ -1571,8 +1573,19 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
/* 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 ccb19ed..aae745f 100644
--- a/source4/torture/rpc/forest_trust.c
+++ b/source4/torture/rpc/forest_trust.c
@@ -516,7 +516,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;
@@ -547,7 +548,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);
@@ -559,11 +560,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/lsa.c b/source4/torture/rpc/lsa.c
index d2180db..2bc9649 100644
--- a/source4/torture/rpc/lsa.c
+++ b/source4/torture/rpc/lsa.c
@@ -4137,7 +4137,8 @@ static bool check_dom_trust_pw(struct dcerpc_pipe *p,
struct netr_Authenticator req_auth;
struct netr_Authenticator rep_auth;
struct netr_ServerPasswordSet2 s;
- struct dcerpc_pipe *p2;
+ struct dcerpc_pipe *p1 = NULL;
+ struct dcerpc_pipe *p2 = NULL;
NTSTATUS status;
bool ok;
int rc;
@@ -4237,18 +4238,25 @@ static bool check_dom_trust_pw(struct dcerpc_pipe *p,
status = dcerpc_parse_binding(tctx, binding, &b2);
torture_assert_ntstatus_ok(tctx, status, "Bad binding string");
- status = dcerpc_pipe_connect_b(tctx, &p2, b2,
+ status = dcerpc_pipe_connect_b(tctx, &p1, b2,
&ndr_table_netlogon,
cli_credentials_init_anon(tctx),
tctx->ev, tctx->lp_ctx);
torture_assert_ntstatus_ok(tctx, status, "dcerpc_pipe_connect_b");
- ok = check_pw_with_ServerAuthenticate3(p2, tctx,
+ ok = check_pw_with_ServerAuthenticate3(p1, tctx,
NETLOGON_NEG_AUTH2_ADS_FLAGS,
server_name,
incoming_creds, &creds);
torture_assert_int_equal(tctx, ok, expected_result,
"check_pw_with_ServerAuthenticate3");
+ if (expected_result == true) {
+ ok = test_SetupCredentialsPipe(p1, tctx, incoming_creds, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p2);
+ torture_assert_int_equal(tctx, ok, true,
+ "test_SetupCredentialsPipe");
+ }
+ TALLOC_FREE(p1);
if (trusted->trust_type != LSA_TRUST_TYPE_DOWNLEVEL) {
#ifdef SAMBA4_USES_HEIMDAL
diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c
index 9f8e8f1..c8e864d 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);
@@ -839,6 +882,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);
@@ -2507,7 +2551,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;
@@ -2515,12 +2559,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);
@@ -3343,7 +3393,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)
{
@@ -3356,14 +3406,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);
@@ -3413,7 +3469,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;
@@ -3436,14 +3492,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)) {
@@ -3868,7 +3930,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;
@@ -3882,6 +3944,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);
@@ -3889,6 +3952,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));
@@ -3962,7 +4029,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 f2f2a6f..a4ab8f0 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 196d9f8..e880f80 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,
@@ -151,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");
@@ -175,11 +176,16 @@ static bool test_PACVerify(struct torture_context *tctx,
credentials);
torture_assert(tctx, server_creds, "Failed to copy of credentials");
- if (!test_SetupCredentials2(p, tctx, negotiate_flags,
+ 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");
@@ -525,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;
@@ -584,6 +591,17 @@ static bool test_S2U4Self(struct torture_context *tctx,
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");
@@ -711,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(client_creds),
- cli_credentials_get_domain(client_creds));
+ 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(client_creds, tctx,
&flags,
chal,
+ NULL, /* server_timestamp */
names_blob,
&lm_resp, &nt_resp,
NULL, NULL);
@@ -744,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,
- server_creds, secure_channel_type,
- &creds)) {
- return false;
- }
-
ZERO_STRUCT(auth2);
netlogon_creds_client_authenticator(creds, &auth);
diff --git a/source4/torture/rpc/samba3rpc.c b/source4/torture/rpc/samba3rpc.c
index ade4a40..9e521cd 100644
--- a/source4/torture/rpc/samba3rpc.c
+++ b/source4/torture/rpc/samba3rpc.c
@@ -1189,10 +1189,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:"
@@ -1362,7 +1362,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;
@@ -1374,10 +1373,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);
@@ -1386,7 +1381,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));
@@ -1406,7 +1401,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(
@@ -1433,7 +1428,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;
@@ -1532,26 +1527,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");
@@ -1799,20 +1782,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");
}
@@ -1833,6 +1802,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");
}
@@ -1844,7 +1827,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)) {
@@ -1899,7 +1882,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 9000fe9..4465698 100644
--- a/source4/torture/rpc/samlogon.c
+++ b/source4/torture/rpc/samlogon.c
@@ -1755,7 +1755,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 293b672..dcdbb8a 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 a72dd31..829c969 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 = NULL;
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 {
@@ -842,6 +854,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 5ee2c2a..7fbf301 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/testprogs/blackbox/test_ldb_simple.sh b/testprogs/blackbox/test_ldb_simple.sh
new file mode 100755
index 0000000..7375cbf
--- /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/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5
index 4b3a69f..34f81b6 100644
--- a/wscript_configure_system_mitkrb5
+++ b/wscript_configure_system_mitkrb5
@@ -59,7 +59,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')
@@ -87,6 +88,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
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-samba/samba.git
More information about the Pkg-samba-maint
mailing list