summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2016-04-12 21:16:50 +0200
committerStefan Metzmacher <metze@samba.org>2016-04-12 21:16:50 +0200
commit47f3a1f221508598a1f43f723d1b654bebee4c57 (patch)
treee4b567488466eef023c80efce03d2f75cbaf6199
parent0dd174954988b1e4d6f59863088e95f5aa07eba6 (diff)
parentcdf4f21e282599fc2b00d8d4ff38d92b4af1fd0b (diff)
downloadsamba-47f3a1f221508598a1f43f723d1b654bebee4c57.tar.gz
Merge tag 'samba-4.2.11' into v4-2-test
samba: tag release samba-4.2.11 Signed-off-by: Stefan Metzmacher <metze@samba.org>
-rw-r--r--VERSION2
-rw-r--r--WHATSNEW.txt581
-rw-r--r--auth/credentials/credentials.c1
-rw-r--r--auth/credentials/credentials.h5
-rw-r--r--auth/credentials/credentials_krb5.c5
-rw-r--r--auth/credentials/credentials_ntlm.c12
-rw-r--r--auth/gensec/gensec.c113
-rw-r--r--auth/gensec/gensec.h25
-rw-r--r--auth/gensec/gensec_internal.h19
-rw-r--r--auth/gensec/gensec_start.c18
-rw-r--r--auth/gensec/gensec_util.c118
-rw-r--r--auth/gensec/schannel.c22
-rw-r--r--auth/gensec/spnego.c357
-rwxr-xr-xauth/gensec/wscript_build2
-rw-r--r--auth/kerberos/gssapi_helper.c395
-rw-r--r--auth/kerberos/gssapi_helper.h55
-rw-r--r--auth/kerberos/gssapi_pac.c16
-rwxr-xr-xauth/kerberos/wscript_build3
-rw-r--r--auth/ntlmssp/gensec_ntlmssp.c9
-rw-r--r--auth/ntlmssp/gensec_ntlmssp_server.c44
-rw-r--r--auth/ntlmssp/ntlmssp.c91
-rw-r--r--auth/ntlmssp/ntlmssp.h17
-rw-r--r--auth/ntlmssp/ntlmssp_client.c534
-rw-r--r--auth/ntlmssp/ntlmssp_ndr.c1
-rw-r--r--auth/ntlmssp/ntlmssp_private.h10
-rw-r--r--auth/ntlmssp/ntlmssp_server.c422
-rw-r--r--auth/ntlmssp/ntlmssp_sign.c103
-rw-r--r--auth/ntlmssp/ntlmssp_util.c176
-rw-r--r--auth/ntlmssp/wscript_build2
-rw-r--r--docs-xml/smbdotconf/ldap/ldapserverrequirestrongauth.xml26
-rw-r--r--docs-xml/smbdotconf/protocol/clientipcmaxprotocol.xml29
-rw-r--r--docs-xml/smbdotconf/protocol/clientipcminprotocol.xml29
-rw-r--r--docs-xml/smbdotconf/protocol/clientmaxprotocol.xml9
-rw-r--r--docs-xml/smbdotconf/protocol/clientminprotocol.xml6
-rw-r--r--docs-xml/smbdotconf/protocol/clientusespnego.xml5
-rw-r--r--docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml27
-rw-r--r--docs-xml/smbdotconf/security/clientipcsigning.xml26
-rw-r--r--docs-xml/smbdotconf/security/clientntlmv2auth.xml5
-rw-r--r--docs-xml/smbdotconf/security/clientsigning.xml13
-rw-r--r--docs-xml/smbdotconf/security/rawntlmv2auth.xml19
-rw-r--r--docs-xml/smbdotconf/security/serversigning.xml2
-rw-r--r--docs-xml/smbdotconf/security/tlspriority.xml22
-rw-r--r--docs-xml/smbdotconf/security/tlsverifypeer.xml47
-rw-r--r--lib/param/loadparm.c48
-rw-r--r--lib/param/loadparm.h6
-rw-r--r--lib/param/param_table.c91
-rw-r--r--lib/util/asn1.c109
-rw-r--r--lib/util/asn1.h25
-rw-r--r--lib/util/tests/asn1_tests.c6
-rw-r--r--lib/util/util.c2
-rw-r--r--lib/util/util_net.c247
-rw-r--r--lib/util/util_net.h1
-rw-r--r--libcli/auth/proto.h6
-rw-r--r--libcli/auth/smbencrypt.c170
-rw-r--r--libcli/auth/spnego.h8
-rw-r--r--libcli/auth/spnego_parse.c55
-rw-r--r--libcli/cldap/cldap.c12
-rw-r--r--libcli/ldap/ldap_message.c32
-rw-r--r--libcli/smb/smbXcli_base.c1
-rw-r--r--libcli/smb/smb_constants.h1
-rw-r--r--libcli/smb/smb_signing.c4
-rw-r--r--libcli/smb/tstream_smbXcli_np.c12
-rw-r--r--libcli/util/error.h1
-rw-r--r--librpc/idl/dcerpc.idl17
-rw-r--r--librpc/idl/epmapper.idl2
-rw-r--r--librpc/idl/ntlmssp.idl48
-rw-r--r--librpc/idl/security.idl18
-rw-r--r--librpc/ndr/ndr_basic.c39
-rw-r--r--librpc/ndr/ndr_ntlmssp.c16
-rw-r--r--librpc/ndr/ndr_ntlmssp.h2
-rw-r--r--librpc/rpc/binding.c2
-rw-r--r--librpc/rpc/dcerpc_error.c164
-rw-r--r--librpc/rpc/dcerpc_util.c204
-rw-r--r--librpc/rpc/rpc_common.h40
-rw-r--r--nsswitch/libwbclient/wbc_pam.c21
-rw-r--r--nsswitch/winbind_struct_protocol.h1
-rw-r--r--python/samba/tests/__init__.py685
-rw-r--r--python/samba/tests/dcerpc/bare.py13
-rw-r--r--python/samba/tests/dcerpc/dnsserver.py2
-rwxr-xr-xpython/samba/tests/dcerpc/raw_protocol.py2623
-rw-r--r--python/samba/tests/dcerpc/srvsvc.py6
-rw-r--r--python/samba/tests/dns.py12
-rw-r--r--python/samba/tests/docs.py3
-rw-r--r--python/samba/tests/ntacls.py7
-rwxr-xr-xpython/samba/tests/subunitrun.py4
-rw-r--r--python/samba/tests/xattr.py10
-rwxr-xr-xselftest/filter-subunit11
-rwxr-xr-xselftest/format-subunit10
-rw-r--r--selftest/knownfail30
-rw-r--r--selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-cert.pem190
-rw-r--r--selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-key.pem54
-rw-r--r--selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-openssl.cnf250
-rw-r--r--selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-private-key.pem51
-rw-r--r--selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-req.pem30
l---------selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-cert.pem1
l---------selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-private-key.pem1
-rw-r--r--selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-cert.pem191
-rw-r--r--selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-key.pem54
-rw-r--r--selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-openssl.cnf250
-rw-r--r--selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-private-key.pem51
-rw-r--r--selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-req.pem30
l---------selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-cert.pem1
l---------selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-private-key.pem1
-rw-r--r--selftest/manage-ca/CA-samba.example.com/NewCerts/00.pem190
-rw-r--r--selftest/manage-ca/CA-samba.example.com/NewCerts/01.pem169
-rw-r--r--selftest/manage-ca/CA-samba.example.com/NewCerts/02.pem191
-rw-r--r--selftest/manage-ca/CA-samba.example.com/NewCerts/03.pem170
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt1
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt.old1
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt4
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr1
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr.old1
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.old3
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-openssl.cnf203
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-private-key.pem102
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt1
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt.old1
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-cert.pem62
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-crl.pem32
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-cert.pem170
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-key.pem30
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-openssl.cnf242
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-private-key.pem27
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-req.pem19
l---------selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-cert.pem1
l---------selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-private-key.pem1
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-cert.pem169
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-key.pem30
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-openssl.cnf242
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-private-key.pem27
-rw-r--r--selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-req.pem19
l---------selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-cert.pem1
l---------selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-private-key.pem1
-rw-r--r--selftest/manage-ca/manage-CA-samba.example.com.cnf21
-rw-r--r--selftest/manage-ca/manage-CA-samba.example.com.sh18
-rwxr-xr-xselftest/manage-ca/manage-ca.sh387
-rw-r--r--selftest/manage-ca/manage-ca.templates.d/manage-CA-example.com.cnf17
-rw-r--r--selftest/manage-ca/manage-ca.templates.d/openssl-BASE-template.cnf201
-rw-r--r--selftest/manage-ca/manage-ca.templates.d/openssl-CA-template.cnf2
-rw-r--r--selftest/manage-ca/manage-ca.templates.d/openssl-DC-template.cnf49
-rw-r--r--selftest/manage-ca/manage-ca.templates.d/openssl-USER-template.cnf41
-rwxr-xr-xselftest/selftest.pl40
-rw-r--r--selftest/target/Samba.pm105
-rwxr-xr-xselftest/target/Samba3.pm1
-rwxr-xr-xselftest/target/Samba4.pm233
-rw-r--r--selftest/tests/__init__.py2
-rw-r--r--selftest/tests/test_run.py2
-rw-r--r--selftest/tests/test_samba.py2
-rw-r--r--selftest/tests/test_socket_wrapper.py2
-rw-r--r--selftest/tests/test_target.py2
-rw-r--r--selftest/tests/test_testlist.py2
-rw-r--r--source3/auth/auth_domain.c2
-rw-r--r--source3/auth/auth_samba4.c4
-rw-r--r--source3/auth/auth_util.c15
-rw-r--r--source3/include/ads.h30
-rw-r--r--source3/include/auth_generic.h7
-rw-r--r--source3/include/proto.h48
-rw-r--r--source3/lib/netapi/cm.c2
-rw-r--r--source3/lib/tldap.c6
-rw-r--r--source3/libads/ads_ldap_protos.h6
-rw-r--r--source3/libads/ads_proto.h11
-rw-r--r--source3/libads/ads_status.c6
-rw-r--r--source3/libads/ads_status.h2
-rw-r--r--source3/libads/disp_sec.c4
-rw-r--r--source3/libads/ldap.c163
-rw-r--r--source3/libads/ldap_printer.c4
-rw-r--r--source3/libads/ldap_utils.c10
-rw-r--r--source3/libads/sasl.c706
-rw-r--r--source3/libads/sasl_wrapping.c2
-rw-r--r--source3/libnet/libnet_join.c6
-rw-r--r--source3/librpc/crypto/gse.c394
-rw-r--r--source3/librpc/rpc/dcerpc.h10
-rw-r--r--source3/librpc/rpc/dcerpc_helpers.c98
-rw-r--r--source3/libsmb/auth_generic.c51
-rw-r--r--source3/libsmb/cliconnect.c674
-rw-r--r--source3/libsmb/clidgram.c2
-rw-r--r--source3/libsmb/clientgen.c11
-rw-r--r--source3/libsmb/clierror.c6
-rw-r--r--source3/libsmb/clifsinfo.c22
-rw-r--r--source3/libsmb/clilist.c6
-rw-r--r--source3/libsmb/clirap.c26
-rw-r--r--source3/libsmb/clirap.h48
-rw-r--r--source3/libsmb/clirap2.c30
-rw-r--r--source3/libsmb/clisecdesc.c4
-rw-r--r--source3/libsmb/clispnego.c283
-rw-r--r--source3/libsmb/libsmb_dir.c18
-rw-r--r--source3/libsmb/libsmb_file.c6
-rw-r--r--source3/libsmb/libsmb_misc.c4
-rw-r--r--source3/libsmb/libsmb_server.c2
-rw-r--r--source3/libsmb/libsmb_stat.c10
-rw-r--r--source3/libsmb/libsmb_xattr.c14
-rw-r--r--source3/libsmb/namequery.c4
-rw-r--r--source3/libsmb/nmblib.c2
-rw-r--r--source3/libsmb/ntlmssp.c765
-rw-r--r--source3/libsmb/ntlmssp_wrap.c135
-rw-r--r--source3/libsmb/passchange.c7
-rw-r--r--source3/libsmb/proto.h26
-rw-r--r--source3/libsmb/samlogon_cache.c2
-rw-r--r--source3/libsmb/smb_share_modes.c18
-rw-r--r--source3/libsmb/smbsock_connect.c2
-rw-r--r--source3/pam_smbpass/wscript_build2
-rw-r--r--source3/param/loadparm.c44
-rw-r--r--source3/rpc_client/cli_lsarpc.c4
-rw-r--r--source3/rpc_client/cli_lsarpc.h4
-rw-r--r--source3/rpc_client/cli_netlogon.c4
-rw-r--r--source3/rpc_client/cli_netlogon.h2
-rw-r--r--source3/rpc_client/cli_pipe.c327
-rw-r--r--source3/rpc_client/rpc_client.h4
-rw-r--r--source3/rpc_server/netlogon/srv_netlog_nt.c57
-rw-r--r--source3/rpc_server/rpc_handles.c7
-rw-r--r--source3/rpc_server/rpc_ncacn_np.c3
-rw-r--r--source3/rpc_server/rpc_pipes.h11
-rw-r--r--source3/rpc_server/rpc_server.c12
-rw-r--r--source3/rpc_server/samr/srv_samr_nt.c21
-rw-r--r--source3/rpc_server/srv_access_check.c6
-rw-r--r--source3/rpc_server/srv_access_check.h4
-rw-r--r--source3/rpc_server/srv_pipe.c502
-rw-r--r--source3/rpcclient/rpcclient.c5
-rwxr-xr-xsource3/script/tests/test_ntlm_auth_s3.sh2
-rwxr-xr-xsource3/script/tests/test_rpcclient_samlogon.sh11
-rwxr-xr-xsource3/script/tests/test_smbclient_auth.sh11
-rwxr-xr-xsource3/selftest/tests.py7
-rw-r--r--source3/smbd/negprot.c6
-rw-r--r--source3/smbd/sesssetup.c4
-rw-r--r--source3/smbd/smb2_negprot.c10
-rw-r--r--source3/smbd/smb2_sesssetup.c3
-rwxr-xr-xsource3/torture/test_ntlm_auth.py553
-rw-r--r--source3/utils/net_ads.c2
-rw-r--r--source3/utils/net_rpc.c2
-rw-r--r--source3/utils/net_util.c2
-rw-r--r--source3/utils/ntlm_auth.c819
-rw-r--r--source3/winbindd/winbindd_ccache_access.c44
-rw-r--r--source3/winbindd/winbindd_cm.c6
-rw-r--r--source3/winbindd/winbindd_dual_srv.c2
-rwxr-xr-xsource3/wscript_build10
-rw-r--r--source4/auth/gensec/cyrus_sasl.c452
-rw-r--r--source4/auth/gensec/gensec_gssapi.c322
-rw-r--r--source4/auth/gensec/gensec_gssapi.h1
-rw-r--r--source4/auth/gensec/gensec_krb5.c12
-rw-r--r--source4/auth/gensec/gensec_socket.h28
-rw-r--r--source4/auth/gensec/pygensec.c83
-rw-r--r--source4/auth/gensec/socket.c435
-rwxr-xr-xsource4/auth/gensec/wscript_build14
-rw-r--r--source4/auth/ntlm/auth_util.c4
-rw-r--r--source4/auth/wscript_configure4
-rwxr-xr-xsource4/dsdb/tests/python/dsdb_schema_info.py3
-rw-r--r--source4/heimdal/lib/gssapi/krb5/aeap.c98
-rw-r--r--source4/heimdal/lib/gssapi/krb5/arcfour.c645
-rw-r--r--source4/heimdal/lib/gssapi/krb5/decapsulate.c3
-rwxr-xr-xsource4/heimdal_build/wscript_configure1
-rw-r--r--source4/ldap_server/ldap_bind.c50
-rw-r--r--source4/ldap_server/ldap_server.c7
-rw-r--r--source4/ldap_server/ldap_server.h2
-rw-r--r--source4/lib/tls/tls.c2
-rw-r--r--source4/lib/tls/tls.h32
-rw-r--r--source4/lib/tls/tls_tstream.c288
-rw-r--r--source4/lib/tls/tlscert.c19
-rw-r--r--source4/lib/tls/wscript6
-rw-r--r--source4/libcli/cliconnect.c2
-rw-r--r--source4/libcli/ldap/ldap_bind.c125
-rw-r--r--source4/libcli/ldap/ldap_client.c443
-rw-r--r--source4/libcli/ldap/ldap_client.h17
-rw-r--r--source4/libcli/ldap/ldap_controls.c48
-rw-r--r--source4/libcli/ldap/wscript_build4
-rw-r--r--source4/libcli/raw/libcliraw.h1
-rw-r--r--source4/libcli/raw/rawnegotiate.c11
-rw-r--r--source4/libcli/smb2/connect.c7
-rw-r--r--source4/libcli/smb_composite/connect.c1
-rw-r--r--source4/libcli/smb_composite/sesssetup.c35
-rw-r--r--source4/librpc/rpc/dcerpc.c351
-rw-r--r--source4/librpc/rpc/dcerpc.h14
-rw-r--r--source4/librpc/rpc/dcerpc_auth.c93
-rw-r--r--source4/librpc/rpc/dcerpc_connect.c22
-rw-r--r--source4/librpc/rpc/dcerpc_roh.c13
-rw-r--r--source4/librpc/rpc/dcerpc_util.c22
-rw-r--r--source4/librpc/rpc/pyrpc.c80
-rw-r--r--source4/param/loadparm.c3
-rw-r--r--source4/rpc_server/backupkey/dcesrv_backupkey.c13
-rw-r--r--source4/rpc_server/common/reply.c49
-rw-r--r--source4/rpc_server/dcerpc_server.c812
-rw-r--r--source4/rpc_server/dcerpc_server.h57
-rw-r--r--source4/rpc_server/dcesrv_auth.c275
-rw-r--r--source4/rpc_server/dcesrv_mgmt.c8
-rw-r--r--source4/rpc_server/dnsserver/dcerpc_dnsserver.c8
-rw-r--r--source4/rpc_server/drsuapi/dcesrv_drsuapi.c8
-rw-r--r--source4/rpc_server/echo/rpc_echo.c7
-rw-r--r--source4/rpc_server/epmapper/rpc_epmapper.c8
-rw-r--r--source4/rpc_server/handles.c8
-rw-r--r--source4/rpc_server/lsa/dcesrv_lsa.c8
-rw-r--r--source4/rpc_server/lsa/lsa_lookup.c12
-rw-r--r--source4/rpc_server/netlogon/dcerpc_netlogon.c46
-rw-r--r--source4/rpc_server/remote/dcesrv_remote.c8
-rw-r--r--source4/rpc_server/samr/dcesrv_samr.c12
-rw-r--r--source4/rpc_server/samr/samr_password.c25
-rwxr-xr-xsource4/selftest/tests.py77
-rw-r--r--source4/smb_server/smb/negprot.c6
-rw-r--r--source4/smb_server/smb/sesssetup.c10
-rw-r--r--source4/smb_server/smb2/negprot.c7
-rw-r--r--source4/smb_server/smb2/sesssetup.c8
-rw-r--r--source4/torture/basic/base.c20
-rw-r--r--source4/torture/drs/python/drs_base.py6
-rw-r--r--source4/torture/ndr/ntlmssp.c181
-rw-r--r--source4/torture/raw/samba3misc.c7
-rw-r--r--source4/torture/rpc/alter_context.c2
-rw-r--r--source4/torture/rpc/backupkey.c21
-rw-r--r--source4/torture/rpc/forest_trust.c12
-rw-r--r--source4/torture/rpc/netlogon.c101
-rw-r--r--source4/torture/rpc/netlogon.h7
-rw-r--r--source4/torture/rpc/remote_pac.c121
-rw-r--r--source4/torture/rpc/samba3rpc.c75
-rw-r--r--source4/torture/rpc/samlogon.c3
-rw-r--r--source4/torture/rpc/samr.c4
-rw-r--r--source4/torture/rpc/schannel.c29
-rw-r--r--source4/torture/rpc/testjoin.c35
-rw-r--r--source4/winbind/wb_pam_auth.c4
-rw-r--r--source4/winbind/wb_samba3_cmd.c9
-rwxr-xr-xtestprogs/blackbox/test_ldb.sh3
-rwxr-xr-xtestprogs/blackbox/test_ldb_simple.sh41
-rw-r--r--testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.idl64
-rw-r--r--testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.out43
-rw-r--r--wscript_configure_system_mitkrb54
321 files changed, 17822 insertions, 7115 deletions
diff --git a/VERSION b/VERSION
index 2492fbdb891..6c442479486 100644
--- a/VERSION
+++ b/VERSION
@@ -25,7 +25,7 @@
########################################################
SAMBA_VERSION_MAJOR=4
SAMBA_VERSION_MINOR=2
-SAMBA_VERSION_RELEASE=10
+SAMBA_VERSION_RELEASE=11
########################################################
# If a official release has a serious bug #
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index f03be3afc4b..ecb5fe6e2c3 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,3 +1,580 @@
+ ==============================
+ Release Notes for Samba 4.2.11
+ April 12, 2016
+ ==============================
+
+This is a security release containing one additional
+regression fix for the security release 4.2.10.
+
+This fixes a regression that prevents things like 'net ads join'
+from working against a Windows 2003 domain.
+
+Changes since 4.2.10:
+=====================
+
+o Stefan Metzmacher <metze@samba.org>
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016
+
+Release notes for the original 4.2.10 release follows:
+------------------------------------------------------
+
+ ==============================
+ Release Notes for Samba 4.2.10
+ April 12, 2016
+ ==============================
+
+
+This is a security release in order to address the following CVEs:
+
+o CVE-2015-5370 (Multiple errors in DCE-RPC code)
+
+o CVE-2016-2110 (Man in the middle attacks possible with NTLMSSP)
+
+o CVE-2016-2111 (NETLOGON Spoofing Vulnerability)
+
+o CVE-2016-2112 (LDAP client and server don't enforce integrity)
+
+o CVE-2016-2113 (Missing TLS certificate validation)
+
+o CVE-2016-2114 ("server signing = mandatory" not enforced)
+
+o CVE-2016-2115 (SMB IPC traffic is not integrity protected)
+
+o CVE-2016-2118 (SAMR and LSA man in the middle attacks possible)
+
+The number of changes are rather huge for a security release,
+compared to typical security releases.
+
+Given the number of problems and the fact that they are all related
+to man in the middle attacks we decided to fix them all at once
+instead of splitting them.
+
+In order to prevent the man in the middle attacks it was required
+to change the (default) behavior for some protocols. Please see the
+"New smb.conf options" and "Behavior changes" sections below.
+
+=======
+Details
+=======
+
+o CVE-2015-5370
+
+ Versions of Samba from 3.6.0 to 4.4.0 inclusive are vulnerable to
+ denial of service attacks (crashes and high cpu consumption)
+ in the DCE-RPC client and server implementations. In addition,
+ errors in validation of the DCE-RPC packets can lead to a downgrade
+ of a secure connection to an insecure one.
+
+ While we think it is unlikely, there's a nonzero chance for
+ a remote code execution attack against the client components,
+ which are used by smbd, winbindd and tools like net, rpcclient and
+ others. This may gain root access to the attacker.
+
+ The above applies all possible server roles Samba can operate in.
+
+ Note that versions before 3.6.0 had completely different marshalling
+ functions for the generic DCE-RPC layer. It's quite possible that
+ that code has similar problems!
+
+ The downgrade of a secure connection to an insecure one may
+ allow an attacker to take control of Active Directory object
+ handles created on a connection created from an Administrator
+ account and re-use them on the now non-privileged connection,
+ compromising the security of the Samba AD-DC.
+
+o CVE-2016-2110:
+
+ There are several man in the middle attacks possible with
+ NTLMSSP authentication.
+
+ E.g. NTLMSSP_NEGOTIATE_SIGN and NTLMSSP_NEGOTIATE_SEAL
+ can be cleared by a man in the middle.
+
+ This was by protocol design in earlier Windows versions.
+
+ Windows Server 2003 RTM and Vista RTM introduced a way
+ to protect against the trivial downgrade.
+
+ See MsvAvFlags and flag 0x00000002 in
+ https://msdn.microsoft.com/en-us/library/cc236646.aspx
+
+ This new feature also implies support for a mechlistMIC
+ when used within SPNEGO, which may prevent downgrades
+ from other SPNEGO mechs, e.g. Kerberos, if sign or
+ seal is finally negotiated.
+
+ The Samba implementation doesn't enforce the existence of
+ required flags, which were requested by the application layer,
+ e.g. LDAP or SMB1 encryption (via the unix extensions).
+ As a result a man in the middle can take over the connection.
+ It is also possible to misguide client and/or
+ server to send unencrypted traffic even if encryption
+ was explicitly requested.
+
+ LDAP (with NTLMSSP authentication) is used as a client
+ by various admin tools of the Samba project,
+ e.g. "net", "samba-tool", "ldbsearch", "ldbedit", ...
+
+ As an active directory member server LDAP is also used
+ by the winbindd service when connecting to domain controllers.
+
+ Samba also offers an LDAP server when running as
+ active directory domain controller.
+
+ The NTLMSSP authentication used by the SMB1 encryption
+ is protected by smb signing, see CVE-2015-5296.
+
+o CVE-2016-2111:
+
+ It's basically the same as CVE-2015-0005 for Windows:
+
+ The NETLOGON service in Microsoft Windows Server 2003 SP2,
+ Windows Server 2008 SP2 and R2 SP1, and Windows Server 2012 Gold
+ and R2, when a Domain Controller is configured, allows remote
+ attackers to spoof the computer name of a secure channel's
+ endpoint, and obtain sensitive session information, by running a
+ crafted application and leveraging the ability to sniff network
+ traffic, aka "NETLOGON Spoofing Vulnerability".
+
+ The vulnerability in Samba is worse as it doesn't require
+ credentials of a computer account in the domain.
+
+ This only applies to Samba running as classic primary domain controller,
+ classic backup domain controller or active directory domain controller.
+
+ The security patches introduce a new option called "raw NTLMv2 auth"
+ ("yes" or "no") for the [global] section in smb.conf.
+ Samba (the smbd process) will reject client using raw NTLMv2
+ without using NTLMSSP.
+
+ Note that this option also applies to Samba running as
+ standalone server and member server.
+
+ You should also consider using "lanman auth = no" (which is already the default)
+ and "ntlm auth = no". Have a look at the smb.conf manpage for further details,
+ as they might impact compatibility with older clients. These also
+ apply for all server roles.
+
+o CVE-2016-2112:
+
+ Samba uses various LDAP client libraries, a builtin one and/or the system
+ ldap libraries (typically openldap).
+
+ As active directory domain controller Samba also provides an LDAP server.
+
+ Samba takes care of doing SASL (GSS-SPNEGO) authentication with Kerberos or NTLMSSP
+ for LDAP connections, including possible integrity (sign) and privacy (seal)
+ protection.
+
+ Samba has support for an option called "client ldap sasl wrapping" since version
+ 3.2.0. Its default value has changed from "plain" to "sign" with version 4.2.0.
+
+ Tools using the builtin LDAP client library do not obey the
+ "client ldap sasl wrapping" option. This applies to tools like:
+ "samba-tool", "ldbsearch", "ldbedit" and more. Some of them have command line
+ options like "--sign" and "--encrypt". With the security update they will
+ also obey the "client ldap sasl wrapping" option as default.
+
+ In all cases, even if explicitly request via "client ldap sasl wrapping",
+ "--sign" or "--encrypt", the protection can be downgraded by a man in the
+ middle.
+
+ The LDAP server doesn't have an option to enforce strong authentication
+ yet. The security patches will introduce a new option called
+ "ldap server require strong auth", possible values are "no",
+ "allow_sasl_over_tls" and "yes".
+
+ As the default behavior was as "no" before, you may
+ have to explicitly change this option until all clients have
+ been adjusted to handle LDAP_STRONG_AUTH_REQUIRED errors.
+ Windows clients and Samba member servers already use
+ integrity protection.
+
+o CVE-2016-2113:
+
+ Samba has support for TLS/SSL for some protocols:
+ ldap and http, but currently certificates are not
+ validated at all. While we have a "tls cafile" option,
+ the configured certificate is not used to validate
+ the server certificate.
+
+ This applies to ldaps:// connections triggered by tools like:
+ "ldbsearch", "ldbedit" and more. Note that it only applies
+ to the ldb tools when they are built as part of Samba or with Samba
+ extensions installed, which means the Samba builtin LDAP client library is
+ used.
+
+ It also applies to dcerpc client connections using ncacn_http (with https://),
+ which are only used by the openchange project. Support for ncacn_http
+ was introduced in version 4.2.0.
+
+ The security patches will introduce a new option called
+ "tls verify peer". Possible values are "no_check", "ca_only",
+ "ca_and_name_if_available", "ca_and_name" and "as_strict_as_possible".
+
+ If you use the self-signed certificates which are auto-generated
+ by Samba, you won't have a crl file and need to explicitly
+ set "tls verify peer = ca_and_name".
+
+o CVE-2016-2114
+
+ Due to a regression introduced in Samba 4.0.0,
+ an explicit "server signing = mandatory" in the [global] section
+ of the smb.conf was not enforced for clients using the SMB1 protocol.
+
+ As a result it does not enforce smb signing and allows man in the middle attacks.
+
+ This problem applies to all possible server roles:
+ standalone server, member server, classic primary domain controller,
+ classic backup domain controller and active directory domain controller.
+
+ In addition, when Samba is configured with "server role = active directory domain controller"
+ the effective default for the "server signing" option should be "mandatory".
+
+ During the early development of Samba 4 we had a new experimental
+ file server located under source4/smb_server. But before
+ the final 4.0.0 release we switched back to the file server
+ under source3/smbd.
+
+ But the logic for the correct default of "server signing" was not
+ ported correctly ported.
+
+ Note that the default for server roles other than active directory domain
+ controller, is "off" because of performance reasons.
+
+o CVE-2016-2115:
+
+ Samba has an option called "client signing", this is turned off by default
+ for performance reasons on file transfers.
+
+ This option is also used when using DCERPC with ncacn_np.
+
+ In order to get integrity protection for ipc related communication
+ by default the "client ipc signing" option is introduced.
+ The effective default for this new option is "mandatory".
+
+ In order to be compatible with more SMB server implementations,
+ the following additional options are introduced:
+ "client ipc min protocol" ("NT1" by default) and
+ "client ipc max protocol" (the highest support SMB2/3 dialect by default).
+ These options overwrite the "client min protocol" and "client max protocol"
+ options, because the default for "client max protocol" is still "NT1".
+ The reason for this is the fact that all SMB2/3 support SMB signing,
+ while there are still SMB1 implementations which don't offer SMB signing
+ by default (this includes Samba versions before 4.0.0).
+
+ Note that winbindd (in versions 4.2.0 and higher) enforces SMB signing
+ against active directory domain controllers despite of the
+ "client signing" and "client ipc signing" options.
+
+o CVE-2016-2118 (a.k.a. BADLOCK):
+
+ The Security Account Manager Remote Protocol [MS-SAMR] and the
+ Local Security Authority (Domain Policy) Remote Protocol [MS-LSAD]
+ are both vulnerable to man in the middle attacks. Both are application level
+ protocols based on the generic DCE 1.1 Remote Procedure Call (DCERPC) protocol.
+
+ These protocols are typically available on all Windows installations
+ as well as every Samba server. They are used to maintain
+ the Security Account Manager Database. This applies to all
+ roles, e.g. standalone, domain member, domain controller.
+
+ Any authenticated DCERPC connection a client initiates against a server
+ can be used by a man in the middle to impersonate the authenticated user
+ against the SAMR or LSAD service on the server.
+
+ The client chosen application protocol, auth type (e.g. Kerberos or NTLMSSP)
+ and auth level (NONE, CONNECT, PKT_INTEGRITY, PKT_PRIVACY) do not matter
+ in this case. A man in the middle can change auth level to CONNECT
+ (which means authentication without message protection) and take over
+ the connection.
+
+ As a result, a man in the middle is able to get read/write access to the
+ Security Account Manager Database, which reveals all passwords
+ and any other potential sensitive information.
+
+ Samba running as an active directory domain controller is additionally
+ missing checks to enforce PKT_PRIVACY for the
+ Directory Replication Service Remote Protocol [MS-DRSR] (drsuapi)
+ and the BackupKey Remote Protocol [MS-BKRP] (backupkey).
+ The Domain Name Service Server Management Protocol [MS-DNSP] (dnsserver)
+ is not enforcing at least PKT_INTEGRITY.
+
+====================
+New smb.conf options
+====================
+
+ allow dcerpc auth level connect (G)
+
+ This option controls whether DCERPC services are allowed to be used with
+ DCERPC_AUTH_LEVEL_CONNECT, which provides authentication, but no per
+ message integrity nor privacy protection.
+
+ Some interfaces like samr, lsarpc and netlogon have a hard-coded default
+ of no and epmapper, mgmt and rpcecho have a hard-coded default of yes.
+
+ The behavior can be overwritten per interface name (e.g. lsarpc,
+ netlogon, samr, srvsvc, winreg, wkssvc ...) by using
+ 'allow dcerpc auth level connect:interface = yes' as option.
+
+ This option yields precedence to the implementation specific restrictions.
+ E.g. the drsuapi and backupkey protocols require DCERPC_AUTH_LEVEL_PRIVACY.
+ The dnsserver protocol requires DCERPC_AUTH_LEVEL_INTEGRITY.
+
+ Default: allow dcerpc auth level connect = no
+
+ Example: allow dcerpc auth level connect = yes
+
+ client ipc signing (G)
+
+ This controls whether the client is allowed or required to use
+ SMB signing for IPC$ connections as DCERPC transport. Possible
+ values are auto, mandatory and disabled.
+
+ When set to mandatory or default, SMB signing is required.
+
+ When set to auto, SMB signing is offered, but not enforced and
+ if set to disabled, SMB signing is not offered either.
+
+ Connections from winbindd to Active Directory Domain Controllers
+ always enforce signing.
+
+ Default: client ipc signing = default
+
+ client ipc max protocol (G)
+
+ The value of the parameter (a string) is the highest protocol level that will
+ be supported for IPC$ connections as DCERPC transport.
+
+ Normally this option should not be set as the automatic negotiation phase
+ in the SMB protocol takes care of choosing the appropriate protocol.
+
+ The value default refers to the latest supported protocol, currently SMB3_11.
+
+ See client max protocol for a full list of available protocols.
+ The values CORE, COREPLUS, LANMAN1, LANMAN2 are silently upgraded to NT1.
+
+ Default: client ipc max protocol = default
+
+ Example: client ipc max protocol = SMB2_10
+
+ client ipc min protocol (G)
+
+ This setting controls the minimum protocol version that the will be
+ attempted to use for IPC$ connections as DCERPC transport.
+
+ Normally this option should not be set as the automatic negotiation phase
+ in the SMB protocol takes care of choosing the appropriate protocol.
+
+ The value default refers to the higher value of NT1 and the
+ effective value of "client min protocol".
+
+ See client max protocol for a full list of available protocols.
+ The values CORE, COREPLUS, LANMAN1, LANMAN2 are silently upgraded to NT1.
+
+ Default: client ipc min protocol = default
+
+ Example: client ipc min protocol = SMB3_11
+
+ ldap server require strong auth (G)
+
+ The ldap server require strong auth defines whether the
+ ldap server requires ldap traffic to be signed or
+ signed and encrypted (sealed). Possible values are no,
+ allow_sasl_over_tls and yes.
+
+ A value of no allows simple and sasl binds over all transports.
+
+ A value of allow_sasl_over_tls allows simple and sasl binds (without sign or seal)
+ over TLS encrypted connections. Unencrypted connections only
+ allow sasl binds with sign or seal.
+
+ A value of yes allows only simple binds over TLS encrypted connections.
+ Unencrypted connections only allow sasl binds with sign or seal.
+
+ Default: ldap server require strong auth = yes
+
+ raw NTLMv2 auth (G)
+
+ This parameter determines whether or not smbd(8) will allow SMB1 clients
+ without extended security (without SPNEGO) to use NTLMv2 authentication.
+
+ If this option, lanman auth and ntlm auth are all disabled, then only
+ clients with SPNEGO support will be permitted. That means NTLMv2 is only
+ supported within NTLMSSP.
+
+ Default: raw NTLMv2 auth = no
+
+ tls verify peer (G)
+
+ This controls if and how strict the client will verify the peer's
+ certificate and name. Possible values are (in increasing order): no_check,
+ ca_only, ca_and_name_if_available, ca_and_name and as_strict_as_possible.
+
+ When set to no_check the certificate is not verified at all,
+ which allows trivial man in the middle attacks.
+
+ When set to ca_only the certificate is verified to be signed from a ca
+ specified in the "tls ca file" option. Setting "tls ca file" to a valid file
+ is required. The certificate lifetime is also verified. If the "tls crl file"
+ option is configured, the certificate is also verified against
+ the ca crl.
+
+ When set to ca_and_name_if_available all checks from ca_only are performed.
+ In addition, the peer hostname is verified against the certificate's
+ name, if it is provided by the application layer and not given as
+ an ip address string.
+
+ When set to ca_and_name all checks from ca_and_name_if_available are performed.
+ In addition the peer hostname needs to be provided and even an ip
+ address is checked against the certificate's name.
+
+ When set to as_strict_as_possible all checks from ca_and_name are performed.
+ In addition the "tls crl file" needs to be configured. Future versions
+ of Samba may implement additional checks.
+
+ Default: tls verify peer = as_strict_as_possible
+
+ tls priority (G) (backported from Samba 4.3 to Samba 4.2)
+
+ This option can be set to a string describing the TLS protocols to be
+ supported in the parts of Samba that use GnuTLS, specifically the AD DC.
+
+ The default turns off SSLv3, as this protocol is no longer considered
+ secure after CVE-2014-3566 (otherwise known as POODLE) impacted SSLv3 use
+ in HTTPS applications.
+
+ The valid options are described in the GNUTLS Priority-Strings
+ documentation at http://gnutls.org/manual/html_node/Priority-Strings.html
+
+ Default: tls priority = NORMAL:-VERS-SSL3.0
+
+================
+Behavior changes
+================
+
+o The default auth level for authenticated binds has changed from
+ DCERPC_AUTH_LEVEL_CONNECT to DCERPC_AUTH_LEVEL_INTEGRITY.
+ That means ncacn_ip_tcp:server is now implicitly the same
+ as ncacn_ip_tcp:server[sign] and offers a similar protection
+ as ncacn_np:server, which relies on smb signing.
+
+o The following constraints are applied to SMB1 connections:
+
+ - "client lanman auth = yes" is now consistently
+ required for authenticated connections using the
+ SMB1 LANMAN2 dialect.
+ - "client ntlmv2 auth = yes" and "client use spnego = yes"
+ (both the default values), require extended security (SPNEGO)
+ support from the server. That means NTLMv2 is only used within
+ NTLMSSP.
+
+o Tools like "samba-tool", "ldbsearch", "ldbedit" and more obey the
+ default of "client ldap sasl wrapping = sign". Even with
+ "client ldap sasl wrapping = plain" they will automatically upgrade
+ to "sign" when getting LDAP_STRONG_AUTH_REQUIRED from the LDAP
+ server.
+
+Changes since 4.2.9:
+====================
+
+o Jeremy Allison <jra@samba.org>
+ * Bug 11344 - CVE-2015-5370: Multiple errors in DCE-RPC code.
+
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Christian Ambach <ambi@samba.org>
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Andrew Bartlett <abartlet@samba.org>
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Ralph Boehme <slow@samba.org>
+ * Bug 11644 - CVE-2016-2112: The LDAP client and server don't enforce
+ integrity protection.
+
+o Günther Deschner <gd@samba.org>
+ * Bug 11749 - CVE-2016-2111: NETLOGON Spoofing Vulnerability.
+
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Björn Jacke <bj@sernet.de>
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Volker Lendecke <vl@samba.org>
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Kamen Mazdrashki <kamenim@samba.org>
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Stefan Metzmacher <metze@samba.org>
+ * Bug 11344 - CVE-2015-5370: Multiple errors in DCE-RPC code.
+
+ * Bug 11616 - CVE-2016-2118: SAMR and LSA man in the middle attacks possible.
+
+ * Bug 11644 - CVE-2016-2112: The LDAP client and server doesn't enforce
+ integrity protection.
+
+ * Bug 11687 - CVE-2016-2114: "server signing = mandatory" not enforced.
+
+ * Bug 11688 - CVE-2016-2110: Man in the middle attacks possible with NTLMSSP.
+
+ * Bug 11749 - CVE-2016-2111: NETLOGON Spoofing Vulnerability.
+
+ * Bug 11752 - CVE-2016-2113: Missing TLS certificate validation allows man in
+ the middle attacks.
+
+ * Bug 11756 - CVE-2016-2115: SMB client connections for IPC traffic are not
+ integrity protected.
+
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Richard Sharpe <rsharpe@samba.org>
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Andreas Schneider <asn@samba.org>
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+o Jelmer Vernooij <jelmer@samba.org>
+ * Bug 11804 - prerequisite backports for the security release on
+ April 12th, 2016.
+
+
+#######################################
+Reporting bugs & Development Discussion
+#######################################
+
+Please discuss this release on the samba-technical mailing list or by
+joining the #samba-technical IRC channel on irc.freenode.net.
+
+If you do report problems then please try to send high quality
+feedback. If you don't provide vital information to help us track down
+the problem then you will probably be ignored. All bug reports should
+be filed under the "Samba 4.1 and newer" product in the project's Bugzilla
+database (https://bugzilla.samba.org/).
+
+
+======================================================================
+== Our Code, Our Bugs, Our Responsibility.
+== The Samba Team
+======================================================================
+
+
+Release notes for older releases follow:
+----------------------------------------
+
+
=============================
Release Notes for Samba 4.2.9
March 8, 2016
@@ -78,8 +655,8 @@ database (https://bugzilla.samba.org/).
======================================================================
-Release notes for older releases follow:
-----------------------------------------
+----------------------------------------------------------------------
+
=============================
Release Notes for Samba 4.2.8
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c
index e988d2d3c79..7c7e4d5748b 100644
--- a/auth/credentials/credentials.c
+++ b/auth/credentials/credentials.c
@@ -900,6 +900,7 @@ _PUBLIC_ void cli_credentials_set_anonymous(struct cli_credentials *cred)
cli_credentials_set_password(cred, NULL, CRED_SPECIFIED);
cli_credentials_set_realm(cred, NULL, CRED_SPECIFIED);
cli_credentials_set_workstation(cred, "", CRED_UNINITIALISED);
+ cli_credentials_set_kerberos_state(cred, CRED_DONT_USE_KERBEROS);
}
/**
diff --git a/auth/credentials/credentials.h b/auth/credentials/credentials.h
index 2da47d2cac3..6c5c2c88f58 100644
--- a/auth/credentials/credentials.h
+++ b/auth/credentials/credentials.h
@@ -22,6 +22,7 @@
#ifndef __CREDENTIALS_H__
#define __CREDENTIALS_H__
+#include "../lib/util/time.h"
#include "../lib/util/data_blob.h"
#include "librpc/gen_ndr/misc.h"
@@ -80,7 +81,9 @@ void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALL
const char **domain);
NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
int *flags,
- DATA_BLOB challenge, DATA_BLOB target_info,
+ DATA_BLOB challenge,
+ const NTTIME *server_timestamp,
+ DATA_BLOB target_info,
DATA_BLOB *_lm_response, DATA_BLOB *_nt_response,
DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key);
const char *cli_credentials_get_realm(struct cli_credentials *cred);
diff --git a/auth/credentials/credentials_krb5.c b/auth/credentials/credentials_krb5.c
index d968e200e77..a340ed97c59 100644
--- a/auth/credentials/credentials_krb5.c
+++ b/auth/credentials/credentials_krb5.c
@@ -516,7 +516,7 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
OM_uint32 maj_stat, min_stat;
struct gssapi_creds_container *gcc;
struct ccache_container *ccache;
-#ifdef SAMBA4_USES_HEIMDAL
+#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
#endif
krb5_enctype *etypes = NULL;
@@ -632,8 +632,7 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
}
}
-#ifdef SAMBA4_USES_HEIMDAL /* MIT lacks GSS_KRB5_CRED_NO_CI_FLAGS_X */
-
+#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
/* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */
maj_stat = gss_set_cred_option(&min_stat, &gcc->creds,
GSS_KRB5_CRED_NO_CI_FLAGS_X,
diff --git a/auth/credentials/credentials_ntlm.c b/auth/credentials/credentials_ntlm.c
index 8c6be395226..c1d0c00de59 100644
--- a/auth/credentials/credentials_ntlm.c
+++ b/auth/credentials/credentials_ntlm.c
@@ -30,7 +30,9 @@
_PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
int *flags,
- DATA_BLOB challenge, DATA_BLOB target_info,
+ DATA_BLOB challenge,
+ const NTTIME *server_timestamp,
+ DATA_BLOB target_info,
DATA_BLOB *_lm_response, DATA_BLOB *_nt_response,
DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key)
{
@@ -102,7 +104,7 @@ _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred
user,
domain,
nt_hash->hash, &challenge,
- &target_info,
+ server_timestamp, &target_info,
&lm_response, &nt_response,
NULL, &session_key)) {
return NT_STATUS_NO_MEMORY;
@@ -110,6 +112,12 @@ _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred
/* LM Key is incompatible... */
*flags &= ~CLI_CRED_LANMAN_AUTH;
+ if (lm_response.length != 0) {
+ /*
+ * We should not expose the lm key.
+ */
+ memset(lm_response.data, 0, lm_response.length);
+ }
} else if (*flags & CLI_CRED_NTLM2) {
MD5_CTX md5_session_nonce_ctx;
uint8_t session_nonce[16];
diff --git a/auth/gensec/gensec.c b/auth/gensec/gensec.c
index 01cceaf912f..4d0968b298f 100644
--- a/auth/gensec/gensec.c
+++ b/auth/gensec/gensec.c
@@ -30,6 +30,16 @@
#include "auth/gensec/gensec_internal.h"
#include "librpc/gen_ndr/dcerpc.h"
+_PRIVATE_ NTSTATUS gensec_may_reset_crypto(struct gensec_security *gensec_security,
+ bool full_reset)
+{
+ if (!gensec_security->ops->may_reset_crypto) {
+ return NT_STATUS_OK;
+ }
+
+ return gensec_security->ops->may_reset_crypto(gensec_security, full_reset);
+}
+
/*
wrappers for the gensec function pointers
*/
@@ -217,6 +227,50 @@ _PUBLIC_ size_t gensec_max_update_size(struct gensec_security *gensec_security)
return gensec_security->max_update_size;
}
+static NTSTATUS gensec_verify_dcerpc_auth_level(struct gensec_security *gensec_security)
+{
+ if (gensec_security->dcerpc_auth_level == 0) {
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Because callers using the
+ * gensec_start_mech_by_auth_type() never call
+ * gensec_want_feature(), it isn't sensible for them
+ * to have to call gensec_have_feature() manually, and
+ * these are not points of negotiation, but are
+ * asserted by the client
+ */
+ switch (gensec_security->dcerpc_auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+ DEBUG(0,("Did not manage to negotiate mandetory feature "
+ "SIGN for dcerpc auth_level %u\n",
+ gensec_security->dcerpc_auth_level));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ break;
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+ DEBUG(0,("Did not manage to negotiate mandetory feature "
+ "SIGN for dcerpc auth_level %u\n",
+ gensec_security->dcerpc_auth_level));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
+ DEBUG(0,("Did not manage to negotiate mandetory feature "
+ "SEAL for dcerpc auth_level %u\n",
+ gensec_security->dcerpc_auth_level));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return NT_STATUS_OK;
+}
+
_PUBLIC_ NTSTATUS gensec_update_ev(struct gensec_security *gensec_security,
TALLOC_CTX *out_mem_ctx,
struct tevent_context *ev,
@@ -261,31 +315,9 @@ _PUBLIC_ NTSTATUS gensec_update_ev(struct gensec_security *gensec_security,
* these are not points of negotiation, but are
* asserted by the client
*/
- switch (gensec_security->dcerpc_auth_level) {
- case DCERPC_AUTH_LEVEL_INTEGRITY:
- if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
- DEBUG(0,("Did not manage to negotiate mandetory feature "
- "SIGN for dcerpc auth_level %u\n",
- gensec_security->dcerpc_auth_level));
- return NT_STATUS_ACCESS_DENIED;
- }
- break;
- case DCERPC_AUTH_LEVEL_PRIVACY:
- if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
- DEBUG(0,("Did not manage to negotiate mandetory feature "
- "SIGN for dcerpc auth_level %u\n",
- gensec_security->dcerpc_auth_level));
- return NT_STATUS_ACCESS_DENIED;
- }
- if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
- DEBUG(0,("Did not manage to negotiate mandetory feature "
- "SEAL for dcerpc auth_level %u\n",
- gensec_security->dcerpc_auth_level));
- return NT_STATUS_ACCESS_DENIED;
- }
- break;
- default:
- break;
+ status = gensec_verify_dcerpc_auth_level(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
return NT_STATUS_OK;
@@ -458,34 +490,9 @@ static void gensec_update_subreq_done(struct tevent_req *subreq)
* these are not points of negotiation, but are
* asserted by the client
*/
- switch (state->gensec_security->dcerpc_auth_level) {
- case DCERPC_AUTH_LEVEL_INTEGRITY:
- if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SIGN)) {
- DEBUG(0,("Did not manage to negotiate mandetory feature "
- "SIGN for dcerpc auth_level %u\n",
- state->gensec_security->dcerpc_auth_level));
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
- }
- break;
- case DCERPC_AUTH_LEVEL_PRIVACY:
- if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SIGN)) {
- DEBUG(0,("Did not manage to negotiate mandetory feature "
- "SIGN for dcerpc auth_level %u\n",
- state->gensec_security->dcerpc_auth_level));
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
- }
- if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SEAL)) {
- DEBUG(0,("Did not manage to negotiate mandetory feature "
- "SEAL for dcerpc auth_level %u\n",
- state->gensec_security->dcerpc_auth_level));
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
- }
- break;
- default:
- break;
+ status = gensec_verify_dcerpc_auth_level(state->gensec_security);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
tevent_req_done(req);
diff --git a/auth/gensec/gensec.h b/auth/gensec/gensec.h
index 0d3a29ca831..e8bd7b1f22a 100644
--- a/auth/gensec/gensec.h
+++ b/auth/gensec/gensec.h
@@ -61,6 +61,8 @@ struct gensec_target {
#define GENSEC_FEATURE_SIGN_PKT_HEADER 0x00000040
#define GENSEC_FEATURE_NEW_SPNEGO 0x00000080
#define GENSEC_FEATURE_UNIX_TOKEN 0x00000100
+#define GENSEC_FEATURE_NTLM_CCACHE 0x00000200
+#define GENSEC_FEATURE_LDAP_STYLE 0x00000400
#define GENSEC_EXPIRE_TIME_INFINITY (NTTIME)0x8000000000000000LL
@@ -107,30 +109,9 @@ const struct gensec_critical_sizes *gensec_interface_version(void);
/* Socket wrapper */
struct gensec_security;
-struct socket_context;
struct auth4_context;
struct auth_user_info_dc;
-/* These functions are for use here only (public because SPNEGO must
- * use them for recursion) */
-NTSTATUS gensec_wrap_packets(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const DATA_BLOB *in,
- DATA_BLOB *out,
- size_t *len_processed);
-/* These functions are for use here only (public because SPNEGO must
- * use them for recursion) */
-NTSTATUS gensec_unwrap_packets(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const DATA_BLOB *in,
- DATA_BLOB *out,
- size_t *len_processed);
-
-/* These functions are for use here only (public because SPNEGO must
- * use them for recursion) */
-NTSTATUS gensec_packet_full_request(struct gensec_security *gensec_security,
- DATA_BLOB blob, size_t *size);
-
struct loadparm_context;
NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
@@ -184,6 +165,8 @@ const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_sec
const struct gensec_security_ops *gensec_security_by_auth_type(
struct gensec_security *gensec_security,
uint32_t auth_type);
+const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
+ const char *name);
const struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx);
const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(
diff --git a/auth/gensec/gensec_internal.h b/auth/gensec/gensec_internal.h
index c04164a3dbd..55352417e99 100644
--- a/auth/gensec/gensec_internal.h
+++ b/auth/gensec/gensec_internal.h
@@ -47,6 +47,8 @@ struct gensec_security_ops {
NTSTATUS (*update_recv)(struct tevent_req *req,
TALLOC_CTX *out_mem_ctx,
DATA_BLOB *out);
+ NTSTATUS (*may_reset_crypto)(struct gensec_security *gensec_security,
+ bool full_reset);
NTSTATUS (*seal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
uint8_t *data, size_t length,
const uint8_t *whole_pdu, size_t pdu_length,
@@ -74,18 +76,6 @@ struct gensec_security_ops {
TALLOC_CTX *mem_ctx,
const DATA_BLOB *in,
DATA_BLOB *out);
- NTSTATUS (*wrap_packets)(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const DATA_BLOB *in,
- DATA_BLOB *out,
- size_t *len_processed);
- NTSTATUS (*unwrap_packets)(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const DATA_BLOB *in,
- DATA_BLOB *out,
- size_t *len_processed);
- NTSTATUS (*packet_full_request)(struct gensec_security *gensec_security,
- DATA_BLOB blob, size_t *size);
NTSTATUS (*session_key)(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx,
DATA_BLOB *session_key);
NTSTATUS (*session_info)(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx,
@@ -122,6 +112,8 @@ struct gensec_security {
* NTLM authentication backend, and user lookup (such as if no
* PAC is found) */
struct auth4_context *auth_context;
+
+ struct gensec_security *child_security;
};
/* this structure is used by backends to determine the size of some critical types */
@@ -131,4 +123,7 @@ struct gensec_critical_sizes {
int sizeof_gensec_security;
};
+NTSTATUS gensec_may_reset_crypto(struct gensec_security *gensec_security,
+ bool full_reset);
+
#endif /* __GENSEC_H__ */
diff --git a/auth/gensec/gensec_start.c b/auth/gensec/gensec_start.c
index b1bc1b93223..cb836f47ac3 100644
--- a/auth/gensec/gensec_start.c
+++ b/auth/gensec/gensec_start.c
@@ -203,8 +203,10 @@ _PUBLIC_ const struct gensec_security_ops *gensec_security_by_sasl_name(
}
backends = gensec_security_mechs(gensec_security, mem_ctx);
for (i=0; backends && backends[i]; i++) {
- if (!gensec_security_ops_enabled(backends[i], gensec_security))
- continue;
+ if (gensec_security != NULL &&
+ !gensec_security_ops_enabled(backends[i], gensec_security)) {
+ continue;
+ }
if (backends[i]->sasl_name
&& (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
backend = backends[i];
@@ -224,7 +226,13 @@ _PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type(
int i;
const struct gensec_security_ops **backends;
const struct gensec_security_ops *backend;
- TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
+ TALLOC_CTX *mem_ctx;
+
+ if (auth_type == DCERPC_AUTH_TYPE_NONE) {
+ return NULL;
+ }
+
+ mem_ctx = talloc_new(gensec_security);
if (!mem_ctx) {
return NULL;
}
@@ -245,8 +253,8 @@ _PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type(
return NULL;
}
-static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
- const char *name)
+const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
+ const char *name)
{
int i;
const struct gensec_security_ops **backends;
diff --git a/auth/gensec/gensec_util.c b/auth/gensec/gensec_util.c
index b8e38b7f7c9..64fffb1efc9 100644
--- a/auth/gensec/gensec_util.c
+++ b/auth/gensec/gensec_util.c
@@ -68,122 +68,6 @@ NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx,
}
/*
- * These functions are for use in the deprecated
- * gensec_socket code (public because SPNEGO must
- * use them for recursion)
- */
-_PUBLIC_ NTSTATUS gensec_wrap_packets(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const DATA_BLOB *in,
- DATA_BLOB *out,
- size_t *len_processed)
-{
- if (!gensec_security->ops->wrap_packets) {
- NTSTATUS nt_status;
- size_t max_input_size;
- DATA_BLOB unwrapped, wrapped;
- max_input_size = gensec_max_input_size(gensec_security);
- unwrapped = data_blob_const(in->data, MIN(max_input_size, (size_t)in->length));
-
- nt_status = gensec_wrap(gensec_security,
- mem_ctx,
- &unwrapped, &wrapped);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
-
- *out = data_blob_talloc(mem_ctx, NULL, 4);
- if (!out->data) {
- return NT_STATUS_NO_MEMORY;
- }
- RSIVAL(out->data, 0, wrapped.length);
-
- if (!data_blob_append(mem_ctx, out, wrapped.data, wrapped.length)) {
- return NT_STATUS_NO_MEMORY;
- }
- *len_processed = unwrapped.length;
- return NT_STATUS_OK;
- }
- return gensec_security->ops->wrap_packets(gensec_security, mem_ctx, in, out,
- len_processed);
-}
-
-/*
- * These functions are for use in the deprecated
- * gensec_socket code (public because SPNEGO must
- * use them for recursion)
- */
-NTSTATUS gensec_unwrap_packets(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const DATA_BLOB *in,
- DATA_BLOB *out,
- size_t *len_processed)
-{
- if (!gensec_security->ops->unwrap_packets) {
- DATA_BLOB wrapped;
- NTSTATUS nt_status;
- size_t packet_size;
- if (in->length < 4) {
- /* Missing the header we already had! */
- DEBUG(0, ("Asked to unwrap packet of bogus length! How did we get the short packet?!\n"));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- packet_size = RIVAL(in->data, 0);
-
- wrapped = data_blob_const(in->data + 4, packet_size);
-
- if (wrapped.length > (in->length - 4)) {
- DEBUG(0, ("Asked to unwrap packed of bogus length %d > %d! How did we get this?!\n",
- (int)wrapped.length, (int)(in->length - 4)));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- nt_status = gensec_unwrap(gensec_security,
- mem_ctx,
- &wrapped, out);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
-
- *len_processed = packet_size + 4;
- return nt_status;
- }
- return gensec_security->ops->unwrap_packets(gensec_security, mem_ctx, in, out,
- len_processed);
-}
-
-/*
- * These functions are for use in the deprecated
- * gensec_socket code (public because SPNEGO must
- * use them for recursion)
- */
-NTSTATUS gensec_packet_full_request(struct gensec_security *gensec_security,
- DATA_BLOB blob, size_t *size)
-{
- if (gensec_security->ops->packet_full_request) {
- return gensec_security->ops->packet_full_request(gensec_security,
- blob, size);
- }
- if (gensec_security->ops->unwrap_packets) {
- if (blob.length) {
- *size = blob.length;
- return NT_STATUS_OK;
- }
- return STATUS_MORE_ENTRIES;
- }
-
- if (blob.length < 4) {
- return STATUS_MORE_ENTRIES;
- }
- *size = 4 + RIVAL(blob.data, 0);
- if (*size > blob.length) {
- return STATUS_MORE_ENTRIES;
- }
- return NT_STATUS_OK;
-}
-
-/*
magic check a GSS-API wrapper packet for an Kerberos OID
*/
static bool gensec_gssapi_check_oid(const DATA_BLOB *blob, const char *oid)
@@ -197,7 +81,7 @@ static bool gensec_gssapi_check_oid(const DATA_BLOB *blob, const char *oid)
if (!asn1_start_tag(data, ASN1_APPLICATION(0))) goto err;
if (!asn1_check_OID(data, oid)) goto err;
- ret = !data->has_error;
+ ret = !asn1_has_error(data);
err:
diff --git a/auth/gensec/schannel.c b/auth/gensec/schannel.c
index ee23e77ace4..1acf7fefb73 100644
--- a/auth/gensec/schannel.c
+++ b/auth/gensec/schannel.c
@@ -467,6 +467,16 @@ static NTSTATUS schannel_update(struct gensec_security *gensec_security, TALLOC_
*out = data_blob(NULL, 0);
+ if (gensec_security->dcerpc_auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
+ switch (gensec_security->gensec_role) {
+ case GENSEC_CLIENT:
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ case GENSEC_SERVER:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
switch (gensec_security->gensec_role) {
case GENSEC_CLIENT:
if (state != NULL) {
@@ -669,9 +679,15 @@ static NTSTATUS schannel_client_start(struct gensec_security *gensec_security)
static bool schannel_have_feature(struct gensec_security *gensec_security,
uint32_t feature)
{
- if (feature & (GENSEC_FEATURE_SIGN |
- GENSEC_FEATURE_SEAL)) {
- return true;
+ if (gensec_security->dcerpc_auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
+ if (feature & GENSEC_FEATURE_SIGN) {
+ return true;
+ }
+ }
+ if (gensec_security->dcerpc_auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ if (feature & GENSEC_FEATURE_SEAL) {
+ return true;
+ }
}
if (feature & GENSEC_FEATURE_DCE_STYLE) {
return true;
diff --git a/auth/gensec/spnego.c b/auth/gensec/spnego.c
index 8fd11e90527..1d4b172e476 100644
--- a/auth/gensec/spnego.c
+++ b/auth/gensec/spnego.c
@@ -53,6 +53,11 @@ struct spnego_state {
const char *neg_oid;
DATA_BLOB mech_types;
+ size_t num_targs;
+ bool mic_requested;
+ bool needs_mic_sign;
+ bool needs_mic_check;
+ bool done_mic_check;
/*
* The following is used to implement
@@ -221,59 +226,6 @@ static NTSTATUS gensec_spnego_unwrap(struct gensec_security *gensec_security,
mem_ctx, in, out);
}
-static NTSTATUS gensec_spnego_wrap_packets(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const DATA_BLOB *in,
- DATA_BLOB *out,
- size_t *len_processed)
-{
- struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
-
- if (spnego_state->state_position != SPNEGO_DONE
- && spnego_state->state_position != SPNEGO_FALLBACK) {
- DEBUG(1, ("gensec_spnego_wrap: wrong state for wrap\n"));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- return gensec_wrap_packets(spnego_state->sub_sec_security,
- mem_ctx, in, out,
- len_processed);
-}
-
-static NTSTATUS gensec_spnego_packet_full_request(struct gensec_security *gensec_security,
- DATA_BLOB blob, size_t *size)
-{
- struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
-
- if (spnego_state->state_position != SPNEGO_DONE
- && spnego_state->state_position != SPNEGO_FALLBACK) {
- DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n"));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- return gensec_packet_full_request(spnego_state->sub_sec_security,
- blob, size);
-}
-
-static NTSTATUS gensec_spnego_unwrap_packets(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const DATA_BLOB *in,
- DATA_BLOB *out,
- size_t *len_processed)
-{
- struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
-
- if (spnego_state->state_position != SPNEGO_DONE
- && spnego_state->state_position != SPNEGO_FALLBACK) {
- DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n"));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- return gensec_unwrap_packets(spnego_state->sub_sec_security,
- mem_ctx, in, out,
- len_processed);
-}
-
static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security, size_t data_size)
{
struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
@@ -469,6 +421,11 @@ static NTSTATUS gensec_spnego_parse_negTokenInit(struct gensec_security *gensec_
spnego_state->neg_oid = all_sec[i].oid;
*unwrapped_out = data_blob_null;
nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ /*
+ * Indicate the downgrade and request a
+ * mic.
+ */
+ spnego_state->mic_requested = true;
break;
}
@@ -727,22 +684,27 @@ static NTSTATUS gensec_spnego_server_negTokenTarg(struct spnego_state *spnego_st
/* compose reply */
spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
spnego_out.negTokenTarg.responseToken = unwrapped_out;
- spnego_out.negTokenTarg.mechListMIC = null_data_blob;
+ spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
spnego_out.negTokenTarg.supportedMech = NULL;
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
- spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
+ if (spnego_state->mic_requested) {
+ spnego_out.negTokenTarg.negResult = SPNEGO_REQUEST_MIC;
+ spnego_state->mic_requested = false;
+ } else {
+ spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
+ }
spnego_state->state_position = SPNEGO_SERVER_TARG;
} else if (NT_STATUS_IS_OK(nt_status)) {
if (unwrapped_out.data) {
spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
}
spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
- spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
spnego_state->state_position = SPNEGO_DONE;
} else {
spnego_out.negTokenTarg.negResult = SPNEGO_REJECT;
+ spnego_out.negTokenTarg.mechListMIC = null_data_blob;
DEBUG(2, ("SPNEGO login failed: %s\n", nt_errstr(nt_status)));
spnego_state->state_position = SPNEGO_DONE;
}
@@ -753,6 +715,7 @@ static NTSTATUS gensec_spnego_server_negTokenTarg(struct spnego_state *spnego_st
}
spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
+ spnego_state->num_targs++;
return nt_status;
}
@@ -837,6 +800,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
const char *my_mechs[] = {NULL, NULL};
NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
+ bool ok;
if (!in.length) {
/* client to produce negTokenInit */
@@ -899,6 +863,14 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
return NT_STATUS_INVALID_PARAMETER;
}
+ ok = spnego_write_mech_types(spnego_state,
+ my_mechs,
+ &spnego_state->mech_types);
+ if (!ok) {
+ DEBUG(1, ("SPNEGO: Failed to write mechTypes\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
/* set next state */
spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
spnego_state->state_position = SPNEGO_CLIENT_TARG;
@@ -936,18 +908,57 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
return NT_STATUS_INVALID_PARAMETER;
}
+ spnego_state->num_targs++;
+
if (!spnego_state->sub_sec_security) {
DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n"));
spnego_free_data(&spnego);
return NT_STATUS_INVALID_PARAMETER;
}
+ if (spnego_state->needs_mic_check) {
+ if (spnego.negTokenTarg.responseToken.length != 0) {
+ DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n"));
+ spnego_free_data(&spnego);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ nt_status = gensec_check_packet(spnego_state->sub_sec_security,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ &spnego.negTokenTarg.mechListMIC);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ spnego_state->needs_mic_check = false;
+ spnego_state->done_mic_check = true;
+ } else {
+ DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
+ nt_errstr(nt_status)));
+ }
+ goto server_response;
+ }
+
nt_status = gensec_update_ev(spnego_state->sub_sec_security,
- out_mem_ctx, ev,
- spnego.negTokenTarg.responseToken,
- &unwrapped_out);
- if (NT_STATUS_IS_OK(nt_status) && spnego.negTokenTarg.mechListMIC.length > 0) {
+ out_mem_ctx, ev,
+ spnego.negTokenTarg.responseToken,
+ &unwrapped_out);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ goto server_response;
+ }
+
+ new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
+ GENSEC_FEATURE_NEW_SPNEGO);
+ if (spnego.negTokenTarg.mechListMIC.length > 0) {
new_spnego = true;
+ }
+
+ if (new_spnego) {
+ spnego_state->needs_mic_check = true;
+ spnego_state->needs_mic_sign = true;
+ }
+
+ if (spnego.negTokenTarg.mechListMIC.length > 0) {
nt_status = gensec_check_packet(spnego_state->sub_sec_security,
spnego_state->mech_types.data,
spnego_state->mech_types.length,
@@ -957,9 +968,14 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
nt_errstr(nt_status)));
+ goto server_response;
}
+
+ spnego_state->needs_mic_check = false;
+ spnego_state->done_mic_check = true;
}
- if (NT_STATUS_IS_OK(nt_status) && new_spnego) {
+
+ if (spnego_state->needs_mic_sign) {
nt_status = gensec_sign_packet(spnego_state->sub_sec_security,
out_mem_ctx,
spnego_state->mech_types.data,
@@ -970,9 +986,16 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n",
nt_errstr(nt_status)));
+ goto server_response;
}
+ spnego_state->needs_mic_sign = false;
}
+ if (spnego_state->needs_mic_check) {
+ nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ server_response:
nt_status = gensec_spnego_server_negTokenTarg(spnego_state,
out_mem_ctx,
nt_status,
@@ -986,7 +1009,8 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
}
case SPNEGO_CLIENT_TARG:
{
- NTSTATUS nt_status;
+ NTSTATUS nt_status = NT_STATUS_INTERNAL_ERROR;
+
if (!in.length) {
return NT_STATUS_INVALID_PARAMETER;
}
@@ -1008,19 +1032,27 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
return NT_STATUS_INVALID_PARAMETER;
}
+ spnego_state->num_targs++;
+
if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
spnego_free_data(&spnego);
return NT_STATUS_LOGON_FAILURE;
}
+ if (spnego.negTokenTarg.negResult == SPNEGO_REQUEST_MIC) {
+ spnego_state->mic_requested = true;
+ }
+
/* Server didn't like our choice of mech, and chose something else */
- if ((spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_INCOMPLETE) &&
+ if (((spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_INCOMPLETE) ||
+ (spnego.negTokenTarg.negResult == SPNEGO_REQUEST_MIC)) &&
spnego.negTokenTarg.supportedMech &&
strcmp(spnego.negTokenTarg.supportedMech, spnego_state->neg_oid) != 0) {
DEBUG(3,("GENSEC SPNEGO: client preferred mech (%s) not accepted, server wants: %s\n",
- gensec_get_name_by_oid(gensec_security, spnego.negTokenTarg.supportedMech),
- gensec_get_name_by_oid(gensec_security, spnego_state->neg_oid)));
+ gensec_get_name_by_oid(gensec_security, spnego_state->neg_oid),
+ gensec_get_name_by_oid(gensec_security, spnego.negTokenTarg.supportedMech)));
+ spnego_state->no_response_expected = false;
talloc_free(spnego_state->sub_sec_security);
nt_status = gensec_subcontext_start(spnego_state,
gensec_security,
@@ -1037,64 +1069,143 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
return nt_status;
}
- nt_status = gensec_update_ev(spnego_state->sub_sec_security,
- out_mem_ctx, ev,
- spnego.negTokenTarg.responseToken,
- &unwrapped_out);
- spnego_state->neg_oid = talloc_strdup(spnego_state, spnego.negTokenTarg.supportedMech);
- } else if (spnego_state->no_response_expected) {
- if (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) {
- DEBUG(3,("GENSEC SPNEGO: client GENSEC accepted, but server rejected (bad password?)\n"));
- nt_status = NT_STATUS_INVALID_PARAMETER;
- } else if (spnego.negTokenTarg.responseToken.length) {
- DEBUG(2,("GENSEC SPNEGO: client GENSEC accepted, but server continued negotiation!\n"));
- nt_status = NT_STATUS_INVALID_PARAMETER;
- } else {
- nt_status = NT_STATUS_OK;
+ spnego_state->neg_oid = talloc_strdup(spnego_state,
+ spnego.negTokenTarg.supportedMech);
+ if (spnego_state->neg_oid == NULL) {
+ spnego_free_data(&spnego);
+ return NT_STATUS_NO_MEMORY;
+ };
+ }
+
+ if (spnego.negTokenTarg.mechListMIC.length > 0) {
+ if (spnego_state->no_response_expected) {
+ spnego_state->needs_mic_check = true;
}
- if (NT_STATUS_IS_OK(nt_status) && spnego.negTokenTarg.mechListMIC.length > 0) {
- nt_status = gensec_check_packet(spnego_state->sub_sec_security,
- spnego_state->mech_types.data,
- spnego_state->mech_types.length,
- spnego_state->mech_types.data,
- spnego_state->mech_types.length,
- &spnego.negTokenTarg.mechListMIC);
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
- nt_errstr(nt_status)));
- }
+ }
+
+ if (spnego_state->needs_mic_check) {
+ if (spnego.negTokenTarg.responseToken.length != 0) {
+ DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n"));
+ spnego_free_data(&spnego);
+ return NT_STATUS_INVALID_PARAMETER;
}
- } else {
- bool new_spnego = false;
+ nt_status = gensec_check_packet(spnego_state->sub_sec_security,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ &spnego.negTokenTarg.mechListMIC);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
+ nt_errstr(nt_status)));
+ spnego_free_data(&spnego);
+ return nt_status;
+ }
+ spnego_state->needs_mic_check = false;
+ spnego_state->done_mic_check = true;
+ goto client_response;
+ }
+
+ if (!spnego_state->no_response_expected) {
nt_status = gensec_update_ev(spnego_state->sub_sec_security,
out_mem_ctx, ev,
spnego.negTokenTarg.responseToken,
&unwrapped_out);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ goto client_response;
+ }
+
+ spnego_state->no_response_expected = true;
+ } else {
+ nt_status = NT_STATUS_OK;
+ }
- if (NT_STATUS_IS_OK(nt_status)
- && spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) {
- new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
- GENSEC_FEATURE_NEW_SPNEGO);
+ if (spnego_state->no_response_expected &&
+ !spnego_state->done_mic_check)
+ {
+ bool new_spnego = false;
+
+ new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
+ GENSEC_FEATURE_NEW_SPNEGO);
+
+ switch (spnego.negTokenTarg.negResult) {
+ case SPNEGO_ACCEPT_COMPLETED:
+ case SPNEGO_NONE_RESULT:
+ if (spnego_state->num_targs == 1) {
+ /*
+ * the first exchange doesn't require
+ * verification
+ */
+ new_spnego = false;
+ }
+ break;
+
+ case SPNEGO_ACCEPT_INCOMPLETE:
+ case SPNEGO_REQUEST_MIC:
+ if (spnego.negTokenTarg.mechListMIC.length > 0) {
+ new_spnego = true;
+ }
+ break;
+ default:
+ break;
}
- if (NT_STATUS_IS_OK(nt_status) && new_spnego) {
- nt_status = gensec_sign_packet(spnego_state->sub_sec_security,
- out_mem_ctx,
- spnego_state->mech_types.data,
- spnego_state->mech_types.length,
- spnego_state->mech_types.data,
- spnego_state->mech_types.length,
- &mech_list_mic);
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n",
- nt_errstr(nt_status)));
+
+ if (spnego_state->mic_requested) {
+ bool sign;
+
+ sign = gensec_have_feature(spnego_state->sub_sec_security,
+ GENSEC_FEATURE_SIGN);
+ if (sign) {
+ new_spnego = true;
}
}
- if (NT_STATUS_IS_OK(nt_status)) {
- spnego_state->no_response_expected = true;
+
+ if (new_spnego) {
+ spnego_state->needs_mic_check = true;
+ spnego_state->needs_mic_sign = true;
}
- }
+ }
+ if (spnego.negTokenTarg.mechListMIC.length > 0) {
+ nt_status = gensec_check_packet(spnego_state->sub_sec_security,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ &spnego.negTokenTarg.mechListMIC);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
+ nt_errstr(nt_status)));
+ spnego_free_data(&spnego);
+ return nt_status;
+ }
+ spnego_state->needs_mic_check = false;
+ spnego_state->done_mic_check = true;
+ }
+
+ if (spnego_state->needs_mic_sign) {
+ nt_status = gensec_sign_packet(spnego_state->sub_sec_security,
+ out_mem_ctx,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ &mech_list_mic);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n",
+ nt_errstr(nt_status)));
+ spnego_free_data(&spnego);
+ return nt_status;
+ }
+ spnego_state->needs_mic_sign = false;
+ }
+
+ if (spnego_state->needs_mic_check) {
+ nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ client_response:
spnego_free_data(&spnego);
if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
@@ -1118,6 +1229,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
return NT_STATUS_INVALID_PARAMETER;
}
+ spnego_state->num_targs++;
spnego_state->state_position = SPNEGO_CLIENT_TARG;
nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
} else {
@@ -1148,26 +1260,24 @@ static NTSTATUS gensec_spnego_update_in(struct gensec_security *gensec_security,
{
struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
size_t expected;
- NTSTATUS status;
bool ok;
*full_in = data_blob_null;
if (spnego_state->in_needed == 0) {
size_t size = 0;
+ int ret;
/*
* try to work out the size of the full
* input token, it might be fragmented
*/
- status = asn1_peek_full_tag(in, ASN1_APPLICATION(0), &size);
- if (!NT_STATUS_IS_OK(status) &&
- !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
- status = asn1_peek_full_tag(in, ASN1_CONTEXT(1), &size);
+ ret = asn1_peek_full_tag(in, ASN1_APPLICATION(0), &size);
+ if ((ret != 0) && (ret != EAGAIN)) {
+ ret = asn1_peek_full_tag(in, ASN1_CONTEXT(1), &size);
}
- if (NT_STATUS_IS_OK(status) ||
- NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+ if ((ret == 0) || (ret == EAGAIN)) {
spnego_state->in_needed = size;
} else {
/*
@@ -1315,6 +1425,16 @@ static NTSTATUS gensec_spnego_update_wrapper(struct gensec_security *gensec_secu
&spnego_state->out_frag);
data_blob_free(&spnego_state->in_frag);
spnego_state->in_needed = 0;
+ if (NT_STATUS_IS_OK(status)) {
+ bool reset_full = true;
+
+ gensec_security->child_security = spnego_state->sub_sec_security;
+
+ reset_full = !spnego_state->done_mic_check;
+
+ status = gensec_may_reset_crypto(spnego_state->sub_sec_security,
+ reset_full);
+ }
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
return status;
@@ -1384,11 +1504,8 @@ static const struct gensec_security_ops gensec_spnego_security_ops = {
.max_input_size = gensec_spnego_max_input_size,
.check_packet = gensec_spnego_check_packet,
.unseal_packet = gensec_spnego_unseal_packet,
- .packet_full_request = gensec_spnego_packet_full_request,
.wrap = gensec_spnego_wrap,
.unwrap = gensec_spnego_unwrap,
- .wrap_packets = gensec_spnego_wrap_packets,
- .unwrap_packets = gensec_spnego_unwrap_packets,
.session_key = gensec_spnego_session_key,
.session_info = gensec_spnego_session_info,
.want_feature = gensec_spnego_want_feature,
diff --git a/auth/gensec/wscript_build b/auth/gensec/wscript_build
index b2f6033ed00..413c60672ae 100755
--- a/auth/gensec/wscript_build
+++ b/auth/gensec/wscript_build
@@ -3,7 +3,7 @@ bld.SAMBA_LIBRARY('gensec',
source='gensec.c gensec_start.c gensec_util.c',
pc_files='gensec.pc',
autoproto='gensec_toplevel_proto.h',
- public_deps='tevent-util samba-util errors LIBPACKET auth_system_session samba-modules gensec_util asn1util',
+ public_deps='tevent-util samba-util errors auth_system_session samba-modules gensec_util asn1util',
public_headers='gensec.h',
deps='com_err',
vnum='0.0.1'
diff --git a/auth/kerberos/gssapi_helper.c b/auth/kerberos/gssapi_helper.c
new file mode 100644
index 00000000000..b7ffb6ca9ff
--- /dev/null
+++ b/auth/kerberos/gssapi_helper.c
@@ -0,0 +1,395 @@
+/*
+ Unix SMB/CIFS implementation.
+ GSSAPI helper functions
+
+ Copyright (C) Stefan Metzmacher 2008,2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/gssapi.h"
+#include "auth/kerberos/pac_utils.h"
+#include "auth/kerberos/gssapi_helper.h"
+
+size_t gssapi_get_sig_size(gss_ctx_id_t gssapi_context,
+ const gss_OID mech,
+ uint32_t gss_want_flags,
+ size_t data_size)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ size_t sig_size = 0;
+
+ if (gss_want_flags & GSS_C_CONF_FLAG) {
+ OM_uint32 min_stat, maj_stat;
+ bool want_sealing = true;
+ int sealed = 0;
+ gss_iov_buffer_desc iov[2];
+
+ if (!(gss_want_flags & GSS_C_DCE_STYLE)) {
+ TALLOC_FREE(frame);
+ return 0;
+ }
+
+ /*
+ * gss_wrap_iov_length() only needs the type and length
+ */
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[0].buffer.value = NULL;
+ iov[0].buffer.length = 0;
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[1].buffer.value = NULL;
+ iov[1].buffer.length = data_size;
+
+ maj_stat = gss_wrap_iov_length(&min_stat,
+ gssapi_context,
+ want_sealing,
+ GSS_C_QOP_DEFAULT,
+ &sealed,
+ iov, ARRAY_SIZE(iov));
+ if (maj_stat) {
+ DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
+ gssapi_error_string(frame,
+ maj_stat,
+ min_stat,
+ mech)));
+ TALLOC_FREE(frame);
+ return 0;
+ }
+
+ sig_size = iov[0].buffer.length;
+ } else if (gss_want_flags & GSS_C_INTEG_FLAG) {
+ NTSTATUS status;
+ uint32_t keytype;
+
+ status = gssapi_get_session_key(frame,
+ gssapi_context,
+ NULL, &keytype);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return 0;
+ }
+
+ switch (keytype) {
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES_CBC_CRC:
+ case ENCTYPE_ARCFOUR_HMAC:
+ case ENCTYPE_ARCFOUR_HMAC_EXP:
+ sig_size = 37;
+ break;
+ default:
+ sig_size = 28;
+ break;
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return sig_size;
+}
+
+NTSTATUS gssapi_seal_packet(gss_ctx_id_t gssapi_context,
+ const gss_OID mech,
+ bool hdr_signing, size_t sig_size,
+ uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *sig)
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_iov_buffer_desc iov[4];
+ int req_seal = 1;
+ int sealed = 0;
+ const uint8_t *pre_sign_ptr = NULL;
+ size_t pre_sign_len = 0;
+ const uint8_t *post_sign_ptr = NULL;
+ size_t post_sign_len = 0;
+
+ if (hdr_signing) {
+ const uint8_t *de = data + length;
+ const uint8_t *we = whole_pdu + pdu_length;
+
+ if (data < whole_pdu) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (de > we) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ pre_sign_len = data - whole_pdu;
+ if (pre_sign_len > 0) {
+ pre_sign_ptr = whole_pdu;
+ }
+ post_sign_len = we - de;
+ if (post_sign_len > 0) {
+ post_sign_ptr = de;
+ }
+ }
+
+ sig->length = sig_size;
+ if (sig->length == 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ sig->data = talloc_zero_array(mem_ctx, uint8_t, sig->length);
+ if (sig->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[0].buffer.length = sig->length;
+ iov[0].buffer.value = sig->data;
+
+ if (pre_sign_ptr != NULL) {
+ iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ iov[1].buffer.length = pre_sign_len;
+ iov[1].buffer.value = discard_const(pre_sign_ptr);
+ } else {
+ iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
+ iov[1].buffer.length = 0;
+ iov[1].buffer.value = NULL;
+ }
+
+ /* data is encrypted in place, which is ok */
+ iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[2].buffer.length = length;
+ iov[2].buffer.value = data;
+
+ if (post_sign_ptr != NULL) {
+ iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ iov[3].buffer.length = post_sign_len;
+ iov[3].buffer.value = discard_const(post_sign_ptr);
+ } else {
+ iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
+ iov[3].buffer.length = 0;
+ iov[3].buffer.value = NULL;
+ }
+
+ maj_stat = gss_wrap_iov(&min_stat,
+ gssapi_context,
+ req_seal,
+ GSS_C_QOP_DEFAULT,
+ &sealed,
+ iov, ARRAY_SIZE(iov));
+ if (GSS_ERROR(maj_stat)) {
+ char *error_string = gssapi_error_string(mem_ctx,
+ maj_stat,
+ min_stat,
+ mech);
+ DEBUG(1, ("gss_wrap_iov failed: %s\n", error_string));
+ talloc_free(error_string);
+ data_blob_free(sig);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (req_seal == 1 && sealed == 0) {
+ DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
+ data_blob_free(sig);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ dump_data_pw("gssapi_seal_packet: sig\n", sig->data, sig->length);
+ dump_data_pw("gssapi_seal_packet: sealed\n", data, length);
+
+ DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
+ (int)iov[2].buffer.length, (int)iov[0].buffer.length));
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS gssapi_unseal_packet(gss_ctx_id_t gssapi_context,
+ const gss_OID mech,
+ bool hdr_signing,
+ uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ const DATA_BLOB *sig)
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_iov_buffer_desc iov[4];
+ gss_qop_t qop_state;
+ int sealed = 0;
+ const uint8_t *pre_sign_ptr = NULL;
+ size_t pre_sign_len = 0;
+ const uint8_t *post_sign_ptr = NULL;
+ size_t post_sign_len = 0;
+
+ if (hdr_signing) {
+ const uint8_t *de = data + length;
+ const uint8_t *we = whole_pdu + pdu_length;
+
+ if (data < whole_pdu) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (de > we) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ pre_sign_len = data - whole_pdu;
+ if (pre_sign_len > 0) {
+ pre_sign_ptr = whole_pdu;
+ }
+ post_sign_len = we - de;
+ if (post_sign_len > 0) {
+ post_sign_ptr = de;
+ }
+ }
+
+ dump_data_pw("gssapi_unseal_packet: sig\n", sig->data, sig->length);
+ dump_data_pw("gssapi_unseal_packet: sealed\n", data, length);
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[0].buffer.length = sig->length;
+ iov[0].buffer.value = sig->data;
+
+ if (pre_sign_ptr != NULL) {
+ iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ iov[1].buffer.length = pre_sign_len;
+ iov[1].buffer.value = discard_const(pre_sign_ptr);
+ } else {
+ iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
+ iov[1].buffer.length = 0;
+ iov[1].buffer.value = NULL;
+ }
+
+ /* data is encrypted in place, which is ok */
+ iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[2].buffer.length = length;
+ iov[2].buffer.value = data;
+
+ if (post_sign_ptr != NULL) {
+ iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ iov[3].buffer.length = post_sign_len;
+ iov[3].buffer.value = discard_const(post_sign_ptr);
+ } else {
+ iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
+ iov[3].buffer.length = 0;
+ iov[3].buffer.value = NULL;
+ }
+
+ maj_stat = gss_unwrap_iov(&min_stat,
+ gssapi_context,
+ &sealed,
+ &qop_state,
+ iov, ARRAY_SIZE(iov));
+ if (GSS_ERROR(maj_stat)) {
+ char *error_string = gssapi_error_string(NULL,
+ maj_stat,
+ min_stat,
+ mech);
+ DEBUG(1, ("gss_unwrap_iov failed: %s\n", error_string));
+ talloc_free(error_string);
+
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (sealed == 0) {
+ DEBUG(0, ("gss_unwrap_iov says data was not sealed!\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
+ (int)iov[2].buffer.length, (int)iov[0].buffer.length));
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS gssapi_sign_packet(gss_ctx_id_t gssapi_context,
+ const gss_OID mech,
+ bool hdr_signing,
+ const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *sig)
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc input_token, output_token;
+
+ if (hdr_signing) {
+ input_token.length = pdu_length;
+ input_token.value = discard_const_p(uint8_t *, whole_pdu);
+ } else {
+ input_token.length = length;
+ input_token.value = discard_const_p(uint8_t *, data);
+ }
+
+ maj_stat = gss_get_mic(&min_stat,
+ gssapi_context,
+ GSS_C_QOP_DEFAULT,
+ &input_token,
+ &output_token);
+ if (GSS_ERROR(maj_stat)) {
+ char *error_string = gssapi_error_string(mem_ctx,
+ maj_stat,
+ min_stat,
+ mech);
+ DEBUG(1, ("GSS GetMic failed: %s\n", error_string));
+ talloc_free(error_string);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, output_token.length);
+ gss_release_buffer(&min_stat, &output_token);
+ if (sig->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dump_data_pw("gssapi_sign_packet: sig\n", sig->data, sig->length);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS gssapi_check_packet(gss_ctx_id_t gssapi_context,
+ const gss_OID mech,
+ bool hdr_signing,
+ const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ const DATA_BLOB *sig)
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc input_token;
+ gss_buffer_desc input_message;
+ gss_qop_t qop_state;
+
+ dump_data_pw("gssapi_check_packet: sig\n", sig->data, sig->length);
+
+ if (hdr_signing) {
+ input_message.length = pdu_length;
+ input_message.value = discard_const(whole_pdu);
+ } else {
+ input_message.length = length;
+ input_message.value = discard_const(data);
+ }
+
+ input_token.length = sig->length;
+ input_token.value = sig->data;
+
+ maj_stat = gss_verify_mic(&min_stat,
+ gssapi_context,
+ &input_message,
+ &input_token,
+ &qop_state);
+ if (GSS_ERROR(maj_stat)) {
+ char *error_string = gssapi_error_string(NULL,
+ maj_stat,
+ min_stat,
+ mech);
+ DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string));
+ talloc_free(error_string);
+
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/auth/kerberos/gssapi_helper.h b/auth/kerberos/gssapi_helper.h
new file mode 100644
index 00000000000..f40adf1540c
--- /dev/null
+++ b/auth/kerberos/gssapi_helper.h
@@ -0,0 +1,55 @@
+/*
+ Unix SMB/CIFS implementation.
+ GSSAPI helper functions
+
+ Copyright (C) Stefan Metzmacher 2008,2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef AUTH_KERBEROS_GSSAPI_HELPER_H
+#define AUTH_KERBEROS_GSSAPI_HELPER_H 1
+
+size_t gssapi_get_sig_size(gss_ctx_id_t gssapi_context,
+ const gss_OID mech,
+ uint32_t gss_want_flags,
+ size_t data_size);
+NTSTATUS gssapi_seal_packet(gss_ctx_id_t gssapi_context,
+ const gss_OID mech,
+ bool hdr_signing, size_t sig_size,
+ uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *sig);
+NTSTATUS gssapi_unseal_packet(gss_ctx_id_t gssapi_context,
+ const gss_OID mech,
+ bool hdr_signing,
+ uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ const DATA_BLOB *sig);
+NTSTATUS gssapi_sign_packet(gss_ctx_id_t gssapi_context,
+ const gss_OID mech,
+ bool hdr_signing,
+ const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *sig);
+NTSTATUS gssapi_check_packet(gss_ctx_id_t gssapi_context,
+ const gss_OID mech,
+ bool hdr_signing,
+ const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ const DATA_BLOB *sig);
+
+#endif /* AUTH_KERBEROS_GSSAPI_HELPER_H */
diff --git a/auth/kerberos/gssapi_pac.c b/auth/kerberos/gssapi_pac.c
index 99181a13091..c6fa9092080 100644
--- a/auth/kerberos/gssapi_pac.c
+++ b/auth/kerberos/gssapi_pac.c
@@ -54,7 +54,7 @@ const gss_OID_desc * const gss_mech_krb5_wrong = krb5_gss_oid_array+2;
gss_OID_desc gse_sesskey_inq_oid = {
GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH,
- (void *)GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
+ discard_const(GSS_KRB5_INQ_SSPI_SESSION_KEY_OID)
};
#ifndef GSS_KRB5_SESSION_KEY_ENCTYPE_OID
@@ -64,7 +64,7 @@ gss_OID_desc gse_sesskey_inq_oid = {
gss_OID_desc gse_sesskeytype_oid = {
GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
- (void *)GSS_KRB5_SESSION_KEY_ENCTYPE_OID
+ discard_const(GSS_KRB5_SESSION_KEY_ENCTYPE_OID)
};
/* The Heimdal OID for getting the PAC */
@@ -236,7 +236,7 @@ NTSTATUS gssapi_get_session_key(TALLOC_CTX *mem_ctx,
if (keytype) {
int diflen, i;
- const char *p;
+ const uint8_t *p;
if (set->count < 2) {
@@ -266,7 +266,7 @@ NTSTATUS gssapi_get_session_key(TALLOC_CTX *mem_ctx,
gss_maj = gss_release_buffer_set(&gss_min, &set);
return NT_STATUS_OK;
}
- p = (uint8_t *)set->elements[1].value + gse_sesskeytype_oid.length;
+ p = (const uint8_t *)set->elements[1].value + gse_sesskeytype_oid.length;
diflen = set->elements[1].length - gse_sesskeytype_oid.length;
if (diflen <= 0) {
gss_maj = gss_release_buffer_set(&gss_min, &set);
@@ -307,9 +307,17 @@ char *gssapi_error_string(TALLOC_CTX *mem_ctx,
disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat,
GSS_C_GSS_CODE, mech,
&msg_ctx, &maj_error_message);
+ if (disp_maj_stat != 0) {
+ maj_error_message.value = NULL;
+ maj_error_message.length = 0;
+ }
disp_maj_stat = gss_display_status(&disp_min_stat, min_stat,
GSS_C_MECH_CODE, mech,
&msg_ctx, &min_error_message);
+ if (disp_maj_stat != 0) {
+ min_error_message.value = NULL;
+ min_error_message.length = 0;
+ }
maj_error_string = talloc_strndup(mem_ctx,
(char *)maj_error_message.value,
diff --git a/auth/kerberos/wscript_build b/auth/kerberos/wscript_build
index 15b48894770..1fa1b51138d 100755
--- a/auth/kerberos/wscript_build
+++ b/auth/kerberos/wscript_build
@@ -1,5 +1,4 @@
#!/usr/bin/env python
bld.SAMBA_SUBSYSTEM('KRB5_PAC',
- source='gssapi_pac.c kerberos_pac.c',
- allow_warnings=True,
+ source='gssapi_pac.c kerberos_pac.c gssapi_helper.c',
deps='gssapi_krb5 ndr-krb5pac krb5samba')
diff --git a/auth/ntlmssp/gensec_ntlmssp.c b/auth/ntlmssp/gensec_ntlmssp.c
index 567258914af..329d8eb4751 100644
--- a/auth/ntlmssp/gensec_ntlmssp.c
+++ b/auth/ntlmssp/gensec_ntlmssp.c
@@ -105,6 +105,15 @@ bool gensec_ntlmssp_have_feature(struct gensec_security *gensec_security,
if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
return true;
}
+ if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
+ if (!ntlmssp_state->session_key.length) {
+ return false;
+ }
+ if (!(ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) {
+ return false;
+ }
+ return ntlmssp_state->new_spnego;
+ }
return false;
}
diff --git a/auth/ntlmssp/gensec_ntlmssp_server.c b/auth/ntlmssp/gensec_ntlmssp_server.c
index 69c56fbbfbb..6147b140fa5 100644
--- a/auth/ntlmssp/gensec_ntlmssp_server.c
+++ b/auth/ntlmssp/gensec_ntlmssp_server.c
@@ -34,7 +34,7 @@
#include "auth/gensec/gensec_internal.h"
#include "auth/common_auth.h"
#include "param/param.h"
-
+#include "param/loadparm.h"
/**
* Return the credentials of a logged on user, including session keys
@@ -98,6 +98,9 @@ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security)
const char *netbios_domain;
const char *dns_name;
const char *dns_domain;
+ enum server_role role;
+
+ role = lpcfg_server_role(gensec_security->settings->lp_ctx);
nt_status = gensec_ntlmssp_start(gensec_security);
NT_STATUS_NOT_OK_RETURN(nt_status);
@@ -117,13 +120,32 @@ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security)
ntlmssp_state->expected_state = NTLMSSP_NEGOTIATE;
- if (lpcfg_lanman_auth(gensec_security->settings->lp_ctx) &&
+ ntlmssp_state->allow_lm_response =
+ lpcfg_lanman_auth(gensec_security->settings->lp_ctx);
+
+ if (ntlmssp_state->allow_lm_response &&
gensec_setting_bool(gensec_security->settings,
"ntlmssp_server", "allow_lm_key", false))
{
ntlmssp_state->allow_lm_key = true;
}
+ if (lpcfg_map_to_guest(gensec_security->settings->lp_ctx) != NEVER_MAP_TO_GUEST) {
+ /*
+ * map to guest is not secure anyway, so
+ * try to make it work and don't try to
+ * negotiate new_spnego and MIC checking
+ */
+ ntlmssp_state->force_old_spnego = true;
+ }
+
+ if (role == ROLE_ACTIVE_DIRECTORY_DC) {
+ /*
+ * map to guest is not supported on an AD DC.
+ */
+ ntlmssp_state->force_old_spnego = false;
+ }
+
ntlmssp_state->neg_flags =
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_VERSION;
@@ -147,18 +169,31 @@ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security)
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
}
+ if (ntlmssp_state->allow_lm_key) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
+ }
+
if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
}
if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+
+ if (gensec_security->want_features & GENSEC_FEATURE_LDAP_STYLE) {
+ /*
+ * We need to handle NTLMSSP_NEGOTIATE_SIGN as
+ * NTLMSSP_NEGOTIATE_SEAL if GENSEC_FEATURE_LDAP_STYLE
+ * is requested.
+ */
+ ntlmssp_state->force_wrap_seal = true;
+ }
}
if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
}
- if (lpcfg_server_role(gensec_security->settings->lp_ctx) == ROLE_STANDALONE) {
+ if (role == ROLE_STANDALONE) {
ntlmssp_state->server.is_standalone = true;
} else {
ntlmssp_state->server.is_standalone = false;
@@ -215,6 +250,9 @@ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security)
ntlmssp_state->server.dns_domain = talloc_strdup(ntlmssp_state, dns_domain);
NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.dns_domain);
+ ntlmssp_state->neg_flags |= ntlmssp_state->required_flags;
+ ntlmssp_state->conf_flags = ntlmssp_state->neg_flags;
+
return NT_STATUS_OK;
}
diff --git a/auth/ntlmssp/ntlmssp.c b/auth/ntlmssp/ntlmssp.c
index 916b376b111..4abab88627a 100644
--- a/auth/ntlmssp/ntlmssp.c
+++ b/auth/ntlmssp/ntlmssp.c
@@ -48,6 +48,10 @@ static const struct ntlmssp_callbacks {
.command = NTLMSSP_INITIAL,
.sync_fn = ntlmssp_client_initial,
},{
+ .role = NTLMSSP_CLIENT,
+ .command = NTLMSSP_NEGOTIATE,
+ .sync_fn = gensec_ntlmssp_resume_ccache,
+ },{
.role = NTLMSSP_SERVER,
.command = NTLMSSP_NEGOTIATE,
.sync_fn = gensec_ntlmssp_server_negotiate,
@@ -82,6 +86,15 @@ static NTSTATUS gensec_ntlmssp_update_find(struct gensec_security *gensec_securi
if (!input.length) {
switch (gensec_ntlmssp->ntlmssp_state->role) {
case NTLMSSP_CLIENT:
+ if (gensec_ntlmssp->ntlmssp_state->resume_ccache) {
+ /*
+ * make sure gensec_ntlmssp_resume_ccache()
+ * will be called
+ */
+ ntlmssp_command = NTLMSSP_NEGOTIATE;
+ break;
+ }
+
ntlmssp_command = NTLMSSP_INITIAL;
break;
case NTLMSSP_SERVER:
@@ -166,6 +179,30 @@ NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security,
return NT_STATUS_OK;
}
+static NTSTATUS gensec_ntlmssp_may_reset_crypto(struct gensec_security *gensec_security,
+ bool full_reset)
+{
+ struct gensec_ntlmssp_context *gensec_ntlmssp =
+ talloc_get_type_abort(gensec_security->private_data,
+ struct gensec_ntlmssp_context);
+ struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
+ NTSTATUS status;
+ bool reset_seqnums = full_reset;
+
+ if (!gensec_ntlmssp_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+ return NT_STATUS_OK;
+ }
+
+ status = ntlmssp_sign_reset(ntlmssp_state, reset_seqnums);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not reset NTLMSSP signing/sealing system (error was: %s)\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
static const char *gensec_ntlmssp_oids[] = {
GENSEC_OID_NTLMSSP,
NULL
@@ -180,6 +217,7 @@ static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
.server_start = gensec_ntlmssp_server_start,
.magic = gensec_ntlmssp_magic,
.update = gensec_ntlmssp_update,
+ .may_reset_crypto= gensec_ntlmssp_may_reset_crypto,
.sig_size = gensec_ntlmssp_sig_size,
.sign_packet = gensec_ntlmssp_sign_packet,
.check_packet = gensec_ntlmssp_check_packet,
@@ -194,6 +232,15 @@ static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
.priority = GENSEC_NTLMSSP
};
+static const struct gensec_security_ops gensec_ntlmssp_resume_ccache_ops = {
+ .name = "ntlmssp_resume_ccache",
+ .client_start = gensec_ntlmssp_resume_ccache_start,
+ .update = gensec_ntlmssp_update,
+ .session_key = gensec_ntlmssp_session_key,
+ .have_feature = gensec_ntlmssp_have_feature,
+ .enabled = true,
+ .priority = GENSEC_NTLMSSP
+};
_PUBLIC_ NTSTATUS gensec_ntlmssp_init(void)
{
@@ -206,16 +253,58 @@ _PUBLIC_ NTSTATUS gensec_ntlmssp_init(void)
return ret;
}
+ ret = gensec_register(&gensec_ntlmssp_resume_ccache_ops);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(0,("Failed to register '%s' gensec backend!\n",
+ gensec_ntlmssp_resume_ccache_ops.name));
+ return ret;
+ }
+
return ret;
}
+static struct gensec_security *gensec_find_child_by_ops(struct gensec_security *gensec_security,
+ const struct gensec_security_ops *ops)
+{
+ struct gensec_security *current = gensec_security;
+
+ while (current != NULL) {
+ if (current->ops == ops) {
+ return current;
+ }
+
+ current = current->child_security;
+ }
+
+ return NULL;
+}
+
uint32_t gensec_ntlmssp_neg_flags(struct gensec_security *gensec_security)
{
struct gensec_ntlmssp_context *gensec_ntlmssp;
- if (gensec_security->ops != &gensec_ntlmssp_security_ops) {
+
+ gensec_security = gensec_find_child_by_ops(gensec_security,
+ &gensec_ntlmssp_security_ops);
+ if (gensec_security == NULL) {
return 0;
}
+
gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data,
struct gensec_ntlmssp_context);
return gensec_ntlmssp->ntlmssp_state->neg_flags;
}
+
+const char *gensec_ntlmssp_server_domain(struct gensec_security *gensec_security)
+{
+ struct gensec_ntlmssp_context *gensec_ntlmssp;
+
+ gensec_security = gensec_find_child_by_ops(gensec_security,
+ &gensec_ntlmssp_security_ops);
+ if (gensec_security == NULL) {
+ return NULL;
+ }
+
+ gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data,
+ struct gensec_ntlmssp_context);
+ return gensec_ntlmssp->ntlmssp_state->server.netbios_domain;
+}
diff --git a/auth/ntlmssp/ntlmssp.h b/auth/ntlmssp/ntlmssp.h
index 6061cd0951c..24127686312 100644
--- a/auth/ntlmssp/ntlmssp.h
+++ b/auth/ntlmssp/ntlmssp.h
@@ -62,7 +62,9 @@ struct ntlmssp_state
bool unicode;
bool use_ntlmv2;
bool use_ccache;
+ bool resume_ccache;
bool use_nt_response; /* Set to 'False' to debug what happens when the NT response is omited */
+ bool allow_lm_response;/* The LM_RESPONSE code is not very secure... */
bool allow_lm_key; /* The LM_KEY code is not very secure... */
const char *user;
@@ -70,9 +72,15 @@ struct ntlmssp_state
uint8_t *nt_hash;
uint8_t *lm_hash;
+ DATA_BLOB negotiate_blob;
+ DATA_BLOB challenge_blob;
+ bool new_spnego;
+ bool force_old_spnego;
+
struct {
const char *netbios_name;
const char *netbios_domain;
+ struct AV_PAIR_LIST av_pair_list;
} client;
struct {
@@ -81,6 +89,8 @@ struct ntlmssp_state
const char *netbios_domain;
const char *dns_name;
const char *dns_domain;
+ NTTIME challenge_endtime;
+ struct AV_PAIR_LIST av_pair_list;
} server;
DATA_BLOB internal_chal; /* Random challenge as supplied to the client for NTLM authentication */
@@ -90,8 +100,12 @@ struct ntlmssp_state
DATA_BLOB nt_resp;
DATA_BLOB session_key;
+ uint32_t conf_flags;
+ uint32_t required_flags;
uint32_t neg_flags; /* the current state of negotiation with the NTLMSSP partner */
+ bool force_wrap_seal;
+
union ntlmssp_crypt_state *crypt;
};
@@ -123,6 +137,8 @@ NTSTATUS ntlmssp_unwrap(struct ntlmssp_state *ntlmssp_stae,
TALLOC_CTX *out_mem_ctx,
const DATA_BLOB *in,
DATA_BLOB *out);
+NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state,
+ bool reset_seqnums);
NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state);
bool ntlmssp_blob_matches_magic(const DATA_BLOB *blob);
@@ -132,3 +148,4 @@ bool ntlmssp_blob_matches_magic(const DATA_BLOB *blob);
NTSTATUS gensec_ntlmssp_init(void);
uint32_t gensec_ntlmssp_neg_flags(struct gensec_security *gensec_security);
+const char *gensec_ntlmssp_server_domain(struct gensec_security *gensec_security);
diff --git a/auth/ntlmssp/ntlmssp_client.c b/auth/ntlmssp/ntlmssp_client.c
index d8531e4c2e9..b4196157c81 100644
--- a/auth/ntlmssp/ntlmssp_client.c
+++ b/auth/ntlmssp/ntlmssp_client.c
@@ -34,6 +34,7 @@ struct auth_session_info;
#include "auth/ntlmssp/ntlmssp_private.h"
#include "../librpc/gen_ndr/ndr_ntlmssp.h"
#include "../auth/ntlmssp/ntlmssp_ndr.h"
+#include "../nsswitch/libwbclient/wbclient.h"
/*********************************************************************
Client side NTLMSSP
@@ -57,38 +58,18 @@ NTSTATUS ntlmssp_client_initial(struct gensec_security *gensec_security,
talloc_get_type_abort(gensec_security->private_data,
struct gensec_ntlmssp_context);
struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
- const char *domain = ntlmssp_state->client.netbios_domain;
- const char *workstation = ntlmssp_state->client.netbios_name;
NTSTATUS status;
-
- /* These don't really matter in the initial packet, so don't panic if they are not set */
- if (!domain) {
- domain = "";
- }
-
- if (!workstation) {
- workstation = "";
- }
-
- if (ntlmssp_state->unicode) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
- } else {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
- }
-
- if (ntlmssp_state->use_ntlmv2) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
- }
+ const DATA_BLOB version_blob = ntlmssp_version_blob();
/* generate the ntlmssp negotiate packet */
status = msrpc_gen(out_mem_ctx,
- out, "CddAA",
+ out, "CddAAb",
"NTLMSSP",
NTLMSSP_NEGOTIATE,
ntlmssp_state->neg_flags,
- domain,
- workstation);
-
+ "", /* domain */
+ "", /* workstation */
+ version_blob.data, version_blob.length);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("ntlmssp_client_initial: failed to generate "
"ntlmssp negotiate packet\n"));
@@ -109,6 +90,122 @@ NTSTATUS ntlmssp_client_initial(struct gensec_security *gensec_security,
}
}
+ ntlmssp_state->negotiate_blob = data_blob_dup_talloc(ntlmssp_state,
+ *out);
+ if (ntlmssp_state->negotiate_blob.length != out->length) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ntlmssp_state->expected_state = NTLMSSP_CHALLENGE;
+
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS gensec_ntlmssp_resume_ccache(struct gensec_security *gensec_security,
+ TALLOC_CTX *out_mem_ctx,
+ DATA_BLOB in, DATA_BLOB *out)
+{
+ struct gensec_ntlmssp_context *gensec_ntlmssp =
+ talloc_get_type_abort(gensec_security->private_data,
+ struct gensec_ntlmssp_context);
+ struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
+ uint32_t neg_flags = 0;
+ uint32_t ntlmssp_command;
+ NTSTATUS status;
+ bool ok;
+
+ *out = data_blob_null;
+
+ if (in.length == 0) {
+ /*
+ * This is compat code for older callers
+ * which were missing the "initial_blob"/"negotiate_blob".
+ *
+ * That means we can't calculate the NTLMSSP_MIC
+ * field correctly and need to force the
+ * old_spnego behaviour.
+ */
+ DEBUG(10, ("%s: in.length==%u force_old_spnego!\n",
+ __func__, (unsigned int)in.length));
+ ntlmssp_state->force_old_spnego = true;
+ ntlmssp_state->neg_flags |= ntlmssp_state->required_flags;
+ ntlmssp_state->required_flags = 0;
+ ntlmssp_state->expected_state = NTLMSSP_CHALLENGE;
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ /* parse the NTLMSSP packet */
+
+ if (in.length > UINT16_MAX) {
+ DEBUG(1, ("%s: reject large request of length %u\n",
+ __func__, (unsigned int)in.length));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ok = msrpc_parse(ntlmssp_state, &in, "Cdd",
+ "NTLMSSP",
+ &ntlmssp_command,
+ &neg_flags);
+ if (!ok) {
+ DEBUG(1, ("%s: failed to parse NTLMSSP Negotiate of length %u\n",
+ __func__, (unsigned int)in.length));
+ dump_data(2, in.data, in.length);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (ntlmssp_command != NTLMSSP_NEGOTIATE) {
+ DEBUG(1, ("%s: no NTLMSSP Negotiate message (length %u)\n",
+ __func__, (unsigned int)in.length));
+ dump_data(2, in.data, in.length);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ntlmssp_state->neg_flags = neg_flags;
+ DEBUG(3, ("Imported Negotiate flags:\n"));
+ debug_ntlmssp_flags(neg_flags);
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ ntlmssp_state->unicode = true;
+ } else {
+ ntlmssp_state->unicode = false;
+ }
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
+ gensec_security->want_features |= GENSEC_FEATURE_SIGN;
+
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ }
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
+ gensec_security->want_features |= GENSEC_FEATURE_SEAL;
+
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL;
+ }
+
+ ntlmssp_state->neg_flags |= ntlmssp_state->required_flags;
+ ntlmssp_state->conf_flags = ntlmssp_state->neg_flags;
+
+ if (DEBUGLEVEL >= 10) {
+ struct NEGOTIATE_MESSAGE *negotiate = talloc(
+ ntlmssp_state, struct NEGOTIATE_MESSAGE);
+ if (negotiate != NULL) {
+ status = ntlmssp_pull_NEGOTIATE_MESSAGE(
+ &in, negotiate, negotiate);
+ if (NT_STATUS_IS_OK(status)) {
+ NDR_PRINT_DEBUG(NEGOTIATE_MESSAGE,
+ negotiate);
+ }
+ TALLOC_FREE(negotiate);
+ }
+ }
+
+ ntlmssp_state->negotiate_blob = data_blob_dup_talloc(ntlmssp_state,
+ in);
+ if (ntlmssp_state->negotiate_blob.length != in.length) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
ntlmssp_state->expected_state = NTLMSSP_CHALLENGE;
return NT_STATUS_MORE_PROCESSING_REQUIRED;
@@ -147,7 +244,13 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
NTSTATUS nt_status;
int flags = 0;
- const char *user, *domain;
+ const char *user = NULL, *domain = NULL, *workstation = NULL;
+ bool is_anonymous = false;
+ const DATA_BLOB version_blob = ntlmssp_version_blob();
+ const NTTIME *server_timestamp = NULL;
+ uint8_t mic_buffer[NTLMSSP_MIC_SIZE] = { 0, };
+ DATA_BLOB mic_blob = data_blob_const(mic_buffer, sizeof(mic_buffer));
+ HMACMD5Context ctx;
TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx);
if (!mem_ctx) {
@@ -172,7 +275,11 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
DEBUG(3, ("Got challenge flags:\n"));
debug_ntlmssp_flags(chal_flags);
- ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, ntlmssp_state->allow_lm_key);
+ nt_status = ntlmssp_handle_neg_flags(ntlmssp_state,
+ chal_flags, "challenge");
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
if (ntlmssp_state->unicode) {
if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
@@ -181,7 +288,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
chal_parse_string = "CdUdbdd";
chal_parse_string_short = "CdUdb";
}
- auth_gen_string = "CdBBUUUBd";
+ auth_gen_string = "CdBBUUUBdbb";
} else {
if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
chal_parse_string = "CdAdbddB";
@@ -190,7 +297,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
chal_parse_string_short = "CdAdb";
}
- auth_gen_string = "CdBBAAABd";
+ auth_gen_string = "CdBBAAABdbb";
}
if (!msrpc_parse(mem_ctx,
@@ -244,7 +351,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
}
/* TODO: parse struct_blob and fill in the rest */
ntlmssp_state->server.netbios_name = "";
- ntlmssp_state->server.netbios_domain = server_domain;
+ ntlmssp_state->server.netbios_domain = talloc_move(ntlmssp_state, &server_domain);
ntlmssp_state->server.dns_name = "";
ntlmssp_state->server.dns_domain = "";
@@ -253,9 +360,118 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
return NT_STATUS_INVALID_PARAMETER;
}
+ is_anonymous = cli_credentials_is_anonymous(gensec_security->credentials);
cli_credentials_get_ntlm_username_domain(gensec_security->credentials, mem_ctx,
&user, &domain);
+ workstation = cli_credentials_get_workstation(gensec_security->credentials);
+
+ if (user == NULL) {
+ DEBUG(10, ("User is NULL, returning INVALID_PARAMETER\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (domain == NULL) {
+ DEBUG(10, ("Domain is NULL, returning INVALID_PARAMETER\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (workstation == NULL) {
+ DEBUG(10, ("Workstation is NULL, returning INVALID_PARAMETER\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (is_anonymous) {
+ ntlmssp_state->neg_flags |= NTLMSSP_ANONYMOUS;
+ /*
+ * don't use the ccache for anonymous auth
+ */
+ ntlmssp_state->use_ccache = false;
+ }
+ if (ntlmssp_state->use_ccache) {
+ struct samr_Password *nt_hash = NULL;
+
+ /*
+ * If we have a password given we don't
+ * use the ccache
+ */
+ nt_hash = cli_credentials_get_nt_hash(gensec_security->credentials,
+ mem_ctx);
+ if (nt_hash != NULL) {
+ ZERO_STRUCTP(nt_hash);
+ TALLOC_FREE(nt_hash);
+ ntlmssp_state->use_ccache = false;
+ }
+ }
+
+ if (ntlmssp_state->use_ccache) {
+ struct wbcCredentialCacheParams params;
+ struct wbcCredentialCacheInfo *info = NULL;
+ struct wbcAuthErrorInfo *error = NULL;
+ struct wbcNamedBlob auth_blobs[2];
+ const struct wbcBlob *wbc_auth_blob = NULL;
+ const struct wbcBlob *wbc_session_key = NULL;
+ wbcErr wbc_status;
+ int i;
+ bool new_spnego = false;
+
+ params.account_name = user;
+ params.domain_name = domain;
+ params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
+
+ auth_blobs[0].name = "challenge_blob";
+ auth_blobs[0].flags = 0;
+ auth_blobs[0].blob.data = in.data;
+ auth_blobs[0].blob.length = in.length;
+ auth_blobs[1].name = "negotiate_blob";
+ auth_blobs[1].flags = 0;
+ auth_blobs[1].blob.data = ntlmssp_state->negotiate_blob.data;
+ auth_blobs[1].blob.length = ntlmssp_state->negotiate_blob.length;
+ params.num_blobs = ARRAY_SIZE(auth_blobs);
+ params.blobs = auth_blobs;
+
+ wbc_status = wbcCredentialCache(&params, &info, &error);
+ wbcFreeMemory(error);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return NT_STATUS_WRONG_CREDENTIAL_HANDLE;
+ }
+
+ for (i=0; i<info->num_blobs; i++) {
+ if (strequal(info->blobs[i].name, "auth_blob")) {
+ wbc_auth_blob = &info->blobs[i].blob;
+ }
+ if (strequal(info->blobs[i].name, "session_key")) {
+ wbc_session_key = &info->blobs[i].blob;
+ }
+ if (strequal(info->blobs[i].name, "new_spnego")) {
+ new_spnego = true;
+ }
+ }
+ if ((wbc_auth_blob == NULL) || (wbc_session_key == NULL)) {
+ wbcFreeMemory(info);
+ return NT_STATUS_WRONG_CREDENTIAL_HANDLE;
+ }
+
+ session_key = data_blob_talloc(mem_ctx,
+ wbc_session_key->data,
+ wbc_session_key->length);
+ if (session_key.length != wbc_session_key->length) {
+ wbcFreeMemory(info);
+ return NT_STATUS_NO_MEMORY;
+ }
+ *out = data_blob_talloc(mem_ctx,
+ wbc_auth_blob->data,
+ wbc_auth_blob->length);
+ if (out->length != wbc_auth_blob->length) {
+ wbcFreeMemory(info);
+ return NT_STATUS_NO_MEMORY;
+ }
+ ntlmssp_state->new_spnego = new_spnego;
+
+ wbcFreeMemory(info);
+ goto done;
+ }
+
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
flags |= CLI_CRED_NTLM2;
}
@@ -265,15 +481,159 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
if (ntlmssp_state->use_nt_response) {
flags |= CLI_CRED_NTLM_AUTH;
}
- if (lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx)) {
+ if (ntlmssp_state->allow_lm_response) {
flags |= CLI_CRED_LANMAN_AUTH;
}
+ if (target_info.length != 0 && !is_anonymous) {
+ struct AV_PAIR *pairs = NULL;
+ uint32_t count = 0;
+ enum ndr_err_code err;
+ struct AV_PAIR *timestamp = NULL;
+ struct AV_PAIR *eol = NULL;
+ uint32_t i = 0;
+ const char *service = NULL;
+ const char *hostname = NULL;
+
+ err = ndr_pull_struct_blob(&target_info,
+ ntlmssp_state,
+ &ntlmssp_state->server.av_pair_list,
+ (ndr_pull_flags_fn_t)ndr_pull_AV_PAIR_LIST);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ return ndr_map_error2ntstatus(err);
+ }
+
+ count = ntlmssp_state->server.av_pair_list.count;
+ /*
+ * We need room for Flags, SingleHost,
+ * ChannelBindings and Target
+ */
+ pairs = talloc_zero_array(ntlmssp_state, struct AV_PAIR,
+ count + 4);
+ if (pairs == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < count; i++) {
+ pairs[i] = ntlmssp_state->server.av_pair_list.pair[i];
+ }
+
+ ntlmssp_state->client.av_pair_list.count = count;
+ ntlmssp_state->client.av_pair_list.pair = pairs;
+
+ eol = ndr_ntlmssp_find_av(&ntlmssp_state->client.av_pair_list,
+ MsvAvEOL);
+ if (eol == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ timestamp = ndr_ntlmssp_find_av(&ntlmssp_state->client.av_pair_list,
+ MsvAvTimestamp);
+ if (timestamp != NULL) {
+ uint32_t sign_features =
+ GENSEC_FEATURE_SESSION_KEY |
+ GENSEC_FEATURE_SIGN |
+ GENSEC_FEATURE_SEAL;
+
+ server_timestamp = &timestamp->Value.AvTimestamp;
+
+ if (ntlmssp_state->force_old_spnego) {
+ sign_features = 0;
+ }
+
+ if (gensec_security->want_features & sign_features) {
+ struct AV_PAIR *av_flags = NULL;
+
+ av_flags = ndr_ntlmssp_find_av(&ntlmssp_state->client.av_pair_list,
+ MsvAvFlags);
+ if (av_flags == NULL) {
+ av_flags = eol;
+ eol++;
+ count++;
+ *eol = *av_flags;
+ av_flags->AvId = MsvAvFlags;
+ av_flags->Value.AvFlags = 0;
+ }
+
+ av_flags->Value.AvFlags |= NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE;
+ ntlmssp_state->new_spnego = true;
+ }
+ }
+
+ {
+ struct AV_PAIR *SingleHost = NULL;
+
+ SingleHost = eol;
+ eol++;
+ count++;
+ *eol = *SingleHost;
+
+ /*
+ * This is not really used, but we want to
+ * add some more random bytes and match
+ * Windows.
+ */
+ SingleHost->AvId = MsvAvSingleHost;
+ SingleHost->Value.AvSingleHost.token_info.Flags = 0;
+ SingleHost->Value.AvSingleHost.token_info.TokenIL = 0;
+ generate_random_buffer(SingleHost->Value.AvSingleHost.token_info.MachineId,
+ sizeof(SingleHost->Value.AvSingleHost.token_info.MachineId));
+ SingleHost->Value.AvSingleHost.remaining = data_blob_null;
+ }
+
+ {
+ struct AV_PAIR *ChannelBindings = NULL;
+
+ ChannelBindings = eol;
+ eol++;
+ count++;
+ *eol = *ChannelBindings;
+
+ /*
+ * gensec doesn't support channel bindings yet,
+ * but we want to match Windows on the wire
+ */
+ ChannelBindings->AvId = MsvChannelBindings;
+ memset(ChannelBindings->Value.ChannelBindings, 0,
+ sizeof(ChannelBindings->Value.ChannelBindings));
+ }
+
+ service = gensec_get_target_service(gensec_security);
+ hostname = gensec_get_target_hostname(gensec_security);
+ if (service != NULL && hostname != NULL) {
+ struct AV_PAIR *target = NULL;
+
+ target = eol;
+ eol++;
+ count++;
+ *eol = *target;
+
+ target->AvId = MsvAvTargetName;
+ target->Value.AvTargetName = talloc_asprintf(pairs, "%s/%s",
+ service,
+ hostname);
+ if (target->Value.AvTargetName == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ ntlmssp_state->client.av_pair_list.count = count;
+ ntlmssp_state->client.av_pair_list.pair = pairs;
+
+ err = ndr_push_struct_blob(&target_info,
+ ntlmssp_state,
+ &ntlmssp_state->client.av_pair_list,
+ (ndr_push_flags_fn_t)ndr_push_AV_PAIR_LIST);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
nt_status = cli_credentials_get_ntlm_response(gensec_security->credentials, mem_ctx,
- &flags, challenge_blob, target_info,
+ &flags, challenge_blob,
+ server_timestamp, target_info,
&lm_response, &nt_response,
&lm_session_key, &session_key);
-
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
@@ -292,7 +652,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
}
if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
- && lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx) && lm_session_key.length == 16) {
+ && ntlmssp_state->allow_lm_key && lm_session_key.length == 16) {
DATA_BLOB new_session_key = data_blob_talloc(mem_ctx, NULL, 16);
if (lm_response.length == 24) {
SMBsesskeygen_lm_sess_key(lm_session_key.data, lm_response.data,
@@ -325,9 +685,6 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
session_key = data_blob_talloc(mem_ctx, client_session_key, sizeof(client_session_key));
}
- DEBUG(3, ("NTLMSSP: Set final flags:\n"));
- debug_ntlmssp_flags(ntlmssp_state->neg_flags);
-
/* this generates the actual auth packet */
nt_status = msrpc_gen(mem_ctx,
out, auth_gen_string,
@@ -337,22 +694,48 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
nt_response.data, nt_response.length,
domain,
user,
- cli_credentials_get_workstation(gensec_security->credentials),
+ workstation,
encrypted_session_key.data, encrypted_session_key.length,
- ntlmssp_state->neg_flags);
+ ntlmssp_state->neg_flags,
+ version_blob.data, version_blob.length,
+ mic_blob.data, mic_blob.length);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(mem_ctx);
return nt_status;
}
+ /*
+ * We always include the MIC, even without:
+ * av_flags->Value.AvFlags |= NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE;
+ * ntlmssp_state->new_spnego = true;
+ *
+ * This matches a Windows client.
+ */
+ hmac_md5_init_limK_to_64(session_key.data,
+ session_key.length,
+ &ctx);
+ hmac_md5_update(ntlmssp_state->negotiate_blob.data,
+ ntlmssp_state->negotiate_blob.length,
+ &ctx);
+ hmac_md5_update(in.data, in.length, &ctx);
+ hmac_md5_update(out->data, out->length, &ctx);
+ hmac_md5_final(mic_buffer, &ctx);
+ memcpy(out->data + NTLMSSP_MIC_OFFSET, mic_buffer, NTLMSSP_MIC_SIZE);
+
+done:
+ data_blob_free(&ntlmssp_state->negotiate_blob);
+
ntlmssp_state->session_key = session_key;
talloc_steal(ntlmssp_state, session_key.data);
+ DEBUG(3, ("NTLMSSP: Set final flags:\n"));
+ debug_ntlmssp_flags(ntlmssp_state->neg_flags);
+
talloc_steal(out_mem_ctx, out->data);
ntlmssp_state->expected_state = NTLMSSP_DONE;
- if (gensec_security->want_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL)) {
+ if (gensec_ntlmssp_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
nt_status = ntlmssp_sign_init(ntlmssp_state);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n",
@@ -398,7 +781,9 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
ntlmssp_state->use_nt_response = gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "send_nt_reponse", true);
- ntlmssp_state->allow_lm_key = (lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx)
+ ntlmssp_state->allow_lm_response = lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx);
+
+ ntlmssp_state->allow_lm_key = (ntlmssp_state->allow_lm_response
&& (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "allow_lm_key", false)
|| gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "lm_key", false)));
@@ -408,8 +793,15 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
ntlmssp_state->neg_flags =
NTLMSSP_NEGOTIATE_NTLM |
+ NTLMSSP_NEGOTIATE_VERSION |
NTLMSSP_REQUEST_TARGET;
+ if (ntlmssp_state->unicode) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+ } else {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
+ }
+
if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "128bit", true)) {
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_128;
}
@@ -437,6 +829,16 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
ntlmssp_state->use_ntlmv2 = false;
}
+ if (ntlmssp_state->use_ntlmv2) {
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_NTLM2;
+ ntlmssp_state->allow_lm_response = false;
+ ntlmssp_state->allow_lm_key = false;
+ }
+
+ if (ntlmssp_state->allow_lm_key) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
+ }
+
if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
/*
* We need to set this to allow a later SetPassword
@@ -447,15 +849,57 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
* that it thinks is only used for NTLMSSP signing and
* sealing. (It is actually pulled out and used directly)
*/
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
}
if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
+
+ if (gensec_security->want_features & GENSEC_FEATURE_LDAP_STYLE) {
+ /*
+ * We need to handle NTLMSSP_NEGOTIATE_SIGN as
+ * NTLMSSP_NEGOTIATE_SEAL if GENSEC_FEATURE_LDAP_STYLE
+ * is requested.
+ */
+ ntlmssp_state->force_wrap_seal = true;
+ /*
+ * We want also work against old Samba servers
+ * which didn't had GENSEC_FEATURE_LDAP_STYLE
+ * we negotiate SEAL too. We may remove this
+ * in a few years. As all servers should have
+ * GENSEC_FEATURE_LDAP_STYLE by then.
+ */
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL;
+ }
}
if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL;
+ }
+ if (gensec_security->want_features & GENSEC_FEATURE_NTLM_CCACHE) {
+ ntlmssp_state->use_ccache = true;
}
+ ntlmssp_state->neg_flags |= ntlmssp_state->required_flags;
+ ntlmssp_state->conf_flags = ntlmssp_state->neg_flags;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS gensec_ntlmssp_resume_ccache_start(struct gensec_security *gensec_security)
+{
+ struct gensec_ntlmssp_context *gensec_ntlmssp = NULL;
+ NTSTATUS status;
+
+ status = gensec_ntlmssp_client_start(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data,
+ struct gensec_ntlmssp_context);
+ gensec_ntlmssp->ntlmssp_state->use_ccache = false;
+ gensec_ntlmssp->ntlmssp_state->resume_ccache = true;
+ gensec_ntlmssp->ntlmssp_state->expected_state = NTLMSSP_NEGOTIATE;
+
return NT_STATUS_OK;
}
diff --git a/auth/ntlmssp/ntlmssp_ndr.c b/auth/ntlmssp/ntlmssp_ndr.c
index af24be9dc22..c8b16ccd413 100644
--- a/auth/ntlmssp/ntlmssp_ndr.c
+++ b/auth/ntlmssp/ntlmssp_ndr.c
@@ -25,6 +25,7 @@
#define NTLMSSP_PULL_MESSAGE(type, blob, mem_ctx, r) \
do { \
enum ndr_err_code __ndr_err; \
+ ZERO_STRUCTP(r); /* in order to deal with unset neg flags */\
__ndr_err = ndr_pull_struct_blob(blob, mem_ctx, r, \
(ndr_pull_flags_fn_t)ndr_pull_ ##type); \
if (!NDR_ERR_CODE_IS_SUCCESS(__ndr_err)) { \
diff --git a/auth/ntlmssp/ntlmssp_private.h b/auth/ntlmssp/ntlmssp_private.h
index 778d638b2ad..e938e5cad8f 100644
--- a/auth/ntlmssp/ntlmssp_private.h
+++ b/auth/ntlmssp/ntlmssp_private.h
@@ -59,8 +59,9 @@ NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security,
/* The following definitions come from auth/ntlmssp_util.c */
void debug_ntlmssp_flags(uint32_t neg_flags);
-void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
- uint32_t neg_flags, bool allow_lm);
+NTSTATUS ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
+ uint32_t neg_flags, const char *name);
+const DATA_BLOB ntlmssp_version_blob(void);
/* The following definitions come from auth/ntlmssp_server.c */
@@ -88,6 +89,10 @@ NTSTATUS ntlmssp_client_initial(struct gensec_security *gensec_security,
TALLOC_CTX *out_mem_ctx,
DATA_BLOB in, DATA_BLOB *out) ;
+NTSTATUS gensec_ntlmssp_resume_ccache(struct gensec_security *gensec_security,
+ TALLOC_CTX *out_mem_ctx,
+ DATA_BLOB in, DATA_BLOB *out);
+
/**
* Next state function for the Challenge Packet. Generate an auth packet.
*
@@ -101,6 +106,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
TALLOC_CTX *out_mem_ctx,
const DATA_BLOB in, DATA_BLOB *out) ;
NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security);
+NTSTATUS gensec_ntlmssp_resume_ccache_start(struct gensec_security *gensec_security);
/* The following definitions come from auth/ntlmssp/gensec_ntlmssp_server.c */
diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c
index 2f3f0bb723f..954964196d1 100644
--- a/auth/ntlmssp/ntlmssp_server.c
+++ b/auth/ntlmssp/ntlmssp_server.c
@@ -21,6 +21,7 @@
*/
#include "includes.h"
+#include "lib/util/time_basic.h"
#include "auth/ntlmssp/ntlmssp.h"
#include "auth/ntlmssp/ntlmssp_private.h"
#include "../librpc/gen_ndr/ndr_ntlmssp.h"
@@ -84,6 +85,27 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security
uint8_t cryptkey[8];
const char *target_name;
NTSTATUS status;
+ struct timeval tv_now = timeval_current();
+ /*
+ * See [MS-NLMP]
+ *
+ * Windows NT 4.0, windows_2000: use 30 minutes,
+ * Windows XP, Windows Server 2003, Windows Vista,
+ * Windows Server 2008, Windows 7, and Windows Server 2008 R2
+ * use 36 hours.
+ *
+ * Newer systems doesn't check this, likely because the
+ * connectionless NTLMSSP is no longer supported.
+ *
+ * As we expect the AUTHENTICATION_MESSAGE to arrive
+ * directly after the NEGOTIATE_MESSAGE (typically less than
+ * as 1 second later). We use a hard timeout of 30 Minutes.
+ *
+ * We don't look at AUTHENTICATE_MESSAGE.NtChallengeResponse.TimeStamp
+ * instead we just remember our own time.
+ */
+ uint32_t max_lifetime = 30 * 60;
+ struct timeval tv_end = timeval_add(&tv_now, max_lifetime, 0);
/* parse the NTLMSSP packet */
#if 0
@@ -91,6 +113,12 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security
#endif
if (request.length) {
+ if (request.length > UINT16_MAX) {
+ DEBUG(1, ("ntlmssp_server_negotiate: reject large request of length %u\n",
+ (unsigned int)request.length));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
if ((request.length < 16) || !msrpc_parse(ntlmssp_state, &request, "Cdd",
"NTLMSSP",
&ntlmssp_command,
@@ -117,7 +145,10 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security
}
}
- ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, ntlmssp_state->allow_lm_key);
+ status = ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, "negotiate");
+ if (!NT_STATUS_IS_OK(status)){
+ return status;
+ }
/* Ask our caller what challenge they would like in the packet */
if (auth_context->get_ntlm_challenge) {
@@ -138,6 +169,7 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security
*/
chal_flags = ntlmssp_state->neg_flags;
+ ntlmssp_state->server.challenge_endtime = timeval_to_nttime(&tv_end);
/* get the right name to fill in as 'target' */
target_name = ntlmssp_target_name(ntlmssp_state,
@@ -150,16 +182,48 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security
cryptkey, 8);
/* This creates the 'blob' of names that appears at the end of the packet */
- if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO)
- {
- status = msrpc_gen(ntlmssp_state, &struct_blob, "aaaaa",
- MsvAvNbDomainName, target_name,
- MsvAvNbComputerName, ntlmssp_state->server.netbios_name,
- MsvAvDnsDomainName, ntlmssp_state->server.dns_domain,
- MsvAvDnsComputerName, ntlmssp_state->server.dns_name,
- MsvAvEOL, "");
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
+ enum ndr_err_code err;
+ struct AV_PAIR *pairs = NULL;
+ uint32_t count = 5;
+
+ pairs = talloc_zero_array(ntlmssp_state, struct AV_PAIR, count + 1);
+ if (pairs == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ pairs[0].AvId = MsvAvNbDomainName;
+ pairs[0].Value.AvNbDomainName = target_name;
+
+ pairs[1].AvId = MsvAvNbComputerName;
+ pairs[1].Value.AvNbComputerName = ntlmssp_state->server.netbios_name;
+
+ pairs[2].AvId = MsvAvDnsDomainName;
+ pairs[2].Value.AvDnsDomainName = ntlmssp_state->server.dns_domain;
+
+ pairs[3].AvId = MsvAvDnsComputerName;
+ pairs[3].Value.AvDnsComputerName= ntlmssp_state->server.dns_name;
+
+ if (!ntlmssp_state->force_old_spnego) {
+ pairs[4].AvId = MsvAvTimestamp;
+ pairs[4].Value.AvTimestamp =
+ timeval_to_nttime(&tv_now);
+ count += 1;
+
+ pairs[5].AvId = MsvAvEOL;
+ } else {
+ pairs[4].AvId = MsvAvEOL;
+ }
+
+ ntlmssp_state->server.av_pair_list.count = count;
+ ntlmssp_state->server.av_pair_list.pair = pairs;
+
+ err = ndr_push_struct_blob(&struct_blob,
+ ntlmssp_state,
+ &ntlmssp_state->server.av_pair_list,
+ (ndr_push_flags_fn_t)ndr_push_AV_PAIR_LIST);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ return NT_STATUS_NO_MEMORY;
}
} else {
struct_blob = data_blob_null;
@@ -168,29 +232,7 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security
{
/* Marshal the packet in the right format, be it unicode or ASCII */
const char *gen_string;
- DATA_BLOB version_blob = data_blob_null;
-
- if (chal_flags & NTLMSSP_NEGOTIATE_VERSION) {
- enum ndr_err_code err;
- struct ntlmssp_VERSION vers;
-
- /* "What Windows returns" as a version number. */
- ZERO_STRUCT(vers);
- vers.ProductMajorVersion = NTLMSSP_WINDOWS_MAJOR_VERSION_6;
- vers.ProductMinorVersion = NTLMSSP_WINDOWS_MINOR_VERSION_1;
- vers.ProductBuild = 0;
- vers.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
-
- err = ndr_push_struct_blob(&version_blob,
- ntlmssp_state,
- &vers,
- (ndr_push_flags_fn_t)ndr_push_ntlmssp_VERSION);
-
- if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
- data_blob_free(&struct_blob);
- return NT_STATUS_NO_MEMORY;
- }
- }
+ const DATA_BLOB version_blob = ntlmssp_version_blob();
if (ntlmssp_state->unicode) {
gen_string = "CdUdbddBb";
@@ -209,13 +251,10 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security
version_blob.data, version_blob.length);
if (!NT_STATUS_IS_OK(status)) {
- data_blob_free(&version_blob);
data_blob_free(&struct_blob);
return status;
}
- data_blob_free(&version_blob);
-
if (DEBUGLEVEL >= 10) {
struct CHALLENGE_MESSAGE *challenge = talloc(
ntlmssp_state, struct CHALLENGE_MESSAGE);
@@ -234,6 +273,18 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security
data_blob_free(&struct_blob);
+ ntlmssp_state->negotiate_blob = data_blob_dup_talloc(ntlmssp_state,
+ request);
+ if (ntlmssp_state->negotiate_blob.length != request.length) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ntlmssp_state->challenge_blob = data_blob_dup_talloc(ntlmssp_state,
+ *reply);
+ if (ntlmssp_state->challenge_blob.length != reply->length) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
ntlmssp_state->expected_state = NTLMSSP_AUTH;
return NT_STATUS_MORE_PROCESSING_REQUIRED;
@@ -266,19 +317,24 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
struct auth4_context *auth_context = gensec_security->auth_context;
uint32_t ntlmssp_command, auth_flags;
NTSTATUS nt_status;
-
+ const unsigned int version_len = 8;
+ DATA_BLOB version_blob = data_blob_null;
+ const unsigned int mic_len = NTLMSSP_MIC_SIZE;
+ DATA_BLOB mic_blob = data_blob_null;
uint8_t session_nonce_hash[16];
-
const char *parse_string;
+ bool ok;
+ struct timeval endtime;
+ bool expired = false;
#if 0
file_save("ntlmssp_auth.dat", request.data, request.length);
#endif
if (ntlmssp_state->unicode) {
- parse_string = "CdBBUUUBd";
+ parse_string = "CdBBUUUBdbb";
} else {
- parse_string = "CdBBAAABd";
+ parse_string = "CdBBAAABdbb";
}
/* zero these out */
@@ -291,7 +347,7 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
ntlmssp_state->client.netbios_name = NULL;
/* now the NTLMSSP encoded auth hashes */
- if (!msrpc_parse(ntlmssp_state, &request, parse_string,
+ ok = msrpc_parse(ntlmssp_state, &request, parse_string,
"NTLMSSP",
&ntlmssp_command,
&ntlmssp_state->lm_resp,
@@ -300,7 +356,35 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
&ntlmssp_state->user,
&ntlmssp_state->client.netbios_name,
&state->encrypted_session_key,
- &auth_flags)) {
+ &auth_flags,
+ &version_blob, version_len,
+ &mic_blob, mic_len);
+ if (!ok) {
+ DEBUG(10, ("ntlmssp_server_auth: failed to parse NTLMSSP (nonfatal):\n"));
+ dump_data(10, request.data, request.length);
+
+ data_blob_free(&version_blob);
+ data_blob_free(&mic_blob);
+
+ if (ntlmssp_state->unicode) {
+ parse_string = "CdBBUUUBd";
+ } else {
+ parse_string = "CdBBAAABd";
+ }
+
+ ok = msrpc_parse(ntlmssp_state, &request, parse_string,
+ "NTLMSSP",
+ &ntlmssp_command,
+ &ntlmssp_state->lm_resp,
+ &ntlmssp_state->nt_resp,
+ &ntlmssp_state->domain,
+ &ntlmssp_state->user,
+ &ntlmssp_state->client.netbios_name,
+ &state->encrypted_session_key,
+ &auth_flags);
+ }
+
+ if (!ok) {
DEBUG(10, ("ntlmssp_server_auth: failed to parse NTLMSSP (nonfatal):\n"));
dump_data(10, request.data, request.length);
@@ -333,8 +417,14 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
talloc_steal(state, state->encrypted_session_key.data);
- if (auth_flags)
- ntlmssp_handle_neg_flags(ntlmssp_state, auth_flags, ntlmssp_state->allow_lm_key);
+ if (auth_flags != 0) {
+ nt_status = ntlmssp_handle_neg_flags(ntlmssp_state,
+ auth_flags,
+ "authenticate");
+ if (!NT_STATUS_IS_OK(nt_status)){
+ return nt_status;
+ }
+ }
if (DEBUGLEVEL >= 10) {
struct AUTHENTICATE_MESSAGE *authenticate = talloc(
@@ -363,6 +453,192 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
file_save("lmhash1.dat", &ntlmssp_state->lm_resp.data, &ntlmssp_state->lm_resp.length);
#endif
+ if (ntlmssp_state->nt_resp.length > 24) {
+ struct NTLMv2_RESPONSE v2_resp;
+ enum ndr_err_code err;
+ uint32_t i = 0;
+ uint32_t count = 0;
+ const struct AV_PAIR *flags = NULL;
+ const struct AV_PAIR *eol = NULL;
+ uint32_t av_flags = 0;
+
+ err = ndr_pull_struct_blob(&ntlmssp_state->nt_resp,
+ ntlmssp_state,
+ &v2_resp,
+ (ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ nt_status = ndr_map_error2ntstatus(err);
+ DEBUG(1,("%s: failed to parse NTLMv2_RESPONSE of length %zu for "
+ "user=[%s] domain=[%s] workstation=[%s] - %s %s\n",
+ __func__, ntlmssp_state->nt_resp.length,
+ ntlmssp_state->user, ntlmssp_state->domain,
+ ntlmssp_state->client.netbios_name,
+ ndr_errstr(err), nt_errstr(nt_status)));
+ return nt_status;
+ }
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &v2_resp);
+ }
+
+ eol = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
+ MsvAvEOL);
+ if (eol == NULL) {
+ DEBUG(1,("%s: missing MsvAvEOL for "
+ "user=[%s] domain=[%s] workstation=[%s]\n",
+ __func__, ntlmssp_state->user, ntlmssp_state->domain,
+ ntlmssp_state->client.netbios_name));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ flags = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
+ MsvAvFlags);
+ if (flags != NULL) {
+ av_flags = flags->Value.AvFlags;
+ }
+
+ if (av_flags & NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE) {
+ if (mic_blob.length != NTLMSSP_MIC_SIZE) {
+ DEBUG(1,("%s: mic_blob.length[%u] for "
+ "user=[%s] domain=[%s] workstation=[%s]\n",
+ __func__,
+ (unsigned)mic_blob.length,
+ ntlmssp_state->user,
+ ntlmssp_state->domain,
+ ntlmssp_state->client.netbios_name));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (request.length <
+ (NTLMSSP_MIC_OFFSET + NTLMSSP_MIC_SIZE))
+ {
+ DEBUG(1,("%s: missing MIC "
+ "request.length[%u] for "
+ "user=[%s] domain=[%s] workstation=[%s]\n",
+ __func__,
+ (unsigned)request.length,
+ ntlmssp_state->user,
+ ntlmssp_state->domain,
+ ntlmssp_state->client.netbios_name));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ntlmssp_state->new_spnego = true;
+ }
+
+ count = ntlmssp_state->server.av_pair_list.count;
+ if (v2_resp.Challenge.AvPairs.count < count) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ for (i = 0; i < count; i++) {
+ const struct AV_PAIR *sp =
+ &ntlmssp_state->server.av_pair_list.pair[i];
+ const struct AV_PAIR *cp = NULL;
+
+ if (sp->AvId == MsvAvEOL) {
+ continue;
+ }
+
+ cp = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
+ sp->AvId);
+ if (cp == NULL) {
+ DEBUG(1,("%s: AvId 0x%x missing for"
+ "user=[%s] domain=[%s] "
+ "workstation=[%s]\n",
+ __func__,
+ (unsigned)sp->AvId,
+ ntlmssp_state->user,
+ ntlmssp_state->domain,
+ ntlmssp_state->client.netbios_name));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ switch (cp->AvId) {
+#define CASE_STRING(v) case Msv ## v: do { \
+ int cmp; \
+ if (sp->Value.v == NULL) { \
+ return NT_STATUS_INTERNAL_ERROR; \
+ } \
+ if (cp->Value.v == NULL) { \
+ DEBUG(1,("%s: invalid %s " \
+ "got[%s] expect[%s] for " \
+ "user=[%s] domain=[%s] workstation=[%s]\n", \
+ __func__, #v, \
+ cp->Value.v, \
+ sp->Value.v, \
+ ntlmssp_state->user, \
+ ntlmssp_state->domain, \
+ ntlmssp_state->client.netbios_name)); \
+ return NT_STATUS_INVALID_PARAMETER; \
+ } \
+ cmp = strcmp(cp->Value.v, sp->Value.v); \
+ if (cmp != 0) { \
+ DEBUG(1,("%s: invalid %s " \
+ "got[%s] expect[%s] for " \
+ "user=[%s] domain=[%s] workstation=[%s]\n", \
+ __func__, #v, \
+ cp->Value.v, \
+ sp->Value.v, \
+ ntlmssp_state->user, \
+ ntlmssp_state->domain, \
+ ntlmssp_state->client.netbios_name)); \
+ return NT_STATUS_INVALID_PARAMETER; \
+ } \
+} while(0); break
+ CASE_STRING(AvNbComputerName);
+ CASE_STRING(AvNbDomainName);
+ CASE_STRING(AvDnsComputerName);
+ CASE_STRING(AvDnsDomainName);
+ CASE_STRING(AvDnsTreeName);
+ case MsvAvTimestamp:
+ if (cp->Value.AvTimestamp != sp->Value.AvTimestamp) {
+ struct timeval ct;
+ struct timeval st;
+ struct timeval_buf tmp1;
+ struct timeval_buf tmp2;
+
+ nttime_to_timeval(&ct,
+ cp->Value.AvTimestamp);
+ nttime_to_timeval(&st,
+ sp->Value.AvTimestamp);
+
+ DEBUG(1,("%s: invalid AvTimestamp "
+ "got[%s] expect[%s] for "
+ "user=[%s] domain=[%s] "
+ "workstation=[%s]\n",
+ __func__,
+ timeval_str_buf(&ct, true, &tmp1),
+ timeval_str_buf(&st, true, &tmp2),
+ ntlmssp_state->user,
+ ntlmssp_state->domain,
+ ntlmssp_state->client.netbios_name));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ break;
+ default:
+ /*
+ * This can't happen as we control
+ * ntlmssp_state->server.av_pair_list
+ */
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ }
+ }
+
+ nttime_to_timeval(&endtime, ntlmssp_state->server.challenge_endtime);
+ expired = timeval_expired(&endtime);
+ if (expired) {
+ struct timeval_buf tmp;
+ DEBUG(1,("%s: challenge invalid (expired %s) for "
+ "user=[%s] domain=[%s] workstation=[%s]\n",
+ __func__,
+ timeval_str_buf(&endtime, true, &tmp),
+ ntlmssp_state->user, ntlmssp_state->domain,
+ ntlmssp_state->client.netbios_name));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
/* NTLM2 uses a 'challenge' that is made of up both the server challenge, and a
client challenge
@@ -474,7 +750,8 @@ static NTSTATUS ntlmssp_server_check_password(struct gensec_security *gensec_sec
static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security,
struct gensec_ntlmssp_context *gensec_ntlmssp,
- struct ntlmssp_server_auth_state *state)
+ struct ntlmssp_server_auth_state *state,
+ DATA_BLOB request)
{
struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
DATA_BLOB user_session_key = state->user_session_key;
@@ -591,7 +868,56 @@ static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security,
talloc_steal(ntlmssp_state, session_key.data);
}
- if (ntlmssp_state->session_key.length) {
+ if (ntlmssp_state->new_spnego) {
+ HMACMD5Context ctx;
+ uint8_t mic_buffer[NTLMSSP_MIC_SIZE] = { 0, };
+ int cmp;
+
+ hmac_md5_init_limK_to_64(ntlmssp_state->session_key.data,
+ ntlmssp_state->session_key.length,
+ &ctx);
+
+ hmac_md5_update(ntlmssp_state->negotiate_blob.data,
+ ntlmssp_state->negotiate_blob.length,
+ &ctx);
+ hmac_md5_update(ntlmssp_state->challenge_blob.data,
+ ntlmssp_state->challenge_blob.length,
+ &ctx);
+
+ /* checked were we set ntlmssp_state->new_spnego */
+ SMB_ASSERT(request.length >
+ (NTLMSSP_MIC_OFFSET + NTLMSSP_MIC_SIZE));
+
+ hmac_md5_update(request.data, NTLMSSP_MIC_OFFSET, &ctx);
+ hmac_md5_update(mic_buffer, NTLMSSP_MIC_SIZE, &ctx);
+ hmac_md5_update(request.data +
+ (NTLMSSP_MIC_OFFSET + NTLMSSP_MIC_SIZE),
+ request.length -
+ (NTLMSSP_MIC_OFFSET + NTLMSSP_MIC_SIZE),
+ &ctx);
+ hmac_md5_final(mic_buffer, &ctx);
+
+ cmp = memcmp(request.data + NTLMSSP_MIC_OFFSET,
+ mic_buffer, NTLMSSP_MIC_SIZE);
+ if (cmp != 0) {
+ DEBUG(1,("%s: invalid NTLMSSP_MIC for "
+ "user=[%s] domain=[%s] workstation=[%s]\n",
+ __func__,
+ ntlmssp_state->user,
+ ntlmssp_state->domain,
+ ntlmssp_state->client.netbios_name));
+ dump_data(1, request.data + NTLMSSP_MIC_OFFSET,
+ NTLMSSP_MIC_SIZE);
+ dump_data(1, mic_buffer,
+ NTLMSSP_MIC_SIZE);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ data_blob_free(&ntlmssp_state->negotiate_blob);
+ data_blob_free(&ntlmssp_state->challenge_blob);
+
+ if (gensec_ntlmssp_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
nt_status = ntlmssp_sign_init(ntlmssp_state);
}
@@ -656,7 +982,7 @@ NTSTATUS gensec_ntlmssp_server_auth(struct gensec_security *gensec_security,
ntlmssp_state->check_password, the ntlmssp_server_postpath
can be done in a callback */
- nt_status = ntlmssp_server_postauth(gensec_security, gensec_ntlmssp, state);
+ nt_status = ntlmssp_server_postauth(gensec_security, gensec_ntlmssp, state, in);
TALLOC_FREE(state);
return nt_status;
}
diff --git a/auth/ntlmssp/ntlmssp_sign.c b/auth/ntlmssp/ntlmssp_sign.c
index c0be91465b3..a9757258803 100644
--- a/auth/ntlmssp/ntlmssp_sign.c
+++ b/auth/ntlmssp/ntlmssp_sign.c
@@ -479,57 +479,18 @@ NTSTATUS ntlmssp_unwrap(struct ntlmssp_state *ntlmssp_state,
&sig);
} else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
- NTSTATUS status;
- struct ntlmssp_crypt_direction save_direction;
-
if (in->length < NTLMSSP_SIG_SIZE) {
return NT_STATUS_INVALID_PARAMETER;
}
sig.data = in->data;
sig.length = NTLMSSP_SIG_SIZE;
- *out = data_blob_talloc(out_mem_ctx, in->data + NTLMSSP_SIG_SIZE, in->length - NTLMSSP_SIG_SIZE);
-
- if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
- save_direction = ntlmssp_state->crypt->ntlm2.receiving;
- } else {
- save_direction = ntlmssp_state->crypt->ntlm;
- }
-
- status = ntlmssp_check_packet(ntlmssp_state,
- out->data, out->length,
- out->data, out->length,
- &sig);
- if (!NT_STATUS_IS_OK(status)) {
- NTSTATUS check_status = status;
- /*
- * The Windows LDAP libraries seems to have a bug
- * and always use sealing even if only signing was
- * negotiated. So we need to fallback.
- */
- if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
- ntlmssp_state->crypt->ntlm2.receiving = save_direction;
- } else {
- ntlmssp_state->crypt->ntlm = save_direction;
- }
-
- status = ntlmssp_unseal_packet(ntlmssp_state,
- out->data,
- out->length,
- out->data,
- out->length,
- &sig);
- if (NT_STATUS_IS_OK(status)) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
- } else {
- status = check_status;
- }
- }
+ *out = data_blob_talloc(out_mem_ctx, in->data + NTLMSSP_SIG_SIZE, in->length - NTLMSSP_SIG_SIZE);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("NTLMSSP packet check for unwrap failed due to invalid signature\n"));
- }
- return status;
+ return ntlmssp_check_packet(ntlmssp_state,
+ out->data, out->length,
+ out->data, out->length,
+ &sig);
} else {
*out = data_blob_talloc(out_mem_ctx, in->data, in->length);
if (!out->data) {
@@ -542,20 +503,30 @@ NTSTATUS ntlmssp_unwrap(struct ntlmssp_state *ntlmssp_state,
/**
Initialise the state for NTLMSSP signing.
*/
-NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
+NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state,
+ bool reset_seqnums)
{
DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n"));
debug_ntlmssp_flags(ntlmssp_state->neg_flags);
- if (ntlmssp_state->session_key.length < 8) {
- DEBUG(3, ("NO session key, cannot intialise signing\n"));
- return NT_STATUS_NO_USER_SESSION_KEY;
+ if (ntlmssp_state->crypt == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
}
- ntlmssp_state->crypt = talloc_zero(ntlmssp_state,
- union ntlmssp_crypt_state);
- if (ntlmssp_state->crypt == NULL) {
- return NT_STATUS_NO_MEMORY;
+ if (ntlmssp_state->force_wrap_seal &&
+ (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN))
+ {
+ /*
+ * We need to handle NTLMSSP_NEGOTIATE_SIGN as
+ * NTLMSSP_NEGOTIATE_SEAL if GENSEC_FEATURE_LDAP_STYLE
+ * is requested.
+ *
+ * The negotiation of flags (and authentication)
+ * is completed when ntlmssp_sign_init() is called
+ * so we can safely pretent NTLMSSP_NEGOTIATE_SEAL
+ * was negotiated.
+ */
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
}
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
@@ -629,7 +600,9 @@ NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
&ntlmssp_state->crypt->ntlm2.sending.seal_state);
/* SEND: seq num */
- ntlmssp_state->crypt->ntlm2.sending.seq_num = 0;
+ if (reset_seqnums) {
+ ntlmssp_state->crypt->ntlm2.sending.seq_num = 0;
+ }
/* RECV: sign key */
calc_ntlmv2_key(ntlmssp_state->crypt->ntlm2.receiving.sign_key,
@@ -649,7 +622,9 @@ NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
&ntlmssp_state->crypt->ntlm2.receiving.seal_state);
/* RECV: seq num */
- ntlmssp_state->crypt->ntlm2.receiving.seq_num = 0;
+ if (reset_seqnums) {
+ ntlmssp_state->crypt->ntlm2.receiving.seq_num = 0;
+ }
} else {
uint8_t weak_session_key[8];
DATA_BLOB seal_session_key = ntlmssp_state->session_key;
@@ -699,8 +674,26 @@ NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
dump_arc4_state("NTLMv1 arc4 state:\n",
&ntlmssp_state->crypt->ntlm.seal_state);
- ntlmssp_state->crypt->ntlm.seq_num = 0;
+ if (reset_seqnums) {
+ ntlmssp_state->crypt->ntlm.seq_num = 0;
+ }
}
return NT_STATUS_OK;
}
+
+NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
+{
+ if (ntlmssp_state->session_key.length < 8) {
+ DEBUG(3, ("NO session key, cannot intialise signing\n"));
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ ntlmssp_state->crypt = talloc_zero(ntlmssp_state,
+ union ntlmssp_crypt_state);
+ if (ntlmssp_state->crypt == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return ntlmssp_sign_reset(ntlmssp_state, true);
+}
diff --git a/auth/ntlmssp/ntlmssp_util.c b/auth/ntlmssp/ntlmssp_util.c
index 96793abfda1..4ae6101f025 100644
--- a/auth/ntlmssp/ntlmssp_util.c
+++ b/auth/ntlmssp/ntlmssp_util.c
@@ -25,6 +25,41 @@
#include "../auth/ntlmssp/ntlmssp.h"
#include "../auth/ntlmssp/ntlmssp_private.h"
+static void debug_ntlmssp_flags_raw(int level, uint32_t flags)
+{
+#define _PRINT_FLAG_LINE(v) do { \
+ if (flags & (v)) { \
+ DEBUGADD(level, (" " #v "\n")); \
+ } \
+} while (0)
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_UNICODE);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_OEM);
+ _PRINT_FLAG_LINE(NTLMSSP_REQUEST_TARGET);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_SIGN);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_SEAL);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_DATAGRAM);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_LM_KEY);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_NETWARE);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_NTLM);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_NT_ONLY);
+ _PRINT_FLAG_LINE(NTLMSSP_ANONYMOUS);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_ALWAYS_SIGN);
+ _PRINT_FLAG_LINE(NTLMSSP_TARGET_TYPE_DOMAIN);
+ _PRINT_FLAG_LINE(NTLMSSP_TARGET_TYPE_SERVER);
+ _PRINT_FLAG_LINE(NTLMSSP_TARGET_TYPE_SHARE);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_IDENTIFY);
+ _PRINT_FLAG_LINE(NTLMSSP_REQUEST_NON_NT_SESSION_KEY);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_TARGET_INFO);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_VERSION);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_128);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_KEY_EXCH);
+ _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_56);
+}
+
/**
* Print out the NTLMSSP flags for debugging
* @param neg_flags The flags from the packet
@@ -32,53 +67,15 @@
void debug_ntlmssp_flags(uint32_t neg_flags)
{
DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags));
-
- if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_UNICODE\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_OEM)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM\n"));
- if (neg_flags & NTLMSSP_REQUEST_TARGET)
- DEBUGADD(4, (" NTLMSSP_REQUEST_TARGET\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_SIGN)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SIGN\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_SEAL)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SEAL\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_DATAGRAM)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DATAGRAM\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_LM_KEY\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NETWARE\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_NTLM)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n"));
- if (neg_flags & NTLMSSP_REQUEST_NON_NT_SESSION_KEY)
- DEBUGADD(4, (" NTLMSSP_REQUEST_NON_NT_SESSION_KEY\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM2\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_TARGET_INFO)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_TARGET_INFO\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_VERSION)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_VERSION\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_128)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_128\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_KEY_EXCH\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_56)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_56\n"));
+ debug_ntlmssp_flags_raw(4, neg_flags);
}
-void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
- uint32_t neg_flags, bool allow_lm)
+NTSTATUS ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
+ uint32_t flags, const char *name)
{
- if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ uint32_t missing_flags = ntlmssp_state->required_flags;
+
+ if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
ntlmssp_state->unicode = true;
@@ -88,49 +85,69 @@ void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
ntlmssp_state->unicode = false;
}
- if ((neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) && allow_lm) {
- /* other end forcing us to use LM */
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
- ntlmssp_state->use_ntlmv2 = false;
- } else {
+ /*
+ * NTLMSSP_NEGOTIATE_NTLM2 (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)
+ * has priority over NTLMSSP_NEGOTIATE_LM_KEY
+ */
+ if (!(flags & NTLMSSP_NEGOTIATE_NTLM2)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
}
- if (!(neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) {
- ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
+ if (!(flags & NTLMSSP_NEGOTIATE_LM_KEY)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
}
- if (!(neg_flags & NTLMSSP_NEGOTIATE_NTLM2)) {
- ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+ if (!(flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
}
- if (!(neg_flags & NTLMSSP_NEGOTIATE_128)) {
+ if (!(flags & NTLMSSP_NEGOTIATE_128)) {
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
}
- if (!(neg_flags & NTLMSSP_NEGOTIATE_56)) {
+ if (!(flags & NTLMSSP_NEGOTIATE_56)) {
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56;
}
- if (!(neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
+ if (!(flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH;
}
- if (!(neg_flags & NTLMSSP_NEGOTIATE_SIGN)) {
+ if (!(flags & NTLMSSP_NEGOTIATE_SIGN)) {
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
}
- if (!(neg_flags & NTLMSSP_NEGOTIATE_SEAL)) {
+ if (!(flags & NTLMSSP_NEGOTIATE_SEAL)) {
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SEAL;
}
- if (!(neg_flags & NTLMSSP_NEGOTIATE_VERSION)) {
- ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_VERSION;
+ if ((flags & NTLMSSP_REQUEST_TARGET)) {
+ ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET;
}
- if ((neg_flags & NTLMSSP_REQUEST_TARGET)) {
- ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET;
+ missing_flags &= ~ntlmssp_state->neg_flags;
+ if (missing_flags != 0) {
+ HRESULT hres = HRES_SEC_E_UNSUPPORTED_FUNCTION;
+ NTSTATUS status = NT_STATUS(HRES_ERROR_V(hres));
+ DEBUG(1, ("%s: Got %s flags[0x%08x] "
+ "- possible downgrade detected! "
+ "missing_flags[0x%08x] - %s\n",
+ __func__, name,
+ (unsigned)flags,
+ (unsigned)missing_flags,
+ nt_errstr(status)));
+ debug_ntlmssp_flags_raw(1, missing_flags);
+ DEBUGADD(4, ("neg_flags[0x%08x]\n",
+ (unsigned)ntlmssp_state->neg_flags));
+ debug_ntlmssp_flags_raw(4, ntlmssp_state->neg_flags);
+ return status;
}
+
+ return NT_STATUS_OK;
}
/* Does this blob looks like it could be NTLMSSP? */
@@ -142,3 +159,38 @@ bool ntlmssp_blob_matches_magic(const DATA_BLOB *blob)
return false;
}
}
+
+const DATA_BLOB ntlmssp_version_blob(void)
+{
+ /*
+ * This is a simplified version of
+ *
+ * enum ndr_err_code err;
+ * struct ntlmssp_VERSION vers;
+ *
+ * ZERO_STRUCT(vers);
+ * vers.ProductMajorVersion = NTLMSSP_WINDOWS_MAJOR_VERSION_6;
+ * vers.ProductMinorVersion = NTLMSSP_WINDOWS_MINOR_VERSION_1;
+ * vers.ProductBuild = 0;
+ * vers.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
+ *
+ * err = ndr_push_struct_blob(&version_blob,
+ * ntlmssp_state,
+ * &vers,
+ * (ndr_push_flags_fn_t)ndr_push_ntlmssp_VERSION);
+ *
+ * if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ * data_blob_free(&struct_blob);
+ * return NT_STATUS_NO_MEMORY;
+ * }
+ */
+ static const uint8_t version_buffer[8] = {
+ NTLMSSP_WINDOWS_MAJOR_VERSION_6,
+ NTLMSSP_WINDOWS_MINOR_VERSION_1,
+ 0x00, 0x00, /* product build */
+ 0x00, 0x00, 0x00, /* reserved */
+ NTLMSSP_REVISION_W2K3
+ };
+
+ return data_blob_const(version_buffer, ARRAY_SIZE(version_buffer));
+}
diff --git a/auth/ntlmssp/wscript_build b/auth/ntlmssp/wscript_build
index 8725a8077d9..e28d4eb9dd8 100644
--- a/auth/ntlmssp/wscript_build
+++ b/auth/ntlmssp/wscript_build
@@ -7,7 +7,7 @@ bld.SAMBA_SUBSYSTEM('NTLMSSP_COMMON',
ntlmssp_server.c
ntlmssp_sign.c
gensec_ntlmssp_server.c''',
- deps='samba-util NDR_NTLMSSP MSRPC_PARSE NTLM_CHECK samba-credentials')
+ deps='samba-util NDR_NTLMSSP MSRPC_PARSE NTLM_CHECK samba-credentials wbclient')
bld.SAMBA_MODULE('gensec_ntlmssp',
source='''''',
diff --git a/docs-xml/smbdotconf/ldap/ldapserverrequirestrongauth.xml b/docs-xml/smbdotconf/ldap/ldapserverrequirestrongauth.xml
new file mode 100644
index 00000000000..02bdd811491
--- /dev/null
+++ b/docs-xml/smbdotconf/ldap/ldapserverrequirestrongauth.xml
@@ -0,0 +1,26 @@
+<samba:parameter name="ldap server require strong auth"
+ context="G"
+ type="enum"
+ enumlist="enum_ldap_server_require_strong_auth_vals"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>
+ The <smbconfoption name="ldap server require strong auth"/> defines whether
+ the ldap server requires ldap traffic to be signed or signed and encrypted (sealed).
+ Possible values are <emphasis>no</emphasis>, <emphasis>allow_sasl_over_tls</emphasis>
+ and <emphasis>yes</emphasis>.
+ </para>
+
+ <para>A value of <emphasis>no</emphasis> allows simple and sasl binds over
+ all transports.</para>
+
+ <para>A value of <emphasis>allow_sasl_over_tls</emphasis> allows simple and sasl binds
+ (without sign or seal) over TLS encrypted connections. Unencrypted connections only
+ allow sasl binds with sign or seal.</para>
+
+ <para>A value of <emphasis>yes</emphasis> allows only simple binds
+ over TLS encrypted connections. Unencrypted connections only
+ allow sasl binds with sign or seal.</para>
+</description>
+<value type="default">yes</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/protocol/clientipcmaxprotocol.xml b/docs-xml/smbdotconf/protocol/clientipcmaxprotocol.xml
new file mode 100644
index 00000000000..408af50940f
--- /dev/null
+++ b/docs-xml/smbdotconf/protocol/clientipcmaxprotocol.xml
@@ -0,0 +1,29 @@
+<samba:parameter name="client ipc max protocol"
+ context="G"
+ type="enum"
+ function="_client_ipc_max_protocol"
+ enumlist="enum_protocol"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>The value of the parameter (a string) is the highest
+ protocol level that will be supported for IPC$ connections as DCERPC transport.</para>
+
+ <para>Normally this option should not be set as the automatic
+ negotiation phase in the SMB protocol takes care of choosing
+ the appropriate protocol.</para>
+
+ <para>The value <constant>default</constant> refers to the latest
+ supported protocol, currently <constant>SMB3_11</constant>.</para>
+
+ <para>See <smbconfoption name="client max protocol"/> for a full list
+ of available protocols. The values CORE, COREPLUS, LANMAN1, LANMAN2
+ are silently upgraded to NT1.</para>
+</description>
+
+<related>client ipc min protocol</related>
+<related>client min protocol</related>
+<related>client max protocol</related>
+
+<value type="default">default</value>
+<value type="example">SMB2_10</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/protocol/clientipcminprotocol.xml b/docs-xml/smbdotconf/protocol/clientipcminprotocol.xml
new file mode 100644
index 00000000000..fc04b780b15
--- /dev/null
+++ b/docs-xml/smbdotconf/protocol/clientipcminprotocol.xml
@@ -0,0 +1,29 @@
+<samba:parameter name="client ipc min protocol"
+ context="G"
+ type="enum"
+ function="_client_ipc_min_protocol"
+ enumlist="enum_protocol"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>This setting controls the minimum protocol version that the
+ will be attempted to use for IPC$ connections as DCERPC transport.</para>
+
+ <para>Normally this option should not be set as the automatic
+ negotiation phase in the SMB protocol takes care of choosing
+ the appropriate protocol.</para>
+
+ <para>The value <constant>default</constant> refers to the higher value
+ of <constant>NT1</constant> and the effective value of
+ <smbconfoption name="client min protocol"/>.</para>
+
+ <para>See <smbconfoption name="client max protocol"/> for a full list
+ of available protocols. The values CORE, COREPLUS, LANMAN1, LANMAN2
+ are silently upgraded to NT1.</para>
+</description>
+
+<related>client ipc max protocol</related>
+<related>client min protocol</related>
+<related>client max protocol</related>
+<value type="default">default</value>
+<value type="example">SMB3_11</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml b/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml
index 121eeb8e717..5a6c9af0a9a 100644
--- a/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml
+++ b/docs-xml/smbdotconf/protocol/clientmaxprotocol.xml
@@ -73,13 +73,16 @@
negotiation phase in the SMB protocol takes care of choosing
the appropriate protocol.</para>
- <para>The value <constant>default</constant> refers to the default protocol in each
- part of the code, currently <constant>NT1</constant> in the client tools and
- <constant>SMB3_02</constant> in winbindd.</para>
+ <para>The value <constant>default</constant> refers to <constant>NT1</constant>.</para>
+
+ <para>IPC$ connections for DCERPC e.g. in winbindd, are handled by the
+ <smbconfoption name="client ipc max protocol"/> option.</para>
</description>
<related>server max protocol</related>
<related>client min protocol</related>
+<related>client ipc min protocol</related>
+<related>client ipc max protocol</related>
<value type="default">default</value>
<value type="example">LANMAN1</value>
diff --git a/docs-xml/smbdotconf/protocol/clientminprotocol.xml b/docs-xml/smbdotconf/protocol/clientminprotocol.xml
index 84e03eac902..052a42c7e40 100644
--- a/docs-xml/smbdotconf/protocol/clientminprotocol.xml
+++ b/docs-xml/smbdotconf/protocol/clientminprotocol.xml
@@ -13,10 +13,16 @@
<para>See <related>client max protocol</related> for a full list
of available protocols.</para>
+
+ <para>IPC$ connections for DCERPC e.g. in winbindd, are handled by the
+ <smbconfoption name="client ipc min protocol"/> option.</para>
</description>
<related>client max protocol</related>
<related>server min protocol</related>
+<related>client ipc min protocol</related>
+<related>client ipc max protocol</related>
+
<value type="default">CORE</value>
<value type="example">NT1</value>
</samba:parameter>
diff --git a/docs-xml/smbdotconf/protocol/clientusespnego.xml b/docs-xml/smbdotconf/protocol/clientusespnego.xml
index c688a656f4f..e53874583b0 100644
--- a/docs-xml/smbdotconf/protocol/clientusespnego.xml
+++ b/docs-xml/smbdotconf/protocol/clientusespnego.xml
@@ -9,6 +9,11 @@
supporting servers (including WindowsXP, Windows2000 and Samba
3.0) to agree upon an authentication
mechanism. This enables Kerberos authentication in particular.</para>
+
+ <para>When <smbconfoption name="client NTLMv2 auth"/> is also set to
+ <constant>yes</constant> extended security (SPNEGO) is required
+ in order to use NTLMv2 only within NTLMSSP. This behavior was
+ introduced with the patches for CVE-2016-2111.</para>
</description>
<value type="default">yes</value>
diff --git a/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml b/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml
new file mode 100644
index 00000000000..03531adbfb3
--- /dev/null
+++ b/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml
@@ -0,0 +1,27 @@
+<samba:parameter name="allow dcerpc auth level connect"
+ context="G"
+ type="boolean"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>This option controls whether DCERPC services are allowed to
+ be used with DCERPC_AUTH_LEVEL_CONNECT, which provides authentication,
+ but no per message integrity nor privacy protection.</para>
+
+ <para>Some interfaces like samr, lsarpc and netlogon have a hard-coded default of
+ <constant>no</constant> and epmapper, mgmt and rpcecho have a hard-coded default of
+ <constant>yes</constant>.
+ </para>
+
+ <para>The behavior can be overwritten per interface name (e.g. lsarpc, netlogon, samr, srvsvc,
+ winreg, wkssvc ...) by using 'allow dcerpc auth level connect:interface = yes' as option.</para>
+
+ <para>This option yields precedence to the implementation specific restrictions.
+ E.g. the drsuapi and backupkey protocols require DCERPC_AUTH_LEVEL_PRIVACY.
+ The dnsserver protocol requires DCERPC_AUTH_LEVEL_INTEGRITY.
+ </para>
+</description>
+
+<value type="default">no</value>
+<value type="example">yes</value>
+
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/security/clientipcsigning.xml b/docs-xml/smbdotconf/security/clientipcsigning.xml
new file mode 100644
index 00000000000..0881c6c020e
--- /dev/null
+++ b/docs-xml/smbdotconf/security/clientipcsigning.xml
@@ -0,0 +1,26 @@
+<samba:parameter name="client ipc signing"
+ context="G"
+ type="enum"
+ function="_client_ipc_signing"
+ enumlist="enum_smb_signing_vals"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>This controls whether the client is allowed or required to use SMB signing for IPC$
+ connections as DCERPC transport. Possible values
+ are <emphasis>auto</emphasis>, <emphasis>mandatory</emphasis>
+ and <emphasis>disabled</emphasis>.
+ </para>
+
+ <para>When set to mandatory or default, SMB signing is required.</para>
+
+ <para>When set to auto, SMB signing is offered, but not enforced and if set
+ to disabled, SMB signing is not offered either.</para>
+
+ <para>Connections from winbindd to Active Directory Domain Controllers
+ always enforce signing.</para>
+</description>
+
+<related>client signing</related>
+
+<value type="default">default</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/security/clientntlmv2auth.xml b/docs-xml/smbdotconf/security/clientntlmv2auth.xml
index 7f303565ba5..451e1803c75 100644
--- a/docs-xml/smbdotconf/security/clientntlmv2auth.xml
+++ b/docs-xml/smbdotconf/security/clientntlmv2auth.xml
@@ -28,6 +28,11 @@
NTLMv2 by default, and some sites (particularly those following
'best practice' security polices) only allow NTLMv2 responses, and
not the weaker LM or NTLM.</para>
+
+ <para>When <smbconfoption name="client use spnego"/> is also set to
+ <constant>yes</constant> extended security (SPNEGO) is required
+ in order to use NTLMv2 only within NTLMSSP. This behavior was
+ introduced with the patches for CVE-2016-2111.</para>
</description>
<value type="default">yes</value>
</samba:parameter>
diff --git a/docs-xml/smbdotconf/security/clientsigning.xml b/docs-xml/smbdotconf/security/clientsigning.xml
index 34fce3e857c..354cc535248 100644
--- a/docs-xml/smbdotconf/security/clientsigning.xml
+++ b/docs-xml/smbdotconf/security/clientsigning.xml
@@ -9,11 +9,16 @@
and <emphasis>disabled</emphasis>.
</para>
- <para>When set to auto or default, SMB signing is offered, but not enforced.
- When set to mandatory, SMB signing is required and if set
- to disabled, SMB signing is not offered either.
-</para>
+ <para>When set to auto or default, SMB signing is offered, but not enforced.</para>
+
+ <para>When set to mandatory, SMB signing is required and if set
+ to disabled, SMB signing is not offered either.</para>
+
+ <para>IPC$ connections for DCERPC e.g. in winbindd, are handled by the
+ <smbconfoption name="client ipc signing"/> option.</para>
</description>
+<related>client ipc signing</related>
+
<value type="default">default</value>
</samba:parameter>
diff --git a/docs-xml/smbdotconf/security/rawntlmv2auth.xml b/docs-xml/smbdotconf/security/rawntlmv2auth.xml
new file mode 100644
index 00000000000..30e7280bc5d
--- /dev/null
+++ b/docs-xml/smbdotconf/security/rawntlmv2auth.xml
@@ -0,0 +1,19 @@
+<samba:parameter name="raw NTLMv2 auth"
+ context="G"
+ type="boolean"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>This parameter determines whether or not <citerefentry><refentrytitle>smbd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry> will allow SMB1 clients without
+ extended security (without SPNEGO) to use NTLMv2 authentication.</para>
+
+ <para>If this option, <command moreinfo="none">lanman auth</command>
+ and <command moreinfo="none">ntlm auth</command> are all disabled,
+ then only clients with SPNEGO support will be permitted.
+ That means NTLMv2 is only supported within NTLMSSP.</para>
+</description>
+
+<related>lanman auth</related>
+<related>ntlm auth</related>
+<value type="default">no</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/security/serversigning.xml b/docs-xml/smbdotconf/security/serversigning.xml
index c94a3ee6ba2..1eb7c41952b 100644
--- a/docs-xml/smbdotconf/security/serversigning.xml
+++ b/docs-xml/smbdotconf/security/serversigning.xml
@@ -11,7 +11,7 @@
</para>
<para>By default, and when smb signing is set to
- <emphasis>default</emphasis>, smb signing enabled when
+ <emphasis>default</emphasis>, smb signing is required when
<smbconfoption name="server role"/> is <emphasis>active directory
domain controller</emphasis> and disabled otherwise.</para>
diff --git a/docs-xml/smbdotconf/security/tlspriority.xml b/docs-xml/smbdotconf/security/tlspriority.xml
new file mode 100644
index 00000000000..d399eef8eef
--- /dev/null
+++ b/docs-xml/smbdotconf/security/tlspriority.xml
@@ -0,0 +1,22 @@
+<samba:parameter name="tls priority"
+ type="string"
+ context="G"
+ constant="1"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+ <description>
+ <para>This option can be set to a string describing the TLS protocols
+ to be supported in the parts of Samba that use GnuTLS, specifically
+ the AD DC.
+ </para>
+ <para>The default turns off SSLv3, as this protocol is no longer considered
+ secure after CVE-2014-3566 (otherwise known as POODLE) impacted SSLv3 use
+ in HTTPS applications.
+ </para>
+ <para>The valid options are described in the
+ <ulink url="http://gnutls.org/manual/html_node/Priority-Strings.html">GNUTLS
+ Priority-Strings documentation at http://gnutls.org/manual/html_node/Priority-Strings.html</ulink>
+ </para>
+ </description>
+
+ <value type="default">NORMAL:-VERS-SSL3.0</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/security/tlsverifypeer.xml b/docs-xml/smbdotconf/security/tlsverifypeer.xml
new file mode 100644
index 00000000000..4f47dd4db0d
--- /dev/null
+++ b/docs-xml/smbdotconf/security/tlsverifypeer.xml
@@ -0,0 +1,47 @@
+<samba:parameter name="tls verify peer"
+ context="G"
+ type="enum"
+ enumlist="enum_tls_verify_peer_vals"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>This controls if and how strict the client will verify the peer's certificate and name.
+ Possible values are (in increasing order):
+ <constant>no_check</constant>,
+ <constant>ca_only</constant>,
+ <constant>ca_and_name_if_available</constant>,
+ <constant>ca_and_name</constant>
+ and
+ <constant>as_strict_as_possible</constant>.</para>
+
+ <para>When set to <constant>no_check</constant> the certificate is not verified at
+ all, which allows trivial man in the middle attacks.
+ </para>
+
+ <para>When set to <constant>ca_only</constant> the certificate is verified to
+ be signed from a ca specified in the <smbconfoption name="tls ca file"/> option.
+ Setting <smbconfoption name="tls ca file"/> to a valid file is required.
+ The certificate lifetime is also verified. If the <smbconfoption name="tls crl file"/>
+ option is configured, the certificate is also verified against the ca crl.
+ </para>
+
+ <para>When set to <constant>ca_and_name_if_available</constant> all checks from
+ <constant>ca_only</constant> are performed. In addition, the peer hostname is verified
+ against the certificate's name, if it is provided by the application layer and
+ not given as an ip address string.
+ </para>
+
+ <para>When set to <constant>ca_and_name</constant> all checks from
+ <constant>ca_and_name_if_available</constant> are performed.
+ In addition the peer hostname needs to be provided and even an ip
+ address is checked against the certificate's name.
+ </para>
+
+ <para>When set to <constant>as_strict_as_possible</constant> all checks from
+ <constant>ca_and_name</constant> are performed. In addition the
+ <smbconfoption name="tls crl file"/> needs to be configured.
+ Future versions of Samba may implement additional checks.
+ </para>
+</description>
+
+<value type="default">as_strict_as_possible</value>
+</samba:parameter>
diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
index 2cc145d600d..4857c199cc5 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -2494,6 +2494,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
lpcfg_do_global_parameter(lp_ctx, "server max protocol", "SMB3");
lpcfg_do_global_parameter(lp_ctx, "client min protocol", "CORE");
lpcfg_do_global_parameter(lp_ctx, "client max protocol", "default");
+ lpcfg_do_global_parameter(lp_ctx, "client ipc min protocol", "default");
+ lpcfg_do_global_parameter(lp_ctx, "client ipc max protocol", "default");
lpcfg_do_global_parameter(lp_ctx, "security", "AUTO");
lpcfg_do_global_parameter(lp_ctx, "EncryptPasswords", "True");
lpcfg_do_global_parameter(lp_ctx, "ReadRaw", "True");
@@ -2509,8 +2511,11 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
lpcfg_do_global_parameter(lp_ctx, "ClientNTLMv2Auth", "True");
lpcfg_do_global_parameter(lp_ctx, "LanmanAuth", "False");
lpcfg_do_global_parameter(lp_ctx, "NTLMAuth", "True");
+ lpcfg_do_global_parameter(lp_ctx, "RawNTLMv2Auth", "False");
lpcfg_do_global_parameter(lp_ctx, "client use spnego principal", "False");
+ lpcfg_do_global_parameter(lp_ctx, "allow dcerpc auth level connect", "False");
+
lpcfg_do_global_parameter(lp_ctx, "UnixExtensions", "True");
lpcfg_do_global_parameter(lp_ctx, "PreferredMaster", "Auto");
@@ -2533,6 +2538,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
lpcfg_do_global_parameter(lp_ctx, "template homedir", "/home/%D/%U");
lpcfg_do_global_parameter(lp_ctx, "client signing", "default");
+ lpcfg_do_global_parameter(lp_ctx, "client ipc signing", "default");
lpcfg_do_global_parameter(lp_ctx, "server signing", "default");
lpcfg_do_global_parameter(lp_ctx, "use spnego", "True");
@@ -2553,9 +2559,11 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
lpcfg_do_global_parameter(lp_ctx, "min wins ttl", "21600");
lpcfg_do_global_parameter(lp_ctx, "tls enabled", "True");
+ lpcfg_do_global_parameter(lp_ctx, "tls verify peer", "as_strict_as_possible");
lpcfg_do_global_parameter(lp_ctx, "tls keyfile", "tls/key.pem");
lpcfg_do_global_parameter(lp_ctx, "tls certfile", "tls/cert.pem");
lpcfg_do_global_parameter(lp_ctx, "tls cafile", "tls/ca.pem");
+ lpcfg_do_global_parameter(lp_ctx, "tls priority", "NORMAL:-VERS-SSL3.0");
lpcfg_do_global_parameter(lp_ctx, "prefork children:smb", "4");
lpcfg_do_global_parameter(lp_ctx, "rndc command", "/usr/sbin/rndc");
@@ -2686,6 +2694,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
lpcfg_do_global_parameter(lp_ctx, "client ldap sasl wrapping", "sign");
+ lpcfg_do_global_parameter(lp_ctx, "ldap server require strong auth", "yes");
+
lpcfg_do_global_parameter(lp_ctx, "follow symlinks", "yes");
lpcfg_do_global_parameter(lp_ctx, "machine password timeout", "604800");
@@ -3176,6 +3186,39 @@ int lpcfg_client_max_protocol(struct loadparm_context *lp_ctx)
return client_max_protocol;
}
+int lpcfg_client_ipc_min_protocol(struct loadparm_context *lp_ctx)
+{
+ int client_ipc_min_protocol = lpcfg__client_ipc_min_protocol(lp_ctx);
+ if (client_ipc_min_protocol == PROTOCOL_DEFAULT) {
+ client_ipc_min_protocol = lpcfg_client_min_protocol(lp_ctx);
+ }
+ if (client_ipc_min_protocol < PROTOCOL_NT1) {
+ return PROTOCOL_NT1;
+ }
+ return client_ipc_min_protocol;
+}
+
+int lpcfg_client_ipc_max_protocol(struct loadparm_context *lp_ctx)
+{
+ int client_ipc_max_protocol = lpcfg__client_ipc_max_protocol(lp_ctx);
+ if (client_ipc_max_protocol == PROTOCOL_DEFAULT) {
+ return PROTOCOL_LATEST;
+ }
+ if (client_ipc_max_protocol < PROTOCOL_NT1) {
+ return PROTOCOL_NT1;
+ }
+ return client_ipc_max_protocol;
+}
+
+int lpcfg_client_ipc_signing(struct loadparm_context *lp_ctx)
+{
+ int client_ipc_signing = lpcfg__client_ipc_signing(lp_ctx);
+ if (client_ipc_signing == SMB_SIGNING_DEFAULT) {
+ return SMB_SIGNING_REQUIRED;
+ }
+ return client_ipc_signing;
+}
+
bool lpcfg_server_signing_allowed(struct loadparm_context *lp_ctx, bool *mandatory)
{
bool allowed = true;
@@ -3210,10 +3253,13 @@ bool lpcfg_server_signing_allowed(struct loadparm_context *lp_ctx, bool *mandato
case SMB_SIGNING_DESIRED:
case SMB_SIGNING_IF_REQUIRED:
break;
- case SMB_SIGNING_DEFAULT:
case SMB_SIGNING_OFF:
allowed = false;
break;
+ case SMB_SIGNING_DEFAULT:
+ case SMB_SIGNING_IPC_DEFAULT:
+ smb_panic(__location__);
+ break;
}
return allowed;
diff --git a/lib/param/loadparm.h b/lib/param/loadparm.h
index 11632de65cc..2d460dc3394 100644
--- a/lib/param/loadparm.h
+++ b/lib/param/loadparm.h
@@ -201,6 +201,12 @@ enum printing_types {PRINT_BSD,PRINT_SYSV,PRINT_AIX,PRINT_HPUX,
#define ADS_AUTH_SASL_FORCE 0x0080
#define ADS_AUTH_USER_CREDS 0x0100
+enum ldap_server_require_strong_auth {
+ LDAP_SERVER_REQUIRE_STRONG_AUTH_NO,
+ LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS,
+ LDAP_SERVER_REQUIRE_STRONG_AUTH_YES,
+};
+
/* DNS update settings */
enum dns_update_settings {DNS_UPDATE_OFF, DNS_UPDATE_ON, DNS_UPDATE_SIGNED};
diff --git a/lib/param/param_table.c b/lib/param/param_table.c
index 530d8589578..4bc9198bf92 100644
--- a/lib/param/param_table.c
+++ b/lib/param/param_table.c
@@ -32,6 +32,7 @@
#include "lib/param/loadparm.h"
#include "lib/param/param_global.h"
#include "libcli/smb/smb_constants.h"
+#include "source4/lib/tls/tls.h"
#ifndef N_
#define N_(x) x
@@ -122,6 +123,20 @@ static const struct enum_list enum_smb_signing_vals[] = {
{-1, NULL}
};
+static const struct enum_list enum_tls_verify_peer_vals[] = {
+ {TLS_VERIFY_PEER_NO_CHECK,
+ TLS_VERIFY_PEER_NO_CHECK_STRING},
+ {TLS_VERIFY_PEER_CA_ONLY,
+ TLS_VERIFY_PEER_CA_ONLY_STRING},
+ {TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE,
+ TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE_STRING},
+ {TLS_VERIFY_PEER_CA_AND_NAME,
+ TLS_VERIFY_PEER_CA_AND_NAME_STRING},
+ {TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE,
+ TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE_STRING},
+ {-1, NULL}
+};
+
/* DNS update options. */
static const struct enum_list enum_dns_update_settings[] = {
{DNS_UPDATE_OFF, "disabled"},
@@ -216,6 +231,18 @@ static const struct enum_list enum_ldap_sasl_wrapping[] = {
{-1, NULL}
};
+static const struct enum_list enum_ldap_server_require_strong_auth_vals[] = {
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_NO, "No" },
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_NO, "False" },
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_NO, "0" },
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS,
+ "allow_sasl_over_tls" },
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, "Yes" },
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, "True" },
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, "1" },
+ {-1, NULL}
+};
+
static const struct enum_list enum_ldap_ssl[] = {
{LDAP_SSL_OFF, "no"},
{LDAP_SSL_OFF, "off"},
@@ -728,6 +755,14 @@ struct parm_struct parm_table[] = {
.flags = FLAG_ADVANCED,
},
{
+ .label = "raw NTLMv2 auth",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .offset = GLOBAL_VAR(raw_ntlmv2_auth),
+ .special = NULL,
+ .enum_list = NULL,
+ },
+ {
.label = "client NTLMv2 auth",
.type = P_BOOL,
.p_class = P_GLOBAL,
@@ -1663,6 +1698,14 @@ struct parm_struct parm_table[] = {
.flags = FLAG_ADVANCED,
},
{
+ .label = "ldap server require strong auth",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .offset = GLOBAL_VAR(ldap_server_require_strong_auth),
+ .special = NULL,
+ .enum_list = enum_ldap_server_require_strong_auth_vals
+ },
+ {
.label = "enable asu support",
.type = P_BOOL,
.p_class = P_GLOBAL,
@@ -4433,6 +4476,54 @@ struct parm_struct parm_table[] = {
.special = NULL,
.enum_list = NULL
},
+ {
+ .label = "tls priority",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .offset = GLOBAL_VAR(tls_priority),
+ .special = NULL,
+ .enum_list = NULL
+ },
+ {
+ .label = "tls verify peer",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .offset = GLOBAL_VAR(tls_verify_peer),
+ .special = NULL,
+ .enum_list = enum_tls_verify_peer_vals,
+ },
+ {
+ .label = "client ipc max protocol",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .offset = GLOBAL_VAR(_client_ipc_max_protocol),
+ .special = NULL,
+ .enum_list = enum_protocol,
+ },
+ {
+ .label = "client ipc min protocol",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .offset = GLOBAL_VAR(_client_ipc_min_protocol),
+ .special = NULL,
+ .enum_list = enum_protocol,
+ },
+ {
+ .label = "client ipc signing",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .offset = GLOBAL_VAR(_client_ipc_signing),
+ .special = NULL,
+ .enum_list = enum_smb_signing_vals,
+ },
+ {
+ .label = "allow dcerpc auth level connect",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .offset = GLOBAL_VAR(allow_dcerpc_auth_level_connect),
+ .special = NULL,
+ .enum_list = NULL
+ },
{NULL, P_BOOL, P_NONE, 0, NULL, NULL, 0}
};
diff --git a/lib/util/asn1.c b/lib/util/asn1.c
index 90f950a1491..4778da498e2 100644
--- a/lib/util/asn1.c
+++ b/lib/util/asn1.c
@@ -20,6 +20,21 @@
#include "includes.h"
#include "../lib/util/asn1.h"
+struct nesting {
+ off_t start;
+ size_t taglen; /* for parsing */
+ struct nesting *next;
+};
+
+
+struct asn1_data {
+ uint8_t *data;
+ size_t length;
+ off_t ofs;
+ struct nesting *nesting;
+ bool has_error;
+};
+
/* allocate an asn1 structure */
struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx)
{
@@ -36,10 +51,36 @@ void asn1_free(struct asn1_data *data)
talloc_free(data);
}
+bool asn1_has_error(const struct asn1_data *data)
+{
+ return data->has_error;
+}
+
+void asn1_set_error(struct asn1_data *data)
+{
+ data->has_error = true;
+}
+
+bool asn1_has_nesting(const struct asn1_data *data)
+{
+ return data->nesting != NULL;
+}
+
+off_t asn1_current_ofs(const struct asn1_data *data)
+{
+ return data->ofs;
+}
+
/* write to the ASN1 buffer, advancing the buffer pointer */
bool asn1_write(struct asn1_data *data, const void *p, int len)
{
if (data->has_error) return false;
+
+ if ((len < 0) || (data->ofs + (size_t)len < data->ofs)) {
+ data->has_error = true;
+ return false;
+ }
+
if (data->length < data->ofs+len) {
uint8_t *newp;
newp = talloc_realloc(data, data->data, uint8_t, data->ofs+len);
@@ -66,7 +107,9 @@ bool asn1_push_tag(struct asn1_data *data, uint8_t tag)
{
struct nesting *nesting;
- asn1_write_uint8(data, tag);
+ if (!asn1_write_uint8(data, tag)) {
+ return false;
+ }
nesting = talloc(data, struct nesting);
if (!nesting) {
data->has_error = true;
@@ -85,6 +128,10 @@ bool asn1_pop_tag(struct asn1_data *data)
struct nesting *nesting;
size_t len;
+ if (data->has_error) {
+ return false;
+ }
+
nesting = data->nesting;
if (!nesting) {
@@ -184,6 +231,10 @@ static bool push_int_bigendian(struct asn1_data *data, unsigned int i, bool nega
bool asn1_write_implicit_Integer(struct asn1_data *data, int i)
{
+ if (data->has_error) {
+ return false;
+ }
+
if (i == -1) {
/* -1 is special as it consists of all-0xff bytes. In
push_int_bigendian this is the only case that is not
@@ -984,6 +1035,26 @@ bool asn1_blob(const struct asn1_data *asn1, DATA_BLOB *blob)
return true;
}
+bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pblob)
+{
+ DATA_BLOB blob;
+
+ if (!asn1_blob(asn1, &blob)) {
+ return false;
+ }
+
+ *pblob = (DATA_BLOB) { .length = blob.length };
+ pblob->data = talloc_move(mem_ctx, &blob.data);
+
+ /*
+ * Stop access from here on
+ */
+ asn1->has_error = true;
+
+ return true;
+}
+
/*
Fill in an asn1 struct without making a copy
*/
@@ -994,35 +1065,7 @@ void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len)
data->length = len;
}
-/*
- check if a ASN.1 blob is a full tag
-*/
-NTSTATUS asn1_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
-{
- struct asn1_data *asn1 = asn1_init(NULL);
- int size;
-
- NT_STATUS_HAVE_NO_MEMORY(asn1);
-
- asn1->data = blob.data;
- asn1->length = blob.length;
- if (!asn1_start_tag(asn1, tag)) {
- talloc_free(asn1);
- return STATUS_MORE_ENTRIES;
- }
- size = asn1_tag_remaining(asn1) + asn1->ofs;
-
- talloc_free(asn1);
-
- if (size > blob.length) {
- return STATUS_MORE_ENTRIES;
- }
-
- *packet_size = size;
- return NT_STATUS_OK;
-}
-
-NTSTATUS asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
+int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
{
struct asn1_data asn1;
size_t size;
@@ -1034,14 +1077,14 @@ NTSTATUS asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
ok = asn1_peek_tag_needed_size(&asn1, tag, &size);
if (!ok) {
- return NT_STATUS_INVALID_BUFFER_SIZE;
+ return EMSGSIZE;
}
if (size > blob.length) {
*packet_size = size;
- return STATUS_MORE_ENTRIES;
+ return EAGAIN;
}
*packet_size = size;
- return NT_STATUS_OK;
+ return 0;
}
diff --git a/lib/util/asn1.h b/lib/util/asn1.h
index 568b4e4cc8b..4eb8506d092 100644
--- a/lib/util/asn1.h
+++ b/lib/util/asn1.h
@@ -20,20 +20,8 @@
#ifndef _ASN_1_H
#define _ASN_1_H
-struct nesting {
- off_t start;
- size_t taglen; /* for parsing */
- struct nesting *next;
-};
-
-struct asn1_data {
- uint8_t *data;
- size_t length;
- off_t ofs;
- struct nesting *nesting;
- bool has_error;
-};
-
+struct nesting;
+struct asn1_data;
typedef struct asn1_data ASN1_DATA;
#define ASN1_APPLICATION(x) ((x)+0x60)
@@ -54,6 +42,10 @@ typedef struct asn1_data ASN1_DATA;
struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx);
void asn1_free(struct asn1_data *data);
+bool asn1_has_error(const struct asn1_data *data);
+void asn1_set_error(struct asn1_data *data);
+bool asn1_has_nesting(const struct asn1_data *data);
+off_t asn1_current_ofs(const struct asn1_data *data);
bool asn1_write(struct asn1_data *data, const void *p, int len);
bool asn1_write_uint8(struct asn1_data *data, uint8_t v);
bool asn1_push_tag(struct asn1_data *data, uint8_t tag);
@@ -99,8 +91,9 @@ bool asn1_read_enumerated(struct asn1_data *data, int *v);
bool asn1_check_enumerated(struct asn1_data *data, int v);
bool asn1_write_enumerated(struct asn1_data *data, uint8_t v);
bool asn1_blob(const struct asn1_data *asn1, DATA_BLOB *blob);
+bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pblob);
void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len);
-NTSTATUS asn1_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size);
-NTSTATUS asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size);
+int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size);
#endif /* _ASN_1_H */
diff --git a/lib/util/tests/asn1_tests.c b/lib/util/tests/asn1_tests.c
index 2c68cb435de..a91d7a7389a 100644
--- a/lib/util/tests/asn1_tests.c
+++ b/lib/util/tests/asn1_tests.c
@@ -337,8 +337,10 @@ static bool test_asn1_Integer(struct torture_context *tctx)
if (!asn1_write_Integer(data, integer_tests[i].value)) goto err;
- blob.data = data->data;
- blob.length = data->length;
+ if (!asn1_blob(data, &blob)) {
+ goto err;
+ }
+
torture_assert_data_blob_equal(tctx, blob, integer_tests[i].blob, "asn1_write_Integer gave incorrect result");
if (!asn1_load(data, blob)) goto err;
diff --git a/lib/util/util.c b/lib/util/util.c
index 21d55c6af27..e21c3641f7e 100644
--- a/lib/util/util.c
+++ b/lib/util/util.c
@@ -530,7 +530,7 @@ void dump_data_cb(const uint8_t *buf, int len,
if (i%16) {
int n;
n = 16 - (i%16);
- cb(" ", private_data);
+ cb(" ", private_data);
if (n>8) {
cb(" ", private_data);
}
diff --git a/lib/util/util_net.c b/lib/util/util_net.c
index d58855da5b2..e5b33aa0a7e 100644
--- a/lib/util/util_net.c
+++ b/lib/util/util_net.c
@@ -41,6 +41,115 @@ void zero_sockaddr(struct sockaddr_storage *pss)
pss->ss_family = AF_INET;
}
+static char *normalize_ipv6_literal(const char *str, char *buf, size_t *_len)
+{
+#define IPv6_LITERAL_NET ".ipv6-literal.net"
+ static const size_t llen = sizeof(IPv6_LITERAL_NET) - 1;
+ size_t len = *_len;
+ int cmp;
+ size_t i;
+ size_t idx_chars = 0;
+ size_t cnt_delimiter = 0;
+ size_t cnt_chars = 0;
+
+ if (len <= llen) {
+ return false;
+ }
+
+ /* ignore a trailing '.' */
+ if (str[len - 1] == '.') {
+ len -= 1;
+ }
+
+ len -= llen;
+ if (len >= INET6_ADDRSTRLEN) {
+ return NULL;
+ }
+ if (len < 2) {
+ return NULL;
+ }
+
+ cmp = strncasecmp(&str[len], IPv6_LITERAL_NET, llen);
+ if (cmp != 0) {
+ return NULL;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (idx_chars != 0) {
+ break;
+ }
+
+ switch (str[i]) {
+ case '-':
+ buf[i] = ':';
+ cnt_chars = 0;
+ cnt_delimiter += 1;
+ break;
+ case 's':
+ buf[i] = '%';
+ idx_chars += 1;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'a':
+ case 'A':
+ case 'b':
+ case 'B':
+ case 'c':
+ case 'C':
+ case 'd':
+ case 'D':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ buf[i] = str[i];
+ cnt_chars += 1;
+ break;
+ default:
+ return NULL;
+ }
+ if (cnt_chars > 4) {
+ return NULL;
+ }
+ if (cnt_delimiter > 7) {
+ return NULL;
+ }
+ }
+
+ if (cnt_delimiter < 2) {
+ return NULL;
+ }
+
+ for (; idx_chars != 0 && i < len; i++) {
+ switch (str[i]) {
+ case '%':
+ case ':':
+ return NULL;
+ default:
+ buf[i] = str[i];
+ idx_chars += 1;
+ break;
+ }
+ }
+
+ if (idx_chars == 1) {
+ return NULL;
+ }
+
+ buf[i] = '\0';
+ *_len = len;
+ return buf;
+}
+
/**
* Wrap getaddrinfo...
*/
@@ -49,6 +158,11 @@ bool interpret_string_addr_internal(struct addrinfo **ppres,
{
int ret;
struct addrinfo hints;
+#if defined(HAVE_IPV6)
+ char addr[INET6_ADDRSTRLEN*2] = { 0, };
+ unsigned int scope_id = 0;
+ size_t len = strlen(str);
+#endif
ZERO_STRUCT(hints);
@@ -58,8 +172,72 @@ bool interpret_string_addr_internal(struct addrinfo **ppres,
/* always try as a numeric host first. This prevents unnecessary name
* lookups, and also ensures we accept IPv6 addresses */
hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+#if defined(HAVE_IPV6)
+ if (len < sizeof(addr)) {
+ char *p = NULL;
+
+ p = normalize_ipv6_literal(str, addr, &len);
+ if (p != NULL) {
+ hints.ai_family = AF_INET6;
+ str = p;
+ }
+ }
+
+ if (strchr_m(str, ':')) {
+ char *p = strchr_m(str, '%');
+
+ /*
+ * Cope with link-local.
+ * This is IP:v6:addr%ifname.
+ */
+
+ if (p && (p > str) && ((scope_id = if_nametoindex(p+1)) != 0)) {
+ /* Length of string we want to copy.
+ This is IP:v6:addr (removing the %ifname).
+ */
+ len = PTR_DIFF(p,str);
+
+ if (len+1 > sizeof(addr)) {
+ /* string+nul too long for array. */
+ return false;
+ }
+ if (str != addr) {
+ memcpy(addr, str, len);
+ }
+ addr[len] = '\0';
+
+ str = addr;
+ }
+ }
+#endif
+
ret = getaddrinfo(str, NULL, &hints, ppres);
if (ret == 0) {
+#if defined(HAVE_IPV6)
+ struct sockaddr_in6 *ps6 = NULL;
+
+ if (scope_id == 0) {
+ return true;
+ }
+ if (ppres == NULL) {
+ return true;
+ }
+ if ((*ppres) == NULL) {
+ return true;
+ }
+ if ((*ppres)->ai_addr->sa_family != AF_INET6) {
+ return true;
+ }
+
+ ps6 = (struct sockaddr_in6 *)(*ppres)->ai_addr;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&ps6->sin6_addr) &&
+ ps6->sin6_scope_id == 0) {
+ ps6->sin6_scope_id = scope_id;
+ }
+#endif
+
return true;
}
@@ -94,35 +272,6 @@ static bool interpret_string_addr_pref(struct sockaddr_storage *pss,
{
struct addrinfo *res = NULL;
int int_flags;
-#if defined(HAVE_IPV6)
- char addr[INET6_ADDRSTRLEN];
- unsigned int scope_id = 0;
-
- if (strchr_m(str, ':')) {
- char *p = strchr_m(str, '%');
-
- /*
- * Cope with link-local.
- * This is IP:v6:addr%ifname.
- */
-
- if (p && (p > str) && ((scope_id = if_nametoindex(p+1)) != 0)) {
- /* Length of string we want to copy.
- This is IP:v6:addr (removing the %ifname).
- */
- size_t len = PTR_DIFF(p,str);
-
- if (len+1 > sizeof(addr)) {
- /* string+nul too long for array. */
- return false;
- }
- memcpy(addr, str, len);
- addr[len] = '\0';
-
- str = addr;
- }
- }
-#endif
zero_sockaddr(pss);
@@ -157,16 +306,6 @@ static bool interpret_string_addr_pref(struct sockaddr_storage *pss,
memcpy(pss, res->ai_addr, res->ai_addrlen);
}
-#if defined(HAVE_IPV6)
- if (pss->ss_family == AF_INET6 && scope_id) {
- struct sockaddr_in6 *ps6 = (struct sockaddr_in6 *)pss;
- if (IN6_IS_ADDR_LINKLOCAL(&ps6->sin6_addr) &&
- ps6->sin6_scope_id == 0) {
- ps6->sin6_scope_id = scope_id;
- }
- }
-#endif
-
freeaddrinfo(res);
return true;
}
@@ -320,6 +459,28 @@ bool is_ipaddress_v4(const char *str)
return false;
}
+bool is_ipv6_literal(const char *str)
+{
+#if defined(HAVE_IPV6)
+ char buf[INET6_ADDRSTRLEN*2] = { 0, };
+ size_t len = strlen(str);
+ char *p = NULL;
+
+ if (len >= sizeof(buf)) {
+ return false;
+ }
+
+ p = normalize_ipv6_literal(str, buf, &len);
+ if (p == NULL) {
+ return false;
+ }
+
+ return true;
+#else
+ return false;
+#endif
+}
+
/**
* Return true if a string could be a IPv6 address.
*/
@@ -328,16 +489,20 @@ bool is_ipaddress_v6(const char *str)
{
#if defined(HAVE_IPV6)
int ret = -1;
+ char *p = NULL;
- if (strchr_m(str, ':')) {
+ p = strchr_m(str, ':');
+ if (p == NULL) {
+ return is_ipv6_literal(str);
+ } else {
char buf[INET6_ADDRSTRLEN] = { 0, };
size_t len;
const char *addr = str;
const char *idxs = NULL;
unsigned int idx = 0;
struct in6_addr ip6;
- char *p = strchr_m(str, '%');
+ p = strchr_m(str, '%');
if (p && (p > str)) {
len = PTR_DIFF(p, str);
idxs = p + 1;
diff --git a/lib/util/util_net.h b/lib/util/util_net.h
index 2f1beffb168..29468b4263d 100644
--- a/lib/util/util_net.h
+++ b/lib/util/util_net.h
@@ -86,6 +86,7 @@ _PUBLIC_ uint32_t interpret_addr(const char *str);
_PUBLIC_ struct in_addr interpret_addr2(const char *str);
_PUBLIC_ bool is_ipaddress_v4(const char *str);
+_PUBLIC_ bool is_ipv6_literal(const char *str);
_PUBLIC_ bool is_ipaddress_v6(const char *str);
bool is_address_any(const struct sockaddr *psa);
diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h
index 0c319d32e7b..a4949d09a46 100644
--- a/libcli/auth/proto.h
+++ b/libcli/auth/proto.h
@@ -144,6 +144,7 @@ DATA_BLOB NTLMv2_generate_names_blob(TALLOC_CTX *mem_ctx,
bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx,
const char *user, const char *domain, const uint8_t nt_hash[16],
const DATA_BLOB *server_chal,
+ const NTTIME *server_timestamp,
const DATA_BLOB *names_blob,
DATA_BLOB *lm_response, DATA_BLOB *nt_response,
DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) ;
@@ -154,6 +155,11 @@ bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ctx,
const DATA_BLOB *names_blob,
DATA_BLOB *lm_response, DATA_BLOB *nt_response,
DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) ;
+NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
+ const char *account_domain,
+ const DATA_BLOB response,
+ const struct netlogon_creds_CredentialState *creds,
+ const char *workgroup);
/***********************************************************
encode a password buffer with a unicode password. The buffer
diff --git a/libcli/auth/smbencrypt.c b/libcli/auth/smbencrypt.c
index ec819cd4db3..c88fbd6e28c 100644
--- a/libcli/auth/smbencrypt.c
+++ b/libcli/auth/smbencrypt.c
@@ -26,7 +26,7 @@
#include "../libcli/auth/msrpc_parse.h"
#include "../lib/crypto/crypto.h"
#include "../libcli/auth/libcli_auth.h"
-#include "../librpc/gen_ndr/ntlmssp.h"
+#include "../librpc/gen_ndr/ndr_ntlmssp.h"
void SMBencrypt_hash(const uint8_t lm_hash[16], const uint8_t *c8, uint8_t p24[24])
{
@@ -387,14 +387,13 @@ DATA_BLOB NTLMv2_generate_names_blob(TALLOC_CTX *mem_ctx,
return names_blob;
}
-static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx, const DATA_BLOB *names_blob)
+static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx,
+ NTTIME nttime,
+ const DATA_BLOB *names_blob)
{
uint8_t client_chal[8];
DATA_BLOB response = data_blob(NULL, 0);
uint8_t long_date[8];
- NTTIME nttime;
-
- unix_to_nt_time(&nttime, time(NULL));
generate_random_buffer(client_chal, sizeof(client_chal));
@@ -417,6 +416,7 @@ static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx, const DATA_BLO
static DATA_BLOB NTLMv2_generate_response(TALLOC_CTX *out_mem_ctx,
const uint8_t ntlm_v2_hash[16],
const DATA_BLOB *server_chal,
+ NTTIME nttime,
const DATA_BLOB *names_blob)
{
uint8_t ntlmv2_response[16];
@@ -433,7 +433,7 @@ static DATA_BLOB NTLMv2_generate_response(TALLOC_CTX *out_mem_ctx,
/* NTLMv2 */
/* generate some data to pass into the response function - including
the hostname and domain name of the server */
- ntlmv2_client_data = NTLMv2_generate_client_data(mem_ctx, names_blob);
+ ntlmv2_client_data = NTLMv2_generate_client_data(mem_ctx, nttime, names_blob);
/* Given that data, and the challenge from the server, generate a response */
SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &ntlmv2_client_data, ntlmv2_response);
@@ -479,6 +479,7 @@ static DATA_BLOB LMv2_generate_response(TALLOC_CTX *mem_ctx,
bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx,
const char *user, const char *domain, const uint8_t nt_hash[16],
const DATA_BLOB *server_chal,
+ const NTTIME *server_timestamp,
const DATA_BLOB *names_blob,
DATA_BLOB *lm_response, DATA_BLOB *nt_response,
DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key)
@@ -494,8 +495,19 @@ bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx,
}
if (nt_response) {
+ const NTTIME *nttime = server_timestamp;
+ NTTIME _now = 0;
+
+ if (nttime == NULL) {
+ struct timeval tv_now = timeval_current();
+ _now = timeval_to_nttime(&tv_now);
+ nttime = &_now;
+ }
+
*nt_response = NTLMv2_generate_response(mem_ctx,
- ntlm_v2_hash, server_chal,
+ ntlm_v2_hash,
+ server_chal,
+ *nttime,
names_blob);
if (user_session_key) {
*user_session_key = data_blob_talloc(mem_ctx, NULL, 16);
@@ -509,8 +521,13 @@ bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx,
/* LMv2 */
if (lm_response) {
- *lm_response = LMv2_generate_response(mem_ctx,
- ntlm_v2_hash, server_chal);
+ if (server_timestamp != NULL) {
+ *lm_response = data_blob_talloc_zero(mem_ctx, 24);
+ } else {
+ *lm_response = LMv2_generate_response(mem_ctx,
+ ntlm_v2_hash,
+ server_chal);
+ }
if (lm_session_key) {
*lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
@@ -535,10 +552,143 @@ bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ctx,
E_md4hash(password, nt_hash);
return SMBNTLMv2encrypt_hash(mem_ctx,
- user, domain, nt_hash, server_chal, names_blob,
+ user, domain, nt_hash,
+ server_chal, NULL, names_blob,
lm_response, nt_response, lm_session_key, user_session_key);
}
+NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
+ const char *account_domain,
+ const DATA_BLOB response,
+ const struct netlogon_creds_CredentialState *creds,
+ const char *workgroup)
+{
+ TALLOC_CTX *frame = NULL;
+ /* RespType + HiRespType */
+ static const char *magic = "\x01\x01";
+ int cmp;
+ struct NTLMv2_RESPONSE v2_resp;
+ enum ndr_err_code err;
+ const struct AV_PAIR *av_nb_cn = NULL;
+ const struct AV_PAIR *av_nb_dn = NULL;
+
+ if (response.length < 48) {
+ /*
+ * NTLMv2_RESPONSE has at least 48 bytes.
+ */
+ return NT_STATUS_OK;
+ }
+
+ cmp = memcmp(response.data + 16, magic, 2);
+ if (cmp != 0) {
+ /*
+ * It doesn't look like a valid NTLMv2_RESPONSE
+ */
+ return NT_STATUS_OK;
+ }
+
+ frame = talloc_stackframe();
+
+ err = ndr_pull_struct_blob(&response, frame, &v2_resp,
+ (ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ NTSTATUS status;
+ status = ndr_map_error2ntstatus(err);
+ DEBUG(2,("Failed to parse NTLMv2_RESPONSE "
+ "length %u - %s - %s\n",
+ (unsigned)response.length,
+ ndr_map_error2string(err),
+ nt_errstr(status)));
+ dump_data(2, response.data, response.length);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &v2_resp);
+ }
+
+ /*
+ * Make sure the netbios computer name in the
+ * NTLMv2_RESPONSE matches the computer name
+ * in the secure channel credentials for workstation
+ * trusts.
+ *
+ * And the netbios domain name matches our
+ * workgroup.
+ *
+ * This prevents workstations from requesting
+ * the session key of NTLMSSP sessions of clients
+ * to other hosts.
+ */
+ if (creds->secure_channel_type == SEC_CHAN_WKSTA) {
+ av_nb_cn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
+ MsvAvNbComputerName);
+ av_nb_dn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
+ MsvAvNbDomainName);
+ }
+
+ if (av_nb_cn != NULL) {
+ const char *v = NULL;
+ char *a = NULL;
+ size_t len;
+
+ v = av_nb_cn->Value.AvNbComputerName;
+
+ a = talloc_strdup(frame, creds->account_name);
+ if (a == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ len = strlen(a);
+ if (len > 0 && a[len - 1] == '$') {
+ a[len - 1] = '\0';
+ }
+
+ cmp = strcasecmp_m(a, v);
+ if (cmp != 0) {
+ DEBUG(2,("%s: NTLMv2_RESPONSE with "
+ "NbComputerName[%s] rejected "
+ "for user[%s\\%s] "
+ "against SEC_CHAN_WKSTA[%s/%s] "
+ "in workgroup[%s]\n",
+ __func__, v,
+ account_domain,
+ account_name,
+ creds->computer_name,
+ creds->account_name,
+ workgroup));
+ TALLOC_FREE(frame);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+ if (av_nb_dn != NULL) {
+ const char *v = NULL;
+
+ v = av_nb_dn->Value.AvNbDomainName;
+
+ cmp = strcasecmp_m(workgroup, v);
+ if (cmp != 0) {
+ DEBUG(2,("%s: NTLMv2_RESPONSE with "
+ "NbDomainName[%s] rejected "
+ "for user[%s\\%s] "
+ "against SEC_CHAN_WKSTA[%s/%s] "
+ "in workgroup[%s]\n",
+ __func__, v,
+ account_domain,
+ account_name,
+ creds->computer_name,
+ creds->account_name,
+ workgroup));
+ TALLOC_FREE(frame);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
/***********************************************************
encode a password buffer with a unicode password. The buffer
is filled with random data to make it harder to attack.
diff --git a/libcli/auth/spnego.h b/libcli/auth/spnego.h
index 539b90336f0..49645e06bff 100644
--- a/libcli/auth/spnego.h
+++ b/libcli/auth/spnego.h
@@ -45,7 +45,11 @@ enum spnego_negResult {
SPNEGO_ACCEPT_COMPLETED = 0,
SPNEGO_ACCEPT_INCOMPLETE = 1,
SPNEGO_REJECT = 2,
- SPNEGO_NONE_RESULT = 3
+ SPNEGO_REQUEST_MIC = 3,
+ /*
+ * The max value is 0xff (255) on the wire
+ */
+ SPNEGO_NONE_RESULT = 256
};
struct spnego_negTokenInit {
@@ -58,7 +62,7 @@ struct spnego_negTokenInit {
};
struct spnego_negTokenTarg {
- uint8_t negResult;
+ enum spnego_negResult negResult;
const char *supportedMech;
DATA_BLOB responseToken;
DATA_BLOB mechListMIC;
diff --git a/libcli/auth/spnego_parse.c b/libcli/auth/spnego_parse.c
index d4c5bdcfa5c..12303766a59 100644
--- a/libcli/auth/spnego_parse.c
+++ b/libcli/auth/spnego_parse.c
@@ -32,12 +32,12 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
- while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
+ while (!asn1_has_error(asn1) && 0 < asn1_tag_remaining(asn1)) {
int i;
uint8_t context;
if (!asn1_peek_uint8(asn1, &context)) {
- asn1->has_error = true;
+ asn1_set_error(asn1);
break;
}
@@ -51,10 +51,10 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
mechTypes = talloc(mem_ctx, const char *);
if (mechTypes == NULL) {
- asn1->has_error = true;
+ asn1_set_error(asn1);
return false;
}
- for (i = 0; !asn1->has_error &&
+ for (i = 0; !asn1_has_error(asn1) &&
0 < asn1_tag_remaining(asn1); i++) {
char *oid;
const char **p;
@@ -63,7 +63,7 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
const char *, i+2);
if (p == NULL) {
talloc_free(mechTypes);
- asn1->has_error = true;
+ asn1_set_error(asn1);
return false;
}
mechTypes = p;
@@ -97,7 +97,7 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
uint8_t type_peek;
if (!asn1_start_tag(asn1, ASN1_CONTEXT(3))) return false;
if (!asn1_peek_uint8(asn1, &type_peek)) {
- asn1->has_error = true;
+ asn1_set_error(asn1);
break;
}
if (type_peek == ASN1_OCTET_STRING) {
@@ -119,7 +119,7 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
break;
}
default:
- asn1->has_error = true;
+ asn1_set_error(asn1);
break;
}
}
@@ -127,7 +127,7 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
if (!asn1_end_tag(asn1)) return false;
if (!asn1_end_tag(asn1)) return false;
- return !asn1->has_error;
+ return !asn1_has_error(asn1);
}
static bool write_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenInit *token)
@@ -190,7 +190,7 @@ static bool write_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenIni
if (!asn1_pop_tag(asn1)) return false;
if (!asn1_pop_tag(asn1)) return false;
- return !asn1->has_error;
+ return !asn1_has_error(asn1);
}
static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
@@ -201,11 +201,13 @@ static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
- while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
+ while (!asn1_has_error(asn1) && 0 < asn1_tag_remaining(asn1)) {
uint8_t context;
+ uint8_t neg_result;
char *oid;
+
if (!asn1_peek_uint8(asn1, &context)) {
- asn1->has_error = true;
+ asn1_set_error(asn1);
break;
}
@@ -213,7 +215,8 @@ static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
case ASN1_CONTEXT(0):
if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
if (!asn1_start_tag(asn1, ASN1_ENUMERATED)) return false;
- if (!asn1_read_uint8(asn1, &token->negResult)) return false;
+ if (!asn1_read_uint8(asn1, &neg_result)) return false;
+ token->negResult = neg_result;
if (!asn1_end_tag(asn1)) return false;
if (!asn1_end_tag(asn1)) return false;
break;
@@ -234,7 +237,7 @@ static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
if (!asn1_end_tag(asn1)) return false;
break;
default:
- asn1->has_error = true;
+ asn1_set_error(asn1);
break;
}
}
@@ -242,7 +245,7 @@ static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
if (!asn1_end_tag(asn1)) return false;
if (!asn1_end_tag(asn1)) return false;
- return !asn1->has_error;
+ return !asn1_has_error(asn1);
}
static bool write_negTokenTarg(struct asn1_data *asn1, struct spnego_negTokenTarg *token)
@@ -279,7 +282,7 @@ static bool write_negTokenTarg(struct asn1_data *asn1, struct spnego_negTokenTar
if (!asn1_pop_tag(asn1)) return false;
if (!asn1_pop_tag(asn1)) return false;
- return !asn1->has_error;
+ return !asn1_has_error(asn1);
}
ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data *token)
@@ -302,7 +305,7 @@ ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data
if (!asn1_load(asn1, data)) goto err;
if (!asn1_peek_uint8(asn1, &context)) {
- asn1->has_error = true;
+ asn1_set_error(asn1);
} else {
switch (context) {
case ASN1_APPLICATION(0):
@@ -319,12 +322,14 @@ ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data
}
break;
default:
- asn1->has_error = true;
+ asn1_set_error(asn1);
break;
}
}
- if (!asn1->has_error) ret = asn1->ofs;
+ if (!asn1_has_error(asn1)) {
+ ret = asn1_current_ofs(asn1);
+ }
err:
@@ -353,15 +358,16 @@ ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_da
write_negTokenTarg(asn1, &spnego->negTokenTarg);
break;
default:
- asn1->has_error = true;
+ asn1_set_error(asn1);
break;
}
- if (!asn1->has_error) {
- *blob = data_blob_talloc(mem_ctx, asn1->data, asn1->length);
- ret = asn1->ofs;
+ if (!asn1_extract_blob(asn1, mem_ctx, blob)) {
+ goto err;
}
+ ret = asn1_current_ofs(asn1);
+
err:
asn1_free(asn1);
@@ -423,12 +429,11 @@ bool spnego_write_mech_types(TALLOC_CTX *mem_ctx,
if (!asn1_pop_tag(asn1)) goto err;
}
- if (asn1->has_error) {
+ if (asn1_has_error(asn1)) {
goto err;
}
- *blob = data_blob_talloc(mem_ctx, asn1->data, asn1->length);
- if (blob->length != asn1->length) {
+ if (!asn1_extract_blob(asn1, mem_ctx, blob)) {
goto err;
}
diff --git a/libcli/cldap/cldap.c b/libcli/cldap/cldap.c
index df81767a760..2d34337338a 100644
--- a/libcli/cldap/cldap.c
+++ b/libcli/cldap/cldap.c
@@ -220,7 +220,6 @@ nomem:
static bool cldap_socket_recv_dgram(struct cldap_socket *c,
struct cldap_incoming *in)
{
- DATA_BLOB blob;
struct asn1_data *asn1;
void *p;
struct cldap_search_state *search;
@@ -230,16 +229,12 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c,
goto error;
}
- blob = data_blob_const(in->buf, in->len);
-
asn1 = asn1_init(in);
if (!asn1) {
goto nomem;
}
- if (!asn1_load(asn1, blob)) {
- goto nomem;
- }
+ asn1_load_nocopy(asn1, in->buf, in->len);
in->ldap_msg = talloc(in, struct ldap_message);
if (in->ldap_msg == NULL) {
@@ -267,8 +262,11 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c,
search = talloc_get_type_abort(p, struct cldap_search_state);
search->response.in = talloc_move(search, &in);
+
search->response.asn1 = asn1;
- search->response.asn1->ofs = 0;
+
+ asn1_load_nocopy(search->response.asn1,
+ search->response.in->buf, search->response.in->len);
DLIST_REMOVE(c->searches.list, search);
diff --git a/libcli/ldap/ldap_message.c b/libcli/ldap/ldap_message.c
index ba94f4ccfac..a4e702a1917 100644
--- a/libcli/ldap/ldap_message.c
+++ b/libcli/ldap/ldap_message.c
@@ -322,7 +322,7 @@ static bool ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree
if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(7))) return false;
if (!asn1_write_LDAPString(data, tree->u.present.attr)) return false;
if (!asn1_pop_tag(data)) return false;
- return !data->has_error;
+ return !asn1_has_error(data);
case LDB_OP_APPROX:
/* approx test */
@@ -366,7 +366,7 @@ static bool ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree
default:
return false;
}
- return !data->has_error;
+ return !asn1_has_error(data);
}
static bool ldap_encode_response(struct asn1_data *data, struct ldap_Result *result)
@@ -691,7 +691,10 @@ _PUBLIC_ bool ldap_encode(struct ldap_message *msg,
if (!asn1_pop_tag(data)) goto err;
- *result = data_blob_talloc(mem_ctx, data->data, data->length);
+ if (!asn1_extract_blob(data, mem_ctx, result)) {
+ goto err;
+ }
+
asn1_free(data);
return true;
@@ -842,7 +845,8 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
if (!asn1_end_tag(data)) goto failed;
- if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
+ if (asn1_has_error(data) || (attrib == NULL) ||
+ (value.data == NULL)) {
goto failed;
}
@@ -954,7 +958,8 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
if (!asn1_end_tag(data)) goto failed;
- if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
+ if (asn1_has_error(data) || (attrib == NULL) ||
+ (value.data == NULL)) {
goto failed;
}
@@ -973,7 +978,8 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
if (!asn1_end_tag(data)) goto failed;
- if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
+ if (asn1_has_error(data) || (attrib == NULL) ||
+ (value.data == NULL)) {
goto failed;
}
@@ -1011,7 +1017,8 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
if (!asn1_end_tag(data)) goto failed;
- if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
+ if (asn1_has_error(data) || (attrib == NULL) ||
+ (value.data == NULL)) {
goto failed;
}
@@ -1609,7 +1616,7 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data,
}
if (!asn1_end_tag(data)) goto prot_err;
- if ((data->has_error) || (data->nesting != NULL)) {
+ if (asn1_has_error(data) || asn1_has_nesting(data)) {
return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
}
return NT_STATUS_OK;
@@ -1626,6 +1633,8 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data,
*/
NTSTATUS ldap_full_packet(void *private_data, DATA_BLOB blob, size_t *packet_size)
{
+ int ret;
+
if (blob.length < 6) {
/*
* We need at least 6 bytes to workout the length
@@ -1633,5 +1642,10 @@ NTSTATUS ldap_full_packet(void *private_data, DATA_BLOB blob, size_t *packet_siz
*/
return STATUS_MORE_ENTRIES;
}
- return asn1_peek_full_tag(blob, ASN1_SEQUENCE(0), packet_size);
+
+ ret = asn1_peek_full_tag(blob, ASN1_SEQUENCE(0), packet_size);
+ if (ret != 0) {
+ return map_nt_error_from_unix_common(ret);
+ }
+ return NT_STATUS_OK;
}
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index b00afbc2d5a..7bf48c80437 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -363,6 +363,7 @@ struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx,
conn->desire_signing = true;
conn->mandatory_signing = false;
break;
+ case SMB_SIGNING_IPC_DEFAULT:
case SMB_SIGNING_REQUIRED:
/* always */
conn->allow_signing = true;
diff --git a/libcli/smb/smb_constants.h b/libcli/smb/smb_constants.h
index 60588769025..9b1de5048d0 100644
--- a/libcli/smb/smb_constants.h
+++ b/libcli/smb/smb_constants.h
@@ -93,6 +93,7 @@ enum protocol_types {
#define PROTOCOL_LATEST PROTOCOL_SMB3_02
enum smb_signing_setting {
+ SMB_SIGNING_IPC_DEFAULT = -2, /* Only used in C code */
SMB_SIGNING_DEFAULT = -1,
SMB_SIGNING_OFF = 0,
SMB_SIGNING_IF_REQUIRED = 1,
diff --git a/libcli/smb/smb_signing.c b/libcli/smb/smb_signing.c
index e128e8f8a0b..a7bc819f489 100644
--- a/libcli/smb/smb_signing.c
+++ b/libcli/smb/smb_signing.c
@@ -424,6 +424,10 @@ bool smb_signing_set_negotiated(struct smb_signing_state *si,
return true;
}
+ if (mandatory) {
+ allowed = true;
+ }
+
if (!si->allowed && mandatory) {
return false;
}
diff --git a/libcli/smb/tstream_smbXcli_np.c b/libcli/smb/tstream_smbXcli_np.c
index 77a326b012d..248bfb02cfc 100644
--- a/libcli/smb/tstream_smbXcli_np.c
+++ b/libcli/smb/tstream_smbXcli_np.c
@@ -111,7 +111,11 @@ static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np *cli_nps)
* Once we've fixed all callers to call
* tstream_disconnect_send()/_recv(), this will
* never be called.
+ *
+ * We use a maximun timeout of 1 second == 1000 msec.
*/
+ cli_nps->timeout = MIN(cli_nps->timeout, 1000);
+
if (cli_nps->is_smb1) {
status = smb1cli_close(cli_nps->conn,
cli_nps->timeout,
@@ -632,7 +636,7 @@ static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq)
}
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
- tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
+ tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__);
return;
}
@@ -980,7 +984,7 @@ static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq)
status = NT_STATUS_OK;
}
if (!NT_STATUS_IS_OK(status)) {
- tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
+ tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
return;
}
@@ -1064,7 +1068,7 @@ static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq)
}
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(subreq);
- tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
+ tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
return;
}
@@ -1290,7 +1294,7 @@ static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
}
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
- tevent_req_error(req, EIO);
+ tevent_req_error(req, EPIPE);
return;
}
diff --git a/libcli/util/error.h b/libcli/util/error.h
index 0972601afb1..14614458473 100644
--- a/libcli/util/error.h
+++ b/libcli/util/error.h
@@ -22,6 +22,7 @@
#include "libcli/util/werror.h"
#include "libcli/util/doserr.h"
#include "libcli/util/ntstatus.h"
+#include "libcli/util/hresult.h"
/*****************************************************************************
convert a NT status code to a dos class/code
diff --git a/librpc/idl/dcerpc.idl b/librpc/idl/dcerpc.idl
index cb7f5b85430..015eb3d1815 100644
--- a/librpc/idl/dcerpc.idl
+++ b/librpc/idl/dcerpc.idl
@@ -106,7 +106,7 @@ interface dcerpc
uint16 max_xmit_frag;
uint16 max_recv_frag;
uint32 assoc_group_id;
- [value(strlen(secondary_address)+1)] uint16 secondary_address_size;
+ [value(strlen_m_term_null(secondary_address))] uint16 secondary_address_size;
[charset(DOS)] uint8 secondary_address[secondary_address_size];
[flag(NDR_ALIGN4)] DATA_BLOB _pad1;
uint8 num_results;
@@ -197,18 +197,21 @@ interface dcerpc
DCERPC_NCA_S_FAULT_TX_OPEN_FAILED = 0x1C000022,
DCERPC_NCA_S_FAULT_CODESET_CONV_ERROR = 0x1C000023,
DCERPC_NCA_S_FAULT_OBJECT_NOT_FOUND = 0x1C000024,
- DCERPC_NCA_S_FAULT_NO_CLIENT_STUB = 0x1C000025
+ DCERPC_NCA_S_FAULT_NO_CLIENT_STUB = 0x1C000025,
+ DCERPC_FAULT_ACCESS_DENIED = 0x00000005,
+ DCERPC_FAULT_NO_CALL_ACTIVE = 0x000006bd,
+ DCERPC_FAULT_CANT_PERFORM = 0x000006d8,
+ DCERPC_FAULT_OUT_OF_RESOURCES = 0x000006d9,
+ DCERPC_FAULT_BAD_STUB_DATA = 0x000006f7,
+ DCERPC_FAULT_SEC_PKG_ERROR = 0x00000721
} dcerpc_nca_status;
const int DCERPC_FAULT_OP_RNG_ERROR = DCERPC_NCA_S_OP_RNG_ERROR;
const int DCERPC_FAULT_UNK_IF = DCERPC_NCA_S_UNKNOWN_IF;
- const int DCERPC_FAULT_NDR = 0x000006f7;
+ const int DCERPC_FAULT_NDR = DCERPC_FAULT_BAD_STUB_DATA;
const int DCERPC_FAULT_INVALID_TAG = DCERPC_NCA_S_FAULT_INVALID_TAG;
const int DCERPC_FAULT_CONTEXT_MISMATCH = DCERPC_NCA_S_FAULT_CONTEXT_MISMATCH;
const int DCERPC_FAULT_OTHER = 0x00000001;
- const int DCERPC_FAULT_ACCESS_DENIED = 0x00000005;
- const int DCERPC_FAULT_CANT_PERFORM = 0x000006d8;
- const int DCERPC_FAULT_SEC_PKG_ERROR = 0x00000721;
/* we return this fault when we haven't yet run the test
to see what fault w2k3 returns in this case */
@@ -529,8 +532,10 @@ interface dcerpc
const uint8 DCERPC_PFC_OFFSET = 3;
const uint8 DCERPC_DREP_OFFSET = 4;
const uint8 DCERPC_FRAG_LEN_OFFSET = 8;
+ const uint32 DCERPC_FRAG_MAX_SIZE = 5840;
const uint8 DCERPC_AUTH_LEN_OFFSET = 10;
const uint8 DCERPC_NCACN_PAYLOAD_OFFSET = 16;
+ const uint32 DCERPC_NCACN_PAYLOAD_MAX_SIZE = 0x400000; /* 4 MByte */
/* little-endian flag */
const uint8 DCERPC_DREP_LE = 0x10;
diff --git a/librpc/idl/epmapper.idl b/librpc/idl/epmapper.idl
index 5f3d653961d..fd8eeb4c475 100644
--- a/librpc/idl/epmapper.idl
+++ b/librpc/idl/epmapper.idl
@@ -214,7 +214,7 @@ interface epmapper
epm_floor floors[num_floors];
} epm_tower;
- typedef struct {
+ typedef [public] struct {
[value(ndr_size_epm_tower(&tower, ndr->flags))] uint32 tower_length;
[subcontext(4)] epm_tower tower;
} epm_twr_t;
diff --git a/librpc/idl/ntlmssp.idl b/librpc/idl/ntlmssp.idl
index 7c3b8fe63ba..95b4f1186f8 100644
--- a/librpc/idl/ntlmssp.idl
+++ b/librpc/idl/ntlmssp.idl
@@ -1,5 +1,7 @@
#include "idl_types.h"
+import "security.idl";
+
/*
ntlmssp interface definition
*/
@@ -54,18 +56,21 @@ interface ntlmssp
/*
NTLMSSP_WINDOWS_MAJOR_VERSION_5: Windows XP SP2 and Server 2003
- NTLMSSP_WINDOWS_MAJOR_VERSION_6: Windows Vista, Server 2008, 7 and Server 2008 R2
+ NTLMSSP_WINDOWS_MAJOR_VERSION_6: Windows Vista, Server 2008, 7, Server 2008 R2, 8, Server 2012, 8.1, Server 2012 R2
+ NTLMSSP_WINDOWS_MAJOR_VERSION_10: Windows 10, Windows Server 2016 Technical Preview
*/
typedef [enum8bit] enum {
NTLMSSP_WINDOWS_MAJOR_VERSION_5 = 0x05,
- NTLMSSP_WINDOWS_MAJOR_VERSION_6 = 0x06
+ NTLMSSP_WINDOWS_MAJOR_VERSION_6 = 0x06,
+ NTLMSSP_WINDOWS_MAJOR_VERSION_10 = 0x0A
} ntlmssp_WindowsMajorVersion;
/*
- NTLMSSP_WINDOWS_MINOR_VERSION_0: Windows Vista, Server 2008, 7, Server 2008 R2
- NTLMSSP_WINDOWS_MINOR_VERSION_1: Windows XP SP2
- NTLMSSP_WINDOWS_MINOR_VERSION_2: Windows Server 2003
+ NTLMSSP_WINDOWS_MINOR_VERSION_0: Windows Vista, 10, Server 2016 Technical Preview
+ NTLMSSP_WINDOWS_MINOR_VERSION_1: Windows XP SP2, 7, Server 2008 R2
+ NTLMSSP_WINDOWS_MINOR_VERSION_2: Windows Server 2003, 8, Server 2012
+ NTLMSSP_WINDOWS_MINOR_VERSION_3: Windows 8.1, Server 2012 R2
*/
typedef [enum8bit] enum {
@@ -123,24 +128,24 @@ interface ntlmssp
MsvAvDnsTreeName = 5,
MsvAvFlags = 6,
MsvAvTimestamp = 7,
- MsAvRestrictions = 8,
+ MsvAvSingleHost = 8,
MsvAvTargetName = 9,
MsvChannelBindings = 10
} ntlmssp_AvId;
- /* [MS-NLMP] 2.2.2.2 Restriction_Encoding */
+ /* [MS-NLMP] 2.2.2.2 SingleHostData */
- typedef struct {
- uint32 Size;
+ typedef [flag(NDR_PAHEX)] struct {
+ [value(8+ndr_size_LSAP_TOKEN_INFO_INTEGRITY(&r->token_info, 0)+r->remaining.length)] uint32 Size;
[value(0)] uint32 Z4;
- boolean32 IntegrityLevel;
- uint32 SubjectIntegrityLevel;
- uint8 MachineId[32];
- } Restriction_Encoding;
+ LSAP_TOKEN_INFO_INTEGRITY token_info;
+ [flag(NDR_REMAINING)] DATA_BLOB remaining;
+ } ntlmssp_SingleHostData;
typedef [bitmap32bit] bitmap {
NTLMSSP_AVFLAG_CONSTRAINTED_ACCOUNT = 0x00000001,
- NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE = 0x00000002
+ NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE = 0x00000002,
+ NTLMSSP_AVFLAG_TARGET_SPN_FROM_UNTRUSTED_SOURCE = 0x00000004
} ntlmssp_AvFlags;
typedef [gensize,nodiscriminant,flag(NDR_NOALIGN)] union {
@@ -152,7 +157,7 @@ interface ntlmssp
[case(MsvAvDnsTreeName)] [flag(ndr_ntlmssp_negotiated_string_flags(NTLMSSP_NEGOTIATE_UNICODE))] string AvDnsTreeName;
[case(MsvAvFlags)] ntlmssp_AvFlags AvFlags;
[case(MsvAvTimestamp)] NTTIME AvTimestamp;
- [case(MsAvRestrictions)] Restriction_Encoding AvRestrictions;
+ [case(MsvAvSingleHost)] ntlmssp_SingleHostData AvSingleHost;
[case(MsvAvTargetName)] [flag(ndr_ntlmssp_negotiated_string_flags(NTLMSSP_NEGOTIATE_UNICODE))] string AvTargetName;
[case(MsvChannelBindings)] uint8 ChannelBindings[16];
[default] [flag(NDR_REMAINING)] DATA_BLOB blob;
@@ -166,7 +171,7 @@ interface ntlmssp
[subcontext(0),subcontext_size(AvLen),switch_is(AvId)] ntlmssp_AvValue Value;
} AV_PAIR;
- typedef [gensize,nopush,nopull,flag(NDR_NOALIGN)] struct {
+ typedef [public,gensize,nopush,nopull,flag(NDR_NOALIGN)] struct {
uint32 count;
AV_PAIR pair[count];
} AV_PAIR_LIST;
@@ -183,7 +188,7 @@ interface ntlmssp
uint8 ServerChallenge[8];
uint8 Reserved[8];
[value(ndr_size_AV_PAIR_LIST(TargetInfo, ndr->flags))] uint16 TargetInfoLen;
- [value(TargetInfoLen)] uint16 TargetNameInfoMaxLen;
+ [value(TargetInfoLen)] uint16 TargetInfoMaxLen;
[relative] [subcontext(0),subcontext_size(TargetInfoLen)] AV_PAIR_LIST *TargetInfo;
[switch_is(NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)] ntlmssp_Version Version;
} CHALLENGE_MESSAGE;
@@ -238,9 +243,12 @@ interface ntlmssp
[default] NTLMv2_RESPONSE v2;
} ntlmssp_NTLM_RESPONSE;
+ const int NTLMSSP_MIC_OFFSET = 72;
+ const int NTLMSSP_MIC_SIZE = 16;
+
typedef [flag(NDR_PAHEX)] struct {
- uint8 MIC[16];
- } MIC;
+ uint8 MIC[NTLMSSP_MIC_SIZE];
+ } ntlmssp_MIC;
/* [MS-NLMP] 2.2.1.3 AUTHENTICATE_MESSAGE */
@@ -269,7 +277,7 @@ interface ntlmssp
[switch_is(NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)] ntlmssp_Version Version;
/* MIC (Message Integrity) is only included when the client has
* sent a timestap Av struct in the CHALLENGE_MESSAGE AvPair */
- /* [flag(NDR_REMAINING)] MIC mic; */
+ /* [flag(NDR_REMAINING)] ntlmssp_MIC mic; */
} AUTHENTICATE_MESSAGE;
/* NTLMSSP signature version */
diff --git a/librpc/idl/security.idl b/librpc/idl/security.idl
index 78c13c99504..88d8936ab78 100644
--- a/librpc/idl/security.idl
+++ b/librpc/idl/security.idl
@@ -648,12 +648,28 @@ interface security
SECINFO_BACKUP |
0);
+ /*
+ * See [MS-KILE] 2.2.5 LSAP_TOKEN_INFO_INTEGRITY
+ */
+ typedef [public,gensize,flag(NDR_PAHEX)] struct {
+ uint32 Flags;
+ uint32 TokenIL;
+ uint8 MachineId[32];
+ } LSAP_TOKEN_INFO_INTEGRITY;
+
+ /*
+ * See [MS-KILE] 2.2.6 Supported Encryption Types Bit Flags
+ */
typedef [public,bitmap32bit] bitmap {
KERB_ENCTYPE_DES_CBC_CRC = 0x00000001,
KERB_ENCTYPE_DES_CBC_MD5 = 0x00000002,
KERB_ENCTYPE_RC4_HMAC_MD5 = 0x00000004,
KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 = 0x00000008,
- KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96 = 0x00000010
+ KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96 = 0x00000010,
+ KERB_ENCTYPE_FAST_SUPPORTED = 0x00010000,
+ KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED = 0x00020000,
+ KERB_ENCTYPE_CLAIMS_SUPPORTED = 0x00040000,
+ KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED = 0x00080000
} kerb_EncTypes;
typedef [public,bitmap32bit] bitmap {
diff --git a/librpc/ndr/ndr_basic.c b/librpc/ndr/ndr_basic.c
index a6cf607f3eb..ea3a2d43613 100644
--- a/librpc/ndr/ndr_basic.c
+++ b/librpc/ndr/ndr_basic.c
@@ -1204,11 +1204,11 @@ _PUBLIC_ void ndr_print_array_uint8(struct ndr_print *ndr, const char *name,
#undef _ONELINE_LIMIT
}
-static void ndr_print_asc(struct ndr_print *ndr, const uint8_t *buf, int len)
+static void ndr_print_dump_data_cb(const char *buf, void *private_data)
{
- int i;
- for (i=0;i<len;i++)
- ndr->print(ndr, "%c", isprint(buf[i])?buf[i]:'.');
+ struct ndr_print *ndr = (struct ndr_print *)private_data;
+
+ ndr->print(ndr, "%s", buf);
}
/*
@@ -1216,37 +1216,8 @@ static void ndr_print_asc(struct ndr_print *ndr, const uint8_t *buf, int len)
*/
static void ndr_dump_data(struct ndr_print *ndr, const uint8_t *buf, int len)
{
- int i=0;
-
ndr->no_newline = true;
-
- for (i=0;i<len;) {
- if (i%16 == 0 && i<len) {
- ndr->print(ndr, "[%04X] ",i);
- }
-
- ndr->print(ndr, "%02X ",(int)buf[i]);
- i++;
- if (i%8 == 0) ndr->print(ndr," ");
- if (i%16 == 0) {
- ndr_print_asc(ndr,&buf[i-16],8); ndr->print(ndr," ");
- ndr_print_asc(ndr,&buf[i-8],8); ndr->print(ndr, "\n");
- }
- }
-
- if (i%16) {
- int n;
- n = 16 - (i%16);
- ndr->print(ndr, " ");
- if (n>8) ndr->print(ndr," ");
- while (n--) ndr->print(ndr," ");
- n = MIN(8,i%16);
- ndr_print_asc(ndr,&buf[i-(i%16)],n); ndr->print(ndr, " ");
- n = (i%16) - n;
- if (n>0) ndr_print_asc(ndr,&buf[i-n],n);
- ndr->print(ndr,"\n");
- }
-
+ dump_data_cb(buf, len, true, ndr_print_dump_data_cb, ndr);
ndr->no_newline = false;
}
diff --git a/librpc/ndr/ndr_ntlmssp.c b/librpc/ndr/ndr_ntlmssp.c
index d024da5ed8e..7027ac0b13d 100644
--- a/librpc/ndr/ndr_ntlmssp.c
+++ b/librpc/ndr/ndr_ntlmssp.c
@@ -176,4 +176,20 @@ _PUBLIC_ void ndr_print_ntlmssp_Version(struct ndr_print *ndr, const char *name,
}
}
+_PUBLIC_ struct AV_PAIR *ndr_ntlmssp_find_av(const struct AV_PAIR_LIST *av_list,
+ enum ntlmssp_AvId AvId)
+{
+ struct AV_PAIR *res = NULL;
+ uint32_t i = 0;
+
+ for (i = 0; i < av_list->count; i++) {
+ if (av_list->pair[i].AvId != AvId) {
+ continue;
+ }
+ res = discard_const_p(struct AV_PAIR, &av_list->pair[i]);
+ break;
+ }
+
+ return res;
+}
diff --git a/librpc/ndr/ndr_ntlmssp.h b/librpc/ndr/ndr_ntlmssp.h
index e07ff15cf6f..5c979ffa4f7 100644
--- a/librpc/ndr/ndr_ntlmssp.h
+++ b/librpc/ndr/ndr_ntlmssp.h
@@ -31,3 +31,5 @@ _PUBLIC_ void ndr_print_ntlmssp_lm_response(TALLOC_CTX *mem_ctx,
bool ntlmv2);
_PUBLIC_ void ndr_print_ntlmssp_Version(struct ndr_print *ndr, const char *name, const union ntlmssp_Version *r);
+_PUBLIC_ struct AV_PAIR *ndr_ntlmssp_find_av(const struct AV_PAIR_LIST *av_list,
+ enum ntlmssp_AvId AvId);
diff --git a/librpc/rpc/binding.c b/librpc/rpc/binding.c
index 37e0c4f54f6..6407a8d4ee1 100644
--- a/librpc/rpc/binding.c
+++ b/librpc/rpc/binding.c
@@ -591,7 +591,7 @@ _PUBLIC_ void dcerpc_binding_get_auth_info(const struct dcerpc_binding *b,
} else if (b->flags & DCERPC_CONNECT) {
auth_level = DCERPC_AUTH_LEVEL_CONNECT;
} else if (auth_type != DCERPC_AUTH_TYPE_NONE) {
- auth_level = DCERPC_AUTH_LEVEL_CONNECT;
+ auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
} else {
auth_level = DCERPC_AUTH_LEVEL_NONE;
}
diff --git a/librpc/rpc/dcerpc_error.c b/librpc/rpc/dcerpc_error.c
index 4f0ed6e5dfa..f38602528d6 100644
--- a/librpc/rpc/dcerpc_error.c
+++ b/librpc/rpc/dcerpc_error.c
@@ -26,58 +26,74 @@
struct dcerpc_fault_table {
const char *errstr;
uint32_t faultcode;
+ NTSTATUS nt_status;
};
static const struct dcerpc_fault_table dcerpc_faults[] =
{
-#define _FAULT_STR(x) { #x , x }
- _FAULT_STR(DCERPC_NCA_S_COMM_FAILURE),
- _FAULT_STR(DCERPC_NCA_S_OP_RNG_ERROR),
- _FAULT_STR(DCERPC_NCA_S_UNKNOWN_IF),
- _FAULT_STR(DCERPC_NCA_S_WRONG_BOOT_TIME),
- _FAULT_STR(DCERPC_NCA_S_YOU_CRASHED),
- _FAULT_STR(DCERPC_NCA_S_PROTO_ERROR),
- _FAULT_STR(DCERPC_NCA_S_OUT_ARGS_TOO_BIG),
- _FAULT_STR(DCERPC_NCA_S_SERVER_TOO_BUSY),
- _FAULT_STR(DCERPC_NCA_S_FAULT_STRING_TOO_LARGE),
- _FAULT_STR(DCERPC_NCA_S_UNSUPPORTED_TYPE),
- _FAULT_STR(DCERPC_NCA_S_FAULT_INT_DIV_BY_ZERO),
- _FAULT_STR(DCERPC_NCA_S_FAULT_ADDR_ERROR),
- _FAULT_STR(DCERPC_NCA_S_FAULT_FP_DIV_BY_ZERO),
- _FAULT_STR(DCERPC_NCA_S_FAULT_FP_UNDERFLOW),
- _FAULT_STR(DCERPC_NCA_S_FAULT_FP_OVERRFLOW),
- _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_TAG),
- _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_BOUND),
- _FAULT_STR(DCERPC_NCA_S_FAULT_RPC_VERSION_MISMATCH),
- _FAULT_STR(DCERPC_NCA_S_FAULT_UNSPEC_REJECT),
- _FAULT_STR(DCERPC_NCA_S_FAULT_BAD_ACTID),
- _FAULT_STR(DCERPC_NCA_S_FAULT_WHO_ARE_YOU_FAILED),
- _FAULT_STR(DCERPC_NCA_S_FAULT_MANAGER_NOT_ENTERED),
- _FAULT_STR(DCERPC_NCA_S_FAULT_CANCEL),
- _FAULT_STR(DCERPC_NCA_S_FAULT_ILL_INST),
- _FAULT_STR(DCERPC_NCA_S_FAULT_FP_ERROR),
- _FAULT_STR(DCERPC_NCA_S_FAULT_INT_OVERFLOW),
- _FAULT_STR(DCERPC_NCA_S_UNUSED_1C000011),
- _FAULT_STR(DCERPC_NCA_S_FAULT_UNSPEC),
- _FAULT_STR(DCERPC_NCA_S_FAULT_REMOTE_COMM_FAILURE),
- _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_EMPTY),
- _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_CLOSED),
- _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_ORDER),
- _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_DISCIPLINE),
- _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_COMM_ERROR),
- _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_MEMORY),
- _FAULT_STR(DCERPC_NCA_S_FAULT_CONTEXT_MISMATCH),
- _FAULT_STR(DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY),
- _FAULT_STR(DCERPC_NCA_S_INVALID_PRES_CONTEXT_ID),
- _FAULT_STR(DCERPC_NCA_S_UNSUPPORTED_AUTHN_LEVEL),
- _FAULT_STR(DCERPC_NCA_S_UNUSED_1C00001E),
- _FAULT_STR(DCERPC_NCA_S_INVALID_CHECKSUM),
- _FAULT_STR(DCERPC_NCA_S_INVALID_CRC),
- _FAULT_STR(DCERPC_NCA_S_FAULT_USER_DEFINED),
- _FAULT_STR(DCERPC_NCA_S_FAULT_TX_OPEN_FAILED),
- _FAULT_STR(DCERPC_NCA_S_FAULT_CODESET_CONV_ERROR),
- _FAULT_STR(DCERPC_NCA_S_FAULT_OBJECT_NOT_FOUND),
- _FAULT_STR(DCERPC_NCA_S_FAULT_NO_CLIENT_STUB),
+#define _FAULT_STR(x, s) { .errstr = #x , .faultcode = x, .nt_status = s }
+#define _FAULT_STR_NO_NT_MAPPING(x) _FAULT_STR(x, NT_STATUS_RPC_NOT_RPC_ERROR)
+ _FAULT_STR(DCERPC_NCA_S_COMM_FAILURE, NT_STATUS_RPC_COMM_FAILURE),
+ _FAULT_STR(DCERPC_NCA_S_OP_RNG_ERROR, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE),
+ _FAULT_STR(DCERPC_NCA_S_UNKNOWN_IF, NT_STATUS_RPC_UNKNOWN_IF),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_WRONG_BOOT_TIME),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_YOU_CRASHED),
+ _FAULT_STR(DCERPC_NCA_S_PROTO_ERROR, NT_STATUS_RPC_PROTOCOL_ERROR),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_OUT_ARGS_TOO_BIG),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_SERVER_TOO_BUSY),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_STRING_TOO_LARGE),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_UNSUPPORTED_TYPE),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_ADDR_ERROR),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_FP_DIV_BY_ZERO, NT_STATUS_RPC_FP_DIV_ZERO),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_FP_UNDERFLOW, NT_STATUS_RPC_FP_UNDERFLOW),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_FP_OVERRFLOW, NT_STATUS_RPC_FP_OVERFLOW),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_INT_DIV_BY_ZERO, NT_STATUS_RPC_FP_DIV_ZERO),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_INT_OVERFLOW, NT_STATUS_RPC_FP_OVERFLOW),
+ /*
+ * What's the difference between NT_STATUS_RPC_INVALID_TAG
+ * and NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE ???
+ *
+ * Our callers expect NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
+ */
+ _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_TAG, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_TAG, NT_STATUS_RPC_INVALID_TAG),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_BOUND, NT_STATUS_RPC_INVALID_BOUND),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_RPC_VERSION_MISMATCH, NT_STATUS_RPC_PROTOCOL_ERROR),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_UNSPEC_REJECT),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_BAD_ACTID),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_WHO_ARE_YOU_FAILED),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_MANAGER_NOT_ENTERED),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_CANCEL, NT_STATUS_RPC_CALL_CANCELLED),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_ILL_INST),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_FP_ERROR),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_UNUSED_1C000011),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_UNSPEC),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_REMOTE_COMM_FAILURE),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_PIPE_EMPTY),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_CLOSED, NT_STATUS_RPC_PIPE_CLOSED),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_PIPE_ORDER),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_DISCIPLINE, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_PIPE_COMM_ERROR),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_PIPE_MEMORY),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_CONTEXT_MISMATCH, NT_STATUS_RPC_SS_CONTEXT_MISMATCH),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_INVALID_PRES_CONTEXT_ID),
+ _FAULT_STR(DCERPC_NCA_S_UNSUPPORTED_AUTHN_LEVEL, NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_UNUSED_1C00001E),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_INVALID_CHECKSUM),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_INVALID_CRC),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_USER_DEFINED),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_TX_OPEN_FAILED),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_CODESET_CONV_ERROR),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_OBJECT_NOT_FOUND),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_NO_CLIENT_STUB),
+ _FAULT_STR(DCERPC_FAULT_OTHER, NT_STATUS_RPC_CALL_FAILED),
+ _FAULT_STR(DCERPC_FAULT_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED),
+ _FAULT_STR(DCERPC_FAULT_NO_CALL_ACTIVE, NT_STATUS_RPC_NO_CALL_ACTIVE),
+ _FAULT_STR(DCERPC_FAULT_CANT_PERFORM, NT_STATUS_EPT_CANT_PERFORM_OP),
+ _FAULT_STR(DCERPC_FAULT_OUT_OF_RESOURCES, NT_STATUS_RPC_OUT_OF_RESOURCES),
+ _FAULT_STR(DCERPC_FAULT_BAD_STUB_DATA, NT_STATUS_RPC_BAD_STUB_DATA),
+ _FAULT_STR(DCERPC_FAULT_SEC_PKG_ERROR, NT_STATUS_RPC_SEC_PKG_ERROR),
{ NULL, 0 }
#undef _FAULT_STR
};
@@ -99,26 +115,40 @@ _PUBLIC_ const char *dcerpc_errstr(TALLOC_CTX *mem_ctx, uint32_t fault_code)
_PUBLIC_ NTSTATUS dcerpc_fault_to_nt_status(uint32_t fault_code)
{
- /* TODO: add more mappings */
- switch (fault_code) {
- case DCERPC_NCA_S_OP_RNG_ERROR:
- return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE;
- case DCERPC_NCA_S_UNKNOWN_IF:
- return NT_STATUS_RPC_UNKNOWN_IF;
- case DCERPC_FAULT_NDR:
- return NT_STATUS_RPC_BAD_STUB_DATA;
- case DCERPC_NCA_S_FAULT_INVALID_TAG:
- return NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE;
- case DCERPC_NCA_S_FAULT_CONTEXT_MISMATCH:
- return NT_STATUS_RPC_SS_CONTEXT_MISMATCH;
- case DCERPC_FAULT_OTHER:
- return NT_STATUS_RPC_CALL_FAILED;
- case DCERPC_FAULT_ACCESS_DENIED:
- return NT_STATUS_ACCESS_DENIED;
- case DCERPC_FAULT_SEC_PKG_ERROR:
- return NT_STATUS_RPC_SEC_PKG_ERROR;
+ int idx = 0;
+ WERROR werr = W_ERROR(fault_code);
+
+ if (fault_code == 0) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
}
- return NT_STATUS_RPC_PROTOCOL_ERROR;
+ while (dcerpc_faults[idx].errstr != NULL) {
+ if (dcerpc_faults[idx].faultcode == fault_code) {
+ return dcerpc_faults[idx].nt_status;
+ }
+ idx++;
+ }
+
+ return werror_to_ntstatus(werr);
}
+_PUBLIC_ uint32_t dcerpc_fault_from_nt_status(NTSTATUS nt_status)
+{
+ int idx = 0;
+ WERROR werr;
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ return DCERPC_NCA_S_PROTO_ERROR;
+ }
+
+ while (dcerpc_faults[idx].errstr != NULL) {
+ if (NT_STATUS_EQUAL(dcerpc_faults[idx].nt_status, nt_status)) {
+ return dcerpc_faults[idx].faultcode;
+ }
+ idx++;
+ }
+
+ werr = ntstatus_to_werror(nt_status);
+
+ return W_ERROR_V(werr);
+}
diff --git a/librpc/rpc/dcerpc_util.c b/librpc/rpc/dcerpc_util.c
index a4dd56986ae..43e1b7f426f 100644
--- a/librpc/rpc/dcerpc_util.c
+++ b/librpc/rpc/dcerpc_util.c
@@ -83,31 +83,49 @@ uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob)
*
* @return - A NTSTATUS error code.
*/
-NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
+NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
TALLOC_CTX *mem_ctx,
- DATA_BLOB *pkt_trailer,
+ const DATA_BLOB *pkt_trailer,
struct dcerpc_auth *auth,
- uint32_t *auth_length,
+ uint32_t *_auth_length,
bool auth_data_only)
{
struct ndr_pull *ndr;
enum ndr_err_code ndr_err;
- uint32_t data_and_pad;
+ uint16_t data_and_pad;
+ uint16_t auth_length;
+ uint32_t tmp_length;
- data_and_pad = pkt_trailer->length
- - (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length);
+ ZERO_STRUCTP(auth);
+ if (_auth_length != NULL) {
+ *_auth_length = 0;
+ }
- /* paranoia check for pad size. This would be caught anyway by
- the ndr_pull_advance() a few lines down, but it scared
- Jeremy enough for him to call me, so we might as well check
- it now, just to prevent someone posting a bogus YouTube
- video in the future.
- */
- if (data_and_pad > pkt_trailer->length) {
- return NT_STATUS_INFO_LENGTH_MISMATCH;
+ /* Paranoia checks for auth_length. The caller should check this... */
+ if (pkt->auth_length == 0) {
+ return NT_STATUS_INTERNAL_ERROR;
}
- *auth_length = pkt_trailer->length - data_and_pad;
+ /* Paranoia checks for auth_length. The caller should check this... */
+ if (pkt->auth_length > pkt->frag_length) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ tmp_length = DCERPC_NCACN_PAYLOAD_OFFSET;
+ tmp_length += DCERPC_AUTH_TRAILER_LENGTH;
+ tmp_length += pkt->auth_length;
+ if (tmp_length > pkt->frag_length) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ if (pkt_trailer->length > UINT16_MAX) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ auth_length = DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length;
+ if (pkt_trailer->length < auth_length) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ data_and_pad = pkt_trailer->length - auth_length;
ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx);
if (!ndr) {
@@ -127,14 +145,28 @@ NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
talloc_free(ndr);
+ ZERO_STRUCTP(auth);
return ndr_map_error2ntstatus(ndr_err);
}
+ if (data_and_pad < auth->auth_pad_length) {
+ DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
+ "Calculated %u got %u\n",
+ (unsigned)data_and_pad,
+ (unsigned)auth->auth_pad_length));
+ talloc_free(ndr);
+ ZERO_STRUCTP(auth);
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
if (auth_data_only && data_and_pad != auth->auth_pad_length) {
- DEBUG(1, (__location__ ": WARNING: pad length mismatch. "
+ DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
"Calculated %u got %u\n",
(unsigned)data_and_pad,
(unsigned)auth->auth_pad_length));
+ talloc_free(ndr);
+ ZERO_STRUCTP(auth);
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
}
DEBUG(6,(__location__ ": auth_pad_length %u\n",
@@ -143,6 +175,83 @@ NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
talloc_steal(mem_ctx, auth->credentials.data);
talloc_free(ndr);
+ if (_auth_length != NULL) {
+ *_auth_length = auth_length;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+* @brief Verify the fields in ncacn_packet header.
+*
+* @param pkt - The ncacn_packet strcuture
+* @param ptype - The expected PDU type
+* @param max_auth_info - The maximum size of a possible auth trailer
+* @param required_flags - The required flags for the pdu.
+* @param optional_flags - The possible optional flags for the pdu.
+*
+* @return - A NTSTATUS error code.
+*/
+NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
+ enum dcerpc_pkt_type ptype,
+ size_t max_auth_info,
+ uint8_t required_flags,
+ uint8_t optional_flags)
+{
+ if (pkt->rpc_vers != 5) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (pkt->rpc_vers_minor != 0) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (pkt->auth_length > pkt->frag_length) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (pkt->ptype != ptype) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (max_auth_info > UINT16_MAX) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (pkt->auth_length > 0) {
+ size_t max_auth_length;
+
+ if (max_auth_info <= DCERPC_AUTH_TRAILER_LENGTH) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+ max_auth_length = max_auth_info - DCERPC_AUTH_TRAILER_LENGTH;
+
+ if (pkt->auth_length > max_auth_length) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+ }
+
+ if ((pkt->pfc_flags & required_flags) != required_flags) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+ if (pkt->pfc_flags & ~(optional_flags|required_flags)) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (pkt->drep[0] & ~DCERPC_DREP_LE) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+ if (pkt->drep[1] != 0) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+ if (pkt->drep[2] != 0) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+ if (pkt->drep[3] != 0) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
return NT_STATUS_OK;
}
@@ -652,3 +761,66 @@ bool dcerpc_sec_verification_trailer_check(
return true;
}
+
+static const struct ndr_syntax_id dcerpc_bind_time_features_prefix = {
+ .uuid = {
+ .time_low = 0x6cb71c2c,
+ .time_mid = 0x9812,
+ .time_hi_and_version = 0x4540,
+ .clock_seq = {0x00, 0x00},
+ .node = {0x00,0x00,0x00,0x00,0x00,0x00}
+ },
+ .if_version = 1,
+};
+
+bool dcerpc_extract_bind_time_features(struct ndr_syntax_id s, uint64_t *_features)
+{
+ uint8_t values[8];
+ uint64_t features = 0;
+
+ values[0] = s.uuid.clock_seq[0];
+ values[1] = s.uuid.clock_seq[1];
+ values[2] = s.uuid.node[0];
+ values[3] = s.uuid.node[1];
+ values[4] = s.uuid.node[2];
+ values[5] = s.uuid.node[3];
+ values[6] = s.uuid.node[4];
+ values[7] = s.uuid.node[5];
+
+ ZERO_STRUCT(s.uuid.clock_seq);
+ ZERO_STRUCT(s.uuid.node);
+
+ if (!ndr_syntax_id_equal(&s, &dcerpc_bind_time_features_prefix)) {
+ if (_features != NULL) {
+ *_features = 0;
+ }
+ return false;
+ }
+
+ features = BVAL(values, 0);
+
+ if (_features != NULL) {
+ *_features = features;
+ }
+
+ return true;
+}
+
+struct ndr_syntax_id dcerpc_construct_bind_time_features(uint64_t features)
+{
+ struct ndr_syntax_id s = dcerpc_bind_time_features_prefix;
+ uint8_t values[8];
+
+ SBVAL(values, 0, features);
+
+ s.uuid.clock_seq[0] = values[0];
+ s.uuid.clock_seq[1] = values[1];
+ s.uuid.node[0] = values[2];
+ s.uuid.node[1] = values[3];
+ s.uuid.node[2] = values[4];
+ s.uuid.node[3] = values[5];
+ s.uuid.node[4] = values[6];
+ s.uuid.node[5] = values[7];
+
+ return s;
+}
diff --git a/librpc/rpc/rpc_common.h b/librpc/rpc/rpc_common.h
index 45d36912030..da6c2a28ea6 100644
--- a/librpc/rpc/rpc_common.h
+++ b/librpc/rpc/rpc_common.h
@@ -106,6 +106,7 @@ struct dcerpc_binding;
const char *dcerpc_errstr(TALLOC_CTX *mem_ctx, uint32_t fault_code);
NTSTATUS dcerpc_fault_to_nt_status(uint32_t fault_code);
+uint32_t dcerpc_fault_from_nt_status(NTSTATUS nt_status);
/* The following definitions come from ../librpc/rpc/binding.c */
@@ -183,12 +184,17 @@ const char *dcerpc_default_transport_endpoint(TALLOC_CTX *mem_ctx,
*
* @return - A NTSTATUS error code.
*/
-NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
+NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
TALLOC_CTX *mem_ctx,
- DATA_BLOB *pkt_trailer,
+ const DATA_BLOB *pkt_trailer,
struct dcerpc_auth *auth,
uint32_t *auth_length,
bool auth_data_only);
+NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
+ enum dcerpc_pkt_type ptype,
+ size_t max_auth_info,
+ uint8_t required_flags,
+ uint8_t optional_flags);
struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct tstream_context *stream);
@@ -370,6 +376,36 @@ bool dcerpc_sec_verification_trailer_check(
const struct dcerpc_sec_vt_pcontext *pcontext,
const struct dcerpc_sec_vt_header2 *header2);
+/**
+ * @brief check and optionally extract the Bind Time Features from
+ * the given ndr_syntax_id.
+ *
+ * <a href="http://msdn.microsoft.com/en-us/library/cc243715.aspx">MS-RPCE 3.3.1.5.3 Bind Time Feature Negotiation</a>.
+ *
+ * @param[in] s the syntax that should be checked.
+ *
+ * @param[out] features This is optional, it will be filled with the extracted
+ * features the on success, otherwise it's filled with 0.
+ *
+ * @return true if the syntax matches the 6CB71C2C-9812-4540 prefix with version 1, false otherwise.
+ *
+ * @see dcerpc_construct_bind_time_features
+ */
+bool dcerpc_extract_bind_time_features(struct ndr_syntax_id syntax, uint64_t *features);
+
+/**
+ * @brief Construct a ndr_syntax_id used for Bind Time Features Negotiation.
+ *
+ * <a href="http://msdn.microsoft.com/en-us/library/cc243715.aspx">MS-RPCE 3.3.1.5.3 Bind Time Feature Negotiation</a>.
+ *
+ * @param[in] features The supported features.
+ *
+ * @return The ndr_syntax_id with the given features.
+ *
+ * @see dcerpc_extract_bind_time_features
+ */
+struct ndr_syntax_id dcerpc_construct_bind_time_features(uint64_t features);
+
#define DCERPC_AUTH_PAD_LENGTH(stub_length) (\
(((stub_length) % DCERPC_AUTH_PAD_ALIGNMENT) > 0)?\
(DCERPC_AUTH_PAD_ALIGNMENT - (stub_length) % DCERPC_AUTH_PAD_ALIGNMENT):\
diff --git a/nsswitch/libwbclient/wbc_pam.c b/nsswitch/libwbclient/wbc_pam.c
index 390d73ef278..4ae2de1f810 100644
--- a/nsswitch/libwbclient/wbc_pam.c
+++ b/nsswitch/libwbclient/wbc_pam.c
@@ -1290,7 +1290,17 @@ wbcErr wbcCtxCredentialCache(struct wbcContext *ctx,
}
for (i=0; i<params->num_blobs; i++) {
- if (strcasecmp(params->blobs[i].name, "initial_blob") == 0) {
+ /*
+ * Older callers may used to provide the NEGOTIATE request
+ * as "initial_blob", but it was completely ignored by winbindd.
+ *
+ * So we keep ignoring it.
+ *
+ * A new callers that is capable to support "new_spnego",
+ * will provide the NEGOTIATE request as "negotiate_blob"
+ * instead.
+ */
+ if (strcasecmp(params->blobs[i].name, "negotiate_blob") == 0) {
if (initial_blob != NULL) {
status = WBC_ERR_INVALID_PARAM;
goto fail;
@@ -1388,6 +1398,15 @@ wbcErr wbcCtxCredentialCache(struct wbcContext *ctx,
if (!WBC_ERROR_IS_OK(status)) {
goto fail;
}
+ if (response.data.ccache_ntlm_auth.new_spnego) {
+ status = wbcAddNamedBlob(
+ &result->num_blobs, &result->blobs, "new_spnego", 0,
+ &response.data.ccache_ntlm_auth.new_spnego,
+ sizeof(response.data.ccache_ntlm_auth.new_spnego));
+ if (!WBC_ERROR_IS_OK(status)) {
+ goto fail;
+ }
+ }
*info = result;
result = NULL;
diff --git a/nsswitch/winbind_struct_protocol.h b/nsswitch/winbind_struct_protocol.h
index 0dffa4be528..245162d2ad6 100644
--- a/nsswitch/winbind_struct_protocol.h
+++ b/nsswitch/winbind_struct_protocol.h
@@ -486,6 +486,7 @@ struct winbindd_response {
struct {
uint8_t session_key[16];
uint32_t auth_blob_len; /* blob in extra_data */
+ uint8_t new_spnego;
} ccache_ntlm_auth;
struct {
fstring dc_unc;
diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py
index 8d3b4dd152d..0499b4e0fc3 100644
--- a/python/samba/tests/__init__.py
+++ b/python/samba/tests/__init__.py
@@ -1,5 +1,6 @@
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2010
+# Copyright (C) Stefan Metzmacher 2014,2015
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -23,19 +24,27 @@ import samba
import samba.auth
from samba import param
from samba.samdb import SamDB
+from samba import credentials
+import samba.ndr
+import samba.dcerpc.dcerpc
+import samba.dcerpc.base
+import samba.dcerpc.epmapper
+import socket
+import struct
import subprocess
+import sys
import tempfile
+import unittest
-samba.ensure_external_module("testtools", "testtools")
+try:
+ from unittest import SkipTest
+except ImportError:
+ class SkipTest(Exception):
+ """Test skipped."""
-# Other modules import these two classes from here, for convenience:
-from testtools.testcase import (
- TestCase as TesttoolsTestCase,
- TestSkipped,
- )
+HEXDUMP_FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])
-
-class TestCase(TesttoolsTestCase):
+class TestCase(unittest.TestCase):
"""A Samba test case."""
def setUp(self):
@@ -53,8 +62,119 @@ class TestCase(TesttoolsTestCase):
def get_credentials(self):
return cmdline_credentials
-
-class LdbTestCase(TesttoolsTestCase):
+ def hexdump(self, src):
+ N = 0
+ result = ''
+ while src:
+ ll = src[:8]
+ lr = src[8:16]
+ src = src[16:]
+ hl = ' '.join(["%02X" % ord(x) for x in ll])
+ hr = ' '.join(["%02X" % ord(x) for x in lr])
+ ll = ll.translate(HEXDUMP_FILTER)
+ lr = lr.translate(HEXDUMP_FILTER)
+ result += "[%04X] %-*s %-*s %s %s\n" % (N, 8*3, hl, 8*3, hr, ll, lr)
+ N += 16
+ return result
+
+ # These functions didn't exist before Python2.7:
+ if sys.version_info < (2, 7):
+ import warnings
+
+ def skipTest(self, reason):
+ raise SkipTest(reason)
+
+ def assertIn(self, member, container, msg=None):
+ self.assertTrue(member in container, msg)
+
+ def assertIs(self, a, b, msg=None):
+ self.assertTrue(a is b, msg)
+
+ def assertIsNot(self, a, b, msg=None):
+ self.assertTrue(a is not b, msg)
+
+ def assertIsNotNone(self, a, msg=None):
+ self.assertTrue(a is not None)
+
+ def assertIsInstance(self, a, b, msg=None):
+ self.assertTrue(isinstance(a, b), msg)
+
+ def assertIsNone(self, a, msg=None):
+ self.assertTrue(a is None, msg)
+
+ def assertGreater(self, a, b, msg=None):
+ self.assertTrue(a > b, msg)
+
+ def assertGreaterEqual(self, a, b, msg=None):
+ self.assertTrue(a >= b, msg)
+
+ def assertLess(self, a, b, msg=None):
+ self.assertTrue(a < b, msg)
+
+ def assertLessEqual(self, a, b, msg=None):
+ self.assertTrue(a <= b, msg)
+
+ def addCleanup(self, fn, *args, **kwargs):
+ self._cleanups = getattr(self, "_cleanups", []) + [
+ (fn, args, kwargs)]
+
+ def _addSkip(self, result, reason):
+ addSkip = getattr(result, 'addSkip', None)
+ if addSkip is not None:
+ addSkip(self, reason)
+ else:
+ warnings.warn("TestResult has no addSkip method, skips not reported",
+ RuntimeWarning, 2)
+ result.addSuccess(self)
+
+ def run(self, result=None):
+ if result is None: result = self.defaultTestResult()
+ result.startTest(self)
+ testMethod = getattr(self, self._testMethodName)
+ try:
+ try:
+ self.setUp()
+ except SkipTest, e:
+ self._addSkip(result, str(e))
+ return
+ except KeyboardInterrupt:
+ raise
+ except:
+ result.addError(self, self._exc_info())
+ return
+
+ ok = False
+ try:
+ testMethod()
+ ok = True
+ except SkipTest, e:
+ self._addSkip(result, str(e))
+ return
+ except self.failureException:
+ result.addFailure(self, self._exc_info())
+ except KeyboardInterrupt:
+ raise
+ except:
+ result.addError(self, self._exc_info())
+
+ try:
+ self.tearDown()
+ except SkipTest, e:
+ self._addSkip(result, str(e))
+ except KeyboardInterrupt:
+ raise
+ except:
+ result.addError(self, self._exc_info())
+ ok = False
+
+ for (fn, args, kwargs) in reversed(getattr(self, "_cleanups", [])):
+ fn(*args, **kwargs)
+ if ok: result.addSuccess(self)
+ finally:
+ result.stopTest(self)
+
+
+class LdbTestCase(TestCase):
"""Trivial test case for running tests against a LDB."""
def setUp(self):
@@ -89,7 +209,7 @@ def env_loadparm():
try:
lp.load(os.environ["SMB_CONF_PATH"])
except KeyError:
- raise Exception("SMB_CONF_PATH not set")
+ raise KeyError("SMB_CONF_PATH not set")
return lp
@@ -109,6 +229,524 @@ cmdline_credentials = None
class RpcInterfaceTestCase(TestCase):
"""DCE/RPC Test case."""
+class RawDCERPCTest(TestCase):
+ """A raw DCE/RPC Test case."""
+
+ def _disconnect(self, reason):
+ if self.s is None:
+ return
+ self.s.close()
+ self.s = None
+ if self.do_hexdump:
+ sys.stderr.write("disconnect[%s]\n" % reason)
+
+ def connect(self):
+ try:
+ self.a = socket.getaddrinfo(self.host, self.tcp_port, socket.AF_UNSPEC,
+ socket.SOCK_STREAM, socket.SOL_TCP,
+ 0)
+ self.s = socket.socket(self.a[0][0], self.a[0][1], self.a[0][2])
+ self.s.settimeout(10)
+ self.s.connect(self.a[0][4])
+ except socket.error as e:
+ self.s.close()
+ raise
+ except IOError as e:
+ self.s.close()
+ raise
+ except Exception as e:
+ raise
+ finally:
+ pass
+
+ def setUp(self):
+ super(RawDCERPCTest, self).setUp()
+ self.do_ndr_print = False
+ self.do_hexdump = False
+
+ self.host = samba.tests.env_get_var_value('SERVER')
+ self.tcp_port = 135
+
+ self.settings = {}
+ self.settings["lp_ctx"] = self.lp_ctx = samba.tests.env_loadparm()
+ self.settings["target_hostname"] = self.host
+
+ self.connect()
+
+ def epmap_reconnect(self, abstract):
+ ndr32 = samba.dcerpc.base.transfer_syntax_ndr()
+
+ tsf0_list = [ndr32]
+ ctx0 = samba.dcerpc.dcerpc.ctx_list()
+ ctx0.context_id = 1
+ ctx0.num_transfer_syntaxes = len(tsf0_list)
+ ctx0.abstract_syntax = samba.dcerpc.epmapper.abstract_syntax()
+ ctx0.transfer_syntaxes = tsf0_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx0])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_BIND_ACK,
+ req.call_id, auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEqual(len(rep.u._pad1), 2)
+ self.assertEqual(rep.u._pad1, '\0' * 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ samba.dcerpc.dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ samba.dcerpc.dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, '\0' * 0)
+
+ # And now try a request
+ data1 = samba.ndr.ndr_pack(abstract)
+ lhs1 = samba.dcerpc.epmapper.epm_lhs()
+ lhs1.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_UUID
+ lhs1.lhs_data = data1[:18]
+ rhs1 = samba.dcerpc.epmapper.epm_rhs_uuid()
+ rhs1.unknown = data1[18:]
+ floor1 = samba.dcerpc.epmapper.epm_floor()
+ floor1.lhs = lhs1
+ floor1.rhs = rhs1
+ data2 = samba.ndr.ndr_pack(ndr32)
+ lhs2 = samba.dcerpc.epmapper.epm_lhs()
+ lhs2.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_UUID
+ lhs2.lhs_data = data2[:18]
+ rhs2 = samba.dcerpc.epmapper.epm_rhs_uuid()
+ rhs2.unknown = data1[18:]
+ floor2 = samba.dcerpc.epmapper.epm_floor()
+ floor2.lhs = lhs2
+ floor2.rhs = rhs2
+ lhs3 = samba.dcerpc.epmapper.epm_lhs()
+ lhs3.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_NCACN
+ lhs3.lhs_data = ""
+ floor3 = samba.dcerpc.epmapper.epm_floor()
+ floor3.lhs = lhs3
+ floor3.rhs.minor_version = 0
+ lhs4 = samba.dcerpc.epmapper.epm_lhs()
+ lhs4.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_TCP
+ lhs4.lhs_data = ""
+ floor4 = samba.dcerpc.epmapper.epm_floor()
+ floor4.lhs = lhs4
+ floor4.rhs.port = self.tcp_port
+ lhs5 = samba.dcerpc.epmapper.epm_lhs()
+ lhs5.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_IP
+ lhs5.lhs_data = ""
+ floor5 = samba.dcerpc.epmapper.epm_floor()
+ floor5.lhs = lhs5
+ floor5.rhs.ipaddr = "0.0.0.0"
+
+ floors = [floor1,floor2,floor3,floor4,floor5]
+ req_tower = samba.dcerpc.epmapper.epm_tower()
+ req_tower.num_floors = len(floors)
+ req_tower.floors = floors
+ req_twr = samba.dcerpc.epmapper.epm_twr_t()
+ req_twr.tower = req_tower
+
+ pack_twr = samba.ndr.ndr_pack(req_twr)
+
+ # object
+ stub = "\x01\x00\x00\x00"
+ stub += "\x00" * 16
+ # tower
+ stub += "\x02\x00\x00\x00"
+ stub += pack_twr
+ # padding?
+ stub += "\x00" * 1
+ # handle
+ stub += "\x00" * 20
+ # max_towers
+ stub += "\x04\x00\x00\x00"
+
+ # we do an epm_Map() request
+ req = self.generate_request(call_id = 1,
+ context_id=ctx0.context_id,
+ opnum=3,
+ stub=stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_RESPONSE,
+ req.call_id, auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ num_towers = struct.unpack_from("<I", rep.u.stub_and_verifier, 20)
+ (array_max, array_ofs, array_cnt) = struct.unpack_from("<III", rep.u.stub_and_verifier, 24)
+ status = struct.unpack_from("<I", rep.u.stub_and_verifier, len(rep.u.stub_and_verifier) - 4)
+ self.assertEqual(status[0], 0)
+ self.assertGreaterEqual(num_towers[0], 1)
+ self.assertEqual(array_max, 4)
+ self.assertEqual(array_ofs, 0)
+ self.assertGreaterEqual(array_cnt, 1)
+
+ unpack_twr = rep.u.stub_and_verifier[(36 + 4 * array_cnt):-4]
+ rep_twr = samba.ndr.ndr_unpack(samba.dcerpc.epmapper.epm_twr_t, unpack_twr, allow_remaining=True)
+ self.assertEqual(rep_twr.tower_length, 75)
+ self.assertEqual(rep_twr.tower.num_floors, 5)
+ self.assertEqual(len(rep_twr.tower.floors), 5)
+ self.assertEqual(rep_twr.tower.floors[3].lhs.protocol,
+ samba.dcerpc.epmapper.EPM_PROTOCOL_TCP)
+ self.assertEqual(rep_twr.tower.floors[3].lhs.protocol,
+ samba.dcerpc.epmapper.EPM_PROTOCOL_TCP)
+
+ # reconnect to the given port
+ self._disconnect("epmap_reconnect")
+ self.tcp_port = rep_twr.tower.floors[3].rhs.port
+ self.connect()
+
+ def send_pdu(self, req, ndr_print=None, hexdump=None):
+ if ndr_print is None:
+ ndr_print = self.do_ndr_print
+ if hexdump is None:
+ hexdump = self.do_hexdump
+ try:
+ req_pdu = samba.ndr.ndr_pack(req)
+ if ndr_print:
+ sys.stderr.write("send_pdu: %s" % samba.ndr.ndr_print(req))
+ if hexdump:
+ sys.stderr.write("send_pdu: %d\n%s" % (len(req_pdu), self.hexdump(req_pdu)))
+ while True:
+ sent = self.s.send(req_pdu, 0)
+ if sent == len(req_pdu):
+ break
+ req_pdu = req_pdu[sent:]
+ except socket.error as e:
+ self._disconnect("send_pdu: %s" % e)
+ raise
+ except IOError as e:
+ self._disconnect("send_pdu: %s" % e)
+ raise
+ finally:
+ pass
+
+ def recv_raw(self, hexdump=None, timeout=None):
+ rep_pdu = None
+ if hexdump is None:
+ hexdump = self.do_hexdump
+ try:
+ if timeout is not None:
+ self.s.settimeout(timeout)
+ rep_pdu = self.s.recv(0xffff, 0)
+ self.s.settimeout(10)
+ if len(rep_pdu) == 0:
+ self._disconnect("recv_raw: EOF")
+ return None
+ if hexdump:
+ sys.stderr.write("recv_raw: %d\n%s" % (len(rep_pdu), self.hexdump(rep_pdu)))
+ except socket.timeout as e:
+ self.s.settimeout(10)
+ sys.stderr.write("recv_raw: TIMEOUT\n")
+ pass
+ except socket.error as e:
+ self._disconnect("recv_raw: %s" % e)
+ raise
+ except IOError as e:
+ self._disconnect("recv_raw: %s" % e)
+ raise
+ finally:
+ pass
+ return rep_pdu
+
+ def recv_pdu(self, ndr_print=None, hexdump=None, timeout=None):
+ rep = None
+ if ndr_print is None:
+ ndr_print = self.do_ndr_print
+ if hexdump is None:
+ hexdump = self.do_hexdump
+ try:
+ rep_pdu = self.recv_raw(hexdump=hexdump, timeout=timeout)
+ if rep_pdu is None:
+ return None
+ rep = samba.ndr.ndr_unpack(samba.dcerpc.dcerpc.ncacn_packet, rep_pdu, allow_remaining=True)
+ if ndr_print:
+ sys.stderr.write("recv_pdu: %s" % samba.ndr.ndr_print(rep))
+ self.assertEqual(rep.frag_length, len(rep_pdu))
+ finally:
+ pass
+ return rep
+
+ def generate_auth(self,
+ auth_type=None,
+ auth_level=None,
+ auth_pad_length=0,
+ auth_context_id=None,
+ auth_blob=None,
+ ndr_print=None, hexdump=None):
+ if ndr_print is None:
+ ndr_print = self.do_ndr_print
+ if hexdump is None:
+ hexdump = self.do_hexdump
+
+ if auth_type is not None:
+ a = samba.dcerpc.dcerpc.auth()
+ a.auth_type = auth_type
+ a.auth_level = auth_level
+ a.auth_pad_length = auth_pad_length
+ a.auth_context_id= auth_context_id
+ a.credentials = auth_blob
+
+ ai = samba.ndr.ndr_pack(a)
+ if ndr_print:
+ sys.stderr.write("generate_auth: %s" % samba.ndr.ndr_print(a))
+ if hexdump:
+ sys.stderr.write("generate_auth: %d\n%s" % (len(ai), self.hexdump(ai)))
+ else:
+ ai = ""
+
+ return ai
+
+ def parse_auth(self, auth_info, ndr_print=None, hexdump=None):
+ if ndr_print is None:
+ ndr_print = self.do_ndr_print
+ if hexdump is None:
+ hexdump = self.do_hexdump
+
+ if (len(auth_info) <= samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH):
+ return None
+
+ if hexdump:
+ sys.stderr.write("parse_auth: %d\n%s" % (len(auth_info), self.hexdump(auth_info)))
+ a = samba.ndr.ndr_unpack(samba.dcerpc.dcerpc.auth, auth_info, allow_remaining=True)
+ if ndr_print:
+ sys.stderr.write("parse_auth: %s" % samba.ndr.ndr_print(a))
+
+ return a
+
+ def generate_pdu(self, ptype, call_id, payload,
+ rpc_vers=5,
+ rpc_vers_minor=0,
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
+ drep = [samba.dcerpc.dcerpc.DCERPC_DREP_LE, 0, 0, 0],
+ ndr_print=None, hexdump=None):
+
+ if getattr(payload, 'auth_info', None):
+ ai = payload.auth_info
+ else:
+ ai = ""
+
+ p = samba.dcerpc.dcerpc.ncacn_packet()
+ p.rpc_vers = rpc_vers
+ p.rpc_vers_minor = rpc_vers_minor
+ p.ptype = ptype
+ p.pfc_flags = pfc_flags
+ p.drep = drep
+ p.frag_length = 0
+ if len(ai) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH:
+ p.auth_length = len(ai) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ else:
+ p.auth_length = 0
+ p.call_id = call_id
+ p.u = payload
+
+ pdu = samba.ndr.ndr_pack(p)
+ p.frag_length = len(pdu)
+
+ return p
+
+ def verify_pdu(self, p, ptype, call_id,
+ rpc_vers=5,
+ rpc_vers_minor=0,
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
+ drep = [samba.dcerpc.dcerpc.DCERPC_DREP_LE, 0, 0, 0],
+ auth_length=None):
+
+ self.assertIsNotNone(p, "No valid pdu")
+
+ if getattr(p.u, 'auth_info', None):
+ ai = p.u.auth_info
+ else:
+ ai = ""
+
+ self.assertEqual(p.rpc_vers, rpc_vers)
+ self.assertEqual(p.rpc_vers_minor, rpc_vers_minor)
+ self.assertEqual(p.ptype, ptype)
+ self.assertEqual(p.pfc_flags, pfc_flags)
+ self.assertEqual(p.drep, drep)
+ self.assertGreaterEqual(p.frag_length,
+ samba.dcerpc.dcerpc.DCERPC_NCACN_PAYLOAD_OFFSET)
+ if len(ai) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH:
+ self.assertEqual(p.auth_length,
+ len(ai) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
+ elif auth_length is not None:
+ self.assertEqual(p.auth_length, auth_length)
+ else:
+ self.assertEqual(p.auth_length, 0)
+ self.assertEqual(p.call_id, call_id)
+
+ return
+
+ def generate_bind(self, call_id,
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
+ max_xmit_frag=5840,
+ max_recv_frag=5840,
+ assoc_group_id=0,
+ ctx_list=[],
+ auth_info="",
+ ndr_print=None, hexdump=None):
+
+ b = samba.dcerpc.dcerpc.bind()
+ b.max_xmit_frag = max_xmit_frag
+ b.max_recv_frag = max_recv_frag
+ b.assoc_group_id = assoc_group_id
+ b.num_contexts = len(ctx_list)
+ b.ctx_list = ctx_list
+ b.auth_info = auth_info
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_BIND,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=b,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ return p
+
+ def generate_alter(self, call_id,
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
+ max_xmit_frag=5840,
+ max_recv_frag=5840,
+ assoc_group_id=0,
+ ctx_list=[],
+ auth_info="",
+ ndr_print=None, hexdump=None):
+
+ a = samba.dcerpc.dcerpc.bind()
+ a.max_xmit_frag = max_xmit_frag
+ a.max_recv_frag = max_recv_frag
+ a.assoc_group_id = assoc_group_id
+ a.num_contexts = len(ctx_list)
+ a.ctx_list = ctx_list
+ a.auth_info = auth_info
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_ALTER,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=a,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ return p
+
+ def generate_auth3(self, call_id,
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
+ auth_info="",
+ ndr_print=None, hexdump=None):
+
+ a = samba.dcerpc.dcerpc.auth3()
+ a.auth_info = auth_info
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_AUTH3,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=a,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ return p
+
+ def generate_request(self, call_id,
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
+ alloc_hint=None,
+ context_id=None,
+ opnum=None,
+ object=None,
+ stub=None,
+ auth_info="",
+ ndr_print=None, hexdump=None):
+
+ if alloc_hint is None:
+ alloc_hint = len(stub)
+
+ r = samba.dcerpc.dcerpc.request()
+ r.alloc_hint = alloc_hint
+ r.context_id = context_id
+ r.opnum = opnum
+ if object is not None:
+ r.object = object
+ r.stub_and_verifier = stub + auth_info
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_REQUEST,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=r,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ if len(auth_info) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH:
+ p.auth_length = len(auth_info) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+
+ return p
+
+ def generate_co_cancel(self, call_id,
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
+ auth_info="",
+ ndr_print=None, hexdump=None):
+
+ c = samba.dcerpc.dcerpc.co_cancel()
+ c.auth_info = auth_info
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_CO_CANCEL,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=c,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ return p
+
+ def generate_orphaned(self, call_id,
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
+ auth_info="",
+ ndr_print=None, hexdump=None):
+
+ o = samba.dcerpc.dcerpc.orphaned()
+ o.auth_info = auth_info
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_ORPHANED,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=o,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ return p
+
+ def generate_shutdown(self, call_id,
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
+ ndr_print=None, hexdump=None):
+
+ s = samba.dcerpc.dcerpc.shutdown()
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_SHUTDOWN,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=s,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ return p
+
+ def assertIsConnected(self):
+ self.assertIsNotNone(self.s, msg="Not connected")
+ return
+
+ def assertNotConnected(self):
+ self.assertIsNone(self.s, msg="Is connected")
+ return
+
+ def assertNDRSyntaxEquals(self, s1, s2):
+ self.assertEqual(s1.uuid, s2.uuid)
+ self.assertEqual(s1.if_version, s2.if_version)
+ return
class ValidNetbiosNameTests(TestCase):
@@ -183,7 +821,6 @@ def connect_samdb(samdb_url, lp=None, session_info=None, credentials=None,
to make proper URL for ldb.connect() while using default
parameters for connection based on test environment
"""
- samdb_url = samdb_url.lower()
if not "://" in samdb_url:
if not ldap_only and os.path.isfile(samdb_url):
samdb_url = "tdb://%s" % samdb_url
@@ -233,8 +870,28 @@ def connect_samdb_ex(samdb_url, lp=None, session_info=None, credentials=None,
return (sam_db, res[0])
+def connect_samdb_env(env_url, env_username, env_password, lp=None):
+ """Connect to SamDB by getting URL and Credentials from environment
+
+ :param env_url: Environment variable name to get lsb url from
+ :param env_username: Username environment variable
+ :param env_password: Password environment variable
+ :return: sam_db_connection
+ """
+ samdb_url = env_get_var_value(env_url)
+ creds = credentials.Credentials()
+ if lp is None:
+ # guess Credentials parameters here. Otherwise workstation
+ # and domain fields are NULL and gencache code segfalts
+ lp = param.LoadParm()
+ creds.guess(lp)
+ creds.set_username(env_get_var_value(env_username))
+ creds.set_password(env_get_var_value(env_password))
+ return connect_samdb(samdb_url, credentials=creds, lp=lp)
+
+
def delete_force(samdb, dn):
try:
samdb.delete(dn)
- except ldb.LdbError, (num, _):
- assert(num == ldb.ERR_NO_SUCH_OBJECT)
+ except ldb.LdbError, (num, errstr):
+ assert num == ldb.ERR_NO_SUCH_OBJECT, "ldb.delete() failed: %s" % errstr
diff --git a/python/samba/tests/dcerpc/bare.py b/python/samba/tests/dcerpc/bare.py
index 3efbf9d4cf3..e101c5bcfcf 100644
--- a/python/samba/tests/dcerpc/bare.py
+++ b/python/samba/tests/dcerpc/bare.py
@@ -31,21 +31,12 @@ class BareTestCase(samba.tests.TestCase):
lp_ctx=samba.tests.env_loadparm())
self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4))
- def test_alter_context(self):
+ def test_two_contexts(self):
x = ClientConnection("ncalrpc:localhost[DEFAULT]",
("12345778-1234-abcd-ef00-0123456789ac", 1),
lp_ctx=samba.tests.env_loadparm())
y = ClientConnection("ncalrpc:localhost",
("60a15ec5-4de8-11d7-a637-005056a20182", 1),
basis_connection=x, lp_ctx=samba.tests.env_loadparm())
- x.alter_context(("60a15ec5-4de8-11d7-a637-005056a20182", 1))
- # FIXME: self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4))
-
- def test_two_connections(self):
- x = ClientConnection("ncalrpc:localhost[DEFAULT]",
- ("60a15ec5-4de8-11d7-a637-005056a20182", 1),
- lp_ctx=samba.tests.env_loadparm())
- y = ClientConnection("ncalrpc:localhost",
- ("60a15ec5-4de8-11d7-a637-005056a20182", 1),
- basis_connection=x, lp_ctx=samba.tests.env_loadparm())
+ self.assertEquals(24, len(x.request(0, chr(0) * 8)))
self.assertEquals("\x01\x00\x00\x00", y.request(0, chr(0) * 4))
diff --git a/python/samba/tests/dcerpc/dnsserver.py b/python/samba/tests/dcerpc/dnsserver.py
index 2b421d07bab..7229877a313 100644
--- a/python/samba/tests/dcerpc/dnsserver.py
+++ b/python/samba/tests/dcerpc/dnsserver.py
@@ -27,7 +27,7 @@ class DnsserverTests(RpcInterfaceTestCase):
super(DnsserverTests, self).setUp()
self.server = env_get_var_value("SERVER_IP")
self.zone = env_get_var_value("REALM").lower()
- self.conn = dnsserver.dnsserver("ncacn_ip_tcp:%s" % (self.server),
+ self.conn = dnsserver.dnsserver("ncacn_ip_tcp:%s[sign]" % (self.server),
self.get_loadparm(),
self.get_credentials())
diff --git a/python/samba/tests/dcerpc/raw_protocol.py b/python/samba/tests/dcerpc/raw_protocol.py
new file mode 100755
index 00000000000..ccd0f6bd210
--- /dev/null
+++ b/python/samba/tests/dcerpc/raw_protocol.py
@@ -0,0 +1,2623 @@
+#!/usr/bin/env python
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2014,2015
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import sys
+import os
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+import samba.dcerpc.dcerpc as dcerpc
+import samba.dcerpc.base as base
+import samba.dcerpc.epmapper
+import samba.dcerpc.mgmt
+import samba.dcerpc.netlogon
+import struct
+from samba.credentials import Credentials
+from samba import gensec
+from samba.tests import RawDCERPCTest
+
+global_ndr_print = False
+global_hexdump = False
+
+class TestDCERPC_BIND(RawDCERPCTest):
+
+ def setUp(self):
+ super(TestDCERPC_BIND, self).setUp()
+ self.do_ndr_print = global_ndr_print
+ self.do_hexdump = global_hexdump
+
+ def _test_no_auth_request_bind_pfc_flags(self, req_pfc_flags, rep_pfc_flags):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, pfc_flags=req_pfc_flags, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ pfc_flags=rep_pfc_flags, auth_length=0)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ # sometimes windows sends random bytes
+ # self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEquals(rep.u.auth_info, '\0' * 0)
+
+ # And now try a request
+ req = self.generate_request(call_id = 1,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ def _test_no_auth_request_alter_pfc_flags(self, req_pfc_flags, rep_pfc_flags):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ # sometimes windows sends random bytes
+ # self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEquals(rep.u.auth_info, '\0' * 0)
+
+ # And now try a alter context
+ req = self.generate_alter(call_id=0, pfc_flags=req_pfc_flags, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ pfc_flags=rep_pfc_flags, auth_length=0)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 0)
+ self.assertEquals(rep.u.secondary_address, "")
+ self.assertEquals(len(rep.u._pad1), 2)
+ # sometimes windows sends random bytes
+ # self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEquals(rep.u.auth_info, '\0' * 0)
+
+ # And now try a request
+ req = self.generate_request(call_id = 1,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ def test_no_auth_request(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_bind_pfc_00(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_bind_pfc_FIRST(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_bind_pfc_LAST(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ # TODO: doesn't announce DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
+ # without authentication
+ def _test_no_auth_request_bind_pfc_HDR_SIGNING(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)
+
+ def test_no_auth_request_bind_pfc_08(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ 8 |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ # TODO: doesn't announce DCERPC_PFC_FLAG_CONC_MPX
+ # by default
+ def _test_no_auth_request_bind_pfc_CONC_MPX(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_CONC_MPX |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_CONC_MPX)
+
+ def test_no_auth_request_bind_pfc_DID_NOT_EXECUTE(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_bind_pfc_MAYBE(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_MAYBE |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_bind_pfc_OBJECT_UUID(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_OBJECT_UUID |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ # TODO: doesn't announce DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
+ # without authentication
+ # TODO: doesn't announce DCERPC_PFC_FLAG_CONC_MPX
+ # by default
+ def _test_no_auth_request_bind_pfc_ff(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ 0xff |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ dcerpc.DCERPC_PFC_FLAG_CONC_MPX)
+
+ def test_no_auth_request_alter_pfc_00(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_FIRST(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_LAST(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ # TODO: doesn't announce DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
+ # without authentication
+ def _test_no_auth_request_alter_pfc_HDR_SIGNING(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)
+
+ def test_no_auth_request_alter_pfc_08(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ 8 |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_CONC_MPX(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_CONC_MPX |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_DID_NOT_EXECUTE(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_MAYBE(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_MAYBE |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_OBJECT_UUID(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_OBJECT_UUID |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ # TODO: doesn't announce DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
+ # without authentication
+ def _test_no_auth_request_alter_pfc_ff(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ 0xff |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)
+
+ def test_no_auth_no_ctx(self):
+ # send an useless bind
+ req = self.generate_bind(call_id=0)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEquals(rep.u.reject_reason,
+ dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+ self.assertEquals(rep.u.num_versions, 1)
+ self.assertEquals(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEquals(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertEquals(len(rep.u._pad), 3)
+ self.assertEquals(rep.u._pad, '\0' * 3)
+
+ def test_invalid_auth_noctx(self):
+ req = self.generate_bind(call_id=0)
+ req.auth_length = dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEquals(rep.u.reject_reason,
+ dcerpc.DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED)
+ self.assertEquals(rep.u.num_versions, 1)
+ self.assertEquals(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEquals(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertEquals(len(rep.u._pad), 3)
+ self.assertEquals(rep.u._pad, '\0' * 3)
+
+ def test_no_auth_valid_valid_request(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEquals(rep.u.auth_info, '\0' * 0)
+
+ # Send a bind again
+ tsf2_list = [ndr32]
+ ctx2 = dcerpc.ctx_list()
+ ctx2.context_id = 2
+ ctx2.num_transfer_syntaxes = len(tsf2_list)
+ ctx2.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx2.transfer_syntaxes = tsf2_list
+
+ req = self.generate_bind(call_id=1, ctx_list=[ctx2])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEquals(rep.u.reject_reason,
+ dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+ self.assertEquals(rep.u.num_versions, 1)
+ self.assertEquals(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEquals(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertEquals(len(rep.u._pad), 3)
+ self.assertEquals(rep.u._pad, '\0' * 3)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_no_auth_invalid_valid_request(self):
+ # send an useless bind
+ req = self.generate_bind(call_id=0)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEquals(rep.u.reject_reason,
+ dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+ self.assertEquals(rep.u.num_versions, 1)
+ self.assertEquals(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEquals(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertEquals(len(rep.u._pad), 3)
+ self.assertEquals(rep.u._pad, '\0' * 3)
+
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_alter_no_auth_no_ctx(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEquals(rep.u.auth_info, '\0' * 0)
+
+ # Send a alter
+ req = self.generate_alter(call_id=1, ctx_list=[])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, 0)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def _test_auth_none_level_bind(self, auth_level,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NONE
+ auth_context_id = 0
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob="none")
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEquals(rep.u.reject_reason, reason)
+ self.assertEquals(rep.u.num_versions, 1)
+ self.assertEquals(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEquals(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertEquals(len(rep.u._pad), 3)
+ self.assertEquals(rep.u._pad, '\0' * 3)
+
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_auth_none_none_bind(self):
+ return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_NONE,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+
+ def test_auth_none_connect_bind(self):
+ return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_CONNECT)
+
+ def test_auth_none_call_bind(self):
+ return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_CALL)
+
+ def test_auth_none_packet_bind(self):
+ return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_PACKET)
+
+ def test_auth_none_integrity_bind(self):
+ return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY)
+
+ def test_auth_none_privacy_bind(self):
+ return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_PRIVACY)
+
+ def test_auth_none_0_bind(self):
+ return self._test_auth_none_level_bind(0,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+
+ def test_auth_none_7_bind(self):
+ return self._test_auth_none_level_bind(7,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+
+ def test_auth_none_255_bind(self):
+ return self._test_auth_none_level_bind(255,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+
+ def _test_auth_none_level_request(self, auth_level):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NONE
+ auth_context_id = 0
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEquals(len(rep.u.auth_info), 0)
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id = 2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob="none")
+
+ req = self.generate_request(call_id = 3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_auth_none_none_request(self):
+ return self._test_auth_none_level_request(dcerpc.DCERPC_AUTH_LEVEL_NONE)
+
+ def test_auth_none_connect_request(self):
+ return self._test_auth_none_level_request(dcerpc.DCERPC_AUTH_LEVEL_CONNECT)
+
+ def test_auth_none_call_request(self):
+ return self._test_auth_none_level_request(dcerpc.DCERPC_AUTH_LEVEL_CALL)
+
+ def _test_neg_xmit_check_values(self,
+ req_xmit=None,
+ req_recv=None,
+ rep_both=None,
+ alter_xmit=None,
+ alter_recv=None):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0,
+ max_xmit_frag=req_xmit,
+ max_recv_frag=req_recv,
+ ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEquals(rep.u.max_xmit_frag, rep_both)
+ self.assertEquals(rep.u.max_recv_frag, rep_both)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEquals(rep.u.auth_info, '\0' * 0)
+
+ assoc_group_id = rep.u.assoc_group_id
+ if alter_xmit is None:
+ alter_xmit = rep_both - 8
+ if alter_recv is None:
+ alter_recv = rep_both - 8
+
+ # max_{xmit,recv}_frag and assoc_group_id are completely
+ # ignored in alter_context requests
+ req = self.generate_alter(call_id=1,
+ max_xmit_frag=alter_xmit,
+ max_recv_frag=alter_recv,
+ assoc_group_id=0xffffffff-rep.u.assoc_group_id,
+ ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEquals(rep.u.max_xmit_frag, rep_both)
+ self.assertEquals(rep.u.max_recv_frag, rep_both)
+ self.assertEquals(rep.u.assoc_group_id, rep.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 0)
+ self.assertEquals(len(rep.u._pad1), 2)
+ #self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEquals(rep.u.auth_info, '\0' * 0)
+
+ chunk_size = rep_both - dcerpc.DCERPC_REQUEST_LENGTH
+ req = self.generate_request(call_id = 2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ alloc_hint=0xffffffff,
+ stub="\00" * chunk_size)
+ self.send_pdu(req,ndr_print=True,hexdump=True)
+ rep = self.recv_pdu(ndr_print=True,hexdump=True)
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ chunk_size = 5840 - dcerpc.DCERPC_REQUEST_LENGTH
+ req = self.generate_request(call_id = 2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ alloc_hint=0xffffffff,
+ stub="\00" * chunk_size)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ chunk_size += 1
+ req = self.generate_request(call_id = 3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ alloc_hint=0xffffffff,
+ stub="\00" * chunk_size)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, 0)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_neg_xmit_ffff_ffff(self):
+ return self._test_neg_xmit_check_values(req_xmit=0xffff,
+ req_recv=0xffff,
+ rep_both=5840)
+
+ def test_neg_xmit_0_ffff(self):
+ return self._test_neg_xmit_check_values(req_xmit=0,
+ req_recv=0xffff,
+ rep_both=2048,
+ alter_xmit=0xffff,
+ alter_recv=0xffff)
+
+ def test_neg_xmit_ffff_0(self):
+ return self._test_neg_xmit_check_values(req_xmit=0xffff,
+ req_recv=0,
+ rep_both=2048)
+
+ def test_neg_xmit_0_0(self):
+ return self._test_neg_xmit_check_values(req_xmit=0,
+ req_recv=0,
+ rep_both=2048,
+ alter_xmit=0xffff,
+ alter_recv=0xffff)
+
+ def test_neg_xmit_3199_0(self):
+ return self._test_neg_xmit_check_values(req_xmit=3199,
+ req_recv=0,
+ rep_both=2048)
+ def test_neg_xmit_0_3199(self):
+ return self._test_neg_xmit_check_values(req_xmit=0,
+ req_recv=3199,
+ rep_both=2048)
+
+ def test_neg_xmit_3199_ffff(self):
+ return self._test_neg_xmit_check_values(req_xmit=3199,
+ req_recv=0xffff,
+ rep_both=3192)
+ def test_neg_xmit_ffff_3199(self):
+ return self._test_neg_xmit_check_values(req_xmit=0xffff,
+ req_recv=3199,
+ rep_both=3192)
+
+ def test_alloc_hint(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx = dcerpc.ctx_list()
+ ctx.context_id = 0
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEquals(rep.u.auth_info, '\0' * 0)
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id = 2,
+ context_id=ctx.context_id,
+ opnum=0,
+ alloc_hint=0xffffffff,
+ stub="")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ req = self.generate_request(call_id = 3,
+ context_id=ctx.context_id,
+ opnum=1,
+ alloc_hint=0xffffffff,
+ stub="\04\00\00\00\00\00\00\00")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ req = self.generate_request(call_id = 4,
+ context_id=ctx.context_id,
+ opnum=1,
+ alloc_hint=1,
+ stub="\04\00\00\00\00\00\00\00")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ def _get_netlogon_ctx(self):
+ abstract = samba.dcerpc.netlogon.abstract_syntax()
+ self.epmap_reconnect(abstract)
+
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx = dcerpc.ctx_list()
+ ctx.context_id = 0
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = abstract
+ ctx.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ port_str = "%d" % self.tcp_port
+ port_len = len(port_str) + 1
+ mod_len = (2 + port_len) % 4
+ if mod_len != 0:
+ port_pad = 4 - mod_len
+ else:
+ port_pad = 0
+ self.assertEquals(rep.u.secondary_address_size, port_len)
+ self.assertEquals(rep.u.secondary_address, port_str)
+ self.assertEquals(len(rep.u._pad1), port_pad)
+ self.assertEquals(rep.u._pad1, '\0' * port_pad)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEquals(rep.u.auth_info, '\0' * 0)
+
+ server = '\\\\' + self.host
+ server_utf16 = unicode(server, 'utf-8').encode('utf-16-le')
+ computer = 'UNKNOWNCOMPUTER'
+ computer_utf16 = unicode(computer, 'utf-8').encode('utf-16-le')
+
+ real_stub = struct.pack('<IIII', 0x00200000,
+ len(server)+1, 0, len(server)+1)
+ real_stub += server_utf16 + '\x00\x00'
+ mod_len = len(real_stub) % 4
+ if mod_len != 0:
+ real_stub += '\x00' * (4 - mod_len)
+ real_stub += struct.pack('<III',
+ len(computer)+1, 0, len(computer)+1)
+ real_stub += computer_utf16 + '\x00\x00'
+ real_stub += '\x11\x22\x33\x44\x55\x66\x77\x88'
+
+ return (ctx, rep, real_stub)
+
+ def _test_fragmented_requests(self, remaining=None, alloc_hint=None,
+ fault_first=None, fault_last=None):
+ (ctx, rep, real_stub) = self._get_netlogon_ctx()
+
+ chunk = rep.u.max_recv_frag - dcerpc.DCERPC_REQUEST_LENGTH
+
+ total = 0
+ first = True
+ while remaining > 0:
+ thistime = min(remaining, chunk)
+ remaining -= thistime
+ total += thistime
+
+ pfc_flags = 0
+ if first:
+ pfc_flags |= dcerpc.DCERPC_PFC_FLAG_FIRST
+ first = False
+ stub = real_stub + '\x00' * (thistime - len(real_stub))
+ else:
+ stub = "\x00" * thistime
+
+ if remaining == 0:
+ pfc_flags |= dcerpc.DCERPC_PFC_FLAG_LAST
+
+ # And now try a request without auth_info
+ # netr_ServerReqChallenge()
+ req = self.generate_request(call_id = 2,
+ pfc_flags=pfc_flags,
+ context_id=ctx.context_id,
+ opnum=4,
+ alloc_hint=alloc_hint,
+ stub=stub)
+ if alloc_hint >= thistime:
+ alloc_hint -= thistime
+ else:
+ alloc_hint = 0
+ self.send_pdu(req,hexdump=False)
+ if fault_first is not None:
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, fault_first)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+ if remaining == 0:
+ break
+ if total >= 0x400000 and fault_last is not None:
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, fault_last)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ if total >= 0x400000 and fault_last is not None:
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, fault_last)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ self.assertEquals(len(rep.u.stub_and_verifier), 12)
+ status = struct.unpack_from("<I", rep.u.stub_and_verifier, len(rep.u.stub_and_verifier) - 4)
+ self.assertEquals(status[0], 0)
+
+ def test_fragmented_requests01(self):
+ return self._test_fragmented_requests(remaining=0x400000,
+ alloc_hint=0x400000)
+
+ def test_fragmented_requests02(self):
+ return self._test_fragmented_requests(remaining=0x400000,
+ alloc_hint=0x100000)
+
+ def test_fragmented_requests03(self):
+ return self._test_fragmented_requests(remaining=0x400000,
+ alloc_hint=0)
+
+ def test_fragmented_requests04(self):
+ return self._test_fragmented_requests(remaining=0x400000,
+ alloc_hint=0x400001,
+ fault_first=dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+
+ def test_fragmented_requests05(self):
+ return self._test_fragmented_requests(remaining=0x500001,
+ alloc_hint=0,
+ fault_last=dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+
+ def _test_same_requests(self, pfc_flags, fault_1st=False, fault_2nd=False):
+ (ctx, rep, real_stub) = self._get_netlogon_ctx()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id = 2,
+ pfc_flags=pfc_flags,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ if fault_1st:
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # netr_ServerReqChallenge without DCERPC_PFC_FLAG_LAST
+ # with the same call_id
+ req = self.generate_request(call_id = 2,
+ pfc_flags=pfc_flags,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ if fault_2nd:
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ def test_first_only_requests(self):
+ return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ fault_2nd=True)
+
+ def test_none_only_requests(self):
+ return self._test_same_requests(pfc_flags=0, fault_1st=True)
+
+ def test_last_only_requests(self):
+ return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_LAST,
+ fault_1st=True)
+
+ def test_first_maybe_requests(self):
+ return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_MAYBE,
+ fault_2nd=True)
+
+ def test_first_didnot_requests(self):
+ return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ fault_2nd=True)
+
+ def test_first_cmpx_requests(self):
+ return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_CONC_MPX,
+ fault_2nd=True)
+
+ def test_first_08_requests(self):
+ return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ 0x08,
+ fault_2nd=True)
+
+ def test_first_cancel_requests(self):
+ (ctx, rep, real_stub) = self._get_netlogon_ctx()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id = 2,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_PENDING_CANCEL,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_NO_CALL_ACTIVE)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_2nd_cancel_requests(self):
+ (ctx, rep, real_stub) = self._get_netlogon_ctx()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id = 2,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id = 2,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_PENDING_CANCEL,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id = 2,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_LAST,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ self.assertEquals(len(rep.u.stub_and_verifier), 12)
+ status = struct.unpack_from("<I", rep.u.stub_and_verifier, len(rep.u.stub_and_verifier) - 4)
+ self.assertEquals(status[0], 0)
+
+ def test_last_cancel_requests(self):
+ (ctx, rep, real_stub) = self._get_netlogon_ctx()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id = 2,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub[:4])
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id = 2,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_PENDING_CANCEL,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub[4:])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ self.assertEquals(len(rep.u.stub_and_verifier), 12)
+ status = struct.unpack_from("<I", rep.u.stub_and_verifier, len(rep.u.stub_and_verifier) - 4)
+ self.assertEquals(status[0], 0)
+
+ def test_mix_requests(self):
+ (ctx, rep, real_stub) = self._get_netlogon_ctx()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id = 50,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id = 51,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, 50,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ def test_spnego_connect_request(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = Credentials()
+ c.set_anonymous()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_alter(call_id=0,
+ ctx_list=ctx_list,
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 0)
+ self.assertEquals(len(rep.u._pad1), 2)
+ # Windows sends garbage
+ #self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertTrue(finished)
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id = 2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob="\x01"+"\x00"*15)
+ req = self.generate_request(call_id = 3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We don't get an auth_info back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY,
+ auth_context_id=auth_context_id,
+ auth_blob="\x01"+"\x00"*15)
+ req = self.generate_request(call_id = 4,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_integrity_request(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = Credentials()
+ c.set_anonymous()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_alter(call_id=0,
+ ctx_list=ctx_list,
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 0)
+ self.assertEquals(len(rep.u._pad1), 2)
+ # Windows sends garbage
+ #self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertTrue(finished)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=dcerpc.DCERPC_AUTH_LEVEL_CONNECT,
+ auth_context_id=auth_context_id,
+ auth_blob="\x01"+"\x00"*15)
+ req = self.generate_request(call_id = 3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_unfinished_request(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = Credentials()
+ c.set_anonymous()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ assoc_group_id = rep.u.assoc_group_id
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob="\x01"+"\x00"*15)
+ req = self.generate_request(call_id = 1,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, 0)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_auth3(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = Credentials()
+ c.set_anonymous()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ #self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_auth3(call_id=0,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id = 2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_connect_reauth_alter(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = Credentials()
+ c.set_anonymous()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 0)
+ self.assertEquals(len(rep.u._pad1), 2)
+ # Windows sends garbage
+ #self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertTrue(finished)
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id = 2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob="\x01"+"\x00"*15)
+ req = self.generate_request(call_id = 3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We don't get an auth_info back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a reauth
+
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, 0)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_connect_reauth_auth3(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = Credentials()
+ c.set_anonymous()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 0)
+ self.assertEquals(len(rep.u._pad1), 2)
+ # Windows sends garbage
+ #self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertTrue(finished)
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id = 2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob="\x01"+"\x00"*15)
+ req = self.generate_request(call_id = 3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub="",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We don't get an auth_info back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, req.u.context_id)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a reauth
+
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_auth3(call_id=0,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, 0)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_change_auth_level(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ c = Credentials()
+ c.set_anonymous()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx1],
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, 0)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_change_abstract(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ ctx1b = dcerpc.ctx_list()
+ ctx1b.context_id = 1
+ ctx1b.num_transfer_syntaxes = len(tsf1_list)
+ ctx1b.abstract_syntax = samba.dcerpc.epmapper.abstract_syntax()
+ ctx1b.transfer_syntaxes = tsf1_list
+
+ c = Credentials()
+ c.set_anonymous()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx1],
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ #self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1b],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, 0)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_change_transfer(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ tsf1b_list = [ndr32,ndr64]
+ ctx1b = dcerpc.ctx_list()
+ ctx1b.context_id = 1
+ ctx1b.num_transfer_syntaxes = len(tsf1b_list)
+ ctx1b.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1b.transfer_syntaxes = tsf1b_list
+
+ c = Credentials()
+ c.set_anonymous()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx1],
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ #self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ # We change ctx_list and auth_level
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1b],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, 0)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_change_auth_type1(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ c = Credentials()
+ c.set_anonymous()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx1],
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ #self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ # We change ctx_list and auth_level
+ auth_info = self.generate_auth(auth_type=dcerpc.DCERPC_AUTH_TYPE_KRB5,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, 0)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_SEC_PKG_ERROR)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_change_auth_type2(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ tsf1b_list = [ndr32,ndr64]
+ ctx1b = dcerpc.ctx_list()
+ ctx1b.context_id = 1
+ ctx1b.num_transfer_syntaxes = len(tsf1b_list)
+ ctx1b.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1b.transfer_syntaxes = tsf1b_list
+
+ c = Credentials()
+ c.set_anonymous()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx1],
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ #self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ # We change ctx_list and auth_level
+ auth_info = self.generate_auth(auth_type=dcerpc.DCERPC_AUTH_TYPE_KRB5,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1b],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, 0)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_change_auth_type3(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ tsf1b_list = [ndr32,ndr64]
+ ctx1b = dcerpc.ctx_list()
+ ctx1b.context_id = 1
+ ctx1b.num_transfer_syntaxes = len(tsf1b_list)
+ ctx1b.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1b.transfer_syntaxes = tsf1b_list
+
+ c = Credentials()
+ c.set_anonymous()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = ""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx1],
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEquals(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEquals(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEquals(rep.u.secondary_address_size, 4)
+ self.assertEquals(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertEquals(len(rep.u._pad1), 2)
+ #self.assertEquals(rep.u._pad1, '\0' * 2)
+ self.assertEquals(rep.u.num_results, 1)
+ self.assertEquals(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEquals(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEquals(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ # We change ctx_list and auth_level
+ auth_info = self.generate_auth(auth_type=dcerpc.DCERPC_AUTH_TYPE_NONE,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1b],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertEquals(rep.u.context_id, 0)
+ self.assertEquals(rep.u.cancel_count, 0)
+ self.assertEquals(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEquals(len(rep.u._pad), 4)
+ self.assertEquals(rep.u._pad, '\0' * 4)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+if __name__ == "__main__":
+ global_ndr_print = True
+ global_hexdump = True
+ import unittest
+ unittest.main()
diff --git a/python/samba/tests/dcerpc/srvsvc.py b/python/samba/tests/dcerpc/srvsvc.py
index 3206a27e678..407a9d52a73 100644
--- a/python/samba/tests/dcerpc/srvsvc.py
+++ b/python/samba/tests/dcerpc/srvsvc.py
@@ -45,12 +45,12 @@ class SrvsvcTests(RpcInterfaceTestCase):
return share
def test_NetShareAdd(self):
- self.skip("Dangerous test")
+ self.skipTest("Dangerous test")
share = self.getDummyShareObject()
self.conn.NetShareAdd(self.server_unc, 2, share, None)
def test_NetShareSetInfo(self):
- self.skip("Dangerous test")
+ self.skipTest("Dangerous test")
share = self.getDummyShareObject()
parm_error = 0x00000000
self.conn.NetShareAdd(self.server_unc, 502, share, parm_error)
@@ -60,7 +60,7 @@ class SrvsvcTests(RpcInterfaceTestCase):
502, share, parm_error)
def test_NetShareDel(self):
- self.skip("Dangerous test")
+ self.skipTest("Dangerous test")
share = self.getDummyShareObject()
parm_error = 0x00000000
self.expectFailure("NetShareAdd doesn't work properly from Python",
diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py
index f7f56a3696b..a0d93abbda8 100644
--- a/python/samba/tests/dns.py
+++ b/python/samba/tests/dns.py
@@ -33,8 +33,6 @@ parser = optparse.OptionParser("dns.py <server name> <server ip> [options]")
sambaopts = options.SambaOptions(parser)
parser.add_option_group(sambaopts)
-FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])
-
# This timeout only has relevance when testing against Windows
# Format errors tend to return patchy responses, so a timeout is needed.
parser.add_option("--timeout", type="int", dest="timeout",
@@ -178,16 +176,6 @@ class DNSTest(TestCase):
if s is not None:
s.close()
- def hexdump(self, src, length=8):
- N=0; result=''
- while src:
- s,src = src[:length],src[length:]
- hexa = ' '.join(["%02X"%ord(x) for x in s])
- s = s.translate(FILTER)
- result += "%04X %-*s %s\n" % (N, length*3, hexa, s)
- N+=length
- return result
-
def make_txt_update(self, prefix, txt_array):
p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
updates = []
diff --git a/python/samba/tests/docs.py b/python/samba/tests/docs.py
index 0d71e685ab7..561628f901d 100644
--- a/python/samba/tests/docs.py
+++ b/python/samba/tests/docs.py
@@ -21,9 +21,7 @@
import samba
import samba.tests
-from samba.tests import TestSkipped, TestCaseInTempDir
-import errno
import os
import re
import subprocess
@@ -36,6 +34,7 @@ class TestCase(samba.tests.TestCaseInTempDir):
parameters.sort()
return message + '\n\n %s' % ('\n '.join(parameters))
+
def get_documented_parameters(sourcedir):
path = os.path.join(sourcedir, "bin", "default", "docs-xml", "smbdotconf")
if not os.path.exists(os.path.join(path, "parameters.all.xml")):
diff --git a/python/samba/tests/ntacls.py b/python/samba/tests/ntacls.py
index aa9ef6852ba..8cd09fbcc54 100644
--- a/python/samba/tests/ntacls.py
+++ b/python/samba/tests/ntacls.py
@@ -19,10 +19,9 @@
"""Tests for samba.ntacls."""
from samba.ntacls import setntacl, getntacl, XattrBackendError
-from samba.dcerpc import xattr, security
from samba.param import LoadParm
-from samba.tests import TestCaseInTempDir, TestSkipped
-import random
+from samba.dcerpc import security
+from samba.tests import TestCaseInTempDir, SkipTest
import os
class NtaclsTests(TestCaseInTempDir):
@@ -64,7 +63,7 @@ class NtaclsTests(TestCaseInTempDir):
def test_setntacl_forcenative(self):
if os.getuid() == 0:
- raise TestSkipped("Running test as root, test skipped")
+ raise SkipTest("Running test as root, test skipped")
lp = LoadParm()
acl = "O:S-1-5-21-2212615479-2695158682-2101375467-512G:S-1-5-21-2212615479-2695158682-2101375467-513D:(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375467-512)"
open(self.tempf, 'w').write("empty")
diff --git a/python/samba/tests/subunitrun.py b/python/samba/tests/subunitrun.py
index d45467607e6..291e7ab461a 100755
--- a/python/samba/tests/subunitrun.py
+++ b/python/samba/tests/subunitrun.py
@@ -37,9 +37,7 @@ signal.signal(signal.SIGINT, signal.SIG_DFL)
import optparse
import samba
import sys
-samba.ensure_external_module("mimeparse", "mimeparse")
-samba.ensure_external_module("extras", "extras")
-samba.ensure_external_module("testtools", "testtools")
+import samba.tests
samba.ensure_external_module("subunit", "subunit/python")
import subunit.run
diff --git a/python/samba/tests/xattr.py b/python/samba/tests/xattr.py
index 89add284566..63874523f00 100644
--- a/python/samba/tests/xattr.py
+++ b/python/samba/tests/xattr.py
@@ -22,9 +22,9 @@ from samba.xattr import copytree_with_xattrs
from samba.dcerpc import xattr
from samba.ndr import ndr_pack
from samba.tests import (
+ SkipTest,
TestCase,
TestCaseInTempDir,
- TestSkipped,
)
import random
import shutil
@@ -42,7 +42,7 @@ class XattrTests(TestCase):
def test_set_xattr_native(self):
if not samba.xattr_native.is_xattr_supported():
- raise TestSkipped()
+ raise SkipTest()
ntacl = xattr.NTACL()
ntacl.version = 1
tempf = self._tmpfilename()
@@ -51,12 +51,12 @@ class XattrTests(TestCase):
samba.xattr_native.wrap_setxattr(tempf, "user.unittests",
ndr_pack(ntacl))
except IOError:
- raise TestSkipped("the filesystem where the tests are runned do not support XATTR")
+ raise SkipTest("the filesystem where the tests are runned do not support XATTR")
os.unlink(tempf)
def test_set_and_get_native(self):
if not samba.xattr_native.is_xattr_supported():
- raise TestSkipped()
+ raise SkipTest()
tempf = self._tmpfilename()
reftxt = "this is a test"
open(tempf, 'w').write("empty")
@@ -65,7 +65,7 @@ class XattrTests(TestCase):
text = samba.xattr_native.wrap_getxattr(tempf, "user.unittests")
self.assertEquals(text, reftxt)
except IOError:
- raise TestSkipped("the filesystem where the tests are runned do not support XATTR")
+ raise SkipTest("the filesystem where the tests are runned do not support XATTR")
os.unlink(tempf)
def test_set_xattr_tdb(self):
diff --git a/selftest/filter-subunit b/selftest/filter-subunit
index 2ce9584c2a5..4f95546794a 100755
--- a/selftest/filter-subunit
+++ b/selftest/filter-subunit
@@ -19,14 +19,15 @@
# to upstream subunit's filtering tools.
import optparse
-import os
import sys
import signal
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/subunit/python"))
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/testtools"))
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/mimeparse"))
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/extras"))
+sys.path.insert(0, "bin/python")
+import samba
+samba.ensure_external_module("mimeparse", "mimeparse")
+samba.ensure_external_module("extras", "extras")
+samba.ensure_external_module("testtools", "testtools")
+samba.ensure_external_module("subunit", "subunit/python")
import subunithelper
diff --git a/selftest/format-subunit b/selftest/format-subunit
index 5da56beb090..dc44842c15a 100755
--- a/selftest/format-subunit
+++ b/selftest/format-subunit
@@ -9,10 +9,12 @@ import os
import signal
import sys
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/subunit/python"))
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/testtools"))
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/mimeparse"))
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/extras"))
+sys.path.insert(0, "bin/python")
+import samba
+samba.ensure_external_module("mimeparse", "mimeparse")
+samba.ensure_external_module("extras", "extras")
+samba.ensure_external_module("testtools", "testtools")
+samba.ensure_external_module("subunit", "subunit/python")
import subunithelper
diff --git a/selftest/knownfail b/selftest/knownfail
index c919a6a92d8..f8a52cf91e3 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -86,6 +86,9 @@
^samba4.rpc.lsalookup with seal,padcheck
^samba4.rpc.lsalookup with validate
^samba4.rpc.lsalookup with bigendian
+^samba4.rpc.lsa on ncacn_np with seal # This gives NT_STATUS_LOCAL_USER_SESSION_KEY
+^samba4.rpc.lsa with seal # This gives NT_STATUS_LOCAL_USER_SESSION_KEY
+^samba4.rpc.lsa.secrets.*seal # This gives NT_STATUS_LOCAL_USER_SESSION_KEY
^samba4.rpc.netlogon.*.LogonUasLogon
^samba4.rpc.netlogon.*.LogonUasLogoff
^samba4.rpc.netlogon.*.DatabaseSync
@@ -98,6 +101,10 @@
^samba4.rpc.netlogon.*.GetTrustPasswords
^samba4.rpc.netlogon.*.DatabaseRedo
^samba4.rpc.netlogon.*.ServerGetTrustInfo
+^samba4.rpc.drsuapi.*ncacn_ip_tcp.*validate # should only work with seal
+^samba4.rpc.drsuapi.*ncacn_ip_tcp.*bigendian # should only work with seal
+^samba4.rpc.samr.passwords.validate.*ncacn_ip_tcp.*with.validate # should only work with seal
+^samba4.rpc.samr.passwords.validate.*ncacn_ip_tcp.*with.bigendian # should only work with seal
^samba4.base.charset.*.Testing partial surrogate
^samba4.*.base.maximum_allowed # broken until we implement NTCREATEX_OPTIONS_BACKUP_INTENT
.*net.api.delshare.* # DelShare isn't implemented yet
@@ -215,6 +222,7 @@
^samba3.smb2.replay.replay4
^samba3.smb2.lock.*replay
^samba3.raw.session.*reauth2 # maybe fix this?
+^samba3.rpc.lsa.secrets.seal # This gives NT_STATUS_LOCAL_USER_SESSION_KEY
^samba3.rpc.samr.passwords.badpwdcount.samr.badPwdCount\(s3dc\) # We fail this test currently
^samba3.rpc.samr.passwords.lockout.*\(s3dc\)$ # We fail this test currently
^samba3.rpc.spoolss.printer.addprinter.driver_info_winreg # knownfail or flapping?
@@ -302,3 +310,25 @@
^samba.blackbox.wbinfo\(s3member:local\).wbinfo -G check for sane mapping\(s3member:local\)
^samba.ntlm_auth.\(dc:local\).ntlm_auth against winbindd with failed require-membership-of
^samba.ntlm_auth.\(dc:local\).ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server against winbind with failed require-membership-of
+^samba.ntlm_auth.\(dc:local\).wbinfo store cached credentials
+^samba.ntlm_auth.\(dc:local\).ntlm_auth ccached credentials with NTLMSSP client and gss-spnego server
+#
+## We assert all "ldap server require strong auth" combinations
+#
+^samba4.ldb.simple.ldap with SIMPLE-BIND.*ad_dc_ntvfs # ldap server require strong auth = allow_sasl_over_tls
+^samba4.ldb.simple.ldap with SIMPLE-BIND.*fl2003dc # ldap server require strong auth = yes
+^samba4.ldb.simple.ldaps with SASL-BIND.*fl2003dc # ldap server require strong auth = yes
+# These are supposed to fail as we want to verify the "tls verify peer"
+# restrictions. Note that fl2008r2dc uses a self-signed certificate
+# with does not have a crl file.
+#
+^samba4.ldb.simple.ldaps.*SERVER_NAME.*tlsverifypeer=ca_and_name_if_available\(
+^samba4.ldb.simple.ldaps.*SERVER_NAME.*tlsverifypeer=ca_and_name\(
+^samba4.ldb.simple.ldaps.*SERVER_NAME.*tlsverifypeer=as_strict_as_possible\(
+^samba4.ldb.simple.ldaps.*SERVER_IP.*tlsverifypeer=ca_and_name\(
+^samba4.ldb.simple.ldaps.*SERVER_IP.*tlsverifypeer=as_strict_as_possible\(
+^samba4.ldb.simple.ldaps.*SERVER.REALM.*tlsverifypeer=as_strict_as_possible.*fl2008r2dc
+#
+# we don't allow auth_level_connect anymore...
+#
+^samba3.blackbox.rpcclient.*ncacn_np.*with.*connect.*rpcclient # we don't allow auth_level_connect anymore
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-cert.pem b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-cert.pem
new file mode 100644
index 00000000000..2a1f36f063f
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-cert.pem
@@ -0,0 +1,190 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+ Validity
+ Not Before: Mar 18 11:44:51 2016 GMT
+ Not After : Mar 13 11:44:51 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Domain Controllers, CN=localdc.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:e6:5f:4f:b7:ba:64:00:94:b2:0b:a0:29:3b:66:
+ 1f:28:85:cd:fa:bb:d7:de:18:8e:e2:4b:14:ab:33:
+ 17:4c:5f:8b:84:0e:b2:19:cd:32:ae:2a:8e:fc:8c:
+ 4b:51:c0:d9:2e:de:7f:d2:d3:7a:83:9d:95:66:6d:
+ e0:08:1a:25:10:2f:d3:27:bf:c7:ae:3a:f9:33:e4:
+ 65:87:af:a2:80:87:cc:f7:69:a3:4d:8d:65:30:81:
+ b3:20:ca:3f:54:28:b7:d9:1f:fe:90:92:8f:34:0b:
+ 0c:44:eb:48:b1:54:3e:66:29:c3:aa:e8:f4:f7:2d:
+ 6a:0c:cc:c2:31:f5:35:76:48:ba:82:c8:d0:06:42:
+ 2f:cd:4e:3f:20:b5:fc:f6:72:fc:0e:fe:92:a3:97:
+ 16:c7:9b:40:e4:ca:5c:47:39:bd:b1:4c:09:e3:a7:
+ 42:c2:0d:a8:b5:3e:f9:dc:7d:39:05:4d:c8:5f:c8:
+ 69:dc:85:5c:3c:9a:23:07:bc:30:33:38:a6:c4:03:
+ 07:59:e3:97:55:84:61:65:52:80:60:fa:77:b6:76:
+ 5a:31:32:51:a6:22:98:b5:ab:dc:67:51:23:76:08:
+ 09:8e:38:1c:75:0b:9c:59:43:1f:41:04:dd:60:69:
+ d9:fa:31:b8:16:5e:b8:f8:27:82:16:8e:c6:ce:d9:
+ 56:01:68:e4:5f:f8:2d:0f:31:85:27:37:92:fa:4d:
+ 0b:b3:f3:6a:f4:be:30:15:0d:8e:00:b5:87:f8:67:
+ 5c:ae:6a:25:59:23:8c:bf:a5:02:eb:b7:cc:0c:fc:
+ bc:3b:bd:80:08:fc:a3:86:5f:2d:ec:79:05:8e:e4:
+ d2:d2:c4:a6:ab:84:e3:da:aa:58:c3:db:8b:28:4b:
+ 15:49:79:7e:58:19:8b:7d:3e:87:9e:79:28:15:e1:
+ 8a:ad:75:10:0b:71:1e:8f:e8:1f:cd:d4:9b:11:e1:
+ 47:26:1a:f8:d4:a3:0b:7d:08:de:a6:f1:7a:93:26:
+ fb:bd:78:a3:60:8a:8b:29:fe:f8:9f:7b:5e:d7:64:
+ 03:e1:58:23:ac:23:35:3f:4f:b9:f7:3d:d6:d7:64:
+ 1f:0b:6b:11:9b:10:1f:2b:49:b2:f9:63:e8:cf:bf:
+ ac:da:9e:b7:f7:12:91:e4:01:77:9a:7f:31:c8:b6:
+ af:7d:5e:4e:55:ee:3d:2a:f9:0d:56:11:49:e3:f6:
+ 09:8c:2f:d0:06:eb:f4:f7:65:9f:db:85:0a:57:7e:
+ 9a:b8:1a:60:11:18:d1:3d:1c:c0:53:65:9b:e8:00:
+ 93:e4:91:61:b6:e8:7b:63:d3:d8:ec:70:8d:92:54:
+ 12:8b:56:1f:cf:83:34:d5:44:86:cd:b6:0b:fc:95:
+ 8f:f9:11
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+ Netscape Cert Type:
+ SSL Server
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Key Encipherment
+ Netscape Comment:
+ Domain Controller Certificate localdc.samba.example.com
+ X509v3 Subject Key Identifier:
+ CD:25:BC:9E:49:98:02:88:4F:A7:5C:4F:2D:68:B9:E3:61:9F:AE:2E
+ X509v3 Authority Key Identifier:
+ keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42
+
+ X509v3 Subject Alternative Name:
+ DNS:localdc.samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com@samba.example.com
+ Netscape CA Revocation Url:
+ http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+ X509v3 Extended Key Usage:
+ TLS Web Client Authentication, TLS Web Server Authentication, msKDC
+ Signature Algorithm: sha256WithRSAEncryption
+ 15:c0:31:31:7f:65:7c:7c:a4:db:1c:23:1b:81:bf:e8:c8:ad:
+ c0:2e:ce:c6:8e:3a:a2:d7:8f:ad:19:9a:e9:ea:72:bd:25:bc:
+ 26:3c:57:a7:53:4e:c5:24:a2:3c:70:59:48:9d:f5:df:2c:bd:
+ b5:b4:71:fe:a6:58:15:eb:31:86:83:c9:7a:39:47:80:f1:9d:
+ 31:ed:e1:5a:26:3f:9c:be:06:45:93:96:d9:3b:7d:d1:9c:b2:
+ ea:7b:a3:71:f0:9d:c7:a1:29:ba:38:eb:e4:be:bc:e9:9d:e8:
+ e1:be:eb:57:5a:1e:d1:09:58:dc:77:04:85:48:ba:94:19:73:
+ 8f:3a:31:6d:3c:ec:37:a6:d7:94:25:e3:98:e9:3c:f6:85:c6:
+ 6a:8e:d5:cd:32:05:1f:76:b7:b0:5a:c5:45:c0:81:20:16:4f:
+ e0:bb:e7:42:06:5c:6c:ff:e6:8a:73:7b:8c:1c:98:fe:2d:47:
+ 8a:e0:06:38:53:77:5b:6b:13:82:f4:a6:0b:c3:b2:88:2a:05:
+ 96:c8:04:66:cb:59:19:08:d4:9b:0f:1f:e3:3a:48:65:32:07:
+ 69:39:34:d4:a3:2e:d5:19:09:c7:07:d9:71:4d:62:81:fc:5a:
+ be:f1:da:65:3a:24:1e:2c:40:c8:78:4a:bb:0a:4f:a4:3d:ab:
+ 3c:b9:22:fb:0b:5c:9f:09:95:76:6f:6b:53:3d:1f:ee:fd:3f:
+ cd:be:7a:61:3e:08:3b:99:69:68:91:a9:9f:b8:4f:b8:c9:1f:
+ d4:ed:86:61:aa:6f:4f:a8:6a:4d:b6:79:e9:af:37:d2:83:9b:
+ f7:61:6a:65:f6:8c:f7:f9:3b:23:b6:cc:78:bf:16:ee:a0:50:
+ 1f:7e:38:7b:72:1b:62:ef:17:60:db:6f:c9:29:c1:c2:53:f7:
+ e8:27:de:3e:22:da:f0:5f:ba:55:9f:57:6f:b9:8f:c4:7a:c5:
+ 72:9a:a3:95:cc:ac:fd:f3:a6:a9:da:d6:57:d3:28:7f:72:60:
+ a8:5b:2f:c3:b1:07:c4:c7:af:d9:3c:a9:e9:78:e1:5a:0f:da:
+ c9:d0:e6:5d:9a:bd:61:ef:1d:25:7f:54:08:aa:f2:6c:11:1e:
+ a4:46:8e:9e:e2:79:c8:c2:dd:09:1b:62:27:e6:70:7a:e4:f3:
+ 66:db:57:30:ce:3f:27:f5:c6:c8:f2:3f:a1:bc:dd:ec:fe:3a:
+ c4:b9:ad:21:73:d8:83:a5:9f:02:ba:d0:52:8a:f2:d5:25:63:
+ 15:82:38:25:e2:74:ce:a6:a5:32:9a:6c:52:33:ba:45:ba:01:
+ 16:14:5f:ce:66:89:9e:03:ed:8a:95:80:c4:cf:20:24:d4:c5:
+ 5b:e5:c3:51:62:57:1e:45:be:0a:47:24:b7:cb:a4:dd:6e:54:
+ 2c:f4:25:80:a3:85:a9:74:0c:c0:65:c9:f8:2f:9a:22:bc:85:
+ c9:63:8a:08:f3:c9:1c:77:9b:a8:42:5a:45:dd:be:21:be:9d:
+ e7:15:9b:67:19:6c:d3:da:9b:67:a8:1d:22:35:d4:16:89:ad:
+ 4c:c3:17:bb:9e:f5:e5:3b:a2:a6:81:34:e0:4c:36:be:bb:e5:
+ a3:60:7d:28:30:82:db:99:ef:c6:19:43:d1:73:24:f0:8e:d1:
+ 6c:3b:cc:f8:cb:1a:14:79:67:07:ea:b5:47:08:bf:11:33:29:
+ 01:2e:fd:44:14:33:f6:36:65:8b:a8:f8:e6:0b:84:6d:a1:91:
+ 08:56:c1:5d:ca:12:b6:00:ba:9c:7e:7e:9b:26:3f:d3:dd:e1:
+ 2f:ae:f5:76:45:ed:a2:9b:b4:a1:a9:d6:b6:f5:7e:68:80:17:
+ 81:fb:ef:24:dc:84:de:38:20:45:34:6c:72:e5:d6:08:61:e7:
+ dd:45:43:d2:06:2b:ae:d9:73:a1:fb:bb:04:3c:61:45:d3:9e:
+ fc:45:c0:e3:db:02:ae:45:e3:de:d1:34:00:b0:1b:0f:ce:f8:
+ 33:0f:87:9c:9b:5d:49:11:7a:30:15:e3:9f:76:02:82:18:c2:
+ a6:dd:25:a6:e0:84:1f:1d:0d:db:81:7c:df:a1:65:9b:5b:08:
+ e0:4e:6d:4c:76:8a:0b:09:14:7c:e1:23:ad:18:4c:02:6b:e3:
+ f4:e0:22:26:e1:30:7e:a5:59:22:5b:a5:73:5a:23:24:1f:1a:
+ 7b:e5:46:f7:0c:14:00:53:72:33:4d:c4:c4:59:3e:04:17:33:
+ 34:04:67:1e:cd:a0:e5:9f:85:87:77:f6:dd:03:f0:74:cf:56:
+ e9:99:a8:95:3a:52:db:d1:61:72:91:60:9f:80:bf:22:26:da:
+ d7:09:4e:df:81:30:dc:9b:b4:c1:c7:cb:97:93:bc:b7:93:a3:
+ db:88:cc:5e:9f:39:94:57:a5:57:d6:cd:1b:12:a4:86:62:4f:
+ b2:08:22:4e:d9:07:8e:27:06:82:d9:f1:ec:70:30:82:56:0c:
+ f7:d9:56:bf:f1:7f:fd:65:90:8d:5e:d5:13:b3:31:89:5d:e8:
+ df:35:2f:77:6b:b7:c7:e8:7d:89:f8:cf:9e:a5:1c:60:be:7c:
+ 6c:b7:0f:fa:8e:62:8e:b0:72:10:8a:04:6a:50:83:3a:38:dc:
+ 13:8b:89:8f:6c:0f:fc:3e:c7:36:15:37:78:5f:24:87:8a:70:
+ cc:3e:5a:fc:88:78:19:70:89:65:a0:c7:47:67:f2:bc:1e:f5:
+ 04:e7:94:ba:74:ea:2a:a7:c1:26:b1:2e:ac:64:0b:fa
+-----BEGIN CERTIFICATE-----
+MIIJ6zCCBdOgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTgxMTQ0NTFaFw0zNjAzMTMxMTQ0NTFaMIG1MQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEbMBkGA1UE
+CwwSRG9tYWluIENvbnRyb2xsZXJzMSIwIAYDVQQDDBlsb2NhbGRjLnNhbWJhLmV4
+YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkBFiZjYS1zYW1iYS5leGFtcGxlLmNvbUBz
+YW1iYS5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+AOZfT7e6ZACUsgugKTtmHyiFzfq7194YjuJLFKszF0xfi4QOshnNMq4qjvyMS1HA
+2S7ef9LTeoOdlWZt4AgaJRAv0ye/x646+TPkZYevooCHzPdpo02NZTCBsyDKP1Qo
+t9kf/pCSjzQLDETrSLFUPmYpw6ro9PctagzMwjH1NXZIuoLI0AZCL81OPyC1/PZy
+/A7+kqOXFsebQOTKXEc5vbFMCeOnQsINqLU++dx9OQVNyF/IadyFXDyaIwe8MDM4
+psQDB1njl1WEYWVSgGD6d7Z2WjEyUaYimLWr3GdRI3YICY44HHULnFlDH0EE3WBp
+2foxuBZeuPgnghaOxs7ZVgFo5F/4LQ8xhSc3kvpNC7PzavS+MBUNjgC1h/hnXK5q
+JVkjjL+lAuu3zAz8vDu9gAj8o4ZfLex5BY7k0tLEpquE49qqWMPbiyhLFUl5flgZ
+i30+h555KBXhiq11EAtxHo/oH83UmxHhRyYa+NSjC30I3qbxepMm+714o2CKiyn+
++J97XtdkA+FYI6wjNT9Pufc91tdkHwtrEZsQHytJsvlj6M+/rNqet/cSkeQBd5p/
+Mci2r31eTlXuPSr5DVYRSeP2CYwv0Abr9Pdln9uFCld+mrgaYBEY0T0cwFNlm+gA
+k+SRYbboe2PT2OxwjZJUEotWH8+DNNVEhs22C/yVj/kRAgMBAAGjggHxMIIB7TAJ
+BgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly93d3cuc2FtYmEuZXhh
+bXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMBEGCWCG
+SAGG+EIBAQQEAwIGQDALBgNVHQ8EBAMCBeAwRgYJYIZIAYb4QgENBDkWN0RvbWFp
+biBDb250cm9sbGVyIENlcnRpZmljYXRlIGxvY2FsZGMuc2FtYmEuZXhhbXBsZS5j
+b20wHQYDVR0OBBYEFM0lvJ5JmAKIT6dcTy1oueNhn64uMB8GA1UdIwQYMBaAFEaH
+hsLnGc8WTAxiy3N//Y8Z5LVCMD0GA1UdEQQ2MDSCGWxvY2FsZGMuc2FtYmEuZXhh
+bXBsZS5jb22gFwYJKwYBBAGCNxkBoAoECAEjRWeJq83vMDEGA1UdEgQqMCiBJmNh
+LXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0GCWCGSAGG+EIB
+BARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMvQ0Etc2FtYmEu
+ZXhhbXBsZS5jb20tY3JsLmNybDAmBgNVHSUEHzAdBggrBgEFBQcDAgYIKwYBBQUH
+AwEGBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggQBABXAMTF/ZXx8pNscIxuBv+jI
+rcAuzsaOOqLXj60Zmunqcr0lvCY8V6dTTsUkojxwWUid9d8svbW0cf6mWBXrMYaD
+yXo5R4DxnTHt4VomP5y+BkWTltk7fdGcsup7o3HwncehKbo46+S+vOmd6OG+61da
+HtEJWNx3BIVIupQZc486MW087Dem15Ql45jpPPaFxmqO1c0yBR92t7BaxUXAgSAW
+T+C750IGXGz/5opze4wcmP4tR4rgBjhTd1trE4L0pgvDsogqBZbIBGbLWRkI1JsP
+H+M6SGUyB2k5NNSjLtUZCccH2XFNYoH8Wr7x2mU6JB4sQMh4SrsKT6Q9qzy5IvsL
+XJ8JlXZva1M9H+79P82+emE+CDuZaWiRqZ+4T7jJH9TthmGqb0+oak22eemvN9KD
+m/dhamX2jPf5OyO2zHi/Fu6gUB9+OHtyG2LvF2Dbb8kpwcJT9+gn3j4i2vBfulWf
+V2+5j8R6xXKao5XMrP3zpqna1lfTKH9yYKhbL8OxB8THr9k8qel44VoP2snQ5l2a
+vWHvHSV/VAiq8mwRHqRGjp7iecjC3QkbYifmcHrk82bbVzDOPyf1xsjyP6G83ez+
+OsS5rSFz2IOlnwK60FKK8tUlYxWCOCXidM6mpTKabFIzukW6ARYUX85miZ4D7YqV
+gMTPICTUxVvlw1FiVx5FvgpHJLfLpN1uVCz0JYCjhal0DMBlyfgvmiK8hcljigjz
+yRx3m6hCWkXdviG+necVm2cZbNPam2eoHSI11BaJrUzDF7ue9eU7oqaBNOBMNr67
+5aNgfSgwgtuZ78YZQ9FzJPCO0Ww7zPjLGhR5ZwfqtUcIvxEzKQEu/UQUM/Y2ZYuo
++OYLhG2hkQhWwV3KErYAupx+fpsmP9Pd4S+u9XZF7aKbtKGp1rb1fmiAF4H77yTc
+hN44IEU0bHLl1ghh591FQ9IGK67Zc6H7uwQ8YUXTnvxFwOPbAq5F497RNACwGw/O
++DMPh5ybXUkRejAV4592AoIYwqbdJabghB8dDduBfN+hZZtbCOBObUx2igsJFHzh
+I60YTAJr4/TgIibhMH6lWSJbpXNaIyQfGnvlRvcMFABTcjNNxMRZPgQXMzQEZx7N
+oOWfhYd39t0D8HTPVumZqJU6UtvRYXKRYJ+AvyIm2tcJTt+BMNybtMHHy5eTvLeT
+o9uIzF6fOZRXpVfWzRsSpIZiT7IIIk7ZB44nBoLZ8exwMIJWDPfZVr/xf/1lkI1e
+1ROzMYld6N81L3drt8fofYn4z56lHGC+fGy3D/qOYo6wchCKBGpQgzo43BOLiY9s
+D/w+xzYVN3hfJIeKcMw+WvyIeBlwiWWgx0dn8rwe9QTnlLp06iqnwSaxLqxkC/o=
+-----END CERTIFICATE-----
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-key.pem
new file mode 100644
index 00000000000..0dec9845d18
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-key.pem
@@ -0,0 +1,54 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIJljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI/ffRVypD9HkCAggA
+MBQGCCqGSIb3DQMHBAjv05OkfOwFaQSCCVCbev4X3oUISTe03sWAz0bzijH5Wg7w
+Vc9+SnYwt0pFZTaUw6MkvhFNUD+BEw0fePpCeBzf2DTVqCQ4RVY7ps3/DmTZQlWa
+KDLbermsiT5n1dc22iYeA1zsHc/h020djrm+Eem5rcNGsxlfln3fRMVwSPEEBBnK
+7k/8tM1SeXe/QmFtm3CRJ02dNzvr11xcYLDN9i2bVskqIFME/+Vi57/rdEAhyaBB
+osJBhv+vvfoyTbZ8buRIxN2rUxkPp27jPqckyZoC9IWE6MXoyyaKYIvkscIIU6Xf
+hj4K/FdozbD6TkCC84KfHqXgMy+CFN04yTt9fORl0L/3NHHJoMjXQsg26wSfbCFY
+t9FK5QQlm0MqimsOaxCTEd1LivRw16KYLOva20t2/1aMpc8nBP4ROheugGhEOsCB
+RwbvANTmg4E/uBWORDsDRu4OQN3XE/nzW3R7uokv4aGON8Ob6M7DExDIQCdsbGvB
+8DdziETmvXAj6yGH0LfqaZhNXpj5uyuNVVt7ROoKYFIOdkUXPC1DFOcLRiClaM87
+8XU8Zy2l/tFh56jgWMzMcqoIlLxIpMMCZl5P533+5nQ2tQtdRynTpKuipdDIFu/r
+JjMsTYgh8knG8C5qSXqNT0hu0yRleGNRVslTBnc7JqjMdqcZBS1Ut4asU7aVn6Fv
+egGmgPXTsC8tnYy6lT+lam+jjdk65SHP+/HUNuyhVzmDKPXaUG/bdh4NmCHaxE4y
+WjLTKMkEs/NBkGDxbqgw3HtatSBiK+JG1zUeaDomxbROjv8VYGGF1RXrp38KOqao
+Tg6gEUzcktbEdcvm+q1Pkau2vPxRcnnOQSSmnqr+w0+kh9OawaZ5B+VMr5eV9mdZ
+oj2yT0nw7+BFJq3zeaIt1ksSkqUaXLVspeJkBC/DbC/MyoOLdMgzHfkxc1/hq0WV
+UoQtHI4lTk+3aWu4ZD47BrigLbeDOvvW/oMF6CdVZBghhsyhvmpWASQ1kiVN7k18
+A19iX5W33x9bjD+0392mSPo525BR24z5x8bTklLng0Kro84sXfRPHMXqIoCEDXz0
+z8QGJtdVdUi9wVLqcCyW+8U51ACTWnrxv0oTlRy7ESbj229Cj29o3qGdCXaU7XVz
+g5WGtziVR1Lquql+hzCckwPLjm6olLyxZwk6d83KwMUckhvLeYXJ65/ZRRaE2R91
+2X0ir7Csk802NPjaV21No3/EJVuw57dZ9xxUUW8Q+OfCQAxKxdKfWcK3JjdNvZn4
+778E/kWg+KdhcQ1yb6MHZafrjnkwAp4qm3Kp936zL5a/nsTT2e0661pC/8FBxfNQ
+H+CFLylW77vpVo/iFSeHzGmOEuUC7hsbqjX8y4x8czuY1sCNA0Ty3tf5gOVhemuP
+xgfJRQF/bUAnlWnCb83peSYq5SUQq1LTtkKGghXCgV1d3MzryAoOr6znZTcE0CSG
+GDUk7vzaZmzKp8TySAFUcuo6Ve297yi9A+dGNsuOyqmFwS7pjrwYI9HPj2BKu7Gw
+Ns/aPs9lJhGR7tjpqyX2Ok4OQBBcwdP3OfjdCQdwdjAjVXlj5BeNiSQ7HiRECYza
+kGzvwuO+10DXTSwcLhakNZZtONFpuMU5JoSCcICUaJ+4AAqJdfO13TiOYHRLN9VC
+2h2/4wGPcvLdYg9ByiE5wt5bysGl0jOtmTA5boK6TD1qF5fD8+WNd7VPDmFS/uUo
+65JXn63Q8A8MC7sQNLOsyoFkXOVr5uLNdZMzbcOqre9h3y1GCucXRAhQ4eOefJPA
+2u/vFk0opk8dMq0FA9LH4zbvhpTBytHdcnkwlsCmv8XO7j544gSbrUNKMqSkY2DT
+R37qxq6iCzaSkNnpxLH8kY5KydCnxqxLhbECbNqdIIajxPgctCbzKJrOe/I9CUzu
+qsXY8+ZVRD2wBOnP8p9oWq0pbilmgNquQD5/maO0Rm09A6Eg4vvki/PJxBC9KRfv
+VXmgk4LsmAPxh/anJFJlK36LRUNosmBFSOZ+NnCMAhEGjH+5VER4hWmWxr4znLfD
+QsIh+uui2fZWr8dBmpArzGyq7C3sB4sIXqacaExu+ed8f/tvU414Y1b75XaIMGX/
+CcSDf/NgGw1+Ucf0hp7nHU6/u7dhuwvrw8LLhXhuGU9al7vVP8n8aEwzNPo1OAnd
+0DcPWGFaFGQlSWL6oOXDsE2KVkI82+2XJZopLL2Envh5ntct0a49DHIi4TP+aVbT
+Q37EU2SvNYvJk0h8dUibrM/hd5UZ8PKWgIamOjhhi+0mTON2sW9Jitr3NSFRw6sn
+NOC9p5kH2R5TGH8r34RbfEU6Zy3bSukuW/63FknS8VLWu0AWfzqNRTIZj8xfoaGd
+MsNTsgTdXHt/9pgbtMRU/EDs9ZfNmbLM1uw5Kfp7garX4TuZefgPAWHzoZM4zD71
+xe6aVOTiPatdDceFuynFdijK3RljO25CgOURQe0OYNNOJIrXGtkmC2szD3LTqW/x
+wn51DiIijGQLrFIzrflw/V7is5VpujyU5dn8/Wk6OTbhoVctmlhOyKVvM/fo2m/g
+q4pSD4TvLWgJW+aU3XZTw55P0hV9zYzienmWc6Ny1zen+829pm6gbYW9N/qsU5CB
+W5h4+rBgp9htUVeeu2mKiaZW9V5Y2IN7frKwZxUQPe3FMS3TEfEjBAqcdJHGPZEZ
+tqFB4CiW7F0w0Tt30ATdoPIbnK/RQa025JhAWjSCLZg88Busik2uEvoZLe8Z+6bc
+hTQnKcHY63LbkqqpYBKvsE/MjYUts7K7QKYQPmFvxoQpgpmqdfQ53ibvDnGeWnxj
+j+5qXgx73cUaKPU14ObiLrhieVCnhEqSRot2aUx2hllbJn7CXj4OUkznFL6k2GGg
+HzOe7PsZUhXWdUaBvSjbr6Whg8erCumJq2b346deoiGl3o/RsgFu4V3tZHN+v1Lj
+gorQXOmnqXOhUbquM+2p5TRiKRfn6ARLf7Ja4UZhmk0w8e1vw+u0WKScMaNQ+BVT
+91lBpJcHqWZiMAVDvgyZk3oM954xEgyr6guG/8eoTUXECUUn0HPbMOqmoLsMH6Ok
+bFR2t1mtan8Qp9zYW8wIMAAdnkOMoYrUgB9KImr8Mr/DCa6ouqybNcO6xuVnVwq3
+vCmSqd5+XPORqnDF1wPZUbKh825VMXENa6RIX4rkiZwG+j4ALtzOqt5u6k3MZNIe
+fmluaS0MnFk2mw==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-openssl.cnf
new file mode 100644
index 00000000000..bf4131fecf8
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-openssl.cnf
@@ -0,0 +1,250 @@
+#
+# Based on the OpenSSL example configuration file.
+# This is mostly being used for generation of certificate requests.
+#
+
+# This definition stops the following lines choking if HOME isn't
+# defined.
+HOME = .
+RANDFILE = $ENV::HOME/.rnd
+
+#CRLDISTPT = [CRL Distribution Point; e.g., http://crl-list.base/w4edom-l4.base.crl]
+CRLDISTPT = http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+# Extra OBJECT IDENTIFIER info:
+oid_section = new_oids
+
+# To use this configuration file with the "-extfile" option of the
+# "openssl x509" utility, name here the section containing the
+# X.509v3 extensions to use:
+# extensions =
+# (Alternatively, use a configuration file that has only
+# X.509v3 extensions in its main [= default] section.)
+
+[ new_oids ]
+# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used as a login credential
+scardLogin=1.3.6.1.4.1.311.20.2.2
+# Used in a smart card login certificate's subject alternative name
+msUPN=1.3.6.1.4.1.311.20.2.3
+# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used to identify a domain controller
+msKDC=1.3.6.1.5.2.3.5
+# Identifies the AD GUID
+msADGUID=1.3.6.1.4.1.311.25.1
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = CA-samba.example.com # Where everything is kept
+certs = $dir/_none_certs # Where the issued certs are kept
+crl_dir = $dir/_none_crl # Where the issued crl are kept
+database = $dir/Private/CA-samba.example.com-index.txt # database index file.
+unique_subject = yes # Set to 'no' to allow creation of
+ # several certificates with same subject.
+new_certs_dir = $dir/NewCerts # default place for new certs.
+
+certificate = $dir/Public/CA-samba.example.com-cert.pem # The CA certificate
+serial = $dir/Private/CA-samba.example.com-serial.txt # The current serial number
+crlnumber = $dir/Private/CA-samba.example.com-crlnumber.txt # the current crl number
+ # must be commented out to leave a V1 CRL
+
+#crl = $dir/Public/CA-samba.example.com-crl.pem # The current CRL
+crl = $dir/Public/CA-samba.example.com-crl.crl # The current CRL
+private_key = $dir/Private/CA-samba.example.com-private-key.pem # The private key
+RANDFILE = $dir/Private/CA-samba.example.com.rand # private random number file
+
+#x509_extensions = # The extensions to add to the cert
+x509_extensions = template_x509_extensions
+
+# Comment out the following two lines for the "traditional"
+# (and highly broken) format.
+name_opt = ca_default # Subject Name options
+cert_opt = ca_default # Certificate field options
+
+# Extension copying option: use with caution.
+# copy_extensions = copy
+
+# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
+# so this is commented out by default to leave a V1 CRL.
+# crlnumber must also be commented out to leave a V1 CRL.
+crl_extensions = crl_ext
+
+default_days = 7300 # how long to certify for
+default_crl_days= 7300 # how long before next CRL
+default_md = sha256 # use public key default MD
+preserve = no # keep passed DN ordering
+
+# A few difference way of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+# For the 'anything' policy
+# At this point in time, you must list all acceptable 'object'
+# types.
+[ policy_anything ]
+countryName = match
+stateOrProvinceName = match
+localityName = match
+organizationName = match
+organizationalUnitName = match
+commonName = supplied
+emailAddress = supplied
+
+####################################################################
+[ req ]
+default_bits = 4096
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extensions to add to the self signed cert
+
+# Passwords for private keys if not present they will be prompted for
+# input_password = secret
+# output_password = secret
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString (PKIX recommendation before 2004)
+# utf8only: only UTF8Strings (PKIX recommendation after 2004).
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings.
+string_mask = utf8only
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = US
+countryName_min = 2
+countryName_max = 2
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = SambaState
+
+localityName = Locality Name (eg, city)
+localityName_default = SambaCity
+
+organizationName = Organization Name (eg, company)
+organizationName_default = SambaSelfTesting
+
+organizationalUnitName = Organizational Unit Name (eg, section)
+organizationalUnitName_default = Domain Controllers
+
+commonName = Common Name (eg, YOUR name)
+commonName_default = localdc.samba.example.com
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_default = ca-samba.example.com@samba.example.com
+emailAddress_max = 64
+
+# SET-ex3 = SET extension number 3
+
+[ req_attributes ]
+#challengePassword = A challenge password
+#challengePassword_min = 4
+#challengePassword_max = 20
+#
+#unstructuredName = An optional company name
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+[ v3_ca ]
+# Extensions for a typical CA
+# PKIX recommendation.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer
+
+# This is what PKIX recommends but some broken software chokes on critical
+# extensions.
+#basicConstraints = critical,CA:true
+# So we do this instead.
+basicConstraints = CA:true
+
+# Key usage: this is typical for a CA certificate.
+keyUsage = cRLSign, keyCertSign
+
+crlDistributionPoints=URI:$CRLDISTPT
+
+# Some might want this also
+nsCertType = sslCA, emailCA
+
+# Include email address in subject alt name: another PKIX recommendation
+subjectAltName=email:copy
+# Copy issuer details
+issuerAltName=issuer:copy
+
+[ crl_ext ]
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always
+
+#[ usr_cert_mskdc ]
+[ template_x509_extensions ]
+
+# These extensions are added when 'ca' signs a request for a domain controller certificate.
+
+# This goes against PKIX guidelines but some CAs do it and some software
+# requires this to avoid interpreting an end user certificate as a CA.
+
+basicConstraints=CA:FALSE
+crlDistributionPoints=URI:$CRLDISTPT
+
+# Here are some examples of the usage of nsCertType. If it is omitted
+# the certificate can be used for anything *except* object signing.
+
+# This is OK for an SSL server.
+nsCertType = server
+
+# This is typical in keyUsage for a client certificate.
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+# This will be displayed in Netscape's comment listbox.
+nsComment = "Domain Controller Certificate localdc.samba.example.com"
+
+# PKIX recommendations harmless if included in all certificates.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+
+# This stuff is for subjectAltName and issuerAltname.
+
+subjectAltName=@dc_subjalt
+
+# Copy subject details
+issuerAltName=issuer:copy
+
+nsCaRevocationUrl = $CRLDISTPT
+#nsBaseUrl
+#nsRevocationUrl
+#nsRenewalUrl
+#nsCaPolicyUrl
+#nsSslServerName
+
+#Extended Key requirements for our domain controller certs
+# serverAuth - says cert can be used to identify an ssl/tls server
+# msKDC - says cert can be used to identify a Kerberos Domain Controller.
+extendedKeyUsage = clientAuth,serverAuth,msKDC
+
+[dc_subjalt]
+DNS=localdc.samba.example.com
+otherName=msADGUID;FORMAT:HEX,OCTETSTRING:0123456789ABCDEF
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-private-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-private-key.pem
new file mode 100644
index 00000000000..f8c3c4070b1
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-private-key.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEA5l9Pt7pkAJSyC6ApO2YfKIXN+rvX3hiO4ksUqzMXTF+LhA6y
+Gc0yriqO/IxLUcDZLt5/0tN6g52VZm3gCBolEC/TJ7/Hrjr5M+Rlh6+igIfM92mj
+TY1lMIGzIMo/VCi32R/+kJKPNAsMROtIsVQ+ZinDquj09y1qDMzCMfU1dki6gsjQ
+BkIvzU4/ILX89nL8Dv6So5cWx5tA5MpcRzm9sUwJ46dCwg2otT753H05BU3IX8hp
+3IVcPJojB7wwMzimxAMHWeOXVYRhZVKAYPp3tnZaMTJRpiKYtavcZ1EjdggJjjgc
+dQucWUMfQQTdYGnZ+jG4Fl64+CeCFo7GztlWAWjkX/gtDzGFJzeS+k0Ls/Nq9L4w
+FQ2OALWH+GdcrmolWSOMv6UC67fMDPy8O72ACPyjhl8t7HkFjuTS0sSmq4Tj2qpY
+w9uLKEsVSXl+WBmLfT6HnnkoFeGKrXUQC3Eej+gfzdSbEeFHJhr41KMLfQjepvF6
+kyb7vXijYIqLKf74n3te12QD4VgjrCM1P0+59z3W12QfC2sRmxAfK0my+WPoz7+s
+2p639xKR5AF3mn8xyLavfV5OVe49KvkNVhFJ4/YJjC/QBuv092Wf24UKV36auBpg
+ERjRPRzAU2Wb6ACT5JFhtuh7Y9PY7HCNklQSi1Yfz4M01USGzbYL/JWP+RECAwEA
+AQKCAgEA1iZfupFACPIxGHGIIrlp2YeY1K3tm34ExQO6cPMLg2mGDfqDQUzpAdJ6
+HPZlxdeZjOI0vMzuJI9GpHMbQSzcq1Fp3pd+jc4wfjag0yNH0mdq98txjNQV7qOC
+2sZnXFqFnQcK42X6TQzAGQkHCCEh6GKGi8gGgAftf3yQQVSKoCw3hQAbsNWyDg3g
+zQ2f25FEEsQ/mGcJPABssMIUSfm5BqmCv+dqPW3pGKM0Le0SJoYJ8FAjaGVoOsWm
+LriXreXJ0IhoOv1AXrSyvTeWM5Bh3HHkobr+/4tFngvm1PwuFLif+V7bxUpHywqE
+cTKOf+OmR9gUImdnVveTDFkpInwSX3UH88lKwg2t9rANuSgrfnhX9MgLxWT52qFw
+hRwtLHamnKZw9IrYq002O00NPAoS2AFApFzAbPBxTy5cOKVzOzBr27w5Qxam+GoH
+LVk/1qePWI0CwP68DN2jFM5TWd9zGUpXnSHcsX0j/qs6UKamUbmszbRenskOtn0b
+d3Et/gKQt6168aBDSkCxFsdkeWMKI9xcnfSi97i/dRCvqIfEGRqoQLwknk2DMoE6
+2Z23hs+tRVRHu49CWABPnMBf5FqN2rocjr15wKAphgbbMIA3tw2wo03wmaMYNzxJ
+M57ejJc+6MNfRyb0nLRaClsveU30qpfWhd36eKdKLZtrfj0Be2ECggEBAP90L6gM
+83MA4hIOvLO5zhMMPdbm0+hOLlKpKUqBsNaCeJWutF9TcnqajoaYy9p+gKlASO5s
+BgQiwMy3JlHc2KrbMXruksUER3d4Oprv/DKS+XfRciRZ0//+jCrNHrBvMB5VQHYs
+wTB9Sdbdgfc1YiPdkF4JRBqmUrMS9b7iv8BLzAxbcdXz2xoXhkmbwgTJghdQAigq
+GnoeXoc8qbA8IYKQefFevd6TzBL6UR+ZFHOjz2A2gX/1G31i6z5cjZc2XRjvI9aC
+rBorjzYg2M7KBusbKhr8zYDqn/Rl0e/vK9NhZEz7Vg2FXUT25WZPlktQV1b3TVtY
+yoWhJj2vy4ffqz0CggEBAObdZdE2I3UY/TTk/jK6LKg+uTB7/AjjaTga4T770IoV
+pdAYEiGAFO1Y22gK14FAzq1CY7/SGtPtie3fBDCDcbv+K/qw7sVZvkXWKKSpvYCq
+pB0xkmTWJGReAYh8QeI9KHuNhfEX2OO6fW2Tx9rt6ZzGxAZrQL7f1gKLjICEtYKp
+dG6OjHHHVZprsFt/czFkfY+cVFvuTOSD8MmCjO5ErM48lCWAVXhJnfDR+rSMjiq7
+2SSqN120vp6Bdm6jatoxsUV4KUIp0kkO8UPA5vJsn+wwX+gXfDjZnqBSTbkia9Mw
+xQ3mCSgYfhyxK8UCVoH466SXCqM7StqV3G04TqJVsmUCggEBALJOtikWCSQ//Izg
+LoVA73/KLqv/aPChCaJ3IzQ3fGjunx7T2GEljSXZFh0LMFetrz70eTO6wSRH4c3D
+FYNUpQP1hf8p4daVWxEgIcAePSpL/sfMsWCANwNb+RizHnXG1o6FsT4LlTm0akMJ
+UHtujrc8I1YQH7J+YAFQ/amk+nVOMvp5JedSlKAMxZZBm1beFOkS1r6UTPDqm87H
+4CX8guNw1z1MhTmEbpDcmp10q5rgP5MH2LKpMuv9jPh1f/uJXchWu+wyP9DwkMEW
+gl8tE1EuH+DAju0qWEYugDB7AFtGgs1dLj631VebApq8eMrPJHe2nQ9i1dIanue1
++lo4HH0CggEAQuU4UYzsbUvWYvNPrQdBVWcHZkMm3rR2kqlHR2bUII7xQwEWj9p7
+NeMfgGBT3cIXoSCxoq2Q1IPqCaErp5sO47hcqgGGzmyYs8fAcyY0IQpRD5yDnPBo
+DyUmMJRAyvuJtXNmsluEn0g0fAHsUUXLAYCe4HVHh4d4jbg9+Cd8KOZNNJPdokJu
+TZaSvZCKom9J6skTsKe2ZCjPJrTLfWcs432uN8ed/ILoXxWZHaP0tfFElFk2PdLX
+wTomRRzZI2xuv4B4BBH2OvE3e7hzsx9Cn7/MqoXTmu2EB1SR7OlKcSGal9JmKNYg
+BNRZqHZq9rJYJZMWpAHUSM5P1t4P+v31+QKCAQEAvkx6xN6DubYIgzHlaBW38iM3
+4pMUOA9DXIxQzDuYX1XCpxTv0d/9Y+nEWGJ9UeVAfRnyThYVoALAcI8xF/YLU9S9
+DiKgG89G6S8ZyVvYSWuJZWi1Y/Dup/SDcGXWuVO0fWS9UaDqzib4zFEtVtjjvkep
+xRZYetMM/v0xTKFCLU9hvsy/Ngb485ChPLgr12ajldubfkHZrmfqbBfqGAsUsmXA
+AP2BKkaopnNY/x8TYFcuYLiypYufXk8Hh/cUhWT0GiuAsPNmB4KwJjkXdktMbkpM
+6enkjxXX4TPfbxe4ftV2GpCdfR7sWFgcJTn+C45Lsl7QT+P65Onr1QNGyKIp7g==
+-----END RSA PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-req.pem b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-req.pem
new file mode 100644
index 00000000000..d0fe335f405
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-S00-req.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIFDzCCAvcCAQAwgckxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTYW1iYVN0YXRl
+MRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNhbWJhU2VsZlRlc3Rpbmcx
+GzAZBgNVBAsMEkRvbWFpbiBDb250cm9sbGVyczEiMCAGA1UEAwwZbG9jYWxkYy5z
+YW1iYS5leGFtcGxlLmNvbTE1MDMGCSqGSIb3DQEJARYmY2Etc2FtYmEuZXhhbXBs
+ZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQDmX0+3umQAlLILoCk7Zh8ohc36u9feGI7iSxSrMxdMX4uEDrIZzTKu
+Ko78jEtRwNku3n/S03qDnZVmbeAIGiUQL9Mnv8euOvkz5GWHr6KAh8z3aaNNjWUw
+gbMgyj9UKLfZH/6Qko80CwxE60ixVD5mKcOq6PT3LWoMzMIx9TV2SLqCyNAGQi/N
+Tj8gtfz2cvwO/pKjlxbHm0DkylxHOb2xTAnjp0LCDai1PvncfTkFTchfyGnchVw8
+miMHvDAzOKbEAwdZ45dVhGFlUoBg+ne2dloxMlGmIpi1q9xnUSN2CAmOOBx1C5xZ
+Qx9BBN1gadn6MbgWXrj4J4IWjsbO2VYBaORf+C0PMYUnN5L6TQuz82r0vjAVDY4A
+tYf4Z1yuaiVZI4y/pQLrt8wM/Lw7vYAI/KOGXy3seQWO5NLSxKarhOPaqljD24so
+SxVJeX5YGYt9PoeeeSgV4YqtdRALcR6P6B/N1JsR4UcmGvjUowt9CN6m8XqTJvu9
+eKNgiosp/vife17XZAPhWCOsIzU/T7n3PdbXZB8LaxGbEB8rSbL5Y+jPv6zanrf3
+EpHkAXeafzHItq99Xk5V7j0q+Q1WEUnj9gmML9AG6/T3ZZ/bhQpXfpq4GmARGNE9
+HMBTZZvoAJPkkWG26Htj09jscI2SVBKLVh/PgzTVRIbNtgv8lY/5EQIDAQABoAAw
+DQYJKoZIhvcNAQELBQADggIBAEO4n5lMOyBsZBuVKOyYYC2uFUCnIXepxLwpTN16
++8wNjXG25B0nm0dgmPpsq4zvYLAMY32vyxo81LKX2fh0f6xyovN7VOmXBUcwHVtl
+6GZIIFDOm8uMQutqX0HV25S9Q5nxqoX1K4stBNmHxAFmyp0vZgz5CcoOn36bWIr1
+CRLKt0RF0unUlzXKdQIdlmugxnfitKg6gkr2MN2ae2wQmZB2Z7Q6edfda82xw2l7
+yE2qwwpstjlgPSrM/W53byiXO5w+5UI1U4mbF8J5eB5xlaLaaoPwuDteOlw0TN+9
+FOgFp0MZq2Mu4YdO8Bcl7k+rTXyviyzNG9MiABYsMwZQ9XSClF6OUIxQFqXBgY7Z
+Xo2wp8ggCsWHgA5uofVXxbnkxquI4pEH9ZzI1jJT7nZIw7Dyb0RJcbMlLArPEbZ6
+pRQapv8vK4Sc3DVxLwu5bnxwzllTjGPQH9Z/uRjft7EK3cByO6x7jZJXpUOKK+0C
+eF8nvmsoqnPfx92tfNZ4tYXga/1hq5warOl++nDSpIPVNlLEhyATuFakxYj9qiag
+fn2qIrXEyoOmjKlTdUJehKIFviUVD+2o/9bBsS3x+fZLPxs8BbWHeq5BuZM5o9qV
+F5A1BrytjQwDWWznU9E/SSiWh0JqQeQaGWLBr1XAejSb7Xk5ecqsO+6aaWvYL9JD
+vI4t
+-----END CERTIFICATE REQUEST-----
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-cert.pem
new file mode 120000
index 00000000000..b7549bb7690
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-cert.pem
@@ -0,0 +1 @@
+DC-localdc.samba.example.com-S00-cert.pem \ No newline at end of file
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-private-key.pem
new file mode 120000
index 00000000000..21601b4df86
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/localdc.samba.example.com/DC-localdc.samba.example.com-private-key.pem
@@ -0,0 +1 @@
+DC-localdc.samba.example.com-S00-private-key.pem \ No newline at end of file
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-cert.pem b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-cert.pem
new file mode 100644
index 00000000000..4cc42aafc9c
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-cert.pem
@@ -0,0 +1,191 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+ Validity
+ Not Before: Mar 18 11:45:30 2016 GMT
+ Not After : Mar 13 11:45:30 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Domain Controllers, CN=plugindc.plugindom.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:aa:a3:74:2b:4b:6d:29:43:67:03:dc:c0:be:ce:
+ a6:e3:43:99:e5:87:34:34:42:70:4b:bb:50:87:6d:
+ e8:65:2b:5e:1a:b3:68:0d:9f:27:eb:dc:b8:84:bb:
+ 3d:f4:40:28:c0:c7:aa:e5:8d:a1:d5:7f:c7:6b:36:
+ 96:6b:3e:65:72:37:0e:d4:2c:03:4d:ee:e6:f8:41:
+ 5c:27:bf:32:53:6c:13:28:1f:be:78:9c:7c:80:53:
+ eb:4d:0a:19:1a:88:49:95:a9:c6:65:23:5b:3e:24:
+ 27:06:eb:7c:58:24:c6:e7:a4:d9:98:02:c4:ce:b3:
+ 1e:01:34:4c:bd:9c:28:da:10:4d:36:e9:7d:a8:68:
+ 04:75:18:eb:f0:58:94:05:b1:61:97:d5:9a:b3:db:
+ 09:71:74:90:05:87:d4:1c:ff:06:2b:c0:51:b6:26:
+ ca:28:8b:c2:08:3a:93:62:f8:69:b4:3b:c3:6d:9b:
+ 0f:80:1d:f8:c3:51:93:78:64:83:63:c7:d0:21:e8:
+ 05:cd:22:3e:3e:e2:c2:66:af:46:6c:c6:7d:d8:ed:
+ 53:b9:cc:42:e9:a2:43:94:31:f4:9e:45:fa:45:35:
+ ab:7f:32:93:95:a5:1b:4a:9d:27:c0:5f:bf:03:7f:
+ ca:37:c3:c2:c9:6f:b6:6e:5f:05:55:56:f5:2f:40:
+ c2:41:12:17:ee:23:1b:3a:9c:39:74:d5:cc:b1:47:
+ 6a:24:85:95:f5:aa:e6:35:40:0c:d3:8f:1e:d3:df:
+ b5:1b:7c:ff:3f:df:7e:7a:d3:f8:e1:92:b0:41:14:
+ f6:aa:1d:8c:36:3d:5c:c5:c5:b7:2f:b8:f8:09:47:
+ c2:51:58:de:80:41:c2:a5:18:c6:a9:16:39:d4:8e:
+ ef:f3:a9:c6:13:db:1e:f5:8a:e7:37:16:7c:df:28:
+ fe:19:44:7b:58:98:ee:72:fa:41:a2:f5:e0:77:c2:
+ 5e:fa:e1:94:87:96:17:66:75:07:45:c8:df:6a:40:
+ 19:3b:da:4d:48:e8:51:a3:1f:ba:41:62:0a:48:f5:
+ 62:42:9e:69:49:aa:ac:36:bd:6f:41:32:bb:62:8a:
+ 96:6b:01:aa:de:14:05:3a:43:e9:45:f2:00:9a:dc:
+ 71:20:b7:65:f2:f0:7d:b3:74:a0:43:1c:3f:5e:22:
+ 47:df:47:8d:5e:cb:93:1a:14:6e:b4:29:0f:af:1c:
+ 07:9c:11:74:24:38:09:23:76:0e:ca:fc:60:8f:1a:
+ e2:dc:d4:fd:fe:cb:12:f8:a7:83:c4:ae:db:a4:c7:
+ 74:b3:a5:76:90:93:9d:a3:78:01:97:e0:ec:09:78:
+ b9:98:ff:b7:2a:9d:05:03:5e:cf:b2:01:80:79:6b:
+ f9:5d:f5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+ Netscape Cert Type:
+ SSL Server
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Key Encipherment
+ Netscape Comment:
+ Domain Controller Certificate plugindc.plugindom.samba.example.com
+ X509v3 Subject Key Identifier:
+ DB:4F:D4:70:C3:38:E6:26:37:6F:1B:50:5E:7D:E5:80:7D:B4:08:0D
+ X509v3 Authority Key Identifier:
+ keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42
+
+ X509v3 Subject Alternative Name:
+ DNS:plugindc.plugindom.samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com@samba.example.com
+ Netscape CA Revocation Url:
+ http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+ X509v3 Extended Key Usage:
+ TLS Web Client Authentication, TLS Web Server Authentication, msKDC
+ Signature Algorithm: sha256WithRSAEncryption
+ ab:ed:44:9c:0d:f9:df:d6:8d:f2:98:05:cb:97:0c:14:9d:0c:
+ b3:2b:49:6c:4f:d6:8f:81:dd:c7:d9:67:be:ad:5b:f6:08:34:
+ 44:09:88:3a:9d:e9:fe:0b:91:89:f8:32:92:43:43:af:cf:04:
+ 5c:35:a4:d2:04:77:04:bf:37:45:57:2b:70:94:d0:7a:5f:b9:
+ d6:9c:47:ac:46:e4:4c:c2:87:5d:78:b7:3c:be:80:42:dc:3c:
+ 36:3b:c0:57:fb:ec:95:3a:bb:58:7e:09:ff:57:4e:4f:59:73:
+ 2a:65:0e:6e:a8:b3:8e:22:6b:40:0c:b5:5b:96:f3:a1:35:92:
+ 17:12:24:f3:43:fe:54:1d:ac:f9:f1:72:cb:97:b8:43:2f:e1:
+ ac:9c:a6:e7:78:98:38:ad:83:eb:c9:77:0b:ea:5a:21:6a:76:
+ f7:b2:4c:d7:7b:d4:57:eb:4c:a4:6e:be:eb:be:60:99:ae:ce:
+ 13:1c:6a:9f:58:e5:64:a2:b6:4e:2a:2e:62:99:d8:fa:af:11:
+ 5c:7e:51:d3:cf:7e:84:1c:f4:8b:a5:df:c8:b2:39:4c:c3:40:
+ 48:2e:b6:9d:3d:bf:b1:7b:58:39:f0:38:60:72:42:f4:8c:2a:
+ b3:66:c1:e9:12:bc:2a:51:75:55:1e:56:2a:bc:6e:40:1c:2b:
+ 16:25:90:97:18:4e:b4:63:dc:ff:7a:31:5e:b2:38:c4:17:65:
+ 3d:1a:31:47:04:75:3a:b7:83:c3:59:09:d5:99:56:45:4d:a0:
+ c8:6f:3e:87:61:17:4f:2e:7b:5c:34:76:45:e1:b5:bf:c4:fe:
+ 32:31:ff:2c:95:52:9c:12:2a:c3:b8:04:f9:25:a3:11:64:35:
+ c8:5d:92:f9:fc:2c:ba:45:18:d0:dc:95:1c:dd:30:16:3f:56:
+ a4:15:45:85:9b:52:55:3f:f6:a8:dd:54:53:d2:84:1b:d3:1a:
+ 97:61:8a:60:d6:fb:a1:75:f3:15:8f:b7:f3:f4:41:dc:7d:24:
+ 90:9a:62:23:a1:ef:c1:01:69:d4:a1:69:82:58:5f:35:b4:83:
+ b1:7c:cf:dc:f2:ca:23:af:5a:ac:e9:53:53:bd:33:8e:22:2a:
+ 1b:cf:ea:e7:e0:24:b2:f5:f7:ff:f6:99:6c:34:13:e9:f2:50:
+ 70:a1:0f:ec:f9:12:22:99:58:08:5d:f0:49:86:f8:14:3b:1b:
+ e6:49:eb:9b:fb:b1:07:60:e0:05:e6:4f:13:39:d1:ea:07:6b:
+ e8:85:33:eb:4f:b7:d3:7f:bd:9b:f4:a4:40:f4:a4:4a:f6:5f:
+ db:04:f5:f8:04:fa:1a:13:1b:cc:75:6f:c2:df:9d:89:12:5b:
+ f1:fa:cf:df:b6:32:3c:3c:5e:e0:26:9a:c7:e7:87:e7:5b:9a:
+ 76:b3:41:a3:0f:e1:f2:12:69:db:1b:32:57:a4:ad:5b:52:32:
+ 8d:7e:ec:34:c4:ce:d2:ee:6b:96:56:0e:ef:97:9a:26:a3:b5:
+ a0:4c:9a:e0:4f:9b:8d:07:df:92:46:1b:53:53:eb:96:62:74:
+ a8:13:03:e3:1f:13:0e:48:22:ca:ba:94:7f:86:80:c0:76:ab:
+ 08:36:e4:02:f3:ad:31:2f:97:00:06:57:09:12:66:d5:4e:8f:
+ 5b:88:67:7c:e3:0f:df:1c:97:17:85:9f:b9:08:4c:6e:88:e3:
+ e7:b9:53:06:87:98:e8:a3:9f:7c:7d:c9:07:d8:69:74:d1:e7:
+ c1:e6:46:e9:0f:2d:4f:04:6d:41:e8:b8:a7:87:d4:5b:1f:89:
+ e4:b1:c0:ba:78:2e:7d:cf:84:56:25:56:95:f7:93:dd:4a:47:
+ 88:b5:ac:d7:da:a7:b3:c9:8c:c5:41:34:8c:31:24:84:d4:51:
+ bb:46:4a:3c:db:72:e6:1b:c1:c2:15:6e:1a:ac:61:bd:ce:f1:
+ a3:ff:60:d9:a7:90:5a:3a:3e:1c:28:13:ed:cf:ef:ed:f1:fb:
+ 79:3a:57:ac:41:de:e6:17:d0:92:c6:fc:bd:6a:1c:e0:44:c7:
+ d7:ce:80:b4:c2:59:75:a8:bc:8b:32:4e:ea:2a:ff:89:fb:f9:
+ 98:6b:04:1a:fd:9e:2e:b9:bf:60:d5:84:80:f8:5b:03:0d:d9:
+ 1e:30:cf:4e:78:2c:a1:88:6d:ee:80:a2:ec:d9:96:00:c9:82:
+ a2:81:c0:6e:74:4b:69:9f:fd:c2:ed:0a:f7:31:a9:dc:89:f7:
+ c5:83:83:51:bf:f0:f6:8f:22:72:8e:f6:0b:54:d0:b8:7a:39:
+ 62:d1:d8:76:bd:c3:85:be:18:41:e9:42:c2:80:21:1c:86:20:
+ f9:4b:55:5f:e3:e1:6e:ae:ab:0a:4a:0c:05:1f:0d:b5:1f:a0:
+ d6:92:dd:20:71:56:74:e8:13:83:2f:4f:d0:72:98:b8:57:b5:
+ cc:06:63:3b:29:5b:f7:be:fc:e1:0e:24:94:da:1c:d1:ba:9f:
+ 7b:af:0d:d9:80:ed:18:85:74:73:62:2f:cb:37:e2:8c:85:90:
+ e9:86:dc:2b:78:b5:2a:47:fb:a1:41:f1:d4:2f:66:87:17:a5:
+ 24:20:54:61:99:03:72:56:5f:96:92:bf:25:4e:d0:20:a0:26:
+ 85:ac:b1:d2:7b:b9:b9:e9:9c:9d:01:52:a7:29:32:bd:94:65:
+ fb:bc:41:d2:9e:6c:59:c7:9a:b6:92:38:ba:fa:08:fc:1f:c7:
+ 72:9a:a3:a2:cb:02:e3:fc:29:20:20:b7:15:76:73:ab
+-----BEGIN CERTIFICATE-----
+MIIKDDCCBfSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTgxMTQ1MzBaFw0zNjAzMTMxMTQ1MzBaMIHAMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEbMBkGA1UE
+CwwSRG9tYWluIENvbnRyb2xsZXJzMS0wKwYDVQQDDCRwbHVnaW5kYy5wbHVnaW5k
+b20uc2FtYmEuZXhhbXBsZS5jb20xNTAzBgkqhkiG9w0BCQEWJmNhLXNhbWJhLmV4
+YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOC
+Ag8AMIICCgKCAgEAqqN0K0ttKUNnA9zAvs6m40OZ5Yc0NEJwS7tQh23oZSteGrNo
+DZ8n69y4hLs99EAowMeq5Y2h1X/HazaWaz5lcjcO1CwDTe7m+EFcJ78yU2wTKB++
+eJx8gFPrTQoZGohJlanGZSNbPiQnBut8WCTG56TZmALEzrMeATRMvZwo2hBNNul9
+qGgEdRjr8FiUBbFhl9Was9sJcXSQBYfUHP8GK8BRtibKKIvCCDqTYvhptDvDbZsP
+gB34w1GTeGSDY8fQIegFzSI+PuLCZq9GbMZ92O1TucxC6aJDlDH0nkX6RTWrfzKT
+laUbSp0nwF+/A3/KN8PCyW+2bl8FVVb1L0DCQRIX7iMbOpw5dNXMsUdqJIWV9arm
+NUAM048e09+1G3z/P99+etP44ZKwQRT2qh2MNj1cxcW3L7j4CUfCUVjegEHCpRjG
+qRY51I7v86nGE9se9YrnNxZ83yj+GUR7WJjucvpBovXgd8Je+uGUh5YXZnUHRcjf
+akAZO9pNSOhRox+6QWIKSPViQp5pSaqsNr1vQTK7YoqWawGq3hQFOkPpRfIAmtxx
+ILdl8vB9s3SgQxw/XiJH30eNXsuTGhRutCkPrxwHnBF0JDgJI3YOyvxgjxri3NT9
+/ssS+KeDxK7bpMd0s6V2kJOdo3gBl+DsCXi5mP+3Kp0FA17PsgGAeWv5XfUCAwEA
+AaOCAgcwggIDMAkGA1UdEwQCMAAwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3
+dy5zYW1iYS5leGFtcGxlLmNvbS9jcmxzL0NBLXNhbWJhLmV4YW1wbGUuY29tLWNy
+bC5jcmwwEQYJYIZIAYb4QgEBBAQDAgZAMAsGA1UdDwQEAwIF4DBRBglghkgBhvhC
+AQ0ERBZCRG9tYWluIENvbnRyb2xsZXIgQ2VydGlmaWNhdGUgcGx1Z2luZGMucGx1
+Z2luZG9tLnNhbWJhLmV4YW1wbGUuY29tMB0GA1UdDgQWBBTbT9RwwzjmJjdvG1Be
+feWAfbQIDTAfBgNVHSMEGDAWgBRGh4bC5xnPFkwMYstzf/2PGeS1QjBIBgNVHREE
+QTA/giRwbHVnaW5kYy5wbHVnaW5kb20uc2FtYmEuZXhhbXBsZS5jb22gFwYJKwYB
+BAGCNxkBoAoECAEjRWeJq83vMDEGA1UdEgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUu
+Y29tQHNhbWJhLmV4YW1wbGUuY29tME0GCWCGSAGG+EIBBARAFj5odHRwOi8vd3d3
+LnNhbWJhLmV4YW1wbGUuY29tL2NybHMvQ0Etc2FtYmEuZXhhbXBsZS5jb20tY3Js
+LmNybDAmBgNVHSUEHzAdBggrBgEFBQcDAgYIKwYBBQUHAwEGBysGAQUCAwUwDQYJ
+KoZIhvcNAQELBQADggQBAKvtRJwN+d/WjfKYBcuXDBSdDLMrSWxP1o+B3cfZZ76t
+W/YINEQJiDqd6f4LkYn4MpJDQ6/PBFw1pNIEdwS/N0VXK3CU0HpfudacR6xG5EzC
+h114tzy+gELcPDY7wFf77JU6u1h+Cf9XTk9ZcyplDm6os44ia0AMtVuW86E1khcS
+JPND/lQdrPnxcsuXuEMv4aycpud4mDitg+vJdwvqWiFqdveyTNd71FfrTKRuvuu+
+YJmuzhMcap9Y5WSitk4qLmKZ2PqvEVx+UdPPfoQc9Iul38iyOUzDQEgutp09v7F7
+WDnwOGByQvSMKrNmwekSvCpRdVUeViq8bkAcKxYlkJcYTrRj3P96MV6yOMQXZT0a
+MUcEdTq3g8NZCdWZVkVNoMhvPodhF08ue1w0dkXhtb/E/jIx/yyVUpwSKsO4BPkl
+oxFkNchdkvn8LLpFGNDclRzdMBY/VqQVRYWbUlU/9qjdVFPShBvTGpdhimDW+6F1
+8xWPt/P0Qdx9JJCaYiOh78EBadShaYJYXzW0g7F8z9zyyiOvWqzpU1O9M44iKhvP
+6ufgJLL19//2mWw0E+nyUHChD+z5EiKZWAhd8EmG+BQ7G+ZJ65v7sQdg4AXmTxM5
+0eoHa+iFM+tPt9N/vZv0pED0pEr2X9sE9fgE+hoTG8x1b8LfnYkSW/H6z9+2Mjw8
+XuAmmsfnh+dbmnazQaMP4fISadsbMlekrVtSMo1+7DTEztLua5ZWDu+XmiajtaBM
+muBPm40H35JGG1NT65ZidKgTA+MfEw5IIsq6lH+GgMB2qwg25ALzrTEvlwAGVwkS
+ZtVOj1uIZ3zjD98clxeFn7kITG6I4+e5UwaHmOijn3x9yQfYaXTR58HmRukPLU8E
+bUHouKeH1FsfieSxwLp4Ln3PhFYlVpX3k91KR4i1rNfap7PJjMVBNIwxJITUUbtG
+SjzbcuYbwcIVbhqsYb3O8aP/YNmnkFo6PhwoE+3P7+3x+3k6V6xB3uYX0JLG/L1q
+HOBEx9fOgLTCWXWovIsyTuoq/4n7+ZhrBBr9ni65v2DVhID4WwMN2R4wz054LKGI
+be6AouzZlgDJgqKBwG50S2mf/cLtCvcxqdyJ98WDg1G/8PaPInKO9gtU0Lh6OWLR
+2Ha9w4W+GEHpQsKAIRyGIPlLVV/j4W6uqwpKDAUfDbUfoNaS3SBxVnToE4MvT9By
+mLhXtcwGYzspW/e+/OEOJJTaHNG6n3uvDdmA7RiFdHNiL8s34oyFkOmG3Ct4tSpH
++6FB8dQvZocXpSQgVGGZA3JWX5aSvyVO0CCgJoWssdJ7ubnpnJ0BUqcpMr2UZfu8
+QdKebFnHmraSOLr6CPwfx3Kao6LLAuP8KSAgtxV2c6s=
+-----END CERTIFICATE-----
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-key.pem
new file mode 100644
index 00000000000..21de683bd19
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-key.pem
@@ -0,0 +1,54 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIJjjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI8qLXeXVBnvQCAggA
+MBQGCCqGSIb3DQMHBAgbmdRIPfia2ASCCUi97VRXS5hQ6b+T8cv5YOs0CdVw+XBd
+3ZiBBM1FF4lFjGMpA+YRLkcC2ksn+dW4Obyimqi6ODk3jhikXJ8LhgCa4uo22ghU
+Pmqsgs3xScwJEM6VHZSGQ0ULJ+wce6mgIPCVzNRkpkREZ+jT9NAPTxSQoBJDYggV
+WERdMf+3us7i2uyn4l+mAbuggEMWgJgXcz5QVCDmMilYW3CHeuT/6VW04ma0dyGa
+d6O4y5DHZiO9u+oCPiHzPWrR9VCD6uq3Yr7JU5B0Aee3Fj/5NXAFsPq5a9VCP76R
+oF7maYitgl1RtPYmD60bGA4yJI1hEsq+xiq/VM0ZHkvKOQJp7Jvp4xR2QPnr71IF
+gmx4GAekWd02sFd3cjt7MV/nRm4W8TWGtQfm8c8Ino5T8zs74EGViNnAMg8wdzqL
+tlmwkOgN94VFXl/taY4qLlmskTD/sdsfwuF6Q+4tef8iDQfxko8dWr8nT3Vj9VWD
+5lQMiolcdJ96CfCitxZXkPL9lPr1LNBOFhTEZ71mhjcXFx7fPdbhTekKAMm060uV
+6ycl+iLWjsJngA4SJZoeBNB+aMCWq/HT9yMWQOQHx80f65AsygGUJlZFkVBO8oQh
+GLIZzZ425ZGwGF235GrQ7gKHYvZcFL+rmhPJAO/xPS0oM87fS760kVfriOwP9JPV
+S7VlmLbdZ3jmz5XWggD2M1Stl0A9+Mwiss6/5IxHgcvew2VCYRQnxss5KCS52UOB
+6ZMG7QlAhLMds/0dEPW5tvupojXMQj2GD1kC1LAWUGrhN2QkJ0efIs4I7sRvYyr0
+5QHBlQACNT8J/W9DiTXAbgMernAgrCGw0RN9Ibnlf2Uf8KWB1HPv7LWnjjyeU6Sj
+8WdAOHPZUkYj71WhAy/UqO9gZ1RbbYtmQ4PnU0tWdzABJbRQQCnXbP0C/b3QNA5Q
+ocTzBg0IUYN2SVw4ApVz8prSHiXNlNxMAnVKGdIbBB3t+a3vXCkHden01MemoP6m
+ybUFPlQ479TvSNut7v7ZwQjtTliiU3plPUuT6fwvXlJfnn+QzKCh0CEbgadQvYam
+lZ8bzkVOTtX+eLG3ZOGUrY6yFf+jFuPx94kE4BJU/DtK9mP/gPWrD6dm476X5xRX
+J2+zPWYogBxkHhANoNI18B3VszEzB9MYzngIUJDJU+5gC8lYtT3O4ZZNlDbj1n/e
+NOEZWxXUaGbGZ84RTbCJxWcZoEVQ0YUWAG7ALNPVBweLcxtx+wH1ctxsv1jNz8uP
+poUMKGbX6EYkE8Ytvq5a3/hlwXcxxX+ynII6X5UJ8jssD3vmMJdHQyY0QhgIoRgJ
+fV0DIqP42bwsEe03F5VFqjBbeGT5Db2RLenoPeYRiBCGjnJvWD20T+mqepBy2Ugj
+I0/+SpELZhID7Ltpfdg5CKqN4/YCaO+gxY3A9Spw2iSmaVCwNXEmlbzh6gv/fRuD
+J3rad27S302caZunZkw6yIjYAcvtT694Wd7mUMFQtjiB6QJPfeNBo1XnSvstWv4b
+yEsKK1gJGTyiYn3/+zUGfuky7TRaKkNyA1baHlQdz42fzX8OHQwausFOjy3HgICM
+pgkirbylxyS9b0utYO1utqOButyfd0P8Y5WKyBZtYV9vY0WlJKwDSRxZBpv9tL6K
+LANEpcSmWZ9gKjpFtmaAIvN03GoLc2aYOwKL3vVOnbkyuUXN7XQDWpMX+xy7AlVR
+IdR2Po2xTH/Hk3kFJW7MxrURNuSGKuHj7HVdWy5pTem/g6RL/OjPbiS3ys76XcoM
+44h71IPOCGTxIGqMpPUAnJk59pOSJFaJLU3Gh87dBAk/amwbPfjRc2VI/d1hVpdB
+jyIFhLOSKOQlIey/29ueDXWVxKbeOSVVPv2QxrI9EvpC7Uayq+ADd4kNDHfz/Jz8
+MknA/T9VmstCyjTQ4mgpwyvoAZCRa+V8nrLWm3Di6fIg8QUv7SZ+qWYKAhgG363t
+5IRnnfoFD3ikCeBKYtiqhvtXoCQIm/rbOvTuLMOx43nF6Vw/nOBHG46ZZUzdwC8u
+2EZnRjKOnxCtAGMkbHf6yMgG8zgM+obAHiD41CpBgDogpzS6zphTQEfDRAiqRNVQ
+XrAaME5bn8aXozGEudPLJD0A0jqaXQiO8UXhToTBefGRqttXSE7XpuweUJ+34j0J
+StpyjL/rXYBb0lfBV+jyOwNB4PCuGcKdEQWiX3usQH1NTJvhRt1iJx17E/GOBGMR
+ygZIMK8vPKSLVfUOuwaXtJBQyH3BfNzwNyBFB2UvZ0xxrlVpi8ro3/6VUDPNNA4F
+ld1bLhG0+M9LNuhset/qvYN41Y8fsQm+bHkIC9IDyCJ5I3bKfPEKFVBDDMKHT3R2
+NVKsCzQSmqLfmhGxgubdjt4fUVDK0BAfQDYsEp9DK9miD6igAy7IM+RkYfK2TqSW
+bOFaf+1YN3W3WMllBYTHuaz+NwgjS6L4z9fgm/f10rEp1HY/Qqvkj9hdw7W5r8IK
+vcCdXa5jM4tuXIpF/GdvwXskFQl8aGGTflU8GNjV7TJ/7SACWdHillQlkkq3VljI
+hqo17cJgHC4NWFhR1X/gnpTOe80Ljkg4QIC7Nam/6rm77+acnfYtJKxOaxv3W6i2
+NCAjBeMRaKrKTIa+YCRQnAYrq8Cx2vWspb/kM7rDMiHaIbDvh0sST6MWXWYqudNs
+Oxdal0PIZx5D1KvtHrX4PhomnTzYcQ81Jz/ufqg9DrpmYZGOm2mVVgRuxjHtBBpk
+97t8sq3kpxXwcDAc1QeQyNekq+mG+qIevkyI5T/lPJEKEJkcpNYqkLoThegtNgzD
+l+lyL5sC9VYcgDhpKH8UoalSFWFVNBu71yXF0lYorRRBFcCFEiEKQOgOvJyB3ire
+f9aRNfo4ukS74BjBu5rqPoQe5JUlO8QGCQjk8y9t6Iz+WoBSZFUGVOeXWSPaWif2
+3y/zTwfvWW7FQB3hqUkqEQg3G2pJbK2a9jspy8vC2nQdr7Lip6FRBQk4Gt8Dp9rq
+EancUwVeMfMRT58jgEH90yJfZk/f8VF1MQh+ByIl2YWfVZjydFOVetG/iHAH4cZs
+/Y/XEG0L79XHlJu+Ccl2T4V6hhRJl6bD234FEsGPO5XFa7oueoy4w0ejdC3D8Ayu
+mwYpvmsfsGJm4C3dbiQLZ8568OkOy32Dq1CSiE/lz6YgcqBlj+T7H6ZWpHN9dkMo
+5zs=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-openssl.cnf
new file mode 100644
index 00000000000..56b18390c03
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-openssl.cnf
@@ -0,0 +1,250 @@
+#
+# Based on the OpenSSL example configuration file.
+# This is mostly being used for generation of certificate requests.
+#
+
+# This definition stops the following lines choking if HOME isn't
+# defined.
+HOME = .
+RANDFILE = $ENV::HOME/.rnd
+
+#CRLDISTPT = [CRL Distribution Point; e.g., http://crl-list.base/w4edom-l4.base.crl]
+CRLDISTPT = http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+# Extra OBJECT IDENTIFIER info:
+oid_section = new_oids
+
+# To use this configuration file with the "-extfile" option of the
+# "openssl x509" utility, name here the section containing the
+# X.509v3 extensions to use:
+# extensions =
+# (Alternatively, use a configuration file that has only
+# X.509v3 extensions in its main [= default] section.)
+
+[ new_oids ]
+# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used as a login credential
+scardLogin=1.3.6.1.4.1.311.20.2.2
+# Used in a smart card login certificate's subject alternative name
+msUPN=1.3.6.1.4.1.311.20.2.3
+# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used to identify a domain controller
+msKDC=1.3.6.1.5.2.3.5
+# Identifies the AD GUID
+msADGUID=1.3.6.1.4.1.311.25.1
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = CA-samba.example.com # Where everything is kept
+certs = $dir/_none_certs # Where the issued certs are kept
+crl_dir = $dir/_none_crl # Where the issued crl are kept
+database = $dir/Private/CA-samba.example.com-index.txt # database index file.
+unique_subject = yes # Set to 'no' to allow creation of
+ # several certificates with same subject.
+new_certs_dir = $dir/NewCerts # default place for new certs.
+
+certificate = $dir/Public/CA-samba.example.com-cert.pem # The CA certificate
+serial = $dir/Private/CA-samba.example.com-serial.txt # The current serial number
+crlnumber = $dir/Private/CA-samba.example.com-crlnumber.txt # the current crl number
+ # must be commented out to leave a V1 CRL
+
+#crl = $dir/Public/CA-samba.example.com-crl.pem # The current CRL
+crl = $dir/Public/CA-samba.example.com-crl.crl # The current CRL
+private_key = $dir/Private/CA-samba.example.com-private-key.pem # The private key
+RANDFILE = $dir/Private/CA-samba.example.com.rand # private random number file
+
+#x509_extensions = # The extensions to add to the cert
+x509_extensions = template_x509_extensions
+
+# Comment out the following two lines for the "traditional"
+# (and highly broken) format.
+name_opt = ca_default # Subject Name options
+cert_opt = ca_default # Certificate field options
+
+# Extension copying option: use with caution.
+# copy_extensions = copy
+
+# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
+# so this is commented out by default to leave a V1 CRL.
+# crlnumber must also be commented out to leave a V1 CRL.
+crl_extensions = crl_ext
+
+default_days = 7300 # how long to certify for
+default_crl_days= 7300 # how long before next CRL
+default_md = sha256 # use public key default MD
+preserve = no # keep passed DN ordering
+
+# A few difference way of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+# For the 'anything' policy
+# At this point in time, you must list all acceptable 'object'
+# types.
+[ policy_anything ]
+countryName = match
+stateOrProvinceName = match
+localityName = match
+organizationName = match
+organizationalUnitName = match
+commonName = supplied
+emailAddress = supplied
+
+####################################################################
+[ req ]
+default_bits = 4096
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extensions to add to the self signed cert
+
+# Passwords for private keys if not present they will be prompted for
+# input_password = secret
+# output_password = secret
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString (PKIX recommendation before 2004)
+# utf8only: only UTF8Strings (PKIX recommendation after 2004).
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings.
+string_mask = utf8only
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = US
+countryName_min = 2
+countryName_max = 2
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = SambaState
+
+localityName = Locality Name (eg, city)
+localityName_default = SambaCity
+
+organizationName = Organization Name (eg, company)
+organizationName_default = SambaSelfTesting
+
+organizationalUnitName = Organizational Unit Name (eg, section)
+organizationalUnitName_default = Domain Controllers
+
+commonName = Common Name (eg, YOUR name)
+commonName_default = plugindc.plugindom.samba.example.com
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_default = ca-samba.example.com@samba.example.com
+emailAddress_max = 64
+
+# SET-ex3 = SET extension number 3
+
+[ req_attributes ]
+#challengePassword = A challenge password
+#challengePassword_min = 4
+#challengePassword_max = 20
+#
+#unstructuredName = An optional company name
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+[ v3_ca ]
+# Extensions for a typical CA
+# PKIX recommendation.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer
+
+# This is what PKIX recommends but some broken software chokes on critical
+# extensions.
+#basicConstraints = critical,CA:true
+# So we do this instead.
+basicConstraints = CA:true
+
+# Key usage: this is typical for a CA certificate.
+keyUsage = cRLSign, keyCertSign
+
+crlDistributionPoints=URI:$CRLDISTPT
+
+# Some might want this also
+nsCertType = sslCA, emailCA
+
+# Include email address in subject alt name: another PKIX recommendation
+subjectAltName=email:copy
+# Copy issuer details
+issuerAltName=issuer:copy
+
+[ crl_ext ]
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always
+
+#[ usr_cert_mskdc ]
+[ template_x509_extensions ]
+
+# These extensions are added when 'ca' signs a request for a domain controller certificate.
+
+# This goes against PKIX guidelines but some CAs do it and some software
+# requires this to avoid interpreting an end user certificate as a CA.
+
+basicConstraints=CA:FALSE
+crlDistributionPoints=URI:$CRLDISTPT
+
+# Here are some examples of the usage of nsCertType. If it is omitted
+# the certificate can be used for anything *except* object signing.
+
+# This is OK for an SSL server.
+nsCertType = server
+
+# This is typical in keyUsage for a client certificate.
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+# This will be displayed in Netscape's comment listbox.
+nsComment = "Domain Controller Certificate plugindc.plugindom.samba.example.com"
+
+# PKIX recommendations harmless if included in all certificates.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+
+# This stuff is for subjectAltName and issuerAltname.
+
+subjectAltName=@dc_subjalt
+
+# Copy subject details
+issuerAltName=issuer:copy
+
+nsCaRevocationUrl = $CRLDISTPT
+#nsBaseUrl
+#nsRevocationUrl
+#nsRenewalUrl
+#nsCaPolicyUrl
+#nsSslServerName
+
+#Extended Key requirements for our domain controller certs
+# serverAuth - says cert can be used to identify an ssl/tls server
+# msKDC - says cert can be used to identify a Kerberos Domain Controller.
+extendedKeyUsage = clientAuth,serverAuth,msKDC
+
+[dc_subjalt]
+DNS=plugindc.plugindom.samba.example.com
+otherName=msADGUID;FORMAT:HEX,OCTETSTRING:0123456789ABCDEF
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-private-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-private-key.pem
new file mode 100644
index 00000000000..c436d7d5429
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-private-key.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKAIBAAKCAgEAqqN0K0ttKUNnA9zAvs6m40OZ5Yc0NEJwS7tQh23oZSteGrNo
+DZ8n69y4hLs99EAowMeq5Y2h1X/HazaWaz5lcjcO1CwDTe7m+EFcJ78yU2wTKB++
+eJx8gFPrTQoZGohJlanGZSNbPiQnBut8WCTG56TZmALEzrMeATRMvZwo2hBNNul9
+qGgEdRjr8FiUBbFhl9Was9sJcXSQBYfUHP8GK8BRtibKKIvCCDqTYvhptDvDbZsP
+gB34w1GTeGSDY8fQIegFzSI+PuLCZq9GbMZ92O1TucxC6aJDlDH0nkX6RTWrfzKT
+laUbSp0nwF+/A3/KN8PCyW+2bl8FVVb1L0DCQRIX7iMbOpw5dNXMsUdqJIWV9arm
+NUAM048e09+1G3z/P99+etP44ZKwQRT2qh2MNj1cxcW3L7j4CUfCUVjegEHCpRjG
+qRY51I7v86nGE9se9YrnNxZ83yj+GUR7WJjucvpBovXgd8Je+uGUh5YXZnUHRcjf
+akAZO9pNSOhRox+6QWIKSPViQp5pSaqsNr1vQTK7YoqWawGq3hQFOkPpRfIAmtxx
+ILdl8vB9s3SgQxw/XiJH30eNXsuTGhRutCkPrxwHnBF0JDgJI3YOyvxgjxri3NT9
+/ssS+KeDxK7bpMd0s6V2kJOdo3gBl+DsCXi5mP+3Kp0FA17PsgGAeWv5XfUCAwEA
+AQKCAgBgQ44Jzqdqm+fFugfSnOpxU3XCkx/US5bmYmnvvQVZ7blM/uE4rgzrdr1x
+w+ATpw5Wk03J6rjdpRRvW4BISA8a/AyVja7fjGMosla25ZoSjenQvPfLOxzRmIYq
+FARNf41jrT+LVwLmb6bEtJyVbUn47HsE0qsMoOfQbhzM6wfw3TlyPQ7yrpu1I7YX
+BSGchJE2Av8fb/ZH1yZYuGPlZ8mnbPur8v4hGZcA5Wq4bsPTNdPuRYfdEwt/xMmZ
+Jbsp01OLjUWYkDTlbS+WllL4kpH0iw6sxpsJCs1tETGbCIdD/B8fxvyTc22ODlKa
+qGkuJC2EgB+nXCpi4aA0oLX5TmNHPnzIAb1d5OEqw20Iwr/tV39RYC7xuLV1FidU
+3qj0jNCJkf+v7TIB0E1CoEbPIRj7plQJWWgTj+EEHtTz/b1lyPLnRUYxfTm1Pcje
+SbYjDd/GxKmUhNQyxIGuNR1B2JA6qZiaYfjFCp4h54NwHWvt0yMR5xUglG7+IGof
+jcLPHlsZtnCit/bGUz35JdbirQFbBWIAHpqLlPf7dqVzaTwI/nw6jdQ/bUxq24kz
+p8f3V7OEzKdemXfGBV9bk9hD+zeCQwm3EqILmPU3Be+sF2xWlkWwR2Xygy8xQ0q5
+2/BnLkY2dXZQMEEJJi5gZRN+irvpC33G4X1qXGZfDjvkeqOeAQKCAQEA1QoWw3Xi
+qyxoSf7F/KZefo1IsXsIsuXYG25fLWExDHncpxEpXl+IqQx1icfMeM0EP/jUFjWu
+Ti9V09u9FcP5Dl+uHfHqc3zFBJfAGhlPH+7YhVcjAzBx5LA7J65GqO3CHSUVk74G
+4nvAr51R1ba85VfgCavllaS6oJcEOZxECBT+1DicaD4Ir6QSDH0+d19t4LUDw1G8
+ARlOpC9rP/eSGL5LqOTiZ8LjjruGI55GG0vpgoG3bEli/Or8uqZzqZjYR5dD9Wfo
+MIjqdDjmojOiZMh9m/coZlphQaGl3Rqb3e2RZkZ2n+wyyo8g5DknyPKyiN0qu9nt
+86m/B3bE0RaFIQKCAQEAzQx3hpsD5PtTXL/K43OXVb4/r9OTwF55TuCnne4xBqgv
+jHMtMsgF481gCtrIbbZ+TH6B5FdYNHBui2hfrN4R1XZoAjAuCRxgHQn8UPd9G415
+aieSIj/wPUQgl8AIOygxDw28FvjDqf7khKF9z+pDsxNDqkTxFl04zYb2cLUBW9/r
+xQ68sb8BxxQ7qbR94gyOnSGO0+9Vy3MQNUAfLbbqMyBKbFym4gPGkVdGCvAaMsHn
+Hu2Z0oZSEwe3hAVL6ZnrqvMOxDbJ7RKZev1YfZGdno8YemAXKwRk3LOxXxodAF4x
+bUUOaY/AVqYvLGu7SJ4h4LBFn/DPnEbpceN3IO/qVQKCAQBH3NZe6rYiXaF0TG/G
+0OwRLmF2FPWTOzsRzcJnUWC1P6ox5PUac4lq1NwVNQOBQE8NsUcBkuwQTaFbDMWU
+wP2TXq0iRsd6W30uFm5jn2P0dqItIH6cBcx1gwkBUqVdOI6BPFAx/SjfXzVZR+0h
+9Tl095aITKbuOpoFr8tqD49XVpW7Srlf5IUTknnQIrNemx86bHUvfrO3fyzq71/z
+PPTYSeDFwSeqLrCKJjGSdEJb1NiZAF66NWshu7ay05EyhW93fswazQkizhygRc1u
+q5I9AvB0GwRSumwSMo/7rI0laIzifiRnv8pGT8+djLYh79RPnKNcqJ++0OSyhNrR
+WRJhAoIBAQCjzjjSNJY44DopVyJ68AXOvqxcBzb6r75TMA9XkEhkHAnYNs69yaNC
+5/e41CzX0Lk23L1hsBFL2yHEhr4f+Evg7rWKQfkU2DFEIY0LFZtBXpTHJBOO/usp
+1nn/IK6yq5n9f6hp5ZNSA8mE1woOBgTNUy90H51Fk3VkY1QOl9sdDVZpVyuRB5kg
+893x5bnG0uc/SeazEnjEjgg9shr2RzDzZPFvfdjnp8KCq2jOJh+XuuWrBH8k+p8o
+irqlYiHR3V+ycneycl5/4KLx6OA/eAul9oTEhm0btWfqFDc3VUIj4Bu2QjuQQwGR
+dzMqVmoISiOgPtFwQ01neBLYI7Iwgtj9AoIBAApZsr/9mYNwzPamSGc1zyDF/9j5
+EM6MXgFAQxpxzQlC36EDliZ8RvrQSJ5HjWxIihcZP/iR0rUBn71kitj5B88iURbF
+lsKyjbX4ZfrmClWiFkmJv0Js4n8+H3YdqFeUPgD3gQ1UfcViJgEt0iOv6N6qN32Q
++ofcWP6cdMEzXmfK+q53U6C38d2WD3QFoc/5qB0NnDYMr7Al4LHcfNwOmxIHDd7q
+C/0ang9tkbjVehX6S1DozFEgmMxYU8ZrB/KwYRMEXTUNSjyn2PXgTNqMch9OZpsD
+c9jmUdN9x7Pi7pyaxiREBpRDp9Cj0RZEcASeUKH2lpuEl7dT9YZaShBeY20=
+-----END RSA PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-req.pem b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-req.pem
new file mode 100644
index 00000000000..4fc6722945f
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-S02-req.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIFGjCCAwICAQAwgdQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTYW1iYVN0YXRl
+MRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNhbWJhU2VsZlRlc3Rpbmcx
+GzAZBgNVBAsMEkRvbWFpbiBDb250cm9sbGVyczEtMCsGA1UEAwwkcGx1Z2luZGMu
+cGx1Z2luZG9tLnNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkBFiZjYS1z
+YW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcN
+AQEBBQADggIPADCCAgoCggIBAKqjdCtLbSlDZwPcwL7OpuNDmeWHNDRCcEu7UIdt
+6GUrXhqzaA2fJ+vcuIS7PfRAKMDHquWNodV/x2s2lms+ZXI3DtQsA03u5vhBXCe/
+MlNsEygfvnicfIBT600KGRqISZWpxmUjWz4kJwbrfFgkxuek2ZgCxM6zHgE0TL2c
+KNoQTTbpfahoBHUY6/BYlAWxYZfVmrPbCXF0kAWH1Bz/BivAUbYmyiiLwgg6k2L4
+abQ7w22bD4Ad+MNRk3hkg2PH0CHoBc0iPj7iwmavRmzGfdjtU7nMQumiQ5Qx9J5F
++kU1q38yk5WlG0qdJ8BfvwN/yjfDwslvtm5fBVVW9S9AwkESF+4jGzqcOXTVzLFH
+aiSFlfWq5jVADNOPHtPftRt8/z/ffnrT+OGSsEEU9qodjDY9XMXFty+4+AlHwlFY
+3oBBwqUYxqkWOdSO7/OpxhPbHvWK5zcWfN8o/hlEe1iY7nL6QaL14HfCXvrhlIeW
+F2Z1B0XI32pAGTvaTUjoUaMfukFiCkj1YkKeaUmqrDa9b0Eyu2KKlmsBqt4UBTpD
+6UXyAJrccSC3ZfLwfbN0oEMcP14iR99HjV7LkxoUbrQpD68cB5wRdCQ4CSN2Dsr8
+YI8a4tzU/f7LEving8Su26THdLOldpCTnaN4AZfg7Al4uZj/tyqdBQNez7IBgHlr
++V31AgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAgEAXdU/NQs8tIc2BsjClwmdZYXo
+HRV/QyyrtxwZyDhIt8jG/DE/rggGXPLOaQQwbPgax7JCYbeyolCLQtOIP/sWwpje
+0rADXkdvwdUyEmEUl6ARmxJNm9j4DTKttAQCFquww70di9X1C7IHXrb5VR2HrvgI
+JChexYX3Nt2Aj01Y1vc7Wn1EStWJ5CUZg3yHe4x5aZ9t0/8J7fXLzmhyNO96S2dy
+BiPz3S7SNv8kRLqHDsKEZq6gzY54lQaCIpj4gCyd573YBm3YogMak9Su58+/AWE5
+lrwAJLSb6nfN0YZhVsq3kAhhD2yT/x1vH3JG/0LcaGqW/zOa0ZLWU2qPk4y5UIKo
+EdC0/FGvmHBDLmb7YPKsjBnrtZ0pGlyxu8vempDG3qa7elsVBW9VvI3R6fPcNfZe
+WJhNuS8RnnANRQJkavZEpPcM/IwBvje5toOH9uHIw9SzG3i8XHuelQ9g49zbpz0h
+JoGalDcQDk1vriIivNPsEo17T2jXxNiZY+BFF2hGNmxjDjenbdFu1N/TQU5ouUag
+SO/h/AqO6ONCXUaPnqcYXYcaC5kY/4Ea4Vp+DcbzKu25FrQLQDcDc4Iq1RpAdHPS
+WJNnR1/IKkTGBvhPHGmp8ZRohynJXPJ6AbLChhpJrJjb+fLsboLNTjIjoOsesxe9
+jzOfD9FSF9kL1esrz70=
+-----END CERTIFICATE REQUEST-----
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-cert.pem
new file mode 120000
index 00000000000..cf090b32d90
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-cert.pem
@@ -0,0 +1 @@
+DC-plugindc.plugindom.samba.example.com-S02-cert.pem \ No newline at end of file
diff --git a/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-private-key.pem
new file mode 120000
index 00000000000..64ddc9628f1
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/DCs/plugindc.plugindom.samba.example.com/DC-plugindc.plugindom.samba.example.com-private-key.pem
@@ -0,0 +1 @@
+DC-plugindc.plugindom.samba.example.com-S02-private-key.pem \ No newline at end of file
diff --git a/selftest/manage-ca/CA-samba.example.com/NewCerts/00.pem b/selftest/manage-ca/CA-samba.example.com/NewCerts/00.pem
new file mode 100644
index 00000000000..2a1f36f063f
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/NewCerts/00.pem
@@ -0,0 +1,190 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+ Validity
+ Not Before: Mar 18 11:44:51 2016 GMT
+ Not After : Mar 13 11:44:51 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Domain Controllers, CN=localdc.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:e6:5f:4f:b7:ba:64:00:94:b2:0b:a0:29:3b:66:
+ 1f:28:85:cd:fa:bb:d7:de:18:8e:e2:4b:14:ab:33:
+ 17:4c:5f:8b:84:0e:b2:19:cd:32:ae:2a:8e:fc:8c:
+ 4b:51:c0:d9:2e:de:7f:d2:d3:7a:83:9d:95:66:6d:
+ e0:08:1a:25:10:2f:d3:27:bf:c7:ae:3a:f9:33:e4:
+ 65:87:af:a2:80:87:cc:f7:69:a3:4d:8d:65:30:81:
+ b3:20:ca:3f:54:28:b7:d9:1f:fe:90:92:8f:34:0b:
+ 0c:44:eb:48:b1:54:3e:66:29:c3:aa:e8:f4:f7:2d:
+ 6a:0c:cc:c2:31:f5:35:76:48:ba:82:c8:d0:06:42:
+ 2f:cd:4e:3f:20:b5:fc:f6:72:fc:0e:fe:92:a3:97:
+ 16:c7:9b:40:e4:ca:5c:47:39:bd:b1:4c:09:e3:a7:
+ 42:c2:0d:a8:b5:3e:f9:dc:7d:39:05:4d:c8:5f:c8:
+ 69:dc:85:5c:3c:9a:23:07:bc:30:33:38:a6:c4:03:
+ 07:59:e3:97:55:84:61:65:52:80:60:fa:77:b6:76:
+ 5a:31:32:51:a6:22:98:b5:ab:dc:67:51:23:76:08:
+ 09:8e:38:1c:75:0b:9c:59:43:1f:41:04:dd:60:69:
+ d9:fa:31:b8:16:5e:b8:f8:27:82:16:8e:c6:ce:d9:
+ 56:01:68:e4:5f:f8:2d:0f:31:85:27:37:92:fa:4d:
+ 0b:b3:f3:6a:f4:be:30:15:0d:8e:00:b5:87:f8:67:
+ 5c:ae:6a:25:59:23:8c:bf:a5:02:eb:b7:cc:0c:fc:
+ bc:3b:bd:80:08:fc:a3:86:5f:2d:ec:79:05:8e:e4:
+ d2:d2:c4:a6:ab:84:e3:da:aa:58:c3:db:8b:28:4b:
+ 15:49:79:7e:58:19:8b:7d:3e:87:9e:79:28:15:e1:
+ 8a:ad:75:10:0b:71:1e:8f:e8:1f:cd:d4:9b:11:e1:
+ 47:26:1a:f8:d4:a3:0b:7d:08:de:a6:f1:7a:93:26:
+ fb:bd:78:a3:60:8a:8b:29:fe:f8:9f:7b:5e:d7:64:
+ 03:e1:58:23:ac:23:35:3f:4f:b9:f7:3d:d6:d7:64:
+ 1f:0b:6b:11:9b:10:1f:2b:49:b2:f9:63:e8:cf:bf:
+ ac:da:9e:b7:f7:12:91:e4:01:77:9a:7f:31:c8:b6:
+ af:7d:5e:4e:55:ee:3d:2a:f9:0d:56:11:49:e3:f6:
+ 09:8c:2f:d0:06:eb:f4:f7:65:9f:db:85:0a:57:7e:
+ 9a:b8:1a:60:11:18:d1:3d:1c:c0:53:65:9b:e8:00:
+ 93:e4:91:61:b6:e8:7b:63:d3:d8:ec:70:8d:92:54:
+ 12:8b:56:1f:cf:83:34:d5:44:86:cd:b6:0b:fc:95:
+ 8f:f9:11
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+ Netscape Cert Type:
+ SSL Server
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Key Encipherment
+ Netscape Comment:
+ Domain Controller Certificate localdc.samba.example.com
+ X509v3 Subject Key Identifier:
+ CD:25:BC:9E:49:98:02:88:4F:A7:5C:4F:2D:68:B9:E3:61:9F:AE:2E
+ X509v3 Authority Key Identifier:
+ keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42
+
+ X509v3 Subject Alternative Name:
+ DNS:localdc.samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com@samba.example.com
+ Netscape CA Revocation Url:
+ http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+ X509v3 Extended Key Usage:
+ TLS Web Client Authentication, TLS Web Server Authentication, msKDC
+ Signature Algorithm: sha256WithRSAEncryption
+ 15:c0:31:31:7f:65:7c:7c:a4:db:1c:23:1b:81:bf:e8:c8:ad:
+ c0:2e:ce:c6:8e:3a:a2:d7:8f:ad:19:9a:e9:ea:72:bd:25:bc:
+ 26:3c:57:a7:53:4e:c5:24:a2:3c:70:59:48:9d:f5:df:2c:bd:
+ b5:b4:71:fe:a6:58:15:eb:31:86:83:c9:7a:39:47:80:f1:9d:
+ 31:ed:e1:5a:26:3f:9c:be:06:45:93:96:d9:3b:7d:d1:9c:b2:
+ ea:7b:a3:71:f0:9d:c7:a1:29:ba:38:eb:e4:be:bc:e9:9d:e8:
+ e1:be:eb:57:5a:1e:d1:09:58:dc:77:04:85:48:ba:94:19:73:
+ 8f:3a:31:6d:3c:ec:37:a6:d7:94:25:e3:98:e9:3c:f6:85:c6:
+ 6a:8e:d5:cd:32:05:1f:76:b7:b0:5a:c5:45:c0:81:20:16:4f:
+ e0:bb:e7:42:06:5c:6c:ff:e6:8a:73:7b:8c:1c:98:fe:2d:47:
+ 8a:e0:06:38:53:77:5b:6b:13:82:f4:a6:0b:c3:b2:88:2a:05:
+ 96:c8:04:66:cb:59:19:08:d4:9b:0f:1f:e3:3a:48:65:32:07:
+ 69:39:34:d4:a3:2e:d5:19:09:c7:07:d9:71:4d:62:81:fc:5a:
+ be:f1:da:65:3a:24:1e:2c:40:c8:78:4a:bb:0a:4f:a4:3d:ab:
+ 3c:b9:22:fb:0b:5c:9f:09:95:76:6f:6b:53:3d:1f:ee:fd:3f:
+ cd:be:7a:61:3e:08:3b:99:69:68:91:a9:9f:b8:4f:b8:c9:1f:
+ d4:ed:86:61:aa:6f:4f:a8:6a:4d:b6:79:e9:af:37:d2:83:9b:
+ f7:61:6a:65:f6:8c:f7:f9:3b:23:b6:cc:78:bf:16:ee:a0:50:
+ 1f:7e:38:7b:72:1b:62:ef:17:60:db:6f:c9:29:c1:c2:53:f7:
+ e8:27:de:3e:22:da:f0:5f:ba:55:9f:57:6f:b9:8f:c4:7a:c5:
+ 72:9a:a3:95:cc:ac:fd:f3:a6:a9:da:d6:57:d3:28:7f:72:60:
+ a8:5b:2f:c3:b1:07:c4:c7:af:d9:3c:a9:e9:78:e1:5a:0f:da:
+ c9:d0:e6:5d:9a:bd:61:ef:1d:25:7f:54:08:aa:f2:6c:11:1e:
+ a4:46:8e:9e:e2:79:c8:c2:dd:09:1b:62:27:e6:70:7a:e4:f3:
+ 66:db:57:30:ce:3f:27:f5:c6:c8:f2:3f:a1:bc:dd:ec:fe:3a:
+ c4:b9:ad:21:73:d8:83:a5:9f:02:ba:d0:52:8a:f2:d5:25:63:
+ 15:82:38:25:e2:74:ce:a6:a5:32:9a:6c:52:33:ba:45:ba:01:
+ 16:14:5f:ce:66:89:9e:03:ed:8a:95:80:c4:cf:20:24:d4:c5:
+ 5b:e5:c3:51:62:57:1e:45:be:0a:47:24:b7:cb:a4:dd:6e:54:
+ 2c:f4:25:80:a3:85:a9:74:0c:c0:65:c9:f8:2f:9a:22:bc:85:
+ c9:63:8a:08:f3:c9:1c:77:9b:a8:42:5a:45:dd:be:21:be:9d:
+ e7:15:9b:67:19:6c:d3:da:9b:67:a8:1d:22:35:d4:16:89:ad:
+ 4c:c3:17:bb:9e:f5:e5:3b:a2:a6:81:34:e0:4c:36:be:bb:e5:
+ a3:60:7d:28:30:82:db:99:ef:c6:19:43:d1:73:24:f0:8e:d1:
+ 6c:3b:cc:f8:cb:1a:14:79:67:07:ea:b5:47:08:bf:11:33:29:
+ 01:2e:fd:44:14:33:f6:36:65:8b:a8:f8:e6:0b:84:6d:a1:91:
+ 08:56:c1:5d:ca:12:b6:00:ba:9c:7e:7e:9b:26:3f:d3:dd:e1:
+ 2f:ae:f5:76:45:ed:a2:9b:b4:a1:a9:d6:b6:f5:7e:68:80:17:
+ 81:fb:ef:24:dc:84:de:38:20:45:34:6c:72:e5:d6:08:61:e7:
+ dd:45:43:d2:06:2b:ae:d9:73:a1:fb:bb:04:3c:61:45:d3:9e:
+ fc:45:c0:e3:db:02:ae:45:e3:de:d1:34:00:b0:1b:0f:ce:f8:
+ 33:0f:87:9c:9b:5d:49:11:7a:30:15:e3:9f:76:02:82:18:c2:
+ a6:dd:25:a6:e0:84:1f:1d:0d:db:81:7c:df:a1:65:9b:5b:08:
+ e0:4e:6d:4c:76:8a:0b:09:14:7c:e1:23:ad:18:4c:02:6b:e3:
+ f4:e0:22:26:e1:30:7e:a5:59:22:5b:a5:73:5a:23:24:1f:1a:
+ 7b:e5:46:f7:0c:14:00:53:72:33:4d:c4:c4:59:3e:04:17:33:
+ 34:04:67:1e:cd:a0:e5:9f:85:87:77:f6:dd:03:f0:74:cf:56:
+ e9:99:a8:95:3a:52:db:d1:61:72:91:60:9f:80:bf:22:26:da:
+ d7:09:4e:df:81:30:dc:9b:b4:c1:c7:cb:97:93:bc:b7:93:a3:
+ db:88:cc:5e:9f:39:94:57:a5:57:d6:cd:1b:12:a4:86:62:4f:
+ b2:08:22:4e:d9:07:8e:27:06:82:d9:f1:ec:70:30:82:56:0c:
+ f7:d9:56:bf:f1:7f:fd:65:90:8d:5e:d5:13:b3:31:89:5d:e8:
+ df:35:2f:77:6b:b7:c7:e8:7d:89:f8:cf:9e:a5:1c:60:be:7c:
+ 6c:b7:0f:fa:8e:62:8e:b0:72:10:8a:04:6a:50:83:3a:38:dc:
+ 13:8b:89:8f:6c:0f:fc:3e:c7:36:15:37:78:5f:24:87:8a:70:
+ cc:3e:5a:fc:88:78:19:70:89:65:a0:c7:47:67:f2:bc:1e:f5:
+ 04:e7:94:ba:74:ea:2a:a7:c1:26:b1:2e:ac:64:0b:fa
+-----BEGIN CERTIFICATE-----
+MIIJ6zCCBdOgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTgxMTQ0NTFaFw0zNjAzMTMxMTQ0NTFaMIG1MQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEbMBkGA1UE
+CwwSRG9tYWluIENvbnRyb2xsZXJzMSIwIAYDVQQDDBlsb2NhbGRjLnNhbWJhLmV4
+YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkBFiZjYS1zYW1iYS5leGFtcGxlLmNvbUBz
+YW1iYS5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+AOZfT7e6ZACUsgugKTtmHyiFzfq7194YjuJLFKszF0xfi4QOshnNMq4qjvyMS1HA
+2S7ef9LTeoOdlWZt4AgaJRAv0ye/x646+TPkZYevooCHzPdpo02NZTCBsyDKP1Qo
+t9kf/pCSjzQLDETrSLFUPmYpw6ro9PctagzMwjH1NXZIuoLI0AZCL81OPyC1/PZy
+/A7+kqOXFsebQOTKXEc5vbFMCeOnQsINqLU++dx9OQVNyF/IadyFXDyaIwe8MDM4
+psQDB1njl1WEYWVSgGD6d7Z2WjEyUaYimLWr3GdRI3YICY44HHULnFlDH0EE3WBp
+2foxuBZeuPgnghaOxs7ZVgFo5F/4LQ8xhSc3kvpNC7PzavS+MBUNjgC1h/hnXK5q
+JVkjjL+lAuu3zAz8vDu9gAj8o4ZfLex5BY7k0tLEpquE49qqWMPbiyhLFUl5flgZ
+i30+h555KBXhiq11EAtxHo/oH83UmxHhRyYa+NSjC30I3qbxepMm+714o2CKiyn+
++J97XtdkA+FYI6wjNT9Pufc91tdkHwtrEZsQHytJsvlj6M+/rNqet/cSkeQBd5p/
+Mci2r31eTlXuPSr5DVYRSeP2CYwv0Abr9Pdln9uFCld+mrgaYBEY0T0cwFNlm+gA
+k+SRYbboe2PT2OxwjZJUEotWH8+DNNVEhs22C/yVj/kRAgMBAAGjggHxMIIB7TAJ
+BgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly93d3cuc2FtYmEuZXhh
+bXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMBEGCWCG
+SAGG+EIBAQQEAwIGQDALBgNVHQ8EBAMCBeAwRgYJYIZIAYb4QgENBDkWN0RvbWFp
+biBDb250cm9sbGVyIENlcnRpZmljYXRlIGxvY2FsZGMuc2FtYmEuZXhhbXBsZS5j
+b20wHQYDVR0OBBYEFM0lvJ5JmAKIT6dcTy1oueNhn64uMB8GA1UdIwQYMBaAFEaH
+hsLnGc8WTAxiy3N//Y8Z5LVCMD0GA1UdEQQ2MDSCGWxvY2FsZGMuc2FtYmEuZXhh
+bXBsZS5jb22gFwYJKwYBBAGCNxkBoAoECAEjRWeJq83vMDEGA1UdEgQqMCiBJmNh
+LXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0GCWCGSAGG+EIB
+BARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMvQ0Etc2FtYmEu
+ZXhhbXBsZS5jb20tY3JsLmNybDAmBgNVHSUEHzAdBggrBgEFBQcDAgYIKwYBBQUH
+AwEGBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggQBABXAMTF/ZXx8pNscIxuBv+jI
+rcAuzsaOOqLXj60Zmunqcr0lvCY8V6dTTsUkojxwWUid9d8svbW0cf6mWBXrMYaD
+yXo5R4DxnTHt4VomP5y+BkWTltk7fdGcsup7o3HwncehKbo46+S+vOmd6OG+61da
+HtEJWNx3BIVIupQZc486MW087Dem15Ql45jpPPaFxmqO1c0yBR92t7BaxUXAgSAW
+T+C750IGXGz/5opze4wcmP4tR4rgBjhTd1trE4L0pgvDsogqBZbIBGbLWRkI1JsP
+H+M6SGUyB2k5NNSjLtUZCccH2XFNYoH8Wr7x2mU6JB4sQMh4SrsKT6Q9qzy5IvsL
+XJ8JlXZva1M9H+79P82+emE+CDuZaWiRqZ+4T7jJH9TthmGqb0+oak22eemvN9KD
+m/dhamX2jPf5OyO2zHi/Fu6gUB9+OHtyG2LvF2Dbb8kpwcJT9+gn3j4i2vBfulWf
+V2+5j8R6xXKao5XMrP3zpqna1lfTKH9yYKhbL8OxB8THr9k8qel44VoP2snQ5l2a
+vWHvHSV/VAiq8mwRHqRGjp7iecjC3QkbYifmcHrk82bbVzDOPyf1xsjyP6G83ez+
+OsS5rSFz2IOlnwK60FKK8tUlYxWCOCXidM6mpTKabFIzukW6ARYUX85miZ4D7YqV
+gMTPICTUxVvlw1FiVx5FvgpHJLfLpN1uVCz0JYCjhal0DMBlyfgvmiK8hcljigjz
+yRx3m6hCWkXdviG+necVm2cZbNPam2eoHSI11BaJrUzDF7ue9eU7oqaBNOBMNr67
+5aNgfSgwgtuZ78YZQ9FzJPCO0Ww7zPjLGhR5ZwfqtUcIvxEzKQEu/UQUM/Y2ZYuo
++OYLhG2hkQhWwV3KErYAupx+fpsmP9Pd4S+u9XZF7aKbtKGp1rb1fmiAF4H77yTc
+hN44IEU0bHLl1ghh591FQ9IGK67Zc6H7uwQ8YUXTnvxFwOPbAq5F497RNACwGw/O
++DMPh5ybXUkRejAV4592AoIYwqbdJabghB8dDduBfN+hZZtbCOBObUx2igsJFHzh
+I60YTAJr4/TgIibhMH6lWSJbpXNaIyQfGnvlRvcMFABTcjNNxMRZPgQXMzQEZx7N
+oOWfhYd39t0D8HTPVumZqJU6UtvRYXKRYJ+AvyIm2tcJTt+BMNybtMHHy5eTvLeT
+o9uIzF6fOZRXpVfWzRsSpIZiT7IIIk7ZB44nBoLZ8exwMIJWDPfZVr/xf/1lkI1e
+1ROzMYld6N81L3drt8fofYn4z56lHGC+fGy3D/qOYo6wchCKBGpQgzo43BOLiY9s
+D/w+xzYVN3hfJIeKcMw+WvyIeBlwiWWgx0dn8rwe9QTnlLp06iqnwSaxLqxkC/o=
+-----END CERTIFICATE-----
diff --git a/selftest/manage-ca/CA-samba.example.com/NewCerts/01.pem b/selftest/manage-ca/CA-samba.example.com/NewCerts/01.pem
new file mode 100644
index 00000000000..deb2b73f312
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/NewCerts/01.pem
@@ -0,0 +1,169 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+ Validity
+ Not Before: Mar 18 11:45:11 2016 GMT
+ Not After : Mar 13 11:45:11 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Users, CN=administrator@samba.example.com/emailAddress=administrator@samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c9:07:44:3a:5f:f6:34:5f:27:8a:7a:6e:2f:fb:
+ 45:1f:c3:3d:dd:2c:43:65:f1:7a:29:3f:42:26:bd:
+ ff:4f:5d:91:c0:bb:75:e3:81:14:7d:59:72:78:96:
+ 1a:5e:8d:95:93:f4:5d:92:79:0e:24:77:4f:8b:08:
+ 4e:72:b1:99:88:63:06:74:b2:dc:f7:82:62:e9:dd:
+ 6f:e5:a7:b4:c9:44:0c:e4:43:41:f8:57:a9:20:b1:
+ 70:c1:76:a1:48:5b:e9:54:b6:4f:22:50:93:90:f0:
+ 62:32:50:9a:6e:22:6b:37:a0:f7:1f:fc:b1:5f:ae:
+ e2:0b:88:6d:ea:29:b6:01:27:b2:84:ef:10:4d:6c:
+ 0a:df:ea:a9:8a:82:98:60:a7:52:73:a4:f7:7c:b2:
+ 4a:b9:f0:9b:c4:f8:19:5a:c0:84:54:52:35:c8:92:
+ 4f:16:af:d6:36:a6:78:57:55:e5:5e:6b:62:00:fa:
+ 48:c2:7a:e7:17:38:b5:23:d5:a8:fb:7d:df:42:5c:
+ 03:f4:7c:ef:ff:f1:a0:e6:d8:27:93:06:b3:a3:21:
+ 68:0e:c4:60:20:02:46:2f:2b:d8:88:e4:2b:01:c2:
+ 31:5a:55:28:be:55:03:f2:06:2b:e4:ec:48:60:e4:
+ b6:db:a1:f0:c5:24:ba:e1:a8:e2:6a:fb:0b:40:6c:
+ 3d:f5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+ Netscape Cert Type:
+ SSL Client, S/MIME
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Key Encipherment
+ Netscape Comment:
+ Smart Card Login Certificate for administrator@samba.example.com
+ X509v3 Subject Key Identifier:
+ 70:86:EC:68:B4:51:8A:1C:12:65:A0:2A:B3:43:33:12:65:83:8D:40
+ X509v3 Authority Key Identifier:
+ keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42
+
+ X509v3 Subject Alternative Name:
+ email:administrator@samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com@samba.example.com
+ Netscape CA Revocation Url:
+ http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+ X509v3 Extended Key Usage:
+ TLS Web Client Authentication, scardLogin
+ Signature Algorithm: sha256WithRSAEncryption
+ 5d:b1:10:f8:36:dd:a9:fd:8d:be:31:53:1d:cf:b5:ea:33:1a:
+ 85:0f:13:8d:cc:67:91:41:97:e4:e9:67:6a:0c:ce:a4:9a:06:
+ b3:53:bf:e6:6d:f1:d1:32:7d:54:5d:6a:a8:94:fe:d4:f6:62:
+ 85:0f:e0:73:f8:ce:51:32:18:65:50:34:f9:f2:66:f8:ec:fd:
+ 94:c2:1d:28:6f:ce:3c:b3:0a:0a:cc:8b:fb:2c:e8:44:d2:d8:
+ 64:d7:19:1c:a4:25:5f:75:63:bc:44:56:64:cb:ca:8c:43:75:
+ 1e:95:36:98:a1:c6:49:e6:14:60:ad:87:91:af:d8:3c:d2:63:
+ 52:82:02:0a:42:c0:e3:7b:50:51:37:d5:c0:a5:0c:09:ac:2d:
+ a0:b3:29:e4:9e:bf:d3:df:01:82:00:a5:ad:fb:35:e8:f6:1c:
+ d7:cb:d1:3c:54:1f:d2:73:38:ce:a6:0a:e2:77:0a:fc:e5:ff:
+ 7e:68:a6:c7:57:fd:c7:cf:95:48:9f:97:6f:fe:2e:9f:e3:d6:
+ b0:a5:b5:33:9f:12:c1:e6:12:15:77:33:8f:1e:35:b5:88:f8:
+ 6b:47:88:e4:cb:49:f7:11:ba:19:39:55:5e:4a:5a:65:76:7e:
+ cc:3a:a7:fa:91:9a:ef:b5:c1:bf:f0:e7:a2:c6:9f:08:17:fc:
+ 4c:a4:ef:0b:d8:c7:a4:f9:74:36:b3:67:90:5e:84:26:83:bd:
+ 36:89:0d:c6:8c:1d:03:ce:8f:80:c9:0c:c6:c0:1e:eb:42:e7:
+ 97:7f:21:ac:b1:64:06:f6:1d:6d:0c:87:ff:c9:30:23:d3:21:
+ 1f:53:05:69:21:d5:26:ca:7f:ce:3a:4e:8d:d1:40:16:7e:a2:
+ c0:0f:95:0c:67:90:47:d2:e2:cf:87:ef:dc:35:18:2a:a2:21:
+ cd:67:b0:b2:14:9f:75:94:93:ba:8c:4d:45:71:cb:e9:df:cd:
+ f5:e3:f0:ff:c3:38:77:c2:41:55:d6:60:96:d8:bd:5f:09:22:
+ 97:44:8d:4d:b1:dd:68:39:04:1b:7a:57:3b:ca:56:27:87:31:
+ 55:84:6c:f0:65:af:ec:0b:52:87:28:0b:2d:52:c0:ce:a3:7d:
+ 7b:47:07:df:8a:65:e9:6f:da:e7:b6:94:06:69:b8:55:3d:11:
+ 01:c6:bf:0b:61:1b:cc:30:47:ab:cf:fb:72:62:f3:eb:66:11:
+ cd:1c:ab:4e:29:bf:b7:78:d6:09:ec:d7:67:5b:17:b9:34:cc:
+ af:5e:d9:02:0b:33:fc:a1:f2:64:33:c4:af:11:5b:08:f7:af:
+ ba:0d:68:d7:cf:d2:40:2f:56:20:34:da:82:18:7c:0e:71:61:
+ a6:58:60:00:30:a6:c7:25:3a:90:70:a0:14:e6:da:d8:12:e9:
+ b3:6a:c4:96:85:41:80:a6:71:17:b5:cf:4f:a2:2d:51:93:fd:
+ 26:eb:44:3c:2a:84:6a:da:18:10:d6:48:e3:8e:0f:c9:69:05:
+ 96:8c:96:f9:74:06:ab:11:d2:e4:e5:d7:22:db:13:93:d6:f9:
+ 24:84:56:7c:6a:43:a9:b8:30:33:2c:a4:42:9f:ec:f6:56:2d:
+ 46:cf:ec:26:49:5e:da:53:21:6b:8c:05:0d:b7:12:26:29:43:
+ 32:b2:6c:ed:07:47:75:2b:0b:7e:5d:28:1b:5b:7b:b5:63:13:
+ 55:4d:f7:a3:f6:fd:2d:f5:6d:43:83:40:46:b3:0d:d6:28:99:
+ d4:fb:89:fb:41:c6:15:35:a5:ee:1a:08:33:b3:0b:75:0a:d0:
+ fc:31:ec:77:80:e2:f0:ab:20:cc:43:24:67:42:a5:d7:e6:b0:
+ b9:84:fd:43:a0:5e:d9:78:10:97:d3:d1:b7:d9:33:70:0f:4d:
+ f0:a1:ac:22:d7:36:53:68:6d:39:e0:14:dc:d7:ea:1e:c2:92:
+ 1b:f8:2a:99:97:14:76:2c:89:3f:b7:89:c7:69:6e:5b:dd:8e:
+ 47:7a:f0:0e:a4:d0:18:c6:c4:34:f0:b8:84:3a:6e:ee:1e:7b:
+ 84:58:d2:10:a6:a2:0c:14:a8:55:e9:c5:7e:ab:97:e4:9d:b5:
+ f0:9f:2e:36:ac:2f:73:30:c8:b1:fc:b4:ce:b4:39:bd:59:75:
+ b8:24:5a:b1:67:de:34:3f:4e:17:5d:d3:bc:bb:6a:6a:b7:3e:
+ 0b:e8:4d:3b:08:d6:de:a7:9a:d7:8d:60:56:bb:3e:6c:d0:a7:
+ f8:45:a2:52:a3:b5:1e:ef:56:df:14:62:52:ed:36:ab:cc:7a:
+ a1:96:14:9a:e9:de:4a:28:68:bd:21:2d:60:d5:06:8a:e9:5e:
+ b6:ce:e1:b4:ed:56:9f:99:87:fe:20:bb:d5:8d:0d:72:1d:7e:
+ 88:27:9c:66:d5:26:aa:32:0a:ad:64:de:b8:13:2d:51:cc:8b:
+ e2:f4:c1:63:a6:64:e8:03:08:42:38:bf:f4:fe:b3:25:03:1b:
+ 14:b9:68:81:14:b9:5d:b9:6a:eb:f0:a9:24:41:8e:49:03:be:
+ 0b:55:cf:ac:77:68:ed:54:ae:55:40:dd:31:c4:3a:e2:d7:86:
+ d5:d5:e4:5e:5b:ce:9e:da:a1:90:58:e1:b3:7c:a6:87:15:bd:
+ 3a:67:b9:ab:29:de:4f:af:08:98:89:45:62:8f:db:5b:2e:2b:
+ e8:97:35:a2:fc:4f:cf:63:7d:56:a0:51:dd:3f:b2:90:a6:9b:
+ a0:9b:9e:93:8d:9d:92:b2:ed:36:d5:e1:f1:e3:97:dc
+-----BEGIN CERTIFICATE-----
+MIII/TCCBOWgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTgxMTQ1MTFaFw0zNjAzMTMxMTQ1MTFaMIGnMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEOMAwGA1UE
+CwwFVXNlcnMxKDAmBgNVBAMMH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5j
+b20xLjAsBgkqhkiG9w0BCQEWH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5j
+b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJB0Q6X/Y0XyeKem4v
++0Ufwz3dLENl8XopP0Imvf9PXZHAu3XjgRR9WXJ4lhpejZWT9F2SeQ4kd0+LCE5y
+sZmIYwZ0stz3gmLp3W/lp7TJRAzkQ0H4V6kgsXDBdqFIW+lUtk8iUJOQ8GIyUJpu
+Ims3oPcf/LFfruILiG3qKbYBJ7KE7xBNbArf6qmKgphgp1JzpPd8skq58JvE+Bla
+wIRUUjXIkk8Wr9Y2pnhXVeVea2IA+kjCeucXOLUj1aj7fd9CXAP0fO//8aDm2CeT
+BrOjIWgOxGAgAkYvK9iI5CsBwjFaVSi+VQPyBivk7Ehg5LbbofDFJLrhqOJq+wtA
+bD31AgMBAAGjggIRMIICDTAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0
+dHA6Ly93d3cuc2FtYmEuZXhhbXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxl
+LmNvbS1jcmwuY3JsMBEGCWCGSAGG+EIBAQQEAwIFoDALBgNVHQ8EBAMCBeAwTwYJ
+YIZIAYb4QgENBEIWQFNtYXJ0IENhcmQgTG9naW4gQ2VydGlmaWNhdGUgZm9yIGFk
+bWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5jb20wHQYDVR0OBBYEFHCG7Gi0UYoc
+EmWgKrNDMxJlg41AMB8GA1UdIwQYMBaAFEaHhsLnGc8WTAxiy3N//Y8Z5LVCMFsG
+A1UdEQRUMFKBH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5jb22gLwYKKwYB
+BAGCNxQCA6AhDB9hZG1pbmlzdHJhdG9yQHNhbWJhLmV4YW1wbGUuY29tMDEGA1Ud
+EgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0G
+CWCGSAGG+EIBBARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMv
+Q0Etc2FtYmEuZXhhbXBsZS5jb20tY3JsLmNybDAfBgNVHSUEGDAWBggrBgEFBQcD
+AgYKKwYBBAGCNxQCAjANBgkqhkiG9w0BAQsFAAOCBAEAXbEQ+Dbdqf2NvjFTHc+1
+6jMahQ8TjcxnkUGX5OlnagzOpJoGs1O/5m3x0TJ9VF1qqJT+1PZihQ/gc/jOUTIY
+ZVA0+fJm+Oz9lMIdKG/OPLMKCsyL+yzoRNLYZNcZHKQlX3VjvERWZMvKjEN1HpU2
+mKHGSeYUYK2Hka/YPNJjUoICCkLA43tQUTfVwKUMCawtoLMp5J6/098BggClrfs1
+6PYc18vRPFQf0nM4zqYK4ncK/OX/fmimx1f9x8+VSJ+Xb/4un+PWsKW1M58SweYS
+FXczjx41tYj4a0eI5MtJ9xG6GTlVXkpaZXZ+zDqn+pGa77XBv/DnosafCBf8TKTv
+C9jHpPl0NrNnkF6EJoO9NokNxowdA86PgMkMxsAe60Lnl38hrLFkBvYdbQyH/8kw
+I9MhH1MFaSHVJsp/zjpOjdFAFn6iwA+VDGeQR9Liz4fv3DUYKqIhzWewshSfdZST
+uoxNRXHL6d/N9ePw/8M4d8JBVdZglti9Xwkil0SNTbHdaDkEG3pXO8pWJ4cxVYRs
+8GWv7AtShygLLVLAzqN9e0cH34pl6W/a57aUBmm4VT0RAca/C2EbzDBHq8/7cmLz
+62YRzRyrTim/t3jWCezXZ1sXuTTMr17ZAgsz/KHyZDPErxFbCPevug1o18/SQC9W
+IDTaghh8DnFhplhgADCmxyU6kHCgFOba2BLps2rEloVBgKZxF7XPT6ItUZP9JutE
+PCqEatoYENZI444PyWkFloyW+XQGqxHS5OXXItsTk9b5JIRWfGpDqbgwMyykQp/s
+9lYtRs/sJkle2lMha4wFDbcSJilDMrJs7QdHdSsLfl0oG1t7tWMTVU33o/b9LfVt
+Q4NARrMN1iiZ1PuJ+0HGFTWl7hoIM7MLdQrQ/DHsd4Di8KsgzEMkZ0Kl1+awuYT9
+Q6Be2XgQl9PRt9kzcA9N8KGsItc2U2htOeAU3NfqHsKSG/gqmZcUdiyJP7eJx2lu
+W92OR3rwDqTQGMbENPC4hDpu7h57hFjSEKaiDBSoVenFfquX5J218J8uNqwvczDI
+sfy0zrQ5vVl1uCRasWfeND9OF13TvLtqarc+C+hNOwjW3qea141gVrs+bNCn+EWi
+UqO1Hu9W3xRiUu02q8x6oZYUmuneSihovSEtYNUGiulets7htO1Wn5mH/iC71Y0N
+ch1+iCecZtUmqjIKrWTeuBMtUcyL4vTBY6Zk6AMIQji/9P6zJQMbFLlogRS5Xblq
+6/CpJEGOSQO+C1XPrHdo7VSuVUDdMcQ64teG1dXkXlvOntqhkFjhs3ymhxW9Ome5
+qyneT68ImIlFYo/bWy4r6Jc1ovxPz2N9VqBR3T+ykKaboJuek42dkrLtNtXh8eOX
+3A==
+-----END CERTIFICATE-----
diff --git a/selftest/manage-ca/CA-samba.example.com/NewCerts/02.pem b/selftest/manage-ca/CA-samba.example.com/NewCerts/02.pem
new file mode 100644
index 00000000000..4cc42aafc9c
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/NewCerts/02.pem
@@ -0,0 +1,191 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+ Validity
+ Not Before: Mar 18 11:45:30 2016 GMT
+ Not After : Mar 13 11:45:30 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Domain Controllers, CN=plugindc.plugindom.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:aa:a3:74:2b:4b:6d:29:43:67:03:dc:c0:be:ce:
+ a6:e3:43:99:e5:87:34:34:42:70:4b:bb:50:87:6d:
+ e8:65:2b:5e:1a:b3:68:0d:9f:27:eb:dc:b8:84:bb:
+ 3d:f4:40:28:c0:c7:aa:e5:8d:a1:d5:7f:c7:6b:36:
+ 96:6b:3e:65:72:37:0e:d4:2c:03:4d:ee:e6:f8:41:
+ 5c:27:bf:32:53:6c:13:28:1f:be:78:9c:7c:80:53:
+ eb:4d:0a:19:1a:88:49:95:a9:c6:65:23:5b:3e:24:
+ 27:06:eb:7c:58:24:c6:e7:a4:d9:98:02:c4:ce:b3:
+ 1e:01:34:4c:bd:9c:28:da:10:4d:36:e9:7d:a8:68:
+ 04:75:18:eb:f0:58:94:05:b1:61:97:d5:9a:b3:db:
+ 09:71:74:90:05:87:d4:1c:ff:06:2b:c0:51:b6:26:
+ ca:28:8b:c2:08:3a:93:62:f8:69:b4:3b:c3:6d:9b:
+ 0f:80:1d:f8:c3:51:93:78:64:83:63:c7:d0:21:e8:
+ 05:cd:22:3e:3e:e2:c2:66:af:46:6c:c6:7d:d8:ed:
+ 53:b9:cc:42:e9:a2:43:94:31:f4:9e:45:fa:45:35:
+ ab:7f:32:93:95:a5:1b:4a:9d:27:c0:5f:bf:03:7f:
+ ca:37:c3:c2:c9:6f:b6:6e:5f:05:55:56:f5:2f:40:
+ c2:41:12:17:ee:23:1b:3a:9c:39:74:d5:cc:b1:47:
+ 6a:24:85:95:f5:aa:e6:35:40:0c:d3:8f:1e:d3:df:
+ b5:1b:7c:ff:3f:df:7e:7a:d3:f8:e1:92:b0:41:14:
+ f6:aa:1d:8c:36:3d:5c:c5:c5:b7:2f:b8:f8:09:47:
+ c2:51:58:de:80:41:c2:a5:18:c6:a9:16:39:d4:8e:
+ ef:f3:a9:c6:13:db:1e:f5:8a:e7:37:16:7c:df:28:
+ fe:19:44:7b:58:98:ee:72:fa:41:a2:f5:e0:77:c2:
+ 5e:fa:e1:94:87:96:17:66:75:07:45:c8:df:6a:40:
+ 19:3b:da:4d:48:e8:51:a3:1f:ba:41:62:0a:48:f5:
+ 62:42:9e:69:49:aa:ac:36:bd:6f:41:32:bb:62:8a:
+ 96:6b:01:aa:de:14:05:3a:43:e9:45:f2:00:9a:dc:
+ 71:20:b7:65:f2:f0:7d:b3:74:a0:43:1c:3f:5e:22:
+ 47:df:47:8d:5e:cb:93:1a:14:6e:b4:29:0f:af:1c:
+ 07:9c:11:74:24:38:09:23:76:0e:ca:fc:60:8f:1a:
+ e2:dc:d4:fd:fe:cb:12:f8:a7:83:c4:ae:db:a4:c7:
+ 74:b3:a5:76:90:93:9d:a3:78:01:97:e0:ec:09:78:
+ b9:98:ff:b7:2a:9d:05:03:5e:cf:b2:01:80:79:6b:
+ f9:5d:f5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+ Netscape Cert Type:
+ SSL Server
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Key Encipherment
+ Netscape Comment:
+ Domain Controller Certificate plugindc.plugindom.samba.example.com
+ X509v3 Subject Key Identifier:
+ DB:4F:D4:70:C3:38:E6:26:37:6F:1B:50:5E:7D:E5:80:7D:B4:08:0D
+ X509v3 Authority Key Identifier:
+ keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42
+
+ X509v3 Subject Alternative Name:
+ DNS:plugindc.plugindom.samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com@samba.example.com
+ Netscape CA Revocation Url:
+ http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+ X509v3 Extended Key Usage:
+ TLS Web Client Authentication, TLS Web Server Authentication, msKDC
+ Signature Algorithm: sha256WithRSAEncryption
+ ab:ed:44:9c:0d:f9:df:d6:8d:f2:98:05:cb:97:0c:14:9d:0c:
+ b3:2b:49:6c:4f:d6:8f:81:dd:c7:d9:67:be:ad:5b:f6:08:34:
+ 44:09:88:3a:9d:e9:fe:0b:91:89:f8:32:92:43:43:af:cf:04:
+ 5c:35:a4:d2:04:77:04:bf:37:45:57:2b:70:94:d0:7a:5f:b9:
+ d6:9c:47:ac:46:e4:4c:c2:87:5d:78:b7:3c:be:80:42:dc:3c:
+ 36:3b:c0:57:fb:ec:95:3a:bb:58:7e:09:ff:57:4e:4f:59:73:
+ 2a:65:0e:6e:a8:b3:8e:22:6b:40:0c:b5:5b:96:f3:a1:35:92:
+ 17:12:24:f3:43:fe:54:1d:ac:f9:f1:72:cb:97:b8:43:2f:e1:
+ ac:9c:a6:e7:78:98:38:ad:83:eb:c9:77:0b:ea:5a:21:6a:76:
+ f7:b2:4c:d7:7b:d4:57:eb:4c:a4:6e:be:eb:be:60:99:ae:ce:
+ 13:1c:6a:9f:58:e5:64:a2:b6:4e:2a:2e:62:99:d8:fa:af:11:
+ 5c:7e:51:d3:cf:7e:84:1c:f4:8b:a5:df:c8:b2:39:4c:c3:40:
+ 48:2e:b6:9d:3d:bf:b1:7b:58:39:f0:38:60:72:42:f4:8c:2a:
+ b3:66:c1:e9:12:bc:2a:51:75:55:1e:56:2a:bc:6e:40:1c:2b:
+ 16:25:90:97:18:4e:b4:63:dc:ff:7a:31:5e:b2:38:c4:17:65:
+ 3d:1a:31:47:04:75:3a:b7:83:c3:59:09:d5:99:56:45:4d:a0:
+ c8:6f:3e:87:61:17:4f:2e:7b:5c:34:76:45:e1:b5:bf:c4:fe:
+ 32:31:ff:2c:95:52:9c:12:2a:c3:b8:04:f9:25:a3:11:64:35:
+ c8:5d:92:f9:fc:2c:ba:45:18:d0:dc:95:1c:dd:30:16:3f:56:
+ a4:15:45:85:9b:52:55:3f:f6:a8:dd:54:53:d2:84:1b:d3:1a:
+ 97:61:8a:60:d6:fb:a1:75:f3:15:8f:b7:f3:f4:41:dc:7d:24:
+ 90:9a:62:23:a1:ef:c1:01:69:d4:a1:69:82:58:5f:35:b4:83:
+ b1:7c:cf:dc:f2:ca:23:af:5a:ac:e9:53:53:bd:33:8e:22:2a:
+ 1b:cf:ea:e7:e0:24:b2:f5:f7:ff:f6:99:6c:34:13:e9:f2:50:
+ 70:a1:0f:ec:f9:12:22:99:58:08:5d:f0:49:86:f8:14:3b:1b:
+ e6:49:eb:9b:fb:b1:07:60:e0:05:e6:4f:13:39:d1:ea:07:6b:
+ e8:85:33:eb:4f:b7:d3:7f:bd:9b:f4:a4:40:f4:a4:4a:f6:5f:
+ db:04:f5:f8:04:fa:1a:13:1b:cc:75:6f:c2:df:9d:89:12:5b:
+ f1:fa:cf:df:b6:32:3c:3c:5e:e0:26:9a:c7:e7:87:e7:5b:9a:
+ 76:b3:41:a3:0f:e1:f2:12:69:db:1b:32:57:a4:ad:5b:52:32:
+ 8d:7e:ec:34:c4:ce:d2:ee:6b:96:56:0e:ef:97:9a:26:a3:b5:
+ a0:4c:9a:e0:4f:9b:8d:07:df:92:46:1b:53:53:eb:96:62:74:
+ a8:13:03:e3:1f:13:0e:48:22:ca:ba:94:7f:86:80:c0:76:ab:
+ 08:36:e4:02:f3:ad:31:2f:97:00:06:57:09:12:66:d5:4e:8f:
+ 5b:88:67:7c:e3:0f:df:1c:97:17:85:9f:b9:08:4c:6e:88:e3:
+ e7:b9:53:06:87:98:e8:a3:9f:7c:7d:c9:07:d8:69:74:d1:e7:
+ c1:e6:46:e9:0f:2d:4f:04:6d:41:e8:b8:a7:87:d4:5b:1f:89:
+ e4:b1:c0:ba:78:2e:7d:cf:84:56:25:56:95:f7:93:dd:4a:47:
+ 88:b5:ac:d7:da:a7:b3:c9:8c:c5:41:34:8c:31:24:84:d4:51:
+ bb:46:4a:3c:db:72:e6:1b:c1:c2:15:6e:1a:ac:61:bd:ce:f1:
+ a3:ff:60:d9:a7:90:5a:3a:3e:1c:28:13:ed:cf:ef:ed:f1:fb:
+ 79:3a:57:ac:41:de:e6:17:d0:92:c6:fc:bd:6a:1c:e0:44:c7:
+ d7:ce:80:b4:c2:59:75:a8:bc:8b:32:4e:ea:2a:ff:89:fb:f9:
+ 98:6b:04:1a:fd:9e:2e:b9:bf:60:d5:84:80:f8:5b:03:0d:d9:
+ 1e:30:cf:4e:78:2c:a1:88:6d:ee:80:a2:ec:d9:96:00:c9:82:
+ a2:81:c0:6e:74:4b:69:9f:fd:c2:ed:0a:f7:31:a9:dc:89:f7:
+ c5:83:83:51:bf:f0:f6:8f:22:72:8e:f6:0b:54:d0:b8:7a:39:
+ 62:d1:d8:76:bd:c3:85:be:18:41:e9:42:c2:80:21:1c:86:20:
+ f9:4b:55:5f:e3:e1:6e:ae:ab:0a:4a:0c:05:1f:0d:b5:1f:a0:
+ d6:92:dd:20:71:56:74:e8:13:83:2f:4f:d0:72:98:b8:57:b5:
+ cc:06:63:3b:29:5b:f7:be:fc:e1:0e:24:94:da:1c:d1:ba:9f:
+ 7b:af:0d:d9:80:ed:18:85:74:73:62:2f:cb:37:e2:8c:85:90:
+ e9:86:dc:2b:78:b5:2a:47:fb:a1:41:f1:d4:2f:66:87:17:a5:
+ 24:20:54:61:99:03:72:56:5f:96:92:bf:25:4e:d0:20:a0:26:
+ 85:ac:b1:d2:7b:b9:b9:e9:9c:9d:01:52:a7:29:32:bd:94:65:
+ fb:bc:41:d2:9e:6c:59:c7:9a:b6:92:38:ba:fa:08:fc:1f:c7:
+ 72:9a:a3:a2:cb:02:e3:fc:29:20:20:b7:15:76:73:ab
+-----BEGIN CERTIFICATE-----
+MIIKDDCCBfSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTgxMTQ1MzBaFw0zNjAzMTMxMTQ1MzBaMIHAMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEbMBkGA1UE
+CwwSRG9tYWluIENvbnRyb2xsZXJzMS0wKwYDVQQDDCRwbHVnaW5kYy5wbHVnaW5k
+b20uc2FtYmEuZXhhbXBsZS5jb20xNTAzBgkqhkiG9w0BCQEWJmNhLXNhbWJhLmV4
+YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOC
+Ag8AMIICCgKCAgEAqqN0K0ttKUNnA9zAvs6m40OZ5Yc0NEJwS7tQh23oZSteGrNo
+DZ8n69y4hLs99EAowMeq5Y2h1X/HazaWaz5lcjcO1CwDTe7m+EFcJ78yU2wTKB++
+eJx8gFPrTQoZGohJlanGZSNbPiQnBut8WCTG56TZmALEzrMeATRMvZwo2hBNNul9
+qGgEdRjr8FiUBbFhl9Was9sJcXSQBYfUHP8GK8BRtibKKIvCCDqTYvhptDvDbZsP
+gB34w1GTeGSDY8fQIegFzSI+PuLCZq9GbMZ92O1TucxC6aJDlDH0nkX6RTWrfzKT
+laUbSp0nwF+/A3/KN8PCyW+2bl8FVVb1L0DCQRIX7iMbOpw5dNXMsUdqJIWV9arm
+NUAM048e09+1G3z/P99+etP44ZKwQRT2qh2MNj1cxcW3L7j4CUfCUVjegEHCpRjG
+qRY51I7v86nGE9se9YrnNxZ83yj+GUR7WJjucvpBovXgd8Je+uGUh5YXZnUHRcjf
+akAZO9pNSOhRox+6QWIKSPViQp5pSaqsNr1vQTK7YoqWawGq3hQFOkPpRfIAmtxx
+ILdl8vB9s3SgQxw/XiJH30eNXsuTGhRutCkPrxwHnBF0JDgJI3YOyvxgjxri3NT9
+/ssS+KeDxK7bpMd0s6V2kJOdo3gBl+DsCXi5mP+3Kp0FA17PsgGAeWv5XfUCAwEA
+AaOCAgcwggIDMAkGA1UdEwQCMAAwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3
+dy5zYW1iYS5leGFtcGxlLmNvbS9jcmxzL0NBLXNhbWJhLmV4YW1wbGUuY29tLWNy
+bC5jcmwwEQYJYIZIAYb4QgEBBAQDAgZAMAsGA1UdDwQEAwIF4DBRBglghkgBhvhC
+AQ0ERBZCRG9tYWluIENvbnRyb2xsZXIgQ2VydGlmaWNhdGUgcGx1Z2luZGMucGx1
+Z2luZG9tLnNhbWJhLmV4YW1wbGUuY29tMB0GA1UdDgQWBBTbT9RwwzjmJjdvG1Be
+feWAfbQIDTAfBgNVHSMEGDAWgBRGh4bC5xnPFkwMYstzf/2PGeS1QjBIBgNVHREE
+QTA/giRwbHVnaW5kYy5wbHVnaW5kb20uc2FtYmEuZXhhbXBsZS5jb22gFwYJKwYB
+BAGCNxkBoAoECAEjRWeJq83vMDEGA1UdEgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUu
+Y29tQHNhbWJhLmV4YW1wbGUuY29tME0GCWCGSAGG+EIBBARAFj5odHRwOi8vd3d3
+LnNhbWJhLmV4YW1wbGUuY29tL2NybHMvQ0Etc2FtYmEuZXhhbXBsZS5jb20tY3Js
+LmNybDAmBgNVHSUEHzAdBggrBgEFBQcDAgYIKwYBBQUHAwEGBysGAQUCAwUwDQYJ
+KoZIhvcNAQELBQADggQBAKvtRJwN+d/WjfKYBcuXDBSdDLMrSWxP1o+B3cfZZ76t
+W/YINEQJiDqd6f4LkYn4MpJDQ6/PBFw1pNIEdwS/N0VXK3CU0HpfudacR6xG5EzC
+h114tzy+gELcPDY7wFf77JU6u1h+Cf9XTk9ZcyplDm6os44ia0AMtVuW86E1khcS
+JPND/lQdrPnxcsuXuEMv4aycpud4mDitg+vJdwvqWiFqdveyTNd71FfrTKRuvuu+
+YJmuzhMcap9Y5WSitk4qLmKZ2PqvEVx+UdPPfoQc9Iul38iyOUzDQEgutp09v7F7
+WDnwOGByQvSMKrNmwekSvCpRdVUeViq8bkAcKxYlkJcYTrRj3P96MV6yOMQXZT0a
+MUcEdTq3g8NZCdWZVkVNoMhvPodhF08ue1w0dkXhtb/E/jIx/yyVUpwSKsO4BPkl
+oxFkNchdkvn8LLpFGNDclRzdMBY/VqQVRYWbUlU/9qjdVFPShBvTGpdhimDW+6F1
+8xWPt/P0Qdx9JJCaYiOh78EBadShaYJYXzW0g7F8z9zyyiOvWqzpU1O9M44iKhvP
+6ufgJLL19//2mWw0E+nyUHChD+z5EiKZWAhd8EmG+BQ7G+ZJ65v7sQdg4AXmTxM5
+0eoHa+iFM+tPt9N/vZv0pED0pEr2X9sE9fgE+hoTG8x1b8LfnYkSW/H6z9+2Mjw8
+XuAmmsfnh+dbmnazQaMP4fISadsbMlekrVtSMo1+7DTEztLua5ZWDu+XmiajtaBM
+muBPm40H35JGG1NT65ZidKgTA+MfEw5IIsq6lH+GgMB2qwg25ALzrTEvlwAGVwkS
+ZtVOj1uIZ3zjD98clxeFn7kITG6I4+e5UwaHmOijn3x9yQfYaXTR58HmRukPLU8E
+bUHouKeH1FsfieSxwLp4Ln3PhFYlVpX3k91KR4i1rNfap7PJjMVBNIwxJITUUbtG
+SjzbcuYbwcIVbhqsYb3O8aP/YNmnkFo6PhwoE+3P7+3x+3k6V6xB3uYX0JLG/L1q
+HOBEx9fOgLTCWXWovIsyTuoq/4n7+ZhrBBr9ni65v2DVhID4WwMN2R4wz054LKGI
+be6AouzZlgDJgqKBwG50S2mf/cLtCvcxqdyJ98WDg1G/8PaPInKO9gtU0Lh6OWLR
+2Ha9w4W+GEHpQsKAIRyGIPlLVV/j4W6uqwpKDAUfDbUfoNaS3SBxVnToE4MvT9By
+mLhXtcwGYzspW/e+/OEOJJTaHNG6n3uvDdmA7RiFdHNiL8s34oyFkOmG3Ct4tSpH
++6FB8dQvZocXpSQgVGGZA3JWX5aSvyVO0CCgJoWssdJ7ubnpnJ0BUqcpMr2UZfu8
+QdKebFnHmraSOLr6CPwfx3Kao6LLAuP8KSAgtxV2c6s=
+-----END CERTIFICATE-----
diff --git a/selftest/manage-ca/CA-samba.example.com/NewCerts/03.pem b/selftest/manage-ca/CA-samba.example.com/NewCerts/03.pem
new file mode 100644
index 00000000000..223d4072ce4
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/NewCerts/03.pem
@@ -0,0 +1,170 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 3 (0x3)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+ Validity
+ Not Before: Mar 18 11:46:04 2016 GMT
+ Not After : Mar 13 11:46:04 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Users, CN=administrator@plugindom.samba.example.com/emailAddress=administrator@plugindom.samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bc:1c:03:de:e6:1e:17:1a:85:5b:13:b8:a9:b1:
+ 26:36:b2:7c:4e:d2:8a:3f:20:37:ea:57:f6:46:38:
+ 9e:86:26:cd:73:cc:6d:a6:a1:4e:21:29:89:f0:7e:
+ 75:a5:8d:5f:92:42:9d:88:81:21:66:8c:2f:1b:f5:
+ 14:54:6b:ed:18:c9:a7:a6:a7:16:07:10:27:77:31:
+ d4:90:a5:cd:a2:9c:96:c0:18:92:76:f9:12:40:ec:
+ 51:54:12:36:ce:c5:02:fd:9e:b9:80:4c:81:e9:7e:
+ 5b:59:2d:4a:7c:0a:35:0c:0f:85:a0:b9:93:23:77:
+ 35:8b:de:18:e7:5d:3e:25:27:cc:0e:f0:0f:ab:40:
+ a5:08:02:84:f1:cf:9b:66:37:12:37:02:4c:03:43:
+ 04:d5:a9:ad:6e:d2:88:c4:85:fa:f3:9f:f2:5d:6d:
+ 1f:f4:54:a1:d7:4a:93:c5:42:e9:cb:da:ff:bd:70:
+ 8b:27:75:4d:77:b0:ea:97:f1:80:75:84:57:5e:1e:
+ e5:a5:d9:89:28:e8:44:a0:77:66:08:64:51:c0:4a:
+ d0:06:c7:b1:b4:1e:6b:0a:94:a0:61:5a:9e:7b:5b:
+ d6:48:ab:1e:7e:65:43:d9:e0:91:51:f5:2b:43:99:
+ a1:94:bb:7f:aa:2b:e9:54:69:c4:e3:f1:e0:38:77:
+ 9f:f9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+ Netscape Cert Type:
+ SSL Client, S/MIME
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Key Encipherment
+ Netscape Comment:
+ Smart Card Login Certificate for administrator@plugindom.samba.example.com
+ X509v3 Subject Key Identifier:
+ 1D:D6:74:30:69:F7:2D:5F:81:E4:83:F1:7E:B0:08:F3:9C:06:41:E4
+ X509v3 Authority Key Identifier:
+ keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42
+
+ X509v3 Subject Alternative Name:
+ email:administrator@plugindom.samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com@samba.example.com
+ Netscape CA Revocation Url:
+ http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+ X509v3 Extended Key Usage:
+ TLS Web Client Authentication, scardLogin
+ Signature Algorithm: sha256WithRSAEncryption
+ 2c:23:ad:2f:a2:83:57:e8:42:b3:27:43:7f:aa:9d:99:ae:9d:
+ 20:7f:0a:b0:f4:32:33:ad:ee:fe:33:aa:20:09:8e:4b:4b:0d:
+ 12:b1:d5:0c:29:bc:13:aa:04:49:ce:2c:b7:01:e7:68:e9:ef:
+ 77:a9:dd:b6:9a:0a:11:bf:88:46:0c:09:7b:ac:6b:ed:6a:8e:
+ 72:fc:d8:28:46:21:48:8f:27:04:67:2c:17:2b:33:f7:8c:18:
+ ca:c6:3d:0e:76:36:fe:6b:03:77:eb:97:28:a9:64:4b:46:32:
+ 38:23:f5:6f:d9:43:b6:4e:c6:b5:14:0c:c5:09:0c:55:94:06:
+ 92:26:10:66:44:90:64:fa:e8:ae:75:43:a0:bd:14:9a:31:37:
+ 87:30:b7:61:87:65:40:b7:c1:2e:94:4c:0a:ed:4c:c2:75:2d:
+ 60:57:f9:b3:cf:b2:ef:19:c3:96:a6:25:d3:1d:92:16:9e:af:
+ e4:e4:ca:87:77:4b:13:31:48:de:99:1a:9c:ea:9a:27:96:bc:
+ 16:48:af:83:41:8c:56:d4:9c:6f:c5:9a:31:c9:35:3a:a5:c9:
+ cc:7f:9f:3d:c2:56:03:6b:df:b3:ac:c0:47:ce:53:5c:bd:38:
+ 7d:57:d4:c3:59:c9:b7:0a:89:ac:c2:15:a4:4d:50:84:67:91:
+ 59:6d:28:a1:78:0c:2e:20:39:06:9d:0c:2d:a7:c4:dc:98:eb:
+ 4f:b4:58:6d:6a:ba:b0:5a:e9:87:7f:c9:11:a5:7c:b7:91:49:
+ f5:0a:e7:f9:c9:7c:ba:30:3d:95:a7:8a:66:47:ed:49:53:74:
+ 85:e3:63:d5:38:34:76:e7:3e:2c:74:b6:58:23:5b:93:be:eb:
+ b2:98:9c:7e:bd:0e:5f:fa:98:4d:76:13:b7:5d:22:bc:76:5b:
+ 13:88:8d:84:8b:fc:a4:25:99:82:3b:1e:2e:58:2a:8f:d7:36:
+ ec:fb:d6:1e:76:b8:0a:31:fa:56:18:38:96:d5:0e:d7:dd:ac:
+ 70:a6:c1:80:0e:9c:9b:44:e7:e8:b6:8a:64:8d:7c:9c:57:6a:
+ 90:ce:2b:c1:c6:da:f5:68:1d:c4:37:58:70:f7:ba:3d:4f:2e:
+ 6c:a6:a2:3b:12:1e:1c:ea:99:bb:ac:54:57:18:c0:d3:7f:8a:
+ c8:7e:73:8e:b1:06:6b:55:57:e3:4f:46:9e:db:50:55:1d:c9:
+ 61:99:de:31:79:75:bc:b1:d6:fe:17:b2:fd:cb:36:3a:12:6b:
+ 0f:c8:b0:a6:be:e1:a4:de:5b:76:02:bc:e4:9b:f9:df:e1:ed:
+ bb:dc:40:62:1b:05:34:c0:53:10:47:ac:c7:18:6e:7c:17:37:
+ 86:f3:84:91:17:00:f3:69:45:3f:fe:fe:3c:c6:b2:13:82:70:
+ fa:fc:1b:51:d0:56:19:b0:9e:9f:1d:27:75:27:81:f1:85:b2:
+ 15:7f:ac:f1:8d:de:fe:3a:57:0f:13:4f:d8:7c:9d:f3:49:a2:
+ fe:5a:e8:91:8c:38:c2:4b:9a:f3:49:0c:92:70:62:8e:ed:91:
+ 8a:3e:da:ab:96:d6:46:5f:25:e6:82:cd:29:03:20:83:3b:63:
+ c2:5b:34:92:12:98:13:b4:56:2d:1d:cf:4b:22:f8:40:fb:7f:
+ ae:3e:49:52:54:de:02:95:0a:f2:22:6f:e1:2c:bd:a4:08:8d:
+ ec:83:79:4a:a8:ee:27:0e:b8:6a:65:4f:ba:be:8a:94:02:ad:
+ ef:72:3e:07:52:52:51:58:6c:e7:20:e4:81:49:da:7f:f1:dd:
+ ea:2b:56:f4:29:75:16:df:b8:19:da:63:b2:a0:d3:93:5d:a6:
+ 81:f4:2d:d3:fb:cb:7c:e3:04:8e:38:9d:66:9d:29:57:28:22:
+ e3:7a:5b:48:cf:6e:79:32:24:6e:e4:dc:7a:05:22:2c:a4:0e:
+ 30:74:41:cd:34:ef:3d:33:4e:01:3e:65:25:01:cc:5d:73:5a:
+ 10:d6:df:45:24:93:69:fa:d3:ab:7f:c8:b7:5a:86:1c:88:be:
+ 32:05:2f:f8:2a:26:02:f5:cc:30:4a:dd:97:0a:3a:db:c0:0c:
+ 67:36:90:9b:f9:2c:e3:d0:04:26:46:c1:a3:4e:a0:46:be:f3:
+ 8b:91:9c:d5:f0:32:09:c5:f0:a3:51:bf:05:70:83:51:25:ba:
+ 6f:8c:25:ea:30:96:52:e6:53:64:38:ac:0e:de:54:e7:5f:da:
+ 30:e0:39:9b:d8:64:d5:3b:70:4f:9a:27:96:36:98:9b:f5:07:
+ 0b:4a:89:40:06:18:9d:6d:e2:6c:40:51:af:83:66:73:87:56:
+ 5c:fa:38:96:a8:dd:4a:28:4a:82:d2:09:0f:e4:77:db:09:ff:
+ 50:34:c9:dc:0e:27:fe:94:1d:65:71:56:59:19:1d:62:a2:1a:
+ 93:bc:25:7b:be:6e:06:2a:e6:ce:ef:fa:cf:30:a2:e6:ce:26:
+ 28:e5:eb:6e:03:64:3c:8f:65:ce:32:33:08:ab:dc:45:69:78:
+ 4e:d3:b5:87:4f:03:48:e0:c3:24:48:cf:74:79:62:1e:b1:e0:
+ 39:12:02:08:db:fe:f8:78:a7:43:7f:e1:e8:86:b4:04:3c:e1:
+ fe:26:71:75:9d:32:4c:3a:ad:84:cb:e6:be:f5:7f:20:9d:04:
+ 4f:ba:41:d1:78:4d:f7:3a:93:89:ef:a4:4e:b4:83:4c:92:70:
+ 39:1d:21:de:c8:4c:9b:5d:26:55:1b:ad:93:48:79:19
+-----BEGIN CERTIFICATE-----
+MIIJLzCCBRegAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTgxMTQ2MDRaFw0zNjAzMTMxMTQ2MDRaMIG7MQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEOMAwGA1UE
+CwwFVXNlcnMxMjAwBgNVBAMMKWFkbWluaXN0cmF0b3JAcGx1Z2luZG9tLnNhbWJh
+LmV4YW1wbGUuY29tMTgwNgYJKoZIhvcNAQkBFilhZG1pbmlzdHJhdG9yQHBsdWdp
+bmRvbS5zYW1iYS5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALwcA97mHhcahVsTuKmxJjayfE7Sij8gN+pX9kY4noYmzXPMbaahTiEp
+ifB+daWNX5JCnYiBIWaMLxv1FFRr7RjJp6anFgcQJ3cx1JClzaKclsAYknb5EkDs
+UVQSNs7FAv2euYBMgel+W1ktSnwKNQwPhaC5kyN3NYveGOddPiUnzA7wD6tApQgC
+hPHPm2Y3EjcCTANDBNWprW7SiMSF+vOf8l1tH/RUoddKk8VC6cva/71wiyd1TXew
+6pfxgHWEV14e5aXZiSjoRKB3ZghkUcBK0AbHsbQeawqUoGFanntb1kirHn5lQ9ng
+kVH1K0OZoZS7f6or6VRpxOPx4Dh3n/kCAwEAAaOCAi8wggIrMAkGA1UdEwQCMAAw
+TwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3dy5zYW1iYS5leGFtcGxlLmNvbS9j
+cmxzL0NBLXNhbWJhLmV4YW1wbGUuY29tLWNybC5jcmwwEQYJYIZIAYb4QgEBBAQD
+AgWgMAsGA1UdDwQEAwIF4DBZBglghkgBhvhCAQ0ETBZKU21hcnQgQ2FyZCBMb2dp
+biBDZXJ0aWZpY2F0ZSBmb3IgYWRtaW5pc3RyYXRvckBwbHVnaW5kb20uc2FtYmEu
+ZXhhbXBsZS5jb20wHQYDVR0OBBYEFB3WdDBp9y1fgeSD8X6wCPOcBkHkMB8GA1Ud
+IwQYMBaAFEaHhsLnGc8WTAxiy3N//Y8Z5LVCMG8GA1UdEQRoMGaBKWFkbWluaXN0
+cmF0b3JAcGx1Z2luZG9tLnNhbWJhLmV4YW1wbGUuY29toDkGCisGAQQBgjcUAgOg
+KwwpYWRtaW5pc3RyYXRvckBwbHVnaW5kb20uc2FtYmEuZXhhbXBsZS5jb20wMQYD
+VR0SBCowKIEmY2Etc2FtYmEuZXhhbXBsZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20w
+TQYJYIZIAYb4QgEEBEAWPmh0dHA6Ly93d3cuc2FtYmEuZXhhbXBsZS5jb20vY3Js
+cy9DQS1zYW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMB8GA1UdJQQYMBYGCCsGAQUF
+BwMCBgorBgEEAYI3FAICMA0GCSqGSIb3DQEBCwUAA4IEAQAsI60vooNX6EKzJ0N/
+qp2Zrp0gfwqw9DIzre7+M6ogCY5LSw0SsdUMKbwTqgRJziy3Aedo6e93qd22mgoR
+v4hGDAl7rGvtao5y/NgoRiFIjycEZywXKzP3jBjKxj0Odjb+awN365coqWRLRjI4
+I/Vv2UO2Tsa1FAzFCQxVlAaSJhBmRJBk+uiudUOgvRSaMTeHMLdhh2VAt8EulEwK
+7UzCdS1gV/mzz7LvGcOWpiXTHZIWnq/k5MqHd0sTMUjemRqc6ponlrwWSK+DQYxW
+1JxvxZoxyTU6pcnMf589wlYDa9+zrMBHzlNcvTh9V9TDWcm3ComswhWkTVCEZ5FZ
+bSiheAwuIDkGnQwtp8TcmOtPtFhtarqwWumHf8kRpXy3kUn1Cuf5yXy6MD2Vp4pm
+R+1JU3SF42PVODR25z4sdLZYI1uTvuuymJx+vQ5f+phNdhO3XSK8dlsTiI2Ei/yk
+JZmCOx4uWCqP1zbs+9YedrgKMfpWGDiW1Q7X3axwpsGADpybROfotopkjXycV2qQ
+zivBxtr1aB3EN1hw97o9Ty5spqI7Eh4c6pm7rFRXGMDTf4rIfnOOsQZrVVfjT0ae
+21BVHclhmd4xeXW8sdb+F7L9yzY6EmsPyLCmvuGk3lt2Arzkm/nf4e273EBiGwU0
+wFMQR6zHGG58FzeG84SRFwDzaUU//v48xrITgnD6/BtR0FYZsJ6fHSd1J4HxhbIV
+f6zxjd7+OlcPE0/YfJ3zSaL+WuiRjDjCS5rzSQyScGKO7ZGKPtqrltZGXyXmgs0p
+AyCDO2PCWzSSEpgTtFYtHc9LIvhA+3+uPklSVN4ClQryIm/hLL2kCI3sg3lKqO4n
+DrhqZU+6voqUAq3vcj4HUlJRWGznIOSBSdp/8d3qK1b0KXUW37gZ2mOyoNOTXaaB
+9C3T+8t84wSOOJ1mnSlXKCLjeltIz255MiRu5Nx6BSIspA4wdEHNNO89M04BPmUl
+Acxdc1oQ1t9FJJNp+tOrf8i3WoYciL4yBS/4KiYC9cwwSt2XCjrbwAxnNpCb+Szj
+0AQmRsGjTqBGvvOLkZzV8DIJxfCjUb8FcINRJbpvjCXqMJZS5lNkOKwO3lTnX9ow
+4Dmb2GTVO3BPmieWNpib9QcLSolABhidbeJsQFGvg2Zzh1Zc+jiWqN1KKEqC0gkP
+5HfbCf9QNMncDif+lB1lcVZZGR1iohqTvCV7vm4GKubO7/rPMKLmziYo5etuA2Q8
+j2XOMjMIq9xFaXhO07WHTwNI4MMkSM90eWIeseA5EgII2/74eKdDf+HohrQEPOH+
+JnF1nTJMOq2Ey+a+9X8gnQRPukHReE33OpOJ76ROtINMknA5HSHeyEybXSZVG62T
+SHkZ
+-----END CERTIFICATE-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt
new file mode 100644
index 00000000000..8a0f05e166a
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt
@@ -0,0 +1 @@
+01
diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt.old b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt.old
new file mode 100644
index 00000000000..4daddb72ffc
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-crlnumber.txt.old
@@ -0,0 +1 @@
+00
diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt
new file mode 100644
index 00000000000..27e6ac3ff60
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt
@@ -0,0 +1,4 @@
+V 360313114451Z 00 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Domain Controllers/CN=localdc.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+V 360313114511Z 01 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Users/CN=administrator@samba.example.com/emailAddress=administrator@samba.example.com
+V 360313114530Z 02 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Domain Controllers/CN=plugindc.plugindom.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+V 360313114604Z 03 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Users/CN=administrator@plugindom.samba.example.com/emailAddress=administrator@plugindom.samba.example.com
diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr
new file mode 100644
index 00000000000..8f7e63a3475
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr.old b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr.old
new file mode 100644
index 00000000000..8f7e63a3475
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.attr.old
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.old b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.old
new file mode 100644
index 00000000000..04d6e6beabc
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-index.txt.old
@@ -0,0 +1,3 @@
+V 360313114451Z 00 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Domain Controllers/CN=localdc.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+V 360313114511Z 01 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Users/CN=administrator@samba.example.com/emailAddress=administrator@samba.example.com
+V 360313114530Z 02 unknown /C=US/ST=SambaState/O=SambaSelfTesting/OU=Domain Controllers/CN=plugindc.plugindom.samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-openssl.cnf
new file mode 100644
index 00000000000..17a55717f06
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-openssl.cnf
@@ -0,0 +1,203 @@
+#
+# Based on the OpenSSL example configuration file.
+# This is mostly being used for generation of certificate requests.
+#
+
+# This definition stops the following lines choking if HOME isn't
+# defined.
+HOME = .
+RANDFILE = $ENV::HOME/.rnd
+
+#CRLDISTPT = [CRL Distribution Point; e.g., http://crl-list.base/w4edom-l4.base.crl]
+CRLDISTPT = http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+# Extra OBJECT IDENTIFIER info:
+oid_section = new_oids
+
+# To use this configuration file with the "-extfile" option of the
+# "openssl x509" utility, name here the section containing the
+# X.509v3 extensions to use:
+# extensions =
+# (Alternatively, use a configuration file that has only
+# X.509v3 extensions in its main [= default] section.)
+
+[ new_oids ]
+# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used as a login credential
+scardLogin=1.3.6.1.4.1.311.20.2.2
+# Used in a smart card login certificate's subject alternative name
+msUPN=1.3.6.1.4.1.311.20.2.3
+# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used to identify a domain controller
+msKDC=1.3.6.1.5.2.3.5
+# Identifies the AD GUID
+msADGUID=1.3.6.1.4.1.311.25.1
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = CA-samba.example.com # Where everything is kept
+certs = $dir/_none_certs # Where the issued certs are kept
+crl_dir = $dir/_none_crl # Where the issued crl are kept
+database = $dir/Private/CA-samba.example.com-index.txt # database index file.
+unique_subject = yes # Set to 'no' to allow creation of
+ # several certificates with same subject.
+new_certs_dir = $dir/NewCerts # default place for new certs.
+
+certificate = $dir/Public/CA-samba.example.com-cert.pem # The CA certificate
+serial = $dir/Private/CA-samba.example.com-serial.txt # The current serial number
+crlnumber = $dir/Private/CA-samba.example.com-crlnumber.txt # the current crl number
+ # must be commented out to leave a V1 CRL
+
+#crl = $dir/Public/CA-samba.example.com-crl.pem # The current CRL
+crl = $dir/Public/CA-samba.example.com-crl.crl # The current CRL
+private_key = $dir/Private/CA-samba.example.com-private-key.pem # The private key
+RANDFILE = $dir/Private/CA-samba.example.com.rand # private random number file
+
+#x509_extensions = # The extensions to add to the cert
+x509_extensions = template_x509_extensions
+
+# Comment out the following two lines for the "traditional"
+# (and highly broken) format.
+name_opt = ca_default # Subject Name options
+cert_opt = ca_default # Certificate field options
+
+# Extension copying option: use with caution.
+# copy_extensions = copy
+
+# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
+# so this is commented out by default to leave a V1 CRL.
+# crlnumber must also be commented out to leave a V1 CRL.
+crl_extensions = crl_ext
+
+default_days = 1 # how long to certify for
+default_crl_days= 7300 # how long before next CRL
+default_md = sha256 # use public key default MD
+preserve = no # keep passed DN ordering
+
+# A few difference way of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+# For the 'anything' policy
+# At this point in time, you must list all acceptable 'object'
+# types.
+[ policy_anything ]
+countryName = match
+stateOrProvinceName = match
+localityName = match
+organizationName = match
+organizationalUnitName = match
+commonName = supplied
+emailAddress = supplied
+
+####################################################################
+[ req ]
+default_bits = 8192
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extensions to add to the self signed cert
+
+# Passwords for private keys if not present they will be prompted for
+# input_password = secret
+# output_password = secret
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString (PKIX recommendation before 2004)
+# utf8only: only UTF8Strings (PKIX recommendation after 2004).
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings.
+string_mask = utf8only
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = US
+countryName_min = 2
+countryName_max = 2
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = SambaState
+
+localityName = Locality Name (eg, city)
+localityName_default = SambaCity
+
+organizationName = Organization Name (eg, company)
+organizationName_default = SambaSelfTesting
+
+organizationalUnitName = Organizational Unit Name (eg, section)
+organizationalUnitName_default = CA Administration
+
+commonName = Common Name (eg, YOUR name)
+commonName_default = CA of samba.example.com
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_default = ca-samba.example.com@samba.example.com
+emailAddress_max = 64
+
+# SET-ex3 = SET extension number 3
+
+[ req_attributes ]
+#challengePassword = A challenge password
+#challengePassword_min = 4
+#challengePassword_max = 20
+#
+#unstructuredName = An optional company name
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+[ v3_ca ]
+# Extensions for a typical CA
+# PKIX recommendation.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer
+
+# This is what PKIX recommends but some broken software chokes on critical
+# extensions.
+#basicConstraints = critical,CA:true
+# So we do this instead.
+basicConstraints = CA:true
+
+# Key usage: this is typical for a CA certificate.
+keyUsage = cRLSign, keyCertSign
+
+crlDistributionPoints=URI:$CRLDISTPT
+
+# Some might want this also
+nsCertType = sslCA, emailCA
+
+# Include email address in subject alt name: another PKIX recommendation
+subjectAltName=email:copy
+# Copy issuer details
+issuerAltName=issuer:copy
+
+[ crl_ext ]
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always
+
+[ template_x509_extensions ]
+
diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-private-key.pem
new file mode 100644
index 00000000000..852b53d9c78
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-private-key.pem
@@ -0,0 +1,102 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIISjjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI8K/V4PKOJq0CAggA
+MBQGCCqGSIb3DQMHBAj0N1BCFJkjIQSCEki8nJ5Sf4sV5cwTX0t2wqkXcZkP0L8f
+wc/F/B9+EmqsJiTpH6wnH1ztcEqTBVfOsln6TYeF9oUgQrEZgYDQE4Hwxq7QKreK
+vOvJlSX5Grk727s32msLjqiH+ccQOFiFme8SiTJqfCeyJyYOWoBMwmney3Ao7+Ab
+1CtJtw6zOHKOeiBM6gNu9hM362ESUSPPiwgfx90koHuilOy3vxHPuGSWtaCt1cGB
+Vuvp/rPY04vUgs4lSXacWB61Jy0qnFu0dGmzeBRP5P4TGzvdAOJY54lAwNxaEZg6
+okVQ32JdNxze708N+uObWE9LYgQpMriEww8f/anKE9yMRD+K8cvMkvMph4qRJuVj
+W9OKJxOpfnRopbVYbh0O+gK3zA9RWQmfvrZ7O30sGqbKQhZWneU1Pa8WfEflfrBs
+TDLQdJ7J9Jdar41faSFDg4jSzqhk8FGtSP7hkmJRII4ltPoXjHUEmpSeGsOtT9Ey
+25QcVcizyHl0ckJ0efib6pUWmhpOF05uf/RTTY7seBv+NY0XPFpMtH5PS6p0dNTt
+bg+MgJqewwfWCcv577MMAdyXHV7aOTUJ+g4V6YME/20tL6sMyQafMfWq4yLMHtmL
+MC/RU8hKnTHT0uh2QHkxFiUWZL7yLwKgXKRU3y00dDJ3QvwnrOdVSXod//H64dyZ
+BYwc/st24DswlAs/xclapNzKm2BjRJxsaeGuEmUpSOQn4iV6r54CEwEgcNB6rKMT
+mYefJ2pKlswCDtZz744LeVqYFb/Tp6bV1Jq3of90GgIf53Ziq5eWILuubWw9ZMJ5
+2ex6A2Lb/+GiXaKdITeJmUvxme6ZxH6efvGE2yciTLki0oPDmPFywcsdJK/FzVNv
+F3gOqD558Oo/uUf2aw/VwUZeFIA465RQbIEXj06F1KnA3JwMlRNJy2Jz10sLcyJR
+vVykjjRZVb36coOrnMt/rGpiXXci77a2hUX/nNrEXL8A2wobS2kGVOPz4klD0Rfh
+/B4kqa3pnPXjUKn0xNe3CHwOd/qOPgzlUYkGDZP+GnuMpaFWfz4tWmLaOElKnWwi
+MbzDAt6Fh+nddHMusxtQv/iyADq5CC7XcZsFfnQQBR9yyrdoMwJxiEbF1oyB2LvS
+iQqWxtoT6Y2PjfBS+zmbLEVQfwxL0UiQ/TrdgWumsIVi02AlEvyj4aIhc52aSevk
+M5rWkKqrJqec9bLeXYlIpS57VYwxd+8FZjkxM/bIrGh7Bas7t1BQ3anh7+t7H6xr
+XU8rwuGDtw0LawkGUC+0OgcmM+45WQdR1LtTP2xrwH1MdIoX0BrVtqW4ZpOBjjyD
+UpG1bv/CGQwRXtZ/pVrWMfohYZOiNqyyiTEgmHjCuoon161mLRnRb6vVKp6eRUH4
+GMW8UM/k1spF/zMUfkuymdyFwkGrdhuDuaiaW3A3sgECqSKY4p4VXa1Awm8v2t0J
+tHTuOAlbuhgtZXE6P1dtas+sc2WbsKC6X6ul+dhzvaBJo31Dz16ly74h+U/UUS9u
+iS6p+UMCdg33R96AITJJ83RNQBIFG6sEZDTEy9fvH31uBVbeuW5GOhT5cMBf9b24
+o9B/gl5CVEmEAdwQ8BY6W7Ujk/GN7q44kmATT8C0zW5vJIbK1SRrYyfhiPjN+uv1
+bVrQDajrmP94MdpPB1YW1q0fZwRsz4836SN0uMSvC++rHzqgT9nhcJM7eHbvXtkY
+u/57OnCTNtSIxzgcnS8TfMJTrHF/f4o/RuBbVBMFZFWHUIN4+OKwf7qzmNYHleMR
+WN+2nTxACLL58RPOzCrQWLsbPFdOE81XSTQjp9YXF7H1MeMVaUhkXZDHShk8SOMX
+oewF6ZvcM6sxgdYz8Ib/5dBDOLxBESc8ctvBgbmDGRopwTdCfDY9+TwZUE4n9Lj3
+EkcNh4282btr1MosBnH/udb5QZhlsXQCwrpvdxNTEsmpLpV5t390B+3Rt6wMxTLG
+j4nNQuK2rj9D3to+S4wyfmg3QOmiUMrVCuW3anmoEcwlHsQN+BSkCF1PleGklCET
+DI4DuQdv5CTg61nN8zIIqqVtCAXiSHX/FM4KAQHD1oLEozoOiS3AH6mx6cJ9rEP6
+iWylQzI2Ppv7hYTKpheboVlL8UsMbr982rUXeIUsGqvM2dSEuX8EjKQKqfDmo+1C
+AA1puZvpGsVgvgEb9cDgklBKFOHRUhV3KP4oe7Zx4SsyTIuNYBG1U1ykIPiTLpQd
+jzu/PwO94AIMiqF3NwEfOU+NBdG3cADdIau2cJucQTzfvBgQz0YkcnQq8dTTUaf/
+P76bviKsNqzy3fawbRziHkPk6VBsNwOkOSz9T9TYrmFlOSC9hJp/7k92TUy6vPxM
+UbsUEZmS2dwmSjtGzjLyTv9yF50qHq5u03LpaKU5IHZHHoi2RnDvwblhtZlm8w9s
+mRrbXiZkYAXg2BKDS7rTWIR3RBptG2iYPuQaUQ4XgMFvDIsGmEgm29GJOpLmIKy2
+NXBL2hRgmDGvUkMdRTKMm2sh+/ml6iW58kXgXyeIp/Z450zq2q2oa2Vd+LCoM+2a
+zEa6ykn6gRIMFIu7VbGNtYrVDixZLqsqGDZc8O1Ob/fGzMiNL8cM+N9GCLRmIV+E
+EqhwyrmF2gKj3mP1D4y1hdcgJvQpYdaPdpTe8cUaDpYtptl/TwS7s9YWjFnPXzfs
+hU4TquWDthGpuIT4D3N6rd3gWHb8wmT67FEjYt7pC8IIkquIaerlkLN5Z5bX+MhH
+1yiZBTmJ7vx+EWG5UMDW4khYNR5ggH1kN3pYbmwQW84GIAiJ6GJcp658QIT8/WKv
+H3kHl+3m5Oduncy6HpuN37Fbzbak0AAevOPtjwTHTyyb7dgbMzp7Z3yApZ9h4ENz
+0tk+2bRG0TPsBBmHYyGx66r9s23yQV+7ewmBY07Z2YkJGJ1ezzwYypseQIFWWxY8
+zmuehkT2sXycF89zGoVWL1Bcrpdg5Bi20rUOtKlkFWzcVNdOXdbcMu8u5RVxeLEj
+ftBInNO8gY9tjvzPKMv7KOj3RE6sPNiVZS/UIicAIEuvgt3Pu8WooG7y32hBE66H
+vITJWK+RvDN6BPfmFMQAAUXLpBTsqkmferPWrgxSd2T3cgbjS5JvAquxt0Mad3TH
+ERPHOoDi62x4jX7UiElNQUGArcVw7MNuo2txkRvCnb8GZK8JiWcBVzuka8Fs1JBe
+kw6tqoauNM+uNRaVgY7o1NPfW3uA53B5N2OHl+t5jmXi+llTmQz5VXE+UiCacxE8
+Vlhtos6w3E7CfCXDfwlvaZHniPM4PZic/jpDZEE+XBWvtcXkgstG3Ufs9MpCIqCj
+ktjiiVBNE+QLaCpw7sNZGq1QOxmdMw97/HRwVGWtzvx63B7a44JBfnVbPAp2e30k
+vTPI2v/4b0+7AvKMnnON7VZHmifngEr6Ok+m7+O1yn2KyigOANPPdzTkGV69tv9c
+XoIkvCXYXDrEpi0n7z4SSze09qAZ12jDAOY+H+/ag1nOar/bP68WSISL1uE3wYWX
+kbdp3xdES5BPXZK/EldVGlHvvqwYBKHI9XmG361+/b/mxLVIcfBwtiiFIaJvnRcc
+pzefHJo01aW34//OYGs1lc7s39Ox2094Xj4uqorNBu4f3hKna5cnzBLqDK/zZUA+
+RV4CutR/OZTw30xv2ho7FKb7uHg7o3jk2cRQgBy3ep2DwxhBZ1HrtozDOLZs2nFL
+9/+GdKahJS+ZOmfSOVKUpyWw2OtlnGYIp3NxsWdGtrK8/aLrFgY9wOHJ7A19Lb2Z
+wTMn+wqrGv7rp4TBdND5eAj5+P+1027GHn20fHtF3yqDsIjwd9Qaoh6JRnB7f0KS
+cQI7X3J7uv6uRT9uNdxk8BV9cliz0OHIvxPdov43QSRetpVMZez1nDwJRx2hkh1X
+tl+qLG9tZvB69Wwh+bFQ5vwtH9YJHHBlg8rdCFMj4IHY1dEPvzpmvd0xxj7lVX1/
+CzN232aaYblfn2SCFUbsnxhAMrb762FIp37VOXw8Uu1ylF0hput46oJhqeheI95X
+0/eLTjE5ZYPYXD6tiGx5JC2R3jSUZ9JDC50YFOYEALyagBc1vzcmMUxbi8SHEGd8
+sgCpWVmCcZfWA6yJRTiuip7pDkXW8E1sm63moYsSZ9DdNboYM500z7Swm6TsOejf
+2m8axEhXJorasZKMw6nLUEO6fyMbbp6ZZRjRd0dBjEdCF9oPKhK5vx+A9e8eiwJ1
+io15AMh94DOVUBtZpMl/oLurGsPyMzbPY3D9FtACDQ5fZ/T1gM3CBQj0YhaoZ8vK
+Zj1F/CdQMhm4GoTaFeZAjOLQb03h7PuDYDBGMk43SIt2ogCYfmQWWQy3TfHZqcFV
+IdT3eYMi/j9cmCrxBJwoftBYVg+qPtGyRisD+CPVJKVGA6Q6T2Fcr5AQdzwtvFjj
+7OTEPEo9cDvS+Y7sTKHULBmHAZAAYQr2CsNZ1G9e0xXvp3+++S4EZ/Xp2xE1iImX
+Uup72cVMZPcm9s7s6u/rS0pEtgf20US7Ct9B77Govevcp5xeNVQHQFehF6Ksd4b0
+dnQCfNZ5bCBjC2D9S2rnPL+N5mkKSMwk+zFjc7owno/INs7za/TGU7wosnS4+nuT
+6J1ya0RrTjPU6eh453R5QKfYof8C1qpHvAhNhLqI/dJK5XSDeBVEcdCj+pEekTC4
+3fFJ2ZNxXIoE7Folwc/VAmlI1lsq/ZimNwL2UQ/Yh06dxm1G9W98F+8m1vNdwudG
+moMbwmrPLnnxTwAOhAQkdtpYKKaiXkH9xkJXNRew/Jaer3YvPF87yyu78eU83ZP/
+3ua/5Aq6L+6FK78nfGfv1FhtYCdsMNZv/xGQS6LVAdOON5A4+0C8A97mAQUYen2F
+34j5TY9iuqeLvXFxSZ/s+hafuRbN682PQ3Mdrd7CINjQmtGHSLoRp+6gTQ844bl4
+kaJhsawxBE8rE63I58w0E715u/o/460N1bYaLBY4n2wbv3pDRVNtJcJRSOeLUSZJ
+2slbE8Ok7jmAexFNlj/cjFwcdMPSjk5J5hVXhRiQgbpVVEpvUPgGuULwXpfot6o5
+uREHPjf/PP9Oneny69Eoijtee8f9SIYEkLsiMpUrdm+3JXc8ohI8DqjmDsr+YUUl
+yJJ5yXyUQjG3YZU5S+3lH0G9VQsIPpIUuqOtllOPLZjZe+7g35GUASeh3TLoO2l7
+Jeub0I5apqXwNSf/Xw+fIbiunMKGGOFotKCYDn7w6HT2HLsFFGu2NJigeBzBsl2N
+Ngms0Ur1r+8EUsmIP2Fox02saKbCyiaTvpMUMTrXPsZ1L83galem8QWr6AiHCk06
+heOu0leO77baMA8hgPjpY1RnVYl4/ZX+fTGkq1rNAmNHt7x46FQEK/yuFtMt1sNh
+DgA+HJpNLh8FTDesiIymfaesoXk79FSD7amsPfT4oNzjo1aqsrQ6qteKD0XqLjOA
+juvUF3O/MhD2frSDT6yHs8Pd5aPDb7DwX8gRaQ68kFwyUXPijpU9rFAylIT15WNb
+xXfwYgq1g5V0eqtEVlLisQj70wRJOADYCRAAcEUYiaf86pN6SUxH3a48XrqZqcVi
+vPteMicbitpcJjmVHAKiKlwqwmFmnwzb57J2xYijG9Y2TKE9HBCDkaKIx3BUQRdq
+VcZJ+wm7rBtScBXhECkyzFbJVOLCSYX/ziKf33BBZKhRY6cCr0UuH1G5nj8wxiin
+fod7Go8slrBS0pnPRWczxH3LqbvpRBA1lfTaKNyBSAjDuVJF5QifiIjRqk5AziCU
+Bk3F3pVIoA72OnXlmdDa2HkG85iH9NyiWEfOkou5goAuQvILu94cX0+gw3bGYNPc
+Uc+LprTR5cXT2aA5D7uRMMWJ+Znrw3/4pnKtVmRGkbMsuFej/gKXvl+UCmYkywXa
+RyE1BeThrRgA4/QeU9x2aqCnZyTmszFW43PtzzZqfks48qpBxYq47NbrfLV5w9av
+1XzVj8NIechjFlB/KUIY6jylY+fAdx8Za8I/RyCFWwlhsDQ4Ef3aWtumlevYu0d6
+1Z63Of+ySvOdlvsoV2fOHAJGa2aeAh+ibXe8h8myNOrzVDx4blParf0F28ikaVOj
+IzH8Rk/UEsCElY+Cb/KVPoPtk1zxtFhAElqq18LGrRbQBT7Ntd/FYf84POZ5ItKu
+B1z8hmq2EIb0FUKV7Hx4coFE6cb8y1NcMs5T0z09nfCiDZJl5Vr0NR6bWDRBWm3L
+seXEEGHblpFl4UTVMZ3szBHGveDSoKujIiqbHC8o4GshhmQBhyIhw0lnxmh40FPk
+R1Y=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt
new file mode 100644
index 00000000000..64969239d5f
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt
@@ -0,0 +1 @@
+04
diff --git a/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt.old b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt.old
new file mode 100644
index 00000000000..75016ea3625
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Private/CA-samba.example.com-serial.txt.old
@@ -0,0 +1 @@
+03
diff --git a/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-cert.pem
new file mode 100644
index 00000000000..2b3d7fb1487
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-cert.pem
@@ -0,0 +1,62 @@
+-----BEGIN CERTIFICATE-----
+MIILPDCCBySgAwIBAgIJAMjuQLBy0LOvMA0GCSqGSIb3DQEBCwUAMIHGMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKU2FtYmFTdGF0ZTESMBAGA1UEBwwJU2FtYmFDaXR5
+MRkwFwYDVQQKDBBTYW1iYVNlbGZUZXN0aW5nMRowGAYDVQQLDBFDQSBBZG1pbmlz
+dHJhdGlvbjEgMB4GA1UEAwwXQ0Egb2Ygc2FtYmEuZXhhbXBsZS5jb20xNTAzBgkq
+hkiG9w0BCQEWJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29t
+MB4XDTE2MDMxODExNDQzNVoXDTM2MDMxMzExNDQzNVowgcYxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIDApTYW1iYVN0YXRlMRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNV
+BAoMEFNhbWJhU2VsZlRlc3RpbmcxGjAYBgNVBAsMEUNBIEFkbWluaXN0cmF0aW9u
+MSAwHgYDVQQDDBdDQSBvZiBzYW1iYS5leGFtcGxlLmNvbTE1MDMGCSqGSIb3DQEJ
+ARYmY2Etc2FtYmEuZXhhbXBsZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20wggQiMA0G
+CSqGSIb3DQEBAQUAA4IEDwAwggQKAoIEAQDRaY4kvh518y/goY9ZM+e7Z2ihJ0fB
+dC7vMPyl+5GjcatbL4pqe/FQWDPVKZrTQzLEjDjoTjfFIaZDE8WGeShDS1Z0vaNf
+u4NPCPyTwYpzH76E5a/gvQVt6c0tJC74pD3Z2u7JdCEkL5ywv/RggMPqVz4SmHZn
+Ul53Y+/GgNoqb3Cbd2IAbD8QxNgbwKoYbP2+31DZALlL3pR4yUYSvf7OxPuY4nRY
+npYpr/C77Zi5nx5nSmplYN15ab2swx2qMMF6LGrxyKK7yfLoDJn2iZa9JswL/gTx
+3Tc+gkEvQQby3wzffWKSA2m7wFGxd1mytsFFnsohloueVj4b/FdTHuJM2SKD5JXf
+l9Jh6ECMcYolcKNpWRZPsv5eAJNiwfy0f2+fuz9x0sB6F5hP0ttEdvYto2ZkMNT/
+hRsBGsAI1NP6AGNgDuGbi9ZLML7kWD0ZH+8ceFl5QKcvDw3QCBiwkc/LtGcnMyRV
+5Fkjiptu7jlNsjYi+h/N8n/sFawjcERYrnaevD0J4qgekq0VuzdcYLZnW7j7L/+A
+klQlJsyP8OD7VRvAbRDmRWRqVKa6wvuOC/zb/QCn10WcabsD6IsbjP5AS8DEosW3
+ld71mCeskTG50TK2+fFoofHTjqJl2g3JCwmBJ/OWj+i986+JG9MaXxqajLGkd0rZ
+AroMHllkSB3STiybQb9uLyJG1hrVeVeYz9uFhCSjQvcYLZ+weIt2C/43BYLp06Ss
+ZHjMy96kiGnUnw6PIMsPW+sZOzfby183kZjdKOWw6TIlDEznlWwFLa43mZqPRLhx
+xsLd6wZAXXYBK2k0fcSMLIGnzLyvzcS6XVD93G136IvZpGgmryZkVBmzkGyoigMy
+h2dzVpj99qu6JNig92YkS5nVRXgt5V63vS4cavwWgxZbMr6q1nOPmphCa8pTJ68u
+PeRS71B9TTF6Wx5T/qeQ/Qzx9aa35eNO3LpogxFRWWJP48yFmjEZ4fKtLYlted1f
+ZfFRlnkYmfuaqCaDUQKnxI1TWaLUMIWxZRNSen471p/x5+M7Vn5q7RLiu+UprFYM
+j1swJ/EBw00KqEtlb6QNHuegqOqwUat1D2F9w/BIq/krR7lhM9UyB9FXttXFwJLS
+WaBXL/S5ZrIXeHvIObOM6ovhza7dtRQuAJSs8DwBfhcNn1JxUGGHkAkg2xSr9Pl8
+wBigczSjGw35YxO+Ne++mF6dlHcoexrm3ZVI84kr1jB4dyFKuVCZ+6TabxeCNytp
+s2+6YoCcu7b1ie2ljt0jhCcw0oEY3OTv0lAdOS4mst4rwgPr8kB3IqlLGnTPUFGg
+g2clRN1JzWE9auTElWA0j4ECRbq4/HXrJB/L2TGi4kfqSGmCzLXgYCe/AgMBAAGj
+ggEpMIIBJTAdBgNVHQ4EFgQURoeGwucZzxZMDGLLc3/9jxnktUIwHwYDVR0jBBgw
+FoAURoeGwucZzxZMDGLLc3/9jxnktUIwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMC
+AQYwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3dy5zYW1iYS5leGFtcGxlLmNv
+bS9jcmxzL0NBLXNhbWJhLmV4YW1wbGUuY29tLWNybC5jcmwwEQYJYIZIAYb4QgEB
+BAQDAgEGMDEGA1UdEQQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4
+YW1wbGUuY29tMDEGA1UdEgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJh
+LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IEAQBeOC+ekA3OZ2DRFN6VQED2
+87IsASYi8kfZhRe/vA6Cx42jqbmJcbdDtc8v2GqMXbuO6nFZCOmhxvShL6ScQI+j
+Scx6pNZYi8s4tg/2KGsTNRhhNXYzQ1hbEpQuDi8cHvft95cKlBTZrZHXyBTJbOZJ
+jy3jbHmzsE+RiuMvBM+QVvo/ykQ2ySc6O8rzOhRwmSvrW+zZEjrOZEjQVFMisq/S
+LkJ8Y8SkxH9F95EBexVztpOzfY20hkc8UDaqDP7OQhoY95mjJ0j90/7TjNTFT1bi
+GmOVMr+K+3RWqUcCvAY0tIG9cPDvRFT5frEcV87W/R1ffG0FnNaq+Y8AGI24UO4s
+TDll92OOX5KDbVunVerw/CII3+9k+tB9lbDYsdfDaoFJaIWLV0kXV9uUS/Ninp8T
+M6smq594Hbjuy8hcse3USKrnMP1lLkb9s3I3U+UV098wf5qFx/sFjeXsPhZcD6Gt
+oL9uGY2M6ZWxgkvOUDtdzfyhplWi7Ps+n+qR6JuCp5cemb8WGarqekeZNuJfve/f
+eWXgpwac5CgJTSOI37LqzYKQehaBD9vJnS9RUMacSxOiH3puXGrxgPye88Yh6YOY
+bkdsDQY17JLdLw6zHObJ1MrywCVLYa9aZlzrISJ2oka4qza+rfl6QVoYNcKUK/oh
+hKcWpcfJOrDlxHneow4iA9uYY2MrKDKuTEgNS+lWYD3EO5iq9cC56anBO581xBXM
+6ZBEijuIHOETlu6Hyks2iVkEEeSDT4JGVn720WXuMuZYMWh+TOTJz9Sq1M4orlsE
+BszVqrfcOV6eb1n1ZeZ8mjxqyTtuuxIbpccNm4kEwH8EDPQvDTF0lnM4qjAYXJxp
+uBEgHVyQY2Y4s6aDtbvoZiTQ4+0YcS/2db4puesXO9UzlBuVgKh4ta8MrYFIhl5t
+V/U8t6/lXC82hyYuX5dNPhKQeScfZiW2VJZYyrVX+gRXyRuP0s9dB7q6G3o0kDCu
+a/H6Hqf59dLppWIJE6aJClCaxhI9B95UeDMg1+eL8nKjrWkgIt6bdNpXGF6CPHeP
+zVB+syvGwNdsYQBb313IpkkADoKtPb0PAK+3tC0Mm06fV/7ORq1/zLU2P8T5adxh
+iXQ7ZkkxO+UVSdIveppG+uCzQrL0n0UmtQLP8euVaXe36vbjq6qECB89r0YFon90
+BHCIuegU2PUFL8sBs8ln3BAG+2sdDslIoQCT1k0Ce7kGoRDubIH7mK+t7ahvZHlu
+jHaSopM+TIQYnwftvb4RVdwHhErHMovIoIirAZ50WALRNIUvMyWNi2uBwBLCyONY
+3DVIyudGERIDT7RXvryvBXplH4Aj3ubu+KSB7WAceHyFpP5GVPULR5m1tAuHAR+K
+-----END CERTIFICATE-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-crl.pem b/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-crl.pem
new file mode 100644
index 00000000000..df9445fbd13
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Public/CA-samba.example.com-crl.pem
@@ -0,0 +1,32 @@
+-----BEGIN X509 CRL-----
+MIIFdTCCAV0CAQEwDQYJKoZIhvcNAQELBQAwgcYxCzAJBgNVBAYTAlVTMRMwEQYD
+VQQIDApTYW1iYVN0YXRlMRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNh
+bWJhU2VsZlRlc3RpbmcxGjAYBgNVBAsMEUNBIEFkbWluaXN0cmF0aW9uMSAwHgYD
+VQQDDBdDQSBvZiBzYW1iYS5leGFtcGxlLmNvbTE1MDMGCSqGSIb3DQEJARYmY2Et
+c2FtYmEuZXhhbXBsZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20XDTE2MDMxODExNDQz
+OFoXDTM2MDMxMzExNDQzOFqgYjBgMDEGA1UdEgQqMCiBJmNhLXNhbWJhLmV4YW1w
+bGUuY29tQHNhbWJhLmV4YW1wbGUuY29tMB8GA1UdIwQYMBaAFEaHhsLnGc8WTAxi
+y3N//Y8Z5LVCMAoGA1UdFAQDAgEAMA0GCSqGSIb3DQEBCwUAA4IEAQDCY6ioFWXc
+znAwARBrMTLSu0eqm2gIK4luXEDM7w8875kGKfp6Xf+SVMpagQwNIWApDsVU59FO
+zGn7GSD6sRaV0FSNiio/XBxIuCLGUrOss6tcClrtpwt8Y/GLv3SMpMwtH0GRsP4w
+INrsUGxC/gh0njEcE6YXZH9QL+p4UBWwPvkFfAT3WijF2WLMCsI18ZPZ/q1ONkNt
+sb3Kr+lowxVbLb5B+YDqP6ncRe1U49l6A1Q/8s0SDDmBnhiMtwSy0rdAxJ5eD2Wn
+HlAkd/JS6xSR68XvG7fD6NrwHVZtGBNBZQvXJth/xS67ym2m36oGffO8w1z1/uxb
+Zmr9HQAomubfc5rKCMQV1fREgnJGtY0VsWpiBqHxIXMK/A4DGVWrcg4GB5h5DHZi
+bb62HjXrm8pQDMkRLS3smmnMbFrfuJ/2jH8hyfoSesQKcHGUJfF2UJh6yuGp8ud4
+uX4YTmb84u5UvrF848etp/Ij4l/qOJjj+C4rCt0CiPHetuMLhfLQuLt5JD220E38
+ESVi9cuj2cjPkpNoPOqqP8p5wOiJ7JZgrBLtZ/ha4gYyDiYqaX63Krp8uBJM2Kqa
+BGgI5aKNzb9aXZhuZaXoiF2hXu+pD0XzmQ3B11hXa7DRwXdQiUcW0K28o/Kfvvzk
+2jubHMiWt+NS8Jw7WeJjNB8rSNjWYGTgf/i8LNi8569AZH7q32wvm/KVUsB2MGAH
+HRXk/yiPW2l4nIKD6/kxHEViVVG0k14IxohhPa8XMqHSt5/sOdZoaD4/7MJ4ci3L
+DXAh/AoNTBhx0PSXGgfb0m8/pDykcdp6m6Ggf6Gzptu4iZroXC3rDMIkkvhKNX5c
+ZanlSgpwcqSr18SEyPjOAWGBoTDStmoVVH1pWgdyL/u6kB4/pEpypQfXJrIV+pjg
+EY6EQEZYtv1h2doJ2K9XkFDE0nPyw0QvdgAWqDTdOCaUhmTL2QbDdcjViV65cXwk
+XyDq8C6aGYLz6Qqi2wzJRyGYfKBC7kDNvB5DIHC4ByFy5oEwm5fDWTkQcJ6hOHeh
+of3zYCts39/dBD90jFFlM3dmSzUNCKJDaO6sudF1BuT1OfjnH6ABSkMfklNbqvKc
+iAnDkmRt1edr3SUyA7RiBsJ4bTjs3YPbvN+zBEOIuRRi0OC8iO9zGG+2nFKtjTzd
+Kz4JdSiGkcNTWoYBDqdiwUvPDDLT5nqO4XDC+1fHST0cy1IP1ggSRh1+YsBZbUnF
+11gHE6WuMoRIQelLqiGjZhXrO8nB2dwu1uR70z2S1zI/Om5B7z/vREDZqewkht9U
+YLmlkGMdhTdMmon9yVkXGEi6va/kyi24O81nJE7cyUnySoKp43zvpr5dZjbtUP0a
+qcBp6pW4976r
+-----END X509 CRL-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-cert.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-cert.pem
new file mode 100644
index 00000000000..223d4072ce4
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-cert.pem
@@ -0,0 +1,170 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 3 (0x3)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+ Validity
+ Not Before: Mar 18 11:46:04 2016 GMT
+ Not After : Mar 13 11:46:04 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Users, CN=administrator@plugindom.samba.example.com/emailAddress=administrator@plugindom.samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bc:1c:03:de:e6:1e:17:1a:85:5b:13:b8:a9:b1:
+ 26:36:b2:7c:4e:d2:8a:3f:20:37:ea:57:f6:46:38:
+ 9e:86:26:cd:73:cc:6d:a6:a1:4e:21:29:89:f0:7e:
+ 75:a5:8d:5f:92:42:9d:88:81:21:66:8c:2f:1b:f5:
+ 14:54:6b:ed:18:c9:a7:a6:a7:16:07:10:27:77:31:
+ d4:90:a5:cd:a2:9c:96:c0:18:92:76:f9:12:40:ec:
+ 51:54:12:36:ce:c5:02:fd:9e:b9:80:4c:81:e9:7e:
+ 5b:59:2d:4a:7c:0a:35:0c:0f:85:a0:b9:93:23:77:
+ 35:8b:de:18:e7:5d:3e:25:27:cc:0e:f0:0f:ab:40:
+ a5:08:02:84:f1:cf:9b:66:37:12:37:02:4c:03:43:
+ 04:d5:a9:ad:6e:d2:88:c4:85:fa:f3:9f:f2:5d:6d:
+ 1f:f4:54:a1:d7:4a:93:c5:42:e9:cb:da:ff:bd:70:
+ 8b:27:75:4d:77:b0:ea:97:f1:80:75:84:57:5e:1e:
+ e5:a5:d9:89:28:e8:44:a0:77:66:08:64:51:c0:4a:
+ d0:06:c7:b1:b4:1e:6b:0a:94:a0:61:5a:9e:7b:5b:
+ d6:48:ab:1e:7e:65:43:d9:e0:91:51:f5:2b:43:99:
+ a1:94:bb:7f:aa:2b:e9:54:69:c4:e3:f1:e0:38:77:
+ 9f:f9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+ Netscape Cert Type:
+ SSL Client, S/MIME
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Key Encipherment
+ Netscape Comment:
+ Smart Card Login Certificate for administrator@plugindom.samba.example.com
+ X509v3 Subject Key Identifier:
+ 1D:D6:74:30:69:F7:2D:5F:81:E4:83:F1:7E:B0:08:F3:9C:06:41:E4
+ X509v3 Authority Key Identifier:
+ keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42
+
+ X509v3 Subject Alternative Name:
+ email:administrator@plugindom.samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com@samba.example.com
+ Netscape CA Revocation Url:
+ http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+ X509v3 Extended Key Usage:
+ TLS Web Client Authentication, scardLogin
+ Signature Algorithm: sha256WithRSAEncryption
+ 2c:23:ad:2f:a2:83:57:e8:42:b3:27:43:7f:aa:9d:99:ae:9d:
+ 20:7f:0a:b0:f4:32:33:ad:ee:fe:33:aa:20:09:8e:4b:4b:0d:
+ 12:b1:d5:0c:29:bc:13:aa:04:49:ce:2c:b7:01:e7:68:e9:ef:
+ 77:a9:dd:b6:9a:0a:11:bf:88:46:0c:09:7b:ac:6b:ed:6a:8e:
+ 72:fc:d8:28:46:21:48:8f:27:04:67:2c:17:2b:33:f7:8c:18:
+ ca:c6:3d:0e:76:36:fe:6b:03:77:eb:97:28:a9:64:4b:46:32:
+ 38:23:f5:6f:d9:43:b6:4e:c6:b5:14:0c:c5:09:0c:55:94:06:
+ 92:26:10:66:44:90:64:fa:e8:ae:75:43:a0:bd:14:9a:31:37:
+ 87:30:b7:61:87:65:40:b7:c1:2e:94:4c:0a:ed:4c:c2:75:2d:
+ 60:57:f9:b3:cf:b2:ef:19:c3:96:a6:25:d3:1d:92:16:9e:af:
+ e4:e4:ca:87:77:4b:13:31:48:de:99:1a:9c:ea:9a:27:96:bc:
+ 16:48:af:83:41:8c:56:d4:9c:6f:c5:9a:31:c9:35:3a:a5:c9:
+ cc:7f:9f:3d:c2:56:03:6b:df:b3:ac:c0:47:ce:53:5c:bd:38:
+ 7d:57:d4:c3:59:c9:b7:0a:89:ac:c2:15:a4:4d:50:84:67:91:
+ 59:6d:28:a1:78:0c:2e:20:39:06:9d:0c:2d:a7:c4:dc:98:eb:
+ 4f:b4:58:6d:6a:ba:b0:5a:e9:87:7f:c9:11:a5:7c:b7:91:49:
+ f5:0a:e7:f9:c9:7c:ba:30:3d:95:a7:8a:66:47:ed:49:53:74:
+ 85:e3:63:d5:38:34:76:e7:3e:2c:74:b6:58:23:5b:93:be:eb:
+ b2:98:9c:7e:bd:0e:5f:fa:98:4d:76:13:b7:5d:22:bc:76:5b:
+ 13:88:8d:84:8b:fc:a4:25:99:82:3b:1e:2e:58:2a:8f:d7:36:
+ ec:fb:d6:1e:76:b8:0a:31:fa:56:18:38:96:d5:0e:d7:dd:ac:
+ 70:a6:c1:80:0e:9c:9b:44:e7:e8:b6:8a:64:8d:7c:9c:57:6a:
+ 90:ce:2b:c1:c6:da:f5:68:1d:c4:37:58:70:f7:ba:3d:4f:2e:
+ 6c:a6:a2:3b:12:1e:1c:ea:99:bb:ac:54:57:18:c0:d3:7f:8a:
+ c8:7e:73:8e:b1:06:6b:55:57:e3:4f:46:9e:db:50:55:1d:c9:
+ 61:99:de:31:79:75:bc:b1:d6:fe:17:b2:fd:cb:36:3a:12:6b:
+ 0f:c8:b0:a6:be:e1:a4:de:5b:76:02:bc:e4:9b:f9:df:e1:ed:
+ bb:dc:40:62:1b:05:34:c0:53:10:47:ac:c7:18:6e:7c:17:37:
+ 86:f3:84:91:17:00:f3:69:45:3f:fe:fe:3c:c6:b2:13:82:70:
+ fa:fc:1b:51:d0:56:19:b0:9e:9f:1d:27:75:27:81:f1:85:b2:
+ 15:7f:ac:f1:8d:de:fe:3a:57:0f:13:4f:d8:7c:9d:f3:49:a2:
+ fe:5a:e8:91:8c:38:c2:4b:9a:f3:49:0c:92:70:62:8e:ed:91:
+ 8a:3e:da:ab:96:d6:46:5f:25:e6:82:cd:29:03:20:83:3b:63:
+ c2:5b:34:92:12:98:13:b4:56:2d:1d:cf:4b:22:f8:40:fb:7f:
+ ae:3e:49:52:54:de:02:95:0a:f2:22:6f:e1:2c:bd:a4:08:8d:
+ ec:83:79:4a:a8:ee:27:0e:b8:6a:65:4f:ba:be:8a:94:02:ad:
+ ef:72:3e:07:52:52:51:58:6c:e7:20:e4:81:49:da:7f:f1:dd:
+ ea:2b:56:f4:29:75:16:df:b8:19:da:63:b2:a0:d3:93:5d:a6:
+ 81:f4:2d:d3:fb:cb:7c:e3:04:8e:38:9d:66:9d:29:57:28:22:
+ e3:7a:5b:48:cf:6e:79:32:24:6e:e4:dc:7a:05:22:2c:a4:0e:
+ 30:74:41:cd:34:ef:3d:33:4e:01:3e:65:25:01:cc:5d:73:5a:
+ 10:d6:df:45:24:93:69:fa:d3:ab:7f:c8:b7:5a:86:1c:88:be:
+ 32:05:2f:f8:2a:26:02:f5:cc:30:4a:dd:97:0a:3a:db:c0:0c:
+ 67:36:90:9b:f9:2c:e3:d0:04:26:46:c1:a3:4e:a0:46:be:f3:
+ 8b:91:9c:d5:f0:32:09:c5:f0:a3:51:bf:05:70:83:51:25:ba:
+ 6f:8c:25:ea:30:96:52:e6:53:64:38:ac:0e:de:54:e7:5f:da:
+ 30:e0:39:9b:d8:64:d5:3b:70:4f:9a:27:96:36:98:9b:f5:07:
+ 0b:4a:89:40:06:18:9d:6d:e2:6c:40:51:af:83:66:73:87:56:
+ 5c:fa:38:96:a8:dd:4a:28:4a:82:d2:09:0f:e4:77:db:09:ff:
+ 50:34:c9:dc:0e:27:fe:94:1d:65:71:56:59:19:1d:62:a2:1a:
+ 93:bc:25:7b:be:6e:06:2a:e6:ce:ef:fa:cf:30:a2:e6:ce:26:
+ 28:e5:eb:6e:03:64:3c:8f:65:ce:32:33:08:ab:dc:45:69:78:
+ 4e:d3:b5:87:4f:03:48:e0:c3:24:48:cf:74:79:62:1e:b1:e0:
+ 39:12:02:08:db:fe:f8:78:a7:43:7f:e1:e8:86:b4:04:3c:e1:
+ fe:26:71:75:9d:32:4c:3a:ad:84:cb:e6:be:f5:7f:20:9d:04:
+ 4f:ba:41:d1:78:4d:f7:3a:93:89:ef:a4:4e:b4:83:4c:92:70:
+ 39:1d:21:de:c8:4c:9b:5d:26:55:1b:ad:93:48:79:19
+-----BEGIN CERTIFICATE-----
+MIIJLzCCBRegAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTgxMTQ2MDRaFw0zNjAzMTMxMTQ2MDRaMIG7MQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEOMAwGA1UE
+CwwFVXNlcnMxMjAwBgNVBAMMKWFkbWluaXN0cmF0b3JAcGx1Z2luZG9tLnNhbWJh
+LmV4YW1wbGUuY29tMTgwNgYJKoZIhvcNAQkBFilhZG1pbmlzdHJhdG9yQHBsdWdp
+bmRvbS5zYW1iYS5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALwcA97mHhcahVsTuKmxJjayfE7Sij8gN+pX9kY4noYmzXPMbaahTiEp
+ifB+daWNX5JCnYiBIWaMLxv1FFRr7RjJp6anFgcQJ3cx1JClzaKclsAYknb5EkDs
+UVQSNs7FAv2euYBMgel+W1ktSnwKNQwPhaC5kyN3NYveGOddPiUnzA7wD6tApQgC
+hPHPm2Y3EjcCTANDBNWprW7SiMSF+vOf8l1tH/RUoddKk8VC6cva/71wiyd1TXew
+6pfxgHWEV14e5aXZiSjoRKB3ZghkUcBK0AbHsbQeawqUoGFanntb1kirHn5lQ9ng
+kVH1K0OZoZS7f6or6VRpxOPx4Dh3n/kCAwEAAaOCAi8wggIrMAkGA1UdEwQCMAAw
+TwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3dy5zYW1iYS5leGFtcGxlLmNvbS9j
+cmxzL0NBLXNhbWJhLmV4YW1wbGUuY29tLWNybC5jcmwwEQYJYIZIAYb4QgEBBAQD
+AgWgMAsGA1UdDwQEAwIF4DBZBglghkgBhvhCAQ0ETBZKU21hcnQgQ2FyZCBMb2dp
+biBDZXJ0aWZpY2F0ZSBmb3IgYWRtaW5pc3RyYXRvckBwbHVnaW5kb20uc2FtYmEu
+ZXhhbXBsZS5jb20wHQYDVR0OBBYEFB3WdDBp9y1fgeSD8X6wCPOcBkHkMB8GA1Ud
+IwQYMBaAFEaHhsLnGc8WTAxiy3N//Y8Z5LVCMG8GA1UdEQRoMGaBKWFkbWluaXN0
+cmF0b3JAcGx1Z2luZG9tLnNhbWJhLmV4YW1wbGUuY29toDkGCisGAQQBgjcUAgOg
+KwwpYWRtaW5pc3RyYXRvckBwbHVnaW5kb20uc2FtYmEuZXhhbXBsZS5jb20wMQYD
+VR0SBCowKIEmY2Etc2FtYmEuZXhhbXBsZS5jb21Ac2FtYmEuZXhhbXBsZS5jb20w
+TQYJYIZIAYb4QgEEBEAWPmh0dHA6Ly93d3cuc2FtYmEuZXhhbXBsZS5jb20vY3Js
+cy9DQS1zYW1iYS5leGFtcGxlLmNvbS1jcmwuY3JsMB8GA1UdJQQYMBYGCCsGAQUF
+BwMCBgorBgEEAYI3FAICMA0GCSqGSIb3DQEBCwUAA4IEAQAsI60vooNX6EKzJ0N/
+qp2Zrp0gfwqw9DIzre7+M6ogCY5LSw0SsdUMKbwTqgRJziy3Aedo6e93qd22mgoR
+v4hGDAl7rGvtao5y/NgoRiFIjycEZywXKzP3jBjKxj0Odjb+awN365coqWRLRjI4
+I/Vv2UO2Tsa1FAzFCQxVlAaSJhBmRJBk+uiudUOgvRSaMTeHMLdhh2VAt8EulEwK
+7UzCdS1gV/mzz7LvGcOWpiXTHZIWnq/k5MqHd0sTMUjemRqc6ponlrwWSK+DQYxW
+1JxvxZoxyTU6pcnMf589wlYDa9+zrMBHzlNcvTh9V9TDWcm3ComswhWkTVCEZ5FZ
+bSiheAwuIDkGnQwtp8TcmOtPtFhtarqwWumHf8kRpXy3kUn1Cuf5yXy6MD2Vp4pm
+R+1JU3SF42PVODR25z4sdLZYI1uTvuuymJx+vQ5f+phNdhO3XSK8dlsTiI2Ei/yk
+JZmCOx4uWCqP1zbs+9YedrgKMfpWGDiW1Q7X3axwpsGADpybROfotopkjXycV2qQ
+zivBxtr1aB3EN1hw97o9Ty5spqI7Eh4c6pm7rFRXGMDTf4rIfnOOsQZrVVfjT0ae
+21BVHclhmd4xeXW8sdb+F7L9yzY6EmsPyLCmvuGk3lt2Arzkm/nf4e273EBiGwU0
+wFMQR6zHGG58FzeG84SRFwDzaUU//v48xrITgnD6/BtR0FYZsJ6fHSd1J4HxhbIV
+f6zxjd7+OlcPE0/YfJ3zSaL+WuiRjDjCS5rzSQyScGKO7ZGKPtqrltZGXyXmgs0p
+AyCDO2PCWzSSEpgTtFYtHc9LIvhA+3+uPklSVN4ClQryIm/hLL2kCI3sg3lKqO4n
+DrhqZU+6voqUAq3vcj4HUlJRWGznIOSBSdp/8d3qK1b0KXUW37gZ2mOyoNOTXaaB
+9C3T+8t84wSOOJ1mnSlXKCLjeltIz255MiRu5Nx6BSIspA4wdEHNNO89M04BPmUl
+Acxdc1oQ1t9FJJNp+tOrf8i3WoYciL4yBS/4KiYC9cwwSt2XCjrbwAxnNpCb+Szj
+0AQmRsGjTqBGvvOLkZzV8DIJxfCjUb8FcINRJbpvjCXqMJZS5lNkOKwO3lTnX9ow
+4Dmb2GTVO3BPmieWNpib9QcLSolABhidbeJsQFGvg2Zzh1Zc+jiWqN1KKEqC0gkP
+5HfbCf9QNMncDif+lB1lcVZZGR1iohqTvCV7vm4GKubO7/rPMKLmziYo5etuA2Q8
+j2XOMjMIq9xFaXhO07WHTwNI4MMkSM90eWIeseA5EgII2/74eKdDf+HohrQEPOH+
+JnF1nTJMOq2Ey+a+9X8gnQRPukHReE33OpOJ76ROtINMknA5HSHeyEybXSZVG62T
+SHkZ
+-----END CERTIFICATE-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-key.pem
new file mode 100644
index 00000000000..f0c97b7cc7f
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIywzM9NUqYIYCAggA
+MBQGCCqGSIb3DQMHBAg/PHGo9J8k2ASCBMgInucWaWmW19O/FNVi2NqcCenKvxfb
+rM1b9KigeRKo1GABmMVen0Ugy5A4YxIF9nrjCYjI+eDfsZjLaP5Fzn3Nt7/eX1bV
+dvKK3N4Zwks0SuMtksyYs2wshT86dVjnHbIXC5p9cJFjPEyxSp/M77ypQnmqTwDM
+2GhYQywPoOQ8b3JwhAREevJnbA6bQw79E/9NzmtrhXJkvahqLWkNGR0yPx9iH0tN
+9qfPP5Svz8un8cHlulb2VoY9BgsoxG0AO9V62slwX3WRv7BKtkyM8E0HXD3sBSNB
+fpt1FhqFW2nQM9F0gikA6LIh4QYBd5c5zMDF1FW5kbFp5OTQaUEvIKw3TTHXQdhs
+bnXfiJ6DxdIdeSubOGP3RxRv9gLmSYMq9UqyVQM4jHKsDMA2RLSj5yc6DTUGYe3a
+OHNk4v0mNLLvW9VJTkoQrnSpr2Px1ZIB2uTBY4+1VV3eALtZTTvW9cJmV7uaPirJ
+gEAQMY2uWHJTOPqzDdB1RwAB3P46b208nPgWuW/DG2+NFhnkGxQGceITRSIc9StF
+icJtVeYPTgOuVsV01V1SrdpgtUg2sEXCfJKWxHROXkFnf0lxibC1m1gRiaLMDHkZ
+sFDPgBpNuGNcf5wtqDxBTwiRhsgwqtMRtXLTzNxh7VDUIXnu4CrwD4Pcmeul/qnd
+5hrHyz7MF0ZUep0IkcR0O3ullo09Ayptsaxv8xcSjKPP7Kt8U1h7YQie/hVQ5roi
+Uhjf1PeaNtIsZtrf0nJnrbj4yY/ZdIXP8uVDWT0+GCDW055cEw6XfTdsRdMzMQqc
+ZfpR7kh2quAuvTzVVzrHve+bVB/AmHXJr1MKPLS7wfyaqESCbVmP+9k7bybjwCKU
+LlPuQVFFtE7ZBSgzkORTfjIMSY0XwISzZY8clowrkHU/ATj6MTZo5mWq18ddEBl3
+3dbUHqM8g9BnSd0oOXORQqInZY1G0U2+O/AJB6haaQAI2LBeSqf0GH+5BU9Ty7wH
+QEfQaQLnwTG3gwugluYTSjn1K9SiHptDHfNxBnCPOflm2PriDAvkylgnHHIRjbsn
+PnC/Wn0QiVUvP4WuVb+p0cfR7s0f6diBuaWaWY6acd0vbrXqs1qp78sqKZ1qVCMA
+FJ+S8IJmu4q9Up92XiyWgMQWi/oa2u9HoNh1K9+LMrXiEnson0VJlCy+SQ+QxTpK
+rOp0bThlqaZF9VYSoawfGiLjbwr2rh8fJ/1bIENy0sIyWvPyRFyl63ku9nI46Ze+
+qQFiG9GRURzRCjyhDZIWJT4F6m65o5LoKFeFTi2WwAV9UK744F06SxsIGHNMm5EV
+iXLIkipWqGJZ/UUEv3vleirud0STQFpp2NYBIGNtEH1LbhjIeF0rALx8+lnPx54F
+atNh52qKkiz/VMBnZ/q/z3+qK9G4ou4b/AB4xzPOQUMLUQ3/aiJciFGRpBCm5QTn
+bnO0IiCpLIgQu6rmEJ59iF5pbujMFXgF5W9DdxvSSvWhsRgu1+V9vUVfR7h9HXc3
+hIglijRDwVSzlvuVslMLtmy+fkzzezFvsmgRPy6t5dGpqmvfGel/wC6m3kQ+0IHt
+t/GUTgPoVS52YhB4xurMsGLYQbjuLnnZ8rc/2O7ciqHhW0tB40D04L6Ap7rCLuqK
+oRY=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-openssl.cnf
new file mode 100644
index 00000000000..8016fb3535b
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-openssl.cnf
@@ -0,0 +1,242 @@
+#
+# Based on the OpenSSL example configuration file.
+# This is mostly being used for generation of certificate requests.
+#
+
+# This definition stops the following lines choking if HOME isn't
+# defined.
+HOME = .
+RANDFILE = $ENV::HOME/.rnd
+
+#CRLDISTPT = [CRL Distribution Point; e.g., http://crl-list.base/w4edom-l4.base.crl]
+CRLDISTPT = http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+# Extra OBJECT IDENTIFIER info:
+oid_section = new_oids
+
+# To use this configuration file with the "-extfile" option of the
+# "openssl x509" utility, name here the section containing the
+# X.509v3 extensions to use:
+# extensions =
+# (Alternatively, use a configuration file that has only
+# X.509v3 extensions in its main [= default] section.)
+
+[ new_oids ]
+# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used as a login credential
+scardLogin=1.3.6.1.4.1.311.20.2.2
+# Used in a smart card login certificate's subject alternative name
+msUPN=1.3.6.1.4.1.311.20.2.3
+# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used to identify a domain controller
+msKDC=1.3.6.1.5.2.3.5
+# Identifies the AD GUID
+msADGUID=1.3.6.1.4.1.311.25.1
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = CA-samba.example.com # Where everything is kept
+certs = $dir/_none_certs # Where the issued certs are kept
+crl_dir = $dir/_none_crl # Where the issued crl are kept
+database = $dir/Private/CA-samba.example.com-index.txt # database index file.
+unique_subject = yes # Set to 'no' to allow creation of
+ # several certificates with same subject.
+new_certs_dir = $dir/NewCerts # default place for new certs.
+
+certificate = $dir/Public/CA-samba.example.com-cert.pem # The CA certificate
+serial = $dir/Private/CA-samba.example.com-serial.txt # The current serial number
+crlnumber = $dir/Private/CA-samba.example.com-crlnumber.txt # the current crl number
+ # must be commented out to leave a V1 CRL
+
+#crl = $dir/Public/CA-samba.example.com-crl.pem # The current CRL
+crl = $dir/Public/CA-samba.example.com-crl.crl # The current CRL
+private_key = $dir/Private/CA-samba.example.com-private-key.pem # The private key
+RANDFILE = $dir/Private/CA-samba.example.com.rand # private random number file
+
+#x509_extensions = # The extensions to add to the cert
+x509_extensions = template_x509_extensions
+
+# Comment out the following two lines for the "traditional"
+# (and highly broken) format.
+name_opt = ca_default # Subject Name options
+cert_opt = ca_default # Certificate field options
+
+# Extension copying option: use with caution.
+# copy_extensions = copy
+
+# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
+# so this is commented out by default to leave a V1 CRL.
+# crlnumber must also be commented out to leave a V1 CRL.
+crl_extensions = crl_ext
+
+default_days = 7300 # how long to certify for
+default_crl_days= 7300 # how long before next CRL
+default_md = sha256 # use public key default MD
+preserve = no # keep passed DN ordering
+
+# A few difference way of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+# For the 'anything' policy
+# At this point in time, you must list all acceptable 'object'
+# types.
+[ policy_anything ]
+countryName = match
+stateOrProvinceName = match
+localityName = match
+organizationName = match
+organizationalUnitName = match
+commonName = supplied
+emailAddress = supplied
+
+####################################################################
+[ req ]
+default_bits = 2048
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extensions to add to the self signed cert
+
+# Passwords for private keys if not present they will be prompted for
+# input_password = secret
+# output_password = secret
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString (PKIX recommendation before 2004)
+# utf8only: only UTF8Strings (PKIX recommendation after 2004).
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings.
+string_mask = utf8only
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = US
+countryName_min = 2
+countryName_max = 2
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = SambaState
+
+localityName = Locality Name (eg, city)
+localityName_default = SambaCity
+
+organizationName = Organization Name (eg, company)
+organizationName_default = SambaSelfTesting
+
+organizationalUnitName = Organizational Unit Name (eg, section)
+organizationalUnitName_default = Users
+
+commonName = Common Name (eg, YOUR name)
+commonName_default = administrator@plugindom.samba.example.com
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_default = administrator@plugindom.samba.example.com
+emailAddress_max = 64
+
+# SET-ex3 = SET extension number 3
+
+[ req_attributes ]
+#challengePassword = A challenge password
+#challengePassword_min = 4
+#challengePassword_max = 20
+#
+#unstructuredName = An optional company name
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+[ v3_ca ]
+# Extensions for a typical CA
+# PKIX recommendation.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer
+
+# This is what PKIX recommends but some broken software chokes on critical
+# extensions.
+#basicConstraints = critical,CA:true
+# So we do this instead.
+basicConstraints = CA:true
+
+# Key usage: this is typical for a CA certificate.
+keyUsage = cRLSign, keyCertSign
+
+crlDistributionPoints=URI:$CRLDISTPT
+
+# Some might want this also
+nsCertType = sslCA, emailCA
+
+# Include email address in subject alt name: another PKIX recommendation
+subjectAltName=email:copy
+# Copy issuer details
+issuerAltName=issuer:copy
+
+[ crl_ext ]
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always
+
+#[ usr_cert_scarduser ]
+[ template_x509_extensions ]
+
+# These extensions are added when 'ca' signs a request for a certificate that will be used to login from a smart card
+
+# This goes against PKIX guidelines but some CAs do it and some software
+# requires this to avoid interpreting an end user certificate as a CA.
+
+basicConstraints=CA:FALSE
+crlDistributionPoints=URI:$CRLDISTPT
+
+# For normal client use this is typical
+nsCertType = client, email
+
+# This is typical in keyUsage for a client certificate.
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+# This will be displayed in Netscape's comment listbox.
+nsComment = "Smart Card Login Certificate for administrator@plugindom.samba.example.com"
+
+# PKIX recommendations harmless if included in all certificates.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+
+# This stuff is for subjectAltName and issuerAltname.
+
+subjectAltName=email:copy,otherName:msUPN;UTF8:administrator@plugindom.samba.example.com
+
+# Copy subject details
+issuerAltName=issuer:copy
+
+nsCaRevocationUrl = $CRLDISTPT
+#nsBaseUrl
+#nsRevocationUrl
+#nsRenewalUrl
+#nsCaPolicyUrl
+#nsSslServerName
+
+#Extended Key requirements for client certs
+extendedKeyUsage = clientAuth,scardLogin
+
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-private-key.pem
new file mode 100644
index 00000000000..a68aaac7bee
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-private-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAvBwD3uYeFxqFWxO4qbEmNrJ8TtKKPyA36lf2RjiehibNc8xt
+pqFOISmJ8H51pY1fkkKdiIEhZowvG/UUVGvtGMmnpqcWBxAndzHUkKXNopyWwBiS
+dvkSQOxRVBI2zsUC/Z65gEyB6X5bWS1KfAo1DA+FoLmTI3c1i94Y510+JSfMDvAP
+q0ClCAKE8c+bZjcSNwJMA0ME1amtbtKIxIX685/yXW0f9FSh10qTxULpy9r/vXCL
+J3VNd7Dql/GAdYRXXh7lpdmJKOhEoHdmCGRRwErQBsextB5rCpSgYVqee1vWSKse
+fmVD2eCRUfUrQ5mhlLt/qivpVGnE4/HgOHef+QIDAQABAoIBABUKwTgW37jP46j7
+fMWmplKqBpO+o25KSVbyff7+6GSzRHo2nPFty9KT1fVMABcDyHQQ9ZRGdZkGB2MG
+OD71T7FdJV7UA/fIS9HehhukIGuXPpnAZenfFLakeLiBzRW2Hg6GydNbO5EF7Gv+
+T/2uGp79wYHoIFhwRlIeBwUifggjyWuLFproK+JGLtzNLEWnn12k/5oSbXTYOcvJ
+mPKGe0XmBMtY8IqlH6BLi04XFWBFT+DE+U0Yx9OzrRi51srq4+acpX06GiaH2Q3E
+J61gr4e2EcDf6AJiz+jihLLBrVgTFda+eldoRyS2eG8EPsD/O7jakiBbKuCIDWwo
+YZnOrYECgYEA3gxYEohP1P/B9D8cSOBYOhwZL3aZBXnWMACup0ppJBWlDkUvNUJa
+ScVZJuj7s6zPp1boWMjfQvfX8q4M7gC3mccotnYGR4zRm1iDbYuUUBmM1ChQ6Cks
+nZRcvYskTOl+ja+aULEde/I6/kYIQFUWyYR6UmKHxXcV0Co9I0DcnVECgYEA2N8z
+qGuVHpZOJPhCod4eFXxKUh1WYUzkMcH4RlJ/h+Y2BYkUDSQb26KBur7KvVHmJm1G
+28zBqLS76/3nha8XuHlLmHnD+6R4LEe8d4sm7RHJWgQMzvrnqle30Db2hBK0dwNI
+JkI9zzQZv7FIqT0DHZ8aWKc+D2luJdDdbboIDikCgYEAh5b8FNz9+q/ubMo46Ftu
+JJXR30TJbimW3Bsei3MJvwokjxE6IYiR/6gtp2/veykUaDfOi6CljIwxZrRXmuH/
+Ozz9JGXvsbNQr06eer8X4s2nTEoOFaZG4zacZvXXRcvzBmvrjEiLG4uv8GMtWLNc
+xdNKqpIWHEN6o3GXgbZywPECgYEAuWbfh70pR3PhrHNcq3rzJxURiG+yOA5/Cxaz
+RJMkma6yQjs1HCLhefvMgjS3p/ALHJDRQfkjGjIgcZinxD6yva9cdCas6EVrwxc0
+xNH+Xi+VflH2DUCsqpDBAMzsJG7FPvVcSfDZXHlDBgDuiFgzgLBS2rVnNc/BLa0I
+j9S5LDkCgYA8Cz5qcVfTU8QoS2ZrYxzLJM7m2h+BwLTaFtV8Gu0nkPQXT/Wa9QJj
+h6eFGIYRvImNe0ASurTqDqQBmmWsFK9SofuPOGW8T+nBm+3ApjtTxev1zugV9YXO
+cc2Opy84+OYqE4prg+qxg8/zgNtUF6IQ+LDB7AXS3FJGCyeCSMmILg==
+-----END RSA PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-req.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-req.pem
new file mode 100644
index 00000000000..0e58e9aa66f
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-S03-req.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIDFTCCAf0CAQAwgc8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTYW1iYVN0YXRl
+MRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNhbWJhU2VsZlRlc3Rpbmcx
+DjAMBgNVBAsMBVVzZXJzMTIwMAYDVQQDDClhZG1pbmlzdHJhdG9yQHBsdWdpbmRv
+bS5zYW1iYS5leGFtcGxlLmNvbTE4MDYGCSqGSIb3DQEJARYpYWRtaW5pc3RyYXRv
+ckBwbHVnaW5kb20uc2FtYmEuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQC8HAPe5h4XGoVbE7ipsSY2snxO0oo/IDfqV/ZGOJ6GJs1z
+zG2moU4hKYnwfnWljV+SQp2IgSFmjC8b9RRUa+0YyaempxYHECd3MdSQpc2inJbA
+GJJ2+RJA7FFUEjbOxQL9nrmATIHpfltZLUp8CjUMD4WguZMjdzWL3hjnXT4lJ8wO
+8A+rQKUIAoTxz5tmNxI3AkwDQwTVqa1u0ojEhfrzn/JdbR/0VKHXSpPFQunL2v+9
+cIsndU13sOqX8YB1hFdeHuWl2Yko6ESgd2YIZFHAStAGx7G0HmsKlKBhWp57W9ZI
+qx5+ZUPZ4JFR9StDmaGUu3+qK+lUacTj8eA4d5/5AgMBAAGgADANBgkqhkiG9w0B
+AQsFAAOCAQEADZFjHLUC/AZU07Ax6GmjmSvP4OIxFm3NWS6OSD3a1MrPN/v6IGBl
+joVTlMpIrVFg2/iXZnLSJechq9HFDJ7wyeIX+QgFwuTDG1cfH7Ji5Xk3HgN2oVyD
+Eea02tTbTOLVGJk27yFJaKCmpGJ3mKiOBFmfZRXitE15hEvOMXVkJVR2FtxxW0fk
+PLYDX74e4fLFZUCgmOh47Seuc0bZk4pLROAaUhxFPOuLiLs//YbdkY8LLz6MYXdv
+ia08JhcEq6zbrPPvTxRtGTFHWSJUhpOkEroRfeT/8vgirwnGLlkeLXIL5l7iyUi+
+3Z01Qrv/frJxsAgMaXdBB4YZES+Z/qoiNA==
+-----END CERTIFICATE REQUEST-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-cert.pem
new file mode 120000
index 00000000000..282971d3f6e
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-cert.pem
@@ -0,0 +1 @@
+USER-administrator@plugindom.samba.example.com-S03-cert.pem \ No newline at end of file
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-private-key.pem
new file mode 120000
index 00000000000..b3fec415305
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@plugindom.samba.example.com/USER-administrator@plugindom.samba.example.com-private-key.pem
@@ -0,0 +1 @@
+USER-administrator@plugindom.samba.example.com-S03-private-key.pem \ No newline at end of file
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-cert.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-cert.pem
new file mode 100644
index 00000000000..deb2b73f312
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-cert.pem
@@ -0,0 +1,169 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=SambaState, L=SambaCity, O=SambaSelfTesting, OU=CA Administration, CN=CA of samba.example.com/emailAddress=ca-samba.example.com@samba.example.com
+ Validity
+ Not Before: Mar 18 11:45:11 2016 GMT
+ Not After : Mar 13 11:45:11 2036 GMT
+ Subject: C=US, ST=SambaState, O=SambaSelfTesting, OU=Users, CN=administrator@samba.example.com/emailAddress=administrator@samba.example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c9:07:44:3a:5f:f6:34:5f:27:8a:7a:6e:2f:fb:
+ 45:1f:c3:3d:dd:2c:43:65:f1:7a:29:3f:42:26:bd:
+ ff:4f:5d:91:c0:bb:75:e3:81:14:7d:59:72:78:96:
+ 1a:5e:8d:95:93:f4:5d:92:79:0e:24:77:4f:8b:08:
+ 4e:72:b1:99:88:63:06:74:b2:dc:f7:82:62:e9:dd:
+ 6f:e5:a7:b4:c9:44:0c:e4:43:41:f8:57:a9:20:b1:
+ 70:c1:76:a1:48:5b:e9:54:b6:4f:22:50:93:90:f0:
+ 62:32:50:9a:6e:22:6b:37:a0:f7:1f:fc:b1:5f:ae:
+ e2:0b:88:6d:ea:29:b6:01:27:b2:84:ef:10:4d:6c:
+ 0a:df:ea:a9:8a:82:98:60:a7:52:73:a4:f7:7c:b2:
+ 4a:b9:f0:9b:c4:f8:19:5a:c0:84:54:52:35:c8:92:
+ 4f:16:af:d6:36:a6:78:57:55:e5:5e:6b:62:00:fa:
+ 48:c2:7a:e7:17:38:b5:23:d5:a8:fb:7d:df:42:5c:
+ 03:f4:7c:ef:ff:f1:a0:e6:d8:27:93:06:b3:a3:21:
+ 68:0e:c4:60:20:02:46:2f:2b:d8:88:e4:2b:01:c2:
+ 31:5a:55:28:be:55:03:f2:06:2b:e4:ec:48:60:e4:
+ b6:db:a1:f0:c5:24:ba:e1:a8:e2:6a:fb:0b:40:6c:
+ 3d:f5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+ Netscape Cert Type:
+ SSL Client, S/MIME
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Key Encipherment
+ Netscape Comment:
+ Smart Card Login Certificate for administrator@samba.example.com
+ X509v3 Subject Key Identifier:
+ 70:86:EC:68:B4:51:8A:1C:12:65:A0:2A:B3:43:33:12:65:83:8D:40
+ X509v3 Authority Key Identifier:
+ keyid:46:87:86:C2:E7:19:CF:16:4C:0C:62:CB:73:7F:FD:8F:19:E4:B5:42
+
+ X509v3 Subject Alternative Name:
+ email:administrator@samba.example.com, othername:<unsupported>
+ X509v3 Issuer Alternative Name:
+ email:ca-samba.example.com@samba.example.com
+ Netscape CA Revocation Url:
+ http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+ X509v3 Extended Key Usage:
+ TLS Web Client Authentication, scardLogin
+ Signature Algorithm: sha256WithRSAEncryption
+ 5d:b1:10:f8:36:dd:a9:fd:8d:be:31:53:1d:cf:b5:ea:33:1a:
+ 85:0f:13:8d:cc:67:91:41:97:e4:e9:67:6a:0c:ce:a4:9a:06:
+ b3:53:bf:e6:6d:f1:d1:32:7d:54:5d:6a:a8:94:fe:d4:f6:62:
+ 85:0f:e0:73:f8:ce:51:32:18:65:50:34:f9:f2:66:f8:ec:fd:
+ 94:c2:1d:28:6f:ce:3c:b3:0a:0a:cc:8b:fb:2c:e8:44:d2:d8:
+ 64:d7:19:1c:a4:25:5f:75:63:bc:44:56:64:cb:ca:8c:43:75:
+ 1e:95:36:98:a1:c6:49:e6:14:60:ad:87:91:af:d8:3c:d2:63:
+ 52:82:02:0a:42:c0:e3:7b:50:51:37:d5:c0:a5:0c:09:ac:2d:
+ a0:b3:29:e4:9e:bf:d3:df:01:82:00:a5:ad:fb:35:e8:f6:1c:
+ d7:cb:d1:3c:54:1f:d2:73:38:ce:a6:0a:e2:77:0a:fc:e5:ff:
+ 7e:68:a6:c7:57:fd:c7:cf:95:48:9f:97:6f:fe:2e:9f:e3:d6:
+ b0:a5:b5:33:9f:12:c1:e6:12:15:77:33:8f:1e:35:b5:88:f8:
+ 6b:47:88:e4:cb:49:f7:11:ba:19:39:55:5e:4a:5a:65:76:7e:
+ cc:3a:a7:fa:91:9a:ef:b5:c1:bf:f0:e7:a2:c6:9f:08:17:fc:
+ 4c:a4:ef:0b:d8:c7:a4:f9:74:36:b3:67:90:5e:84:26:83:bd:
+ 36:89:0d:c6:8c:1d:03:ce:8f:80:c9:0c:c6:c0:1e:eb:42:e7:
+ 97:7f:21:ac:b1:64:06:f6:1d:6d:0c:87:ff:c9:30:23:d3:21:
+ 1f:53:05:69:21:d5:26:ca:7f:ce:3a:4e:8d:d1:40:16:7e:a2:
+ c0:0f:95:0c:67:90:47:d2:e2:cf:87:ef:dc:35:18:2a:a2:21:
+ cd:67:b0:b2:14:9f:75:94:93:ba:8c:4d:45:71:cb:e9:df:cd:
+ f5:e3:f0:ff:c3:38:77:c2:41:55:d6:60:96:d8:bd:5f:09:22:
+ 97:44:8d:4d:b1:dd:68:39:04:1b:7a:57:3b:ca:56:27:87:31:
+ 55:84:6c:f0:65:af:ec:0b:52:87:28:0b:2d:52:c0:ce:a3:7d:
+ 7b:47:07:df:8a:65:e9:6f:da:e7:b6:94:06:69:b8:55:3d:11:
+ 01:c6:bf:0b:61:1b:cc:30:47:ab:cf:fb:72:62:f3:eb:66:11:
+ cd:1c:ab:4e:29:bf:b7:78:d6:09:ec:d7:67:5b:17:b9:34:cc:
+ af:5e:d9:02:0b:33:fc:a1:f2:64:33:c4:af:11:5b:08:f7:af:
+ ba:0d:68:d7:cf:d2:40:2f:56:20:34:da:82:18:7c:0e:71:61:
+ a6:58:60:00:30:a6:c7:25:3a:90:70:a0:14:e6:da:d8:12:e9:
+ b3:6a:c4:96:85:41:80:a6:71:17:b5:cf:4f:a2:2d:51:93:fd:
+ 26:eb:44:3c:2a:84:6a:da:18:10:d6:48:e3:8e:0f:c9:69:05:
+ 96:8c:96:f9:74:06:ab:11:d2:e4:e5:d7:22:db:13:93:d6:f9:
+ 24:84:56:7c:6a:43:a9:b8:30:33:2c:a4:42:9f:ec:f6:56:2d:
+ 46:cf:ec:26:49:5e:da:53:21:6b:8c:05:0d:b7:12:26:29:43:
+ 32:b2:6c:ed:07:47:75:2b:0b:7e:5d:28:1b:5b:7b:b5:63:13:
+ 55:4d:f7:a3:f6:fd:2d:f5:6d:43:83:40:46:b3:0d:d6:28:99:
+ d4:fb:89:fb:41:c6:15:35:a5:ee:1a:08:33:b3:0b:75:0a:d0:
+ fc:31:ec:77:80:e2:f0:ab:20:cc:43:24:67:42:a5:d7:e6:b0:
+ b9:84:fd:43:a0:5e:d9:78:10:97:d3:d1:b7:d9:33:70:0f:4d:
+ f0:a1:ac:22:d7:36:53:68:6d:39:e0:14:dc:d7:ea:1e:c2:92:
+ 1b:f8:2a:99:97:14:76:2c:89:3f:b7:89:c7:69:6e:5b:dd:8e:
+ 47:7a:f0:0e:a4:d0:18:c6:c4:34:f0:b8:84:3a:6e:ee:1e:7b:
+ 84:58:d2:10:a6:a2:0c:14:a8:55:e9:c5:7e:ab:97:e4:9d:b5:
+ f0:9f:2e:36:ac:2f:73:30:c8:b1:fc:b4:ce:b4:39:bd:59:75:
+ b8:24:5a:b1:67:de:34:3f:4e:17:5d:d3:bc:bb:6a:6a:b7:3e:
+ 0b:e8:4d:3b:08:d6:de:a7:9a:d7:8d:60:56:bb:3e:6c:d0:a7:
+ f8:45:a2:52:a3:b5:1e:ef:56:df:14:62:52:ed:36:ab:cc:7a:
+ a1:96:14:9a:e9:de:4a:28:68:bd:21:2d:60:d5:06:8a:e9:5e:
+ b6:ce:e1:b4:ed:56:9f:99:87:fe:20:bb:d5:8d:0d:72:1d:7e:
+ 88:27:9c:66:d5:26:aa:32:0a:ad:64:de:b8:13:2d:51:cc:8b:
+ e2:f4:c1:63:a6:64:e8:03:08:42:38:bf:f4:fe:b3:25:03:1b:
+ 14:b9:68:81:14:b9:5d:b9:6a:eb:f0:a9:24:41:8e:49:03:be:
+ 0b:55:cf:ac:77:68:ed:54:ae:55:40:dd:31:c4:3a:e2:d7:86:
+ d5:d5:e4:5e:5b:ce:9e:da:a1:90:58:e1:b3:7c:a6:87:15:bd:
+ 3a:67:b9:ab:29:de:4f:af:08:98:89:45:62:8f:db:5b:2e:2b:
+ e8:97:35:a2:fc:4f:cf:63:7d:56:a0:51:dd:3f:b2:90:a6:9b:
+ a0:9b:9e:93:8d:9d:92:b2:ed:36:d5:e1:f1:e3:97:dc
+-----BEGIN CERTIFICATE-----
+MIII/TCCBOWgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBxjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMClNhbWJhU3RhdGUxEjAQBgNVBAcMCVNhbWJhQ2l0eTEZMBcGA1UE
+CgwQU2FtYmFTZWxmVGVzdGluZzEaMBgGA1UECwwRQ0EgQWRtaW5pc3RyYXRpb24x
+IDAeBgNVBAMMF0NBIG9mIHNhbWJhLmV4YW1wbGUuY29tMTUwMwYJKoZIhvcNAQkB
+FiZjYS1zYW1iYS5leGFtcGxlLmNvbUBzYW1iYS5leGFtcGxlLmNvbTAeFw0xNjAz
+MTgxMTQ1MTFaFw0zNjAzMTMxMTQ1MTFaMIGnMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKU2FtYmFTdGF0ZTEZMBcGA1UECgwQU2FtYmFTZWxmVGVzdGluZzEOMAwGA1UE
+CwwFVXNlcnMxKDAmBgNVBAMMH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5j
+b20xLjAsBgkqhkiG9w0BCQEWH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5j
+b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJB0Q6X/Y0XyeKem4v
++0Ufwz3dLENl8XopP0Imvf9PXZHAu3XjgRR9WXJ4lhpejZWT9F2SeQ4kd0+LCE5y
+sZmIYwZ0stz3gmLp3W/lp7TJRAzkQ0H4V6kgsXDBdqFIW+lUtk8iUJOQ8GIyUJpu
+Ims3oPcf/LFfruILiG3qKbYBJ7KE7xBNbArf6qmKgphgp1JzpPd8skq58JvE+Bla
+wIRUUjXIkk8Wr9Y2pnhXVeVea2IA+kjCeucXOLUj1aj7fd9CXAP0fO//8aDm2CeT
+BrOjIWgOxGAgAkYvK9iI5CsBwjFaVSi+VQPyBivk7Ehg5LbbofDFJLrhqOJq+wtA
+bD31AgMBAAGjggIRMIICDTAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECGPmh0
+dHA6Ly93d3cuc2FtYmEuZXhhbXBsZS5jb20vY3Jscy9DQS1zYW1iYS5leGFtcGxl
+LmNvbS1jcmwuY3JsMBEGCWCGSAGG+EIBAQQEAwIFoDALBgNVHQ8EBAMCBeAwTwYJ
+YIZIAYb4QgENBEIWQFNtYXJ0IENhcmQgTG9naW4gQ2VydGlmaWNhdGUgZm9yIGFk
+bWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5jb20wHQYDVR0OBBYEFHCG7Gi0UYoc
+EmWgKrNDMxJlg41AMB8GA1UdIwQYMBaAFEaHhsLnGc8WTAxiy3N//Y8Z5LVCMFsG
+A1UdEQRUMFKBH2FkbWluaXN0cmF0b3JAc2FtYmEuZXhhbXBsZS5jb22gLwYKKwYB
+BAGCNxQCA6AhDB9hZG1pbmlzdHJhdG9yQHNhbWJhLmV4YW1wbGUuY29tMDEGA1Ud
+EgQqMCiBJmNhLXNhbWJhLmV4YW1wbGUuY29tQHNhbWJhLmV4YW1wbGUuY29tME0G
+CWCGSAGG+EIBBARAFj5odHRwOi8vd3d3LnNhbWJhLmV4YW1wbGUuY29tL2NybHMv
+Q0Etc2FtYmEuZXhhbXBsZS5jb20tY3JsLmNybDAfBgNVHSUEGDAWBggrBgEFBQcD
+AgYKKwYBBAGCNxQCAjANBgkqhkiG9w0BAQsFAAOCBAEAXbEQ+Dbdqf2NvjFTHc+1
+6jMahQ8TjcxnkUGX5OlnagzOpJoGs1O/5m3x0TJ9VF1qqJT+1PZihQ/gc/jOUTIY
+ZVA0+fJm+Oz9lMIdKG/OPLMKCsyL+yzoRNLYZNcZHKQlX3VjvERWZMvKjEN1HpU2
+mKHGSeYUYK2Hka/YPNJjUoICCkLA43tQUTfVwKUMCawtoLMp5J6/098BggClrfs1
+6PYc18vRPFQf0nM4zqYK4ncK/OX/fmimx1f9x8+VSJ+Xb/4un+PWsKW1M58SweYS
+FXczjx41tYj4a0eI5MtJ9xG6GTlVXkpaZXZ+zDqn+pGa77XBv/DnosafCBf8TKTv
+C9jHpPl0NrNnkF6EJoO9NokNxowdA86PgMkMxsAe60Lnl38hrLFkBvYdbQyH/8kw
+I9MhH1MFaSHVJsp/zjpOjdFAFn6iwA+VDGeQR9Liz4fv3DUYKqIhzWewshSfdZST
+uoxNRXHL6d/N9ePw/8M4d8JBVdZglti9Xwkil0SNTbHdaDkEG3pXO8pWJ4cxVYRs
+8GWv7AtShygLLVLAzqN9e0cH34pl6W/a57aUBmm4VT0RAca/C2EbzDBHq8/7cmLz
+62YRzRyrTim/t3jWCezXZ1sXuTTMr17ZAgsz/KHyZDPErxFbCPevug1o18/SQC9W
+IDTaghh8DnFhplhgADCmxyU6kHCgFOba2BLps2rEloVBgKZxF7XPT6ItUZP9JutE
+PCqEatoYENZI444PyWkFloyW+XQGqxHS5OXXItsTk9b5JIRWfGpDqbgwMyykQp/s
+9lYtRs/sJkle2lMha4wFDbcSJilDMrJs7QdHdSsLfl0oG1t7tWMTVU33o/b9LfVt
+Q4NARrMN1iiZ1PuJ+0HGFTWl7hoIM7MLdQrQ/DHsd4Di8KsgzEMkZ0Kl1+awuYT9
+Q6Be2XgQl9PRt9kzcA9N8KGsItc2U2htOeAU3NfqHsKSG/gqmZcUdiyJP7eJx2lu
+W92OR3rwDqTQGMbENPC4hDpu7h57hFjSEKaiDBSoVenFfquX5J218J8uNqwvczDI
+sfy0zrQ5vVl1uCRasWfeND9OF13TvLtqarc+C+hNOwjW3qea141gVrs+bNCn+EWi
+UqO1Hu9W3xRiUu02q8x6oZYUmuneSihovSEtYNUGiulets7htO1Wn5mH/iC71Y0N
+ch1+iCecZtUmqjIKrWTeuBMtUcyL4vTBY6Zk6AMIQji/9P6zJQMbFLlogRS5Xblq
+6/CpJEGOSQO+C1XPrHdo7VSuVUDdMcQ64teG1dXkXlvOntqhkFjhs3ymhxW9Ome5
+qyneT68ImIlFYo/bWy4r6Jc1ovxPz2N9VqBR3T+ykKaboJuek42dkrLtNtXh8eOX
+3A==
+-----END CERTIFICATE-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-key.pem
new file mode 100644
index 00000000000..8fd071e0e49
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIoZ6d4mqaZJgCAggA
+MBQGCCqGSIb3DQMHBAjIgOrp5hZNzwSCBMjN+4OCjg+nTVC3WPMEHePoX4Utg7nv
+KymusJKn1Uh6tuVjP3JJtxQUtFblEeeeNtFGH7voDbW/BUFWJMgwleNdH6yeB4jw
+8AaSFNB325sUKTK4jzzVJPPbV2zf59ZnJN334RqlcJIMc4ptd/L2kvZhkEhQmAXW
+z70lz1ufz498vdeFu1FvyC2TQInHglCVbJBBde+hxVe66O2/ztjzpYhYEvPrPaGm
+TWjEdBsd1bpcspsbXhGd+gyA23S+Tg3VHXooLFW8C5AFFBVyEn8f7dv3ThGLCrG8
+/bkBr+WegR6r/etNwIGeXerdGzS+NMZZ2t0x7eoAAJetUtj4YJHWcaInvRlB8bJ/
+dJ64q6iOjACecIk17+DOksqjnxX8d2xTRxVd41wMMPoJ0rw/Se6fPty2Iyz+z+pK
+XahP6Nj/TpXwnqvB44tMiWHENTN6+HbWecFyCVHcx1NOsWex50JZbsufsmwffi6H
+Sk8tDuz+NseFnkbT1dDJirO/PkMaGk9+YqC9Hi/+prXFowcSKC0xrzuoz3PghxD9
+XoAdDhU3OGEfegwWT4GMQM4bOhiT2TOMmpoPuyi2bhtb/0v2pj3OaDxqUku9GBfK
++W7KSmRVLbHJkTZoLPaFtXvk0qOP6b6LH/bevMuPEz2YKiyhb8JDrIIspn/CfjJA
+DbIINBH0d3HNUduX4+GhIKAKDJenciTQXAwA6wjsxIpEwb7jvgup+o+7cAW2GcWu
+mQCrpRQDwM0jU/ATFx/aAJoTJjwEESn0h2AhZfnTbx4d0Re9tjzm2CwOvr6ZPc3H
+eQzuC5Z+fksITab2ZG+s++qV09cUqlwjCm73ISVyqkajv774YjDSYTDw77wB6Xu7
+7i7mKDXGqGdUgaIry6wMmJI+dumMArzBtcG0AGI8f/WvpK5R50q5Msx0fS4aBva7
+QDcqWfz89yIjJvxW6R+56PsZDV4uOSwFfSMqizNVc1fwoGmgLmPx2ACqxksIetX1
+7rvd1OZG2Q5Mmbs2VX9+LPWgXQkOvW2OL7Ywr6oWdlsOyNWzUaZFkhmKLnTqT9kG
+hzt64fR4XZMrSpCHNFhECve2GCMqQDzUaoNwOFM5t6G9xSbHfZlA6AvE4fS1so7r
+NiEycl/JBwatJyYHw8OpN4Honry/OHJONj95Hl3LUL4s1YXuXyOFsovPDH1ot5t6
+tLSiK1ggdpi8nxQY7j86beu1JGOMVoZF15RGPbam8HoGJM93iCe6yI+pEa9rytfy
+PFg6QscmaAe5oA2Aw3HTjTcyz4sKOct8mYkbWdSgoRLhN4fXM+5/lgTolBpsrFVZ
+4bxkFmkRlc5CDBpGkY/4j4AsXiKZSsB+iX3abQvXL4f1YFqggFLBLVEtaECcarfN
+dINQJCQvfK79ZBuMYZAieAoiuF7CEPDQCfwRJ8H/35JdcnXg3vEusKhapEfJg+Dg
+xbNJc9Vlzta/ABTaj4nxKFXGWJEY/IYcWwM2NN+SdrEwzoykrOUGkwIrCVqshXZx
+bgN8qnt6D9OPlm5xos12RGwmlDIenmQMt+aG7RXGOWVa0nmv/VTVkLmRfrBcEJ6F
+XYsKJ6oz2vgItlKoZLDpjiRB+ENbRwfJy1Hd6lPTi/a8bw9izyEQXef3X3pT9YfM
+Tow=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-openssl.cnf b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-openssl.cnf
new file mode 100644
index 00000000000..db7236074bd
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-openssl.cnf
@@ -0,0 +1,242 @@
+#
+# Based on the OpenSSL example configuration file.
+# This is mostly being used for generation of certificate requests.
+#
+
+# This definition stops the following lines choking if HOME isn't
+# defined.
+HOME = .
+RANDFILE = $ENV::HOME/.rnd
+
+#CRLDISTPT = [CRL Distribution Point; e.g., http://crl-list.base/w4edom-l4.base.crl]
+CRLDISTPT = http://www.samba.example.com/crls/CA-samba.example.com-crl.crl
+
+# Extra OBJECT IDENTIFIER info:
+oid_section = new_oids
+
+# To use this configuration file with the "-extfile" option of the
+# "openssl x509" utility, name here the section containing the
+# X.509v3 extensions to use:
+# extensions =
+# (Alternatively, use a configuration file that has only
+# X.509v3 extensions in its main [= default] section.)
+
+[ new_oids ]
+# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used as a login credential
+scardLogin=1.3.6.1.4.1.311.20.2.2
+# Used in a smart card login certificate's subject alternative name
+msUPN=1.3.6.1.4.1.311.20.2.3
+# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used to identify a domain controller
+msKDC=1.3.6.1.5.2.3.5
+# Identifies the AD GUID
+msADGUID=1.3.6.1.4.1.311.25.1
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = CA-samba.example.com # Where everything is kept
+certs = $dir/_none_certs # Where the issued certs are kept
+crl_dir = $dir/_none_crl # Where the issued crl are kept
+database = $dir/Private/CA-samba.example.com-index.txt # database index file.
+unique_subject = yes # Set to 'no' to allow creation of
+ # several certificates with same subject.
+new_certs_dir = $dir/NewCerts # default place for new certs.
+
+certificate = $dir/Public/CA-samba.example.com-cert.pem # The CA certificate
+serial = $dir/Private/CA-samba.example.com-serial.txt # The current serial number
+crlnumber = $dir/Private/CA-samba.example.com-crlnumber.txt # the current crl number
+ # must be commented out to leave a V1 CRL
+
+#crl = $dir/Public/CA-samba.example.com-crl.pem # The current CRL
+crl = $dir/Public/CA-samba.example.com-crl.crl # The current CRL
+private_key = $dir/Private/CA-samba.example.com-private-key.pem # The private key
+RANDFILE = $dir/Private/CA-samba.example.com.rand # private random number file
+
+#x509_extensions = # The extensions to add to the cert
+x509_extensions = template_x509_extensions
+
+# Comment out the following two lines for the "traditional"
+# (and highly broken) format.
+name_opt = ca_default # Subject Name options
+cert_opt = ca_default # Certificate field options
+
+# Extension copying option: use with caution.
+# copy_extensions = copy
+
+# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
+# so this is commented out by default to leave a V1 CRL.
+# crlnumber must also be commented out to leave a V1 CRL.
+crl_extensions = crl_ext
+
+default_days = 7300 # how long to certify for
+default_crl_days= 7300 # how long before next CRL
+default_md = sha256 # use public key default MD
+preserve = no # keep passed DN ordering
+
+# A few difference way of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+# For the 'anything' policy
+# At this point in time, you must list all acceptable 'object'
+# types.
+[ policy_anything ]
+countryName = match
+stateOrProvinceName = match
+localityName = match
+organizationName = match
+organizationalUnitName = match
+commonName = supplied
+emailAddress = supplied
+
+####################################################################
+[ req ]
+default_bits = 2048
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extensions to add to the self signed cert
+
+# Passwords for private keys if not present they will be prompted for
+# input_password = secret
+# output_password = secret
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString (PKIX recommendation before 2004)
+# utf8only: only UTF8Strings (PKIX recommendation after 2004).
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings.
+string_mask = utf8only
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = US
+countryName_min = 2
+countryName_max = 2
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = SambaState
+
+localityName = Locality Name (eg, city)
+localityName_default = SambaCity
+
+organizationName = Organization Name (eg, company)
+organizationName_default = SambaSelfTesting
+
+organizationalUnitName = Organizational Unit Name (eg, section)
+organizationalUnitName_default = Users
+
+commonName = Common Name (eg, YOUR name)
+commonName_default = administrator@samba.example.com
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_default = administrator@samba.example.com
+emailAddress_max = 64
+
+# SET-ex3 = SET extension number 3
+
+[ req_attributes ]
+#challengePassword = A challenge password
+#challengePassword_min = 4
+#challengePassword_max = 20
+#
+#unstructuredName = An optional company name
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+[ v3_ca ]
+# Extensions for a typical CA
+# PKIX recommendation.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer
+
+# This is what PKIX recommends but some broken software chokes on critical
+# extensions.
+#basicConstraints = critical,CA:true
+# So we do this instead.
+basicConstraints = CA:true
+
+# Key usage: this is typical for a CA certificate.
+keyUsage = cRLSign, keyCertSign
+
+crlDistributionPoints=URI:$CRLDISTPT
+
+# Some might want this also
+nsCertType = sslCA, emailCA
+
+# Include email address in subject alt name: another PKIX recommendation
+subjectAltName=email:copy
+# Copy issuer details
+issuerAltName=issuer:copy
+
+[ crl_ext ]
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always
+
+#[ usr_cert_scarduser ]
+[ template_x509_extensions ]
+
+# These extensions are added when 'ca' signs a request for a certificate that will be used to login from a smart card
+
+# This goes against PKIX guidelines but some CAs do it and some software
+# requires this to avoid interpreting an end user certificate as a CA.
+
+basicConstraints=CA:FALSE
+crlDistributionPoints=URI:$CRLDISTPT
+
+# For normal client use this is typical
+nsCertType = client, email
+
+# This is typical in keyUsage for a client certificate.
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+# This will be displayed in Netscape's comment listbox.
+nsComment = "Smart Card Login Certificate for administrator@samba.example.com"
+
+# PKIX recommendations harmless if included in all certificates.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+
+# This stuff is for subjectAltName and issuerAltname.
+
+subjectAltName=email:copy,otherName:msUPN;UTF8:administrator@samba.example.com
+
+# Copy subject details
+issuerAltName=issuer:copy
+
+nsCaRevocationUrl = $CRLDISTPT
+#nsBaseUrl
+#nsRevocationUrl
+#nsRenewalUrl
+#nsCaPolicyUrl
+#nsSslServerName
+
+#Extended Key requirements for client certs
+extendedKeyUsage = clientAuth,scardLogin
+
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-private-key.pem
new file mode 100644
index 00000000000..1d5ceeb2e14
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-private-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAyQdEOl/2NF8ninpuL/tFH8M93SxDZfF6KT9CJr3/T12RwLt1
+44EUfVlyeJYaXo2Vk/RdknkOJHdPiwhOcrGZiGMGdLLc94Ji6d1v5ae0yUQM5ENB
++FepILFwwXahSFvpVLZPIlCTkPBiMlCabiJrN6D3H/yxX67iC4ht6im2ASeyhO8Q
+TWwK3+qpioKYYKdSc6T3fLJKufCbxPgZWsCEVFI1yJJPFq/WNqZ4V1XlXmtiAPpI
+wnrnFzi1I9Wo+33fQlwD9Hzv//Gg5tgnkwazoyFoDsRgIAJGLyvYiOQrAcIxWlUo
+vlUD8gYr5OxIYOS226HwxSS64ajiavsLQGw99QIDAQABAoIBAFcGeUfYEQpdAw4U
+sCy/Vw5IBDkCF29DWUIP64BAEg12kUlhHcjOMWOOXFrNiD7UhiNVz0hAdZnduKaU
+gvlt3uxHCh1s7PGNFWrufKlrr3zNo9MRNrbepA3OIuTtiSZ8+4a7oYhWX3uIRMpJ
+UIFLDyU23qSPTO4CFEMv3X1Ybz0SALtUxZr5fwtAOn/EdiqSQzF65tBe0OzMWzfc
+Jm1Uvv3H/Dm8intOUMDQk+8KmQSp/Mj1Fwi4jU77WbZWXmAuDE1bQ6TSUHUBYBdp
+FgmRPk8gcOOHNjvEa62hZ2KIyKixjXoRKm9Sxr3jeZWG9QZcJFyVRMH37wa9vU8U
+d9lszkUCgYEA7ZkeFNO7ISqi4G5VeaTiZFMtGwHBUHYU30ccPg5T1gNNb0rOo17Y
+BOuqPE3HbqsfRiN1jTIkEE68ngP1VCE9H7WQ1pxMZSqBIotgGqZLFBkvbKTnlCNL
+dAtgTFQbZuBP/M/JN8g934kgjn33LOfPKoCzCnO9XZwEKVyRivQBV48CgYEA2JkT
+wVvLxB6NgshStjLBcLbeIPADT24xcH7Wyr7WoSx+F/J0q3nT5qHAFmVDttFMujc2
+EVBeJclMxmC529O+SPid8X3/Y9BqOwSzBdFIEBw0xbv0ntgCr0qYNHkkqqvvDNCm
+4VsIOeNi4YvNwHFuUB4+7upAkG/khGORJnIJ8DsCgYEAiG9Rb8I5hY0XJGsXGBgP
+jG6ayxRR7qMvzxrlY9kUWSNiVtMNH5D52LF++svrBmirN7pq6R5uyRJ9ivtY5+uC
+TvAS8LmlwL4Mk0qXcBYnrK3dprR26oDt9gAGVy5A4e1S4ShsMmUA6piyokBBLH8c
+XhqzNQBLMDLDzQCD7te44Y8CgYEAnVYlCZIa5G2lMdk+a+dWqP/NP3PZk7th4mvg
+rwoNcqqVNeQDaARpLuFUXXBVzdkfuS0d81nD6gLd6ESe/dZEJVGjuaZi/CiK4jA5
+swIhLMKweupbeX9EA/1VrthJEEkwrshqUM0FnrdUPq6FWUOMdFpkMLytBb6h6qFA
+8QJpwb0CgYEA11acodjgxuuLPOOxUG7sl++ZNT8/2Upx02QbPknJ/Hmu63CHv2qL
+HxGvsynw3ardm9flgbpxSuU5K2ntQjo64SfZxgTC5z5Oqr0m6oIoMutQTNvTnbtm
+AhQ9V9Z795DcLaDDNAQB3LmEvQWT5FSDSdi2lLXzQWlHf//VGDIipjE=
+-----END RSA PRIVATE KEY-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-req.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-req.pem
new file mode 100644
index 00000000000..7c2f1630908
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-S01-req.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIDATCCAekCAQAwgbsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTYW1iYVN0YXRl
+MRIwEAYDVQQHDAlTYW1iYUNpdHkxGTAXBgNVBAoMEFNhbWJhU2VsZlRlc3Rpbmcx
+DjAMBgNVBAsMBVVzZXJzMSgwJgYDVQQDDB9hZG1pbmlzdHJhdG9yQHNhbWJhLmV4
+YW1wbGUuY29tMS4wLAYJKoZIhvcNAQkBFh9hZG1pbmlzdHJhdG9yQHNhbWJhLmV4
+YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyQdEOl/2
+NF8ninpuL/tFH8M93SxDZfF6KT9CJr3/T12RwLt144EUfVlyeJYaXo2Vk/RdknkO
+JHdPiwhOcrGZiGMGdLLc94Ji6d1v5ae0yUQM5ENB+FepILFwwXahSFvpVLZPIlCT
+kPBiMlCabiJrN6D3H/yxX67iC4ht6im2ASeyhO8QTWwK3+qpioKYYKdSc6T3fLJK
+ufCbxPgZWsCEVFI1yJJPFq/WNqZ4V1XlXmtiAPpIwnrnFzi1I9Wo+33fQlwD9Hzv
+//Gg5tgnkwazoyFoDsRgIAJGLyvYiOQrAcIxWlUovlUD8gYr5OxIYOS226HwxSS6
+4ajiavsLQGw99QIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAGx2x4siii0Z5wAL
+u/UPPTQqqKvOdtAGpQzeT/pBw1ttXq8G3tgSJ4H0KAcqFfUFdjTVqMbzSGFF3InX
+uop0fkZIG4A5uMKNget2atlP6BUejlVoHWA2Tyuioo+iYDAosN9fI3RkgOgEl4T2
+fwcOkae2uTVTUloDaBfzQNPRd86RCHVEYc+PSjVfNUoTjRug/BhR+7ZOTcDRFQ4N
+61LeMll9j/ooFEYgpfXBygoDpx44mEH69c/7aLjydq/nLMKbCtNG7NYDAEUbruB4
+D48JYBDHB/1XqzvIYwmXLAdlZ3prNaF+c/O7KHqa+R2kilZ+YvhUuyuHLEMecNsD
+owjRHmw=
+-----END CERTIFICATE REQUEST-----
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-cert.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-cert.pem
new file mode 120000
index 00000000000..3b134b6f698
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-cert.pem
@@ -0,0 +1 @@
+USER-administrator@samba.example.com-S01-cert.pem \ No newline at end of file
diff --git a/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-private-key.pem b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-private-key.pem
new file mode 120000
index 00000000000..964892eba9c
--- /dev/null
+++ b/selftest/manage-ca/CA-samba.example.com/Users/administrator@samba.example.com/USER-administrator@samba.example.com-private-key.pem
@@ -0,0 +1 @@
+USER-administrator@samba.example.com-S01-private-key.pem \ No newline at end of file
diff --git a/selftest/manage-ca/manage-CA-samba.example.com.cnf b/selftest/manage-ca/manage-CA-samba.example.com.cnf
new file mode 100644
index 00000000000..65c9b95ecbe
--- /dev/null
+++ b/selftest/manage-ca/manage-CA-samba.example.com.cnf
@@ -0,0 +1,21 @@
+#
+# All passwords are "1234"
+#
+
+CRL_HTTP_BASE="http://www.samba.example.com/crls"
+CRL_SSH_BASE="none@samba.example.com:/none/crls"
+DNS_DOMAIN="samba.example.com"
+
+CA_BITS="8192"
+DC_BITS="4096"
+USER_BITS="2048"
+# 20 years should be enough
+CA_DAYS="7300"
+CRL_DAYS="7300"
+DC_DAYS="7300"
+USER_DAYS="7300"
+
+COUNTRY_NAME="US"
+STATE_NAME="SambaState"
+LOCALITY_NAME="SambaCity"
+ORGANIZATION_NAME="SambaSelfTesting"
diff --git a/selftest/manage-ca/manage-CA-samba.example.com.sh b/selftest/manage-ca/manage-CA-samba.example.com.sh
new file mode 100644
index 00000000000..449a58a4bcf
--- /dev/null
+++ b/selftest/manage-ca/manage-CA-samba.example.com.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+
+set -e
+set -u
+set -x
+
+#
+# All passwords are "1234"
+#
+
+# DONE # ./manage-ca.sh manage-CA-samba.example.com.cnf init_ca
+# DONE #
+# DONE # ./manage-ca.sh manage-CA-samba.example.com.cnf create_dc localdc.samba.example.com 0123456789ABCDEF
+# DONE # ./manage-ca.sh manage-CA-samba.example.com.cnf create_user administrator@samba.example.com
+# DONE #
+# DONE # ./manage-ca.sh manage-CA-samba.example.com.cnf create_dc plugindc.plugindom.samba.example.com 0123456789ABCDEF
+# DONE # ./manage-ca.sh manage-CA-samba.example.com.cnf create_user administrator@plugindom.samba.example.com
diff --git a/selftest/manage-ca/manage-ca.sh b/selftest/manage-ca/manage-ca.sh
new file mode 100755
index 00000000000..ab796b718af
--- /dev/null
+++ b/selftest/manage-ca/manage-ca.sh
@@ -0,0 +1,387 @@
+#!/bin/bash
+#
+
+set -e
+set -u
+#set -x
+
+umask 022
+
+function print_usage()
+{
+ echo "Usage:"
+ echo ""
+ echo "${0} <CNF_FILE> <CMD> [<ARG1> [<ARG2>]]"
+ echo ""
+ echo "${0} <CNF_FILE> init_ca"
+ echo "${0} <CNF_FILE> update_crl"
+ echo "${0} <CNF_FILE> publish_crl"
+ echo "${0} <CNF_FILE> create_dc <DC_DNS_NAME> <DC_OBJECTGUID_HEX>"
+ echo "${0} <CNF_FILE> revoke_dc <DC_DNS_NAME> <REVOKE_RESON>"
+ echo "${0} <CNF_FILE> create_user <USER_PRINCIPAL_NAME>"
+ echo "${0} <CNF_FILE> revoke_user <USER_PRINCIPAL_NAME> <REVOKE_RESON>"
+ echo ""
+}
+
+function check_arg()
+{
+ local k="${1}"
+ local v="${2}"
+
+ test -n "${v}" || {
+ print_usage
+ echo "ERROR: CMD[${CMD}] argument <${k}> missing"
+ return 1
+ }
+
+ return 0
+}
+CNF="${1-}"
+test -n "${CNF}" || {
+ print_usage
+ echo "ERROR: speficy <CNF_FILE> see manage-ca.templates.d/manage-CA-example.com.cnf"
+ exit 1
+}
+test -e "${CNF}" || {
+ print_usage
+ echo "ERROR: CNF_FILE[${CNF}] does not exist"
+ exit 1
+}
+CMD="${2-}"
+CMDARG1="${3-}"
+CMDARG2="${4-}"
+
+TEMPLATE_DIR="manage-ca.templates.d"
+DEFAULT_VARS=""
+DEFAULT_VARS="${DEFAULT_VARS} CRL_HTTP_BASE DNS_DOMAIN DEFAULT_BITS"
+DEFAULT_VARS="${DEFAULT_VARS} DEFAULT_BITS DEFAULT_DAYS DEFAULT_CRL_DAYS"
+DEFAULT_VARS="${DEFAULT_VARS} COUNTRY_NAME STATE_NAME LOCALITY_NAME ORGANIZATION_NAME"
+DEFAULT_VARS="${DEFAULT_VARS} ORGANIZATIONAL_UNIT_NAME COMMON_NAME EMAIL_ADDRESS"
+
+source "${CNF}"
+
+DEFAULT_BITS=${DEFAULT_BITS:=8192}
+CA_BITS=${CA_BITS:=${DEFAULT_BITS}}
+DC_BITS=${DC_BITS:=${DEFAULT_BITS}}
+USER_BITS=${USER_BITS:=${DEFAULT_BITS}}
+
+CA_DAYS=${CA_DAYS:=3650}
+CRL_DAYS=${CRL_DAYS:=30}
+DC_DAYS=${DC_DAYS:=730}
+USER_DAYS=${USER_DAYS:=730}
+
+CA_DIR="CA-${DNS_DOMAIN}"
+DEFAULT_VARS="${DEFAULT_VARS} CA_DIR"
+
+CACERT_PEM="${CA_DIR}/Public/CA-${DNS_DOMAIN}-cert.pem"
+CACERT_CER="${CA_DIR}/Public/CA-${DNS_DOMAIN}-cert.cer"
+CACRL_PEM="${CA_DIR}/Public/CA-${DNS_DOMAIN}-crl.pem"
+CACRL_CRL="${CA_DIR}/Public/CA-${DNS_DOMAIN}-crl.crl"
+CA_SERIAL="${CA_DIR}/Private/CA-${DNS_DOMAIN}-serial.txt"
+
+function generate_from_template()
+{
+ local base_template="${TEMPLATE_DIR}/$1"
+ local cmd_template="${TEMPLATE_DIR}/$2"
+ local cnf_file="$3"
+ shift 3
+ local vars="$@"
+
+ test -f "${base_template}" || {
+ echo "base_template[${base_template}] does not exists"
+ return 1
+ }
+ test -f "${cmd_template}" || {
+ echo "cmd_template[${cmd_template}] does not exists"
+ return 1
+ }
+ test -e "${cnf_file}" && {
+ echo "cnf_file[${cnf_file}] already exists"
+ return 1
+ }
+
+ local sedargs=""
+ for k in $vars; do
+ v=$(eval echo "\${${k}}")
+ sedargs="${sedargs} -e 's!@@${k}@@!${v}!g'"
+ done
+
+ #echo "sedargs[${sedargs}]"
+ cat "${base_template}" "${cmd_template}" | eval sed ${sedargs} > "${cnf_file}"
+ grep '@@' "${cnf_file}" | wc -l | grep -q '^0' || {
+ echo "invalid context in cnf_file[${cnf_file}]"
+ grep '@@' "${cnf_file}"
+ return 1
+ }
+
+ return 0
+}
+
+case "${CMD}" in
+init_ca)
+ test -e "${CA_DIR}" && {
+ echo "CA with CA_DIR[${CA_DIR}] already exists"
+ exit 1
+ }
+
+ OPENSSLCNF="${CA_DIR}/Private/CA-${DNS_DOMAIN}-openssl.cnf"
+ CA_INDEX="${CA_DIR}/Private/CA-${DNS_DOMAIN}-index.txt"
+ CA_CRLNUMBER="${CA_DIR}/Private/CA-${DNS_DOMAIN}-crlnumber.txt"
+ PRIVATEKEY="${CA_DIR}/Private/CA-${DNS_DOMAIN}-private-key.pem"
+
+ ORGANIZATIONAL_UNIT_NAME="CA Administration"
+ COMMON_NAME="CA of ${DNS_DOMAIN}"
+ EMAIL_ADDRESS="ca-${DNS_DOMAIN}@${DNS_DOMAIN}"
+
+ DEFAULT_BITS="${CA_BITS}"
+ DEFAULT_DAYS="1"
+ DEFAULT_CRL_DAYS="${CRL_DAYS}"
+
+ mkdir -p "${CA_DIR}/"{,Public}
+ umask 077
+ mkdir -p "${CA_DIR}/"{,Private,NewCerts,DCs,Users}
+ umask 022
+ touch "${CA_INDEX}"
+ echo "00" > "${CA_SERIAL}"
+ echo "00" > "${CA_CRLNUMBER}"
+
+ generate_from_template \
+ "openssl-BASE-template.cnf" \
+ "openssl-CA-template.cnf" \
+ "${OPENSSLCNF}" \
+ ${DEFAULT_VARS}
+ openssl req -new -x509 -sha256 -extensions v3_ca -days "${CA_DAYS}" -keyout "${PRIVATEKEY}" -out "${CACERT_PEM}" -config "${OPENSSLCNF}"
+ openssl x509 -in "${CACERT_PEM}" -inform PEM -out "${CACERT_CER}" -outform DER
+ echo -n "Generate CRL [ENTER] to continue"
+ read
+ openssl ca -config "${OPENSSLCNF}" -gencrl -out "${CACRL_PEM}"
+ openssl crl -in "${CACRL_PEM}" -inform PEM -out "${CACRL_CRL}" -outform DER
+ ls -la "${CA_DIR}"/Public/CA-*
+ echo "Please run: '${0} ${CNF} publish_crl'"
+ exit 0
+ ;;
+update_crl)
+ test -e "${CA_DIR}" || {
+ echo "CA with CA_DIR[${CA_DIR}] does not exists"
+ exit 1
+ }
+
+ OPENSSLCNF="${CA_DIR}/Private/CA-${DNS_DOMAIN}-openssl.cnf"
+ openssl ca -config "${OPENSSLCNF}" -gencrl -out "${CACRL_PEM}"
+ openssl crl -in "${CACRL_PEM}" -inform PEM -out "${CACRL_CRL}" -outform DER
+ ls -la "${CACRL_PEM}" "${CACRL_CRL}"
+ echo "Please run: '${0} ${CNF} publish_crl'"
+ exit 0
+ ;;
+publish_crl)
+ test -e "${CA_DIR}" || {
+ echo "CA with CA_DIR[${CA_DIR}] does not exists"
+ exit 1
+ }
+
+ echo "Upload ${CACRL_CRL} to ${CRL_SSH_BASE}/"
+ rsync -a -P "${CACRL_CRL}" "${CRL_SSH_BASE}/"
+ echo "Check ${CRL_HTTP_BASE}/CA-${DNS_DOMAIN}-crl.crl"
+ exit 0
+ ;;
+create_dc)
+ test -e "${CA_DIR}" || {
+ echo "CA with CA_DIR[${CA_DIR}] does not exists"
+ exit 1
+ }
+ #
+ #
+ # ldbsearch -H ldap://DC_DNS_NAME '(dnsHostName=DC_DNS_NAME)' distinguishedName --controls=search_options:1:1 --controls=extended_dn:1:0
+ DC_DNS_NAME="${CMDARG1}"
+ check_arg "DC_DNS_NAME" "${DC_DNS_NAME}"
+ DC_OBJECTGUID_HEX=$(echo "${CMDARG2}" | tr a-z A-Z)
+ check_arg "DC_OBJECTGUID_HEX" "${DC_OBJECTGUID_HEX}"
+
+ DC_DIR="${CA_DIR}/DCs/${DC_DNS_NAME}"
+ test -e "${DC_DIR}" && {
+ echo "DC with DC_DIR[${DC_DIR}] already exists"
+ exit 1
+ }
+
+ NEXT_SERIAL=$(cat "${CA_SERIAL}" | xargs)
+ DCFILE_BASE="DC-${DC_DNS_NAME}-S${NEXT_SERIAL}"
+ OPENSSLCNF="${DC_DIR}/${DCFILE_BASE}-openssl.cnf"
+ DCKEY_PEM="${DC_DIR}/${DCFILE_BASE}-key.pem"
+ DCKEY_PRIVATE_PEM="${DC_DIR}/${DCFILE_BASE}-private-key.pem"
+ DCKEY_PRIVATE_PEM_BASE="${DCFILE_BASE}-private-key.pem"
+ DCKEY_PRIVATE_PEM_LINK="${DC_DIR}/DC-${DC_DNS_NAME}-private-key.pem"
+ DCREQ_PEM="${DC_DIR}/${DCFILE_BASE}-req.pem"
+ DCCERT_PEM="${DC_DIR}/${DCFILE_BASE}-cert.pem"
+ DCCERT_PEM_BASE="${DCFILE_BASE}-cert.pem"
+ DCCERT_PEM_LINK="${DC_DIR}/DC-${DC_DNS_NAME}-cert.pem"
+ DCCERT_CER="${DC_DIR}/${DCFILE_BASE}-cert.cer"
+ DCCERT_P12="${DC_DIR}/${DCFILE_BASE}-private.p12"
+
+ ORGANIZATIONAL_UNIT_NAME="Domain Controllers"
+ COMMON_NAME="${DC_DNS_NAME}"
+ EMAIL_ADDRESS="ca-${DNS_DOMAIN}@${DNS_DOMAIN}"
+
+ DEFAULT_BITS="${DC_BITS}"
+ DEFAULT_DAYS="${DC_DAYS}"
+ DEFAULT_CRL_DAYS="${CRL_DAYS}"
+
+ umask 077
+ mkdir -p "${DC_DIR}/"
+
+ generate_from_template \
+ "openssl-BASE-template.cnf" \
+ "openssl-DC-template.cnf" \
+ "${OPENSSLCNF}" \
+ ${DEFAULT_VARS} DC_DNS_NAME DC_OBJECTGUID_HEX
+
+ openssl req -new -newkey rsa -keyout "${DCKEY_PEM}" -out "${DCREQ_PEM}" -config "${OPENSSLCNF}"
+ openssl rsa -in "${DCKEY_PEM}" -inform PEM -out "${DCKEY_PRIVATE_PEM}" -outform PEM
+ openssl ca -config "${OPENSSLCNF}" -in "${DCREQ_PEM}" -out "${DCCERT_PEM}"
+ ln -s "${DCKEY_PRIVATE_PEM_BASE}" "${DCKEY_PRIVATE_PEM_LINK}"
+ ln -s "${DCCERT_PEM_BASE}" "${DCCERT_PEM_LINK}"
+ openssl x509 -in "${DCCERT_PEM}" -inform PEM -out "${DCCERT_CER}" -outform DER
+ echo "Generate ${DCCERT_P12}"
+ openssl pkcs12 -in "${DCCERT_PEM}" -inkey "${DCKEY_PRIVATE_PEM}" -export -out "${DCCERT_P12}"
+ ls -la "${DC_DIR}"/*.*
+ exit 0
+ ;;
+revoke_dc)
+ test -e "${CA_DIR}" || {
+ echo "CA with CA_DIR[${CA_DIR}] does not exists"
+ exit 1
+ }
+ DC_DNS_NAME="${CMDARG1}"
+ check_arg "DC_DNS_NAME" "${DC_DNS_NAME}"
+ REVOKE_REASON="${CMDARG2}"
+ check_arg "REVOKE_REASON" "${REVOKE_REASON}"
+
+ DC_DIR="${CA_DIR}/DCs/${DC_DNS_NAME}"
+ test -e "${DC_DIR}" || {
+ echo "DC with DC_DIR[${DC_DIR}] does not exists"
+ exit 1
+ }
+
+ OPENSSLCNF="${CA_DIR}/Private/CA-${DNS_DOMAIN}-openssl.cnf"
+ DCKEY_PRIVATE_PEM_LINK="${DC_DIR}/DC-${DC_DNS_NAME}-private-key.pem"
+ DCCERT_PEM_LINK="${DC_DIR}/DC-${DC_DNS_NAME}-cert.pem"
+
+ REVOKE_DATE=$(date +%Y%m%d-%H%M%S)
+ REVOKE_DC_DIR="${DC_DIR}.${REVOKE_DATE}.revoked-${REVOKE_REASON}"
+
+ openssl ca -config "${OPENSSLCNF}" -revoke "${DCCERT_PEM_LINK}" -crl_reason "${REVOKE_REASON}"
+
+ mv "${DCKEY_PRIVATE_PEM_LINK}" "${DCKEY_PRIVATE_PEM_LINK}.revoked"
+ mv "${DCCERT_PEM_LINK}" "${DCCERT_PEM_LINK}.revoked"
+ mv "${DC_DIR}" "${REVOKE_DC_DIR}"
+ echo "${REVOKE_DC_DIR}"
+
+ openssl ca -config "${OPENSSLCNF}" -gencrl -out "${CACRL_PEM}"
+ openssl crl -in "${CACRL_PEM}" -inform PEM -out "${CACRL_CRL}" -outform DER
+ ls -la "${CACRL_PEM}" "${CACRL_CRL}"
+ echo "Please run: '${0} ${CNF} publish_crl'"
+ exit 0
+ ;;
+create_user)
+ test -e "${CA_DIR}" || {
+ echo "CA with CA_DIR[${CA_DIR}] does not exists"
+ exit 1
+ }
+ USER_PRINCIPAL_NAME="${CMDARG1}"
+ check_arg "USER_PRINCIPAL_NAME" "${USER_PRINCIPAL_NAME}"
+
+ USER_DIR="${CA_DIR}/Users/${USER_PRINCIPAL_NAME}"
+ test -e "${USER_DIR}" && {
+ echo "USER with USER_DIR[${USER_DIR}] already exists"
+ exit 1
+ }
+
+ NEXT_SERIAL=$(cat "${CA_SERIAL}" | xargs)
+ USERFILE_BASE="USER-${USER_PRINCIPAL_NAME}-S${NEXT_SERIAL}"
+ OPENSSLCNF="${USER_DIR}/${USERFILE_BASE}-openssl.cnf"
+ USERKEY_PEM="${USER_DIR}/${USERFILE_BASE}-key.pem"
+ USERKEY_PRIVATE_PEM="${USER_DIR}/${USERFILE_BASE}-private-key.pem"
+ USERKEY_PRIVATE_PEM_BASE="${USERFILE_BASE}-private-key.pem"
+ USERKEY_PRIVATE_PEM_LINK="${USER_DIR}/USER-${USER_PRINCIPAL_NAME}-private-key.pem"
+ USERREQ_PEM="${USER_DIR}/${USERFILE_BASE}-req.pem"
+ USERCERT_PEM="${USER_DIR}/${USERFILE_BASE}-cert.pem"
+ USERCERT_PEM_BASE="${USERFILE_BASE}-cert.pem"
+ USERCERT_PEM_LINK="${USER_DIR}/USER-${USER_PRINCIPAL_NAME}-cert.pem"
+ USERCERT_CER="${USER_DIR}/${USERFILE_BASE}-cert.cer"
+ USERCERT_P12="${USER_DIR}/${USERFILE_BASE}-private.p12"
+
+ ORGANIZATIONAL_UNIT_NAME="Users"
+ COMMON_NAME="${USER_PRINCIPAL_NAME}"
+ EMAIL_ADDRESS="${USER_PRINCIPAL_NAME}"
+
+ DEFAULT_BITS="${USER_BITS}"
+ DEFAULT_DAYS="${USER_DAYS}"
+ DEFAULT_CRL_DAYS="${CRL_DAYS}"
+
+ umask 077
+ mkdir -p "${USER_DIR}/"
+
+ generate_from_template \
+ "openssl-BASE-template.cnf" \
+ "openssl-USER-template.cnf" \
+ "${OPENSSLCNF}" \
+ ${DEFAULT_VARS} USER_PRINCIPAL_NAME
+
+ openssl req -new -newkey rsa -keyout "${USERKEY_PEM}" -out "${USERREQ_PEM}" -config "${OPENSSLCNF}"
+ openssl rsa -in "${USERKEY_PEM}" -inform PEM -out "${USERKEY_PRIVATE_PEM}" -outform PEM
+ openssl ca -config "${OPENSSLCNF}" -in "${USERREQ_PEM}" -out "${USERCERT_PEM}"
+ ln -s "${USERKEY_PRIVATE_PEM_BASE}" "${USERKEY_PRIVATE_PEM_LINK}"
+ ln -s "${USERCERT_PEM_BASE}" "${USERCERT_PEM_LINK}"
+ openssl x509 -in "${USERCERT_PEM}" -inform PEM -out "${USERCERT_CER}" -outform DER
+ echo "Generate ${USERCERT_P12}"
+ openssl pkcs12 -in "${USERCERT_PEM}" -inkey "${USERKEY_PRIVATE_PEM}" -export -out "${USERCERT_P12}"
+ ls -la "${USER_DIR}"/*.*
+ exit 0
+ ;;
+revoke_user)
+ test -e "${CA_DIR}" || {
+ echo "CA with CA_DIR[${CA_DIR}] does not exists"
+ exit 1
+ }
+ USER_PRINCIPAL_NAME="${CMDARG1}"
+ check_arg "USER_PRINCIPAL_NAME" "${USER_PRINCIPAL_NAME}"
+ REVOKE_REASON="${CMDARG2}"
+ check_arg "REVOKE_REASON" "${REVOKE_REASON}"
+
+ USER_DIR="${CA_DIR}/Users/${USER_PRINCIPAL_NAME}"
+ test -e "${USER_DIR}" || {
+ echo "USER with USER_DIR[${USER_DIR}] does not exists"
+ exit 1
+ }
+
+ OPENSSLCNF="${CA_DIR}/Private/CA-${DNS_DOMAIN}-openssl.cnf"
+ USERKEY_PRIVATE_PEM_LINK="${USER_DIR}/USER-${USER_PRINCIPAL_NAME}-private-key.pem"
+ USERCERT_PEM_LINK="${USER_DIR}/USER-${USER_PRINCIPAL_NAME}-cert.pem"
+
+ REVOKE_DATE=$(date +%Y%m%d-%H%M%S)
+ REVOKE_USER_DIR="${USER_DIR}.${REVOKE_DATE}.revoked-${REVOKE_REASON}"
+
+ openssl ca -config "${OPENSSLCNF}" -revoke "${USERCERT_PEM_LINK}" -crl_reason "${REVOKE_REASON}"
+
+ mv "${USERKEY_PRIVATE_PEM_LINK}" "${USERKEY_PRIVATE_PEM_LINK}.revoked"
+ mv "${USERCERT_PEM_LINK}" "${USERCERT_PEM_LINK}.revoked"
+ mv "${USER_DIR}" "${REVOKE_USER_DIR}.revoked"
+ echo "${REVOKE_USER_DIR}"
+
+ openssl ca -config "${OPENSSLCNF}" -gencrl -out "${CACRL_PEM}"
+ openssl crl -in "${CACRL_PEM}" -inform PEM -out "${CACRL_CRL}" -outform DER
+ ls -la "${CACRL_PEM}" "${CACRL_CRL}"
+ echo "Please run: '${0} ${CNF} publish_crl'"
+ exit 0
+ ;;
+usage)
+ print_usage
+ exit 1
+ ;;
+*)
+ print_usage
+ echo "ERROR: CMD[${CMD}] - unknown"
+ exit 1
+ ;;
+esac
+
+exit 1
diff --git a/selftest/manage-ca/manage-ca.templates.d/manage-CA-example.com.cnf b/selftest/manage-ca/manage-ca.templates.d/manage-CA-example.com.cnf
new file mode 100644
index 00000000000..1f3d24ef29b
--- /dev/null
+++ b/selftest/manage-ca/manage-ca.templates.d/manage-CA-example.com.cnf
@@ -0,0 +1,17 @@
+
+CRL_HTTP_BASE="http://www.example.com/crls"
+CRL_SSH_BASE="www.example.com:/path/to/crls"
+DNS_DOMAIN="example.com"
+
+#CA_BITS="8192"
+#DC_BITS="8192"
+#USER_BITS="8192"
+#CA_DAYS="3650"
+#CRL_DAYS="30"
+#DC_DAYS="730"
+#USER_DAYS="730"
+
+COUNTRY_NAME="US"
+STATE_NAME="ExampleState"
+LOCALITY_NAME="ExampleCity"
+ORGANIZATION_NAME="ExampleOrganization"
diff --git a/selftest/manage-ca/manage-ca.templates.d/openssl-BASE-template.cnf b/selftest/manage-ca/manage-ca.templates.d/openssl-BASE-template.cnf
new file mode 100644
index 00000000000..ca8415b67d0
--- /dev/null
+++ b/selftest/manage-ca/manage-ca.templates.d/openssl-BASE-template.cnf
@@ -0,0 +1,201 @@
+#
+# Based on the OpenSSL example configuration file.
+# This is mostly being used for generation of certificate requests.
+#
+
+# This definition stops the following lines choking if HOME isn't
+# defined.
+HOME = .
+RANDFILE = $ENV::HOME/.rnd
+
+#CRLDISTPT = [CRL Distribution Point; e.g., http://crl-list.base/w4edom-l4.base.crl]
+CRLDISTPT = @@CRL_HTTP_BASE@@/CA-@@DNS_DOMAIN@@-crl.crl
+
+# Extra OBJECT IDENTIFIER info:
+oid_section = new_oids
+
+# To use this configuration file with the "-extfile" option of the
+# "openssl x509" utility, name here the section containing the
+# X.509v3 extensions to use:
+# extensions =
+# (Alternatively, use a configuration file that has only
+# X.509v3 extensions in its main [= default] section.)
+
+[ new_oids ]
+# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used as a login credential
+scardLogin=1.3.6.1.4.1.311.20.2.2
+# Used in a smart card login certificate's subject alternative name
+msUPN=1.3.6.1.4.1.311.20.2.3
+# Ordinarily, certificates must have this oid as an enhanced key usage in order for Windows to allow them to be used to identify a domain controller
+msKDC=1.3.6.1.5.2.3.5
+# Identifies the AD GUID
+msADGUID=1.3.6.1.4.1.311.25.1
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = @@CA_DIR@@ # Where everything is kept
+certs = $dir/_none_certs # Where the issued certs are kept
+crl_dir = $dir/_none_crl # Where the issued crl are kept
+database = $dir/Private/CA-@@DNS_DOMAIN@@-index.txt # database index file.
+unique_subject = yes # Set to 'no' to allow creation of
+ # several certificates with same subject.
+new_certs_dir = $dir/NewCerts # default place for new certs.
+
+certificate = $dir/Public/CA-@@DNS_DOMAIN@@-cert.pem # The CA certificate
+serial = $dir/Private/CA-@@DNS_DOMAIN@@-serial.txt # The current serial number
+crlnumber = $dir/Private/CA-@@DNS_DOMAIN@@-crlnumber.txt # the current crl number
+ # must be commented out to leave a V1 CRL
+
+#crl = $dir/Public/CA-@@DNS_DOMAIN@@-crl.pem # The current CRL
+crl = $dir/Public/CA-@@DNS_DOMAIN@@-crl.crl # The current CRL
+private_key = $dir/Private/CA-@@DNS_DOMAIN@@-private-key.pem # The private key
+RANDFILE = $dir/Private/CA-@@DNS_DOMAIN@@.rand # private random number file
+
+#x509_extensions = # The extensions to add to the cert
+x509_extensions = template_x509_extensions
+
+# Comment out the following two lines for the "traditional"
+# (and highly broken) format.
+name_opt = ca_default # Subject Name options
+cert_opt = ca_default # Certificate field options
+
+# Extension copying option: use with caution.
+# copy_extensions = copy
+
+# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
+# so this is commented out by default to leave a V1 CRL.
+# crlnumber must also be commented out to leave a V1 CRL.
+crl_extensions = crl_ext
+
+default_days = @@DEFAULT_DAYS@@ # how long to certify for
+default_crl_days= @@DEFAULT_CRL_DAYS@@ # how long before next CRL
+default_md = sha256 # use public key default MD
+preserve = no # keep passed DN ordering
+
+# A few difference way of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+# For the 'anything' policy
+# At this point in time, you must list all acceptable 'object'
+# types.
+[ policy_anything ]
+countryName = match
+stateOrProvinceName = match
+localityName = match
+organizationName = match
+organizationalUnitName = match
+commonName = supplied
+emailAddress = supplied
+
+####################################################################
+[ req ]
+default_bits = @@DEFAULT_BITS@@
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extensions to add to the self signed cert
+
+# Passwords for private keys if not present they will be prompted for
+# input_password = secret
+# output_password = secret
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString (PKIX recommendation before 2004)
+# utf8only: only UTF8Strings (PKIX recommendation after 2004).
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings.
+string_mask = utf8only
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = @@COUNTRY_NAME@@
+countryName_min = 2
+countryName_max = 2
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = @@STATE_NAME@@
+
+localityName = Locality Name (eg, city)
+localityName_default = @@LOCALITY_NAME@@
+
+organizationName = Organization Name (eg, company)
+organizationName_default = @@ORGANIZATION_NAME@@
+
+organizationalUnitName = Organizational Unit Name (eg, section)
+organizationalUnitName_default = @@ORGANIZATIONAL_UNIT_NAME@@
+
+commonName = Common Name (eg, YOUR name)
+commonName_default = @@COMMON_NAME@@
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_default = @@EMAIL_ADDRESS@@
+emailAddress_max = 64
+
+# SET-ex3 = SET extension number 3
+
+[ req_attributes ]
+#challengePassword = A challenge password
+#challengePassword_min = 4
+#challengePassword_max = 20
+#
+#unstructuredName = An optional company name
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+[ v3_ca ]
+# Extensions for a typical CA
+# PKIX recommendation.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer
+
+# This is what PKIX recommends but some broken software chokes on critical
+# extensions.
+#basicConstraints = critical,CA:true
+# So we do this instead.
+basicConstraints = CA:true
+
+# Key usage: this is typical for a CA certificate.
+keyUsage = cRLSign, keyCertSign
+
+crlDistributionPoints=URI:$CRLDISTPT
+
+# Some might want this also
+nsCertType = sslCA, emailCA
+
+# Include email address in subject alt name: another PKIX recommendation
+subjectAltName=email:copy
+# Copy issuer details
+issuerAltName=issuer:copy
+
+[ crl_ext ]
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always
+
diff --git a/selftest/manage-ca/manage-ca.templates.d/openssl-CA-template.cnf b/selftest/manage-ca/manage-ca.templates.d/openssl-CA-template.cnf
new file mode 100644
index 00000000000..4c6bb4a8836
--- /dev/null
+++ b/selftest/manage-ca/manage-ca.templates.d/openssl-CA-template.cnf
@@ -0,0 +1,2 @@
+[ template_x509_extensions ]
+
diff --git a/selftest/manage-ca/manage-ca.templates.d/openssl-DC-template.cnf b/selftest/manage-ca/manage-ca.templates.d/openssl-DC-template.cnf
new file mode 100644
index 00000000000..0b0424da27f
--- /dev/null
+++ b/selftest/manage-ca/manage-ca.templates.d/openssl-DC-template.cnf
@@ -0,0 +1,49 @@
+#[ usr_cert_mskdc ]
+[ template_x509_extensions ]
+
+# These extensions are added when 'ca' signs a request for a domain controller certificate.
+
+# This goes against PKIX guidelines but some CAs do it and some software
+# requires this to avoid interpreting an end user certificate as a CA.
+
+basicConstraints=CA:FALSE
+crlDistributionPoints=URI:$CRLDISTPT
+
+# Here are some examples of the usage of nsCertType. If it is omitted
+# the certificate can be used for anything *except* object signing.
+
+# This is OK for an SSL server.
+nsCertType = server
+
+# This is typical in keyUsage for a client certificate.
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+# This will be displayed in Netscape's comment listbox.
+nsComment = "Domain Controller Certificate @@DC_DNS_NAME@@"
+
+# PKIX recommendations harmless if included in all certificates.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+
+# This stuff is for subjectAltName and issuerAltname.
+
+subjectAltName=@dc_subjalt
+
+# Copy subject details
+issuerAltName=issuer:copy
+
+nsCaRevocationUrl = $CRLDISTPT
+#nsBaseUrl
+#nsRevocationUrl
+#nsRenewalUrl
+#nsCaPolicyUrl
+#nsSslServerName
+
+#Extended Key requirements for our domain controller certs
+# serverAuth - says cert can be used to identify an ssl/tls server
+# msKDC - says cert can be used to identify a Kerberos Domain Controller.
+extendedKeyUsage = clientAuth,serverAuth,msKDC
+
+[dc_subjalt]
+DNS=@@DC_DNS_NAME@@
+otherName=msADGUID;FORMAT:HEX,OCTETSTRING:@@DC_OBJECTGUID_HEX@@
diff --git a/selftest/manage-ca/manage-ca.templates.d/openssl-USER-template.cnf b/selftest/manage-ca/manage-ca.templates.d/openssl-USER-template.cnf
new file mode 100644
index 00000000000..71674b9c07c
--- /dev/null
+++ b/selftest/manage-ca/manage-ca.templates.d/openssl-USER-template.cnf
@@ -0,0 +1,41 @@
+#[ usr_cert_scarduser ]
+[ template_x509_extensions ]
+
+# These extensions are added when 'ca' signs a request for a certificate that will be used to login from a smart card
+
+# This goes against PKIX guidelines but some CAs do it and some software
+# requires this to avoid interpreting an end user certificate as a CA.
+
+basicConstraints=CA:FALSE
+crlDistributionPoints=URI:$CRLDISTPT
+
+# For normal client use this is typical
+nsCertType = client, email
+
+# This is typical in keyUsage for a client certificate.
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+# This will be displayed in Netscape's comment listbox.
+nsComment = "Smart Card Login Certificate for @@USER_PRINCIPAL_NAME@@"
+
+# PKIX recommendations harmless if included in all certificates.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+
+# This stuff is for subjectAltName and issuerAltname.
+
+subjectAltName=email:copy,otherName:msUPN;UTF8:@@USER_PRINCIPAL_NAME@@
+
+# Copy subject details
+issuerAltName=issuer:copy
+
+nsCaRevocationUrl = $CRLDISTPT
+#nsBaseUrl
+#nsRevocationUrl
+#nsRenewalUrl
+#nsCaPolicyUrl
+#nsSslServerName
+
+#Extended Key requirements for client certs
+extendedKeyUsage = clientAuth,scardLogin
+
diff --git a/selftest/selftest.pl b/selftest/selftest.pl
index 1d5826da5ea..4d82b31487b 100755
--- a/selftest/selftest.pl
+++ b/selftest/selftest.pl
@@ -27,6 +27,7 @@ use Cwd qw(abs_path);
use lib "$RealBin";
use Subunit;
use SocketWrapper;
+use target::Samba;
eval {
require Time::HiRes;
@@ -505,6 +506,42 @@ sub write_clientconf($$$)
mkdir("$clientdir/ncalrpcdir", 0755);
umask $mask;
+ my $cadir = "$ENV{SRCDIR_ABS}/selftest/manage-ca/CA-samba.example.com";
+ my $cacert = "$cadir/Public/CA-samba.example.com-cert.pem";
+ my $cacrl_pem = "$cadir/Public/CA-samba.example.com-crl.pem";
+ my $ca_users_dir = "$cadir/Users";
+
+ if ( -d "$clientdir/pkinit" ) {
+ unlink <$clientdir/pkinit/*>;
+ } else {
+ mkdir("$clientdir/pkinit", 0700);
+ }
+
+ # each user has a USER-${USER_PRINCIPAL_NAME}-cert.pem and
+ # USER-${USER_PRINCIPAL_NAME}-private-key.pem symlink
+ # We make a copy here and make the certificated easily
+ # accessable in the client environment.
+ my $mask = umask;
+ umask 0077;
+ opendir USERS, "${ca_users_dir}" or die "Could not open dir '${ca_users_dir}': $!";
+ for my $d (readdir USERS) {
+ my $user_dir = "${ca_users_dir}/${d}";
+ next if ${d} =~ /^\./;
+ next if (! -d "${user_dir}");
+ opendir USER, "${user_dir}" or die "Could not open dir '${user_dir}': $!";
+ for my $l (readdir USER) {
+ my $user_link = "${user_dir}/${l}";
+ next if ${l} =~ /^\./;
+ next if (! -l "${user_link}");
+
+ my $dest = "${clientdir}/pkinit/${l}";
+ Samba::copy_file_content(${user_link}, ${dest});
+ }
+ closedir USER;
+ }
+ closedir USERS;
+ umask $mask;
+
open(CF, ">$conffile");
print CF "[global]\n";
print CF "\tnetbios name = client\n";
@@ -538,6 +575,9 @@ sub write_clientconf($$$)
#We don't want to run 'speed' tests for very long
torture:timelimit = 1
winbind separator = /
+ tls cafile = ${cacert}
+ tls crlfile = ${cacrl_pem}
+ tls verify peer = no_check
";
close(CF);
}
diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm
index ccc63f3713d..dabe442c142 100644
--- a/selftest/target/Samba.pm
+++ b/selftest/target/Samba.pm
@@ -75,6 +75,111 @@ sub nss_wrapper_winbind_so_path($) {
return $ret;
}
+sub copy_file_content($$)
+{
+ my ($in, $out) = @_;
+ open(IN, "${in}") or die("failed to open in[${in}] for reading: $!");
+ open(OUT, ">${out}") or die("failed to open out[${out}] for writing: $!");
+ while(<IN>) {
+ print OUT $_;
+ }
+ close(OUT);
+ close(IN);
+}
+
+sub prepare_keyblobs($)
+{
+ my ($ctx) = @_;
+
+ my $cadir = "$ENV{SRCDIR_ABS}/selftest/manage-ca/CA-samba.example.com";
+ my $cacert = "$cadir/Public/CA-samba.example.com-cert.pem";
+ my $cacrl_pem = "$cadir/Public/CA-samba.example.com-crl.pem";
+ my $dcdnsname = "$ctx->{hostname}.$ctx->{dnsname}";
+ my $dcdir = "$cadir/DCs/$dcdnsname";
+ my $dccert = "$dcdir/DC-$dcdnsname-cert.pem";
+ my $dckey_private = "$dcdir/DC-$dcdnsname-private-key.pem";
+ my $userprincipalname = "administrator\@$ctx->{dnsname}";
+ my $userdir = "$cadir/Users/$userprincipalname";
+ my $usercert = "$userdir/USER-$userprincipalname-cert.pem";
+ my $userkey_private = "$userdir/USER-$userprincipalname-private-key.pem";
+
+ my $tlsdir = "$ctx->{tlsdir}";
+ my $pkinitdir = "$ctx->{prefix_abs}/pkinit";
+ #TLS and PKINIT crypto blobs
+ my $dhfile = "$tlsdir/dhparms.pem";
+ my $cafile = "$tlsdir/ca.pem";
+ my $crlfile = "$tlsdir/crl.pem";
+ my $certfile = "$tlsdir/cert.pem";
+ my $keyfile = "$tlsdir/key.pem";
+ my $usercertfile = "$pkinitdir/USER-$userprincipalname-cert.pem";
+ my $userkeyfile = "$pkinitdir/USER-$userprincipalname-private-key.pem";
+
+ mkdir($tlsdir, 0700);
+ mkdir($pkinitdir, 0700);
+ my $oldumask = umask;
+ umask 0077;
+
+ # This is specified here to avoid draining entropy on every run
+ # generate by
+ # openssl dhparam -out dhparms.pem -text -2 8192
+ open(DHFILE, ">$dhfile");
+ print DHFILE <<EOF;
+-----BEGIN DH PARAMETERS-----
+MIIECAKCBAEAlcpjuJptCzC2bIIApLuyFLw2nODQUztqs/peysY9e3LgWh/xrc87
+SWJNSUrqFJFh2m357WH0XGcTdTk0b/8aIYIWjbwEhWR/5hZ+1x2TDrX1awkYayAe
+pr0arycmWHaAmhw+m+dBdj2O2jRMe7gn0ha85JALNl+Z3wv2q2eys8TIiQ2dbHPx
+XvpMmlAv7QHZnpSpX/XgueQr6T3EYggljppZwk1fe4W2cxBjCv9w/Q83pJXMEVVB
+WESEQPZC38v6hVIXIlF4J7jXjV3+NtCLL4nvsy0jrLEntyKz5OB8sNPRzJr0Ju2Y
+yXORCSMMXMygP+dxJtQ6txzQYWyaCYN1HqHDZy3cFL9Qy8kTFqIcW56Lti2GsW/p
+jSMzEOa1NevhKNFL3dSZJx5m+5ZeMvWXlCqXSptmVdbs5wz5jkMUm/E6pVfM5lyb
+Ttlcq2iYPqnJz1jcL5xwhoufID8zSJCPJ7C0jb0Ngy5wLIUZfjXJUXxUyxTnNR9i
+N9Sc+UkDvLxnCW+qzjyPXGlQU1SsJwMLWa2ZecL/uYE4bOdcN3g+5WHkevyDnXqR
++yy9x7sGXjBT3bRWK5tVHJWOi6eBu1hp39U6aK8oOJWiUt3vmC2qEdIsT6JaLNNi
+YKrSfRGBf19IJBaagen1S19bb3dnmwoU1RaWM0EeJQW1oXOBg7zLisB2yuu5azBn
+tse00+0nc+GbH2y+jP0sE7xil1QeilZl+aQ3tX9vL0cnCa+8602kXxU7P5HaX2+d
+05pvoHmeZbDV85io36oF976gBYeYN+qAkTUMsIZhuLQDuyn0963XOLyn1Pm6SBrU
+OkIZXW7WoKEuO/YSfizUIqXwmAMJjnEMJCWG51MZZKx//9Hsdp1RXSm/bRSbvXB7
+MscjvQYWmfCFnIk8LYnEt3Yey40srEiS9xyZqdrvobxz+sU1XcqR38kpVf4gKASL
+xURia64s4emuJF+YHIObyydazQ+6/wX/C+m+nyfhuxSO6j1janPwtYbU+Uj3TzeM
+04K1mpPQpZcaMdZZiNiu7i8VJlOPKAz7aJT8TnMMF5GMyzyLpSMpc+NF9L/BSocV
+/cUM4wQT2PTHrcyYzmTVH7c9bzBkuxqrwVB1BY1jitDV9LIYIVBglKcX88qrfHIM
+XiXPAIwGclD59qm2cG8OdM9NA5pNMI119KuUAIJsUdgPbR1LkT2XTT15YVoHmFSQ
+DlaWOXn4td031jr0EisX8QtFR7+/0Nfoni6ydFGs5fNH/L1ckq6FEO4OhgucJw9H
+YRmiFlsQBQNny78vNchwZne3ZixkShtGW0hWDdi2n+h7St1peNJCNJjMbEhRsPRx
+RmNGWh4AL8rho4RO9OBao0MnUdjbbffD+wIBAg==
+-----END DH PARAMETERS-----
+EOF
+ close(DHFILE);
+
+ if (! -e ${dckey_private}) {
+ umask $oldumask;
+ return;
+ }
+
+ copy_file_content(${cacert}, ${cafile});
+ copy_file_content(${cacrl_pem}, ${crlfile});
+ copy_file_content(${dccert}, ${certfile});
+ copy_file_content(${dckey_private}, ${keyfile});
+ if (-e ${userkey_private}) {
+ copy_file_content(${usercert}, ${usercertfile});
+ copy_file_content(${userkey_private}, ${userkeyfile});
+ }
+
+ # COMPAT stuff to be removed in a later commit
+ my $kdccertfile = "$tlsdir/kdc.pem";
+ copy_file_content(${dccert}, ${kdccertfile});
+ if (-e ${userkey_private}) {
+ my $adminkeyfile = "$tlsdir/adminkey.pem";
+ my $admincertfile = "$tlsdir/admincert.pem";
+ my $admincertupnfile = "$tlsdir/admincertupn.pem";
+ copy_file_content(${userkey_private}, ${adminkeyfile});
+ copy_file_content(${usercert}, ${admincertfile});
+ copy_file_content(${usercert}, ${admincertupnfile});
+ }
+
+ umask $oldumask;
+}
+
sub mk_krb5_conf($$)
{
my ($ctx, $other_realms_stanza) = @_;
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index ac8bfb7c606..bb1fd5b08cb 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -210,6 +210,7 @@ sub setup_s3dc($$)
domain master = yes
domain logons = yes
lanman auth = yes
+ raw NTLMv2 auth = yes
rpc_server:epmapper = external
rpc_server:spoolss = external
diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index ab3124858c9..7ea154407c9 100755
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -247,219 +247,6 @@ sub mk_openldap($$)
return ($slapd_conf_d, $pidfile);
}
-sub mk_keyblobs($$)
-{
- my ($self, $tlsdir) = @_;
-
- #TLS and PKINIT crypto blobs
- my $dhfile = "$tlsdir/dhparms.pem";
- my $cafile = "$tlsdir/ca.pem";
- my $certfile = "$tlsdir/cert.pem";
- my $reqkdc = "$tlsdir/req-kdc.der";
- my $kdccertfile = "$tlsdir/kdc.pem";
- my $keyfile = "$tlsdir/key.pem";
- my $adminkeyfile = "$tlsdir/adminkey.pem";
- my $reqadmin = "$tlsdir/req-admin.der";
- my $admincertfile = "$tlsdir/admincert.pem";
- my $admincertupnfile = "$tlsdir/admincertupn.pem";
-
- mkdir($tlsdir, 0700);
- my $oldumask = umask;
- umask 0077;
-
- #This is specified here to avoid draining entropy on every run
- open(DHFILE, ">$dhfile");
- print DHFILE <<EOF;
------BEGIN DH PARAMETERS-----
-MGYCYQC/eWD2xkb7uELmqLi+ygPMKyVcpHUo2yCluwnbPutEueuxrG/Cys8j8wLO
-svCN/jYNyR2NszOmg7ZWcOC/4z/4pWDVPUZr8qrkhj5MRKJc52MncfaDglvEdJrv
-YX70obsCAQI=
------END DH PARAMETERS-----
-EOF
- close(DHFILE);
-
- #Likewise, we pregenerate the key material. This allows the
- #other certificates to be pre-generated
- open(KEYFILE, ">$keyfile");
- print KEYFILE <<EOF;
------BEGIN RSA PRIVATE KEY-----
-MIICXQIBAAKBgQDKg6pAwCHUMA1DfHDmWhZfd+F0C+9Jxcqvpw9ii9En3E1uflpc
-ol3+S9/6I/uaTmJHZre+DF3dTzb/UOZo0Zem8N+IzzkgoGkFafjXuT3BL5UPY2/H
-6H+pPqVIRLOmrWImai359YyoKhFyo37Y6HPeU8QcZ+u2rS9geapIWfeuowIDAQAB
-AoGAAqDLzFRR/BF1kpsiUfL4WFvTarCe9duhwj7ORc6fs785qAXuwUYAJ0Uvzmy6
-HqoGv3t3RfmeHDmjcpPHsbOKnsOQn2MgmthidQlPBMWtQMff5zdoYNUFiPS0XQBq
-szNW4PRjaA9KkLQVTwnzdXGkBSkn/nGxkaVu7OR3vJOBoo0CQQDO4upypesnbe6p
-9/xqfZ2uim8IwV1fLlFClV7WlCaER8tsQF4lEi0XSzRdXGUD/dilpY88Nb+xok/X
-8Z8OvgAXAkEA+pcLsx1gN7kxnARxv54jdzQjC31uesJgMKQXjJ0h75aUZwTNHmZQ
-vPxi6u62YiObrN5oivkixwFNncT9MxTxVQJBAMaWUm2SjlLe10UX4Zdm1MEB6OsC
-kVoX37CGKO7YbtBzCfTzJGt5Mwc1DSLA2cYnGJqIfSFShptALlwedot0HikCQAJu
-jNKEKnbf+TdGY8Q0SKvTebOW2Aeg80YFkaTvsXCdyXrmdQcifw4WdO9KucJiDhSz
-Y9hVapz7ykEJtFtWjLECQQDIlfc63I5ZpXfg4/nN4IJXUW6AmPVOYIA5215itgki
-cSlMYli1H9MEXH0pQMGv5Qyd0OYIx2DDg96mZ+aFvqSG
------END RSA PRIVATE KEY-----
-EOF
- close(KEYFILE);
-
- open(ADMINKEYFILE, ">$adminkeyfile");
-
- print ADMINKEYFILE <<EOF;
------BEGIN RSA PRIVATE KEY-----
-MIICXQIBAAKBgQD0+OL7TQBj0RejbIH1+g5GeRaWaM9xF43uE5y7jUHEsi5owhZF
-5iIoHZeeL6cpDF5y1BZRs0JlA1VqMry1jjKlzFYVEMMFxB6esnXhl0Jpip1JkUMM
-XLOP1m/0dqayuHBWozj9f/cdyCJr0wJIX1Z8Pr+EjYRGPn/MF0xdl3JRlwIDAQAB
-AoGAP8mjCP628Ebc2eACQzOWjgEvwYCPK4qPmYOf1zJkArzG2t5XAGJ5WGrENRuB
-cm3XFh1lpmaADl982UdW3gul4gXUy6w4XjKK4vVfhyHj0kZ/LgaXUK9BAGhroJ2L
-osIOUsaC6jdx9EwSRctwdlF3wWJ8NK0g28AkvIk+FlolW4ECQQD7w5ouCDnf58CN
-u4nARx4xv5XJXekBvOomkCQAmuOsdOb6b9wn3mm2E3au9fueITjb3soMR31AF6O4
-eAY126rXAkEA+RgHzybzZEP8jCuznMqoN2fq/Vrs6+W3M8/G9mzGEMgLLpaf2Jiz
-I9tLZ0+OFk9tkRaoCHPfUOCrVWJZ7Y53QQJBAMhoA6rw0WDyUcyApD5yXg6rusf4
-ASpo/tqDkqUIpoL464Qe1tjFqtBM3gSXuhs9xsz+o0bzATirmJ+WqxrkKTECQHt2
-OLCpKqwAspU7N+w32kaUADoRLisCEdrhWklbwpQgwsIVsCaoEOpt0CLloJRYTANE
-yoZeAErTALjyZYZEPcECQQDlUi0N8DFxQ/lOwWyR3Hailft+mPqoPCa8QHlQZnlG
-+cfgNl57YHMTZFwgUVFRdJNpjH/WdZ5QxDcIVli0q+Ko
------END RSA PRIVATE KEY-----
-EOF
-
- #generated with
- # hxtool issue-certificate --self-signed --issue-ca \
- # --ca-private-key="FILE:$KEYFILE" \
- # --subject="CN=CA,DC=samba,DC=example,DC=com" \
- # --certificate="FILE:$CAFILE" --lifetime="25 years"
-
- open(CAFILE, ">$cafile");
- print CAFILE <<EOF;
------BEGIN CERTIFICATE-----
-MIICcTCCAdqgAwIBAgIUaBPmjnPVqyFqR5foICmLmikJTzgwCwYJKoZIhvcNAQEFMFIxEzAR
-BgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMRUwEwYKCZImiZPy
-LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDgwMzAxMTIyMzEyWhgPMjAzMzAyMjQx
-MjIzMTJaMFIxEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl
-MRUwEwYKCZImiZPyLGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMIGfMA0GCSqGSIb3DQEBAQUA
-A4GNADCBiQKBgQDKg6pAwCHUMA1DfHDmWhZfd+F0C+9Jxcqvpw9ii9En3E1uflpcol3+S9/6
-I/uaTmJHZre+DF3dTzb/UOZo0Zem8N+IzzkgoGkFafjXuT3BL5UPY2/H6H+pPqVIRLOmrWIm
-ai359YyoKhFyo37Y6HPeU8QcZ+u2rS9geapIWfeuowIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC
-AaYwHQYDVR0OBBYEFMLZufegDKLZs0VOyFXYK1L6M8oyMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
-KoZIhvcNAQEFBQADgYEAAZJbCAAkaqgFJ0xgNovn8Ydd0KswQPjicwiODPgw9ZPoD2HiOUVO
-yYDRg/dhFF9y656OpcHk4N7qZ2sl3RlHkzDu+dseETW+CnKvQIoXNyeARRJSsSlwrwcoD4JR
-HTLk2sGigsWwrJ2N99sG/cqSJLJ1MFwLrs6koweBnYU0f/g=
------END CERTIFICATE-----
-EOF
-
- #generated with GNUTLS internally in Samba.
-
- open(CERTFILE, ">$certfile");
- print CERTFILE <<EOF;
------BEGIN CERTIFICATE-----
-MIICYTCCAcygAwIBAgIE5M7SRDALBgkqhkiG9w0BAQUwZTEdMBsGA1UEChMUU2Ft
-YmEgQWRtaW5pc3RyYXRpb24xNDAyBgNVBAsTK1NhbWJhIC0gdGVtcG9yYXJ5IGF1
-dG9nZW5lcmF0ZWQgY2VydGlmaWNhdGUxDjAMBgNVBAMTBVNhbWJhMB4XDTA2MDgw
-NDA0MzY1MloXDTA4MDcwNDA0MzY1MlowZTEdMBsGA1UEChMUU2FtYmEgQWRtaW5p
-c3RyYXRpb24xNDAyBgNVBAsTK1NhbWJhIC0gdGVtcG9yYXJ5IGF1dG9nZW5lcmF0
-ZWQgY2VydGlmaWNhdGUxDjAMBgNVBAMTBVNhbWJhMIGcMAsGCSqGSIb3DQEBAQOB
-jAAwgYgCgYDKg6pAwCHUMA1DfHDmWhZfd+F0C+9Jxcqvpw9ii9En3E1uflpcol3+
-S9/6I/uaTmJHZre+DF3dTzb/UOZo0Zem8N+IzzkgoGkFafjXuT3BL5UPY2/H6H+p
-PqVIRLOmrWImai359YyoKhFyo37Y6HPeU8QcZ+u2rS9geapIWfeuowIDAQABoyUw
-IzAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAsGCSqGSIb3DQEB
-BQOBgQAmkN6XxvDnoMkGcWLCTwzxGfNNSVcYr7TtL2aJh285Xw9zaxcm/SAZBFyG
-LYOChvh6hPU7joMdDwGfbiLrBnMag+BtGlmPLWwp/Kt1wNmrRhduyTQFhN3PP6fz
-nBr9vVny2FewB2gHmelaPS//tXdxivSXKz3NFqqXLDJjq7P8wA==
------END CERTIFICATE-----
-EOF
- close(CERTFILE);
-
- #KDC certificate
- # hxtool request-create \
- # --subject="CN=krbtgt,CN=users,DC=samba,DC=example,DC=com" \
- # --key="FILE:$KEYFILE" $KDCREQ
-
- # hxtool issue-certificate --ca-certificate=FILE:$CAFILE,$KEYFILE \
- # --type="pkinit-kdc" \
- # --pk-init-principal="krbtgt/SAMBA.EXAMPLE.COM@SAMBA.EXAMPLE.COM" \
- # --req="PKCS10:$KDCREQ" --certificate="FILE:$KDCCERTFILE" \
- # --lifetime="25 years"
-
- open(KDCCERTFILE, ">$kdccertfile");
- print KDCCERTFILE <<EOF;
------BEGIN CERTIFICATE-----
-MIIDDDCCAnWgAwIBAgIUI2Tzj+JnMzMcdeabcNo30rovzFAwCwYJKoZIhvcNAQEFMFIxEzAR
-BgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMRUwEwYKCZImiZPy
-LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDgwMzAxMTMxOTIzWhgPMjAzMzAyMjQx
-MzE5MjNaMGYxEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl
-MRUwEwYKCZImiZPyLGQBGQwFc2FtYmExDjAMBgNVBAMMBXVzZXJzMQ8wDQYDVQQDDAZrcmJ0
-Z3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMqDqkDAIdQwDUN8cOZaFl934XQL70nF
-yq+nD2KL0SfcTW5+WlyiXf5L3/oj+5pOYkdmt74MXd1PNv9Q5mjRl6bw34jPOSCgaQVp+Ne5
-PcEvlQ9jb8fof6k+pUhEs6atYiZqLfn1jKgqEXKjftjoc95TxBxn67atL2B5qkhZ966jAgMB
-AAGjgcgwgcUwDgYDVR0PAQH/BAQDAgWgMBIGA1UdJQQLMAkGBysGAQUCAwUwVAYDVR0RBE0w
-S6BJBgYrBgEFAgKgPzA9oBMbEVNBTUJBLkVYQU1QTEUuQ09NoSYwJKADAgEBoR0wGxsGa3Ji
-dGd0GxFTQU1CQS5FWEFNUExFLkNPTTAfBgNVHSMEGDAWgBTC2bn3oAyi2bNFTshV2CtS+jPK
-MjAdBgNVHQ4EFgQUwtm596AMotmzRU7IVdgrUvozyjIwCQYDVR0TBAIwADANBgkqhkiG9w0B
-AQUFAAOBgQBmrVD5MCmZjfHp1nEnHqTIh8r7lSmVtDx4s9MMjxm9oNrzbKXynvdhwQYFVarc
-ge4yRRDXtSebErOl71zVJI9CVeQQpwcH+tA85oGA7oeFtO/S7ls581RUU6tGgyxV4veD+lJv
-KPH5LevUtgD+q9H4LU4Sq5N3iFwBaeryB0g2wg==
------END CERTIFICATE-----
-EOF
-
- # hxtool request-create \
- # --subject="CN=Administrator,CN=users,DC=samba,DC=example,DC=com" \
- # --key="FILE:$ADMINKEYFILE" $ADMINREQFILE
-
- # hxtool issue-certificate --ca-certificate=FILE:$CAFILE,$KEYFILE \
- # --type="pkinit-client" \
- # --pk-init-principal="administrator@SAMBA.EXAMPLE.COM" \
- # --req="PKCS10:$ADMINREQFILE" --certificate="FILE:$ADMINCERTFILE" \
- # --lifetime="25 years"
-
- open(ADMINCERTFILE, ">$admincertfile");
- print ADMINCERTFILE <<EOF;
------BEGIN CERTIFICATE-----
-MIIDHTCCAoagAwIBAgIUUggzW4lLRkMKe1DAR2NKatkMDYwwCwYJKoZIhvcNAQELMFIxEzAR
-BgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMRUwEwYKCZImiZPy
-LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDkwNzI3MDMzMjE1WhgPMjAzNDA3MjIw
-MzMyMTVaMG0xEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl
-MRUwEwYKCZImiZPyLGQBGQwFc2FtYmExDjAMBgNVBAMMBXVzZXJzMRYwFAYDVQQDDA1BZG1p
-bmlzdHJhdG9yMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0+OL7TQBj0RejbIH1+g5G
-eRaWaM9xF43uE5y7jUHEsi5owhZF5iIoHZeeL6cpDF5y1BZRs0JlA1VqMry1jjKlzFYVEMMF
-xB6esnXhl0Jpip1JkUMMXLOP1m/0dqayuHBWozj9f/cdyCJr0wJIX1Z8Pr+EjYRGPn/MF0xd
-l3JRlwIDAQABo4HSMIHPMA4GA1UdDwEB/wQEAwIFoDAoBgNVHSUEITAfBgcrBgEFAgMEBggr
-BgEFBQcDAgYKKwYBBAGCNxQCAjBIBgNVHREEQTA/oD0GBisGAQUCAqAzMDGgExsRU0FNQkEu
-RVhBTVBMRS5DT02hGjAYoAMCAQGhETAPGw1BZG1pbmlzdHJhdG9yMB8GA1UdIwQYMBaAFMLZ
-ufegDKLZs0VOyFXYK1L6M8oyMB0GA1UdDgQWBBQg81bLyfCA88C2B/BDjXlGuaFaxjAJBgNV
-HRMEAjAAMA0GCSqGSIb3DQEBCwUAA4GBAEf/OSHUDJaGdtWGNuJeqcVYVMwrfBAc0OSwVhz1
-7/xqKHWo8wIMPkYRtaRHKLNDsF8GkhQPCpVsa6mX/Nt7YQnNvwd+1SBP5E8GvwWw9ZzLJvma
-nk2n89emuayLpVtp00PymrDLRBcNaRjFReQU8f0o509kiVPHduAp3jOiy13l
------END CERTIFICATE-----
-EOF
- close(ADMINCERTFILE);
-
- # hxtool issue-certificate --ca-certificate=FILE:$CAFILE,$KEYFILE \
- # --type="pkinit-client" \
- # --ms-upn="administrator@samba.example.com" \
- # --req="PKCS10:$ADMINREQFILE" --certificate="FILE:$ADMINCERTUPNFILE" \
- # --lifetime="25 years"
-
- open(ADMINCERTUPNFILE, ">$admincertupnfile");
- print ADMINCERTUPNFILE <<EOF;
------BEGIN CERTIFICATE-----
-MIIDDzCCAnigAwIBAgIUUp3CJMuNaEaAdPKp3QdNIwG7a4wwCwYJKoZIhvcNAQELMFIxEzAR
-BgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMRUwEwYKCZImiZPy
-LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDkwNzI3MDMzMzA1WhgPMjAzNDA3MjIw
-MzMzMDVaMG0xEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl
-MRUwEwYKCZImiZPyLGQBGQwFc2FtYmExDjAMBgNVBAMMBXVzZXJzMRYwFAYDVQQDDA1BZG1p
-bmlzdHJhdG9yMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0+OL7TQBj0RejbIH1+g5G
-eRaWaM9xF43uE5y7jUHEsi5owhZF5iIoHZeeL6cpDF5y1BZRs0JlA1VqMry1jjKlzFYVEMMF
-xB6esnXhl0Jpip1JkUMMXLOP1m/0dqayuHBWozj9f/cdyCJr0wJIX1Z8Pr+EjYRGPn/MF0xd
-l3JRlwIDAQABo4HEMIHBMA4GA1UdDwEB/wQEAwIFoDAoBgNVHSUEITAfBgcrBgEFAgMEBggr
-BgEFBQcDAgYKKwYBBAGCNxQCAjA6BgNVHREEMzAxoC8GCisGAQQBgjcUAgOgIQwfYWRtaW5p
-c3RyYXRvckBzYW1iYS5leGFtcGxlLmNvbTAfBgNVHSMEGDAWgBTC2bn3oAyi2bNFTshV2CtS
-+jPKMjAdBgNVHQ4EFgQUIPNWy8nwgPPAtgfwQ415RrmhWsYwCQYDVR0TBAIwADANBgkqhkiG
-9w0BAQsFAAOBgQBk42+egeUB3Ji2PC55fbt3FNKxvmm2xUUFkV9POK/YR9rajKOwk5jtYSeS
-Zd7J9s//rNFNa7waklFkDaY56+QWTFtdvxfE+KoHaqt6X8u6pqi7p3M4wDKQox+9Dx8yWFyq
-Wfz/8alZ5aMezCQzXJyIaJsCLeKABosSwHcpAFmxlQ==
------END CERTIFICATE-----
-EOF
-
- umask $oldumask;
-}
-
sub provision_raw_prepare($$$$$$$$$$)
{
my ($self, $prefix, $server_role, $hostname,
@@ -611,6 +398,11 @@ sub provision_raw_step1($$)
warn("can't open $ctx->{smb_conf}$?");
return undef;
}
+
+ Samba::prepare_keyblobs($ctx);
+ my $crlfile = "$ctx->{tlsdir}/crl.pem";
+ $crlfile = "" unless -e ${crlfile};
+
print CONFFILE "
[global]
netbios name = $ctx->{netbiosname}
@@ -630,6 +422,8 @@ sub provision_raw_step1($$)
name resolve order = file bcast
interfaces = $ctx->{interfaces}
tls dh params file = $ctx->{tlsdir}/dhparms.pem
+ tls crlfile = ${crlfile}
+ tls verify peer = no_check
panic action = $RealBin/gdb_backtrace \%d
wins support = yes
server role = $ctx->{server_role}
@@ -637,6 +431,7 @@ sub provision_raw_step1($$)
dcerpc endpoint servers = +winreg +srvsvc
notify:inotify = false
ldb:nosync = true
+ ldap server require strong auth = yes
#We don't want to pass our self-tests if the PAC code is wrong
gensec:require_pac = true
log file = $ctx->{logdir}/log.\%m
@@ -668,8 +463,6 @@ sub provision_raw_step1($$)
";
close(CONFFILE);
- $self->mk_keyblobs($ctx->{tlsdir});
-
#Default the KDC IP to the server's IP
if (not defined($ctx->{kdc_ipv4})) {
$ctx->{kdc_ipv4} = $ctx->{ipv4};
@@ -1314,7 +1107,9 @@ sub provision_dc($$)
print "PROVISIONING DC...";
my $extra_conf_options = "netbios aliases = localDC1-a
- server services = +winbind -winbindd";
+ server services = +winbind -winbindd
+ ldap server require strong auth = allow_sasl_over_tls
+ ";
my $ret = $self->provision($prefix,
"domain controller",
"localdc",
@@ -1420,6 +1215,7 @@ sub provision_fl2008r2dc($$)
my ($self, $prefix) = @_;
print "PROVISIONING DC...";
+ my $extra_conf_options = "ldap server require strong auth = no";
my $ret = $self->provision($prefix,
"domain controller",
"dc7",
@@ -1427,7 +1223,8 @@ sub provision_fl2008r2dc($$)
"samba2008R2.example.com",
"2008_R2",
"locDCpass7",
- undef, "", "", undef);
+ undef, $extra_conf_options,
+ "", undef);
unless ($self->add_wins_config("$prefix/private")) {
warn("Unable to add wins configuration");
@@ -1615,7 +1412,7 @@ sub provision_plugin_s4_dc($$)
"domain controller",
"plugindc",
"PLUGINDOMAIN",
- "plugindc.samba.example.com",
+ "plugindom.samba.example.com",
"2008",
"locDCpass1",
undef, $extra_smbconf_options,
diff --git a/selftest/tests/__init__.py b/selftest/tests/__init__.py
index 85d0316b464..ee536630ce1 100644
--- a/selftest/tests/__init__.py
+++ b/selftest/tests/__init__.py
@@ -19,8 +19,6 @@
"""Tests for selftest."""
-from testtools import TestCase
-
import unittest
def test_suite():
diff --git a/selftest/tests/test_run.py b/selftest/tests/test_run.py
index de5f4b121bc..9b77516adb0 100644
--- a/selftest/tests/test_run.py
+++ b/selftest/tests/test_run.py
@@ -22,6 +22,7 @@
import datetime
import os
import subunit
+from samba.tests import TestCase
import tempfile
from selftest.run import (
@@ -33,7 +34,6 @@ from selftest.run import (
run_testsuite_command,
)
-from selftest.tests import TestCase
class ExpandEnvironmentStringsTests(TestCase):
diff --git a/selftest/tests/test_samba.py b/selftest/tests/test_samba.py
index b49463eabb9..23de0d34c73 100644
--- a/selftest/tests/test_samba.py
+++ b/selftest/tests/test_samba.py
@@ -21,7 +21,7 @@
from cStringIO import StringIO
-from selftest.tests import TestCase
+from samba.tests import TestCase
from selftest.target.samba import (
bindir_path,
diff --git a/selftest/tests/test_socket_wrapper.py b/selftest/tests/test_socket_wrapper.py
index 81fe5b603cf..e278fdddfa6 100644
--- a/selftest/tests/test_socket_wrapper.py
+++ b/selftest/tests/test_socket_wrapper.py
@@ -19,7 +19,7 @@
"""Tests for selftest/socket_wrapper."""
-from selftest.tests import TestCase
+from samba.tests import TestCase
from selftest import socket_wrapper
diff --git a/selftest/tests/test_target.py b/selftest/tests/test_target.py
index 00b7126a073..ed9b064961e 100644
--- a/selftest/tests/test_target.py
+++ b/selftest/tests/test_target.py
@@ -29,7 +29,7 @@ from selftest.target import (
UnsupportedEnvironment,
)
-from selftest.tests import TestCase
+from samba.tests import TestCase
class DummyEnvironment(Environment):
diff --git a/selftest/tests/test_testlist.py b/selftest/tests/test_testlist.py
index 7007d6d35a2..d82b00cefdb 100644
--- a/selftest/tests/test_testlist.py
+++ b/selftest/tests/test_testlist.py
@@ -22,7 +22,7 @@
import os
import tempfile
-from selftest.tests import TestCase
+from samba.tests import TestCase
from selftest.testlist import (
RestrictedTestManager,
diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c
index c3c54f343dd..b10162547eb 100644
--- a/source3/auth/auth_domain.c
+++ b/source3/auth/auth_domain.c
@@ -98,7 +98,7 @@ static NTSTATUS connect_to_domain_password_server(struct cli_state **cli_ret,
/* Attempt connection */
result = cli_full_connection(&cli, lp_netbios_name(), dc_name, dc_ss, 0,
- "IPC$", "IPC", "", "", "", 0, SMB_SIGNING_DEFAULT);
+ "IPC$", "IPC", "", "", "", 0, SMB_SIGNING_IPC_DEFAULT);
if (!NT_STATUS_IS_OK(result)) {
/* map to something more useful */
diff --git a/source3/auth/auth_samba4.c b/source3/auth/auth_samba4.c
index 0a80d173355..4f37fea7ac6 100644
--- a/source3/auth/auth_samba4.c
+++ b/source3/auth/auth_samba4.c
@@ -245,8 +245,8 @@ static NTSTATUS prepare_gensec(const struct auth_context *auth_context,
status = cli_credentials_set_machine_account(server_credentials, lp_ctx);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status)));
- talloc_free(server_credentials);
- server_credentials = NULL;
+ TALLOC_FREE(frame);
+ return status;
}
status = samba_server_gensec_start(mem_ctx,
diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index 2b355e45565..c1aa9978553 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -34,6 +34,7 @@
#include "../auth/auth_sam_reply.h"
#include "../librpc/gen_ndr/idmap.h"
#include "lib/param/loadparm.h"
+#include "../lib/tsocket/tsocket.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
@@ -353,6 +354,20 @@ NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx,
const struct tsocket_address *remote_address,
DATA_BLOB lm_resp, DATA_BLOB nt_resp)
{
+ bool allow_raw = lp_raw_ntlmv2_auth();
+
+ if (!allow_raw && nt_resp.length >= 48) {
+ /*
+ * NTLMv2_RESPONSE has at least 48 bytes
+ * and should only be supported via NTLMSSP.
+ */
+ DEBUG(2,("Rejecting raw NTLMv2 authentication with "
+ "user [%s\\%s] from[%s]\n",
+ client_domain, smb_name,
+ tsocket_address_string(remote_address, mem_ctx)));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
return make_user_info(mem_ctx,
user_info, smb_name, smb_name,
client_domain, client_domain,
diff --git a/source3/include/ads.h b/source3/include/ads.h
index 3de1d8b199e..daea56d58ee 100644
--- a/source3/include/ads.h
+++ b/source3/include/ads.h
@@ -13,7 +13,7 @@ struct ads_struct;
struct ads_saslwrap_ops {
const char *name;
- ADS_STATUS (*wrap)(struct ads_struct *, uint8 *buf, uint32 len);
+ ADS_STATUS (*wrap)(struct ads_struct *, uint8_t *buf, uint32_t len);
ADS_STATUS (*unwrap)(struct ads_struct *);
void (*disconnect)(struct ads_struct *);
};
@@ -53,7 +53,7 @@ typedef struct ads_struct {
/* info derived from the servers config */
struct {
- uint32 flags; /* cldap flags identifying the services. */
+ uint32_t flags; /* cldap flags identifying the services. */
char *realm;
char *bind_path;
char *ldap_server_name;
@@ -82,23 +82,23 @@ typedef struct ads_struct {
const struct ads_saslwrap_ops *wrap_ops;
void *wrap_private_data;
struct {
- uint32 ofs;
- uint32 needed;
- uint32 left;
+ uint32_t ofs;
+ uint32_t needed;
+ uint32_t left;
#define ADS_SASL_WRAPPING_IN_MAX_WRAPPED 0x0FFFFFFF
- uint32 max_wrapped;
- uint32 min_wrapped;
- uint32 size;
- uint8 *buf;
+ uint32_t max_wrapped;
+ uint32_t min_wrapped;
+ uint32_t size;
+ uint8_t *buf;
} in;
struct {
- uint32 ofs;
- uint32 left;
+ uint32_t ofs;
+ uint32_t left;
#define ADS_SASL_WRAPPING_OUT_MAX_WRAPPED 0x00A00000
- uint32 max_unwrapped;
- uint32 sig_size;
- uint32 size;
- uint8 *buf;
+ uint32_t max_unwrapped;
+ uint32_t sig_size;
+ uint32_t size;
+ uint8_t *buf;
} out;
} ldap;
#endif /* HAVE_LDAP */
diff --git a/source3/include/auth_generic.h b/source3/include/auth_generic.h
index 96b07cd8f77..a1558ea2e31 100644
--- a/source3/include/auth_generic.h
+++ b/source3/include/auth_generic.h
@@ -40,11 +40,12 @@ NTSTATUS auth_generic_set_password(struct auth_generic_state *ans,
NTSTATUS auth_generic_client_prepare(TALLOC_CTX *mem_ctx,
struct auth_generic_state **_ans);
NTSTATUS auth_generic_client_start(struct auth_generic_state *ans, const char *oid);
-
+NTSTATUS auth_generic_client_start_by_name(struct auth_generic_state *ans,
+ const char *name);
NTSTATUS auth_generic_client_start_by_authtype(struct auth_generic_state *ans,
uint8_t auth_type,
uint8_t auth_level);
-
-extern const struct gensec_security_ops gensec_ntlmssp3_client_ops;
+NTSTATUS auth_generic_client_start_by_sasl(struct auth_generic_state *ans,
+ const char **sasl_list);
#endif /* _AUTH_GENERIC_ */
diff --git a/source3/include/proto.h b/source3/include/proto.h
index ce23289bab4..be900246da4 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -732,13 +732,6 @@ bool wins_server_tag_ips(const char *tag, TALLOC_CTX *mem_ctx,
struct in_addr **pservers, int *pnum_servers);
unsigned wins_srv_count_tag(const char *tag);
-/* The following definitions come from libsmb/clispnego.c */
-
-DATA_BLOB spnego_gen_negTokenInit(TALLOC_CTX *ctx,
- const char *OIDs[],
- DATA_BLOB *psecblob,
- const char *principal);
-
#ifndef ASN1_MAX_OIDS
#define ASN1_MAX_OIDS 20
#endif
@@ -748,18 +741,6 @@ bool spnego_parse_negTokenInit(TALLOC_CTX *ctx,
char **principal,
DATA_BLOB *secblob);
DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const uint8 tok_id[2]);
-int spnego_gen_krb5_negTokenInit(TALLOC_CTX *ctx,
- const char *principal, int time_offset,
- DATA_BLOB *targ,
- DATA_BLOB *session_key_krb5, uint32 extra_ap_opts,
- const char *ccname, time_t *expire_time);
-bool spnego_parse_challenge(TALLOC_CTX *ctx, const DATA_BLOB blob,
- DATA_BLOB *chal1, DATA_BLOB *chal2);
-DATA_BLOB spnego_gen_auth(TALLOC_CTX *ctx, DATA_BLOB blob);
-bool spnego_parse_auth_response(TALLOC_CTX *ctx,
- DATA_BLOB blob, NTSTATUS nt_status,
- const char *mechOID,
- DATA_BLOB *auth);
/* The following definitions come from libsmb/conncache.c */
@@ -903,31 +884,6 @@ bool get_dc_name(const char *domain,
fstring srv_name,
struct sockaddr_storage *ss_out);
-/* The following definitions come from libsmb/ntlmssp.c */
-struct ntlmssp_state;
-NTSTATUS ntlmssp_set_username(struct ntlmssp_state *ntlmssp_state, const char *user) ;
-NTSTATUS ntlmssp_set_password(struct ntlmssp_state *ntlmssp_state, const char *password) ;
-NTSTATUS ntlmssp_set_password_hash(struct ntlmssp_state *ntlmssp_state,
- const char *hash);
-NTSTATUS ntlmssp_set_domain(struct ntlmssp_state *ntlmssp_state, const char *domain) ;
-void ntlmssp_want_feature_list(struct ntlmssp_state *ntlmssp_state, char *feature_list);
-void ntlmssp_want_feature(struct ntlmssp_state *ntlmssp_state, uint32_t feature);
-NTSTATUS ntlmssp_update(struct ntlmssp_state *ntlmssp_state,
- const DATA_BLOB in, DATA_BLOB *out) ;
-bool ntlmssp_is_anonymous(struct ntlmssp_state *ntlmssp_state);
-NTSTATUS ntlmssp_server_start(TALLOC_CTX *mem_ctx,
- bool is_standalone,
- const char *netbios_name,
- const char *netbios_domain,
- const char *dns_name,
- const char *dns_domain,
- struct ntlmssp_state **ntlmssp_state);
-NTSTATUS ntlmssp_client_start(TALLOC_CTX *mem_ctx,
- const char *netbios_name,
- const char *netbios_domain,
- bool use_ntlmv2,
- struct ntlmssp_state **_ntlmssp_state);
-
/* The following definitions come from libsmb/passchange.c */
NTSTATUS remote_password_change(const char *remote_machine, const char *user_name,
@@ -988,7 +944,9 @@ const char *lp_idmap_backend(const char *domain_name);
const char *lp_idmap_default_backend (void);
int lp_security(void);
int lp_client_max_protocol(void);
-int lp_winbindd_max_protocol(void);
+int lp_client_ipc_min_protocol(void);
+int lp_client_ipc_max_protocol(void);
+int lp_client_ipc_signing(void);
int lp_smb2_max_credits(void);
int lp_cups_encrypt(void);
bool lp_widelinks(int );
diff --git a/source3/lib/netapi/cm.c b/source3/lib/netapi/cm.c
index 801e61f4a45..e9f2863952f 100644
--- a/source3/lib/netapi/cm.c
+++ b/source3/lib/netapi/cm.c
@@ -88,7 +88,7 @@ static WERROR libnetapi_open_ipc_connection(struct libnetapi_ctx *ctx,
if (!auth_info) {
return WERR_NOMEM;
}
- auth_info->signing_state = SMB_SIGNING_DEFAULT;
+ auth_info->signing_state = SMB_SIGNING_IPC_DEFAULT;
set_cmdline_auth_info_use_kerberos(auth_info, ctx->use_kerberos);
set_cmdline_auth_info_username(auth_info, ctx->username);
if (ctx->password) {
diff --git a/source3/lib/tldap.c b/source3/lib/tldap.c
index 5d3773e4c7c..17238a547e0 100644
--- a/source3/lib/tldap.c
+++ b/source3/lib/tldap.c
@@ -1315,7 +1315,7 @@ done:
}
s++;
- if (data->has_error) {
+ if (asn1_has_error(data)) {
return false;
}
@@ -1529,7 +1529,7 @@ static bool tldap_push_filter_basic(struct tldap_context *ld,
if (!asn1_write_OctetString(data, uval, uval_len)) return false;
}
- if (data->has_error) {
+ if (asn1_has_error(data)) {
return false;
}
return asn1_pop_tag(data);
@@ -2019,7 +2019,7 @@ static bool tldap_decode_controls(struct tldap_req_state *state)
if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto out;
if (!asn1_read_OctetString_talloc(msg, data, &oid)) goto out;
- if ((data->has_error) || (oid == NULL)) {
+ if (asn1_has_error(data) || (oid == NULL)) {
goto out;
}
c->oid = oid;
diff --git a/source3/libads/ads_ldap_protos.h b/source3/libads/ads_ldap_protos.h
index 3024ae2ea65..b063815678a 100644
--- a/source3/libads/ads_ldap_protos.h
+++ b/source3/libads/ads_ldap_protos.h
@@ -51,7 +51,7 @@ char **ads_pull_strings_range(ADS_STRUCT *ads,
size_t *num_strings,
bool *more_strings);
bool ads_pull_uint32(ADS_STRUCT *ads, LDAPMessage *msg, const char *field,
- uint32 *v);
+ uint32_t *v);
bool ads_pull_guid(ADS_STRUCT *ads, LDAPMessage *msg, struct GUID *guid);
bool ads_pull_sid(ADS_STRUCT *ads, LDAPMessage *msg, const char *field,
struct dom_sid *sid);
@@ -120,12 +120,12 @@ ADS_STATUS ads_parse_gpo(ADS_STRUCT *ads,
const char *gpo_dn,
struct GROUP_POLICY_OBJECT *gpo);
ADS_STATUS ads_search_retry_dn_sd_flags(ADS_STRUCT *ads, LDAPMessage **res,
- uint32 sd_flags,
+ uint32_t sd_flags,
const char *dn,
const char **attrs);
ADS_STATUS ads_do_search_all_sd_flags(ADS_STRUCT *ads, const char *bind_path,
int scope, const char *expr,
- const char **attrs, uint32 sd_flags,
+ const char **attrs, uint32_t sd_flags,
LDAPMessage **res);
ADS_STATUS ads_get_tokensids(ADS_STRUCT *ads,
TALLOC_CTX *mem_ctx,
diff --git a/source3/libads/ads_proto.h b/source3/libads/ads_proto.h
index 1e34247e2fe..1399f41fbf7 100644
--- a/source3/libads/ads_proto.h
+++ b/source3/libads/ads_proto.h
@@ -66,7 +66,6 @@ bool ads_sitename_match(ADS_STRUCT *ads);
bool ads_closest_dc(ADS_STRUCT *ads);
ADS_STATUS ads_connect(ADS_STRUCT *ads);
ADS_STATUS ads_connect_user_creds(ADS_STRUCT *ads);
-ADS_STATUS ads_connect_gc(ADS_STRUCT *ads);
void ads_disconnect(ADS_STRUCT *ads);
ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
int scope, const char *expr, const char **attrs,
@@ -85,7 +84,7 @@ char *ads_ou_string(ADS_STRUCT *ads, const char *org_unit);
char *ads_default_ou_string(ADS_STRUCT *ads, const char *wknguid);
ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
const char *name, const char **vals);
-uint32 ads_get_kvno(ADS_STRUCT *ads, const char *account_name);
+uint32_t ads_get_kvno(ADS_STRUCT *ads, const char *account_name);
uint32_t ads_get_machine_kvno(ADS_STRUCT *ads, const char *machine_name);
bool ads_element_in_array(const char **el_array, size_t num_el, const char *el);
@@ -103,9 +102,9 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name,
ADS_STATUS ads_move_machine_acct(ADS_STRUCT *ads, const char *machine_name,
const char *org_unit, bool *moved);
int ads_count_replies(ADS_STRUCT *ads, void *res);
-ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn);
+ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32_t *usn);
ADS_STATUS ads_current_time(ADS_STRUCT *ads);
-ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32 *val);
+ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32_t *val);
ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, struct dom_sid *sid);
ADS_STATUS ads_site_dn(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char **site_name);
ADS_STATUS ads_site_dn_for_machine(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char *computer_name, const char **site_dn);
@@ -122,12 +121,12 @@ char* ads_get_dnshostname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine
char* ads_get_upn( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name );
char* ads_get_samaccountname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name );
ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name,
- uint32 account_type, const char *org_unit);
+ uint32_t account_type, const char *org_unit);
ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname);
ADS_STATUS ads_find_samaccount(ADS_STRUCT *ads,
TALLOC_CTX *mem_ctx,
const char *samaccountname,
- uint32 *uac_ret,
+ uint32_t *uac_ret,
const char **dn_ret);
ADS_STATUS ads_config_path(ADS_STRUCT *ads,
TALLOC_CTX *mem_ctx,
diff --git a/source3/libads/ads_status.c b/source3/libads/ads_status.c
index 7465531404d..70569949aeb 100644
--- a/source3/libads/ads_status.c
+++ b/source3/libads/ads_status.c
@@ -119,8 +119,8 @@ const char *ads_errstr(ADS_STATUS status)
case ENUM_ADS_ERROR_GSS:
{
char *ret;
- uint32 msg_ctx;
- uint32 minor;
+ uint32_t msg_ctx;
+ uint32_t minor;
gss_buffer_desc msg1, msg2;
msg_ctx = 0;
@@ -147,7 +147,7 @@ const char *ads_errstr(ADS_STATUS status)
}
#ifdef HAVE_KRB5
-NTSTATUS gss_err_to_ntstatus(uint32 maj, uint32 min)
+NTSTATUS gss_err_to_ntstatus(uint32_t maj, uint32_t min)
{
ADS_STATUS adss = ADS_ERROR_GSS(maj, min);
DEBUG(10,("gss_err_to_ntstatus: Error %s\n",
diff --git a/source3/libads/ads_status.h b/source3/libads/ads_status.h
index ff7c1036380..2ff4ef003b1 100644
--- a/source3/libads/ads_status.h
+++ b/source3/libads/ads_status.h
@@ -63,6 +63,6 @@ ADS_STATUS ads_build_nt_error(enum ads_error_type etype,
NTSTATUS nt_status);
NTSTATUS ads_ntstatus(ADS_STATUS status);
const char *ads_errstr(ADS_STATUS status);
-NTSTATUS gss_err_to_ntstatus(uint32 maj, uint32 min);
+NTSTATUS gss_err_to_ntstatus(uint32_t maj, uint32_t min);
#endif /* _LIBADS_ADS_STATUS_H_ */
diff --git a/source3/libads/disp_sec.c b/source3/libads/disp_sec.c
index 7dcdc95901e..472741fa1b6 100644
--- a/source3/libads/disp_sec.c
+++ b/source3/libads/disp_sec.c
@@ -29,7 +29,7 @@
#ifdef HAVE_LDAP
static struct perm_mask_str {
- uint32 mask;
+ uint32_t mask;
const char *str;
} perms[] = {
{SEC_RIGHTS_FULL_CTRL, "[Full Control]"},
@@ -59,7 +59,7 @@ static struct perm_mask_str {
};
/* convert a security permissions into a string */
-static void ads_disp_perms(uint32 type)
+static void ads_disp_perms(uint32_t type)
{
int i = 0;
int j = 0;
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index 6031b421e98..121ba08d0c0 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -476,139 +476,6 @@ static NTSTATUS ads_find_dc(ADS_STRUCT *ads)
return NT_STATUS_NO_LOGON_SERVERS;
}
-/*********************************************************************
- *********************************************************************/
-
-static NTSTATUS ads_lookup_site(void)
-{
- ADS_STRUCT *ads = NULL;
- ADS_STATUS ads_status;
- NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
-
- ads = ads_init(lp_realm(), NULL, NULL);
- if (!ads) {
- return NT_STATUS_NO_MEMORY;
- }
-
- /* The NO_BIND here will find a DC and set the client site
- but not establish the TCP connection */
-
- ads->auth.flags = ADS_AUTH_NO_BIND;
- ads_status = ads_connect(ads);
- if (!ADS_ERR_OK(ads_status)) {
- DEBUG(4, ("ads_lookup_site: ads_connect to our realm failed! (%s)\n",
- ads_errstr(ads_status)));
- }
- nt_status = ads_ntstatus(ads_status);
-
- if (ads) {
- ads_destroy(&ads);
- }
-
- return nt_status;
-}
-
-/*********************************************************************
- *********************************************************************/
-
-static const char* host_dns_domain(const char *fqdn)
-{
- const char *p = fqdn;
-
- /* go to next char following '.' */
-
- if ((p = strchr_m(fqdn, '.')) != NULL) {
- p++;
- }
-
- return p;
-}
-
-
-/**
- * Connect to the Global Catalog server
- * @param ads Pointer to an existing ADS_STRUCT
- * @return status of connection
- *
- * Simple wrapper around ads_connect() that fills in the
- * GC ldap server information
- **/
-
-ADS_STATUS ads_connect_gc(ADS_STRUCT *ads)
-{
- TALLOC_CTX *frame = talloc_stackframe();
- struct dns_rr_srv *gcs_list;
- int num_gcs;
- const char *realm = ads->server.realm;
- NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
- ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
- int i;
- bool done = false;
- char *sitename = NULL;
- const char *dns_hosts_file;
-
- if (!realm)
- realm = lp_realm();
-
- if ((sitename = sitename_fetch(frame, realm)) == NULL) {
- ads_lookup_site();
- sitename = sitename_fetch(frame, realm);
- }
-
- dns_hosts_file = lp_parm_const_string(-1, "resolv", "host file", NULL);
- do {
- /* We try once with a sitename and once without
- (unless we don't have a sitename and then we're
- done */
-
- if (sitename == NULL)
- done = true;
-
- nt_status = ads_dns_query_gcs(frame, dns_hosts_file,
- realm, sitename,
- &gcs_list, &num_gcs);
-
- if (!NT_STATUS_IS_OK(nt_status)) {
- ads_status = ADS_ERROR_NT(nt_status);
- goto done;
- }
-
- /* Loop until we get a successful connection or have gone
- through them all. When connecting a GC server, make sure that
- the realm is the server's DNS name and not the forest root */
-
- for (i=0; i<num_gcs; i++) {
- ads->server.gc = true;
- ads->server.ldap_server = SMB_STRDUP(gcs_list[i].hostname);
- ads->server.realm = SMB_STRDUP(host_dns_domain(ads->server.ldap_server));
- ads_status = ads_connect(ads);
- if (ADS_ERR_OK(ads_status)) {
- /* Reset the bind_dn to "". A Global Catalog server
- may host multiple domain trees in a forest.
- Windows 2003 GC server will accept "" as the search
- path to imply search all domain trees in the forest */
-
- SAFE_FREE(ads->config.bind_path);
- ads->config.bind_path = SMB_STRDUP("");
-
-
- goto done;
- }
- SAFE_FREE(ads->server.ldap_server);
- SAFE_FREE(ads->server.realm);
- }
-
- TALLOC_FREE(gcs_list);
- num_gcs = 0;
- } while (!done);
-
-done:
- talloc_destroy(frame);
-
- return ads_status;
-}
-
-
/**
* Connect to the LDAP server
* @param ads Pointer to an existing ADS_STRUCT
@@ -1174,7 +1041,7 @@ static ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
ADS_STATUS ads_do_search_all_sd_flags(ADS_STRUCT *ads, const char *bind_path,
int scope, const char *expr,
- const char **attrs, uint32 sd_flags,
+ const char **attrs, uint32_t sd_flags,
LDAPMessage **res)
{
ads_control args;
@@ -1783,10 +1650,10 @@ ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
* @return the kvno for the account, or -1 in case of a failure.
**/
-uint32 ads_get_kvno(ADS_STRUCT *ads, const char *account_name)
+uint32_t ads_get_kvno(ADS_STRUCT *ads, const char *account_name)
{
LDAPMessage *res = NULL;
- uint32 kvno = (uint32)-1; /* -1 indicates a failure */
+ uint32_t kvno = (uint32)-1; /* -1 indicates a failure */
char *filter;
const char *attrs[] = {"msDS-KeyVersionNumber", NULL};
char *dn_string = NULL;
@@ -2136,7 +2003,7 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name,
const char *objectClass[] = {"top", "person", "organizationalPerson",
"user", "computer", NULL};
LDAPMessage *res = NULL;
- uint32 acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\
+ uint32_t acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\
UF_DONT_EXPIRE_PASSWD |\
UF_ACCOUNTDISABLE );
@@ -2312,7 +2179,7 @@ static void dump_sd(ADS_STRUCT *ads, const char *filed, struct berval **values)
struct security_descriptor *psd;
NTSTATUS status;
- status = unmarshall_sec_desc(talloc_tos(), (uint8 *)values[0]->bv_val,
+ status = unmarshall_sec_desc(talloc_tos(), (uint8_t *)values[0]->bv_val,
values[0]->bv_len, &psd);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("unmarshall_sec_desc failed: %s\n",
@@ -2725,7 +2592,7 @@ int ads_count_replies(ADS_STRUCT *ads, void *res)
}
/**
- * pull a single uint32 from a ADS result
+ * pull a single uint32_t from a ADS result
* @param ads connection to ads server
* @param msg Results of search
* @param field Attribute to retrieve
@@ -2733,7 +2600,7 @@ int ads_count_replies(ADS_STRUCT *ads, void *res)
* @return boolean inidicating success
*/
bool ads_pull_uint32(ADS_STRUCT *ads, LDAPMessage *msg, const char *field,
- uint32 *v)
+ uint32_t *v)
{
char **values;
@@ -2858,7 +2725,7 @@ int ads_count_replies(ADS_STRUCT *ads, void *res)
if (values[0]) {
NTSTATUS status;
status = unmarshall_sec_desc(mem_ctx,
- (uint8 *)values[0]->bv_val,
+ (uint8_t *)values[0]->bv_val,
values[0]->bv_len, sd);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("unmarshall_sec_desc failed: %s\n",
@@ -2908,7 +2775,7 @@ int ads_count_replies(ADS_STRUCT *ads, void *res)
* @param usn Pointer to retrieved update serial number
* @return status of search
**/
-ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn)
+ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32_t *usn)
{
const char *attrs[] = {"highestCommittedUSN", NULL};
ADS_STATUS status;
@@ -3020,7 +2887,7 @@ done:
/********************************************************************
********************************************************************/
-ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32 *val)
+ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32_t *val)
{
const char *attrs[] = {"domainFunctionality", NULL};
ADS_STATUS status;
@@ -3512,7 +3379,7 @@ out:
* @return status of join
**/
ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name,
- uint32 account_type, const char *org_unit)
+ uint32_t account_type, const char *org_unit)
{
ADS_STATUS status;
LDAPMessage *res = NULL;
@@ -3708,7 +3575,7 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
struct dom_sid *tmp_sids;
struct dom_sid tmp_user_sid;
struct dom_sid tmp_primary_group_sid;
- uint32 pgid;
+ uint32_t pgid;
const char *attrs[] = {
"objectSid",
"tokenGroups",
@@ -3790,14 +3657,14 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
* @param ads connection to ads server
* @param mem_ctx TALLOC_CTX for allocating sid array
* @param samaccountname to search
- * @param uac_ret uint32 pointer userAccountControl attribute value
+ * @param uac_ret uint32_t pointer userAccountControl attribute value
* @param dn_ret pointer to dn
* @return status of token query
**/
ADS_STATUS ads_find_samaccount(ADS_STRUCT *ads,
TALLOC_CTX *mem_ctx,
const char *samaccountname,
- uint32 *uac_ret,
+ uint32_t *uac_ret,
const char **dn_ret)
{
ADS_STATUS status;
@@ -3805,7 +3672,7 @@ ADS_STATUS ads_find_samaccount(ADS_STRUCT *ads,
const char *filter;
LDAPMessage *res = NULL;
char *dn = NULL;
- uint32 uac = 0;
+ uint32_t uac = 0;
filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)(sAMAccountName=%s))",
samaccountname);
diff --git a/source3/libads/ldap_printer.c b/source3/libads/ldap_printer.c
index e9eb41967f2..82c131104b9 100644
--- a/source3/libads/ldap_printer.c
+++ b/source3/libads/ldap_printer.c
@@ -146,7 +146,7 @@ static bool map_dword(TALLOC_CTX *ctx, ADS_MODLIST *mods,
if (value->type != REG_DWORD) {
return false;
}
- if (value->data.length != sizeof(uint32)) {
+ if (value->data.length != sizeof(uint32_t)) {
return false;
}
str_value = talloc_asprintf(ctx, "%d", IVAL(value->data.data, 0));
@@ -292,7 +292,7 @@ WERROR get_remote_printer_publishing_data(struct rpc_pipe_client *cli,
char *printername;
struct spoolss_PrinterEnumValues *info;
uint32_t count;
- uint32 i;
+ uint32_t i;
struct policy_handle pol;
WERROR werr;
diff --git a/source3/libads/ldap_utils.c b/source3/libads/ldap_utils.c
index 88db3a3ab73..117dc557e25 100644
--- a/source3/libads/ldap_utils.c
+++ b/source3/libads/ldap_utils.c
@@ -36,7 +36,7 @@ static ADS_STATUS ads_ranged_search_internal(ADS_STRUCT *ads,
const char *range_attr,
char ***strings,
size_t *num_strings,
- uint32 *first_usn,
+ uint32_t *first_usn,
int *num_retries,
bool *more_values);
@@ -169,7 +169,7 @@ static ADS_STATUS ads_do_search_retry_args(ADS_STRUCT *ads, const char *bind_pat
}
ADS_STATUS ads_search_retry_dn_sd_flags(ADS_STRUCT *ads, LDAPMessage **res,
- uint32 sd_flags,
+ uint32_t sd_flags,
const char *dn,
const char **attrs)
{
@@ -242,7 +242,7 @@ ADS_STATUS ads_ranged_search(ADS_STRUCT *ads,
size_t *num_strings)
{
ADS_STATUS status;
- uint32 first_usn;
+ uint32_t first_usn;
int num_retries = 0;
const char **attrs;
bool more_values = False;
@@ -296,14 +296,14 @@ static ADS_STATUS ads_ranged_search_internal(ADS_STRUCT *ads,
const char *range_attr,
char ***strings,
size_t *num_strings,
- uint32 *first_usn,
+ uint32_t *first_usn,
int *num_retries,
bool *more_values)
{
LDAPMessage *res = NULL;
ADS_STATUS status;
int count;
- uint32 current_usn;
+ uint32_t current_usn;
DEBUG(10, ("Searching for attrs[0] = %s, attrs[1] = %s\n", attrs[0], attrs[1]));
diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c
index ea0b821294e..22aa9cf4bb7 100644
--- a/source3/libads/sasl.c
+++ b/source3/libads/sasl.c
@@ -19,6 +19,7 @@
#include "includes.h"
#include "../libcli/auth/spnego.h"
+#include "auth/credentials/credentials.h"
#include "auth/gensec/gensec.h"
#include "auth_generic.h"
#include "ads.h"
@@ -28,7 +29,7 @@
#ifdef HAVE_LDAP
-static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
+static ADS_STATUS ads_sasl_gensec_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
{
struct gensec_security *gensec_security =
talloc_get_type_abort(ads->ldap.wrap_private_data,
@@ -46,6 +47,7 @@ static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
}
if ((ads->ldap.out.size - 4) < wrapped.length) {
+ TALLOC_FREE(frame);
return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
}
@@ -60,7 +62,7 @@ static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
return ADS_SUCCESS;
}
-static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
+static ADS_STATUS ads_sasl_gensec_unwrap(ADS_STRUCT *ads)
{
struct gensec_security *gensec_security =
talloc_get_type_abort(ads->ldap.wrap_private_data,
@@ -94,7 +96,7 @@ static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
return ADS_SUCCESS;
}
-static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
+static void ads_sasl_gensec_disconnect(ADS_STRUCT *ads)
{
struct gensec_security *gensec_security =
talloc_get_type_abort(ads->ldap.wrap_private_data,
@@ -106,30 +108,32 @@ static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
ads->ldap.wrap_private_data = NULL;
}
-static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
- .name = "ntlmssp",
- .wrap = ads_sasl_ntlmssp_wrap,
- .unwrap = ads_sasl_ntlmssp_unwrap,
- .disconnect = ads_sasl_ntlmssp_disconnect
+static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
+ .name = "gensec",
+ .wrap = ads_sasl_gensec_wrap,
+ .unwrap = ads_sasl_gensec_unwrap,
+ .disconnect = ads_sasl_gensec_disconnect
};
/*
- perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
+ perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
we fit on one socket??)
*/
-static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
+static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
+ const char *sasl,
+ enum credentials_use_kerberos krb5_state,
+ const char *target_service,
+ const char *target_hostname,
+ const DATA_BLOB server_blob)
{
- DATA_BLOB msg1 = data_blob_null;
- DATA_BLOB blob = data_blob_null;
DATA_BLOB blob_in = data_blob_null;
DATA_BLOB blob_out = data_blob_null;
- struct berval cred, *scred = NULL;
int rc;
NTSTATUS nt_status;
ADS_STATUS status;
- int turn = 1;
-
struct auth_generic_state *auth_generic_state;
+ bool use_spnego_principal = lp_client_use_spnego_principal();
+ const char *sasl_list[] = { sasl, NULL };
nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
if (!NT_STATUS_IS_OK(nt_status)) {
@@ -146,6 +150,39 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
return ADS_ERROR_NT(nt_status);
}
+ if (server_blob.length == 0) {
+ use_spnego_principal = false;
+ }
+
+ if (krb5_state == CRED_DONT_USE_KERBEROS) {
+ use_spnego_principal = false;
+ }
+
+ cli_credentials_set_kerberos_state(auth_generic_state->credentials,
+ krb5_state);
+
+ if (target_service != NULL) {
+ nt_status = gensec_set_target_service(
+ auth_generic_state->gensec_security,
+ target_service);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return ADS_ERROR_NT(nt_status);
+ }
+ }
+
+ if (target_hostname != NULL) {
+ nt_status = gensec_set_target_hostname(
+ auth_generic_state->gensec_security,
+ target_hostname);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return ADS_ERROR_NT(nt_status);
+ }
+ }
+
+ if (target_service != NULL && target_hostname != NULL) {
+ use_spnego_principal = false;
+ }
+
switch (ads->ldap.wrap_type) {
case ADS_SASLWRAP_TYPE_SEAL:
gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
@@ -157,105 +194,133 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
} else {
/*
* windows servers are broken with sign only,
- * so we need to use seal here too
+ * so we let the NTLMSSP backend to seal here,
+ * via GENSEC_FEATURE_LDAP_STYLE.
*/
gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
- gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
- ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
+ gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
}
break;
case ADS_SASLWRAP_TYPE_PLAIN:
break;
}
- nt_status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
+ nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
+ sasl_list);
if (!NT_STATUS_IS_OK(nt_status)) {
return ADS_ERROR_NT(nt_status);
}
- blob_in = data_blob_null;
+ rc = LDAP_SASL_BIND_IN_PROGRESS;
+ nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ if (use_spnego_principal) {
+ blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
+ if (blob_in.length == 0) {
+ TALLOC_FREE(auth_generic_state);
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+ } else {
+ blob_in = data_blob_null;
+ }
+ blob_out = data_blob_null;
+
+ while (true) {
+ struct berval cred, *scred = NULL;
- do {
nt_status = gensec_update(auth_generic_state->gensec_security,
talloc_tos(), blob_in, &blob_out);
data_blob_free(&blob_in);
- if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
- || NT_STATUS_IS_OK(nt_status))
- && blob_out.length) {
- if (turn == 1) {
- const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
- /* and wrap it in a SPNEGO wrapper */
- msg1 = spnego_gen_negTokenInit(talloc_tos(),
- OIDs_ntlm, &blob_out, NULL);
- } else {
- /* wrap it in SPNEGO */
- msg1 = spnego_gen_auth(talloc_tos(), blob_out);
- }
-
+ if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
+ && !NT_STATUS_IS_OK(nt_status))
+ {
+ TALLOC_FREE(auth_generic_state);
data_blob_free(&blob_out);
+ return ADS_ERROR_NT(nt_status);
+ }
- cred.bv_val = (char *)msg1.data;
- cred.bv_len = msg1.length;
- scred = NULL;
- rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
- data_blob_free(&msg1);
- if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
- if (scred) {
- ber_bvfree(scred);
- }
+ if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
+ break;
+ }
- TALLOC_FREE(auth_generic_state);
- return ADS_ERROR(rc);
- }
+ cred.bv_val = (char *)blob_out.data;
+ cred.bv_len = blob_out.length;
+ scred = NULL;
+ rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
+ data_blob_free(&blob_out);
+ if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
if (scred) {
- blob = data_blob(scred->bv_val, scred->bv_len);
ber_bvfree(scred);
- } else {
- blob = data_blob_null;
}
+ TALLOC_FREE(auth_generic_state);
+ return ADS_ERROR(rc);
+ }
+ if (scred) {
+ blob_in = data_blob_talloc(talloc_tos(),
+ scred->bv_val,
+ scred->bv_len);
+ if (blob_in.length != scred->bv_len) {
+ ber_bvfree(scred);
+ TALLOC_FREE(auth_generic_state);
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+ ber_bvfree(scred);
} else {
+ blob_in = data_blob_null;
+ }
+ if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
+ break;
+ }
+ }
+ data_blob_free(&blob_in);
+ data_blob_free(&blob_out);
+
+ if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
+ bool ok;
+
+ ok = gensec_have_feature(auth_generic_state->gensec_security,
+ GENSEC_FEATURE_SEAL);
+ if (!ok) {
+ DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
TALLOC_FREE(auth_generic_state);
- data_blob_free(&blob_out);
- return ADS_ERROR_NT(nt_status);
+ return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
}
-
- if ((turn == 1) &&
- (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
- DATA_BLOB tmp_blob = data_blob_null;
- /* the server might give us back two challenges */
- if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in,
- &tmp_blob)) {
- TALLOC_FREE(auth_generic_state);
- data_blob_free(&blob);
- DEBUG(3,("Failed to parse challenges\n"));
- return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- }
- data_blob_free(&tmp_blob);
- } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
- if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP,
- &blob_in)) {
+ ok = gensec_have_feature(auth_generic_state->gensec_security,
+ GENSEC_FEATURE_SIGN);
+ if (!ok) {
+ DEBUG(0,("The gensec feature signing request, but unavailable\n"));
+ TALLOC_FREE(auth_generic_state);
+ return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
+ }
- TALLOC_FREE(auth_generic_state);
- data_blob_free(&blob);
- DEBUG(3,("Failed to parse auth response\n"));
- return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- }
+ } else if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
+ bool ok;
+
+ ok = gensec_have_feature(auth_generic_state->gensec_security,
+ GENSEC_FEATURE_SIGN);
+ if (!ok) {
+ DEBUG(0,("The gensec feature signing request, but unavailable\n"));
+ TALLOC_FREE(auth_generic_state);
+ return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
}
- data_blob_free(&blob);
- data_blob_free(&blob_out);
- turn++;
- } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
-
+ }
+
if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
- uint32_t sig_size = gensec_sig_size(auth_generic_state->gensec_security, 0);
- ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - sig_size;
- ads->ldap.out.sig_size = sig_size;
- ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
- ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
- status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, auth_generic_state->gensec_security);
+ size_t max_wrapped = gensec_max_wrapped_size(auth_generic_state->gensec_security);
+ ads->ldap.out.max_unwrapped = gensec_max_input_size(auth_generic_state->gensec_security);
+
+ ads->ldap.out.sig_size = max_wrapped - ads->ldap.out.max_unwrapped;
+ /*
+ * Note that we have to truncate this to 0x2C
+ * (taken from a capture with LDAP unbind), as the
+ * signature size is not constant for Kerberos with
+ * arcfour-hmac-md5.
+ */
+ ads->ldap.in.min_wrapped = MIN(ads->ldap.out.sig_size, 0x2C);
+ ads->ldap.in.max_wrapped = max_wrapped;
+ status = ads_setup_sasl_wrapping(ads, &ads_sasl_gensec_ops, auth_generic_state->gensec_security);
if (!ADS_ERR_OK(status)) {
DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
ads_errstr(status)));
@@ -339,12 +404,12 @@ done:
return status;
}
-static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
+static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
{
gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
ADS_STATUS status;
int gss_rc;
- uint32 minor_status;
+ uint32_t minor_status;
gss_buffer_desc unwrapped, wrapped;
int conf_req_flag, conf_state;
@@ -385,7 +450,7 @@ static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
ADS_STATUS status;
int gss_rc;
- uint32 minor_status;
+ uint32_t minor_status;
gss_buffer_desc unwrapped, wrapped;
int conf_state;
@@ -421,7 +486,7 @@ static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
{
gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
- uint32 minor_status;
+ uint32_t minor_status;
gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
@@ -436,306 +501,37 @@ static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
.disconnect = ads_sasl_gssapi_disconnect
};
-/*
- perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
-*/
-static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
-{
- ADS_STATUS status;
- bool ok;
- uint32 minor_status;
- int gss_rc, rc;
- gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
- gss_OID_desc krb5_mech_type =
- {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
- gss_OID mech_type = &krb5_mech_type;
- gss_OID actual_mech_type = GSS_C_NULL_OID;
- const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
- gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
- gss_buffer_desc input_token, output_token;
- uint32 req_flags, ret_flags;
- uint32 req_tmp, ret_tmp;
- DATA_BLOB unwrapped;
- DATA_BLOB wrapped;
- struct berval cred, *scred = NULL;
- uint32_t context_validity = 0;
- time_t context_endtime = 0;
-
- status = ads_init_gssapi_cred(ads, &gss_cred);
- if (!ADS_ERR_OK(status)) {
- goto failed;
- }
-
- input_token.value = NULL;
- input_token.length = 0;
-
- req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
- switch (ads->ldap.wrap_type) {
- case ADS_SASLWRAP_TYPE_SEAL:
- req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
- break;
- case ADS_SASLWRAP_TYPE_SIGN:
- req_flags |= GSS_C_INTEG_FLAG;
- break;
- case ADS_SASLWRAP_TYPE_PLAIN:
- break;
- }
-
- /* Note: here we explicit ask for the krb5 mech_type */
- gss_rc = gss_init_sec_context(&minor_status,
- gss_cred,
- &context_handle,
- serv_name,
- mech_type,
- req_flags,
- 0,
- NULL,
- &input_token,
- &actual_mech_type,
- &output_token,
- &ret_flags,
- NULL);
- if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
- status = ADS_ERROR_GSS(gss_rc, minor_status);
- goto failed;
- }
-
- /*
- * As some gssapi krb5 mech implementations
- * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
- * to req_flags internaly, it's not possible to
- * use plain or signing only connection via
- * the gssapi interface.
- *
- * Because of this we need to check it the ret_flags
- * has more flags as req_flags and correct the value
- * of ads->ldap.wrap_type.
- *
- * I ads->auth.flags has ADS_AUTH_SASL_FORCE
- * we need to give an error.
- */
- req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
- ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
-
- if (req_tmp == ret_tmp) {
- /* everythings fine... */
-
- } else if (req_flags & GSS_C_CONF_FLAG) {
- /*
- * here we wanted sealing but didn't got it
- * from the gssapi library
- */
- status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
- goto failed;
-
- } else if ((req_flags & GSS_C_INTEG_FLAG) &&
- !(ret_flags & GSS_C_INTEG_FLAG)) {
- /*
- * here we wanted siging but didn't got it
- * from the gssapi library
- */
- status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
- goto failed;
-
- } else if (ret_flags & GSS_C_CONF_FLAG) {
- /*
- * here we didn't want sealing
- * but the gssapi library forces it
- * so correct the needed wrap_type if
- * the caller didn't forced siging only
- */
- if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
- status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
- goto failed;
- }
-
- ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
- req_flags = ret_flags;
-
- } else if (ret_flags & GSS_C_INTEG_FLAG) {
- /*
- * here we didn't want signing
- * but the gssapi library forces it
- * so correct the needed wrap_type if
- * the caller didn't forced plain
- */
- if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
- status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
- goto failed;
- }
-
- ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
- req_flags = ret_flags;
- } else {
- /*
- * This could (should?) not happen
- */
- status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
- goto failed;
-
- }
-
- /* and wrap that in a shiny SPNEGO wrapper */
- unwrapped = data_blob_const(output_token.value, output_token.length);
- wrapped = spnego_gen_negTokenInit(talloc_tos(),
- spnego_mechs, &unwrapped, NULL);
- gss_release_buffer(&minor_status, &output_token);
- if (unwrapped.length > wrapped.length) {
- status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- goto failed;
- }
-
- cred.bv_val = (char *)wrapped.data;
- cred.bv_len = wrapped.length;
-
- rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
- &scred);
- data_blob_free(&wrapped);
- if (rc != LDAP_SUCCESS) {
- status = ADS_ERROR(rc);
- goto failed;
- }
-
- if (scred) {
- wrapped = data_blob_const(scred->bv_val, scred->bv_len);
- } else {
- wrapped = data_blob_null;
- }
-
- ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
- OID_KERBEROS5_OLD,
- &unwrapped);
- if (scred) ber_bvfree(scred);
- if (!ok) {
- status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
- goto failed;
- }
-
- input_token.value = unwrapped.data;
- input_token.length = unwrapped.length;
-
- /*
- * As we asked for mutal authentication
- * we need to pass the servers response
- * to gssapi
- */
- gss_rc = gss_init_sec_context(&minor_status,
- gss_cred,
- &context_handle,
- serv_name,
- mech_type,
- req_flags,
- 0,
- NULL,
- &input_token,
- &actual_mech_type,
- &output_token,
- &ret_flags,
- NULL);
- data_blob_free(&unwrapped);
- if (gss_rc) {
- status = ADS_ERROR_GSS(gss_rc, minor_status);
- goto failed;
- }
-
- gss_release_buffer(&minor_status, &output_token);
-
- /*
- * If we the sign and seal options
- * doesn't match after getting the response
- * from the server, we don't want to use the connection
- */
- req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
- ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
-
- if (req_tmp != ret_tmp) {
- /* everythings fine... */
- status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
- goto failed;
- }
-
- gss_rc =
- gss_context_time(&minor_status, context_handle, &context_validity);
- if (gss_rc == GSS_S_COMPLETE) {
- if (context_validity != 0) {
- context_endtime = time(NULL) + context_validity;
- DEBUG(10, ("context (service ticket) valid for "
- "%u seconds\n",
- context_validity));
- } else {
- DEBUG(10, ("context (service ticket) expired\n"));
- }
- } else {
- DEBUG(1, ("gss_context_time failed (%d,%u) -"
- " this will be a one-time context\n",
- gss_rc, minor_status));
- if (gss_rc == GSS_S_CONTEXT_EXPIRED) {
- DEBUG(10, ("context (service ticket) expired\n"));
- }
- }
-
- if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
- uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
-
- gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
- (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
- GSS_C_QOP_DEFAULT,
- max_msg_size, &ads->ldap.out.max_unwrapped);
- if (gss_rc) {
- status = ADS_ERROR_GSS(gss_rc, minor_status);
- goto failed;
- }
-
- ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
- ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
- ads->ldap.in.max_wrapped = max_msg_size;
- status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
- if (!ADS_ERR_OK(status)) {
- DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
- ads_errstr(status)));
- goto failed;
- }
- /* make sure we don't free context_handle */
- context_handle = GSS_C_NO_CONTEXT;
- }
-
- ads->auth.tgs_expire = context_endtime;
- status = ADS_SUCCESS;
-
-failed:
- if (gss_cred != GSS_C_NO_CREDENTIAL)
- gss_release_cred(&minor_status, &gss_cred);
- if (context_handle != GSS_C_NO_CONTEXT)
- gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
- return status;
-}
-
#endif /* HAVE_KRB5 */
#ifdef HAVE_KRB5
struct ads_service_principal {
- char *string;
+ char *service;
+ char *hostname;
+ char *string;
#ifdef HAVE_KRB5
- gss_name_t name;
+ gss_name_t name;
#endif
};
static void ads_free_service_principal(struct ads_service_principal *p)
{
+ SAFE_FREE(p->service);
+ SAFE_FREE(p->hostname);
SAFE_FREE(p->string);
#ifdef HAVE_KRB5
if (p->name) {
- uint32 minor_status;
+ uint32_t minor_status;
gss_release_name(&minor_status, &p->name);
}
#endif
ZERO_STRUCTP(p);
}
-
-static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
- char **returned_principal)
+static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
+ char **service,
+ char **hostname,
+ char **principal)
{
ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
char *princ = NULL;
@@ -815,13 +611,26 @@ static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
goto out;
}
+ *service = SMB_STRDUP("ldap");
+ if (*service == NULL) {
+ status = ADS_ERROR(LDAP_PARAM_ERROR);
+ goto out;
+ }
+ *hostname = SMB_STRDUP(server);
+ if (*hostname == NULL) {
+ SAFE_FREE(*service);
+ status = ADS_ERROR(LDAP_PARAM_ERROR);
+ goto out;
+ }
rc = asprintf(&princ, "ldap/%s@%s", server, realm);
if (rc == -1 || princ == NULL) {
+ SAFE_FREE(*service);
+ SAFE_FREE(*hostname);
status = ADS_ERROR(LDAP_PARAM_ERROR);
goto out;
}
- *returned_principal = princ;
+ *principal = princ;
status = ADS_SUCCESS;
out:
@@ -830,7 +639,6 @@ out:
}
static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
- const char *given_principal,
struct ads_service_principal *p)
{
ADS_STATUS status;
@@ -839,33 +647,18 @@ static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
/* GSS_KRB5_NT_PRINCIPAL_NAME */
gss_OID_desc nt_principal =
{10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
- uint32 minor_status;
+ uint32_t minor_status;
int gss_rc;
#endif
ZERO_STRUCTP(p);
- /* I've seen a child Windows 2000 domain not send
- the principal name back in the first round of
- the SASL bind reply. So we guess based on server
- name and realm. --jerry */
- /* Also try best guess when we get the w2k8 ignore principal
- back, or when we are configured to ignore it - gd,
- abartlet */
-
- if (!lp_client_use_spnego_principal() ||
- !given_principal ||
- strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
-
- status = ads_guess_service_principal(ads, &p->string);
- if (!ADS_ERR_OK(status)) {
- return status;
- }
- } else {
- p->string = SMB_STRDUP(given_principal);
- if (!p->string) {
- return ADS_ERROR(LDAP_NO_MEMORY);
- }
+ status = ads_guess_target(ads,
+ &p->service,
+ &p->hostname,
+ &p->string);
+ if (!ADS_ERR_OK(status)) {
+ return status;
}
#ifdef HAVE_KRB5
@@ -882,63 +675,6 @@ static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
return ADS_SUCCESS;
}
-/*
- perform a LDAP/SASL/SPNEGO/KRB5 bind
-*/
-static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
-{
- DATA_BLOB blob = data_blob_null;
- struct berval cred, *scred = NULL;
- DATA_BLOB session_key = data_blob_null;
- int rc;
-
- if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
- return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
- }
-
- rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
- ads->auth.time_offset, &blob, &session_key, 0,
- ads->auth.ccache_name,
- &ads->auth.tgs_expire);
-
- if (rc) {
- return ADS_ERROR_KRB5(rc);
- }
-
- /* now send the auth packet and we should be done */
- cred.bv_val = (char *)blob.data;
- cred.bv_len = blob.length;
-
- rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
-
- data_blob_free(&blob);
- data_blob_free(&session_key);
- if(scred)
- ber_bvfree(scred);
-
- return ADS_ERROR(rc);
-}
-
-static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
- struct ads_service_principal *p)
-{
-#ifdef HAVE_KRB5
- /*
- * we only use the gsskrb5 based implementation
- * when sasl sign or seal is requested.
- *
- * This has the following reasons:
- * - it's likely that the gssapi krb5 mech implementation
- * doesn't support to negotiate plain connections
- * - the ads_sasl_spnego_rawkrb5_bind is more robust
- * against clock skew errors
- */
- if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
- return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
- }
-#endif
- return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
-}
#endif /* HAVE_KRB5 */
/*
@@ -946,6 +682,8 @@ static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
*/
static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct ads_service_principal p = {0};
struct berval *scred=NULL;
int rc, i;
ADS_STATUS status;
@@ -960,7 +698,7 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
status = ADS_ERROR(rc);
- goto failed;
+ goto done;
}
blob = data_blob(scred->bv_val, scred->bv_len);
@@ -975,11 +713,10 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
reply */
if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
OIDs[0] == NULL) {
- data_blob_free(&blob);
status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
- goto failed;
+ goto done;
}
- data_blob_free(&blob);
+ TALLOC_FREE(given_principal);
/* make sure the server understands kerberos */
for (i=0;OIDs[i];i++) {
@@ -992,59 +729,60 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
#endif
talloc_free(OIDs[i]);
}
- DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
+
+ status = ads_generate_service_principal(ads, &p);
+ if (!ADS_ERR_OK(status)) {
+ goto done;
+ }
#ifdef HAVE_KRB5
if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
got_kerberos_mechanism)
{
- struct ads_service_principal p;
-
- status = ads_generate_service_principal(ads, given_principal, &p);
- TALLOC_FREE(given_principal);
- if (!ADS_ERR_OK(status)) {
- return status;
- }
-
- status = ads_sasl_spnego_krb5_bind(ads, &p);
+ status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
+ CRED_MUST_USE_KERBEROS,
+ p.service, p.hostname,
+ blob);
if (ADS_ERR_OK(status)) {
ads_free_service_principal(&p);
- return status;
+ goto done;
}
- DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
+ DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
"calling kinit\n", ads_errstr(status)));
status = ADS_ERROR_KRB5(ads_kinit_password(ads));
if (ADS_ERR_OK(status)) {
- status = ads_sasl_spnego_krb5_bind(ads, &p);
+ status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
+ CRED_MUST_USE_KERBEROS,
+ p.service, p.hostname,
+ blob);
if (!ADS_ERR_OK(status)) {
DEBUG(0,("kinit succeeded but "
- "ads_sasl_spnego_krb5_bind failed: %s\n",
+ "ads_sasl_spnego_gensec_bind(KRB5) failed: %s\n",
ads_errstr(status)));
}
}
- ads_free_service_principal(&p);
-
/* only fallback to NTLMSSP if allowed */
if (ADS_ERR_OK(status) ||
!(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
- return status;
+ goto done;
}
- } else
-#endif
- {
- TALLOC_FREE(given_principal);
}
+#endif
/* lets do NTLMSSP ... this has the big advantage that we don't need
to sync clocks, and we don't rely on special versions of the krb5
library for HMAC_MD4 encryption */
- return ads_sasl_spnego_ntlmssp_bind(ads);
-
-failed:
+ status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
+ CRED_DONT_USE_KERBEROS,
+ p.service, p.hostname,
+ data_blob_null);
+done:
+ ads_free_service_principal(&p);
+ TALLOC_FREE(frame);
return status;
}
@@ -1059,20 +797,20 @@ failed:
*/
static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
{
- uint32 minor_status;
+ uint32_t minor_status;
gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
gss_OID mech_type = GSS_C_NULL_OID;
gss_buffer_desc output_token, input_token;
- uint32 req_flags, ret_flags;
+ uint32_t req_flags, ret_flags;
int conf_state;
struct berval cred;
struct berval *scred = NULL;
int i=0;
int gss_rc, rc;
- uint8 *p;
- uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
- uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
+ uint8_t *p;
+ uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
+ uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
ADS_STATUS status;
input_token.value = NULL;
@@ -1149,7 +887,7 @@ static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv
goto failed;
}
- p = (uint8 *)output_token.value;
+ p = (uint8_t *)output_token.value;
#if 0
file_save("sasl_gssapi.dat", output_token.value, output_token.length);
@@ -1187,7 +925,7 @@ static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv
status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
goto failed;
}
- p = (uint8 *)output_token.value;
+ p = (uint8_t *)output_token.value;
RSIVAL(p,0,max_msg_size);
SCVAL(p,0,ads->ldap.wrap_type);
@@ -1266,7 +1004,7 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
ADS_STATUS status;
struct ads_service_principal p;
- status = ads_generate_service_principal(ads, NULL, &p);
+ status = ads_generate_service_principal(ads, &p);
if (!ADS_ERR_OK(status)) {
return status;
}
diff --git a/source3/libads/sasl_wrapping.c b/source3/libads/sasl_wrapping.c
index d7353ac79c9..9296d60ba9d 100644
--- a/source3/libads/sasl_wrapping.c
+++ b/source3/libads/sasl_wrapping.c
@@ -171,7 +171,7 @@ eagain:
return -1;
}
-static ber_slen_t ads_saslwrap_prepare_outbuf(ADS_STRUCT *ads, uint32 len)
+static ber_slen_t ads_saslwrap_prepare_outbuf(ADS_STRUCT *ads, uint32_t len)
{
ads->ldap.out.ofs = 0;
ads->ldap.out.left = 0;
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 187e524606c..d7c7679d26e 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -846,7 +846,7 @@ static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
domain,
pass,
flags,
- SMB_SIGNING_DEFAULT);
+ SMB_SIGNING_IPC_DEFAULT);
}
/****************************************************************
@@ -1407,7 +1407,7 @@ NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
netbios_domain_name,
machine_password,
flags,
- SMB_SIGNING_DEFAULT);
+ SMB_SIGNING_IPC_DEFAULT);
E_md4hash(machine_password, current_nt_hash.hash);
SAFE_FREE(machine_password);
@@ -1421,7 +1421,7 @@ NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
NULL,
"",
0,
- SMB_SIGNING_DEFAULT);
+ SMB_SIGNING_IPC_DEFAULT);
}
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index 8db3cdd227a..fc31064ea1d 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -33,15 +33,20 @@
#if defined(HAVE_KRB5)
#include "auth/kerberos/pac_utils.h"
+#include "auth/kerberos/gssapi_helper.h"
#include "gse_krb5.h"
static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
+static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
+ size_t data_size);
struct gse_context {
gss_ctx_id_t gssapi_context;
gss_name_t server_name;
gss_name_t client_name;
OM_uint32 gss_want_flags, gss_got_flags;
+ size_t max_wrap_buf_size;
+ size_t sig_size;
gss_cred_id_t delegated_cred_handle;
@@ -132,6 +137,7 @@ static NTSTATUS gse_context_init(TALLOC_CTX *mem_ctx,
talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor);
gse_ctx->expire_time = GENSEC_EXPIRE_TIME_INFINITY;
+ gse_ctx->max_wrap_buf_size = UINT16_MAX;
memcpy(&gse_ctx->gss_mech, gss_mech_krb5, sizeof(gss_OID_desc));
@@ -197,8 +203,11 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
{
struct gse_context *gse_ctx;
OM_uint32 gss_maj, gss_min;
- gss_buffer_desc name_buffer = {0, NULL};
+ gss_buffer_desc name_buffer = GSS_C_EMPTY_BUFFER;
gss_OID_set_desc mech_set;
+#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
+ gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
+#endif
NTSTATUS status;
if (!server || !service) {
@@ -251,12 +260,34 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
&gse_ctx->creds,
NULL, NULL);
if (gss_maj) {
- DEBUG(0, ("gss_acquire_creds failed for %s, with [%s]\n",
- (char *)name_buffer.value,
+ DEBUG(5, ("gss_acquire_creds failed for GSS_C_NO_NAME with [%s] -"
+ "the caller may retry after a kinit.\n",
+ gse_errstr(gse_ctx, gss_maj, gss_min)));
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto err_out;
+ }
+
+#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
+ /*
+ * Don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG.
+ *
+ * This allows us to disable SIGN and SEAL for
+ * AUTH_LEVEL_CONNECT and AUTH_LEVEL_INTEGRITY.
+ *
+ * https://groups.yahoo.com/neo/groups/cat-ietf/conversations/topics/575
+ * http://krbdev.mit.edu/rt/Ticket/Display.html?id=6938
+ */
+ gss_maj = gss_set_cred_option(&gss_min, &gse_ctx->creds,
+ GSS_KRB5_CRED_NO_CI_FLAGS_X,
+ &empty_buffer);
+ if (gss_maj) {
+ DEBUG(0, ("gss_set_cred_option(GSS_KRB5_CRED_NO_CI_FLAGS_X), "
+ "failed with [%s]\n",
gse_errstr(gse_ctx, gss_maj, gss_min)));
status = NT_STATUS_INTERNAL_ERROR;
goto err_out;
}
+#endif
*_gse_ctx = gse_ctx;
TALLOC_FREE(name_buffer.value);
@@ -541,193 +572,6 @@ done:
return errstr;
}
-static size_t gse_get_signature_length(struct gse_context *gse_ctx,
- bool seal, size_t payload_size)
-{
- OM_uint32 gss_min, gss_maj;
- gss_iov_buffer_desc iov[2];
- int sealed;
-
- /*
- * gss_wrap_iov_length() only needs the type and length
- */
- iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
- iov[0].buffer.value = NULL;
- iov[0].buffer.length = 0;
- iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
- iov[1].buffer.value = NULL;
- iov[1].buffer.length = payload_size;
-
- gss_maj = gss_wrap_iov_length(&gss_min, gse_ctx->gssapi_context,
- seal, GSS_C_QOP_DEFAULT,
- &sealed, iov, 2);
- if (gss_maj) {
- DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
- gse_errstr(talloc_tos(), gss_maj, gss_min)));
- return 0;
- }
-
- return iov[0].buffer.length;
-}
-
-static NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
- DATA_BLOB *data, DATA_BLOB *signature)
-{
- OM_uint32 gss_min, gss_maj;
- gss_iov_buffer_desc iov[2];
- int req_seal = 1; /* setting to 1 means we request sign+seal */
- int sealed = 1;
- NTSTATUS status;
-
- /* allocate the memory ourselves so we do not need to talloc_memdup */
- signature->length = gse_get_signature_length(gse_ctx, true, data->length);
- if (!signature->length) {
- return NT_STATUS_INTERNAL_ERROR;
- }
- signature->data = (uint8_t *)talloc_size(mem_ctx, signature->length);
- if (!signature->data) {
- return NT_STATUS_NO_MEMORY;
- }
- iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
- iov[0].buffer.value = signature->data;
- iov[0].buffer.length = signature->length;
-
- /* data is encrypted in place, which is ok */
- iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
- iov[1].buffer.value = data->data;
- iov[1].buffer.length = data->length;
-
- gss_maj = gss_wrap_iov(&gss_min, gse_ctx->gssapi_context,
- req_seal, GSS_C_QOP_DEFAULT,
- &sealed, iov, 2);
- if (gss_maj) {
- DEBUG(0, ("gss_wrap_iov failed with [%s]\n",
- gse_errstr(talloc_tos(), gss_maj, gss_min)));
- status = NT_STATUS_ACCESS_DENIED;
- goto done;
- }
-
- if (!sealed) {
- DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
- status = NT_STATUS_ACCESS_DENIED;
- goto done;
- }
-
- status = NT_STATUS_OK;
-
- DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
- (int)iov[1].buffer.length, (int)iov[0].buffer.length));
-
-done:
- return status;
-}
-
-static NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
- DATA_BLOB *data, const DATA_BLOB *signature)
-{
- OM_uint32 gss_min, gss_maj;
- gss_iov_buffer_desc iov[2];
- int sealed;
- NTSTATUS status;
-
- iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
- iov[0].buffer.value = signature->data;
- iov[0].buffer.length = signature->length;
-
- /* data is decrypted in place, which is ok */
- iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
- iov[1].buffer.value = data->data;
- iov[1].buffer.length = data->length;
-
- gss_maj = gss_unwrap_iov(&gss_min, gse_ctx->gssapi_context,
- &sealed, NULL, iov, 2);
- if (gss_maj) {
- DEBUG(0, ("gss_unwrap_iov failed with [%s]\n",
- gse_errstr(talloc_tos(), gss_maj, gss_min)));
- status = NT_STATUS_ACCESS_DENIED;
- goto done;
- }
-
- if (!sealed) {
- DEBUG(0, ("gss_unwrap_iov says data is not sealed!\n"));
- status = NT_STATUS_ACCESS_DENIED;
- goto done;
- }
-
- status = NT_STATUS_OK;
-
- DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
- (int)iov[1].buffer.length, (int)iov[0].buffer.length));
-
-done:
- return status;
-}
-
-static NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
- DATA_BLOB *data, DATA_BLOB *signature)
-{
- OM_uint32 gss_min, gss_maj;
- gss_buffer_desc in_data = { 0, NULL };
- gss_buffer_desc out_data = { 0, NULL};
- NTSTATUS status;
-
- in_data.value = data->data;
- in_data.length = data->length;
-
- gss_maj = gss_get_mic(&gss_min, gse_ctx->gssapi_context,
- GSS_C_QOP_DEFAULT,
- &in_data, &out_data);
- if (gss_maj) {
- DEBUG(0, ("gss_get_mic failed with [%s]\n",
- gse_errstr(talloc_tos(), gss_maj, gss_min)));
- status = NT_STATUS_ACCESS_DENIED;
- goto done;
- }
-
- *signature = data_blob_talloc(mem_ctx,
- out_data.value, out_data.length);
- if (!signature->data) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
- status = NT_STATUS_OK;
-
-done:
- if (out_data.value) {
- gss_maj = gss_release_buffer(&gss_min, &out_data);
- }
- return status;
-}
-
-static NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
- const DATA_BLOB *data, const DATA_BLOB *signature)
-{
- OM_uint32 gss_min, gss_maj;
- gss_buffer_desc in_data = { 0, NULL };
- gss_buffer_desc in_token = { 0, NULL};
- NTSTATUS status;
-
- in_data.value = data->data;
- in_data.length = data->length;
- in_token.value = signature->data;
- in_token.length = signature->length;
-
- gss_maj = gss_verify_mic(&gss_min, gse_ctx->gssapi_context,
- &in_data, &in_token, NULL);
- if (gss_maj) {
- DEBUG(0, ("gss_verify_mic failed with [%s]\n",
- gse_errstr(talloc_tos(), gss_maj, gss_min)));
- status = NT_STATUS_ACCESS_DENIED;
- goto done;
- }
-
- status = NT_STATUS_OK;
-
-done:
- return status;
-}
-
static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security)
{
struct gse_context *gse_ctx;
@@ -753,6 +597,9 @@ static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security)
return NT_STATUS_INVALID_PARAMETER;
}
+ if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
+ do_sign = true;
+ }
if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
do_sign = true;
}
@@ -921,8 +768,31 @@ static NTSTATUS gensec_gse_seal_packet(struct gensec_security *gensec_security,
struct gse_context *gse_ctx =
talloc_get_type_abort(gensec_security->private_data,
struct gse_context);
- DATA_BLOB payload = data_blob_const(data, length);
- return gse_seal(mem_ctx, gse_ctx, &payload, sig);
+ bool hdr_signing = false;
+ size_t sig_size = 0;
+ NTSTATUS status;
+
+ if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+ hdr_signing = true;
+ }
+
+ sig_size = gensec_gse_sig_size(gensec_security, length);
+
+ status = gssapi_seal_packet(gse_ctx->gssapi_context,
+ &gse_ctx->gss_mech,
+ hdr_signing, sig_size,
+ data, length,
+ whole_pdu, pdu_length,
+ mem_ctx, sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%ju,"
+ "data=%ju,pdu=%ju) failed: %s\n",
+ hdr_signing, sig_size, length, pdu_length,
+ nt_errstr(status)));
+ return status;
+ }
+
+ return NT_STATUS_OK;
}
static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security,
@@ -933,8 +803,28 @@ static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security
struct gse_context *gse_ctx =
talloc_get_type_abort(gensec_security->private_data,
struct gse_context);
- DATA_BLOB payload = data_blob_const(data, length);
- return gse_unseal(talloc_tos() /* unused */, gse_ctx, &payload, sig);
+ bool hdr_signing = false;
+ NTSTATUS status;
+
+ if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+ hdr_signing = true;
+ }
+
+ status = gssapi_unseal_packet(gse_ctx->gssapi_context,
+ &gse_ctx->gss_mech,
+ hdr_signing,
+ data, length,
+ whole_pdu, pdu_length,
+ sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%ju,"
+ "data=%ju,pdu=%ju) failed: %s\n",
+ hdr_signing, sig->length, length, pdu_length,
+ nt_errstr(status)));
+ return status;
+ }
+
+ return NT_STATUS_OK;
}
static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security,
@@ -946,8 +836,28 @@ static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security,
struct gse_context *gse_ctx =
talloc_get_type_abort(gensec_security->private_data,
struct gse_context);
- DATA_BLOB payload = data_blob_const(data, length);
- return gse_sign(mem_ctx, gse_ctx, &payload, sig);
+ bool hdr_signing = false;
+ NTSTATUS status;
+
+ if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+ hdr_signing = true;
+ }
+
+ status = gssapi_sign_packet(gse_ctx->gssapi_context,
+ &gse_ctx->gss_mech,
+ hdr_signing,
+ data, length,
+ whole_pdu, pdu_length,
+ mem_ctx, sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u,"
+ "data=%ju,pdu=%ju) failed: %s\n",
+ hdr_signing, length, pdu_length,
+ nt_errstr(status)));
+ return status;
+ }
+
+ return NT_STATUS_OK;
}
static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security,
@@ -958,8 +868,28 @@ static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security,
struct gse_context *gse_ctx =
talloc_get_type_abort(gensec_security->private_data,
struct gse_context);
- DATA_BLOB payload = data_blob_const(data, length);
- return gse_sigcheck(NULL, gse_ctx, &payload, sig);
+ bool hdr_signing = false;
+ NTSTATUS status;
+
+ if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+ hdr_signing = true;
+ }
+
+ status = gssapi_check_packet(gse_ctx->gssapi_context,
+ &gse_ctx->gss_mech,
+ hdr_signing,
+ data, length,
+ whole_pdu, pdu_length,
+ sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%ju"
+ "data=%ju,pdu=%ju) failed: %s\n",
+ hdr_signing, sig->length, length, pdu_length,
+ nt_errstr(status)));
+ return status;
+ }
+
+ return NT_STATUS_OK;
}
/* Try to figure out what features we actually got on the connection */
@@ -970,18 +900,15 @@ static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
talloc_get_type_abort(gensec_security->private_data,
struct gse_context);
+ if (feature & GENSEC_FEATURE_SESSION_KEY) {
+ return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
+ }
if (feature & GENSEC_FEATURE_SIGN) {
return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
}
if (feature & GENSEC_FEATURE_SEAL) {
return gse_ctx->gss_got_flags & GSS_C_CONF_FLAG;
}
- if (feature & GENSEC_FEATURE_SESSION_KEY) {
- /* Only for GSE/Krb5 */
- if (smb_gss_oid_equal(gse_ctx->ret_mech, gss_mech_krb5)) {
- return true;
- }
- }
if (feature & GENSEC_FEATURE_DCE_STYLE) {
return gse_ctx->gss_got_flags & GSS_C_DCE_STYLE;
}
@@ -1019,6 +946,17 @@ static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
return true;
}
+ if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+ if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
+ return true;
+ }
+
+ if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
+ return true;
+ }
+
+ return false;
+ }
return false;
}
@@ -1126,6 +1064,40 @@ static NTSTATUS gensec_gse_session_info(struct gensec_security *gensec_security,
return NT_STATUS_OK;
}
+static size_t gensec_gse_max_input_size(struct gensec_security *gensec_security)
+{
+ struct gse_context *gse_ctx =
+ talloc_get_type_abort(gensec_security->private_data,
+ struct gse_context);
+ OM_uint32 maj_stat, min_stat;
+ OM_uint32 max_input_size;
+
+ maj_stat = gss_wrap_size_limit(&min_stat,
+ gse_ctx->gssapi_context,
+ gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
+ GSS_C_QOP_DEFAULT,
+ gse_ctx->max_wrap_buf_size,
+ &max_input_size);
+ if (GSS_ERROR(maj_stat)) {
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DEBUG(1, ("gensec_gssapi_max_input_size: determining signature size with gss_wrap_size_limit failed: %s\n",
+ gse_errstr(mem_ctx, maj_stat, min_stat)));
+ talloc_free(mem_ctx);
+ return 0;
+ }
+
+ return max_input_size;
+}
+
+/* Find out the maximum output size negotiated on this connection */
+static size_t gensec_gse_max_wrapped_size(struct gensec_security *gensec_security)
+{
+ struct gse_context *gse_ctx =
+ talloc_get_type_abort(gensec_security->private_data,
+ struct gse_context);
+ return gse_ctx->max_wrap_buf_size;
+}
+
static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
size_t data_size)
{
@@ -1133,9 +1105,15 @@ static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
talloc_get_type_abort(gensec_security->private_data,
struct gse_context);
- return gse_get_signature_length(gse_ctx,
- gensec_security->want_features & GENSEC_FEATURE_SEAL,
- data_size);
+ if (gse_ctx->sig_size > 0) {
+ return gse_ctx->sig_size;
+ }
+
+ gse_ctx->sig_size = gssapi_get_sig_size(gse_ctx->gssapi_context,
+ &gse_ctx->gss_mech,
+ gse_ctx->gss_want_flags,
+ data_size);
+ return gse_ctx->sig_size;
}
static const char *gensec_gse_krb5_oids[] = {
@@ -1159,6 +1137,8 @@ const struct gensec_security_ops gensec_gse_krb5_security_ops = {
.check_packet = gensec_gse_check_packet,
.seal_packet = gensec_gse_seal_packet,
.unseal_packet = gensec_gse_unseal_packet,
+ .max_input_size = gensec_gse_max_input_size,
+ .max_wrapped_size = gensec_gse_max_wrapped_size,
.wrap = gensec_gse_wrap,
.unwrap = gensec_gse_unwrap,
.have_feature = gensec_gse_have_feature,
diff --git a/source3/librpc/rpc/dcerpc.h b/source3/librpc/rpc/dcerpc.h
index e7d66b7252b..183801228f5 100644
--- a/source3/librpc/rpc/dcerpc.h
+++ b/source3/librpc/rpc/dcerpc.h
@@ -40,6 +40,7 @@ struct gensec_security;
struct pipe_auth_data {
enum dcerpc_AuthType auth_type;
enum dcerpc_AuthLevel auth_level;
+ uint32_t auth_context_id;
bool client_hdr_signing;
bool hdr_signing;
bool verified_bitmask1;
@@ -69,10 +70,6 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx,
uint32_t auth_context_id,
const DATA_BLOB *credentials,
DATA_BLOB *blob);
-NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx,
- const DATA_BLOB *blob,
- struct dcerpc_auth *r,
- bool bigendian);
NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth,
size_t header_len, size_t data_left,
size_t max_xmit_frag,
@@ -83,8 +80,7 @@ NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
struct ncacn_packet *pkt,
DATA_BLOB *pkt_trailer,
- size_t header_size,
- DATA_BLOB *raw_pkt,
- size_t *pad_len);
+ uint8_t header_size,
+ DATA_BLOB *raw_pkt);
#endif /* __S3_DCERPC_H__ */
diff --git a/source3/librpc/rpc/dcerpc_helpers.c b/source3/librpc/rpc/dcerpc_helpers.c
index 1193baa7983..aab43a1abd4 100644
--- a/source3/librpc/rpc/dcerpc_helpers.c
+++ b/source3/librpc/rpc/dcerpc_helpers.c
@@ -177,47 +177,6 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx,
}
/**
-* @brief Decodes a dcerpc_auth blob
-*
-* @param mem_ctx The memory context on which to allocate the packet
-* elements
-* @param blob The blob of data to decode
-* @param r An empty dcerpc_auth structure, must not be NULL
-*
-* @return a NTSTATUS error code
-*/
-NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx,
- const DATA_BLOB *blob,
- struct dcerpc_auth *r,
- bool bigendian)
-{
- enum ndr_err_code ndr_err;
- struct ndr_pull *ndr;
-
- ndr = ndr_pull_init_blob(blob, mem_ctx);
- if (!ndr) {
- return NT_STATUS_NO_MEMORY;
- }
- if (bigendian) {
- ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
- }
-
- ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, r);
-
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- talloc_free(ndr);
- return ndr_map_error2ntstatus(ndr_err);
- }
- talloc_free(ndr);
-
- if (DEBUGLEVEL >= 10) {
- NDR_PRINT_DEBUG(dcerpc_auth, r);
- }
-
- return NT_STATUS_OK;
-}
-
-/**
* @brief Calculate how much data we can in a packet, including calculating
* auth token and pad lengths.
*
@@ -444,7 +403,7 @@ NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
auth->auth_type,
auth->auth_level,
pad_len,
- 1 /* context id. */,
+ auth->auth_context_id,
&auth_blob,
&auth_info);
if (!NT_STATUS_IS_OK(status)) {
@@ -481,19 +440,18 @@ NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
*
* @param auth The auth data for the connection
* @param pkt The actual ncacn_packet
-* @param pkt_trailer The stub_and_verifier part of the packet
+* @param pkt_trailer [in][out] The stub_and_verifier part of the packet,
+* the auth_trailer and padding will be removed.
* @param header_size The header size
* @param raw_pkt The whole raw packet data blob
-* @param pad_len [out] The padding length used in the packet
*
* @return A NTSTATUS error code
*/
NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
struct ncacn_packet *pkt,
DATA_BLOB *pkt_trailer,
- size_t header_size,
- DATA_BLOB *raw_pkt,
- size_t *pad_len)
+ uint8_t header_size,
+ DATA_BLOB *raw_pkt)
{
struct gensec_security *gensec_security;
NTSTATUS status;
@@ -502,6 +460,14 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
DATA_BLOB full_pkt;
DATA_BLOB data;
+ /*
+ * These check should be done in the caller.
+ */
+ SMB_ASSERT(raw_pkt->length == pkt->frag_length);
+ SMB_ASSERT(header_size <= pkt->frag_length);
+ SMB_ASSERT(pkt_trailer->length < pkt->frag_length);
+ SMB_ASSERT((pkt_trailer->length + header_size) <= pkt->frag_length);
+
switch (auth->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
DEBUG(10, ("Requested Privacy.\n"));
@@ -515,7 +481,6 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
if (pkt->auth_length != 0) {
break;
}
- *pad_len = 0;
return NT_STATUS_OK;
case DCERPC_AUTH_LEVEL_NONE:
@@ -524,7 +489,6 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
"authenticated connection!\n"));
return NT_STATUS_INVALID_PARAMETER;
}
- *pad_len = 0;
return NT_STATUS_OK;
default:
@@ -533,16 +497,8 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
return NT_STATUS_INVALID_PARAMETER;
}
- /* Paranioa checks for auth_length. */
- if (pkt->auth_length > pkt->frag_length) {
- return NT_STATUS_INFO_LENGTH_MISMATCH;
- }
- if (((unsigned int)pkt->auth_length
- + DCERPC_AUTH_TRAILER_LENGTH < (unsigned int)pkt->auth_length) ||
- ((unsigned int)pkt->auth_length
- + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) {
- /* Integer wrap attempt. */
- return NT_STATUS_INFO_LENGTH_MISMATCH;
+ if (pkt->auth_length == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
}
status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
@@ -551,10 +507,23 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
return status;
}
+ if (auth_info.auth_type != auth->auth_type) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (auth_info.auth_level != auth->auth_level) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (auth_info.auth_context_id != auth->auth_context_id) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ pkt_trailer->length -= auth_length;
data = data_blob_const(raw_pkt->data + header_size,
- pkt_trailer->length - auth_length);
- full_pkt = data_blob_const(raw_pkt->data,
- raw_pkt->length - auth_info.credentials.length);
+ pkt_trailer->length);
+ full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length);
+ full_pkt.length -= auth_info.credentials.length;
switch (auth->auth_type) {
case DCERPC_AUTH_TYPE_NONE:
@@ -579,10 +548,13 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
* pkt_trailer actually has a copy of the raw data, and they
* are still both used in later calls */
if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ if (pkt_trailer->length != data.length) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
memcpy(pkt_trailer->data, data.data, data.length);
}
- *pad_len = auth_info.auth_pad_length;
+ pkt_trailer->length -= auth_info.auth_pad_length;
data_blob_free(&auth_info.credentials);
return NT_STATUS_OK;
}
diff --git a/source3/libsmb/auth_generic.c b/source3/libsmb/auth_generic.c
index 1f6c681a6e5..2e45cdbc53e 100644
--- a/source3/libsmb/auth_generic.c
+++ b/source3/libsmb/auth_generic.c
@@ -78,7 +78,7 @@ NTSTATUS auth_generic_client_prepare(TALLOC_CTX *mem_ctx, struct auth_generic_st
}
backends = talloc_zero_array(gensec_settings,
- const struct gensec_security_ops *, 6);
+ const struct gensec_security_ops *, 7);
if (backends == NULL) {
TALLOC_FREE(ans);
return NT_STATUS_NO_MEMORY;
@@ -92,7 +92,8 @@ NTSTATUS auth_generic_client_prepare(TALLOC_CTX *mem_ctx, struct auth_generic_st
backends[idx++] = &gensec_gse_krb5_security_ops;
#endif
- backends[idx++] = &gensec_ntlmssp3_client_ops;
+ backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
+ backends[idx++] = gensec_security_by_name(NULL, "ntlmssp_resume_ccache");
backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
backends[idx++] = gensec_security_by_auth_type(NULL, DCERPC_AUTH_TYPE_SCHANNEL);
@@ -143,6 +144,29 @@ NTSTATUS auth_generic_client_start(struct auth_generic_state *ans, const char *o
return NT_STATUS_OK;
}
+NTSTATUS auth_generic_client_start_by_name(struct auth_generic_state *ans,
+ const char *name)
+{
+ NTSTATUS status;
+
+ /* Transfer the credentials to gensec */
+ status = gensec_set_credentials(ans->gensec_security, ans->credentials);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to set GENSEC credentials: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ talloc_unlink(ans, ans->credentials);
+ ans->credentials = NULL;
+
+ status = gensec_start_mech_by_name(ans->gensec_security, name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
NTSTATUS auth_generic_client_start_by_authtype(struct auth_generic_state *ans,
uint8_t auth_type,
uint8_t auth_level)
@@ -167,3 +191,26 @@ NTSTATUS auth_generic_client_start_by_authtype(struct auth_generic_state *ans,
return NT_STATUS_OK;
}
+
+NTSTATUS auth_generic_client_start_by_sasl(struct auth_generic_state *ans,
+ const char **sasl_list)
+{
+ NTSTATUS status;
+
+ /* Transfer the credentials to gensec */
+ status = gensec_set_credentials(ans->gensec_security, ans->credentials);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to set GENSEC credentials: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ talloc_unlink(ans, ans->credentials);
+ ans->credentials = NULL;
+
+ status = gensec_start_mech_by_sasl_list(ans->gensec_security, sasl_list);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 46d3da3fc45..039fba2c71b 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -26,7 +26,10 @@
#include "../libcli/auth/libcli_auth.h"
#include "../libcli/auth/spnego.h"
#include "smb_krb5.h"
-#include "../auth/ntlmssp/ntlmssp.h"
+#include "auth/credentials/credentials.h"
+#include "auth/gensec/gensec.h"
+#include "auth/ntlmssp/ntlmssp.h"
+#include "auth_generic.h"
#include "libads/kerberos_proto.h"
#include "krb5_env.h"
#include "../lib/util/tevent_ntstatus.h"
@@ -1282,218 +1285,179 @@ static void use_in_memory_ccache(void) {
setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
}
+#endif /* HAVE_KRB5 */
+
/****************************************************************************
- Do a spnego/kerberos encrypted session setup.
+ Do a spnego/NTLMSSP encrypted session setup.
****************************************************************************/
-struct cli_session_setup_kerberos_state {
+struct cli_session_setup_gensec_state {
+ struct tevent_context *ev;
struct cli_state *cli;
- DATA_BLOB negTokenTarg;
- DATA_BLOB session_key_krb5;
- ADS_STATUS ads_status;
+ struct auth_generic_state *auth_generic;
+ bool is_anonymous;
+ DATA_BLOB blob_in;
+ uint8_t *inbuf;
+ struct iovec *recv_iov;
+ DATA_BLOB blob_out;
+ bool local_ready;
+ bool remote_ready;
+ DATA_BLOB session_key;
};
-static void cli_session_setup_kerberos_done(struct tevent_req *subreq);
+static int cli_session_setup_gensec_state_destructor(
+ struct cli_session_setup_gensec_state *state)
+{
+ TALLOC_FREE(state->auth_generic);
+ data_blob_clear_free(&state->session_key);
+ return 0;
+}
-static struct tevent_req *cli_session_setup_kerberos_send(
+static void cli_session_setup_gensec_local_next(struct tevent_req *req);
+static void cli_session_setup_gensec_local_done(struct tevent_req *subreq);
+static void cli_session_setup_gensec_remote_next(struct tevent_req *req);
+static void cli_session_setup_gensec_remote_done(struct tevent_req *subreq);
+static void cli_session_setup_gensec_ready(struct tevent_req *req);
+
+static struct tevent_req *cli_session_setup_gensec_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
- const char *principal)
+ const char *user, const char *pass, const char *domain,
+ enum credentials_use_kerberos krb5_state,
+ const char *target_service,
+ const char *target_hostname,
+ const char *target_principal)
{
- struct tevent_req *req, *subreq;
- struct cli_session_setup_kerberos_state *state;
- int rc;
-
- DEBUG(2,("Doing kerberos session setup\n"));
+ struct tevent_req *req;
+ struct cli_session_setup_gensec_state *state;
+ NTSTATUS status;
+ bool use_spnego_principal = lp_client_use_spnego_principal();
req = tevent_req_create(mem_ctx, &state,
- struct cli_session_setup_kerberos_state);
+ struct cli_session_setup_gensec_state);
if (req == NULL) {
return NULL;
}
+ state->ev = ev;
state->cli = cli;
- state->ads_status = ADS_SUCCESS;
- /*
- * Ok, this is cheating: spnego_gen_krb5_negTokenInit can block if
- * we have to acquire a ticket. To be fixed later :-)
- */
- rc = spnego_gen_krb5_negTokenInit(state, principal, 0, &state->negTokenTarg,
- &state->session_key_krb5, 0, NULL, NULL);
- if (rc) {
- DEBUG(1, ("cli_session_setup_kerberos: "
- "spnego_gen_krb5_negTokenInit failed: %s\n",
- error_message(rc)));
- state->ads_status = ADS_ERROR_KRB5(rc);
- tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ talloc_set_destructor(
+ state, cli_session_setup_gensec_state_destructor);
+
+ status = auth_generic_client_prepare(state, &state->auth_generic);
+ if (tevent_req_nterror(req, status)) {
return tevent_req_post(req, ev);
}
-#if 0
- file_save("negTokenTarg.dat", state->negTokenTarg.data,
- state->negTokenTarg.length);
-#endif
-
- if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- state->cli->smb2.session = smbXcli_session_create(cli,
- cli->conn);
- if (tevent_req_nomem(state->cli->smb2.session, req)) {
- return tevent_req_post(req, ev);
+ gensec_want_feature(state->auth_generic->gensec_security,
+ GENSEC_FEATURE_SESSION_KEY);
+ if (cli->use_ccache) {
+ gensec_want_feature(state->auth_generic->gensec_security,
+ GENSEC_FEATURE_NTLM_CCACHE);
+ if (pass != NULL && strlen(pass) == 0) {
+ /*
+ * some callers pass "" as no password
+ *
+ * GENSEC_FEATURE_NTLM_CCACHE only handles
+ * NULL as no password.
+ */
+ pass = NULL;
}
}
- subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
- if (tevent_req_nomem(subreq, req)) {
+ status = auth_generic_set_username(state->auth_generic, user);
+ if (tevent_req_nterror(req, status)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req);
- return req;
-}
-static void cli_session_setup_kerberos_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct cli_session_setup_kerberos_state *state = tevent_req_data(
- req, struct cli_session_setup_kerberos_state);
- uint8_t *inbuf = NULL;
- struct iovec *recv_iov = NULL;
- NTSTATUS status;
-
- status = cli_sesssetup_blob_recv(subreq, state,
- NULL, &inbuf, &recv_iov);
- TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
+ status = auth_generic_set_domain(state->auth_generic, domain);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
}
- if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
- struct smbXcli_session *session = state->cli->smb2.session;
- status = smb2cli_session_set_session_key(session,
- state->session_key_krb5,
- recv_iov);
- if (tevent_req_nterror(req, status)) {
- return;
+ if (cli->pw_nt_hash) {
+ struct samr_Password nt_hash;
+ size_t converted;
+ bool ok;
+
+ if (pass == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
}
- } else {
- struct smbXcli_session *session = state->cli->smb1.session;
- status = smb1cli_session_set_session_key(session,
- state->session_key_krb5);
- if (tevent_req_nterror(req, status)) {
- return;
+ converted = strhex_to_str((char *)nt_hash.hash,
+ sizeof(nt_hash.hash),
+ pass, strlen(pass));
+ if (converted != sizeof(nt_hash.hash)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
}
- if (smb1cli_conn_activate_signing(state->cli->conn, state->session_key_krb5,
- data_blob_null)
- && !smb1cli_conn_check_signing(state->cli->conn, inbuf, 1)) {
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
+ ok = cli_credentials_set_nt_hash(state->auth_generic->credentials,
+ &nt_hash, CRED_SPECIFIED);
+ if (!ok) {
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
+ }
+ } else {
+ status = auth_generic_set_password(state->auth_generic, pass);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
}
}
- tevent_req_done(req);
-}
+ cli_credentials_set_kerberos_state(state->auth_generic->credentials,
+ krb5_state);
-static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req)
-{
- struct cli_session_setup_kerberos_state *state = tevent_req_data(
- req, struct cli_session_setup_kerberos_state);
- NTSTATUS status;
-
- if (tevent_req_is_nterror(req, &status)) {
- return ADS_ERROR_NT(status);
+ if (krb5_state == CRED_DONT_USE_KERBEROS) {
+ use_spnego_principal = false;
}
- return state->ads_status;
-}
-
-#endif /* HAVE_KRB5 */
-
-/****************************************************************************
- Do a spnego/NTLMSSP encrypted session setup.
-****************************************************************************/
-
-struct cli_session_setup_ntlmssp_state {
- struct tevent_context *ev;
- struct cli_state *cli;
- struct ntlmssp_state *ntlmssp_state;
- int turn;
- DATA_BLOB blob_out;
-};
-static int cli_session_setup_ntlmssp_state_destructor(
- struct cli_session_setup_ntlmssp_state *state)
-{
- if (state->ntlmssp_state != NULL) {
- TALLOC_FREE(state->ntlmssp_state);
+ if (target_service != NULL) {
+ status = gensec_set_target_service(
+ state->auth_generic->gensec_security,
+ target_service);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
}
- return 0;
-}
-static void cli_session_setup_ntlmssp_done(struct tevent_req *req);
+ if (target_hostname != NULL) {
+ status = gensec_set_target_hostname(
+ state->auth_generic->gensec_security,
+ target_hostname);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ }
-static struct tevent_req *cli_session_setup_ntlmssp_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
- const char *user, const char *pass, const char *domain)
-{
- struct tevent_req *req, *subreq;
- struct cli_session_setup_ntlmssp_state *state;
- NTSTATUS status;
- DATA_BLOB blob_out;
- const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
+ if (target_principal != NULL) {
+ status = gensec_set_target_principal(
+ state->auth_generic->gensec_security,
+ target_principal);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ use_spnego_principal = false;
+ } else if (target_service != NULL && target_hostname != NULL) {
+ use_spnego_principal = false;
+ }
- req = tevent_req_create(mem_ctx, &state,
- struct cli_session_setup_ntlmssp_state);
- if (req == NULL) {
- return NULL;
+ if (use_spnego_principal) {
+ const DATA_BLOB *b;
+ b = smbXcli_conn_server_gss_blob(cli->conn);
+ if (b != NULL) {
+ state->blob_in = *b;
+ }
}
- state->ev = ev;
- state->cli = cli;
- state->turn = 1;
- state->ntlmssp_state = NULL;
- talloc_set_destructor(
- state, cli_session_setup_ntlmssp_state_destructor);
+ state->is_anonymous = cli_credentials_is_anonymous(state->auth_generic->credentials);
- status = ntlmssp_client_start(state,
- lp_netbios_name(),
- lp_workgroup(),
- lp_client_ntlmv2_auth(),
- &state->ntlmssp_state);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- ntlmssp_want_feature(state->ntlmssp_state,
- NTLMSSP_FEATURE_SESSION_KEY);
- if (cli->use_ccache) {
- ntlmssp_want_feature(state->ntlmssp_state,
- NTLMSSP_FEATURE_CCACHE);
- }
- status = ntlmssp_set_username(state->ntlmssp_state, user);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- status = ntlmssp_set_domain(state->ntlmssp_state, domain);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- if (cli->pw_nt_hash) {
- status = ntlmssp_set_password_hash(state->ntlmssp_state, pass);
- } else {
- status = ntlmssp_set_password(state->ntlmssp_state, pass);
- }
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- status = ntlmssp_update(state->ntlmssp_state, data_blob_null,
- &blob_out);
- if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- goto fail;
+ status = auth_generic_client_start(state->auth_generic,
+ GENSEC_OID_SPNEGO);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
}
- state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
- data_blob_free(&blob_out);
-
if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
state->cli->smb2.session = smbXcli_session_create(cli,
cli->conn);
@@ -1502,150 +1466,226 @@ static struct tevent_req *cli_session_setup_ntlmssp_send(
}
}
- subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
- if (tevent_req_nomem(subreq, req)) {
+ cli_session_setup_gensec_local_next(req);
+ if (!tevent_req_is_in_progress(req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
+
return req;
-fail:
- tevent_req_nterror(req, status);
- return tevent_req_post(req, ev);
}
-static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
+static void cli_session_setup_gensec_local_next(struct tevent_req *req)
{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
- req, struct cli_session_setup_ntlmssp_state);
- DATA_BLOB blob_in, msg_in, blob_out;
- uint8_t *inbuf = NULL;
- struct iovec *recv_iov = NULL;
- bool parse_ret;
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
+ struct tevent_req *subreq = NULL;
+
+ if (state->local_ready) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ subreq = gensec_update_send(state, state->ev,
+ state->auth_generic->gensec_security,
+ state->blob_in);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_gensec_local_done, req);
+}
+
+static void cli_session_setup_gensec_local_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
NTSTATUS status;
- status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in,
- &inbuf, &recv_iov);
+ status = gensec_update_recv(subreq, state, &state->blob_out);
TALLOC_FREE(subreq);
- data_blob_free(&state->blob_out);
+ state->blob_in = data_blob_null;
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED))
+ {
+ tevent_req_nterror(req, status);
+ return;
+ }
if (NT_STATUS_IS_OK(status)) {
- if (state->cli->server_domain[0] == '\0') {
- TALLOC_FREE(state->cli->server_domain);
- state->cli->server_domain = talloc_strdup(state->cli,
- state->ntlmssp_state->server.netbios_domain);
- if (state->cli->server_domain == NULL) {
- tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
- return;
- }
- }
+ state->local_ready = true;
+ }
- if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
- struct smbXcli_session *session = state->cli->smb2.session;
+ if (state->local_ready && state->remote_ready) {
+ cli_session_setup_gensec_ready(req);
+ return;
+ }
- if (ntlmssp_is_anonymous(state->ntlmssp_state)) {
- /*
- * Windows server does not set the
- * SMB2_SESSION_FLAG_IS_GUEST nor
- * SMB2_SESSION_FLAG_IS_NULL flag.
- *
- * This fix makes sure we do not try
- * to verify a signature on the final
- * session setup response.
- */
- TALLOC_FREE(state->ntlmssp_state);
- tevent_req_done(req);
- return;
- }
+ cli_session_setup_gensec_remote_next(req);
+}
- status = smb2cli_session_set_session_key(session,
- state->ntlmssp_state->session_key,
- recv_iov);
- if (tevent_req_nterror(req, status)) {
- return;
- }
- } else {
- struct smbXcli_session *session = state->cli->smb1.session;
+static void cli_session_setup_gensec_remote_next(struct tevent_req *req)
+{
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
+ struct tevent_req *subreq = NULL;
- status = smb1cli_session_set_session_key(session,
- state->ntlmssp_state->session_key);
- if (tevent_req_nterror(req, status)) {
- return;
- }
+ if (state->remote_ready) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
- if (smb1cli_conn_activate_signing(
- state->cli->conn, state->ntlmssp_state->session_key,
- data_blob_null)
- && !smb1cli_conn_check_signing(state->cli->conn, inbuf, 1)) {
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
- }
- }
- TALLOC_FREE(state->ntlmssp_state);
- tevent_req_done(req);
+ subreq = cli_sesssetup_blob_send(state, state->ev,
+ state->cli, state->blob_out);
+ if (tevent_req_nomem(subreq, req)) {
return;
}
- if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_set_callback(subreq,
+ cli_session_setup_gensec_remote_done,
+ req);
+}
+
+static void cli_session_setup_gensec_remote_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
+ NTSTATUS status;
+
+ TALLOC_FREE(state->inbuf);
+ TALLOC_FREE(state->recv_iov);
+
+ status = cli_sesssetup_blob_recv(subreq, state, &state->blob_in,
+ &state->inbuf, &state->recv_iov);
+ TALLOC_FREE(subreq);
+ data_blob_free(&state->blob_out);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED))
+ {
tevent_req_nterror(req, status);
return;
}
- if (blob_in.length == 0) {
- tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
- return;
+ if (NT_STATUS_IS_OK(status)) {
+ state->remote_ready = true;
}
- if ((state->turn == 1)
- && NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- DATA_BLOB tmp_blob = data_blob_null;
- /* the server might give us back two challenges */
- parse_ret = spnego_parse_challenge(state, blob_in, &msg_in,
- &tmp_blob);
- data_blob_free(&tmp_blob);
- } else {
- parse_ret = spnego_parse_auth_response(state, blob_in, status,
- OID_NTLMSSP, &msg_in);
- }
- state->turn += 1;
-
- if (!parse_ret) {
- DEBUG(3,("Failed to parse auth response\n"));
- if (NT_STATUS_IS_OK(status)
- || NT_STATUS_EQUAL(status,
- NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
+ if (state->local_ready && state->remote_ready) {
+ cli_session_setup_gensec_ready(req);
+ return;
}
- status = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out);
+ cli_session_setup_gensec_local_next(req);
+}
- if (!NT_STATUS_IS_OK(status)
- && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- TALLOC_FREE(state->ntlmssp_state);
- tevent_req_nterror(req, status);
+static void cli_session_setup_gensec_ready(struct tevent_req *req)
+{
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
+ const char *server_domain = NULL;
+ NTSTATUS status;
+
+ if (state->blob_in.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
- state->blob_out = spnego_gen_auth(state, blob_out);
- if (tevent_req_nomem(state->blob_out.data, req)) {
+ if (state->blob_out.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
- subreq = cli_sesssetup_blob_send(state, state->ev, state->cli,
- state->blob_out);
- if (tevent_req_nomem(subreq, req)) {
+ /*
+ * gensec_ntlmssp_server_domain() returns NULL
+ * if NTLMSSP is not used.
+ *
+ * We can remove this later
+ * and leave the server domain empty for SMB2 and above
+ * in future releases.
+ */
+ server_domain = gensec_ntlmssp_server_domain(
+ state->auth_generic->gensec_security);
+
+ if (state->cli->server_domain[0] == '\0' && server_domain != NULL) {
+ TALLOC_FREE(state->cli->server_domain);
+ state->cli->server_domain = talloc_strdup(state->cli,
+ server_domain);
+ if (state->cli->server_domain == NULL) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ }
+
+ status = gensec_session_key(state->auth_generic->gensec_security,
+ state, &state->session_key);
+ if (tevent_req_nterror(req, status)) {
return;
}
- tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
+
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ struct smbXcli_session *session = state->cli->smb2.session;
+
+ if (state->is_anonymous) {
+ /*
+ * Windows server does not set the
+ * SMB2_SESSION_FLAG_IS_GUEST nor
+ * SMB2_SESSION_FLAG_IS_NULL flag.
+ *
+ * This fix makes sure we do not try
+ * to verify a signature on the final
+ * session setup response.
+ */
+ tevent_req_done(req);
+ return;
+ }
+
+ status = smb2cli_session_set_session_key(session,
+ state->session_key,
+ state->recv_iov);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ } else {
+ struct smbXcli_session *session = state->cli->smb1.session;
+ bool active;
+
+ status = smb1cli_session_set_session_key(session,
+ state->session_key);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ active = smb1cli_conn_activate_signing(state->cli->conn,
+ state->session_key,
+ data_blob_null);
+ if (active) {
+ bool ok;
+
+ ok = smb1cli_conn_check_signing(state->cli->conn,
+ state->inbuf, 1);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ }
+ }
+
+ tevent_req_done(req);
}
-static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req)
+static NTSTATUS cli_session_setup_gensec_recv(struct tevent_req *req)
{
- struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
- req, struct cli_session_setup_ntlmssp_state);
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
@@ -1725,6 +1765,7 @@ static char *cli_session_setup_get_account(TALLOC_CTX *mem_ctx,
struct cli_session_setup_spnego_state {
struct tevent_context *ev;
struct cli_state *cli;
+ const char *target_hostname;
const char *user;
const char *account;
const char *pass;
@@ -1741,14 +1782,14 @@ static void cli_session_setup_spnego_done_ntlmssp(struct tevent_req *subreq);
static struct tevent_req *cli_session_setup_spnego_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
- const char *user, const char *pass, const char *user_domain,
- const char *dest_realm)
+ const char *user, const char *pass, const char *user_domain)
{
struct tevent_req *req, *subreq;
struct cli_session_setup_spnego_state *state;
char *principal = NULL;
char *OIDs[ASN1_MAX_OIDS];
int i;
+ const char *dest_realm = cli_state_remote_realm(cli);
const DATA_BLOB *server_blob;
NTSTATUS status;
@@ -1769,6 +1810,7 @@ static struct tevent_req *cli_session_setup_spnego_send(
return tevent_req_post(req, ev);
}
+ state->target_hostname = smbXcli_conn_remote_name(cli->conn);
server_blob = smbXcli_conn_server_gss_blob(cli->conn);
DEBUG(3,("Doing spnego session setup (blob length=%lu)\n",
@@ -1823,9 +1865,13 @@ static struct tevent_req *cli_session_setup_spnego_send(
* and do not store results */
if (user && *user && cli->got_kerberos_mechanism && cli->use_kerberos) {
- const char *remote_name = smbXcli_conn_remote_name(cli->conn);
char *tmp;
+ tmp = cli_session_setup_get_principal(
+ talloc_tos(), principal, state->target_hostname, dest_realm);
+ TALLOC_FREE(principal);
+ principal = tmp;
+
if (pass && *pass) {
int ret;
@@ -1833,8 +1879,8 @@ static struct tevent_req *cli_session_setup_spnego_send(
ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
if (ret){
+ DEBUG(0, ("Kinit for %s to access %s failed: %s\n", user, principal, error_message(ret)));
TALLOC_FREE(principal);
- DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
if (cli->fallback_after_kerberos)
goto ntlmssp;
state->result = ADS_ERROR_KRB5(ret);
@@ -1843,14 +1889,12 @@ static struct tevent_req *cli_session_setup_spnego_send(
}
}
- tmp = cli_session_setup_get_principal(
- talloc_tos(), principal, remote_name, dest_realm);
- TALLOC_FREE(principal);
- principal = tmp;
-
if (principal) {
- subreq = cli_session_setup_kerberos_send(
- state, ev, cli, principal);
+ subreq = cli_session_setup_gensec_send(
+ state, ev, cli,
+ state->account, pass, user_domain,
+ CRED_MUST_USE_KERBEROS,
+ "cifs", state->target_hostname, principal);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
@@ -1863,8 +1907,11 @@ static struct tevent_req *cli_session_setup_spnego_send(
#endif
ntlmssp:
- subreq = cli_session_setup_ntlmssp_send(
- state, ev, cli, state->account, pass, user_domain);
+ subreq = cli_session_setup_gensec_send(
+ state, state->ev, state->cli,
+ state->account, state->pass, state->user_domain,
+ CRED_DONT_USE_KERBEROS,
+ "cifs", state->target_hostname, NULL);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
@@ -1880,9 +1927,11 @@ static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq)
subreq, struct tevent_req);
struct cli_session_setup_spnego_state *state = tevent_req_data(
req, struct cli_session_setup_spnego_state);
+ NTSTATUS status;
- state->result = cli_session_setup_kerberos_recv(subreq);
+ status = cli_session_setup_gensec_recv(subreq);
TALLOC_FREE(subreq);
+ state->result = ADS_ERROR_NT(status);
if (ADS_ERR_OK(state->result) ||
!state->cli->fallback_after_kerberos) {
@@ -1890,9 +1939,11 @@ static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq)
return;
}
- subreq = cli_session_setup_ntlmssp_send(
- state, state->ev, state->cli, state->account, state->pass,
- state->user_domain);
+ subreq = cli_session_setup_gensec_send(
+ state, state->ev, state->cli,
+ state->account, state->pass, state->user_domain,
+ CRED_DONT_USE_KERBEROS,
+ "cifs", state->target_hostname, NULL);
if (tevent_req_nomem(subreq, req)) {
return;
}
@@ -1909,7 +1960,7 @@ static void cli_session_setup_spnego_done_ntlmssp(struct tevent_req *subreq)
req, struct cli_session_setup_spnego_state);
NTSTATUS status;
- status = cli_session_setup_ntlmssp_recv(subreq);
+ status = cli_session_setup_gensec_recv(subreq);
TALLOC_FREE(subreq);
state->result = ADS_ERROR_NT(status);
tevent_req_done(req);
@@ -2023,10 +2074,8 @@ struct tevent_req *cli_session_setup_send(TALLOC_CTX *mem_ctx,
}
if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- const char *remote_realm = cli_state_remote_realm(cli);
-
subreq = cli_session_setup_spnego_send(
- state, ev, cli, user, pass, workgroup, remote_realm);
+ state, ev, cli, user, pass, workgroup);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
@@ -2086,10 +2135,8 @@ struct tevent_req *cli_session_setup_send(TALLOC_CTX *mem_ctx,
/* if the server supports extended security then use SPNEGO */
if (smb1cli_conn_capabilities(cli->conn) & CAP_EXTENDED_SECURITY) {
- const char *remote_realm = cli_state_remote_realm(cli);
-
subreq = cli_session_setup_spnego_send(
- state, ev, cli, user, pass, workgroup, remote_realm);
+ state, ev, cli, user, pass, workgroup);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
@@ -2098,6 +2145,17 @@ struct tevent_req *cli_session_setup_send(TALLOC_CTX *mem_ctx,
return req;
} else {
/* otherwise do a NT1 style session setup */
+ if (lp_client_ntlmv2_auth() && lp_client_use_spnego()) {
+ /*
+ * Don't send an NTLMv2 response without NTLMSSP
+ * if we want to use spnego support
+ */
+ DEBUG(1, ("Server does not support EXTENDED_SECURITY "
+ " but 'client use spnego = yes"
+ " and 'client ntlmv2 auth = yes'\n"));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
+ }
subreq = cli_session_setup_nt1_send(
state, ev, cli, user, pass, passlen, ntpass, ntpasslen,
@@ -2410,7 +2468,7 @@ struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
* Non-encrypted passwords - convert to DOS codepage
* before using.
*/
- tmp_pass = talloc_array(talloc_tos(), uint8, 0);
+ tmp_pass = talloc_array(talloc_tos(), uint8_t, 0);
if (tevent_req_nomem(tmp_pass, req)) {
return tevent_req_post(req, ev);
}
@@ -2637,7 +2695,7 @@ static struct tevent_req *cli_raw_tcon_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
const char *service, const char *pass, const char *dev);
static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req,
- uint16 *max_xmit, uint16 *tid);
+ uint16_t *max_xmit, uint16_t *tid);
static void cli_tree_connect_smb2_done(struct tevent_req *subreq);
static void cli_tree_connect_andx_done(struct tevent_req *subreq);
@@ -3120,6 +3178,8 @@ fail:
struct cli_start_connection_state {
struct tevent_context *ev;
struct cli_state *cli;
+ int min_protocol;
+ int max_protocol;
};
static void cli_start_connection_connected(struct tevent_req *subreq);
@@ -3149,6 +3209,14 @@ static struct tevent_req *cli_start_connection_send(
}
state->ev = ev;
+ if (signing_state == SMB_SIGNING_IPC_DEFAULT) {
+ state->min_protocol = lp_client_ipc_min_protocol();
+ state->max_protocol = lp_client_ipc_max_protocol();
+ } else {
+ state->min_protocol = lp_client_min_protocol();
+ state->max_protocol = lp_client_max_protocol();
+ }
+
subreq = cli_connect_nb_send(state, ev, dest_host, dest_ss, port,
0x20, my_name, signing_state, flags);
if (tevent_req_nomem(subreq, req)) {
@@ -3174,8 +3242,8 @@ static void cli_start_connection_connected(struct tevent_req *subreq)
subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn,
state->cli->timeout,
- lp_client_min_protocol(),
- lp_client_max_protocol());
+ state->min_protocol,
+ state->max_protocol);
if (tevent_req_nomem(subreq, req)) {
return;
}
@@ -3543,7 +3611,7 @@ static void cli_raw_tcon_done(struct tevent_req *subreq)
}
static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req,
- uint16 *max_xmit, uint16 *tid)
+ uint16_t *max_xmit, uint16_t *tid)
{
struct cli_raw_tcon_state *state = tevent_req_data(
req, struct cli_raw_tcon_state);
@@ -3559,7 +3627,7 @@ static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req,
NTSTATUS cli_raw_tcon(struct cli_state *cli,
const char *service, const char *pass, const char *dev,
- uint16 *max_xmit, uint16 *tid)
+ uint16_t *max_xmit, uint16_t *tid)
{
struct tevent_context *ev;
struct tevent_req *req;
diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c
index be237540316..d8fa1c6b935 100644
--- a/source3/libsmb/clidgram.c
+++ b/source3/libsmb/clidgram.c
@@ -33,7 +33,7 @@
*/
static bool cli_prep_mailslot(bool unique, const char *mailslot,
- uint16 priority,
+ uint16_t priority,
char *buf, int len,
const char *srcname, int src_type,
const char *dstname, int dest_type,
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index 71ec1dcc99a..79e1392c5db 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -231,6 +231,15 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx,
use_level_II_oplocks = true;
}
+ if (signing_state == SMB_SIGNING_IPC_DEFAULT) {
+ /*
+ * Ensure for IPC/RPC the default is to require
+ * signing unless explicitly turned off by the
+ * administrator.
+ */
+ signing_state = lp_client_ipc_signing();
+ }
+
if (signing_state == SMB_SIGNING_DEFAULT) {
signing_state = lp_client_signing();
}
@@ -379,7 +388,7 @@ uint16_t cli_state_get_vc_num(struct cli_state *cli)
Set the PID to use for smb messages. Return the old pid.
****************************************************************************/
-uint16 cli_setpid(struct cli_state *cli, uint16 pid)
+uint16_t cli_setpid(struct cli_state *cli, uint16 pid)
{
uint16_t ret = cli->smb1.pid;
cli->smb1.pid = pid;
diff --git a/source3/libsmb/clierror.c b/source3/libsmb/clierror.c
index a53c9c4e1e8..f20980251f4 100644
--- a/source3/libsmb/clierror.c
+++ b/source3/libsmb/clierror.c
@@ -84,7 +84,7 @@ NTSTATUS cli_nt_error(struct cli_state *cli)
code.
****************************************************************************/
-void cli_dos_error(struct cli_state *cli, uint8 *eclass, uint32 *ecode)
+void cli_dos_error(struct cli_state *cli, uint8_t *eclass, uint32_t *ecode)
{
if (!cli_state_is_connected(cli)) {
*eclass = ERRDOS;
@@ -115,8 +115,8 @@ int cli_errno(struct cli_state *cli)
}
if (cli_is_dos_error(cli)) {
- uint8 eclass;
- uint32 ecode;
+ uint8_t eclass;
+ uint32_t ecode;
cli_dos_error(cli, &eclass, &ecode);
status = dos_to_ntstatus(eclass, ecode);
diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c
index 376c4f5d5b1..3fbfbbe67a6 100644
--- a/source3/libsmb/clifsinfo.c
+++ b/source3/libsmb/clifsinfo.c
@@ -120,9 +120,9 @@ NTSTATUS cli_unix_extensions_version_recv(struct tevent_req *req,
return NT_STATUS_OK;
}
-NTSTATUS cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor,
- uint16 *pminor, uint32 *pcaplow,
- uint32 *pcaphigh)
+NTSTATUS cli_unix_extensions_version(struct cli_state *cli, uint16_t *pmajor,
+ uint16_t *pminor, uint32_t *pcaplow,
+ uint32_t *pcaphigh)
{
TALLOC_CTX *frame = talloc_stackframe();
struct tevent_context *ev;
@@ -235,8 +235,8 @@ NTSTATUS cli_set_unix_extensions_capabilities_recv(struct tevent_req *req)
}
NTSTATUS cli_set_unix_extensions_capabilities(struct cli_state *cli,
- uint16 major, uint16 minor,
- uint32 caplow, uint32 caphigh)
+ uint16_t major, uint16 minor,
+ uint32_t caplow, uint32 caphigh)
{
struct tevent_context *ev;
struct tevent_req *req;
@@ -432,7 +432,7 @@ NTSTATUS cli_get_fs_full_size_info(struct cli_state *cli,
uint64_t *sectors_per_allocation_unit,
uint64_t *bytes_per_sector)
{
- uint16 setup[1];
+ uint16_t setup[1];
uint8_t param[2];
uint8_t *rdata = NULL;
uint32_t rdata_count;
@@ -476,8 +476,8 @@ fail:
}
NTSTATUS cli_get_posix_fs_info(struct cli_state *cli,
- uint32 *optimal_transfer_size,
- uint32 *block_size,
+ uint32_t *optimal_transfer_size,
+ uint32_t *block_size,
uint64_t *total_blocks,
uint64_t *blocks_available,
uint64_t *user_blocks_available,
@@ -485,7 +485,7 @@ NTSTATUS cli_get_posix_fs_info(struct cli_state *cli,
uint64_t *free_file_nodes,
uint64_t *fs_identifier)
{
- uint16 setup[1];
+ uint16_t setup[1];
uint8_t param[2];
uint8_t *rdata = NULL;
uint32_t rdata_count;
@@ -748,8 +748,8 @@ NTSTATUS cli_force_encryption(struct cli_state *c,
const char *password,
const char *domain)
{
- uint16 major, minor;
- uint32 caplow, caphigh;
+ uint16_t major, minor;
+ uint32_t caplow, caphigh;
NTSTATUS status;
if (!SERVER_HAS_UNIX_CIFS(c)) {
diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c
index 3080fb883dd..2e5023916e7 100644
--- a/source3/libsmb/clilist.c
+++ b/source3/libsmb/clilist.c
@@ -56,7 +56,7 @@ static size_t interpret_long_filename(TALLOC_CTX *ctx,
const char *p,
const char *pdata_end,
struct file_info *finfo,
- uint32 *p_resume_key,
+ uint32_t *p_resume_key,
DATA_BLOB *p_last_name_raw)
{
int len;
@@ -479,7 +479,7 @@ static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
}
NTSTATUS cli_list_old(struct cli_state *cli, const char *mask,
- uint16 attribute,
+ uint16_t attribute,
NTSTATUS (*fn)(const char *, struct file_info *,
const char *, void *), void *state)
{
@@ -929,7 +929,7 @@ NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
return NT_STATUS_OK;
}
-NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16 attribute,
+NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16_t attribute,
NTSTATUS (*fn)(const char *, struct file_info *, const char *,
void *), void *state)
{
diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c
index 64e3767c129..c176fd6c45a 100644
--- a/source3/libsmb/clirap.c
+++ b/source3/libsmb/clirap.c
@@ -165,7 +165,7 @@ bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
Call a NetShareEnum - try and browse available connections on a host.
****************************************************************************/
-int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
+int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32_t, const char *, void *), void *state)
{
char *rparam = NULL;
char *rdata = NULL;
@@ -272,8 +272,8 @@ int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, co
the comment and a state pointer.
****************************************************************************/
-bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
- void (*fn)(const char *, uint32, const char *, void *),
+bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32_t stype,
+ void (*fn)(const char *, uint32_t, const char *, void *),
void *state)
{
char *rparam = NULL;
@@ -284,7 +284,7 @@ bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
char param[1024];
int uLevel = 1;
size_t len;
- uint32 func = RAP_NetServerEnum2;
+ uint32_t func = RAP_NetServerEnum2;
char *last_entry = NULL;
int total_cnt = 0;
int return_cnt = 0;
@@ -626,7 +626,7 @@ NTSTATUS cli_qpathinfo1_recv(struct tevent_req *req,
time_t *access_time,
time_t *write_time,
off_t *size,
- uint16 *mode)
+ uint16_t *mode)
{
struct cli_qpathinfo1_state *state = tevent_req_data(
req, struct cli_qpathinfo1_state);
@@ -668,7 +668,7 @@ NTSTATUS cli_qpathinfo1(struct cli_state *cli,
time_t *access_time,
time_t *write_time,
off_t *size,
- uint16 *mode)
+ uint16_t *mode)
{
TALLOC_CTX *frame = talloc_stackframe();
struct tevent_context *ev;
@@ -709,7 +709,7 @@ NTSTATUS cli_setpathinfo_basic(struct cli_state *cli, const char *fname,
time_t access_time,
time_t write_time,
time_t change_time,
- uint16 mode)
+ uint16_t mode)
{
unsigned int data_len = 0;
char data[40];
@@ -802,7 +802,7 @@ NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
struct timespec *access_time,
struct timespec *write_time,
struct timespec *change_time,
- off_t *size, uint16 *mode,
+ off_t *size, uint16_t *mode,
SMB_INO_T *ino)
{
struct cli_qpathinfo2_state *state = tevent_req_data(
@@ -842,7 +842,7 @@ NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname,
struct timespec *access_time,
struct timespec *write_time,
struct timespec *change_time,
- off_t *size, uint16 *mode,
+ off_t *size, uint16_t *mode,
SMB_INO_T *ino)
{
TALLOC_CTX *frame = NULL;
@@ -1138,7 +1138,7 @@ NTSTATUS cli_qfilename(struct cli_state *cli, uint16_t fnum,
****************************************************************************/
NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum,
- uint16 *mode, off_t *size,
+ uint16_t *mode, off_t *size,
struct timespec *create_time,
struct timespec *access_time,
struct timespec *write_time,
@@ -1255,7 +1255,7 @@ static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
}
NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
- SMB_STRUCT_STAT *sbuf, uint32 *attributes)
+ SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
{
struct cli_qpathinfo_basic_state *state = tevent_req_data(
req, struct cli_qpathinfo_basic_state);
@@ -1274,7 +1274,7 @@ NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
}
NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
- SMB_STRUCT_STAT *sbuf, uint32 *attributes)
+ SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
{
TALLOC_CTX *frame = NULL;
struct tevent_context *ev;
@@ -1420,7 +1420,7 @@ NTSTATUS cli_qpathinfo3(struct cli_state *cli, const char *fname,
struct timespec *access_time,
struct timespec *write_time,
struct timespec *change_time,
- off_t *size, uint16 *mode,
+ off_t *size, uint16_t *mode,
SMB_INO_T *ino)
{
NTSTATUS status = NT_STATUS_OK;
diff --git a/source3/libsmb/clirap.h b/source3/libsmb/clirap.h
index 54f06b4e76c..a0d4d0609af 100644
--- a/source3/libsmb/clirap.h
+++ b/source3/libsmb/clirap.h
@@ -35,9 +35,9 @@ bool cli_api(struct cli_state *cli,
char **rparam, unsigned int *rprcnt,
char **rdata, unsigned int *rdrcnt);
bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation);
-int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state);
-bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
- void (*fn)(const char *, uint32, const char *, void *),
+int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32_t, const char *, void *), void *state);
+bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32_t stype,
+ void (*fn)(const char *, uint32_t, const char *, void *),
void *state);
bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
const char *old_password);
@@ -50,20 +50,20 @@ NTSTATUS cli_qpathinfo1_recv(struct tevent_req *req,
time_t *access_time,
time_t *write_time,
off_t *size,
- uint16 *mode);
+ uint16_t *mode);
NTSTATUS cli_qpathinfo1(struct cli_state *cli,
const char *fname,
time_t *change_time,
time_t *access_time,
time_t *write_time,
off_t *size,
- uint16 *mode);
+ uint16_t *mode);
NTSTATUS cli_setpathinfo_basic(struct cli_state *cli, const char *fname,
time_t create_time,
time_t access_time,
time_t write_time,
time_t change_time,
- uint16 mode);
+ uint16_t mode);
struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
@@ -73,21 +73,21 @@ NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
struct timespec *access_time,
struct timespec *write_time,
struct timespec *change_time,
- off_t *size, uint16 *mode,
+ off_t *size, uint16_t *mode,
SMB_INO_T *ino);
NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname,
struct timespec *create_time,
struct timespec *access_time,
struct timespec *write_time,
struct timespec *change_time,
- off_t *size, uint16 *mode,
+ off_t *size, uint16_t *mode,
SMB_INO_T *ino);
NTSTATUS cli_qpathinfo3(struct cli_state *cli, const char *fname,
struct timespec *create_time,
struct timespec *access_time,
struct timespec *write_time,
struct timespec *change_time,
- off_t *size, uint16 *mode,
+ off_t *size, uint16_t *mode,
SMB_INO_T *ino);
struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
@@ -108,7 +108,7 @@ bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
NTSTATUS cli_qfilename(struct cli_state *cli, uint16_t fnum,
TALLOC_CTX *mem_ctx, char **name);
NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum,
- uint16 *mode, off_t *size,
+ uint16_t *mode, off_t *size,
struct timespec *create_time,
struct timespec *access_time,
struct timespec *write_time,
@@ -119,9 +119,9 @@ struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx,
struct cli_state *cli,
const char *fname);
NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
- SMB_STRUCT_STAT *sbuf, uint32 *attributes);
+ SMB_STRUCT_STAT *sbuf, uint32_t *attributes);
NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
- SMB_STRUCT_STAT *sbuf, uint32 *attributes);
+ SMB_STRUCT_STAT *sbuf, uint32_t *attributes);
NTSTATUS cli_qpathinfo_standard(struct cli_state *cli, const char *fname,
uint64_t *allocated, uint64_t *size,
uint32_t *nlinks,
@@ -191,31 +191,31 @@ int cli_RNetUserEnum(struct cli_state *cli, void (*fn)(const char *, const char
int cli_RNetUserEnum0(struct cli_state *cli,
void (*fn)(const char *, void *),
void *state);
-int cli_NetFileClose(struct cli_state *cli, uint32 file_id );
-int cli_NetFileGetInfo(struct cli_state *cli, uint32 file_id, void (*fn)(const char *, const char *, uint16, uint16, uint32));
+int cli_NetFileClose(struct cli_state *cli, uint32_t file_id );
+int cli_NetFileGetInfo(struct cli_state *cli, uint32_t file_id, void (*fn)(const char *, const char *, uint16_t, uint16_t, uint32_t));
int cli_NetFileEnum(struct cli_state *cli, const char * user,
const char * base_path,
- void (*fn)(const char *, const char *, uint16, uint16,
- uint32));
+ void (*fn)(const char *, const char *, uint16_t, uint16_t,
+ uint32_t));
int cli_NetShareAdd(struct cli_state *cli, struct rap_share_info_2 * sinfo );
int cli_NetShareDelete(struct cli_state *cli, const char * share_name );
bool cli_get_pdc_name(struct cli_state *cli, const char *workgroup, char **pdc_name);
bool cli_get_server_domain(struct cli_state *cli);
-bool cli_get_server_type(struct cli_state *cli, uint32 *pstype);
+bool cli_get_server_type(struct cli_state *cli, uint32_t *pstype);
bool cli_get_server_name(TALLOC_CTX *mem_ctx, struct cli_state *cli,
char **servername);
-bool cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32 stype);
+bool cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32_t stype);
bool cli_NetWkstaUserLogoff(struct cli_state *cli, const char *user, const char *workstation);
int cli_NetPrintQEnum(struct cli_state *cli,
- void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
- void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,unsigned int,unsigned int,const char*));
+ void (*qfn)(const char*,uint16_t,uint16_t,uint16_t,const char*,const char*,const char*,const char*,const char*,uint16_t,uint16_t),
+ void (*jfn)(uint16_t,const char*,const char*,const char*,const char*,uint16_t,uint16_t,const char*,unsigned int,unsigned int,const char*));
int cli_NetPrintQGetInfo(struct cli_state *cli, const char *printer,
- void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
- void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,unsigned int,unsigned int,const char*));
+ void (*qfn)(const char*,uint16_t,uint16_t,uint16_t,const char*,const char*,const char*,const char*,const char*,uint16_t,uint16_t),
+ void (*jfn)(uint16_t,const char*,const char*,const char*,const char*,uint16_t,uint16_t,const char*,unsigned int,unsigned int,const char*));
int cli_RNetServiceEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state);
-int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16, uint16, uint16, unsigned int, unsigned int, unsigned int, char *));
+int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16_t, uint16_t, uint16_t, unsigned int, unsigned int, unsigned int, char *));
int cli_NetSessionGetInfo(struct cli_state *cli, const char *workstation,
- void (*fn)(const char *, const char *, uint16, uint16, uint16, unsigned int, unsigned int, unsigned int, const char *));
+ void (*fn)(const char *, const char *, uint16_t, uint16_t, uint16_t, unsigned int, unsigned int, unsigned int, const char *));
int cli_NetSessionDel(struct cli_state *cli, const char *workstation);
int cli_NetConnectionEnum(struct cli_state *cli, const char *qualifier,
void (*fn)(uint16_t conid, uint16_t contype,
diff --git a/source3/libsmb/clirap2.c b/source3/libsmb/clirap2.c
index 457a82ee116..931bc237f9a 100644
--- a/source3/libsmb/clirap2.c
+++ b/source3/libsmb/clirap2.c
@@ -218,7 +218,7 @@ static size_t rap_getstringp(TALLOC_CTX *ctx, char *p, char **dest, char *r, uin
return 4;
}
-static char *make_header(char *param, uint16 apinum, const char *reqfmt, const char *datafmt)
+static char *make_header(char *param, uint16_t apinum, const char *reqfmt, const char *datafmt)
{
PUTWORD(param,apinum);
if (reqfmt)
@@ -1097,7 +1097,7 @@ int cli_RNetUserEnum0(struct cli_state *cli,
Call a NetFileClose2 - close open file on another session to server.
****************************************************************************/
-int cli_NetFileClose(struct cli_state *cli, uint32 file_id )
+int cli_NetFileClose(struct cli_state *cli, uint32_t file_id )
{
char *rparam = NULL;
char *rdata = NULL;
@@ -1145,7 +1145,7 @@ int cli_NetFileClose(struct cli_state *cli, uint32 file_id )
workstation.
****************************************************************************/
-int cli_NetFileGetInfo(struct cli_state *cli, uint32 file_id, void (*fn)(const char *, const char *, uint16, uint16, uint32))
+int cli_NetFileGetInfo(struct cli_state *cli, uint32_t file_id, void (*fn)(const char *, const char *, uint16_t, uint16_t, uint32_t))
{
char *rparam = NULL;
char *rdata = NULL;
@@ -1245,8 +1245,8 @@ int cli_NetFileGetInfo(struct cli_state *cli, uint32 file_id, void (*fn)(const c
int cli_NetFileEnum(struct cli_state *cli, const char * user,
const char * base_path,
- void (*fn)(const char *, const char *, uint16, uint16,
- uint32))
+ void (*fn)(const char *, const char *, uint16_t, uint16_t,
+ uint32_t))
{
char *rparam = NULL;
char *rdata = NULL;
@@ -1636,7 +1636,7 @@ bool cli_get_server_domain(struct cli_state *cli)
*
* Parameters:
* cli - pointer to cli_state structure
-* pstype - pointer to uint32 to contain returned server type
+* pstype - pointer to uint32_t to contain returned server type
*
* Returns:
* True - success
@@ -1646,7 +1646,7 @@ bool cli_get_server_domain(struct cli_state *cli)
*
************************************************************************/
-bool cli_get_server_type(struct cli_state *cli, uint32 *pstype)
+bool cli_get_server_type(struct cli_state *cli, uint32_t *pstype)
{
char *rparam = NULL;
char *rdata = NULL;
@@ -1775,7 +1775,7 @@ bool cli_get_server_name(TALLOC_CTX *mem_ctx, struct cli_state *cli,
*
************************************************************************/
-bool cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32 stype)
+bool cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32_t stype)
{
char *rparam = NULL;
char *rdata = NULL;
@@ -1910,8 +1910,8 @@ bool cli_NetWkstaUserLogoff(struct cli_state *cli, const char *user, const char
}
int cli_NetPrintQEnum(struct cli_state *cli,
- void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
- void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,unsigned int,unsigned int,const char*))
+ void (*qfn)(const char*,uint16_t,uint16_t,uint16_t,const char*,const char*,const char*,const char*,const char*,uint16_t,uint16_t),
+ void (*jfn)(uint16_t,const char*,const char*,const char*,const char*,uint16_t,uint16_t,const char*,unsigned int,unsigned int,const char*))
{
char param[WORDSIZE /* api number */
+sizeof(RAP_NetPrintQEnum_REQ) /* req string */
@@ -2018,7 +2018,7 @@ int cli_NetPrintQEnum(struct cli_state *cli,
if (jobcount) {
int j;
for (j=0;j<jobcount;j++) {
- uint16 jid = 0, pos = 0, fsstatus = 0;
+ uint16_t jid = 0, pos = 0, fsstatus = 0;
char ownername[RAP_USERNAME_LEN];
char notifyname[RAP_MACHNAME_LEN];
char datatype[RAP_DATATYPE_LEN];
@@ -2086,8 +2086,8 @@ int cli_NetPrintQEnum(struct cli_state *cli,
}
int cli_NetPrintQGetInfo(struct cli_state *cli, const char *printer,
- void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
- void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,unsigned int,unsigned int,const char*))
+ void (*qfn)(const char*,uint16_t,uint16_t,uint16_t,const char*,const char*,const char*,const char*,const char*,uint16_t,uint16_t),
+ void (*jfn)(uint16_t,const char*,const char*,const char*,const char*,uint16_t,uint16_t,const char*,unsigned int,unsigned int,const char*))
{
char param[WORDSIZE /* api number */
+sizeof(RAP_NetPrintQGetInfo_REQ) /* req string */
@@ -2347,7 +2347,7 @@ int cli_RNetServiceEnum(struct cli_state *cli, void (*fn)(const char *, const ch
Call a NetSessionEnum - list workstations with sessions to an SMB server.
****************************************************************************/
-int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16, uint16, uint16, unsigned int, unsigned int, unsigned int, char *))
+int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16_t, uint16_t, uint16_t, unsigned int, unsigned int, unsigned int, char *))
{
char param[WORDSIZE /* api number */
+sizeof(RAP_NetSessionEnum_REQ) /* parm string */
@@ -2447,7 +2447,7 @@ int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16,
****************************************************************************/
int cli_NetSessionGetInfo(struct cli_state *cli, const char *workstation,
- void (*fn)(const char *, const char *, uint16, uint16, uint16, unsigned int, unsigned int, unsigned int, const char *))
+ void (*fn)(const char *, const char *, uint16_t, uint16_t, uint16_t, unsigned int, unsigned int, unsigned int, const char *))
{
char param[WORDSIZE /* api number */
+sizeof(RAP_NetSessionGetInfo_REQ) /* req string */
diff --git a/source3/libsmb/clisecdesc.c b/source3/libsmb/clisecdesc.c
index 986610fb785..c11e4b322ef 100644
--- a/source3/libsmb/clisecdesc.c
+++ b/source3/libsmb/clisecdesc.c
@@ -62,7 +62,7 @@ NTSTATUS cli_query_security_descriptor(struct cli_state *cli,
goto cleanup;
}
- status = unmarshall_sec_desc(mem_ctx, (uint8 *)rdata, rdata_count,
+ status = unmarshall_sec_desc(mem_ctx, (uint8_t *)rdata, rdata_count,
&lsd);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("unmarshall_sec_desc failed: %s\n",
@@ -100,7 +100,7 @@ NTSTATUS cli_set_security_descriptor(struct cli_state *cli,
const struct security_descriptor *sd)
{
uint8_t param[8];
- uint8 *data;
+ uint8_t *data;
size_t len;
NTSTATUS status;
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
index ec8d1ee7806..959eaa433d6 100644
--- a/source3/libsmb/clispnego.c
+++ b/source3/libsmb/clispnego.c
@@ -26,73 +26,6 @@
#include "../lib/util/asn1.h"
/*
- generate a negTokenInit packet given a list of supported
- OIDs (the mechanisms) a blob, and a principal name string
-*/
-
-DATA_BLOB spnego_gen_negTokenInit(TALLOC_CTX *ctx,
- const char *OIDs[],
- DATA_BLOB *psecblob,
- const char *principal)
-{
- int i;
- ASN1_DATA *data;
- DATA_BLOB ret = data_blob_null;
-
- data = asn1_init(talloc_tos());
- if (data == NULL) {
- return data_blob_null;
- }
-
- if (!asn1_push_tag(data,ASN1_APPLICATION(0))) goto err;
- if (!asn1_write_OID(data,OID_SPNEGO)) goto err;
- if (!asn1_push_tag(data,ASN1_CONTEXT(0))) goto err;
- if (!asn1_push_tag(data,ASN1_SEQUENCE(0))) goto err;
-
- if (!asn1_push_tag(data,ASN1_CONTEXT(0))) goto err;
- if (!asn1_push_tag(data,ASN1_SEQUENCE(0))) goto err;
- for (i=0; OIDs[i]; i++) {
- if (!asn1_write_OID(data,OIDs[i])) goto err;
- }
- if (!asn1_pop_tag(data)) goto err;
- if (!asn1_pop_tag(data)) goto err;
-
- if (psecblob && psecblob->length && psecblob->data) {
- if (!asn1_push_tag(data, ASN1_CONTEXT(2))) goto err;
- if (!asn1_write_OctetString(data,psecblob->data,
- psecblob->length)) goto err;
- if (!asn1_pop_tag(data)) goto err;
- }
-
- if (principal) {
- if (!asn1_push_tag(data, ASN1_CONTEXT(3))) goto err;
- if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
- if (!asn1_push_tag(data, ASN1_CONTEXT(0))) goto err;
- if (!asn1_write_GeneralString(data,principal)) goto err;
- if (!asn1_pop_tag(data)) goto err;
- if (!asn1_pop_tag(data)) goto err;
- if (!asn1_pop_tag(data)) goto err;
- }
-
- if (!asn1_pop_tag(data)) goto err;
- if (!asn1_pop_tag(data)) goto err;
-
- if (!asn1_pop_tag(data)) goto err;
-
- ret = data_blob_talloc(ctx, data->data, data->length);
-
- err:
-
- if (data->has_error) {
- DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data->ofs));
- }
-
- asn1_free(data);
-
- return ret;
-}
-
-/*
parse a negTokenInit packet giving a GUID, a list of supported
OIDs (the mechanisms) and a principal name string
*/
@@ -143,7 +76,7 @@ bool spnego_parse_negTokenInit(TALLOC_CTX *ctx,
if (!asn1_read_OID(data,ctx, &OIDs[i])) {
goto err;
}
- if (data->has_error) {
+ if (asn1_has_error(data)) {
goto err;
}
}
@@ -209,11 +142,11 @@ bool spnego_parse_negTokenInit(TALLOC_CTX *ctx,
if (!asn1_end_tag(data)) goto err;
- ret = !data->has_error;
+ ret = !asn1_has_error(data);
err:
- if (data->has_error) {
+ if (asn1_has_error(data)) {
int j;
if (principal) {
TALLOC_FREE(*principal);
@@ -250,219 +183,23 @@ DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const ui
if (!asn1_write(data, ticket.data, ticket.length)) goto err;
if (!asn1_pop_tag(data)) goto err;
- ret = data_blob_talloc(ctx, data->data, data->length);
-
- err:
-
- if (data->has_error) {
- DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data->ofs));
+ if (!asn1_extract_blob(data, ctx, &ret)) {
+ goto err;
}
asn1_free(data);
-
- return ret;
-}
-
-/*
- generate a SPNEGO krb5 negTokenInit packet, ready for a EXTENDED_SECURITY
- kerberos session setup
-*/
-int spnego_gen_krb5_negTokenInit(TALLOC_CTX *ctx,
- const char *principal, int time_offset,
- DATA_BLOB *targ,
- DATA_BLOB *session_key_krb5, uint32 extra_ap_opts,
- const char *ccname, time_t *expire_time)
-{
- int retval;
- DATA_BLOB tkt, tkt_wrapped;
- const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
-
- /* get a kerberos ticket for the service and extract the session key */
- retval = cli_krb5_get_ticket(ctx, principal, time_offset,
- &tkt, session_key_krb5,
- extra_ap_opts, ccname,
- expire_time, NULL);
- if (retval) {
- return retval;
- }
-
- /* wrap that up in a nice GSS-API wrapping */
- tkt_wrapped = spnego_gen_krb5_wrap(ctx, tkt, TOK_ID_KRB_AP_REQ);
-
- /* and wrap that in a shiny SPNEGO wrapper */
- *targ = spnego_gen_negTokenInit(ctx, krb_mechs, &tkt_wrapped, NULL);
-
- data_blob_free(&tkt_wrapped);
- data_blob_free(&tkt);
-
- return retval;
-}
-
-
-/*
- parse a spnego NTLMSSP challenge packet giving two security blobs
-*/
-bool spnego_parse_challenge(TALLOC_CTX *ctx, const DATA_BLOB blob,
- DATA_BLOB *chal1, DATA_BLOB *chal2)
-{
- bool ret = false;
- ASN1_DATA *data;
-
- ZERO_STRUCTP(chal1);
- ZERO_STRUCTP(chal2);
-
- data = asn1_init(talloc_tos());
- if (data == NULL) {
- return false;
- }
-
- if (!asn1_load(data, blob)) goto err;
- if (!asn1_start_tag(data,ASN1_CONTEXT(1))) goto err;
- if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err;
-
- if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err;
- if (!asn1_check_enumerated(data,1)) goto err;
- if (!asn1_end_tag(data)) goto err;
-
- if (!asn1_start_tag(data,ASN1_CONTEXT(1))) goto err;
- if (!asn1_check_OID(data, OID_NTLMSSP)) goto err;
- if (!asn1_end_tag(data)) goto err;
-
- if (!asn1_start_tag(data,ASN1_CONTEXT(2))) goto err;
- if (!asn1_read_OctetString(data, ctx, chal1)) goto err;
- if (!asn1_end_tag(data)) goto err;
-
- /* the second challenge is optional (XP doesn't send it) */
- if (asn1_tag_remaining(data)) {
- if (!asn1_start_tag(data,ASN1_CONTEXT(3))) goto err;
- if (!asn1_read_OctetString(data, ctx, chal2)) goto err;
- if (!asn1_end_tag(data)) goto err;
- }
-
- if (!asn1_end_tag(data)) goto err;
- if (!asn1_end_tag(data)) goto err;
-
- ret = !data->has_error;
+ data = NULL;
err:
- if (data->has_error) {
- data_blob_free(chal1);
- data_blob_free(chal2);
- }
-
- asn1_free(data);
- return ret;
-}
-
-
-/*
- generate a SPNEGO auth packet. This will contain the encrypted passwords
-*/
-DATA_BLOB spnego_gen_auth(TALLOC_CTX *ctx, DATA_BLOB blob)
-{
- ASN1_DATA *data;
- DATA_BLOB ret = data_blob_null;
-
- data = asn1_init(talloc_tos());
- if (data == NULL) {
- return data_blob_null;
- }
-
- if (!asn1_push_tag(data, ASN1_CONTEXT(1))) goto err;
- if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
- if (!asn1_push_tag(data, ASN1_CONTEXT(2))) goto err;
- if (!asn1_write_OctetString(data,blob.data,blob.length)) goto err;
- if (!asn1_pop_tag(data)) goto err;
- if (!asn1_pop_tag(data)) goto err;
- if (!asn1_pop_tag(data)) goto err;
-
- ret = data_blob_talloc(ctx, data->data, data->length);
-
- err:
-
- asn1_free(data);
-
- return ret;
-}
-
-/*
- parse a SPNEGO auth packet. This contains the encrypted passwords
-*/
-bool spnego_parse_auth_response(TALLOC_CTX *ctx,
- DATA_BLOB blob, NTSTATUS nt_status,
- const char *mechOID,
- DATA_BLOB *auth)
-{
- ASN1_DATA *data;
- uint8 negResult;
- bool ret = false;
-
- if (NT_STATUS_IS_OK(nt_status)) {
- negResult = SPNEGO_ACCEPT_COMPLETED;
- } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- negResult = SPNEGO_ACCEPT_INCOMPLETE;
- } else {
- negResult = SPNEGO_REJECT;
- }
-
- data = asn1_init(talloc_tos());
- if (data == NULL) {
- return false;
- }
-
- *auth = data_blob_null;
-
- if (!asn1_load(data, blob)) goto err;
- if (!asn1_start_tag(data, ASN1_CONTEXT(1))) goto err;
- if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto err;
- if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto err;
- if (!asn1_check_enumerated(data, negResult)) goto err;
- if (!asn1_end_tag(data)) goto err;
-
- if (asn1_tag_remaining(data)) {
- if (!asn1_start_tag(data,ASN1_CONTEXT(1))) goto err;
- if (!asn1_check_OID(data, mechOID)) goto err;
- if (!asn1_end_tag(data)) goto err;
-
- if (asn1_tag_remaining(data)) {
- if (!asn1_start_tag(data,ASN1_CONTEXT(2))) goto err;
- if (!asn1_read_OctetString(data, ctx, auth)) goto err;
- if (!asn1_end_tag(data)) goto err;
+ if (data != NULL) {
+ if (asn1_has_error(data)) {
+ DEBUG(1, ("Failed to build krb5 wrapper at offset %d\n",
+ (int)asn1_current_ofs(data)));
}
- } else if (negResult == SPNEGO_ACCEPT_INCOMPLETE) {
- data->has_error = 1;
- goto err;
- }
-
- /* Binding against Win2K DC returns a duplicate of the responseToken in
- * the optional mechListMIC field. This is a bug in Win2K. We ignore
- * this field if it exists. Win2K8 may return a proper mechListMIC at
- * which point we need to implement the integrity checking. */
- if (asn1_tag_remaining(data)) {
- DATA_BLOB mechList = data_blob_null;
- if (!asn1_start_tag(data, ASN1_CONTEXT(3))) goto err;
- if (!asn1_read_OctetString(data, ctx, &mechList)) goto err;
- data_blob_free(&mechList);
- if (!asn1_end_tag(data)) goto err;
- DEBUG(5,("spnego_parse_auth_response received mechListMIC, "
- "ignoring.\n"));
- }
-
- if (!asn1_end_tag(data)) goto err;
- if (!asn1_end_tag(data)) goto err;
-
- ret = !data->has_error;
- err:
-
- if (data->has_error) {
- DEBUG(3,("spnego_parse_auth_response failed at %d\n", (int)data->ofs));
asn1_free(data);
- data_blob_free(auth);
- return false;
}
- asn1_free(data);
return ret;
}
diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c
index 3a07f118b0c..d131c30c772 100644
--- a/source3/libsmb/libsmb_dir.c
+++ b/source3/libsmb/libsmb_dir.c
@@ -60,7 +60,7 @@ static int
add_dirent(SMBCFILE *dir,
const char *name,
const char *comment,
- uint32 type)
+ uint32_t type)
{
struct smbc_dirent *dirent;
int size;
@@ -138,7 +138,7 @@ add_dirent(SMBCFILE *dir,
static void
list_unique_wg_fn(const char *name,
- uint32 type,
+ uint32_t type,
const char *comment,
void *state)
{
@@ -183,7 +183,7 @@ list_unique_wg_fn(const char *name,
static void
list_fn(const char *name,
- uint32 type,
+ uint32_t type,
const char *comment,
void *state)
{
@@ -257,15 +257,15 @@ dir_list_fn(const char *mnt,
static int
net_share_enum_rpc(struct cli_state *cli,
void (*fn)(const char *name,
- uint32 type,
+ uint32_t type,
const char *comment,
void *state),
void *state)
{
int i;
WERROR result;
- uint32 preferred_len = 0xffffffff;
- uint32 type;
+ uint32_t preferred_len = 0xffffffff;
+ uint32_t type;
struct srvsvc_NetShareInfoCtr info_ctr;
struct srvsvc_NetShareCtr1 ctr1;
fstring name = "";
@@ -377,7 +377,7 @@ SMBC_opendir_ctx(SMBCCTX *context,
char *options = NULL;
char *workgroup = NULL;
char *path = NULL;
- uint16 mode;
+ uint16_t mode;
uint16_t port = 0;
char *p = NULL;
SMBCSRV *srv = NULL;
@@ -1562,7 +1562,7 @@ SMBC_chmod_ctx(SMBCCTX *context,
char *targetpath = NULL;
struct cli_state *targetcli = NULL;
char *path = NULL;
- uint16 mode;
+ uint16_t mode;
uint16_t port = 0;
TALLOC_CTX *frame = talloc_stackframe();
NTSTATUS status;
@@ -1832,7 +1832,7 @@ SMBC_unlink_ctx(SMBCCTX *context,
int saverr = errno;
off_t size = 0;
- uint16 mode = 0;
+ uint16_t mode = 0;
struct timespec write_time_ts;
struct timespec access_time_ts;
struct timespec change_time_ts;
diff --git a/source3/libsmb/libsmb_file.c b/source3/libsmb/libsmb_file.c
index c8beafce65e..916364920f3 100644
--- a/source3/libsmb/libsmb_file.c
+++ b/source3/libsmb/libsmb_file.c
@@ -401,7 +401,7 @@ bool
SMBC_getatr(SMBCCTX * context,
SMBCSRV *srv,
const char *path,
- uint16 *mode,
+ uint16_t *mode,
off_t *size,
struct timespec *create_time_ts,
struct timespec *access_time_ts,
@@ -531,7 +531,7 @@ SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
time_t access_time,
time_t write_time,
time_t change_time,
- uint16 mode)
+ uint16_t mode)
{
uint16_t fd;
int ret;
@@ -586,7 +586,7 @@ SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
* cli_setatr() for that, and with only this parameter, it
* seems to work on win98.
*/
- if (ret && mode != (uint16) -1) {
+ if (ret && mode != (uint16_t) -1) {
ret = NT_STATUS_IS_OK(cli_setatr(srv->cli, path, mode, 0));
}
diff --git a/source3/libsmb/libsmb_misc.c b/source3/libsmb/libsmb_misc.c
index 98739c69ef4..1d874c74cd8 100644
--- a/source3/libsmb/libsmb_misc.c
+++ b/source3/libsmb/libsmb_misc.c
@@ -53,8 +53,8 @@ SMBC_errno(SMBCCTX *context,
int ret = cli_errno(c);
if (cli_is_dos_error(c)) {
- uint8 eclass;
- uint32 ecode;
+ uint8_t eclass;
+ uint32_t ecode;
cli_dos_error(c, &eclass, &ecode);
diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c
index 6e8e3c37d32..39a0b470769 100644
--- a/source3/libsmb/libsmb_server.c
+++ b/source3/libsmb/libsmb_server.c
@@ -267,7 +267,7 @@ SMBC_server_internal(TALLOC_CTX *ctx,
struct cli_state *c = NULL;
const char *server_n = server;
int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0);
- uint32 fs_attrs = 0;
+ uint32_t fs_attrs = 0;
const char *username_used;
NTSTATUS status;
char *newserver, *newshare;
diff --git a/source3/libsmb/libsmb_stat.c b/source3/libsmb/libsmb_stat.c
index 3c895cefd3e..4191ad6d215 100644
--- a/source3/libsmb/libsmb_stat.c
+++ b/source3/libsmb/libsmb_stat.c
@@ -119,7 +119,7 @@ SMBC_stat_ctx(SMBCCTX *context,
struct timespec access_time_ts;
struct timespec change_time_ts;
off_t size = 0;
- uint16 mode = 0;
+ uint16_t mode = 0;
uint16_t port = 0;
SMB_INO_T ino = 0;
TALLOC_CTX *frame = talloc_stackframe();
@@ -207,7 +207,7 @@ SMBC_fstat_ctx(SMBCCTX *context,
struct timespec access_time_ts;
struct timespec write_time_ts;
off_t size;
- uint16 mode;
+ uint16_t mode;
char *server = NULL;
char *share = NULL;
char *user = NULL;
@@ -368,7 +368,7 @@ SMBC_fstatvfs_ctx(SMBCCTX *context,
struct statvfs *st)
{
unsigned long flags = 0;
- uint32 fs_attrs = 0;
+ uint32_t fs_attrs = 0;
struct cli_state *cli = file->srv->cli;
struct smbXcli_tcon *tcon;
TALLOC_CTX *frame = talloc_stackframe();
@@ -424,8 +424,8 @@ SMBC_fstatvfs_ctx(SMBCCTX *context,
flags |= SMBC_VFS_FEATURE_NO_UNIXCIFS;
} else {
- uint32 optimal_transfer_size;
- uint32 block_size;
+ uint32_t optimal_transfer_size;
+ uint32_t block_size;
uint64_t total_blocks;
uint64_t blocks_available;
uint64_t user_blocks_available;
diff --git a/source3/libsmb/libsmb_xattr.c b/source3/libsmb/libsmb_xattr.c
index 9f7bea8da11..8c23a8f87a6 100644
--- a/source3/libsmb/libsmb_xattr.c
+++ b/source3/libsmb/libsmb_xattr.c
@@ -146,7 +146,7 @@ ace_compare(struct security_ace *ace1,
static void
sort_acl(struct security_acl *the_acl)
{
- uint32 i;
+ uint32_t i;
if (!the_acl) return;
TYPESAFE_QSORT(the_acl->aces, the_acl->num_aces, ace_compare);
@@ -272,7 +272,7 @@ parse_ace(struct cli_state *ipc_cli,
const struct perm_value *v;
struct perm_value {
const char perm[7];
- uint32 mask;
+ uint32_t mask;
};
TALLOC_CTX *frame = talloc_stackframe();
@@ -558,7 +558,7 @@ dos_attr_query(SMBCCTX *context,
struct timespec access_time_ts;
struct timespec change_time_ts;
off_t size = 0;
- uint16 mode = 0;
+ uint16_t mode = 0;
SMB_INO_T inode = 0;
DOS_ATTR_DESC *ret;
@@ -708,7 +708,7 @@ cacl_get(SMBCCTX *context,
char *buf,
int bufsize)
{
- uint32 i;
+ uint32_t i;
int n = 0;
int n_used;
bool all;
@@ -746,7 +746,7 @@ cacl_get(SMBCCTX *context,
time_t access_time = (time_t)0;
time_t change_time = (time_t)0;
off_t size = 0;
- uint16 mode = 0;
+ uint16_t mode = 0;
SMB_INO_T ino = 0;
struct cli_state *cli = srv->cli;
struct {
@@ -1515,7 +1515,7 @@ cacl_set(SMBCCTX *context,
struct security_acl *dacl = NULL;
struct dom_sid *owner_sid = NULL;
struct dom_sid *group_sid = NULL;
- uint32 i, j;
+ uint32_t i, j;
size_t sd_size;
int ret = 0;
char *p;
@@ -1595,7 +1595,7 @@ cacl_set(SMBCCTX *context,
for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
if (security_ace_equal(&sd->dacl->aces[i],
&old->dacl->aces[j])) {
- uint32 k;
+ uint32_t k;
for (k=j; k<old->dacl->num_aces-1;k++) {
old->dacl->aces[k] =
old->dacl->aces[k+1];
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 6f056be54a6..544c5086c55 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -241,9 +241,9 @@ static struct in_addr my_socket_addr_v4(void)
static int generate_trn_id(void)
{
- uint16 id;
+ uint16_t id;
- generate_random_buffer((uint8 *)&id, sizeof(id));
+ generate_random_buffer((uint8_t *)&id, sizeof(id));
return id % (unsigned)0x7FFF;
}
diff --git a/source3/libsmb/nmblib.c b/source3/libsmb/nmblib.c
index 4adc3da5fab..8feb029b05e 100644
--- a/source3/libsmb/nmblib.c
+++ b/source3/libsmb/nmblib.c
@@ -1334,7 +1334,7 @@ static unsigned char *name_ptr(unsigned char *buf, size_t buf_len, unsigned int
c = *(unsigned char *)(buf+ofs);
if ((c & 0xC0) == 0xC0) {
- uint16 l = 0;
+ uint16_t l = 0;
if (ofs > buf_len - 1) {
return NULL;
diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c
deleted file mode 100644
index e661aebba12..00000000000
--- a/source3/libsmb/ntlmssp.c
+++ /dev/null
@@ -1,765 +0,0 @@
-/*
- Unix SMB/Netbios implementation.
- Version 3.0
- handle NLTMSSP, server side
-
- Copyright (C) Andrew Tridgell 2001
- Copyright (C) Andrew Bartlett 2001-2010
- Copyright (C) Stefan Metzmacher 2005
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "../auth/ntlmssp/ntlmssp.h"
-#include "../auth/ntlmssp/ntlmssp_private.h"
-#include "../libcli/auth/libcli_auth.h"
-#include "../librpc/gen_ndr/ndr_ntlmssp.h"
-#include "../auth/ntlmssp/ntlmssp_ndr.h"
-#include "../lib/crypto/md5.h"
-#include "../lib/crypto/arcfour.h"
-#include "../lib/crypto/hmacmd5.h"
-#include "../nsswitch/libwbclient/wbclient.h"
-
-static NTSTATUS ntlmssp3_client_initial(struct ntlmssp_state *ntlmssp_state,
- TALLOC_CTX *out_mem_ctx,
- DATA_BLOB reply, DATA_BLOB *next_request);
-static NTSTATUS ntlmssp3_client_challenge(struct ntlmssp_state *ntlmssp_state,
- TALLOC_CTX *out_mem_ctx, /* Unused at this time */
- const DATA_BLOB reply, DATA_BLOB *next_request);
-/**
- * Callbacks for NTLMSSP - for both client and server operating modes
- *
- */
-
-static const struct ntlmssp_callbacks {
- enum ntlmssp_role role;
- enum ntlmssp_message_type ntlmssp_command;
- NTSTATUS (*fn)(struct ntlmssp_state *ntlmssp_state,
- TALLOC_CTX *out_mem_ctx,
- DATA_BLOB in, DATA_BLOB *out);
-} ntlmssp_callbacks[] = {
- {NTLMSSP_CLIENT, NTLMSSP_INITIAL, ntlmssp3_client_initial},
- {NTLMSSP_CLIENT, NTLMSSP_CHALLENGE, ntlmssp3_client_challenge},
- {NTLMSSP_CLIENT, NTLMSSP_UNKNOWN, NULL},
- {NTLMSSP_SERVER, NTLMSSP_UNKNOWN, NULL}
-};
-
-/**
- * Set a username on an NTLMSSP context - ensures it is talloc()ed
- *
- */
-
-NTSTATUS ntlmssp_set_username(struct ntlmssp_state *ntlmssp_state, const char *user)
-{
- ntlmssp_state->user = talloc_strdup(ntlmssp_state, user ? user : "" );
- if (!ntlmssp_state->user) {
- return NT_STATUS_NO_MEMORY;
- }
- return NT_STATUS_OK;
-}
-
-/**
- * Converts a password to the hashes on an NTLMSSP context.
- *
- */
-NTSTATUS ntlmssp_set_password(struct ntlmssp_state *ntlmssp_state, const char *password)
-{
- uint8_t lm_hash[16];
- uint8_t nt_hash[16];
-
- TALLOC_FREE(ntlmssp_state->lm_hash);
- TALLOC_FREE(ntlmssp_state->nt_hash);
-
- if (password == NULL) {
- return NT_STATUS_OK;
- }
-
- if (E_deshash(password, lm_hash)) {
- ntlmssp_state->lm_hash = (uint8_t *)
- talloc_memdup(ntlmssp_state, lm_hash, 16);
- if (!ntlmssp_state->lm_hash) {
- return NT_STATUS_NO_MEMORY;
- }
- }
-
- E_md4hash(password, nt_hash);
-
- ntlmssp_state->nt_hash = (uint8_t *)
- talloc_memdup(ntlmssp_state, nt_hash, 16);
- if (!ntlmssp_state->nt_hash) {
- TALLOC_FREE(ntlmssp_state->lm_hash);
- return NT_STATUS_NO_MEMORY;
- }
-
- return NT_STATUS_OK;
-}
-
-NTSTATUS ntlmssp_set_password_hash(struct ntlmssp_state *state,
- const char *pwhash)
-{
- char nt_hash[16];
- size_t converted;
-
- converted = strhex_to_str(
- nt_hash, sizeof(nt_hash), pwhash, strlen(pwhash));
- if (converted != sizeof(nt_hash)) {
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- TALLOC_FREE(state->lm_hash);
- TALLOC_FREE(state->nt_hash);
-
- state->nt_hash = (uint8_t *)talloc_memdup(state, nt_hash, 16);
- if (!state->nt_hash) {
- return NT_STATUS_NO_MEMORY;
- }
- return NT_STATUS_OK;
-}
-
-/**
- * Set a domain on an NTLMSSP context - ensures it is talloc()ed
- *
- */
-NTSTATUS ntlmssp_set_domain(struct ntlmssp_state *ntlmssp_state, const char *domain)
-{
- ntlmssp_state->domain = talloc_strdup(ntlmssp_state,
- domain ? domain : "" );
- if (!ntlmssp_state->domain) {
- return NT_STATUS_NO_MEMORY;
- }
- return NT_STATUS_OK;
-}
-
-/**
- * Request features for the NTLMSSP negotiation
- *
- * @param ntlmssp_state NTLMSSP state
- * @param feature_list List of space separated features requested from NTLMSSP.
- */
-void ntlmssp_want_feature_list(struct ntlmssp_state *ntlmssp_state, char *feature_list)
-{
- /*
- * We need to set this to allow a later SetPassword
- * via the SAMR pipe to succeed. Strange.... We could
- * also add NTLMSSP_NEGOTIATE_SEAL here. JRA.
- */
- if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, True)) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
- }
- if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, True)) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
- }
- if(in_list("NTLMSSP_FEATURE_SEAL", feature_list, True)) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
- }
- if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list, true)) {
- ntlmssp_state->use_ccache = true;
- }
-}
-
-/**
- * Request a feature for the NTLMSSP negotiation
- *
- * @param ntlmssp_state NTLMSSP state
- * @param feature Bit flag specifying the requested feature
- */
-void ntlmssp_want_feature(struct ntlmssp_state *ntlmssp_state, uint32_t feature)
-{
- /* As per JRA's comment above */
- if (feature & NTLMSSP_FEATURE_SESSION_KEY) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
- }
- if (feature & NTLMSSP_FEATURE_SIGN) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
- }
- if (feature & NTLMSSP_FEATURE_SEAL) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
- }
- if (feature & NTLMSSP_FEATURE_CCACHE) {
- ntlmssp_state->use_ccache = true;
- }
-}
-
-/**
- * Next state function for the NTLMSSP state machine
- *
- * @param ntlmssp_state NTLMSSP State
- * @param in The packet in from the NTLMSSP partner, as a DATA_BLOB
- * @param out The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK.
- */
-
-NTSTATUS ntlmssp_update(struct ntlmssp_state *ntlmssp_state,
- const DATA_BLOB input, DATA_BLOB *out)
-{
- uint32_t ntlmssp_command;
- int i;
-
- if (ntlmssp_state->expected_state == NTLMSSP_DONE) {
- /* Called update after negotiations finished. */
- DEBUG(1, ("Called NTLMSSP after state machine was 'done'\n"));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- *out = data_blob_null;
-
- if (!input.length) {
- switch (ntlmssp_state->role) {
- case NTLMSSP_CLIENT:
- ntlmssp_command = NTLMSSP_INITIAL;
- break;
- case NTLMSSP_SERVER:
- /* 'datagram' mode - no neg packet */
- ntlmssp_command = NTLMSSP_NEGOTIATE;
- break;
- default:
- DEBUG(1, ("Invalid role: %d\n", ntlmssp_state->role));
- return NT_STATUS_INVALID_PARAMETER;
- }
- } else {
- if (!msrpc_parse(ntlmssp_state, &input, "Cd",
- "NTLMSSP",
- &ntlmssp_command)) {
- DEBUG(1, ("Failed to parse NTLMSSP packet, could not extract NTLMSSP command\n"));
- dump_data(2, input.data, input.length);
- return NT_STATUS_INVALID_PARAMETER;
- }
- }
-
- if (ntlmssp_command != ntlmssp_state->expected_state) {
- DEBUG(1, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command, ntlmssp_state->expected_state));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- for (i=0; ntlmssp_callbacks[i].fn; i++) {
- if (ntlmssp_callbacks[i].role == ntlmssp_state->role
- && ntlmssp_callbacks[i].ntlmssp_command == ntlmssp_command) {
- return ntlmssp_callbacks[i].fn(ntlmssp_state, ntlmssp_state, input, out);
- }
- }
-
- DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n",
- ntlmssp_state->role, ntlmssp_command));
-
- return NT_STATUS_INVALID_PARAMETER;
-}
-
-/*********************************************************************
- Client side NTLMSSP
-*********************************************************************/
-
-/**
- * Next state function for the Initial packet
- *
- * @param ntlmssp_state NTLMSSP State
- * @param request The request, as a DATA_BLOB. reply.data must be NULL
- * @param request The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors or NT_STATUS_OK.
- */
-
-static NTSTATUS ntlmssp3_client_initial(struct ntlmssp_state *ntlmssp_state,
- TALLOC_CTX *out_mem_ctx,
- DATA_BLOB in, DATA_BLOB *out)
-{
- const char *domain = ntlmssp_state->client.netbios_domain;
- const char *workstation = ntlmssp_state->client.netbios_name;
- NTSTATUS status;
-
- /* These don't really matter in the initial packet, so don't panic if they are not set */
- if (!domain) {
- domain = "";
- }
-
- if (!workstation) {
- workstation = "";
- }
-
- if (ntlmssp_state->unicode) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
- } else {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
- }
-
- if (ntlmssp_state->use_ntlmv2) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
- }
-
- /* generate the ntlmssp negotiate packet */
- status = msrpc_gen(out_mem_ctx,
- out, "CddAA",
- "NTLMSSP",
- NTLMSSP_NEGOTIATE,
- ntlmssp_state->neg_flags,
- domain,
- workstation);
-
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("ntlmssp_client_initial: failed to generate "
- "ntlmssp negotiate packet\n"));
- return status;
- }
-
- if (DEBUGLEVEL >= 10) {
- struct NEGOTIATE_MESSAGE *negotiate = talloc(
- talloc_tos(), struct NEGOTIATE_MESSAGE);
- if (negotiate != NULL) {
- status = ntlmssp_pull_NEGOTIATE_MESSAGE(
- out, negotiate, negotiate);
- if (NT_STATUS_IS_OK(status)) {
- NDR_PRINT_DEBUG(NEGOTIATE_MESSAGE,
- negotiate);
- }
- TALLOC_FREE(negotiate);
- }
- }
-
- ntlmssp_state->expected_state = NTLMSSP_CHALLENGE;
-
- return NT_STATUS_MORE_PROCESSING_REQUIRED;
-}
-
-bool ntlmssp_is_anonymous(struct ntlmssp_state *ntlmssp_state)
-{
- const char *user = ntlmssp_state->user;
-
- if (user == NULL) {
- return true;
- }
-
- if (strlen(user) == 0) {
- return true;
- }
-
- return false;
-}
-
-/**
- * Next state function for the Challenge Packet. Generate an auth packet.
- *
- * @param ntlmssp_state NTLMSSP State
- * @param request The request, as a DATA_BLOB. reply.data must be NULL
- * @param request The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors or NT_STATUS_OK.
- */
-
-static NTSTATUS ntlmssp3_client_challenge(struct ntlmssp_state *ntlmssp_state,
- TALLOC_CTX *out_mem_ctx, /* Unused at this time */
- const DATA_BLOB reply, DATA_BLOB *next_request)
-{
- uint32_t chal_flags, ntlmssp_command, unkn1 = 0, unkn2 = 0;
- DATA_BLOB server_domain_blob;
- DATA_BLOB challenge_blob;
- DATA_BLOB struct_blob = data_blob_null;
- char *server_domain;
- const char *chal_parse_string;
- const char *chal_parse_string_short = NULL;
- const char *auth_gen_string;
- DATA_BLOB lm_response = data_blob_null;
- DATA_BLOB nt_response = data_blob_null;
- DATA_BLOB session_key = data_blob_null;
- DATA_BLOB encrypted_session_key = data_blob_null;
- NTSTATUS nt_status = NT_STATUS_OK;
- bool anon = ntlmssp_is_anonymous(ntlmssp_state);
-
- if (!anon && ntlmssp_state->use_ccache) {
- struct wbcCredentialCacheParams params;
- struct wbcCredentialCacheInfo *info = NULL;
- struct wbcAuthErrorInfo *error = NULL;
- struct wbcNamedBlob auth_blob;
- struct wbcBlob *wbc_next = NULL;
- struct wbcBlob *wbc_session_key = NULL;
- wbcErr wbc_status;
- int i;
-
- /*
- * We need to set the netbios name or we are not able to connect
- * a Windows DC.
- */
- if (ntlmssp_state->server.netbios_domain == NULL ||
- ntlmssp_state->server.netbios_domain[0] == '\0') {
- ntlmssp_state->server.netbios_domain = ntlmssp_state->domain;
- }
-
- params.account_name = ntlmssp_state->user;
- params.domain_name = ntlmssp_state->domain;
- params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
-
- auth_blob.name = "challenge_blob";
- auth_blob.flags = 0;
- auth_blob.blob.data = reply.data;
- auth_blob.blob.length = reply.length;
- params.num_blobs = 1;
- params.blobs = &auth_blob;
-
- wbc_status = wbcCredentialCache(&params, &info, &error);
- wbcFreeMemory(error);
- if (!WBC_ERROR_IS_OK(wbc_status)) {
- goto noccache;
- }
-
- for (i=0; i<info->num_blobs; i++) {
- if (strequal(info->blobs[i].name, "auth_blob")) {
- wbc_next = &info->blobs[i].blob;
- }
- if (strequal(info->blobs[i].name, "session_key")) {
- wbc_session_key = &info->blobs[i].blob;
- }
- }
- if ((wbc_next == NULL) || (wbc_session_key == NULL)) {
- wbcFreeMemory(info);
- goto noccache;
- }
-
- *next_request = data_blob_talloc(ntlmssp_state,
- wbc_next->data,
- wbc_next->length);
- ntlmssp_state->session_key = data_blob_talloc(ntlmssp_state,
- wbc_session_key->data,
- wbc_session_key->length);
-
- wbcFreeMemory(info);
- goto done;
- }
-
-noccache:
-
- if (!msrpc_parse(ntlmssp_state, &reply, "CdBd",
- "NTLMSSP",
- &ntlmssp_command,
- &server_domain_blob,
- &chal_flags)) {
- DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
- dump_data(2, reply.data, reply.length);
-
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if (DEBUGLEVEL >= 10) {
- struct CHALLENGE_MESSAGE *challenge = talloc(
- talloc_tos(), struct CHALLENGE_MESSAGE);
- if (challenge != NULL) {
- NTSTATUS status;
- challenge->NegotiateFlags = chal_flags;
- status = ntlmssp_pull_CHALLENGE_MESSAGE(
- &reply, challenge, challenge);
- if (NT_STATUS_IS_OK(status)) {
- NDR_PRINT_DEBUG(CHALLENGE_MESSAGE,
- challenge);
- }
- TALLOC_FREE(challenge);
- }
- }
-
- data_blob_free(&server_domain_blob);
-
- DEBUG(3, ("Got challenge flags:\n"));
- debug_ntlmssp_flags(chal_flags);
-
- ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth());
-
- if (ntlmssp_state->unicode) {
- if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
- chal_parse_string = "CdUdbddB";
- } else {
- chal_parse_string = "CdUdbdd";
- chal_parse_string_short = "CdUdb";
- }
- auth_gen_string = "CdBBUUUBd";
- } else {
- if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
- chal_parse_string = "CdAdbddB";
- } else {
- chal_parse_string = "CdAdbdd";
- chal_parse_string_short = "CdAdb";
- }
-
- auth_gen_string = "CdBBAAABd";
- }
-
- DEBUG(3, ("NTLMSSP: Set final flags:\n"));
- debug_ntlmssp_flags(ntlmssp_state->neg_flags);
-
- if (!msrpc_parse(ntlmssp_state, &reply, chal_parse_string,
- "NTLMSSP",
- &ntlmssp_command,
- &server_domain,
- &chal_flags,
- &challenge_blob, 8,
- &unkn1, &unkn2,
- &struct_blob)) {
-
- bool ok = false;
-
- DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
-
- if (chal_parse_string_short != NULL) {
- /*
- * In the case where NTLMSSP_NEGOTIATE_TARGET_INFO
- * is not used, some NTLMSSP servers don't return
- * the unused unkn1 and unkn2 fields.
- * See bug:
- * https://bugzilla.samba.org/show_bug.cgi?id=10016
- * for packet traces.
- * Try and parse again without them.
- */
- ok = msrpc_parse(ntlmssp_state, &reply,
- chal_parse_string_short,
- "NTLMSSP",
- &ntlmssp_command,
- &server_domain,
- &chal_flags,
- &challenge_blob, 8);
- if (!ok) {
- DEBUG(1, ("Failed to short parse "
- "the NTLMSSP Challenge: (#2)\n"));
- }
- }
-
- if (!ok) {
- dump_data(2, reply.data, reply.length);
- return NT_STATUS_INVALID_PARAMETER;
- }
- }
-
- if (chal_flags & NTLMSSP_TARGET_TYPE_SERVER) {
- ntlmssp_state->server.is_standalone = true;
- } else {
- ntlmssp_state->server.is_standalone = false;
- }
- /* TODO: parse struct_blob and fill in the rest */
- ntlmssp_state->server.netbios_name = "";
- ntlmssp_state->server.netbios_domain = server_domain;
- ntlmssp_state->server.dns_name = "";
- ntlmssp_state->server.dns_domain = "";
-
- if (challenge_blob.length != 8) {
- data_blob_free(&struct_blob);
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if (anon || !ntlmssp_state->nt_hash) {
- static const uint8_t zeros[16] = {0, };
- /* do nothing - blobs are zero length */
-
- /* session key is all zeros */
- session_key = data_blob_talloc(ntlmssp_state, zeros, 16);
-
- /* not doing NLTM2 without a password */
- ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
- } else if (ntlmssp_state->use_ntlmv2) {
- if (!struct_blob.length) {
- /* be lazy, match win2k - we can't do NTLMv2 without it */
- DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- /* TODO: if the remote server is standalone, then we should replace 'domain'
- with the server name as supplied above */
-
- if (!SMBNTLMv2encrypt_hash(ntlmssp_state,
- ntlmssp_state->user,
- ntlmssp_state->domain,
- ntlmssp_state->nt_hash, &challenge_blob,
- &struct_blob,
- &lm_response, &nt_response, NULL,
- &session_key)) {
- data_blob_free(&challenge_blob);
- data_blob_free(&struct_blob);
- return NT_STATUS_NO_MEMORY;
- }
- } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
- MD5_CTX md5_session_nonce_ctx;
- uint8_t session_nonce[16];
- uint8_t session_nonce_hash[16];
- uint8_t user_session_key[16];
-
- lm_response = data_blob_talloc(ntlmssp_state, NULL, 24);
- generate_random_buffer(lm_response.data, 8);
- memset(lm_response.data+8, 0, 16);
-
- memcpy(session_nonce, challenge_blob.data, 8);
- memcpy(&session_nonce[8], lm_response.data, 8);
-
- MD5Init(&md5_session_nonce_ctx);
- MD5Update(&md5_session_nonce_ctx, challenge_blob.data, 8);
- MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
- MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
-
- DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
- DEBUG(5, ("challenge is: \n"));
- dump_data(5, session_nonce_hash, 8);
-
- nt_response = data_blob_talloc(ntlmssp_state, NULL, 24);
- SMBNTencrypt_hash(ntlmssp_state->nt_hash,
- session_nonce_hash,
- nt_response.data);
-
- session_key = data_blob_talloc(ntlmssp_state, NULL, 16);
-
- SMBsesskeygen_ntv1(ntlmssp_state->nt_hash, user_session_key);
- hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
- dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
- } else {
- /* lanman auth is insecure, it may be disabled */
- if (lp_client_lanman_auth() && ntlmssp_state->lm_hash) {
- lm_response = data_blob_talloc(ntlmssp_state,
- NULL, 24);
- SMBencrypt_hash(ntlmssp_state->lm_hash,challenge_blob.data,
- lm_response.data);
- }
-
- nt_response = data_blob_talloc(ntlmssp_state, NULL, 24);
- SMBNTencrypt_hash(ntlmssp_state->nt_hash,challenge_blob.data,
- nt_response.data);
-
- session_key = data_blob_talloc(ntlmssp_state, NULL, 16);
- if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
- && lp_client_lanman_auth() && ntlmssp_state->lm_hash) {
- SMBsesskeygen_lm_sess_key(ntlmssp_state->lm_hash, lm_response.data,
- session_key.data);
- dump_data_pw("LM session key\n", session_key.data, session_key.length);
- } else {
- SMBsesskeygen_ntv1(ntlmssp_state->nt_hash, session_key.data);
- dump_data_pw("NT session key:\n", session_key.data, session_key.length);
- }
- }
- data_blob_free(&struct_blob);
-
- /* Key exchange encryptes a new client-generated session key with
- the password-derived key */
- if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
- /* Make up a new session key */
- uint8_t client_session_key[16];
- generate_random_buffer(client_session_key, sizeof(client_session_key));
-
- /* Encrypt the new session key with the old one */
- encrypted_session_key = data_blob(client_session_key, sizeof(client_session_key));
- dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
- arcfour_crypt_blob(encrypted_session_key.data, encrypted_session_key.length, &session_key);
- dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
-
- /* Mark the new session key as the 'real' session key */
- data_blob_free(&session_key);
- session_key = data_blob_talloc(ntlmssp_state,
- client_session_key,
- sizeof(client_session_key));
- }
-
- /* this generates the actual auth packet */
- nt_status = msrpc_gen(ntlmssp_state, next_request, auth_gen_string,
- "NTLMSSP",
- NTLMSSP_AUTH,
- lm_response.data, lm_response.length,
- nt_response.data, nt_response.length,
- ntlmssp_state->domain,
- ntlmssp_state->user,
- ntlmssp_state->client.netbios_name,
- encrypted_session_key.data, encrypted_session_key.length,
- ntlmssp_state->neg_flags);
-
- if (!NT_STATUS_IS_OK(nt_status)) {
- return NT_STATUS_NO_MEMORY;
- }
-
- if (DEBUGLEVEL >= 10) {
- struct AUTHENTICATE_MESSAGE *authenticate = talloc(
- talloc_tos(), struct AUTHENTICATE_MESSAGE);
- if (authenticate != NULL) {
- NTSTATUS status;
- authenticate->NegotiateFlags =
- ntlmssp_state->neg_flags;
- status = ntlmssp_pull_AUTHENTICATE_MESSAGE(
- next_request, authenticate, authenticate);
- if (NT_STATUS_IS_OK(status)) {
- NDR_PRINT_DEBUG(AUTHENTICATE_MESSAGE,
- authenticate);
- }
- TALLOC_FREE(authenticate);
- }
- }
-
- data_blob_free(&encrypted_session_key);
-
- data_blob_free(&ntlmssp_state->chal);
-
- ntlmssp_state->session_key = session_key;
-
- ntlmssp_state->chal = challenge_blob;
- ntlmssp_state->lm_resp = lm_response;
- ntlmssp_state->nt_resp = nt_response;
-
-done:
-
- ntlmssp_state->expected_state = NTLMSSP_DONE;
-
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_sign_init(ntlmssp_state))) {
- DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", nt_errstr(nt_status)));
- }
-
- return nt_status;
-}
-
-NTSTATUS ntlmssp_client_start(TALLOC_CTX *mem_ctx,
- const char *netbios_name,
- const char *netbios_domain,
- bool use_ntlmv2,
- struct ntlmssp_state **_ntlmssp_state)
-{
- struct ntlmssp_state *ntlmssp_state;
-
- if (!netbios_name) {
- netbios_name = "";
- }
-
- if (!netbios_domain) {
- netbios_domain = "";
- }
-
- ntlmssp_state = talloc_zero(mem_ctx, struct ntlmssp_state);
- if (!ntlmssp_state) {
- return NT_STATUS_NO_MEMORY;
- }
-
- ntlmssp_state->role = NTLMSSP_CLIENT;
-
- ntlmssp_state->unicode = True;
-
- ntlmssp_state->use_ntlmv2 = use_ntlmv2;
-
- ntlmssp_state->expected_state = NTLMSSP_INITIAL;
-
- ntlmssp_state->neg_flags =
- NTLMSSP_NEGOTIATE_128 |
- NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
- NTLMSSP_NEGOTIATE_NTLM |
- NTLMSSP_NEGOTIATE_NTLM2 |
- NTLMSSP_NEGOTIATE_KEY_EXCH |
- NTLMSSP_REQUEST_TARGET;
-
- ntlmssp_state->client.netbios_name = talloc_strdup(ntlmssp_state, netbios_name);
- if (!ntlmssp_state->client.netbios_name) {
- talloc_free(ntlmssp_state);
- return NT_STATUS_NO_MEMORY;
- }
- ntlmssp_state->client.netbios_domain = talloc_strdup(ntlmssp_state, netbios_domain);
- if (!ntlmssp_state->client.netbios_domain) {
- talloc_free(ntlmssp_state);
- return NT_STATUS_NO_MEMORY;
- }
-
- *_ntlmssp_state = ntlmssp_state;
- return NT_STATUS_OK;
-}
diff --git a/source3/libsmb/ntlmssp_wrap.c b/source3/libsmb/ntlmssp_wrap.c
deleted file mode 100644
index 46f68aede79..00000000000
--- a/source3/libsmb/ntlmssp_wrap.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- NLTMSSP wrappers
-
- Copyright (C) Andrew Tridgell 2001
- Copyright (C) Andrew Bartlett 2001-2003,2011
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "auth/ntlmssp/ntlmssp.h"
-#include "auth/ntlmssp/ntlmssp_private.h"
-#include "auth_generic.h"
-#include "auth/gensec/gensec.h"
-#include "auth/gensec/gensec_internal.h"
-#include "auth/credentials/credentials.h"
-#include "librpc/rpc/dcerpc.h"
-#include "lib/param/param.h"
-
-static NTSTATUS gensec_ntlmssp3_client_update(struct gensec_security *gensec_security,
- TALLOC_CTX *out_mem_ctx,
- struct tevent_context *ev,
- const DATA_BLOB request,
- DATA_BLOB *reply)
-{
- NTSTATUS status;
- struct gensec_ntlmssp_context *gensec_ntlmssp =
- talloc_get_type_abort(gensec_security->private_data,
- struct gensec_ntlmssp_context);
-
- status = ntlmssp_update(gensec_ntlmssp->ntlmssp_state, request, reply);
- if (NT_STATUS_IS_OK(status) ||
- NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- talloc_steal(out_mem_ctx, reply->data);
- }
-
- return status;
-}
-
-static NTSTATUS gensec_ntlmssp3_client_start(struct gensec_security *gensec_security)
-{
- NTSTATUS nt_status;
- struct gensec_ntlmssp_context *gensec_ntlmssp;
- const char *user, *domain;
- const char *password;
-
- nt_status = gensec_ntlmssp_start(gensec_security);
- NT_STATUS_NOT_OK_RETURN(nt_status);
-
- gensec_ntlmssp =
- talloc_get_type_abort(gensec_security->private_data,
- struct gensec_ntlmssp_context);
-
- nt_status = ntlmssp_client_start(gensec_ntlmssp,
- lp_netbios_name(), lp_workgroup(),
- lp_client_ntlmv2_auth(), &gensec_ntlmssp->ntlmssp_state);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
-
- cli_credentials_get_ntlm_username_domain(gensec_security->credentials, gensec_ntlmssp, &user, &domain);
- if (!user || !domain) {
- return NT_STATUS_NO_MEMORY;
- }
-
- nt_status = ntlmssp_set_username(gensec_ntlmssp->ntlmssp_state, user);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
-
- nt_status = ntlmssp_set_domain(gensec_ntlmssp->ntlmssp_state, domain);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
-
- password = cli_credentials_get_password(gensec_security->credentials);
- if (!password) {
- return NT_STATUS_NO_MEMORY;
- }
-
- nt_status = ntlmssp_set_password(gensec_ntlmssp->ntlmssp_state, password);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
-
- if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
- gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
- }
- if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
- gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
- }
- if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
- gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
- gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
- }
-
- return NT_STATUS_OK;
-}
-
-static const char *gensec_ntlmssp3_client_oids[] = {
- GENSEC_OID_NTLMSSP,
- NULL
-};
-
-const struct gensec_security_ops gensec_ntlmssp3_client_ops = {
- .name = "ntlmssp3_client",
- .sasl_name = GENSEC_SASL_NAME_NTLMSSP, /* "NTLM" */
- .auth_type = DCERPC_AUTH_TYPE_NTLMSSP,
- .oid = gensec_ntlmssp3_client_oids,
- .client_start = gensec_ntlmssp3_client_start,
- .magic = gensec_ntlmssp_magic,
- .update = gensec_ntlmssp3_client_update,
- .sig_size = gensec_ntlmssp_sig_size,
- .sign_packet = gensec_ntlmssp_sign_packet,
- .check_packet = gensec_ntlmssp_check_packet,
- .seal_packet = gensec_ntlmssp_seal_packet,
- .unseal_packet = gensec_ntlmssp_unseal_packet,
- .wrap = gensec_ntlmssp_wrap,
- .unwrap = gensec_ntlmssp_unwrap,
- .session_key = gensec_ntlmssp_session_key,
- .have_feature = gensec_ntlmssp_have_feature,
- .enabled = true,
- .priority = GENSEC_NTLMSSP
-};
diff --git a/source3/libsmb/passchange.c b/source3/libsmb/passchange.c
index 9736adab9f6..3b8767672e3 100644
--- a/source3/libsmb/passchange.c
+++ b/source3/libsmb/passchange.c
@@ -57,7 +57,7 @@ NTSTATUS remote_password_change(const char *remote_machine, const char *user_nam
*err_str = NULL;
result = cli_connect_nb(remote_machine, NULL, 0, 0x20, NULL,
- SMB_SIGNING_DEFAULT, 0, &cli);
+ SMB_SIGNING_IPC_DEFAULT, 0, &cli);
if (!NT_STATUS_IS_OK(result)) {
if (asprintf(err_str, "Unable to connect to SMB server on "
"machine %s. Error was : %s.\n",
@@ -67,8 +67,9 @@ NTSTATUS remote_password_change(const char *remote_machine, const char *user_nam
return result;
}
- result = smbXcli_negprot(cli->conn, cli->timeout, PROTOCOL_CORE,
- PROTOCOL_NT1);
+ result = smbXcli_negprot(cli->conn, cli->timeout,
+ lp_client_ipc_min_protocol(),
+ lp_client_ipc_max_protocol());
if (!NT_STATUS_IS_OK(result)) {
if (asprintf(err_str, "machine %s rejected the negotiate "
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index 08dda9685fc..a4b3c7423ab 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -99,7 +99,7 @@ NTSTATUS cli_full_connection(struct cli_state **output_cli,
int signing_state);
NTSTATUS cli_raw_tcon(struct cli_state *cli,
const char *service, const char *pass, const char *dev,
- uint16 *max_xmit, uint16 *tid);
+ uint16_t *max_xmit, uint16_t *tid);
struct cli_state *get_ipc_connect(char *server,
struct sockaddr_storage *server_ss,
const struct user_auth_info *user_info);
@@ -176,7 +176,7 @@ void cli_nt_pipes_close(struct cli_state *cli);
void cli_shutdown(struct cli_state *cli);
const char *cli_state_remote_realm(struct cli_state *cli);
uint16_t cli_state_get_vc_num(struct cli_state *cli);
-uint16 cli_setpid(struct cli_state *cli, uint16 pid);
+uint16_t cli_setpid(struct cli_state *cli, uint16_t pid);
uint16_t cli_getpid(struct cli_state *cli);
bool cli_state_has_tcon(struct cli_state *cli);
uint16_t cli_state_get_tid(struct cli_state *cli);
@@ -204,7 +204,7 @@ NTSTATUS cli_smb(TALLOC_CTX *mem_ctx, struct cli_state *cli,
const char *cli_errstr(struct cli_state *cli);
NTSTATUS cli_nt_error(struct cli_state *cli);
-void cli_dos_error(struct cli_state *cli, uint8 *eclass, uint32 *ecode);
+void cli_dos_error(struct cli_state *cli, uint8_t *eclass, uint32_t *ecode);
int cli_errno(struct cli_state *cli);
bool cli_is_error(struct cli_state *cli);
bool cli_is_nt_error(struct cli_state *cli);
@@ -643,16 +643,16 @@ NTSTATUS cli_unix_extensions_version_recv(struct tevent_req *req,
uint16_t *pmajor, uint16_t *pminor,
uint32_t *pcaplow,
uint32_t *pcaphigh);
-NTSTATUS cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor,
- uint16 *pminor, uint32 *pcaplow,
- uint32 *pcaphigh);
+NTSTATUS cli_unix_extensions_version(struct cli_state *cli, uint16_t *pmajor,
+ uint16_t *pminor, uint32_t *pcaplow,
+ uint32_t *pcaphigh);
struct tevent_req *cli_set_unix_extensions_capabilities_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
uint16_t major, uint16_t minor, uint32_t caplow, uint32_t caphigh);
NTSTATUS cli_set_unix_extensions_capabilities_recv(struct tevent_req *req);
NTSTATUS cli_set_unix_extensions_capabilities(struct cli_state *cli,
- uint16 major, uint16 minor,
- uint32 caplow, uint32 caphigh);
+ uint16_t major, uint16_t minor,
+ uint32_t caplow, uint32 caphigh);
struct tevent_req *cli_get_fs_attr_info_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli);
@@ -660,7 +660,7 @@ NTSTATUS cli_get_fs_attr_info_recv(struct tevent_req *req, uint32_t *fs_attr);
NTSTATUS cli_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr);
NTSTATUS cli_get_fs_volume_info(struct cli_state *cli,
TALLOC_CTX *mem_ctx, char **volume_name,
- uint32 *pserial_number, time_t *pdate);
+ uint32_t *pserial_number, time_t *pdate);
NTSTATUS cli_get_fs_full_size_info(struct cli_state *cli,
uint64_t *total_allocation_units,
uint64_t *caller_allocation_units,
@@ -668,8 +668,8 @@ NTSTATUS cli_get_fs_full_size_info(struct cli_state *cli,
uint64_t *sectors_per_allocation_unit,
uint64_t *bytes_per_sector);
NTSTATUS cli_get_posix_fs_info(struct cli_state *cli,
- uint32 *optimal_transfer_size,
- uint32 *block_size,
+ uint32_t *optimal_transfer_size,
+ uint32_t *block_size,
uint64_t *total_blocks,
uint64_t *blocks_available,
uint64_t *user_blocks_available,
@@ -688,7 +688,7 @@ NTSTATUS cli_force_encryption(struct cli_state *c,
/* The following definitions come from libsmb/clilist.c */
-NTSTATUS cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute,
+NTSTATUS cli_list_old(struct cli_state *cli,const char *Mask,uint16_t attribute,
NTSTATUS (*fn)(const char *, struct file_info *,
const char *, void *), void *state);
NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
@@ -704,7 +704,7 @@ struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
uint16_t info_level);
NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
struct file_info **finfo, size_t *num_finfo);
-NTSTATUS cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
+NTSTATUS cli_list(struct cli_state *cli,const char *Mask,uint16_t attribute,
NTSTATUS (*fn)(const char *, struct file_info *, const char *,
void *), void *state);
diff --git a/source3/libsmb/samlogon_cache.c b/source3/libsmb/samlogon_cache.c
index 0a157d48463..a91ef6e4214 100644
--- a/source3/libsmb/samlogon_cache.c
+++ b/source3/libsmb/samlogon_cache.c
@@ -261,7 +261,7 @@ struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const struct do
--jerry */
{
time_t now = time(NULL);
- uint32 time_diff;
+ uint32_t time_diff;
/* is the entry expired? */
time_diff = now - t;
diff --git a/source3/libsmb/smb_share_modes.c b/source3/libsmb/smb_share_modes.c
index bf21bf5a593..325078d0875 100644
--- a/source3/libsmb/smb_share_modes.c
+++ b/source3/libsmb/smb_share_modes.c
@@ -60,7 +60,7 @@ struct locking_data {
int num_share_mode_entries;
struct timespec old_write_time;
struct timespec changed_write_time;
- uint32 num_delete_token_entries;
+ uint32_t num_delete_token_entries;
} s;
struct share_mode_entry dummy; /* Needed for alignment. */
} u;
@@ -146,7 +146,7 @@ static TDB_DATA get_locking_key(struct locking_key *lk, uint64_t dev,
lk->dev = (SMB_DEV_T)dev;
lk->inode = (SMB_INO_T)ino;
lk->extid = extid;
- ld.dptr = (uint8 *)lk;
+ ld.dptr = (uint8_t *)lk;
ld.dsize = sizeof(*lk);
return ld;
}
@@ -213,7 +213,7 @@ static void create_share_mode_entry(struct share_mode_entry *out,
out->id.devid = in->dev;
out->id.inode = in->ino;
out->id.extid = in->extid;
- out->uid = (uint32)geteuid();
+ out->uid = (uint32_t)geteuid();
out->flags = 0;
out->name_hash = name_hash;
}
@@ -342,7 +342,7 @@ int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx,
int orig_num_share_modes = 0;
struct locking_data *ld = NULL; /* internal samba db state. */
struct share_mode_entry *shares = NULL;
- uint8 *new_data_p = NULL;
+ uint8_t *new_data_p = NULL;
size_t new_data_size = 0;
int err = 0;
uint32_t name_hash = smb_name_hash(sharepath, filename, &err);
@@ -354,7 +354,7 @@ int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx,
db_data = tdb_fetch_compat(db_ctx->smb_tdb, locking_key);
if (!db_data.dptr) {
/* We must create the entry. */
- db_data.dptr = (uint8 *)malloc(
+ db_data.dptr = (uint8_t *)malloc(
sizeof(struct locking_data) +
sizeof(struct share_mode_entry) +
strlen(sharepath) + 1 +
@@ -389,7 +389,7 @@ int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx,
}
/* Entry exists, we must add a new entry. */
- new_data_p = (uint8 *)malloc(
+ new_data_p = (uint8_t *)malloc(
db_data.dsize + sizeof(struct share_mode_entry));
if (!new_data_p) {
free(db_data.dptr);
@@ -463,10 +463,10 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx,
int orig_num_share_modes = 0;
struct locking_data *ld = NULL; /* internal samba db state. */
struct share_mode_entry *shares = NULL;
- uint8 *new_data_p = NULL;
+ uint8_t *new_data_p = NULL;
size_t remaining_size = 0;
size_t i, num_share_modes;
- const uint8 *remaining_ptr = NULL;
+ const uint8_t *remaining_ptr = NULL;
db_data = tdb_fetch_compat(db_ctx->smb_tdb, locking_key);
if (!db_data.dptr) {
@@ -490,7 +490,7 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx,
}
/* More than one - allocate a new record minus the one we'll delete. */
- new_data_p = (uint8 *)malloc(
+ new_data_p = (uint8_t *)malloc(
db_data.dsize - sizeof(struct share_mode_entry));
if (!new_data_p) {
free(db_data.dptr);
diff --git a/source3/libsmb/smbsock_connect.c b/source3/libsmb/smbsock_connect.c
index dc04b6a966e..9f915e1bb42 100644
--- a/source3/libsmb/smbsock_connect.c
+++ b/source3/libsmb/smbsock_connect.c
@@ -29,7 +29,7 @@
struct cli_session_request_state {
struct tevent_context *ev;
int sock;
- uint32 len_hdr;
+ uint32_t len_hdr;
struct iovec iov[3];
uint8_t nb_session_response;
};
diff --git a/source3/pam_smbpass/wscript_build b/source3/pam_smbpass/wscript_build
index a4eaa6c2972..fb760b431d1 100644
--- a/source3/pam_smbpass/wscript_build
+++ b/source3/pam_smbpass/wscript_build
@@ -8,7 +8,7 @@ if bld.CONFIG_SET('WITH_PAM_MODULES'):
support.c''',
allow_warnings=True,
deps='''tdb talloc pam PAM_ERRORS wbclient cap asn1util param pdb
- LIBNTLMSSP LIBTSOCKET''',
+ LIBTSOCKET''',
cflags='-DLOCALEDIR=\"%s/locale\"' % bld.env.DATADIR,
realname='pam_smbpass.so',
install_path='${PAMMODULESDIR}',
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index d15d7fc5e8a..e805fa420a1 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -69,6 +69,7 @@
#include "dbwrap/dbwrap.h"
#include "dbwrap/dbwrap_rbt.h"
#include "../lib/util/bitmap.h"
+#include "source4/lib/tls/tls.h"
#ifdef HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>
@@ -612,6 +613,8 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
Globals.server_min_protocol = PROTOCOL_LANMAN1;
Globals._client_max_protocol = PROTOCOL_DEFAULT;
Globals.client_min_protocol = PROTOCOL_CORE;
+ Globals._client_ipc_max_protocol = PROTOCOL_DEFAULT;
+ Globals._client_ipc_min_protocol = PROTOCOL_DEFAULT;
Globals._security = SEC_AUTO;
Globals.encrypt_passwords = true;
Globals.client_schannel = Auto;
@@ -663,9 +666,12 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
Globals.client_plaintext_auth = false; /* Do NOT use a plaintext password even if is requested by the server */
Globals.lanman_auth = false; /* Do NOT use the LanMan hash, even if it is supplied */
Globals.ntlm_auth = true; /* Do use NTLMv1 if it is supplied by the client (otherwise NTLMv2) */
+ Globals.raw_ntlmv2_auth = false; /* Reject NTLMv2 without NTLMSSP */
Globals.client_ntlmv2_auth = true; /* Client should always use use NTLMv2, as we can't tell that the server supports it, but most modern servers do */
/* Note, that we will also use NTLM2 session security (which is different), if it is available */
+ Globals.allow_dcerpc_auth_level_connect = false; /* we don't allow this by default */
+
Globals.map_to_guest = 0; /* By Default, "Never" */
Globals.oplock_break_wait_time = 0; /* By Default, 0 msecs. */
Globals.enhanced_browsing = true;
@@ -710,6 +716,9 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
Globals.client_ldap_sasl_wrapping = ADS_AUTH_SASL_SIGN;
+ Globals.ldap_server_require_strong_auth =
+ LDAP_SERVER_REQUIRE_STRONG_AUTH_YES;
+
/* This is what we tell the afs client. in reality we set the token
* to never expire, though, when this runs out the afs client will
* forget the token. Set to 0 to get NEVERDATE.*/
@@ -785,6 +794,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
Globals.client_use_spnego = true;
Globals.client_signing = SMB_SIGNING_DEFAULT;
+ Globals._client_ipc_signing = SMB_SIGNING_DEFAULT;
Globals.server_signing = SMB_SIGNING_DEFAULT;
Globals.defer_sharing_violations = true;
@@ -832,10 +842,12 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
Globals.dcerpc_endpoint_servers = (const char **)str_list_make_v3(NULL, "epmapper wkssvc rpcecho samr netlogon lsarpc spoolss drsuapi dssetup unixinfo browser eventlog6 backupkey dnsserver", NULL);
Globals.tls_enabled = true;
+ Globals.tls_verify_peer = TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE;
lpcfg_string_set(Globals.ctx, &Globals._tls_keyfile, "tls/key.pem");
lpcfg_string_set(Globals.ctx, &Globals._tls_certfile, "tls/cert.pem");
lpcfg_string_set(Globals.ctx, &Globals._tls_cafile, "tls/ca.pem");
+ lpcfg_string_set(Globals.ctx, &Globals.tls_priority, "NORMAL:-VERS-SSL3.0");
lpcfg_string_set(Globals.ctx, &Globals.share_backend, "classic");
@@ -4338,13 +4350,37 @@ int lp_client_max_protocol(void)
return client_max_protocol;
}
-int lp_winbindd_max_protocol(void)
+int lp_client_ipc_min_protocol(void)
{
- int client_max_protocol = lp__client_max_protocol();
- if (client_max_protocol == PROTOCOL_DEFAULT) {
+ int client_ipc_min_protocol = lp__client_ipc_min_protocol();
+ if (client_ipc_min_protocol == PROTOCOL_DEFAULT) {
+ client_ipc_min_protocol = lp_client_min_protocol();
+ }
+ if (client_ipc_min_protocol < PROTOCOL_NT1) {
+ return PROTOCOL_NT1;
+ }
+ return client_ipc_min_protocol;
+}
+
+int lp_client_ipc_max_protocol(void)
+{
+ int client_ipc_max_protocol = lp__client_ipc_max_protocol();
+ if (client_ipc_max_protocol == PROTOCOL_DEFAULT) {
return PROTOCOL_LATEST;
}
- return client_max_protocol;
+ if (client_ipc_max_protocol < PROTOCOL_NT1) {
+ return PROTOCOL_NT1;
+ }
+ return client_ipc_max_protocol;
+}
+
+int lp_client_ipc_signing(void)
+{
+ int client_ipc_signing = lp__client_ipc_signing();
+ if (client_ipc_signing == SMB_SIGNING_DEFAULT) {
+ return SMB_SIGNING_REQUIRED;
+ }
+ return client_ipc_signing;
}
struct loadparm_global * get_globals(void)
diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c
index 974538b87bd..f50a5e92d03 100644
--- a/source3/rpc_client/cli_lsarpc.c
+++ b/source3/rpc_client/cli_lsarpc.c
@@ -81,7 +81,7 @@ NTSTATUS dcerpc_lsa_open_policy(struct dcerpc_binding_handle *h,
NTSTATUS rpccli_lsa_open_policy(struct rpc_pipe_client *cli,
TALLOC_CTX *mem_ctx,
- bool sec_qos, uint32 des_access,
+ bool sec_qos, uint32_t des_access,
struct policy_handle *pol)
{
NTSTATUS status;
@@ -140,7 +140,7 @@ NTSTATUS dcerpc_lsa_open_policy2(struct dcerpc_binding_handle *h,
NTSTATUS rpccli_lsa_open_policy2(struct rpc_pipe_client *cli,
TALLOC_CTX *mem_ctx, bool sec_qos,
- uint32 des_access, struct policy_handle *pol)
+ uint32_t des_access, struct policy_handle *pol)
{
NTSTATUS status;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
diff --git a/source3/rpc_client/cli_lsarpc.h b/source3/rpc_client/cli_lsarpc.h
index 36afe0bdfb0..4f9464d5b05 100644
--- a/source3/rpc_client/cli_lsarpc.h
+++ b/source3/rpc_client/cli_lsarpc.h
@@ -54,7 +54,7 @@ NTSTATUS dcerpc_lsa_open_policy(struct dcerpc_binding_handle *h,
NTSTATUS *result);
NTSTATUS rpccli_lsa_open_policy(struct rpc_pipe_client *cli,
TALLOC_CTX *mem_ctx,
- bool sec_qos, uint32 des_access,
+ bool sec_qos, uint32_t des_access,
struct policy_handle *pol);
/**
@@ -83,7 +83,7 @@ NTSTATUS dcerpc_lsa_open_policy2(struct dcerpc_binding_handle *h,
NTSTATUS *result);
NTSTATUS rpccli_lsa_open_policy2(struct rpc_pipe_client *cli,
TALLOC_CTX *mem_ctx, bool sec_qos,
- uint32 des_access, struct policy_handle *pol);
+ uint32_t des_access, struct policy_handle *pol);
/**
* @brief Look up the names that correspond to an array of sids.
diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index 7063351ef8a..9c727f7da31 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -312,7 +312,7 @@ NTSTATUS rpccli_netlogon_password_logon(struct netlogon_creds_cli_context *creds
}
case NetlogonNetworkInformation: {
struct netr_NetworkInfo *network_info;
- uint8 chal[8];
+ uint8_t chal[8];
unsigned char local_lm_response[24];
unsigned char local_nt_response[24];
struct netr_ChallengeResponse lm;
@@ -400,7 +400,7 @@ NTSTATUS rpccli_netlogon_network_logon(struct netlogon_creds_cli_context *creds,
const char *username,
const char *domain,
const char *workstation,
- const uint8 chal[8],
+ const uint8_t chal[8],
DATA_BLOB lm_response,
DATA_BLOB nt_response,
uint8_t *authoritative,
diff --git a/source3/rpc_client/cli_netlogon.h b/source3/rpc_client/cli_netlogon.h
index fee08016d5d..0765dfac618 100644
--- a/source3/rpc_client/cli_netlogon.h
+++ b/source3/rpc_client/cli_netlogon.h
@@ -60,7 +60,7 @@ NTSTATUS rpccli_netlogon_network_logon(struct netlogon_creds_cli_context *creds,
const char *username,
const char *domain,
const char *workstation,
- const uint8 chal[8],
+ const uint8_t chal[8],
DATA_BLOB lm_response,
DATA_BLOB nt_response,
uint8_t *authoritative,
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index 652a773ab51..cb01338c01e 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -56,9 +56,9 @@ static const char *rpccli_pipe_txt(TALLOC_CTX *mem_ctx,
Rpc pipe call id.
********************************************************************/
-static uint32 get_rpc_call_id(void)
+static uint32_t get_rpc_call_id(void)
{
- static uint32 call_id = 0;
+ static uint32_t call_id = 0;
return ++call_id;
}
@@ -391,9 +391,9 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
DATA_BLOB *rdata,
DATA_BLOB *reply_pdu)
{
- struct dcerpc_response *r;
+ const struct dcerpc_response *r = NULL;
+ DATA_BLOB tmp_stub = data_blob_null;
NTSTATUS ret = NT_STATUS_OK;
- size_t pad_len = 0;
/*
* Point the return values at the real data including the RPC
@@ -401,50 +401,128 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
*/
*rdata = *pdu;
+ if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
+ !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
+ /*
+ * TODO: do we still need this hack which was introduced
+ * in commit a42afcdcc7ab9aa9ed193ae36d3dbb10843447f0.
+ *
+ * I don't even know what AS/U might be...
+ */
+ DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
+ "fragment first/last ON.\n"));
+ pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+ }
+
/* Ensure we have the correct type. */
switch (pkt->ptype) {
- case DCERPC_PKT_ALTER_RESP:
+ case DCERPC_PKT_BIND_NAK:
+ DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
+ rpccli_pipe_txt(talloc_tos(), cli)));
+
+ ret = dcerpc_verify_ncacn_packet_header(pkt,
+ DCERPC_PKT_BIND_NAK,
+ 0, /* max_auth_info */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST,
+ 0); /* optional flags */
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+ "RPC packet type - %u, expected %u: %s\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->ptype, expected_pkt_type,
+ nt_errstr(ret)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ return ret;
+ }
+
+ /* Use this for now... */
+ return NT_STATUS_NETWORK_ACCESS_DENIED;
+
case DCERPC_PKT_BIND_ACK:
+ ret = dcerpc_verify_ncacn_packet_header(pkt,
+ expected_pkt_type,
+ pkt->u.bind_ack.auth_info.length,
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST,
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+ "RPC packet type - %u, expected %u: %s\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->ptype, expected_pkt_type,
+ nt_errstr(ret)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ return ret;
+ }
- /* Client code never receives this kind of packets */
break;
+ case DCERPC_PKT_ALTER_RESP:
+ ret = dcerpc_verify_ncacn_packet_header(pkt,
+ expected_pkt_type,
+ pkt->u.alter_resp.auth_info.length,
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST,
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+ "RPC packet type - %u, expected %u: %s\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->ptype, expected_pkt_type,
+ nt_errstr(ret)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ return ret;
+ }
+
+ break;
case DCERPC_PKT_RESPONSE:
r = &pkt->u.response;
+ ret = dcerpc_verify_ncacn_packet_header(pkt,
+ expected_pkt_type,
+ r->stub_and_verifier.length,
+ 0, /* required_flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+ "RPC packet type - %u, expected %u: %s\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->ptype, expected_pkt_type,
+ nt_errstr(ret)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ return ret;
+ }
+
+ tmp_stub.data = r->stub_and_verifier.data;
+ tmp_stub.length = r->stub_and_verifier.length;
+
/* Here's where we deal with incoming sign/seal. */
ret = dcerpc_check_auth(cli->auth, pkt,
- &r->stub_and_verifier,
+ &tmp_stub,
DCERPC_RESPONSE_LENGTH,
- pdu, &pad_len);
+ pdu);
if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+ "RPC packet type - %u, expected %u: %s\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->ptype, expected_pkt_type,
+ nt_errstr(ret)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
return ret;
}
- if (pkt->frag_length < DCERPC_RESPONSE_LENGTH + pad_len) {
- return NT_STATUS_BUFFER_TOO_SMALL;
- }
-
/* Point the return values at the NDR data. */
- rdata->data = r->stub_and_verifier.data;
-
- if (pkt->auth_length) {
- /* We've already done integer wrap tests in
- * dcerpc_check_auth(). */
- rdata->length = r->stub_and_verifier.length
- - pad_len
- - DCERPC_AUTH_TRAILER_LENGTH
- - pkt->auth_length;
- } else {
- rdata->length = r->stub_and_verifier.length;
- }
+ *rdata = tmp_stub;
- DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n",
+ DEBUG(10, ("Got pdu len %lu, data_len %lu\n",
(long unsigned int)pdu->length,
- (long unsigned int)rdata->length,
- (unsigned int)pad_len));
+ (long unsigned int)rdata->length));
/*
* If this is the first reply, and the allocation hint is
@@ -465,14 +543,24 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
break;
- case DCERPC_PKT_BIND_NAK:
- DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
- rpccli_pipe_txt(talloc_tos(), cli)));
- /* Use this for now... */
- return NT_STATUS_NETWORK_ACCESS_DENIED;
-
case DCERPC_PKT_FAULT:
+ ret = dcerpc_verify_ncacn_packet_header(pkt,
+ DCERPC_PKT_FAULT,
+ 0, /* max_auth_info */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST,
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, (__location__ ": Connection to %s got an unexpected "
+ "RPC packet type - %u, expected %u: %s\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->ptype, expected_pkt_type,
+ nt_errstr(ret)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ return ret;
+ }
+
DEBUG(1, (__location__ ": RPC fault code %s received "
"from %s!\n",
dcerpc_errstr(talloc_tos(),
@@ -489,13 +577,6 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
return NT_STATUS_RPC_PROTOCOL_ERROR;
}
- if (pkt->ptype != expected_pkt_type) {
- DEBUG(3, (__location__ ": Connection to %s got an unexpected "
- "RPC packet type - %u, not %u\n",
- rpccli_pipe_txt(talloc_tos(), cli),
- pkt->ptype, expected_pkt_type));
- return NT_STATUS_RPC_PROTOCOL_ERROR;
- }
if (pkt->call_id != call_id) {
DEBUG(3, (__location__ ": Connection to %s got an unexpected "
@@ -505,17 +586,6 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
return NT_STATUS_RPC_PROTOCOL_ERROR;
}
- /* Do this just before return - we don't want to modify any rpc header
- data before now as we may have needed to do cryptographic actions on
- it before. */
-
- if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
- !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
- DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
- "fragment first/last ON.\n"));
- pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
- }
-
return NT_STATUS_OK;
}
@@ -866,6 +936,12 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
state->pkt = talloc(state, struct ncacn_packet);
if (!state->pkt) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
@@ -875,18 +951,16 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
state->pkt,
!state->endianess);
if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
tevent_req_nterror(req, status);
return;
}
- if (state->incoming_frag.length != state->pkt->frag_length) {
- DEBUG(5, ("Incorrect pdu length %u, expected %u\n",
- (unsigned int)state->incoming_frag.length,
- (unsigned int)state->pkt->frag_length));
- tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
- return;
- }
-
status = cli_pipe_validate_current_pdu(state,
state->cli, state->pkt,
&state->incoming_frag,
@@ -900,6 +974,28 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
(unsigned)state->reply_pdu_offset,
nt_errstr(status)));
+ if (state->pkt->ptype != DCERPC_PKT_FAULT && !NT_STATUS_IS_OK(status)) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
+ }
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
return;
@@ -924,7 +1020,24 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
"%s\n",
state->endianess?"little":"big",
state->pkt->drep[0]?"little":"big"));
- tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (state->reply_pdu_offset + rdata.length > MAX_RPC_DATA_SIZE) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
return;
}
@@ -932,6 +1045,12 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
if (state->reply_pdu.length < state->reply_pdu_offset + rdata.length) {
if (!data_blob_realloc(NULL, &state->reply_pdu,
state->reply_pdu_offset + rdata.length)) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
@@ -960,6 +1079,14 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
subreq = get_complete_frag_send(state, state->ev, state->cli,
&state->incoming_frag);
+ if (subreq == NULL) {
+ /*
+ * TODO: do a real async disconnect ...
+ *
+ * For now do it sync...
+ */
+ TALLOC_FREE(state->cli->transport);
+ }
if (tevent_req_nomem(subreq, req)) {
return;
}
@@ -1039,14 +1166,14 @@ static NTSTATUS create_generic_auth_rpc_bind_req(struct rpc_pipe_client *cli,
static NTSTATUS create_bind_or_alt_ctx_internal(TALLOC_CTX *mem_ctx,
enum dcerpc_pkt_type ptype,
- uint32 rpc_call_id,
+ uint32_t rpc_call_id,
const struct ndr_syntax_id *abstract,
const struct ndr_syntax_id *transfer,
const DATA_BLOB *auth_info,
bool client_hdr_signing,
DATA_BLOB *blob)
{
- uint16 auth_len = auth_info->length;
+ uint16_t auth_len = auth_info->length;
NTSTATUS status;
union dcerpc_payload u;
struct dcerpc_ctx_list ctx_list;
@@ -1093,7 +1220,7 @@ static NTSTATUS create_bind_or_alt_ctx_internal(TALLOC_CTX *mem_ctx,
static NTSTATUS create_rpc_bind_req(TALLOC_CTX *mem_ctx,
struct rpc_pipe_client *cli,
struct pipe_auth_data *auth,
- uint32 rpc_call_id,
+ uint32_t rpc_call_id,
const struct ndr_syntax_id *abstract,
const struct ndr_syntax_id *transfer,
DATA_BLOB *rpc_out)
@@ -1123,7 +1250,7 @@ static NTSTATUS create_rpc_bind_req(TALLOC_CTX *mem_ctx,
auth->auth_type,
auth->auth_level,
0, /* auth_pad_length */
- 1, /* auth_context_id */
+ auth->auth_context_id,
&auth_token,
&auth_info);
if (!NT_STATUS_IS_OK(ret)) {
@@ -1628,9 +1755,8 @@ static bool check_bind_response(const struct dcerpc_bind_ack *r,
static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx,
struct rpc_pipe_client *cli,
- uint32 rpc_call_id,
- enum dcerpc_AuthType auth_type,
- enum dcerpc_AuthLevel auth_level,
+ struct pipe_auth_data *auth,
+ uint32_t rpc_call_id,
DATA_BLOB *pauth_blob,
DATA_BLOB *rpc_out)
{
@@ -1640,10 +1766,10 @@ static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx,
u.auth3._pad = 0;
status = dcerpc_push_dcerpc_auth(mem_ctx,
- auth_type,
- auth_level,
+ auth->auth_type,
+ auth->auth_level,
0, /* auth_pad_length */
- 1, /* auth_context_id */
+ auth->auth_context_id,
pauth_blob,
&u.auth3.auth_info);
if (!NT_STATUS_IS_OK(status)) {
@@ -1673,9 +1799,8 @@ static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx,
********************************************************************/
static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx,
- enum dcerpc_AuthType auth_type,
- enum dcerpc_AuthLevel auth_level,
- uint32 rpc_call_id,
+ struct pipe_auth_data *auth,
+ uint32_t rpc_call_id,
const struct ndr_syntax_id *abstract,
const struct ndr_syntax_id *transfer,
const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */
@@ -1685,10 +1810,10 @@ static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx,
NTSTATUS status;
status = dcerpc_push_dcerpc_auth(mem_ctx,
- auth_type,
- auth_level,
+ auth->auth_type,
+ auth->auth_level,
0, /* auth_pad_length */
- 1, /* auth_context_id */
+ auth->auth_context_id,
pauth_blob,
&auth_info);
if (!NT_STATUS_IS_OK(status)) {
@@ -1826,23 +1951,44 @@ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq)
return;
default:
- /* Paranoid lenght checks */
- if (pkt->frag_length < DCERPC_AUTH_TRAILER_LENGTH
- + pkt->auth_length) {
- tevent_req_nterror(req,
- NT_STATUS_INFO_LENGTH_MISMATCH);
+ if (pkt->auth_length == 0) {
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
return;
}
+
/* get auth credentials */
- status = dcerpc_pull_dcerpc_auth(talloc_tos(),
- &pkt->u.bind_ack.auth_info,
- &auth, false);
+ status = dcerpc_pull_auth_trailer(pkt, talloc_tos(),
+ &pkt->u.bind_ack.auth_info,
+ &auth, NULL, true);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("Failed to pull dcerpc auth: %s.\n",
nt_errstr(status)));
tevent_req_nterror(req, status);
return;
}
+
+ if (auth.auth_type != pauth->auth_type) {
+ DEBUG(0, (__location__ " Auth type %u mismatch expected %u.\n",
+ auth.auth_type, pauth->auth_type));
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (auth.auth_level != pauth->auth_level) {
+ DEBUG(0, (__location__ " Auth level %u mismatch expected %u.\n",
+ auth.auth_level, pauth->auth_level));
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (auth.auth_context_id != pauth->auth_context_id) {
+ DEBUG(0, (__location__ " Auth context id %u mismatch expected %u.\n",
+ (unsigned)auth.auth_context_id,
+ (unsigned)pauth->auth_context_id));
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
break;
}
@@ -1903,9 +2049,7 @@ static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
/* Now prepare the alter context pdu. */
data_blob_free(&state->rpc_out);
- status = create_rpc_alter_context(state,
- auth->auth_type,
- auth->auth_level,
+ status = create_rpc_alter_context(state, auth,
state->rpc_call_id,
&state->cli->abstract_syntax,
&state->cli->transfer_syntax,
@@ -1938,10 +2082,8 @@ static NTSTATUS rpc_bind_finish_send(struct tevent_req *req,
/* Now prepare the auth3 context pdu. */
data_blob_free(&state->rpc_out);
- status = create_rpc_bind_auth3(state, state->cli,
+ status = create_rpc_bind_auth3(state, state->cli, auth,
state->rpc_call_id,
- auth->auth_type,
- auth->auth_level,
auth_token,
&state->rpc_out);
if (!NT_STATUS_IS_OK(status)) {
@@ -2194,8 +2336,9 @@ static struct tevent_req *rpccli_bh_disconnect_send(TALLOC_CTX *mem_ctx,
/*
* TODO: do a real async disconnect ...
*
- * For now the caller needs to free rpc_cli
+ * For now we do it sync...
*/
+ TALLOC_FREE(hs->rpc_cli->transport);
hs->rpc_cli = NULL;
tevent_req_done(req);
@@ -2296,6 +2439,7 @@ NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
result->auth_type = DCERPC_AUTH_TYPE_NONE;
result->auth_level = DCERPC_AUTH_LEVEL_NONE;
+ result->auth_context_id = 0;
status = auth_generic_client_prepare(result,
&auth_generic_ctx);
@@ -2356,6 +2500,7 @@ static NTSTATUS rpccli_generic_bind_data(TALLOC_CTX *mem_ctx,
result->auth_type = auth_type;
result->auth_level = auth_level;
+ result->auth_context_id = 1;
status = auth_generic_client_prepare(result,
&auth_generic_ctx);
diff --git a/source3/rpc_client/rpc_client.h b/source3/rpc_client/rpc_client.h
index 7c5ff0e8181..b033da6c3d7 100644
--- a/source3/rpc_client/rpc_client.h
+++ b/source3/rpc_client/rpc_client.h
@@ -44,8 +44,8 @@ struct rpc_pipe_client {
char *desthost;
char *srv_name_slash;
- uint16 max_xmit_frag;
- uint16 max_recv_frag;
+ uint16_t max_xmit_frag;
+ uint16_t max_recv_frag;
struct pipe_auth_data *auth;
};
diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index b487c31e872..932df1de7d6 100644
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -1573,6 +1573,7 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
case NetlogonNetworkTransitiveInformation:
{
const char *wksname = nt_workstation;
+ const char *workgroup = lp_workgroup();
status = make_auth_context_fixed(talloc_tos(), &auth_context,
logon->network->challenge);
@@ -1599,6 +1600,14 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
logon->network->nt.length)) {
status = NT_STATUS_NO_MEMORY;
}
+
+ if (NT_STATUS_IS_OK(status)) {
+ status = NTLMv2_RESPONSE_verify_netlogon_creds(
+ user_info->client.account_name,
+ user_info->client.domain_name,
+ user_info->password.response.nt,
+ creds, workgroup);
+ }
break;
}
case NetlogonInteractiveInformation:
@@ -1707,6 +1716,14 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
r->out.validation->sam3);
break;
case 6:
+ /* Only allow this if the pipe is protected. */
+ if (p->auth.auth_level < DCERPC_AUTH_LEVEL_PRIVACY) {
+ DEBUG(0,("netr_Validation6: client %s not using privacy for netlogon\n",
+ get_remote_machine_name()));
+ status = NT_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
status = serverinfo_to_SamInfo6(server_info,
r->out.validation->sam6);
break;
@@ -2456,22 +2473,16 @@ NTSTATUS _netr_GetForestTrustInformation(struct pipes_struct *p,
NTSTATUS status;
struct netlogon_creds_CredentialState *creds;
struct lsa_ForestTrustInformation *info, **info_ptr;
- struct loadparm_context *lp_ctx;
/* TODO: check server name */
- lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers());
- if (lp_ctx == NULL) {
- DEBUG(0, ("loadparm_init_s3 failed\n"));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- status = schannel_check_creds_state(p->mem_ctx, lp_ctx,
- r->in.computer_name,
- r->in.credential,
- r->out.return_authenticator,
- &creds);
- talloc_unlink(p->mem_ctx, lp_ctx);
+ become_root();
+ status = netr_creds_server_step_check(p, p->mem_ctx,
+ r->in.computer_name,
+ r->in.credential,
+ r->out.return_authenticator,
+ &creds);
+ unbecome_root();
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -2558,22 +2569,16 @@ NTSTATUS _netr_ServerGetTrustInfo(struct pipes_struct *p,
bool trusted;
struct netr_TrustInfo *trust_info;
struct pdb_trusted_domain *td;
- struct loadparm_context *lp_ctx;
-
- lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers());
- if (lp_ctx == NULL) {
- DEBUG(0, ("loadparm_init_s3 failed\n"));
- return NT_STATUS_INTERNAL_ERROR;
- }
/* TODO: check server name */
- status = schannel_check_creds_state(p->mem_ctx, lp_ctx,
- r->in.computer_name,
- r->in.credential,
- r->out.return_authenticator,
- &creds);
- talloc_unlink(p->mem_ctx, lp_ctx);
+ become_root();
+ status = netr_creds_server_step_check(p, p->mem_ctx,
+ r->in.computer_name,
+ r->in.credential,
+ r->out.return_authenticator,
+ &creds);
+ unbecome_root();
if (!NT_STATUS_IS_OK(status)) {
return status;
}
diff --git a/source3/rpc_server/rpc_handles.c b/source3/rpc_server/rpc_handles.c
index 3542acca106..62b545c55c9 100644
--- a/source3/rpc_server/rpc_handles.c
+++ b/source3/rpc_server/rpc_handles.c
@@ -69,6 +69,7 @@ int make_base_pipes_struct(TALLOC_CTX *mem_ctx,
p->msg_ctx = msg_ctx;
p->transport = transport;
p->endian = endian;
+ p->allow_bind = true;
p->remote_address = tsocket_address_copy(remote_address, p);
if (p->remote_address == NULL) {
@@ -253,8 +254,8 @@ static struct dcesrv_handle *create_rpc_handle_internal(struct pipes_struct *p,
struct policy_handle *hnd, void *data_ptr)
{
struct dcesrv_handle *rpc_hnd;
- static uint32 pol_hnd_low = 0;
- static uint32 pol_hnd_high = 0;
+ static uint32_t pol_hnd_low = 0;
+ static uint32_t pol_hnd_high = 0;
time_t t = time(NULL);
if (p->pipe_handles->count > MAX_OPEN_POLS) {
@@ -336,7 +337,7 @@ static struct dcesrv_handle *find_policy_by_hnd_internal(struct pipes_struct *p,
for (h = p->pipe_handles->handles; h != NULL; h = h->next) {
if (memcmp(&h->wire_handle, hnd, sizeof(*hnd)) == 0) {
DEBUG(6,("Found policy hnd[%u] ", count));
- dump_data(6, (const uint8 *)hnd, sizeof(*hnd));
+ dump_data(6, (const uint8_t *)hnd, sizeof(*hnd));
if (data_p) {
*data_p = h->data;
}
diff --git a/source3/rpc_server/rpc_ncacn_np.c b/source3/rpc_server/rpc_ncacn_np.c
index d504847b434..5647596f559 100644
--- a/source3/rpc_server/rpc_ncacn_np.c
+++ b/source3/rpc_server/rpc_ncacn_np.c
@@ -224,7 +224,7 @@ struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx,
return NULL;
}
- context_fns = talloc(p, struct pipe_rpc_fns);
+ context_fns = talloc_zero(p, struct pipe_rpc_fns);
if (context_fns == NULL) {
DEBUG(0,("talloc() failed!\n"));
TALLOC_FREE(p);
@@ -977,6 +977,7 @@ static NTSTATUS rpc_pipe_open_external(TALLOC_CTX *mem_ctx,
}
result->auth->auth_type = DCERPC_AUTH_TYPE_NONE;
result->auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
+ result->auth->auth_context_id = 0;
status = rpccli_anon_bind_data(result, &auth);
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/rpc_server/rpc_pipes.h b/source3/rpc_server/rpc_pipes.h
index e65209aefc0..d44ee92bd5c 100644
--- a/source3/rpc_server/rpc_pipes.h
+++ b/source3/rpc_server/rpc_pipes.h
@@ -94,6 +94,10 @@ struct pipe_rpc_fns {
uint32_t context_id;
struct ndr_syntax_id syntax;
+ /*
+ * shall we allow "connect" auth level for this interface ?
+ */
+ bool allow_connect;
};
/*
@@ -127,6 +131,13 @@ struct pipes_struct {
bool pipe_bound;
/*
+ * States we can be in.
+ */
+ bool allow_alter;
+ bool allow_bind;
+ bool allow_auth3;
+
+ /*
* Set the DCERPC_FAULT to return.
*/
int fault_state;
diff --git a/source3/rpc_server/rpc_server.c b/source3/rpc_server/rpc_server.c
index 01a854ccafa..5effe66d9bb 100644
--- a/source3/rpc_server/rpc_server.c
+++ b/source3/rpc_server/rpc_server.c
@@ -558,6 +558,12 @@ static void named_pipe_packet_done(struct tevent_req *subreq)
return;
}
+ if (npc->p->fault_state != 0) {
+ DEBUG(2, ("Disconnect after fault\n"));
+ sys_errno = EINVAL;
+ goto fail;
+ }
+
/* clear out any data that may have been left around */
npc->count = 0;
TALLOC_FREE(npc->iov);
@@ -1292,6 +1298,12 @@ static void dcerpc_ncacn_packet_done(struct tevent_req *subreq)
goto fail;
}
+ if (ncacn_conn->p->fault_state != 0) {
+ DEBUG(2, ("Disconnect after fault\n"));
+ sys_errno = EINVAL;
+ goto fail;
+ }
+
/* clear out any data that may have been left around */
ncacn_conn->count = 0;
TALLOC_FREE(ncacn_conn->iov);
diff --git a/source3/rpc_server/samr/srv_samr_nt.c b/source3/rpc_server/samr/srv_samr_nt.c
index 76703d1389c..259b0dd1a9f 100644
--- a/source3/rpc_server/samr/srv_samr_nt.c
+++ b/source3/rpc_server/samr/srv_samr_nt.c
@@ -5097,7 +5097,7 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p,
case 18:
status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES);
if(!NT_STATUS_IS_OK(status)) {
- return status;
+ break;
}
/* Used by AS/U JRA. */
status = set_user_info_18(&info->info18,
@@ -5114,7 +5114,7 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p,
case 21:
status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES);
if(!NT_STATUS_IS_OK(status)) {
- return status;
+ break;
}
status = set_user_info_21(&info->info21,
p->mem_ctx,
@@ -5124,6 +5124,9 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p,
case 23:
status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES);
+ if(!NT_STATUS_IS_OK(status)) {
+ break;
+ }
arcfour_crypt_blob(info->info23.password.data, 516,
&session_key);
@@ -5137,6 +5140,9 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p,
case 24:
status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES);
+ if(!NT_STATUS_IS_OK(status)) {
+ break;
+ }
arcfour_crypt_blob(info->info24.password.data,
516,
&session_key);
@@ -5150,6 +5156,9 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p,
case 25:
status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES);
+ if(!NT_STATUS_IS_OK(status)) {
+ break;
+ }
encode_or_decode_arc4_passwd_buffer(
info->info25.password.data,
&session_key);
@@ -5163,6 +5172,9 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p,
case 26:
status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES);
+ if(!NT_STATUS_IS_OK(status)) {
+ break;
+ }
encode_or_decode_arc4_passwd_buffer(
info->info26.password.data,
&session_key);
@@ -6734,6 +6746,11 @@ NTSTATUS _samr_ValidatePassword(struct pipes_struct *p,
return NT_STATUS_ACCESS_DENIED;
}
+ if (p->auth.auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+ p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
if (r->in.level < 1 || r->in.level > 3) {
return NT_STATUS_INVALID_INFO_CLASS;
}
diff --git a/source3/rpc_server/srv_access_check.c b/source3/rpc_server/srv_access_check.c
index 878e38b1923..bb638251ba5 100644
--- a/source3/rpc_server/srv_access_check.c
+++ b/source3/rpc_server/srv_access_check.c
@@ -47,12 +47,12 @@
NTSTATUS access_check_object( struct security_descriptor *psd, struct security_token *token,
enum sec_privilege needed_priv_1, enum sec_privilege needed_priv_2,
- uint32 rights_mask,
- uint32 des_access, uint32 *acc_granted,
+ uint32_t rights_mask,
+ uint32_t des_access, uint32 *acc_granted,
const char *debug )
{
NTSTATUS status = NT_STATUS_ACCESS_DENIED;
- uint32 saved_mask = 0;
+ uint32_t saved_mask = 0;
bool priv_granted = false;
bool is_system = false;
bool is_root = false;
diff --git a/source3/rpc_server/srv_access_check.h b/source3/rpc_server/srv_access_check.h
index 72ce539568e..0e161689a86 100644
--- a/source3/rpc_server/srv_access_check.h
+++ b/source3/rpc_server/srv_access_check.h
@@ -34,8 +34,8 @@
NTSTATUS access_check_object( struct security_descriptor *psd, struct security_token *token,
enum sec_privilege needed_priv_1, enum sec_privilege needed_priv_2,
- uint32 rights_mask,
- uint32 des_access, uint32 *acc_granted,
+ uint32_t rights_mask,
+ uint32_t des_access, uint32 *acc_granted,
const char *debug );
void map_max_allowed_access(const struct security_token *nt_token,
const struct security_unix_token *unix_token,
diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
index 77200f8fed1..bcd7e5db6c2 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -30,7 +30,7 @@
#include "includes.h"
#include "system/filesys.h"
#include "srv_pipe_internal.h"
-#include "../librpc/gen_ndr/dcerpc.h"
+#include "../librpc/gen_ndr/ndr_dcerpc.h"
#include "../librpc/rpc/rpc_common.h"
#include "dcesrv_auth_generic.h"
#include "rpc_server.h"
@@ -44,6 +44,12 @@
#include "librpc/ndr/ndr_table.h"
#include "auth/gensec/gensec.h"
#include "librpc/ndr/ndr_dcerpc.h"
+#include "lib/tsocket/tsocket.h"
+#include "../librpc/gen_ndr/ndr_samr.h"
+#include "../librpc/gen_ndr/ndr_lsa.h"
+#include "../librpc/gen_ndr/ndr_netlogon.h"
+#include "../librpc/gen_ndr/ndr_epmapper.h"
+#include "../librpc/gen_ndr/ndr_echo.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_SRV
@@ -272,10 +278,14 @@ static bool setup_bind_nak(struct pipes_struct *p, struct ncacn_packet *pkt)
p->out_data.data_sent_length = 0;
p->out_data.current_pdu_sent = 0;
+ set_incoming_fault(p);
TALLOC_FREE(p->auth.auth_ctx);
p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE;
p->auth.auth_type = DCERPC_AUTH_TYPE_NONE;
p->pipe_bound = False;
+ p->allow_bind = false;
+ p->allow_alter = false;
+ p->allow_auth3 = false;
return True;
}
@@ -338,39 +348,118 @@ static bool check_bind_req(struct pipes_struct *p,
{
struct pipe_rpc_fns *context_fns;
bool ok;
+ const char *interface_name = NULL;
- DEBUG(3,("check_bind_req for %s\n",
+ DEBUG(3,("check_bind_req for %s context_id=%u\n",
ndr_interface_name(&abstract->uuid,
- abstract->if_version)));
+ abstract->if_version),
+ (unsigned)context_id));
+
+ ok = ndr_syntax_id_equal(transfer, &ndr_transfer_syntax_ndr);
+ if (!ok) {
+ DEBUG(1,("check_bind_req unknown transfer syntax for "
+ "%s context_id=%u\n",
+ ndr_interface_name(&abstract->uuid,
+ abstract->if_version),
+ (unsigned)context_id));
+ return false;
+ }
+
+ for (context_fns = p->contexts;
+ context_fns != NULL;
+ context_fns = context_fns->next)
+ {
+ if (context_fns->context_id != context_id) {
+ continue;
+ }
+
+ ok = ndr_syntax_id_equal(&context_fns->syntax,
+ abstract);
+ if (ok) {
+ return true;
+ }
+
+ DEBUG(1,("check_bind_req: changing abstract syntax for "
+ "%s context_id=%u into %s not supported\n",
+ ndr_interface_name(&context_fns->syntax.uuid,
+ context_fns->syntax.if_version),
+ (unsigned)context_id,
+ ndr_interface_name(&abstract->uuid,
+ abstract->if_version)));
+ return false;
+ }
/* we have to check all now since win2k introduced a new UUID on the lsaprpc pipe */
- if (rpc_srv_pipe_exists_by_id(abstract) &&
- ndr_syntax_id_equal(transfer, &ndr_transfer_syntax_ndr)) {
- DEBUG(3, ("check_bind_req: %s -> %s rpc service\n",
- rpc_srv_get_pipe_cli_name(abstract),
- rpc_srv_get_pipe_srv_name(abstract)));
- } else {
+ if (!rpc_srv_pipe_exists_by_id(abstract)) {
return false;
}
+ DEBUG(3, ("check_bind_req: %s -> %s rpc service\n",
+ rpc_srv_get_pipe_cli_name(abstract),
+ rpc_srv_get_pipe_srv_name(abstract)));
+
ok = init_pipe_handles(p, abstract);
if (!ok) {
DEBUG(1, ("Failed to init pipe handles!\n"));
return false;
}
- context_fns = talloc(p, struct pipe_rpc_fns);
+ context_fns = talloc_zero(p, struct pipe_rpc_fns);
if (context_fns == NULL) {
DEBUG(0,("check_bind_req: talloc() failed!\n"));
return false;
}
+ interface_name = ndr_interface_name(&abstract->uuid,
+ abstract->if_version);
+ SMB_ASSERT(interface_name != NULL);
+
context_fns->next = context_fns->prev = NULL;
context_fns->n_cmds = rpc_srv_get_pipe_num_cmds(abstract);
context_fns->cmds = rpc_srv_get_pipe_cmds(abstract);
context_fns->context_id = context_id;
context_fns->syntax = *abstract;
+ context_fns->allow_connect = lp_allow_dcerpc_auth_level_connect();
+ /*
+ * for the samr, lsarpc and netlogon interfaces we don't allow "connect"
+ * auth_level by default.
+ */
+ ok = ndr_syntax_id_equal(abstract, &ndr_table_samr.syntax_id);
+ if (ok) {
+ context_fns->allow_connect = false;
+ }
+ ok = ndr_syntax_id_equal(abstract, &ndr_table_lsarpc.syntax_id);
+ if (ok) {
+ context_fns->allow_connect = false;
+ }
+ ok = ndr_syntax_id_equal(abstract, &ndr_table_netlogon.syntax_id);
+ if (ok) {
+ context_fns->allow_connect = false;
+ }
+ /*
+ * for the epmapper and echo interfaces we allow "connect"
+ * auth_level by default.
+ */
+ ok = ndr_syntax_id_equal(abstract, &ndr_table_epmapper.syntax_id);
+ if (ok) {
+ context_fns->allow_connect = true;
+ }
+ ok = ndr_syntax_id_equal(abstract, &ndr_table_rpcecho.syntax_id);
+ if (ok) {
+ context_fns->allow_connect = true;
+ }
+ /*
+ * every interface can be modified to allow "connect" auth_level by
+ * using a parametric option like:
+ * allow dcerpc auth level connect:<interface>
+ * e.g.
+ * allow dcerpc auth level connect:samr = yes
+ */
+ context_fns->allow_connect = lp_parm_bool(-1,
+ "allow dcerpc auth level connect",
+ interface_name, context_fns->allow_connect);
+
/* add to the list of open contexts */
DLIST_ADD( p->contexts, context_fns );
@@ -449,6 +538,8 @@ static bool pipe_auth_generic_bind(struct pipes_struct *p,
p->auth.auth_ctx = gensec_security;
p->auth.auth_type = auth_info->auth_type;
+ p->auth.auth_level = auth_info->auth_level;
+ p->auth.auth_context_id = auth_info->auth_context_id;
if (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) {
p->auth.client_hdr_signing = true;
@@ -573,9 +664,8 @@ static NTSTATUS pipe_auth_verify_final(struct pipes_struct *p)
static bool api_pipe_bind_req(struct pipes_struct *p,
struct ncacn_packet *pkt)
{
- struct dcerpc_auth auth_info;
- uint16 assoc_gid;
- unsigned int auth_type = DCERPC_AUTH_TYPE_NONE;
+ struct dcerpc_auth auth_info = {0};
+ uint16_t assoc_gid;
NTSTATUS status;
struct ndr_syntax_id id;
uint8_t pfc_flags = 0;
@@ -585,14 +675,38 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
DATA_BLOB auth_blob = data_blob_null;
const struct ndr_interface_table *table;
- /* No rebinds on a bound pipe - use alter context. */
- if (p->pipe_bound) {
- DEBUG(2,("Rejecting bind request on bound rpc connection\n"));
+ if (!p->allow_bind) {
+ DEBUG(2,("Pipe not in allow bind state\n"));
return setup_bind_nak(p, pkt);
}
+ p->allow_bind = false;
+
+ status = dcerpc_verify_ncacn_packet_header(pkt,
+ DCERPC_PKT_BIND,
+ pkt->u.bind.auth_info.length,
+ 0, /* required flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("api_pipe_bind_req: invalid pdu: %s\n",
+ nt_errstr(status)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ goto err_exit;
+ }
if (pkt->u.bind.num_contexts == 0) {
- DEBUG(0, ("api_pipe_bind_req: no rpc contexts around\n"));
+ DEBUG(1, ("api_pipe_bind_req: no rpc contexts around\n"));
+ goto err_exit;
+ }
+
+ if (pkt->u.bind.ctx_list[0].num_transfer_syntaxes == 0) {
+ DEBUG(1, ("api_pipe_bind_req: no transfer syntaxes around\n"));
goto err_exit;
}
@@ -671,7 +785,6 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
bind_ack_ctx.reason.value = 0;
bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0];
} else {
- p->pipe_bound = False;
/* Rejection reason: abstract syntax not supported */
bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
bind_ack_ctx.reason.value = DCERPC_BIND_REASON_ASYNTAX;
@@ -682,71 +795,25 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
* Check if this is an authenticated bind request.
*/
if (pkt->auth_length) {
- /* Quick length check. Won't catch a bad auth footer,
- * prevents overrun. */
-
- if (pkt->frag_length < RPC_HEADER_LEN +
- DCERPC_AUTH_TRAILER_LENGTH +
- pkt->auth_length) {
- DEBUG(0,("api_pipe_bind_req: auth_len (%u) "
- "too long for fragment %u.\n",
- (unsigned int)pkt->auth_length,
- (unsigned int)pkt->frag_length));
- goto err_exit;
- }
-
/*
* Decode the authentication verifier.
*/
- status = dcerpc_pull_dcerpc_auth(pkt,
- &pkt->u.bind.auth_info,
- &auth_info, p->endian);
+ status = dcerpc_pull_auth_trailer(pkt, pkt,
+ &pkt->u.bind.auth_info,
+ &auth_info, NULL, true);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n"));
goto err_exit;
}
- auth_type = auth_info.auth_type;
-
- /* Work out if we have to sign or seal etc. */
- switch (auth_info.auth_level) {
- case DCERPC_AUTH_LEVEL_INTEGRITY:
- p->auth.auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
- break;
- case DCERPC_AUTH_LEVEL_PRIVACY:
- p->auth.auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
- break;
- case DCERPC_AUTH_LEVEL_CONNECT:
- p->auth.auth_level = DCERPC_AUTH_LEVEL_CONNECT;
- break;
- default:
- DEBUG(0, ("Unexpected auth level (%u).\n",
- (unsigned int)auth_info.auth_level ));
+ if (!pipe_auth_generic_bind(p, pkt,
+ &auth_info, &auth_resp)) {
goto err_exit;
}
-
- switch (auth_type) {
- case DCERPC_AUTH_TYPE_NONE:
- break;
-
- default:
- if (!pipe_auth_generic_bind(p, pkt,
- &auth_info, &auth_resp)) {
- goto err_exit;
- }
- break;
- }
- }
-
- if (auth_type == DCERPC_AUTH_TYPE_NONE) {
- /* Unauthenticated bind request. */
- /* We're finished - no more packets. */
+ } else {
p->auth.auth_type = DCERPC_AUTH_TYPE_NONE;
- /* We must set the pipe auth_level here also. */
p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE;
- p->pipe_bound = True;
- /* The session key was initialized from the SMB
- * session in make_internal_rpc_pipe_p */
+ p->auth.auth_context_id = 0;
}
ZERO_STRUCT(u.bind_ack);
@@ -793,15 +860,15 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n",
nt_errstr(status)));
+ goto err_exit;
}
if (auth_resp.length) {
-
status = dcerpc_push_dcerpc_auth(pkt,
- auth_type,
- auth_info.auth_level,
- 0,
- 1, /* auth_context_id */
+ p->auth.auth_type,
+ p->auth.auth_level,
+ 0, /* pad_len */
+ p->auth.auth_context_id,
&auth_resp,
&auth_blob);
if (!NT_STATUS_IS_OK(status)) {
@@ -832,6 +899,22 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
p->out_data.current_pdu_sent = 0;
TALLOC_FREE(auth_blob.data);
+
+ if (bind_ack_ctx.result == 0) {
+ p->allow_alter = true;
+ p->allow_auth3 = true;
+ if (p->auth.auth_type == DCERPC_AUTH_TYPE_NONE) {
+ status = pipe_auth_verify_final(p);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("pipe_auth_verify_final failed: %s\n",
+ nt_errstr(status)));
+ goto err_exit;
+ }
+ }
+ } else {
+ goto err_exit;
+ }
+
return True;
err_exit:
@@ -854,18 +937,39 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt)
DEBUG(5, ("api_pipe_bind_auth3: decode request. %d\n", __LINE__));
- if (pkt->auth_length == 0) {
- DEBUG(1, ("No auth field sent for bind request!\n"));
+ if (!p->allow_auth3) {
+ DEBUG(1, ("Pipe not in allow auth3 state.\n"));
+ goto err;
+ }
+
+ status = dcerpc_verify_ncacn_packet_header(pkt,
+ DCERPC_PKT_AUTH3,
+ pkt->u.auth3.auth_info.length,
+ 0, /* required flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("api_pipe_bind_auth3: invalid pdu: %s\n",
+ nt_errstr(status)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ goto err;
+ }
+
+ /* We can only finish if the pipe is unbound for now */
+ if (p->pipe_bound) {
+ DEBUG(0, (__location__ ": Pipe already bound, "
+ "AUTH3 not supported!\n"));
goto err;
}
- /* Ensure there's enough data for an authenticated request. */
- if (pkt->frag_length < RPC_HEADER_LEN
- + DCERPC_AUTH_TRAILER_LENGTH
- + pkt->auth_length) {
- DEBUG(1,("api_pipe_ntlmssp_auth_process: auth_len "
- "%u is too large.\n",
- (unsigned int)pkt->auth_length));
+ if (pkt->auth_length == 0) {
+ DEBUG(1, ("No auth field sent for auth3 request!\n"));
goto err;
}
@@ -873,9 +977,9 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt)
* Decode the authentication verifier response.
*/
- status = dcerpc_pull_dcerpc_auth(pkt,
- &pkt->u.auth3.auth_info,
- &auth_info, p->endian);
+ status = dcerpc_pull_auth_trailer(pkt, pkt,
+ &pkt->u.auth3.auth_info,
+ &auth_info, NULL, true);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to unmarshall dcerpc_auth.\n"));
goto err;
@@ -893,6 +997,21 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt)
goto err;
}
+ if (auth_info.auth_level != p->auth.auth_level) {
+ DEBUG(1, ("Auth level mismatch! Client sent %d, "
+ "but auth was started as level %d!\n",
+ auth_info.auth_level, p->auth.auth_level));
+ goto err;
+ }
+
+ if (auth_info.auth_context_id != p->auth.auth_context_id) {
+ DEBUG(0, ("Auth context id mismatch! Client sent %u, "
+ "but auth was started as level %u!\n",
+ (unsigned)auth_info.auth_context_id,
+ (unsigned)p->auth.auth_context_id));
+ goto err;
+ }
+
gensec_security = p->auth.auth_ctx;
status = auth_generic_server_step(gensec_security,
@@ -923,6 +1042,10 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt)
return true;
err:
+ p->pipe_bound = false;
+ p->allow_bind = false;
+ p->allow_alter = false;
+ p->allow_auth3 = false;
TALLOC_FREE(p->auth.auth_ctx);
return false;
@@ -936,19 +1059,53 @@ err:
static bool api_pipe_alter_context(struct pipes_struct *p,
struct ncacn_packet *pkt)
{
- struct dcerpc_auth auth_info;
- uint16 assoc_gid;
+ struct dcerpc_auth auth_info = {0};
+ uint16_t assoc_gid;
NTSTATUS status;
union dcerpc_payload u;
- struct dcerpc_ack_ctx bind_ack_ctx;
+ struct dcerpc_ack_ctx alter_ack_ctx;
DATA_BLOB auth_resp = data_blob_null;
DATA_BLOB auth_blob = data_blob_null;
struct gensec_security *gensec_security;
DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__));
- if (pkt->u.bind.assoc_group_id != 0) {
- assoc_gid = pkt->u.bind.assoc_group_id;
+ if (!p->allow_alter) {
+ DEBUG(1, ("Pipe not in allow alter state.\n"));
+ goto err_exit;
+ }
+
+ status = dcerpc_verify_ncacn_packet_header(pkt,
+ DCERPC_PKT_ALTER,
+ pkt->u.alter.auth_info.length,
+ 0, /* required flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("api_pipe_alter_context: invalid pdu: %s\n",
+ nt_errstr(status)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ goto err_exit;
+ }
+
+ if (pkt->u.alter.num_contexts == 0) {
+ DEBUG(1, ("api_pipe_alter_context: no rpc contexts around\n"));
+ goto err_exit;
+ }
+
+ if (pkt->u.alter.ctx_list[0].num_transfer_syntaxes == 0) {
+ DEBUG(1, ("api_pipe_alter_context: no transfer syntaxes around\n"));
+ goto err_exit;
+ }
+
+ if (pkt->u.alter.assoc_group_id != 0) {
+ assoc_gid = pkt->u.alter.assoc_group_id;
} else {
assoc_gid = 0x53f0;
}
@@ -958,59 +1115,45 @@ static bool api_pipe_alter_context(struct pipes_struct *p,
*/
/* If the requested abstract synt uuid doesn't match our client pipe,
- reject the bind_ack & set the transfer interface synt to all 0's,
+ reject the alter_ack & set the transfer interface synt to all 0's,
ver 0 (observed when NT5 attempts to bind to abstract interfaces
unknown to NT4)
Needed when adding entries to a DACL from NT5 - SK */
if (check_bind_req(p,
- &pkt->u.bind.ctx_list[0].abstract_syntax,
- &pkt->u.bind.ctx_list[0].transfer_syntaxes[0],
- pkt->u.bind.ctx_list[0].context_id)) {
+ &pkt->u.alter.ctx_list[0].abstract_syntax,
+ &pkt->u.alter.ctx_list[0].transfer_syntaxes[0],
+ pkt->u.alter.ctx_list[0].context_id)) {
- bind_ack_ctx.result = 0;
- bind_ack_ctx.reason.value = 0;
- bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0];
+ alter_ack_ctx.result = 0;
+ alter_ack_ctx.reason.value = 0;
+ alter_ack_ctx.syntax = pkt->u.alter.ctx_list[0].transfer_syntaxes[0];
} else {
- p->pipe_bound = False;
/* Rejection reason: abstract syntax not supported */
- bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
- bind_ack_ctx.reason.value = DCERPC_BIND_REASON_ASYNTAX;
- bind_ack_ctx.syntax = ndr_syntax_id_null;
+ alter_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
+ alter_ack_ctx.reason.value = DCERPC_BIND_REASON_ASYNTAX;
+ alter_ack_ctx.syntax = ndr_syntax_id_null;
}
/*
* Check if this is an authenticated alter context request.
*/
if (pkt->auth_length) {
- /* Quick length check. Won't catch a bad auth footer,
- * prevents overrun. */
-
- if (pkt->frag_length < RPC_HEADER_LEN +
- DCERPC_AUTH_TRAILER_LENGTH +
- pkt->auth_length) {
- DEBUG(0,("api_pipe_alter_context: auth_len (%u) "
- "too long for fragment %u.\n",
- (unsigned int)pkt->auth_length,
- (unsigned int)pkt->frag_length ));
+ /* We can only finish if the pipe is unbound for now */
+ if (p->pipe_bound) {
+ DEBUG(0, (__location__ ": Pipe already bound, "
+ "Altering Context not yet supported!\n"));
goto err_exit;
}
- status = dcerpc_pull_dcerpc_auth(pkt,
- &pkt->u.bind.auth_info,
- &auth_info, p->endian);
+ status = dcerpc_pull_auth_trailer(pkt, pkt,
+ &pkt->u.alter.auth_info,
+ &auth_info, NULL, true);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n"));
goto err_exit;
}
- /* We can only finish if the pipe is unbound for now */
- if (p->pipe_bound) {
- DEBUG(0, (__location__ ": Pipe already bound, "
- "Altering Context not yet supported!\n"));
- goto err_exit;
- }
-
if (auth_info.auth_type != p->auth.auth_type) {
DEBUG(0, ("Auth type mismatch! Client sent %d, "
"but auth was started as type %d!\n",
@@ -1018,6 +1161,21 @@ static bool api_pipe_alter_context(struct pipes_struct *p,
goto err_exit;
}
+ if (auth_info.auth_level != p->auth.auth_level) {
+ DEBUG(0, ("Auth level mismatch! Client sent %d, "
+ "but auth was started as level %d!\n",
+ auth_info.auth_level, p->auth.auth_level));
+ goto err_exit;
+ }
+
+ if (auth_info.auth_context_id != p->auth.auth_context_id) {
+ DEBUG(0, ("Auth context id mismatch! Client sent %u, "
+ "but auth was started as level %u!\n",
+ (unsigned)auth_info.auth_context_id,
+ (unsigned)p->auth.auth_context_id));
+ goto err_exit;
+ }
+
gensec_security = p->auth.auth_ctx;
status = auth_generic_server_step(gensec_security,
pkt,
@@ -1054,7 +1212,7 @@ static bool api_pipe_alter_context(struct pipes_struct *p,
u.alter_resp.secondary_address_size = 1;
u.alter_resp.num_results = 1;
- u.alter_resp.ctx_list = &bind_ack_ctx;
+ u.alter_resp.ctx_list = &alter_ack_ctx;
/* NOTE: We leave the auth_info empty so we can calculate the padding
* later and then append the auth_info --simo */
@@ -1074,16 +1232,17 @@ static bool api_pipe_alter_context(struct pipes_struct *p,
&u,
&p->out_data.frag);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n",
+ DEBUG(0, ("Failed to marshall alter_resp packet. (%s)\n",
nt_errstr(status)));
+ goto err_exit;
}
if (auth_resp.length) {
status = dcerpc_push_dcerpc_auth(pkt,
- auth_info.auth_type,
- auth_info.auth_level,
+ p->auth.auth_type,
+ p->auth.auth_level,
0, /* pad_len */
- 1, /* auth_context_id */
+ p->auth.auth_context_id,
&auth_resp,
&auth_blob);
if (!NT_STATUS_IS_OK(status)) {
@@ -1174,6 +1333,7 @@ static bool api_pipe_request(struct pipes_struct *p,
TALLOC_CTX *frame = talloc_stackframe();
bool ret = False;
struct pipe_rpc_fns *pipe_fns;
+ const char *interface_name = NULL;
if (!p->pipe_bound) {
DEBUG(1, ("Pipe not bound!\n"));
@@ -1194,8 +1354,40 @@ static bool api_pipe_request(struct pipes_struct *p,
return false;
}
+ interface_name = ndr_interface_name(&pipe_fns->syntax.uuid,
+ pipe_fns->syntax.if_version);
+ SMB_ASSERT(interface_name != NULL);
+
+ switch (p->auth.auth_level) {
+ case DCERPC_AUTH_LEVEL_NONE:
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ if (!pipe_fns->allow_connect) {
+ char *addr;
+
+ addr = tsocket_address_string(p->remote_address, frame);
+
+ DEBUG(1, ("%s: restrict auth_level_connect access "
+ "to [%s] with auth[type=0x%x,level=0x%x] "
+ "on [%s] from [%s]\n",
+ __func__, interface_name,
+ p->auth.auth_type,
+ p->auth.auth_level,
+ derpc_transport_string_by_transport(p->transport),
+ addr));
+
+ setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED));
+ TALLOC_FREE(frame);
+ return true;
+ }
+ break;
+ }
+
if (!srv_pipe_check_verification_trailer(p, pkt, pipe_fns)) {
DEBUG(1, ("srv_pipe_check_verification_trailer: failed\n"));
+ set_incoming_fault(p);
setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED));
data_blob_free(&p->out_data.rdata);
TALLOC_FREE(frame);
@@ -1209,9 +1401,7 @@ static bool api_pipe_request(struct pipes_struct *p,
return false;
}
- DEBUG(5, ("Requested %s rpc service\n",
- ndr_interface_name(&pipe_fns->syntax.uuid,
- pipe_fns->syntax.if_version)));
+ DEBUG(5, ("Requested %s rpc service\n", interface_name));
ret = api_rpcTNP(p, pkt, pipe_fns->cmds, pipe_fns->n_cmds,
&pipe_fns->syntax);
@@ -1345,7 +1535,11 @@ void set_incoming_fault(struct pipes_struct *p)
data_blob_free(&p->in_data.data);
p->in_data.pdu_needed_len = 0;
p->in_data.pdu.length = 0;
- p->fault_state = DCERPC_FAULT_CANT_PERFORM;
+ p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
+
+ p->allow_alter = false;
+ p->allow_auth3 = false;
+ p->pipe_bound = false;
DEBUG(10, ("Setting fault state\n"));
}
@@ -1356,7 +1550,6 @@ static NTSTATUS dcesrv_auth_request(struct pipe_auth_data *auth,
{
NTSTATUS status;
size_t hdr_size = DCERPC_REQUEST_LENGTH;
- size_t pad_len;
DEBUG(10, ("Checking request auth.\n"));
@@ -1367,25 +1560,11 @@ static NTSTATUS dcesrv_auth_request(struct pipe_auth_data *auth,
/* in case of sealing this function will unseal the data in place */
status = dcerpc_check_auth(auth, pkt,
&pkt->u.request.stub_and_verifier,
- hdr_size, raw_pkt,
- &pad_len);
+ hdr_size, raw_pkt);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
-
- /* remove padding and auth trailer,
- * this way the caller will get just the data */
- if (pkt->auth_length) {
- size_t trail_len = pad_len
- + DCERPC_AUTH_TRAILER_LENGTH
- + pkt->auth_length;
- if (pkt->u.request.stub_and_verifier.length < trail_len) {
- return NT_STATUS_INFO_LENGTH_MISMATCH;
- }
- pkt->u.request.stub_and_verifier.length -= trail_len;
- }
-
return NT_STATUS_OK;
}
@@ -1406,6 +1585,29 @@ static bool process_request_pdu(struct pipes_struct *p, struct ncacn_packet *pkt
return False;
}
+ /*
+ * We don't ignore DCERPC_PFC_FLAG_PENDING_CANCEL.
+ * TODO: we can reject it with DCERPC_FAULT_NO_CALL_ACTIVE later.
+ */
+ status = dcerpc_verify_ncacn_packet_header(pkt,
+ DCERPC_PKT_REQUEST,
+ pkt->u.request.stub_and_verifier.length,
+ 0, /* required_flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("process_request_pdu: invalid pdu: %s\n",
+ nt_errstr(status)));
+ NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ set_incoming_fault(p);
+ return false;
+ }
+
hdr2 = dcerpc_sec_vt_header2_from_ncacn_packet(pkt);
if (pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST) {
p->header2 = hdr2;
@@ -1597,7 +1799,7 @@ done:
if (!reply) {
DEBUG(3,("DCE/RPC fault sent!"));
set_incoming_fault(p);
- setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
+ setup_fault_pdu(p, NT_STATUS(DCERPC_NCA_S_PROTO_ERROR));
}
/* pkt and p->in_data.pdu.data freed by caller */
}
diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c
index ac7576fc017..a35e4223327 100644
--- a/source3/rpcclient/rpcclient.c
+++ b/source3/rpcclient/rpcclient.c
@@ -1110,10 +1110,9 @@ out_free:
}
}
if (pipe_default_auth_type != DCERPC_AUTH_TYPE_NONE) {
- /* If neither Integrity or Privacy are requested then
- * Use just Connect level */
+ /* If nothing is requested then default to integrity */
if (pipe_default_auth_level == DCERPC_AUTH_LEVEL_NONE) {
- pipe_default_auth_level = DCERPC_AUTH_LEVEL_CONNECT;
+ pipe_default_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
}
}
diff --git a/source3/script/tests/test_ntlm_auth_s3.sh b/source3/script/tests/test_ntlm_auth_s3.sh
index 655556b692c..bd4ffa1ea1b 100755
--- a/source3/script/tests/test_ntlm_auth_s3.sh
+++ b/source3/script/tests/test_ntlm_auth_s3.sh
@@ -94,6 +94,8 @@ testit "ntlm_auth with NTLMSSP client and gss-spnego server" $PYTHON $SRC3DIR/to
testit "ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH $ADDARGS --client-domain=fOo --server-domain=fOo --client-helper=gss-spnego-client --server-helper=gss-spnego || failed=`expr $failed + 1`
testit "ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server against winbind" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH --client-username=$USERNAME --client-domain=$DOMAIN --client-password=$PASSWORD --server-use-winbindd --client-helper=gss-spnego-client --server-helper=gss-spnego $ADDARGS || failed=`expr $failed + 1`
+testit "wbinfo store cached credentials" $BINDIR/wbinfo --ccache-save=$DOMAIN/$USERNAME%$PASSWORD || failed=`expr $failed + 1`
+testit "ntlm_auth ccached credentials with NTLMSSP client and gss-spnego server" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH $ADDARGS --client-username=$USERNAME --client-domain=$DOMAIN --client-use-cached-creds --client-helper=ntlmssp-client-1 --server-helper=gss-spnego --server-use-winbindd || failed=`expr $failed + 1`
testit "ntlm_auth against winbindd with require-membership-of" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH --client-username=$USERNAME --client-domain=$DOMAIN --client-password=$PASSWORD --server-use-winbindd $ADDARGS --require-membership-of=$SID || failed=`expr $failed + 1`
testit "ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server against winbind with require-membership-of" $PYTHON $SRC3DIR/torture/test_ntlm_auth.py $NTLM_AUTH --client-username=$USERNAME --client-domain=$DOMAIN --client-password=$PASSWORD --server-use-winbindd --client-helper=gss-spnego-client --server-helper=gss-spnego $ADDARGS --require-membership-of=$SID || failed=`expr $failed + 1`
diff --git a/source3/script/tests/test_rpcclient_samlogon.sh b/source3/script/tests/test_rpcclient_samlogon.sh
index 01af7f80a15..a41ae44d25f 100755
--- a/source3/script/tests/test_rpcclient_samlogon.sh
+++ b/source3/script/tests/test_rpcclient_samlogon.sh
@@ -12,16 +12,21 @@ PASSWORD="$2"
shift 2
ADDARGS="$*"
-rpcclient_samlogon()
+rpcclient_samlogon_schannel_seal()
{
- $VALGRIND $BINDIR/rpcclient -U% -c "samlogon $USERNAME $PASSWORD;samlogon $USERNAME $PASSWORD" $@
+ $VALGRIND $BINDIR/rpcclient -U% -c "schannel;samlogon $USERNAME $PASSWORD;samlogon $USERNAME $PASSWORD" $@
}
+rpcclient_samlogon_schannel_sign()
+{
+ $VALGRIND $BINDIR/rpcclient -U% -c "schannelsign;samlogon $USERNAME $PASSWORD;samlogon $USERNAME $PASSWORD" $@
+}
incdir=`dirname $0`/../../../testprogs/blackbox
. $incdir/subunit.sh
testit "rpcclient dsenumdomtrusts" $VALGRIND $BINDIR/rpcclient $ADDARGS -U% -c "dsenumdomtrusts" || failed=`expr $failed + 1`
testit "rpcclient getdcsitecoverage" $VALGRIND $BINDIR/rpcclient $ADDARGS -U% -c "getdcsitecoverage" || failed=`expr $failed + 1`
-testit "rpcclient samlogon" rpcclient_samlogon $ADDARGS || failed=`expr $failed +1`
+testit "rpcclient samlogon schannel seal" rpcclient_samlogon_schannel_seal $ADDARGS || failed=`expr $failed +1`
+testit "rpcclient samlogon schannel sign" rpcclient_samlogon_schannel_sign $ADDARGS || failed=`expr $failed +1`
testok $0 $failed
diff --git a/source3/script/tests/test_smbclient_auth.sh b/source3/script/tests/test_smbclient_auth.sh
index 24e98b1f552..2402f737287 100755
--- a/source3/script/tests/test_smbclient_auth.sh
+++ b/source3/script/tests/test_smbclient_auth.sh
@@ -21,6 +21,17 @@ ADDARGS="$*"
incdir=`dirname $0`/../../../testprogs/blackbox
. $incdir/subunit.sh
+echo "${SERVER_IP}" | grep -q ':.*:' && {
+ # If we have an ipv6 address e.g.
+ # fd00:0000:0000:0000:0000:0000:5357:5f03
+ # we also try
+ # fd00-0000-0000-0000-0000-0000-5357-5f03.ipv6-literal.net
+ IPV6LITERAL=$(echo "${SERVER_IP}.ipv6-literal.net" | sed -e 's!:!-!g' -e 's!%!s!')
+ testit "smbclient //${IPV6LITERAL}/tmpguest" $SMBCLIENT //${IPV6LITERAL}/tmpguest $CONFIGURATION -U$USERNAME%$PASSWORD -c quit $ADDARGS
+ testit "smbclient //${IPV6LITERAL}./tmpguest" $SMBCLIENT //${IPV6LITERAL}./tmpguest $CONFIGURATION -U$USERNAME%$PASSWORD -c quit $ADDARGS
+}
+testit "smbclient //${SERVER_IP}/tmpguest" $SMBCLIENT //${SERVER_IP}/tmpguest $CONFIGURATION -U$USERNAME%$PASSWORD -p 139 -c quit $ADDARGS
+
testit "smbclient //$SERVER/guestonly" $SMBCLIENT //$SERVER/guestonly $CONFIGURATION -U$USERNAME%$PASSWORD -I $SERVER_IP -p 139 -c quit $ADDARGS
testit "smbclient //$SERVER/guestonly as anon" $SMBCLIENT //$SERVER/guestonly $CONFIGURATION -U% -I $SERVER_IP -p 139 -c quit $ADDARGS
testit "smbclient //$SERVER/tmpguest" $SMBCLIENT //$SERVER/tmpguest $CONFIGURATION -U$USERNAME%$PASSWORD -I $SERVER_IP -p 139 -c quit $ADDARGS
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 830753c12b4..8b929214af8 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -135,6 +135,9 @@ for env in ["s3dc", "member", "s3member"]:
plantestsuite("samba3.blackbox.smbclient_auth.plain (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbclient_auth.sh"), '$SERVER', '$SERVER_IP', '$DC_USERNAME', '$DC_PASSWORD', smbclient3, configuration])
plantestsuite("samba3.blackbox.smbclient_auth.plain (%s) member creds" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbclient_auth.sh"), '$SERVER', '$SERVER_IP', '$SERVER/$USERNAME', '$PASSWORD', smbclient3, configuration])
+env="s3dc"
+plantestsuite("samba3.blackbox.smbclient_auth.plain (%s) ipv6" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbclient_auth.sh"), '$SERVER', '$SERVER_IPV6', '$SERVER/$USERNAME', '$PASSWORD', smbclient3, configuration])
+
for env in ["member", "s3member"]:
plantestsuite("samba3.blackbox.net_cred_change.(%s:local)" % env, "%s:local" % env, [os.path.join(samba3srcdir, "script/tests/test_net_cred_change.sh"), configuration])
@@ -338,8 +341,8 @@ for t in tests:
plansmbtorture4testsuite(t, "plugin_s4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD', 'over ncacn_np ')
plansmbtorture4testsuite(t, "plugin_s4_dc", 'ncacn_ip_tcp:$SERVER_IP -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ')
elif t == "rpc.samr.passwords.validate":
- plansmbtorture4testsuite(t, "s3dc", 'ncacn_ip_tcp:$SERVER_IP -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ')
- plansmbtorture4testsuite(t, "plugin_s4_dc", 'ncacn_ip_tcp:$SERVER_IP -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ')
+ plansmbtorture4testsuite(t, "s3dc", 'ncacn_ip_tcp:$SERVER_IP[seal] -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ')
+ plansmbtorture4testsuite(t, "plugin_s4_dc", 'ncacn_ip_tcp:$SERVER_IP[seal] -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ')
elif t == "smb2.durable-open" or t == "smb2.durable-v2-open" or t == "smb2.replay":
plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/durable -U$USERNAME%$PASSWORD')
plansmbtorture4testsuite(t, "plugin_s4_dc", '//$SERVER_IP/durable -U$USERNAME%$PASSWORD')
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
index 2ea74450732..ff7337c438c 100644
--- a/source3/smbd/negprot.c
+++ b/source3/smbd/negprot.c
@@ -544,6 +544,7 @@ void reply_negprot(struct smb_request *req)
size_t converted_size;
struct smbXsrv_connection *xconn = req->xconn;
struct smbd_server_connection *sconn = req->sconn;
+ bool signing_required = true;
START_PROFILE(SMBnegprot);
@@ -717,8 +718,9 @@ void reply_negprot(struct smb_request *req)
DEBUG( 5, ( "negprot index=%d\n", choice ) );
- if ((lp_server_signing() == SMB_SIGNING_REQUIRED)
- && (chosen_level < PROTOCOL_NT1)) {
+ /* We always have xconn->smb1.signing_state also for >= SMB2_02 */
+ signing_required = smb_signing_is_mandatory(xconn->smb1.signing_state);
+ if (signing_required && (chosen_level < PROTOCOL_NT1)) {
exit_server_cleanly("SMB signing is required and "
"client negotiated a downlevel protocol");
}
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index b2617041e52..33574f7c086 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -37,6 +37,7 @@
#include "../libcli/security/security.h"
#include "auth/gensec/gensec.h"
#include "lib/conn_tdb.h"
+#include "../libcli/smb/smb_signing.h"
/****************************************************************************
Add the standard 'Samba' signature to the end of the session setup.
@@ -598,7 +599,8 @@ void reply_sesssetup_and_X(struct smb_request *req)
struct smbd_server_connection *sconn = req->sconn;
bool doencrypt = xconn->smb1.negprot.encrypted_passwords;
bool signing_allowed = false;
- bool signing_mandatory = false;
+ bool signing_mandatory = smb_signing_is_mandatory(
+ xconn->smb1.signing_state);
START_PROFILE(SMBsesssetupX);
diff --git a/source3/smbd/smb2_negprot.c b/source3/smbd/smb2_negprot.c
index eb238d38b08..bb11f0613ad 100644
--- a/source3/smbd/smb2_negprot.c
+++ b/source3/smbd/smb2_negprot.c
@@ -24,6 +24,7 @@
#include "../libcli/smb/smb_common.h"
#include "../lib/tsocket/tsocket.h"
#include "../librpc/ndr/libndr.h"
+#include "../libcli/smb/smb_signing.h"
extern fstring remote_proto;
@@ -149,6 +150,7 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
uint32_t max_read = lp_smb2_max_read();
uint32_t max_write = lp_smb2_max_write();
NTTIME now = timeval_to_nttime(&req->request_time);
+ bool signing_required = true;
status = smbd_smb2_request_verify_sizes(req, 0x24);
if (!NT_STATUS_IS_OK(status)) {
@@ -228,7 +230,13 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
}
security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
- if (lp_server_signing() == SMB_SIGNING_REQUIRED) {
+ /*
+ * We use xconn->smb1.signing_state as that's already present
+ * and used lpcfg_server_signing_allowed() to get the correct
+ * defaults, e.g. signing_required for an ad_dc.
+ */
+ signing_required = smb_signing_is_mandatory(xconn->smb1.signing_state);
+ if (signing_required) {
security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
}
diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index e255e46ba95..8b239c9b3b0 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -186,7 +186,8 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
struct smbXsrv_connection *xconn = smb2req->xconn;
if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
- lp_server_signing() == SMB_SIGNING_REQUIRED) {
+ (xconn->smb2.server.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED))
+ {
x->global->signing_required = true;
}
diff --git a/source3/torture/test_ntlm_auth.py b/source3/torture/test_ntlm_auth.py
index d17af9b0bf9..fffeb2696b2 100755
--- a/source3/torture/test_ntlm_auth.py
+++ b/source3/torture/test_ntlm_auth.py
@@ -27,300 +27,305 @@ import sys
from optparse import OptionParser
class ReadChildError(Exception):
- pass
+ pass
class WriteChildError(Exception):
- pass
+ pass
def readLine(pipe):
- """readLine(pipe) -> str
- Read a line from the child's pipe, returns the string read.
- Throws ReadChildError if the read fails.
- """
- buf = os.read(pipe, 2047)
- newline = buf.find('\n')
- if newline == -1:
- raise ReadChildError()
- return buf[:newline]
+ """readLine(pipe) -> str
+ Read a line from the child's pipe, returns the string read.
+ Throws ReadChildError if the read fails.
+ """
+ buf = os.read(pipe, 2047)
+ newline = buf.find('\n')
+ if newline == -1:
+ raise ReadChildError()
+ return buf[:newline]
def writeLine(pipe, buf):
- """writeLine(pipe, buf) -> nul
- Write a line to the child's pipe.
- Raises WriteChildError if the write fails.
- """
- written = os.write(pipe, buf)
- if written != len(buf):
- raise WriteChildError()
- os.write(pipe, "\n")
+ """writeLine(pipe, buf) -> nul
+ Write a line to the child's pipe.
+ Raises WriteChildError if the write fails.
+ """
+ written = os.write(pipe, buf)
+ if written != len(buf):
+ raise WriteChildError()
+ os.write(pipe, "\n")
def parseCommandLine():
- """parseCommandLine() -> (opts, ntlm_auth_path)
- Parse the command line.
- Return a tuple consisting of the options and the path to ntlm_auth.
- """
- usage = "usage: %prog [options] path/to/ntlm_auth"
- parser = OptionParser(usage)
-
- parser.set_defaults(client_username="foo")
- parser.set_defaults(client_password="secret")
- parser.set_defaults(client_domain="FOO")
- parser.set_defaults(client_helper="ntlmssp-client-1")
-
- parser.set_defaults(server_username="foo")
- parser.set_defaults(server_password="secret")
- parser.set_defaults(server_domain="FOO")
- parser.set_defaults(server_helper="squid-2.5-ntlmssp")
- parser.set_defaults(config_file="/etc/samba/smb.conf")
-
- parser.add_option("--client-username", dest="client_username",\
- help="User name for the client. [default: foo]")
- parser.add_option("--client-password", dest="client_password",\
- help="Password the client will send. [default: secret]")
- parser.add_option("--client-domain", dest="client_domain",\
- help="Domain the client authenticates for. [default: FOO]")
- parser.add_option("--client-helper", dest="client_helper",\
- help="Helper mode for the ntlm_auth client. [default: ntlmssp-client-1]")
-
- parser.add_option("--target-hostname", dest="target_hostname",\
- help="Target hostname for kerberos")
- parser.add_option("--target-service", dest="target_service",\
- help="Target service for kerberos")
-
-
- parser.add_option("--server-username", dest="server_username",\
- help="User name server uses for local auth. [default: foo]")
- parser.add_option("--server-password", dest="server_password",\
- help="Password server uses for local auth. [default: secret]")
- parser.add_option("--server-domain", dest="server_domain",\
- help="Domain server uses for local auth. [default: FOO]")
- parser.add_option("--server-helper", dest="server_helper",\
- help="Helper mode for the ntlm_auth server. [default: squid-2.5-server]")
- parser.add_option("--server-use-winbindd", dest="server_use_winbindd",\
- help="Use winbindd to check the password (rather than default username/pw)", action="store_true")
- parser.add_option("--require-membership-of", dest="sid",\
- help="Require that the user is a member of this group to authenticate.")
-
-
- parser.add_option("-s", "--configfile", dest="config_file",\
- help="Path to smb.conf file. [default:/etc/samba/smb.conf")
-
- (opts, args) = parser.parse_args()
- if len(args) != 1:
- parser.error("Invalid number of arguments.")
-
- if not os.access(args[0], os.X_OK):
- parser.error("%s is not executable." % args[0])
-
- return (opts, args[0])
+ """parseCommandLine() -> (opts, ntlm_auth_path)
+ Parse the command line.
+ Return a tuple consisting of the options and the path to ntlm_auth.
+ """
+ usage = "usage: %prog [options] path/to/ntlm_auth"
+ parser = OptionParser(usage)
+
+ parser.set_defaults(client_username="foo")
+ parser.set_defaults(client_password="secret")
+ parser.set_defaults(client_domain="FOO")
+ parser.set_defaults(client_helper="ntlmssp-client-1")
+
+ parser.set_defaults(server_username="foo")
+ parser.set_defaults(server_password="secret")
+ parser.set_defaults(server_domain="FOO")
+ parser.set_defaults(server_helper="squid-2.5-ntlmssp")
+ parser.set_defaults(config_file="/etc/samba/smb.conf")
+
+ parser.add_option("--client-username", dest="client_username",\
+ help="User name for the client. [default: foo]")
+ parser.add_option("--client-password", dest="client_password",\
+ help="Password the client will send. [default: secret]")
+ parser.add_option("--client-domain", dest="client_domain",\
+ help="Domain the client authenticates for. [default: FOO]")
+ parser.add_option("--client-helper", dest="client_helper",\
+ help="Helper mode for the ntlm_auth client. [default: ntlmssp-client-1]")
+ parser.add_option("--client-use-cached-creds", dest="client_use_cached_creds",\
+ help="Use winbindd credentials cache (rather than default username/pw)", action="store_true")
+
+ parser.add_option("--target-hostname", dest="target_hostname",\
+ help="Target hostname for kerberos")
+ parser.add_option("--target-service", dest="target_service",\
+ help="Target service for kerberos")
+
+
+ parser.add_option("--server-username", dest="server_username",\
+ help="User name server uses for local auth. [default: foo]")
+ parser.add_option("--server-password", dest="server_password",\
+ help="Password server uses for local auth. [default: secret]")
+ parser.add_option("--server-domain", dest="server_domain",\
+ help="Domain server uses for local auth. [default: FOO]")
+ parser.add_option("--server-helper", dest="server_helper",\
+ help="Helper mode for the ntlm_auth server. [default: squid-2.5-server]")
+ parser.add_option("--server-use-winbindd", dest="server_use_winbindd",\
+ help="Use winbindd to check the password (rather than default username/pw)", action="store_true")
+ parser.add_option("--require-membership-of", dest="sid",\
+ help="Require that the user is a member of this group to authenticate.")
+
+
+ parser.add_option("-s", "--configfile", dest="config_file",\
+ help="Path to smb.conf file. [default:/etc/samba/smb.conf")
+
+ (opts, args) = parser.parse_args()
+ if len(args) != 1:
+ parser.error("Invalid number of arguments.")
+
+ if not os.access(args[0], os.X_OK):
+ parser.error("%s is not executable." % args[0])
+
+ return (opts, args[0])
def main():
- """main() -> int
- Run the test.
- Returns 0 if test succeeded, <>0 otherwise.
- """
- (opts, ntlm_auth_path) = parseCommandLine()
+ """main() -> int
+ Run the test.
+ Returns 0 if test succeeded, <>0 otherwise.
+ """
+ (opts, ntlm_auth_path) = parseCommandLine()
- (client_in_r, client_in_w) = os.pipe()
- (client_out_r, client_out_w) = os.pipe()
-
- client_pid = os.fork()
-
- if not client_pid:
- # We're in the client child
- os.close(0)
- os.close(1)
-
- os.dup2(client_out_r, 0)
- os.close(client_out_r)
- os.close(client_out_w)
-
- os.dup2(client_in_w, 1)
- os.close(client_in_r)
- os.close(client_in_w)
-
- client_args = []
- client_args.append("--helper-protocol=%s" % opts.client_helper)
- client_args.append("--username=%s" % opts.client_username)
- client_args.append("--password=%s" % opts.client_password)
- client_args.append("--domain=%s" % opts.client_domain)
- client_args.append("--configfile=%s" % opts.config_file)
- if opts.target_service:
- client_args.append("--target-service=%s" % opts.target_service)
- if opts.target_hostname:
- client_args.append("--target-hostname=%s" % opts.target_hostname)
-
- os.execv(ntlm_auth_path, client_args)
-
- client_in = client_in_r
- os.close(client_in_w)
-
- client_out = client_out_w
- os.close(client_out_r)
-
- (server_in_r, server_in_w) = os.pipe()
- (server_out_r, server_out_w) = os.pipe()
-
- server_pid = os.fork()
-
- if not server_pid:
- # We're in the server child
- os.close(0)
- os.close(1)
-
- os.dup2(server_out_r, 0)
- os.close(server_out_r)
- os.close(server_out_w)
-
- os.dup2(server_in_w, 1)
- os.close(server_in_r)
- os.close(server_in_w)
-
- server_args = []
- server_args.append("--helper-protocol=%s" % opts.server_helper)
- if not opts.server_use_winbindd:
- server_args.append("--username=%s" % opts.server_username)
- server_args.append("--password=%s" % opts.server_password)
- server_args.append("--domain=%s" % opts.server_domain)
- if opts.sid:
- raise Exception("Server must be using winbindd for require-membership-of.")
- else:
- if opts.sid:
- server_args.append("--require-membership-of=%s" % opts.sid)
-
- server_args.append("--configfile=%s" % opts.config_file)
-
- os.execv(ntlm_auth_path, server_args)
-
- server_in = server_in_r
- os.close(server_in_w)
-
- server_out = server_out_w
- os.close(server_out_r)
-
- if opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "squid-2.5-ntlmssp":
-
- # We're in the parent
- writeLine(client_out, "YR")
- buf = readLine(client_in)
-
- if buf.count("YR ", 0, 3) != 1:
- sys.exit(1)
-
- writeLine(server_out, buf)
- buf = readLine(server_in)
-
- if buf.count("TT ", 0, 3) != 1:
- sys.exit(2)
-
- writeLine(client_out, buf)
- buf = readLine(client_in)
-
- if buf.count("AF ", 0, 3) != 1:
- sys.exit(3)
-
- # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
- buf = buf.replace("AF", "KK", 1)
-
- writeLine(server_out, buf)
- buf = readLine(server_in)
-
- if buf.count("AF ", 0, 3) != 1:
- sys.exit(4)
-
-
- elif opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "gss-spnego":
- # We're in the parent
- writeLine(client_out, "YR")
- buf = readLine(client_in)
-
- if buf.count("YR ", 0, 3) != 1:
- sys.exit(1)
-
- writeLine(server_out, buf)
- buf = readLine(server_in)
-
- if buf.count("TT ", 0, 3) != 1:
- sys.exit(2)
-
- writeLine(client_out, buf)
- buf = readLine(client_in)
+ (client_in_r, client_in_w) = os.pipe()
+ (client_out_r, client_out_w) = os.pipe()
- if buf.count("AF ", 0, 3) != 1:
- sys.exit(3)
+ client_pid = os.fork()
- # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
- buf = buf.replace("AF", "KK", 1)
-
- writeLine(server_out, buf)
- buf = readLine(server_in)
-
- if buf.count("AF * ", 0, 5) != 1:
- sys.exit(4)
+ if not client_pid:
+ # We're in the client child
+ os.close(0)
+ os.close(1)
+ os.dup2(client_out_r, 0)
+ os.close(client_out_r)
+ os.close(client_out_w)
- elif opts.client_helper == "gss-spnego-client" and opts.server_helper == "gss-spnego":
- # We're in the parent
- writeLine(server_out, "YR")
- buf = readLine(server_in)
-
- while True:
- if buf.count("AF ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1:
- sys.exit(1)
-
- writeLine(client_out, buf)
- buf = readLine(client_in)
-
- if buf.count("AF", 0, 2) == 1:
- break
-
- if buf.count("AF ", 0, 5) != 1 and buf.count("KK ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1:
- sys.exit(2)
-
- writeLine(server_out, buf)
- buf = readLine(server_in)
-
- if buf.count("AF * ", 0, 5) == 1:
- break
-
- else:
- sys.exit(5)
+ os.dup2(client_in_w, 1)
+ os.close(client_in_r)
+ os.close(client_in_w)
- if opts.client_helper == "ntlmssp-client-1":
- writeLine(client_out, "GK")
- buf = readLine(client_in)
+ client_args = []
+ client_args.append("--helper-protocol=%s" % opts.client_helper)
+ client_args.append("--username=%s" % opts.client_username)
+ if opts.client_use_cached_creds:
+ client_args.append("--use-cached-creds")
+ else:
+ client_args.append("--password=%s" % opts.client_password)
+ client_args.append("--domain=%s" % opts.client_domain)
+ client_args.append("--configfile=%s" % opts.config_file)
+ if opts.target_service:
+ client_args.append("--target-service=%s" % opts.target_service)
+ if opts.target_hostname:
+ client_args.append("--target-hostname=%s" % opts.target_hostname)
- if buf.count("GK ", 0, 3) != 1:
- sys.exit(4)
-
- writeLine(client_out, "GF")
- buf = readLine(client_in)
-
- if buf.count("GF ", 0, 3) != 1:
- sys.exit(4)
-
- if opts.server_helper == "squid-2.5-ntlmssp":
- writeLine(server_out, "GK")
- buf = readLine(server_in)
-
- if buf.count("GK ", 0, 3) != 1:
- sys.exit(4)
+ os.execv(ntlm_auth_path, client_args)
- writeLine(server_out, "GF")
- buf = readLine(server_in)
-
- if buf.count("GF ", 0, 3) != 1:
- sys.exit(4)
-
- os.close(server_in)
- os.close(server_out)
- os.close(client_in)
- os.close(client_out)
- os.waitpid(server_pid, 0)
- os.waitpid(client_pid, 0)
- sys.exit(0)
+ client_in = client_in_r
+ os.close(client_in_w)
+
+ client_out = client_out_w
+ os.close(client_out_r)
+
+ (server_in_r, server_in_w) = os.pipe()
+ (server_out_r, server_out_w) = os.pipe()
+
+ server_pid = os.fork()
+
+ if not server_pid:
+ # We're in the server child
+ os.close(0)
+ os.close(1)
+
+ os.dup2(server_out_r, 0)
+ os.close(server_out_r)
+ os.close(server_out_w)
+
+ os.dup2(server_in_w, 1)
+ os.close(server_in_r)
+ os.close(server_in_w)
+
+ server_args = []
+ server_args.append("--helper-protocol=%s" % opts.server_helper)
+ if not opts.server_use_winbindd:
+ server_args.append("--username=%s" % opts.server_username)
+ server_args.append("--password=%s" % opts.server_password)
+ server_args.append("--domain=%s" % opts.server_domain)
+ if opts.sid:
+ raise Exception("Server must be using winbindd for require-membership-of.")
+ else:
+ if opts.sid:
+ server_args.append("--require-membership-of=%s" % opts.sid)
+
+ server_args.append("--configfile=%s" % opts.config_file)
+
+ os.execv(ntlm_auth_path, server_args)
+
+ server_in = server_in_r
+ os.close(server_in_w)
+
+ server_out = server_out_w
+ os.close(server_out_r)
+
+ if opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "squid-2.5-ntlmssp":
+
+ # We're in the parent
+ writeLine(client_out, "YR")
+ buf = readLine(client_in)
+
+ if buf.count("YR ", 0, 3) != 1:
+ sys.exit(1)
+
+ writeLine(server_out, buf)
+ buf = readLine(server_in)
+
+ if buf.count("TT ", 0, 3) != 1:
+ sys.exit(2)
+
+ writeLine(client_out, buf)
+ buf = readLine(client_in)
+
+ if buf.count("AF ", 0, 3) != 1:
+ sys.exit(3)
+
+ # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
+ buf = buf.replace("AF", "KK", 1)
+
+ writeLine(server_out, buf)
+ buf = readLine(server_in)
+
+ if buf.count("AF ", 0, 3) != 1:
+ sys.exit(4)
+
+
+ elif opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "gss-spnego":
+ # We're in the parent
+ writeLine(client_out, "YR")
+ buf = readLine(client_in)
+
+ if buf.count("YR ", 0, 3) != 1:
+ sys.exit(1)
+
+ writeLine(server_out, buf)
+ buf = readLine(server_in)
+
+ if buf.count("TT ", 0, 3) != 1:
+ sys.exit(2)
+
+ writeLine(client_out, buf)
+ buf = readLine(client_in)
+
+ if buf.count("AF ", 0, 3) != 1:
+ sys.exit(3)
+
+ # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
+ buf = buf.replace("AF", "KK", 1)
+
+ writeLine(server_out, buf)
+ buf = readLine(server_in)
+
+ if buf.count("AF * ", 0, 5) != 1:
+ sys.exit(4)
+
+
+ elif opts.client_helper == "gss-spnego-client" and opts.server_helper == "gss-spnego":
+ # We're in the parent
+ writeLine(server_out, "YR")
+ buf = readLine(server_in)
+
+ while True:
+ if buf.count("AF ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1:
+ sys.exit(1)
+
+ writeLine(client_out, buf)
+ buf = readLine(client_in)
+
+ if buf.count("AF", 0, 2) == 1:
+ break
+
+ if buf.count("AF ", 0, 5) != 1 and buf.count("KK ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1:
+ sys.exit(2)
+
+ writeLine(server_out, buf)
+ buf = readLine(server_in)
+
+ if buf.count("AF * ", 0, 5) == 1:
+ break
+
+ else:
+ sys.exit(5)
+
+ if opts.client_helper == "ntlmssp-client-1":
+ writeLine(client_out, "GK")
+ buf = readLine(client_in)
+
+ if buf.count("GK ", 0, 3) != 1:
+ sys.exit(4)
+
+ writeLine(client_out, "GF")
+ buf = readLine(client_in)
+
+ if buf.count("GF ", 0, 3) != 1:
+ sys.exit(4)
+
+ if opts.server_helper == "squid-2.5-ntlmssp":
+ writeLine(server_out, "GK")
+ buf = readLine(server_in)
+
+ if buf.count("GK ", 0, 3) != 1:
+ sys.exit(4)
+
+ writeLine(server_out, "GF")
+ buf = readLine(server_in)
+
+ if buf.count("GF ", 0, 3) != 1:
+ sys.exit(4)
+
+ os.close(server_in)
+ os.close(server_out)
+ os.close(client_in)
+ os.close(client_out)
+ os.waitpid(server_pid, 0)
+ os.waitpid(client_pid, 0)
+ sys.exit(0)
if __name__ == "__main__":
- main()
+ main()
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
index 5f18bf4401a..3d7d8a15dce 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -1907,7 +1907,7 @@ static int net_ads_printer_publish(struct net_context *c, int argc, const char *
c->opt_user_name, c->opt_workgroup,
c->opt_password ? c->opt_password : "",
CLI_FULL_CONNECTION_USE_KERBEROS,
- SMB_SIGNING_DEFAULT);
+ SMB_SIGNING_IPC_DEFAULT);
if (NT_STATUS_IS_ERR(nt_status)) {
d_fprintf(stderr, _("Unable to open a connection to %s to "
diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c
index cd17b2cf1a2..8f65a73b396 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -7395,7 +7395,7 @@ bool net_rpc_check(struct net_context *c, unsigned flags)
return false;
status = cli_connect_nb(server_name, &server_ss, 0, 0x20,
- lp_netbios_name(), SMB_SIGNING_DEFAULT,
+ lp_netbios_name(), SMB_SIGNING_IPC_DEFAULT,
0, &cli);
if (!NT_STATUS_IS_OK(status)) {
return false;
diff --git a/source3/utils/net_util.c b/source3/utils/net_util.c
index 13a0ef12d86..de929ffd75d 100644
--- a/source3/utils/net_util.c
+++ b/source3/utils/net_util.c
@@ -126,7 +126,7 @@ NTSTATUS connect_to_service(struct net_context *c,
service_name, service_type,
c->opt_user_name, c->opt_workgroup,
c->opt_password, flags,
- SMB_SIGNING_DEFAULT);
+ SMB_SIGNING_IPC_DEFAULT);
if (!NT_STATUS_IS_OK(nt_status)) {
d_fprintf(stderr, _("Could not connect to server %s\n"),
server_name);
diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c
index 3906f3829df..d01c522dffd 100644
--- a/source3/utils/ntlm_auth.c
+++ b/source3/utils/ntlm_auth.c
@@ -29,7 +29,6 @@
#include "popt_common.h"
#include "utils/ntlm_auth.h"
#include "../libcli/auth/libcli_auth.h"
-#include "../libcli/auth/spnego.h"
#include "auth/ntlmssp/ntlmssp.h"
#include "auth/gensec/gensec.h"
#include "auth/gensec/gensec_internal.h"
@@ -38,7 +37,6 @@
#include "smb_krb5.h"
#include "lib/util/tiniparser.h"
#include "../lib/crypto/arcfour.h"
-#include "libads/kerberos_proto.h"
#include "nsswitch/winbind_client.h"
#include "librpc/gen_ndr/krb5pac.h"
#include "../lib/util/asn1.h"
@@ -100,6 +98,10 @@ typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
struct ntlm_auth_state *state, char *buf,
int length, void **private2);
+static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
+ struct loadparm_context *lp_ctx,
+ char *buf, int length, void **private1);
+
static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
struct loadparm_context *lp_ctx,
struct ntlm_auth_state *state,
@@ -225,13 +227,25 @@ static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mod
static const char *get_password(struct cli_credentials *credentials)
{
+ TALLOC_CTX *frame = talloc_stackframe();
char *password = NULL;
+ struct ntlm_auth_state *state;
+
+ state = talloc_zero(frame, struct ntlm_auth_state);
+ if (state == NULL) {
+ DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
+ x_fprintf(x_stderr, "ERR\n");
+ exit(1);
+ }
+
+ state->mem_ctx = state;
/* Ask for a password */
x_fprintf(x_stdout, "PW\n");
- manage_squid_request(NUM_HELPER_MODES /* bogus */, NULL, NULL, manage_gensec_get_pw_request, (void **)&password);
+ manage_squid_request(NUM_HELPER_MODES /* bogus */, NULL, state, manage_gensec_get_pw_request, (void **)&password);
talloc_steal(credentials, password);
+ TALLOC_FREE(frame);
return password;
}
@@ -254,6 +268,10 @@ static void gensec_want_feature_list(struct gensec_security *state, char* featur
DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
gensec_want_feature(state, GENSEC_FEATURE_SEAL);
}
+ if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list, true)) {
+ DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
+ gensec_want_feature(state, GENSEC_FEATURE_NTLM_CCACHE);
+ }
}
static char winbind_separator(void)
@@ -953,57 +971,75 @@ static NTSTATUS local_pw_check(struct auth4_context *auth4_context,
return nt_status;
}
-static NTSTATUS ntlm_auth_start_ntlmssp_client(struct ntlmssp_state **client_ntlmssp_state)
+static NTSTATUS ntlm_auth_prepare_gensec_client(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct gensec_security **gensec_security_out)
{
- NTSTATUS status;
- if ( (opt_username == NULL) || (opt_domain == NULL) ) {
- status = NT_STATUS_UNSUCCESSFUL;
- DEBUG(1, ("Need username and domain for NTLMSSP\n"));
- return NT_STATUS_INVALID_PARAMETER;
- }
+ struct gensec_security *gensec_security = NULL;
+ NTSTATUS nt_status;
+ TALLOC_CTX *tmp_ctx;
+ const struct gensec_security_ops **backends = NULL;
+ struct gensec_settings *gensec_settings = NULL;
+ size_t idx = 0;
- status = ntlmssp_client_start(NULL,
- lp_netbios_name(),
- lp_workgroup(),
- lp_client_ntlmv2_auth(),
- client_ntlmssp_state);
+ tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Could not start NTLMSSP client: %s\n",
- nt_errstr(status)));
- TALLOC_FREE(*client_ntlmssp_state);
- return status;
+ gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
+ if (gensec_settings == NULL) {
+ DEBUG(10, ("lpcfg_gensec_settings failed\n"));
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
}
- status = ntlmssp_set_username(*client_ntlmssp_state, opt_username);
-
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Could not set username: %s\n",
- nt_errstr(status)));
- TALLOC_FREE(*client_ntlmssp_state);
- return status;
+ backends = talloc_zero_array(gensec_settings,
+ const struct gensec_security_ops *, 4);
+ if (backends == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
}
+ gensec_settings->backends = backends;
+
+ gensec_init();
+
+ /* These need to be in priority order, krb5 before NTLMSSP */
+#if defined(HAVE_KRB5)
+ backends[idx++] = &gensec_gse_krb5_security_ops;
+#endif
- status = ntlmssp_set_domain(*client_ntlmssp_state, opt_domain);
+ backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Could not set domain: %s\n",
- nt_errstr(status)));
- TALLOC_FREE(*client_ntlmssp_state);
- return status;
+ backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
+
+ nt_status = gensec_client_start(NULL, &gensec_security,
+ gensec_settings);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ TALLOC_FREE(tmp_ctx);
+ return nt_status;
}
- if (opt_password) {
- status = ntlmssp_set_password(*client_ntlmssp_state, opt_password);
+ talloc_unlink(tmp_ctx, gensec_settings);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Could not set password: %s\n",
- nt_errstr(status)));
- TALLOC_FREE(*client_ntlmssp_state);
- return status;
+ if (opt_target_service != NULL) {
+ nt_status = gensec_set_target_service(gensec_security,
+ opt_target_service);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ TALLOC_FREE(tmp_ctx);
+ return nt_status;
+ }
+ }
+
+ if (opt_target_hostname != NULL) {
+ nt_status = gensec_set_target_hostname(gensec_security,
+ opt_target_hostname);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ TALLOC_FREE(tmp_ctx);
+ return nt_status;
}
}
+ *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
+ TALLOC_FREE(tmp_ctx);
return NT_STATUS_OK;
}
@@ -1027,9 +1063,9 @@ static struct auth4_context *make_auth4_context_ntlm_auth(TALLOC_CTX *mem_ctx, b
return auth4_context;
}
-static NTSTATUS ntlm_auth_start_ntlmssp_server(TALLOC_CTX *mem_ctx,
- struct loadparm_context *lp_ctx,
- struct gensec_security **gensec_security_out)
+static NTSTATUS ntlm_auth_prepare_gensec_server(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct gensec_security **gensec_security_out)
{
struct gensec_security *gensec_security;
NTSTATUS nt_status;
@@ -1135,260 +1171,18 @@ static NTSTATUS ntlm_auth_start_ntlmssp_server(TALLOC_CTX *mem_ctx,
talloc_unlink(tmp_ctx, gensec_settings);
talloc_unlink(tmp_ctx, auth4_context);
- nt_status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_NTLMSSP);
- if (!NT_STATUS_IS_OK(nt_status)) {
- TALLOC_FREE(tmp_ctx);
- return nt_status;
- }
-
*gensec_security_out = talloc_steal(mem_ctx, gensec_security);
TALLOC_FREE(tmp_ctx);
return NT_STATUS_OK;
}
-/*******************************************************************
- Used by firefox to drive NTLM auth to IIS servers.
-*******************************************************************/
-
-static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_msg,
- DATA_BLOB *reply)
-{
- struct winbindd_request wb_request;
- struct winbindd_response wb_response;
- int ctrl = 0;
- NSS_STATUS result;
-
- /* get winbindd to do the ntlmssp step on our behalf */
- ZERO_STRUCT(wb_request);
- ZERO_STRUCT(wb_response);
-
- /*
- * This is tricky here. If we set krb5_auth in pam_winbind.conf
- * creds for users in trusted domain will be stored the winbindd
- * child of the trusted domain. If we ask the primary domain for
- * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
- * domain's child for ccache_ntlm_auth. that is to say, we have to
- * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags.
- */
- ctrl = get_pam_winbind_config();
-
- if (ctrl & WINBIND_KRB5_AUTH) {
- wb_request.flags |= WBFLAG_PAM_CONTACT_TRUSTDOM;
- }
-
- fstr_sprintf(wb_request.data.ccache_ntlm_auth.user,
- "%s%c%s", opt_domain, winbind_separator(), opt_username);
- wb_request.data.ccache_ntlm_auth.uid = geteuid();
- wb_request.data.ccache_ntlm_auth.initial_blob_len = initial_msg.length;
- wb_request.data.ccache_ntlm_auth.challenge_blob_len = challenge_msg.length;
- wb_request.extra_len = initial_msg.length + challenge_msg.length;
-
- if (wb_request.extra_len > 0) {
- wb_request.extra_data.data = SMB_MALLOC_ARRAY(char, wb_request.extra_len);
- if (wb_request.extra_data.data == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- memcpy(wb_request.extra_data.data, initial_msg.data, initial_msg.length);
- memcpy(wb_request.extra_data.data + initial_msg.length,
- challenge_msg.data, challenge_msg.length);
- }
-
- result = winbindd_request_response(NULL, WINBINDD_CCACHE_NTLMAUTH, &wb_request, &wb_response);
- SAFE_FREE(wb_request.extra_data.data);
-
- if (result != NSS_STATUS_SUCCESS) {
- winbindd_free_response(&wb_response);
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- if (reply) {
- *reply = data_blob(wb_response.extra_data.data,
- wb_response.data.ccache_ntlm_auth.auth_blob_len);
- if (wb_response.data.ccache_ntlm_auth.auth_blob_len > 0 &&
- reply->data == NULL) {
- winbindd_free_response(&wb_response);
- return NT_STATUS_NO_MEMORY;
- }
- }
-
- winbindd_free_response(&wb_response);
- return NT_STATUS_MORE_PROCESSING_REQUIRED;
-}
-
static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
struct loadparm_context *lp_ctx,
struct ntlm_auth_state *state,
char *buf, int length, void **private2)
{
- DATA_BLOB request, reply;
- NTSTATUS nt_status;
-
- if (!opt_username || !*opt_username) {
- x_fprintf(x_stderr, "username must be specified!\n\n");
- exit(1);
- }
-
- if (strlen(buf) < 2) {
- DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
- x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
- return;
- }
-
- if (strlen(buf) > 3) {
- if(strncmp(buf, "SF ", 3) == 0) {
- DEBUG(10, ("Looking for flags to negotiate\n"));
- talloc_free(state->want_feature_list);
- state->want_feature_list = talloc_strdup(state->mem_ctx,
- buf+3);
- x_fprintf(x_stdout, "OK\n");
- return;
- }
- request = base64_decode_data_blob(buf + 3);
- } else {
- request = data_blob_null;
- }
-
- if (strncmp(buf, "PW ", 3) == 0) {
- /* We asked for a password and obviously got it :-) */
-
- opt_password = SMB_STRNDUP((const char *)request.data,
- request.length);
-
- if (opt_password == NULL) {
- DEBUG(1, ("Out of memory\n"));
- x_fprintf(x_stdout, "BH Out of memory\n");
- data_blob_free(&request);
- return;
- }
-
- x_fprintf(x_stdout, "OK\n");
- data_blob_free(&request);
- return;
- }
-
- if (!state->ntlmssp_state && use_cached_creds) {
- /* check whether cached credentials are usable. */
- DATA_BLOB empty_blob = data_blob_null;
-
- nt_status = do_ccache_ntlm_auth(empty_blob, empty_blob, NULL);
- if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- /* failed to use cached creds */
- use_cached_creds = False;
- }
- }
-
- if (opt_password == NULL && !use_cached_creds) {
- /* Request a password from the calling process. After
- sending it, the calling process should retry asking for the
- negotiate. */
-
- DEBUG(10, ("Requesting password\n"));
- x_fprintf(x_stdout, "PW\n");
- return;
- }
-
- if (strncmp(buf, "YR", 2) == 0) {
- TALLOC_FREE(state->ntlmssp_state);
- state->cli_state = CLIENT_INITIAL;
- } else if (strncmp(buf, "TT", 2) == 0) {
- /* No special preprocessing required */
- } else if (strncmp(buf, "GF", 2) == 0) {
- DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
-
- if(state->cli_state == CLIENT_FINISHED) {
- x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags);
- }
- else {
- x_fprintf(x_stdout, "BH\n");
- }
-
- data_blob_free(&request);
- return;
- } else if (strncmp(buf, "GK", 2) == 0 ) {
- DEBUG(10, ("Requested session key\n"));
-
- if(state->cli_state == CLIENT_FINISHED) {
- char *key64 = base64_encode_data_blob(state->mem_ctx,
- state->session_key);
- x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
- TALLOC_FREE(key64);
- }
- else {
- x_fprintf(x_stdout, "BH\n");
- }
-
- data_blob_free(&request);
- return;
- } else {
- DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
- x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
- return;
- }
-
- if (!state->ntlmssp_state) {
- nt_status = ntlm_auth_start_ntlmssp_client(
- &state->ntlmssp_state);
- if (!NT_STATUS_IS_OK(nt_status)) {
- x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
- return;
- }
- ntlmssp_want_feature_list(state->ntlmssp_state,
- state->want_feature_list);
- state->initial_message = data_blob_null;
- }
-
- DEBUG(10, ("got NTLMSSP packet:\n"));
- dump_data(10, request.data, request.length);
-
- if (use_cached_creds && !opt_password &&
- (state->cli_state == CLIENT_RESPONSE)) {
- nt_status = do_ccache_ntlm_auth(state->initial_message, request,
- &reply);
- } else {
- nt_status = ntlmssp_update(state->ntlmssp_state, request,
- &reply);
- }
-
- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
- reply);
- if (state->cli_state == CLIENT_INITIAL) {
- x_fprintf(x_stdout, "YR %s\n", reply_base64);
- state->initial_message = reply;
- state->cli_state = CLIENT_RESPONSE;
- } else {
- x_fprintf(x_stdout, "KK %s\n", reply_base64);
- data_blob_free(&reply);
- }
- TALLOC_FREE(reply_base64);
- DEBUG(10, ("NTLMSSP challenge\n"));
- } else if (NT_STATUS_IS_OK(nt_status)) {
- char *reply_base64 = base64_encode_data_blob(talloc_tos(),
- reply);
- x_fprintf(x_stdout, "AF %s\n", reply_base64);
- TALLOC_FREE(reply_base64);
-
- if(state->have_session_key)
- data_blob_free(&state->session_key);
-
- state->session_key = data_blob(
- state->ntlmssp_state->session_key.data,
- state->ntlmssp_state->session_key.length);
- state->neg_flags = state->ntlmssp_state->neg_flags;
- state->have_session_key = true;
-
- DEBUG(10, ("NTLMSSP OK!\n"));
- state->cli_state = CLIENT_FINISHED;
- TALLOC_FREE(state->ntlmssp_state);
- } else {
- x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
- DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
- state->cli_state = CLIENT_ERROR;
- TALLOC_FREE(state->ntlmssp_state);
- }
-
- data_blob_free(&request);
+ manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
+ return;
}
static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
@@ -1507,11 +1301,42 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
if (!(state->gensec_state)) {
switch (stdio_helper_mode) {
case GSS_SPNEGO_CLIENT:
+ /*
+ * cached credentials are only supported by
+ * NTLMSSP_CLIENT_1 for now.
+ */
+ use_cached_creds = false;
+ /* fall through */
case NTLMSSP_CLIENT_1:
/* setup the client side */
- nt_status = gensec_client_start(NULL, &state->gensec_state,
- lpcfg_gensec_settings(NULL, lp_ctx));
+ if (state->set_password != NULL) {
+ use_cached_creds = false;
+ }
+
+ if (use_cached_creds) {
+ struct wbcCredentialCacheParams params;
+ struct wbcCredentialCacheInfo *info = NULL;
+ struct wbcAuthErrorInfo *error = NULL;
+ wbcErr wbc_status;
+
+ params.account_name = opt_username;
+ params.domain_name = opt_domain;
+ params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
+ params.num_blobs = 0;
+ params.blobs = NULL;
+
+ wbc_status = wbcCredentialCache(&params, &info,
+ &error);
+ wbcFreeMemory(error);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ use_cached_creds = false;
+ }
+ wbcFreeMemory(info);
+ }
+
+ nt_status = ntlm_auth_prepare_gensec_client(state, lp_ctx,
+ &state->gensec_state);
if (!NT_STATUS_IS_OK(nt_status)) {
x_fprintf(x_stdout, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status));
talloc_free(mem_ctx);
@@ -1526,7 +1351,10 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
if (opt_domain) {
cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED);
}
- if (state->set_password) {
+ if (use_cached_creds) {
+ gensec_want_feature(state->gensec_state,
+ GENSEC_FEATURE_NTLM_CCACHE);
+ } else if (state->set_password) {
cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED);
} else {
cli_credentials_set_password_callback(creds, get_password);
@@ -1541,8 +1369,8 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
case GSS_SPNEGO_SERVER:
case SQUID_2_5_NTLMSSP:
{
- nt_status = ntlm_auth_start_ntlmssp_server(state, lp_ctx,
- &state->gensec_state);
+ nt_status = ntlm_auth_prepare_gensec_server(state, lp_ctx,
+ &state->gensec_state);
if (!NT_STATUS_IS_OK(nt_status)) {
x_fprintf(x_stdout, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status));
talloc_free(mem_ctx);
@@ -1621,12 +1449,17 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
return;
}
- if (stdio_helper_mode == SQUID_2_5_NTLMSSP && strncmp(buf, "GF", 2) == 0) {
+ if (strncmp(buf, "GF", 2) == 0) {
uint32_t neg_flags;
+ DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
+
neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state);
+ if (neg_flags == 0) {
+ x_fprintf(x_stdout, "BH\n");
+ return;
+ }
- DEBUG(10, ("Requested negotiated feature flags\n"));
x_fprintf(x_stdout, "GF 0x%08x\n", neg_flags);
return;
}
@@ -1730,408 +1563,12 @@ static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mod
return;
}
-static struct ntlmssp_state *client_ntlmssp_state = NULL;
-
-static bool manage_client_ntlmssp_init(struct spnego_data spnego)
-{
- NTSTATUS status;
- DATA_BLOB null_blob = data_blob_null;
- DATA_BLOB to_server;
- char *to_server_base64;
- const char *my_mechs[] = {OID_NTLMSSP, NULL};
- TALLOC_CTX *ctx = talloc_tos();
-
- DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
-
- if (client_ntlmssp_state != NULL) {
- DEBUG(1, ("Request for initial SPNEGO request where "
- "we already have a state\n"));
- return False;
- }
-
- if (!client_ntlmssp_state) {
- if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state))) {
- x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
- return False;
- }
- }
-
-
- if (opt_password == NULL) {
-
- /* Request a password from the calling process. After
- sending it, the calling process should retry with
- the negTokenInit. */
-
- DEBUG(10, ("Requesting password\n"));
- x_fprintf(x_stdout, "PW\n");
- return True;
- }
-
- spnego.type = SPNEGO_NEG_TOKEN_INIT;
- spnego.negTokenInit.mechTypes = my_mechs;
- spnego.negTokenInit.reqFlags = data_blob_null;
- spnego.negTokenInit.reqFlagsPadding = 0;
- spnego.negTokenInit.mechListMIC = null_blob;
-
- status = ntlmssp_update(client_ntlmssp_state, null_blob,
- &spnego.negTokenInit.mechToken);
-
- if ( !(NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
- NT_STATUS_IS_OK(status)) ) {
- DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
- nt_errstr(status)));
- TALLOC_FREE(client_ntlmssp_state);
- return False;
- }
-
- spnego_write_data(ctx, &to_server, &spnego);
- data_blob_free(&spnego.negTokenInit.mechToken);
-
- to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
- data_blob_free(&to_server);
- x_fprintf(x_stdout, "KK %s\n", to_server_base64);
- TALLOC_FREE(to_server_base64);
- return True;
-}
-
-static void manage_client_ntlmssp_targ(struct spnego_data spnego)
-{
- NTSTATUS status;
- DATA_BLOB null_blob = data_blob_null;
- DATA_BLOB request;
- DATA_BLOB to_server;
- char *to_server_base64;
- TALLOC_CTX *ctx = talloc_tos();
-
- DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
-
- if (client_ntlmssp_state == NULL) {
- DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
- x_fprintf(x_stdout, "BH Got NTLMSSP tArg without a client state\n");
- return;
- }
-
- if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
- x_fprintf(x_stdout, "NA\n");
- TALLOC_FREE(client_ntlmssp_state);
- return;
- }
-
- if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
- x_fprintf(x_stdout, "AF\n");
- TALLOC_FREE(client_ntlmssp_state);
- return;
- }
-
- status = ntlmssp_update(client_ntlmssp_state,
- spnego.negTokenTarg.responseToken,
- &request);
-
- if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED or OK from "
- "ntlmssp_client_update, got: %s\n",
- nt_errstr(status)));
- x_fprintf(x_stdout, "BH Expected MORE_PROCESSING_REQUIRED from "
- "ntlmssp_client_update\n");
- data_blob_free(&request);
- TALLOC_FREE(client_ntlmssp_state);
- return;
- }
-
- spnego.type = SPNEGO_NEG_TOKEN_TARG;
- spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
- spnego.negTokenTarg.supportedMech = (const char *)OID_NTLMSSP;
- spnego.negTokenTarg.responseToken = request;
- spnego.negTokenTarg.mechListMIC = null_blob;
-
- spnego_write_data(ctx, &to_server, &spnego);
- data_blob_free(&request);
-
- to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
- data_blob_free(&to_server);
- x_fprintf(x_stdout, "KK %s\n", to_server_base64);
- TALLOC_FREE(to_server_base64);
- return;
-}
-
-#ifdef HAVE_KRB5
-
-static bool manage_client_krb5_init(struct spnego_data spnego)
-{
- char *principal;
- DATA_BLOB tkt, tkt_wrapped, to_server;
- DATA_BLOB session_key_krb5 = data_blob_null;
- struct spnego_data reply;
- char *reply_base64;
- int retval;
-
- const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL};
- ssize_t len;
- TALLOC_CTX *ctx = talloc_tos();
-
- principal = spnego.negTokenInit.targetPrincipal;
-
- /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
- */
- if (!lp_client_use_spnego_principal() || strequal(principal, ADS_IGNORE_PRINCIPAL)) {
- principal = NULL;
- }
-
- if (principal == NULL &&
- opt_target_service && opt_target_hostname && !is_ipaddress(opt_target_hostname)) {
- DEBUG(3,("manage_client_krb5_init: using target "
- "hostname not SPNEGO principal\n"));
-
- principal = kerberos_get_principal_from_service_hostname(talloc_tos(),
- opt_target_service,
- opt_target_hostname,
- lp_realm());
-
- if (!principal) {
- return false;
- }
-
- DEBUG(3,("manage_client_krb5_init: guessed "
- "server principal=%s\n",
- principal ? principal : "<null>"));
- }
-
- if (principal == NULL) {
- DEBUG(3,("manage_client_krb5_init: could not guess server principal\n"));
- return false;
- }
-
- retval = cli_krb5_get_ticket(ctx, principal, 0,
- &tkt, &session_key_krb5,
- 0, NULL, NULL, NULL);
- if (retval) {
- char *user = NULL;
-
- /* Let's try to first get the TGT, for that we need a
- password. */
-
- if (opt_password == NULL) {
- DEBUG(10, ("Requesting password\n"));
- x_fprintf(x_stdout, "PW\n");
- return True;
- }
-
- user = talloc_asprintf(talloc_tos(), "%s@%s", opt_username, opt_domain);
- if (!user) {
- return false;
- }
-
- if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) {
- DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
- return False;
- }
-
- retval = cli_krb5_get_ticket(ctx, principal, 0,
- &tkt, &session_key_krb5,
- 0, NULL, NULL, NULL);
- if (retval) {
- DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));
- return False;
- }
-
- }
-
- /* wrap that up in a nice GSS-API wrapping */
- tkt_wrapped = spnego_gen_krb5_wrap(ctx, tkt, TOK_ID_KRB_AP_REQ);
-
- data_blob_free(&session_key_krb5);
-
- ZERO_STRUCT(reply);
-
- reply.type = SPNEGO_NEG_TOKEN_INIT;
- reply.negTokenInit.mechTypes = my_mechs;
- reply.negTokenInit.reqFlags = data_blob_null;
- reply.negTokenInit.reqFlagsPadding = 0;
- reply.negTokenInit.mechToken = tkt_wrapped;
- reply.negTokenInit.mechListMIC = data_blob_null;
-
- len = spnego_write_data(ctx, &to_server, &reply);
- data_blob_free(&tkt);
-
- if (len == -1) {
- DEBUG(1, ("Could not write SPNEGO data blob\n"));
- return False;
- }
-
- reply_base64 = base64_encode_data_blob(talloc_tos(), to_server);
- x_fprintf(x_stdout, "KK %s *\n", reply_base64);
-
- TALLOC_FREE(reply_base64);
- data_blob_free(&to_server);
- DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
- return True;
-}
-
-static void manage_client_krb5_targ(struct spnego_data spnego)
-{
- switch (spnego.negTokenTarg.negResult) {
- case SPNEGO_ACCEPT_INCOMPLETE:
- DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
- x_fprintf(x_stdout, "BH Got a Kerberos negTokenTarg with "
- "ACCEPT_INCOMPLETE\n");
- break;
- case SPNEGO_ACCEPT_COMPLETED:
- DEBUG(10, ("Accept completed\n"));
- x_fprintf(x_stdout, "AF\n");
- break;
- case SPNEGO_REJECT:
- DEBUG(10, ("Rejected\n"));
- x_fprintf(x_stdout, "NA\n");
- break;
- default:
- DEBUG(1, ("Got an invalid negTokenTarg\n"));
- x_fprintf(x_stdout, "AF\n");
- }
-}
-
-#endif
-
static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
struct loadparm_context *lp_ctx,
struct ntlm_auth_state *state,
char *buf, int length, void **private2)
{
- DATA_BLOB request;
- struct spnego_data spnego;
- ssize_t len;
- TALLOC_CTX *ctx = talloc_tos();
-
- if (!opt_username || !*opt_username) {
- x_fprintf(x_stderr, "username must be specified!\n\n");
- exit(1);
- }
-
- if (strlen(buf) <= 3) {
- DEBUG(1, ("SPNEGO query [%s] too short\n", buf));
- x_fprintf(x_stdout, "BH SPNEGO query too short\n");
- return;
- }
-
- request = base64_decode_data_blob(buf+3);
-
- if (strncmp(buf, "PW ", 3) == 0) {
-
- /* We asked for a password and obviously got it :-) */
-
- opt_password = SMB_STRNDUP((const char *)request.data, request.length);
-
- if (opt_password == NULL) {
- DEBUG(1, ("Out of memory\n"));
- x_fprintf(x_stdout, "BH Out of memory\n");
- data_blob_free(&request);
- return;
- }
-
- x_fprintf(x_stdout, "OK\n");
- data_blob_free(&request);
- return;
- }
-
- if ( (strncmp(buf, "TT ", 3) != 0) &&
- (strncmp(buf, "AF ", 3) != 0) &&
- (strncmp(buf, "NA ", 3) != 0) ) {
- DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
- x_fprintf(x_stdout, "BH SPNEGO request invalid\n");
- data_blob_free(&request);
- return;
- }
-
- /* So we got a server challenge to generate a SPNEGO
- client-to-server request... */
-
- len = spnego_read_data(ctx, request, &spnego);
- data_blob_free(&request);
-
- if (len == -1) {
- DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf));
- x_fprintf(x_stdout, "BH Could not read SPNEGO data\n");
- return;
- }
-
- if (spnego.type == SPNEGO_NEG_TOKEN_INIT) {
-
- /* The server offers a list of mechanisms */
-
- const char *const *mechType = spnego.negTokenInit.mechTypes;
-
- while (*mechType != NULL) {
-
-#ifdef HAVE_KRB5
- if ( (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) ||
- (strcmp(*mechType, OID_KERBEROS5) == 0) ) {
- if (manage_client_krb5_init(spnego))
- goto out;
- }
-#endif
-
- if (strcmp(*mechType, OID_NTLMSSP) == 0) {
- if (manage_client_ntlmssp_init(spnego))
- goto out;
- }
-
- mechType++;
- }
-
- DEBUG(1, ("Server offered no compatible mechanism\n"));
- x_fprintf(x_stdout, "BH Server offered no compatible mechanism\n");
- return;
- }
-
- if (spnego.type == SPNEGO_NEG_TOKEN_TARG) {
-
- if (spnego.negTokenTarg.supportedMech == NULL) {
- /* On accept/reject Windows does not send the
- mechanism anymore. Handle that here and
- shut down the mechanisms. */
-
- switch (spnego.negTokenTarg.negResult) {
- case SPNEGO_ACCEPT_COMPLETED:
- x_fprintf(x_stdout, "AF\n");
- break;
- case SPNEGO_REJECT:
- x_fprintf(x_stdout, "NA\n");
- break;
- default:
- DEBUG(1, ("Got a negTokenTarg with no mech and an "
- "unknown negResult: %d\n",
- spnego.negTokenTarg.negResult));
- x_fprintf(x_stdout, "BH Got a negTokenTarg with"
- " no mech and an unknown "
- "negResult\n");
- }
-
- TALLOC_FREE(client_ntlmssp_state);
- goto out;
- }
-
- if (strcmp(spnego.negTokenTarg.supportedMech,
- OID_NTLMSSP) == 0) {
- manage_client_ntlmssp_targ(spnego);
- goto out;
- }
-
-#if HAVE_KRB5
- if (strcmp(spnego.negTokenTarg.supportedMech,
- OID_KERBEROS5_OLD) == 0) {
- manage_client_krb5_targ(spnego);
- goto out;
- }
-#endif
-
- }
-
- DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf));
- x_fprintf(x_stdout, "BH Got an SPNEGO token I could not handle\n");
- return;
-
- out:
- spnego_free_data(&spnego);
+ manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
return;
}
diff --git a/source3/winbindd/winbindd_ccache_access.c b/source3/winbindd/winbindd_ccache_access.c
index 7e300dbe92e..9bcbf0bb05a 100644
--- a/source3/winbindd/winbindd_ccache_access.c
+++ b/source3/winbindd/winbindd_ccache_access.c
@@ -48,14 +48,16 @@ static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username,
const char *password,
const DATA_BLOB initial_msg,
const DATA_BLOB challenge_msg,
+ TALLOC_CTX *mem_ctx,
DATA_BLOB *auth_msg,
- uint8_t session_key[16])
+ uint8_t session_key[16],
+ uint8_t *new_spnego)
{
NTSTATUS status;
struct auth_generic_state *auth_generic_state = NULL;
- DATA_BLOB dummy_msg, reply, session_key_blob;
+ DATA_BLOB reply, session_key_blob;
- status = auth_generic_client_prepare(NULL, &auth_generic_state);
+ status = auth_generic_client_prepare(mem_ctx, &auth_generic_state);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Could not start NTLMSSP client: %s\n",
@@ -87,29 +89,26 @@ static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username,
goto done;
}
- gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SESSION_KEY);
+ if (initial_msg.length == 0) {
+ gensec_want_feature(auth_generic_state->gensec_security,
+ GENSEC_FEATURE_SESSION_KEY);
+ }
- status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
+ status = auth_generic_client_start_by_name(auth_generic_state,
+ "ntlmssp_resume_ccache");
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Could not start NTLMSSP mech: %s\n",
+ DEBUG(1, ("Could not start NTLMSSP resume mech: %s\n",
nt_errstr(status)));
goto done;
}
- /* We need to get our protocol handler into the right state. So first
- we ask it to generate the initial message. Actually the client has already
- sent its own initial message, so we're going to drop this one on the floor.
- The client might have sent a different message, for example with different
- negotiation options, but as far as I can tell this won't hurt us. (Unless
- the client sent a different username or domain, in which case that's their
- problem for telling us the wrong username or domain.)
- Since we have a copy of the initial message that the client sent, we could
- resolve any discrepancies if we had to.
- */
- dummy_msg = data_blob_null;
+ /*
+ * We inject the inital NEGOTIATE message our caller used
+ * in order to get the state machine into the correct possition.
+ */
reply = data_blob_null;
status = gensec_update(auth_generic_state->gensec_security,
- talloc_tos(), dummy_msg, &reply);
+ talloc_tos(), initial_msg, &reply);
data_blob_free(&reply);
if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
@@ -120,7 +119,7 @@ static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username,
/* Now we are ready to handle the server's actual response. */
status = gensec_update(auth_generic_state->gensec_security,
- NULL, challenge_msg, &reply);
+ mem_ctx, challenge_msg, &reply);
if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
DEBUG(1, ("We didn't get a response to the challenge! [%s]\n",
nt_errstr(status)));
@@ -146,6 +145,8 @@ static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username,
memcpy(session_key, session_key_blob.data, 16);
data_blob_free(&session_key_blob);
*auth_msg = reply;
+ *new_spnego = gensec_have_feature(auth_generic_state->gensec_security,
+ GENSEC_FEATURE_NEW_SPNEGO);
status = NT_STATUS_OK;
done:
@@ -273,8 +274,9 @@ void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state)
result = do_ntlm_auth_with_stored_pw(
name_user, name_domain, entry->pass,
- initial, challenge, &auth,
- state->response->data.ccache_ntlm_auth.session_key);
+ initial, challenge, talloc_tos(), &auth,
+ state->response->data.ccache_ntlm_auth.session_key,
+ &state->response->data.ccache_ntlm_auth.new_spnego);
if (!NT_STATUS_IS_OK(result)) {
goto process_result;
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index cbce0c40c06..63175e54986 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -882,7 +882,7 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
- enum smb_signing_setting smb_sign_client_connections = lp_client_signing();
+ enum smb_signing_setting smb_sign_client_connections = lp_client_ipc_signing();
if (smb_sign_client_connections == SMB_SIGNING_DEFAULT) {
/*
@@ -935,8 +935,8 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
cli_set_timeout(*cli, 10000); /* 10 seconds */
result = smbXcli_negprot((*cli)->conn, (*cli)->timeout,
- lp_client_min_protocol(),
- lp_winbindd_max_protocol());
+ lp_client_ipc_min_protocol(),
+ lp_client_ipc_max_protocol());
if (!NT_STATUS_IS_OK(result)) {
DEBUG(1, ("cli_negprot failed: %s\n", nt_errstr(result)));
diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index bff310a6f13..cb85560500c 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -711,7 +711,7 @@ reconnect:
logon_server, NETLOGON_CONTROL_QUERY,
2, &info, &werr);
- if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+ if (!dcerpc_binding_handle_is_connected(b) && !retry) {
DEBUG(10, ("Session might have expired. "
"Reconnect and retry once.\n"));
invalidate_cm_connection(&domain->conn);
diff --git a/source3/wscript_build b/source3/wscript_build
index 58e1b9996d9..2c94ef31ffe 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -358,14 +358,9 @@ bld.SAMBA3_LIBRARY('smbd_shim',
deps='talloc',
private_library=True)
-bld.SAMBA3_SUBSYSTEM('LIBNTLMSSP',
- source='''libsmb/ntlmssp.c
- libsmb/ntlmssp_wrap.c''',
- deps='NDR_NTLMSSP NTLMSSP_COMMON wbclient')
-
bld.SAMBA3_SUBSYSTEM('auth_generic',
source='libsmb/auth_generic.c',
- deps='LIBNTLMSSP gse gensec')
+ deps='gse gensec')
bld.SAMBA3_LIBRARY('libsmb',
source='''libsmb/clientgen.c
@@ -393,7 +388,6 @@ bld.SAMBA3_LIBRARY('libsmb',
libsmb/smbsock_connect.c
libsmb/cli_smb2_fnum.c''',
deps='''
- LIBNTLMSSP
auth_generic
CLDAP
LIBNMB
@@ -1420,7 +1414,7 @@ bld.SAMBA3_BINARY('ntlm_auth',
tiniparser
libsmb
popt_samba3
- LIBNTLMSSP gse gensec''')
+ gse gensec''')
bld.SAMBA3_BINARY('timelimit',
source='script/tests/timelimit.c',
diff --git a/source4/auth/gensec/cyrus_sasl.c b/source4/auth/gensec/cyrus_sasl.c
deleted file mode 100644
index 08dccd6f5d1..00000000000
--- a/source4/auth/gensec/cyrus_sasl.c
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- Connect GENSEC to an external SASL lib
-
- Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "lib/tsocket/tsocket.h"
-#include "auth/credentials/credentials.h"
-#include "auth/gensec/gensec.h"
-#include "auth/gensec/gensec_internal.h"
-#include "auth/gensec/gensec_proto.h"
-#include "auth/gensec/gensec_toplevel_proto.h"
-#include <sasl/sasl.h>
-
-NTSTATUS gensec_sasl_init(void);
-
-struct gensec_sasl_state {
- sasl_conn_t *conn;
- int step;
- bool wrap;
-};
-
-static NTSTATUS sasl_nt_status(int sasl_ret)
-{
- switch (sasl_ret) {
- case SASL_CONTINUE:
- return NT_STATUS_MORE_PROCESSING_REQUIRED;
- case SASL_NOMEM:
- return NT_STATUS_NO_MEMORY;
- case SASL_BADPARAM:
- case SASL_NOMECH:
- return NT_STATUS_INVALID_PARAMETER;
- case SASL_BADMAC:
- return NT_STATUS_ACCESS_DENIED;
- case SASL_OK:
- return NT_STATUS_OK;
- default:
- return NT_STATUS_UNSUCCESSFUL;
- }
-}
-
-static int gensec_sasl_get_user(void *context, int id,
- const char **result, unsigned *len)
-{
- struct gensec_security *gensec_security = talloc_get_type(context, struct gensec_security);
- const char *username = cli_credentials_get_username(gensec_get_credentials(gensec_security));
- if (id != SASL_CB_USER && id != SASL_CB_AUTHNAME) {
- return SASL_FAIL;
- }
-
- *result = username;
- return SASL_OK;
-}
-
-static int gensec_sasl_get_realm(void *context, int id,
- const char **availrealms,
- const char **result)
-{
- struct gensec_security *gensec_security = talloc_get_type(context, struct gensec_security);
- const char *realm = cli_credentials_get_realm(gensec_get_credentials(gensec_security));
- int i;
- if (id != SASL_CB_GETREALM) {
- return SASL_FAIL;
- }
-
- for (i=0; availrealms && availrealms[i]; i++) {
- if (strcasecmp_m(realm, availrealms[i]) == 0) {
- result[i] = availrealms[i];
- return SASL_OK;
- }
- }
- /* None of the realms match, so lets not specify one */
- *result = "";
- return SASL_OK;
-}
-
-static int gensec_sasl_get_password(sasl_conn_t *conn, void *context, int id,
- sasl_secret_t **psecret)
-{
- struct gensec_security *gensec_security = talloc_get_type(context, struct gensec_security);
- const char *password = cli_credentials_get_password(gensec_get_credentials(gensec_security));
-
- sasl_secret_t *secret;
- if (!password) {
- *psecret = NULL;
- return SASL_OK;
- }
- secret = talloc_size(gensec_security, sizeof(sasl_secret_t)+strlen(password)+1);
- if (!secret) {
- return SASL_NOMEM;
- }
- secret->len = strlen(password);
- strlcpy((char*)secret->data, password, secret->len+1);
- *psecret = secret;
- return SASL_OK;
-}
-
-static int gensec_sasl_dispose(struct gensec_sasl_state *gensec_sasl_state)
-{
- sasl_dispose(&gensec_sasl_state->conn);
- return SASL_OK;
-}
-
-static NTSTATUS gensec_sasl_client_start(struct gensec_security *gensec_security)
-{
- struct gensec_sasl_state *gensec_sasl_state;
- const char *service = gensec_get_target_service(gensec_security);
- const char *target_name = gensec_get_target_hostname(gensec_security);
- const struct tsocket_address *tlocal_addr = gensec_get_local_address(gensec_security);
- const struct tsocket_address *tremote_addr = gensec_get_remote_address(gensec_security);
- char *local_addr = NULL;
- char *remote_addr = NULL;
- int sasl_ret;
-
- sasl_callback_t *callbacks;
-
- gensec_sasl_state = talloc_zero(gensec_security, struct gensec_sasl_state);
- if (!gensec_sasl_state) {
- return NT_STATUS_NO_MEMORY;
- }
-
- callbacks = talloc_array(gensec_sasl_state, sasl_callback_t, 5);
- callbacks[0].id = SASL_CB_USER;
- callbacks[0].proc = gensec_sasl_get_user;
- callbacks[0].context = gensec_security;
-
- callbacks[1].id = SASL_CB_AUTHNAME;
- callbacks[1].proc = gensec_sasl_get_user;
- callbacks[1].context = gensec_security;
-
- callbacks[2].id = SASL_CB_GETREALM;
- callbacks[2].proc = gensec_sasl_get_realm;
- callbacks[2].context = gensec_security;
-
- callbacks[3].id = SASL_CB_PASS;
- callbacks[3].proc = gensec_sasl_get_password;
- callbacks[3].context = gensec_security;
-
- callbacks[4].id = SASL_CB_LIST_END;
- callbacks[4].proc = NULL;
- callbacks[4].context = NULL;
-
- gensec_security->private_data = gensec_sasl_state;
-
- if (tlocal_addr) {
- local_addr = talloc_asprintf(gensec_sasl_state,
- "%s;%d",
- tsocket_address_inet_addr_string(tlocal_addr, gensec_sasl_state),
- tsocket_address_inet_port(tlocal_addr));
- }
-
- if (tremote_addr) {
- remote_addr = talloc_asprintf(gensec_sasl_state,
- "%s;%d",
- tsocket_address_inet_addr_string(tremote_addr, gensec_sasl_state),
- tsocket_address_inet_port(tremote_addr));
- }
- gensec_sasl_state->step = 0;
-
- sasl_ret = sasl_client_new(service,
- target_name,
- local_addr, remote_addr, callbacks, 0,
- &gensec_sasl_state->conn);
-
- if (sasl_ret == SASL_OK) {
- sasl_security_properties_t props;
- talloc_set_destructor(gensec_sasl_state, gensec_sasl_dispose);
-
- ZERO_STRUCT(props);
- if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
- props.min_ssf = 1;
- props.max_ssf = 1;
- props.maxbufsize = 65536;
- gensec_sasl_state->wrap = true;
- }
- if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
- props.min_ssf = 40;
- props.max_ssf = UINT_MAX;
- props.maxbufsize = 65536;
- gensec_sasl_state->wrap = true;
- }
-
- sasl_ret = sasl_setprop(gensec_sasl_state->conn, SASL_SEC_PROPS, &props);
- }
- if (sasl_ret != SASL_OK) {
- DEBUG(1, ("GENSEC SASL: client_new failed: %s\n", sasl_errdetail(gensec_sasl_state->conn)));
- }
- return sasl_nt_status(sasl_ret);
-}
-
-static NTSTATUS gensec_sasl_update(struct gensec_security *gensec_security,
- TALLOC_CTX *out_mem_ctx,
- struct tevent_context *ev,
- const DATA_BLOB in, DATA_BLOB *out)
-{
- struct gensec_sasl_state *gensec_sasl_state = talloc_get_type(gensec_security->private_data,
- struct gensec_sasl_state);
- int sasl_ret;
- const char *out_data;
- unsigned int out_len;
-
- if (gensec_sasl_state->step == 0) {
- const char *mech;
- sasl_ret = sasl_client_start(gensec_sasl_state->conn, gensec_security->ops->sasl_name,
- NULL, &out_data, &out_len, &mech);
- } else {
- sasl_ret = sasl_client_step(gensec_sasl_state->conn,
- (char*)in.data, in.length, NULL,
- &out_data, &out_len);
- }
- if (sasl_ret == SASL_OK || sasl_ret == SASL_CONTINUE) {
- *out = data_blob_talloc(out_mem_ctx, out_data, out_len);
- } else {
- DEBUG(1, ("GENSEC SASL: step %d update failed: %s\n", gensec_sasl_state->step,
- sasl_errdetail(gensec_sasl_state->conn)));
- }
- gensec_sasl_state->step++;
- return sasl_nt_status(sasl_ret);
-}
-
-static NTSTATUS gensec_sasl_unwrap_packets(struct gensec_security *gensec_security,
- TALLOC_CTX *out_mem_ctx,
- const DATA_BLOB *in,
- DATA_BLOB *out,
- size_t *len_processed)
-{
- struct gensec_sasl_state *gensec_sasl_state = talloc_get_type(gensec_security->private_data,
- struct gensec_sasl_state);
- const char *out_data;
- unsigned int out_len;
-
- int sasl_ret = sasl_decode(gensec_sasl_state->conn,
- (char*)in->data, in->length, &out_data,
- &out_len);
- if (sasl_ret == SASL_OK) {
- *out = data_blob_talloc(out_mem_ctx, out_data, out_len);
- *len_processed = in->length;
- } else {
- DEBUG(1, ("GENSEC SASL: unwrap failed: %s\n", sasl_errdetail(gensec_sasl_state->conn)));
- }
- return sasl_nt_status(sasl_ret);
-
-}
-
-static NTSTATUS gensec_sasl_wrap_packets(struct gensec_security *gensec_security,
- TALLOC_CTX *out_mem_ctx,
- const DATA_BLOB *in,
- DATA_BLOB *out,
- size_t *len_processed)
-{
- struct gensec_sasl_state *gensec_sasl_state = talloc_get_type(gensec_security->private_data,
- struct gensec_sasl_state);
- const char *out_data;
- unsigned int out_len;
- unsigned len_permitted;
- int sasl_ret = sasl_getprop(gensec_sasl_state->conn, SASL_SSF,
- (const void**)&len_permitted);
- if (sasl_ret != SASL_OK) {
- return sasl_nt_status(sasl_ret);
- }
- len_permitted = MIN(len_permitted, in->length);
-
- sasl_ret = sasl_encode(gensec_sasl_state->conn,
- (char*)in->data, len_permitted, &out_data,
- &out_len);
- if (sasl_ret == SASL_OK) {
- *out = data_blob_talloc(out_mem_ctx, out_data, out_len);
- *len_processed = in->length;
- } else {
- DEBUG(1, ("GENSEC SASL: wrap failed: %s\n", sasl_errdetail(gensec_sasl_state->conn)));
- }
- return sasl_nt_status(sasl_ret);
-}
-
-/* Try to figure out what features we actually got on the connection */
-static bool gensec_sasl_have_feature(struct gensec_security *gensec_security,
- uint32_t feature)
-{
- struct gensec_sasl_state *gensec_sasl_state = talloc_get_type(gensec_security->private_data,
- struct gensec_sasl_state);
- sasl_ssf_t ssf;
- int sasl_ret;
-
- /* If we did not elect to wrap, then we have neither sign nor seal, no matter what the SSF claims */
- if (!gensec_sasl_state->wrap) {
- return false;
- }
-
- sasl_ret = sasl_getprop(gensec_sasl_state->conn, SASL_SSF,
- (const void**)&ssf);
- if (sasl_ret != SASL_OK) {
- return false;
- }
- if (feature & GENSEC_FEATURE_SIGN) {
- if (ssf == 0) {
- return false;
- }
- if (ssf >= 1) {
- return true;
- }
- }
- if (feature & GENSEC_FEATURE_SEAL) {
- if (ssf <= 1) {
- return false;
- }
- if (ssf > 1) {
- return true;
- }
- }
- return false;
-}
-
-/* This could in theory work with any SASL mech */
-static const struct gensec_security_ops gensec_sasl_security_ops = {
- .name = "sasl-DIGEST-MD5",
- .sasl_name = "DIGEST-MD5",
- .client_start = gensec_sasl_client_start,
- .update = gensec_sasl_update,
- .wrap_packets = gensec_sasl_wrap_packets,
- .unwrap_packets = gensec_sasl_unwrap_packets,
- .have_feature = gensec_sasl_have_feature,
- .enabled = true,
- .priority = GENSEC_SASL
-};
-
-static int gensec_sasl_log(void *context,
- int sasl_log_level,
- const char *message)
-{
- int dl;
- switch (sasl_log_level) {
- case SASL_LOG_NONE:
- dl = 0;
- break;
- case SASL_LOG_ERR:
- dl = 1;
- break;
- case SASL_LOG_FAIL:
- dl = 2;
- break;
- case SASL_LOG_WARN:
- dl = 3;
- break;
- case SASL_LOG_NOTE:
- dl = 5;
- break;
- case SASL_LOG_DEBUG:
- dl = 10;
- break;
- case SASL_LOG_TRACE:
- dl = 11;
- break;
-#if DEBUG_PASSWORD
- case SASL_LOG_PASS:
- dl = 100;
- break;
-#endif
- default:
- dl = 0;
- break;
- }
- DEBUG(dl, ("gensec_sasl: %s\n", message));
-
- return SASL_OK;
-}
-
-NTSTATUS gensec_sasl_init(void)
-{
- NTSTATUS ret;
- int sasl_ret;
-#if 0
- int i;
- const char **sasl_mechs;
-#endif
-
- static const sasl_callback_t callbacks[] = {
- {
- .id = SASL_CB_LOG,
- .proc = gensec_sasl_log,
- .context = NULL,
- },
- {
- .id = SASL_CB_LIST_END,
- .proc = gensec_sasl_log,
- .context = NULL,
- }
- };
- sasl_ret = sasl_client_init(callbacks);
-
- if (sasl_ret == SASL_NOMECH) {
- /* Nothing to do here */
- return NT_STATUS_OK;
- }
-
- if (sasl_ret != SASL_OK) {
- return sasl_nt_status(sasl_ret);
- }
-
- /* For now, we just register DIGEST-MD5 */
-#if 1
- ret = gensec_register(&gensec_sasl_security_ops);
- if (!NT_STATUS_IS_OK(ret)) {
- DEBUG(0,("Failed to register '%s' gensec backend!\n",
- gensec_sasl_security_ops.name));
- return ret;
- }
-#else
- sasl_mechs = sasl_global_listmech();
- for (i = 0; sasl_mechs && sasl_mechs[i]; i++) {
- const struct gensec_security_ops *oldmech;
- struct gensec_security_ops *newmech;
- oldmech = gensec_security_by_sasl_name(NULL, sasl_mechs[i]);
- if (oldmech) {
- continue;
- }
- newmech = talloc(talloc_autofree_context(), struct gensec_security_ops);
- if (!newmech) {
- return NT_STATUS_NO_MEMORY;
- }
- *newmech = gensec_sasl_security_ops;
- newmech->sasl_name = talloc_strdup(newmech, sasl_mechs[i]);
- newmech->name = talloc_asprintf(newmech, "sasl-%s", sasl_mechs[i]);
- if (!newmech->sasl_name || !newmech->name) {
- return NT_STATUS_NO_MEMORY;
- }
-
- ret = gensec_register(newmech);
- if (!NT_STATUS_IS_OK(ret)) {
- DEBUG(0,("Failed to register '%s' gensec backend!\n",
- gensec_sasl_security_ops.name));
- return ret;
- }
- }
-#endif
- return NT_STATUS_OK;
-}
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c
index 514d4238d58..15685a88340 100644
--- a/source4/auth/gensec/gensec_gssapi.c
+++ b/source4/auth/gensec/gensec_gssapi.c
@@ -42,6 +42,7 @@
#include "gensec_gssapi.h"
#include "lib/util/util_net.h"
#include "auth/kerberos/pac_utils.h"
+#include "auth/kerberos/gssapi_helper.h"
#ifndef gss_mech_spnego
gss_OID_desc spnego_mech_oid_desc =
@@ -53,67 +54,35 @@ _PUBLIC_ NTSTATUS gensec_gssapi_init(void);
static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security);
static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security);
+static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size);
static int gensec_gssapi_destructor(struct gensec_gssapi_state *gensec_gssapi_state)
{
- OM_uint32 maj_stat, min_stat;
-
+ OM_uint32 min_stat;
+
if (gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
- maj_stat = gss_release_cred(&min_stat,
- &gensec_gssapi_state->delegated_cred_handle);
+ gss_release_cred(&min_stat,
+ &gensec_gssapi_state->delegated_cred_handle);
}
if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
- maj_stat = gss_delete_sec_context (&min_stat,
- &gensec_gssapi_state->gssapi_context,
- GSS_C_NO_BUFFER);
+ gss_delete_sec_context(&min_stat,
+ &gensec_gssapi_state->gssapi_context,
+ GSS_C_NO_BUFFER);
}
if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
- maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name);
+ gss_release_name(&min_stat,
+ &gensec_gssapi_state->server_name);
}
if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
- maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
- }
-
- if (gensec_gssapi_state->lucid) {
- gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid);
+ gss_release_name(&min_stat,
+ &gensec_gssapi_state->client_name);
}
return 0;
}
-static NTSTATUS gensec_gssapi_init_lucid(struct gensec_gssapi_state *gensec_gssapi_state)
-{
- OM_uint32 maj_stat, min_stat;
-
- if (gensec_gssapi_state->lucid) {
- return NT_STATUS_OK;
- }
-
- maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
- &gensec_gssapi_state->gssapi_context,
- 1,
- (void **)&gensec_gssapi_state->lucid);
- if (maj_stat != GSS_S_COMPLETE) {
- DEBUG(0,("gensec_gssapi_init_lucid: %s\n",
- gssapi_error_string(gensec_gssapi_state,
- maj_stat, min_stat,
- gensec_gssapi_state->gss_oid)));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- if (gensec_gssapi_state->lucid->version != 1) {
- DEBUG(0,("gensec_gssapi_init_lucid: lucid version[%d] != 1\n",
- gensec_gssapi_state->lucid->version));
- gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid);
- gensec_gssapi_state->lucid = NULL;
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- return NT_STATUS_OK;
-}
-
static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
{
struct gensec_gssapi_state *gensec_gssapi_state;
@@ -191,8 +160,6 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
gensec_gssapi_state->client_cred = NULL;
gensec_gssapi_state->server_cred = NULL;
- gensec_gssapi_state->lucid = NULL;
-
gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
gensec_gssapi_state->sasl = false;
@@ -303,6 +270,7 @@ static NTSTATUS gensec_gssapi_client_creds(struct gensec_security *gensec_securi
return NT_STATUS_INVALID_PARAMETER;
case KRB5KDC_ERR_PREAUTH_FAILED:
case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
+ case KRB5KRB_AP_ERR_BAD_INTEGRITY:
DEBUG(1, ("Wrong username or password: %s\n", error_string));
return NT_STATUS_LOGON_FAILURE;
case KRB5KDC_ERR_CLIENT_REVOKED:
@@ -524,7 +492,8 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
gss_release_buffer(&min_stat2, &output_token);
- if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG) {
+ if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG &&
+ gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
} else {
DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
@@ -1028,53 +997,30 @@ static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_securit
{
struct gensec_gssapi_state *gensec_gssapi_state
= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
- OM_uint32 maj_stat, min_stat;
- gss_buffer_desc input_token, output_token;
- int conf_state;
- ssize_t sig_length;
+ bool hdr_signing = false;
+ size_t sig_size = 0;
+ NTSTATUS status;
if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
- DEBUG(1, ("gensec_gssapi_seal_packet: "
- "GENSEC_FEATURE_SIGN_PKT_HEADER not supported\n"));
- return NT_STATUS_ACCESS_DENIED;
+ hdr_signing = true;
}
- input_token.length = length;
- input_token.value = data;
-
- maj_stat = gss_wrap(&min_stat,
- gensec_gssapi_state->gssapi_context,
- gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
- GSS_C_QOP_DEFAULT,
- &input_token,
- &conf_state,
- &output_token);
- if (GSS_ERROR(maj_stat)) {
- DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n",
- gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
- return NT_STATUS_ACCESS_DENIED;
- }
+ sig_size = gensec_gssapi_sig_size(gensec_security, length);
- if (output_token.length < input_token.length) {
- DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%ld] *less* than caller length [%ld]\n",
- (long)output_token.length, (long)length));
- return NT_STATUS_INTERNAL_ERROR;
+ status = gssapi_seal_packet(gensec_gssapi_state->gssapi_context,
+ gensec_gssapi_state->gss_oid,
+ hdr_signing, sig_size,
+ data, length,
+ whole_pdu, pdu_length,
+ mem_ctx, sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%ju,"
+ "data=%ju,pdu=%ju) failed: %s\n",
+ hdr_signing, sig_size, length, pdu_length,
+ nt_errstr(status)));
+ return status;
}
- sig_length = output_token.length - input_token.length;
-
- memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
- *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
- dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
- dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
- dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
-
- gss_release_buffer(&min_stat, &output_token);
-
- if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
- && !conf_state) {
- return NT_STATUS_ACCESS_DENIED;
- }
return NT_STATUS_OK;
}
@@ -1085,55 +1031,27 @@ static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_secur
{
struct gensec_gssapi_state *gensec_gssapi_state
= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
- OM_uint32 maj_stat, min_stat;
- gss_buffer_desc input_token, output_token;
- int conf_state;
- gss_qop_t qop_state;
- DATA_BLOB in;
-
- dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
+ bool hdr_signing = false;
+ NTSTATUS status;
if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
- DEBUG(1, ("gensec_gssapi_unseal_packet: "
- "GENSEC_FEATURE_SIGN_PKT_HEADER not supported\n"));
- return NT_STATUS_ACCESS_DENIED;
- }
-
- in = data_blob_talloc(gensec_security, NULL, sig->length + length);
-
- memcpy(in.data, sig->data, sig->length);
- memcpy(in.data + sig->length, data, length);
-
- input_token.length = in.length;
- input_token.value = in.data;
-
- maj_stat = gss_unwrap(&min_stat,
- gensec_gssapi_state->gssapi_context,
- &input_token,
- &output_token,
- &conf_state,
- &qop_state);
- talloc_free(in.data);
- if (GSS_ERROR(maj_stat)) {
- char *error_string = gssapi_error_string(NULL, maj_stat, min_stat, gensec_gssapi_state->gss_oid);
- DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n",
- error_string));
- talloc_free(error_string);
- return NT_STATUS_ACCESS_DENIED;
+ hdr_signing = true;
}
- if (output_token.length != length) {
- return NT_STATUS_INTERNAL_ERROR;
+ status = gssapi_unseal_packet(gensec_gssapi_state->gssapi_context,
+ gensec_gssapi_state->gss_oid,
+ hdr_signing,
+ data, length,
+ whole_pdu, pdu_length,
+ sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%ju,"
+ "data=%ju,pdu=%ju) failed: %s\n",
+ hdr_signing, sig->length, length, pdu_length,
+ nt_errstr(status)));
+ return status;
}
- memcpy(data, output_token.value, length);
-
- gss_release_buffer(&min_stat, &output_token);
-
- if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
- && !conf_state) {
- return NT_STATUS_ACCESS_DENIED;
- }
return NT_STATUS_OK;
}
@@ -1145,34 +1063,27 @@ static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_securit
{
struct gensec_gssapi_state *gensec_gssapi_state
= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
- OM_uint32 maj_stat, min_stat;
- gss_buffer_desc input_token, output_token;
+ bool hdr_signing = false;
+ NTSTATUS status;
if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
- input_token.length = pdu_length;
- input_token.value = discard_const_p(uint8_t *, whole_pdu);
- } else {
- input_token.length = length;
- input_token.value = discard_const_p(uint8_t *, data);
+ hdr_signing = true;
}
- maj_stat = gss_get_mic(&min_stat,
- gensec_gssapi_state->gssapi_context,
- GSS_C_QOP_DEFAULT,
- &input_token,
- &output_token);
- if (GSS_ERROR(maj_stat)) {
- DEBUG(1, ("GSS GetMic failed: %s\n",
- gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
- return NT_STATUS_ACCESS_DENIED;
+ status = gssapi_sign_packet(gensec_gssapi_state->gssapi_context,
+ gensec_gssapi_state->gss_oid,
+ hdr_signing,
+ data, length,
+ whole_pdu, pdu_length,
+ mem_ctx, sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u,"
+ "data=%ju,pdu=%ju) failed: %s\n",
+ hdr_signing, length, pdu_length,
+ nt_errstr(status)));
+ return status;
}
- *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, output_token.length);
-
- dump_data_pw("gensec_gssapi_sign_packet: sig\n", sig->data, sig->length);
-
- gss_release_buffer(&min_stat, &output_token);
-
return NT_STATUS_OK;
}
@@ -1183,35 +1094,25 @@ static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_securi
{
struct gensec_gssapi_state *gensec_gssapi_state
= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
- OM_uint32 maj_stat, min_stat;
- gss_buffer_desc input_token;
- gss_buffer_desc input_message;
- gss_qop_t qop_state;
-
- dump_data_pw("gensec_gssapi_check_packet: sig\n", sig->data, sig->length);
+ bool hdr_signing = false;
+ NTSTATUS status;
if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
- input_message.length = pdu_length;
- input_message.value = discard_const(whole_pdu);
- } else {
- input_message.length = length;
- input_message.value = discard_const(data);
+ hdr_signing = true;
}
- input_token.length = sig->length;
- input_token.value = sig->data;
-
- maj_stat = gss_verify_mic(&min_stat,
- gensec_gssapi_state->gssapi_context,
- &input_message,
- &input_token,
- &qop_state);
- if (GSS_ERROR(maj_stat)) {
- char *error_string = gssapi_error_string(NULL, maj_stat, min_stat, gensec_gssapi_state->gss_oid);
- DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string));
- talloc_free(error_string);
-
- return NT_STATUS_ACCESS_DENIED;
+ status = gssapi_check_packet(gensec_gssapi_state->gssapi_context,
+ gensec_gssapi_state->gss_oid,
+ hdr_signing,
+ data, length,
+ whole_pdu, pdu_length,
+ sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%ju,"
+ "data=%ju,pdu=%ju) failed: %s\n",
+ hdr_signing, sig->length, length, pdu_length,
+ nt_errstr(status)));
+ return status;
}
return NT_STATUS_OK;
@@ -1294,8 +1195,7 @@ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security,
}
if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
- /* TODO: implement this using gss_wrap_iov() */
- return false;
+ return true;
}
if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
@@ -1402,9 +1302,8 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
return nt_status;
}
- if (!(gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG)) {
- DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n"));
- } else {
+ if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG &&
+ gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
krb5_error_code ret;
const char *error_string;
@@ -1434,7 +1333,10 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
/* It has been taken from this place... */
gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+ } else {
+ DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n"));
}
+
*_session_info = talloc_steal(mem_ctx, session_info);
talloc_free(tmp_ctx);
@@ -1445,56 +1347,18 @@ static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, si
{
struct gensec_gssapi_state *gensec_gssapi_state
= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
- NTSTATUS status;
-
- if (gensec_gssapi_state->sig_size) {
- return gensec_gssapi_state->sig_size;
- }
-
- if (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG) {
- gensec_gssapi_state->sig_size = 45;
- } else {
- gensec_gssapi_state->sig_size = 37;
- }
+ size_t sig_size;
- status = gensec_gssapi_init_lucid(gensec_gssapi_state);
- if (!NT_STATUS_IS_OK(status)) {
+ if (gensec_gssapi_state->sig_size > 0) {
return gensec_gssapi_state->sig_size;
}
- if (gensec_gssapi_state->lucid->protocol == 1) {
- if (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG) {
- /*
- * TODO: windows uses 76 here, but we don't know
- * gss_wrap works with aes keys yet
- */
- gensec_gssapi_state->sig_size = 76;
- } else {
- gensec_gssapi_state->sig_size = 28;
- }
- } else if (gensec_gssapi_state->lucid->protocol == 0) {
- switch (gensec_gssapi_state->lucid->rfc1964_kd.ctx_key.type) {
- case ENCTYPE_DES_CBC_CRC:
- case ENCTYPE_ARCFOUR_HMAC:
- case ENCTYPE_ARCFOUR_HMAC_EXP:
- if (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG) {
- gensec_gssapi_state->sig_size = 45;
- } else {
- gensec_gssapi_state->sig_size = 37;
- }
- break;
-#ifdef SAMBA4_USES_HEIMDAL
- case ENCTYPE_OLD_DES3_CBC_SHA1:
- if (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG) {
- gensec_gssapi_state->sig_size = 57;
- } else {
- gensec_gssapi_state->sig_size = 49;
- }
- break;
-#endif
- }
- }
+ sig_size = gssapi_get_sig_size(gensec_gssapi_state->gssapi_context,
+ gensec_gssapi_state->gss_oid,
+ gensec_gssapi_state->gss_want_flags,
+ data_size);
+ gensec_gssapi_state->sig_size = sig_size;
return gensec_gssapi_state->sig_size;
}
@@ -1525,6 +1389,8 @@ static const struct gensec_security_ops gensec_gssapi_spnego_security_ops = {
.check_packet = gensec_gssapi_check_packet,
.seal_packet = gensec_gssapi_seal_packet,
.unseal_packet = gensec_gssapi_unseal_packet,
+ .max_input_size = gensec_gssapi_max_input_size,
+ .max_wrapped_size = gensec_gssapi_max_wrapped_size,
.wrap = gensec_gssapi_wrap,
.unwrap = gensec_gssapi_unwrap,
.have_feature = gensec_gssapi_have_feature,
@@ -1550,6 +1416,8 @@ static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
.check_packet = gensec_gssapi_check_packet,
.seal_packet = gensec_gssapi_seal_packet,
.unseal_packet = gensec_gssapi_unseal_packet,
+ .max_input_size = gensec_gssapi_max_input_size,
+ .max_wrapped_size = gensec_gssapi_max_wrapped_size,
.wrap = gensec_gssapi_wrap,
.unwrap = gensec_gssapi_unwrap,
.have_feature = gensec_gssapi_have_feature,
diff --git a/source4/auth/gensec/gensec_gssapi.h b/source4/auth/gensec/gensec_gssapi.h
index b7429b5f48d..cf0e3a8d914 100644
--- a/source4/auth/gensec/gensec_gssapi.h
+++ b/source4/auth/gensec/gensec_gssapi.h
@@ -46,7 +46,6 @@ struct gensec_gssapi_state {
NTTIME expire_time;
/* gensec_gssapi only */
- gss_krb5_lucid_context_v1_t *lucid;
gss_OID gss_oid;
struct gss_channel_bindings_struct *input_chan_bindings;
diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c
index c34c43425e4..5d2f8b87ddc 100644
--- a/source4/auth/gensec/gensec_krb5.c
+++ b/source4/auth/gensec/gensec_krb5.c
@@ -27,7 +27,6 @@
#include "system/kerberos.h"
#include "auth/kerberos/kerberos.h"
#include "auth/auth.h"
-#include "lib/socket/socket.h"
#include "lib/tsocket/tsocket.h"
#include "librpc/gen_ndr/dcerpc.h"
#include "auth/credentials/credentials.h"
@@ -418,14 +417,17 @@ static DATA_BLOB gensec_gssapi_gen_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLO
if (!asn1_pop_tag(data)) goto err;
- ret = data_blob_talloc(mem_ctx, data->data, data->length);
+ if (!asn1_extract_blob(data, mem_ctx, &ret)) {
+ goto err;
+ }
asn1_free(data);
return ret;
err:
- DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data->ofs));
+ DEBUG(1, ("Failed to build krb5 wrapper at offset %d\n",
+ (int)asn1_current_ofs(data)));
asn1_free(data);
return ret;
}
@@ -450,7 +452,7 @@ static bool gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *
data_remaining = asn1_tag_remaining(data);
if (data_remaining < 3) {
- data->has_error = true;
+ asn1_set_error(data);
} else {
if (!asn1_read(data, tok_id, 2)) goto err;
data_remaining -= 2;
@@ -460,7 +462,7 @@ static bool gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *
if (!asn1_end_tag(data)) goto err;
- ret = !data->has_error;
+ ret = !asn1_has_error(data);
err:
diff --git a/source4/auth/gensec/gensec_socket.h b/source4/auth/gensec/gensec_socket.h
deleted file mode 100644
index bb12cc00ead..00000000000
--- a/source4/auth/gensec/gensec_socket.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- GENSEC socket interface
-
- Copyright (C) Andrew Bartlett 2006
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-NTSTATUS gensec_socket_init(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- struct socket_context *current_socket,
- struct tevent_context *ev,
- void (*recv_handler)(void *, uint16_t),
- void *recv_private,
- struct socket_context **new_socket);
diff --git a/source4/auth/gensec/pygensec.c b/source4/auth/gensec/pygensec.c
index 83864e65af2..a6be0cbe25b 100644
--- a/source4/auth/gensec/pygensec.c
+++ b/source4/auth/gensec/pygensec.c
@@ -504,6 +504,83 @@ static PyObject *py_gensec_unwrap(PyObject *self, PyObject *args)
return ret;
}
+static PyObject *py_gensec_sig_size(PyObject *self, PyObject *args)
+{
+ struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+ Py_ssize_t data_size = 0;
+ size_t sig_size = 0;
+
+ if (!PyArg_ParseTuple(args, "n", &data_size)) {
+ return NULL;
+ }
+
+ sig_size = gensec_sig_size(security, data_size);
+
+ return PyLong_FromSize_t(sig_size);
+}
+
+static PyObject *py_gensec_sign_packet(PyObject *self, PyObject *args)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ Py_ssize_t data_length = 0;
+ Py_ssize_t pdu_length = 0;
+ DATA_BLOB data, pdu, sig;
+ PyObject *py_sig;
+ struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+
+ if (!PyArg_ParseTuple(args, "z#z#", &data.data, &data_length, &pdu.data, &pdu_length)) {
+ return NULL;
+ }
+ data.length = data_length;
+ pdu.length = pdu_length;
+
+ mem_ctx = talloc_new(NULL);
+
+ status = gensec_sign_packet(security, mem_ctx,
+ data.data, data.length,
+ pdu.data, pdu.length, &sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_SetNTSTATUS(status);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ py_sig = PyBytes_FromStringAndSize((const char *)sig.data, sig.length);
+ talloc_free(mem_ctx);
+ return py_sig;
+}
+
+static PyObject *py_gensec_check_packet(PyObject *self, PyObject *args)
+{
+ NTSTATUS status;
+ Py_ssize_t data_length = 0;
+ Py_ssize_t pdu_length = 0;
+ Py_ssize_t sig_length = 0;
+ DATA_BLOB data, pdu, sig;
+ struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+
+ if (!PyArg_ParseTuple(args, "z#z#z#",
+ &data.data, &data_length,
+ &pdu.data, &pdu_length,
+ &sig.data, &sig_length)) {
+ return NULL;
+ }
+ data.length = data_length;
+ pdu.length = pdu_length;
+ sig.length = sig_length;
+
+ status = gensec_check_packet(security,
+ data.data, data.length,
+ pdu.data, pdu.length, &sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
static PyMethodDef py_gensec_security_methods[] = {
{ "start_client", (PyCFunction)py_gensec_start_client, METH_VARARGS|METH_KEYWORDS|METH_CLASS,
"S.start_client(settings) -> gensec" },
@@ -537,6 +614,12 @@ static PyMethodDef py_gensec_security_methods[] = {
"S.wrap(blob_in) -> blob_out\nPackage one clear packet into a wrapped GENSEC packet." },
{ "unwrap", (PyCFunction)py_gensec_unwrap, METH_VARARGS,
"S.unwrap(blob_in) -> blob_out\nPerform one wrapped GENSEC packet into a clear packet." },
+ { "sig_size", (PyCFunction)py_gensec_sig_size, METH_VARARGS,
+ "S.sig_size(data_size) -> sig_size\nSize of the DCERPC packet signature" },
+ { "sign_packet", (PyCFunction)py_gensec_sign_packet, METH_VARARGS,
+ "S.sign_packet(data, whole_pdu) -> sig\nSign a DCERPC packet." },
+ { "check_packet", (PyCFunction)py_gensec_check_packet, METH_VARARGS,
+ "S.check_packet(data, whole_pdu, sig)\nCheck a DCERPC packet." },
{ NULL }
};
diff --git a/source4/auth/gensec/socket.c b/source4/auth/gensec/socket.c
deleted file mode 100644
index c89e0802323..00000000000
--- a/source4/auth/gensec/socket.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- GENSEC socket interface
-
- Copyright (C) Andrew Bartlett 2006
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "lib/events/events.h"
-#include "lib/socket/socket.h"
-#include "lib/stream/packet.h"
-#include "auth/gensec/gensec.h"
-#include "auth/gensec/gensec_proto.h"
-#include "auth/gensec/gensec_socket.h"
-
-static const struct socket_ops gensec_socket_ops;
-
-struct gensec_socket {
- struct gensec_security *gensec_security;
- struct socket_context *socket;
- struct tevent_context *ev;
- struct packet_context *packet;
- DATA_BLOB read_buffer; /* SASL packets are turned into liniarlised data here, for reading */
- size_t orig_send_len;
- bool eof;
- NTSTATUS error;
- bool interrupted;
- void (*recv_handler)(void *, uint16_t);
- void *recv_private;
- int in_extra_read;
- bool wrap; /* Should we be wrapping on this socket at all? */
-};
-
-static NTSTATUS gensec_socket_init_fn(struct socket_context *sock)
-{
- switch (sock->type) {
- case SOCKET_TYPE_STREAM:
- break;
- default:
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- sock->backend_name = "gensec";
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS gensec_socket_full_request(void *private_data, DATA_BLOB blob, size_t *size)
-{
- struct gensec_socket *gensec_socket = talloc_get_type(private_data, struct gensec_socket);
- struct gensec_security *gensec_security = gensec_socket->gensec_security;
- return gensec_packet_full_request(gensec_security, blob, size);
-}
-
-/* Try to figure out how much data is waiting to be read */
-static NTSTATUS gensec_socket_pending(struct socket_context *sock, size_t *npending)
-{
- struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
- if (!gensec_socket->wrap) {
- return socket_pending(gensec_socket->socket, npending);
- }
-
- if (gensec_socket->read_buffer.length > 0) {
- *npending = gensec_socket->read_buffer.length;
- return NT_STATUS_OK;
- }
-
- /* This is a lie. We hope the decrypted data will always be
- * less than this value, so the application just gets a short
- * read. Without reading and decrypting it, we can't tell.
- * If the SASL mech does compression, then we just need to
- * manually trigger read events */
- return socket_pending(gensec_socket->socket, npending);
-}
-
-/* Note if an error occours, so we can return it up the stack */
-static void gensec_socket_error_handler(void *private_data, NTSTATUS status)
-{
- struct gensec_socket *gensec_socket = talloc_get_type(private_data, struct gensec_socket);
- if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
- gensec_socket->eof = true;
- } else {
- gensec_socket->error = status;
- }
-}
-
-static void gensec_socket_trigger_read(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval t, void *private_data)
-{
- struct gensec_socket *gensec_socket = talloc_get_type(private_data, struct gensec_socket);
-
- gensec_socket->in_extra_read++;
- gensec_socket->recv_handler(gensec_socket->recv_private, TEVENT_FD_READ);
- gensec_socket->in_extra_read--;
-
- /* It may well be that, having run the recv handler, we still
- * have even more data waiting for us!
- */
- if (gensec_socket->read_buffer.length > 0) {
- /* Schedule this funcion to run again */
- tevent_add_timer(gensec_socket->ev, gensec_socket, timeval_zero(),
- gensec_socket_trigger_read, gensec_socket);
- }
-}
-
-/* These two routines could be changed to use a circular buffer of
- * some kind, or linked lists, or ... */
-static NTSTATUS gensec_socket_recv(struct socket_context *sock, void *buf,
- size_t wantlen, size_t *nread)
-{
- struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
-
- if (!gensec_socket->wrap) {
- return socket_recv(gensec_socket->socket, buf, wantlen, nread);
- }
-
- gensec_socket->error = NT_STATUS_OK;
-
- if (gensec_socket->read_buffer.length == 0) {
- /* Process any data on the socket, into the read buffer. At
- * this point, the socket is not available for read any
- * longer */
- packet_recv(gensec_socket->packet);
-
- if (gensec_socket->eof) {
- *nread = 0;
- return NT_STATUS_OK;
- }
-
- if (!NT_STATUS_IS_OK(gensec_socket->error)) {
- return gensec_socket->error;
- }
-
- if (gensec_socket->read_buffer.length == 0) {
- /* Clearly we don't have the entire SASL packet yet,
- * so it has not been written into the buffer */
- *nread = 0;
- return STATUS_MORE_ENTRIES;
- }
- }
-
-
- *nread = MIN(wantlen, gensec_socket->read_buffer.length);
- memcpy(buf, gensec_socket->read_buffer.data, *nread);
-
- if (gensec_socket->read_buffer.length > *nread) {
- memmove(gensec_socket->read_buffer.data,
- gensec_socket->read_buffer.data + *nread,
- gensec_socket->read_buffer.length - *nread);
- }
-
- gensec_socket->read_buffer.length -= *nread;
- gensec_socket->read_buffer.data = talloc_realloc(gensec_socket,
- gensec_socket->read_buffer.data,
- uint8_t,
- gensec_socket->read_buffer.length);
-
- if (gensec_socket->read_buffer.length &&
- gensec_socket->in_extra_read == 0 &&
- gensec_socket->recv_handler) {
- /* Manually call a read event, to get this moving
- * again (as the socket should be dry, so the normal
- * event handler won't trigger) */
- tevent_add_timer(gensec_socket->ev, gensec_socket, timeval_zero(),
- gensec_socket_trigger_read, gensec_socket);
- }
-
- return NT_STATUS_OK;
-}
-
-/* Completed SASL packet callback. When we have a 'whole' SASL
- * packet, decrypt it, and add it to the read buffer
- *
- * This function (and anything under it) MUST NOT call the event system
- */
-static NTSTATUS gensec_socket_unwrap(void *private_data, DATA_BLOB blob)
-{
- struct gensec_socket *gensec_socket = talloc_get_type(private_data, struct gensec_socket);
- DATA_BLOB unwrapped;
- NTSTATUS nt_status;
- TALLOC_CTX *mem_ctx;
- size_t packet_size;
-
- mem_ctx = talloc_new(gensec_socket);
- if (!mem_ctx) {
- return NT_STATUS_NO_MEMORY;
- }
- nt_status = gensec_unwrap_packets(gensec_socket->gensec_security,
- mem_ctx,
- &blob, &unwrapped,
- &packet_size);
- if (!NT_STATUS_IS_OK(nt_status)) {
- talloc_free(mem_ctx);
- return nt_status;
- }
-
- if (packet_size != blob.length) {
- DEBUG(0, ("gensec_socket_unwrap: Did not consume entire packet!\n"));
- talloc_free(mem_ctx);
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- /* We could change this into a linked list, and have
- * gensec_socket_recv() and gensec_socket_pending() walk the
- * linked list */
-
- if (!data_blob_append(gensec_socket, &gensec_socket->read_buffer,
- unwrapped.data, unwrapped.length)) {
- talloc_free(mem_ctx);
- return NT_STATUS_NO_MEMORY;
- }
-
- talloc_free(mem_ctx);
- return NT_STATUS_OK;
-}
-
-/* when the data is sent, we know we have not been interrupted */
-static void send_callback(void *private_data)
-{
- struct gensec_socket *gensec_socket = talloc_get_type(private_data, struct gensec_socket);
- gensec_socket->interrupted = false;
-}
-
-/*
- send data, but only as much as we allow in one packet.
-
- If this returns STATUS_MORE_ENTRIES, the caller must retry with
- exactly the same data, or a NULL blob.
-*/
-static NTSTATUS gensec_socket_send(struct socket_context *sock,
- const DATA_BLOB *blob, size_t *sendlen)
-{
- NTSTATUS nt_status;
- struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
- DATA_BLOB wrapped;
- TALLOC_CTX *mem_ctx;
-
- if (!gensec_socket->wrap) {
- return socket_send(gensec_socket->socket, blob, sendlen);
- }
-
- *sendlen = 0;
-
- /* We have have been interupted, so the caller should be
- * giving us the same data again. */
- if (gensec_socket->interrupted) {
- packet_queue_run(gensec_socket->packet);
-
- if (!NT_STATUS_IS_OK(gensec_socket->error)) {
- return gensec_socket->error;
- } else if (gensec_socket->interrupted) {
- return STATUS_MORE_ENTRIES;
- } else {
- *sendlen = gensec_socket->orig_send_len;
- gensec_socket->orig_send_len = 0;
- return NT_STATUS_OK;
- }
- }
-
- mem_ctx = talloc_new(gensec_socket);
- if (!mem_ctx) {
- return NT_STATUS_NO_MEMORY;
- }
-
- nt_status = gensec_wrap_packets(gensec_socket->gensec_security,
- mem_ctx,
- blob, &wrapped,
- &gensec_socket->orig_send_len);
- if (!NT_STATUS_IS_OK(nt_status)) {
- talloc_free(mem_ctx);
- return nt_status;
- }
-
- gensec_socket->interrupted = true;
- gensec_socket->error = NT_STATUS_OK;
-
- nt_status = packet_send_callback(gensec_socket->packet,
- wrapped,
- send_callback, gensec_socket);
-
- talloc_free(mem_ctx);
-
- packet_queue_run(gensec_socket->packet);
-
- if (!NT_STATUS_IS_OK(gensec_socket->error)) {
- return gensec_socket->error;
- } else if (gensec_socket->interrupted) {
- return STATUS_MORE_ENTRIES;
- } else {
- *sendlen = gensec_socket->orig_send_len;
- gensec_socket->orig_send_len = 0;
- return NT_STATUS_OK;
- }
-}
-
-/* Turn a normal socket into a potentially GENSEC wrapped socket */
-/* CAREFUL: this function will steal 'current_socket' */
-
-NTSTATUS gensec_socket_init(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- struct socket_context *current_socket,
- struct tevent_context *ev,
- void (*recv_handler)(void *, uint16_t),
- void *recv_private,
- struct socket_context **new_socket)
-{
- struct gensec_socket *gensec_socket;
- struct socket_context *new_sock;
- NTSTATUS nt_status;
-
- nt_status = socket_create_with_ops(mem_ctx, &gensec_socket_ops, &new_sock,
- SOCKET_TYPE_STREAM, current_socket->flags | SOCKET_FLAG_ENCRYPT);
- if (!NT_STATUS_IS_OK(nt_status)) {
- *new_socket = NULL;
- return nt_status;
- }
-
- new_sock->state = current_socket->state;
-
- gensec_socket = talloc(new_sock, struct gensec_socket);
- if (gensec_socket == NULL) {
- *new_socket = NULL;
- talloc_free(new_sock);
- return NT_STATUS_NO_MEMORY;
- }
-
- new_sock->private_data = gensec_socket;
- gensec_socket->socket = current_socket;
-
- /* Nothing to do here, if we are not actually wrapping on this socket */
- if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) &&
- !gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
-
- gensec_socket->wrap = false;
- talloc_steal(gensec_socket, current_socket);
- *new_socket = new_sock;
- return NT_STATUS_OK;
- }
-
- gensec_socket->gensec_security = gensec_security;
-
- gensec_socket->wrap = true;
- gensec_socket->eof = false;
- gensec_socket->error = NT_STATUS_OK;
- gensec_socket->interrupted = false;
- gensec_socket->in_extra_read = 0;
-
- gensec_socket->read_buffer = data_blob(NULL, 0);
-
- gensec_socket->recv_handler = recv_handler;
- gensec_socket->recv_private = recv_private;
- gensec_socket->ev = ev;
-
- gensec_socket->packet = packet_init(gensec_socket);
- if (gensec_socket->packet == NULL) {
- *new_socket = NULL;
- talloc_free(new_sock);
- return NT_STATUS_NO_MEMORY;
- }
-
- packet_set_private(gensec_socket->packet, gensec_socket);
- packet_set_socket(gensec_socket->packet, gensec_socket->socket);
- packet_set_callback(gensec_socket->packet, gensec_socket_unwrap);
- packet_set_full_request(gensec_socket->packet, gensec_socket_full_request);
- packet_set_error_handler(gensec_socket->packet, gensec_socket_error_handler);
- packet_set_serialise(gensec_socket->packet);
-
- /* TODO: full-request that knows about maximum packet size */
-
- talloc_steal(gensec_socket, current_socket);
- *new_socket = new_sock;
- return NT_STATUS_OK;
-}
-
-
-static NTSTATUS gensec_socket_set_option(struct socket_context *sock, const char *option, const char *val)
-{
- set_socket_options(socket_get_fd(sock), option);
- return NT_STATUS_OK;
-}
-
-static char *gensec_socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
-{
- struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
- return socket_get_peer_name(gensec->socket, mem_ctx);
-}
-
-static struct socket_address *gensec_socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
-{
- struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
- return socket_get_peer_addr(gensec->socket, mem_ctx);
-}
-
-static struct socket_address *gensec_socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
-{
- struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
- return socket_get_my_addr(gensec->socket, mem_ctx);
-}
-
-static int gensec_socket_get_fd(struct socket_context *sock)
-{
- struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
- return socket_get_fd(gensec->socket);
-}
-
-static const struct socket_ops gensec_socket_ops = {
- .name = "gensec",
- .fn_init = gensec_socket_init_fn,
- .fn_recv = gensec_socket_recv,
- .fn_send = gensec_socket_send,
- .fn_pending = gensec_socket_pending,
-
- .fn_set_option = gensec_socket_set_option,
-
- .fn_get_peer_name = gensec_socket_get_peer_name,
- .fn_get_peer_addr = gensec_socket_get_peer_addr,
- .fn_get_my_addr = gensec_socket_get_my_addr,
- .fn_get_fd = gensec_socket_get_fd
-};
-
diff --git a/source4/auth/gensec/wscript_build b/source4/auth/gensec/wscript_build
index 1a44a9072c3..3c7cc2e12b4 100755
--- a/source4/auth/gensec/wscript_build
+++ b/source4/auth/gensec/wscript_build
@@ -1,7 +1,7 @@
#!/usr/bin/env python
bld.SAMBA_SUBSYSTEM('gensec_util',
- source='socket.c gensec_tstream.c',
+ source='gensec_tstream.c',
deps='tevent-util tevent samba-util LIBTSOCKET',
autoproto='gensec_proto.h')
@@ -19,21 +19,9 @@ bld.SAMBA_MODULE('gensec_gssapi',
source='gensec_gssapi.c',
subsystem='gensec',
init_function='gensec_gssapi_init',
- allow_warnings=True,
deps='gssapi samba-credentials authkrb5 com_err gensec_util'
)
-
-bld.SAMBA_MODULE('cyrus_sasl',
- source='cyrus_sasl.c',
- subsystem='gensec',
- init_function='gensec_sasl_init',
- deps='samba-credentials sasl2',
- allow_warnings=True,
- enabled=bld.CONFIG_SET('HAVE_SASL')
- )
-
-
bld.SAMBA_PYTHON('pygensec',
source='pygensec.c',
deps='gensec pytalloc-util pyparam_util',
diff --git a/source4/auth/ntlm/auth_util.c b/source4/auth/ntlm/auth_util.c
index 16977fa00a3..3e5a0da59c2 100644
--- a/source4/auth/ntlm/auth_util.c
+++ b/source4/auth/ntlm/auth_util.c
@@ -350,7 +350,9 @@ NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth4_context *auth_conte
if (!SMBNTLMv2encrypt_hash(user_info_temp,
user_info_in->client.account_name,
user_info_in->client.domain_name,
- user_info_in->password.hash.nt->hash, &chall_blob,
+ user_info_in->password.hash.nt->hash,
+ &chall_blob,
+ NULL, /* server_timestamp */
&names_blob,
&lmv2_response, &ntlmv2_response,
&lmv2_session_key, &ntlmv2_session_key)) {
diff --git a/source4/auth/wscript_configure b/source4/auth/wscript_configure
index 1d26cde1398..d25cc0b359d 100644
--- a/source4/auth/wscript_configure
+++ b/source4/auth/wscript_configure
@@ -2,7 +2,3 @@
conf.CHECK_HEADERS('security/pam_appl.h')
conf.CHECK_FUNCS_IN('pam_start', 'pam', checklibc=True)
-
-if (conf.CHECK_HEADERS('sasl/sasl.h') and
- conf.CHECK_FUNCS_IN('sasl_client_init', 'sasl2')):
- conf.DEFINE('HAVE_SASL', 1)
diff --git a/source4/dsdb/tests/python/dsdb_schema_info.py b/source4/dsdb/tests/python/dsdb_schema_info.py
index 28fce1b00f4..8f64f1063c0 100755
--- a/source4/dsdb/tests/python/dsdb_schema_info.py
+++ b/source4/dsdb/tests/python/dsdb_schema_info.py
@@ -30,8 +30,7 @@ import time
import random
sys.path.insert(0, "bin/python")
-import samba
-samba.ensure_external_module("testtools", "testtools")
+import samba.tests
from ldb import SCOPE_BASE, LdbError
diff --git a/source4/heimdal/lib/gssapi/krb5/aeap.c b/source4/heimdal/lib/gssapi/krb5/aeap.c
index 47913e4aec0..fe95ecf0b9c 100644
--- a/source4/heimdal/lib/gssapi/krb5/aeap.c
+++ b/source4/heimdal/lib/gssapi/krb5/aeap.c
@@ -44,17 +44,43 @@ _gk_wrap_iov(OM_uint32 * minor_status,
gss_iov_buffer_desc *iov,
int iov_count)
{
- const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
- krb5_context context;
+ const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
+ krb5_context context;
+ OM_uint32 ret;
+ krb5_keyblock *key;
+ krb5_keytype keytype;
+
+ GSSAPI_KRB5_INIT (&context);
+
+ if (ctx->more_flags & IS_CFX)
+ return _gssapi_wrap_cfx_iov(minor_status, ctx, context,
+ conf_req_flag, conf_state,
+ iov, iov_count);
+
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+ ret = _gsskrb5i_get_token_key(ctx, context, &key);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ krb5_enctype_to_keytype(context, key->keytype, &keytype);
- GSSAPI_KRB5_INIT (&context);
+ switch (keytype) {
+ case KEYTYPE_ARCFOUR:
+ case KEYTYPE_ARCFOUR_56:
+ ret = _gssapi_wrap_iov_arcfour(minor_status, ctx, context,
+ conf_req_flag, conf_state,
+ iov, iov_count, key);
+ break;
- if (ctx->more_flags & IS_CFX)
- return _gssapi_wrap_cfx_iov(minor_status, ctx, context,
- conf_req_flag, conf_state,
- iov, iov_count);
+ default:
+ ret = GSS_S_FAILURE;
+ break;
+ }
- return GSS_S_FAILURE;
+ krb5_free_keyblock(context, key);
+ return ret;
}
OM_uint32 GSSAPI_CALLCONV
@@ -67,6 +93,9 @@ _gk_unwrap_iov(OM_uint32 *minor_status,
{
const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
krb5_context context;
+ OM_uint32 ret;
+ krb5_keytype keytype;
+ krb5_keyblock *key;
GSSAPI_KRB5_INIT (&context);
@@ -74,7 +103,30 @@ _gk_unwrap_iov(OM_uint32 *minor_status,
return _gssapi_unwrap_cfx_iov(minor_status, ctx, context,
conf_state, qop_state, iov, iov_count);
- return GSS_S_FAILURE;
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+ ret = _gsskrb5i_get_token_key(ctx, context, &key);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ krb5_enctype_to_keytype(context, key->keytype, &keytype);
+
+ switch (keytype) {
+ case KEYTYPE_ARCFOUR:
+ case KEYTYPE_ARCFOUR_56:
+ ret = _gssapi_unwrap_iov_arcfour(minor_status, ctx, context,
+ conf_state, qop_state,
+ iov, iov_count, key);
+ break;
+
+ default:
+ ret = GSS_S_FAILURE;
+ break;
+ }
+
+ krb5_free_keyblock(context, key);
+ return ret;
}
OM_uint32 GSSAPI_CALLCONV
@@ -88,6 +140,9 @@ _gk_wrap_iov_length(OM_uint32 * minor_status,
{
const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
krb5_context context;
+ OM_uint32 ret;
+ krb5_keytype keytype;
+ krb5_keyblock *key;
GSSAPI_KRB5_INIT (&context);
@@ -96,5 +151,28 @@ _gk_wrap_iov_length(OM_uint32 * minor_status,
conf_req_flag, qop_req, conf_state,
iov, iov_count);
- return GSS_S_FAILURE;
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+ ret = _gsskrb5i_get_token_key(ctx, context, &key);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ krb5_enctype_to_keytype(context, key->keytype, &keytype);
+
+ switch (keytype) {
+ case KEYTYPE_ARCFOUR:
+ case KEYTYPE_ARCFOUR_56:
+ ret = _gssapi_wrap_iov_length_arcfour(minor_status, ctx, context,
+ conf_req_flag, qop_req, conf_state,
+ iov, iov_count);
+ break;
+
+ default:
+ ret = GSS_S_FAILURE;
+ break;
+ }
+
+ krb5_free_keyblock(context, key);
+ return ret;
}
diff --git a/source4/heimdal/lib/gssapi/krb5/arcfour.c b/source4/heimdal/lib/gssapi/krb5/arcfour.c
index f5e41e4056f..a61f7686e95 100644
--- a/source4/heimdal/lib/gssapi/krb5/arcfour.c
+++ b/source4/heimdal/lib/gssapi/krb5/arcfour.c
@@ -69,7 +69,7 @@
static krb5_error_code
arcfour_mic_key(krb5_context context, krb5_keyblock *key,
- void *cksum_data, size_t cksum_size,
+ const void *cksum_data, size_t cksum_size,
void *key6_data, size_t key6_size)
{
krb5_error_code ret;
@@ -112,30 +112,73 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key,
static krb5_error_code
-arcfour_mic_cksum(krb5_context context,
- krb5_keyblock *key, unsigned usage,
- u_char *sgn_cksum, size_t sgn_cksum_sz,
- const u_char *v1, size_t l1,
- const void *v2, size_t l2,
- const void *v3, size_t l3)
+arcfour_mic_cksum_iov(krb5_context context,
+ krb5_keyblock *key, unsigned usage,
+ u_char *sgn_cksum, size_t sgn_cksum_sz,
+ const u_char *v1, size_t l1,
+ const void *v2, size_t l2,
+ const gss_iov_buffer_desc *iov,
+ int iov_count,
+ const gss_iov_buffer_desc *padding)
{
Checksum CKSUM;
u_char *ptr;
size_t len;
+ size_t ofs = 0;
+ int i;
krb5_crypto crypto;
krb5_error_code ret;
assert(sgn_cksum_sz == 8);
- len = l1 + l2 + l3;
+ len = l1 + l2;
+
+ for (i=0; i < iov_count; i++) {
+ switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+ case GSS_IOV_BUFFER_TYPE_DATA:
+ case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
+ break;
+ default:
+ continue;
+ }
+
+ len += iov[i].buffer.length;
+ }
+
+ if (padding) {
+ len += padding->buffer.length;
+ }
ptr = malloc(len);
if (ptr == NULL)
return ENOMEM;
- memcpy(ptr, v1, l1);
- memcpy(ptr + l1, v2, l2);
- memcpy(ptr + l1 + l2, v3, l3);
+ memcpy(ptr + ofs, v1, l1);
+ ofs += l1;
+ memcpy(ptr + ofs, v2, l2);
+ ofs += l2;
+
+ for (i=0; i < iov_count; i++) {
+ switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+ case GSS_IOV_BUFFER_TYPE_DATA:
+ case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
+ break;
+ default:
+ continue;
+ }
+
+ memcpy(ptr + ofs,
+ iov[i].buffer.value,
+ iov[i].buffer.length);
+ ofs += iov[i].buffer.length;
+ }
+
+ if (padding) {
+ memcpy(ptr + ofs,
+ padding->buffer.value,
+ padding->buffer.length);
+ ofs += padding->buffer.length;
+ }
ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret) {
@@ -149,6 +192,7 @@ arcfour_mic_cksum(krb5_context context,
0,
ptr, len,
&CKSUM);
+ memset(ptr, 0, len);
free(ptr);
if (ret == 0) {
memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz);
@@ -159,6 +203,26 @@ arcfour_mic_cksum(krb5_context context,
return ret;
}
+static krb5_error_code
+arcfour_mic_cksum(krb5_context context,
+ krb5_keyblock *key, unsigned usage,
+ u_char *sgn_cksum, size_t sgn_cksum_sz,
+ const u_char *v1, size_t l1,
+ const void *v2, size_t l2,
+ const void *v3, size_t l3)
+{
+ gss_iov_buffer_desc iov;
+
+ iov.type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ iov.buffer.value = rk_UNCONST(v3);
+ iov.buffer.length = l3;
+
+ return arcfour_mic_cksum_iov(context, key, usage,
+ sgn_cksum, sgn_cksum_sz,
+ v1, l1, v2, l2,
+ &iov, 1, NULL);
+}
+
OM_uint32
_gssapi_get_mic_arcfour(OM_uint32 * minor_status,
@@ -760,3 +824,562 @@ _gssapi_wrap_size_arcfour(OM_uint32 *minor_status,
return GSS_S_COMPLETE;
}
+
+OM_uint32
+_gssapi_wrap_iov_length_arcfour(OM_uint32 *minor_status,
+ gsskrb5_ctx ctx,
+ krb5_context context,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+ size_t data_len = 0;
+ int i;
+ gss_iov_buffer_desc *header = NULL;
+ gss_iov_buffer_desc *padding = NULL;
+ gss_iov_buffer_desc *trailer = NULL;
+
+ *minor_status = 0;
+
+ for (i = 0; i < iov_count; i++) {
+ switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+ case GSS_IOV_BUFFER_TYPE_EMPTY:
+ break;
+ case GSS_IOV_BUFFER_TYPE_DATA:
+ data_len += iov[i].buffer.length;
+ break;
+ case GSS_IOV_BUFFER_TYPE_HEADER:
+ if (header != NULL) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+ header = &iov[i];
+ break;
+ case GSS_IOV_BUFFER_TYPE_TRAILER:
+ if (trailer != NULL) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+ trailer = &iov[i];
+ break;
+ case GSS_IOV_BUFFER_TYPE_PADDING:
+ if (padding != NULL) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+ padding = &iov[i];
+ break;
+ case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
+ break;
+ default:
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
+ if (major_status != GSS_S_COMPLETE) {
+ return major_status;
+ }
+
+ if (IS_DCE_STYLE(ctx)) {
+ size_t len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+ size_t total_len;
+ _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
+ header->buffer.length = total_len;
+ } else {
+ size_t len;
+ size_t total_len;
+ if (padding) {
+ data_len += 1; /* padding */
+ }
+ len = data_len + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+ _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
+ header->buffer.length = total_len - data_len;
+ }
+
+ if (trailer) {
+ trailer->buffer.length = 0;
+ }
+
+ if (padding) {
+ padding->buffer.length = 1;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+_gssapi_wrap_iov_arcfour(OM_uint32 *minor_status,
+ gsskrb5_ctx ctx,
+ krb5_context context,
+ int conf_req_flag,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ krb5_keyblock *key)
+{
+ OM_uint32 major_status, junk;
+ gss_iov_buffer_desc *header, *padding, *trailer;
+ krb5_error_code kret;
+ int32_t seq_number;
+ u_char Klocaldata[16], k6_data[16], *p, *p0;
+ size_t make_len = 0;
+ size_t header_len = 0;
+ size_t data_len = 0;
+ krb5_keyblock Klocal;
+ int i;
+
+ header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+ major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
+ if (major_status != GSS_S_COMPLETE) {
+ return major_status;
+ }
+
+ for (i = 0; i < iov_count; i++) {
+ switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+ case GSS_IOV_BUFFER_TYPE_DATA:
+ break;
+ default:
+ continue;
+ }
+
+ data_len += iov[i].buffer.length;
+ }
+
+ if (padding) {
+ data_len += 1;
+ }
+
+ if (IS_DCE_STYLE(ctx)) {
+ size_t unwrapped_len;
+ unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+ _gssapi_encap_length(unwrapped_len,
+ &make_len,
+ &header_len,
+ GSS_KRB5_MECHANISM);
+ } else {
+ size_t unwrapped_len;
+ unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + data_len;
+ _gssapi_encap_length(unwrapped_len,
+ &make_len,
+ &header_len,
+ GSS_KRB5_MECHANISM);
+ header_len -= data_len;
+ }
+
+ if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) {
+ major_status = _gk_allocate_buffer(minor_status, header,
+ header_len);
+ if (major_status != GSS_S_COMPLETE)
+ goto failure;
+ } else if (header->buffer.length < header_len) {
+ *minor_status = KRB5_BAD_MSIZE;
+ major_status = GSS_S_FAILURE;
+ goto failure;
+ } else {
+ header->buffer.length = header_len;
+ }
+
+ if (padding) {
+ if (GSS_IOV_BUFFER_FLAGS(padding->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) {
+ major_status = _gk_allocate_buffer(minor_status, padding, 1);
+ if (major_status != GSS_S_COMPLETE)
+ goto failure;
+ } else if (padding->buffer.length < 1) {
+ *minor_status = KRB5_BAD_MSIZE;
+ major_status = GSS_S_FAILURE;
+ goto failure;
+ } else {
+ padding->buffer.length = 1;
+ }
+ memset(padding->buffer.value, 1, 1);
+ }
+
+ if (trailer) {
+ trailer->buffer.length = 0;
+ trailer->buffer.value = NULL;
+ }
+
+ p0 = _gssapi_make_mech_header(header->buffer.value,
+ make_len,
+ GSS_KRB5_MECHANISM);
+ p = p0;
+
+ *p++ = 0x02; /* TOK_ID */
+ *p++ = 0x01;
+ *p++ = 0x11; /* SGN_ALG */
+ *p++ = 0x00;
+ if (conf_req_flag) {
+ *p++ = 0x10; /* SEAL_ALG */
+ *p++ = 0x00;
+ } else {
+ *p++ = 0xff; /* SEAL_ALG */
+ *p++ = 0xff;
+ }
+ *p++ = 0xff; /* Filler */
+ *p++ = 0xff;
+
+ p = NULL;
+
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+ krb5_auth_con_getlocalseqnumber(context,
+ ctx->auth_context,
+ &seq_number);
+ _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8);
+
+ krb5_auth_con_setlocalseqnumber(context,
+ ctx->auth_context,
+ ++seq_number);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+
+ memset(p0 + 8 + 4,
+ (ctx->more_flags & LOCAL) ? 0 : 0xff,
+ 4);
+
+ krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
+
+ /* Sign Data */
+ kret = arcfour_mic_cksum_iov(context,
+ key, KRB5_KU_USAGE_SEAL,
+ p0 + 16, 8, /* SGN_CKSUM */
+ p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
+ p0 + 24, 8, /* Confounder */
+ iov, iov_count, /* Data + SignOnly */
+ padding); /* padding */
+ if (kret) {
+ *minor_status = kret;
+ major_status = GSS_S_FAILURE;
+ goto failure;
+ }
+
+ Klocal.keytype = key->keytype;
+ Klocal.keyvalue.data = Klocaldata;
+ Klocal.keyvalue.length = sizeof(Klocaldata);
+
+ for (i = 0; i < 16; i++) {
+ Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
+ }
+ kret = arcfour_mic_key(context, &Klocal,
+ p0 + 8, 4, /* SND_SEQ */
+ k6_data, sizeof(k6_data));
+ memset(Klocaldata, 0, sizeof(Klocaldata));
+ if (kret) {
+ *minor_status = kret;
+ major_status = GSS_S_FAILURE;
+ goto failure;
+ }
+
+ if (conf_req_flag) {
+ EVP_CIPHER_CTX rc4_key;
+
+ EVP_CIPHER_CTX_init(&rc4_key);
+ EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
+
+ /* Confounder */
+ EVP_Cipher(&rc4_key, p0 + 24, p0 + 24, 8);
+
+ /* Seal Data */
+ for (i=0; i < iov_count; i++) {
+ switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+ case GSS_IOV_BUFFER_TYPE_DATA:
+ break;
+ default:
+ continue;
+ }
+
+ EVP_Cipher(&rc4_key, iov[i].buffer.value,
+ iov[i].buffer.value, iov[i].buffer.length);
+ }
+
+ /* Padding */
+ if (padding) {
+ EVP_Cipher(&rc4_key, padding->buffer.value,
+ padding->buffer.value, padding->buffer.length);
+ }
+
+ EVP_CIPHER_CTX_cleanup(&rc4_key);
+ }
+ memset(k6_data, 0, sizeof(k6_data));
+
+ kret = arcfour_mic_key(context, key,
+ p0 + 16, 8, /* SGN_CKSUM */
+ k6_data, sizeof(k6_data));
+ if (kret) {
+ *minor_status = kret;
+ major_status = GSS_S_FAILURE;
+ }
+
+ {
+ EVP_CIPHER_CTX rc4_key;
+
+ EVP_CIPHER_CTX_init(&rc4_key);
+ EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
+ EVP_Cipher(&rc4_key, p0 + 8, p0 + 8, 8); /* SND_SEQ */
+ EVP_CIPHER_CTX_cleanup(&rc4_key);
+
+ memset(k6_data, 0, sizeof(k6_data));
+ }
+
+ if (conf_state)
+ *conf_state = conf_req_flag;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+
+failure:
+
+ gss_release_iov_buffer(&junk, iov, iov_count);
+
+ return major_status;
+}
+
+OM_uint32
+_gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status,
+ gsskrb5_ctx ctx,
+ krb5_context context,
+ int *pconf_state,
+ gss_qop_t *pqop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ krb5_keyblock *key)
+{
+ OM_uint32 major_status;
+ gss_iov_buffer_desc *header, *padding, *trailer;
+ krb5_keyblock Klocal;
+ uint8_t Klocaldata[16];
+ uint8_t k6_data[16], snd_seq[8], Confounder[8];
+ uint8_t cksum_data[8];
+ uint8_t *_p = NULL;
+ const uint8_t *p, *p0;
+ size_t verify_len = 0;
+ uint32_t seq_number;
+ size_t hlen = 0;
+ int conf_state;
+ int cmp;
+ size_t i;
+ krb5_error_code kret;
+ OM_uint32 ret;
+
+ if (pconf_state != NULL) {
+ *pconf_state = 0;
+ }
+ if (pqop_state != NULL) {
+ *pqop_state = 0;
+ }
+
+ header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+ /* Check if the packet is correct */
+ major_status = _gk_verify_buffers(minor_status,
+ ctx,
+ header,
+ padding,
+ trailer);
+ if (major_status != GSS_S_COMPLETE) {
+ return major_status;
+ }
+
+ if (padding != NULL && padding->buffer.length != 1) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ if (IS_DCE_STYLE(context)) {
+ verify_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE +
+ GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE;
+ if (header->buffer.length > verify_len) {
+ return GSS_S_BAD_MECH;
+ }
+ } else {
+ verify_len = header->buffer.length;
+ }
+ _p = header->buffer.value;
+
+ ret = _gssapi_verify_mech_header(&_p,
+ verify_len,
+ GSS_KRB5_MECHANISM);
+ if (ret) {
+ return ret;
+ }
+ p0 = _p;
+
+ /* length of mech header */
+ hlen = (p0 - (uint8_t *)header->buffer.value);
+ hlen += GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+
+ if (hlen > header->buffer.length) {
+ return GSS_S_BAD_MECH;
+ }
+
+ p = p0;
+
+ if (memcmp(p, "\x02\x01", 2) != 0)
+ return GSS_S_BAD_SIG;
+ p += 2;
+ if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
+ return GSS_S_BAD_SIG;
+ p += 2;
+
+ if (memcmp (p, "\x10\x00", 2) == 0)
+ conf_state = 1;
+ else if (memcmp (p, "\xff\xff", 2) == 0)
+ conf_state = 0;
+ else
+ return GSS_S_BAD_SIG;
+
+ p += 2;
+ if (memcmp (p, "\xff\xff", 2) != 0)
+ return GSS_S_BAD_MIC;
+ p = NULL;
+
+ kret = arcfour_mic_key(context,
+ key,
+ p0 + 16, /* SGN_CKSUM */
+ 8, /* SGN_CKSUM_LEN */
+ k6_data,
+ sizeof(k6_data));
+ if (kret) {
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ {
+ EVP_CIPHER_CTX rc4_key;
+
+ EVP_CIPHER_CTX_init(&rc4_key);
+ EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
+ EVP_Cipher(&rc4_key, snd_seq, p0 + 8, 8); /* SND_SEQ */
+ EVP_CIPHER_CTX_cleanup(&rc4_key);
+
+ memset(k6_data, 0, sizeof(k6_data));
+ }
+
+ _gsskrb5_decode_be_om_uint32(snd_seq, &seq_number);
+
+ if (ctx->more_flags & LOCAL) {
+ cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4);
+ } else {
+ cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4);
+ }
+ if (cmp != 0) {
+ *minor_status = 0;
+ return GSS_S_BAD_MIC;
+ }
+
+ if (ctx->more_flags & LOCAL) {
+ cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4);
+ } else {
+ cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4);
+ }
+ if (cmp != 0) {
+ *minor_status = 0;
+ return GSS_S_BAD_MIC;
+ }
+
+ /* keyblock */
+ Klocal.keytype = key->keytype;
+ Klocal.keyvalue.data = Klocaldata;
+ Klocal.keyvalue.length = sizeof(Klocaldata);
+
+ for (i = 0; i < 16; i++) {
+ Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
+ }
+
+ kret = arcfour_mic_key(context,
+ &Klocal,
+ snd_seq,
+ 4,
+ k6_data, sizeof(k6_data));
+ memset(Klocaldata, 0, sizeof(Klocaldata));
+ if (kret) {
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ if (conf_state == 1) {
+ EVP_CIPHER_CTX rc4_key;
+
+ EVP_CIPHER_CTX_init(&rc4_key);
+ EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
+
+ /* Confounder */
+ EVP_Cipher(&rc4_key, Confounder, p0 + 24, 8);
+
+ /* Data */
+ for (i = 0; i < iov_count; i++) {
+ switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+ case GSS_IOV_BUFFER_TYPE_DATA:
+ break;
+ default:
+ continue;
+ }
+
+ EVP_Cipher(&rc4_key, iov[i].buffer.value,
+ iov[i].buffer.value, iov[i].buffer.length);
+ }
+
+ /* Padding */
+ if (padding) {
+ EVP_Cipher(&rc4_key, padding->buffer.value,
+ padding->buffer.value, padding->buffer.length);
+ }
+
+ EVP_CIPHER_CTX_cleanup(&rc4_key);
+ } else {
+ /* Confounder */
+ memcpy(Confounder, p0 + 24, 8);
+ }
+ memset(k6_data, 0, sizeof(k6_data));
+
+ /* Prepare the buffer for signing */
+ kret = arcfour_mic_cksum_iov(context,
+ key, KRB5_KU_USAGE_SEAL,
+ cksum_data, sizeof(cksum_data),
+ p0, 8,
+ Confounder, sizeof(Confounder),
+ iov, iov_count,
+ padding);
+ if (kret) {
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */
+ if (cmp != 0) {
+ *minor_status = 0;
+ return GSS_S_BAD_MIC;
+ }
+
+ if (padding) {
+ size_t plen;
+
+ ret = _gssapi_verify_pad(&padding->buffer, 1, &plen);
+ if (ret) {
+ *minor_status = 0;
+ return ret;
+ }
+ }
+
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+ ret = _gssapi_msg_order_check(ctx->order, seq_number);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (pconf_state) {
+ *pconf_state = conf_state;
+ }
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/krb5/decapsulate.c b/source4/heimdal/lib/gssapi/krb5/decapsulate.c
index 640c064d0bf..86085f56950 100644
--- a/source4/heimdal/lib/gssapi/krb5/decapsulate.c
+++ b/source4/heimdal/lib/gssapi/krb5/decapsulate.c
@@ -190,6 +190,9 @@ _gssapi_verify_pad(gss_buffer_t wrapped_token,
size_t padlength;
int i;
+ if (wrapped_token->length < 1)
+ return GSS_S_BAD_MECH;
+
pad = (u_char *)wrapped_token->value + wrapped_token->length - 1;
padlength = *pad;
diff --git a/source4/heimdal_build/wscript_configure b/source4/heimdal_build/wscript_configure
index 90df14cdbbc..e49c9c99bb8 100755
--- a/source4/heimdal_build/wscript_configure
+++ b/source4/heimdal_build/wscript_configure
@@ -94,6 +94,7 @@ conf.define('HAVE_GSSKRB5_GET_SUBKEY', 1)
conf.define('HAVE_GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT', 1)
conf.define('HAVE_GSS_IMPORT_CRED', 1)
conf.define('HAVE_GSS_EXPORT_CRED', 1)
+conf.define('HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X', 1)
conf.define('HAVE_GSSAPI', 1)
conf.define('HAVE_ADDR_TYPE_IN_KRB5_ADDRESS', 1)
conf.define('HAVE_CHECKSUM_IN_KRB5_CHECKSUM', 1)
diff --git a/source4/ldap_server/ldap_bind.c b/source4/ldap_server/ldap_bind.c
index 69a6b6153b0..99ca148547c 100644
--- a/source4/ldap_server/ldap_bind.c
+++ b/source4/ldap_server/ldap_bind.c
@@ -45,6 +45,23 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
DEBUG(10, ("BindSimple dn: %s\n",req->dn));
+ reply = ldapsrv_init_reply(call, LDAP_TAG_BindResponse);
+ if (!reply) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (req->dn != NULL &&
+ strlen(req->dn) != 0 &&
+ call->conn->require_strong_auth > LDAP_SERVER_REQUIRE_STRONG_AUTH_NO &&
+ call->conn->sockets.active != call->conn->sockets.tls)
+ {
+ status = NT_STATUS_NETWORK_ACCESS_DENIED;
+ result = LDAP_STRONG_AUTH_REQUIRED;
+ errstr = talloc_asprintf(reply,
+ "BindSimple: Transport encryption required.");
+ goto do_reply;
+ }
+
status = crack_auto_name_to_nt4_name(call, call->conn->connection->event.ctx, call->conn->lp_ctx, req->dn, &nt4_domain, &nt4_account);
if (NT_STATUS_IS_OK(status)) {
status = authenticate_username_pw(call,
@@ -58,11 +75,6 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
&session_info);
}
- reply = ldapsrv_init_reply(call, LDAP_TAG_BindResponse);
- if (!reply) {
- return NT_STATUS_NO_MEMORY;
- }
-
if (NT_STATUS_IS_OK(status)) {
result = LDAP_SUCCESS;
errstr = NULL;
@@ -86,6 +98,7 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
errstr = talloc_asprintf(reply, "Simple Bind Failed: %s", nt_errstr(status));
}
+do_reply:
resp = &reply->msg->r.BindResponse;
resp->response.resultcode = result;
resp->response.errormessage = errstr;
@@ -181,6 +194,7 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN);
gensec_want_feature(conn->gensec, GENSEC_FEATURE_SEAL);
gensec_want_feature(conn->gensec, GENSEC_FEATURE_ASYNC_REPLIES);
+ gensec_want_feature(conn->gensec, GENSEC_FEATURE_LDAP_STYLE);
status = gensec_start_mech_by_sasl_name(conn->gensec, req->creds.SASL.mechanism);
@@ -217,7 +231,6 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
result = LDAP_SASL_BIND_IN_PROGRESS;
errstr = NULL;
} else if (NT_STATUS_IS_OK(status)) {
- struct auth_session_info *old_session_info=NULL;
struct ldapsrv_sasl_postprocess_context *context = NULL;
result = LDAP_SUCCESS;
@@ -262,17 +275,38 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
status = NT_STATUS_NO_MEMORY;
}
}
+ } else {
+ switch (call->conn->require_strong_auth) {
+ case LDAP_SERVER_REQUIRE_STRONG_AUTH_NO:
+ break;
+ case LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS:
+ if (call->conn->sockets.active == call->conn->sockets.tls) {
+ break;
+ }
+ status = NT_STATUS_NETWORK_ACCESS_DENIED;
+ result = LDAP_STRONG_AUTH_REQUIRED;
+ errstr = talloc_asprintf(reply,
+ "SASL:[%s]: not allowed if TLS is used.",
+ req->creds.SASL.mechanism);
+ break;
+ case LDAP_SERVER_REQUIRE_STRONG_AUTH_YES:
+ status = NT_STATUS_NETWORK_ACCESS_DENIED;
+ result = LDAP_STRONG_AUTH_REQUIRED;
+ errstr = talloc_asprintf(reply,
+ "SASL:[%s]: Sign or Seal are required.",
+ req->creds.SASL.mechanism);
+ break;
+ }
}
if (result != LDAP_SUCCESS) {
- conn->session_info = old_session_info;
} else if (!NT_STATUS_IS_OK(status)) {
- conn->session_info = old_session_info;
result = LDAP_OPERATIONS_ERROR;
errstr = talloc_asprintf(reply,
"SASL:[%s]: Failed to setup SASL socket: %s",
req->creds.SASL.mechanism, nt_errstr(status));
} else {
+ struct auth_session_info *old_session_info=NULL;
old_session_info = conn->session_info;
conn->session_info = NULL;
diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c
index 691266cfabf..f4134d76bd6 100644
--- a/source4/ldap_server/ldap_server.c
+++ b/source4/ldap_server/ldap_server.c
@@ -334,6 +334,12 @@ static void ldapsrv_accept(struct stream_connection *c,
conn->sockets.active = conn->sockets.raw;
+ if (conn->is_privileged) {
+ conn->require_strong_auth = LDAP_SERVER_REQUIRE_STRONG_AUTH_NO;
+ } else {
+ conn->require_strong_auth = lpcfg_ldap_server_require_strong_auth(conn->lp_ctx);
+ }
+
if (!NT_STATUS_IS_OK(ldapsrv_backend_Init(conn))) {
ldapsrv_terminate_connection(conn, "backend Init failed");
return;
@@ -934,6 +940,7 @@ static void ldapsrv_task_init(struct task_server *task)
lpcfg_tls_cafile(ldap_service, task->lp_ctx),
lpcfg_tls_crlfile(ldap_service, task->lp_ctx),
lpcfg_tls_dhpfile(ldap_service, task->lp_ctx),
+ lpcfg_tls_priority(task->lp_ctx),
&ldap_service->tls_params);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("ldapsrv failed tstream_tls_params_server - %s\n",
diff --git a/source4/ldap_server/ldap_server.h b/source4/ldap_server/ldap_server.h
index 6f8b433a1cd..87a71630881 100644
--- a/source4/ldap_server/ldap_server.h
+++ b/source4/ldap_server/ldap_server.h
@@ -22,6 +22,7 @@
#include "lib/socket/socket.h"
#include "lib/stream/packet.h"
#include "system/network.h"
+#include "lib/param/loadparm.h"
struct ldapsrv_connection {
struct loadparm_context *lp_ctx;
@@ -42,6 +43,7 @@ struct ldapsrv_connection {
bool global_catalog;
bool is_privileged;
+ enum ldap_server_require_strong_auth require_strong_auth;
struct {
int initial_timeout;
diff --git a/source4/lib/tls/tls.c b/source4/lib/tls/tls.c
index 2fe4ff7a3fc..f2197e6c3b5 100644
--- a/source4/lib/tls/tls.c
+++ b/source4/lib/tls/tls.c
@@ -31,7 +31,7 @@
#if ENABLE_GNUTLS
#include <gnutls/gnutls.h>
-#define DH_BITS 1024
+#define DH_BITS 2048
#if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T)
typedef gnutls_datum gnutls_datum_t;
diff --git a/source4/lib/tls/tls.h b/source4/lib/tls/tls.h
index ed3c81ee2b4..e600c89cceb 100644
--- a/source4/lib/tls/tls.h
+++ b/source4/lib/tls/tls.h
@@ -45,6 +45,11 @@ struct socket_context *tls_init_server(struct tls_params *parms,
struct tevent_fd *fde,
const char *plain_chars);
+void tls_cert_generate(TALLOC_CTX *mem_ctx,
+ const char *hostname,
+ const char *keyfile, const char *certfile,
+ const char *cafile);
+
/*
call tls_init_client() on each new client connection
*/
@@ -63,9 +68,33 @@ const struct socket_ops *socket_tls_ops(enum socket_type type);
struct tstream_context;
struct tstream_tls_params;
+enum tls_verify_peer_state {
+ TLS_VERIFY_PEER_NO_CHECK = 0,
+#define TLS_VERIFY_PEER_NO_CHECK_STRING "no_check"
+
+ TLS_VERIFY_PEER_CA_ONLY = 10,
+#define TLS_VERIFY_PEER_CA_ONLY_STRING "ca_only"
+
+ TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE = 20,
+#define TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE_STRING \
+ "ca_and_name_if_available"
+
+ TLS_VERIFY_PEER_CA_AND_NAME = 30,
+#define TLS_VERIFY_PEER_CA_AND_NAME_STRING "ca_and_name"
+
+ TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE = 9999,
+#define TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE_STRING \
+ "as_strict_as_possible"
+};
+
+const char *tls_verify_peer_string(enum tls_verify_peer_state verify_peer);
+
NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
const char *ca_file,
const char *crl_file,
+ const char *tls_priority,
+ enum tls_verify_peer_state verify_peer,
+ const char *peer_name,
struct tstream_tls_params **_tlsp);
NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx,
@@ -76,6 +105,7 @@ NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx,
const char *ca_file,
const char *crl_file,
const char *dhp_file,
+ const char *tls_priority,
struct tstream_tls_params **_params);
bool tstream_tls_params_enabled(struct tstream_tls_params *params);
@@ -85,7 +115,7 @@ struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
struct tstream_context *plain_stream,
struct tstream_tls_params *tls_params,
const char *location);
-#define tstream_tls_connect_send(mem_ctx, ev, plain_stream, tls_params); \
+#define tstream_tls_connect_send(mem_ctx, ev, plain_stream, tls_params) \
_tstream_tls_connect_send(mem_ctx, ev, plain_stream, tls_params, __location__)
int tstream_tls_connect_recv(struct tevent_req *req,
diff --git a/source4/lib/tls/tls_tstream.c b/source4/lib/tls/tls_tstream.c
index b907d0a4d30..2ccb9090eba 100644
--- a/source4/lib/tls/tls_tstream.c
+++ b/source4/lib/tls/tls_tstream.c
@@ -20,22 +20,64 @@
#include "includes.h"
#include "system/network.h"
#include "system/filesys.h"
+#include "system/time.h"
#include "../util/tevent_unix.h"
#include "../lib/tsocket/tsocket.h"
#include "../lib/tsocket/tsocket_internal.h"
+#include "../lib/util/util_net.h"
#include "lib/tls/tls.h"
#if ENABLE_GNUTLS
#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
-#define DH_BITS 1024
+#define DH_BITS 2048
#if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T)
typedef gnutls_datum gnutls_datum_t;
#endif
+/*
+ * define our own values in a high range
+ */
+#ifndef HAVE_DECL_GNUTLS_CERT_EXPIRED
+#define GNUTLS_CERT_EXPIRED 0x10000000
+#define REQUIRE_CERT_TIME_CHECKS 1
+#endif
+#ifndef HAVE_DECL_GNUTLS_CERT_NOT_ACTIVATED
+#define GNUTLS_CERT_NOT_ACTIVATED 0x20000000
+#ifndef REQUIRE_CERT_TIME_CHECKS
+#define REQUIRE_CERT_TIME_CHECKS 1
+#endif
+#endif
+#ifndef HAVE_DECL_GNUTLS_CERT_UNEXPECTED_OWNER
+#define GNUTLS_CERT_UNEXPECTED_OWNER 0x40000000
+#endif
+
#endif /* ENABLE_GNUTLS */
+const char *tls_verify_peer_string(enum tls_verify_peer_state verify_peer)
+{
+ switch (verify_peer) {
+ case TLS_VERIFY_PEER_NO_CHECK:
+ return TLS_VERIFY_PEER_NO_CHECK_STRING;
+
+ case TLS_VERIFY_PEER_CA_ONLY:
+ return TLS_VERIFY_PEER_CA_ONLY_STRING;
+
+ case TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE:
+ return TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE_STRING;
+
+ case TLS_VERIFY_PEER_CA_AND_NAME:
+ return TLS_VERIFY_PEER_CA_AND_NAME_STRING;
+
+ case TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE:
+ return TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE_STRING;
+ }
+
+ return "unknown tls_verify_peer_state";
+}
+
static const struct tstream_context_ops tstream_tls_ops;
struct tstream_tls {
@@ -46,6 +88,9 @@ struct tstream_tls {
gnutls_session tls_session;
#endif /* ENABLE_GNUTLS */
+ enum tls_verify_peer_state verify_peer;
+ const char *peer_name;
+
struct tevent_context *current_ev;
struct tevent_immediate *retry_im;
@@ -868,8 +913,11 @@ struct tstream_tls_params {
#if ENABLE_GNUTLS
gnutls_certificate_credentials x509_cred;
gnutls_dh_params dh_params;
+ const char *tls_priority;
#endif /* ENABLE_GNUTLS */
bool tls_enabled;
+ enum tls_verify_peer_state verify_peer;
+ const char *peer_name;
};
static int tstream_tls_params_destructor(struct tstream_tls_params *tlsp)
@@ -895,6 +943,9 @@ bool tstream_tls_params_enabled(struct tstream_tls_params *tlsp)
NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
const char *ca_file,
const char *crl_file,
+ const char *tls_priority,
+ enum tls_verify_peer_state verify_peer,
+ const char *peer_name,
struct tstream_tls_params **_tlsp)
{
#if ENABLE_GNUTLS
@@ -912,6 +963,21 @@ NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
talloc_set_destructor(tlsp, tstream_tls_params_destructor);
+ tlsp->verify_peer = verify_peer;
+ if (peer_name != NULL) {
+ tlsp->peer_name = talloc_strdup(tlsp, peer_name);
+ if (tlsp->peer_name == NULL) {
+ talloc_free(tlsp);
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else if (tlsp->verify_peer >= TLS_VERIFY_PEER_CA_AND_NAME) {
+ DEBUG(0,("TLS failed to missing peer_name - "
+ "with 'tls verify peer = %s'\n",
+ tls_verify_peer_string(tlsp->verify_peer)));
+ talloc_free(tlsp);
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred);
if (ret != GNUTLS_E_SUCCESS) {
DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
@@ -919,7 +985,7 @@ NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
return NT_STATUS_NO_MEMORY;
}
- if (ca_file && *ca_file) {
+ if (ca_file && *ca_file && file_exist(ca_file)) {
ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
ca_file,
GNUTLS_X509_FMT_PEM);
@@ -929,9 +995,16 @@ NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
talloc_free(tlsp);
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
+ } else if (tlsp->verify_peer >= TLS_VERIFY_PEER_CA_ONLY) {
+ DEBUG(0,("TLS failed to missing cafile %s - "
+ "with 'tls verify peer = %s'\n",
+ ca_file,
+ tls_verify_peer_string(tlsp->verify_peer)));
+ talloc_free(tlsp);
+ return NT_STATUS_INVALID_PARAMETER_MIX;
}
- if (crl_file && *crl_file) {
+ if (crl_file && *crl_file && file_exist(crl_file)) {
ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred,
crl_file,
GNUTLS_X509_FMT_PEM);
@@ -941,6 +1014,19 @@ NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
talloc_free(tlsp);
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
+ } else if (tlsp->verify_peer >= TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE) {
+ DEBUG(0,("TLS failed to missing crlfile %s - "
+ "with 'tls verify peer = %s'\n",
+ crl_file,
+ tls_verify_peer_string(tlsp->verify_peer)));
+ talloc_free(tlsp);
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ tlsp->tls_priority = talloc_strdup(tlsp, tls_priority);
+ if (tlsp->tls_priority == NULL) {
+ talloc_free(tlsp);
+ return NT_STATUS_NO_MEMORY;
}
tlsp->tls_enabled = true;
@@ -964,6 +1050,7 @@ struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
{
struct tevent_req *req;
struct tstream_tls_connect_state *state;
+ const char *error_pos;
#if ENABLE_GNUTLS
struct tstream_tls *tlss;
int ret;
@@ -988,6 +1075,13 @@ struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
talloc_set_destructor(tlss, tstream_tls_destructor);
tlss->plain_stream = plain_stream;
+ tlss->verify_peer = tls_params->verify_peer;
+ if (tls_params->peer_name != NULL) {
+ tlss->peer_name = talloc_strdup(tlss, tls_params->peer_name);
+ if (tevent_req_nomem(tlss->peer_name, req)) {
+ return tevent_req_post(req, ev);
+ }
+ }
tlss->current_ev = ev;
tlss->retry_im = tevent_create_immediate(tlss);
@@ -1002,9 +1096,12 @@ struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- ret = gnutls_set_default_priority(tlss->tls_session);
+ ret = gnutls_priority_set_direct(tlss->tls_session,
+ tls_params->tls_priority,
+ &error_pos);
if (ret != GNUTLS_E_SUCCESS) {
- DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
+ DEBUG(0,("TLS %s - %s. Check 'tls priority' option at '%s'\n",
+ __location__, gnutls_strerror(ret), error_pos));
tevent_req_error(req, EINVAL);
return tevent_req_post(req, ev);
}
@@ -1061,8 +1158,6 @@ int tstream_tls_connect_recv(struct tevent_req *req,
return 0;
}
-extern void tls_cert_generate(TALLOC_CTX *, const char *, const char *, const char *, const char *);
-
/*
initialise global tls state
*/
@@ -1074,6 +1169,7 @@ NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx,
const char *ca_file,
const char *crl_file,
const char *dhp_file,
+ const char *tls_priority,
struct tstream_tls_params **_tlsp)
{
struct tstream_tls_params *tlsp;
@@ -1204,6 +1300,12 @@ NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx,
gnutls_certificate_set_dh_params(tlsp->x509_cred, tlsp->dh_params);
+ tlsp->tls_priority = talloc_strdup(tlsp, tls_priority);
+ if (tlsp->tls_priority == NULL) {
+ talloc_free(tlsp);
+ return NT_STATUS_NO_MEMORY;
+ }
+
tlsp->tls_enabled = true;
#else /* ENABLE_GNUTLS */
@@ -1230,6 +1332,7 @@ struct tevent_req *_tstream_tls_accept_send(TALLOC_CTX *mem_ctx,
struct tevent_req *req;
struct tstream_tls_accept_state *state;
struct tstream_tls *tlss;
+ const char *error_pos;
#if ENABLE_GNUTLS
int ret;
#endif /* ENABLE_GNUTLS */
@@ -1267,9 +1370,12 @@ struct tevent_req *_tstream_tls_accept_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- ret = gnutls_set_default_priority(tlss->tls_session);
+ ret = gnutls_priority_set_direct(tlss->tls_session,
+ tlsp->tls_priority,
+ &error_pos);
if (ret != GNUTLS_E_SUCCESS) {
- DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
+ DEBUG(0,("TLS %s - %s. Check 'tls priority' option at '%s'\n",
+ __location__, gnutls_strerror(ret), error_pos));
tevent_req_error(req, EINVAL);
return tevent_req_post(req, ev);
}
@@ -1343,6 +1449,170 @@ static void tstream_tls_retry_handshake(struct tstream_context *stream)
return;
}
+ if (tlss->verify_peer >= TLS_VERIFY_PEER_CA_ONLY) {
+ unsigned int status = UINT32_MAX;
+ bool ip = true;
+ const char *hostname = NULL;
+#ifndef HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3
+ bool need_crt_checks = false;
+#endif
+
+ if (tlss->peer_name != NULL) {
+ ip = is_ipaddress(tlss->peer_name);
+ }
+
+ if (!ip) {
+ hostname = tlss->peer_name;
+ }
+
+ if (tlss->verify_peer == TLS_VERIFY_PEER_CA_ONLY) {
+ hostname = NULL;
+ }
+
+ if (tlss->verify_peer >= TLS_VERIFY_PEER_CA_AND_NAME) {
+ if (hostname == NULL) {
+ DEBUG(1,("TLS %s - no hostname available for "
+ "verify_peer[%s] and peer_name[%s]\n",
+ __location__,
+ tls_verify_peer_string(tlss->verify_peer),
+ tlss->peer_name));
+ tlss->error = EINVAL;
+ tevent_req_error(req, tlss->error);
+ return;
+ }
+ }
+
+#ifdef HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3
+ ret = gnutls_certificate_verify_peers3(tlss->tls_session,
+ hostname,
+ &status);
+ if (ret != GNUTLS_E_SUCCESS) {
+ DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
+ tlss->error = EIO;
+ tevent_req_error(req, tlss->error);
+ return;
+ }
+#else /* not HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3 */
+ ret = gnutls_certificate_verify_peers2(tlss->tls_session, &status);
+ if (ret != GNUTLS_E_SUCCESS) {
+ DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
+ tlss->error = EIO;
+ tevent_req_error(req, tlss->error);
+ return;
+ }
+
+ if (status == 0) {
+ if (hostname != NULL) {
+ need_crt_checks = true;
+ }
+#ifdef REQUIRE_CERT_TIME_CHECKS
+ need_crt_checks = true;
+#endif
+ }
+
+ if (need_crt_checks) {
+ gnutls_x509_crt crt;
+ const gnutls_datum *cert_list;
+ unsigned int cert_list_size = 0;
+#ifdef REQUIRE_CERT_TIME_CHECKS
+ time_t now = time(NULL);
+ time_t tret = -1;
+#endif
+
+ cert_list = gnutls_certificate_get_peers(tlss->tls_session,
+ &cert_list_size);
+ if (cert_list == NULL) {
+ cert_list_size = 0;
+ }
+ if (cert_list_size == 0) {
+ DEBUG(1,("TLS %s - cert_list_size == 0\n",
+ __location__));
+ tlss->error = EIO;
+ tevent_req_error(req, tlss->error);
+ return;
+ }
+
+ ret = gnutls_x509_crt_init(&crt);
+ if (ret != GNUTLS_E_SUCCESS) {
+ DEBUG(1,("TLS %s - %s\n", __location__,
+ gnutls_strerror(ret)));
+ tlss->error = EIO;
+ tevent_req_error(req, tlss->error);
+ return;
+ }
+ ret = gnutls_x509_crt_import(crt,
+ &cert_list[0],
+ GNUTLS_X509_FMT_DER);
+ if (ret != GNUTLS_E_SUCCESS) {
+ DEBUG(1,("TLS %s - %s\n", __location__,
+ gnutls_strerror(ret)));
+ gnutls_x509_crt_deinit(crt);
+ tlss->error = EIO;
+ tevent_req_error(req, tlss->error);
+ return;
+ }
+
+ if (hostname != NULL) {
+ ret = gnutls_x509_crt_check_hostname(crt,
+ hostname);
+ if (ret == 0) {
+ status |= GNUTLS_CERT_INVALID;
+ status |= GNUTLS_CERT_UNEXPECTED_OWNER;
+ }
+ }
+
+#ifndef HAVE_DECL_GNUTLS_CERT_NOT_ACTIVATED
+ /*
+ * GNUTLS_CERT_NOT_ACTIVATED is defined by ourself
+ */
+ tret = gnutls_x509_crt_get_activation_time(crt);
+ if ((tret == -1) || (now > tret)) {
+ status |= GNUTLS_CERT_INVALID;
+ status |= GNUTLS_CERT_NOT_ACTIVATED;
+ }
+#endif
+#ifndef HAVE_DECL_GNUTLS_CERT_EXPIRED
+ /*
+ * GNUTLS_CERT_EXPIRED is defined by ourself
+ */
+ tret = gnutls_certificate_expiration_time_peers(tlss->tls_session);
+ if ((tret == -1) || (now > tret)) {
+ status |= GNUTLS_CERT_INVALID;
+ status |= GNUTLS_CERT_EXPIRED;
+ }
+#endif
+ gnutls_x509_crt_deinit(crt);
+ }
+#endif
+
+ if (status != 0) {
+ DEBUG(1,("TLS %s - check failed for "
+ "verify_peer[%s] and peer_name[%s] "
+ "status 0x%x (%s%s%s%s%s%s%s%s)\n",
+ __location__,
+ tls_verify_peer_string(tlss->verify_peer),
+ tlss->peer_name,
+ status,
+ status & GNUTLS_CERT_INVALID ? "invalid " : "",
+ status & GNUTLS_CERT_REVOKED ? "revoked " : "",
+ status & GNUTLS_CERT_SIGNER_NOT_FOUND ?
+ "signer_not_found " : "",
+ status & GNUTLS_CERT_SIGNER_NOT_CA ?
+ "signer_not_ca " : "",
+ status & GNUTLS_CERT_INSECURE_ALGORITHM ?
+ "insecure_algorithm " : "",
+ status & GNUTLS_CERT_NOT_ACTIVATED ?
+ "not_activated " : "",
+ status & GNUTLS_CERT_EXPIRED ?
+ "expired " : "",
+ status & GNUTLS_CERT_UNEXPECTED_OWNER ?
+ "unexptected_owner " : ""));
+ tlss->error = EINVAL;
+ tevent_req_error(req, tlss->error);
+ return;
+ }
+ }
+
tevent_req_done(req);
#else /* ENABLE_GNUTLS */
tevent_req_error(req, ENOSYS);
diff --git a/source4/lib/tls/tlscert.c b/source4/lib/tls/tlscert.c
index b44d46b0f1b..f1808d7cfd9 100644
--- a/source4/lib/tls/tlscert.c
+++ b/source4/lib/tls/tlscert.c
@@ -20,6 +20,7 @@
*/
#include "includes.h"
+#include "lib/tls/tls.h"
#if ENABLE_GNUTLS
#include <gnutls/gnutls.h>
@@ -29,9 +30,10 @@
#endif
#define ORGANISATION_NAME "Samba Administration"
-#define UNIT_NAME "Samba - temporary autogenerated certificate"
+#define CA_NAME "Samba - temporary autogenerated CA certificate"
+#define UNIT_NAME "Samba - temporary autogenerated HOST certificate"
#define LIFETIME 700*24*60*60
-#define DH_BITS 1024
+#define RSA_BITS 4096
/*
auto-generate a set of self signed certificates
@@ -76,11 +78,11 @@ void tls_cert_generate(TALLOC_CTX *mem_ctx,
DEBUG(3,("Generating private key\n"));
TLSCHECK(gnutls_x509_privkey_init(&key));
- TLSCHECK(gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, DH_BITS, 0));
+ TLSCHECK(gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, RSA_BITS, 0));
DEBUG(3,("Generating CA private key\n"));
TLSCHECK(gnutls_x509_privkey_init(&cakey));
- TLSCHECK(gnutls_x509_privkey_generate(cakey, GNUTLS_PK_RSA, DH_BITS, 0));
+ TLSCHECK(gnutls_x509_privkey_generate(cakey, GNUTLS_PK_RSA, RSA_BITS, 0));
DEBUG(3,("Generating CA certificate\n"));
TLSCHECK(gnutls_x509_crt_init(&cacrt));
@@ -89,7 +91,7 @@ void tls_cert_generate(TALLOC_CTX *mem_ctx,
ORGANISATION_NAME, strlen(ORGANISATION_NAME)));
TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt,
GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0,
- UNIT_NAME, strlen(UNIT_NAME)));
+ CA_NAME, strlen(CA_NAME)));
TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt,
GNUTLS_OID_X520_COMMON_NAME, 0,
hostname, strlen(hostname)));
@@ -97,10 +99,8 @@ void tls_cert_generate(TALLOC_CTX *mem_ctx,
TLSCHECK(gnutls_x509_crt_set_serial(cacrt, &serial, sizeof(serial)));
TLSCHECK(gnutls_x509_crt_set_activation_time(cacrt, activation));
TLSCHECK(gnutls_x509_crt_set_expiration_time(cacrt, expiry));
- TLSCHECK(gnutls_x509_crt_set_ca_status(cacrt, 0));
-#ifdef GNUTLS_KP_TLS_WWW_SERVER
- TLSCHECK(gnutls_x509_crt_set_key_purpose_oid(cacrt, GNUTLS_KP_TLS_WWW_SERVER, 0));
-#endif
+ TLSCHECK(gnutls_x509_crt_set_ca_status(cacrt, 1));
+ TLSCHECK(gnutls_x509_crt_set_key_usage(cacrt, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN));
TLSCHECK(gnutls_x509_crt_set_version(cacrt, 3));
TLSCHECK(gnutls_x509_crt_get_key_id(cacrt, 0, keyid, &keyidsize));
#if HAVE_GNUTLS_X509_CRT_SET_SUBJECT_KEY_ID
@@ -133,6 +133,7 @@ void tls_cert_generate(TALLOC_CTX *mem_ctx,
TLSCHECK(gnutls_x509_crt_set_subject_key_id(crt, keyid, keyidsize));
#endif
TLSCHECK(gnutls_x509_crt_sign(crt, crt, key));
+ TLSCHECK(gnutls_x509_crt_sign(crt, cacrt, cakey));
DEBUG(3,("Exporting TLS keys\n"));
diff --git a/source4/lib/tls/wscript b/source4/lib/tls/wscript
index cbba87d5804..3fd8acaff18 100644
--- a/source4/lib/tls/wscript
+++ b/source4/lib/tls/wscript
@@ -39,6 +39,11 @@ def configure(conf):
conf.CHECK_FUNCS_IN('gnutls_global_init', 'gnutls',
headers='gnutls/gnutls.h')
+ conf.CHECK_FUNCS_IN('gnutls_certificate_verify_peers3', 'gnutls',
+ headers='gnutls/gnutls.h')
+ conf.CHECK_DECLS('GNUTLS_CERT_EXPIRED GNUTLS_CERT_NOT_ACTIVATED GNUTLS_CERT_UNEXPECTED_OWNER',
+ headers='gnutls/gnutls.h gnutls/x509.h')
+
conf.CHECK_VARIABLE('gnutls_x509_crt_set_version',
headers='gnutls/gnutls.h gnutls/x509.h',
define='HAVE_GNUTLS_X509_CRT_SET_VERSION',
@@ -64,6 +69,5 @@ def configure(conf):
def build(bld):
bld.SAMBA_SUBSYSTEM('LIBTLS',
source='tls.c tlscert.c tls_tstream.c',
- allow_warnings=True,
public_deps='talloc gnutls gcrypt samba-hostconfig samba_socket LIBTSOCKET tevent tevent-util'
)
diff --git a/source4/libcli/cliconnect.c b/source4/libcli/cliconnect.c
index 17151923d5b..35d963eebf8 100644
--- a/source4/libcli/cliconnect.c
+++ b/source4/libcli/cliconnect.c
@@ -77,7 +77,7 @@ NTSTATUS smbcli_negprot(struct smbcli_state *cli, bool unicode, int maxprotocol)
return NT_STATUS_NO_MEMORY;
}
- return smb_raw_negotiate(cli->transport, unicode, maxprotocol);
+ return smb_raw_negotiate(cli->transport, unicode, PROTOCOL_CORE, maxprotocol);
}
/* wrapper around smb_raw_sesssetup() */
diff --git a/source4/libcli/ldap/ldap_bind.c b/source4/libcli/ldap/ldap_bind.c
index a96ea9f6aee..397b4cb3e44 100644
--- a/source4/libcli/ldap/ldap_bind.c
+++ b/source4/libcli/ldap/ldap_bind.c
@@ -28,10 +28,11 @@
#include "lib/tls/tls.h"
#include "auth/gensec/gensec.h"
#include "auth/gensec/gensec_internal.h" /* TODO: remove this */
-#include "auth/gensec/gensec_socket.h"
+#include "source4/auth/gensec/gensec_tstream.h"
#include "auth/credentials/credentials.h"
#include "lib/stream/packet.h"
#include "param/param.h"
+#include "param/loadparm.h"
struct ldap_simple_creds {
const char *dn;
@@ -216,7 +217,7 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn,
struct ldap_SearchResEntry *search;
int count, i;
bool first = true;
-
+ int wrap_flags = 0;
const char **sasl_names;
uint32_t old_gensec_features;
static const char *supported_sasl_mech_attrs[] = {
@@ -224,6 +225,27 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn,
NULL
};
unsigned int logon_retries = 0;
+ size_t queue_length;
+
+ if (conn->sockets.active == NULL) {
+ status = NT_STATUS_CONNECTION_DISCONNECTED;
+ goto failed;
+ }
+
+ queue_length = tevent_queue_length(conn->sockets.send_queue);
+ if (queue_length != 0) {
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ DEBUG(1, ("SASL bind triggered with non empty send_queue[%ju]: %s\n",
+ queue_length, nt_errstr(status)));
+ goto failed;
+ }
+
+ if (conn->pending != NULL) {
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ DEBUG(1, ("SASL bind triggered with pending requests: %s\n",
+ nt_errstr(status)));
+ goto failed;
+ }
status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs,
false, NULL, NULL, &sasl_mechs_msgs);
@@ -264,12 +286,29 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn,
gensec_init();
+ if (conn->sockets.active == conn->sockets.tls) {
+ /*
+ * require Kerberos SIGN/SEAL only if we don't use SSL
+ * Windows seem not to like double encryption
+ */
+ wrap_flags = 0;
+ } else if (cli_credentials_is_anonymous(creds)) {
+ /*
+ * anonymous isn't protected
+ */
+ wrap_flags = 0;
+ } else {
+ wrap_flags = lpcfg_client_ldap_sasl_wrapping(lp_ctx);
+ }
+
try_logon_again:
/*
we loop back here on a logon failure, and re-create the
gensec session. The logon_retries counter ensures we don't
loop forever.
*/
+ data_blob_free(&input);
+ TALLOC_FREE(conn->gensec);
status = gensec_client_start(conn, &conn->gensec,
lpcfg_gensec_settings(conn, lp_ctx));
@@ -278,10 +317,8 @@ try_logon_again:
goto failed;
}
- /* require Kerberos SIGN/SEAL only if we don't use SSL
- * Windows seem not to like double encryption */
old_gensec_features = cli_credentials_get_gensec_features(creds);
- if (tls_enabled(conn->sock)) {
+ if (wrap_flags == 0) {
cli_credentials_set_gensec_features(creds, old_gensec_features & ~(GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL));
}
@@ -297,6 +334,21 @@ try_logon_again:
* context, so we don't tatoo it ) */
cli_credentials_set_gensec_features(creds, old_gensec_features);
+ if (wrap_flags & ADS_AUTH_SASL_SEAL) {
+ gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN);
+ gensec_want_feature(conn->gensec, GENSEC_FEATURE_SEAL);
+ }
+ if (wrap_flags & ADS_AUTH_SASL_SIGN) {
+ gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN);
+ }
+
+ /*
+ * This is an indication for the NTLMSSP backend to
+ * also encrypt when only GENSEC_FEATURE_SIGN is requested
+ * in gensec_[un]wrap().
+ */
+ gensec_want_feature(conn->gensec, GENSEC_FEATURE_LDAP_STYLE);
+
if (conn->host) {
status = gensec_set_target_hostname(conn->gensec, conn->host);
if (!NT_STATUS_IS_OK(status)) {
@@ -385,6 +437,13 @@ try_logon_again:
result = response->r.BindResponse.response.resultcode;
+ if (result == LDAP_STRONG_AUTH_REQUIRED) {
+ if (wrap_flags == 0) {
+ wrap_flags = ADS_AUTH_SASL_SIGN;
+ goto try_logon_again;
+ }
+ }
+
if (result == LDAP_INVALID_CREDENTIALS) {
/*
try a second time on invalid credentials, to
@@ -413,8 +472,6 @@ try_logon_again:
new credentials, or get a new ticket
if using kerberos
*/
- talloc_free(conn->gensec);
- conn->gensec = NULL;
goto try_logon_again;
}
}
@@ -436,27 +493,45 @@ try_logon_again:
}
}
- talloc_free(tmp_ctx);
+ TALLOC_FREE(tmp_ctx);
- if (NT_STATUS_IS_OK(status)) {
- struct socket_context *sasl_socket;
- status = gensec_socket_init(conn->gensec,
- conn,
- conn->sock,
- conn->event.event_ctx,
- ldap_read_io_handler,
- conn,
- &sasl_socket);
- if (!NT_STATUS_IS_OK(status)) goto failed;
-
- conn->sock = sasl_socket;
- packet_set_socket(conn->packet, conn->sock);
-
- conn->bind.type = LDAP_BIND_SASL;
- conn->bind.creds = creds;
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
}
- return status;
+ conn->bind.type = LDAP_BIND_SASL;
+ conn->bind.creds = creds;
+
+ if (wrap_flags & ADS_AUTH_SASL_SEAL) {
+ if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SEAL)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ } else if (wrap_flags & ADS_AUTH_SASL_SIGN) {
+ if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ }
+
+ if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN) &&
+ !gensec_have_feature(conn->gensec, GENSEC_FEATURE_SEAL)) {
+ return NT_STATUS_OK;
+ }
+
+ status = gensec_create_tstream(conn->sockets.raw,
+ conn->gensec,
+ conn->sockets.raw,
+ &conn->sockets.sasl);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ conn->sockets.active = conn->sockets.sasl;
+
+ return NT_STATUS_OK;
failed:
talloc_free(tmp_ctx);
diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c
index 7c8bb0304c9..817863a3449 100644
--- a/source4/libcli/ldap/ldap_client.c
+++ b/source4/libcli/ldap/ldap_client.c
@@ -25,22 +25,36 @@
#include "includes.h"
#include <tevent.h>
#include "lib/socket/socket.h"
+#include "lib/tsocket/tsocket.h"
+#include "libcli/util/tstream.h"
#include "../lib/util/asn1.h"
#include "../lib/util/dlinklist.h"
#include "libcli/ldap/libcli_ldap.h"
#include "libcli/ldap/ldap_proto.h"
#include "libcli/ldap/ldap_client.h"
#include "libcli/composite/composite.h"
-#include "lib/stream/packet.h"
#include "lib/tls/tls.h"
#include "auth/gensec/gensec.h"
#include "system/time.h"
#include "param/param.h"
#include "libcli/resolve/resolve.h"
+static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status);
+
+static int ldap_connection_destructor(struct ldap_connection *conn)
+{
+ /*
+ * NT_STATUS_OK means that callbacks of pending requests are not
+ * triggered
+ */
+ ldap_connection_dead(conn, NT_STATUS_OK);
+ return 0;
+}
+
/**
create a new ldap_connection stucture. The event context is optional
*/
+
_PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx,
struct loadparm_context *lp_ctx,
struct tevent_context *ev)
@@ -59,6 +73,13 @@ _PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx,
conn->next_messageid = 1;
conn->event.event_ctx = ev;
+ conn->sockets.send_queue = tevent_queue_create(conn,
+ "ldap_connection send_queue");
+ if (conn->sockets.send_queue == NULL) {
+ TALLOC_FREE(conn);
+ return NULL;
+ }
+
conn->lp_ctx = lp_ctx;
/* set a reasonable request timeout */
@@ -66,29 +87,35 @@ _PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx,
/* explicitly avoid reconnections by default */
conn->reconnect.max_retries = 0;
-
+
+ talloc_set_destructor(conn, ldap_connection_destructor);
return conn;
}
/*
the connection is dead
*/
-static void ldap_connection_dead(struct ldap_connection *conn)
+static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status)
{
struct ldap_request *req;
- talloc_free(conn->sock); /* this will also free event.fde */
- talloc_free(conn->packet);
- conn->sock = NULL;
- conn->event.fde = NULL;
- conn->packet = NULL;
+ tevent_queue_stop(conn->sockets.send_queue);
+ TALLOC_FREE(conn->sockets.recv_subreq);
+ conn->sockets.active = NULL;
+ TALLOC_FREE(conn->sockets.sasl);
+ TALLOC_FREE(conn->sockets.tls);
+ TALLOC_FREE(conn->sockets.raw);
/* return an error for any pending request ... */
while (conn->pending) {
req = conn->pending;
DLIST_REMOVE(req->conn->pending, req);
+ req->conn = NULL;
req->state = LDAP_REQUEST_DONE;
- req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ if (NT_STATUS_IS_OK(status)) {
+ continue;
+ }
+ req->status = status;
if (req->async.fn) {
req->async.fn(req);
}
@@ -100,11 +127,9 @@ static void ldap_reconnect(struct ldap_connection *conn);
/*
handle packet errors
*/
-static void ldap_error_handler(void *private_data, NTSTATUS status)
+static void ldap_error_handler(struct ldap_connection *conn, NTSTATUS status)
{
- struct ldap_connection *conn = talloc_get_type(private_data,
- struct ldap_connection);
- ldap_connection_dead(conn);
+ ldap_connection_dead(conn, status);
/* but try to reconnect so that the ldb client can go on */
ldap_reconnect(conn);
@@ -130,7 +155,7 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message
if (req == NULL) {
DEBUG(0,("ldap: no matching message id for %u\n",
msg->messageid));
- talloc_free(msg);
+ TALLOC_FREE(msg);
return;
}
@@ -138,6 +163,7 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message
for (i=0; msg->controls && msg->controls[i]; i++) {
if (!msg->controls_decoded[i] &&
msg->controls[i]->critical) {
+ TALLOC_FREE(msg);
req->status = NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION);
req->state = LDAP_REQUEST_DONE;
DLIST_REMOVE(conn->pending, req);
@@ -149,10 +175,10 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message
}
/* add to the list of replies received */
- talloc_steal(req, msg);
req->replies = talloc_realloc(req, req->replies,
struct ldap_message *, req->num_replies+1);
if (req->replies == NULL) {
+ TALLOC_FREE(msg);
req->status = NT_STATUS_NO_MEMORY;
req->state = LDAP_REQUEST_DONE;
DLIST_REMOVE(conn->pending, req);
@@ -178,64 +204,120 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message
}
}
+static void ldap_connection_recv_done(struct tevent_req *subreq);
+
+static void ldap_connection_recv_next(struct ldap_connection *conn)
+{
+ struct tevent_req *subreq = NULL;
+
+ if (conn->sockets.recv_subreq != NULL) {
+ return;
+ }
+
+ if (conn->sockets.active == NULL) {
+ return;
+ }
+
+ if (conn->pending == NULL) {
+ return;
+ }
+
+ /*
+ * The minimun size of a LDAP pdu is 7 bytes
+ *
+ * dumpasn1 -hh ldap-unbind-min.dat
+ *
+ * <30 05 02 01 09 42 00>
+ * 0 5: SEQUENCE {
+ * <02 01 09>
+ * 2 1: INTEGER 9
+ * <42 00>
+ * 5 0: [APPLICATION 2]
+ * : Error: Object has zero length.
+ * : }
+ *
+ * dumpasn1 -hh ldap-unbind-windows.dat
+ *
+ * <30 84 00 00 00 05 02 01 09 42 00>
+ * 0 5: SEQUENCE {
+ * <02 01 09>
+ * 6 1: INTEGER 9
+ * <42 00>
+ * 9 0: [APPLICATION 2]
+ * : Error: Object has zero length.
+ * : }
+ *
+ * This means using an initial read size
+ * of 7 is ok.
+ */
+ subreq = tstream_read_pdu_blob_send(conn,
+ conn->event.event_ctx,
+ conn->sockets.active,
+ 7, /* initial_read_size */
+ ldap_full_packet,
+ conn);
+ if (subreq == NULL) {
+ ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ tevent_req_set_callback(subreq, ldap_connection_recv_done, conn);
+ conn->sockets.recv_subreq = subreq;
+ return;
+}
/*
decode/process LDAP data
*/
-static NTSTATUS ldap_recv_handler(void *private_data, DATA_BLOB blob)
+static void ldap_connection_recv_done(struct tevent_req *subreq)
{
NTSTATUS status;
- struct ldap_connection *conn = talloc_get_type(private_data,
- struct ldap_connection);
- struct ldap_message *msg = talloc(conn, struct ldap_message);
- struct asn1_data *asn1 = asn1_init(conn);
-
- if (asn1 == NULL || msg == NULL) {
- return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
+ struct ldap_connection *conn =
+ tevent_req_callback_data(subreq,
+ struct ldap_connection);
+ struct ldap_message *msg;
+ struct asn1_data *asn1;
+ DATA_BLOB blob;
+
+ msg = talloc_zero(conn, struct ldap_message);
+ if (msg == NULL) {
+ ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
+ return;
}
- if (!asn1_load(asn1, blob)) {
- talloc_free(msg);
- talloc_free(asn1);
- return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
+ asn1 = asn1_init(conn);
+ if (asn1 == NULL) {
+ TALLOC_FREE(msg);
+ ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
+ return;
}
-
- status = ldap_decode(asn1, samba_ldap_control_handlers(), msg);
+
+ conn->sockets.recv_subreq = NULL;
+
+ status = tstream_read_pdu_blob_recv(subreq,
+ asn1,
+ &blob);
+ TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(msg);
asn1_free(asn1);
- return status;
+ ldap_error_handler(conn, status);
+ return;
}
- ldap_match_message(conn, msg);
+ asn1_load_nocopy(asn1, blob.data, blob.length);
- data_blob_free(&blob);
+ status = ldap_decode(asn1, samba_ldap_control_handlers(), msg);
asn1_free(asn1);
- return NT_STATUS_OK;
-}
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(msg);
+ ldap_error_handler(conn, status);
+ return;
+ }
-/* Handle read events, from the GENSEC socket callback, or real events */
-void ldap_read_io_handler(void *private_data, uint16_t flags)
-{
- struct ldap_connection *conn = talloc_get_type(private_data,
- struct ldap_connection);
- packet_recv(conn->packet);
-}
+ ldap_match_message(conn, msg);
+ ldap_connection_recv_next(conn);
-/*
- handle ldap socket events
-*/
-static void ldap_io_handler(struct tevent_context *ev, struct tevent_fd *fde,
- uint16_t flags, void *private_data)
-{
- struct ldap_connection *conn = talloc_get_type(private_data,
- struct ldap_connection);
- if (flags & TEVENT_FD_WRITE) {
- packet_queue_run(conn->packet);
- if (!tls_enabled(conn->sock)) return;
- }
- if (flags & TEVENT_FD_READ) {
- ldap_read_io_handler(private_data, flags);
- }
+ return;
}
/*
@@ -284,6 +366,10 @@ static NTSTATUS ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
struct ldap_connect_state {
struct composite_context *ctx;
struct ldap_connection *conn;
+ struct socket_context *sock;
+ struct tstream_context *raw;
+ struct tstream_tls_params *tls_params;
+ struct tstream_context *tls;
};
static void ldap_connect_recv_unix_conn(struct composite_context *ctx);
@@ -327,11 +413,11 @@ _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *con
struct socket_address *unix_addr;
char path[1025];
- NTSTATUS status = socket_create("unix", SOCKET_TYPE_STREAM, &conn->sock, 0);
+ NTSTATUS status = socket_create("unix", SOCKET_TYPE_STREAM, &state->sock, 0);
if (!NT_STATUS_IS_OK(status)) {
return NULL;
}
- talloc_steal(conn, conn->sock);
+ talloc_steal(state, state->sock);
SMB_ASSERT(sizeof(protocol)>10);
SMB_ASSERT(sizeof(path)>1024);
@@ -354,29 +440,53 @@ _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *con
}
rfc1738_unescape(path);
-
- unix_addr = socket_address_from_strings(conn, conn->sock->backend_name,
+
+ unix_addr = socket_address_from_strings(state, state->sock->backend_name,
path, 0);
- if (!unix_addr) {
- return NULL;
+ if (composite_nomem(unix_addr, result)) {
+ return result;
}
- ctx = socket_connect_send(conn->sock, NULL, unix_addr,
- 0, conn->event.event_ctx);
+
+ ctx = socket_connect_send(state->sock, NULL, unix_addr,
+ 0, result->event_ctx);
ctx->async.fn = ldap_connect_recv_unix_conn;
ctx->async.private_data = state;
return result;
} else {
NTSTATUS status = ldap_parse_basic_url(conn, url, &conn->host,
&conn->port, &conn->ldaps);
- if (!NT_STATUS_IS_OK(state->ctx->status)) {
- composite_error(state->ctx, status);
+ if (!NT_STATUS_IS_OK(status)) {
+ composite_error(result, status);
return result;
}
-
+
+ if (conn->ldaps) {
+ char *ca_file = lpcfg_tls_cafile(state, conn->lp_ctx);
+ char *crl_file = lpcfg_tls_crlfile(state, conn->lp_ctx);
+ const char *tls_priority = lpcfg_tls_priority(conn->lp_ctx);
+ enum tls_verify_peer_state verify_peer =
+ lpcfg_tls_verify_peer(conn->lp_ctx);
+
+ status = tstream_tls_params_client(state,
+ ca_file,
+ crl_file,
+ tls_priority,
+ verify_peer,
+ conn->host,
+ &state->tls_params);
+ if (!NT_STATUS_IS_OK(status)) {
+ composite_error(result, status);
+ return result;
+ }
+ }
+
ctx = socket_connect_multi_send(state, conn->host, 1, &conn->port,
- lpcfg_resolve_context(conn->lp_ctx), conn->event.event_ctx);
- if (ctx == NULL) goto failed;
+ lpcfg_resolve_context(conn->lp_ctx),
+ result->event_ctx);
+ if (composite_nomem(ctx, result)) {
+ return result;
+ }
ctx->async.fn = ldap_connect_recv_tcp_conn;
ctx->async.private_data = state;
@@ -387,72 +497,80 @@ _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *con
return NULL;
}
+static void ldap_connect_got_tls(struct tevent_req *subreq);
+
static void ldap_connect_got_sock(struct composite_context *ctx,
- struct ldap_connection *conn)
+ struct ldap_connection *conn)
{
- /* setup a handler for events on this socket */
- conn->event.fde = tevent_add_fd(conn->event.event_ctx, conn->sock,
- socket_get_fd(conn->sock),
- TEVENT_FD_READ, ldap_io_handler, conn);
- if (conn->event.fde == NULL) {
- composite_error(ctx, NT_STATUS_INTERNAL_ERROR);
- return;
- }
-
- tevent_fd_set_close_fn(conn->event.fde, socket_tevent_fd_close_fn);
- socket_set_flags(conn->sock, SOCKET_FLAG_NOCLOSE);
+ struct ldap_connect_state *state =
+ talloc_get_type_abort(ctx->private_data,
+ struct ldap_connect_state);
+ struct tevent_req *subreq = NULL;
+ int fd;
+ int ret;
- talloc_steal(conn, conn->sock);
- if (conn->ldaps) {
- struct socket_context *tls_socket;
- char *cafile = lpcfg_tls_cafile(conn->sock, conn->lp_ctx);
+ socket_set_flags(state->sock, SOCKET_FLAG_NOCLOSE);
+ fd = socket_get_fd(state->sock);
+ TALLOC_FREE(state->sock);
- if (!cafile || !*cafile) {
- talloc_free(conn->sock);
- return;
- }
+ smb_set_close_on_exec(fd);
+ set_blocking(fd, false);
- tls_socket = tls_init_client(conn->sock, conn->event.fde, cafile);
- talloc_free(cafile);
-
- if (tls_socket == NULL) {
- talloc_free(conn->sock);
- return;
- }
+ ret = tstream_bsd_existing_socket(state, fd, &state->raw);
+ if (ret == -1) {
+ NTSTATUS status = map_nt_error_from_unix_common(errno);
+ composite_error(state->ctx, status);
+ return;
+ }
- conn->sock = talloc_steal(conn, tls_socket);
+ if (!conn->ldaps) {
+ conn->sockets.raw = talloc_move(conn, &state->raw);
+ conn->sockets.active = conn->sockets.raw;
+ composite_done(state->ctx);
+ return;
}
- conn->packet = packet_init(conn);
- if (conn->packet == NULL) {
- talloc_free(conn->sock);
+ subreq = tstream_tls_connect_send(state, state->ctx->event_ctx,
+ state->raw, state->tls_params);
+ if (composite_nomem(subreq, state->ctx)) {
return;
}
+ tevent_req_set_callback(subreq, ldap_connect_got_tls, state);
+}
- packet_set_private(conn->packet, conn);
- packet_set_socket(conn->packet, conn->sock);
- packet_set_callback(conn->packet, ldap_recv_handler);
- packet_set_full_request(conn->packet, ldap_full_packet);
- packet_set_error_handler(conn->packet, ldap_error_handler);
- packet_set_event_context(conn->packet, conn->event.event_ctx);
- packet_set_fde(conn->packet, conn->event.fde);
-/* packet_set_serialise(conn->packet); */
+static void ldap_connect_got_tls(struct tevent_req *subreq)
+{
+ struct ldap_connect_state *state =
+ tevent_req_callback_data(subreq,
+ struct ldap_connect_state);
+ int err;
+ int ret;
- if (conn->ldaps) {
- packet_set_unreliable_select(conn->packet);
+ ret = tstream_tls_connect_recv(subreq, &err, state, &state->tls);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ NTSTATUS status = map_nt_error_from_unix_common(err);
+ composite_error(state->ctx, status);
+ return;
}
- composite_done(ctx);
+ talloc_steal(state->tls, state->tls_params);
+
+ state->conn->sockets.raw = talloc_move(state->conn, &state->raw);
+ state->conn->sockets.tls = talloc_move(state->conn->sockets.raw,
+ &state->tls);
+ state->conn->sockets.active = state->conn->sockets.tls;
+ composite_done(state->ctx);
}
static void ldap_connect_recv_tcp_conn(struct composite_context *ctx)
{
struct ldap_connect_state *state =
- talloc_get_type(ctx->async.private_data,
- struct ldap_connect_state);
+ talloc_get_type_abort(ctx->async.private_data,
+ struct ldap_connect_state);
struct ldap_connection *conn = state->conn;
uint16_t port;
- NTSTATUS status = socket_connect_multi_recv(ctx, state, &conn->sock,
+ NTSTATUS status = socket_connect_multi_recv(ctx, state, &state->sock,
&port);
if (!NT_STATUS_IS_OK(status)) {
composite_error(state->ctx, status);
@@ -465,8 +583,8 @@ static void ldap_connect_recv_tcp_conn(struct composite_context *ctx)
static void ldap_connect_recv_unix_conn(struct composite_context *ctx)
{
struct ldap_connect_state *state =
- talloc_get_type(ctx->async.private_data,
- struct ldap_connect_state);
+ talloc_get_type_abort(ctx->async.private_data,
+ struct ldap_connect_state);
struct ldap_connection *conn = state->conn;
NTSTATUS status = socket_connect_recv(ctx);
@@ -533,7 +651,7 @@ static void ldap_reconnect(struct ldap_connection *conn)
/* rebind */
status = ldap_rebind(conn);
if ( ! NT_STATUS_IS_OK(status)) {
- ldap_connection_dead(conn);
+ ldap_connection_dead(conn, status);
}
}
@@ -552,7 +670,10 @@ static int ldap_request_destructor(struct ldap_request *req)
static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer *te,
struct timeval t, void *private_data)
{
- struct ldap_request *req = talloc_get_type(private_data, struct ldap_request);
+ struct ldap_request *req =
+ talloc_get_type_abort(private_data,
+ struct ldap_request);
+
req->status = NT_STATUS_IO_TIMEOUT;
if (req->state == LDAP_REQUEST_PENDING) {
DLIST_REMOVE(req->conn->pending, req);
@@ -570,26 +691,17 @@ static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer
static void ldap_request_failed_complete(struct tevent_context *ev, struct tevent_timer *te,
struct timeval t, void *private_data)
{
- struct ldap_request *req = talloc_get_type(private_data, struct ldap_request);
- if (req->async.fn) {
- req->async.fn(req);
- }
-}
+ struct ldap_request *req =
+ talloc_get_type_abort(private_data,
+ struct ldap_request);
-/*
- called on completion of a one-way ldap request
-*/
-static void ldap_request_oneway_complete(void *private_data)
-{
- struct ldap_request *req = talloc_get_type(private_data, struct ldap_request);
- if (req->state == LDAP_REQUEST_PENDING) {
- DLIST_REMOVE(req->conn->pending, req);
- }
- req->state = LDAP_REQUEST_DONE;
if (req->async.fn) {
req->async.fn(req);
}
}
+
+static void ldap_request_written(struct tevent_req *subreq);
+
/*
send a ldap message - async interface
*/
@@ -598,12 +710,12 @@ _PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn,
{
struct ldap_request *req;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- packet_send_callback_fn_t send_callback = NULL;
+ struct tevent_req *subreq = NULL;
req = talloc_zero(conn, struct ldap_request);
if (req == NULL) return NULL;
- if (conn->sock == NULL) {
+ if (conn->sockets.active == NULL) {
status = NT_STATUS_INVALID_CONNECTION;
goto failed;
}
@@ -628,25 +740,31 @@ _PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn,
goto failed;
}
- if (req->type == LDAP_TAG_AbandonRequest ||
- req->type == LDAP_TAG_UnbindRequest) {
- send_callback = ldap_request_oneway_complete;
+ /* put a timeout on the request */
+ req->time_event = tevent_add_timer(conn->event.event_ctx, req,
+ timeval_current_ofs(conn->timeout, 0),
+ ldap_request_timeout, req);
+ if (req->time_event == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
}
- status = packet_send_callback(conn->packet, req->data,
- send_callback, req);
- if (!NT_STATUS_IS_OK(status)) {
+ req->write_iov.iov_base = req->data.data;
+ req->write_iov.iov_len = req->data.length;
+
+ subreq = tstream_writev_queue_send(req, conn->event.event_ctx,
+ conn->sockets.active,
+ conn->sockets.send_queue,
+ &req->write_iov, 1);
+ if (subreq == NULL) {
+ status = NT_STATUS_NO_MEMORY;
goto failed;
}
+ tevent_req_set_callback(subreq, ldap_request_written, req);
req->state = LDAP_REQUEST_PENDING;
DLIST_ADD(conn->pending, req);
- /* put a timeout on the request */
- req->time_event = tevent_add_timer(conn->event.event_ctx, req,
- timeval_current_ofs(conn->timeout, 0),
- ldap_request_timeout, req);
-
return req;
failed:
@@ -658,6 +776,38 @@ failed:
return req;
}
+static void ldap_request_written(struct tevent_req *subreq)
+{
+ struct ldap_request *req =
+ tevent_req_callback_data(subreq,
+ struct ldap_request);
+ int err;
+ ssize_t ret;
+
+ ret = tstream_writev_queue_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ NTSTATUS error = map_nt_error_from_unix_common(err);
+ ldap_error_handler(req->conn, error);
+ return;
+ }
+
+ if (req->type == LDAP_TAG_AbandonRequest ||
+ req->type == LDAP_TAG_UnbindRequest)
+ {
+ if (req->state == LDAP_REQUEST_PENDING) {
+ DLIST_REMOVE(req->conn->pending, req);
+ }
+ req->state = LDAP_REQUEST_DONE;
+ if (req->async.fn) {
+ req->async.fn(req);
+ }
+ return;
+ }
+
+ ldap_connection_recv_next(req->conn);
+}
+
/*
wait for a request to complete
@@ -667,6 +817,7 @@ _PUBLIC_ NTSTATUS ldap_request_wait(struct ldap_request *req)
{
while (req->state < LDAP_REQUEST_DONE) {
if (tevent_loop_once(req->conn->event.event_ctx) != 0) {
+ req->state = LDAP_REQUEST_ERROR;
req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
break;
}
diff --git a/source4/libcli/ldap/ldap_client.h b/source4/libcli/ldap/ldap_client.h
index 3b4da6bcf23..e2b1b30e493 100644
--- a/source4/libcli/ldap/ldap_client.h
+++ b/source4/libcli/ldap/ldap_client.h
@@ -20,6 +20,7 @@
*/
+#include "system/network.h" /* for struct iovec */
#include "libcli/ldap/libcli_ldap.h"
enum ldap_request_state { LDAP_REQUEST_SEND=1, LDAP_REQUEST_PENDING=2, LDAP_REQUEST_DONE=3, LDAP_REQUEST_ERROR=4 };
@@ -39,6 +40,8 @@ struct ldap_request {
NTSTATUS status;
DATA_BLOB data;
+ struct iovec write_iov;
+
struct {
void (*fn)(struct ldap_request *);
void *private_data;
@@ -50,7 +53,16 @@ struct ldap_request {
/* main context for a ldap client connection */
struct ldap_connection {
- struct socket_context *sock;
+ struct {
+ struct tstream_context *raw;
+ struct tstream_context *tls;
+ struct tstream_context *sasl;
+ struct tstream_context *active;
+
+ struct tevent_queue *send_queue;
+ struct tevent_req *recv_subreq;
+ } sockets;
+
struct loadparm_context *lp_ctx;
char *host;
@@ -89,10 +101,7 @@ struct ldap_connection {
struct {
struct tevent_context *event_ctx;
- struct tevent_fd *fde;
} event;
-
- struct packet_context *packet;
};
struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx,
diff --git a/source4/libcli/ldap/ldap_controls.c b/source4/libcli/ldap/ldap_controls.c
index f910acba383..448a2633c26 100644
--- a/source4/libcli/ldap/ldap_controls.c
+++ b/source4/libcli/ldap/ldap_controls.c
@@ -512,10 +512,10 @@ static bool encode_verify_name_request(void *mem_ctx, void *in, DATA_BLOB *out)
return false;
}
- *out = data_blob_talloc(mem_ctx, data->data, data->length);
- if (out->data == NULL) {
+ if (!asn1_extract_blob(data, mem_ctx, out)) {
return false;
}
+
talloc_free(data);
return true;
@@ -716,10 +716,10 @@ static bool encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out)
return false;
}
- *out = data_blob_talloc(mem_ctx, data->data, data->length);
- if (out->data == NULL) {
+ if (!asn1_extract_blob(data, mem_ctx, out)) {
return false;
}
+
talloc_free(data);
return true;
@@ -774,10 +774,10 @@ static bool encode_server_sort_request(void *mem_ctx, void *in, DATA_BLOB *out)
return false;
}
- *out = data_blob_talloc(mem_ctx, data->data, data->length);
- if (out->data == NULL) {
+ if (!asn1_extract_blob(data, mem_ctx, out)) {
return false;
}
+
talloc_free(data);
return true;
@@ -809,10 +809,10 @@ static bool encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out)
return false;
}
- *out = data_blob_talloc(mem_ctx, data->data, data->length);
- if (out->data == NULL) {
+ if (!asn1_extract_blob(data, mem_ctx, out)) {
return false;
}
+
talloc_free(data);
return true;
@@ -837,10 +837,10 @@ static bool encode_sd_flags_request(void *mem_ctx, void *in, DATA_BLOB *out)
return false;
}
- *out = data_blob_talloc(mem_ctx, data->data, data->length);
- if (out->data == NULL) {
+ if (!asn1_extract_blob(data, mem_ctx, out)) {
return false;
}
+
talloc_free(data);
return true;
@@ -865,10 +865,10 @@ static bool encode_search_options_request(void *mem_ctx, void *in, DATA_BLOB *ou
return false;
}
- *out = data_blob_talloc(mem_ctx, data->data, data->length);
- if (out->data == NULL) {
+ if (!asn1_extract_blob(data, mem_ctx, out)) {
return false;
}
+
talloc_free(data);
return true;
@@ -897,10 +897,10 @@ static bool encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out
return false;
}
- *out = data_blob_talloc(mem_ctx, data->data, data->length);
- if (out->data == NULL) {
+ if (!asn1_extract_blob(data, mem_ctx, out)) {
return false;
}
+
talloc_free(data);
return true;
@@ -935,10 +935,10 @@ static bool encode_asq_control(void *mem_ctx, void *in, DATA_BLOB *out)
return false;
}
- *out = data_blob_talloc(mem_ctx, data->data, data->length);
- if (out->data == NULL) {
+ if (!asn1_extract_blob(data, mem_ctx, out)) {
return false;
}
+
talloc_free(data);
return true;
@@ -971,10 +971,10 @@ static bool encode_dirsync_request(void *mem_ctx, void *in, DATA_BLOB *out)
return false;
}
- *out = data_blob_talloc(mem_ctx, data->data, data->length);
- if (out->data == NULL) {
+ if (!asn1_extract_blob(data, mem_ctx, out)) {
return false;
}
+
talloc_free(data);
return true;
@@ -1047,10 +1047,10 @@ static bool encode_vlv_request(void *mem_ctx, void *in, DATA_BLOB *out)
return false;
}
- *out = data_blob_talloc(mem_ctx, data->data, data->length);
- if (out->data == NULL) {
+ if (!asn1_extract_blob(data, mem_ctx, out)) {
return false;
}
+
talloc_free(data);
return true;
@@ -1089,10 +1089,10 @@ static bool encode_vlv_response(void *mem_ctx, void *in, DATA_BLOB *out)
return false;
}
- *out = data_blob_talloc(mem_ctx, data->data, data->length);
- if (out->data == NULL) {
+ if (!asn1_extract_blob(data, mem_ctx, out)) {
return false;
}
+
talloc_free(data);
return true;
@@ -1140,10 +1140,10 @@ static bool encode_openldap_dereference(void *mem_ctx, void *in, DATA_BLOB *out)
return false;
}
- *out = data_blob_talloc(mem_ctx, data->data, data->length);
- if (out->data == NULL) {
+ if (!asn1_extract_blob(data, mem_ctx, out)) {
return false;
}
+
talloc_free(data);
return true;
}
diff --git a/source4/libcli/ldap/wscript_build b/source4/libcli/ldap/wscript_build
index f7afec73f29..f79cc2b6149 100644
--- a/source4/libcli/ldap/wscript_build
+++ b/source4/libcli/ldap/wscript_build
@@ -3,9 +3,9 @@
bld.SAMBA_LIBRARY('cli-ldap',
source='ldap_client.c ldap_bind.c ldap_ildap.c ldap_controls.c',
autoproto='ldap_proto.h',
- public_deps='errors tevent LIBPACKET',
+ public_deps='errors tevent',
public_headers='libcli_ldap.h:ldap-util.h',
- deps='cli_composite samba_socket NDR_SAMR LIBTLS ndr LP_RESOLVE gensec cli-ldap-common',
+ deps='cli_composite LIBSAMBA_TSOCKET samba_socket NDR_SAMR LIBTLS ndr LP_RESOLVE gensec cli-ldap-common',
private_library=True
)
diff --git a/source4/libcli/raw/libcliraw.h b/source4/libcli/raw/libcliraw.h
index 95e69431c1e..8220cd7c563 100644
--- a/source4/libcli/raw/libcliraw.h
+++ b/source4/libcli/raw/libcliraw.h
@@ -95,6 +95,7 @@ struct smbcli_options {
unsigned int use_spnego:1;
unsigned int unicode:1;
unsigned int ntstatus_support:1;
+ int min_protocol;
int max_protocol;
uint32_t max_xmit;
uint16_t max_mux;
diff --git a/source4/libcli/raw/rawnegotiate.c b/source4/libcli/raw/rawnegotiate.c
index 9b0ed38cf0c..4b42c2662a0 100644
--- a/source4/libcli/raw/rawnegotiate.c
+++ b/source4/libcli/raw/rawnegotiate.c
@@ -37,6 +37,7 @@ static void smb_raw_negotiate_done(struct tevent_req *subreq);
struct tevent_req *smb_raw_negotiate_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct smbcli_transport *transport,
+ int minprotocol,
int maxprotocol)
{
struct tevent_req *req;
@@ -51,10 +52,14 @@ struct tevent_req *smb_raw_negotiate_send(TALLOC_CTX *mem_ctx,
}
state->transport = transport;
+ if (maxprotocol > PROTOCOL_NT1) {
+ maxprotocol = PROTOCOL_NT1;
+ }
+
subreq = smbXcli_negprot_send(state, ev,
transport->conn,
timeout_msec,
- PROTOCOL_CORE,
+ minprotocol,
maxprotocol);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
@@ -127,7 +132,8 @@ NTSTATUS smb_raw_negotiate_recv(struct tevent_req *req)
/*
Send a negprot command (sync interface)
*/
-NTSTATUS smb_raw_negotiate(struct smbcli_transport *transport, bool unicode, int maxprotocol)
+NTSTATUS smb_raw_negotiate(struct smbcli_transport *transport, bool unicode,
+ int minprotocol, int maxprotocol)
{
NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
struct tevent_req *subreq = NULL;
@@ -136,6 +142,7 @@ NTSTATUS smb_raw_negotiate(struct smbcli_transport *transport, bool unicode, int
subreq = smb_raw_negotiate_send(transport,
transport->ev,
transport,
+ minprotocol,
maxprotocol);
if (subreq == NULL) {
return NT_STATUS_NO_MEMORY;
diff --git a/source4/libcli/smb2/connect.c b/source4/libcli/smb2/connect.c
index 9535380d646..1a6ae34d2cd 100644
--- a/source4/libcli/smb2/connect.c
+++ b/source4/libcli/smb2/connect.c
@@ -134,6 +134,7 @@ static void smb2_connect_socket_done(struct composite_context *creq)
struct tevent_req *subreq;
NTSTATUS status;
uint32_t timeout_msec;
+ enum protocol_types min_protocol;
status = smbcli_sock_connect_recv(creq, state, &sock);
if (tevent_req_nterror(req, status)) {
@@ -146,10 +147,14 @@ static void smb2_connect_socket_done(struct composite_context *creq)
}
timeout_msec = state->transport->options.request_timeout * 1000;
+ min_protocol = state->transport->options.min_protocol;
+ if (min_protocol < PROTOCOL_SMB2_02) {
+ min_protocol = PROTOCOL_SMB2_02;
+ }
subreq = smbXcli_negprot_send(state, state->ev,
state->transport->conn, timeout_msec,
- PROTOCOL_SMB2_02,
+ min_protocol,
state->transport->options.max_protocol);
if (tevent_req_nomem(subreq, req)) {
return;
diff --git a/source4/libcli/smb_composite/connect.c b/source4/libcli/smb_composite/connect.c
index d87d5ecae27..fffa768ac97 100644
--- a/source4/libcli/smb_composite/connect.c
+++ b/source4/libcli/smb_composite/connect.c
@@ -297,6 +297,7 @@ static NTSTATUS connect_send_negprot(struct composite_context *c,
state->subreq = smb_raw_negotiate_send(state,
state->transport->ev,
state->transport,
+ state->transport->options.min_protocol,
state->transport->options.max_protocol);
NT_STATUS_HAVE_NO_MEMORY(state->subreq);
tevent_req_set_callback(state->subreq, subreq_handler, c);
diff --git a/source4/libcli/smb_composite/sesssetup.c b/source4/libcli/smb_composite/sesssetup.c
index e4964c19b5d..9f989f21f2c 100644
--- a/source4/libcli/smb_composite/sesssetup.c
+++ b/source4/libcli/smb_composite/sesssetup.c
@@ -329,9 +329,21 @@ static NTSTATUS session_setup_nt1(struct composite_context *c,
if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
+ if (!cli_credentials_is_anonymous(io->in.credentials) &&
+ session->options.ntlmv2_auth &&
+ session->transport->options.use_spnego)
+ {
+ /*
+ * Don't send an NTLMv2_RESPONSE without NTLMSSP
+ * if we want to use spnego
+ */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
nt_status = cli_credentials_get_ntlm_response(io->in.credentials, state,
&flags,
session->transport->negotiate.secblob,
+ NULL, /* server_timestamp */
names_blob,
&state->setup.nt1.in.password1,
&state->setup.nt1.in.password2,
@@ -392,24 +404,13 @@ static NTSTATUS session_setup_old(struct composite_context *c,
struct sesssetup_state *state = talloc_get_type(c->private_data,
struct sesssetup_state);
const char *password = cli_credentials_get_password(io->in.credentials);
- const char *domain = cli_credentials_get_domain(io->in.credentials);
/*
* domain controllers tend to reject the NTLM v2 blob
* if the netbiosname is not valid (e.g. IP address or FQDN)
* so just leave it away (as Windows client do)
*/
- DATA_BLOB names_blob = NTLMv2_generate_names_blob(state, NULL, domain);
-
DATA_BLOB session_key;
- int flags = 0;
- if (session->options.lanman_auth) {
- flags |= CLI_CRED_LANMAN_AUTH;
- }
-
- if (session->options.ntlmv2_auth) {
- flags |= CLI_CRED_NTLMv2_AUTH;
- }
state->setup.old.level = RAW_SESSSETUP_OLD;
state->setup.old.in.bufsize = session->transport->options.max_xmit;
@@ -423,9 +424,21 @@ static NTSTATUS session_setup_old(struct composite_context *c,
&state->setup.old.in.domain);
if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
+ DATA_BLOB names_blob = data_blob_null;
+ int flags = 0;
+
+ if (!cli_credentials_is_anonymous(io->in.credentials) &&
+ !session->options.lanman_auth)
+ {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ flags |= CLI_CRED_LANMAN_AUTH;
+
nt_status = cli_credentials_get_ntlm_response(io->in.credentials, state,
&flags,
session->transport->negotiate.secblob,
+ NULL, /* server_timestamp */
names_blob,
&state->setup.old.in.password,
NULL,
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index 6e3410bd238..827499155f8 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -65,6 +65,8 @@ struct rpc_request {
DATA_BLOB request_data;
bool ignore_timeout;
bool wait_for_sync;
+ bool verify_bitmask1;
+ bool verify_pcontext;
struct {
void (*callback)(struct rpc_request *);
@@ -139,7 +141,9 @@ static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
}
c->call_id = 1;
- c->security_state.auth_info = NULL;
+ c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
+ c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
+ c->security_state.auth_context_id = 0;
c->security_state.session_key = dcerpc_generic_session_key;
c->security_state.generic_state = NULL;
c->flags = 0;
@@ -220,12 +224,8 @@ static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
return;
}
- if (hs->p->conn->security_state.auth_info == NULL) {
- return;
- }
-
- *auth_type = hs->p->conn->security_state.auth_info->auth_type;
- *auth_level = hs->p->conn->security_state.auth_info->auth_level;
+ *auth_type = hs->p->conn->security_state.auth_type;
+ *auth_level = hs->p->conn->security_state.auth_level;
}
struct dcerpc_bh_raw_call_state {
@@ -741,12 +741,16 @@ static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX
struct dcerpc_auth auth;
uint32_t auth_length;
- if (!c->security_state.auth_info ||
- !c->security_state.generic_state) {
- return NT_STATUS_OK;
+ status = dcerpc_verify_ncacn_packet_header(pkt, DCERPC_PKT_RESPONSE,
+ pkt->u.response.stub_and_verifier.length,
+ 0, /* required_flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
- switch (c->security_state.auth_info->auth_level) {
+ switch (c->security_state.auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
case DCERPC_AUTH_LEVEL_INTEGRITY:
break;
@@ -766,6 +770,14 @@ static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX
return NT_STATUS_INVALID_LEVEL;
}
+ if (pkt->auth_length == 0) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (c->security_state.generic_state == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
&pkt->u.response.stub_and_verifier,
&auth, &auth_length, false);
@@ -773,8 +785,20 @@ static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX
pkt->u.response.stub_and_verifier.length -= auth_length;
+ if (auth.auth_type != c->security_state.auth_type) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (auth.auth_level != c->security_state.auth_level) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (auth.auth_context_id != c->security_state.auth_context_id) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
/* check signature or unseal the packet */
- switch (c->security_state.auth_info->auth_level) {
+ switch (c->security_state.auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
status = gensec_unseal_packet(c->security_state.generic_state,
raw_packet->data + DCERPC_REQUEST_LENGTH,
@@ -830,13 +854,13 @@ static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
size_t payload_length;
enum ndr_err_code ndr_err;
size_t hdr_size = DCERPC_REQUEST_LENGTH;
+ struct dcerpc_auth auth_info = {
+ .auth_type = c->security_state.auth_type,
+ .auth_level = c->security_state.auth_level,
+ .auth_context_id = c->security_state.auth_context_id,
+ };
- /* non-signed packets are simpler */
- if (c->security_state.auth_info == NULL) {
- return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
- }
-
- switch (c->security_state.auth_info->auth_level) {
+ switch (c->security_state.auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
case DCERPC_AUTH_LEVEL_INTEGRITY:
if (sig_size == 0) {
@@ -883,21 +907,18 @@ static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
ndr_push_align() as that is relative to the start of the
whole packet, whereas w2k8 wants it relative to the start
of the stub */
- c->security_state.auth_info->auth_pad_length =
+ auth_info.auth_pad_length =
DCERPC_AUTH_PAD_LENGTH(pkt->u.request.stub_and_verifier.length);
- ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
+ ndr_err = ndr_push_zero(ndr, auth_info.auth_pad_length);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return ndr_map_error2ntstatus(ndr_err);
}
payload_length = pkt->u.request.stub_and_verifier.length +
- c->security_state.auth_info->auth_pad_length;
-
- /* we start without signature, it will appended later */
- c->security_state.auth_info->credentials = data_blob(NULL,0);
+ auth_info.auth_pad_length;
/* add the auth verifier */
- ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
+ ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth_info);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return ndr_map_error2ntstatus(ndr_err);
}
@@ -915,7 +936,7 @@ static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
dcerpc_set_auth_length(blob, sig_size);
/* sign or seal the packet */
- switch (c->security_state.auth_info->auth_level) {
+ switch (c->security_state.auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
status = gensec_seal_packet(c->security_state.generic_state,
mem_ctx,
@@ -955,7 +976,7 @@ static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
(unsigned) creds2.length,
(unsigned) sig_size,
- (unsigned) c->security_state.auth_info->auth_pad_length,
+ (unsigned) auth_info.auth_pad_length,
(unsigned) pkt->u.request.stub_and_verifier.length));
dcerpc_set_frag_length(blob, blob->length + creds2.length);
dcerpc_set_auth_length(blob, creds2.length);
@@ -1223,7 +1244,7 @@ struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
/* construct the NDR form of the packet */
status = ncacn_push_auth(&blob, state, &pkt,
- p->conn->security_state.auth_info);
+ p->conn->security_state.tmp_auth_info.out);
if (tevent_req_nterror(req, status)) {
return tevent_req_post(req, ev);
}
@@ -1296,6 +1317,7 @@ static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
tevent_req_data(req,
struct dcerpc_bind_state);
struct dcecli_connection *conn = state->p->conn;
+ struct dcecli_security *sec = &conn->security_state;
struct dcerpc_binding *b = NULL;
NTSTATUS status;
uint32_t flags;
@@ -1329,14 +1351,34 @@ static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
return;
}
- if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
- (pkt->u.bind_ack.num_results == 0) ||
- (pkt->u.bind_ack.ctx_list[0].result != 0)) {
+ status = dcerpc_verify_ncacn_packet_header(pkt,
+ DCERPC_PKT_BIND_ACK,
+ pkt->u.bind_ack.auth_info.length,
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST,
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
+ if (!NT_STATUS_IS_OK(status)) {
state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
return;
}
+ if (pkt->u.bind_ack.num_results != 1) {
+ state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
+ tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
+ return;
+ }
+
+ if (pkt->u.bind_ack.ctx_list[0].result != 0) {
+ status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
+ DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
+ pkt->u.bind_ack.ctx_list[0].reason.value,
+ nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
/*
* DCE-RPC 1.1 (c706) specifies
* CONST_MUST_RCV_FRAG_SIZE as 1432
@@ -1369,11 +1411,13 @@ static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
}
/* the bind_ack might contain a reply set of credentials */
- if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
+ if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
uint32_t auth_length;
- status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
- conn->security_state.auth_info, &auth_length, true);
+ status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
+ &pkt->u.bind_ack.auth_info,
+ sec->tmp_auth_info.in,
+ &auth_length, true);
if (tevent_req_nterror(req, status)) {
return;
}
@@ -1423,9 +1467,8 @@ NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
}
/* construct the NDR form of the packet */
- status = ncacn_push_auth(&blob, mem_ctx,
- &pkt,
- p->conn->security_state.auth_info);
+ status = ncacn_push_auth(&blob, mem_ctx, &pkt,
+ p->conn->security_state.tmp_auth_info.out);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -1461,8 +1504,7 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c,
to run the auth routines so that we don't get the sign/seal
info out of step with the server
*/
- if (c->security_state.auth_info && c->security_state.generic_state &&
- pkt->ptype == DCERPC_PKT_RESPONSE) {
+ if (pkt->ptype == DCERPC_PKT_RESPONSE) {
status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
}
@@ -1502,7 +1544,16 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c,
}
if (pkt->ptype == DCERPC_PKT_FAULT) {
+ status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
+ dcerpc_connection_dead(c, status);
+ return;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ dcerpc_connection_dead(c, status);
+ return;
+ }
req->fault_code = pkt->u.fault.status;
req->status = NT_STATUS_NET_WRITE_FAULT;
goto req_done;
@@ -1511,20 +1562,27 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c,
if (pkt->ptype != DCERPC_PKT_RESPONSE) {
DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
(int)pkt->ptype));
- req->fault_code = DCERPC_FAULT_OTHER;
- req->status = NT_STATUS_NET_WRITE_FAULT;
- goto req_done;
+ dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
}
/* now check the status from the auth routines, and if it failed then fail
this request accordingly */
if (!NT_STATUS_IS_OK(status)) {
- req->status = status;
- goto req_done;
+ dcerpc_connection_dead(c, status);
+ return;
}
length = pkt->u.response.stub_and_verifier.length;
+ if (req->payload.length + length > DCERPC_NCACN_PAYLOAD_MAX_SIZE) {
+ DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n",
+ (unsigned)req->payload.length + length,
+ DCERPC_NCACN_PAYLOAD_MAX_SIZE));
+ dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
if (length > 0) {
req->payload.data = talloc_realloc(req,
req->payload.data,
@@ -1545,6 +1603,13 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c,
return;
}
+ if (req->verify_bitmask1) {
+ req->p->conn->security_state.verified_bitmask1 = true;
+ }
+ if (req->verify_pcontext) {
+ req->p->verified_pcontext = true;
+ }
+
if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
req->flags |= DCERPC_PULL_BIGENDIAN;
} else {
@@ -1569,6 +1634,8 @@ req_done:
}
}
+static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
+
/*
perform the send side of a async dcerpc request
*/
@@ -1579,6 +1646,7 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
DATA_BLOB *stub_data)
{
struct rpc_request *req;
+ NTSTATUS status;
req = talloc_zero(mem_ctx, struct rpc_request);
if (req == NULL) {
@@ -1601,6 +1669,12 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
req->request_data.length = stub_data->length;
req->request_data.data = stub_data->data;
+ status = dcerpc_request_prepare_vt(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(req);
+ return NULL;
+ }
+
DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
talloc_set_destructor(req, dcerpc_req_dequeue);
@@ -1615,6 +1689,120 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
return req;
}
+static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
+{
+ struct dcecli_security *sec = &req->p->conn->security_state;
+ struct dcerpc_sec_verification_trailer *t;
+ struct dcerpc_sec_vt *c = NULL;
+ struct ndr_push *ndr = NULL;
+ enum ndr_err_code ndr_err;
+
+ if (sec->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
+ return NT_STATUS_OK;
+ }
+
+ t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
+ if (t == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!sec->verified_bitmask1) {
+ t->commands = talloc_realloc(t, t->commands,
+ struct dcerpc_sec_vt,
+ t->count.count + 1);
+ if (t->commands == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ c = &t->commands[t->count.count++];
+ ZERO_STRUCTP(c);
+
+ c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
+ if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
+ c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
+ }
+ req->verify_bitmask1 = true;
+ }
+
+ if (!req->p->verified_pcontext) {
+ t->commands = talloc_realloc(t, t->commands,
+ struct dcerpc_sec_vt,
+ t->count.count + 1);
+ if (t->commands == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ c = &t->commands[t->count.count++];
+ ZERO_STRUCTP(c);
+
+ c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
+ c->u.pcontext.abstract_syntax = req->p->syntax;
+ c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
+
+ req->verify_pcontext = true;
+ }
+
+ if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
+ t->commands = talloc_realloc(t, t->commands,
+ struct dcerpc_sec_vt,
+ t->count.count + 1);
+ if (t->commands == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ c = &t->commands[t->count.count++];
+ ZERO_STRUCTP(c);
+
+ c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
+ c->u.header2.ptype = DCERPC_PKT_REQUEST;
+ if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
+ c->u.header2.drep[0] = 0;
+ } else {
+ c->u.header2.drep[0] = DCERPC_DREP_LE;
+ }
+ c->u.header2.drep[1] = 0;
+ c->u.header2.drep[2] = 0;
+ c->u.header2.drep[3] = 0;
+ c->u.header2.call_id = req->call_id;
+ c->u.header2.context_id = req->p->context_id;
+ c->u.header2.opnum = req->opnum;
+ }
+
+ if (t->count.count == 0) {
+ TALLOC_FREE(t);
+ return NT_STATUS_OK;
+ }
+
+ c = &t->commands[t->count.count - 1];
+ c->command |= DCERPC_SEC_VT_COMMAND_END;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
+ }
+
+ ndr = ndr_push_init_ctx(req);
+ if (ndr == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * for now we just copy and append
+ */
+
+ ndr_err = ndr_push_bytes(ndr, req->request_data.data,
+ req->request_data.length);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
+ NDR_SCALARS | NDR_BUFFERS,
+ t);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ req->request_data = ndr_push_blob(ndr);
+
+ return NT_STATUS_OK;
+}
+
/*
Send a request using the transport
*/
@@ -1644,25 +1832,9 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
need_async = true;
}
- if (c->security_state.auth_info &&
- c->security_state.generic_state)
- {
- struct gensec_security *gensec = c->security_state.generic_state;
-
- switch (c->security_state.auth_info->auth_level) {
- case DCERPC_AUTH_LEVEL_PRIVACY:
- case DCERPC_AUTH_LEVEL_INTEGRITY:
- can_async = gensec_have_feature(gensec,
+ if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
+ can_async = gensec_have_feature(c->security_state.generic_state,
GENSEC_FEATURE_ASYNC_REPLIES);
- break;
- case DCERPC_AUTH_LEVEL_CONNECT:
- case DCERPC_AUTH_LEVEL_NONE:
- can_async = true;
- break;
- default:
- can_async = false;
- break;
- }
}
if (need_async && !can_async) {
@@ -1682,8 +1854,7 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
request header size */
chunk_size = p->conn->srv_max_recv_frag;
chunk_size -= DCERPC_REQUEST_LENGTH;
- if (c->security_state.auth_info &&
- c->security_state.generic_state) {
+ if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
size_t max_payload = chunk_size;
max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
@@ -2119,7 +2290,7 @@ struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
/* construct the NDR form of the packet */
status = ncacn_push_auth(&blob, state, &pkt,
- p->conn->security_state.auth_info);
+ p->conn->security_state.tmp_auth_info.out);
if (tevent_req_nterror(req, status)) {
return tevent_req_post(req, ev);
}
@@ -2192,6 +2363,7 @@ static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
tevent_req_data(req,
struct dcerpc_alter_context_state);
struct dcecli_connection *conn = state->p->conn;
+ struct dcecli_security *sec = &conn->security_state;
NTSTATUS status;
/*
@@ -2213,23 +2385,15 @@ static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
*/
tevent_req_defer_callback(req, state->ev);
- if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
- pkt->u.alter_resp.num_results == 1 &&
- pkt->u.alter_resp.ctx_list[0].result != 0) {
- status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
- DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
- pkt->u.alter_resp.ctx_list[0].reason.value,
- nt_errstr(status)));
- tevent_req_nterror(req, status);
- return;
- }
-
if (pkt->ptype == DCERPC_PKT_FAULT) {
DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
dcerpc_errstr(state, pkt->u.fault.status)));
if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
state->p->last_fault_code = pkt->u.fault.status;
tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
+ } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
+ state->p->last_fault_code = pkt->u.fault.status;
+ tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
} else {
state->p->last_fault_code = pkt->u.fault.status;
status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
@@ -2238,21 +2402,42 @@ static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
return;
}
- if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
- pkt->u.alter_resp.num_results == 0 ||
- pkt->u.alter_resp.ctx_list[0].result != 0) {
+ status = dcerpc_verify_ncacn_packet_header(pkt,
+ DCERPC_PKT_ALTER_RESP,
+ pkt->u.alter_resp.auth_info.length,
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST,
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
+ if (!NT_STATUS_IS_OK(status)) {
+ state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
+ tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
+ return;
+ }
+
+ if (pkt->u.alter_resp.num_results != 1) {
state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
return;
}
+ if (pkt->u.alter_resp.ctx_list[0].result != 0) {
+ status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
+ DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
+ pkt->u.alter_resp.ctx_list[0].reason.value,
+ nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
/* the alter_resp might contain a reply set of credentials */
- if (conn->security_state.auth_info &&
- pkt->u.alter_resp.auth_info.length) {
+ if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
uint32_t auth_length;
- status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
- conn->security_state.auth_info, &auth_length, true);
+ status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
+ &pkt->u.alter_resp.auth_info,
+ sec->tmp_auth_info.in,
+ &auth_length, true);
if (tevent_req_nterror(req, status)) {
return;
}
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index a7d16947707..1b0eb7d9ba1 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -46,11 +46,21 @@ struct dcecli_connection;
struct gensec_settings;
struct cli_credentials;
struct dcecli_security {
- struct dcerpc_auth *auth_info;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+ uint32_t auth_context_id;
+ struct {
+ struct dcerpc_auth *out;
+ struct dcerpc_auth *in;
+ TALLOC_CTX *mem;
+ } tmp_auth_info;
struct gensec_security *generic_state;
/* get the session key */
NTSTATUS (*session_key)(struct dcecli_connection *, DATA_BLOB *);
+
+ bool verified_bitmask1;
+
};
/*
@@ -126,6 +136,8 @@ struct dcerpc_pipe {
*/
bool inhibit_timeout_processing;
bool timed_out;
+
+ bool verified_pcontext;
};
/* default timeout for all rpc requests, in seconds */
diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c
index 2d60d38732b..d617b07e07c 100644
--- a/source4/librpc/rpc/dcerpc_auth.c
+++ b/source4/librpc/rpc/dcerpc_auth.c
@@ -124,7 +124,8 @@ _PUBLIC_ NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
struct bind_auth_state {
struct dcerpc_pipe *pipe;
- DATA_BLOB credentials;
+ struct dcerpc_auth out_auth_info;
+ struct dcerpc_auth in_auth_info;
bool more_processing; /* Is there anything more to do after the
* first bind itself received? */
};
@@ -141,6 +142,27 @@ static void bind_auth_next_step(struct composite_context *c)
state = talloc_get_type(c->private_data, struct bind_auth_state);
sec = &state->pipe->conn->security_state;
+ if (state->in_auth_info.auth_type != sec->auth_type) {
+ composite_error(c, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (state->in_auth_info.auth_level != sec->auth_level) {
+ composite_error(c, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (state->in_auth_info.auth_context_id != sec->auth_context_id) {
+ composite_error(c, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
+ state->out_auth_info = (struct dcerpc_auth) {
+ .auth_type = sec->auth_type,
+ .auth_level = sec->auth_level,
+ .auth_context_id = sec->auth_context_id,
+ };
+
/* The status value here, from GENSEC is vital to the security
* of the system. Even if the other end accepts, if GENSEC
* claims 'MORE_PROCESSING_REQUIRED' then you must keep
@@ -156,16 +178,14 @@ static void bind_auth_next_step(struct composite_context *c)
c->status = gensec_update_ev(sec->generic_state, state,
state->pipe->conn->event_ctx,
- sec->auth_info->credentials,
- &state->credentials);
+ state->in_auth_info.credentials,
+ &state->out_auth_info.credentials);
if (state->pipe->timed_out) {
composite_error(c, NT_STATUS_IO_TIMEOUT);
return;
}
state->pipe->inhibit_timeout_processing = false;
- data_blob_free(&sec->auth_info->credentials);
-
if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
more_processing = true;
c->status = NT_STATUS_OK;
@@ -173,18 +193,21 @@ static void bind_auth_next_step(struct composite_context *c)
if (!composite_is_ok(c)) return;
- if (state->credentials.length == 0) {
+ if (state->out_auth_info.credentials.length == 0) {
composite_done(c);
return;
}
- sec->auth_info->credentials = state->credentials;
+ state->in_auth_info = (struct dcerpc_auth) {
+ .auth_type = DCERPC_AUTH_TYPE_NONE,
+ };
+ sec->tmp_auth_info.in = &state->in_auth_info;
+ sec->tmp_auth_info.mem = state;
+ sec->tmp_auth_info.out = &state->out_auth_info;
if (!more_processing) {
/* NO reply expected, so just send it */
c->status = dcerpc_auth3(state->pipe, state);
- data_blob_free(&state->credentials);
- sec->auth_info->credentials = data_blob(NULL, 0);
if (!composite_is_ok(c)) return;
composite_done(c);
@@ -197,8 +220,6 @@ static void bind_auth_next_step(struct composite_context *c)
state->pipe,
&state->pipe->syntax,
&state->pipe->transfer_syntax);
- data_blob_free(&state->credentials);
- sec->auth_info->credentials = data_blob(NULL, 0);
if (composite_nomem(subreq, c)) return;
tevent_req_set_callback(subreq, bind_auth_recv_alter, c);
}
@@ -209,6 +230,11 @@ static void bind_auth_recv_alter(struct tevent_req *subreq)
struct composite_context *c =
tevent_req_callback_data(subreq,
struct composite_context);
+ struct bind_auth_state *state = talloc_get_type(c->private_data,
+ struct bind_auth_state);
+ struct dcecli_security *sec = &state->pipe->conn->security_state;
+
+ ZERO_STRUCT(sec->tmp_auth_info);
c->status = dcerpc_alter_context_recv(subreq);
TALLOC_FREE(subreq);
@@ -225,14 +251,15 @@ static void bind_auth_recv_bindreply(struct tevent_req *subreq)
struct composite_context);
struct bind_auth_state *state = talloc_get_type(c->private_data,
struct bind_auth_state);
+ struct dcecli_security *sec = &state->pipe->conn->security_state;
+
+ ZERO_STRUCT(sec->tmp_auth_info);
c->status = dcerpc_bind_recv(subreq);
TALLOC_FREE(subreq);
if (!composite_is_ok(c)) return;
if (state->pipe->conn->flags & DCERPC_HEADER_SIGNING) {
- struct dcecli_security *sec = &state->pipe->conn->security_state;
-
gensec_want_feature(sec->generic_state, GENSEC_FEATURE_SIGN_PKT_HEADER);
}
@@ -353,15 +380,20 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
return c;
}
- sec->auth_info = talloc(p, struct dcerpc_auth);
- if (composite_nomem(sec->auth_info, c)) return c;
+ sec->auth_type = auth_type;
+ sec->auth_level = auth_level,
+ /*
+ * We use auth_context_id = 1 as some older
+ * Samba versions (<= 4.2.3) use that value hardcoded
+ * in a response.
+ */
+ sec->auth_context_id = 1;
- sec->auth_info->auth_type = auth_type;
- sec->auth_info->auth_level = auth_level,
- sec->auth_info->auth_pad_length = 0;
- sec->auth_info->auth_reserved = 0;
- sec->auth_info->auth_context_id = random();
- sec->auth_info->credentials = data_blob(NULL, 0);
+ state->out_auth_info = (struct dcerpc_auth) {
+ .auth_type = sec->auth_type,
+ .auth_level = sec->auth_level,
+ .auth_context_id = sec->auth_context_id,
+ };
/* The status value here, from GENSEC is vital to the security
* of the system. Even if the other end accepts, if GENSEC
@@ -377,8 +409,8 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
state->pipe->timed_out = false;
c->status = gensec_update_ev(sec->generic_state, state,
p->conn->event_ctx,
- sec->auth_info->credentials,
- &state->credentials);
+ data_blob_null,
+ &state->out_auth_info.credentials);
if (state->pipe->timed_out) {
composite_error(c, NT_STATUS_IO_TIMEOUT);
return c;
@@ -394,25 +426,28 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
state->more_processing = NT_STATUS_EQUAL(c->status,
NT_STATUS_MORE_PROCESSING_REQUIRED);
- if (state->credentials.length == 0) {
+ if (state->out_auth_info.credentials.length == 0) {
composite_done(c);
return c;
}
- sec->auth_info->credentials = state->credentials;
-
if (gensec_have_feature(sec->generic_state, GENSEC_FEATURE_SIGN_PKT_HEADER)) {
- if (auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
+ if (sec->auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
state->pipe->conn->flags |= DCERPC_PROPOSE_HEADER_SIGNING;
}
}
+ state->in_auth_info = (struct dcerpc_auth) {
+ .auth_type = DCERPC_AUTH_TYPE_NONE,
+ };
+ sec->tmp_auth_info.in = &state->in_auth_info;
+ sec->tmp_auth_info.mem = state;
+ sec->tmp_auth_info.out = &state->out_auth_info;
+
/* The first request always is a dcerpc_bind. The subsequent ones
* depend on gensec results */
subreq = dcerpc_bind_send(state, p->conn->event_ctx, p,
&syntax, &transfer_syntax);
- data_blob_free(&state->credentials);
- sec->auth_info->credentials = data_blob(NULL, 0);
if (composite_nomem(subreq, c)) return c;
tevent_req_set_callback(subreq, bind_auth_recv_bindreply, c);
diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c
index 9c5dbebcc1d..8ed12578e21 100644
--- a/source4/librpc/rpc/dcerpc_connect.c
+++ b/source4/librpc/rpc/dcerpc_connect.c
@@ -183,6 +183,11 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CT
conn->in.fallback_to_anonymous = false;
}
+ conn->in.options.min_protocol = PROTOCOL_NT1;
+ conn->in.options.max_protocol = PROTOCOL_NT1;
+
+ conn->in.options.signing = lpcfg_client_ipc_signing(lp_ctx);
+
/* send smb connect request */
conn_req = smb_composite_connect_send(conn, s->io.conn,
s->io.resolve_ctx,
@@ -277,6 +282,17 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send(
lpcfg_smbcli_options(lp_ctx, &options);
+ options.min_protocol = lpcfg_client_ipc_min_protocol(lp_ctx);
+ if (options.min_protocol < PROTOCOL_SMB2_02) {
+ options.min_protocol = PROTOCOL_SMB2_02;
+ }
+ options.max_protocol = lpcfg_client_ipc_max_protocol(lp_ctx);
+ if (options.max_protocol < PROTOCOL_SMB2_02) {
+ options.max_protocol = PROTOCOL_SMB2_02;
+ }
+
+ options.signing = lpcfg_client_ipc_signing(lp_ctx);
+
/* send smb2 connect request */
subreq = smb2_connect_send(s, c->event_ctx,
host,
@@ -773,6 +789,7 @@ static void continue_connect(struct composite_context *c, struct pipe_connect_st
struct composite_context *ncacn_unix_req;
struct composite_context *ncalrpc_req;
enum dcerpc_transport_t transport;
+ enum protocol_types min_ipc_protocol;
uint32_t flags;
/* dcerpc pipe connect input parameters */
@@ -786,6 +803,11 @@ static void continue_connect(struct composite_context *c, struct pipe_connect_st
transport = dcerpc_binding_get_transport(s->binding);
flags = dcerpc_binding_get_flags(s->binding);
+ min_ipc_protocol = lpcfg_client_ipc_min_protocol(s->lp_ctx);
+ if (min_ipc_protocol >= PROTOCOL_SMB2_02) {
+ flags |= DCERPC_SMB2;
+ }
+
/* connect dcerpc pipe depending on required transport */
switch (transport) {
case NCACN_NP:
diff --git a/source4/librpc/rpc/dcerpc_roh.c b/source4/librpc/rpc/dcerpc_roh.c
index 09072940f90..6da29787fbe 100644
--- a/source4/librpc/rpc/dcerpc_roh.c
+++ b/source4/librpc/rpc/dcerpc_roh.c
@@ -31,6 +31,7 @@
#include "librpc/rpc/dcerpc.h"
#include "librpc/rpc/dcerpc_roh.h"
#include "librpc/rpc/dcerpc_proto.h"
+#include "lib/param/param.h"
static ssize_t tstream_roh_pending_bytes(struct tstream_context *stream);
static struct tevent_req * tstream_roh_readv_send(
@@ -184,7 +185,17 @@ struct tevent_req *dcerpc_pipe_open_roh_send(struct dcecli_connection *conn,
/* Initialize TLS */
if (use_tls) {
- status = tstream_tls_params_client(state->roh, NULL, NULL,
+ char *ca_file = lpcfg_tls_cafile(state, lp_ctx);
+ char *crl_file = lpcfg_tls_crlfile(state, lp_ctx);
+ const char *tls_priority = lpcfg_tls_priority(lp_ctx);
+ enum tls_verify_peer_state verify_peer =
+ lpcfg_tls_verify_peer(lp_ctx);
+
+ status = tstream_tls_params_client(state->roh,
+ ca_file, crl_file,
+ tls_priority,
+ verify_peer,
+ state->rpc_proxy,
&state->tls_params);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("%s: Failed tstream_tls_params_client - %s\n",
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index de960b246be..d7757503820 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -662,15 +662,15 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
/* Perform an authenticated DCE-RPC bind
*/
- if (!(conn->flags & (DCERPC_SIGN|DCERPC_SEAL))) {
+ if (!(conn->flags & (DCERPC_CONNECT|DCERPC_SEAL))) {
/*
we are doing an authenticated connection,
- but not using sign or seal. We must force
- the CONNECT dcerpc auth type as a NONE auth
- type doesn't allow authentication
- information to be passed.
+ which needs to use [connect], [sign] or [seal].
+ If nothing is specified, we default to [sign] now.
+ This give roughly the same protection as
+ ncacn_np with smb signing.
*/
- conn->flags |= DCERPC_CONNECT;
+ conn->flags |= DCERPC_SIGN;
}
if (conn->flags & DCERPC_AUTH_SPNEGO) {
@@ -760,6 +760,16 @@ _PUBLIC_ NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx,
NTSTATUS dcerpc_generic_session_key(struct dcecli_connection *c,
DATA_BLOB *session_key)
{
+ *session_key = data_blob_null;
+
+ if (c != NULL) {
+ if (c->transport.transport != NCALRPC &&
+ c->transport.transport != NCACN_UNIX_STREAM)
+ {
+ return NT_STATUS_LOCAL_USER_SESSION_KEY;
+ }
+ }
+
/* this took quite a few CPU cycles to find ... */
session_key->data = discard_const_p(unsigned char, "SystemLibraryDTC");
session_key->length = 16;
diff --git a/source4/librpc/rpc/pyrpc.c b/source4/librpc/rpc/pyrpc.c
index 09f663213b6..243e96b93ef 100644
--- a/source4/librpc/rpc/pyrpc.c
+++ b/source4/librpc/rpc/pyrpc.c
@@ -246,44 +246,8 @@ static PyObject *py_iface_request(PyObject *self, PyObject *args, PyObject *kwar
return ret;
}
-static PyObject *py_iface_alter_context(PyObject *self, PyObject *args, PyObject *kwargs)
-{
- dcerpc_InterfaceObject *iface = (dcerpc_InterfaceObject *)self;
- NTSTATUS status;
- const char *kwnames[] = { "abstract_syntax", "transfer_syntax", NULL };
- PyObject *py_abstract_syntax = Py_None, *py_transfer_syntax = Py_None;
- struct ndr_syntax_id abstract_syntax, transfer_syntax;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:alter_context",
- discard_const_p(char *, kwnames), &py_abstract_syntax,
- &py_transfer_syntax)) {
- return NULL;
- }
-
- if (!ndr_syntax_from_py_object(py_abstract_syntax, &abstract_syntax))
- return NULL;
-
- if (py_transfer_syntax == Py_None) {
- transfer_syntax = ndr_transfer_syntax_ndr;
- } else {
- if (!ndr_syntax_from_py_object(py_transfer_syntax, &transfer_syntax))
- return NULL;
- }
-
- status = dcerpc_alter_context(iface->pipe, iface->pipe, &abstract_syntax,
- &transfer_syntax);
-
- if (!NT_STATUS_IS_OK(status)) {
- PyErr_SetDCERPCStatus(iface->pipe, status);
- return NULL;
- }
-
- Py_RETURN_NONE;
-}
-
static PyMethodDef dcerpc_interface_methods[] = {
{ "request", (PyCFunction)py_iface_request, METH_VARARGS|METH_KEYWORDS, "S.request(opnum, data, object=None) -> data\nMake a raw request" },
- { "alter_context", (PyCFunction)py_iface_alter_context, METH_VARARGS|METH_KEYWORDS, "S.alter_context(syntax)\nChange to a different interface" },
{ NULL, NULL, 0, NULL },
};
@@ -398,6 +362,45 @@ static PyTypeObject py_transfer_syntax_ndr64_SyntaxType = {
.tp_new = py_transfer_syntax_ndr64_new,
};
+static PyObject *py_bind_time_features_syntax_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ const char *kwnames[] = {
+ "features", NULL
+ };
+ unsigned long long features = 0;
+ struct ndr_syntax_id syntax;
+ PyObject *args2 = Py_None;
+ PyObject *kwargs2 = Py_None;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "K:features", discard_const_p(char *, kwnames), &features)) {
+ return NULL;
+ }
+
+ args2 = Py_BuildValue("()");
+ if (args2 == NULL) {
+ return NULL;
+ }
+
+ kwargs2 = Py_BuildValue("{}");
+ if (kwargs2 == NULL) {
+ Py_DECREF(args2);
+ return NULL;
+ }
+
+ syntax = dcerpc_construct_bind_time_features(features);
+
+ return py_dcerpc_syntax_init_helper(type, args2, kwargs2, &syntax);
+}
+
+static PyTypeObject py_bind_time_features_syntax_SyntaxType = {
+ PyObject_HEAD_INIT(NULL) 0,
+ .tp_name = "base.bind_time_features_syntax",
+ .tp_basicsize = sizeof(pytalloc_Object),
+ .tp_doc = "bind_time_features_syntax(features)\n",
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_new = py_bind_time_features_syntax_new,
+};
+
void initbase(void)
{
PyObject *m;
@@ -413,6 +416,7 @@ void initbase(void)
py_transfer_syntax_ndr_SyntaxType.tp_base = ndr_syntax_id_Type;
py_transfer_syntax_ndr64_SyntaxType.tp_base = ndr_syntax_id_Type;
+ py_bind_time_features_syntax_SyntaxType.tp_base = ndr_syntax_id_Type;
if (PyType_Ready(&dcerpc_InterfaceType) < 0)
return;
@@ -421,6 +425,8 @@ void initbase(void)
return;
if (PyType_Ready(&py_transfer_syntax_ndr64_SyntaxType) < 0)
return;
+ if (PyType_Ready(&py_bind_time_features_syntax_SyntaxType) < 0)
+ return;
m = Py_InitModule3("base", NULL, "DCE/RPC protocol implementation");
if (m == NULL)
@@ -433,4 +439,6 @@ void initbase(void)
PyModule_AddObject(m, "transfer_syntax_ndr", (PyObject *)(void *)&py_transfer_syntax_ndr_SyntaxType);
Py_INCREF((PyObject *)(void *)&py_transfer_syntax_ndr64_SyntaxType);
PyModule_AddObject(m, "transfer_syntax_ndr64", (PyObject *)(void *)&py_transfer_syntax_ndr64_SyntaxType);
+ Py_INCREF((PyObject *)(void *)&py_bind_time_features_syntax_SyntaxType);
+ PyModule_AddObject(m, "bind_time_features_syntax", (PyObject *)(void *)&py_bind_time_features_syntax_SyntaxType);
}
diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c
index af3313f6dd8..f53b2dd1807 100644
--- a/source4/param/loadparm.c
+++ b/source4/param/loadparm.c
@@ -36,10 +36,11 @@ void lpcfg_smbcli_options(struct loadparm_context *lp_ctx,
{
options->max_xmit = lpcfg_max_xmit(lp_ctx);
options->max_mux = lpcfg_max_mux(lp_ctx);
- options->use_spnego = lpcfg_nt_status_support(lp_ctx) && lpcfg_use_spnego(lp_ctx);
+ options->use_spnego = lpcfg_nt_status_support(lp_ctx) && lpcfg_client_use_spnego(lp_ctx);
options->signing = lpcfg_client_signing(lp_ctx);
options->request_timeout = SMB_REQUEST_TIMEOUT;
options->ntstatus_support = lpcfg_nt_status_support(lp_ctx);
+ options->min_protocol = lpcfg_client_min_protocol(lp_ctx);
options->max_protocol = lpcfg__client_max_protocol(lp_ctx);
options->unicode = lpcfg_unicode(lp_ctx);
options->use_oplocks = true;
diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c
index 9dea3d6357e..4037d18edf0 100644
--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c
+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c
@@ -54,6 +54,14 @@ static const AlgorithmIdentifier _hx509_signature_rsa_with_var_num = {
{ 7, discard_const_p(unsigned, rsa_with_var_num) }, NULL
};
+#define DCESRV_INTERFACE_BACKUPKEY_BIND(call, iface) \
+ dcesrv_interface_backupkey_bind(call, iface)
+static NTSTATUS dcesrv_interface_backupkey_bind(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ return dcesrv_interface_bind_require_privacy(dce_call, iface);
+}
+
static NTSTATUS set_lsa_secret(TALLOC_CTX *mem_ctx,
struct ldb_context *ldb,
const char *name,
@@ -1791,11 +1799,6 @@ static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call,
return WERR_NOT_SUPPORTED;
}
- if (!dce_call->conn->auth_state.auth_info ||
- dce_call->conn->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
- DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
- }
-
ldb_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
dce_call->conn->dce_ctx->lp_ctx,
system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
diff --git a/source4/rpc_server/common/reply.c b/source4/rpc_server/common/reply.c
index 007b68083bf..8f0e3043ad0 100644
--- a/source4/rpc_server/common/reply.c
+++ b/source4/rpc_server/common/reply.c
@@ -97,28 +97,41 @@ void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
/*
return a dcerpc fault
*/
-NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
+NTSTATUS dcesrv_fault_with_flags(struct dcesrv_call_state *call,
+ uint32_t fault_code,
+ uint8_t extra_flags)
{
struct ncacn_packet pkt;
struct data_blob_list_item *rep;
- uint8_t zeros[4];
+ static const uint8_t zeros[4] = { 0, };
NTSTATUS status;
- /* setup a bind_ack */
+ /* setup a fault */
dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
pkt.auth_length = 0;
pkt.call_id = call->pkt.call_id;
pkt.ptype = DCERPC_PKT_FAULT;
- pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
- pkt.u.fault.alloc_hint = 0;
- pkt.u.fault.context_id = 0;
+ pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
+ pkt.u.fault.alloc_hint = 24;
+ switch (call->pkt.ptype) {
+ case DCERPC_PKT_REQUEST:
+ pkt.u.fault.context_id = call->pkt.u.request.context_id;
+ break;
+ default:
+ pkt.u.fault.context_id = 0;
+ break;
+ }
+ if (fault_code == DCERPC_NCA_S_PROTO_ERROR) {
+ /*
+ * context_id = 0 is forced on protocol errors.
+ */
+ pkt.u.fault.context_id = 0;
+ }
pkt.u.fault.cancel_count = 0;
pkt.u.fault.status = fault_code;
-
- ZERO_STRUCT(zeros);
pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
- rep = talloc(call, struct data_blob_list_item);
+ rep = talloc_zero(call, struct data_blob_list_item);
if (!rep) {
return NT_STATUS_NO_MEMORY;
}
@@ -142,7 +155,10 @@ NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
return NT_STATUS_OK;
}
-
+NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
+{
+ return dcesrv_fault_with_flags(call, fault_code, 0);
+}
_PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
{
@@ -183,9 +199,9 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
/* we can write a full max_recv_frag size, minus the dcerpc
request header size */
- chunk_size = call->conn->cli_max_recv_frag;
+ chunk_size = call->conn->max_xmit_frag;
chunk_size -= DCERPC_REQUEST_LENGTH;
- if (call->conn->auth_state.auth_info &&
+ if (call->conn->auth_state.auth_finished &&
call->conn->auth_state.gensec_security) {
size_t max_payload = chunk_size;
@@ -206,7 +222,7 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
struct data_blob_list_item *rep;
struct ncacn_packet pkt;
- rep = talloc(call, struct data_blob_list_item);
+ rep = talloc_zero(call, struct data_blob_list_item);
NT_STATUS_HAVE_NO_MEMORY(rep);
length = MIN(chunk_size, stub.length);
@@ -259,5 +275,12 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *c,
DATA_BLOB *session_key)
{
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(c->endpoint->ep_description);
+
+ if (transport != NCALRPC && transport != NCACN_UNIX_STREAM) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
return dcerpc_generic_session_key(NULL, session_key);
}
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index b1c763b76f7..278e1af3eaa 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -42,9 +42,6 @@
#include "lib/util/samba_modules.h"
#include "librpc/gen_ndr/ndr_dcerpc.h"
-/* this is only used when the client asks for an unknown interface */
-#define DUMMY_ASSOC_GROUP 0x0FFFFFFF
-
extern const struct dcesrv_interface dcesrv_mgmt_interface;
@@ -74,7 +71,7 @@ static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_c
assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
if (assoc_group == NULL) {
- DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
+ DEBUG(2,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
return NULL;
}
return talloc_reference(mem_ctx, assoc_group);
@@ -269,7 +266,7 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
/* check if this endpoint exists
*/
if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
- ep = talloc(dce_ctx, struct dcesrv_endpoint);
+ ep = talloc_zero(dce_ctx, struct dcesrv_endpoint);
if (!ep) {
return NT_STATUS_NO_MEMORY;
}
@@ -278,7 +275,7 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
add_ep = true;
/* add mgmt interface */
- ifl = talloc(ep, struct dcesrv_if_list);
+ ifl = talloc_zero(ep, struct dcesrv_if_list);
if (!ifl) {
return NT_STATUS_NO_MEMORY;
}
@@ -297,7 +294,7 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
}
/* talloc a new interface list element */
- ifl = talloc(ep, struct dcesrv_if_list);
+ ifl = talloc_zero(ep, struct dcesrv_if_list);
if (!ifl) {
return NT_STATUS_NO_MEMORY;
}
@@ -408,6 +405,9 @@ _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
p->msg_ctx = msg_ctx;
p->server_id = server_id;
p->state_flags = state_flags;
+ p->allow_bind = true;
+ p->max_recv_frag = 5840;
+ p->max_xmit_frag = 5840;
*_p = p;
return NT_STATUS_OK;
@@ -450,6 +450,23 @@ static void dcesrv_call_set_list(struct dcesrv_call_state *call,
}
}
+static void dcesrv_call_disconnect_after(struct dcesrv_call_state *call,
+ const char *reason)
+{
+ if (call->conn->terminate != NULL) {
+ return;
+ }
+
+ call->conn->allow_bind = false;
+ call->conn->allow_alter = false;
+ call->conn->allow_auth3 = false;
+ call->conn->allow_request = false;
+
+ call->terminate_reason = talloc_strdup(call, reason);
+ if (call->terminate_reason == NULL) {
+ call->terminate_reason = __location__;
+ }
+}
/*
return a dcerpc bind_nak
@@ -460,6 +477,13 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
struct dcerpc_bind_nak_version version;
struct data_blob_list_item *rep;
NTSTATUS status;
+ static const uint8_t _pad[3] = { 0, };
+
+ /*
+ * We add the call to the pending_call_list
+ * in order to defer the termination.
+ */
+ dcesrv_call_disconnect_after(call, "dcesrv_bind_nak");
/* setup a bind_nak */
dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
@@ -472,9 +496,9 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
version.rpc_vers_minor = 0;
pkt.u.bind_nak.num_versions = 1;
pkt.u.bind_nak.versions = &version;
- pkt.u.bind_nak._pad = data_blob_null;
+ pkt.u.bind_nak._pad = data_blob_const(_pad, sizeof(_pad));
- rep = talloc(call, struct data_blob_list_item);
+ rep = talloc_zero(call, struct data_blob_list_item);
if (!rep) {
return NT_STATUS_NO_MEMORY;
}
@@ -498,6 +522,19 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
return NT_STATUS_OK;
}
+static NTSTATUS dcesrv_fault_disconnect(struct dcesrv_call_state *call,
+ uint32_t fault_code)
+{
+ /*
+ * We add the call to the pending_call_list
+ * in order to defer the termination.
+ */
+ dcesrv_call_disconnect_after(call, "dcesrv_fault_disconnect");
+
+ return dcesrv_fault_with_flags(call, fault_code,
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
+}
+
static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
{
DLIST_REMOVE(c->conn->contexts, c);
@@ -510,6 +547,115 @@ static int dcesrv_connection_context_destructor(struct dcesrv_connection_context
return 0;
}
+static void dcesrv_prepare_context_auth(struct dcesrv_call_state *dce_call)
+{
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(endpoint->ep_description);
+ struct dcesrv_connection_context *context = dce_call->context;
+ const struct dcesrv_interface *iface = context->iface;
+
+ context->min_auth_level = DCERPC_AUTH_LEVEL_NONE;
+
+ if (transport == NCALRPC) {
+ context->allow_connect = true;
+ return;
+ }
+
+ /*
+ * allow overwrite per interface
+ * allow dcerpc auth level connect:<interface>
+ */
+ context->allow_connect = lpcfg_allow_dcerpc_auth_level_connect(lp_ctx);
+ context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
+ "allow dcerpc auth level connect",
+ iface->name,
+ context->allow_connect);
+}
+
+NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ if (dce_call->context == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ dce_call->context->min_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ if (dce_call->context == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ dce_call->context->min_auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(endpoint->ep_description);
+ struct dcesrv_connection_context *context = dce_call->context;
+
+ if (context == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (transport == NCALRPC) {
+ context->allow_connect = true;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * allow overwrite per interface
+ * allow dcerpc auth level connect:<interface>
+ */
+ context->allow_connect = false;
+ context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
+ "allow dcerpc auth level connect",
+ iface->name,
+ context->allow_connect);
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(endpoint->ep_description);
+ struct dcesrv_connection_context *context = dce_call->context;
+
+ if (context == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (transport == NCALRPC) {
+ context->allow_connect = true;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * allow overwrite per interface
+ * allow dcerpc auth level connect:<interface>
+ */
+ context->allow_connect = true;
+ context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
+ "allow dcerpc auth level connect",
+ iface->name,
+ context->allow_connect);
+ return NT_STATUS_OK;
+}
+
/*
handle a bind request
*/
@@ -524,14 +670,57 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
uint32_t context_id;
const struct dcesrv_interface *iface;
uint32_t extra_flags = 0;
+ uint16_t max_req = 0;
+ uint16_t max_rep = 0;
+ const char *ep_prefix = "";
+ const char *endpoint = NULL;
+
+ status = dcerpc_verify_ncacn_packet_header(&call->pkt,
+ DCERPC_PKT_BIND,
+ call->pkt.u.bind.auth_info.length,
+ 0, /* required flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ return dcesrv_bind_nak(call,
+ DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED);
+ }
+
+ /* max_recv_frag and max_xmit_frag result always in the same value! */
+ max_req = MIN(call->pkt.u.bind.max_xmit_frag,
+ call->pkt.u.bind.max_recv_frag);
+ /*
+ * The values are between 2048 and 5840 tested against Windows 2012R2
+ * via ncacn_ip_tcp on port 135.
+ */
+ max_req = MAX(2048, max_req);
+ max_rep = MIN(max_req, call->conn->max_recv_frag);
+ /* They are truncated to an 8 byte boundary. */
+ max_rep &= 0xFFF8;
+
+ /* max_recv_frag and max_xmit_frag result always in the same value! */
+ call->conn->max_recv_frag = max_rep;
+ call->conn->max_xmit_frag = max_rep;
/*
if provided, check the assoc_group is valid
*/
- if (call->pkt.u.bind.assoc_group_id != 0 &&
- lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
- dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
- return dcesrv_bind_nak(call, 0);
+ if (call->pkt.u.bind.assoc_group_id != 0) {
+ call->conn->assoc_group = dcesrv_assoc_group_reference(call->conn,
+ call->conn->dce_ctx,
+ call->pkt.u.bind.assoc_group_id);
+ } else {
+ call->conn->assoc_group = dcesrv_assoc_group_new(call->conn,
+ call->conn->dce_ctx);
+ }
+ if (call->conn->assoc_group == NULL) {
+ return dcesrv_bind_nak(call, 0);
}
if (call->pkt.u.bind.num_contexts < 1 ||
@@ -540,12 +729,6 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
}
context_id = call->pkt.u.bind.ctx_list[0].context_id;
-
- /* you can't bind twice on one context */
- if (dcesrv_find_context(call->conn, context_id) != NULL) {
- return dcesrv_bind_nak(call, 0);
- }
-
if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
@@ -573,7 +756,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
if (iface) {
/* add this context to the list of available context_ids */
- struct dcesrv_connection_context *context = talloc(call->conn,
+ struct dcesrv_connection_context *context = talloc_zero(call->conn,
struct dcesrv_connection_context);
if (context == NULL) {
return dcesrv_bind_nak(call, 0);
@@ -581,22 +764,15 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
context->conn = call->conn;
context->iface = iface;
context->context_id = context_id;
- if (call->pkt.u.bind.assoc_group_id != 0) {
- context->assoc_group = dcesrv_assoc_group_reference(context,
- call->conn->dce_ctx,
- call->pkt.u.bind.assoc_group_id);
- } else {
- context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
- }
- if (context->assoc_group == NULL) {
- talloc_free(context);
- return dcesrv_bind_nak(call, 0);
- }
+ /* legacy for openchange dcesrv_mapiproxy.c */
+ context->assoc_group = call->conn->assoc_group;
context->private_data = NULL;
DLIST_ADD(call->conn->contexts, context);
call->context = context;
talloc_set_destructor(context, dcesrv_connection_context_destructor);
+ dcesrv_prepare_context_auth(call);
+
status = iface->bind(call, iface, if_version);
if (!NT_STATUS_IS_OK(status)) {
char *uuid_str = GUID_string(call, &uuid);
@@ -611,10 +787,6 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
}
}
- if (call->conn->cli_max_recv_frag == 0) {
- call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
- }
-
if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
(call->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED;
@@ -627,9 +799,20 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
/* handle any authentication that is being requested */
if (!dcesrv_auth_bind(call)) {
- talloc_free(call->context);
- call->context = NULL;
- return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
+ struct dcesrv_auth *auth = &call->conn->auth_state;
+
+ TALLOC_FREE(call->context);
+
+ if (auth->auth_level != DCERPC_AUTH_LEVEL_NONE) {
+ /*
+ * We only give INVALID_AUTH_TYPE if the auth_level was
+ * valid.
+ */
+ return dcesrv_bind_nak(call,
+ DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE);
+ }
+ return dcesrv_bind_nak(call,
+ DCERPC_BIND_NAK_REASON_NOT_SPECIFIED);
}
/* setup a bind_ack */
@@ -638,29 +821,39 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
pkt.call_id = call->pkt.call_id;
pkt.ptype = DCERPC_PKT_BIND_ACK;
pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
- pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
- pkt.u.bind_ack.max_recv_frag = 0x2000;
+ pkt.u.bind_ack.max_xmit_frag = call->conn->max_xmit_frag;
+ pkt.u.bind_ack.max_recv_frag = call->conn->max_recv_frag;
+ pkt.u.bind_ack.assoc_group_id = call->conn->assoc_group->id;
- /*
- make it possible for iface->bind() to specify the assoc_group_id
- This helps the openchange mapiproxy plugin to work correctly.
-
- metze
- */
- if (call->context) {
- pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
- } else {
- pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
+ if (iface) {
+ endpoint = dcerpc_binding_get_string_option(
+ call->conn->endpoint->ep_description,
+ "endpoint");
}
- if (iface) {
- /* FIXME: Use pipe name as specified by endpoint instead of interface name */
- pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
- } else {
- pkt.u.bind_ack.secondary_address = "";
+ if (endpoint == NULL) {
+ endpoint = "";
+ }
+
+ if (strncasecmp(endpoint, "\\pipe\\", 6) == 0) {
+ /*
+ * TODO: check if this is really needed
+ *
+ * Or if we should fix this in our idl files.
+ */
+ ep_prefix = "\\PIPE\\";
+ endpoint += 6;
+ }
+
+ pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "%s%s",
+ ep_prefix,
+ endpoint);
+ if (pkt.u.bind_ack.secondary_address == NULL) {
+ TALLOC_FREE(call->context);
+ return NT_STATUS_NO_MEMORY;
}
pkt.u.bind_ack.num_results = 1;
- pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
+ pkt.u.bind_ack.ctx_list = talloc_zero(call, struct dcerpc_ack_ctx);
if (!pkt.u.bind_ack.ctx_list) {
talloc_free(call->context);
call->context = NULL;
@@ -678,7 +871,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
return dcesrv_bind_nak(call, 0);
}
- rep = talloc(call, struct data_blob_list_item);
+ rep = talloc_zero(call, struct data_blob_list_item);
if (!rep) {
talloc_free(call->context);
call->context = NULL;
@@ -686,7 +879,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
}
status = ncacn_push_auth(&rep->blob, call, &pkt,
- call->conn->auth_state.auth_info);
+ call->out_auth_info);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(call->context);
call->context = NULL;
@@ -713,9 +906,35 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
*/
static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
{
+ NTSTATUS status;
+
+ if (!call->conn->allow_auth3) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ if (call->conn->auth_state.auth_finished) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ status = dcerpc_verify_ncacn_packet_header(&call->pkt,
+ DCERPC_PKT_AUTH3,
+ call->pkt.u.auth3.auth_info.length,
+ 0, /* required flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
/* handle the auth3 in the auth code */
if (!dcesrv_auth_auth3(call)) {
- return dcesrv_fault(call, DCERPC_FAULT_OTHER);
+ call->conn->auth_state.auth_invalid = true;
}
talloc_free(call);
@@ -757,30 +976,22 @@ static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_
}
/* add this context to the list of available context_ids */
- context = talloc(call->conn, struct dcesrv_connection_context);
+ context = talloc_zero(call->conn, struct dcesrv_connection_context);
if (context == NULL) {
return NT_STATUS_NO_MEMORY;
}
context->conn = call->conn;
context->iface = iface;
context->context_id = context_id;
- if (call->pkt.u.alter.assoc_group_id != 0) {
- context->assoc_group = dcesrv_assoc_group_reference(context,
- call->conn->dce_ctx,
- call->pkt.u.alter.assoc_group_id);
- } else {
- context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
- }
- if (context->assoc_group == NULL) {
- talloc_free(context);
- call->context = NULL;
- return NT_STATUS_NO_MEMORY;
- }
+ /* legacy for openchange dcesrv_mapiproxy.c */
+ context->assoc_group = call->conn->assoc_group;
context->private_data = NULL;
DLIST_ADD(call->conn->contexts, context);
call->context = context;
talloc_set_destructor(context, dcesrv_connection_context_destructor);
+ dcesrv_prepare_context_auth(call);
+
status = iface->bind(call, iface, if_version);
if (!NT_STATUS_IS_OK(status)) {
/* we don't want to trigger the iface->unbind() hook */
@@ -819,15 +1030,11 @@ static NTSTATUS dcesrv_alter_resp(struct dcesrv_call_state *call,
}
}
pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
- pkt.u.alter_resp.max_xmit_frag = 0x2000;
- pkt.u.alter_resp.max_recv_frag = 0x2000;
- if (result == 0) {
- pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
- } else {
- pkt.u.alter_resp.assoc_group_id = 0;
- }
+ pkt.u.alter_resp.max_xmit_frag = call->conn->max_xmit_frag;
+ pkt.u.alter_resp.max_recv_frag = call->conn->max_recv_frag;
+ pkt.u.alter_resp.assoc_group_id = call->conn->assoc_group->id;
pkt.u.alter_resp.num_results = 1;
- pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
+ pkt.u.alter_resp.ctx_list = talloc_zero(call, struct dcerpc_ack_ctx);
if (!pkt.u.alter_resp.ctx_list) {
return NT_STATUS_NO_MEMORY;
}
@@ -839,21 +1046,15 @@ static NTSTATUS dcesrv_alter_resp(struct dcesrv_call_state *call,
status = dcesrv_auth_alter_ack(call, &pkt);
if (!NT_STATUS_IS_OK(status)) {
- if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
- || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
- || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
- || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
- return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
- }
- return dcesrv_fault(call, 0);
+ return dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR);
}
- rep = talloc(call, struct data_blob_list_item);
+ rep = talloc_zero(call, struct data_blob_list_item);
if (!rep) {
return NT_STATUS_NO_MEMORY;
}
- status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
+ status = ncacn_push_auth(&rep->blob, call, &pkt, call->out_auth_info);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -878,38 +1079,86 @@ static NTSTATUS dcesrv_alter_resp(struct dcesrv_call_state *call,
static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
{
NTSTATUS status;
- uint32_t context_id;
+ const struct dcerpc_ctx_list *ctx = NULL;
+ bool auth_ok = false;
+
+ if (!call->conn->allow_alter) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ status = dcerpc_verify_ncacn_packet_header(&call->pkt,
+ DCERPC_PKT_ALTER,
+ call->pkt.u.alter.auth_info.length,
+ 0, /* required flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
- /* handle any authentication that is being requested */
- if (!dcesrv_auth_alter(call)) {
- /* TODO: work out the right reject code */
- return dcesrv_alter_resp(call,
- DCERPC_BIND_PROVIDER_REJECT,
- DCERPC_BIND_REASON_ASYNTAX);
+ auth_ok = dcesrv_auth_alter(call);
+ if (!auth_ok) {
+ if (call->in_auth_info.auth_type == DCERPC_AUTH_TYPE_NONE) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_FAULT_ACCESS_DENIED);
+ }
}
- context_id = call->pkt.u.alter.ctx_list[0].context_id;
+ if (call->pkt.u.alter.num_contexts < 1) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+ ctx = &call->pkt.u.alter.ctx_list[0];
+ if (ctx->num_transfer_syntaxes < 1) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
/* see if they are asking for a new interface */
- call->context = dcesrv_find_context(call->conn, context_id);
+ call->context = dcesrv_find_context(call->conn, ctx->context_id);
if (!call->context) {
- status = dcesrv_alter_new_context(call, context_id);
+ status = dcesrv_alter_new_context(call, ctx->context_id);
if (!NT_STATUS_IS_OK(status)) {
return dcesrv_alter_resp(call,
DCERPC_BIND_PROVIDER_REJECT,
DCERPC_BIND_REASON_ASYNTAX);
}
+ } else {
+ bool ok;
+
+ ok = ndr_syntax_id_equal(&ctx->abstract_syntax,
+ &call->context->iface->syntax_id);
+ if (!ok) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ if (ctx->num_transfer_syntaxes != 1) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ ok = ndr_syntax_id_equal(&ctx->transfer_syntaxes[0],
+ &ndr_transfer_syntax_ndr);
+ if (!ok) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
}
- if (call->pkt.u.alter.assoc_group_id != 0 &&
- lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
- call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
- DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
- call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
- /* TODO: can they ask for a new association group? */
- return dcesrv_alter_resp(call,
- DCERPC_BIND_PROVIDER_REJECT,
- DCERPC_BIND_REASON_ASYNTAX);
+ /* handle any authentication that is being requested */
+ if (!auth_ok) {
+ if (call->in_auth_info.auth_type !=
+ call->conn->auth_state.auth_type)
+ {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_FAULT_SEC_PKG_ERROR);
+ }
+ return dcesrv_fault_disconnect(call, DCERPC_FAULT_ACCESS_DENIED);
}
return dcesrv_alter_resp(call,
@@ -982,10 +1231,17 @@ done:
*/
static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
{
+ const struct dcesrv_endpoint *endpoint = call->conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(endpoint->ep_description);
struct ndr_pull *pull;
NTSTATUS status;
struct dcesrv_connection_context *context;
+ if (!call->conn->allow_request) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
/* if authenticated, and the mech we use can't do async replies, don't use them... */
if (call->conn->auth_state.gensec_security &&
!gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
@@ -997,6 +1253,49 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
}
+ switch (call->conn->auth_state.auth_level) {
+ case DCERPC_AUTH_LEVEL_NONE:
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ if (!context->allow_connect) {
+ char *addr;
+
+ addr = tsocket_address_string(call->conn->remote_address,
+ call);
+
+ DEBUG(2, ("%s: restrict auth_level_connect access "
+ "to [%s] with auth[type=0x%x,level=0x%x] "
+ "on [%s] from [%s]\n",
+ __func__, context->iface->name,
+ call->conn->auth_state.auth_type,
+ call->conn->auth_state.auth_level,
+ derpc_transport_string_by_transport(transport),
+ addr));
+ return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
+ }
+ break;
+ }
+
+ if (call->conn->auth_state.auth_level < context->min_auth_level) {
+ char *addr;
+
+ addr = tsocket_address_string(call->conn->remote_address, call);
+
+ DEBUG(2, ("%s: restrict access by min_auth_level[0x%x] "
+ "to [%s] with auth[type=0x%x,level=0x%x] "
+ "on [%s] from [%s]\n",
+ __func__,
+ context->min_auth_level,
+ context->iface->name,
+ call->conn->auth_state.auth_type,
+ call->conn->auth_state.auth_level,
+ derpc_transport_string_by_transport(transport),
+ addr));
+ return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
+ }
+
pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
NT_STATUS_HAVE_NO_MEMORY(pull);
@@ -1083,12 +1382,13 @@ _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(stru
/*
process some input to a dcerpc endpoint server.
*/
-NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
- struct ncacn_packet *pkt,
- DATA_BLOB blob)
+static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
+ struct ncacn_packet *pkt,
+ DATA_BLOB blob)
{
NTSTATUS status;
struct dcesrv_call_state *call;
+ struct dcesrv_call_state *existing = NULL;
call = talloc_zero(dce_conn, struct dcesrv_call_state);
if (!call) {
@@ -1109,77 +1409,187 @@ NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
talloc_set_destructor(call, dcesrv_call_dequeue);
- /* we have to check the signing here, before combining the
- pdus */
- if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
- !dcesrv_auth_request(call, &blob)) {
- return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
+ if (call->conn->allow_bind) {
+ /*
+ * Only one bind is possible per connection
+ */
+ call->conn->allow_bind = false;
+ return dcesrv_bind(call);
}
- /* see if this is a continued packet */
- if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
- !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
- struct dcesrv_call_state *call2 = call;
- uint32_t alloc_size;
-
- /* we only allow fragmented requests, no other packet types */
- if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
- return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
+ /* we have to check the signing here, before combining the
+ pdus */
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
+ if (!call->conn->allow_request) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_NCA_S_PROTO_ERROR);
}
- /* this is a continuation of an existing call - find the call
- then tack it on the end */
- call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
- if (!call) {
- return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
+ status = dcerpc_verify_ncacn_packet_header(&call->pkt,
+ DCERPC_PKT_REQUEST,
+ call->pkt.u.request.stub_and_verifier.length,
+ 0, /* required_flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_PENDING_CANCEL |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_NCA_S_PROTO_ERROR);
}
- if (call->pkt.ptype != call2->pkt.ptype) {
- /* trying to play silly buggers are we? */
- return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
+ if (call->pkt.frag_length > DCERPC_FRAG_MAX_SIZE) {
+ /*
+ * We don't use dcesrv_fault_disconnect()
+ * here, because we don't want to set
+ * DCERPC_PFC_FLAG_DID_NOT_EXECUTE
+ *
+ * Note that we don't check against the negotiated
+ * max_recv_frag, but a hard coded value.
+ */
+ dcesrv_call_disconnect_after(call,
+ "dcesrv_auth_request - frag_length too large");
+ return dcesrv_fault(call,
+ DCERPC_NCA_S_PROTO_ERROR);
}
- if (memcmp(call->pkt.drep, call2->pkt.drep, sizeof(pkt->drep)) != 0) {
- return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
+
+ if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
+ /* only one request is possible in the fragmented list */
+ if (dce_conn->incoming_fragmented_call_list != NULL) {
+ TALLOC_FREE(call);
+ call = dce_conn->incoming_fragmented_call_list;
+ dcesrv_call_disconnect_after(call,
+ "dcesrv_auth_request - "
+ "existing fragmented call");
+ return dcesrv_fault(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+ if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_PENDING_CANCEL) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_FAULT_NO_CALL_ACTIVE);
+ }
+ } else {
+ const struct dcerpc_request *nr = &call->pkt.u.request;
+ const struct dcerpc_request *er = NULL;
+ int cmp;
+
+ existing = dcesrv_find_fragmented_call(dce_conn,
+ call->pkt.call_id);
+ if (existing == NULL) {
+ dcesrv_call_disconnect_after(call,
+ "dcesrv_auth_request - "
+ "no existing fragmented call");
+ return dcesrv_fault(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+ er = &existing->pkt.u.request;
+
+ if (call->pkt.ptype != existing->pkt.ptype) {
+ /* trying to play silly buggers are we? */
+ return dcesrv_fault_disconnect(existing,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+ cmp = memcmp(call->pkt.drep, existing->pkt.drep,
+ sizeof(pkt->drep));
+ if (cmp != 0) {
+ return dcesrv_fault_disconnect(existing,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+ if (nr->context_id != er->context_id) {
+ return dcesrv_fault_disconnect(existing,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+ if (nr->opnum != er->opnum) {
+ return dcesrv_fault_disconnect(existing,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
}
- if (call->pkt.call_id != call2->pkt.call_id) {
- return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
+
+ if (!dcesrv_auth_request(call, &blob)) {
+ /*
+ * We don't use dcesrv_fault_disconnect()
+ * here, because we don't want to set
+ * DCERPC_PFC_FLAG_DID_NOT_EXECUTE
+ */
+ dcesrv_call_disconnect_after(call,
+ "dcesrv_auth_request - failed");
+ return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
}
- if (call->pkt.u.request.context_id != call2->pkt.u.request.context_id) {
- return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ /* see if this is a continued packet */
+ if (existing != NULL) {
+ struct dcerpc_request *er = &existing->pkt.u.request;
+ const struct dcerpc_request *nr = &call->pkt.u.request;
+ size_t available;
+ size_t alloc_size;
+ size_t alloc_hint;
+
+ /*
+ * Up to 4 MByte are allowed by all fragments
+ */
+ available = DCERPC_NCACN_PAYLOAD_MAX_SIZE;
+ if (er->stub_and_verifier.length > available) {
+ dcesrv_call_disconnect_after(existing,
+ "dcesrv_auth_request - existing payload too large");
+ return dcesrv_fault(existing, DCERPC_FAULT_ACCESS_DENIED);
}
- if (call->pkt.u.request.opnum != call2->pkt.u.request.opnum) {
- return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
+ available -= er->stub_and_verifier.length;
+ if (nr->alloc_hint > available) {
+ dcesrv_call_disconnect_after(existing,
+ "dcesrv_auth_request - alloc hint too large");
+ return dcesrv_fault(existing, DCERPC_FAULT_ACCESS_DENIED);
}
-
- alloc_size = call->pkt.u.request.stub_and_verifier.length +
- call2->pkt.u.request.stub_and_verifier.length;
- if (call->pkt.u.request.alloc_hint > alloc_size) {
- alloc_size = call->pkt.u.request.alloc_hint;
+ if (nr->stub_and_verifier.length > available) {
+ dcesrv_call_disconnect_after(existing,
+ "dcesrv_auth_request - new payload too large");
+ return dcesrv_fault(existing, DCERPC_FAULT_ACCESS_DENIED);
}
-
- call->pkt.u.request.stub_and_verifier.data =
- talloc_realloc(call,
- call->pkt.u.request.stub_and_verifier.data,
+ alloc_hint = er->stub_and_verifier.length + nr->alloc_hint;
+ /* allocate at least 1 byte */
+ alloc_hint = MAX(alloc_hint, 1);
+ alloc_size = er->stub_and_verifier.length +
+ nr->stub_and_verifier.length;
+ alloc_size = MAX(alloc_size, alloc_hint);
+
+ er->stub_and_verifier.data =
+ talloc_realloc(existing,
+ er->stub_and_verifier.data,
uint8_t, alloc_size);
- if (!call->pkt.u.request.stub_and_verifier.data) {
- return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
+ if (er->stub_and_verifier.data == NULL) {
+ TALLOC_FREE(call);
+ return dcesrv_fault_with_flags(existing,
+ DCERPC_FAULT_OUT_OF_RESOURCES,
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
}
- memcpy(call->pkt.u.request.stub_and_verifier.data +
- call->pkt.u.request.stub_and_verifier.length,
- call2->pkt.u.request.stub_and_verifier.data,
- call2->pkt.u.request.stub_and_verifier.length);
- call->pkt.u.request.stub_and_verifier.length +=
- call2->pkt.u.request.stub_and_verifier.length;
+ memcpy(er->stub_and_verifier.data +
+ er->stub_and_verifier.length,
+ nr->stub_and_verifier.data,
+ nr->stub_and_verifier.length);
+ er->stub_and_verifier.length += nr->stub_and_verifier.length;
- call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
+ existing->pkt.pfc_flags |= (call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
- talloc_free(call2);
+ TALLOC_FREE(call);
+ call = existing;
}
/* this may not be the last pdu in the chain - if its isn't then
just put it on the incoming_fragmented_call_list and wait for the rest */
if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
+ /*
+ * Up to 4 MByte are allowed by all fragments
+ */
+ if (call->pkt.u.request.alloc_hint > DCERPC_NCACN_PAYLOAD_MAX_SIZE) {
+ dcesrv_call_disconnect_after(call,
+ "dcesrv_auth_request - initial alloc hint too large");
+ return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
+ }
dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
return NT_STATUS_OK;
}
@@ -1189,7 +1599,8 @@ NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
switch (call->pkt.ptype) {
case DCERPC_PKT_BIND:
- status = dcesrv_bind(call);
+ status = dcesrv_bind_nak(call,
+ DCERPC_BIND_NAK_REASON_NOT_SPECIFIED);
break;
case DCERPC_PKT_AUTH3:
status = dcesrv_auth3(call);
@@ -1201,7 +1612,7 @@ NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
status = dcesrv_request(call);
break;
default:
- status = NT_STATUS_INVALID_PARAMETER;
+ status = dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
break;
}
@@ -1228,7 +1639,7 @@ _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
return NT_STATUS_INTERNAL_ERROR;
}
- dce_ctx = talloc(mem_ctx, struct dcesrv_context);
+ dce_ctx = talloc_zero(mem_ctx, struct dcesrv_context);
NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
dce_ctx->endpoint_list = NULL;
dce_ctx->lp_ctx = lp_ctx;
@@ -1366,6 +1777,11 @@ static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, cons
srv_conn = talloc_get_type(dce_conn->transport.private_data,
struct stream_connection);
+ dce_conn->allow_bind = false;
+ dce_conn->allow_auth3 = false;
+ dce_conn->allow_alter = false;
+ dce_conn->allow_request = false;
+
if (dce_conn->pending_call_list == NULL) {
char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason);
@@ -1429,6 +1845,7 @@ struct dcesrv_sock_reply_state {
};
static void dcesrv_sock_reply_done(struct tevent_req *subreq);
+static void dcesrv_call_terminate_step1(struct tevent_req *subreq);
static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
{
@@ -1444,7 +1861,7 @@ static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
struct dcesrv_sock_reply_state *substate;
struct tevent_req *subreq;
- substate = talloc(call, struct dcesrv_sock_reply_state);
+ substate = talloc_zero(call, struct dcesrv_sock_reply_state);
if (!substate) {
dcesrv_terminate_connection(dce_conn, "no memory");
return;
@@ -1455,7 +1872,7 @@ static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
DLIST_REMOVE(call->replies, rep);
- if (call->replies == NULL) {
+ if (call->replies == NULL && call->terminate_reason == NULL) {
substate->call = call;
}
@@ -1475,6 +1892,20 @@ static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
substate);
}
+ if (call->terminate_reason != NULL) {
+ struct tevent_req *subreq;
+
+ subreq = tevent_queue_wait_send(call,
+ dce_conn->event_ctx,
+ dce_conn->send_queue);
+ if (!subreq) {
+ dcesrv_terminate_connection(dce_conn, __location__);
+ return;
+ }
+ tevent_req_set_callback(subreq, dcesrv_call_terminate_step1,
+ call);
+ }
+
DLIST_REMOVE(call->conn->call_list, call);
call->list = DCESRV_LIST_NONE;
}
@@ -1502,8 +1933,51 @@ static void dcesrv_sock_reply_done(struct tevent_req *subreq)
}
}
+static void dcesrv_call_terminate_step2(struct tevent_req *subreq);
+
+static void dcesrv_call_terminate_step1(struct tevent_req *subreq)
+{
+ struct dcesrv_call_state *call = tevent_req_callback_data(subreq,
+ struct dcesrv_call_state);
+ bool ok;
+ struct timeval tv;
+
+ /* make sure we stop send queue before removing subreq */
+ tevent_queue_stop(call->conn->send_queue);
+
+ ok = tevent_queue_wait_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ dcesrv_terminate_connection(call->conn, __location__);
+ return;
+ }
+
+ /* disconnect after 200 usecs */
+ tv = timeval_current_ofs_usec(200);
+ subreq = tevent_wakeup_send(call, call->conn->event_ctx, tv);
+ if (subreq == NULL) {
+ dcesrv_terminate_connection(call->conn, __location__);
+ return;
+ }
+ tevent_req_set_callback(subreq, dcesrv_call_terminate_step2,
+ call);
+}
+
+static void dcesrv_call_terminate_step2(struct tevent_req *subreq)
+{
+ struct dcesrv_call_state *call = tevent_req_callback_data(subreq,
+ struct dcesrv_call_state);
+ bool ok;
+ ok = tevent_wakeup_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ dcesrv_terminate_connection(call->conn, __location__);
+ return;
+ }
+ dcesrv_terminate_connection(call->conn, call->terminate_reason);
+}
struct dcesrv_socket_context {
const struct dcesrv_endpoint *endpoint;
@@ -1688,7 +2162,7 @@ static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx,
NTSTATUS status;
const char *endpoint;
- dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
+ dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context);
NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
/* remember the endpoint of this socket */
@@ -1744,7 +2218,7 @@ static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx,
full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
endpoint);
- dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
+ dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context);
NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
/* remember the endpoint of this socket */
@@ -1778,7 +2252,7 @@ static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
return NT_STATUS_INVALID_PARAMETER;
}
- dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
+ dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context);
NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
/* remember the endpoint of this socket */
@@ -1816,7 +2290,7 @@ static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct
port = atoi(endpoint);
}
- dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
+ dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context);
NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
/* remember the endpoint of this socket */
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index 8786cd83cc6..15b25ea8fda 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -130,6 +130,14 @@ struct dcesrv_call_state {
/* this is used by the boilerplate code to generate DCERPC faults */
uint32_t fault_code;
+
+ /* the reason why we terminate the connection after sending a response */
+ const char *terminate_reason;
+
+ /* temporary auth_info fields */
+ struct dcerpc_auth in_auth_info;
+ struct dcerpc_auth _out_auth_info;
+ struct dcerpc_auth *out_auth_info;
};
#define DCESRV_HANDLE_ANY 255
@@ -146,18 +154,23 @@ struct dcesrv_handle {
/* hold the authentication state information */
struct dcesrv_auth {
- struct dcerpc_auth *auth_info;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+ uint32_t auth_context_id;
struct gensec_security *gensec_security;
struct auth_session_info *session_info;
NTSTATUS (*session_key)(struct dcesrv_connection *, DATA_BLOB *session_key);
bool client_hdr_signing;
bool hdr_signing;
+ bool auth_finished;
+ bool auth_invalid;
};
struct dcesrv_connection_context {
struct dcesrv_connection_context *next, *prev;
uint32_t context_id;
+ /* TODO: remove this legacy (for openchange) in master */
struct dcesrv_assoc_group *assoc_group;
/* the connection this is on */
@@ -168,6 +181,12 @@ struct dcesrv_connection_context {
/* private data for the interface implementation */
void *private_data;
+
+ /*
+ * the minimum required auth level for this interface
+ */
+ enum dcerpc_AuthLevel min_auth_level;
+ bool allow_connect;
};
@@ -195,12 +214,20 @@ struct dcesrv_connection {
struct dcesrv_call_state *call_list;
/* the maximum size the client wants to receive */
- uint32_t cli_max_recv_frag;
+ uint16_t max_recv_frag;
+ uint16_t max_xmit_frag;
DATA_BLOB partial_input;
- /* the current authentication state */
- struct dcesrv_auth auth_state;
+ /* This can be removed in master... */
+ struct {
+ struct dcerpc_auth *auth_info;
+ struct gensec_security *gensec_security;
+ struct auth_session_info *session_info;
+ NTSTATUS (*session_key)(struct dcesrv_connection *, DATA_BLOB *session_key);
+ bool client_hdr_signing;
+ bool hdr_signing;
+ } _unused_auth_state;
/* the event_context that will be used for this connection */
struct tevent_context *event_ctx;
@@ -232,6 +259,20 @@ struct dcesrv_connection {
const struct tsocket_address *local_address;
const struct tsocket_address *remote_address;
+
+ /* the current authentication state */
+ struct dcesrv_auth auth_state;
+
+ /*
+ * remember which pdu types are allowed
+ */
+ bool allow_bind;
+ bool allow_auth3;
+ bool allow_alter;
+ bool allow_request;
+
+ /* the association group the connection belongs to */
+ struct dcesrv_assoc_group *assoc_group;
};
@@ -407,5 +448,13 @@ _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call);
*/
_PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call);
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface);
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface);
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface);
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface);
#endif /* SAMBA_DCERPC_SERVER_H */
diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index 51f299550bd..2b3f8b07710 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -39,26 +39,55 @@
*/
bool dcesrv_auth_bind(struct dcesrv_call_state *call)
{
- struct cli_credentials *server_credentials;
+ struct cli_credentials *server_credentials = NULL;
struct ncacn_packet *pkt = &call->pkt;
struct dcesrv_connection *dce_conn = call->conn;
struct dcesrv_auth *auth = &dce_conn->auth_state;
NTSTATUS status;
uint32_t auth_length;
- if (pkt->u.bind.auth_info.length == 0) {
- dce_conn->auth_state.auth_info = NULL;
+ if (pkt->auth_length == 0) {
+ auth->auth_type = DCERPC_AUTH_TYPE_NONE;
+ auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
+ auth->auth_context_id = 0;
return true;
}
- dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth);
- if (!dce_conn->auth_state.auth_info) {
+ status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.bind.auth_info,
+ &call->in_auth_info,
+ &auth_length, false);
+ if (!NT_STATUS_IS_OK(status)) {
return false;
}
- status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.bind.auth_info,
- dce_conn->auth_state.auth_info,
- &auth_length, false);
+ switch (call->in_auth_info.auth_level) {
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ case DCERPC_AUTH_LEVEL_CALL:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ /*
+ * We evaluate auth_type only if auth_level was valid
+ */
+ break;
+ default:
+ /*
+ * Setting DCERPC_AUTH_LEVEL_NONE,
+ * gives the caller a chance to decide what
+ * reject_reason to use
+ *
+ * Note: DCERPC_AUTH_LEVEL_NONE == 1
+ */
+ auth->auth_type = DCERPC_AUTH_TYPE_NONE;
+ auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
+ auth->auth_context_id = 0;
+ return false;
+ }
+
+ auth->auth_type = call->in_auth_info.auth_type;
+ auth->auth_level = call->in_auth_info.auth_level;
+ auth->auth_context_id = call->in_auth_info.auth_context_id;
+
server_credentials
= cli_credentials_init(call);
if (!server_credentials) {
@@ -69,9 +98,9 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call)
cli_credentials_set_conf(server_credentials, call->conn->dce_ctx->lp_ctx);
status = cli_credentials_set_machine_account(server_credentials, call->conn->dce_ctx->lp_ctx);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status)));
- talloc_free(server_credentials);
- server_credentials = NULL;
+ DEBUG(1, ("Failed to obtain server credentials: %s\n",
+ nt_errstr(status)));
+ return false;
}
status = samba_server_gensec_start(dce_conn, call->event_ctx,
@@ -80,14 +109,28 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call)
server_credentials,
NULL,
&auth->gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to call samba_server_gensec_start %s\n",
+ nt_errstr(status)));
+ return false;
+ }
- status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_info->auth_type,
- auth->auth_info->auth_level);
+ if (call->conn->remote_address != NULL) {
+ status = gensec_set_remote_address(auth->gensec_security,
+ call->conn->remote_address);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to call gensec_set_remote_address() %s\n",
+ nt_errstr(status)));
+ return false;
+ }
+ }
+ status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_type,
+ auth->auth_level);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3, ("Failed to start GENSEC mechanism for DCERPC server: auth_type=%d, auth_level=%d: %s\n",
- (int)auth->auth_info->auth_type,
- (int)auth->auth_info->auth_level,
+ (int)auth->auth_type,
+ (int)auth->auth_level,
nt_errstr(status)));
return false;
}
@@ -105,10 +148,20 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe
NTSTATUS status;
bool want_header_signing = false;
- if (!call->conn->auth_state.gensec_security) {
+ dce_conn->allow_alter = true;
+ dce_conn->allow_auth3 = true;
+
+ if (call->pkt.auth_length == 0) {
+ dce_conn->auth_state.auth_finished = true;
+ dce_conn->allow_request = true;
return NT_STATUS_OK;
}
+ /* We can't work without an existing gensec state */
+ if (!call->conn->auth_state.gensec_security) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) {
dce_conn->auth_state.client_hdr_signing = true;
want_header_signing = true;
@@ -118,10 +171,17 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe
want_header_signing = false;
}
+ call->_out_auth_info = (struct dcerpc_auth) {
+ .auth_type = dce_conn->auth_state.auth_type,
+ .auth_level = dce_conn->auth_state.auth_level,
+ .auth_context_id = dce_conn->auth_state.auth_context_id,
+ };
+ call->out_auth_info = &call->_out_auth_info;
+
status = gensec_update_ev(dce_conn->auth_state.gensec_security,
call, call->event_ctx,
- dce_conn->auth_state.auth_info->credentials,
- &dce_conn->auth_state.auth_info->credentials);
+ call->in_auth_info.credentials,
+ &call->out_auth_info->credentials);
if (NT_STATUS_IS_OK(status)) {
status = gensec_session_info(dce_conn->auth_state.gensec_security,
@@ -131,6 +191,8 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe
DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
return status;
}
+ dce_conn->auth_state.auth_finished = true;
+ dce_conn->allow_request = true;
if (!gensec_have_feature(dce_conn->auth_state.gensec_security,
GENSEC_FEATURE_SIGN_PKT_HEADER))
@@ -149,9 +211,6 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe
dce_conn->auth_state.session_key = dcesrv_generic_session_key;
return NT_STATUS_OK;
} else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- dce_conn->auth_state.auth_info->auth_pad_length = 0;
- dce_conn->auth_state.auth_info->auth_reserved = 0;
-
if (!gensec_have_feature(dce_conn->auth_state.gensec_security,
GENSEC_FEATURE_SIGN_PKT_HEADER))
{
@@ -184,24 +243,49 @@ bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
NTSTATUS status;
uint32_t auth_length;
- /* We can't work without an existing gensec state, and an new blob to feed it */
- if (!dce_conn->auth_state.auth_info ||
- !dce_conn->auth_state.gensec_security ||
- pkt->u.auth3.auth_info.length == 0) {
+ if (pkt->auth_length == 0) {
+ return false;
+ }
+
+ if (dce_conn->auth_state.auth_finished) {
+ return false;
+ }
+
+ /* We can't work without an existing gensec state */
+ if (!dce_conn->auth_state.gensec_security) {
return false;
}
status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.auth3.auth_info,
- dce_conn->auth_state.auth_info, &auth_length, true);
+ &call->in_auth_info, &auth_length, true);
if (!NT_STATUS_IS_OK(status)) {
return false;
}
+ if (call->in_auth_info.auth_type != dce_conn->auth_state.auth_type) {
+ return false;
+ }
+
+ if (call->in_auth_info.auth_level != dce_conn->auth_state.auth_level) {
+ return false;
+ }
+
+ if (call->in_auth_info.auth_context_id != dce_conn->auth_state.auth_context_id) {
+ return false;
+ }
+
+ call->_out_auth_info = (struct dcerpc_auth) {
+ .auth_type = dce_conn->auth_state.auth_type,
+ .auth_level = dce_conn->auth_state.auth_level,
+ .auth_context_id = dce_conn->auth_state.auth_context_id,
+ };
+ call->out_auth_info = &call->_out_auth_info;
+
/* Pass the extra data we got from the client down to gensec for processing */
status = gensec_update_ev(dce_conn->auth_state.gensec_security,
call, call->event_ctx,
- dce_conn->auth_state.auth_info->credentials,
- &dce_conn->auth_state.auth_info->credentials);
+ call->in_auth_info.credentials,
+ &call->out_auth_info->credentials);
if (NT_STATUS_IS_OK(status)) {
status = gensec_session_info(dce_conn->auth_state.gensec_security,
dce_conn,
@@ -210,8 +294,18 @@ bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
return false;
}
+ dce_conn->auth_state.auth_finished = true;
+ dce_conn->allow_request = true;
+
/* Now that we are authenticated, go back to the generic session key... */
dce_conn->auth_state.session_key = dcesrv_generic_session_key;
+
+ if (call->out_auth_info->credentials.length != 0) {
+
+ DEBUG(4, ("GENSEC produced output token (len=%u) at bind_auth3\n",
+ (unsigned)call->out_auth_info->credentials.length));
+ return false;
+ }
return true;
} else {
DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_auth3: %s\n",
@@ -233,27 +327,40 @@ bool dcesrv_auth_alter(struct dcesrv_call_state *call)
uint32_t auth_length;
/* on a pure interface change there is no auth blob */
- if (pkt->u.alter.auth_info.length == 0) {
+ if (pkt->auth_length == 0) {
+ if (!dce_conn->auth_state.auth_finished) {
+ return false;
+ }
return true;
}
- /* We can't work without an existing gensec state */
- if (!dce_conn->auth_state.gensec_security) {
+ if (dce_conn->auth_state.auth_finished) {
return false;
}
- dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth);
- if (!dce_conn->auth_state.auth_info) {
+ /* We can't work without an existing gensec state */
+ if (!dce_conn->auth_state.gensec_security) {
return false;
}
status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.alter.auth_info,
- dce_conn->auth_state.auth_info,
- &auth_length, true);
+ &call->in_auth_info, &auth_length, true);
if (!NT_STATUS_IS_OK(status)) {
return false;
}
+ if (call->in_auth_info.auth_type != dce_conn->auth_state.auth_type) {
+ return false;
+ }
+
+ if (call->in_auth_info.auth_level != dce_conn->auth_state.auth_level) {
+ return false;
+ }
+
+ if (call->in_auth_info.auth_context_id != dce_conn->auth_state.auth_context_id) {
+ return false;
+ }
+
return true;
}
@@ -268,19 +375,25 @@ NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_pack
/* on a pure interface change there is no auth_info structure
setup */
- if (!call->conn->auth_state.auth_info ||
- dce_conn->auth_state.auth_info->credentials.length == 0) {
+ if (call->pkt.auth_length == 0) {
return NT_STATUS_OK;
}
if (!call->conn->auth_state.gensec_security) {
- return NT_STATUS_INVALID_PARAMETER;
+ return NT_STATUS_INTERNAL_ERROR;
}
+ call->_out_auth_info = (struct dcerpc_auth) {
+ .auth_type = dce_conn->auth_state.auth_type,
+ .auth_level = dce_conn->auth_state.auth_level,
+ .auth_context_id = dce_conn->auth_state.auth_context_id,
+ };
+ call->out_auth_info = &call->_out_auth_info;
+
status = gensec_update_ev(dce_conn->auth_state.gensec_security,
call, call->event_ctx,
- dce_conn->auth_state.auth_info->credentials,
- &dce_conn->auth_state.auth_info->credentials);
+ call->in_auth_info.credentials,
+ &call->out_auth_info->credentials);
if (NT_STATUS_IS_OK(status)) {
status = gensec_session_info(dce_conn->auth_state.gensec_security,
@@ -290,13 +403,13 @@ NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_pack
DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
return status;
}
+ dce_conn->auth_state.auth_finished = true;
+ dce_conn->allow_request = true;
/* Now that we are authenticated, got back to the generic session key... */
dce_conn->auth_state.session_key = dcesrv_generic_session_key;
return NT_STATUS_OK;
} else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- dce_conn->auth_state.auth_info->auth_pad_length = 0;
- dce_conn->auth_state.auth_info->auth_reserved = 0;
return NT_STATUS_OK;
}
@@ -312,24 +425,23 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
{
struct ncacn_packet *pkt = &call->pkt;
struct dcesrv_connection *dce_conn = call->conn;
- struct dcerpc_auth auth;
NTSTATUS status;
uint32_t auth_length;
size_t hdr_size = DCERPC_REQUEST_LENGTH;
- if (!dce_conn->auth_state.auth_info ||
- !dce_conn->auth_state.gensec_security) {
- if (pkt->auth_length != 0) {
- return false;
- }
- return true;
+ if (!dce_conn->allow_request) {
+ return false;
+ }
+
+ if (dce_conn->auth_state.auth_invalid) {
+ return false;
}
if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
hdr_size += 16;
}
- switch (dce_conn->auth_state.auth_info->auth_level) {
+ switch (dce_conn->auth_state.auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
case DCERPC_AUTH_LEVEL_INTEGRITY:
break;
@@ -349,36 +461,41 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
return false;
}
+ if (!dce_conn->auth_state.gensec_security) {
+ return false;
+ }
+
status = dcerpc_pull_auth_trailer(pkt, call,
&pkt->u.request.stub_and_verifier,
- &auth, &auth_length, false);
+ &call->in_auth_info, &auth_length, false);
if (!NT_STATUS_IS_OK(status)) {
return false;
}
- if (auth.auth_type != dce_conn->auth_state.auth_info->auth_type) {
+ if (call->in_auth_info.auth_type != dce_conn->auth_state.auth_type) {
return false;
}
- if (auth.auth_level != dce_conn->auth_state.auth_info->auth_level) {
+ if (call->in_auth_info.auth_level != dce_conn->auth_state.auth_level) {
return false;
}
- if (auth.auth_context_id != dce_conn->auth_state.auth_info->auth_context_id) {
+ if (call->in_auth_info.auth_context_id != dce_conn->auth_state.auth_context_id) {
return false;
}
pkt->u.request.stub_and_verifier.length -= auth_length;
/* check signature or unseal the packet */
- switch (dce_conn->auth_state.auth_info->auth_level) {
+ switch (dce_conn->auth_state.auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
status = gensec_unseal_packet(dce_conn->auth_state.gensec_security,
full_packet->data + hdr_size,
pkt->u.request.stub_and_verifier.length,
full_packet->data,
- full_packet->length-auth.credentials.length,
- &auth.credentials);
+ full_packet->length-
+ call->in_auth_info.credentials.length,
+ &call->in_auth_info.credentials);
memcpy(pkt->u.request.stub_and_verifier.data,
full_packet->data + hdr_size,
pkt->u.request.stub_and_verifier.length);
@@ -389,8 +506,9 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
pkt->u.request.stub_and_verifier.data,
pkt->u.request.stub_and_verifier.length,
full_packet->data,
- full_packet->length-auth.credentials.length,
- &auth.credentials);
+ full_packet->length-
+ call->in_auth_info.credentials.length,
+ &call->in_auth_info.credentials);
break;
case DCERPC_AUTH_LEVEL_CONNECT:
@@ -404,10 +522,10 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
}
/* remove the indicated amount of padding */
- if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) {
+ if (pkt->u.request.stub_and_verifier.length < call->in_auth_info.auth_pad_length) {
return false;
}
- pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length;
+ pkt->u.request.stub_and_verifier.length -= call->in_auth_info.auth_pad_length;
return NT_STATUS_IS_OK(status);
}
@@ -427,13 +545,7 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
uint32_t payload_length;
DATA_BLOB creds2;
- /* non-signed packets are simple */
- if (dce_conn->auth_state.auth_info == NULL) {
- status = ncacn_push_auth(blob, call, pkt, NULL);
- return NT_STATUS_IS_OK(status);
- }
-
- switch (dce_conn->auth_state.auth_info->auth_level) {
+ switch (dce_conn->auth_state.auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
case DCERPC_AUTH_LEVEL_INTEGRITY:
if (sig_size == 0) {
@@ -458,6 +570,10 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
return false;
}
+ if (!dce_conn->auth_state.gensec_security) {
+ return false;
+ }
+
ndr = ndr_push_init_ctx(call);
if (!ndr) {
return false;
@@ -472,28 +588,31 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
return false;
}
+ call->_out_auth_info = (struct dcerpc_auth) {
+ .auth_type = dce_conn->auth_state.auth_type,
+ .auth_level = dce_conn->auth_state.auth_level,
+ .auth_context_id = dce_conn->auth_state.auth_context_id,
+ };
+ call->out_auth_info = &call->_out_auth_info;
+
/* pad to 16 byte multiple in the payload portion of the
packet. This matches what w2k3 does. Note that we can't use
ndr_push_align() as that is relative to the start of the
whole packet, whereas w2k8 wants it relative to the start
of the stub */
- dce_conn->auth_state.auth_info->auth_pad_length =
+ call->out_auth_info->auth_pad_length =
DCERPC_AUTH_PAD_LENGTH(pkt->u.response.stub_and_verifier.length);
- ndr_err = ndr_push_zero(ndr,
- dce_conn->auth_state.auth_info->auth_pad_length);
+ ndr_err = ndr_push_zero(ndr, call->out_auth_info->auth_pad_length);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return false;
}
payload_length = pkt->u.response.stub_and_verifier.length +
- dce_conn->auth_state.auth_info->auth_pad_length;
-
- /* we start without signature, it will appended later */
- dce_conn->auth_state.auth_info->credentials = data_blob(NULL, 0);
+ call->out_auth_info->auth_pad_length;
/* add the auth verifier */
ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
- dce_conn->auth_state.auth_info);
+ call->out_auth_info);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return false;
}
@@ -511,7 +630,7 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
dcerpc_set_auth_length(blob, sig_size);
/* sign or seal the packet */
- switch (dce_conn->auth_state.auth_info->auth_level) {
+ switch (dce_conn->auth_state.auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
status = gensec_seal_packet(dce_conn->auth_state.gensec_security,
call,
@@ -544,7 +663,7 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
if (creds2.length != sig_size) {
DEBUG(3,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
(unsigned)creds2.length, (uint32_t)sig_size,
- (unsigned)dce_conn->auth_state.auth_info->auth_pad_length,
+ (unsigned)call->out_auth_info->auth_pad_length,
(unsigned)pkt->u.response.stub_and_verifier.length));
dcerpc_set_frag_length(blob, blob->length + creds2.length);
dcerpc_set_auth_length(blob, creds2.length);
diff --git a/source4/rpc_server/dcesrv_mgmt.c b/source4/rpc_server/dcesrv_mgmt.c
index 8c4eb63ec30..4d3428d13cf 100644
--- a/source4/rpc_server/dcesrv_mgmt.c
+++ b/source4/rpc_server/dcesrv_mgmt.c
@@ -23,6 +23,14 @@
#include "rpc_server/dcerpc_server.h"
#include "librpc/gen_ndr/ndr_mgmt.h"
+#define DCESRV_INTERFACE_MGMT_BIND(call, iface) \
+ dcesrv_interface_mgmt_bind(call, iface)
+static NTSTATUS dcesrv_interface_mgmt_bind(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ return dcesrv_interface_bind_allow_connect(dce_call, iface);
+}
+
/*
mgmt_inq_if_ids
*/
diff --git a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
index be315001ee2..7571756845c 100644
--- a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
+++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
@@ -28,6 +28,14 @@
#include "dnsserver.h"
#include "lib/ldb/include/ldb_private.h"
+#define DCESRV_INTERFACE_DNSSERVER_BIND(call, iface) \
+ dcesrv_interface_dnsserver_bind(call, iface)
+static NTSTATUS dcesrv_interface_dnsserver_bind(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ return dcesrv_interface_bind_require_integrity(dce_call, iface);
+}
+
struct dnsserver_state {
struct loadparm_context *lp_ctx;
struct ldb_context *samdb;
diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c
index 879f63f6df5..c28f557b545 100644
--- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c
+++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c
@@ -39,6 +39,14 @@
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); \
} while (0)
+#define DCESRV_INTERFACE_DRSUAPI_BIND(call, iface) \
+ dcesrv_interface_drsuapi_bind(call, iface)
+static NTSTATUS dcesrv_interface_drsuapi_bind(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ return dcesrv_interface_bind_require_privacy(dce_call, iface);
+}
+
/*
drsuapi_DsBind
*/
diff --git a/source4/rpc_server/echo/rpc_echo.c b/source4/rpc_server/echo/rpc_echo.c
index 4863c779f4c..49c9e23c678 100644
--- a/source4/rpc_server/echo/rpc_echo.c
+++ b/source4/rpc_server/echo/rpc_echo.c
@@ -26,6 +26,13 @@
#include "librpc/gen_ndr/ndr_echo.h"
#include "lib/events/events.h"
+#define DCESRV_INTERFACE_RPCECHO_BIND(call, iface) \
+ dcesrv_interface_rpcecho_bind(call, iface)
+static NTSTATUS dcesrv_interface_rpcecho_bind(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ return dcesrv_interface_bind_allow_connect(dce_call, iface);
+}
static NTSTATUS dcesrv_echo_AddOne(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_AddOne *r)
{
diff --git a/source4/rpc_server/epmapper/rpc_epmapper.c b/source4/rpc_server/epmapper/rpc_epmapper.c
index 62627ce3093..6b934d7d1b4 100644
--- a/source4/rpc_server/epmapper/rpc_epmapper.c
+++ b/source4/rpc_server/epmapper/rpc_epmapper.c
@@ -24,6 +24,14 @@
#include "librpc/gen_ndr/ndr_epmapper.h"
#include "rpc_server/dcerpc_server.h"
+#define DCESRV_INTERFACE_EPMAPPER_BIND(call, iface) \
+ dcesrv_interface_epmapper_bind(call, iface)
+static NTSTATUS dcesrv_interface_epmapper_bind(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ return dcesrv_interface_bind_allow_connect(dce_call, iface);
+}
+
typedef uint32_t error_status_t;
/* handle types for this module */
diff --git a/source4/rpc_server/handles.c b/source4/rpc_server/handles.c
index be9f16ce733..820da49c02d 100644
--- a/source4/rpc_server/handles.c
+++ b/source4/rpc_server/handles.c
@@ -46,7 +46,7 @@ _PUBLIC_ struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_connection_contex
sid = &context->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
- h = talloc(context->assoc_group, struct dcesrv_handle);
+ h = talloc_zero(context->conn->assoc_group, struct dcesrv_handle);
if (!h) {
return NULL;
}
@@ -56,12 +56,12 @@ _PUBLIC_ struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_connection_contex
talloc_free(h);
return NULL;
}
- h->assoc_group = context->assoc_group;
+ h->assoc_group = context->conn->assoc_group;
h->iface = context->iface;
h->wire_handle.handle_type = handle_type;
h->wire_handle.uuid = GUID_random();
- DLIST_ADD(context->assoc_group->handles, h);
+ DLIST_ADD(context->conn->assoc_group->handles, h);
talloc_set_destructor(h, dcesrv_handle_destructor);
@@ -87,7 +87,7 @@ _PUBLIC_ struct dcesrv_handle *dcesrv_handle_fetch(
return dcesrv_handle_new(context, handle_type);
}
- for (h=context->assoc_group->handles; h; h=h->next) {
+ for (h=context->conn->assoc_group->handles; h; h=h->next) {
if (h->wire_handle.handle_type == p->handle_type &&
GUID_equal(&p->uuid, &h->wire_handle.uuid)) {
if (handle_type != DCESRV_HANDLE_ANY &&
diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c
index 53b937ef5d4..0218d9d6814 100644
--- a/source4/rpc_server/lsa/dcesrv_lsa.c
+++ b/source4/rpc_server/lsa/dcesrv_lsa.c
@@ -33,6 +33,14 @@
#include "libcli/security/session.h"
#include "libcli/lsarpc/util_lsarpc.h"
+#define DCESRV_INTERFACE_LSARPC_BIND(call, iface) \
+ dcesrv_interface_lsarpc_bind(call, iface)
+static NTSTATUS dcesrv_interface_lsarpc_bind(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ return dcesrv_interface_bind_reject_connect(dce_call, iface);
+}
+
/*
this type allows us to distinguish handle types
*/
diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c
index 8d92ba89d06..d90ca70c0c1 100644
--- a/source4/rpc_server/lsa/lsa_lookup.c
+++ b/source4/rpc_server/lsa/lsa_lookup.c
@@ -718,7 +718,7 @@ NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call,
{
enum dcerpc_transport_t transport =
dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
- struct dcerpc_auth *auth_info = dce_call->conn->auth_state.auth_info;
+ const struct dcesrv_auth *auth = &dce_call->conn->auth_state;
struct lsa_policy_state *policy_state;
struct lsa_LookupSids2 q;
NTSTATUS status;
@@ -731,8 +731,8 @@ NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call,
* We don't have policy handles on this call. So this must be restricted
* to crypto connections only.
*/
- if (auth_info->auth_type != DCERPC_AUTH_TYPE_SCHANNEL ||
- auth_info->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
+ if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL ||
+ auth->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
}
@@ -944,7 +944,7 @@ NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX
{
enum dcerpc_transport_t transport =
dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
- struct dcerpc_auth *auth_info = dce_call->conn->auth_state.auth_info;
+ const struct dcesrv_auth *auth = &dce_call->conn->auth_state;
struct lsa_policy_state *policy_state;
struct lsa_LookupNames3 q;
NTSTATUS status;
@@ -957,8 +957,8 @@ NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX
* We don't have policy handles on this call. So this must be restricted
* to crypto connections only.
*/
- if (auth_info->auth_type != DCERPC_AUTH_TYPE_SCHANNEL ||
- auth_info->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
+ if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL ||
+ auth->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
}
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index b2f0073d091..9ba28425ff2 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -41,6 +41,14 @@
#include "librpc/gen_ndr/ndr_irpc.h"
#include "lib/socket/netif.h"
+#define DCESRV_INTERFACE_NETLOGON_BIND(call, iface) \
+ dcesrv_interface_netlogon_bind(call, iface)
+static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ return dcesrv_interface_bind_reject_connect(dce_call, iface);
+}
+
static struct memcache *global_challenge_table;
struct netlogon_server_pipe_state {
@@ -126,6 +134,8 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
bool allow_nt4_crypto = lpcfg_allow_nt4_crypto(dce_call->conn->dce_ctx->lp_ctx);
bool reject_des_client = !allow_nt4_crypto;
bool reject_md5_client = lpcfg_reject_md5_clients(dce_call->conn->dce_ctx->lp_ctx);
+ int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx);
+ bool reject_none_rpc = (schannel == true);
ZERO_STRUCTP(r->out.return_credentials);
*r->out.rid = 0;
@@ -198,6 +208,10 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
negotiate_flags = *r->in.negotiate_flags & server_flags;
+ if (negotiate_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
+ reject_none_rpc = false;
+ }
+
if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
reject_des_client = false;
}
@@ -234,6 +248,14 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
*/
*r->out.negotiate_flags = negotiate_flags;
+ if (reject_none_rpc) {
+ /* schannel must be used, but client did not offer it. */
+ DEBUG(0,("%s: schannel required but client failed "
+ "to offer it. Client was %s\n",
+ __func__, r->in.account_name));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
switch (r->in.secure_channel_type) {
case SEC_CHAN_WKSTA:
case SEC_CHAN_DNS_DOMAIN:
@@ -451,7 +473,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate2(struct dcesrv_call_state *dce_ca
/*
* If schannel is required for this call test that it actually is available.
*/
-static NTSTATUS schannel_check_required(struct dcerpc_auth *auth_info,
+static NTSTATUS schannel_check_required(const struct dcesrv_auth *auth_info,
const char *computer_name,
bool integrity, bool privacy)
{
@@ -487,11 +509,11 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
struct netlogon_creds_CredentialState **creds_out)
{
NTSTATUS nt_status;
- struct dcerpc_auth *auth_info = dce_call->conn->auth_state.auth_info;
- bool schannel_global_required = false; /* Should be lpcfg_schannel_server() == true */
+ int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx);
+ bool schannel_global_required = (schannel == true);
if (schannel_global_required) {
- nt_status = schannel_check_required(auth_info,
+ nt_status = schannel_check_required(&dce_call->conn->auth_state,
computer_name,
true, false);
if (!NT_STATUS_IS_OK(nt_status)) {
@@ -724,6 +746,8 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_check(const struct netr_LogonSamLogonE
static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_LogonSamLogonEx *r, struct netlogon_creds_CredentialState *creds)
{
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ const char *workgroup = lpcfg_workgroup(lp_ctx);
struct auth4_context *auth_context;
struct auth_usersupplied_info *user_info;
struct auth_user_info_dc *user_info_dc;
@@ -794,6 +818,13 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
user_info->password.response.lanman = data_blob_talloc(mem_ctx, r->in.logon->network->lm.data, r->in.logon->network->lm.length);
user_info->password.response.nt = data_blob_talloc(mem_ctx, r->in.logon->network->nt.data, r->in.logon->network->nt.length);
+ nt_status = NTLMv2_RESPONSE_verify_netlogon_creds(
+ user_info->client.account_name,
+ user_info->client.domain_name,
+ user_info->password.response.nt,
+ creds, workgroup);
+ NT_STATUS_NOT_OK_RETURN(nt_status);
+
break;
@@ -889,6 +920,10 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
break;
case 6:
+ if (dce_call->conn->auth_state.auth_level < DCERPC_AUTH_LEVEL_PRIVACY) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx,
user_info_dc,
&sam3);
@@ -945,8 +980,7 @@ static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call,
return nt_status;
}
- if (!dce_call->conn->auth_state.auth_info ||
- dce_call->conn->auth_state.auth_info->auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
+ if (dce_call->conn->auth_state.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
return NT_STATUS_ACCESS_DENIED;
}
return dcesrv_netr_LogonSamLogon_base(dce_call, mem_ctx, r, creds);
diff --git a/source4/rpc_server/remote/dcesrv_remote.c b/source4/rpc_server/remote/dcesrv_remote.c
index be4bd1253e0..3eb0ad4b4a1 100644
--- a/source4/rpc_server/remote/dcesrv_remote.c
+++ b/source4/rpc_server/remote/dcesrv_remote.c
@@ -117,9 +117,9 @@ static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct
}
/* If we already have a remote association group ID, then use that */
- if (dce_call->context->assoc_group->proxied_id != 0) {
+ if (dce_call->conn->assoc_group->proxied_id != 0) {
status = dcerpc_binding_set_assoc_group_id(b,
- dce_call->context->assoc_group->proxied_id);
+ dce_call->conn->assoc_group->proxied_id);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("dcerpc_binding_set_assoc_group_id() - %s'\n",
nt_errstr(status)));
@@ -148,8 +148,8 @@ static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct
return status;
}
- if (dce_call->context->assoc_group->proxied_id == 0) {
- dce_call->context->assoc_group->proxied_id =
+ if (dce_call->conn->assoc_group->proxied_id == 0) {
+ dce_call->conn->assoc_group->proxied_id =
dcerpc_binding_get_assoc_group_id(priv->c_pipe->binding);
}
diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c
index 8c34e305f15..55efdacf90a 100644
--- a/source4/rpc_server/samr/dcesrv_samr.c
+++ b/source4/rpc_server/samr/dcesrv_samr.c
@@ -41,6 +41,14 @@
#include "lib/util/tsort.h"
#include "libds/common/flag_mapping.h"
+#define DCESRV_INTERFACE_SAMR_BIND(call, iface) \
+ dcesrv_interface_samr_bind(call, iface)
+static NTSTATUS dcesrv_interface_samr_bind(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ return dcesrv_interface_bind_reject_connect(dce_call, iface);
+}
+
/* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
#define QUERY_STRING(msg, field, attr) \
@@ -4318,6 +4326,10 @@ static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
}
+ if (dce_call->conn->auth_state.auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+ DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
+ }
+
(*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
r2.in.domain_name = NULL;
diff --git a/source4/rpc_server/samr/samr_password.c b/source4/rpc_server/samr/samr_password.c
index 1466decc081..f053dad31ae 100644
--- a/source4/rpc_server/samr/samr_password.c
+++ b/source4/rpc_server/samr/samr_password.c
@@ -419,7 +419,10 @@ NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
+ DEBUG(3,("samr: failed to get session key: %s "
+ "=> NT_STATUS_WRONG_PASSWORD\n",
+ nt_errstr(nt_status)));
+ return NT_STATUS_WRONG_PASSWORD;
}
arcfour_crypt_blob(pwbuf->data, 516, &session_key);
@@ -458,7 +461,10 @@ NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
+ DEBUG(3,("samr: failed to get session key: %s "
+ "=> NT_STATUS_WRONG_PASSWORD\n",
+ nt_errstr(nt_status)));
+ return NT_STATUS_WRONG_PASSWORD;
}
co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
@@ -500,11 +506,26 @@ NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
const uint8_t *nt_pwd_hash)
{
struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
+ uint8_t random_session_key[16] = { 0, };
DATA_BLOB session_key = data_blob(NULL, 0);
DATA_BLOB in, out;
NTSTATUS nt_status = NT_STATUS_OK;
nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) {
+ DEBUG(3,("samr: failed to get session key: %s "
+ "=> use a random session key\n",
+ nt_errstr(nt_status)));
+
+ /*
+ * Windows just uses a random key
+ */
+ generate_random_buffer(random_session_key,
+ sizeof(random_session_key));
+ session_key = data_blob_const(random_session_key,
+ sizeof(random_session_key));
+ nt_status = NT_STATUS_OK;
+ }
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index e044c80e59c..5d451e9b9ed 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -43,8 +43,11 @@ smbclient4 = binpath('smbclient4')
bbdir = os.path.join(srcdir(), "testprogs/blackbox")
# Simple tests for LDAP and CLDAP
-for options in ['-U"$USERNAME%$PASSWORD" --option=socket:testnonblock=true', '-U"$USERNAME%$PASSWORD"', '-U"$USERNAME%$PASSWORD" -k yes', '-U"$USERNAME%$PASSWORD" -k no', '-U"$USERNAME%$PASSWORD" -k no --sign', '-U"$USERNAME%$PASSWORD" -k no --encrypt', '-U"$USERNAME%$PASSWORD" -k yes --encrypt', '-U"$USERNAME%$PASSWORD" -k yes --sign']:
- plantestsuite("samba4.ldb.ldap with options %s(dc)" % options, "dc", "%s/test_ldb.sh ldap $SERVER %s" % (bbdir, options))
+for auth_type in ['', '-k no', '-k yes']:
+ for auth_level in ['--option=clientldapsaslwrapping=plain', '--sign', '--encrypt']:
+ creds = '-U"$USERNAME%$PASSWORD"'
+ options = creds + ' ' + auth_type + ' ' + auth_level
+ plantestsuite("samba4.ldb.ldap with options %r(dc)" % options, "dc", "%s/test_ldb.sh ldap $SERVER %s" % (bbdir, options))
# see if we support ADS on the Samba3 side
try:
@@ -64,6 +67,58 @@ if have_tls_support:
plantestsuite("samba4.ldb.ldaps with options %s(dc)" % options, "dc",
"%s/test_ldb.sh ldaps $SERVER_IP %s" % (bbdir, options))
+ creds_options = [
+ '--simple-bind-dn=$USERNAME@$REALM --password=$PASSWORD',
+ ]
+ peer_options = {
+ 'SERVER_IP': '$SERVER_IP',
+ 'SERVER_NAME': '$SERVER',
+ 'SERVER.REALM': '$SERVER.$REALM',
+ }
+ tls_verify_options = [
+ '--option="tlsverifypeer=no_check"',
+ '--option="tlsverifypeer=ca_only"',
+ '--option="tlsverifypeer=ca_and_name_if_available"',
+ '--option="tlsverifypeer=ca_and_name"',
+ '--option="tlsverifypeer=as_strict_as_possible"',
+ ]
+
+ # we use :local for fl2008r2dc because of the self-signed certificate
+ for env in ["ad_dc_ntvfs", "fl2008r2dc:local"]:
+ for peer_key in peer_options.keys():
+ peer_val = peer_options[peer_key]
+ for creds in creds_options:
+ for tls_verify in tls_verify_options:
+ options = creds + ' ' + tls_verify
+ plantestsuite("samba4.ldb.simple.ldaps with options %s %s(%s)" % (
+ peer_key, options, env), env,
+ "%s/test_ldb_simple.sh ldaps %s %s" % (bbdir, peer_val, options))
+
+# test all "ldap server require strong auth" combinations
+for env in ["ad_dc_ntvfs", "fl2008r2dc", "fl2003dc"]:
+ options = '--simple-bind-dn="$USERNAME@$REALM" --password="$PASSWORD"'
+ plantestsuite("samba4.ldb.simple.ldap with SIMPLE-BIND %s(%s)" % (options, env),
+ env, "%s/test_ldb_simple.sh ldap $SERVER %s" % (bbdir, options))
+ if have_tls_support:
+ options += ' --option="tlsverifypeer=no_check"'
+ plantestsuite("samba4.ldb.simple.ldaps with SIMPLE-BIND %s(%s)" % (options, env),
+ env, "%s/test_ldb_simple.sh ldaps $SERVER %s" % (bbdir, options))
+
+ auth_options = [
+ '--option=clientldapsaslwrapping=plain',
+ '--sign',
+ '--encrypt',
+ ]
+
+ for auth_option in auth_options:
+ options = '-U"$USERNAME%$PASSWORD"' + ' ' + auth_option
+ plantestsuite("samba4.ldb.simple.ldap with SASL-BIND %s(%s)" % (options, env),
+ env, "%s/test_ldb_simple.sh ldap $SERVER %s" % (bbdir, options))
+ if have_tls_support:
+ options = '-U"$USERNAME%$PASSWORD" --option="tlsverifypeer=no_check"'
+ plantestsuite("samba4.ldb.simple.ldaps with SASL-BIND %s(%s)" % (options, env),
+ env, "%s/test_ldb_simple.sh ldaps $SERVER %s" % (bbdir, options))
+
for options in ['-U"$USERNAME%$PASSWORD"']:
plantestsuite("samba4.ldb.ldapi with options %s(dc:local)" % options, "dc:local",
"%s/test_ldb.sh ldapi $PREFIX_ABS/dc/private/ldapi %s" % (bbdir, options))
@@ -82,12 +137,12 @@ else:
# add tests to this list as they start passing, so we test
# that they stay passing
-ncacn_np_tests = ["rpc.schannel", "rpc.join", "rpc.lsa", "rpc.dssetup", "rpc.altercontext", "rpc.netlogon", "rpc.handles", "rpc.samsync", "rpc.samba3-sessionkey", "rpc.samba3-getusername", "rpc.samba3-lsa", "rpc.samba3-bind", "rpc.samba3-netlogon", "rpc.asyncbind", "rpc.lsalookup", "rpc.lsa-getuser", "rpc.schannel2", "rpc.authcontext"]
-ncalrpc_tests = ["rpc.schannel", "rpc.join", "rpc.lsa", "rpc.dssetup", "rpc.altercontext", "rpc.netlogon", "rpc.drsuapi", "rpc.asyncbind", "rpc.lsalookup", "rpc.lsa-getuser", "rpc.schannel2", "rpc.authcontext"]
+ncacn_np_tests = ["rpc.schannel", "rpc.join", "rpc.lsa", "rpc.dssetup", "rpc.altercontext", "rpc.netlogon", "rpc.netlogon.admin", "rpc.handles", "rpc.samsync", "rpc.samba3-sessionkey", "rpc.samba3-getusername", "rpc.samba3-lsa", "rpc.samba3-bind", "rpc.samba3-netlogon", "rpc.asyncbind", "rpc.lsalookup", "rpc.lsa-getuser", "rpc.schannel2", "rpc.authcontext"]
+ncalrpc_tests = ["rpc.schannel", "rpc.join", "rpc.lsa", "rpc.dssetup", "rpc.altercontext", "rpc.netlogon", "rpc.netlogon.admin", "rpc.asyncbind", "rpc.lsalookup", "rpc.lsa-getuser", "rpc.schannel2", "rpc.authcontext"]
drs_rpc_tests = smbtorture4_testsuites("drs.rpc")
-ncacn_ip_tcp_tests = ["rpc.schannel", "rpc.join", "rpc.lsa", "rpc.dssetup", "rpc.netlogon", "rpc.asyncbind", "rpc.lsalookup", "rpc.lsa-getuser", "rpc.schannel2", "rpc.authcontext", "rpc.samr.passwords.validate"] + drs_rpc_tests
-slow_ncacn_np_tests = ["rpc.samlogon", "rpc.samr.users", "rpc.samr.large-dc", "rpc.samr.users.privileges", "rpc.samr.passwords", "rpc.samr.passwords.pwdlastset", "rpc.samr.passwords.lockout", "rpc.samr.passwords.badpwdcount"]
-slow_ncacn_ip_tcp_tests = ["rpc.samr", "rpc.cracknames"]
+ncacn_ip_tcp_tests = ["rpc.schannel", "rpc.join", "rpc.lsa", "rpc.dssetup", "rpc.drsuapi", "rpc.netlogon", "rpc.netlogon.admin", "rpc.asyncbind", "rpc.lsalookup", "rpc.lsa-getuser", "rpc.schannel2", "rpc.authcontext", "rpc.samr.passwords.validate"] + drs_rpc_tests
+slow_ncacn_np_tests = ["rpc.samlogon", "rpc.samr", "rpc.samr.users", "rpc.samr.large-dc", "rpc.samr.users.privileges", "rpc.samr.passwords", "rpc.samr.passwords.pwdlastset", "rpc.samr.passwords.lockout", "rpc.samr.passwords.badpwdcount"]
+slow_ncacn_ip_tcp_tests = ["rpc.cracknames"]
all_rpc_tests = ncalrpc_tests + ncacn_np_tests + ncacn_ip_tcp_tests + slow_ncacn_np_tests + slow_ncacn_ip_tcp_tests + ["rpc.lsa.secrets", "rpc.pac", "rpc.samba3-sharesec", "rpc.countcalls"]
@@ -135,7 +190,10 @@ for transport in ["ncacn_np", "ncacn_ip_tcp"]:
else:
raise AssertionError("Invalid transport %r" % transport)
for t in tests:
- plansmbtorture4testsuite(t, env, ["%s:$SERVER" % transport, '-U$USERNAME%$PASSWORD', '--workgroup=$DOMAIN'], "samba4.%s on %s" % (t, transport))
+ bindoptions = ''
+ if t == 'rpc.cracknames':
+ bindoptions = 'seal'
+ plansmbtorture4testsuite(t, env, ["%s:$SERVER[%s]" % (transport,bindoptions), '-U$USERNAME%$PASSWORD', '--workgroup=$DOMAIN'], "samba4.%s on %s with %s" % (t, transport, bindoptions))
# Tests for the DFS referral calls implementation
for t in smbtorture4_testsuites("dfs."):
@@ -470,6 +528,7 @@ planpythontestsuite("dc:local", "samba.tests.dcerpc.rpcecho")
planoldpythontestsuite("dc:local", "samba.tests.dcerpc.registry", extra_args=['-U"$USERNAME%$PASSWORD"'])
planoldpythontestsuite("dc", "samba.tests.dcerpc.dnsserver", extra_args=['-U"$USERNAME%$PASSWORD"'])
planoldpythontestsuite("plugin_s4_dc", "samba.tests.dcerpc.dnsserver", extra_args=['-U"$USERNAME%$PASSWORD"'])
+planoldpythontestsuite("plugin_s4_dc", "samba.tests.dcerpc.raw_protocol", extra_args=['-U"$USERNAME%$PASSWORD"'])
plantestsuite_loadlist("samba4.ldap.python(dc)", "dc", [python, os.path.join(samba4srcdir, "dsdb/tests/python/ldap.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
plantestsuite_loadlist("samba4.tokengroups.python(dc)", "dc:local", [python, os.path.join(samba4srcdir, "dsdb/tests/python/token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
plantestsuite("samba4.sam.python(dc)", "dc", [python, os.path.join(samba4srcdir, "dsdb/tests/python/sam.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
@@ -505,7 +564,7 @@ plantestsuite("samba4.blackbox.setpassword.py", "none", ["PYTHON=%s" % python, o
plantestsuite("samba4.blackbox.newuser.py", "none", ["PYTHON=%s" % python, os.path.join(samba4srcdir, "setup/tests/blackbox_newuser.sh"), '$PREFIX/provision'])
plantestsuite("samba4.blackbox.group.py", "none", ["PYTHON=%s" % python, os.path.join(samba4srcdir, "setup/tests/blackbox_group.sh"), '$PREFIX/provision'])
plantestsuite("samba4.blackbox.spn.py(dc:local)", "dc:local", ["PYTHON=%s" % python, os.path.join(samba4srcdir, "setup/tests/blackbox_spn.sh"), '$PREFIX/dc'])
-plantestsuite_loadlist("samba4.ldap.bind(dc)", "dc", [python, os.path.join(srcdir(), "auth/credentials/tests/bind.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '$LOADLIST', '$LISTOPT'])
+plantestsuite_loadlist("samba4.ldap.bind(fl2008r2dc)", "fl2008r2dc", [python, os.path.join(srcdir(), "auth/credentials/tests/bind.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '$LOADLIST', '$LISTOPT'])
# This makes sure we test the rid allocation code
t = "rpc.samr.large-dc"
diff --git a/source4/smb_server/smb/negprot.c b/source4/smb_server/smb/negprot.c
index cdfa2b4046f..dfcc1a29bf2 100644
--- a/source4/smb_server/smb/negprot.c
+++ b/source4/smb_server/smb/negprot.c
@@ -387,8 +387,10 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice)
nt_status = cli_credentials_set_machine_account(server_credentials, req->smb_conn->lp_ctx);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(nt_status)));
- talloc_free(server_credentials);
- server_credentials = NULL;
+ /*
+ * We keep the server_credentials as anonymous
+ * this is required for the spoolss.notify test
+ */
}
nt_status = samba_server_gensec_start(req,
diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c
index 4ebc0c47718..e06853afcd4 100644
--- a/source4/smb_server/smb/sesssetup.c
+++ b/source4/smb_server/smb/sesssetup.c
@@ -263,6 +263,7 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
const char *remote_machine = NULL;
struct tevent_req *subreq;
struct sesssetup_context *state;
+ bool allow_raw = lpcfg_raw_ntlmv2_auth(req->smb_conn->lp_ctx);
sess->nt1.out.vuid = 0;
sess->nt1.out.action = 0;
@@ -338,6 +339,15 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
user_info->password.response.nt = sess->nt1.in.password2;
user_info->password.response.nt.data = talloc_steal(user_info, sess->nt1.in.password2.data);
+ if (!allow_raw && user_info->password.response.nt.length >= 48) {
+ /*
+ * NTLMv2_RESPONSE has at least 48 bytes
+ * and should only be supported via NTLMSSP.
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto failed;
+ }
+
subreq = auth_check_password_send(state,
req->smb_conn->connection->event.ctx,
state->auth_context,
diff --git a/source4/smb_server/smb2/negprot.c b/source4/smb_server/smb2/negprot.c
index b48b1700bf0..addd278eb4c 100644
--- a/source4/smb_server/smb2/negprot.c
+++ b/source4/smb_server/smb2/negprot.c
@@ -49,8 +49,10 @@ static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB *
nt_status = cli_credentials_set_machine_account(server_credentials, req->smb_conn->lp_ctx);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(nt_status)));
- talloc_free(server_credentials);
- server_credentials = NULL;
+ /*
+ * We keep the server_credentials as anonymous
+ * this is required for the spoolss.notify test
+ */
}
req->smb_conn->negotiate.server_credentials = talloc_steal(req->smb_conn, server_credentials);
@@ -145,6 +147,7 @@ static NTSTATUS smb2srv_negprot_backend(struct smb2srv_request *req, struct smb2
switch (signing_setting) {
case SMB_SIGNING_DEFAULT:
+ case SMB_SIGNING_IPC_DEFAULT:
smb_panic(__location__);
break;
case SMB_SIGNING_OFF:
diff --git a/source4/smb_server/smb2/sesssetup.c b/source4/smb_server/smb2/sesssetup.c
index 35a14840300..36adafdb891 100644
--- a/source4/smb_server/smb2/sesssetup.c
+++ b/source4/smb_server/smb2/sesssetup.c
@@ -201,14 +201,6 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses
set SMB2_NEGOTIATE_SIGNING_REQUIRED */
if (io->smb2.in.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
smb_sess->smb2_signing.required = true;
- } else if (req->smb_conn->smb2_signing_required) {
- /*
- * if required signing was negotiates in SMB2 Negotiate
- * then the client made an error not using it here
- */
- DEBUG(1, ("SMB2 signing required on the connection but not used on session\n"));
- req->status = NT_STATUS_FOOBAR;
- goto failed;
}
/* disable receipt of more packets on this socket until we've
diff --git a/source4/torture/basic/base.c b/source4/torture/basic/base.c
index 6a792b2781f..01ac170ea2f 100644
--- a/source4/torture/basic/base.c
+++ b/source4/torture/basic/base.c
@@ -371,6 +371,7 @@ static bool run_negprot_nowait(struct torture_context *tctx)
struct tevent_req *req;
req = smb_raw_negotiate_send(cli, tctx->ev,
cli->transport,
+ PROTOCOL_CORE,
PROTOCOL_NT1);
tevent_loop_once(tctx->ev);
if (!tevent_req_is_in_progress(req)) {
@@ -1527,6 +1528,7 @@ static bool torture_chkpath_test(struct torture_context *tctx,
static bool torture_samba3_errorpaths(struct torture_context *tctx)
{
bool nt_status_support;
+ bool client_ntlmv2_auth;
struct smbcli_state *cli_nt = NULL, *cli_dos = NULL;
bool result = false;
int fnum;
@@ -1536,18 +1538,27 @@ static bool torture_samba3_errorpaths(struct torture_context *tctx)
NTSTATUS status;
nt_status_support = lpcfg_nt_status_support(tctx->lp_ctx);
+ client_ntlmv2_auth = lpcfg_client_ntlmv2_auth(tctx->lp_ctx);
if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", "yes")) {
torture_result(tctx, TORTURE_FAIL, "Could not set 'nt status support = yes'\n");
goto fail;
}
+ if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", "yes")) {
+ torture_result(tctx, TORTURE_FAIL, "Could not set 'client ntlmv2 auth = yes'\n");
+ goto fail;
+ }
if (!torture_open_connection(&cli_nt, tctx, 0)) {
goto fail;
}
if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", "no")) {
- torture_result(tctx, TORTURE_FAIL, "Could not set 'nt status support = yes'\n");
+ torture_result(tctx, TORTURE_FAIL, "Could not set 'nt status support = no'\n");
+ goto fail;
+ }
+ if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", "no")) {
+ torture_result(tctx, TORTURE_FAIL, "Could not set 'client ntlmv2 auth = no'\n");
goto fail;
}
@@ -1557,7 +1568,12 @@ static bool torture_samba3_errorpaths(struct torture_context *tctx)
if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support",
nt_status_support ? "yes":"no")) {
- torture_result(tctx, TORTURE_FAIL, "Could not reset 'nt status support = yes'");
+ torture_result(tctx, TORTURE_FAIL, "Could not reset 'nt status support'");
+ goto fail;
+ }
+ if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth",
+ client_ntlmv2_auth ? "yes":"no")) {
+ torture_result(tctx, TORTURE_FAIL, "Could not reset 'client ntlmv2 auth'");
goto fail;
}
diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index f692edc4f57..683987fdb6d 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -24,10 +24,8 @@ import time
import os
sys.path.insert(0, "bin/python")
-import samba
+import samba.tests
from samba import dsdb
-samba.ensure_external_module("testtools", "testtools")
-samba.ensure_external_module("subunit", "subunit/python")
from ldb import (
SCOPE_BASE,
@@ -35,8 +33,6 @@ from ldb import (
FLAG_MOD_REPLACE,
)
-import samba.tests
-
class DrsBaseTestCase(samba.tests.BlackboxTestCase):
"""Base class implementation for all DRS python tests.
diff --git a/source4/torture/ndr/ntlmssp.c b/source4/torture/ndr/ntlmssp.c
index a3cf7b8591d..aeac26ffe57 100644
--- a/source4/torture/ndr/ntlmssp.c
+++ b/source4/torture/ndr/ntlmssp.c
@@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
test suite for ntlmssp ndr operations
- Copyright (C) Guenther Deschner 2010
+ Copyright (C) Guenther Deschner 2010,2015
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,6 +33,23 @@ static const uint8_t ntlmssp_NEGOTIATE_MESSAGE_data[] = {
static bool ntlmssp_NEGOTIATE_MESSAGE_check(struct torture_context *tctx,
struct NEGOTIATE_MESSAGE *r)
{
+ torture_assert_str_equal(tctx, r->Signature, "NTLMSSP", "Signature");
+ torture_assert_int_equal(tctx, r->MessageType, NtLmNegotiate, "MessageType");
+ torture_assert_int_equal(tctx, r->NegotiateFlags, 0xe2088297, "NegotiateFlags");
+ torture_assert_int_equal(tctx, r->DomainNameLen, 0, "DomainNameLen");
+ torture_assert_int_equal(tctx, r->DomainNameMaxLen, 0, "DomainNameMaxLen");
+ torture_assert(tctx, r->DomainName == NULL, "DomainName");
+ torture_assert_int_equal(tctx, r->WorkstationLen, 0, "WorkstationLen");
+ torture_assert_int_equal(tctx, r->WorkstationMaxLen, 0, "WorkstationMaxLen");
+ torture_assert(tctx, r->Workstation == NULL, "Workstation");
+ torture_assert_int_equal(tctx, r->Version.version.ProductMajorVersion, NTLMSSP_WINDOWS_MAJOR_VERSION_6, "ProductMajorVersion");
+ torture_assert_int_equal(tctx, r->Version.version.ProductMinorVersion, NTLMSSP_WINDOWS_MINOR_VERSION_1, "ProductMinorVersion");
+ torture_assert_int_equal(tctx, r->Version.version.ProductBuild, 0x1db0, "ProductBuild");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[0], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[1], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[2], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.NTLMRevisionCurrent, NTLMSSP_REVISION_W2K3, "NTLMRevisionCurrent");
+
return true;
}
@@ -58,6 +75,48 @@ static const uint8_t ntlmssp_CHALLENGE_MESSAGE_data[] = {
static bool ntlmssp_CHALLENGE_MESSAGE_check(struct torture_context *tctx,
struct CHALLENGE_MESSAGE *r)
{
+ uint8_t chal[8] = { 0xed, 0xc8, 0x2b, 0x7d, 0x2e, 0xd7, 0xd0, 0xd9 };
+ uint8_t data[8] = { 0 };
+
+ torture_assert_str_equal(tctx, r->Signature, "NTLMSSP", "Signature");
+ torture_assert_int_equal(tctx, r->MessageType, NtLmChallenge, "MessageType");
+ torture_assert_int_equal(tctx, r->TargetNameLen, 10, "TargetNameLen");
+ torture_assert_int_equal(tctx, r->TargetNameMaxLen, 10, "TargetNameMaxLen");
+ torture_assert_str_equal(tctx, r->TargetName, "SAMBA", "TargetName");
+ torture_assert_int_equal(tctx, r->NegotiateFlags, 0xe2898295, "NegotiateFlags");
+ torture_assert_mem_equal(tctx, r->ServerChallenge, chal, 8, "ServerChallenge");
+ torture_assert_mem_equal(tctx, r->Reserved, data, 8, "Reserved");
+ torture_assert_int_equal(tctx, r->TargetInfoLen, 120, "TargetInfoLen");
+ torture_assert_int_equal(tctx, r->TargetInfoMaxLen, 120, "TargetInfoMaxLen");
+ torture_assert_int_equal(tctx, r->TargetInfo->count, 5, "TargetInfo->count");
+
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[0].AvId, MsvAvNbDomainName, "AvId");
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[0].AvLen, 10, "AvLen");
+ torture_assert_str_equal(tctx, r->TargetInfo->pair[0].Value.AvNbDomainName, "SAMBA", "AvNbDomainName");
+
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[1].AvId, MsvAvNbComputerName, "AvId");
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[1].AvLen, 16, "AvLen");
+ torture_assert_str_equal(tctx, r->TargetInfo->pair[1].Value.AvNbComputerName, "MTHELENA", "AvNbComputerName");
+
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[2].AvId, MsvAvDnsDomainName, "AvId");
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[2].AvLen, 28, "AvLen");
+ torture_assert_str_equal(tctx, r->TargetInfo->pair[2].Value.AvDnsDomainName, "ber.redhat.com", "AvDnsDomainName");
+
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[3].AvId, MsvAvDnsComputerName, "AvId");
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[3].AvLen, 46, "AvLen");
+ torture_assert_str_equal(tctx, r->TargetInfo->pair[3].Value.AvDnsComputerName, "mthelena.ber.redhat.com", "AvDnsComputerName");
+
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[4].AvId, MsvAvEOL, "AvId");
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[4].AvLen, 0, "AvLen");
+
+ torture_assert_int_equal(tctx, r->Version.version.ProductMajorVersion, NTLMSSP_WINDOWS_MAJOR_VERSION_6, "ProductMajorVersion");
+ torture_assert_int_equal(tctx, r->Version.version.ProductMinorVersion, NTLMSSP_WINDOWS_MINOR_VERSION_1, "ProductMinorVersion");
+ torture_assert_int_equal(tctx, r->Version.version.ProductBuild, 0, "ProductBuild");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[0], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[1], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[2], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.NTLMRevisionCurrent, NTLMSSP_REVISION_W2K3, "NTLMRevisionCurrent");
+
return true;
}
@@ -105,6 +164,113 @@ static const uint8_t ntlmssp_AUTHENTICATE_MESSAGE_data[] = {
static bool ntlmssp_AUTHENTICATE_MESSAGE_check(struct torture_context *tctx,
struct AUTHENTICATE_MESSAGE *r)
{
+ uint8_t lm_challenge_response[24] = { 0 };
+ struct NTLMv2_RESPONSE v2;
+ struct AV_PAIR_LIST AvPairs;
+ uint8_t Response[16] = {
+ 0x38, 0xcf, 0xfb, 0x39, 0x5a, 0xb3, 0x4c, 0x58,
+ 0x86, 0x35, 0xa3, 0xe7, 0x1e, 0x00, 0x98, 0x43
+ };
+ uint8_t ChallengeFromClient[8] = {
+ 0x3c, 0x21, 0x0a, 0xe9, 0xde, 0x61, 0xc0, 0x7e
+ };
+ uint8_t MachineId[32] = {
+ 0x0a, 0xfd, 0x3b, 0x2c, 0xad, 0x43, 0x46, 0x8b,
+ 0x49, 0x01, 0x6c, 0xa5, 0xf3, 0xbc, 0xd2, 0x13,
+ 0xbb, 0x70, 0xe2, 0x65, 0x96, 0xba, 0x0d, 0x8d,
+ 0x5d, 0x31, 0xe6, 0x47, 0x94, 0x61, 0xed, 0x28
+ };
+ uint8_t EncryptedRandomSessionKey[16] = {
+ 0xA4, 0x23, 0xD4, 0x5C, 0x16, 0x52, 0x8D, 0x56,
+ 0x34, 0x2D, 0x1C, 0xFF, 0x86, 0x17, 0xC9, 0x4F
+ };
+
+ torture_assert_str_equal(tctx, r->Signature, "NTLMSSP", "Signature");
+ torture_assert_int_equal(tctx, r->MessageType, NtLmAuthenticate, "MessageType");
+ torture_assert_int_equal(tctx, r->LmChallengeResponseLen, 24, "LmChallengeResponseLen");
+ torture_assert_int_equal(tctx, r->LmChallengeResponseMaxLen, 24, "LmChallengeResponseMaxLen");
+ torture_assert_mem_equal(tctx, r->LmChallengeResponse->v1.Response, lm_challenge_response, 24, "LmChallengeResponse");
+
+ torture_assert_int_equal(tctx, r->NtChallengeResponseLen, 270, "NtChallengeResponseLen");
+ torture_assert_int_equal(tctx, r->NtChallengeResponseMaxLen, 270, "NtChallengeResponseMaxLen");
+
+ v2 = r->NtChallengeResponse->v2;
+
+ torture_assert_mem_equal(tctx, v2.Response, Response, 16, "v2.Response");
+ torture_assert_int_equal(tctx, v2.Challenge.RespType, 1, "RespType");
+ torture_assert_int_equal(tctx, v2.Challenge.HiRespType, 1, "HiRespType");
+ torture_assert_int_equal(tctx, v2.Challenge.Reserved1, 0, "Reserved1");
+ torture_assert_int_equal(tctx, v2.Challenge.Reserved2, 0, "Reserved2");
+ /* TimeStamp : Tue Sep 14 17:06:53 2010 CEST */
+ torture_assert_mem_equal(tctx, v2.Challenge.ChallengeFromClient, ChallengeFromClient, 8, "v2.Challenge.ChallengeFromClient");
+ torture_assert_int_equal(tctx, v2.Challenge.Reserved3, 0, "Reserved3");
+
+ AvPairs = v2.Challenge.AvPairs;
+
+ torture_assert_int_equal(tctx, AvPairs.count, 8, "AvPairs.count");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[0].AvId, MsvAvNbDomainName, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[0].AvLen, 10, "AvLen");
+ torture_assert_str_equal(tctx, AvPairs.pair[0].Value.AvNbDomainName, "SAMBA", "Value.AvNbDomainName");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[1].AvId, MsvAvNbComputerName, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[1].AvLen, 16, "AvLen");
+ torture_assert_str_equal(tctx, AvPairs.pair[1].Value.AvNbComputerName, "MTHELENA", "Value.AvNbComputerName");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[2].AvId, MsvAvDnsDomainName, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[2].AvLen, 28, "AvLen");
+ torture_assert_str_equal(tctx, AvPairs.pair[2].Value.AvDnsDomainName, "ber.redhat.com", "Value.AvDnsDomainName");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[3].AvId, MsvAvDnsComputerName, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[3].AvLen, 46, "AvLen");
+ torture_assert_str_equal(tctx, AvPairs.pair[3].Value.AvDnsComputerName, "mthelena.ber.redhat.com", "Value.AvDnsComputerName");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[4].AvId, MsvAvSingleHost, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[4].AvLen, 48, "AvLen");
+ torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.Size, 48, "Value.AvSingleHost.Size");
+ torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.Z4, 0, "Value.AvSingleHost.Z4");
+ torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.token_info.Flags, 0, "Value.AvSingleHost.token_info.Flags");
+ torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.token_info.TokenIL, 0x00003000, "Value.AvSingleHost.token_info.TokenIL");
+ torture_assert_mem_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.token_info.MachineId, MachineId, 32, "Value.AvSingleHost.token_info.MachineId");
+ torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.remaining.length, 0, "Value.AvSingleHost.remaining.length");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[5].AvId, MsvChannelBindings, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[5].AvLen, 16, "AvLen");
+ torture_assert_mem_equal(tctx, AvPairs.pair[5].Value.ChannelBindings, lm_challenge_response, 16, "Value.ChannelBindings");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[6].AvId, MsvAvTargetName, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[6].AvLen, 26, "AvLen");
+ torture_assert_str_equal(tctx, AvPairs.pair[6].Value.AvTargetName, "cifs/mthelena", "Value.AvTargetName");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[7].AvId, MsvAvEOL, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[7].AvLen, 0, "AvLen");
+
+ torture_assert_int_equal(tctx, r->DomainNameLen, 14, "DomainNameLen");
+ torture_assert_int_equal(tctx, r->DomainNameMaxLen, 14, "DomainNameMaxLen");
+ torture_assert_str_equal(tctx, r->DomainName, "W2K8DOM", "DomainName");
+
+ torture_assert_int_equal(tctx, r->UserNameLen, 26, "UserNameLen");
+ torture_assert_int_equal(tctx, r->UserNameMaxLen, 26, "UserNameMaxLen");
+ torture_assert_str_equal(tctx, r->UserName, "Administrator", "UserName");
+
+ torture_assert_int_equal(tctx, r->WorkstationLen, 12, "WorkstationLen");
+ torture_assert_int_equal(tctx, r->WorkstationMaxLen, 12, "WorkstationMaxLen");
+ torture_assert_str_equal(tctx, r->Workstation, "W2K8R2", "Workstation");
+
+ torture_assert_int_equal(tctx, r->EncryptedRandomSessionKeyLen, 16, "EncryptedRandomSessionKeyLen");
+ torture_assert_int_equal(tctx, r->EncryptedRandomSessionKeyMaxLen, 16, "EncryptedRandomSessionKeyMaxLen");
+ torture_assert_mem_equal(tctx, r->EncryptedRandomSessionKey->data, EncryptedRandomSessionKey, 16, "EncryptedRandomSessionKeyMaxLen");
+
+ torture_assert_int_equal(tctx, r->NegotiateFlags, 0xe2888215, "NegotiateFlags");
+
+ torture_assert_int_equal(tctx, r->Version.version.ProductMajorVersion, NTLMSSP_WINDOWS_MAJOR_VERSION_6, "ProductMajorVersion");
+ torture_assert_int_equal(tctx, r->Version.version.ProductMinorVersion, NTLMSSP_WINDOWS_MINOR_VERSION_1, "ProductMinorVersion");
+ torture_assert_int_equal(tctx, r->Version.version.ProductBuild, 0x1db0, "ProductBuild");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[0], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[1], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[2], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.NTLMRevisionCurrent, NTLMSSP_REVISION_W2K3, "NTLMRevisionCurrent");
+
return true;
}
@@ -113,9 +279,18 @@ struct torture_suite *ndr_ntlmssp_suite(TALLOC_CTX *ctx)
struct torture_suite *suite = torture_suite_create(ctx, "ntlmssp");
torture_suite_add_ndr_pull_test(suite, NEGOTIATE_MESSAGE, ntlmssp_NEGOTIATE_MESSAGE_data, ntlmssp_NEGOTIATE_MESSAGE_check);
-#if 0
torture_suite_add_ndr_pull_test(suite, CHALLENGE_MESSAGE, ntlmssp_CHALLENGE_MESSAGE_data, ntlmssp_CHALLENGE_MESSAGE_check);
torture_suite_add_ndr_pull_test(suite, AUTHENTICATE_MESSAGE, ntlmssp_AUTHENTICATE_MESSAGE_data, ntlmssp_AUTHENTICATE_MESSAGE_check);
-#endif
+
+ torture_suite_add_ndr_pullpush_test(suite,
+ NEGOTIATE_MESSAGE,
+ data_blob_const(ntlmssp_NEGOTIATE_MESSAGE_data, sizeof(ntlmssp_NEGOTIATE_MESSAGE_data)),
+ ntlmssp_NEGOTIATE_MESSAGE_check);
+
+ torture_suite_add_ndr_pullpush_test(suite,
+ CHALLENGE_MESSAGE,
+ data_blob_const(ntlmssp_CHALLENGE_MESSAGE_data, sizeof(ntlmssp_CHALLENGE_MESSAGE_data)),
+ ntlmssp_CHALLENGE_MESSAGE_check);
+
return suite;
}
diff --git a/source4/torture/raw/samba3misc.c b/source4/torture/raw/samba3misc.c
index a818c6bb484..97586538a45 100644
--- a/source4/torture/raw/samba3misc.c
+++ b/source4/torture/raw/samba3misc.c
@@ -440,22 +440,29 @@ bool torture_samba3_badpath(struct torture_context *torture)
bool ret = true;
TALLOC_CTX *mem_ctx;
bool nt_status_support;
+ bool client_ntlmv2_auth;
torture_assert(torture, mem_ctx = talloc_init("torture_samba3_badpath"), "talloc_init failed");
nt_status_support = lpcfg_nt_status_support(torture->lp_ctx);
+ client_ntlmv2_auth = lpcfg_client_ntlmv2_auth(torture->lp_ctx);
torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "yes"), ret, fail, "Could not set 'nt status support = yes'\n");
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", "yes"), ret, fail, "Could not set 'client ntlmv2 auth = yes'\n");
torture_assert_goto(torture, torture_open_connection(&cli_nt, torture, 0), ret, fail, "Could not open NTSTATUS connection\n");
torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "no"), ret, fail, "Could not set 'nt status support = no'\n");
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", "no"), ret, fail, "Could not set 'client ntlmv2 auth = no'\n");
torture_assert_goto(torture, torture_open_connection(&cli_dos, torture, 1), ret, fail, "Could not open DOS connection\n");
torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support",
nt_status_support ? "yes":"no"),
ret, fail, "Could not set 'nt status support' back to where it was\n");
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth",
+ client_ntlmv2_auth ? "yes":"no"),
+ ret, fail, "Could not set 'client ntlmv2 auth' back to where it was\n");
torture_assert(torture, torture_setup_dir(cli_nt, dirname), "creating test directory");
diff --git a/source4/torture/rpc/alter_context.c b/source4/torture/rpc/alter_context.c
index d14cabc3a09..60e03db2914 100644
--- a/source4/torture/rpc/alter_context.c
+++ b/source4/torture/rpc/alter_context.c
@@ -85,7 +85,7 @@ bool torture_rpc_alter_context(struct torture_context *torture)
if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
ret &= test_lsa_OpenPolicy2_ex(p->binding_handle, torture, &handle,
- NT_STATUS_IO_DEVICE_ERROR);
+ NT_STATUS_CONNECTION_DISCONNECTED);
torture_assert(torture, !dcerpc_binding_handle_is_connected(p->binding_handle),
"dcerpc disonnected");
diff --git a/source4/torture/rpc/backupkey.c b/source4/torture/rpc/backupkey.c
index 1a57bd2c687..119b1d68d9c 100644
--- a/source4/torture/rpc/backupkey.c
+++ b/source4/torture/rpc/backupkey.c
@@ -1542,8 +1542,10 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
struct bkrp_server_side_wrapped *server_side_wrapped,
enum test_wrong wrong)
{
- struct dcerpc_pipe *lsa_p;
- struct dcerpc_binding_handle *lsa_b;
+ char *lsa_binding_string = NULL;
+ struct dcerpc_binding *lsa_binding = NULL;
+ struct dcerpc_pipe *lsa_p = NULL;
+ struct dcerpc_binding_handle *lsa_b = NULL;
struct lsa_OpenSecret r_secret;
struct lsa_QuerySecret r_query_secret;
struct policy_handle *handle, sec_handle;
@@ -1568,9 +1570,20 @@ static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
ZERO_STRUCT(r_query_secret);
/* Now read BCKUPKEY_P and prove we can do a matching decrypt and encrypt */
-
+
+ /* lsa_OpenSecret only works with ncacn_np and AUTH_LEVEL_NONE */
+ lsa_binding_string = talloc_asprintf(tctx, "ncacn_np:%s",
+ torture_setting_string(tctx, "host", NULL));
+ torture_assert(tctx, lsa_binding_string != NULL, "lsa_binding_string");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_parse_binding(tctx, lsa_binding_string, &lsa_binding),
+ "Failed to parse dcerpc binding");
+
torture_assert_ntstatus_ok(tctx,
- torture_rpc_connection(tctx, &lsa_p, &ndr_table_lsarpc),
+ dcerpc_pipe_connect_b(tctx, &lsa_p,
+ lsa_binding, &ndr_table_lsarpc,
+ cmdline_credentials, tctx->ev, tctx->lp_ctx),
"Opening LSA pipe");
lsa_b = lsa_p->binding_handle;
diff --git a/source4/torture/rpc/forest_trust.c b/source4/torture/rpc/forest_trust.c
index 74a56ef639b..758befcc1e3 100644
--- a/source4/torture/rpc/forest_trust.c
+++ b/source4/torture/rpc/forest_trust.c
@@ -592,7 +592,8 @@ static bool test_validate_trust(struct torture_context *tctx,
NTSTATUS status;
struct cli_credentials *credentials;
struct dcerpc_binding *b;
- struct dcerpc_pipe *p;
+ struct dcerpc_pipe *p1 = NULL;
+ struct dcerpc_pipe *p = NULL;
struct netr_GetForestTrustInformation fr;
struct lsa_ForestTrustInformation *forest_trust_info;
@@ -620,7 +621,7 @@ static bool test_validate_trust(struct torture_context *tctx,
trusted_dom_name, CRED_SPECIFIED);
cli_credentials_set_secure_channel_type(credentials, SEC_CHAN_DOMAIN);
- status = dcerpc_pipe_connect_b(tctx, &p, b,
+ status = dcerpc_pipe_connect_b(tctx, &p1, b,
&ndr_table_netlogon, credentials,
tctx->ev, tctx->lp_ctx);
@@ -632,11 +633,16 @@ static bool test_validate_trust(struct torture_context *tctx,
return false;
}
- if (!test_SetupCredentials3(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES,
+ if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES,
credentials, &creds)) {
torture_comment(tctx, "test_SetupCredentials3 failed.\n");
return false;
}
+ if (!test_SetupCredentialsPipe(p1, tctx, credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ torture_comment(tctx, "test_SetupCredentialsPipe failed.\n");
+ return false;
+ }
netlogon_creds_client_authenticator(creds, &a);
diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c
index a2450cf1c25..66f09a239c5 100644
--- a/source4/torture/rpc/netlogon.c
+++ b/source4/torture/rpc/netlogon.c
@@ -359,6 +359,35 @@ bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx,
return true;
}
+bool test_SetupCredentialsPipe(const struct dcerpc_pipe *p1,
+ struct torture_context *tctx,
+ struct cli_credentials *machine_credentials,
+ struct netlogon_creds_CredentialState *creds,
+ uint32_t additional_flags,
+ struct dcerpc_pipe **_p2)
+{
+ NTSTATUS status;
+ struct dcerpc_binding *b2 = NULL;
+ struct dcerpc_pipe *p2 = NULL;
+
+ b2 = dcerpc_binding_dup(tctx, p1->binding);
+ torture_assert(tctx, b2 != NULL, "dcerpc_binding_dup");
+ dcerpc_binding_set_flags(b2,
+ DCERPC_SCHANNEL | additional_flags,
+ DCERPC_AUTH_OPTIONS);
+
+ cli_credentials_set_netlogon_creds(machine_credentials, creds);
+ status = dcerpc_pipe_connect_b(tctx, &p2, b2,
+ &ndr_table_netlogon,
+ machine_credentials,
+ tctx->ev, tctx->lp_ctx);
+ cli_credentials_set_netlogon_creds(machine_credentials, NULL);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_pipe_connect_b schannel");
+
+ *_p2 = p2;
+ return true;
+}
+
/*
try a change password for our machine account
*/
@@ -436,7 +465,7 @@ static bool test_SetPassword(struct torture_context *tctx,
try a change password for our machine account
*/
static bool test_SetPassword_flags(struct torture_context *tctx,
- struct dcerpc_pipe *p,
+ struct dcerpc_pipe *p1,
struct cli_credentials *machine_credentials,
uint32_t negotiate_flags)
{
@@ -445,14 +474,20 @@ static bool test_SetPassword_flags(struct torture_context *tctx,
struct netlogon_creds_CredentialState *creds;
struct netr_Authenticator credential, return_authenticator;
struct samr_Password new_password;
- struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
- if (!test_SetupCredentials2(p, tctx, negotiate_flags,
+ if (!test_SetupCredentials2(p1, tctx, negotiate_flags,
machine_credentials,
cli_credentials_get_secure_channel_type(machine_credentials),
&creds)) {
return false;
}
+ if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
@@ -532,7 +567,7 @@ static DATA_BLOB netlogon_very_rand_pass(TALLOC_CTX *mem_ctx, int len)
try a change password for our machine account
*/
static bool test_SetPassword2_with_flags(struct torture_context *tctx,
- struct dcerpc_pipe *p,
+ struct dcerpc_pipe *p1,
struct cli_credentials *machine_credentials,
uint32_t flags)
{
@@ -544,11 +579,19 @@ static bool test_SetPassword2_with_flags(struct torture_context *tctx,
struct samr_Password nt_hash;
struct netr_Authenticator credential, return_authenticator;
struct netr_CryptPassword new_password;
- struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
- if (!test_SetupCredentials2(p, tctx, flags, machine_credentials, cli_credentials_get_secure_channel_type(machine_credentials), &creds)) {
+ if (!test_SetupCredentials2(p1, tctx, flags, machine_credentials,
+ cli_credentials_get_secure_channel_type(machine_credentials),
+ &creds)) {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
return false;
}
+ b = p->binding_handle;
r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
@@ -838,6 +881,7 @@ static bool test_netlogon_ops_args(struct dcerpc_pipe *p, struct torture_context
status = cli_credentials_get_ntlm_response(cmdline_credentials, tctx,
&flags,
chal,
+ NULL, /* server_timestamp */
names_blob,
&lm_resp, &nt_resp,
NULL, NULL);
@@ -2454,7 +2498,7 @@ static bool test_LogonControl2Ex(struct torture_context *tctx,
}
static bool test_netr_GetForestTrustInformation(struct torture_context *tctx,
- struct dcerpc_pipe *p,
+ struct dcerpc_pipe *p1,
struct cli_credentials *machine_credentials)
{
struct netr_GetForestTrustInformation r;
@@ -2462,12 +2506,18 @@ static bool test_netr_GetForestTrustInformation(struct torture_context *tctx,
struct netr_Authenticator a;
struct netr_Authenticator return_authenticator;
struct lsa_ForestTrustInformation *forest_trust_info;
- struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
- if (!test_SetupCredentials3(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS,
+ if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS,
machine_credentials, &creds)) {
return false;
}
+ if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
netlogon_creds_client_authenticator(creds, &a);
@@ -3290,7 +3340,7 @@ static bool test_netr_DsRAddressToSitenamesExW(struct torture_context *tctx,
}
static bool test_netr_ServerGetTrustInfo_flags(struct torture_context *tctx,
- struct dcerpc_pipe *p,
+ struct dcerpc_pipe *p1,
struct cli_credentials *machine_credentials,
uint32_t negotiate_flags)
{
@@ -3303,14 +3353,20 @@ static bool test_netr_ServerGetTrustInfo_flags(struct torture_context *tctx,
struct netr_TrustInfo *trust_info;
struct netlogon_creds_CredentialState *creds;
- struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
struct samr_Password nt_hash;
- if (!test_SetupCredentials3(p, tctx, negotiate_flags,
+ if (!test_SetupCredentials3(p1, tctx, negotiate_flags,
machine_credentials, &creds)) {
return false;
}
+ if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
netlogon_creds_client_authenticator(creds, &a);
@@ -3360,7 +3416,7 @@ static bool test_netr_ServerGetTrustInfo_AES(struct torture_context *tctx,
}
static bool test_GetDomainInfo(struct torture_context *tctx,
- struct dcerpc_pipe *p,
+ struct dcerpc_pipe *p1,
struct cli_credentials *machine_credentials)
{
struct netr_LogonGetDomainInfo r;
@@ -3383,14 +3439,20 @@ static bool test_GetDomainInfo(struct torture_context *tctx,
char **spns = NULL;
int num_spns = 0;
char *temp_str;
- struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
torture_comment(tctx, "Testing netr_LogonGetDomainInfo\n");
- if (!test_SetupCredentials3(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS,
+ if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS,
machine_credentials, &creds)) {
return false;
}
+ if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
/* We won't double-check this when we are over 'local' transports */
if (dcerpc_server_name(p)) {
@@ -3815,7 +3877,7 @@ static bool test_GetDomainInfo(struct torture_context *tctx,
}
static bool test_GetDomainInfo_async(struct torture_context *tctx,
- struct dcerpc_pipe *p,
+ struct dcerpc_pipe *p1,
struct cli_credentials *machine_credentials)
{
NTSTATUS status;
@@ -3829,6 +3891,7 @@ static bool test_GetDomainInfo_async(struct torture_context *tctx,
int i;
union netr_WorkstationInfo query;
union netr_DomainInfo info;
+ struct dcerpc_pipe *p = NULL;
torture_comment(tctx, "Testing netr_LogonGetDomainInfo - async count %d\n", ASYNC_COUNT);
@@ -3836,6 +3899,10 @@ static bool test_GetDomainInfo_async(struct torture_context *tctx,
machine_credentials, &creds)) {
return false;
}
+ if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
ZERO_STRUCT(r);
r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
@@ -3907,7 +3974,7 @@ static bool test_ManyGetDCName(struct torture_context *tctx,
int i;
if (p->conn->transport.transport != NCACN_NP) {
- return true;
+ torture_skip(tctx, "test_ManyGetDCName works only with NCACN_NP");
}
torture_comment(tctx, "Torturing GetDCName\n");
diff --git a/source4/torture/rpc/netlogon.h b/source4/torture/rpc/netlogon.h
index f2f2a6f9c95..a4ab8f00ce0 100644
--- a/source4/torture/rpc/netlogon.h
+++ b/source4/torture/rpc/netlogon.h
@@ -28,3 +28,10 @@ bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx,
uint32_t negotiate_flags,
struct cli_credentials *machine_credentials,
struct netlogon_creds_CredentialState **creds_out);
+
+bool test_SetupCredentialsPipe(const struct dcerpc_pipe *p1,
+ struct torture_context *tctx,
+ struct cli_credentials *machine_credentials,
+ struct netlogon_creds_CredentialState *creds,
+ uint32_t additional_flags,
+ struct dcerpc_pipe **_p2);
diff --git a/source4/torture/rpc/remote_pac.c b/source4/torture/rpc/remote_pac.c
index 7ea123b8bda..aaf08e04713 100644
--- a/source4/torture/rpc/remote_pac.c
+++ b/source4/torture/rpc/remote_pac.c
@@ -118,7 +118,7 @@ static NTSTATUS test_generate_session_info_pac(struct auth4_context *auth_ctx,
/* Also happens to be a really good one-step verfication of our Kerberos stack */
static bool test_PACVerify(struct torture_context *tctx,
- struct dcerpc_pipe *p,
+ struct dcerpc_pipe *p1,
struct cli_credentials *credentials,
enum netr_SchannelType secure_channel_type,
const char *test_machine_name,
@@ -139,6 +139,8 @@ static bool test_PACVerify(struct torture_context *tctx,
struct netlogon_creds_CredentialState *creds;
struct gensec_security *gensec_client_context;
struct gensec_security *gensec_server_context;
+ struct cli_credentials *client_creds;
+ struct cli_credentials *server_creds;
DATA_BLOB client_to_server, server_to_client, pac_wrapped, payload;
struct PAC_Validate pac_wrapped_struct;
@@ -149,7 +151,8 @@ static bool test_PACVerify(struct torture_context *tctx,
struct auth_session_info *session_info;
struct pac_data *pac_data;
- struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
TALLOC_CTX *tmp_ctx = talloc_new(tctx);
torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");
@@ -157,11 +160,32 @@ static bool test_PACVerify(struct torture_context *tctx,
"Testing PAC Verify (secure_channel_type: %d, machine: %s, negotiate_flags: 0x%08x\n",
secure_channel_type, test_machine_name, negotiate_flags);
- if (!test_SetupCredentials2(p, tctx, negotiate_flags,
- credentials, secure_channel_type,
+ /*
+ * Copy the credentials in order to use a different MEMORY krb5 ccache
+ * for each client/server setup. The MEMORY cache identifier is a
+ * pointer to the creds container. If we copy it the pointer changes and
+ * we will get a new clean memory cache.
+ */
+ client_creds = cli_credentials_shallow_copy(tmp_ctx,
+ cmdline_credentials);
+ torture_assert(tctx, client_creds, "Failed to copy of credentials");
+ /* Invalidate the gss creds container to allocate a new MEMORY ccache */
+ cli_credentials_invalidate_ccache(client_creds, CRED_SPECIFIED);
+
+ server_creds = cli_credentials_shallow_copy(tmp_ctx,
+ credentials);
+ torture_assert(tctx, server_creds, "Failed to copy of credentials");
+
+ if (!test_SetupCredentials2(p1, tctx, negotiate_flags,
+ server_creds, secure_channel_type,
&creds)) {
return false;
}
+ if (!test_SetupCredentialsPipe(p1, tctx, server_creds, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
auth_context = talloc_zero(tmp_ctx, struct auth4_context);
torture_assert(tctx, auth_context != NULL, "talloc_new() failed");
@@ -174,7 +198,7 @@ static bool test_PACVerify(struct torture_context *tctx,
status = gensec_set_target_hostname(gensec_client_context, test_machine_name);
- status = gensec_set_credentials(gensec_client_context, cmdline_credentials);
+ status = gensec_set_credentials(gensec_client_context, client_creds);
torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
@@ -185,7 +209,7 @@ static bool test_PACVerify(struct torture_context *tctx,
auth_context, &gensec_server_context);
torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
- status = gensec_set_credentials(gensec_server_context, credentials);
+ status = gensec_set_credentials(gensec_server_context, server_creds);
torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
@@ -269,7 +293,7 @@ static bool test_PACVerify(struct torture_context *tctx,
r.in.logon = &logon;
r.in.logon_level = NetlogonGenericInformation;
r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
- r.in.computer_name = cli_credentials_get_workstation(credentials);
+ r.in.computer_name = cli_credentials_get_workstation(server_creds);
r.in.validation_level = NetlogonValidationGenericInfo2;
r.out.validation = &validation;
r.out.authoritative = &authoritative;
@@ -292,7 +316,7 @@ static bool test_PACVerify(struct torture_context *tctx,
r.in.logon_level = NetlogonGenericInformation;
r.in.logon = &logon;
r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
- r.in.computer_name = cli_credentials_get_workstation(credentials);
+ r.in.computer_name = cli_credentials_get_workstation(server_creds);
r.in.validation_level = NetlogonValidationGenericInfo2;
torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
@@ -315,7 +339,7 @@ static bool test_PACVerify(struct torture_context *tctx,
r.in.logon_level = NetlogonGenericInformation;
r.in.logon = &logon;
r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
- r.in.computer_name = cli_credentials_get_workstation(credentials);
+ r.in.computer_name = cli_credentials_get_workstation(server_creds);
r.in.validation_level = NetlogonValidationGenericInfo2;
torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
@@ -368,7 +392,7 @@ static bool test_PACVerify(struct torture_context *tctx,
r.in.logon_level = NetlogonGenericInformation;
r.in.logon = &logon;
r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
- r.in.computer_name = cli_credentials_get_workstation(credentials);
+ r.in.computer_name = cli_credentials_get_workstation(server_creds);
r.in.validation_level = NetlogonValidationGenericInfo2;
torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
@@ -420,7 +444,7 @@ static bool test_PACVerify(struct torture_context *tctx,
r.in.logon_level = NetlogonGenericInformation;
r.in.logon = &logon;
r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
- r.in.computer_name = cli_credentials_get_workstation(credentials);
+ r.in.computer_name = cli_credentials_get_workstation(server_creds);
r.in.validation_level = NetlogonValidationGenericInfo2;
torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
@@ -431,6 +455,8 @@ static bool test_PACVerify(struct torture_context *tctx,
torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
"Credential chaining failed");
+ talloc_free(tmp_ctx);
+
return true;
}
@@ -505,14 +531,15 @@ static bool test_PACVerify_workstation_des(struct torture_context *tctx,
/* Check various ways to get the PAC, in particular check the group membership and other details between the PAC from a normal kinit, S2U4Self and a SamLogon */
static bool test_S2U4Self(struct torture_context *tctx,
- struct dcerpc_pipe *p,
+ struct dcerpc_pipe *p1,
struct cli_credentials *credentials,
enum netr_SchannelType secure_channel_type,
const char *test_machine_name,
uint32_t negotiate_flags)
{
NTSTATUS status;
- struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
struct netr_LogonSamLogon r;
@@ -527,6 +554,8 @@ static bool test_S2U4Self(struct torture_context *tctx,
struct netlogon_creds_CredentialState *creds;
struct gensec_security *gensec_client_context;
struct gensec_security *gensec_server_context;
+ struct cli_credentials *client_creds;
+ struct cli_credentials *server_creds;
struct auth4_context *auth_context;
struct auth_session_info *kinit_session_info;
@@ -548,6 +577,31 @@ static bool test_S2U4Self(struct torture_context *tctx,
"Testing S4U2SELF (secure_channel_type: %d, machine: %s, negotiate_flags: 0x%08x\n",
secure_channel_type, test_machine_name, negotiate_flags);
+ /*
+ * Copy the credentials in order to use a different MEMORY krb5 ccache
+ * for each client/server setup. The MEMORY cache identifier is a
+ * pointer to the creds container. If we copy it the pointer changes and
+ * we will get a new clean memory cache.
+ */
+ client_creds = cli_credentials_shallow_copy(tmp_ctx,
+ cmdline_credentials);
+ torture_assert(tctx, client_creds, "Failed to copy of credentials");
+
+ server_creds = cli_credentials_shallow_copy(tmp_ctx,
+ credentials);
+ torture_assert(tctx, server_creds, "Failed to copy of credentials");
+
+ if (!test_SetupCredentials2(p1, tctx, negotiate_flags,
+ server_creds, secure_channel_type,
+ &creds)) {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(p1, tctx, server_creds, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
+
auth_context = talloc_zero(tmp_ctx, struct auth4_context);
torture_assert(tctx, auth_context != NULL, "talloc_new() failed");
@@ -561,7 +615,7 @@ static bool test_S2U4Self(struct torture_context *tctx,
status = gensec_set_target_hostname(gensec_client_context, test_machine_name);
- status = gensec_set_credentials(gensec_client_context, cmdline_credentials);
+ status = gensec_set_credentials(gensec_client_context, client_creds);
torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
@@ -572,7 +626,7 @@ static bool test_S2U4Self(struct torture_context *tctx,
auth_context, &gensec_server_context);
torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
- status = gensec_set_credentials(gensec_server_context, credentials);
+ status = gensec_set_credentials(gensec_server_context, server_creds);
torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
@@ -606,9 +660,10 @@ static bool test_S2U4Self(struct torture_context *tctx,
/* Now do the dance with S2U4Self */
/* Wipe out any existing ccache */
- cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
- cli_credentials_set_impersonate_principal(credentials,
- cli_credentials_get_principal(cmdline_credentials, tmp_ctx),
+ cli_credentials_invalidate_ccache(client_creds, CRED_SPECIFIED);
+ cli_credentials_invalidate_ccache(server_creds, CRED_SPECIFIED);
+ cli_credentials_set_impersonate_principal(server_creds,
+ cli_credentials_get_principal(client_creds, tmp_ctx),
talloc_asprintf(tmp_ctx, "host/%s", test_machine_name));
status = gensec_client_start(tctx, &gensec_client_context,
@@ -618,7 +673,7 @@ static bool test_S2U4Self(struct torture_context *tctx,
status = gensec_set_target_hostname(gensec_client_context, test_machine_name);
/* We now set the same credentials on both client and server contexts */
- status = gensec_set_credentials(gensec_client_context, credentials);
+ status = gensec_set_credentials(gensec_client_context, server_creds);
torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
@@ -629,7 +684,7 @@ static bool test_S2U4Self(struct torture_context *tctx,
auth_context, &gensec_server_context);
torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
- status = gensec_set_credentials(gensec_server_context, credentials);
+ status = gensec_set_credentials(gensec_server_context, server_creds);
torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
@@ -655,16 +710,16 @@ static bool test_S2U4Self(struct torture_context *tctx,
} while (1);
/* Don't pollute the remaining tests with the changed credentials */
- cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
- cli_credentials_set_target_service(credentials, NULL);
- cli_credentials_set_impersonate_principal(credentials, NULL, NULL);
+ cli_credentials_invalidate_ccache(server_creds, CRED_SPECIFIED);
+ cli_credentials_set_target_service(server_creds, NULL);
+ cli_credentials_set_impersonate_principal(server_creds, NULL, NULL);
/* Extract the PAC using Samba's code */
status = gensec_session_info(gensec_server_context, gensec_server_context, &s2u4self_session_info);
torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
- cli_credentials_get_ntlm_username_domain(cmdline_credentials, tctx,
+ cli_credentials_get_ntlm_username_domain(client_creds, tctx,
&ninfo.identity_info.account_name.string,
&ninfo.identity_info.domain_name.string);
@@ -674,12 +729,13 @@ static bool test_S2U4Self(struct torture_context *tctx,
chal = data_blob_const(ninfo.challenge,
sizeof(ninfo.challenge));
- names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(credentials),
- cli_credentials_get_domain(credentials));
+ names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(server_creds),
+ cli_credentials_get_domain(server_creds));
- status = cli_credentials_get_ntlm_response(cmdline_credentials, tctx,
+ status = cli_credentials_get_ntlm_response(client_creds, tctx,
&flags,
chal,
+ NULL, /* server_timestamp */
names_blob,
&lm_resp, &nt_resp,
NULL, NULL);
@@ -694,12 +750,12 @@ static bool test_S2U4Self(struct torture_context *tctx,
ninfo.identity_info.parameter_control = 0;
ninfo.identity_info.logon_id_low = 0;
ninfo.identity_info.logon_id_high = 0;
- ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials);
+ ninfo.identity_info.workstation.string = cli_credentials_get_workstation(server_creds);
logon.network = &ninfo;
r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
- r.in.computer_name = cli_credentials_get_workstation(credentials);
+ r.in.computer_name = cli_credentials_get_workstation(server_creds);
r.in.credential = &auth;
r.in.return_authenticator = &auth2;
r.in.logon_level = NetlogonNetworkInformation;
@@ -707,12 +763,6 @@ static bool test_S2U4Self(struct torture_context *tctx,
r.out.validation = &validation;
r.out.authoritative = &authoritative;
- if (!test_SetupCredentials2(p, tctx, negotiate_flags,
- credentials, secure_channel_type,
- &creds)) {
- return false;
- }
-
ZERO_STRUCT(auth2);
netlogon_creds_client_authenticator(creds, &auth);
@@ -797,7 +847,6 @@ struct torture_suite *torture_rpc_remote_pac(TALLOC_CTX *mem_ctx)
struct torture_suite *suite = torture_suite_create(mem_ctx, "pac");
struct torture_rpc_tcase *tcase;
- /* It is important to use different names, so that old entries in our credential cache are not used */
tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netr-bdc-arcfour",
&ndr_table_netlogon, TEST_MACHINE_NAME_BDC);
torture_rpc_tcase_add_test_creds(tcase, "verify-sig-arcfour", test_PACVerify_bdc_arcfour);
diff --git a/source4/torture/rpc/samba3rpc.c b/source4/torture/rpc/samba3rpc.c
index ff1a53ca314..cec3aaad3ed 100644
--- a/source4/torture/rpc/samba3rpc.c
+++ b/source4/torture/rpc/samba3rpc.c
@@ -192,13 +192,19 @@ bool torture_bind_authcontext(struct torture_context *torture)
if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
torture_comment(torture, "dcerpc_lsa_OpenPolicy2 with wrong vuid gave %s, "
- "expected NT_STATUS_IO_DEVICE_ERROR\n",
+ "expected NT_STATUS_CONNECTION_DISCONNECTED\n",
nt_errstr(status));
- status = NT_STATUS_IO_DEVICE_ERROR;
+ status = NT_STATUS_CONNECTION_DISCONNECTED;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR)) {
+ torture_comment(torture, "dcerpc_lsa_OpenPolicy2 with wrong vuid gave %s, "
+ "expected NT_STATUS_CONNECTION_DISCONNECTED\n",
+ nt_errstr(status));
+ status = NT_STATUS_CONNECTION_DISCONNECTED;
}
- torture_assert_ntstatus_equal(torture, status, NT_STATUS_IO_DEVICE_ERROR,
- "lsa io device error");
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_CONNECTION_DISCONNECTED,
+ "lsa connection disconnected");
smb1cli_session_set_id(tmp->smbXcli, tmp_vuid);
cli->tree->session = tmp;
@@ -1139,10 +1145,10 @@ static bool schan(struct torture_context *tctx,
generate_random_buffer(chal.data, chal.length);
names_blob = NTLMv2_generate_names_blob(
mem_ctx,
- cli_credentials_get_workstation(user_creds),
- cli_credentials_get_domain(user_creds));
+ cli_credentials_get_workstation(wks_creds),
+ cli_credentials_get_domain(wks_creds));
status = cli_credentials_get_ntlm_response(
- user_creds, mem_ctx, &flags, chal, names_blob,
+ user_creds, mem_ctx, &flags, chal, NULL, names_blob,
&lm_resp, &nt_resp, NULL, NULL);
if (!NT_STATUS_IS_OK(status)) {
torture_comment(tctx, "cli_credentials_get_ntlm_response failed:"
@@ -1312,7 +1318,6 @@ static bool torture_netlogon_samba3(struct torture_context *torture)
{
NTSTATUS status;
struct smbcli_state *cli;
- struct cli_credentials *anon_creds;
struct cli_credentials *wks_creds;
const char *wks_name;
int i;
@@ -1324,10 +1329,6 @@ static bool torture_netlogon_samba3(struct torture_context *torture)
wks_name = get_myname(torture);
}
- if (!(anon_creds = cli_credentials_init_anon(torture))) {
- torture_fail(torture, "create_anon_creds failed\n");
- }
-
lpcfg_smbcli_options(torture->lp_ctx, &options);
lpcfg_smbcli_session_options(torture->lp_ctx, &session_options);
@@ -1336,7 +1337,7 @@ static bool torture_netlogon_samba3(struct torture_context *torture)
lpcfg_smb_ports(torture->lp_ctx),
"IPC$", NULL,
lpcfg_socket_options(torture->lp_ctx),
- anon_creds,
+ cmdline_credentials,
lpcfg_resolve_context(torture->lp_ctx),
torture->ev, &options, &session_options,
lpcfg_gensec_settings(torture, torture->lp_ctx));
@@ -1356,7 +1357,7 @@ static bool torture_netlogon_samba3(struct torture_context *torture)
CRED_SPECIFIED);
torture_assert(torture,
- join3(torture, cli, false, cmdline_credentials, wks_creds),
+ join3(torture, cli, false, NULL, wks_creds),
"join failed");
cli_credentials_set_domain(
@@ -1383,7 +1384,7 @@ static bool torture_netlogon_samba3(struct torture_context *torture)
}
torture_assert(torture,
- leave(torture, cli, cmdline_credentials, wks_creds),
+ leave(torture, cli, NULL, wks_creds),
"leave failed");
return true;
@@ -1482,26 +1483,14 @@ static bool torture_samba3_sessionkey(struct torture_context *torture)
}
torture_assert(torture,
- test_join3(torture, false, anon_creds, cmdline_credentials, wks_name),
- "join using ntlmssp bind on an anonymous smb connection failed");
-
- torture_assert(torture,
test_join3(torture, false, cmdline_credentials, NULL, wks_name),
"join using anonymous bind on an authenticated smb connection failed");
- torture_assert(torture,
- test_join3(torture, false, cmdline_credentials, cmdline_credentials, wks_name),
- "join using ntlmssp bind on an authenticated smb connection failed");
-
/*
* The following two are tests for setuserinfolevel 25
*/
torture_assert(torture,
- test_join3(torture, true, anon_creds, cmdline_credentials, wks_name),
- "join using ntlmssp bind on an anonymous smb connection failed");
-
- torture_assert(torture,
test_join3(torture, true, cmdline_credentials, NULL, wks_name),
"join using anonymous bind on an authenticated smb connection failed");
@@ -1786,20 +1775,6 @@ static bool torture_samba3_rpc_getusername(struct torture_context *torture)
lpcfg_smbcli_options(torture->lp_ctx, &options);
lpcfg_smbcli_session_options(torture->lp_ctx, &session_options);
- status = smbcli_full_connection(
- torture, &cli, torture_setting_string(torture, "host", NULL),
- lpcfg_smb_ports(torture->lp_ctx),
- "IPC$", NULL, lpcfg_socket_options(torture->lp_ctx), cmdline_credentials,
- lpcfg_resolve_context(torture->lp_ctx), torture->ev, &options,
- &session_options, lpcfg_gensec_settings(torture, torture->lp_ctx));
- torture_assert_ntstatus_ok(torture, status, "smbcli_full_connection failed\n");
-
- if (!(user_sid = whoami(torture, torture, cli->tree))) {
- torture_fail(torture, "whoami on auth'ed connection failed\n");
- }
-
- talloc_free(cli);
-
if (!(anon_creds = cli_credentials_init_anon(torture))) {
torture_fail(torture, "create_anon_creds failed\n");
}
@@ -1820,6 +1795,20 @@ static bool torture_samba3_rpc_getusername(struct torture_context *torture)
torture_assert_sid_equal(torture, user_sid, dom_sid_parse_talloc(torture, "s-1-5-7"),
"Anon lsa_GetUserName returned unexpected SID");
+ talloc_free(cli);
+
+ status = smbcli_full_connection(
+ torture, &cli, torture_setting_string(torture, "host", NULL),
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$", NULL, lpcfg_socket_options(torture->lp_ctx), cmdline_credentials,
+ lpcfg_resolve_context(torture->lp_ctx), torture->ev, &options,
+ &session_options, lpcfg_gensec_settings(torture, torture->lp_ctx));
+ torture_assert_ntstatus_ok(torture, status, "smbcli_full_connection failed\n");
+
+ if (!(user_sid = whoami(torture, torture, cli->tree))) {
+ torture_fail(torture, "whoami on auth'ed connection failed\n");
+ }
+
if (!(user_creds = cli_credentials_init(torture))) {
torture_fail(torture, "cli_credentials_init failed\n");
}
@@ -1831,7 +1820,7 @@ static bool torture_samba3_rpc_getusername(struct torture_context *torture)
generate_random_password(user_creds, 8, 255),
CRED_SPECIFIED);
- if (!create_user(torture, torture, cli, cmdline_credentials,
+ if (!create_user(torture, torture, cli, NULL,
cli_credentials_get_username(user_creds),
cli_credentials_get_password(user_creds),
&domain_name, &created_sid)) {
@@ -1886,7 +1875,7 @@ static bool torture_samba3_rpc_getusername(struct torture_context *torture)
del:
if (!delete_user(torture, cli,
- cmdline_credentials,
+ NULL,
cli_credentials_get_username(user_creds))) {
torture_fail(torture, "delete_user failed\n");
}
diff --git a/source4/torture/rpc/samlogon.c b/source4/torture/rpc/samlogon.c
index 3c5398d8c8e..bfa8b639c3d 100644
--- a/source4/torture/rpc/samlogon.c
+++ b/source4/torture/rpc/samlogon.c
@@ -1754,7 +1754,8 @@ bool torture_rpc_samlogon(struct torture_context *torture)
* with INTERNAL_ERROR */
status = dcerpc_binding_set_flags(b,
- DCERPC_SCHANNEL | DCERPC_SIGN |
+ DCERPC_SCHANNEL |
+ DCERPC_SIGN | DCERPC_SEAL |
DCERPC_SCHANNEL_128,
DCERPC_AUTH_OPTIONS);
torture_assert_ntstatus_ok(torture, status, "set flags");
diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c
index 293b6722cc2..dcdbb8ad550 100644
--- a/source4/torture/rpc/samr.c
+++ b/source4/torture/rpc/samr.c
@@ -3096,6 +3096,7 @@ static bool test_SamLogon(struct torture_context *tctx,
status = cli_credentials_get_ntlm_response(test_credentials, tctx,
&flags,
chal,
+ NULL, /* server_timestamp */
names_blob,
&lm_resp, &nt_resp,
NULL, NULL);
@@ -3257,7 +3258,8 @@ static bool setup_schannel_netlogon_pipe(struct torture_context *tctx,
* with INTERNAL_ERROR */
status = dcerpc_binding_set_flags(b,
- DCERPC_SCHANNEL | DCERPC_SIGN |
+ DCERPC_SCHANNEL |
+ DCERPC_SIGN | DCERPC_SEAL |
DCERPC_SCHANNEL_AUTO,
DCERPC_AUTH_OPTIONS);
torture_assert_ntstatus_ok(tctx, status, "set flags");
diff --git a/source4/torture/rpc/schannel.c b/source4/torture/rpc/schannel.c
index de93fcad1a6..d5de134dcce 100644
--- a/source4/torture/rpc/schannel.c
+++ b/source4/torture/rpc/schannel.c
@@ -62,6 +62,7 @@ bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx,
struct netr_SamBaseInfo *base;
const char *crypto_alg = "";
bool can_do_validation_6 = true;
+ enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
if (lpcfg_client_lanman_auth(tctx->lp_ctx)) {
flags |= CLI_CRED_LANMAN_AUTH;
@@ -86,6 +87,7 @@ bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx,
status = cli_credentials_get_ntlm_response(cmdline_credentials, tctx,
&flags,
chal,
+ NULL, /* server_timestamp */
names_blob,
&lm_resp, &nt_resp,
NULL, NULL);
@@ -131,16 +133,26 @@ bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx,
}
}
- r.in.validation_level = 6;
+ dcerpc_binding_handle_auth_info(b, NULL, &auth_level);
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ r.in.validation_level = 6;
- torture_comment(tctx,
- "Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n",
- ninfo.identity_info.account_name.string, crypto_alg,
- r.in.validation_level);
+ torture_comment(tctx,
+ "Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n",
+ ninfo.identity_info.account_name.string, crypto_alg,
+ r.in.validation_level);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r),
+ "LogonSamLogonEx failed");
+ } else {
+ torture_comment(tctx,
+ "Skip auth_level[%u] Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n",
+ auth_level, ninfo.identity_info.account_name.string, crypto_alg,
+ r.in.validation_level);
+ r.out.result = NT_STATUS_INVALID_INFO_CLASS;
+ }
- torture_assert_ntstatus_ok(tctx,
- dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r),
- "LogonSamLogonEx failed");
if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_INFO_CLASS)) {
can_do_validation_6 = false;
} else {
@@ -741,6 +753,7 @@ static bool torture_schannel_bench_start(struct torture_schannel_bench_conn *con
status = cli_credentials_get_ntlm_response(user_creds, conn->tmp,
&flags,
chal,
+ NULL, /* server_timestamp */
names_blob,
&lm_resp, &nt_resp,
NULL, NULL);
diff --git a/source4/torture/rpc/testjoin.c b/source4/torture/rpc/testjoin.c
index 5ee2c2ac9f9..7fbf301b6ca 100644
--- a/source4/torture/rpc/testjoin.c
+++ b/source4/torture/rpc/testjoin.c
@@ -503,10 +503,36 @@ _PUBLIC_ struct test_join *torture_join_domain(struct torture_context *tctx,
struct test_join *tj;
struct samr_SetUserInfo s;
union samr_UserInfo u;
-
+ const char *binding_str = NULL;
+ struct dcerpc_binding *binding = NULL;
+ enum dcerpc_transport_t transport;
+
tj = talloc_zero(tctx, struct test_join);
if (!tj) return NULL;
+ binding_str = torture_setting_string(tctx, "binding", NULL);
+ if (binding_str == NULL) {
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ binding_str = talloc_asprintf(tj, "ncacn_np:%s", host);
+ }
+ status = dcerpc_parse_binding(tj, binding_str, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("dcerpc_parse_binding(%s) failed - %s\n",
+ binding_str, nt_errstr(status)));
+ talloc_free(tj);
+ return NULL;
+ }
+ transport = dcerpc_binding_get_transport(binding);
+ switch (transport) {
+ case NCALRPC:
+ case NCACN_UNIX_STREAM:
+ break;
+ default:
+ dcerpc_binding_set_transport(binding, NCACN_NP);
+ dcerpc_binding_set_flags(binding, 0, DCERPC_AUTH_OPTIONS);
+ break;
+ }
+
libnet_r = talloc_zero(tj, struct libnet_JoinDomain);
if (!libnet_r) {
talloc_free(tj);
@@ -522,9 +548,10 @@ _PUBLIC_ struct test_join *torture_join_domain(struct torture_context *tctx,
tj->libnet_r = libnet_r;
libnet_ctx->cred = cmdline_credentials;
- libnet_r->in.binding = torture_setting_string(tctx, "binding", NULL);
- if (!libnet_r->in.binding) {
- libnet_r->in.binding = talloc_asprintf(libnet_r, "ncacn_np:%s", torture_setting_string(tctx, "host", NULL));
+ libnet_r->in.binding = dcerpc_binding_string(libnet_r, binding);
+ if (libnet_r->in.binding == NULL) {
+ talloc_free(tj);
+ return NULL;
}
libnet_r->in.level = LIBNET_JOINDOMAIN_SPECIFIED;
libnet_r->in.netbios_name = machine_name;
diff --git a/source4/winbind/wb_pam_auth.c b/source4/winbind/wb_pam_auth.c
index c84b51f4fe9..bb9cf42d772 100644
--- a/source4/winbind/wb_pam_auth.c
+++ b/source4/winbind/wb_pam_auth.c
@@ -250,7 +250,9 @@ struct composite_context *wb_cmd_pam_auth_send(TALLOC_CTX *mem_ctx,
cli_credentials_get_domain(credentials));
status = cli_credentials_get_ntlm_response(
- credentials, mem_ctx, &flags, chal, names_blob,
+ credentials, mem_ctx, &flags, chal,
+ NULL, /* server_timestamp */
+ names_blob,
&lm_resp, &nt_resp, NULL, NULL);
if (!NT_STATUS_IS_OK(status)) {
return NULL;
diff --git a/source4/winbind/wb_samba3_cmd.c b/source4/winbind/wb_samba3_cmd.c
index 9ec3c4b0ccd..2e6a2601ce5 100644
--- a/source4/winbind/wb_samba3_cmd.c
+++ b/source4/winbind/wb_samba3_cmd.c
@@ -643,8 +643,13 @@ NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
chal.data = s3call->request->data.auth_crap.chal;
chal.length = sizeof(s3call->request->data.auth_crap.chal);
- nt_resp.data = (uint8_t *)s3call->request->data.auth_crap.nt_resp;
- nt_resp.length = s3call->request->data.auth_crap.nt_resp_len;
+ if (s3call->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
+ nt_resp.data = (uint8_t *)s3call->request->extra_data.data;
+ nt_resp.length = s3call->request->extra_len;
+ } else {
+ nt_resp.data = (uint8_t *)s3call->request->data.auth_crap.nt_resp;
+ nt_resp.length = s3call->request->data.auth_crap.nt_resp_len;
+ }
lm_resp.data = (uint8_t *)s3call->request->data.auth_crap.lm_resp;
lm_resp.length = s3call->request->data.auth_crap.lm_resp_len;
diff --git a/testprogs/blackbox/test_ldb.sh b/testprogs/blackbox/test_ldb.sh
index 60bad44ebb9..394a7e88bf5 100755
--- a/testprogs/blackbox/test_ldb.sh
+++ b/testprogs/blackbox/test_ldb.sh
@@ -39,6 +39,9 @@ ldbsearch="$VALGRIND ldbsearch"
check "RootDSE" $ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base DUMMY=x dnsHostName highestCommittedUSN || failed=`expr $failed + 1`
check "RootDSE (full)" $ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base '(objectClass=*)' || failed=`expr $failed + 1`
check "RootDSE (extended)" $ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base '(objectClass=*)' --extended-dn || failed=`expr $failed + 1`
+if [ x$p = x"ldaps" ]; then
+ testit_expect_failure "RootDSE over SSLv3 should fail" $ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base DUMMY=x dnsHostName highestCommittedUSN --option='tlspriority=NONE:+VERS-SSL3.0:+MAC-ALL:+CIPHER-ALL:+RSA:+SIGN-ALL:+COMP-NULL' && failed=`expr $failed + 1`
+fi
echo "Getting defaultNamingContext"
BASEDN=`$ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base DUMMY=x defaultNamingContext | grep defaultNamingContext | awk '{print $2}'`
diff --git a/testprogs/blackbox/test_ldb_simple.sh b/testprogs/blackbox/test_ldb_simple.sh
new file mode 100755
index 00000000000..7375cbfd843
--- /dev/null
+++ b/testprogs/blackbox/test_ldb_simple.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+if [ $# -lt 2 ]; then
+cat <<EOF
+Usage: test_ldb_simple.sh PROTOCOL SERVER [OPTIONS]
+EOF
+exit 1;
+fi
+
+
+p=$1
+SERVER=$2
+PREFIX=$3
+shift 2
+options="$*"
+
+. `dirname $0`/subunit.sh
+
+check() {
+ name="$1"
+ shift
+ cmdline="$*"
+ echo "test: $name"
+ $cmdline
+ status=$?
+ if [ x$status = x0 ]; then
+ echo "success: $name"
+ else
+ echo "failure: $name"
+ failed=`expr $failed + 1`
+ fi
+ return $status
+}
+
+export PATH="$BINDIR:$PATH"
+
+ldbsearch="$VALGRIND ldbsearch"
+
+check "currentTime" $ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base currentTime || failed=`expr $failed + 1`
+
+exit $failed
diff --git a/testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.idl b/testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.idl
new file mode 100644
index 00000000000..73aeb16d379
--- /dev/null
+++ b/testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.idl
@@ -0,0 +1,64 @@
+#ifndef MIDLTESTS_C_CODE
+
+/*
+ * For midltests_tcp.exe you may want to
+ * redirect the traffic via rinetd
+ * with a /etc/rinetd.conf like this:
+ *
+ * 172.31.9.1 5032 172.31.9.8 5032
+ * 172.31.9.1 5064 172.31.9.8 5064
+ *
+ * This is useful to watch the traffic with
+ * a network sniffer.
+ */
+/*
+cpp_quote("#define LISTEN_IP \"0.0.0.0\"")
+cpp_quote("#define FORWARD_IP \"127.0.0.1\"")
+cpp_quote("#define CONNECT_IP \"172.31.9.1\"")
+*/
+
+/*
+ * With midltests_tcp.exe NDR64 is enforced by default.
+ * For testing it might be needed to allow downgrades
+ * to NDR32. This is needed when you use 'pipe'.
+ */
+//cpp_quote("#define DONOT_FORCE_NDR64 1")
+
+[
+ uuid("225b9fcb-eb3d-497b-8b0b-591f049a2507"),
+ pointer_default(unique)
+]
+interface midltests
+{
+
+ typedef struct {
+ [range(1,10000)] long cb;
+ [size_is(cb)] char rcg[];
+ } DRS_EXTENSIONS;
+
+ long midltests_fn(
+ [out] DRS_EXTENSIONS **e
+ );
+}
+
+#elif MIDLTESTS_C_CODE
+
+static void midltests(void)
+{
+ DRS_EXTENSIONS *e = NULL;
+ cli_midltests_fn(&e);
+}
+
+long srv_midltests_fn(DRS_EXTENSIONS **_e)
+{
+ DRS_EXTENSIONS *e;
+ printf("srv_midltests_fn: Start\n");
+ e = (DRS_EXTENSIONS *)malloc(sizeof(DRS_EXTENSIONS) + 0x34);
+ e->cb = 0x34;
+ memset(e->rcg, 0xcd, e->cb);
+ *_e = e;
+ printf("srv_midltests_fn: End\n");
+ return 0x65757254;
+}
+
+#endif
diff --git a/testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.out b/testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.out
new file mode 100644
index 00000000000..e0b3a0ee338
--- /dev/null
+++ b/testprogs/win32/midltests/valid/midltests_DRS_EXTENSIONS.out
@@ -0,0 +1,43 @@
+Wait for setup of server threads
+
+Test NDR32
+
+ndr32: disable NDR64
+
+ndr32:in => out: ptype[request] flen[24] plen[0] ahint[0]
+
+
+srv_midltests_fn: Start
+srv_midltests_fn: End
+
+ndr32:out => in: ptype[response] flen[92] plen[68] ahint[68]
+
+[000] 00 00 02 00 34 00 00 00 34 00 00 00 CD CD CD CD ....4... 4.......
+[010] CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
+[020] CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
+[030] CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
+[040] 54 72 75 65 True
+
+NDRTcpThread[ndr32] stop
+
+Test NDR64
+
+ndr64: got NDR64
+
+ndr64:in => out: ptype[request] flen[24] plen[0] ahint[0]
+
+
+srv_midltests_fn: Start
+srv_midltests_fn: End
+
+ndr64:out => in: ptype[response] flen[100] plen[76] ahint[76]
+
+[000] 00 00 02 00 00 00 00 00 34 00 00 00 00 00 00 00 ........ 4.......
+[010] 34 00 00 00 CD CD CD CD CD CD CD CD CD CD CD CD 4....... ........
+[020] CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
+[030] CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
+[040] CD CD CD CD CD CD CD CD 54 72 75 65 ........ True
+
+NDRTcpThread[ndr64] stop
+
+Test OK
diff --git a/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5
index 0db55ce9ea4..4b50d60dd2d 100644
--- a/wscript_configure_system_mitkrb5
+++ b/wscript_configure_system_mitkrb5
@@ -55,7 +55,8 @@ conf.CHECK_FUNCS_IN('_et_list', 'com_err')
conf.CHECK_HEADERS('com_err.h', lib='com_err')
conf.CHECK_HEADERS('krb5.h krb5/locate_plugin.h', lib='krb5')
-conf.CHECK_HEADERS('gssapi.h gssapi/gssapi_generic.h gssapi/gssapi.h gssapi/gssapi_ext.h gssapi/gssapi_krb5.h', lib='gssapi')
+possible_gssapi_headers="gssapi.h gssapi/gssapi_generic.h gssapi/gssapi.h gssapi/gssapi_ext.h gssapi/gssapi_krb5.h gssapi/gssapi_oid.h"
+conf.CHECK_HEADERS(possible_gssapi_headers, lib='gssapi')
conf.CHECK_FUNCS_IN('krb5_encrypt_data', 'k5crypto')
conf.CHECK_FUNCS_IN('des_set_key','crypto')
@@ -83,6 +84,7 @@ conf.CHECK_FUNCS_IN('''
gss_krb5_export_lucid_sec_context
gss_import_cred gss_export_cred
''', 'gssapi gssapi_krb5')
+conf.CHECK_VARIABLE('GSS_KRB5_CRED_NO_CI_FLAGS_X', headers=possible_gssapi_headers)
conf.CHECK_FUNCS_IN('krb5_mk_req_extended krb5_kt_compare', 'krb5')
conf.CHECK_FUNCS('''
krb5_set_default_in_tkt_etypes krb5_set_default_tgs_enctypes